Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions components/usb_device/include/usb_device.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,32 @@ class UsbDevice : public BaseComponent {
/// @brief Convenience overload of write_vendor() that ignores errors.
bool write_vendor(std::span<const uint8_t> data);

/// @brief Bytes of free space currently in the vendor TX FIFO.
/// @return How many bytes write_vendor() can accept right now without
/// blocking, or 0 if not initialized / no vendor interface / not
/// mounted. A point-in-time hint: with a single serialized writer it
/// is stable, otherwise treat it as advisory. Use it to skip or defer
/// a streaming frame when the host has stopped draining the endpoint,
/// instead of building the frame and having write_vendor() drop it.
size_t vendor_write_available() const;

/// @brief Bytes of free space currently in the CDC TX FIFO.
/// @return How many bytes write_cdc() can accept right now, or 0 if not
/// initialized / no CDC interface / not mounted. See
/// vendor_write_available() for usage notes.
size_t cdc_write_available() const;

/// @brief Discard any bytes queued in the vendor TX FIFO that have not been
/// sent yet. Call this when the host goes away (e.g. on a detected
/// disconnect / stream stall) so a stale backlog (queued telemetry) is
/// not delivered to the next host that connects and mis-parsed as a
/// reply to its first command.
void vendor_write_clear();

/// @brief Discard any bytes queued in the CDC TX FIFO that have not been sent
/// yet. See vendor_write_clear() for usage notes.
void cdc_write_clear();

/**
* @brief Send a HID input report on the HID function's interrupt IN endpoint.
* @param report_id HID report id (0 if the report descriptor has no report id;
Expand Down
43 changes: 43 additions & 0 deletions components/usb_device/src/usb_device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,21 @@ bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage,

#endif // CFG_TUD_VENDOR > 0

// Device unmount: drop any bytes still queued in the TX FIFOs. A host that goes
// away (cable pull / re-enumeration / suspend) leaves its unread backlog in the
// software FIFO; clearing it here means the next host to mount starts from an
// empty pipe and cannot mis-parse a stale frame as the reply to its first
// command. (An abrupt tab close does NOT unmount, so it does not reach here --
// that path relies on the streaming producer's own backpressure handling.)
void tud_umount_cb(void) {
#if (CFG_TUD_VENDOR > 0)
tud_vendor_write_clear();
#endif
#if (CFG_TUD_CDC > 0)
tud_cdc_n_write_clear(kCdcPort);
#endif
}

#if (CFG_TUD_HID > 0)

// HID: return the application-supplied report descriptor for the given instance.
Expand Down Expand Up @@ -1142,6 +1157,34 @@ bool UsbDevice::is_vendor_connected() const {
return tud_mounted();
}

size_t UsbDevice::vendor_write_available() const {
#if (CFG_TUD_VENDOR > 0)
if (!initialized_ || !config_.vendor || !tud_mounted())
return 0;
return tud_vendor_write_available();
#else
return 0;
#endif
}

size_t UsbDevice::cdc_write_available() const {
if (!initialized_ || !config_.cdc || !tud_mounted())
return 0;
return tud_cdc_n_write_available(kCdcPort);
}
Comment on lines +1170 to +1174

void UsbDevice::vendor_write_clear() {
#if (CFG_TUD_VENDOR > 0)
if (initialized_ && config_.vendor)
tud_vendor_write_clear();
#endif
}

void UsbDevice::cdc_write_clear() {
if (initialized_ && config_.cdc)
tud_cdc_n_write_clear(kCdcPort);
}
Comment on lines +1183 to +1186

bool UsbDevice::is_hid_ready() const {
#if (CFG_TUD_HID > 0)
if (!initialized_ || !config_.hid)
Expand Down
Loading