summaryrefslogtreecommitdiff
path: root/src/class
diff options
context:
space:
mode:
authorHa Thach <[email protected]>2022-11-04 15:42:50 +0700
committerGitHub <[email protected]>2022-11-04 15:42:50 +0700
commitb554c2ed836527296dd0b79169db04fc2f68cf5a (patch)
tree34b25122fac701370b5883b7a878b6a7d92fd76f /src/class
parent35668fc523c7c972bf91f32dbb3b50ad8b4f3c74 (diff)
parent28f49c088bb0c498d730d80943017172061cfd05 (diff)
Merge branch 'master' into rp2040-hcd-bulk
Diffstat (limited to 'src/class')
-rw-r--r--src/class/audio/audio_device.c291
-rw-r--r--src/class/audio/audio_device.h64
-rwxr-xr-xsrc/class/bth/bth_device.c6
-rw-r--r--src/class/cdc/cdc_device.c10
-rw-r--r--src/class/cdc/cdc_host.c8
-rw-r--r--src/class/dfu/dfu_device.c2
-rw-r--r--src/class/hid/hid_device.c20
-rw-r--r--src/class/hid/hid_device.h8
-rw-r--r--src/class/hid/hid_host.c9
-rw-r--r--src/class/midi/midi_device.c16
-rw-r--r--src/class/msc/msc_device.c35
-rw-r--r--src/class/msc/msc_host.c8
-rw-r--r--src/class/net/ecm_rndis_device.c16
-rw-r--r--src/class/net/ncm_device.c9
-rw-r--r--src/class/usbtmc/usbtmc.h5
-rw-r--r--src/class/usbtmc/usbtmc_device.c82
-rw-r--r--src/class/usbtmc/usbtmc_device.h4
-rw-r--r--src/class/vendor/vendor_device.c22
-rw-r--r--src/class/video/video.h79
-rw-r--r--src/class/video/video_device.c219
20 files changed, 691 insertions, 222 deletions
diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c
index 06979b09e..698fba566 100644
--- a/src/class/audio/audio_device.c
+++ b/src/class/audio/audio_device.c
@@ -66,7 +66,7 @@
// Use ring buffer if it's available, some MCUs need extra RAM requirements
#ifndef TUD_AUDIO_PREFER_RING_BUFFER
-#if CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX
+#if CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT
#define TUD_AUDIO_PREFER_RING_BUFFER 0
#else
#define TUD_AUDIO_PREFER_RING_BUFFER 1
@@ -102,7 +102,7 @@
CFG_TUSB_MCU == OPT_MCU_GD32VF103 || \
CFG_TUSB_MCU == OPT_MCU_LPC18XX || \
CFG_TUSB_MCU == OPT_MCU_LPC43XX || \
- CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX || \
+ CFG_TUSB_MCU == OPT_MCU_MIMXRT || \
CFG_TUSB_MCU == OPT_MCU_MSP432E4
#if TUD_AUDIO_PREFER_RING_BUFFER
#define USE_LINEAR_BUFFER 0
@@ -305,9 +305,35 @@ typedef struct
#endif
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
- uint32_t fb_val; // Feedback value for asynchronous mode (in 16.16 format).
-#endif
+ struct {
+ uint32_t value; // Feedback value for asynchronous mode (in 16.16 format).
+ uint32_t min_value; // min value according to UAC2 FMT-2.0 section 2.3.1.1.
+ uint32_t max_value; // max value according to UAC2 FMT-2.0 section 2.3.1.1.
+
+ uint8_t frame_shift; // bInterval-1 in unit of frame (FS), micro-frame (HS)
+ uint8_t compute_method;
+
+ union {
+ uint8_t power_of_2; // pre-computed power of 2 shift
+ float float_const; // pre-computed float constant
+
+ struct {
+ uint32_t sample_freq;
+ uint32_t mclk_freq;
+ }fixed;
+
+#if 0 // implement later
+ struct {
+ uint32_t nominal_value;
+ uint32_t threshold_bytes;
+ }fifo_count;
#endif
+ }compute;
+
+ } feedback;
+#endif // CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
+
+#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT
#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
tu_fifo_t ep_in_ff;
@@ -315,7 +341,7 @@ typedef struct
// Audio control interrupt buffer - no FIFO - 6 Bytes according to UAC 2 specification (p. 74)
#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
- CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ep_int_ctr_buf[CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE];
+ CFG_TUSB_MEM_ALIGN uint8_t ep_int_ctr_buf[CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE];
#endif
// Decoding parameters - parameters are set when alternate AS interface is set by host
@@ -421,6 +447,10 @@ static inline uint8_t tu_desc_subtype(void const* desc)
}
#endif
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
+static bool set_fb_params_freq(audiod_function_t* audio, uint32_t sample_freq, uint32_t mclk_freq);
+#endif
+
bool tud_audio_n_mounted(uint8_t func_id)
{
TU_VERIFY(func_id < CFG_TUD_AUDIO);
@@ -511,7 +541,7 @@ tu_fifo_t* tud_audio_n_get_rx_support_ff(uint8_t func_id, uint8_t ff_idx)
static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t* audio, uint16_t n_bytes_received)
{
- uint8_t idxItf;
+ uint8_t idxItf = 0;
uint8_t const *dummy2;
uint8_t idx_audio_fct = 0;
@@ -522,7 +552,10 @@ static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t* audio, uint16_t
}
// Call a weak callback here - a possibility for user to get informed an audio packet was received and data gets now loaded into EP FIFO (or decoded into support RX software FIFO)
- if (tud_audio_rx_done_pre_read_cb) TU_VERIFY(tud_audio_rx_done_pre_read_cb(rhport, n_bytes_received, idx_audio_fct, audio->ep_out, audio->alt_setting[idxItf]));
+ if (tud_audio_rx_done_pre_read_cb)
+ {
+ TU_VERIFY(tud_audio_rx_done_pre_read_cb(rhport, n_bytes_received, idx_audio_fct, audio->ep_out, audio->alt_setting[idxItf]));
+ }
#if CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT
@@ -536,7 +569,7 @@ static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t* audio, uint16_t
case AUDIO_FORMAT_TYPE_I:
- switch (audio->format_type_I_tx)
+ switch (audio->format_type_I_rx)
{
case AUDIO_DATA_FORMAT_TYPE_I_PCM:
TU_VERIFY(audiod_decode_type_I_pcm(rhport, audio, n_bytes_received));
@@ -576,7 +609,10 @@ static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t* audio, uint16_t
#endif
// Call a weak callback here - a possibility for user to get informed decoding was completed
- if (tud_audio_rx_done_post_read_cb) TU_VERIFY(tud_audio_rx_done_post_read_cb(rhport, n_bytes_received, idx_audio_fct, audio->ep_out, audio->alt_setting[idxItf]));
+ if (tud_audio_rx_done_post_read_cb)
+ {
+ TU_VERIFY(tud_audio_rx_done_post_read_cb(rhport, n_bytes_received, idx_audio_fct, audio->ep_out, audio->alt_setting[idxItf]));
+ }
return true;
}
@@ -1039,7 +1075,7 @@ static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audi
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
static inline bool audiod_fb_send(uint8_t rhport, audiod_function_t *audio)
{
- return usbd_edpt_xfer(rhport, audio->ep_fb, (uint8_t *) &audio->fb_val, 4);
+ return usbd_edpt_xfer(rhport, audio->ep_fb, (uint8_t *) &audio->feedback.value, 4);
}
#endif
@@ -1510,7 +1546,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
tu_fifo_clear(&audio->tx_supp_ff[cnt]);
}
#endif
-
+
// Invoke callback - can be used to stop data sampling
if (tud_audio_set_itf_close_EP_cb) TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request));
@@ -1543,7 +1579,8 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
// Close corresponding feedback EP
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
usbd_edpt_close(rhport, audio->ep_fb);
- audio->ep_fb = 0; // Necessary?
+ audio->ep_fb = 0;
+ tu_memclr(&audio->feedback, sizeof(audio->feedback));
#endif
}
#endif
@@ -1592,7 +1629,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
// Reconfigure size of support FIFOs - this is necessary to avoid samples to get split in case of a wrap
#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING
- const uint16_t active_fifo_depth = (audio->tx_supp_ff_sz_max / audio->n_bytes_per_sampe_tx) * audio->n_bytes_per_sampe_tx;
+ const uint16_t active_fifo_depth = (uint16_t) ((audio->tx_supp_ff_sz_max / audio->n_bytes_per_sampe_tx) * audio->n_bytes_per_sampe_tx);
for (uint8_t cnt = 0; cnt < audio->n_tx_supp_ff; cnt++)
{
tu_fifo_config(&audio->tx_supp_ff[cnt], audio->tx_supp_ff[cnt].buffer, active_fifo_depth, 1, true);
@@ -1602,8 +1639,6 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
#endif
#endif
- // Invoke callback - can be used to trigger data sampling if not already running
- if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request));
// Schedule first transmit if alternate interface is not zero i.e. streaming is disabled - in case no sample data is available a ZLP is loaded
// It is necessary to trigger this here since the refill is done with an RX FIFO empty interrupt which can only trigger if something was in there
@@ -1635,16 +1670,6 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
#endif
#endif
-#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
- // In case of asynchronous EP, call Cb after ep_fb is set
- if ( !(desc_ep->bmAttributes.sync == 0x01 && audio->ep_fb == 0) )
- {
- if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request));
- }
-#else
- // Invoke callback
- if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request));
-#endif
// Prepare for incoming data
#if USE_LINEAR_BUFFER_RX
TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, audio->lin_buf_out, audio->ep_out_sz), false);
@@ -1657,12 +1682,10 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && desc_ep->bmAttributes.usage == 1) // Check if usage is explicit data feedback
{
audio->ep_fb = ep_addr;
+ audio->feedback.frame_shift = desc_ep->bInterval -1;
- // Invoke callback after ep_out is set
- if (audio->ep_out != 0)
- {
- if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request));
- }
+ // Enable SOF interrupt if callback is implemented
+ if (tud_audio_feedback_interval_isr) usbd_sof_enable(rhport, true);
}
#endif
#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT
@@ -1674,6 +1697,49 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
TU_VERIFY(foundEPs == nEps);
+ // Invoke one callback for a final set interface
+ if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request));
+
+#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
+ // Prepare feedback computation if callback is available
+ if (tud_audio_feedback_params_cb)
+ {
+ audio_feedback_params_t fb_param;
+
+ tud_audio_feedback_params_cb(func_id, alt, &fb_param);
+ audio->feedback.compute_method = fb_param.method;
+
+ // Minimal/Maximum value in 16.16 format for full speed (1ms per frame) or high speed (125 us per frame)
+ uint32_t const frame_div = (TUSB_SPEED_FULL == tud_speed_get()) ? 1000 : 8000;
+ audio->feedback.min_value = (fb_param.sample_freq/frame_div - 1) << 16;
+ audio->feedback.max_value = (fb_param.sample_freq/frame_div + 1) << 16;
+
+ switch(fb_param.method)
+ {
+ case AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED:
+ case AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT:
+ case AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2:
+ set_fb_params_freq(audio, fb_param.sample_freq, fb_param.frequency.mclk_freq);
+ break;
+
+ #if 0 // implement later
+ case AUDIO_FEEDBACK_METHOD_FIFO_COUNT:
+ {
+ uint64_t fb64 = ((uint64_t) fb_param.sample_freq) << 16;
+ audio->feedback.compute.fifo_count.nominal_value = (uint32_t) (fb64 / frame_div);
+ audio->feedback.compute.fifo_count.threshold_bytes = fb_param.fifo_count.threshold_bytes;
+
+ tud_audio_fb_set(audio->feedback.compute.fifo_count.nominal_value);
+ }
+ break;
+ #endif
+
+ // nothing to do
+ default: break;
+ }
+ }
+#endif
+
// We are done - abort loop
break;
}
@@ -1682,6 +1748,20 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
p_desc = tu_desc_next(p_desc);
}
+#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
+ // Disable SOF interrupt if no driver has any enabled feedback EP
+ bool disable = true;
+ for(uint8_t i=0; i < CFG_TUD_AUDIO; i++)
+ {
+ if (_audiod_fct[i].ep_fb != 0)
+ {
+ disable = false;
+ break;
+ }
+ }
+ if (disable) usbd_sof_enable(rhport, false);
+#endif
+
tud_control_status(rhport, p_request);
return true;
@@ -1898,14 +1978,14 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3
(void) xferred_bytes;
// Search for interface belonging to given end point address and proceed as required
- uint8_t func_id;
- for (func_id = 0; func_id < CFG_TUD_AUDIO; func_id++)
+ for (uint8_t func_id = 0; func_id < CFG_TUD_AUDIO; func_id++)
{
+ audiod_function_t* audio = &_audiod_fct[func_id];
#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
// Data transmission of control interrupt finished
- if (_audiod_fct[func_id].ep_int_ctr == ep_addr)
+ if (audio->ep_int_ctr == ep_addr)
{
// According to USB2 specification, maximum payload of interrupt EP is 8 bytes on low speed, 64 bytes on full speed, and 1024 bytes on high speed (but only if an alternate interface other than 0 is used - see specification p. 49)
// In case there is nothing to send we have to return a NAK - this is taken care of by PHY ???
@@ -1922,7 +2002,7 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3
#if CFG_TUD_AUDIO_ENABLE_EP_IN
// Data transmission of audio packet finished
- if (_audiod_fct[func_id].ep_in == ep_addr && _audiod_fct[func_id].alt_setting != 0)
+ if (audio->ep_in == ep_addr && audio->alt_setting != 0)
{
// USB 2.0, section 5.6.4, third paragraph, states "An isochronous endpoint must specify its required bus access period. However, an isochronous endpoint must be prepared to handle poll rates faster than the one specified."
// That paragraph goes on to say "An isochronous IN endpoint must return a zero-length packet whenever data is requested at a faster interval than the specified interval and data is not available."
@@ -1933,7 +2013,7 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3
// This is the only place where we can fill something into the EPs buffer!
// Load new data
- TU_VERIFY(audiod_tx_done_cb(rhport, &_audiod_fct[func_id]));
+ TU_VERIFY(audiod_tx_done_cb(rhport, audio));
// Transmission of ZLP is done by audiod_tx_done_cb()
return true;
@@ -1943,24 +2023,24 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3
#if CFG_TUD_AUDIO_ENABLE_EP_OUT
// New audio packet received
- if (_audiod_fct[func_id].ep_out == ep_addr)
+ if (audio->ep_out == ep_addr)
{
- TU_VERIFY(audiod_rx_done_cb(rhport, &_audiod_fct[func_id], (uint16_t) xferred_bytes));
+ TU_VERIFY(audiod_rx_done_cb(rhport, audio, (uint16_t) xferred_bytes));
return true;
}
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
// Transmission of feedback EP finished
- if (_audiod_fct[func_id].ep_fb == ep_addr)
+ if (audio->ep_fb == ep_addr)
{
- if (tud_audio_fb_done_cb) TU_VERIFY(tud_audio_fb_done_cb(rhport));
+ if (tud_audio_fb_done_cb) tud_audio_fb_done_cb(func_id);
// Schedule a transmit with the new value if EP is not busy
- if (!usbd_edpt_busy(rhport, _audiod_fct[func_id].ep_fb))
+ if (!usbd_edpt_busy(rhport, audio->ep_fb))
{
// Schedule next transmission - value is changed bytud_audio_n_fb_set() in the meantime or the old value gets sent
- return audiod_fb_send(rhport, &_audiod_fct[func_id]);
+ return audiod_fb_send(rhport, audio);
}
}
#endif
@@ -1970,6 +2050,111 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3
return false;
}
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
+
+static bool set_fb_params_freq(audiod_function_t* audio, uint32_t sample_freq, uint32_t mclk_freq)
+{
+ // Check if frame interval is within sane limits
+ // The interval value n_frames was taken from the descriptors within audiod_set_interface()
+
+ // n_frames_min is ceil(2^10 * f_s / f_m) for full speed and ceil(2^13 * f_s / f_m) for high speed
+ // this lower limit ensures the measures feedback value has sufficient precision
+ uint32_t const k = (TUSB_SPEED_FULL == tud_speed_get()) ? 10 : 13;
+ uint32_t const n_frame = (1UL << audio->feedback.frame_shift);
+
+ if ( (((1UL << k) * sample_freq / mclk_freq) + 1) > n_frame )
+ {
+ TU_LOG1(" UAC2 feedback interval too small\r\n"); TU_BREAKPOINT(); return false;
+ }
+
+ // Check if parameters really allow for a power of two division
+ if ((mclk_freq % sample_freq) == 0 && tu_is_power_of_two(mclk_freq / sample_freq))
+ {
+ audio->feedback.compute_method = AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2;
+ audio->feedback.compute.power_of_2 = 16 - audio->feedback.frame_shift - tu_log2(mclk_freq / sample_freq);
+ }
+ else if ( audio->feedback.compute_method == AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT)
+ {
+ audio->feedback.compute.float_const = (float)sample_freq / mclk_freq * (1UL << (16 - audio->feedback.frame_shift));
+ }
+ else
+ {
+ audio->feedback.compute.fixed.sample_freq = sample_freq;
+ audio->feedback.compute.fixed.mclk_freq = mclk_freq;
+ }
+
+ return true;
+}
+
+uint32_t tud_audio_feedback_update(uint8_t func_id, uint32_t cycles)
+{
+ audiod_function_t* audio = &_audiod_fct[func_id];
+ uint32_t feedback;
+
+ switch (audio->feedback.compute_method)
+ {
+ case AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2:
+ feedback = (cycles << audio->feedback.compute.power_of_2);
+ break;
+
+ case AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT:
+ feedback = (uint32_t) ((float) cycles * audio->feedback.compute.float_const);
+ break;
+
+ case AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED:
+ {
+ uint64_t fb64 = (((uint64_t) cycles) * audio->feedback.compute.fixed.sample_freq) << (16 - audio->feedback.frame_shift);
+ feedback = (uint32_t) (fb64 / audio->feedback.compute.fixed.mclk_freq);
+ }
+ break;
+
+ default: return 0;
+ }
+
+ // For Windows: https://docs.microsoft.com/en-us/windows-hardware/drivers/audio/usb-2-0-audio-drivers
+ // The size of isochronous packets created by the device must be within the limits specified in FMT-2.0 section 2.3.1.1.
+ // This means that the deviation of actual packet size from nominal size must not exceed +/- one audio slot
+ // (audio slot = channel count samples).
+ if ( feedback > audio->feedback.max_value ) feedback = audio->feedback.max_value;
+ if ( feedback < audio->feedback.min_value ) feedback = audio->feedback.min_value;
+
+ tud_audio_n_fb_set(func_id, feedback);
+
+ return feedback;
+}
+#endif
+
+TU_ATTR_FAST_FUNC void audiod_sof_isr (uint8_t rhport, uint32_t frame_count)
+{
+ (void) rhport;
+ (void) frame_count;
+
+#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
+ // Determine feedback value - The feedback method is described in 5.12.4.2 of the USB 2.0 spec
+ // Boiled down, the feedback value Ff = n_samples / (micro)frame.
+ // Since an accuracy of less than 1 Sample / second is desired, at least n_frames = ceil(2^K * f_s / f_m) frames need to be measured, where K = 10 for full speed and K = 13 for high speed, f_s is the sampling frequency e.g. 48 kHz and f_m is the cpu clock frequency e.g. 100 MHz (or any other master clock whose clock count is available and locked to f_s)
+ // The update interval in the (4.10.2.1) Feedback Endpoint Descriptor must be less or equal to 2^(K - P), where P = min( ceil(log2(f_m / f_s)), K)
+ // feedback = n_cycles / n_frames * f_s / f_m in 16.16 format, where n_cycles are the number of main clock cycles within fb_n_frames
+
+ // Iterate over audio functions and set feedback value
+ for(uint8_t i=0; i < CFG_TUD_AUDIO; i++)
+ {
+ audiod_function_t* audio = &_audiod_fct[i];
+
+ if (audio->ep_fb != 0)
+ {
+ // HS shift need to be adjusted since SOF event is generated for frame only
+ uint8_t const hs_adjust = (TUSB_SPEED_HIGH == tud_speed_get()) ? 3 : 0;
+ uint32_t const interval = 1UL << (audio->feedback.frame_shift - hs_adjust);
+ if ( 0 == (frame_count & (interval-1)) )
+ {
+ if(tud_audio_feedback_interval_isr) tud_audio_feedback_interval_isr(i, frame_count, audio->feedback.frame_shift);
+ }
+ }
+ }
+#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
+}
+
bool tud_audio_buffer_and_schedule_control_xfer(uint8_t rhport, tusb_control_request_t const * p_request, void* data, uint16_t len)
{
// Handles only sending of data not receiving
@@ -2164,6 +2349,16 @@ static bool audiod_verify_ep_exists(uint8_t ep, uint8_t *func_id)
// Currently, only AS interfaces with an EP (in or out) are supposed to be parsed for!
static void audiod_parse_for_AS_params(audiod_function_t* audio, uint8_t const * p_desc, uint8_t const * p_desc_end, uint8_t const as_itf)
{
+#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT
+ if (as_itf != audio->ep_in_as_intf_num && as_itf != audio->ep_out_as_intf_num) return; // Abort, this interface has no EP, this driver does not support this currently
+#endif
+#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_EP_OUT
+ if (as_itf != audio->ep_in_as_intf_num) return;
+#endif
+#if !CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT
+ if (as_itf != audio->ep_out_as_intf_num) return;
+#endif
+
p_desc = tu_desc_next(p_desc); // Exclude standard AS interface descriptor of current alternate interface descriptor
while (p_desc < p_desc_end)
@@ -2174,16 +2369,6 @@ static void audiod_parse_for_AS_params(audiod_function_t* audio, uint8_t const *
// Look for a Class-Specific AS Interface Descriptor(4.9.2) to verify format type and format and also to get number of physical channels
if (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && tu_desc_subtype(p_desc) == AUDIO_CS_AS_INTERFACE_AS_GENERAL)
{
-#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT
- if (as_itf != audio->ep_in_as_intf_num && as_itf != audio->ep_out_as_intf_num) break; // Abort loop, this interface has no EP, this driver does not support this currently
-#endif
-#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_EP_OUT
- if (as_itf != audio->ep_in_as_intf_num) break;
-#endif
-#if !CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT
- if (as_itf != audio->ep_out_as_intf_num) break;
-#endif
-
#if CFG_TUD_AUDIO_ENABLE_EP_IN
if (as_itf == audio->ep_in_as_intf_num)
{
@@ -2255,7 +2440,7 @@ bool tud_audio_n_fb_set(uint8_t func_id, uint32_t feedback)
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION
if ( TUSB_SPEED_FULL == tud_speed_get() )
{
- uint8_t * fb = (uint8_t *) &_audiod_fct[func_id].fb_val;
+ uint8_t * fb = (uint8_t *) &_audiod_fct[func_id].feedback.value;
// For FS format is 10.14
*(fb++) = (feedback >> 2) & 0xFF;
@@ -2267,7 +2452,7 @@ bool tud_audio_n_fb_set(uint8_t func_id, uint32_t feedback)
#else
{
// Send value as-is, caller will choose the appropriate format
- _audiod_fct[func_id].fb_val = feedback;
+ _audiod_fct[func_id].feedback.value = feedback;
}
#endif
diff --git a/src/class/audio/audio_device.h b/src/class/audio/audio_device.h
index f406cf281..0ef100fa4 100644
--- a/src/class/audio/audio_device.h
+++ b/src/class/audio/audio_device.h
@@ -458,7 +458,14 @@ TU_ATTR_WEAK bool tud_audio_rx_done_post_read_cb(uint8_t rhport, uint16_t n_byte
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
-TU_ATTR_WEAK bool tud_audio_fb_done_cb(uint8_t rhport);
+TU_ATTR_WEAK void tud_audio_fb_done_cb(uint8_t func_id);
+
+
+// determined by the user itself and set by use of tud_audio_n_fb_set(). The feedback value may be determined e.g. from some fill status of some FIFO buffer. Advantage: No ISR interrupt is enabled, hence the CPU need not to handle an ISR every 1ms or 125us and thus less CPU load, disadvantage: typically a larger FIFO is needed to compensate for jitter (e.g. 8 frames), i.e. a larger delay is introduced.
+
+// Feedback value is calculated within the audio driver by use of SOF interrupt. The driver needs information about the master clock f_m from which the audio sample frequency f_s is derived, f_s itself, and the cycle count of f_m at time of the SOF interrupt (e.g. by use of a hardware counter) - see tud_audio_set_fb_params(). Advantage: Reduced jitter in the feedback value computation, hence, the receive FIFO can be smaller (e.g. 2 frames) and thus a smaller delay is possible, disadvantage: higher CPU load due to SOF ISR handling every frame i.e. 1ms or 125us. This option is a great starting point to try the SOF ISR option but depending on your hardware setup (performance of the CPU) it might not work. If so, figure out why and use the next option. (The most critical point is the reading of the cycle counter value of f_m. It is read from within the SOF ISR - see: audiod_sof() -, hence, the ISR must has a high priority such that no software dependent "random" delay i.e. jitter is introduced).
+
+// Feedback value is determined by the user by use of SOF interrupt. The user may use tud_audio_sof_isr() which is called every SOF (of course only invoked when an alternate interface other than zero was set). The number of frames used to determine the feedback value for the currently active alternate setting can be get by tud_audio_get_fb_n_frames(). The feedback value must be set by use of tud_audio_n_fb_set().
// This function is used to provide data rate feedback from an asynchronous sink. Feedback value will be sent at FB endpoint interval till it's changed.
//
@@ -468,9 +475,61 @@ TU_ATTR_WEAK bool tud_audio_fb_done_cb(uint8_t rhport);
//
// Note that due to a bug in its USB Audio 2.0 driver, Windows currently requires 16.16 format for _all_ USB 2.0 devices. On Linux and macOS it seems the
// driver can work with either format. So a good compromise is to keep format correction disabled and stick to 16.16 format.
+
+// Feedback value can be determined from within the SOF ISR of the audio driver. This should reduce jitter. If the feature is used, the user can not set the feedback value.
+
+// Determine feedback value - The feedback method is described in 5.12.4.2 of the USB 2.0 spec
+// Boiled down, the feedback value Ff = n_samples / (micro)frame.
+// Since an accuracy of less than 1 Sample / second is desired, at least n_frames = ceil(2^K * f_s / f_m) frames need to be measured, where K = 10 for full speed and K = 13 for high speed, f_s is the sampling frequency e.g. 48 kHz and f_m is the cpu clock frequency e.g. 100 MHz (or any other master clock whose clock count is available and locked to f_s)
+// The update interval in the (4.10.2.1) Feedback Endpoint Descriptor must be less or equal to 2^(K - P), where P = min( ceil(log2(f_m / f_s)), K)
+// feedback = n_cycles / n_frames * f_s / f_m in 16.16 format, where n_cycles are the number of main clock cycles within fb_n_frames
+
bool tud_audio_n_fb_set(uint8_t func_id, uint32_t feedback);
static inline bool tud_audio_fb_set(uint32_t feedback);
+
+// Update feedback value with passed cycles since last time this update function is called.
+// Typically called within tud_audio_sof_isr(). Required tud_audio_feedback_params_cb() is implemented
+// This function will also call tud_audio_feedback_set()
+// return feedback value in 16.16 for reference (0 for error)
+uint32_t tud_audio_feedback_update(uint8_t func_id, uint32_t cycles);
+
+enum {
+ AUDIO_FEEDBACK_METHOD_DISABLED,
+ AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED,
+ AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT,
+ AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2,
+
+ // impelemnt later
+ // AUDIO_FEEDBACK_METHOD_FIFO_COUNT
+};
+
+typedef struct {
+ uint8_t method;
+ uint32_t sample_freq; // sample frequency in Hz
+
+ union {
+ struct {
+ uint32_t mclk_freq; // Main clock frequency in Hz i.e. master clock to which sample clock is based on
+ }frequency;
+
+#if 0 // implement later
+ struct {
+ uint32_t threshold_bytes; // minimum number of bytes received to be considered as filled/ready
+ }fifo_count;
#endif
+ };
+}audio_feedback_params_t;
+
+// Invoked when needed to set feedback parameters
+TU_ATTR_WEAK void tud_audio_feedback_params_cb(uint8_t func_id, uint8_t alt_itf, audio_feedback_params_t* feedback_param);
+
+// Callback in ISR context, invoked periodically according to feedback endpoint bInterval.
+// Could be used to compute and update feedback value, should be placed in RAM if possible
+// frame_number : current SOF count
+// interval_shift: number of bit shift i.e log2(interval) from Feedback endpoint descriptor
+TU_ATTR_WEAK TU_ATTR_FAST_FUNC void tud_audio_feedback_interval_isr(uint8_t func_id, uint32_t frame_number, uint8_t interval_shift);
+
+#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
TU_ATTR_WEAK bool tud_audio_int_ctr_done_cb(uint8_t rhport, uint16_t n_bytes_copied);
@@ -612,10 +671,12 @@ static inline uint16_t tud_audio_int_ctr_write(uint8_t const* buffer, uint16_t l
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
+
static inline bool tud_audio_fb_set(uint32_t feedback)
{
return tud_audio_n_fb_set(0, feedback);
}
+
#endif
//--------------------------------------------------------------------+
@@ -626,6 +687,7 @@ void audiod_reset (uint8_t rhport);
uint16_t audiod_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len);
bool audiod_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request);
bool audiod_xfer_cb (uint8_t rhport, uint8_t edpt_addr, xfer_result_t result, uint32_t xferred_bytes);
+void audiod_sof_isr (uint8_t rhport, uint32_t frame_count);
#ifdef __cplusplus
}
diff --git a/src/class/bth/bth_device.c b/src/class/bth/bth_device.c
index f40bfbd0d..f96bb3552 100755
--- a/src/class/bth/bth_device.c
+++ b/src/class/bth/bth_device.c
@@ -59,10 +59,12 @@ CFG_TUSB_MEM_SECTION btd_interface_t _btd_itf;
static bool bt_tx_data(uint8_t ep, void *data, uint16_t len)
{
+ uint8_t const rhport = 0;
+
// skip if previous transfer not complete
- TU_VERIFY(!usbd_edpt_busy(TUD_OPT_RHPORT, ep));
+ TU_VERIFY(!usbd_edpt_busy(rhport, ep));
- TU_ASSERT(usbd_edpt_xfer(TUD_OPT_RHPORT, ep, data, len));
+ TU_ASSERT(usbd_edpt_xfer(rhport, ep, data, len));
return true;
}
diff --git a/src/class/cdc/cdc_device.c b/src/class/cdc/cdc_device.c
index 2b9b84e7a..fab6f0035 100644
--- a/src/class/cdc/cdc_device.c
+++ b/src/class/cdc/cdc_device.c
@@ -82,7 +82,7 @@ CFG_TUSB_MEM_SECTION static cdcd_interface_t _cdcd_itf[CFG_TUD_CDC];
static bool _prep_out_transaction (cdcd_interface_t* p_cdc)
{
- uint8_t const rhport = TUD_OPT_RHPORT;
+ uint8_t const rhport = 0;
uint16_t available = tu_fifo_remaining(&p_cdc->rx_ff);
// Prepare for incoming data but only allow what we can store in the ring buffer.
@@ -145,7 +145,7 @@ uint32_t tud_cdc_n_available(uint8_t itf)
uint32_t tud_cdc_n_read(uint8_t itf, void* buffer, uint32_t bufsize)
{
cdcd_interface_t* p_cdc = &_cdcd_itf[itf];
- uint32_t num_read = tu_fifo_read_n(&p_cdc->rx_ff, buffer, bufsize);
+ uint32_t num_read = tu_fifo_read_n(&p_cdc->rx_ff, buffer, (uint16_t) bufsize);
_prep_out_transaction(p_cdc);
return num_read;
}
@@ -168,7 +168,7 @@ void tud_cdc_n_read_flush (uint8_t itf)
uint32_t tud_cdc_n_write(uint8_t itf, void const* buffer, uint32_t bufsize)
{
cdcd_interface_t* p_cdc = &_cdcd_itf[itf];
- uint16_t ret = tu_fifo_write_n(&p_cdc->tx_ff, buffer, bufsize);
+ uint16_t ret = tu_fifo_write_n(&p_cdc->tx_ff, buffer, (uint16_t) bufsize);
// flush if queue more than packet size
if ( tu_fifo_count(&p_cdc->tx_ff) >= BULK_PACKET_SIZE )
@@ -189,7 +189,7 @@ uint32_t tud_cdc_n_write_flush (uint8_t itf)
// No data to send
if ( !tu_fifo_count(&p_cdc->tx_ff) ) return 0;
- uint8_t const rhport = TUD_OPT_RHPORT;
+ uint8_t const rhport = 0;
// Claim the endpoint
TU_VERIFY( usbd_edpt_claim(rhport, p_cdc->ep_in), 0 );
@@ -435,7 +435,7 @@ bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_
// Received new data
if ( ep_addr == p_cdc->ep_out )
{
- tu_fifo_write_n(&p_cdc->rx_ff, &p_cdc->epout_buf, xferred_bytes);
+ tu_fifo_write_n(&p_cdc->rx_ff, &p_cdc->epout_buf, (uint16_t) xferred_bytes);
// Check for wanted char and invoke callback if needed
if ( tud_cdc_rx_wanted_cb && (((signed char) p_cdc->wanted_char) != -1) )
diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c
index 044085e81..ee824cb4e 100644
--- a/src/class/cdc/cdc_host.c
+++ b/src/class/cdc/cdc_host.c
@@ -105,7 +105,7 @@ bool tuh_cdc_send(uint8_t dev_addr, void const * p_data, uint32_t length, bool i
uint8_t const ep_out = cdch_data[dev_addr-1].ep_out;
if ( usbh_edpt_busy(dev_addr, ep_out) ) return false;
- return usbh_edpt_xfer(dev_addr, ep_out, (void*)(uintptr_t) p_data, length);
+ return usbh_edpt_xfer(dev_addr, ep_out, (void*)(uintptr_t) p_data, (uint16_t) length);
}
bool tuh_cdc_receive(uint8_t dev_addr, void * p_buffer, uint32_t length, bool is_notify)
@@ -117,7 +117,7 @@ bool tuh_cdc_receive(uint8_t dev_addr, void * p_buffer, uint32_t length, bool is
uint8_t const ep_in = cdch_data[dev_addr-1].ep_in;
if ( usbh_edpt_busy(dev_addr, ep_in) ) return false;
- return usbh_edpt_xfer(dev_addr, ep_in, p_buffer, length);
+ return usbh_edpt_xfer(dev_addr, ep_in, p_buffer, (uint16_t) length);
}
bool tuh_cdc_set_control_line_state(uint8_t dev_addr, bool dtr, bool rts, tuh_xfer_cb_t complete_cb)
@@ -133,8 +133,8 @@ bool tuh_cdc_set_control_line_state(uint8_t dev_addr, bool dtr, bool rts, tuh_xf
.direction = TUSB_DIR_OUT
},
.bRequest = CDC_REQUEST_SET_CONTROL_LINE_STATE,
- .wValue = (rts ? 2 : 0) | (dtr ? 1 : 0),
- .wIndex = p_cdc->itf_num,
+ .wValue = tu_htole16((uint16_t) ((dtr ? 1u : 0u) | (rts ? 2u : 0u))),
+ .wIndex = tu_htole16(p_cdc->itf_num),
.wLength = 0
};
diff --git a/src/class/dfu/dfu_device.c b/src/class/dfu/dfu_device.c
index 8d859d2ee..aa5891ca9 100644
--- a/src/class/dfu/dfu_device.c
+++ b/src/class/dfu/dfu_device.c
@@ -167,6 +167,8 @@ uint16_t dfu_moded_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc,
uint8_t alt_count = 0;
uint16_t drv_len = 0;
+ TU_VERIFY(itf_desc->bInterfaceSubClass == TUD_DFU_APP_SUBCLASS && itf_desc->bInterfaceProtocol == DFU_PROTOCOL_DFU, 0);
+
while(itf_desc->bInterfaceSubClass == TUD_DFU_APP_SUBCLASS && itf_desc->bInterfaceProtocol == DFU_PROTOCOL_DFU)
{
TU_ASSERT(max_len > drv_len, 0);
diff --git a/src/class/hid/hid_device.c b/src/class/hid/hid_device.c
index 562ca7f36..8077e4deb 100644
--- a/src/class/hid/hid_device.c
+++ b/src/class/hid/hid_device.c
@@ -76,11 +76,12 @@ static inline uint8_t get_index_by_itfnum(uint8_t itf_num)
//--------------------------------------------------------------------+
bool tud_hid_n_ready(uint8_t instance)
{
+ uint8_t const rhport = 0;
uint8_t const ep_in = _hidd_itf[instance].ep_in;
- return tud_ready() && (ep_in != 0) && !usbd_edpt_busy(TUD_OPT_RHPORT, ep_in);
+ return tud_ready() && (ep_in != 0) && !usbd_edpt_busy(rhport, ep_in);
}
-bool tud_hid_n_report(uint8_t instance, uint8_t report_id, void const* report, uint8_t len)
+bool tud_hid_n_report(uint8_t instance, uint8_t report_id, void const* report, uint16_t len)
{
uint8_t const rhport = 0;
hidd_interface_t * p_hid = &_hidd_itf[instance];
@@ -91,7 +92,7 @@ bool tud_hid_n_report(uint8_t instance, uint8_t report_id, void const* report, u
// prepare data
if (report_id)
{
- len = tu_min8(len, CFG_TUD_HID_EP_BUFSIZE-1);
+ len = tu_min16(len, CFG_TUD_HID_EP_BUFSIZE-1);
p_hid->epin_buf[0] = report_id;
memcpy(p_hid->epin_buf+1, report, len);
@@ -99,11 +100,11 @@ bool tud_hid_n_report(uint8_t instance, uint8_t report_id, void const* report, u
}else
{
// If report id = 0, skip ID field
- len = tu_min8(len, CFG_TUD_HID_EP_BUFSIZE);
+ len = tu_min16(len, CFG_TUD_HID_EP_BUFSIZE);
memcpy(p_hid->epin_buf, report, len);
}
- return usbd_edpt_xfer(TUD_OPT_RHPORT, p_hid->ep_in, p_hid->epin_buf, len);
+ return usbd_edpt_xfer(rhport, p_hid->ep_in, p_hid->epin_buf, len);
}
uint8_t tud_hid_n_interface_protocol(uint8_t instance)
@@ -172,7 +173,7 @@ bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id,
//--------------------------------------------------------------------+
void hidd_init(void)
{
- hidd_reset(TUD_OPT_RHPORT);
+ hidd_reset(0);
}
void hidd_reset(uint8_t rhport)
@@ -186,7 +187,8 @@ uint16_t hidd_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint1
TU_VERIFY(TUSB_CLASS_HID == desc_itf->bInterfaceClass, 0);
// len = interface + hid + n*endpoints
- uint16_t const drv_len = sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + desc_itf->bNumEndpoints*sizeof(tusb_desc_endpoint_t);
+ uint16_t const drv_len = (uint16_t) (sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) +
+ desc_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t));
TU_ASSERT(max_len >= drv_len, 0);
// Find available interface
@@ -401,13 +403,13 @@ bool hidd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_
{
if (tud_hid_report_complete_cb)
{
- tud_hid_report_complete_cb(instance, p_hid->epin_buf, (uint8_t) xferred_bytes);
+ tud_hid_report_complete_cb(instance, p_hid->epin_buf, (/*uint16_t*/ uint8_t) xferred_bytes);
}
}
// Received report
else if (ep_addr == p_hid->ep_out)
{
- tud_hid_set_report_cb(instance, 0, HID_REPORT_TYPE_INVALID, p_hid->epout_buf, xferred_bytes);
+ tud_hid_set_report_cb(instance, 0, HID_REPORT_TYPE_INVALID, p_hid->epout_buf, (uint16_t) xferred_bytes);
TU_ASSERT(usbd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf)));
}
diff --git a/src/class/hid/hid_device.h b/src/class/hid/hid_device.h
index 078b67349..3143b1024 100644
--- a/src/class/hid/hid_device.h
+++ b/src/class/hid/hid_device.h
@@ -62,7 +62,7 @@ uint8_t tud_hid_n_interface_protocol(uint8_t instance);
uint8_t tud_hid_n_get_protocol(uint8_t instance);
// Send report to host
-bool tud_hid_n_report(uint8_t instance, uint8_t report_id, void const* report, uint8_t len);
+bool tud_hid_n_report(uint8_t instance, uint8_t report_id, void const* report, uint16_t len);
// KEYBOARD: convenient helper to send keyboard report if application
// use template layout report as defined by hid_keyboard_report_t
@@ -82,7 +82,7 @@ bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id, int8_t x, int
static inline bool tud_hid_ready(void);
static inline uint8_t tud_hid_interface_protocol(void);
static inline uint8_t tud_hid_get_protocol(void);
-static inline bool tud_hid_report(uint8_t report_id, void const* report, uint8_t len);
+static inline bool tud_hid_report(uint8_t report_id, void const* report, uint16_t len);
static inline bool tud_hid_keyboard_report(uint8_t report_id, uint8_t modifier, uint8_t keycode[6]);
static inline bool tud_hid_mouse_report(uint8_t report_id, uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal);
static inline bool tud_hid_gamepad_report(uint8_t report_id, int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons);
@@ -116,7 +116,7 @@ TU_ATTR_WEAK bool tud_hid_set_idle_cb(uint8_t instance, uint8_t idle_rate);
// Invoked when sent REPORT successfully to host
// Application can use this to send the next report
// Note: For composite reports, report[0] is report ID
-TU_ATTR_WEAK void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint8_t len);
+TU_ATTR_WEAK void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, /*uint16_t*/ uint8_t len );
//--------------------------------------------------------------------+
@@ -137,7 +137,7 @@ static inline uint8_t tud_hid_get_protocol(void)
return tud_hid_n_get_protocol(0);
}
-static inline bool tud_hid_report(uint8_t report_id, void const* report, uint8_t len)
+static inline bool tud_hid_report(uint8_t report_id, void const* report, uint16_t len)
{
return tud_hid_n_report(0, report_id, report, len);
}
diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c
index ce3d1598c..ca745464c 100644
--- a/src/class/hid/hid_host.c
+++ b/src/class/hid/hid_host.c
@@ -295,10 +295,10 @@ bool hidh_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint3
{
TU_LOG2(" Get Report callback (%u, %u)\r\n", dev_addr, instance);
TU_LOG3_MEM(hid_itf->epin_buf, xferred_bytes, 2);
- tuh_hid_report_received_cb(dev_addr, instance, hid_itf->epin_buf, xferred_bytes);
+ tuh_hid_report_received_cb(dev_addr, instance, hid_itf->epin_buf, (uint16_t) xferred_bytes);
}else
{
- if (tuh_hid_report_sent_cb) tuh_hid_report_sent_cb(dev_addr, instance, hid_itf->epout_buf, xferred_bytes);
+ if (tuh_hid_report_sent_cb) tuh_hid_report_sent_cb(dev_addr, instance, hid_itf->epout_buf, (uint16_t) xferred_bytes);
}
return true;
@@ -329,10 +329,11 @@ bool hidh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *de
TU_VERIFY(TUSB_CLASS_HID == desc_itf->bInterfaceClass);
- TU_LOG2("HID opening Interface %u (addr = %u)\r\n", desc_itf->bInterfaceNumber, dev_addr);
+ TU_LOG2("[%u] HID opening Interface %u\r\n", dev_addr, desc_itf->bInterfaceNumber);
// len = interface + hid + n*endpoints
- uint16_t const drv_len = sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + desc_itf->bNumEndpoints*sizeof(tusb_desc_endpoint_t);
+ uint16_t const drv_len = (uint16_t) (sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) +
+ desc_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t));
TU_ASSERT(max_len >= drv_len);
uint8_t const *p_desc = (uint8_t const *) desc_itf;
diff --git a/src/class/midi/midi_device.c b/src/class/midi/midi_device.c
index 2ce1376bd..de41706e8 100644
--- a/src/class/midi/midi_device.c
+++ b/src/class/midi/midi_device.c
@@ -92,7 +92,7 @@ bool tud_midi_n_mounted (uint8_t itf)
static void _prep_out_transaction (midid_interface_t* p_midi)
{
- uint8_t const rhport = TUD_OPT_RHPORT;
+ uint8_t const rhport = 0;
uint16_t available = tu_fifo_remaining(&p_midi->rx_ff);
// Prepare for incoming data but only allow what we can store in the ring buffer.
@@ -127,7 +127,7 @@ uint32_t tud_midi_n_available(uint8_t itf, uint8_t cable_num)
midid_stream_t const* stream = &midi->stream_read;
// when using with packet API stream total & index are both zero
- return tu_fifo_count(&midi->rx_ff) + (stream->total - stream->index);
+ return tu_fifo_count(&midi->rx_ff) + (uint8_t) (stream->total - stream->index);
}
uint32_t tud_midi_n_stream_read(uint8_t itf, uint8_t cable_num, void* buffer, uint32_t bufsize)
@@ -179,7 +179,7 @@ uint32_t tud_midi_n_stream_read(uint8_t itf, uint8_t cable_num, void* buffer, ui
}
// Copy data up to bufsize
- uint32_t const count = tu_min32(stream->total - stream->index, bufsize);
+ uint8_t const count = (uint8_t) tu_min32(stream->total - stream->index, bufsize);
// Skip the header (1st byte) in the buffer
memcpy(buf8, stream->buffer + 1 + stream->index, count);
@@ -219,7 +219,7 @@ static uint32_t write_flush(midid_interface_t* midi)
// No data to send
if ( !tu_fifo_count(&midi->tx_ff) ) return 0;
- uint8_t const rhport = TUD_OPT_RHPORT;
+ uint8_t const rhport = 0;
// skip if previous transfer not complete
TU_VERIFY( usbd_edpt_claim(rhport, midi->ep_in), 0 );
@@ -276,13 +276,13 @@ uint32_t tud_midi_n_stream_write(uint8_t itf, uint8_t cable_num, uint8_t const*
else if ( (msg >= 0x8 && msg <= 0xB) || msg == 0xE )
{
// Channel Voice Messages
- stream->buffer[0] = (cable_num << 4) | msg;
+ stream->buffer[0] = (uint8_t) ((cable_num << 4) | msg);
stream->total = 4;
}
else if ( msg == 0xC || msg == 0xD)
{
// Channel Voice Messages, two-byte variants (Program Change and Channel Pressure)
- stream->buffer[0] = (cable_num << 4) | msg;
+ stream->buffer[0] = (uint8_t) ((cable_num << 4) | msg);
stream->total = 3;
}
else if ( msg == 0xf )
@@ -312,7 +312,7 @@ uint32_t tud_midi_n_stream_write(uint8_t itf, uint8_t cable_num, uint8_t const*
else
{
// Pack individual bytes if we don't support packing them into words.
- stream->buffer[0] = cable_num << 4 | 0xf;
+ stream->buffer[0] = (uint8_t) (cable_num << 4 | 0xf);
stream->buffer[2] = 0;
stream->buffer[3] = 0;
stream->index = 2;
@@ -513,7 +513,7 @@ bool midid_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32
// receive new data
if ( ep_addr == p_midi->ep_out )
{
- tu_fifo_write_n(&p_midi->rx_ff, p_midi->epout_buf, xferred_bytes);
+ tu_fifo_write_n(&p_midi->rx_ff, p_midi->epout_buf, (uint16_t) xferred_bytes);
// invoke receive callback if available
if (tud_midi_rx_cb) tud_midi_rx_cb(itf);
diff --git a/src/class/msc/msc_device.c b/src/class/msc/msc_device.c
index 3facb76d6..00b0a1d06 100644
--- a/src/class/msc/msc_device.c
+++ b/src/class/msc/msc_device.c
@@ -28,9 +28,9 @@
#if (CFG_TUD_ENABLED && CFG_TUD_MSC)
+#include "device/dcd.h" // for faking dcd_event_xfer_complete
#include "device/usbd.h"
#include "device/usbd_pvt.h"
-#include "device/dcd.h" // for faking dcd_event_xfer_complete
#include "msc_device.h"
@@ -463,7 +463,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
{
// Didn't check for case 9 (Ho > Dn), which requires examining scsi command first
// but it is OK to just receive data then responded with failed status
- TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_out, _mscd_buf, p_msc->total_len) );
+ TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_out, _mscd_buf, (uint16_t) p_msc->total_len) );
}
}else
{
@@ -473,7 +473,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
// Invoke user callback if not built-in
if ( (resplen < 0) && (p_msc->sense_key == 0) )
{
- resplen = tud_msc_scsi_cb(p_cbw->lun, p_cbw->command, _mscd_buf, p_msc->total_len);
+ resplen = tud_msc_scsi_cb(p_cbw->lun, p_cbw->command, _mscd_buf, (uint16_t) p_msc->total_len);
}
if ( resplen < 0 )
@@ -506,7 +506,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
{
// cannot return more than host expect
p_msc->total_len = tu_min32((uint32_t) resplen, p_cbw->total_bytes);
- TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_in, _mscd_buf, p_msc->total_len) );
+ TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_in, _mscd_buf, (uint16_t) p_msc->total_len) );
}
}
}
@@ -541,7 +541,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
// OUT transfer, invoke callback if needed
if ( !is_data_in(p_cbw->dir) )
{
- int32_t cb_result = tud_msc_scsi_cb(p_cbw->lun, p_cbw->command, _mscd_buf, p_msc->total_len);
+ int32_t cb_result = tud_msc_scsi_cb(p_cbw->lun, p_cbw->command, _mscd_buf, (uint16_t) p_msc->total_len);
if ( cb_result < 0 )
{
@@ -707,7 +707,7 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_
read_capa10.block_size = tu_htonl(block_size);
resplen = sizeof(read_capa10);
- memcpy(buffer, &read_capa10, resplen);
+ memcpy(buffer, &read_capa10, (size_t) resplen);
}
}
break;
@@ -741,7 +741,7 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_
read_fmt_capa.block_size_u16 = tu_htons(block_size);
resplen = sizeof(read_fmt_capa);
- memcpy(buffer, &read_fmt_capa, resplen);
+ memcpy(buffer, &read_fmt_capa, (size_t) resplen);
}
}
break;
@@ -764,7 +764,7 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_
tud_msc_inquiry_cb(lun, inquiry_rsp.vendor_id, inquiry_rsp.product_id, inquiry_rsp.product_rev);
resplen = sizeof(inquiry_rsp);
- memcpy(buffer, &inquiry_rsp, resplen);
+ memcpy(buffer, &inquiry_rsp, (size_t) resplen);
}
break;
@@ -788,7 +788,7 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_
mode_resp.write_protected = !writable;
resplen = sizeof(mode_resp);
- memcpy(buffer, &mode_resp, resplen);
+ memcpy(buffer, &mode_resp, (size_t) resplen);
}
break;
@@ -801,17 +801,17 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_
};
sense_rsp.add_sense_len = sizeof(scsi_sense_fixed_resp_t) - 8;
- sense_rsp.sense_key = p_msc->sense_key;
+ sense_rsp.sense_key = (uint8_t) (p_msc->sense_key & 0x0F);
sense_rsp.add_sense_code = p_msc->add_sense_code;
sense_rsp.add_sense_qualifier = p_msc->add_sense_qualifier;
resplen = sizeof(sense_rsp);
- memcpy(buffer, &sense_rsp, resplen);
+ memcpy(buffer, &sense_rsp, (size_t) resplen);
// request sense callback could overwrite the sense data
if (tud_msc_request_sense_cb)
{
- resplen = tud_msc_request_sense_cb(lun, buffer, bufsize);
+ resplen = tud_msc_request_sense_cb(lun, buffer, (uint16_t) bufsize);
}
// Clear sense data after copy
@@ -859,7 +859,7 @@ static void proc_read10_cmd(uint8_t rhport, mscd_interface_t* p_msc)
}
else
{
- TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_in, _mscd_buf, nbytes), );
+ TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_in, _mscd_buf, (uint16_t) nbytes), );
}
}
@@ -883,7 +883,7 @@ static void proc_write10_cmd(uint8_t rhport, mscd_interface_t* p_msc)
}
// remaining bytes capped at class buffer
- int32_t nbytes = (int32_t) tu_min32(sizeof(_mscd_buf), p_cbw->total_bytes-p_msc->xferred_len);
+ uint16_t nbytes = (uint16_t) tu_min32(sizeof(_mscd_buf), p_cbw->total_bytes-p_msc->xferred_len);
// Write10 callback will be called later when usb transfer complete
TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_out, _mscd_buf, nbytes), );
@@ -921,14 +921,15 @@ static void proc_write10_new_data(uint8_t rhport, mscd_interface_t* p_msc, uint3
// Application consume less than what we got (including zero)
if ( (uint32_t) nbytes < xferred_bytes )
{
+ uint32_t const left_over = xferred_bytes - (uint32_t) nbytes;
if ( nbytes > 0 )
{
- p_msc->xferred_len += nbytes;
- memmove(_mscd_buf, _mscd_buf+nbytes, xferred_bytes-nbytes);
+ p_msc->xferred_len += (uint16_t) nbytes;
+ memmove(_mscd_buf, _mscd_buf+nbytes, left_over);
}
// simulate an transfer complete with adjusted parameters --> callback will be invoked with adjusted parameter
- dcd_event_xfer_complete(rhport, p_msc->ep_out, xferred_bytes-nbytes, XFER_RESULT_SUCCESS, false);
+ dcd_event_xfer_complete(rhport, p_msc->ep_out, left_over, XFER_RESULT_SUCCESS, false);
}
else
{
diff --git a/src/class/msc/msc_host.c b/src/class/msc/msc_host.c
index c54a63f37..934f79ff7 100644
--- a/src/class/msc/msc_host.c
+++ b/src/class/msc/msc_host.c
@@ -325,19 +325,19 @@ bool msch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32
p_msc->stage = MSC_STAGE_DATA;
uint8_t const ep_data = (cbw->dir & TUSB_DIR_IN_MASK) ? p_msc->ep_in : p_msc->ep_out;
- TU_ASSERT(usbh_edpt_xfer(dev_addr, ep_data, p_msc->buffer, cbw->total_bytes));
+ TU_ASSERT(usbh_edpt_xfer(dev_addr, ep_data, p_msc->buffer, (uint16_t) cbw->total_bytes));
}else
{
// Status stage
p_msc->stage = MSC_STAGE_STATUS;
- TU_ASSERT(usbh_edpt_xfer(dev_addr, p_msc->ep_in, (uint8_t*) &p_msc->csw, sizeof(msc_csw_t)));
+ TU_ASSERT(usbh_edpt_xfer(dev_addr, p_msc->ep_in, (uint8_t*) &p_msc->csw, (uint16_t) sizeof(msc_csw_t)));
}
break;
case MSC_STAGE_DATA:
// Status stage
p_msc->stage = MSC_STAGE_STATUS;
- TU_ASSERT(usbh_edpt_xfer(dev_addr, p_msc->ep_in, (uint8_t*) &p_msc->csw, sizeof(msc_csw_t)));
+ TU_ASSERT(usbh_edpt_xfer(dev_addr, p_msc->ep_in, (uint8_t*) &p_msc->csw, (uint16_t) sizeof(msc_csw_t)));
break;
case MSC_STAGE_STATUS:
@@ -370,7 +370,7 @@ bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *de
MSC_PROTOCOL_BOT == desc_itf->bInterfaceProtocol);
// msc driver length is fixed
- uint16_t const drv_len = sizeof(tusb_desc_interface_t) + desc_itf->bNumEndpoints*sizeof(tusb_desc_endpoint_t);
+ uint16_t const drv_len = (uint16_t) (sizeof(tusb_desc_interface_t) + desc_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t));
TU_ASSERT(drv_len <= max_len);
msch_interface_t* p_msc = get_itf(dev_addr);
diff --git a/src/class/net/ecm_rndis_device.c b/src/class/net/ecm_rndis_device.c
index f6b318058..5f316762f 100644
--- a/src/class/net/ecm_rndis_device.c
+++ b/src/class/net/ecm_rndis_device.c
@@ -108,20 +108,22 @@ static bool can_xmit;
void tud_network_recv_renew(void)
{
- usbd_edpt_xfer(TUD_OPT_RHPORT, _netd_itf.ep_out, received, sizeof(received));
+ usbd_edpt_xfer(0, _netd_itf.ep_out, received, sizeof(received));
}
static void do_in_xfer(uint8_t *buf, uint16_t len)
{
can_xmit = false;
- usbd_edpt_xfer(TUD_OPT_RHPORT, _netd_itf.ep_in, buf, len);
+ usbd_edpt_xfer(0, _netd_itf.ep_in, buf, len);
}
void netd_report(uint8_t *buf, uint16_t len)
{
+ uint8_t const rhport = 0;
+
// skip if previous report not yet acknowledged by host
- if ( usbd_edpt_busy(TUD_OPT_RHPORT, _netd_itf.ep_notif) ) return;
- usbd_edpt_xfer(TUD_OPT_RHPORT, _netd_itf.ep_notif, buf, len);
+ if ( usbd_edpt_busy(rhport, _netd_itf.ep_notif) ) return;
+ usbd_edpt_xfer(rhport, _netd_itf.ep_notif, buf, len);
}
//--------------------------------------------------------------------+
@@ -316,11 +318,11 @@ bool netd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t
rndis_generic_msg_t *rndis_msg = (rndis_generic_msg_t *) ((void*) notify.rndis_buf);
uint32_t msglen = tu_le32toh(rndis_msg->MessageLength);
TU_ASSERT(msglen <= sizeof(notify.rndis_buf));
- tud_control_xfer(rhport, request, notify.rndis_buf, msglen);
+ tud_control_xfer(rhport, request, notify.rndis_buf, (uint16_t) msglen);
}
else
{
- tud_control_xfer(rhport, request, notify.rndis_buf, sizeof(notify.rndis_buf));
+ tud_control_xfer(rhport, request, notify.rndis_buf, (uint16_t) sizeof(notify.rndis_buf));
}
}
break;
@@ -367,7 +369,7 @@ static void handle_incoming_packet(uint32_t len)
}
}
- if (!tud_network_recv_cb(pnt, size))
+ if (!tud_network_recv_cb(pnt, (uint16_t) size))
{
/* if a buffer was never handled by user code, we must renew on the user's behalf */
tud_network_recv_renew();
diff --git a/src/class/net/ncm_device.c b/src/class/net/ncm_device.c
index 1987337f8..00892b49c 100644
--- a/src/class/net/ncm_device.c
+++ b/src/class/net/ncm_device.c
@@ -188,7 +188,7 @@ static void ncm_start_tx(void) {
ntb->ndp.datagram[ncm_interface.datagram_count].wDatagramLength = 0;
// Kick off an endpoint transfer
- usbd_edpt_xfer(TUD_OPT_RHPORT, ncm_interface.ep_in, ntb->data, ntb_length);
+ usbd_edpt_xfer(0, ncm_interface.ep_in, ntb->data, ntb_length);
ncm_interface.transferring = true;
// Swap to the other NTB and clear it out
@@ -229,7 +229,7 @@ void tud_network_recv_renew(void)
{
if (!ncm_interface.num_datagrams)
{
- usbd_edpt_xfer(TUD_OPT_RHPORT, ncm_interface.ep_out, receive_ntb, sizeof(receive_ntb));
+ usbd_edpt_xfer(0, ncm_interface.ep_out, receive_ntb, sizeof(receive_ntb));
return;
}
@@ -316,14 +316,15 @@ uint16_t netd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint1
static void ncm_report(void)
{
+ uint8_t const rhport = 0;
if (ncm_interface.report_state == REPORT_SPEED) {
ncm_notify_speed_change.header.wIndex = ncm_interface.itf_num;
- usbd_edpt_xfer(TUD_OPT_RHPORT, ncm_interface.ep_notif, (uint8_t *) &ncm_notify_speed_change, sizeof(ncm_notify_speed_change));
+ usbd_edpt_xfer(rhport, ncm_interface.ep_notif, (uint8_t *) &ncm_notify_speed_change, sizeof(ncm_notify_speed_change));
ncm_interface.report_state = REPORT_CONNECTED;
ncm_interface.report_pending = true;
} else if (ncm_interface.report_state == REPORT_CONNECTED) {
ncm_notify_connected.header.wIndex = ncm_interface.itf_num;
- usbd_edpt_xfer(TUD_OPT_RHPORT, ncm_interface.ep_notif, (uint8_t *) &ncm_notify_connected, sizeof(ncm_notify_connected));
+ usbd_edpt_xfer(rhport, ncm_interface.ep_notif, (uint8_t *) &ncm_notify_connected, sizeof(ncm_notify_connected));
ncm_interface.report_state = REPORT_DONE;
ncm_interface.report_pending = true;
}
diff --git a/src/class/usbtmc/usbtmc.h b/src/class/usbtmc/usbtmc.h
index 7d7005c2e..e7016ae24 100644
--- a/src/class/usbtmc/usbtmc.h
+++ b/src/class/usbtmc/usbtmc.h
@@ -189,7 +189,10 @@ typedef enum {
USBTMC_STATUS_FAILED = 0x80,
USBTMC_STATUS_TRANSFER_NOT_IN_PROGRESS = 0x81,
USBTMC_STATUS_SPLIT_NOT_IN_PROGRESS = 0x82,
- USBTMC_STATUS_SPLIT_IN_PROGRESS = 0x83
+ USBTMC_STATUS_SPLIT_IN_PROGRESS = 0x83,
+
+ /****** USBTMC 488 *************/
+ USB488_STATUS_INTERRUPT_IN_BUSY = 0x20
} usbtmc_status_enum;
/************************************************************
diff --git a/src/class/usbtmc/usbtmc_device.c b/src/class/usbtmc/usbtmc_device.c
index b02b07575..af4a92732 100644
--- a/src/class/usbtmc/usbtmc_device.c
+++ b/src/class/usbtmc/usbtmc_device.c
@@ -64,7 +64,8 @@
// USBTMC 3.2.2 error conditions not strictly followed
// No local lock-out, REN, or GTL.
// Clear message available status byte at the correct time? (488 4.3.1.3)
-
+// Ability to defer status byte transmission
+// Transmission of status byte in response to USB488 SRQ condition
#include "tusb_option.h"
@@ -80,6 +81,11 @@
static char logMsg[150];
#endif
+// Buffer size must be an exact multiple of the max packet size for both
+// bulk (up to 64 bytes for FS, 512 bytes for HS). In addation, this driver
+// imposes a minimum buffer size of 32 bytes.
+#define USBTMCD_BUFFER_SIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
+
/*
* The state machine does not allow simultaneous reading and writing. This is
* consistent with USBTMC.
@@ -120,9 +126,12 @@ typedef struct
uint8_t ep_int_in;
// 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_MAX_PACKET_SIZE];
+ 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_MAX_PACKET_SIZE];
+ CFG_TUSB_MEM_ALIGN uint8_t ep_bulk_out_buf[USBTMCD_BUFFER_SIZE];
+ uint32_t ep_bulk_out_wMaxPacketSize;
+
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)
@@ -139,11 +148,8 @@ CFG_TUSB_MEM_SECTION static usbtmc_interface_state_t usbtmc_state =
.itf_id = 0xFF,
};
-// 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");
-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");
+// We need all headers to fit in a single packet in this implementation, 32 bytes will fit all standard USBTMC headers
+TU_VERIFY_STATIC(USBTMCD_BUFFER_SIZE >= 32u,"USBTMC dev buffer size too small");
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);
@@ -151,7 +157,6 @@ static bool handle_devMsgOut(uint8_t rhport, void *data, size_t len, size_t pack
static uint8_t termChar;
static uint8_t termCharRequested = false;
-
osal_mutex_def_t usbtmcLockBuffer;
static osal_mutex_t usbtmcLock;
@@ -282,12 +287,15 @@ uint16_t usbtmcd_open_cb(uint8_t rhport, tusb_desc_interface_t const * itf_desc,
tusb_desc_endpoint_t const *ep_desc = (tusb_desc_endpoint_t const *)p_desc;
switch(ep_desc->bmAttributes.xfer) {
case TUSB_XFER_BULK:
- TU_ASSERT(tu_edpt_packet_size(ep_desc) == USBTMCD_MAX_PACKET_SIZE, 0);
+ // Ensure buffer is an exact multiple of the maxPacketSize
+ TU_ASSERT((USBTMCD_BUFFER_SIZE % tu_edpt_packet_size(ep_desc)) == 0, 0);
if (tu_edpt_dir(ep_desc->bEndpointAddress) == TUSB_DIR_IN)
{
usbtmc_state.ep_bulk_in = ep_desc->bEndpointAddress;
+ usbtmc_state.ep_bulk_in_wMaxPacketSize = tu_edpt_packet_size(ep_desc);
} else {
usbtmc_state.ep_bulk_out = ep_desc->bEndpointAddress;
+ usbtmc_state.ep_bulk_out_wMaxPacketSize = tu_edpt_packet_size(ep_desc);
}
break;
@@ -395,7 +403,7 @@ static bool handle_devMsgOut(uint8_t rhport, void *data, size_t len, size_t pack
// return true upon failure, as we can assume error is being handled elsewhere.
TU_VERIFY(usbtmc_state.state == STATE_RCV,true);
- bool shortPacket = (packetLen < USBTMCD_MAX_PACKET_SIZE);
+ bool shortPacket = (packetLen < usbtmc_state.ep_bulk_out_wMaxPacketSize);
// Packet is to be considered complete when we get enough data or at a short packet.
bool atEnd = false;
@@ -522,7 +530,7 @@ bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint
break;
case STATE_TX_INITIATED:
- if(usbtmc_state.transfer_size_remaining >=sizeof(usbtmc_state.ep_bulk_in_buf))
+ if(usbtmc_state.transfer_size_remaining >= sizeof(usbtmc_state.ep_bulk_in_buf))
{
// FIXME! This removes const below!
TU_VERIFY( usbd_edpt_xfer(rhport, usbtmc_state.ep_bulk_in,
@@ -539,7 +547,7 @@ bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint
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 ))
+ if(((packetLen % usbtmc_state.ep_bulk_in_wMaxPacketSize) != 0) || (packetLen == 0 ))
{
usbtmc_state.state = STATE_TX_SHORTED;
}
@@ -589,18 +597,31 @@ bool usbtmcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request
{
uint32_t ep_addr = (request->wIndex);
+ // At this point, a transfer MAY be in progress. Based on USB spec, when clearing bulk EP HALT,
+ // the EP transfer buffer needs to be cleared and DTOG needs to be reset, even if
+ // the EP is not halted. The only USBD API interface to do this is to stall and then unstall the EP.
if(ep_addr == usbtmc_state.ep_bulk_out)
{
criticalEnter();
+ usbd_edpt_stall(rhport, (uint8_t)ep_addr);
+ usbd_edpt_clear_stall(rhport, (uint8_t)ep_addr);
usbtmc_state.state = STATE_NAK; // USBD core has placed EP in NAK state for us
criticalLeave();
tud_usbtmc_bulkOut_clearFeature_cb();
}
else if (ep_addr == usbtmc_state.ep_bulk_in)
{
+ usbd_edpt_stall(rhport, (uint8_t)ep_addr);
+ usbd_edpt_clear_stall(rhport, (uint8_t)ep_addr);
tud_usbtmc_bulkIn_clearFeature_cb();
}
- else
+ else if ((usbtmc_state.ep_int_in != 0) && (ep_addr == usbtmc_state.ep_int_in))
+ {
+ // Clearing interrupt in EP
+ usbd_edpt_stall(rhport, (uint8_t)ep_addr);
+ usbd_edpt_clear_stall(rhport, (uint8_t)ep_addr);
+ }
+ else
{
return false;
}
@@ -680,7 +701,7 @@ bool usbtmcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request
usbtmc_state.transfer_size_remaining = 0u;
// Check if we've queued a short packet
criticalEnter();
- usbtmc_state.state = ((usbtmc_state.transfer_size_sent % USBTMCD_MAX_PACKET_SIZE) == 0) ?
+ usbtmc_state.state = ((usbtmc_state.transfer_size_sent % usbtmc_state.ep_bulk_in_wMaxPacketSize) == 0) ?
STATE_ABORTING_BULK_IN : STATE_ABORTING_BULK_IN_SHORTED;
criticalLeave();
if(usbtmc_state.transfer_size_sent == 0)
@@ -810,25 +831,32 @@ bool usbtmcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request
bTag = request->wValue & 0x7F;
TU_VERIFY(request->bmRequestType == 0xA1);
- TU_VERIFY((request->wValue & (~0x7F)) == 0u); // Other bits are required to be zero
+ TU_VERIFY((request->wValue & (~0x7F)) == 0u); // Other bits are required to be zero (USB488v1.0 Table 11)
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)
{
- rsp.USBTMC_status = USBTMC_STATUS_SUCCESS;
- rsp.statusByte = 0x00; // Use interrupt endpoint, instead.
-
- usbtmc_read_stb_interrupt_488_t intMsg =
+ rsp.statusByte = 0x00; // Use interrupt endpoint, instead. Must be 0x00 (USB488v1.0 4.3.1.2)
+ if(usbd_edpt_busy(rhport, usbtmc_state.ep_int_in))
+ {
+ rsp.USBTMC_status = USB488_STATUS_INTERRUPT_IN_BUSY;
+ }
+ else
{
- .bNotify1 = {
- .one = 1,
- .bTag = bTag & 0x7Fu,
- },
- .StatusByte = tud_usbtmc_get_stb_cb(&(rsp.USBTMC_status))
- };
- usbd_edpt_xfer(rhport, usbtmc_state.ep_int_in, (void*)&intMsg, sizeof(intMsg));
+ rsp.USBTMC_status = USBTMC_STATUS_SUCCESS;
+ usbtmc_read_stb_interrupt_488_t intMsg =
+ {
+ .bNotify1 = {
+ .one = 1,
+ .bTag = bTag & 0x7Fu,
+ },
+ .StatusByte = tud_usbtmc_get_stb_cb(&(rsp.USBTMC_status))
+ };
+ // Must be queued before control request response sent (USB488v1.0 4.3.1.2)
+ usbd_edpt_xfer(rhport, usbtmc_state.ep_int_in, (void*)&intMsg, sizeof(intMsg));
+ }
}
else
{
diff --git a/src/class/usbtmc/usbtmc_device.h b/src/class/usbtmc/usbtmc_device.h
index 0549a1569..144b3315d 100644
--- a/src/class/usbtmc/usbtmc_device.h
+++ b/src/class/usbtmc/usbtmc_device.h
@@ -35,10 +35,6 @@
#define CFG_TUD_USBTMC_ENABLE_488 (1)
#endif
-// USB spec says that full-speed must be 8,16,32, or 64.
-// However, this driver implementation requires it to be >=32
-#define USBTMCD_MAX_PACKET_SIZE (64u)
-
/***********************************************
* Functions to be implemeted by the class implementation
*/
diff --git a/src/class/vendor/vendor_device.c b/src/class/vendor/vendor_device.c
index 6e3ceb1c4..3b81a108f 100644
--- a/src/class/vendor/vendor_device.c
+++ b/src/class/vendor/vendor_device.c
@@ -84,21 +84,23 @@ bool tud_vendor_n_peek(uint8_t itf, uint8_t* u8)
//--------------------------------------------------------------------+
static void _prep_out_transaction (vendord_interface_t* p_itf)
{
+ uint8_t const rhport = 0;
+
// skip if previous transfer not complete
- if ( usbd_edpt_busy(TUD_OPT_RHPORT, p_itf->ep_out) ) return;
+ if ( usbd_edpt_busy(rhport, p_itf->ep_out) ) return;
// Prepare for incoming data but only allow what we can store in the ring buffer.
uint16_t max_read = tu_fifo_remaining(&p_itf->rx_ff);
if ( max_read >= CFG_TUD_VENDOR_EPSIZE )
{
- usbd_edpt_xfer(TUD_OPT_RHPORT, p_itf->ep_out, p_itf->epout_buf, CFG_TUD_VENDOR_EPSIZE);
+ usbd_edpt_xfer(rhport, p_itf->ep_out, p_itf->epout_buf, CFG_TUD_VENDOR_EPSIZE);
}
}
uint32_t tud_vendor_n_read (uint8_t itf, void* buffer, uint32_t bufsize)
{
vendord_interface_t* p_itf = &_vendord_itf[itf];
- uint32_t num_read = tu_fifo_read_n(&p_itf->rx_ff, buffer, bufsize);
+ uint32_t num_read = tu_fifo_read_n(&p_itf->rx_ff, buffer, (uint16_t) bufsize);
_prep_out_transaction(p_itf);
return num_read;
}
@@ -115,13 +117,15 @@ void tud_vendor_n_read_flush (uint8_t itf)
//--------------------------------------------------------------------+
static uint16_t maybe_transmit(vendord_interface_t* p_itf)
{
+ uint8_t const rhport = 0;
+
// skip if previous transfer not complete
- TU_VERIFY( !usbd_edpt_busy(TUD_OPT_RHPORT, p_itf->ep_in) );
+ TU_VERIFY( !usbd_edpt_busy(rhport, p_itf->ep_in) );
uint16_t count = tu_fifo_read_n(&p_itf->tx_ff, p_itf->epin_buf, CFG_TUD_VENDOR_EPSIZE);
if (count > 0)
{
- TU_ASSERT( usbd_edpt_xfer(TUD_OPT_RHPORT, p_itf->ep_in, p_itf->epin_buf, count) );
+ TU_ASSERT( usbd_edpt_xfer(rhport, p_itf->ep_in, p_itf->epin_buf, count) );
}
return count;
}
@@ -129,7 +133,7 @@ static uint16_t maybe_transmit(vendord_interface_t* p_itf)
uint32_t tud_vendor_n_write (uint8_t itf, void const* buffer, uint32_t bufsize)
{
vendord_interface_t* p_itf = &_vendord_itf[itf];
- uint16_t ret = tu_fifo_write_n(&p_itf->tx_ff, buffer, bufsize);
+ uint16_t ret = tu_fifo_write_n(&p_itf->tx_ff, buffer, (uint16_t) bufsize);
if (tu_fifo_count(&p_itf->tx_ff) >= CFG_TUD_VENDOR_EPSIZE) {
maybe_transmit(p_itf);
}
@@ -227,7 +231,7 @@ uint16_t vendord_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, ui
if ( p_vendor->ep_in ) maybe_transmit(p_vendor);
}
- return (uintptr_t) p_desc - (uintptr_t) desc_itf;
+ return (uint16_t) ((uintptr_t) p_desc - (uintptr_t) desc_itf);
}
bool vendord_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
@@ -248,7 +252,7 @@ bool vendord_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint
if ( ep_addr == p_itf->ep_out )
{
// Receive new data
- tu_fifo_write_n(&p_itf->rx_ff, p_itf->epout_buf, xferred_bytes);
+ tu_fifo_write_n(&p_itf->rx_ff, p_itf->epout_buf, (uint16_t) xferred_bytes);
// Invoked callback if any
if (tud_vendor_rx_cb) tud_vendor_rx_cb(itf);
@@ -257,7 +261,7 @@ bool vendord_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint
}
else if ( ep_addr == p_itf->ep_in )
{
- if (tud_vendor_tx_cb) tud_vendor_tx_cb(itf, xferred_bytes);
+ if (tud_vendor_tx_cb) tud_vendor_tx_cb(itf, (uint16_t) xferred_bytes);
// Send complete, try to send more if possible
maybe_transmit(p_itf);
}
diff --git a/src/class/video/video.h b/src/class/video/video.h
index 844746546..e8227ea60 100644
--- a/src/class/video/video.h
+++ b/src/class/video/video.h
@@ -303,6 +303,45 @@ typedef struct TU_ATTR_PACKED {
} tusb_desc_cs_video_fmt_uncompressed_t;
typedef struct TU_ATTR_PACKED {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bDescriptorSubType;
+ uint8_t bFormatIndex;
+ uint8_t bNumFrameDescriptors;
+ uint8_t bmFlags;
+ uint8_t bDefaultFrameIndex;
+ uint8_t bAspectRatioX;
+ uint8_t bAspectRatioY;
+ uint8_t bmInterlaceFlags;
+ uint8_t bCopyProtect;
+} tusb_desc_cs_video_fmt_mjpeg_t;
+
+typedef struct TU_ATTR_PACKED {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bDescriptorSubType;
+ uint8_t bFormatIndex;
+ uint32_t dwMaxVideoFrameBufferSize; /* deprecated */
+ uint8_t bFormatType;
+} tusb_desc_cs_video_fmt_dv_t;
+
+typedef struct TU_ATTR_PACKED {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bDescriptorSubType;
+ uint8_t bFormatIndex;
+ uint8_t bNumFrameDescriptors;
+ uint8_t guidFormat[16];
+ uint8_t bBitsPerPixel;
+ uint8_t bDefaultFrameIndex;
+ uint8_t bAspectRatioX;
+ uint8_t bAspectRatioY;
+ uint8_t bmInterlaceFlags;
+ uint8_t bCopyProtect;
+ uint8_t bVaribaleSize;
+} tusb_desc_cs_video_fmt_frame_based_t;
+
+typedef struct TU_ATTR_PACKED {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bDescriptorSubType;
@@ -318,6 +357,24 @@ typedef struct TU_ATTR_PACKED {
uint32_t dwFrameInterval[];
} tusb_desc_cs_video_frm_uncompressed_t;
+typedef tusb_desc_cs_video_frm_uncompressed_t tusb_desc_cs_video_frm_mjpeg_t;
+
+typedef struct TU_ATTR_PACKED {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bDescriptorSubType;
+ uint8_t bFrameIndex;
+ uint8_t bmCapabilities;
+ uint16_t wWidth;
+ uint16_t wHeight;
+ uint32_t dwMinBitRate;
+ uint32_t dwMaxBitRate;
+ uint32_t dwDefaultFrameInterval;
+ uint8_t bFrameIntervalType;
+ uint32_t dwBytesPerLine;
+ uint32_t dwFrameInterval[];
+} tusb_desc_cs_video_frm_frame_based_t;
+
//--------------------------------------------------------------------+
// Requests
//--------------------------------------------------------------------+
@@ -378,8 +435,11 @@ TU_VERIFY_STATIC( sizeof(video_probe_and_commit_control_t) == 48, "size is not c
#define TUD_VIDEO_DESC_CS_VS_IN_LEN 13
#define TUD_VIDEO_DESC_CS_VS_OUT_LEN 9
#define TUD_VIDEO_DESC_CS_VS_FMT_UNCOMPR_LEN 27
+#define TUD_VIDEO_DESC_CS_VS_FMT_MJPEG_LEN 11
#define TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT_LEN 38
#define TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_DISC_LEN 26
+#define TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_CONT_LEN 38
+#define TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_DISC_LEN 26
#define TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN 6
/* 2.2 compression formats */
@@ -462,6 +522,25 @@ TU_VERIFY_STATIC( sizeof(video_probe_and_commit_control_t) == 48, "size is not c
_frmidx, _cap, U16_TO_U8S_LE(_width), U16_TO_U8S_LE(_height), U32_TO_U8S_LE(_minbr), U32_TO_U8S_LE(_maxbr), \
U32_TO_U8S_LE(_maxfrmbufsz), U32_TO_U8S_LE(_frminterval), (TU_ARGS_NUM(__VA_ARGS__)), __VA_ARGS__
+/* Motion-JPEG 3.1.1 Table 3-1 */
+#define TUD_VIDEO_DESC_CS_VS_FMT_MJPEG(_fmtidx, _numfrmdesc, _fixed_sz, _frmidx, _asrx, _asry, _interlace, _cp) \
+ TUD_VIDEO_DESC_CS_VS_FMT_MJPEG_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_FORMAT_MJPEG, \
+ _fmtidx, _numfrmdesc, _fixed_sz, _frmidx, _asrx, _asry, _interlace, _cp
+
+/* Motion-JPEG 3.1.1 Table 3-2 and 3-3 */
+#define TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_CONT(_frmidx, _cap, _width, _height, _minbr, _maxbr, _maxfrmbufsz, _frminterval, _minfrminterval, _maxfrminterval, _frmintervalstep) \
+ TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_CONT_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_FRAME_MJPEG, \
+ _frmidx, _cap, U16_TO_U8S_LE(_width), U16_TO_U8S_LE(_height), U32_TO_U8S_LE(_minbr), U32_TO_U8S_LE(_maxbr), \
+ U32_TO_U8S_LE(_maxfrmbufsz), U32_TO_U8S_LE(_frminterval), 0, \
+ U32_TO_U8S_LE(_minfrminterval), U32_TO_U8S_LE(_maxfrminterval), U32_TO_U8S_LE(_frmintervalstep)
+
+/* Motion-JPEG 3.1.1 Table 3-2 and 3-4 */
+#define TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_DISC(_frmidx, _cap, _width, _height, _minbr, _maxbr, _maxfrmbufsz, _frminterval, ...) \
+ TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_DISC_LEN + (TU_ARGS_NUM(__VA_ARGS__)) * 4, \
+ TUSB_DESC_CS_INTERFACE, VIDEO_CS_VS_INTERFACE_FRAME_MJPEG, \
+ _frmidx, _cap, U16_TO_U8S_LE(_width), U16_TO_U8S_LE(_height), U32_TO_U8S_LE(_minbr), U32_TO_U8S_LE(_maxbr), \
+ U32_TO_U8S_LE(_maxfrmbufsz), U32_TO_U8S_LE(_frminterval), (TU_ARGS_NUM(__VA_ARGS__)), __VA_ARGS__
+
/* 3.9.2.6 */
#define TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING(_color, _trns, _mat) \
TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN, \
diff --git a/src/class/video/video_device.c b/src/class/video/video_device.c
index 91718f205..a6d2724c1 100644
--- a/src/class/video/video_device.c
+++ b/src/class/video/video_device.c
@@ -59,6 +59,34 @@ typedef struct TU_ATTR_PACKED {
uint8_t bEntityId;
} tusb_desc_cs_video_entity_itf_t;
+typedef union {
+ struct TU_ATTR_PACKED {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bDescriptorSubType;
+ uint8_t bFormatIndex;
+ uint8_t bNumFrameDescriptors;
+ };
+ tusb_desc_cs_video_fmt_uncompressed_t uncompressed;
+ tusb_desc_cs_video_fmt_mjpeg_t mjpeg;
+ tusb_desc_cs_video_fmt_frame_based_t frame_based;
+} tusb_desc_cs_video_fmt_t;
+
+typedef union {
+ struct TU_ATTR_PACKED {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bDescriptorSubType;
+ uint8_t bFrameIndex;
+ uint8_t bmCapabilities;
+ uint16_t wWidth;
+ uint16_t wHeight;
+ };
+ tusb_desc_cs_video_frm_uncompressed_t uncompressed;
+ tusb_desc_cs_video_frm_mjpeg_t mjpeg;
+ tusb_desc_cs_video_frm_frame_based_t frame_based;
+} tusb_desc_cs_video_frm_t;
+
/* video streaming interface */
typedef struct TU_ATTR_PACKED {
uint8_t index_vc; /* index of bound video control interface */
@@ -243,6 +271,13 @@ static void const* _find_desc_ep(void const *beg, void const *end)
return end;
}
+/** Return the end of the video control descriptor. */
+static inline void const* _end_of_control_descriptor(void const *desc)
+{
+ tusb_desc_vc_itf_t const *vc = (tusb_desc_vc_itf_t const *)desc;
+ return desc + vc->std.bLength + vc->ctl.wTotalLength;
+}
+
/** Find the first entity descriptor with the entity ID
* specified by the argument belonging to the current video control descriptor.
*
@@ -253,10 +288,8 @@ static void const* _find_desc_ep(void const *beg, void const *end)
* @retval end did not found interface descriptor */
static void const* _find_desc_entity(void const *desc, uint_fast8_t entityid)
{
- tusb_desc_vc_itf_t const *vc = (tusb_desc_vc_itf_t const*)desc;
- void const *beg = vc;
- void const *end = beg + vc->std.bLength + vc->ctl.wTotalLength;
- for (void const *cur = beg; cur < end; cur = _find_desc(cur, end, TUSB_DESC_CS_INTERFACE)) {
+ void const *end = _end_of_control_descriptor(desc);
+ for (void const *cur = desc; cur < end; cur = _find_desc(cur, end, TUSB_DESC_CS_INTERFACE)) {
tusb_desc_cs_video_entity_itf_t const *itf = (tusb_desc_cs_video_entity_itf_t const *)cur;
if ((VIDEO_CS_ITF_VC_INPUT_TERMINAL <= itf->bDescriptorSubtype
&& itf->bDescriptorSubtype < VIDEO_CS_ITF_VC_MAX)
@@ -276,17 +309,38 @@ static inline void const* _end_of_streaming_descriptor(void const *desc)
}
/** Find the first format descriptor with the specified format number. */
-static inline tusb_desc_cs_video_fmt_uncompressed_t const *_find_desc_format(void const *beg, void const *end, uint_fast8_t fmtnum)
+static inline void const *_find_desc_format(void const *beg, void const *end, uint_fast8_t fmtnum)
{
- return (tusb_desc_cs_video_fmt_uncompressed_t const*)
- _find_desc_3(beg, end, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED, fmtnum);
+ for (void const *cur = beg; cur < end; cur = _find_desc(cur, end, TUSB_DESC_CS_INTERFACE)) {
+ uint8_t const *p = (uint8_t const *)cur;
+ uint_fast8_t fmt = p[2];
+ if ((fmt == VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED ||
+ fmt == VIDEO_CS_ITF_VS_FORMAT_MJPEG ||
+ fmt == VIDEO_CS_ITF_VS_FORMAT_DV ||
+ fmt == VIDEO_CS_ITF_VS_FRAME_FRAME_BASED) &&
+ fmtnum == p[3]) {
+ return cur;
+ }
+ cur = tu_desc_next(cur);
+ }
+ return end;
}
/** Find the first frame descriptor with the specified format number. */
-static inline tusb_desc_cs_video_frm_uncompressed_t const *_find_desc_frame(void const *beg, void const *end, uint_fast8_t frmnum)
+static inline void const *_find_desc_frame(void const *beg, void const *end, uint_fast8_t frmnum)
{
- return (tusb_desc_cs_video_frm_uncompressed_t const*)
- _find_desc_3(beg, end, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_FRAME_UNCOMPRESSED, frmnum);
+ for (void const *cur = beg; cur < end; cur = _find_desc(cur, end, TUSB_DESC_CS_INTERFACE)) {
+ uint8_t const *p = (uint8_t const *)cur;
+ uint_fast8_t frm = p[2];
+ if ((frm == VIDEO_CS_ITF_VS_FRAME_UNCOMPRESSED ||
+ frm == VIDEO_CS_ITF_VS_FRAME_MJPEG ||
+ frm == VIDEO_CS_ITF_VS_FRAME_FRAME_BASED) &&
+ frmnum == p[3]) {
+ return cur;
+ }
+ cur = tu_desc_next(cur);
+ }
+ return end;
}
/** Set uniquely determined values to variables that have not been set
@@ -297,7 +351,7 @@ static bool _update_streaming_parameters(videod_streaming_interface_t const *stm
{
tusb_desc_vs_itf_t const *vs = _get_desc_vs(stm);
uint_fast8_t fmtnum = param->bFormatIndex;
- TU_ASSERT(fmtnum <= vs->stm.bNumFormats);
+ TU_ASSERT(vs && fmtnum <= vs->stm.bNumFormats);
if (!fmtnum) {
if (1 < vs->stm.bNumFormats) return true; /* Need to negotiate all variables. */
fmtnum = 1;
@@ -307,7 +361,6 @@ static bool _update_streaming_parameters(videod_streaming_interface_t const *stm
/* Set the parameters determined by the format */
param->wKeyFrameRate = 1;
param->wPFrameRate = 0;
- param->wCompQuality = 1; /* 1 to 10000 */
param->wCompWindowSize = 1; /* GOP size? */
param->wDelay = 0; /* milliseconds */
param->dwClockFrequency = 27000000; /* same as MPEG-2 system time clock */
@@ -319,8 +372,18 @@ static bool _update_streaming_parameters(videod_streaming_interface_t const *stm
param->bBitDepthLuma = 8;
void const *end = _end_of_streaming_descriptor(vs);
- tusb_desc_cs_video_fmt_uncompressed_t const *fmt = _find_desc_format(tu_desc_next(vs), end, fmtnum);
+ tusb_desc_cs_video_fmt_t const *fmt = _find_desc_format(tu_desc_next(vs), end, fmtnum);
TU_ASSERT(fmt != end);
+
+ switch (fmt->bDescriptorSubType) {
+ case VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED:
+ param->wCompQuality = 1; /* 1 to 10000 */
+ break;
+ case VIDEO_CS_ITF_VS_FORMAT_MJPEG:
+ break;
+ default: return false;
+ }
+
uint_fast8_t frmnum = param->bFrameIndex;
TU_ASSERT(frmnum <= fmt->bNumFrameDescriptors);
if (!frmnum) {
@@ -328,28 +391,39 @@ static bool _update_streaming_parameters(videod_streaming_interface_t const *stm
frmnum = 1;
param->bFrameIndex = 1;
}
- tusb_desc_cs_video_frm_uncompressed_t const *frm = _find_desc_frame(tu_desc_next(fmt), end, frmnum);
+ tusb_desc_cs_video_frm_t const *frm = _find_desc_frame(tu_desc_next(fmt), end, frmnum);
TU_ASSERT(frm != end);
/* Set the parameters determined by the frame */
uint_fast32_t frame_size = param->dwMaxVideoFrameSize;
if (!frame_size) {
- frame_size = (uint_fast32_t)frm->wWidth * frm->wHeight * fmt->bBitsPerPixel / 8;
+ switch (fmt->bDescriptorSubType) {
+ case VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED:
+ frame_size = (uint_fast32_t)frm->wWidth * frm->wHeight * fmt->uncompressed.bBitsPerPixel / 8;
+ break;
+ case VIDEO_CS_ITF_VS_FORMAT_MJPEG:
+ frame_size = (uint_fast32_t)frm->wWidth * frm->wHeight * 16 / 8; /* YUV422 */
+ break;
+ default: break;
+ }
param->dwMaxVideoFrameSize = frame_size;
}
uint_fast32_t interval = param->dwFrameInterval;
if (!interval) {
- if ((1 < frm->bFrameIntervalType) ||
- ((0 == frm->bFrameIntervalType) && (frm->dwFrameInterval[1] != frm->dwFrameInterval[0]))) {
+ if ((1 < frm->uncompressed.bFrameIntervalType) ||
+ ((0 == frm->uncompressed.bFrameIntervalType) &&
+ (frm->uncompressed.dwFrameInterval[1] != frm->uncompressed.dwFrameInterval[0]))) {
return true;
}
- interval = frm->dwFrameInterval[0];
+ interval = frm->uncompressed.dwFrameInterval[0];
param->dwFrameInterval = interval;
}
uint_fast32_t interval_ms = interval / 10000;
TU_ASSERT(interval_ms);
uint_fast32_t payload_size = (frame_size + interval_ms - 1) / interval_ms + 2;
+ if (CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE < payload_size)
+ payload_size = CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE;
param->dwMaxPayloadTransferSize = payload_size;
return true;
}
@@ -366,7 +440,8 @@ static bool _negotiate_streaming_parameters(videod_streaming_interface_t const *
if (!fmtnum) {
switch (request) {
case VIDEO_REQUEST_GET_MAX:
- param->bFormatIndex = _get_desc_vs(stm)->stm.bNumFormats;
+ if (_get_desc_vs(stm))
+ param->bFormatIndex = _get_desc_vs(stm)->stm.bNumFormats;
break;
case VIDEO_REQUEST_GET_MIN:
case VIDEO_REQUEST_GET_DEF:
@@ -393,8 +468,9 @@ static bool _negotiate_streaming_parameters(videod_streaming_interface_t const *
uint_fast8_t frmnum = param->bFrameIndex;
if (!frmnum) {
tusb_desc_vs_itf_t const *vs = _get_desc_vs(stm);
+ TU_ASSERT(vs);
void const *end = _end_of_streaming_descriptor(vs);
- tusb_desc_cs_video_fmt_uncompressed_t const *fmt = _find_desc_format(tu_desc_next(vs), end, fmtnum);
+ tusb_desc_cs_video_fmt_t const *fmt = _find_desc_format(tu_desc_next(vs), end, fmtnum);
switch (request) {
case VIDEO_REQUEST_GET_MAX:
frmnum = fmt->bNumFrameDescriptors;
@@ -403,31 +479,50 @@ static bool _negotiate_streaming_parameters(videod_streaming_interface_t const *
frmnum = 1;
break;
case VIDEO_REQUEST_GET_DEF:
- frmnum = fmt->bDefaultFrameIndex;
+ switch (fmt->bDescriptorSubType) {
+ case VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED:
+ frmnum = fmt->uncompressed.bDefaultFrameIndex;
+ break;
+ case VIDEO_CS_ITF_VS_FORMAT_MJPEG:
+ frmnum = fmt->mjpeg.bDefaultFrameIndex;
+ break;
+ default: return false;
+ }
break;
default: return false;
}
- param->bFrameIndex = frmnum;
+ param->bFrameIndex = (uint8_t)frmnum;
/* Set the parameters determined by the frame */
- tusb_desc_cs_video_frm_uncompressed_t const *frm = _find_desc_frame(tu_desc_next(fmt), end, frmnum);
- param->dwMaxVideoFrameSize = frm->wWidth * frm->wHeight * fmt->bBitsPerPixel / 8;
+ tusb_desc_cs_video_frm_t const *frm = _find_desc_frame(tu_desc_next(fmt), end, frmnum);
+ uint_fast32_t frame_size;
+ switch (fmt->bDescriptorSubType) {
+ case VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED:
+ frame_size = (uint_fast32_t)frm->wWidth * frm->wHeight * fmt->uncompressed.bBitsPerPixel / 8;
+ break;
+ case VIDEO_CS_ITF_VS_FORMAT_MJPEG:
+ frame_size = (uint_fast32_t)frm->wWidth * frm->wHeight * 16 / 8; /* YUV422 */
+ break;
+ default: return false;
+ }
+ param->dwMaxVideoFrameSize = frame_size;
return true;
}
if (!param->dwFrameInterval) {
tusb_desc_vs_itf_t const *vs = _get_desc_vs(stm);
+ TU_ASSERT(vs);
void const *end = _end_of_streaming_descriptor(vs);
- tusb_desc_cs_video_fmt_uncompressed_t const *fmt = _find_desc_format(tu_desc_next(vs), end, fmtnum);
- tusb_desc_cs_video_frm_uncompressed_t const *frm = _find_desc_frame(tu_desc_next(fmt), end, frmnum);
+ tusb_desc_cs_video_fmt_t const *fmt = _find_desc_format(tu_desc_next(vs), end, fmtnum);
+ tusb_desc_cs_video_frm_t const *frm = _find_desc_frame(tu_desc_next(fmt), end, frmnum);
uint_fast32_t interval, interval_ms;
switch (request) {
case VIDEO_REQUEST_GET_MAX:
{
uint_fast32_t min_interval, max_interval;
- uint_fast8_t num_intervals = frm->bFrameIntervalType;
- max_interval = num_intervals ? frm->dwFrameInterval[num_intervals - 1]: frm->dwFrameInterval[1];
- min_interval = frm->dwFrameInterval[0];
+ uint_fast8_t num_intervals = frm->uncompressed.bFrameIntervalType;
+ max_interval = num_intervals ? frm->uncompressed.dwFrameInterval[num_intervals - 1]: frm->uncompressed.dwFrameInterval[1];
+ min_interval = frm->uncompressed.dwFrameInterval[0];
interval = max_interval;
interval_ms = min_interval / 10000;
}
@@ -435,24 +530,24 @@ static bool _negotiate_streaming_parameters(videod_streaming_interface_t const *
case VIDEO_REQUEST_GET_MIN:
{
uint_fast32_t min_interval, max_interval;
- uint_fast8_t num_intervals = frm->bFrameIntervalType;
- max_interval = num_intervals ? frm->dwFrameInterval[num_intervals - 1]: frm->dwFrameInterval[1];
- min_interval = frm->dwFrameInterval[0];
+ uint_fast8_t num_intervals = frm->uncompressed.bFrameIntervalType;
+ max_interval = num_intervals ? frm->uncompressed.dwFrameInterval[num_intervals - 1]: frm->uncompressed.dwFrameInterval[1];
+ min_interval = frm->uncompressed.dwFrameInterval[0];
interval = min_interval;
interval_ms = max_interval / 10000;
}
break;
case VIDEO_REQUEST_GET_DEF:
- interval = frm->dwDefaultFrameInterval;
+ interval = frm->uncompressed.dwDefaultFrameInterval;
interval_ms = interval / 10000;
break;
case VIDEO_REQUEST_GET_RES:
{
- uint_fast8_t num_intervals = frm->bFrameIntervalType;
+ uint_fast8_t num_intervals = frm->uncompressed.bFrameIntervalType;
if (num_intervals) {
interval = 0;
} else {
- interval = frm->dwFrameInterval[2];
+ interval = frm->uncompressed.dwFrameInterval[2];
interval_ms = interval / 10000;
}
}
@@ -464,11 +559,15 @@ static bool _negotiate_streaming_parameters(videod_streaming_interface_t const *
param->dwMaxPayloadTransferSize = 0;
} else {
uint_fast32_t frame_size = param->dwMaxVideoFrameSize;
+ uint_fast32_t payload_size;
if (!interval_ms) {
- param->dwMaxPayloadTransferSize = frame_size + 2;
+ payload_size = frame_size + 2;
} else {
- param->dwMaxPayloadTransferSize = (frame_size + interval_ms - 1) / interval_ms + 2;
+ payload_size = (frame_size + interval_ms - 1) / interval_ms + 2;
}
+ if (CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE < payload_size)
+ payload_size = CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE;
+ param->dwMaxPayloadTransferSize = payload_size;
}
return true;
}
@@ -485,7 +584,7 @@ static bool _close_vc_itf(uint8_t rhport, videod_interface_t *self)
/* The next descriptor after the class-specific VC interface header descriptor. */
void const *cur = (void const*)vc + vc->std.bLength + vc->ctl.bLength;
/* The end of the video control interface descriptor. */
- void const *end = (void const*)vc + vc->std.bLength + vc->ctl.wTotalLength;
+ void const *end = _end_of_control_descriptor(vc);
if (vc->std.bNumEndpoints) {
/* Find the notification endpoint descriptor. */
cur = _find_desc(cur, end, TUSB_DESC_ENDPOINT);
@@ -517,7 +616,7 @@ static bool _open_vc_itf(uint8_t rhport, videod_interface_t *self, uint_fast8_t
TU_ASSERT(vc->ctl.bInCollection <= CFG_TUD_VIDEO_STREAMING);
/* Update to point the end of the video control interface descriptor. */
- end = cur + vc->std.bLength + vc->ctl.wTotalLength;
+ end = _end_of_control_descriptor(cur);
/* Advance to the next descriptor after the class-specific VC interface header descriptor. */
cur += vc->std.bLength + vc->ctl.bLength;
TU_LOG2(" bNumEndpoints %d\n", vc->std.bNumEndpoints);
@@ -532,7 +631,7 @@ static bool _open_vc_itf(uint8_t rhport, videod_interface_t *self, uint_fast8_t
/* Open the notification endpoint */
TU_ASSERT(usbd_edpt_open(rhport, notif));
}
- self->cur = (void const*)vc - beg;
+ self->cur = (uint16_t) ((void const*)vc - beg);
return true;
}
@@ -550,7 +649,7 @@ static bool _open_vs_itf(uint8_t rhport, videod_streaming_interface_t *stm, uint
for (i = 0; i < TU_ARRAY_SIZE(stm->desc.ep); ++i) {
uint_fast16_t ofs_ep = stm->desc.ep[i];
if (!ofs_ep) break;
- uint_fast8_t ep_adr = _desc_ep_addr(desc + ofs_ep);
+ uint8_t ep_adr = _desc_ep_addr(desc + ofs_ep);
usbd_edpt_close(rhport, ep_adr);
stm->desc.ep[i] = 0;
TU_LOG2(" close EP%02x\n", ep_adr);
@@ -567,13 +666,14 @@ static bool _open_vs_itf(uint8_t rhport, videod_streaming_interface_t *stm, uint
TU_VERIFY(cur < end);
uint_fast8_t numeps = ((tusb_desc_interface_t const *)cur)->bNumEndpoints;
TU_ASSERT(numeps <= TU_ARRAY_SIZE(stm->desc.ep));
- stm->desc.cur = cur - desc; /* Save the offset of the new settings */
+ stm->desc.cur = (uint16_t) (cur - desc); /* Save the offset of the new settings */
if (!altnum) {
/* initialize streaming settings */
stm->max_payload_transfer_size = 0;
video_probe_and_commit_control_t *param =
(video_probe_and_commit_control_t *)&stm->ep_buf;
tu_memclr(param, sizeof(*param));
+ TU_LOG2(" done 0\n");
return _update_streaming_parameters(stm, param);
}
/* Open endpoints of the new settings. */
@@ -594,7 +694,7 @@ static bool _open_vs_itf(uint8_t rhport, videod_streaming_interface_t *stm, uint
stm->max_payload_transfer_size = max_size;
}
TU_ASSERT(usbd_edpt_open(rhport, ep));
- stm->desc.ep[i] = cur - desc;
+ stm->desc.ep[i] = (uint16_t) (cur - desc);
TU_LOG2(" open EP%02x\n", _desc_ep_addr(cur));
}
/* initialize payload header */
@@ -602,6 +702,7 @@ static bool _open_vs_itf(uint8_t rhport, videod_streaming_interface_t *stm, uint
hdr->bHeaderLength = sizeof(*hdr);
hdr->bmHeaderInfo = 0;
+ TU_LOG2(" done\n");
return true;
}
@@ -674,7 +775,7 @@ static int handle_video_ctl_cs_req(uint8_t rhport, uint8_t stage,
if (stage == CONTROL_STAGE_SETUP) {
TU_VERIFY(1 == request->wLength, VIDEO_ERROR_UNKNOWN);
TU_VERIFY(tud_control_xfer(rhport, request, &self->power_mode, sizeof(self->power_mode)), VIDEO_ERROR_UNKNOWN);
- } else if (stage == CONTROL_STAGE_ACK) {
+ } else if (stage == CONTROL_STAGE_DATA) {
if (tud_video_power_mode_cb) return tud_video_power_mode_cb(ctl_idx, self->power_mode);
}
return VIDEO_ERROR_NONE;
@@ -819,7 +920,7 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage,
TU_VERIFY(sizeof(video_probe_and_commit_control_t) == request->wLength, VIDEO_ERROR_UNKNOWN);
TU_VERIFY(tud_control_xfer(rhport, request, self->ep_buf, sizeof(video_probe_and_commit_control_t)),
VIDEO_ERROR_UNKNOWN);
- } else if (stage == CONTROL_STAGE_ACK) {
+ } else if (stage == CONTROL_STAGE_DATA) {
TU_VERIFY(_update_streaming_parameters(self, (video_probe_and_commit_control_t*)self->ep_buf),
VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE);
}
@@ -843,7 +944,7 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage,
video_probe_and_commit_control_t tmp;
tmp = *(video_probe_and_commit_control_t*)&self->ep_buf;
TU_VERIFY(_negotiate_streaming_parameters(self, request->bRequest, &tmp), VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE);
- TU_VERIFY(tud_control_xfer(rhport, request, self->ep_buf, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN);
+ TU_VERIFY(tud_control_xfer(rhport, request, &tmp, sizeof(tmp)), VIDEO_ERROR_UNKNOWN);
}
return VIDEO_ERROR_NONE;
@@ -860,7 +961,7 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage,
if (stage == CONTROL_STAGE_SETUP)
{
TU_VERIFY(1 == request->wLength, VIDEO_ERROR_UNKNOWN);
- TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)(uintptr_t) &_cap_get_set, sizeof(_cap_get_set)), VIDEO_ERROR_UNKNOWN);
+ TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)(uintptr_t)&_cap_get_set, sizeof(_cap_get_set)), VIDEO_ERROR_UNKNOWN);
}
return VIDEO_ERROR_NONE;
@@ -874,7 +975,7 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage,
if (stage == CONTROL_STAGE_SETUP) {
TU_VERIFY(sizeof(video_probe_and_commit_control_t) == request->wLength, VIDEO_ERROR_UNKNOWN);
TU_VERIFY(tud_control_xfer(rhport, request, self->ep_buf, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN);
- } else if (stage == CONTROL_STAGE_ACK) {
+ } else if (stage == CONTROL_STAGE_DATA) {
TU_VERIFY(_update_streaming_parameters(self, (video_probe_and_commit_control_t*)self->ep_buf), VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE);
if (tud_video_commit_cb) {
return tud_video_commit_cb(self->index_vc, self->index_vs, (video_probe_and_commit_control_t*)self->ep_buf);
@@ -976,7 +1077,7 @@ bool tud_video_n_frame_xfer(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, void *bu
/* Find EP address */
void const *desc = _videod_itf[stm->index_vc].beg;
- uint_fast8_t ep_addr = 0;
+ uint8_t ep_addr = 0;
for (uint_fast8_t i = 0; i < CFG_TUD_VIDEO_STREAMING; ++i) {
uint_fast16_t ofs_ep = stm->desc.ep[i];
if (!ofs_ep) continue;
@@ -985,7 +1086,7 @@ bool tud_video_n_frame_xfer(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, void *bu
}
if (!ep_addr) return false;
- TU_VERIFY( usbd_edpt_claim(0, ep_addr));
+ TU_VERIFY( usbd_edpt_claim(0, ep_addr) );
/* update the packet header */
tusb_video_payload_header_t *hdr = (tusb_video_payload_header_t*)stm->ep_buf;
hdr->FrameID ^= 1;
@@ -994,7 +1095,7 @@ bool tud_video_n_frame_xfer(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, void *bu
stm->buffer = (uint8_t*)buffer;
stm->bufsize = bufsize;
uint_fast16_t pkt_len = _prepare_in_payload(stm);
- TU_ASSERT( usbd_edpt_xfer(0, ep_addr, stm->ep_buf, pkt_len), 0);
+ TU_ASSERT( usbd_edpt_xfer(0, ep_addr, stm->ep_buf, (uint16_t) pkt_len), 0);
return true;
}
@@ -1034,7 +1135,7 @@ uint16_t videod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin
/* Find available interface */
videod_interface_t *self = NULL;
- uint_fast8_t ctl_idx;
+ uint8_t ctl_idx;
for (ctl_idx = 0; ctl_idx < CFG_TUD_VIDEO; ++ctl_idx) {
if (_videod_itf[ctl_idx].beg) continue;
self = &_videod_itf[ctl_idx];
@@ -1051,10 +1152,10 @@ uint16_t videod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin
uint_fast8_t bInCollection = vc->ctl.bInCollection;
/* Find the end of the video interface descriptor */
void const *cur = _next_desc_itf(itf_desc, end);
- for (uint_fast8_t stm_idx = 0; stm_idx < bInCollection; ++stm_idx) {
+ for (uint8_t stm_idx = 0; stm_idx < bInCollection; ++stm_idx) {
videod_streaming_interface_t *stm = NULL;
/* find free streaming interface handle */
- for (uint_fast8_t i = 0; i < CFG_TUD_VIDEO_STREAMING; ++i) {
+ for (uint8_t i = 0; i < CFG_TUD_VIDEO_STREAMING; ++i) {
if (_videod_streaming_itf[i].desc.beg) continue;
stm = &_videod_streaming_itf[i];
self->stm[stm_idx] = i;
@@ -1063,12 +1164,12 @@ uint16_t videod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin
TU_ASSERT(stm, 0);
stm->index_vc = ctl_idx;
stm->index_vs = stm_idx;
- stm->desc.beg = (uintptr_t)cur - (uintptr_t)itf_desc;
+ stm->desc.beg = (uint16_t) ((uintptr_t)cur - (uintptr_t)itf_desc);
cur = _next_desc_itf(cur, end);
- stm->desc.end = (uintptr_t)cur - (uintptr_t)itf_desc;
+ stm->desc.end = (uint16_t) ((uintptr_t)cur - (uintptr_t)itf_desc);
}
- self->len = (uintptr_t)cur - (uintptr_t)itf_desc;
- return (uintptr_t)cur - (uintptr_t)itf_desc;
+ self->len = (uint16_t) ((uintptr_t)cur - (uintptr_t)itf_desc);
+ return (uint16_t) ((uintptr_t)cur - (uintptr_t)itf_desc);
}
// Invoked when a control transfer occurred on an interface of this class
@@ -1134,7 +1235,7 @@ bool videod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3
/* Claim the endpoint */
TU_VERIFY( usbd_edpt_claim(rhport, ep_addr), 0);
uint_fast16_t pkt_len = _prepare_in_payload(stm);
- TU_ASSERT( usbd_edpt_xfer(rhport, ep_addr, stm->ep_buf, pkt_len), 0);
+ TU_ASSERT( usbd_edpt_xfer(rhport, ep_addr, stm->ep_buf, (uint16_t) pkt_len), 0);
} else {
stm->buffer = NULL;
stm->bufsize = 0;