diff --git a/examples/device/usbtmc/src/usbtmc_app.c b/examples/device/usbtmc/src/usbtmc_app.c index 495746e07..2982675b1 100644 --- a/examples/device/usbtmc/src/usbtmc_app.c +++ b/examples/device/usbtmc/src/usbtmc_app.c @@ -96,6 +96,13 @@ static usbtmc_msg_dev_dep_msg_in_header_t rspMsg = { } }; +void tud_usbtmc_app_open_cb(uint8_t rhport, uint8_t interface_id) +{ + (void)interface_id; + usbtmcd_start_bus_read(rhport); +} + + bool tud_usbtmc_app_msg_trigger_cb(uint8_t rhport, usbtmc_msg_generic_t* msg) { (void)rhport; (void)msg; @@ -149,6 +156,7 @@ bool tud_usbtmc_app_msg_data_cb(uint8_t rhport, void *data, size_t len, bool tra d=0; resp_delay = (uint32_t)d; } + usbtmcd_start_bus_read(rhport); return true; } @@ -162,6 +170,7 @@ bool tud_usbtmc_app_msgBulkIn_complete_cb(uint8_t rhport) bulkInStarted = 0; buffer_tx_ix = 0; } + usbtmcd_start_bus_read(rhport); return true; } @@ -259,6 +268,8 @@ bool tud_usbtmc_app_check_clear_cb(uint8_t rhport, usbtmc_get_clear_status_rsp_t queryState = 0; bulkInStarted = false; status = 0; + buffer_tx_ix = 0u; + buffer_len = 0u; rsp->USBTMC_status = USBTMC_STATUS_SUCCESS; rsp->bmClear.BulkInFifoBytes = 0u; return true; @@ -274,6 +285,7 @@ bool tud_usbtmc_app_check_abort_bulk_in_cb(uint8_t rhport, usbtmc_check_abort_bu { (void)rhport; (void)rsp; + usbtmcd_start_bus_read(rhport); return true; } @@ -288,6 +300,7 @@ bool tud_usbtmc_app_check_abort_bulk_out_cb(uint8_t rhport, usbtmc_check_abort_b { (void)rhport; (void)rsp; + usbtmcd_start_bus_read(rhport); return true; } @@ -298,6 +311,7 @@ void usmtmcd_app_bulkIn_clearFeature_cb(uint8_t rhport) void usmtmcd_app_bulkOut_clearFeature_cb(uint8_t rhport) { (void)rhport; + usbtmcd_start_bus_read(rhport); } // Return status byte, but put the transfer result status code in the rspResult argument. @@ -313,7 +327,7 @@ uint8_t tud_usbtmc_app_get_stb_cb(uint8_t rhport, uint8_t *tmcResult) return old_status; } -bool tud_usbtmc_app_indicator_pluse_cb(uint8_t rhport, tusb_control_request_t const * msg, uint8_t *tmcResult) +bool tud_usbtmc_app_indicator_pulse_cb(uint8_t rhport, tusb_control_request_t const * msg, uint8_t *tmcResult) { (void)rhport; (void)msg; diff --git a/src/class/usbtmc/usbtmc_device.c b/src/class/usbtmc/usbtmc_device.c index e3d2c316e..401b4acc4 100644 --- a/src/class/usbtmc/usbtmc_device.c +++ b/src/class/usbtmc/usbtmc_device.c @@ -99,9 +99,10 @@ static char logMsg[150]; typedef enum { - STATE_CLOSED, - STATE_IDLE, - STATE_RCV, + STATE_CLOSED, // Endpoints have not yet been opened since USB reset + STATE_NAK, // Bulk-out endpoint is in NAK state. + STATE_IDLE, // Bulk-out endpoint is waiting for CMD. + STATE_RCV, // Bulk-out is receiving DEV_DEP message STATE_TX_REQUESTED, STATE_TX_INITIATED, STATE_TX_SHORTED, @@ -243,7 +244,7 @@ void usbtmcd_init_cb(void) TU_ASSERT(!tud_usbtmc_app_capabilities.bmIntfcCapabilities.talkOnly,); # endif if(tud_usbtmc_app_capabilities.bmIntfcCapabilities.supportsIndicatorPulse) - TU_ASSERT(&tud_usbtmc_app_indicator_pluse_cb != NULL,); + TU_ASSERT(&tud_usbtmc_app_indicator_pulse_cb != NULL,); #endif usbtmcLock = osal_mutex_create(&usbtmcLockBuffer); @@ -322,11 +323,37 @@ bool usbtmcd_open_cb(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin } #endif #endif - usbtmc_state.state = STATE_IDLE; - TU_VERIFY( usbd_edpt_xfer(rhport, usbtmc_state.ep_bulk_out, usbtmc_state.ep_bulk_out_buf, 64)); + atomicChangeState(STATE_CLOSED, STATE_NAK); + tud_usbtmc_app_open_cb(rhport, itf_desc->iInterface); return true; } +// Tell USBTMC class to set its bulk-in EP to ACK so that it can +// receive USBTMC commands. +// Returns false if it was already in an ACK state or is busy +// processing a command (such as a clear). Returns true if it was +// in the NAK state and successfully transitioned to the ACK wait +// state. +bool usbtmcd_start_bus_read(uint8_t rhport) +{ + usbtmcd_state_enum oldState = usbtmc_state.state; + switch(oldState) + { + // These may transition to IDLE + case STATE_NAK: + case STATE_ABORTING_BULK_IN_ABORTED: + TU_VERIFY(atomicChangeState(oldState, STATE_IDLE)); + break; + // When receiving, let it remain receiving + case STATE_RCV: + break; + default: + TU_VERIFY(false); + } + TU_VERIFY(usbd_edpt_xfer(rhport, usbtmc_state.ep_bulk_out, usbtmc_state.ep_bulk_out_buf, 64)); + return true; +} + void usbtmcd_reset_cb(uint8_t rhport) { (void)rhport; @@ -367,19 +394,21 @@ static bool handle_devMsgOut(uint8_t rhport, void *data, size_t len, size_t pack if(len >= usbtmc_state.transfer_size_remaining || shortPacket) { atEnd = true; + TU_VERIFY(atomicChangeState(STATE_RCV, STATE_NAK)); } len = tu_min32(len, usbtmc_state.transfer_size_remaining); + usbtmc_state.transfer_size_remaining -= len; + usbtmc_state.transfer_size_sent += len; + + // App may (should?) call the wait_for_bus() command at this point if(!tud_usbtmc_app_msg_data_cb(rhport,data, len, atEnd)) { // TODO: Go to an error state upon failure other than just stalling the EP? return false; } - usbtmc_state.transfer_size_remaining -= len; - usbtmc_state.transfer_size_sent += len; - TU_VERIFY(atomicChangeState(STATE_RCV, atEnd ? STATE_IDLE : STATE_RCV)); return true; } @@ -453,7 +482,6 @@ bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint TU_VERIFY(false); return false; } - TU_VERIFY(usbd_edpt_xfer(rhport, usbtmc_state.ep_bulk_out, usbtmc_state.ep_bulk_out_buf, USBTMCD_MAX_PACKET_SIZE)); return true; case STATE_RCV: @@ -462,7 +490,6 @@ bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint usbd_edpt_stall(rhport, usbtmc_state.ep_bulk_out); TU_VERIFY(false); } - TU_VERIFY(usbd_edpt_xfer(rhport, usbtmc_state.ep_bulk_out, usbtmc_state.ep_bulk_out_buf, USBTMCD_MAX_PACKET_SIZE)); return true; case STATE_ABORTING_BULK_OUT: @@ -482,8 +509,7 @@ bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint { switch(usbtmc_state.state) { case STATE_TX_SHORTED: - - usbtmc_state.state = STATE_IDLE; + TU_VERIFY(atomicChangeState(STATE_TX_SHORTED, STATE_NAK)); TU_VERIFY(tud_usbtmc_app_msgBulkIn_complete_cb(rhport)); break; @@ -508,7 +534,7 @@ bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint if(((packetLen % USBTMCD_MAX_PACKET_SIZE) != 0) || (packetLen == 0 )) { usbtmc_state.state = STATE_TX_SHORTED; - } + } } return true; case STATE_ABORTING_BULK_IN: @@ -548,9 +574,10 @@ bool usbtmcd_control_request_cb(uint8_t rhport, tusb_control_request_t const * r if(ep_addr == usbtmc_state.ep_bulk_out) { + criticalEnter(); + usbtmc_state.state = STATE_NAK; // USBD core has placed EP in NAK state for us + criticalLeave(); usmtmcd_app_bulkOut_clearFeature_cb(rhport); - // And start a new OUT xfer request now that things are clear - TU_ASSERT( usbd_edpt_xfer(rhport, usbtmc_state.ep_bulk_out, usbtmc_state.ep_bulk_out_buf, 64)); } else if (ep_addr == usbtmc_state.ep_bulk_in) { @@ -605,6 +632,7 @@ bool usbtmcd_control_request_cb(uint8_t rhport, tusb_control_request_t const * r TU_VERIFY(tud_control_xfer(rhport, request, (void*)&rsp,sizeof(rsp))); return true; } + case USBTMC_bREQUEST_CHECK_ABORT_BULK_OUT_STATUS: { usbtmc_check_abort_bulk_rsp_t rsp = { @@ -750,7 +778,7 @@ bool usbtmcd_control_request_cb(uint8_t rhport, tusb_control_request_t const * r TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface TU_VERIFY(request->wLength == sizeof(tmcStatusCode)); TU_VERIFY(tud_usbtmc_app_capabilities.bmIntfcCapabilities.supportsIndicatorPulse); - TU_VERIFY(tud_usbtmc_app_indicator_pluse_cb(rhport, request, &tmcStatusCode)); + TU_VERIFY(tud_usbtmc_app_indicator_pulse_cb(rhport, request, &tmcStatusCode)); TU_VERIFY(tud_control_xfer(rhport, request, (void*)&tmcStatusCode, sizeof(tmcStatusCode))); return true; } diff --git a/src/class/usbtmc/usbtmc_device.h b/src/class/usbtmc/usbtmc_device.h index d33d73905..3638b5527 100644 --- a/src/class/usbtmc/usbtmc_device.h +++ b/src/class/usbtmc/usbtmc_device.h @@ -55,6 +55,17 @@ extern usbtmc_response_capabilities_488_t const tud_usbtmc_app_capabilities; extern usbtmc_response_capabilities_t const tud_usbtmc_app_capabilities; #endif +// In order to proceed, app must call call usbtmcd_start_bus_read(rhport) during or soon after: +// * tud_usbtmc_app_open_cb +// * tud_usbtmc_app_msg_data_cb +// * tud_usbtmc_app_msgBulkIn_complete_cb +// * tud_usbtmc_app_msg_trigger_cb +// * (successful) tud_usbtmc_app_check_abort_bulk_out_cb +// * (successful) tud_usbtmc_app_check_abort_bulk_in_cb +// * (successful) usmtmcd_app_bulkOut_clearFeature_cb + +void tud_usbtmc_app_open_cb(uint8_t rhport, uint8_t interface_id); + bool tud_usbtmc_app_msgBulkOut_start_cb(uint8_t rhport, usbtmc_msg_request_dev_dep_out const * msgHeader); // transfer_complete does not imply that a message is complete. bool tud_usbtmc_app_msg_data_cb(uint8_t rhport, void *data, size_t len, bool transfer_complete); @@ -73,7 +84,7 @@ bool tud_usbtmc_app_check_abort_bulk_out_cb(uint8_t rhport, usbtmc_check_abort_b bool tud_usbtmc_app_check_clear_cb(uint8_t rhport, usbtmc_get_clear_status_rsp_t *rsp); // Indicator pulse should be 0.5 to 1.0 seconds long -TU_ATTR_WEAK bool tud_usbtmc_app_indicator_pluse_cb(uint8_t rhport, tusb_control_request_t const * msg, uint8_t *tmcResult); +TU_ATTR_WEAK bool tud_usbtmc_app_indicator_pulse_cb(uint8_t rhport, tusb_control_request_t const * msg, uint8_t *tmcResult); #if (CFG_USBTMC_CFG_ENABLE_488) uint8_t tud_usbtmc_app_get_stb_cb(uint8_t rhport, uint8_t *tmcResult); @@ -93,6 +104,8 @@ bool usbtmcd_transmit_dev_msg_data( const void * data, size_t len, bool endOfMessage, bool usingTermChar); +bool usbtmcd_start_bus_read(uint8_t rhport); + /* "callbacks" from USB device core */