aboutsummaryrefslogtreecommitdiffstats
path: root/source/code.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/code.cpp')
-rw-r--r--source/code.cpp194
1 files changed, 194 insertions, 0 deletions
diff --git a/source/code.cpp b/source/code.cpp
new file mode 100644
index 0000000..ae0d2bf
--- /dev/null
+++ b/source/code.cpp
@@ -0,0 +1,194 @@
+/**
+ * @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 std::string statusMessage;
+extern stmdsp::device *m_device;
+
+TextEditor editor; // file.cpp
+static std::string editorCompiled;
+static std::string compileMessage;
+
+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, 635}, true);
+
+ if (ImGui::BeginPopup("compile", ImGuiWindowFlags_AlwaysHorizontalScrollbar)) {
+ ImGui::Text(compileMessage.c_str());
+ if (ImGui::Button("Close"))
+ ImGui::CloseCurrentPopup();
+ ImGui::EndPopup();
+ }
+}
+
+void compileEditorCode()
+{
+ // 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();
+ compileMessage = sstr.str();
+
+ std::filesystem::remove(tempFileName);
+ std::filesystem::remove(tempFileName + script_ext);
+ std::filesystem::remove(makeOutput);
+
+ if (result == 0) {
+ editorCompiled = editor.GetText();
+ statusMessage = "Compilation succeeded.";
+ } else {
+ statusMessage = "Compilation failed.";
+ ImGui::OpenPopup("compile");
+ }
+}
+
+void disassembleCode()
+{
+ 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();
+ compileMessage = sstr.str();
+ }
+
+ ImGui::OpenPopup("compile");
+ std::filesystem::remove(output);
+
+ statusMessage = "Ready.";
+ } else {
+ statusMessage = "Failed to load disassembly.";
+ }
+}
+
+std::string newTempFileName()
+{
+ auto tempPath = std::filesystem::temp_directory_path();
+ tempPath /= "stmdspgui_build";
+ return tempPath.string();
+}
+