scpi_args_helper.h 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. #ifndef SCPI_ARGS_HELPER_H
  2. #define SCPI_ARGS_HELPER_H
  3. // SCPI Command Argument parser helper header.
  4. // Include only to the command handler file like 'idn.c' or similar.
  5. // ------------------------------------------------------------------------
  6. #include "app/scpi/scpi_base.h" // SCPI_MAX_ARGS
  7. #include "app/scpi/scpi_commands.h" // processCharacterArgument
  8. #include "app/scpi/scpi_numeric_types.h" // sProcessNumericEntry_t, sStrToken_t, sNumericRange_t
  9. #include "app/scpi/scpi_numeric.h"
  10. #include "app/scpi/scpi_args.h"
  11. #include <stdint.h> // uint8_t
  12. // ------------------------------------------------------------------------
  13. // @SCPI_ARGS_N macro:
  14. // Defines amount of SCPI-command arguments including optional ones.
  15. // The command handler module must include this header either after defining this macro,
  16. // or after defining a pair of SCPI_ARGS_N_Q + SCPI_ARGS_N_C.
  17. //
  18. // @SCPI_ARGS_N_Q macro:
  19. // Defines amount of SCPI-command arguments including optional ones for QUERY.
  20. // The command handler module must include this header after defining this macro.
  21. // It is required to be defined together with SCPI_ARGS_N_C.
  22. // Useless if SCPI_ARGS_N is defined.
  23. //
  24. // @SCPI_ARGS_N_C macro:
  25. // Defines amount of SCPI-command arguments including optional ones for COMMNAD(non-query).
  26. // The command handler module must include this header after defining this macro.
  27. // It is required to be defined together with SCPI_ARGS_N_Q.
  28. // Useless if SCPI_ARGS_N is defined.
  29. // @SCPI_ARGS_MANDATORY_N macro:
  30. // Defines amount of mandatory SCPI-command arguments, not including optional ones.
  31. // If the command requires all the parameters and does not allow to omit any argument,
  32. // this value must be equal to SCPI_ARGS_N, or must be undefined. The command handler module
  33. // must include this header after defining this macro. All the optional command parameters
  34. // are located in the end of the argument set.
  35. // The command handler module must include this header either after defining this macro,
  36. // or after defining a pair of SCPI_ARGS_MANDATORY_N_Q + SCPI_ARGS_MANDATORY_N_C.
  37. // @SCPI_ARGS_MANDATORY_N_Q macro:
  38. // Defines amount of mandatory SCPI-command arguments, not including optional ones, for QUERY.
  39. // If the command requires all the parameters and does not allow to omit any argument,
  40. // this value must be equal to SCPI_ARGS_N_Q, or must be undefined. The command handler module
  41. // must include this header after defining this macro. All the optional command parameters are
  42. // located in the end of the argument set.
  43. // It is required to be defined together with SCPI_ARGS_MANDATORY_N_C.
  44. // Useless if SCPI_ARGS_MANDATORY_N is defined.
  45. // @SCPI_ARGS_MANDATORY_N_C macro:
  46. // Defines amount of mandatory SCPI-command arguments, not including optional ones, for COMMAND.
  47. // If the command requires all the parameters and does not allow to omit any argument,
  48. // this value must be be equal to SCPI_ARGS_N_C, or must be undefined. The command handler module
  49. // must include this header after defining this macro. All the optional command parameters are
  50. // located in the end of the argument set.
  51. // It is required to be defined together with SCPI_ARGS_MANDATORY_N_Q.
  52. // Useless if SCPI_ARGS_MANDATORY_N is defined.
  53. #define GC(_common_ctx_) ((sScpiParserContext_t*)((_common_ctx_)->global_ctx))
  54. #if !defined(SCPI_ARGS_HELPER_C)
  55. #ifndef SCPI_ARGS_N
  56. #if defined(SCPI_ARGS_N_Q) && !defined(SCPI_ARGS_N_C)
  57. #error The macro 'SCPI_ARGS_N_C' is undefined.
  58. #elif defined(SCPI_ARGS_N_C) && !defined(SCPI_ARGS_N_Q)
  59. #error The macro 'SCPI_ARGS_N_Q' is undefined.
  60. #elif !defined(SCPI_ARGS_N_C) && !defined(SCPI_ARGS_N_Q)
  61. #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.
  62. #endif
  63. #endif
  64. #if defined(SCPI_ARGS_N) && (SCPI_ARGS_N > SCPI_MAX_ARGS)
  65. #error Invalid value 'SCPI_ARGS_N'. Limit exceeded. See the limit 'SCPI_MAX_ARGS'.
  66. #endif
  67. #if defined(SCPI_ARGS_N_Q) && (SCPI_ARGS_N_Q > SCPI_MAX_ARGS)
  68. #error Invalid value 'SCPI_ARGS_N_Q'. Limit exceeded. See the limit 'SCPI_MAX_ARGS'.
  69. #endif
  70. #if defined(SCPI_ARGS_N_C) && (SCPI_ARGS_N_C > SCPI_MAX_ARGS)
  71. #error Invalid value 'SCPI_ARGS_N_C'. Limit exceeded. See the limit 'SCPI_MAX_ARGS'.
  72. #endif
  73. #if defined(SCPI_ARGS_N)
  74. #ifndef SCPI_ARGS_MANDATORY_N
  75. #define SCPI_ARGS_MANDATORY_N SCPI_ARGS_N
  76. #elif SCPI_ARGS_MANDATORY_N > SCPI_ARGS_N
  77. #error The value 'SCPI_ARGS_MANDATORY_N' shall not be greater than 'SCPI_ARGS_N'
  78. #endif
  79. #endif
  80. #if defined(SCPI_ARGS_N_Q) && defined(SCPI_ARGS_N_C)
  81. #ifndef SCPI_ARGS_MANDATORY_N_C
  82. #define SCPI_ARGS_MANDATORY_N_C SCPI_ARGS_N_C
  83. #elif SCPI_ARGS_MANDATORY_N_C > SCPI_ARGS_N_C
  84. #error The value 'SCPI_ARGS_MANDATORY_N_C' shall not be greater than 'SCPI_ARGS_N_C'
  85. #endif
  86. #ifndef SCPI_ARGS_MANDATORY_N_Q
  87. #define SCPI_ARGS_MANDATORY_N_Q SCPI_ARGS_N_Q
  88. #elif SCPI_ARGS_MANDATORY_N_Q > SCPI_ARGS_N_Q
  89. #error The value 'SCPI_ARGS_MANDATORY_N_Q' shall not be greater than 'SCPI_ARGS_N_Q'
  90. #endif
  91. #endif
  92. #else // scpi_args_helper.c
  93. #endif
  94. // ------------------------------------------------------------------------
  95. // @SCPI_ARGS_VAR_TOKENS
  96. // Default variable name for the string tokens array
  97. #define SCPI_ARGS_VAR_TOKENS argTokens
  98. #if defined(SCPI_ARGS_N)
  99. // @SCPI_ARGS_VAR_TYPES
  100. // Default variable name for the argument types array
  101. #define SCPI_ARGS_VAR_TYPES argTypes
  102. #endif
  103. #if defined(SCPI_ARGS_N_C) && defined(SCPI_ARGS_N_Q)
  104. // @SCPI_ARGS_VAR_TYPES_C
  105. // Default variable name for the argument types array (command only)
  106. #define SCPI_ARGS_VAR_TYPES_C argTypesCommand
  107. // @SCPI_ARGS_VAR_TYPES_Q
  108. // Default variable name for the argument types array (query only)
  109. #define SCPI_ARGS_VAR_TYPES_Q argTypesQuery
  110. #endif
  111. // ------------------------------------------------------------------------
  112. // @DECLARE_SCPI_ARGS macro:
  113. // Use this macro to decalre parser entities for command arguments.
  114. // @_VariableTypes_ - the name of the argument types array
  115. // The rest arguments of this macro are the set of SCPI_ARGS_N types of command
  116. // arguments (eScpiArgType_t), e.g.:
  117. // #define SCPI_ARGS_N 1
  118. // DECLARE_SCPI_ARGS( SCPI_ARGS_VAR_TYPES, eScpiArg_Character );
  119. #if defined(SCPI_ARGS_N)
  120. #if SCPI_ARGS_N == 0
  121. #define DECLARE_SCPI_ARGS(...)
  122. #else
  123. #define DECLARE_SCPI_ARGS(...) \
  124. static const uint8_t SCPI_ARGS_VAR_TYPES[ SCPI_ARGS_N ] = { __VA_ARGS__ };
  125. #endif
  126. #elif defined(SCPI_ARGS_N_C) && defined(SCPI_ARGS_N_Q)
  127. #if SCPI_ARGS_N_C == 0
  128. #define DECLARE_SCPI_ARGS_C(...)
  129. #else
  130. #define DECLARE_SCPI_ARGS_C(...) \
  131. static const uint8_t SCPI_ARGS_VAR_TYPES_C[ SCPI_ARGS_N_C ] = { __VA_ARGS__ };
  132. #endif
  133. #if SCPI_ARGS_N_Q == 0
  134. #define DECLARE_SCPI_ARGS_Q(...)
  135. #else
  136. #define DECLARE_SCPI_ARGS_Q(...) \
  137. static const uint8_t SCPI_ARGS_VAR_TYPES_Q[ SCPI_ARGS_N_Q ] = { __VA_ARGS__ };
  138. #endif
  139. #endif
  140. // Routine @parseArguments call helper
  141. #if defined(SCPI_ARGS_N)
  142. #define SCPI_PARSE_ARGUMENTS_C(_common_ctx_) (assert(false), 0)
  143. #define SCPI_PARSE_ARGUMENTS_Q(_common_ctx_) (assert(false), 0)
  144. #if SCPI_ARGS_N == 0
  145. #define SCPI_PARSE_ARGUMENTS(_common_ctx_) parseArguments_helper( (_common_ctx_), NULL, SCPI_ARGS_N, 0 )
  146. #else
  147. #define SCPI_PARSE_ARGUMENTS(_common_ctx_) parseArguments_helper( (_common_ctx_), SCPI_ARGS_VAR_TYPES, SCPI_ARGS_N, (SCPI_ARGS_N) - (SCPI_ARGS_MANDATORY_N) )
  148. #define SCPI_PARSE_ARRAY_ARGUMENTS(_common_ctx_) parseArrayArguments_helper( (_common_ctx_), SCPI_ARGS_VAR_TYPES, SCPI_ARGS_N, SCPI_ARGS_MANDATORY_N )
  149. #endif
  150. #elif defined(SCPI_ARGS_N_C) && defined(SCPI_ARGS_N_Q)
  151. #define SCPI_PARSE_ARGUMENTS(_common_ctx_) ((GC(_common_ctx_)->sMessage.bQuery)?\
  152. SCPI_PARSE_ARGUMENTS_Q(_common_ctx_):\
  153. SCPI_PARSE_ARGUMENTS_C(_common_ctx_))
  154. #if SCPI_ARGS_N_C == 0
  155. #define SCPI_PARSE_ARGUMENTS_C(_common_ctx_) parseArguments_helper( (_common_ctx_), NULL, SCPI_ARGS_N_C, 0 )
  156. #else
  157. #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) )
  158. #endif
  159. #if SCPI_ARGS_N_Q == 0
  160. #define SCPI_PARSE_ARGUMENTS_Q(_common_ctx_) parseArguments_helper( (_common_ctx_), NULL, SCPI_ARGS_N_Q, 0 )
  161. #else
  162. #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) )
  163. #endif
  164. #endif
  165. // ------------------------------------------------------------------------
  166. // @DECLARE_ARGUMENT_CHARACTER_ALLOWED_LIST
  167. // Declares an array of elements for SCPI Character Parameter value allowed list
  168. // Use this macro together with @processCharacterArgument to interpretate passed parameter.
  169. // @_name_ - variable name
  170. // @... - rest arguments is a "strings" that contain allowed values, e.g. "NORMal"
  171. #define DECLARE_ARGUMENT_CHARACTER_ALLOWED_LIST(_name_, ...) static const xArgument_t _name_[] = { __VA_ARGS__, NULL }
  172. // @DECLARE_ARGUMENT_CHARACTER_ALLOWED_LIST_EXPORT - the same as @DECLARE_ARGUMENT_CHARACTER_ALLOWED_LIST but declare
  173. // global variable that can be imported to another module.
  174. #define DECLARE_ARGUMENT_CHARACTER_ALLOWED_LIST_EXPORT(_name_, ...) const xArgument_t _name_[] = { __VA_ARGS__, NULL }
  175. // @DECLARE_ARGUMENT_CHARACTER_ALLOWED_LIST_IMPORT
  176. // Imports an array of elements for SCPI Character Parameter value allowed list that have been
  177. // declared with @DECLARE_ARGUMENT_CHARACTER_ALLOWED_LIST_EXPORT in other module.
  178. // Use this macro together with @processCharacterArgument to interpretate passed parameter.
  179. #define DECLARE_ARGUMENT_CHARACTER_ALLOWED_LIST_IMPORT(_name_) extern const xArgument_t _name_[];
  180. #define SCPI_ARGUMENT_CHARACTER_VALUE_TOKEN(_list_,_valueN_,_token_) scpi_argument_value_token(_list_,_valueN_,_token_)
  181. // ------------------------------------------------------------------------
  182. // @DECLARE_ARGUMENT_NUMERIC_VALUES_F64
  183. //
  184. #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_) }
  185. // @DECLARE_ARGUMENT_NUMERIC_VALUES_F32
  186. //
  187. #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_) }
  188. // @DECLARE_ARGUMENT_NUMERIC_VALUES_I64
  189. //
  190. #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_) }
  191. // @DECLARE_ARGUMENT_NUMERIC_VALUES_I32
  192. //
  193. #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_) }
  194. // @DECLARE_ARGUMENT_NUMERIC_VALUES_I16
  195. //
  196. #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_) }
  197. // @DECLARE_ARGUMENT_NUMERIC_VALUES_I8
  198. //
  199. #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_) }
  200. // ------------------------------------------------------------------------
  201. // Routine @processCharacterArgument call helper
  202. // * Macro group @SCPI_PROCESS_ARGUMENT_NUMERIC, @SCPI_PROCESS_ARGUMENT_C_NUMERIC, @SCPI_PROCESS_ARGUMENT_Q_NUMERIC
  203. // Process the numeric argument token and convert to the integer or float representation.
  204. // The result is the pointer to [sNumericEntry_t] structure, where the result is stored together the
  205. // value type and conversion error result.
  206. #if defined(SCPI_ARGS_N)
  207. #define SCPI_PROCESS_ARGUMENT_C_CHARACTER(_common_ctx_, _list_, _id_) (assert(false), 0)
  208. #define SCPI_PROCESS_ARGUMENT_Q_CHARACTER(_common_ctx_, _list_, _id_) (assert(false), 0)
  209. #define SCPI_PROCESS_ARGUMENT_C_NUMERIC(_common_ctx_, _range_, _id_) (assert(false), 0)
  210. #define SCPI_PROCESS_ARGUMENT_Q_NUMERIC(_common_ctx_, _range_, _id_) (assert(false), 0)
  211. #if SCPI_ARGS_N == 0
  212. #define SCPI_PROCESS_ARGUMENT_CHARACTER(_common_ctx_, _list_, _id_) (SCPI_ARGUMENT_CHARACTER_INVALID_ID)
  213. #define SCPI_PROCESS_ARGUMENT_NUMERIC(_common_ctx_, _range_, _id_) (false)
  214. #define SCPI_PROCESS_ARGUMENT_NUMERIC(_common_ctx_, _range_, _id_) (false)
  215. #define SCPI_PROCESS_ARGUMENT_ARRAY(_common_ctx_, _range_, _id_) (SCPI_ARGUMENT_CHARACTER_INVALID_ID)
  216. #else
  217. #define SCPI_PROCESS_ARGUMENT_CHARACTER(_common_ctx_, _list_, _id_) processArgument_Character_helper( (_common_ctx_), SCPI_ARGS_VAR_TYPES, _list_, _id_ )
  218. #define SCPI_PROCESS_ARGUMENT_NUMERIC(_common_ctx_, _range_, _id_) processArgument_Numeric_helper( (_common_ctx_), SCPI_ARGS_VAR_TYPES, _range_, _id_)
  219. #define SCPI_PROCESS_ARGUMENT_ARRAY(_common_ctx_, _range_, _id_, _result_arg_, _result_size_) processArgument_Array_helper( (_common_ctx_), _range_, _id_, _result_arg_, _result_size_)
  220. #endif
  221. #elif defined(SCPI_ARGS_N_C) && defined(SCPI_ARGS_N_Q)
  222. #define SCPI_PROCESS_ARGUMENT_CHARACTER(_common_ctx_, _list_, _id_) ((GC(_common_ctx_)->sMessage.bQuery)?\
  223. SCPI_PROCESS_ARGUMENT_Q_CHARACTER(_common_ctx_,_list_,_id_):\
  224. SCPI_PROCESS_ARGUMENT_C_CHARACTER(_common_ctx_,_list_,_id_))
  225. #define SCPI_PROCESS_ARGUMENT_NUMERIC(_common_ctx_, _range_, _id_) ((GC(_common_ctx_)->sMessage.bQuery)?\
  226. SCPI_PROCESS_ARGUMENT_Q_NUMERIC(_common_ctx_,_range_,_id_):\
  227. SCPI_PROCESS_ARGUMENT_C_NUMERIC(_common_ctx_,_range_,_id_))
  228. #if SCPI_ARGS_N_C == 0
  229. #define SCPI_PROCESS_ARGUMENT_C_CHARACTER(_common_ctx_, _list_, _id_) (SCPI_ARGUMENT_CHARACTER_INVALID_ID)
  230. #define SCPI_PROCESS_ARGUMENT_C_NUMERIC(_common_ctx_, _range_, _id_) (false)
  231. #else
  232. #define SCPI_PROCESS_ARGUMENT_C_CHARACTER(_common_ctx_, _list_, _id_) processArgument_Character_helper( (_common_ctx_), SCPI_ARGS_VAR_TYPES_C, _list_, _id_ )
  233. #define SCPI_PROCESS_ARGUMENT_C_NUMERIC(_common_ctx_, _range_, _id_) processArgument_Numeric_helper( (_common_ctx_), SCPI_ARGS_VAR_TYPES_C, _range_, _id_ )
  234. #endif
  235. #if SCPI_ARGS_N_Q == 0
  236. #define SCPI_PROCESS_ARGUMENT_Q_CHARACTER(_common_ctx_, _list_, _id_) (SCPI_ARGUMENT_CHARACTER_INVALID_ID)
  237. #define SCPI_PROCESS_ARGUMENT_Q_NUMERIC(_common_ctx_, _range_, _id_) (false)
  238. #else
  239. #define SCPI_PROCESS_ARGUMENT_Q_CHARACTER(_common_ctx_, _list_, _id_) processArgument_Character_helper( (_common_ctx_), SCPI_ARGS_VAR_TYPES_Q, _list_, _id_ )
  240. #define SCPI_PROCESS_ARGUMENT_Q_NUMERIC(_common_ctx_, _range_, _id_) processArgument_Numeric_helper( (_common_ctx_), SCPI_ARGS_VAR_TYPES_Q, _range_, _id_ )
  241. #define SCPI_PROCESS_ARGUMENT_Q_ARRAY(_common_ctx_, _range_, _id_) processArgument_Numeric_helper( (_common_ctx_), SCPI_ARGS_VAR_TYPES_Q, _range_, _id_ )
  242. #endif
  243. #endif
  244. #define SCPI_ARGUMENT_CHARACTER_INVALID_ID (-1)
  245. // @processArgument_Character_helper
  246. // Helper function. Used for convenient call of the other helper functions
  247. // Parameters:
  248. // @common_ctx - process program data state context, see @sProcessProgramDataCommonContext_t
  249. // @argTypes - array of argument types to set the parameters parsing methods (see @parseArguments, @eScpiArgType_t)
  250. // Other parameters: refer @processCharacterArgument
  251. // Returns: SCPI_ARGUMENT_CHARACTER_INVALID_ID in error case, or argument option index in @allowedList
  252. int8_t processArgument_Character_helper( void * common_ctx, const uint8_t * argTypes, const xArgument_t * allowedList, uint8_t argId );
  253. // @processArgument_Numeric_helper
  254. // Helper function. Used for convenient call of the other helper functions.
  255. // Processes the NUMERIC argument. See @processNumericArgument
  256. // Parameters:
  257. // @common_ctx - process program data state context, see @sProcessProgramDataCommonContext_t
  258. // @argTypes - array of argument types to set the parameters parsing methods (see @parseArguments, @eScpiArgType_t)
  259. // Other parameters: refer @processNumericArgument
  260. // Returns: pointer to the numeric entry descriptor with value and type, and the error code, or NULL
  261. // if @common_ctx is set to NULL.
  262. const sNumericEntry_t * processArgument_Numeric_helper( void * common_ctx, const uint8_t * argTypes, const sNumericRange_t * range, uint8_t argId );
  263. const sNumericEntry_t * processArgument_Array_helper( void * common_ctx, const sNumericRange_t * range, uint8_t argId, void * result_arg, uint16_t result_size);
  264. // @scpi_argument_value_token
  265. // Get the string tokens of the specified value in the allowed CHARACTER value list.
  266. // Parameters:
  267. // @list - allowed values list, see @DECLARE_ARGUMENT_CHARACTER_ALLOWED_LIST
  268. // @valueIndex - index in the array;
  269. // @pOutToken - string token to fill, can not be NULL;
  270. // Returns: filled string token (@pOutToken).
  271. // Note: if @valueList is out of range, NULL pointer is returned, and @pOutToken is unchanged.
  272. const sStrToken_t * scpi_argument_value_token( const xArgument_t * list, size_t valueIndex, sStrToken_t * pOutToken );
  273. #endif