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()) {
uint8_t request[3] = {
'r',
'd',
static_cast<uint8_t>(count),
static_cast<uint8_t>(count >> 8)
};
@ -39,7 +39,7 @@ namespace stmdsp
} else {
return {};
}
}
}*/
void device::continuous_start() {
if (connected())
@ -63,7 +63,7 @@ namespace stmdsp
std::vector<adcsample_t> device::continuous_read() {
if (connected()) {
m_serial.write("s");
m_serial.write("a");
std::vector<adcsample_t> data (2048);
m_serial.read(reinterpret_cast<uint8_t *>(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<uint8_t>(size),
static_cast<uint8_t>(size >> 8)
};
@ -92,6 +92,6 @@ namespace stmdsp
void device::unload_filter() {
if (connected())
m_serial.write("E");
m_serial.write("e");
}
}

@ -38,7 +38,7 @@ namespace stmdsp
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_measure();

@ -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 {

@ -3,7 +3,9 @@
#include "stmdsp.hpp"
#include <fstream>
#include <future>
#include <iostream>
#include <thread>
#include <wx/button.h>
#include <wx/combobox.h>
@ -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;

@ -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

@ -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_

@ -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_format.hpp"
#include <algorithm>
#include <cstring>
//constexpr unsigned int ELF_LOAD_ADDR = 0x10000000;
static const unsigned char elf_header[] = { '\177', 'E', 'L', 'F' };
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);
}
//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<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_
#define ELF_LOAD_HPP_

@ -19,23 +19,47 @@
#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;
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<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 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<char>(run_status),
static_cast<char>(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]);
}
}
}

Loading…
Cancel
Save