151 lines
3.5 KiB
C
151 lines
3.5 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)
|
|
{
|
|
const char * s = "^ RESTART-IGNORE TIME ^";
|
|
size_t len = strlen(s);
|
|
return (len == length) && (strncmp((const char *)buf, s, length) == 0);
|
|
}
|
|
|
|
uint32_t handle_line(uint8_t const * const buf, int length,
|
|
struct timer_state * timer_state)
|
|
{
|
|
/*
|
|
printf("handle_line: ");
|
|
for (int i = 0; i < length; i++) {
|
|
printf("%02x ", buf[i]);
|
|
}
|
|
*/
|
|
printf("\n");
|
|
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)) {
|
|
timer_state->status = TIMER_RUNNING;
|
|
return EVENT_TYPE__TIME_RESUME;
|
|
} 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;
|
|
}
|