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