initial: incomplete
This commit is contained in:
commit
8623d7cd86
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
*.out
|
||||
*.o
|
||||
*.gch
|
||||
*.d
|
||||
main
|
BIN
DejaVuSansMono.ttf
Normal file
BIN
DejaVuSansMono.ttf
Normal file
Binary file not shown.
40
Makefile
Normal file
40
Makefile
Normal file
@ -0,0 +1,40 @@
|
||||
SDL ?= ../SDL
|
||||
|
||||
DEBUG = -g -gdwarf-4
|
||||
|
||||
CFLAGS += -Wall -Werror -Wfatal-errors
|
||||
CFLAGS += -std=c2x
|
||||
CFLAGS += -I$(SDL)/include -D_REENTRANT
|
||||
CFLAGS += -I/usr/local/include
|
||||
CFLAGS += $(shell pkg-config --cflags freetype2)
|
||||
LDFLAGS += -L$(SDL)/build -lSDL3 -Wl,-rpath=$(SDL)/build
|
||||
LDFLAGS += -Wl,-rpath,/usr/local/lib -L/usr/local/lib -lserialport
|
||||
LDFLAGS += $(shell pkg-config --libs freetype2)
|
||||
|
||||
DEPFLAGS = -MMD -MP
|
||||
|
||||
OPT = -O3 -march=native
|
||||
|
||||
OBJS = \
|
||||
timer.o
|
||||
|
||||
all: main
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CARCH) $(CFLAGS) $(OPT) $(DEBUG) $(DEPFLAGS) -MF ${<}.d -c $< -o $@
|
||||
|
||||
main: $(OBJS)
|
||||
$(CC) $(LDFLAGS) $^ -o $@
|
||||
|
||||
-include $(shell find -type f -name '*.d')
|
||||
|
||||
.SUFFIXES:
|
||||
.INTERMEDIATE:
|
||||
.SECONDARY:
|
||||
.PHONY: all clean
|
||||
|
||||
%: RCS/%,v
|
||||
%: RCS/%
|
||||
%: %,v
|
||||
%: s.%
|
||||
%: SCCS/s.%
|
42
packet.h
Normal file
42
packet.h
Normal file
@ -0,0 +1,42 @@
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef _Float64 float64_t;
|
||||
|
||||
enum packet_type {
|
||||
PACKET_TYPE__TIME_START = 0x2112858517,
|
||||
PACKET_TYPE__TIME_STOP = 0xdf75d3f8,
|
||||
PACKET_TYPE__RTT_DELAY = 0xc7065931,
|
||||
PACKET_TYPE__ACK = 0xfde7959f,
|
||||
};
|
||||
|
||||
struct time_stop_data {
|
||||
uint32_t integer_value;
|
||||
uint32_t fraction_value;
|
||||
uint16_t integer_digits;
|
||||
uint16_t fraction_digits;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
static_assert((sizeof (struct time_stop_data)) == 4 * 3);
|
||||
|
||||
struct rtt_delay_data {
|
||||
float64_t offset;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct ack_data {
|
||||
uint64_t seq;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
static_assert((sizeof (struct rtt_delay_data)) == 8);
|
||||
|
||||
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 timing_packet)) == 4 * 4);
|
128
parse_serial.c
Normal file
128
parse_serial.c
Normal file
@ -0,0 +1,128 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "packet.h"
|
||||
#include "bufsize.h"
|
||||
|
||||
uint8_t const * parse_int(uint8_t const * buf, int * length, int * number, int * digits)
|
||||
{
|
||||
*number = 0;
|
||||
*digits = 0;
|
||||
|
||||
while (*length > 0) {
|
||||
*length -= 1;
|
||||
uint8_t c = *buf++;
|
||||
if (c < 0x20 || c > 0x7f)
|
||||
continue;
|
||||
switch (c) {
|
||||
case '0': [[fallthrough]];
|
||||
case '1': [[fallthrough]];
|
||||
case '2': [[fallthrough]];
|
||||
case '3': [[fallthrough]];
|
||||
case '4': [[fallthrough]];
|
||||
case '5': [[fallthrough]];
|
||||
case '6': [[fallthrough]];
|
||||
case '7': [[fallthrough]];
|
||||
case '8': [[fallthrough]];
|
||||
case '9':
|
||||
*digits += 1;
|
||||
number *= 10;
|
||||
number += c - '0';
|
||||
break;
|
||||
case ' ':
|
||||
break;
|
||||
default:
|
||||
buf--;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
exit:
|
||||
return buf;
|
||||
}
|
||||
|
||||
int parse_time(uint8_t const * const buf, int length, struct stopwatch_time * time)
|
||||
{
|
||||
if (length < 3)
|
||||
return -1;
|
||||
|
||||
uint8_t const * bufi = buf;
|
||||
bufi = parse_int(bufi, &length, &time->integer_value, &time->integer_digits);
|
||||
|
||||
if (integer_digits == 0) {
|
||||
fprintf(stderr, "invalid integer at `%c`\n", *bufi);
|
||||
return -1;
|
||||
}
|
||||
if (*bufi++ != '.') {
|
||||
fprintf(stderr, "missing decimal point: `%c`\n", *bufi);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (length < 1)
|
||||
return -1;
|
||||
|
||||
bufi = parse_int(bufi, &length, &time->fraction_value, &time->fraction_digits);
|
||||
if (integer_digits == 0) {
|
||||
fprintf(stderr, "invalid fraction at `%c`\n", *bufi);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int min(int a, int b) {
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
struct parser_state {
|
||||
uint8_t buf[BUFSIZE];
|
||||
int offset;
|
||||
};
|
||||
|
||||
bool is_()
|
||||
{
|
||||
}
|
||||
|
||||
void parse_line(uint8_t * buf, int length,
|
||||
struct timer_state * timer_state)
|
||||
{
|
||||
if (length == 0) {
|
||||
timer_state->status = COUNTER_RUNNING;
|
||||
int ret = clock_gettime(CLOCK_MONOTONIC, &timer_state->counter.start);
|
||||
timer_state->counter.offset.tv_sec = 0;
|
||||
timer_state->counter.offset.tv_nsec = 0;
|
||||
assert(ret != -1);
|
||||
} else if (is_) {
|
||||
}
|
||||
}
|
||||
|
||||
void handle_parse(uint8_t * read_buf, int length,
|
||||
struct parser_state * parser_state,
|
||||
struct timer_state * timer_state)
|
||||
{
|
||||
while (length > 0) {
|
||||
int copy_length = min(length, BUFSIZE - state->offset);
|
||||
length -= copy_length;
|
||||
memcpy(&state->buf[state->offset], read_buf, copy_length);
|
||||
state->offset += copy_length;
|
||||
|
||||
while (state->offset > 0) {
|
||||
int i = 0;
|
||||
while (i < state->offset) {
|
||||
if (state->buf[i] == '\r') {
|
||||
fprintf(stderr, "r at %d %d\n", i, state->offset);
|
||||
handle_line(state->buf, i);
|
||||
state->offset -= i + 1;
|
||||
assert(state->offset >= 0);
|
||||
memmove(&state->buf[0], &state->buf[i + 1], state->offset);
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
if (i == state->offset)
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
exit:
|
||||
continue;
|
||||
}
|
||||
}
|
183
serial_forwarder.c
Normal file
183
serial_forwarder.c
Normal file
@ -0,0 +1,183 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <libserialport.h>
|
||||
|
||||
#include "bufsize.h"
|
||||
|
||||
#define PORT 4321
|
||||
#define SERIALPORT "/dev/ttyS0"
|
||||
|
||||
int sp_error(const char * s, enum sp_return result)
|
||||
{
|
||||
char * error_message;
|
||||
switch (result) {
|
||||
case SP_ERR_ARG:
|
||||
printf("%s: error: Invalid argument.\n", s);
|
||||
case SP_ERR_FAIL:
|
||||
error_message = sp_last_error_message();
|
||||
printf("%s: error: Failed: %s\n", error_message, s);
|
||||
sp_free_error_message(error_message);
|
||||
case SP_ERR_SUPP:
|
||||
printf("%s: error: Not supported.\n", s);
|
||||
case SP_ERR_MEM:
|
||||
printf("%s: error: Couldn't allocate memory.\n", s);
|
||||
case SP_OK: [[fallthrough]];
|
||||
default:
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
int init_serial(struct sp_port * port)
|
||||
{
|
||||
enum sp_return sp_ret;
|
||||
|
||||
sp_ret = sp_get_port_by_name(SERIALPORT, &port);
|
||||
if (sp_ret != SP_OK) {
|
||||
sp_error("sp_get_port_by_name", sp_ret);
|
||||
return -1;
|
||||
}
|
||||
sp_ret = sp_open(port, SP_MODE_READ_WRITE);
|
||||
if (sp_ret != SP_OK) {
|
||||
sp_error("sp_open", sp_ret);
|
||||
return -1;
|
||||
}
|
||||
sp_ret = sp_set_baudrate(port, 1200);
|
||||
if (sp_ret != SP_OK) {
|
||||
sp_error("sp_set_baudrate", sp_ret);
|
||||
return -1;
|
||||
}
|
||||
sp_ret = sp_set_bits(port, 8);
|
||||
if (sp_ret != SP_OK) {
|
||||
sp_error("sp_set_bits", sp_ret);
|
||||
return -1;
|
||||
}
|
||||
sp_ret = sp_set_parity(port, SP_PARITY_NONE);
|
||||
if (sp_ret != SP_OK) {
|
||||
sp_error("sp_set_parity", sp_ret);
|
||||
return -1;
|
||||
}
|
||||
sp_ret = sp_set_stopbits(port, 1);
|
||||
if (sp_ret != SP_OK) {
|
||||
sp_error("sp_set_stopbits", sp_ret);
|
||||
return -1;
|
||||
}
|
||||
sp_ret = sp_set_flowcontrol(port, SP_FLOWCONTROL_NONE);
|
||||
if (sp_ret != SP_OK) {
|
||||
sp_error("sp_set_flowcontrol", sp_ret);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int handle_sock(int sock)
|
||||
{
|
||||
struct sockaddr_in src_addr;
|
||||
socklen_t addrlen = (sizeof (struct sockaddr_in));
|
||||
|
||||
char buf[BUFSIZE];
|
||||
|
||||
while (true) {
|
||||
ssize_t recv_len = recvfrom(sock, buf, BUFSIZE, 0, (struct sockaddr *)&src_addr, &addrlen);
|
||||
if (recv_len == -1) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
perror("eagain");
|
||||
return 0;
|
||||
} else {
|
||||
perror("recvfrom");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
struct receiver_state {
|
||||
uint64_t seq;
|
||||
uint64_t ack_seq;
|
||||
};
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
int sock = socket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP);
|
||||
if (sock == -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);
|
||||
|
||||
ret = bind(sock, (struct sockaddr *)&sockaddr, (sizeof (struct sockaddr_in)));
|
||||
if (ret == -1) {
|
||||
perror("bind");
|
||||
return -1;
|
||||
}
|
||||
|
||||
#define MAX_EVENTS 2
|
||||
struct epoll_event events[MAX_EVENTS];
|
||||
|
||||
int epollfd = epoll_create1(0);
|
||||
if (epollfd == -1) {
|
||||
perror("epoll_create1");
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct epoll_event ev;
|
||||
ev.events = EPOLLIN | EPOLLET;
|
||||
ev.data.fd = sock;
|
||||
ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, sock, &ev);
|
||||
if (ret == -1) {
|
||||
perror("epoll_ctl: sock");
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
printf("Wait for datagram\n");
|
||||
|
||||
int nfds = epoll_wait(epollfd, events, MAX_EVENTS, 1000);
|
||||
if (nfds == -1) {
|
||||
perror("epoll_wait");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int n = 0; n < nfds; ++n) {
|
||||
if (events[n].data.fd == sock) {
|
||||
ret = handle_sock(sock);
|
||||
if (ret == -1)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
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);
|
||||
|
||||
return 0;
|
||||
}
|
61
time_display.c
Normal file
61
time_display.c
Normal file
@ -0,0 +1,61 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#define BUFLEN 512
|
||||
#define PORT 1234
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (sock == -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);
|
||||
|
||||
ret = bind(sock, (struct sockaddr *)&sockaddr, (sizeof (struct sockaddr_in)));
|
||||
if (ret == -1) {
|
||||
perror("bind");
|
||||
return -1;
|
||||
}
|
||||
|
||||
char buf[BUFLEN];
|
||||
|
||||
while (1) {
|
||||
printf("Wait for datagram\n");
|
||||
|
||||
struct sockaddr_in src_addr = {0};
|
||||
socklen_t addrlen = (sizeof (struct sockaddr_in));
|
||||
|
||||
ssize_t recv_len = recvfrom(sock, buf, BUFLEN, 0, (struct sockaddr *)&src_addr, &addrlen);
|
||||
if (recv_len == -1) {
|
||||
perror("recvfrom");
|
||||
return -1;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
/*
|
||||
//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;
|
||||
}
|
270
timer.c
Normal file
270
timer.c
Normal file
@ -0,0 +1,270 @@
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include <libserialport.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) {
|
||||
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();
|
||||
}
|
22
timer.h
Normal file
22
timer.h
Normal file
@ -0,0 +1,22 @@
|
||||
#include <time.h>
|
||||
|
||||
enum counter_status {
|
||||
COUNTER_STOPPED,
|
||||
COUNTER_RUNNING,
|
||||
};
|
||||
|
||||
struct stopwatch_time {
|
||||
int32_t whole;
|
||||
int32_t fraction;
|
||||
};
|
||||
|
||||
struct running_counter {
|
||||
struct timespec start; // CLOCK_MONOTONIC (relative)
|
||||
struct timespec offset; // CLOCK_MONOTONIC (relative)
|
||||
};
|
||||
|
||||
struct timer_state {
|
||||
enum counter_status status;
|
||||
struct running_counter counter;
|
||||
struct stopwatch_time time;
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user