218 lines
7.6 KiB
C++
218 lines
7.6 KiB
C++
/*
|
|
* Copyright (C) EdgeTX
|
|
*
|
|
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "simulatorinterface.h"
|
|
|
|
#include <QMutex>
|
|
#include <QTimer>
|
|
#include <QVector>
|
|
#include <atomic>
|
|
|
|
#include "wasm_export.h"
|
|
|
|
#include <SDL.h>
|
|
|
|
class WasmSimulatorInterface : public SimulatorInterface
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
WasmSimulatorInterface(const QString & wasmPath, const QString & boardName,
|
|
Board::Type boardType);
|
|
virtual ~WasmSimulatorInterface();
|
|
|
|
QString name() override;
|
|
bool isRunning() override;
|
|
void readRadioData(QByteArray & dest) override {}
|
|
uint8_t * getLcd() override;
|
|
uint8_t getSensorInstance(uint16_t id, uint8_t defaultValue = 0) override;
|
|
uint16_t getSensorRatio(uint16_t id) override;
|
|
const int getCapability(Capability cap) override;
|
|
|
|
public slots:
|
|
void init() override;
|
|
void start(const char * filename = nullptr, bool tests = true) override;
|
|
void stop() override;
|
|
void setSdPath(const QString & sdPath = "",
|
|
const QString & settingsPath = "") override;
|
|
void setVolumeGain(const int value) override;
|
|
void setRadioData(const QByteArray & data) override {}
|
|
void setAnalogValue(uint8_t index, int16_t value) override;
|
|
void setKey(uint8_t key, bool state) override;
|
|
void setSwitch(uint8_t swtch, int8_t state) override;
|
|
void setTrim(unsigned int idx, int value) override;
|
|
void setTrimSwitch(uint8_t trim, bool state) override;
|
|
void setTrainerInput(unsigned int inputNumber, int16_t value) override;
|
|
void setInputValue(int type, uint8_t index, int16_t value) override;
|
|
void rotaryEncoderEvent(int steps) override;
|
|
void touchEvent(int type, int x, int y) override;
|
|
void lcdFlushed() override;
|
|
void setTrainerTimeout(uint16_t ms) override;
|
|
void sendInternalModuleTelemetry(const quint8 protocol,
|
|
const QByteArray data) override;
|
|
void sendExternalModuleTelemetry(const quint8 protocol,
|
|
const QByteArray data) override;
|
|
void setLuaStateReloadPermanentScripts() override;
|
|
void addTracebackDevice(QIODevice * device) override;
|
|
void removeTracebackDevice(QIODevice * device) override;
|
|
void receiveAuxSerialData(const quint8 port_num,
|
|
const QByteArray & data) override;
|
|
|
|
// Called by WASM import simuGetAnalog
|
|
int16_t getAnalogValue(uint8_t index);
|
|
|
|
// Called by WASM import simuTrace
|
|
void writeTrace(const char * text);
|
|
|
|
// Called by WASM import simuQueueAudio
|
|
void queueAudio(const uint8_t * buf, uint32_t len);
|
|
|
|
// Called by WASM import simuLcdNotify (from WAMR thread)
|
|
void notifyLcdReady();
|
|
|
|
protected slots:
|
|
void run();
|
|
void onLcdNotify();
|
|
|
|
protected:
|
|
bool loadModule();
|
|
void unloadModule();
|
|
bool resolveExports();
|
|
void refreshLcd();
|
|
void checkOutputsChanged();
|
|
void initAudio();
|
|
void deinitAudio();
|
|
|
|
QString m_wasmPath;
|
|
QString m_boardName;
|
|
Board::Type m_boardType;
|
|
QString m_sdPath;
|
|
QString m_settingsPath;
|
|
|
|
QTimer * m_timer10ms = nullptr;
|
|
std::atomic<bool> m_lcdNotified{false};
|
|
QMutex m_mutex;
|
|
QMutex m_mtxTbDevices;
|
|
QVector<QIODevice *> m_tracebackDevices;
|
|
bool m_stopRequested = false;
|
|
|
|
// Audio
|
|
SDL_AudioDeviceID m_audioDevice = 0;
|
|
int m_volumeGain = SDL_MIX_MAXVOLUME;
|
|
|
|
// Host-side analog values (polled by WASM via simuGetAnalog)
|
|
static constexpr int MAX_ANALOGS = 32;
|
|
int16_t m_analogValues[MAX_ANALOGS] = {};
|
|
|
|
// Cached output values for change detection
|
|
TxOutputs m_lastOutputs;
|
|
bool m_resetOutputsData = true;
|
|
|
|
// Persistent WASM buffer for bulk copies (allocated once in init)
|
|
uint32_t m_wasmScratchBuf = 0;
|
|
uint32_t m_wasmScratchSize = 0;
|
|
|
|
// Host-side LCD buffer + persistent WASM-side copy buffer
|
|
uint8_t * m_lcdBuffer = nullptr;
|
|
uint32_t m_lcdBufferSize = 0;
|
|
uint32_t m_wasmLcdBuf = 0;
|
|
uint32_t m_lcdWidth = 0;
|
|
uint32_t m_lcdHeight = 0;
|
|
uint32_t m_lcdDepth = 0;
|
|
|
|
// WAMR handles
|
|
wasm_module_t m_module = nullptr;
|
|
wasm_module_inst_t m_moduleInst = nullptr;
|
|
wasm_exec_env_t m_execEnv = nullptr;
|
|
QByteArray m_wasmBinary;
|
|
|
|
// Cached WASM function references
|
|
wasm_function_inst_t m_fnInit = nullptr;
|
|
wasm_function_inst_t m_fnStart = nullptr;
|
|
wasm_function_inst_t m_fnStop = nullptr;
|
|
wasm_function_inst_t m_fnIsRunning = nullptr;
|
|
wasm_function_inst_t m_fnSetKey = nullptr;
|
|
wasm_function_inst_t m_fnSetTrim = nullptr;
|
|
wasm_function_inst_t m_fnSetSwitch = nullptr;
|
|
wasm_function_inst_t m_fnLcdChanged = nullptr;
|
|
wasm_function_inst_t m_fnLcdCopy = nullptr;
|
|
wasm_function_inst_t m_fnLcdGetWidth = nullptr;
|
|
wasm_function_inst_t m_fnLcdGetHeight = nullptr;
|
|
wasm_function_inst_t m_fnLcdGetDepth = nullptr;
|
|
wasm_function_inst_t m_fnTouchDown = nullptr;
|
|
wasm_function_inst_t m_fnTouchUp = nullptr;
|
|
wasm_function_inst_t m_fnFatfsSetPaths = nullptr;
|
|
wasm_function_inst_t m_fnRotaryEncoderEvent = nullptr;
|
|
wasm_function_inst_t m_fnGetCapability = nullptr;
|
|
|
|
// Output value exports (bulk copy)
|
|
wasm_function_inst_t m_fnGetNumChannels = nullptr;
|
|
wasm_function_inst_t m_fnCopyChannelOutputs = nullptr;
|
|
wasm_function_inst_t m_fnCopyMixOutputs = nullptr;
|
|
wasm_function_inst_t m_fnGetNumLogicalSwitches = nullptr;
|
|
wasm_function_inst_t m_fnCopyLogicalSwitches = nullptr;
|
|
wasm_function_inst_t m_fnGetTrimValue = nullptr;
|
|
wasm_function_inst_t m_fnGetTrimRange = nullptr;
|
|
wasm_function_inst_t m_fnGetFlightMode = nullptr;
|
|
wasm_function_inst_t m_fnGetNumGVars = nullptr;
|
|
wasm_function_inst_t m_fnGetNumFlightModes = nullptr;
|
|
wasm_function_inst_t m_fnGetGVar = nullptr;
|
|
|
|
// Phase 4: telemetry, trim, lua, lcd, trainer
|
|
wasm_function_inst_t m_fnSetTrimValue = nullptr;
|
|
wasm_function_inst_t m_fnSendTelemetry = nullptr;
|
|
wasm_function_inst_t m_fnLuaReloadPermanentScripts = nullptr;
|
|
wasm_function_inst_t m_fnLcdFlushed = nullptr;
|
|
wasm_function_inst_t m_fnGetMaxTrainerChannels = nullptr;
|
|
wasm_function_inst_t m_fnCopyTrainerInput = nullptr;
|
|
wasm_function_inst_t m_fnSetTrainerTimeout = nullptr;
|
|
|
|
// Backlight and function switch LEDs
|
|
wasm_function_inst_t m_fnGetBacklightState = nullptr;
|
|
wasm_function_inst_t m_fnGetNumCustomSwitches = nullptr;
|
|
wasm_function_inst_t m_fnGetCustomSwitchColor = nullptr;
|
|
wasm_function_inst_t m_fnGetCustomSwitchIndex = nullptr;
|
|
|
|
// Trainer input buffer (flushed in bulk via run())
|
|
static constexpr int MAX_TRAINER_CH = 16;
|
|
int16_t m_trainerValues[MAX_TRAINER_CH] = {};
|
|
bool m_trainerDirty = false;
|
|
|
|
// Cached function switch LED colors for change detection
|
|
static constexpr int MAX_FS_LEDS = 8;
|
|
uint32_t m_lastFSLedColors[MAX_FS_LEDS] = {};
|
|
|
|
wasm_function_inst_t m_fnMalloc = nullptr;
|
|
wasm_function_inst_t m_fnFree = nullptr;
|
|
};
|
|
|
|
class WasmSimulatorFactory : public SimulatorFactory
|
|
{
|
|
public:
|
|
WasmSimulatorFactory(const QString & wasmPath, const QString & boardName,
|
|
Board::Type boardType);
|
|
|
|
QString name() override;
|
|
Board::Type type() override;
|
|
SimulatorInterface * create() override;
|
|
|
|
private:
|
|
QString m_wasmPath;
|
|
QString m_boardName;
|
|
Board::Type m_boardType;
|
|
};
|