-
Notifications
You must be signed in to change notification settings - Fork 1
/
calculator.c
executable file
·180 lines (144 loc) · 4.35 KB
/
calculator.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
#include "calculator.h"
#include "calculator_lcd.h"
#include "pushbutton.h"
#include "alarm.h"
#include "adc.h"
#include "scuba.h"
#include "assert.h"
#include "dive_time.h"
#include <os.h>
void updateAlarms(CalculationState *currState){
uint8_t any_alarms = 0;
if(gas_to_surface_in_cl(currState->depth_mm)>currState->air_ml) {
currState->current_alarms |= ALARM_HIGH;
any_alarms = 1;
}
if(-15000>=currState->rate_mm_per_m) {
currState->current_alarms |= ALARM_MEDIUM;
any_alarms = 1;
}
if(40000<currState->depth_mm) {
currState->current_alarms |= ALARM_LOW;
any_alarms = 1;
}
if(!any_alarms) {
currState->current_alarms = ALARM_NONE;
}
}
void postAlarms(CalculationState *currState){
OS_ERR err;
OSFlagPost(&g_alarm_flags, (OS_FLAGS)currState->current_alarms, OS_OPT_POST_FLAG_SET,&err);
assert(OS_ERR_NONE == err);
}
uint16_t getTankChange_ml(){
uint16_t buttonPresses=0;
// Wait for a signal from the button debouncer.
OS_ERR err;
while(OSSemPend(&g_sw1_sem, 0, OS_OPT_PEND_NON_BLOCKING, 0, &err), OS_ERR_PEND_WOULD_BLOCK!=err){
buttonPresses++;
}
return buttonPresses*5000;
}
uint8_t g_b_is_new_timer;
void timer_init() {
g_b_is_new_timer = 1u;
}
void timer_update(CalculationState *state) {
if (state->depth_mm > 0)
{
if (is_timer_off())
{
start_timer(g_b_is_new_timer);
// This will only trigger the first time we dive
if (g_b_is_new_timer)
{
g_b_is_new_timer = 0;
}
}
}
else
{
if (!g_b_is_new_timer)
{
stop_timer();
}
}
}
void calculator_task(void* vptr) {
CalculationState calcState;
uint16_t tankChange_ml = 0;
uint16_t adc = 0;
OS_ERR err;
calculator_lcd_init();
adc_init();
timer_init();
// init values
calcState.depth_mm = 0;
calcState.rate_mm_per_m = 0;
calcState.air_ml = 50 * 1000; // init air in ml
calcState.elapsed_time_s = 0;
calcState.current_alarms = ALARM_NONE;
calcState.display_units = CALC_UNITS_METRIC;
for (;;)
{
while (1)
{
// determine DisplayUnits - check if SW2 has been toggled
OSSemPend(&g_sw2_sem, 0, OS_OPT_PEND_NON_BLOCKING, 0, &err);
// Check for change
if (OS_ERR_NONE == err)
{
calcState.display_units = (calcState.display_units == CALC_UNITS_METRIC ? CALC_UNITS_IMPERIAL : CALC_UNITS_METRIC);
} else if (OS_ERR_PEND_WOULD_BLOCK == err)
{
// no update
break;
} else
{
assert(0); // error state
}
}
adc = adc_read();
/* RATE and DEPTH */
// calculate ASCENT RATE int32_t rate_mm_per_m;
int32_t descent_rate = ADC2RATE(adc);
if(calcState.depth_mm > 0 || (calcState.depth_mm == 0 && descent_rate > 0)) {
calcState.rate_mm_per_m = 1000 * descent_rate;
} else {
calcState.rate_mm_per_m = 0;
}
// calculate DEPTH int32_t depth_mm;
calcState.depth_mm += depth_change_in_mm(calcState.rate_mm_per_m / 1000);
// no flying divers
if(calcState.depth_mm < 0) {
calcState.depth_mm = 0;
}
/* UPDATE AIR */
// check SW2 air changes
if(calcState.depth_mm == 0) {
tankChange_ml = getTankChange_ml();
calcState.air_ml = (calcState.air_ml + tankChange_ml > 2000000) ? 2000000 : calcState.air_ml + tankChange_ml;
} else {
// calculate uint32_t air_ml;
uint32_t gas_rate = gas_rate_in_cl(calcState.depth_mm) * 10; // cl -> ml
if(gas_rate < calcState.air_ml) {
calcState.air_ml -= gas_rate;
} else {
calcState.air_ml = 0;
}
}
/* UPDATE TIMER */
// apply the timer logic
timer_update(&calcState);
// get value from timer
calcState.elapsed_time_s = get_dive_time_in_seconds();
// alarms
updateAlarms(&calcState);
postAlarms(&calcState);
/* DISPLAY STATE */
// determine alarm state enum CurrentAlarm current_alarm;
calculator_lcd_update(&calcState);
// sleep 500 ms
OSTimeDlyHMSM(0, 0, 0, 500, OS_OPT_TIME_HMSM_STRICT, &err);
}
}