process_command.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. #define SCPI_CORE_STATE__PROCESSCOMMAND_GUARD
  2. #include "app/scpi/CommandParserStates/process_command.h"
  3. #define SCPI_CORE_PRIVATE // access to 'scpi_core_private.h'
  4. #define SCPI_PROCESS_COMMAND_C // access to some const variables in 'scpi_core_private.h'
  5. #include "app/scpi/scpi_core_private.h"
  6. #include "app/scpi/scpi_commands.h"
  7. //----------------------------------------------------------------
  8. // Refer to:
  9. // [1] IEEE 488.2 Standard, revision IEEE Std 488.2-1987 (1992)
  10. // "IEEE Standard Codes, Formats, Protocols, and Common Commands for Use With IEEE Std 488.1-1987, IEEE
  11. // Standard Digital Interface for Programmable Instrumentation"
  12. // [2] SCPI Specification, revision 1999.0
  13. // "Standard Commands for Programmable Instruments (SCPI), VERSION 1999.0, May 1999"
  14. // [3] Gpib Programming Tutorial, (http://g2pc1.bu.edu/~qzpeng/gpib/manual/GpibProgTut.pdf)
  15. // Electronics Group (http://www.few.vu.nl/~elec), 11 January 2000 Electronics Group
  16. //----------------------------------------------------------------
  17. // =================================================================================
  18. // @sProcessCommandHeaderContext_t
  19. // State's private context typedef
  20. typedef struct
  21. {
  22. uint8_t eCmdHeader_type;
  23. bool bKeepParserContext;
  24. }
  25. sProcessCommandHeaderContext_t;
  26. // =================================================================================
  27. // @ctx_ProcessCommandHeader
  28. // State's private context
  29. sProcessCommandHeaderContext_t ctx_ProcessCommandHeader;
  30. // =================================================================================
  31. // @fsqvbl_ProcessCommandHeader
  32. // State's virtual table
  33. static void fsqe_ProcessCommandHeader( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
  34. static void fsql_ProcessCommandHeader( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
  35. static const struct fFSeqEntry_t * fsqf_ProcessCommandHeader( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx, const struct fFSeqEntry_t * * pDeferredNext );
  36. const fFSeqVTable_t fsqvbl_ProcessCommandHeader =
  37. {
  38. .f = fsqf_ProcessCommandHeader,
  39. .enter = fsqe_ProcessCommandHeader,
  40. .leave = fsql_ProcessCommandHeader
  41. };
  42. // =================================================================================
  43. // @fsqe_ProcessCommandHeader
  44. // State's enter routine
  45. static void fsqe_ProcessCommandHeader( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
  46. {
  47. sScpiParserContext_t * global_ctx = ctx;
  48. sProcessCommandHeaderContext_t * private_ctx = fsq_GetPrivateCtxRef(this);
  49. assert( private_ctx );
  50. assert( global_ctx );
  51. const char * pCmdHeader_shead = NULL;
  52. const char * pCmdHeader_stail = NULL;
  53. private_ctx->bKeepParserContext = false; // reset parser context at next call
  54. // @eCmdHeader_type: need to identify query/command (@eScpiEntityType_t)
  55. private_ctx->eCmdHeader_type = eScpiEntityTypeInvalid;
  56. // Retrieve the command header entity info:
  57. getParsedEntityDetails( &(global_ctx->sParser.xCtxObj),
  58. (void const**)&pCmdHeader_shead,
  59. (void const**)&pCmdHeader_stail,
  60. &private_ctx->eCmdHeader_type );
  61. assert( pCmdHeader_shead );
  62. assert( pCmdHeader_stail );
  63. assert( eScpiEntityTypeInvalid != private_ctx->eCmdHeader_type );
  64. // update current input buffer iterator
  65. global_ctx->sMessage.pStr = (const uint8_t*)pCmdHeader_stail;
  66. // search for command handler
  67. // [3], "3.4 Omitting the header path",
  68. // This first header is assumed to be found in the root branch. So, it is required to save
  69. // the branch if the command is found.
  70. global_ctx->sParser.xHandler = scpiSearchCommandHandler(
  71. (const sTreeList_t **)&global_ctx->sParser.xCmdBranch,
  72. pCmdHeader_shead,
  73. pCmdHeader_stail,
  74. private_ctx->eCmdHeader_type,
  75. &global_ctx->sParser.xHandlerToken,
  76. global_ctx->sParser.bFirstCommandIndicator );
  77. // reset the first command indicator
  78. global_ctx->sParser.bFirstCommandIndicator = false;
  79. if( NULL == global_ctx->sParser.xHandler )
  80. {
  81. global_ctx->sParser.xHandlerToken.shead = pCmdHeader_shead;
  82. global_ctx->sParser.xHandlerToken.stail = pCmdHeader_stail;
  83. // Enter error state
  84. fsq_RaiseError( SCPI_ERROR_UNDEFHEADER_ERROR, SCPI_ERROR_UNDEFHEADER_ERROR_MSG, pCmdHeader_shead, pCmdHeader_stail );
  85. }
  86. }
  87. // =================================================================================
  88. // @fsql_ProcessCommandHeader
  89. // State's leave routine
  90. static void fsql_ProcessCommandHeader( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
  91. {
  92. }
  93. // =================================================================================
  94. // @fsqf_ProcessCommandHeader
  95. // State's body routine
  96. static const struct fFSeqEntry_t * fsqf_ProcessCommandHeader( const struct fFSeqEntry_t * this,
  97. tFSeqCtx_t ctx,
  98. const struct fFSeqEntry_t * * pnext )
  99. {
  100. sScpiParserContext_t * global_ctx = ctx;
  101. sProcessCommandHeaderContext_t * private_ctx = fsq_GetPrivateCtxRef(this);
  102. const struct fFSeqEntry_t * nextstate = fsq_GetStateById(this,eHandleError); // go next state: eHandleError by default
  103. assert( private_ctx );
  104. assert( global_ctx );
  105. // Formal checking
  106. if( eScpiEventRestart == global_ctx->sEvent.eCode )
  107. {
  108. // go to reset state
  109. nextstate = fsq_GetStateById(this,eParserResetState);
  110. goto L_fsqf_ProcessCommandHeader_EXIT;
  111. }
  112. if( eScpiEventError == global_ctx->sEvent.eCode ) // Transport error.
  113. {
  114. // Enter error state
  115. nextstate = fsq_GetStateById(this,eHandleError); // enter the error state
  116. goto L_fsqf_ProcessCommandHeader_EXIT;
  117. }
  118. // check if has the handler been found:
  119. if( NULL == global_ctx->sParser.xHandler )
  120. {
  121. global_ctx->sEvent.eStatus = eScpiStatus_failed;
  122. // Note: impossible to complete parsing the rest part of the message
  123. // due to the data stage of the undefinded command can not be recognized.
  124. return nextstate; // Note: go to next state: eHandleError (default)
  125. }
  126. // It is required to skip Command Program Header separator ("7.4.3, [1]"):
  127. {
  128. // Retrieve the command header entity info to get the tail pointer if the last parsed entity:
  129. const char * shead = (const char *)global_ctx->sMessage.pStr;
  130. // determine the new tail pointer (@sWrite.nDataLength may change each call)
  131. const char * stail = (const char *)global_ctx->sMessage.pEnd;
  132. assert( shead <= stail );
  133. // In current step it is required to find command separator: header separator or message terminator.
  134. // If a command have a data parameter, the parser will find header separator (space), otherwise
  135. // the parser will find either message terminator (NL) or message separator (semicolon).
  136. // Declare a set of parser functions to use:
  137. eScpiParserStatus_t (* x_fParser[2])( xParseEntry_t * xObj ) =
  138. {
  139. parseProgramHeaderSeparator, // try to find program header separator (HEADER <SEP> DATA)
  140. parseProgramMessageSeparator // try to find program message separator (HEADER1 <SEP> HEADER2)
  141. };
  142. size_t iParserIdx = 0; // current parser index
  143. L_fsqf_ProcessCommandHeader_again: // marker to return
  144. // prepare parser context
  145. if( !prepareParserContext( &(global_ctx->sParser.xCtxObj), // re-use @xCtxObj object
  146. shead, // pass input buffer
  147. (stail - shead), // pass input buffer size
  148. global_ctx->sMessage.w_bEndOfMessage, // pass end-of-message by identifying the event
  149. private_ctx->bKeepParserContext ) ) // parser context keep indicator
  150. {
  151. global_ctx->sEvent.eStatus = eScpiStatus_invalid;
  152. (void)nextstate; // Note: go to next state: eHandleError (default)
  153. }
  154. else
  155. {
  156. global_ctx->sEvent.eStatus = eScpiStatus_failed; // forward set
  157. // try to call the parser only if index is not out of range
  158. if( iParserIdx < (sizeof(x_fParser)/sizeof(*x_fParser)) )
  159. {
  160. // 1. iParserIdx=0: parseProgramHeaderSeparator
  161. // 2. iParserIdx=1: parseProgramMessageSeparator
  162. global_ctx->sEvent.eStatus = x_fParser[iParserIdx++]( &(global_ctx->sParser.xCtxObj) );
  163. }
  164. // check status:
  165. switch( global_ctx->sEvent.eStatus )
  166. {
  167. // in case success:
  168. case eScpiStatus_success:
  169. {
  170. // successfully parsed: program command header separator
  171. // Retrieve the last parsed entity tail and
  172. // ... update current input buffer iterator @sMessage.pStr
  173. getParsedEntityDetails( &(global_ctx->sParser.xCtxObj),
  174. NULL,
  175. (void const**)&global_ctx->sMessage.pStr,
  176. NULL );
  177. (void)global_ctx->sMessage.pStr;
  178. assert( eScpiEventWrite == global_ctx->sEvent.eCode
  179. || eScpiEventRead == global_ctx->sEvent.eCode );
  180. assert( eScpiEntityTypeCmnQueryProgHdr == private_ctx->eCmdHeader_type ||
  181. eScpiEntityTypeCmpQueryProgHdr == private_ctx->eCmdHeader_type ||
  182. eScpiEntityTypeCmnCommandProgHdr == private_ctx->eCmdHeader_type ||
  183. eScpiEntityTypeCmpCommandProgHdr == private_ctx->eCmdHeader_type );
  184. bool eventProcess = false;
  185. // decode entity type to encode new event for next state
  186. switch( private_ctx->eCmdHeader_type )
  187. {
  188. // For command-type entities:
  189. case eScpiEntityTypeCmnCommandProgHdr:
  190. case eScpiEntityTypeCmpCommandProgHdr:
  191. {
  192. global_ctx->sMessage.bQuery = false; // Command type
  193. eventProcess = true;
  194. }
  195. break;
  196. // For query-type entities:
  197. case eScpiEntityTypeCmnQueryProgHdr:
  198. case eScpiEntityTypeCmpQueryProgHdr:
  199. {
  200. global_ctx->sMessage.bQuery = true; // Query type
  201. eventProcess = true;
  202. }
  203. break;
  204. default: // impossible
  205. eventProcess = false;
  206. }
  207. if( eventProcess )
  208. {
  209. // Command mnemonic successfully parsed
  210. // The command is ready to be executed
  211. // Restore parsing iterator to search command parameters
  212. global_ctx->sMessage.pStr = (const uint8_t*)global_ctx->sParser.xHandlerToken.stail;
  213. // prepare parser context
  214. if( !prepareParserContext( &(global_ctx->sParser.xCtxObj),
  215. global_ctx->sMessage.pStr, // pass input buffer
  216. (ptrdiff_t)global_ctx->sMessage.pEnd - (ptrdiff_t)global_ctx->sMessage.pStr, // pass input buffer size
  217. global_ctx->sMessage.w_bEndOfMessage, // pass end-of-message by identifying the event
  218. private_ctx->bKeepParserContext ) )
  219. {
  220. assert(false); // forbidden state
  221. global_ctx->sEvent.eStatus = eScpiStatus_failed;
  222. // Something went wrong...
  223. fsq_RaiseError( SCPI_ERROR_EXECUTION_ERROR, SCPI_ERROR_EXECUTION_ERROR_MSG,
  224. global_ctx->sParser.xHandlerToken.shead, global_ctx->sParser.xHandlerToken.stail );
  225. (void)nextstate; // Note: go to next state: eHandleError (default)
  226. }
  227. else
  228. {
  229. // Next station: data processing state, be careful, the state is about closing :)
  230. // go to next state: eProcessProgramData
  231. nextstate = fsq_GetStateById(this,eProcessProgramData);
  232. }
  233. }
  234. else
  235. {
  236. global_ctx->sEvent.eStatus = eScpiStatus_failed;
  237. assert(false); // forbidden state
  238. // Something went wrong...
  239. fsq_RaiseError( SCPI_ERROR_EXECUTION_ERROR, SCPI_ERROR_EXECUTION_ERROR_MSG,
  240. global_ctx->sParser.xHandlerToken.shead, global_ctx->sParser.xHandlerToken.stail );
  241. (void)nextstate; // Note: go to next state: eHandleError (default)
  242. }
  243. }
  244. break;
  245. case eScpiStatus_need_data:
  246. {
  247. private_ctx->bKeepParserContext = true; // keep parser context til next call
  248. nextstate = NULL; // NULL, do not change state
  249. }
  250. break;
  251. case eScpiStatus_failed:
  252. case eScpiStatus_invalid:
  253. default:
  254. {
  255. // try another parser
  256. if( iParserIdx < (sizeof(x_fParser)/sizeof(*x_fParser)) )
  257. {
  258. goto L_fsqf_ProcessCommandHeader_again;
  259. }
  260. // Enter error state
  261. fsq_RaiseError( SCPI_ERROR_COMMAND_HEADER_SEP, SCPI_ERROR_COMMAND_HEADER_SEP_MSG, global_ctx->sParser.xHandlerToken.shead, global_ctx->sParser.xHandlerToken.stail );
  262. (void)nextstate; // Note: go to next state: eHandleError (default)
  263. }
  264. break;
  265. }
  266. }
  267. }
  268. L_fsqf_ProcessCommandHeader_EXIT:
  269. return nextstate;
  270. }