diff --git a/main.c b/main.c index 6fde8ce..6a6818d 100644 --- a/main.c +++ b/main.c @@ -9,33 +9,33 @@ 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); -const uint16_t scpi_cmd_lang_len = 5; -const SCPI_command_t scpi_cmd_lang[5] = { +const SCPI_command_t scpi_cmd_lang[] = { { - .level_cnt = 1, .levels = {"*IDN?"}, - .param_cnt = 0, .params = {}, + .levels = {"*IDN?"}, + .params = {}, .callback = cmd_aIDNq_cb }, { - .level_cnt = 3, .levels = {"APPLy", "SINe"}, - .param_cnt = 3, .params = {SCPI_DT_INT, SCPI_DT_FLOAT, SCPI_DT_FLOAT}, + .levels = {"APPLy", "SINe"}, + .params = {SCPI_DT_INT, SCPI_DT_FLOAT, SCPI_DT_FLOAT}, .callback = cmd_APPL_SIN_cb }, { - .level_cnt = 2, .levels = {"APPLy", "TRIangle"}, - .param_cnt = 3, .params = {SCPI_DT_INT, SCPI_DT_FLOAT, SCPI_DT_FLOAT}, + .levels = {"APPLy", "TRIangle"}, + .params = {SCPI_DT_INT, SCPI_DT_FLOAT, SCPI_DT_FLOAT}, .callback = cmd_APPL_TRI_cb }, { - .level_cnt = 1, .levels = {"FREQuency"}, - .param_cnt = 1, .params = {SCPI_DT_INT}, + .levels = {"FREQuency"}, + .params = {SCPI_DT_INT}, .callback = cmd_FREQ_cb }, { - .level_cnt = 2, .levels = {"DISPlay", "TEXT"}, - .param_cnt = 2, .params = {SCPI_DT_STRING, SCPI_DT_BOOL}, + .levels = {"DISPlay", "TEXT"}, + .params = {SCPI_DT_STRING, SCPI_DT_BOOL}, .callback = cmd_DISP_TEXT_cb }, + {0} // mark end }; @@ -74,7 +74,7 @@ int main() // const char *inp = "FREQ 50\n"; const char *inp = "DISPlay:TEXT 'banana', OFF\nFUBAR moo fuck\r\nFREQ 50\r\n"; - for(int i=0;i + + + + + EnvironmentId + {dfe3cb4a-0f3e-4da9-9c52-5d2c464adafb} + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + true + false + true + + Cpp + + CppGlobal + + + + QmlJS + + QmlJSGlobal + + + 2 + UTF-8 + false + 4 + true + 80 + true + true + 1 + true + false + 0 + true + 0 + 8 + true + 1 + true + true + true + true + + + + ProjectExplorer.Project.PluginSettings + + + + 1 + + + + + ProjectExplorer.Project.Target.0 + + Desktop + Desktop + {ee748544-c6c0-4f44-9cef-fbb65dc2525a} + 0 + 0 + 0 + + /home/ondra/stm32/build-scpi-Desktop-Debug + + + true + qmake + + QtProjectManager.QMakeBuildStep + false + true + + false + false + false + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + false + + + + 2 + Build + + ProjectExplorer.BuildSteps.Build + + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + true + clean + + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Debug + + Qt4ProjectManager.Qt4BuildConfiguration + 2 + true + + + /home/ondra/stm32/build-scpi-Desktop-Release + + + true + qmake + + QtProjectManager.QMakeBuildStep + false + true + + false + false + false + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + false + + + + 2 + Build + + ProjectExplorer.BuildSteps.Build + + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + true + clean + + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Release + + Qt4ProjectManager.Qt4BuildConfiguration + 0 + true + + 2 + + + 0 + Deploy + + ProjectExplorer.BuildSteps.Deploy + + 1 + Deploy locally + + ProjectExplorer.DefaultDeployConfiguration + + 1 + + + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + scpi + + Qt4ProjectManager.Qt4RunConfiguration:/home/ondra/stm32/scpi_/scpi.pro + + scpi.pro + false + true + + 3768 + false + true + false + false + true + + 1 + + + + ProjectExplorer.Project.TargetCount + 1 + + + ProjectExplorer.Project.Updater.FileVersion + 18 + + + Version + 18 + + diff --git a/scpi_parser.c b/scpi_parser.c index 1e4c14b..941e0ff 100644 --- a/scpi_parser.c +++ b/scpi_parser.c @@ -65,6 +65,9 @@ static void pars_arg_char(char c); static void pars_arg_comma(void); static void pars_arg_newline(void); +static uint8_t cmd_param_count(const SCPI_command_t *cmd); +static uint8_t cmd_level_count(const SCPI_command_t *cmd); + static bool try_match_cmd(const SCPI_command_t *cmd, bool partial); static void charbuf_terminate(void); static void charbuf_append(char c); @@ -118,6 +121,30 @@ static void pars_reset_cmd_keeplevel(void) } +static uint8_t cmd_param_count(const SCPI_command_t *cmd) +{ + for (uint8_t i = 0; i < MAX_PARAM_COUNT; i++) { + if (cmd->params[i] == SCPI_DT_NONE) { + return i; + } + } + + return MAX_PARAM_COUNT; +} + + +static uint8_t cmd_level_count(const SCPI_command_t *cmd) +{ + for (uint8_t i = 0; i < MAX_LEVEL_COUNT; i++) { + if (cmd->levels[i][0] == 0) { + return i; + } + } + + return MAX_LEVEL_COUNT; +} + + /** Add a byte to charbuf, error on overflow */ static void charbuf_append(char c) { @@ -292,7 +319,7 @@ static void pars_cmd_newline(void) // complete match if (pars_match_cmd(false)) { - if (pst.matched_cmd->param_cnt == 0) { + if (cmd_param_count(pst.matched_cmd) == 0) { // no param command - OK pst.matched_cmd->callback(pst.args); // args are empty } else { @@ -315,7 +342,7 @@ static void pars_cmd_space(void) } if (pars_match_cmd(false)) { - if (pst.matched_cmd->param_cnt == 0) { + if (cmd_param_count(pst.matched_cmd) == 0) { // no commands pst.state = PARS_TRAILING_WHITE; } else { @@ -398,11 +425,12 @@ static bool pars_match_cmd(bool partial) char *dest = pst.cur_levels[pst.cur_level_i++]; strcpy(dest, pst.charbuf); - for (uint16_t i = 0; i < scpi_cmd_lang_len; i++) { + for (uint16_t i = 0; i < 0xFFFF; i++) { const SCPI_command_t *cmd = &scpi_cmd_lang[i]; + if (cmd->levels[0][0] == 0) break; // end marker - if (cmd->level_cnt > MAX_LEVEL_COUNT) { + if (cmd_level_count(cmd) > MAX_LEVEL_COUNT) { // FAIL, too deep. Bad config continue; } @@ -426,15 +454,16 @@ static bool pars_match_cmd(bool partial) /** Try to match current state to a given command */ static bool try_match_cmd(const SCPI_command_t *cmd, bool partial) { - if (pst.cur_level_i > cmd->level_cnt) return false; // command too short + const uint8_t level_cnt = cmd_level_count(cmd); + if (pst.cur_level_i > level_cnt) return false; // command too short if (pst.cur_level_i == 0) return false; // nothing to match if (partial) { - if (pst.cur_level_i == cmd->level_cnt) { + if (pst.cur_level_i == level_cnt) { return false; // would be exact match } } else { - if (pst.cur_level_i != cmd->level_cnt) { + if (pst.cur_level_i != level_cnt) { return false; // can be only partial match } } @@ -503,7 +532,7 @@ static void pars_arg_char(char c) /** Received a comma while collecting an arg */ static void pars_arg_comma(void) { - if (pst.arg_i == pst.matched_cmd->param_cnt - 1) { + if (pst.arg_i == cmd_param_count(pst.matched_cmd) - 1) { // it was the last argument // comma illegal printf("ERROR unexpected comma after the last argument\n");//TODO error @@ -525,7 +554,7 @@ static void pars_arg_comma(void) static void pars_arg_newline(void) { - if (pst.arg_i < pst.matched_cmd->param_cnt - 1) { + if (pst.arg_i < cmd_param_count(pst.matched_cmd) - 1) { // not the last arg yet - fail printf("ERROR not enough arguments!\n");//TODO error pst.state = PARS_DISCARD_LINE; diff --git a/scpi_parser.h b/scpi_parser.h index 2393638..8209a19 100644 --- a/scpi_parser.h +++ b/scpi_parser.h @@ -33,10 +33,9 @@ typedef union { /** SCPI command preset */ typedef struct { - const uint8_t level_cnt; // number of used command levels (colons + 1) - const char levels[MAX_LEVEL_COUNT][MAX_CMD_LEN]; // up to 4 parts + // NOTE: command array is terminated by {0} - zero in levels[0][0] - const uint8_t param_cnt; // parameter count + 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, @@ -44,8 +43,7 @@ typedef struct { void (*callback)(const SCPI_argval_t * args); } SCPI_command_t; - -extern const uint16_t scpi_cmd_lang_len; // number of commands +// Zero terminated command struct array extern const SCPI_command_t scpi_cmd_lang[]; // --------------- functions --------------------