diff --git a/examples/common/scpi-def.c b/examples/common/scpi-def.c index 50216210..050d89a0 100644 --- a/examples/common/scpi-def.c +++ b/examples/common/scpi-def.c @@ -353,70 +353,75 @@ static scpi_result_t My_CoreTstQ(scpi_t * context) { return SCPI_RES_OK; } -const scpi_command_t scpi_commands[] = { - /* IEEE Mandated Commands (SCPI std V1999.0 4.1.1) */ - { .pattern = "*CLS", .callback = SCPI_CoreCls,}, - { .pattern = "*ESE", .callback = SCPI_CoreEse,}, - { .pattern = "*ESE?", .callback = SCPI_CoreEseQ,}, - { .pattern = "*ESR?", .callback = SCPI_CoreEsrQ,}, - { .pattern = "*IDN?", .callback = SCPI_CoreIdnQ,}, - { .pattern = "*OPC", .callback = SCPI_CoreOpc,}, - { .pattern = "*OPC?", .callback = SCPI_CoreOpcQ,}, - { .pattern = "*RST", .callback = SCPI_CoreRst,}, - { .pattern = "*SRE", .callback = SCPI_CoreSre,}, - { .pattern = "*SRE?", .callback = SCPI_CoreSreQ,}, - { .pattern = "*STB?", .callback = SCPI_CoreStbQ,}, - { .pattern = "*TST?", .callback = My_CoreTstQ,}, - { .pattern = "*WAI", .callback = SCPI_CoreWai,}, - - /* Required SCPI commands (SCPI std V1999.0 4.2.1) */ - {.pattern = "SYSTem:ERRor[:NEXT]?", .callback = SCPI_SystemErrorNextQ,}, - {.pattern = "SYSTem:ERRor:COUNt?", .callback = SCPI_SystemErrorCountQ,}, - {.pattern = "SYSTem:VERSion?", .callback = SCPI_SystemVersionQ,}, - - /* {.pattern = "STATus:OPERation?", .callback = scpi_stub_callback,}, */ - /* {.pattern = "STATus:OPERation:EVENt?", .callback = scpi_stub_callback,}, */ - /* {.pattern = "STATus:OPERation:CONDition?", .callback = scpi_stub_callback,}, */ - /* {.pattern = "STATus:OPERation:ENABle", .callback = scpi_stub_callback,}, */ - /* {.pattern = "STATus:OPERation:ENABle?", .callback = scpi_stub_callback,}, */ - - {.pattern = "STATus:QUEStionable[:EVENt]?", .callback = SCPI_StatusQuestionableEventQ,}, - /* {.pattern = "STATus:QUEStionable:CONDition?", .callback = scpi_stub_callback,}, */ - {.pattern = "STATus:QUEStionable:ENABle", .callback = SCPI_StatusQuestionableEnable,}, - {.pattern = "STATus:QUEStionable:ENABle?", .callback = SCPI_StatusQuestionableEnableQ,}, - - {.pattern = "STATus:PRESet", .callback = SCPI_StatusPreset,}, - - /* DMM */ - {.pattern = "MEASure:VOLTage:DC?", .callback = DMM_MeasureVoltageDcQ,}, - {.pattern = "CONFigure:VOLTage:DC", .callback = DMM_ConfigureVoltageDc,}, - {.pattern = "MEASure:VOLTage:DC:RATio?", .callback = SCPI_StubQ,}, - {.pattern = "MEASure:VOLTage:AC?", .callback = DMM_MeasureVoltageAcQ,}, - {.pattern = "MEASure:CURRent:DC?", .callback = SCPI_StubQ,}, - {.pattern = "MEASure:CURRent:AC?", .callback = SCPI_StubQ,}, - {.pattern = "MEASure:RESistance?", .callback = SCPI_StubQ,}, - {.pattern = "MEASure:FRESistance?", .callback = SCPI_StubQ,}, - {.pattern = "MEASure:FREQuency?", .callback = SCPI_StubQ,}, - {.pattern = "MEASure:PERiod?", .callback = SCPI_StubQ,}, - - {.pattern = "SYSTem:COMMunication:TCPIP:CONTROL?", .callback = SCPI_SystemCommTcpipControlQ,}, - - {.pattern = "TEST:BOOL", .callback = TEST_Bool,}, - {.pattern = "TEST:CHOice?", .callback = TEST_ChoiceQ,}, - {.pattern = "TEST#:NUMbers#", .callback = TEST_Numbers,}, - {.pattern = "TEST:TEXT", .callback = TEST_Text,}, - {.pattern = "TEST:ARBitrary?", .callback = TEST_ArbQ,}, - {.pattern = "TEST:CHANnellist", .callback = TEST_Chanlst,}, +const scpi_command_t scpi_commands[] = { + /* Optional help command */ +#if USE_HELP_FILTER + {"HELP?", SCPI_HelpQ, SCPI_CMD_DESC("[] - list supported commands [containing \"\"] (multiple block data)") SCPI_CMD_TAG(0)}, +#else + {"HELP?", SCPI_HelpQ, SCPI_CMD_DESC("\t - list supported commands (multiple block data)") SCPI_CMD_TAG(0)}, +#endif + /* IEEE Mandated Commands (SCPI std V1999.0 4.1.1): *CLS *ESE *ESE? *ESR? *IDN? *OPC *OPC? *RST *SRE *SRE? *STB? *TST? *WAI */ + {"*CLS", SCPI_CoreCls, SCPI_CMD_DESC("\t - clear all Event Status registers, errors, output queue") SCPI_CMD_TAG(0)}, + /* -- Standard Event Status Group [EVENT]-[ENABLE] */ + {"*ESE", SCPI_CoreEse, SCPI_CMD_DESC("<0..255> - set Standard Event Status Enable / event mask") SCPI_CMD_TAG(0)}, + {"*ESE?", SCPI_CoreEseQ, SCPI_CMD_DESC("\t - read ESE (0..255)") SCPI_CMD_TAG(0)}, + {"*ESR?", SCPI_CoreEsrQ, SCPI_CMD_DESC("\t - read+clear Standard Event Status register (0..255)") SCPI_CMD_TAG(0)}, + /* -- IEEE Mandated Commands (continued ...) */ + {"*IDN?", SCPI_CoreIdnQ, SCPI_CMD_DESC("\t - read device identifier (str,str,str,str)") SCPI_CMD_TAG(0)}, + {"*OPC", SCPI_CoreOpc, SCPI_CMD_DESC("\t - complete ops preceding Operation Complete Command, set ESR.OPC 1") SCPI_CMD_TAG(0)}, + {"*OPC?", SCPI_CoreOpcQ, SCPI_CMD_DESC("\t - read ESR.OPC (0:ongoing-ops 1:done)") SCPI_CMD_TAG(0)}, + {"*RST", SCPI_CoreRst, SCPI_CMD_DESC("\t - reset instrument and interface") SCPI_CMD_TAG(0)}, + {"*SRE", SCPI_CoreSre, SCPI_CMD_DESC("<0..255> - set Service Request Enable / event mask over STB") SCPI_CMD_TAG(0)}, + {"*SRE?", SCPI_CoreSreQ, SCPI_CMD_DESC("\t - read SRE (0..255)") SCPI_CMD_TAG(0)}, + {"*STB?", SCPI_CoreStbQ, SCPI_CMD_DESC("\t - read STatus Byte (0..255)") SCPI_CMD_TAG(0)}, + {"*TST?", My_CoreTstQ, SCPI_CMD_DESC("\t - read self-test result (0:no-failures)") SCPI_CMD_TAG(0)}, + {"*WAI", SCPI_CoreWai, SCPI_CMD_DESC("\t - halt cmd execution until pending operations complete") SCPI_CMD_TAG(0)}, + + /* Required SCPI commands (SCPI std V1999.0 4.2.1) : SYSTem:ERRor, STATus:OPERation, STATus:QUEStionable and STATus:PRESet */ + {"SYSTem:ERRor[:NEXT]?", SCPI_SystemErrorNextQ, SCPI_CMD_DESC("\t - get next error in queue (int-errno,str)") SCPI_CMD_TAG(0)}, + {"SYSTem:ERRor:COUNt?", SCPI_SystemErrorCountQ, SCPI_CMD_DESC("\t - queued error count (0.." SCPI_ERROR_QUEUE_SIZE_STR ")") SCPI_CMD_TAG(0)}, + {"SYSTem:VERSion?", SCPI_SystemVersionQ, SCPI_CMD_DESC("\t - query system version (str)") SCPI_CMD_TAG(0)}, + /* -- Operation Status Group [CONDITION]-[EVENT]-[ENABLE] */ + {"STATus:OPERation:CONDition?", SCPI_StubQ, SCPI_CMD_DESC("\t - not implemented (0)") SCPI_CMD_TAG(0)}, + {"STATus:OPERation[:EVENt]?", SCPI_StubQ, SCPI_CMD_DESC("\t - not implemented (0)") SCPI_CMD_TAG(0)}, + {"STATus:OPERation:ENABle", SCPI_Stub, SCPI_CMD_DESC("\t - not implemented") SCPI_CMD_TAG(0)}, + {"STATus:OPERation:ENABle?", SCPI_StubQ, SCPI_CMD_DESC("\t - not implemented (0)") SCPI_CMD_TAG(0)}, + /* -- Questionable Status Group [CONDITION]-[EVENT]-[ENABLE] */ + {"STATus:QUEStionable:CONDition?", SCPI_StubQ, SCPI_CMD_DESC("\t - not implemented (0)") SCPI_CMD_TAG(0)}, /* "\t - read momentary Questionable Condition register (0..65535)" */ + {"STATus:QUEStionable[:EVENt]?", SCPI_StatusQuestionableEventQ, SCPI_CMD_DESC("\t - read Questionable Event register (0..65535)") SCPI_CMD_TAG(0)}, + {"STATus:QUEStionable:ENABle", SCPI_StatusQuestionableEnable, SCPI_CMD_DESC("<0..65535> - set Questionable Enable / event mask") SCPI_CMD_TAG(0)}, + {"STATus:QUEStionable:ENABle?", SCPI_StatusQuestionableEnableQ, SCPI_CMD_DESC("\t - Questionable Status Enable (0..65535)") SCPI_CMD_TAG(0)}, + {"STATus:PRESet", SCPI_StatusPreset, SCPI_CMD_DESC("\t - load Status sub-system register defaults") SCPI_CMD_TAG(0)}, + + /* commands specific to DMM example with TEST sub-system */ + {"SYSTem:COMMunication:TCPIP:CONTROL?", SCPI_SystemCommTcpipControlQ, SCPI_CMD_DESC("\t - read TCPIP control port (int)") SCPI_CMD_TAG(0)}, + {"CONFigure:VOLTage:DC", DMM_ConfigureVoltageDc, SCPI_CMD_DESC("[,] - test command") SCPI_CMD_TAG(0)}, + {"MEASure:VOLTage:DC?", DMM_MeasureVoltageDcQ, SCPI_CMD_DESC("[[,]] - test command (0)") SCPI_CMD_TAG(0)}, + {"MEASure:VOLTage:DC:RATio?", SCPI_StubQ, SCPI_CMD_DESC("\t - not implemented (0)") SCPI_CMD_TAG(0)}, + {"MEASure:VOLTage:AC?", DMM_MeasureVoltageAcQ, SCPI_CMD_DESC("[[,]] - test command (0)") SCPI_CMD_TAG(0)}, + {"MEASure:CURRent:DC?", SCPI_StubQ, SCPI_CMD_DESC("\t - not implemented (0)") SCPI_CMD_TAG(0)}, + {"MEASure:CURRent:AC?", SCPI_StubQ, SCPI_CMD_DESC("\t - not implemented (0)") SCPI_CMD_TAG(0)}, + {"MEASure:RESistance?", SCPI_StubQ, SCPI_CMD_DESC("\t - not implemented (0)") SCPI_CMD_TAG(0)}, + {"MEASure:FRESistance?", SCPI_StubQ, SCPI_CMD_DESC("\t - not implemented (0)") SCPI_CMD_TAG(0)}, + {"MEASure:FREQuency?", SCPI_StubQ, SCPI_CMD_DESC("\t - not implemented (0)") SCPI_CMD_TAG(0)}, + {"MEASure:PERiod?", SCPI_StubQ, SCPI_CMD_DESC("\t - not implemented (0)") SCPI_CMD_TAG(0)}, + {"TEST:BOOL", TEST_Bool, SCPI_CMD_DESC(" - test command") SCPI_CMD_TAG(0)}, + {"TEST:CHOice?", TEST_ChoiceQ, SCPI_CMD_DESC(" - test command (\"BUS\":5 \"IMMediate\":6 \"EXTernal\":7)") SCPI_CMD_TAG(0)}, + {"TEST#:NUMbers#", TEST_Numbers, SCPI_CMD_DESC("\t - test command with optional numbers - default 1") SCPI_CMD_TAG(0)}, + {"TEST:TEXT", TEST_Text, SCPI_CMD_DESC("[, ...] - debug print param as received") SCPI_CMD_TAG(0)}, + {"TEST:ARBitrary?", TEST_ArbQ, SCPI_CMD_DESC(" - receive and return block data (block data)") SCPI_CMD_TAG(0)}, + {"TEST:CHANnellist", TEST_Chanlst, SCPI_CMD_DESC(" - test channel list parsing") SCPI_CMD_TAG(0)}, + SCPI_CMD_LIST_END }; scpi_interface_t scpi_interface = { - .error = SCPI_Error, - .write = SCPI_Write, + .error = SCPI_Error, + .write = SCPI_Write, .control = SCPI_Control, - .flush = SCPI_Flush, - .reset = SCPI_Reset, + .flush = SCPI_Flush, + .reset = SCPI_Reset, }; char scpi_input_buffer[SCPI_INPUT_BUFFER_LENGTH]; diff --git a/examples/common/scpi-def.cpp b/examples/common/scpi-def.cpp index abbc80a6..052808e4 100644 --- a/examples/common/scpi-def.cpp +++ b/examples/common/scpi-def.cpp @@ -353,70 +353,75 @@ static scpi_result_t My_CoreTstQ(scpi_t * context) { return SCPI_RES_OK; } -const scpi_command_t scpi_commands[] = { - /* IEEE Mandated Commands (SCPI std V1999.0 4.1.1) */ - {"*CLS", SCPI_CoreCls, 0}, - {"*ESE", SCPI_CoreEse, 0}, - {"*ESE?", SCPI_CoreEseQ, 0}, - {"*ESR?", SCPI_CoreEsrQ, 0}, - {"*IDN?", SCPI_CoreIdnQ, 0}, - {"*OPC", SCPI_CoreOpc, 0}, - {"*OPC?", SCPI_CoreOpcQ, 0}, - {"*RST", SCPI_CoreRst, 0}, - {"*SRE", SCPI_CoreSre, 0}, - {"*SRE?", SCPI_CoreSreQ, 0}, - {"*STB?", SCPI_CoreStbQ, 0}, - {"*TST?", My_CoreTstQ, 0}, - {"*WAI", SCPI_CoreWai, 0}, - - /* Required SCPI commands (SCPI std V1999.0 4.2.1) */ - {"SYSTem:ERRor[:NEXT]?", SCPI_SystemErrorNextQ, 0}, - {"SYSTem:ERRor:COUNt?", SCPI_SystemErrorCountQ, 0}, - {"SYSTem:VERSion?", SCPI_SystemVersionQ, 0}, - - //{"STATus:OPERation?", scpi_stub_callback, 0}, - //{"STATus:OPERation:EVENt?", scpi_stub_callback, 0}, - //{"STATus:OPERation:CONDition?", scpi_stub_callback, 0}, - //{"STATus:OPERation:ENABle", scpi_stub_callback, 0}, - //{"STATus:OPERation:ENABle?", scpi_stub_callback, 0}, - - {"STATus:QUEStionable[:EVENt]?", SCPI_StatusQuestionableEventQ, 0}, - //{"STATus:QUEStionable:CONDition?", scpi_stub_callback, 0}, - {"STATus:QUEStionable:ENABle", SCPI_StatusQuestionableEnable, 0}, - {"STATus:QUEStionable:ENABle?", SCPI_StatusQuestionableEnableQ, 0}, - - {"STATus:PRESet", SCPI_StatusPreset, 0}, - - /* DMM */ - {"MEASure:VOLTage:DC?", DMM_MeasureVoltageDcQ, 0}, - {"CONFigure:VOLTage:DC", DMM_ConfigureVoltageDc, 0}, - {"MEASure:VOLTage:DC:RATio?", SCPI_StubQ, 0}, - {"MEASure:VOLTage:AC?", DMM_MeasureVoltageAcQ, 0}, - {"MEASure:CURRent:DC?", SCPI_StubQ, 0}, - {"MEASure:CURRent:AC?", SCPI_StubQ, 0}, - {"MEASure:RESistance?", SCPI_StubQ, 0}, - {"MEASure:FRESistance?", SCPI_StubQ, 0}, - {"MEASure:FREQuency?", SCPI_StubQ, 0}, - {"MEASure:PERiod?", SCPI_StubQ, 0}, - - {"SYSTem:COMMunication:TCPIP:CONTROL?", SCPI_SystemCommTcpipControlQ, 0}, - - {"TEST:BOOL", TEST_Bool, 0}, - {"TEST:CHOice?", TEST_ChoiceQ, 0}, - {"TEST#:NUMbers#", TEST_Numbers, 0}, - {"TEST:TEXT", TEST_Text, 0}, - {"TEST:ARBitrary?", TEST_ArbQ, 0}, - {"TEST:CHANnellist", TEST_Chanlst, 0}, +const scpi_command_t scpi_commands[] = { + /* Optional help command */ +#if USE_HELP_FILTER + {"HELP?", SCPI_HelpQ, SCPI_CMD_DESC("[] - list supported commands [containing \"\"] (multiple block data)") SCPI_CMD_TAG(0)}, +#else + {"HELP?", SCPI_HelpQ, SCPI_CMD_DESC("\t - list supported commands (multiple block data)") SCPI_CMD_TAG(0)}, +#endif + /* IEEE Mandated Commands (SCPI std V1999.0 4.1.1): *CLS *ESE *ESE? *ESR? *IDN? *OPC *OPC? *RST *SRE *SRE? *STB? *TST? *WAI */ + {"*CLS", SCPI_CoreCls, SCPI_CMD_DESC("\t - clear all Event Status registers, errors, output queue") SCPI_CMD_TAG(0)}, + /* -- Standard Event Status Group [EVENT]-[ENABLE] */ + {"*ESE", SCPI_CoreEse, SCPI_CMD_DESC("<0..255> - set Standard Event Status Enable / event mask") SCPI_CMD_TAG(0)}, + {"*ESE?", SCPI_CoreEseQ, SCPI_CMD_DESC("\t - read ESE (0..255)") SCPI_CMD_TAG(0)}, + {"*ESR?", SCPI_CoreEsrQ, SCPI_CMD_DESC("\t - read+clear Standard Event Status register (0..255)") SCPI_CMD_TAG(0)}, + /* -- IEEE Mandated Commands (continued ...) */ + {"*IDN?", SCPI_CoreIdnQ, SCPI_CMD_DESC("\t - read device identifier (str,str,str,str)") SCPI_CMD_TAG(0)}, + {"*OPC", SCPI_CoreOpc, SCPI_CMD_DESC("\t - complete ops preceding Operation Complete Command, set ESR.OPC 1") SCPI_CMD_TAG(0)}, + {"*OPC?", SCPI_CoreOpcQ, SCPI_CMD_DESC("\t - read ESR.OPC (0:ongoing-ops 1:done)") SCPI_CMD_TAG(0)}, + {"*RST", SCPI_CoreRst, SCPI_CMD_DESC("\t - reset instrument and interface") SCPI_CMD_TAG(0)}, + {"*SRE", SCPI_CoreSre, SCPI_CMD_DESC("<0..255> - set Service Request Enable / event mask over STB") SCPI_CMD_TAG(0)}, + {"*SRE?", SCPI_CoreSreQ, SCPI_CMD_DESC("\t - read SRE (0..255)") SCPI_CMD_TAG(0)}, + {"*STB?", SCPI_CoreStbQ, SCPI_CMD_DESC("\t - read STatus Byte (0..255)") SCPI_CMD_TAG(0)}, + {"*TST?", My_CoreTstQ, SCPI_CMD_DESC("\t - read self-test result (0:no-failures)") SCPI_CMD_TAG(0)}, + {"*WAI", SCPI_CoreWai, SCPI_CMD_DESC("\t - halt cmd execution until pending operations complete") SCPI_CMD_TAG(0)}, + + /* Required SCPI commands (SCPI std V1999.0 4.2.1) : SYSTem:ERRor, STATus:OPERation, STATus:QUEStionable and STATus:PRESet */ + {"SYSTem:ERRor[:NEXT]?", SCPI_SystemErrorNextQ, SCPI_CMD_DESC("\t - get next error in queue (int-errno,str)") SCPI_CMD_TAG(0)}, + {"SYSTem:ERRor:COUNt?", SCPI_SystemErrorCountQ, SCPI_CMD_DESC("\t - queued error count (0.." SCPI_ERROR_QUEUE_SIZE_STR ")") SCPI_CMD_TAG(0)}, + {"SYSTem:VERSion?", SCPI_SystemVersionQ, SCPI_CMD_DESC("\t - query system version (str)") SCPI_CMD_TAG(0)}, + /* -- Operation Status Group [CONDITION]-[EVENT]-[ENABLE] */ + {"STATus:OPERation:CONDition?", SCPI_StubQ, SCPI_CMD_DESC("\t - not implemented (0)") SCPI_CMD_TAG(0)}, + {"STATus:OPERation[:EVENt]?", SCPI_StubQ, SCPI_CMD_DESC("\t - not implemented (0)") SCPI_CMD_TAG(0)}, + {"STATus:OPERation:ENABle", SCPI_Stub, SCPI_CMD_DESC("\t - not implemented") SCPI_CMD_TAG(0)}, + {"STATus:OPERation:ENABle?", SCPI_StubQ, SCPI_CMD_DESC("\t - not implemented (0)") SCPI_CMD_TAG(0)}, + /* -- Questionable Status Group [CONDITION]-[EVENT]-[ENABLE] */ + {"STATus:QUEStionable:CONDition?", SCPI_StubQ, SCPI_CMD_DESC("\t - not implemented (0)") SCPI_CMD_TAG(0)}, /* "\t - read momentary Questionable Condition register (0..65535)" */ + {"STATus:QUEStionable[:EVENt]?", SCPI_StatusQuestionableEventQ, SCPI_CMD_DESC("\t - read Questionable Event register (0..65535)") SCPI_CMD_TAG(0)}, + {"STATus:QUEStionable:ENABle", SCPI_StatusQuestionableEnable, SCPI_CMD_DESC("<0..65535> - set Questionable Enable / event mask") SCPI_CMD_TAG(0)}, + {"STATus:QUEStionable:ENABle?", SCPI_StatusQuestionableEnableQ, SCPI_CMD_DESC("\t - Questionable Status Enable (0..65535)") SCPI_CMD_TAG(0)}, + {"STATus:PRESet", SCPI_StatusPreset, SCPI_CMD_DESC("\t - load Status sub-system register defaults") SCPI_CMD_TAG(0)}, + + /* commands specific to DMM example with TEST sub-system */ + {"SYSTem:COMMunication:TCPIP:CONTROL?", SCPI_SystemCommTcpipControlQ, SCPI_CMD_DESC("\t - read TCPIP control port (int)") SCPI_CMD_TAG(0)}, + {"CONFigure:VOLTage:DC", DMM_ConfigureVoltageDc, SCPI_CMD_DESC("[,] - test command") SCPI_CMD_TAG(0)}, + {"MEASure:VOLTage:DC?", DMM_MeasureVoltageDcQ, SCPI_CMD_DESC("[[,]] - test command (0)") SCPI_CMD_TAG(0)}, + {"MEASure:VOLTage:DC:RATio?", SCPI_StubQ, SCPI_CMD_DESC("\t - not implemented (0)") SCPI_CMD_TAG(0)}, + {"MEASure:VOLTage:AC?", DMM_MeasureVoltageAcQ, SCPI_CMD_DESC("[[,]] - test command (0)") SCPI_CMD_TAG(0)}, + {"MEASure:CURRent:DC?", SCPI_StubQ, SCPI_CMD_DESC("\t - not implemented (0)") SCPI_CMD_TAG(0)}, + {"MEASure:CURRent:AC?", SCPI_StubQ, SCPI_CMD_DESC("\t - not implemented (0)") SCPI_CMD_TAG(0)}, + {"MEASure:RESistance?", SCPI_StubQ, SCPI_CMD_DESC("\t - not implemented (0)") SCPI_CMD_TAG(0)}, + {"MEASure:FRESistance?", SCPI_StubQ, SCPI_CMD_DESC("\t - not implemented (0)") SCPI_CMD_TAG(0)}, + {"MEASure:FREQuency?", SCPI_StubQ, SCPI_CMD_DESC("\t - not implemented (0)") SCPI_CMD_TAG(0)}, + {"MEASure:PERiod?", SCPI_StubQ, SCPI_CMD_DESC("\t - not implemented (0)") SCPI_CMD_TAG(0)}, + {"TEST:BOOL", TEST_Bool, SCPI_CMD_DESC(" - test command") SCPI_CMD_TAG(0)}, + {"TEST:CHOice?", TEST_ChoiceQ, SCPI_CMD_DESC(" - test command (\"BUS\":5 \"IMMediate\":6 \"EXTernal\":7)") SCPI_CMD_TAG(0)}, + {"TEST#:NUMbers#", TEST_Numbers, SCPI_CMD_DESC("\t - test command with optional numbers - default 1") SCPI_CMD_TAG(0)}, + {"TEST:TEXT", TEST_Text, SCPI_CMD_DESC("[, ...] - debug print param as received") SCPI_CMD_TAG(0)}, + {"TEST:ARBitrary?", TEST_ArbQ, SCPI_CMD_DESC(" - receive and return block data (block data)") SCPI_CMD_TAG(0)}, + {"TEST:CHANnellist", TEST_Chanlst, SCPI_CMD_DESC(" - test channel list parsing") SCPI_CMD_TAG(0)}, + SCPI_CMD_LIST_END }; scpi_interface_t scpi_interface = { - /*.error = */ SCPI_Error, - /*.write = */ SCPI_Write, + /*.error = */ SCPI_Error, + /*.write = */ SCPI_Write, /*.control = */ SCPI_Control, - /*.flush = */ SCPI_Flush, - /*.reset = */ SCPI_Reset, + /*.flush = */ SCPI_Flush, + /*.reset = */ SCPI_Reset, }; char scpi_input_buffer[SCPI_INPUT_BUFFER_LENGTH]; diff --git a/examples/common/scpi-def.h b/examples/common/scpi-def.h index 9e89f95a..33e893a3 100644 --- a/examples/common/scpi-def.h +++ b/examples/common/scpi-def.h @@ -41,6 +41,8 @@ extern "C" { #define SCPI_IDN3 NULL #define SCPI_IDN4 "01-02" +#define SCPI_ERROR_QUEUE_SIZE_STR PP_XSTR(SCPI_ERROR_QUEUE_SIZE) + extern const scpi_command_t scpi_commands[]; extern scpi_interface_t scpi_interface; extern char scpi_input_buffer[]; diff --git a/libscpi/Makefile b/libscpi/Makefile index 9a0b5ee5..04c27f34 100644 --- a/libscpi/Makefile +++ b/libscpi/Makefile @@ -28,7 +28,7 @@ SHAREDLIBVER = $(SHAREDLIB).$(VERSION) SRCS = $(addprefix src/, \ error.c fifo.c ieee488.c \ - minimal.c parser.c units.c utils.c \ + minimal.c help.c parser.c units.c utils.c \ lexer.c expression.c \ ) @@ -37,7 +37,7 @@ OBJS_SHARED = $(addprefix $(OBJDIR_SHARED)/, $(notdir $(SRCS:.c=.o))) HDRS = $(addprefix inc/scpi/, \ scpi.h constants.h error.h \ - ieee488.h minimal.h parser.h types.h units.h \ + ieee488.h minimal.h help.h parser.h types.h units.h \ expression.h \ ) \ $(addprefix src/, \ diff --git a/libscpi/inc/scpi/config.h b/libscpi/inc/scpi/config.h index 2d3652e6..5c61c3a1 100644 --- a/libscpi/inc/scpi/config.h +++ b/libscpi/inc/scpi/config.h @@ -49,9 +49,9 @@ extern "C" { #endif /* set the termination character(s) */ -#define LINE_ENDING_CR "\r" /* use a carriage return as termination charcter */ -#define LINE_ENDING_LF "\n" /* use a line feed as termination charcter */ -#define LINE_ENDING_CRLF "\r\n" /* use carriage return + line feed as termination charcters */ +#define LINE_ENDING_CR "\r" /* use a carriage return as termination character */ +#define LINE_ENDING_LF "\n" /* use a line feed as termination character */ +#define LINE_ENDING_CRLF "\r\n" /* use carriage return + line feed as termination characters */ #ifndef SCPI_LINE_ENDING #define SCPI_LINE_ENDING LINE_ENDING_CRLF @@ -63,7 +63,7 @@ extern "C" { /** * Detect, if it has limited resources or it is running on a full blown operating system. - * All values can be overiden by scpi_user_config.h + * All values can be overridden by scpi_user_config.h */ #define SYSTEM_BARE_METAL 0 #define SYSTEM_FULL_BLOWN 1 @@ -80,8 +80,8 @@ extern "C" { * 0 = Minimal set of errors * 1 = Full set of errors * - * For small systems, full set of errors will occupy large ammount of data - * It is enabled by default on full blown systems and disabled on limited bare metal systems + * For small systems, full set of errors will occupy large amount of data. + * It is enabled by default on full blown systems and disabled on limited bare metal systems. */ #ifndef USE_FULL_ERROR_LIST #define USE_FULL_ERROR_LIST SYSTEM_TYPE @@ -114,10 +114,18 @@ extern "C" { #define USE_COMMAND_TAGS 1 #endif +#ifndef USE_COMMAND_DESCRIPTIONS +#define USE_COMMAND_DESCRIPTIONS 0 +#endif + #ifndef USE_DEPRECATED_FUNCTIONS #define USE_DEPRECATED_FUNCTIONS 1 #endif +#ifndef USE_HELP_FILTER +#define USE_HELP_FILTER 1 +#endif + #ifndef USE_CUSTOM_DTOSTRE #define USE_CUSTOM_DTOSTRE 0 #endif @@ -178,14 +186,14 @@ extern "C" { #define USE_UNITS_ELECTRIC_CHARGE_CONDUCTANCE SYSTEM_TYPE #endif -/* define local macros depending on existance of strnlen */ +/* define local macros depending on existence of strnlen */ #if HAVE_STRNLEN #define SCPIDEFINE_strnlen(s, l) strnlen((s), (l)) #else #define SCPIDEFINE_strnlen(s, l) BSD_strnlen((s), (l)) #endif -/* define local macros depending on existance of strncasecmp and strnicmp */ +/* define local macros depending on existence of strncasecmp and strnicmp */ #if HAVE_STRNCASECMP #define SCPIDEFINE_strncasecmp(s1, s2, l) strncasecmp((s1), (s2), (l)) #elif HAVE_STRNICMP diff --git a/libscpi/inc/scpi/help.h b/libscpi/inc/scpi/help.h new file mode 100644 index 00000000..47eac0b9 --- /dev/null +++ b/libscpi/inc/scpi/help.h @@ -0,0 +1,53 @@ +/*- + * BSD 2-Clause License + * + * Copyright (c) 2023, Helge Wurst + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file help.h + * @date Tue Jan 17 16:27:00 UTC 2023 + * + * @brief HELP? [""] command handler + * + * + */ + +#ifndef SCPI_HELP_H +#define SCPI_HELP_H + +#include "scpi/types.h" + +#ifdef __cplusplus +extern "C" { +#endif + + scpi_result_t SCPI_HelpQ(scpi_t * context); + +#ifdef __cplusplus +} +#endif + +#endif /* SCPI_HELP_H */ diff --git a/libscpi/inc/scpi/minimal.h b/libscpi/inc/scpi/minimal.h index e14f1ed6..8208bfff 100644 --- a/libscpi/inc/scpi/minimal.h +++ b/libscpi/inc/scpi/minimal.h @@ -60,10 +60,8 @@ extern "C" { scpi_result_t SCPI_StatusOperationEnable(scpi_t * context); scpi_result_t SCPI_StatusPreset(scpi_t * context); - #ifdef __cplusplus } #endif #endif /* SCPI_MINIMAL_H */ - diff --git a/libscpi/inc/scpi/scpi.h b/libscpi/inc/scpi/scpi.h index ea28dd44..eb333bf1 100644 --- a/libscpi/inc/scpi/scpi.h +++ b/libscpi/inc/scpi/scpi.h @@ -46,6 +46,7 @@ #include "scpi/units.h" #include "scpi/utils.h" #include "scpi/expression.h" +#include "scpi/help.h" #endif /* SCPI_H */ diff --git a/libscpi/inc/scpi/types.h b/libscpi/inc/scpi/types.h index eb9b2153..b012f718 100644 --- a/libscpi/inc/scpi/types.h +++ b/libscpi/inc/scpi/types.h @@ -50,7 +50,7 @@ extern "C" { #endif -#if !HAVE_STDBOOL +#if (!HAVE_STDBOOL) && (!_GLIBCXX_HAVE_STDBOOL_H) typedef unsigned char bool; #endif @@ -170,13 +170,22 @@ extern "C" { typedef enum _scpi_result_t scpi_result_t; typedef struct _scpi_command_t scpi_command_t; - + +/* Helper macros for _scpi_command_t items. Usage: + _scpi_command_t cmd = {.pattern=":SOME:PATTern", .callback=SCPI_StubQ, SCPI_CMD_DESC("\t - a command") SCPI_CMD_TAG(0)}; +*/ +#if USE_COMMAND_DESCRIPTIONS +#define SCPI_CMD_DESC(S) (S), +#else +#define SCPI_CMD_DESC(S) +#endif #if USE_COMMAND_TAGS - #define SCPI_CMD_LIST_END {NULL, NULL, 0} +#define SCPI_CMD_TAG(T) (T), #else - #define SCPI_CMD_LIST_END {NULL, NULL} +#define SCPI_CMD_TAG(T) #endif +#define SCPI_CMD_LIST_END {NULL, NULL, SCPI_CMD_DESC(NULL) SCPI_CMD_TAG(0)} /* scpi interface */ typedef struct _scpi_t scpi_t; @@ -404,14 +413,17 @@ extern "C" { typedef struct _scpi_data_parameter_t scpi_data_parameter_t; typedef scpi_token_t scpi_parameter_t; - + struct _scpi_command_t { const char * pattern; scpi_command_callback_t callback; +#if USE_COMMAND_DESCRIPTIONS + const char * description; +#endif /* USE_COMMAND_DESCRIPTIONS */ #if USE_COMMAND_TAGS int32_t tag; #endif /* USE_COMMAND_TAGS */ - }; +}; struct _scpi_interface_t { scpi_error_callback_t error; @@ -456,4 +468,3 @@ extern "C" { #endif #endif /* SCPI_TYPES_H */ - diff --git a/libscpi/inc/scpi/utils.h b/libscpi/inc/scpi/utils.h index 055e4683..fb853313 100644 --- a/libscpi/inc/scpi/utils.h +++ b/libscpi/inc/scpi/utils.h @@ -54,9 +54,13 @@ extern "C" { /* deprecated finction, should be removed later */ #define SCPI_LongToStr(val, str, len, base) SCPI_Int32ToStr((val), (str), (len), (base), TRUE) +/* Pre-Processor Transform String (double indirection PP_XSTR(s) converts a number definition into a string definiton) */ +#define PP_STR(s) #s +#define PP_XSTR(s) PP_STR(s) + + #ifdef __cplusplus } #endif #endif /* SCPI_UTILS_H */ - diff --git a/libscpi/src/help.c b/libscpi/src/help.c new file mode 100644 index 00000000..95149cdf --- /dev/null +++ b/libscpi/src/help.c @@ -0,0 +1,83 @@ +/*- + * BSD 2-Clause License + * + * Copyright (c) 2023, Helge Wurst + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + /** + * @file help.c + * @date Tue Jan 17 16:27:00 UTC 2023 + * + * @brief HELP? [""] command handler + * + * + */ + +#include "scpi/parser.h" +#include "scpi/help.h" +#include "scpi/constants.h" +#include "scpi/error.h" +#include "scpi/ieee488.h" +#include "utils_private.h" + +/** + * HELP? [""] + * @param context + * @return + */ +scpi_result_t SCPI_HelpQ(scpi_t * context) { +#if USE_HELP_FILTER + size_t search_string_len = 0; + const char * search_string = NULL; + scpi_bool_t narrowed_down = SCPI_ParamCharacters(context, &search_string, &search_string_len, FALSE); +#endif + size_t i; + for(i = 0; context->cmdlist[i].pattern != NULL; i++) { + size_t pattern_len = strlen(context->cmdlist[i].pattern); +#if USE_HELP_FILTER + if(narrowed_down && (NULL == strncasestrn(context->cmdlist[i].pattern, pattern_len, search_string, search_string_len))){ + continue; + } +#endif + size_t block_len = 1 + pattern_len + strlen(SCPI_LINE_ENDING); +#if USE_COMMAND_DESCRIPTIONS + size_t description_len = context->cmdlist[i].description ? strlen(context->cmdlist[i].description) : 0; + if(description_len > 0){ + block_len = 1 + pattern_len + 1 + description_len + strlen(SCPI_LINE_ENDING); + } +#endif + SCPI_ResultArbitraryBlockHeader(context, block_len); + SCPI_ResultArbitraryBlockData(context, "\t", 1); + SCPI_ResultArbitraryBlockData(context, context->cmdlist[i].pattern, pattern_len); +#if USE_COMMAND_DESCRIPTIONS + if(description_len > 0){ + SCPI_ResultArbitraryBlockData(context, " ", 1); + SCPI_ResultArbitraryBlockData(context, context->cmdlist[i].description, description_len); + } +#endif + SCPI_ResultArbitraryBlockData(context, SCPI_LINE_ENDING, strlen(SCPI_LINE_ENDING)); + } + return SCPI_RES_OK; +} diff --git a/libscpi/src/utils.c b/libscpi/src/utils.c index 328f8be7..cf851929 100644 --- a/libscpi/src/utils.c +++ b/libscpi/src/utils.c @@ -1140,3 +1140,44 @@ uint64_t SCPI_Swap64(uint64_t val) { ((val & 0x00FF000000000000ull) >> 40) | ((val & 0xFF00000000000000ull) >> 56); } + +#define CHAR_TO_UPPER(c) ((c)>96 && (c)<123 ? (char)((c) ^ 0x20) : (c)) +#define CHAR_TO_LOWER(c) ((c)>64 && (c)< 91 ? (char)((c) | 0x20) : (c)) + +/** + * @brief Locate a binary substring within a binary string (case-insensitive `strnstrn`). + * @param[in] s binary string + * @param[in] slen length of binary string s + * @param[in] find binary substring + * @param[in] findlen length of binary substring find + * @return Pointer to first match in s if found, otherwise `NULL`. + * @author Alvaro Lopez Ortega + */ +char * strncasestrn (const char *s, size_t slen, const char *find, size_t findlen) +{ + char first; + char cursor_chr; + + if ((find == NULL) || (findlen == 0)) + return (char *)s; + + if ((*find == '\0')) + return (char *)s; + + first = CHAR_TO_LOWER(*find); + find++; + findlen--; + + do { + do { + if (slen-- < 1 || (cursor_chr = *s++) == '\0') + return NULL; + } while (CHAR_TO_LOWER(cursor_chr) != first); + if (findlen > slen) { + return NULL; + } + } while (SCPIDEFINE_strncasecmp(s, find, findlen) != 0); + + s--; + return (char *)s; +} diff --git a/libscpi/src/utils_private.h b/libscpi/src/utils_private.h index 6ae1616a..7955433a 100644 --- a/libscpi/src/utils_private.h +++ b/libscpi/src/utils_private.h @@ -99,6 +99,8 @@ extern "C" { char *OUR_strndup(const char *s, size_t n); #endif + char * strncasestrn (const char *s, size_t slen, const char *find, size_t findlen); + #ifndef min #define min(a, b) (((a) < (b)) ? (a) : (b)) #endif