Mercurial > public > ostc4
view Discovery/Src/logbook_miniLive.c @ 945:aad1a6b9aaec Evo_2_23
Added slow exit graph to t3 view:
In the first implementation slow exit was only available in T7 view. To enable it in T3 view the common parts have been extracted into a separate function which is shared between T7 and T3. Only the drawing specific parts remain in the T7 / T3 files.
author | Ideenmodellierer |
---|---|
date | Thu, 19 Dec 2024 22:16:36 +0100 |
parents | 6d8ae8fbccf5 |
children |
line wrap: on
line source
/** ****************************************************************************** * @copyright heinrichs weikamp * @file logbook_miniLive.c * @author heinrichs weikamp gmbh * @date 13-March-2015 * @version V0.0.1 * @since 13-March-2015 * @brief little logbook for during the dive * @bug * @warning ****************************************************************************** * @attention * * <h2><center>© COPYRIGHT(c) 2015 heinrichs weikamp</center></h2> * ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include <string.h> #include "logbook_miniLive.h" #include "data_exchange.h" #include "logbook.h" #include "tHome.h" /* ****************************************************************************** * @brief t7_updateMiniLiveLogbook. / Create depth samples for view during dive * @author heinrichs weikamp gmbh * @version V0.0.1 * @date 13-March-2015 ****************************************************************************** * */ #define MLLsize (296) static uint16_t MLLdataDepth[MLLsize]; static uint16_t MLLpointer = 0; static uint8_t MLLtickIntervallSeconds = 2; /* Replay Block data storage */ #define DEPTH_DATA_LENGTH (1800u) /* Resolution: 1 hours dive, sampling every 2 seconds */ uint16_t ReplayDepthData[DEPTH_DATA_LENGTH]; uint8_t ReplayMarkerData[DEPTH_DATA_LENGTH]; uint16_t liveDepthData[DEPTH_DATA_LENGTH]; uint16_t liveDepthDataMod[DEPTH_DATA_LENGTH]; /* live data modified to fit to marker checks */ uint16_t liveDecoData[DEPTH_DATA_LENGTH]; uint16_t liveDecoDataMod[DEPTH_DATA_LENGTH]; static uint16_t liveDataIndex = 0; static uint16_t liveDataIndexMod = 0; static uint8_t ReplayDataResolution = 2; /* Time represented by one sample (second) */ static uint16_t ReplayDataLength = 0; /* Number of data entries */ static uint16_t ReplayDataMaxDepth = 0; static uint16_t ReplayDataMinutes = 0; static uint16_t ReplayDataOffset = 0xFFFF; /* Stepbackwards format used by log functions */ static uint16_t ReplayMarkerIndex = 0; uint16_t *getMiniLiveLogbookPointerToData(void) { return MLLdataDepth; } uint16_t getMiniLiveLogbookActualDataLength(void) { return MLLpointer; } uint16_t MiniLiveLogbook_getNextMarkerIndex(uint16_t curIndex) { uint16_t index = 0; if((ReplayMarkerData[0] != 0xFF) && (curIndex < ReplayDataLength)) { index = curIndex; do { index++; if (index == ReplayDataLength) { index = 0; } if(ReplayMarkerData[index] != 0) { break; } }while (index != curIndex); } return index; } static uint16_t workdata[DEPTH_DATA_LENGTH]; static void compressMarkerData(uint16_t* pSource, uint16_t* pTarget, float step, uint16_t startIndex, uint16_t stopIndex) { uint16_t workIndex = startIndex; float nextStep = (float)workIndex; while (workIndex <= ReplayMarkerIndex) { workdata[workIndex] = *pSource++; nextStep += step; while(nextStep < workIndex + 1) { if(*pSource != 0xFFFF) /* do not average "ignore" value */ { if(workdata[workIndex] == 0xFFFF) /* first value to be shown */ { workdata[workIndex] = *pSource; } else { workdata[workIndex] += *pSource; workdata[workIndex] /= 2; } } pSource++; nextStep += step; } workIndex++; } memcpy(&pTarget[startIndex],&workdata[startIndex],(workIndex - startIndex -1) * 2); while(workIndex < DEPTH_DATA_LENGTH) { pTarget[workIndex] = 0xFFFF; workIndex++; } } static void stretchMarkerData(uint16_t* pSource, uint16_t* pTarget, float step, uint16_t startIndex, uint16_t stopIndex) { uint16_t workIndex = startIndex; float nextStep = (float)workIndex; while (workIndex <= stopIndex) { nextStep += step; if(nextStep > stopIndex) { nextStep = stopIndex; } while(workIndex <= (uint16_t)nextStep) { workdata[workIndex++] = *pSource; } pSource++; } memcpy(&pTarget[startIndex],&workdata[startIndex],(workIndex - startIndex) * 2); while(workIndex < DEPTH_DATA_LENGTH) { pTarget[workIndex] = 0xFFFF; workIndex++; } } void MiniLiveLogbook_checkMarker(void) { static uint16_t lastLifeIndex = 0; uint16_t* pDepthData; uint16_t* pDecoData; float step; uint16_t lastMarkerIndex = ReplayMarkerIndex; ReplayMarkerIndex = MiniLiveLogbook_getNextMarkerIndex(ReplayMarkerIndex); if(ReplayMarkerIndex <= lastMarkerIndex) /* no other marker found or last marker checked => reset marker to 0 to deactivate check function */ { ReplayMarkerIndex = 0; lastLifeIndex = 0; liveDataIndexMod = liveDataIndex; } else { if(lastMarkerIndex == 0) /* use real live data */ { pDepthData = &liveDepthData[0]; pDecoData = &liveDecoData[0]; lastLifeIndex = 0; } else { pDepthData = &liveDepthDataMod[lastMarkerIndex]; /* work with already modified data */ pDecoData = &liveDecoDataMod[lastMarkerIndex]; } if(lastLifeIndex == liveDataIndex) /* repeated button press before new data was generated => draw straight line */ { step = ReplayMarkerIndex-lastMarkerIndex; } else { step = (ReplayMarkerIndex-lastMarkerIndex) / (float)(liveDataIndex - lastLifeIndex); /* the live data shall be modified to match the history data */ } lastLifeIndex = liveDataIndex; if(step < 1) /* compression needed */ { compressMarkerData(pDepthData, liveDepthDataMod, step, lastMarkerIndex, ReplayMarkerIndex); compressMarkerData(pDecoData, liveDecoDataMod, step, lastMarkerIndex, ReplayMarkerIndex); } else /* stretch data */ { stretchMarkerData(pDepthData, liveDepthDataMod, step, lastMarkerIndex, ReplayMarkerIndex); stretchMarkerData(pDecoData, liveDecoDataMod, step, lastMarkerIndex, ReplayMarkerIndex); } liveDataIndexMod = ReplayMarkerIndex; } } void compressBuffer_uint16(uint16_t* pdata, uint16_t size) { uint16_t* pTarget = pdata; uint16_t* pSource = pdata; uint16_t result = 0; uint16_t index = 0; for(index = 0; index < size/2; index++) { *pTarget = *pSource++; *pTarget += *pSource++; result = *pTarget /= 2; if((*pTarget != 0) && (result == 0)) /* avoid termination of information by round up to 1 */ { *pTarget++ = 1; } else { *pTarget++ = result; } } memset(pTarget,0,size/2); } void updateMiniLiveLogbook( _Bool checkOncePerSecond) { static uint8_t bDiveMode = 0; static uint32_t last_second = 0; static uint8_t secondsCount = 0; static uint8_t lifesecondsCount = 0; const SDecoinfo* pDecoinfo; uint8_t stopDepth = 0; uint16_t stopTime = 0; if(checkOncePerSecond) { uint32_t now = current_second(); if( last_second == now) return; last_second = now; } secondsCount++; lifesecondsCount++; if(!bDiveMode) { if((stateUsed->mode == MODE_DIVE) && (stateUsed->lifeData.dive_time_seconds >= 5)) { secondsCount = 0; MLLtickIntervallSeconds = 2; bDiveMode = 1; MLLpointer = 1; for(int i=0;i<MLLsize;i++) MLLdataDepth[i] = 0; for(liveDataIndex = 0; liveDataIndex < DEPTH_DATA_LENGTH; liveDataIndex++) { liveDepthData[liveDataIndex] = 0xFFFF; liveDecoData[liveDataIndex] = 0xFFFF; } lifesecondsCount = 0; liveDataIndex = 0; liveDataIndexMod = 0; liveDepthData[liveDataIndex++] = 0; /* start at 0 */ } } else if(stateUsed->mode == MODE_DIVE) { bDiveMode = 3; // if(secondsCount >= MLLtickIntervallSeconds) { secondsCount = 0; /* in case of a buffer overrun the buffer is divided and the first half is filled with a compressed image of the complete buffer */ if((MLLpointer >= MLLsize) && (MLLtickIntervallSeconds < 127)) { MLLpointer = 0; MLLtickIntervallSeconds *= 2; compressBuffer_uint16(MLLdataDepth,MLLsize); MLLpointer = MLLsize/2; } if(MLLpointer < MLLsize) MLLdataDepth[MLLpointer++] = (int)(stateUsed->lifeData.depth_meter * 10); } if(lifesecondsCount >= ReplayDataResolution) { lifesecondsCount = 0; if(liveDataIndex >= DEPTH_DATA_LENGTH) /* compress data */ { ReplayDataResolution *= 2; compressBuffer_uint16(liveDepthData,DEPTH_DATA_LENGTH); compressBuffer_uint16(liveDepthDataMod, DEPTH_DATA_LENGTH); compressBuffer_uint16(ReplayDepthData,DEPTH_DATA_LENGTH); /* also compress Replay data to simplify mapping between live and replay data */ liveDataIndex = DEPTH_DATA_LENGTH / 2; liveDataIndexMod /= 2; } liveDepthData[liveDataIndex] = (int)(stateUsed->lifeData.depth_meter * 100); liveDepthDataMod[liveDataIndexMod] = liveDepthData[liveDataIndex]; if(stateUsed->diveSettings.deco_type.ub.standard == VPM_MODE) { pDecoinfo = &stateUsed->decolistVPM; } else { pDecoinfo = &stateUsed->decolistBuehlmann; } tHome_findNextStop(pDecoinfo->output_stop_length_seconds, &stopDepth, &stopTime); if(stopDepth) { liveDecoData[liveDataIndex] = stopDepth * 100; liveDecoDataMod[liveDataIndexMod] = stopDepth * 100; } else { liveDecoData[liveDataIndex] = 0xFFFF; liveDecoDataMod[liveDataIndexMod] = 0xFFFF; } liveDataIndex++; liveDataIndexMod++; } } else if(bDiveMode == 3) { //End of Dive for(int i=0;i<MLLsize;i++) MLLdataDepth[i] = 0; bDiveMode = 0; } } uint8_t prepareReplayLog(uint8_t StepBackwards) { uint8_t retVal = 0; uint16_t index = 0; uint16_t dataLength = 0; uint8_t markerDetected = 0; SLogbookHeader logbookHeader; if(ReplayDataOffset == StepBackwards) /* Entry already selected => reset selection */ { ReplayDataOffset = 0xFFFF; ReplayDataResolution = 2; ReplayDataLength = 0; ReplayDataMaxDepth = 0; ReplayDataMinutes = 0; retVal = 1; } else { ReplayDataOffset = StepBackwards; logbook_getHeader(StepBackwards ,&logbookHeader); dataLength = logbook_readSampleData(StepBackwards, DEPTH_DATA_LENGTH, ReplayDepthData,NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ReplayMarkerData); /* check if a marker is provided. If not disable marker functionality for the replay block */ for(index = 0; index < dataLength; index++) { if(ReplayMarkerData[index] != 0) { markerDetected = 1; break; } } if(markerDetected == 0) { ReplayMarkerData[0] = 0xFF; } ReplayDataResolution = logbookHeader.total_diveTime_seconds / dataLength; ReplayDataLength = dataLength; ReplayDataMaxDepth = logbookHeader.maxDepth; ReplayDataMinutes = logbookHeader.diveTimeMinutes; if(dataLength != 0) { retVal = 1; } } return retVal; } uint8_t getReplayInfo(uint16_t** pReplayData, uint8_t** pReplayMarker, uint16_t* DataLength, uint16_t* MaxDepth, uint16_t* diveMinutes) { uint8_t retVal = 0; if((ReplayDataOffset != 0xFFFF) && (pReplayData != NULL) && (DataLength != NULL) && (MaxDepth != NULL) && (pReplayMarker != 0)) { *pReplayData = ReplayDepthData; *pReplayMarker = ReplayMarkerData; *DataLength = ReplayDataLength; *MaxDepth = ReplayDataMaxDepth; *diveMinutes = ReplayDataMinutes; retVal = 1; } return retVal; } uint16_t *getMiniLiveReplayPointerToData(void) { if(ReplayMarkerIndex == 0) { return liveDepthData; } else { return liveDepthDataMod; } } uint16_t *getMiniLiveDecoPointerToData(void) { if(ReplayMarkerIndex == 0) { return liveDecoData; } else { return liveDecoDataMod; } } uint16_t getMiniLiveReplayLength(void) { return liveDataIndex; } uint16_t getReplayOffset(void) { return ReplayDataOffset; } uint16_t getReplayDataResolution(void) { return ReplayDataResolution; } /************************ (C) COPYRIGHT heinrichs weikamp *****END OF FILE****/