Merge pull request #2606 from opentx/raphaelcoeffic/issue2579

Fixes #2579: Added support for Trainer signal alarm
This commit is contained in:
Bertrand Songis
2015-08-01 08:41:50 +02:00
16 changed files with 198 additions and 91 deletions
+2 -2
View File
@@ -108,7 +108,7 @@ return main_thread_error;
#ifdef SETTRAINER_IMPORT
#undef SETTRAINER_IMPORT
ppmInValid = 100;
g_ppmIns[inputNumber] = LIMIT< ::int16_t>(-512, value, 512);
ppmInputValidityTimer = 100;
ppmInput[inputNumber] = LIMIT< ::int16_t>(-512, value, 512);
#endif
+1 -1
View File
@@ -1058,7 +1058,7 @@ ifeq ($(GUI), YES)
CPPDEFS += -DGUI
endif
CPPSRC += opentx.cpp functions.cpp strhelpers.cpp $(PULSESSRC) switches.cpp curves.cpp mixer.cpp stamp.cpp $(GUISRC) $(EEPROMSRC) timers.cpp
CPPSRC += opentx.cpp functions.cpp strhelpers.cpp $(PULSESSRC) switches.cpp curves.cpp mixer.cpp stamp.cpp $(GUISRC) $(EEPROMSRC) timers.cpp trainer_input.cpp
ifeq ($(GUI), YES)
GUISRC += gui/$(GUIDIRECTORY)/lcd.cpp gui/$(GUIDIRECTORY)/splash.cpp gui/$(GUIDIRECTORY)/fonts.cpp
+2
View File
@@ -169,6 +169,8 @@ const char * const audioFilenames[] = {
"swr_red",
"telemko",
"telemok",
"trainko",
"trainok",
#if defined(PCBSKY9X)
"highmah",
"hightemp",
+2
View File
@@ -331,6 +331,8 @@ void audioStart();
#define AUDIO_RXBATT_RED() audioEvent(AU_RXBATT_RED)
#define AUDIO_TELEMETRY_LOST() audioEvent(AU_TELEMETRY_LOST)
#define AUDIO_TELEMETRY_BACK() audioEvent(AU_TELEMETRY_BACK)
#define AUDIO_TRAINER_LOST() audioEvent(AU_TRAINER_LOST)
#define AUDIO_TRAINER_BACK() audioEvent(AU_TRAINER_BACK)
#define AUDIO_HEARTBEAT()
+3 -3
View File
@@ -97,15 +97,15 @@ void menuGeneralTrainer(uint8_t event)
for (uint8_t i=0; i<4; i++) {
uint8_t x = (i*TRAINER_CALIB_POS+16)*FW/2;
#if defined (PPM_UNIT_PERCENT_PREC1)
lcd_outdezAtt(x, MENU_HEADER_HEIGHT+1+6*FH, (g_ppmIns[i]-g_eeGeneral.trainer.calib[i])*2, PREC1);
lcd_outdezAtt(x, MENU_HEADER_HEIGHT+1+6*FH, (ppmInput[i]-g_eeGeneral.trainer.calib[i])*2, PREC1);
#else
lcd_outdezAtt(x, MENU_HEADER_HEIGHT+1+6*FH, (g_ppmIns[i]-g_eeGeneral.trainer.calib[i])/5, 0);
lcd_outdezAtt(x, MENU_HEADER_HEIGHT+1+6*FH, (ppmInput[i]-g_eeGeneral.trainer.calib[i])/5, 0);
#endif
}
if (attr) {
if (event==EVT_KEY_LONG(KEY_ENTER)){
memcpy(g_eeGeneral.trainer.calib, g_ppmIns, sizeof(g_eeGeneral.trainer.calib));
memcpy(g_eeGeneral.trainer.calib, ppmInput, sizeof(g_eeGeneral.trainer.calib));
eeDirty(EE_GENERAL);
AUDIO_WARNING1();
}
@@ -99,15 +99,15 @@ void menuGeneralTrainer(uint8_t event)
for (int i=0; i<4; i++) {
uint8_t x = (i*TRAINER_CALIB_POS+16)*FW/2;
#if defined (PPM_UNIT_PERCENT_PREC1)
lcd_outdezAtt(x, MENU_HEADER_HEIGHT+1+6*FH, (g_ppmIns[i]-g_eeGeneral.trainer.calib[i])*2, PREC1);
lcd_outdezAtt(x, MENU_HEADER_HEIGHT+1+6*FH, (ppmInput[i]-g_eeGeneral.trainer.calib[i])*2, PREC1);
#else
lcd_outdezAtt(x, MENU_HEADER_HEIGHT+1+6*FH, (g_ppmIns[i]-g_eeGeneral.trainer.calib[i])/5, 0);
lcd_outdezAtt(x, MENU_HEADER_HEIGHT+1+6*FH, (ppmInput[i]-g_eeGeneral.trainer.calib[i])/5, 0);
#endif
}
if (attr) {
if (event==EVT_KEY_LONG(KEY_ENTER)){
memcpy(g_eeGeneral.trainer.calib, g_ppmIns, sizeof(g_eeGeneral.trainer.calib));
memcpy(g_eeGeneral.trainer.calib, ppmInput, sizeof(g_eeGeneral.trainer.calib));
eeDirty(EE_GENERAL);
AUDIO_WARNING1();
}
+4 -4
View File
@@ -293,7 +293,7 @@ getvalue_t getValue(mixsrc_t i)
else if (i<MIXSRC_SW1) return getSwitch(SWSRC_THR+i-MIXSRC_THR) ? 1024 : -1024;
#endif
else if (i<=MIXSRC_LAST_LOGICAL_SWITCH) return getSwitch(SWSRC_FIRST_LOGICAL_SWITCH+i-MIXSRC_FIRST_LOGICAL_SWITCH) ? 1024 : -1024;
else if (i<=MIXSRC_LAST_TRAINER) { int16_t x = g_ppmIns[i-MIXSRC_FIRST_TRAINER]; if (i<MIXSRC_FIRST_TRAINER+NUM_CAL_PPM) { x-= g_eeGeneral.trainer.calib[i-MIXSRC_FIRST_TRAINER]; } return x*2; }
else if (i<=MIXSRC_LAST_TRAINER) { int16_t x = ppmInput[i-MIXSRC_FIRST_TRAINER]; if (i<MIXSRC_FIRST_TRAINER+NUM_CAL_PPM) { x-= g_eeGeneral.trainer.calib[i-MIXSRC_FIRST_TRAINER]; } return x*2; }
else if (i<=MIXSRC_LAST_CH) return ex_chans[i-MIXSRC_CH1];
#if defined(GVARS)
@@ -455,12 +455,12 @@ void evalInputs(uint8_t mode)
}
#endif
if (mode <= e_perout_mode_inactive_flight_mode && isFunctionActive(FUNCTION_TRAINER+ch) && ppmInValid) {
if (mode <= e_perout_mode_inactive_flight_mode && isFunctionActive(FUNCTION_TRAINER+ch) && IS_TRAINER_INPUT_VALID()) {
// trainer mode
TrainerMix* td = &g_eeGeneral.trainer.mix[ch];
if (td->mode) {
uint8_t chStud = td->srcChn;
int32_t vStud = (g_ppmIns[chStud]- g_eeGeneral.trainer.calib[chStud]);
int32_t vStud = (ppmInput[chStud]- g_eeGeneral.trainer.calib[chStud]);
vStud *= td->studWeight;
vStud /= 50;
switch (td->mode) {
@@ -662,7 +662,7 @@ void evalFlightModeMixes(uint8_t mode, uint8_t tick10ms)
#define MIXER_LINE_DISABLE() (mixCondition = true, mixEnabled = 0)
if (mixEnabled && md->srcRaw >= MIXSRC_FIRST_TRAINER && md->srcRaw <= MIXSRC_LAST_TRAINER && !ppmInValid) {
if (mixEnabled && md->srcRaw >= MIXSRC_FIRST_TRAINER && md->srcRaw <= MIXSRC_LAST_TRAINER && !IS_TRAINER_INPUT_VALID()) {
MIXER_LINE_DISABLE();
}
+4 -26
View File
@@ -155,7 +155,7 @@ void per10ms()
#endif
if (trimsCheckTimer) trimsCheckTimer--;
if (ppmInValid) ppmInValid--;
if (ppmInputValidityTimer) ppmInputValidityTimer--;
#if defined(CPUARM)
if (trimsDisplayTimer)
@@ -1714,6 +1714,7 @@ void doMixerCalculations()
s_cnt_1s += 1;
logicalSwitchesTimerTick();
checkTrainerSignalWarning();
if (s_cnt_1s >= 10) { // 1sec
s_cnt_1s -= 10;
@@ -2068,10 +2069,6 @@ void checkBattery()
}
}
int16_t g_ppmIns[NUM_TRAINER];
uint8_t ppmInState = 0; // 0=unsync 1..8= wait for value i-1
uint8_t ppmInValid = 0;
#if !defined(SIMU) && !defined(CPUARM)
volatile uint8_t g_tmr16KHz; //continuous timer 16ms (16MHz/1024/256) -- 8-bit counter overflow
@@ -2153,27 +2150,8 @@ ISR(TIMER3_CAPT_vect) // G: High frequency noise can cause stack overflo with IS
PAUSE_PPMIN_INTERRUPT();
sei(); // enable other interrupts
uint16_t val = (capture - lastCapt) / 2;
// G: We process g_ppmIns immediately here, to make servo movement as smooth as possible
// while under trainee control
if (val>4000 && val < 16000) { // G: Prioritize reset pulse. (Needed when less than 8 incoming pulses)
ppmInState = 1; // triggered
}
else {
if (ppmInState>0 && ppmInState<=8) {
if (val>800 && val<2200) { // if valid pulse-width range
ppmInValid = PPM_IN_VALID_TIMEOUT;
g_ppmIns[ppmInState++ - 1] = (int16_t)(val - 1500) * (uint8_t)(g_eeGeneral.PPM_Multiplier+10)/10; //+-500 != 512, but close enough.
}
else {
ppmInState = 0; // not triggered
}
}
}
lastCapt = capture;
captureTrainerPulses(capture);
cli(); // disable other interrupts for stack pops before this function's RETI
RESUME_PPMIN_INTERRUPT();
}
+4 -4
View File
@@ -1127,10 +1127,8 @@ extern uint8_t g_vbat100mV;
extern uint8_t g_beepCnt;
extern uint8_t g_beepVal[5];
extern uint8_t ppmInState; //0=unsync 1..8= wait for value i-1
extern uint8_t ppmInValid;
#define PPM_IN_VALID_TIMEOUT 100
extern int16_t g_ppmIns[NUM_TRAINER];
#include "trainer_input.h"
extern int32_t chans[NUM_CHNOUT];
extern int16_t ex_chans[NUM_CHNOUT]; // Outputs (before LIMITS) of the last perMain
extern int16_t channelOutputs[NUM_CHNOUT];
@@ -1392,6 +1390,8 @@ enum AUDIO_SOUNDS {
AU_SWR_RED,
AU_TELEMETRY_LOST,
AU_TELEMETRY_BACK,
AU_TRAINER_LOST,
AU_TRAINER_BACK,
#endif
#if defined(PCBSKY9X)
AU_TX_MAH_HIGH,
+2 -2
View File
@@ -87,7 +87,7 @@ void processSbusFrame(uint8_t *sbus, int16_t *pulses, uint32_t size)
inputbits >>= SBUS_CH_BITS;
}
ppmInValid = PPM_IN_VALID_TIMEOUT;
ppmInputValidityTimer = PPM_IN_VALID_TIMEOUT;
}
void processSbusInput()
@@ -108,7 +108,7 @@ void processSbusInput()
else {
if (SbusIndex) {
if ((uint16_t) (getTmr2MHz() - SbusTimer) > SBUS_FRAME_GAP_DELAY) {
processSbusFrame(SbusFrame, g_ppmIns, SbusIndex);
processSbusFrame(SbusFrame, ppmInput, SbusIndex);
SbusIndex = 0;
}
}
+1 -22
View File
@@ -248,31 +248,10 @@ void start_timer4()
extern "C" void TC3_IRQHandler() //capture ppm in at 2MHz
{
static uint16_t lastCapt ;
uint16_t capture = TC1->TC_CHANNEL[0].TC_RA ;
(void) TC1->TC_CHANNEL[0].TC_SR ; // Acknowledge the interrupt
uint16_t val = ((uint16_t)(capture - lastCapt)) / 2;
// G: We process g_ppmIns immediately here, to make servo movement as smooth as possible
// while under trainee control
if (val>4000 && val<19000) { // G: Prioritize reset pulse. (Needed when less than 16 incoming pulses)
ppmInState = 1; // triggered
}
else {
if (ppmInState>0 && ppmInState<=16) {
if (val>800 && val<2200) { // if valid pulse-width range
ppmInValid = PPM_IN_VALID_TIMEOUT;
g_ppmIns[ppmInState++ - 1] = (int16_t)(val - 1500)*(g_eeGeneral.PPM_Multiplier+10)/10; //+-500 != 512, but close enough.
}
else {
ppmInState = 0; // not triggered
}
}
}
lastCapt = capture;
captureTrainerPulses(capture);
}
void init_trainer_capture()
+1 -21
View File
@@ -121,8 +121,6 @@ void stop_trainer_capture()
extern "C" void TIM3_IRQHandler()
{
uint16_t capture = 0;
static uint16_t lastCapt ;
uint16_t val ;
bool doCapture = false ;
// What mode? in or out?
@@ -139,25 +137,7 @@ extern "C" void TIM3_IRQHandler()
}
if (doCapture) {
val = (uint16_t)(capture - lastCapt) / 2 ;
lastCapt = capture;
// We process g_ppmInsright here to make servo movement as smooth as possible
// while under trainee control
if (val>4000 && val<19000) { // G: Prioritize reset pulse. (Needed when less than 16 incoming pulses)
ppmInState = 1; // triggered
}
else {
if (ppmInState>0 && ppmInState<=16) {
if (val>800 && val<2200) {
ppmInValid = PPM_IN_VALID_TIMEOUT;
g_ppmIns[ppmInState++ - 1] = (int16_t)(val - 1500)*(g_eeGeneral.PPM_Multiplier+10)/10; //+-500 != 512, but close enough.
}
else {
ppmInState = 0; // not triggered
}
}
}
captureTrainerPulses(capture);
}
// PPM out compare interrupt
+2 -2
View File
@@ -1019,7 +1019,7 @@ TEST(Trainer, UnpluggedTest)
g_model.mixData[0].weight = 100;
g_model.mixData[0].delayUp = DELAY_STEP*5;
g_model.mixData[0].delayDown = DELAY_STEP*5;
ppmInValid = 0;
g_ppmIns[0] = 1024;
ppmInputValidityTimer = 0;
ppmInput[0] = 1024;
CHECK_DELAY(0, 5000);
}
+69
View File
@@ -0,0 +1,69 @@
/*
* Authors (alphabetical order)
* - Andre Bernet <bernet.andre@gmail.com>
* - Andreas Weitl
* - Bertrand Songis <bsongis@gmail.com>
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
* - Cameron Weeks <th9xer@gmail.com>
* - Erez Raviv
* - Gabriel Birkus
* - Jean-Pierre Parisy
* - Karl Szmutny
* - Michael Blandford
* - Michal Hlavinka
* - Pat Mackenzie
* - Philip Moss
* - Rob Thomson
* - Romolo Manfredini <romolo.manfredini@gmail.com>
* - Thomas Husterer
*
* opentx is based on code named
* gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/,
* er9x by Erez Raviv: http://code.google.com/p/er9x/,
* and the original (and ongoing) project by
* Thomas Husterer, th9x: http://code.google.com/p/th9x/
*
* 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 "trainer_input.h"
int16_t ppmInput[NUM_TRAINER];
uint8_t ppmInputValidityTimer;
#if defined(CPUARM)
#include "audio_arm.h"
void checkTrainerSignalWarning()
{
enum PpmInValidState_t {
PPM_IN_IS_NOT_USED=0,
PPM_IN_IS_VALID,
PPM_IN_INVALID
};
static uint8_t ppmInputValidState = PPM_IN_IS_NOT_USED;
if(ppmInputValidityTimer && (ppmInputValidState == PPM_IN_IS_NOT_USED)) {
ppmInputValidState = PPM_IN_IS_VALID;
}
else if (!ppmInputValidityTimer && (ppmInputValidState == PPM_IN_IS_VALID)) {
ppmInputValidState = PPM_IN_INVALID;
AUDIO_TRAINER_LOST();
}
else if (ppmInputValidityTimer && (ppmInputValidState == PPM_IN_INVALID)) {
ppmInputValidState = PPM_IN_IS_VALID;
AUDIO_TRAINER_BACK();
}
}
#endif
+89
View File
@@ -0,0 +1,89 @@
/*
* Authors (alphabetical order)
* - Andre Bernet <bernet.andre@gmail.com>
* - Andreas Weitl
* - Bertrand Songis <bsongis@gmail.com>
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
* - Cameron Weeks <th9xer@gmail.com>
* - Erez Raviv
* - Gabriel Birkus
* - Jean-Pierre Parisy
* - Karl Szmutny
* - Michael Blandford
* - Michal Hlavinka
* - Pat Mackenzie
* - Philip Moss
* - Rob Thomson
* - Romolo Manfredini <romolo.manfredini@gmail.com>
* - Thomas Husterer
*
* opentx is based on code named
* gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/,
* er9x by Erez Raviv: http://code.google.com/p/er9x/,
* and the original (and ongoing) project by
* Thomas Husterer, th9x: http://code.google.com/p/th9x/
*
* 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 trainer_input_h
#define trainer_input_h
#include "myeeprom.h"
// Trainer input channels
extern int16_t ppmInput[NUM_TRAINER];
// Timer gets decremented in per10ms()
#define PPM_IN_VALID_TIMEOUT 100 // 1s
extern uint8_t ppmInputValidityTimer;
#define IS_TRAINER_INPUT_VALID() (ppmInputValidityTimer != 0)
#if defined(CPUARM)
void checkTrainerSignalWarning();
#else
#define checkTrainerSignalWarning()
#endif
// Needs to be inlined to avoid slow function calls in ISR routines
inline void captureTrainerPulses(uint16_t capture)
{
static uint16_t lastCapt=0;
static uint8_t channelNumber=0;
uint16_t val = (uint16_t)(capture - lastCapt) / 2;
lastCapt = capture;
// We process ppmInput right here to make servo movement as smooth as possible
// while under trainee control
//
// G: Prioritize reset pulse. (Needed when less than 16 incoming pulses)
//
if (val>4000 && val<19000) {
channelNumber = 1; // triggered
}
else {
if ((channelNumber > 0) && (channelNumber <= NUM_TRAINER)) {
if (val>800 && val<2200) {
ppmInputValidityTimer = PPM_IN_VALID_TIMEOUT;
ppmInput[channelNumber++ - 1] =
//+-500 != 512, but close enough.
(int16_t)(val - 1500)*(g_eeGeneral.PPM_Multiplier+10)/10;
}
else {
channelNumber = 0; // not triggered
}
}
}
}
#endif
+9 -1
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python
# -*- coding: utf-8 -*-
@@ -186,6 +186,8 @@ def ttsEn():
(u"radio antenna defective", "swr_red", NO_ALTERNATE),
(u"telemetry lost", "telemko", NO_ALTERNATE),
(u"telemetry recovered", "telemok", NO_ALTERNATE),
(u"trainer signal lost", "trainko", NO_ALTERNATE),
(u"trainer signal recovered", "trainok", NO_ALTERNATE),
]:
systemSounds.append((s, filename(f, a)))
for i, (s, f) in enumerate([
@@ -282,6 +284,8 @@ def ttsFr():
(u"Antenne défectueuse", "swr_red", NO_ALTERNATE),
(u"Plus de télémétrie", "telemko", NO_ALTERNATE),
(u"Télémétrie retrouvée", "telemok", NO_ALTERNATE),
(u"Signal écolage perdu", "trainko", NO_ALTERNATE),
(u"Signal écolage retrouvé", "trainok", NO_ALTERNATE),
]:
systemSounds.append((s, filename(f, a)))
for i, (s, f) in enumerate([
@@ -599,6 +603,10 @@ def ttsDe():
(u"Funksignal schlecht!", "rssi_org", NO_ALTERNATE),
(u"Funksignal kritisch!", "rssi_red", NO_ALTERNATE),
(u"Problem mit der sender Antenna", "swr_red", NO_ALTERNATE),
(u"Telemetrie verloren", "telemko", NO_ALTERNATE),
(u"Telemetrie wiederhergestellt", "telemok", NO_ALTERNATE),
(u"Schülersignal verloren", "trainko", NO_ALTERNATE),
(u"Schülersignal wiederhergestellt", "trainok", NO_ALTERNATE),
]:
systemSounds.append((s, filename(f, a)))
for i, s in enumerate(["Timer", "Timer", "Sendung", "Empfang", "A1", "A2", "Hoehe", "Motor",