This commit is contained in:
Nathan Conrad 2019-09-14 22:55:42 -04:00
parent e53e9bd4f0
commit c755aee7d0
4 changed files with 182 additions and 95 deletions

View File

@ -97,7 +97,9 @@ bool usbtmcd_app_msg_trigger(uint8_t rhport, usbtmc_msg_generic_t* msg) {
bool usbtmcd_app_msg_data(uint8_t rhport, void *data, size_t len, bool transfer_complete) bool usbtmcd_app_msg_data(uint8_t rhport, void *data, size_t len, bool transfer_complete)
{ {
(void)rhport; (void)rhport;
(void)transfer_complete;
// If transfer isn't finished, we just ignore it (for now)
if(transfer_complete && (len >=4) && !strncasecmp("*idn?",data,4)) { if(transfer_complete && (len >=4) && !strncasecmp("*idn?",data,4)) {
queryState = 1; queryState = 1;
} }
@ -107,26 +109,24 @@ bool usbtmcd_app_msg_data(uint8_t rhport, void *data, size_t len, bool transfer_
bool usbtmcd_app_msgBulkIn_complete(uint8_t rhport) bool usbtmcd_app_msgBulkIn_complete(uint8_t rhport)
{ {
(void)rhport; (void)rhport;
status &= (uint8_t)~(0x10u); // clear MAV
return true; return true;
} }
static uint8_t noQueryMsg[] = "ERR: No query\n";
bool usbtmcd_app_msgBulkIn_request(uint8_t rhport, usbtmc_msg_request_dev_dep_in const * request) bool usbtmcd_app_msgBulkIn_request(uint8_t rhport, usbtmc_msg_request_dev_dep_in const * request)
{ {
rspMsg.header.MsgID = request->header.MsgID, rspMsg.header.MsgID = request->header.MsgID,
rspMsg.header.bTag = request->header.bTag, rspMsg.header.bTag = request->header.bTag,
rspMsg.header.bTagInverse = request->header.bTagInverse; rspMsg.header.bTagInverse = request->header.bTagInverse;
if(queryState != 0)
{ TU_ASSERT(bulkInStarted == 0);
TU_ASSERT(bulkInStarted == 0); bulkInStarted = 1;
bulkInStarted = 1;
} // > If a USBTMC interface receives a Bulk-IN request prior to receiving a USBTMC command message
else // that expects a response, the device must NAK the request
{
rspMsg.TransferSize = sizeof(noQueryMsg)-1;
usbtmcd_transmit_dev_msg_data(rhport, &rspMsg, noQueryMsg);
}
// Always return true indicating not to stall the EP. // Always return true indicating not to stall the EP.
return true; return true;
} }
@ -157,12 +157,28 @@ void usbtmc_app_task_iter(void) {
bulkInStarted = 0; bulkInStarted = 0;
rspMsg.TransferSize = sizeof(idn)-1; rspMsg.TransferSize = sizeof(idn)-1;
usbtmcd_transmit_dev_msg_data(rhport, &rspMsg, idn); usbtmcd_transmit_dev_msg_data(rhport, &rspMsg, idn);
status &= ~(0x10u); // MAV // MAV is cleared in the transfer complete callback.
} }
break; break;
default:
TU_ASSERT(false,);
return;
} }
} }
bool usbtmcd_app_initiate_clear(uint8_t rhport, uint8_t *tmcResult) {
(void)rhport;
*tmcResult = USBTMC_STATUS_SUCCESS;
return true;
}
bool usbtmcd_app_get_clear_status(uint8_t rhport, usbtmc_get_clear_status_rsp_t *rsp) {
(void)rhport;
rsp->USBTMC_status = USBTMC_STATUS_SUCCESS;
rsp->bmClear.BulkInFifoBytes = 0u;
return true;
}
// Return status byte, but put the transfer result status code in the rspResult argument. // Return status byte, but put the transfer result status code in the rspResult argument.
uint8_t usbtmcd_app_get_stb(uint8_t rhport, uint8_t *tmcResult) uint8_t usbtmcd_app_get_stb(uint8_t rhport, uint8_t *tmcResult)
{ {

View File

@ -73,53 +73,67 @@ typedef struct TU_ATTR_PACKED
typedef struct TU_ATTR_PACKED { typedef struct TU_ATTR_PACKED {
usbtmc_msg_header_t header ; ///< Header usbtmc_msg_header_t header ; ///< Header
uint32_t TransferSize ; ///< Transfer size; LSB first uint32_t TransferSize ; ///< Transfer size; LSB first
struct { struct TU_ATTR_PACKED
uint8_t EOM : 1 ; ///< EOM set on last byte {
unsigned int EOM : 1 ; ///< EOM set on last byte
} bmTransferAttributes; } bmTransferAttributes;
uint8_t _reserved[3]; uint8_t _reserved[3];
} usbtmc_msg_request_dev_dep_out; } usbtmc_msg_request_dev_dep_out;
TU_VERIFY_STATIC(sizeof(usbtmc_msg_request_dev_dep_out) == 12u, "struct wrong length");
// Next 8 bytes are message-specific // Next 8 bytes are message-specific
typedef struct TU_ATTR_PACKED { typedef struct TU_ATTR_PACKED
{
usbtmc_msg_header_t header ; ///< Header usbtmc_msg_header_t header ; ///< Header
uint32_t TransferSize ; ///< Transfer size; LSB first uint32_t TransferSize ; ///< Transfer size; LSB first
struct { struct TU_ATTR_PACKED
uint8_t : 0; {
uint8_t TermCharEnabled : 1 ; ///< "The Bulk-IN transfer must terminate on the specified TermChar."; CAPABILITIES must list TermChar unsigned int TermCharEnabled : 1 ; ///< "The Bulk-IN transfer must terminate on the specified TermChar."; CAPABILITIES must list TermChar
} bmTransferAttributes; } bmTransferAttributes;
uint8_t TermChar; uint8_t TermChar;
uint8_t _reserved[2]; uint8_t _reserved[2];
} usbtmc_msg_request_dev_dep_in; } usbtmc_msg_request_dev_dep_in;
TU_VERIFY_STATIC(sizeof(usbtmc_msg_request_dev_dep_in) == 12u, "struct wrong length");
/* Bulk-in headers */ /* Bulk-in headers */
typedef struct TU_ATTR_PACKED typedef struct TU_ATTR_PACKED
{ {
usbtmc_msg_header_t header; usbtmc_msg_header_t header;
uint32_t TransferSize; uint32_t TransferSize;
struct { struct TU_ATTR_PACKED
{
uint8_t EOM: 1; ///< Last byte of transfer is the end of the message uint8_t EOM: 1; ///< Last byte of transfer is the end of the message
uint8_t UsingTermChar: 1; ///< Support TermChar && Request.TermCharEnabled && last char in transfer is TermChar uint8_t UsingTermChar: 1; ///< Support TermChar && Request.TermCharEnabled && last char in transfer is TermChar
} bmTransferAttributes; } bmTransferAttributes;
uint8_t _reserved[3]; uint8_t _reserved[3];
} usbtmc_msg_dev_dep_msg_in_header_t; } usbtmc_msg_dev_dep_msg_in_header_t;
TU_VERIFY_STATIC(sizeof(usbtmc_msg_dev_dep_msg_in_header_t) == 12u, "struct wrong length");
/* Unsupported vendor things.... Are these ever used?*/ /* Unsupported vendor things.... Are these ever used?*/
typedef struct TU_ATTR_PACKED { typedef struct TU_ATTR_PACKED
{
usbtmc_msg_header_t header ; ///< Header usbtmc_msg_header_t header ; ///< Header
uint32_t TransferSize ; ///< Transfer size; LSB first uint32_t TransferSize ; ///< Transfer size; LSB first
uint8_t _reserved[4]; uint8_t _reserved[4];
} usbtmc_msg_request_vendor_specific_out; } usbtmc_msg_request_vendor_specific_out;
typedef struct TU_ATTR_PACKED { TU_VERIFY_STATIC(sizeof(usbtmc_msg_request_vendor_specific_out) == 12u, "struct wrong length");
typedef struct TU_ATTR_PACKED
{
usbtmc_msg_header_t header ; ///< Header usbtmc_msg_header_t header ; ///< Header
uint32_t TransferSize ; ///< Transfer size; LSB first uint32_t TransferSize ; ///< Transfer size; LSB first
uint8_t _reserved[4]; uint8_t _reserved[4];
} usbtmc_msg_request_vendor_specific_in; } usbtmc_msg_request_vendor_specific_in;
TU_VERIFY_STATIC(sizeof(usbtmc_msg_request_vendor_specific_in) == 12u, "struct wrong length");
// Control request type should use tusb_control_request_t // Control request type should use tusb_control_request_t
/* /*
@ -187,13 +201,15 @@ typedef struct TU_ATTR_PACKED {
uint8_t _reserved; uint8_t _reserved;
uint16_t bcdUSBTMC; ///< USBTMC_VERSION uint16_t bcdUSBTMC; ///< USBTMC_VERSION
struct { struct TU_ATTR_PACKED
uint8_t listenOnly :1; {
uint8_t talkOnly :1; unsigned int listenOnly :1;
uint8_t supportsIndicatorPulse :1; unsigned int talkOnly :1;
unsigned int supportsIndicatorPulse :1;
} bmIntfcCapabilities; } bmIntfcCapabilities;
struct { struct TU_ATTR_PACKED
uint8_t canEndBulkInOnTermChar :1; {
unsigned int canEndBulkInOnTermChar :1;
} bmDevCapabilities; } bmDevCapabilities;
uint8_t _reserved2[6]; uint8_t _reserved2[6];
uint8_t _reserved3[12]; uint8_t _reserved3[12];
@ -201,40 +217,51 @@ typedef struct TU_ATTR_PACKED {
TU_VERIFY_STATIC(sizeof(usbtmc_response_capabilities_t) == 0x18, "struct wrong length"); TU_VERIFY_STATIC(sizeof(usbtmc_response_capabilities_t) == 0x18, "struct wrong length");
typedef struct TU_ATTR_PACKED
{
uint8_t USBTMC_status;
struct TU_ATTR_PACKED
{
unsigned int BulkInFifoBytes :1;
} bmClear;
} usbtmc_get_clear_status_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
uint8_t _reserved; uint8_t _reserved;
uint16_t bcdUSBTMC; ///< USBTMC_VERSION uint16_t bcdUSBTMC; ///< USBTMC_VERSION
struct struct TU_ATTR_PACKED
{ {
uint8_t listenOnly :1; unsigned int listenOnly :1;
uint8_t talkOnly :1; unsigned int talkOnly :1;
uint8_t supportsIndicatorPulse :1; unsigned int supportsIndicatorPulse :1;
} bmIntfcCapabilities; } bmIntfcCapabilities;
struct struct TU_ATTR_PACKED
{ {
uint8_t canEndBulkInOnTermChar :1; unsigned int canEndBulkInOnTermChar :1;
} bmDevCapabilities; } bmDevCapabilities;
uint8_t _reserved2[6]; uint8_t _reserved2[6];
uint16_t bcdUSB488; uint16_t bcdUSB488;
struct struct TU_ATTR_PACKED
{ {
uint8_t is488_2 :1; unsigned int is488_2 :1;
uint8_t supportsREN_GTL_LLO :1; unsigned int supportsREN_GTL_LLO :1;
uint8_t supportsTrigger :1; unsigned int supportsTrigger :1;
} bmIntfcCapabilities488; } bmIntfcCapabilities488;
struct struct TU_ATTR_PACKED
{ {
uint8_t SCPI :1; unsigned int SCPI :1;
uint8_t SR1 :1; unsigned int SR1 :1;
uint8_t RL1 :1; unsigned int RL1 :1;
uint8_t DT1 :1; unsigned int DT1 :1;
} bmDevCapabilities488; } bmDevCapabilities488;
uint8_t _reserved3[8]; uint8_t _reserved3[8];
} usbtmc_response_capabilities_488_t; } usbtmc_response_capabilities_488_t;
@ -253,14 +280,15 @@ TU_VERIFY_STATIC(sizeof(usbtmc_read_stb_rsp_488_t) == 3u, "struct wrong length")
typedef struct TU_ATTR_PACKET typedef struct TU_ATTR_PACKET
{ {
union { union {
struct { struct TU_ATTR_PACKED {
uint8_t bTag : 7; unsigned int bTag : 7;
uint8_t one : 1; unsigned int one : 1;
} bNotify1Struct; } bNotify1Struct;
uint8_t bNotify1; uint8_t bNotify1;
}; };
uint8_t StatusByte; uint8_t StatusByte;
} usbtmc_read_stb_interrupt_488_t; } usbtmc_read_stb_interrupt_488_t;
TU_VERIFY_STATIC(sizeof(usbtmc_read_stb_interrupt_488_t) == 2u, "struct wrong length"); TU_VERIFY_STATIC(sizeof(usbtmc_read_stb_interrupt_488_t) == 2u, "struct wrong length");
#endif #endif

View File

@ -170,6 +170,9 @@ bool usbtmcd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16
uint8_t const * p_desc; uint8_t const * p_desc;
uint8_t found_endpoints = 0; uint8_t found_endpoints = 0;
usbtmcd_reset(rhport);
// Perhaps there are other application specific class drivers, so don't assert here. // Perhaps there are other application specific class drivers, so don't assert here.
if( itf_desc->bInterfaceClass != USBTMC_APP_CLASS) if( itf_desc->bInterfaceClass != USBTMC_APP_CLASS)
return false; return false;
@ -232,6 +235,12 @@ bool usbtmcd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16
void usbtmcd_reset(uint8_t rhport) void usbtmcd_reset(uint8_t rhport)
{ {
// FIXME: Do endpoints need to be closed here? // FIXME: Do endpoints need to be closed here?
usbtmc_state.state = STATE_IDLE;
usbtmc_state.itf_id = 0xFF;
usbtmc_state.ep_bulk_in = 0;
usbtmc_state.ep_bulk_out = 0;
usbtmc_state.ep_int_in = 0;
(void)rhport; (void)rhport;
} }
@ -376,15 +385,19 @@ bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint
bool usbtmcd_control_request(uint8_t rhport, tusb_control_request_t const * request) { bool usbtmcd_control_request(uint8_t rhport, tusb_control_request_t const * request) {
uint8_t tmcStatusCode = USBTMC_STATUS_FAILED;
#if (USBTMC_CFG_ENABLE_488) #if (USBTMC_CFG_ENABLE_488)
ushort bTag; ushort bTag;
#endif #endif
// We only handle class requests, IN direction. // We only handle class requests, IN direction.
// (for now)
if(request->bmRequestType_bit.type != TUSB_REQ_TYPE_CLASS) if(request->bmRequestType_bit.type != TUSB_REQ_TYPE_CLASS)
{ {
return false; return false;
} }
// Verification that we own the interface is unneeded since it's been routed to us specifically.
switch(request->bRequest) switch(request->bRequest)
{ {
// USBTMC required requests // USBTMC required requests
@ -392,74 +405,100 @@ bool usbtmcd_control_request(uint8_t rhport, tusb_control_request_t const * requ
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_INITIATE_ABORT_BULK_IN:
case USBTMC_bREQUEST_CHECK_ABORT_BULK_IN_STATUS: case USBTMC_bREQUEST_CHECK_ABORT_BULK_IN_STATUS:
TU_VERIFY(request->bmRequestType == 0xA2); // in,class,EP {
TU_VERIFY(false); TU_VERIFY(request->bmRequestType == 0xA2); // in,class,EP
break; TU_VERIFY(request->wLength == 1u);
tmcStatusCode = USBTMC_STATUS_FAILED;
usbd_edpt_xfer(rhport, usbtmc_state.ep_int_in, (void*)&tmcStatusCode,sizeof(tmcStatusCode));
return true;
}
case USBTMC_bREQUEST_INITIATE_CLEAR: case USBTMC_bREQUEST_INITIATE_CLEAR:
{
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
// control endpoint response shown in Table 31, and clear all input buffers and output buffers.
usbd_edpt_stall(rhport, usbtmc_state.ep_bulk_out);
TU_VERIFY(usbtmcd_app_initiate_clear(rhport, &tmcStatusCode));
TU_VERIFY(usbd_edpt_xfer(rhport, usbtmc_state.ep_int_in, (void*)&tmcStatusCode,sizeof(tmcStatusCode)));
return true;
}
case USBTMC_bREQUEST_CHECK_CLEAR_STATUS: case USBTMC_bREQUEST_CHECK_CLEAR_STATUS:
TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface {
TU_VERIFY(false); usbtmc_get_clear_status_rsp_t clearStatusRsp = {0};
break; TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface
TU_VERIFY(request->wLength == sizeof(clearStatusRsp));
TU_VERIFY(usbtmcd_app_get_clear_status(rhport, &clearStatusRsp));
TU_VERIFY(usbd_edpt_xfer(rhport, usbtmc_state.ep_int_in, (void*)&clearStatusRsp,sizeof(clearStatusRsp)));
return true;
}
case USBTMC_bREQUEST_GET_CAPABILITIES: case USBTMC_bREQUEST_GET_CAPABILITIES:
TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface {
TU_VERIFY(request->wValue == 0x0000); TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface
TU_VERIFY(request->wIndex == usbtmc_state.itf_id); 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))); return true;
return true; }
// USBTMC Optional Requests // USBTMC Optional Requests
case USBTMC_bREQUEST_INDICATOR_PULSE: // Optional case USBTMC_bREQUEST_INDICATOR_PULSE: // Optional
TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface {
TU_VERIFY(usbtmcd_app_capabilities.bmIntfcCapabilities.supportsIndicatorPulse); TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface
uint8_t tmcResult; TU_VERIFY(request->wLength == sizeof(tmcStatusCode));
TU_VERIFY(usbtmcd_app_indicator_pluse(rhport, request, &tmcResult)); TU_VERIFY(usbtmcd_app_capabilities.bmIntfcCapabilities.supportsIndicatorPulse);
TU_VERIFY(tud_control_xfer(rhport, request, (void*)&tmcResult, sizeof(tmcResult))); TU_VERIFY(usbtmcd_app_indicator_pluse(rhport, request, &tmcStatusCode));
TU_VERIFY(tud_control_xfer(rhport, request, (void*)&tmcStatusCode, sizeof(tmcStatusCode)));
return true; return true;
}
#if (USBTMC_CFG_ENABLE_488) #if (USBTMC_CFG_ENABLE_488)
// USB488 required requests // USB488 required requests
case USBTMC488_bREQUEST_READ_STATUS_BYTE: case USBTMC488_bREQUEST_READ_STATUS_BYTE:
TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface
bTag = request->wValue & 0x7F;
TU_VERIFY(request->bmRequestType == 0xA1);
TU_VERIFY((request->wValue & (~0x7F)) == 0u); // Other bits are required to be zero
TU_VERIFY(bTag >= 0x02 && bTag <= 127);
TU_VERIFY(request->wIndex == usbtmc_state.itf_id);
TU_VERIFY(request->wLength == 0x0003);
usbtmc_read_stb_rsp_488_t rsp;
rsp.bTag = (uint8_t)bTag;
if(usbtmc_state.ep_int_in != 0)
{ {
rsp.USBTMC_status = USBTMC_STATUS_SUCCESS; usbtmc_read_stb_rsp_488_t rsp;
rsp.statusByte = 0x00; // Use interrupt endpoint, instead. TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface
TU_VERIFY(request->wLength == sizeof(rsp)); // in,class,interface
usbtmc_read_stb_interrupt_488_t intMsg = bTag = request->wValue & 0x7F;
TU_VERIFY(request->bmRequestType == 0xA1);
TU_VERIFY((request->wValue & (~0x7F)) == 0u); // Other bits are required to be zero
TU_VERIFY(bTag >= 0x02 && bTag <= 127);
TU_VERIFY(request->wIndex == usbtmc_state.itf_id);
TU_VERIFY(request->wLength == 0x0003);
rsp.bTag = (uint8_t)bTag;
if(usbtmc_state.ep_int_in != 0)
{ {
.bNotify1 = (uint8_t)(0x80 | bTag), rsp.USBTMC_status = USBTMC_STATUS_SUCCESS;
.StatusByte = usbtmcd_app_get_stb(rhport, &(rsp.USBTMC_status)) rsp.statusByte = 0x00; // Use interrupt endpoint, instead.
};
usbd_edpt_xfer(rhport, usbtmc_state.ep_int_in, (void*)&intMsg,sizeof(intMsg));
} usbtmc_read_stb_interrupt_488_t intMsg =
else {
{ .bNotify1 = (uint8_t)(0x80 | bTag),
rsp.statusByte = usbtmcd_app_get_stb(rhport, &(rsp.USBTMC_status)); .StatusByte = usbtmcd_app_get_stb(rhport, &(rsp.USBTMC_status))
} };
TU_VERIFY(tud_control_xfer(rhport, request, (void*)&rsp, sizeof(rsp))); usbd_edpt_xfer(rhport, usbtmc_state.ep_int_in, (void*)&intMsg,sizeof(intMsg));
return true;
}
else
{
rsp.statusByte = usbtmcd_app_get_stb(rhport, &(rsp.USBTMC_status));
}
TU_VERIFY(tud_control_xfer(rhport, request, (void*)&rsp, sizeof(rsp)));
return true;
}
// USB488 optional requests // USB488 optional requests
case USBTMC488_bREQUEST_REN_CONTROL: case USBTMC488_bREQUEST_REN_CONTROL:
case USBTMC488_bREQUEST_GO_TO_LOCAL: case USBTMC488_bREQUEST_GO_TO_LOCAL:
case USBTMC488_bREQUEST_LOCAL_LOCKOUT: case USBTMC488_bREQUEST_LOCAL_LOCKOUT:
TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface {
TU_VERIFY(false); TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface
return false; TU_VERIFY(false);
return false;
}
#endif #endif
default: default:

View File

@ -64,6 +64,10 @@ bool usbtmcd_app_msgBulkIn_request(uint8_t rhport, usbtmc_msg_request_dev_dep_in
bool usbtmcd_app_msgBulkIn_complete(uint8_t rhport); bool usbtmcd_app_msgBulkIn_complete(uint8_t rhport);
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);
// Indicator pulse should be 0.5 to 1.0 seconds long // 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); TU_ATTR_WEAK bool usbtmcd_app_indicator_pluse(uint8_t rhport, tusb_control_request_t const * msg, uint8_t *tmcResult);