Demo Glucose Service

Dependencies:   BLE_API mbed nRF51822

Fork of BLE_HeartRate by Bluetooth Low Energy

BLE_Glucose_demo implements the Glucose Service which enables a collector device to connect and interact with.

There is a brief sample code edited with Android Studio for demo this BLE_Glucose_demo example, and it is public on github, everyone can clone it by this URL: https://github.com/Marcomissyou/BluetoothLeGlucose.git. It is convenient for you to development your BLE idea.

There is also provided apk file so you can download and install it directly then demo this code, but make sure your Android phone supports Bluetooth 4.0. /media/uploads/Marcomissyou/bleglucoseservice.apk

GlucoseService.h

Committer:
wgd8700
Date:
2015-08-14
Revision:
68:56408fc76e3b
Parent:
67:aa3a1bbed328

File content as of revision 68:56408fc76e3b:

/* 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.
 */

#ifndef __BLE_GLUCOSE_SERVICE_H__
#define __BLE_GLUCOSE_SERVICE_H__

#include "BLE.h"
/**
* @class GlucoseService
* @brief BLE Glucose Service. This service displays the Glucose measurement value represented as a 16bit Float format.<br>
* @This example can be demonstrated with Blood Pressure Android App downloaded from
* @https://github.com/Marcomissyou/BluetoothLeGlucose.git
* @Author: Marco.Hsu  
* @Email: marco.missyou@gmail.com  
*/
static uint16_t SEQUENCE_NUMBER = 11111;
static uint16_t BASE_TIME_YEAR = 2015;
static uint8_t BASE_TIME_MONTH = 5;
static uint8_t BASE_TIME_DAY = 29;
static uint8_t BASE_TIME_HOURS = 17;
static uint8_t BASE_TIME_MINUTES = 30;
static uint8_t BASE_TIME_SECONDS = 45;

class GlucoseService {
public:
    GlucoseService(BLEDevice &_ble, float GluMeasure, uint16_t GluFeature =2111):
        ble(_ble),
        GluReceiveBuffer(),
        GluReceive_flag(),
        GlucoseMeasurementValue(GluMeasure),
        GlucoseFeatureValue(GluFeature),
        GlucoseValue(GattCharacteristic::UUID_GLUCOSE_MEASUREMENT_CHAR, GlucoseMeasurementValue.getPointer(),
        12, 12,GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY),
        GlucoseFeature(GattCharacteristic::UUID_GLUCOSE_FEATURE_CHAR, &GluFeature),
        GluControlPoint(GattCharacteristic::UUID_RECORD_ACCESS_CONTROL_POINT_CHAR, GluReceiveBuffer, 4, 4,
        GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE)
        {
            setupService();
        }

    void updateGlucoseMeasurement(float GluMeasure) {
        GlucoseMeasurementValue.updateGlucoseMeasurement(GluMeasure);
        ble.updateCharacteristicValue(GlucoseValue.getValueAttribute().getHandle(), GlucoseMeasurementValue.getPointer(), 12);
    }
    
    virtual void onDataWritten(const GattWriteCallbackParams *params) {
        if (params->handle == GluControlPoint.getValueAttribute().getHandle()) {
            uint16_t bytesRead = params->len;
            if (bytesRead <= 4) {
                memcpy(GluReceiveBuffer, params->data, bytesRead);
                GluReceive_flag = 1;
            }
        }
    }
    
    bool is_GluReceived(){
        if(GluReceive_flag ==1){
            return true;
        }
        return false;
    }
    
    uint8_t *getControlPoint(){
        return GluReceiveBuffer;
        }
        
    void CleanFlag(){
        GluReceive_flag = 0;
        }
    
private:
    void setupService(void) {
        static bool serviceAdded = false; /* We should only ever need to add the heart rate service once. */
        if (serviceAdded) {
            return;
        }
        GattCharacteristic *charTable[] = {&GlucoseValue, &GlucoseFeature, &GluControlPoint}; //, &GlucoseContext
        GattService         GluService(GattService::UUID_GLUCOSE_SERVICE, charTable, sizeof(charTable) / sizeof(GattCharacteristic *));
        ble.addService(GluService);
        serviceAdded = true;
        ble.onDataWritten(this, &GlucoseService::onDataWritten);
    }

//==========================================================================================================
private:
struct GlucoseMeasurementBytes {
        static const unsigned FLAGS_BYTE_INDEX = 0;
        static const unsigned TIME_OFFSET_PRESENT = 0;
        static const unsigned GLUCOSE_CONCENTRATION_Type_Sample_Location = 1;
        static const unsigned GLUCOSE_CONCENTRATION_UNIT = 1; // 0 = kg/L, 1 = mol/L
        static const unsigned SENSOR_STATUS_ANNUNCIATION = 0;
        static const unsigned CONTEXT_INFORMATION_FOLLOWS_FALSE = 0;
        static const unsigned CONTEXT_INFORMATION_FOLLOWS_TRUE = 1;
        static const unsigned VALUE_FORMAT_BITNUM = 0;
        static const uint8_t  VALUE_FORMAT_FLAG   = 0;
        
        // Initial setting Glucose measurement value
        GlucoseMeasurementBytes(uint16_t GluMeasure) : GlucoseMeasurementValue() { 
            updateGlucoseMeasurement(GluMeasure);
        }
        
        void updateDataAndSequneceNumber(){
            SEQUENCE_NUMBER++;
            memcpy(&GlucoseMeasurementValue[FLAGS_BYTE_INDEX+3], &BASE_TIME_YEAR, 2);
            memcpy(&GlucoseMeasurementValue[FLAGS_BYTE_INDEX+5], &BASE_TIME_MONTH, 1);
            memcpy(&GlucoseMeasurementValue[FLAGS_BYTE_INDEX+6], &BASE_TIME_DAY, 1);
            memcpy(&GlucoseMeasurementValue[FLAGS_BYTE_INDEX+7], &BASE_TIME_HOURS, 1);
            memcpy(&GlucoseMeasurementValue[FLAGS_BYTE_INDEX+8], &BASE_TIME_MINUTES, 1);
            memcpy(&GlucoseMeasurementValue[FLAGS_BYTE_INDEX+9], &BASE_TIME_SECONDS, 1);
            
            }
        
        void updateGlucoseMeasurement(float GluMeasure) {
            GlucoseMeasurementValue[FLAGS_BYTE_INDEX] = (TIME_OFFSET_PRESENT << 0)|(GLUCOSE_CONCENTRATION_Type_Sample_Location << 1)
                                                    |(GLUCOSE_CONCENTRATION_UNIT << 2)|(SENSOR_STATUS_ANNUNCIATION << 3)
                                                    |(CONTEXT_INFORMATION_FOLLOWS_FALSE << 4);
                                                    
            memcpy(&GlucoseMeasurementValue[FLAGS_BYTE_INDEX+1], &SEQUENCE_NUMBER, 2);
            memcpy(&GlucoseMeasurementValue[FLAGS_BYTE_INDEX+3], &BASE_TIME_YEAR, 2);
            memcpy(&GlucoseMeasurementValue[FLAGS_BYTE_INDEX+5], &BASE_TIME_MONTH, 1);
            memcpy(&GlucoseMeasurementValue[FLAGS_BYTE_INDEX+6], &BASE_TIME_DAY, 1);
            memcpy(&GlucoseMeasurementValue[FLAGS_BYTE_INDEX+7], &BASE_TIME_HOURS, 1);
            memcpy(&GlucoseMeasurementValue[FLAGS_BYTE_INDEX+8], &BASE_TIME_MINUTES, 1);
            memcpy(&GlucoseMeasurementValue[FLAGS_BYTE_INDEX+9], &BASE_TIME_SECONDS, 1);
            uint16_t GluMeasureData = ieee11073_float16(GluMeasure);
            GlucoseMeasurementValue[FLAGS_BYTE_INDEX + 10] = (uint8_t)(GluMeasureData & 0xFF);
            GlucoseMeasurementValue[FLAGS_BYTE_INDEX + 11] = (uint8_t)(GluMeasureData >> 8);
        }

        uint8_t       *getPointer(void) {
            return GlucoseMeasurementValue;
        }
        
        uint16_t ieee11073_float16(float GluMeasure) {
            uint8_t  exponent = 0; 
            uint16_t mantissa = (uint16_t)GluMeasure;
            return ((exponent << 12)&0xF0) | (mantissa << 0) & 0x0FFF ;
        }

        uint8_t GlucoseMeasurementValue[14];
    };
        
private:
    BLEDevice           &ble;
    GlucoseMeasurementBytes  GlucoseMeasurementValue;
    GattCharacteristic       GlucoseValue;  
    uint16_t GlucoseFeatureValue;
    ReadWriteGattCharacteristic<uint16_t>  GlucoseFeature;
    uint8_t             GluReceiveBuffer[4];
    uint8_t             GluReceive_flag;
    GattCharacteristic GluControlPoint;
};
#endif /* #ifndef __BLE_GLUCOSE_SERVICE_H__*/