From eea71a8b3b080299ad95ac79a7d45b2dc0d5b6f6 Mon Sep 17 00:00:00 2001 From: Nathan Conrad Date: Wed, 18 Sep 2019 19:24:54 -0400 Subject: [PATCH] usbtmc updates.... --- examples/device/usbtmc/src/tusb_config.h | 4 +- examples/device/usbtmc/src/usbtmc_app.c | 32 ++- src/class/usbtmc/usbtmc.h | 14 ++ src/class/usbtmc/usbtmc_device.c | 279 +++++++++++++++++------ src/class/usbtmc/usbtmc_device.h | 6 +- 5 files changed, 261 insertions(+), 74 deletions(-) diff --git a/examples/device/usbtmc/src/tusb_config.h b/examples/device/usbtmc/src/tusb_config.h index 022dc7691..16484424a 100644 --- a/examples/device/usbtmc/src/tusb_config.h +++ b/examples/device/usbtmc/src/tusb_config.h @@ -56,8 +56,8 @@ //------------- CLASS -------------// #define CFG_TUD_USBTMC 1 -#define CFG_TUD_USBTMC_ENABLE_INT_EP -//#define USBTMC_CFG_ENABLE_488 0 +#define CFG_TUD_USBTMC_ENABLE_INT_EP 1 +#define USBTMC_CFG_ENABLE_488 1 #ifdef __cplusplus } diff --git a/examples/device/usbtmc/src/usbtmc_app.c b/examples/device/usbtmc/src/usbtmc_app.c index e21c3ca22..03800ab17 100644 --- a/examples/device/usbtmc/src/usbtmc_app.c +++ b/examples/device/usbtmc/src/usbtmc_app.c @@ -64,8 +64,8 @@ usbtmcd_app_capabilities = } #endif }; -//static const char idn[] = "TinyUSB,ModelNumber,SerialNumber,FirmwareVer"; -static const char idn[] = "TinyUSB,ModelNumber,SerialNumber,FirmwareVer and a bunch of other text to make it longer than a packet, perhaps?\n"; +static const char idn[] = "TinyUSB,ModelNumber,SerialNumber,FirmwareVer123456\r\n"; +//static const char idn[] = "TinyUSB,ModelNumber,SerialNumber,FirmwareVer and a bunch of other text to make it longer than a packet, perhaps? lets make it three transfers...\n"; static volatile uint8_t status; // 0=not query, 1=queried, 2=delay,set(MAV), 3=delay 4=ready? @@ -154,14 +154,14 @@ void usbtmc_app_task_iter(void) { queryState = 2; break; case 2: - if( (board_millis() - queryDelayStart) > 5u) { + if( (board_millis() - queryDelayStart) > 200u) { queryDelayStart = board_millis(); queryState=3; status |= 0x10u; // MAV } break; case 3: - if( (board_millis() - queryDelayStart) > 10u) { + if( (board_millis() - queryDelayStart) > 400u) { queryState = 4; } break; @@ -169,6 +169,7 @@ void usbtmc_app_task_iter(void) { if(bulkInStarted) { queryState = 0; bulkInStarted = 0; + uart_tx_str_sync("usbtmc_app_task_iter: sending rsp!\r\n"); usbtmcd_transmit_dev_msg_data(rhport, idn, tu_min32(sizeof(idn)-1,msgReqLen),false); // MAV is cleared in the transfer complete callback. } @@ -189,7 +190,7 @@ bool usbtmcd_app_initiate_clear(uint8_t rhport, uint8_t *tmcResult) return true; } -bool usbtmcd_app_get_clear_status(uint8_t rhport, usbtmc_get_clear_status_rsp_t *rsp) +bool usbtmcd_app_check_clear(uint8_t rhport, usbtmc_get_clear_status_rsp_t *rsp) { (void)rhport; queryState = 0; @@ -199,6 +200,27 @@ bool usbtmcd_app_get_clear_status(uint8_t rhport, usbtmc_get_clear_status_rsp_t rsp->bmClear.BulkInFifoBytes = 0u; return true; } +bool usbtmcd_app_initiate_abort_bulk_in(uint8_t rhport, uint8_t *tmcResult) +{ + bulkInStarted = 0; + *tmcResult = USBTMC_STATUS_SUCCESS; + return true; +} +bool usbtmcd_app_check_abort_bulk_in(uint8_t rhport, usbtmc_check_abort_bulk_rsp_t *rsp) +{ + return true; +} + +bool usbtmcd_app_initiate_abort_bulk_out(uint8_t rhport, uint8_t *tmcResult) +{ + *tmcResult = USBTMC_STATUS_SUCCESS; + return true; + +} +bool usbtmcd_app_check_abort_bulk_out(uint8_t rhport, usbtmc_check_abort_bulk_rsp_t *rsp) +{ + return true; +} void usmtmcd_app_bulkIn_clearFeature(uint8_t rhport) { diff --git a/src/class/usbtmc/usbtmc.h b/src/class/usbtmc/usbtmc.h index 6893c3743..0944c907a 100644 --- a/src/class/usbtmc/usbtmc.h +++ b/src/class/usbtmc/usbtmc.h @@ -237,6 +237,20 @@ typedef struct TU_ATTR_PACKED TU_VERIFY_STATIC(sizeof(usbtmc_get_clear_status_rsp_t) == 2u, "struct wrong length"); +// Used for both check_abort_bulk_in_status and check_abort_bulk_out_status +typedef struct TU_ATTR_PACKED +{ + uint8_t USBTMC_status; + struct TU_ATTR_PACKED + { + unsigned int BulkInFifoBytes : 1; ///< Has queued data or a short packet that is queued + } bmAbortBulkIn; + uint8_t _reserved[2]; ///< Must be zero + uint32_t NBYTES_RXD_TXD; +} usbtmc_check_abort_bulk_rsp_t; + +TU_VERIFY_STATIC(sizeof(usbtmc_check_abort_bulk_rsp_t) == 8u, "struct wrong length"); + typedef struct TU_ATTR_PACKED { uint8_t USBTMC_status; ///< usbtmc_status_enum diff --git a/src/class/usbtmc/usbtmc_device.c b/src/class/usbtmc/usbtmc_device.c index 6d562641e..c71d4d963 100644 --- a/src/class/usbtmc/usbtmc_device.c +++ b/src/class/usbtmc/usbtmc_device.c @@ -93,8 +93,11 @@ typedef enum STATE_RCV, STATE_TX_REQUESTED, STATE_TX_INITIATED, + STATE_TX_SHORTED, STATE_CLEARING, STATE_ABORTING_BULK_IN, + STATE_ABORTING_BULK_IN_SHORTED, // aborting, and short packet has been queued for transmission + STATE_ABORTING_BULK_IN_ABORTED, // aborting, and short packet has been queued for transmission STATE_ABORTING_BULK_OUT, STATE_NUM_STATES } usbtmcd_state_enum; @@ -113,6 +116,7 @@ typedef struct // OUT buffer receives one packet at a time uint8_t ep_bulk_out_buf[USBTMCD_MAX_PACKET_SIZE]; uint32_t transfer_size_remaining; // also used for requested length for bulk IN. + uint32_t transfer_size_sent; // To keep track of data bytes that have been queued in FIFO (not header bytes) uint8_t lastBulkOutTag; // used for aborts (mostly) uint8_t lastBulkInTag; // used for aborts (mostly) @@ -128,6 +132,11 @@ static usbtmc_interface_state_t usbtmc_state = .ep_bulk_out = 0, .ep_int_in = 0 }; +#ifdef xDEBUG +#define TRACE(str) uart_tx_str_sync(str) +#else +#define TRACE(STR) do {} while (0) +#endif // We need all headers to fit in a single packet in this implementation. TU_VERIFY_STATIC(USBTMCD_MAX_PACKET_SIZE >= 32u,"USBTMC dev EP packet size too small"); @@ -188,7 +197,7 @@ bool usbtmcd_transmit_dev_msg_data( if((packetLen + hdr->TransferSize) <= txBufLen) { memcpy((uint8_t*)(usbtmc_state.ep_bulk_in_buf) + packetLen, data, hdr->TransferSize); - packetLen = (uint16_t)(packetLen+ hdr->TransferSize); + packetLen = (uint16_t)(packetLen + hdr->TransferSize); // Pad up to multiple of 4 bytes while((packetLen % 4) != 0) { @@ -196,13 +205,15 @@ bool usbtmcd_transmit_dev_msg_data( packetLen++; } usbtmc_state.transfer_size_remaining = 0; + usbtmc_state.transfer_size_sent = len; usbtmc_state.devInBuffer = NULL; } else /* partial packet */ { memcpy((uint8_t*)(usbtmc_state.ep_bulk_in_buf) + packetLen, data, txBufLen - packetLen); - usbtmc_state.devInBuffer += txBufLen - packetLen; - usbtmc_state.transfer_size_remaining = hdr->TransferSize - (txBufLen - packetLen); + usbtmc_state.devInBuffer = (uint8_t*)data + (txBufLen - packetLen); + usbtmc_state.transfer_size_remaining = len - (txBufLen - packetLen); + usbtmc_state.transfer_size_sent = txBufLen - packetLen; packetLen = txBufLen; } @@ -210,7 +221,8 @@ bool usbtmcd_transmit_dev_msg_data( criticalEnter(); { TU_VERIFY(usbtmc_state.state == STATE_TX_REQUESTED); - usbtmc_state.state = STATE_TX_INITIATED; + // We used packetlen as a max, not the buffer size, so this is OK here, no need for modulus + usbtmc_state.state = (packetLen >= txBufLen) ? STATE_TX_INITIATED : STATE_TX_SHORTED; } criticalLeave(); @@ -322,6 +334,8 @@ void usbtmcd_reset(uint8_t rhport) usbtmc_state.ep_bulk_in = 0; usbtmc_state.ep_bulk_out = 0; usbtmc_state.ep_int_in = 0; + usbtmc_state.lastBulkInTag = 0; + usbtmc_state.lastBulkOutTag = 0; (void)rhport; } @@ -351,10 +365,16 @@ static bool handle_devMsgOut(uint8_t rhport, void *data, size_t len, size_t pack if(len > usbtmc_state.transfer_size_remaining) len = usbtmc_state.transfer_size_remaining; usbtmcd_app_msg_data(rhport,data, len, atEnd); + + usbtmc_state.transfer_size_sent += len; if(atEnd) + { usbtmc_state.state = STATE_IDLE; + } else + { usbtmc_state.state = STATE_RCV; + } return true; } @@ -363,8 +383,10 @@ static bool handle_devMsgIn(uint8_t rhport, void *data, size_t len) TU_VERIFY(len == sizeof(usbtmc_msg_request_dev_dep_in)); usbtmc_msg_request_dev_dep_in *msg = (usbtmc_msg_request_dev_dep_in*)data; +#ifdef xDebug sprintf(logMsg," handle_devMsgIn len=%ul\r\n",len); - uart_tx_str_sync(logMsg); + TRACE(logMsg); +#endif criticalEnter(); { @@ -387,10 +409,13 @@ static bool handle_devMsgIn(uint8_t rhport, void *data, size_t len) bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { + TRACE("USBTMC Xfer CB" ); TU_VERIFY(result == XFER_RESULT_SUCCESS); - uart_tx_str_sync("USBTMC Xfer CB" ); + +#ifdef xDebug sprintf(logMsg," STATE=%lu ", (uint32_t)usbtmc_state.state); - uart_tx_str_sync(logMsg); + TRACE(logMsg); +#endif if(usbtmc_state.state == STATE_CLEARING) { return true; /* I think we can ignore everything here */ @@ -398,23 +423,26 @@ bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint if(ep_addr == usbtmc_state.ep_bulk_out) { - uart_tx_str_sync("OUT"); + usbtmc_msg_generic_t *msg = NULL; + TRACE("OUT"); switch(usbtmc_state.state) { case STATE_IDLE: TU_VERIFY(xferred_bytes >= sizeof(usbtmc_msg_generic_t)); - usbtmc_msg_generic_t *msg = (usbtmc_msg_generic_t*)(usbtmc_state.ep_bulk_out_buf); + msg = (usbtmc_msg_generic_t*)(usbtmc_state.ep_bulk_out_buf); uint8_t invInvTag = (uint8_t)~(msg->header.bTagInverse); TU_VERIFY(msg->header.bTag == invInvTag); TU_VERIFY(msg->header.bTag != 0x00); +#ifdef xDebug sprintf(logMsg," type=%lu\r\n",(uint32_t)msg->header.MsgID); - uart_tx_str_sync(logMsg); + TRACE(logMsg); +#endif switch(msg->header.MsgID) { case USBTMC_MSGID_DEV_DEP_MSG_OUT: + usbtmc_state.transfer_size_sent = 0u; TU_VERIFY(handle_devMsgOutStart(rhport, msg, xferred_bytes)); - TU_VERIFY(usbd_edpt_xfer(rhport, usbtmc_state.ep_bulk_out, usbtmc_state.ep_bulk_out_buf, USBTMCD_MAX_PACKET_SIZE)); usbtmc_state.lastBulkOutTag = msg->header.bTag; break; @@ -428,7 +456,6 @@ bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint // Spec says we halt the EP if we didn't declare we support it. TU_VERIFY(usbtmcd_app_capabilities.bmIntfcCapabilities488.supportsTrigger); TU_VERIFY(usbtmcd_app_msg_trigger(rhport, msg)); - TU_VERIFY(usbd_edpt_xfer(rhport, usbtmc_state.ep_bulk_out, usbtmc_state.ep_bulk_out_buf, USBTMCD_MAX_PACKET_SIZE)); break; #endif @@ -439,58 +466,95 @@ 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: TU_VERIFY(handle_devMsgOut(rhport, usbtmc_state.ep_bulk_out_buf, xferred_bytes, xferred_bytes)); return true; + case STATE_ABORTING_BULK_OUT: + TU_VERIFY(false); + return false; // Shold be stalled by now... case STATE_TX_REQUESTED: case STATE_TX_INITIATED: case STATE_ABORTING_BULK_IN: - case STATE_ABORTING_BULK_OUT: + case STATE_ABORTING_BULK_IN_SHORTED: + case STATE_ABORTING_BULK_IN_ABORTED: default: + +#ifdef xDebug if(msg == NULL) sprintf(logMsg," Unknown received control?\r\n "); else { sprintf(logMsg," msg=%lu\r\n ", (uint32_t)msg->header.MsgID); } - uart_tx_str_sync(logMsg); + TRACE(logMsg); +#endif TU_VERIFY(false); } } else if(ep_addr == usbtmc_state.ep_bulk_in) { +#ifdef xDebug sprintf(logMsg,"IN\r\n"); - uart_tx_str_sync(logMsg); - TU_ASSERT(usbtmc_state.state == STATE_TX_INITIATED); - if(usbtmc_state.transfer_size_remaining == 0) - { + TRACE(logMsg); +#endif + switch(usbtmc_state.state) { + case STATE_TX_SHORTED: + + TRACE("IN TX shorted done\r\n"); + usbtmc_state.state = STATE_IDLE; TU_VERIFY(usbtmcd_app_msgBulkIn_complete(rhport)); - TU_VERIFY( usbd_edpt_xfer(rhport, usbtmc_state.ep_bulk_out, usbtmc_state.ep_bulk_out_buf, USBTMCD_MAX_PACKET_SIZE)); - } - else if(usbtmc_state.transfer_size_remaining > sizeof(usbtmc_state.devInBuffer)) - { - memcpy(usbtmc_state.ep_bulk_in_buf, usbtmc_state.devInBuffer, sizeof(usbtmc_state.ep_bulk_in_buf)); - usbtmc_state.devInBuffer += sizeof(usbtmc_state.devInBuffer); - usbtmc_state.transfer_size_remaining -= sizeof(usbtmc_state.devInBuffer); - TU_VERIFY( usbd_edpt_xfer(rhport, usbtmc_state.ep_bulk_in, usbtmc_state.ep_bulk_in_buf,sizeof(usbtmc_state.devInBuffer))); - } - else // last packet - { - size_t packetLen = usbtmc_state.transfer_size_remaining; - memcpy(usbtmc_state.ep_bulk_in_buf, usbtmc_state.devInBuffer, usbtmc_state.transfer_size_remaining); - while((packetLen % 4) != 0) + break; + + case STATE_TX_INITIATED: + if(usbtmc_state.transfer_size_remaining >=sizeof(usbtmc_state.ep_bulk_in_buf)) { - usbtmc_state.ep_bulk_in_buf[packetLen] = 0; - packetLen++; + TRACE("IN TX continuing\r\n"); + memcpy(usbtmc_state.ep_bulk_in_buf, usbtmc_state.devInBuffer, sizeof(usbtmc_state.ep_bulk_in_buf)); + usbtmc_state.devInBuffer += sizeof(usbtmc_state.devInBuffer); + usbtmc_state.transfer_size_remaining -= sizeof(usbtmc_state.devInBuffer); + usbtmc_state.transfer_size_sent += sizeof(usbtmc_state.devInBuffer); + TU_VERIFY( usbd_edpt_xfer(rhport, usbtmc_state.ep_bulk_in, usbtmc_state.ep_bulk_in_buf,sizeof(usbtmc_state.devInBuffer))); } - usbtmc_state.transfer_size_remaining = 0; - usbtmc_state.devInBuffer = NULL; - TU_VERIFY( usbd_edpt_xfer(rhport, usbtmc_state.ep_bulk_in, usbtmc_state.ep_bulk_in_buf,(uint16_t)packetLen)); + else // last packet + { + TRACE("IN TX last packet\r\n"); + size_t packetLen = usbtmc_state.transfer_size_remaining; + memcpy(usbtmc_state.ep_bulk_in_buf, usbtmc_state.devInBuffer, usbtmc_state.transfer_size_remaining); + while((packetLen % 4) != 0) + { + usbtmc_state.ep_bulk_in_buf[packetLen] = 0u; + packetLen++; + } + usbtmc_state.transfer_size_sent += sizeof(usbtmc_state.transfer_size_remaining); + usbtmc_state.transfer_size_remaining = 0; + usbtmc_state.devInBuffer = NULL; + TU_VERIFY( usbd_edpt_xfer(rhport, usbtmc_state.ep_bulk_in, usbtmc_state.ep_bulk_in_buf,(uint16_t)packetLen)); + if(((packetLen % USBTMCD_MAX_PACKET_SIZE) != 0) || (packetLen == 0 )) + { + usbtmc_state.state = STATE_TX_SHORTED; + } + } + return true; + case STATE_ABORTING_BULK_IN: + // need to send short packet (ZLP?) + TRACE("IN aborting\r\n"); + TU_VERIFY( usbd_edpt_xfer(rhport, usbtmc_state.ep_bulk_in, usbtmc_state.ep_bulk_in_buf,(uint16_t)0u)); + usbtmc_state.state = STATE_ABORTING_BULK_IN_SHORTED; + return true; + case STATE_ABORTING_BULK_IN_SHORTED: + /* Done. :)*/ + TRACE("IN shorted\r\n"); + usbtmc_state.state = STATE_ABORTING_BULK_IN_ABORTED; + return true; + default: + TRACE("IN unknown\r\n"); + TU_ASSERT(false); + return false; } - return true; } else if (ep_addr == usbtmc_state.ep_int_in) { // Good? @@ -505,13 +569,14 @@ bool usbtmcd_control_request(uint8_t rhport, tusb_control_request_t const * requ #if (USBTMC_CFG_ENABLE_488) uint8_t bTag; #endif + TRACE("xfer cb\r\n"); if((request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD) && (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_ENDPOINT) && (request->bRequest == TUSB_REQ_CLEAR_FEATURE) && (request->wValue == TUSB_REQ_FEATURE_EDPT_HALT)) { - uart_tx_str_sync("feature clear\r\n"); + TRACE("feature clear\r\n"); if((request->wIndex) == usbtmc_state.ep_bulk_out) { usmtmcd_app_bulkOut_clearFeature(rhport); @@ -536,42 +601,124 @@ bool usbtmcd_control_request(uint8_t rhport, tusb_control_request_t const * requ { // USBTMC required requests case USBTMC_bREQUEST_INITIATE_ABORT_BULK_OUT: - case USBTMC_bREQUEST_CHECK_ABORT_BULK_OUT_STATUS: { - TU_VERIFY(request->bmRequestType == 0xA2); // in,class,EP - TU_VERIFY(request->wLength == 1u); - tmcStatusCode = USBTMC_STATUS_FAILED; - usbd_edpt_xfer(rhport, 0u, (void*)&tmcStatusCode,sizeof(tmcStatusCode)); + usbtmc_initiate_abort_rsp_t rsp = { + .bTag = usbtmc_state.lastBulkOutTag, + }; + TRACE("init abort bulk out\r\n"); + TU_VERIFY(request->bmRequestType == 0xA2); // in,class,interface + TU_VERIFY(request->wLength == sizeof(rsp)); + TU_VERIFY(request->wIndex == usbtmc_state.ep_bulk_out); + + // wValue is the requested bTag to abort + if(usbtmc_state.state != STATE_RCV) + { + rsp.USBTMC_status = USBTMC_STATUS_FAILED; + TRACE("init abort bulk out failed\r\n"); + } + else if(usbtmc_state.lastBulkOutTag == (request->wValue & 0xf7u)) + { + rsp.USBTMC_status = USBTMC_STATUS_TRANSFER_NOT_IN_PROGRESS; + TRACE("init abort bulk out not inprogress\r\n"); + } + else + { + rsp.USBTMC_status = USBTMC_STATUS_SUCCESS; + // Check if we've queued a short packet + usbtmc_state.state = STATE_ABORTING_BULK_OUT; + TU_VERIFY(usbtmcd_app_initiate_abort_bulk_out(rhport, &(rsp.USBTMC_status))); + usbd_edpt_stall(rhport, usbtmc_state.ep_bulk_out); + TRACE("init abort bulk out success\r\n"); + } + TU_VERIFY(tud_control_xfer(rhport, request, (void*)&rsp,sizeof(rsp))); return true; } - case USBTMC_bREQUEST_CHECK_ABORT_BULK_IN_STATUS: + case USBTMC_bREQUEST_CHECK_ABORT_BULK_OUT_STATUS: { + TRACE("init check abort bulk out\r\n"); + usbtmc_check_abort_bulk_rsp_t rsp = { + .USBTMC_status = USBTMC_STATUS_SUCCESS, + .NBYTES_RXD_TXD = usbtmc_state.transfer_size_sent + }; TU_VERIFY(request->bmRequestType == 0xA2); // in,class,EP - TU_VERIFY(request->wLength == 1u); - usbtmc_get_clear_status_rsp_t clearStatusRsp = {0}; - tmcStatusCode = USBTMC_STATUS_FAILED; - usbd_edpt_xfer(rhport, 0u, (void*)&tmcStatusCode,sizeof(tmcStatusCode)); + TU_VERIFY(request->wLength == sizeof(rsp)); + TU_VERIFY(request->wIndex == usbtmc_state.ep_bulk_out); + TU_VERIFY(usbtmcd_app_check_abort_bulk_out(rhport, &(rsp.USBTMC_status))); + TU_VERIFY(usbd_edpt_xfer(rhport, 0u, (void*)&rsp,sizeof(rsp))); return true; } case USBTMC_bREQUEST_INITIATE_ABORT_BULK_IN: { - usbtmc_initiate_abort_rsp_t rsp = {0}; - uart_tx_str_sync("init abort bulk in\r\n"); - TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface - TU_VERIFY(request->wLength == sizeof(tmcStatusCode)); - TU_VERIFY(request->wIndex == usbtmc_state.ep_int_in); + usbtmc_initiate_abort_rsp_t rsp = { + .bTag = usbtmc_state.lastBulkInTag, + }; + TRACE("init abort bulk in\r\n"); + TU_VERIFY(request->bmRequestType == 0xA2); // in,class,interface + TU_VERIFY(request->wLength == sizeof(rsp)); + TU_VERIFY(request->wIndex == usbtmc_state.ep_bulk_in); // wValue is the requested bTag to abort - usbtmc_state.transfer_size_remaining = 0; - usbtmc_state.state = STATE_ABORTING_BULK_IN; - TU_VERIFY(usbtmcd_app_initiate_clear(rhport, &tmcStatusCode)); - TU_VERIFY(tud_control_xfer(rhport, request, (void*)&tmcStatusCode,sizeof(tmcStatusCode))); + if((usbtmc_state.state == STATE_TX_REQUESTED || usbtmc_state.state == STATE_TX_INITIATED) && + usbtmc_state.lastBulkInTag == (request->wValue & 0xf7u)) + { + rsp.USBTMC_status = USBTMC_STATUS_SUCCESS; + usbtmc_state.transfer_size_remaining = 0; + // Check if we've queued a short packet + usbtmc_state.state = ((usbtmc_state.transfer_size_sent % USBTMCD_MAX_PACKET_SIZE) != 0) ? + STATE_ABORTING_BULK_IN : STATE_ABORTING_BULK_IN_SHORTED; + TU_VERIFY(usbtmcd_app_initiate_abort_bulk_in(rhport, &(rsp.USBTMC_status))); + TRACE("init abort bulk success\r\n"); + } + else if((usbtmc_state.state == STATE_TX_REQUESTED || usbtmc_state.state == STATE_TX_INITIATED)) + { // FIXME: Unsure how to check if the OUT endpoint fifo is non-empty.... + rsp.USBTMC_status = USBTMC_STATUS_TRANSFER_NOT_IN_PROGRESS; + TRACE("init abort bulk in not in progress\r\n"); + } + else + { + rsp.USBTMC_status = USBTMC_STATUS_FAILED; + TRACE("init abort bulk in failed\r\n"); + } + TU_VERIFY(tud_control_xfer(rhport, request, (void*)&rsp,sizeof(rsp))); + return true; + } + + case USBTMC_bREQUEST_CHECK_ABORT_BULK_IN_STATUS: + { + TRACE("xfer check abort in\r\n"); + TU_VERIFY(request->bmRequestType == 0xA2); // in,class,EP + TU_VERIFY(request->wLength == 8u); + + usbtmc_check_abort_bulk_rsp_t rsp = + { + .USBTMC_status = USBTMC_STATUS_FAILED, + .bmAbortBulkIn = + { + .BulkInFifoBytes = (usbtmc_state.state == STATE_ABORTING_BULK_IN_ABORTED) + }, + .NBYTES_RXD_TXD = usbtmc_state.transfer_size_sent, + }; + TU_VERIFY(usbtmcd_app_check_abort_bulk_in(rhport, &rsp)); + switch(usbtmc_state.state) + { + case STATE_ABORTING_BULK_IN_ABORTED: + rsp.USBTMC_status = USBTMC_STATUS_SUCCESS; + break; + case STATE_ABORTING_BULK_IN: + case STATE_ABORTING_BULK_OUT: + rsp.USBTMC_status = USBTMC_STATUS_PENDING; + break; + default: + break; + } + TU_VERIFY(tud_control_xfer(rhport, request, (void*)&rsp,sizeof(rsp))); + return true; } case USBTMC_bREQUEST_INITIATE_CLEAR: { - uart_tx_str_sync("init clear\r\n"); + TRACE("init clear\r\n"); TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface TU_VERIFY(request->wLength == sizeof(tmcStatusCode)); // After receiving an INITIATE_CLEAR request, the device must Halt the Bulk-OUT endpoint, queue the @@ -586,7 +733,7 @@ bool usbtmcd_control_request(uint8_t rhport, tusb_control_request_t const * requ case USBTMC_bREQUEST_CHECK_CLEAR_STATUS: { - uart_tx_str_sync("check clear\r\n"); + TRACE("check clear\r\n"); TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface usbtmc_get_clear_status_rsp_t clearStatusRsp = {0}; TU_VERIFY(request->wLength == sizeof(clearStatusRsp)); @@ -600,7 +747,7 @@ bool usbtmcd_control_request(uint8_t rhport, tusb_control_request_t const * requ else { // Let app check if it's clear - TU_VERIFY(usbtmcd_app_get_clear_status(rhport, &clearStatusRsp)); + TU_VERIFY(usbtmcd_app_check_clear(rhport, &clearStatusRsp)); } if(clearStatusRsp.USBTMC_status == USBTMC_STATUS_SUCCESS) usbtmc_state.state = STATE_IDLE; @@ -610,7 +757,7 @@ bool usbtmcd_control_request(uint8_t rhport, tusb_control_request_t const * requ case USBTMC_bREQUEST_GET_CAPABILITIES: { - uart_tx_str_sync("get capabilities\r\n"); + TRACE("get capabilities\r\n"); TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface TU_VERIFY(request->wLength == sizeof(usbtmcd_app_capabilities)); TU_VERIFY(tud_control_xfer(rhport, request, (void*)&usbtmcd_app_capabilities, sizeof(usbtmcd_app_capabilities))); @@ -620,7 +767,7 @@ bool usbtmcd_control_request(uint8_t rhport, tusb_control_request_t const * requ case USBTMC_bREQUEST_INDICATOR_PULSE: // Optional { - uart_tx_str_sync("indicate\r\n"); + TRACE("indicate\r\n"); TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface TU_VERIFY(request->wLength == sizeof(tmcStatusCode)); TU_VERIFY(usbtmcd_app_capabilities.bmIntfcCapabilities.supportsIndicatorPulse); @@ -633,7 +780,7 @@ bool usbtmcd_control_request(uint8_t rhport, tusb_control_request_t const * requ // USB488 required requests case USBTMC488_bREQUEST_READ_STATUS_BYTE: { - uart_tx_str_sync("read stb\r\n"); + TRACE("read stb\r\n"); usbtmc_read_stb_rsp_488_t rsp; TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface TU_VERIFY(request->wLength == sizeof(rsp)); // in,class,interface @@ -672,7 +819,7 @@ bool usbtmcd_control_request(uint8_t rhport, tusb_control_request_t const * requ case USBTMC488_bREQUEST_GO_TO_LOCAL: case USBTMC488_bREQUEST_LOCAL_LOCKOUT: { - uart_tx_str_sync("Unsupported REN/GTL/LLO\r\n"); + TRACE("Unsupported REN/GTL/LLO\r\n"); TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface TU_VERIFY(false); return false; @@ -680,7 +827,7 @@ bool usbtmcd_control_request(uint8_t rhport, tusb_control_request_t const * requ #endif default: - uart_tx_str_sync("Default CTRL handler\r\n"); + TRACE("Default CTRL handler\r\n"); TU_VERIFY(false); return false; } diff --git a/src/class/usbtmc/usbtmc_device.h b/src/class/usbtmc/usbtmc_device.h index a0ba82e30..4c991d5ff 100644 --- a/src/class/usbtmc/usbtmc_device.h +++ b/src/class/usbtmc/usbtmc_device.h @@ -64,9 +64,13 @@ bool usbtmcd_app_msgBulkIn_request(uint8_t rhport, usbtmc_msg_request_dev_dep_in bool usbtmcd_app_msgBulkIn_complete(uint8_t rhport); void usmtmcd_app_bulkIn_clearFeature(uint8_t rhport); // Notice to clear and abort the pending BULK out transfer +bool usbtmcd_app_initiate_abort_bulk_in(uint8_t rhport, uint8_t *tmcResult); +bool usbtmcd_app_initiate_abort_bulk_out(uint8_t rhport, uint8_t *tmcResult); bool usbtmcd_app_initiate_clear(uint8_t rhport, uint8_t *tmcResult); -bool usbtmcd_app_get_clear_status(uint8_t rhport, usbtmc_get_clear_status_rsp_t *rsp); +bool usbtmcd_app_check_abort_bulk_in(uint8_t rhport, usbtmc_check_abort_bulk_rsp_t *rsp); +bool usbtmcd_app_check_abort_bulk_out(uint8_t rhport, usbtmc_check_abort_bulk_rsp_t *rsp); +bool usbtmcd_app_check_clear(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 usbtmcd_app_indicator_pluse(uint8_t rhport, tusb_control_request_t const * msg, uint8_t *tmcResult);