chore(dsmp): separate DSMP and DSM2, cleanup code, add DSMP status display and Enable AETR option (#6932)
Co-authored-by: Peter Feerick <peter.feerick@gmail.com>
This commit is contained in:
@@ -0,0 +1,537 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* Based on code named
|
||||
* opentx - https://github.com/opentx/opentx
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "dsmp.h"
|
||||
#include "hal/module_port.h"
|
||||
#include "mixer_scheduler.h"
|
||||
|
||||
#include "edgetx.h"
|
||||
#include "telemetry/spektrum.h"
|
||||
|
||||
#define DSMP_SEND_X_PLUS 0
|
||||
|
||||
#define DSMP_BITRATE 115200
|
||||
|
||||
#define MAX_REG_CHANNELS 12
|
||||
#define MAX_CHANNELS 20
|
||||
|
||||
// DSMP Flags
|
||||
#define DSMP_FLAGS_DSMX 0x01
|
||||
#define DSMP_FLAGS_DSM2 0x00
|
||||
#define DSMP_FLAGS_11mS 0x02
|
||||
#define DSMP_FLAGS_22mS 0x00
|
||||
#define DSMP_FLAGS_2048 0x04 // 11 bits
|
||||
#define DSMP_FLAGS_1024 0x00 // 10 bits
|
||||
#define DSMP_FLAGS_FUTABA 0x10 // Translate to AETR -> TAER
|
||||
// #define DSMP_FLAGS_DEVO 0x20
|
||||
#define DSMP_FLAGS_AUTO 0x40
|
||||
#define DSMP_FLAGS_BIND 0x80
|
||||
|
||||
#define DSMP_FLAGS_TXMODE (DSMP_FLAGS_DSMX | DSMP_FLAGS_11mS | DSMP_FLAGS_2048)
|
||||
|
||||
// DSMP Power Settings
|
||||
#define DSMP_POWER_NORMAL 7
|
||||
#define DSMP_POWER_RANGE 4
|
||||
|
||||
// Same Encoding as MultiModule (What channel is each of the functions)
|
||||
// R | T | E | A
|
||||
#define DSMP_CH_AETR ((3<<6)|(2<<4)|(1<<2)|0)
|
||||
#define DSMP_CH_TAER ((3<<6)|(0<<4)|(2<<2)|1)
|
||||
|
||||
#define DSMP_NO_CHANNEL 0xFF
|
||||
|
||||
// MAP AETR->TAER:
|
||||
static uint8_t AETR_TAER_MAP[] = {2, 0, 1};
|
||||
|
||||
static DSMPModuleStatus dsmpStatus = DSMPModuleStatus();
|
||||
|
||||
// Power cycle of the DSMP module
|
||||
// The DSMP module code has the channel data initialized to 0 and initial number of bits as 10b (ch resolution 1024)
|
||||
// The Setup message pass the last BIND configuration to the Module via the setup package (for example, 2048 it was bound to DSMX).
|
||||
// Scenario 1: Setup package processed by DSMP before Ch data
|
||||
// When the Setup package is received, will send the existing CH values (0), so servos will move to the side until valid
|
||||
// Ch data is received.
|
||||
// Scenario 2: Channel packed process by DSMP before Setup package
|
||||
// In this case, it will assume that the Ch data is encoded in 10bits instead of 2048 (if DSMX), then the servos move to
|
||||
// to extreme too.
|
||||
//
|
||||
// Both scenarios are not right, so initially send more frequently the Setup package (usualy every 2.2 sec), but will
|
||||
// be sent every 2 messages (66ms). There is still jump, but for an instant.
|
||||
// The only way to properly fix it is at the DSMP firmware level.. (fixed on DSMP V2).
|
||||
|
||||
|
||||
#define FAST_INITIAL_SETUP_COUNT 50 // 3*22*50=3.3 sec of sending fast status after module activation
|
||||
|
||||
// Using 22.06ms instead of 22ms for V1 module.. This is becuase the module try to send 4 RF
|
||||
// packets to the RX with with spacing 4/7/4/7 (22ms cycle) just after receiving
|
||||
// the message from the TX (perfect world). But the timing is not perfect on the
|
||||
// DSMP module, is really 4.025/7.033/4.025/6.x and the last will be cut too short
|
||||
// to 6.88 by the new TX message (needs to be at least 6.92, up to 7.05). That
|
||||
// can create problems in some RXs (Servos not moving smoth). Compensating for
|
||||
// that little extra delay to make the last closer to 7ms spacing.
|
||||
|
||||
#define SCHEDULER_PERIOD_V1 22060
|
||||
#define SCHEDULER_PERIOD_V2 11000
|
||||
|
||||
static uint8_t pass;
|
||||
static uint8_t pass0_counter;
|
||||
static uint8_t pass0_period;
|
||||
|
||||
static uint16_t fastSetup_count;
|
||||
|
||||
#if DSMP_SEND_X_PLUS
|
||||
static uint8_t x_plus_ch = 0;
|
||||
#endif
|
||||
|
||||
DSMPModuleStatus& getDSMPStatus(uint8_t module)
|
||||
{
|
||||
return dsmpStatus;
|
||||
}
|
||||
|
||||
static void* dsmpInit(uint8_t module)
|
||||
{
|
||||
TRACE("[DSMP] dsmpInit()");
|
||||
pass0_counter = 2; // Send Setup every 2 ch data packages
|
||||
pass = 1; // Start Sending channels
|
||||
pass0_period = 100; // Send pass0 every 100 messages
|
||||
fastSetup_count = FAST_INITIAL_SETUP_COUNT;
|
||||
return (void*)dsmInit(module, DSMP_BITRATE, SCHEDULER_PERIOD_V1, true);
|
||||
}
|
||||
|
||||
|
||||
static inline void sendByte(uint8_t*& p_buf, uint8_t b)
|
||||
{
|
||||
*p_buf++ = b;
|
||||
}
|
||||
|
||||
#if defined(LUA)
|
||||
static uint8_t isFPDataReady()
|
||||
{
|
||||
// Check for Forward Programming data
|
||||
// Multi_Buffer[0..2]=="DSM" -> Lua script is running
|
||||
// Multi_Buffer[3]==0x70 + len -> TX to RX data ready to be sent
|
||||
// Multi_Buffer[4..9]=6 bytes of TX to RX data
|
||||
return (Multi_Buffer && (Multi_Buffer[3] & 0xF8) == 0x70 &&
|
||||
memcmp(Multi_Buffer, "DSM", 3) == 0);
|
||||
}
|
||||
|
||||
static void sendFPLemonDSMP(uint8_t*& p_buf)
|
||||
{
|
||||
auto forwardProgLen = Multi_Buffer[3] & 0x0F;
|
||||
TRACE("LemonDSMP: DSMP FwdProg Send data len = [%d]", forwardProgLen);
|
||||
// Send Forward Prog Data (Includes Len + 6 bytes).. 9 bytes totat
|
||||
sendByte(p_buf, 0xAA);
|
||||
sendByte(p_buf, 3); // Pass=3
|
||||
|
||||
for (uint8_t i = 0; i < 7; i++) {
|
||||
sendByte(p_buf, Multi_Buffer[3 + i]);
|
||||
}
|
||||
|
||||
Multi_Buffer[3] = 0x00; // Data sent, clear LUA to send more
|
||||
}
|
||||
#endif
|
||||
|
||||
static void updateModuleStatus(uint8_t flags)
|
||||
{
|
||||
// Update Status
|
||||
dsmpStatus.lastUpdate = get_tmr10ms();
|
||||
dsmpStatus.flags = flags;
|
||||
dsmpStatus.ch_order = (flags & DSMP_FLAGS_FUTABA) ? DSMP_CH_AETR : DSMP_CH_TAER;
|
||||
}
|
||||
|
||||
static uint16_t getDSMPChannelValue(uint8_t module, uint8_t flags, uint8_t channel)
|
||||
{
|
||||
uint8_t txChannel = channel;
|
||||
// Map from AETR->TAER ???
|
||||
if ((flags & DSMP_FLAGS_FUTABA) && (channel < 3)) {
|
||||
txChannel = AETR_TAER_MAP[channel];
|
||||
}
|
||||
|
||||
int value = channelOutputs[txChannel] + 2 * PPM_CH_CENTER(txChannel) - 2 * PPM_CENTER;
|
||||
uint16_t pulse;
|
||||
|
||||
if (flags & DSMP_FLAGS_2048) { // Use 11-bit ?
|
||||
// Scale to 349/512=0.681, MultiModule is about 0.667
|
||||
pulse = limit(0, ((value * 349) >> 9) + 1024, 2047) | (channel << 11);
|
||||
} else {
|
||||
pulse = limit(0, ((value * 13) >> 5) + 512, 1023) | (channel << 10);
|
||||
}
|
||||
|
||||
return pulse;
|
||||
}
|
||||
|
||||
static void setupPulsesLemonDSMP(uint8_t module, uint8_t*& p_buf)
|
||||
{
|
||||
const auto modelId = g_model.header.modelId[module];
|
||||
/* const*/ auto& md = g_model.moduleData[module];
|
||||
|
||||
//uint8_t start_channel = md.channelsStart;
|
||||
auto channels = md.getChannelsCount();
|
||||
auto flags = md.dsmp.flags;
|
||||
auto module_mode = getModuleMode(module);
|
||||
auto version = dsmpStatus.version[0];
|
||||
|
||||
if (md.dsmp.enableAETR) { // Move GUI settings to flags
|
||||
flags |= DSMP_FLAGS_FUTABA;
|
||||
}
|
||||
|
||||
if (pass0_counter == pass0_period/2) {
|
||||
// update status String.. about each second
|
||||
updateModuleStatus(flags);
|
||||
}
|
||||
|
||||
#if defined(LUA)
|
||||
if ((version> 1) && isFPDataReady()) { // Sent any forward prog data??
|
||||
sendFPLemonDSMP(p_buf);
|
||||
Multi_Buffer[3] = 0x00; // Data sent, clear LUA to send more
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Send channel data
|
||||
sendByte(p_buf, 0xAA);
|
||||
sendByte(p_buf, pass);
|
||||
|
||||
// Setup packet
|
||||
if (pass == 0) {
|
||||
flags &= DSMP_FLAGS_TXMODE; // Only the TXMODE part
|
||||
|
||||
if (module_mode == MODULE_MODE_BIND) {
|
||||
flags = DSMP_FLAGS_BIND | DSMP_FLAGS_AUTO;
|
||||
channels = min<uint8_t>(channels, MAX_REG_CHANNELS);
|
||||
md.dsmp.flags = DSMP_FLAGS_DSMX | DSMP_FLAGS_11mS | DSMP_FLAGS_2048;
|
||||
storageDirty(EE_MODEL);
|
||||
}
|
||||
sendByte(p_buf, flags);
|
||||
|
||||
uint8_t pwr = DSMP_POWER_NORMAL;
|
||||
if (module_mode == MODULE_MODE_RANGECHECK) {
|
||||
pwr = DSMP_POWER_RANGE;
|
||||
}
|
||||
sendByte(p_buf, pwr);
|
||||
sendByte(p_buf, channels );
|
||||
sendByte(p_buf, modelId); // V1.0 ignores it, V2.0 use it
|
||||
|
||||
pass = 1; // move to send Ch data
|
||||
return;
|
||||
} else {
|
||||
#if DSMP_SEND_X_PLUS
|
||||
uint8_t xPlusEnabled = (version > 1) && (channels >= MAX_REG_CHANNELS) && (flags & DSMP_FLAGS_DSMX);
|
||||
#endif
|
||||
// Channel DATA messages
|
||||
uint8_t current_channel = 0;
|
||||
if (pass == 2) {
|
||||
current_channel += 7;
|
||||
}
|
||||
|
||||
// Send channels
|
||||
for (int i=0; i<7; i++) {
|
||||
uint16_t pulse = 0xFFFF; // NO-DATA
|
||||
uint8_t ch_to_send = DSMP_NO_CHANNEL;
|
||||
|
||||
if (current_channel < min<uint8_t>(channels,MAX_REG_CHANNELS)) {
|
||||
ch_to_send = current_channel;
|
||||
}
|
||||
|
||||
#if DSMP_SEND_X_PLUS
|
||||
else if (xPlusEnabled && (current_channel >= MAX_REG_CHANNELS)) {
|
||||
// X-plus channel multiplexing (Ch13-20)
|
||||
ch_to_send = MAX_REG_CHANNELS + x_plus_ch;
|
||||
x_plus_ch = (x_plus_ch + 1) % 8; // 8 X-plus channels
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ch_to_send != DSMP_NO_CHANNEL) {
|
||||
pulse = getDSMPChannelValue(module, flags, ch_to_send);
|
||||
}
|
||||
|
||||
sendByte(p_buf, pulse >> 8);
|
||||
sendByte(p_buf, pulse & 0xFF);
|
||||
current_channel++;
|
||||
} // For
|
||||
}
|
||||
|
||||
if (++pass > 2) pass = 1;
|
||||
if (channels < 8) pass = 1;
|
||||
|
||||
if (module_mode == MODULE_MODE_BIND) { // Force setup packet in Bind mode.
|
||||
pass = 0;
|
||||
} else if (--pass0_counter == 0) {
|
||||
pass = 0;
|
||||
updateModuleStatus(flags);
|
||||
if ((version == 1) && (fastSetup_count > 0)) {
|
||||
fastSetup_count--;
|
||||
pass0_counter = 2; // Keep sendint setup every 2 ch messages
|
||||
} else {
|
||||
pass0_counter = pass0_period; // restar counter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void dsmpSendPulses(void* ctx, uint8_t* buffer, int16_t* channels, uint8_t nChannels)
|
||||
{
|
||||
auto mod_st = (etx_module_state_t*)ctx;
|
||||
auto module = modulePortGetModule(mod_st);
|
||||
auto drv = modulePortGetSerialDrv(mod_st->tx);
|
||||
auto drvCtx = modulePortGetCtx(mod_st->tx);
|
||||
|
||||
auto p_data = buffer;
|
||||
setupPulsesLemonDSMP(module, p_data);
|
||||
drv->sendBuffer(drvCtx, buffer, p_data - buffer);
|
||||
}
|
||||
|
||||
/* The DSMP Bind Return Message contains:
|
||||
Byte
|
||||
0 Flags:
|
||||
Protocol: Maxk 0x01 0=DSM2, 1=DSMX
|
||||
RefreshCycle: Mask 0x02 0=22ms, 1=11ms
|
||||
Resolution: Mask 0x04 0=1024, 1=2048
|
||||
Bind: Mask 0x80 1=Enter Bind Mode (Output only)
|
||||
Bind_Auto: Mask 0x40 1=Use AutoBind (Output only)
|
||||
1 ?? Always 0x00; ?? RX type maybe
|
||||
2 Number of Channels (Up to 12)
|
||||
3 TX Mode:
|
||||
0x01 - DSM2 1024/22ms,
|
||||
0x02 - DSM2 1024/22ms >7 channels,
|
||||
0x11 - DSM2 2048/11ms
|
||||
0x12 - DSM2 2048/11ms >7 channels,
|
||||
0xa2 - DSMX 22ms > 7 channels,
|
||||
0xb2 - DSMX 11ms
|
||||
*/
|
||||
|
||||
static void processDSMPBindPacket(uint8_t module, uint8_t* packet)
|
||||
{
|
||||
uint8_t flags = packet[0];
|
||||
uint8_t rxType = packet[1];
|
||||
uint8_t channels = packet[2];
|
||||
uint8_t txMode = packet[3];
|
||||
|
||||
// save flags, only the TXMode Part
|
||||
g_model.moduleData[module].dsmp.flags = flags & DSMP_FLAGS_TXMODE;
|
||||
|
||||
// save number of channels
|
||||
if (channels > MAX_REG_CHANNELS) {
|
||||
channels = MAX_REG_CHANNELS;
|
||||
}
|
||||
g_model.moduleData[module].channelsCount = channels - 8;
|
||||
if (dsmpStatus.version[0] == 1) { // V1.0 always use modelId=0
|
||||
g_model.header.modelId[module] = 0;
|
||||
}
|
||||
|
||||
TRACE("[DSMP] DSMP bind packet: flags:0x%X / Ch: %i / TxMode =0x%X", flags & 0x3F, channels, txMode);
|
||||
|
||||
storageDirty(EE_MODEL);
|
||||
|
||||
/* Finally stop binding as the rx just told us that it is bound */
|
||||
if (getModuleMode(module) == MODULE_MODE_BIND) {
|
||||
setModuleMode(module, MODULE_MODE_NORMAL);
|
||||
}
|
||||
|
||||
// Convert DSMP bind to Spektrum compatible bind and continue with common Spektrum.cpp bind processing
|
||||
uint8_t newPacket[10] = {0, 0, 0, 0, rxType, channels, txMode, 0, 0, 0};
|
||||
processDSMBindPacket(newPacket);
|
||||
|
||||
// FARZU:.. The real problem was using module[moduleID].counter.. is actually used by the restart mechanism
|
||||
restartModuleAsync(module, 10); // ~100ms
|
||||
}
|
||||
|
||||
|
||||
static void processDSMPManufacturerData(uint8_t module, uint8_t* packet)
|
||||
{
|
||||
// Format M,M,M,M, V, V where M is 4 byte manufacturer data, and V is 2 byte
|
||||
dsmpStatus.version[0] = packet[4]; // Major
|
||||
dsmpStatus.version[1] = packet[5]; // Minor
|
||||
|
||||
TRACE("LemonDSMP: Ver [%d.%d]", dsmpStatus.version[0], dsmpStatus.version[1]);
|
||||
|
||||
if (dsmpStatus.version[0] > 1 && mixerSchedulerGetPeriod(module) != SCHEDULER_PERIOD_V2) {
|
||||
// V2 suppors 11ms
|
||||
mixerSchedulerSetPeriod(module, SCHEDULER_PERIOD_V2);
|
||||
pass0_period = 200; // extend period
|
||||
}
|
||||
}
|
||||
|
||||
static void dsmpTelemetryData(uint8_t module, uint8_t data,
|
||||
uint8_t* rxBuffer, uint8_t& rxBufferCount)
|
||||
{
|
||||
dsmpStatus.lastUpdate = get_tmr10ms();
|
||||
|
||||
if (rxBuffer[1] == 0x80 && rxBufferCount >= DSM_BIND_PACKET_LENGTH) {
|
||||
processDSMPBindPacket(module, rxBuffer + 2); // Skip 0xAA 0x80
|
||||
rxBufferCount = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (rxBuffer[1] == 0xFF && rxBufferCount >= SPEKTRUM_TELEMETRY_LENGTH) {
|
||||
processDSMPManufacturerData(module, rxBuffer + 2); // Skip 0xAA 0xFF
|
||||
rxBufferCount = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (rxBufferCount >= SPEKTRUM_TELEMETRY_LENGTH) {
|
||||
// Debug print content of Telemetry to console
|
||||
#if 0
|
||||
debugPrintf("[DSMP] Packet 0x%02X rssi 0x%02X: ic2 0x%02x, %02x: ",
|
||||
rxBuffer[0], rxBuffer[1], rxBuffer[2], rxBuffer[3]);
|
||||
for (int i=4; i<SPEKTRUM_TELEMETRY_LENGTH; i+=4) {
|
||||
debugPrintf("%02X%02X %02X%02X ", rxBuffer[i], rxBuffer[i + 1],
|
||||
rxBuffer[i + 2], rxBuffer[i + 3]);
|
||||
}
|
||||
debugPrintf(CRLF);
|
||||
#endif
|
||||
|
||||
processSpektrumPacket(rxBuffer);
|
||||
rxBufferCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void dsmpDebugData(uint8_t module, uint8_t data, uint8_t* rxBuffer,
|
||||
uint8_t& rxBufferCount)
|
||||
{
|
||||
// Format is: 0xAB, <len> <type> <data>
|
||||
if (rxBufferCount < 2) return; // Keep buiding
|
||||
|
||||
auto expectedLen = rxBuffer[1];
|
||||
|
||||
// Overflow???
|
||||
if (expectedLen + 2 > TELEMETRY_RX_PACKET_SIZE) {
|
||||
expectedLen = TELEMETRY_RX_PACKET_SIZE - 2;
|
||||
}
|
||||
|
||||
if (rxBufferCount >= expectedLen + 2) {
|
||||
// msg Completed
|
||||
auto dataType = rxBuffer[2];
|
||||
|
||||
if (dataType == 1) { // Debug Msg
|
||||
TRACE_NOCRLF("[DSMP] Debug: ");
|
||||
for (auto i = 0; i < expectedLen - 1; i++) {
|
||||
TRACE_NOCRLF("%c", rxBuffer[3 + i]);
|
||||
}
|
||||
TRACE(CRLF);
|
||||
}
|
||||
|
||||
rxBufferCount = 0; // Build new message
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
|
||||
uint8_t& rxBufferCount = *len;
|
||||
|
||||
if (rxBufferCount == 0 && (data != 0xAA && data != 0xAB)) {
|
||||
TRACE("[DSMP] invalid start byte 0x%02X", data);
|
||||
return;
|
||||
}
|
||||
|
||||
if (rxBufferCount < TELEMETRY_RX_PACKET_SIZE) {
|
||||
|
||||
TRACE("[DSMP] Data 0x%02X, len = %d", data, rxBufferCount);
|
||||
buffer[rxBufferCount++] = data; // Keep building message
|
||||
} else {
|
||||
TRACE("[DSMP] array size %d error", rxBufferCount);
|
||||
rxBufferCount = 0;
|
||||
}
|
||||
|
||||
if (buffer[0] == 0xAA) { // Telemetry data or Bind
|
||||
dsmpTelemetryData(module, data, buffer, *len);
|
||||
} else if (buffer[0] == 0xAB) { // Status
|
||||
dsmpDebugData(module, data, buffer, *len);
|
||||
}
|
||||
}
|
||||
|
||||
void DSMPModuleStatus::getStatusString(char* statusText) const
|
||||
{
|
||||
if (!isValid()) {
|
||||
strcpy(statusText, STR_MODULE_NO_TELEMETRY);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& md = g_model.moduleData[EXTERNAL_MODULE];
|
||||
auto channels = md.getChannelsCount();
|
||||
|
||||
char* tmp = statusText;
|
||||
|
||||
// Version
|
||||
*tmp = 0;
|
||||
tmp = strAppend(tmp, "v", 1);
|
||||
tmp = strAppendUnsigned(tmp, dsmpStatus.version[0]);
|
||||
tmp = strAppend(tmp, ".", 1);
|
||||
tmp = strAppendUnsigned(tmp, dsmpStatus.version[1]);
|
||||
|
||||
char b[] = "? ";
|
||||
if (ch_order != 0xFF) { // Same encoding as MultiModule
|
||||
uint8_t temp = ch_order;
|
||||
b[temp & 0x03] = 'A';
|
||||
temp >>= 2;
|
||||
b[temp & 0x03] = 'E';
|
||||
temp >>= 2;
|
||||
b[temp & 0x03] = 'T';
|
||||
temp >>= 2;
|
||||
b[temp & 0x03] = 'R';
|
||||
}
|
||||
|
||||
tmp = strAppend(tmp, " ", 1);
|
||||
tmp = strAppend(tmp, b, strlen(b));
|
||||
|
||||
const char* mode;
|
||||
|
||||
mode = (flags & DSMP_FLAGS_DSMX) ? " X" : " 2"; // DSMX or DSM2
|
||||
tmp = strAppend(tmp, mode, strlen(mode));
|
||||
|
||||
mode = (flags & DSMP_FLAGS_11mS) ? "_2F" : "_1F"; // 1 or 2 Frames (11ms/22ms)
|
||||
tmp = strAppend(tmp, mode, strlen(mode));
|
||||
|
||||
#if 0
|
||||
// Good for Debugging, but not much for regular users
|
||||
|
||||
//mode = (flags & DSMP_FLAGS_2048) ? " 2048" : " 1024";
|
||||
//tmp = strAppend(tmp, mode, strlen(mode));
|
||||
|
||||
tmp = strAppend(tmp, " S:", 4);
|
||||
uint16_t servoRefresh = (mixerSchedulerGetPeriod(EXTERNAL_MODULE) / 1000);
|
||||
if (channels > 7) servoRefresh *= 2;
|
||||
tmp = strAppendUnsigned(tmp, servoRefresh);
|
||||
tmp = strAppend(tmp, "ms", 2);
|
||||
|
||||
servoRefresh = mixerSchedulerGetPeriod(EXTERNAL_MODULE);
|
||||
tmp = strAppend(tmp, " TX:", 5);
|
||||
tmp = strAppendUnsigned(tmp, servoRefresh);
|
||||
tmp = strAppend(tmp, "us", 2);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
const etx_proto_driver_t DSMPDriver = {
|
||||
.protocol = PROTOCOL_CHANNELS_DSMP,
|
||||
.init = dsmpInit,
|
||||
.deinit = dsmDeInit,
|
||||
.sendPulses = dsmpSendPulses,
|
||||
.processData = dsmpProcessData,
|
||||
.processFrame = nullptr,
|
||||
.onConfigChange = nullptr,
|
||||
.txCompleted = modulePortSerialTxCompleted,
|
||||
};
|
||||
Reference in New Issue
Block a user