Rohit Grover / Mbed 2 deprecated BLE_HeartRate_Pixart

Dependencies:   BLE_API mbed nRF51822 paw8001motion25_nrf51_mbed_keil

Fork of BLE_HeartRate by Bluetooth Low Energy

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2006-2013 ARM Limited
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 #include "mbed.h"
00018 #include "BLEDevice.h"
00019 #include "HeartRateService.h"
00020 #include "BatteryService.h"
00021 #include "DeviceInformationService.h"
00022 
00023 BLEDevice  ble;
00024 DigitalOut led1(LED1);
00025 /* ---------------------------------------------------------------
00026  * Below for PAH8001 code
00027 *///--------------------------------------------------------------
00028 #include "app_util_platform.h"
00029 #include "nrf_soc.h"
00030 #include "app_util.h"
00031 #include "PAH8001Set.h"
00032 extern "C"
00033 {
00034     #include "pxialg.h"
00035 }
00036 Serial  pc(USBTX, USBRX);
00037 I2C i2c(I2C_SDA0, I2C_SCL0);
00038 Ticker  ticker;
00039 /* Power optimized, 1.0mA @disconnection, 4.5mA @connection */
00040 #define MIN_CONN_INTERVAL   MSEC_TO_UNITS(379, UNIT_1_25_MS)              /**< Minimum connection interval (379 ms) */
00041 #define MAX_CONN_INTERVAL   MSEC_TO_UNITS(399, UNIT_1_25_MS)              /**< Maximum connection interval (399 ms). */
00042 #define SLAVE_LATENCY       4                                             /**< Slave latency. */
00043 #define CONN_SUP_TIMEOUT    MSEC_TO_UNITS(6000, UNIT_10_MS)               /**< Connection supervisory timeout (6 seconds). */
00044 /* ---------------------------------------------------------------
00045  * End of PAH8001 code
00046 *///--------------------------------------------------------------
00047 
00048 const static char     DEVICE_NAME[]        = "PixArt_HRmbed";
00049 static const uint16_t uuid16_list[]        = {GattService::UUID_HEART_RATE_SERVICE,
00050                                               GattService::UUID_BATTERY_SERVICE,
00051                                               GattService::UUID_DEVICE_INFORMATION_SERVICE};
00052  /* ---------------------------------------------------------------
00053  * Below for PAH8001 code
00054 *///--------------------------------------------------------------
00055 static volatile bool  triggerSensorPolling = false;
00056 void disconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t reason)
00057 {
00058     ble.startAdvertising(); // restart advertising
00059     triggerSensorPolling = false;
00060 }
00061 void onconnectionCallback(Gap::Handle_t handle, Gap::addr_type_t peerAddrType, const Gap::address_t peerAddr, const Gap::ConnectionParams_t *p_conn_param)
00062 {
00063     triggerSensorPolling = true;
00064     Gap::ConnectionParams_t gap_conn_params;
00065     gap_conn_params.minConnectionInterval = MIN_CONN_INTERVAL;
00066     gap_conn_params.maxConnectionInterval = MAX_CONN_INTERVAL;
00067     gap_conn_params.slaveLatency = SLAVE_LATENCY;
00068     gap_conn_params.connectionSupervisionTimeout = CONN_SUP_TIMEOUT;
00069     ble.updateConnectionParams(handle, &gap_conn_params);
00070 }
00071 
00072 void periodicCallback(void)
00073 {  
00074     if(triggerSensorPolling == true){
00075         HR_Cnt++;
00076         CRITICAL_REGION_ENTER();
00077         Pixart_HRD();
00078         CRITICAL_REGION_EXIT();
00079     }
00080     else
00081         HR_Cnt = 0;
00082 }
00083 
00084 int main(void)
00085 {   uint8_t tmp;
00086     pc.baud (115200);
00087     pc.printf("\n\rStart initialization\n\r");    
00088     
00089     led1 = 1;
00090     PAH8001_init(); //PAH8001 initialization
00091 
00092     ble.init();
00093     ble.onDisconnection(disconnectionCallback);
00094     ble.onConnection(onconnectionCallback);
00095 
00096     /* Setup primary service. */
00097     uint8_t hrmCounter = 100;
00098     HeartRateService hrService(ble, hrmCounter, HeartRateService::LOCATION_FINGER);
00099 
00100     /* Setup auxiliary services. */
00101     BatteryService           battery(ble);
00102     DeviceInformationService deviceInfo(ble, "ARM", "Model1", "SN1", "hw-rev1", "fw-rev1", "soft-rev1");
00103 
00104     /* Setup advertising. */
00105     ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
00106     ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list));
00107     ble.accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_HEART_RATE_SENSOR);
00108     ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
00109     ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
00110     ble.setAdvertisingInterval(1600); /* 1000ms; in multiples of 0.625ms. */
00111     ble.startAdvertising();
00112     
00113     pc.printf("Before while 1\n\r");
00114     while (true) {
00115         if(triggerSensorPolling == true){
00116             if(!isFIFOEmpty())
00117             {
00118                 led1 = 1;
00119                 //pc.printf("PPG[8]: %d\n\r", ppg_mems_data.HRD_Data[8]);
00120                 if(Pop(&ppg_mems_data)) //Get data from FIFO
00121                 {
00122                     MEMS_Data[0] = ppg_mems_data.MEMS_Data[0];
00123                     MEMS_Data[1] = ppg_mems_data.MEMS_Data[1];
00124                     MEMS_Data[2] = ppg_mems_data.MEMS_Data[2];
00125                     
00126                     tmp = PxiAlg_Process(ppg_mems_data.HRD_Data, MEMS_Data);
00127                     //if( tmp == FLAG_DATA_READY)
00128                     if( tmp != FLAG_DATA_READY)
00129                     {
00130                         pc.printf("AlgoProcssRtn: %d\n\r", tmp);
00131                         pc.printf("PPG[8]: %d\n\r", ppg_mems_data.HRD_Data[8]);
00132                     }
00133                     else
00134                     {
00135                         //Check Flag
00136                     }
00137     
00138                     //ready_flag = PxiAlg_GetReadyFlag();
00139                     //motion_flag = PxiAlg_GetMotionFlag() ;
00140                 }
00141                 led1 = 0;
00142             }
00143             if(HR_Cnt > HR_Rpt)
00144             {
00145                 HR_Cnt = 0;
00146                 PxiAlg_HrGet(&myHR);
00147                 pc.printf("HR: %d\n\r", (uint8_t)myHR);            
00148     
00149                 hrmCounter = (uint8_t)myHR;
00150                 hrService.updateHeartRate(hrmCounter);
00151             }
00152         }
00153         else
00154             ble.waitForEvent();
00155     }
00156 }
00157 
00158 
00159 
00160 void PAH8001_init()
00161 {   uint8_t q;
00162     uint8_t bank=0, temp;
00163 
00164     if(readRegister(0x00) == 0x30)
00165         pc.printf("PAH8001 I2C Link Successful!\n\r");
00166     else
00167         pc.printf("PAH8001 I2C Link Fail!\n\r");
00168         
00169     alg_version = PxiAlg_Version();
00170     pc.printf("Algo Ver: %d\n\r", alg_version);
00171     PxiAlg_EnableFastOutput(true);
00172 
00173 #ifdef DEBUG_8001
00174     writeRegister(0x09, 0x5A); writeRegister(0x54, 0xEE);
00175     pc.printf("\n\r~~~Start Test Pattern~~~ \n\r");
00176     pc.printf("Reg0x09: %d\n\r", readRegister(0x09));
00177     pc.printf("Reg0x54: %d\n\r", readRegister(0x54));
00178     pc.printf("Reg0x1E: %d\n\r", readRegister(0x1E));
00179     
00180     float MEMS_Data[3] = {0 ,0, 0}; //apply test pattern
00181     float myHR = 0 ;
00182     for(q=0;q<PPG_PATTERN_SIZE;q++)
00183         PxiAlg_Process((unsigned char*)PPG_Data[q], MEMS_Data);
00184     PxiAlg_HrGet(&myHR);
00185     pc.printf("HR: %f\n\r", myHR);
00186     pc.printf("~~~End of Test Pattern~~~ \n\r");
00187     while(1);
00188 #endif
00189     
00190 #ifndef DEBUG_8001
00191     ticker.attach_us(&periodicCallback, PAH8001_Poll*1000);
00192     
00193     pc.printf("\n\r~~~Start Real-time HRM~~~ \n\r");
00194     //Initialization settings
00195     writeRegister(0x06, 0x82);  //Reset sensor
00196     wait_ms(10);    //make a delay
00197     
00198     for(q=0;q<INIT_PPG_REG_ARRAY_SIZE;q++){
00199         if(init_ppg_register_array[q][0] == 0x7F)
00200             bank = init_ppg_register_array[q][1];
00201 
00202         if((bank == 0) && (init_ppg_register_array[q][0] == 0x17) )
00203         {
00204             //read and write bit7=1
00205             temp = readRegister(0x17);
00206             temp |= 0x80 ;
00207             writeRegister(0x17, temp) ;
00208         }
00209         else
00210             writeRegister(init_ppg_register_array[q][0], init_ppg_register_array[q][1]);
00211     }
00212 #endif
00213 }
00214 
00215 void writeRegister(uint8_t addr, uint8_t data)
00216 {
00217     char data_write[2];
00218     
00219     data_write[0] = addr;
00220     data_write[1] = data;
00221     i2c.write(I2C_ADDR, data_write, 2, 0);
00222 }
00223 uint8_t readRegister(uint8_t addr)
00224 {
00225     char data_write[2];
00226     char data_read[2];
00227     
00228     data_write[0] = addr;
00229     i2c.write(I2C_ADDR, data_write, 1, 0);
00230     i2c.read(I2C_ADDR, data_read, 1, 0);
00231     return data_read[0];
00232 }
00233 
00234 bool Pixart_HRD(void)
00235 {
00236     uint8_t tmp=0;
00237     char data_write[2];
00238     char data_read[4];
00239     ppg_mems_data_t ppg_mems_data;
00240     //Check Touch Status for power saving
00241     writeRegister(0x7F,0x00); //bank0
00242     tmp = readRegister(0x00);
00243     tmp = readRegister(0x59)&0x80;
00244     led_ctrl(tmp);
00245 
00246     //writeRegister(0x7F,0x01); //bank1
00247     ppg_mems_data.HRD_Data[0]=readRegister(0x68)&0x0f; //check status: 0 is not ready, 1 is ready, 2 is loss one data?
00248 
00249     if(ppg_mems_data.HRD_Data[0] ==0)
00250     {
00251         writeRegister(0x7F,0x00); //bank0
00252         return false;
00253     }
00254     else
00255     {
00256         //Only support burst read (0x64~0x67), when using I2C interface
00257         data_write[0] = 0x64;
00258         i2c.write(PAH8001_ADDR, data_write, 1, 1);
00259         i2c.read(PAH8001_ADDR, data_read, 4, 0);
00260         ppg_mems_data.HRD_Data[1]=data_read[0]&0xff;
00261         ppg_mems_data.HRD_Data[2]=data_read[1]&0xff;
00262         ppg_mems_data.HRD_Data[3]=data_read[2]&0xff;
00263         ppg_mems_data.HRD_Data[4]=data_read[3]&0xff;
00264 
00265         //Only support burst read (0x1A~0x1C), when using I2C interface
00266         data_write[0] = 0x1A;
00267         i2c.write(PAH8001_ADDR, data_write, 1, 1);
00268         i2c.read(PAH8001_ADDR, data_read, 3, 0);
00269         ppg_mems_data.HRD_Data[5]=data_read[0]&0xff;
00270         ppg_mems_data.HRD_Data[6]=data_read[1]&0xff;
00271         ppg_mems_data.HRD_Data[7]=data_read[2]&0xff;
00272 
00273         ppg_mems_data.HRD_Data[8]=Frame_Count++;
00274         ppg_mems_data.HRD_Data[9]=40;
00275         ppg_mems_data.HRD_Data[10]=_led_current_change_flag;
00276         writeRegister(0x7F,0x00); //bank0
00277         //bit7 is Touch Flag (bit7=1 is meant Touch, and bit7=0 is meant No Touch)
00278         ppg_mems_data.HRD_Data[11]=(readRegister(0x59)&0x80); //Check Touch Flag
00279         ppg_mems_data.HRD_Data[12]= ppg_mems_data.HRD_Data[6];
00280         
00281         //If no G sensor, please set G_Sensor_Data[3] = {0};
00282         ppg_mems_data.MEMS_Data[0] = 0;//ReadGSensorX();
00283         ppg_mems_data.MEMS_Data[1] = 0;//ReadGSensorY();
00284         ppg_mems_data.MEMS_Data[2] = 0;//ReadGSensorZ();
00285         Push(&ppg_mems_data); //Save data into FIFO
00286         
00287         return true;
00288     }
00289 }
00290 
00291 bool isFIFOEmpty(void)
00292 {
00293     return (_write_index == _read_index);
00294 }
00295 
00296 bool Push(ppg_mems_data_t *data)
00297 {
00298     int tmp = _write_index;
00299     tmp++;
00300     if(tmp >= FIFO_SIZE)
00301         tmp = 0;
00302     if(tmp == _read_index)
00303         return false;
00304     _ppg_mems_data[tmp] = *data;
00305     _write_index = tmp;
00306     
00307     return true;
00308 }
00309 
00310 bool Pop(ppg_mems_data_t *data)
00311 {
00312     int tmp;
00313     if(isFIFOEmpty())
00314         return false;
00315     *data = _ppg_mems_data[_read_index];
00316     tmp = _read_index + 1;
00317     if(tmp >= FIFO_SIZE)
00318         tmp = 0;
00319     _read_index = tmp;
00320     
00321     return true;
00322 }
00323 
00324 /***********************LED Control Start***********************************/
00325 void led_ctrl(uint8_t touch)    {
00326     if(touch == 0x80)   {
00327         uint8_t data;
00328         //uint16_t Frame_Average, EP_L, EP_H, Exposure_Line;
00329         uint16_t EP_L, EP_H, Exposure_Line;
00330         writeRegister(0x7f,0x00);
00331         writeRegister(0x05,0x98);
00332         writeRegister(0x7f,0x01);
00333         //writeRegister(0x42,0xA4);
00334         writeRegister(0x7f,0x00);
00335         data = readRegister(0x33);
00336         EP_H=data&0x03;
00337         data = readRegister(0x32);
00338         EP_L=data;
00339         Exposure_Line=(EP_H<<8)+EP_L;
00340         writeRegister(0x7f,0x01);
00341         if(_sleepflag==1)   {
00342             writeRegister(0x38, (0xE0|DEFAULT_LED_STEP));
00343             _sleepflag = 0 ;
00344         }
00345 
00346         if (_state_count <= STATE_COUNT_TH) {
00347             _state_count++;
00348             _led_current_change_flag = 0;
00349         }
00350         else {
00351             _state_count = 0;
00352             if(_state == 0) {
00353                 if( (Exposure_Line>=LED_CTRL_EXPO_TIME_HI_BOUND) || (Exposure_Line<=LED_CTRL_EXPO_TIME_LOW_BOUND) ) {
00354                     //writeRegister(0x7f,0x01);
00355                     data = readRegister(0x38);
00356                     _led_step=data&0x1f;
00357                     if( (Exposure_Line>=LED_CTRL_EXPO_TIME_HI_BOUND) && (_led_step < LED_CURRENT_HI) )  {
00358                         _state = 1 ;
00359                         _led_step=_led_step+LED_INC_DEC_STEP;
00360 
00361                         if(_led_step>LED_CURRENT_HI)
00362                             _led_step=LED_CURRENT_HI;
00363                         writeRegister(0x38, (_led_step|0xE0));
00364                         _led_current_change_flag = 1;
00365                     }
00366                     else if((Exposure_Line<=LED_CTRL_EXPO_TIME_LOW_BOUND) && (_led_step > LED_CURRENT_LOW) )    {
00367                         _state = 2 ;
00368                         if(_led_step<=(LED_CURRENT_LOW+LED_INC_DEC_STEP))
00369                             _led_step=LED_CURRENT_LOW;
00370                         else
00371                             _led_step=_led_step-LED_INC_DEC_STEP;
00372                         writeRegister(0x38, (_led_step|0xE0));
00373                         _led_current_change_flag = 1;
00374                     }
00375                     else    {
00376                         _state = 0 ;
00377                         _led_current_change_flag = 0;
00378                     }
00379                 }
00380                 else {
00381                     _led_current_change_flag = 0;
00382                 }
00383             }
00384             else if(_state == 1)    {
00385                 if(Exposure_Line > LED_CTRL_EXPO_TIME_HI)   {
00386                     _state = 1 ;
00387                     _led_step=_led_step+LED_INC_DEC_STEP;
00388                     if(_led_step>=LED_CURRENT_HI)   {
00389                         _state = 0 ;
00390                         _led_step=LED_CURRENT_HI;
00391                     }
00392                     writeRegister(0x38, (_led_step|0xE0));
00393                     _led_current_change_flag = 1;
00394                 }
00395                 else    {
00396                     _state = 0 ;
00397                     _led_current_change_flag = 0;
00398                 }
00399             }
00400             else    {
00401                 if(Exposure_Line < LED_CTRL_EXPO_TIME_LOW)  {
00402                     _state = 2 ;
00403                     if(_led_step<=(LED_CURRENT_LOW+LED_INC_DEC_STEP))   {
00404                         _state = 0 ;
00405                         _led_step=LED_CURRENT_LOW;
00406                     }
00407                     else
00408                         _led_step=_led_step-LED_INC_DEC_STEP;
00409                     writeRegister(0x38, (_led_step|0xE0));
00410                     _led_current_change_flag = 1;
00411                 }
00412                 else    {
00413                     _state = 0;
00414                     _led_current_change_flag = 0;
00415                 }
00416             }
00417         }
00418     }
00419     else    {
00420         writeRegister(0x7f,0x00);
00421         writeRegister(0x05,0xB8);
00422         writeRegister(0x7F,0x01);
00423         //writeRegister(0x42,0xA0);
00424         _led_step = DEFAULT_LED_STEP;
00425         writeRegister(0x38, 0xFF);
00426         _sleepflag = 1;
00427         _led_current_change_flag = 0;
00428     }
00429 }
00430 /***********************LED Control End ***********************************/
00431 /* ---------------------------------------------------------------
00432  * End of PAH8001 code
00433 *///--------------------------------------------------------------