* © 2018 Aaron Taylor <ataylor at subgeniuskitty dot com>
* See LICENSE.txt file for copyright and license details.
#include <SDL2/SDL_ttf.h>
#define DEFAULT_PORT "4999"
#define WINDOW_HEIGHT 1000
#define WINDOW_WIDTH 1000
#define DOT_HEIGHT (WINDOW_HEIGHT / 140)
#define DOT_WIDTH (WINDOW_WIDTH / 140)
#define CHUNK_HEIGHT (DOT_HEIGHT * 4)
#define CHUNK_WIDTH (DOT_WIDTH * 8)
#define FONT_WIDTH (DOT_WIDTH * 4)
#define BORDER (DOT_WIDTH * 3)
print_usage(char ** argv
)
printf( "NED Front Panel v%d (www.subgeniuskitty.com)\n"
" -h Help (prints this message)\n"
" -f <path, optional> Path to a TTF file.\n"
" Default is './liberation_mono.tff'.\n"
" -p <port, optional> Port to listen on for NED snapshots.\n"
word_to_leds(uint32_t voffset
, uint32_t hoffset
, uint32_t word
, SDL_Renderer
* renderer
)
for (int i
=0; i
<8; i
++) {
SDL_SetRenderDrawColor(renderer
, 100, 150, 100, SDL_ALPHA_OPAQUE
);
SDL_SetRenderDrawColor(renderer
, 100, 100, 150, SDL_ALPHA_OPAQUE
);
r
.x
= ((CHUNK_WIDTH
* i
) + hoffset
);
SDL_RenderFillRect(renderer
, &r
);
for (int i
=0; i
<BITSPERWORD
; i
++) {
r
.x
= ((((2 * (BITSPERWORD
- i
)) * DOT_WIDTH
) - (1.5 * DOT_WIDTH
)) + hoffset
);
r
.y
= (voffset
+ (2 * DOT_HEIGHT
));
SDL_SetRenderDrawColor(renderer
, 255, 255, 255, SDL_ALPHA_OPAQUE
);
SDL_SetRenderDrawColor(renderer
, 0, 0, 0, SDL_ALPHA_OPAQUE
);
SDL_RenderFillRect(renderer
, &r
);
print_text(uint32_t voffset
, uint32_t hoffset
, char * str
, TTF_Font
* font
, SDL_Renderer
* renderer
)
r
.w
= (FONT_WIDTH
* strnlen(str
, MAX_STRING
));
SDL_Color white
= {255,255,255};
SDL_Surface
* surface
= TTF_RenderText_Solid(font
, str
, white
);
SDL_Texture
* texture
= SDL_CreateTextureFromSurface(renderer
, surface
);
SDL_RenderCopy(renderer
, texture
, NULL
, &r
);
SDL_DestroyTexture(texture
);
SDL_FreeSurface(surface
);
sdl_init(SDL_Window
** window
, SDL_Renderer
** renderer
, TTF_Font
** font
, char * font_path
)
/* Initialize SDL subsystems. */
/* We require the VIDEO subsystem for display. */
/* The EVENTS and FILE I/O subsystems are initialized by default. */
SDL_Init(SDL_INIT_VIDEO
);
if(TTF_Init() == -1) printf("TTF_Init: %s\n", TTF_GetError());
/* Create an SDL window and renderer, and populate the pointers. */
SDL_CreateWindowAndRenderer(WINDOW_WIDTH
, WINDOW_HEIGHT
, SDL_WINDOW_RESIZABLE
, window
, renderer
);
/* Clear window so it appears normal to user. */
SDL_SetRenderDrawColor(*renderer
, 128, 128, 128, SDL_ALPHA_OPAQUE
);
SDL_RenderClear(*renderer
);
SDL_RenderPresent(*renderer
);
*font
= TTF_OpenFont(font_path
, 24);
if (font
== NULL
) printf("TTF_OpenFont: %s\n", TTF_GetError());
valid_sequence_number(uint32_t new_sn
)
/* Comparison is "new_sn > old_sn" per RFC1982: Serial Number Arithmetic. */
((new_sn
< old_sn
) && ((old_sn
- new_sn
) > (0x80000000)))
((new_sn
> old_sn
) && ((new_sn
- old_sn
) < (0x80000000)))
main(int argc
, char ** argv
)
* Process command line arguments
while ((c
= getopt(argc
,argv
,"hp:f:")) != -1) {
// TODO: What do I want to consider valid input?
// TODO: What do I want to consider valid input?
if (font_path
== NULL
) asprintf(&font_path
, "./liberation_mono.ttf");
if (fp_port
== NULL
) asprintf(&fp_port
, "4999");
signal(SIGINT
, sigint_handler
);
sdl_init(&window
, &renderer
, &font
, font_path
);
struct addrinfo
* servinfo
;
memset(&hints
, 0, sizeof(hints
));
hints
.ai_family
= AF_INET
;
hints
.ai_socktype
= SOCK_DGRAM
;
hints
.ai_flags
= AI_PASSIVE
;
if ((rv
= getaddrinfo(NULL
, fp_port
, &hints
, &servinfo
)) != 0) {
fprintf(stderr
, "ERROR: getaddrinfo: %s\n", gai_strerror(rv
));
for (p
= servinfo
; p
!= NULL
; p
= p
->ai_next
) {
if ((sockfd
= socket(p
->ai_family
, p
->ai_socktype
, p
->ai_protocol
)) == -1) {
if (bind(sockfd
, p
->ai_addr
, p
->ai_addrlen
) == -1) {
fprintf(stderr
, "ERROR: Failed to bind to socket.\n");
* Datagram format (all entries are 4 bytes):
* Sequence number (See RFC1982)
* Currently executing word
* Top 16 RAM words from start address
struct sockaddr_storage their_addr
;
addr_len
= sizeof their_addr
;
if ((numbytes
= recvfrom(sockfd
, word
, 156, 0,
(struct sockaddr
*) &their_addr
, &addr_len
)) == -1
fprintf(stderr
, "WARNING: Unable to receive matching snapshot packet.\n");
if ((numbytes
== 156) && valid_sequence_number(word
[0])) {
SDL_SetRenderDrawColor(renderer
, 128, 128, 128, SDL_ALPHA_OPAQUE
);
SDL_RenderClear(renderer
);
asprintf(&msg
, "PC: 0x%08x", word
[2]);
print_text((1 * CHUNK_HEIGHT
), BORDER
, msg
, font
, renderer
);
word_to_leds((2 * CHUNK_HEIGHT
), BORDER
, word
[2], renderer
);
asprintf(&msg
, "SC: 0x%08x", word
[3]);
print_text((4 * CHUNK_HEIGHT
), BORDER
, msg
, font
, renderer
);
word_to_leds((5 * CHUNK_HEIGHT
), BORDER
, word
[3], renderer
);
asprintf(&msg
, "TOS@%u", word
[5]);
print_text((7 * CHUNK_HEIGHT
), BORDER
, msg
, font
, renderer
);
for (int i
=0; i
<16; i
++) {
word_to_leds(((i
+8) * CHUNK_HEIGHT
), BORDER
, word
[(i
+6)], renderer
);
asprintf(&msg
, "CW: 0x%08x", word
[1]);
print_text((1 * CHUNK_HEIGHT
), ((WINDOW_WIDTH
/ 2) + BORDER
), msg
, font
, renderer
);
word_to_leds((2 * CHUNK_HEIGHT
), ((WINDOW_WIDTH
/ 2) + BORDER
), word
[1], renderer
);
asprintf(&msg
, "PSW: 0x%08x", word
[4]);
print_text((4 * CHUNK_HEIGHT
), ((WINDOW_WIDTH
/ 2) + BORDER
), msg
, font
, renderer
);
word_to_leds((5 * CHUNK_HEIGHT
), ((WINDOW_WIDTH
/ 2) + BORDER
), word
[4], renderer
);
asprintf(&msg
, "RAM: 0x%08x", word
[22]);
print_text((7 * CHUNK_HEIGHT
), ((WINDOW_WIDTH
/ 2) + BORDER
), msg
, font
, renderer
);
for (int i
=0; i
<16; i
++) {
word_to_leds(((i
+8) * CHUNK_HEIGHT
), ((WINDOW_WIDTH
/ 2) + BORDER
), word
[(i
+23)], renderer
);
SDL_RenderPresent(renderer
);