#define SCPI_CORE_STATE__SEARCH4COMMAND_GUARD #include "app/scpi/CommandParserStates/search_for_command.h" #define SCPI_CORE_PRIVATE // access to 'scpi_core_private.h' #include "app/scpi/scpi_core_private.h" // ================================================================================= // @sSearchForCommandHeaderContext_t // State's private context typedef typedef struct { bool bKeepParserContext; } sSearchForCommandHeaderContext_t; // ================================================================================= // @ctx_SearchForCommandHeader // State's private context sSearchForCommandHeaderContext_t ctx_SearchForCommandHeader; // ================================================================================= // @fsqvbl_SearchForCommandHeader // State's virtual table static void fsqe_SearchForCommandHeader( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx ); static void fsql_SearchForCommandHeader( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx ); static const struct fFSeqEntry_t * fsqf_SearchForCommandHeader( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx, const struct fFSeqEntry_t * * pnext ); const fFSeqVTable_t fsqvbl_SearchForCommandHeader = { .f = fsqf_SearchForCommandHeader, .enter = fsqe_SearchForCommandHeader, .leave = fsql_SearchForCommandHeader }; // ================================================================================= // @fsqe_SearchForCommandHeader // State's enter routine static void fsqe_SearchForCommandHeader( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx ) { sScpiParserContext_t * global_ctx = ctx; sSearchForCommandHeaderContext_t * private_ctx = fsq_GetPrivateCtxRef(this); private_ctx->bKeepParserContext = false; (void)global_ctx; } // ================================================================================= // @fsql_SearchForCommandHeader // State's leave routine static void fsql_SearchForCommandHeader( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx ) { sScpiParserContext_t * global_ctx = ctx; sSearchForCommandHeaderContext_t * private_ctx = fsq_GetPrivateCtxRef(this); (void)ctx, (void)private_ctx; (void)global_ctx; } // ================================================================================= // @fsqf_SearchForCommandHeader // State's body routine static const struct fFSeqEntry_t * fsqf_SearchForCommandHeader( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx, const struct fFSeqEntry_t * * pDeferredNext ) { // -------------------------------------------------------------------------- const struct fFSeqEntry_t * nextstate = NULL; // do not change state, do not call next state sScpiParserContext_t * global_ctx = ctx; sSearchForCommandHeaderContext_t * private_ctx = fsq_GetPrivateCtxRef(this); // -------------------------------------------------------------------------- // Handle events: switch( global_ctx->sEvent.eCode ) { case eScpiEventRestart: { nextstate = fsq_GetStateById(this,eParserResetState); } break; case eScpiEventWrite: // Handle the WRITE event case eScpiEventRead: // Handle the READ event { // 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 ) ) { global_ctx->sEvent.eStatus = eScpiStatus_invalid; } else { // parse the command program header global_ctx->sEvent.eStatus = parseCommandProgramHeader( &(global_ctx->sParser.xCtxObj) ); switch( global_ctx->sEvent.eStatus ) { case eScpiStatus_success: { // successfully parsed // go to next state: eProcessCommandHeader nextstate = fsq_GetStateById(this,eProcessCommandHeader); } break; case eScpiStatus_need_data: { private_ctx->bKeepParserContext = true; (void)nextstate; // keep NULL, do not change state } break; case eScpiStatus_failed: case eScpiStatus_invalid: { const char * start = NULL; const char * stop = NULL; uint8_t type; if( getParsedEntityDetails( &(global_ctx->sParser.xCtxObj), (const void**)&start, (const void**)&stop, &type ) ) { // check for empty-line command string if( scpi_isnl(*start) ) { // requested string is an empty-line command string, and the parser error is obviously can not be generated // But it is required to enter the error state because only the error state is legal next state. // It is impossible to restart the parser because maybe there are some data in output buffer to sent. } else { // Check if the last character is '\n' and cut it off if( scpi_isnl((*(stop-1))) && (0 < (stop - start)) ) stop--; int32_t error; const char * msg = getParserError( &(global_ctx->sParser.xCtxObj), &error ); if( NULL == msg ) { error = SCPI_ERROR_COMMAND_HEADER; msg = SCPI_ERROR_COMMAND_HEADER_MSG; } fsq_RaiseError( error, msg, start, stop ); } } else { #if 0 int32_t error; const char * msg = getParserError( &(global_ctx->sParser.xCtxObj), &error ); if( NULL == msg ) { error = SCPI_ERROR_COMMAND_HEADER; msg = SCPI_ERROR_COMMAND_HEADER_MSG; } fsq_RaiseError( error, msg, NULL, 0 ); #else assert( false ); #endif } nextstate = fsq_GetStateById(this,eHandleError); // enter the error state } break; } } } break; case eScpiEventError: // Transport error. { // Enter error state nextstate = fsq_GetStateById(this,eHandleError); // enter the error state } break; } (void)global_ctx->sEvent.eCode; // keep event code, it will be reused in @eProcessProgramData state return nextstate; }