Files
edgetx-gx12/radio/src/trainer.cpp
T

210 lines
5.3 KiB
C++

/*
* 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 "hal/trainer_driver.h"
#include "edgetx.h"
// Timer gets decremented in per10ms()
#define TRAINER_IN_VALID_TIMEOUT 100 // 1s
int16_t trainerInput[MAX_TRAINER_CHANNELS];
uint8_t trainerInputValidityTimer;
uint8_t currentTrainerMode = 0xff;
void (*_on_change_cb)(uint8_t, uint8_t) = nullptr;
// Active signal received
bool isTrainerValid() { return trainerInputValidityTimer != 0; }
void trainerResetTimer()
{
trainerInputValidityTimer = TRAINER_IN_VALID_TIMEOUT;
}
void trainerDecTimer()
{
if (trainerInputValidityTimer) trainerInputValidityTimer--;
}
void trainerSetTimer(uint16_t t)
{
trainerInputValidityTimer = t;
}
enum {
TRAINER_NOT_CONNECTED = 0,
TRAINER_CONNECTED,
TRAINER_DISCONNECTED,
TRAINER_RECONNECTED
};
uint8_t trainerStatus = TRAINER_NOT_CONNECTED;
bool isTrainerConnected()
{
return trainerStatus == TRAINER_CONNECTED || trainerStatus == TRAINER_RECONNECTED;
}
void checkTrainerSignalWarning()
{
enum {
TRAINER_IN_IS_NOT_USED = 0,
TRAINER_IN_IS_VALID,
TRAINER_IN_IS_INVALID
};
static uint8_t trainerInputValidState = TRAINER_IN_IS_NOT_USED;
if (trainerInputValidityTimer && (trainerInputValidState == TRAINER_IN_IS_NOT_USED)) {
trainerInputValidState = TRAINER_IN_IS_VALID;
trainerStatus = TRAINER_CONNECTED;
AUDIO_TRAINER_CONNECTED();
}
else if (!trainerInputValidityTimer && (trainerInputValidState == TRAINER_IN_IS_VALID)) {
trainerInputValidState = TRAINER_IN_IS_INVALID;
trainerStatus = TRAINER_DISCONNECTED;
AUDIO_TRAINER_LOST();
}
else if (trainerInputValidityTimer && (trainerInputValidState == TRAINER_IN_IS_INVALID)) {
trainerInputValidState = TRAINER_IN_IS_VALID;
trainerStatus = TRAINER_RECONNECTED;
AUDIO_TRAINER_BACK();
}
}
static void trainer_init_module_sbus();
static void trainer_stop_module_sbus();
void stopTrainer()
{
switch (currentTrainerMode) {
case TRAINER_MODE_MASTER_TRAINER_JACK:
case TRAINER_MODE_SLAVE:
trainer_stop_dsc();
break;
case TRAINER_MODE_MASTER_SERIAL:
sbusAuxSetEnabled(false);
break;
case TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE:
trainer_stop_module_cppm();
break;
case TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE:
trainer_stop_module_sbus();
break;
}
if (_on_change_cb) {
_on_change_cb(currentTrainerMode, 0xFF);
}
currentTrainerMode = 0xFF;
}
void checkTrainerSettings()
{
uint8_t requiredTrainerMode = g_model.trainerData.mode;
if (requiredTrainerMode != currentTrainerMode) {
if (currentTrainerMode != 0xFF) {
stopTrainer();
}
switch (requiredTrainerMode) {
case TRAINER_MODE_MASTER_TRAINER_JACK:
trainer_init_dsc_in();
break;
case TRAINER_MODE_SLAVE:
trainer_init_dsc_out();
break;
case TRAINER_MODE_MASTER_SERIAL:
sbusAuxSetEnabled(true);
break;
case TRAINER_MODE_MASTER_CPPM_EXTERNAL_MODULE:
trainer_init_module_cppm();
break;
case TRAINER_MODE_MASTER_SBUS_EXTERNAL_MODULE:
trainer_init_module_sbus();
break;
}
if (_on_change_cb) {
_on_change_cb(currentTrainerMode, requiredTrainerMode);
}
currentTrainerMode = requiredTrainerMode;
}
}
void trainerSetChangeCb(void (*changeCb)(uint8_t, uint8_t))
{
_on_change_cb = changeCb;
}
static const etx_serial_init sbusTrainerParams = {
.baudrate = SBUS_BAUDRATE,
.encoding = ETX_Encoding_8E2,
.direction = ETX_Dir_RX,
.polarity = ETX_Pol_Normal,
};
static etx_module_state_t* sbus_trainer_mod_st = nullptr;
static void trainer_init_module_sbus()
{
if (sbus_trainer_mod_st) return;
// check if UART with inverter on heartbeat pin is available
sbus_trainer_mod_st = modulePortInitSerial(EXTERNAL_MODULE, ETX_MOD_PORT_UART,
&sbusTrainerParams, false);
if(sbus_trainer_mod_st == nullptr) {
// otherwise fall back to S.Port pin
sbus_trainer_mod_st = modulePortInitSerial(
EXTERNAL_MODULE, ETX_MOD_PORT_SPORT, &sbusTrainerParams, false);
}
if (sbus_trainer_mod_st) {
// configure IDLE IRQ callback
auto drv = modulePortGetSerialDrv(sbus_trainer_mod_st->rx);
auto ctx = modulePortGetCtx(sbus_trainer_mod_st->rx);
sbusSetReceiveCtx(ctx, drv);
if (drv && drv->setIdleCb)
drv->setIdleCb(ctx, sbusFrameReceived, nullptr);
// switch ON
modulePortSetPower(EXTERNAL_MODULE, true);
}
}
static void trainer_stop_module_sbus()
{
if (!sbus_trainer_mod_st) return;
modulePortDeInit(sbus_trainer_mod_st);
modulePortSetPower(EXTERNAL_MODULE,false);
sbus_trainer_mod_st = nullptr;
}