timer/parse_serial.c

141 lines
3.2 KiB
C

#include <stdint.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include "packet.h"
#include "parse_serial.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 (time->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 (time->fraction_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;
}
bool is_timer_resume(uint8_t const * const buf, int length)
{
return false;
}
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_RAW, &timer_state->counter.start);
assert(ret != -1);
timer_state->counter.offset.tv_sec = 0;
timer_state->counter.offset.tv_nsec = 0;
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 EVENT_TYPE__TIME_STOP;
}
}
return false;
}
uint32_t handle_parse(uint8_t * read_buf, int length,
struct parser_state * parser_state,
struct timer_state * timer_state)
{
uint32_t type = EVENT_TYPE__INVALID;
while (length > 0) {
int copy_length = min(length, BUFSIZE - parser_state->offset);
length -= copy_length;
memcpy(&parser_state->buf[parser_state->offset], read_buf, copy_length);
parser_state->offset += copy_length;
while (parser_state->offset > 0) {
int i = 0;
while (i < parser_state->offset) {
if (parser_state->buf[i] == '\r') {
fprintf(stderr, "r at %d %d\n", i, parser_state->offset);
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);
break;
}
i++;
if (i == parser_state->offset)
goto exit;
}
}
exit:
continue;
}
return type;
}