aboutsummaryrefslogtreecommitdiffstats
path: root/source/communication.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/communication.cpp')
-rw-r--r--source/communication.cpp295
1 files changed, 295 insertions, 0 deletions
diff --git a/source/communication.cpp b/source/communication.cpp
new file mode 100644
index 0000000..b5ee28e
--- /dev/null
+++ b/source/communication.cpp
@@ -0,0 +1,295 @@
+#include "communication.hpp"
+
+#include "ch.h"
+#include "hal.h"
+
+#include "periph/adc.hpp"
+#include "periph/dac.hpp"
+#include "periph/usbserial.hpp"
+#include "elfload.hpp"
+#include "error.hpp"
+#include "conversion.hpp"
+#include "runstatus.hpp"
+#include "samples.hpp"
+
+#include <algorithm>
+#include <tuple>
+
+__attribute__((section(".stacks")))
+std::array<char, 4096> CommunicationManager::m_thread_stack = {};
+
+void CommunicationManager::begin()
+{
+ chThdCreateStatic(m_thread_stack.data(),
+ m_thread_stack.size(),
+ NORMALPRIO,
+ threadComm,
+ nullptr);
+}
+
+static void writeADCBuffer(unsigned char *);
+static void setBufferSize(unsigned char *);
+static void updateGenerator(unsigned char *);
+static void loadAlgorithm(unsigned char *);
+static void readStatus(unsigned char *);
+static void startConversionMeasure(unsigned char *);
+static void startConversion(unsigned char *);
+static void stopConversion(unsigned char *);
+static void startGenerator(unsigned char *);
+static void readADCBuffer(unsigned char *);
+static void readDACBuffer(unsigned char *);
+static void unloadAlgorithm(unsigned char *);
+static void readIdentifier(unsigned char *);
+static void readExecTime(unsigned char *);
+static void sampleRate(unsigned char *);
+static void readConversionResults(unsigned char *);
+static void readConversionInput(unsigned char *);
+static void readMessage(unsigned char *);
+static void stopGenerator(unsigned char *);
+
+static const std::array<std::pair<char, void (*)(unsigned char *)>, 19> commandTable {{
+ {'A', writeADCBuffer},
+ {'B', setBufferSize},
+ {'D', updateGenerator},
+ {'E', loadAlgorithm},
+ {'I', readStatus},
+ {'M', startConversionMeasure},
+ {'R', startConversion},
+ {'S', stopConversion},
+ {'W', startGenerator},
+ {'a', readADCBuffer},
+ {'d', readDACBuffer},
+ {'e', unloadAlgorithm},
+ {'i', readIdentifier},
+ {'m', readExecTime},
+ {'r', sampleRate},
+ {'s', readConversionResults},
+ {'t', readConversionInput},
+ {'u', readMessage},
+ {'w', stopGenerator}
+}};
+
+void CommunicationManager::threadComm(void *)
+{
+ while (1) {
+ if (USBSerial::isActive()) {
+ // Attempt to receive a command packet
+ if (unsigned char cmd[3]; USBSerial::read(&cmd[0], 1) > 0) {
+ // Packet received, first byte represents the desired command/action
+ auto func = std::find_if(commandTable.cbegin(), commandTable.cend(),
+ [&cmd](const auto& f) { return f.first == cmd[0]; });
+ if (func != commandTable.cend())
+ func->second(cmd);
+ }
+ }
+
+ chThdSleepMicroseconds(100);
+ }
+}
+
+void writeADCBuffer(unsigned char *)
+{
+ USBSerial::read(Samples::In.bytedata(), Samples::In.bytesize());
+}
+
+void setBufferSize(unsigned char *cmd)
+{
+ if (EM.assert(run_status == RunStatus::Idle, Error::NotIdle) &&
+ EM.assert(USBSerial::read(&cmd[1], 2) == 2, Error::BadParamSize))
+ {
+ // count is multiplied by two since this command receives size of buffer
+ // for each algorithm application.
+ unsigned int count = (cmd[1] | (cmd[2] << 8)) * 2;
+ if (EM.assert(count <= MAX_SAMPLE_BUFFER_SIZE, Error::BadParam)) {
+ Samples::In.setSize(count);
+ Samples::Out.setSize(count);
+ }
+ }
+}
+
+void updateGenerator(unsigned char *cmd)
+{
+ if (EM.assert(USBSerial::read(&cmd[1], 2) == 2, Error::BadParamSize)) {
+ unsigned int count = cmd[1] | (cmd[2] << 8);
+ if (EM.assert(count <= MAX_SAMPLE_BUFFER_SIZE, Error::BadParam)) {
+ if (!DAC::isSigGenRunning()) {
+ Samples::Generator.setSize(count);
+ USBSerial::read(
+ reinterpret_cast<uint8_t *>(Samples::Generator.data()),
+ Samples::Generator.bytesize());
+ } else {
+ const int more = DAC::sigGenWantsMore();
+ if (more == -1) {
+ USBSerial::write(reinterpret_cast<const uint8_t *>("\0"), 1);
+ } else {
+ USBSerial::write(reinterpret_cast<const uint8_t *>("\1"), 1);
+
+ // Receive streamed samples in half-buffer chunks.
+ USBSerial::read(reinterpret_cast<uint8_t *>(
+ more == 0 ? Samples::Generator.data() : Samples::Generator.middata()),
+ Samples::Generator.bytesize() / 2);
+ }
+ }
+ }
+ }
+}
+
+void loadAlgorithm(unsigned char *cmd)
+{
+ if (EM.assert(run_status == RunStatus::Idle, Error::NotIdle) &&
+ EM.assert(USBSerial::read(&cmd[1], 2) == 2, Error::BadParamSize))
+ {
+ // Only load the binary if it can fit in the memory reserved for it.
+ unsigned int size = cmd[1] | (cmd[2] << 8);
+ if (EM.assert(size < MAX_ELF_FILE_SIZE, Error::BadUserCodeSize)) {
+ USBSerial::read(ELFManager::fileBuffer(), size);
+ auto success = ELFManager::loadFromInternalBuffer();
+ EM.assert(success, Error::BadUserCodeLoad);
+ }
+ }
+}
+
+void readStatus(unsigned char *)
+{
+ unsigned char buf[2] = {
+ static_cast<unsigned char>(run_status),
+ static_cast<unsigned char>(EM.pop())
+ };
+
+ USBSerial::write(buf, sizeof(buf));
+}
+
+void startConversionMeasure(unsigned char *)
+{
+ if (EM.assert(run_status == RunStatus::Idle, Error::NotIdle)) {
+ run_status = RunStatus::Running;
+ ConversionManager::startMeasured();
+ }
+}
+
+void startConversion(unsigned char *)
+{
+ if (EM.assert(run_status == RunStatus::Idle, Error::NotIdle)) {
+ run_status = RunStatus::Running;
+ ConversionManager::start();
+ }
+}
+
+void stopConversion(unsigned char *)
+{
+ if (run_status == RunStatus::Running) {
+ ConversionManager::stop();
+ run_status = RunStatus::Idle;
+ }
+}
+
+void startGenerator(unsigned char *)
+{
+ DAC::start(1, Samples::Generator.data(), Samples::Generator.size());
+}
+
+void readADCBuffer(unsigned char *)
+{
+ USBSerial::write(Samples::In.bytedata(), Samples::In.bytesize());
+}
+
+void readDACBuffer(unsigned char *)
+{
+
+ USBSerial::write(Samples::Out.bytedata(), Samples::Out.bytesize());
+}
+
+void unloadAlgorithm(unsigned char *)
+{
+ ELFManager::unload();
+}
+
+void readIdentifier(unsigned char *)
+{
+#if defined(TARGET_PLATFORM_H7)
+ USBSerial::write(reinterpret_cast<const uint8_t *>("stmdsph"), 7);
+#else
+ USBSerial::write(reinterpret_cast<const uint8_t *>("stmdspl"), 7);
+#endif
+}
+
+void readExecTime(unsigned char *)
+{
+ // Stores the measured execution time.
+ extern time_measurement_t conversion_time_measurement;
+ USBSerial::write(reinterpret_cast<uint8_t *>(&conversion_time_measurement.last),
+ sizeof(rtcnt_t));
+}
+
+void sampleRate(unsigned char *cmd)
+{
+ if (EM.assert(USBSerial::read(&cmd[1], 1) == 1, Error::BadParamSize)) {
+ if (cmd[1] == 0xFF) {
+ unsigned char r = SClock::getRate();
+ USBSerial::write(&r, 1);
+ } else {
+ auto r = static_cast<SClock::Rate>(cmd[1]);
+ SClock::setRate(r);
+ ADC::setRate(r);
+ }
+ }
+}
+
+void readConversionResults(unsigned char *)
+{
+ if (auto samps = Samples::Out.modified(); samps != nullptr) {
+ unsigned char buf[2] = {
+ static_cast<unsigned char>(Samples::Out.size() / 2 & 0xFF),
+ static_cast<unsigned char>(((Samples::Out.size() / 2) >> 8) & 0xFF)
+ };
+ USBSerial::write(buf, 2);
+ unsigned int total = Samples::Out.bytesize() / 2;
+ unsigned int offset = 0;
+ unsigned char unused;
+ while (total > 512) {
+ USBSerial::write(reinterpret_cast<uint8_t *>(samps) + offset, 512);
+ while (USBSerial::read(&unused, 1) == 0);
+ offset += 512;
+ total -= 512;
+ }
+ USBSerial::write(reinterpret_cast<uint8_t *>(samps) + offset, total);
+ while (USBSerial::read(&unused, 1) == 0);
+ } else {
+ USBSerial::write(reinterpret_cast<const uint8_t *>("\0\0"), 2);
+ }
+}
+
+void readConversionInput(unsigned char *)
+{
+ if (auto samps = Samples::In.modified(); samps != nullptr) {
+ unsigned char buf[2] = {
+ static_cast<unsigned char>(Samples::In.size() / 2 & 0xFF),
+ static_cast<unsigned char>(((Samples::In.size() / 2) >> 8) & 0xFF)
+ };
+ USBSerial::write(buf, 2);
+ unsigned int total = Samples::In.bytesize() / 2;
+ unsigned int offset = 0;
+ unsigned char unused;
+ while (total > 512) {
+ USBSerial::write(reinterpret_cast<uint8_t *>(samps) + offset, 512);
+ while (USBSerial::read(&unused, 1) == 0);
+ offset += 512;
+ total -= 512;
+ }
+ USBSerial::write(reinterpret_cast<uint8_t *>(samps) + offset, total);
+ while (USBSerial::read(&unused, 1) == 0);
+ } else {
+ USBSerial::write(reinterpret_cast<const uint8_t *>("\0\0"), 2);
+ }
+}
+
+void readMessage(unsigned char *)
+{
+ //USBSerial::write(reinterpret_cast<uint8_t *>(userMessageBuffer), userMessageSize);
+}
+
+void stopGenerator(unsigned char *)
+{
+ DAC::stop(1);
+}
+