Changes1...
This commit is contained in:
@@ -228,6 +228,15 @@ typedef struct TU_ATTR_PACKED
|
|||||||
|
|
||||||
TU_VERIFY_STATIC(sizeof(usbtmc_get_clear_status_rsp_t) == 2u, "struct wrong length");
|
TU_VERIFY_STATIC(sizeof(usbtmc_get_clear_status_rsp_t) == 2u, "struct wrong length");
|
||||||
|
|
||||||
|
// Used for both abort bulk IN and bulk OUT
|
||||||
|
typedef struct TU_ATTR_PACKED
|
||||||
|
{
|
||||||
|
uint8_t USBTMC_status;
|
||||||
|
uint8_t bTag;
|
||||||
|
} usbtmc_initiate_abort_rsp_t;
|
||||||
|
|
||||||
|
TU_VERIFY_STATIC(sizeof(usbtmc_get_clear_status_rsp_t) == 2u, "struct wrong length");
|
||||||
|
|
||||||
typedef struct TU_ATTR_PACKED
|
typedef struct TU_ATTR_PACKED
|
||||||
{
|
{
|
||||||
uint8_t USBTMC_status; ///< usbtmc_status_enum
|
uint8_t USBTMC_status; ///< usbtmc_status_enum
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
/*
|
/*
|
||||||
* The MIT License (MIT)
|
* The MIT License (MIT)
|
||||||
*
|
*
|
||||||
* Copyright (c) 2019 N Conrad
|
* Copyright (c) 2019 Nathan Conrad
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -33,31 +33,53 @@
|
|||||||
|
|
||||||
#include "tusb_option.h"
|
#include "tusb_option.h"
|
||||||
|
|
||||||
// We don't do any cross-task anything here (everything is in tud or interrupt context).
|
// Synchronization is needed in some spots.
|
||||||
// You must ensure thread safety in your own app.
|
// These functions should NOT be called from interrupts.
|
||||||
|
|
||||||
|
/* The library is designed that its functions can be called by any user task, with need for
|
||||||
|
* additional locking. In the case of "no OS", this task is never preempted other than by
|
||||||
|
* interrupts, and the USBTMC code isn't called by interrupts, so all is OK. In the case
|
||||||
|
* of an OS, this class driver uses the OSAL to perform locking. The code uses a single lock
|
||||||
|
* and does not call outside of this class with a lock held, so deadlocks won't happen.
|
||||||
|
*
|
||||||
|
* This module's application-facing functions are not reentrant. The application must
|
||||||
|
* only call them from a single thread (or implement its own locking).
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
//Limitations (not planned to be implemented):
|
//Limitations:
|
||||||
// "vendor-specific" commands are not handled
|
// "vendor-specific" commands are not handled.
|
||||||
// Dealing with "termchar" must be handled by the application layer,
|
// Dealing with "termchar" must be handled by the application layer,
|
||||||
// though additional error checking is does in this module.
|
// though additional error checking is does in this module.
|
||||||
|
// talkOnly and listenOnly are NOT supported. They're no permitted
|
||||||
|
// in USB488, anyway.
|
||||||
|
|
||||||
|
/* Supported:
|
||||||
|
*
|
||||||
|
* Notification pulse
|
||||||
|
* Trigger
|
||||||
|
* Read status byte (both by interrupt endpoint and control message)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
// USBTMC 3.2.2 error conditions not strictly followed
|
// USBTMC 3.2.2 error conditions not strictly followed
|
||||||
// No local lock-out, REN, or GTL.
|
// No local lock-out, REN, or GTL.
|
||||||
// Cannot handle clear.
|
// Cannot handle clear.
|
||||||
// Not all "capabilities" supported
|
|
||||||
// Clear message available status byte at the correct time? (488 4.3.1.3)
|
// Clear message available status byte at the correct time? (488 4.3.1.3)
|
||||||
// Split transfers
|
// Abort bulk in/out
|
||||||
// No CLEAR_FEATURE/HALT no EP (yet)
|
// No CLEAR_FEATURE/HALT no EP (yet)
|
||||||
// No aborting transfers.
|
|
||||||
|
|
||||||
#if (TUSB_OPT_DEVICE_ENABLED && CFG_TUD_USBTMC)
|
#if (TUSB_OPT_DEVICE_ENABLED && CFG_TUD_USBTMC)
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
#include "usbtmc.h"
|
#include "usbtmc.h"
|
||||||
#include "usbtmc_device.h"
|
#include "usbtmc_device.h"
|
||||||
#include "device/dcd.h"
|
#include "device/dcd.h"
|
||||||
#include "device/usbd.h"
|
#include "device/usbd.h"
|
||||||
|
#include "uart_util.h"
|
||||||
|
static char logMsg[150];
|
||||||
|
|
||||||
// FIXME: I shouldn't need to include _pvt headers.
|
// FIXME: I shouldn't need to include _pvt headers.
|
||||||
#include "device/usbd_pvt.h"
|
#include "device/usbd_pvt.h"
|
||||||
@@ -70,21 +92,31 @@ typedef enum
|
|||||||
STATE_IDLE,
|
STATE_IDLE,
|
||||||
STATE_RCV,
|
STATE_RCV,
|
||||||
STATE_TX_REQUESTED,
|
STATE_TX_REQUESTED,
|
||||||
STATE_TX_INITIATED
|
STATE_TX_INITIATED,
|
||||||
|
STATE_CLEARING,
|
||||||
|
STATE_ABORTING_BULK_IN,
|
||||||
|
STATE_ABORTING_BULK_OUT,
|
||||||
|
STATE_NUM_STATES
|
||||||
} usbtmcd_state_enum;
|
} usbtmcd_state_enum;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
usbtmcd_state_enum state;
|
volatile usbtmcd_state_enum state;
|
||||||
|
|
||||||
uint8_t itf_id;
|
uint8_t itf_id;
|
||||||
uint8_t ep_bulk_in;
|
uint8_t ep_bulk_in;
|
||||||
uint8_t ep_bulk_out;
|
uint8_t ep_bulk_out;
|
||||||
uint8_t ep_int_in;
|
uint8_t ep_int_in;
|
||||||
uint8_t ep_bulk_in_buf[64];
|
// IN buffer is only used for first packet, not the remainder
|
||||||
uint8_t ep_bulk_out_buf[64];
|
// in order to deal with prepending header
|
||||||
uint8_t lastTag;
|
uint8_t ep_bulk_in_buf[USBTMCD_MAX_PACKET_SIZE];
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
uint8_t lastBulkOutTag; // used for aborts (mostly)
|
||||||
|
uint8_t lastBulkInTag; // used for aborts (mostly)
|
||||||
|
|
||||||
uint32_t transfer_size_remaining;
|
|
||||||
uint8_t const * devInBuffer;
|
uint8_t const * devInBuffer;
|
||||||
} usbtmc_interface_state_t;
|
} usbtmc_interface_state_t;
|
||||||
|
|
||||||
@@ -97,39 +129,63 @@ static usbtmc_interface_state_t usbtmc_state =
|
|||||||
.ep_int_in = 0
|
.ep_int_in = 0
|
||||||
};
|
};
|
||||||
|
|
||||||
// We want everything to fit nicely in a single packet, so lets require EP size >32
|
// We need all headers to fit in a single packet in this implementation.
|
||||||
// I'm not sure if this is really necessary, though.
|
|
||||||
TU_VERIFY_STATIC(USBTMCD_MAX_PACKET_SIZE >= 32u,"USBTMC dev EP packet size too small");
|
TU_VERIFY_STATIC(USBTMCD_MAX_PACKET_SIZE >= 32u,"USBTMC dev EP packet size too small");
|
||||||
|
TU_VERIFY_STATIC(
|
||||||
|
(sizeof(usbtmc_state.ep_bulk_in_buf) % USBTMCD_MAX_PACKET_SIZE) == 0,
|
||||||
|
"packet buffer must be a multiple of the packet size");
|
||||||
|
|
||||||
static bool handle_devMsgOutStart(uint8_t rhport, void *data, size_t len);
|
static bool handle_devMsgOutStart(uint8_t rhport, void *data, size_t len);
|
||||||
static bool handle_devMsgOut(uint8_t rhport, void *data, size_t len, size_t packetLen);
|
static bool handle_devMsgOut(uint8_t rhport, void *data, size_t len, size_t packetLen);
|
||||||
|
|
||||||
|
|
||||||
|
osal_mutex_def_t usbtmcLockBuffer;
|
||||||
|
static osal_mutex_t usbtmcLock;
|
||||||
|
|
||||||
|
// Our own private lock, mostly for the state variable.
|
||||||
|
#define criticalEnter() do {osal_mutex_lock(usbtmcLock,OSAL_TIMEOUT_WAIT_FOREVER); } while (0)
|
||||||
|
#define criticalLeave() do {osal_mutex_unlock(usbtmcLock); } while (0)
|
||||||
|
|
||||||
// called from app
|
// called from app
|
||||||
// We keep a reference to the buffer, so it MUST not change until the app is
|
// We keep a reference to the buffer, so it MUST not change until the app is
|
||||||
// notified that the transfer is complete.
|
// notified that the transfer is complete.
|
||||||
// length of data is specified in the hdr.
|
// length of data is specified in the hdr.
|
||||||
|
|
||||||
|
// We can't just send the whole thing at once because we need to concatanate the
|
||||||
|
// header with the data.
|
||||||
bool usbtmcd_transmit_dev_msg_data(
|
bool usbtmcd_transmit_dev_msg_data(
|
||||||
uint8_t rhport,
|
uint8_t rhport,
|
||||||
usbtmc_msg_dev_dep_msg_in_header_t const * hdr,
|
const void * data, size_t len,
|
||||||
const void *data)
|
bool usingTermChar)
|
||||||
{
|
{
|
||||||
TU_ASSERT(usbtmc_state.state == STATE_TX_REQUESTED);
|
const unsigned int txBufLen = sizeof(usbtmc_state.ep_bulk_in_buf);
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
TU_ASSERT(hdr->TransferSize > 0u);
|
TU_ASSERT(len > 0u);
|
||||||
if(hdr->bmTransferAttributes.UsingTermChar)
|
TU_ASSERT(len <= usbtmc_state.transfer_size_remaining);
|
||||||
|
if(usingTermChar)
|
||||||
{
|
{
|
||||||
TU_ASSERT(usbtmcd_app_capabilities.bmDevCapabilities.canEndBulkInOnTermChar);
|
TU_ASSERT(usbtmcd_app_capabilities.bmDevCapabilities.canEndBulkInOnTermChar);
|
||||||
TU_ASSERT(termCharRequested);
|
TU_ASSERT(termCharRequested);
|
||||||
TU_ASSERT(((uint8_t*)data)[hdr->TransferSize-1] == termChar);
|
TU_ASSERT(((uint8_t*)data)[len-1] == termChar);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
TU_VERIFY(usbtmc_state.state == STATE_TX_REQUESTED);
|
||||||
|
usbtmc_msg_dev_dep_msg_in_header_t *hdr = (usbtmc_msg_dev_dep_msg_in_header_t*)usbtmc_state.ep_bulk_in_buf;
|
||||||
|
memset(hdr, 0x00, sizeof(*hdr));
|
||||||
|
hdr->header.MsgID = USBTMC_MSGID_DEV_DEP_MSG_IN;
|
||||||
|
hdr->header.bTag = usbtmc_state.lastBulkInTag;
|
||||||
|
hdr->header.bTagInverse = (uint8_t)~(usbtmc_state.lastBulkInTag);
|
||||||
|
hdr->TransferSize = len;
|
||||||
|
hdr->bmTransferAttributes.EOM = 1u;
|
||||||
|
hdr->bmTransferAttributes.UsingTermChar = usingTermChar;
|
||||||
|
|
||||||
// Copy in the header
|
// Copy in the header
|
||||||
memcpy(usbtmc_state.ep_bulk_in_buf, hdr, sizeof(*hdr));
|
|
||||||
size_t packetLen = sizeof(*hdr);
|
size_t packetLen = sizeof(*hdr);
|
||||||
// Single-packet transfer
|
|
||||||
if((packetLen + hdr->TransferSize) <= USBTMCD_MAX_PACKET_SIZE)
|
// If it fits in a single trasnmission:
|
||||||
|
if((packetLen + hdr->TransferSize) <= txBufLen)
|
||||||
{
|
{
|
||||||
memcpy((uint8_t*)(usbtmc_state.ep_bulk_in_buf) + packetLen, data, hdr->TransferSize);
|
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);
|
||||||
@@ -142,14 +198,22 @@ bool usbtmcd_transmit_dev_msg_data(
|
|||||||
usbtmc_state.transfer_size_remaining = 0;
|
usbtmc_state.transfer_size_remaining = 0;
|
||||||
usbtmc_state.devInBuffer = NULL;
|
usbtmc_state.devInBuffer = NULL;
|
||||||
}
|
}
|
||||||
else
|
else /* partial packet */
|
||||||
{
|
{
|
||||||
memcpy((uint8_t*)(usbtmc_state.ep_bulk_in_buf) + packetLen, data, USBTMCD_MAX_PACKET_SIZE - packetLen);
|
memcpy((uint8_t*)(usbtmc_state.ep_bulk_in_buf) + packetLen, data, txBufLen - packetLen);
|
||||||
usbtmc_state.transfer_size_remaining = hdr->TransferSize - (USBTMCD_MAX_PACKET_SIZE - packetLen);
|
usbtmc_state.devInBuffer += txBufLen - packetLen;
|
||||||
usbtmc_state.devInBuffer += (USBTMCD_MAX_PACKET_SIZE - packetLen);
|
usbtmc_state.transfer_size_remaining = hdr->TransferSize - (txBufLen - packetLen);
|
||||||
packetLen = USBTMCD_MAX_PACKET_SIZE;
|
packetLen = txBufLen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
criticalEnter();
|
||||||
|
{
|
||||||
|
TU_VERIFY(usbtmc_state.state == STATE_TX_REQUESTED);
|
||||||
usbtmc_state.state = STATE_TX_INITIATED;
|
usbtmc_state.state = STATE_TX_INITIATED;
|
||||||
|
}
|
||||||
|
criticalLeave();
|
||||||
|
|
||||||
TU_VERIFY( usbd_edpt_xfer(rhport, usbtmc_state.ep_bulk_in, usbtmc_state.ep_bulk_in_buf, (uint16_t)packetLen));
|
TU_VERIFY( usbd_edpt_xfer(rhport, usbtmc_state.ep_bulk_in, usbtmc_state.ep_bulk_in_buf, (uint16_t)packetLen));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -160,10 +224,15 @@ void usbtmcd_init(void)
|
|||||||
# if USBTMC_CFG_ENABLE_488
|
# if USBTMC_CFG_ENABLE_488
|
||||||
if(usbtmcd_app_capabilities.bmIntfcCapabilities488.supportsTrigger)
|
if(usbtmcd_app_capabilities.bmIntfcCapabilities488.supportsTrigger)
|
||||||
TU_ASSERT(&usbtmcd_app_msg_trigger != NULL,);
|
TU_ASSERT(&usbtmcd_app_msg_trigger != NULL,);
|
||||||
|
// Per USB488 spec: table 8
|
||||||
|
TU_ASSERT(!usbtmcd_app_capabilities.bmIntfcCapabilities.listenOnly,);
|
||||||
|
TU_ASSERT(!usbtmcd_app_capabilities.bmIntfcCapabilities.talkOnly,);
|
||||||
# endif
|
# endif
|
||||||
if(usbtmcd_app_capabilities.bmIntfcCapabilities.supportsIndicatorPulse)
|
if(usbtmcd_app_capabilities.bmIntfcCapabilities.supportsIndicatorPulse)
|
||||||
TU_ASSERT(&usbtmcd_app_indicator_pluse != NULL,);
|
TU_ASSERT(&usbtmcd_app_indicator_pluse != NULL,);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
usbtmcLock = osal_mutex_create(&usbtmcLockBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool usbtmcd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t *p_length)
|
bool usbtmcd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t *p_length)
|
||||||
@@ -226,10 +295,17 @@ bool usbtmcd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16
|
|||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
TU_ASSERT(usbtmc_state.ep_bulk_in != 0);
|
TU_ASSERT(usbtmc_state.ep_bulk_in != 0);
|
||||||
TU_ASSERT(usbtmc_state.ep_bulk_out != 0);
|
TU_ASSERT(usbtmc_state.ep_bulk_out != 0);
|
||||||
if (itf_desc->bNumEndpoints == 2) {
|
if (itf_desc->bNumEndpoints == 2)
|
||||||
|
{
|
||||||
TU_ASSERT(usbtmc_state.ep_int_in == 0);
|
TU_ASSERT(usbtmc_state.ep_int_in == 0);
|
||||||
}
|
}
|
||||||
else if (itf_desc->bNumEndpoints == 2)
|
else if (itf_desc->bNumEndpoints == 3)
|
||||||
|
{
|
||||||
|
TU_ASSERT(usbtmc_state.ep_int_in != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(usbtmcd_app_capabilities.bmIntfcCapabilities488.is488_2 ||
|
||||||
|
usbtmcd_app_capabilities.bmDevCapabilities488.SR1)
|
||||||
{
|
{
|
||||||
TU_ASSERT(usbtmc_state.ep_int_in != 0);
|
TU_ASSERT(usbtmc_state.ep_int_in != 0);
|
||||||
}
|
}
|
||||||
@@ -286,12 +362,22 @@ static bool handle_devMsgIn(uint8_t rhport, void *data, size_t len)
|
|||||||
{
|
{
|
||||||
TU_VERIFY(len == sizeof(usbtmc_msg_request_dev_dep_in));
|
TU_VERIFY(len == sizeof(usbtmc_msg_request_dev_dep_in));
|
||||||
usbtmc_msg_request_dev_dep_in *msg = (usbtmc_msg_request_dev_dep_in*)data;
|
usbtmc_msg_request_dev_dep_in *msg = (usbtmc_msg_request_dev_dep_in*)data;
|
||||||
|
|
||||||
|
sprintf(logMsg," handle_devMsgIn len=%ul\r\n",len);
|
||||||
|
uart_tx_str_sync(logMsg);
|
||||||
|
|
||||||
|
criticalEnter();
|
||||||
|
{
|
||||||
TU_VERIFY(usbtmc_state.state == STATE_IDLE);
|
TU_VERIFY(usbtmc_state.state == STATE_IDLE);
|
||||||
usbtmc_state.state = STATE_TX_REQUESTED;
|
usbtmc_state.state = STATE_TX_REQUESTED;
|
||||||
|
usbtmc_state.lastBulkInTag = msg->header.bTag;
|
||||||
usbtmc_state.transfer_size_remaining = msg->TransferSize;
|
usbtmc_state.transfer_size_remaining = msg->TransferSize;
|
||||||
|
}
|
||||||
|
criticalLeave();
|
||||||
|
|
||||||
termCharRequested = msg->bmTransferAttributes.TermCharEnabled;
|
termCharRequested = msg->bmTransferAttributes.TermCharEnabled;
|
||||||
termChar = msg->TermChar;
|
termChar = msg->TermChar;
|
||||||
|
|
||||||
if(termCharRequested)
|
if(termCharRequested)
|
||||||
TU_VERIFY(usbtmcd_app_capabilities.bmDevCapabilities.canEndBulkInOnTermChar);
|
TU_VERIFY(usbtmcd_app_capabilities.bmDevCapabilities.canEndBulkInOnTermChar);
|
||||||
|
|
||||||
@@ -302,8 +388,17 @@ 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)
|
bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
|
||||||
{
|
{
|
||||||
TU_VERIFY(result == XFER_RESULT_SUCCESS);
|
TU_VERIFY(result == XFER_RESULT_SUCCESS);
|
||||||
|
uart_tx_str_sync("USBTMC Xfer CB" );
|
||||||
|
sprintf(logMsg," STATE=%lu ", (uint32_t)usbtmc_state.state);
|
||||||
|
uart_tx_str_sync(logMsg);
|
||||||
|
|
||||||
|
if(usbtmc_state.state == STATE_CLEARING) {
|
||||||
|
return true; /* I think we can ignore everything here */
|
||||||
|
}
|
||||||
|
|
||||||
if(ep_addr == usbtmc_state.ep_bulk_out)
|
if(ep_addr == usbtmc_state.ep_bulk_out)
|
||||||
{
|
{
|
||||||
|
uart_tx_str_sync("OUT");
|
||||||
switch(usbtmc_state.state)
|
switch(usbtmc_state.state)
|
||||||
{
|
{
|
||||||
case STATE_IDLE:
|
case STATE_IDLE:
|
||||||
@@ -312,15 +407,19 @@ bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint
|
|||||||
uint8_t invInvTag = (uint8_t)~(msg->header.bTagInverse);
|
uint8_t invInvTag = (uint8_t)~(msg->header.bTagInverse);
|
||||||
TU_VERIFY(msg->header.bTag == invInvTag);
|
TU_VERIFY(msg->header.bTag == invInvTag);
|
||||||
TU_VERIFY(msg->header.bTag != 0x00);
|
TU_VERIFY(msg->header.bTag != 0x00);
|
||||||
usbtmc_state.lastTag = msg->header.bTag;
|
|
||||||
|
sprintf(logMsg," type=%lu\r\n",(uint32_t)msg->header.MsgID);
|
||||||
|
uart_tx_str_sync(logMsg);
|
||||||
|
|
||||||
switch(msg->header.MsgID) {
|
switch(msg->header.MsgID) {
|
||||||
case USBTMC_MSGID_DEV_DEP_MSG_OUT:
|
case USBTMC_MSGID_DEV_DEP_MSG_OUT:
|
||||||
TU_VERIFY(handle_devMsgOutStart(rhport, msg, xferred_bytes));
|
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));
|
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;
|
break;
|
||||||
|
|
||||||
case USBTMC_MSGID_DEV_DEP_MSG_IN:
|
case USBTMC_MSGID_DEV_DEP_MSG_IN:
|
||||||
|
uart_tx_sync("Handling msg in req\r\n", 21);
|
||||||
TU_VERIFY(handle_devMsgIn(rhport, msg, xferred_bytes));
|
TU_VERIFY(handle_devMsgIn(rhport, msg, xferred_bytes));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -336,6 +435,7 @@ bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint
|
|||||||
case USBTMC_MSGID_VENDOR_SPECIFIC_MSG_OUT:
|
case USBTMC_MSGID_VENDOR_SPECIFIC_MSG_OUT:
|
||||||
case USBTMC_MSGID_VENDOR_SPECIFIC_IN:
|
case USBTMC_MSGID_VENDOR_SPECIFIC_IN:
|
||||||
default:
|
default:
|
||||||
|
|
||||||
TU_VERIFY(false);
|
TU_VERIFY(false);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -347,12 +447,22 @@ bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint
|
|||||||
|
|
||||||
case STATE_TX_REQUESTED:
|
case STATE_TX_REQUESTED:
|
||||||
case STATE_TX_INITIATED:
|
case STATE_TX_INITIATED:
|
||||||
|
case STATE_ABORTING_BULK_IN:
|
||||||
|
case STATE_ABORTING_BULK_OUT:
|
||||||
default:
|
default:
|
||||||
|
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);
|
||||||
TU_VERIFY(false);
|
TU_VERIFY(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(ep_addr == usbtmc_state.ep_bulk_in)
|
else if(ep_addr == usbtmc_state.ep_bulk_in)
|
||||||
{
|
{
|
||||||
|
sprintf(logMsg,"IN\r\n");
|
||||||
|
uart_tx_str_sync(logMsg);
|
||||||
TU_ASSERT(usbtmc_state.state == STATE_TX_INITIATED);
|
TU_ASSERT(usbtmc_state.state == STATE_TX_INITIATED);
|
||||||
if(usbtmc_state.transfer_size_remaining == 0)
|
if(usbtmc_state.transfer_size_remaining == 0)
|
||||||
{
|
{
|
||||||
@@ -360,14 +470,14 @@ bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint
|
|||||||
TU_VERIFY(usbtmcd_app_msgBulkIn_complete(rhport));
|
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));
|
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 >= 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, USBTMCD_MAX_PACKET_SIZE);
|
memcpy(usbtmc_state.ep_bulk_in_buf, usbtmc_state.devInBuffer, sizeof(usbtmc_state.ep_bulk_in_buf));
|
||||||
usbtmc_state.devInBuffer += USBTMCD_MAX_PACKET_SIZE;
|
usbtmc_state.devInBuffer += sizeof(usbtmc_state.devInBuffer);
|
||||||
usbtmc_state.transfer_size_remaining -= USBTMCD_MAX_PACKET_SIZE;
|
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,USBTMCD_MAX_PACKET_SIZE));
|
TU_VERIFY( usbd_edpt_xfer(rhport, usbtmc_state.ep_bulk_in, usbtmc_state.ep_bulk_in_buf,sizeof(usbtmc_state.devInBuffer)));
|
||||||
}
|
}
|
||||||
else // short packet
|
else // last packet
|
||||||
{
|
{
|
||||||
size_t packetLen = usbtmc_state.transfer_size_remaining;
|
size_t packetLen = usbtmc_state.transfer_size_remaining;
|
||||||
memcpy(usbtmc_state.ep_bulk_in_buf, usbtmc_state.devInBuffer, usbtmc_state.transfer_size_remaining);
|
memcpy(usbtmc_state.ep_bulk_in_buf, usbtmc_state.devInBuffer, usbtmc_state.transfer_size_remaining);
|
||||||
@@ -401,6 +511,7 @@ bool usbtmcd_control_request(uint8_t rhport, tusb_control_request_t const * requ
|
|||||||
(request->bRequest == TUSB_REQ_CLEAR_FEATURE) &&
|
(request->bRequest == TUSB_REQ_CLEAR_FEATURE) &&
|
||||||
(request->wValue == TUSB_REQ_FEATURE_EDPT_HALT))
|
(request->wValue == TUSB_REQ_FEATURE_EDPT_HALT))
|
||||||
{
|
{
|
||||||
|
uart_tx_str_sync("feature clear\r\n");
|
||||||
if((request->wIndex) == usbtmc_state.ep_bulk_out)
|
if((request->wIndex) == usbtmc_state.ep_bulk_out)
|
||||||
{
|
{
|
||||||
usmtmcd_app_bulkOut_clearFeature(rhport);
|
usmtmcd_app_bulkOut_clearFeature(rhport);
|
||||||
@@ -426,8 +537,6 @@ bool usbtmcd_control_request(uint8_t rhport, tusb_control_request_t const * requ
|
|||||||
// USBTMC required requests
|
// USBTMC required requests
|
||||||
case USBTMC_bREQUEST_INITIATE_ABORT_BULK_OUT:
|
case USBTMC_bREQUEST_INITIATE_ABORT_BULK_OUT:
|
||||||
case USBTMC_bREQUEST_CHECK_ABORT_BULK_OUT_STATUS:
|
case USBTMC_bREQUEST_CHECK_ABORT_BULK_OUT_STATUS:
|
||||||
case USBTMC_bREQUEST_INITIATE_ABORT_BULK_IN:
|
|
||||||
case USBTMC_bREQUEST_CHECK_ABORT_BULK_IN_STATUS:
|
|
||||||
{
|
{
|
||||||
TU_VERIFY(request->bmRequestType == 0xA2); // in,class,EP
|
TU_VERIFY(request->bmRequestType == 0xA2); // in,class,EP
|
||||||
TU_VERIFY(request->wLength == 1u);
|
TU_VERIFY(request->wLength == 1u);
|
||||||
@@ -435,14 +544,41 @@ bool usbtmcd_control_request(uint8_t rhport, tusb_control_request_t const * requ
|
|||||||
usbd_edpt_xfer(rhport, 0u, (void*)&tmcStatusCode,sizeof(tmcStatusCode));
|
usbd_edpt_xfer(rhport, 0u, (void*)&tmcStatusCode,sizeof(tmcStatusCode));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
case USBTMC_bREQUEST_CHECK_ABORT_BULK_IN_STATUS:
|
||||||
|
{
|
||||||
|
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));
|
||||||
|
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);
|
||||||
|
// 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)));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
case USBTMC_bREQUEST_INITIATE_CLEAR:
|
case USBTMC_bREQUEST_INITIATE_CLEAR:
|
||||||
{
|
{
|
||||||
|
uart_tx_str_sync("init clear\r\n");
|
||||||
TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface
|
TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface
|
||||||
TU_VERIFY(request->wLength == sizeof(tmcStatusCode));
|
TU_VERIFY(request->wLength == sizeof(tmcStatusCode));
|
||||||
// After receiving an INITIATE_CLEAR request, the device must Halt the Bulk-OUT endpoint, queue the
|
// After receiving an INITIATE_CLEAR request, the device must Halt the Bulk-OUT endpoint, queue the
|
||||||
// control endpoint response shown in Table 31, and clear all input buffers and output buffers.
|
// control endpoint response shown in Table 31, and clear all input buffers and output buffers.
|
||||||
usbd_edpt_stall(rhport, usbtmc_state.ep_bulk_out);
|
usbd_edpt_stall(rhport, usbtmc_state.ep_bulk_out);
|
||||||
|
usbtmc_state.transfer_size_remaining = 0;
|
||||||
|
usbtmc_state.state = STATE_CLEARING;
|
||||||
TU_VERIFY(usbtmcd_app_initiate_clear(rhport, &tmcStatusCode));
|
TU_VERIFY(usbtmcd_app_initiate_clear(rhport, &tmcStatusCode));
|
||||||
TU_VERIFY(tud_control_xfer(rhport, request, (void*)&tmcStatusCode,sizeof(tmcStatusCode)));
|
TU_VERIFY(tud_control_xfer(rhport, request, (void*)&tmcStatusCode,sizeof(tmcStatusCode)));
|
||||||
return true;
|
return true;
|
||||||
@@ -450,17 +586,31 @@ bool usbtmcd_control_request(uint8_t rhport, tusb_control_request_t const * requ
|
|||||||
|
|
||||||
case USBTMC_bREQUEST_CHECK_CLEAR_STATUS:
|
case USBTMC_bREQUEST_CHECK_CLEAR_STATUS:
|
||||||
{
|
{
|
||||||
usbtmc_get_clear_status_rsp_t clearStatusRsp = {0};
|
uart_tx_str_sync("check clear\r\n");
|
||||||
TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface
|
TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface
|
||||||
|
usbtmc_get_clear_status_rsp_t clearStatusRsp = {0};
|
||||||
TU_VERIFY(request->wLength == sizeof(clearStatusRsp));
|
TU_VERIFY(request->wLength == sizeof(clearStatusRsp));
|
||||||
TU_VERIFY(usbtmcd_app_get_clear_status(rhport, &clearStatusRsp));
|
|
||||||
|
|
||||||
|
if(usbd_edpt_busy(rhport, usbtmc_state.ep_bulk_in))
|
||||||
|
{
|
||||||
|
// Stuff stuck in TX buffer?
|
||||||
|
clearStatusRsp.bmClear.BulkInFifoBytes = 1;
|
||||||
|
clearStatusRsp.USBTMC_status = USBTMC_STATUS_PENDING;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Let app check if it's clear
|
||||||
|
TU_VERIFY(usbtmcd_app_get_clear_status(rhport, &clearStatusRsp));
|
||||||
|
}
|
||||||
|
if(clearStatusRsp.USBTMC_status == USBTMC_STATUS_SUCCESS)
|
||||||
|
usbtmc_state.state = STATE_IDLE;
|
||||||
TU_VERIFY(tud_control_xfer(rhport, request, (void*)&clearStatusRsp,sizeof(clearStatusRsp)));
|
TU_VERIFY(tud_control_xfer(rhport, request, (void*)&clearStatusRsp,sizeof(clearStatusRsp)));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
case USBTMC_bREQUEST_GET_CAPABILITIES:
|
case USBTMC_bREQUEST_GET_CAPABILITIES:
|
||||||
{
|
{
|
||||||
|
uart_tx_str_sync("get capabilities\r\n");
|
||||||
TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface
|
TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface
|
||||||
TU_VERIFY(request->wLength == sizeof(usbtmcd_app_capabilities));
|
TU_VERIFY(request->wLength == sizeof(usbtmcd_app_capabilities));
|
||||||
TU_VERIFY(tud_control_xfer(rhport, request, (void*)&usbtmcd_app_capabilities, sizeof(usbtmcd_app_capabilities)));
|
TU_VERIFY(tud_control_xfer(rhport, request, (void*)&usbtmcd_app_capabilities, sizeof(usbtmcd_app_capabilities)));
|
||||||
@@ -470,6 +620,7 @@ bool usbtmcd_control_request(uint8_t rhport, tusb_control_request_t const * requ
|
|||||||
|
|
||||||
case USBTMC_bREQUEST_INDICATOR_PULSE: // Optional
|
case USBTMC_bREQUEST_INDICATOR_PULSE: // Optional
|
||||||
{
|
{
|
||||||
|
uart_tx_str_sync("indicate\r\n");
|
||||||
TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface
|
TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface
|
||||||
TU_VERIFY(request->wLength == sizeof(tmcStatusCode));
|
TU_VERIFY(request->wLength == sizeof(tmcStatusCode));
|
||||||
TU_VERIFY(usbtmcd_app_capabilities.bmIntfcCapabilities.supportsIndicatorPulse);
|
TU_VERIFY(usbtmcd_app_capabilities.bmIntfcCapabilities.supportsIndicatorPulse);
|
||||||
@@ -482,6 +633,7 @@ bool usbtmcd_control_request(uint8_t rhport, tusb_control_request_t const * requ
|
|||||||
// USB488 required requests
|
// USB488 required requests
|
||||||
case USBTMC488_bREQUEST_READ_STATUS_BYTE:
|
case USBTMC488_bREQUEST_READ_STATUS_BYTE:
|
||||||
{
|
{
|
||||||
|
uart_tx_str_sync("read stb\r\n");
|
||||||
usbtmc_read_stb_rsp_488_t rsp;
|
usbtmc_read_stb_rsp_488_t rsp;
|
||||||
TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface
|
TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface
|
||||||
TU_VERIFY(request->wLength == sizeof(rsp)); // in,class,interface
|
TU_VERIFY(request->wLength == sizeof(rsp)); // in,class,interface
|
||||||
@@ -520,6 +672,7 @@ bool usbtmcd_control_request(uint8_t rhport, tusb_control_request_t const * requ
|
|||||||
case USBTMC488_bREQUEST_GO_TO_LOCAL:
|
case USBTMC488_bREQUEST_GO_TO_LOCAL:
|
||||||
case USBTMC488_bREQUEST_LOCAL_LOCKOUT:
|
case USBTMC488_bREQUEST_LOCAL_LOCKOUT:
|
||||||
{
|
{
|
||||||
|
uart_tx_str_sync("Unsupported REN/GTL/LLO\r\n");
|
||||||
TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface
|
TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface
|
||||||
TU_VERIFY(false);
|
TU_VERIFY(false);
|
||||||
return false;
|
return false;
|
||||||
@@ -527,6 +680,7 @@ bool usbtmcd_control_request(uint8_t rhport, tusb_control_request_t const * requ
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
uart_tx_str_sync("Default CTRL handler\r\n");
|
||||||
TU_VERIFY(false);
|
TU_VERIFY(false);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user