Skip to content

Commit

Permalink
Avoid blocking when writing to serial
Browse files Browse the repository at this point in the history
This makes it so that in B-to-A serial communication, certain types of
packets (REQUEST_B_INIT, REPORT_RECEIVED, START_OF_FRAME,
MIDI_RECEIVED) are dropped when the outgoing buffer is full and we'd
have to block. This way we can keep regularly calling tuh_task().

This should never happen during normal operation.
  • Loading branch information
jfedor2 committed Dec 2, 2024
1 parent 6f588f3 commit 334ec70
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 6 deletions.
8 changes: 4 additions & 4 deletions firmware/src/remapper_dual_b.cc
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ bool serial_callback(const uint8_t* data, uint16_t len) {

void request_b_init() {
request_b_init_t msg;
serial_write((uint8_t*) &msg, sizeof(msg));
serial_write_nonblocking((uint8_t*) &msg, sizeof(msg));
}

int main() {
Expand Down Expand Up @@ -82,7 +82,7 @@ void report_received_callback(uint8_t dev_addr, uint8_t instance, uint8_t const*
msg->dev_addr = dev_addr;
msg->interface = instance;
memcpy(msg->report, report, len);
serial_write((uint8_t*) msg, len + sizeof(report_received_t));
serial_write_nonblocking((uint8_t*) msg, len + sizeof(report_received_t));
}

void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len) {
Expand Down Expand Up @@ -137,7 +137,7 @@ void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance) {

void tuh_sof_cb() {
start_of_frame_t msg;
serial_write((uint8_t*) &msg, sizeof(msg));
serial_write_nonblocking((uint8_t*) &msg, sizeof(msg));
}

void get_report_cb(uint8_t dev_addr, uint8_t interface, uint8_t report_id, uint8_t report_type, uint8_t* report, uint16_t len) {
Expand Down Expand Up @@ -170,6 +170,6 @@ void tuh_midi_rx_cb(uint8_t dev_addr, uint32_t num_packets) {
msg->command = DualCommand::MIDI_RECEIVED;
msg->hub_port = hub_port;
while (tuh_midi_packet_read(dev_addr, msg->msg)) {
serial_write((uint8_t*) msg, sizeof(midi_received_t));
serial_write_nonblocking((uint8_t*) msg, sizeof(midi_received_t));
}
}
29 changes: 28 additions & 1 deletion firmware/src/serial.cc
Original file line number Diff line number Diff line change
Expand Up @@ -127,9 +127,30 @@ void send_escaped_byte(uint8_t b) {
}
}

void serial_write(const uint8_t* data, uint16_t len) {
bool serial_write(const uint8_t* data, uint16_t len, bool drop_if_blocking) {
uint32_t crc = crc32(data, len);

if (drop_if_blocking) {
// determine how many bytes would be written, including escaped characters
uint16_t bytes_to_send = len + 2 + 4;
for (uint16_t i = 0; i < len; i++) {
if ((data[i] == END) || (data[i] == ESC)) {
bytes_to_send++;
}
}
for (uint16_t i = 0; i < 4; i++) {
uint8_t b = crc >> (i * 8);
if ((b == END) || (b == ESC)) {
bytes_to_send++;
}
}
// drop if there's not enough space in the buffer
// uart also has as fifo, but it's not long
if (bytes_to_send > BUFFER_SIZE - buf_items) {
return false;
}
}

my_putc(END);

for (int i = 0; i < len; i++) {
Expand All @@ -141,4 +162,10 @@ void serial_write(const uint8_t* data, uint16_t len) {
}

my_putc(END);

return true;
}

bool serial_write_nonblocking(const uint8_t* data, uint16_t len) {
return serial_write(data, len, true);
}
3 changes: 2 additions & 1 deletion firmware/src/serial.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ typedef bool (*msg_recv_cb_t)(const uint8_t* data, uint16_t len);

void serial_init();
bool serial_read(msg_recv_cb_t callback);
void serial_write(const uint8_t* data, uint16_t len);
bool serial_write(const uint8_t* data, uint16_t len, bool drop_if_blocking = false);
bool serial_write_nonblocking(const uint8_t* data, uint16_t len);

#endif

0 comments on commit 334ec70

Please sign in to comment.