aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClyne Sullivan <clyne@bitgloo.com>2021-05-23 13:19:09 -0400
committerClyne Sullivan <clyne@bitgloo.com>2021-05-23 13:19:09 -0400
commitf1773b634eb6cf4e1312379dcc7bcbab7291c60b (patch)
tree2fe10536100230e7e6a3b597147f51ba4ddc32d8
parentd2f50fb9259a3142fa6b319a7a735a0e19355d01 (diff)
2nd pot; some doc; smooth WAV playback
-rw-r--r--gui/wxmain_devdata.cpp24
-rw-r--r--gui/wxmain_mrun.cpp22
-rw-r--r--source/adc.cpp19
-rw-r--r--source/adc.hpp2
-rw-r--r--source/dac.cpp18
-rw-r--r--source/dac.hpp4
-rw-r--r--source/elf_load.cpp2
-rw-r--r--source/elf_load.hpp2
-rw-r--r--source/main.cpp156
-rw-r--r--source/samplebuffer.cpp11
-rw-r--r--source/samplebuffer.hpp11
-rw-r--r--source/sclock.cpp11
-rw-r--r--source/sclock.hpp11
-rw-r--r--source/usbserial.cpp4
-rw-r--r--source/usbserial.hpp2
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<float>(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 <array>
-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<Sample *>(0x38000000)); // 16k
@@ -95,35 +73,38 @@ static SampleBuffer samplesOut (reinterpret_cast<Sample *>(0x2000C000)); // 16k
static SampleBuffer samplesSigGen (reinterpret_cast<Sample *>(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<uint32_t>(conversionThreadUPWA) + conversionThreadUPWASize;
conversionThreadHandle = chThdCreateStatic(
conversionThreadWA, sizeof(conversionThreadWA),
HIGHPRIO,
conversionThread,
- reinterpret_cast<void *>(reinterpret_cast<uint32_t>(conversionThreadUPWA) +
- conversionThreadUPWASize));
+ reinterpret_cast<void *>(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<uint8_t *>(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<uint8_t *>(
+ 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 <https://www.gnu.org/licenses/>.
+ */
+
#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 <https://www.gnu.org/licenses/>.
+ */
+
#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 <https://www.gnu.org/licenses/>.
+ */
+
#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 <https://www.gnu.org/licenses/>.
+ */
+
#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.