mirror of
https://github.com/opentx/opentx.git
synced 2025-07-26 17:55:19 +03:00
Add T16 support
Added support for: - T16 radio - internal multi-protocol module. - flashing internal and external multi-protocol modules. Many thx to: - goebish, for the hardware support. - qba667, for the original patches for the internal multi-protocol support (UI and serial com).
This commit is contained in:
parent
4a618f1317
commit
6b12010473
98 changed files with 4585 additions and 481 deletions
|
@ -31,27 +31,38 @@
|
|||
#define MULTI_CHANS 16
|
||||
#define MULTI_CHAN_BITS 11
|
||||
|
||||
static void sendFrameProtocolHeader(uint8_t port, bool failsafe);
|
||||
static void sendFrameProtocolHeader(uint8_t moduleIdx, bool failsafe);
|
||||
|
||||
void sendChannels(uint8_t port);
|
||||
void sendChannels(uint8_t moduleIdx);
|
||||
|
||||
static void sendSetupFrame()
|
||||
static void sendMulti(uint8_t moduleIdx, uint8_t b)
|
||||
{
|
||||
#if defined(INTERNAL_MODULE_MULTI)
|
||||
if (moduleIdx == INTERNAL_MODULE) {
|
||||
intmodulePulsesData.multi.sendByte(b);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
sendByteSbus(b);
|
||||
}
|
||||
|
||||
static void sendSetupFrame(uint8_t moduleIdx)
|
||||
{
|
||||
// Old multi firmware will mark config messsages as invalid frame and throw them away
|
||||
sendByteSbus('M');
|
||||
sendByteSbus('P');
|
||||
sendByteSbus(0x80); // Module Configuration
|
||||
sendByteSbus(1); // 1 byte data
|
||||
sendMulti(moduleIdx, 'M');
|
||||
sendMulti(moduleIdx, 'P');
|
||||
sendMulti(moduleIdx, 0x80); // Module Configuration
|
||||
sendMulti(moduleIdx, 1); // 1 byte data
|
||||
uint8_t config = 0x01 | 0x02; // inversion + multi_telemetry
|
||||
#if !defined(PPM_PIN_SERIAL)
|
||||
// TODO why PPM_PIN_SERIAL would change MULTI protocol?
|
||||
config |= 0x04; // input synchronsisation
|
||||
#endif
|
||||
|
||||
sendByteSbus(config);
|
||||
sendMulti(moduleIdx, config);
|
||||
}
|
||||
|
||||
static void sendFailsafeChannels(uint8_t port)
|
||||
static void sendFailsafeChannels(uint8_t moduleIdx)
|
||||
{
|
||||
uint32_t bits = 0;
|
||||
uint8_t bitsavailable = 0;
|
||||
|
@ -60,61 +71,72 @@ static void sendFailsafeChannels(uint8_t port)
|
|||
int16_t failsafeValue = g_model.failsafeChannels[i];
|
||||
int pulseValue;
|
||||
|
||||
if (g_model.moduleData[port].failsafeMode == FAILSAFE_HOLD) {
|
||||
if (g_model.moduleData[moduleIdx].failsafeMode == FAILSAFE_HOLD) {
|
||||
pulseValue = 2047;
|
||||
}
|
||||
else if (g_model.moduleData[port].failsafeMode == FAILSAFE_NOPULSES) {
|
||||
else if (g_model.moduleData[moduleIdx].failsafeMode == FAILSAFE_NOPULSES) {
|
||||
pulseValue = 0;
|
||||
}
|
||||
else {
|
||||
failsafeValue += 2 * PPM_CH_CENTER(g_model.moduleData[port].channelsStart + i) - 2 * PPM_CENTER;
|
||||
failsafeValue += 2 * PPM_CH_CENTER(g_model.moduleData[moduleIdx].channelsStart + i) - 2 * PPM_CENTER;
|
||||
pulseValue = limit(1, (failsafeValue * 800 / 1000) + 1024, 2047);
|
||||
}
|
||||
|
||||
bits |= pulseValue << bitsavailable;
|
||||
bitsavailable += MULTI_CHAN_BITS;
|
||||
while (bitsavailable >= 8) {
|
||||
sendByteSbus((uint8_t) (bits & 0xff));
|
||||
sendMulti(moduleIdx, (uint8_t) (bits & 0xff));
|
||||
bits >>= 8;
|
||||
bitsavailable -= 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setupPulsesMultimodule()
|
||||
void setupPulsesMulti(uint8_t moduleIdx)
|
||||
{
|
||||
static int counter = 0;
|
||||
static int counter[2] = {0,0}; //TODO
|
||||
|
||||
// Every 1000 cycles (=9s) send a config packet that configures the multimodule (inversion, telemetry type)
|
||||
counter[moduleIdx]++;
|
||||
if (counter[moduleIdx] % 1000 == 500) {
|
||||
sendSetupFrame(moduleIdx);
|
||||
}
|
||||
else if (counter[moduleIdx] % 1000 == 0 && g_model.moduleData[moduleIdx].failsafeMode != FAILSAFE_NOT_SET && g_model.moduleData[moduleIdx].failsafeMode != FAILSAFE_RECEIVER) {
|
||||
sendFrameProtocolHeader(moduleIdx, true);
|
||||
sendFailsafeChannels(moduleIdx);
|
||||
}
|
||||
else {
|
||||
// Normal Frame
|
||||
sendFrameProtocolHeader(moduleIdx, false);
|
||||
sendChannels(moduleIdx);
|
||||
}
|
||||
}
|
||||
|
||||
void setupPulsesMultiExternalModule()
|
||||
{
|
||||
#if defined(PPM_PIN_SERIAL)
|
||||
extmodulePulsesData.dsm2.serialByte = 0 ;
|
||||
extmodulePulsesData.dsm2.serialBitCount = 0 ;
|
||||
#else
|
||||
extmodulePulsesData.dsm2.rest = multiSyncStatus.getAdjustedRefreshRate();
|
||||
extmodulePulsesData.dsm2.rest = getMultiSyncStatus(EXTERNAL_MODULE).getAdjustedRefreshRate();
|
||||
extmodulePulsesData.dsm2.index = 0;
|
||||
#endif
|
||||
|
||||
extmodulePulsesData.dsm2.ptr = extmodulePulsesData.dsm2.pulses;
|
||||
|
||||
// Every 1000 cycles (=9s) send a config packet that configures the multimodule (inversion, telemetry type)
|
||||
counter++;
|
||||
if (counter % 1000 == 500) {
|
||||
sendSetupFrame();
|
||||
}
|
||||
else if (counter % 1000 == 0 && g_model.moduleData[EXTERNAL_MODULE].failsafeMode != FAILSAFE_NOT_SET && g_model.moduleData[EXTERNAL_MODULE].failsafeMode != FAILSAFE_RECEIVER) {
|
||||
sendFrameProtocolHeader(EXTERNAL_MODULE, true);
|
||||
sendFailsafeChannels(EXTERNAL_MODULE);
|
||||
}
|
||||
else {
|
||||
// Normal Frame
|
||||
sendFrameProtocolHeader(EXTERNAL_MODULE, false);
|
||||
sendChannels(EXTERNAL_MODULE);
|
||||
}
|
||||
|
||||
setupPulsesMulti(EXTERNAL_MODULE);
|
||||
putDsm2Flush();
|
||||
}
|
||||
|
||||
#if defined(INTERNAL_MODULE_MULTI)
|
||||
void setupPulsesMultiInternalModule()
|
||||
{
|
||||
intmodulePulsesData.multi.initFrame();
|
||||
setupPulsesMulti(INTERNAL_MODULE);
|
||||
}
|
||||
#endif
|
||||
|
||||
void sendChannels(uint8_t port)
|
||||
void sendChannels(uint8_t moduleIdx)
|
||||
{
|
||||
uint32_t bits = 0;
|
||||
uint8_t bitsavailable = 0;
|
||||
|
@ -123,7 +145,7 @@ void sendChannels(uint8_t port)
|
|||
// Range for pulses (channelsOutputs) is [-1024:+1024] for [-100%;100%]
|
||||
// Multi uses [204;1843] as [-100%;100%]
|
||||
for (int i = 0; i < MULTI_CHANS; i++) {
|
||||
int channel = g_model.moduleData[port].channelsStart + i;
|
||||
int channel = g_model.moduleData[moduleIdx].channelsStart + i;
|
||||
int value = channelOutputs[channel] + 2 * PPM_CH_CENTER(channel) - 2 * PPM_CENTER;
|
||||
|
||||
// Scale to 80%
|
||||
|
@ -133,36 +155,36 @@ void sendChannels(uint8_t port)
|
|||
bits |= value << bitsavailable;
|
||||
bitsavailable += MULTI_CHAN_BITS;
|
||||
while (bitsavailable >= 8) {
|
||||
sendByteSbus((uint8_t) (bits & 0xff));
|
||||
sendMulti(moduleIdx, (uint8_t) (bits & 0xff));
|
||||
bits >>= 8;
|
||||
bitsavailable -= 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sendFrameProtocolHeader(uint8_t port, bool failsafe)
|
||||
void sendFrameProtocolHeader(uint8_t moduleIdx, bool failsafe)
|
||||
{// byte 1+2, protocol information
|
||||
|
||||
// Our enumeration starts at 0
|
||||
int type = g_model.moduleData[port].getMultiProtocol(false) + 1;
|
||||
int subtype = g_model.moduleData[port].subType;
|
||||
int8_t optionValue = g_model.moduleData[port].multi.optionValue;
|
||||
int type = g_model.moduleData[moduleIdx].getMultiProtocol(false) + 1;
|
||||
int subtype = g_model.moduleData[moduleIdx].subType;
|
||||
int8_t optionValue = g_model.moduleData[moduleIdx].multi.optionValue;
|
||||
|
||||
uint8_t protoByte = 0;
|
||||
if (moduleState[port].mode == MODULE_MODE_BIND)
|
||||
if (moduleState[moduleIdx].mode == MODULE_MODE_BIND)
|
||||
protoByte |= MULTI_SEND_BIND;
|
||||
else if (moduleState[port].mode == MODULE_MODE_RANGECHECK)
|
||||
else if (moduleState[moduleIdx].mode == MODULE_MODE_RANGECHECK)
|
||||
protoByte |= MULTI_SEND_RANGECHECK;
|
||||
|
||||
// rfProtocol
|
||||
if (g_model.moduleData[port].getMultiProtocol(true) == MODULE_SUBTYPE_MULTI_DSM2) {
|
||||
if (g_model.moduleData[moduleIdx].getMultiProtocol(true) == MODULE_SUBTYPE_MULTI_DSM2) {
|
||||
|
||||
// Autobinding should always be done in DSMX 11ms
|
||||
if (g_model.moduleData[port].multi.autoBindMode && moduleState[port].mode == MODULE_MODE_BIND)
|
||||
if (g_model.moduleData[moduleIdx].multi.autoBindMode && moduleState[moduleIdx].mode == MODULE_MODE_BIND)
|
||||
subtype = MM_RF_DSM2_SUBTYPE_AUTO;
|
||||
|
||||
// Multi module in DSM mode wants the number of channels to be used as option value
|
||||
optionValue = sentModuleChannels(EXTERNAL_MODULE);
|
||||
optionValue = sentModuleChannels(moduleIdx);
|
||||
|
||||
}
|
||||
|
||||
|
@ -175,7 +197,7 @@ void sendFrameProtocolHeader(uint8_t port, bool failsafe)
|
|||
if (type >= 25)
|
||||
type = type + 1;
|
||||
|
||||
if (g_model.moduleData[port].getMultiProtocol(true) == MODULE_SUBTYPE_MULTI_FRSKY) {
|
||||
if (g_model.moduleData[moduleIdx].getMultiProtocol(true) == MODULE_SUBTYPE_MULTI_FRSKY) {
|
||||
if (subtype == MM_RF_FRSKY_SUBTYPE_D8) {
|
||||
//D8
|
||||
type = 3;
|
||||
|
@ -199,12 +221,12 @@ void sendFrameProtocolHeader(uint8_t port, bool failsafe)
|
|||
|
||||
// Set the highest bit of option byte in AFHDS2A protocol to instruct MULTI to passthrough telemetry bytes instead
|
||||
// of sending Frsky D telemetry
|
||||
if (g_model.moduleData[port].getMultiProtocol(false) == MODULE_SUBTYPE_MULTI_FS_AFHDS2A)
|
||||
if (g_model.moduleData[moduleIdx].getMultiProtocol(false) == MODULE_SUBTYPE_MULTI_FS_AFHDS2A)
|
||||
optionValue = optionValue | 0x80;
|
||||
|
||||
// For custom protocol send unmodified type byte
|
||||
if (g_model.moduleData[port].getMultiProtocol(true) == MM_RF_CUSTOM_SELECTED)
|
||||
type = g_model.moduleData[port].getMultiProtocol(false);
|
||||
if (g_model.moduleData[moduleIdx].getMultiProtocol(true) == MM_RF_CUSTOM_SELECTED)
|
||||
type = g_model.moduleData[moduleIdx].getMultiProtocol(false);
|
||||
|
||||
|
||||
uint8_t headerByte = 0x54;
|
||||
|
@ -213,24 +235,24 @@ void sendFrameProtocolHeader(uint8_t port, bool failsafe)
|
|||
|
||||
// header, byte 0, 0x55 for proto 0-31 0x54 for 32-63
|
||||
if (type <= 31)
|
||||
sendByteSbus(headerByte+1);
|
||||
sendMulti(moduleIdx, headerByte+1);
|
||||
else
|
||||
sendByteSbus(headerByte);
|
||||
sendMulti(moduleIdx, headerByte);
|
||||
|
||||
|
||||
// protocol byte
|
||||
protoByte |= (type & 0x1f);
|
||||
if (g_model.moduleData[port].getMultiProtocol(true) != MODULE_SUBTYPE_MULTI_DSM2)
|
||||
protoByte |= (g_model.moduleData[port].multi.autoBindMode << 6);
|
||||
if (g_model.moduleData[moduleIdx].getMultiProtocol(true) != MODULE_SUBTYPE_MULTI_DSM2)
|
||||
protoByte |= (g_model.moduleData[moduleIdx].multi.autoBindMode << 6);
|
||||
|
||||
sendByteSbus(protoByte);
|
||||
sendMulti(moduleIdx, protoByte);
|
||||
|
||||
// byte 2, subtype, powermode, model id
|
||||
sendByteSbus((uint8_t) ((g_model.header.modelId[port] & 0x0f)
|
||||
sendMulti(moduleIdx, (uint8_t) ((g_model.header.modelId[moduleIdx] & 0x0f)
|
||||
| ((subtype & 0x7) << 4)
|
||||
| (g_model.moduleData[port].multi.lowPowerMode << 7))
|
||||
| (g_model.moduleData[moduleIdx].multi.lowPowerMode << 7))
|
||||
);
|
||||
|
||||
// byte 3
|
||||
sendByteSbus((uint8_t) optionValue);
|
||||
sendMulti(moduleIdx, (uint8_t) optionValue);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue