Maxim Integrated / Mbed OS MAXREFDES220#

Dependencies:   USBDevice max32630fthr

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