1
0
Fork 0
mirror of https://github.com/opentx/opentx.git synced 2025-07-23 16:25:16 +03:00

Fixes #2009: Timer Voice minute call not working for persistent timers

Timers moved to timer.cpp
Added timer overflow protection
Added timer gtests
THt mode now triggers on THR>10%
This commit is contained in:
Damjan Adamic 2015-01-29 19:26:54 +01:00
parent 76937ea566
commit afc41f082e
25 changed files with 4001 additions and 3563 deletions

View file

@ -15,13 +15,13 @@
*/ */
#include "stdio.h" #include <stdio.h>
#include "inttypes.h" #include <inttypes.h>
#include "string.h" #include <string.h>
#include "file.h"
#include <assert.h> #include <assert.h>
#include <algorithm> #include <algorithm>
#include "eeprominterface.h" #include "eeprominterface.h"
#include "file.h"
RleFile::RleFile(): RleFile::RleFile():
eeprom(NULL), eeprom(NULL),

View file

@ -71,6 +71,7 @@ namespace Open9xGruvin9x {
#include "radio/src/functions.cpp" #include "radio/src/functions.cpp"
#include "radio/src/curves.cpp" #include "radio/src/curves.cpp"
#include "radio/src/mixer.cpp" #include "radio/src/mixer.cpp"
#include "radio/src/timers.cpp"
#include "radio/src/pulses/pulses_avr.cpp" #include "radio/src/pulses/pulses_avr.cpp"
#include "radio/src/stamp.cpp" #include "radio/src/stamp.cpp"
#include "radio/src/maths.cpp" #include "radio/src/maths.cpp"

View file

@ -72,6 +72,7 @@ namespace OpenTxM128 {
#include "radio/src/functions.cpp" #include "radio/src/functions.cpp"
#include "radio/src/curves.cpp" #include "radio/src/curves.cpp"
#include "radio/src/mixer.cpp" #include "radio/src/mixer.cpp"
#include "radio/src/timers.cpp"
#include "radio/src/pulses/pulses_avr.cpp" #include "radio/src/pulses/pulses_avr.cpp"
#include "radio/src/stamp.cpp" #include "radio/src/stamp.cpp"
#include "radio/src/maths.cpp" #include "radio/src/maths.cpp"

View file

@ -75,6 +75,7 @@ namespace OpenTxM64 {
#include "radio/src/functions.cpp" #include "radio/src/functions.cpp"
#include "radio/src/curves.cpp" #include "radio/src/curves.cpp"
#include "radio/src/mixer.cpp" #include "radio/src/mixer.cpp"
#include "radio/src/timers.cpp"
#include "radio/src/pulses/pulses_avr.cpp" #include "radio/src/pulses/pulses_avr.cpp"
#include "radio/src/stamp.cpp" #include "radio/src/stamp.cpp"
#include "radio/src/maths.cpp" #include "radio/src/maths.cpp"

View file

@ -83,6 +83,7 @@ namespace Open9xSky9x {
#include "radio/src/switches.cpp" #include "radio/src/switches.cpp"
#include "radio/src/functions.cpp" #include "radio/src/functions.cpp"
#include "radio/src/mixer.cpp" #include "radio/src/mixer.cpp"
#include "radio/src/timers.cpp"
#include "radio/src/curves.cpp" #include "radio/src/curves.cpp"
#include "radio/src/targets/sky9x/pulses_driver.cpp" #include "radio/src/targets/sky9x/pulses_driver.cpp"
#include "radio/src/pulses/pulses_arm.cpp" #include "radio/src/pulses/pulses_arm.cpp"

View file

@ -87,6 +87,7 @@ inline int geteepromsize() {
#include "radio/src/curves.cpp" #include "radio/src/curves.cpp"
#include "radio/src/mixer.cpp" #include "radio/src/mixer.cpp"
#include "radio/src/sdcard.cpp" #include "radio/src/sdcard.cpp"
#include "radio/src/timers.cpp"
#include "radio/src/targets/taranis/pulses_driver.cpp" #include "radio/src/targets/taranis/pulses_driver.cpp"
#include "radio/src/targets/taranis/rtc_driver.cpp" #include "radio/src/targets/taranis/rtc_driver.cpp"
#include "radio/src/targets/taranis/trainer_driver.cpp" #include "radio/src/targets/taranis/trainer_driver.cpp"

View file

@ -88,6 +88,7 @@ inline int geteepromsize() {
#include "radio/src/curves.cpp" #include "radio/src/curves.cpp"
#include "radio/src/mixer.cpp" #include "radio/src/mixer.cpp"
#include "radio/src/sdcard.cpp" #include "radio/src/sdcard.cpp"
#include "radio/src/timers.cpp"
#include "radio/src/targets/taranis/pulses_driver.cpp" #include "radio/src/targets/taranis/pulses_driver.cpp"
#include "radio/src/targets/taranis/rtc_driver.cpp" #include "radio/src/targets/taranis/rtc_driver.cpp"
#include "radio/src/targets/taranis/rotenc_driver.cpp" #include "radio/src/targets/taranis/rotenc_driver.cpp"

View file

@ -954,7 +954,7 @@ ifeq ($(GUI), YES)
CPPDEFS += -DGUI CPPDEFS += -DGUI
endif endif
CPPSRC += opentx.cpp functions.cpp strhelpers.cpp $(PULSESSRC) switches.cpp curves.cpp mixer.cpp stamp.cpp $(GUISRC) $(EEPROMSRC) CPPSRC += opentx.cpp functions.cpp strhelpers.cpp $(PULSESSRC) switches.cpp curves.cpp mixer.cpp stamp.cpp $(GUISRC) $(EEPROMSRC) timers.cpp
ifeq ($(GUI), YES) ifeq ($(GUI), YES)
GUISRC += gui/$(GUIDIRECTORY)/lcd.cpp gui/$(GUIDIRECTORY)/splash.cpp gui/$(GUIDIRECTORY)/fonts.cpp GUISRC += gui/$(GUIDIRECTORY)/lcd.cpp gui/$(GUIDIRECTORY)/splash.cpp gui/$(GUIDIRECTORY)/fonts.cpp

View file

@ -285,7 +285,7 @@ const struct TraceElement * getTraceElement(uint16_t idx)
void dumpTraceBuffer() void dumpTraceBuffer()
{ {
TRACE("Dump of Trace Buffer ("VERS_STR " " DATE_STR " " TIME_STR "):"); TRACE("Dump of Trace Buffer (" VERS_STR " " DATE_STR " " TIME_STR "):");
TRACE("# Time Event Data"); TRACE("# Time Event Data");
for(int n = 0; n < TRACE_BUFFER_LEN; ++n) { for(int n = 0; n < TRACE_BUFFER_LEN; ++n) {
struct gtm tp; struct gtm tp;

View file

@ -35,9 +35,10 @@
*/ */
#include <stdint.h> #include <stdint.h>
#include <inttypes.h>
#include <string.h>
#include "opentx.h" #include "opentx.h"
#include "inttypes.h" #include "timers.h"
#include "string.h"
uint8_t s_eeDirtyMsk; uint8_t s_eeDirtyMsk;
tmr10ms_t s_eeDirtyTime10ms; tmr10ms_t s_eeDirtyTime10ms;

View file

@ -35,9 +35,10 @@
*/ */
#include <stdint.h> #include <stdint.h>
#include <inttypes.h>
#include <string.h>
#include "opentx.h" #include "opentx.h"
#include "inttypes.h" #include "timers.h"
#include "string.h"
volatile uint32_t Spi_complete; // TODO in the driver ? volatile uint32_t Spi_complete; // TODO in the driver ?
@ -396,11 +397,7 @@ void eeLoadModel(uint8_t id)
customFunctionsReset(); customFunctionsReset();
for (uint8_t i=0; i<MAX_TIMERS; i++) { restoreTimers();
if (g_model.timers[i].persistent) {
timersStates[i].val = g_model.timers[i].value;
}
}
resumeMixerCalculations(); resumeMixerCalculations();
// TODO pulses should be started after mixer calculations ... // TODO pulses should be started after mixer calculations ...

View file

@ -34,9 +34,10 @@
* *
*/ */
#include <inttypes.h>
#include <string.h>
#include "opentx.h" #include "opentx.h"
#include "inttypes.h" #include "timers.h"
#include "string.h"
uint8_t s_write_err = 0; // error reasons uint8_t s_write_err = 0; // error reasons
RlcFile theFile; //used for any file operation RlcFile theFile; //used for any file operation
@ -985,13 +986,7 @@ void eeLoadModel(uint8_t id)
customFunctionsReset(); customFunctionsReset();
#if !defined(PCBSTD) restoreTimers();
for (uint8_t i=0; i<MAX_TIMERS; i++) {
if (g_model.timers[i].persistent) {
timersStates[i].val = g_model.timers[i].value;
}
}
#endif
#if defined(CPUARM) #if defined(CPUARM)
for (int i=0; i<TELEM_VALUES_MAX; i++) { for (int i=0; i<TELEM_VALUES_MAX; i++) {

View file

@ -35,6 +35,7 @@
*/ */
#include "opentx.h" #include "opentx.h"
#include "timers.h"
CustomFunctionsContext modelFunctionsContext = { 0 }; CustomFunctionsContext modelFunctionsContext = { 0 };
@ -359,10 +360,7 @@ void evalFunctions()
#if defined(CPUARM) #if defined(CPUARM)
case FUNC_SET_TIMER: case FUNC_SET_TIMER:
{ {
TimerState & timerState = timersStates[CFN_TIMER_INDEX(cfn)]; timerSet(CFN_TIMER_INDEX(cfn), CFN_PARAM(cfn));
timerState.state = TMR_OFF; // is changed to RUNNING dep from mode
timerState.val = CFN_PARAM(cfn);
timerState.val_10ms = 0 ;
break; break;
} }
#endif #endif

File diff suppressed because it is too large Load diff

View file

@ -1,224 +1,225 @@
/* /*
* Authors (alphabetical order) * Authors (alphabetical order)
* - Andre Bernet <bernet.andre@gmail.com> * - Andre Bernet <bernet.andre@gmail.com>
* - Andreas Weitl * - Andreas Weitl
* - Bertrand Songis <bsongis@gmail.com> * - Bertrand Songis <bsongis@gmail.com>
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com> * - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
* - Cameron Weeks <th9xer@gmail.com> * - Cameron Weeks <th9xer@gmail.com>
* - Erez Raviv * - Erez Raviv
* - Gabriel Birkus * - Gabriel Birkus
* - Jean-Pierre Parisy * - Jean-Pierre Parisy
* - Karl Szmutny * - Karl Szmutny
* - Michael Blandford * - Michael Blandford
* - Michal Hlavinka * - Michal Hlavinka
* - Pat Mackenzie * - Pat Mackenzie
* - Philip Moss * - Philip Moss
* - Rob Thomson * - Rob Thomson
* - Romolo Manfredini <romolo.manfredini@gmail.com> * - Romolo Manfredini <romolo.manfredini@gmail.com>
* - Thomas Husterer * - Thomas Husterer
* *
* opentx is based on code named * opentx is based on code named
* gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/, * gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/,
* er9x by Erez Raviv: http://code.google.com/p/er9x/, * er9x by Erez Raviv: http://code.google.com/p/er9x/,
* and the original (and ongoing) project by * and the original (and ongoing) project by
* Thomas Husterer, th9x: http://code.google.com/p/th9x/ * Thomas Husterer, th9x: http://code.google.com/p/th9x/
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
*/ */
#include "../../opentx.h" #include "../../opentx.h"
#include "../../timers.h"
void menuStatisticsView(uint8_t event)
{ void menuStatisticsView(uint8_t event)
TITLE(STR_MENUSTAT); {
TITLE(STR_MENUSTAT);
switch(event)
{ switch(event)
case EVT_KEY_FIRST(KEY_UP): {
chainMenu(menuStatisticsDebug); case EVT_KEY_FIRST(KEY_UP):
break; chainMenu(menuStatisticsDebug);
break;
#if defined(CPUARM)
case EVT_KEY_LONG(KEY_MENU): #if defined(CPUARM)
g_eeGeneral.globalTimer = 0; case EVT_KEY_LONG(KEY_MENU):
eeDirty(EE_GENERAL); g_eeGeneral.globalTimer = 0;
sessionTimer = 0; eeDirty(EE_GENERAL);
break; sessionTimer = 0;
#endif break;
case EVT_KEY_FIRST(KEY_EXIT): #endif
chainMenu(menuMainView); case EVT_KEY_FIRST(KEY_EXIT):
break; chainMenu(menuMainView);
} break;
}
lcd_puts( 1*FW, FH*0, STR_TOTTM1TM2THRTHP);
putsTimer( 5*FW+5*FWNUM+1, FH*1, timersStates[0].val, 0, 0); lcd_puts( 1*FW, FH*0, STR_TOTTM1TM2THRTHP);
putsTimer( 12*FW+5*FWNUM+1, FH*1, timersStates[1].val, 0, 0); putsTimer( 5*FW+5*FWNUM+1, FH*1, timersStates[0].val, 0, 0);
putsTimer( 12*FW+5*FWNUM+1, FH*1, timersStates[1].val, 0, 0);
putsTimer( 5*FW+5*FWNUM+1, FH*2, s_timeCumThr, 0, 0);
putsTimer( 12*FW+5*FWNUM+1, FH*2, s_timeCum16ThrP/16, 0, 0); putsTimer( 5*FW+5*FWNUM+1, FH*2, s_timeCumThr, 0, 0);
putsTimer( 12*FW+5*FWNUM+1, FH*2, s_timeCum16ThrP/16, 0, 0);
putsTimer( 12*FW+5*FWNUM+1, FH*0, sessionTimer, 0, 0);
putsTimer( 12*FW+5*FWNUM+1, FH*0, sessionTimer, 0, 0);
#if defined(CPUARM)
putsTimer(21*FW+5*FWNUM+1, 0*FH, g_eeGeneral.globalTimer + sessionTimer, TIMEHOUR, 0); #if defined(CPUARM)
#endif putsTimer(21*FW+5*FWNUM+1, 0*FH, g_eeGeneral.globalTimer + sessionTimer, TIMEHOUR, 0);
#endif
#if defined(THRTRACE)
coord_t traceRd = (s_traceCnt < 0 ? s_traceWr : 0); #if defined(THRTRACE)
const coord_t x = 5; coord_t traceRd = (s_traceCnt < 0 ? s_traceWr : 0);
const coord_t y = 60; const coord_t x = 5;
lcd_hline(x-3, y, MAXTRACE+3+3); const coord_t y = 60;
lcd_vline(x, y-32, 32+3); lcd_hline(x-3, y, MAXTRACE+3+3);
lcd_vline(x, y-32, 32+3);
for (coord_t i=0; i<MAXTRACE; i+=6) {
lcd_vline(x+i+6, y-1, 3); for (coord_t i=0; i<MAXTRACE; i+=6) {
} lcd_vline(x+i+6, y-1, 3);
for (coord_t i=1; i<=MAXTRACE; i++) { }
lcd_vline(x+i, y-s_traceBuf[traceRd], s_traceBuf[traceRd]); for (coord_t i=1; i<=MAXTRACE; i++) {
traceRd++; lcd_vline(x+i, y-s_traceBuf[traceRd], s_traceBuf[traceRd]);
if (traceRd>=MAXTRACE) traceRd = 0; traceRd++;
if (traceRd==s_traceWr) break; if (traceRd>=MAXTRACE) traceRd = 0;
} if (traceRd==s_traceWr) break;
#endif }
} #endif
}
#if defined(PCBSKY9X)
#define MENU_DEBUG_COL1_OFS (11*FW-3) #if defined(PCBSKY9X)
#define MENU_DEBUG_COL2_OFS (17*FW) #define MENU_DEBUG_COL1_OFS (11*FW-3)
#define MENU_DEBUG_Y_CURRENT (1*FH) #define MENU_DEBUG_COL2_OFS (17*FW)
#define MENU_DEBUG_Y_MAH (2*FH) #define MENU_DEBUG_Y_CURRENT (1*FH)
#define MENU_DEBUG_Y_CPU_TEMP (3*FH) #define MENU_DEBUG_Y_MAH (2*FH)
#define MENU_DEBUG_Y_COPROC (4*FH) #define MENU_DEBUG_Y_CPU_TEMP (3*FH)
#define MENU_DEBUG_Y_MIXMAX (5*FH) #define MENU_DEBUG_Y_COPROC (4*FH)
#define MENU_DEBUG_Y_RTOS (6*FH) #define MENU_DEBUG_Y_MIXMAX (5*FH)
#else #define MENU_DEBUG_Y_RTOS (6*FH)
#define MENU_DEBUG_COL1_OFS (14*FW) #else
#endif #define MENU_DEBUG_COL1_OFS (14*FW)
#endif
void menuStatisticsDebug(uint8_t event)
{ void menuStatisticsDebug(uint8_t event)
TITLE(STR_MENUDEBUG); {
TITLE(STR_MENUDEBUG);
switch(event)
{ switch(event)
#if defined(CPUARM) {
case EVT_KEY_LONG(KEY_ENTER): #if defined(CPUARM)
g_eeGeneral.mAhUsed = 0; case EVT_KEY_LONG(KEY_ENTER):
g_eeGeneral.globalTimer = 0; g_eeGeneral.mAhUsed = 0;
eeDirty(EE_GENERAL); g_eeGeneral.globalTimer = 0;
#if defined(PCBSKY9X) eeDirty(EE_GENERAL);
Current_used = 0; #if defined(PCBSKY9X)
#endif Current_used = 0;
sessionTimer = 0; #endif
killEvents(event); sessionTimer = 0;
AUDIO_KEYPAD_UP(); killEvents(event);
break; AUDIO_KEYPAD_UP();
#endif break;
case EVT_KEY_FIRST(KEY_ENTER): #endif
#if !defined(CPUARM) case EVT_KEY_FIRST(KEY_ENTER):
g_tmr1Latency_min = 0xff; #if !defined(CPUARM)
g_tmr1Latency_max = 0; g_tmr1Latency_min = 0xff;
#endif g_tmr1Latency_max = 0;
maxMixerDuration = 0; #endif
AUDIO_KEYPAD_UP(); maxMixerDuration = 0;
break; AUDIO_KEYPAD_UP();
break;
#if defined(DEBUG_TRACE_BUFFER)
case EVT_KEY_FIRST(KEY_UP): #if defined(DEBUG_TRACE_BUFFER)
pushMenu(menuTraceBuffer); case EVT_KEY_FIRST(KEY_UP):
return; pushMenu(menuTraceBuffer);
#endif return;
#endif
case EVT_KEY_FIRST(KEY_DOWN):
chainMenu(menuStatisticsView); case EVT_KEY_FIRST(KEY_DOWN):
break; chainMenu(menuStatisticsView);
case EVT_KEY_FIRST(KEY_EXIT): break;
chainMenu(menuMainView); case EVT_KEY_FIRST(KEY_EXIT):
break; chainMenu(menuMainView);
} break;
}
#if defined(PCBSKY9X)
if ((ResetReason&RSTC_SR_RSTTYP) == (2<<8)) { #if defined(PCBSKY9X)
lcd_puts(LCD_W-8*FW, 0*FH, "WATCHDOG"); if ((ResetReason&RSTC_SR_RSTTYP) == (2<<8)) {
} lcd_puts(LCD_W-8*FW, 0*FH, "WATCHDOG");
else if (unexpectedShutdown) { }
lcd_puts(LCD_W-13*FW, 0*FH, "UNEXP.SHTDOWN"); else if (unexpectedShutdown) {
} lcd_puts(LCD_W-13*FW, 0*FH, "UNEXP.SHTDOWN");
#endif }
#endif
#if defined(PCBSKY9X) && !defined(REVA)
// current #if defined(PCBSKY9X) && !defined(REVA)
lcd_putsLeft(MENU_DEBUG_Y_CURRENT, STR_CPU_CURRENT); // current
putsValueWithUnit(MENU_DEBUG_COL1_OFS, MENU_DEBUG_Y_CURRENT, getCurrent(), UNIT_MILLIAMPS, LEFT); lcd_putsLeft(MENU_DEBUG_Y_CURRENT, STR_CPU_CURRENT);
uint32_t current_scale = 488 + g_eeGeneral.currentCalib; putsValueWithUnit(MENU_DEBUG_COL1_OFS, MENU_DEBUG_Y_CURRENT, getCurrent(), UNIT_MILLIAMPS, LEFT);
lcd_putc(MENU_DEBUG_COL2_OFS, MENU_DEBUG_Y_CURRENT, '>'); uint32_t current_scale = 488 + g_eeGeneral.currentCalib;
putsValueWithUnit(MENU_DEBUG_COL2_OFS+FW+1, MENU_DEBUG_Y_CURRENT, Current_max*10*current_scale/8192, UNIT_RAW, LEFT); lcd_putc(MENU_DEBUG_COL2_OFS, MENU_DEBUG_Y_CURRENT, '>');
// consumption putsValueWithUnit(MENU_DEBUG_COL2_OFS+FW+1, MENU_DEBUG_Y_CURRENT, Current_max*10*current_scale/8192, UNIT_RAW, LEFT);
lcd_putsLeft(MENU_DEBUG_Y_MAH, STR_CPU_MAH); // consumption
putsValueWithUnit(MENU_DEBUG_COL1_OFS, MENU_DEBUG_Y_MAH, g_eeGeneral.mAhUsed + Current_used*current_scale/8192/36, UNIT_MAH, LEFT|PREC1); lcd_putsLeft(MENU_DEBUG_Y_MAH, STR_CPU_MAH);
#endif putsValueWithUnit(MENU_DEBUG_COL1_OFS, MENU_DEBUG_Y_MAH, g_eeGeneral.mAhUsed + Current_used*current_scale/8192/36, UNIT_MAH, LEFT|PREC1);
#endif
#if defined(PCBSKY9X)
lcd_putsLeft(MENU_DEBUG_Y_CPU_TEMP, STR_CPU_TEMP); #if defined(PCBSKY9X)
putsValueWithUnit(MENU_DEBUG_COL1_OFS, MENU_DEBUG_Y_CPU_TEMP, getTemperature(), UNIT_TEMPERATURE, LEFT); lcd_putsLeft(MENU_DEBUG_Y_CPU_TEMP, STR_CPU_TEMP);
lcd_putc(MENU_DEBUG_COL2_OFS, MENU_DEBUG_Y_CPU_TEMP, '>'); putsValueWithUnit(MENU_DEBUG_COL1_OFS, MENU_DEBUG_Y_CPU_TEMP, getTemperature(), UNIT_TEMPERATURE, LEFT);
putsValueWithUnit(MENU_DEBUG_COL2_OFS+FW+1, MENU_DEBUG_Y_CPU_TEMP, maxTemperature+g_eeGeneral.temperatureCalib, UNIT_TEMPERATURE, LEFT); lcd_putc(MENU_DEBUG_COL2_OFS, MENU_DEBUG_Y_CPU_TEMP, '>');
#endif putsValueWithUnit(MENU_DEBUG_COL2_OFS+FW+1, MENU_DEBUG_Y_CPU_TEMP, maxTemperature+g_eeGeneral.temperatureCalib, UNIT_TEMPERATURE, LEFT);
#endif
#if defined(COPROCESSOR)
lcd_putsLeft(MENU_DEBUG_Y_COPROC, STR_COPROC_TEMP); #if defined(COPROCESSOR)
lcd_putsLeft(MENU_DEBUG_Y_COPROC, STR_COPROC_TEMP);
if (Coproc_read==0) {
lcd_putsAtt(MENU_DEBUG_COL1_OFS, MENU_DEBUG_Y_COPROC, PSTR("Co Proc NACK"),INVERS); if (Coproc_read==0) {
} lcd_putsAtt(MENU_DEBUG_COL1_OFS, MENU_DEBUG_Y_COPROC, PSTR("Co Proc NACK"),INVERS);
else if (Coproc_read==0x81) { }
lcd_putsAtt(MENU_DEBUG_COL1_OFS, MENU_DEBUG_Y_COPROC, PSTR("Inst.TinyApp"),INVERS); else if (Coproc_read==0x81) {
} lcd_putsAtt(MENU_DEBUG_COL1_OFS, MENU_DEBUG_Y_COPROC, PSTR("Inst.TinyApp"),INVERS);
else if (Coproc_read<3) { }
lcd_putsAtt(MENU_DEBUG_COL1_OFS, MENU_DEBUG_Y_COPROC, PSTR("Upgr.TinyApp"),INVERS); else if (Coproc_read<3) {
} lcd_putsAtt(MENU_DEBUG_COL1_OFS, MENU_DEBUG_Y_COPROC, PSTR("Upgr.TinyApp"),INVERS);
else { }
putsValueWithUnit(MENU_DEBUG_COL1_OFS, MENU_DEBUG_Y_COPROC, Coproc_temp, UNIT_TEMPERATURE, LEFT); else {
putsValueWithUnit(MENU_DEBUG_COL2_OFS, MENU_DEBUG_Y_COPROC, Coproc_maxtemp, UNIT_TEMPERATURE, LEFT); putsValueWithUnit(MENU_DEBUG_COL1_OFS, MENU_DEBUG_Y_COPROC, Coproc_temp, UNIT_TEMPERATURE, LEFT);
} putsValueWithUnit(MENU_DEBUG_COL2_OFS, MENU_DEBUG_Y_COPROC, Coproc_maxtemp, UNIT_TEMPERATURE, LEFT);
#endif }
#endif
#if defined(CPUARM)
lcd_putsLeft(MENU_DEBUG_Y_MIXMAX, STR_TMIXMAXMS); #if defined(CPUARM)
lcd_outdezAtt(MENU_DEBUG_COL1_OFS, MENU_DEBUG_Y_MIXMAX, DURATION_MS_PREC2(maxMixerDuration), PREC2|LEFT); lcd_putsLeft(MENU_DEBUG_Y_MIXMAX, STR_TMIXMAXMS);
lcd_puts(lcdLastPos, MENU_DEBUG_Y_MIXMAX, "ms"); lcd_outdezAtt(MENU_DEBUG_COL1_OFS, MENU_DEBUG_Y_MIXMAX, DURATION_MS_PREC2(maxMixerDuration), PREC2|LEFT);
#endif lcd_puts(lcdLastPos, MENU_DEBUG_Y_MIXMAX, "ms");
#endif
#if defined(PCBSKY9X)
lcd_putsLeft(MENU_DEBUG_Y_RTOS, STR_FREESTACKMINB); #if defined(PCBSKY9X)
lcd_outdezAtt(MENU_DEBUG_COL1_OFS, MENU_DEBUG_Y_RTOS, stack_free(0), UNSIGN|LEFT); lcd_putsLeft(MENU_DEBUG_Y_RTOS, STR_FREESTACKMINB);
lcd_puts(lcdLastPos, MENU_DEBUG_Y_RTOS, "/"); lcd_outdezAtt(MENU_DEBUG_COL1_OFS, MENU_DEBUG_Y_RTOS, stack_free(0), UNSIGN|LEFT);
lcd_outdezAtt(lcdLastPos, MENU_DEBUG_Y_RTOS, stack_free(1), UNSIGN|LEFT); lcd_puts(lcdLastPos, MENU_DEBUG_Y_RTOS, "/");
lcd_puts(lcdLastPos, MENU_DEBUG_Y_RTOS, "/"); lcd_outdezAtt(lcdLastPos, MENU_DEBUG_Y_RTOS, stack_free(1), UNSIGN|LEFT);
lcd_outdezAtt(lcdLastPos, MENU_DEBUG_Y_RTOS, stack_free(2), UNSIGN|LEFT); lcd_puts(lcdLastPos, MENU_DEBUG_Y_RTOS, "/");
#endif lcd_outdezAtt(lcdLastPos, MENU_DEBUG_Y_RTOS, stack_free(2), UNSIGN|LEFT);
#endif
#if !defined(CPUARM)
lcd_putsLeft(1*FH, STR_TMR1LATMAXUS); #if !defined(CPUARM)
lcd_outdez8(MENU_DEBUG_COL1_OFS , 1*FH, g_tmr1Latency_max/2 ); lcd_putsLeft(1*FH, STR_TMR1LATMAXUS);
lcd_putsLeft(2*FH, STR_TMR1LATMINUS); lcd_outdez8(MENU_DEBUG_COL1_OFS , 1*FH, g_tmr1Latency_max/2 );
lcd_outdez8(MENU_DEBUG_COL1_OFS , 2*FH, g_tmr1Latency_min/2 ); lcd_putsLeft(2*FH, STR_TMR1LATMINUS);
lcd_putsLeft(3*FH, STR_TMR1JITTERUS); lcd_outdez8(MENU_DEBUG_COL1_OFS , 2*FH, g_tmr1Latency_min/2 );
lcd_outdez8(MENU_DEBUG_COL1_OFS , 3*FH, (g_tmr1Latency_max - g_tmr1Latency_min) /2 ); lcd_putsLeft(3*FH, STR_TMR1JITTERUS);
lcd_putsLeft(4*FH, STR_TMIXMAXMS); lcd_outdez8(MENU_DEBUG_COL1_OFS , 3*FH, (g_tmr1Latency_max - g_tmr1Latency_min) /2 );
lcd_outdezAtt(MENU_DEBUG_COL1_OFS, 4*FH, DURATION_MS_PREC2(maxMixerDuration), PREC2); lcd_putsLeft(4*FH, STR_TMIXMAXMS);
lcd_putsLeft(5*FH, STR_FREESTACKMINB); lcd_outdezAtt(MENU_DEBUG_COL1_OFS, 4*FH, DURATION_MS_PREC2(maxMixerDuration), PREC2);
lcd_outdezAtt(14*FW, 5*FH, stack_free(), UNSIGN) ; lcd_putsLeft(5*FH, STR_FREESTACKMINB);
#endif lcd_outdezAtt(14*FW, 5*FH, stack_free(), UNSIGN) ;
#endif
lcd_puts(3*FW, 7*FH+1, STR_MENUTORESET);
lcd_status_line(); lcd_puts(3*FW, 7*FH+1, STR_MENUTORESET);
} lcd_status_line();
}

View file

@ -35,6 +35,7 @@
*/ */
#include "opentx.h" #include "opentx.h"
#include "timers.h"
#if defined(REVPLUS) && defined(LCD_DUAL_BUFFER) #if defined(REVPLUS) && defined(LCD_DUAL_BUFFER)
display_t displayBuf1[DISPLAY_BUF_SIZE]; display_t displayBuf1[DISPLAY_BUF_SIZE];

View file

@ -35,6 +35,7 @@
*/ */
#include "../../opentx.h" #include "../../opentx.h"
#include "../../timers.h"
#define BIGSIZE MIDSIZE #define BIGSIZE MIDSIZE
#define LBOX_CENTERX (BOX_WIDTH/2 + 17) #define LBOX_CENTERX (BOX_WIDTH/2 + 17)

View file

@ -35,6 +35,7 @@
*/ */
#include "../../opentx.h" #include "../../opentx.h"
#include "../../timers.h"
void menuStatisticsView(uint8_t event) void menuStatisticsView(uint8_t event)
{ {

View file

@ -39,6 +39,7 @@
#include "opentx.h" #include "opentx.h"
#include "stamp-opentx.h" #include "stamp-opentx.h"
#include "bin_allocator.h" #include "bin_allocator.h"
#include "timers.h"
#if !defined(SIMU) #if !defined(SIMU)
extern "C" { extern "C" {

View file

@ -35,6 +35,7 @@
*/ */
#include "opentx.h" #include "opentx.h"
#include "timers.h"
#if defined(PCBTARANIS) #if defined(PCBTARANIS)
int8_t virtualInputsTrims[NUM_INPUTS]; int8_t virtualInputsTrims[NUM_INPUTS];

File diff suppressed because it is too large Load diff

View file

@ -270,6 +270,15 @@
#define convertSimuPath(x) (x) #define convertSimuPath(x) (x)
#endif #endif
#if !defined(CPUM64) && !defined(ACCURAT_THROTTLE_TIMER)
// code cost is about 16 bytes for higher throttle accuracy for timer
// would not be noticable anyway, because all version up to this change had only 16 steps;
// now it has already 32 steps; this define would increase to 128 steps
#if !defined(ACCURAT_THROTTLE_TIMER)
#define ACCURAT_THROTTLE_TIMER
#endif
#endif
// RESX range is used for internal calculation; The menu says -100.0 to 100.0; internally it is -1024 to 1024 to allow some optimizations // RESX range is used for internal calculation; The menu says -100.0 to 100.0; internally it is -1024 to 1024 to allow some optimizations
#define RESX_SHIFT 10 #define RESX_SHIFT 10
#define RESX 1024 #define RESX 1024
@ -867,16 +876,6 @@ extern uint16_t sessionTimer;
extern uint16_t s_timeCumThr; extern uint16_t s_timeCumThr;
extern uint16_t s_timeCum16ThrP; extern uint16_t s_timeCum16ThrP;
struct TimerState {
uint16_t cnt;
uint16_t sum;
uint8_t state;
int16_t val;
uint8_t val_10ms;
};
extern TimerState timersStates[MAX_TIMERS];
#if defined(OVERRIDE_CHANNEL_FUNCTION) #if defined(OVERRIDE_CHANNEL_FUNCTION)
#if defined(CPUARM) #if defined(CPUARM)
typedef int16_t safetych_t; typedef int16_t safetych_t;
@ -895,12 +894,6 @@ extern uint8_t trimsDisplayTimer;
extern uint8_t trimsDisplayMask; extern uint8_t trimsDisplayMask;
#endif #endif
#define TMR_OFF 0
#define TMR_RUNNING 1
#define TMR_NEGATIVE 2
#define TMR_STOPPED 3
#define TMR_TRIGGED 4
void timerReset(uint8_t idx);
void flightReset(); void flightReset();
extern uint8_t unexpectedShutdown; extern uint8_t unexpectedShutdown;
@ -1068,12 +1061,6 @@ inline void resumeMixerCalculations()
#define resumeMixerCalculations() #define resumeMixerCalculations()
#endif #endif
#if defined(CPUARM) || defined(CPUM2560)
void saveTimers();
#else
#define saveTimers()
#endif
void generalDefault(); void generalDefault();
void modelDefault(uint8_t id); void modelDefault(uint8_t id);

284
radio/src/tests/timers.cpp Normal file
View file

@ -0,0 +1,284 @@
/*
* 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 "gtests.h"
#include "opentx.h"
#include "timers.h"
/*
struct TimerState {
uint16_t cnt;
uint16_t sum;
uint8_t state;
int16_t val;
uint8_t val_10ms;
};
PACK(typedef struct t_TimerData {
int8_t mode; // timer trigger source -> off, abs, stk, stk%, sw/!sw, !m_sw/!m_sw
uint16_t start;
uint8_t countdownBeep:2;
uint8_t minuteBeep:1;
uint8_t persistent:2; // 0 off, 1 flight, 2 manual reset
uint8_t spare:3;
uint16_t value;
}) TimerData;
enum TimerModes {
TMRMODE_NONE,
TMRMODE_ABS,
TMRMODE_THR,
TMRMODE_THR_REL,
TMRMODE_THR_TRG,
TMRMODE_COUNT
};
enum CountDownModes {
COUNTDOWN_SILENT,
COUNTDOWN_BEEPS,
COUNTDOWN_VOICE
};
*/
#if !defined(CPUARM)
#undef timerSet
void timerSet(int idx, int16_t val)
{
TimerState & timerState = timersStates[idx];
timerState.state = TMR_OFF; // is changed to RUNNING dep from mode
timerState.val = val;
timerState.val_10ms = 0 ;
}
#endif // #if !defined(CPUARM)
#if defined(ACCURAT_THROTTLE_TIMER)
#define THR_100 128 // approximately 10% full throttle
#define THR_50 64 // approximately 10% full throttle
#define THR_10 13 // approximately 10% full throttle
#else
#define THR_100 32 // approximately 10% full throttle
#define THR_50 16 // approximately 10% full throttle
#define THR_10 3 // approximately 10% full throttle
#endif
#define TEST_AB_EQUAL(a, b) if (a != b) { return ::testing::AssertionFailure() << \
#a "= " << (uint32_t)a << ", " << #b "= " << (uint32_t)b; };
void initModelTimer(uint32_t idx, uint8_t mode, int16_t start = 0)
{
g_model.timers[0].mode = mode;
g_model.timers[0].start = start;
g_model.timers[0].countdownBeep = COUNTDOWN_SILENT;
g_model.timers[0].minuteBeep = 0;
g_model.timers[0].spare = 0;
#if defined(CPUARM) || defined(CPUM2560)
g_model.timers[0].persistent = 0;
g_model.timers[0].value = 0;
#endif
}
/*
Run timers for n seconds and test the end state
*/
::testing::AssertionResult evalTimersForNSecondsAndTest(unsigned int n, uint8_t throttle, uint32_t idx, uint8_t state, int16_t value)
{
unsigned int noLoops = n * 100;
while(noLoops--)
{
evalTimers(throttle, 1);
}
TEST_AB_EQUAL(timersStates[idx].state, state);
TEST_AB_EQUAL(timersStates[idx].val, value);
return ::testing::AssertionSuccess();
}
TEST(Timers, timerReset)
{
initModelTimer(0, TMRMODE_THR_REL, 200);
timerReset(0);
EXPECT_TRUE(evalTimersForNSecondsAndTest(0, THR_100, 0, TMR_OFF, 200));
initModelTimer(1, TMRMODE_THR_REL, 0);
timerReset(1);
EXPECT_TRUE(evalTimersForNSecondsAndTest(0, THR_100, 1, TMR_OFF, 0));
}
#if defined(CPUARM)
TEST(Timers, timerSet)
{
timerSet(0, 500);
EXPECT_TRUE(evalTimersForNSecondsAndTest(0, THR_100, 0, TMR_OFF, 500));
timerSet(1, 300);
EXPECT_TRUE(evalTimersForNSecondsAndTest(0, THR_100, 1, TMR_OFF, 300));
}
#endif // #if defined(CPUARM)
#if defined(CPUARM) || defined(CPUM2560)
TEST(Timers, saveRestoreTimers)
{
g_model.timers[0].persistent = 1;
g_model.timers[1].persistent = 1;
timerSet(0, 500);
timerSet(1, 1500);
saveTimers();
EXPECT_EQ(g_model.timers[0].value, 500);
EXPECT_EQ(g_model.timers[1].value, 1500);
EXPECT_TRUE(evalTimersForNSecondsAndTest(0, THR_100, 0, TMR_OFF, 500));
EXPECT_TRUE(evalTimersForNSecondsAndTest(0, THR_100, 1, TMR_OFF, 1500));
timerReset(0);
timerReset(1);
restoreTimers();
EXPECT_TRUE(evalTimersForNSecondsAndTest(0, THR_100, 0, TMR_OFF, 500));
EXPECT_TRUE(evalTimersForNSecondsAndTest(0, THR_100, 1, TMR_OFF, 1500));
}
#endif
TEST(Timers, timerOff)
{
initModelTimer(0, TMRMODE_NONE, 0);
timerReset(0);
EXPECT_TRUE(evalTimersForNSecondsAndTest(0, THR_100, 0, TMR_OFF, 0));
EXPECT_TRUE(evalTimersForNSecondsAndTest(10, THR_100, 0, TMR_OFF, 0));
}
TEST(Timers, timerAbsolute)
{
initModelTimer(0, TMRMODE_ABS, 0);
timerReset(0);
EXPECT_TRUE(evalTimersForNSecondsAndTest(1, THR_100, 0, TMR_RUNNING, 1));
EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_100, 0, TMR_RUNNING, 101));
EXPECT_TRUE(evalTimersForNSecondsAndTest(100, 0, 0, TMR_RUNNING, 201));
// max timer value test
timerSet(0, TIMER_MAX-10);
EXPECT_TRUE(evalTimersForNSecondsAndTest(1, THR_100, 0, TMR_RUNNING, TIMER_MAX-9));
EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_100, 0, TMR_RUNNING, TIMER_MAX));
// test down-running
g_model.timers[0].start = 200;
timerReset(0);
EXPECT_TRUE(evalTimersForNSecondsAndTest(1, THR_100, 0, TMR_RUNNING, 199));
EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_100, 0, TMR_RUNNING, 99));
EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_100, 0, TMR_NEGATIVE, -1));
EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_100, 0, TMR_STOPPED, -101));
// min timer value test
timerSet(0, TIMER_MIN+10);
EXPECT_TRUE(evalTimersForNSecondsAndTest(1, THR_100, 0, TMR_RUNNING, TIMER_MIN+9));
EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_100, 0, TMR_RUNNING, TIMER_MIN));
}
TEST(Timers, timerThrottle)
{
initModelTimer(0, TMRMODE_THR, 0);
timerReset(0);
EXPECT_TRUE(evalTimersForNSecondsAndTest(1, 0, 0, TMR_RUNNING, 0));
EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_100, 0, TMR_RUNNING, 100));
EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_10, 0, TMR_RUNNING, 200));
EXPECT_TRUE(evalTimersForNSecondsAndTest(100, 0, 0, TMR_RUNNING, 200));
// test down-running
g_model.timers[0].start = 200;
timerReset(0);
EXPECT_TRUE(evalTimersForNSecondsAndTest(1, THR_100, 0, TMR_RUNNING, 199));
EXPECT_TRUE(evalTimersForNSecondsAndTest(1, 0, 0, TMR_RUNNING, 199));
EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_100, 0, TMR_RUNNING, 99));
EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_50, 0, TMR_NEGATIVE, -1));
EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_100, 0, TMR_STOPPED,-101));
}
TEST(Timers, timerThrottleRelative)
{
initModelTimer(0, TMRMODE_THR_REL, 0);
timerReset(0);
EXPECT_TRUE(evalTimersForNSecondsAndTest(1, 0, 0, TMR_RUNNING, 0));
EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_100, 0, TMR_RUNNING, 100));
EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_50, 0, TMR_RUNNING, 150)); // 50% throttle == 50s
#if defined(ACCURAT_THROTTLE_TIMER)
EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_10, 0, TMR_RUNNING, 160)); // 10% throttle == 10s
EXPECT_TRUE(evalTimersForNSecondsAndTest(100, 0, 0, TMR_RUNNING, 160));
#else
EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_10, 0, TMR_RUNNING, 159)); // 10% throttle == 10s
EXPECT_TRUE(evalTimersForNSecondsAndTest(100, 0, 0, TMR_RUNNING, 159));
#endif
// test down-running
initModelTimer(0, TMRMODE_THR_REL, 200);
timerReset(0);
EXPECT_TRUE(evalTimersForNSecondsAndTest(1, THR_100, 0, TMR_RUNNING, 199));
EXPECT_TRUE(evalTimersForNSecondsAndTest(1, 0, 0, TMR_RUNNING, 199));
EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_100, 0, TMR_RUNNING, 99));
EXPECT_TRUE(evalTimersForNSecondsAndTest(200, THR_50, 0, TMR_NEGATIVE, -1)); // 50% throttle == 100s
#if defined(ACCURAT_THROTTLE_TIMER)
EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_10, 0, TMR_NEGATIVE,-11)); // 10% throttle == 10s
EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_100, 0, TMR_STOPPED,-111));
#else
EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_10, 0, TMR_NEGATIVE,-10)); // 10% throttle == 10s
EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_100, 0, TMR_STOPPED,-110));
#endif
}
TEST(Timers, timerThrottleTriggered)
{
initModelTimer(0, TMRMODE_THR_TRG, 0);
timerReset(0);
EXPECT_TRUE(evalTimersForNSecondsAndTest(1, 0, 0, TMR_OFF, 0));
EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_10-1, 0, TMR_OFF, 0)); // below threshold
EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_50, 0, TMR_RUNNING, 100));
EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_100, 0, TMR_RUNNING, 200));
EXPECT_TRUE(evalTimersForNSecondsAndTest(100, 0, 0, TMR_RUNNING, 300));
// test down-running
initModelTimer(0, TMRMODE_THR_TRG, 200);
timerReset(0);
EXPECT_TRUE(evalTimersForNSecondsAndTest(1, 0, 0, TMR_OFF, 200));
EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_10-1, 0, TMR_OFF, 200)); // below threshold
EXPECT_TRUE(evalTimersForNSecondsAndTest(100, THR_100, 0, TMR_RUNNING, 100));
EXPECT_TRUE(evalTimersForNSecondsAndTest(101, THR_50, 0, TMR_NEGATIVE, -1));
EXPECT_TRUE(evalTimersForNSecondsAndTest(10, 0, 0, TMR_NEGATIVE,-11));
EXPECT_TRUE(evalTimersForNSecondsAndTest(100, 0, 0, TMR_STOPPED,-111));
}

209
radio/src/timers.cpp Normal file
View file

@ -0,0 +1,209 @@
/*
* 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 "opentx.h"
#include "timers.h"
TimerState timersStates[MAX_TIMERS] = { 0 };
void timerReset(uint8_t idx)
{
TimerState & timerState = timersStates[idx];
timerState.state = TMR_OFF; // is changed to RUNNING dep from mode
timerState.val = g_model.timers[idx].start;
timerState.val_10ms = 0 ;
}
#if defined(CPUARM)
void timerSet(int idx, int16_t val)
{
TimerState & timerState = timersStates[idx];
timerState.state = TMR_OFF; // is changed to RUNNING dep from mode
timerState.val = val;
timerState.val_10ms = 0 ;
}
#endif // #if defined(CPUARM)
#if defined(CPUARM) || defined(CPUM2560)
void restoreTimers()
{
for (uint8_t i=0; i<MAX_TIMERS; i++) {
if (g_model.timers[i].persistent) {
timersStates[i].val = g_model.timers[i].value;
}
}
}
void saveTimers()
{
for (uint8_t i=0; i<MAX_TIMERS; i++) {
if (g_model.timers[i].persistent) {
TimerState *timerState = &timersStates[i];
if (g_model.timers[i].value != (uint16_t)timerState->val) {
g_model.timers[i].value = timerState->val;
eeDirty(EE_MODEL);
}
}
}
#if defined(CPUARM) && !defined(REVA)
if (sessionTimer > 0) {
g_eeGeneral.globalTimer += sessionTimer;
eeDirty(EE_GENERAL);
sessionTimer = 0;
}
#endif
}
#endif // #if defined(CPUARM) || defined(CPUM2560)
#if defined(ACCURAT_THROTTLE_TIMER)
#define THR_TRG_TRESHOLD 13 // approximately 10% full throttle
#else
#define THR_TRG_TRESHOLD 3 // approximately 10% full throttle
#endif
void evalTimers(int16_t throttle, uint8_t tick10ms)
{
for (uint8_t i=0; i<MAX_TIMERS; i++) {
int8_t tm = g_model.timers[i].mode;
uint16_t tv = g_model.timers[i].start;
TimerState * timerState = &timersStates[i];
if (tm) {
if ((timerState->state == TMR_OFF) && (tm != TMRMODE_THR_TRG)) {
timerState->state = TMR_RUNNING;
timerState->cnt = 0;
timerState->sum = 0;
}
if (tm == TMRMODE_THR_REL) {
timerState->cnt++;
timerState->sum += throttle;
}
if ((timerState->val_10ms += tick10ms) >= 100) {
if (timerState->val == TIMER_MAX) break;
if (timerState->val == TIMER_MIN) break;
timerState->val_10ms -= 100 ;
int16_t newTimerVal = timerState->val;
if (tv) newTimerVal = tv - newTimerVal;
if (tm == TMRMODE_ABS) {
newTimerVal++;
}
else if (tm == TMRMODE_THR) {
if (throttle) newTimerVal++;
}
else if (tm == TMRMODE_THR_REL) {
// @@@ open.20.fsguruh: why so complicated? we have already a s_sum field; use it for the half seconds (not showable) as well
// check for s_cnt[i]==0 is not needed because we are shure it is at least 1
#if defined(ACCURAT_THROTTLE_TIMER)
if ((timerState->sum/timerState->cnt) >= 128) { // throttle was normalized to 0 to 128 value (throttle/64*2 (because - range is added as well)
newTimerVal++; // add second used of throttle
timerState->sum -= 128*timerState->cnt;
}
#else
if ((timerState->sum/timerState->cnt) >= 32) { // throttle was normalized to 0 to 32 value (throttle/16*2 (because - range is added as well)
newTimerVal++; // add second used of throttle
timerState->sum -= 32*timerState->cnt;
}
#endif
timerState->cnt=0;
}
else if (tm == TMRMODE_THR_TRG) {
// we can't rely on (throttle || newTimerVal > 0) as a detection if timer should be running
// because having persistent timer brakes this rule
if ((throttle > THR_TRG_TRESHOLD) && timerState->state == TMR_OFF) {
timerState->state = TMR_RUNNING; // start timer running
timerState->cnt = 0;
timerState->sum = 0;
TRACE("Timer[%d] THr triggered", i);
}
if (timerState->state != TMR_OFF) newTimerVal++;
}
else {
if (tm > 0) tm -= (TMRMODE_COUNT-1);
if (getSwitch(tm))
newTimerVal++;
}
switch (timerState->state) {
case TMR_RUNNING:
if (tv && newTimerVal>=(int16_t)tv) {
AUDIO_TIMER_00(g_model.timers[i].countdownBeep);
timerState->state = TMR_NEGATIVE;
TRACE("Timer[%d] negative", i);
}
break;
case TMR_NEGATIVE:
if (newTimerVal >= (int16_t)tv + MAX_ALERT_TIME) {
timerState->state = TMR_STOPPED;
TRACE("Timer[%d] stopped state at %d", i, newTimerVal);
}
break;
}
if (tv) newTimerVal = tv - newTimerVal; // if counting backwards - display backwards
if (newTimerVal != timerState->val) {
timerState->val = newTimerVal;
if (timerState->state == TMR_RUNNING) {
if (g_model.timers[i].countdownBeep && g_model.timers[i].start) {
if (newTimerVal==30) {
AUDIO_TIMER_30();
TRACE("Timer[%d] 30s announcement", i);
}
if (newTimerVal==20) {
AUDIO_TIMER_20();
TRACE("Timer[%d] 20s announcement", i);
}
if (newTimerVal<=10) {
AUDIO_TIMER_LT10(g_model.timers[i].countdownBeep, newTimerVal);
TRACE("Timer[%d] %ds announcement", i, newTimerVal);
}
}
if (g_model.timers[i].minuteBeep && (newTimerVal % 60)==0) {
AUDIO_TIMER_MINUTE(newTimerVal);
TRACE("Timer[%d] %d minute announcement", i, newTimerVal/60);
}
}
}
}
}
}
}

74
radio/src/timers.h Normal file
View file

@ -0,0 +1,74 @@
/*
* 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 timers_h
#define timers_h
#define TMR_OFF 0
#define TMR_RUNNING 1
#define TMR_NEGATIVE 2
#define TMR_STOPPED 3
#define TIMER_MAX (32767)
#define TIMER_MIN (-32767-1)
struct TimerState {
uint16_t cnt;
uint16_t sum;
uint8_t state;
int16_t val;
uint8_t val_10ms;
};
extern TimerState timersStates[MAX_TIMERS];
void timerReset(uint8_t idx);
#if defined(CPUARM)
void timerSet(int idx, int16_t val);
#endif // #if defined(CPUARM)
#if defined(CPUARM) || defined(CPUM2560)
void saveTimers();
void restoreTimers();
#else
#define saveTimers()
#define restoreTimers()
#endif
void evalTimers(int16_t throttle, uint8_t tick10ms);
#endif