add notification support for device class USBTMC.

The ep_int_in is already used for responding to USB488
READ_STATUS_BYTE requests, but that EP is defined for all of USBTMC.
This extends the functionality to let callers send notifications and
receive ACKs.
This commit is contained in:
Tommie Gannert 2024-02-26 11:41:50 +01:00
parent f92c2c2758
commit 5ce7b14711
3 changed files with 55 additions and 6 deletions

View File

@ -183,6 +183,23 @@ typedef enum {
} usmtmc_request_type_enum; } usmtmc_request_type_enum;
typedef enum {
// The last and first valid bNotify1 for use by the USBTMC class specification.
USBTMC_bNOTIFY1_USBTMC_FIRST = 0x00,
USBTMC_bNOTIFY1_USBTMC_LAST = 0x3F,
// The last and first valid bNotify1 for use by vendors.
USBTMC_bNOTIFY1_VENDOR_SPECIFIC_FIRST = 0x40,
USBTMC_bNOTIFY1_VENDOR_SPECIFIC_LAST = 0x7F,
// The last and first valid bNotify1 for use by USBTMC subclass specifications.
USBTMC_bNOTIFY1_SUBCLASS_FIRST = 0x80,
USBTMC_bNOTIFY1_SUBCLASS_LAST = 0xFF,
// From the USB488 Subclass Specification, Section 3.4.
USB488_bNOTIFY1_SRQ = 0x81,
} usbtmc_int_in_payload_format;
typedef enum { typedef enum {
USBTMC_STATUS_SUCCESS = 0x01, USBTMC_STATUS_SUCCESS = 0x01,
USBTMC_STATUS_PENDING = 0x02, USBTMC_STATUS_PENDING = 0x02,
@ -303,6 +320,14 @@ typedef struct TU_ATTR_PACKED
TU_VERIFY_STATIC(sizeof(usbtmc_read_stb_rsp_488_t) == 3u, "struct wrong length"); TU_VERIFY_STATIC(sizeof(usbtmc_read_stb_rsp_488_t) == 3u, "struct wrong length");
typedef struct TU_ATTR_PACKED
{
uint8_t bNotify1; // Must be USB488_bNOTIFY1_SRQ
uint8_t StatusByte;
} usbtmc_srq_interrupt_488_t;
TU_VERIFY_STATIC(sizeof(usbtmc_srq_interrupt_488_t) == 2u, "struct wrong length");
typedef struct TU_ATTR_PACKED typedef struct TU_ATTR_PACKED
{ {
struct TU_ATTR_PACKED struct TU_ATTR_PACKED

View File

@ -240,6 +240,18 @@ bool tud_usbtmc_transmit_dev_msg_data(
return true; return true;
} }
bool tud_usbtmc_transmit_notification_data(const void * data, size_t len)
{
#ifndef NDEBUG
TU_ASSERT(len >= 1);
TU_ASSERT(usbtmc_state.ep_int_in != 0);
#endif
if (usbd_edpt_busy(usbtmc_state.rhport, usbtmc_state.ep_int_in)) return false;
TU_VERIFY(usbd_edpt_xfer(usbtmc_state.rhport, usbtmc_state.ep_int_in, (void *)data, len));
return true;
}
void usbtmcd_init_cb(void) void usbtmcd_init_cb(void)
{ {
usbtmc_state.capabilities = tud_usbtmc_get_capabilities_cb(); usbtmc_state.capabilities = tud_usbtmc_get_capabilities_cb();
@ -578,7 +590,9 @@ bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint
} }
} }
else if (ep_addr == usbtmc_state.ep_int_in) { else if (ep_addr == usbtmc_state.ep_int_in) {
// Good? if (tud_usbtmc_notification_complete_cb) {
TU_VERIFY(tud_usbtmc_notification_complete_cb());
}
return true; return true;
} }
return false; return false;

View File

@ -73,6 +73,10 @@ bool tud_usbtmc_check_abort_bulk_in_cb(usbtmc_check_abort_bulk_rsp_t *rsp);
bool tud_usbtmc_check_abort_bulk_out_cb(usbtmc_check_abort_bulk_rsp_t *rsp); bool tud_usbtmc_check_abort_bulk_out_cb(usbtmc_check_abort_bulk_rsp_t *rsp);
bool tud_usbtmc_check_clear_cb(usbtmc_get_clear_status_rsp_t *rsp); bool tud_usbtmc_check_clear_cb(usbtmc_get_clear_status_rsp_t *rsp);
// The interrupt-IN endpoint buffer was transmitted to the host. Use
// tud_usbtmc_transmit_notification_data to send another notification.
TU_ATTR_WEAK bool tud_usbtmc_notification_complete_cb(void);
// 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 tud_usbtmc_indicator_pulse_cb(tusb_control_request_t const * msg, uint8_t *tmcResult); TU_ATTR_WEAK bool tud_usbtmc_indicator_pulse_cb(tusb_control_request_t const * msg, uint8_t *tmcResult);
@ -93,6 +97,17 @@ bool tud_usbtmc_transmit_dev_msg_data(
const void * data, size_t len, const void * data, size_t len,
bool endOfMessage, bool usingTermChar); bool endOfMessage, bool usingTermChar);
// Buffers a notification to be sent to the host. The buffer must be
// valid until the tud_usbtmc_notification_complete_cb callback. The
// data starts with the bNotify1 field, see the USBTMC Specification,
// Table 13.
//
// If the previous notification data has not yet been sent, this
// returns false.
//
// Requires an interrupt endpoint in the interface.
bool tud_usbtmc_transmit_notification_data(const void * data, size_t len);
bool tud_usbtmc_start_bus_read(void); bool tud_usbtmc_start_bus_read(void);
@ -104,9 +119,4 @@ bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result,
bool usbtmcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); bool usbtmcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request);
void usbtmcd_init_cb(void); void usbtmcd_init_cb(void);
/************************************************************
* USBTMC Descriptor Templates
*************************************************************/
#endif /* CLASS_USBTMC_USBTMC_DEVICE_H_ */ #endif /* CLASS_USBTMC_USBTMC_DEVICE_H_ */