gui improvements; code templates

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

@ -0,0 +1,29 @@
/**
* 1_convolve_simple.cpp
* Written by Clyne Sullivan.
*
* Computes a convolution in the simplest way possible. While the code is brief, it lacks many
* possible optimizations. The convolution's result will not fill the output buffer either, as the
* transient response is not calculated.
*/
adcsample_t *process_data(adcsample_t *samples, unsigned int size)
{
// Define our output buffer. SIZE is the largest size of the 'samples' buffer.
static adcsample_t buffer[SIZE];
// Define our filter
constexpr unsigned int filter_size = 3;
float filter[filter_size] = {
0.3333, 0.3333, 0.3333
};
// Begin convolving:
for (int n = 0; n < size - (filter_size - 1); n++) {
buffer[n] = 0;
for (int k = 0; k < filter_size; k++)
buffer[n] += samples[n + k] * filter[k];
}
return buffer;
}

@ -0,0 +1,47 @@
/**
* 2_convolve_overlap_save.cpp
* Written by Clyne Sullivan.
*
* This convolution examples takes an overlap-save approach, where samples from the previous run
* are saved so that the overall operation is not interrupted (i.e. the observed output will
* transition smoothly between processed "chunks").
*
* Note that there are still improvements that can be made to the code; for example, notice every
* spot where an integer/float conversion is necessary. Operations like these may slow down the
* computation.
*/
adcsample_t *process_data(adcsample_t *samples, unsigned int size)
{
static adcsample_t buffer[SIZE];
constexpr unsigned int filter_size = 3;
float filter[filter_size] = {
0.3333, 0.3333, 0.3333
};
// Keep a buffer of extra samples for overlap-save
static adcsample_t prev[filter_size];
for (int n = 0; n < size; n++) {
buffer[n] = 0;
for (int k = 0; k < filter_size; k++) {
int i = n - (filter_size - 1) + k;
// If i is >= 0, access current sample buffer.
// If i is < 0, provide the previous samples from the 'prev' buffer
if (i >= 0)
buffer[n] += samples[i] * filter[k];
else
buffer[n] += prev[filter_size - 1 + i] * filter[k];
}
}
// Save samples for the next convolution run
for (int i = 0; i < filter_size; i++)
prev[i] = samples[size - filter_size + i];
return buffer;
}

@ -0,0 +1,47 @@
/**
* 3_fir.cpp
* Written by Clyne Sullivan.
*
* The below code was written for applying FIR filters. While this is still essentially an overlap-
* save convolution, other optimizations have been made to allow for larger filters to be applied
* within the available execution time. Samples are also normalized so that they center around zero.
*/
adcsample_t *process_data(adcsample_t *samples, unsigned int size)
{
static adcsample_t buffer[SIZE];
// Define the filter:
constexpr unsigned int filter_size = 3;
static float filter[filter_size] = {
// Put filter values here (note: precision will be truncated for 'float' size).
0.3333, 0.3333, 0.3333
};
// Do an overlap-save convolution
static adcsample_t prev[filter_size];
for (int n = 0; n < size; n++) {
// Using a float variable for accumulation allows for better code optimization
float v = 0;
for (int k = 0; k < filter_size; k++) {
int i = n - (filter_size - 1) + k;
auto s = i >= 0 ? samples[i] : prev[filter_size - 1 + i];
// Sample values are 0 to 4095. Below, the original sample is normalized to a -1.0 to
// 1.0 range for calculation.
v += (s / 2048.f - 1) * filter[k];
}
// Return value to sample range of 0-4095.
buffer[n] = (v + 1) * 2048.f;
}
// Save samples for next convolution
for (int i = 0; i < filter_size; i++)
prev[i] = samples[size - filter_size + i];
return buffer;
}

@ -12,11 +12,14 @@ public:
virtual bool OnInit() final {
wxFont::AddPrivateFont("./Hack-Regular.ttf");
auto mainFrame = new MainFrame;
mainFrame->Show(true);
SetTopWindow(mainFrame);
m_main_frame = new MainFrame;
m_main_frame->Show(true);
SetTopWindow(m_main_frame);
return true;
}
private:
MainFrame *m_main_frame = nullptr;
};
#endif // WXAPP_HPP_

@ -1,10 +1,14 @@
#include "wxmain.hpp"
#include <wx/dir.h>
#include <wx/filename.h>
#include <wx/filedlg.h>
#include <wx/menu.h>
#include <wx/menuitem.h>
#include <wx/msgdlg.h>
#include <wx/panel.h>
#include <wx/sizer.h>
#include <wx/splitter.h>
#include <wx/statusbr.h>
enum Id {
@ -12,28 +16,69 @@ enum Id {
MFileNew,
MFileOpen,
MFileOpenTemplate,
MFileSave,
MFileSaveAs,
MFileQuit,
MRunConnect,
MRunStart,
MRunMeasure,
MRunCompile,
MRunUpload,
MRunUnload
MRunUnload,
MCodeCompile,
MCodeDisassemble
};
MainFrame::MainFrame() : wxFrame(nullptr, -1, "stmdspgui", wxPoint(50, 50), wxSize(640, 800))
MainFrame::MainFrame() : wxFrame(nullptr, wxID_ANY, "stmdspgui", wxPoint(50, 50), wxSize(640, 800))
{
auto splitter = new wxSplitterWindow(this, wxID_ANY);
auto panelCode = new wxPanel(splitter, wxID_ANY);
auto panelOutput = new wxPanel(splitter, wxID_ANY);
auto sizerCode = new wxBoxSizer(wxVERTICAL);
auto sizerOutput = new wxBoxSizer(wxVERTICAL);
auto sizerSplitter = new wxBoxSizer(wxVERTICAL);
auto menuFile = new wxMenu;
auto menuRun = new wxMenu;
auto menuCode = new wxMenu;
// Member initialization
m_status_bar = new wxStatusBar(this);
m_text_editor = new wxStyledTextCtrl(panelCode, wxID_ANY, wxDefaultPosition, wxSize(620, 500));
m_compile_output = new wxTextCtrl(panelOutput, wxID_ANY, wxEmptyString, wxDefaultPosition,
wxSize(620, 250), wxTE_READONLY | wxTE_MULTILINE | wxHSCROLL);
m_measure_timer = new wxTimer(this, Id::MeasureTimer);
m_menu_bar = new wxMenuBar;
m_status_bar->SetStatusText("Ready.");
SetStatusBar(m_status_bar);
auto menubar = new wxMenuBar;
auto menuFile = new wxMenu;
splitter->SetSashGravity(0.5);
splitter->SetMinimumPaneSize(20);
prepareEditor();
sizerCode->Add(m_text_editor, 1, wxEXPAND | wxALL, 0);
panelCode->SetSizer(sizerCode);
m_compile_output->SetBackgroundColour(wxColour(0, 0, 0));
m_compile_output->SetDefaultStyle(wxTextAttr(*wxWHITE, *wxBLACK, wxFont("Hack")));
sizerOutput->Add(m_compile_output, 1, wxEXPAND | wxALL, 0);
panelOutput->SetSizer(sizerOutput);
splitter->SplitHorizontally(panelCode, panelOutput, 500);
sizerSplitter->Add(splitter, 1, wxEXPAND, 5);
SetSizer(sizerSplitter);
sizerSplitter->SetSizeHints(this);
Bind(wxEVT_TIMER, &MainFrame::onMeasureTimer, this, Id::MeasureTimer);
Bind(wxEVT_MENU, &MainFrame::onFileNew, this, Id::MFileNew, wxID_ANY,
menuFile->Append(MFileNew, "&New"));
Bind(wxEVT_MENU, &MainFrame::onFileOpen, this, Id::MFileOpen, wxID_ANY, menuFile->Append(MFileOpen, "&Open"));
Bind(wxEVT_MENU, &MainFrame::onFileOpen, this, Id::MFileOpen, wxID_ANY,
menuFile->Append(MFileOpen, "&Open"));
menuFile->Append(MFileOpenTemplate, "Open &Template", loadTemplates());
Bind(wxEVT_MENU, &MainFrame::onFileSave, this, Id::MFileSave, wxID_ANY,
menuFile->Append(MFileSave, "&Save"));
Bind(wxEVT_MENU, &MainFrame::onFileSaveAs, this, Id::MFileSaveAs, wxID_ANY,
@ -42,7 +87,6 @@ MainFrame::MainFrame() : wxFrame(nullptr, -1, "stmdspgui", wxPoint(50, 50), wxSi
Bind(wxEVT_MENU, &MainFrame::onFileQuit, this, Id::MFileQuit, wxID_ANY,
menuFile->Append(MFileQuit, "&Quit"));
auto menuRun = new wxMenu;
Bind(wxEVT_MENU, &MainFrame::onRunConnect, this, Id::MRunConnect, wxID_ANY,
menuRun->Append(MRunConnect, "&Connect"));
menuRun->AppendSeparator();
@ -50,31 +94,34 @@ MainFrame::MainFrame() : wxFrame(nullptr, -1, "stmdspgui", wxPoint(50, 50), wxSi
menuRun->Append(MRunStart, "&Start"));
m_run_measure = menuRun->AppendCheckItem(MRunMeasure, "&Measure code time");
menuRun->AppendSeparator();
Bind(wxEVT_MENU, &MainFrame::onRunCompile, this, Id::MRunCompile, wxID_ANY,
menuRun->Append(MRunCompile, "&Compile code"));
Bind(wxEVT_MENU, &MainFrame::onRunUpload, this, Id::MRunUpload, wxID_ANY,
menuRun->Append(MRunUpload, "&Upload code"));
Bind(wxEVT_MENU, &MainFrame::onRunUnload, this, Id::MRunUnload, wxID_ANY,
menuRun->Append(MRunUnload, "U&nload code"));
menubar->Append(menuFile, "&File");
menubar->Append(menuRun, "&Run");
SetMenuBar(menubar);
Bind(wxEVT_MENU, &MainFrame::onRunCompile, this, Id::MCodeCompile, wxID_ANY,
menuCode->Append(MCodeCompile, "&Compile code"));
Bind(wxEVT_MENU, &MainFrame::onCodeDisassemble, this, Id::MCodeDisassemble, wxID_ANY,
menuCode->Append(MCodeDisassemble, "Show &Disassembly"));
auto window = new wxBoxSizer(wxVERTICAL);
Bind(wxEVT_CLOSE_WINDOW, &MainFrame::onCloseEvent, this, wxID_ANY);
m_text_editor = new wxStyledTextCtrl(this, wxID_ANY, wxDefaultPosition, wxSize(620, 500));
prepareEditor();
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);
m_menu_bar->Append(menuFile, "&File");
m_menu_bar->Append(menuRun, "&Run");
m_menu_bar->Append(menuCode, "&Code");
SetMenuBar(m_menu_bar);
}
m_measure_timer = new wxTimer(this, Id::MeasureTimer);
Bind(wxEVT_TIMER, &MainFrame::onMeasureTimer, this, Id::MeasureTimer);
void MainFrame::onCloseEvent(wxCloseEvent& event)
{
SetMenuBar(nullptr);
m_menu_bar->Remove(2);
m_menu_bar->Remove(1);
m_menu_bar->Remove(0);
delete m_menu_bar;
delete m_measure_timer;
event.Skip();
}
void MainFrame::onMeasureTimer([[maybe_unused]] wxTimerEvent&)
@ -157,24 +204,25 @@ extern "C" void process_data_entry()
wxString MainFrame::compileEditorCode()
{
static wxString temp_file_name;
if (m_temp_file_name.IsEmpty())
m_temp_file_name = wxFileName::CreateTempFileName("stmdspgui");
if (temp_file_name.IsEmpty())
temp_file_name = wxFileName::CreateTempFileName("stmdspgui");
wxFile file (temp_file_name, wxFile::write);
wxFile file (m_temp_file_name, wxFile::write);
file.Write(file_header + m_text_editor->GetText());
file.Close();
wxFile makefile (temp_file_name + "make", wxFile::write);
wxFile makefile (m_temp_file_name + "make", wxFile::write);
wxString make_text (makefile_text);
make_text.Replace("$0", temp_file_name);
make_text.Replace("$0", m_temp_file_name);
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" +
wxString make_output = m_temp_file_name + "make.log";
if (wxFile::Exists(make_output))
wxRemoveFile(make_output);
wxString make_command = wxString("make -C ") + m_temp_file_name.BeforeLast('/') +
" -f " + m_temp_file_name + "make" +
" > " + make_output + " 2>&1";
int result = system(make_command.ToAscii());
@ -182,9 +230,11 @@ wxString MainFrame::compileEditorCode()
if (result == 0) {
m_status_bar->SetStatusText("Compilation succeeded.");
return temp_file_name + ".o";
m_compile_output->ChangeValue("");
return m_temp_file_name + ".o";
} else {
m_status_bar->SetStatusText("Compilation failed.");
m_compile_output->LoadFile(make_output);
return "";
}
}
@ -211,7 +261,8 @@ void MainFrame::onFileOpen([[maybe_unused]] wxCommandEvent&)
if (openDialog.ShowModal() != wxID_CANCEL) {
if (wxFileInputStream file_stream (openDialog.GetPath()); file_stream.IsOk()) {
auto size = file_stream.GetSize();
auto buffer = new char[size];
auto buffer = new char[size + 1];
buffer[size] = '\0';
if (file_stream.ReadAll(buffer, size)) {
m_open_file_path = openDialog.GetPath();
m_text_editor->SetText(buffer);
@ -223,6 +274,25 @@ void MainFrame::onFileOpen([[maybe_unused]] wxCommandEvent&)
}
}
void MainFrame::onFileOpenTemplate(wxCommandEvent& event)
{
auto file_path = wxGetCwd() + "/templates/" + m_menu_bar->GetLabel(event.GetId());
if (wxFileInputStream file_stream (file_path); file_stream.IsOk()) {
auto size = file_stream.GetSize();
auto buffer = new char[size + 1];
buffer[size] = '\0';
if (file_stream.ReadAll(buffer, size)) {
m_open_file_path = "";
m_text_editor->SetText(buffer);
//m_text_editor->DiscardEdits();
m_status_bar->SetStatusText("Ready.");
}
delete[] buffer;
}
}
void MainFrame::onFileSave(wxCommandEvent& ce)
{
if (m_text_editor->IsModified()) {
@ -328,11 +398,6 @@ void MainFrame::onRunStart(wxCommandEvent& ce)
}
}
void MainFrame::onRunCompile([[maybe_unused]] wxCommandEvent&)
{
compileEditorCode();
}
void MainFrame::onRunUpload([[maybe_unused]] wxCommandEvent&)
{
if (auto file = compileEditorCode(); !file.IsEmpty()) {
@ -363,3 +428,42 @@ void MainFrame::onRunUnload([[maybe_unused]] wxCommandEvent&)
}
}
void MainFrame::onRunCompile([[maybe_unused]] wxCommandEvent&)
{
compileEditorCode();
}
void MainFrame::onCodeDisassemble([[maybe_unused]] wxCommandEvent&)
{
auto output = m_temp_file_name + ".asm.log";
wxString command = wxString("arm-none-eabi-objdump -d ") + m_temp_file_name + ".orig.o"
" > " + output + " 2>&1";
if (system(command.ToAscii()) == 0) {
m_compile_output->LoadFile(output);
m_status_bar->SetStatusText(wxString::Format(wxT("Done. Line count: %u."),
m_compile_output->GetNumberOfLines()));
} else {
m_compile_output->ChangeValue("");
m_status_bar->SetStatusText("Failed to load disassembly (code compiled?).");
}
}
wxMenu *MainFrame::loadTemplates()
{
wxMenu *menu = new wxMenu;
wxArrayString files;
if (wxDir::GetAllFiles(wxGetCwd() + "/templates", &files, "*.cpp", wxDIR_FILES) > 0) {
files.Sort();
int id = 1000;
for (auto file : files) {
Bind(wxEVT_MENU, &MainFrame::onFileOpenTemplate, this, id, wxID_ANY,
menu->Append(id, file.AfterLast('/')));
id++;
}
}
return menu;
}

@ -23,18 +23,23 @@ class MainFrame : public wxFrame
public:
MainFrame();
void onCloseEvent(wxCloseEvent&);
void onFileNew(wxCommandEvent&);
void onFileOpen(wxCommandEvent&);
void onFileOpenTemplate(wxCommandEvent&);
void onFileSave(wxCommandEvent&);
void onFileSaveAs(wxCommandEvent&);
void onFileQuit(wxCommandEvent&);
void onRunConnect(wxCommandEvent&);
void onRunStart(wxCommandEvent&);
void onRunCompile(wxCommandEvent&);
void onRunUpload(wxCommandEvent&);
void onRunUnload(wxCommandEvent&);
void onRunCompile(wxCommandEvent&);
void onCodeDisassemble(wxCommandEvent&);
void onMeasureTimer(wxTimerEvent& te);
private:
@ -46,13 +51,16 @@ private:
wxMenuItem *m_run_measure = nullptr;
wxTimer *m_measure_timer = nullptr;
wxStatusBar *m_status_bar = nullptr;
wxMenuBar *m_menu_bar = nullptr;
wxString m_open_file_path;
wxString m_temp_file_name;
stmdsp::device *m_device = nullptr;
bool tryDevice();
void prepareEditor();
wxString compileEditorCode();
wxMenu *loadTemplates();
};
#endif // WXMAIN_HPP_

Loading…
Cancel
Save