From 4611bbac2341e9e586434b45637fe00ec0e33478 Mon Sep 17 00:00:00 2001
From: Clyne Sullivan <clyne@bitgloo.com>
Date: Thu, 24 Sep 2020 09:48:08 -0400
Subject: better elf management and error recovery

---
 Makefile        |   2 +-
 gui/wxmain.cpp  |  12 ++----
 source/adc.cpp  |  25 +++++++-----
 source/dac.cpp  |   2 +-
 source/main.cpp | 122 ++++++++++++++++++++++++++++----------------------------
 5 files changed, 81 insertions(+), 82 deletions(-)

diff --git a/Makefile b/Makefile
index 75633ed..50e7905 100644
--- a/Makefile
+++ b/Makefile
@@ -55,7 +55,7 @@ endif
 # Stack size to be allocated to the Cortex-M process stack. This stack is
 # the stack used by the main() thread.
 ifeq ($(USE_PROCESS_STACKSIZE),)
-  USE_PROCESS_STACKSIZE = 0x400
+  USE_PROCESS_STACKSIZE = 8192
 endif
 
 # Stack size to the allocated to the Cortex-M main/exceptions stack. This
diff --git a/gui/wxmain.cpp b/gui/wxmain.cpp
index fa9118d..0c6c9b3 100644
--- a/gui/wxmain.cpp
+++ b/gui/wxmain.cpp
@@ -181,7 +181,8 @@ void MainFrame::prepareEditor()
 
 static const char *makefile_text = R"make(
 all:
-	@arm-none-eabi-g++ -x c++ -mcpu=cortex-m4 -mthumb -Os --specs=nosys.specs -nostartfiles -fPIE $0 -o $0.o -Wl,-Ttext-segment=0 -Wl,-eprocess_data_entry -Wl,-zmax-page-size=512
+	@arm-none-eabi-g++ -x c++ -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Os --specs=nosys.specs -nostartfiles -fPIE $0 -o $0.o -Wl,-Ttext-segment=0 -Wl,-eprocess_data_entry -Wl,-zmax-page-size=512
+	@cp $0.o $0.orig.o
 	@arm-none-eabi-strip -s -S --strip-unneeded $0.o
 	@arm-none-eabi-objcopy --remove-section .ARM.exidx \
                            --remove-section .ARM.attributes \
@@ -195,14 +196,7 @@ static const char *file_header = R"cpp(
 
 using adcsample_t = uint16_t;
 
-static void process_data(adcsample_t *samples, unsigned int size);
-
-__attribute__((optimize("-O0")))
-static void *alloc(unsigned int count) {
-    void *result = nullptr;
-    asm("mov r0, %0; mov r1, %1; svc 0" :: "r" (&result), "r" (count));
-    return result;
-}
+void process_data(adcsample_t *samples, unsigned int size);
 
 extern "C" void process_data_entry() {
     auto func = (void (*)())process_data;
diff --git a/source/adc.cpp b/source/adc.cpp
index c912a7e..f63c386 100644
--- a/source/adc.cpp
+++ b/source/adc.cpp
@@ -20,7 +20,7 @@ constexpr static const ADCConfig adc_config = {
 
 static void adc_read_callback(ADCDriver *);
 
-/*constexpr*/ static ADCConversionGroup adc_group_config = {
+static ADCConversionGroup adc_group_config = {
     .circular = false,
     .num_channels = 1,
     .end_cb = adc_read_callback,
@@ -29,7 +29,7 @@ static void adc_read_callback(ADCDriver *);
     .cfgr2 = 0,
     .tr1 = ADC_TR(0, 4095),
     .smpr = {
-        ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_2P5), 0
+        ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_24P5), 0
     },
     .sqr = {
         ADC_SQR1_SQ1_N(ADC_CHANNEL_IN5),
@@ -65,7 +65,7 @@ namespace adc
         adc_is_read_finished = false;
         adc_group_config.circular = false;
         adcStartConversion(adcd, &adc_group_config, buffer, count);
-        gptStartContinuous(gptd, 2);
+        gptStartContinuous(gptd, 8);
         while (!adc_is_read_finished);
         return buffer;
     }
@@ -77,12 +77,13 @@ namespace adc
         adc_operation_func = operation_func;
         adc_group_config.circular = true;
         adcStartConversion(adcd, &adc_group_config, buffer, count);
-        gptStartContinuous(gptd, 2);
+        gptStartContinuous(gptd, 8);
     }
     
     void read_stop()
     {
         gptStopTimer(gptd);
+        adcStopConversion(adcd);
         adc_group_config.circular = false;
         adc_current_buffer = nullptr;
         adc_current_buffer_size = 0;
@@ -126,15 +127,17 @@ namespace adc
 
 void adc_read_callback(ADCDriver *driver)
 {
-    if (!adc_group_config.circular) {
+    if (adc_group_config.circular) {
+        if (adc_operation_func != nullptr) {
+            auto half_size = adc_current_buffer_size / 2;
+            if (adcIsBufferComplete(driver))
+                adc_operation_func(adc_current_buffer + half_size, half_size);
+            else
+                adc_operation_func(adc_current_buffer, half_size);
+        }
+    } else {
         gptStopTimer(gptd);
         adc_is_read_finished = true;
-    } else if (adc_operation_func != nullptr) {
-        auto half_size = adc_current_buffer_size / 2;
-        if (adcIsBufferComplete(driver))
-            adc_operation_func(adc_current_buffer + half_size, half_size);
-        else
-            adc_operation_func(adc_current_buffer, half_size);
     }
 }
 
diff --git a/source/dac.cpp b/source/dac.cpp
index 6d5950e..8fae1e5 100644
--- a/source/dac.cpp
+++ b/source/dac.cpp
@@ -48,7 +48,7 @@ namespace dac
     void write_start(dacsample_t *buffer, size_t count)
     {
         dacStartConversion(dacd, &dac_group_config, buffer, count);
-        gptStartContinuous(gptd, 2);
+        gptStartContinuous(gptd, 8);
     }
     
     void write_stop()
diff --git a/source/main.cpp b/source/main.cpp
index f55c801..1e2772a 100644
--- a/source/main.cpp
+++ b/source/main.cpp
@@ -22,10 +22,19 @@
 enum class RunStatus : char
 {
     Idle = '1',
-    Converting
+    Converting,
+    Recovered
 };
 static RunStatus run_status = RunStatus::Idle;
 
+#define MSG_CONVFIRST  (1)
+#define MSG_CONVSECOND (2)
+
+static msg_t conversionMBBuffer[8];
+static MAILBOX_DECL(conversionMB, conversionMBBuffer, 8);
+
+static THD_WORKING_AREA(conversionThreadWA, 1024);
+static THD_FUNCTION(conversionThread, arg);
 
 static_assert(sizeof(adcsample_t) == sizeof(uint16_t));
 static_assert(sizeof(dacsample_t) == sizeof(uint16_t));
@@ -40,24 +49,34 @@ CC_ALIGN(CACHE_LINE_SIZE)
 static std::array<dacsample_t, CACHE_SIZE_ALIGN(dacsample_t, 2048)> dac_samples;
 
 static uint8_t elf_file_store[2048];
-static uint8_t elf_exec_store[2048];
+static uint8_t elf_exec_store[4096];
 static elf::entry_t elf_entry = nullptr;
 
-static volatile bool signal_operate_done = false;
-
 static void signal_operate(adcsample_t *buffer, size_t count);
+static void main_loop();
 
 int main()
 {
     halInit();
     chSysInit();
 
+    // Enable FPU
+    SCB->CPACR |= 0xF << 20;
+
     palSetPadMode(GPIOA, 5,  PAL_MODE_OUTPUT_PUSHPULL); // LED
 
     adc::init();
     dac::init();
     usbserial::init();
 
+    chThdCreateStatic(conversionThreadWA, sizeof(conversionThreadWA),
+                      NORMALPRIO,
+                      conversionThread, nullptr);
+    main_loop();
+}
+
+void main_loop()
+{
     static unsigned int dac_sample_count = 2048;
 	while (true) {
         if (usbserial::is_active()) {
@@ -79,7 +98,6 @@ int main()
                     dac::write_start(&dac_samples[0], dac_samples.size());
                     break;
                 case 's':
-                    while (!signal_operate_done);
                     usbserial::write(dac_samples.data(), dac_samples.size() * sizeof(adcsample_t));
                     break;
                 case 'S':
@@ -124,62 +142,42 @@ int main()
 	}
 }
 
-void quick_freeall();
-
-void signal_operate(adcsample_t *buffer, size_t count)
-{
-    if (elf_entry) {
-        elf_entry(buffer, count);
-        quick_freeall();
-    }
-
-    auto dac_buffer = &dac_samples[buffer == &adc_samples[0] ? 0 : 1024];
-    std::copy(buffer, buffer + count, dac_buffer);
-    signal_operate_done = buffer == &adc_samples[1024];
-}
-
-// Dynamic memory allocation below
-
-uint8_t quick_malloc_heap[8192];
-uint8_t *quick_malloc_next = quick_malloc_heap;
-
-void *quick_malloc(unsigned int size)
-{
-    if (auto free = std::distance(quick_malloc_next, quick_malloc_heap + 8192); free < 0 || size > static_cast<unsigned int>(free))
-        return nullptr;
-
-    auto ptr = quick_malloc_next;
-    quick_malloc_next += size;
-    return ptr;
-}
-
-void quick_freeall()
+void conversion_abort()
 {
-    if (quick_malloc_next != quick_malloc_heap)
-        quick_malloc_next = quick_malloc_heap;
+    elf_entry = nullptr;
+    dac::write_stop();
+    adc::read_stop();
+    run_status = RunStatus::Recovered;
 }
 
-void port_syscall(struct port_extctx *ctxp, uint32_t n)
+THD_FUNCTION(conversionThread, arg)
 {
-    switch (n) {
-    case 0:
-        *reinterpret_cast<void **>(ctxp->r0) = quick_malloc(ctxp->r1);
-        break;
-    case 1:
-        quick_freeall();
-        break;
+    (void)arg;
+
+    while (1) {
+        msg_t message;
+        if (chMBFetchTimeout(&conversionMB, &message, TIME_INFINITE) == MSG_OK) {
+            auto samples = &adc_samples[0];
+            auto halfsize = adc_samples.size() / 2;
+            if (message == MSG_CONVFIRST) {
+                if (elf_entry)
+                    elf_entry(samples, halfsize);
+                std::copy(samples, samples + halfsize, &dac_samples[0]);
+            } else if (message == MSG_CONVSECOND) {
+                if (elf_entry)
+                    elf_entry(samples + halfsize, halfsize);
+                std::copy(samples + halfsize, samples + halfsize * 2, &dac_samples[1024]);
+            }
+        }
     }
-
-    chSysHalt("svc");
 }
 
-void conversion_abort()
+void signal_operate(adcsample_t *buffer, size_t count)
 {
-    elf_entry = nullptr;
-    dac::write_stop();
-    adc::read_stop();
-    signal_operate_done = true;
-    run_status = RunStatus::Idle;
+    if (chMBGetUsedCountI(&conversionMB) > 1)
+        conversion_abort();
+    else
+        chMBPostI(&conversionMB, buffer == &adc_samples[0] ? MSG_CONVFIRST : MSG_CONVSECOND);
 }
 
 extern "C" {
@@ -189,14 +187,18 @@ void HardFault_Handler()
 {
     asm("push {lr}");
 
-    if (run_status == RunStatus::Converting) {
-        uint32_t *stack;
-        asm("mrs %0, msp" : "=r" (stack));
-        stack[6] = stack[5];   // Escape from elf_entry code
-        stack[7] |= (1 << 24); // Keep Thumb mode enabled
+    uint32_t *stack;
+    asm("mrs %0, psp" : "=r" (stack));
+    //stack++;
+    stack[7] |= (1 << 24); // Keep Thumb mode enabled
 
-        conversion_abort();
-    }
+    conversion_abort();
+
+    //if (run_status == RunStatus::Converting) {
+    //    stack[6] = stack[5];   // Escape from elf_entry code
+    //} else /*if (run_status == RunStatus::Recovered)*/ {
+        stack[6] = (uint32_t)main_loop & ~1; // Return to safety
+    //}
 
     asm("pop {lr}; bx lr");
 }
-- 
cgit v1.2.3