feat(simu): cross-platform connection of host serial ports to simu radio (#5584)

This commit is contained in:
Nigel Williams
2024-12-16 20:00:42 +10:00
committed by GitHub
parent 8885016fd5
commit 9109d4f46f
22 changed files with 789 additions and 808 deletions
+193
View File
@@ -23,6 +23,7 @@
#include "edgetx.h"
#include "simulcd.h"
#include "switches.h"
#include "serial.h"
#include "hal/adc_driver.h"
#include "hal/rotary_encoder.h"
@@ -41,6 +42,16 @@
int16_t g_anas[MAX_ANALOG_INPUTS];
QVector<QIODevice *> OpenTxSimulator::tracebackDevices;
typedef struct {
uint8_t index;
QMutex mutex;
QQueue<uint8_t> receiveBuffer;
OpenTxSimulator * simulator;
} simulated_serial_port_t;
simulated_serial_port_t simulatedSerialPorts[MAX_AUX_SERIAL];
extern etx_serial_port_t * serialPorts[MAX_AUX_SERIAL];
#if defined(HARDWARE_TOUCH)
tmr10ms_t downTime = 0;
tmr10ms_t tapTime = 0;
@@ -74,6 +85,94 @@ void firmwareTraceCb(const char * text)
}
}
// Serial port handling needs to know about OpenTxSimulator, so we we
// need to update what's in simpgmspace.cpp when we have a simulator
// to point at.
static void* simulator_host_drv_init(void* hw_def, const etx_serial_init* dev)
{
if (hw_def == nullptr)
return nullptr;
simulated_serial_port_t *port = (simulated_serial_port_t *)hw_def;
port->simulator->drv_auxSerialInit(port->index, dev);
// Return the port definition as the context
return (void *)port;
}
static void simulator_host_drv_deinit(void* ctx)
{
if (ctx == nullptr)
return;
simulated_serial_port_t *port = (simulated_serial_port_t *)ctx;
port->simulator->drv_auxSerialDeinit(port->index);
}
static void simulator_host_drv_send_byte(void* ctx, uint8_t b)
{
if (ctx == nullptr)
return;
simulated_serial_port_t *port = (simulated_serial_port_t *)ctx;
port->simulator->drv_auxSerialSendByte(port->index, b);
}
static void simulator_host_drv_send_buffer(void* ctx, const uint8_t* b, uint32_t l)
{
if (ctx == nullptr)
return;
simulated_serial_port_t *port = (simulated_serial_port_t *)ctx;
port->simulator->drv_auxSerialSendBuffer(port->index, b, l);
}
static int simulator_host_drv_get_byte(void* ctx, uint8_t* b)
{
if (ctx == nullptr)
return 0;
simulated_serial_port_t *port = (simulated_serial_port_t *)ctx;
return port->simulator->drv_auxSerialGetByte(port->index, b);
}
static void simulator_host_drv_set_baudrate(void* ctx, uint32_t baudrate)
{
if (ctx == nullptr)
return;
simulated_serial_port_t *port = (simulated_serial_port_t *)ctx;
port->simulator->drv_auxSerialSetBaudrate(port->index, baudrate);
}
static const etx_serial_driver_t simulator_host_drv = {
.init = simulator_host_drv_init,
.deinit = simulator_host_drv_deinit,
.sendByte = simulator_host_drv_send_byte,
.sendBuffer = simulator_host_drv_send_buffer,
.txCompleted = nullptr,
.waitForTxCompleted = nullptr,
.enableRx = nullptr,
.getByte = simulator_host_drv_get_byte,
.getLastByte = nullptr,
.getBufferedBytes = nullptr,
.copyRxBuffer = nullptr,
.clearRxBuffer = nullptr,
.getBaudrate = nullptr,
.setBaudrate = simulator_host_drv_set_baudrate,
.setPolarity = nullptr,
.setHWOption = nullptr,
.setReceiveCb = nullptr,
.setIdleCb = nullptr,
.setBaudrateCb = nullptr,
};
OpenTxSimulator::OpenTxSimulator() :
SimulatorInterface(),
m_timer10ms(nullptr),
@@ -82,6 +181,17 @@ OpenTxSimulator::OpenTxSimulator() :
{
tracebackDevices.clear();
traceCallback = firmwareTraceCb;
// When we create the simulator, we change the UART driver
for (int i = 0; i < MAX_AUX_SERIAL; i++) {
etx_serial_port_t * port = serialPorts[i];
if (port != nullptr) {
port->uart = &simulator_host_drv;
port->hw_def = &(simulatedSerialPorts[i]);
simulatedSerialPorts[i].index = i;
simulatedSerialPorts[i].simulator = this;
}
}
}
OpenTxSimulator::~OpenTxSimulator()
@@ -89,6 +199,13 @@ OpenTxSimulator::~OpenTxSimulator()
traceCallback = nullptr;
tracebackDevices.clear();
for (int i = 0; i < MAX_AUX_SERIAL; i++) {
etx_serial_port_t * port = serialPorts[i];
if (port != nullptr) {
port->hw_def = nullptr;
}
}
if (m_timer10ms)
delete m_timer10ms;
@@ -507,6 +624,14 @@ const int OpenTxSimulator::getCapability(Capability cap)
case CAP_TELEM_FRSKY_SPORT :
ret = 1;
break;
case CAP_SERIAL_AUX1:
ret = (auxSerialGetPort(SP_AUX1) != nullptr);
break;
case CAP_SERIAL_AUX2:
ret = (auxSerialGetPort(SP_AUX2) != nullptr);
break;
}
return ret;
}
@@ -539,6 +664,74 @@ void OpenTxSimulator::removeTracebackDevice(QIODevice * device)
}
}
void OpenTxSimulator::receiveAuxSerialData(quint8 port_nr, const QByteArray & data)
{
if (port_nr >= MAX_AUX_SERIAL)
return;
QMutexLocker locker(&(simulatedSerialPorts[port_nr].mutex));
for (uint8_t byte : data)
simulatedSerialPorts[port_nr].receiveBuffer.enqueue(byte);
}
void OpenTxSimulator::drv_auxSerialSetBaudrate(quint8 port_nr, quint32 baudrate)
{
emit auxSerialSetBaudrate(port_nr, baudrate);
}
void OpenTxSimulator::drv_auxSerialInit(quint8 port_nr, const etx_serial_init* dev)
{
switch(dev->encoding) {
case ETX_Encoding_8N1:
emit auxSerialSetEncoding(port_nr, SERIAL_ENCODING_8N1);
break;
case ETX_Encoding_8E2:
emit auxSerialSetEncoding(port_nr, SERIAL_ENCODING_8E2);
break;
default:
// Do nothing, host hardware can't do SERIAL_ENCODING_PXX1_PWM
break;
}
if (dev->baudrate != 0)
emit auxSerialSetBaudrate(port_nr, dev->baudrate);
emit auxSerialStart(port_nr);
}
void OpenTxSimulator::drv_auxSerialDeinit(quint8 port_nr)
{
emit auxSerialStop(port_nr);
}
void OpenTxSimulator::drv_auxSerialSendByte(quint8 port_nr, uint8_t b)
{
QByteArray data = QByteArray((const char *)&b, 1);
emit auxSerialSendData(port_nr, data);
}
void OpenTxSimulator::drv_auxSerialSendBuffer(quint8 port_nr, const uint8_t* b, uint32_t l)
{
QByteArray data = QByteArray((const char *)b, l);
emit auxSerialSendData(port_nr, data);
}
int OpenTxSimulator::drv_auxSerialGetByte(quint8 port_nr, uint8_t *b)
{
// Obtain the port's mutex before messing with the buffer
QMutexLocker locker(&(simulatedSerialPorts[port_nr].mutex));
if (simulatedSerialPorts[port_nr].receiveBuffer.isEmpty())
return 0;
uint8_t byte = simulatedSerialPorts[port_nr].receiveBuffer.dequeue();
*b = byte;
return 1;
}
/*** Protected functions ***/