From 241a089c39c77345e8e0a0c8a04301ba2271e432 Mon Sep 17 00:00:00 2001 From: Clyne Sullivan Date: Sun, 18 Oct 2020 21:20:00 -0400 Subject: [PATCH] document/standardize; add compile log to gui --- gui/stmdsp.cpp | 12 +-- gui/stmdsp.hpp | 2 +- gui/wxmain.cpp | 18 +++- gui/wxmain.hpp | 3 + source/adc.cpp | 2 +- source/elf_format.hpp | 7 ++ source/elf_load.cpp | 32 ++---- source/elf_load.hpp | 11 ++ source/main.cpp | 237 ++++++++++++++++++++++++++---------------- 9 files changed, 200 insertions(+), 124 deletions(-) diff --git a/gui/stmdsp.cpp b/gui/stmdsp.cpp index bbfc716..8f19065 100644 --- a/gui/stmdsp.cpp +++ b/gui/stmdsp.cpp @@ -25,10 +25,10 @@ namespace stmdsp } } - std::vector device::sample(unsigned long int count) { + /*std::vector device::sample(unsigned long int count) { if (connected()) { uint8_t request[3] = { - 'r', + 'd', static_cast(count), static_cast(count >> 8) }; @@ -39,7 +39,7 @@ namespace stmdsp } else { return {}; } - } + }*/ void device::continuous_start() { if (connected()) @@ -63,7 +63,7 @@ namespace stmdsp std::vector device::continuous_read() { if (connected()) { - m_serial.write("s"); + m_serial.write("a"); std::vector data (2048); m_serial.read(reinterpret_cast(data.data()), 2048 * sizeof(adcsample_t)); return data; @@ -80,7 +80,7 @@ namespace stmdsp void device::upload_filter(unsigned char *buffer, size_t size) { if (connected()) { uint8_t request[3] = { - 'e', + 'E', static_cast(size), static_cast(size >> 8) }; @@ -92,6 +92,6 @@ namespace stmdsp void device::unload_filter() { if (connected()) - m_serial.write("E"); + m_serial.write("e"); } } diff --git a/gui/stmdsp.hpp b/gui/stmdsp.hpp index 06d36ba..2d336c5 100644 --- a/gui/stmdsp.hpp +++ b/gui/stmdsp.hpp @@ -38,7 +38,7 @@ namespace stmdsp return m_serial.isOpen(); } - std::vector sample(unsigned long int count = 1); + //std::vector sample(unsigned long int count = 1); void continuous_start(); void continuous_start_measure(); diff --git a/gui/wxmain.cpp b/gui/wxmain.cpp index d4f4878..874f26e 100644 --- a/gui/wxmain.cpp +++ b/gui/wxmain.cpp @@ -63,9 +63,13 @@ MainFrame::MainFrame() : wxFrame(nullptr, -1, "stmdspgui", wxPoint(50, 50), wxSi auto window = new wxBoxSizer(wxVERTICAL); - m_text_editor = new wxStyledTextCtrl(this, wxID_ANY, wxDefaultPosition, wxSize(620, 700)); + m_text_editor = new wxStyledTextCtrl(this, wxID_ANY, wxDefaultPosition, wxSize(620, 500)); prepareEditor(); - window->Add(m_text_editor, 1, wxEXPAND | wxALL, 10); + window->Add(m_text_editor, 2, wxEXPAND | wxALL, 10); + + m_compile_output = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, + wxTE_READONLY | wxTE_MULTILINE | wxHSCROLL); + window->Add(m_compile_output, 1, wxEXPAND | wxALL, 10); SetSizerAndFit(window); @@ -168,9 +172,15 @@ wxString MainFrame::compileEditorCode() makefile.Write(make_text); makefile.Close(); + wxString make_output = temp_file_name + "make.log"; wxString make_command = wxString("make -C ") + temp_file_name.BeforeLast('/') + - " -f " + temp_file_name + "make"; - if (system(make_command.ToAscii()) == 0) { + " -f " + temp_file_name + "make" + + " > " + make_output + " 2>&1"; + + int result = system(make_command.ToAscii()); + m_compile_output->LoadFile(make_output); + + if (result == 0) { m_status_bar->SetStatusText("Compilation succeeded."); return temp_file_name + ".o"; } else { diff --git a/gui/wxmain.hpp b/gui/wxmain.hpp index b8ff11d..268a08d 100644 --- a/gui/wxmain.hpp +++ b/gui/wxmain.hpp @@ -3,7 +3,9 @@ #include "stmdsp.hpp" +#include #include +#include #include #include #include @@ -39,6 +41,7 @@ private: bool m_is_running = false; wxComboBox *m_device_combo = nullptr; wxStyledTextCtrl *m_text_editor = nullptr; + wxTextCtrl *m_compile_output = nullptr; wxControl *m_signal_area = nullptr; wxMenuItem *m_run_measure = nullptr; wxTimer *m_measure_timer = nullptr; diff --git a/source/adc.cpp b/source/adc.cpp index 744dbc0..6c1af7b 100644 --- a/source/adc.cpp +++ b/source/adc.cpp @@ -26,7 +26,7 @@ static ADCConversionGroup adc_group_config = { .end_cb = adc_read_callback, .error_cb = nullptr, .cfgr = ADC_CFGR_EXTEN_RISING | ADC_CFGR_EXTSEL_SRC(12), /* TIM4_TRGO */ - .cfgr2 = 0, + .cfgr2 = 0,//ADC_CFGR2_ROVSE | ADC_CFGR2_OVSR_0 | ADC_CFGR2_OVSS_1, // Oversampling 2x .tr1 = ADC_TR(0, 4095), .smpr = { ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_12P5), 0 diff --git a/source/elf_format.hpp b/source/elf_format.hpp index ed74c7b..d4feb99 100644 --- a/source/elf_format.hpp +++ b/source/elf_format.hpp @@ -1,3 +1,10 @@ +/** + * @file elf_format.cpp + * @brief Defines ELF binary format info. + * + * Free to use, written by Clyne Sullivan. + */ + #ifndef STMDSP_ELF_FORMAT_HPP_ #define STMDSP_ELF_FORMAT_HPP_ diff --git a/source/elf_load.cpp b/source/elf_load.cpp index 3fd8a0f..79cd4fe 100644 --- a/source/elf_load.cpp +++ b/source/elf_load.cpp @@ -1,11 +1,20 @@ +/** + * @file elf_load.cpp + * @brief Loads ELF binary data into memory for execution. + * + * Copyright (C) 2020 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 "elf_load.hpp" #include "elf_format.hpp" #include #include -//constexpr unsigned int ELF_LOAD_ADDR = 0x10000000; - static const unsigned char elf_header[] = { '\177', 'E', 'L', 'F' }; template @@ -14,8 +23,6 @@ constexpr static auto ptr_from_offset(void *base, uint32_t offset) return reinterpret_cast(reinterpret_cast(base) + offset); } -//static Elf32_Shdr *find_section(Elf32_Ehdr *ehdr, const char *name); - namespace elf { entry_t load(void *elf_data) @@ -52,20 +59,3 @@ entry_t load(void *elf_data) } // namespace elf -//Elf32_Shdr *find_section(Elf32_Ehdr *ehdr, const char *name) -//{ -// auto shdr = ptr_from_offset(ehdr, ehdr->e_shoff); -// auto shdr_str = ptr_from_offset(ehdr, -// ehdr->e_shoff + ehdr->e_shstrndx * ehdr->e_shentsize); -// -// for (Elf32_Half i = 0; i < ehdr->e_shnum; i++) { -// char *section = ptr_from_offset(ehdr, shdr_str->sh_offset) + shdr->sh_name; -// if (!strcmp(section, name)) -// return shdr; -// -// shdr = ptr_from_offset(shdr, ehdr->e_shentsize); -// } -// -// return 0; -//} - diff --git a/source/elf_load.hpp b/source/elf_load.hpp index 4fda526..faa74d2 100644 --- a/source/elf_load.hpp +++ b/source/elf_load.hpp @@ -1,3 +1,14 @@ +/** + * @file elf_load.hpp + * @brief Loads ELF binary data into memory for execution. + * + * Copyright (C) 2020 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 ELF_LOAD_HPP_ #define ELF_LOAD_HPP_ diff --git a/source/main.cpp b/source/main.cpp index 1e3c5fb..c46685f 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -19,23 +19,47 @@ #include +constexpr unsigned int MAX_ELF_FILE_SIZE = 12 * 1024; +constexpr unsigned int MAX_ERROR_QUEUE_SIZE = 8; constexpr unsigned int MAX_SAMPLE_BUFFER_SIZE = 8000; enum class RunStatus : char { Idle = '1', - Converting, - Recovered + Running }; +enum class Error : char +{ + None = 0, + BadParam, + BadParamSize, + BadUserCodeLoad, + BadUserCodeSize, + NotIdle, + ConversionAborted +}; + static RunStatus run_status = RunStatus::Idle; +static Error error_queue[MAX_ERROR_QUEUE_SIZE]; +static unsigned int error_queue_index = 0; + +static void error_queue_add(Error error) +{ + if (error_queue_index < MAX_ERROR_QUEUE_SIZE) + error_queue[error_queue_index++] = error; +} +static Error error_queue_pop() +{ + return error_queue_index == 0 ? Error::None : error_queue[--error_queue_index]; +} #define MSG_CONVFIRST (1) #define MSG_CONVSECOND (2) #define MSG_CONVFIRST_MEASURE (3) #define MSG_CONVSECOND_MEASURE (4) -static msg_t conversionMBBuffer[8]; -static MAILBOX_DECL(conversionMB, conversionMBBuffer, 8); +static msg_t conversionMBBuffer[4]; +static MAILBOX_DECL(conversionMB, conversionMBBuffer, 4); static THD_WORKING_AREA(conversionThreadWA, 1024); static THD_FUNCTION(conversionThread, arg); @@ -54,7 +78,7 @@ CC_ALIGN(CACHE_LINE_SIZE) #endif static std::array dac_samples; -static uint8_t elf_file_store[12288]; +static uint8_t elf_file_store[MAX_ELF_FILE_SIZE]; static elf::entry_t elf_entry = nullptr; static void signal_operate(adcsample_t *buffer, size_t count); @@ -87,9 +111,13 @@ int main() main_loop(); } +static unsigned int dac_sample_count = MAX_SAMPLE_BUFFER_SIZE; +static unsigned int adc_sample_count = MAX_SAMPLE_BUFFER_SIZE; +static bool adc_preloaded = false; +static bool dac_preloaded = false; + void main_loop() { - static unsigned int dac_sample_count = MAX_SAMPLE_BUFFER_SIZE; while (1) { if (usbserial::is_active()) { @@ -98,111 +126,136 @@ void main_loop() // Packet received, first byte represents the desired command/action switch (cmd[0]) { - // 'r' - Conduct a single sample of the ADC, and send the results back over USB. - case 'r': - // Get the next two bytes of the packet to determine the desired sample size - if (run_status != RunStatus::Idle || usbserial::read(&cmd[1], 2) < 2) - break; - if (unsigned int desiredSize = cmd[1] | (cmd[2] << 8); desiredSize <= adc_samples.size()) { - adc::read(&adc_samples[0], desiredSize); - usbserial::write(adc_samples.data(), desiredSize * sizeof(adcsample_t)); - } + case 'a': + usbserial::write(adc_samples.data(), adc_sample_count * sizeof(adcsample_t)); + break; + case 'A': + usbserial::read(&adc_samples[0], adc_sample_count * sizeof(adcsample_t)); break; - // 'R' - Begin continuous sampling/conversion of the ADC. Samples will go through - // the conversion code, and will be sent out over the DAC. - case 'R': - //if (run_status != RunStatus::Idle) - // break; - - run_status = RunStatus::Converting; - dac_samples.fill(0); - adc::read_start(signal_operate, &adc_samples[0], adc_samples.size()); - dac::write_start(&dac_samples[0], dac_samples.size()); + case 'B': + if (run_status == RunStatus::Idle) { + if (usbserial::read(&cmd[1], 2) == 2) { + unsigned int count = cmd[1] | (cmd[2] << 8); + if (count <= MAX_SAMPLE_BUFFER_SIZE / 2) { + adc_sample_count = count * 2; + dac_sample_count = count * 2; + } else { + error_queue_add(Error::BadParam); + } + } else { + error_queue_add(Error::BadParamSize); + } + } else { + error_queue_add(Error::NotIdle); + } break; - // 'M' - Begins continuous sampling, but measures the execution time of the first - // sample processing. This duration can be later read through 'm'. - case 'M': - run_status = RunStatus::Converting; - dac_samples.fill(0); - adc::read_start(signal_operate_measure, &adc_samples[0], adc_samples.size()); - dac::write_start(&dac_samples[0], dac_samples.size()); + case 'd': + usbserial::write(dac_samples.data(), dac_sample_count * sizeof(dacsample_t)); + break; + case 'D': + usbserial::read(&dac_samples[0], dac_sample_count * sizeof(dacsample_t)); break; - // 'm' - Returns the last measured sample processing time, presumably in processor - // ticks. - case 'm': - usbserial::write(&conversion_time_measurement.last, sizeof(rtcnt_t)); + // 'E' - Reads in and loads the compiled conversion code binary from USB. + case 'E': + if (run_status == RunStatus::Idle) { + if (usbserial::read(&cmd[1], 2) == 2) { + // Only load the binary if it can fit in the memory reserved for it. + unsigned int size = cmd[1] | (cmd[2] << 8); + if (size < sizeof(elf_file_store)) { + usbserial::read(elf_file_store, size); + elf_entry = elf::load(elf_file_store); + + if (elf_entry == nullptr) + error_queue_add(Error::BadUserCodeLoad); + } else { + error_queue_add(Error::BadUserCodeSize); + } + } else { + error_queue_add(Error::BadParamSize); + } + } else { + error_queue_add(Error::NotIdle); + } break; - // 's' - Sends the current contents of the DAC buffer back over USB. - case 's': - usbserial::write(dac_samples.data(), 1/*dac_samples.size()*/ * sizeof(dacsample_t)); + // 'e' - Unloads the currently loaded conversion code + case 'e': + elf_entry = nullptr; break; - // 'S' - Stops the continuous sampling/conversion. - case 'S': - //if (run_status != RunStatus::Converting) - // break; + // 'i' - Sends an identifying string to confirm that this is the stmdsp device. + case 'i': + usbserial::write("stmdsp", 6); + break; - dac::write_stop(); - adc::read_stop(); - run_status = RunStatus::Idle; + // 'I' - Sends the current run status. + case 'I': + { + char buf[2] = { + static_cast(run_status), + static_cast(error_queue_pop()) + }; + usbserial::write(buf, sizeof(buf)); + } break; - // 'e' - Reads in and loads the compiled conversion code binary from USB. - case 'e': - // Get the binary's size - if (usbserial::read(&cmd[1], 2) < 2) - break; - - // Only load the binary if it can fit in the memory reserved for it. - if (unsigned int binarySize = cmd[1] | (cmd[2] << 8); binarySize < sizeof(elf_file_store)) { - usbserial::read(elf_file_store, binarySize); - elf_entry = elf::load(elf_file_store); + // 'M' - Begins continuous sampling, but measures the execution time of the first + // sample processing. This duration can be later read through 'm'. + case 'M': + if (run_status == RunStatus::Idle) { + run_status = RunStatus::Running; + dac_samples.fill(0); + if (!adc_preloaded) + adc::read_start(signal_operate_measure, &adc_samples[0], adc_sample_count); + if (!dac_preloaded) + dac::write_start(&dac_samples[0], dac_sample_count); } else { - elf_entry = nullptr; + error_queue_add(Error::NotIdle); } break; - // 'E' - Unloads the currently loaded conversion code - case 'E': - elf_entry = nullptr; + // 'm' - Returns the last measured sample processing time, presumably in processor + // ticks. + case 'm': + usbserial::write(&conversion_time_measurement.last, sizeof(rtcnt_t)); break; - // 'W' - Sets the number of samples for DAC writing with command 'w'. - // If the provided count is zero, DAC writing is stopped. - case 'W': - if (usbserial::read(&cmd[1], 2) < 2) - break; - if (unsigned int sampleCount = cmd[1] | (cmd[2] << 8); sampleCount <= dac_samples.size()) { - if (sampleCount > 0) - dac_sample_count = sampleCount; - else - dac::write_stop(); + // 'R' - Begin continuous sampling/conversion of the ADC. Samples will go through + // the conversion code, and will be sent out over the DAC. + case 'R': + if (run_status == RunStatus::Idle) { + run_status = RunStatus::Running; + dac_samples.fill(0); + if (!adc_preloaded) + adc::read_start(signal_operate, &adc_samples[0], adc_sample_count); + if (!dac_preloaded) + dac::write_start(&dac_samples[0], dac_sample_count); + } else { + error_queue_add(Error::NotIdle); } break; - // 'w' - Starts the DAC, looping over the given data (data size set by command 'W'). - case 'w': - if (usbserial::read(&dac_samples[0], dac_sample_count * sizeof(dacsample_t) != - dac_sample_count * sizeof(dacsample_t))) - { - break; + case 'r': + if (usbserial::read(&cmd[1], 1) == 1) { + adc_preloaded = cmd[1] & (1 << 0); + dac_preloaded = cmd[1] & (1 << 1); } else { - dac::write_start(&dac_samples[0], dac_sample_count); + error_queue_add(Error::BadParamSize); } break; - // 'i' - Sends an identifying string to confirm that this is the stmdsp device. - case 'i': - usbserial::write("stmdsp", 6); - break; - - // 'I' - Sends the current run status. - case 'I': - usbserial::write(&run_status, sizeof(run_status)); + // 'S' - Stops the continuous sampling/conversion. + case 'S': + if (run_status == RunStatus::Running) { + if (!dac_preloaded) + dac::write_stop(); + if (!adc_preloaded) + adc::read_stop(); + run_status = RunStatus::Idle; + } break; default: @@ -218,9 +271,11 @@ void main_loop() void conversion_abort() { elf_entry = nullptr; - dac::write_stop(); - adc::read_stop(); - run_status = RunStatus::Recovered; + if (!dac_preloaded) + dac::write_stop(); + if (!adc_preloaded) + adc::read_stop(); + error_queue_add(Error::ConversionAborted); } THD_FUNCTION(conversionThread, arg) @@ -231,7 +286,7 @@ THD_FUNCTION(conversionThread, arg) msg_t message; if (chMBFetchTimeout(&conversionMB, &message, TIME_INFINITE) == MSG_OK) { adcsample_t *samples = nullptr; - auto halfsize = adc_samples.size() / 2; + auto halfsize = adc_sample_count / 2; if (message == MSG_CONVFIRST) { if (elf_entry) samples = elf_entry(&adc_samples[0], halfsize); @@ -243,7 +298,7 @@ THD_FUNCTION(conversionThread, arg) samples = elf_entry(&adc_samples[halfsize], halfsize); if (!samples) samples = &adc_samples[halfsize]; - std::copy(samples, samples + halfsize, &dac_samples[dac_samples.size() / 2]); + std::copy(samples, samples + halfsize, &dac_samples[dac_sample_count / 2]); } else if (message == MSG_CONVFIRST_MEASURE) { chTMStartMeasurementX(&conversion_time_measurement); if (elf_entry) @@ -259,7 +314,7 @@ THD_FUNCTION(conversionThread, arg) chTMStopMeasurementX(&conversion_time_measurement); if (!samples) samples = &adc_samples[halfsize]; - std::copy(samples, samples + halfsize, &dac_samples[dac_samples.size() / 2]); + std::copy(samples, samples + halfsize, &dac_samples[dac_sample_count / 2]); } } }