#define SCPI_CORE_STATE__HANDLEERROR_GUARD #include "app/scpi/CommandParserStates/handle_error.h" #define SCPI_CORE_PRIVATE // access to 'scpi_core_private.h' #define SCPI_HANDLE_ERROR_C // access to some const variables in 'scpi_core_private.h' #include "app/scpi/scpi_core_private.h" #include "app/scpi/scpi_errq.h" //---------------------------------------------------------------- // Refer to: // [1] SCPI Specification, revision 1999.0 // "Standard Commands for Programmable Instruments (SCPI), VERSION 1999.0, May 1999" // [2] 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 // [3] 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 //---------------------------------------------------------------- // Refer "21.8.1 The Error/Event Queue", [1] // Refer "8.2.2 System sub-system", [2] // ================================================================================= // @sHandleErrorContext_t // State's private context typedef typedef struct { uint8_t lastEventCode; } sHandleErrorContext_t; // ================================================================================= // @ctx_HandleError // State's private context sHandleErrorContext_t ctx_HandleError; // ================================================================================= // @fsqvbl_HandleError // State's virtual table static void fsqe_HandleError( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx ); static void fsql_HandleError( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx ); static const struct fFSeqEntry_t * fsqf_HandleError( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx, const struct fFSeqEntry_t * * pnext ); const fFSeqVTable_t fsqvbl_HandleError = { .f = fsqf_HandleError, .enter = fsqe_HandleError, .leave = fsql_HandleError }; // ================================================================================= // @fsqe_HandleError // State's enter routine static void fsqe_HandleError( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx ) { sScpiParserContext_t * global_ctx = ctx; sHandleErrorContext_t * private_ctx = fsq_GetPrivateCtxRef(this); (void)global_ctx, (void)private_ctx; private_ctx->lastEventCode = global_ctx->sEvent.eCode; if( SCPI_ERROR_STATE != global_ctx->sExecution.runtimeError ) { if( ! errq_push( &global_ctx->sExecution.xScpiErrorQueue, global_ctx->sExecution.runtimeError, global_ctx->sExecution.xScpiErrorMessage ) ) { // Error Queue Overflow global_ctx->sExecution.errorQueueOverflow = true; // "21.8.1 The Error/Event Queue", [1] // "21.8.11 Device-Specific Error", [1] // "11.5.1.1.6 Bit 3 N Device-Specific ERROR (DDE)", [3] GPIBMachine.fGPIB_set_event_status_register_device_specific_error_state( &global_ctx->sGPIB.registers, true ); global_ctx->sExecution.runtimeError = SCPI_ERROR_SUCCESS; // clear error code global_ctx->sEvent.eStatus = eScpiStatus_success; // clear error status } else { // Notify GPIB: error available in the queue // "4 Instrument status", [2] // "4.1 Status Byte registers (STB and SRE)", [2] // "11.2.2.3 Master Summary Status", [4] // "11.3.2.4 Clearing the Service Request Enable Register", [3] GPIBMachine.fGPIB_set_error_available_bit( &global_ctx->sGPIB.registers, true ); switch( SCPI_ERROR_CLASS(global_ctx->sExecution.runtimeError) ) { // ------------ Reasons: -------------- // "6.1.6.1.1 Parser Errors", [3] // "6.5.4 Command Error", [3] case SCPI_ERROR_CLASS_COMMAND: GPIBMachine.fGPIB_set_event_status_register_command_error_state( &global_ctx->sGPIB.registers, true ); break; // ------------ Reasons: -------------- // "6.5.5 Execution Error", [3] // "11.5.1.1.5 Bit 4 N Execution ERROR (E)", [3] // "<...> the device shall continue parsing the input stream. <...>", [3] case SCPI_ERROR_CLASS_EXECUTION: GPIBMachine.fGPIB_set_event_status_register_execution_error_state( &global_ctx->sGPIB.registers, true ); // "11.5.1.1.5 Bit 4 N Execution ERROR (E)", [3] // "<...> the device shall continue parsing the input stream. <...>", [3] global_ctx->sEvent.eCode = eScpiEventContinue; // change event code to continue parsing break; // "11.5.1.1.6 Bit 3 N Device-Specific ERROR (DDE)", [3] case SCPI_ERROR_CLASS_DEVICE: GPIBMachine.fGPIB_set_event_status_register_device_specific_error_state( &global_ctx->sGPIB.registers, true ); break; // ------------ Reasons: -------------- // "6.3.1.3 QUERY State", [3] // "6.3.1.7 DEADLOCK State", [3] // "6.3.2.2 UNTERMINATED Action", [3] // "6.3.2.3 INTERRUPTED Action", [3] // "6.5.7 Query Error", [3] case SCPI_ERROR_CLASS_QUERY: GPIBMachine.fGPIB_set_event_status_register_query_error_state( &global_ctx->sGPIB.registers, true ); break; } global_ctx->sExecution.runtimeError = SCPI_ERROR_SUCCESS; // clear error code global_ctx->sEvent.eStatus = eScpiStatus_success; // clear error status } } } // ================================================================================= // @fsql_HandleError // State's leave routine static void fsql_HandleError( const struct fFSeqEntry_t * this, tFSeqCtx_t ctx ) { sScpiParserContext_t * global_ctx = ctx; sHandleErrorContext_t * private_ctx = fsq_GetPrivateCtxRef(this); (void)ctx, (void)private_ctx, (void)global_ctx; } // ================================================================================= // @fsqf_HandleError // State's body routine static const struct fFSeqEntry_t * fsqf_HandleError( 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; sHandleErrorContext_t * private_ctx = fsq_GetPrivateCtxRef(this); uint8_t nextEvent = eScpiEventEmpty; // -------------------------------------------------------------------------- switch( global_ctx->sEvent.eCode ) { case eScpiEventRestart: { // go to reset state nextstate = fsq_GetStateById(this,eParserResetState); } break; case eScpiEventContinue: { // Search for the following message unit separator // goto next state: eProcessEndOfProgramData nextstate = fsq_GetStateById(this,eProcessEndOfProgramData); nextEvent = private_ctx->lastEventCode; (void)global_ctx->sEvent.eStatus;; // already cleared } break; case eScpiEventError: // transport error { global_ctx->sEvent.eStatus = eScpiStatus_success; (void)nextstate; // keep this state } break; case eScpiEventRead: // read event during Error condition: case eScpiEventWrite: // command parse error -> error state { // Respond with empty string: if( global_ctx->sRead.nDataLength == 0 ) // no response in output buffer if( global_ctx->sRead.nBufferSize >= 1 ) // there is vacant room in output buffer { scpi_WriteCharOutput( ' ' ); // "Query error", "11.5.1.1.7 Bit 2", [3] // "An attempt is being made to read data from the Output Queue when no output is either present or pending" GPIBMachine.fGPIB_set_event_status_register_query_error_state( &global_ctx->sGPIB.registers, true ); } global_ctx->sEvent.eStatus = eScpiStatus_success; global_ctx->sMessage.r_bEndOfMessage = true; scpi_UpdateMessageAvailable(); (void)nextstate; // keep this state } break; } global_ctx->sEvent.eCode = nextEvent; return nextstate; }