| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328 |
- #define SCPI_CORE_STATE__PROCESSCOMMAND_GUARD
- #include "app/scpi/CommandParserStates/process_command.h"
- #define SCPI_CORE_PRIVATE // access to 'scpi_core_private.h'
- #define SCPI_PROCESS_COMMAND_C // access to some const variables in 'scpi_core_private.h'
- #include "app/scpi/scpi_core_private.h"
- #include "app/scpi/scpi_commands.h"
- //----------------------------------------------------------------
- // Refer to:
- // [1] IEEE 488.2 Standard, revision IEEE Std 488.2-1987 (1992)
- // "IEEE Standard Codes, Formats, Protocols, and Common Commands for Use With IEEE Std 488.1-1987, IEEE
- // Standard Digital Interface for Programmable Instrumentation"
- // [2] SCPI Specification, revision 1999.0
- // "Standard Commands for Programmable Instruments (SCPI), VERSION 1999.0, May 1999"
- // [3] Gpib Programming Tutorial, (http://g2pc1.bu.edu/~qzpeng/gpib/manual/GpibProgTut.pdf)
- // Electronics Group (http://www.few.vu.nl/~elec), 11 January 2000 Electronics Group
- //----------------------------------------------------------------
- // =================================================================================
- // @sProcessCommandHeaderContext_t
- // State's private context typedef
- typedef struct
- {
- uint8_t eCmdHeader_type;
- bool bKeepParserContext;
- }
- sProcessCommandHeaderContext_t;
- // =================================================================================
- // @ctx_ProcessCommandHeader
- // State's private context
- sProcessCommandHeaderContext_t ctx_ProcessCommandHeader;
- // =================================================================================
- // @fsqvbl_ProcessCommandHeader
- // State's virtual table
- static void fsqe_ProcessCommandHeader( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
- static void fsql_ProcessCommandHeader( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx );
- static const struct fFSeqEntry_t * fsqf_ProcessCommandHeader( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx, const struct fFSeqEntry_t * * pDeferredNext );
- const fFSeqVTable_t fsqvbl_ProcessCommandHeader =
- {
- .f = fsqf_ProcessCommandHeader,
- .enter = fsqe_ProcessCommandHeader,
- .leave = fsql_ProcessCommandHeader
- };
- // =================================================================================
- // @fsqe_ProcessCommandHeader
- // State's enter routine
- static void fsqe_ProcessCommandHeader( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
- {
- sScpiParserContext_t * global_ctx = ctx;
- sProcessCommandHeaderContext_t * private_ctx = fsq_GetPrivateCtxRef(this);
- assert( private_ctx );
- assert( global_ctx );
- const char * pCmdHeader_shead = NULL;
- const char * pCmdHeader_stail = NULL;
- private_ctx->bKeepParserContext = false; // reset parser context at next call
- // @eCmdHeader_type: need to identify query/command (@eScpiEntityType_t)
- private_ctx->eCmdHeader_type = eScpiEntityTypeInvalid;
-
- // Retrieve the command header entity info:
- getParsedEntityDetails( &(global_ctx->sParser.xCtxObj),
- (void const**)&pCmdHeader_shead,
- (void const**)&pCmdHeader_stail,
- &private_ctx->eCmdHeader_type );
- assert( pCmdHeader_shead );
- assert( pCmdHeader_stail );
- assert( eScpiEntityTypeInvalid != private_ctx->eCmdHeader_type );
-
- // update current input buffer iterator
- global_ctx->sMessage.pStr = (const uint8_t*)pCmdHeader_stail;
- // search for command handler
- // [3], "3.4 Omitting the header path",
- // This first header is assumed to be found in the root branch. So, it is required to save
- // the branch if the command is found.
- global_ctx->sParser.xHandler = scpiSearchCommandHandler(
- (const sTreeList_t **)&global_ctx->sParser.xCmdBranch,
- pCmdHeader_shead,
- pCmdHeader_stail,
- private_ctx->eCmdHeader_type,
- &global_ctx->sParser.xHandlerToken,
- global_ctx->sParser.bFirstCommandIndicator );
- // reset the first command indicator
- global_ctx->sParser.bFirstCommandIndicator = false;
- if( NULL == global_ctx->sParser.xHandler )
- {
- global_ctx->sParser.xHandlerToken.shead = pCmdHeader_shead;
- global_ctx->sParser.xHandlerToken.stail = pCmdHeader_stail;
- // Enter error state
- fsq_RaiseError( SCPI_ERROR_UNDEFHEADER_ERROR, SCPI_ERROR_UNDEFHEADER_ERROR_MSG, pCmdHeader_shead, pCmdHeader_stail );
- }
- }
- // =================================================================================
- // @fsql_ProcessCommandHeader
- // State's leave routine
- static void fsql_ProcessCommandHeader( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx )
- {
- }
- // =================================================================================
- // @fsqf_ProcessCommandHeader
- // State's body routine
- static const struct fFSeqEntry_t * fsqf_ProcessCommandHeader( const struct fFSeqEntry_t * this,
- tFSeqCtx_t ctx,
- const struct fFSeqEntry_t * * pnext )
- {
- sScpiParserContext_t * global_ctx = ctx;
- sProcessCommandHeaderContext_t * private_ctx = fsq_GetPrivateCtxRef(this);
- const struct fFSeqEntry_t * nextstate = fsq_GetStateById(this,eHandleError); // go next state: eHandleError by default
- assert( private_ctx );
- assert( global_ctx );
- // Formal checking
- if( eScpiEventRestart == global_ctx->sEvent.eCode )
- {
- // go to reset state
- nextstate = fsq_GetStateById(this,eParserResetState);
- goto L_fsqf_ProcessCommandHeader_EXIT;
- }
- if( eScpiEventError == global_ctx->sEvent.eCode ) // Transport error.
- {
- // Enter error state
- nextstate = fsq_GetStateById(this,eHandleError); // enter the error state
- goto L_fsqf_ProcessCommandHeader_EXIT;
- }
- // check if has the handler been found:
- if( NULL == global_ctx->sParser.xHandler )
- {
- global_ctx->sEvent.eStatus = eScpiStatus_failed;
- // Note: impossible to complete parsing the rest part of the message
- // due to the data stage of the undefinded command can not be recognized.
- return nextstate; // Note: go to next state: eHandleError (default)
- }
- // It is required to skip Command Program Header separator ("7.4.3, [1]"):
- {
- // Retrieve the command header entity info to get the tail pointer if the last parsed entity:
- const char * shead = (const char *)global_ctx->sMessage.pStr;
-
- // determine the new tail pointer (@sWrite.nDataLength may change each call)
- const char * stail = (const char *)global_ctx->sMessage.pEnd;
-
- assert( shead <= stail );
-
- // In current step it is required to find command separator: header separator or message terminator.
- // If a command have a data parameter, the parser will find header separator (space), otherwise
- // the parser will find either message terminator (NL) or message separator (semicolon).
- // Declare a set of parser functions to use:
- eScpiParserStatus_t (* x_fParser[2])( xParseEntry_t * xObj ) =
- {
- parseProgramHeaderSeparator, // try to find program header separator (HEADER <SEP> DATA)
- parseProgramMessageSeparator // try to find program message separator (HEADER1 <SEP> HEADER2)
- };
- size_t iParserIdx = 0; // current parser index
- L_fsqf_ProcessCommandHeader_again: // marker to return
- // prepare parser context
- if( !prepareParserContext( &(global_ctx->sParser.xCtxObj), // re-use @xCtxObj object
- shead, // pass input buffer
- (stail - shead), // pass input buffer size
- global_ctx->sMessage.w_bEndOfMessage, // pass end-of-message by identifying the event
- private_ctx->bKeepParserContext ) ) // parser context keep indicator
- {
- global_ctx->sEvent.eStatus = eScpiStatus_invalid;
- (void)nextstate; // Note: go to next state: eHandleError (default)
- }
- else
- {
- global_ctx->sEvent.eStatus = eScpiStatus_failed; // forward set
- // try to call the parser only if index is not out of range
- if( iParserIdx < (sizeof(x_fParser)/sizeof(*x_fParser)) )
- {
- // 1. iParserIdx=0: parseProgramHeaderSeparator
- // 2. iParserIdx=1: parseProgramMessageSeparator
- global_ctx->sEvent.eStatus = x_fParser[iParserIdx++]( &(global_ctx->sParser.xCtxObj) );
- }
- // check status:
- switch( global_ctx->sEvent.eStatus )
- {
- // in case success:
- case eScpiStatus_success:
- {
- // successfully parsed: program command header separator
- // Retrieve the last parsed entity tail and
- // ... update current input buffer iterator @sMessage.pStr
- getParsedEntityDetails( &(global_ctx->sParser.xCtxObj),
- NULL,
- (void const**)&global_ctx->sMessage.pStr,
- NULL );
- (void)global_ctx->sMessage.pStr;
- assert( eScpiEventWrite == global_ctx->sEvent.eCode
- || eScpiEventRead == global_ctx->sEvent.eCode );
- assert( eScpiEntityTypeCmnQueryProgHdr == private_ctx->eCmdHeader_type ||
- eScpiEntityTypeCmpQueryProgHdr == private_ctx->eCmdHeader_type ||
- eScpiEntityTypeCmnCommandProgHdr == private_ctx->eCmdHeader_type ||
- eScpiEntityTypeCmpCommandProgHdr == private_ctx->eCmdHeader_type );
-
- bool eventProcess = false;
- // decode entity type to encode new event for next state
- switch( private_ctx->eCmdHeader_type )
- {
- // For command-type entities:
- case eScpiEntityTypeCmnCommandProgHdr:
- case eScpiEntityTypeCmpCommandProgHdr:
- {
- global_ctx->sMessage.bQuery = false; // Command type
- eventProcess = true;
- }
- break;
- // For query-type entities:
- case eScpiEntityTypeCmnQueryProgHdr:
- case eScpiEntityTypeCmpQueryProgHdr:
- {
- global_ctx->sMessage.bQuery = true; // Query type
- eventProcess = true;
- }
- break;
- default: // impossible
- eventProcess = false;
- }
- if( eventProcess )
- {
- // Command mnemonic successfully parsed
- // The command is ready to be executed
- // Restore parsing iterator to search command parameters
- global_ctx->sMessage.pStr = (const uint8_t*)global_ctx->sParser.xHandlerToken.stail;
- // prepare parser context
- if( !prepareParserContext( &(global_ctx->sParser.xCtxObj),
- global_ctx->sMessage.pStr, // pass input buffer
- (ptrdiff_t)global_ctx->sMessage.pEnd - (ptrdiff_t)global_ctx->sMessage.pStr, // pass input buffer size
- global_ctx->sMessage.w_bEndOfMessage, // pass end-of-message by identifying the event
- private_ctx->bKeepParserContext ) )
- {
- assert(false); // forbidden state
- global_ctx->sEvent.eStatus = eScpiStatus_failed;
- // Something went wrong...
- fsq_RaiseError( SCPI_ERROR_EXECUTION_ERROR, SCPI_ERROR_EXECUTION_ERROR_MSG,
- global_ctx->sParser.xHandlerToken.shead, global_ctx->sParser.xHandlerToken.stail );
- (void)nextstate; // Note: go to next state: eHandleError (default)
- }
- else
- {
- // Next station: data processing state, be careful, the state is about closing :)
- // go to next state: eProcessProgramData
- nextstate = fsq_GetStateById(this,eProcessProgramData);
- }
- }
- else
- {
- global_ctx->sEvent.eStatus = eScpiStatus_failed;
-
- assert(false); // forbidden state
- // Something went wrong...
- fsq_RaiseError( SCPI_ERROR_EXECUTION_ERROR, SCPI_ERROR_EXECUTION_ERROR_MSG,
- global_ctx->sParser.xHandlerToken.shead, global_ctx->sParser.xHandlerToken.stail );
-
- (void)nextstate; // Note: go to next state: eHandleError (default)
- }
- }
- break;
- case eScpiStatus_need_data:
- {
- private_ctx->bKeepParserContext = true; // keep parser context til next call
- nextstate = NULL; // NULL, do not change state
- }
- break;
-
- case eScpiStatus_failed:
- case eScpiStatus_invalid:
- default:
- {
- // try another parser
- if( iParserIdx < (sizeof(x_fParser)/sizeof(*x_fParser)) )
- {
- goto L_fsqf_ProcessCommandHeader_again;
- }
- // Enter error state
- fsq_RaiseError( SCPI_ERROR_COMMAND_HEADER_SEP, SCPI_ERROR_COMMAND_HEADER_SEP_MSG, global_ctx->sParser.xHandlerToken.shead, global_ctx->sParser.xHandlerToken.stail );
- (void)nextstate; // Note: go to next state: eHandleError (default)
- }
- break;
- }
- }
- }
- L_fsqf_ProcessCommandHeader_EXIT:
- return nextstate;
- }
|