usbtmclib_basic.c 68 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748
  1. #define USBTMCLIB_BASIC_C
  2. #include "usbtmclib/usbtmclib_basic.h"
  3. #include "app/scpi/scpi_core.h"
  4. #include <string.h>
  5. static eTMCLibStatus_t tmclib_bulkin_check_inprogress(sUSBTMCContext_t*);
  6. static eTMCLibStatus_t tmclib_bulkout_check_inprogress(sUSBTMCContext_t*);
  7. static eTMCLibStatus_t tmclib_new_data_transfer(sUSBTMCContext_t*, sUSBTransfer_t *);
  8. static eTMCLibStatus_t tmclib_bulkout_process( sUSBTMCContext_t *, sUSBTransfer_t * );
  9. static eTMCLibStatus_t tmclib_bulkin_process( sUSBTMCContext_t *, sUSBTransfer_t * );
  10. static eTMCLibStatus_t tmclib_interruptin_process( sUSBTMCContext_t *, sUSBTransfer_t * );
  11. static void tmclib_bulkout_error( sUSBTMCContext_t *, sUSBTransfer_t *, eTMCLibStatus_t );
  12. static void tmclib_bulkin_error( sUSBTMCContext_t *, sUSBTransfer_t *, eTMCLibStatus_t );
  13. static void tmclib_interruptin_error( sUSBTMCContext_t *, sUSBTransfer_t *, eTMCLibStatus_t );
  14. static sUSBTMCContext_t ctxUsbTmc;
  15. static eTMCLibStatus_t lastRequestStatus = tmclib_status_success;
  16. #if DEBUG_USBTMC > 0 // SCPI debug only
  17. volatile uint32_t gDebugUSBTMC_TxBytes = 0;
  18. #endif
  19. // =================================================================================
  20. // tmclib_cleanup_bulkout()
  21. static void tmclib_cleanup_bulkout_header( sUSBTMCContext_t * ctx )
  22. {
  23. ctx->bulkOutHeader.bTag = 0;
  24. ctx->bulkOutHeader.bTagInverse = 0;
  25. ctx->bulkOutHeader.MsgID = eUsbtmcMsg_Reserved;
  26. ctx->bulkOutHeader.Reserved = 0;
  27. memset( ctx->bulkOutHeader.cmdSpec.rawBytes, 0,
  28. sizeof(ctx->bulkOutHeader.cmdSpec.rawBytes) );
  29. }
  30. // =================================================================================
  31. // tmclib_cleanup_bulkin()
  32. static void tmclib_cleanup_bulkin_header( sUSBTMCContext_t * ctx )
  33. {
  34. ctx->bulkInHeader.bTag = 0;
  35. ctx->bulkInHeader.bTagInverse = 0;
  36. ctx->bulkInHeader.MsgID = eUsbtmcMsg_Reserved;
  37. ctx->bulkInHeader.Reserved = 0;
  38. memset( ctx->bulkInHeader.cmdSpec.rawBytes, 0,
  39. sizeof(ctx->bulkInHeader.cmdSpec.rawBytes) );
  40. }
  41. // =================================================================================
  42. // tmclib_cleanup_interruptin()
  43. static void tmclib_cleanup_interruptin_header( sUSBTMCContext_t * ctx )
  44. {
  45. memset( &ctx->interruptInHeader, 0, sizeof(ctx->interruptInHeader) );
  46. }
  47. // =================================================================================
  48. // tmclib_write_bulkin_header()
  49. // Writes current bulk-in header (DevDepMsgIn) into output transfer.
  50. static bool tmclib_write_bulkin_header( sUSBTMCContext_t * ctx )
  51. {
  52. (void)ctx->bulkInHeader.bTag;
  53. (void)ctx->bulkInHeader.bTagInverse;
  54. (void)ctx->bulkInHeader.MsgID;
  55. (void)ctx->bulkInHeader.Reserved;
  56. (void)ctx->bulkInHeader.cmdSpec.DevDepMsgIn.transferSize;
  57. (void)ctx->bulkInHeader.cmdSpec.DevDepMsgIn.Reserved;
  58. (void)ctx->bulkInHeader.cmdSpec.DevDepMsgIn.bmTransferAttributes;
  59. // remember the raw Bulk-In header to be able to modify data later
  60. ctx->psActiveInHeader = (sUSBTMCBulkInHeader_t*)usb_transfer_raw_read(ctx->bulkInState.transf);
  61. // push entire header
  62. if( !usb_push_transfer( ctx->bulkInState.transf,
  63. ctx->bulkInHeader.rawBytes,
  64. sizeof(ctx->bulkInHeader) ) )
  65. {
  66. ctx->psActiveInHeader = NULL;
  67. return false;
  68. }
  69. return true;
  70. }
  71. // =================================================================================
  72. // tmclib_update_bulkin()
  73. // Writes current bulk-in header (DevDepMsgIn) into output transfer.
  74. static bool tmclib_update_bulkin( sUSBTMCContext_t * ctx )
  75. {
  76. my_assert( ctx );
  77. if( NULL != ctx->psActiveInHeader )
  78. {
  79. // update current transfer BulkIN header:
  80. ctx->psActiveInHeader->cmdSpec.DevDepMsgIn.transferSize
  81. = ctx->bulkInState.transferSize; // update TransferSize field
  82. // check End-of-message indicator
  83. if( ctx->bulkInState.bEndOfMessage )
  84. ctx->psActiveInHeader->cmdSpec.DevDepMsgIn.bmTransferAttributes
  85. |= bm_DEV_DEP_MSG_IN_EOM; // set End-Of-Message indicator
  86. else
  87. ctx->psActiveInHeader->cmdSpec.DevDepMsgIn.bmTransferAttributes
  88. &= ~bm_DEV_DEP_MSG_IN_EOM; // reset End-Of-Message indicator
  89. return true;
  90. }
  91. return false;
  92. }
  93. // =================================================================================
  94. // tmclib_write_notification_header()
  95. // Writes current interrupt-in header into output transfer.
  96. static bool tmclib_write_notification_header( sUSBTMCContext_t * ctx )
  97. {
  98. // remember the raw Notification (Interrupt-In) header to be able to modify data later
  99. ctx->psActiveNotificationHeader = (sUSBTMCNotificationHeader_t*)usb_transfer_raw_read(ctx->interruptInState.transf);
  100. // push entire header
  101. if( !usb_push_transfer( ctx->interruptInState.transf,
  102. ctx->interruptInHeader.rawBytes,
  103. sizeof(ctx->interruptInHeader) ) )
  104. {
  105. ctx->psActiveNotificationHeader = NULL;
  106. return false;
  107. }
  108. // only for interrupt-in transfer: calculate the bytes including the header bytes
  109. ctx->interruptInState.bytesCounter += sizeof(ctx->interruptInHeader);
  110. return true;
  111. }
  112. // =================================================================================
  113. // tmclib_update_notification()
  114. // Writes current notification header into output transfer.
  115. static bool tmclib_update_notification( sUSBTMCContext_t * ctx )
  116. {
  117. my_assert( ctx );
  118. if( NULL != ctx->psActiveNotificationHeader )
  119. {
  120. // update current transfer BulkIN header:
  121. USBTMC_USB488NotificationHeader_SetTag( ctx->interruptInHeader, ctx->interruptInState.bTag );
  122. USBTMC_USB488NotificationHeader_SetSTB( ctx->interruptInHeader, ctx->interruptInState.STB );
  123. USBTMC_USB488NotificationHeader_SetTag( *(ctx->psActiveNotificationHeader), ctx->interruptInState.bTag );
  124. USBTMC_USB488NotificationHeader_SetSTB( *(ctx->psActiveNotificationHeader), ctx->interruptInState.STB );
  125. return true;
  126. }
  127. return false;
  128. }
  129. // =================================================================================
  130. // @tmclib_init()
  131. // Initialize TMC library
  132. // @rx - receiving buffer object
  133. // @tx - transmitting buffer object
  134. // @ntx - interrupt/notify transmitting buffer object
  135. eTMCLibStatus_t tmclib_init( sUSBTransfer_t * rx, sUSBTransfer_t * tx, sUSBTransfer_t * ntx )
  136. {
  137. sUSBTMCContext_t * ctx = &ctxUsbTmc;
  138. if( usb_size_transfer( rx ) > SCPI_MAX_INPUT_COMMAND )
  139. {
  140. // Invalid value SCPI_MAX_INPUT_COMMAND.
  141. // Maximum input command length shall be at least equal to @rx size or more (see 'USB_BULK_USBTMC_RX_BUFFER')
  142. // The longest input packet must fit to the command buffer.
  143. // This check can not be performed in compile time due to isolation between low-level buffer and SCPI parser level.
  144. my_assert( usb_size_transfer( rx ) <= SCPI_MAX_INPUT_COMMAND );
  145. return tmclib_status_invalid_length;
  146. }
  147. tmclib_cleanup_bulkout_header( ctx );
  148. tmclib_cleanup_bulkin_header( ctx );
  149. tmclib_cleanup_interruptin_header( ctx );
  150. ctx->bulkOutState.bInProgress = false;
  151. ctx->bulkOutState.bEndOfMessage = false;
  152. ctx->bulkOutState.transferSize = 0;
  153. ctx->bulkOutState.bytesCounter = 0;
  154. ctx->bulkOutState.transf = rx;
  155. ctx->bulkOutState.bNewTransfer = false;
  156. ctx->bulkOutState.bLatestTag = 0;
  157. ctx->bulkInState.bInProgress = false;
  158. ctx->bulkInState.bEndOfMessage = false;
  159. ctx->bulkInState.transferSize = 0;
  160. ctx->bulkInState.bytesCounter = 0;
  161. ctx->bulkInState.transf = tx;
  162. ctx->bulkInState.bNewTransfer = false;
  163. ctx->bulkInState.bLatestTag = 0;
  164. ctx->interruptInState.bInProgress = false;
  165. ctx->interruptInState.bEndOfMessage = false;
  166. ctx->interruptInState.bytesCounter = 0;
  167. ctx->interruptInState.bTag = 0; ///???
  168. ctx->interruptInState.STB = 0; ///???
  169. ctx->interruptInState.transf = ntx;
  170. ctx->interruptInState.bNewTransfer = false;
  171. if( eScpiStatus_success != sSCPILibHandle.fInit() )
  172. {
  173. return (lastRequestStatus = tmclib_status_failure);
  174. }
  175. return (lastRequestStatus = tmclib_status_success);
  176. }
  177. // =================================================================================
  178. // @tmclib_deinit()
  179. // Deinitialize TMC library
  180. eTMCLibStatus_t tmclib_deinit()
  181. {
  182. tmclib_generic_event( COMPOUND_tmclib_event_context_abort_bulkout(0, true) );
  183. tmclib_generic_event( COMPOUND_tmclib_event_context_abort_bulkin(0, true) );
  184. tmclib_generic_event( COMPOUND_tmclib_event_context_abort_interruptin(0, true) );
  185. sSCPILibHandle.fDeInit();
  186. return (lastRequestStatus = tmclib_status_success);
  187. }
  188. // =================================================================================
  189. // @tmclib_abort_bulkout()
  190. // Aborts currently running BulkOUT transfer
  191. // @eventCtx->abort:
  192. // * @transfer_bTag - The bTag value associated with the transfer to abort, see 4.2.1.2 [1]
  193. // * @force - makes to ignore the @transfer_bTag if true
  194. // Returns:
  195. // in case of success: @tmclib_status_success
  196. // in case of error: @tmclib_status_not_in_progress
  197. eTMCLibStatus_t tmclib_abort_bulkout( sTMCEventContext_t * eventCtx )
  198. {
  199. sUSBTMCContext_t * ctx = &ctxUsbTmc;
  200. if( eventCtx->event != eTMCEventBulkOutStop )
  201. {
  202. my_assert( eventCtx->event == eTMCEventBulkOutStop );
  203. return (lastRequestStatus = tmclib_status_invalid_param); // invalid event
  204. }
  205. if( eventCtx->abort.force || ctx->bulkOutState.bInProgress )
  206. {
  207. if( eventCtx->abort.force || (eventCtx->abort.transfer_bTag == ctx->bulkOutHeader.bTag) )
  208. {
  209. ctx->bulkOutState.bLatestTag = ctx->bulkOutHeader.bTag; // remember latest bTag
  210. ctx->bulkOutState.bInProgress = false;
  211. ctx->bulkOutState.bNewTransfer = false;
  212. (void)ctx->bulkOutState.bytesCounter; // do not clear the last transfer byte counter to respond with
  213. // force cancellation: forget about latest transaction
  214. if( eventCtx->abort.force ) ctx->bulkOutState.bLatestTag = 0;
  215. tmclib_cleanup_bulkout_header( ctx );
  216. // check if No-Reset-Transfer feature is requested
  217. if( !eventCtx->abort.noResetTransfer )
  218. {usb_reset_transfer( ctx->bulkOutState.transf );} // Not requested, just reset transfer
  219. else
  220. {usb_transfer_compress( ctx->bulkOutState.transf );} // Requested, compress transfer
  221. return (lastRequestStatus = tmclib_status_success);
  222. }
  223. }
  224. // check for already aborted transfer:
  225. if( (eventCtx->abort.transfer_bTag == ctx->bulkOutState.bLatestTag) )
  226. {
  227. // forget about latest transaction: set zero value
  228. ctx->bulkOutState.bLatestTag = 0;
  229. // this transfer has been already aborted: return 'success' code for previous aborted transfer
  230. return (lastRequestStatus = tmclib_status_success);
  231. }
  232. // Error: BulkOut transfer is not in progress
  233. return (lastRequestStatus = tmclib_status_not_in_progress);
  234. }
  235. // =================================================================================
  236. // @tmclib_abort_bulkin()
  237. // Aborts currently running BulkIN transfer
  238. // @eventCtx->abort:
  239. // * @transfer_bTag - The bTag value associated with the transfer to abort, see 4.2.1.4 [1]
  240. // * @force - makes to ignore the @transfer_bTag if true
  241. // Returns:
  242. // in case of success: @tmclib_status_success
  243. // in case of error: @tmclib_status_not_in_progress
  244. eTMCLibStatus_t tmclib_abort_bulkin( sTMCEventContext_t * eventCtx )
  245. {
  246. sUSBTMCContext_t * ctx = &ctxUsbTmc;
  247. if( eventCtx->event != eTMCEventBulkInStop )
  248. {
  249. my_assert( eventCtx->event == eTMCEventBulkInStop );
  250. return (lastRequestStatus = tmclib_status_invalid_param); // invalid event
  251. }
  252. if( eventCtx->abort.force || ctx->bulkInState.bInProgress )
  253. {
  254. if( eventCtx->abort.force || (eventCtx->abort.transfer_bTag == ctx->bulkInHeader.bTag) )
  255. {
  256. ctx->bulkInState.bLatestTag = ctx->bulkInHeader.bTag; // remember latest bTag
  257. ctx->bulkInState.bInProgress = false;
  258. ctx->bulkInState.bNewTransfer = false;
  259. ctx->psActiveInHeader = NULL;
  260. (void)ctx->bulkInState.bytesCounter; // do not clear the last transfer byte counter to respond with
  261. // force cancellation: forget about latest transaction
  262. if( eventCtx->abort.force ) ctx->bulkInState.bLatestTag = 0;
  263. tmclib_cleanup_bulkin_header( ctx );
  264. // @noResetTransfer - not supported for BulkIN
  265. my_assert( !eventCtx->abort.noResetTransfer );
  266. usb_reset_transfer( ctx->bulkInState.transf );
  267. // reset short packet indicator?
  268. if( eventCtx->abort.clearShortPacketIndicator )
  269. {
  270. // reset short packet indicator to NOT TO SEND zero packet
  271. usb_transfer_clear_shortpacket( ctx->bulkInState.transf );
  272. }
  273. return (lastRequestStatus = tmclib_status_success);
  274. }
  275. }
  276. // check for already aborted transfer:
  277. if( (eventCtx->abort.transfer_bTag == ctx->bulkInState.bLatestTag) )
  278. {
  279. // forget about latest transaction: set zero value
  280. ctx->bulkInState.bLatestTag = 0;
  281. // this transfer has been already aborted: return 'success' code for previous aborted transfer
  282. return (lastRequestStatus = tmclib_status_success);
  283. }
  284. // Error: BulkIn transfer is not in progress
  285. return (lastRequestStatus = tmclib_status_not_in_progress);
  286. }
  287. // =================================================================================
  288. // @tmclib_abort_interruptin()
  289. // Aborts currently running InterruptIN transfer
  290. // @eventCtx->abort:
  291. // * @transfer_bTag - The bTag value associated with the transfer to abort, see 4.3.1 [2]
  292. // * @force - makes to ignore the @transfer_bTag if true
  293. // Returns:
  294. // in case of success: @tmclib_status_success
  295. // in case of error: @tmclib_status_not_in_progress
  296. static eTMCLibStatus_t tmclib_abort_interruptin( sTMCEventContext_t * eventCtx )
  297. {
  298. sUSBTMCContext_t * ctx = &ctxUsbTmc;
  299. if( eventCtx->event != eTMCEventInterruptInStop )
  300. {
  301. my_assert( eventCtx->event == eTMCEventInterruptInStop );
  302. return (lastRequestStatus = tmclib_status_invalid_param); // invalid event
  303. }
  304. if( eventCtx->abort.force || ctx->interruptInState.bInProgress )
  305. {
  306. if( eventCtx->abort.force || (eventCtx->abort.transfer_bTag == ctx->interruptInState.bTag ) )
  307. {
  308. ctx->interruptInState.bInProgress = false;
  309. ctx->interruptInState.bNewTransfer = false;
  310. ctx->interruptInState.bEndOfMessage = false;
  311. ctx->interruptInState.bytesCounter = 0;
  312. ctx->interruptInState.STB = 0; ///???
  313. ctx->interruptInState.bTag = 0; ///???
  314. ctx->psActiveNotificationHeader = NULL;
  315. tmclib_cleanup_interruptin_header( ctx );
  316. // @noResetTransfer - not supported for InterruptIN
  317. my_assert( !eventCtx->abort.noResetTransfer );
  318. usb_reset_transfer( ctx->interruptInState.transf );
  319. return (lastRequestStatus = tmclib_status_success);
  320. }
  321. }
  322. // Error: BulkOut transfer is not in progress
  323. return (lastRequestStatus = tmclib_status_not_in_progress);
  324. }
  325. // =================================================================================
  326. // @tmclib_complete_interruptin()
  327. // Aborts currently running InterruptIN transfer
  328. // @transfer_bTag - The bTag value associated with the transfer to abort, see 4.3.1 [2]
  329. // @force - makes to ignore the @transfer_bTag if true
  330. // Returns:
  331. // in case of success: @tmclib_status_success
  332. // in case of error: @tmclib_status_not_in_progress
  333. eTMCLibStatus_t tmclib_complete_interruptin( uint8_t transfer_bTag, bool force )
  334. {
  335. sUSBTMCContext_t * ctx = &ctxUsbTmc;
  336. if( force || ctx->interruptInState.bInProgress )
  337. {
  338. if( force || (transfer_bTag == ctx->interruptInState.bTag ) )
  339. {
  340. ctx->interruptInState.bInProgress = false;
  341. ctx->interruptInState.bNewTransfer = false;
  342. ctx->interruptInState.bEndOfMessage = true;
  343. (void)ctx->interruptInState.bytesCounter;
  344. (void)ctx->interruptInState.STB; ///???
  345. (void)ctx->interruptInState.bTag; ///???
  346. (void)ctx->psActiveNotificationHeader;
  347. (void)&ctx->interruptInHeader;
  348. (void)ctx->interruptInState.transf;
  349. return (lastRequestStatus = tmclib_status_success);
  350. }
  351. }
  352. // Error: Interrupt-IN transfer is not in progress
  353. return (lastRequestStatus = tmclib_status_not_in_progress);
  354. }
  355. // =================================================================================
  356. // @tmclib_new_data_transfer()
  357. // Starts new BulkOUT/BulkIN transfer
  358. // @ctx - the USBTMC context
  359. static eTMCLibStatus_t tmclib_new_data_transfer( sUSBTMCContext_t * ctx, sUSBTransfer_t * rx )
  360. {
  361. eTMCLibStatus_t status = tmclib_status_success;
  362. do
  363. {
  364. if( usb_count_transfer( rx ) < sizeof( ctx->bulkOutHeader ) )
  365. {
  366. // 3.2 Bulk-OUT endpoint, [1]
  367. // error: BulkOut header is fragmented
  368. // Either the host sent the header fragmented, or the internal buffer
  369. // is too small. Processing is impossible.
  370. status = tmclib_status_header_fragmented_error;
  371. break;
  372. }
  373. // Read the BulkOut header from the transfer
  374. if( sizeof( ctx->bulkOutHeader ) != usb_read_transfer( rx, &ctx->bulkOutHeader, sizeof( ctx->bulkOutHeader ), false ) )
  375. {
  376. // error: can not read the header
  377. status = tmclib_status_read_error;
  378. break;
  379. }
  380. if( ( (1ul << 8*sizeof(ctx->bulkOutHeader.bTag)) - 1
  381. !=
  382. (ctx->bulkOutHeader.bTag ^ ctx->bulkOutHeader.bTagInverse))
  383. // @bTag must not be zero, 3.2 Bulk-OUT endpoint, [1]
  384. || 0 == ctx->bulkOutHeader.bTag )
  385. {
  386. // error: invalid bTag field
  387. // 3.2.2.3 Bulk-OUT transfer protocol errors, [1]
  388. status = tmclib_status_header_error;
  389. break;
  390. }
  391. eUSBTMCMsgId_t msgId = (eUSBTMCMsgId_t)ctx->bulkOutHeader.MsgID;
  392. switch( msgId )
  393. {
  394. case eUsbtmcMsg_DevDepMsgOut:
  395. {
  396. if( 0 == ctx->bulkOutHeader.cmdSpec.DevDepMsgOut.transferSize )
  397. {
  398. // error: invalid @transferSize
  399. status = tmclib_status_header_error;
  400. }
  401. else
  402. {
  403. // Initialize BulkOut transfer
  404. ctx->bulkOutState.transferSize = ctx->bulkOutHeader.cmdSpec.DevDepMsgOut.transferSize;
  405. ctx->bulkOutState.bInProgress = true;
  406. ctx->bulkOutState.bNewTransfer = true;
  407. ctx->bulkOutState.bytesCounter = 0;
  408. ctx->bulkOutState.bEndOfMessage = USBTMC_CHECK_BITMAP(
  409. ctx->bulkOutHeader.cmdSpec.DevDepMsgOut.bmTransferAttributes,
  410. bm_DEV_DEP_MSG_OUT_EOM );
  411. status = tmclib_status_success;
  412. }
  413. }
  414. break;
  415. case eUsbtmcMsg_ReqDevDepMsgIn:
  416. {
  417. if( 0 == ctx->bulkOutHeader.cmdSpec.ReqDevDepMsgIn.transferSize )
  418. {
  419. // error: invalid @transferSize
  420. status = tmclib_status_header_error;
  421. }
  422. else
  423. {
  424. if( USBTMC_CHECK_BITMAP(
  425. ctx->bulkOutHeader.cmdSpec.ReqDevDepMsgIn.bmTransferAttributes,
  426. bm_REQUEST_DEV_DEP_MSG_IN_TRMCH ) )
  427. {
  428. // error: TermChar is not supported
  429. status = tmclib_status_unsupported_termchar;
  430. }
  431. else
  432. {
  433. // Initialize BulkIn transfer
  434. ctx->bulkInState.transferSize = ctx->bulkOutHeader.cmdSpec.ReqDevDepMsgIn.transferSize;
  435. ctx->bulkInState.bInProgress = true;
  436. ctx->bulkInState.bNewTransfer = true;
  437. ctx->bulkInState.bytesCounter = 0;
  438. ctx->bulkInState.bEndOfMessage = false; // @bEndOfMessage can be changed later
  439. // Filling header:
  440. ctx->bulkInHeader.bTag = ctx->bulkOutHeader.bTag;
  441. ctx->bulkInHeader.bTagInverse = ctx->bulkOutHeader.bTagInverse;
  442. ctx->bulkInHeader.MsgID = eUsbtmcMsg_DevDepMsgIn;
  443. ctx->bulkInHeader.Reserved = 0;
  444. ctx->bulkInHeader.cmdSpec.DevDepMsgIn.transferSize = ctx->bulkInState.transferSize;
  445. ctx->bulkInHeader.cmdSpec.DevDepMsgIn.bmTransferAttributes = bm_DEV_DEP_MSG_IN_EOM; // set End-of-message indicator by default
  446. status = tmclib_status_success;
  447. }
  448. }
  449. }
  450. break;
  451. case eUsbtmcMsg_VendorSpecificOut:
  452. {
  453. // error: VENDOR_SPECIFIC_OUT message is not supported
  454. status = tmclib_status_unsupported_message_error;
  455. }
  456. break;
  457. case eUsbtmcMsg_ReqVendorSpecificIn:
  458. {
  459. // error: REQUEST_VENDOR_SPECIFIC_IN message is not supported
  460. status = tmclib_status_unsupported_message_error;
  461. }
  462. break;
  463. case eUsbtmcMsg_Usb488_Trigger:
  464. {
  465. // error: Trigger message is not supported
  466. status = tmclib_status_unsupported_message_error;
  467. }
  468. break;
  469. default:
  470. {
  471. // error: Invalid MsgID
  472. status = tmclib_status_invalid_message_error;
  473. }
  474. }
  475. }
  476. while( false );
  477. return (lastRequestStatus = status);
  478. }
  479. // =================================================================================
  480. // @tmclib_new_notification_transfer()
  481. // Starts new InterruptIN transfer
  482. // @ctx - the USBTMC context
  483. // @bTag - the Tag identifier, [2], 3.4.2 Interrupt-IN DATA sent due to READ_STATUS_BYTE request
  484. static eTMCLibStatus_t tmclib_new_notification_transfer( sUSBTMCContext_t * ctx, uint8_t bTag )
  485. {
  486. eTMCLibStatus_t status = tmclib_status_success;
  487. do
  488. {
  489. if( usb_space_transfer( ctx->interruptInState.transf ) < sizeof( ctx->interruptInHeader ) )
  490. {
  491. // 3.4.2 Interrupt-IN DATA sent due to READ_STATUS_BYTE request, [2]
  492. // error: no free space to place notification Interrupt-IN packet. Processing is impossible.
  493. status = tmclib_status_header_fragmented_error;
  494. break;
  495. }
  496. // Initialize InterruptIn transfer
  497. ctx->interruptInState.bTag = bTag; ///???
  498. ctx->interruptInState.STB = 0; ///???
  499. ctx->interruptInState.bInProgress = true;
  500. ctx->interruptInState.bNewTransfer = true;
  501. ctx->interruptInState.bEndOfMessage = false;
  502. ctx->interruptInState.bytesCounter = 0;
  503. // Filling header (can be modified later by @tmclib_update_notification):
  504. tmclib_cleanup_interruptin_header( ctx );
  505. status = tmclib_status_success;
  506. }
  507. while( false );
  508. return (lastRequestStatus = status);
  509. }
  510. // =================================================================================
  511. // @tmclib_bulkout_gettag
  512. // Returns the bTag field for current BulkOut transfer
  513. // @pbTag - pointer to the bTag to be filled, can not be NULL
  514. // Note: if there no transaction is, function returns bTag=0
  515. // Returns: returns @tmclib_status_success if @pbTag is not NULL,
  516. // otherwise returns @tmclib_status_invalid_param
  517. eTMCLibStatus_t tmclib_bulkout_gettag( uint8_t * pbTag )
  518. {
  519. sUSBTMCContext_t * ctx = &ctxUsbTmc;
  520. if( NULL == pbTag )
  521. {
  522. return ( lastRequestStatus = tmclib_status_invalid_param );
  523. }
  524. if( ctx->bulkOutState.bInProgress )
  525. {
  526. *pbTag = ctx->bulkOutHeader.bTag;
  527. }
  528. else
  529. {
  530. *pbTag = 0;
  531. }
  532. return ( lastRequestStatus = tmclib_status_success );
  533. }
  534. // =================================================================================
  535. // @tmclib_bulkin_gettag
  536. // Returns the bTag field for current BulkIn transfer
  537. // @pbTag - pointer to the bTag to be filled, can not be NULL
  538. // Note: if there no transaction is, function returns bTag=0
  539. // Returns: returns @tmclib_status_success if @pbTag is not NULL,
  540. // otherwise returns @tmclib_status_invalid_param
  541. eTMCLibStatus_t tmclib_bulkin_gettag( uint8_t * pbTag )
  542. {
  543. sUSBTMCContext_t * ctx = &ctxUsbTmc;
  544. if( NULL == pbTag )
  545. {
  546. return ( lastRequestStatus = tmclib_status_invalid_param );
  547. }
  548. if( ctx->bulkInState.bInProgress )
  549. {
  550. *pbTag = ctx->bulkInHeader.bTag;
  551. }
  552. else
  553. {
  554. *pbTag = 0;
  555. }
  556. return ( lastRequestStatus = tmclib_status_success );
  557. }
  558. // =================================================================================
  559. // @tmclib_bulkout_gettag_latest
  560. // Returns the bTag field for latest valid BulkOut transfer
  561. // @pbTag - pointer to the bTag to be filled, can not be NULL
  562. // Note: if there no transaction is, function returns bTag for the latest valid
  563. // BulkOut transfer, or bTag for current transaction otherwise.
  564. // Returns: returns @tmclib_status_success if @pbTag is not NULL,
  565. // otherwise returns @tmclib_status_invalid_param
  566. eTMCLibStatus_t tmclib_bulkout_gettag_latest( uint8_t * pbTag )
  567. {
  568. sUSBTMCContext_t * ctx = &ctxUsbTmc;
  569. if( NULL == pbTag )
  570. {
  571. return ( lastRequestStatus = tmclib_status_invalid_param );
  572. }
  573. if( ctx->bulkOutState.bInProgress )
  574. {
  575. // current transaction
  576. *pbTag = ctx->bulkOutHeader.bTag;
  577. }
  578. else
  579. {
  580. if( 0 != ctx->bulkOutState.bLatestTag )
  581. {
  582. *pbTag = ctx->bulkOutState.bLatestTag;
  583. }
  584. else
  585. {
  586. *pbTag = 0;
  587. }
  588. }
  589. return ( lastRequestStatus = tmclib_status_success );
  590. }
  591. // =================================================================================
  592. // @tmclib_bulkin_gettag_latest
  593. // Returns the bTag field for latest valid BulkIn transfer
  594. // @pbTag - pointer to the bTag to be filled, can not be NULL
  595. // Note: if there no transaction is, function returns bTag for the latest valid
  596. // BulkIn transfer, or bTag for current transaction otherwise.
  597. // Returns: returns @tmclib_status_success if @pbTag is not NULL,
  598. // otherwise returns @tmclib_status_invalid_param
  599. eTMCLibStatus_t tmclib_bulkin_gettag_latest( uint8_t * pbTag )
  600. {
  601. sUSBTMCContext_t * ctx = &ctxUsbTmc;
  602. if( NULL == pbTag )
  603. {
  604. return ( lastRequestStatus = tmclib_status_invalid_param );
  605. }
  606. if( ctx->bulkInState.bInProgress )
  607. {
  608. // current transaction
  609. *pbTag = ctx->bulkInHeader.bTag;
  610. }
  611. else
  612. {
  613. if( 0 != ctx->bulkInState.bLatestTag )
  614. {
  615. *pbTag = ctx->bulkInState.bLatestTag;
  616. }
  617. else
  618. {
  619. *pbTag = 0;
  620. }
  621. }
  622. return ( lastRequestStatus = tmclib_status_success );
  623. }
  624. // =================================================================================
  625. // @tmclib_bulkout_getcounter
  626. // Returns the bytes counter for current BulkOut transfer
  627. // @pnBytes - pointer to the uint32_t variable to be filled, can not be NULL
  628. // Note: if there no transaction is, function returns the counter for the last transfer
  629. // Returns: returns @tmclib_status_success if @pnBytes is not NULL,
  630. // otherwise returns @tmclib_status_failure
  631. eTMCLibStatus_t tmclib_bulkout_getcounter( uint32_t * pnBytes )
  632. {
  633. sUSBTMCContext_t * ctx = &ctxUsbTmc;
  634. if( NULL == pnBytes )
  635. {
  636. return ( lastRequestStatus = tmclib_status_failure );
  637. }
  638. *pnBytes = ctx->bulkOutState.bytesCounter;
  639. return ( lastRequestStatus = tmclib_status_success );
  640. }
  641. // =================================================================================
  642. // @tmclib_bulkin_getcounter
  643. // Returns the bytes counter for current BulkIn transfer
  644. // @pnBytes - pointer to the uint32_t variable to be filled, can not be NULL
  645. // Note: if there no transaction is, function returns the counter for the last transfer
  646. // Returns: returns @tmclib_status_success if @pnBytes is not NULL,
  647. // otherwise returns @tmclib_status_failure
  648. eTMCLibStatus_t tmclib_bulkin_getcounter( uint32_t * pnBytes )
  649. {
  650. sUSBTMCContext_t * ctx = &ctxUsbTmc;
  651. if( NULL == pnBytes )
  652. {
  653. return ( lastRequestStatus = tmclib_status_failure );
  654. }
  655. *pnBytes = ctx->bulkInState.bytesCounter;
  656. return ( lastRequestStatus = tmclib_status_success );
  657. }
  658. // =================================================================================
  659. // @tmclib_bulkout_check_inprogress()
  660. // Checks weither the Bulk-OUT transfer is in progress
  661. // @ctx - the USBTMC context
  662. // Returns: tmclib_status_in_progress in case the transfer is in progress,
  663. // and tmclib_status_not_in_progress otherwise.
  664. static eTMCLibStatus_t tmclib_bulkout_check_inprogress( sUSBTMCContext_t * ctx )
  665. {
  666. if( ! ctx->bulkOutState.bInProgress )
  667. {
  668. // status: not in progrss
  669. return (lastRequestStatus = tmclib_status_not_in_progress);
  670. }
  671. // status: In progrss
  672. return (lastRequestStatus = tmclib_status_in_progress);
  673. }
  674. // =================================================================================
  675. // @tmclib_bulkin_check_inprogress()
  676. // Checks weither the Bulk-IN transfer is in progress
  677. // @ctx - the USBTMC context
  678. // Returns: tmclib_status_in_progress in case the transfer is in progress,
  679. // and tmclib_status_not_in_progress otherwise.
  680. static eTMCLibStatus_t tmclib_bulkin_check_inprogress( sUSBTMCContext_t * ctx )
  681. {
  682. if( ! ctx->bulkInState.bInProgress )
  683. {
  684. // status: not in progrss
  685. return (lastRequestStatus = tmclib_status_not_in_progress);
  686. }
  687. // status: In progrss
  688. return (lastRequestStatus = tmclib_status_in_progress);
  689. }
  690. // =================================================================================
  691. // @tmclib_interruptin_check_inprogress()
  692. // Checks weither the Interrupt-IN transfer is in progress
  693. // @ctx - the USBTMC context
  694. // Returns: tmclib_status_in_progress in case the transfer is in progress,
  695. // and tmclib_status_not_in_progress otherwise.
  696. static eTMCLibStatus_t tmclib_interruptin_check_inprogress( sUSBTMCContext_t * ctx )
  697. {
  698. if( ! ctx->interruptInState.bInProgress )
  699. {
  700. // status: not in progrss
  701. return (lastRequestStatus = tmclib_status_not_in_progress);
  702. }
  703. // status: In progrss
  704. return (lastRequestStatus = tmclib_status_in_progress);
  705. }
  706. // =================================================================================
  707. // @tmclib_bulkout_event
  708. // Processes USBTMC Bulk-OUT event
  709. // @eventCtx - event context (sTMCBulkOutEventCtx_t part is used)
  710. // @eventCtx->event - event id to process (only eTMCEventIO is supported):
  711. // * eTMCEventIO - data I/O signal
  712. // @eventCtx->bulkOut.rx - the buffer object to be used to receive data
  713. // Returns: the operation status:
  714. // tmclib_status_success in case of success,
  715. // tmclib_status_in_progress in of no error has occurred, but it is required to receive more data,
  716. // tmclib_status_halt_bulkin in case of error and it is required to halt BulkIN EP,
  717. // tmclib_status_failure otherwise and it is requried to halt BulkOUT EP.
  718. static eTMCLibStatus_t tmclib_bulkout_event( sTMCEventContext_t * eventCtx )
  719. {
  720. eTMCLibStatus_t status = tmclib_status_success;
  721. sUSBTMCContext_t * ctx = &ctxUsbTmc;
  722. bool bProcessed = false;
  723. switch( eventCtx->event )
  724. {
  725. case eTMCEventBulkOut:
  726. {
  727. // Check if the BulkOut transfer is in progress
  728. if( tmclib_status_not_in_progress == tmclib_bulkout_check_inprogress( ctx ) )
  729. {
  730. // No, the transfer either is aborted or not started yet.
  731. // create new BulkOut/BulkIn transfer
  732. status = tmclib_new_data_transfer( ctx, eventCtx->bulkOut.rx );
  733. // check for BulkIn transfer
  734. if( tmclib_status_in_progress == tmclib_bulkin_check_inprogress( ctx ) )
  735. {
  736. // new BulkIN transfer just has been created
  737. bProcessed = true; // at least one transfer is created
  738. // push the BULKIN header into output transfer:
  739. if( !tmclib_write_bulkin_header( ctx ) )
  740. {
  741. status = tmclib_status_failure;
  742. }
  743. else
  744. {
  745. // this is to unlock transfer flags and reset short-packet indicator for new transfer
  746. usb_transfer_clear_shortpacket( ctx->bulkInState.transf );
  747. // perform virtual BulkIN event
  748. status = tmclib_bulkin_process( ctx, ctx->bulkInState.transf );
  749. // check status
  750. if( USBTMC_NOTERROR(status) )
  751. {
  752. switch(status)
  753. {
  754. case tmclib_status_in_progress:
  755. {
  756. my_assert( status != tmclib_status_in_progress ); // 'tmclib_bulkin_process' never returns 'tmclib_status_in_progress'
  757. status = tmclib_status_failure;
  758. }
  759. break;
  760. case tmclib_status_not_in_progress:
  761. {
  762. my_assert( status != tmclib_status_not_in_progress ); // 'tmclib_bulkin_process' never returns 'tmclib_status_not_in_progress'
  763. status = tmclib_status_failure;
  764. }
  765. break;
  766. case tmclib_status_again:
  767. {
  768. my_assert( status != tmclib_status_again ); // 'tmclib_bulkin_process' never returns 'tmclib_status_again'
  769. status = tmclib_status_failure;
  770. }
  771. break;
  772. case tmclib_status_need_data:
  773. {
  774. my_assert( status != tmclib_status_need_data ); // 'tmclib_bulkin_process' never returns 'tmclib_status_need_data'
  775. status = tmclib_status_failure;
  776. }
  777. break;
  778. case tmclib_status_success:
  779. case tmclib_status_no_more_data:
  780. case tmclib_status_need_read:
  781. {
  782. // if BulkIN event succeded, it is required to
  783. // ... send data from output data.
  784. status = tmclib_status_need_read;
  785. }
  786. break;
  787. default:
  788. my_assert( status == tmclib_status_success ); // 'tmclib_bulkin_process' returns undefined code
  789. }
  790. }
  791. }
  792. }
  793. }
  794. }
  795. break;
  796. default: status = tmclib_status_invalid_param; // invalid event
  797. my_assert( false );
  798. }
  799. if( USBTMC_NOTERROR(status) )
  800. {
  801. // Yes, continue the transfer processing
  802. // Check if BulkOut transfer is in progress
  803. // NOTE: BulkOUT transfer also initiates BulkIN transfers, so,
  804. // ... event @status is success, the BulkOut transfer can be
  805. // ... not started due to it just initiates BulkIn transfer.
  806. if( tmclib_status_in_progress == tmclib_bulkout_check_inprogress( ctx ) )
  807. {
  808. bProcessed = true; // at least one transfer is created
  809. status = tmclib_bulkout_process( ctx, eventCtx->bulkOut.rx );
  810. }
  811. }
  812. if( !bProcessed )
  813. {
  814. if( status == tmclib_status_success )
  815. status = tmclib_status_not_in_progress;
  816. }
  817. lastRequestStatus = status;
  818. // check the error code:
  819. if( USBTMC_ERROR(status) )
  820. {
  821. tmclib_bulkout_error( ctx, eventCtx->bulkOut.rx, status );
  822. tmclib_abort_bulkout( COMPOUND_tmclib_event_context_abort_bulkout(0, true) );
  823. if( status != tmclib_status_halt_bulkin )
  824. {
  825. status = tmclib_status_failure;
  826. }
  827. }
  828. return ( status );
  829. }
  830. // =================================================================================
  831. // @tmclib_bulkin_event
  832. // Processes USBTMC Bulk-IN event
  833. // @eventCtx - event context (sTMCBulkInEventCtx_t part is used)
  834. // @eventCtx->event - event id to process (only eTMCEventIO is supported):
  835. // * eTMCEventIO - data I/O signal
  836. // @eventCtx->bulkIn.tx - the buffer object to be used to transmit data
  837. // Returns: the operation status:
  838. // =tmclib_status_success in case of success,
  839. // >tmclib_status_success in case of warning,
  840. // <tmclib_status_success in case of failure
  841. //
  842. // Note: User shall reset Short-Packet indicator using @usb_transfer_modify_flags
  843. // ... routine to avoid sending short packet in case no data queued into the transfer
  844. // ... after successful call (return true with empty transfer)
  845. static eTMCLibStatus_t tmclib_bulkin_event( sTMCEventContext_t * eventCtx )
  846. {
  847. eTMCLibStatus_t status = tmclib_status_success;
  848. sUSBTMCContext_t * ctx = &ctxUsbTmc;
  849. switch( eventCtx->event )
  850. {
  851. case eTMCEventBulkIn:
  852. {
  853. // Check if the BulkIn transfer is in progress
  854. if( tmclib_status_in_progress == tmclib_bulkin_check_inprogress( ctx ) )
  855. {
  856. // Yes, the transfer is in progress
  857. // continue the transfer processing
  858. status = tmclib_bulkin_process( ctx, eventCtx->bulkIn.tx );
  859. }
  860. else
  861. {
  862. // BulkIn transfer is not in progress
  863. // Possibilities:
  864. // 1. It is the last packet and it is would be good to clear EP IN
  865. // 2. It is an erroneous IN-transaction from host
  866. status = tmclib_status_not_in_progress;
  867. }
  868. }
  869. break;
  870. default: status = tmclib_status_invalid_param; // invalid event
  871. my_assert( false );
  872. }
  873. lastRequestStatus = status;
  874. // Do to transform WARNING codes to ERRORs: generate BulkIN error on error codes only
  875. if( USBTMC_ERROR(status) )
  876. {
  877. tmclib_bulkin_error( ctx, eventCtx->bulkIn.tx, status );
  878. }
  879. return ( status );
  880. }
  881. // =================================================================================
  882. // @tmclib_interruptin_event
  883. // Processes USBTMC Interrupt-IN event
  884. // @eventCtx - event context (sTMCInterruptInEventCtx_t part is used)
  885. // @eventCtx->event - event id to process:
  886. // * eTMCEventInterruptInStart - startup signal to initiate InterruptIn trnasfer, must be generated before eTMCEventIO
  887. // * eTMCEventIO - data I/O signal
  888. // @eventCtx->interruptIn.ntx - the buffer object to be used to transmit data, must be NULL on 'eTMCEventInterruptInStart' event
  889. // @eventCtx->interruptIn.bTag - the Tag identifier, [2], 3.4.2 Interrupt-IN DATA sent due to READ_STATUS_BYTE request,
  890. // ... is valid only on 'eTMCEventInterruptInStart' event
  891. //
  892. // Returns: the operation status:
  893. // tmclib_status_success in case of success,
  894. // tmclib_status_failure otherwise
  895. //
  896. // Note: if @initiate is true, the function only creates new transfer without calling Tx-Handler,
  897. // and @ntx must be NULL
  898. //
  899. // Note: Each event generates a single INTERRUPT-IN packet begining with Interrupt-IN header
  900. // Note: Each interrupt-in event must be not longer than @ntx transfer length.
  901. // Note: In case it is required to send more data than @ntx can carry, you need:
  902. // - increase Interrupt-IN EP buffer (see USB specification) and increase @ntx transfer space
  903. // or:
  904. // - send the data using multiple packets (each packet begins with INTERRUPT-IN header), pay
  905. // attention that @ctx->interruptInState will not be reset until user layer return tmclib_status_success
  906. // or tmclib_status_no_more_data.
  907. static eTMCLibStatus_t tmclib_interruptin_event( sTMCEventContext_t * eventCtx )
  908. {
  909. eTMCLibStatus_t status = tmclib_status_not_in_progress; // by default: transfer is not in progress
  910. sUSBTMCContext_t * ctx = &ctxUsbTmc;
  911. switch( eventCtx->event )
  912. {
  913. case eTMCEventInterruptInStart: /* do not process event on start signal */
  914. {
  915. // Only create the transfer on start signal
  916. if( NULL != eventCtx->interruptIn.ntx )
  917. {
  918. // Formal checking: on @initiate=true no @ntx pointer is known
  919. // Do checking to catch errors.
  920. // Do not call @tmclib_interruptin_error due to @ntx is must be NULL, but it is not by error
  921. return tmclib_status_invalid_param;
  922. }
  923. // Create new transfer with specified @bTag
  924. status = tmclib_new_notification_transfer( ctx, eventCtx->interruptIn.bTag );
  925. }
  926. break;
  927. case eTMCEventInterruptIn:
  928. {
  929. // check for Interrupt-In transfer
  930. // Continue only if transfer is already started
  931. if( tmclib_status_in_progress == tmclib_interruptin_check_inprogress( ctx ) )
  932. {
  933. // new InterruptIN transfer just has been created
  934. // push the INTERRUPT-IN header into output transfer
  935. // Warning: each event begins with new notification header.
  936. if( !tmclib_write_notification_header( ctx ) )
  937. {
  938. status = tmclib_status_failure;
  939. }
  940. else
  941. {
  942. /* No short packet control is required
  943. #if 0
  944. // this is to unlock transfer flags and reset short-packet indicator for new transfer
  945. usb_transfer_clear_shortpacket( ntx );
  946. #endif
  947. */
  948. // perform virtual InterruptIN event
  949. status = tmclib_interruptin_process( ctx, eventCtx->interruptIn.ntx );
  950. // check status
  951. if( USBTMC_NOTERROR(status) )
  952. {
  953. switch(status)
  954. {
  955. case tmclib_status_in_progress:
  956. {
  957. my_assert( status != tmclib_status_in_progress ); // 'tmclib_interruptin_process' never returns 'tmclib_status_in_progress'
  958. status = tmclib_status_failure;
  959. }
  960. break;
  961. case tmclib_status_not_in_progress:
  962. {
  963. my_assert( status != tmclib_status_not_in_progress ); // 'tmclib_interruptin_process' never returns 'tmclib_status_not_in_progress'
  964. status = tmclib_status_failure;
  965. }
  966. break;
  967. case tmclib_status_again:
  968. {
  969. my_assert( status != tmclib_status_again ); // 'tmclib_interruptin_process' never returns 'tmclib_status_again'
  970. status = tmclib_status_failure;
  971. }
  972. break;
  973. case tmclib_status_need_data:
  974. {
  975. my_assert( status != tmclib_status_need_data ); // 'tmclib_interruptin_process' never returns 'tmclib_status_need_data'
  976. status = tmclib_status_failure;
  977. }
  978. break;
  979. case tmclib_status_success:
  980. case tmclib_status_no_more_data:
  981. {
  982. // Attention: complete transfer but do not interrupt (do not clear usb_transfer) !
  983. // since no more data is planned to send: abort interrupt-in transfer
  984. status = tmclib_complete_interruptin( ctx->interruptInState.bTag, false );
  985. }
  986. /*no break*/
  987. case tmclib_status_need_read:
  988. {
  989. // if BulkIN event succeded, it is required to
  990. // ... send data from output data.
  991. status = tmclib_status_need_read;
  992. }
  993. break;
  994. default:
  995. my_assert( status == tmclib_status_success ); // 'tmclib_interruptin_process' returns undefined code
  996. }
  997. }
  998. }
  999. }
  1000. }
  1001. break;
  1002. default: status = tmclib_status_invalid_param; // invalid event
  1003. my_assert( false );
  1004. }
  1005. lastRequestStatus = status;
  1006. // check the error code:
  1007. if( USBTMC_ERROR(status) )
  1008. {
  1009. tmclib_interruptin_error( ctx, eventCtx->interruptIn.ntx, status );
  1010. tmclib_abort_interruptin( COMPOUND_tmclib_event_context_abort_interruptin(0, true) );
  1011. status = tmclib_status_failure;
  1012. }
  1013. return status;
  1014. }
  1015. // =================================================================================
  1016. // @tmclib_bulkout_process
  1017. //
  1018. static eTMCLibStatus_t tmclib_bulkout_process( sUSBTMCContext_t * ctx, sUSBTransfer_t * rx )
  1019. {
  1020. // Bytes left in the @rx transfer
  1021. size_t nBytes = usb_count_transfer( rx );
  1022. // Bytes left to receive during current USBTMC transfer
  1023. size_t nBytesLeft = ctx->bulkOutState.transferSize - ctx->bulkOutState.bytesCounter;
  1024. // Alignment bytes requried to receive
  1025. size_t nBytesAlignment = (sizeof(uint32_t) - ctx->bulkOutState.transferSize % sizeof(uint32_t)) % sizeof(uint32_t);
  1026. // retrieve the short packet flag
  1027. bool bShortPacket = usb_transfer_check_shortpacket( rx ); // bulk-out: short packet received?
  1028. // Error identifier: reset
  1029. int32_t nError = SCPILIB_ERROR_SUCCESS;
  1030. // new transfer indicator show if a new transfer started since this packet
  1031. bool bNewTransfer = ctx->bulkOutState.bNewTransfer;
  1032. // Check if the last packet is a short packet (no more data is expected after the short packet)
  1033. if( bShortPacket )
  1034. {
  1035. // If the short packet has been received, the transfer is running out.
  1036. // This is the last BulkOut event in the transfer.
  1037. // Check if the read data counters are match to the expected:
  1038. // UPD. Host can join DEV_DEP_MSG_OUT and REQUEST_DEV_DEP_MSG_IN, and @rx will contain
  1039. // more data than the transfer declares.
  1040. if( nBytes < nBytesLeft + nBytesAlignment )
  1041. {
  1042. nBytes = 0;
  1043. nError = SCPILIB_ERROR_BUFFER_OVERFLOW;
  1044. }
  1045. else
  1046. {
  1047. // if a short packet received then pass @nBytesLeft instead of @nBytes
  1048. nBytes = nBytesLeft; // cut of alignment bytes
  1049. }
  1050. }
  1051. else
  1052. {
  1053. // Calculate whole transfer size
  1054. size_t bytesRequied = (sizeof( ctx->bulkOutHeader ) + nBytesLeft + nBytesAlignment);
  1055. // Since USBTMC Library uses Low-Level USB transfer buffers, it is required
  1056. // the USB Bulk OUT transfer to be not frangmented, so it must fit to the
  1057. // transfer @rx, check it:
  1058. if( usb_size_transfer( rx ) <= bytesRequied )
  1059. {
  1060. // overflow
  1061. (void)nBytes;
  1062. nError = SCPILIB_ERROR_BUFFER_OVERFLOW;
  1063. }
  1064. }
  1065. // check error condition
  1066. if( SCPILIB_ERROR_SUCCESS == nError )
  1067. {
  1068. if( bNewTransfer )
  1069. {
  1070. // Since new transfer started it is required to restart SCPI-parser
  1071. sSCPILibHandle.fNewTransfer();
  1072. }
  1073. switch( sSCPILibHandle.fWrite( usb_transfer_raw_read( rx ), // get raw pointer and pass it to @fWrite
  1074. nBytes, bShortPacket, bNewTransfer ) )
  1075. {
  1076. case eScpiStatus_success: // Both either failed or success statuses means
  1077. case eScpiStatus_failed: // ... that the SCPI library has been processed request.
  1078. { // Need to return @tmclib_status_success to not halt
  1079. // ... Bulk-OUT endpoint.
  1080. // @nBytes bytes have been processed
  1081. lastRequestStatus = tmclib_status_success; // request processed
  1082. }
  1083. break;
  1084. case eScpiStatus_invalid:
  1085. {
  1086. // @nBytes bytes have been processed
  1087. lastRequestStatus = tmclib_status_failure; // development error
  1088. }
  1089. break;
  1090. case eScpiStatus_need_data:
  1091. {
  1092. if( bShortPacket )
  1093. {
  1094. lastRequestStatus = tmclib_status_failure; // development error
  1095. }
  1096. else
  1097. {
  1098. // Need more data to continue, it is required to keep
  1099. // ... @nBytes bytes in the buffer til the next call.
  1100. nBytes = 0; // clear @nBytes to keep data in the buffer
  1101. lastRequestStatus = tmclib_status_need_data;
  1102. }
  1103. }
  1104. break;
  1105. }
  1106. // Retrieve bytes from the buffer
  1107. if( 0 < nBytes )
  1108. {
  1109. // @nBytes bytes have been processed
  1110. usb_transfer_virtual_read( rx, nBytes );
  1111. nBytesLeft -= nBytes;
  1112. // Check if all the protocol data has been processed (except alignment data)
  1113. if( 0 == nBytesLeft )
  1114. {
  1115. if( 0 < nBytesAlignment )
  1116. {
  1117. usb_transfer_virtual_read( rx, nBytesAlignment );
  1118. }
  1119. }
  1120. }
  1121. if( bShortPacket )
  1122. {
  1123. // Since the short packet received the transfer must be terminated
  1124. // Check if there data left in the transfer.
  1125. // If it is, check if there no error occurred?
  1126. if( USBTMC_NOTERROR(lastRequestStatus) && (usb_count_transfer( rx ) > 0) )
  1127. {
  1128. // Yes, there some data left, and no error occurred
  1129. // Maybe it is another USBTMC header?
  1130. tmclib_abort_bulkout( COMPOUND_tmclib_event_context_abort_bulkout_noreset(0, true) );
  1131. // Notify the caller to call the routine again to process the rest data in the transfer
  1132. lastRequestStatus = tmclib_status_again;
  1133. }
  1134. else
  1135. {
  1136. // No data or error occurred, just reset transfer
  1137. tmclib_abort_bulkout( COMPOUND_tmclib_event_context_abort_bulkout(0, true) );
  1138. }
  1139. }
  1140. // reset 'new transfer' indicator
  1141. ctx->bulkOutState.bNewTransfer = false;
  1142. }
  1143. else
  1144. {
  1145. // Error condition.
  1146. // Notify the SCPI level
  1147. switch( sSCPILibHandle.fError( nError, NULL ) )
  1148. {
  1149. case eScpiStatus_success:
  1150. lastRequestStatus = tmclib_status_success; // error processed
  1151. break;
  1152. case eScpiStatus_failed: // Unrecoverable error
  1153. case eScpiStatus_invalid:
  1154. lastRequestStatus = tmclib_status_failure;
  1155. break;
  1156. case eScpiStatus_need_data: // Forbidden states
  1157. default:
  1158. my_assert( false );
  1159. lastRequestStatus = tmclib_status_failure;
  1160. }
  1161. // reset transfer
  1162. tmclib_abort_bulkout( COMPOUND_tmclib_event_context_abort_bulkout(0, true) );
  1163. }
  1164. // 3.2 Bulk-OUT endpoint, [1]
  1165. // 3.2.2.3 Bulk-OUT transfer protocol errors, [1]
  1166. return ( lastRequestStatus );
  1167. }
  1168. // =================================================================================
  1169. // tmclib_bulkin_process()
  1170. // Processes BulkIN transfer.
  1171. //
  1172. // Note: User shall reset Short-Packet indicator using @usb_transfer_modify_flags
  1173. // ... routine to avoid sending short packet in case no data queued into the transfer
  1174. // ... after successful call (return true with empty transfer)
  1175. static eTMCLibStatus_t tmclib_bulkin_process( sUSBTMCContext_t * ctx, sUSBTransfer_t * tx )
  1176. {
  1177. // Bytes free in the @tx transfer
  1178. size_t nBytes = usb_space_transfer( tx );
  1179. size_t nBytesOut = 0;
  1180. // Due to USBTMC required to send data by portions with
  1181. // ... the length multiple of 4, it is required to limit the
  1182. // ... buffers size up to the maximum length multiple of 4 to
  1183. // ... avoid the case when it is there no free space in the
  1184. // ... buffer to add alinment bytes in the end.
  1185. nBytes -= nBytes%sizeof(uint32_t);
  1186. #warning SCPI freeSpace+sentCount ?????
  1187. // Check the transfer boundary: @bytesCounter (sent) + @nBytes (available space)
  1188. if( nBytes + ctx->bulkInState.bytesCounter >
  1189. ctx->bulkInState.transferSize )
  1190. {
  1191. // limit the buffer space
  1192. // TransferSize does not include the number of bytes in BulkIN header or alignment bytes
  1193. nBytes = ctx->bulkInState.transferSize - ctx->bulkInState.bytesCounter;
  1194. }
  1195. // check if current transfer ran out:
  1196. // check if all the data is already queued in transfer:
  1197. if( 0 == nBytes )
  1198. {
  1199. // set success status without queuing any data
  1200. lastRequestStatus = tmclib_status_success;
  1201. // check if all the data is already send from transfer:
  1202. if( 0 == usb_count_transfer( tx ) )
  1203. {
  1204. // close Bulk-IN transfer due to there no more data to send
  1205. // Do not clear short packet indicator (use COMPOUND_tmclib_event_context_complete_bulkin instead of COMPOUND_tmclib_event_context_abort_bulkin!)
  1206. tmclib_abort_bulkin( COMPOUND_tmclib_event_context_complete_bulkin(ctx->bulkInHeader.bTag, false) );
  1207. // set informative status: equal to 'tmclib_status_success'
  1208. lastRequestStatus = tmclib_status_no_more_data;
  1209. }
  1210. // do not queue any data
  1211. nBytesOut = 0;
  1212. }
  1213. else
  1214. {
  1215. bool EOM = true; // forward set
  1216. // generate SCPI-parser read-event
  1217. switch( sSCPILibHandle.fRead( usb_transfer_raw_write( tx ), // get raw pointer and pass it to @fRead
  1218. nBytes, &nBytesOut, &EOM ) )
  1219. #warning SCPI write more than TransferSize due to sw buffer (@tx) is larger than TransferSize
  1220. {
  1221. case eScpiStatus_failed:
  1222. {
  1223. nBytesOut = 0; // due to error: clear @nBytesOut
  1224. // // SCPI library has been failed during the request processing.
  1225. // Need to return @eScpiStatus_failed to halt Bulk-OUT endpoint.
  1226. tmclib_abort_bulkin( COMPOUND_tmclib_event_context_abort_bulkin(ctx->bulkInHeader.bTag, false) );
  1227. // this is to unlock transfer flags only
  1228. usb_transfer_clear_shortpacket( tx );
  1229. lastRequestStatus = tmclib_status_read_error;
  1230. }
  1231. break;
  1232. case eScpiStatus_success:
  1233. {
  1234. // // SCPI library has been successfully processed the request.
  1235. // Need to return @tmclib_status_success to not halt Bulk-OUT endpoint.
  1236. // @EOM: is true if there no data is planned to transfer, it is required
  1237. // ... to indicate that this message is the last one in current transfer;
  1238. // @EOM: is false if it is required to generate another READ event to indicate
  1239. // that this message is NOT the last one in current transfer;
  1240. ctx->bulkInState.bEndOfMessage = EOM; // set End-of-message indicator
  1241. if( 0 < nBytesOut )
  1242. {
  1243. // @nBytesOut bytes have been placed into the output buffer
  1244. ctx->bulkInState.bytesCounter += nBytesOut;
  1245. #if DEBUG_USBTMC > 0 // SCPI debug only
  1246. gDebugUSBTMC_TxBytes += nBytesOut;
  1247. #endif
  1248. // since it is the last transaction, it is required adjust
  1249. // ... the ending data boundary to fit the 32-bit alignment
  1250. // ... using the entire transfer bytes counter @bytesCounter:
  1251. nBytesOut += sizeof(uint32_t) - ctx->bulkInState.bytesCounter%sizeof(uint32_t);
  1252. }
  1253. // update current transfer size: set to current transfer counter
  1254. ctx->bulkInState.transferSize = ctx->bulkInState.bytesCounter;
  1255. // update bulk-in header in current buffer
  1256. tmclib_update_bulkin( ctx );
  1257. lastRequestStatus = tmclib_status_success; // request processed
  1258. }
  1259. break;
  1260. case eScpiStatus_invalid:
  1261. {
  1262. // @nBytes bytes have been processed
  1263. lastRequestStatus = tmclib_status_failure; // development error
  1264. }
  1265. break;
  1266. case eScpiStatus_need_data:
  1267. {
  1268. // Need more free space to continue, it is required to
  1269. // ... send @nBytesOut bytes from output buffer.
  1270. ctx->bulkInState.bytesCounter += nBytesOut;
  1271. #if DEBUG_USBTMC > 0 // SCPI debug only
  1272. gDebugUSBTMC_TxBytes += nBytesOut;
  1273. #endif
  1274. // since more data is planned to transfer, it is required
  1275. // ... to indicate that this message is not the last one in
  1276. // ... current transfer:
  1277. ctx->bulkInState.bEndOfMessage = false; // reset End-of-message indicator
  1278. // update current transfer size: set to current transfer counter
  1279. ctx->bulkInState.transferSize = ctx->bulkInState.bytesCounter;
  1280. // update bulk-in header in current buffer
  1281. tmclib_update_bulkin( ctx );
  1282. // set status
  1283. lastRequestStatus = tmclib_status_need_read;
  1284. }
  1285. break;
  1286. }
  1287. }
  1288. // perform virtual write (the data is already in the buffer)
  1289. usb_transfer_virtual_write( tx, nBytesOut );
  1290. // reset 'new transfer' indicator
  1291. ctx->bulkInState.bNewTransfer = false;
  1292. return lastRequestStatus;
  1293. }
  1294. // =================================================================================
  1295. // tmclib_interruptin_process()
  1296. // Processes InterruptIN transfer.
  1297. //
  1298. static eTMCLibStatus_t tmclib_interruptin_process( sUSBTMCContext_t * ctx, sUSBTransfer_t * ntx )
  1299. {
  1300. // Bytes free in the @tx transfer
  1301. size_t nBytes = usb_space_transfer( ntx );
  1302. size_t nBytesOut = 0;
  1303. // check if current transfer ran out:
  1304. // check if all the data is already queued in transfer:
  1305. if( 0 == nBytes )
  1306. {
  1307. // set success status without queuing any data
  1308. lastRequestStatus = tmclib_status_success;
  1309. // check if all the data is already send from transfer:
  1310. if( 0 == usb_count_transfer( ntx ) )
  1311. {
  1312. // close Bulk-IN transfer due to there no more data to send
  1313. tmclib_abort_interruptin( COMPOUND_tmclib_event_context_abort_interruptin(ctx->interruptInState.bTag, false) );
  1314. // set informative status: equal to 'tmclib_status_success'
  1315. lastRequestStatus = tmclib_status_no_more_data;
  1316. }
  1317. // do not queue any data
  1318. nBytesOut = 0;
  1319. }
  1320. else
  1321. {
  1322. // generate SCPI-parser read-event
  1323. switch( sSCPILibHandle.fNotificationRead( usb_transfer_raw_write( ntx ), // get raw pointer and pass it to @fRead
  1324. nBytes, &nBytesOut, &ctx->interruptInState.STB ) )
  1325. {
  1326. case eScpiStatus_failed:
  1327. {
  1328. nBytesOut = 0; // due to error: clear @nBytesOut
  1329. // SCPI library has been failed during the request processing.
  1330. // Need to return @eScpiStatus_failed to halt Interrupt-IN endpoint.
  1331. tmclib_abort_interruptin( COMPOUND_tmclib_event_context_abort_interruptin(ctx->interruptInState.bTag, false) );
  1332. // this is to unlock transfer flags only
  1333. usb_transfer_clear_shortpacket( ntx );
  1334. lastRequestStatus = tmclib_status_read_error;
  1335. }
  1336. break;
  1337. case eScpiStatus_success:
  1338. {
  1339. // // SCPI library has been successfully processed the request.
  1340. // Need to return @tmclib_status_success to not halt endpoint.
  1341. // since no data is planned to transfer, it is required
  1342. // ... to indicate that this message is the last one in
  1343. // ... current transfer:
  1344. ctx->interruptInState.bEndOfMessage = true; // set End-of-message indicator
  1345. if( 0 < nBytesOut )
  1346. {
  1347. // @nBytesOut bytes have been placed into the output buffer
  1348. ctx->interruptInState.bytesCounter += nBytesOut;
  1349. }
  1350. // update bulk-in header in current buffer
  1351. tmclib_update_notification( ctx );
  1352. lastRequestStatus = tmclib_status_success; // request processed
  1353. }
  1354. break;
  1355. case eScpiStatus_invalid:
  1356. {
  1357. // @nBytes bytes have been processed
  1358. lastRequestStatus = tmclib_status_failure; // development error
  1359. }
  1360. break;
  1361. case eScpiStatus_need_data:
  1362. {
  1363. // Need more free space to continue, it is required to
  1364. // ... send @nBytesOut bytes from output buffer.
  1365. ctx->interruptInState.bytesCounter += nBytesOut;
  1366. // since more data is planned to transfer, it is required
  1367. // ... to indicate that this message is not the last one in
  1368. // ... current transfer:
  1369. ctx->interruptInState.bEndOfMessage = false; // reset End-of-message indicator
  1370. // update bulk-in header in current buffer
  1371. tmclib_update_notification( ctx );
  1372. // set status
  1373. lastRequestStatus = tmclib_status_need_read;
  1374. }
  1375. break;
  1376. }
  1377. }
  1378. // perform virtual write (the data is already in the buffer)
  1379. usb_transfer_virtual_write( ntx, nBytesOut );
  1380. // reset 'new transfer' indicator
  1381. ctx->interruptInState.bNewTransfer = false;
  1382. return lastRequestStatus;
  1383. }
  1384. // =================================================================================
  1385. // @tmclib_device_clear
  1386. // Resets the USBTMC and SCPI state
  1387. // @eventCtx - event context (sTMCDeviceClearEventCtx_t)
  1388. // @eventCtx->event - event id to process:
  1389. // * eTMCEventDeviceClear - resets the USBTMC and SCPI state
  1390. // @eventCtx->clear.resetTransport - reset all the transfers
  1391. //
  1392. // Returns: the operation status:
  1393. // tmclib_status_success in case of success,
  1394. // tmclib_status_failure otherwise
  1395. //
  1396. static eTMCLibStatus_t tmclib_device_clear( sTMCEventContext_t * eventCtx )
  1397. {
  1398. if( eventCtx->clear.resetTransport )
  1399. {
  1400. eventCtx->abort.transfer_bTag = 0;
  1401. eventCtx->abort.clearShortPacketIndicator = true;
  1402. eventCtx->abort.force = true;
  1403. eventCtx->abort.noResetTransfer = false;
  1404. tmclib_abort_bulkin( eventCtx );
  1405. tmclib_abort_bulkout( eventCtx );
  1406. tmclib_abort_interruptin( eventCtx );
  1407. }
  1408. // Reset SCPI Parser and FSM state
  1409. if( eScpiStatus_success == sSCPILibHandle.fReset() )
  1410. {
  1411. return tmclib_status_success;
  1412. }
  1413. return tmclib_status_failure;
  1414. }
  1415. // =================================================================================
  1416. static void tmclib_bulkout_error( sUSBTMCContext_t * ctx, sUSBTransfer_t * rx, eTMCLibStatus_t status )
  1417. {
  1418. }
  1419. // =================================================================================
  1420. static void tmclib_bulkin_error( sUSBTMCContext_t * ctx, sUSBTransfer_t * tx, eTMCLibStatus_t status )
  1421. {
  1422. }
  1423. // =================================================================================
  1424. static void tmclib_interruptin_error( sUSBTMCContext_t * ctx, sUSBTransfer_t * tx, eTMCLibStatus_t status )
  1425. {
  1426. }
  1427. // =================================================================================
  1428. // @tmclib_generic_event()
  1429. // Processes USBTMC specific event.
  1430. // @eventCtx - event context, all the fields must be filled in accordance to @eventCtx->event code
  1431. // @eventCtx->event - event identifier:
  1432. //
  1433. // +------------------------------------------------------------------------------------------------------------
  1434. // * eTMCEventBulkInStop - Aborts currently running BulkIN transfer
  1435. // |---> @eventCtx->abort:
  1436. // | - @transfer_bTag - The bTag value associated with the transfer to abort, see 4.2.1.4 [1]
  1437. // | - @force - makes to ignore the @transfer_bTag if true
  1438. // +------------------------------------------------------------------------------------------------------------
  1439. // * eTMCEventBulkOutStop - Aborts currently running BulkOUT transfer
  1440. // |---> @eventCtx->abort:
  1441. // | - @transfer_bTag - The bTag value associated with the transfer to abort, see 4.2.1.2 [1]
  1442. // | - @force - makes to ignore the @transfer_bTag if true
  1443. // +------------------------------------------------------------------------------------------------------------
  1444. // * eTMCEventInterruptInStop - Aborts currently running InterruptIN transfer
  1445. // |---> @eventCtx->abort:
  1446. // | - @transfer_bTag - The bTag value associated with the transfer to abort, see 4.3.1 [2]
  1447. // | - @force - makes to ignore the @transfer_bTag if true
  1448. // +------------------------------------------------------------------------------------------------------------
  1449. // * eTMCEventBulkIn - Processes USBTMC Bulk-IN event
  1450. // |---> @eventCtx->bulkIn:
  1451. // | - @tx - the buffer object to be used to transmit data
  1452. // +------------------------------------------------------------------------------------------------------------
  1453. // * eTMCEventBulkOut - Processes USBTMC Bulk-OUT event
  1454. // |---> @eventCtx->bulkOut:
  1455. // | - @rx - the buffer object to be used to receive data
  1456. // +------------------------------------------------------------------------------------------------------------
  1457. // * eTMCEventInterruptInStart - Initialize new Interrupt-IN transfer w/o data processing
  1458. // | ...The function only creates new transfer without calling Tx-Handler. This call must be
  1459. // | ...provided before 'eTMCEventInterruptIn' event to prapare transfer.
  1460. // |----> @eventCtx->interruptIn:
  1461. // | - @ntx - must be NULL, or 'tmclib_status_invalid_param' will be returned otherwise
  1462. // | - @bTag - the Tag identifier, [2], 3.4.2 Interrupt-IN DATA sent due to READ_STATUS_BYTE request,
  1463. // +------------------------------------------------------------------------------------------------------------
  1464. // * eTMCEventInterruptIn - Processes USBTMC Interrupt-IN event.
  1465. // | Note that 'eTMCEventInterruptInStart' must be generated before 'eTMCEventInterruptIn' for normal operation.
  1466. // | Note: Each event generates a single INTERRUPT-IN packet begining with Interrupt-IN header
  1467. // | Note: Each interrupt-in event must be not longer than @ntx transfer length.
  1468. // | Note: In case it is required to send more data than @ntx can carry, you need:
  1469. // | - increase Interrupt-IN EP buffer (see USB specification) and increase @ntx transfer space
  1470. // | or:
  1471. // | - send the data using multiple packets (each packet begins with INTERRUPT-IN header), pay
  1472. // | attention that @ctx->interruptInState will not be reset until user layer return tmclib_status_success
  1473. // | or tmclib_status_no_more_data.
  1474. // |----> @eventCtx->interruptIn:
  1475. // | - @ntx - the buffer object to be used to transmit data
  1476. // | - @bTag - don't care
  1477. // +------------------------------------------------------------------------------------------------------------
  1478. //
  1479. // Returns: the operation status:
  1480. // tmclib_status_success in case of success,
  1481. // tmclib_status_failure otherwise
  1482. //
  1483. eTMCLibStatus_t tmclib_generic_event( sTMCEventContext_t * eventCtx )
  1484. {
  1485. switch( eventCtx->event )
  1486. {
  1487. case eTMCEventInterruptInStart: // InterruptIn initialize (only for Interrupt-IN)
  1488. return tmclib_interruptin_event( eventCtx );
  1489. case eTMCEventBulkIn: // BulkIn event
  1490. return tmclib_bulkin_event( eventCtx );
  1491. case eTMCEventBulkOut: // BulkOut event
  1492. return tmclib_bulkout_event( eventCtx );
  1493. case eTMCEventInterruptIn: // InterruptIn event
  1494. return tmclib_interruptin_event( eventCtx );
  1495. case eTMCEventBulkInStop: // BulkIn abort
  1496. return tmclib_abort_bulkin( eventCtx );
  1497. case eTMCEventBulkOutStop: // BulkOut abort
  1498. return tmclib_abort_bulkout( eventCtx );
  1499. case eTMCEventInterruptInStop: // InterruptIn abort
  1500. return tmclib_abort_interruptin( eventCtx );
  1501. case eTMCEventDeviceClear: // Device Clear
  1502. return tmclib_device_clear( eventCtx );
  1503. }
  1504. return tmclib_status_invalid_param;
  1505. }