chore: New module/serial API (#3055)
* WiP: new module interface * WiP: softserial timer DMA * WiP: setup() and send() in one step and remove methods specific to internal or external module * fixes and extra port config * horus targets * module ports have moved * T8 support (only internal module) * fix nv14 * stupid GCC.... * disable BT * remove nv14 telem driver * remove old aux serial driver * Move module buffers out of pulses.h * Soft serial fixes and PXX1 support * Fixed PPM module output * Fixed CLI * compilation fixes * Ported bluetooth and flysky gimbal to new serial driver * Re-enable soft-serial RX * fixes and cleanup * nv14 fixes * Fix flysky gimbals * Ghost module * 16 bytes of RAM * Remove getByte from module API * Ghost cleanup * fix: _half_duplex_input() must be called after usart init * WiP * more cleanup * Remove board specific settings from PXX1 / PXX2 drivers * A bit of PXX2 header cleanup * Add support for OVER8 and ONEBIT * Add some support for inverters (NV14 / EL18) * Support NV14 power fixes in generic board * Fix polarity handling * Fix RX DMA * Fix mixer not running * Add soft-serial polarity control * Quick fix for telemetry polling while module port is changed * Fix bootloader DEBUG * Fix MPM telemetry * Fix pulse start * DSM2 soft-serial fallback * DSMP async module restart * Fix CRSF LUA upstream * Remove global variable telemetryProtocol * Use HAL/LL constants * Fix various issue with AFHDS3 and NV14/EL18 internal module * Fixed S.PORT unit tests * fix: update widx after writing at current index * fix: init error condition * Fix: possible infinite loop in _find_port() * Add support for bidir S.PORT init * Add support for "getLastByte" in HW serial driver * PXX1: Add support for S.PORT based on IDLE callback * Fix rebase error * Fix softserial _rx_fifo_push() * Add softserial support for waitForTxCompleted() * Fix MPM flashing (internal / external) * Fixed external MPM * Activate RX DMA on internal module Seems to work with serial passthrough without issues, at least on the L3R PRO. * Fix softserial DMA on stdlcd F4 targets * Add softserial support for 32bit timers (mostly TIM2) * More precise soft-serial * Fix MPM update using inverters & HW uart * Raise S.PORT DMA/USART IRQ prio to achieve faster switching to input * Remove useless delays * Fix flashing external ELRS module * Added a retry mechanism for FrSky S.PORT update * Remove useless enableRx() * External FrSky modules are all flashed via S.PORT * Remove power management unit update This was only used on the first batch of X-lite.
This commit is contained in:
+141
-80
@@ -19,7 +19,12 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "dsm2.h"
|
||||
#include "hal/module_port.h"
|
||||
#include "mixer_scheduler.h"
|
||||
|
||||
#include "opentx.h"
|
||||
#include "telemetry/spektrum.h"
|
||||
|
||||
#define DSM2_SEND_BIND (1 << 7)
|
||||
#define DSM2_SEND_RANGECHECK (1 << 5)
|
||||
@@ -31,62 +36,18 @@
|
||||
#define DSMX_BIT 0x08
|
||||
#define BAD_DATA 0x47
|
||||
|
||||
#define BITLEN_DSM2 (8*2) //125000 Baud => 8uS per bit
|
||||
#define DSM2_BITRATE 125000
|
||||
|
||||
static void reset_dsm2_buffer()
|
||||
static inline void sendByte(uint8_t*& p_buf, uint8_t b)
|
||||
{
|
||||
extmodulePulsesData.dsm2.index = 0;
|
||||
extmodulePulsesData.dsm2.ptr = extmodulePulsesData.dsm2.pulses;
|
||||
*p_buf++ = b;
|
||||
}
|
||||
|
||||
static void _send_1(uint8_t v)
|
||||
{
|
||||
*extmodulePulsesData.dsm2.ptr++ = v - 1;
|
||||
extmodulePulsesData.dsm2.index += 1;
|
||||
}
|
||||
|
||||
static void _sendByte(uint8_t b, uint8_t bit_len) // max 10 changes 0 10 10 10 10 1
|
||||
{
|
||||
bool lev = 0;
|
||||
uint8_t len = bit_len; // max val: 9*16 < 256
|
||||
for (uint8_t i=0; i<=8; i++) { // 8Bits + Stop=1
|
||||
bool nlev = b & 1; // lsb first
|
||||
if (lev == nlev) {
|
||||
len += bit_len;
|
||||
}
|
||||
else {
|
||||
_send_1(len);
|
||||
len = bit_len;
|
||||
lev = nlev;
|
||||
}
|
||||
b = (b>>1) | 0x80; // shift in stop bit
|
||||
}
|
||||
_send_1(len); // stop bit (len is already bit_len)
|
||||
}
|
||||
|
||||
static void sendByteDsm2(uint8_t b)
|
||||
{
|
||||
_sendByte(b, BITLEN_DSM2);
|
||||
}
|
||||
|
||||
void putDsm2Flush()
|
||||
{
|
||||
if (extmodulePulsesData.dsm2.index & 1)
|
||||
*extmodulePulsesData.dsm2.ptr++ = 255;
|
||||
else
|
||||
*(extmodulePulsesData.dsm2.ptr - 1) = 255;
|
||||
}
|
||||
|
||||
// This is the data stream to send, prepare after 19.5 mS
|
||||
// Send after 22.5 mS
|
||||
|
||||
void setupPulsesDSM2()
|
||||
static void setupPulsesDSM2(uint8_t module, uint8_t*& p_buf)
|
||||
{
|
||||
uint8_t dsmDat[14];
|
||||
|
||||
reset_dsm2_buffer();
|
||||
|
||||
switch (moduleState[EXTERNAL_MODULE].protocol) {
|
||||
switch (moduleState[module].protocol) {
|
||||
case PROTOCOL_CHANNELS_DSM2_LP45:
|
||||
dsmDat[0] = 0x00;
|
||||
break;
|
||||
@@ -98,17 +59,17 @@ void setupPulsesDSM2()
|
||||
break;
|
||||
}
|
||||
|
||||
if (moduleState[EXTERNAL_MODULE].mode == MODULE_MODE_BIND) {
|
||||
if (moduleState[module].mode == MODULE_MODE_BIND) {
|
||||
dsmDat[0] |= DSM2_SEND_BIND;
|
||||
}
|
||||
else if (moduleState[EXTERNAL_MODULE].mode == MODULE_MODE_RANGECHECK) {
|
||||
else if (moduleState[module].mode == MODULE_MODE_RANGECHECK) {
|
||||
dsmDat[0] |= DSM2_SEND_RANGECHECK;
|
||||
}
|
||||
|
||||
dsmDat[1] = g_model.header.modelId[EXTERNAL_MODULE]; // DSM2 Header second byte for model match
|
||||
dsmDat[1] = g_model.header.modelId[module]; // DSM2 Header second byte for model match
|
||||
|
||||
for (int i=0; i<DSM2_CHANS; i++) {
|
||||
int channel = g_model.moduleData[EXTERNAL_MODULE].channelsStart+i;
|
||||
int channel = g_model.moduleData[module].channelsStart+i;
|
||||
int value = channelOutputs[channel] + 2*PPM_CH_CENTER(channel) - 2*PPM_CENTER;
|
||||
uint16_t pulse = limit(0, ((value*13)>>5)+512, 1023);
|
||||
dsmDat[2+2*i] = (i<<2) | ((pulse>>8)&0x03);
|
||||
@@ -116,36 +77,28 @@ void setupPulsesDSM2()
|
||||
}
|
||||
|
||||
for (int i=0; i<14; i++) {
|
||||
sendByteDsm2(dsmDat[i]);
|
||||
sendByte(p_buf, dsmDat[i]);
|
||||
}
|
||||
|
||||
putDsm2Flush();
|
||||
}
|
||||
|
||||
#define BITLEN_DSMP (17)
|
||||
|
||||
static void sendByteDSMP(uint8_t b)
|
||||
{
|
||||
_sendByte(b, BITLEN_DSMP);
|
||||
}
|
||||
#define DSMP_BITRATE 115200
|
||||
|
||||
void setupPulsesLemonDSMP()
|
||||
static void setupPulsesLemonDSMP(uint8_t module, uint8_t*& p_buf)
|
||||
{
|
||||
static uint8_t pass = 0;
|
||||
|
||||
reset_dsm2_buffer();
|
||||
|
||||
const auto& md = g_model.moduleData[EXTERNAL_MODULE];
|
||||
const auto& md = g_model.moduleData[module];
|
||||
|
||||
uint8_t start_channel = md.channelsStart;
|
||||
auto channels = md.getChannelsCount();
|
||||
auto flags = md.dsmp.flags & 0x3F;
|
||||
|
||||
// Force setup packet in Bind mode.
|
||||
auto module_mode = getModuleMode(EXTERNAL_MODULE);
|
||||
auto module_mode = getModuleMode(module);
|
||||
|
||||
sendByteDSMP( 0xAA );
|
||||
sendByteDSMP( pass );
|
||||
sendByte(p_buf, 0xAA);
|
||||
sendByte(p_buf, pass);
|
||||
|
||||
// Setup packet
|
||||
if (pass == 0) {
|
||||
@@ -154,17 +107,17 @@ void setupPulsesLemonDSMP()
|
||||
flags = DSM2_SEND_BIND | (1 << 6 /* AUTO */);
|
||||
channels = 12;
|
||||
}
|
||||
sendByteDSMP( flags );
|
||||
sendByte(p_buf, flags);
|
||||
|
||||
uint8_t pwr = 7;
|
||||
if (module_mode == MODULE_MODE_RANGECHECK) {
|
||||
pwr = 4;
|
||||
}
|
||||
sendByteDSMP( pwr );
|
||||
sendByteDSMP( channels );
|
||||
sendByte(p_buf, pwr);
|
||||
sendByte(p_buf, channels );
|
||||
|
||||
// Model number
|
||||
sendByteDSMP( 1 );
|
||||
sendByte(p_buf, 1);
|
||||
|
||||
// Send only 1 single Setup packet
|
||||
pass = 1;
|
||||
@@ -192,20 +145,18 @@ void setupPulsesLemonDSMP()
|
||||
pulse = limit(0, ((value*13)>>5)+512, 1023) | (current_channel << 10);
|
||||
}
|
||||
|
||||
sendByteDSMP( pulse >> 8 );
|
||||
sendByteDSMP( pulse & 0xFF );
|
||||
sendByte(p_buf, pulse >> 8);
|
||||
sendByte(p_buf, pulse & 0xFF);
|
||||
} else {
|
||||
// Outside of announced number of channels:
|
||||
// -> send invalid value
|
||||
sendByteDSMP( 0xFF );
|
||||
sendByteDSMP( 0xFF );
|
||||
sendByte(p_buf, 0xFF);
|
||||
sendByte(p_buf, 0xFF);
|
||||
}
|
||||
current_channel++;
|
||||
}
|
||||
}
|
||||
|
||||
putDsm2Flush();
|
||||
|
||||
if (++pass > 2) pass = 1;
|
||||
if (channels < 8) pass = 1;
|
||||
|
||||
@@ -213,9 +164,119 @@ void setupPulsesLemonDSMP()
|
||||
// bind packet is setup
|
||||
pass = 0;
|
||||
}
|
||||
else if (--moduleState[EXTERNAL_MODULE].counter == 0) {
|
||||
else if (--moduleState[module].counter == 0) {
|
||||
// every 100th packet is setup
|
||||
pass = 0;
|
||||
moduleState[EXTERNAL_MODULE].counter = 100;
|
||||
moduleState[module].counter = 100;
|
||||
}
|
||||
}
|
||||
|
||||
const etx_serial_init dsmUartParams = {
|
||||
.baudrate = 0,
|
||||
.encoding = ETX_Encoding_8N1,
|
||||
.direction = ETX_Dir_TX,
|
||||
.polarity = ETX_Pol_Inverted,
|
||||
};
|
||||
|
||||
static void* dsmInit(uint8_t module, uint32_t baudrate, uint16_t period, bool telemetry)
|
||||
{
|
||||
// only external module supported
|
||||
if (module == INTERNAL_MODULE) return nullptr;
|
||||
|
||||
etx_serial_init params(dsmUartParams);
|
||||
params.baudrate = baudrate;
|
||||
auto mod_st = modulePortInitSerial(module, ETX_MOD_PORT_UART, ¶ms);
|
||||
if (!mod_st) {
|
||||
// inverted soft-serial fallback
|
||||
mod_st = modulePortInitSerial(module, ETX_MOD_PORT_SOFT_INV, ¶ms);
|
||||
if (!mod_st) return nullptr;
|
||||
}
|
||||
|
||||
if (telemetry) {
|
||||
params.direction = ETX_Dir_RX;
|
||||
if (!modulePortInitSerial(module, ETX_MOD_PORT_SPORT, ¶ms)) {
|
||||
// inverted soft-serial fallback
|
||||
modulePortInitSerial(module, ETX_MOD_PORT_SPORT_INV, ¶ms);
|
||||
}
|
||||
}
|
||||
|
||||
mixerSchedulerSetPeriod(module, period);
|
||||
return (void*)mod_st;
|
||||
}
|
||||
|
||||
static void* dsm2Init(uint8_t module)
|
||||
{
|
||||
return dsmInit(module, DSM2_BITRATE, DSM2_PERIOD, false);
|
||||
}
|
||||
|
||||
static void* dsmpInit(uint8_t module)
|
||||
{
|
||||
return dsmInit(module, DSMP_BITRATE, 11 * 1000 /* 11ms in us */, true);
|
||||
}
|
||||
|
||||
|
||||
static void dsmDeInit(void* ctx)
|
||||
{
|
||||
auto mod_st = (etx_module_state_t*)ctx;
|
||||
modulePortDeInit(mod_st);
|
||||
}
|
||||
|
||||
static void _dsm_send(etx_module_state_t* st, uint8_t* buffer, uint32_t len)
|
||||
{
|
||||
auto drv = modulePortGetSerialDrv(st->tx);
|
||||
auto ctx = modulePortGetCtx(st->tx);
|
||||
drv->sendBuffer(ctx, buffer, len);
|
||||
}
|
||||
|
||||
static void dsm2SendPulses(void* ctx, uint8_t* buffer, int16_t* channels, uint8_t nChannels)
|
||||
{
|
||||
// TODO:
|
||||
(void)channels;
|
||||
(void)nChannels;
|
||||
|
||||
auto mod_st = (etx_module_state_t*)ctx;
|
||||
auto module = modulePortGetModule(mod_st);
|
||||
|
||||
auto p_data = buffer;
|
||||
setupPulsesDSM2(module, p_data);
|
||||
_dsm_send(mod_st, buffer, p_data - buffer);
|
||||
}
|
||||
|
||||
static void dsmpSendPulses(void* ctx, uint8_t* buffer, int16_t* channels, uint8_t nChannels)
|
||||
{
|
||||
// TODO:
|
||||
(void)channels;
|
||||
(void)nChannels;
|
||||
|
||||
auto mod_st = (etx_module_state_t*)ctx;
|
||||
auto module = modulePortGetModule(mod_st);
|
||||
|
||||
auto p_data = buffer;
|
||||
setupPulsesLemonDSMP(module, p_data);
|
||||
_dsm_send(mod_st, buffer, p_data - buffer);
|
||||
}
|
||||
|
||||
static void dsmpProcessData(void* ctx, uint8_t data, uint8_t* buffer, uint8_t* len)
|
||||
{
|
||||
auto mod_st = (etx_module_state_t*)ctx;
|
||||
auto module = modulePortGetModule(mod_st);
|
||||
|
||||
processSpektrumTelemetryData(module, data, buffer, *len);
|
||||
}
|
||||
|
||||
// No telemetry
|
||||
const etx_proto_driver_t DSM2Driver = {
|
||||
.protocol = PROTOCOL_CHANNELS_DSM2_LP45,
|
||||
.init = dsm2Init,
|
||||
.deinit = dsmDeInit,
|
||||
.sendPulses = dsm2SendPulses,
|
||||
.processData = nullptr,
|
||||
};
|
||||
|
||||
const etx_proto_driver_t DSMPDriver = {
|
||||
.protocol = PROTOCOL_CHANNELS_DSMP,
|
||||
.init = dsmpInit,
|
||||
.deinit = dsmDeInit,
|
||||
.sendPulses = dsmpSendPulses,
|
||||
.processData = dsmpProcessData,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user