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.
dsp-paw/firmware/source/communication.cpp

294 lines
9.0 KiB
C++

#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 measureConversion(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', measureConversion},
{'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 measureConversion(unsigned char *)
{
if (EM.assert(run_status == RunStatus::Running, Error::NotRunning))
ConversionManager::startMeasurement();
}
void startConversion(unsigned char *)
{
if (EM.assert(run_status == RunStatus::Idle, Error::NotIdle)) {
run_status = RunStatus::Running;
ConversionManager::start();
}
}
void stopConversion(unsigned char *)
{
if (EM.assert(run_status == RunStatus::Running, Error::NotRunning)) {
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);
}