You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
stmdspgui/source/code.cpp

191 lines
5.1 KiB
C++

/**
* @file code.cpp
* @brief Contains code for algorithm-code-related UI elements and logic.
*
* Copyright (C) 2021 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 "imgui.h"
#include "backends/imgui_impl_sdl.h"
#include "backends/imgui_impl_opengl2.h"
#include "TextEditor.h"
#include "config.h"
#include "stmdsp.hpp"
#include "stmdsp_code.hpp"
#include <cstdio>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <string>
extern std::string tempFileName;
extern stmdsp::device *m_device;
extern void log(const std::string& str);
TextEditor editor; // file.cpp
static std::string editorCompiled;
static std::string newTempFileName();
static void compileEditorCode();
static void disassembleCode();
void codeEditorInit()
{
editor.SetLanguageDefinition(TextEditor::LanguageDefinition::CPlusPlus());
editor.SetPalette(TextEditor::GetLightPalette());
}
void codeRenderMenu()
{
if (ImGui::BeginMenu("Code")) {
if (ImGui::MenuItem("Compile code"))
compileEditorCode();
if (ImGui::MenuItem("Show disassembly"))
disassembleCode();
ImGui::EndMenu();
}
}
void codeRenderToolbar()
{
if (ImGui::Button("Compile"))
compileEditorCode();
ImGui::SameLine();
ImGui::Button("Upload");
}
void codeRenderWidgets()
{
editor.Render("code", {WINDOW_WIDTH - 15, 450}, true);
}
void compileEditorCode()
{
log("Compiling...");
// Scrap cached build if there are changes
if (editor.GetText().compare(editorCompiled) != 0) {
std::filesystem::remove(tempFileName + ".o");
std::filesystem::remove(tempFileName + ".orig.o");
}
stmdsp::platform platform;
if (m_device != nullptr) {
platform = m_device->get_platform();
} else {
// Assume a default.
platform = stmdsp::platform::L4;
}
if (tempFileName.size() == 0)
tempFileName = newTempFileName();
{
std::ofstream file (tempFileName, std::ios::trunc | std::ios::binary);
auto file_text = platform == stmdsp::platform::L4 ? stmdsp::file_header_l4
: stmdsp::file_header_h7;
auto samples_text = std::to_string(m_device ? m_device->get_buffer_size()
: stmdsp::SAMPLES_MAX);
for (std::size_t i = 0; (i = file_text.find("$0", i)) != std::string::npos;) {
file_text.replace(i, 2, samples_text);
i += 2;
}
file << file_text;
file << "\n";
file << editor.GetText();
}
constexpr const char *script_ext =
#ifndef STMDSP_WIN32
".sh";
#else
".bat";
#endif
{
std::ofstream makefile (tempFileName + script_ext, std::ios::binary);
auto make_text = platform == stmdsp::platform::L4 ? stmdsp::makefile_text_l4
: stmdsp::makefile_text_h7;
auto cwd = std::filesystem::current_path().string();
for (std::size_t i = 0; (i = make_text.find("$0", i)) != std::string::npos;) {
make_text.replace(i, 2, tempFileName);
i += 2;
}
for (std::size_t i = 0; (i = make_text.find("$1", i)) != std::string::npos;) {
make_text.replace(i, 2, cwd);
i += 2;
}
makefile << make_text;
}
auto makeOutput = tempFileName + script_ext + ".log";
auto makeCommand = tempFileName + script_ext + " > " + makeOutput + " 2>&1";
#ifndef STMDSP_WIN32
system((std::string("chmod +x ") + tempFileName + script_ext).c_str());
#endif
int result = system(makeCommand.c_str());
std::ifstream result_file (makeOutput);
std::ostringstream sstr;
sstr << result_file.rdbuf();
log(sstr.str().c_str());
std::filesystem::remove(tempFileName);
std::filesystem::remove(tempFileName + script_ext);
std::filesystem::remove(makeOutput);
if (result == 0) {
editorCompiled = editor.GetText();
log("Compilation succeeded.");
} else {
log("Compilation failed.");
}
}
void disassembleCode()
{
log("Disassembling...");
if (tempFileName.size() == 0 || editor.GetText().compare(editorCompiled) != 0) {
compileEditorCode();
}
auto output = tempFileName + ".asm.log";
auto command = std::string("arm-none-eabi-objdump -d --no-show-raw-insn ") +
tempFileName + ".orig.o > " + output + " 2>&1";
if (system(command.c_str()) == 0) {
{
std::ifstream result_file (output);
std::ostringstream sstr;
sstr << result_file.rdbuf();
log(sstr.str().c_str());
}
ImGui::OpenPopup("compile");
std::filesystem::remove(output);
log("Ready.");
} else {
log("Failed to load disassembly.");
}
}
std::string newTempFileName()
{
auto tempPath = std::filesystem::temp_directory_path();
tempPath /= "stmdspgui_build";
return tempPath.string();
}