ST / Mbed OS Node_BLE_Sensors_Device

Dependencies:   X_NUCLEO_IKS01A2

Fork of Node_BLE_Switch_Device by ST

Bluetooth Low Energy enabled device with environmental and inertial features, i.e. "Pressure", "Humidity", "Temperature", "Accelerometer", "Gyroscope", and "Magnetometer", plus "Switch" feature, compatible with BlueST Protocol.

source/main.cpp

Committer:
Davidroid
Date:
2018-08-06
Revision:
7:2b5ed57b088c
Parent:
6:01d49589410e

File content as of revision 7:2b5ed57b088c:

/**
 *******************************************************************************
 * @file    main.cpp
 * @author  Davide Aliprandi, STMicroelectronics
 * @version V1.0.0
 * @date    March 31st, 2018
 * @brief   mbed test application for the STMicroelectronics X-NUCLEO-IDB05A1
 *          Bluetooth Low energy Expansion Board.
 *******************************************************************************
 * @attention
 *
 * <h2><center>&copy; COPYRIGHT(c) 2018 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 
 * 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.
 *
 *******************************************************************************
 */


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

/* mbed specific header files. */
#include <events/mbed_events.h>
#include <mbed.h>
#include "ble/BLE.h"
#include "CustomService.h"
#include "XNucleoIKS01A2.h"


/* Definitions ---------------------------------------------------------------*/

#define BLE_ADVERTISING_INTERVAL_ms 1000
#define BLUETOOTH_PERIODIC_CALLBACK_ms 500
#define DELAY_1 100


/* Types ---------------------------------------------------------------------*/

/* Toggle state. */
typedef enum
{
    TOGGLE_OFF = 0,
    TOGGLE_ON
} toggle_t;


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

/* Switch and toggle state. */
CustomService::switch_state_t switch_state;
bool toggle_state;

/* LED to indicate system state. */
DigitalOut led_state(LED1); //Conflicts with SPI CLK on D13.

/* Bluetooth. */
const static char    DEVICE_NAME[] = "IOT_DEVICE";
const static uint8_t MANUFACTURER_SPECIFIC_DATA[]= {0x01,0x80,0x20,0xfc,0x00,0x00};
static EventQueue event_queue(/* event count */ 10 * EVENTS_EVENT_SIZE);
CustomService *custom_service;

/* Button event. */
InterruptIn event(USER_BUTTON);

/* Instantiate the expansion board */
static XNucleoIKS01A2 *mems_expansion_board = XNucleoIKS01A2::instance(D14, D15, D4, D5);

/* Components. */
static HTS221Sensor *hum_tem = mems_expansion_board->ht_sensor;
static LPS22HBSensor *pre_tem = mems_expansion_board->pt_sensor;
static LSM6DSLSensor *acc_gyr = mems_expansion_board->acc_gyro;
static LSM303AGRMagSensor *mag = mems_expansion_board->magnetometer;
//static LSM303AGRAccSensor *acc = mems_expansion_board->accelerometer;

/* Timestamp. */
static uint16_t time_stamp = 0;


/* Custom service related functions ------------------------------------------*/

void button_callback(void) {
    switch_state = (CustomService::switch_state_t) (CustomService::SWITCH_ON - switch_state);
    toggle_state = true;
}

void get_and_send_env_sensors() {
    float pressure, humidity, temperature;

    pre_tem->get_pressure(&pressure);
    hum_tem->get_humidity(&humidity);
    hum_tem->get_temperature(&temperature);

    event_queue.call(Callback<void(
        uint16_t,
        float, float, float
    )>(custom_service, &CustomService::send_env_sensors),
        time_stamp++,
        pressure, humidity, temperature
    );
    //printf("Env Sensors: (%d) %d %d %d\r\n", time_stamp, pressure, humidity, temperature);
}

void get_and_send_ine_sensors() {
    static axes_t accelerometer, gyroscope, magnetometer;

    acc_gyr->get_x_axes((int32_t *) &accelerometer);
    acc_gyr->get_g_axes((int32_t *) &gyroscope);
    mag->get_m_axes((int32_t *) &magnetometer);
    //accelerometer->get_x_axes((int32_t *) (&accelerometer));

    event_queue.call(Callback<void(
        uint16_t,
        axes_t*, axes_t*, axes_t*
    )>(custom_service, &CustomService::send_ine_sensors),
        time_stamp++,
        &accelerometer, &gyroscope, &magnetometer
    );
    //printf("Ine Sensors: (%d) %d %d %d %d %d %d %d %d %d\r\n", time_stamp, accelerometer.x, accelerometer.y, accelerometer.z, gyroscope.x, gyroscope.y, gyroscope.z, magnetometer.x, magnetometer.y, magnetometer.z);
}


/* Bluetooth related functions -----------------------------------------------*/

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

/**
 * This callback allows the custom service to read updates from the
 * characteristic.
 *
 * @param[in] params
 *     Information about the characterisitc being updated.
 */
void on_data_read_callback(const GattReadCallbackParams *params) {
    /* Reading characteristic and sending it via bluetooth. */
/*
    if (params->handle == custom_service->get_state_command_handle()) {
        if (BLE::Instance().getGapState().connected) {
            event_queue.call(Callback<void(uint16_t, uint8_t)>(custom_service, &CustomService::send_state), time_stamp++, led_state.read() ? CustomService::SWITCH_ON : CustomService::SWITCH_OFF);
        }
    } else
*/
    if (params->handle == custom_service->get_env_sensors_handle()) {
        if (BLE::Instance().getGapState().connected) {
            get_and_send_env_sensors();
        }
    } else if (params->handle == custom_service->get_ine_sensors_handle()) {
        if (BLE::Instance().getGapState().connected) {
            get_and_send_ine_sensors();
        }
    }
}

/**
 * This callback allows the custom service to write updates to the
 * characteristic.
 *
 * @param[in] params
 *     Information about the characterisitc being updated.
 */
void on_data_written_callback(const GattWriteCallbackParams *params) {
    /* Receiving data via bluetooth and writing it to the characteristic. */
    if (params->handle == custom_service->get_state_command_handle()) {
        led_state.write(((CustomService::switch_state_t) ((uint8_t *) (params->data))[SWITCH_DATA_INDEX]));
    } 
}

/**
 * This function is called periodically and sends notifications.
 */
void periodic_callback(void)
{
    /* Reading toggle command and sending it via bluetooth, if needed. */
    if (toggle_state) {
        if (BLE::Instance().getGapState().connected) {
            event_queue.call(Callback<void(uint16_t, uint8_t)>(custom_service, &CustomService::send_state), time_stamp++, switch_state);
            toggle_state = false;
        }
    }

    /* Reading sensors and sending data via bluetooth. */
    if (BLE::Instance().getGapState().connected) {
        get_and_send_env_sensors();
        get_and_send_ine_sensors();
    }
}

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

/**
 * Callback triggered when the ble initialization process has finished.
 */
void ble_init_complete(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 on_ble_init_error_callback */
        on_ble_init_error_callback(ble, error);
        return;
    }

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

    ble.gap().onDisconnection(on_disconnection_callback);
    ble.gattServer().onDataWritten(on_data_written_callback);
    ble.gattServer().onDataRead(on_data_read_callback);

    custom_service = new CustomService(ble);

    /* Setup advertising data. */
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS, (uint8_t *) CUSTOM_SERVICE_UUID, sizeof(CUSTOM_SERVICE_UUID));
    ble.gap().accumulateScanResponse(GapAdvertisingData::MANUFACTURER_SPECIFIC_DATA, MANUFACTURER_SPECIFIC_DATA, sizeof(MANUFACTURER_SPECIFIC_DATA));
    ble.gap().accumulateScanResponse(GapAdvertisingData::COMPLETE_LOCAL_NAME, (const uint8_t *) DEVICE_NAME, sizeof(DEVICE_NAME) - 1);
    ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
    ble.gap().setAdvertisingInterval(BLE_ADVERTISING_INTERVAL_ms);
    ble.gap().startAdvertising();
}

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


/* Main function -------------------------------------------------------------*/

int main()
{
    /*----- Initialization. -----*/

    /* Printing to the console. */
    printf("Sensors Node Application Example\r\n\n");

    /* Bluetooth. */
    event_queue.call_every(BLUETOOTH_PERIODIC_CALLBACK_ms, periodic_callback);
    BLE &ble = BLE::Instance();
    ble.onEventsToProcess(schedule_ble_events_processing);
    ble.init(ble_init_complete);

    /* Attaching and enabling interrupt handlers. */
    event.fall(button_callback);

    /* Setting up initial state: led OFF, no toggle state. */
    led_state.write(CustomService::SWITCH_OFF);
    toggle_state = false;
    
    /* Enabling sensors. */
    hum_tem->enable();
    pre_tem->enable();
    acc_gyr->enable_x();
    acc_gyr->enable_g();
    mag->enable();
    //acc->enable();

    /* Start. */
    event_queue.dispatch_forever();

    return 0;
}