Fix doc path
[opentx.git] / radio / src / timers.cpp
blob9f6e3611d30e36885177addd26eec91e4d93c6b0
1 /*
2 * Copyright (C) OpenTX
4 * Based on code named
5 * th9x - http://code.google.com/p/th9x
6 * er9x - http://code.google.com/p/er9x
7 * gruvin9x - http://code.google.com/p/gruvin9x
9 * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
21 #include "opentx.h"
22 #include "timers.h"
24 #if TIMERS > MAX_TIMERS
25 #error "Timers cannot exceed " .. MAX_TIMERS
26 #endif
28 TimerState timersStates[TIMERS] = { { 0 } };
30 void timerReset(uint8_t idx)
32 TimerState & timerState = timersStates[idx];
33 timerState.state = TMR_OFF; // is changed to RUNNING dep from mode
34 timerState.val = g_model.timers[idx].start;
35 timerState.val_10ms = 0 ;
38 #if defined(CPUARM)
39 void timerSet(int idx, int val)
41 TimerState & timerState = timersStates[idx];
42 timerState.state = TMR_OFF; // is changed to RUNNING dep from mode
43 timerState.val = val;
44 timerState.val_10ms = 0 ;
46 #endif // #if defined(CPUARM)
48 #if defined(CPUARM) || defined(CPUM2560)
49 void restoreTimers()
51 for (uint8_t i=0; i<TIMERS; i++) {
52 if (g_model.timers[i].persistent) {
53 timersStates[i].val = g_model.timers[i].value;
58 void saveTimers()
60 for (uint8_t i=0; i<TIMERS; i++) {
61 if (g_model.timers[i].persistent) {
62 TimerState *timerState = &timersStates[i];
63 if (g_model.timers[i].value != (uint16_t)timerState->val) {
64 g_model.timers[i].value = timerState->val;
65 storageDirty(EE_MODEL);
70 #endif // #if defined(CPUARM) || defined(CPUM2560)
72 #if defined(ACCURAT_THROTTLE_TIMER)
73 #define THR_TRG_TRESHOLD 13 // approximately 10% full throttle
74 #else
75 #define THR_TRG_TRESHOLD 3 // approximately 10% full throttle
76 #endif
78 void evalTimers(int16_t throttle, uint8_t tick10ms)
80 for (uint8_t i=0; i<TIMERS; i++) {
81 tmrmode_t timerMode = g_model.timers[i].mode;
82 tmrstart_t timerStart = g_model.timers[i].start;
83 TimerState * timerState = &timersStates[i];
85 if (timerMode) {
86 if ((timerState->state == TMR_OFF) && (timerMode != TMRMODE_THR_TRG)) {
87 timerState->state = TMR_RUNNING;
88 timerState->cnt = 0;
89 timerState->sum = 0;
92 if (timerMode == TMRMODE_THR_REL) {
93 timerState->cnt++;
94 timerState->sum += throttle;
97 if ((timerState->val_10ms += tick10ms) >= 100) {
98 if (timerState->val == TIMER_MAX) break;
99 if (timerState->val == TIMER_MIN) break;
101 timerState->val_10ms -= 100 ;
102 tmrval_t newTimerVal = timerState->val;
103 if (timerStart) newTimerVal = timerStart - newTimerVal;
105 if (timerMode == TMRMODE_ABS) {
106 newTimerVal++;
108 else if (timerMode == TMRMODE_THR) {
109 if (throttle) newTimerVal++;
111 else if (timerMode == TMRMODE_THR_REL) {
112 // @@@ open.20.fsguruh: why so complicated? we have already a s_sum field; use it for the half seconds (not showable) as well
113 // check for s_cnt[i]==0 is not needed because we are shure it is at least 1
114 #if defined(ACCURAT_THROTTLE_TIMER)
115 if ((timerState->sum/timerState->cnt) >= 128) { // throttle was normalized to 0 to 128 value (throttle/64*2 (because - range is added as well)
116 newTimerVal++; // add second used of throttle
117 timerState->sum -= 128*timerState->cnt;
119 #else
120 if ((timerState->sum/timerState->cnt) >= 32) { // throttle was normalized to 0 to 32 value (throttle/16*2 (because - range is added as well)
121 newTimerVal++; // add second used of throttle
122 timerState->sum -= 32*timerState->cnt;
124 #endif
125 timerState->cnt = 0;
127 else if (timerMode == TMRMODE_THR_TRG) {
128 // we can't rely on (throttle || newTimerVal > 0) as a detection if timer should be running
129 // because having persistent timer brakes this rule
130 if ((throttle > THR_TRG_TRESHOLD) && timerState->state == TMR_OFF) {
131 timerState->state = TMR_RUNNING; // start timer running
132 timerState->cnt = 0;
133 timerState->sum = 0;
134 // TRACE("Timer[%d] THr triggered", i);
136 if (timerState->state != TMR_OFF) newTimerVal++;
138 else {
139 if (timerMode > 0) timerMode -= (TMRMODE_COUNT-1);
140 if (getSwitch(timerMode)) {
141 newTimerVal++;
145 switch (timerState->state) {
146 case TMR_RUNNING:
147 if (timerStart && newTimerVal>=(tmrval_t)timerStart) {
148 AUDIO_TIMER_ELAPSED(i);
149 timerState->state = TMR_NEGATIVE;
150 // TRACE("Timer[%d] negative", i);
152 break;
153 case TMR_NEGATIVE:
154 if (newTimerVal >= (tmrval_t)timerStart + MAX_ALERT_TIME) {
155 timerState->state = TMR_STOPPED;
156 // TRACE("Timer[%d] stopped state at %d", i, newTimerVal);
158 break;
161 if (timerStart) newTimerVal = timerStart - newTimerVal; // if counting backwards - display backwards
163 if (newTimerVal != timerState->val) {
164 timerState->val = newTimerVal;
165 if (timerState->state == TMR_RUNNING) {
166 if (g_model.timers[i].countdownBeep && g_model.timers[i].start) {
167 AUDIO_TIMER_COUNTDOWN(i, newTimerVal);
169 if (g_model.timers[i].minuteBeep && (newTimerVal % 60)==0) {
170 AUDIO_TIMER_MINUTE(newTimerVal);
171 // TRACE("Timer[%d] %d minute announcement", i, newTimerVal/60);