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>&copy; 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****/