From 8c1c1e97f6a31515e58ef137f240c2071fdbaea1 Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Wed, 26 Jun 2024 02:44:07 -0500 Subject: [PATCH] duplicate send, resend, ack The 'software' renderer is now explicitly requested. --- Makefile | 2 +- gpio.c | 10 ++-- packet.c | 87 ++++++++++++++++++++++--------- packet.h | 18 +++++-- parse_serial.c | 2 +- ping_pong.c | 10 ++-- ping_pong.h | 2 +- serial_forwarder.c | 124 ++++++++++++++++++++++++++++++++++++--------- time_display.c | 84 ++++++++++++++++++++---------- timer.h | 1 + timespec.c | 21 +++++--- timespec.h | 3 ++ 12 files changed, 267 insertions(+), 97 deletions(-) diff --git a/Makefile b/Makefile index 0d2ffe5..4041c03 100644 --- a/Makefile +++ b/Makefile @@ -43,7 +43,7 @@ serial_forwarder: $(SERIAL_FORWARDER_OBJS) $(CC) $^ -o $@ time_display: $(TIME_DISPLAY_OBJS) - $(CC) $(LDFLAGS) $^ -o $@ + $(CC) $^ -o $@ $(LDFLAGS) -include $(shell find -type f -name '*.d') diff --git a/gpio.c b/gpio.c index 2d027fd..9bc21cc 100644 --- a/gpio.c +++ b/gpio.c @@ -66,13 +66,13 @@ void gpio_set_values_from_link_state(struct gpio_state * gpio_state, struct timespec delta = timespec_sub(&now, &link_state->last_pong); if (delta.tv_sec >= LAST_PONG_TIMEOUT) { - printf("pong timeout %ld\n", delta.tv_sec); - if (gpio_state->chip_fd != -1) - gpio_set_values(gpio_state, GREEN); - } else { - printf("pong ok %ld\n", delta.tv_sec); + printf("gpio pong timeout %ld\n", delta.tv_sec); if (gpio_state->chip_fd != -1) gpio_set_values(gpio_state, RED); + } else { + printf("gpio pong ok %ld\n", delta.tv_sec); + if (gpio_state->chip_fd != -1) + gpio_set_values(gpio_state, GREEN); } } diff --git a/packet.c b/packet.c index 9242107..1eab0db 100644 --- a/packet.c +++ b/packet.c @@ -5,6 +5,9 @@ #include "link.h" #include "timer.h" #include "packet.h" +#include "timespec.h" + +#define DUPLICATE_SEND 3 int packet_send_ping(int sockfd, struct sockaddr_in6 * dest_addr) @@ -56,12 +59,12 @@ int packet_send_pong(int sockfd, int packet_send_average_rtt(int sockfd, struct sockaddr_in6 * dest_addr, - struct timespec * time) + struct timespec * offset) { - struct packet_ping_pong pkt; + struct packet_average_rtt pkt; pkt.event.type = EVENT_TYPE__AVERAGE_RTT; pkt.event.sequence = 0; - memcpy(&pkt.time, time, (sizeof (struct timespec))); + memcpy(&pkt.offset, offset, (sizeof (struct timespec))); int ret = sendto(sockfd, &pkt, (sizeof (pkt)), @@ -83,16 +86,18 @@ int packet_send_start_event(int sockfd, { struct packet_start pkt; pkt.event.type = EVENT_TYPE__TIME_START; - pkt.event.sequence = link_state->send_sequence++; + pkt.event.sequence = ++link_state->send_sequence; - int ret = sendto(sockfd, - &pkt, (sizeof (pkt)), - 0, - (struct sockaddr *)dest_addr, - (sizeof (struct sockaddr_in6))); - if (ret == -1) { - perror("packet_send_start_event sendto"); - return -1; + for (int i = 0; i < DUPLICATE_SEND; i++) { + int ret = sendto(sockfd, + &pkt, (sizeof (pkt)), + 0, + (struct sockaddr *)dest_addr, + (sizeof (struct sockaddr_in6))); + if (ret == -1) { + perror("packet_send_start_event sendto"); + return -1; + } } return 0; @@ -100,20 +105,28 @@ int packet_send_start_event(int sockfd, int packet_send_resume_event(int sockfd, struct sockaddr_in6 * dest_addr, + struct timer_state * timer_state, struct link_state * link_state) { - struct packet_start pkt; + struct packet_resume pkt; pkt.event.type = EVENT_TYPE__TIME_RESUME; - pkt.event.sequence = link_state->send_sequence++; + pkt.event.sequence = ++link_state->send_sequence; + struct timespec now; + int ret = clock_gettime(CLOCK_MONOTONIC_RAW, &now); + assert(ret != -1); + pkt.offset = timespec_sub(&now, &timer_state->counter.start); + printf("resume offset %ld.%09ld\n", pkt.offset.tv_sec, pkt.offset.tv_nsec); - int ret = sendto(sockfd, - &pkt, (sizeof (pkt)), - 0, - (struct sockaddr *)dest_addr, - (sizeof (struct sockaddr_in6))); - if (ret == -1) { - perror("packet_send_resume_event sendto"); - return -1; + for (int i = 0; i < DUPLICATE_SEND; i++) { + int ret = sendto(sockfd, + &pkt, (sizeof (pkt)), + 0, + (struct sockaddr *)dest_addr, + (sizeof (struct sockaddr_in6))); + if (ret == -1) { + perror("packet_send_resume_event sendto"); + return -1; + } } return 0; @@ -126,16 +139,40 @@ int packet_send_stopwatch_event(int sockfd, { struct packet_stopwatch pkt; pkt.event.type = EVENT_TYPE__TIME_STOP; - pkt.event.sequence = link_state->send_sequence++; + pkt.event.sequence = ++link_state->send_sequence; memcpy(&pkt.stopwatch_time, &timer_state->time, (sizeof (struct stopwatch_time))); + for (int i = 0; i < DUPLICATE_SEND; i++) { + int ret = sendto(sockfd, + &pkt, (sizeof (pkt)), + 0, + (struct sockaddr *)dest_addr, + (sizeof (struct sockaddr_in6))); + if (ret == -1) { + perror("packet_send_stopwatch_event sendto"); + return -1; + } + } + + return 0; +} + +int packet_send_ack(int sockfd, + struct sockaddr_in6 * dest_addr, + uint32_t sequence) +{ + struct packet_ack pkt; + pkt.event.type = EVENT_TYPE__ACK; + pkt.event.sequence = sequence; + int ret = sendto(sockfd, - &pkt, (sizeof (pkt)), + &pkt, (sizeof (pkt)), 0, (struct sockaddr *)dest_addr, (sizeof (struct sockaddr_in6))); + if (ret == -1) { - perror("packet_send_stopwatch_event sendto"); + perror("packet_send_pong sendto"); return -1; } diff --git a/packet.h b/packet.h index c25aff1..24417ce 100644 --- a/packet.h +++ b/packet.h @@ -38,18 +38,26 @@ struct packet_start { static_assert((sizeof (struct packet_start)) == (sizeof (struct event))); +struct packet_resume { + struct event event; + struct timespec offset; +}; + +static_assert((sizeof (struct packet_resume)) == + (sizeof (struct event)) + (sizeof (struct timespec))); + struct packet_ack { struct event event; }; static_assert((sizeof (struct packet_ack)) == (sizeof (struct event))); -struct packet_rtt_delay { +struct packet_average_rtt { struct event event; struct timespec offset; }; -static_assert((sizeof (struct packet_rtt_delay)) == (sizeof (struct event)) + (sizeof (struct timespec))); +static_assert((sizeof (struct packet_average_rtt)) == (sizeof (struct event)) + (sizeof (struct timespec))); struct packet_ping_pong { struct event event; @@ -63,15 +71,19 @@ int packet_send_pong(int sockfd, struct timespec * time); int packet_send_average_rtt(int sockfd, struct sockaddr_in6 * dest_addr, - struct timespec * time); + struct timespec * offset); int packet_send_start_event(int sockfd, struct sockaddr_in6 * dest_addr, struct link_state * link_state); int packet_send_resume_event(int sockfd, struct sockaddr_in6 * dest_addr, + struct timer_state * timer_state, struct link_state * link_state); int packet_send_stopwatch_event(int sockfd, struct sockaddr_in6 * dest_addr, struct timer_state * timer_state, struct link_state * link_state); +int packet_send_ack(int sockfd, + struct sockaddr_in6 * dest_addr, + uint32_t sequence); diff --git a/parse_serial.c b/parse_serial.c index 5cc1b35..257699e 100644 --- a/parse_serial.c +++ b/parse_serial.c @@ -94,7 +94,7 @@ uint32_t handle_line(uint8_t const * const buf, int length, return EVENT_TYPE__TIME_START; } else if (is_timer_resume(buf, length)) { timer_state->status = TIMER_RUNNING; - return EVENT_TYPE__TIME_START; + return EVENT_TYPE__TIME_RESUME; } else { int ret = parse_time(buf, length, &timer_state->time); if (ret == 0) { diff --git a/ping_pong.c b/ping_pong.c index 473aab5..8768330 100644 --- a/ping_pong.c +++ b/ping_pong.c @@ -55,13 +55,15 @@ int handle_ping_pong(int sockfd, break; case EVENT_TYPE__AVERAGE_RTT: { - if (length != (sizeof (struct packet_ping_pong))) { - printf("handle_ping_pong: average_rtt: invalid length\n"); + if (length != (sizeof (struct packet_average_rtt))) { + printf("handle_average_rtt: average_rtt: invalid length\n"); return 0; // recoverable } - struct packet_ping_pong * ping_pkt = (struct packet_ping_pong *)buf; + struct packet_average_rtt * ping_pkt = (struct packet_average_rtt *)buf; - printf("recv average_rtt: %ld.%09ld\n", ping_pkt->time.tv_sec, ping_pkt->time.tv_nsec); + printf("recv average_rtt: %ld.%09ld\n", ping_pkt->offset.tv_sec, ping_pkt->offset.tv_nsec); + + link_state->remote_average_rtt = ping_pkt->offset; } break; default: diff --git a/ping_pong.h b/ping_pong.h index 3103f11..e72a2c1 100644 --- a/ping_pong.h +++ b/ping_pong.h @@ -4,7 +4,7 @@ #include "link.h" -#define PING_INTERVAL 5 +#define PING_INTERVAL 1 int handle_ping_pong(int sockfd, struct sockaddr_in6 * dest_addr, diff --git a/serial_forwarder.c b/serial_forwarder.c index 0c9cf0c..4e773ef 100644 --- a/serial_forwarder.c +++ b/serial_forwarder.c @@ -20,6 +20,7 @@ #include "link.h" #include "timespec.h" #include "ping_pong.h" +#include "gpio.h" #define PORT 4321 //#define SERIALPORT "/dev/ttyS0" @@ -47,6 +48,10 @@ int handle_buf(int sockfd, } } break; + case EVENT_TYPE__ACK: + printf("recv ack %d\n", evt->sequence); + link_state->recv_sequence = evt->sequence; + break; default: printf("unhandled event %d\n", evt->type); break; @@ -108,10 +113,76 @@ int rearm_timer(int timerfd) return 0; } +int handle_event(int sockfd, + struct sockaddr_in6 * dest_addr, + struct timer_state * timer_state, + struct link_state * link_state, + uint32_t type) +{ + int ret; + switch (type) { + case EVENT_TYPE__TIME_STOP: + printf("event time stop\n"); + ret = packet_send_stopwatch_event(sockfd, dest_addr, timer_state, link_state); + if (ret == -1) { + return -1; + } + break; + case EVENT_TYPE__TIME_START: + printf("event time start\n"); + ret = packet_send_start_event(sockfd, dest_addr, link_state); + if (ret == -1) { + return -1; + } + break; + case EVENT_TYPE__TIME_RESUME: + printf("event time resume\n"); + ret = packet_send_resume_event(sockfd, dest_addr, timer_state, link_state); + if (ret == -1) { + return -1; + } + break; + default: + break; + } + return 0; +} + +int check_sequence(int sockfd, + struct sockaddr_in6 * dest_addr, + struct timer_state * timer_state, + struct link_state * link_state) +{ + printf("check_sequence send %ld recv: %ld\n", link_state->send_sequence, link_state->recv_sequence); + + if (link_state->send_sequence != link_state->recv_sequence) { + switch (timer_state->status) { + case TIMER_STOPPED: + handle_event(sockfd, + dest_addr, + timer_state, + link_state, + EVENT_TYPE__TIME_STOP); + break; + case TIMER_RUNNING: + handle_event(sockfd, + dest_addr, + timer_state, + link_state, + EVENT_TYPE__TIME_RESUME); + break; + } + } + + return 0; +} + int handle_timerfd(int timerfd, int sockfd, struct sockaddr_in6 * dest_addr, - struct link_state * link_state) + struct timer_state * timer_state, + struct link_state * link_state, + struct gpio_state * gpio_state) { uint64_t expired_count = 0; while (true) { @@ -130,11 +201,23 @@ int handle_timerfd(int timerfd, rearm_timer(timerfd); - int ret = packet_send_ping(sockfd, dest_addr); + int ret; + ret = packet_send_ping(sockfd, dest_addr); if (ret == -1) { return -1; } + ret = check_sequence(sockfd, + dest_addr, + timer_state, + link_state); + if (ret == -1) { + return -1; + } + + gpio_set_values_from_link_state(gpio_state, + link_state); + return 0; } @@ -168,28 +251,13 @@ int handle_serialfd(int serialfd, uint32_t type = handle_parse(buf, len, parser_state, timer_state); - int ret; - switch (type) { - case EVENT_TYPE__TIME_STOP: - ret = packet_send_stopwatch_event(sockfd, dest_addr, timer_state, link_state); - if (ret == -1) { - return -1; - } - break; - case EVENT_TYPE__TIME_START: - ret = packet_send_start_event(sockfd, dest_addr, link_state); - if (ret == -1) { - return -1; - } - break; - case EVENT_TYPE__TIME_RESUME: - ret = packet_send_resume_event(sockfd, dest_addr, link_state); - if (ret == -1) { - return -1; - } - break; - default: - break; + int ret = handle_event(sockfd, + dest_addr, + timer_state, + link_state, + type); + if (ret == -1) { + return -1; } } @@ -291,6 +359,10 @@ int main(void) struct parser_state parser_state = {0}; struct timer_state timer_state = {0}; struct link_state link_state = {0}; + struct gpio_state gpio_state = {0}; + + gpio_open("/dev/gpiochip0", &gpio_state); + // ignored gpio_open error while (1) { int nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1); @@ -308,7 +380,9 @@ int main(void) ret = handle_timerfd(timerfd, sockfd, &dest_addr, - &link_state); + &timer_state, + &link_state, + &gpio_state); if (ret == -1) return -1; } else if (events[n].data.fd == serialfd) { diff --git a/time_display.c b/time_display.c index 2b9a289..fd486aa 100644 --- a/time_display.c +++ b/time_display.c @@ -172,36 +172,62 @@ int handle_buf(int sockfd, struct link_state * link_state) { struct event * evt = (struct event *)buf; + + if (evt->sequence != 0) { + if (evt->sequence == link_state->recv_sequence) { + printf("ignore duplicate seq %d; recv %ld type %d\n", evt->sequence, link_state->recv_sequence, evt->type); + return 0; + } else { + printf("type %d seq %d\n", evt->sequence, evt->type); + link_state->recv_sequence = evt->sequence; + } + } + switch (evt->type) { case EVENT_TYPE__TIME_STOP: - if (length != (sizeof (struct packet_stopwatch))) { - printf("handle_buf: packet_stopwatch: invalid length\n"); - return 0; - } + { + if (length != (sizeof (struct packet_stopwatch))) { + printf("handle_buf: packet_stopwatch: invalid length\n"); + return 0; + } - struct packet_stopwatch * time_pkt = (struct packet_stopwatch *)buf; - memcpy(&timer_state->time, &time_pkt->stopwatch_time, (sizeof (struct stopwatch_time))); - timer_state->status = TIMER_STOPPED; + struct packet_stopwatch * time_pkt = (struct packet_stopwatch *)buf; + memcpy(&timer_state->time, &time_pkt->stopwatch_time, (sizeof (struct stopwatch_time))); + timer_state->status = TIMER_STOPPED; + packet_send_ack(sockfd, dest_addr, evt->sequence); + } break; case EVENT_TYPE__TIME_START: - if (length != (sizeof (struct event))) { - printf("handle_buf: time start: invalid length\n"); - return 0; - } + { + if (length != (sizeof (struct packet_start))) { + printf("handle_buf: time start: invalid length\n"); + return 0; + } - 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; + int ret = clock_gettime(CLOCK_MONOTONIC_RAW, &timer_state->counter.start); + assert(ret != -1); + timer_state->counter.offset = timespec_div(&link_state->remote_average_rtt, 2); + printf("counter_offset %ld.%09ld\n", timer_state->counter.offset.tv_sec, timer_state->counter.offset.tv_nsec); + timer_state->status = TIMER_RUNNING; + packet_send_ack(sockfd, dest_addr, evt->sequence); + } break; case EVENT_TYPE__TIME_RESUME: - if (length != (sizeof (struct event))) { - printf("handle_buf: time resume: invalid length\n"); - return 0; + { + if (length != (sizeof (struct packet_resume))) { + printf("handle_buf: time resume: invalid length\n"); + return 0; + } + struct packet_resume * resume_pkt = (struct packet_resume *)buf; + printf("resume offset %ld.%09ld\n", resume_pkt->offset.tv_sec, resume_pkt->offset.tv_nsec); + int ret = clock_gettime(CLOCK_MONOTONIC_RAW, &timer_state->counter.start); + assert(ret != -1); + timer_state->counter.offset = timespec_div(&link_state->remote_average_rtt, 2); + timer_state->counter.offset = timespec_add(&timer_state->counter.offset, &resume_pkt->offset); + printf("counter offset %ld.%09ld\n", timer_state->counter.offset.tv_sec, timer_state->counter.offset.tv_nsec); + timer_state->status = TIMER_RUNNING; + packet_send_ack(sockfd, dest_addr, evt->sequence); } - - timer_state->status = TIMER_RUNNING; break; case EVENT_TYPE__PING: [[fallthrough]]; case EVENT_TYPE__PONG: [[fallthrough]]; @@ -294,7 +320,13 @@ int main() 512, // h SDL_WINDOW_RESIZABLE);// | SDL_WINDOW_MAXIMIZED); - renderer = SDL_CreateRenderer(window, NULL); + int num_drivers = SDL_GetNumRenderDrivers(); + printf("available drivers:\n"); + for (int i = 0; i < num_drivers; i++) { + const char * s = SDL_GetRenderDriver(i); + printf(" %s\n", s); + } + renderer = SDL_CreateRenderer(window, "software"); SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); SDL_PropertiesID props = SDL_GetRendererProperties(renderer); @@ -376,10 +408,11 @@ int main() int ret = clock_gettime(CLOCK_MONOTONIC_RAW, &now); assert(ret != -1); - struct timespec duration = timespec_sub(&now, &timer_state.counter.start); + struct timespec real_start = timespec_sub(&timer_state.counter.start, &timer_state.counter.offset); + struct timespec duration = timespec_sub(&now, &real_start); snprintf(str_buf, (sizeof (str_buf)) - 1, - "%ld.%ld", + "%ld.%02ld", duration.tv_sec, duration.tv_nsec / (1000000000 / 100)); // 2 digits } @@ -390,6 +423,7 @@ int main() } int length = strlen(str_buf); + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); SDL_RenderClear(renderer); int window_width; int window_height; @@ -433,8 +467,6 @@ int main() default: break; } - - } } diff --git a/timer.h b/timer.h index 08b55b2..87d6b7f 100644 --- a/timer.h +++ b/timer.h @@ -2,6 +2,7 @@ #include #include +#include enum timer_status { TIMER_STOPPED, diff --git a/timespec.c b/timespec.c index d73429a..77b0002 100644 --- a/timespec.c +++ b/timespec.c @@ -31,6 +31,18 @@ struct timespec timespec_add(const struct timespec * a, return c; } +struct timespec timespec_div(const struct timespec * a, + int n) +{ + int64_t rem = a->tv_sec % n; + struct timespec c = { + .tv_sec = a->tv_sec / n, + .tv_nsec = (a->tv_nsec / n) + (rem * 1000000000 / n) + }; + assert(c.tv_nsec < 1000000000); + return c; +} + struct timespec timespec_average(const struct timespec * ts, int length) { @@ -39,10 +51,7 @@ struct timespec timespec_average(const struct timespec * ts, c = timespec_add(&c, &ts[i]); //printf("rtt[%d]: %ld.%09ld\n", i, ts[i].tv_sec, ts[i].tv_nsec); } - int64_t rem = c.tv_sec % length; - c.tv_sec /= length; - c.tv_nsec = (c.tv_nsec / length) + (rem * 1000000000 / length); - assert(c.tv_nsec < 1000000000); - //printf("average: %ld.%09ld\n", c.tv_sec, c.tv_nsec); - return c; + struct timespec d = timespec_div(&c, length); + //printf("average: %ld.%09ld\n", d.tv_sec, d.tv_nsec); + return d; } diff --git a/timespec.h b/timespec.h index 2494920..6bdd088 100644 --- a/timespec.h +++ b/timespec.h @@ -8,5 +8,8 @@ struct timespec timespec_sub(const struct timespec * a, struct timespec timespec_add(const struct timespec * a, const struct timespec * b); +struct timespec timespec_div(const struct timespec * a, + int n); + struct timespec timespec_average(const struct timespec * ts, int length);