diff --git a/examples/test-arduino/build-arduino-library.py b/examples/test-arduino/build-arduino-library.py index f98b5d0f..53089151 100644 --- a/examples/test-arduino/build-arduino-library.py +++ b/examples/test-arduino/build-arduino-library.py @@ -11,64 +11,72 @@ import sys import shutil -# -# make scpi-parser as arduino compatible library -# -scpi_parser_dir = os.path.join(os.path.dirname(__file__), 'scpi-parser') -libscpi_dir = os.path.join(os.path.dirname(__file__), '../../libscpi') - def rm_then_cp(src, dest): if os.path.exists(dest): shutil.rmtree(dest) shutil.copytree(src, dest) -# copy *.h files -rm_then_cp(os.path.join(libscpi_dir, 'inc/scpi'), os.path.join(scpi_parser_dir, 'src/scpi')) +def build_scpi_parser_lib(libscpi_dir, scpi_parser_dir): + ''' + Build scpi-parser as arduino compatible library + ''' + + # copy *.h files + rm_then_cp(os.path.join(libscpi_dir, 'inc/scpi'), os.path.join(scpi_parser_dir, 'src/scpi')) + + # modify config.h + config_h_file_path = os.path.join(scpi_parser_dir, 'src/scpi/config.h') + config_h_file = open(config_h_file_path) + tmp_file_path = config_h_file_path + ".tmp" + tmp_file = open(tmp_file_path, "w") + for line in config_h_file: + if line == '#ifdef SCPI_USER_CONFIG\n': + tmp_file.write('// This is automatically added by the build-arduino-library.py\n') + tmp_file.write('#define SCPI_USER_CONFIG 1\n') + tmp_file.write('\n') + tmp_file.write(line) + config_h_file.close() + tmp_file.close() + os.unlink(config_h_file_path) + os.rename(tmp_file_path, config_h_file_path) -# modify config.h -config_h_file_path = os.path.join(scpi_parser_dir, 'src/scpi/config.h') -config_h_file = open(config_h_file_path) -tmp_file_path = config_h_file_path + ".tmp" -tmp_file = open(tmp_file_path, "w") -for line in config_h_file: - if line == '#ifdef SCPI_USER_CONFIG\n': - tmp_file.write('// This is automatically added by the build-arduino-library.py\n') - tmp_file.write('#define SCPI_USER_CONFIG 1\n') - tmp_file.write('\n') - tmp_file.write(line) -config_h_file.close() -tmp_file.close() -os.unlink(config_h_file_path) -os.rename(tmp_file_path, config_h_file_path) + # copy scpi_user_config.h + shutil.copyfile(os.path.join(os.path.dirname(__file__), 'scpi_user_config.h'), os.path.join(scpi_parser_dir, 'src/scpi/scpi_user_config.h')) -# copy scpi_user_config.h -shutil.copyfile(os.path.join(os.path.dirname(__file__), 'scpi_user_config.h'), os.path.join(scpi_parser_dir, 'src/scpi/scpi_user_config.h')) + # copy *.c files + rm_then_cp(os.path.join(libscpi_dir, 'src'), os.path.join(scpi_parser_dir, 'src/impl')) -# copy *.c files -rm_then_cp(os.path.join(libscpi_dir, 'src'), os.path.join(scpi_parser_dir, 'src/impl')) +def copy_lib(src_lib_dir, dst_name): + # + # find arduino libraries directory + # + ARDUINO_LIB_DIR_CANDIDATES = { + 'Linux': ['Arduino/libraries/', 'Documents/Arduino/libraries/'], + 'Darwin': ['Documents/Arduino/libraries/'], + 'Windows': ['Documents\\Arduino\\libraries\\', 'My Documents\\Arduino\\libraries\\'] + } -# -# find arduino libraries directory -# -ARDUINO_LIB_DIR_CANDIDATES = { - 'Linux': ['Arduino/libraries/', 'Documents/Arduino/libraries/'], - 'Darwin': ['Documents/Arduino/libraries/'], - 'Windows': ['Documents\\Arduino\\libraries\\', 'My Documents\\Arduino\\libraries\\'] -} + home_dir = os.path.expanduser('~') -home_dir = os.path.expanduser('~') + arduino_libs_dir = None -arduino_libs_dir = None + candidates = ARDUINO_LIB_DIR_CANDIDATES.get(platform.system()) + if candidates: + for candidate_dir in ARDUINO_LIB_DIR_CANDIDATES.get(platform.system()): + arduino_libs_dir = os.path.join(home_dir, candidate_dir) + if os.path.exists(arduino_libs_dir): + break -candidates = ARDUINO_LIB_DIR_CANDIDATES.get(platform.system()) -if candidates: - for candidate_dir in ARDUINO_LIB_DIR_CANDIDATES.get(platform.system()): - arduino_libs_dir = os.path.join(home_dir, candidate_dir) - if os.path.exists(arduino_libs_dir): - break + if arduino_libs_dir: + # copy arduino scpi-parser library to the arduino libraries folder + rm_then_cp(src_lib_dir, os.path.join(arduino_libs_dir, dst_name)) + return True + else: + print("Arduino libraries directory not found!") + return False -if arduino_libs_dir: - # copy arduino scpi-parser library to the arduino libraries folder - rm_then_cp(scpi_parser_dir, os.path.join(arduino_libs_dir, 'scpi-parser')) -else: - print("Arduino libraries directory not found!") +if __name__ == "__main__": + libscpi_dir = os.path.join(os.path.dirname(__file__), '../../libscpi') + scpi_parser_dir = os.path.join(os.path.dirname(__file__), 'scpi-parser') + build_scpi_parser_lib(libscpi_dir, scpi_parser_dir) + copy_lib(scpi_parser_dir, 'scpi-parser') \ No newline at end of file diff --git a/examples/test-arduino/scpi-def.cpp b/examples/test-arduino/scpi-def.cpp index 35568983..e056ea8e 100644 --- a/examples/test-arduino/scpi-def.cpp +++ b/examples/test-arduino/scpi-def.cpp @@ -37,7 +37,6 @@ #include #include #include -#include "scpi/scpi.h" #include "scpi-def.h" #if USE_64K_PROGMEM_FOR_CMD_LIST @@ -47,7 +46,7 @@ scpi_result_t DMM_MeasureVoltageDcQ(scpi_t * context) { scpi_number_t param1, param2; char bf[15]; - fprintf(stderr, "meas:volt:dc\r\n"); // debug command name + SerialPrintf("meas:volt:dc"); // debug command name // read first parameter if present if (!SCPI_ParamNumber(context, scpi_special_numbers_def, ¶m1, false)) { @@ -61,11 +60,11 @@ scpi_result_t DMM_MeasureVoltageDcQ(scpi_t * context) { SCPI_NumberToStr(context, scpi_special_numbers_def, ¶m1, bf, 15); - fprintf(stderr, "\tP1=%s\r\n", bf); + SerialPrintf("\tP1=%s", bf); SCPI_NumberToStr(context, scpi_special_numbers_def, ¶m2, bf, 15); - fprintf(stderr, "\tP2=%s\r\n", bf); + SerialPrintf("\tP2=%s", bf); SCPI_ResultDouble(context, 0); @@ -75,7 +74,7 @@ scpi_result_t DMM_MeasureVoltageDcQ(scpi_t * context) { scpi_result_t DMM_MeasureVoltageAcQ(scpi_t * context) { scpi_number_t param1, param2; char bf[15]; - fprintf(stderr, "meas:volt:ac\r\n"); // debug command name + SerialPrintf("meas:volt:ac"); // debug command name // read first parameter if present if (!SCPI_ParamNumber(context, scpi_special_numbers_def, ¶m1, false)) { @@ -89,11 +88,11 @@ scpi_result_t DMM_MeasureVoltageAcQ(scpi_t * context) { SCPI_NumberToStr(context, scpi_special_numbers_def, ¶m1, bf, 15); - fprintf(stderr, "\tP1=%s\r\n", bf); + SerialPrintf("\tP1=%s", bf); SCPI_NumberToStr(context, scpi_special_numbers_def, ¶m2, bf, 15); - fprintf(stderr, "\tP2=%s\r\n", bf); + SerialPrintf("\tP2=%s", bf); SCPI_ResultDouble(context, 0); @@ -102,7 +101,7 @@ scpi_result_t DMM_MeasureVoltageAcQ(scpi_t * context) { scpi_result_t DMM_ConfigureVoltageDc(scpi_t * context) { double param1, param2; - fprintf(stderr, "conf:volt:dc\r\n"); // debug command name + SerialPrintf("conf:volt:dc"); // debug command name // read first parameter if present if (!SCPI_ParamDouble(context, ¶m1, true)) { @@ -114,22 +113,22 @@ scpi_result_t DMM_ConfigureVoltageDc(scpi_t * context) { // do something, if parameter not present } - fprintf(stderr, "\tP1=%lf\r\n", param1); - fprintf(stderr, "\tP2=%lf\r\n", param2); + SerialPrintf("\tP1=%lf", param1); + SerialPrintf("\tP2=%lf", param2); return SCPI_RES_OK; } scpi_result_t TEST_Bool(scpi_t * context) { scpi_bool_t param1; - fprintf(stderr, "TEST:BOOL\r\n"); // debug command name + SerialPrintf("TEST:BOOL"); // debug command name // read first parameter if present if (!SCPI_ParamBool(context, ¶m1, true)) { return SCPI_RES_ERR; } - fprintf(stderr, "\tP1=%d\r\n", param1); + SerialPrintf("\tP1=%d", param1); return SCPI_RES_OK; } @@ -151,7 +150,7 @@ scpi_result_t TEST_ChoiceQ(scpi_t * context) { } SCPI_ChoiceToName(trigger_source, param, &name); - fprintf(stderr, "\tP1=%s (%ld)\r\n", name, (long int) param); + SerialPrintf("\tP1=%s (%ld)", name, (long int) param); SCPI_ResultInt32(context, param); @@ -160,7 +159,7 @@ scpi_result_t TEST_ChoiceQ(scpi_t * context) { scpi_result_t TEST_Numbers(scpi_t * context) { - fprintf(stderr, "RAW CMD %.*s\r\n", (int) context->param_list.cmd_raw.length, context->param_list.cmd_raw.data); + SerialPrintf("RAW CMD %.*s", (int) context->param_list.cmd_raw.length, context->param_list.cmd_raw.data); return SCPI_RES_OK; } @@ -173,7 +172,7 @@ scpi_result_t TEST_Text(scpi_t * context) { buffer[0] = '\0'; } - fprintf(stderr, "TEXT: ***%s***\r\n", buffer); + SerialPrintf("TEXT: ***%s***", buffer); return SCPI_RES_OK; } @@ -287,6 +286,16 @@ static const scpi_command_t scpi_commands[] PROGMEM = { SCPI_CMD_LIST_END }; +#elif USE_FULL_PROGMEM_FOR_CMD_LIST + +#define SCPI_COMMAND(P, C) P +static const char scpi_command_patterns[] PROGMEM = SCPI_COMMANDS; +#define SCPI_COMMAND(P, C) {(const char *)(sizeof(P) - 1), C}, +static const scpi_command_t scpi_commands[] PROGMEM = { + SCPI_COMMANDS + SCPI_CMD_LIST_END +}; + #else #define SCPI_COMMAND(P, C) {P, C}, @@ -297,7 +306,6 @@ static const scpi_command_t scpi_commands[] = { #endif - static scpi_interface_t scpi_interface = { /* error */ SCPI_Error, /* write */ SCPI_Write, @@ -312,8 +320,13 @@ static char scpi_input_buffer[SCPI_INPUT_BUFFER_LENGTH]; static scpi_reg_val_t scpi_regs[SCPI_REG_COUNT]; -scpi_t scpi_context = { +static scpi_t scpi_context = { +#if USE_FULL_PROGMEM_FOR_CMD_LIST + /* cmdlist */ 0, + /* cmdpatterns */ 0, +#else /* cmdlist */ scpi_commands, +#endif /* buffer */ { /* length */ SCPI_INPUT_BUFFER_LENGTH, /* position */ 0, /* data */ scpi_input_buffer}, /* param_list */ @@ -337,3 +350,10 @@ scpi_t scpi_context = { {"MANUFACTURE", "INSTR2013", NULL, "01-02"}, }; +scpi_t *SCPI_GetContext() { +#if USE_FULL_PROGMEM_FOR_CMD_LIST + scpi_context.cmdlist = pgm_get_far_address(scpi_commands); + scpi_context.cmdpatterns = pgm_get_far_address(scpi_command_patterns); +#endif + return &scpi_context; +} \ No newline at end of file diff --git a/examples/test-arduino/scpi-def.h b/examples/test-arduino/scpi-def.h index 4bfc06c7..417c7dce 100644 --- a/examples/test-arduino/scpi-def.h +++ b/examples/test-arduino/scpi-def.h @@ -3,7 +3,9 @@ #include "scpi/scpi.h" -extern scpi_t scpi_context; +void SerialPrintf(const char *format, ...); + +scpi_t *SCPI_GetContext(); size_t SCPI_Write(scpi_t * context, const char * data, size_t len); int SCPI_Error(scpi_t * context, int_fast16_t err); diff --git a/examples/test-arduino/scpi_user_config.h b/examples/test-arduino/scpi_user_config.h index 7b72f27b..22f07aae 100644 --- a/examples/test-arduino/scpi_user_config.h +++ b/examples/test-arduino/scpi_user_config.h @@ -7,6 +7,7 @@ extern "C" { #define USE_COMMAND_TAGS 0 #define USE_64K_PROGMEM_FOR_CMD_LIST 0 +#define USE_FULL_PROGMEM_FOR_CMD_LIST 1 #define SCPI_MAX_CMD_PATTERN_SIZE 128 // strtoull is not defined on some arduino boards diff --git a/examples/test-arduino/test-arduino.ino b/examples/test-arduino/test-arduino.ino index 666ea52a..cfcdd327 100644 --- a/examples/test-arduino/test-arduino.ino +++ b/examples/test-arduino/test-arduino.ino @@ -65,9 +65,11 @@ void setup() { while (!Serial); Serial.println("serial com ready"); - SCPI_Init(&scpi_context); + scpi_t *context = SCPI_GetContext(); + + SCPI_Init(context); -#define TEST_SCPI_INPUT(cmd) result = SCPI_Input(&scpi_context, cmd, strlen(cmd)) +#define TEST_SCPI_INPUT(cmd) result = SCPI_Input(context, cmd, strlen(cmd)) TEST_SCPI_INPUT("*CLS\r\n"); TEST_SCPI_INPUT("*RST\r\n"); diff --git a/libscpi/inc/scpi/config.h b/libscpi/inc/scpi/config.h index 8b97aecf..3d8c5fb3 100644 --- a/libscpi/inc/scpi/config.h +++ b/libscpi/inc/scpi/config.h @@ -97,6 +97,10 @@ extern "C" { #define USE_64K_PROGMEM_FOR_CMD_LIST 0 #endif +#ifndef USE_FULL_PROGMEM_FOR_CMD_LIST +#define USE_FULL_PROGMEM_FOR_CMD_LIST 0 +#endif + #ifndef USE_DEPRECATED_FUNCTIONS #define USE_DEPRECATED_FUNCTIONS 1 #endif diff --git a/libscpi/inc/scpi/types.h b/libscpi/inc/scpi/types.h index ebeb4799..bdf8e749 100644 --- a/libscpi/inc/scpi/types.h +++ b/libscpi/inc/scpi/types.h @@ -43,6 +43,10 @@ #include #include "scpi/config.h" +#if USE_FULL_PROGMEM_FOR_CMD_LIST +#include +#endif + #if HAVE_STDBOOL #include #endif @@ -113,11 +117,7 @@ extern "C" { typedef struct _scpi_command_t scpi_command_t; -#if USE_COMMAND_TAGS -#define SCPI_CMD_LIST_END {NULL, NULL, 0} -#else -#define SCPI_CMD_LIST_END {NULL, NULL} -#endif +#define SCPI_CMD_LIST_END {} /* scpi interface */ typedef struct _scpi_t scpi_t; @@ -262,7 +262,7 @@ extern "C" { const scpi_command_t * cmd; lex_state_t lex_state; scpi_const_buffer_t cmd_raw; -#if USE_64K_PROGMEM_FOR_CMD_LIST +#if USE_64K_PROGMEM_FOR_CMD_LIST || USE_FULL_PROGMEM_FOR_CMD_LIST scpi_command_t cmd_s; char cmd_pattern_s[SCPI_MAX_CMD_PATTERN_SIZE + 1]; #endif @@ -297,9 +297,13 @@ extern "C" { scpi_command_callback_t reset; }; - struct _scpi_t { +#if USE_FULL_PROGMEM_FOR_CMD_LIST + uint_farptr_t cmdlist; + uint_farptr_t cmdpatterns; +#else const scpi_command_t * cmdlist; +#endif scpi_buffer_t buffer; scpi_param_list_t param_list; scpi_interface_t * interface; diff --git a/libscpi/src/parser.c b/libscpi/src/parser.c index 568ae47d..dbbb0426 100644 --- a/libscpi/src/parser.c +++ b/libscpi/src/parser.c @@ -164,6 +164,7 @@ static scpi_bool_t processCommand(scpi_t * context) { */ static scpi_bool_t findCommandHeader(scpi_t * context, const char * header, int len) { int32_t i; + #if USE_64K_PROGMEM_FOR_CMD_LIST PGM_P pattern; @@ -174,8 +175,34 @@ static scpi_bool_t findCommandHeader(scpi_t * context, const char * header, int if (matchCommand(context->param_list.cmd_pattern_s, header, len, NULL, 0, 0)) { context->param_list.cmd_s.callback = (scpi_command_callback_t)pgm_read_word(&context->cmdlist[i].callback); #if USE_COMMAND_TAGS - context->param_list.cmd_s..tag = (int32_t)pgm_read_dword(&context->cmdlist[i].tag); + context->param_list.cmd_s.tag = (int32_t)pgm_read_dword(&context->cmdlist[i].tag); #endif + return TRUE; + } + } + + +#elif USE_FULL_PROGMEM_FOR_CMD_LIST + uint_farptr_t p_cmd = context->cmdlist; + uint_farptr_t p_pattern = context->cmdpatterns; + uint16_t pattern_length; + + for (i = 0; + (pattern_length = pgm_read_word_far(p_cmd + offsetof(scpi_command_t, pattern))) != 0; + ++i, p_cmd += sizeof(scpi_command_t), p_pattern += pattern_length) + { + strncpy_PF(context->param_list.cmd_pattern_s, p_pattern, pattern_length); + context->param_list.cmd_pattern_s[pattern_length] = '\0'; + + if (matchCommand(context->param_list.cmd_pattern_s, header, len, NULL, 0, 0)) { + context->param_list.cmd_s.callback = (scpi_command_callback_t)pgm_read_word_far(p_cmd + offsetof(scpi_command_t, callback)); +#if USE_COMMAND_TAGS + context->param_list.cmd_s.tag = (int32_t)pgm_read_dword_far(p_cmd + offsetof(scpi_command_t, tag)); +#endif + return TRUE; + } + } + #else const scpi_command_t * cmd; @@ -183,10 +210,11 @@ static scpi_bool_t findCommandHeader(scpi_t * context, const char * header, int cmd = &context->cmdlist[i]; if (matchCommand(cmd->pattern, header, len, NULL, 0, 0)) { context->param_list.cmd = cmd; -#endif return TRUE; } } +#endif + return FALSE; } @@ -273,7 +301,7 @@ void SCPI_Init(scpi_t * context) { context->idn[3] = SCPI_DEFAULT_4_REVISION; } -#if USE_64K_PROGMEM_FOR_CMD_LIST +#if USE_64K_PROGMEM_FOR_CMD_LIST || USE_FULL_PROGMEM_FOR_CMD_LIST context->param_list.cmd_s.pattern = context->param_list.cmd_pattern_s; context->param_list.cmd = &context->param_list.cmd_s; #endif