#ifndef SCPI_ARGS_HELPER_H #define SCPI_ARGS_HELPER_H // SCPI Command Argument parser helper header. // Include only to the command handler file like 'idn.c' or similar. // ------------------------------------------------------------------------ #include "app/scpi/scpi_base.h" // SCPI_MAX_ARGS #include "app/scpi/scpi_commands.h" // processCharacterArgument #include "app/scpi/scpi_numeric_types.h" // sProcessNumericEntry_t, sStrToken_t, sNumericRange_t #include "app/scpi/scpi_numeric.h" #include "app/scpi/scpi_args.h" #include // uint8_t // ------------------------------------------------------------------------ // @SCPI_ARGS_N macro: // Defines amount of SCPI-command arguments including optional ones. // The command handler module must include this header either after defining this macro, // or after defining a pair of SCPI_ARGS_N_Q + SCPI_ARGS_N_C. // // @SCPI_ARGS_N_Q macro: // Defines amount of SCPI-command arguments including optional ones for QUERY. // The command handler module must include this header after defining this macro. // It is required to be defined together with SCPI_ARGS_N_C. // Useless if SCPI_ARGS_N is defined. // // @SCPI_ARGS_N_C macro: // Defines amount of SCPI-command arguments including optional ones for COMMNAD(non-query). // The command handler module must include this header after defining this macro. // It is required to be defined together with SCPI_ARGS_N_Q. // Useless if SCPI_ARGS_N is defined. // @SCPI_ARGS_MANDATORY_N macro: // Defines amount of mandatory SCPI-command arguments, not including optional ones. // If the command requires all the parameters and does not allow to omit any argument, // this value must be equal to SCPI_ARGS_N, or must be undefined. The command handler module // must include this header after defining this macro. All the optional command parameters // are located in the end of the argument set. // The command handler module must include this header either after defining this macro, // or after defining a pair of SCPI_ARGS_MANDATORY_N_Q + SCPI_ARGS_MANDATORY_N_C. // @SCPI_ARGS_MANDATORY_N_Q macro: // Defines amount of mandatory SCPI-command arguments, not including optional ones, for QUERY. // If the command requires all the parameters and does not allow to omit any argument, // this value must be equal to SCPI_ARGS_N_Q, or must be undefined. The command handler module // must include this header after defining this macro. All the optional command parameters are // located in the end of the argument set. // It is required to be defined together with SCPI_ARGS_MANDATORY_N_C. // Useless if SCPI_ARGS_MANDATORY_N is defined. // @SCPI_ARGS_MANDATORY_N_C macro: // Defines amount of mandatory SCPI-command arguments, not including optional ones, for COMMAND. // If the command requires all the parameters and does not allow to omit any argument, // this value must be be equal to SCPI_ARGS_N_C, or must be undefined. The command handler module // must include this header after defining this macro. All the optional command parameters are // located in the end of the argument set. // It is required to be defined together with SCPI_ARGS_MANDATORY_N_Q. // Useless if SCPI_ARGS_MANDATORY_N is defined. #define GC(_common_ctx_) ((sScpiParserContext_t*)((_common_ctx_)->global_ctx)) #if !defined(SCPI_ARGS_HELPER_C) #ifndef SCPI_ARGS_N #if defined(SCPI_ARGS_N_Q) && !defined(SCPI_ARGS_N_C) #error The macro 'SCPI_ARGS_N_C' is undefined. #elif defined(SCPI_ARGS_N_C) && !defined(SCPI_ARGS_N_Q) #error The macro 'SCPI_ARGS_N_Q' is undefined. #elif !defined(SCPI_ARGS_N_C) && !defined(SCPI_ARGS_N_Q) #error The macro 'SCPI_ARGS_N' shall be defined to the amount of command parameters or 'SCPI_ARGS_N_Q' and 'SCPI_ARGS_N_C' shall be used instead. #endif #endif #if defined(SCPI_ARGS_N) && (SCPI_ARGS_N > SCPI_MAX_ARGS) #error Invalid value 'SCPI_ARGS_N'. Limit exceeded. See the limit 'SCPI_MAX_ARGS'. #endif #if defined(SCPI_ARGS_N_Q) && (SCPI_ARGS_N_Q > SCPI_MAX_ARGS) #error Invalid value 'SCPI_ARGS_N_Q'. Limit exceeded. See the limit 'SCPI_MAX_ARGS'. #endif #if defined(SCPI_ARGS_N_C) && (SCPI_ARGS_N_C > SCPI_MAX_ARGS) #error Invalid value 'SCPI_ARGS_N_C'. Limit exceeded. See the limit 'SCPI_MAX_ARGS'. #endif #if defined(SCPI_ARGS_N) #ifndef SCPI_ARGS_MANDATORY_N #define SCPI_ARGS_MANDATORY_N SCPI_ARGS_N #elif SCPI_ARGS_MANDATORY_N > SCPI_ARGS_N #error The value 'SCPI_ARGS_MANDATORY_N' shall not be greater than 'SCPI_ARGS_N' #endif #endif #if defined(SCPI_ARGS_N_Q) && defined(SCPI_ARGS_N_C) #ifndef SCPI_ARGS_MANDATORY_N_C #define SCPI_ARGS_MANDATORY_N_C SCPI_ARGS_N_C #elif SCPI_ARGS_MANDATORY_N_C > SCPI_ARGS_N_C #error The value 'SCPI_ARGS_MANDATORY_N_C' shall not be greater than 'SCPI_ARGS_N_C' #endif #ifndef SCPI_ARGS_MANDATORY_N_Q #define SCPI_ARGS_MANDATORY_N_Q SCPI_ARGS_N_Q #elif SCPI_ARGS_MANDATORY_N_Q > SCPI_ARGS_N_Q #error The value 'SCPI_ARGS_MANDATORY_N_Q' shall not be greater than 'SCPI_ARGS_N_Q' #endif #endif #else // scpi_args_helper.c #endif // ------------------------------------------------------------------------ // @SCPI_ARGS_VAR_TOKENS // Default variable name for the string tokens array #define SCPI_ARGS_VAR_TOKENS argTokens #if defined(SCPI_ARGS_N) // @SCPI_ARGS_VAR_TYPES // Default variable name for the argument types array #define SCPI_ARGS_VAR_TYPES argTypes #endif #if defined(SCPI_ARGS_N_C) && defined(SCPI_ARGS_N_Q) // @SCPI_ARGS_VAR_TYPES_C // Default variable name for the argument types array (command only) #define SCPI_ARGS_VAR_TYPES_C argTypesCommand // @SCPI_ARGS_VAR_TYPES_Q // Default variable name for the argument types array (query only) #define SCPI_ARGS_VAR_TYPES_Q argTypesQuery #endif // ------------------------------------------------------------------------ // @DECLARE_SCPI_ARGS macro: // Use this macro to decalre parser entities for command arguments. // @_VariableTypes_ - the name of the argument types array // The rest arguments of this macro are the set of SCPI_ARGS_N types of command // arguments (eScpiArgType_t), e.g.: // #define SCPI_ARGS_N 1 // DECLARE_SCPI_ARGS( SCPI_ARGS_VAR_TYPES, eScpiArg_Character ); #if defined(SCPI_ARGS_N) #if SCPI_ARGS_N == 0 #define DECLARE_SCPI_ARGS(...) #else #define DECLARE_SCPI_ARGS(...) \ static const uint8_t SCPI_ARGS_VAR_TYPES[ SCPI_ARGS_N ] = { __VA_ARGS__ }; #endif #elif defined(SCPI_ARGS_N_C) && defined(SCPI_ARGS_N_Q) #if SCPI_ARGS_N_C == 0 #define DECLARE_SCPI_ARGS_C(...) #else #define DECLARE_SCPI_ARGS_C(...) \ static const uint8_t SCPI_ARGS_VAR_TYPES_C[ SCPI_ARGS_N_C ] = { __VA_ARGS__ }; #endif #if SCPI_ARGS_N_Q == 0 #define DECLARE_SCPI_ARGS_Q(...) #else #define DECLARE_SCPI_ARGS_Q(...) \ static const uint8_t SCPI_ARGS_VAR_TYPES_Q[ SCPI_ARGS_N_Q ] = { __VA_ARGS__ }; #endif #endif // Routine @parseArguments call helper #if defined(SCPI_ARGS_N) #define SCPI_PARSE_ARGUMENTS_C(_common_ctx_) (assert(false), 0) #define SCPI_PARSE_ARGUMENTS_Q(_common_ctx_) (assert(false), 0) #if SCPI_ARGS_N == 0 #define SCPI_PARSE_ARGUMENTS(_common_ctx_) parseArguments_helper( (_common_ctx_), NULL, SCPI_ARGS_N, 0 ) #else #define SCPI_PARSE_ARGUMENTS(_common_ctx_) parseArguments_helper( (_common_ctx_), SCPI_ARGS_VAR_TYPES, SCPI_ARGS_N, (SCPI_ARGS_N) - (SCPI_ARGS_MANDATORY_N) ) #define SCPI_PARSE_ARRAY_ARGUMENTS(_common_ctx_) parseArrayArguments_helper( (_common_ctx_), SCPI_ARGS_VAR_TYPES, SCPI_ARGS_N, SCPI_ARGS_MANDATORY_N ) #endif #elif defined(SCPI_ARGS_N_C) && defined(SCPI_ARGS_N_Q) #define SCPI_PARSE_ARGUMENTS(_common_ctx_) ((GC(_common_ctx_)->sMessage.bQuery)?\ SCPI_PARSE_ARGUMENTS_Q(_common_ctx_):\ SCPI_PARSE_ARGUMENTS_C(_common_ctx_)) #if SCPI_ARGS_N_C == 0 #define SCPI_PARSE_ARGUMENTS_C(_common_ctx_) parseArguments_helper( (_common_ctx_), NULL, SCPI_ARGS_N_C, 0 ) #else #define SCPI_PARSE_ARGUMENTS_C(_common_ctx_) parseArguments_helper( (_common_ctx_), SCPI_ARGS_VAR_TYPES_C, SCPI_ARGS_N_C, (SCPI_ARGS_N_C) - (SCPI_ARGS_MANDATORY_N_C) ) #endif #if SCPI_ARGS_N_Q == 0 #define SCPI_PARSE_ARGUMENTS_Q(_common_ctx_) parseArguments_helper( (_common_ctx_), NULL, SCPI_ARGS_N_Q, 0 ) #else #define SCPI_PARSE_ARGUMENTS_Q(_common_ctx_) parseArguments_helper( (_common_ctx_), SCPI_ARGS_VAR_TYPES_Q, SCPI_ARGS_N_Q, (SCPI_ARGS_N_Q) - (SCPI_ARGS_MANDATORY_N_Q) ) #endif #endif // ------------------------------------------------------------------------ // @DECLARE_ARGUMENT_CHARACTER_ALLOWED_LIST // Declares an array of elements for SCPI Character Parameter value allowed list // Use this macro together with @processCharacterArgument to interpretate passed parameter. // @_name_ - variable name // @... - rest arguments is a "strings" that contain allowed values, e.g. "NORMal" #define DECLARE_ARGUMENT_CHARACTER_ALLOWED_LIST(_name_, ...) static const xArgument_t _name_[] = { __VA_ARGS__, NULL } // @DECLARE_ARGUMENT_CHARACTER_ALLOWED_LIST_EXPORT - the same as @DECLARE_ARGUMENT_CHARACTER_ALLOWED_LIST but declare // global variable that can be imported to another module. #define DECLARE_ARGUMENT_CHARACTER_ALLOWED_LIST_EXPORT(_name_, ...) const xArgument_t _name_[] = { __VA_ARGS__, NULL } // @DECLARE_ARGUMENT_CHARACTER_ALLOWED_LIST_IMPORT // Imports an array of elements for SCPI Character Parameter value allowed list that have been // declared with @DECLARE_ARGUMENT_CHARACTER_ALLOWED_LIST_EXPORT in other module. // Use this macro together with @processCharacterArgument to interpretate passed parameter. #define DECLARE_ARGUMENT_CHARACTER_ALLOWED_LIST_IMPORT(_name_) extern const xArgument_t _name_[]; #define SCPI_ARGUMENT_CHARACTER_VALUE_TOKEN(_list_,_valueN_,_token_) scpi_argument_value_token(_list_,_valueN_,_token_) // ------------------------------------------------------------------------ // @DECLARE_ARGUMENT_NUMERIC_VALUES_F64 // #define DECLARE_ARGUMENT_NUMERIC_VALUES_F64(_name_, _min_, _max_) static const sNumericRange_t _name_ = { .type = SCPI_NUMERIC_LIMIT_TYPE_F64, .min.f = (_min_), .max.f = (_max_) } // @DECLARE_ARGUMENT_NUMERIC_VALUES_F32 // #define DECLARE_ARGUMENT_NUMERIC_VALUES_F32(_name_, _min_, _max_) static const sNumericRange_t _name_ = { .type = SCPI_NUMERIC_LIMIT_TYPE_F32, .min.f = (_min_), .max.f = (_max_) } // @DECLARE_ARGUMENT_NUMERIC_VALUES_I64 // #define DECLARE_ARGUMENT_NUMERIC_VALUES_I64(_name_, _min_, _max_) static const sNumericRange_t _name_ = { .type = SCPI_NUMERIC_LIMIT_TYPE_I64, .min.i = (_min_), .max.i = (_max_) } // @DECLARE_ARGUMENT_NUMERIC_VALUES_I32 // #define DECLARE_ARGUMENT_NUMERIC_VALUES_I32(_name_, _min_, _max_) static const sNumericRange_t _name_ = { .type = SCPI_NUMERIC_LIMIT_TYPE_I32, .min.i = (_min_), .max.i = (_max_) } // @DECLARE_ARGUMENT_NUMERIC_VALUES_I16 // #define DECLARE_ARGUMENT_NUMERIC_VALUES_I16(_name_, _min_, _max_) static const sNumericRange_t _name_ = { .type = SCPI_NUMERIC_LIMIT_TYPE_I16, .min.i = (_min_), .max.i = (_max_) } // @DECLARE_ARGUMENT_NUMERIC_VALUES_I8 // #define DECLARE_ARGUMENT_NUMERIC_VALUES_I8(_name_, _min_, _max_) static const sNumericRange_t _name_ = { .type = SCPI_NUMERIC_LIMIT_TYPE_I8 , .min.i = (_min_), .max.i = (_max_) } // ------------------------------------------------------------------------ // Routine @processCharacterArgument call helper // * Macro group @SCPI_PROCESS_ARGUMENT_NUMERIC, @SCPI_PROCESS_ARGUMENT_C_NUMERIC, @SCPI_PROCESS_ARGUMENT_Q_NUMERIC // Process the numeric argument token and convert to the integer or float representation. // The result is the pointer to [sNumericEntry_t] structure, where the result is stored together the // value type and conversion error result. #if defined(SCPI_ARGS_N) #define SCPI_PROCESS_ARGUMENT_C_CHARACTER(_common_ctx_, _list_, _id_) (assert(false), 0) #define SCPI_PROCESS_ARGUMENT_Q_CHARACTER(_common_ctx_, _list_, _id_) (assert(false), 0) #define SCPI_PROCESS_ARGUMENT_C_NUMERIC(_common_ctx_, _range_, _id_) (assert(false), 0) #define SCPI_PROCESS_ARGUMENT_Q_NUMERIC(_common_ctx_, _range_, _id_) (assert(false), 0) #if SCPI_ARGS_N == 0 #define SCPI_PROCESS_ARGUMENT_CHARACTER(_common_ctx_, _list_, _id_) (SCPI_ARGUMENT_CHARACTER_INVALID_ID) #define SCPI_PROCESS_ARGUMENT_NUMERIC(_common_ctx_, _range_, _id_) (false) #define SCPI_PROCESS_ARGUMENT_NUMERIC(_common_ctx_, _range_, _id_) (false) #define SCPI_PROCESS_ARGUMENT_ARRAY(_common_ctx_, _range_, _id_) (SCPI_ARGUMENT_CHARACTER_INVALID_ID) #else #define SCPI_PROCESS_ARGUMENT_CHARACTER(_common_ctx_, _list_, _id_) processArgument_Character_helper( (_common_ctx_), SCPI_ARGS_VAR_TYPES, _list_, _id_ ) #define SCPI_PROCESS_ARGUMENT_NUMERIC(_common_ctx_, _range_, _id_) processArgument_Numeric_helper( (_common_ctx_), SCPI_ARGS_VAR_TYPES, _range_, _id_) #define SCPI_PROCESS_ARGUMENT_ARRAY(_common_ctx_, _range_, _id_, _result_arg_, _result_size_) processArgument_Array_helper( (_common_ctx_), _range_, _id_, _result_arg_, _result_size_) #endif #elif defined(SCPI_ARGS_N_C) && defined(SCPI_ARGS_N_Q) #define SCPI_PROCESS_ARGUMENT_CHARACTER(_common_ctx_, _list_, _id_) ((GC(_common_ctx_)->sMessage.bQuery)?\ SCPI_PROCESS_ARGUMENT_Q_CHARACTER(_common_ctx_,_list_,_id_):\ SCPI_PROCESS_ARGUMENT_C_CHARACTER(_common_ctx_,_list_,_id_)) #define SCPI_PROCESS_ARGUMENT_NUMERIC(_common_ctx_, _range_, _id_) ((GC(_common_ctx_)->sMessage.bQuery)?\ SCPI_PROCESS_ARGUMENT_Q_NUMERIC(_common_ctx_,_range_,_id_):\ SCPI_PROCESS_ARGUMENT_C_NUMERIC(_common_ctx_,_range_,_id_)) #if SCPI_ARGS_N_C == 0 #define SCPI_PROCESS_ARGUMENT_C_CHARACTER(_common_ctx_, _list_, _id_) (SCPI_ARGUMENT_CHARACTER_INVALID_ID) #define SCPI_PROCESS_ARGUMENT_C_NUMERIC(_common_ctx_, _range_, _id_) (false) #else #define SCPI_PROCESS_ARGUMENT_C_CHARACTER(_common_ctx_, _list_, _id_) processArgument_Character_helper( (_common_ctx_), SCPI_ARGS_VAR_TYPES_C, _list_, _id_ ) #define SCPI_PROCESS_ARGUMENT_C_NUMERIC(_common_ctx_, _range_, _id_) processArgument_Numeric_helper( (_common_ctx_), SCPI_ARGS_VAR_TYPES_C, _range_, _id_ ) #endif #if SCPI_ARGS_N_Q == 0 #define SCPI_PROCESS_ARGUMENT_Q_CHARACTER(_common_ctx_, _list_, _id_) (SCPI_ARGUMENT_CHARACTER_INVALID_ID) #define SCPI_PROCESS_ARGUMENT_Q_NUMERIC(_common_ctx_, _range_, _id_) (false) #else #define SCPI_PROCESS_ARGUMENT_Q_CHARACTER(_common_ctx_, _list_, _id_) processArgument_Character_helper( (_common_ctx_), SCPI_ARGS_VAR_TYPES_Q, _list_, _id_ ) #define SCPI_PROCESS_ARGUMENT_Q_NUMERIC(_common_ctx_, _range_, _id_) processArgument_Numeric_helper( (_common_ctx_), SCPI_ARGS_VAR_TYPES_Q, _range_, _id_ ) #define SCPI_PROCESS_ARGUMENT_Q_ARRAY(_common_ctx_, _range_, _id_) processArgument_Numeric_helper( (_common_ctx_), SCPI_ARGS_VAR_TYPES_Q, _range_, _id_ ) #endif #endif #define SCPI_ARGUMENT_CHARACTER_INVALID_ID (-1) // @processArgument_Character_helper // Helper function. Used for convenient call of the other helper functions // Parameters: // @common_ctx - process program data state context, see @sProcessProgramDataCommonContext_t // @argTypes - array of argument types to set the parameters parsing methods (see @parseArguments, @eScpiArgType_t) // Other parameters: refer @processCharacterArgument // Returns: SCPI_ARGUMENT_CHARACTER_INVALID_ID in error case, or argument option index in @allowedList int8_t processArgument_Character_helper( void * common_ctx, const uint8_t * argTypes, const xArgument_t * allowedList, uint8_t argId ); // @processArgument_Numeric_helper // Helper function. Used for convenient call of the other helper functions. // Processes the NUMERIC argument. See @processNumericArgument // Parameters: // @common_ctx - process program data state context, see @sProcessProgramDataCommonContext_t // @argTypes - array of argument types to set the parameters parsing methods (see @parseArguments, @eScpiArgType_t) // Other parameters: refer @processNumericArgument // Returns: pointer to the numeric entry descriptor with value and type, and the error code, or NULL // if @common_ctx is set to NULL. const sNumericEntry_t * processArgument_Numeric_helper( void * common_ctx, const uint8_t * argTypes, const sNumericRange_t * range, uint8_t argId ); const sNumericEntry_t * processArgument_Array_helper( void * common_ctx, const sNumericRange_t * range, uint8_t argId, void * result_arg, uint16_t result_size); // @scpi_argument_value_token // Get the string tokens of the specified value in the allowed CHARACTER value list. // Parameters: // @list - allowed values list, see @DECLARE_ARGUMENT_CHARACTER_ALLOWED_LIST // @valueIndex - index in the array; // @pOutToken - string token to fill, can not be NULL; // Returns: filled string token (@pOutToken). // Note: if @valueList is out of range, NULL pointer is returned, and @pOutToken is unchanged. const sStrToken_t * scpi_argument_value_token( const xArgument_t * list, size_t valueIndex, sStrToken_t * pOutToken ); #endif