duplicate send, resend, ack

The 'software' renderer is now explicitly requested.
This commit is contained in:
Zack Buhman 2024-06-26 02:44:07 -05:00
parent 16eaa08244
commit 8c1c1e97f6
12 changed files with 267 additions and 97 deletions

View File

@ -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')

10
gpio.c
View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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) {

View File

@ -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:

View File

@ -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,

View File

@ -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) {

View File

@ -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;
}
}
}

View File

@ -2,6 +2,7 @@
#include <time.h>
#include <stddef.h>
#include <assert.h>
enum timer_status {
TIMER_STOPPED,

View File

@ -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;
}

View File

@ -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);