From 89b8217435286081dc0fe481559da3ee5c20c72a Mon Sep 17 00:00:00 2001 From: lonkaars Date: Wed, 19 Oct 2022 18:15:36 +0200 Subject: last-records response handler implemented --- shared/backlog.c | 47 ++++++++++++++++++++++++++++++++++++++++++++ shared/backlog.h | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ shared/protocol.c | 7 ++----- shared/protocol.h | 5 ++++- shared/test.c | 50 ++++++++++++++++++++++++++++++++++------------ shared/util.h | 4 ++++ 6 files changed, 153 insertions(+), 19 deletions(-) create mode 100644 shared/backlog.c create mode 100644 shared/backlog.h create mode 100644 shared/util.h (limited to 'shared') diff --git a/shared/backlog.c b/shared/backlog.c new file mode 100644 index 0000000..926ccad --- /dev/null +++ b/shared/backlog.c @@ -0,0 +1,47 @@ +#include + +#include "backlog.h" + +ws_s_backlog_database* g_ws_backlog_database = NULL; + +void ws_backlog_alloc(uint16_t record_amt) { + g_ws_backlog_database = malloc(sizeof(ws_s_backlog_database) + sizeof(ws_s_backlog_record) * record_amt); + g_ws_backlog_database->buffer_size = record_amt; + g_ws_backlog_database->buffer_start = 0; + g_ws_backlog_database->buffer_end = 0; +} + +void ws_backlog_add_record(ws_s_backlog_record record) { + static uint16_t id = 0; + + g_ws_backlog_database->records[g_ws_backlog_database->buffer_end].id = id++; + g_ws_backlog_database->records[g_ws_backlog_database->buffer_end].sens_atm_pressure = record.sens_atm_pressure; + g_ws_backlog_database->records[g_ws_backlog_database->buffer_end].sens_humidity = record.sens_humidity; + g_ws_backlog_database->records[g_ws_backlog_database->buffer_end].sens_temperature = record.sens_temperature; + + // shift buffer start/end + g_ws_backlog_database->buffer_end = (g_ws_backlog_database->buffer_end + 1) % g_ws_backlog_database->buffer_size; + if (g_ws_backlog_database->buffer_end == g_ws_backlog_database->buffer_start) + g_ws_backlog_database->buffer_start = (g_ws_backlog_database->buffer_start + 1) % g_ws_backlog_database->buffer_size; +} + +ws_s_backlog_record* ws_backlog_get_record(uint16_t record_index) { + return &g_ws_backlog_database->records[record_index]; +} + +ws_s_backlog_record* ws_backlog_get_last_record(uint16_t record_offset) { + return ws_backlog_get_record((g_ws_backlog_database->buffer_end - record_offset - 1) % g_ws_backlog_database->buffer_size); +} + +static uint16_t mod(uint16_t a, uint16_t b) { + uint16_t m = a % b; + return m < 0 ? (b < 0) ? m - b : m + b : m; +} + +uint16_t ws_backlog_get_record_count() { + // add buffer_size to the result of the modulo operation if it's result is negative + // (only works when buffer_size is less than 2^15) + // this is a consequence of the way in which c handles negative numbers in modulo operations + int16_t mod = (g_ws_backlog_database->buffer_end - g_ws_backlog_database->buffer_start) % g_ws_backlog_database->buffer_size; + return mod < 0 ? mod + g_ws_backlog_database->buffer_size : mod; +} diff --git a/shared/backlog.h b/shared/backlog.h new file mode 100644 index 0000000..c8ea019 --- /dev/null +++ b/shared/backlog.h @@ -0,0 +1,59 @@ +#pragma once + +#include + +/** + * @brief allocate backlog buffer and set global backlog pointer + * @param record_amt amount of records to keep before overwriting oldest record + */ +void ws_backlog_alloc(uint16_t record_amt); + +// enable struct packing +#pragma pack(push, 1) + +/** @brief backlog record */ +typedef struct { + uint16_t id; /**< unique record identifier, numbered sequentially */ + uint8_t sens_temperature; /**< temperature reading */ + uint8_t sens_humidity; /**< humidity reading */ + uint8_t sens_atm_pressure; /**< atmospheric pressure reading */ +} ws_s_backlog_record; + +typedef struct { + uint16_t buffer_size; /**< buffer size (amount of records) */ + uint16_t buffer_start; /** first record index */ + uint16_t buffer_end; /** last record index */ + ws_s_backlog_record records[]; /** record array */ +} ws_s_backlog_database; + +// disable struct packing +#pragma pack(pop) + +/** @brief global record backlog database pointer */ +extern ws_s_backlog_database* g_ws_backlog_database; + +/** + * @brief add record to database + * + * automatically sets record.id, pushes buffer_end forwards and overwrites the + * last record if the buffer is full + */ +void ws_backlog_add_record(ws_s_backlog_record record); + +/** + * there's intentionally no function to retrieve multiple records as an array, + * as this would either require + * (a) copying the selection which is not possible with the current memory + * constraints, or + * (b) giving a direct pointer, but this would cause undefined behavior at the + * ring buffer seam + */ + +/** @brief get pointer to record with index `record_index` from the database */ +ws_s_backlog_record* ws_backlog_get_record(uint16_t record_index); + +/** @brief get pointer to last record with offset `record_offset` from the database */ +ws_s_backlog_record* ws_backlog_get_last_record(uint16_t record_offset); + +/** @brief return amount of valid records in database */ +uint16_t ws_backlog_get_record_count(); diff --git a/shared/protocol.c b/shared/protocol.c index 225b46f..55e6759 100644 --- a/shared/protocol.c +++ b/shared/protocol.c @@ -50,14 +50,11 @@ void ws_protocol_parse_req_byte(ws_s_protocol_req_parser_state* state, char inpu // send response char response_first_line[16]; sprintf(response_first_line, "%s,%x\n", response->success == WS_PROTOCOL_CMD_RETURN_OK ? "ok" : "error", response->msg->bytes); - ws_s_bin* response_first_line_bin = ws_bin_s_alloc(strlen(response_first_line)); - strncpy((char*) response_first_line_bin->data, response_first_line, strlen(response_first_line)); - ws_protocol_send_data(response_first_line_bin); - if (!response->csh) ws_protocol_send_data(response->msg); + ws_protocol_send_data(response_first_line, strlen(response_first_line)); + if (!response->csh) ws_protocol_send_data((char*) response->msg->data, response->msg->bytes); else (*g_ws_protocol_res_handlers[response->cmd_code])(state->target, response, true); // free response data containers - free(response_first_line_bin); free(response->msg); free(response); diff --git a/shared/protocol.h b/shared/protocol.h index c31ebc6..fbe29d6 100644 --- a/shared/protocol.h +++ b/shared/protocol.h @@ -137,8 +137,11 @@ ws_protocol_res_handler_t ws_protocol_res_last_records; * this function should be implemented in the source files of each target * platform, as the send interface will be different on desktop and on the * stm32. + * + * @param data pointer to data char array + * @param length length of data array */ -void ws_protocol_send_data(ws_s_bin* data); +void ws_protocol_send_data(const char* data, unsigned int length); /** @brief response handlers, called when a command is parsed */ static ws_protocol_res_handler_t* g_ws_protocol_res_handlers[WS_PROTOCOL_CMD_AMOUNT] = { diff --git a/shared/test.c b/shared/test.c index 0968252..287332a 100644 --- a/shared/test.c +++ b/shared/test.c @@ -6,34 +6,40 @@ #include #include "protocol.h" +#include "backlog.h" +#include "util.h" void ws_protocol_res_last_records(ws_s_protocol_parsed_req_cmd* parsed_cmd, ws_s_protocol_res* response, bool send) { - const char* response_text = "" - "id,temperature,humidity,atmospheric_pressure\n" - "10dc,2f,c5,7f\n" - "10dd,30,c6,7f\n" - "10de,31,c7,7f\n" - "10df,35,ca,7e\n" - "10e0,34,c9,7e\n"; + static unsigned int record_amount = 0; + const char* response_header = "id,temperature,humidity,atmospheric_pressure\n"; + const size_t response_line_size = sizeof("xxxx,xx,xx,xx\n"); if (!send) { response->success = WS_PROTOCOL_CMD_RETURN_OK; + if (sscanf(parsed_cmd->argv[1], "%u", &record_amount) < 1) response->success = WS_PROTOCOL_CMD_RETURN_ERROR; + record_amount = WS_MIN(record_amount, ws_backlog_get_record_count()); response->csh = true; response->msg = ws_bin_s_alloc(0); - response->msg->bytes = strlen(response_text); + response->msg->bytes = strlen(response_header) + response_line_size * record_amount; } else { // example send routine - ws_s_bin* response_test = ws_bin_s_alloc(strlen(response_text)); - strncpy((char*) response_test->data, response_text, strlen(response_text)); - ws_protocol_send_data(response_test); + ws_protocol_send_data(response_header, strlen(response_header)); + char line[response_line_size + 1]; // +1 for null terminator -> sprintf + for (unsigned int i = 0; i < record_amount; i++) { + ws_s_backlog_record* record = ws_backlog_get_last_record(i); + sprintf(line, "%04x,%02x,%02x,%02x\n", record->id, record->sens_temperature, record->sens_humidity, record->sens_atm_pressure); + ws_protocol_send_data(line, response_line_size); + } } } -void ws_protocol_send_data(ws_s_bin* data) { - printf("%.*s", data->bytes, data->data); +void ws_protocol_send_data(const char* data, unsigned int length) { + printf("%.*s", length, data); } int main() { + ws_backlog_alloc(10); + // disable echo and enable raw mode fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK); struct termios term; @@ -45,6 +51,24 @@ int main() { ws_s_protocol_req_parser_state* parser1 = ws_protocol_req_parser_alloc(); + ws_backlog_add_record((ws_s_backlog_record) { + .sens_temperature = 0x29, + .sens_humidity = 0x34, + .sens_atm_pressure = 0x69, + }); + + ws_backlog_add_record((ws_s_backlog_record) { + .sens_temperature = 0x00, + .sens_humidity = 0x00, + .sens_atm_pressure = 0x00, + }); + + ws_backlog_add_record((ws_s_backlog_record) { + .sens_temperature = 0x01, + .sens_humidity = 0x01, + .sens_atm_pressure = 0x01, + }); + fflush(stdout); char byte; diff --git a/shared/util.h b/shared/util.h new file mode 100644 index 0000000..f39ff34 --- /dev/null +++ b/shared/util.h @@ -0,0 +1,4 @@ +#pragma once + +#define WS_MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define WS_MAX(a, b) (((a) > (b)) ? (a) : (b)) -- cgit v1.2.3