From 0b4ae04d37c40c04c2e074baa50c4db8e2bc2385 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Thu, 3 Dec 2015 14:27:10 +0100 Subject: [PATCH] working blob reading system --- main.c | 18 +++++++++++++---- scpi_parser.c | 55 ++++++++++++++++++++++++++++++++++++++++----------- scpi_parser.h | 23 +++++++++++++++------ 3 files changed, 75 insertions(+), 21 deletions(-) diff --git a/main.c b/main.c index d1a585e..fd48186 100644 --- a/main.c +++ b/main.c @@ -9,6 +9,7 @@ void cmd_APPL_TRI_cb(const SCPI_argval_t *args); void cmd_FREQ_cb(const SCPI_argval_t *args); void cmd_DISP_TEXT_cb(const SCPI_argval_t *args); void cmd_DATA_BLOB_cb(const SCPI_argval_t *args); +void cmd_DATA_BLOB_data(const uint8_t *bytes); const SCPI_command_t scpi_cmd_lang[] = { { @@ -38,8 +39,10 @@ const SCPI_command_t scpi_cmd_lang[] = { }, { .levels = {"DATA", "BLOB"}, - .params = {SCPI_DT_BLOB}, - .callback = cmd_DATA_BLOB_cb + .params = {SCPI_DT_FLOAT, SCPI_DT_BLOB}, + .callback = cmd_DATA_BLOB_cb, + .blob_chunk = 4, + .blob_callback = cmd_DATA_BLOB_data }, {0} // end marker }; @@ -73,9 +76,16 @@ void cmd_DISP_TEXT_cb(const SCPI_argval_t *args) printf("cb DISPlay:TEXT %s, %d\n", args[0].STRING, args[1].BOOL); } + void cmd_DATA_BLOB_cb(const SCPI_argval_t *args) { - // noop + printf("cb DATA:BLOB %f, <%d>\n", args[0].FLOAT, args[1].BLOB_LEN); +} + + +void cmd_DATA_BLOB_data(const uint8_t *bytes) +{ + printf("blob item: %s\n", bytes); } @@ -85,7 +95,7 @@ int main() // const char *inp = "FREQ 50\n"; //const char *inp = "DISPlay:TEXT 'banana', OFF\nDISP:TEXT \"dblquot!\", 1\r\nFREQ 50\r\n"; - const char *inp = "DATA:BLOB #49080\n"; + const char *inp = "DATA:BLOB 13.456, #216AbcdEfghIjklMnop\nFREQ 50\r\n"; for (int i = 0; i < strlen(inp); i++) { scpi_handle_byte(inp[i]); diff --git a/scpi_parser.c b/scpi_parser.c index 48763f4..0523aa8 100644 --- a/scpi_parser.c +++ b/scpi_parser.c @@ -13,9 +13,11 @@ typedef enum { PARS_ARG_STR_APOS, // collect arg - string with single quotes PARS_ARG_STR_QUOT, // collect arg - string with double quotes PARS_ARG_BLOB_PREAMBLE, + PARS_ARG_BLOB_BODY, // blob body, callback for each group // command with no args terminated by whitespace, discard whitespace until newline and then run callback. // error on non-whitespace PARS_TRAILING_WHITE, + PARS_TRAILING_WHITE_NOCB, // no callback. PARS_DISCARD_LINE, // used after detecting error } parser_state_t; @@ -32,7 +34,8 @@ static struct { char charbuf[MAX_CHARBUF_LEN]; uint16_t charbuf_i; - int8_t blob_preamble_cnt; // preamble counter, if 0, was just #, must read count + int32_t blob_cnt; // preamble counter, if 0, was just #, must read count. Used also for blob body. + int32_t blob_len; // total blob length to read // recognized complete command level strings (FUNCtion) - exact copy from command struct char cur_levels[MAX_LEVEL_COUNT][MAX_CMD_LEN]; @@ -52,6 +55,8 @@ static struct { .cur_level_i = 0, .cmdbuf_kept = false, .matched_cmd = NULL, + .blob_cnt = 0, + .blob_len = 0, .arg_i = 0 }; @@ -102,6 +107,8 @@ static void pars_reset_cmd(void) pst.cmdbuf_kept = false; pst.matched_cmd = NULL; pst.arg_i = 0; + pst.blob_cnt = 0; + pst.blob_len = 0; } @@ -120,6 +127,8 @@ static void pars_reset_cmd_keeplevel(void) pst.matched_cmd = NULL; pst.arg_i = 0; + pst.blob_cnt = 0; + pst.blob_len = 0; } @@ -231,10 +240,14 @@ void scpi_handle_byte(const uint8_t b) break; case PARS_TRAILING_WHITE: + case PARS_TRAILING_WHITE_NOCB: if (IS_WHITESPACE(c)) break; if (c == '\n') { - pars_run_callback(); + if(pst.state != PARS_TRAILING_WHITE_NOCB) { + pars_run_callback(); + } + pars_reset_cmd(); } else { printf("ERROR unexpected char '%c' in trailing whitespace.\n", c);//TODO error @@ -264,7 +277,7 @@ void scpi_handle_byte(const uint8_t b) } break; - // TODO escape sequence in string + // TODO escape sequence in string case PARS_ARG_STR_APOS: if (c == '\'') { @@ -293,6 +306,25 @@ void scpi_handle_byte(const uint8_t b) case PARS_ARG_BLOB_PREAMBLE: // # pars_blob_preamble_char(c); + break; + + case PARS_ARG_BLOB_BODY: + charbuf_append(c); + pst.blob_cnt++; + + if (pst.charbuf_i >= pst.matched_cmd->blob_chunk) { + charbuf_terminate(); + + if (pst.matched_cmd->blob_callback != NULL) { + pst.matched_cmd->blob_callback((uint8_t *)pst.charbuf); + } + } + + if (pst.blob_cnt == pst.blob_len) { + pst.state = PARS_TRAILING_WHITE_NOCB; // discard trailing whitespace until newline + } + + break; } } @@ -539,7 +571,7 @@ static void pars_arg_char(char c) case SCPI_DT_BLOB: if (c == '#') { pst.state = PARS_ARG_BLOB_PREAMBLE; - pst.blob_preamble_cnt = 0; + pst.blob_cnt = 0; } else { printf("ERROR unexpected char '%c', binary block should start with #\n", c);//TODO error pst.state = PARS_DISCARD_LINE; @@ -689,14 +721,14 @@ static void arg_convert_value(void) static void pars_blob_preamble_char(uint8_t c) { - if (pst.blob_preamble_cnt == 0) { + if (pst.blob_cnt == 0) { if (!INRANGE(c, '1', '9')) { printf("ERROR expected ASCII 1-9 after #\n");//TODO error pst.state = PARS_DISCARD_LINE; return; } - pst.blob_preamble_cnt = c - '0'; // 1-9 + pst.blob_cnt = c - '0'; // 1-9 } else { if (c == '\n') { printf("ERROR unexpected newline in blob preamble\n");//TODO error @@ -711,17 +743,18 @@ static void pars_blob_preamble_char(uint8_t c) } charbuf_append(c); - if (--pst.blob_preamble_cnt == 0) { + if (--pst.blob_cnt == 0) { // end of preamble sequence charbuf_terminate(); - int bytecnt; - sscanf(pst.charbuf, "%d", &bytecnt); + sscanf(pst.charbuf, "%d", &pst.blob_len); - printf("BLOB byte count = %d\n", bytecnt); // TODO + pst.args[pst.arg_i].BLOB_LEN = pst.blob_len; + pars_run_callback(); // Call handler, enter special blob mode - pst.state = PARS_DISCARD_LINE;//FIXME + pst.state = PARS_ARG_BLOB_BODY; + pst.blob_cnt = 0; } } } diff --git a/scpi_parser.h b/scpi_parser.h index 8209a19..feac81a 100644 --- a/scpi_parser.h +++ b/scpi_parser.h @@ -27,20 +27,31 @@ typedef union { int32_t INT; bool BOOL; char STRING[MAX_STRING_LEN+1]; // terminator - uint32_t BLOB; + uint32_t BLOB_LEN; } SCPI_argval_t; -/** SCPI command preset */ +/** + * SCPI command preset + * NOTE: command array is terminated by {0} - zero in levels[0][0] + */ typedef struct { - // NOTE: command array is terminated by {0} - zero in levels[0][0] - + // levels MUST BE FIRST! const char levels[MAX_LEVEL_COUNT][MAX_CMD_LEN]; // up to 4 parts - const SCPI_datatype_t params[MAX_PARAM_COUNT]; // parameter types (0 for unused) // called when the command is completed. BLOB arg must be last in the argument list, // and only the first part is collected. - void (*callback)(const SCPI_argval_t * args); + void (*callback)(const SCPI_argval_t *args); + + // Param types - optional (defaults to zeros) + const SCPI_datatype_t params[MAX_PARAM_COUNT]; // parameter types (0 for unused) + + // --- OPTIONAL (only for blob) --- + + // Number of bytes in a blob callback + const uint8_t blob_chunk; + // Blob chunk callback (every blob_chunk bytes) + void (*blob_callback)(const uint8_t *bytes); } SCPI_command_t; // Zero terminated command struct array