document/standardize; add compile log to gui

pull/3/head
Clyne 4 years ago
parent 9c98bfb62c
commit 241a089c39

@ -25,10 +25,10 @@ namespace stmdsp
} }
} }
std::vector<adcsample_t> device::sample(unsigned long int count) { /*std::vector<adcsample_t> device::sample(unsigned long int count) {
if (connected()) { if (connected()) {
uint8_t request[3] = { uint8_t request[3] = {
'r', 'd',
static_cast<uint8_t>(count), static_cast<uint8_t>(count),
static_cast<uint8_t>(count >> 8) static_cast<uint8_t>(count >> 8)
}; };
@ -39,7 +39,7 @@ namespace stmdsp
} else { } else {
return {}; return {};
} }
} }*/
void device::continuous_start() { void device::continuous_start() {
if (connected()) if (connected())
@ -63,7 +63,7 @@ namespace stmdsp
std::vector<adcsample_t> device::continuous_read() { std::vector<adcsample_t> device::continuous_read() {
if (connected()) { if (connected()) {
m_serial.write("s"); m_serial.write("a");
std::vector<adcsample_t> data (2048); std::vector<adcsample_t> data (2048);
m_serial.read(reinterpret_cast<uint8_t *>(data.data()), 2048 * sizeof(adcsample_t)); m_serial.read(reinterpret_cast<uint8_t *>(data.data()), 2048 * sizeof(adcsample_t));
return data; return data;
@ -80,7 +80,7 @@ namespace stmdsp
void device::upload_filter(unsigned char *buffer, size_t size) { void device::upload_filter(unsigned char *buffer, size_t size) {
if (connected()) { if (connected()) {
uint8_t request[3] = { uint8_t request[3] = {
'e', 'E',
static_cast<uint8_t>(size), static_cast<uint8_t>(size),
static_cast<uint8_t>(size >> 8) static_cast<uint8_t>(size >> 8)
}; };
@ -92,6 +92,6 @@ namespace stmdsp
void device::unload_filter() { void device::unload_filter() {
if (connected()) if (connected())
m_serial.write("E"); m_serial.write("e");
} }
} }

@ -38,7 +38,7 @@ namespace stmdsp
return m_serial.isOpen(); return m_serial.isOpen();
} }
std::vector<adcsample_t> sample(unsigned long int count = 1); //std::vector<adcsample_t> sample(unsigned long int count = 1);
void continuous_start(); void continuous_start();
void continuous_start_measure(); void continuous_start_measure();

@ -63,9 +63,13 @@ MainFrame::MainFrame() : wxFrame(nullptr, -1, "stmdspgui", wxPoint(50, 50), wxSi
auto window = new wxBoxSizer(wxVERTICAL); 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(); 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); SetSizerAndFit(window);
@ -168,9 +172,15 @@ wxString MainFrame::compileEditorCode()
makefile.Write(make_text); makefile.Write(make_text);
makefile.Close(); makefile.Close();
wxString make_output = temp_file_name + "make.log";
wxString make_command = wxString("make -C ") + temp_file_name.BeforeLast('/') + wxString make_command = wxString("make -C ") + temp_file_name.BeforeLast('/') +
" -f " + temp_file_name + "make"; " -f " + temp_file_name + "make" +
if (system(make_command.ToAscii()) == 0) { " > " + 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."); m_status_bar->SetStatusText("Compilation succeeded.");
return temp_file_name + ".o"; return temp_file_name + ".o";
} else { } else {

@ -3,7 +3,9 @@
#include "stmdsp.hpp" #include "stmdsp.hpp"
#include <fstream>
#include <future> #include <future>
#include <iostream>
#include <thread> #include <thread>
#include <wx/button.h> #include <wx/button.h>
#include <wx/combobox.h> #include <wx/combobox.h>
@ -39,6 +41,7 @@ private:
bool m_is_running = false; bool m_is_running = false;
wxComboBox *m_device_combo = nullptr; wxComboBox *m_device_combo = nullptr;
wxStyledTextCtrl *m_text_editor = nullptr; wxStyledTextCtrl *m_text_editor = nullptr;
wxTextCtrl *m_compile_output = nullptr;
wxControl *m_signal_area = nullptr; wxControl *m_signal_area = nullptr;
wxMenuItem *m_run_measure = nullptr; wxMenuItem *m_run_measure = nullptr;
wxTimer *m_measure_timer = nullptr; wxTimer *m_measure_timer = nullptr;

@ -26,7 +26,7 @@ static ADCConversionGroup adc_group_config = {
.end_cb = adc_read_callback, .end_cb = adc_read_callback,
.error_cb = nullptr, .error_cb = nullptr,
.cfgr = ADC_CFGR_EXTEN_RISING | ADC_CFGR_EXTSEL_SRC(12), /* TIM4_TRGO */ .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), .tr1 = ADC_TR(0, 4095),
.smpr = { .smpr = {
ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_12P5), 0 ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_12P5), 0

@ -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_ #ifndef STMDSP_ELF_FORMAT_HPP_
#define STMDSP_ELF_FORMAT_HPP_ #define STMDSP_ELF_FORMAT_HPP_

@ -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 <https://www.gnu.org/licenses/>.
*/
#include "elf_load.hpp" #include "elf_load.hpp"
#include "elf_format.hpp" #include "elf_format.hpp"
#include <algorithm> #include <algorithm>
#include <cstring> #include <cstring>
//constexpr unsigned int ELF_LOAD_ADDR = 0x10000000;
static const unsigned char elf_header[] = { '\177', 'E', 'L', 'F' }; static const unsigned char elf_header[] = { '\177', 'E', 'L', 'F' };
template<typename T> template<typename T>
@ -14,8 +23,6 @@ constexpr static auto ptr_from_offset(void *base, uint32_t offset)
return reinterpret_cast<T>(reinterpret_cast<uint8_t *>(base) + offset); return reinterpret_cast<T>(reinterpret_cast<uint8_t *>(base) + offset);
} }
//static Elf32_Shdr *find_section(Elf32_Ehdr *ehdr, const char *name);
namespace elf { namespace elf {
entry_t load(void *elf_data) entry_t load(void *elf_data)
@ -52,20 +59,3 @@ entry_t load(void *elf_data)
} // namespace elf } // namespace elf
//Elf32_Shdr *find_section(Elf32_Ehdr *ehdr, const char *name)
//{
// auto shdr = ptr_from_offset<Elf32_Shdr *>(ehdr, ehdr->e_shoff);
// auto shdr_str = ptr_from_offset<Elf32_Shdr *>(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<char *>(ehdr, shdr_str->sh_offset) + shdr->sh_name;
// if (!strcmp(section, name))
// return shdr;
//
// shdr = ptr_from_offset<Elf32_Shdr *>(shdr, ehdr->e_shentsize);
// }
//
// return 0;
//}

@ -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 <https://www.gnu.org/licenses/>.
*/
#ifndef ELF_LOAD_HPP_ #ifndef ELF_LOAD_HPP_
#define ELF_LOAD_HPP_ #define ELF_LOAD_HPP_

@ -19,23 +19,47 @@
#include <array> #include <array>
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; constexpr unsigned int MAX_SAMPLE_BUFFER_SIZE = 8000;
enum class RunStatus : char enum class RunStatus : char
{ {
Idle = '1', Idle = '1',
Converting, Running
Recovered
}; };
enum class Error : char
{
None = 0,
BadParam,
BadParamSize,
BadUserCodeLoad,
BadUserCodeSize,
NotIdle,
ConversionAborted
};
static RunStatus run_status = RunStatus::Idle; 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_CONVFIRST (1)
#define MSG_CONVSECOND (2) #define MSG_CONVSECOND (2)
#define MSG_CONVFIRST_MEASURE (3) #define MSG_CONVFIRST_MEASURE (3)
#define MSG_CONVSECOND_MEASURE (4) #define MSG_CONVSECOND_MEASURE (4)
static msg_t conversionMBBuffer[8]; static msg_t conversionMBBuffer[4];
static MAILBOX_DECL(conversionMB, conversionMBBuffer, 8); static MAILBOX_DECL(conversionMB, conversionMBBuffer, 4);
static THD_WORKING_AREA(conversionThreadWA, 1024); static THD_WORKING_AREA(conversionThreadWA, 1024);
static THD_FUNCTION(conversionThread, arg); static THD_FUNCTION(conversionThread, arg);
@ -54,7 +78,7 @@ CC_ALIGN(CACHE_LINE_SIZE)
#endif #endif
static std::array<dacsample_t, CACHE_SIZE_ALIGN(dacsample_t, MAX_SAMPLE_BUFFER_SIZE)> dac_samples; static std::array<dacsample_t, CACHE_SIZE_ALIGN(dacsample_t, MAX_SAMPLE_BUFFER_SIZE)> 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 elf::entry_t elf_entry = nullptr;
static void signal_operate(adcsample_t *buffer, size_t count); static void signal_operate(adcsample_t *buffer, size_t count);
@ -87,9 +111,13 @@ int main()
main_loop(); 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() void main_loop()
{ {
static unsigned int dac_sample_count = MAX_SAMPLE_BUFFER_SIZE;
while (1) { while (1) {
if (usbserial::is_active()) { if (usbserial::is_active()) {
@ -98,111 +126,136 @@ void main_loop()
// Packet received, first byte represents the desired command/action // Packet received, first byte represents the desired command/action
switch (cmd[0]) { switch (cmd[0]) {
// 'r' - Conduct a single sample of the ADC, and send the results back over USB. case 'a':
case 'r': usbserial::write(adc_samples.data(), adc_sample_count * sizeof(adcsample_t));
// 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; break;
if (unsigned int desiredSize = cmd[1] | (cmd[2] << 8); desiredSize <= adc_samples.size()) { case 'A':
adc::read(&adc_samples[0], desiredSize); usbserial::read(&adc_samples[0], adc_sample_count * sizeof(adcsample_t));
usbserial::write(adc_samples.data(), desiredSize * sizeof(adcsample_t));
}
break; break;
// 'R' - Begin continuous sampling/conversion of the ADC. Samples will go through case 'B':
// the conversion code, and will be sent out over the DAC. if (run_status == RunStatus::Idle) {
case 'R': if (usbserial::read(&cmd[1], 2) == 2) {
//if (run_status != RunStatus::Idle) unsigned int count = cmd[1] | (cmd[2] << 8);
// break; if (count <= MAX_SAMPLE_BUFFER_SIZE / 2) {
adc_sample_count = count * 2;
run_status = RunStatus::Converting; dac_sample_count = count * 2;
dac_samples.fill(0); } else {
adc::read_start(signal_operate, &adc_samples[0], adc_samples.size()); error_queue_add(Error::BadParam);
dac::write_start(&dac_samples[0], dac_samples.size()); }
break; } else {
error_queue_add(Error::BadParamSize);
// 'M' - Begins continuous sampling, but measures the execution time of the first }
// sample processing. This duration can be later read through 'm'. } else {
case 'M': error_queue_add(Error::NotIdle);
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());
break;
// 'm' - Returns the last measured sample processing time, presumably in processor
// ticks.
case 'm':
usbserial::write(&conversion_time_measurement.last, sizeof(rtcnt_t));
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));
break; break;
// 'S' - Stops the continuous sampling/conversion. case 'd':
case 'S': usbserial::write(dac_samples.data(), dac_sample_count * sizeof(dacsample_t));
//if (run_status != RunStatus::Converting)
// break;
dac::write_stop();
adc::read_stop();
run_status = RunStatus::Idle;
break; break;
case 'D':
// 'e' - Reads in and loads the compiled conversion code binary from USB. usbserial::read(&dac_samples[0], dac_sample_count * sizeof(dacsample_t));
case 'e':
// Get the binary's size
if (usbserial::read(&cmd[1], 2) < 2)
break; break;
// '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. // 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)) { unsigned int size = cmd[1] | (cmd[2] << 8);
usbserial::read(elf_file_store, binarySize); if (size < sizeof(elf_file_store)) {
usbserial::read(elf_file_store, size);
elf_entry = elf::load(elf_file_store); elf_entry = elf::load(elf_file_store);
if (elf_entry == nullptr)
error_queue_add(Error::BadUserCodeLoad);
} else { } else {
elf_entry = nullptr; error_queue_add(Error::BadUserCodeSize);
}
} else {
error_queue_add(Error::BadParamSize);
}
} else {
error_queue_add(Error::NotIdle);
} }
break; break;
// 'E' - Unloads the currently loaded conversion code // 'e' - Unloads the currently loaded conversion code
case 'E': case 'e':
elf_entry = nullptr; elf_entry = nullptr;
break; break;
// 'W' - Sets the number of samples for DAC writing with command 'w'. // 'i' - Sends an identifying string to confirm that this is the stmdsp device.
// If the provided count is zero, DAC writing is stopped. case 'i':
case 'W': usbserial::write("stmdsp", 6);
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();
}
break; break;
// 'w' - Starts the DAC, looping over the given data (data size set by command 'W'). // 'I' - Sends the current run status.
case 'w': case 'I':
if (usbserial::read(&dac_samples[0], dac_sample_count * sizeof(dacsample_t) !=
dac_sample_count * sizeof(dacsample_t)))
{ {
char buf[2] = {
static_cast<char>(run_status),
static_cast<char>(error_queue_pop())
};
usbserial::write(buf, sizeof(buf));
}
break; 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':
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 { } else {
error_queue_add(Error::NotIdle);
}
break;
// 'm' - Returns the last measured sample processing time, presumably in processor
// ticks.
case 'm':
usbserial::write(&conversion_time_measurement.last, sizeof(rtcnt_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) {
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); dac::write_start(&dac_samples[0], dac_sample_count);
} else {
error_queue_add(Error::NotIdle);
} }
break; break;
// 'i' - Sends an identifying string to confirm that this is the stmdsp device. case 'r':
case 'i': if (usbserial::read(&cmd[1], 1) == 1) {
usbserial::write("stmdsp", 6); adc_preloaded = cmd[1] & (1 << 0);
dac_preloaded = cmd[1] & (1 << 1);
} else {
error_queue_add(Error::BadParamSize);
}
break; break;
// 'I' - Sends the current run status. // 'S' - Stops the continuous sampling/conversion.
case 'I': case 'S':
usbserial::write(&run_status, sizeof(run_status)); if (run_status == RunStatus::Running) {
if (!dac_preloaded)
dac::write_stop();
if (!adc_preloaded)
adc::read_stop();
run_status = RunStatus::Idle;
}
break; break;
default: default:
@ -218,9 +271,11 @@ void main_loop()
void conversion_abort() void conversion_abort()
{ {
elf_entry = nullptr; elf_entry = nullptr;
if (!dac_preloaded)
dac::write_stop(); dac::write_stop();
if (!adc_preloaded)
adc::read_stop(); adc::read_stop();
run_status = RunStatus::Recovered; error_queue_add(Error::ConversionAborted);
} }
THD_FUNCTION(conversionThread, arg) THD_FUNCTION(conversionThread, arg)
@ -231,7 +286,7 @@ THD_FUNCTION(conversionThread, arg)
msg_t message; msg_t message;
if (chMBFetchTimeout(&conversionMB, &message, TIME_INFINITE) == MSG_OK) { if (chMBFetchTimeout(&conversionMB, &message, TIME_INFINITE) == MSG_OK) {
adcsample_t *samples = nullptr; adcsample_t *samples = nullptr;
auto halfsize = adc_samples.size() / 2; auto halfsize = adc_sample_count / 2;
if (message == MSG_CONVFIRST) { if (message == MSG_CONVFIRST) {
if (elf_entry) if (elf_entry)
samples = elf_entry(&adc_samples[0], halfsize); samples = elf_entry(&adc_samples[0], halfsize);
@ -243,7 +298,7 @@ THD_FUNCTION(conversionThread, arg)
samples = elf_entry(&adc_samples[halfsize], halfsize); samples = elf_entry(&adc_samples[halfsize], halfsize);
if (!samples) if (!samples)
samples = &adc_samples[halfsize]; 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) { } else if (message == MSG_CONVFIRST_MEASURE) {
chTMStartMeasurementX(&conversion_time_measurement); chTMStartMeasurementX(&conversion_time_measurement);
if (elf_entry) if (elf_entry)
@ -259,7 +314,7 @@ THD_FUNCTION(conversionThread, arg)
chTMStopMeasurementX(&conversion_time_measurement); chTMStopMeasurementX(&conversion_time_measurement);
if (!samples) if (!samples)
samples = &adc_samples[halfsize]; 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]);
} }
} }
} }

Loading…
Cancel
Save