Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
DataLoggingService.cpp
00001 /******************************************************************************* 00002 * Copyright (C) 2016 Maxim Integrated Products, Inc., All Rights Reserved. 00003 * 00004 * Permission is hereby granted, free of charge, to any person obtaining a 00005 * copy of this software and associated documentation files (the "Software"), 00006 * to deal in the Software without restriction, including without limitation 00007 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 00008 * and/or sell copies of the Software, and to permit persons to whom the 00009 * Software is furnished to do so, subject to the following conditions: 00010 * 00011 * The above copyright notice and this permission notice shall be included 00012 * in all copies or substantial portions of the Software. 00013 * 00014 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 00015 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 00016 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 00017 * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES 00018 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 00019 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 00020 * OTHER DEALINGS IN THE SOFTWARE. 00021 * 00022 * Except as contained in this notice, the name of Maxim Integrated 00023 * Products, Inc. shall not be used except as stated in the Maxim Integrated 00024 * Products, Inc. Branding Policy. 00025 * 00026 * The mere transfer of this software does not imply any licenses 00027 * of trade secrets, proprietary technology, copyrights, patents, 00028 * trademarks, maskwork rights, or any other form of intellectual 00029 * property whatsoever. Maxim Integrated Products, Inc. retains all 00030 * ownership rights. 00031 ******************************************************************************* 00032 */ 00033 #include "mbed.h" 00034 #include "Logging.h" 00035 #include "Streaming.h" 00036 #include "RpcServer.h" 00037 #include "S25FS512.h" 00038 #include "BMP280.h" 00039 #include "PacketFifo.h" 00040 #include "DataLoggingService.h" 00041 #include "ServiceNonInterrupt.h" 00042 #include "HspLed.h" 00043 #include "MAX30001_helper.h" 00044 #include "MAX30101_helper.h" 00045 #include "StringInOut.h" 00046 #include "StringHelper.h" 00047 #include "Peripherals.h" 00048 #include "Device_Logging.h" 00049 00050 /// BMP280 logging object reference 00051 extern Device_Logging *bmp280_Logging; 00052 /// MAX14720 instance 0 logging object reference 00053 extern Device_Logging *MAX30205_0_Logging; 00054 /// MAX14720 instance 1 logging object reference 00055 extern Device_Logging *MAX30205_1_Logging; 00056 00057 #define PING_PONG_BUFFER_SIZE 512 00058 #define HALF_OF_PING_PONG_BUFFER_SIZE PING_PONG_BUFFER_SIZE / 2 00059 #define MISSION_DEFINITION_SIZE 4096 00060 00061 eLoggingTrigger loggingTrigger; 00062 00063 /// buffer where mission strings are stored 00064 char loggingMissionCmds[MISSION_DEFINITION_SIZE]; 00065 /// This houses two 256 byte ram concatenated to act as a ping-pong 00066 uint8_t PingPong_SRAM[PING_PONG_BUFFER_SIZE]; 00067 uint32_t buttonTrigger = 0; 00068 00069 eLoggingOutput loggingOutput; 00070 // extern int bleStartCommand; 00071 bool volatile globalFlag; 00072 extern int highDataRate; 00073 static uint32_t currentPage; 00074 static uint32_t sramIndex; 00075 /// flag to indicate that sram buffer 0 is dirty and will need to be flushed 00076 static uint32_t sram_buffer_0_dirty; 00077 /// flag to indicate that sram buffer 1 is dirty and will need to be flushed 00078 static uint32_t sram_buffer_1_dirty; 00079 /// usb byte buffer for sending out a bulk transfer 00080 static uint8_t usb_block[64]; 00081 /// running index used to accumulate bytes to send as a block via bulk transfer 00082 static uint16_t usb_block_index = 0; 00083 00084 typedef enum { 00085 eStartEvent_NULL, 00086 eStartEvent_BLE, 00087 eStartEvent_BUTTON, 00088 eStartEvent_RPC_TO_USB, 00089 eStartEvent_RPC_TO_FLASH 00090 } eStartEvent; 00091 static eStartEvent startEvent; 00092 00093 /** 00094 * @brief Sets a flag to start USB logging (streaming) 00095 */ 00096 void LoggingService_StartLoggingUsb(void) { 00097 loggingTrigger = eTriggerLog_RPC_USB; 00098 } 00099 00100 /** 00101 * @brief Sets a flag to start flash logging 00102 */ 00103 void LoggingService_StartLoggingFlash(void) { 00104 loggingTrigger = eTriggerLog_RPC_FLASH; 00105 } 00106 00107 /** 00108 * @brief Checks the various logging start condition 00109 * @return 1 if a start condition is true, 0 if there is no start condition 00110 */ 00111 static bool _LoggingService_CheckStartCondition(void) { 00112 bool buttonPressed; 00113 buttonPressed = Peripherals::pushButton()->GetButtonFallState(); 00114 00115 // default not logging USB or flash 00116 loggingOutput = eLogToNothing; 00117 startEvent = eStartEvent_NULL; 00118 if (buttonPressed) { 00119 Peripherals::pushButton()->clearButtonFallState(); 00120 // a falling state has been detected... wait for a fraction of a second and 00121 // re-read the pin 00122 // only start datalogging if the pin was released within this wait time 00123 wait(0.75f); 00124 int buttonRead = Peripherals::pushButton()->Read(); 00125 // if after a period of time the button is still pressed then get out 00126 if (buttonRead == 0) 00127 return 0; 00128 buttonTrigger = 0; 00129 00130 loggingTrigger = eTriggerLog_BUTTON; 00131 loggingOutput = eLogToFlash; 00132 startEvent = eStartEvent_BUTTON; 00133 return true; 00134 } 00135 if (loggingTrigger == eTriggerLog_RPC_FLASH) { 00136 loggingOutput = eLogToFlash; 00137 startEvent = eStartEvent_RPC_TO_FLASH; 00138 return true; 00139 } 00140 if (Peripherals::hspBLE()->getStartDataLogging()) { 00141 loggingTrigger = eTriggerLog_BLE; 00142 loggingOutput = eLogToFlash; 00143 startEvent = eStartEvent_BLE; 00144 return true; 00145 } 00146 // check if start is from RPC call for USB streaming 00147 if (loggingTrigger == eTriggerLog_RPC_USB) { 00148 loggingOutput = eLogtoUsb; 00149 startEvent = eStartEvent_RPC_TO_USB; 00150 return true; 00151 } 00152 return false; 00153 } 00154 00155 /** 00156 * @brief Read the mission string from flash into a buffer 00157 * @return false if a mission was not defined, true if mission was read and 00158 * buffered 00159 */ 00160 static bool _LoggingService_ReadMissionFromFlash(void) { 00161 // get mission from flash 00162 Logging_ReadMissionFromFlash((uint8_t *)loggingMissionCmds); 00163 if (Logging_IsMissionDefined((uint8_t *)loggingMissionCmds) == 0) { 00164 return false; 00165 } 00166 printf(loggingMissionCmds); 00167 fflush(stdout); 00168 RPC_ProcessCmds(loggingMissionCmds); 00169 return true; 00170 } 00171 00172 /** 00173 * @brief Process a RPC command that is pointed to. 00174 * @param cmd RPC string to process 00175 */ 00176 void ProcessCmd(char *cmd) { 00177 char cmd_[256]; 00178 char reply[512]; 00179 strcpy(cmd_, cmd); 00180 RPC_call(cmd_, reply); 00181 } 00182 00183 /** 00184 * @brief Buffer sensor fifo data in ram buffers, when a ram buffer is full (a 00185 * flash page worth of data is accumulated) then flash that buffer. 00186 * A buffer ping pong method is used so that one buffer can be flashing as 00187 * the other buffer fills with sensor fifo data. 00188 * @param fifoData Sensor data taken from the fifo to be stored into flash 00189 */ 00190 static void _LoggingServer_OutputToFlash(uint32_t fifoData) { 00191 uint32_t index; 00192 char str[128]; 00193 uint8_t *ptr; 00194 // 00195 // Log To Flash 00196 // 00197 // i.e. there is data, read one 32-bit size data at a time. 00198 // put the fifo data into the ping-pong SRAM 00199 PingPong_SRAM[sramIndex++] = fifoData & 0xFF; // LSByte goes into index N 00200 PingPong_SRAM[sramIndex++] = (fifoData >> 8) & 0xFF; 00201 PingPong_SRAM[sramIndex++] = (fifoData >> 16) & 0xFF; 00202 PingPong_SRAM[sramIndex++] = (fifoData >> 24) & 0xFF; // MSByte goes into index N+3 00203 00204 // flag this buffer as dirty 00205 if (sramIndex <= 256) 00206 sram_buffer_0_dirty = 1; 00207 else 00208 sram_buffer_1_dirty = 1; 00209 00210 if (sramIndex == 256 || 00211 sramIndex == 512) // Either Ping SRAM or Pong SRAM location is full 00212 { // therefore write to Flash 00213 00214 index = sramIndex - 256; 00215 ptr = &PingPong_SRAM[index]; 00216 sprintf(str, "currentPage=%d", currentPage); 00217 Peripherals::s25FS512()->writePage_Helper(currentPage, ptr, 0); 00218 00219 // this page is no longer dirty 00220 if (index == 0) 00221 sram_buffer_0_dirty = 0; 00222 if (index == 256) 00223 sram_buffer_1_dirty = 0; 00224 00225 currentPage++; 00226 } 00227 sramIndex = sramIndex % 512; // Wrap around the index 00228 } 00229 00230 /** 00231 * @brief If flash ram buffers are flagged as dirty, flush to flash 00232 */ 00233 static void _LoggingServer_WriteDirtySramBufferToFlash(void) { 00234 uint8_t *ptr = PingPong_SRAM; 00235 if (sram_buffer_0_dirty == 0 && sram_buffer_1_dirty == 0) 00236 return; 00237 if (sram_buffer_0_dirty == 1) { 00238 ptr += 0; 00239 } 00240 if (sram_buffer_1_dirty == 1) { 00241 ptr += 256; 00242 } 00243 printf("_LoggingServer_WriteDirtySramBufferToFlash:%d,%d\n", 00244 sram_buffer_0_dirty, sram_buffer_1_dirty); 00245 fflush(stdout); 00246 // s25fs512_WritePage_Helper(currentPage, ptr, 0); 00247 Peripherals::s25FS512()->writePage_Helper(currentPage, ptr, 0); 00248 } 00249 00250 /** 00251 * @brief Initialize the USB block running index 00252 * @param fifoData Sensor data taken from the fifo to be sent out USB 00253 */ 00254 static void _LoggingServer_OutputToCdcAcm(uint32_t fifoData) { 00255 uint8_t *ptr; 00256 uint8_t str[16]; 00257 sprintf((char *)str, "%X ", fifoData); 00258 ptr = str; 00259 usb_block_index = 0; 00260 while (*ptr != 0) { 00261 usb_block[usb_block_index] = *ptr; 00262 ptr++; 00263 usb_block_index++; 00264 } 00265 Peripherals::usbSerial()->writeBlock(usb_block, usb_block_index); 00266 } 00267 00268 /** 00269 * @brief Initialize the USB block running index 00270 */ 00271 static void _LoggingServer_OutputToCdcAcm_Start(void) { usb_block_index = 0; } 00272 00273 /** 00274 * @brief Buffer up fifoData from sensors, do a USB block transfer if buffer is 00275 * full 00276 * @param fifoData Sensor data taken from the fifo to be send out USB within a 00277 * bulk block transfer 00278 * @return Return the success status of the writeblock operation 00279 */ 00280 static bool _LoggingServer_OutputToCdcAcm_Block(uint32_t fifoData) { 00281 uint8_t str[64]; 00282 uint8_t *ptr; 00283 bool result; 00284 // 00285 // Log to CDCACM 00286 // 00287 result = true; 00288 sprintf((char *)str, "%X ", fifoData); 00289 ptr = str; 00290 while (*ptr != 0) { 00291 usb_block[usb_block_index] = *ptr; 00292 ptr++; 00293 usb_block_index++; 00294 if (usb_block_index >= 64) { 00295 result = Peripherals::usbSerial()->writeBlock(usb_block, 64); 00296 usb_block_index = 0; 00297 } 00298 } 00299 return result; 00300 } 00301 00302 /** 00303 * @brief Output a full USB block via bulk transfer 00304 */ 00305 static void _LoggingServer_OutputToCdcAcm_End(void) { 00306 if (usb_block_index == 0) 00307 return; 00308 Peripherals::usbSerial()->writeBlock(usb_block, usb_block_index - 1); 00309 } 00310 00311 /** 00312 * @brief Blink LED pattern that indicates that the flash end boundary has been 00313 * reached 00314 */ 00315 static void BlinkEndOfDatalogging(void) { 00316 // blink to signal end of logging 00317 Peripherals::hspLed()->pattern(0x55555555, 20); 00318 wait(2); 00319 } 00320 00321 /** 00322 * @brief Reads the first data page of flash, if all FF's then the page is empty 00323 * @return 1 if the flash is empty as indicated by the first data page of the 00324 * flash, 0 if not 00325 */ 00326 int isFlashEmpty(void) { 00327 int i; 00328 uint8_t data[256]; 00329 int firstDataPage = Logging_GetLoggingStartPage(); 00330 Peripherals::s25FS512()->readPages_Helper(firstDataPage, firstDataPage, data, 0); 00331 for (i = 0; i < 256; i++) { 00332 if (data[i] != 0xFF) 00333 return 0; 00334 } 00335 return 1; 00336 } 00337 00338 /** 00339 * @brief Blink LED pattern that indicates that the flash is not empty and a new 00340 * flash logging session can not occur 00341 */ 00342 void BlinkFlashNotEmpty(void) { 00343 Peripherals::hspLed()->pattern(0x55555555, 20); 00344 wait(1); 00345 } 00346 00347 void ExecuteDefaultMission(void) { 00348 ProcessCmd("/MAX30001/CAL_InitStart 01 01 01 03 7FF 00"); 00349 ProcessCmd("/MAX30001/ECG_InitStart 01 01 01 00 02 03 1F 0 00 00 01"); 00350 ProcessCmd("/MAX30001/RtoR_InitStart 01 03 0F 00 03 01 00 00 01"); 00351 ProcessCmd("/MAX30001/Rbias_FMSTR_Init 01 02 01 01 00"); 00352 ProcessCmd("/LIS2DH/InitStart 02 01"); 00353 } 00354 00355 void LoggingService_Init(void) { loggingTrigger = eTriggerLog_NULL; } 00356 00357 /** 00358 * @brief This routine checks to see if a USB or flash logging action needs to be taken 00359 * The routine checks for a start condition via button press, USB command, or BLE command 00360 * Once one of these start conditions is present, the logging begins until stopped or memory is full 00361 * @return 1 if successful, 0 if error or logging was aborted and no logging occurred 00362 */ 00363 uint8_t LoggingService_ServiceRoutine(void) { 00364 uint32_t fifoData; 00365 uint32_t endPage; 00366 USBSerial *usbSerial = Peripherals::usbSerial(); 00367 // BMP280 *bmp280 = Peripherals::bmp280(); 00368 bool buttonPressed; 00369 int packetBurstCount = 0; 00370 HspLed *hspLed = Peripherals::hspLed(); 00371 00372 sramIndex = 0; 00373 // only start logging if conditions exist 00374 00375 if (_LoggingService_CheckStartCondition() == false) return 0; 00376 printf("Begin Logging..."); 00377 if (startEvent == eStartEvent_NULL) printf("eStartEvent_NULL..."); 00378 if (startEvent == eStartEvent_BLE) printf("eStartEvent_BLE..."); 00379 if (startEvent == eStartEvent_BUTTON) printf("eStartEvent_BUTTON..."); 00380 if (startEvent == eStartEvent_RPC_TO_USB) printf("eStartEvent_RPC_TO_USB..."); 00381 if (startEvent == eStartEvent_RPC_TO_FLASH) printf("eStartEvent_RPC_TO_FLASH..."); 00382 fflush(stdout); 00383 00384 // start logging stuttered blink pattern 00385 hspLed->pattern(0xA0F3813, 20); 00386 00387 if (startEvent == eStartEvent_RPC_TO_FLASH || 00388 startEvent == eStartEvent_BUTTON) { 00389 // check to see if datalog already in flash... abort and force user to erase 00390 // flash if needed 00391 if (loggingOutput == eLogToFlash) { 00392 if (isFlashEmpty() == 0) { 00393 Logging_SetStart(false); 00394 // bleStartCommand = 0x00; 00395 BlinkFlashNotEmpty(); 00396 hspLed->blink(1000); 00397 printf("Abort Logging, flash log exists. "); 00398 fflush(stdout); 00399 return 0; 00400 } 00401 } 00402 } 00403 00404 if (startEvent == eStartEvent_BLE) { 00405 // check for mission in flash 00406 if (_LoggingService_ReadMissionFromFlash() == false) { 00407 // if there is no mission in flash then do a default mission for the sake 00408 // of ble Android app working "out-of-the-box" and stream RtoR and Accel 00409 printf("No Mission in Flash...ExecuteDefaultMission..."); 00410 fflush(stdout); 00411 ExecuteDefaultMission(); 00412 // do not log this data 00413 loggingOutput = eLogToNothing; 00414 } else { 00415 // there is a mission in flash check if there is already logged data 00416 if (isFlashEmpty() == 0) { 00417 // just do default mission 00418 printf("Logged Data Detected...ExecuteDefaultMission..."); 00419 fflush(stdout); 00420 ExecuteDefaultMission(); 00421 // do not log this data 00422 loggingOutput = eLogToNothing; 00423 } else { 00424 // flag that we are logging to flash 00425 loggingOutput = eLogToFlash; 00426 } 00427 } 00428 } 00429 00430 // if we are logging to flash then read mission in flash 00431 if (loggingOutput == eLogToFlash) { 00432 if (_LoggingService_ReadMissionFromFlash() == 00433 false) { // if there is no mission in flash then get out 00434 Logging_SetStart(false); 00435 Peripherals::hspLed()->pattern(0xC3C3C3C3, 20); 00436 wait(2); 00437 printf("Abort Logging, Mission does not exist. "); 00438 fflush(stdout); 00439 return 0; 00440 } 00441 currentPage = Logging_GetLoggingStartPage(); 00442 endPage = Logging_GetLoggingEndPage(); 00443 } 00444 00445 MAX30001_Helper_SetupInterrupts(); 00446 if (MAX30001_AnyStreamingSet() == 1) { 00447 MAX30001_Helper_StartSync(); 00448 } 00449 00450 SetDataLoggingStream(TRUE); 00451 ServiceNonInterrupt_Init(); 00452 ServiceNonInterrupt_StartTimer(); 00453 00454 while (usbSerial->readable()) { 00455 usbSerial->_getc(); 00456 } 00457 fifo_clear(GetUSBIncomingFifo()); // clear USB serial incoming fifo 00458 fifo_clear(GetStreamOutFifo()); 00459 00460 sram_buffer_0_dirty = 0; 00461 sram_buffer_1_dirty = 0; 00462 00463 00464 if (loggingOutput == eLogToNothing) printf("eLogToNothing..."); fflush(stdout); 00465 if (loggingOutput == eLogToFlash) printf("eLogToFlash..."); fflush(stdout); 00466 if (loggingOutput == eLogtoUsb) printf("eLogtoUsb..."); fflush(stdout); 00467 printf("highDataRate=%d...",highDataRate); fflush(stdout); 00468 00469 00470 Peripherals::timestampTimer()->reset(); 00471 Peripherals::timestampTimer()->start(); 00472 00473 _LoggingServer_OutputToCdcAcm_Start(); 00474 while (1) { 00475 if (loggingOutput == eLogToFlash) { 00476 // check if we are at the end of flash 00477 if (currentPage >= endPage) { 00478 BlinkEndOfDatalogging(); // blink for 3 seconds to signal end of logging 00479 break; 00480 } 00481 } 00482 00483 if (startEvent == eStartEvent_BUTTON) { 00484 buttonPressed = Peripherals::pushButton()->GetButtonFallState(); 00485 if (buttonPressed) { 00486 Peripherals::pushButton()->clearButtonFallState(); 00487 // if there is a dirty sram buffer... flush it to flash 00488 _LoggingServer_WriteDirtySramBufferToFlash(); 00489 BlinkEndOfDatalogging(); // blink for 3 seconds to signal end of logging 00490 break; 00491 } 00492 } 00493 00494 if (loggingTrigger == eTriggerLog_BLE) { 00495 if (Peripherals::hspBLE()->getStartDataLogging() == false) { 00496 // if there is a dirty sram buffer... flush it to flash 00497 _LoggingServer_WriteDirtySramBufferToFlash(); 00498 BlinkEndOfDatalogging(); // blink for 3 seconds to signal end of logging 00499 break; 00500 } 00501 } 00502 00503 if (startEvent == eStartEvent_RPC_TO_USB || 00504 startEvent == eStartEvent_RPC_TO_FLASH) { 00505 if (usbSerial->available()) { 00506 if (loggingOutput == eLogToFlash) { 00507 _LoggingServer_WriteDirtySramBufferToFlash(); 00508 } 00509 wait(0.2f); 00510 while (usbSerial->available()) { 00511 usbSerial->_getc(); 00512 } 00513 fifo_clear(GetUSBIncomingFifo()); // clear USB serial incoming fifo 00514 fifo_clear(GetStreamOutFifo()); 00515 break; 00516 } 00517 } 00518 00519 // check to see if data is available 00520 packetBurstCount = 0; 00521 while (PacketFifo_Empty() == 0) { 00522 if (packetBurstCount >= 100) 00523 break; 00524 fifoData = PacketFifo_GetUint32(); 00525 if (loggingOutput == eLogToFlash) { 00526 _LoggingServer_OutputToFlash(fifoData); 00527 } 00528 if (loggingOutput == eLogtoUsb) { 00529 if (highDataRate == 0) 00530 _LoggingServer_OutputToCdcAcm(fifoData); 00531 else 00532 _LoggingServer_OutputToCdcAcm_Block(fifoData); 00533 } 00534 packetBurstCount++; 00535 } 00536 00537 if (PacketFifo_Empty() != 0) { 00538 Peripherals::ble()->waitForEvent(); 00539 } 00540 ServiceNonInterrupt_BMP280(bmp280_Logging); 00541 ServiceNonInterrupt_MAX30205(MAX30205_0_Logging, 00542 Peripherals::max30205_top(), 00543 PACKET_MAX30205_TEMP_TOP); 00544 ServiceNonInterrupt_MAX30205(MAX30205_1_Logging, 00545 Peripherals::max30205_bottom(), 00546 PACKET_MAX30205_TEMP_BOTTOM); 00547 } 00548 _LoggingServer_OutputToCdcAcm_End(); 00549 printf("End Logging.\n"); 00550 fflush(stdout); 00551 00552 bmp280_Logging->stop(); 00553 MAX30205_0_Logging->stop(); 00554 MAX30205_1_Logging->stop(); 00555 MAX30001_Helper_Stop(); // if any MAX30001 streams have been started, stop 00556 // them 00557 MAX30101_Helper_Stop(); // if any MAX30101 streams have been started, stop 00558 // them 00559 Peripherals::lis2dh()->stop(); 00560 SetDataLoggingStream(FALSE); 00561 Peripherals::timestampTimer()->stop(); 00562 hspLed->blink(1000); 00563 // default to non-usb packet speed optimizing 00564 highDataRate = 0; 00565 loggingTrigger = eTriggerLog_NULL; 00566 return 1; 00567 }
Generated on Tue Jul 12 2022 21:52:37 by
1.7.2