aconno acnsensa project for iOS devices with iBeacon packets support.

Dependencies:   LSM9DS1 Si7006A20 aconno_SEGGER_RTT aconno_bsp adc52832_common

main.cpp

Committer:
Dautor
Date:
2017-12-13
Revision:
2:c0654c5fb771
Parent:
1:326ce5e200fb
Child:
3:78ceda8ef565

File content as of revision 2:c0654c5fb771:

/* 
 * aconno.de
 * Made by Jurica Resetar
 * Edited by Karlo Milicevic
 * All right reserved 
 *
 */

#include "mbed.h"
#include "ble/BLE.h"
#include "acd52832_bsp.h"
#include "GapAdvertisingData.h"
#include "Si7006A20.h"
#include "LSM9DS1.h"
#include "math.h"
#include "nrf52_digital.h"
#include "adc52832_common/utilities.h"
#include "MPL115A1.h"

#define V0 0.47    /* In volts */
#define TC 0.01    /* In volts */
#define VCC (3.6)
#define VALUE_TO_PERCENTAGE (100)
#define WAKEUP_TIME_DELAY_MS (150)
#define APPLICATION_ID (0xCF170059)

#define I2C_DATA (p19)
#define I2C_CLK  (p20)
#define SPI_MISO (p5)
#define SPI_MOSI (p3)
#define SPI_SCLK (p4)

#define DEBUG_PRINT     (0)
#define SLEEP_TIME      (0.150)          /* Sleep time in seconds */
#define WAKE_UP_TIME    (0.150)          /* Awake time in ms */
#define ADV_INTERVAL    (100)            /* Advertising interval in ms */
#define GO_TO_SLEEP     (0)              /* Sleep flag: 0 -> Device will not go to sleep, 1 -> Will go to sleep mode */
#define CALIBRATION_STEPS 20

static AnalogIn temperature(ADC_TEMP);
static AnalogIn light(ADC_LIGHT);
static NRF52_DigitalOut lightPower(p28);
static NRF52_DigitalOut temperaturePower(p31);
static NRF52_DigitalOut shdn(p6);
static NRF52_DigitalOut led(p23);
static NRF52_DigitalOut power(p2);
static NRF52_DigitalOut cs(p7);
static Si7006   *si;
static LSM9DS1  *mems;
static SPI      *spi;
static MPL115A1 *mpl115a1;

#if DEBUG_PRINT
    #include "nrf52_uart.h"
    NRF52_UART serial = NRF52_UART(p25, p26, Baud9600);   //Tx, RX BaudRate
    char buffer[256] = {0};
    #define SEND(...) {uint8_t len = sprintf(buffer, __VA_ARGS__); serial.send(buffer, len);}
    #define SENDN(...) {uint8_t len = sprintf(buffer "\n\r", __VA_ARGS__); serial.send(buffer, len);}
#else
    #define SEND(...);
    #define SENDN(...);
#endif

static bool sleepFlag = true;

static vector3_s memsAccInit;
static vector3_s memsGyrInit;
static vector3_s memsMagInit;

static BLE &ble = BLE::Instance();
static GapAdvertisingData adv_data = GapAdvertisingData();

struct __attribute__((packed, aligned(1))) advertising_packet{
    uint32_t header;
    uint8_t  type;
    union{
        struct{
            int16_t gyr[3];
            int16_t acc[3];
            int16_t mag[3];
        };
        struct{
            float temperature;
            float humidity;
            float pressure;
            float light;
        };
    };
};
static advertising_packet advPacket;

void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params){
    //  Restart Advertising on disconnection
    BLE::Instance().gap().startAdvertising();
}

/**
 *  Function for waking the core up
 */
void wakeMeUp(){
    sleepFlag = false;
}

void onBleInitError(BLE &ble, ble_error_t error){
    /* Avoid compiler warnings */
    (void) ble;
    (void) error;
}

/**
 * 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) {
        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 advertising */
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED);
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::MANUFACTURER_SPECIFIC_DATA, (uint8_t *)&advPacket, sizeof(advPacket));
    ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED);    
    ble.gap().setAdvertisingInterval(ADV_INTERVAL);
    ble.gap().startAdvertising();    
}

float getLight(){
    return light.read() * VALUE_TO_PERCENTAGE;
}

float voltage2temp(float vOut){
    return ((float)vOut - (float)V0)/((float)TC);
}

float getTemperature(){
    return voltage2temp(temperature.read()*(float)VCC);
}

float getHumidity(){
    float result;
    si->getHumidity(&result);
    return result;
}

void readGyr(vector3_s *gyro_data){
    mems->readGyro((int16_t *)gyro_data);
    *gyro_data -= memsGyrInit;
}

void readAcc(vector3_s *acc_data){
    mems->readAcc((int16_t *)acc_data);
    *acc_data -= memsAccInit;
}

void readMag(vector3_s *magneto_data){
    mems->readMag((int16_t *)magneto_data);
    *magneto_data -= memsMagInit;
}

void calibrateAcc(){
    vector3_s acc_data;
    for(uint8_t counter = 0; counter < CALIBRATION_STEPS; ++counter){
        readAcc(&acc_data);
        memsAccInit += acc_data;
    }
    memsAccInit /= CALIBRATION_STEPS;
}

void calibrateGyr(){
    vector3_s gyro_data;
    for(uint8_t counter = 0; counter < CALIBRATION_STEPS; ++counter){
        readGyr(&gyro_data);
        memsGyrInit += gyro_data;
    }
    memsGyrInit /= CALIBRATION_STEPS;
}

void calibrateMag(){
    vector3_s mag_data;
    for(uint8_t counter = 0; counter < CALIBRATION_STEPS; ++counter){
        readMag(&mag_data);
        memsMagInit += mag_data;
    }
    memsMagInit /= CALIBRATION_STEPS;
}

void updateData(){
    static uint8_t adv_type = 0;
    
    if(adv_type < 1){
        advPacket.type = 0x00;
        readGyr((vector3_s *)advPacket.gyr);
        readAcc((vector3_s *)advPacket.acc);
        readMag((vector3_s *)advPacket.mag);
    }
    else{
        advPacket.type = 0x01;
        advPacket.temperature = getTemperature();
        advPacket.light       = getLight();
        advPacket.humidity    = getHumidity();
        advPacket.pressure    = mpl115a1->getPressure();
    }
    if(++adv_type > 2) adv_type = 0;
    
    adv_data = ble.getAdvertisingData();
    adv_data.updateData(adv_data.MANUFACTURER_SPECIFIC_DATA, (uint8_t *)&advPacket, sizeof(advPacket));
    ble.setAdvertisingData(adv_data);
}


int main(){
    power = 1;
    wait_ms(WAKEUP_TIME_DELAY_MS);
    temperaturePower = 1;
    lightPower = 1;
    shdn = 1; // Wake up the pressure sensor
    
    advPacket.header = APPLICATION_ID;
    
    ble.init(bleInitComplete);
    
    I2C i2c(I2C_DATA, I2C_CLK);
    si       = new Si7006(&i2c);
    mems     = new LSM9DS1(&i2c);
    spi      = new SPI(SPI_MOSI, SPI_MISO, SPI_SCLK);
    mpl115a1 = new MPL115A1(*spi, cs);
    
    mems->startAcc();
    mems->startGyro();
    mems->startMag();
    
    led = 1;
    
    Ticker ticker;
    ticker.attach(wakeMeUp, SLEEP_TIME); // Wake the device up
    
    while(ble.hasInitialized() == false); /* spin loop */
    while(true){
        if (sleepFlag && GO_TO_SLEEP){
            ble.gap().stopAdvertising();
            sleep();
            ble.waitForEvent();
        }
        else{
            // I'm awake
            updateData();
            ble.gap().startAdvertising();
            wait_ms(WAKE_UP_TIME);
            sleepFlag = true;
        }
    }
}