From e72315b7872622d317b06276270d24948dd2b389 Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Sun, 23 Jun 2024 12:13:19 -0500 Subject: [PATCH] time_display: get timing data from UDP --- .gitignore | 4 +- Makefile | 15 +- event.h | 4 - link.c | 0 link.h | 10 ++ packet.h | 65 ++++---- parse_serial.c | 33 +++-- parse_serial.h | 6 +- serial_forwarder | Bin 49432 -> 0 bytes serial_forwarder.c | 159 ++++++++++++++------ time_display.c | 358 +++++++++++++++++++++++++++++++++++++++++---- timer.c | 270 ---------------------------------- timer.h | 16 +- 13 files changed, 530 insertions(+), 410 deletions(-) delete mode 100644 event.h create mode 100644 link.c create mode 100644 link.h delete mode 100755 serial_forwarder delete mode 100644 timer.c diff --git a/.gitignore b/.gitignore index 38e1df7..df18bcb 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,6 @@ *.o *.gch *.d -main \ No newline at end of file +main +serial_forwarder +time_display \ No newline at end of file diff --git a/Makefile b/Makefile index 9a222b3..880c721 100644 --- a/Makefile +++ b/Makefile @@ -13,20 +13,27 @@ DEPFLAGS = -MMD -MP OPT = -O3 -march=native -OBJS = \ - timer.o - SERIAL_FORWARDER_OBJS = \ serial_forwarder.o \ serial.o \ parse_serial.o -all: serial_forwarder +TIME_DISPLAY_OBJS = \ + time_display.o + +all: serial_forwarder time_display + +clean: + rm -f *.o *.d *.gch + rm -f serial_forwarder time_display %.o: %.c $(CC) $(CARCH) $(CFLAGS) $(OPT) $(DEBUG) $(DEPFLAGS) -MF ${<}.d -c $< -o $@ serial_forwarder: $(SERIAL_FORWARDER_OBJS) + $(CC) $^ -o $@ + +time_display: $(TIME_DISPLAY_OBJS) $(CC) $(LDFLAGS) $^ -o $@ -include $(shell find -type f -name '*.d') diff --git a/event.h b/event.h deleted file mode 100644 index 2c80916..0000000 --- a/event.h +++ /dev/null @@ -1,4 +0,0 @@ -enum command { - CMD_NOP, - CMD_STATE_TRANSFER, -}; diff --git a/link.c b/link.c new file mode 100644 index 0000000..e69de29 diff --git a/link.h b/link.h new file mode 100644 index 0000000..7ac7d2c --- /dev/null +++ b/link.h @@ -0,0 +1,10 @@ +#pragma once + +#include + +struct link_state { + uint64_t send_sequence; + uint64_t recv_sequence; + struct timespec send_ping; + struct timespec recv_ping; +}; diff --git a/packet.h b/packet.h index aaa0158..98d40d1 100644 --- a/packet.h +++ b/packet.h @@ -1,42 +1,47 @@ +#pragma once + #include -#include #include -typedef _Float64 float64_t; +#include "timer.h" -enum packet_type { - PACKET_TYPE__TIME_START = 0x2112858517, - PACKET_TYPE__TIME_STOP = 0xdf75d3f8, - PACKET_TYPE__RTT_DELAY = 0xc7065931, - PACKET_TYPE__ACK = 0xfde7959f, +#define EVENT_TYPE__INVALID 0x00000000 +#define EVENT_TYPE__TIME_START 0x12858517 +#define EVENT_TYPE__TIME_STOP 0xdf75d3f8 +#define EVENT_TYPE__RTT_DELAY 0xc7065931 +#define EVENT_TYPE__PING 0x0ba0d4c2 +#define EVENT_TYPE__ACK 0xfde7959f + +static_assert((sizeof (struct timespec)) == 8 + 8); + +struct event { + uint32_t type; + uint32_t sequence; }; -struct time_stop_data { - uint32_t integer_value; - uint32_t fraction_value; - uint16_t integer_digits; - uint16_t fraction_digits; -} __attribute__((__packed__)); +struct packet_stopwatch { + struct event event; + struct stopwatch_time stopwatch_time; +}; -static_assert((sizeof (struct time_stop_data)) == 4 * 3); +static_assert((sizeof (struct packet_stopwatch)) == + (sizeof (struct event)) + (sizeof (struct stopwatch_time))); -struct rtt_delay_data { - float64_t offset; -} __attribute__((__packed__)); +struct packet_start { + struct event event; +}; -struct ack_data { - uint64_t seq; -} __attribute__((__packed__)); +static_assert((sizeof (struct packet_start)) == (sizeof (struct event))); -static_assert((sizeof (struct rtt_delay_data)) == 8); +struct packet_ack { + struct event event; +}; -struct timing_packet { - uint32_t type; - union { - struct time_stop_data time_stop; - struct rtt_delay_data rtt_delay; - struct ack_data ack; - }; -} __attribute__((__packed__)); +static_assert((sizeof (struct packet_ack)) == (sizeof (struct event))); -static_assert((sizeof (struct timing_packet)) == 4 * 4); +struct packet_rtt_delay { + struct event event; + struct timespec offset; +}; + +static_assert((sizeof (struct packet_rtt_delay)) == (sizeof (struct event)) + (sizeof (struct timespec))); diff --git a/parse_serial.c b/parse_serial.c index b35d0c6..e83d864 100644 --- a/parse_serial.c +++ b/parse_serial.c @@ -80,34 +80,35 @@ bool is_timer_resume(uint8_t const * const buf, int length) return false; } -bool handle_line(uint8_t const * const buf, int length, - struct timer_state * timer_state) +uint32_t handle_line(uint8_t const * const buf, int length, + struct timer_state * timer_state) { if (length == 0) { timer_state->status = TIMER_RUNNING; - int ret = clock_gettime(CLOCK_MONOTONIC, &timer_state->counter.start); + int ret = clock_gettime(CLOCK_MONOTONIC_RAW, &timer_state->counter.start); + assert(ret != -1); timer_state->counter.offset.tv_sec = 0; timer_state->counter.offset.tv_nsec = 0; - assert(ret != -1); - return true; - } else if (is_timer_resume(buf, length)) { - return true; - } else { + return EVENT_TYPE__TIME_START; + } /*else if (is_timer_resume(buf, length)) { + return true; // fixme + } */ else { int ret = parse_time(buf, length, &timer_state->time); if (ret == 0) { timer_state->status = TIMER_STOPPED; - return true; + return EVENT_TYPE__TIME_STOP; } } return false; } -bool handle_parse(uint8_t * read_buf, int length, - struct parser_state * parser_state, - struct timer_state * timer_state) +uint32_t handle_parse(uint8_t * read_buf, int length, + struct parser_state * parser_state, + struct timer_state * timer_state) { - bool have_state_change = false; + uint32_t type = EVENT_TYPE__INVALID; + while (length > 0) { int copy_length = min(length, BUFSIZE - parser_state->offset); length -= copy_length; @@ -119,8 +120,8 @@ bool handle_parse(uint8_t * read_buf, int length, while (i < parser_state->offset) { if (parser_state->buf[i] == '\r') { fprintf(stderr, "r at %d %d\n", i, parser_state->offset); - have_state_change |= handle_line(parser_state->buf, i, - timer_state); + type = handle_line(parser_state->buf, i, + timer_state); parser_state->offset -= i + 1; assert(parser_state->offset >= 0); memmove(&parser_state->buf[0], &parser_state->buf[i + 1], parser_state->offset); @@ -135,5 +136,5 @@ bool handle_parse(uint8_t * read_buf, int length, continue; } - return have_state_change; + return type; } diff --git a/parse_serial.h b/parse_serial.h index 72af749..95a9660 100644 --- a/parse_serial.h +++ b/parse_serial.h @@ -10,6 +10,6 @@ struct parser_state { int offset; }; -bool handle_parse(uint8_t * read_buf, int length, - struct parser_state * parser_state, - struct timer_state * timer_state); +uint32_t handle_parse(uint8_t * read_buf, int length, + struct parser_state * parser_state, + struct timer_state * timer_state); diff --git a/serial_forwarder b/serial_forwarder deleted file mode 100755 index 355dcf94246e8232785da4a8875706711010ab07..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 49432 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 diff --git a/serial_forwarder.c b/serial_forwarder.c index b2d75a0..6029ea6 100644 --- a/serial_forwarder.c +++ b/serial_forwarder.c @@ -8,26 +8,35 @@ #include #include #include +#include #include +#include #include "bufsize.h" #include "serial.h" #include "timer.h" #include "parse_serial.h" +#include "packet.h" #define PORT 4321 //#define SERIALPORT "/dev/ttyS0" -#define SERIALPORT "/dev/ttyUSB0" +//#define SERIALPORT "/dev/ttyUSB0" +#define SERIALPORT "foo.fifo" -int handle_sock(int sock) +static struct sockaddr_in6 dest_addr; + +int handle_sockfd(int sockfd) { - struct sockaddr_in src_addr; - socklen_t addrlen = (sizeof (struct sockaddr_in)); + struct sockaddr_in6 src_addr; + socklen_t addrlen = (sizeof (struct sockaddr_in6)); char buf[BUFSIZE]; while (true) { - ssize_t recv_len = recvfrom(sock, buf, BUFSIZE, 0, (struct sockaddr *)&src_addr, &addrlen); + ssize_t recv_len = recvfrom(sockfd, + buf, (sizeof (buf)), + 0, + (struct sockaddr *)&src_addr, &addrlen); if (recv_len == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) { perror("sock eagain"); @@ -38,10 +47,10 @@ int handle_sock(int sock) } } - printf("got %ld data\n", recv_len); - printf("Received packet from %s:%d\n", inet_ntoa(src_addr.sin_addr), ntohs(src_addr.sin_port)); - buf[recv_len] = 0; - printf("Data: %s\n", buf); + char src_addr_str[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, &src_addr.sin6_addr, src_addr_str, INET6_ADDRSTRLEN); + printf("Received packet from %s:%d\n", src_addr_str, ntohs(src_addr.sin6_port)); + printf("length: %ld\n", recv_len); } } @@ -86,19 +95,57 @@ int handle_timerfd(int timerfd) return 0; } -struct receiver_state { - uint64_t seq; - uint64_t ack_seq; -}; +int send_stopwatch_event(int sockfd, + struct timer_state * timer_state, + struct link_state * link_state) +{ + struct packet_stopwatch pkt; + pkt.event.type = EVENT_TYPE__TIME_STOP; + pkt.event.sequence = link_state.send_sequence++; + memcpy(&pkt.stopwatch_time, &timer_state->time, (sizeof (struct stopwatch_time))); -int handle_serialfd(int timerfd, + int ret = sendto(sockfd, + &pkt, (sizeof (struct packet_stopwatch)), + 0, + (struct sockaddr *)&dest_addr, + (sizeof (struct sockaddr_in6))); + if (ret == -1) { + perror("sendto()"); + } + + return 0; +} + +int send_start_event(int sockfd, + struct timer_state * timer_state, + struct link_state * link_state) +{ + struct packet_start pkt; + pkt.event.type = EVENT_TYPE__TIME_START; + pkt.event.sequence = link_state.send_sequence++; + + int ret = sendto(sockfd, + &pkt, (sizeof (struct packet_stopwatch)), + 0, + (struct sockaddr *)&dest_addr, + (sizeof (struct sockaddr_in6))); + if (ret == -1) { + perror("sendto()"); + } + + return 0; +} + +int handle_serialfd(int serialfd, + int sockfd, struct parser_state * parser_state, - struct timer_state * timer_state) + struct timer_state * timer_state, + struct link_state * link_state) { uint8_t buf[BUFSIZE]; while (true) { - ssize_t len = read(timerfd, buf, (sizeof (buf))); + ssize_t len = read(serialfd, buf, (sizeof (buf))); if (len == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) { fprintf(stderr, "serialfd eagain\n"); @@ -115,10 +162,26 @@ int handle_serialfd(int timerfd, } fprintf(stderr, "\n"); */ - bool have_state_change = handle_parse(buf, len, - parser_state, - timer_state); - printf("have_state_change: %d\n", have_state_change); + uint32_t type = handle_parse(buf, len, + parser_state, + timer_state); + int ret; + switch (type) { + case EVENT_TYPE__TIME_STOP: + ret = send_stopwatch_event(sockfd, timer_state, link_state); + if (ret == -1) { + return -1; + } + break; + case EVENT_TYPE__TIME_START: + ret = send_start_event(sockfd, timer_state, link_state); + if (ret == -1) { + return -1; + } + break; + default: + break; + } } return 0; @@ -128,20 +191,20 @@ int main(void) { int ret; - int sock = socket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP); - if (sock == -1) { + int sockfd = socket(AF_INET6, SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP); + if (sockfd == -1) { perror("socket"); return -1; } - struct sockaddr_in sockaddr = {0}; - sockaddr.sin_family = AF_INET; - sockaddr.sin_port = htons(PORT); - sockaddr.sin_addr.s_addr = htonl(INADDR_ANY); + struct sockaddr_in6 sockaddr = {0}; + sockaddr.sin6_family = AF_INET6; + sockaddr.sin6_port = htons(PORT); + sockaddr.sin6_addr = in6addr_any; - ret = bind(sock, (struct sockaddr *)&sockaddr, (sizeof (struct sockaddr_in))); + ret = bind(sockfd, (struct sockaddr *)&sockaddr, (sizeof (struct sockaddr_in6))); if (ret == -1) { - perror("bind"); + perror("sockfd bind"); return -1; } @@ -157,8 +220,8 @@ int main(void) { struct epoll_event ev; ev.events = EPOLLIN | EPOLLET; - ev.data.fd = sock; - ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, sock, &ev); + ev.data.fd = sockfd; + ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, sockfd, &ev); if (ret == -1) { perror("epoll_ctl: sock"); return -1; @@ -192,10 +255,12 @@ int main(void) perror("open: serialport"); return -1; } + /* ret = set_terminal_attributes(serialfd); if (ret == -1) { return -1; } + */ { struct epoll_event ev; @@ -208,8 +273,14 @@ int main(void) } } + dest_addr.sin6_family = AF_INET6; + dest_addr.sin6_port = htons(1234); + ret = inet_pton(AF_INET6, "::1", &dest_addr.sin6_addr); + assert(ret == 1); + struct parser_state parser_state = {0}; struct timer_state timer_state = {0}; + struct link_state link_state = {0}; while (1) { printf("Wait for datagram\n"); @@ -221,8 +292,8 @@ int main(void) } for (int n = 0; n < nfds; ++n) { - if (events[n].data.fd == sock) { - ret = handle_sock(sock); + if (events[n].data.fd == sockfd) { + ret = handle_sockfd(sockfd); if (ret == -1) return -1; } else if (events[n].data.fd == timerfd) { @@ -232,31 +303,25 @@ int main(void) } else if (events[n].data.fd == serialfd) { fprintf(stderr, "handle_serialfd\n"); ret = handle_serialfd(serialfd, + sockfd, &parser_state, - &timer_state); - if (ret == -1) + &timer_state, + &link_state); + if (ret == -1) { return -1; + } } else { assert(0); } } - /* - struct sockaddr_in dest_addr; - dest_addr.sin_family = AF_INET; - dest_addr.sin_port = htons(1234); - dest_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); - - ret = sendto(sock, buf, 3, 0, (struct sockaddr *)&dest_addr, (sizeof (struct sockaddr_in))); - if (ret == -1) { - perror("sendto()"); - } - */ - //sleep(2); } - close(sock); + close(sockfd); + close(serialfd); + close(timerfd); + close(epollfd); return 0; } diff --git a/time_display.c b/time_display.c index 4028a3b..2d709ba 100644 --- a/time_display.c +++ b/time_display.c @@ -1,61 +1,355 @@ -#include -#include -#include #include -#include +#include +#include +#include #include +#include +#include +#include + +#include +#include FT_FREETYPE_H + +#include + +#include "timer.h" +#include "bufsize.h" +#include "packet.h" + +struct glyph { + int32_t width; + int32_t height; + + int32_t horiBearingX; + int32_t horiBearingY; + int32_t horiAdvance; + + SDL_Texture * texture; +}; + +static struct glyph glyphs[0x80 - 0x20] = {0}; +int32_t face_height; + +int +load_outline_char(SDL_Renderer * renderer, + const FT_Face face, + const FT_Int32 load_flags, + const FT_Render_Mode render_mode, + const FT_ULong char_code) +{ + FT_Error error; + FT_UInt glyph_index = FT_Get_Char_Index(face, char_code); + + error = FT_Load_Glyph(face, glyph_index, load_flags); + if (error) { + printf("FT_Load_Glyph %s\n", FT_Error_String(error)); + return -1; + } + + error = FT_Render_Glyph(face->glyph, render_mode); + if (error) { + printf("FT_Render_Glyph %s\n", FT_Error_String(error)); + return -1; + } + + struct glyph * glyph = &glyphs[char_code - 0x20]; + + glyph->width = face->glyph->bitmap.width; + glyph->height = face->glyph->bitmap.rows; + glyph->horiBearingX = face->glyph->metrics.horiBearingX; + glyph->horiBearingY = face->glyph->metrics.horiBearingY; + glyph->horiAdvance = face->glyph->metrics.horiAdvance; + + if (face->glyph->bitmap.pitch != 0) { + SDL_Surface * surface = SDL_CreateSurface(face->glyph->bitmap.width, + face->glyph->bitmap.rows, + SDL_PIXELFORMAT_RGBA8888); + + SDL_LockSurface(surface); + + for (int y = 0; y < face->glyph->bitmap.rows; y++) { + for (int x = 0; x < face->glyph->bitmap.width; x++) { + int s_ix = y * face->glyph->bitmap.pitch + x; + int d_ix = y * surface->pitch + x * 4; + uint8_t gray = face->glyph->bitmap.buffer[s_ix]; + ((uint8_t *)surface->pixels)[d_ix + 0] = gray; + ((uint8_t *)surface->pixels)[d_ix + 1] = gray; + ((uint8_t *)surface->pixels)[d_ix + 2] = gray; + ((uint8_t *)surface->pixels)[d_ix + 3] = 255; + } + } + + SDL_UnlockSurface(surface); + + if (glyph->texture != NULL) + SDL_DestroyTexture(glyph->texture); + glyph->texture = SDL_CreateTextureFromSurface(renderer, surface); + if (glyph->texture == NULL) { + printf("%s\n", SDL_GetError()); + } + assert(glyph->texture != NULL); + + SDL_DestroySurface(surface); + } + + return 0; +} + +int load_font(SDL_Renderer * renderer, int font_size) +{ + FT_Library library; + FT_Face face; + FT_Error error; + + error = FT_Init_FreeType(&library); + if (error) { + printf("FT_Init_FreeType\n"); + return -1; + } + + error = FT_New_Face(library, "DejaVuSansMono.ttf", 0, &face); + if (error) { + printf("FT_New_Face\n"); + return -1; + } + + error = FT_Set_Pixel_Sizes(face, 0, font_size); + if (error) { + printf("FT_Set_Pixel_Sizes: %s %d\n", FT_Error_String(error), error); + return -1; + } + + for (int char_code = 0x20; char_code <= 0x7f; char_code++) { + load_outline_char(renderer, face, FT_LOAD_DEFAULT, FT_RENDER_MODE_NORMAL, char_code); + } + + printf("loaded size %ld\n", face->size->metrics.height >> 6); + face_height = face->size->metrics.height; + + return 0; +} + +void render(SDL_Renderer * renderer, int window_width, int window_height, const char * s, int length) +{ + int32_t advance = (window_width - (window_width * 5 / 100)) << 6; + for (int i = (length - 1); i >= 0; i--) { + char c = s[i]; + struct glyph * glyph = &glyphs[c - 0x20]; + advance -= glyph->horiAdvance; + if (glyph->texture != NULL) { + double x = (double)(advance + glyph->horiBearingX) / 64.f; + double y = (window_height / 2) + (face_height >> 6) / 3 + ((double)glyph->horiBearingY / -64.f); + SDL_FRect srect = { + .x = 0.f, + .y = 0.f, + .w = glyph->width, + .h = glyph->height + }; + SDL_FRect drect = { + .x = x, + .y = y, + .w = glyph->width, + .h = glyph->height + }; + SDL_RenderTexture(renderer, glyph->texture, &srect, &drect); + } + } +} + +int max(int a, int b) { + return a > b ? a : b; +} -#define BUFLEN 512 #define PORT 1234 -int main(void) +void handle_buf(void * buf, ssize_t length, + struct timer_state * timer_state) +{ + struct event * evt = (struct event *)buf; + switch (evt->type) { + case EVENT_TYPE__TIME_STOP: + if (length != (sizeof (struct packet_stopwatch))) { + printf("handle_buf: event_stopwatch: invalid length\n"); + } + printf("handle_buf: event_stopwatch: valid length\n"); + + struct packet_stopwatch * time_evt = (struct packet_stopwatch *)buf; + memcpy(&timer_state->time, &time_evt->stopwatch_time, (sizeof (struct stopwatch_time))); + timer_state->status = TIMER_STOPPED; + break; + case EVENT_TYPE__TIME_START: + int ret = clock_gettime(CLOCK_MONOTONIC_RAW, &timer_state->counter.start); + assert(ret != -1); + timer_state->counter.offset.tv_sec = 0; + timer_state->counter.offset.tv_nsec = 0; + timer_state->status = TIMER_RUNNING; + break; + default: + printf("unhandled event %d\n", evt->type); + break; + } +} + +int handle_sockfd(int sockfd, struct timer_state * timer_state) +{ + char buf[BUFSIZE]; + struct sockaddr_in6 src_addr; + socklen_t addrlen = (sizeof (struct sockaddr_in6)); + + while (1) { + ssize_t recv_len = recvfrom(sockfd, + buf, (sizeof (buf)), + 0, + (struct sockaddr *)&src_addr, &addrlen); + if (recv_len == -1) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { + //perror("sock eagain"); + return 0; + } else { + perror("recvfrom sock"); + return -1; + } + } + + char src_addr_str[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, &src_addr.sin6_addr, src_addr_str, INET6_ADDRSTRLEN); + printf("Received packet from %s:%d\n", src_addr_str, ntohs(src_addr.sin6_port)); + printf("length: %ld\n", recv_len); + handle_buf(buf, recv_len, timer_state); + } + + return 0; +} + +int main() { int ret; + SDL_Window * window; + SDL_Renderer * renderer; - int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (sock == -1) { + ret = SDL_Init(SDL_INIT_VIDEO); + assert(ret == 0); + + window = SDL_CreateWindow("timer", + 512, // w + 512, // h + SDL_WINDOW_RESIZABLE);// | SDL_WINDOW_MAXIMIZED); + + renderer = SDL_CreateRenderer(window, NULL); + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); + + SDL_PropertiesID props = SDL_GetRendererProperties(renderer); + + const char * name = SDL_GetRendererName(renderer); + assert(name != NULL); + printf("renderer: %s\n", name); + const SDL_PixelFormatEnum * formats = SDL_GetProperty(props, SDL_PROP_RENDERER_TEXTURE_FORMATS_POINTER, NULL); + assert(formats != NULL); + while (*formats != SDL_PIXELFORMAT_UNKNOWN) { + printf("%s\n", SDL_GetPixelFormatName(*formats++)); + } + + int last_width = -1; + + uint64_t ticks = SDL_GetTicks(); + const int min_length = 5; + int max_length = min_length; + + /* + socket + */ + + int sockfd = socket(AF_INET6, SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP); + if (sockfd == -1) { perror("socket"); return -1; } - struct sockaddr_in sockaddr = {0}; - sockaddr.sin_family = AF_INET; - sockaddr.sin_port = htons(PORT); - sockaddr.sin_addr.s_addr = htonl(INADDR_ANY); + struct sockaddr_in6 sockaddr; + sockaddr.sin6_family = AF_INET6; + sockaddr.sin6_port = htons(PORT); + sockaddr.sin6_addr = in6addr_any; - ret = bind(sock, (struct sockaddr *)&sockaddr, (sizeof (struct sockaddr_in))); + ret = bind(sockfd, (struct sockaddr *)&sockaddr, (sizeof (struct sockaddr_in6))); if (ret == -1) { perror("bind"); return -1; } - char buf[BUFLEN]; + /* + */ + + struct timer_state timer_state = {0}; while (1) { - printf("Wait for datagram\n"); + handle_sockfd(sockfd, &timer_state); - struct sockaddr_in src_addr = {0}; - socklen_t addrlen = (sizeof (struct sockaddr_in)); + char str_buf[16]; + switch (timer_state.status) { + case TIMER_STOPPED: + snprintf(str_buf, (sizeof (str_buf)) - 1, "%d.%02d", timer_state.time.integer_value, timer_state.time.fraction_value); + break; + case TIMER_RUNNING: + { + struct timespec now; + int ret = clock_gettime(CLOCK_MONOTONIC_RAW, &now); + assert(ret != -1); - ssize_t recv_len = recvfrom(sock, buf, BUFLEN, 0, (struct sockaddr *)&src_addr, &addrlen); - if (recv_len == -1) { - perror("recvfrom"); - return -1; + double now_d = (double)now.tv_sec + ((double)now.tv_nsec / 1000000000.f); + struct timespec * start = &timer_state.counter.start; + double start_d = (double)start->tv_sec + ((double)start->tv_nsec / 1000000000.f); + double duration = now_d - start_d; + + snprintf(str_buf, (sizeof (str_buf)) - 1, "%.02f", duration); + } + break; + default: + str_buf[0] = 0; + break; + } + int length = strlen(str_buf); + + SDL_RenderClear(renderer); + int window_width; + int window_height; + ret = SDL_GetWindowSizeInPixels(window, &window_width, &window_height); + assert(ret == 0); + if ((window_width != last_width) || (length > max_length)) { + max_length = max(min_length, length); + last_width = window_width; + + int divisor = max(1, (max_length * 8 / 10)); + int font_size = (window_width * 95 / 100) / divisor; + printf("fs %d %d max_length: %d\n", font_size, window_width, max_length); + load_font(renderer, font_size); } - buf[recv_len] = 0; - printf("Received packet from %s:%d\n", inet_ntoa(src_addr.sin_addr), ntohs(src_addr.sin_port)); - printf("Data: %s\n", buf); + render(renderer, window_width, window_height, str_buf, length); + + while (SDL_GetTicks() - ticks < (1000 / 60)) { SDL_Delay(1); } + SDL_RenderPresent(renderer); + ticks = SDL_GetTicks(); + + SDL_Event event; + while (SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_EVENT_QUIT: + goto exit; + case SDL_EVENT_KEY_DOWN: + if (event.key.keysym.sym == SDLK_ESCAPE) + goto exit; + break; + default: + break; + } + - /* - //now reply the client with the same data - if (sendto(s, buf, recv_len, 0, (struct sockaddr*) &si_other, slen) == -1) { - die("sendto()"); } - */ } - close(sock); - - return 0; + exit: + SDL_DestroyRenderer(renderer); + SDL_DestroyWindow(window); + SDL_Quit(); + close(sockfd); } diff --git a/timer.c b/timer.c deleted file mode 100644 index d43664e..0000000 --- a/timer.c +++ /dev/null @@ -1,270 +0,0 @@ -#include -#include -#include - -#include -#include FT_FREETYPE_H - -#include - -#include - -struct glyph { - int32_t width; - int32_t height; - - int32_t horiBearingX; - int32_t horiBearingY; - int32_t horiAdvance; - - SDL_Texture * texture; -}; - -static struct glyph glyphs[0x80 - 0x20] = {0}; -int32_t face_height; - -int -load_outline_char(SDL_Renderer * renderer, - const FT_Face face, - const FT_Int32 load_flags, - const FT_Render_Mode render_mode, - const FT_ULong char_code) -{ - FT_Error error; - FT_UInt glyph_index = FT_Get_Char_Index(face, char_code); - - error = FT_Load_Glyph(face, glyph_index, load_flags); - if (error) { - printf("FT_Load_Glyph %s\n", FT_Error_String(error)); - return -1; - } - - error = FT_Render_Glyph(face->glyph, render_mode); - if (error) { - printf("FT_Render_Glyph %s\n", FT_Error_String(error)); - return -1; - } - - struct glyph * glyph = &glyphs[char_code - 0x20]; - - glyph->width = face->glyph->bitmap.width; - glyph->height = face->glyph->bitmap.rows; - glyph->horiBearingX = face->glyph->metrics.horiBearingX; - glyph->horiBearingY = face->glyph->metrics.horiBearingY; - glyph->horiAdvance = face->glyph->metrics.horiAdvance; - - if (face->glyph->bitmap.pitch != 0) { - SDL_Surface * surface = SDL_CreateSurface(face->glyph->bitmap.width, - face->glyph->bitmap.rows, - SDL_PIXELFORMAT_RGBA8888); - - SDL_LockSurface(surface); - - for (int y = 0; y < face->glyph->bitmap.rows; y++) { - for (int x = 0; x < face->glyph->bitmap.width; x++) { - int s_ix = y * face->glyph->bitmap.pitch + x; - int d_ix = y * surface->pitch + x * 4; - uint8_t gray = face->glyph->bitmap.buffer[s_ix]; - ((uint8_t *)surface->pixels)[d_ix + 0] = gray; - ((uint8_t *)surface->pixels)[d_ix + 1] = gray; - ((uint8_t *)surface->pixels)[d_ix + 2] = gray; - ((uint8_t *)surface->pixels)[d_ix + 3] = 255; - } - } - - SDL_UnlockSurface(surface); - - if (glyph->texture != NULL) - SDL_DestroyTexture(glyph->texture); - glyph->texture = SDL_CreateTextureFromSurface(renderer, surface); - if (glyph->texture == NULL) { - printf("%s\n", SDL_GetError()); - } - assert(glyph->texture != NULL); - - SDL_DestroySurface(surface); - } - - return 0; -} - -int load_font(SDL_Renderer * renderer, int font_size) -{ - FT_Library library; - FT_Face face; - FT_Error error; - - error = FT_Init_FreeType(&library); - if (error) { - printf("FT_Init_FreeType\n"); - return -1; - } - - error = FT_New_Face(library, "DejaVuSansMono.ttf", 0, &face); - if (error) { - printf("FT_New_Face\n"); - return -1; - } - - error = FT_Set_Pixel_Sizes(face, 0, font_size); - if (error) { - printf("FT_Set_Pixel_Sizes: %s %d\n", FT_Error_String(error), error); - return -1; - } - - for (int char_code = 0x20; char_code <= 0x7f; char_code++) { - load_outline_char(renderer, face, FT_LOAD_DEFAULT, FT_RENDER_MODE_NORMAL, char_code); - } - - printf("loaded size %ld\n", face->size->metrics.height >> 6); - face_height = face->size->metrics.height; - - return 0; -} - -void render(SDL_Renderer * renderer, int window_width, int window_height, const char * s, int length) -{ - int32_t advance = (window_width - (window_width * 5 / 100)) << 6; - for (int i = (length - 1); i >= 0; i--) { - char c = s[i]; - struct glyph * glyph = &glyphs[c - 0x20]; - advance -= glyph->horiAdvance; - if (glyph->texture != NULL) { - float x = (float)(advance + glyph->horiBearingX) / 64.f; - float y = (window_height / 2) + (face_height >> 6) / 3 + (float)(-glyph->horiBearingY) / 64.f; - SDL_FRect srect = { - .x = 0.f, - .y = 0.f, - .w = glyph->width, - .h = glyph->height - }; - SDL_FRect drect = { - .x = x, - .y = y, - .w = glyph->width, - .h = glyph->height - }; - SDL_RenderTexture(renderer, glyph->texture, &srect, &drect); - } - } -} - -int max(int a, int b) { - return a > b ? a : b; -} - -int main() -{ - int ret; - SDL_Window * window; - SDL_Renderer * renderer; - - ret = SDL_Init(SDL_INIT_VIDEO); - assert(ret == 0); - - window = SDL_CreateWindow("timer", - 512, // w - 512, // h - SDL_WINDOW_RESIZABLE);// | SDL_WINDOW_MAXIMIZED); - - renderer = SDL_CreateRenderer(window, NULL); - SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); - - SDL_PropertiesID props = SDL_GetRendererProperties(renderer); - - const char * name = SDL_GetRendererName(renderer); - assert(name != NULL); - printf("renderer: %s\n", name); - const SDL_PixelFormatEnum * formats = SDL_GetProperty(props, SDL_PROP_RENDERER_TEXTURE_FORMATS_POINTER, NULL); - assert(formats != NULL); - while (*formats != SDL_PIXELFORMAT_UNKNOWN) { - printf("%s\n", SDL_GetPixelFormatName(*formats++)); - } - - int last_width = -1; - - uint64_t ticks = SDL_GetTicks(); - const int min_length = 4; - int max_length = min_length; - - /* - */ - - uint8_t read_buf[32] = {'7', '1', '.', '0', '1', '\r'}; - - struct state state = {0}; - - int i = 0; - while (1) { - i++; - //enum sp_return sp_ret = sp_nonblocking_read(port, read_buf, (sizeof (read_buf))); - enum sp_return sp_ret = 6; - if (sp_ret < 0) { - printf("sp_nonblocking_read error\n"); - break; - } - handle_state(read_buf, sp_ret, &state); - - char str_buf[16]; - switch (state.counter_state) { - case COUNTER_STOPPED: - snprintf(str_buf, (sizeof (str_buf)) - 1, "%d.%02d", state.time.whole, state.time.fraction); - break; - case COUNTER_RUNNING: - { - uint64_t counter = SDL_GetPerformanceCounter(); - uint64_t frequency = SDL_GetPerformanceFrequency(); - double duration = (((double)counter) - ((double)state.counter)) / ((double)frequency); - - snprintf(str_buf, (sizeof (str_buf)) - 1, "%.02f", duration); - } - break; - default: - str_buf[0] = 0; - break; - } - int length = strlen(str_buf); - - SDL_RenderClear(renderer); - int window_width; - int window_height; - ret = SDL_GetWindowSizeInPixels(window, &window_width, &window_height); - assert(ret == 0); - if ((window_width != last_width) || (length > max_length)) { - max_length = max(min_length, length); - last_width = window_width; - - int divisor = max(1, (max_length * 8 / 10)); - int font_size = (window_width * 95 / 100) / divisor; - printf("fs %d %d %d\n", font_size, window_width, max_length); - load_font(renderer, font_size); - } - - render(renderer, window_width, window_height, str_buf, length); - - while (SDL_GetTicks() - ticks < (1000 / 60)) { SDL_Delay(1); } - SDL_RenderPresent(renderer); - ticks = SDL_GetTicks(); - - SDL_Event event; - while (SDL_PollEvent(&event)) { - switch (event.type) { - case SDL_EVENT_QUIT: - goto exit; - case SDL_EVENT_KEY_DOWN: - if (event.key.keysym.sym == SDLK_ESCAPE) - goto exit; - break; - default: - break; - } - - - } - } - - exit: - SDL_DestroyRenderer(renderer); - SDL_DestroyWindow(window); - SDL_Quit(); -} diff --git a/timer.h b/timer.h index 61df870..08b55b2 100644 --- a/timer.h +++ b/timer.h @@ -1,6 +1,7 @@ #pragma once #include +#include enum timer_status { TIMER_STOPPED, @@ -15,12 +16,21 @@ struct stopwatch_time { }; struct running_counter { - struct timespec start; // CLOCK_MONOTONIC (relative) - struct timespec offset; // CLOCK_MONOTONIC (relative) + struct timespec start; // (absolute) + struct timespec offset; // (relative) }; struct timer_state { - enum timer_status status; struct running_counter counter; struct stopwatch_time time; + enum timer_status status; + int _pad; }; + +static_assert((sizeof (struct running_counter)) == (8 * 2) * 2); +static_assert((sizeof (struct stopwatch_time)) == 4 * 4); +static_assert((sizeof (enum timer_status)) == 4); +static_assert((sizeof (struct timer_state)) == ((8 * 2) * 2) + (4 * 4) + 4 + 4); +static_assert((offsetof (struct timer_state, counter)) == 0); +static_assert((offsetof (struct timer_state, time )) == (8 * 2) * 2); +static_assert((offsetof (struct timer_state, status )) == ((8 * 2) * 2) + (4 * 4));