duplicate send, resend, ack
The 'software' renderer is now explicitly requested.
This commit is contained in:
parent
16eaa08244
commit
8c1c1e97f6
2
Makefile
2
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')
|
||||
|
||||
|
10
gpio.c
10
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
87
packet.c
87
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;
|
||||
}
|
||||
|
||||
|
18
packet.h
18
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);
|
||||
|
@ -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) {
|
||||
|
10
ping_pong.c
10
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:
|
||||
|
@ -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,
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
1
timer.h
1
timer.h
@ -2,6 +2,7 @@
|
||||
|
||||
#include <time.h>
|
||||
#include <stddef.h>
|
||||
#include <assert.h>
|
||||
|
||||
enum timer_status {
|
||||
TIMER_STOPPED,
|
||||
|
21
timespec.c
21
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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user