Support new Multi 1.3 features (#7077)
This commit is contained in:
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* 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 "opentx.h"
|
||||
|
||||
/* Telemetry
|
||||
packet[0] = TX RSSI value
|
||||
packet[1] = TX LQI value
|
||||
packet[2] = frame number
|
||||
packet[3-12] telemetry data
|
||||
|
||||
The frame number takes the following values: 0x00, 0x01, 0x02, 0x03 and 0x04. The frames can be present or not, they also do not have to follow each others.
|
||||
Here is a description of the telemetry data for each frame number:
|
||||
- frame 0x00
|
||||
[3] = [12] = ??
|
||||
[4] = RX_Voltage*10 in V
|
||||
[5] = Temperature-20 in °C
|
||||
[6] = RX_RSSI
|
||||
[7] = RX_LQI ??
|
||||
[8] = RX_STR ??
|
||||
[9,10] = [10]*256+[9]=max lost packet time in ms, max value seems 2s=0x7D0
|
||||
[11] = 0x00 ??
|
||||
- frame 0x01 Unknown
|
||||
- frame 0x02 Unknown
|
||||
- frame 0x03 Unknown
|
||||
- frame 0x04 Unknown
|
||||
*/
|
||||
|
||||
struct HottSensor
|
||||
{
|
||||
const uint16_t id;
|
||||
const char * name;
|
||||
const TelemetryUnit unit;
|
||||
const uint8_t precision;
|
||||
};
|
||||
|
||||
// telemetry frames
|
||||
enum
|
||||
{
|
||||
HOTT_FRAME_00 = 0x00,
|
||||
HOTT_FRAME_01 = 0x01,
|
||||
HOTT_FRAME_02 = 0x02,
|
||||
HOTT_FRAME_03 = 0x03,
|
||||
HOTT_FRAME_04 = 0x04,
|
||||
};
|
||||
|
||||
#define HOTT_TELEM_NORMAL 0x00
|
||||
#define HOTT_TELEM_BIND 0x40
|
||||
#define HOTT_TELEM_MENU 0x80
|
||||
|
||||
// telemetry sensors ID
|
||||
enum
|
||||
{
|
||||
HOTT_ID_RX_VOLTAGE = 0x0004,// RX_Batt Voltage
|
||||
HOTT_ID_TEMP1 = 0x0005, // RX Temperature sensor
|
||||
TX_RSSI_ID = 0xFF00, // Pseudo id outside 1 byte range of Hott sensors
|
||||
TX_LQI_ID = 0xFF01, // Pseudo id outside 1 byte range of Hott sensors
|
||||
RX_RSSI_ID = 0xFF02, // Pseudo id outside 1 byte range of Hott sensors
|
||||
RX_LQI_ID = 0xFF03, // Pseudo id outside 1 byte range of Hott sensors
|
||||
};
|
||||
|
||||
const HottSensor hottSensors[] = {
|
||||
//frame 00
|
||||
{HOTT_ID_RX_VOLTAGE, ZSTR_BATT, UNIT_VOLTS, 1}, // RX_Batt Voltage
|
||||
{HOTT_ID_TEMP1, ZSTR_TEMP1, UNIT_CELSIUS, 0}, // RX Temperature sensor
|
||||
//frame 01
|
||||
//frame 02
|
||||
//frame 03
|
||||
//frame 04
|
||||
{TX_RSSI_ID, ZSTR_TX_RSSI, UNIT_RAW, 0}, // Pseudo id outside 1 byte range of Hott sensors
|
||||
{TX_LQI_ID, ZSTR_TX_QUALITY, UNIT_RAW, 0}, // Pseudo id outside 1 byte range of Hott sensors
|
||||
{RX_RSSI_ID, ZSTR_RSSI, UNIT_DB, 0}, // RX RSSI
|
||||
{RX_LQI_ID, ZSTR_RX_QUALITY, UNIT_RAW, 0}, // RX LQI
|
||||
{0x00, NULL, UNIT_RAW, 0}, // sentinel
|
||||
};
|
||||
|
||||
const HottSensor * getHottSensor(uint16_t id)
|
||||
{
|
||||
for (const HottSensor * sensor = hottSensors; sensor->id; sensor++) {
|
||||
if (id == sensor->id)
|
||||
return sensor;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void processHottPacket(const uint8_t * packet)
|
||||
{
|
||||
// Set TX RSSI Value
|
||||
setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, TX_RSSI_ID, 0, 0, packet[0]>>1, UNIT_RAW, 0);
|
||||
// Set TX LQI Value
|
||||
setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, TX_LQI_ID, 0, 0, packet[1], UNIT_RAW, 0);
|
||||
|
||||
#if defined(LUA)
|
||||
#define HOTT_MENU_NBR_PAGE 0x13
|
||||
// Config menu consists of the different telem pages put all together
|
||||
// [3] = config mennu page 0x00 to 0x12.
|
||||
// Page X [4] = seems like all the telem pages with the same value are going together to make the full config menu text. Seen so far 'a', 'b', 'c', 'd'
|
||||
// Page X [5..13] = 9 ascii chars to be displayed, char is highlighted when ascii|0x80
|
||||
// Screen display is 21 characters large which means that once the first 21 chars are filled go to the begining of the next line
|
||||
// Menu commands are sent through TX packets:
|
||||
// packet[28]= 0xXF=>no key press, 0xXD=>down, 0xXB=>up, 0xX9=>enter, 0xXE=>right, 0xX7=>left with X=0 or D
|
||||
// packet[29]= 0xX1/0xX9 with X=0 or X counting 0,1,1,2,2,..,9,9
|
||||
if (Multi_Buffer && memcmp(Multi_Buffer, "HoTT", 4) == 0) {
|
||||
// HoTT Lua script is running
|
||||
if (Multi_Buffer[4] == 0xFF) {
|
||||
// Init
|
||||
memset(&Multi_Buffer[6], ' ', HOTT_MENU_NBR_PAGE * 9); // Clear text buffer
|
||||
}
|
||||
|
||||
if (packet[3] < HOTT_MENU_NBR_PAGE && Multi_Buffer[5] >= 0xD7 && Multi_Buffer[5] <= 0xDF) {
|
||||
Multi_Buffer[4] = packet[4]; // Store current menu being received
|
||||
memcpy(&Multi_Buffer[6 + packet[3] * 9], &packet[5], 9); // Store the received page in the buffer
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
const HottSensor * sensor;
|
||||
int32_t value;
|
||||
|
||||
if (packet[2] == HOTT_TELEM_NORMAL) {
|
||||
switch (packet[3]) {
|
||||
case HOTT_FRAME_00:
|
||||
// RX_VOLT
|
||||
value = packet[5];
|
||||
sensor = getHottSensor(HOTT_ID_RX_VOLTAGE);
|
||||
setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_RX_VOLTAGE, 0, 0, value, sensor->unit, sensor->precision);
|
||||
// RX_TEMP
|
||||
value = packet[6] - 20;
|
||||
sensor = getHottSensor(HOTT_ID_TEMP1);
|
||||
setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, HOTT_ID_TEMP1, 0, 0, value, sensor->unit, sensor->precision);
|
||||
// RX_RSSI
|
||||
setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, RX_RSSI_ID, 0, 0, packet[7], UNIT_DB, 0);
|
||||
// RX_LQI
|
||||
telemetryData.rssi.set(packet[8]);
|
||||
if (packet[8] > 0)
|
||||
telemetryStreaming = TELEMETRY_TIMEOUT10ms;
|
||||
setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, RX_LQI_ID, 0, 0, packet[8], UNIT_RAW, 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
// unknown
|
||||
value = (packet[7] << 24) | (packet[6] << 16) | (packet[5] << 8) | packet[4];
|
||||
setTelemetryValue(PROTOCOL_TELEMETRY_HOTT, 0xFE00 | packet[3], 0, 0, value, UNIT_RAW, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void hottSetDefault(int index, uint16_t id, uint8_t subId, uint8_t instance)
|
||||
{
|
||||
TelemetrySensor &telemetrySensor = g_model.telemetrySensors[index];
|
||||
telemetrySensor.id = id;
|
||||
telemetrySensor.subId = subId;
|
||||
telemetrySensor.instance = instance;
|
||||
|
||||
const HottSensor * sensor = getHottSensor(id);
|
||||
if (sensor) {
|
||||
TelemetryUnit unit = sensor->unit;
|
||||
uint8_t prec = min<uint8_t>(2, sensor->precision);
|
||||
telemetrySensor.init(sensor->name, unit, prec);
|
||||
if (unit == UNIT_RPMS) {
|
||||
telemetrySensor.custom.ratio = 1;
|
||||
telemetrySensor.custom.offset = 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
telemetrySensor.init(id);
|
||||
}
|
||||
|
||||
storageDirty(EE_MODEL);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) OpenTX
|
||||
*
|
||||
* Based on code named
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _HOTT_H
|
||||
#define _HOTT_H
|
||||
|
||||
void hottSetDefault(int index, uint16_t id, uint8_t subId, uint8_t instance);
|
||||
|
||||
// Used by multi protocol
|
||||
void processHottPacket(const uint8_t * packet);
|
||||
|
||||
#endif
|
||||
+124
-67
@@ -39,7 +39,8 @@ enum MultiPacketTypes : uint8_t
|
||||
HitecTelemetry,
|
||||
SpectrumScannerPacket,
|
||||
FlyskyIBusTelemetryAC,
|
||||
MultiRxChannels
|
||||
MultiRxChannels,
|
||||
HottTelemetry,
|
||||
};
|
||||
|
||||
enum MultiBufferState : uint8_t
|
||||
@@ -65,6 +66,7 @@ static MultiModuleSyncStatus multiSyncStatus[NUM_MODULES] = {MultiModuleSyncStat
|
||||
static uint8_t multiBindStatus[NUM_MODULES] = {MULTI_NORMAL_OPERATION, MULTI_NORMAL_OPERATION};
|
||||
|
||||
static MultiBufferState multiTelemetryBufferState[NUM_MODULES];
|
||||
static uint16_t multiTelemetryLastRxTS[NUM_MODULES];
|
||||
|
||||
MultiModuleStatus &getMultiModuleStatus(uint8_t module)
|
||||
{
|
||||
@@ -96,6 +98,11 @@ void setMultiTelemetryBufferState(uint8_t module, MultiBufferState state)
|
||||
multiTelemetryBufferState[module] = state;
|
||||
}
|
||||
|
||||
static uint16_t& getMultiTelemetryLastRxTS(uint8_t module)
|
||||
{
|
||||
return multiTelemetryLastRxTS[module];
|
||||
}
|
||||
|
||||
// Use additional telemetry buffer
|
||||
uint8_t intTelemetryRxBuffer[TELEMETRY_RX_PACKET_SIZE];
|
||||
uint8_t intTelemetryRxBufferCount;
|
||||
@@ -107,6 +114,7 @@ static MultiModuleSyncStatus multiSyncStatus;
|
||||
static uint8_t multiBindStatus = MULTI_NORMAL_OPERATION;
|
||||
|
||||
static MultiBufferState multiTelemetryBufferState;
|
||||
static uint16_t multiTelemetryLastRxTS;
|
||||
|
||||
MultiModuleStatus& getMultiModuleStatus(uint8_t)
|
||||
{
|
||||
@@ -138,6 +146,11 @@ void setMultiTelemetryBufferState(uint8_t, MultiBufferState state)
|
||||
multiTelemetryBufferState = state;
|
||||
}
|
||||
|
||||
uint16_t& getMultiTelemetryLastRxTS(uint8_t module)
|
||||
{
|
||||
return multiTelemetryLastRxTS;
|
||||
}
|
||||
|
||||
#endif // INTERNAL_MODULE_MULTI
|
||||
|
||||
|
||||
@@ -150,9 +163,9 @@ static MultiBufferState guessProtocol(uint8_t module)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (g_model.moduleData[moduleIdx].getMultiProtocol(false) == MODULE_SUBTYPE_MULTI_DSM2)
|
||||
if (g_model.moduleData[moduleIdx].getMultiProtocol() == MODULE_SUBTYPE_MULTI_DSM2)
|
||||
return SpektrumTelemetryFallback;
|
||||
else if (g_model.moduleData[module].getMultiProtocol(false) == MODULE_SUBTYPE_MULTI_FS_AFHDS2A)
|
||||
else if (g_model.moduleData[module].getMultiProtocol() == MODULE_SUBTYPE_MULTI_FS_AFHDS2A)
|
||||
return FlyskyTelemetryFallback;
|
||||
else
|
||||
return FrskyTelemetryFallback;
|
||||
@@ -196,20 +209,38 @@ static void processMultiScannerPacket(const uint8_t *data)
|
||||
}
|
||||
}
|
||||
|
||||
static void processMultiStatusPacket(const uint8_t * data, uint8_t module)
|
||||
static void processMultiStatusPacket(const uint8_t * data, uint8_t module, uint8_t len)
|
||||
{
|
||||
MultiModuleStatus &status = getMultiModuleStatus(module);
|
||||
|
||||
// At least two status packets without bind flag
|
||||
bool wasBinding = status.isBinding();
|
||||
|
||||
status.lastUpdate = get_tmr10ms();
|
||||
status.flags = data[0];
|
||||
status.major = data[1];
|
||||
status.minor = data[2];
|
||||
status.revision = data[3];
|
||||
status.patch = data[4];
|
||||
status.lastUpdate = get_tmr10ms();
|
||||
|
||||
if (len < 6) {
|
||||
status.ch_order = 0xFF;
|
||||
}
|
||||
else {
|
||||
status.ch_order = data[5];
|
||||
if (len >= 24) {
|
||||
status.protocolNext = data[6];
|
||||
status.protocolPrev = data[7];
|
||||
memcpy(status.protocolName, &data[8], 7);
|
||||
status.protocolName[7] = 0;
|
||||
status.protocolSubNbr = data[15] & 0x0F;
|
||||
memcpy(status.protocolSubName, &data[16], 8);
|
||||
status.protocolSubName[8] = 0;
|
||||
status.optionDisp = data[15] >> 4;
|
||||
}
|
||||
else {
|
||||
status.protocolName[0] = 0;
|
||||
}
|
||||
}
|
||||
if (getMultiModuleStatus(module).requiresFailsafeCheck) {
|
||||
getMultiModuleStatus(module).requiresFailsafeCheck = false;
|
||||
if (getMultiModuleStatus(module).supportsFailsafe() && g_model.moduleData[module].failsafeMode == FAILSAFE_NOT_SET)
|
||||
@@ -289,7 +320,7 @@ static void processMultiTelemetryPaket(const uint8_t * packet, uint8_t module)
|
||||
switch (type) {
|
||||
case MultiStatus:
|
||||
if (len >= 5)
|
||||
processMultiStatusPacket(data, module);
|
||||
processMultiStatusPacket(data, module, len);
|
||||
break;
|
||||
|
||||
case DSMBindPacket:
|
||||
@@ -327,6 +358,13 @@ static void processMultiTelemetryPaket(const uint8_t * packet, uint8_t module)
|
||||
TRACE("[MP] Received Hitec telemetry len %d < 8", len);
|
||||
break;
|
||||
|
||||
case HottTelemetry:
|
||||
if (len >= 14)
|
||||
processHottPacket(data);
|
||||
else
|
||||
TRACE("[MP] Received HoTT telemetry len %d < 14", len);
|
||||
break;
|
||||
|
||||
case FrSkyHubTelemetry:
|
||||
if (len >= 4)
|
||||
frskyDProcessPacket(data);
|
||||
@@ -382,17 +420,7 @@ static void processMultiTelemetryPaket(const uint8_t * packet, uint8_t module)
|
||||
}
|
||||
}
|
||||
|
||||
// sprintf does not work AVR ARM
|
||||
// use a small helper function
|
||||
static void appendInt(char * buf, uint32_t val)
|
||||
{
|
||||
while (*buf)
|
||||
buf++;
|
||||
|
||||
strAppendUnsigned(buf, val);
|
||||
}
|
||||
|
||||
#define MIN_REFRESH_RATE 7000
|
||||
#define MIN_REFRESH_RATE 5500
|
||||
|
||||
void MultiModuleSyncStatus::calcAdjustedRefreshRate(uint16_t newRefreshRate, uint16_t newInputLag)
|
||||
{
|
||||
@@ -444,8 +472,8 @@ void MultiModuleSyncStatus::calcAdjustedRefreshRate(uint16_t newRefreshRate, uin
|
||||
adjustedRefreshRate = (adjustedRefreshRate + perframeps);
|
||||
|
||||
// Safeguards
|
||||
if (adjustedRefreshRate < 6 * 1000 * 1000)
|
||||
adjustedRefreshRate = 6 * 1000 * 1000;
|
||||
if (adjustedRefreshRate < MIN_REFRESH_RATE * 1000)
|
||||
adjustedRefreshRate = MIN_REFRESH_RATE * 1000;
|
||||
if (adjustedRefreshRate > 30 * 1000 * 1000)
|
||||
adjustedRefreshRate = 30 * 1000 * 1000;
|
||||
|
||||
@@ -454,12 +482,11 @@ void MultiModuleSyncStatus::calcAdjustedRefreshRate(uint16_t newRefreshRate, uin
|
||||
|
||||
static uint8_t counter;
|
||||
|
||||
uint16_t MultiModuleSyncStatus::getAdjustedRefreshRate()
|
||||
const uint16_t MultiModuleSyncStatus::getAdjustedRefreshRate()
|
||||
{
|
||||
if (!isValid() || refreshRate == 0)
|
||||
return 18000;
|
||||
|
||||
|
||||
counter = (uint8_t) (counter + 1 % 10);
|
||||
uint16_t rate = (uint16_t) ((adjustedRefreshRate + counter * 50) / 500);
|
||||
// Check how far off we are from our target, positive means we are too slow, negative we are too fast
|
||||
@@ -471,37 +498,27 @@ uint16_t MultiModuleSyncStatus::getAdjustedRefreshRate()
|
||||
return rate;
|
||||
}
|
||||
|
||||
|
||||
static void prependSpaces(char * buf, int val)
|
||||
{
|
||||
while (*buf)
|
||||
buf++;
|
||||
|
||||
int k = 10000;
|
||||
while (val / k == 0 && k > 0) {
|
||||
*buf = ' ';
|
||||
buf++;
|
||||
k /= 10;
|
||||
}
|
||||
*buf = '\0';
|
||||
}
|
||||
|
||||
void MultiModuleSyncStatus::getRefreshString(char * statusText)
|
||||
{
|
||||
if (!isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
strcpy(statusText, "L ");
|
||||
prependSpaces(statusText, inputLag);
|
||||
appendInt(statusText, inputLag);
|
||||
strcat(statusText, "ns R ");
|
||||
prependSpaces(statusText, adjustedRefreshRate / 1000);
|
||||
appendInt(statusText, (uint32_t) (adjustedRefreshRate / 1000));
|
||||
strcat(statusText, "ns");
|
||||
char * tmp = statusText;
|
||||
#if defined(DEBUG)
|
||||
*tmp++ = 'L';
|
||||
tmp = strAppendUnsigned(tmp, inputLag, 5);
|
||||
tmp = strAppend(tmp, "us R ");
|
||||
tmp = strAppendUnsigned(tmp, (uint32_t) (adjustedRefreshRate / 1000), 5);
|
||||
tmp = strAppend(tmp, "us");
|
||||
#else
|
||||
tmp = strAppend(tmp, "Sync at ");
|
||||
tmp = strAppendUnsigned(tmp, (uint32_t) (adjustedRefreshRate / 1000000));
|
||||
tmp = strAppend(tmp, " ms");
|
||||
#endif
|
||||
}
|
||||
|
||||
void MultiModuleStatus::getStatusString(char * statusText)
|
||||
void MultiModuleStatus::getStatusString(char * statusText) const
|
||||
{
|
||||
if (!isValid()) {
|
||||
#if defined(PCBTARANIS) || defined(PCBHORUS)
|
||||
@@ -531,19 +548,46 @@ void MultiModuleStatus::getStatusString(char * statusText)
|
||||
return;
|
||||
}
|
||||
|
||||
if (major == 1 && minor < 3 && SLOW_BLINK_ON_PHASE) {
|
||||
strcpy(statusText, STR_MODULE_UPGRADE);
|
||||
}
|
||||
else {
|
||||
char * tmp = statusText;
|
||||
*tmp++ = 'V';
|
||||
tmp = strAppendUnsigned(tmp, major);
|
||||
*tmp++ = '.';
|
||||
tmp = strAppendUnsigned(tmp, minor);
|
||||
*tmp++ = '.';
|
||||
tmp = strAppendUnsigned(tmp, revision);
|
||||
*tmp++ = '.';
|
||||
tmp = strAppendUnsigned(tmp, patch);
|
||||
|
||||
strcpy(statusText, "V");
|
||||
appendInt(statusText, major);
|
||||
strcat(statusText, ".");
|
||||
appendInt(statusText, minor);
|
||||
strcat(statusText, ".");
|
||||
appendInt(statusText, revision);
|
||||
strcat(statusText, ".");
|
||||
appendInt(statusText, patch);
|
||||
strcat(statusText, " ");
|
||||
|
||||
if (isBinding())
|
||||
strcat(statusText, STR_MODULE_BINDING);
|
||||
if (isBinding()) {
|
||||
strcpy(tmp, " " TR_MODULE_BINDING);
|
||||
}
|
||||
else if (ch_order != 0xFF) {
|
||||
uint8_t temp = ch_order;
|
||||
*tmp++ = ' ';
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
switch (temp & 0x03) {
|
||||
case 0:
|
||||
*tmp++ = 'A';
|
||||
break;
|
||||
case 1:
|
||||
*tmp++ = 'E';
|
||||
break;
|
||||
case 2:
|
||||
*tmp++ = 'T';
|
||||
break;
|
||||
case 3:
|
||||
*tmp++ = 'R';
|
||||
break;
|
||||
}
|
||||
temp >>= 2;
|
||||
}
|
||||
*tmp = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t * getRxBuffer(uint8_t moduleIdx)
|
||||
@@ -600,7 +644,14 @@ void processMultiTelemetryData(uint8_t data, uint8_t module)
|
||||
uint8_t * rxBuffer = getRxBuffer(module);
|
||||
uint8_t &rxBufferCount = getRxBufferCount(module);
|
||||
|
||||
//debugPrintf("State: %d, byte received %02X, buflen: %d\r\n", multiTelemetryBufferState, data, rxBufferCount);
|
||||
uint16_t &lastRxTS = getMultiTelemetryLastRxTS(module);
|
||||
uint16_t nowMs = (uint16_t)RTOS_GET_MS();
|
||||
if (nowMs - lastRxTS > 15)
|
||||
setMultiTelemetryBufferState(module, NoProtocolDetected);
|
||||
lastRxTS = nowMs;
|
||||
|
||||
// debugPrintf("State: %d, byte received %02X, buflen: %d\r\n", getMultiTelemetryBufferState(module), data, rxBufferCount);
|
||||
|
||||
switch (getMultiTelemetryBufferState(module)) {
|
||||
case NoProtocolDetected:
|
||||
if (data == 'M') {
|
||||
@@ -691,16 +742,22 @@ void processMultiTelemetryData(uint8_t data, uint8_t module)
|
||||
break;
|
||||
|
||||
case ReceivingMultiStatus:
|
||||
rxBuffer[rxBufferCount++] = data;
|
||||
if (rxBufferCount > 5 && rxBuffer[0] == rxBufferCount - 1) {
|
||||
processMultiStatusPacket(rxBuffer + 1, module);
|
||||
rxBufferCount = 0;
|
||||
setMultiTelemetryBufferState(module, NoProtocolDetected);
|
||||
if (rxBufferCount < TELEMETRY_RX_PACKET_SIZE) {
|
||||
rxBuffer[rxBufferCount++] = data;
|
||||
if (rxBufferCount > 5 && rxBuffer[0] == rxBufferCount - 1) {
|
||||
processMultiStatusPacket(rxBuffer + 1, module, rxBuffer[0]);
|
||||
rxBufferCount = 0;
|
||||
setMultiTelemetryBufferState(module, NoProtocolDetected);
|
||||
}
|
||||
if (rxBufferCount > 24) {
|
||||
// too long ignore
|
||||
TRACE("Overlong multi status packet detected ignoring, wanted %d", rxBuffer[0]);
|
||||
rxBufferCount = 0;
|
||||
setMultiTelemetryBufferState(module, NoProtocolDetected);
|
||||
}
|
||||
}
|
||||
if (rxBufferCount > 10) {
|
||||
// too long ignore
|
||||
TRACE("Overlong multi status packet detected ignoring, wanted %d", rxBuffer[0]);
|
||||
rxBufferCount = 0;
|
||||
else {
|
||||
TRACE("[MP] array size %d error", rxBufferCount);
|
||||
setMultiTelemetryBufferState(module, NoProtocolDetected);
|
||||
}
|
||||
break;
|
||||
|
||||
+22
-11
@@ -21,6 +21,9 @@
|
||||
#ifndef OPENTX_MULTI_H
|
||||
#define OPENTX_MULTI_H
|
||||
|
||||
#define MULTI_BUFFER_SIZE 177
|
||||
extern uint8_t * Multi_Buffer;
|
||||
|
||||
/*
|
||||
Multiprotocol telemetry definition
|
||||
|
||||
@@ -93,23 +96,21 @@ void processMultiTelemetryData(uint8_t data, uint8_t module);
|
||||
|
||||
// This should be put into the Module definition if other modules gain this functionality
|
||||
struct MultiModuleSyncStatus {
|
||||
uint32_t adjustedRefreshRate; // in ps
|
||||
uint32_t adjustedRefreshRate = 9000 * 1000; // in ps
|
||||
tmr10ms_t lastUpdate;
|
||||
uint16_t refreshRate;
|
||||
uint16_t inputLag;
|
||||
uint8_t interval;
|
||||
uint8_t target;
|
||||
|
||||
inline bool isValid() {return (get_tmr10ms() - lastUpdate < 100);}
|
||||
void getRefreshString(char* refreshText);
|
||||
uint16_t getAdjustedRefreshRate();
|
||||
void calcAdjustedRefreshRate(uint16_t newRefreshRate, uint16_t newInputLag);
|
||||
|
||||
MultiModuleSyncStatus() {
|
||||
// Initialise to a valid value
|
||||
adjustedRefreshRate=9000 * 1000;
|
||||
inline bool isValid() const
|
||||
{
|
||||
return (get_tmr10ms() - lastUpdate < 100);
|
||||
}
|
||||
|
||||
|
||||
void getRefreshString(char * refreshText);
|
||||
const uint16_t getAdjustedRefreshRate();
|
||||
void calcAdjustedRefreshRate(uint16_t newRefreshRate, uint16_t newInputLag);
|
||||
};
|
||||
|
||||
MultiModuleSyncStatus& getMultiSyncStatus(uint8_t module);
|
||||
@@ -121,14 +122,24 @@ struct MultiModuleStatus {
|
||||
uint8_t minor;
|
||||
uint8_t revision;
|
||||
uint8_t patch;
|
||||
uint8_t ch_order;
|
||||
|
||||
uint8_t flags;
|
||||
uint8_t requiresFailsafeCheck;
|
||||
tmr10ms_t lastUpdate;
|
||||
|
||||
void getStatusString(char* statusText);
|
||||
uint8_t protocolPrev = 0;
|
||||
uint8_t protocolNext = 0;
|
||||
char protocolName[8] = {0};
|
||||
uint8_t protocolSubNbr = 0;
|
||||
char protocolSubName[9] = {0};
|
||||
uint8_t optionDisp = 0;
|
||||
|
||||
void getStatusString(char * statusText) const;
|
||||
|
||||
inline bool isValid() const { return (bool)(get_tmr10ms() - lastUpdate < 200); }
|
||||
inline bool isBufferFull() const { return (bool) (flags & 0x80); }
|
||||
inline bool supportsDisableMapping() const { return (bool) (flags & 0x40); }
|
||||
inline bool supportsFailsafe() const { return (bool) (flags & 0x20); }
|
||||
inline bool isWaitingforBind() const { return (bool) (flags & 0x10); }
|
||||
inline bool isBinding() const { return (bool) (flags & 0x08); }
|
||||
|
||||
@@ -373,7 +373,7 @@ void processSpektrumPacket(const uint8_t *packet)
|
||||
void processDSMBindPacket(uint8_t module, const uint8_t *packet)
|
||||
{
|
||||
uint32_t debugval;
|
||||
if (g_model.moduleData[module].type == MODULE_TYPE_MULTIMODULE && g_model.moduleData[module].getMultiProtocol(true) == MODULE_SUBTYPE_MULTI_DSM2
|
||||
if (g_model.moduleData[module].type == MODULE_TYPE_MULTIMODULE && g_model.moduleData[module].getMultiProtocol() == MODULE_SUBTYPE_MULTI_DSM2
|
||||
&& g_model.moduleData[module].multi.autoBindMode) {
|
||||
|
||||
int channels = packet[5];
|
||||
@@ -399,7 +399,7 @@ void processDSMBindPacket(uint8_t module, const uint8_t *packet)
|
||||
setTelemetryValue(PROTOCOL_TELEMETRY_SPEKTRUM, (I2C_PSEUDO_TX << 8) + 4, 0, 0, debugval, UNIT_RAW, 0);
|
||||
|
||||
/* Finally stop binding as the rx just told us that it is bound */
|
||||
if (g_model.moduleData[module].type == MODULE_TYPE_MULTIMODULE && g_model.moduleData[module].getMultiProtocol(true) == MODULE_SUBTYPE_MULTI_DSM2 && moduleState[module].mode == MODULE_MODE_BIND) {
|
||||
if (g_model.moduleData[module].type == MODULE_TYPE_MULTIMODULE && g_model.moduleData[module].getMultiProtocol() == MODULE_SUBTYPE_MULTI_DSM2 && moduleState[module].mode == MODULE_MODE_BIND) {
|
||||
setMultiBindStatus(module, MULTI_BIND_FINISHED);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "spektrum.h"
|
||||
#include "flysky_ibus.h"
|
||||
#include "hitec.h"
|
||||
#include "hott.h"
|
||||
#include "multi.h"
|
||||
#endif
|
||||
|
||||
@@ -104,8 +105,13 @@ void frskyDSetDefault(int index, uint16_t id);
|
||||
extern uint8_t telemetryProtocol;
|
||||
|
||||
#if defined (MULTIMODULE)
|
||||
#define IS_D16_MULTI() ((g_model.moduleData[EXTERNAL_MODULE].getMultiProtocol(false) == MODULE_SUBTYPE_MULTI_FRSKY) && (g_model.moduleData[EXTERNAL_MODULE].subType == MM_RF_FRSKY_SUBTYPE_D16 || g_model.moduleData[EXTERNAL_MODULE].subType == MM_RF_FRSKY_SUBTYPE_D16_8CH))
|
||||
#define IS_FRSKY_SPORT_PROTOCOL() (telemetryProtocol == PROTOCOL_TELEMETRY_FRSKY_SPORT || (telemetryProtocol == PROTOCOL_TELEMETRY_MULTIMODULE && IS_D16_MULTI()))
|
||||
#define IS_D16_MULTI(module) ((g_model.moduleData[module].getMultiProtocol() == MODULE_SUBTYPE_MULTI_FRSKY) && (g_model.moduleData[module].subType == MM_RF_FRSKY_SUBTYPE_D16 || g_model.moduleData[module].subType == MM_RF_FRSKY_SUBTYPE_D16_8CH || g_model.moduleData[module].subType == MM_RF_FRSKY_SUBTYPE_D16_LBT || g_model.moduleData[module].subType == MM_RF_FRSKY_SUBTYPE_D16_LBT_8CH))
|
||||
#define IS_HOTT_MULTI(module) (g_model.moduleData[module].getMultiProtocol() == MODULE_SUBTYPE_MULTI_HOTT)
|
||||
#if defined(HARDWARE_INTERNAL_MODULE)
|
||||
#define IS_FRSKY_SPORT_PROTOCOL() (telemetryProtocol == PROTOCOL_TELEMETRY_FRSKY_SPORT || (telemetryProtocol == PROTOCOL_TELEMETRY_MULTIMODULE && (IS_D16_MULTI(INTERNAL_MODULE)||IS_D16_MULTI(EXTERNAL_MODULE))))
|
||||
#else
|
||||
#define IS_FRSKY_SPORT_PROTOCOL() (telemetryProtocol == PROTOCOL_TELEMETRY_FRSKY_SPORT || (telemetryProtocol == PROTOCOL_TELEMETRY_MULTIMODULE && IS_D16_MULTI(EXTERNAL_MODULE)))
|
||||
#endif
|
||||
#else
|
||||
#define IS_FRSKY_SPORT_PROTOCOL() (telemetryProtocol == PROTOCOL_TELEMETRY_FRSKY_SPORT)
|
||||
#endif
|
||||
|
||||
@@ -530,6 +530,9 @@ int setTelemetryValue(TelemetryProtocol protocol, uint16_t id, uint8_t subId, ui
|
||||
case PROTOCOL_TELEMETRY_HITEC:
|
||||
hitecSetDefault(index, id, subId, instance);
|
||||
break;
|
||||
case PROTOCOL_TELEMETRY_HOTT:
|
||||
hottSetDefault(index, id, subId, instance);
|
||||
break;
|
||||
#endif
|
||||
#if defined(LUA)
|
||||
case PROTOCOL_TELEMETRY_LUA:
|
||||
|
||||
Reference in New Issue
Block a user