BLE PLX profile with customized services (raw data).

Dependencies:   MtSense06

https://mtmtechblog.files.wordpress.com/2016/04/mtsense06-post-title.jpeg?w=772 https://blog.mtmtech.com.tw/2016/06/28/pulse-oximeter-with-mtconnect04/

main.cpp

Committer:
johnathanlyu
Date:
2017-03-31
Revision:
2:7a08b9410b96
Parent:
1:0ec0e5694c4a

File content as of revision 2:7a08b9410b96:

/* Copyright (c) 2016 MtM Technology Corporation, MIT License
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
 * and associated documentation files (the "Software"), to deal in the Software without restriction, 
 * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or 
 * substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#include <events/mbed_events.h>
#include <mbed.h>
#include "ble/BLE.h"
#include "ble/Gap.h"
#include "ble/services/BatteryService.h"
#include "ble/services/DeviceInformationService.h"
#include "PulseOximeterService.h"
#include "M1.h"

/* 
 * set 0 disable M1 data send to uart
 *     1 enable M1 data send to urat
 */
#define M1_UART_RAW_DATA_ENABLE     0

DigitalOut ledRed(p16, 1);
Serial pc(p5, p4);
I2C i2c(p3, p2);
M1 m1(i2c);

const static char     DEVICE_NAME[] = "MtM_PLX";
static const uint16_t uuid16_list[] = { 0x1822, /* UUID_PULSE_OXIMETER_SERVICE */
                                        GattService::UUID_BATTERY_SERVICE,
                                        GattService::UUID_DEVICE_INFORMATION_SERVICE};

static PulseOximeterService* plxServicePtr;
static BatteryService* batteryServicePtr;

static EventQueue eventQueue(
    /* event count */ 16 * /* event size */ 32
);


void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params)
{
    BLE::Instance().gap().startAdvertising();
}

void blinkCallback(void)
{
    ledRed = !ledRed;
}

void plxCallback(void)
{
    M1::Plx plx;
    
    BLE &ble = BLE::Instance();
    if (ble.gap().getState().connected && m1.IsSkinIn()) {
        m1.GetPlx(&plx);
        plxServicePtr->updatePlxMeas((float)plx.spo2, (float)plx.pulseRate);
    }
}

void rawCallback(void)
{
    M1::Raw raw;
    static uint8_t cnt = 0;
    static uint8_t raw_x3[6*3];

    BLE &ble = BLE::Instance();
    if (ble.gap().getState().connected && m1.IsSkinIn()) {
        m1.GetRaw(&raw);
        
        raw_x3[6*cnt+0] = (uint8_t)(raw.red   >> 8);
        raw_x3[6*cnt+1] = (uint8_t)(raw.red   >> 0);
        raw_x3[6*cnt+2] = (uint8_t)(raw.ir    >> 8);
        raw_x3[6*cnt+3] = (uint8_t)(raw.ir    >> 0);
        raw_x3[6*cnt+4] = (uint8_t)(raw.green >> 8);
        raw_x3[6*cnt+5] = (uint8_t)(raw.green >> 0);
        
        if (++cnt >= 3) {
            plxServicePtr->updateRaw(raw_x3);
            cnt = 0;
        }
    } else {
        cnt = 0;
    }
}

void rawCallbackToUART() {
    M1::Raw raw;
    if(m1.IsSkinIn()) {
            m1.GetRaw(&raw);  
            pc.printf("%d,%d,%d\r\n",raw.red, raw.ir, raw.green);
        }   
}

void StatusCallback(void)
{
    M1::Status sta;
    
    BLE &ble = BLE::Instance();
    if (ble.gap().getState().connected) {
        m1.GetStatus(&sta);
        plxServicePtr->updateStatusFlagAndSignalQuality(sta.flags, sta.signalQuality);
    }  
}

void batteryCallback(void )
{
    uint8_t batteryLevel = 99;

    BLE &ble = BLE::Instance();
    if (ble.gap().getState().connected) {
        batteryServicePtr->updateBatteryLevel(batteryLevel);
    }
}

/**
 * This function is called when the ble initialization process has failled
 */
void onBleInitError(BLE &ble, ble_error_t error)
{
    /* Initialization error handling should go here */
}

/**
 * Callback triggered when the ble initialization process has finished
 */
void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
{
    BLE&        ble   = params->ble;
    ble_error_t error = params->error;

    if (error != BLE_ERROR_NONE) {
        /* In case of error, forward the error handling to onBleInitError */
        onBleInitError(ble, error);
        return;
    }

    /* Ensure that it is the default instance of BLE */
    if(ble.getInstanceID() != BLE::DEFAULT_INSTANCE) {
        return;
    }

    ble.gap().onDisconnection(disconnectionCallback);

    /* Setup primary service */
    plxServicePtr     = new PulseOximeterService(ble, 0, 0);
    batteryServicePtr = new BatteryService(ble, 100);
    DeviceInformationService deviceInfo(ble, "MtM");

    /* Setup advertising */
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *) uuid16_list, sizeof(uuid16_list));
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *) DEVICE_NAME, sizeof(DEVICE_NAME));
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::PULSE_OXIMETER_GENERIC);
    ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
    ble.gap().setAdvertisingInterval(1000); /* 1000ms */
    ble.gap().startAdvertising();
}

void scheduleBleEventsProcessing(BLE::OnEventsToProcessCallbackContext* context) {
    BLE &ble = BLE::Instance();
    eventQueue.call(Callback<void()>(&ble, &BLE::processEvents));
}

int main()
{
    /* Disable the hardware flow control of Serial, then show the mbed version */
    pc.set_flow_control(SerialBase::Disabled);
    pc.baud(115200);
    pc.printf("\r\n");
    pc.printf("mbed version(%d.%d.%d)\r\n", MBED_MAJOR_VERSION, MBED_MINOR_VERSION, MBED_PATCH_VERSION);
    pc.printf("\r\n");

    /* Config device */
    m1.ConfigDevice();

#if M1_UART_RAW_DATA_ENABLE
    /* 35ms getter raw data to uart */
    eventQueue.call_every(35,   rawCallbackToUART);
    eventQueue.call_every(500,  blinkCallback);
#else
    /* Update each data every N ms */
    eventQueue.call_every(1000, plxCallback);
    eventQueue.call_every(35,   rawCallback);
    eventQueue.call_every(1000, StatusCallback);
    eventQueue.call_every(500,  batteryCallback);
    eventQueue.call_every(500,  blinkCallback);

    BLE &ble = BLE::Instance();
    ble.onEventsToProcess(scheduleBleEventsProcessing);
    ble.init(bleInitComplete);
#endif    

    eventQueue.dispatch_forever();

    return 0;
}