From 7a4c3184a16de93d4e3584258b1234bd0553f66e Mon Sep 17 00:00:00 2001 From: Bernd Herzog Date: Sat, 13 Jan 2024 18:05:29 +0100 Subject: [PATCH] reworked usb serial communication (#1766) --- firmware/application/CMakeLists.txt | 3 +- firmware/application/event_m0.cpp | 9 +- firmware/application/event_m0.hpp | 1 + firmware/application/usb_serial.cpp | 10 +- firmware/application/usb_serial.hpp | 1 + firmware/application/usb_serial_cdc.c | 11 +- ...erial_io.c => usb_serial_device_to_host.c} | 39 +----- ...erial_io.h => usb_serial_device_to_host.h} | 2 - .../application/usb_serial_host_to_device.cpp | 122 ++++++++++++++++++ .../application/usb_serial_host_to_device.hpp | 32 +++++ firmware/application/usb_serial_shell.cpp | 2 +- .../usb_serial_shell_filesystem.cpp | 5 +- firmware/application/usb_serial_thread.hpp | 2 +- firmware/common/ui_widget.cpp | 2 +- 14 files changed, 188 insertions(+), 53 deletions(-) rename firmware/application/{usb_serial_io.c => usb_serial_device_to_host.c} (82%) rename firmware/application/{usb_serial_io.h => usb_serial_device_to_host.h} (93%) create mode 100644 firmware/application/usb_serial_host_to_device.cpp create mode 100644 firmware/application/usb_serial_host_to_device.hpp diff --git a/firmware/application/CMakeLists.txt b/firmware/application/CMakeLists.txt index b03955e15..2eae541ed 100644 --- a/firmware/application/CMakeLists.txt +++ b/firmware/application/CMakeLists.txt @@ -116,7 +116,7 @@ set(CSRC usb_serial_cdc.c usb_serial_descriptor.c usb_serial_endpoints.c - usb_serial_io.c + usb_serial_device_to_host.c ${HACKRF_PATH}/firmware/common/usb.c ${HACKRF_PATH}/firmware/common/usb_queue.c ${HACKRF_PATH}/firmware/hackrf_usb/usb_device.c @@ -207,6 +207,7 @@ set(CPPSRC usb_serial_event.cpp usb_serial_thread.cpp usb_serial.cpp + usb_serial_host_to_device.cpp qrcodegen.cpp radio.cpp receiver_model.cpp diff --git a/firmware/application/event_m0.cpp b/firmware/application/event_m0.cpp index 12fc81977..3225ce479 100644 --- a/firmware/application/event_m0.cpp +++ b/firmware/application/event_m0.cpp @@ -164,9 +164,8 @@ void EventDispatcher::dispatch(const eventmask_t events) { handle_rtc_tick(); } - if (events & EVT_MASK_USB) { - handle_usb(); - } + handle_usb_transfer(); + handle_usb(); if (events & EVT_MASK_SWITCHES) { handle_switches(); @@ -225,6 +224,10 @@ void EventDispatcher::handle_usb() { portapack::usb_serial.dispatch(); } +void EventDispatcher::handle_usb_transfer() { + portapack::usb_serial.dispatch_transfer(); +} + void EventDispatcher::handle_shell() { if (waiting_for_shellmode) { waiting_for_shellmode = false; diff --git a/firmware/application/event_m0.hpp b/firmware/application/event_m0.hpp index a4a3cfe07..f84ba1b46 100644 --- a/firmware/application/event_m0.hpp +++ b/firmware/application/event_m0.hpp @@ -122,6 +122,7 @@ class EventDispatcher { void handle_local_queue(); void handle_rtc_tick(); void handle_usb(); + void handle_usb_transfer(); void handle_shell(); static ui::Widget* touch_widget(ui::Widget* const w, ui::TouchEvent event); diff --git a/firmware/application/usb_serial.cpp b/firmware/application/usb_serial.cpp index bf32e40ae..f419588fc 100644 --- a/firmware/application/usb_serial.cpp +++ b/firmware/application/usb_serial.cpp @@ -1,11 +1,12 @@ extern "C" { -#include "usb_serial_io.h" +#include "usb_serial_device_to_host.h" #include "usb_serial_cdc.h" } #include "usb_serial_shell.hpp" #include "usb_serial.hpp" #include "portapack.hpp" +#include "usb_serial_host_to_device.hpp" #include #include @@ -24,6 +25,7 @@ void USBSerial::initialize() { init_serial_usb_driver(&SUSBD1); shellInit(); + init_host_to_device(); } void USBSerial::dispatch() { @@ -35,7 +37,11 @@ void USBSerial::dispatch() { create_shell(_eventDispatcher); } - bulk_out_receive(); + schedule_host_to_device_transfer(); +} + +void USBSerial::dispatch_transfer() { + complete_host_to_device_transfer(); } void USBSerial::on_channel_opened() { diff --git a/firmware/application/usb_serial.hpp b/firmware/application/usb_serial.hpp index 55e1900bc..af3f2c4ec 100644 --- a/firmware/application/usb_serial.hpp +++ b/firmware/application/usb_serial.hpp @@ -32,6 +32,7 @@ class USBSerial { public: void initialize(); void dispatch(); + void dispatch_transfer(); void on_channel_opened(); void on_channel_closed(); void setEventDispatcher(EventDispatcher* ed) { _eventDispatcher = ed; } diff --git a/firmware/application/usb_serial_cdc.c b/firmware/application/usb_serial_cdc.c index 57ffdfea9..ef254511b 100644 --- a/firmware/application/usb_serial_cdc.c +++ b/firmware/application/usb_serial_cdc.c @@ -31,11 +31,16 @@ static Thread* thread_usb_event = NULL; CH_IRQ_HANDLER(USB0_IRQHandler) { CH_IRQ_PROLOGUE(); + + const uint32_t status = USB0_USBSTS_D & USB0_USBINTR_D; + usb0_isr(); - chSysLockFromIsr(); - chEvtSignalI(thread_usb_event, EVT_MASK_USB); - chSysUnlockFromIsr(); + if (status & USB0_USBSTS_D_UI) { + chSysLockFromIsr(); + chEvtSignalI(thread_usb_event, EVT_MASK_USB); + chSysUnlockFromIsr(); + } CH_IRQ_EPILOGUE(); } diff --git a/firmware/application/usb_serial_io.c b/firmware/application/usb_serial_device_to_host.c similarity index 82% rename from firmware/application/usb_serial_io.c rename to firmware/application/usb_serial_device_to_host.c index aa1439c19..60ed02a4b 100644 --- a/firmware/application/usb_serial_io.c +++ b/firmware/application/usb_serial_device_to_host.c @@ -19,7 +19,7 @@ * Boston, MA 02110-1301, USA. */ -#include "usb_serial_io.h" +#include "usb_serial_device_to_host.h" #include "usb_serial_endpoints.h" @@ -40,43 +40,6 @@ SerialUSBDriver SUSBD1; -uint8_t usb_bulk_buffer[USB_BULK_BUFFER_SIZE]; - -void bulk_out_receive(void) { - int ret; - - while (chIQGetEmptyI(&SUSBD1.iqueue) < USB_BULK_BUFFER_SIZE) - chThdSleepMilliseconds(1); // wait for shell thread when buffer is full - - do { - ret = usb_transfer_schedule( - &usb_endpoint_bulk_out, - &usb_bulk_buffer[0], - USB_BULK_BUFFER_SIZE, - serial_bulk_transfer_complete, - NULL); - - } while (ret != -1); -} - -void serial_bulk_transfer_complete(void* user_data, unsigned int bytes_transferred) { - (void)user_data; - - chSysLockFromIsr(); - for (unsigned int i = 0; i < bytes_transferred; i++) { - msg_t ret; - do { - ret = chIQPutI(&SUSBD1.iqueue, usb_bulk_buffer[i]); - - if (ret == Q_FULL) { - chDbgPanic("USB iqueue buffer full"); - } - - } while (ret == Q_FULL); - } - chSysUnlockFromIsr(); -} - static void onotify(GenericQueue* qp) { SerialUSBDriver* sdp = chQGetLink(qp); uint8_t buff[USBSERIAL_BUFFERS_SIZE]; diff --git a/firmware/application/usb_serial_io.h b/firmware/application/usb_serial_device_to_host.h similarity index 93% rename from firmware/application/usb_serial_io.h rename to firmware/application/usb_serial_device_to_host.h index 614f58c8a..77f688dee 100644 --- a/firmware/application/usb_serial_io.h +++ b/firmware/application/usb_serial_device_to_host.h @@ -48,8 +48,6 @@ typedef struct SerialUSBDriver SerialUSBDriver; extern SerialUSBDriver SUSBD1; void init_serial_usb_driver(SerialUSBDriver* sdp); -void bulk_out_receive(void); -void serial_bulk_transfer_complete(void* user_data, unsigned int bytes_transferred); #ifdef __cplusplus extern "C" { diff --git a/firmware/application/usb_serial_host_to_device.cpp b/firmware/application/usb_serial_host_to_device.cpp new file mode 100644 index 000000000..0d64e749c --- /dev/null +++ b/firmware/application/usb_serial_host_to_device.cpp @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2023 Bernd Herzog + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "usb_serial_host_to_device.hpp" +#include "event_m0.hpp" +#include "usb_serial_device_to_host.h" + +extern "C" { +#include +#include +#include +} + +#include +#include + +static Thread* thread_usb_event = NULL; + +struct usb_bulk_buffer_t { + uint8_t* data; + size_t length; + bool completed; +}; + +std::queue usb_bulk_buffer_queue; +std::queue usb_bulk_buffer_spare; + +void serial_bulk_transfer_complete(void* user_data, unsigned int bytes_transferred) { + usb_bulk_buffer_t* transfer_data = (usb_bulk_buffer_t*)user_data; + + transfer_data->length = bytes_transferred; + transfer_data->completed = true; +} + +void init_host_to_device() { + thread_usb_event = chThdSelf(); +} + +void schedule_host_to_device_transfer() { + if (usb_bulk_buffer_queue.size() >= 8) + return; + + static usb_bulk_buffer_t* transfer_data = nullptr; + + int ret; + + do { + if (transfer_data == nullptr) { + if (usb_bulk_buffer_spare.empty() == false) { + transfer_data = usb_bulk_buffer_spare.front(); + transfer_data->length = 0; + transfer_data->completed = false; + usb_bulk_buffer_spare.pop(); + } else { + transfer_data = new usb_bulk_buffer_t{ + .data = new uint8_t[USB_BULK_BUFFER_SIZE], + .length = 0, + .completed = false}; + } + } + + ret = usb_transfer_schedule( + &usb_endpoint_bulk_out, + transfer_data->data, + USB_BULK_BUFFER_SIZE, + serial_bulk_transfer_complete, + transfer_data); + + if (ret != -1) { + usb_bulk_buffer_queue.push(transfer_data); + transfer_data = nullptr; + + if (usb_bulk_buffer_queue.size() >= 8) + return; + } + } while (ret != -1); +} + +void complete_host_to_device_transfer() { + for (; !usb_bulk_buffer_queue.empty(); usb_bulk_buffer_queue.pop()) { + usb_bulk_buffer_t* transfer_data = usb_bulk_buffer_queue.front(); + + while (transfer_data->completed == false) + return; + + chSysLock(); + for (unsigned int i = 0; i < transfer_data->length; i++) { + msg_t ret; + do { + ret = chIQPutI(&SUSBD1.iqueue, transfer_data->data[i]); + + if (ret == Q_FULL) { + chSysUnlock(); + chThdSleepMilliseconds(1); // wait for shell thread when buffer is full + chSysLock(); + } + + } while (ret == Q_FULL); + } + chSysUnlock(); + + usb_bulk_buffer_spare.push(transfer_data); + } +} diff --git a/firmware/application/usb_serial_host_to_device.hpp b/firmware/application/usb_serial_host_to_device.hpp new file mode 100644 index 000000000..5c89a73b5 --- /dev/null +++ b/firmware/application/usb_serial_host_to_device.hpp @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2023 Bernd Herzog + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#pragma once + +#include "ch.h" +#include "hal.h" + +#define USB_BULK_BUFFER_SIZE 64 + +void init_host_to_device(); +void serial_bulk_transfer_complete(void* user_data, unsigned int bytes_transferred); +void schedule_host_to_device_transfer(); +void complete_host_to_device_transfer(); diff --git a/firmware/application/usb_serial_shell.cpp b/firmware/application/usb_serial_shell.cpp index 8cb6c7dea..7b081b178 100644 --- a/firmware/application/usb_serial_shell.cpp +++ b/firmware/application/usb_serial_shell.cpp @@ -36,7 +36,7 @@ #include "crc.hpp" #include "hackrf_cpld_data.hpp" -#include "usb_serial_io.h" +#include "usb_serial_device_to_host.h" #include "chprintf.h" #include "chqueues.h" #include "ui_external_items_menu_loader.hpp" diff --git a/firmware/application/usb_serial_shell_filesystem.cpp b/firmware/application/usb_serial_shell_filesystem.cpp index b4ae90e42..821c30193 100644 --- a/firmware/application/usb_serial_shell_filesystem.cpp +++ b/firmware/application/usb_serial_shell_filesystem.cpp @@ -20,7 +20,7 @@ */ #include "usb_serial_shell_filesystem.hpp" -#include "usb_serial_io.h" +#include "usb_serial_device_to_host.h" #include "chprintf.h" #include "string_format.hpp" @@ -172,6 +172,9 @@ void cmd_sd_close(BaseSequentialStream* chp, int argc, char* argv[]) { return; } + auto error = shell_file->sync(); + if (report_on_error(chp, error)) return; + delete shell_file; shell_file = nullptr; diff --git a/firmware/application/usb_serial_thread.hpp b/firmware/application/usb_serial_thread.hpp index 252bbafe4..05ee70dbc 100644 --- a/firmware/application/usb_serial_thread.hpp +++ b/firmware/application/usb_serial_thread.hpp @@ -30,7 +30,7 @@ #include "optional.hpp" #include "chprintf.h" -#include "usb_serial_io.h" +#include "usb_serial_device_to_host.h" #include #include diff --git a/firmware/common/ui_widget.cpp b/firmware/common/ui_widget.cpp index 4860173f2..2f654c055 100644 --- a/firmware/common/ui_widget.cpp +++ b/firmware/common/ui_widget.cpp @@ -31,7 +31,7 @@ #include "chprintf.h" #include "irq_controls.hpp" #include "string_format.hpp" -#include "usb_serial_io.h" +#include "usb_serial_device_to_host.h" using namespace portapack;