Maxim Integrated / Mbed OS MAXREFDES220_HR_SPO2_MONITOR

Dependencies:   max32630fthr USBDevice

Fork of MAXREFDES220_HEART_RATE_MONITOR by Maxim Integrated

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers SSMAX30101Comm.cpp Source File

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, &reg_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 }