mirror of
https://github.com/opentx/opentx.git
synced 2025-07-24 16:55:20 +03:00
399 lines
10 KiB
C++
Executable file
399 lines
10 KiB
C++
Executable file
/*
|
|
* 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.
|
|
*/
|
|
|
|
#include "opentx.h"
|
|
#include "io/frsky_pxx2.h"
|
|
#include "pulses/pxx2.h"
|
|
|
|
uint8_t s_pulses_paused = 0;
|
|
ModuleState moduleState[NUM_MODULES];
|
|
InternalModulePulsesData intmodulePulsesData __DMA;
|
|
ExternalModulePulsesData extmodulePulsesData __DMA;
|
|
TrainerPulsesData trainerPulsesData __DMA;
|
|
|
|
uint8_t getModuleType(uint8_t module)
|
|
{
|
|
uint8_t type = g_model.moduleData[module].type;
|
|
|
|
#if defined(HARDWARE_INTERNAL_MODULE)
|
|
if (module == INTERNAL_MODULE && isInternalModuleAvailable(type)) {
|
|
return type;
|
|
}
|
|
#endif
|
|
|
|
if (module == EXTERNAL_MODULE && isExternalModuleAvailable(type)) {
|
|
return type;
|
|
}
|
|
|
|
return MODULE_TYPE_NONE;
|
|
}
|
|
|
|
uint8_t getRequiredProtocol(uint8_t module)
|
|
{
|
|
uint8_t protocol;
|
|
|
|
switch (getModuleType(module)) {
|
|
case MODULE_TYPE_PPM:
|
|
protocol = PROTOCOL_CHANNELS_PPM;
|
|
break;
|
|
|
|
case MODULE_TYPE_XJT_PXX1:
|
|
#if defined(INTMODULE_USART)
|
|
if (module == INTERNAL_MODULE) {
|
|
protocol = PROTOCOL_CHANNELS_PXX1_SERIAL;
|
|
break;
|
|
}
|
|
#endif
|
|
// no break
|
|
|
|
case MODULE_TYPE_R9M_PXX1:
|
|
protocol = PROTOCOL_CHANNELS_PXX1_PULSES;
|
|
break;
|
|
|
|
#if defined(HARDWARE_EXTERNAL_MODULE_SIZE_SML)
|
|
case MODULE_TYPE_R9M_LITE_PXX1:
|
|
case MODULE_TYPE_R9M_LITE_PRO_PXX1:
|
|
protocol = PROTOCOL_CHANNELS_PXX1_SERIAL;
|
|
break;
|
|
|
|
case MODULE_TYPE_R9M_LITE_PXX2:
|
|
protocol = PROTOCOL_CHANNELS_PXX2_LOWSPEED;
|
|
break;
|
|
#endif
|
|
|
|
case MODULE_TYPE_ISRM_PXX2:
|
|
case MODULE_TYPE_R9M_PXX2:
|
|
#if defined(HARDWARE_EXTERNAL_MODULE_SIZE_SML)
|
|
case MODULE_TYPE_XJT_LITE_PXX2:
|
|
case MODULE_TYPE_R9M_LITE_PRO_PXX2:
|
|
#endif
|
|
protocol = PROTOCOL_CHANNELS_PXX2_HIGHSPEED;
|
|
break;
|
|
|
|
case MODULE_TYPE_SBUS:
|
|
protocol = PROTOCOL_CHANNELS_SBUS;
|
|
break;
|
|
|
|
#if defined(MULTIMODULE)
|
|
case MODULE_TYPE_MULTIMODULE:
|
|
protocol = PROTOCOL_CHANNELS_MULTIMODULE;
|
|
break;
|
|
#endif
|
|
|
|
#if defined(DSM2)
|
|
case MODULE_TYPE_DSM2:
|
|
protocol = limit<uint8_t>(PROTOCOL_CHANNELS_DSM2_LP45, PROTOCOL_CHANNELS_DSM2_LP45+g_model.moduleData[module].rfProtocol, PROTOCOL_CHANNELS_DSM2_DSMX);
|
|
// The module is set to OFF during one second before BIND start
|
|
{
|
|
static tmr10ms_t bindStartTime = 0;
|
|
if (moduleState[module].mode == MODULE_MODE_BIND) {
|
|
if (bindStartTime == 0) bindStartTime = get_tmr10ms();
|
|
if ((tmr10ms_t)(get_tmr10ms() - bindStartTime) < 100) {
|
|
protocol = PROTOCOL_CHANNELS_NONE;
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
bindStartTime = 0;
|
|
}
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
#if defined(CROSSFIRE)
|
|
case MODULE_TYPE_CROSSFIRE:
|
|
protocol = PROTOCOL_CHANNELS_CROSSFIRE;
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
protocol = PROTOCOL_CHANNELS_NONE;
|
|
break;
|
|
}
|
|
|
|
if (s_pulses_paused) {
|
|
protocol = PROTOCOL_CHANNELS_NONE;
|
|
}
|
|
|
|
#if 0
|
|
// will need an EEPROM conversion
|
|
if (moduleState[module].mode == MODULE_OFF) {
|
|
protocol = PROTOCOL_CHANNELS_NONE;
|
|
}
|
|
#endif
|
|
|
|
return protocol;
|
|
}
|
|
|
|
void enablePulsesExternalModule(uint8_t protocol)
|
|
{
|
|
// start new protocol hardware here
|
|
|
|
switch (protocol) {
|
|
#if defined(PXX1)
|
|
case PROTOCOL_CHANNELS_PXX1_PULSES:
|
|
extmodulePxx1PulsesStart();
|
|
break;
|
|
#endif
|
|
|
|
#if defined(PXX1) && defined(HARDWARE_EXTERNAL_MODULE_SIZE_SML)
|
|
case PROTOCOL_CHANNELS_PXX1_SERIAL:
|
|
extmodulePxx1SerialStart();
|
|
break;
|
|
#endif
|
|
|
|
#if defined(DSM2)
|
|
case PROTOCOL_CHANNELS_DSM2_LP45:
|
|
case PROTOCOL_CHANNELS_DSM2_DSM2:
|
|
case PROTOCOL_CHANNELS_DSM2_DSMX:
|
|
extmoduleSerialStart(DSM2_BAUDRATE, DSM2_PERIOD * 2000, false);
|
|
break;
|
|
#endif
|
|
|
|
#if defined(CROSSFIRE)
|
|
case PROTOCOL_CHANNELS_CROSSFIRE:
|
|
EXTERNAL_MODULE_ON();
|
|
break;
|
|
#endif
|
|
|
|
#if defined(PXX2)
|
|
case PROTOCOL_CHANNELS_PXX2_HIGHSPEED:
|
|
extmoduleInvertedSerialStart(PXX2_HIGHSPEED_BAUDRATE);
|
|
break;
|
|
|
|
case PROTOCOL_CHANNELS_PXX2_LOWSPEED:
|
|
extmoduleInvertedSerialStart(PXX2_LOWSPEED_BAUDRATE);
|
|
break;
|
|
#endif
|
|
|
|
#if defined(MULTIMODULE)
|
|
case PROTOCOL_CHANNELS_MULTIMODULE:
|
|
extmoduleSerialStart(MULTIMODULE_BAUDRATE, MULTIMODULE_PERIOD * 2000, true);
|
|
break;
|
|
#endif
|
|
|
|
#if defined(SBUS)
|
|
case PROTOCOL_CHANNELS_SBUS:
|
|
extmoduleSerialStart(SBUS_BAUDRATE, SBUS_PERIOD_HALF_US, false);
|
|
break;
|
|
#endif
|
|
|
|
#if defined(PPM)
|
|
case PROTOCOL_CHANNELS_PPM:
|
|
extmodulePpmStart();
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void setupPulsesExternalModule(uint8_t protocol)
|
|
{
|
|
switch (protocol) {
|
|
#if defined(PXX1)
|
|
case PROTOCOL_CHANNELS_PXX1_PULSES:
|
|
extmodulePulsesData.pxx.setupFrame(EXTERNAL_MODULE);
|
|
scheduleNextMixerCalculation(EXTERNAL_MODULE, PXX_PULSES_PERIOD);
|
|
break;
|
|
#endif
|
|
|
|
#if defined(PXX1) && defined(EXTMODULE_USART)
|
|
case PROTOCOL_CHANNELS_PXX1_SERIAL:
|
|
extmodulePulsesData.pxx_uart.setupFrame(EXTERNAL_MODULE);
|
|
scheduleNextMixerCalculation(EXTERNAL_MODULE, EXTMODULE_PXX1_SERIAL_PERIOD);
|
|
break;
|
|
#endif
|
|
|
|
#if defined(PXX2)
|
|
case PROTOCOL_CHANNELS_PXX2_HIGHSPEED:
|
|
case PROTOCOL_CHANNELS_PXX2_LOWSPEED:
|
|
extmodulePulsesData.pxx2.setupFrame(EXTERNAL_MODULE);
|
|
scheduleNextMixerCalculation(EXTERNAL_MODULE, PXX2_PERIOD);
|
|
break;
|
|
#endif
|
|
|
|
#if defined(SBUS)
|
|
case PROTOCOL_CHANNELS_SBUS:
|
|
setupPulsesSbus();
|
|
scheduleNextMixerCalculation(EXTERNAL_MODULE, SBUS_PERIOD);
|
|
break;
|
|
#endif
|
|
|
|
#if defined(DSM2)
|
|
case PROTOCOL_CHANNELS_DSM2_LP45:
|
|
case PROTOCOL_CHANNELS_DSM2_DSM2:
|
|
case PROTOCOL_CHANNELS_DSM2_DSMX:
|
|
setupPulsesDSM2();
|
|
scheduleNextMixerCalculation(EXTERNAL_MODULE, DSM2_PERIOD);
|
|
break;
|
|
#endif
|
|
|
|
#if defined(CROSSFIRE)
|
|
case PROTOCOL_CHANNELS_CROSSFIRE:
|
|
setupPulsesCrossfire();
|
|
scheduleNextMixerCalculation(EXTERNAL_MODULE, CROSSFIRE_PERIOD);
|
|
break;
|
|
#endif
|
|
|
|
#if defined(MULTIMODULE)
|
|
case PROTOCOL_CHANNELS_MULTIMODULE:
|
|
setupPulsesMultimodule();
|
|
scheduleNextMixerCalculation(EXTERNAL_MODULE, MULTIMODULE_PERIOD);
|
|
break;
|
|
#endif
|
|
|
|
#if defined(PPM)
|
|
case PROTOCOL_CHANNELS_PPM:
|
|
setupPulsesPPMExternalModule();
|
|
scheduleNextMixerCalculation(EXTERNAL_MODULE, PPM_PERIOD(EXTERNAL_MODULE));
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
#if defined(HARDWARE_INTERNAL_MODULE)
|
|
void enablePulsesInternalModule(uint8_t protocol)
|
|
{
|
|
// start new protocol hardware here
|
|
|
|
switch (protocol) {
|
|
#if defined(PXX1) && !defined(INTMODULE_USART)
|
|
case PROTOCOL_CHANNELS_PXX1_PULSES:
|
|
intmodulePxx1PulsesStart();
|
|
break;
|
|
#endif
|
|
|
|
#if defined(PXX1) && defined(INTMODULE_USART)
|
|
case PROTOCOL_CHANNELS_PXX1_SERIAL:
|
|
intmodulePxx1SerialStart();
|
|
break;
|
|
#endif
|
|
|
|
#if defined(PXX2)
|
|
case PROTOCOL_CHANNELS_PXX2_HIGHSPEED:
|
|
intmoduleSerialStart(PXX2_HIGHSPEED_BAUDRATE, true);
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void setupPulsesInternalModule(uint8_t protocol)
|
|
{
|
|
switch (protocol) {
|
|
#if defined(HARDWARE_INTERNAL_MODULE) && defined(PXX1) && !defined(INTMODULE_USART)
|
|
case PROTOCOL_CHANNELS_PXX1_PULSES:
|
|
intmodulePulsesData.pxx.setupFrame(INTERNAL_MODULE);
|
|
scheduleNextMixerCalculation(INTERNAL_MODULE, INTMODULE_PXX1_SERIAL_PERIOD);
|
|
break;
|
|
#endif
|
|
|
|
#if defined(PXX1) && defined(INTMODULE_USART)
|
|
case PROTOCOL_CHANNELS_PXX1_SERIAL:
|
|
intmodulePulsesData.pxx_uart.setupFrame(INTERNAL_MODULE);
|
|
#if !defined(INTMODULE_HEARTBEAT)
|
|
scheduleNextMixerCalculation(INTERNAL_MODULE, INTMODULE_PXX1_SERIAL_PERIOD);
|
|
#endif
|
|
break;
|
|
#endif
|
|
|
|
#if defined(PXX2)
|
|
case PROTOCOL_CHANNELS_PXX2_HIGHSPEED:
|
|
intmodulePulsesData.pxx2.setupFrame(INTERNAL_MODULE);
|
|
if (moduleState[INTERNAL_MODULE].mode == MODULE_MODE_SPECTRUM_ANALYSER || moduleState[INTERNAL_MODULE].mode == MODULE_MODE_POWER_METER) {
|
|
scheduleNextMixerCalculation(INTERNAL_MODULE, PXX2_TOOLS_PERIOD);
|
|
}
|
|
#if !defined(INTMODULE_HEARTBEAT)
|
|
else {
|
|
scheduleNextMixerCalculation(INTERNAL_MODULE, PXX2_PERIOD);
|
|
}
|
|
#endif
|
|
break;
|
|
#endif
|
|
|
|
#if defined(PCBTARANIS) && defined(INTERNAL_MODULE_PPM)
|
|
case PROTOCOL_CHANNELS_PPM:
|
|
setupPulsesPPM(&extmodulePulsesData.ppm, g_model.moduleData[INTERNAL_MODULE].channelsStart, g_model.moduleData[INTERNAL_MODULE].channelsCount, g_model.moduleData[INTERNAL_MODULE].ppm.frameLength);
|
|
scheduleNextMixerCalculation(INTERNAL_MODULE, PPM_PERIOD(INTERNAL_MODULE));
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
bool setupPulsesInternalModule()
|
|
{
|
|
uint8_t protocol = getRequiredProtocol(INTERNAL_MODULE);
|
|
|
|
heartbeat |= (HEART_TIMER_PULSES << INTERNAL_MODULE);
|
|
|
|
if (moduleState[INTERNAL_MODULE].protocol != protocol) {
|
|
intmoduleStop();
|
|
moduleState[INTERNAL_MODULE].protocol = protocol;
|
|
enablePulsesInternalModule(protocol);
|
|
return false;
|
|
}
|
|
else {
|
|
setupPulsesInternalModule(protocol);
|
|
return true;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
bool setupPulsesExternalModule()
|
|
{
|
|
uint8_t protocol = getRequiredProtocol(EXTERNAL_MODULE);
|
|
|
|
heartbeat |= (HEART_TIMER_PULSES << EXTERNAL_MODULE);
|
|
|
|
if (moduleState[EXTERNAL_MODULE].protocol != protocol) {
|
|
extmoduleStop();
|
|
moduleState[EXTERNAL_MODULE].protocol = protocol;
|
|
enablePulsesExternalModule(protocol);
|
|
return false;
|
|
}
|
|
else {
|
|
setupPulsesExternalModule(protocol);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
void setCustomFailsafe(uint8_t moduleIndex)
|
|
{
|
|
if (moduleIndex < NUM_MODULES) {
|
|
for (int ch=0; ch<MAX_OUTPUT_CHANNELS; ch++) {
|
|
if (ch < g_model.moduleData[moduleIndex].channelsStart || ch >= sentModuleChannels(moduleIndex) + g_model.moduleData[moduleIndex].channelsStart) {
|
|
g_model.failsafeChannels[ch] = 0;
|
|
}
|
|
else if (g_model.failsafeChannels[ch] < FAILSAFE_CHANNEL_HOLD) {
|
|
g_model.failsafeChannels[ch] = channelOutputs[ch];
|
|
}
|
|
}
|
|
}
|
|
}
|