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 355dcf9..0000000 Binary files a/serial_forwarder and /dev/null differ 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));