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.
Dependencies: max32630fthr USBDevice
Fork of MAXREFDES220_HEART_RATE_MONITOR by
SSMAX30101Comm.cpp
00001 /******************************************************************************* 00002 * Copyright (C) 2017 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 00034 #include "DSInterface.h" 00035 #include "SSMAX30101Comm.h" 00036 #include "Peripherals.h" 00037 #include "assert.h" 00038 #include "utils.h" 00039 #include "CRC8.h" 00040 00041 #ifdef ENABLE_BLE 00042 #include "BLE_ICARUS.h" 00043 #endif 00044 00045 #define ENABLE_MAX30101 00046 #define ENABLE_ACCEL 00047 #define ENABLE_WHRM_ANS_SP02 00048 #define ENABLE_BPT 00049 00050 static const char* const cmd_tbl[] = { 00051 "get_format ppg 0", 00052 "get_format bpt 0", 00053 "get_format bpt 1", 00054 "read ppg 0", 00055 "read bpt 0", 00056 "read bpt 1", 00057 "get_reg ppg", 00058 "set_reg ppg", 00059 "dump_reg ppg", 00060 "set_cfg ppg agc 0", 00061 "set_cfg ppg agc 1", 00062 "set_cfg bpt med", 00063 "set_cfg bpt sys_bp", 00064 "set_cfg bpt dia_bp", 00065 "set_cfg bpt date", 00066 "set_cfg bpt nonrest", 00067 "self_test ppg os24", 00068 "self_test ppg acc", 00069 }; 00070 00071 SSMAX30101Comm::SSMAX30101Comm(USBSerial *USB, SSInterface* ssInterface, DSInterface* dsInterface) 00072 :SensorComm("ppg", true), m_USB(USB), ss_int(ssInterface), ds_int(dsInterface), agc_enabled(true) 00073 { 00074 max30101_mode1_data_req.data_size = SSMAX30101_MODE1_DATASIZE; 00075 max30101_mode1_data_req.callback = callback(this, &SSMAX30101Comm::max30101_data_rx); 00076 00077 whrm_mode1_data_req.data_size = SSWHRM_MODE1_DATASIZE; 00078 whrm_mode1_data_req.callback = callback(this, &SSMAX30101Comm::whrm_data_rx); 00079 00080 accel_mode1_data_req.data_size = SSACCEL_MODE1_DATASIZE; 00081 accel_mode1_data_req.callback = callback(this, &SSMAX30101Comm::accel_data_rx); 00082 00083 agc_mode1_data_req.data_size = SSAGC_MODE1_DATASIZE; 00084 agc_mode1_data_req.callback = callback(this, &SSMAX30101Comm::agc_data_rx); 00085 00086 bpt_mode1_2_data_req.data_size = SSBPT_MODE1_2_DATASIZE; 00087 bpt_mode1_2_data_req.callback = callback(this, &SSMAX30101Comm::bpt_data_rx); 00088 00089 queue_init(&max30101_queue, max30101_queue_buf, sizeof(max30101_mode1_data), sizeof(max30101_queue_buf)); 00090 queue_init(&whrm_queue, whrm_queue_buf, sizeof(whrm_mode1_data), sizeof(whrm_queue_buf)); 00091 queue_init(&accel_queue, accel_queue_buf, sizeof(accel_mode1_data), sizeof(accel_queue_buf)); 00092 queue_init(&bpt_queue, bpt_queue_buf, sizeof(bpt_mode1_2_data), sizeof(bpt_queue_buf)); 00093 } 00094 00095 void SSMAX30101Comm::stop() 00096 { 00097 comm_mutex.lock(); 00098 ss_int->disable_irq(); 00099 data_report_mode = 0; 00100 sample_count = 0; 00101 #ifdef ENABLE_MAX30101 00102 ss_int->disable_sensor(SS_SENSORIDX_MAX30101); 00103 #endif 00104 #ifdef ENABLE_ACCEL 00105 ss_int->disable_sensor(SS_SENSORIDX_ACCEL); 00106 #endif 00107 #ifdef ENABLE_WHRM_ANS_SP02 00108 ss_int->disable_algo(SS_ALGOIDX_WHRM); 00109 #endif 00110 #ifdef ENABLE_BPT 00111 ss_int->disable_algo(SS_ALGOIDX_BPT); 00112 #endif 00113 ss_int->ss_clear_interrupt_flag(); 00114 ss_int->enable_irq(); 00115 comm_mutex.unlock(); 00116 } 00117 00118 int SSMAX30101Comm::parse_cal_str(const char *ptr_ch, const char *cmd, uint8_t *cal_data, int cal_data_sz) 00119 { 00120 char ascii_byte[] = { 0, 0, 0 }; 00121 const char* sptr = ptr_ch + strlen(cmd); 00122 int found = 0; 00123 int ssfound; 00124 unsigned int val32; 00125 00126 //Eat spaces after cmd 00127 while (*sptr == ' ') { sptr++; } 00128 if (*sptr == '\0') 00129 return -1; 00130 //sptr++; 00131 00132 while (found < cal_data_sz) { 00133 if (*sptr == '\0') 00134 break; 00135 ascii_byte[0] = *sptr++; 00136 ascii_byte[1] = *sptr++; 00137 ssfound = sscanf(ascii_byte, "%x", &val32); 00138 if (ssfound != 1) 00139 break; 00140 *(cal_data + found) = (uint8_t)val32; 00141 //pr_err("cal_data[%d]=%d\r\n", found, val32); 00142 found++; 00143 } 00144 00145 //pr_err("total found: %d\r\n", found); 00146 if (found < cal_data_sz) 00147 return -1; 00148 return 0; 00149 } 00150 00151 bool SSMAX30101Comm::parse_command(const char* cmd) 00152 { 00153 int ret; 00154 char cal_str_to_be_set[650]; 00155 SS_STATUS status; 00156 bool recognizedCmd = false; 00157 00158 if (!ss_int) { 00159 pr_err("No SmartSensor Interface defined!"); 00160 return false; 00161 } 00162 if (!ds_int) { 00163 pr_err("No DeviceStudio Interface defined!"); 00164 return false; 00165 } 00166 00167 for (int i = 0; i < NUM_CMDS; i++) { 00168 if (starts_with(cmd, cmd_tbl[i])) { 00169 cmd_state_t user_cmd = (cmd_state_t)i; 00170 recognizedCmd = true; 00171 00172 switch (user_cmd) { 00173 case get_format_ppg_0: 00174 { 00175 #ifdef ASCII_COMM 00176 m_USB->printf("\r\n%s format=smpleCnt,irCnt,redCnt,led3,led4," 00177 "accelX,accelY,accelZ,hr,hrconf,spo2,status err=0\r\n", cmd); 00178 #else 00179 m_USB->printf("\r\n%s enc=bin cs=1 format={smpleCnt,32},{irCnt,20}," 00180 "{redCnt,20},{led3,20},{led4,20},{accelX,14,3},{accelY,14,3}," 00181 "{accelZ,14,3},{hr,12,1},{hrconf,8},{spo2,11,1},{status,8} err=0\r\n", cmd); 00182 #endif 00183 } break; 00184 00185 case get_format_bpt_0: 00186 { 00187 #ifdef ASCII_COMM 00188 m_USB->printf("\r\n%s format=status,prog,irCnt,hr,sys_bp,dia_bp err=0\r\n", cmd); 00189 #else 00190 m_USB->printf("\r\n%s enc=bin cs=1 format={status,4},{irCnt,19},{hr,9}," 00191 "{prog,9},{sys_bp,9},{dia_bp,9} err=0\r\n", cmd); 00192 #endif 00193 } break; 00194 00195 case get_format_bpt_1: 00196 { 00197 #ifdef ASCII_COMM 00198 m_USB->printf("\r\n%s format=status,prog,irCnt,hr,sys_bp,dia_bp err=0\r\n", cmd); 00199 #else 00200 m_USB->printf("\r\n%s enc=bin cs=1 format={status,4},{irCnt,19},{hr,9}," 00201 "{prog,9},{sys_bp,9},{dia_bp,9} err=0\r\n", cmd); 00202 #endif 00203 } break; 00204 00205 case read_ppg_0: 00206 { 00207 sample_count = 0; 00208 00209 status = ss_int->set_data_type(SS_DATATYPE_BOTH, false); 00210 if (status != SS_SUCCESS) { 00211 m_USB->printf("\r\n%s err=%d\r\n", cmd, COMM_GENERAL_ERROR); 00212 m_USB->printf("FAILED at line %d\n", __LINE__); 00213 break; 00214 } 00215 00216 status = ss_int->set_fifo_thresh(15); 00217 if (status != SS_SUCCESS) { 00218 m_USB->printf("\r\n%s err=%d\r\n", cmd, COMM_GENERAL_ERROR); 00219 m_USB->printf("FAILED at line %d\n", __LINE__); 00220 break; 00221 } 00222 00223 #if 0 00224 if (agc_enabled) { 00225 status = ss_int->enable_algo(SS_ALGOIDX_AGC, 1, &agc_mode1_data_req); 00226 } else { 00227 status = ss_int->disable_algo(SS_ALGOIDX_AGC); 00228 } 00229 #endif 00230 if (status != SS_SUCCESS) { 00231 m_USB->printf("\r\n%s err=%d\r\n", cmd, COMM_GENERAL_ERROR); 00232 m_USB->printf("FAILED at line %d - agc_enabled: %d\n", __LINE__, agc_enabled); 00233 ss_int->enable_irq(); 00234 break; 00235 } 00236 00237 ss_int->disable_irq(); 00238 #ifdef ENABLE_MAX30101 00239 status = ss_int->enable_sensor(SS_SENSORIDX_MAX30101, 1, &max30101_mode1_data_req); 00240 if (status != SS_SUCCESS) { 00241 m_USB->printf("\r\n%s err=%d\r\n", cmd, COMM_GENERAL_ERROR); 00242 m_USB->printf("FAILED at line %d\n", __LINE__); 00243 ss_int->enable_irq(); 00244 break; 00245 } 00246 #endif 00247 #ifdef ENABLE_ACCEL 00248 status = ss_int->enable_sensor(SS_SENSORIDX_ACCEL, 1, &accel_mode1_data_req); 00249 if (status != SS_SUCCESS) { 00250 m_USB->printf("\r\n%s err=%d\r\n", cmd, COMM_GENERAL_ERROR); 00251 m_USB->printf("FAILED at line %d\n", __LINE__); 00252 ss_int->enable_irq(); 00253 break; 00254 } 00255 00256 #endif 00257 00258 #ifdef ENABLE_WHRM_ANS_SP02 00259 status = ss_int->enable_algo(SS_ALGOIDX_WHRM, 1, &whrm_mode1_data_req); 00260 if (status != SS_SUCCESS) { 00261 m_USB->printf("\r\n%s err=%d\r\n", cmd, COMM_GENERAL_ERROR); 00262 m_USB->printf("FAILED at line %d\n", __LINE__); 00263 ss_int->enable_irq(); 00264 break; 00265 } 00266 00267 #endif 00268 comm_mutex.lock(); 00269 data_report_mode = read_ppg_0; 00270 comm_mutex.unlock(); 00271 m_USB->printf("\r\n%s err=%d\r\n", cmd, COMM_SUCCESS); 00272 ss_int->enable_irq(); 00273 break; 00274 } 00275 00276 /* BP Calibration */ 00277 case read_bpt_0: 00278 { 00279 sample_count = 0; 00280 00281 status = ss_int->set_data_type(SS_DATATYPE_BOTH, false); 00282 if (status != SS_SUCCESS) { 00283 m_USB->printf("\r\n%s err=%d\r\n", cmd, COMM_GENERAL_ERROR); 00284 m_USB->printf("FAILED at line %d\n", __LINE__); 00285 break; 00286 } 00287 00288 status = ss_int->set_fifo_thresh(15); 00289 if (status != SS_SUCCESS) { 00290 m_USB->printf("\r\n%s err=%d\r\n", cmd, COMM_GENERAL_ERROR); 00291 m_USB->printf("FAILED at line %d\n", __LINE__); 00292 break; 00293 } 00294 00295 #if 0 00296 if (agc_enabled) { 00297 status = ss_int->enable_algo(SS_ALGOIDX_AGC, 1, &agc_mode1_data_req); 00298 } else { 00299 status = ss_int->disable_algo(SS_ALGOIDX_AGC); 00300 } 00301 #endif 00302 if (status != SS_SUCCESS) { 00303 m_USB->printf("\r\n%s err=%d\r\n", cmd, COMM_GENERAL_ERROR); 00304 m_USB->printf("FAILED at line %d - agc_enabled: %d\n", __LINE__, agc_enabled); 00305 ss_int->enable_irq(); 00306 break; 00307 } 00308 00309 ss_int->disable_irq(); 00310 #ifdef ENABLE_MAX30101 00311 status = ss_int->enable_sensor(SS_SENSORIDX_MAX30101, 1, &max30101_mode1_data_req); 00312 if (status != SS_SUCCESS) { 00313 m_USB->printf("\r\n%s err=%d\r\n", cmd, COMM_GENERAL_ERROR); 00314 m_USB->printf("FAILED at line %d\n", __LINE__); 00315 ss_int->enable_irq(); 00316 break; 00317 } 00318 #endif 00319 00320 #ifdef ENABLE_BPT 00321 status = ss_int->enable_algo(SS_ALGOIDX_BPT, 1, &bpt_mode1_2_data_req); 00322 if (status != SS_SUCCESS) { 00323 m_USB->printf("\r\n%s err=%d\r\n", cmd, COMM_GENERAL_ERROR); 00324 m_USB->printf("FAILED at line %d\n", __LINE__); 00325 ss_int->enable_irq(); 00326 break; 00327 } 00328 #endif 00329 comm_mutex.lock(); 00330 data_report_mode = read_bpt_0; 00331 comm_mutex.unlock(); 00332 m_USB->printf("\r\n%s err=%d\r\n", cmd, COMM_SUCCESS); 00333 ss_int->enable_irq(); 00334 break; 00335 } 00336 00337 /* BP Estimation */ 00338 case read_bpt_1: 00339 { 00340 sample_count = 0; 00341 00342 status = ss_int->set_data_type(SS_DATATYPE_BOTH, false); 00343 if (status != SS_SUCCESS) { 00344 m_USB->printf("\r\n%s err=%d\r\n", cmd, COMM_GENERAL_ERROR); 00345 break; 00346 } 00347 00348 status = ss_int->set_fifo_thresh(15); 00349 if (status != SS_SUCCESS) { 00350 m_USB->printf("\r\n%s err=%d\r\n", cmd, COMM_GENERAL_ERROR); 00351 break; 00352 } 00353 00354 if (agc_enabled) { 00355 status = ss_int->enable_algo(SS_ALGOIDX_AGC, 1, &agc_mode1_data_req); 00356 } else { 00357 status = ss_int->disable_algo(SS_ALGOIDX_AGC); 00358 } 00359 00360 if (status != SS_SUCCESS) { 00361 m_USB->printf("\r\n%s err=%d\r\n", cmd, COMM_GENERAL_ERROR); 00362 ss_int->enable_irq(); 00363 break; 00364 } 00365 00366 ss_int->disable_irq(); 00367 #ifdef ENABLE_MAX30101 00368 status = ss_int->enable_sensor(SS_SENSORIDX_MAX30101, 1, &max30101_mode1_data_req); 00369 if (status != SS_SUCCESS) { 00370 m_USB->printf("\r\n%s err=%d\r\n", cmd, COMM_GENERAL_ERROR); 00371 ss_int->enable_irq(); 00372 break; 00373 } 00374 #endif 00375 00376 #ifdef ENABLE_BPT 00377 status = ss_int->enable_algo(SS_ALGOIDX_BPT, 2, &bpt_mode1_2_data_req); 00378 if (status != SS_SUCCESS) { 00379 m_USB->printf("\r\n%s err=%d\r\n", cmd, status); 00380 ss_int->enable_irq(); 00381 break; 00382 } 00383 #endif 00384 comm_mutex.lock(); 00385 data_report_mode = read_bpt_0; 00386 comm_mutex.unlock(); 00387 m_USB->printf("\r\n%s err=%d\r\n", cmd, COMM_SUCCESS); 00388 ss_int->enable_irq(); 00389 } break; 00390 00391 case get_reg_ppg: 00392 { 00393 uint8_t addr; 00394 uint32_t val; 00395 00396 ret = parse_get_reg_cmd(cmd, sensor_type, &addr); 00397 if (!ret) { 00398 status = ss_int->get_reg(SS_SENSORIDX_MAX30101, addr, &val); 00399 if (status == SS_SUCCESS) { 00400 m_USB->printf("\r\n%s reg_val=%02X err=%d\r\n", cmd, (uint8_t)val, COMM_SUCCESS); 00401 } else { 00402 m_USB->printf("\r\n%s err=%d\r\n", cmd, COMM_GENERAL_ERROR); 00403 } 00404 } else { 00405 m_USB->printf("\r\n%s err=%d\r\n", cmd, COMM_INVALID_PARAM); 00406 } 00407 00408 } break; 00409 00410 case set_reg_ppg: 00411 { 00412 uint8_t addr; 00413 uint8_t val; 00414 00415 ret = parse_set_reg_cmd(cmd, sensor_type, &addr, &val); 00416 if (!ret) { 00417 status = ss_int->set_reg(SS_SENSORIDX_MAX30101, addr, val, SSMAX30101_REG_SIZE); 00418 if (status == SS_SUCCESS) { 00419 m_USB->printf("\r\n%s err=%d\r\n", cmd, COMM_SUCCESS); 00420 } else { 00421 m_USB->printf("\r\n%s err=%d\r\n", cmd, COMM_GENERAL_ERROR); 00422 } 00423 } else { 00424 m_USB->printf("\r\n%s err=%d\r\n", cmd, COMM_INVALID_PARAM); 00425 } 00426 00427 } break; 00428 00429 case dump_reg_ppg: 00430 { 00431 int num_regs; 00432 status = ss_int->dump_reg(SS_SENSORIDX_MAX30101, ®_vals[0], ARRAY_SIZE(reg_vals), &num_regs); 00433 if (status == SS_SUCCESS) { 00434 int len = 0; 00435 bool comma = false; 00436 for (int reg = 0; reg < num_regs; reg++) { 00437 if (comma) { 00438 len += snprintf(&charbuf[0] + len, sizeof(charbuf) - len - 1, ","); 00439 } 00440 len += snprintf(&charbuf[0] + len, sizeof(charbuf) - len - 1, 00441 "{%X,%lX}", reg_vals[reg].addr, reg_vals[reg].val); 00442 comma = true; 00443 } 00444 charbuf[len] = '\0'; 00445 00446 m_USB->printf("\r\n%s reg_val=%s err=%d\r\n", cmd, &charbuf[0], COMM_SUCCESS); 00447 00448 } else { 00449 m_USB->printf("\r\n%s err=%d\r\n", cmd, COMM_GENERAL_ERROR); 00450 } 00451 00452 } break; 00453 00454 case set_agc_en: 00455 { 00456 agc_enabled = true; 00457 m_USB->printf("\r\n%s err=%d\r\n", cmd, COMM_SUCCESS); 00458 } break; 00459 case set_agc_dis: 00460 { 00461 agc_enabled = false; 00462 m_USB->printf("\r\n%s err=%d\r\n", cmd, COMM_SUCCESS); 00463 } break; 00464 00465 case set_cfg_bpt_med: 00466 { 00467 uint8_t val; 00468 ret = (parse_cmd_data(cmd, cmd_tbl[i], &val, 1, false) != 1); 00469 if (ret) { 00470 m_USB->printf("\r\n%s err=%d\r\n", cmd, COMM_INVALID_PARAM); 00471 break; 00472 } 00473 00474 status = ss_int->set_algo_cfg(SS_ALGOIDX_BPT, SS_CFGIDX_BP_USE_MED, &val, 1); 00475 if (status == SS_SUCCESS) 00476 m_USB->printf("\r\n%s err=%d\r\n", cmd, COMM_SUCCESS); 00477 else 00478 m_USB->printf("\r\n%s err=%d\r\n", cmd, COMM_GENERAL_ERROR); 00479 00480 } break; 00481 00482 case set_cfg_bpt_sys_bp: 00483 { 00484 uint8_t val[3]; 00485 ret = (parse_cmd_data(cmd, cmd_tbl[i], &val[0], 3, false) != 3); 00486 if (ret) { 00487 m_USB->printf("\r\n%s err=%d\r\n", cmd, COMM_INVALID_PARAM); 00488 break; 00489 } 00490 00491 status = ss_int->set_algo_cfg(SS_ALGOIDX_BPT, SS_CFGIDX_BP_SYS_BP_CAL, &val[0], 3); 00492 if (status == SS_SUCCESS) 00493 m_USB->printf("\r\n%s err=%d\r\n", cmd, COMM_SUCCESS); 00494 else 00495 m_USB->printf("\r\n%s err=%d\r\n", cmd, COMM_GENERAL_ERROR); 00496 00497 } break; 00498 00499 case set_cfg_bpt_dia_bp: 00500 { 00501 uint8_t val[3]; 00502 ret = (parse_cmd_data(cmd, cmd_tbl[i], &val[0], 3, false) != 3); 00503 if (ret) { 00504 m_USB->printf("\r\n%s err=%d\r\n", cmd, COMM_INVALID_PARAM); 00505 break; 00506 } 00507 00508 status = ss_int->set_algo_cfg(SS_ALGOIDX_BPT, SS_CFGIDX_BP_DIA_BP_CAL, &val[0], 3); 00509 if (status == SS_SUCCESS) 00510 m_USB->printf("\r\n%s err=%d\r\n", cmd, COMM_SUCCESS); 00511 else 00512 m_USB->printf("\r\n%s err=%d\r\n", cmd, COMM_GENERAL_ERROR); 00513 } break; 00514 00515 case set_cfg_bpt_date: 00516 { 00517 // Date format is yyyy mm dd 00518 uint32_t val[3]; 00519 ret = (parse_cmd_data(cmd, cmd_tbl[i], &val[0], 3, false) != 3); 00520 if (ret) { 00521 m_USB->printf("\r\n%s err=%d\r\n", cmd, COMM_INVALID_PARAM); 00522 break; 00523 } 00524 00525 uint8_t date[4] = { (uint8_t)((val[0] >> 8) & 0xFF), (uint8_t)(val[0] & 0xFF), //year_MSB, year_LSB 00526 (uint8_t)val[1], //Month 00527 (uint8_t)val[2] }; //Day 00528 00529 status = ss_int->set_algo_cfg(SS_ALGOIDX_BPT, SS_CFGIDX_BP_EST_DATE, &date[0], 4); 00530 if (status == SS_SUCCESS) 00531 m_USB->printf("\r\n%s err=%d\r\n", cmd, COMM_SUCCESS); 00532 else 00533 m_USB->printf("\r\n%s err=%d\r\n", cmd, COMM_GENERAL_ERROR); 00534 00535 } break; 00536 case set_cfg_bpt_nonrest: 00537 { 00538 uint8_t val; 00539 ret = (parse_cmd_data(cmd, cmd_tbl[i], &val, 1, false) != 1); 00540 if (ret) { 00541 m_USB->printf("\r\n%s err=%d\r\n", cmd, COMM_INVALID_PARAM); 00542 break; 00543 } 00544 00545 status = ss_int->set_algo_cfg(SS_ALGOIDX_BPT, SS_CFGIDX_BP_EST_NONREST, &val, 1); 00546 if (status == SS_SUCCESS) 00547 m_USB->printf("\r\n%s err=%d\r\n", cmd, COMM_SUCCESS); 00548 else 00549 m_USB->printf("\r\n%s err=%d\r\n", cmd, COMM_GENERAL_ERROR); 00550 00551 } break; 00552 00553 case self_test_ppg_os24: 00554 { 00555 ret = selftest_max30101(); 00556 m_USB->printf("%s selftest_max30101: err=<%d>\r\n", cmd, ret); 00557 } break; 00558 00559 case self_test_ppg_acc: 00560 { 00561 ret = selftest_accelerometer(); 00562 m_USB->printf("%s selftest_accelerometer: err=<%d>\r\n", cmd, ret); 00563 } break; 00564 00565 default: 00566 { 00567 assert_msg(false, "Invalid switch case!"); 00568 } break; 00569 00570 } 00571 break; 00572 } 00573 } 00574 00575 return recognizedCmd; 00576 } 00577 00578 void SSMAX30101Comm::max30101_data_rx(uint8_t* data_ptr) 00579 { 00580 max30101_mode1_data sample; 00581 sample.led1 = (data_ptr[0] << 16) | (data_ptr[1] << 8) | data_ptr[2]; 00582 sample.led2 = (data_ptr[3] << 16) | (data_ptr[4] << 8) | data_ptr[5]; 00583 sample.led3 = (data_ptr[6] << 16) | (data_ptr[7] << 8) | data_ptr[8]; 00584 sample.led4 = (data_ptr[9] << 16) | (data_ptr[10] << 8) | data_ptr[11]; 00585 00586 pr_info("led1=%.6X led2=%.6X led3=%.6X led4=%.6X\r\n", sample.led1, sample.led2, sample.led3, sample.led4); 00587 00588 enqueue(&max30101_queue, &sample); 00589 } 00590 00591 void SSMAX30101Comm::bpt_data_rx(uint8_t* data_ptr) 00592 { 00593 bpt_mode1_2_data sample; 00594 sample.status = data_ptr[0]; 00595 sample.prog = data_ptr[1]; 00596 sample.hr = (data_ptr[2] << 8) | data_ptr[3]; 00597 sample.sys_bp = data_ptr[4]; 00598 sample.dia_bp = data_ptr[5]; 00599 00600 pr_info("status=%d prog=%d hr=%.1f sys=%d dia=%d\r\n", sample.status, sample.prog, sample.hr, sample.sys_bp, sample.dia_bp); 00601 enqueue(&bpt_queue, &sample); 00602 } 00603 00604 void SSMAX30101Comm::whrm_data_rx(uint8_t* data_ptr) 00605 { 00606 //See API doc for data format 00607 whrm_mode1_data sample; 00608 sample.hr = (data_ptr[0] << 8) | data_ptr[1]; 00609 sample.hr_conf = data_ptr[2]; 00610 sample.spo2 = (data_ptr[3] << 8) | data_ptr[4]; 00611 sample.status = data_ptr[5]; 00612 00613 pr_info("hr=%.1f conf=%d spo2=%d status=%d\r\n", (float)sample.hr / 10.0, sample.hr_conf, sample.spo2, sample.status); 00614 enqueue(&whrm_queue, &sample); 00615 } 00616 00617 void SSMAX30101Comm::accel_data_rx(uint8_t* data_ptr) 00618 { 00619 //See API doc for data format 00620 accel_mode1_data sample; 00621 sample.x = (data_ptr[0] << 8) | data_ptr[1]; 00622 sample.y = (data_ptr[2] << 8) | data_ptr[3]; 00623 sample.z = (data_ptr[4] << 8) | data_ptr[5]; 00624 00625 enqueue(&accel_queue, &sample); 00626 } 00627 00628 void SSMAX30101Comm::agc_data_rx(uint8_t* data_ptr) 00629 { 00630 //NOP: AGC does not collect data 00631 } 00632 00633 int SSMAX30101Comm::data_report_execute(char* buf, int size) 00634 { 00635 uint8_t tmp_report_mode; 00636 max30101_mode1_data max30101_sample = { 0 }; 00637 whrm_mode1_data whrm_sample = { 0 }; 00638 accel_mode1_data accel_sample = { 0 }; 00639 bpt_mode1_2_data bpt_sample = { 0 }; 00640 int16_t data_len = 0; 00641 00642 if (size <= 0) 00643 return 0; 00644 00645 if (!is_enabled()) 00646 return 0; 00647 00648 ss_int->ss_execute_once(); 00649 00650 comm_mutex.lock(); 00651 tmp_report_mode = data_report_mode; 00652 comm_mutex.unlock(); 00653 00654 switch (tmp_report_mode) { 00655 case read_ppg_0: 00656 { 00657 if (1 00658 00659 #ifdef ENABLE_MAX30101 00660 && queue_len(&max30101_queue) > 0 00661 #endif 00662 #ifdef ENABLE_ACCEL 00663 && queue_len(&accel_queue) > 0 00664 #endif 00665 #ifdef ENABLE_WHRM_ANS_SP02 00666 && queue_len(&whrm_queue) > 0 00667 #endif 00668 ) 00669 { 00670 #ifdef ENABLE_MAX30101 00671 dequeue(&max30101_queue, &max30101_sample); 00672 #endif 00673 #ifdef ENABLE_ACCEL 00674 dequeue(&accel_queue, &accel_sample); 00675 #endif 00676 #ifdef ENABLE_WHRM_ANS_SP02 00677 dequeue(&whrm_queue, &whrm_sample); 00678 #endif 00679 00680 #ifdef ASCII_COMM 00681 data_len = snprintf(buf, size - 1, "%u,%lu,%lu,%lu,%lu,%.3f,%.3f,%.3f,%.1f,%d,%.1f,%d\r\n", 00682 sample_count++, 00683 max30101_sample.led1, 00684 max30101_sample.led2, 00685 max30101_sample.led3, 00686 max30101_sample.led4, 00687 accel_sample.x * 0.001, 00688 accel_sample.y * 0.001, 00689 accel_sample.z * 0.001, 00690 whrm_sample.hr * 0.1, 00691 whrm_sample.hr_conf, 00692 whrm_sample.spo2 * 0.1, 00693 whrm_sample.status); 00694 #else 00695 assert_msg(((uint32_t)size > sizeof(ds_pkt_data_mode1)), "data_report_execute buffer too small"); 00696 ds_pkt_data_mode1* pkt = (ds_pkt_data_mode1*)buf; 00697 pkt->start_byte = DS_BINARY_PACKET_START_BYTE; 00698 pkt->led1 = max30101_sample.led1; 00699 pkt->led2 = max30101_sample.led2; 00700 pkt->led3 = max30101_sample.led3; 00701 pkt->led4 = max30101_sample.led4; 00702 pkt->x = accel_sample.x; 00703 pkt->y = accel_sample.y; 00704 pkt->z = accel_sample.z; 00705 pkt->hr = whrm_sample.hr; 00706 pkt->spo2 = whrm_sample.spo2; 00707 pkt->status = whrm_sample.status; 00708 pkt->crc8 = crc8((uint8_t*)pkt, sizeof(ds_pkt_data_mode1) - sizeof(uint8_t)); 00709 data_len = sizeof(ds_pkt_data_mode1); 00710 #endif 00711 #if 1 00712 //static uint32_t led4_old_cnt = 0; 00713 00714 //if (max30101_sample.led4 != (led4_old_cnt + 1)) { 00715 // pr_err("\r\n**** JUMP %d to %d\r\n", max30101_sample.led4, led4_old_cnt); 00716 //} 00717 //led4_old_cnt = max30101_sample.led4; 00718 #endif 00719 00720 } 00721 } break; 00722 00723 00724 case read_bpt_0: 00725 case read_bpt_1: 00726 { 00727 if (1 00728 00729 #ifdef ENABLE_MAX30101 00730 && queue_len(&max30101_queue) > 0 00731 #endif 00732 #ifdef ENABLE_BPT 00733 && queue_len(&bpt_queue) > 0 00734 #endif 00735 ) 00736 { 00737 #ifdef ENABLE_MAX30101 00738 dequeue(&max30101_queue, &max30101_sample); 00739 #endif 00740 #ifdef ENABLE_BPT 00741 dequeue(&bpt_queue, &bpt_sample); 00742 #endif 00743 00744 #ifdef ASCII_COMM 00745 data_len = snprintf(buf, size - 0, "%d,%d,%.1f,%d,%d,%d\r\n", 00746 bpt_sample.status, 00747 max30101_sample.led1, 00748 bpt_sample.hr * 0.1, 00749 bpt_sample.prog, 00750 bpt_sample.sys_bp, 00751 bpt_sample.dia_bp); 00752 #else 00753 assert_msg(((uint32_t)size > sizeof(ds_pkt_bpt_data)), "data_report_execute buffer too small"); 00754 ds_pkt_bpt_data *pkt = (ds_pkt_bpt_data *)buf; 00755 pkt->start_byte = DS_BINARY_PACKET_START_BYTE; 00756 pkt->status = bpt_sample.status; 00757 pkt->irCnt = max30101_sample.led1; 00758 pkt->hr = bpt_sample.hr / 10; 00759 pkt->prog = bpt_sample.prog; 00760 pkt->sys_bp = bpt_sample.sys_bp; 00761 pkt->dia_bp = bpt_sample.dia_bp; 00762 pkt->crc8 = crc8((uint8_t*)pkt, sizeof(ds_pkt_bpt_data) - sizeof(uint8_t)); 00763 data_len = sizeof(ds_pkt_bpt_data); 00764 #endif 00765 00766 } 00767 } break; 00768 00769 default: 00770 return 0; 00771 } 00772 00773 if (data_len < 0) { 00774 pr_err("snprintf console_tx_buf failed"); 00775 } else if (data_len > size) { 00776 pr_err("buffer is insufficient to hold data"); 00777 } 00778 00779 return data_len; 00780 } 00781 00782 // TODO: convert this to PPG sensor test 00783 int SSMAX30101Comm::selftest_max30101(){ 00784 int ret; 00785 uint8_t test_result; 00786 bool test_failed = false; 00787 m_USB->printf("starting selftest_max30101\r\n"); 00788 // configure mfio pin for self test 00789 ss_int->mfio_selftest(); 00790 ret = ss_int->self_test(SS_SENSORIDX_MAX30101, &test_result, 500); 00791 if(ret != SS_SUCCESS){ 00792 m_USB->printf("ss_int->self_test(SS_SENSORIDX_MAX30101, &test_result) has failed err<-1>\r\n"); 00793 test_failed = true; 00794 } 00795 // reset mfio pin to old state 00796 if(!ss_int->reset_mfio_irq()){ 00797 m_USB->printf("smart sensor reset_mfio_irq has failed err<-1>\r\n"); 00798 test_failed = true; 00799 } 00800 // reset the sensor to turn off the LED 00801 ret = ss_int->reset(); 00802 if(test_failed | !self_test_result_evaluate("selftest_max30101", test_result)){ 00803 return -1; 00804 }else{ 00805 return SS_SUCCESS; 00806 } 00807 } 00808 00809 int SSMAX30101Comm::selftest_accelerometer(){ 00810 int ret; 00811 uint8_t test_result; 00812 bool test_failed = false; 00813 m_USB->printf("starting selftest_accelerometer\r\n"); 00814 ret = ss_int->self_test(SS_SENSORIDX_ACCEL, &test_result, 1000); 00815 if(ret != SS_SUCCESS){ 00816 m_USB->printf("ss_int->self_test(SS_SENSORIDX_ACCEL, &test_result) has failed err<-1>\r\n"); 00817 test_failed = true; 00818 } 00819 // reset the sensor to turn off the LED 00820 ret = ss_int->reset(); 00821 if(ret != SS_SUCCESS){ 00822 m_USB->printf("smart sensor reset has failed err<-1>\r\n"); 00823 test_failed = true; 00824 } 00825 if(test_failed | !self_test_result_evaluate("selftest_accelerometer", test_result)){ 00826 return -1; 00827 }else{ 00828 return SS_SUCCESS; 00829 } 00830 } 00831 00832 bool SSMAX30101Comm::self_test_result_evaluate(const char *message, uint8_t result){ 00833 // check i2c response status 00834 if(result != 0x00){ 00835 m_USB->printf("%s has failed % 02X err<-1>\r\n", message, result); 00836 if((result & FAILURE_COMM)) 00837 m_USB->printf("%s communication has failed err<-1>\r\n", message); 00838 if(result & FAILURE_INTERRUPT) 00839 m_USB->printf("%s interrupt pin check has failed err<-1>\r\n", message); 00840 return false; 00841 } 00842 return true; 00843 } 00844 00845 const char* SSMAX30101Comm::get_algo_ver() 00846 { 00847 return ss_int->get_ss_algo_version(); 00848 }
Generated on Tue Jul 12 2022 10:59:32 by
1.7.2

Heart Rate SpO2 Algorithm EvKit Health Monitor Development System Board MAXREFDES220