Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: BLE_API mbed nRF51822 paw8001motion25_nrf51_mbed_keil
Fork of BLE_HeartRate by
main.cpp
- Committer:
- rgrover1
- Date:
- 2015-01-23
- Revision:
- 51:464a019d3191
- Parent:
- 50:f7808934677c
File content as of revision 51:464a019d3191:
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "mbed.h"
#include "BLEDevice.h"
#include "HeartRateService.h"
#include "BatteryService.h"
#include "DeviceInformationService.h"
BLEDevice ble;
DigitalOut led1(LED1);
/* ---------------------------------------------------------------
* Below for PAH8001 code
*///--------------------------------------------------------------
#include "app_util_platform.h"
#include "nrf_soc.h"
#include "app_util.h"
#include "PAH8001Set.h"
extern "C"
{
#include "pxialg.h"
}
Serial pc(USBTX, USBRX);
I2C i2c(I2C_SDA0, I2C_SCL0);
Ticker ticker;
/* Power optimized, 1.0mA @disconnection, 4.5mA @connection */
#define MIN_CONN_INTERVAL MSEC_TO_UNITS(379, UNIT_1_25_MS) /**< Minimum connection interval (379 ms) */
#define MAX_CONN_INTERVAL MSEC_TO_UNITS(399, UNIT_1_25_MS) /**< Maximum connection interval (399 ms). */
#define SLAVE_LATENCY 4 /**< Slave latency. */
#define CONN_SUP_TIMEOUT MSEC_TO_UNITS(6000, UNIT_10_MS) /**< Connection supervisory timeout (6 seconds). */
/* ---------------------------------------------------------------
* End of PAH8001 code
*///--------------------------------------------------------------
const static char DEVICE_NAME[] = "PixArt_HRmbed";
static const uint16_t uuid16_list[] = {GattService::UUID_HEART_RATE_SERVICE,
GattService::UUID_BATTERY_SERVICE,
GattService::UUID_DEVICE_INFORMATION_SERVICE};
/* ---------------------------------------------------------------
* Below for PAH8001 code
*///--------------------------------------------------------------
static volatile bool triggerSensorPolling = false;
void disconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t reason)
{
ble.startAdvertising(); // restart advertising
triggerSensorPolling = false;
}
void onconnectionCallback(Gap::Handle_t handle, Gap::addr_type_t peerAddrType, const Gap::address_t peerAddr, const Gap::ConnectionParams_t *p_conn_param)
{
triggerSensorPolling = true;
Gap::ConnectionParams_t gap_conn_params;
gap_conn_params.minConnectionInterval = MIN_CONN_INTERVAL;
gap_conn_params.maxConnectionInterval = MAX_CONN_INTERVAL;
gap_conn_params.slaveLatency = SLAVE_LATENCY;
gap_conn_params.connectionSupervisionTimeout = CONN_SUP_TIMEOUT;
ble.updateConnectionParams(handle, &gap_conn_params);
}
void periodicCallback(void)
{
if(triggerSensorPolling == true){
HR_Cnt++;
CRITICAL_REGION_ENTER();
Pixart_HRD();
CRITICAL_REGION_EXIT();
}
else
HR_Cnt = 0;
}
int main(void)
{ uint8_t tmp;
pc.baud (115200);
pc.printf("\n\rStart initialization\n\r");
led1 = 1;
PAH8001_init(); //PAH8001 initialization
ble.init();
ble.onDisconnection(disconnectionCallback);
ble.onConnection(onconnectionCallback);
/* Setup primary service. */
uint8_t hrmCounter = 100;
HeartRateService hrService(ble, hrmCounter, HeartRateService::LOCATION_FINGER);
/* Setup auxiliary services. */
BatteryService battery(ble);
DeviceInformationService deviceInfo(ble, "ARM", "Model1", "SN1", "hw-rev1", "fw-rev1", "soft-rev1");
/* Setup advertising. */
ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list));
ble.accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_HEART_RATE_SENSOR);
ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
ble.setAdvertisingInterval(1600); /* 1000ms; in multiples of 0.625ms. */
ble.startAdvertising();
pc.printf("Before while 1\n\r");
while (true) {
if(triggerSensorPolling == true){
if(!isFIFOEmpty())
{
led1 = 1;
//pc.printf("PPG[8]: %d\n\r", ppg_mems_data.HRD_Data[8]);
if(Pop(&ppg_mems_data)) //Get data from FIFO
{
MEMS_Data[0] = ppg_mems_data.MEMS_Data[0];
MEMS_Data[1] = ppg_mems_data.MEMS_Data[1];
MEMS_Data[2] = ppg_mems_data.MEMS_Data[2];
tmp = PxiAlg_Process(ppg_mems_data.HRD_Data, MEMS_Data);
//if( tmp == FLAG_DATA_READY)
if( tmp != FLAG_DATA_READY)
{
pc.printf("AlgoProcssRtn: %d\n\r", tmp);
pc.printf("PPG[8]: %d\n\r", ppg_mems_data.HRD_Data[8]);
}
else
{
//Check Flag
}
//ready_flag = PxiAlg_GetReadyFlag();
//motion_flag = PxiAlg_GetMotionFlag() ;
}
led1 = 0;
}
if(HR_Cnt > HR_Rpt)
{
HR_Cnt = 0;
PxiAlg_HrGet(&myHR);
pc.printf("HR: %d\n\r", (uint8_t)myHR);
hrmCounter = (uint8_t)myHR;
hrService.updateHeartRate(hrmCounter);
}
}
else
ble.waitForEvent();
}
}
void PAH8001_init()
{ uint8_t q;
uint8_t bank=0, temp;
if(readRegister(0x00) == 0x30)
pc.printf("PAH8001 I2C Link Successful!\n\r");
else
pc.printf("PAH8001 I2C Link Fail!\n\r");
alg_version = PxiAlg_Version();
pc.printf("Algo Ver: %d\n\r", alg_version);
PxiAlg_EnableFastOutput(true);
#ifdef DEBUG_8001
writeRegister(0x09, 0x5A); writeRegister(0x54, 0xEE);
pc.printf("\n\r~~~Start Test Pattern~~~ \n\r");
pc.printf("Reg0x09: %d\n\r", readRegister(0x09));
pc.printf("Reg0x54: %d\n\r", readRegister(0x54));
pc.printf("Reg0x1E: %d\n\r", readRegister(0x1E));
float MEMS_Data[3] = {0 ,0, 0}; //apply test pattern
float myHR = 0 ;
for(q=0;q<PPG_PATTERN_SIZE;q++)
PxiAlg_Process((unsigned char*)PPG_Data[q], MEMS_Data);
PxiAlg_HrGet(&myHR);
pc.printf("HR: %f\n\r", myHR);
pc.printf("~~~End of Test Pattern~~~ \n\r");
while(1);
#endif
#ifndef DEBUG_8001
ticker.attach_us(&periodicCallback, PAH8001_Poll*1000);
pc.printf("\n\r~~~Start Real-time HRM~~~ \n\r");
//Initialization settings
writeRegister(0x06, 0x82); //Reset sensor
wait_ms(10); //make a delay
for(q=0;q<INIT_PPG_REG_ARRAY_SIZE;q++){
if(init_ppg_register_array[q][0] == 0x7F)
bank = init_ppg_register_array[q][1];
if((bank == 0) && (init_ppg_register_array[q][0] == 0x17) )
{
//read and write bit7=1
temp = readRegister(0x17);
temp |= 0x80 ;
writeRegister(0x17, temp) ;
}
else
writeRegister(init_ppg_register_array[q][0], init_ppg_register_array[q][1]);
}
#endif
}
void writeRegister(uint8_t addr, uint8_t data)
{
char data_write[2];
data_write[0] = addr;
data_write[1] = data;
i2c.write(I2C_ADDR, data_write, 2, 0);
}
uint8_t readRegister(uint8_t addr)
{
char data_write[2];
char data_read[2];
data_write[0] = addr;
i2c.write(I2C_ADDR, data_write, 1, 0);
i2c.read(I2C_ADDR, data_read, 1, 0);
return data_read[0];
}
bool Pixart_HRD(void)
{
uint8_t tmp=0;
char data_write[2];
char data_read[4];
ppg_mems_data_t ppg_mems_data;
//Check Touch Status for power saving
writeRegister(0x7F,0x00); //bank0
tmp = readRegister(0x00);
tmp = readRegister(0x59)&0x80;
led_ctrl(tmp);
//writeRegister(0x7F,0x01); //bank1
ppg_mems_data.HRD_Data[0]=readRegister(0x68)&0x0f; //check status: 0 is not ready, 1 is ready, 2 is loss one data?
if(ppg_mems_data.HRD_Data[0] ==0)
{
writeRegister(0x7F,0x00); //bank0
return false;
}
else
{
//Only support burst read (0x64~0x67), when using I2C interface
data_write[0] = 0x64;
i2c.write(PAH8001_ADDR, data_write, 1, 1);
i2c.read(PAH8001_ADDR, data_read, 4, 0);
ppg_mems_data.HRD_Data[1]=data_read[0]&0xff;
ppg_mems_data.HRD_Data[2]=data_read[1]&0xff;
ppg_mems_data.HRD_Data[3]=data_read[2]&0xff;
ppg_mems_data.HRD_Data[4]=data_read[3]&0xff;
//Only support burst read (0x1A~0x1C), when using I2C interface
data_write[0] = 0x1A;
i2c.write(PAH8001_ADDR, data_write, 1, 1);
i2c.read(PAH8001_ADDR, data_read, 3, 0);
ppg_mems_data.HRD_Data[5]=data_read[0]&0xff;
ppg_mems_data.HRD_Data[6]=data_read[1]&0xff;
ppg_mems_data.HRD_Data[7]=data_read[2]&0xff;
ppg_mems_data.HRD_Data[8]=Frame_Count++;
ppg_mems_data.HRD_Data[9]=40;
ppg_mems_data.HRD_Data[10]=_led_current_change_flag;
writeRegister(0x7F,0x00); //bank0
//bit7 is Touch Flag (bit7=1 is meant Touch, and bit7=0 is meant No Touch)
ppg_mems_data.HRD_Data[11]=(readRegister(0x59)&0x80); //Check Touch Flag
ppg_mems_data.HRD_Data[12]= ppg_mems_data.HRD_Data[6];
//If no G sensor, please set G_Sensor_Data[3] = {0};
ppg_mems_data.MEMS_Data[0] = 0;//ReadGSensorX();
ppg_mems_data.MEMS_Data[1] = 0;//ReadGSensorY();
ppg_mems_data.MEMS_Data[2] = 0;//ReadGSensorZ();
Push(&ppg_mems_data); //Save data into FIFO
return true;
}
}
bool isFIFOEmpty(void)
{
return (_write_index == _read_index);
}
bool Push(ppg_mems_data_t *data)
{
int tmp = _write_index;
tmp++;
if(tmp >= FIFO_SIZE)
tmp = 0;
if(tmp == _read_index)
return false;
_ppg_mems_data[tmp] = *data;
_write_index = tmp;
return true;
}
bool Pop(ppg_mems_data_t *data)
{
int tmp;
if(isFIFOEmpty())
return false;
*data = _ppg_mems_data[_read_index];
tmp = _read_index + 1;
if(tmp >= FIFO_SIZE)
tmp = 0;
_read_index = tmp;
return true;
}
/***********************LED Control Start***********************************/
void led_ctrl(uint8_t touch) {
if(touch == 0x80) {
uint8_t data;
//uint16_t Frame_Average, EP_L, EP_H, Exposure_Line;
uint16_t EP_L, EP_H, Exposure_Line;
writeRegister(0x7f,0x00);
writeRegister(0x05,0x98);
writeRegister(0x7f,0x01);
//writeRegister(0x42,0xA4);
writeRegister(0x7f,0x00);
data = readRegister(0x33);
EP_H=data&0x03;
data = readRegister(0x32);
EP_L=data;
Exposure_Line=(EP_H<<8)+EP_L;
writeRegister(0x7f,0x01);
if(_sleepflag==1) {
writeRegister(0x38, (0xE0|DEFAULT_LED_STEP));
_sleepflag = 0 ;
}
if (_state_count <= STATE_COUNT_TH) {
_state_count++;
_led_current_change_flag = 0;
}
else {
_state_count = 0;
if(_state == 0) {
if( (Exposure_Line>=LED_CTRL_EXPO_TIME_HI_BOUND) || (Exposure_Line<=LED_CTRL_EXPO_TIME_LOW_BOUND) ) {
//writeRegister(0x7f,0x01);
data = readRegister(0x38);
_led_step=data&0x1f;
if( (Exposure_Line>=LED_CTRL_EXPO_TIME_HI_BOUND) && (_led_step < LED_CURRENT_HI) ) {
_state = 1 ;
_led_step=_led_step+LED_INC_DEC_STEP;
if(_led_step>LED_CURRENT_HI)
_led_step=LED_CURRENT_HI;
writeRegister(0x38, (_led_step|0xE0));
_led_current_change_flag = 1;
}
else if((Exposure_Line<=LED_CTRL_EXPO_TIME_LOW_BOUND) && (_led_step > LED_CURRENT_LOW) ) {
_state = 2 ;
if(_led_step<=(LED_CURRENT_LOW+LED_INC_DEC_STEP))
_led_step=LED_CURRENT_LOW;
else
_led_step=_led_step-LED_INC_DEC_STEP;
writeRegister(0x38, (_led_step|0xE0));
_led_current_change_flag = 1;
}
else {
_state = 0 ;
_led_current_change_flag = 0;
}
}
else {
_led_current_change_flag = 0;
}
}
else if(_state == 1) {
if(Exposure_Line > LED_CTRL_EXPO_TIME_HI) {
_state = 1 ;
_led_step=_led_step+LED_INC_DEC_STEP;
if(_led_step>=LED_CURRENT_HI) {
_state = 0 ;
_led_step=LED_CURRENT_HI;
}
writeRegister(0x38, (_led_step|0xE0));
_led_current_change_flag = 1;
}
else {
_state = 0 ;
_led_current_change_flag = 0;
}
}
else {
if(Exposure_Line < LED_CTRL_EXPO_TIME_LOW) {
_state = 2 ;
if(_led_step<=(LED_CURRENT_LOW+LED_INC_DEC_STEP)) {
_state = 0 ;
_led_step=LED_CURRENT_LOW;
}
else
_led_step=_led_step-LED_INC_DEC_STEP;
writeRegister(0x38, (_led_step|0xE0));
_led_current_change_flag = 1;
}
else {
_state = 0;
_led_current_change_flag = 0;
}
}
}
}
else {
writeRegister(0x7f,0x00);
writeRegister(0x05,0xB8);
writeRegister(0x7F,0x01);
//writeRegister(0x42,0xA0);
_led_step = DEFAULT_LED_STEP;
writeRegister(0x38, 0xFF);
_sleepflag = 1;
_led_current_change_flag = 0;
}
}
/***********************LED Control End ***********************************/
/* ---------------------------------------------------------------
* End of PAH8001 code
*///--------------------------------------------------------------
