| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711 |
- #define SCPI_CORE_PRIVATE // access to 'scpi_core_private.h'
- #define SCPI_CORE_C // access to const values in 'scpi_core_private.h' structures
- #include "app/scpi/scpi_core.h"
- #include "app/scpi/scpi_core_private.h"
- #include "app/scpi/scpi_parser.h"
- #include "app/scpi/scpi_commands.h"
- #include "app/scpi/scpi_errq.h"
- #include "app/scpi/CommandParserStates/reset_state.h"
- #include "app/scpi/CommandParserStates/search_for_command.h"
- #include "app/scpi/CommandParserStates/process_command.h"
- #include "app/scpi/CommandParserStates/process_data.h"
- #include "app/scpi/CommandParserStates/endof_process_data.h"
- #include "app/scpi/CommandParserStates/handle_error.h"
- #include <stdio.h>
- #include "my_assert.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] "Programming Guide", "Keysight Models 664xA, 665xA, 667xA, 668xA, and 669xA GPIB DC Power Supplies", Edition 2, December 2014, "5964-8269"
- static eScpiStatus_t fSCPIInit( );
- static eScpiStatus_t fSCPIReset( );
- static eScpiStatus_t fSCPINewOutTransfer( );
- static eScpiStatus_t fSCPIWrite( const uint8_t * pData, size_t nDataLen, bool bEndOfMessage, bool bNewTransfer );
- static eScpiStatus_t fSCPIRead( uint8_t * pBuffer, size_t nBufferLen, size_t * pnBytesOut, bool *pEOM );
- static eScpiStatus_t fSCPINotificationRead( uint8_t * pBuffer, size_t nBufferLen, size_t * pnBytesOut, uint8_t * pSTB );
- static eScpiStatus_t fSCPIError( int32_t error, const void * errorCtx );
- static eScpiStatus_t fSCPIDeInit();
- const sSCPILibHandle_t sSCPILibHandle = {
- .fInit = fSCPIInit,
- .fReset = fSCPIReset,
- .fNewTransfer = fSCPINewOutTransfer,
- .fWrite = fSCPIWrite,
- .fRead = fSCPIRead,
- .fNotificationRead = fSCPINotificationRead,
- .fError = fSCPIError,
- .fDeInit = fSCPIDeInit
- };
- // -----------------------------------------------------------
- // @seqScpiProcessor
- // The SCPI module functor-sequencer for command iterator
- static xFSeqObj_t seqScpiProcessor;
- // -----------------------------------------------------------
- // @ctx_ScpiParser
- // SCPI parser common context
- static sScpiParserContext_t ctx_ScpiParser;
- // -----------------------------------------------------------
- const sScpiParserStateEntry_t sParserStateMap[] = {
- // State: eParserResetState
- [eParserResetState] = SCPI_STATE_PARSERRESETSTATE,
-
- // State: SearchForCommandHeader
- [eSearchForCommandHeader] = SCPI_STATE_SEARCH4COMMAND,
-
- // State: ProcessCommandHeader
- [eProcessCommandHeader] = SCPI_STATE_PROCESSCOMMAND,
- // State: ProcessProgramData
- [eProcessProgramData] = SCPI_STATE_PROCESSDATA,
- // State: EndOfProcessProgramData
- [eProcessEndOfProgramData] = SCPI_STATE_ENDOFPROCESSDATA,
- // State: HandleError
- [eHandleError] = SCPI_STATE_HANDLEERROR,
- };
- // -----------------------------------------------------------
- // @fsq_GetPrivateCtxRef
- // Get access to the state's private context by pointer
- // @this - the state entry, passed into main state function, or
- // ... entry-/leave- routines.
- // Returns: the state private context pointer that represented by the
- // @ctx_ref field in @sScpiParserStateEntry_t structure.
- void * fsq_GetPrivateCtxRef( const struct fFSeqEntry_t * this )
- {
- // Refer to: @sParserStateMap[], @sScpiParserStateEntry_t
- const sScpiParserStateEntry_t * container = (const sScpiParserStateEntry_t *)this;
- return container->ctx_ref;
- }
- // -----------------------------------------------------------
- // @fsq_GetStateById_unsafe
- // Get the state entry by state identifier @sid
- // @sid - the state identifier (eScpiParserStateId_t)
- // Returns: the state entry pointer
- static const struct fFSeqEntry_t * fsq_GetStateById_unsafe( eScpiParserStateId_t sid )
- {
- if( sid < cellsof(sParserStateMap) )
- return &sParserStateMap[sid].entry;
- return NULL;
- }
- // -----------------------------------------------------------
- // @fsq_GetStateById
- // Get the state entry by state identifier @sid
- // @this - current state pointer
- // @sid - the state identifier (eScpiParserStateId_t)
- // Returns: the state entry pointer
- // Note: the caller must be the state from the same entity
- const struct fFSeqEntry_t * fsq_GetStateById( const struct fFSeqEntry_t * this, eScpiParserStateId_t sid )
- {
- my_assert( sid < cellsof(sParserStateMap) );
- if( sid < cellsof(sParserStateMap) )
- {
- ptrdiff_t range_begin = (ptrdiff_t)&sParserStateMap[0];
- ptrdiff_t range_end = (ptrdiff_t)&sParserStateMap[ cellsof(sParserStateMap) - 1 ];
- my_assert( (ptrdiff_t)this >= range_begin && (ptrdiff_t)this <= range_end );
- if( (ptrdiff_t)this >= range_begin && (ptrdiff_t)this <= range_end )
- return &sParserStateMap[sid].entry;
- }
- return NULL;
- }
- // -----------------------------------------------------------
- // @fsq_RaiseErrorEx
- // Generate internal error event to place it into SCPI Error Log
- // @scpiError - SCPI error code
- // @msgHandler - optional null-terminated string prefix, if exist, the function also adds additional prefix with error number
- // @msgDescription - optional string message with @msgDescLength length
- // @msgDescriptionEnd - end of optional message string, is used to determine the string length (@msgDescription)
- // @msgDescriptionEx - extended optional string message with @msgDescLength length
- // @msgDescriptionEndEx - end of extended optional message string, is used to determine the string length (@msgDescriptionEx)
- void fsq_RaiseErrorEx( int scpiError, const char * msgHeader, const char * msgDescription, const char * msgDescriptionEnd,
- const char * msgDescriptionEx, const char * msgDescriptionEndEx )
- {
- ctx_ScpiParser.sExecution.runtimeError = scpiError;
- size_t nPos = 0;
- size_t nSize = SCPI_ERRORMSG_MAX - 1;
- if( NULL != msgHeader )
- {
- char errNumber[8] = { '\0' };
- _snprintf( errNumber, sizeof(errNumber), "%d, ", scpiError );
- size_t plen = strlen( errNumber );
- if( plen < nSize )
- {
- strcpy( &ctx_ScpiParser.sExecution.xScpiErrorMessage[nPos], errNumber );
- nSize -= plen;
- nPos += plen;
- }
- plen = strlen( msgHeader );
- my_assert( plen < SCPI_ERRORMSG_MAX );
- if( plen < nSize )
- {
- strcpy( &ctx_ScpiParser.sExecution.xScpiErrorMessage[nPos], msgHeader );
- nSize -= plen;
- nPos += plen;
- }
- }
- if( NULL == msgDescription || NULL == msgDescriptionEnd )
- {
- msgDescription = msgDescriptionEx;
- msgDescriptionEnd = msgDescriptionEndEx;
- msgDescriptionEx = NULL;
- msgDescriptionEndEx = NULL;
- }
- if( NULL != msgDescription && NULL != msgDescriptionEnd )
- {
- // remove trailing NL-character
- if( scpi_isnl( *(msgDescriptionEnd-1) ) )
- {
- msgDescriptionEnd--;
- }
- if( (ptrdiff_t)msgDescriptionEnd - (ptrdiff_t)msgDescription == 0 )
- {
- msgDescription = msgDescriptionEx;
- msgDescriptionEnd = msgDescriptionEndEx;
- msgDescriptionEx = NULL;
- msgDescriptionEndEx = NULL;
- }
- if( (ptrdiff_t)msgDescriptionEnd - (ptrdiff_t)msgDescription > 0 )
- {
- size_t msgDescLength = (ptrdiff_t)msgDescriptionEnd - (ptrdiff_t)msgDescription;
- size_t plen = msgDescLength;
- if( NULL != msgHeader )
- {
- // Default message mode: @msgHeader and @msgDescription
- const char prfstr[] = ": '"; plen += strlen(prfstr);
- const char psfstr[] = "'"; plen += strlen(psfstr);
- if( plen < nSize )
- {
- // Full message fits to the buffer
- strcpy( &ctx_ScpiParser.sExecution.xScpiErrorMessage[nPos], prfstr );
- strncat( ctx_ScpiParser.sExecution.xScpiErrorMessage, msgDescription, msgDescLength );
- strcat( ctx_ScpiParser.sExecution.xScpiErrorMessage, psfstr );
- }
- else
- {
- const char sfxstr[] = "..."; plen = strlen(sfxstr);
- plen += strlen(prfstr);
- plen += strlen(psfstr);
- // there is free space for a part of description?
- if( nSize >= plen )
- {
- msgDescLength = nSize - plen;
- if( msgDescLength > 8 )
- {
- strcpy( &ctx_ScpiParser.sExecution.xScpiErrorMessage[nPos], prfstr );
- strncat( ctx_ScpiParser.sExecution.xScpiErrorMessage, msgDescription, msgDescLength );
- strcat( ctx_ScpiParser.sExecution.xScpiErrorMessage, sfxstr );
- strcat( ctx_ScpiParser.sExecution.xScpiErrorMessage, psfstr );
- plen += msgDescLength;
- }
- else
- plen = 0;
- }
- else
- plen = 0;
- }
- }
- else
- {
- // Custom message mode: Only @msgDescription
- if( plen < nSize )
- {
- strncpy( &ctx_ScpiParser.sExecution.xScpiErrorMessage[nPos], msgDescription, msgDescLength );
- }
- else
- {
- plen = 0;
- }
- }
- nSize -= plen;
- nPos += plen;
- }
- }
- if( NULL != msgDescriptionEx && NULL != msgDescriptionEndEx )
- {
- // remove trailing NL-character
- if( scpi_isnl( *(msgDescriptionEndEx-1) ) )
- {
- msgDescriptionEndEx--;
- }
- if( (ptrdiff_t)msgDescriptionEndEx - (ptrdiff_t)msgDescriptionEx > 0 )
- {
- size_t msgDescLength = (ptrdiff_t)msgDescriptionEndEx - (ptrdiff_t)msgDescriptionEx;
- size_t plen = msgDescLength;
- if( NULL != msgHeader || NULL != msgDescription )
- {
- // Default message mode: @msgHeader or @msgDescription already exist
- const char prfstr[] = " in '"; plen += strlen(prfstr);
- const char psfstr[] = "'"; plen += strlen(psfstr);
- if( plen < nSize )
- {
- // Full message fits to the buffer
- strcpy( &ctx_ScpiParser.sExecution.xScpiErrorMessage[nPos], prfstr );
- strncat( ctx_ScpiParser.sExecution.xScpiErrorMessage, msgDescriptionEx, msgDescLength );
- strcat( ctx_ScpiParser.sExecution.xScpiErrorMessage, psfstr );
- }
- else
- {
- const char sfxstr[] = "..."; plen = strlen(sfxstr);
- plen += strlen(prfstr);
- plen += strlen(psfstr);
- // there is free space for a part of description?
- if( nSize >= plen )
- {
- msgDescLength = nSize - plen;
- if( msgDescLength > 12 )
- {
- strcpy( &ctx_ScpiParser.sExecution.xScpiErrorMessage[nPos], prfstr );
- strncat( ctx_ScpiParser.sExecution.xScpiErrorMessage, msgDescriptionEx, msgDescLength );
- strcat( ctx_ScpiParser.sExecution.xScpiErrorMessage, sfxstr );
- strcat( ctx_ScpiParser.sExecution.xScpiErrorMessage, psfstr );
- plen += msgDescLength;
- }
- else
- plen = 0;
- }
- else
- plen = 0;
- }
- }
- else
- {
- // Custom message mode: Only @msgDescriptionEx
- if( plen < nSize )
- {
- strncpy( &ctx_ScpiParser.sExecution.xScpiErrorMessage[nPos], msgDescriptionEx, msgDescLength );
- }
- else
- {
- plen = 0;
- }
- }
- nSize -= plen;
- nPos += plen;
- }
- }
- ctx_ScpiParser.sExecution.xScpiErrorMessage[nPos] = '\0';
- }
- // -----------------------------------------------------------
- // @fsq_RaiseError
- // Generate internal error event to place it into SCPI Error Log
- // @scpiError - SCPI error code
- // @msgHandler - optional null-terminated string prefix, if exist, the function also adds additional prefix with error number
- // @msgDescription - optional string message with @msgDescLength length
- // @msgDescriptionEnd - end of optional message string, is used to determine the string length (@msgDescription)
- void fsq_RaiseError( int scpiError, const char * msgHeader, const char * msgDescription, const char * msgDescriptionEnd )
- {
- fsq_RaiseErrorEx( scpiError, msgHeader, msgDescription, msgDescriptionEnd, NULL, NULL );
- }
- // -----------------------------------------------------------
- int32_t scpi_WriteChunkOutput( const void * src, size_t length )
- {
- // This routine may be called even if no output buffer is prepared.
- // Check it
- if( NULL == ctx_ScpiParser.sRead.pBufferIdx
- || 0 == ctx_ScpiParser.sRead.nBufferSize
- || NULL == ctx_ScpiParser.sRead.pBuffer )
- {
- return 0;
- }
- size_t chunkSize = ((ctx_ScpiParser.sRead.nBufferSize > length)? length : ctx_ScpiParser.sRead.nBufferSize); // min(nBufferSize, length)
- if( chunkSize > 0 )
- {
- memcpy( ctx_ScpiParser.sRead.pBufferIdx, src, chunkSize );
- ctx_ScpiParser.sRead.pBufferIdx += chunkSize;
- ctx_ScpiParser.sRead.nDataLength += chunkSize;
- ctx_ScpiParser.sRead.nTotalLength += chunkSize;
- ctx_ScpiParser.sRead.nBufferSize -= chunkSize;
- }
- return chunkSize;
- }
- int32_t scpi_WriteCharOutput( uint8_t ch )
- {
- return scpi_WriteChunkOutput( &ch, sizeof(ch) );
- }
- // -----------------------------------------------------------
- // @scpi_UpdateMessageAvailable
- // Updates the message available status, MAV
- // "6.1.10.2.1 Message Available Message (MAV)", [1]
- void scpi_UpdateMessageAvailable()
- {
- // Check if .sRead structure is available:
- // Note this routine can be called on Read and Write events not only from SCPI-core, but
- // by changing Write event to Read event, in this case .sRead structure is initialized.
- if( (NULL != ctx_ScpiParser.sRead.pBuffer) && (0 != ctx_ScpiParser.sRead.nBufferSize) )
- {
- // Message available: only if EOM is reset the MAV is set if is there data in the output buffer.
- // Otherwise, if EOM is set, these bytes will be send as soon as possible, so this means there no data to send anymore
- // in SCPI core.
- bool message_available = (ctx_ScpiParser.sRead.nDataLength > 0) && (!ctx_ScpiParser.sMessage.r_bEndOfMessage);
- // Is there data to send to host: set Message-Available indicator
- GPIBMachine.fGPIB_set_message_available_bit( &ctx_ScpiParser.sGPIB.registers, message_available );
- }
- }
- // -----------------------------------------------------------
- // @GPIB_Init
- // Initialize the GPIB machine state to the startup defaults
- static void GPIB_Init()
- {
- GPIBMachine.fGPIB_set_event_status_enable_register( &ctx_ScpiParser.sGPIB.registers, 0 ); // Reset ESE
- GPIBMachine.fGPIB_set_service_request_enable_register( &ctx_ScpiParser.sGPIB.registers, 0 ); // Reset SRE
- GPIBMachine.fGPIB_set_event_summary_enable_state( &ctx_ScpiParser.sGPIB.registers, true ); // Set SRE.ESB
- GPIBMachine.fGPIB_set_message_available_enable_state( &ctx_ScpiParser.sGPIB.registers, true ); // Set SRE.MAV
- GPIBMachine.fGPIB_set_error_available_enable_state( &ctx_ScpiParser.sGPIB.registers, true ); // Set SRE.EAV
- // "11.5.1.1.2 Bit 7 - Power On (PON)", [1]
- // "6.1.8.2.1 Power-On Message (pon)", [1]
- // "6.3.1.1 IDLE State", [1]
- // "The PON (Power-On) Bit", "Service Request Enable Register", [2]
- GPIBMachine.fGPIB_set_event_status_register_power_on_state( &ctx_ScpiParser.sGPIB.registers, true ); // Set ESR.PON
- // "5.6.1 Control and Operation Definitions", [1]
- GPIBMachine.fGPIB_set_event_status_register_user_request_state( &ctx_ScpiParser.sGPIB.registers, false );
- // "11.5.1.1.4 Bit 5 - Command ERROR (CME)", [1]
- GPIBMachine.fGPIB_set_event_status_register_command_error_state( &ctx_ScpiParser.sGPIB.registers, false );
- // "11.5.1.1.5 Bit 4 - Execution ERROR (E)", [1]
- GPIBMachine.fGPIB_set_event_status_register_execution_error_state( &ctx_ScpiParser.sGPIB.registers, false );
- // "11.5.1.1.6 Bit 3 - Device-Specific ERROR (DDE)", [1]
- GPIBMachine.fGPIB_set_event_status_register_device_specific_error_state( &ctx_ScpiParser.sGPIB.registers, false );
- // "11.5.1.1.7 Bit 2 - Query ERROR (QYE)", [1]
- GPIBMachine.fGPIB_set_event_status_register_query_error_state( &ctx_ScpiParser.sGPIB.registers, false );
- // "11.5.1.1.8 Bit 1 - Request Control (RQC)", [1]
- GPIBMachine.fGPIB_set_event_status_register_request_control_state( &ctx_ScpiParser.sGPIB.registers, false );
- // Set OPC:
- // Note, since the device supports only syncrounious commands, the OPC can be set once and have never been reset.
- // "11.5.1.1.9 Bit 0 - Operation Complete (OPC)", [1]
- // "<...> This event bit is generated in response to the *OPC command. <...>"
- GPIBMachine.fGPIB_set_event_status_register_operation_complete_state( &ctx_ScpiParser.sGPIB.registers, false );
- // "11.3.3 Service Request Generation", [1]
- // Service Request Generation - reset status
- GPIBMachine.fGPIB_set_service_request_status( &ctx_ScpiParser.sGPIB.registers, false );
- }
- // -----------------------------------------------------------
- // @fSCPIInit
- // Initialize parser
- static eScpiStatus_t fSCPIInit()
- {
- // prepare global context: see @eParserResetState state dispatch function
- (void)ctx_ScpiParser;
-
- // construct state machine object, link the first state 'eSearchForCommandHeader'
- fSeqConstruct( &seqScpiProcessor, fsq_GetStateById_unsafe(eParserResetState), &ctx_ScpiParser );
- // Initialize SCPI Error Log Queue
- ctx_ScpiParser.sExecution.errorQueueOverflow = false; // reset overflow indicator
- bool errqrc = errq_init( &ctx_ScpiParser.sExecution.xScpiErrorQueue,
- ctx_ScpiParser.sExecution.xScpiErrorLogStorage,
- sizeof(ctx_ScpiParser.sExecution.xScpiErrorLogStorage) );
- my_assert( errqrc ); (void)errqrc;
- // "5.8 Device Clear Requirements", [1]
- // In Device Clear event: DO NOT clear Error Queue and any bits other than clearing MAV bit in GPIB
- // Due to the 'reset_state' is executes on DEVICE CLEAR (INITIATE_CLEAR), it is impossible to
- // initialize GPIB in 'reset_state'.
- // So, the initialization is placed here:
- GPIB_Init();
- // startup the SCPI parser state machine
- fSeqStartup( &seqScpiProcessor, NULL );
- // ... It is requried to execute the ResetState job: initialize and
- // ... go next state
- fSeqDispatch( &seqScpiProcessor );
- return (eScpiStatus_t)ctx_ScpiParser.sEvent.eStatus;
- }
- // -----------------------------------------------------------
- // @fSCPIReset
- // Reset parser
- static eScpiStatus_t fSCPIReset()
- {
- // shutdown the SCPI parser state machine
- fSeqShutdown( &seqScpiProcessor );
- // startup the SCPI parser state machine a reset state
- fSeqStartup( &seqScpiProcessor, fsq_GetStateById_unsafe(eParserResetState) );
- // process the state machine state:
- // ... It is requried to execute the ResetState job: initialize and
- // ... go next state
- fSeqDispatch( &seqScpiProcessor );
- return (eScpiStatus_t)ctx_ScpiParser.sEvent.eStatus;
- }
- // -----------------------------------------------------------
- // @fSCPINewOutTransfer
- // New Transfer Event
- static eScpiStatus_t fSCPINewOutTransfer()
- {
- // prepare global context: set the buffer properties
- ctx_ScpiParser.sWrite.pData = NULL;
- ctx_ScpiParser.sWrite.nDataLength = NULL;
- ctx_ScpiParser.sMessage.w_bEndOfMessage = false;
- ctx_ScpiParser.sMessage.r_bEndOfMessage = false; // IN-transfer is reset
- ctx_ScpiParser.sMessage.bQuery = false;
- ctx_ScpiParser.sMessage.pStr = NULL;
- ctx_ScpiParser.sMessage.bLeadResponseSep = false;
- ctx_ScpiParser.sRead.pBuffer = NULL;
- ctx_ScpiParser.sRead.pBufferIdx = NULL;
- ctx_ScpiParser.sRead.nDataLength = 0;
- ctx_ScpiParser.sRead.nBufferSize = 0;
- ctx_ScpiParser.sRead.nTotalLength = 0;
- ctx_ScpiParser.sRead.vLastBufferIdx = NULL;
- //ctx_ScpiParser.sEvent.bNewTransfer = true; // pass New Transfer indicator
- ctx_ScpiParser.sEvent.eCode = eScpiEventRestart; // send RESTART event
-
- // process the state machine state
- fSeqDispatch( &seqScpiProcessor );
- return (eScpiStatus_t)ctx_ScpiParser.sEvent.eStatus;
- }
- // -----------------------------------------------------------
- // @fSCPIWrite
- // Write parser event
- static eScpiStatus_t fSCPIWrite( const uint8_t * pData, size_t nDataLen, bool bEndOfMessage, bool bNewTransfer )
- {
- my_assert( pData );
- my_assert( nDataLen );
- // Bufferizing input command string:
- if( bNewTransfer )
- {
- // New transfer: cleanup cached input string and replace it with new one
- my_assert( nDataLen < sizeof(ctx_ScpiParser.sCache.inputCommand) );
- if( nDataLen >= sizeof(ctx_ScpiParser.sCache.inputCommand) )
- {
- return eScpiStatus_failed; // buffer overflow
- }
- memcpy( &ctx_ScpiParser.sCache.inputCommand[0], pData, nDataLen );
- ctx_ScpiParser.sCache.nBytes = nDataLen;
- }
- else
- {
- // Continue transfer: concatinate cached input string with new part
- if( ctx_ScpiParser.sCache.nBytes + nDataLen >= sizeof(ctx_ScpiParser.sCache.inputCommand) )
- {
- return eScpiStatus_failed; // buffer overflow
- }
- memcpy( &ctx_ScpiParser.sCache.inputCommand[ctx_ScpiParser.sCache.nBytes], pData, nDataLen );
- ctx_ScpiParser.sCache.nBytes += nDataLen;
- }
- // prepare global context: set the buffer properties
- ctx_ScpiParser.sWrite.pData = ctx_ScpiParser.sCache.inputCommand;
- ctx_ScpiParser.sWrite.nDataLength = ctx_ScpiParser.sCache.nBytes;
- ctx_ScpiParser.sMessage.w_bEndOfMessage = bEndOfMessage;
- (void)ctx_ScpiParser.sMessage.r_bEndOfMessage;
- ctx_ScpiParser.sMessage.bQuery = false;
- ctx_ScpiParser.sMessage.pStr = pData;
- ctx_ScpiParser.sMessage.pEnd = (pData + nDataLen);
- ctx_ScpiParser.sMessage.bLeadResponseSep = false;
- ctx_ScpiParser.sRead.pBuffer = NULL;
- ctx_ScpiParser.sRead.pBufferIdx = NULL;
- ctx_ScpiParser.sRead.nBufferSize = 0;
- ctx_ScpiParser.sRead.nDataLength = 0;
- ctx_ScpiParser.sRead.vLastBufferIdx = NULL;
- (void)ctx_ScpiParser.sRead.nTotalLength;
- //ctx_ScpiParser.sEvent.bNewTransfer = bNewTransfer; // pass New Transfer indicator
- ctx_ScpiParser.sEvent.eCode = eScpiEventWrite; // send WRITE event
-
- // process the state machine state
- fSeqDispatch( &seqScpiProcessor );
- return (eScpiStatus_t)ctx_ScpiParser.sEvent.eStatus;
- }
- // -----------------------------------------------------------
- // @fSCPIRead
- // Read parser event
- // @pBuffer - response buffer pointer
- // @nBufferLen - response buffer size
- // @pnBytesOut - pointer to the variable to store the value of written bytes to response buffer
- // @pEOM - pointer to the variable to store the End-Of-Message indicator. This indicator is set by
- // the SCPI library to notify the caller to specify SCPI End-of-message flag in Bulk-IN header that
- // is responsible for the stream control. If this flag is set, the Host must generate next READ event
- // even if the current buffer is not completely full. It is used together with complex command that
- // require several responses. Note: this value is only valid if the return value is not the error code.
- static eScpiStatus_t fSCPIRead( uint8_t * pBuffer, size_t nBufferLen, size_t * pnBytesOut, bool *pEOM )
- {
- my_assert( pBuffer );
- my_assert( nBufferLen );
- my_assert( pnBytesOut );
- // prepare global context: set the buffer properties
- (void)ctx_ScpiParser.sWrite.pData; // keep value
- (void)ctx_ScpiParser.sWrite.nDataLength; // keep value
- (void)ctx_ScpiParser.sMessage.w_bEndOfMessage; // keep value
- ctx_ScpiParser.sMessage.r_bEndOfMessage = false; // reset by default, need to set to interrupt reading
- (void)ctx_ScpiParser.sMessage.bQuery; // keep value
- (void)ctx_ScpiParser.sMessage.pStr; // keep value
- (void)ctx_ScpiParser.sMessage.pEnd; // keep value
- (void)ctx_ScpiParser.sMessage.bLeadResponseSep; // keep value
- ctx_ScpiParser.sRead.pBuffer = pBuffer;
- ctx_ScpiParser.sRead.pBufferIdx = pBuffer;
- ctx_ScpiParser.sRead.nBufferSize = nBufferLen;
- ctx_ScpiParser.sRead.nDataLength = 0;
- ctx_ScpiParser.sRead.vLastBufferIdx = pBuffer;
- (void)ctx_ScpiParser.sRead.nTotalLength;
- ctx_ScpiParser.sEvent.eCode = eScpiEventRead; // send READ event
- ctx_ScpiParser.sEvent.eStatus = eScpiStatus_failed; // forward set by default
- //ctx_ScpiParser.sEvent.bNewTransfer = false;
- // process the state machine state
- fSeqDispatch( &seqScpiProcessor );
- *pnBytesOut = ctx_ScpiParser.sRead.nDataLength; // @nDataLength shall be modified
- *pEOM = ctx_ScpiParser.sMessage.r_bEndOfMessage;
- #warning SCPI missing EOM bit set if TransferSize is full (return eScpiStatus_need_data)
- return (eScpiStatus_t)ctx_ScpiParser.sEvent.eStatus;
- }
- // -----------------------------------------------------------
- // @fSCPINotificationRead
- // Read notification data (Interrupt-IN read)
- static eScpiStatus_t fSCPINotificationRead( uint8_t * pBuffer, size_t nBufferLen, size_t * pnBytesOut, uint8_t * pSTB )
- {
- my_assert( pBuffer );
- my_assert( nBufferLen );
- my_assert( pnBytesOut );
- // "11.2.2.1 Reading with a Serial Poll", [1]
- // "11.2.2.2 Reading With the *STB? Query", [1]
- GPIBMachine.fGPIB_get_status_byte_serial_poll( &ctx_ScpiParser.sGPIB.registers, pSTB );
- *pnBytesOut = 0; // no more bytes will be returned in notification, [2] 3.4.2 Interrupt-IN DATA sent due to READ_STATUS_BYTE request
- ctx_ScpiParser.sEvent.eStatus = eScpiStatus_success; // forward set by default
- return (eScpiStatus_t)ctx_ScpiParser.sEvent.eStatus;
- }
- // -----------------------------------------------------------
- // @fSCPIError
- // Error notification from USBTMC level.
- // @error - error id, see @SCPILIB_ERROR_* macro group
- // @errorCtx - error dependent context, optional;
- // Return:
- // - eScpiStatus_success: error processed successfully
- // - eScpiStatus_failed: unrecoveral error, need to process it on USBTMC level.
- static eScpiStatus_t fSCPIError( int32_t error, const void * errorCtx )
- {
- // shall not be SCPILIB_ERROR_SUCCESS
- my_assert( error != SCPILIB_ERROR_SUCCESS );
- // prepare global context: set the buffer properties
- ctx_ScpiParser.sWrite.pData = NULL;
- ctx_ScpiParser.sWrite.nDataLength = 0;
- (void)ctx_ScpiParser.sMessage.w_bEndOfMessage;
- (void)ctx_ScpiParser.sMessage.r_bEndOfMessage;
- (void)ctx_ScpiParser.sMessage.bQuery;
- ctx_ScpiParser.sMessage.pStr = NULL;
- ctx_ScpiParser.sMessage.pEnd = NULL;
- (void)ctx_ScpiParser.sMessage.bLeadResponseSep;
- ctx_ScpiParser.sRead.pBuffer = NULL;
- ctx_ScpiParser.sRead.pBufferIdx = NULL;
- ctx_ScpiParser.sRead.nBufferSize = 0;
- ctx_ScpiParser.sRead.nDataLength = 0;
- ctx_ScpiParser.sRead.vLastBufferIdx = NULL;
- (void)ctx_ScpiParser.sRead.nTotalLength;
- ctx_ScpiParser.sEvent.eCode = eScpiEventError; // send ERROR event
- ctx_ScpiParser.sEvent.eStatus = eScpiStatus_invalid;
- switch( error )
- {
- case SCPILIB_ERROR_BUFFER_OVERFLOW:
- {
- fsq_RaiseError( SCPI_ERROR_INBUF_OVERFLOW, SCPI_ERROR_INBUF_OVERFLOW_MSG, NULL, 0 );
- }
- break;
- default: return eScpiStatus_invalid; // invalid error code, interrupt processing
- }
- // process the state machine state
- fSeqDispatch( &seqScpiProcessor );
- return (eScpiStatus_t)ctx_ScpiParser.sEvent.eStatus;
- }
- // -----------------------------------------------------------
- // @fSCPIDeInit
- // Deinitialize parser
- static eScpiStatus_t fSCPIDeInit()
- {
- // prepare global context:
- ctx_ScpiParser.sEvent.eCode = eScpiEventEmpty; // no event occurred
- // shutdown the SCPI parser state machine
- fSeqShutdown( &seqScpiProcessor );
- return (eScpiStatus_t)ctx_ScpiParser.sEvent.eStatus;
- }
|