|
1082
|
1 /**
|
|
|
2 ******************************************************************************
|
|
|
3 * @file hud.c
|
|
|
4 * @author heinrichs weikamp gmbh
|
|
|
5 * @version V0.0.1
|
|
|
6 * @date 09-Mar-2026
|
|
|
7 * @brief Support function for HUD configuration
|
|
|
8 *
|
|
|
9 @verbatim
|
|
|
10 ==============================================================================
|
|
|
11 ##### How to use #####
|
|
|
12 ==============================================================================
|
|
|
13 @endverbatim
|
|
|
14 ******************************************************************************
|
|
|
15 * @attention
|
|
|
16 *
|
|
|
17 * COPYRIGHT(c) 2026 heinrichs weikamp
|
|
|
18 *
|
|
|
19 ******************************************************************************
|
|
|
20 */
|
|
|
21
|
|
|
22 #include "hud.h"
|
|
|
23 #include "settings.h"
|
|
|
24 #include "data_central.h"
|
|
|
25 #include "data_exchange.h"
|
|
|
26 #include "data_exchange_main.h"
|
|
|
27 #include "gfx_colors.h"
|
|
|
28 #include "math.h"
|
|
|
29 #include "tHome.h"
|
|
|
30
|
|
|
31 uint8_t hudActive;
|
|
|
32 static uint8_t hudAddress;
|
|
|
33 static uint8_t hudVersion;
|
|
|
34
|
|
|
35 static uint8_t hudLEDPerFct[NUM_OF_HUD_FCT]; /* array providing the version depending LED per function mapping */
|
|
|
36 static uint8_t hudLEDNeedPerFct[HUD_FCT_END+1] = {0, 1, 2, 2, 2, 2, 2, 2, 0}; /* array providing information how many LEDs are needed to provide a function */
|
|
|
37
|
|
|
38 void hud_Init()
|
|
|
39 {
|
|
|
40 uint8_t index = 0;
|
|
|
41 SDiveState * pStateReal = stateRealGetPointerWrite();
|
|
|
42 SSettings *pSettings = settingsGetPointer();
|
|
|
43
|
|
|
44 memset(pStateReal->lifeData.HUD_led_sequence,0,EXT_INTERFACE_HUD_LED_MAX);
|
|
|
45 hudActive = 0;
|
|
|
46 hudAddress = 0xFF;
|
|
|
47 hudVersion = 0;
|
|
|
48
|
|
|
49 for(index = EXT_INTERFACE_MUX_OFFSET; index < EXT_INTERFACE_SENSOR_CNT; index++)
|
|
|
50 {
|
|
|
51 if(pSettings->ext_sensor_map[index] == SENSOR_HUD)
|
|
|
52 {
|
|
|
53 hudActive = 1;
|
|
|
54 hudAddress = index;
|
|
|
55 break;
|
|
|
56 }
|
|
|
57 }
|
|
|
58 }
|
|
|
59
|
|
|
60 uint8_t hud_IsActive()
|
|
|
61 {
|
|
|
62 return hudActive;
|
|
|
63 }
|
|
|
64
|
|
|
65 uint8_t hud_GetAddress(void)
|
|
|
66 {
|
|
|
67 return hudAddress;
|
|
|
68 }
|
|
|
69
|
|
|
70 void hud_GetString(uint8_t id, uint8_t* pText)
|
|
|
71 {
|
|
|
72 switch(id)
|
|
|
73 {
|
|
|
74 case HUD_FCT_NONE: sprintf((char*)pText,"%c", TXT_Off);
|
|
|
75 break;
|
|
|
76 case HUD_FCT_WARNING: sprintf((char*)pText,"%c", TXT_Warning);
|
|
|
77 break;
|
|
|
78 case HUD_FCT_PPO2SUM: sprintf((char*)pText,"%c%c (1 - 3)", TXT_2BYTE, TXT2BYTE_O2monitor);
|
|
|
79 break;
|
|
|
80 case HUD_FCT_PPO2_0:
|
|
|
81 case HUD_FCT_PPO2_1:
|
|
|
82 case HUD_FCT_PPO2_2: sprintf((char*)pText,"%c%c (%d)", TXT_2BYTE, TXT2BYTE_O2monitor, (id - HUD_FCT_PPO2_0));
|
|
|
83 break;
|
|
|
84 case HUD_FCT_ASCENT_SPEED: sprintf((char*)pText,"%c%c", TXT_2BYTE, TXT2BYTE_AscentSpeed);
|
|
|
85 break;
|
|
|
86 case HUD_FCT_DECO: sprintf((char*)pText,"%c%c", TXT_2BYTE, TXT2BYTE_WarnDecoMissed);
|
|
|
87 break;
|
|
|
88 default:
|
|
|
89 break;
|
|
|
90 }
|
|
|
91 }
|
|
|
92
|
|
|
93 uint8_t hud_NextFct(uint8_t curFct, uint8_t fctId)
|
|
|
94 {
|
|
|
95 uint8_t done = 0;
|
|
|
96 uint8_t nextFct = curFct;
|
|
|
97 SSettings *pSettings = settingsGetPointer();
|
|
|
98
|
|
|
99
|
|
|
100 while (done == 0)
|
|
|
101 {
|
|
|
102 nextFct++;
|
|
|
103 if(nextFct < HUD_FCT_END)
|
|
|
104 {
|
|
|
105 if(hudLEDNeedPerFct[nextFct] <= hudLEDPerFct[fctId])
|
|
|
106 {
|
|
|
107 switch(nextFct) /* this switch handles conditional function. e.g. monitor2 should be skipped if no sensor2 is connected */
|
|
|
108 {
|
|
|
109 case HUD_FCT_PPO2_0:
|
|
|
110 case HUD_FCT_PPO2_1:
|
|
|
111 case HUD_FCT_PPO2_2: if((pSettings->ext_sensor_map[nextFct - HUD_FCT_PPO2_0] >= SENSOR_ANALOG) && (pSettings->ext_sensor_map[nextFct - HUD_FCT_PPO2_0] < SENSOR_TYPE_O2_END))
|
|
|
112 {
|
|
|
113 done = 1;
|
|
|
114 }
|
|
|
115 break;
|
|
|
116 default: done = 1;
|
|
|
117 break;
|
|
|
118 }
|
|
|
119 }
|
|
|
120 }
|
|
|
121 else
|
|
|
122 {
|
|
|
123 nextFct = HUD_FCT_NONE;
|
|
|
124 break;
|
|
|
125 }
|
|
|
126 }
|
|
|
127 return nextFct;
|
|
|
128 }
|
|
|
129
|
|
|
130 static void hud_UpdateWarning(uint8_t fctId)
|
|
|
131 {
|
|
|
132 // SDiveState * pStateReal = stateRealGetPointerWrite();
|
|
|
133
|
|
|
134 if(stateUsed->warnings.numWarnings)
|
|
|
135 {
|
|
|
136 stateUsedWrite->lifeData.HUD_led_sequence[fctId * 2] = 0x32;
|
|
|
137 }
|
|
|
138 else
|
|
|
139 {
|
|
|
140 stateUsedWrite->lifeData.HUD_led_sequence[fctId * 2] = 0;
|
|
|
141 }
|
|
|
142 }
|
|
|
143
|
|
|
144 static void hud_UpdatePPO2Monitor(uint8_t fctId, float ppO2)
|
|
|
145 {
|
|
|
146 // SDiveState * pStateReal = stateRealGetPointerWrite();
|
|
|
147
|
|
|
148 stateUsedWrite->lifeData.HUD_led_sequence[(fctId * 2)] = 0;
|
|
|
149 stateUsedWrite->lifeData.HUD_led_sequence[(fctId * 2) + 1] = 0;
|
|
|
150
|
|
|
151 if(fabs(stateUsed->lifeData.actualGas.setPoint_cbar - ppO2) < 0.06) /* green constant */
|
|
|
152 {
|
|
|
153 stateUsedWrite->lifeData.HUD_led_sequence[(fctId * 2) + 1] = 0x01;
|
|
|
154 }
|
|
|
155 else if((stateUsed->lifeData.actualGas.setPoint_cbar - ppO2) < 0.2) /* to low => blink green */
|
|
|
156 {
|
|
|
157 stateUsedWrite->lifeData.HUD_led_sequence[(fctId * 2) + 1] = 0x13;
|
|
|
158 }
|
|
|
159 else if((stateUsed->lifeData.actualGas.setPoint_cbar - ppO2) < 0.2) /* to high => blink red */
|
|
|
160 {
|
|
|
161 stateUsedWrite->lifeData.HUD_led_sequence[(fctId * 2)] = 0x13;
|
|
|
162 }
|
|
|
163 else /* out of range => red */
|
|
|
164 {
|
|
|
165 stateUsedWrite->lifeData.HUD_led_sequence[(fctId * 2)] = 0x01;
|
|
|
166 }
|
|
|
167 }
|
|
|
168
|
|
|
169 static void hud_UpdateAscentSpeed(uint8_t fctId)
|
|
|
170 {
|
|
|
171 // SDiveState * pStateReal = stateRealGetPointerWrite();
|
|
|
172 uint8_t indicatorColor = 0;
|
|
|
173
|
|
|
174 indicatorColor = drawingColor_from_ascentspeed(stateUsed->lifeData.ascent_rate_meter_per_min);
|
|
|
175 stateUsedWrite->lifeData.HUD_led_sequence[(fctId * 2)] = 0;
|
|
|
176 stateUsedWrite->lifeData.HUD_led_sequence[(fctId * 2) + 1] = 0;
|
|
|
177
|
|
|
178 switch(indicatorColor) /* map color to LED operation */
|
|
|
179 {
|
|
|
180 case CLUT_NiceGreen: stateUsedWrite->lifeData.HUD_led_sequence[(fctId * 2) + 1] = 0x01; /* green constant */
|
|
|
181 break;
|
|
|
182 case CLUT_WarningYellow: stateUsedWrite->lifeData.HUD_led_sequence[(fctId * 2)] = 0x55; /* fast blink red */
|
|
|
183 break;
|
|
|
184 case CLUT_WarningRed: stateUsedWrite->lifeData.HUD_led_sequence[(fctId * 2)] = 0x01; /* red constant */
|
|
|
185 break;
|
|
|
186 }
|
|
|
187 }
|
|
|
188
|
|
|
189 static void hud_UpdateDecoIndicator(uint8_t fctId)
|
|
|
190 {
|
|
|
191 uint16_t nextstopLengthSeconds = 0;
|
|
|
192 uint8_t nextstopDepthMeter = 0;
|
|
|
193 const SDecoinfo * pDecoinfo = getDecoInfo();
|
|
|
194
|
|
|
195 stateUsedWrite->lifeData.HUD_led_sequence[(fctId * 2)] = 0;
|
|
|
196 stateUsedWrite->lifeData.HUD_led_sequence[(fctId * 2) + 1] = 0;
|
|
|
197
|
|
|
198 if(pDecoinfo->output_time_to_surface_seconds)
|
|
|
199 {
|
|
|
200 tHome_findNextStop(pDecoinfo->output_stop_length_seconds, &nextstopDepthMeter, &nextstopLengthSeconds);
|
|
|
201 if(nextstopDepthMeter > 0)
|
|
|
202 {
|
|
|
203 if(fabs(stateUsed->lifeData.depth_meter - nextstopDepthMeter) < 1.5) /* close to stop */
|
|
|
204 {
|
|
|
205 if((stateUsed->lifeData.depth_meter + 0.1) >= nextstopDepthMeter)
|
|
|
206 {
|
|
|
207 stateUsedWrite->lifeData.HUD_led_sequence[(fctId * 2) + 1] = 0x01; /* close below deco stop => green constant */
|
|
|
208 }
|
|
|
209 else
|
|
|
210 {
|
|
|
211 stateUsedWrite->lifeData.HUD_led_sequence[(fctId * 2)] = 0x55; /* close above deco stop => red fast blink */
|
|
|
212 }
|
|
|
213 }
|
|
|
214 else if(((stateUsed->lifeData.depth_meter +0.1) > nextstopDepthMeter))
|
|
|
215 {
|
|
|
216 stateUsedWrite->lifeData.HUD_led_sequence[(fctId * 2) + 1] = 0x13; /* Ascent to deco stop => green slow blink */
|
|
|
217 }
|
|
|
218 else
|
|
|
219 {
|
|
|
220 stateUsedWrite->lifeData.HUD_led_sequence[(fctId * 2)] = 0x01; /* Missed deco stop => red constant */
|
|
|
221 }
|
|
|
222 }
|
|
|
223 }
|
|
|
224 }
|
|
|
225
|
|
|
226 void hud_UpdateStatus()
|
|
|
227 {
|
|
|
228 static uint32_t updateTick = 0;
|
|
|
229
|
|
|
230 SDiveState * pStateReal = stateRealGetPointerWrite();
|
|
|
231 SSettings *pSettings = settingsGetPointer();
|
|
|
232
|
|
|
233 uint8_t index = 0;
|
|
|
234
|
|
|
235 if(hudVersion == 0)
|
|
|
236 {
|
|
|
237 if((pStateReal->lifeData.extIf_sensor_data[hudAddress][HUD_INFO_VERSION_OFFSET] > 0) && (pStateReal->lifeData.extIf_sensor_data[hudAddress][HUD_INFO_VERSION_OFFSET] <= 1))
|
|
|
238 {
|
|
|
239 hudVersion = pStateReal->lifeData.extIf_sensor_data[hudAddress][HUD_INFO_VERSION_OFFSET];
|
|
|
240 switch(hudVersion)
|
|
|
241 {
|
|
|
242 case 1:
|
|
|
243 default: hudLEDPerFct[0] = 2;
|
|
|
244 hudLEDPerFct[1] = 2;
|
|
|
245 hudLEDPerFct[2] = 2;
|
|
|
246 hudLEDPerFct[3] = 1;
|
|
|
247 break;
|
|
|
248 }
|
|
|
249 }
|
|
|
250 }
|
|
|
251 else
|
|
|
252 {
|
|
|
253 if(time_elapsed_ms(updateTick, HAL_GetTick()) > 2000)
|
|
|
254 {
|
|
|
255 if(stateUsed->mode == MODE_DIVE)
|
|
|
256 {
|
|
|
257 for( index = 0; index < NUM_OF_HUD_FCT; index++)
|
|
|
258 {
|
|
|
259 switch(pSettings->hudFunction[index])
|
|
|
260 {
|
|
|
261 case HUD_FCT_WARNING: hud_UpdateWarning(index);
|
|
|
262 break;
|
|
|
263 case HUD_FCT_PPO2SUM: hud_UpdatePPO2Monitor(index, stateUsed->lifeData.ppO2);
|
|
|
264 break;
|
|
|
265 case HUD_FCT_PPO2_0:
|
|
|
266 case HUD_FCT_PPO2_1:
|
|
|
267 case HUD_FCT_PPO2_2: hud_UpdatePPO2Monitor(index, stateUsed->lifeData.ppO2Sensor_bar[pSettings->hudFunction[index] - HUD_FCT_PPO2_0]);
|
|
|
268 break;
|
|
|
269 case HUD_FCT_ASCENT_SPEED: hud_UpdateAscentSpeed(index);
|
|
|
270 break;
|
|
|
271 case HUD_FCT_DECO: hud_UpdateDecoIndicator(index);
|
|
|
272 break;
|
|
|
273 case HUD_FCT_NONE:
|
|
|
274 default:
|
|
|
275 break;
|
|
|
276 }
|
|
|
277 }
|
|
|
278 }
|
|
|
279 else
|
|
|
280 {
|
|
|
281 #ifndef ENABLE_HUD_TESTING
|
|
|
282 memset(pStateReal->lifeData.HUD_led_sequence,0,EXT_INTERFACE_HUD_LED_MAX);
|
|
|
283 pStateReal->lifeData.HUD_led_sequence[6] = 0x01; /* switch only blue LED on */
|
|
|
284 #endif
|
|
|
285 }
|
|
|
286 DataEX_setExtInterface_Cmd(EXT_INTERFACE_HUD_UPDATE, hudAddress);
|
|
|
287 updateTick = HAL_GetTick();
|
|
|
288 }
|
|
|
289 }
|
|
|
290 }
|