From 385b47211ea8674f97f014537d694bb2efbd6ab9 Mon Sep 17 00:00:00 2001 From: lonkaars Date: Thu, 13 Oct 2022 15:59:14 +0200 Subject: WIP protocol implementation --- shared/protocol.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 shared/protocol.c (limited to 'shared/protocol.c') diff --git a/shared/protocol.c b/shared/protocol.c new file mode 100644 index 0000000..85b320f --- /dev/null +++ b/shared/protocol.c @@ -0,0 +1,72 @@ +#include +#include + +#include "protocol.h" + +void ws_protocol_parse_byte(ws_s_protocol_parser_state* state, char input) { + switch(input) { + case WS_PROTOCOL_C_NEWLINE: { + if (!state->valid) return; + break; + } + + case WS_PROTOCOL_C_SPACE: { + if (!state->valid) return; + printf("argument delimiter\n"); + return; + } + + case WS_PROTOCOL_C_NULL: { + state->valid = false; + return; + } + + default: { + if (!state->valid) return; + printf("recv byte 0x%02x, (\"%c\")\n", input, input); + state->cmd[state->cmd_len++] = input; + state->args_len[state->arg_len] += 1; + if (state->cmd_len == WS_PROTOCOL_CMD_BUFFER_LEN) state->valid = false; + return; + } + } + + printf("command done!\n"); +} + +void ws_protocol_parse_bytes(ws_s_protocol_parser_state* state, char* input, unsigned int length) { + for (unsigned int i = 0; i < length; i++) ws_protocol_parse_byte(state, input[i]); +} + +ws_s_protocol_parser_state* ws_protocol_parser_alloc() { + ws_s_protocol_parser_state* parser_state = malloc(sizeof(ws_s_protocol_parser_state) + sizeof(uint16_t) * WS_PROTOCOL_CMD_MAX_ARGUMENTS); + parser_state->cmd = malloc(sizeof(char) * WS_PROTOCOL_CMD_BUFFER_LEN); + parser_state->valid = true; + parser_state->cmd_len = 0; + parser_state->arg_len = 0; + parser_state->target = NULL; + return parser_state; +} + +void ws_protocol_cmd_init(ws_s_protocol_parser_state* state) { + state->target = malloc(sizeof(ws_s_protocol_parsed_cmd) + sizeof(char*) * state->arg_len); + for (unsigned int i = 0; i < state->arg_len; i++) + state->target->argv[i] = malloc(sizeof(char) * state->args_len[i]); + state->target->argc = state->arg_len; +} + +void ws_protocol_parser_free(ws_s_protocol_parser_state* state) { + if (state == NULL) return; + if (state->target != NULL) ws_protocol_cmd_free(state->target); + free(state->cmd); + free(state); + state = NULL; + return; +} +void ws_protocol_cmd_free(ws_s_protocol_parsed_cmd* cmd) { + for (unsigned int i = 0; i < cmd->argc; i++) + free(cmd->argv[i]); + free(cmd); + cmd = NULL; + return; +} -- cgit v1.2.3 From 78f8f18e48d25547e837630d8317ef029bba6d72 Mon Sep 17 00:00:00 2001 From: lonkaars Date: Thu, 13 Oct 2022 20:37:23 +0200 Subject: more protocol parsing done --- shared/bin.c | 11 ++++++++++ shared/bin.h | 5 +++-- shared/main | Bin 21456 -> 28568 bytes shared/makefile | 2 +- shared/protocol.c | 42 ++++++++++++++++++++++++++++++++---- shared/protocol.h | 63 ++++++++++++++++++++++++++++++++++++++++++++++-------- 6 files changed, 107 insertions(+), 16 deletions(-) create mode 100644 shared/bin.c (limited to 'shared/protocol.c') diff --git a/shared/bin.c b/shared/bin.c new file mode 100644 index 0000000..def2aa8 --- /dev/null +++ b/shared/bin.c @@ -0,0 +1,11 @@ +#include +#include +#include + +#include "bin.h" + +ws_s_bin *ws_bin_s_alloc(uint16_t bytes) { + ws_s_bin *temp = malloc(sizeof(ws_s_bin) + sizeof(uint8_t) * bytes); + temp->bytes = bytes; + return temp; +} diff --git a/shared/bin.h b/shared/bin.h index c7405be..bfcda0c 100644 --- a/shared/bin.h +++ b/shared/bin.h @@ -2,11 +2,12 @@ #include +/** @brief binary data container with length */ typedef struct { uint16_t bytes; uint8_t data[]; } ws_s_bin; -/** allocate new ws_s_bin struct and fill with `*data` for `bytes` bytes */ -ws_s_bin *ws_bin_s_alloc(uint16_t bytes, uint8_t *data); +/** @brief allocate new ws_s_bin struct */ +ws_s_bin *ws_bin_s_alloc(uint16_t bytes); diff --git a/shared/main b/shared/main index 7d7b7fe..10b0d3c 100755 Binary files a/shared/main and b/shared/main differ diff --git a/shared/makefile b/shared/makefile index 4d538da..2ca254c 100644 --- a/shared/makefile +++ b/shared/makefile @@ -1,7 +1,7 @@ CC = gcc LD = gcc RM = rm -f -CFLAGS = +CFLAGS = -g LFLAGS = TARGET = main diff --git a/shared/protocol.c b/shared/protocol.c index 85b320f..49d1795 100644 --- a/shared/protocol.c +++ b/shared/protocol.c @@ -1,5 +1,6 @@ #include #include +#include #include "protocol.h" @@ -12,7 +13,7 @@ void ws_protocol_parse_byte(ws_s_protocol_parser_state* state, char input) { case WS_PROTOCOL_C_SPACE: { if (!state->valid) return; - printf("argument delimiter\n"); + state->arg_len++; return; } @@ -23,15 +24,39 @@ void ws_protocol_parse_byte(ws_s_protocol_parser_state* state, char input) { default: { if (!state->valid) return; - printf("recv byte 0x%02x, (\"%c\")\n", input, input); state->cmd[state->cmd_len++] = input; state->args_len[state->arg_len] += 1; if (state->cmd_len == WS_PROTOCOL_CMD_BUFFER_LEN) state->valid = false; return; } } + // arg_len is used as an index while parsing, so add 1 to get length + state->arg_len++; - printf("command done!\n"); + // parse cmd into argc and argv + ws_protocol_cmd_init(state); + // create response + ws_s_protocol_response* response = ws_protocol_parse_finished(state->target); + + //TODO: send response + + free(response->msg); + free(response); + + return; +} + +ws_s_protocol_response* ws_protocol_parse_finished(ws_s_protocol_parsed_cmd* parsed_cmd) { + ws_s_protocol_response* response = malloc(sizeof(ws_s_protocol_response)); + + if (strncmp("last-records", parsed_cmd->argv[0], 12) == 0) { + printf("last-records found!\n"); + } + + response->msg = ws_bin_s_alloc(50); + strncpy((char*) response->msg->data, "hello world!\n\0", 14); + + return response; } void ws_protocol_parse_bytes(ws_s_protocol_parser_state* state, char* input, unsigned int length) { @@ -51,8 +76,16 @@ ws_s_protocol_parser_state* ws_protocol_parser_alloc() { void ws_protocol_cmd_init(ws_s_protocol_parser_state* state) { state->target = malloc(sizeof(ws_s_protocol_parsed_cmd) + sizeof(char*) * state->arg_len); for (unsigned int i = 0; i < state->arg_len; i++) - state->target->argv[i] = malloc(sizeof(char) * state->args_len[i]); + state->target->argv[i] = malloc(sizeof(char) * (state->args_len[i] + 1)); + state->target->argc = state->arg_len; + + unsigned int head = 0; + for (unsigned int i = 0; i < state->arg_len; i++) { + strncpy(state->target->argv[i], &state->cmd[head], state->args_len[i]); + state->target->argv[i][state->args_len[i]] = 0x00; // terminate argument with null byte + head += state->args_len[i]; + } } void ws_protocol_parser_free(ws_s_protocol_parser_state* state) { @@ -63,6 +96,7 @@ void ws_protocol_parser_free(ws_s_protocol_parser_state* state) { state = NULL; return; } + void ws_protocol_cmd_free(ws_s_protocol_parsed_cmd* cmd) { for (unsigned int i = 0; i < cmd->argc; i++) free(cmd->argv[i]); diff --git a/shared/protocol.h b/shared/protocol.h index 5cf7ac6..3082af4 100644 --- a/shared/protocol.h +++ b/shared/protocol.h @@ -14,24 +14,54 @@ #define WS_PROTOCOL_C_SPACE (0x20) #define WS_PROTOCOL_C_NULL (0x00) +/** + * @brief parsed cmd struct, holds arguments similar to argc and argv provided + * to `int main()` + */ typedef struct { - int argc; - char* argv[]; + int argc; /** argument count */ + char* argv[]; /** argument array, null terminated strings */ } ws_s_protocol_parsed_cmd; +/** + * @brief holds parser state variables for `ws_protocol_parse_byte` function. + * each incoming tcp request should get it's own parser 'instance' + */ typedef struct { - ws_s_protocol_parsed_cmd* target; - bool valid; - char* cmd; - uint16_t cmd_len; - uint16_t arg_len; - uint16_t args_len[]; + ws_s_protocol_parsed_cmd* target; /** parsed cmd reference */ + bool valid; /** command still valid flag */ + char* cmd; /** raw cmd */ + uint16_t cmd_len; /** raw cmd string length */ + uint16_t arg_len; /** amount of arguments */ + uint16_t args_len[]; /** array of argument lengths */ } ws_s_protocol_parser_state; -//TODO: document +/** @brief return values for command handlers */ +typedef enum { + WS_PROTOCOL_CMD_RETURN_OK = 0, + WS_PROTOCOL_CMD_RETURN_ERROR = 1, +} ws_e_protocol_cmd_return_value; + +/** @brief request response data struct */ +typedef struct { + ws_e_protocol_cmd_return_value success; + ws_s_bin* msg; +} ws_s_protocol_response; + +/** + * @brief allocate parser struct + * + * @return pointer to newly allocated struct + */ ws_s_protocol_parser_state* ws_protocol_parser_alloc(); +/** @brief deallocate parser struct, automatically frees all child pointers */ void ws_protocol_parser_free(ws_s_protocol_parser_state* state); +/** + * @brief initialize ws_s_protocol_parsed_cmd struct pointer of + * ws_s_protocol_parser_state (internal only) + */ void ws_protocol_cmd_init(ws_s_protocol_parser_state* state); +/** @brief deallocate ws_s_protocol_parsed_cmd struct pointer (internal only) */ void ws_protocol_cmd_free(ws_s_protocol_parsed_cmd* cmd); /** @@ -53,6 +83,21 @@ void ws_protocol_parse_byte(ws_s_protocol_parser_state* state, char input); * @param length input byte array length */ void ws_protocol_parse_bytes(ws_s_protocol_parser_state* state, char* input, unsigned int length); +/** + * @brief handle complete command + * + * this function gets called when ws_protocol_parse_byte has detected a + * finished command. this function decides which command handler gets called, + * given that argv[0] contains a valid command. command argument parsing is + * handled by the command handler function. + * + * @remark [server] + * + * @return response + * + * @param parsed_cmd cmd parsed into ws_s_protocol_parsed_cmd struct + */ +ws_s_protocol_response* ws_protocol_parse_finished(ws_s_protocol_parsed_cmd* parsed_cmd); /** * @brief create a `last-records` request command -- cgit v1.2.3 From f58ed35f0b73e933b6dd1f98472941c1d5d7ce9c Mon Sep 17 00:00:00 2001 From: lonkaars Date: Fri, 14 Oct 2022 16:21:21 +0200 Subject: request handler function executed --- shared/makefile | 2 +- shared/protocol.c | 26 +++++++++++++++++++++----- shared/protocol.h | 11 +++++++---- shared/test.c | 4 ++-- 4 files changed, 31 insertions(+), 12 deletions(-) (limited to 'shared/protocol.c') diff --git a/shared/makefile b/shared/makefile index 2ca254c..2093f00 100644 --- a/shared/makefile +++ b/shared/makefile @@ -1,7 +1,7 @@ CC = gcc LD = gcc RM = rm -f -CFLAGS = -g +CFLAGS = -g -std=c11 LFLAGS = TARGET = main diff --git a/shared/protocol.c b/shared/protocol.c index 49d1795..6e3bc73 100644 --- a/shared/protocol.c +++ b/shared/protocol.c @@ -46,16 +46,32 @@ void ws_protocol_parse_byte(ws_s_protocol_parser_state* state, char input) { return; } +#define WS_CMD_MAP(parsed_cmd, name, code) \ + if (strlen(parsed_cmd->argv[0]) == strlen(name) && strncmp(parsed_cmd->argv[0], name, strlen(name)) == 0) return code; + +static ws_e_protocol_cmd ws_protocol_get_cmd_code(ws_s_protocol_parsed_cmd* parsed_cmd) { + WS_CMD_MAP(parsed_cmd, "last-records", WS_PROTOCOL_CMD_LAST_RECORDS); + + return WS_PROTOCOL_CMD_UNKNOWN; +} + ws_s_protocol_response* ws_protocol_parse_finished(ws_s_protocol_parsed_cmd* parsed_cmd) { ws_s_protocol_response* response = malloc(sizeof(ws_s_protocol_response)); + response->success = WS_PROTOCOL_CMD_RETURN_ERROR; + response->msg = NULL; - if (strncmp("last-records", parsed_cmd->argv[0], 12) == 0) { - printf("last-records found!\n"); - } + ws_e_protocol_cmd cmd_code = ws_protocol_get_cmd_code(parsed_cmd); + if (cmd_code == WS_PROTOCOL_CMD_UNKNOWN) goto ws_protocol_parse_exit; + if (cmd_code >= WS_PROTOCOL_CMD_AMOUNT) goto ws_protocol_parse_exit; + + void (*ws_protocol_res_handler)(ws_s_protocol_parsed_cmd*, ws_s_protocol_response*) = + g_ws_protocol_res_handlers[cmd_code]; + if (ws_protocol_res_handler == NULL) goto ws_protocol_parse_exit; + (*ws_protocol_res_handler)(parsed_cmd, response); - response->msg = ws_bin_s_alloc(50); - strncpy((char*) response->msg->data, "hello world!\n\0", 14); +ws_protocol_parse_exit: + if (response->msg == NULL) response->msg = ws_bin_s_alloc(0); return response; } diff --git a/shared/protocol.h b/shared/protocol.h index 3082af4..a19fe48 100644 --- a/shared/protocol.h +++ b/shared/protocol.h @@ -115,16 +115,19 @@ ws_s_bin* ws_protocol_req_last_records(unsigned int record_amount); * command, and returns the response string * * @param parsed_cmd complete parsed command from ws_protocol_parse_* - * - * @return ws_s_bin containing response string + * @param response response struct with uninitialized pointer to msg */ -ws_s_bin* ws_protocol_res_last_records(ws_s_protocol_parsed_cmd* parsed_cmd); +void ws_protocol_res_last_records(ws_s_protocol_parsed_cmd* parsed_cmd, ws_s_protocol_response* response); +/** @brief cmd codes (used to call handlers) */ typedef enum { + WS_PROTOCOL_CMD_UNKNOWN = -1, + WS_PROTOCOL_CMD_LAST_RECORDS = 0, } ws_e_protocol_cmd; -static ws_s_bin* (*g_ws_protocol_res_handlers[WS_PROTOCOL_CMD_AMOUNT])(ws_s_protocol_parsed_cmd* parsed_cmd) = { +/** @brief response handlers, called when a command is parsed */ +static void (*g_ws_protocol_res_handlers[WS_PROTOCOL_CMD_AMOUNT])(ws_s_protocol_parsed_cmd*, ws_s_protocol_response*) = { [WS_PROTOCOL_CMD_LAST_RECORDS] = &ws_protocol_res_last_records }; diff --git a/shared/test.c b/shared/test.c index 788dc94..5f2cd60 100644 --- a/shared/test.c +++ b/shared/test.c @@ -6,8 +6,8 @@ #include "protocol.h" -ws_s_bin* ws_protocol_res_last_records(ws_s_protocol_parsed_cmd* parsed_cmd) { - return NULL; +void ws_protocol_res_last_records(ws_s_protocol_parsed_cmd* parsed_cmd, ws_s_protocol_response* response) { + printf("last-records detected!\n"); } int main() { -- cgit v1.2.3 From ec475b0469104a0a76542c52286ed08933ac750c Mon Sep 17 00:00:00 2001 From: lonkaars Date: Fri, 14 Oct 2022 16:47:12 +0200 Subject: more protocol stuff working --- shared/protocol.c | 9 +++++++++ shared/protocol.h | 9 +++++++++ shared/test.c | 16 +++++++++++++++- 3 files changed, 33 insertions(+), 1 deletion(-) (limited to 'shared/protocol.c') diff --git a/shared/protocol.c b/shared/protocol.c index 6e3bc73..bcb764e 100644 --- a/shared/protocol.c +++ b/shared/protocol.c @@ -39,10 +39,19 @@ void ws_protocol_parse_byte(ws_s_protocol_parser_state* state, char input) { ws_s_protocol_response* response = ws_protocol_parse_finished(state->target); //TODO: 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); + ws_protocol_send_data(response->msg); + free(response_first_line_bin); free(response->msg); free(response); + //TODO: reset command in parser_state for next command + return; } diff --git a/shared/protocol.h b/shared/protocol.h index a19fe48..74b289c 100644 --- a/shared/protocol.h +++ b/shared/protocol.h @@ -119,6 +119,15 @@ ws_s_bin* ws_protocol_req_last_records(unsigned int record_amount); */ void ws_protocol_res_last_records(ws_s_protocol_parsed_cmd* parsed_cmd, ws_s_protocol_response* response); +/** + * @brief data sender wrapper + * + * 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. + */ +void ws_protocol_send_data(ws_s_bin* data); + /** @brief cmd codes (used to call handlers) */ typedef enum { WS_PROTOCOL_CMD_UNKNOWN = -1, diff --git a/shared/test.c b/shared/test.c index 5f2cd60..2c3c3a3 100644 --- a/shared/test.c +++ b/shared/test.c @@ -3,11 +3,25 @@ #include #include #include +#include #include "protocol.h" void ws_protocol_res_last_records(ws_s_protocol_parsed_cmd* parsed_cmd, ws_s_protocol_response* response) { - printf("last-records detected!\n"); + 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"; + response->success = WS_PROTOCOL_CMD_RETURN_OK; + response->msg = ws_bin_s_alloc(strlen(response_text)); + strncpy((char*) response->msg->data, response_text, strlen(response_text)); +} + +void ws_protocol_send_data(ws_s_bin* data) { + printf("%.*s", data->bytes, data->data); } int main() { -- cgit v1.2.3 From a8ec533f4e548601e283cee628aaf5ffc1e7d662 Mon Sep 17 00:00:00 2001 From: lonkaars Date: Fri, 14 Oct 2022 17:06:02 +0200 Subject: parser done --- shared/protocol.c | 27 +++++++++++++++++---------- shared/protocol.h | 2 ++ shared/test.c | 1 + 3 files changed, 20 insertions(+), 10 deletions(-) (limited to 'shared/protocol.c') diff --git a/shared/protocol.c b/shared/protocol.c index bcb764e..377e79e 100644 --- a/shared/protocol.c +++ b/shared/protocol.c @@ -7,7 +7,6 @@ void ws_protocol_parse_byte(ws_s_protocol_parser_state* state, char input) { switch(input) { case WS_PROTOCOL_C_NEWLINE: { - if (!state->valid) return; break; } @@ -34,11 +33,11 @@ void ws_protocol_parse_byte(ws_s_protocol_parser_state* state, char input) { state->arg_len++; // parse cmd into argc and argv - ws_protocol_cmd_init(state); + if (state->valid) ws_protocol_cmd_init(state); // create response ws_s_protocol_response* response = ws_protocol_parse_finished(state->target); - //TODO: send response + // 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)); @@ -46,11 +45,13 @@ void ws_protocol_parse_byte(ws_s_protocol_parser_state* state, char input) { ws_protocol_send_data(response_first_line_bin); ws_protocol_send_data(response->msg); + // free response data containers free(response_first_line_bin); free(response->msg); free(response); - //TODO: reset command in parser_state for next command + // reset parser + ws_protocol_parser_reset(state); return; } @@ -59,6 +60,7 @@ void ws_protocol_parse_byte(ws_s_protocol_parser_state* state, char input) { if (strlen(parsed_cmd->argv[0]) == strlen(name) && strncmp(parsed_cmd->argv[0], name, strlen(name)) == 0) return code; static ws_e_protocol_cmd ws_protocol_get_cmd_code(ws_s_protocol_parsed_cmd* parsed_cmd) { + if (parsed_cmd == NULL) return WS_PROTOCOL_CMD_UNKNOWN; // invalid command WS_CMD_MAP(parsed_cmd, "last-records", WS_PROTOCOL_CMD_LAST_RECORDS); return WS_PROTOCOL_CMD_UNKNOWN; @@ -91,10 +93,7 @@ void ws_protocol_parse_bytes(ws_s_protocol_parser_state* state, char* input, uns ws_s_protocol_parser_state* ws_protocol_parser_alloc() { ws_s_protocol_parser_state* parser_state = malloc(sizeof(ws_s_protocol_parser_state) + sizeof(uint16_t) * WS_PROTOCOL_CMD_MAX_ARGUMENTS); parser_state->cmd = malloc(sizeof(char) * WS_PROTOCOL_CMD_BUFFER_LEN); - parser_state->valid = true; - parser_state->cmd_len = 0; - parser_state->arg_len = 0; - parser_state->target = NULL; + ws_protocol_parser_reset(parser_state); return parser_state; } @@ -116,16 +115,24 @@ void ws_protocol_cmd_init(ws_s_protocol_parser_state* state) { void ws_protocol_parser_free(ws_s_protocol_parser_state* state) { if (state == NULL) return; if (state->target != NULL) ws_protocol_cmd_free(state->target); + state->target = NULL; free(state->cmd); free(state); - state = NULL; return; } +void ws_protocol_parser_reset(ws_s_protocol_parser_state* state) { + if (state->target != NULL) ws_protocol_cmd_free(state->target); + state->target = NULL; + state->valid = true; + state->cmd_len = 0; + state->arg_len = 0; + memset(state->args_len, 0, sizeof(uint16_t) * WS_PROTOCOL_CMD_MAX_ARGUMENTS); +} + void ws_protocol_cmd_free(ws_s_protocol_parsed_cmd* cmd) { for (unsigned int i = 0; i < cmd->argc; i++) free(cmd->argv[i]); free(cmd); - cmd = NULL; return; } diff --git a/shared/protocol.h b/shared/protocol.h index 74b289c..b7b92bb 100644 --- a/shared/protocol.h +++ b/shared/protocol.h @@ -56,6 +56,8 @@ typedef struct { ws_s_protocol_parser_state* ws_protocol_parser_alloc(); /** @brief deallocate parser struct, automatically frees all child pointers */ void ws_protocol_parser_free(ws_s_protocol_parser_state* state); +/** @brief reset parser state to parse a new request */ +void ws_protocol_parser_reset(ws_s_protocol_parser_state* state); /** * @brief initialize ws_s_protocol_parsed_cmd struct pointer of * ws_s_protocol_parser_state (internal only) diff --git a/shared/test.c b/shared/test.c index 2c3c3a3..588cd16 100644 --- a/shared/test.c +++ b/shared/test.c @@ -45,6 +45,7 @@ int main() { } ws_protocol_parser_free(parser1); + parser1 = NULL; return 0; } -- cgit v1.2.3 From 42bf616eac96eba1846c64123a4b3822061b418c Mon Sep 17 00:00:00 2001 From: lonkaars Date: Mon, 17 Oct 2022 12:11:37 +0200 Subject: update naming scheme in protocol.{c,h} --- shared/protocol.c | 44 +++++++++++++++++++++--------------------- shared/protocol.h | 57 +++++++++++++++++++++++-------------------------------- shared/test.c | 16 +++++++--------- 3 files changed, 53 insertions(+), 64 deletions(-) (limited to 'shared/protocol.c') diff --git a/shared/protocol.c b/shared/protocol.c index 377e79e..6795197 100644 --- a/shared/protocol.c +++ b/shared/protocol.c @@ -4,9 +4,9 @@ #include "protocol.h" -void ws_protocol_parse_byte(ws_s_protocol_parser_state* state, char input) { +void ws_protocol_parse_req_byte(ws_s_protocol_req_parser_state* state, char input) { switch(input) { - case WS_PROTOCOL_C_NEWLINE: { + case WS_PROTOCOL_C_EOL: { break; } @@ -33,9 +33,9 @@ void ws_protocol_parse_byte(ws_s_protocol_parser_state* state, char input) { state->arg_len++; // parse cmd into argc and argv - if (state->valid) ws_protocol_cmd_init(state); + if (state->valid) ws_protocol_req_cmd_init(state); // create response - ws_s_protocol_response* response = ws_protocol_parse_finished(state->target); + ws_s_protocol_res* response = ws_protocol_parse_req_finished(state->target); // send response char response_first_line[16]; @@ -51,7 +51,7 @@ void ws_protocol_parse_byte(ws_s_protocol_parser_state* state, char input) { free(response); // reset parser - ws_protocol_parser_reset(state); + ws_protocol_req_parser_reset(state); return; } @@ -59,23 +59,23 @@ void ws_protocol_parse_byte(ws_s_protocol_parser_state* state, char input) { #define WS_CMD_MAP(parsed_cmd, name, code) \ if (strlen(parsed_cmd->argv[0]) == strlen(name) && strncmp(parsed_cmd->argv[0], name, strlen(name)) == 0) return code; -static ws_e_protocol_cmd ws_protocol_get_cmd_code(ws_s_protocol_parsed_cmd* parsed_cmd) { +static ws_e_protocol_cmd ws_protocol_get_req_cmd_code(ws_s_protocol_parsed_req_cmd* parsed_cmd) { if (parsed_cmd == NULL) return WS_PROTOCOL_CMD_UNKNOWN; // invalid command WS_CMD_MAP(parsed_cmd, "last-records", WS_PROTOCOL_CMD_LAST_RECORDS); return WS_PROTOCOL_CMD_UNKNOWN; } -ws_s_protocol_response* ws_protocol_parse_finished(ws_s_protocol_parsed_cmd* parsed_cmd) { - ws_s_protocol_response* response = malloc(sizeof(ws_s_protocol_response)); +ws_s_protocol_res* ws_protocol_parse_req_finished(ws_s_protocol_parsed_req_cmd* parsed_cmd) { + ws_s_protocol_res* response = malloc(sizeof(ws_s_protocol_res)); response->success = WS_PROTOCOL_CMD_RETURN_ERROR; response->msg = NULL; - ws_e_protocol_cmd cmd_code = ws_protocol_get_cmd_code(parsed_cmd); + ws_e_protocol_cmd cmd_code = ws_protocol_get_req_cmd_code(parsed_cmd); if (cmd_code == WS_PROTOCOL_CMD_UNKNOWN) goto ws_protocol_parse_exit; if (cmd_code >= WS_PROTOCOL_CMD_AMOUNT) goto ws_protocol_parse_exit; - void (*ws_protocol_res_handler)(ws_s_protocol_parsed_cmd*, ws_s_protocol_response*) = + void (*ws_protocol_res_handler)(ws_s_protocol_parsed_req_cmd*, ws_s_protocol_res*) = g_ws_protocol_res_handlers[cmd_code]; if (ws_protocol_res_handler == NULL) goto ws_protocol_parse_exit; (*ws_protocol_res_handler)(parsed_cmd, response); @@ -86,19 +86,19 @@ ws_protocol_parse_exit: return response; } -void ws_protocol_parse_bytes(ws_s_protocol_parser_state* state, char* input, unsigned int length) { - for (unsigned int i = 0; i < length; i++) ws_protocol_parse_byte(state, input[i]); +void ws_protocol_parse_req_bytes(ws_s_protocol_req_parser_state* state, char* input, unsigned int length) { + for (unsigned int i = 0; i < length; i++) ws_protocol_parse_req_byte(state, input[i]); } -ws_s_protocol_parser_state* ws_protocol_parser_alloc() { - ws_s_protocol_parser_state* parser_state = malloc(sizeof(ws_s_protocol_parser_state) + sizeof(uint16_t) * WS_PROTOCOL_CMD_MAX_ARGUMENTS); +ws_s_protocol_req_parser_state* ws_protocol_req_parser_alloc() { + ws_s_protocol_req_parser_state* parser_state = malloc(sizeof(ws_s_protocol_req_parser_state) + sizeof(uint16_t) * WS_PROTOCOL_CMD_MAX_ARGUMENTS); parser_state->cmd = malloc(sizeof(char) * WS_PROTOCOL_CMD_BUFFER_LEN); - ws_protocol_parser_reset(parser_state); + ws_protocol_req_parser_reset(parser_state); return parser_state; } -void ws_protocol_cmd_init(ws_s_protocol_parser_state* state) { - state->target = malloc(sizeof(ws_s_protocol_parsed_cmd) + sizeof(char*) * state->arg_len); +void ws_protocol_req_cmd_init(ws_s_protocol_req_parser_state* state) { + state->target = malloc(sizeof(ws_s_protocol_parsed_req_cmd) + sizeof(char*) * state->arg_len); for (unsigned int i = 0; i < state->arg_len; i++) state->target->argv[i] = malloc(sizeof(char) * (state->args_len[i] + 1)); @@ -112,17 +112,17 @@ void ws_protocol_cmd_init(ws_s_protocol_parser_state* state) { } } -void ws_protocol_parser_free(ws_s_protocol_parser_state* state) { +void ws_protocol_req_parser_free(ws_s_protocol_req_parser_state* state) { if (state == NULL) return; - if (state->target != NULL) ws_protocol_cmd_free(state->target); + if (state->target != NULL) ws_protocol_req_cmd_free(state->target); state->target = NULL; free(state->cmd); free(state); return; } -void ws_protocol_parser_reset(ws_s_protocol_parser_state* state) { - if (state->target != NULL) ws_protocol_cmd_free(state->target); +void ws_protocol_req_parser_reset(ws_s_protocol_req_parser_state* state) { + if (state->target != NULL) ws_protocol_req_cmd_free(state->target); state->target = NULL; state->valid = true; state->cmd_len = 0; @@ -130,7 +130,7 @@ void ws_protocol_parser_reset(ws_s_protocol_parser_state* state) { memset(state->args_len, 0, sizeof(uint16_t) * WS_PROTOCOL_CMD_MAX_ARGUMENTS); } -void ws_protocol_cmd_free(ws_s_protocol_parsed_cmd* cmd) { +void ws_protocol_req_cmd_free(ws_s_protocol_parsed_req_cmd* cmd) { for (unsigned int i = 0; i < cmd->argc; i++) free(cmd->argv[i]); free(cmd); diff --git a/shared/protocol.h b/shared/protocol.h index b7b92bb..9f17e8d 100644 --- a/shared/protocol.h +++ b/shared/protocol.h @@ -10,31 +10,31 @@ #define WS_PROTOCOL_CMD_AMOUNT (1) -#define WS_PROTOCOL_C_NEWLINE (0x0a) +#define WS_PROTOCOL_C_EOL (0x0a) #define WS_PROTOCOL_C_SPACE (0x20) #define WS_PROTOCOL_C_NULL (0x00) /** - * @brief parsed cmd struct, holds arguments similar to argc and argv provided - * to `int main()` + * @brief parsed request cmd struct, holds arguments similar to argc and argv + * provided to `int main()` */ typedef struct { int argc; /** argument count */ char* argv[]; /** argument array, null terminated strings */ -} ws_s_protocol_parsed_cmd; +} ws_s_protocol_parsed_req_cmd; /** - * @brief holds parser state variables for `ws_protocol_parse_byte` function. + * @brief holds parser state variables for `ws_protocol_parse_req_byte` function. * each incoming tcp request should get it's own parser 'instance' */ typedef struct { - ws_s_protocol_parsed_cmd* target; /** parsed cmd reference */ + ws_s_protocol_parsed_req_cmd* target; /** parsed cmd reference */ bool valid; /** command still valid flag */ char* cmd; /** raw cmd */ uint16_t cmd_len; /** raw cmd string length */ uint16_t arg_len; /** amount of arguments */ uint16_t args_len[]; /** array of argument lengths */ -} ws_s_protocol_parser_state; +} ws_s_protocol_req_parser_state; /** @brief return values for command handlers */ typedef enum { @@ -46,64 +46,57 @@ typedef enum { typedef struct { ws_e_protocol_cmd_return_value success; ws_s_bin* msg; -} ws_s_protocol_response; +} ws_s_protocol_res; /** * @brief allocate parser struct * * @return pointer to newly allocated struct */ -ws_s_protocol_parser_state* ws_protocol_parser_alloc(); +ws_s_protocol_req_parser_state* ws_protocol_req_parser_alloc(); /** @brief deallocate parser struct, automatically frees all child pointers */ -void ws_protocol_parser_free(ws_s_protocol_parser_state* state); +void ws_protocol_req_parser_free(ws_s_protocol_req_parser_state* state); /** @brief reset parser state to parse a new request */ -void ws_protocol_parser_reset(ws_s_protocol_parser_state* state); +void ws_protocol_req_parser_reset(ws_s_protocol_req_parser_state* state); /** - * @brief initialize ws_s_protocol_parsed_cmd struct pointer of - * ws_s_protocol_parser_state (internal only) + * @brief initialize ws_s_protocol_parsed_req_cmd struct pointer of + * ws_s_protocol_req_parser_state (internal only) */ -void ws_protocol_cmd_init(ws_s_protocol_parser_state* state); -/** @brief deallocate ws_s_protocol_parsed_cmd struct pointer (internal only) */ -void ws_protocol_cmd_free(ws_s_protocol_parsed_cmd* cmd); +void ws_protocol_req_cmd_init(ws_s_protocol_req_parser_state* state); +/** @brief deallocate ws_s_protocol_parsed_req_cmd struct pointer (internal only) */ +void ws_protocol_req_cmd_free(ws_s_protocol_parsed_req_cmd* cmd); /** * @brief parse incoming data byte by byte until a finished command is detected * - * @remark [server] - * * @param state parser state object, each incoming request should have it's own parser state * @param input input byte */ -void ws_protocol_parse_byte(ws_s_protocol_parser_state* state, char input); +void ws_protocol_parse_req_byte(ws_s_protocol_req_parser_state* state, char input); /** * @brief parse incoming data chunk * - * @remark [server] - * * @param state parser state object, each incoming request should have it's own parser state * @param input input byte array * @param length input byte array length */ -void ws_protocol_parse_bytes(ws_s_protocol_parser_state* state, char* input, unsigned int length); +void ws_protocol_parse_req_bytes(ws_s_protocol_req_parser_state* state, char* input, unsigned int length); /** * @brief handle complete command * - * this function gets called when ws_protocol_parse_byte has detected a + * this function gets called when ws_protocol_parse_req_byte(s) has detected a * finished command. this function decides which command handler gets called, * given that argv[0] contains a valid command. command argument parsing is * handled by the command handler function. * - * @remark [server] - * * @return response * - * @param parsed_cmd cmd parsed into ws_s_protocol_parsed_cmd struct + * @param parsed_cmd cmd parsed into ws_s_protocol_parsed_req_cmd struct */ -ws_s_protocol_response* ws_protocol_parse_finished(ws_s_protocol_parsed_cmd* parsed_cmd); +ws_s_protocol_res* ws_protocol_parse_req_finished(ws_s_protocol_parsed_req_cmd* parsed_cmd); /** * @brief create a `last-records` request command - * @remark [client] * @return ws_s_bin containing the command string */ ws_s_bin* ws_protocol_req_last_records(unsigned int record_amount); @@ -111,15 +104,13 @@ ws_s_bin* ws_protocol_req_last_records(unsigned int record_amount); /** * @brief `last-records` response handler * - * @remark [server] - * * gets fired when the weather station receives a complete `last-records` * command, and returns the response string * - * @param parsed_cmd complete parsed command from ws_protocol_parse_* + * @param parsed_cmd complete parsed command from ws_protocol_parse_req_* * @param response response struct with uninitialized pointer to msg */ -void ws_protocol_res_last_records(ws_s_protocol_parsed_cmd* parsed_cmd, ws_s_protocol_response* response); +void ws_protocol_res_last_records(ws_s_protocol_parsed_req_cmd* parsed_cmd, ws_s_protocol_res* response); /** * @brief data sender wrapper @@ -138,7 +129,7 @@ typedef enum { } ws_e_protocol_cmd; /** @brief response handlers, called when a command is parsed */ -static void (*g_ws_protocol_res_handlers[WS_PROTOCOL_CMD_AMOUNT])(ws_s_protocol_parsed_cmd*, ws_s_protocol_response*) = { +static void (*g_ws_protocol_res_handlers[WS_PROTOCOL_CMD_AMOUNT])(ws_s_protocol_parsed_req_cmd*, ws_s_protocol_res*) = { [WS_PROTOCOL_CMD_LAST_RECORDS] = &ws_protocol_res_last_records }; diff --git a/shared/test.c b/shared/test.c index 588cd16..f9d4bbc 100644 --- a/shared/test.c +++ b/shared/test.c @@ -7,7 +7,7 @@ #include "protocol.h" -void ws_protocol_res_last_records(ws_s_protocol_parsed_cmd* parsed_cmd, ws_s_protocol_response* response) { +void ws_protocol_res_last_records(ws_s_protocol_parsed_req_cmd* parsed_cmd, ws_s_protocol_res* response) { const char* response_text = "" "id,temperature,humidity,atmospheric_pressure\n" "10dc,2f,c5,7f\n" @@ -34,17 +34,15 @@ int main() { term.c_cc[VMIN] = 1; tcsetattr(STDIN_FILENO, 0, &term); - ws_s_protocol_parser_state* parser1 = ws_protocol_parser_alloc(); + ws_s_protocol_req_parser_state* parser1 = ws_protocol_req_parser_alloc(); - for(;;) { - fflush(stdout); + fflush(stdout); - char byte; - while(read(STDIN_FILENO, &byte, 1) > 0) - ws_protocol_parse_byte(parser1, byte); - } + char byte; + while(read(STDIN_FILENO, &byte, 1) > 0) + ws_protocol_parse_req_byte(parser1, byte); - ws_protocol_parser_free(parser1); + ws_protocol_req_parser_free(parser1); parser1 = NULL; return 0; -- cgit v1.2.3 From e555b5b5e0ad94279ef62d16feacee4976e2970d Mon Sep 17 00:00:00 2001 From: lonkaars Date: Wed, 19 Oct 2022 16:38:11 +0200 Subject: custom response data send handlers implemented --- shared/protocol.c | 35 ++++++++++++++++++----------------- shared/protocol.h | 42 +++++++++++++++++++++++++++--------------- shared/test.c | 17 +++++++++++++---- 3 files changed, 58 insertions(+), 36 deletions(-) (limited to 'shared/protocol.c') diff --git a/shared/protocol.c b/shared/protocol.c index 6795197..225b46f 100644 --- a/shared/protocol.c +++ b/shared/protocol.c @@ -4,6 +4,16 @@ #include "protocol.h" +#define WS_CMD_MAP(parsed_cmd, name, code) \ + if (strlen(parsed_cmd->argv[0]) == strlen(name) && strncmp(parsed_cmd->argv[0], name, strlen(name)) == 0) return code; + +static ws_e_protocol_cmd ws_protocol_get_req_cmd_code(ws_s_protocol_parsed_req_cmd* parsed_cmd) { + if (parsed_cmd == NULL) return WS_PROTOCOL_CMD_UNKNOWN; // invalid command + WS_CMD_MAP(parsed_cmd, "last-records", WS_PROTOCOL_CMD_LAST_RECORDS); + + return WS_PROTOCOL_CMD_UNKNOWN; +} + void ws_protocol_parse_req_byte(ws_s_protocol_req_parser_state* state, char input) { switch(input) { case WS_PROTOCOL_C_EOL: { @@ -43,7 +53,8 @@ void ws_protocol_parse_req_byte(ws_s_protocol_req_parser_state* state, char inpu 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); - ws_protocol_send_data(response->msg); + if (!response->csh) ws_protocol_send_data(response->msg); + else (*g_ws_protocol_res_handlers[response->cmd_code])(state->target, response, true); // free response data containers free(response_first_line_bin); @@ -56,29 +67,19 @@ void ws_protocol_parse_req_byte(ws_s_protocol_req_parser_state* state, char inpu return; } -#define WS_CMD_MAP(parsed_cmd, name, code) \ - if (strlen(parsed_cmd->argv[0]) == strlen(name) && strncmp(parsed_cmd->argv[0], name, strlen(name)) == 0) return code; - -static ws_e_protocol_cmd ws_protocol_get_req_cmd_code(ws_s_protocol_parsed_req_cmd* parsed_cmd) { - if (parsed_cmd == NULL) return WS_PROTOCOL_CMD_UNKNOWN; // invalid command - WS_CMD_MAP(parsed_cmd, "last-records", WS_PROTOCOL_CMD_LAST_RECORDS); - - return WS_PROTOCOL_CMD_UNKNOWN; -} - ws_s_protocol_res* ws_protocol_parse_req_finished(ws_s_protocol_parsed_req_cmd* parsed_cmd) { ws_s_protocol_res* response = malloc(sizeof(ws_s_protocol_res)); response->success = WS_PROTOCOL_CMD_RETURN_ERROR; + response->csh = false; response->msg = NULL; + response->cmd_code = ws_protocol_get_req_cmd_code(parsed_cmd); - ws_e_protocol_cmd cmd_code = ws_protocol_get_req_cmd_code(parsed_cmd); - if (cmd_code == WS_PROTOCOL_CMD_UNKNOWN) goto ws_protocol_parse_exit; - if (cmd_code >= WS_PROTOCOL_CMD_AMOUNT) goto ws_protocol_parse_exit; + if (response->cmd_code == WS_PROTOCOL_CMD_UNKNOWN) goto ws_protocol_parse_exit; + if (response->cmd_code >= WS_PROTOCOL_CMD_AMOUNT) goto ws_protocol_parse_exit; - void (*ws_protocol_res_handler)(ws_s_protocol_parsed_req_cmd*, ws_s_protocol_res*) = - g_ws_protocol_res_handlers[cmd_code]; + ws_protocol_res_handler_t* ws_protocol_res_handler = g_ws_protocol_res_handlers[response->cmd_code]; if (ws_protocol_res_handler == NULL) goto ws_protocol_parse_exit; - (*ws_protocol_res_handler)(parsed_cmd, response); + (*ws_protocol_res_handler)(parsed_cmd, response, false); ws_protocol_parse_exit: diff --git a/shared/protocol.h b/shared/protocol.h index 9f17e8d..c31ebc6 100644 --- a/shared/protocol.h +++ b/shared/protocol.h @@ -42,10 +42,22 @@ typedef enum { WS_PROTOCOL_CMD_RETURN_ERROR = 1, } ws_e_protocol_cmd_return_value; +/** @brief cmd codes (used to call handlers) */ +typedef enum { + WS_PROTOCOL_CMD_UNKNOWN = -1, + + WS_PROTOCOL_CMD_LAST_RECORDS = 0, +} ws_e_protocol_cmd; + /** @brief request response data struct */ typedef struct { - ws_e_protocol_cmd_return_value success; - ws_s_bin* msg; + ws_e_protocol_cmd_return_value success; /** status code for response + validity, defaults to + WS_PROTOCOL_CMD_RETURN_ERROR */ + bool csh; /** whether the response handler has logic for a custom send + handler, false by default */ + ws_s_bin* msg; /** pointer to response data, uninitialized by default */ + ws_e_protocol_cmd cmd_code; /** cmd code */ } ws_s_protocol_res; /** @@ -102,15 +114,22 @@ ws_s_protocol_res* ws_protocol_parse_req_finished(ws_s_protocol_parsed_req_cmd* ws_s_bin* ws_protocol_req_last_records(unsigned int record_amount); /** - * @brief `last-records` response handler + * @brief response handler * - * gets fired when the weather station receives a complete `last-records` - * command, and returns the response string + * gets fired when the weather station receives a complete command, and returns + * a response struct with a success code and an optional message. if + * response->csh is set to `true` within the handler, it gets fired a second + * time after the response header is sent, but with the `send` parameter set to + * `true`. this is so response handlers can send large amounts of data without + * allocating large areas of memory. * * @param parsed_cmd complete parsed command from ws_protocol_parse_req_* * @param response response struct with uninitialized pointer to msg + * @param send `false` on first run, `true` on second run if `response->csh` was set to true */ -void ws_protocol_res_last_records(ws_s_protocol_parsed_req_cmd* parsed_cmd, ws_s_protocol_res* response); +typedef void ws_protocol_res_handler_t(ws_s_protocol_parsed_req_cmd*, ws_s_protocol_res*, bool); + +ws_protocol_res_handler_t ws_protocol_res_last_records; /** * @brief data sender wrapper @@ -121,15 +140,8 @@ void ws_protocol_res_last_records(ws_s_protocol_parsed_req_cmd* parsed_cmd, ws_s */ void ws_protocol_send_data(ws_s_bin* data); -/** @brief cmd codes (used to call handlers) */ -typedef enum { - WS_PROTOCOL_CMD_UNKNOWN = -1, - - WS_PROTOCOL_CMD_LAST_RECORDS = 0, -} ws_e_protocol_cmd; - /** @brief response handlers, called when a command is parsed */ -static void (*g_ws_protocol_res_handlers[WS_PROTOCOL_CMD_AMOUNT])(ws_s_protocol_parsed_req_cmd*, ws_s_protocol_res*) = { - [WS_PROTOCOL_CMD_LAST_RECORDS] = &ws_protocol_res_last_records +static ws_protocol_res_handler_t* g_ws_protocol_res_handlers[WS_PROTOCOL_CMD_AMOUNT] = { + [WS_PROTOCOL_CMD_LAST_RECORDS] = &ws_protocol_res_last_records, }; diff --git a/shared/test.c b/shared/test.c index f9d4bbc..0968252 100644 --- a/shared/test.c +++ b/shared/test.c @@ -7,7 +7,7 @@ #include "protocol.h" -void ws_protocol_res_last_records(ws_s_protocol_parsed_req_cmd* parsed_cmd, ws_s_protocol_res* response) { +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" @@ -15,9 +15,18 @@ void ws_protocol_res_last_records(ws_s_protocol_parsed_req_cmd* parsed_cmd, ws_s "10de,31,c7,7f\n" "10df,35,ca,7e\n" "10e0,34,c9,7e\n"; - response->success = WS_PROTOCOL_CMD_RETURN_OK; - response->msg = ws_bin_s_alloc(strlen(response_text)); - strncpy((char*) response->msg->data, response_text, strlen(response_text)); + + if (!send) { + response->success = WS_PROTOCOL_CMD_RETURN_OK; + response->csh = true; + response->msg = ws_bin_s_alloc(0); + response->msg->bytes = strlen(response_text); + } 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); + } } void ws_protocol_send_data(ws_s_bin* data) { -- cgit v1.2.3 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 ++++ stm32f091/backlog.c | 41 ++++++++++++++++++++++++------------- stm32f091/backlog.h | 4 +++- 8 files changed, 183 insertions(+), 34 deletions(-) create mode 100644 shared/backlog.c create mode 100644 shared/backlog.h create mode 100644 shared/util.h (limited to 'shared/protocol.c') 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)) diff --git a/stm32f091/backlog.c b/stm32f091/backlog.c index 3f21924..926ccad 100644 --- a/stm32f091/backlog.c +++ b/stm32f091/backlog.c @@ -2,33 +2,46 @@ #include "backlog.h" -ws_s_backlog_database* WS_G_BACKLOG_DATABASE = NULL; +ws_s_backlog_database* g_ws_backlog_database = NULL; void ws_backlog_alloc(uint16_t record_amt) { - WS_G_BACKLOG_DATABASE = malloc(sizeof(ws_s_backlog_database) + sizeof(ws_s_backlog_record) * record_amt); - WS_G_BACKLOG_DATABASE->buffer_size = record_amt; - WS_G_BACKLOG_DATABASE->buffer_start = 0; - WS_G_BACKLOG_DATABASE->buffer_end = 0; + 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; - WS_G_BACKLOG_DATABASE->records[WS_G_BACKLOG_DATABASE->buffer_end].id = id++; - WS_G_BACKLOG_DATABASE->records[WS_G_BACKLOG_DATABASE->buffer_end].sens_atm_pressure = record.sens_atm_pressure; - WS_G_BACKLOG_DATABASE->records[WS_G_BACKLOG_DATABASE->buffer_end].sens_humidity = record.sens_humidity; - WS_G_BACKLOG_DATABASE->records[WS_G_BACKLOG_DATABASE->buffer_end].sens_temperature = record.sens_temperature; + 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 - WS_G_BACKLOG_DATABASE->buffer_end = (WS_G_BACKLOG_DATABASE->buffer_end + 1) % WS_G_BACKLOG_DATABASE->buffer_size; - if (WS_G_BACKLOG_DATABASE->buffer_end == WS_G_BACKLOG_DATABASE->buffer_start) - WS_G_BACKLOG_DATABASE->buffer_start = (WS_G_BACKLOG_DATABASE->buffer_start + 1) % WS_G_BACKLOG_DATABASE->buffer_size; + 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 &WS_G_BACKLOG_DATABASE->records[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((WS_G_BACKLOG_DATABASE->buffer_end - record_offset - 1) % WS_G_BACKLOG_DATABASE->buffer_size); + 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/stm32f091/backlog.h b/stm32f091/backlog.h index 465b3c0..c8ea019 100644 --- a/stm32f091/backlog.h +++ b/stm32f091/backlog.h @@ -30,7 +30,7 @@ typedef struct { #pragma pack(pop) /** @brief global record backlog database pointer */ -extern ws_s_backlog_database* WS_G_BACKLOG_DATABASE; +extern ws_s_backlog_database* g_ws_backlog_database; /** * @brief add record to database @@ -55,3 +55,5 @@ 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(); -- cgit v1.2.3 From aab4ed17b94f54813368201d3a0cba3f3d432589 Mon Sep 17 00:00:00 2001 From: lonkaars Date: Wed, 19 Oct 2022 20:04:06 +0200 Subject: integrate protocol code into stm32 code --- shared/backlog.c | 47 ---------------------------- shared/backlog.h | 59 ----------------------------------- shared/makefile | 24 --------------- shared/protocol.c | 87 ++++++++++++++++++++++++++-------------------------- shared/protocol.md | 7 +++-- shared/shared.mk | 1 + shared/test.c | 82 ------------------------------------------------- shared/testcmd | 1 - stm32f091/backlog.c | 5 --- stm32f091/esp8266.c | 7 +++-- stm32f091/main.c | 1 - stm32f091/makefile | 8 +++++ stm32f091/protocol.c | 33 ++++++++++++++++++++ stm32f091/sensor.c | 6 ++++ stm32f091/server.c | 2 +- stm32f091/util.h | 3 +- 16 files changed, 103 insertions(+), 270 deletions(-) delete mode 100644 shared/backlog.c delete mode 100644 shared/backlog.h delete mode 100644 shared/makefile create mode 100644 shared/shared.mk delete mode 100644 shared/test.c delete mode 100644 shared/testcmd create mode 100644 stm32f091/protocol.c (limited to 'shared/protocol.c') diff --git a/shared/backlog.c b/shared/backlog.c deleted file mode 100644 index 926ccad..0000000 --- a/shared/backlog.c +++ /dev/null @@ -1,47 +0,0 @@ -#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 deleted file mode 100644 index c8ea019..0000000 --- a/shared/backlog.h +++ /dev/null @@ -1,59 +0,0 @@ -#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/makefile b/shared/makefile deleted file mode 100644 index 2093f00..0000000 --- a/shared/makefile +++ /dev/null @@ -1,24 +0,0 @@ -CC = gcc -LD = gcc -RM = rm -f -CFLAGS = -g -std=c11 -LFLAGS = -TARGET = main - -SRCS := $(wildcard *.c) -OBJS := $(patsubst %.c,%.o, $(SRCS)) - -all: main - -%.o: %.c - $(CC) -c $(CFLAGS) $< -o $@ - -$(TARGET): $(OBJS) - $(LD) $^ $(LFLAGS) -o $@ - -clean: - $(RM) $(TARGET) $(OBJS) - -compile_commands: clean - compiledb make - diff --git a/shared/protocol.c b/shared/protocol.c index 55e6759..c6e5ddd 100644 --- a/shared/protocol.c +++ b/shared/protocol.c @@ -15,30 +15,30 @@ static ws_e_protocol_cmd ws_protocol_get_req_cmd_code(ws_s_protocol_parsed_req_c } void ws_protocol_parse_req_byte(ws_s_protocol_req_parser_state* state, char input) { - switch(input) { - case WS_PROTOCOL_C_EOL: { - break; - } + switch(input) { + case WS_PROTOCOL_C_EOL: { + break; + } - case WS_PROTOCOL_C_SPACE: { - if (!state->valid) return; + case WS_PROTOCOL_C_SPACE: { + if (!state->valid) return; state->arg_len++; - return; - } - - case WS_PROTOCOL_C_NULL: { - state->valid = false; - return; - } - - default: { - if (!state->valid) return; - state->cmd[state->cmd_len++] = input; - state->args_len[state->arg_len] += 1; - if (state->cmd_len == WS_PROTOCOL_CMD_BUFFER_LEN) state->valid = false; - return; - } - } + return; + } + + case WS_PROTOCOL_C_NULL: { + state->valid = false; + return; + } + + default: { + if (!state->valid) return; + state->cmd[state->cmd_len++] = input; + state->args_len[state->arg_len] += 1; + if (state->cmd_len == WS_PROTOCOL_CMD_BUFFER_LEN) state->valid = false; + return; + } + } // arg_len is used as an index while parsing, so add 1 to get length state->arg_len++; @@ -85,22 +85,23 @@ ws_protocol_parse_exit: } void ws_protocol_parse_req_bytes(ws_s_protocol_req_parser_state* state, char* input, unsigned int length) { - for (unsigned int i = 0; i < length; i++) ws_protocol_parse_req_byte(state, input[i]); + for (unsigned int i = 0; i < length; i++) ws_protocol_parse_req_byte(state, input[i]); } ws_s_protocol_req_parser_state* ws_protocol_req_parser_alloc() { - ws_s_protocol_req_parser_state* parser_state = malloc(sizeof(ws_s_protocol_req_parser_state) + sizeof(uint16_t) * WS_PROTOCOL_CMD_MAX_ARGUMENTS); - parser_state->cmd = malloc(sizeof(char) * WS_PROTOCOL_CMD_BUFFER_LEN); + ws_s_protocol_req_parser_state* parser_state = malloc(sizeof(ws_s_protocol_req_parser_state) + sizeof(uint16_t) * WS_PROTOCOL_CMD_MAX_ARGUMENTS); + parser_state->cmd = malloc(sizeof(char) * WS_PROTOCOL_CMD_BUFFER_LEN); + parser_state->target = NULL; ws_protocol_req_parser_reset(parser_state); - return parser_state; + return parser_state; } void ws_protocol_req_cmd_init(ws_s_protocol_req_parser_state* state) { - state->target = malloc(sizeof(ws_s_protocol_parsed_req_cmd) + sizeof(char*) * state->arg_len); - for (unsigned int i = 0; i < state->arg_len; i++) - state->target->argv[i] = malloc(sizeof(char) * (state->args_len[i] + 1)); + state->target = malloc(sizeof(ws_s_protocol_parsed_req_cmd) + sizeof(char*) * state->arg_len); + for (unsigned int i = 0; i < state->arg_len; i++) + state->target->argv[i] = malloc(sizeof(char) * (state->args_len[i] + 1)); - state->target->argc = state->arg_len; + state->target->argc = state->arg_len; unsigned int head = 0; for (unsigned int i = 0; i < state->arg_len; i++) { @@ -111,26 +112,26 @@ void ws_protocol_req_cmd_init(ws_s_protocol_req_parser_state* state) { } void ws_protocol_req_parser_free(ws_s_protocol_req_parser_state* state) { - if (state == NULL) return; - if (state->target != NULL) ws_protocol_req_cmd_free(state->target); + if (state == NULL) return; + if (state->target != NULL) ws_protocol_req_cmd_free(state->target); state->target = NULL; - free(state->cmd); - free(state); - return; + free(state->cmd); + free(state); + return; } void ws_protocol_req_parser_reset(ws_s_protocol_req_parser_state* state) { if (state->target != NULL) ws_protocol_req_cmd_free(state->target); - state->target = NULL; - state->valid = true; - state->cmd_len = 0; - state->arg_len = 0; + state->target = NULL; + state->valid = true; + state->cmd_len = 0; + state->arg_len = 0; memset(state->args_len, 0, sizeof(uint16_t) * WS_PROTOCOL_CMD_MAX_ARGUMENTS); } void ws_protocol_req_cmd_free(ws_s_protocol_parsed_req_cmd* cmd) { - for (unsigned int i = 0; i < cmd->argc; i++) - free(cmd->argv[i]); - free(cmd); - return; + for (int i = 0; i < cmd->argc; i++) + free(cmd->argv[i]); + free(cmd); + return; } diff --git a/shared/protocol.md b/shared/protocol.md index bafec4d..b6e955c 100644 --- a/shared/protocol.md +++ b/shared/protocol.md @@ -29,8 +29,9 @@ conventions. Returns the last `n` records in csv format. The first line has the csv table header, with the fields `id`, `temperature`, `humidity`, and `atmospheric_pressure`. The rest of the response consists of 1 record per line. -When `n` is 0, or no records exist yet, the csv header is still returned, but -without any records. +The amount of records is limited to the amount of valid records in the backlog +buffer. When the amount of returned records is 0, the response consists of the +csv header, but without any following records. ## Example transaction @@ -39,7 +40,7 @@ starting with `<`, and response by lines starting with `>`. ``` < last-records 5<0a> -> ok,115<0a> +> ok,73<0a> > id,temperature,humidity,atmospheric_pressure<0a> > 10dc,2f,c5,7f<0a> > 10dd,30,c6,7f<0a> diff --git a/shared/shared.mk b/shared/shared.mk new file mode 100644 index 0000000..f9586ff --- /dev/null +++ b/shared/shared.mk @@ -0,0 +1 @@ +OBJS += $(patsubst %.c,%-stm.o, $(wildcard ../shared/*.c)) diff --git a/shared/test.c b/shared/test.c deleted file mode 100644 index 287332a..0000000 --- a/shared/test.c +++ /dev/null @@ -1,82 +0,0 @@ -#include -#include -#include -#include -#include -#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) { - 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_header) + response_line_size * record_amount; - } else { - // example send routine - 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(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; - tcgetattr(STDIN_FILENO, &term); - term.c_lflag &= ~(ECHO | ICANON); - term.c_cc[VTIME] = 0; - term.c_cc[VMIN] = 1; - tcsetattr(STDIN_FILENO, 0, &term); - - 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; - while(read(STDIN_FILENO, &byte, 1) > 0) - ws_protocol_parse_req_byte(parser1, byte); - - ws_protocol_req_parser_free(parser1); - parser1 = NULL; - - return 0; -} diff --git a/shared/testcmd b/shared/testcmd deleted file mode 100644 index 17f8842..0000000 --- a/shared/testcmd +++ /dev/null @@ -1 +0,0 @@ -last-records 5 diff --git a/stm32f091/backlog.c b/stm32f091/backlog.c index 926ccad..662fc75 100644 --- a/stm32f091/backlog.c +++ b/stm32f091/backlog.c @@ -33,11 +33,6 @@ 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) diff --git a/stm32f091/esp8266.c b/stm32f091/esp8266.c index 6f12191..4c5d0d2 100644 --- a/stm32f091/esp8266.c +++ b/stm32f091/esp8266.c @@ -22,7 +22,7 @@ void ws_esp8266_ATsendCommand(uint8_t* data){ } int ws_esp8266_checkOK(uint8_t *receiveData,int length){ char *ret=""; - char *ret1=""; + // char *ret1=""; HAL_UART_Transmit(&huart2, receiveData,length,1000); ret = strstr((char*)receiveData,"OK"); // ret = strstr((char*)receiveData,"change"); @@ -159,8 +159,9 @@ void ws_esp8266_serveraan(){ HAL_Delay(1000); } void ws_esp8266_serveruit(){ - int ret; - uint8_t buffer1[27]={0}; uint8_t Tx_server[]="AT+CIPSERVER=0\r\n"; + //int ret; + //uint8_t buffer1[27]={0}; + uint8_t Tx_server[]="AT+CIPSERVER=0\r\n"; // // while(ret!=1){ diff --git a/stm32f091/main.c b/stm32f091/main.c index 9235f1b..7cb0718 100644 --- a/stm32f091/main.c +++ b/stm32f091/main.c @@ -16,7 +16,6 @@ int main() { }); ws_backlog_alloc(24 * 60); - ws_sensor_read(); xTaskCreate(ws_sensor_read_task, "sensor", 128, NULL, 1, NULL); vTaskStartScheduler(); diff --git a/stm32f091/makefile b/stm32f091/makefile index 5a185de..20424c3 100644 --- a/stm32f091/makefile +++ b/stm32f091/makefile @@ -5,6 +5,8 @@ RM = rm -f TARGET = main +include ../shared/shared.mk + SHARED_FLAGS += -g SHARED_FLAGS += -DSTM32F091xC SHARED_FLAGS += -Wall @@ -74,9 +76,15 @@ $(TARGET).bin: $(TARGET).elf %.o: %.s $(CC) -c $(AFLAGS) $< -o $@ +lib/%.o: lib/%.c + $(CC) -c $(CFLAGS) -w $< -o $@ + %.o: %.c $(CC) -c $(CFLAGS) $< -o $@ +%-stm.o: %.c + $(CC) -c $(CFLAGS) $< -o $@ + $(TARGET).elf: $(OBJS) $(LD) $(LFLAGS) $^ -o $@ diff --git a/stm32f091/protocol.c b/stm32f091/protocol.c new file mode 100644 index 0000000..589ee5d --- /dev/null +++ b/stm32f091/protocol.c @@ -0,0 +1,33 @@ +#include + +#include "../shared/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) { + 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_header) + response_line_size * record_amount; + } else { + 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(const char* data, unsigned int length) { + //TODO: implement on esp data channels + HAL_UART_Transmit(&huart2, (uint8_t*) data, length, HAL_MAX_DELAY); +} diff --git a/stm32f091/sensor.c b/stm32f091/sensor.c index bc3cfd3..1c94e2a 100644 --- a/stm32f091/sensor.c +++ b/stm32f091/sensor.c @@ -58,6 +58,12 @@ void ws_sensor_read() { .sens_humidity = ws_sensor_humidity() }; ws_backlog_add_record(record); + + // < DEBUG PROTOCOL PARSING CODE > + // ws_s_protocol_req_parser_state* parser = ws_protocol_req_parser_alloc(); + // const char* request = "last-records 5\n"; + // ws_protocol_parse_req_bytes(parser, (char*) request, strlen(request)); + // ws_protocol_req_parser_free(parser); } void ws_sensor_read_task() { diff --git a/stm32f091/server.c b/stm32f091/server.c index e289245..4840527 100644 --- a/stm32f091/server.c +++ b/stm32f091/server.c @@ -28,7 +28,7 @@ void ws_server_demo() { uint8_t receive[24]={0}; uint8_t sendToQTData[]="gelukt"; uint8_t test[]="test"; - int ret; + //int ret; //ATsendCommand(sendToQTData); while (1) { diff --git a/stm32f091/util.h b/stm32f091/util.h index 8e3258f..92f093f 100644 --- a/stm32f091/util.h +++ b/stm32f091/util.h @@ -6,10 +6,11 @@ #include #include "setup.h" +#include "../shared/util.h" #define ws_usb_printf(fmt, ...) { \ char temp[255]; \ - sprintf(temp, fmt, ##__VA_ARGS__); \ + snprintf(temp, 255, fmt, ##__VA_ARGS__); \ HAL_UART_Transmit(&huart2, (uint8_t*) temp, sizeof(char) * strlen(temp), HAL_MAX_DELAY); \ } -- cgit v1.2.3 From 89e652af2506f7cf7854ce2e6f5b9b97423d1d40 Mon Sep 17 00:00:00 2001 From: lonkaars Date: Thu, 27 Oct 2022 18:33:43 +0200 Subject: fix dumb typo's and added comments to faulty code --- shared/protocol.c | 5 ++++- stm32f091/server.c | 6 +++--- stm32f091/setup.c | 2 ++ 3 files changed, 9 insertions(+), 4 deletions(-) (limited to 'shared/protocol.c') diff --git a/shared/protocol.c b/shared/protocol.c index c6e5ddd..ca0edc4 100644 --- a/shared/protocol.c +++ b/shared/protocol.c @@ -99,7 +99,10 @@ ws_s_protocol_req_parser_state* ws_protocol_req_parser_alloc() { void ws_protocol_req_cmd_init(ws_s_protocol_req_parser_state* state) { state->target = malloc(sizeof(ws_s_protocol_parsed_req_cmd) + sizeof(char*) * state->arg_len); for (unsigned int i = 0; i < state->arg_len; i++) - state->target->argv[i] = malloc(sizeof(char) * (state->args_len[i] + 1)); + state->target->argv[i] = malloc(sizeof(char) * (state->args_len[i] + 1)); // segfaults on 2nd run? + // state->target->argv stays empty according to debugger + // goes to HardFault_Handler on 2nd iteration + // this might be the stm running out of heap memory though i'm not sure state->target->argc = state->arg_len; diff --git a/stm32f091/server.c b/stm32f091/server.c index 1b677c2..7e44774 100644 --- a/stm32f091/server.c +++ b/stm32f091/server.c @@ -16,7 +16,7 @@ static ws_s_server_parser g_ws_server_parser = { .current_channel = 0, .channel_data_length = 0, .channel_data_counter = 0, - .channel_listen_mode = WS_SERVER_CL_DATA_LENGTH, + .channel_listen_mode = WS_SERVER_CL_CHANNEL_ID, }; static ws_s_protocol_req_parser_state* g_ws_protocol_parsers[WS_SERVER_MAX_CHANNELS] = {0}; @@ -101,8 +101,8 @@ void ws_server_req_incoming(uint8_t* data, size_t size) { g_ws_server_parser.channel_data_ignore = true; break; } - g_ws_server_parser.current_channel *= 10; - g_ws_server_parser.current_channel += byte - '0'; // ascii to int + g_ws_server_parser.channel_data_length *= 10; + g_ws_server_parser.channel_data_length += byte - '0'; // ascii to int break; } case WS_SERVER_CL_DATA_READ: { diff --git a/stm32f091/setup.c b/stm32f091/setup.c index 2175ab3..5b6c6a4 100644 --- a/stm32f091/setup.c +++ b/stm32f091/setup.c @@ -90,7 +90,9 @@ void ws_io_setup() { .Pull = GPIO_NOPULL }); + // TODO: remove debug size ws_backlog_alloc(24 * 60); + // ws_backlog_alloc(10); #ifdef WS_ESP8266_WLAN_MAC ws_esp8266_set_mac(); -- cgit v1.2.3 From 1cac46e7701ef2783aea13d55261582f4d91f2fa Mon Sep 17 00:00:00 2001 From: lonkaars Date: Fri, 28 Oct 2022 09:57:50 +0200 Subject: working janky protocol! --- shared/protocol.c | 14 ++++++++++---- shared/protocol.h | 3 ++- shared/util.c | 7 +++++++ shared/util.h | 2 ++ stm32f091/esp8266.c | 27 -------------------------- stm32f091/protocol.c | 8 ++++++-- stm32f091/server.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++------ stm32f091/server.h | 13 +++++++++++-- stm32f091/setup.c | 3 ++- 9 files changed, 88 insertions(+), 43 deletions(-) create mode 100644 shared/util.c (limited to 'shared/protocol.c') diff --git a/shared/protocol.c b/shared/protocol.c index ca0edc4..fcc84a4 100644 --- a/shared/protocol.c +++ b/shared/protocol.c @@ -3,6 +3,7 @@ #include #include "protocol.h" +#include "util.h" #define WS_CMD_MAP(parsed_cmd, name, code) \ if (strlen(parsed_cmd->argv[0]) == strlen(name) && strncmp(parsed_cmd->argv[0], name, strlen(name)) == 0) return code; @@ -99,10 +100,7 @@ ws_s_protocol_req_parser_state* ws_protocol_req_parser_alloc() { void ws_protocol_req_cmd_init(ws_s_protocol_req_parser_state* state) { state->target = malloc(sizeof(ws_s_protocol_parsed_req_cmd) + sizeof(char*) * state->arg_len); for (unsigned int i = 0; i < state->arg_len; i++) - state->target->argv[i] = malloc(sizeof(char) * (state->args_len[i] + 1)); // segfaults on 2nd run? - // state->target->argv stays empty according to debugger - // goes to HardFault_Handler on 2nd iteration - // this might be the stm running out of heap memory though i'm not sure + state->target->argv[i] = malloc(sizeof(char) * (state->args_len[i] + 1)); state->target->argc = state->arg_len; @@ -138,3 +136,11 @@ void ws_protocol_req_cmd_free(ws_s_protocol_parsed_req_cmd* cmd) { free(cmd); return; } + +unsigned short ws_protocol_get_header_size(ws_s_protocol_res* response) { + unsigned short size = 2; // comma and trailing newline + if (response->success == WS_PROTOCOL_CMD_RETURN_OK) size += 2; // ok + if (response->success == WS_PROTOCOL_CMD_RETURN_ERROR) size += 5; // error + size += ws_log16(response->msg->bytes); // amount of characters for message size (hex) + return size; +} \ No newline at end of file diff --git a/shared/protocol.h b/shared/protocol.h index fbe29d6..5bcb114 100644 --- a/shared/protocol.h +++ b/shared/protocol.h @@ -5,7 +5,7 @@ #include "bin.h" -#define WS_PROTOCOL_CMD_MAX_ARGUMENTS (1) +#define WS_PROTOCOL_CMD_MAX_ARGUMENTS (2) #define WS_PROTOCOL_CMD_BUFFER_LEN (40) #define WS_PROTOCOL_CMD_AMOUNT (1) @@ -148,3 +148,4 @@ static ws_protocol_res_handler_t* g_ws_protocol_res_handlers[WS_PROTOCOL_CMD_AMO [WS_PROTOCOL_CMD_LAST_RECORDS] = &ws_protocol_res_last_records, }; +unsigned short ws_protocol_get_header_size(ws_s_protocol_res* response); \ No newline at end of file diff --git a/shared/util.c b/shared/util.c new file mode 100644 index 0000000..ea972b0 --- /dev/null +++ b/shared/util.c @@ -0,0 +1,7 @@ +#include "util.h" + +unsigned int ws_log16(unsigned int x) { + unsigned int l = 0; + while (x >>= 4) ++l; // bitshift right by 4 until x == 0 + return l; +} \ No newline at end of file diff --git a/shared/util.h b/shared/util.h index f39ff34..94a3dfe 100644 --- a/shared/util.h +++ b/shared/util.h @@ -2,3 +2,5 @@ #define WS_MIN(a, b) (((a) < (b)) ? (a) : (b)) #define WS_MAX(a, b) (((a) > (b)) ? (a) : (b)) + +unsigned int ws_log16(unsigned int x); diff --git a/stm32f091/esp8266.c b/stm32f091/esp8266.c index d45954e..db134a0 100644 --- a/stm32f091/esp8266.c +++ b/stm32f091/esp8266.c @@ -80,30 +80,3 @@ void ws_esp8266_set_mac() { void ws_esp8266_set_ip() { ws_esp8266_send_seq("AT+CIPSTA=\"" WS_ESP8266_WLAN_IP "\"\r\n"); } - -// TODO: refactor code from here to EOF -void ws_esp8266_ATsendCommand(uint8_t* data){ - char dataChar[20]; - uint8_t Tx_send[]="AT+CIPSEND=0,"; - - itoa(strlen((char*)data),dataChar,10); - strcat((char*)Tx_send,dataChar); - strcat((char*)Tx_send,"\r\n"); - HAL_UART_Transmit(&huart1, Tx_send, strlen((char*)Tx_send),1000); - HAL_Delay(2000); - HAL_UART_Transmit(&huart1, data, strlen((char*)data),1000); - HAL_Delay(1000); - HAL_UART_Transmit(&huart2, data, strlen((char*)data),1000); - HAL_Delay(5000); -} -void ws_esp8266_close(){ - - uint8_t Tx_close[]="AT+CIPCLOSE=0\r\n"; - - - HAL_UART_Transmit(&huart1, Tx_close,strlen((char*)Tx_close), 100); - - HAL_Delay(3000); - -} - diff --git a/stm32f091/protocol.c b/stm32f091/protocol.c index 589ee5d..3a8d78b 100644 --- a/stm32f091/protocol.c +++ b/stm32f091/protocol.c @@ -3,6 +3,8 @@ #include "../shared/protocol.h" #include "backlog.h" #include "util.h" +#include "server.h" +#include "esp8266.h" void ws_protocol_res_last_records(ws_s_protocol_parsed_req_cmd* parsed_cmd, ws_s_protocol_res* response, bool send) { static unsigned int record_amount = 0; @@ -16,6 +18,7 @@ void ws_protocol_res_last_records(ws_s_protocol_parsed_req_cmd* parsed_cmd, ws_s response->csh = true; response->msg = ws_bin_s_alloc(0); response->msg->bytes = strlen(response_header) + response_line_size * record_amount; + ws_server_req_respond_start(0, response->msg->bytes + ws_protocol_get_header_size(response)); } else { ws_protocol_send_data(response_header, strlen(response_header)); char line[response_line_size + 1]; // +1 for null terminator -> sprintf @@ -24,10 +27,11 @@ void ws_protocol_res_last_records(ws_s_protocol_parsed_req_cmd* parsed_cmd, ws_s 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); } + ws_protocol_send_data("\r\n", 2); // test } } void ws_protocol_send_data(const char* data, unsigned int length) { - //TODO: implement on esp data channels - HAL_UART_Transmit(&huart2, (uint8_t*) data, length, HAL_MAX_DELAY); + ws_server_buffer_send_append((uint8_t*) data, length); + // HAL_UART_Transmit(&huart1, (uint8_t*) data, length, HAL_MAX_DELAY); } diff --git a/stm32f091/server.c b/stm32f091/server.c index 7e44774..d4f7e20 100644 --- a/stm32f091/server.c +++ b/stm32f091/server.c @@ -9,7 +9,7 @@ #include "setup.h" #include "consts.h" -static ws_s_server_parser g_ws_server_parser = { +ws_s_server_parser g_ws_server_parser = { .last_response = WS_SERVER_RC_NONE, .mode = WS_SERVER_LM_IDLE, @@ -20,7 +20,7 @@ static ws_s_server_parser g_ws_server_parser = { }; static ws_s_protocol_req_parser_state* g_ws_protocol_parsers[WS_SERVER_MAX_CHANNELS] = {0}; - +static unsigned int g_ws_esp8266_dma_tx_buffer_index = 0; void ws_server_req_parse_byte(unsigned int channel, uint8_t byte, bool ignore) { if (ignore) return; @@ -80,6 +80,9 @@ void ws_server_req_incoming(uint8_t* data, size_t size) { if (next_few_bytes_are("+IPD,")) { i += 4; // skip I, P, D, and comma g_ws_server_parser.mode = WS_SERVER_LM_IPD_LISTENING; + } else if (byte == '>') { + g_ws_server_parser.mode = WS_SERVER_LM_CIPSEND_LISTENING; + ws_server_buffer_send_finish(); } break; } @@ -114,6 +117,7 @@ void ws_server_req_incoming(uint8_t* data, size_t size) { g_ws_server_parser.channel_data_length = 0; g_ws_server_parser.channel_listen_mode = WS_SERVER_CL_CHANNEL_ID; ws_server_req_finish(g_ws_server_parser.current_channel, g_ws_server_parser.channel_data_ignore); + g_ws_server_parser.mode = WS_SERVER_LM_IDLE; } break; } @@ -121,6 +125,14 @@ void ws_server_req_incoming(uint8_t* data, size_t size) { } break; } + case WS_SERVER_LM_CIPSEND_LISTENING: { + if (next_few_bytes_are("SEND OK")) { + i += 6; + // g_ws_server_parser.mode = WS_SERVER_LM_IDLE; + ws_server_req_respond_end(0); + } + break; + } default: {} } } @@ -132,9 +144,39 @@ void ws_server_send(uint8_t* data, size_t size) { while (g_ws_server_parser.mode != WS_SERVER_LM_IDLE) {}; } -void ws_server_req_respond(unsigned int channel, uint8_t* data, size_t size) { - uint8_t Tx_send[]="AT+CIPSEND=0,LEN:"; - uint8_t Tx_close[]="AT+CIPCLOSE=0\r\n"; - return; +void ws_server_buffer_send_append(uint8_t* data, size_t size) { + // TODO: buffer overrun protection + // while (!__HAL_DMA_GET_FLAG(&hdma_usart1_tx, DMA_FLAG_TC2)); // make sure buffer isn't used + strncpy((char*) &g_ws_esp8266_dma_tx_buffer[g_ws_esp8266_dma_tx_buffer_index], (char*) data, size); // append string + g_ws_esp8266_dma_tx_buffer_index += size; // shift head +} + +void ws_server_buffer_send_finish() { +#ifdef WS_DBG_PRINT_ESP_OVER_USART2 + uint8_t green[] = { 0x1b, 0x5b, 0x33, 0x32, 0x6d }; + HAL_UART_Transmit(&huart2, green, sizeof(green), 100); + HAL_UART_Transmit(&huart2, g_ws_esp8266_dma_tx_buffer, strlen((char*) g_ws_esp8266_dma_tx_buffer), 100); +#endif + + HAL_UART_Transmit_DMA(&huart1, g_ws_esp8266_dma_tx_buffer, strlen((char*) g_ws_esp8266_dma_tx_buffer)); + __HAL_UART_ENABLE_IT(&huart1, UART_IT_TXE); + g_ws_esp8266_dma_tx_buffer_index = 0; + while (!__HAL_DMA_GET_FLAG(&hdma_usart1_tx, DMA_FLAG_TC2)); +} + +void ws_server_req_respond_start(unsigned int channel, size_t size) { + char* cmd = NULL; + size_t len = asiprintf(&cmd, "AT+CIPSEND=%d,%d\r\n", channel, size); + g_ws_server_parser.mode = WS_SERVER_LM_CMD_ECHO; + ws_esp8266_send((uint8_t*) cmd, len); + while (!__HAL_DMA_GET_FLAG(&hdma_usart1_tx, DMA_FLAG_TC2)); +} + +void ws_server_req_respond_end(unsigned int channel) { + char* cmd = NULL; + size_t len = asiprintf(&cmd, "AT+CIPCLOSE=%d\r\n", channel); + g_ws_server_parser.mode = WS_SERVER_LM_CMD_ECHO; + ws_esp8266_send((uint8_t*) cmd, len); + while (!__HAL_DMA_GET_FLAG(&hdma_usart1_tx, DMA_FLAG_TC2)); } diff --git a/stm32f091/server.h b/stm32f091/server.h index 44882e4..128b579 100644 --- a/stm32f091/server.h +++ b/stm32f091/server.h @@ -9,6 +9,7 @@ typedef enum { WS_SERVER_LM_STATUS_CODE, /** @brief listen for busy, ERROR or OK */ WS_SERVER_LM_IDLE, /** @brief listen for incoming +IPD commands */ WS_SERVER_LM_IPD_LISTENING, /** @brief +IPD received, now reading data */ + WS_SERVER_LM_CIPSEND_LISTENING, /** @brief AT+CIPSEND sent, now reading data */ } ws_e_server_listen_mode; typedef enum { @@ -34,6 +35,9 @@ typedef struct { bool channel_data_ignore; } ws_s_server_parser; +/** @brief global server parser struct */ +extern ws_s_server_parser g_ws_server_parser; + /** * @brief +IPD incoming request handler * @@ -46,8 +50,10 @@ typedef struct { */ void ws_server_req_incoming(uint8_t* data, size_t size); -/** @brief send response to incoming request on specific channel */ -void ws_server_req_respond(unsigned int channel, uint8_t* data, size_t size); +/** @brief send AT response header for incoming request on specific channel */ +void ws_server_req_respond_start(unsigned int channel, size_t size); +/** @brief send AT tcp close on specific channel */ +void ws_server_req_respond_end(unsigned int channel); /** @brief send data to esp, waiting until server returns to idle mode */ void ws_server_send(uint8_t* data, size_t size); @@ -74,3 +80,6 @@ void ws_server_req_parse_byte(unsigned int channel, uint8_t byte, bool ignore); * @param ignore ignore mode */ void ws_server_req_finish(unsigned int channel, bool ignore); + +void ws_server_buffer_send_append(uint8_t* data, size_t size); +void ws_server_buffer_send_finish(); diff --git a/stm32f091/setup.c b/stm32f091/setup.c index 5b6c6a4..1971809 100644 --- a/stm32f091/setup.c +++ b/stm32f091/setup.c @@ -8,6 +8,7 @@ #include "esp8266.h" #include "setup.h" #include "backlog.h" +#include "server.h" I2C_HandleTypeDef hi2c1 = { .Instance = I2C1, @@ -101,7 +102,7 @@ void ws_io_setup() { ws_esp8266_set_ip(); #endif ws_esp8266_ap_client_mode(); - ws_esp8266_connect(); + do ws_esp8266_connect(); while (g_ws_server_parser.last_response == WS_SERVER_RC_ERR); ws_esp8266_start_tcp_server(); } -- cgit v1.2.3 From 4cd465332087e4ab12709f28fae55df10e1a1154 Mon Sep 17 00:00:00 2001 From: lonkaars Date: Fri, 28 Oct 2022 12:14:50 +0200 Subject: add todo.md, fixed segfault in protocol.c, and fix response sending --- shared/protocol.c | 5 +++-- stm32f091/consts.h | 2 +- stm32f091/protocol.c | 13 +++++++------ stm32f091/server.c | 18 ++++++++++-------- stm32f091/todo.md | 10 ++++++++++ 5 files changed, 31 insertions(+), 17 deletions(-) create mode 100644 stm32f091/todo.md (limited to 'shared/protocol.c') diff --git a/shared/protocol.c b/shared/protocol.c index fcc84a4..e17a728 100644 --- a/shared/protocol.c +++ b/shared/protocol.c @@ -99,10 +99,11 @@ ws_s_protocol_req_parser_state* ws_protocol_req_parser_alloc() { void ws_protocol_req_cmd_init(ws_s_protocol_req_parser_state* state) { state->target = malloc(sizeof(ws_s_protocol_parsed_req_cmd) + sizeof(char*) * state->arg_len); - for (unsigned int i = 0; i < state->arg_len; i++) + unsigned int args = WS_MIN(state->arg_len, WS_PROTOCOL_CMD_MAX_ARGUMENTS); + for (unsigned int i = 0; i < args; i++) state->target->argv[i] = malloc(sizeof(char) * (state->args_len[i] + 1)); - state->target->argc = state->arg_len; + state->target->argc = args; unsigned int head = 0; for (unsigned int i = 0; i < state->arg_len; i++) { diff --git a/stm32f091/consts.h b/stm32f091/consts.h index 3d2ef5a..955ceea 100644 --- a/stm32f091/consts.h +++ b/stm32f091/consts.h @@ -6,7 +6,7 @@ #define WS_SERVER_MAX_CHANNELS 4 #define WS_DMA_RX_BUFFER_SIZE 100 -#define WS_DMA_TX_BUFFER_SIZE 1024 +#define WS_DMA_TX_BUFFER_SIZE 100 #define WS_PINOUT_I2C_SDA_PIN GPIO_PIN_9 #define WS_PINOUT_I2C_SDA_PORT GPIOB diff --git a/stm32f091/protocol.c b/stm32f091/protocol.c index 3a8d78b..21e6527 100644 --- a/stm32f091/protocol.c +++ b/stm32f091/protocol.c @@ -13,19 +13,21 @@ void ws_protocol_res_last_records(ws_s_protocol_parsed_req_cmd* parsed_cmd, ws_s 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_header) + response_line_size * record_amount; + response->msg->bytes = 0; + record_amount = WS_MIN(record_amount, ws_backlog_get_record_count()); + if (sscanf(parsed_cmd->argv[1], "%u", &record_amount) < 1) response->success = WS_PROTOCOL_CMD_RETURN_ERROR; + else response->msg->bytes = strlen(response_header) + response_line_size * record_amount; ws_server_req_respond_start(0, response->msg->bytes + ws_protocol_get_header_size(response)); } else { + if (response->success == WS_PROTOCOL_CMD_RETURN_ERROR) return; ws_protocol_send_data(response_header, strlen(response_header)); - char line[response_line_size + 1]; // +1 for null terminator -> sprintf + char line[response_line_size]; 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); + ws_protocol_send_data(line, response_line_size - 1); // remove string terminator } ws_protocol_send_data("\r\n", 2); // test } @@ -33,5 +35,4 @@ void ws_protocol_res_last_records(ws_s_protocol_parsed_req_cmd* parsed_cmd, ws_s void ws_protocol_send_data(const char* data, unsigned int length) { ws_server_buffer_send_append((uint8_t*) data, length); - // HAL_UART_Transmit(&huart1, (uint8_t*) data, length, HAL_MAX_DELAY); } diff --git a/stm32f091/server.c b/stm32f091/server.c index 8001380..1419da8 100644 --- a/stm32f091/server.c +++ b/stm32f091/server.c @@ -20,7 +20,7 @@ ws_s_server_parser g_ws_server_parser = { }; static ws_s_protocol_req_parser_state* g_ws_protocol_parsers[WS_SERVER_MAX_CHANNELS] = {0}; -static unsigned int g_ws_esp8266_dma_tx_buffer_index = 0; +static unsigned int g_ws_esp8266_dma_tx_buffer_size = 0; void ws_server_req_parse_byte(unsigned int channel, uint8_t byte, bool ignore) { if (ignore) return; @@ -126,7 +126,7 @@ void ws_server_req_incoming(uint8_t* data, size_t size) { break; } case WS_SERVER_LM_CIPSEND_LISTENING: { - if (next_few_bytes_are("SEND OK")) { + if (next_few_bytes_are("SEND OK") || next_few_bytes_are("ERROR")) { ws_server_req_respond_end(0); // g_ws_server_parser.mode = WS_SERVER_LM_IDLE; } @@ -146,23 +146,25 @@ void ws_server_send(uint8_t* data, size_t size) { void ws_server_buffer_send_append(uint8_t* data, size_t size) { // TODO: buffer overrun protection // while (!__HAL_DMA_GET_FLAG(&hdma_usart1_tx, DMA_FLAG_TC2)); // make sure buffer isn't used - strncpy((char*) &g_ws_esp8266_dma_tx_buffer[g_ws_esp8266_dma_tx_buffer_index], (char*) data, size); // append string - g_ws_esp8266_dma_tx_buffer_index += size; // shift head + strncpy((char*) &g_ws_esp8266_dma_tx_buffer[g_ws_esp8266_dma_tx_buffer_size], (char*) data, size); // append string + g_ws_esp8266_dma_tx_buffer_size += size; // shift head } +// TODO: refactor this void ws_server_buffer_send_finish() { #ifdef WS_DBG_PRINT_ESP_OVER_USART2 uint8_t green[] = { 0x1b, 0x5b, 0x33, 0x32, 0x6d }; HAL_UART_Transmit(&huart2, green, sizeof(green), 100); - HAL_UART_Transmit(&huart2, g_ws_esp8266_dma_tx_buffer, strlen((char*) g_ws_esp8266_dma_tx_buffer), 100); + HAL_UART_Transmit(&huart2, g_ws_esp8266_dma_tx_buffer, g_ws_esp8266_dma_tx_buffer_size, 100); #endif - HAL_UART_Transmit_DMA(&huart1, g_ws_esp8266_dma_tx_buffer, strlen((char*) g_ws_esp8266_dma_tx_buffer)); + HAL_UART_Transmit_DMA(&huart1, g_ws_esp8266_dma_tx_buffer, g_ws_esp8266_dma_tx_buffer_size); __HAL_UART_ENABLE_IT(&huart1, UART_IT_TXE); - g_ws_esp8266_dma_tx_buffer_index = 0; + g_ws_esp8266_dma_tx_buffer_size = 0; while (!__HAL_DMA_GET_FLAG(&hdma_usart1_tx, DMA_FLAG_TC2)); } +// TODO: refactor this void ws_server_req_respond_start(unsigned int channel, size_t size) { char* cmd = NULL; size_t len = asiprintf(&cmd, "AT+CIPSEND=%d,%d\r\n", channel, size); @@ -171,6 +173,7 @@ void ws_server_req_respond_start(unsigned int channel, size_t size) { while (!__HAL_DMA_GET_FLAG(&hdma_usart1_tx, DMA_FLAG_TC2)); } +// TODO: refactor this void ws_server_req_respond_end(unsigned int channel) { char* cmd = NULL; size_t len = asiprintf(&cmd, "AT+CIPCLOSE=%d\r\n", channel); @@ -178,4 +181,3 @@ void ws_server_req_respond_end(unsigned int channel) { ws_esp8266_send((uint8_t*) cmd, len); while (!__HAL_DMA_GET_FLAG(&hdma_usart1_tx, DMA_FLAG_TC2)); } - diff --git a/stm32f091/todo.md b/stm32f091/todo.md new file mode 100644 index 0000000..767d745 --- /dev/null +++ b/stm32f091/todo.md @@ -0,0 +1,10 @@ +- handle errors from `AT+CIPSEND`, these look like this: + ``` + > AT0,CONNECT + + > +IPD,0,15:last-records 5<0a> + < AT+CIPSEND=0,125 + > AT+CIPSEND=0,125 + + > ERROR + ``` -- cgit v1.2.3 From babb6dc29a5c4af60292ffad5216317d13e2a685 Mon Sep 17 00:00:00 2001 From: lonkaars Date: Fri, 28 Oct 2022 14:31:56 +0200 Subject: fix off-by-one error and create macro for switching serial debug print color --- shared/protocol.c | 2 +- stm32f091/consts.h | 2 +- stm32f091/esp8266.c | 3 +-- stm32f091/protocol.c | 14 ++++++++------ stm32f091/server.c | 8 +++----- stm32f091/setup.c | 7 +++++++ stm32f091/util.h | 4 ++++ 7 files changed, 25 insertions(+), 15 deletions(-) (limited to 'shared/protocol.c') diff --git a/shared/protocol.c b/shared/protocol.c index e17a728..8887070 100644 --- a/shared/protocol.c +++ b/shared/protocol.c @@ -142,6 +142,6 @@ unsigned short ws_protocol_get_header_size(ws_s_protocol_res* response) { unsigned short size = 2; // comma and trailing newline if (response->success == WS_PROTOCOL_CMD_RETURN_OK) size += 2; // ok if (response->success == WS_PROTOCOL_CMD_RETURN_ERROR) size += 5; // error - size += ws_log16(response->msg->bytes); // amount of characters for message size (hex) + size += ws_log16(response->msg->bytes) + 1; // amount of characters for message size (hex) return size; } \ No newline at end of file diff --git a/stm32f091/consts.h b/stm32f091/consts.h index 955ceea..3d2ef5a 100644 --- a/stm32f091/consts.h +++ b/stm32f091/consts.h @@ -6,7 +6,7 @@ #define WS_SERVER_MAX_CHANNELS 4 #define WS_DMA_RX_BUFFER_SIZE 100 -#define WS_DMA_TX_BUFFER_SIZE 100 +#define WS_DMA_TX_BUFFER_SIZE 1024 #define WS_PINOUT_I2C_SDA_PIN GPIO_PIN_9 #define WS_PINOUT_I2C_SDA_PORT GPIOB diff --git a/stm32f091/esp8266.c b/stm32f091/esp8266.c index 754b45b..b896567 100644 --- a/stm32f091/esp8266.c +++ b/stm32f091/esp8266.c @@ -58,8 +58,7 @@ void ws_esp8266_send(uint8_t* data, size_t size) { g_ws_esp8266_dma_tx_buffer[limited_size] = 0x00; #ifdef WS_DBG_PRINT_ESP_OVER_USART2 - uint8_t green[] = { 0x1b, 0x5b, 0x33, 0x32, 0x6d }; - HAL_UART_Transmit(&huart2, green, sizeof(green), 100); + ws_dbg_set_usart2_tty_color(2); HAL_UART_Transmit(&huart2, g_ws_esp8266_dma_tx_buffer, strlen((char*) g_ws_esp8266_dma_tx_buffer), 100); #endif diff --git a/stm32f091/protocol.c b/stm32f091/protocol.c index 21e6527..4d605fc 100644 --- a/stm32f091/protocol.c +++ b/stm32f091/protocol.c @@ -9,27 +9,29 @@ void ws_protocol_res_last_records(ws_s_protocol_parsed_req_cmd* parsed_cmd, ws_s_protocol_res* response, bool send) { 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"); + const unsigned int response_line_len = strlen("xxxx,xx,xx,xx\n"); if (!send) { response->success = WS_PROTOCOL_CMD_RETURN_OK; response->csh = true; response->msg = ws_bin_s_alloc(0); response->msg->bytes = 0; - record_amount = WS_MIN(record_amount, ws_backlog_get_record_count()); if (sscanf(parsed_cmd->argv[1], "%u", &record_amount) < 1) response->success = WS_PROTOCOL_CMD_RETURN_ERROR; - else response->msg->bytes = strlen(response_header) + response_line_size * record_amount; + else { + record_amount = WS_MIN(record_amount, ws_backlog_get_record_count()); + response->msg->bytes = strlen(response_header) + response_line_len * record_amount; + } ws_server_req_respond_start(0, response->msg->bytes + ws_protocol_get_header_size(response)); } else { if (response->success == WS_PROTOCOL_CMD_RETURN_ERROR) return; ws_protocol_send_data(response_header, strlen(response_header)); - char line[response_line_size]; + char line[response_line_len + 1]; // + 1 for string terminator 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 - 1); // remove string terminator + ws_protocol_send_data(line, response_line_len); // remove string terminator } - ws_protocol_send_data("\r\n", 2); // test + // ws_protocol_send_data("\r\n", 2); // test } } diff --git a/stm32f091/server.c b/stm32f091/server.c index 1419da8..6225eae 100644 --- a/stm32f091/server.c +++ b/stm32f091/server.c @@ -8,6 +8,7 @@ #include "server.h" #include "setup.h" #include "consts.h" +#include "util.h" ws_s_server_parser g_ws_server_parser = { .last_response = WS_SERVER_RC_NONE, @@ -48,8 +49,7 @@ void ws_server_req_finish(unsigned int channel, bool ignore) { #define next_few_bytes_are(code) (i + sizeof(code) - 1 < size && strncmp((char*)&data[i], code, sizeof(code) - 1) == 0) void ws_server_req_incoming(uint8_t* data, size_t size) { #ifdef WS_DBG_PRINT_ESP_OVER_USART2 - uint8_t red[] = { 0x1b, 0x5b, 0x33, 0x31, 0x6d }; - HAL_UART_Transmit(&huart2, red, sizeof(red), 100); + ws_dbg_set_usart2_tty_color(1); HAL_UART_Transmit(&huart2, data, size, 100); #endif @@ -128,7 +128,6 @@ void ws_server_req_incoming(uint8_t* data, size_t size) { case WS_SERVER_LM_CIPSEND_LISTENING: { if (next_few_bytes_are("SEND OK") || next_few_bytes_are("ERROR")) { ws_server_req_respond_end(0); - // g_ws_server_parser.mode = WS_SERVER_LM_IDLE; } break; } @@ -153,8 +152,7 @@ void ws_server_buffer_send_append(uint8_t* data, size_t size) { // TODO: refactor this void ws_server_buffer_send_finish() { #ifdef WS_DBG_PRINT_ESP_OVER_USART2 - uint8_t green[] = { 0x1b, 0x5b, 0x33, 0x32, 0x6d }; - HAL_UART_Transmit(&huart2, green, sizeof(green), 100); + ws_dbg_set_usart2_tty_color(2); HAL_UART_Transmit(&huart2, g_ws_esp8266_dma_tx_buffer, g_ws_esp8266_dma_tx_buffer_size, 100); #endif diff --git a/stm32f091/setup.c b/stm32f091/setup.c index 3bf331f..1591649 100644 --- a/stm32f091/setup.c +++ b/stm32f091/setup.c @@ -9,6 +9,7 @@ #include "setup.h" #include "backlog.h" #include "server.h" +#include "util.h" I2C_HandleTypeDef hi2c1 = { .Instance = I2C1, @@ -95,6 +96,12 @@ void ws_io_setup() { ws_backlog_alloc(24 * 60); // ws_backlog_alloc(10); +#ifdef WS_DBG_PRINT_ESP_OVER_USART2 + ws_dbg_set_usart2_tty_color(7); + const char restart_str[] = "\r\n--- stm restart ---\r\n"; + HAL_UART_Transmit(&huart2, restart_str, strlen(restart_str), 100); +#endif + #ifdef WS_ESP8266_WLAN_MAC ws_esp8266_set_mac(); #endif diff --git a/stm32f091/util.h b/stm32f091/util.h index 92f093f..9f5c1ec 100644 --- a/stm32f091/util.h +++ b/stm32f091/util.h @@ -14,3 +14,7 @@ HAL_UART_Transmit(&huart2, (uint8_t*) temp, sizeof(char) * strlen(temp), HAL_MAX_DELAY); \ } +#define ws_dbg_set_usart2_tty_color(color) { \ + uint8_t sgr[] = { 0x1b, 0x5b, 0x33, 0x30 + color, 0x6d }; \ + HAL_UART_Transmit(&huart2, sgr, sizeof(sgr), 100); \ +} -- cgit v1.2.3