| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748 |
- #define USBTMCLIB_BASIC_C
- #include "usbtmclib/usbtmclib_basic.h"
- #include "app/scpi/scpi_core.h"
- #include <string.h>
- static eTMCLibStatus_t tmclib_bulkin_check_inprogress(sUSBTMCContext_t*);
- static eTMCLibStatus_t tmclib_bulkout_check_inprogress(sUSBTMCContext_t*);
- static eTMCLibStatus_t tmclib_new_data_transfer(sUSBTMCContext_t*, sUSBTransfer_t *);
- static eTMCLibStatus_t tmclib_bulkout_process( sUSBTMCContext_t *, sUSBTransfer_t * );
- static eTMCLibStatus_t tmclib_bulkin_process( sUSBTMCContext_t *, sUSBTransfer_t * );
- static eTMCLibStatus_t tmclib_interruptin_process( sUSBTMCContext_t *, sUSBTransfer_t * );
- static void tmclib_bulkout_error( sUSBTMCContext_t *, sUSBTransfer_t *, eTMCLibStatus_t );
- static void tmclib_bulkin_error( sUSBTMCContext_t *, sUSBTransfer_t *, eTMCLibStatus_t );
- static void tmclib_interruptin_error( sUSBTMCContext_t *, sUSBTransfer_t *, eTMCLibStatus_t );
- static sUSBTMCContext_t ctxUsbTmc;
- static eTMCLibStatus_t lastRequestStatus = tmclib_status_success;
- #if DEBUG_USBTMC > 0 // SCPI debug only
- volatile uint32_t gDebugUSBTMC_TxBytes = 0;
- #endif
- // =================================================================================
- // tmclib_cleanup_bulkout()
- static void tmclib_cleanup_bulkout_header( sUSBTMCContext_t * ctx )
- {
- ctx->bulkOutHeader.bTag = 0;
- ctx->bulkOutHeader.bTagInverse = 0;
- ctx->bulkOutHeader.MsgID = eUsbtmcMsg_Reserved;
- ctx->bulkOutHeader.Reserved = 0;
- memset( ctx->bulkOutHeader.cmdSpec.rawBytes, 0,
- sizeof(ctx->bulkOutHeader.cmdSpec.rawBytes) );
- }
- // =================================================================================
- // tmclib_cleanup_bulkin()
- static void tmclib_cleanup_bulkin_header( sUSBTMCContext_t * ctx )
- {
- ctx->bulkInHeader.bTag = 0;
- ctx->bulkInHeader.bTagInverse = 0;
- ctx->bulkInHeader.MsgID = eUsbtmcMsg_Reserved;
- ctx->bulkInHeader.Reserved = 0;
- memset( ctx->bulkInHeader.cmdSpec.rawBytes, 0,
- sizeof(ctx->bulkInHeader.cmdSpec.rawBytes) );
- }
- // =================================================================================
- // tmclib_cleanup_interruptin()
- static void tmclib_cleanup_interruptin_header( sUSBTMCContext_t * ctx )
- {
- memset( &ctx->interruptInHeader, 0, sizeof(ctx->interruptInHeader) );
- }
- // =================================================================================
- // tmclib_write_bulkin_header()
- // Writes current bulk-in header (DevDepMsgIn) into output transfer.
- static bool tmclib_write_bulkin_header( sUSBTMCContext_t * ctx )
- {
- (void)ctx->bulkInHeader.bTag;
- (void)ctx->bulkInHeader.bTagInverse;
- (void)ctx->bulkInHeader.MsgID;
- (void)ctx->bulkInHeader.Reserved;
- (void)ctx->bulkInHeader.cmdSpec.DevDepMsgIn.transferSize;
- (void)ctx->bulkInHeader.cmdSpec.DevDepMsgIn.Reserved;
- (void)ctx->bulkInHeader.cmdSpec.DevDepMsgIn.bmTransferAttributes;
- // remember the raw Bulk-In header to be able to modify data later
- ctx->psActiveInHeader = (sUSBTMCBulkInHeader_t*)usb_transfer_raw_read(ctx->bulkInState.transf);
- // push entire header
- if( !usb_push_transfer( ctx->bulkInState.transf,
- ctx->bulkInHeader.rawBytes,
- sizeof(ctx->bulkInHeader) ) )
- {
- ctx->psActiveInHeader = NULL;
- return false;
- }
- return true;
- }
- // =================================================================================
- // tmclib_update_bulkin()
- // Writes current bulk-in header (DevDepMsgIn) into output transfer.
- static bool tmclib_update_bulkin( sUSBTMCContext_t * ctx )
- {
- my_assert( ctx );
- if( NULL != ctx->psActiveInHeader )
- {
- // update current transfer BulkIN header:
- ctx->psActiveInHeader->cmdSpec.DevDepMsgIn.transferSize
- = ctx->bulkInState.transferSize; // update TransferSize field
- // check End-of-message indicator
- if( ctx->bulkInState.bEndOfMessage )
- ctx->psActiveInHeader->cmdSpec.DevDepMsgIn.bmTransferAttributes
- |= bm_DEV_DEP_MSG_IN_EOM; // set End-Of-Message indicator
- else
- ctx->psActiveInHeader->cmdSpec.DevDepMsgIn.bmTransferAttributes
- &= ~bm_DEV_DEP_MSG_IN_EOM; // reset End-Of-Message indicator
- return true;
- }
- return false;
- }
- // =================================================================================
- // tmclib_write_notification_header()
- // Writes current interrupt-in header into output transfer.
- static bool tmclib_write_notification_header( sUSBTMCContext_t * ctx )
- {
- // remember the raw Notification (Interrupt-In) header to be able to modify data later
- ctx->psActiveNotificationHeader = (sUSBTMCNotificationHeader_t*)usb_transfer_raw_read(ctx->interruptInState.transf);
- // push entire header
- if( !usb_push_transfer( ctx->interruptInState.transf,
- ctx->interruptInHeader.rawBytes,
- sizeof(ctx->interruptInHeader) ) )
- {
- ctx->psActiveNotificationHeader = NULL;
- return false;
- }
- // only for interrupt-in transfer: calculate the bytes including the header bytes
- ctx->interruptInState.bytesCounter += sizeof(ctx->interruptInHeader);
- return true;
- }
- // =================================================================================
- // tmclib_update_notification()
- // Writes current notification header into output transfer.
- static bool tmclib_update_notification( sUSBTMCContext_t * ctx )
- {
- my_assert( ctx );
- if( NULL != ctx->psActiveNotificationHeader )
- {
- // update current transfer BulkIN header:
- USBTMC_USB488NotificationHeader_SetTag( ctx->interruptInHeader, ctx->interruptInState.bTag );
- USBTMC_USB488NotificationHeader_SetSTB( ctx->interruptInHeader, ctx->interruptInState.STB );
- USBTMC_USB488NotificationHeader_SetTag( *(ctx->psActiveNotificationHeader), ctx->interruptInState.bTag );
- USBTMC_USB488NotificationHeader_SetSTB( *(ctx->psActiveNotificationHeader), ctx->interruptInState.STB );
-
- return true;
- }
- return false;
- }
- // =================================================================================
- // @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 )
- {
- sUSBTMCContext_t * ctx = &ctxUsbTmc;
- if( usb_size_transfer( rx ) > SCPI_MAX_INPUT_COMMAND )
- {
- // Invalid value SCPI_MAX_INPUT_COMMAND.
- // Maximum input command length shall be at least equal to @rx size or more (see 'USB_BULK_USBTMC_RX_BUFFER')
- // The longest input packet must fit to the command buffer.
- // This check can not be performed in compile time due to isolation between low-level buffer and SCPI parser level.
- my_assert( usb_size_transfer( rx ) <= SCPI_MAX_INPUT_COMMAND );
-
- return tmclib_status_invalid_length;
- }
- tmclib_cleanup_bulkout_header( ctx );
- tmclib_cleanup_bulkin_header( ctx );
- tmclib_cleanup_interruptin_header( ctx );
- ctx->bulkOutState.bInProgress = false;
- ctx->bulkOutState.bEndOfMessage = false;
- ctx->bulkOutState.transferSize = 0;
- ctx->bulkOutState.bytesCounter = 0;
- ctx->bulkOutState.transf = rx;
- ctx->bulkOutState.bNewTransfer = false;
- ctx->bulkOutState.bLatestTag = 0;
- ctx->bulkInState.bInProgress = false;
- ctx->bulkInState.bEndOfMessage = false;
- ctx->bulkInState.transferSize = 0;
- ctx->bulkInState.bytesCounter = 0;
- ctx->bulkInState.transf = tx;
- ctx->bulkInState.bNewTransfer = false;
- ctx->bulkInState.bLatestTag = 0;
- ctx->interruptInState.bInProgress = false;
- ctx->interruptInState.bEndOfMessage = false;
- ctx->interruptInState.bytesCounter = 0;
- ctx->interruptInState.bTag = 0; ///???
- ctx->interruptInState.STB = 0; ///???
- ctx->interruptInState.transf = ntx;
- ctx->interruptInState.bNewTransfer = false;
- if( eScpiStatus_success != sSCPILibHandle.fInit() )
- {
- return (lastRequestStatus = tmclib_status_failure);
- }
-
- return (lastRequestStatus = tmclib_status_success);
- }
- // =================================================================================
- // @tmclib_deinit()
- // Deinitialize TMC library
- eTMCLibStatus_t tmclib_deinit()
- {
- tmclib_generic_event( COMPOUND_tmclib_event_context_abort_bulkout(0, true) );
- tmclib_generic_event( COMPOUND_tmclib_event_context_abort_bulkin(0, true) );
- tmclib_generic_event( COMPOUND_tmclib_event_context_abort_interruptin(0, true) );
- sSCPILibHandle.fDeInit();
- return (lastRequestStatus = tmclib_status_success);
- }
- // =================================================================================
- // @tmclib_abort_bulkout()
- // 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
- // Returns:
- // in case of success: @tmclib_status_success
- // in case of error: @tmclib_status_not_in_progress
- eTMCLibStatus_t tmclib_abort_bulkout( sTMCEventContext_t * eventCtx )
- {
- sUSBTMCContext_t * ctx = &ctxUsbTmc;
- if( eventCtx->event != eTMCEventBulkOutStop )
- {
- my_assert( eventCtx->event == eTMCEventBulkOutStop );
- return (lastRequestStatus = tmclib_status_invalid_param); // invalid event
- }
- if( eventCtx->abort.force || ctx->bulkOutState.bInProgress )
- {
- if( eventCtx->abort.force || (eventCtx->abort.transfer_bTag == ctx->bulkOutHeader.bTag) )
- {
- ctx->bulkOutState.bLatestTag = ctx->bulkOutHeader.bTag; // remember latest bTag
- ctx->bulkOutState.bInProgress = false;
- ctx->bulkOutState.bNewTransfer = false;
- (void)ctx->bulkOutState.bytesCounter; // do not clear the last transfer byte counter to respond with
- // force cancellation: forget about latest transaction
- if( eventCtx->abort.force ) ctx->bulkOutState.bLatestTag = 0;
- tmclib_cleanup_bulkout_header( ctx );
- // check if No-Reset-Transfer feature is requested
- if( !eventCtx->abort.noResetTransfer )
- {usb_reset_transfer( ctx->bulkOutState.transf );} // Not requested, just reset transfer
- else
- {usb_transfer_compress( ctx->bulkOutState.transf );} // Requested, compress transfer
- return (lastRequestStatus = tmclib_status_success);
- }
- }
- // check for already aborted transfer:
- if( (eventCtx->abort.transfer_bTag == ctx->bulkOutState.bLatestTag) )
- {
- // forget about latest transaction: set zero value
- ctx->bulkOutState.bLatestTag = 0;
- // this transfer has been already aborted: return 'success' code for previous aborted transfer
- return (lastRequestStatus = tmclib_status_success);
- }
- // Error: BulkOut transfer is not in progress
- return (lastRequestStatus = tmclib_status_not_in_progress);
- }
- // =================================================================================
- // @tmclib_abort_bulkin()
- // 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
- // Returns:
- // in case of success: @tmclib_status_success
- // in case of error: @tmclib_status_not_in_progress
- eTMCLibStatus_t tmclib_abort_bulkin( sTMCEventContext_t * eventCtx )
- {
- sUSBTMCContext_t * ctx = &ctxUsbTmc;
- if( eventCtx->event != eTMCEventBulkInStop )
- {
- my_assert( eventCtx->event == eTMCEventBulkInStop );
- return (lastRequestStatus = tmclib_status_invalid_param); // invalid event
- }
- if( eventCtx->abort.force || ctx->bulkInState.bInProgress )
- {
- if( eventCtx->abort.force || (eventCtx->abort.transfer_bTag == ctx->bulkInHeader.bTag) )
- {
- ctx->bulkInState.bLatestTag = ctx->bulkInHeader.bTag; // remember latest bTag
- ctx->bulkInState.bInProgress = false;
- ctx->bulkInState.bNewTransfer = false;
- ctx->psActiveInHeader = NULL;
- (void)ctx->bulkInState.bytesCounter; // do not clear the last transfer byte counter to respond with
- // force cancellation: forget about latest transaction
- if( eventCtx->abort.force ) ctx->bulkInState.bLatestTag = 0;
- tmclib_cleanup_bulkin_header( ctx );
- // @noResetTransfer - not supported for BulkIN
- my_assert( !eventCtx->abort.noResetTransfer );
- usb_reset_transfer( ctx->bulkInState.transf );
- // reset short packet indicator?
- if( eventCtx->abort.clearShortPacketIndicator )
- {
- // reset short packet indicator to NOT TO SEND zero packet
- usb_transfer_clear_shortpacket( ctx->bulkInState.transf );
- }
-
- return (lastRequestStatus = tmclib_status_success);
- }
- }
- // check for already aborted transfer:
- if( (eventCtx->abort.transfer_bTag == ctx->bulkInState.bLatestTag) )
- {
- // forget about latest transaction: set zero value
- ctx->bulkInState.bLatestTag = 0;
- // this transfer has been already aborted: return 'success' code for previous aborted transfer
- return (lastRequestStatus = tmclib_status_success);
- }
- // Error: BulkIn transfer is not in progress
- return (lastRequestStatus = tmclib_status_not_in_progress);
- }
- // =================================================================================
- // @tmclib_abort_interruptin()
- // 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
- // Returns:
- // in case of success: @tmclib_status_success
- // in case of error: @tmclib_status_not_in_progress
- static eTMCLibStatus_t tmclib_abort_interruptin( sTMCEventContext_t * eventCtx )
- {
- sUSBTMCContext_t * ctx = &ctxUsbTmc;
- if( eventCtx->event != eTMCEventInterruptInStop )
- {
- my_assert( eventCtx->event == eTMCEventInterruptInStop );
- return (lastRequestStatus = tmclib_status_invalid_param); // invalid event
- }
- if( eventCtx->abort.force || ctx->interruptInState.bInProgress )
- {
- if( eventCtx->abort.force || (eventCtx->abort.transfer_bTag == ctx->interruptInState.bTag ) )
- {
- ctx->interruptInState.bInProgress = false;
- ctx->interruptInState.bNewTransfer = false;
- ctx->interruptInState.bEndOfMessage = false;
- ctx->interruptInState.bytesCounter = 0;
- ctx->interruptInState.STB = 0; ///???
- ctx->interruptInState.bTag = 0; ///???
- ctx->psActiveNotificationHeader = NULL;
- tmclib_cleanup_interruptin_header( ctx );
- // @noResetTransfer - not supported for InterruptIN
- my_assert( !eventCtx->abort.noResetTransfer );
- usb_reset_transfer( ctx->interruptInState.transf );
- return (lastRequestStatus = tmclib_status_success);
- }
- }
- // Error: BulkOut transfer is not in progress
- return (lastRequestStatus = tmclib_status_not_in_progress);
- }
- // =================================================================================
- // @tmclib_complete_interruptin()
- // Aborts currently running InterruptIN transfer
- // @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
- // Returns:
- // in case of success: @tmclib_status_success
- // in case of error: @tmclib_status_not_in_progress
- eTMCLibStatus_t tmclib_complete_interruptin( uint8_t transfer_bTag, bool force )
- {
- sUSBTMCContext_t * ctx = &ctxUsbTmc;
- if( force || ctx->interruptInState.bInProgress )
- {
- if( force || (transfer_bTag == ctx->interruptInState.bTag ) )
- {
- ctx->interruptInState.bInProgress = false;
- ctx->interruptInState.bNewTransfer = false;
- ctx->interruptInState.bEndOfMessage = true;
- (void)ctx->interruptInState.bytesCounter;
- (void)ctx->interruptInState.STB; ///???
- (void)ctx->interruptInState.bTag; ///???
- (void)ctx->psActiveNotificationHeader;
- (void)&ctx->interruptInHeader;
- (void)ctx->interruptInState.transf;
- return (lastRequestStatus = tmclib_status_success);
- }
- }
- // Error: Interrupt-IN transfer is not in progress
- return (lastRequestStatus = tmclib_status_not_in_progress);
- }
- // =================================================================================
- // @tmclib_new_data_transfer()
- // Starts new BulkOUT/BulkIN transfer
- // @ctx - the USBTMC context
- static eTMCLibStatus_t tmclib_new_data_transfer( sUSBTMCContext_t * ctx, sUSBTransfer_t * rx )
- {
- eTMCLibStatus_t status = tmclib_status_success;
- do
- {
- if( usb_count_transfer( rx ) < sizeof( ctx->bulkOutHeader ) )
- {
- // 3.2 Bulk-OUT endpoint, [1]
- // error: BulkOut header is fragmented
- // Either the host sent the header fragmented, or the internal buffer
- // is too small. Processing is impossible.
- status = tmclib_status_header_fragmented_error;
- break;
- }
- // Read the BulkOut header from the transfer
- if( sizeof( ctx->bulkOutHeader ) != usb_read_transfer( rx, &ctx->bulkOutHeader, sizeof( ctx->bulkOutHeader ), false ) )
- {
- // error: can not read the header
- status = tmclib_status_read_error;
- break;
- }
- if( ( (1ul << 8*sizeof(ctx->bulkOutHeader.bTag)) - 1
- !=
- (ctx->bulkOutHeader.bTag ^ ctx->bulkOutHeader.bTagInverse))
- // @bTag must not be zero, 3.2 Bulk-OUT endpoint, [1]
- || 0 == ctx->bulkOutHeader.bTag )
- {
- // error: invalid bTag field
- // 3.2.2.3 Bulk-OUT transfer protocol errors, [1]
- status = tmclib_status_header_error;
- break;
- }
- eUSBTMCMsgId_t msgId = (eUSBTMCMsgId_t)ctx->bulkOutHeader.MsgID;
-
- switch( msgId )
- {
- case eUsbtmcMsg_DevDepMsgOut:
- {
- if( 0 == ctx->bulkOutHeader.cmdSpec.DevDepMsgOut.transferSize )
- {
- // error: invalid @transferSize
- status = tmclib_status_header_error;
- }
- else
- {
- // Initialize BulkOut transfer
- ctx->bulkOutState.transferSize = ctx->bulkOutHeader.cmdSpec.DevDepMsgOut.transferSize;
- ctx->bulkOutState.bInProgress = true;
- ctx->bulkOutState.bNewTransfer = true;
- ctx->bulkOutState.bytesCounter = 0;
- ctx->bulkOutState.bEndOfMessage = USBTMC_CHECK_BITMAP(
- ctx->bulkOutHeader.cmdSpec.DevDepMsgOut.bmTransferAttributes,
- bm_DEV_DEP_MSG_OUT_EOM );
- status = tmclib_status_success;
- }
- }
- break;
- case eUsbtmcMsg_ReqDevDepMsgIn:
- {
- if( 0 == ctx->bulkOutHeader.cmdSpec.ReqDevDepMsgIn.transferSize )
- {
- // error: invalid @transferSize
- status = tmclib_status_header_error;
- }
- else
- {
- if( USBTMC_CHECK_BITMAP(
- ctx->bulkOutHeader.cmdSpec.ReqDevDepMsgIn.bmTransferAttributes,
- bm_REQUEST_DEV_DEP_MSG_IN_TRMCH ) )
- {
- // error: TermChar is not supported
- status = tmclib_status_unsupported_termchar;
- }
- else
- {
- // Initialize BulkIn transfer
- ctx->bulkInState.transferSize = ctx->bulkOutHeader.cmdSpec.ReqDevDepMsgIn.transferSize;
- ctx->bulkInState.bInProgress = true;
- ctx->bulkInState.bNewTransfer = true;
- ctx->bulkInState.bytesCounter = 0;
- ctx->bulkInState.bEndOfMessage = false; // @bEndOfMessage can be changed later
- // Filling header:
- ctx->bulkInHeader.bTag = ctx->bulkOutHeader.bTag;
- ctx->bulkInHeader.bTagInverse = ctx->bulkOutHeader.bTagInverse;
- ctx->bulkInHeader.MsgID = eUsbtmcMsg_DevDepMsgIn;
- ctx->bulkInHeader.Reserved = 0;
- ctx->bulkInHeader.cmdSpec.DevDepMsgIn.transferSize = ctx->bulkInState.transferSize;
- ctx->bulkInHeader.cmdSpec.DevDepMsgIn.bmTransferAttributes = bm_DEV_DEP_MSG_IN_EOM; // set End-of-message indicator by default
- status = tmclib_status_success;
- }
- }
- }
- break;
- case eUsbtmcMsg_VendorSpecificOut:
- {
- // error: VENDOR_SPECIFIC_OUT message is not supported
- status = tmclib_status_unsupported_message_error;
- }
- break;
- case eUsbtmcMsg_ReqVendorSpecificIn:
- {
- // error: REQUEST_VENDOR_SPECIFIC_IN message is not supported
- status = tmclib_status_unsupported_message_error;
- }
- break;
- case eUsbtmcMsg_Usb488_Trigger:
- {
- // error: Trigger message is not supported
- status = tmclib_status_unsupported_message_error;
- }
- break;
- default:
- {
- // error: Invalid MsgID
- status = tmclib_status_invalid_message_error;
- }
- }
- }
- while( false );
- return (lastRequestStatus = status);
- }
- // =================================================================================
- // @tmclib_new_notification_transfer()
- // Starts new InterruptIN transfer
- // @ctx - the USBTMC context
- // @bTag - the Tag identifier, [2], 3.4.2 Interrupt-IN DATA sent due to READ_STATUS_BYTE request
- static eTMCLibStatus_t tmclib_new_notification_transfer( sUSBTMCContext_t * ctx, uint8_t bTag )
- {
- eTMCLibStatus_t status = tmclib_status_success;
- do
- {
- if( usb_space_transfer( ctx->interruptInState.transf ) < sizeof( ctx->interruptInHeader ) )
- {
- // 3.4.2 Interrupt-IN DATA sent due to READ_STATUS_BYTE request, [2]
- // error: no free space to place notification Interrupt-IN packet. Processing is impossible.
- status = tmclib_status_header_fragmented_error;
- break;
- }
- // Initialize InterruptIn transfer
- ctx->interruptInState.bTag = bTag; ///???
- ctx->interruptInState.STB = 0; ///???
- ctx->interruptInState.bInProgress = true;
- ctx->interruptInState.bNewTransfer = true;
- ctx->interruptInState.bEndOfMessage = false;
- ctx->interruptInState.bytesCounter = 0;
- // Filling header (can be modified later by @tmclib_update_notification):
- tmclib_cleanup_interruptin_header( ctx );
- status = tmclib_status_success;
- }
- while( false );
- return (lastRequestStatus = status);
- }
- // =================================================================================
- // @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_invalid_param
- eTMCLibStatus_t tmclib_bulkout_gettag( uint8_t * pbTag )
- {
- sUSBTMCContext_t * ctx = &ctxUsbTmc;
- if( NULL == pbTag )
- {
- return ( lastRequestStatus = tmclib_status_invalid_param );
- }
- if( ctx->bulkOutState.bInProgress )
- {
- *pbTag = ctx->bulkOutHeader.bTag;
- }
- else
- {
- *pbTag = 0;
- }
- return ( lastRequestStatus = tmclib_status_success );
- }
- // =================================================================================
- // @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_invalid_param
- eTMCLibStatus_t tmclib_bulkin_gettag( uint8_t * pbTag )
- {
- sUSBTMCContext_t * ctx = &ctxUsbTmc;
- if( NULL == pbTag )
- {
- return ( lastRequestStatus = tmclib_status_invalid_param );
- }
- if( ctx->bulkInState.bInProgress )
- {
- *pbTag = ctx->bulkInHeader.bTag;
- }
- else
- {
- *pbTag = 0;
- }
- return ( lastRequestStatus = tmclib_status_success );
- }
- // =================================================================================
- // @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 )
- {
- sUSBTMCContext_t * ctx = &ctxUsbTmc;
- if( NULL == pbTag )
- {
- return ( lastRequestStatus = tmclib_status_invalid_param );
- }
- if( ctx->bulkOutState.bInProgress )
- {
- // current transaction
- *pbTag = ctx->bulkOutHeader.bTag;
- }
- else
- {
- if( 0 != ctx->bulkOutState.bLatestTag )
- {
- *pbTag = ctx->bulkOutState.bLatestTag;
- }
- else
- {
- *pbTag = 0;
- }
- }
- return ( lastRequestStatus = tmclib_status_success );
- }
- // =================================================================================
- // @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 )
- {
- sUSBTMCContext_t * ctx = &ctxUsbTmc;
- if( NULL == pbTag )
- {
- return ( lastRequestStatus = tmclib_status_invalid_param );
- }
- if( ctx->bulkInState.bInProgress )
- {
- // current transaction
- *pbTag = ctx->bulkInHeader.bTag;
- }
- else
- {
- if( 0 != ctx->bulkInState.bLatestTag )
- {
- *pbTag = ctx->bulkInState.bLatestTag;
- }
- else
- {
- *pbTag = 0;
- }
- }
- return ( lastRequestStatus = tmclib_status_success );
- }
- // =================================================================================
- // @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 )
- {
- sUSBTMCContext_t * ctx = &ctxUsbTmc;
- if( NULL == pnBytes )
- {
- return ( lastRequestStatus = tmclib_status_failure );
- }
- *pnBytes = ctx->bulkOutState.bytesCounter;
- return ( lastRequestStatus = tmclib_status_success );
- }
- // =================================================================================
- // @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 )
- {
- sUSBTMCContext_t * ctx = &ctxUsbTmc;
- if( NULL == pnBytes )
- {
- return ( lastRequestStatus = tmclib_status_failure );
- }
- *pnBytes = ctx->bulkInState.bytesCounter;
- return ( lastRequestStatus = tmclib_status_success );
- }
- // =================================================================================
- // @tmclib_bulkout_check_inprogress()
- // Checks weither the Bulk-OUT transfer is in progress
- // @ctx - the USBTMC context
- // Returns: tmclib_status_in_progress in case the transfer is in progress,
- // and tmclib_status_not_in_progress otherwise.
- static eTMCLibStatus_t tmclib_bulkout_check_inprogress( sUSBTMCContext_t * ctx )
- {
- if( ! ctx->bulkOutState.bInProgress )
- {
- // status: not in progrss
- return (lastRequestStatus = tmclib_status_not_in_progress);
- }
- // status: In progrss
- return (lastRequestStatus = tmclib_status_in_progress);
- }
- // =================================================================================
- // @tmclib_bulkin_check_inprogress()
- // Checks weither the Bulk-IN transfer is in progress
- // @ctx - the USBTMC context
- // Returns: tmclib_status_in_progress in case the transfer is in progress,
- // and tmclib_status_not_in_progress otherwise.
- static eTMCLibStatus_t tmclib_bulkin_check_inprogress( sUSBTMCContext_t * ctx )
- {
- if( ! ctx->bulkInState.bInProgress )
- {
- // status: not in progrss
- return (lastRequestStatus = tmclib_status_not_in_progress);
- }
- // status: In progrss
- return (lastRequestStatus = tmclib_status_in_progress);
- }
- // =================================================================================
- // @tmclib_interruptin_check_inprogress()
- // Checks weither the Interrupt-IN transfer is in progress
- // @ctx - the USBTMC context
- // Returns: tmclib_status_in_progress in case the transfer is in progress,
- // and tmclib_status_not_in_progress otherwise.
- static eTMCLibStatus_t tmclib_interruptin_check_inprogress( sUSBTMCContext_t * ctx )
- {
- if( ! ctx->interruptInState.bInProgress )
- {
- // status: not in progrss
- return (lastRequestStatus = tmclib_status_not_in_progress);
- }
- // status: In progrss
- return (lastRequestStatus = tmclib_status_in_progress);
- }
- // =================================================================================
- // @tmclib_bulkout_event
- // Processes USBTMC Bulk-OUT event
- // @eventCtx - event context (sTMCBulkOutEventCtx_t part is used)
- // @eventCtx->event - event id to process (only eTMCEventIO is supported):
- // * eTMCEventIO - data I/O signal
- // @eventCtx->bulkOut.rx - the buffer object to be used to receive data
- // Returns: the operation status:
- // tmclib_status_success in case of success,
- // tmclib_status_in_progress in of no error has occurred, but it is required to receive more data,
- // tmclib_status_halt_bulkin in case of error and it is required to halt BulkIN EP,
- // tmclib_status_failure otherwise and it is requried to halt BulkOUT EP.
- static eTMCLibStatus_t tmclib_bulkout_event( sTMCEventContext_t * eventCtx )
- {
- eTMCLibStatus_t status = tmclib_status_success;
- sUSBTMCContext_t * ctx = &ctxUsbTmc;
- bool bProcessed = false;
- switch( eventCtx->event )
- {
- case eTMCEventBulkOut:
- {
- // Check if the BulkOut transfer is in progress
- if( tmclib_status_not_in_progress == tmclib_bulkout_check_inprogress( ctx ) )
- {
- // No, the transfer either is aborted or not started yet.
- // create new BulkOut/BulkIn transfer
- status = tmclib_new_data_transfer( ctx, eventCtx->bulkOut.rx );
- // check for BulkIn transfer
- if( tmclib_status_in_progress == tmclib_bulkin_check_inprogress( ctx ) )
- {
- // new BulkIN transfer just has been created
- bProcessed = true; // at least one transfer is created
- // push the BULKIN header into output transfer:
- if( !tmclib_write_bulkin_header( ctx ) )
- {
- status = tmclib_status_failure;
- }
- else
- {
- // this is to unlock transfer flags and reset short-packet indicator for new transfer
- usb_transfer_clear_shortpacket( ctx->bulkInState.transf );
- // perform virtual BulkIN event
- status = tmclib_bulkin_process( ctx, ctx->bulkInState.transf );
- // check status
- if( USBTMC_NOTERROR(status) )
- {
- switch(status)
- {
- case tmclib_status_in_progress:
- {
- my_assert( status != tmclib_status_in_progress ); // 'tmclib_bulkin_process' never returns 'tmclib_status_in_progress'
- status = tmclib_status_failure;
- }
- break;
- case tmclib_status_not_in_progress:
- {
- my_assert( status != tmclib_status_not_in_progress ); // 'tmclib_bulkin_process' never returns 'tmclib_status_not_in_progress'
- status = tmclib_status_failure;
- }
- break;
- case tmclib_status_again:
- {
- my_assert( status != tmclib_status_again ); // 'tmclib_bulkin_process' never returns 'tmclib_status_again'
- status = tmclib_status_failure;
- }
- break;
- case tmclib_status_need_data:
- {
- my_assert( status != tmclib_status_need_data ); // 'tmclib_bulkin_process' never returns 'tmclib_status_need_data'
- status = tmclib_status_failure;
- }
- break;
- case tmclib_status_success:
- case tmclib_status_no_more_data:
- case tmclib_status_need_read:
- {
- // if BulkIN event succeded, it is required to
- // ... send data from output data.
- status = tmclib_status_need_read;
- }
- break;
-
- default:
- my_assert( status == tmclib_status_success ); // 'tmclib_bulkin_process' returns undefined code
- }
- }
- }
- }
- }
- }
- break;
- default: status = tmclib_status_invalid_param; // invalid event
- my_assert( false );
- }
-
- if( USBTMC_NOTERROR(status) )
- {
- // Yes, continue the transfer processing
- // Check if BulkOut transfer is in progress
- // NOTE: BulkOUT transfer also initiates BulkIN transfers, so,
- // ... event @status is success, the BulkOut transfer can be
- // ... not started due to it just initiates BulkIn transfer.
- if( tmclib_status_in_progress == tmclib_bulkout_check_inprogress( ctx ) )
- {
- bProcessed = true; // at least one transfer is created
- status = tmclib_bulkout_process( ctx, eventCtx->bulkOut.rx );
- }
- }
- if( !bProcessed )
- {
- if( status == tmclib_status_success )
- status = tmclib_status_not_in_progress;
- }
- lastRequestStatus = status;
- // check the error code:
- if( USBTMC_ERROR(status) )
- {
- tmclib_bulkout_error( ctx, eventCtx->bulkOut.rx, status );
- tmclib_abort_bulkout( COMPOUND_tmclib_event_context_abort_bulkout(0, true) );
- if( status != tmclib_status_halt_bulkin )
- {
- status = tmclib_status_failure;
- }
- }
- return ( status );
- }
- // =================================================================================
- // @tmclib_bulkin_event
- // Processes USBTMC Bulk-IN event
- // @eventCtx - event context (sTMCBulkInEventCtx_t part is used)
- // @eventCtx->event - event id to process (only eTMCEventIO is supported):
- // * eTMCEventIO - data I/O signal
- // @eventCtx->bulkIn.tx - the buffer object to be used to transmit data
- // Returns: the operation status:
- // =tmclib_status_success in case of success,
- // >tmclib_status_success in case of warning,
- // <tmclib_status_success in case of failure
- //
- // Note: User shall reset Short-Packet indicator using @usb_transfer_modify_flags
- // ... routine to avoid sending short packet in case no data queued into the transfer
- // ... after successful call (return true with empty transfer)
- static eTMCLibStatus_t tmclib_bulkin_event( sTMCEventContext_t * eventCtx )
- {
- eTMCLibStatus_t status = tmclib_status_success;
- sUSBTMCContext_t * ctx = &ctxUsbTmc;
- switch( eventCtx->event )
- {
- case eTMCEventBulkIn:
- {
- // Check if the BulkIn transfer is in progress
- if( tmclib_status_in_progress == tmclib_bulkin_check_inprogress( ctx ) )
- {
- // Yes, the transfer is in progress
-
- // continue the transfer processing
- status = tmclib_bulkin_process( ctx, eventCtx->bulkIn.tx );
- }
- else
- {
- // BulkIn transfer is not in progress
- // Possibilities:
- // 1. It is the last packet and it is would be good to clear EP IN
- // 2. It is an erroneous IN-transaction from host
- status = tmclib_status_not_in_progress;
- }
- }
- break;
- default: status = tmclib_status_invalid_param; // invalid event
- my_assert( false );
- }
- lastRequestStatus = status;
- // Do to transform WARNING codes to ERRORs: generate BulkIN error on error codes only
- if( USBTMC_ERROR(status) )
- {
- tmclib_bulkin_error( ctx, eventCtx->bulkIn.tx, status );
- }
- return ( status );
- }
- // =================================================================================
- // @tmclib_interruptin_event
- // Processes USBTMC Interrupt-IN event
- // @eventCtx - event context (sTMCInterruptInEventCtx_t part is used)
- // @eventCtx->event - event id to process:
- // * eTMCEventInterruptInStart - startup signal to initiate InterruptIn trnasfer, must be generated before eTMCEventIO
- // * eTMCEventIO - data I/O signal
- // @eventCtx->interruptIn.ntx - the buffer object to be used to transmit data, must be NULL on 'eTMCEventInterruptInStart' event
- // @eventCtx->interruptIn.bTag - the Tag identifier, [2], 3.4.2 Interrupt-IN DATA sent due to READ_STATUS_BYTE request,
- // ... is valid only on 'eTMCEventInterruptInStart' event
- //
- // Returns: the operation status:
- // tmclib_status_success in case of success,
- // tmclib_status_failure otherwise
- //
- // Note: if @initiate is true, the function only creates new transfer without calling Tx-Handler,
- // and @ntx must be NULL
- //
- // 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.
- static eTMCLibStatus_t tmclib_interruptin_event( sTMCEventContext_t * eventCtx )
- {
- eTMCLibStatus_t status = tmclib_status_not_in_progress; // by default: transfer is not in progress
- sUSBTMCContext_t * ctx = &ctxUsbTmc;
- switch( eventCtx->event )
- {
- case eTMCEventInterruptInStart: /* do not process event on start signal */
- {
- // Only create the transfer on start signal
- if( NULL != eventCtx->interruptIn.ntx )
- {
- // Formal checking: on @initiate=true no @ntx pointer is known
- // Do checking to catch errors.
- // Do not call @tmclib_interruptin_error due to @ntx is must be NULL, but it is not by error
- return tmclib_status_invalid_param;
- }
- // Create new transfer with specified @bTag
- status = tmclib_new_notification_transfer( ctx, eventCtx->interruptIn.bTag );
- }
- break;
- case eTMCEventInterruptIn:
- {
- // check for Interrupt-In transfer
- // Continue only if transfer is already started
- if( tmclib_status_in_progress == tmclib_interruptin_check_inprogress( ctx ) )
- {
- // new InterruptIN transfer just has been created
- // push the INTERRUPT-IN header into output transfer
- // Warning: each event begins with new notification header.
- if( !tmclib_write_notification_header( ctx ) )
- {
- status = tmclib_status_failure;
- }
- else
- {
- /* No short packet control is required
- #if 0
- // this is to unlock transfer flags and reset short-packet indicator for new transfer
- usb_transfer_clear_shortpacket( ntx );
- #endif
- */
- // perform virtual InterruptIN event
- status = tmclib_interruptin_process( ctx, eventCtx->interruptIn.ntx );
- // check status
- if( USBTMC_NOTERROR(status) )
- {
- switch(status)
- {
- case tmclib_status_in_progress:
- {
- my_assert( status != tmclib_status_in_progress ); // 'tmclib_interruptin_process' never returns 'tmclib_status_in_progress'
- status = tmclib_status_failure;
- }
- break;
- case tmclib_status_not_in_progress:
- {
- my_assert( status != tmclib_status_not_in_progress ); // 'tmclib_interruptin_process' never returns 'tmclib_status_not_in_progress'
- status = tmclib_status_failure;
- }
- break;
- case tmclib_status_again:
- {
- my_assert( status != tmclib_status_again ); // 'tmclib_interruptin_process' never returns 'tmclib_status_again'
- status = tmclib_status_failure;
- }
- break;
- case tmclib_status_need_data:
- {
- my_assert( status != tmclib_status_need_data ); // 'tmclib_interruptin_process' never returns 'tmclib_status_need_data'
- status = tmclib_status_failure;
- }
- break;
- case tmclib_status_success:
- case tmclib_status_no_more_data:
- {
- // Attention: complete transfer but do not interrupt (do not clear usb_transfer) !
- // since no more data is planned to send: abort interrupt-in transfer
- status = tmclib_complete_interruptin( ctx->interruptInState.bTag, false );
- }
- /*no break*/
- case tmclib_status_need_read:
- {
- // if BulkIN event succeded, it is required to
- // ... send data from output data.
- status = tmclib_status_need_read;
- }
- break;
-
- default:
- my_assert( status == tmclib_status_success ); // 'tmclib_interruptin_process' returns undefined code
- }
- }
- }
- }
- }
- break;
- default: status = tmclib_status_invalid_param; // invalid event
- my_assert( false );
- }
- lastRequestStatus = status;
- // check the error code:
- if( USBTMC_ERROR(status) )
- {
- tmclib_interruptin_error( ctx, eventCtx->interruptIn.ntx, status );
- tmclib_abort_interruptin( COMPOUND_tmclib_event_context_abort_interruptin(0, true) );
- status = tmclib_status_failure;
- }
- return status;
- }
- // =================================================================================
- // @tmclib_bulkout_process
- //
- static eTMCLibStatus_t tmclib_bulkout_process( sUSBTMCContext_t * ctx, sUSBTransfer_t * rx )
- {
- // Bytes left in the @rx transfer
- size_t nBytes = usb_count_transfer( rx );
- // Bytes left to receive during current USBTMC transfer
- size_t nBytesLeft = ctx->bulkOutState.transferSize - ctx->bulkOutState.bytesCounter;
-
- // Alignment bytes requried to receive
- size_t nBytesAlignment = (sizeof(uint32_t) - ctx->bulkOutState.transferSize % sizeof(uint32_t)) % sizeof(uint32_t);
- // retrieve the short packet flag
- bool bShortPacket = usb_transfer_check_shortpacket( rx ); // bulk-out: short packet received?
- // Error identifier: reset
- int32_t nError = SCPILIB_ERROR_SUCCESS;
- // new transfer indicator show if a new transfer started since this packet
- bool bNewTransfer = ctx->bulkOutState.bNewTransfer;
- // Check if the last packet is a short packet (no more data is expected after the short packet)
- if( bShortPacket )
- {
- // If the short packet has been received, the transfer is running out.
- // This is the last BulkOut event in the transfer.
- // Check if the read data counters are match to the expected:
- // UPD. Host can join DEV_DEP_MSG_OUT and REQUEST_DEV_DEP_MSG_IN, and @rx will contain
- // more data than the transfer declares.
- if( nBytes < nBytesLeft + nBytesAlignment )
- {
- nBytes = 0;
- nError = SCPILIB_ERROR_BUFFER_OVERFLOW;
- }
- else
- {
- // if a short packet received then pass @nBytesLeft instead of @nBytes
- nBytes = nBytesLeft; // cut of alignment bytes
- }
- }
- else
- {
- // Calculate whole transfer size
- size_t bytesRequied = (sizeof( ctx->bulkOutHeader ) + nBytesLeft + nBytesAlignment);
- // Since USBTMC Library uses Low-Level USB transfer buffers, it is required
- // the USB Bulk OUT transfer to be not frangmented, so it must fit to the
- // transfer @rx, check it:
- if( usb_size_transfer( rx ) <= bytesRequied )
- {
- // overflow
- (void)nBytes;
- nError = SCPILIB_ERROR_BUFFER_OVERFLOW;
- }
- }
- // check error condition
- if( SCPILIB_ERROR_SUCCESS == nError )
- {
- if( bNewTransfer )
- {
- // Since new transfer started it is required to restart SCPI-parser
- sSCPILibHandle.fNewTransfer();
- }
-
- switch( sSCPILibHandle.fWrite( usb_transfer_raw_read( rx ), // get raw pointer and pass it to @fWrite
- nBytes, bShortPacket, bNewTransfer ) )
- {
- case eScpiStatus_success: // Both either failed or success statuses means
- case eScpiStatus_failed: // ... that the SCPI library has been processed request.
- { // Need to return @tmclib_status_success to not halt
- // ... Bulk-OUT endpoint.
- // @nBytes bytes have been processed
-
- lastRequestStatus = tmclib_status_success; // request processed
- }
- break;
- case eScpiStatus_invalid:
- {
- // @nBytes bytes have been processed
- lastRequestStatus = tmclib_status_failure; // development error
- }
- break;
- case eScpiStatus_need_data:
- {
- if( bShortPacket )
- {
- lastRequestStatus = tmclib_status_failure; // development error
- }
- else
- {
- // Need more data to continue, it is required to keep
- // ... @nBytes bytes in the buffer til the next call.
- nBytes = 0; // clear @nBytes to keep data in the buffer
- lastRequestStatus = tmclib_status_need_data;
- }
- }
- break;
- }
- // Retrieve bytes from the buffer
- if( 0 < nBytes )
- {
- // @nBytes bytes have been processed
- usb_transfer_virtual_read( rx, nBytes );
-
- nBytesLeft -= nBytes;
-
- // Check if all the protocol data has been processed (except alignment data)
- if( 0 == nBytesLeft )
- {
- if( 0 < nBytesAlignment )
- {
- usb_transfer_virtual_read( rx, nBytesAlignment );
- }
- }
- }
- if( bShortPacket )
- {
- // Since the short packet received the transfer must be terminated
- // Check if there data left in the transfer.
- // If it is, check if there no error occurred?
- if( USBTMC_NOTERROR(lastRequestStatus) && (usb_count_transfer( rx ) > 0) )
- {
- // Yes, there some data left, and no error occurred
- // Maybe it is another USBTMC header?
- tmclib_abort_bulkout( COMPOUND_tmclib_event_context_abort_bulkout_noreset(0, true) );
- // Notify the caller to call the routine again to process the rest data in the transfer
- lastRequestStatus = tmclib_status_again;
- }
- else
- {
- // No data or error occurred, just reset transfer
- tmclib_abort_bulkout( COMPOUND_tmclib_event_context_abort_bulkout(0, true) );
- }
-
- }
- // reset 'new transfer' indicator
- ctx->bulkOutState.bNewTransfer = false;
- }
- else
- {
- // Error condition.
- // Notify the SCPI level
- switch( sSCPILibHandle.fError( nError, NULL ) )
- {
- case eScpiStatus_success:
- lastRequestStatus = tmclib_status_success; // error processed
- break;
- case eScpiStatus_failed: // Unrecoverable error
- case eScpiStatus_invalid:
- lastRequestStatus = tmclib_status_failure;
- break;
-
- case eScpiStatus_need_data: // Forbidden states
- default:
- my_assert( false );
- lastRequestStatus = tmclib_status_failure;
- }
- // reset transfer
- tmclib_abort_bulkout( COMPOUND_tmclib_event_context_abort_bulkout(0, true) );
- }
- // 3.2 Bulk-OUT endpoint, [1]
- // 3.2.2.3 Bulk-OUT transfer protocol errors, [1]
- return ( lastRequestStatus );
- }
- // =================================================================================
- // tmclib_bulkin_process()
- // Processes BulkIN transfer.
- //
- // Note: User shall reset Short-Packet indicator using @usb_transfer_modify_flags
- // ... routine to avoid sending short packet in case no data queued into the transfer
- // ... after successful call (return true with empty transfer)
- static eTMCLibStatus_t tmclib_bulkin_process( sUSBTMCContext_t * ctx, sUSBTransfer_t * tx )
- {
- // Bytes free in the @tx transfer
- size_t nBytes = usb_space_transfer( tx );
- size_t nBytesOut = 0;
- // Due to USBTMC required to send data by portions with
- // ... the length multiple of 4, it is required to limit the
- // ... buffers size up to the maximum length multiple of 4 to
- // ... avoid the case when it is there no free space in the
- // ... buffer to add alinment bytes in the end.
- nBytes -= nBytes%sizeof(uint32_t);
- #warning SCPI freeSpace+sentCount ?????
- // Check the transfer boundary: @bytesCounter (sent) + @nBytes (available space)
- if( nBytes + ctx->bulkInState.bytesCounter >
- ctx->bulkInState.transferSize )
- {
- // limit the buffer space
- // TransferSize does not include the number of bytes in BulkIN header or alignment bytes
- nBytes = ctx->bulkInState.transferSize - ctx->bulkInState.bytesCounter;
- }
- // check if current transfer ran out:
- // check if all the data is already queued in transfer:
- if( 0 == nBytes )
- {
- // set success status without queuing any data
- lastRequestStatus = tmclib_status_success;
- // check if all the data is already send from transfer:
- if( 0 == usb_count_transfer( tx ) )
- {
- // close Bulk-IN transfer due to there no more data to send
- // Do not clear short packet indicator (use COMPOUND_tmclib_event_context_complete_bulkin instead of COMPOUND_tmclib_event_context_abort_bulkin!)
- tmclib_abort_bulkin( COMPOUND_tmclib_event_context_complete_bulkin(ctx->bulkInHeader.bTag, false) );
- // set informative status: equal to 'tmclib_status_success'
- lastRequestStatus = tmclib_status_no_more_data;
- }
- // do not queue any data
- nBytesOut = 0;
- }
- else
- {
- bool EOM = true; // forward set
- // generate SCPI-parser read-event
- switch( sSCPILibHandle.fRead( usb_transfer_raw_write( tx ), // get raw pointer and pass it to @fRead
- nBytes, &nBytesOut, &EOM ) )
- #warning SCPI write more than TransferSize due to sw buffer (@tx) is larger than TransferSize
- {
- case eScpiStatus_failed:
- {
- nBytesOut = 0; // due to error: clear @nBytesOut
- // // SCPI library has been failed during the request processing.
- // Need to return @eScpiStatus_failed to halt Bulk-OUT endpoint.
- tmclib_abort_bulkin( COMPOUND_tmclib_event_context_abort_bulkin(ctx->bulkInHeader.bTag, false) );
- // this is to unlock transfer flags only
- usb_transfer_clear_shortpacket( tx );
- lastRequestStatus = tmclib_status_read_error;
- }
- break;
- case eScpiStatus_success:
- {
- // // SCPI library has been successfully processed the request.
- // Need to return @tmclib_status_success to not halt Bulk-OUT endpoint.
- // @EOM: is true if there no data is planned to transfer, it is required
- // ... to indicate that this message is the last one in current transfer;
- // @EOM: is false if it is required to generate another READ event to indicate
- // that this message is NOT the last one in current transfer;
- ctx->bulkInState.bEndOfMessage = EOM; // set End-of-message indicator
- if( 0 < nBytesOut )
- {
- // @nBytesOut bytes have been placed into the output buffer
- ctx->bulkInState.bytesCounter += nBytesOut;
- #if DEBUG_USBTMC > 0 // SCPI debug only
- gDebugUSBTMC_TxBytes += nBytesOut;
- #endif
- // since it is the last transaction, it is required adjust
- // ... the ending data boundary to fit the 32-bit alignment
- // ... using the entire transfer bytes counter @bytesCounter:
- nBytesOut += sizeof(uint32_t) - ctx->bulkInState.bytesCounter%sizeof(uint32_t);
- }
- // update current transfer size: set to current transfer counter
- ctx->bulkInState.transferSize = ctx->bulkInState.bytesCounter;
- // update bulk-in header in current buffer
- tmclib_update_bulkin( ctx );
-
- lastRequestStatus = tmclib_status_success; // request processed
- }
- break;
- case eScpiStatus_invalid:
- {
- // @nBytes bytes have been processed
- lastRequestStatus = tmclib_status_failure; // development error
- }
- break;
- case eScpiStatus_need_data:
- {
- // Need more free space to continue, it is required to
- // ... send @nBytesOut bytes from output buffer.
- ctx->bulkInState.bytesCounter += nBytesOut;
- #if DEBUG_USBTMC > 0 // SCPI debug only
- gDebugUSBTMC_TxBytes += nBytesOut;
- #endif
- // since more data is planned to transfer, it is required
- // ... to indicate that this message is not the last one in
- // ... current transfer:
- ctx->bulkInState.bEndOfMessage = false; // reset End-of-message indicator
- // update current transfer size: set to current transfer counter
- ctx->bulkInState.transferSize = ctx->bulkInState.bytesCounter;
- // update bulk-in header in current buffer
- tmclib_update_bulkin( ctx );
- // set status
- lastRequestStatus = tmclib_status_need_read;
- }
- break;
- }
- }
- // perform virtual write (the data is already in the buffer)
- usb_transfer_virtual_write( tx, nBytesOut );
-
- // reset 'new transfer' indicator
- ctx->bulkInState.bNewTransfer = false;
- return lastRequestStatus;
- }
- // =================================================================================
- // tmclib_interruptin_process()
- // Processes InterruptIN transfer.
- //
- static eTMCLibStatus_t tmclib_interruptin_process( sUSBTMCContext_t * ctx, sUSBTransfer_t * ntx )
- {
- // Bytes free in the @tx transfer
- size_t nBytes = usb_space_transfer( ntx );
- size_t nBytesOut = 0;
- // check if current transfer ran out:
- // check if all the data is already queued in transfer:
- if( 0 == nBytes )
- {
- // set success status without queuing any data
- lastRequestStatus = tmclib_status_success;
- // check if all the data is already send from transfer:
- if( 0 == usb_count_transfer( ntx ) )
- {
- // close Bulk-IN transfer due to there no more data to send
- tmclib_abort_interruptin( COMPOUND_tmclib_event_context_abort_interruptin(ctx->interruptInState.bTag, false) );
- // set informative status: equal to 'tmclib_status_success'
- lastRequestStatus = tmclib_status_no_more_data;
- }
- // do not queue any data
- nBytesOut = 0;
- }
- else
- {
- // generate SCPI-parser read-event
- switch( sSCPILibHandle.fNotificationRead( usb_transfer_raw_write( ntx ), // get raw pointer and pass it to @fRead
- nBytes, &nBytesOut, &ctx->interruptInState.STB ) )
- {
- case eScpiStatus_failed:
- {
- nBytesOut = 0; // due to error: clear @nBytesOut
- // SCPI library has been failed during the request processing.
- // Need to return @eScpiStatus_failed to halt Interrupt-IN endpoint.
- tmclib_abort_interruptin( COMPOUND_tmclib_event_context_abort_interruptin(ctx->interruptInState.bTag, false) );
- // this is to unlock transfer flags only
- usb_transfer_clear_shortpacket( ntx );
- lastRequestStatus = tmclib_status_read_error;
- }
- break;
- case eScpiStatus_success:
- {
- // // SCPI library has been successfully processed the request.
- // Need to return @tmclib_status_success to not halt endpoint.
- // since no data is planned to transfer, it is required
- // ... to indicate that this message is the last one in
- // ... current transfer:
- ctx->interruptInState.bEndOfMessage = true; // set End-of-message indicator
- if( 0 < nBytesOut )
- {
- // @nBytesOut bytes have been placed into the output buffer
- ctx->interruptInState.bytesCounter += nBytesOut;
- }
- // update bulk-in header in current buffer
- tmclib_update_notification( ctx );
-
- lastRequestStatus = tmclib_status_success; // request processed
- }
- break;
- case eScpiStatus_invalid:
- {
- // @nBytes bytes have been processed
- lastRequestStatus = tmclib_status_failure; // development error
- }
- break;
- case eScpiStatus_need_data:
- {
- // Need more free space to continue, it is required to
- // ... send @nBytesOut bytes from output buffer.
- ctx->interruptInState.bytesCounter += nBytesOut;
- // since more data is planned to transfer, it is required
- // ... to indicate that this message is not the last one in
- // ... current transfer:
- ctx->interruptInState.bEndOfMessage = false; // reset End-of-message indicator
- // update bulk-in header in current buffer
- tmclib_update_notification( ctx );
- // set status
- lastRequestStatus = tmclib_status_need_read;
- }
- break;
- }
- }
- // perform virtual write (the data is already in the buffer)
- usb_transfer_virtual_write( ntx, nBytesOut );
-
- // reset 'new transfer' indicator
- ctx->interruptInState.bNewTransfer = false;
- return lastRequestStatus;
- }
- // =================================================================================
- // @tmclib_device_clear
- // Resets the USBTMC and SCPI state
- // @eventCtx - event context (sTMCDeviceClearEventCtx_t)
- // @eventCtx->event - event id to process:
- // * eTMCEventDeviceClear - resets the USBTMC and SCPI state
- // @eventCtx->clear.resetTransport - reset all the transfers
- //
- // Returns: the operation status:
- // tmclib_status_success in case of success,
- // tmclib_status_failure otherwise
- //
- static eTMCLibStatus_t tmclib_device_clear( sTMCEventContext_t * eventCtx )
- {
- if( eventCtx->clear.resetTransport )
- {
- eventCtx->abort.transfer_bTag = 0;
- eventCtx->abort.clearShortPacketIndicator = true;
- eventCtx->abort.force = true;
- eventCtx->abort.noResetTransfer = false;
- tmclib_abort_bulkin( eventCtx );
- tmclib_abort_bulkout( eventCtx );
- tmclib_abort_interruptin( eventCtx );
- }
- // Reset SCPI Parser and FSM state
- if( eScpiStatus_success == sSCPILibHandle.fReset() )
- {
- return tmclib_status_success;
- }
- return tmclib_status_failure;
- }
- // =================================================================================
- static void tmclib_bulkout_error( sUSBTMCContext_t * ctx, sUSBTransfer_t * rx, eTMCLibStatus_t status )
- {
-
- }
- // =================================================================================
- static void tmclib_bulkin_error( sUSBTMCContext_t * ctx, sUSBTransfer_t * tx, eTMCLibStatus_t status )
- {
- }
- // =================================================================================
- static void tmclib_interruptin_error( sUSBTMCContext_t * ctx, sUSBTransfer_t * tx, eTMCLibStatus_t status )
- {
- }
- // =================================================================================
- // @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 )
- {
- switch( eventCtx->event )
- {
- case eTMCEventInterruptInStart: // InterruptIn initialize (only for Interrupt-IN)
- return tmclib_interruptin_event( eventCtx );
- case eTMCEventBulkIn: // BulkIn event
- return tmclib_bulkin_event( eventCtx );
- case eTMCEventBulkOut: // BulkOut event
- return tmclib_bulkout_event( eventCtx );
- case eTMCEventInterruptIn: // InterruptIn event
- return tmclib_interruptin_event( eventCtx );
- case eTMCEventBulkInStop: // BulkIn abort
- return tmclib_abort_bulkin( eventCtx );
- case eTMCEventBulkOutStop: // BulkOut abort
- return tmclib_abort_bulkout( eventCtx );
- case eTMCEventInterruptInStop: // InterruptIn abort
- return tmclib_abort_interruptin( eventCtx );
- case eTMCEventDeviceClear: // Device Clear
- return tmclib_device_clear( eventCtx );
- }
- return tmclib_status_invalid_param;
- }
|