Felix Rüdiger / Mbed 2 deprecated BLE_Nano_MPU6050Service

Dependencies:   BLE_API mbed nRF51822 MPU6050_lib

main.cpp

Committer:
fruediger
Date:
2015-07-13
Revision:
7:af3e2b9c137a
Parent:
6:c1db7e82d76a
Child:
9:6a28d9c0e486

File content as of revision 7:af3e2b9c137a:

/** Includes */

#include "common.h"
#include "mbed.h"
#include "BLE.h"
#include "MPU6050Service.h"
#include "services/BatteryService.h"
#include "services/DeviceInformationService.h"
/***/
#include "LedPwmService.h"

/** Constants */

static const char           deviceName[]                = "nano bear";
static const char           deviceManufacturers[]       = "???";
static const char           deviceModelNumber[]         = "";
static const char           deviceSerialNumber[]        = XSTRING_(MBED_BUILD_TIMESTAMP);
static const char           deviceHardwareRev[]         = "0.1";
static const char           deviceFirmwareRev[]         = "0.1";
static const char           deviceSoftwareRev[]         = "";          

static const uint16_t       minimumConnectionInterval   = Gap::MSEC_TO_GAP_DURATION_UNITS(20); // 20ms
static const uint16_t       maximumConnectionInterval   = Gap::MSEC_TO_GAP_DURATION_UNITS(40); // 40ms;
static const uint16_t       slaveLatency                = 0;

static const float          tickerTimeout               = 0.05f;
static const float          batteryCritBlinkSequ[]      = { 0.000f, 0.146f, 0.500f, 0.854f, 1.000f, 0.854f, 0.500f, 0.146f };
static const float          connectedBlinkSequ[]        = { 1.000f, 1.000f, 1.000f, 1.000f, 1.000f, 1.000f, 1.000f, 1.000f,
                                                            1.000f, 1.000f, 1.000f, 1.000f, 1.000f, 1.000f, 1.000f, 1.000f,                                                            
                                                            1.000f, 1.000f, 1.000f, 1.000f, 1.000f, 1.000f, 1.000f, 1.000f,                                                           
                                                            1.000f, 1.000f, 1.000f, 1.000f, 1.000f, 1.000f, 1.000f, 1.000f, 
                                                            1.000f, 1.000f, 1.000f, 1.000f, 1.000f, 1.000f, 1.000f, 1.000f,                                                           
                                                            1.000f, 1.000f, 1.000f, 1.000f, 1.000f, 1.000f, 1.000f, 1.000f,                                                           
                                                            1.000f, 0.962f, 0.854f, 0.691f, 0.500f, 0.309f, 0.146f, 0.038f,
                                                            0.000f, 0.038f, 0.146f, 0.309f, 0.500f, 0.691f, 0.854f, 0.962f };
static const float          disconnectedBlinkSequ[]     = { 0.000f, 0.038f, 0.146f, 0.309f, 0.500f, 0.691f, 0.854f, 0.962f,
                                                            1.000f, 0.962f, 0.854f, 0.691f, 0.500f, 0.309f, 0.146f, 0.038f,
                                                            0.000f, 0.038f, 0.146f, 0.309f, 0.500f, 0.691f, 0.854f, 0.962f,
                                                            1.000f, 0.962f, 0.854f, 0.691f, 0.500f, 0.309f, 0.146f, 0.038f,
                                                            0.000f, 0.038f, 0.146f, 0.309f, 0.500f, 0.691f, 0.854f, 0.962f,
                                                            1.000f, 0.962f, 0.854f, 0.691f, 0.500f, 0.309f, 0.146f, 0.038f,
                                                            0.000f, 0.000f, 0.000f, 0.000f, 0.000f, 0.000f, 0.000f, 0.000f,                                                            
                                                            0.000f, 0.000f, 0.000f, 0.000f, 0.000f, 0.000f, 0.000f, 0.000f,                                                            
                                                            0.000f, 0.000f, 0.000f, 0.000f, 0.000f, 0.000f, 0.000f, 0.000f };
                                                            
//static const uint8_t       batteryCritThreshold         = 30; // 30%

/** Power determination stuff:
 *
 *  The following is the schematic circuit ...
 *
 *       I0->      ____
 *      --------*-|____|-*-----------                   ... where ...
 *      |       |   R2   |          |                       
 *      |       |        |     _____|_____                    |
 *      |      | |      | |   |           |                  | |        ____
 *      |   R1 | |   R4 | |   | BLE nano  |                  | |  and -|____|-  are resistors ...
 *      |      |_|      |_|   |           |--...             |_|
 *      |       |~0->    |    |           |                   |
 *      | Uref1 *--------|----| P0_4      |--...
 *  + __|__     |        |~0->|           |             ... and ...
 * U0  ___      |  Uref2 *----| P0_5      |--...
 *      |       |        |    |           |               + __|__  
 *      |      | |      | |   |           |--...             ___   is the constant voltage source
 *      |   R2 | |   R5 | |   |           |                   |    (a battery in this case)
 *      |      |_|      |_|   |___________|
 *      |       |        |          |
 *      |       |        |          |
 *      *-------*--------*----------*--------...
 *                                 _|_
 *
 *
 *  Therefore the input values are
 *
 *    U0 = (R1 / R2 + 1) * Uref1
 *
 *    I0 = ((R1 + R3) / R2 + 1) / R3 * Uref1 - (R4 / R5 + 1) / R3 * Uref2
 *                              
 */
 
#define R1              1000.0f
#define R2              1000.0f
#define R3              220.0f
#define R4              1000.0f
#define R5              1000.0f
#define NANO_OP_VOLT    3.3f

static const float          voltFac                     = ((R1 / R2) + 1.0f) * NANO_OP_VOLT;
static const float          currFac1                    = ((((R1 + R3) / R2) + 1.0f) / R3) * NANO_OP_VOLT;
static const float          currFac2                    = (((R4 / R5) + 1.0f) / R3) * NANO_OP_VOLT;



/** Global variables */

Serial                      pc(USBTX, USBRX);

BLE                         ble;
Gap::ConnectionParams_t     fast;

BatteryService             *battery             = NULL;
DeviceInformationService   *deviceInformation   = NULL;
MPU6050Service             *mpu6050             = NULL;
LedPwmService              *ledService          = NULL;

PwmOut                      btLed(P0_28);
PwmOut                      batLed(P0_29);
//DigitalOut                  aliveLed(LED1);
AnalogIn                    uRef1(P0_4);
AnalogIn                    uRef2(P0_5);

Ticker                      ticker;


/** Helpers */

inline Gap &gap()
{
    // get us the corresponding Gap instance only once and then save and reuse that instance 
    // (the underlying Gap instance shouldn't change on the BLE object)
    static Gap &gap = ble.gap();
    return gap;
}

float funitf(char *cunit_out, float value, int unit = 0, float divisor = 1000.0f, float upper_bound = 900.0f, float lower_bound = 0.9f)
{
    static const char prefix[] = { 'y', 'z', 'a', 'f', 'p', 'n', 'u', 'm', 0, 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y' };
    static const int prefixOffset = 8;
    
    if (unit < -8)
        do
        {
            unit++;
            value *= divisor;
        } while (unit < -8);
    else if (unit > 8)
        do
        {
            unit--;
            value /= divisor;
        } while (unit > 8);
    else while (unit != -8 && unit != 8)
        if (value > upper_bound)
        {
            unit++;
            value /= divisor;
        }
        else if (value < lower_bound)
        {
            unit--;
            value *= divisor;
        }
        else
            break;
    
    cunit_out[0] = prefix[prefixOffset + unit];
    return value;
}



/** Callback functions */

void periodicCallback()
{           
    static int          batCnt                      = -1;
    static int          conCnt                      = -1;
    static const int    batteryCritBlinkSequSize    = sizeof(batteryCritBlinkSequ) / sizeof(float);
    static const int    connectedBlinkSequSize      = sizeof(connectedBlinkSequ) / sizeof(float);
    static const int    disconnectedBlinkSequSize   = sizeof(disconnectedBlinkSequ) / sizeof(float);
    
    // alive state led
    
    // aliveLed = !aliveLed;
    
    // battery level led
    
/*    uint8_t batteryLevel = (uint8_t)(batteryLevelRescale * batLevel * 100.0f);
    if (batteryLevel > 100)
    {
        batteryLevel = 100;
        batLed = 1.0f;
    }
    else if (batteryLevel <= batteryCritThreshold)
    {
        batCnt = (batCnt + 1) % (batteryCritBlinkSequSize);
        batLed = batteryCritBlinkSequ[batCnt];
    }
    else
        batLed = 1.0f;
        
    // also update BatteryService characteristic if needed    
    
    static uint8_t oldBatteryLevel = 0xFF;
    if (batteryLevel != oldBatteryLevel && battery != NULL)
    {        
        battery->updateBatteryLevel(batteryLevel);
        
        pc.printf("Battery level is now: %i%%.", batteryLevel);
        
        oldBatteryLevel = batteryLevel;
    }   
*/

    // log source voltage and current
    
    static char unitV[] = "\0";
    static char unitA[] = "\0";
    
    float u0 = funitf(&unitV[0], voltFac * uRef1.read());
    float i0 = funitf(&unitA[0], (currFac1 * uRef1.read()) - (currFac2 * uRef2.read()));
    
    pc.printf("U0 = %10.6f%2sV, I0 = %10.6f%2sA\r\n", u0, unitV, i0, unitA);
    
    // bluetooth connection state led
    
    if (gap().getState().connected)
    {
        conCnt = ((conCnt + 1) % connectedBlinkSequSize);    
        btLed = connectedBlinkSequ[conCnt];      
    }
    else
    {
        conCnt = ((conCnt + 1) % disconnectedBlinkSequSize);    
        btLed = disconnectedBlinkSequ[conCnt];
    }  
}

void timeoutCallback(Gap::TimeoutSource_t source)
{
    pc.printf("\r\nGot TIMEOUT ");
    switch (source)
    {
        case Gap::TIMEOUT_SRC_ADVERTISING:      pc.printf("while advertising!\r\n"); break;
        case Gap::TIMEOUT_SRC_SECURITY_REQUEST: pc.printf("during security request!\r\n"); break;
        case Gap::TIMEOUT_SRC_SCAN:             pc.printf("while scanning!\r\n"); break;
        case Gap::TIMEOUT_SRC_CONN:             pc.printf("during connection!\r\n"); break;
    }
    
    gap().startAdvertising();    
    
    pc.printf("Restarting ADVERTISING...\r\n");
}

void disconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t reason)
{
    pc.printf("\r\nDISCONNECTED because ");
    switch (reason)
    {
        case Gap::CONNECTION_TIMEOUT:                           pc.printf("of connection timeout!\r\n"); break;
        case Gap::REMOTE_USER_TERMINATED_CONNECTION:            pc.printf("the remote user terminated the connection!\r\n"); break;
        case Gap::REMOTE_DEV_TERMINATION_DUE_TO_LOW_RESOURCES:  pc.printf("the remote device is low on resources!\r\n"); break;
        case Gap::REMOTE_DEV_TERMINATION_DUE_TO_POWER_OFF:      pc.printf("the remote device is off!\r\n"); break;
        case Gap::LOCAL_HOST_TERMINATED_CONNECTION:             pc.printf("we terminated the connection!\r\n"); break;
        case Gap::CONN_INTERVAL_UNACCEPTABLE:                   pc.printf("the connection interval is unacceptable!\r\n"); break;
    }
    
    gap().startAdvertising();
    
    pc.printf("Restarting ADVERTISING...\r\n");
}

void connectionCallback(const Gap::ConnectionCallbackParams_t *params)
{
    pc.printf("\r\nGot a CONNECTION from %02X:%02X:%02X:%02X:%02X:%02X (we are a ", (params->peerAddr)[0], (params->peerAddr)[1], (params->peerAddr)[2], (params->peerAddr)[3], (params->peerAddr)[4], (params->peerAddr)[5]);
    
    switch(params->role)
    {
        case Gap::PERIPHERAL:   pc.printf("peripheral)!\r\n"); break;
        case Gap::CENTRAL:      pc.printf("central)!\r\n"); break;
    }
    
    pc.printf("Updating connection parameters to be faster...\r\n");
        
    // update the connection parameters with the tuned fast ones
    ble.updateConnectionParams(params->handle, &fast);
    
    pc.printf("Starting MPU-6050 service...\r\n");
    
    // start polling and sending sensor data
    mpu6050->start();
}



/** Main */

int main()
{   
    btLed       = 1.0f;
    //batLed      = 1.0f;
    //aliveLed    = 1;

    ble.init(); 
        
    ticker.attach(periodicCallback, tickerTimeout);
    
    gap().onTimeout(timeoutCallback);   
    gap().onDisconnection(disconnectionCallback);
    gap().onConnection(connectionCallback);
    
    gap().setDeviceName((const uint8_t*)deviceName);
    
    gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
    gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (const uint8_t*)deviceName, sizeof(deviceName));
    gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
    
    //TODO: DECISION: advertising at minimal interval may consumes to much power, but is way faster
    gap().setAdvertisingInterval(gap().getMinAdvertisingInterval());
    
    // tune the preferred connection parameters to enable transfer more often
    // TODO: DECISION: also waht about power consumption?
    gap().getPreferredConnectionParams(&fast);
    fast.minConnectionInterval = minimumConnectionInterval;
    fast.maxConnectionInterval = maximumConnectionInterval;
    fast.slaveLatency = slaveLatency;
    gap().setPreferredConnectionParams(&fast);
    
    gap().startAdvertising();
    
    pc.printf("\r\nStart ADVERTISING...\r\n");
    
    BatteryService              _battery(ble); 
    battery                     = &_battery;  
    
    DeviceInformationService    _deviceInformation(ble, deviceManufacturers, deviceModelNumber, deviceSerialNumber, deviceHardwareRev, deviceFirmwareRev, deviceSoftwareRev);
    deviceInformation           = &_deviceInformation;
    
    MPU6050Service              _mpu6050(ble);
    mpu6050                     = &_mpu6050;
    
    LedPwmService               _ledService(ble, LED);
    ledService                  = &_ledService;
    
    while (true)
        ble.waitForEvent();
}