Jerry Bradshaw
/
mbed-os-test
ddd
Embed:
(wiki syntax)
Show/hide line numbers
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:12:44 by 1.7.2