mirror of
https://github.com/opentx/opentx.git
synced 2025-07-24 00:35:18 +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:
parent
76937ea566
commit
afc41f082e
25 changed files with 4001 additions and 3563 deletions
|
@ -15,13 +15,13 @@
|
|||
*/
|
||||
|
||||
|
||||
#include "stdio.h"
|
||||
#include "inttypes.h"
|
||||
#include "string.h"
|
||||
#include "file.h"
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <algorithm>
|
||||
#include "eeprominterface.h"
|
||||
#include "file.h"
|
||||
|
||||
RleFile::RleFile():
|
||||
eeprom(NULL),
|
||||
|
|
|
@ -71,6 +71,7 @@ namespace Open9xGruvin9x {
|
|||
#include "radio/src/functions.cpp"
|
||||
#include "radio/src/curves.cpp"
|
||||
#include "radio/src/mixer.cpp"
|
||||
#include "radio/src/timers.cpp"
|
||||
#include "radio/src/pulses/pulses_avr.cpp"
|
||||
#include "radio/src/stamp.cpp"
|
||||
#include "radio/src/maths.cpp"
|
||||
|
|
|
@ -72,6 +72,7 @@ namespace OpenTxM128 {
|
|||
#include "radio/src/functions.cpp"
|
||||
#include "radio/src/curves.cpp"
|
||||
#include "radio/src/mixer.cpp"
|
||||
#include "radio/src/timers.cpp"
|
||||
#include "radio/src/pulses/pulses_avr.cpp"
|
||||
#include "radio/src/stamp.cpp"
|
||||
#include "radio/src/maths.cpp"
|
||||
|
|
|
@ -75,6 +75,7 @@ namespace OpenTxM64 {
|
|||
#include "radio/src/functions.cpp"
|
||||
#include "radio/src/curves.cpp"
|
||||
#include "radio/src/mixer.cpp"
|
||||
#include "radio/src/timers.cpp"
|
||||
#include "radio/src/pulses/pulses_avr.cpp"
|
||||
#include "radio/src/stamp.cpp"
|
||||
#include "radio/src/maths.cpp"
|
||||
|
|
|
@ -83,6 +83,7 @@ namespace Open9xSky9x {
|
|||
#include "radio/src/switches.cpp"
|
||||
#include "radio/src/functions.cpp"
|
||||
#include "radio/src/mixer.cpp"
|
||||
#include "radio/src/timers.cpp"
|
||||
#include "radio/src/curves.cpp"
|
||||
#include "radio/src/targets/sky9x/pulses_driver.cpp"
|
||||
#include "radio/src/pulses/pulses_arm.cpp"
|
||||
|
|
|
@ -87,6 +87,7 @@ inline int geteepromsize() {
|
|||
#include "radio/src/curves.cpp"
|
||||
#include "radio/src/mixer.cpp"
|
||||
#include "radio/src/sdcard.cpp"
|
||||
#include "radio/src/timers.cpp"
|
||||
#include "radio/src/targets/taranis/pulses_driver.cpp"
|
||||
#include "radio/src/targets/taranis/rtc_driver.cpp"
|
||||
#include "radio/src/targets/taranis/trainer_driver.cpp"
|
||||
|
|
|
@ -88,6 +88,7 @@ inline int geteepromsize() {
|
|||
#include "radio/src/curves.cpp"
|
||||
#include "radio/src/mixer.cpp"
|
||||
#include "radio/src/sdcard.cpp"
|
||||
#include "radio/src/timers.cpp"
|
||||
#include "radio/src/targets/taranis/pulses_driver.cpp"
|
||||
#include "radio/src/targets/taranis/rtc_driver.cpp"
|
||||
#include "radio/src/targets/taranis/rotenc_driver.cpp"
|
||||
|
|
|
@ -954,7 +954,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)
|
||||
CPPSRC += opentx.cpp functions.cpp strhelpers.cpp $(PULSESSRC) switches.cpp curves.cpp mixer.cpp stamp.cpp $(GUISRC) $(EEPROMSRC) timers.cpp
|
||||
|
||||
ifeq ($(GUI), YES)
|
||||
GUISRC += gui/$(GUIDIRECTORY)/lcd.cpp gui/$(GUIDIRECTORY)/splash.cpp gui/$(GUIDIRECTORY)/fonts.cpp
|
||||
|
|
|
@ -35,9 +35,10 @@
|
|||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include "opentx.h"
|
||||
#include "inttypes.h"
|
||||
#include "string.h"
|
||||
#include "timers.h"
|
||||
|
||||
uint8_t s_eeDirtyMsk;
|
||||
tmr10ms_t s_eeDirtyTime10ms;
|
||||
|
|
|
@ -35,9 +35,10 @@
|
|||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include "opentx.h"
|
||||
#include "inttypes.h"
|
||||
#include "string.h"
|
||||
#include "timers.h"
|
||||
|
||||
volatile uint32_t Spi_complete; // TODO in the driver ?
|
||||
|
||||
|
@ -396,11 +397,7 @@ void eeLoadModel(uint8_t id)
|
|||
|
||||
customFunctionsReset();
|
||||
|
||||
for (uint8_t i=0; i<MAX_TIMERS; i++) {
|
||||
if (g_model.timers[i].persistent) {
|
||||
timersStates[i].val = g_model.timers[i].value;
|
||||
}
|
||||
}
|
||||
restoreTimers();
|
||||
|
||||
resumeMixerCalculations();
|
||||
// TODO pulses should be started after mixer calculations ...
|
||||
|
|
|
@ -34,9 +34,10 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include "opentx.h"
|
||||
#include "inttypes.h"
|
||||
#include "string.h"
|
||||
#include "timers.h"
|
||||
|
||||
uint8_t s_write_err = 0; // error reasons
|
||||
RlcFile theFile; //used for any file operation
|
||||
|
@ -985,13 +986,7 @@ void eeLoadModel(uint8_t id)
|
|||
|
||||
customFunctionsReset();
|
||||
|
||||
#if !defined(PCBSTD)
|
||||
for (uint8_t i=0; i<MAX_TIMERS; i++) {
|
||||
if (g_model.timers[i].persistent) {
|
||||
timersStates[i].val = g_model.timers[i].value;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
restoreTimers();
|
||||
|
||||
#if defined(CPUARM)
|
||||
for (int i=0; i<TELEM_VALUES_MAX; i++) {
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
*/
|
||||
|
||||
#include "opentx.h"
|
||||
#include "timers.h"
|
||||
|
||||
CustomFunctionsContext modelFunctionsContext = { 0 };
|
||||
|
||||
|
@ -359,10 +360,7 @@ void evalFunctions()
|
|||
#if defined(CPUARM)
|
||||
case FUNC_SET_TIMER:
|
||||
{
|
||||
TimerState & timerState = timersStates[CFN_TIMER_INDEX(cfn)];
|
||||
timerState.state = TMR_OFF; // is changed to RUNNING dep from mode
|
||||
timerState.val = CFN_PARAM(cfn);
|
||||
timerState.val_10ms = 0 ;
|
||||
timerSet(CFN_TIMER_INDEX(cfn), CFN_PARAM(cfn));
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
*/
|
||||
|
||||
#include "../../opentx.h"
|
||||
#include "../../timers.h"
|
||||
|
||||
#define BIGSIZE DBLSIZE
|
||||
#define LBOX_CENTERX (LCD_W/4 + 10)
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
*/
|
||||
|
||||
#include "../../opentx.h"
|
||||
#include "../../timers.h"
|
||||
|
||||
void menuStatisticsView(uint8_t event)
|
||||
{
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
*/
|
||||
|
||||
#include "opentx.h"
|
||||
#include "timers.h"
|
||||
|
||||
#if defined(REVPLUS) && defined(LCD_DUAL_BUFFER)
|
||||
display_t displayBuf1[DISPLAY_BUF_SIZE];
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
*/
|
||||
|
||||
#include "../../opentx.h"
|
||||
#include "../../timers.h"
|
||||
|
||||
#define BIGSIZE MIDSIZE
|
||||
#define LBOX_CENTERX (BOX_WIDTH/2 + 17)
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
*/
|
||||
|
||||
#include "../../opentx.h"
|
||||
#include "../../timers.h"
|
||||
|
||||
void menuStatisticsView(uint8_t event)
|
||||
{
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include "opentx.h"
|
||||
#include "stamp-opentx.h"
|
||||
#include "bin_allocator.h"
|
||||
#include "timers.h"
|
||||
|
||||
#if !defined(SIMU)
|
||||
extern "C" {
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
*/
|
||||
|
||||
#include "opentx.h"
|
||||
#include "timers.h"
|
||||
|
||||
#if defined(PCBTARANIS)
|
||||
int8_t virtualInputsTrims[NUM_INPUTS];
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
*/
|
||||
|
||||
#include "opentx.h"
|
||||
#include "timers.h"
|
||||
|
||||
#if defined(COLORLCD)
|
||||
#elif defined(PCBTARANIS)
|
||||
|
@ -1520,14 +1521,6 @@ uint8_t trimsDisplayTimer = 0;
|
|||
uint8_t trimsDisplayMask = 0;
|
||||
#endif
|
||||
|
||||
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 ;
|
||||
}
|
||||
|
||||
void flightReset()
|
||||
{
|
||||
// we don't reset the whole audio here (the tada.wav would be cut, if a prompt is queued before FlightReset, it should be played)
|
||||
|
@ -1552,8 +1545,6 @@ void flightReset()
|
|||
RESET_THR_TRACE();
|
||||
}
|
||||
|
||||
TimerState timersStates[MAX_TIMERS] = { { 0 }, { 0 } };
|
||||
|
||||
#if defined(THRTRACE)
|
||||
uint8_t s_traceBuf[MAXTRACE];
|
||||
#if LCD_W >= 255
|
||||
|
@ -1703,95 +1694,7 @@ void doMixerCalculations()
|
|||
val >>= (RESX_SHIFT-4); // calibrate it
|
||||
#endif
|
||||
|
||||
// Timers start
|
||||
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) {
|
||||
timerState->state = TMR_RUNNING;
|
||||
timerState->cnt = 0;
|
||||
timerState->sum = 0;
|
||||
}
|
||||
|
||||
if (tm == TMRMODE_THR_REL) {
|
||||
timerState->cnt++;
|
||||
timerState->sum+=val;
|
||||
}
|
||||
|
||||
if ((timerState->val_10ms += tick10ms) >= 100) {
|
||||
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 (val) 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) {
|
||||
if (val) {
|
||||
timerState->state = TMR_TRIGGED;
|
||||
}
|
||||
if (timerState->state == TMR_TRIGGED) {
|
||||
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;
|
||||
}
|
||||
break;
|
||||
case TMR_NEGATIVE:
|
||||
if (newTimerVal >= (int16_t)tv + MAX_ALERT_TIME) timerState->state = TMR_STOPPED;
|
||||
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();
|
||||
if (newTimerVal==20) AUDIO_TIMER_20();
|
||||
if (newTimerVal<=10) AUDIO_TIMER_LT10(g_model.timers[i].countdownBeep, newTimerVal);
|
||||
}
|
||||
if (g_model.timers[i].minuteBeep && (newTimerVal % 60)==0) {
|
||||
AUDIO_TIMER_MINUTE(newTimerVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} //endfor timer loop (only two)
|
||||
evalTimers(val, tick10ms);
|
||||
|
||||
static uint8_t s_cnt_100ms;
|
||||
static uint8_t s_cnt_1s;
|
||||
|
@ -2455,29 +2358,6 @@ void moveTrimsToOffsets() // copy state of 3 primary to subtrim
|
|||
AUDIO_WARNING2();
|
||||
}
|
||||
|
||||
#if defined(CPUARM) || defined(CPUM2560)
|
||||
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(ROTARY_ENCODERS)
|
||||
volatile rotenc_t g_rotenc[ROTARY_ENCODERS] = {0};
|
||||
#elif defined(ROTARY_ENCODER_NAVIGATION)
|
||||
|
|
|
@ -270,6 +270,15 @@
|
|||
#define convertSimuPath(x) (x)
|
||||
#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
|
||||
#define RESX_SHIFT 10
|
||||
#define RESX 1024
|
||||
|
@ -867,16 +876,6 @@ extern uint16_t sessionTimer;
|
|||
extern uint16_t s_timeCumThr;
|
||||
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(CPUARM)
|
||||
typedef int16_t safetych_t;
|
||||
|
@ -895,12 +894,6 @@ extern uint8_t trimsDisplayTimer;
|
|||
extern uint8_t trimsDisplayMask;
|
||||
#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();
|
||||
|
||||
extern uint8_t unexpectedShutdown;
|
||||
|
@ -1068,12 +1061,6 @@ inline void resumeMixerCalculations()
|
|||
#define resumeMixerCalculations()
|
||||
#endif
|
||||
|
||||
#if defined(CPUARM) || defined(CPUM2560)
|
||||
void saveTimers();
|
||||
#else
|
||||
#define saveTimers()
|
||||
#endif
|
||||
|
||||
void generalDefault();
|
||||
void modelDefault(uint8_t id);
|
||||
|
||||
|
|
284
radio/src/tests/timers.cpp
Normal file
284
radio/src/tests/timers.cpp
Normal 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
209
radio/src/timers.cpp
Normal 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
74
radio/src/timers.h
Normal 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
|
Loading…
Add table
Add a link
Reference in a new issue