usb_application_usbtmc.c 47 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040
  1. #define USB_APPLICATION_USBTMC_C
  2. #include "usb/usb_config.h"
  3. #include "usb/usb_bridge.h"
  4. #include "usbd_usbtmc.h"
  5. #include "usbapp/usb_application_usbtmc.h"
  6. #include "usbapp/usbtmclib/usbtmclib_basic.h"
  7. #include "app/led/led.h"
  8. #include "my_assert.h"
  9. //----------------------------------------------------------------
  10. // Refer to:
  11. // [1] USBTMC Standard, rev. 1.0, 14/04/2003
  12. // "Universal Serial Bus Test and Measurement Class Specification (USBTMC)"
  13. // [2] USBTMC-USB488 Standard, rev. 1.0, 14/04/2003
  14. // "Universal Serial Bus Test and Measurement Class, Subclass USB488 Specification (USBTMC-USB488)
  15. // [3] IEEE 488.1 Standard, ANSI/IEEE Std 488.1-1987
  16. // "IEEE Standard Digital Interface, ANSI/IEEE Std 488.1-1987"
  17. // [4] IEEE 488.2 Standard, revision IEEE Std 488.2-1987
  18. // "IEEE Standard Codes, Formats, Protocols, and Common Commands for Use With IEEE Std 488.1-1987, IEEE
  19. // Standard Digital Interface for Programmable Instrumentation"
  20. // [5] SCPI Specification, revision 1999.0
  21. // "Standard Commands for Programmable Instruments (SCPI), VERSION 1999.0, May 1999"
  22. //----------------------------------------------------------------
  23. #if DEBUG_USBTMC_REQUESTS > 0
  24. #define MAX_DEBUG_LOG 10
  25. volatile int gDebugLogIdx = 0;
  26. volatile int gDebugLogRollover = 0;
  27. static uint32_t gDebugLog[ MAX_DEBUG_LOG ] = {0};
  28. void debug_log( uint8_t value, uint16_t value2 )
  29. {
  30. if( gDebugLogIdx == 0 )
  31. {
  32. memset( gDebugLog, 0, sizeof(gDebugLog) );
  33. }
  34. if( gDebugLogIdx >= MAX_DEBUG_LOG )
  35. {
  36. memset( gDebugLog, 0, sizeof(gDebugLog) );
  37. gDebugLogIdx = 0;
  38. gDebugLogRollover++;
  39. }
  40. gDebugLog[ gDebugLogIdx++ ] = (((uint32_t)value2) << 16) | value;
  41. }
  42. #define DEBUG_LOG_STATE_INITABIN 0x01
  43. #define DEBUG_LOG_STATE_CHKSTATUS_PEND 0x02
  44. #define DEBUG_LOG_STATE_CHKSTATUS_OK 0x03
  45. #define DEBUG_LOG_STATE_DATAIN 0x04
  46. #endif
  47. //----------------------------------------------------------------
  48. #define INDICATOR_PULSE_REQUEST_SUPPORT (CONFIG_LEDS) // enable INDICATOR_PULSE if CONFIG_LEDS is available
  49. //----------------------------------------------------------------
  50. static int8_t fUSBTMCProto_Init();
  51. static int8_t fUSBTMCProto_DeInit();
  52. static void fUSBTMCProto_Reset();
  53. static bool fUSBTMCProto_Setup( const tUSBSetupPacket_t * pSetup, bool bFirstStage, bool success );
  54. static size_t fUSBTMCProto_ControlRx( const tUSBSetupPacket_t * pSetup, sUSBTransfer_t * rx, size_t idx, size_t bytesRemaining );
  55. static size_t fUSBTMCProto_ControlTx( const tUSBSetupPacket_t * pSetup, sUSBTransfer_t * tx, size_t idx, size_t bytesRemaining );
  56. const sUSBAppEntry_Control_t usbapplication_USBTMC_control = {
  57. .fUsbInit = fUSBTMCProto_Init,
  58. .fUsbDeInit = fUSBTMCProto_DeInit,
  59. .fUsbSetup = fUSBTMCProto_Setup,
  60. .fUsbCtlEpRx = fUSBTMCProto_ControlRx,
  61. .fUsbCtlEpTx = fUSBTMCProto_ControlTx,
  62. .fResetEvent = fUSBTMCProto_Reset,
  63. };
  64. // USBTMC_datain_beginsend()
  65. // Begin the transmission using DataIN handler virtual call.
  66. // Due to the hardware does not support NAK-sent-interrupt, it is
  67. // required to initiate the first packet sending to start TX-flow (DataIN).
  68. // This function issues the first packet sending using virtual DataIN event.
  69. uint8_t USBTMC_datain_beginsend( uint8_t epnum );
  70. // USBTMC_datain_sendprepared()
  71. // Begin the transmission using already prepared TX-transfer.
  72. // Due to the hardware does not support NAK-sent-interrupt, it is
  73. // required to initiate the first packet sending to start TX-flow (DataIN).
  74. // This function issues the first packet sending using virtual DataIN event.
  75. uint8_t USBTMC_datain_sendprepared( uint8_t epnum );
  76. // USBTMC_datain_zerosend()
  77. // Queue zero packet in BulkIN EP without calling TX-handler
  78. uint8_t USBTMC_datain_zerosend( uint8_t epnum );
  79. static bool fUSBTMCProto_DataRxHandler( uint8_t bEpLogAddress, sUSBTransfer_t * rx );
  80. static bool fUSBTMCProto_DataTxHandler( uint8_t bEpLogAddress, sUSBTransfer_t * tx );
  81. static bool fUSBTMCProto_DataErrHandler( uint8_t bEpLogAddress, uint32_t error );
  82. static bool fUSBTMCProto_IntTxHandler( uint8_t bEpLogAddress, sUSBTransfer_t * tx );
  83. static bool fUSBTMCProto_IntErrHandler( uint8_t bEpLogAddress, uint32_t error );
  84. // @usbapplication_USBTMC_dataapp
  85. // Data channel handler descriptor
  86. const sUSBAppEntry_Data_t usbapplication_USBTMC_dataapp = {
  87. .fDataInitHandler = NULL,
  88. .fDataRxHandler = fUSBTMCProto_DataRxHandler,
  89. .fDataTxHandler = fUSBTMCProto_DataTxHandler,
  90. .fDataErrHandler = fUSBTMCProto_DataErrHandler,
  91. .fDataDeInitHandler = NULL,
  92. };
  93. // @usbapplication_USBTMC_intapp
  94. // Interrupt channel handler descriptor
  95. const sUSBAppEntry_Data_t usbapplication_USBTMC_intapp = {
  96. .fDataInitHandler = NULL,
  97. .fDataRxHandler = NULL, // no data receiving is expected
  98. .fDataTxHandler = fUSBTMCProto_IntTxHandler,
  99. .fDataErrHandler = fUSBTMCProto_IntErrHandler,
  100. .fDataDeInitHandler = NULL,
  101. };
  102. //===========================================================================================
  103. #if INDICATOR_PULSE_REQUEST_SUPPORT
  104. // 4.2.1.8 GET_CAPABILITIES, table 37, [1]
  105. // Refer to @sUSBTMC_GetCapabilities_Response_t
  106. #define USBTMC_IFACE_CAPABILITIES (USBTMC_IFACE_CAPABILITIES_INDICATOR_PULSE) // Indicator Pulse request is supported :)
  107. #else
  108. // 4.2.1.8 GET_CAPABILITIES, table 37, [1]
  109. // Refer to @sUSBTMC_GetCapabilities_Response_t
  110. #define USBTMC_IFACE_CAPABILITIES (0) // No Indicator Pulse request supported :(
  111. #endif
  112. // 4.2.1.8 GET_CAPABILITIES, table 37, [1]
  113. // Refer to @sUSBTMC_GetCapabilities_Response_t
  114. #define USBTMC_DEVICE_CAPABILITIES (0)
  115. // 4.2.2 GET_CAPABILITIES, table 8, [2]
  116. // Refer to @sUSB488_GetCapabilities_Response_t
  117. #define USB488_IFACE_CAPABILITIES (USB488_IFACE_CAPABILITIES_4882IF)
  118. // 4.2.2 GET_CAPABILITIES, table 8, [2]
  119. // Refer to @sUSB488_GetCapabilities_Response_t
  120. #define USB488_DEVICE_CAPABILITIES (USB488_DEVICE_CAPABILITIES_SERVICE_REQUEST | USB488_DEVICE_CAPABILITIES_SCPI)
  121. // ===================================================================================
  122. // @sUsbTmcContext
  123. // Local module context variables
  124. static struct {
  125. //sUSBTransfer_t * xBulkOutTransfer; // data buffer for Bulk-Out transfer
  126. //sUSBTransfer_t * xBulkInTransfer; // data buffer for Bulk-In transfer
  127. const USBD_DescriptorsTypeDef * xDescHandlers; // class GetDescriptor handlers set
  128. bool bInitiateBulkOutAbort; // Initiate BulkOut abort request flag: true if received, false otherwise
  129. bool bInitiateBulkInAbort; // Initiate BulkIn abort request flag: true if received, false otherwise
  130. bool bInitiateClear; // Initiate Clear request flag: true if received, false otherwise
  131. struct
  132. {
  133. union
  134. {
  135. uint8_t rawBytesResponse[1]; // byte-array access to avoid casting and warnings
  136. sUSBTMC_InitiateAbortBulkInOut_Response_t responseInitiateAbortBulkX;
  137. sUSBTMC_CheckAbortBulkOut_Response_t responseCheckAbortBulkOut;
  138. sUSBTMC_CheckAbortBulkIn_Response_t responseCheckAbortBulkIn;
  139. sUSBTMC_InitiateClear_Response_t responseInitiateClear;
  140. sUSBTMC_CheckClear_Response_t responseCheckClear;
  141. sUSBTMC_GetCapabilities_Response_t responseGetCapabilities;
  142. sUSBTMC_IndicatorPulse_Response_t responseIndicatorPulse;
  143. sUSBTMC_USB488_ReadStatusByte_Response_t responseUsb488ReadStatusByte;
  144. };
  145. }
  146. tmpSetup; // temporary variables are valid during single request: Setup -> Rx/Tx
  147. } sUsbTmcContext;
  148. // ===================================================================================
  149. static int8_t fUSBTMCProto_Init()
  150. {
  151. // Check the Control-OUT buffer size
  152. // If the buffer size is less than the maximum packet size to be sent:
  153. if( usbd_usbtmc_get_control_tx_transfer_size() < sizeof( sUsbTmcContext.tmpSetup ) )
  154. {
  155. // Error: the buffer size is less than the maximum packet size to be sent.
  156. // See @fUSBTMCProto_ControlTx for details.
  157. // The function @fUSBTMCProto_ControlTx does not support multi-packet mode
  158. return -1; // error:
  159. }
  160. // Register Bulk-Data handler -> @usbapplication_USBTMC_dataapp
  161. usb_bridge_register_dataapp( USBTMC_BULKIO_EP, &usbapplication_USBTMC_dataapp );
  162. // Register Interrupt-Data handler -> @usbapplication_USBTMC_intapp
  163. usb_bridge_register_dataapp( USBTMC_INTIO_EP, &usbapplication_USBTMC_intapp );
  164. sUsbTmcContext.bInitiateBulkOutAbort = false;
  165. sUsbTmcContext.bInitiateBulkInAbort = false;
  166. sUsbTmcContext.bInitiateClear = false;
  167. //sUsbTmcContext.xBulkOutTransfer = ;
  168. //sUsbTmcContext.xBulkInTransfer = USBD_USBTMC_GetDataTxTransferHandle();
  169. sUsbTmcContext.xDescHandlers = USBD_USBTMC_GetDescriptorHandlers();
  170. if( tmclib_status_success != tmclib_init(
  171. USBD_USBTMC_GetDataRxTransferHandle(),
  172. USBD_USBTMC_GetDataTxTransferHandle(),
  173. USBD_USBTMC_GetInterruptTxTransferHandle() )
  174. )
  175. {
  176. return -1; // error
  177. }
  178. return 0;
  179. }
  180. // ===================================================================================
  181. static int8_t fUSBTMCProto_DeInit()
  182. {
  183. usb_bridge_unregister_dataapp( USBTMC_BULKIO_EP );
  184. usb_bridge_unregister_dataapp( USBTMC_INTIO_EP );
  185. tmclib_deinit();
  186. return 0;
  187. }
  188. // ===================================================================================
  189. // @fUSBTMCProto_Reset
  190. // USB Bus reset event
  191. static void fUSBTMCProto_Reset()
  192. {
  193. tmclib_generic_event( COMPOUND_tmclib_event_context_abort_bulkout(0, true) );
  194. tmclib_generic_event( COMPOUND_tmclib_event_context_abort_bulkin(0, true) );
  195. tmclib_generic_event( COMPOUND_tmclib_event_context_abort_interruptin(0, true) );
  196. sUsbTmcContext.bInitiateBulkOutAbort = false;
  197. sUsbTmcContext.bInitiateBulkInAbort = false;
  198. sUsbTmcContext.bInitiateClear = false;
  199. }
  200. // ===================================================================================
  201. // @fUSBTMCProto_Setup
  202. // USBTMC protocol, USB Setup Handler
  203. // Processes the class requests and reacts to some standard requests
  204. static bool fUSBTMCProto_Setup( const tUSBSetupPacket_t * pSetup, bool bFirstStage, bool success )
  205. {
  206. // Check the request type
  207. switch( pSetup->bmRequest & USB_REQ_TYPE_MASK )
  208. {
  209. // Standard request: this call is performed BEFORE the ENDPOINT clearing by core
  210. case USB_REQ_TYPE_STANDARD:
  211. {
  212. // Check request ID:
  213. switch( pSetup->bRequest )
  214. {
  215. // USBTMC must process CLEAR_FEATURE standard request with type ENDPOINT_HALT:
  216. // see section 4.1 "Standard requests", [1]
  217. case USB_REQ_CLEAR_FEATURE:
  218. {
  219. // process ENDPOINT_HALT request type:
  220. if( USB_FEATURE_EP_HALT == pSetup->wValue )
  221. {
  222. // Host tries to restore synchronization: clear stalled endpoint
  223. // check the endpoint address:
  224. switch( pSetup->wIndex )
  225. {
  226. case USBTMC_BULKOUT_EP:
  227. // section 4.1.1.1 "USBTMC interface Bulk-OUT endpoints", [1]
  228. tmclib_generic_event( COMPOUND_tmclib_event_context_abort_bulkout(0, true) ); // forced interrupt current transfer
  229. // Clear EP and reset the buffer, restart receiving
  230. USBD_USBTMC_ClearEP( USBTMC_BULKOUT_EP );
  231. return true; // pass this request, core does the job
  232. break;
  233. case USBTMC_BULKIN_EP:
  234. // section 4.1.1.2 "USBTMC interface Bulk-IN endpoints", [1]
  235. tmclib_generic_event( COMPOUND_tmclib_event_context_abort_bulkin(0, true) ); // forced interrupt current transfer
  236. // Clear EP and reset the buffer
  237. USBD_USBTMC_NakEP( USBTMC_BULKIN_EP ); // set NAK instead of VALID
  238. return true; // pass this request, core does the job
  239. break;
  240. case USBTMC_INTERRUPTIN_EP:
  241. // [1] has no information about such event
  242. // Do processing in formal way: abort the transfer and set NAK state over EP
  243. tmclib_generic_event( COMPOUND_tmclib_event_context_abort_interruptin(0, true) ); // forced interrupt current transfer
  244. // Clear EP and reset the buffer
  245. USBD_USBTMC_NakEP( USBTMC_INTERRUPTIN_EP ); // set NAK instead of VALID
  246. return true; // pass this request, core does the job
  247. break;
  248. }
  249. }
  250. }
  251. break;
  252. }
  253. }
  254. break;
  255. // see 4.2.1 "USBTMC requests", [1]
  256. case USB_REQ_TYPE_CLASS:
  257. {
  258. // In accordance with USBTMC standard [1], the code "STATUS_SUCCESS" means
  259. // the device queued the INITIATE request to be performed.
  260. // @bInitiateBulkInAbort must remember if such request is queued in case
  261. // the host will try to queue another request. If host performs another
  262. // request, the device must discard the response for previously queued request
  263. // and queue new request only if the previous request is already done.
  264. // But if the device executes this request synchroniusly, there no previously
  265. // request pending, and the request is always done.
  266. // In other words, @bInitiateBulkInAbort shows only if is there the response
  267. // prepared for previously INITIATE request or not for next CHECK_STATUS request.
  268. // 4.2.1.1 "USBTMC split transactions", point 3, [1]
  269. if( sUsbTmcContext.bInitiateBulkOutAbort &&
  270. (eUSBTMC_INITIATE_ABORT_BULK_OUT == pSetup->bRequest ||
  271. eUSBTMC_INITIATE_CLEAR == pSetup->bRequest ) )
  272. {
  273. // reset the prepared response: comes down to reseting the flag
  274. sUsbTmcContext.bInitiateBulkOutAbort = false;
  275. }
  276. // ---
  277. // 4.2.1.1 "USBTMC split transactions", point 3, [1]
  278. if( sUsbTmcContext.bInitiateBulkInAbort &&
  279. (eUSBTMC_INITIATE_ABORT_BULK_IN == pSetup->bRequest ||
  280. eUSBTMC_INITIATE_CLEAR == pSetup->bRequest ) )
  281. {
  282. // reset the prepared response: comes down to reseting the flag
  283. sUsbTmcContext.bInitiateBulkInAbort = false;
  284. }
  285. // ---
  286. // 4.2.1.1 "USBTMC split transactions", point 3, [1]
  287. if( sUsbTmcContext.bInitiateClear && (eUSBTMC_CHECK_CLEAR_STATUS != pSetup->bRequest) )
  288. {
  289. // reset the prepared response: comes down to reseting the flag
  290. sUsbTmcContext.bInitiateClear = false;
  291. }
  292. // ---
  293. // Check request ID:
  294. switch( pSetup->bRequest )
  295. {
  296. // Aborts a Bulk-OUT transfer.
  297. // see 4.2.1.2 "INITIATE_ABORT_BULK_OUT", [1]
  298. case eUSBTMC_INITIATE_ABORT_BULK_OUT:
  299. {
  300. if( pSetup->wIndex != USBTMC_BULKOUT_EP )
  301. return false; // Error, 4.2.1.2 INITIATE_ABORT_BULK_OUT, [1]
  302. // zero init the response bytes
  303. memset( sUsbTmcContext.tmpSetup.rawBytesResponse, 0, sizeof(sUsbTmcContext.tmpSetup.responseInitiateAbortBulkX) );
  304. // preserve the bTag to put the value into the response (fUSBTMCProto_ControlRx)
  305. tmclib_bulkout_gettag_latest( &sUsbTmcContext.tmpSetup.responseInitiateAbortBulkX.bTag );
  306. // try to abort BulkOut transfer with the specified bTag
  307. if( tmclib_status_success == tmclib_generic_event( COMPOUND_tmclib_event_context_abort_bulkout((uint8_t)pSetup->wValue, false) ) )
  308. {
  309. // Halt the BulkOut endpoint to interrupt the transfer, 4.2.1.2, table 18 [1]
  310. USBD_USBTMC_StallEP( USBTMC_BULKOUT_EP );
  311. sUsbTmcContext.bInitiateBulkOutAbort = true; // INITIATE response prepared
  312. sUsbTmcContext.tmpSetup.responseInitiateAbortBulkX.USBTMC_status = eUSBTMC_STATUS_SUCCESS;
  313. }
  314. else
  315. {
  316. // error: transfer isn't in progress
  317. sUsbTmcContext.bInitiateBulkOutAbort = false; // INITIATE response not prepared
  318. sUsbTmcContext.tmpSetup.responseInitiateAbortBulkX.USBTMC_status = eUSBTMC_STATUS_TRANSFER_NOT_IN_PROGRESS;
  319. }
  320. return true; // pass this request -> fUSBTMCProto_ControlTx
  321. }
  322. break;
  323. // Returns the status of the previously sent INITIATE_ABORT_BULK_OUT request.
  324. case eUSBTMC_CHECK_ABORT_BULK_OUT_STATUS:
  325. {
  326. if( pSetup->wIndex != USBTMC_BULKOUT_EP )
  327. return false; // Error, 4.2.1.3 CHECK_ABORT_BULK_OUT_STATUS, [1]
  328. // zero init the response bytes
  329. memset( sUsbTmcContext.tmpSetup.rawBytesResponse, 0, sizeof(sUsbTmcContext.tmpSetup.responseCheckAbortBulkOut) );
  330. if( sUsbTmcContext.bInitiateBulkOutAbort )
  331. {
  332. uint32_t NBYTES_RXD = 0;
  333. // retireve number of received bytes during last transfer
  334. tmclib_bulkout_getcounter( &NBYTES_RXD );
  335. sUsbTmcContext.tmpSetup.responseCheckAbortBulkOut.NBYTES_RXD = NBYTES_RXD;
  336. sUsbTmcContext.tmpSetup.responseCheckAbortBulkOut.USBTMC_status = eUSBTMC_STATUS_SUCCESS; // successfully aborted
  337. // clear the request indicator
  338. sUsbTmcContext.bInitiateBulkOutAbort = false;
  339. }
  340. else
  341. {
  342. sUsbTmcContext.tmpSetup.responseCheckAbortBulkOut.USBTMC_status = eUSBTMC_STATUS_SPLIT_NOT_IN_PROGRESS; // not INITIATE request received
  343. }
  344. return true; // pass this request -> fUSBTMCProto_ControlTx
  345. }
  346. break;
  347. // Aborts a Bulk-IN transfer.
  348. case eUSBTMC_INITIATE_ABORT_BULK_IN:
  349. {
  350. if( pSetup->wIndex != USBTMC_BULKIN_EP )
  351. return false; // Error, 4.2.1.4 INITIATE_ABORT_BULK_IN, [1]
  352. // zero init the response bytes
  353. memset( sUsbTmcContext.tmpSetup.rawBytesResponse, 0, sizeof(sUsbTmcContext.tmpSetup.responseInitiateAbortBulkX) );
  354. // preserve the bTag to put the value into the response (fUSBTMCProto_ControlTx)
  355. tmclib_bulkin_gettag_latest( &sUsbTmcContext.tmpSetup.responseInitiateAbortBulkX.bTag );
  356. // try to abort BulkIn transfer with the specified bTag
  357. if( tmclib_status_success == tmclib_generic_event( COMPOUND_tmclib_event_context_abort_bulkin((uint8_t)pSetup->wValue, false) ) )
  358. {
  359. // Restore endpoint, BulkIN EP must not be halted, due to:
  360. // - 4.2.1.4, table 26;
  361. // - 3.3.2.4 "Halt", table 12
  362. USBD_USBTMC_NakEP( USBTMC_BULKIN_EP );
  363. // [1], 4.2.1.4 INITIATE_ABORT_BULK_IN, Table 26
  364. // "If a short packet has not been queued, queue a shortpacket to terminate the transfer."
  365. // "If a short packet can not yet be queued, wait until a short packet can be queued."
  366. USBTMC_datain_zerosend( USBTMC_BULKIN_EP ); // queue a short packet to terminate transfer
  367. #if DEBUG_USBTMC_REQUESTS > 0
  368. debug_log( DEBUG_LOG_STATE_INITABIN, 0 );
  369. #endif
  370. sUsbTmcContext.bInitiateBulkInAbort = true; // INITIATE response prepared
  371. sUsbTmcContext.tmpSetup.responseInitiateAbortBulkX.USBTMC_status = eUSBTMC_STATUS_SUCCESS;
  372. }
  373. else
  374. {
  375. // error: transfer isn't in progress
  376. sUsbTmcContext.bInitiateBulkInAbort = false; // INITIATE response not prepared
  377. sUsbTmcContext.tmpSetup.responseInitiateAbortBulkX.USBTMC_status = eUSBTMC_STATUS_TRANSFER_NOT_IN_PROGRESS;
  378. }
  379. return true; // pass this request -> fUSBTMCProto_ControlTx
  380. }
  381. break;
  382. // Returns the status of the previously sent INITIATE_ABORT_BULK_IN request.
  383. case eUSBTMC_CHECK_ABORT_BULK_IN_STATUS:
  384. {
  385. if( pSetup->wIndex != USBTMC_BULKIN_EP )
  386. return false; // Error, 4.2.1.5 CHECK_ABORT_BULK_IN_STATUS, [1]
  387. // zero init the response bytes
  388. memset( sUsbTmcContext.tmpSetup.rawBytesResponse, 0, sizeof(sUsbTmcContext.tmpSetup.responseCheckAbortBulkIn) );
  389. if( sUsbTmcContext.bInitiateBulkInAbort )
  390. {
  391. uint32_t NBYTES_TXD = 0;
  392. // retireve number of transferred bytes during last transfer
  393. tmclib_bulkin_getcounter( &NBYTES_TXD );
  394. if( ! USBD_USBTMC_GetTxQueuedSize( USBTMC_BULKIN_EP, NULL ) )
  395. {
  396. // [1]. 4.2.1.5 CHECK_ABORT_BULK_IN_STATUS, Table 29 -- CHECK_ABORT_BULK_IN_STATUS USBTMC_status values
  397. // The device must set NBYTES_TXD to the appropriate value.
  398. sUsbTmcContext.tmpSetup.responseCheckAbortBulkIn.NBYTES_TXD = NBYTES_TXD;
  399. // BulkIN transfer already reset, FIFO is empty, so bmAbortBulkIn.D0 is zero.
  400. sUsbTmcContext.tmpSetup.responseCheckAbortBulkIn.bmAbortBulkIn = 0;
  401. sUsbTmcContext.tmpSetup.responseCheckAbortBulkIn.USBTMC_status = eUSBTMC_STATUS_SUCCESS; // successfully aborted
  402. #if DEBUG_USBTMC_REQUESTS > 0
  403. debug_log( DEBUG_LOG_STATE_CHKSTATUS_OK, 0 );
  404. #endif
  405. // clear the request status
  406. sUsbTmcContext.bInitiateBulkInAbort = false;
  407. }
  408. else
  409. {
  410. // [1]. 4.2.1.5 CHECK_ABORT_BULK_IN_STATUS, Table 29 -- CHECK_ABORT_BULK_IN_STATUS USBTMC_status values
  411. // The device must set NBYTES_TXD = 0x00000000.
  412. sUsbTmcContext.tmpSetup.responseCheckAbortBulkIn.NBYTES_TXD = 0;
  413. // BulkIN transfer already reset, but FIFO is not empty and short packet must be send, so bmAbortBulkIn.D0 is set.
  414. sUsbTmcContext.tmpSetup.responseCheckAbortBulkIn.bmAbortBulkIn = 1;
  415. sUsbTmcContext.tmpSetup.responseCheckAbortBulkIn.USBTMC_status = eUSBTMC_STATUS_PENDING; // successfully aborted
  416. #if DEBUG_USBTMC_REQUESTS > 0
  417. debug_log( DEBUG_LOG_STATE_CHKSTATUS_PEND, 0 );
  418. #endif
  419. // keep the request status true
  420. sUsbTmcContext.bInitiateBulkInAbort = true;
  421. }
  422. }
  423. else
  424. {
  425. sUsbTmcContext.tmpSetup.responseCheckAbortBulkIn.USBTMC_status = eUSBTMC_STATUS_SPLIT_NOT_IN_PROGRESS; // not INITIATE request received
  426. }
  427. return true; // pass this request -> fUSBTMCProto_ControlTx
  428. }
  429. break;
  430. // Clears all previously sent pending and
  431. // unprocessed Bulk-OUT USBTMC message
  432. // content and clears all pending Bulk-IN transfers
  433. // from the USBTMC interface.
  434. case eUSBTMC_INITIATE_CLEAR:
  435. {
  436. //#error sUsbTmcContext.xDescHandler
  437. if( pSetup->wIndex != USB_TMC_INTERFACE_VALUE )
  438. return false; // Error, see 4.2.1.6 INITIATE_CLEAR, [1]
  439. // zero init the response bytes
  440. memset( sUsbTmcContext.tmpSetup.rawBytesResponse, 0, sizeof(sUsbTmcContext.tmpSetup.responseInitiateClear) );
  441. // 4.2.1.6 INITIATE_CLEAR, [2]
  442. // Halt Bulk-OUT EP and clear FIFO
  443. USBD_USBTMC_StallEP( USBTMC_BULKOUT_EP );
  444. // Abort bulk-out transfer and clear the state
  445. tmclib_generic_event( COMPOUND_tmclib_event_context_abort_bulkout(0, true) );
  446. // 4.2.1.6 INITIATE_CLEAR, [2]
  447. // Remove all queued packets and clear FIFO for BulkIn
  448. // Set NAK status to interrupt the transfer and clear buffer
  449. USBD_USBTMC_NakEP( USBTMC_BULKIN_EP );
  450. // Abort bulk-in transfer and clear the state
  451. tmclib_generic_event( COMPOUND_tmclib_event_context_abort_bulkin(0, true) );
  452. // --------------- Non-standard -----------------------------------------------------
  453. // There no recomendations for Interrupt-IN EP during INITIATE_CLEAR request
  454. // But it is good to restore the initial state to clear Interrupt-IN EP here.
  455. // Set NAK state for Interrupt-IN EP
  456. USBD_USBTMC_NakEP( USBTMC_INTERRUPTIN_EP );
  457. // abort interrupt-in transfer
  458. tmclib_generic_event( COMPOUND_tmclib_event_context_abort_interruptin(0, true) );
  459. // ----------------------------------------------------------------------------------
  460. // Clean up USBTMC and SCPI module
  461. tmclib_generic_event( COMPOUND_tmclib_event_context_device_clear(false) );
  462. sUsbTmcContext.tmpSetup.responseInitiateClear.USBTMC_status = eUSBTMC_STATUS_SUCCESS; // successfully cleared
  463. sUsbTmcContext.bInitiateClear = true;
  464. #if DEBUG_USB > 0 // SCPI debug only
  465. extern void spy_tx_log_cleanup();
  466. spy_tx_log_cleanup();
  467. #endif
  468. return true; // pass this request -> fUSBTMCProto_ControlTx
  469. }
  470. break;
  471. // Returns the status of the previously sent INITIATE_CLEAR request.
  472. case eUSBTMC_CHECK_CLEAR_STATUS:
  473. {
  474. if( pSetup->wIndex != USB_TMC_INTERFACE_VALUE )
  475. return false; // Error, see 4.2.1.7 CHECK_CLEAR_STATUS, [1]
  476. // zero init the response bytes
  477. memset( sUsbTmcContext.tmpSetup.rawBytesResponse, 0, sizeof(sUsbTmcContext.tmpSetup.responseCheckClear) );
  478. // [1], 4.2.1.7 CHECK_CLEAR_STATUS
  479. if( sUsbTmcContext.bInitiateClear )
  480. {
  481. sUsbTmcContext.tmpSetup.responseCheckClear.bmClear = 0; // all FIFOs are cleared, bmClear.D0 is zero
  482. sUsbTmcContext.tmpSetup.responseCheckClear.USBTMC_status = eUSBTMC_STATUS_SUCCESS; // successfully aborted
  483. // clear the request indicator
  484. sUsbTmcContext.bInitiateClear = false;
  485. }
  486. else
  487. {
  488. sUsbTmcContext.tmpSetup.responseCheckClear.USBTMC_status = eUSBTMC_STATUS_SPLIT_NOT_IN_PROGRESS; // not INITIATE request received
  489. }
  490. return true; // pass this request -> fUSBTMCProto_ControlTx
  491. }
  492. break;
  493. // Returns attributes and capabilities of the USBTMC interface.
  494. case eUSBTMC_GET_CAPABILITIES:
  495. {
  496. if( pSetup->wIndex != USB_TMC_INTERFACE_VALUE )
  497. return false; // Error, see 4.2.1.8 GET_CAPABILITIES, [1]
  498. // zero init the response bytes
  499. memset( sUsbTmcContext.tmpSetup.rawBytesResponse, 0, sizeof(sUsbTmcContext.tmpSetup.responseGetCapabilities) );
  500. sUsbTmcContext.tmpSetup.responseGetCapabilities.USBTMC_status = eUSBTMC_STATUS_SUCCESS; // successfull
  501. sUsbTmcContext.tmpSetup.responseGetCapabilities.bcdUSBTMC = USBTMC_VERSION;
  502. sUsbTmcContext.tmpSetup.responseGetCapabilities.ifaceCaps = USBTMC_IFACE_CAPABILITIES;
  503. sUsbTmcContext.tmpSetup.responseGetCapabilities.devCaps = USBTMC_DEVICE_CAPABILITIES;
  504. sUsbTmcContext.tmpSetup.responseGetCapabilities.usb488.bcdUSB488 = USB488_VERSION;
  505. sUsbTmcContext.tmpSetup.responseGetCapabilities.usb488.ifaceCaps = USB488_IFACE_CAPABILITIES;
  506. sUsbTmcContext.tmpSetup.responseGetCapabilities.usb488.devCaps = USB488_DEVICE_CAPABILITIES;
  507. return true; // pass this request -> fUSBTMCProto_ControlTx
  508. }
  509. break;
  510. // A mechanism to turn on an activity indicator for
  511. // identification purposes. The device indicates
  512. // whether or not it supports this request in the
  513. // GET_CAPABILITIES response packet.
  514. case eUSBTMC_INDICATOR_PULSE:
  515. {
  516. #if INDICATOR_PULSE_REQUEST_SUPPORT
  517. if( pSetup->wIndex != USB_TMC_INTERFACE_VALUE )
  518. return false; // Error, see 4.2.1.9 INDICATOR_PULSE, [1]
  519. // zero init the response bytes
  520. memset( sUsbTmcContext.tmpSetup.rawBytesResponse, 0, sizeof(sUsbTmcContext.tmpSetup.responseIndicatorPulse) );
  521. sUsbTmcContext.tmpSetup.responseIndicatorPulse.USBTMC_status = eUSBTMC_STATUS_SUCCESS; // successfull
  522. // Perform LED Signaling
  523. LEDHandle.SetMode( eLedMode_Signaling );
  524. return true; // pass this request -> fUSBTMCProto_ControlTx
  525. #else
  526. return false; // Error, see 4.2.1.9 INDICATOR_PULSE, [1]
  527. #endif
  528. }
  529. break;
  530. #warning SCPI Add "default:" and route to USB488 dependent request processor (4.3 USB488 subclass specific requests)
  531. // Allows to read the status byte using class request
  532. case eUSBTMC_USB488_READ_STATUS_BYTE:
  533. {
  534. if( pSetup->wIndex != USB_TMC_INTERFACE_VALUE )
  535. return false; // Error, see 4.3.1 READ_STATUS_BYTE, [2]
  536. if( pSetup->wValue & 0x80 ||
  537. (pSetup->wValue & 0x7F) < 2 )
  538. return false; // Error, see 4.3.1 READ_STATUS_BYTE, [2]
  539. // zero init the response bytes
  540. memset( sUsbTmcContext.tmpSetup.rawBytesResponse, 0, sizeof(sUsbTmcContext.tmpSetup.responseUsb488ReadStatusByte) );
  541. sUsbTmcContext.tmpSetup.responseUsb488ReadStatusByte.USBTMC_status = eUSBTMC_STATUS_SUCCESS; // successfull
  542. sUsbTmcContext.tmpSetup.responseUsb488ReadStatusByte.bTag = pSetup->wValue & 0x7F;
  543. // 4.3.1.2 Response format for USB488 interfaces with an Interrupt-IN endpoint, [2]
  544. sUsbTmcContext.tmpSetup.responseUsb488ReadStatusByte.bStatusByte = 0; // forward set to constant
  545. // Set NAK state for Interrupt-IN EP
  546. USBD_USBTMC_NakEP( USBTMC_BULKIN_EP );
  547. // Initiate Interrupt-In transfer
  548. tmclib_generic_event( COMPOUND_tmclib_event_context_interruptin_start( eventCtx, NULL, sUsbTmcContext.tmpSetup.responseUsb488ReadStatusByte.bTag ) );
  549. return true; // pass this request -> fUSBTMCProto_ControlTx
  550. }
  551. break;
  552. }
  553. }
  554. break;
  555. }
  556. return false;
  557. }
  558. // ===================================================================================
  559. // fUSBTMCProto_ControlRx()
  560. // The setup packet has been processed and filtered already in @fUSBTMCProto_Setup()
  561. // This function receives the SETUP packet DATA payload
  562. static size_t fUSBTMCProto_ControlRx( const tUSBSetupPacket_t * pSetup, sUSBTransfer_t * rx, size_t idx, size_t bytesRemaining )
  563. {
  564. // No incoming packets expected via CONTROL-transfer
  565. return 0;
  566. }
  567. // ===================================================================================
  568. // fUSBTMCProto_ControlTx()
  569. // The setup packet has been processed and filtered already in @fUSBTMCProto_Setup()
  570. // This function queues the response only.
  571. static size_t fUSBTMCProto_ControlTx( const tUSBSetupPacket_t * pSetup, sUSBTransfer_t * tx, size_t idx, size_t bytesRemaining )
  572. {
  573. // All the followed requests require the response.
  574. // To simplify the implementation this function requires
  575. // the control endpoint MAX_PACKET_SIZE to be not less than
  576. // the higest incoming packet.
  577. // This function does not support multi-packet mode, the buffer size
  578. // must have enough space to place the biggest possible response.
  579. // see @fUSBTMCProto_Init for details.
  580. size_t bytes = 0;
  581. if( 0 != idx )
  582. return 0; // multi-packet transaction: wtf? see the comment above
  583. // Check the request type
  584. switch( pSetup->bmRequest & USB_REQ_TYPE_MASK )
  585. {
  586. // see 4.2.1 "USBTMC requests", [1]
  587. case USB_REQ_TYPE_CLASS:
  588. {
  589. // Check request ID:
  590. switch( pSetup->bRequest )
  591. {
  592. case eUSBTMC_INITIATE_ABORT_BULK_OUT: // Aborts a Bulk-OUT transfer.
  593. case eUSBTMC_INITIATE_ABORT_BULK_IN: // Aborts a Bulk-IN transfer.
  594. {
  595. if( sizeof(sUsbTmcContext.tmpSetup.responseInitiateAbortBulkX) == bytesRemaining ) // 4.2.1.2, Table 19, [1]
  596. {
  597. bytes += usb_write_transfer( tx, sUsbTmcContext.tmpSetup.rawBytesResponse, sizeof(sUsbTmcContext.tmpSetup.responseInitiateAbortBulkX) );
  598. }
  599. }
  600. break;
  601. // Returns the status of the previously sent INITIATE_ABORT_BULK_OUT request.
  602. case eUSBTMC_CHECK_ABORT_BULK_OUT_STATUS:
  603. {
  604. if( sizeof(sUsbTmcContext.tmpSetup.responseCheckAbortBulkOut) == bytesRemaining ) // 4.2.1.3, Table 22, [1]
  605. {
  606. bytes += usb_write_transfer( tx, &sUsbTmcContext.tmpSetup.rawBytesResponse, sizeof(sUsbTmcContext.tmpSetup.responseCheckAbortBulkOut) );
  607. }
  608. }
  609. break;
  610. // Returns the status of the previously sent INITIATE_ABORT_BULK_IN request.
  611. case eUSBTMC_CHECK_ABORT_BULK_IN_STATUS:
  612. {
  613. if( sizeof(sUsbTmcContext.tmpSetup.responseCheckAbortBulkIn) == bytesRemaining ) // 4.2.1.5, Table 28, [1]
  614. {
  615. bytes += usb_write_transfer( tx, &sUsbTmcContext.tmpSetup.rawBytesResponse, sizeof(sUsbTmcContext.tmpSetup.responseCheckAbortBulkIn) );
  616. }
  617. }
  618. break;
  619. // Clears all previously sent pending and
  620. // unprocessed Bulk-OUT USBTMC message
  621. // content and clears all pending Bulk-IN transfers
  622. // from the USBTMC interface.
  623. case eUSBTMC_INITIATE_CLEAR:
  624. {
  625. if( sizeof(sUsbTmcContext.tmpSetup.responseInitiateClear) == bytesRemaining ) // 4.2.1.6, Table 30, [1]
  626. {
  627. bytes += usb_write_transfer( tx, sUsbTmcContext.tmpSetup.rawBytesResponse, sizeof(sUsbTmcContext.tmpSetup.responseInitiateClear) );
  628. }
  629. }
  630. break;
  631. // Returns the status of the previously sent INITIATE_CLEAR request.
  632. case eUSBTMC_CHECK_CLEAR_STATUS:
  633. {
  634. if( sizeof(sUsbTmcContext.tmpSetup.responseCheckClear) == bytesRemaining ) // 4.2.1.7, Table 34, [1]
  635. {
  636. bytes += usb_write_transfer( tx, sUsbTmcContext.tmpSetup.rawBytesResponse, sizeof(sUsbTmcContext.tmpSetup.responseCheckClear) );
  637. }
  638. }
  639. break;
  640. // Returns attributes and capabilities of the USBTMC interface.
  641. case eUSBTMC_GET_CAPABILITIES:
  642. {
  643. if( sizeof(sUsbTmcContext.tmpSetup.responseGetCapabilities) == bytesRemaining ) // 4.2.1.8 GET_CAPABILITIES, table 37, [1]
  644. {
  645. bytes += usb_write_transfer( tx, sUsbTmcContext.tmpSetup.rawBytesResponse, sizeof(sUsbTmcContext.tmpSetup.responseGetCapabilities) );
  646. }
  647. }
  648. break;
  649. // A mechanism to turn on an activity indicator for
  650. // identification purposes. The device indicates
  651. // whether or not it supports this request in the
  652. // GET_CAPABILITIES response packet.
  653. case eUSBTMC_INDICATOR_PULSE:
  654. {
  655. if( sizeof(sUsbTmcContext.tmpSetup.responseIndicatorPulse) == bytesRemaining ) // 4.2.1.9 INDICATOR_PULSE, table 39, [1]
  656. {
  657. bytes += usb_write_transfer( tx, sUsbTmcContext.tmpSetup.rawBytesResponse, sizeof(sUsbTmcContext.tmpSetup.responseIndicatorPulse) );
  658. }
  659. }
  660. break;
  661. // Allows to read the status byte using class request
  662. case eUSBTMC_USB488_READ_STATUS_BYTE:
  663. {
  664. if( sizeof(sUsbTmcContext.tmpSetup.responseUsb488ReadStatusByte) == bytesRemaining ) // 4.3.1 READ_STATUS_BYTE, [2]
  665. {
  666. bytes += usb_write_transfer( tx, sUsbTmcContext.tmpSetup.rawBytesResponse, sizeof(sUsbTmcContext.tmpSetup.responseUsb488ReadStatusByte) );
  667. // need to force-call Interrupt-IN handler (fUSBTMCProto_IntTxHandler();)
  668. USBTMC_datain_beginsend( USBTMC_INTERRUPTIN_EP );
  669. }
  670. }
  671. break;
  672. }
  673. }
  674. break;
  675. }
  676. return bytes;
  677. }
  678. // ===================================================================================
  679. // @fUSBTMCProto_DataRxHandler
  680. // USBTMC Data Incoming handler (Bulk-Out)
  681. static bool fUSBTMCProto_DataRxHandler( uint8_t bEpLogAddress, sUSBTransfer_t * rx )
  682. {
  683. eTMCLibStatus_t status;
  684. bulk_out_label:
  685. status = tmclib_generic_event( COMPOUND_tmclib_event_context_bulkout( eventCtx, rx ) );
  686. if( USBTMC_NOTERROR(status) )
  687. {
  688. if( USBTMC_WARNING(status) )
  689. {
  690. switch( status )
  691. {
  692. case tmclib_status_invalid_param:
  693. {
  694. my_assert( status != tmclib_status_invalid_param ); // 'tmclib_bulkout_event' SHALL never return 'tmclib_status_invalid_param'
  695. }
  696. break;
  697. case tmclib_status_in_progress:
  698. {
  699. my_assert( status != tmclib_status_in_progress ); // 'tmclib_bulkout_event' never returns 'tmclib_status_in_progress'
  700. }
  701. break;
  702. case tmclib_status_again:
  703. {
  704. // there is some data in @rx transfer required to be processed
  705. }
  706. goto bulk_out_label;;
  707. case tmclib_status_need_data:
  708. {
  709. my_assert( status != tmclib_status_need_data ); // 'tmclib_bulkout_event' never returns 'tmclib_status_need_data'
  710. }
  711. break;
  712. case tmclib_status_not_in_progress:
  713. {
  714. my_assert( status != tmclib_status_not_in_progress ); // 'tmclib_bulkout_event' never returns 'tmclib_status_not_in_progress'
  715. }
  716. break;
  717. case tmclib_status_no_more_data:
  718. {
  719. my_assert( status != tmclib_status_no_more_data ); // 'tmclib_bulkout_event' never returns 'tmclib_status_no_more_data'
  720. }
  721. break;
  722. case tmclib_status_need_read:
  723. {
  724. // normal operation
  725. uint8_t rc = USBTMC_datain_sendprepared( USBTMC_BULKIN_EP );
  726. (void)rc;
  727. }
  728. break;
  729. default:
  730. my_assert( status == tmclib_status_success ); // 'tmclib_bulkout_event' returns undefined code
  731. }
  732. }
  733. }
  734. else
  735. {
  736. if( status == tmclib_status_halt_bulkin )
  737. {
  738. // 3.3.2.4 Halt, [1]
  739. USBD_USBTMC_StallEP( USBTMC_BULKIN_EP );
  740. }
  741. // 3.2.2.3 Bulk-OUT transfer protocol errors, [1]
  742. // 3.2.2.4 Halt, [1]
  743. USBD_USBTMC_StallEP( USBTMC_BULKOUT_EP );
  744. }
  745. return USBTMC_NOTERROR(status);
  746. }
  747. // ===================================================================================
  748. // @fUSBTMCProto_DataTxHandler
  749. // USBTMC Data Outcoming handler (Bulk-IN)
  750. // Note: User shall reset Short-Packet indicator using @usb_transfer_modify_flags
  751. // ... routine to avoid sending short packet in case no data queued into the transfer
  752. // ... after successful call (return true with empty transfer)
  753. static bool fUSBTMCProto_DataTxHandler( uint8_t bEpLogAddress, sUSBTransfer_t * tx )
  754. {
  755. eTMCLibStatus_t status = tmclib_generic_event( COMPOUND_tmclib_event_context_bulkin( eventCtx, tx ) );
  756. if( USBTMC_NOTERROR(status) )
  757. {
  758. if( USBTMC_WARNING(status) )
  759. {
  760. switch( status )
  761. {
  762. case tmclib_status_invalid_param:
  763. {
  764. my_assert( status != tmclib_status_invalid_param ); // 'tmclib_bulkin_event' SHALL never return 'tmclib_status_invalid_param'
  765. }
  766. break;
  767. case tmclib_status_in_progress:
  768. {
  769. my_assert( status != tmclib_status_in_progress ); // 'tmclib_bulkin_event' never returns 'tmclib_status_in_progress'
  770. }
  771. break;
  772. case tmclib_status_again:
  773. {
  774. my_assert( status != tmclib_status_again ); // 'tmclib_bulkin_event' never returns 'tmclib_status_again'
  775. }
  776. break;
  777. case tmclib_status_need_data:
  778. {
  779. my_assert( status != tmclib_status_need_data ); // 'tmclib_bulkin_event' never returns 'tmclib_status_need_data'
  780. }
  781. break;
  782. case tmclib_status_not_in_progress:
  783. case tmclib_status_no_more_data: // need set NAK condition over EP
  784. {
  785. // cleanup EP IN to provide NAK response in next IN transaction
  786. USBD_USBTMC_NakEP( USBTMC_BULKIN_EP );
  787. }
  788. break;
  789. case tmclib_status_need_read:
  790. {
  791. // normal operation
  792. }
  793. break;
  794. default:
  795. my_assert( status == tmclib_status_success ); // 'tmclib_bulkin_event' returns undefined code
  796. }
  797. }
  798. return true;
  799. }
  800. return false;
  801. }
  802. // ===================================================================================
  803. // @fUSBTMCProto_DataErrHandler
  804. // USBTMC Error handler for Data channel
  805. static bool fUSBTMCProto_DataErrHandler( uint8_t bEpLogAddress, uint32_t error )
  806. {
  807. #warning BulkOut -> Stall
  808. return true; // bibb
  809. }
  810. // ===================================================================================
  811. // @fUSBTMCProto_IntTxHandler
  812. // USBTMC Interrupt Outcoming handler (Interrupt-IN)
  813. static bool fUSBTMCProto_IntTxHandler( uint8_t bEpLogAddress, sUSBTransfer_t * ntx )
  814. {
  815. eTMCLibStatus_t status = tmclib_generic_event( COMPOUND_tmclib_event_context_interruptin( eventCtx, ntx ) );
  816. if( USBTMC_NOTERROR(status) )
  817. {
  818. switch( status )
  819. {
  820. case tmclib_status_invalid_param:
  821. {
  822. my_assert( status != tmclib_status_invalid_param ); // 'tmclib_interruptin_event' SHALL never return 'tmclib_status_invalid_param'
  823. }
  824. break;
  825. case tmclib_status_in_progress:
  826. {
  827. my_assert( status != tmclib_status_in_progress ); // 'tmclib_interruptin_event' never returns 'tmclib_status_in_progress'
  828. }
  829. break;
  830. case tmclib_status_again:
  831. {
  832. my_assert( status != tmclib_status_again ); // 'tmclib_interruptin_event' never returns 'tmclib_status_again'
  833. }
  834. break;
  835. case tmclib_status_need_data:
  836. {
  837. my_assert( status != tmclib_status_need_data ); // 'tmclib_interruptin_event' never returns 'tmclib_status_need_data'
  838. }
  839. break;
  840. case tmclib_status_not_in_progress:
  841. case tmclib_status_no_more_data: // need set NAK condition over EP
  842. {
  843. // cleanup EP IN to provide NAK response in next IN transaction
  844. USBD_USBTMC_NakEP( USBTMC_INTERRUPTIN_EP );
  845. }
  846. break;
  847. case tmclib_status_success:
  848. case tmclib_status_need_read:
  849. {
  850. // normal operation
  851. }
  852. break;
  853. default:
  854. my_assert( status == tmclib_status_success ); // 'tmclib_interruptin_event' returns undefined code
  855. }
  856. return true;
  857. }
  858. return false;
  859. }
  860. // ===================================================================================
  861. // @fUSBTMCProto_IntErrHandler
  862. // USBTMC Error handler for Interrupt channel
  863. static bool fUSBTMCProto_IntErrHandler( uint8_t bEpLogAddress, uint32_t error )
  864. {
  865. return true; // bibb
  866. }
  867. // ===================================================================================
  868. // USBTMC_datain_beginsend()
  869. // Begin the transmission using DataIN handler virtual call.
  870. // Due to the hardware does not support NAK-sent-interrupt, it is
  871. // required to initiate the first packet sending to start TX-flow (DataIN).
  872. // This function issues the first packet sending using virtual DataIN event.
  873. //
  874. uint8_t USBTMC_datain_beginsend( uint8_t epnum )
  875. {
  876. // issue virtual DataIN event:
  877. return USBD_USBTMC_DataIn_BeginSend( epnum, false );
  878. }
  879. // ===================================================================================
  880. // USBTMC_datain_sendprepared()
  881. // Begin the transmission using already prepared TX-transfer.
  882. // Due to the hardware does not support NAK-sent-interrupt, it is
  883. // required to initiate the first packet sending to start TX-flow (DataIN).
  884. // This function issues the first packet sending using virtual DataIN event.
  885. //
  886. uint8_t USBTMC_datain_sendprepared( uint8_t epnum )
  887. {
  888. // issue virtual DataIN event:
  889. return USBD_USBTMC_DataIn_BeginSend( epnum, true );
  890. }
  891. // ===================================================================================
  892. // USBTMC_datain_zerosend()
  893. // Queue zero packet in BulkIN EP without calling TX-handler
  894. //
  895. uint8_t USBTMC_datain_zerosend( uint8_t epnum )
  896. {
  897. return USBD_USBTMC_DataIn_ZeroSend( epnum );
  898. }