From 5ce7b147117826dd75c2d7b347df80b0177e7252 Mon Sep 17 00:00:00 2001 From: Tommie Gannert Date: Mon, 26 Feb 2024 11:41:50 +0100 Subject: [PATCH 1/6] 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. --- src/class/usbtmc/usbtmc.h | 25 +++++++++++++++++++++++++ src/class/usbtmc/usbtmc_device.c | 16 +++++++++++++++- src/class/usbtmc/usbtmc_device.h | 20 +++++++++++++++----- 3 files changed, 55 insertions(+), 6 deletions(-) diff --git a/src/class/usbtmc/usbtmc.h b/src/class/usbtmc/usbtmc.h index 090ab3c4ab..327de087c7 100644 --- a/src/class/usbtmc/usbtmc.h +++ b/src/class/usbtmc/usbtmc.h @@ -183,6 +183,23 @@ typedef 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 { USBTMC_STATUS_SUCCESS = 0x01, 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"); +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 { struct TU_ATTR_PACKED diff --git a/src/class/usbtmc/usbtmc_device.c b/src/class/usbtmc/usbtmc_device.c index 573654d58b..debe445fd2 100644 --- a/src/class/usbtmc/usbtmc_device.c +++ b/src/class/usbtmc/usbtmc_device.c @@ -240,6 +240,18 @@ bool tud_usbtmc_transmit_dev_msg_data( 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) { 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) { - // Good? + if (tud_usbtmc_notification_complete_cb) { + TU_VERIFY(tud_usbtmc_notification_complete_cb()); + } return true; } return false; diff --git a/src/class/usbtmc/usbtmc_device.h b/src/class/usbtmc/usbtmc_device.h index c1298ddb88..2f3c91dbdf 100644 --- a/src/class/usbtmc/usbtmc_device.h +++ b/src/class/usbtmc/usbtmc_device.h @@ -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_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 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, 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); @@ -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); void usbtmcd_init_cb(void); -/************************************************************ - * USBTMC Descriptor Templates - *************************************************************/ - - #endif /* CLASS_USBTMC_USBTMC_DEVICE_H_ */ From 9e674fa109348d97fb4280ac534be665f619a4d8 Mon Sep 17 00:00:00 2001 From: Tommie Gannert Date: Fri, 15 Mar 2024 15:02:13 +0100 Subject: [PATCH 2/6] [usbtmc] cast to uintptr_t to get rid of const for usbd_edpt_xfer. --- src/class/usbtmc/usbtmc_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/class/usbtmc/usbtmc_device.c b/src/class/usbtmc/usbtmc_device.c index debe445fd2..4092c37ea3 100644 --- a/src/class/usbtmc/usbtmc_device.c +++ b/src/class/usbtmc/usbtmc_device.c @@ -248,7 +248,7 @@ bool tud_usbtmc_transmit_notification_data(const void * data, size_t len) #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)); + TU_VERIFY(usbd_edpt_xfer(usbtmc_state.rhport, usbtmc_state.ep_int_in, (void *)(uintptr_t) data, len)); return true; } From 98e85a296deb89dbcc05033bda26e3c9581d535b Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Sat, 27 Apr 2024 17:09:05 +0200 Subject: [PATCH 3/6] bulk_in: copy buffer to ensure alignment correctness. --- src/class/usbtmc/usbtmc_device.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/class/usbtmc/usbtmc_device.c b/src/class/usbtmc/usbtmc_device.c index 4092c37ea3..81e9697323 100644 --- a/src/class/usbtmc/usbtmc_device.c +++ b/src/class/usbtmc/usbtmc_device.c @@ -552,9 +552,10 @@ bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint case STATE_TX_INITIATED: if(usbtmc_state.transfer_size_remaining >= sizeof(usbtmc_state.ep_bulk_in_buf)) { - // FIXME! This removes const below! + // Copy buffer to ensure alignment correctness + memcpy(usbtmc_state.ep_bulk_in_buf, usbtmc_state.devInBuffer, sizeof(usbtmc_state.ep_bulk_in_buf)); TU_VERIFY( usbd_edpt_xfer(rhport, usbtmc_state.ep_bulk_in, - (void*)(uintptr_t) usbtmc_state.devInBuffer, sizeof(usbtmc_state.ep_bulk_in_buf))); + usbtmc_state.ep_bulk_in_buf, sizeof(usbtmc_state.ep_bulk_in_buf))); usbtmc_state.devInBuffer += sizeof(usbtmc_state.ep_bulk_in_buf); usbtmc_state.transfer_size_remaining -= sizeof(usbtmc_state.ep_bulk_in_buf); usbtmc_state.transfer_size_sent += sizeof(usbtmc_state.ep_bulk_in_buf); From fdb431b5c70ff605eebda8988e1728e7118b4ab4 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Sat, 27 Apr 2024 17:12:00 +0200 Subject: [PATCH 4/6] Buffer int msg to ensure alignment and placement correctness. --- src/class/usbtmc/usbtmc_device.c | 18 +++++++++++++----- src/class/usbtmc/usbtmc_device.h | 17 ++++++----------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/class/usbtmc/usbtmc_device.c b/src/class/usbtmc/usbtmc_device.c index 81e9697323..59d9b184e7 100644 --- a/src/class/usbtmc/usbtmc_device.c +++ b/src/class/usbtmc/usbtmc_device.c @@ -86,6 +86,11 @@ tu_static char logMsg[150]; // imposes a minimum buffer size of 32 bytes. #define USBTMCD_BUFFER_SIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) +// Interrupt endpoint buffer size, default to 2 bytes as USB488 specification. +#ifndef CFG_TUD_USBTMC_INT_EP_SIZE +#define CFG_TUD_USBTMC_INT_EP_SIZE 2 +#endif + /* * The state machine does not allow simultaneous reading and writing. This is * consistent with USBTMC. @@ -124,13 +129,15 @@ typedef struct uint8_t ep_bulk_in; uint8_t ep_bulk_out; uint8_t ep_int_in; + uint32_t ep_bulk_in_wMaxPacketSize; + uint32_t ep_bulk_out_wMaxPacketSize; // IN buffer is only used for first packet, not the remainder // in order to deal with prepending header CFG_TUSB_MEM_ALIGN uint8_t ep_bulk_in_buf[USBTMCD_BUFFER_SIZE]; - uint32_t ep_bulk_in_wMaxPacketSize; // OUT buffer receives one packet at a time CFG_TUSB_MEM_ALIGN uint8_t ep_bulk_out_buf[USBTMCD_BUFFER_SIZE]; - uint32_t ep_bulk_out_wMaxPacketSize; + // Buffer int msg to ensure alignment and placement correctness + CFG_TUSB_MEM_ALIGN uint8_t ep_int_in_buf[CFG_TUD_USBTMC_INT_EP_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) @@ -243,12 +250,13 @@ bool tud_usbtmc_transmit_dev_msg_data( bool tud_usbtmc_transmit_notification_data(const void * data, size_t len) { #ifndef NDEBUG - TU_ASSERT(len >= 1); + TU_ASSERT(len > 0); 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_busy(usbtmc_state.rhport, usbtmc_state.ep_int_in)); - TU_VERIFY(usbd_edpt_xfer(usbtmc_state.rhport, usbtmc_state.ep_int_in, (void *)(uintptr_t) data, len)); + TU_VERIFY(tu_memcpy_s(usbtmc_state.ep_int_in_buf, sizeof(usbtmc_state.ep_int_in_buf), data, len) == 0); + TU_VERIFY(usbd_edpt_xfer(usbtmc_state.rhport, usbtmc_state.ep_int_in, usbtmc_state.ep_int_in_buf, len)); return true; } diff --git a/src/class/usbtmc/usbtmc_device.h b/src/class/usbtmc/usbtmc_device.h index 2f3c91dbdf..af7ea6ec9a 100644 --- a/src/class/usbtmc/usbtmc_device.h +++ b/src/class/usbtmc/usbtmc_device.h @@ -86,21 +86,16 @@ TU_ATTR_WEAK bool tud_usbtmc_msg_trigger_cb(usbtmc_msg_generic_t* msg); //TU_ATTR_WEAK bool tud_usbtmc_app_go_to_local_cb(); #endif -/******************************************* - * Called from app - * - * We keep a reference to the buffer, so it MUST not change until the app is - * notified that the transfer is complete. - ******************************************/ - +// Called from app +// +// We keep a reference to the buffer, so it MUST not change until the app is +// notified that the transfer is complete. bool tud_usbtmc_transmit_dev_msg_data( const void * data, size_t len, 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. +// Buffers a notification to be sent to the host. 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. From a018b229ba01d146f089e679524dfa72b92ec95a Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Sat, 27 Apr 2024 17:12:23 +0200 Subject: [PATCH 5/6] Update .gitignore. --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index e6ccec736e..56ae7600f1 100644 --- a/.gitignore +++ b/.gitignore @@ -57,6 +57,7 @@ hw/mcu/st/cmsis_device_f4 hw/mcu/st/cmsis_device_f7 hw/mcu/st/cmsis_device_g0 hw/mcu/st/cmsis_device_g4 +hw/mcu/st/cmsis_device_h5 hw/mcu/st/cmsis_device_h7 hw/mcu/st/cmsis_device_l0 hw/mcu/st/cmsis_device_l1 @@ -72,6 +73,7 @@ hw/mcu/st/stm32f4xx_hal_driver hw/mcu/st/stm32f7xx_hal_driver hw/mcu/st/stm32g0xx_hal_driver hw/mcu/st/stm32g4xx_hal_driver +hw/mcu/st/stm32h5xx_hal_driver hw/mcu/st/stm32h7xx_hal_driver hw/mcu/st/stm32l0xx_hal_driver hw/mcu/st/stm32l1xx_hal_driver From bd033a2d531d09478ddd947121e12aa6ece86d56 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Sat, 27 Apr 2024 17:24:19 +0200 Subject: [PATCH 6/6] Fix CI. --- src/class/usbtmc/usbtmc_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/class/usbtmc/usbtmc_device.c b/src/class/usbtmc/usbtmc_device.c index 59d9b184e7..f80abdaf33 100644 --- a/src/class/usbtmc/usbtmc_device.c +++ b/src/class/usbtmc/usbtmc_device.c @@ -256,7 +256,7 @@ bool tud_usbtmc_transmit_notification_data(const void * data, size_t len) TU_VERIFY(usbd_edpt_busy(usbtmc_state.rhport, usbtmc_state.ep_int_in)); TU_VERIFY(tu_memcpy_s(usbtmc_state.ep_int_in_buf, sizeof(usbtmc_state.ep_int_in_buf), data, len) == 0); - TU_VERIFY(usbd_edpt_xfer(usbtmc_state.rhport, usbtmc_state.ep_int_in, usbtmc_state.ep_int_in_buf, len)); + TU_VERIFY(usbd_edpt_xfer(usbtmc_state.rhport, usbtmc_state.ep_int_in, usbtmc_state.ep_int_in_buf, (uint16_t)len)); return true; }