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