Skip to content

Commit

Permalink
Check/wait USB connection status in USB MIDI BulkTX
Browse files Browse the repository at this point in the history
  • Loading branch information
tttapa committed Sep 1, 2024
1 parent 748fad2 commit 8c884a2
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 57 deletions.
8 changes: 8 additions & 0 deletions src/MIDI_Interfaces/USBMIDI/LowLevel/BulkTX.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,14 @@ struct BulkTX {
/// Check if all transfers have completed.
bool is_done() const;

/// Get the number messages that failed to send.
uint32_t getWriteError() const { return writing.error.load(mo_rlx); }
/// Get and clear the number messages that failed to send.
uint32_t clearWriteError() { return writing.error.exchange(0, mo_rlx); }

protected:
void reset(uint16_t packet_size = MaxPacketSize);
bool wait_connect();

private:
static constexpr uint16_t MaxPacketSize = MaxPacketSizeV;
Expand Down Expand Up @@ -89,9 +95,11 @@ struct BulkTX {
interrupt_atomic<Buffer *> sending {nullptr};
interrupt_atomic<Buffer *> send_later {nullptr};
interrupt_atomic<Buffer *> send_now {nullptr};
interrupt_atomic<uint32_t> error {0};
uint16_t packet_size = MaxPacketSize;
} writing;
using wbuffer_t = typename Writing::Buffer;
bool disconnected = false;

uint32_t index_of(wbuffer_t *p) const { return p - writing.buffers; }
wbuffer_t *other_buf(wbuffer_t *p) {
Expand Down
28 changes: 28 additions & 0 deletions src/MIDI_Interfaces/USBMIDI/LowLevel/BulkTX.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,44 @@ void BulkTX<Derived, MessageTypeT, MaxPacketSizeV>::write(MessageType msg) {
write(&msg, 1);
}

template <class Derived, class MessageTypeT, uint16_t MaxPacketSizeV>
bool BulkTX<Derived, MessageTypeT, MaxPacketSizeV>::wait_connect() {
if (CRTP(Derived).connectedForWrite()) {
disconnected = false;
return true; // connection is okay
} else if (disconnected) {
return false; // don't retry
}
#ifdef ARDUINO
// Wait for up to half a second (or until connected)
for (int i = 0; i < 100; ++i) {
delay(5);
if (CRTP(Derived).connectedForWrite()) {
disconnected = false;
return true;
}
}
#endif
disconnected = true;
return false;
}

template <class Derived, class MessageTypeT, uint16_t MaxPacketSizeV>
void BulkTX<Derived, MessageTypeT, MaxPacketSizeV>::write(
const MessageType *msgs, uint32_t num_msgs) {
if (!wait_connect()) {
writing.error.fetch_add(num_msgs, mo_rlx);
return;
}
const uint32_t *end = msgs + num_msgs;
while (msgs != end) msgs += write_impl(msgs, end - msgs);
}

template <class Derived, class MessageTypeT, uint16_t MaxPacketSizeV>
uint32_t BulkTX<Derived, MessageTypeT, MaxPacketSizeV>::write_nonblock(
const MessageType *msgs, uint32_t num_msgs) {
if (!CRTP(Derived).connectedForWrite())
return 0;
uint32_t total_sent = 0, sent = 1;
while (total_sent < num_msgs && sent != 0) {
sent = write_impl(msgs + total_sent, num_msgs - total_sent, true);
Expand Down
57 changes: 6 additions & 51 deletions src/MIDI_Interfaces/USBMIDI/Teensy-host/TeensyHostMIDI.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,49 +31,12 @@ class TeensyHostMIDI
return packet;
}

/// Send a MIDI USB message. May block.
///
/// @param msg
/// The 4-byte MIDI USB message to send.
void write(uint32_t msg) {
if (txpipe)
BulkTX<TeensyHostMIDI, uint32_t, MaxPacketSize>::write(msg);
}

/// Send multiple MIDI USB messages. May block.
///
/// @param msgs
/// An array of 4-byte MIDI USB messages to send.
/// @param num_msgs
/// The number of messages in the array.
void write(const uint32_t *msgs, uint32_t num_msgs) {
if (txpipe)
BulkTX<TeensyHostMIDI, uint32_t, MaxPacketSize>::write(msgs,
num_msgs);
}

/// Send multiple MIDI USB messages. May block.
template <size_t N>
void write(const uint32_t (&msgs)[N]) {
write(msgs, N);
}

/// Send multiple MIDI USB messages without blocking.
///
/// @param msgs
/// An array of 4-byte MIDI USB messages to send.
/// @param num_msgs
/// The number of messages in the array.
/// @return The number of messages that were actually sent.
uint32_t write_nonblock(const uint32_t *msgs, uint32_t num_msgs) {
if (txpipe)
return BulkTX<TeensyHostMIDI, uint32_t,
MaxPacketSize>::write_nonblock(msgs, num_msgs);
return 0;
}

using BulkTX<TeensyHostMIDI, uint32_t, MaxPacketSize>::send_now;
using BulkRX<TeensyHostMIDI, uint32_t, MaxPacketSize>::read;
using BulkTX<TeensyHostMIDI, uint32_t, MaxPacketSize>::write;
using BulkTX<TeensyHostMIDI, uint32_t, MaxPacketSize>::write_nonblock;
using BulkTX<TeensyHostMIDI, uint32_t, MaxPacketSize>::send_now;
using BulkTX<TeensyHostMIDI, uint32_t, MaxPacketSize>::getWriteError;
using BulkTX<TeensyHostMIDI, uint32_t, MaxPacketSize>::clearWriteError;

/// Set the timeout, the number of microseconds to buffer the outgoing MIDI
/// messages. A shorter timeout usually results in lower latency, but also
Expand All @@ -84,14 +47,7 @@ class TeensyHostMIDI
write_error_timeout_duration = timeout;
}

/// Count how many USB packets were dropped.
uint32_t getWriteError() const { return write_errors; }
/// Clear the counter of how many USB packets were dropped.
uint32_t clearWriteError() {
auto old = write_errors;
write_errors = 0;
return old;
}
bool connectedForWrite() const { return txpipe; }

protected:
bool claim(Device_t *device, int type, const uint8_t *descriptors,
Expand Down Expand Up @@ -139,7 +95,6 @@ class TeensyHostMIDI
USBDriverTimer write_timeout {this};
microseconds write_timeout_duration {1'000};
microseconds write_error_timeout_duration {40'000};
uint32_t write_errors {0};

protected:
friend class BulkRX<TeensyHostMIDI, uint32_t, MaxPacketSize>;
Expand Down
9 changes: 3 additions & 6 deletions src/MIDI_Interfaces/USBMIDI/mbed/PluggableUSBMIDI.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ class PluggableUSBMIDI : protected arduino::internal::PluggableUSBModule,
public:
/// Check if this class is connected and ready.
bool connected() const;
bool connectedForWrite() const { return connected(); }

/// Try reading a 4-byte MIDI USB message.
///
Expand All @@ -68,6 +69,8 @@ class PluggableUSBMIDI : protected arduino::internal::PluggableUSBModule,
using BulkTX<PluggableUSBMIDI, uint32_t, 64>::write;
using BulkTX<PluggableUSBMIDI, uint32_t, 64>::write_nonblock;
using BulkTX<PluggableUSBMIDI, uint32_t, 64>::send_now;
using BulkTX<PluggableUSBMIDI, uint32_t, 64>::getWriteError;
using BulkTX<PluggableUSBMIDI, uint32_t, 64>::clearWriteError;

/// Set the timeout, the number of microseconds to buffer the outgoing MIDI
/// messages. A shorter timeout usually results in lower latency, but also
Expand All @@ -78,11 +81,6 @@ class PluggableUSBMIDI : protected arduino::internal::PluggableUSBModule,
error_timeout_duration = timeout;
}

/// Count how many USB packets were dropped.
uint32_t getWriteError() const { return write_errors; }
/// Clear the counter of how many USB packets were dropped.
uint32_t clearWriteError() { return std::exchange(write_errors, 0); }

protected:
void init(EndpointResolver &resolver) override;
void callback_state_change(DeviceState new_state) override;
Expand All @@ -103,7 +101,6 @@ class PluggableUSBMIDI : protected arduino::internal::PluggableUSBModule,
microseconds timeout_duration {1'000};
microseconds error_timeout_duration {40'000};
mbed::Timeout timeout;
uint32_t write_errors {0};

usb_ep_t bulk_in_ep;
usb_ep_t bulk_out_ep;
Expand Down
1 change: 1 addition & 0 deletions test/MIDI_Interfaces/test-USBBulk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ struct TestBulkTX : cs::BulkTX<TestBulkTX, uint32_t, PacketSize> {
tx_start(data, size);
}
void tx_start_isr(const void *data, uint32_t size) { tx_start(data, size); }
bool connectedForWrite() const { return true; }

timer_t timeout_timerid {}, write_timerid {};
itimerspec timeout_its {}, write_its {};
Expand Down

0 comments on commit 8c884a2

Please sign in to comment.