#ifndef USBTMCLIB_BASIC_H #define USBTMCLIB_BASIC_H // USB Test And Measurement Control Protocol (TMC) // Library version 1.0 // 23/07/19 // Sychov A. //---------------------------------------------------------------- // Refer to: // [1] USBTMC Standard, rev. 1.0, 14/04/2003 // "Universal Serial Bus Test and Measurement Class Specification (USBTMC)" // [2] USBTMC-USB488 Standard, rev. 1.0, 14/04/2003 // "Universal Serial Bus Test and Measurement Class, Subclass USB488 Specification (USBTMC-USB488) //---------------------------------------------------------------- #include #include #include "usbtmclib/usbtmclib_types.h" #include "usbtmclib/usbtmclib_requests.h" #include "usbtmclib/usbtmclib_errors.h" #include "app/usb/usb_transfers.h" #include "app/usb/usb_transfer_flags.h" #define USBTMC_VERSION 0x0100 // 4.2.1.8 GET_CAPABILITIES, table 37, [1] #define USB488_VERSION 0x0100 // 4.2.2 GET_CAPABILITIES, table 8, [2] typedef struct { bool bInProgress; uint32_t transferSize; uint32_t bytesCounter; bool bEndOfMessage; sUSBTransfer_t * transf; bool bNewTransfer; // @bytesCounter for BulkOut: // The total number of USBTMC message data bytes (not including // Bulk-OUT Header or alignment bytes) in the transfer received, // and not discarded, by the device // @bytesCounter for BulkIn: // The total number of USBTMC message data bytes (not including // Bulk-IN Header or alignment bytes) sent in the transfer // @bEndOfMessage for BulkOut: // Specifies if the EOM flag is set in Bulk-OUT header // See @bm_DEV_DEP_MSG_OUT_EOM for details. // @transf for BulkOUT: // Receiving buffer object // @transf for BulkIN: // Transmitting buffer object // @bNewTransfer for BulkOUT: // Set if new transfer just has been started // bLatestTag - the latest aborted/completed transaction bTag uint8_t bLatestTag; } sUSBTMCTransferState_t; typedef struct { bool bInProgress; uint32_t bytesCounter; bool bEndOfMessage; // @STB - status byte (IEEE 488.1/IEEE 488.2) // The part of USBTMC-USB488 Interrupt-IN Header, [2], 3.4 Interrupt-IN uint8_t STB; // @bTag - transfer identifier (bTag), [2], 4.3.1 READ_STATUS_BYTE // The part of USBTMC-USB488 Interrupt-IN Header, [2], 3.4 Interrupt-IN uint8_t bTag; // @transf for InterruptIn: // Transmitting buffer object sUSBTransfer_t * transf; // @bNewTransfer for InterruptIn: // Set if new transfer just has been started bool bNewTransfer; } sUSBTMCIntTransferState_t; typedef struct { sUSBTMCBulkOutHeader_t bulkOutHeader; sUSBTMCBulkInHeader_t bulkInHeader; sUSBTMCNotificationHeader_t interruptInHeader; sUSBTMCTransferState_t bulkOutState; sUSBTMCTransferState_t bulkInState; sUSBTMCIntTransferState_t interruptInState; sUSBTMCBulkInHeader_t * psActiveInHeader; sUSBTMCNotificationHeader_t * psActiveNotificationHeader; } sUSBTMCContext_t; typedef enum { tmclib_status_min = -2147483648, tmclib_status_invalid_param = -10, // ERROR/FAIL tmclib_status_invalid_length = -9, // ERROR/FAIL tmclib_status_halt_bulkin = -8, // ERROR/FAIL tmclib_status_unsupported_termchar = -7, // ERROR/FAIL tmclib_status_unsupported_message_error = -6, // ERROR/FAIL tmclib_status_invalid_message_error = -5, // ERROR/FAIL tmclib_status_header_error = -4, // ERROR/FAIL tmclib_status_read_error = -3, // ERROR/FAIL tmclib_status_header_fragmented_error = -2, // ERROR/FAIL tmclib_status_failure = -1, // ERROR/FAIL tmclib_status_success = 0, // SUCCESS/OK tmclib_status_in_progress = 1, // SIGNAL/WARNING tmclib_status_not_in_progress = 2, // SIGNAL/WARNING tmclib_status_again = 3, // SIGNAL/WARNING tmclib_status_need_data = 4, // SIGNAL/WARNING tmclib_status_need_read = 5, // SIGNAL/WARNING tmclib_status_no_more_data = 6, // SIGNAL/WARNING tmclib_status_max = 2147483647, } eTMCLibStatus_t; // @eTMCLibEvent_t // Common TMCLibrary event identifier. // Is used in tmclib_*_event() routines typedef enum { eTMCEventInterruptInStart, // InterruptIn initialize (only for Interrupt-IN) eTMCEventBulkIn, // BulkIn event eTMCEventBulkOut, // BulkOut event eTMCEventInterruptIn, // InterruptIn event eTMCEventBulkInStop, // BulkIn abort eTMCEventBulkOutStop, // BulkOut abort eTMCEventInterruptInStop, // InterruptIn abort eTMCEventDeviceClear, // Common Clear Event (*RST or Device Clear) } eTMCLibEvent_t; typedef struct { sUSBTransfer_t * tx; } sTMCBulkInEventCtx_t; #define DEFINE_tmclib_event_context_bulkin( _name, _tx ) \ sTMCEventContext_t eventCtx = { \ .event = (eTMCEventBulkIn),\ .bulkIn = { \ .tx = (_tx) \ } \ } #define COMPOUND_tmclib_event_context_bulkin( _name, _tx ) \ &((sTMCEventContext_t){ \ .event = (eTMCEventBulkIn),\ .bulkIn = { \ .tx = (_tx) \ } \ }) typedef struct { sUSBTransfer_t * rx; } sTMCBulkOutEventCtx_t; #define DEFINE_tmclib_event_context_bulkout( _name, _rx ) \ sTMCEventContext_t eventCtx = { \ .event = (eTMCEventBulkOut),\ .bulkOut = { \ .rx = (_rx) \ } \ } #define COMPOUND_tmclib_event_context_bulkout( _name, _rx ) \ &((sTMCEventContext_t){ \ .event = (eTMCEventBulkOut),\ .bulkOut = { \ .rx = (_rx) \ } \ }) typedef struct { sUSBTransfer_t * ntx; uint8_t bTag; } sTMCInterruptInEventCtx_t; #define DEFINE_tmclib_event_context_interruptin_start( _name, _ntx, _btag ) \ sTMCEventContext_t _name = { \ .event = (eTMCEventInterruptInStart),\ .interruptIn = { \ .ntx = (_ntx),\ .bTag = (_btag) \ } \ } #define DEFINE_tmclib_event_context_interruptin( _name, _ntx ) \ sTMCEventContext_t _name = { \ .event = (eTMCEventInterruptIn),\ .interruptIn = { \ .ntx = (_ntx),\ .bTag = (0) \ } \ } #define COMPOUND_tmclib_event_context_interruptin_start( _name, _ntx, _btag ) \ &((sTMCEventContext_t){ \ .event = (eTMCEventInterruptInStart),\ .interruptIn = { \ .ntx = (_ntx),\ .bTag = (_btag) \ } \ }) #define COMPOUND_tmclib_event_context_interruptin( _name, _ntx ) \ &((sTMCEventContext_t){ \ .event = (eTMCEventInterruptIn),\ .interruptIn = { \ .ntx = (_ntx),\ .bTag = (0) \ } \ }) typedef struct { // @force - makes to ignore the @transfer_bTag if true bool force; // @clearShortPacketIndicator - clear Short Packet Indicator assotiated with USB transfer bool clearShortPacketIndicator; // @noResetTransfer // By default shall be false. // If set, the transfer will not be reset. Is used only if buffer contains more data than // expected for the transfer bool noResetTransfer; // @transfer_bTag - The bTag value associated with the transfer to abort, // - BulkOut: see 4.2.1.2 [1] // - BulkIn: see 4.2.1.4 [1] // - InterruptIn: see 4.3.1 [2] uint8_t transfer_bTag; } sTMCAbortEventCtx_t; typedef struct { // @resetTransport - reset all the USBTMC transfers bool resetTransport; } sTMCDeviceClearEventCtx_t; #define DEFINE_tmclib_event_context_abort_bulkout( _name, _btag, _force ) \ sTMCEventContext_t _name = { \ .event = eTMCEventBulkOutStop,\ .abort = { \ .force = (_force),\ .clearShortPacketIndicator = (false), \ .noResetTransfer = (false), \ .transfer_bTag = (_btag) \ } \ } #define DEFINE_tmclib_event_context_abort_bulkin( _name, _btag, _force ) \ sTMCEventContext_t _name = { \ .event = eTMCEventBulkInStop,\ .abort = { \ .force = (_force),\ .clearShortPacketIndicator = (true), \ .noResetTransfer = (false), \ .transfer_bTag = (_btag) \ } \ } #define DEFINE_tmclib_event_context_complete_bulkin( _name, _btag ) \ sTMCEventContext_t _name = { \ .event = eTMCEventBulkInStop,\ .abort = { \ .force = (false),\ .clearShortPacketIndicator = (false), \ .noResetTransfer = (false), \ .transfer_bTag = (_btag) \ } \ } #define DEFINE_tmclib_event_context_abort_interruptin( _name, _btag, _force ) \ sTMCEventContext_t _name = { \ .event = eTMCEventInterruptInStop,\ .abort = { \ .force = (_force),\ .clearShortPacketIndicator = (false), \ .noResetTransfer = (false), \ .transfer_bTag = (_btag) \ } \ } #define COMPOUND_tmclib_event_context_abort_bulkout( _btag, _force ) \ &((sTMCEventContext_t){ \ .event = eTMCEventBulkOutStop,\ .abort = { \ .force = (_force),\ .clearShortPacketIndicator = (false), \ .noResetTransfer = (false), \ .transfer_bTag = (_btag) \ } \ }) #define COMPOUND_tmclib_event_context_abort_bulkout_noreset( _btag, _force ) \ &((sTMCEventContext_t){ \ .event = eTMCEventBulkOutStop,\ .abort = { \ .force = (_force),\ .clearShortPacketIndicator = (false), \ .noResetTransfer = (true), \ .transfer_bTag = (_btag) \ } \ }) #define COMPOUND_tmclib_event_context_abort_bulkin( _btag, _force ) \ &((sTMCEventContext_t){ \ .event = eTMCEventBulkInStop,\ .abort = { \ .force = (_force),\ .clearShortPacketIndicator = (true), \ .noResetTransfer = (false), \ .transfer_bTag = (_btag) \ } \ }) #define COMPOUND_tmclib_event_context_complete_bulkin( _btag, _force ) \ &((sTMCEventContext_t){ \ .event = eTMCEventBulkInStop,\ .abort = { \ .force = (_force),\ .clearShortPacketIndicator = (false), \ .noResetTransfer = (false), \ .transfer_bTag = (_btag) \ } \ }) #define COMPOUND_tmclib_event_context_abort_interruptin( _btag, _force ) \ &((sTMCEventContext_t){ \ .event = eTMCEventInterruptInStop,\ .abort = { \ .force = (_force),\ .clearShortPacketIndicator = (false), \ .noResetTransfer = (false), \ .transfer_bTag = (_btag) \ } \ }) #define COMPOUND_tmclib_event_context_device_clear( _fullReset ) \ &((sTMCEventContext_t){ \ .event = eTMCEventDeviceClear,\ .clear = { \ .resetTransport = (_fullReset),\ } \ }) typedef struct { eTMCLibEvent_t event; // event identified union { sTMCBulkInEventCtx_t bulkIn; // for events: eTMCEventBulkIn sTMCBulkOutEventCtx_t bulkOut; // for events: eTMCEventBulkOut sTMCInterruptInEventCtx_t interruptIn; // for events: eTMCEventInterruptIn, eTMCEventBulkInStart sTMCAbortEventCtx_t abort; // for events: eTMCEventBulkInStop, eTMCEventBulkOutStop, eTMCEventInterruptInStop sTMCDeviceClearEventCtx_t clear; // for events: eTMCEventDeviceClear }; } sTMCEventContext_t; #define USBTMC_CHECK_BITMAP( Bitmap, Flag ) ((bool)((Bitmap)&(Flag))) #define USBTMC_ERROR(status) ( tmclib_status_success > (status) ) #define USBTMC_NOTERROR(status) ( tmclib_status_success <=(status) ) #define USBTMC_WARNING(status) ( tmclib_status_success < (status) ) // @tmclib_init() // Initialize TMC library // @rx - receiving buffer object // @tx - transmitting buffer object // @ntx - interrupt/notify transmitting buffer object eTMCLibStatus_t tmclib_init( sUSBTransfer_t * rx, sUSBTransfer_t * tx, sUSBTransfer_t * ntx ); // @tmclib_deinit() // Deinitialize TMC library eTMCLibStatus_t tmclib_deinit(); // // @tmclib_new_bulkout() // // Starts new BulkOUT transfer // eTMCLibStatus_t tmclib_new_bulkout(); // // // @tmclib_new_bulkin() // // Starts new BulkIN transfer // eTMCLibStatus_t tmclib_new_bulkin(); // @tmclib_bulkout_gettag // Returns the bTag field for current BulkOut transfer // @pbTag - pointer to the bTag to be filled, can not be NULL // Note: if there no transaction is, function returns bTag=0 // Returns: returns @tmclib_status_success if @pbTag is not NULL, // otherwise returns @tmclib_status_failure eTMCLibStatus_t tmclib_bulkout_gettag( uint8_t * pbTag ); // @tmclib_bulkin_gettag // Returns the bTag field for current BulkIn transfer // @pbTag - pointer to the bTag to be filled, can not be NULL // Note: if there no transaction is, function returns bTag=0 // Returns: returns @tmclib_status_success if @pbTag is not NULL, // otherwise returns @tmclib_status_failure eTMCLibStatus_t tmclib_bulkin_gettag( uint8_t * pbTag ); // @tmclib_bulkout_gettag_latest // Returns the bTag field for latest valid BulkOut transfer // @pbTag - pointer to the bTag to be filled, can not be NULL // Note: if there no transaction is, function returns bTag for the latest valid // BulkOut transfer, or bTag for current transaction otherwise. // Returns: returns @tmclib_status_success if @pbTag is not NULL, // otherwise returns @tmclib_status_invalid_param eTMCLibStatus_t tmclib_bulkout_gettag_latest( uint8_t * pbTag ); // @tmclib_bulkin_gettag_latest // Returns the bTag field for latest valid BulkIn transfer // @pbTag - pointer to the bTag to be filled, can not be NULL // Note: if there no transaction is, function returns bTag for the latest valid // BulkIn transfer, or bTag for current transaction otherwise. // Returns: returns @tmclib_status_success if @pbTag is not NULL, // otherwise returns @tmclib_status_invalid_param eTMCLibStatus_t tmclib_bulkin_gettag_latest( uint8_t * pbTag ); // @tmclib_bulkout_getcounter // Returns the bytes counter for current BulkOut transfer // @pnBytes - pointer to the uint32_t variable to be filled, can not be NULL // Note: if there no transaction is, function returns the counter for the last transfer // Returns: returns @tmclib_status_success if @pnBytes is not NULL, // otherwise returns @tmclib_status_failure eTMCLibStatus_t tmclib_bulkout_getcounter( uint32_t * pnBytes ); // @tmclib_bulkin_getcounter // Returns the bytes counter for current BulkIn transfer // @pnBytes - pointer to the uint32_t variable to be filled, can not be NULL // Note: if there no transaction is, function returns the counter for the last transfer // Returns: returns @tmclib_status_success if @pnBytes is not NULL, // otherwise returns @tmclib_status_failure eTMCLibStatus_t tmclib_bulkin_getcounter( uint32_t * pnBytes ); // @tmclib_generic_event() // Processes USBTMC specific event. // @eventCtx - event context, all the fields must be filled in accordance to @eventCtx->event code // @eventCtx->event - event identifier: // // +------------------------------------------------------------------------------------------------------------ // * eTMCEventBulkInStop - Aborts currently running BulkIN transfer // |---> @eventCtx->abort: // | - @transfer_bTag - The bTag value associated with the transfer to abort, see 4.2.1.4 [1] // | - @force - makes to ignore the @transfer_bTag if true // +------------------------------------------------------------------------------------------------------------ // * eTMCEventBulkOutStop - Aborts currently running BulkOUT transfer // |---> @eventCtx->abort: // | - @transfer_bTag - The bTag value associated with the transfer to abort, see 4.2.1.2 [1] // | - @force - makes to ignore the @transfer_bTag if true // +------------------------------------------------------------------------------------------------------------ // * eTMCEventInterruptInStop - Aborts currently running InterruptIN transfer // |---> @eventCtx->abort: // | - @transfer_bTag - The bTag value associated with the transfer to abort, see 4.3.1 [2] // | - @force - makes to ignore the @transfer_bTag if true // +------------------------------------------------------------------------------------------------------------ // * eTMCEventBulkIn - Processes USBTMC Bulk-IN event // |---> @eventCtx->bulkIn: // | - @tx - the buffer object to be used to transmit data // +------------------------------------------------------------------------------------------------------------ // * eTMCEventBulkOut - Processes USBTMC Bulk-OUT event // |---> @eventCtx->bulkOut: // | - @rx - the buffer object to be used to receive data // +------------------------------------------------------------------------------------------------------------ // * eTMCEventInterruptInStart - Initialize new Interrupt-IN transfer w/o data processing // | ...The function only creates new transfer without calling Tx-Handler. This call must be // | ...provided before 'eTMCEventInterruptIn' event to prapare transfer. // |----> @eventCtx->interruptIn: // | - @ntx - must be NULL, or 'tmclib_status_invalid_param' will be returned otherwise // | - @bTag - the Tag identifier, [2], 3.4.2 Interrupt-IN DATA sent due to READ_STATUS_BYTE request, // +------------------------------------------------------------------------------------------------------------ // * eTMCEventInterruptIn - Processes USBTMC Interrupt-IN event. // | Note that 'eTMCEventInterruptInStart' must be generated before 'eTMCEventInterruptIn' for normal operation. // | Note: Each event generates a single INTERRUPT-IN packet begining with Interrupt-IN header // | Note: Each interrupt-in event must be not longer than @ntx transfer length. // | Note: In case it is required to send more data than @ntx can carry, you need: // | - increase Interrupt-IN EP buffer (see USB specification) and increase @ntx transfer space // | or: // | - send the data using multiple packets (each packet begins with INTERRUPT-IN header), pay // | attention that @ctx->interruptInState will not be reset until user layer return tmclib_status_success // | or tmclib_status_no_more_data. // |----> @eventCtx->interruptIn: // | - @ntx - the buffer object to be used to transmit data // | - @bTag - don't care // +------------------------------------------------------------------------------------------------------------ // // Returns: the operation status: // tmclib_status_success in case of success, // tmclib_status_failure otherwise // eTMCLibStatus_t tmclib_generic_event( sTMCEventContext_t * eventCtx ); #endif