Mercurial > public > ostc4
comparison Discovery/Src/logbook.c @ 38:5f11787b4f42
include in ostc4 repository
author | heinrichsweikamp |
---|---|
date | Sat, 28 Apr 2018 11:52:34 +0200 |
parents | |
children | b7689d9e888a |
comparison
equal
deleted
inserted
replaced
37:ccc45c0e1ea2 | 38:5f11787b4f42 |
---|---|
1 /** | |
2 ****************************************************************************** | |
3 * @copyright heinrichs weikamp | |
4 * @file logbook.c | |
5 * @author heinrichs weikamp gmbh and heinrichs weikamp gmbh | |
6 * @date 22-Apr-2014 | |
7 * @version V0.0.3 | |
8 * @since 03-Feb-2016 | |
9 * @brief Everything about creating and evaluating the logbook | |
10 * without the flash part which is included in externLogbookFlash.c | |
11 * and the USB/Bluetooth part in tComm.c | |
12 * CHANGE V0.0.3 hw: ppO2 sensor values | |
13 * CHANGE V0.0.4 hw: fix event bytes according to hwos_interface.odt dated 160610 in bitbucket hwOS | |
14 * @bug | |
15 * @warning | |
16 @verbatim | |
17 ============================================================================== | |
18 ##### Header ##### | |
19 ============================================================================== | |
20 [..] SLogbookHeader | |
21 The order has changed in comparsion to OSTC3 for perfect alignment | |
22 with 16bit and 32bit. The header is 256kB as well. | |
23 DO NOT rearrange anything but add new data to a second page | |
24 beyond diveHeaderEnd. Use extraPagesWithData to indicate that there is | |
25 data available that was not available in the OSTC3 256KB | |
26 This data will be behind the diveHeaderEnd. DO NOT delete diveHeaderEnd. | |
27 | |
28 [..] SLogbookHeaderOSTC3 | |
29 is the format used by the OSTC3. | |
30 logbook_getHeaderOSTC3() does the job using the global headers in logbook.c | |
31 | |
32 [..] SSmallHeader | |
33 - is the format used by the OSTC3 | |
34 | |
35 [..] Summary | |
36 The header format is not perfect and might be optimized prior to | |
37 releasing the diving computer. For now it is good to be compatible | |
38 with PC software available for checking the content of the logbook | |
39 | |
40 | |
41 @endverbatim | |
42 ****************************************************************************** | |
43 * @attention | |
44 * | |
45 * <h2><center>© COPYRIGHT(c) 2014 heinrichs weikamp</center></h2> | |
46 * | |
47 ****************************************************************************** | |
48 */ | |
49 | |
50 /* Includes ------------------------------------------------------------------*/ | |
51 #include <stdint.h> | |
52 #include <string.h> | |
53 #include "logbook.h" | |
54 //#include "test_vpm.h" | |
55 #include "externLogbookFlash.h" | |
56 #include "data_exchange.h" | |
57 #include "decom.h" | |
58 #include "tHome.h" // for tHome_findNextStop() | |
59 | |
60 /* Private types -------------------------------------------------------------*/ | |
61 | |
62 #define NUM_GASES 5 | |
63 | |
64 #define LOGBOOK_VERSION (0x30) | |
65 #define LOGBOOK_VERSION_OSTC3 (0x24) | |
66 | |
67 typedef struct /* don't forget to adjust void clear_divisor(void) */ | |
68 { | |
69 uint8_t temperature; | |
70 uint8_t deco_ndl; | |
71 uint8_t gradientFactor; | |
72 uint8_t ppo2; | |
73 uint8_t decoplan; | |
74 uint8_t cns; | |
75 uint8_t tank; | |
76 } SDivisor; | |
77 | |
78 /* Exported variables --------------------------------------------------------*/ | |
79 | |
80 /* Private variables ---------------------------------------------------------*/ | |
81 uint8_t data_store[10000]; | |
82 SLogbookHeader header; | |
83 SLogbookHeaderOSTC3 headerOSTC3; | |
84 SLogbookHeaderOSTC3compact headerOSTC3compact; | |
85 SSmallHeader smallHeader; | |
86 SDivisor divisor; | |
87 SDivisor divisorBackup; | |
88 | |
89 /* Private function prototypes -----------------------------------------------*/ | |
90 void clear_divisor(void); | |
91 void logbook_SetAverageDepth(float average_depth_meter); | |
92 void logbook_SetMinTemperature(float min_temperature_celsius); | |
93 void logbook_SetMaxCNS(float max_cns_percentage); | |
94 void logbook_SetCompartmentDesaturation(void); | |
95 void logbook_SetLastStop(float last_stop_depth_bar); | |
96 void logbook_writedata(void * data, int length_byte); | |
97 void logbook_UpdateHeader(void); | |
98 | |
99 /* Exported functions --------------------------------------------------------*/ | |
100 | |
101 /** used by test_vpm.c at the moment */ | |
102 void logbook_EndDive(void) | |
103 { | |
104 ext_flash_close_new_dive_log((uint8_t*) &header); | |
105 } | |
106 | |
107 | |
108 // =============================================================================== | |
109 // logbook_last_totalDiveCount | |
110 /// @brief Fix setting issues | |
111 /// @date 04-April-2016 | |
112 /// | |
113 /// @return diveNumber (totalDiveCounter) of latest log entry, 0 if not a valid header | |
114 // =============================================================================== | |
115 uint16_t logbook_lastDive_diveNumber(void) | |
116 { | |
117 SLogbookHeader tempLogbookHeader; | |
118 if(logbook_getHeader(0, &tempLogbookHeader)) | |
119 { | |
120 return tempLogbookHeader.diveNumber; | |
121 } | |
122 else | |
123 { | |
124 return 0; | |
125 } | |
126 } | |
127 | |
128 | |
129 /** | |
130 ****************************************************************************** | |
131 * @brief logbook_getCurrentHeader. / | |
132 * @author Peter Ryser | |
133 * @version V0.0.1 | |
134 * @date 22-April-2014 | |
135 ****************************************************************************** | |
136 * | |
137 * @return SLogbookHeader*: | |
138 */ | |
139 SLogbookHeader* logbook_getCurrentHeader(void) | |
140 { | |
141 return &header; | |
142 } | |
143 | |
144 /** | |
145 ****************************************************************************** | |
146 * @brief logbook_getHeaderOSTC3. / | |
147 * @author heinrichs weikamp gmbh | |
148 * @version V0.0.1 | |
149 * @date 26-Nov-2014 | |
150 ****************************************************************************** | |
151 * | |
152 * @param StepBackwards : 0 Last lokbook entry, 1 second to last entry, etc. | |
153 * @param SSLogbookHeader* pLogbookHeader: Output found LogbookHeader | |
154 * @return uint8_t : 1 = success | |
155 */ | |
156 /* | |
157 SLogbookHeaderOSTC3 * logbook_getHeaderOSTC3(uint8_t StepBackwards) | |
158 { | |
159 if(!logbook_getHeader(StepBackwards, &header)) | |
160 return 0; | |
161 else | |
162 { | |
163 logbook_build_ostc3header(); | |
164 return &headerOSTC3; | |
165 } | |
166 } | |
167 */ | |
168 | |
169 /** | |
170 ****************************************************************************** | |
171 * @brief logbook_getNumberOfHeaders. / | |
172 * @author heinrichs weikamp gmbh | |
173 * @version V0.0.1 | |
174 * @date 18-May-2016 | |
175 ****************************************************************************** | |
176 * | |
177 * @return uint8_t : number of valid headers (0xFAFA) found. | |
178 */ | |
179 uint8_t logbook_getNumberOfHeaders(void) | |
180 { | |
181 return ext_flash_count_dive_headers(); | |
182 } | |
183 | |
184 | |
185 /** | |
186 ****************************************************************************** | |
187 * @brief logbook_getHeader. / | |
188 * @author Peter Ryser | |
189 * @version V0.0.1 | |
190 * @date 22-April-2014 | |
191 ****************************************************************************** | |
192 * | |
193 * @param StepBackwards : 0 Last lokbook entry, 1 second to last entry, etc. | |
194 * @param SSLogbookHeader* pLogbookHeader: Output found LogbookHeader | |
195 * @return uint8_t : 1 = success | |
196 */ | |
197 uint8_t logbook_getHeader(uint8_t StepBackwards,SLogbookHeader* pLogbookHeader) | |
198 { | |
199 ext_flash_read_dive_header((uint8_t *)pLogbookHeader, StepBackwards); | |
200 if(pLogbookHeader->diveHeaderStart != 0xFAFA) | |
201 return 0; | |
202 else | |
203 return 1; | |
204 } | |
205 | |
206 /** | |
207 ****************************************************************************** | |
208 * @brief logbook_initNewdiveProfile. / | |
209 * creates header and smallHeader from diveState and global Settings | |
210 * and writes new lookboock entry on flash device | |
211 * diveState | |
212 * @author Peter Ryser | |
213 * @version V0.0.1 | |
214 * @date 22-April-2014 | |
215 ****************************************************************************** | |
216 * | |
217 * @param SDiveState* pInfo: Input | |
218 * @param SSettings* pSettings: Input | |
219 */ | |
220 | |
221 void logbook_initNewdiveProfile(const SDiveState* pInfo, SSettings* pSettings) | |
222 { | |
223 RTC_DateTypeDef Sdate; | |
224 RTC_TimeTypeDef Stime; | |
225 | |
226 for(int i = 0; i < sizeof(SLogbookHeader); i++) | |
227 { | |
228 ((uint8_t*)(&header))[i] = 0; | |
229 } | |
230 header.diveHeaderStart = 0xFAFA; | |
231 header.diveHeaderEnd = 0xFBFB; | |
232 header.samplingRate = 2; | |
233 if(pInfo->diveSettings.diveMode == DIVEMODE_OC) | |
234 { | |
235 for(int i = 0; i < 5; i++) | |
236 { | |
237 header.gasordil[i].oxygen_percentage = pSettings->gas[i+1].oxygen_percentage; | |
238 header.gasordil[i].helium_percentage = pSettings->gas[i+1].helium_percentage; | |
239 header.gasordil[i].note.uw = pSettings->gas[i+1].note.uw; | |
240 header.gasordil[i].depth_meter = pSettings->gas[i+1].depth_meter; | |
241 } | |
242 } | |
243 else | |
244 { | |
245 for(int i = 0; i < 5; i++) | |
246 { | |
247 header.gasordil[i].oxygen_percentage = pSettings->gas[i+6].oxygen_percentage; | |
248 header.gasordil[i].helium_percentage = pSettings->gas[i+6].helium_percentage; | |
249 header.gasordil[i].note.uw = pSettings->gas[i+6].note.uw; | |
250 header.gasordil[i].depth_meter = pSettings->gas[i+6].depth_meter; | |
251 } | |
252 | |
253 for(int i = 0; i < 5; i++) | |
254 { | |
255 header.setpoint[i].setpoint_cbar = pSettings->setpoint[i+1].setpoint_cbar; | |
256 header.setpoint[i].depth_meter = pSettings->setpoint[i+1].depth_meter; | |
257 } | |
258 } | |
259 // header.gasordil[pInfo->lifeData.actualGas.GasIdInSettings].depth_meter = 0; | |
260 | |
261 translateDate(pInfo->lifeData.dateBinaryFormat, &Sdate); | |
262 translateTime(pInfo->lifeData.timeBinaryFormat, &Stime); | |
263 header.dateYear = Sdate.Year; | |
264 header.dateMonth = Sdate.Month; | |
265 header.dateDay = Sdate.Date; | |
266 header.timeHour = Stime.Hours; | |
267 header.timeMinute = Stime.Minutes; | |
268 header.cnsAtBeginning = (uint16_t)((pInfo->lifeData.cns * 100) + 0.5f); | |
269 header.surfacePressure_mbar = (uint16_t)(pInfo->lifeData.pressure_surface_bar * 1000); | |
270 header.firmwareVersionHigh = firmwareVersion_16bit_high(); | |
271 header.firmwareVersionLow = firmwareVersion_16bit_low(); | |
272 header.logbookProfileVersion = LOGBOOK_VERSION; | |
273 header.salinity = pSettings->salinity; | |
274 header.diveNumber = pSettings->totalDiveCounter; | |
275 header.personalDiveCount = pSettings->personalDiveCount; | |
276 | |
277 header.diveMode = pInfo->diveSettings.diveMode; | |
278 header.CCRmode = pInfo->diveSettings.CCR_Mode; | |
279 header.lastDecostop_m = pSettings->last_stop_depth_meter; | |
280 | |
281 if(pInfo->diveSettings.deco_type.ub.standard == GF_MODE) | |
282 { | |
283 header.decoModel = 1; | |
284 header.gfLow_or_Vpm_conservatism = pInfo->diveSettings.gf_low; | |
285 header.gfHigh = pInfo->diveSettings.gf_high; | |
286 } | |
287 else | |
288 { | |
289 header.decoModel = 2; | |
290 header.gfLow_or_Vpm_conservatism = pInfo->diveSettings.vpm_conservatism; | |
291 header.gfHigh = 0; | |
292 } | |
293 | |
294 memcpy(header.n2Compartments, pInfo->lifeData.tissue_nitrogen_bar, 64); | |
295 memcpy(header.heCompartments, pInfo->lifeData.tissue_helium_bar, 64); | |
296 | |
297 logbook_SetCompartmentDesaturation(); | |
298 | |
299 ext_flash_start_new_dive_log_and_set_actualPointerSample((uint8_t*)&header); | |
300 | |
301 smallHeader.profileLength[0] = 0xFF; | |
302 smallHeader.profileLength[1] = 0xFF; | |
303 smallHeader.profileLength[2] = 0xFF; | |
304 smallHeader.samplingRate_seconds = 2; | |
305 smallHeader.numDivisors = 7; | |
306 | |
307 smallHeader.tempType = 0; | |
308 smallHeader.tempLength = 2; | |
309 smallHeader.tempDivisor = 6; | |
310 | |
311 smallHeader.deco_ndlType = 1; | |
312 smallHeader.deco_ndlLength = 2; | |
313 smallHeader.deco_ndlDivisor = 6; //= 6; | |
314 | |
315 /* GF in % at actual position */ | |
316 smallHeader.gfType = 2; | |
317 smallHeader.gfLength = 1; | |
318 smallHeader.gfDivisor = 0; //12; | |
319 | |
320 /* 3 Sensors: 8bit ppO2 in 0.01bar, 16bit voltage in 0,1mV */ | |
321 smallHeader.ppo2Type = 3; | |
322 smallHeader.ppo2Length = 9; | |
323 smallHeader.ppo2Divisor = 2; //2 | |
324 | |
325 /* last 15 stops in minutes (last, second_to_last, ... */ | |
326 /* last stop depth is defined in header */ | |
327 smallHeader.decoplanType = 4; | |
328 smallHeader.decoplanLength = 15; | |
329 smallHeader.decoplanDivisor = 12;//12; | |
330 | |
331 smallHeader.cnsType = 5; | |
332 smallHeader.cnsLength = 2; | |
333 smallHeader.cnsDivisor = 12; | |
334 | |
335 smallHeader.tankType = 6; | |
336 smallHeader.tankLength = 0; | |
337 smallHeader.tankDivisor = 0; | |
338 | |
339 logbook_writedata((void *) &smallHeader,sizeof(smallHeader)); | |
340 | |
341 clear_divisor(); | |
342 } | |
343 | |
344 /** | |
345 ****************************************************************************** | |
346 * @brief clear_divisor / clears divisor struct | |
347 * @author Peter Ryser | |
348 * @version V0.0.1 | |
349 * @date 22-April-2014 | |
350 ****************************************************************************** | |
351 * | |
352 */ | |
353 void clear_divisor(void) | |
354 { | |
355 divisor.cns = smallHeader.cnsDivisor - 1; | |
356 divisor.decoplan = smallHeader.decoplanDivisor - 1; | |
357 divisor.deco_ndl = smallHeader.deco_ndlDivisor - 1; | |
358 divisor.gradientFactor = smallHeader.gfDivisor -1 ; | |
359 divisor.ppo2 = smallHeader.ppo2Divisor - 1; | |
360 divisor.tank = smallHeader.tankDivisor - 1; | |
361 divisor.temperature = smallHeader.tempDivisor - 1; | |
362 } | |
363 | |
364 | |
365 /** | |
366 ****************************************************************************** | |
367 * @brief add16. / adds 16 bit variable to 8 bit array | |
368 * @author Peter Ryser | |
369 * @version V0.0.1 | |
370 * @date 22-April-2014 | |
371 ****************************************************************************** | |
372 * | |
373 * @param uint8_t *pos: Output 8 bit array | |
374 * @param uint16_t var: 16 bit variable | |
375 */ | |
376 void addU16(uint8_t *pos, uint16_t var) | |
377 { | |
378 *((uint16_t*)pos) = var; | |
379 } | |
380 | |
381 void addS16(uint8_t *pos, int16_t var) | |
382 { | |
383 *((int16_t*)pos) = var; | |
384 } | |
385 | |
386 /** | |
387 ****************************************************************************** | |
388 * @brief logbook_writeSample. / Writes one logbook sampl | |
389 * @author Peter Ryser | |
390 * @date 22-April-2014 | |
391 * @version V0.0.2 | |
392 * @since 20-June-2016 | |
393 * @bug Deco/NDL Status fixed in V0.0.2 | |
394 | |
395 | |
396 ****************************************************************************** | |
397 * | |
398 * @param SDiveState state: | |
399 */ | |
400 | |
401 void logbook_writeSample(SDiveState state) | |
402 { | |
403 uint8_t sample[256]; | |
404 // int position = 0; | |
405 int length = 0; | |
406 // _Bool bEvent = 0; | |
407 uint8_t nextstopDepthMeter = 0; | |
408 uint16_t nextstopLengthSeconds = 0; | |
409 uint8_t nextstopLengthMinutes = 0; | |
410 bit8_Type eventByte1, eventByte2; | |
411 bit8_Type profileByteFlag; | |
412 int i = 0; | |
413 for(i = 0; i <256 ;i++) | |
414 sample[i] = 0; | |
415 addU16(sample, (uint16_t)(state.lifeData.depth_meter * 100)); | |
416 length += 2; | |
417 sample[2] = 0; | |
418 length++; | |
419 eventByte1.uw = 0; | |
420 eventByte2.uw = 0; | |
421 //uint16_t tmpU16 = 0; | |
422 const SDecoinfo * pDecoinfo; // new hw 160620 | |
423 | |
424 //BuildEevntyte 1 | |
425 // sub old 0-3 only one at a time | |
426 if(state.events.manualMarker) | |
427 { | |
428 eventByte1.uw = 6; | |
429 } | |
430 else | |
431 if(state.warnings.decoMissed) | |
432 { | |
433 eventByte1.uw = 2; | |
434 } | |
435 else | |
436 if(state.warnings.ppO2Low) | |
437 { | |
438 eventByte1.uw = 4; | |
439 } | |
440 else | |
441 if(state.warnings.ppO2High) | |
442 { | |
443 eventByte1.uw = 5; | |
444 } | |
445 else | |
446 if(state.warnings.lowBattery) | |
447 { | |
448 eventByte1.uw = 7; | |
449 } | |
450 else | |
451 if(state.warnings.slowWarning) | |
452 { | |
453 eventByte1.uw = 1; | |
454 } | |
455 // sub bit 4 to 7 | |
456 if(state.events.manuelGasSet) | |
457 { | |
458 eventByte1.ub.bit4 = 1; | |
459 } | |
460 if(state.events.gasChange) | |
461 { | |
462 eventByte1.ub.bit5 = 1; | |
463 } | |
464 if(state.events.setpointChange) | |
465 { | |
466 eventByte1.ub.bit6 = 1; | |
467 } | |
468 // sub bit 7 + eventbyte2 | |
469 if(state.events.bailout) | |
470 { | |
471 eventByte1.ub.bit7 = 1; | |
472 eventByte2.ub.bit0 = 1; | |
473 } | |
474 //Add EventByte 1 | |
475 if(eventByte1.uw > 0) | |
476 { | |
477 sample[length] = eventByte1.uw; | |
478 length++; | |
479 } | |
480 if(eventByte2.uw > 0) | |
481 { | |
482 sample[length] = eventByte2.uw; | |
483 length++; | |
484 } | |
485 //Add EventInfos | |
486 if(state.events.manuelGasSet) | |
487 { | |
488 //manual gas in %O2 & %He | |
489 sample[length] = state.events.info_manuelGasSetO2; | |
490 length += 1; | |
491 sample[length] = state.events.info_manuelGasSetHe; | |
492 length += 1; | |
493 } | |
494 if(state.events.gasChange) | |
495 { | |
496 //Current gas (gasid) | |
497 sample[length] = state.events.info_GasChange; | |
498 length += 1; | |
499 } | |
500 if(state.events.setpointChange) | |
501 { | |
502 //New setpoint in cbar | |
503 sample[length] = state.events.info_SetpointChange; | |
504 length += 1; | |
505 } | |
506 if(state.events.bailout) | |
507 { | |
508 //bailout gas in % O2 & %He | |
509 sample[length] = state.events.info_bailoutO2; | |
510 length += 1; | |
511 sample[length] = state.events.info_bailoutHe; | |
512 length += 1; | |
513 } | |
514 | |
515 | |
516 if(divisor.temperature == 0) | |
517 { | |
518 divisor.temperature = smallHeader.tempDivisor - 1; | |
519 addS16(&sample[length], (int16_t)((state.lifeData.temperature_celsius * 10.0f) + 0.5f)); | |
520 length += 2; | |
521 } | |
522 else | |
523 { | |
524 divisor.temperature--; | |
525 } | |
526 | |
527 | |
528 if(smallHeader.deco_ndlDivisor > 0) | |
529 { | |
530 if(divisor.deco_ndl == 0) | |
531 { | |
532 divisor.deco_ndl = smallHeader.deco_ndlDivisor - 1; | |
533 | |
534 if(stateUsed->diveSettings.deco_type.ub.standard == GF_MODE) | |
535 pDecoinfo = &stateUsed->decolistBuehlmann; | |
536 else if(stateUsed->diveSettings.deco_type.ub.standard == VPM_MODE) | |
537 pDecoinfo = &stateUsed->decolistVPM; | |
538 else // should not happen as only GF and VPM at the moment | |
539 { | |
540 sample[length] = 0; | |
541 length += 1; | |
542 sample[length] = 0; | |
543 length += 1; | |
544 } | |
545 | |
546 if(pDecoinfo->output_ndl_seconds > 0) | |
547 { | |
548 sample[length] = 0; | |
549 length += 1; | |
550 sample[length] = (uint8_t)pDecoinfo->output_ndl_seconds / 60; | |
551 length += 1; | |
552 } | |
553 else if(pDecoinfo->output_time_to_surface_seconds) | |
554 { | |
555 tHome_findNextStop(pDecoinfo->output_stop_length_seconds, &nextstopDepthMeter, &nextstopLengthSeconds); | |
556 nextstopLengthMinutes = (nextstopLengthSeconds +59 ) / 60; | |
557 | |
558 sample[length] = nextstopDepthMeter; | |
559 length += 1; | |
560 sample[length] = nextstopLengthMinutes; | |
561 length += 1; | |
562 } | |
563 else | |
564 { | |
565 sample[length] = 0; | |
566 length += 1; | |
567 sample[length] = 0; | |
568 length += 1; | |
569 } | |
570 } | |
571 else | |
572 { | |
573 divisor.deco_ndl --; | |
574 } | |
575 } | |
576 | |
577 | |
578 if(smallHeader.ppo2Divisor) | |
579 { | |
580 if(divisor.ppo2 == 0) | |
581 { | |
582 divisor.ppo2 = smallHeader.ppo2Divisor - 1; | |
583 | |
584 for(int i = 0; i <3; i++) | |
585 { | |
586 sample[length] = (uint8_t)(state.lifeData.ppO2Sensor_bar[i] * 100.0f + 0.5f); | |
587 length += 1; | |
588 addU16(&sample[length], (uint16_t)(state.lifeData.sensorVoltage_mV[i] * 10.0f + 0.5f)); | |
589 length += 2; | |
590 } | |
591 } | |
592 else | |
593 { | |
594 divisor.ppo2--; | |
595 } | |
596 } | |
597 | |
598 | |
599 if(smallHeader.decoplanDivisor) | |
600 { | |
601 if(divisor.decoplan == 0) | |
602 { | |
603 divisor.decoplan = smallHeader.decoplanDivisor - 1; | |
604 if(state.diveSettings.deco_type.ub.standard == VPM_MODE) | |
605 { | |
606 for(int i = 0; i <15; i++) | |
607 { | |
608 sample[length] = state.decolistVPM.output_stop_length_seconds[i] / 60; | |
609 length += 1; | |
610 } | |
611 } | |
612 else if(state.diveSettings.deco_type.ub.standard == GF_MODE) | |
613 { | |
614 for(int i = 0; i <15; i++) | |
615 { | |
616 sample[length] = state.decolistBuehlmann.output_stop_length_seconds[i] / 60; | |
617 length += 1; | |
618 } | |
619 } | |
620 else | |
621 { | |
622 for(int i = 0; i <15; i++) | |
623 { | |
624 sample[length] = 0; | |
625 length += 1; | |
626 } | |
627 } | |
628 // add16(&sample[length], state.temperature); | |
629 //length += 2; | |
630 } | |
631 else | |
632 { | |
633 divisor.decoplan --; | |
634 } | |
635 } | |
636 if(divisor.cns == 0) | |
637 { | |
638 divisor.cns = smallHeader.cnsDivisor - 1; | |
639 //addU16(&sample[length], (uint16_t)(state.lifeData.cns * 100.0f + 0.5f)); | |
640 addU16(&sample[length], (uint16_t)(state.lifeData.cns)); // hw 151110 cns is 0 to 100 % and more (not 0 to 1.00 and more) | |
641 length += 2; | |
642 } | |
643 else | |
644 { | |
645 divisor.cns--; | |
646 } | |
647 | |
648 profileByteFlag.uw = length - 3; | |
649 if(eventByte1.uw) | |
650 { | |
651 profileByteFlag.ub.bit7 = 1; | |
652 } | |
653 sample[2] = profileByteFlag.uw; | |
654 logbook_writedata((void *) sample,length); | |
655 | |
656 } | |
657 | |
658 | |
659 | |
660 uint16_t actual_depth1; | |
661 uint16_t actual_depth2; | |
662 uint16_t actual_length1; | |
663 uint16_t actual_length2; | |
664 uint16_t actual_inum; | |
665 | |
666 /** | |
667 ****************************************************************************** | |
668 * @brief readSample. / Reads data of one logbook sample | |
669 * @author Peter Ryser | |
670 * @version V0.0.1 | |
671 * @date 22-April-2014 | |
672 ****************************************************************************** | |
673 * | |
674 * @param int32_t* depth: output Value | |
675 * @param int16_t * gasid: output Value | |
676 * @param int32_t* temperature: output Value | |
677 * @param int32_t* sensor1, sensor2, sensor3: output Value | |
678 * @param int32_t* cns: output Value | |
679 * @return bytes read / 0 = reading Error | |
680 */ | |
681 uint16_t readSample(int32_t* depth, int16_t * gasid, int16_t* setpoint_cbar, int32_t* temperature, int32_t* sensor1, int32_t* sensor2, int32_t* sensor3, int32_t* cns, SManualGas* manualGas, int16_t* bailout, int16_t* decostopDepth) | |
682 { | |
683 int length = 0; | |
684 _Bool bEvent = 0; | |
685 bit8_Type eventByte1, eventByte2; | |
686 bit8_Type profileByteFlag; | |
687 | |
688 eventByte1.uw = 0; | |
689 eventByte2.uw = 0; | |
690 uint8_t tempU8 = 0; | |
691 uint16_t temp = 0; | |
692 uint16_t bytesRead = 0; | |
693 | |
694 if(gasid) | |
695 *gasid = -1; | |
696 if(temperature) | |
697 *temperature = -1000; | |
698 if(sensor1) | |
699 *sensor1 = -1; | |
700 if(sensor2) | |
701 *sensor2 = -1; | |
702 if(sensor3) | |
703 *sensor3 = -1; | |
704 if(cns) | |
705 *cns = -1; | |
706 if(setpoint_cbar) | |
707 *setpoint_cbar = -1; | |
708 if(bailout) | |
709 *bailout = -1; | |
710 if(manualGas) | |
711 { | |
712 manualGas->percentageO2 =-1; | |
713 manualGas->percentageHe =-1; | |
714 } | |
715 if(decostopDepth) | |
716 *decostopDepth = -1; | |
717 | |
718 ext_flash_read_next_sample_part( (uint8_t*)&temp, 2); | |
719 if(depth) | |
720 *depth = (int32_t)temp; | |
721 bytesRead += 2; | |
722 | |
723 ext_flash_read_next_sample_part( &profileByteFlag.uw, 1); | |
724 bytesRead ++; | |
725 | |
726 bEvent = profileByteFlag.ub.bit7; | |
727 profileByteFlag.ub.bit7 = 0; | |
728 length = profileByteFlag.uw; | |
729 | |
730 if(bEvent) | |
731 { | |
732 ext_flash_read_next_sample_part( &eventByte1.uw, 1); | |
733 bytesRead ++; | |
734 | |
735 length--; | |
736 | |
737 //second event byte | |
738 if(eventByte1.ub.bit7) | |
739 { | |
740 ext_flash_read_next_sample_part( &eventByte2.uw, 1); | |
741 bytesRead ++; | |
742 length--; | |
743 } | |
744 else | |
745 { | |
746 eventByte2.uw = 0; | |
747 } | |
748 | |
749 //manual Gas Set | |
750 if( eventByte1.ub.bit4) | |
751 { | |
752 //Evaluate manual Gas | |
753 ext_flash_read_next_sample_part( (uint8_t*)&tempU8, 1); | |
754 bytesRead +=1; | |
755 length -= 1; | |
756 manualGas->percentageO2 = tempU8; | |
757 ext_flash_read_next_sample_part( (uint8_t*)&tempU8, 1); | |
758 bytesRead +=1; | |
759 length -= 1; | |
760 manualGas->percentageHe = tempU8; | |
761 if(gasid) | |
762 *gasid = 0; | |
763 } | |
764 //gas change | |
765 if( eventByte1.ub.bit5) | |
766 { | |
767 ext_flash_read_next_sample_part( &tempU8, 1); | |
768 bytesRead +=1; | |
769 length -= 1; | |
770 if(gasid) | |
771 *gasid = (uint16_t)tempU8; | |
772 } | |
773 //SetpointChange | |
774 if( eventByte1.ub.bit6) | |
775 { | |
776 ext_flash_read_next_sample_part( &tempU8, 1); | |
777 *setpoint_cbar = tempU8; | |
778 bytesRead +=1; | |
779 length -= 1; | |
780 } | |
781 | |
782 // second event Byte | |
783 //bailout | |
784 if(eventByte2.ub.bit1) | |
785 { | |
786 //evaluate bailout gas Gas | |
787 *bailout = 1; | |
788 | |
789 ext_flash_read_next_sample_part( (uint8_t*)&tempU8, 1); | |
790 bytesRead +=1; | |
791 length -= 1; | |
792 manualGas->percentageO2 = tempU8; | |
793 ext_flash_read_next_sample_part( (uint8_t*)&tempU8, 1); | |
794 bytesRead +=1; | |
795 length -= 1; | |
796 manualGas->percentageHe = tempU8; | |
797 | |
798 if(gasid) | |
799 *gasid = 0; | |
800 } | |
801 } | |
802 | |
803 if(divisor.temperature == 0) | |
804 { | |
805 divisor.temperature = smallHeader.tempDivisor - 1; | |
806 ext_flash_read_next_sample_part( (uint8_t*)&temp, 2); | |
807 bytesRead +=2; | |
808 length -= 2; | |
809 if(temperature) | |
810 { | |
811 *temperature = (int32_t)temp; | |
812 } | |
813 } | |
814 else | |
815 { | |
816 divisor.temperature--; | |
817 } | |
818 | |
819 if(smallHeader.deco_ndlDivisor > 0) | |
820 { | |
821 if(divisor.deco_ndl == 0) | |
822 { | |
823 divisor.deco_ndl = smallHeader.deco_ndlDivisor - 1; | |
824 ext_flash_read_next_sample_part( &tempU8, 1); | |
825 if(decostopDepth) | |
826 { | |
827 *decostopDepth = tempU8 * 100; | |
828 } | |
829 ext_flash_read_next_sample_part( &tempU8, 1); | |
830 bytesRead += 2; | |
831 length -= 2; | |
832 } | |
833 else | |
834 { | |
835 divisor.deco_ndl--; | |
836 } | |
837 } | |
838 | |
839 if(divisor.ppo2 == 0) | |
840 { | |
841 int32_t ppO2Tmp = 0; | |
842 divisor.ppo2 = smallHeader.ppo2Divisor -1; | |
843 for(int i = 0; i <3 ; i++) | |
844 { | |
845 ext_flash_read_next_sample_part( &tempU8, 1); | |
846 ppO2Tmp += tempU8; | |
847 bytesRead +=1; | |
848 length -= 1; | |
849 ext_flash_read_next_sample_part( (uint8_t*)&temp, 2); | |
850 bytesRead +=2; | |
851 length -= 2; | |
852 if(sensor1 && (i==0)) | |
853 *sensor1 = (((int32_t)tempU8) * 0xFFFF) + temp; | |
854 if(sensor2 && (i==1)) | |
855 *sensor2 = (((int32_t)tempU8) * 0xFFFF) + temp; | |
856 if(sensor3 && (i==2)) | |
857 *sensor3 = (((int32_t)tempU8) * 0xFFFF) + temp; | |
858 } | |
859 } | |
860 else | |
861 { | |
862 divisor.ppo2--; | |
863 } | |
864 | |
865 if(smallHeader.decoplanDivisor > 0) | |
866 { | |
867 if(divisor.decoplan == 0) | |
868 { | |
869 divisor.decoplan = smallHeader.decoplanDivisor - 1; | |
870 for(int i = 0; i <15; i++) | |
871 ext_flash_read_next_sample_part( &tempU8, 1); | |
872 bytesRead += 15; | |
873 length -= 15; | |
874 } | |
875 else | |
876 { | |
877 divisor.decoplan--; | |
878 } | |
879 } | |
880 | |
881 | |
882 | |
883 if(divisor.cns == 0) | |
884 { | |
885 divisor.cns = smallHeader.cnsDivisor - 1; | |
886 | |
887 ext_flash_read_next_sample_part( (uint8_t*)&temp, 2); | |
888 bytesRead +=2; | |
889 length -= 2; | |
890 if(cns) | |
891 { | |
892 *cns = (int32_t)temp; | |
893 } | |
894 } | |
895 else | |
896 { | |
897 divisor.cns--; | |
898 } | |
899 | |
900 if (length != 0) | |
901 return 0; | |
902 | |
903 return bytesRead; | |
904 } | |
905 /** | |
906 ****************************************************************************** | |
907 * @brief logbook_readSampleData. / Reads sample data of whole logbook entry | |
908 * @author Peter Ryser | |
909 * @version V0.0.1 | |
910 * @date 22-April-2014 | |
911 ****************************************************************************** | |
912 * | |
913 * @param uint8_t StepBackwards: witch lookbook entry? | |
914 * @param uint16_t length : maxlength of output arrays | |
915 * @param int32_t* depth : output array | |
916 * @param int16_t * gasid : output array | |
917 * @param int32_t* temperature : output array | |
918 * @param int32_t* ppo2 : output array | |
919 * @param int32_t* cns : output array | |
920 * @return length of output | |
921 */ | |
922 uint16_t logbook_readSampleData(uint8_t StepBackwards, uint16_t length,uint16_t* depth, uint8_t* gasid, int16_t* temperature, uint16_t* ppo2, uint16_t* setpoint, uint16_t* sensor1, uint16_t* sensor2, uint16_t* sensor3, uint16_t* cns, uint8_t* bailout, uint16_t* decostopDepth) | |
923 { | |
924 //Test read | |
925 //SLogbookHeader header; | |
926 | |
927 //logbook_getHeader(&header); | |
928 SLogbookHeader header; | |
929 int iNum; | |
930 int firstgasid = 0; | |
931 int retVal = 0; | |
932 int compression = 0; | |
933 int i; | |
934 // uint32_t diveTime_seconds; | |
935 int32_t depthVal = 0; | |
936 int16_t gasidVal = 0; | |
937 int16_t setPointVal = 0; | |
938 int16_t bailoutVal = 0; | |
939 int16_t bailoutLast = 0; | |
940 uint16_t setPointLast = 0; | |
941 int32_t temperatureVal = 0; | |
942 int32_t sensor1Val = 0; | |
943 int32_t sensor2Val = 0; | |
944 int32_t sensor3Val = 0; | |
945 int32_t sensor1Last = 0; | |
946 int32_t sensor2Last = 0; | |
947 int32_t sensor3Last = 0; | |
948 int32_t cnsVal = 0; | |
949 int32_t depthLast = 0; | |
950 int16_t gasidLast = 0; | |
951 int32_t temperatureLast = 0; | |
952 int32_t temperatureFirst = 0; | |
953 int32_t cnsLast = 0; | |
954 int16_t decostepDepthVal = 0; | |
955 int16_t decostepDepthLast = 0; | |
956 | |
957 SManualGas manualGasVal; | |
958 SManualGas manualGasLast; | |
959 manualGasLast.percentageO2 = 0; | |
960 manualGasLast.percentageHe = 0; | |
961 | |
962 float ambiant_pressure_bar = 0; | |
963 float ppO2 = 0; | |
964 ext_flash_read_dive_header((uint8_t*)&header, StepBackwards); | |
965 for(i = 0;i< 5;i++) | |
966 { | |
967 if(header.gasordil[i].note.ub.first) | |
968 break; | |
969 } | |
970 firstgasid = i + 1; | |
971 if(header.diveMode == DIVEMODE_CCR) | |
972 setPointLast = header.setpoint[0].setpoint_cbar; | |
973 else | |
974 setPointLast = 0; | |
975 //diveTime_seconds = header.diveTime_seconds ; | |
976 for(compression = 1; compression < 100; compression ++) | |
977 { | |
978 if((header.total_diveTime_seconds / header.samplingRate)/compression <= length) | |
979 break; | |
980 } | |
981 | |
982 | |
983 for(i = 0;i< length;i++) | |
984 { | |
985 if(depth) | |
986 depth[i] = 0; | |
987 if(temperature) | |
988 temperature[i] = 0; | |
989 if(gasid) | |
990 gasid[i] = 0; | |
991 if(ppo2) | |
992 ppo2[i] = 0; | |
993 if(setpoint) | |
994 setpoint[i] = 0; | |
995 if(sensor1) | |
996 sensor1[i] = 0; | |
997 if(sensor2) | |
998 sensor2[i] = 0; | |
999 if(sensor3) | |
1000 sensor3[i] = 0; | |
1001 if(cns) | |
1002 cns[i] = 0; | |
1003 } | |
1004 //We start with fist gasid | |
1005 gasidLast = firstgasid; | |
1006 | |
1007 | |
1008 //uint16_t* ppo2, uint16_t* cns# | |
1009 uint32_t totalNumberOfBytes = 0; | |
1010 uint32_t bytesRead = 0; | |
1011 ext_flash_open_read_sample( StepBackwards,&totalNumberOfBytes); | |
1012 ext_flash_read_next_sample_part((uint8_t*)&smallHeader, sizeof(SSmallHeader)); | |
1013 bytesRead += sizeof(SSmallHeader); | |
1014 | |
1015 clear_divisor(); | |
1016 | |
1017 iNum = 0; | |
1018 int counter = 0; | |
1019 temperatureLast = -1000; | |
1020 while ((bytesRead < totalNumberOfBytes) && (iNum < length)) | |
1021 { | |
1022 ext_flash_set_entry_point(); | |
1023 divisorBackup = divisor; | |
1024 retVal = readSample(&depthVal,&gasidVal, &setPointVal, &temperatureVal, &sensor1Val, &sensor2Val, &sensor3Val, &cnsVal, &manualGasVal, &bailoutVal, &decostepDepthVal); | |
1025 | |
1026 if(retVal == 0) | |
1027 { | |
1028 //Error try to read again!!! | |
1029 ext_flash_reopen_read_sample_at_entry_point(); | |
1030 divisor = divisorBackup; | |
1031 retVal = readSample(&depthVal,&gasidVal,&setPointVal, &temperatureVal, &sensor1Val, &sensor2Val, &sensor3Val, &cnsVal, &manualGasVal, &bailoutVal, &decostepDepthVal); | |
1032 | |
1033 if(retVal == 0) | |
1034 break; | |
1035 } | |
1036 bytesRead +=retVal; | |
1037 | |
1038 //if for some variable no new value is in the sample for (z.B. gasidVal = -1), we take the last value | |
1039 if(depthVal == -1) | |
1040 depthVal = depthLast; | |
1041 else | |
1042 depthLast = depthVal; | |
1043 | |
1044 if(gasidVal == -1) | |
1045 gasidVal = gasidLast; | |
1046 else | |
1047 gasidLast = gasidVal; | |
1048 | |
1049 if(temperatureVal == -1000) | |
1050 temperatureVal = temperatureLast; | |
1051 else | |
1052 { | |
1053 if(temperatureLast == -1000) | |
1054 temperatureFirst = temperatureVal; | |
1055 temperatureLast = temperatureVal; | |
1056 } | |
1057 | |
1058 if(setPointVal == -1) | |
1059 setPointVal = setPointLast; | |
1060 else | |
1061 setPointLast = setPointVal; | |
1062 | |
1063 if(sensor1Val == -1) | |
1064 sensor1Val = sensor1Last; | |
1065 else | |
1066 sensor1Last = sensor1Val; | |
1067 | |
1068 if(sensor2Val == -1) | |
1069 sensor2Val = sensor2Last; | |
1070 else | |
1071 sensor2Last = sensor2Val; | |
1072 | |
1073 if(sensor3Val == -1) | |
1074 sensor3Val = sensor3Last; | |
1075 else | |
1076 sensor3Last = sensor3Val; | |
1077 | |
1078 if(cnsVal == -1) | |
1079 cnsVal = cnsLast; | |
1080 else | |
1081 cnsLast = cnsVal; | |
1082 | |
1083 if(manualGasVal.percentageO2 == -1) | |
1084 manualGasVal = manualGasLast; | |
1085 else | |
1086 manualGasLast = manualGasVal; | |
1087 | |
1088 if(bailoutVal == -1) | |
1089 bailoutVal = bailoutLast; | |
1090 else | |
1091 bailoutLast = bailoutVal; | |
1092 | |
1093 if(decostepDepthVal == -1) | |
1094 decostepDepthVal = decostepDepthLast; | |
1095 else | |
1096 decostepDepthLast = decostepDepthVal; | |
1097 | |
1098 counter++; | |
1099 // Heed compression | |
1100 // Write here to arrays | |
1101 if(counter == compression) | |
1102 { | |
1103 if(depth) | |
1104 depth[iNum] = depthVal; | |
1105 if(gasid) | |
1106 gasid[iNum] = gasidVal; | |
1107 if(temperature) | |
1108 temperature[iNum] = temperatureVal; | |
1109 if(cns) | |
1110 cns[iNum] = cnsVal; | |
1111 if(bailout) | |
1112 bailout[iNum] = bailoutVal; | |
1113 if(decostopDepth) | |
1114 decostopDepth[iNum] = decostepDepthVal; | |
1115 | |
1116 if(ppo2) | |
1117 { | |
1118 //Calc ppo2 - Values | |
1119 SGas gas; | |
1120 gas.setPoint_cbar = setPointVal; | |
1121 if(gasidVal > 0) | |
1122 { | |
1123 gas.helium_percentage = header.gasordil[gasidVal - 1].helium_percentage; | |
1124 gas.nitrogen_percentage = 100 - gas.helium_percentage - header.gasordil[gasidVal - 1].oxygen_percentage; | |
1125 } | |
1126 else | |
1127 { | |
1128 gas.helium_percentage = manualGasVal.percentageHe; | |
1129 gas.nitrogen_percentage = 100 - gas.helium_percentage - manualGasVal.percentageO2; | |
1130 } | |
1131 ambiant_pressure_bar =((float)(depthVal + header.surfacePressure_mbar))/1000; | |
1132 ppO2 = decom_calc_ppO2(ambiant_pressure_bar, &gas ); | |
1133 ppo2[iNum] = (uint16_t) ( ppO2 * 100); | |
1134 } | |
1135 | |
1136 if(setpoint) | |
1137 setpoint[iNum] = setPointVal; | |
1138 | |
1139 if(sensor1) | |
1140 sensor1[iNum] = (sensor1Val / 0xFFFF) & 0xFF; | |
1141 if(sensor2) | |
1142 sensor2[iNum] = (sensor2Val / 0xFFFF) & 0xFF; | |
1143 if(sensor3) | |
1144 sensor3[iNum] = (sensor3Val / 0xFFFF) & 0xFF; | |
1145 iNum++; | |
1146 counter = 0; | |
1147 } | |
1148 } | |
1149 | |
1150 // Fix first Temperature Entries 150930 hw | |
1151 if(temperature) | |
1152 { | |
1153 int i = 0; | |
1154 while((temperature[i] == -1000) && (i < iNum)) | |
1155 temperature[i++] = temperatureFirst; | |
1156 } | |
1157 | |
1158 ext_flash_close_read_sample(); | |
1159 return iNum; | |
1160 } | |
1161 | |
1162 | |
1163 /******************************************************************************** | |
1164 * @brief logbook_InitAndWrite. / Controls writing of logbook | |
1165 * Should be called ten times per second | |
1166 * Automatically Initializes logbook at beginning of dive, | |
1167 * write samples every 2 seconds | |
1168 * and finishes logbook after end of dive | |
1169 *********************************************************************************/ | |
1170 | |
1171 void logbook_InitAndWrite(void) | |
1172 { | |
1173 SSettings *pSettings = settingsGetPointer(); | |
1174 static uint8_t bDiveMode = 0; | |
1175 static uint32_t tickstart = 0; | |
1176 uint32_t ticksdiff = 0; | |
1177 uint32_t lasttick = 0; | |
1178 static float min_temperature_float_celsius = 0; | |
1179 | |
1180 const SDiveState * pStateReal = stateRealGetPointer(); | |
1181 | |
1182 if(!bDiveMode) | |
1183 { | |
1184 if((pStateReal->mode == MODE_DIVE) && (pStateReal->diveSettings.diveMode != DIVEMODE_Apnea) && (pStateReal->lifeData.dive_time_seconds >= 5)) | |
1185 { | |
1186 //InitdiveProfile | |
1187 pSettings->totalDiveCounter++; | |
1188 logbook_initNewdiveProfile(pStateReal,settingsGetPointer()); | |
1189 min_temperature_float_celsius = pStateReal->lifeData.temperature_celsius; | |
1190 //Write logbook sample | |
1191 logbook_writeSample(*pStateReal); | |
1192 resetEvents(); | |
1193 tickstart = HAL_GetTick(); | |
1194 bDiveMode = 1; | |
1195 } | |
1196 } | |
1197 else if((pStateReal->mode == MODE_DIVE) && (pStateReal->diveSettings.diveMode != DIVEMODE_Apnea)) | |
1198 { | |
1199 lasttick = HAL_GetTick(); | |
1200 ticksdiff = time_elapsed_ms(tickstart,lasttick); | |
1201 // | |
1202 if(ticksdiff >= 2000) | |
1203 { | |
1204 //Write logbook sample | |
1205 logbook_writeSample(*pStateReal); | |
1206 resetEvents(); | |
1207 if(min_temperature_float_celsius > pStateReal->lifeData.temperature_celsius) | |
1208 min_temperature_float_celsius = pStateReal->lifeData.temperature_celsius; | |
1209 tickstart = lasttick; | |
1210 if((bDiveMode == 1) && (pStateReal->lifeData.dive_time_seconds >= pSettings->divetimeToCreateLogbook)) | |
1211 { | |
1212 ext_flash_create_new_dive_log((uint8_t*)&header); | |
1213 /** save settings | |
1214 * with new lastDiveLogId and time and day | |
1215 */ | |
1216 pSettings->personalDiveCount++; | |
1217 if(pSettings->logbookOffset) | |
1218 { | |
1219 pSettings->logbookOffset++; | |
1220 } | |
1221 ext_flash_write_settings(); | |
1222 ext_flash_disable_protection_for_logbook(); | |
1223 bDiveMode = 3; | |
1224 } | |
1225 if(bDiveMode == 3) | |
1226 logbook_UpdateHeader(); | |
1227 } | |
1228 } | |
1229 else if(bDiveMode == 3) | |
1230 { | |
1231 //End of Dive | |
1232 logbook_SetAverageDepth(pStateReal->lifeData.average_depth_meter); | |
1233 logbook_SetMinTemperature(min_temperature_float_celsius); | |
1234 logbook_SetMaxCNS(pStateReal->lifeData.cns); | |
1235 logbook_SetCompartmentDesaturation(); | |
1236 logbook_SetLastStop(pStateReal->diveSettings.last_stop_depth_bar); | |
1237 logbook_EndDive(); | |
1238 bDiveMode = 0; | |
1239 } else | |
1240 { | |
1241 ext_flash_enable_protection(); | |
1242 } | |
1243 } | |
1244 | |
1245 | |
1246 /* Private functions ---------------------------------------------------------*/ | |
1247 | |
1248 /******************************************************************************** | |
1249 * @brief logbook_UpdateHeader. / | |
1250 * set date, time, max depth. etc. pp. | |
1251 * the internal pointer to the end of profile and length will be set by | |
1252 ext_flash_close_new_dive_log() in externLogbookFlash.c | |
1253 * @author heinrichs weikamp gmbh | |
1254 * @version V0.0.1 | |
1255 * @date 27-Nov-2014 | |
1256 *********************************************************************************/ | |
1257 void logbook_UpdateHeader(void) | |
1258 { | |
1259 const SDiveState * pStateReal = stateRealGetPointer(); | |
1260 SSettings *pSettings = settingsGetPointer(); | |
1261 // uint16_t secondsAtShallow = 0; | |
1262 RTC_DateTypeDef Sdate; | |
1263 RTC_TimeTypeDef Stime; | |
1264 uint32_t time1_u32, time2_u32; | |
1265 uint32_t divetimeHelper; | |
1266 | |
1267 /* time and day */ | |
1268 /* don't update CHANGE 160224 hw, maybe save actual time and date at other place | |
1269 translateDate(pStateReal->lifeData.dateBinaryFormat, &Sdate); | |
1270 translateTime(pStateReal->lifeData.timeBinaryFormat, &Stime); | |
1271 | |
1272 header.dateYear = Sdate.Year; | |
1273 header.dateMonth = Sdate.Month; | |
1274 header.dateDay = Sdate.Date; | |
1275 header.timeHour = Stime.Hours; | |
1276 header.timeMinute = Stime.Minutes; | |
1277 */ | |
1278 /// 160315 Quick fix for empty date problem | |
1279 if((!(header.dateYear)) || (!(header.dateMonth)) || (!(header.dateDay))) | |
1280 { | |
1281 translateDate(pStateReal->lifeData.dateBinaryFormat, &Sdate); | |
1282 translateTime(pStateReal->lifeData.timeBinaryFormat, &Stime); | |
1283 | |
1284 header.dateYear = Sdate.Year; | |
1285 header.dateMonth = Sdate.Month; | |
1286 header.dateDay = Sdate.Date; | |
1287 | |
1288 time1_u32 = (uint32_t)header.timeMinute + (uint32_t)(header.timeHour * 60); | |
1289 time2_u32 = (uint32_t)Stime.Minutes + (uint32_t)(Stime.Hours * 60); | |
1290 if(time2_u32 < time1_u32) | |
1291 { | |
1292 if(header.dateDay > 1) | |
1293 { | |
1294 header.dateDay -= 1; | |
1295 } | |
1296 else | |
1297 { | |
1298 header.dateMonth --; | |
1299 if(!header.dateMonth) | |
1300 { | |
1301 header.dateYear--; | |
1302 header.dateMonth = 12; | |
1303 header.dateDay = 31; | |
1304 } | |
1305 else | |
1306 { | |
1307 if(header.dateMonth == 2) | |
1308 header.dateDay = 28; | |
1309 else | |
1310 if((header.dateMonth == 4) || (header.dateMonth == 6) || (header.dateMonth == 9) || (header.dateMonth == 11)) | |
1311 header.dateDay = 30; | |
1312 else | |
1313 header.dateDay = 31; | |
1314 } | |
1315 } | |
1316 } | |
1317 } | |
1318 | |
1319 /* duration */ | |
1320 header.total_diveTime_seconds = pStateReal->lifeData.dive_time_seconds; | |
1321 header.maxDepth = pStateReal->lifeData.max_depth_meter * 100; | |
1322 | |
1323 /* old: | |
1324 | |
1325 secondsAtShallow = pSettings->timeoutDiveReachedZeroDepth; | |
1326 if(pStateReal->lifeData.dive_time_seconds <= secondsAtShallow) | |
1327 secondsAtShallow = 0; | |
1328 header.diveTimeMinutes = (header.total_diveTime_seconds - secondsAtShallow )/ 60; | |
1329 header.diveTimeSeconds = header.total_diveTime_seconds - secondsAtShallow - (header.diveTimeMinutes * 60); | |
1330 */ | |
1331 divetimeHelper = pStateReal->lifeData.dive_time_seconds_without_surface_time; | |
1332 header.diveTimeMinutes = (uint16_t)(divetimeHelper/60); | |
1333 divetimeHelper -= 60 * (uint32_t)header.diveTimeMinutes; | |
1334 header.diveTimeSeconds = (uint16_t)divetimeHelper; | |
1335 | |
1336 /* deco algorithm (final) */ | |
1337 if(pStateReal->diveSettings.deco_type.ub.standard == GF_MODE) | |
1338 { | |
1339 header.decoModel = 1; | |
1340 header.gfLow_or_Vpm_conservatism = pStateReal->diveSettings.gf_low; | |
1341 header.gfHigh = pStateReal->diveSettings.gf_high; | |
1342 } | |
1343 else | |
1344 { | |
1345 header.decoModel = 2; | |
1346 header.gfLow_or_Vpm_conservatism = pStateReal->diveSettings.vpm_conservatism; | |
1347 header.gfHigh = 0; | |
1348 } | |
1349 | |
1350 /* tissue load */ | |
1351 memcpy(header.n2Compartments, pStateReal->lifeData.tissue_nitrogen_bar, 64); | |
1352 memcpy(header.heCompartments, pStateReal->lifeData.tissue_helium_bar, 64); | |
1353 | |
1354 } | |
1355 | |
1356 | |
1357 void logbook_SetAverageDepth(float average_depth_meter) | |
1358 { | |
1359 header.averageDepth_mbar = (uint16_t)(average_depth_meter * 100); | |
1360 } | |
1361 | |
1362 | |
1363 void logbook_SetMinTemperature(float min_temperature_celsius) | |
1364 { | |
1365 header.minTemp = (int16_t)((min_temperature_celsius * 10.0f) + 0.5f); | |
1366 } | |
1367 | |
1368 | |
1369 void logbook_SetMaxCNS(float max_cns_percentage) | |
1370 { | |
1371 if(max_cns_percentage < 9999) | |
1372 header.maxCNS = (uint16_t)(max_cns_percentage); | |
1373 else | |
1374 header.maxCNS = 9999; | |
1375 } | |
1376 | |
1377 | |
1378 void logbook_SetDesaturationTime(void) | |
1379 { | |
1380 header.desaturationTime = 48 * 60; | |
1381 } | |
1382 | |
1383 | |
1384 void logbook_SetCompartmentDesaturation(void) | |
1385 { | |
1386 const SDiveState * pStateReal = stateRealGetPointer(); | |
1387 | |
1388 decom_tissues_desaturation_time(&pStateReal->lifeData, &secondaryInformation); | |
1389 for(int i=0;i<16;i++) | |
1390 { | |
1391 if(secondaryInformation.tissue_nitrogen_desaturation_time_minutes[i] <= (15 * 255)) | |
1392 header.n2CompartDesatTime_min[i] = (uint8_t)((secondaryInformation.tissue_nitrogen_desaturation_time_minutes[i] + 14) / 15); | |
1393 else | |
1394 header.n2CompartDesatTime_min[i] = 255; | |
1395 if(secondaryInformation.tissue_helium_desaturation_time_minutes[i] <= (15 * 255)) | |
1396 header.heCompartDesatTime_min[i] = (uint8_t)((secondaryInformation.tissue_helium_desaturation_time_minutes[i] + 14 )/ 15); | |
1397 else | |
1398 header.heCompartDesatTime_min[i] = 255; | |
1399 } | |
1400 } | |
1401 | |
1402 void logbook_SetLastStop(float last_stop_depth_bar) | |
1403 { | |
1404 header.lastDecostop_m = (uint8_t)(last_stop_depth_bar / 10.0f); | |
1405 } | |
1406 | |
1407 void logbook_writedata(void * data, int length_byte) | |
1408 { | |
1409 ext_flash_write_sample(data, length_byte); | |
1410 } | |
1411 | |
1412 | |
1413 /******************************************************************************** | |
1414 * @brief logbook_build_ostc3header. / | |
1415 * @author heinrichs weikamp gmbh | |
1416 * @version V0.0.2 | |
1417 * @date 27-Nov-2014 | |
1418 *********************************************************************************/ | |
1419 SLogbookHeaderOSTC3 * logbook_build_ostc3header(SLogbookHeader* pHead) | |
1420 { | |
1421 convert_Type data; | |
1422 | |
1423 memcpy(headerOSTC3.diveHeaderStart, &pHead->diveHeaderStart, 2); | |
1424 memcpy(headerOSTC3.pBeginProfileData, &pHead->pBeginProfileData, 3); | |
1425 memcpy(headerOSTC3.pEndProfileData, &pHead->pEndProfileData, 3); | |
1426 | |
1427 data.u8bit.byteHigh = 0; | |
1428 data.u8bit.byteLow = pHead->profileLength[0]; | |
1429 data.u8bit.byteMidLow = pHead->profileLength[1]; | |
1430 data.u8bit.byteMidHigh = pHead->profileLength[2]; | |
1431 | |
1432 if(data.u32bit != 0xFFFFFF) | |
1433 data.u32bit += 3; | |
1434 | |
1435 headerOSTC3.profileLength[0] = data.u8bit.byteLow; | |
1436 headerOSTC3.profileLength[1] = data.u8bit.byteMidLow; | |
1437 headerOSTC3.profileLength[2] = data.u8bit.byteMidHigh; | |
1438 | |
1439 memcpy(headerOSTC3.gasordil, pHead->gasordil, 20); | |
1440 | |
1441 if(pHead->logbookProfileVersion == LOGBOOK_VERSION) | |
1442 { | |
1443 headerOSTC3.logbookProfileVersion = LOGBOOK_VERSION_OSTC3; | |
1444 memcpy(headerOSTC3.personalDiveCount, &pHead->personalDiveCount, 2); | |
1445 headerOSTC3.safetyDistance_10cm = 0; | |
1446 | |
1447 for(int i=0;i<5;i++) | |
1448 { | |
1449 if(!pHead->gasordil[i].note.ub.active) | |
1450 headerOSTC3.gasordil[3 + (i*4)] = 0; | |
1451 else if(pHead->gasordil[i].note.ub.first) | |
1452 { | |
1453 /* depth = 0, note = 1 */ | |
1454 headerOSTC3.gasordil[2 + (i*4)] = 0; | |
1455 headerOSTC3.gasordil[3 + (i*4)] = 1; | |
1456 } | |
1457 else if( pHead->gasordil[i].depth_meter) | |
1458 { | |
1459 /* note = 3 */ | |
1460 headerOSTC3.gasordil[3 + (i*4)] = 3; | |
1461 } | |
1462 } | |
1463 } | |
1464 else | |
1465 { | |
1466 headerOSTC3.logbookProfileVersion = 0xFF; | |
1467 headerOSTC3.personalDiveCount[0] = 0xFF; | |
1468 headerOSTC3.personalDiveCount[1] = 0xFF; | |
1469 headerOSTC3.safetyDistance_10cm = 0xFF; | |
1470 } | |
1471 | |
1472 headerOSTC3.dateYear = pHead->dateYear; | |
1473 headerOSTC3.dateMonth = pHead->dateMonth; | |
1474 headerOSTC3.dateDay = pHead->dateDay; | |
1475 headerOSTC3.timeHour = pHead->timeHour; | |
1476 headerOSTC3.timeMinute = pHead->timeMinute; | |
1477 | |
1478 | |
1479 memcpy(headerOSTC3.maxDepth, &pHead->maxDepth, 2); | |
1480 memcpy(headerOSTC3.diveTimeMinutes, &pHead->diveTimeMinutes, 2); | |
1481 | |
1482 headerOSTC3.diveTimeSeconds = pHead->diveTimeSeconds; | |
1483 | |
1484 memcpy(headerOSTC3.minTemp, &pHead->minTemp, 2); | |
1485 memcpy(headerOSTC3.surfacePressure_mbar,&pHead->surfacePressure_mbar, 2); | |
1486 memcpy(headerOSTC3.desaturationTime, &pHead->desaturationTime, 2); | |
1487 | |
1488 headerOSTC3.firmwareVersionHigh = pHead->firmwareVersionHigh; | |
1489 headerOSTC3.firmwareVersionLow = pHead->firmwareVersionLow; | |
1490 | |
1491 memcpy(headerOSTC3.batteryVoltage, &pHead->batteryVoltage, 2); | |
1492 | |
1493 headerOSTC3.samplingRate = pHead->samplingRate; | |
1494 | |
1495 memcpy(headerOSTC3.cnsAtBeginning, &pHead->cnsAtBeginning, 2); | |
1496 | |
1497 headerOSTC3.gfAtBeginning = pHead->gfAtBeginning; | |
1498 headerOSTC3.gfAtEnd = pHead->gfAtEnd; | |
1499 | |
1500 memcpy(headerOSTC3.setpoint, pHead->setpoint, 10); | |
1501 | |
1502 headerOSTC3.salinity = pHead->salinity; | |
1503 | |
1504 memcpy(headerOSTC3.maxCNS, &pHead->maxCNS, 2); | |
1505 memcpy(headerOSTC3.averageDepth_mbar, &pHead->averageDepth_mbar, 2); | |
1506 memcpy(headerOSTC3.total_diveTime_seconds,&pHead->total_diveTime_seconds, 2); | |
1507 | |
1508 headerOSTC3.gfLow_or_Vpm_conservatism = pHead->gfLow_or_Vpm_conservatism; | |
1509 headerOSTC3.gfHigh = pHead->gfHigh; | |
1510 headerOSTC3.decoModel = pHead->decoModel; | |
1511 | |
1512 memcpy(headerOSTC3.diveNumber, &pHead->diveNumber, 2); | |
1513 | |
1514 headerOSTC3.diveMode = pHead->diveMode; | |
1515 headerOSTC3.CCRmode = pHead->CCRmode; | |
1516 | |
1517 memcpy(headerOSTC3.n2CompartDesatTime_min,pHead->n2CompartDesatTime_min, 16); | |
1518 memcpy(headerOSTC3.n2Compartments, pHead->n2Compartments, 64); | |
1519 memcpy(headerOSTC3.heCompartDesatTime_min,pHead->heCompartDesatTime_min, 16); | |
1520 memcpy(headerOSTC3.heCompartments, pHead->heCompartments, 64); | |
1521 | |
1522 headerOSTC3.lastDecostop_m = pHead->lastDecostop_m; | |
1523 | |
1524 memcpy(headerOSTC3.hwHudBattery_mV, &pHead->hwHudBattery_mV, 2); | |
1525 | |
1526 headerOSTC3.hwHudLastStatus = pHead->hwHudLastStatus; | |
1527 | |
1528 memcpy(headerOSTC3.batteryGaugeRegisters,&pHead->batteryGaugeRegisters, 6); | |
1529 | |
1530 | |
1531 memcpy(headerOSTC3.diveHeaderEnd, &pHead->diveHeaderEnd, 2); | |
1532 | |
1533 return &headerOSTC3; | |
1534 } | |
1535 | |
1536 | |
1537 /******************************************************************************** | |
1538 * @brief logbook_build_ostc3header_compact. / | |
1539 * @author heinrichs weikamp gmbh | |
1540 * @version V0.0.1 | |
1541 * @date 31-Juli-2015 | |
1542 *********************************************************************************/ | |
1543 SLogbookHeaderOSTC3compact * logbook_build_ostc3header_compact(SLogbookHeader* pHead) | |
1544 { | |
1545 convert_Type data; | |
1546 | |
1547 data.u8bit.byteHigh = 0; | |
1548 data.u8bit.byteLow = pHead->profileLength[0]; | |
1549 data.u8bit.byteMidLow = pHead->profileLength[1]; | |
1550 data.u8bit.byteMidHigh = pHead->profileLength[2]; | |
1551 | |
1552 if(data.u32bit != 0xFFFFFF) | |
1553 { | |
1554 data.u32bit += 3; | |
1555 | |
1556 headerOSTC3compact.profileLength[0] = data.u8bit.byteLow; | |
1557 headerOSTC3compact.profileLength[1] = data.u8bit.byteMidLow; | |
1558 headerOSTC3compact.profileLength[2] = data.u8bit.byteMidHigh; | |
1559 | |
1560 headerOSTC3compact.dateYear = pHead->dateYear; | |
1561 headerOSTC3compact.dateMonth = pHead->dateMonth; | |
1562 headerOSTC3compact.dateDay = pHead->dateDay; | |
1563 headerOSTC3compact.timeHour = pHead->timeHour; | |
1564 headerOSTC3compact.timeMinute = pHead->timeMinute; | |
1565 | |
1566 memcpy(headerOSTC3compact.maxDepth, &pHead->maxDepth, 2); | |
1567 memcpy(headerOSTC3compact.diveTimeMinutes, &pHead->diveTimeMinutes, 2); | |
1568 | |
1569 headerOSTC3compact.diveTimeSeconds = pHead->diveTimeSeconds; | |
1570 | |
1571 | |
1572 headerOSTC3compact.totalDiveNumberLow = pHead->diveNumber & 0xFF; | |
1573 headerOSTC3compact.totalDiveNumberHigh = (uint8_t)(pHead->diveNumber/256); | |
1574 headerOSTC3compact.profileVersion = 0x24; // Logbook-Profile version, 0x24 = date and time is start not end | |
1575 } | |
1576 else | |
1577 { | |
1578 memset(&headerOSTC3compact, 0xFF, sizeof(SLogbookHeaderOSTC3compact)); | |
1579 } | |
1580 return &headerOSTC3compact; | |
1581 } | |
1582 | |
1583 | |
1584 /** | |
1585 ****************************************************************************** | |
1586 * @brief logbook_readSampleData. / Reads sample data of whole logbook entry | |
1587 * @author Peter Ryser | |
1588 * @version V0.0.1 | |
1589 * @date 22-April-2014 | |
1590 ****************************************************************************** | |
1591 * | |
1592 * @param uint8_t StepBackwards: witch lookbook entry? | |
1593 * @param uint16_t length : maxlength of output arrays | |
1594 * @param int32_t* depth : output array | |
1595 * @param int16_t * gasid : output array | |
1596 * @param int32_t* temperature : output array | |
1597 * @param int32_t* ppo2 : output array | |
1598 * @param int32_t* cns : output array | |
1599 * @return length of output | |
1600 */ | |
1601 void logbook_recover_brokenlog(uint8_t headerId) | |
1602 { | |
1603 int16_t retVal; | |
1604 int32_t depthVal = 0; | |
1605 int16_t gasidVal = 0; | |
1606 int16_t setPointVal = 0; | |
1607 int16_t bailoutVal = 0; | |
1608 int32_t temperatureVal = 0; | |
1609 int32_t sensor1Val = 0; | |
1610 int32_t sensor2Val = 0; | |
1611 int32_t sensor3Val = 0; | |
1612 int32_t cnsVal = 0; | |
1613 SManualGas manualGasVal; | |
1614 | |
1615 //uint16_t* ppo2, uint16_t* cns# | |
1616 uint32_t bytesRead = 0; | |
1617 | |
1618 ext_flash_read_block_start(); | |
1619 ext_flash_read_next_sample_part((uint8_t*)&smallHeader, sizeof(SSmallHeader)); | |
1620 bytesRead += sizeof(SSmallHeader); | |
1621 | |
1622 clear_divisor(); | |
1623 | |
1624 | |
1625 int sampleCounter = 0; | |
1626 int maxdepth = 0; | |
1627 uint32_t avrdepth = 0; | |
1628 while (true) | |
1629 { | |
1630 | |
1631 ext_flash_set_entry_point(); | |
1632 divisorBackup = divisor; | |
1633 retVal = readSample(&depthVal,&gasidVal, &setPointVal, &temperatureVal, &sensor1Val, &sensor2Val, &sensor3Val, &cnsVal, &manualGasVal, &bailoutVal, NULL); | |
1634 if(retVal == 0) | |
1635 { | |
1636 //Error try to read again!!! | |
1637 ext_flash_reopen_read_sample_at_entry_point(); | |
1638 divisor = divisorBackup; | |
1639 retVal = readSample(&depthVal,&gasidVal, &setPointVal, &temperatureVal, &sensor1Val, &sensor2Val, &sensor3Val, &cnsVal, &manualGasVal, &bailoutVal, NULL); | |
1640 | |
1641 if(retVal == 0) | |
1642 { | |
1643 //Error try to read again!!! | |
1644 ext_flash_reopen_read_sample_at_entry_point(); | |
1645 divisor = divisorBackup; | |
1646 retVal = readSample(&depthVal,&gasidVal, &setPointVal, &temperatureVal, &sensor1Val, &sensor2Val, &sensor3Val, &cnsVal, &manualGasVal, &bailoutVal, NULL); | |
1647 | |
1648 if(retVal == 0) | |
1649 { | |
1650 ext_flash_reopen_read_sample_at_entry_point(); | |
1651 break; | |
1652 } | |
1653 | |
1654 } | |
1655 } | |
1656 if(depthVal > maxdepth) | |
1657 maxdepth = depthVal; | |
1658 avrdepth += depthVal; | |
1659 sampleCounter++; | |
1660 bytesRead +=retVal; | |
1661 } | |
1662 avrdepth/= sampleCounter; | |
1663 ext_flash_close_read_sample(); | |
1664 SLogbookHeader header; | |
1665 | |
1666 ext_flash_read_dive_header2((uint8_t*) &header, headerId, false); | |
1667 header.total_diveTime_seconds = sampleCounter * header.samplingRate; | |
1668 header.diveTimeMinutes = header.total_diveTime_seconds /60; | |
1669 header.diveTimeSeconds = header.total_diveTime_seconds - header.diveTimeMinutes * 60; | |
1670 header.maxDepth = maxdepth; | |
1671 header.averageDepth_mbar = avrdepth; | |
1672 SSettings * settings = settingsGetPointer(); | |
1673 settings->lastDiveLogId = headerId; | |
1674 ext_flash_close_new_dive_log((uint8_t *)&header); | |
1675 } | |
1676 | |
1677 /************************ (C) COPYRIGHT heinrichs weikamp *****END OF FILE****/ |