From f1773b634eb6cf4e1312379dcc7bcbab7291c60b Mon Sep 17 00:00:00 2001 From: Clyne Sullivan Date: Sun, 23 May 2021 13:19:09 -0400 Subject: [PATCH] 2nd pot; some doc; smooth WAV playback --- gui/wxmain_devdata.cpp | 24 +++++-- gui/wxmain_mrun.cpp | 22 +++--- source/adc.cpp | 19 ++--- source/adc.hpp | 2 +- source/dac.cpp | 18 ++++- source/dac.hpp | 4 +- source/elf_load.cpp | 2 +- source/elf_load.hpp | 2 +- source/main.cpp | 156 +++++++++++++++++++++++----------------- source/samplebuffer.cpp | 11 +++ source/samplebuffer.hpp | 11 +++ source/sclock.cpp | 11 +++ source/sclock.hpp | 11 +++ source/usbserial.cpp | 4 +- source/usbserial.hpp | 2 +- 15 files changed, 198 insertions(+), 101 deletions(-) diff --git a/gui/wxmain_devdata.cpp b/gui/wxmain_devdata.cpp index 551f6cc..7f736a2 100644 --- a/gui/wxmain_devdata.cpp +++ b/gui/wxmain_devdata.cpp @@ -49,16 +49,16 @@ const char *makefile_text_l4 = #endif "arm-none-eabi-g++ -x c++ -Os -std=c++20 -fno-exceptions -fno-rtti " "-mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 -mtune=cortex-m4 " - "-nostartfiles -I$1/cmsis" + "-nostartfiles -I$1/cmsis " "-Wl,-Ttext-segment=0x10000000 -Wl,-zmax-page-size=512 -Wl,-eprocess_data_entry " "$0 -o $0.o" NEWLINE - COPY " $0.o $0.orig.o" NEWLINE - "arm-none-eabi-strip -s -S --strip-unneeded $0.o" NEWLINE - "arm-none-eabi-objcopy --remove-section .ARM.attributes " + COPY " $0.o $0.orig.o" NEWLINE + "arm-none-eabi-strip -s -S --strip-unneeded $0.o" NEWLINE + "arm-none-eabi-objcopy --remove-section .ARM.attributes " "--remove-section .comment " "--remove-section .noinit " "$0.o" NEWLINE - "arm-none-eabi-size $0.o" NEWLINE; + "arm-none-eabi-size $0.o" NEWLINE; // $0 = buffer size const char *file_header_h7 = R"cpp( @@ -168,11 +168,21 @@ asm("vsqrt.f32 s0, s0; bx lr"); return 0; } -auto readalt() { +auto readpot1() { Sample s; -asm("push {r4-r6}; svc 3; mov %0, r0; pop {r4-r6}" : "=&r"(s)); +asm("push {r4-r6}; eor r0, r0; svc 3; mov %0, r0; pop {r4-r6}" : "=&r"(s)); return s; } +auto readpot2() { +Sample s; +asm("push {r4-r6}; mov r0, #1; svc 3; mov %0, r0; pop {r4-r6}" : "=&r"(s)); +return s; +} + +void puts(const char *s) { +// 's' will already be in r0. +asm("push {r4-r6}; svc 4; pop {r4-r6}"); +} // End stmdspgui header code diff --git a/gui/wxmain_mrun.cpp b/gui/wxmain_mrun.cpp index 58b1873..e12d068 100644 --- a/gui/wxmain_mrun.cpp +++ b/gui/wxmain_mrun.cpp @@ -48,18 +48,16 @@ void MainFrame::onRunStart(wxCommandEvent& ce) m_device->continuous_start_measure(); m_timer_performance->StartOnce(1000); } else { - if (m_device->is_siggening() && m_wav_clip) { - // TODO Confirm need for factor of 500 - m_timer_wavclip->Start(m_device->get_buffer_size() * 500 / - srateNums[m_rate_select->GetSelection()]); - } else if (m_conv_result_log) { - m_timer_record->Start(m_device->get_buffer_size() / - srateNums[m_rate_select->GetSelection()] * - 800 / 1000); - } else if (m_run_draw_samples->IsChecked()) { - m_timer_record->Start(m_device->get_buffer_size() / - srateNums[m_rate_select->GetSelection()]); - } + auto reqSpeedExact = + m_device->get_buffer_size() + / static_cast(srateNums[m_rate_select->GetSelection()]) + * 1000.f * 0.5f; + int reqSpeed = reqSpeedExact; + + if (m_device->is_siggening() && m_wav_clip) + m_timer_wavclip->Start(reqSpeed); + if (m_conv_result_log || m_run_draw_samples->IsChecked()) + m_timer_record->Start(reqSpeed); m_device->continuous_start(); } diff --git a/source/adc.cpp b/source/adc.cpp index 3ab5430..2a4fa38 100644 --- a/source/adc.cpp +++ b/source/adc.cpp @@ -2,7 +2,7 @@ * @file adc.cpp * @brief Manages signal reading through the ADC. * - * Copyright (C) 2020 Clyne Sullivan + * Copyright (C) 2021 Clyne Sullivan * * Distributed under the GNU GPL v3 or later. You should have received a copy of * the GNU General Public License along with this program. @@ -69,7 +69,7 @@ static void readAltCallback(ADCDriver *) } ADCConversionGroup ADC::m_group_config2 = { .circular = false, - .num_channels = 1, + .num_channels = 2, .end_cb = readAltCallback, .error_cb = nullptr, .cfgr = ADC_CFGR_EXTEN_RISING | ADC_CFGR_EXTSEL_SRC(13), /* TIM6_TRGO */ @@ -88,10 +88,10 @@ ADCConversionGroup ADC::m_group_config2 = { .awd3cr = 0, #endif .smpr = { - ADC_SMPR1_SMP_AN1(ADC_SMPR_SMP_12P5), 0 + ADC_SMPR1_SMP_AN1(ADC_SMPR_SMP_12P5) | ADC_SMPR1_SMP_AN2(ADC_SMPR_SMP_12P5), 0 }, .sqr = { - ADC_SQR1_SQ1_N(ADC_CHANNEL_IN1), + ADC_SQR1_SQ1_N(ADC_CHANNEL_IN1) | ADC_SQR1_SQ2_N(ADC_CHANNEL_IN2), 0, 0, 0 }, }; @@ -107,6 +107,7 @@ void ADC::begin() #else palSetPadMode(GPIOA, 0, PAL_MODE_INPUT_ANALOG); // Algorithm in palSetPadMode(GPIOC, 0, PAL_MODE_INPUT_ANALOG); // Potentiometer 1 + palSetPadMode(GPIOC, 1, PAL_MODE_INPUT_ANALOG); // Potentiometer 2 #endif adcStart(m_driver, &m_config); @@ -135,15 +136,15 @@ void ADC::stop() adcsample_t ADC::readAlt(unsigned int id) { - if (id != 0) + if (id > 1) return 0; - static adcsample_t result[32] = {}; + static adcsample_t result[16] = {}; readAltDone = false; - adcStartConversion(m_driver2, &m_group_config2, result, 32); + adcStartConversion(m_driver2, &m_group_config2, result, 8); while (!readAltDone) - ; + __WFI(); adcStopConversion(m_driver2); - return result[0]; + return result[id]; } void ADC::setRate(SClock::Rate rate) diff --git a/source/adc.hpp b/source/adc.hpp index 24a7fff..5f7fa08 100644 --- a/source/adc.hpp +++ b/source/adc.hpp @@ -2,7 +2,7 @@ * @file adc.hpp * @brief Manages signal reading through the ADC. * - * Copyright (C) 2020 Clyne Sullivan + * Copyright (C) 2021 Clyne Sullivan * * Distributed under the GNU GPL v3 or later. You should have received a copy of * the GNU General Public License along with this program. diff --git a/source/dac.cpp b/source/dac.cpp index ce9c465..2772928 100644 --- a/source/dac.cpp +++ b/source/dac.cpp @@ -2,7 +2,7 @@ * @file dac.cpp * @brief Manages signal creation using the DAC. * - * Copyright (C) 2020 Clyne Sullivan + * Copyright (C) 2021 Clyne Sullivan * * Distributed under the GNU GPL v3 or later. You should have received a copy of * the GNU General Public License along with this program. @@ -22,9 +22,16 @@ const DACConfig DAC::m_config = { .cr = 0 }; +static int dacIsDone = -1; +static void dacEndCallback(DACDriver *dacd) +{ + if (dacd == &DACD2) + dacIsDone = dacIsBufferComplete(dacd) ? 1 : 0; +} + const DACConversionGroup DAC::m_group_config = { .num_channels = 1, - .end_cb = nullptr, + .end_cb = dacEndCallback, .error_cb = nullptr, #if defined(TARGET_PLATFORM_H7) .trigger = 5 // TIM6_TRGO @@ -45,11 +52,18 @@ void DAC::begin() void DAC::start(int channel, dacsample_t *buffer, size_t count) { if (channel >= 0 && channel < 2) { + if (channel == 1) + dacIsDone = -1; dacStartConversion(m_driver[channel], &m_group_config, buffer, count); SClock::start(); } } +int DAC::sigGenWantsMore() +{ + return dacIsDone; +} + void DAC::stop(int channel) { if (channel >= 0 && channel < 2) { diff --git a/source/dac.hpp b/source/dac.hpp index e305c4b..4360c26 100644 --- a/source/dac.hpp +++ b/source/dac.hpp @@ -2,7 +2,7 @@ * @file dac.hpp * @brief Manages signal creation using the DAC. * - * Copyright (C) 2020 Clyne Sullivan + * Copyright (C) 2021 Clyne Sullivan * * Distributed under the GNU GPL v3 or later. You should have received a copy of * the GNU General Public License along with this program. @@ -23,6 +23,8 @@ public: static void start(int channel, dacsample_t *buffer, size_t count); static void stop(int channel); + static int sigGenWantsMore(); + private: static DACDriver *m_driver[2]; diff --git a/source/elf_load.cpp b/source/elf_load.cpp index 0e41d6a..e161206 100644 --- a/source/elf_load.cpp +++ b/source/elf_load.cpp @@ -2,7 +2,7 @@ * @file elf_load.cpp * @brief Loads ELF binary data into memory for execution. * - * Copyright (C) 2020 Clyne Sullivan + * Copyright (C) 2021 Clyne Sullivan * * Distributed under the GNU GPL v3 or later. You should have received a copy of * the GNU General Public License along with this program. diff --git a/source/elf_load.hpp b/source/elf_load.hpp index 619dada..ae7265b 100644 --- a/source/elf_load.hpp +++ b/source/elf_load.hpp @@ -2,7 +2,7 @@ * @file elf_load.hpp * @brief Loads ELF binary data into memory for execution. * - * Copyright (C) 2020 Clyne Sullivan + * Copyright (C) 2021 Clyne Sullivan * * Distributed under the GNU GPL v3 or later. You should have received a copy of * the GNU General Public License along with this program. diff --git a/source/main.cpp b/source/main.cpp index aaf268a..e9c33ef 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -2,7 +2,7 @@ * @file main.cpp * @brief Program entry point. * - * Copyright (C) 2020 Clyne Sullivan + * Copyright (C) 2021 Clyne Sullivan * * Distributed under the GNU GPL v3 or later. You should have received a copy of * the GNU General Public License along with this program. @@ -26,8 +26,16 @@ static_assert(sizeof(dacsample_t) == sizeof(uint16_t)); #include -constexpr unsigned int MAX_ELF_FILE_SIZE = 16 * 1024; +// Pin definitions +// +#if defined(TARGET_PLATFORM_L4) +constexpr auto LINE_LED_GREEN = PAL_LINE(GPIOC_BASE, 10U); +constexpr auto LINE_LED_YELLOW = PAL_LINE(GPIOC_BASE, 11U); +constexpr auto LINE_LED_RED = PAL_LINE(GPIOC_BASE, 12U); +#endif +// Run status +// enum class RunStatus : char { Idle = '1', @@ -36,6 +44,8 @@ enum class RunStatus : char }; static RunStatus run_status = RunStatus::Idle; +// Conversion threads messaging +// #define MSG_CONVFIRST (1) #define MSG_CONVSECOND (2) #define MSG_CONVFIRST_MEASURE (3) @@ -44,43 +54,11 @@ static RunStatus run_status = RunStatus::Idle; #define MSG_FOR_FIRST(m) (m & 1) #define MSG_FOR_MEASURE(m) (m > 2) -static ErrorManager EM; - static msg_t conversionMBBuffer[2]; static MAILBOX_DECL(conversionMB, conversionMBBuffer, 2); -// Thread for LED status and wakeup hold -__attribute__((section(".stacks"))) -static THD_WORKING_AREA(monitorThreadWA, 256); -static THD_FUNCTION(monitorThread, arg); - -// Thread for managing the conversion task -__attribute__((section(".stacks"))) -static THD_WORKING_AREA(conversionThreadMonitorWA, 1024); -static THD_FUNCTION(conversionThreadMonitor, arg); -static thread_t *conversionThreadHandle = nullptr; - -// Thread for unprivileged algorithm execution -__attribute__((section(".stacks"))) -static THD_WORKING_AREA(conversionThreadWA, 128); // All we do is enter unprivileged mode. -static THD_FUNCTION(conversionThread, arg); -constexpr unsigned int conversionThreadUPWASize = -#if defined(TARGET_PLATFORM_H7) - 62 * 1024; -#else - 15 * 1024; -#endif -__attribute__((section(".convdata"))) -static THD_WORKING_AREA(conversionThreadUPWA, conversionThreadUPWASize); -__attribute__((section(".convdata"))) -static thread_t *conversionThreadMonitorHandle = nullptr; - -// Thread for USB monitoring -__attribute__((section(".stacks"))) -static THD_WORKING_AREA(communicationThreadWA, 4096); -static THD_FUNCTION(communicationThread, arg); - -static time_measurement_t conversion_time_measurement; +// Sample input and output buffers +// #if defined(TARGET_PLATFORM_H7) __attribute__((section(".convdata"))) static SampleBuffer samplesIn (reinterpret_cast(0x38000000)); // 16k @@ -95,35 +73,38 @@ static SampleBuffer samplesOut (reinterpret_cast(0x2000C000)); // 16k static SampleBuffer samplesSigGen (reinterpret_cast(0x20010000)); // 16k #endif +// Algorithm binary storage +// +constexpr unsigned int MAX_ELF_FILE_SIZE = 16 * 1024; static unsigned char elf_file_store[MAX_ELF_FILE_SIZE]; __attribute__((section(".convdata"))) static ELF::Entry elf_entry = nullptr; +// Other variables +// +static ErrorManager EM; +static time_measurement_t conversion_time_measurement; static char userMessageBuffer[128]; static unsigned char userMessageSize = 0; +// Functions +// __attribute__((section(".convcode"))) static void conversion_unprivileged_main(); - -static void mpu_setup(); +static void startThreads(); +static void mpuSetup(); static void abortAlgorithmFromISR(); -static void signal_operate(adcsample_t *buffer, size_t count); -static void signal_operate_measure(adcsample_t *buffer, size_t count); - -#if defined(TARGET_PLATFORM_L4) -constexpr auto LINE_LED_GREEN = PAL_LINE(GPIOC_BASE, 10U); -constexpr auto LINE_LED_YELLOW = PAL_LINE(GPIOC_BASE, 11U); -constexpr auto LINE_LED_RED = PAL_LINE(GPIOC_BASE, 12U); -#endif +static void signalOperate(adcsample_t *buffer, size_t count); +static void signalOperateMeasure(adcsample_t *buffer, size_t count); int main() { - // Initialize the RTOS + // Initialize ChibiOS halInit(); chSysInit(); SCB->CPACR |= 0xF << 20; // Enable FPU - mpu_setup(); + mpuSetup(); #if defined(TARGET_PLATFORM_L4) palSetLineMode(LINE_LED_GREEN, PAL_MODE_OUTPUT_PUSHPULL); @@ -140,7 +121,42 @@ int main() SClock::setRate(SClock::Rate::R32K); ADC::setRate(SClock::Rate::R32K); - chTMObjectInit(&conversion_time_measurement); + startThreads(); + chThdExit(0); + return 0; +} + +static THD_FUNCTION(monitorThread, arg); // Runs status LEDs and allows debug halt. +static THD_FUNCTION(conversionThreadMonitor, arg); // Monitors and manages algo. thread. +static THD_FUNCTION(conversionThread, arg); // Algorithm thread (unprivileged). +static THD_FUNCTION(communicationThread, arg); // Manages USB communications. + +// Need to hold some thread handles for mailbox usage. +static thread_t *conversionThreadHandle = nullptr; +__attribute__((section(".convdata"))) +static thread_t *conversionThreadMonitorHandle = nullptr; + +// The more stack for the algorithm, the merrier. +constexpr unsigned int conversionThreadUPWASize = +#if defined(TARGET_PLATFORM_H7) + 62 * 1024; +#else + 15 * 1024; +#endif + +__attribute__((section(".stacks"))) +static THD_WORKING_AREA(monitorThreadWA, 256); +__attribute__((section(".stacks"))) +static THD_WORKING_AREA(conversionThreadMonitorWA, 1024); +__attribute__((section(".stacks"))) +static THD_WORKING_AREA(conversionThreadWA, 128); // For entering unprivileged mode. +__attribute__((section(".convdata"))) +static THD_WORKING_AREA(conversionThreadUPWA, conversionThreadUPWASize); +__attribute__((section(".stacks"))) +static THD_WORKING_AREA(communicationThreadWA, 4096); + +void startThreads() +{ chThdCreateStatic( monitorThreadWA, sizeof(monitorThreadWA), LOWPRIO, @@ -149,19 +165,17 @@ int main() conversionThreadMonitorWA, sizeof(conversionThreadMonitorWA), NORMALPRIO + 1, conversionThreadMonitor, nullptr); + auto conversionThreadUPWAEnd = + reinterpret_cast(conversionThreadUPWA) + conversionThreadUPWASize; conversionThreadHandle = chThdCreateStatic( conversionThreadWA, sizeof(conversionThreadWA), HIGHPRIO, conversionThread, - reinterpret_cast(reinterpret_cast(conversionThreadUPWA) + - conversionThreadUPWASize)); + reinterpret_cast(conversionThreadUPWAEnd)); chThdCreateStatic( communicationThreadWA, sizeof(communicationThreadWA), NORMALPRIO, communicationThread, nullptr); - - chThdExit(0); - return 0; } THD_FUNCTION(communicationThread, arg) @@ -190,7 +204,7 @@ THD_FUNCTION(communicationThread, arg) // 'S' - Stop conversion. // 's' - Get latest block of conversion results. // 't' - Get latest block of conversion input. - // 'u' - Get user message. + // 'u' - Get user message. // 'W' - Start signal generator (siggen). // 'w' - Stop siggen. @@ -222,8 +236,22 @@ THD_FUNCTION(communicationThread, arg) if (EM.assert(USBSerial::read(&cmd[1], 2) == 2, Error::BadParamSize)) { unsigned int count = cmd[1] | (cmd[2] << 8); if (EM.assert(count <= MAX_SAMPLE_BUFFER_SIZE, Error::BadParam)) { - samplesSigGen.setSize(count); - USBSerial::read(samplesSigGen.bytedata(), samplesSigGen.bytesize()); + if (run_status == RunStatus::Idle) { + samplesSigGen.setSize(count * 2); + USBSerial::read( + reinterpret_cast(samplesSigGen.middata()), + samplesSigGen.bytesize() / 2); + } else if (run_status == RunStatus::Running) { + int more; + do { + chThdSleepMicroseconds(10); + more = DAC::sigGenWantsMore(); + } while (more == -1); + + USBSerial::read(reinterpret_cast( + more == 0 ? samplesSigGen.data() : samplesSigGen.middata()), + samplesSigGen.bytesize() / 2); + } } } break; @@ -275,7 +303,7 @@ THD_FUNCTION(communicationThread, arg) if (EM.assert(run_status == RunStatus::Idle, Error::NotIdle)) { run_status = RunStatus::Running; samplesOut.clear(); - ADC::start(samplesIn.data(), samplesIn.size(), signal_operate_measure); + ADC::start(samplesIn.data(), samplesIn.size(), signalOperateMeasure); DAC::start(0, samplesOut.data(), samplesOut.size()); } break; @@ -293,7 +321,7 @@ THD_FUNCTION(communicationThread, arg) if (EM.assert(run_status == RunStatus::Idle, Error::NotIdle)) { run_status = RunStatus::Running; samplesOut.clear(); - ADC::start(samplesIn.data(), samplesIn.size(), signal_operate); + ADC::start(samplesIn.data(), samplesIn.size(), signalOperate); DAC::start(0, samplesOut.data(), samplesOut.size()); } break; @@ -488,7 +516,7 @@ void conversion_unprivileged_main() } } -void mpu_setup() +void mpuSetup() { // Set up MPU for user algorithm #if defined(TARGET_PLATFORM_H7) @@ -561,7 +589,7 @@ void abortAlgorithmFromISR() } } -void signal_operate(adcsample_t *buffer, size_t) +void signalOperate(adcsample_t *buffer, size_t) { chSysLockFromISR(); @@ -582,7 +610,7 @@ void signal_operate(adcsample_t *buffer, size_t) } } -void signal_operate_measure(adcsample_t *buffer, [[maybe_unused]] size_t count) +void signalOperateMeasure(adcsample_t *buffer, [[maybe_unused]] size_t count) { chSysLockFromISR(); if (buffer == samplesIn.data()) { @@ -594,7 +622,7 @@ void signal_operate_measure(adcsample_t *buffer, [[maybe_unused]] size_t count) } chSysUnlockFromISR(); - ADC::setOperation(signal_operate); + ADC::setOperation(signalOperate); } extern "C" { @@ -654,7 +682,7 @@ void port_syscall(struct port_extctx *ctxp, uint32_t n) } break; case 3: - ctxp->r0 = ADC::readAlt(0); + ctxp->r0 = ADC::readAlt(ctxp->r0); break; case 4: { diff --git a/source/samplebuffer.cpp b/source/samplebuffer.cpp index 24cc424..1acf2f4 100644 --- a/source/samplebuffer.cpp +++ b/source/samplebuffer.cpp @@ -1,3 +1,14 @@ +/** + * @file samplebuffer.cpp + * @brief Manages ADC/DAC buffer data. + * + * Copyright (C) 2021 Clyne Sullivan + * + * Distributed under the GNU GPL v3 or later. You should have received a copy of + * the GNU General Public License along with this program. + * If not, see . + */ + #include "samplebuffer.hpp" SampleBuffer::SampleBuffer(Sample *buffer) : diff --git a/source/samplebuffer.hpp b/source/samplebuffer.hpp index 6d17d2a..d13023a 100644 --- a/source/samplebuffer.hpp +++ b/source/samplebuffer.hpp @@ -1,3 +1,14 @@ +/** + * @file samplebuffer.hpp + * @brief Manages ADC/DAC buffer data. + * + * Copyright (C) 2021 Clyne Sullivan + * + * Distributed under the GNU GPL v3 or later. You should have received a copy of + * the GNU General Public License along with this program. + * If not, see . + */ + #ifndef SAMPLEBUFFER_HPP_ #define SAMPLEBUFFER_HPP_ diff --git a/source/sclock.cpp b/source/sclock.cpp index 198c684..317b995 100644 --- a/source/sclock.cpp +++ b/source/sclock.cpp @@ -1,3 +1,14 @@ +/** + * @file sclock.cpp + * @brief Manages sampling rate clock speeds. + * + * Copyright (C) 2021 Clyne Sullivan + * + * Distributed under the GNU GPL v3 or later. You should have received a copy of + * the GNU General Public License along with this program. + * If not, see . + */ + #include "sclock.hpp" GPTDriver *SClock::m_timer = &GPTD6; diff --git a/source/sclock.hpp b/source/sclock.hpp index 960d9e3..d5b93df 100644 --- a/source/sclock.hpp +++ b/source/sclock.hpp @@ -1,3 +1,14 @@ +/** + * @file sclock.hpp + * @brief Manages sampling rate clock speeds. + * + * Copyright (C) 2021 Clyne Sullivan + * + * Distributed under the GNU GPL v3 or later. You should have received a copy of + * the GNU General Public License along with this program. + * If not, see . + */ + #ifndef SCLOCK_HPP_ #define SCLOCK_HPP_ diff --git a/source/usbserial.cpp b/source/usbserial.cpp index c24be2f..775a911 100644 --- a/source/usbserial.cpp +++ b/source/usbserial.cpp @@ -2,7 +2,7 @@ * @file usbserial.cpp * @brief Wrapper for ChibiOS's SerialUSBDriver. * - * Copyright (C) 2020 Clyne Sullivan + * Copyright (C) 2021 Clyne Sullivan * * Distributed under the GNU GPL v3 or later. You should have received a copy of * the GNU General Public License along with this program. @@ -32,7 +32,7 @@ bool USBSerial::isActive() { if (auto config = m_driver->config; config != nullptr) { if (auto usbp = config->usbp; usbp != nullptr) - return usbp->state == USB_ACTIVE; + return usbp->state == USB_ACTIVE && !ibqIsEmptyI(&m_driver->ibqueue); } return false; diff --git a/source/usbserial.hpp b/source/usbserial.hpp index 828fc56..58113c9 100644 --- a/source/usbserial.hpp +++ b/source/usbserial.hpp @@ -2,7 +2,7 @@ * @file usbserial.hpp * @brief Wrapper for ChibiOS's SerialUSBDriver. * - * Copyright (C) 2020 Clyne Sullivan + * Copyright (C) 2021 Clyne Sullivan * * Distributed under the GNU GPL v3 or later. You should have received a copy of * the GNU General Public License along with this program.