https://github.com/j123b567/scpi-parser
Dependents: scpi_sx127x scpi_sx127x_firstTest MLX90418_I2C_master
Revision 1:b497f235115a, committed 2015-08-07
- Comitter:
- dudmuck
- Date:
- Fri Aug 07 21:54:11 2015 +0000
- Parent:
- 0:aad43948c45c
- Commit message:
- update from github commit 6e5e3e0e3fc450eaf53feee059824ad85c4f270d
Changed in this revision
--- a/inc/scpi/config.h Thu Apr 09 22:42:15 2015 +0000 +++ b/inc/scpi/config.h Fri Aug 07 21:54:11 2015 +0000 @@ -2,7 +2,7 @@ * Copyright (c) 2012-2013 Jan Breuer, * * All Rights Reserved - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: @@ -11,7 +11,7 @@ * 2. 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 AUTHORS ``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 @@ -28,10 +28,10 @@ /** * @file config.h * @date Wed Mar 20 12:21:26 UTC 2013 - * + * * @brief SCPI Configuration - * - * + * + * */ #ifndef __SCPI_CONFIG_H_ @@ -41,7 +41,54 @@ extern "C" { #endif +#ifdef SCPI_USER_CONFIG +#include "scpi_user_config.h" +#endif + +/* set the termination character(s) */ +#define LINE_ENDING_CR "\r" /* use a <CR> carriage return as termination charcter */ +#define LINE_ENDING_LF "\n" /* use a <LF> line feed as termination charcter */ +#define LINE_ENDING_CRLF "\r\n" /* use <CR><LF> carriage return + line feed as termination charcters */ + +#ifndef SCPI_LINE_ENDING +#define SCPI_LINE_ENDING LINE_ENDING_CRLF +#endif + +/* Enable full error list + * 0 = Minimal set of errors + * 1 = Full set of errors + * + * For small systems, full set of errors will occupy large ammount of data + */ +#ifndef USE_FULL_ERROR_LIST +#define USE_FULL_ERROR_LIST 0 +#endif + +/** + * Enable also LIST_OF_USER_ERRORS to be included + * 0 = Use only library defined errors + * 1 = Use also LIST_OF_USER_ERRORS + */ +#ifndef USE_USER_ERROR_LIST +#define USE_USER_ERROR_LIST 0 +#endif + /* Compiler specific */ +/* RealView/Keil ARM Compiler, e.g. Cortex-M CPUs */ +#if defined(__CC_ARM) +#define HAVE_STRNLEN 0 +#define HAVE_STRNCASECMP 1 +#define HAVE_STRNICMP 0 +#endif + +/* National Instruments (R) CVI x86/x64 PC platform */ +#if defined(_CVI_) +#define HAVE_STRNLEN 0 +#define HAVE_STRNCASECMP 0 +#define HAVE_STRNICMP 1 +#define HAVE_STDBOOL 0 +#endif + /* 8bit PIC - PIC16, etc */ #if defined(_MPC_) #define HAVE_STRNLEN 0 @@ -63,6 +110,12 @@ #define HAVE_STRNICMP 0 #endif +/* AVR libc */ +#if defined(__AVR__) +#include <stdlib.h> +#define HAVE_DTOSTRE 1 +#endif + /* ======== test strnlen ======== */ #ifndef HAVE_STRNLEN #define HAVE_STRNLEN 1 @@ -76,22 +129,33 @@ #define HAVE_STRNICMP 0 #endif +#ifndef HAVE_STDBOOL +#define HAVE_STDBOOL 1 +#endif + /* define local macros depending on existance of strnlen */ #if HAVE_STRNLEN -#define SCPI_strnlen(s, l) strnlen((s), (l)) +#define SCPIDEFINE_strnlen(s, l) strnlen((s), (l)) #else -#define SCPI_strnlen(s, l) BSD_strnlen((s), (l)) +#define SCPIDEFINE_strnlen(s, l) BSD_strnlen((s), (l)) #endif /* define local macros depending on existance of strncasecmp and strnicmp */ #if HAVE_STRNCASECMP -#define SCPI_strncasecmp(s1, s2, l) strncasecmp((s1), (s2), (l)) +#define SCPIDEFINE_strncasecmp(s1, s2, l) strncasecmp((s1), (s2), (l)) #elif HAVE_STRNICMP -#define SCPI_strncasecmp(s1, s2, l) strnicmp((s1), (s2), (l)) +#define SCPIDEFINE_strncasecmp(s1, s2, l) strnicmp((s1), (s2), (l)) #else -#define SCPI_strncasecmp(s1, s2, l) OUR_strncasecmp((s1), (s2), (l)) +#define SCPIDEFINE_strncasecmp(s1, s2, l) OUR_strncasecmp((s1), (s2), (l)) #endif +#if HAVE_DTOSTRE +#define SCPIDEFINE_doubleToStr(v, s, l) strlen(dtostre((v), (s), 6, DTOSTR_PLUS_SIGN | DTOSTR_ALWAYS_SIGN | DTOSTR_UPPERCASE)) +#else +#define SCPIDEFINE_doubleToStr(v, s, l) snprintf((s), (l), "%lg", (v)) +#endif + + #ifdef __cplusplus } #endif
--- a/inc/scpi/constants.h Thu Apr 09 22:42:15 2015 +0000 +++ b/inc/scpi/constants.h Fri Aug 07 21:54:11 2015 +0000 @@ -61,4 +61,3 @@ #endif #endif /* SCPI_CONSTANTS_H */ -
--- a/inc/scpi/debug.h Thu Apr 09 22:42:15 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -/*- - * Copyright (c) 2012-2013 Jan Breuer, - * - * All Rights Reserved - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. 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 AUTHORS ``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 AUTHORS 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 scpi_debug.h - * @date Thu Nov 15 10:58:45 UTC 2012 - * - * @brief SCPI debug function - * - * - */ - -#ifndef SCPI_DEBUG_H -#define SCPI_DEBUG_H - -#include "scpi/types.h" - -#ifdef __cplusplus -extern "C" { -#endif - - - /* #define SCPI_DEBUG_COMMAND(a) scpi_debug_command(a) */ - #define SCPI_DEBUG_COMMAND(a) - - - scpi_bool_t SCPI_DebugCommand(scpi_t * context); - - -#ifdef __cplusplus -} -#endif - -#endif /* SCPI_DEBUG_H */ -
--- a/inc/scpi/error.h Thu Apr 09 22:42:15 2015 +0000 +++ b/inc/scpi/error.h Fri Aug 07 21:54:11 2015 +0000 @@ -37,9 +37,10 @@ #ifndef SCPI_ERROR_H #define SCPI_ERROR_H +#include "scpi/config.h" #include "scpi/types.h" -#ifdef __cplusplus +#ifdef __cplusplus extern "C" { #endif @@ -50,28 +51,153 @@ int32_t SCPI_ErrorCount(scpi_t * context); const char * SCPI_ErrorTranslate(int16_t err); -/* http://en.wikipedia.org/wiki/X_Macro */ + +/* Using X-Macro technique to define everything once + * http://en.wikipedia.org/wiki/X_Macro + * + * X macro is for minimal set of errors for library itself + * XE macro is for full set of SCPI errors available to user application + */ #define LIST_OF_ERRORS \ - X(SCPI_ERROR_SYNTAX, -102, "Syntax error") \ - X(SCPI_ERROR_INVALID_SEPARATOR, -103, "Invalid separator") \ - X(SCPI_ERROR_UNDEFINED_HEADER, -113, "Undefined header") \ - X(SCPI_ERROR_PARAMETER_NOT_ALLOWED,-108, "Parameter not allowed") \ - X(SCPI_ERROR_MISSING_PARAMETER, -109, "Missing parameter") \ - X(SCPI_ERROR_INVALID_SUFFIX, -131, "Invalid suffix") \ - X(SCPI_ERROR_SUFFIX_NOT_ALLOWED, -138, "Suffix not allowed") \ - X(SCPI_ERROR_EXECUTION_ERROR, -200, "Execution error") \ - X(SCPI_ERROR_ILLEGAL_PARAMETER_VALUE,-224,"Illegal parameter value") \ - + XE(SCPI_ERROR_COMMAND, -100, "Command error") \ + X(SCPI_ERROR_INVALID_CHARACTER, -101, "Invalid character") \ + XE(SCPI_ERROR_SYNTAX, -102, "Syntax error") \ + X(SCPI_ERROR_INVALID_SEPARATOR, -103, "Invalid separator") \ + X(SCPI_ERROR_DATA_TYPE_ERROR, -104, "Data type error") \ + XE(SCPI_ERROR_GET_NOT_ALLOWED, -105, "GET not allowed") \ + X(SCPI_ERROR_PARAMETER_NOT_ALLOWED, -108, "Parameter not allowed") \ + X(SCPI_ERROR_MISSING_PARAMETER, -109, "Missing parameter") \ + XE(SCPI_ERROR_COMMAND_HEADER, -110, "Command header error") \ + XE(SCPI_ERROR_HEADER_SEPARATOR, -111, "Header separator error") \ + XE(SCPI_ERROR_PRG_MNEMONIC_TOO_LONG, -112, "Program mnemonic too long") \ + X(SCPI_ERROR_UNDEFINED_HEADER, -113, "Undefined header") \ + XE(SCPI_ERROR_HEADER_SUFFIX_OUTOFRANGE, -114, "Header suffix out of range") \ + XE(SCPI_ERROR_UNEXP_NUM_OF_PARAMETER, -115, "Unexpected number of parameters") \ + XE(SCPI_ERROR_NUMERIC_DATA_ERROR, -120, "Numeric data error") \ + XE(SCPI_ERROR_INVAL_CHAR_IN_NUMBER, -121, "Invalid character in number") \ + XE(SCPI_ERROR_EXPONENT_TOO_LONG, -123, "Exponent too large") \ + XE(SCPI_ERROR_TOO_MANY_DIGITS, -124, "Too many digits") \ + XE(SCPI_ERROR_NUMERIC_DATA_NOT_ALLOWED, -128, "Numeric data not allowed") \ + XE(SCPI_ERROR_SUFFIX_ERROR, -130, "Suffix error") \ + X(SCPI_ERROR_INVALID_SUFFIX, -131, "Invalid suffix") \ + XE(SCPI_ERROR_SUFFIX_TOO_LONG, -134, "Suffix too long") \ + X(SCPI_ERROR_SUFFIX_NOT_ALLOWED, -138, "Suffix not allowed") \ + XE(SCPI_ERROR_CHARACTER_DATA_ERROR, -140, "Character data error") \ + XE(SCPI_ERROR_INVAL_CHARACTER_DATA, -141, "Invalid character data") \ + XE(SCPI_ERROR_CHARACTER_DATA_TOO_LONG, -144, "Character data too long") \ + XE(SCPI_ERROR_CHARACTER_DATA_NOT_ALLOWED, -148, "Character data not allowed") \ + XE(SCPI_ERROR_STRING_DATA_ERROR, -150, "String data error") \ + X(SCPI_ERROR_INVALID_STRING_DATA, -151, "Invalid string data") \ + XE(SCPI_ERROR_STRING_DATA_NOT_ALLOWED, -158, "String data not allowed") \ + XE(SCPI_ERROR_BLOCK_DATA_ERROR, -160, "Block data error") \ + XE(SCPI_ERROR_INVALID_BLOCK_DATA, -161, "Invalid block data") \ + XE(SCPI_ERROR_BLOCK_DATA_NOT_ALLOWED, -168, "Block data not allowed") \ + XE(SCPI_ERROR_EXPRESSION_PARSING_ERROR, -170, "Expression error") \ + XE(SCPI_ERROR_INVAL_EXPRESSION, -171, "Invalid expression") \ + XE(SCPI_ERROR_EXPRESSION_DATA_NOT_ALLOWED, -178, "Expression data not allowed") \ + XE(SCPI_ERROR_MACRO_DEFINITION_ERROR, -180, "Macro error") \ + XE(SCPI_ERROR_INVAL_OUTSIDE_MACRO_DEF, -181, "Invalid outside macro definition") \ + XE(SCPI_ERROR_INVAL_INSIDE_MACRO_DEF, -183, "Invalid inside macro definition") \ + XE(SCPI_ERROR_MACRO_PARAMETER_ERROR, -184, "Macro parameter error") \ + X(SCPI_ERROR_EXECUTION_ERROR, -200, "Execution error") \ + XE(SCPI_ERROR_INVAL_WHILE_IN_LOCAL, -201, "Invalid while in local") \ + XE(SCPI_ERROR_SETTINGS_LOST_DUE_TO_RTL, -202, "Settings lost due to rtl") \ + XE(SCPI_ERROR_COMMAND_PROTECTED, -203, "Command protected TK024") \ + XE(SCPI_ERROR_TRIGGER_ERROR, -210, "Trigger error") \ + XE(SCPI_ERROR_TRIGGER_IGNORED, -211, "Trigger ignored") \ + XE(SCPI_ERROR_ARM_IGNORED, -212, "Arm ignored") \ + XE(SCPI_ERROR_INIT_IGNORED, -213, "Init ignored") \ + XE(SCPI_ERROR_TRIGGER_DEADLOCK, -214, "Trigger deadlock") \ + XE(SCPI_ERROR_ARM_DEADLOCK, -215, "Arm deadlock") \ + XE(SCPI_ERROR_PARAMETER_ERROR, -220, "Parameter error") \ + XE(SCPI_ERROR_SETTINGS_CONFLICT, -221, "Settings conflict") \ + XE(SCPI_ERROR_DATA_OUT_OF_RANGE, -222, "Data out of range") \ + XE(SCPI_ERROR_TOO_MUCH_DATA, -223, "Too much data") \ + X(SCPI_ERROR_ILLEGAL_PARAMETER_VALUE, -224, "Illegal parameter value") \ + XE(SCPI_ERROR_OUT_OF_MEMORY_FOR_REQ_OP, -225, "Out of memory") \ + XE(SCPI_ERROR_LISTS_NOT_SAME_LENGTH, -226, "Lists not same length") \ + XE(SCPI_ERROR_DATA_CORRUPT, -230, "Data corrupt or stale") \ + XE(SCPI_ERROR_DATA_QUESTIONABLE, -231, "Data questionable") \ + XE(SCPI_ERROR_INVAL_VERSION, -233, "Invalid version") \ + XE(SCPI_ERROR_HARDWARE_ERROR, -240, "Hardware error") \ + XE(SCPI_ERROR_HARDWARE_MISSING, -241, "Hardware missing") \ + XE(SCPI_ERROR_MASS_STORAGE_ERROR, -250, "Mass storage error") \ + XE(SCPI_ERROR_MISSING_MASS_STORAGE, -251, "Missing mass storage") \ + XE(SCPI_ERROR_MISSING_MASS_MEDIA, -252, "Missing media") \ + XE(SCPI_ERROR_CORRUPT_MEDIA, -253, "Corrupt media") \ + XE(SCPI_ERROR_MEDIA_FULL, -254, "Media full") \ + XE(SCPI_ERROR_DIRECTORY_FULL, -255, "Directory full") \ + XE(SCPI_ERROR_FILE_NAME_NOT_FOUND, -256, "File name not found") \ + XE(SCPI_ERROR_FILE_NAME_ERROR, -257, "File name error") \ + XE(SCPI_ERROR_MEDIA_PROTECTED, -258, "Media protected") \ + XE(SCPI_ERROR_EXPRESSION_EXECUTING_ERROR, -260, "Expression error") \ + XE(SCPI_ERROR_MATH_ERROR_IN_EXPRESSION, -261, "Math error in expression") \ + XE(SCPI_ERROR_MACRO_UNDEF_EXEC_ERROR, -270, "Macro error") \ + XE(SCPI_ERROR_MACRO_SYNTAX_ERROR, -271, "Macro syntax error") \ + XE(SCPI_ERROR_MACRO_EXECUTION_ERROR, -272, "Macro execution error") \ + XE(SCPI_ERROR_ILLEGAL_MACRO_LABEL, -273, "Illegal macro label") \ + XE(SCPI_ERROR_IMPROPER_USED_MACRO_PARAM, -274, "Macro parameter error") \ + XE(SCPI_ERROR_MACRO_DEFINITION_TOO_LONG, -275, "Macro definition too long") \ + XE(SCPI_ERROR_MACRO_RECURSION_ERROR, -276, "Macro recursion error") \ + XE(SCPI_ERROR_MACRO_REDEF_NOT_ALLOWED, -277, "Macro redefinition not allowed") \ + XE(SCPI_ERROR_MACRO_HEADER_NOT_FOUND, -278, "Macro header not found") \ + XE(SCPI_ERROR_PROGRAM_ERROR, -280, "Program error") \ + XE(SCPI_ERROR_CANNOT_CREATE_PROGRAM, -281, "Cannot create program") \ + XE(SCPI_ERROR_ILLEGAL_PROGRAM_NAME, -282, "Illegal program name") \ + XE(SCPI_ERROR_ILLEGAL_VARIABLE_NAME, -283, "Illegal variable name") \ + XE(SCPI_ERROR_PROGRAM_CURRENTLY_RUNNING, -284, "Program currently running") \ + XE(SCPI_ERROR_PROGRAM_SYNTAX_ERROR, -285, "Program syntax error") \ + XE(SCPI_ERROR_PROGRAM_RUNTIME_ERROR, -286, "Program runtime error") \ + XE(SCPI_ERROR_MEMORY_USE_ERROR, -290, "Memory use error") \ + XE(SCPI_ERROR_OUT_OF_MEMORY, -291, "Out of memory") \ + XE(SCPI_ERROR_REF_NAME_DOES_NOT_EXIST, -292, "Referenced name does not exist") \ + XE(SCPI_ERROR_REF_NAME_ALREADY_EXISTS, -293, "Referenced name already exists") \ + XE(SCPI_ERROR_INCOMPATIBLE_TYPE, -294, "Incompatible type") \ + XE(SCPI_ERROR_DEVICE_ERROR, -300, "Device specific error") \ + X(SCPI_ERROR_SYSTEM_ERROR, -310, "System error") \ + XE(SCPI_ERROR_MEMORY_ERROR, -311, "Memory error") \ + XE(SCPI_ERROR_PUD_MEMORY_LOST, -312, "PUD memory lost") \ + XE(SCPI_ERROR_CALIBRATION_MEMORY_LOST, -313, "Calibration memory lost") \ + XE(SCPI_ERROR_SAVE_RECALL_MEMORY_LOST, -314, "Save/recall memory lost") \ + XE(SCPI_ERROR_CONFIGURATION_MEMORY_LOST, -315, "Configuration memory lost") \ + XE(SCPI_ERROR_STORAGE_FAULT, -320, "Storage fault") \ + XE(SCPI_ERROR_OUT_OF_DEVICE_MEMORY, -321, "Out of memory") \ + XE(SCPI_ERROR_SELF_TEST_FAILED, -330, "Self-test failed") \ + XE(SCPI_ERROR_CALIBRATION_FAILED, -340, "Calibration failed") \ + XE(SCPI_ERROR_QUEUE_OVERFLOW, -350, "Queue overflow") \ + XE(SCPI_ERROR_COMMUNICATION_ERROR, -360, "Communication error") \ + XE(SCPI_ERROR_PARITY_ERROR_IN_CMD_MSG, -361, "Parity error in program message") \ + XE(SCPI_ERROR_FRAMING_ERROR_IN_CMD_MSG, -362, "Framing error in program message") \ + XE(SCPI_ERROR_INPUT_BUFFER_OVERRUN, -363, "Input buffer overrun") \ + XE(SCPI_ERROR_TIME_OUT, -365, "Time out error") \ + XE(SCPI_ERROR_QUERY_ERROR, -400, "Query error") \ + XE(SCPI_ERROR_QUERY_INTERRUPTED, -410, "Query INTERRUPTED") \ + XE(SCPI_ERROR_QUERY_UNTERMINATED, -420, "Query UNTERMINATED") \ + XE(SCPI_ERROR_QUERY_DEADLOCKED, -430, "Query DEADLOCKED") \ + XE(SCPI_ERROR_QUERY_UNTERM_INDEF_RESP, -440, "Query UNTERMINATED after indefinite response") \ + XE(SCPI_ERROR_POWER_ON, -500, "Power on") \ + XE(SCPI_ERROR_USER_REQUEST, -600, "User request") \ + XE(SCPI_ERROR_REQUEST_CONTROL, -700, "Request control") \ + XE(SCPI_ERROR_OPERATION_COMPLETE, -800, "Operation complete") \ enum { #define X(def, val, str) def = val, +#if USE_FULL_ERROR_LIST +#define XE X +#else +#define XE(def, val, str) +#endif LIST_OF_ERRORS + +#if USE_USER_ERROR_LIST +LIST_OF_USER_ERRORS +#endif #undef X +#undef XE }; -#ifdef __cplusplus +#ifdef __cplusplus } #endif -#endif /* SCPI_ERROR_H */ - +#endif /* SCPI_ERROR_H */
--- a/inc/scpi/fifo.h Thu Apr 09 22:42:15 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -/*- - * Copyright (c) 2012-2013 Jan Breuer, - * - * All Rights Reserved - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. 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 AUTHORS ``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 AUTHORS 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 scpi_fifo.h - * @date Thu Nov 15 10:58:45 UTC 2012 - * - * @brief basic FIFO implementation - * - * - */ - -#ifndef SCPI_FIFO_H -#define SCPI_FIFO_H - -#include "scpi/types.h" - -#ifdef __cplusplus -extern "C" { -#endif - - -#define FIFO_SIZE 16 - - struct _fifo_t { - int16_t wr; - int16_t rd; - int16_t size; - int16_t data[FIFO_SIZE]; - }; - typedef struct _fifo_t fifo_t; - - void fifo_init(fifo_t * fifo); - void fifo_clear(fifo_t * fifo); - scpi_bool_t fifo_add(fifo_t * fifo, int16_t value); - scpi_bool_t fifo_remove(fifo_t * fifo, int16_t * value); - scpi_bool_t fifo_count(fifo_t * fifo, int16_t * value); - -#ifdef __cplusplus -} -#endif - -#endif /* SCPI_FIFO_H */
--- a/inc/scpi/ieee488.h Thu Apr 09 22:42:15 2015 +0000 +++ b/inc/scpi/ieee488.h Fri Aug 07 21:54:11 2015 +0000 @@ -82,6 +82,7 @@ void SCPI_RegSet(scpi_t * context, scpi_reg_name_t name, scpi_reg_val_t val); void SCPI_RegSetBits(scpi_t * context, scpi_reg_name_t name, scpi_reg_val_t bits); void SCPI_RegClearBits(scpi_t * context, scpi_reg_name_t name, scpi_reg_val_t bits); + void SCPI_EventClear(scpi_t * context); #ifdef __cplusplus
--- a/inc/scpi/minimal.h Thu Apr 09 22:42:15 2015 +0000 +++ b/inc/scpi/minimal.h Fri Aug 07 21:54:11 2015 +0000 @@ -60,4 +60,3 @@ #endif #endif /* SCPI_MINIMAL_H */ -
--- a/inc/scpi/parser.h Thu Apr 09 22:42:15 2015 +0000 +++ b/inc/scpi/parser.h Fri Aug 07 21:54:11 2015 +0000 @@ -37,37 +37,51 @@ #ifndef SCPI_PARSER_H #define SCPI_PARSER_H +#include <string.h> #include "scpi/types.h" -#include "scpi/debug.h" #ifdef __cplusplus extern "C" { #endif - void SCPI_Init(scpi_t * context); - int SCPI_Input(scpi_t * context, const char * data, size_t len); - int SCPI_Parse(scpi_t * context, char * data, size_t len); + int SCPI_Input(scpi_t * context, const char * data, int len); + int SCPI_Parse(scpi_t * context, char * data, int len); + - scpi_bool_t SCPI_IsCmd(scpi_t * context, const char * cmd); - - size_t SCPI_ResultString(scpi_t * context, const char * data); + size_t SCPI_ResultCharacters(scpi_t * context, const char * data, size_t len); +#define SCPI_ResultMnemonic(context, data) SCPI_ResultCharacters((context), (data), strlen(data)) size_t SCPI_ResultInt(scpi_t * context, int32_t val); + size_t SCPI_ResultIntBase(scpi_t * context, int32_t val, int8_t base); size_t SCPI_ResultDouble(scpi_t * context, double val); size_t SCPI_ResultText(scpi_t * context, const char * data); + size_t SCPI_ResultArbitraryBlock(scpi_t * context, const char * data, size_t len); size_t SCPI_ResultBool(scpi_t * context, scpi_bool_t val); + + scpi_bool_t SCPI_Parameter(scpi_t * context, scpi_parameter_t * parameter, scpi_bool_t mandatory); + scpi_bool_t SCPI_ParamIsNumber(scpi_parameter_t * parameter, scpi_bool_t suffixAllowed); + scpi_bool_t SCPI_ParamToInt(scpi_t * context, scpi_parameter_t * parameter, int32_t * value); + scpi_bool_t SCPI_ParamToDouble(scpi_t * context, scpi_parameter_t * parameter, double * value); + scpi_bool_t SCPI_ParamToChoice(scpi_t * context, scpi_parameter_t * parameter, const scpi_choice_def_t * options, int32_t * value); + scpi_bool_t SCPI_ChoiceToName(const scpi_choice_def_t * options, int32_t tag, const char ** text); + scpi_bool_t SCPI_ParamInt(scpi_t * context, int32_t * value, scpi_bool_t mandatory); scpi_bool_t SCPI_ParamDouble(scpi_t * context, double * value, scpi_bool_t mandatory); - scpi_bool_t SCPI_ParamString(scpi_t * context, const char ** value, size_t * len, scpi_bool_t mandatory); - scpi_bool_t SCPI_ParamText(scpi_t * context, const char ** value, size_t * len, scpi_bool_t mandatory); + scpi_bool_t SCPI_ParamCharacters(scpi_t * context, const char ** value, size_t * len, scpi_bool_t mandatory); + scpi_bool_t SCPI_ParamArbitraryBlock(scpi_t * context, const char ** value, size_t * len, scpi_bool_t mandatory); + scpi_bool_t SCPI_ParamCopyText(scpi_t * context, char * buffer, size_t buffer_len, size_t * copy_len, scpi_bool_t mandatory); + scpi_bool_t SCPI_ParamBool(scpi_t * context, scpi_bool_t * value, scpi_bool_t mandatory); - scpi_bool_t SCPI_ParamChoice(scpi_t * context, const char * options[], int32_t * value, scpi_bool_t mandatory); + scpi_bool_t SCPI_ParamChoice(scpi_t * context, const scpi_choice_def_t * options, int32_t * value, scpi_bool_t mandatory); + scpi_bool_t SCPI_IsCmd(scpi_t * context, const char * cmd); + int32_t SCPI_CmdTag(scpi_t * context); + scpi_bool_t SCPI_Match(const char * pattern, const char * value, size_t len); + scpi_bool_t SCPI_CommandNumbers(scpi_t * context, int32_t * numbers, size_t len); #ifdef __cplusplus } #endif #endif /* SCPI_PARSER_H */ -
--- a/inc/scpi/scpi.h Thu Apr 09 22:42:15 2015 +0000 +++ b/inc/scpi/scpi.h Fri Aug 07 21:54:11 2015 +0000 @@ -43,8 +43,8 @@ #include "scpi/constants.h" #include "scpi/minimal.h" #include "scpi/units.h" +#include "scpi/utils.h" #endif /* SCPI_H */ -
--- a/inc/scpi/types.h Thu Apr 09 22:42:15 2015 +0000 +++ b/inc/scpi/types.h Fri Aug 07 21:54:11 2015 +0000 @@ -4,7 +4,7 @@ * Copyright (c) 2012 Jan Breuer * * All Rights Reserved - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: @@ -13,7 +13,7 @@ * 2. 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 AUTHORS ``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 @@ -30,10 +30,10 @@ /** * @file scpi_types.h * @date Thu Nov 15 10:58:45 UTC 2012 - * + * * @brief SCPI data types - * - * + * + * */ #ifndef SCPI_TYPES_H @@ -41,12 +41,20 @@ #include <stddef.h> #include <stdint.h> +#include "scpi/config.h" + +#if HAVE_STDBOOL #include <stdbool.h> +#endif #ifdef __cplusplus extern "C" { #endif +#if !HAVE_STDBOOL + typedef unsigned char bool; +#endif + #ifndef FALSE #define FALSE 0 #endif @@ -61,13 +69,13 @@ /* IEEE 488.2 registers */ enum _scpi_reg_name_t { SCPI_REG_STB = 0, /* Status Byte */ - SCPI_REG_SRE, /* Service Request Enable Register */ - SCPI_REG_ESR, /* Standard Event Status Register (ESR, SESR) */ - SCPI_REG_ESE, /* Event Status Enable Register */ - SCPI_REG_OPER, /* OPERation Status Register */ - SCPI_REG_OPERE, /* OPERation Status Enable Register */ - SCPI_REG_QUES, /* QUEStionable status register */ - SCPI_REG_QUESE, /* QUEStionable status Enable Register */ + SCPI_REG_SRE, /* Service Request Enable Register */ + SCPI_REG_ESR, /* Standard Event Status Register (ESR, SESR) */ + SCPI_REG_ESE, /* Event Status Enable Register */ + SCPI_REG_OPER, /* OPERation Status Register */ + SCPI_REG_OPERE, /* OPERation Status Enable Register */ + SCPI_REG_QUES, /* QUEStionable status register */ + SCPI_REG_QUESE, /* QUEStionable status Enable Register */ /* last definition - number of registers */ SCPI_REG_COUNT @@ -76,21 +84,21 @@ enum _scpi_ctrl_name_t { SCPI_CTRL_SRQ = 1, /* service request */ - SCPI_CTRL_GTL, /* Go to local */ - SCPI_CTRL_SDC, /* Selected device clear */ - SCPI_CTRL_PPC, /* Parallel poll configure */ - SCPI_CTRL_GET, /* Group execute trigger */ - SCPI_CTRL_TCT, /* Take control */ - SCPI_CTRL_LLO, /* Device clear */ - SCPI_CTRL_DCL, /* Local lockout */ - SCPI_CTRL_PPU, /* Parallel poll unconfigure */ - SCPI_CTRL_SPE, /* Serial poll enable */ - SCPI_CTRL_SPD, /* Serial poll disable */ - SCPI_CTRL_MLA, /* My local address */ - SCPI_CTRL_UNL, /* Unlisten */ - SCPI_CTRL_MTA, /* My talk address */ - SCPI_CTRL_UNT, /* Untalk */ - SCPI_CTRL_MSA /* My secondary address */ + SCPI_CTRL_GTL, /* Go to local */ + SCPI_CTRL_SDC, /* Selected device clear */ + SCPI_CTRL_PPC, /* Parallel poll configure */ + SCPI_CTRL_GET, /* Group execute trigger */ + SCPI_CTRL_TCT, /* Take control */ + SCPI_CTRL_LLO, /* Device clear */ + SCPI_CTRL_DCL, /* Local lockout */ + SCPI_CTRL_PPU, /* Parallel poll unconfigure */ + SCPI_CTRL_SPE, /* Serial poll enable */ + SCPI_CTRL_SPD, /* Serial poll disable */ + SCPI_CTRL_MLA, /* My local address */ + SCPI_CTRL_UNL, /* Unlisten */ + SCPI_CTRL_MTA, /* My talk address */ + SCPI_CTRL_UNT, /* Untalk */ + SCPI_CTRL_MSA /* My secondary address */ }; typedef enum _scpi_ctrl_name_t scpi_ctrl_name_t; @@ -105,37 +113,90 @@ typedef struct _scpi_command_t scpi_command_t; +#define SCPI_CMD_LIST_END {NULL, NULL, 0} + + /* scpi interface */ + typedef struct _scpi_t scpi_t; + typedef struct _scpi_interface_t scpi_interface_t; + struct _scpi_buffer_t { size_t length; size_t position; char * data; }; typedef struct _scpi_buffer_t scpi_buffer_t; - + struct _scpi_const_buffer_t { size_t length; size_t position; const char * data; }; - typedef struct _scpi_const_buffer_t scpi_const_buffer_t; - - struct _scpi_param_list_t { - const scpi_command_t * cmd; - const char * parameters; - size_t length; - scpi_const_buffer_t cmd_raw; - }; - #define SCPI_CMD_LIST_END {NULL, NULL, } - typedef struct _scpi_param_list_t scpi_param_list_t; - - /* scpi interface */ - typedef struct _scpi_t scpi_t; - typedef struct _scpi_interface_t scpi_interface_t; + typedef struct _scpi_const_buffer_t scpi_const_buffer_t; typedef size_t(*scpi_write_t)(scpi_t * context, const char * data, size_t len); typedef scpi_result_t(*scpi_write_control_t)(scpi_t * context, scpi_ctrl_name_t ctrl, scpi_reg_val_t val); typedef int (*scpi_error_callback_t)(scpi_t * context, int_fast16_t error); + /* scpi lexer */ + enum _scpi_token_type_t { + SCPI_TOKEN_COMMA, + SCPI_TOKEN_SEMICOLON, + SCPI_TOKEN_QUESTION, + SCPI_TOKEN_NL, + SCPI_TOKEN_HEXNUM, + SCPI_TOKEN_OCTNUM, + SCPI_TOKEN_BINNUM, + SCPI_TOKEN_PROGRAM_MNEMONIC, + SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA, + SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA_WITH_SUFFIX, + SCPI_TOKEN_SUFFIX_PROGRAM_DATA, + SCPI_TOKEN_ARBITRARY_BLOCK_PROGRAM_DATA, + SCPI_TOKEN_SINGLE_QUOTE_PROGRAM_DATA, + SCPI_TOKEN_DOUBLE_QUOTE_PROGRAM_DATA, + SCPI_TOKEN_PROGRAM_EXPRESSION, + SCPI_TOKEN_COMPOUND_PROGRAM_HEADER, + SCPI_TOKEN_INCOMPLETE_COMPOUND_PROGRAM_HEADER, + SCPI_TOKEN_COMMON_PROGRAM_HEADER, + SCPI_TOKEN_INCOMPLETE_COMMON_PROGRAM_HEADER, + SCPI_TOKEN_COMPOUND_QUERY_PROGRAM_HEADER, + SCPI_TOKEN_COMMON_QUERY_PROGRAM_HEADER, + SCPI_TOKEN_WS, + SCPI_TOKEN_ALL_PROGRAM_DATA, + SCPI_TOKEN_INVALID, + SCPI_TOKEN_UNKNOWN, + }; + typedef enum _scpi_token_type_t scpi_token_type_t; + + struct _scpi_token_t { + scpi_token_type_t type; + char * ptr; + int len; + }; + typedef struct _scpi_token_t scpi_token_t; + + struct _lex_state_t { + char * buffer; + char * pos; + int len; + }; + typedef struct _lex_state_t lex_state_t; + + /* scpi parser */ + enum _message_termination_t { + SCPI_MESSAGE_TERMINATION_NONE, + SCPI_MESSAGE_TERMINATION_NL, + SCPI_MESSAGE_TERMINATION_SEMICOLON, + }; + typedef enum _message_termination_t message_termination_t; + + struct _scpi_parser_state_t { + scpi_token_t programHeader; + scpi_token_t programData; + int numberOfParameters; + message_termination_t termination; + }; + typedef struct _scpi_parser_state_t scpi_parser_state_t; + typedef scpi_result_t(*scpi_command_callback_t)(scpi_t *); /* scpi error queue */ @@ -159,7 +220,7 @@ scpi_unit_t unit; double mult; }; - #define SCPI_UNITS_LIST_END {NULL, SCPI_UNIT_NONE, 0} +#define SCPI_UNITS_LIST_END {NULL, SCPI_UNIT_NONE, 0} typedef struct _scpi_unit_def_t scpi_unit_def_t; enum _scpi_special_number_t { @@ -176,23 +237,43 @@ }; typedef enum _scpi_special_number_t scpi_special_number_t; - struct _scpi_special_number_def_t { + struct _scpi_choice_def_t { const char * name; - scpi_special_number_t type; + int32_t tag; }; - #define SCPI_SPECIAL_NUMBERS_LIST_END {NULL, SCPI_NUM_NUMBER} - typedef struct _scpi_special_number_def_t scpi_special_number_def_t; +#define SCPI_CHOICE_LIST_END {NULL, -1} + typedef struct _scpi_choice_def_t scpi_choice_def_t; + + struct _scpi_param_list_t { + const scpi_command_t * cmd; + lex_state_t lex_state; + scpi_const_buffer_t cmd_raw; + }; + typedef struct _scpi_param_list_t scpi_param_list_t; - struct _scpi_number_t { - double value; + struct _scpi_number_parameter_t { + scpi_bool_t special; + union { + double value; + int32_t tag; + }; scpi_unit_t unit; - scpi_special_number_t type; + int8_t base; }; - typedef struct _scpi_number_t scpi_number_t; + typedef struct _scpi_number_parameter_t scpi_number_t; + + struct _scpi_data_parameter_t { + const char * ptr; + int32_t len; + }; + 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; + int32_t tag; }; struct _scpi_interface_t { @@ -201,13 +282,12 @@ scpi_write_control_t control; scpi_command_callback_t flush; scpi_command_callback_t reset; - scpi_command_callback_t test; }; struct _scpi_t { const scpi_command_t * cmdlist; scpi_buffer_t buffer; - scpi_param_list_t paramlist; + scpi_param_list_t param_list; scpi_interface_t * interface; int_fast16_t output_count; int_fast16_t input_count; @@ -215,8 +295,8 @@ scpi_error_queue_t error_queue; scpi_reg_val_t * registers; const scpi_unit_def_t * units; - const scpi_special_number_def_t * special_numbers; void * user_context; + scpi_parser_state_t parser_state; const char * idn[4]; }; @@ -225,4 +305,3 @@ #endif #endif /* SCPI_TYPES_H */ -
--- a/inc/scpi/units.h Thu Apr 09 22:42:15 2015 +0000 +++ b/inc/scpi/units.h Fri Aug 07 21:54:11 2015 +0000 @@ -44,14 +44,15 @@ #endif extern const scpi_unit_def_t scpi_units_def[]; - extern const scpi_special_number_def_t scpi_special_numbers_def[]; - - scpi_bool_t SCPI_ParamNumber(scpi_t * context, scpi_number_t * value, scpi_bool_t mandatory); - size_t SCPI_NumberToStr(scpi_t * context, scpi_number_t * value, char * str, size_t len); + extern const scpi_choice_def_t scpi_special_numbers_def[]; + + scpi_bool_t SCPI_ParamNumber(scpi_t * context, const scpi_choice_def_t * special, scpi_number_t * value, scpi_bool_t mandatory); + + scpi_bool_t SCPI_ParamTranslateNumberVal(scpi_t * context, scpi_parameter_t * parameter); + size_t SCPI_NumberToStr(scpi_t * context, const scpi_choice_def_t * special, scpi_number_t * value, char * str, size_t len); #ifdef __cplusplus } #endif #endif /* SCPI_UNITS_H */ -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/inc/scpi/utils.h Fri Aug 07 21:54:11 2015 +0000 @@ -0,0 +1,53 @@ +/*- + * Copyright (c) 2012-2015 Jan Breuer, + * + * All Rights Reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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 AUTHORS ``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 AUTHORS 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 utils.h + * + * @brief Conversion routines and string manipulation routines + * + * + */ + +#ifndef SCPI_UTILS_H +#define SCPI_UTILS_H + +#include <stdint.h> +#include "scpi/types.h" + +#ifdef __cplusplus +extern "C" { +#endif + + size_t SCPI_LongToStr(int32_t val, char * str, size_t len, int8_t base); + size_t SCPI_DoubleToStr(double val, char * str, size_t len); + +#ifdef __cplusplus +} +#endif + +#endif /* SCPI_UTILS_H */
--- a/inc/scpi/utils_private.h Thu Apr 09 22:42:15 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,98 +0,0 @@ -/*- - * Copyright (c) 2012-2013 Jan Breuer, - * - * All Rights Reserved - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. 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 AUTHORS ``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 AUTHORS 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 scpi_utils.h - * @date Thu Nov 15 10:58:45 UTC 2012 - * - * @brief Conversion routines and string manipulation routines - * - * - */ - -#ifndef SCPI_UTILS_H -#define SCPI_UTILS_H - -#include <stdint.h> -#include "scpi/config.h" -#include "scpi/types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#if defined(__GNUC__) && (__GNUC__ >= 4) - #define LOCAL __attribute__((visibility ("hidden"))) -#else - #define LOCAL -#endif - - const char * strnpbrk(const char *str, size_t size, const char *set) LOCAL; - scpi_bool_t compareStr(const char * str1, size_t len1, const char * str2, size_t len2) LOCAL; - scpi_bool_t compareStrAndNum(const char * str1, size_t len1, const char * str2, size_t len2) LOCAL; - size_t longToStr(int32_t val, char * str, size_t len) LOCAL; - size_t doubleToStr(double val, char * str, size_t len) LOCAL; - size_t strToLong(const char * str, int32_t * val) LOCAL; - size_t strToDouble(const char * str, double * val) LOCAL; - scpi_bool_t locateText(const char * str1, size_t len1, const char ** str2, size_t * len2) LOCAL; - scpi_bool_t locateStr(const char * str1, size_t len1, const char ** str2, size_t * len2) LOCAL; - size_t skipWhitespace(const char * cmd, size_t len) LOCAL; - size_t skipColon(const char * cmd, size_t len) LOCAL; - scpi_bool_t matchPattern(const char * pattern, size_t pattern_len, const char * str, size_t str_len) LOCAL; - scpi_bool_t matchCommand(const char * pattern, const char * cmd, size_t len) LOCAL; - scpi_bool_t composeCompoundCommand(char * ptr_prev, size_t len_prev, char ** pptr, size_t * plen); - -#if !HAVE_STRNLEN - size_t BSD_strnlen(const char *s, size_t maxlen); -#endif - -#if !HAVE_STRNCASECMP && !HAVE_STRNICMP - int OUR_strncasecmp(const char *s1, const char *s2, size_t n); -#endif - -#define min(a, b) (((a) < (b)) ? (a) : (b)) -#define max(a, b) (((a) > (b)) ? (a) : (b)) - -#if 0 -#define max(a,b) \ - ({ __typeof__ (a) _a = (a); \ - __typeof__ (b) _b = (b); \ - _a > _b ? _a : _b; }) - -#define min(a,b) \ - ({ __typeof__ (a) _a = (a); \ - __typeof__ (b) _b = (b); \ - _a < _b ? _a : _b; }) - -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* SCPI_UTILS_H */ -
--- a/src/error.c Thu Apr 09 22:42:15 2015 +0000 +++ b/src/error.c Fri Aug 07 21:54:11 2015 +0000 @@ -2,7 +2,7 @@ * Copyright (c) 2012-2013 Jan Breuer, * * All Rights Reserved - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: @@ -11,7 +11,7 @@ * 2. 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 AUTHORS ``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 @@ -28,10 +28,10 @@ /** * @file scpi_error.c * @date Thu Nov 15 10:58:45 UTC 2012 - * + * * @brief Error handling and storing routines - * - * + * + * */ #include <stdint.h> @@ -39,13 +39,16 @@ #include "scpi/parser.h" #include "scpi/ieee488.h" #include "scpi/error.h" -#include "scpi/fifo.h" +#include "fifo_private.h" /* basic FIFO */ -static fifo_t local_error_queue; +static scpi_fifo_t local_error_queue; - +/** + * Initialize error queue + * @param context - scpi context + */ void SCPI_ErrorInit(scpi_t * context) { /* * // FreeRTOS @@ -54,7 +57,34 @@ /* basic FIFO */ context->error_queue = (scpi_error_queue_t)&local_error_queue; - fifo_init((fifo_t *)context->error_queue); + fifo_init((scpi_fifo_t *)context->error_queue); +} + +/** + * Emit no error + * @param context scpi context + */ +static void SCPI_ErrorEmitEmpty(scpi_t * context) { + if ((SCPI_ErrorCount(context) == 0) && (SCPI_RegGet(context, SCPI_REG_STB) & STB_QMA)) { + SCPI_RegClearBits(context, SCPI_REG_STB, STB_QMA); + + if (context->interface && context->interface->error) { + context->interface->error(context, 0); + } + } +} + +/** + * Emit error + * @param context scpi context + * @param err Error to emit + */ +static void SCPI_ErrorEmit(scpi_t * context, int16_t err) { + SCPI_RegSetBits(context, SCPI_REG_STB, STB_QMA); + + if (context->interface && context->interface->error) { + context->interface->error(context, err); + } } /** @@ -68,7 +98,9 @@ */ /* basic FIFO */ - fifo_clear((fifo_t *)context->error_queue); + fifo_clear((scpi_fifo_t *)context->error_queue); + + SCPI_ErrorEmitEmpty(context); } /** @@ -87,7 +119,9 @@ */ /* basic FIFO */ - fifo_remove((fifo_t *)context->error_queue, &result); + fifo_remove((scpi_fifo_t *)context->error_queue, &result); + + SCPI_ErrorEmitEmpty(context); return result; } @@ -95,7 +129,7 @@ /** * Return number of errors/events in the queue * @param context - * @return + * @return */ int32_t SCPI_ErrorCount(scpi_t * context) { int16_t result = 0; @@ -106,7 +140,7 @@ */ /* basic FIFO */ - fifo_count((fifo_t *)context->error_queue, &result); + fifo_count((scpi_fifo_t *)context->error_queue, &result); return result; } @@ -118,7 +152,7 @@ */ /* basic FIFO */ - fifo_add((fifo_t *)context->error_queue, err); + fifo_add((scpi_fifo_t *)context->error_queue, err); } struct error_reg { @@ -127,12 +161,13 @@ scpi_reg_val_t bit; }; -#define ERROR_DEFS_N 8 +#define ERROR_DEFS_N 9 static const struct error_reg errs[ERROR_DEFS_N] = { {-100, -199, ESR_CER}, /* Command error (e.g. syntax error) ch 21.8.9 */ {-200, -299, ESR_EER}, /* Execution Error (e.g. range error) ch 21.8.10 */ {-300, -399, ESR_DER}, /* Device specific error -300, -399 ch 21.8.11 */ + { 1,32767, ESR_DER}, /* Device designer provided specific error 1, 32767 ch 21.8.11 */ {-400, -499, ESR_QER}, /* Query error -400, -499 ch 21.8.12 */ {-500, -599, ESR_PON}, /* Power on event -500, -599 ch 21.8.13 */ {-600, -699, ESR_URQ}, /* User Request Event -600, -699 ch 21.8.14 */ @@ -157,11 +192,9 @@ } } + SCPI_ErrorEmit(context, err); + if (context) { - if (context->interface && context->interface->error) { - context->interface->error(context, err); - } - context->cmd_error = TRUE; } } @@ -174,11 +207,19 @@ const char * SCPI_ErrorTranslate(int16_t err) { switch (err) { case 0: return "No error"; - #define X(def, val, str) case def: return str; - LIST_OF_ERRORS - #undef X +#define X(def, val, str) case def: return str; +#if USE_FULL_ERROR_LIST +#define XE X +#else +#define XE(def, val, str) +#endif +LIST_OF_ERRORS + +#if USE_USER_ERROR_LIST +LIST_OF_USER_ERRORS +#endif +#undef X +#undef XE default: return "Unknown error"; } } - -
--- a/src/fifo.c Thu Apr 09 22:42:15 2015 +0000 +++ b/src/fifo.c Fri Aug 07 21:54:11 2015 +0000 @@ -1,18 +1,32 @@ -#include "scpi/fifo.h" +#include "fifo_private.h" -void fifo_init(fifo_t * fifo) { +/** + * Initialize fifo + * @param fifo + */ +void fifo_init(scpi_fifo_t * fifo) { fifo->wr = 0; fifo->rd = 0; fifo->size = FIFO_SIZE; } -void fifo_clear(fifo_t * fifo) { +/** + * Empty fifo + * @param fifo + */ +void fifo_clear(scpi_fifo_t * fifo) { fifo->wr = 0; fifo->rd = 0; } -scpi_bool_t fifo_add(fifo_t * fifo, int16_t value) { +/** + * Add element to fifo. If fifo is full, remove last element. + * @param fifo + * @param value + * @return + */ +scpi_bool_t fifo_add(scpi_fifo_t * fifo, int16_t value) { /* FIFO full? */ if (fifo->wr == ((fifo->rd + fifo->size) % (fifo->size + 1))) { fifo_remove(fifo, NULL); @@ -24,7 +38,13 @@ return TRUE; } -scpi_bool_t fifo_remove(fifo_t * fifo, int16_t * value) { +/** + * Remove element form fifo + * @param fifo + * @param value + * @return FALSE - fifo is empty + */ +scpi_bool_t fifo_remove(scpi_fifo_t * fifo, int16_t * value) { /* FIFO empty? */ if (fifo->wr == fifo->rd) { return FALSE; @@ -39,7 +59,13 @@ return TRUE; } -scpi_bool_t fifo_count(fifo_t * fifo, int16_t * value) { +/** + * Retrive number of elements in fifo + * @param fifo + * @param value + * @return + */ +scpi_bool_t fifo_count(scpi_fifo_t * fifo, int16_t * value) { *value = fifo->wr - fifo->rd; if (*value < 0) { *value += (fifo->size + 1);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/fifo_private.h Fri Aug 07 21:54:11 2015 +0000 @@ -0,0 +1,68 @@ +/*- + * Copyright (c) 2012-2013 Jan Breuer, + * + * All Rights Reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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 AUTHORS ``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 AUTHORS 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 scpi_fifo.h + * @date Thu Nov 15 10:58:45 UTC 2012 + * + * @brief basic FIFO implementation + * + * + */ + +#ifndef SCPI_FIFO_H +#define SCPI_FIFO_H + +#include "scpi/types.h" +#include "utils_private.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +#define FIFO_SIZE 16 + + struct _scpi_fifo_t { + int16_t wr; + int16_t rd; + int16_t size; + int16_t data[FIFO_SIZE]; + }; + typedef struct _scpi_fifo_t scpi_fifo_t; + + void fifo_init(scpi_fifo_t * fifo) LOCAL; + void fifo_clear(scpi_fifo_t * fifo) LOCAL; + scpi_bool_t fifo_add(scpi_fifo_t * fifo, int16_t value) LOCAL; + scpi_bool_t fifo_remove(scpi_fifo_t * fifo, int16_t * value) LOCAL; + scpi_bool_t fifo_count(scpi_fifo_t * fifo, int16_t * value) LOCAL; + +#ifdef __cplusplus +} +#endif + +#endif /* SCPI_FIFO_H */
--- a/src/ieee488.c Thu Apr 09 22:42:15 2015 +0000 +++ b/src/ieee488.c Fri Aug 07 21:54:11 2015 +0000 @@ -212,7 +212,7 @@ scpi_result_t SCPI_CoreEse(scpi_t * context) { int32_t new_ESE; if (SCPI_ParamInt(context, &new_ESE, TRUE)) { - SCPI_RegSet(context, SCPI_REG_ESE, new_ESE); + SCPI_RegSet(context, SCPI_REG_ESE, (scpi_reg_val_t)new_ESE); } return SCPI_RES_OK; } @@ -250,10 +250,14 @@ * @return */ scpi_result_t SCPI_CoreIdnQ(scpi_t * context) { - SCPI_ResultString(context, context->idn[0]); - SCPI_ResultString(context, context->idn[1]); - SCPI_ResultString(context, context->idn[2]); - SCPI_ResultString(context, context->idn[3]); + int i; + for (i = 0; i<4; i++) { + if (context->idn[i]) { + SCPI_ResultMnemonic(context, context->idn[i]); + } else { + SCPI_ResultMnemonic(context, "0"); + } + } return SCPI_RES_OK; } @@ -298,7 +302,7 @@ scpi_result_t SCPI_CoreSre(scpi_t * context) { int32_t new_SRE; if (SCPI_ParamInt(context, &new_SRE, TRUE)) { - SCPI_RegSet(context, SCPI_REG_SRE, new_SRE); + SCPI_RegSet(context, SCPI_REG_SRE, (scpi_reg_val_t)new_SRE); } return SCPI_RES_OK; } @@ -329,11 +333,8 @@ * @return */ scpi_result_t SCPI_CoreTstQ(scpi_t * context) { - int result = 0; - if (context && context->interface && context->interface->test) { - result = context->interface->test(context); - } - SCPI_ResultInt(context, result); + (void) context; + SCPI_ResultInt(context, 0); return SCPI_RES_OK; } @@ -347,4 +348,3 @@ /* NOP */ return SCPI_RES_OK; } -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lexer.c Fri Aug 07 21:54:11 2015 +0000 @@ -0,0 +1,890 @@ +/*- + * Copyright (c) 2012-2013 Jan Breuer, + * + * All Rights Reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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 AUTHORS ``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 AUTHORS 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 lexer.c + * @date Wed Mar 20 19:35:19 UTC 2013 + * + * @brief SCPI Lexer + * + * + */ + +#include <ctype.h> +#include <stdio.h> +#include <string.h> + +#include "lexer_private.h" +#include "scpi/error.h" + +/** + * Is white space + * @param c + * @return + */ +static int isws(int c) { + if ((c == ' ') || (c == '\t')) { + return 1; + } + return 0; +} + +/** + * Is binary digit + * @param c + * @return + */ +static int isbdigit(int c) { + if ((c == '0') || (c == '1')) { + return 1; + } + return 0; +} + +/** + * Is hexadecimal digit + * @param c + * @return + */ +static int isqdigit(int c) { + if ((c == '0') || (c == '1') || (c == '2') || (c == '3') || (c == '4') || (c == '5') || (c == '6') || (c == '7')) { + return 1; + } + return 0; +} + +/** + * Is end of string + * @param state + * @return + */ +static int iseos(lex_state_t * state) { + if ((state->buffer + state->len) <= (state->pos)) { + return 1; + } else { + return 0; + } +} + +/** + * Private export of iseos + * @param state + * @return + */ +int scpiLex_IsEos(lex_state_t * state) { + return iseos(state); +} + +/** + * Test current character + * @param state + * @param chr + * @return + */ +static int ischr(lex_state_t * state, char chr) { + return (state->pos[0] == chr); +} + +/** + * Is plus or minus + * @param c + * @return + */ +static int isplusmn(int c) { + return c == '+' || c == '-'; +} + +/** + * Is letter H + * @param c + * @return + */ +static int isH(int c) { + return c == 'h' || c == 'H'; +} + +/** + * Is letter B + * @param c + * @return + */ +static int isB(int c) { + return c == 'b' || c == 'B'; +} + +/** + * Is letter Q + * @param c + * @return + */ +static int isQ(int c) { + return c == 'q' || c == 'Q'; +} + +/** + * Is letter E + * @param c + * @return + */ +static int isE(int c) { + return c == 'e' || c == 'E'; +} + +#define SKIP_NONE 0 +#define SKIP_OK 1 +#define SKIP_INCOMPLETE -1 + +/* skip characters */ +/* 7.4.1 <PROGRAM MESSAGE UNIT SEPARATOR>*/ +// TODO: static int skipProgramMessageUnitSeparator(lex_state_t * state) + +/** + * Skip all whitespaces + * @param state + * @return + */ +static int skipWs(lex_state_t * state) { + int someSpace = 0; + while (!iseos(state) && isws(state->pos[0])) { + state->pos++; + someSpace++; + } + + return someSpace; +} + +/* 7.4.2 <PROGRAM DATA SEPARATOR> */ +// static int skipProgramDataSeparator(lex_state_t * state) + +/* 7.5.2 <PROGRAM MESSAGE TERMINATOR> */ +// static int skipProgramMessageTerminator(lex_state_t * state) + +/** + * Skip decimal digit + * @param state + * @return + */ +static int skipDigit(lex_state_t * state) { + if (!iseos(state) && isdigit(state->pos[0])) { + state->pos++; + return SKIP_OK; + } else { + return SKIP_NONE; + } +} + +/** + * Skip multiple decimal digits + * @param state + * @return + */ +static int skipNumbers(lex_state_t * state) { + int someNumbers = 0; + while (!iseos(state) && isdigit(state->pos[0])) { + state->pos++; + someNumbers++; + } + return someNumbers; +} + +/** + * Skip plus or minus + * @param state + * @return + */ +static int skipPlusmn(lex_state_t * state) { + if (!iseos(state) && isplusmn(state->pos[0])) { + state->pos++; + return SKIP_OK; + } else { + return SKIP_NONE; + } +} + +/** + * Skip any character from 'a'-'Z' + * @param state + * @return + */ +static int skipAlpha(lex_state_t * state) { + int someLetters = 0; + while (!iseos(state) && isalpha(state->pos[0])) { + state->pos++; + someLetters++; + } + return someLetters; +} + +/** + * Skip exact character chr or nothing + * @param state + * @param chr + * @return + */ +static int skipChr(lex_state_t * state, char chr) { + if (!iseos(state) && ischr(state, chr)) { + state->pos++; + return SKIP_OK; + } else { + return SKIP_NONE; + } +} + +/** + * Skip slash or dot + * @param state + * @return + */ +static int skipSlashDot(lex_state_t * state) { + if (!iseos(state) && (ischr(state, '/') | ischr(state, '.'))) { + state->pos++; + return SKIP_OK; + } else { + return SKIP_NONE; + } +} + +/** + * Skip star + * @param state + * @return + */ +static int skipStar(lex_state_t * state) { + if (!iseos(state) && ischr(state, '*')) { + state->pos++; + return SKIP_OK; + } else { + return SKIP_NONE; + } +} + +/** + * Skip colon + * @param state + * @return + */ +static int skipColon(lex_state_t * state) { + if (!iseos(state) && ischr(state, ':')) { + state->pos++; + return SKIP_OK; + } else { + return SKIP_NONE; + } +} + +/* 7.6.1.2 <COMMAND PROGRAM HEADER> */ + +/** + * Skip program mnemonic [a-z][a-z0-9_]* + * @param state + * @return + */ +static int skipProgramMnemonic(lex_state_t * state) { + const char * startPos = state->pos; + if (!iseos(state) && isalpha(state->pos[0])) { + state->pos++; + while (!iseos(state) && (isalnum(state->pos[0]) || ischr(state, '_'))) { + state->pos++; + } + } + + if (iseos(state)) { + return (state->pos - startPos) * SKIP_INCOMPLETE; + } else { + return (state->pos - startPos) * SKIP_OK; + } +} + +/* tokens */ + +/** + * Detect token white space + * @param state + * @param token + * @return + */ +int scpiLex_WhiteSpace(lex_state_t * state, scpi_token_t * token) { + token->ptr = state->pos; + + skipWs(state); + + token->len = state->pos - token->ptr; + + if (token->len > 0) { + token->type = SCPI_TOKEN_WS; + } else { + token->type = SCPI_TOKEN_UNKNOWN; + } + + return token->len; +} + +/* 7.6.1 <COMMAND PROGRAM HEADER> */ + +/** + * Skip command program header \*<PROGRAM MNEMONIC> + * @param state + * @return + */ +static int skipCommonProgramHeader(lex_state_t * state) { + int res; + if (skipStar(state)) { + res = skipProgramMnemonic(state); + if (res == SKIP_NONE && iseos(state)) { + return SKIP_INCOMPLETE; + } else if (res <= SKIP_INCOMPLETE) { + return SKIP_OK; + } else if (res >= SKIP_OK) { + return SKIP_OK; + } else { + return SKIP_INCOMPLETE; + } + } + return SKIP_NONE; +} + +/** + * Skip compound program header :<PROGRAM MNEMONIC>:<PROGRAM MNEMONIC>... + * @param state + * @return + */ +static int skipCompoundProgramHeader(lex_state_t * state) { + int res; + int firstColon = skipColon(state); + + res = skipProgramMnemonic(state); + if (res >= SKIP_OK) { + while (skipColon(state)) { + res = skipProgramMnemonic(state); + if (res <= SKIP_INCOMPLETE) { + return SKIP_OK; + } else if (res == SKIP_NONE) { + return SKIP_INCOMPLETE; + } + } + return SKIP_OK; + } else if (res <= SKIP_INCOMPLETE) { + return SKIP_OK; + } else if (firstColon) { + return SKIP_INCOMPLETE; + } else { + return SKIP_NONE; + } +} + +/** + * Detect token command or compound program header + * @param state + * @param token + * @return + */ +int scpiLex_ProgramHeader(lex_state_t * state, scpi_token_t * token) { + int res; + token->ptr = state->pos; + token->type = SCPI_TOKEN_UNKNOWN; + + res = skipCommonProgramHeader(state); + if (res >= SKIP_OK) { + if (skipChr(state, '?') >= SKIP_OK) { + token->type = SCPI_TOKEN_COMMON_QUERY_PROGRAM_HEADER; + } else { + token->type = SCPI_TOKEN_COMMON_PROGRAM_HEADER; + } + } else if (res <= SKIP_INCOMPLETE) { + token->type = SCPI_TOKEN_INCOMPLETE_COMMON_PROGRAM_HEADER; + } else if (res == SKIP_NONE) { + res = skipCompoundProgramHeader(state); + + if (res >= SKIP_OK) { + if (skipChr(state, '?') >= SKIP_OK) { + token->type = SCPI_TOKEN_COMPOUND_QUERY_PROGRAM_HEADER; + } else { + token->type = SCPI_TOKEN_COMPOUND_PROGRAM_HEADER; + } + } else if (res <= SKIP_INCOMPLETE) { + token->type = SCPI_TOKEN_INCOMPLETE_COMPOUND_PROGRAM_HEADER; + } + } + + if (token->type != SCPI_TOKEN_UNKNOWN) { + token->len = state->pos - token->ptr; + } else { + token->len = 0; + state->pos = token->ptr; + } + + return token->len; +} + +/* 7.7.1 <CHARACTER PROGRAM DATA> */ + +/** + * Detect token "Character program data" + * @param state + * @param token + * @return + */ +int scpiLex_CharacterProgramData(lex_state_t * state, scpi_token_t * token) { + token->ptr = state->pos; + + if (!iseos(state) && isalpha(state->pos[0])) { + state->pos++; + while (!iseos(state) && (isalnum(state->pos[0]) || ischr(state, '_'))) { + state->pos++; + } + } + + token->len = state->pos - token->ptr; + if (token->len > 0) { + token->type = SCPI_TOKEN_PROGRAM_MNEMONIC; + } else { + token->type = SCPI_TOKEN_UNKNOWN; + } + + return token->len; +} + +/* 7.7.2 <DECIMAL NUMERIC PROGRAM DATA> */ +static int skipMantisa(lex_state_t * state) { + int someNumbers = 0; + + skipPlusmn(state); + + someNumbers += skipNumbers(state); + + if (skipChr(state, '.')) { + someNumbers += skipNumbers(state); + } + + return someNumbers; +} + +static int skipExponent(lex_state_t * state) { + int someNumbers = 0; + + if (!iseos(state) && isE(state->pos[0])) { + state->pos++; + + skipWs(state); + + skipPlusmn(state); + + someNumbers = skipNumbers(state); + } + + return someNumbers; +} + +/** + * Detect token Decimal number + * @param state + * @param token + * @return + */ +int scpiLex_DecimalNumericProgramData(lex_state_t * state, scpi_token_t * token) { + char * rollback; + token->ptr = state->pos; + + if (skipMantisa(state)) { + rollback = state->pos; + skipWs(state); + if (!skipExponent(state)) { + state->pos = rollback; + } + } else { + state->pos = token->ptr; + } + + token->len = state->pos - token->ptr; + if (token->len > 0) { + token->type = SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA; + } else { + token->type = SCPI_TOKEN_UNKNOWN; + } + + return token->len; +} + +/* 7.7.3 <SUFFIX PROGRAM DATA> */ +int scpiLex_SuffixProgramData(lex_state_t * state, scpi_token_t * token) { + token->ptr = state->pos; + + skipChr(state, '/'); + + // TODO: strict parsing : SLASH? (ALPHA+ (MINUS? DIGIT)?) ((SLASH | DOT) (ALPHA+ (MINUS? DIGIT)?))* + if (skipAlpha(state)) { + skipChr(state, '-'); + skipDigit(state); + + while (skipSlashDot(state)) { + skipAlpha(state); + skipChr(state, '-'); + skipDigit(state); + } + } + + token->len = state->pos - token->ptr; + if ((token->len > 0)) { + token->type = SCPI_TOKEN_SUFFIX_PROGRAM_DATA; + } else { + token->type = SCPI_TOKEN_UNKNOWN; + state->pos = token->ptr; + token->len = 0; + } + + return token->len; +} + +/* 7.7.4 <NONDECIMAL NUMERIC PROGRAM DATA> */ +static int skipHexNum(lex_state_t * state) { + int someNumbers = 0; + while (!iseos(state) && isxdigit(state->pos[0])) { + state->pos++; + someNumbers++; + } + return someNumbers; +} + +static int skipOctNum(lex_state_t * state) { + int someNumbers = 0; + while (!iseos(state) && isqdigit(state->pos[0])) { + state->pos++; + someNumbers++; + } + return someNumbers; +} + +static int skipBinNum(lex_state_t * state) { + int someNumbers = 0; + while (!iseos(state) && isbdigit(state->pos[0])) { + state->pos++; + someNumbers++; + } + return someNumbers; +} + +/** + * Detect token nondecimal number + * @param state + * @param token + * @return + */ +int scpiLex_NondecimalNumericData(lex_state_t * state, scpi_token_t * token) { + int someNumbers = 0; + token->ptr = state->pos; + if (skipChr(state, '#')) { + if (!iseos(state)) { + if (isH(state->pos[0])) { + state->pos++; + someNumbers = skipHexNum(state); + token->type = SCPI_TOKEN_HEXNUM; + } else if (isQ(state->pos[0])) { + state->pos++; + someNumbers = skipOctNum(state); + token->type = SCPI_TOKEN_OCTNUM; + } else if (isB(state->pos[0])) { + state->pos++; + someNumbers = skipBinNum(state); + token->type = SCPI_TOKEN_BINNUM; + } + } + } + + if (someNumbers) { + token->ptr += 2; // ignore number prefix + token->len = state->pos - token->ptr; + } else { + token->type = SCPI_TOKEN_UNKNOWN; + state->pos = token->ptr; + token->len = 0; + } + return token->len > 0 ? token->len + 2 : 0; +} + +/* 7.7.5 <STRING PROGRAM DATA> */ +static int isascii7bit(int c) { + return (c >= 0) && (c <= 0x7f); +} + +static void skipQuoteProgramData(lex_state_t * state, char quote) { + while (!iseos(state)) { + if (isascii7bit(state->pos[0]) && !ischr(state, quote)) { + state->pos++; + } else if (ischr(state, quote)) { + state->pos++; + if (!iseos(state) && ischr(state, quote)) { + state->pos++; + } else { + state->pos--; + break; + } + } + } +} + +static void skipDoubleQuoteProgramData(lex_state_t * state) { + skipQuoteProgramData(state, '"'); +} + +static void skipSingleQuoteProgramData(lex_state_t * state) { + skipQuoteProgramData(state, '\''); +} + +/** + * Detect token String data + * @param state + * @param token + * @return + */ +int scpiLex_StringProgramData(lex_state_t * state, scpi_token_t * token) { + token->ptr = state->pos; + + if (!iseos(state)) { + if (ischr(state, '"')) { + state->pos++; + token->type = SCPI_TOKEN_DOUBLE_QUOTE_PROGRAM_DATA; + skipDoubleQuoteProgramData(state); + if (!iseos(state) && ischr(state, '"')) { + state->pos++; + token->len = state->pos - token->ptr; + } else { + state->pos = token->ptr; + } + } else if (ischr(state, '\'')) { + state->pos++; + token->type = SCPI_TOKEN_SINGLE_QUOTE_PROGRAM_DATA; + skipSingleQuoteProgramData(state); + if (!iseos(state) && ischr(state, '\'')) { + state->pos++; + token->len = state->pos - token->ptr; + } else { + state->pos = token->ptr; + } + } + } + + token->len = state->pos - token->ptr; + + if ((token->len > 0)) { + token->ptr++; + token->len -= 2; + } else { + token->type = SCPI_TOKEN_UNKNOWN; + state->pos = token->ptr; + token->len = 0; + } + + return token->len > 0 ? token->len + 2 : 0; +} + +/* 7.7.6 <ARBITRARY BLOCK PROGRAM DATA> */ +static int isNonzeroDigit(int c) { + return isdigit(c) && (c != '0'); +} + +/** + * Detect token Block Data + * @param state + * @param token + * @return + */ +int scpiLex_ArbitraryBlockProgramData(lex_state_t * state, scpi_token_t * token) { + int i; + int arbitraryBlockLength = 0; + const char * ptr = state->pos; + int validData = -1; + token->ptr = state->pos; + + if (skipChr(state, '#')) { + if (!iseos(state) && isNonzeroDigit(state->pos[0])) { + /* Get number of digits */ + i = state->pos[0] - '0'; + state->pos++; + + for (; i > 0; i--) { + if (!iseos(state) && isdigit(state->pos[0])) { + arbitraryBlockLength *= 10; + arbitraryBlockLength += (state->pos[0] - '0'); + state->pos++; + } else { + break; + } + } + + if (i == 0) { + state->pos += arbitraryBlockLength; + if ((state->buffer + state->len) >= (state->pos)) { + token->ptr = state->pos - arbitraryBlockLength; + token->len = arbitraryBlockLength; + validData = 1; + } + } else if (iseos(state)) { + validData = 0; + } + } else if (iseos(state)) { + validData = 0; + } + } + + if (validData == 1) { + // valid + token->type = SCPI_TOKEN_ARBITRARY_BLOCK_PROGRAM_DATA; + } else if (validData == 0) { + // incomplete + token->type = SCPI_TOKEN_UNKNOWN; + token->len = 0; + state->pos = state->buffer + state->len; + } else { + // invalid + token->type = SCPI_TOKEN_UNKNOWN; + state->pos = token->ptr; + token->len = 0; + } + + return token->len + (token->ptr - ptr); +} + +/* 7.7.7 <EXPRESSION PROGRAM DATA> */ +static int isProgramExpression(int c) { + if ((c >= 0x20) && (c <= 0x7e)) { + if ((c != 0x22) + && (c != 0x23) + && (c != 0x27) + && (c != 0x28) + && (c != 0x29) + && (c != 0x3B)) { + return 1; + } + } + + return 0; +} + +static void skipProgramExpression(lex_state_t * state) { + while (!iseos(state) && isProgramExpression(state->pos[0])) { + state->pos++; + } +} + +// TODO: 7.7.7.2-2 recursive - any program data + +/** + * Detect token Expression + * @param state + * @param token + * @return + */ +int scpiLex_ProgramExpression(lex_state_t * state, scpi_token_t * token) { + token->ptr = state->pos; + + if (!iseos(state) && ischr(state, '(')) { + state->pos++; + skipProgramExpression(state); + + if (!iseos(state) && ischr(state, ')')) { + state->pos++; + token->len = state->pos - token->ptr; + } else { + token->len = 0; + } + } + + if ((token->len > 0)) { + token->type = SCPI_TOKEN_PROGRAM_EXPRESSION; + } else { + token->type = SCPI_TOKEN_UNKNOWN; + state->pos = token->ptr; + token->len = 0; + } + + return token->len; +} + +/** + * Detect token comma + * @param state + * @param token + * @return + */ +int scpiLex_Comma(lex_state_t * state, scpi_token_t * token) { + token->ptr = state->pos; + + if (skipChr(state, ',')) { + token->len = 1; + token->type = SCPI_TOKEN_COMMA; + } else { + token->len = 0; + token->type = SCPI_TOKEN_UNKNOWN; + } + + return token->len; +} + +/** + * Detect token semicolon + * @param state + * @param token + * @return + */ +int scpiLex_Semicolon(lex_state_t * state, scpi_token_t * token) { + token->ptr = state->pos; + + if (skipChr(state, ';')) { + token->len = 1; + token->type = SCPI_TOKEN_SEMICOLON; + } else { + token->len = 0; + token->type = SCPI_TOKEN_UNKNOWN; + } + + return token->len; +} + +/** + * Detect token New line + * @param state + * @param token + * @return + */ +int scpiLex_NewLine(lex_state_t * state, scpi_token_t * token) { + token->ptr = state->pos; + + skipChr(state, '\r'); + skipChr(state, '\n'); + + token->len = state->pos - token->ptr; + + if ((token->len > 0)) { + token->type = SCPI_TOKEN_NL; + } else { + token->type = SCPI_TOKEN_UNKNOWN; + state->pos = token->ptr; + token->len = 0; + } + + return token->len; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lexer_private.h Fri Aug 07 21:54:11 2015 +0000 @@ -0,0 +1,65 @@ +/*- + * Copyright (c) 2012-2013 Jan Breuer, + * + * All Rights Reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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 AUTHORS ``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 AUTHORS 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 lexer.h + * @date Thu Mar 21 15:00:58 UTC 2013 + * + * @brief SCPI Lexer + * + * + */ + +#ifndef SCPI_LEXER_H +#define SCPI_LEXER_H + +#include "scpi/types.h" +#include "utils_private.h" + +#ifdef __cplusplus +extern "C" { +#endif + + int scpiLex_IsEos(lex_state_t * state) LOCAL; + int scpiLex_WhiteSpace(lex_state_t * state, scpi_token_t * token) LOCAL; + int scpiLex_ProgramHeader(lex_state_t * state, scpi_token_t * token) LOCAL; + int scpiLex_CharacterProgramData(lex_state_t * state, scpi_token_t * token) LOCAL; + int scpiLex_DecimalNumericProgramData(lex_state_t * state, scpi_token_t * token) LOCAL; + int scpiLex_SuffixProgramData(lex_state_t * state, scpi_token_t * token) LOCAL; + int scpiLex_NondecimalNumericData(lex_state_t * state, scpi_token_t * token) LOCAL; + int scpiLex_StringProgramData(lex_state_t * state, scpi_token_t * token) LOCAL; + int scpiLex_ArbitraryBlockProgramData(lex_state_t * state, scpi_token_t * token) LOCAL; + int scpiLex_ProgramExpression(lex_state_t * state, scpi_token_t * token) LOCAL; + int scpiLex_Comma(lex_state_t * state, scpi_token_t * token) LOCAL; + int scpiLex_Semicolon(lex_state_t * state, scpi_token_t * token) LOCAL; + int scpiLex_NewLine(lex_state_t * state, scpi_token_t * token) LOCAL; + +#ifdef __cplusplus +} +#endif + +#endif /* SCPI_LEXER_H */
--- a/src/minimal.c Thu Apr 09 22:42:15 2015 +0000 +++ b/src/minimal.c Fri Aug 07 21:54:11 2015 +0000 @@ -57,7 +57,7 @@ * @return */ scpi_result_t SCPI_StubQ(scpi_t * context) { - SCPI_ResultString(context, ""); + SCPI_ResultInt(context, 0); return SCPI_RES_OK; } @@ -67,7 +67,7 @@ * @return */ scpi_result_t SCPI_SystemVersionQ(scpi_t * context) { - SCPI_ResultString(context, SCPI_STD_VERSION_REVISION); + SCPI_ResultMnemonic(context, SCPI_STD_VERSION_REVISION); return SCPI_RES_OK; } @@ -131,7 +131,7 @@ scpi_result_t SCPI_StatusQuestionableEnable(scpi_t * context) { int32_t new_QUESE; if (SCPI_ParamInt(context, &new_QUESE, TRUE)) { - SCPI_RegSet(context, SCPI_REG_QUESE, new_QUESE); + SCPI_RegSet(context, SCPI_REG_QUESE, (scpi_reg_val_t)new_QUESE); } return SCPI_RES_OK; }
--- a/src/parser.c Thu Apr 09 22:42:15 2015 +0000 +++ b/src/parser.c Fri Aug 07 21:54:11 2015 +0000 @@ -2,7 +2,7 @@ * Copyright (c) 2012-2013 Jan Breuer, * * All Rights Reserved - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: @@ -11,7 +11,7 @@ * 2. 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 AUTHORS ``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 @@ -28,10 +28,10 @@ /** * @file scpi_parser.c * @date Thu Nov 15 10:58:45 UTC 2012 - * + * * @brief SCPI parser implementation - * - * + * + * */ #include <ctype.h> @@ -39,103 +39,11 @@ #include "scpi/config.h" #include "scpi/parser.h" -#include "scpi/utils_private.h" +#include "parser_private.h" +#include "lexer_private.h" #include "scpi/error.h" #include "scpi/constants.h" - - -static size_t cmdTerminatorPos(const char * cmd, size_t len); -static size_t cmdlineSeparatorPos(const char * cmd, size_t len); -static const char * cmdlineSeparator(const char * cmd, size_t len); -static const char * cmdlineTerminator(const char * cmd, size_t len); -static size_t skipCmdLine(const char * cmd, size_t len); - -static void paramSkipBytes(scpi_t * context, size_t num); -static void paramSkipWhitespace(scpi_t * context); -static scpi_bool_t paramNext(scpi_t * context, scpi_bool_t mandatory); - -/* -int _strnicmp(const char* s1, const char* s2, size_t len) { - int result = 0; - int i; - - for (i = 0; i < len && s1[i] && s2[i]; i++) { - char c1 = tolower(s1[i]); - char c2 = tolower(s2[i]); - if (c1 != c2) { - result = (int) c1 - (int) c2; - break; - } - } - - return result; -} - */ - -/** - * Find command termination character - * @param cmd - input command - * @param len - max search length - * @return position of terminator or len - */ -size_t cmdTerminatorPos(const char * cmd, size_t len) { - const char * terminator = strnpbrk(cmd, len, "; \r\n\t"); - if (terminator == NULL) { - return len; - } else { - return terminator - cmd; - } -} - -/** - * Find command line separator - * @param cmd - input command - * @param len - max search length - * @return pointer to line separator or NULL - */ -const char * cmdlineSeparator(const char * cmd, size_t len) { - return strnpbrk(cmd, len, ";\r\n"); -} - -/** - * Find command line terminator - * @param cmd - input command - * @param len - max search length - * @return pointer to command line terminator or NULL - */ -const char * cmdlineTerminator(const char * cmd, size_t len) { - return strnpbrk(cmd, len, "\r\n"); -} - -/** - * Find command line separator position - * @param cmd - input command - * @param len - max search length - * @return position of line separator or len - */ -size_t cmdlineSeparatorPos(const char * cmd, size_t len) { - const char * separator = cmdlineSeparator(cmd, len); - if (separator == NULL) { - return len; - } else { - return separator - cmd; - } -} - -/** - * Find next part of command - * @param cmd - input command - * @param len - max search length - * @return number of characters to be skipped - */ -size_t skipCmdLine(const char * cmd, size_t len) { - const char * separator = cmdlineSeparator(cmd, len); - if (separator == NULL) { - return len; - } else { - return separator + 1 - cmd; - } -} +#include "scpi/utils.h" /** * Write data to SCPI output @@ -168,7 +76,7 @@ */ static size_t writeDelimiter(scpi_t * context) { if (context->output_count > 0) { - return writeData(context, ", ", 2); + return writeData(context, ",", 1); } else { return 0; } @@ -182,7 +90,10 @@ static size_t writeNewLine(scpi_t * context) { if (context->output_count > 0) { size_t len; - len = writeData(context, "\r\n", 2); +#ifndef SCPI_LINE_ENDING +#error no termination character defined +#endif + len = writeData(context, SCPI_LINE_ENDING, strlen(SCPI_LINE_ENDING)); flushData(context); return len; } else { @@ -191,17 +102,33 @@ } /** + * Conditionaly write ";" + * @param context + * @return number of characters written + */ +static size_t writeSemicolon(scpi_t * context) { + if (context->output_count > 0) { + return writeData(context, ";", 1); + } else { + return 0; + } +} + +/** * Process command * @param context */ static void processCommand(scpi_t * context) { - const scpi_command_t * cmd = context->paramlist.cmd; + const scpi_command_t * cmd = context->param_list.cmd; + lex_state_t * state = &context->param_list.lex_state; + + /* conditionaly write ; */ + writeSemicolon(context); context->cmd_error = FALSE; context->output_count = 0; context->input_count = 0; - SCPI_DEBUG_COMMAND(context); /* if callback exists - call command callback */ if (cmd->callback != NULL) { if ((cmd->callback(context) != SCPI_RES_OK) && !context->cmd_error) { @@ -209,14 +136,8 @@ } } - /* conditionaly write new line */ - writeNewLine(context); - - /* skip all whitespaces */ - paramSkipWhitespace(context); - /* set error if command callback did not read all parameters */ - if (context->paramlist.length != 0 && !context->cmd_error) { + if (state->pos < (state->buffer + state->len) && !context->cmd_error) { SCPI_ErrorPush(context, SCPI_ERROR_PARAMETER_NOT_ALLOWED); } } @@ -226,19 +147,14 @@ * @param context * @result TRUE if context->paramlist is filled with correct values */ -static scpi_bool_t findCommand(scpi_t * context, const char * cmdline_ptr, size_t cmdline_len, size_t cmd_len) { +static scpi_bool_t findCommandHeader(scpi_t * context, const char * header, int len) { int32_t i; const scpi_command_t * cmd; for (i = 0; context->cmdlist[i].pattern != NULL; i++) { cmd = &context->cmdlist[i]; - if (matchCommand(cmd->pattern, cmdline_ptr, cmd_len)) { - context->paramlist.cmd = cmd; - context->paramlist.parameters = cmdline_ptr + cmd_len; - context->paramlist.length = cmdline_len - cmd_len; - context->paramlist.cmd_raw.data = cmdline_ptr; - context->paramlist.cmd_raw.length = cmd_len; - context->paramlist.cmd_raw.position = 0; + if (matchCommand(cmd->pattern, header, len, NULL, 0)) { + context->param_list.cmd = cmd; return TRUE; } } @@ -252,38 +168,60 @@ * @param len - command line length * @return 1 if the last evaluated command was found */ -int SCPI_Parse(scpi_t * context, char * data, size_t len) { +int SCPI_Parse(scpi_t * context, char * data, int len) { int result = 0; - const char * cmdline_end = data + len; - char * cmdline_ptr = data; - size_t cmd_len; - size_t cmdline_len; - char * cmdline_ptr_prev = NULL; - size_t cmd_len_prev = 0; + scpi_parser_state_t * state; + int r; + scpi_token_t cmd_prev = {SCPI_TOKEN_UNKNOWN, NULL, 0}; if (context == NULL) { return -1; } - while (cmdline_ptr < cmdline_end) { + state = &context->parser_state; + context->output_count = 0; + + while (1) { result = 0; - cmd_len = cmdTerminatorPos(cmdline_ptr, cmdline_end - cmdline_ptr); - if (cmd_len > 0) { - composeCompoundCommand(cmdline_ptr_prev, cmd_len_prev, - &cmdline_ptr, &cmd_len); - cmdline_len = cmdlineSeparatorPos(cmdline_ptr, cmdline_end - cmdline_ptr); - if(findCommand(context, cmdline_ptr, cmdline_len, cmd_len)) { + + r = scpiParser_detectProgramMessageUnit(state, data, len); + + if (state->programHeader.type == SCPI_TOKEN_INVALID) { + SCPI_ErrorPush(context, SCPI_ERROR_INVALID_CHARACTER); + } else if (state->programHeader.len > 0) { + + composeCompoundCommand(&cmd_prev, &state->programHeader); + + if (findCommandHeader(context, state->programHeader.ptr, state->programHeader.len)) { + + context->param_list.lex_state.buffer = state->programData.ptr; + context->param_list.lex_state.pos = context->param_list.lex_state.buffer; + context->param_list.lex_state.len = state->programData.len; + context->param_list.cmd_raw.data = state->programHeader.ptr; + context->param_list.cmd_raw.position = 0; + context->param_list.cmd_raw.length = state->programHeader.len; + processCommand(context); + result = 1; - cmdline_ptr_prev = cmdline_ptr; - cmd_len_prev = cmd_len; + cmd_prev = state->programHeader; } else { SCPI_ErrorPush(context, SCPI_ERROR_UNDEFINED_HEADER); } } - cmdline_ptr += skipCmdLine(cmdline_ptr, cmdline_end - cmdline_ptr); - cmdline_ptr += skipWhitespace(cmdline_ptr, cmdline_end - cmdline_ptr); + + if (r < len) { + data += r; + len -= r; + } else { + break; + } + } + + /* conditionaly write new line */ + writeNewLine(context); + return result; } @@ -307,7 +245,7 @@ if (context->idn[3] == NULL) { context->idn[3] = SCPI_DEFAULT_4_REVISION; } - + context->buffer.position = 0; SCPI_ErrorInit(context); } @@ -316,22 +254,24 @@ * Interface to the application. Adds data to system buffer and try to search * command line termination. If the termination is found or if len=0, command * parser is called. - * + * * @param context * @param data - data to process * @param len - length of data - * @return + * @return */ -int SCPI_Input(scpi_t * context, const char * data, size_t len) { +int SCPI_Input(scpi_t * context, const char * data, int len) { int result = 0; - const char * cmd_term; + size_t totcmdlen = 0; + int cmdlen = 0; + if (len == 0) { context->buffer.data[context->buffer.position] = 0; result = SCPI_Parse(context, context->buffer.data, context->buffer.position); context->buffer.position = 0; } else { - size_t buffer_free; - int ws; + int buffer_free; + buffer_free = context->buffer.length - context->buffer.position; if (len > (buffer_free - 1)) { return -1; @@ -340,16 +280,20 @@ context->buffer.position += len; context->buffer.data[context->buffer.position] = 0; - ws = skipWhitespace(context->buffer.data, context->buffer.position); - cmd_term = cmdlineTerminator(context->buffer.data + ws, context->buffer.position - ws); - while (cmd_term != NULL) { - int curr_len = cmd_term - context->buffer.data; - result = SCPI_Parse(context, context->buffer.data + ws, curr_len - ws); - memmove(context->buffer.data, cmd_term, context->buffer.position - curr_len); - context->buffer.position -= curr_len; - - ws = skipWhitespace(context->buffer.data, context->buffer.position); - cmd_term = cmdlineTerminator(context->buffer.data + ws, context->buffer.position - ws); + + while (1) { + cmdlen = scpiParser_detectProgramMessageUnit(&context->parser_state, context->buffer.data + totcmdlen, context->buffer.position - totcmdlen); + totcmdlen += cmdlen; + + if (context->parser_state.termination == SCPI_MESSAGE_TERMINATION_NL) { + result = SCPI_Parse(context, context->buffer.data, totcmdlen); + memmove(context->buffer.data, context->buffer.data + totcmdlen, context->buffer.position - totcmdlen); + context->buffer.position -= totcmdlen; + totcmdlen = 0; + } else { + if (context->parser_state.programHeader.type == SCPI_TOKEN_UNKNOWN) break; + if (totcmdlen >= context->buffer.position) break; + } } } @@ -362,10 +306,9 @@ * Write raw string result to the output * @param context * @param data - * @return + * @return */ -size_t SCPI_ResultString(scpi_t * context, const char * data) { - size_t len = strlen(data); +size_t SCPI_ResultCharacters(scpi_t * context, const char * data, size_t len) { size_t result = 0; result += writeDelimiter(context); result += writeData(context, data, len); @@ -377,38 +320,61 @@ * Write integer value to the result * @param context * @param val - * @return + * @return */ size_t SCPI_ResultInt(scpi_t * context, int32_t val) { - char buffer[12]; + return SCPI_ResultIntBase(context, val, 10); +} + +/** + * Return prefix of nondecimal base + * @param base + * @return + */ +static const char * getBasePrefix(int8_t base) { + switch (base) { + case 2: return "#B"; + case 8: return "#Q"; + case 16: return "#H"; + default: return NULL; + } +} + +/** + * Write integer value in specific base to the result + * @param context + * @param val + * @param base + * @return + */ +size_t SCPI_ResultIntBase(scpi_t * context, int32_t val, int8_t base) { + char buffer[33]; + const char * basePrefix; size_t result = 0; - size_t len = longToStr(val, buffer, sizeof (buffer)); + size_t len; + + len = SCPI_LongToStr(val, buffer, sizeof (buffer), base); + basePrefix = getBasePrefix(base); + result += writeDelimiter(context); + if (basePrefix != NULL) { + result += writeData(context, basePrefix, 2); + } result += writeData(context, buffer, len); context->output_count++; return result; } /** - * Write boolean value to the result - * @param context - * @param val - * @return - */ -size_t SCPI_ResultBool(scpi_t * context, scpi_bool_t val) { - return SCPI_ResultInt(context, val ? 1 : 0); -} - -/** * Write double walue to the result * @param context * @param val - * @return + * @return */ size_t SCPI_ResultDouble(scpi_t * context, double val) { char buffer[32]; size_t result = 0; - size_t len = doubleToStr(val, buffer, sizeof (buffer)); + size_t len = SCPI_DoubleToStr(val, buffer, sizeof (buffer)); result += writeDelimiter(context); result += writeData(context, buffer, len); context->output_count++; @@ -420,266 +386,661 @@ * Write string withn " to the result * @param context * @param data - * @return + * @return */ size_t SCPI_ResultText(scpi_t * context, const char * data) { size_t result = 0; result += writeDelimiter(context); result += writeData(context, "\"", 1); + // TODO: convert " to "" result += writeData(context, data, strlen(data)); result += writeData(context, "\"", 1); context->output_count++; return result; } -/* parsing parameters */ - /** - * Skip num bytes from the begginig of parameters + * Write arbitrary block program data to the result * @param context - * @param num + * @param data + * @param len + * @return */ -void paramSkipBytes(scpi_t * context, size_t num) { - if (context->paramlist.length < num) { - num = context->paramlist.length; - } - context->paramlist.parameters += num; - context->paramlist.length -= num; +size_t SCPI_ResultArbitraryBlock(scpi_t * context, const char * data, size_t len) { + size_t result = 0; + char block_header[12]; + size_t header_len; + block_header[0] = '#'; + SCPI_LongToStr(len, block_header + 2, 10, 10); + + header_len = strlen(block_header + 2); + block_header[1] = (char)(header_len + '0'); + + result += writeData(context, block_header, header_len + 2); + result += writeData(context, data, len); + + context->output_count++; + return result; } /** - * Skip white spaces from the beggining of parameters + * Write boolean value to the result * @param context + * @param val + * @return */ -void paramSkipWhitespace(scpi_t * context) { - size_t ws = skipWhitespace(context->paramlist.parameters, context->paramlist.length); - paramSkipBytes(context, ws); +size_t SCPI_ResultBool(scpi_t * context, scpi_bool_t val) { + return SCPI_ResultIntBase(context, val ? 1 : 0, 10); +} + +/* parsing parameters */ + +/** + * Invalidate token + * @param token + * @param ptr + */ +static void invalidateToken(scpi_token_t * token, char * ptr) { + token->len = 0; + token->ptr = ptr; + token->type = SCPI_TOKEN_UNKNOWN; } /** - * Find next parameter + * Get one parameter from command line * @param context + * @param parameter * @param mandatory - * @return + * @return */ -scpi_bool_t paramNext(scpi_t * context, scpi_bool_t mandatory) { - paramSkipWhitespace(context); - if (context->paramlist.length == 0) { +scpi_bool_t SCPI_Parameter(scpi_t * context, scpi_parameter_t * parameter, scpi_bool_t mandatory) { + lex_state_t * state; + + if (!parameter) { + SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR); + return FALSE; + } + + invalidateToken(parameter, NULL); + + state = &context->param_list.lex_state; + + if (state->pos >= (state->buffer + state->len)) { if (mandatory) { SCPI_ErrorPush(context, SCPI_ERROR_MISSING_PARAMETER); + } else { + parameter->type = SCPI_TOKEN_PROGRAM_MNEMONIC; // TODO: select something different } return FALSE; } if (context->input_count != 0) { - if (context->paramlist.parameters[0] == ',') { - paramSkipBytes(context, 1); - paramSkipWhitespace(context); - } else { + scpiLex_Comma(state, parameter); + if (parameter->type != SCPI_TOKEN_COMMA) { + invalidateToken(parameter, NULL); SCPI_ErrorPush(context, SCPI_ERROR_INVALID_SEPARATOR); return FALSE; } } + context->input_count++; - return TRUE; + + scpiParser_parseProgramData(&context->param_list.lex_state, parameter); + + switch (parameter->type) { + case SCPI_TOKEN_HEXNUM: + case SCPI_TOKEN_OCTNUM: + case SCPI_TOKEN_BINNUM: + case SCPI_TOKEN_PROGRAM_MNEMONIC: + case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA: + case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA_WITH_SUFFIX: + case SCPI_TOKEN_ARBITRARY_BLOCK_PROGRAM_DATA: + case SCPI_TOKEN_SINGLE_QUOTE_PROGRAM_DATA: + case SCPI_TOKEN_DOUBLE_QUOTE_PROGRAM_DATA: + case SCPI_TOKEN_PROGRAM_EXPRESSION: + return TRUE; + default: + invalidateToken(parameter, NULL); + SCPI_ErrorPush(context, SCPI_ERROR_INVALID_STRING_DATA); + return FALSE; + } +} + +/** + * Detect if parameter is number + * @param parameter + * @param suffixAllowed + * @return + */ +scpi_bool_t SCPI_ParamIsNumber(scpi_parameter_t * parameter, scpi_bool_t suffixAllowed) { + switch (parameter->type) { + case SCPI_TOKEN_HEXNUM: + case SCPI_TOKEN_OCTNUM: + case SCPI_TOKEN_BINNUM: + case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA: + return TRUE; + case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA_WITH_SUFFIX: + return suffixAllowed; + default: + return FALSE; + } } /** - * Parse integer parameter + * Convert parameter to integer + * @param context + * @param parameter + * @param value result + * @return TRUE if succesful + */ +scpi_bool_t SCPI_ParamToInt(scpi_t * context, scpi_parameter_t * parameter, int32_t * value) { + + if (!value) { + SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR); + return FALSE; + } + + switch (parameter->type) { + case SCPI_TOKEN_HEXNUM: + return strToLong(parameter->ptr, value, 16) > 0 ? TRUE : FALSE; + case SCPI_TOKEN_OCTNUM: + return strToLong(parameter->ptr, value, 8) > 0 ? TRUE : FALSE; + case SCPI_TOKEN_BINNUM: + return strToLong(parameter->ptr, value, 2) > 0 ? TRUE : FALSE; + case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA: + case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA_WITH_SUFFIX: + return strToLong(parameter->ptr, value, 10) > 0 ? TRUE : FALSE; + } + return FALSE; +} + +/** + * Convert parameter to double + * @param context + * @param parameter + * @param value result + * @return TRUE if succesful + */ +scpi_bool_t SCPI_ParamToDouble(scpi_t * context, scpi_parameter_t * parameter, double * value) { + scpi_bool_t result = FALSE; + int32_t valint; + + if (!value) { + SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR); + return FALSE; + } + + switch (parameter->type) { + case SCPI_TOKEN_HEXNUM: + case SCPI_TOKEN_OCTNUM: + case SCPI_TOKEN_BINNUM: + result = SCPI_ParamToInt(context, parameter, &valint); + *value = valint; + break; + case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA: + case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA_WITH_SUFFIX: + result = strToDouble(parameter->ptr, value) > 0 ? TRUE : FALSE; + break; + } + return result; +} + +/** + * Read floating point parameter * @param context * @param value * @param mandatory - * @return + * @return */ -scpi_bool_t SCPI_ParamInt(scpi_t * context, int32_t * value, scpi_bool_t mandatory) { - const char * param; - size_t param_len; - size_t num_len; +scpi_bool_t SCPI_ParamDouble(scpi_t * context, double * value, scpi_bool_t mandatory) { + scpi_bool_t result; + scpi_parameter_t param; if (!value) { + SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR); return FALSE; } - if (!SCPI_ParamString(context, ¶m, ¶m_len, mandatory)) { - return FALSE; + result = SCPI_Parameter(context, ¶m, mandatory); + if (result) { + if (SCPI_ParamIsNumber(¶m, FALSE)) { + SCPI_ParamToDouble(context, ¶m, value); + } else if (SCPI_ParamIsNumber(¶m, TRUE)) { + SCPI_ErrorPush(context, SCPI_ERROR_SUFFIX_NOT_ALLOWED); + result = FALSE; + } else { + SCPI_ErrorPush(context, SCPI_ERROR_DATA_TYPE_ERROR); + result = FALSE; + } } - - num_len = strToLong(param, value); - - if (num_len != param_len) { - SCPI_ErrorPush(context, SCPI_ERROR_SUFFIX_NOT_ALLOWED); - return FALSE; - } - - return TRUE; + return result; } /** - * Parse double parameter + * Read integer parameter * @param context * @param value * @param mandatory - * @return + * @return */ -scpi_bool_t SCPI_ParamDouble(scpi_t * context, double * value, scpi_bool_t mandatory) { - const char * param; - size_t param_len; - size_t num_len; +scpi_bool_t SCPI_ParamInt(scpi_t * context, int32_t * value, scpi_bool_t mandatory) { + scpi_bool_t result; + scpi_parameter_t param; if (!value) { + SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR); return FALSE; } - if (!SCPI_ParamString(context, ¶m, ¶m_len, mandatory)) { + result = SCPI_Parameter(context, ¶m, mandatory); + if (result) { + if (SCPI_ParamIsNumber(¶m, FALSE)) { + SCPI_ParamToInt(context, ¶m, value); + } else if (SCPI_ParamIsNumber(¶m, TRUE)) { + SCPI_ErrorPush(context, SCPI_ERROR_SUFFIX_NOT_ALLOWED); + result = FALSE; + } else { + SCPI_ErrorPush(context, SCPI_ERROR_DATA_TYPE_ERROR); + result = FALSE; + } + } + return result; +} + +/** + * Read character parameter + * @param context + * @param value + * @param len + * @param mandatory + * @return + */ +scpi_bool_t SCPI_ParamCharacters(scpi_t * context, const char ** value, size_t * len, scpi_bool_t mandatory) { + scpi_bool_t result; + scpi_parameter_t param; + + if (!value || !len) { + SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR); return FALSE; } - num_len = strToDouble(param, value); + result = SCPI_Parameter(context, ¶m, mandatory); + if (result) { + *value = param.ptr; + *len = param.len; - if (num_len != param_len) { - SCPI_ErrorPush(context, SCPI_ERROR_SUFFIX_NOT_ALLOWED); - return FALSE; + // TODO: return also parameter type (ProgramMnemonic, ArbitraryBlockProgramData, SingleQuoteProgramData, DoubleQuoteProgramData } - return TRUE; + return result; } /** - * Parse string parameter + * Get arbitrary block program data and returns pointer to data * @param context - * @param value Pointer to string buffer where pointer to non-null terminated string will be returned - * @param len Length of returned non-null terminated string + * @param value result pointer to data + * @param len result length of data * @param mandatory - * @return + * @return */ -scpi_bool_t SCPI_ParamString(scpi_t * context, const char ** value, size_t * len, scpi_bool_t mandatory) { - size_t length; +scpi_bool_t SCPI_ParamArbitraryBlock(scpi_t * context, const char ** value, size_t * len, scpi_bool_t mandatory) { + scpi_bool_t result; + scpi_parameter_t param; if (!value || !len) { + SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR); + return FALSE; + } + + result = SCPI_Parameter(context, ¶m, mandatory); + if (result) { + if (param.type == SCPI_TOKEN_ARBITRARY_BLOCK_PROGRAM_DATA) { + *value = param.ptr; + *len = param.len; + } else { + SCPI_ErrorPush(context, SCPI_ERROR_DATA_TYPE_ERROR); + result = FALSE; + } + } + + return result; +} + +scpi_bool_t SCPI_ParamCopyText(scpi_t * context, char * buffer, size_t buffer_len, size_t * copy_len, scpi_bool_t mandatory) { + scpi_bool_t result; + scpi_parameter_t param; + size_t i_from; + size_t i_to; + char quote; + + if (!buffer || !copy_len) { + SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR); return FALSE; } - if (!paramNext(context, mandatory)) { + result = SCPI_Parameter(context, ¶m, mandatory); + if (result) { + + switch (param.type) { + case SCPI_TOKEN_SINGLE_QUOTE_PROGRAM_DATA: + case SCPI_TOKEN_DOUBLE_QUOTE_PROGRAM_DATA: + quote = param.type == SCPI_TOKEN_SINGLE_QUOTE_PROGRAM_DATA ? '\'' : '"'; + for (i_from = 0, i_to = 0; i_from < (size_t) param.len; i_from++) { + if (i_from >= buffer_len) { + break; + } + buffer[i_to] = param.ptr[i_from]; + i_to++; + if (param.ptr[i_from] == quote) { + i_from++; + } + } + break; + default: + SCPI_ErrorPush(context, SCPI_ERROR_DATA_TYPE_ERROR); + result = FALSE; + } + } + + return result; +} + +/** + * Convert parameter to choice + * @param context + * @param parameter - should be PROGRAM_MNEMONIC + * @param options - NULL terminated list of choices + * @param value - index to options + * @return + */ +scpi_bool_t SCPI_ParamToChoice(scpi_t * context, scpi_parameter_t * parameter, const scpi_choice_def_t * options, int32_t * value) { + size_t res; + scpi_bool_t result = FALSE; + + if (!options || !value) { + SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR); return FALSE; } - if (locateStr(context->paramlist.parameters, context->paramlist.length, value, &length)) { - paramSkipBytes(context, length); - paramSkipWhitespace(context); - if (len) { - *len = length; + if (parameter->type == SCPI_TOKEN_PROGRAM_MNEMONIC) { + for (res = 0; options[res].name; ++res) { + if (matchPattern(options[res].name, strlen(options[res].name), parameter->ptr, parameter->len, NULL)) { + *value = options[res].tag; + result = TRUE; + break; + } + } + + if (!result) { + SCPI_ErrorPush(context, SCPI_ERROR_ILLEGAL_PARAMETER_VALUE); } - return TRUE; + } else { + SCPI_ErrorPush(context, SCPI_ERROR_DATA_TYPE_ERROR); + } + + return result; +} + +/** + * Find tag in choices and returns its first textual representation + * @param options specifications of choices numbers (patterns) + * @param tag numerical representatio of choice + * @param text result text + * @return TRUE if succesfule, else FALSE + */ +scpi_bool_t SCPI_ChoiceToName(const scpi_choice_def_t * options, int32_t tag, const char ** text) { + int i; + + for (i = 0; options[i].name != NULL; i++) { + if (options[i].tag == tag) { + *text = options[i].name; + return TRUE; + } } return FALSE; } /** - * Parse text parameter (can be inside "") - * @param context - * @param value Pointer to string buffer where pointer to non-null terminated string will be returned - * @param len Length of returned non-null terminated string - * @param mandatory - * @return - */ -scpi_bool_t SCPI_ParamText(scpi_t * context, const char ** value, size_t * len, scpi_bool_t mandatory) { - size_t length; - - if (!value || !len) { - return FALSE; - } - - if (!paramNext(context, mandatory)) { - return FALSE; - } - - if (locateText(context->paramlist.parameters, context->paramlist.length, value, &length)) { - paramSkipBytes(context, length); - if (len) { - *len = length; - } - return TRUE; - } - - return FALSE; -} - -/** - * Parse boolean parameter as described in the spec SCPI-99 7.3 Boolean Program Data + * Read BOOL parameter (0,1,ON,OFF) * @param context * @param value * @param mandatory - * @return + * @return */ scpi_bool_t SCPI_ParamBool(scpi_t * context, scpi_bool_t * value, scpi_bool_t mandatory) { - const char * param; - size_t param_len; - size_t num_len; - int32_t i; + scpi_bool_t result; + scpi_parameter_t param; + int32_t intval; + + scpi_choice_def_t bool_options[] = { + {"OFF", 0}, + {"ON", 1}, + SCPI_CHOICE_LIST_END /* termination of option list */ + }; if (!value) { - return FALSE; - } - - if (!SCPI_ParamString(context, ¶m, ¶m_len, mandatory)) { + SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR); return FALSE; } - if (matchPattern("ON", 2, param, param_len)) { - *value = TRUE; - } else if (matchPattern("OFF", 3, param, param_len)) { - *value = FALSE; - } else { - num_len = strToLong(param, &i); + result = SCPI_Parameter(context, ¶m, mandatory); - if (num_len != param_len) { - SCPI_ErrorPush(context, SCPI_ERROR_SUFFIX_NOT_ALLOWED); - return FALSE; + if (result) { + if (param.type == SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA) { + SCPI_ParamToInt(context, ¶m, &intval); + *value = intval ? TRUE : FALSE; + } else { + result = SCPI_ParamToChoice(context, ¶m, bool_options, &intval); + if (result) { + *value = intval ? TRUE : FALSE; + } } - - *value = i ? TRUE : FALSE; } - return TRUE; + return result; } /** - * Parse choice parameter + * Read value from list of options * @param context * @param options * @param value * @param mandatory - * @return + * @return */ -scpi_bool_t SCPI_ParamChoice(scpi_t * context, const char * options[], int32_t * value, scpi_bool_t mandatory) { - const char * param; - size_t param_len; - size_t res; +scpi_bool_t SCPI_ParamChoice(scpi_t * context, const scpi_choice_def_t * options, int32_t * value, scpi_bool_t mandatory) { + scpi_bool_t result; + scpi_parameter_t param; if (!options || !value) { - return FALSE; - } - - if (!SCPI_ParamString(context, ¶m, ¶m_len, mandatory)) { + SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR); return FALSE; } - for (res = 0; options[res]; ++res) { - if (matchPattern(options[res], strlen(options[res]), param, param_len)) { - *value = res; - return TRUE; + result = SCPI_Parameter(context, ¶m, mandatory); + if (result) { + result = SCPI_ParamToChoice(context, ¶m, options, value); + } + + return result; +} + +/** + * Parse one parameter and detect type + * @param state + * @param token + * @return + */ +int scpiParser_parseProgramData(lex_state_t * state, scpi_token_t * token) { + scpi_token_t tmp; + int result = 0; + int wsLen; + int suffixLen; + int realLen = 0; + realLen += scpiLex_WhiteSpace(state, &tmp); + + if (result == 0) result = scpiLex_NondecimalNumericData(state, token); + if (result == 0) result = scpiLex_CharacterProgramData(state, token); + if (result == 0) { + result = scpiLex_DecimalNumericProgramData(state, token); + if (result != 0) { + wsLen = scpiLex_WhiteSpace(state, &tmp); + suffixLen = scpiLex_SuffixProgramData(state, &tmp); + if (suffixLen > 0) { + token->len += wsLen + suffixLen; + token->type = SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA_WITH_SUFFIX; + result = token->len; + } } } - SCPI_ErrorPush(context, SCPI_ERROR_ILLEGAL_PARAMETER_VALUE); - return FALSE; + if (result == 0) result = scpiLex_StringProgramData(state, token); + if (result == 0) result = scpiLex_ArbitraryBlockProgramData(state, token); + if (result == 0) result = scpiLex_ProgramExpression(state, token); + + realLen += scpiLex_WhiteSpace(state, &tmp); + + return result + realLen; +} + +/** + * Skip all parameters to correctly detect end of command line. + * @param state + * @param token + * @param numberOfParameters + * @return + */ +int scpiParser_parseAllProgramData(lex_state_t * state, scpi_token_t * token, int * numberOfParameters) { + + int result; + scpi_token_t tmp; + int paramCount = 0; + + token->len = -1; + token->type = SCPI_TOKEN_ALL_PROGRAM_DATA; + token->ptr = state->pos; + + + for (result = 1; result != 0; result = scpiLex_Comma(state, &tmp)) { + token->len += result; + + if (result == 0) { + token->type = SCPI_TOKEN_UNKNOWN; + token->len = 0; + paramCount = -1; + break; + } + + result = scpiParser_parseProgramData(state, &tmp); + if (tmp.type != SCPI_TOKEN_UNKNOWN) { + token->len += result; + } else { + token->type = SCPI_TOKEN_UNKNOWN; + token->len = 0; + paramCount = -1; + break; + } + paramCount++; + } + + if (token->len == -1) { + token->len = 0; + } + + if (numberOfParameters != NULL) { + *numberOfParameters = paramCount; + } + return token->len; } +/** + * Skip complete command line - program header and parameters + * @param state + * @param buffer + * @param len + * @return + */ +int scpiParser_detectProgramMessageUnit(scpi_parser_state_t * state, char * buffer, int len) { + lex_state_t lex_state; + scpi_token_t tmp; + int result = 0; + + lex_state.buffer = lex_state.pos = buffer; + lex_state.len = len; + state->numberOfParameters = 0; + + /* ignore whitespace at the begginig */ + scpiLex_WhiteSpace(&lex_state, &tmp); + + if (scpiLex_ProgramHeader(&lex_state, &state->programHeader) >= 0) { + if (scpiLex_WhiteSpace(&lex_state, &tmp) > 0) { + scpiParser_parseAllProgramData(&lex_state, &state->programData, &state->numberOfParameters); + } else { + invalidateToken(&state->programData, lex_state.pos); + } + } else { + invalidateToken(&state->programHeader, lex_state.buffer); + invalidateToken(&state->programData, lex_state.buffer); + } + + if (result == 0) result = scpiLex_NewLine(&lex_state, &tmp); + if (result == 0) result = scpiLex_Semicolon(&lex_state, &tmp); + + if (!scpiLex_IsEos(&lex_state) && (result == 0)) { + lex_state.pos++; + + state->programHeader.len = 1; + state->programHeader.type = SCPI_TOKEN_INVALID; + + invalidateToken(&state->programData, lex_state.buffer); + } + + if (SCPI_TOKEN_SEMICOLON == tmp.type) { + state->termination = SCPI_MESSAGE_TERMINATION_SEMICOLON; + } else if (SCPI_TOKEN_NL == tmp.type) { + state->termination = SCPI_MESSAGE_TERMINATION_NL; + } else { + state->termination = SCPI_MESSAGE_TERMINATION_NONE; + } + + return lex_state.pos - lex_state.buffer; +} + +/** + * Check current command + * - suitable for one handle to multiple commands + * @param context + * @param cmd + * @return + */ scpi_bool_t SCPI_IsCmd(scpi_t * context, const char * cmd) { - if (! context->paramlist.cmd) { + const char * pattern; + + if (!context->param_list.cmd) { return FALSE; } - const char * pattern = context->paramlist.cmd->pattern; - return matchCommand (pattern, cmd, strlen (cmd)); + pattern = context->param_list.cmd->pattern; + return matchCommand (pattern, cmd, strlen (cmd), NULL, 0); } + +/** + * Return the .tag field of the matching scpi_command_t + * @param context + * @return + */ +int32_t SCPI_CmdTag(scpi_t * context) { + if (context->param_list.cmd) { + return context->param_list.cmd->tag; + } else { + return 0; + } +} + +scpi_bool_t SCPI_Match(const char * pattern, const char * value, size_t len) { + return matchCommand (pattern, value, len, NULL, 0); +} + +scpi_bool_t SCPI_CommandNumbers(scpi_t * context, int32_t * numbers, size_t len) { + return matchCommand (context->param_list.cmd->pattern, context->param_list.cmd_raw.data, context->param_list.cmd_raw.length, numbers, len); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/parser_private.h Fri Aug 07 21:54:11 2015 +0000 @@ -0,0 +1,54 @@ +/*- + * Copyright (c) 2012-2013 Jan Breuer, + * + * All Rights Reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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 AUTHORS ``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 AUTHORS 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 parser_private.h + * + * @brief SCPI Parser private definitions + * + * + */ + +#ifndef SCPI_PARSER_PRIVATE_H +#define SCPI_PARSER_PRIVATE_H + +#include "scpi/types.h" +#include "utils_private.h" + +#ifdef __cplusplus +extern "C" { +#endif + + int scpiParser_parseProgramData(lex_state_t * state, scpi_token_t * token) LOCAL; + int scpiParser_parseAllProgramData(lex_state_t * state, scpi_token_t * token, int * numberOfParameters) LOCAL; + int scpiParser_detectProgramMessageUnit(scpi_parser_state_t * state, char * buffer, int len) LOCAL; + +#ifdef __cplusplus +} +#endif + +#endif /* SCPI_PARSER_PRIVATE_H */
--- a/src/units.c Thu Apr 09 22:42:15 2015 +0000 +++ b/src/units.c Fri Aug 07 21:54:11 2015 +0000 @@ -37,8 +37,10 @@ #include <string.h> #include "scpi/parser.h" #include "scpi/units.h" -#include "scpi/utils_private.h" +#include "utils_private.h" +#include "scpi/utils.h" #include "scpi/error.h" +#include "lexer_private.h" /* @@ -62,39 +64,39 @@ */ const scpi_unit_def_t scpi_units_def[] = { /* voltage */ - {/* name */ "UV", /* unit */ SCPI_UNIT_VOLT, /* mult */ 1e-6}, - {/* name */ "MV", /* unit */ SCPI_UNIT_VOLT, /* mult */ 1e-3}, - {/* name */ "V", /* unit */ SCPI_UNIT_VOLT, /* mult */ 1}, - {/* name */ "KV", /* unit */ SCPI_UNIT_VOLT, /* mult */ 1e3}, + {/* name */ "UV", /* unit */ SCPI_UNIT_VOLT, /* mult */ 1e-6}, + {/* name */ "MV", /* unit */ SCPI_UNIT_VOLT, /* mult */ 1e-3}, + {/* name */ "V", /* unit */ SCPI_UNIT_VOLT, /* mult */ 1}, + {/* name */ "KV", /* unit */ SCPI_UNIT_VOLT, /* mult */ 1e3}, /* current */ - {/* name */ "UA", /* unit */ SCPI_UNIT_AMPER, /* mult */ 1e-6}, - {/* name */ "MA", /* unit */ SCPI_UNIT_AMPER, /* mult */ 1e-3}, - {/* name */ "A", /* unit */ SCPI_UNIT_AMPER, /* mult */ 1}, - {/* name */ "KA", /* unit */ SCPI_UNIT_AMPER, /* mult */ 1e3}, + {/* name */ "UA", /* unit */ SCPI_UNIT_AMPER, /* mult */ 1e-6}, + {/* name */ "MA", /* unit */ SCPI_UNIT_AMPER, /* mult */ 1e-3}, + {/* name */ "A", /* unit */ SCPI_UNIT_AMPER, /* mult */ 1}, + {/* name */ "KA", /* unit */ SCPI_UNIT_AMPER, /* mult */ 1e3}, /* resistance */ - {/* name */ "OHM", /* unit */ SCPI_UNIT_OHM, /* mult */ 1}, - {/* name */ "KOHM", /* unit */ SCPI_UNIT_OHM, /* mult */ 1e3}, - {/* name */ "MOHM", /* unit */ SCPI_UNIT_OHM, /* mult */ 1e6}, + {/* name */ "OHM", /* unit */ SCPI_UNIT_OHM, /* mult */ 1}, + {/* name */ "KOHM", /* unit */ SCPI_UNIT_OHM, /* mult */ 1e3}, + {/* name */ "MOHM", /* unit */ SCPI_UNIT_OHM, /* mult */ 1e6}, /* frequency */ - {/* name */ "HZ", /* unit */ SCPI_UNIT_HERTZ, /* mult */ 1}, - {/* name */ "KHZ", /* unit */ SCPI_UNIT_HERTZ, /* mult */ 1e3}, - {/* name */ "MHZ", /* unit */ SCPI_UNIT_HERTZ, /* mult */ 1e6}, - {/* name */ "GHZ", /* unit */ SCPI_UNIT_HERTZ, /* mult */ 1e9}, + {/* name */ "HZ", /* unit */ SCPI_UNIT_HERTZ, /* mult */ 1}, + {/* name */ "KHZ", /* unit */ SCPI_UNIT_HERTZ, /* mult */ 1e3}, + {/* name */ "MHZ", /* unit */ SCPI_UNIT_HERTZ, /* mult */ 1e6}, + {/* name */ "GHZ", /* unit */ SCPI_UNIT_HERTZ, /* mult */ 1e9}, /* temperature */ - {/* name */ "CEL", /* unit */ SCPI_UNIT_CELSIUS, /* mult */ 1}, + {/* name */ "CEL", /* unit */ SCPI_UNIT_CELSIUS, /* mult */ 1}, /* time */ - {/* name */ "PS", /* unit */ SCPI_UNIT_SECONDS, /* mult */ 1e-12}, - {/* name */ "NS", /* unit */ SCPI_UNIT_SECONDS, /* mult */ 1e-9}, - {/* name */ "US", /* unit */ SCPI_UNIT_SECONDS, /* mult */ 1e-6}, - {/* name */ "MS", /* unit */ SCPI_UNIT_SECONDS, /* mult */ 1e-3}, - {/* name */ "S", /* unit */ SCPI_UNIT_SECONDS, /* mult */ 1}, - {/* name */ "MIN", /* unit */ SCPI_UNIT_SECONDS, /* mult */ 60}, - {/* name */ "HR", /* unit */ SCPI_UNIT_SECONDS, /* mult */ 3600}, + {/* name */ "PS", /* unit */ SCPI_UNIT_SECONDS, /* mult */ 1e-12}, + {/* name */ "NS", /* unit */ SCPI_UNIT_SECONDS, /* mult */ 1e-9}, + {/* name */ "US", /* unit */ SCPI_UNIT_SECONDS, /* mult */ 1e-6}, + {/* name */ "MS", /* unit */ SCPI_UNIT_SECONDS, /* mult */ 1e-3}, + {/* name */ "S", /* unit */ SCPI_UNIT_SECONDS, /* mult */ 1}, + {/* name */ "MIN", /* unit */ SCPI_UNIT_SECONDS, /* mult */ 60}, + {/* name */ "HR", /* unit */ SCPI_UNIT_SECONDS, /* mult */ 3600}, SCPI_UNITS_LIST_END, }; @@ -102,71 +104,20 @@ /* * Special number values definition */ -const scpi_special_number_def_t scpi_special_numbers_def[] = { - {/* name */ "MINimum", /* type */ SCPI_NUM_MIN}, - {/* name */ "MAXimum", /* type */ SCPI_NUM_MAX}, - {/* name */ "DEFault", /* type */ SCPI_NUM_DEF}, - {/* name */ "UP", /* type */ SCPI_NUM_UP}, - {/* name */ "DOWN", /* type */ SCPI_NUM_DOWN}, - {/* name */ "NAN", /* type */ SCPI_NUM_NAN}, - {/* name */ "INFinity", /* type */ SCPI_NUM_INF}, - {/* name */ "NINF", /* type */ SCPI_NUM_NINF}, - {/* name */ "AUTO", /* type */ SCPI_NUM_AUTO}, - SCPI_SPECIAL_NUMBERS_LIST_END, +const scpi_choice_def_t scpi_special_numbers_def[] = { + {/* name */ "MINimum", /* type */ SCPI_NUM_MIN}, + {/* name */ "MAXimum", /* type */ SCPI_NUM_MAX}, + {/* name */ "DEFault", /* type */ SCPI_NUM_DEF}, + {/* name */ "UP", /* type */ SCPI_NUM_UP}, + {/* name */ "DOWN", /* type */ SCPI_NUM_DOWN}, + {/* name */ "NAN", /* type */ SCPI_NUM_NAN}, + {/* name */ "INFinity", /* type */ SCPI_NUM_INF}, + {/* name */ "NINF", /* type */ SCPI_NUM_NINF}, + {/* name */ "AUTO", /* type */ SCPI_NUM_AUTO}, + SCPI_CHOICE_LIST_END, }; /** - * Match string constant to one of special number values - * @param specs specifications of special numbers (patterns) - * @param str string to be recognised - * @param len length of string - * @param value resultin value - * @return TRUE if str matches one of specs patterns - */ -static scpi_bool_t translateSpecialNumber(const scpi_special_number_def_t * specs, const char * str, size_t len, scpi_number_t * value) { - int i; - - value->value = 0.0; - value->unit = SCPI_UNIT_NONE; - value->type = SCPI_NUM_NUMBER; - - if (specs == NULL) { - return FALSE; - } - - for (i = 0; specs[i].name != NULL; i++) { - if (matchPattern(specs[i].name, strlen(specs[i].name), str, len)) { - value->type = specs[i].type; - return TRUE; - } - } - - return FALSE; -} - -/** - * Convert special number type to its string representation - * @param specs specifications of special numbers (patterns) - * @param type type of special number - * @return String representing special number or NULL - */ -static const char * translateSpecialNumberInverse(const scpi_special_number_def_t * specs, scpi_special_number_t type) { - int i; - - if (specs == NULL) { - return NULL; - } - - for (i = 0; specs[i].name != NULL; i++) { - if (specs[i].type == type) { - return specs[i].name; - } - } - - return NULL; -} - -/** * Convert string describing unit to its representation * @param units units patterns * @param unit text representation of unknown unit @@ -175,11 +126,11 @@ */ static const scpi_unit_def_t * translateUnit(const scpi_unit_def_t * units, const char * unit, size_t len) { int i; - + if (units == NULL) { return NULL; } - + for (i = 0; units[i].name != NULL; i++) { if (compareStr(unit, len, units[i].name, strlen(units[i].name))) { return &units[i]; @@ -197,11 +148,11 @@ */ static const char * translateUnitInverse(const scpi_unit_def_t * units, const scpi_unit_t unit) { int i; - + if (units == NULL) { return NULL; } - + for (i = 0; units[i].name != NULL; i++) { if ((units[i].unit == unit) && (units[i].mult == 1)) { return units[i].name; @@ -249,43 +200,97 @@ * @param mandatory if the parameter is mandatory * @return */ -scpi_bool_t SCPI_ParamNumber(scpi_t * context, scpi_number_t * value, scpi_bool_t mandatory) { +scpi_bool_t SCPI_ParamNumber(scpi_t * context, const scpi_choice_def_t * special, scpi_number_t * value, scpi_bool_t mandatory) +{ + scpi_token_t token; + lex_state_t state; + scpi_parameter_t param; scpi_bool_t result; - const char * param; - size_t len; - size_t numlen; + int32_t tag; - /* read parameter and shift to the next one */ - result = SCPI_ParamString(context, ¶m, &len, mandatory); - - /* value not initializes */ if (!value) { + SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR); return FALSE; } - value->type = SCPI_NUM_DEF; + result = SCPI_Parameter(context, ¶m, mandatory); + + if (!result) { + return result; + } + + state.buffer = param.ptr; + state.pos = state.buffer; + state.len = param.len; - /* if parameter was not found, return TRUE or FALSE according - * to fact that parameter was mandatory or not */ - if (!result) { - return mandatory ? FALSE : TRUE; + switch(param.type) { + case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA: + case SCPI_TOKEN_HEXNUM: + case SCPI_TOKEN_OCTNUM: + case SCPI_TOKEN_BINNUM: + case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA_WITH_SUFFIX: + case SCPI_TOKEN_PROGRAM_MNEMONIC: + value->unit = SCPI_UNIT_NONE; + value->special = FALSE; + result = TRUE; + break; } - /* convert string to special number type */ - if (translateSpecialNumber(context->special_numbers, param, len, value)) { - /* found special type */ - return TRUE; + switch(param.type) { + case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA: + case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA_WITH_SUFFIX: + case SCPI_TOKEN_PROGRAM_MNEMONIC: + value->base = 10; + break; + case SCPI_TOKEN_BINNUM: + value->base = 2; + break; + case SCPI_TOKEN_HEXNUM: + value->base = 16; + break; + case SCPI_TOKEN_OCTNUM: + value->base = 8; + break; } - /* convert text from double - no special type */ - numlen = strToDouble(param, &value->value); + switch(param.type) { + case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA: + SCPI_ParamToDouble(context, ¶m, &(value->value)); + break; + case SCPI_TOKEN_HEXNUM: + SCPI_ParamToDouble(context, ¶m, &(value->value)); + break; + case SCPI_TOKEN_OCTNUM: + SCPI_ParamToDouble(context, ¶m, &(value->value)); + break; + case SCPI_TOKEN_BINNUM: + SCPI_ParamToDouble(context, ¶m, &(value->value)); + break; + case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA_WITH_SUFFIX: + scpiLex_DecimalNumericProgramData(&state, &token); + scpiLex_WhiteSpace(&state, &token); + scpiLex_SuffixProgramData(&state, &token); - /* transform units of value */ - if (numlen <= len) { - return transformNumber(context, param + numlen, len - numlen, value); + SCPI_ParamToDouble(context, ¶m, &(value->value)); + + result = transformNumber(context, token.ptr, token.len, value); + break; + case SCPI_TOKEN_PROGRAM_MNEMONIC: + scpiLex_WhiteSpace(&state, &token); + scpiLex_CharacterProgramData(&state, &token); + + /* convert string to special number type */ + SCPI_ParamToChoice(context, &token, special, &tag); + + value->special = TRUE; + value->tag = tag; + + break; + default: + result = FALSE; } - return FALSE; + return result; } /** @@ -296,7 +301,7 @@ * @param len max length of string * @return number of chars written to string */ -size_t SCPI_NumberToStr(scpi_t * context, scpi_number_t * value, char * str, size_t len) { +size_t SCPI_NumberToStr(scpi_t * context, const scpi_choice_def_t * special, scpi_number_t * value, char * str, size_t len) { const char * type; const char * unit; size_t result; @@ -305,14 +310,17 @@ return 0; } - type = translateSpecialNumberInverse(context->special_numbers, value->type); - - if (type) { - strncpy(str, type, len); - return min(strlen(type), len); + if (value->special) { + if (SCPI_ChoiceToName(special, value->tag, &type)) { + strncpy(str, type, len); + return min(strlen(type), len); + } else { + str[0] = 0; + return 0; + } } - result = doubleToStr(value->value, str, len); + result = SCPI_DoubleToStr(value->value, str, len); unit = translateUnitInverse(context->units, value->unit);
--- a/src/utils.c Thu Apr 09 22:42:15 2015 +0000 +++ b/src/utils.c Fri Aug 07 21:54:11 2015 +0000 @@ -1,4 +1,3 @@ -#define HAVE_STRNLEN 0 /*- * Copyright (c) 2013 Jan Breuer * Richard.hmm @@ -42,7 +41,8 @@ #include <string.h> #include <ctype.h> -#include "scpi/utils_private.h" +#include "utils_private.h" +#include "scpi/utils.h" static size_t patternSeparatorShortPos(const char * pattern, size_t len); static size_t patternSeparatorPos(const char * pattern, size_t len); @@ -55,7 +55,7 @@ * @param set * @return */ -const char * strnpbrk(const char *str, size_t size, const char *set) { +char * strnpbrk(const char *str, size_t size, const char *set) { const char *scanp; long c, sc; const char * strend = str + size; @@ -63,7 +63,7 @@ while ((strend != str) && ((c = *str++) != 0)) { for (scanp = set; (sc = *scanp++) != '\0';) if (sc == c) - return str - 1; + return ((char *) (str - 1)); } return (NULL); } @@ -73,35 +73,63 @@ * @param val integer value * @param str converted textual representation * @param len string buffer length + * @param base output base * @return number of bytes written to str (without '\0') */ -size_t longToStr(int32_t val, char * str, size_t len) { - uint32_t x = 1000000000L; +size_t SCPI_LongToStr(int32_t val, char * str, size_t len, int8_t base) { + const char digits[] = "0123456789ABCDEF"; + +#define ADD_CHAR(c) if (pos < len) str[pos++] = (c) + uint32_t x = 0; int_fast8_t digit; size_t pos = 0; + uint32_t uval = val; - if (val == 0) { - if (pos < len) str[pos++] = '0'; + if (uval == 0) { + ADD_CHAR('0'); } else { - if (val < 0) { - val = -val; - if (pos < len) str[pos++] = '-'; + + switch (base) { + case 2: + x = 0x80000000L; + break; + case 8: + x = 0x40000000L; + break; + case 10: + x = 1000000000L; + break; + case 0x10: + x = 0x10000000L; + break; + default: + x = 1000000000L; + base = 10; + break; } - while ((val / x) == 0) { - x /= 10; + // add sign for numbers in base 10 + if ((val < 0) && (base == 10)) { + uval = -val; + ADD_CHAR('-'); + } + + // remove leading zeros + while ((uval / x) == 0) { + x /= base; } do { - digit = (uint8_t) (val / x); - if (pos < len) str[pos++] = digit + '0'; - val -= digit * x; - x /= 10; + digit = (uint8_t) (uval / x); + ADD_CHAR(digits[digit]); + uval -= digit * x; + x /= base; } while (x && (pos < len)); } if (pos < len) str[pos] = 0; return pos; +#undef ADD_CHAR } /** @@ -111,8 +139,8 @@ * @param len string buffer length * @return number of bytes written to str (without '\0') */ -size_t doubleToStr(double val, char * str, size_t len) { - return snprintf(str, len, "%lg", val); +size_t SCPI_DoubleToStr(double val, char * str, size_t len) { + return SCPIDEFINE_doubleToStr(val, str, len); } /** @@ -121,9 +149,9 @@ * @param val 32bit integer result * @return number of bytes used in string */ -size_t strToLong(const char * str, int32_t * val) { +size_t strToLong(const char * str, int32_t * val, int8_t base) { char * endptr; - *val = strtol(str, &endptr, 0); + *val = strtol(str, &endptr, base); return endptr - str; } @@ -152,7 +180,7 @@ return FALSE; } - if (SCPI_strncasecmp(str1, str2, len2) == 0) { + if (SCPIDEFINE_strncasecmp(str1, str2, len2) == 0) { return TRUE; } @@ -167,7 +195,7 @@ * @param len2 * @return TRUE if strings match */ -scpi_bool_t compareStrAndNum(const char * str1, size_t len1, const char * str2, size_t len2) { +scpi_bool_t compareStrAndNum(const char * str1, size_t len1, const char * str2, size_t len2, int32_t * num) { scpi_bool_t result = FALSE; size_t i; @@ -175,222 +203,34 @@ return FALSE; } - if (SCPI_strncasecmp(str1, str2, len1) == 0) { + if (SCPIDEFINE_strncasecmp(str1, str2, len1) == 0) { result = TRUE; - } - for (i = len1; i<len2; i++) { - if (!isdigit((int) str2[i])) { - result = FALSE; - break; + if (num) { + if (len1 == len2) { + *num = 1; + } else { + int32_t tmpNum; + i = len1 + strToLong(str2 + len1, &tmpNum, 10); + if (i != len2) { + result = FALSE; + } else { + *num = tmpNum; + } + } + } else { + for (i = len1; i<len2; i++) { + if (!isdigit((int) str2[i])) { + result = FALSE; + break; + } + } } } return result; } -enum _locate_text_states { - STATE_FIRST_WHITESPACE, - STATE_TEXT_QUOTED, - STATE_TEXT, - STATE_LAST_WHITESPACE, - STATE_COMMA, - STATE_ERROR -}; -typedef enum _locate_text_states locate_text_states; - -struct _locate_text_nfa { - locate_text_states state; - int32_t startIdx; - int32_t stopIdx; - size_t i; -}; -typedef struct _locate_text_nfa locate_text_nfa; - -/** - * Test locate text state, if it is correct final state - */ -static scpi_bool_t isFinalState(locate_text_states state) { - return ( - ((state) == STATE_COMMA) - || ((state) == STATE_LAST_WHITESPACE) - || ((state) == STATE_TEXT) || - ((state) == STATE_FIRST_WHITESPACE) - ); -} - -/** - * Perform locateText automaton to search string pattern - * @param nfa stores automaton state - * @param c current char processed - */ -static scpi_bool_t locateTextAutomaton(locate_text_nfa * nfa, unsigned char c) { - switch(nfa->state) { - /* first state locating only white spaces */ - case STATE_FIRST_WHITESPACE: - if(isspace(c)) { - nfa->startIdx = nfa->stopIdx = nfa->i + 1; - } else if (c == ',') { - nfa->state = STATE_COMMA; - } else if (c == '"') { - nfa->startIdx = nfa->i + 1; - nfa->state = STATE_TEXT_QUOTED; - } else { - nfa->startIdx = nfa->i; - nfa->stopIdx = nfa->i + 1; - nfa->state = STATE_TEXT; - } - break; - /* state locating any text inside "" */ - case STATE_TEXT_QUOTED: - if(c == '"') { - nfa->state = STATE_LAST_WHITESPACE; - nfa->stopIdx = nfa->i; - } - break; - /* locate text ignoring quotes */ - case STATE_TEXT: - if (c == ',') { - nfa->state = STATE_COMMA; - } else if (!isspace(c)) { - nfa->stopIdx = nfa->i + 1; - } - break; - /* locating text after last quote */ - case STATE_LAST_WHITESPACE: - if (c == ',') { - nfa->state = STATE_COMMA; - } else if (!isspace(c)) { - nfa->state = STATE_ERROR; - } - break; - - default: - break; - } - - /* if it is terminating state, break from for loop */ - if ((nfa->state == STATE_COMMA) || (nfa->state == STATE_ERROR)) { - return FALSE; - } else { - return TRUE; - } -} - -/** - * Locate text in string. Text is separated by two "" - * example: "text", next parameter - * regexp: ^[ \t\r\n]*"([^"]*)"[ \t\r\n]*,? - * regexp: ^[ \t\r\n]*([^,]*)[ \t\r\n]*,? - * @param str1 string to be searched - * @param len1 length of string - * @param str2 result - * @param len2 length of result - * @return string str1 contains text and str2 was set - */ -scpi_bool_t locateText(const char * str1, size_t len1, const char ** str2, size_t * len2) { - locate_text_nfa nfa; - nfa.state = STATE_FIRST_WHITESPACE; - nfa.startIdx = 0; - nfa.stopIdx = 0; - - for (nfa.i = 0; nfa.i < len1; nfa.i++) { - if(FALSE == locateTextAutomaton(&nfa, str1[nfa.i])) { - break; - } - } - - if (isFinalState(nfa.state)) { - - if (str2) { - *str2 = &str1[nfa.startIdx]; - } - - if (len2) { - *len2 = nfa.stopIdx - nfa.startIdx; - } - return TRUE; - } - return FALSE; -} - -/** - * Perform locateStr automaton to search string pattern - * @param nfa stores automaton state - * @param c current char processed - */ -static scpi_bool_t locateStrAutomaton(locate_text_nfa * nfa, unsigned char c) { - switch(nfa->state) { - /* first state locating only white spaces */ - case STATE_FIRST_WHITESPACE: - if(isspace(c)) { - nfa->startIdx = nfa->stopIdx = nfa->i + 1; - } else if (c == ',') { - nfa->state = STATE_COMMA; - } else { - nfa->startIdx = nfa->i; - nfa->stopIdx = nfa->i + 1; - nfa->state = STATE_TEXT; - } - break; - /* locate text ignoring quotes */ - case STATE_TEXT: - if (c == ',') { - nfa->state = STATE_COMMA; - } else if (!isspace(c)) { - nfa->stopIdx = nfa->i + 1; - } - break; - - default: - break; - } - - /* if it is terminating state, break from for loop */ - if ((nfa->state == STATE_COMMA) || (nfa->state == STATE_ERROR)) { - return FALSE; - } else { - return TRUE; - } -} - -/** - * Locate string in string. - * regexp: ^[ \t\r\n]*([^,]*)[ \t\r\n]*,? - * @param str1 string to be searched - * @param len1 length of string - * @param str2 result - * @param len2 length of result - * @return string str1 contains text and str2 was set - */ -scpi_bool_t locateStr(const char * str1, size_t len1, const char ** str2, size_t * len2) { - locate_text_nfa nfa; - nfa.state = STATE_FIRST_WHITESPACE; - nfa.startIdx = 0; - nfa.stopIdx = 0; - - - for (nfa.i = 0; nfa.i < len1; nfa.i++) { - if(FALSE == locateStrAutomaton(&nfa, str1[nfa.i])) { - break; - } - } - - if (isFinalState(nfa.state)) { - - if (str2) { - *str2 = &str1[nfa.startIdx]; - } - - if (len2) { - *len2 = nfa.stopIdx - nfa.startIdx; - } - return TRUE; - } - return FALSE; -} - - /** * Count white spaces from the beggining * @param cmd - command @@ -414,7 +254,7 @@ * @param len - max search length * @return position of separator or len */ -size_t patternSeparatorShortPos(const char * pattern, size_t len) { +static size_t patternSeparatorShortPos(const char * pattern, size_t len) { size_t i; for (i = 0; (i < len) && pattern[i]; i++) { if (islower((unsigned char) pattern[i])) { @@ -430,9 +270,9 @@ * @param len - max search length * @return position of separator or len */ -size_t patternSeparatorPos(const char * pattern, size_t len) { +static size_t patternSeparatorPos(const char * pattern, size_t len) { - const char * separator = strnpbrk(pattern, len, "?:[]"); + char * separator = strnpbrk(pattern, len, "?:[]"); if (separator == NULL) { return len; } else { @@ -446,8 +286,8 @@ * @param len - max search length * @return position of separator or len */ -size_t cmdSeparatorPos(const char * cmd, size_t len) { - const char * separator = strnpbrk(cmd, len, ":?"); +static size_t cmdSeparatorPos(const char * cmd, size_t len) { + char * separator = strnpbrk(cmd, len, ":?"); size_t result; if (separator == NULL) { result = len; @@ -466,7 +306,7 @@ * @param str_len * @return */ -scpi_bool_t matchPattern(const char * pattern, size_t pattern_len, const char * str, size_t str_len) { +scpi_bool_t matchPattern(const char * pattern, size_t pattern_len, const char * str, size_t str_len, int32_t * num) { int pattern_sep_pos_short; if (pattern[pattern_len - 1] == '#') { @@ -474,8 +314,8 @@ pattern_sep_pos_short = patternSeparatorShortPos(pattern, new_pattern_len); - return compareStrAndNum(pattern, new_pattern_len, str, str_len) || - compareStrAndNum(pattern, pattern_sep_pos_short, str, str_len); + return compareStrAndNum(pattern, new_pattern_len, str, str_len, num) || + compareStrAndNum(pattern, pattern_sep_pos_short, str, str_len, num); } else { pattern_sep_pos_short = patternSeparatorShortPos(pattern, pattern_len); @@ -492,18 +332,21 @@ * @param len - max search length * @return TRUE if pattern matches, FALSE otherwise */ -scpi_bool_t matchCommand(const char * pattern, const char * cmd, size_t len) { +scpi_bool_t matchCommand(const char * pattern, const char * cmd, size_t len, int32_t *numbers, size_t numbers_len) { scpi_bool_t result = FALSE; int leftFlag = 0; // flag for '[' on left int rightFlag = 0; // flag for ']' on right int cmd_sep_pos = 0; + size_t numbers_idx = 0; + int32_t *number_ptr = NULL; + const char * pattern_ptr = pattern; int pattern_len = strlen(pattern); const char * pattern_end = pattern + pattern_len; const char * cmd_ptr = cmd; - size_t cmd_len = SCPI_strnlen(cmd, len); + size_t cmd_len = SCPIDEFINE_strnlen(cmd, len); const char * cmd_end = cmd + cmd_len; /* now support optional keywords in pattern style, e.g. [:MEASure]:VOLTage:DC? */ @@ -519,7 +362,7 @@ if (cmd_ptr[0] == ':') { /* handle errornouse ":*IDN?" */ - if((cmd_len >= 2) && (cmd_ptr[1] != '*')) { + if ((cmd_len >= 2) && (cmd_ptr[1] != '*')) { cmd_len--; cmd_ptr++; } @@ -535,7 +378,19 @@ cmd_sep_pos = cmdSeparatorPos(cmd_ptr, cmd_end - cmd_ptr); } - if (matchPattern(pattern_ptr, pattern_sep_pos, cmd_ptr, cmd_sep_pos)) { + if (pattern_ptr[pattern_sep_pos - 1] == '#') { + if (numbers && (numbers_idx < numbers_len)) { + number_ptr = numbers + numbers_idx; + *number_ptr = 1; // default value + } else { + number_ptr = NULL; + } + numbers_idx++; + } else { + number_ptr = NULL; + } + + if (matchPattern(pattern_ptr, pattern_sep_pos, cmd_ptr, cmd_sep_pos, number_ptr)) { pattern_ptr = pattern_ptr + pattern_sep_pos; cmd_ptr = cmd_ptr + cmd_sep_pos; result = TRUE; @@ -619,74 +474,45 @@ /** * Compose command from previsou command anc current command - * - * @param ptr_prev pointer to previous command - * @param len_prev length of previous command - * @param pptr pointer to pointer of current command - * @param plen pointer to length of current command - * - * ptr_prev and ptr should be in the same memory buffer - * - * Function will add part of previous command prior to ptr_prev - * - * char * cmd = "meas:volt:dc?;ac?" - * char * ptr_prev = cmd; - * size_t len_prev = 13; - * char * ptr = cmd + 14; - * size_t len = 3; - * - * composeCompoundCommand(ptr_prev, len_prev, &ptr, &len); - * - * after calling this - * - * - * + * + * @param prev pointer to previous command + * @param current pointer of current command + * + * prev and current should be in the same memory buffer */ -scpi_bool_t composeCompoundCommand(char * ptr_prev, size_t len_prev, - char ** pptr, size_t * plen) { - char * ptr; - size_t len; +scpi_bool_t composeCompoundCommand(const scpi_token_t * prev, scpi_token_t * current) { size_t i; /* Invalid input */ - if (pptr == NULL || plen == NULL) + if (current == NULL || current->ptr == NULL || current->len == 0) return FALSE; /* no previous command - nothing to do*/ - if (ptr_prev == NULL || len_prev == 0) + if (prev->ptr == NULL || prev->len == 0) return TRUE; - - ptr = *pptr; - len = *plen; - - /* No current command */ - if (len == 0 || ptr == NULL) - return FALSE; - + /* Common command or command root - nothing to do */ - if (ptr[0] == '*' || ptr[0] == ':') + if (current->ptr[0] == '*' || current->ptr[0] == ':') return TRUE; - + /* Previsou command was common command - nothing to do */ - if (ptr_prev[0] == '*') + if (prev->ptr[0] == '*') return TRUE; - + /* Find last occurence of ':' */ - for (i = len_prev; i > 0; i--) { - if (ptr_prev[i-1] == ':') { + for (i = prev->len; i > 0; i--) { + if (prev->ptr[i - 1] == ':') { break; } } - + /* Previous command was simple command - nothing to do*/ if (i == 0) return TRUE; - - ptr -= i; - len += i; - memmove(ptr, ptr_prev, i); - *plen = len; - *pptr = ptr; + + current->ptr -= i; + current->len += i; + memmove(current->ptr, prev->ptr, i); return TRUE; } @@ -712,20 +538,20 @@ #endif #if !HAVE_STRNCASECMP && !HAVE_STRNICMP + int OUR_strncasecmp(const char *s1, const char *s2, size_t n) { unsigned char c1, c2; - for(; n != 0; n--) { - c1 = tolower((unsigned char)*s1++); - c2 = tolower((unsigned char)*s2++); + for (; n != 0; n--) { + c1 = tolower((unsigned char) *s1++); + c2 = tolower((unsigned char) *s2++); if (c1 != c2) { return c1 - c2; } - if (c1 = '\0') { + if (c1 == '\0') { return 0; } } return 0; } #endif -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/utils_private.h Fri Aug 07 21:54:11 2015 +0000 @@ -0,0 +1,99 @@ +/*- + * Copyright (c) 2012-2013 Jan Breuer, + * + * All Rights Reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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 AUTHORS ``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 AUTHORS 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 scpi_utils.h + * @date Thu Nov 15 10:58:45 UTC 2012 + * + * @brief Conversion routines and string manipulation routines + * + * + */ + +#ifndef SCPI_UTILS_PRIVATE_H +#define SCPI_UTILS_PRIVATE_H + +#include <stdint.h> +#include "scpi/config.h" +#include "scpi/types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(__GNUC__) && (__GNUC__ >= 4) + #define LOCAL __attribute__((visibility ("hidden"))) +#else + #define LOCAL +#endif + + char * strnpbrk(const char *str, size_t size, const char *set) LOCAL; + scpi_bool_t compareStr(const char * str1, size_t len1, const char * str2, size_t len2) LOCAL; + scpi_bool_t compareStrAndNum(const char * str1, size_t len1, const char * str2, size_t len2, int32_t * num) LOCAL; + size_t strToLong(const char * str, int32_t * val, int8_t base) LOCAL; + size_t strToDouble(const char * str, double * val) LOCAL; + scpi_bool_t locateText(const char * str1, size_t len1, const char ** str2, size_t * len2) LOCAL; + scpi_bool_t locateStr(const char * str1, size_t len1, const char ** str2, size_t * len2) LOCAL; + size_t skipWhitespace(const char * cmd, size_t len) LOCAL; + scpi_bool_t matchPattern(const char * pattern, size_t pattern_len, const char * str, size_t str_len, int32_t * num) LOCAL; + scpi_bool_t matchCommand(const char * pattern, const char * cmd, size_t len, int32_t *numbers, size_t numbers_len) LOCAL; + scpi_bool_t composeCompoundCommand(const scpi_token_t * prev, scpi_token_t * current) LOCAL; + +#if !HAVE_STRNLEN + size_t BSD_strnlen(const char *s, size_t maxlen) LOCAL; +#endif + +#if !HAVE_STRNCASECMP && !HAVE_STRNICMP + int OUR_strncasecmp(const char *s1, const char *s2, size_t n) LOCAL; +#endif + +#ifndef min + #define min(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +#ifndef max + #define max(a, b) (((a) > (b)) ? (a) : (b)) +#endif + +#if 0 +#define max(a,b) \ + ({ __typeof__ (a) _a = (a); \ + __typeof__ (b) _b = (b); \ + _a > _b ? _a : _b; }) + +#define min(a,b) \ + ({ __typeof__ (a) _a = (a); \ + __typeof__ (b) _b = (b); \ + _a < _b ? _a : _b; }) + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* SCPI_UTILS_PRIVATE_H */