SunTracker_BLE_Remote

Dependencies:   BLE_API X_NUCLEO_IDB0XA1 X_NUCLEO_IKS01A1 mbed

Fork of SunTracker_BLE_Remote by ST Expansion SW Team

This application is the BLE Remote Control for the SunTracker demo application that you can find here.
Please refer to that page for further information.

main.cpp

Committer:
fabiombed
Date:
2016-04-12
Revision:
6:ce0e5024e3fa
Parent:
5:5e62f661a7ab
Child:
7:eb2215fe86b2

File content as of revision 6:ce0e5024e3fa:

/**
 ******************************************************************************
 * @file    main.cpp
 * @author  Fabio Brembilla
 * @version V2.0.0
 * @date    March, 2016
 * @brief   SunTracker + BLE (Client) Vertical Application
 *          This application use IKS01A1, IDB0XA1 expansion boards
 ******************************************************************************
 * @attention
 *
 * <h2><center>&copy; COPYRIGHT(c) 2016 STMicroelectronics</center></h2>
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *   1. Redistributions of source code must retain the above copyright notice,
 *      this list of conditions and the following disclaimer.
 *   2. Redistributions in binary form must reproduce the above copyright notice,
 *      this list of conditions and the following disclaimer in the documentation
 *      and/or other materials provided with the distribution.
 *   3. Neither the name of STMicroelectronics nor the names of its contributors
 *      may be used to endorse or promote products derived from this software
 *      without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 ******************************************************************************
 */

/* Define --------------------------------------------------------------------*/

#define Sensors     //IKS01A1 Option

/* Includes ------------------------------------------------------------------*/

#include "mbed.h"
#include "ble/BLE.h"
#include "ble/DiscoveredCharacteristic.h"
#include "ble/DiscoveredService.h"

#ifdef Sensors
    #include "DevI2C.h"
    #include "x_nucleo_iks01a1.h"
#endif

/* BlueTooth -----------------------------------------------------------------*/

#include "Utils.h" // Need for STORE_LE_16 and STORE_LE_32

#define SCAN_INT  0x30 // 30 ms = 48 * 0.625 ms
#define SCAN_WIND 0x30 // 30 ms = 48 * 0.625 ms

const Gap::Address_t  BLE_address_BE       = {0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA};  // CLIENT address
const Gap::Address_t  BLE_peer_address_BE  = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF};  // SERVER address (must be the same of SERVER)
//const Gap::Address_t  BLE_address_BE       = {0xCC, 0x00, 0x00, 0xE1, 0x80, 0x02};  // CLIENT address
//const Gap::Address_t  BLE_peer_address_BE  = {0xFD, 0x66, 0x05, 0x13, 0xBE, 0xBA};  // SERVER address (must be the same of SERVER)

DiscoveredCharacteristic userbutton_bleCharacteristic;
DiscoveredCharacteristic difference_bleCharacteristic;
DiscoveredCharacteristic position_bleCharacteristic;
DiscoveredCharacteristic sunpanel_bleCharacteristic;

#define SIZEOF_CONTROL_DATA_LEN     2
#define DIFFERENCE_DATA_LEN         2
// 1 byte   0xFF     8 bit      int8
// 2 byte   0xFFFF   16 bit     int16

uint8_t value_write[SIZEOF_CONTROL_DATA_LEN];
int16_t value_read = 0;
uint8_t value_write_diff[DIFFERENCE_DATA_LEN];

/* Variables ------------------------------------------------------------------*/

enum {
  IDLE = 0,
  READ_BUT  = 1,
  READ_DIF  = 2,
  READ_POS  = 3,
  READ_SUN  = 4,
  WRITE_BUT = 5,
  WRITE_DIF = 6
};
int trigger_Op = IDLE;
bool trigger_button = false;

int8_t display=0;      // Shown on Display: 0 = Motor Speed, 1 = Solar Panel Value, 2 = Manual Control [--> Receive BLE]
int16_t diff=0;        // Babybear or Accelerometer difference [--> Receive BLE]
int16_t pos=0;         // Motor Position [--> Receive BLE]
int16_t measure=0;     // ADC Value from SunPanel [--> Receive BLE]

/* Initializations ------------------------------------------------------------*/

#ifdef Sensors    

// Initializing I2C bus
DevI2C dev_i2c(D14, D15);

// Initializing Sensors Component IKS01A1
static X_NUCLEO_IKS01A1 *mems;
MotionSensor *accelerometer;

int32_t acc_data[3];    // Accelerometer difference
int16_t acc_diff=0;     // Accelerometer difference
#endif

InterruptIn mybutton(USER_BUTTON);

/* User_Button_Pressed -------------------------------------------------------*/

void User_Button_Pressed(void)
{
    trigger_button = true;
}

/* Bluetooth CallBack ---------------------------------------------------------*/

void advertisementCallback(const Gap::AdvertisementCallbackParams_t *params)
{    
    if (params->peerAddr[0] != BLE_peer_address_BE[0]) // return if miss the server MAC address
    { 
        printf("Missing Expected MAC Address\n\r");
        return; // exit from advertisementCallback
    }
    
//    printf("adv peerAddr[%02x %02x %02x %02x %02x %02x] rssi %d, isScanResponse %u, AdvertisementType %u\r\n",
//           params->peerAddr[5], params->peerAddr[4], params->peerAddr[3], params->peerAddr[2], params->peerAddr[1], params->peerAddr[0],
//           params->rssi, params->isScanResponse, params->type);

    printf("Found Expected MAC Address: isScanResponse %u, AdvertisementType %u\r\n",params->isScanResponse, params->type);
    
    if(!params->isScanResponse)
    {
      BLE::Instance().gap().connect(params->peerAddr, Gap::ADDR_TYPE_PUBLIC, NULL, NULL);
    }
}

void serviceDiscoveryCallback(const DiscoveredService *service)
{
    printf("Start Service Discovery\r\n");
/*
    if (service->getUUID().shortOrLong() == UUID::UUID_TYPE_SHORT)
    {
        printf("S UUID-%x attrs[%u %u]\r\n", service->getUUID().getShortUUID(), service->getStartHandle(), service->getEndHandle());
    }
    else
    {
        printf("S UUID-");
        const uint8_t *longUUIDBytes = service->getUUID().getBaseUUID();
        for (unsigned i = 0; i < UUID::LENGTH_OF_LONG_UUID; i++)
        {
            printf("%02X", longUUIDBytes[i]);
        }
        printf(" attrs[%u %u]\r\n", service->getStartHandle(), service->getEndHandle());
    }
*/    
}

void characteristicDiscoveryCallback(const DiscoveredCharacteristic *characteristicP)
{   
    if (characteristicP->getUUID().getShortUUID() == 0xA001)
    {
        userbutton_bleCharacteristic = *characteristicP;
        printf("Found 0xA001 Characteristic\r\n");
    }
    
    if (characteristicP->getUUID().getShortUUID() == 0xB001)
    {
        difference_bleCharacteristic = *characteristicP;    
        printf("Found 0xB001 Characteristic\r\n");
    }
    
    if (characteristicP->getUUID().getShortUUID() == 0xB002)
    {
        position_bleCharacteristic = *characteristicP;
        printf("Found 0xB002 Characteristic\r\n");
    }
    
    if (characteristicP->getUUID().getShortUUID() == 0xB003)
    {
        sunpanel_bleCharacteristic = *characteristicP;
        printf("Found 0xB003 Characteristic\r\n");
    }
}

void discoveryTerminationCallback(Gap::Handle_t connectionHandle)
{
    //printf("discoveryTerminationCallback for handle %u\r\n", connectionHandle);
    printf("Stop Service Discovery\r\n\r\n");
    
    trigger_Op = READ_BUT;
}

void onDataReadCallback(const GattReadCallbackParams *response)
{
    // Read SERVER --> CLIENT
    
    /*
    printf("response Handle %d\r\n", response->handle);
    printf("userbutton Handle %d\r\n", userbutton_bleCharacteristic.getValueHandle());
    printf("difference Handle %d\r\n", difference_bleCharacteristic.getValueHandle());
    printf("position Handle %d\r\n", position_bleCharacteristic.getValueHandle());
    printf("sunpanel Handle %d\r\n", sunpanel_bleCharacteristic.getValueHandle());
    
    printf("onDataRead (data[0] %x)\r\n", response->data[0]);
    printf("onDataRead (data[1] %x)\r\n\r\n", response->data[1]);   
    */
    
    // Return original value after inverted with STORE_LE_16 to send by BLE
    value_read = response->data[0] + (response->data[1]<<8);    
    
    if (response->handle == userbutton_bleCharacteristic.getValueHandle())
    {     
        display = value_read;         
        printf("\n\rReceive BLE Display %d\n\r", display);
        
        trigger_Op = READ_DIF;
    }
    
    if (response->handle == difference_bleCharacteristic.getValueHandle())
    {    
        diff = value_read;      
        printf("Receive BLE Difference %d lux/mems\n\r", diff);
        
        trigger_Op = READ_POS;
    }
    
    if (response->handle == position_bleCharacteristic.getValueHandle())
    {   
        pos = value_read;
        printf("Receive BLE Position %d\n\r", pos);
        
        trigger_Op = READ_SUN;
    }
    
    if (response->handle == sunpanel_bleCharacteristic.getValueHandle())
    {   
        measure = value_read;         
        printf("Receive BLE Sunpanel %d mV\n\r", measure);
        
        trigger_Op = WRITE_BUT;
    }
}

void myonDataWriteCallback(const GattWriteCallbackParams *response)
{
    // Write CLIENT --> SERVER

    //printf("myonDataWrite (data[0] %x)\n\r", response->data[0]);
    //printf("myonDataWrite (data[1] %x)\n\r\n\r", response->data[1]);

    // Return original value after inverted with STORE_LE_16 to send by BLE
    value_read = response->data[0] + (response->data[1]<<8);

    if (response->handle == userbutton_bleCharacteristic.getValueHandle())
    {
        printf("\r\n\r\nonDataWrite BUTTON (data %d)\r\n", value_read);
        
        trigger_Op = READ_BUT; 
    }
    
    if (response->handle == difference_bleCharacteristic.getValueHandle())
    {        
        //printf("onDataWrite DIFF (data %d)\r\n", value_read);
        
        trigger_Op = READ_BUT;  
    }
}

/** 
 * 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 */ 
    
    printf("Inizialization Error\n\r");
}

void connectionCallback(const Gap::ConnectionCallbackParams_t *params)
{
    //uint16_t CONTROL_SERVICE_UUID = 0xA000;
    //uint16_t USERBUTTON_CHARACTERISTIC_UUID = 0xA001;

    //uint16_t SENSORS_SERVICE_UUID = 0xB000;
    //uint16_t DIFFERENCE_CHARACTERISTIC_UUID = 0xB001;
    //uint16_t POSITION_CHARACTERISTIC_UUID = 0xB002;
    //uint16_t SUNPANEL_CHARACTERISTIC_UUID = 0xB003;    
    
    if (params->role == Gap::CENTRAL)
    {
        BLE &ble = BLE::Instance();
        ble.gattClient().onServiceDiscoveryTermination(discoveryTerminationCallback);
        // Discover all SERVICES and CHARACTERISTICS
        ble.gattClient().launchServiceDiscovery(params->handle, serviceDiscoveryCallback, characteristicDiscoveryCallback);
        
        // Works only for one characteristic, if you need to discover all characteristic, use the above command
        //ble.gattClient().launchServiceDiscovery(params->handle, serviceDiscoveryCallback, characteristicDiscoveryCallback, CONTROL_SERVICE_UUID, USERBUTTON_CHARACTERISTIC_UUID);  
        //ble.gattClient().launchServiceDiscovery(params->handle, serviceDiscoveryCallback, characteristicDiscoveryCallback, SENSORS_SERVICE_UUID, DIFFERENCE_CHARACTERISTIC_UUID);
        //ble.gattClient().launchServiceDiscovery(params->handle, serviceDiscoveryCallback, characteristicDiscoveryCallback, SENSORS_SERVICE_UUID, POSITION_CHARACTERISTIC_UUID);
        //ble.gattClient().launchServiceDiscovery(params->handle, serviceDiscoveryCallback, characteristicDiscoveryCallback, SENSORS_SERVICE_UUID, SUNPANEL_CHARACTERISTIC_UUID);
    }
    
    printf("Remote Connected\n\r");
}

void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params)
{
    (void)params;
    
    printf("Remote Disconnected\n\r");
}

/** 
 * 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; }

    // Set BT Address
    ble.gap().setAddress(BLEProtocol::AddressType::PUBLIC, BLE_address_BE);

    ble.gap().onConnection(connectionCallback);
    ble.onDisconnection(disconnectionCallback);
       
    ble.gattClient().onDataRead(onDataReadCallback);
    ble.gattClient().onDataWrite(myonDataWriteCallback);

    ble.gap().setScanParams(SCAN_INT, SCAN_WIND);
    ble.gap().startScan(advertisementCallback);
            
    // Main Loop
    while (true) {  
    
        //if (!ble.gattClient().isServiceDiscoveryActive())
        if (trigger_Op!=IDLE) // Wait until discoveryTerminationCallback
        {   
            
            // At present ARM BLE_API don't support Enable/Disable Notify from Client
            //userbutton_bleCharacteristic.notify(); 
            //difference_bleCharacteristic.notify();
            //position_bleCharacteristic.notify();
            //sunpanel_bleCharacteristic.notify();
            
            // Don't run more ble .read or .write in the same loop
            // because the callback is an interrupt and it doesn't work correctly if overloaded
          
            if (display == 0 || display == 1)
            { if (trigger_Op == WRITE_DIF) trigger_Op = READ_BUT; } // if Display 0 or 1, skip WRITE_DIF
            
            if (display == 2)
            { if (trigger_Op == READ_DIF) trigger_Op = WRITE_BUT; } // if Display 2, skip READ_DIF, READ_POS, READ_SUN
            
            switch(trigger_Op)
            {
            case READ_BUT:
                userbutton_bleCharacteristic.read();
                trigger_Op = IDLE;
                break;
            case READ_DIF:
                difference_bleCharacteristic.read();
                trigger_Op = IDLE;
                break;
            case READ_POS:
                position_bleCharacteristic.read();
                trigger_Op = IDLE;
                break;
            case READ_SUN:
                sunpanel_bleCharacteristic.read();
                trigger_Op = IDLE;
                break;
            case WRITE_BUT:
                if (trigger_button == true)
                {
                    memset (value_write, 0, SIZEOF_CONTROL_DATA_LEN); 
                    STORE_LE_16(value_write, 1234);
                    userbutton_bleCharacteristic.write(SIZEOF_CONTROL_DATA_LEN, value_write);
                    trigger_Op = IDLE;
                    trigger_button = false;
                } else {
                    #ifdef Sensors
                    trigger_Op = WRITE_DIF;
                    #else
                    trigger_Op = READ_BUT;
                    #endif
                }
                break;                                 
            case WRITE_DIF:    
                #ifdef Sensors             
                accelerometer->Get_X_Axes(acc_data);
                acc_diff = acc_data[0];
                //printf("Send BLE Difference %d lux/mems\n\r", acc_diff);
                 
                memset (value_write_diff, 0, DIFFERENCE_DATA_LEN);
                STORE_LE_16(value_write_diff, acc_diff);
                difference_bleCharacteristic.write(DIFFERENCE_DATA_LEN, value_write_diff);
                trigger_Op = IDLE;
                #else
                trigger_Op = READ_BUT;
                #endif
                break;
            default:
                break;
            }
            
        }
        ble.waitForEvent();
    }
}

/* Ticker --------------------------------------------------------------------*/
/*
void ticker_Callback(void)
{

}
*/
/* Main ----------------------------------------------------------------------*/

int main(void)
{
    printf("\r\n\r\nSunTracker Remote Control\r\n\r\n");
    
    #ifdef Sensors
    // Initializing Sensors Component
    mems=X_NUCLEO_IKS01A1::Instance(&dev_i2c);
    accelerometer = mems->GetAccelerometer();
    printf("Init Sensors OK\r\n");
    #endif
        
    //Ticker ticker;
    //ticker.attach(ticker_Callback, 1); // every 1 second
    
    mybutton.fall(&User_Button_Pressed);
    
    BLE::Instance().init(bleInitComplete);
}