Geo beacon for VF.

Dependencies:   MMA8452 aconno_bsp adc52832_common

main.cpp

Committer:
jurica238814
Date:
2017-07-25
Revision:
10:fd91664032d8
Parent:
9:2ab2be19add9
Child:
11:92a9fffd5015

File content as of revision 10:fd91664032d8:

/*
 *
 *  Made by Jurica Resetar @ aconno
 *  aconno.de
 *  All rights reserved
 *
 */

#include "mbed.h"
#include "ble/BLE.h"
#include "GapAdvertisingData.h"
#include "acd52832_bsp.h"
#include "mma8452.h"

#define DEBUG               (1)
#define DEBUG_ACC           (0)

#define SLEEP_TIME          (2.0)      // Sleep time in seconds WAS 0.85
#define AWAKE_TIME          (3.0)      // Was 0.15
#define ADV_TIMER_TIME      (1.0)      // Advertising time (in s)
#define SCAN_TIMER_TIME     (2.0)      // Scanning time (in s)
#define FREE_TIME           (0.01)     // Time between end of a scanning and sleep mode

/* Static constants for the BLE example */
#define MAX_BLE_PACKET_SIZE (31)
#define MSD_SIZE            (18)
#define MSD_ID              (0xFF)
#define BUZZ_TIME           (1.0)   // Buzz time in s
#define ADV_INTERVAL        (100)   // Advertising interval (in ms)
#define SCAN_INTERVAL       (100)   // Scan interval (in ms)
#define SCAN_WINDOW         (50)

/* Static constants for the accelerometer */
#define WHO_AM_I            0x0D           // Type 'read' : This should return the device id of 0x2A
#define OUT_Z_MSB           0x05           // Type 'read' : z axis - 8 most significatn bit of a 12 bit sample
#define I2C_DATA            (p29)
#define I2C_CLK             (p2)
#define INT2_PIN            (p4)
#define BUZZER              (p31)

uint8_t sleepFlag = 0;
int8_t txPower = 4;
uint8_t MSD[MSD_SIZE] = {0x59, 0x00, 0xE1, 0x61, 0x35, 0xBA, 0xC0, 0xEC, 0x47, 0x2A, 0x98, 0x00, 0xAF, 0x18, 0x43, 0xFF, 0x05, 0x00};
uint8_t my_mac_address[6] = {};          
uint8_t buzzer_flag = 0;

enum _radioState{
    OFF,
    ADVERTISING,
    SCANNING
    };
enum _radioState radioState = OFF;

void turnBuzzOff(void);
void goToSleep();
void startAdvertising();
void startScanning();
void WakeMeUp();

Ticker WakeSleepT;
Ticker turnBuzzOffT;
PwmOut buzzer(BUZZER);
PwmOut gyro_power(p7);
PwmOut i2c_power(p5);     // I2C Pull-ups power pin
InterruptIn gyro_pulse(INT2_PIN);
Acc_MMA8452 acc(I2C_DATA, I2C_CLK, MMA8452_ADDRESS);
BLE &ble = BLE::Instance();


#if DEBUG
    DigitalOut advLED(p22);
    DigitalOut scanLED(p23);
    DigitalOut awake(p24);
#endif
#if DEBUG_ACC
    DigitalOut int_led(p22);
#endif

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

/**
 * This function is called when the ble initialization process has failed
 */
void onBleInitError(BLE &ble, ble_error_t error){
    /* Avoid compiler warnings */
    (void) ble;
    (void) 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);

    /* Get my MAC address */
    BLEProtocol::AddressType_t temp_address_type;
    ble.gap().getAddress(&temp_address_type, my_mac_address);
    
    
    /* setup advertising */
    
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED);
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::MANUFACTURER_SPECIFIC_DATA, (uint8_t *)MSD, MSD_SIZE);
    ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED);    
    ble.gap().setAdvertisingInterval(ADV_INTERVAL);  // --> Has to be at least 100ms!
    //ble.gap().startAdvertising();   
}


uint8_t findMSDIndex(const Gap::AdvertisementCallbackParams_t *params){
    uint8_t i=0;
    uint8_t len;
    
    do{
        len = params->advertisingData[i];
        i++;
        if(params->advertisingData[i] == MSD_ID) return i;
        else i += (len-1);
    }while(i<MAX_BLE_PACKET_SIZE);
    
    return 0;
}

/**
 *  Function is called when BLE radio discovers any kind of advertisment 
 */
void advertisementCallback(const Gap::AdvertisementCallbackParams_t *params){
    uint8_t i=0;
    uint8_t msdOffset;
    
    ble.gap().stopScan();
    msdOffset = findMSDIndex(params);
    if(msdOffset == 0){
        // There's no MSD in BLE advertisement data
        return;
    }
    
    if ((params->advertisingData[msdOffset]) == MSD_ID){ 
        // Follows Manufacturer Specific Data
        if ((params->advertisingData[msdOffset+1]) == 0x59){
            if ((params->advertisingData[msdOffset+2]) == 0x00){
                for(i=0; i<6; i++){
                    if((params->advertisingData[msdOffset+i+3]) == my_mac_address[5-i] || 1){
                        continue;
                    }
                    else{
                        return;
                    }
                }
                turnBuzzOffT.detach();
                WakeSleepT.detach();
                buzzer.write(0.5F);
                turnBuzzOffT.attach(turnBuzzOff, BUZZ_TIME);
                //wait_ms(40);
                //buzzer.write(0.0F);
            }
        }
    }
}

/**
 *  The function is called when ticker generates interrupt
 */
void turnBuzzOff(void){
    buzzer.write(0.0F);
    turnBuzzOffT.detach();
    ble.gap().startScan(advertisementCallback);
    WakeSleepT.attach(goToSleep, AWAKE_TIME);
}

void startAdvertising(){
    ble.gap().startAdvertising();
    radioState = ADVERTISING;
    #if DEBUG
        advLED = 0;
        scanLED = 1;
    #endif
    WakeSleepT.detach();
    WakeSleepT.attach(WakeMeUp, ADV_TIMER_TIME);    // Call the wakeMeUp function
}

void startScanning(){
    ble.gap().stopAdvertising();
    ble.gap().setScanParams(SCAN_INTERVAL, SCAN_WINDOW);
    ble.gap().setScanTimeout(SCAN_TIMER_TIME);
    ble.gap().startScan(advertisementCallback);
    radioState = SCANNING;
    #if DEBUG
        advLED = 1;
        scanLED = 0;
    #endif
    WakeSleepT.detach();
    WakeSleepT.attach(WakeMeUp, SCAN_TIMER_TIME);
}

void WakeMeUp(){
    sleepFlag = 0;
    switch(radioState){
        case OFF:{
                startAdvertising();
                break;
            }
        case ADVERTISING:{
                startScanning();
                break;
            }
        case SCANNING:{
                radioState = OFF;
                ble.gap().stopAdvertising();    // Just in case
                ble.gap().stopScan();
                WakeSleepT.detach();
                WakeSleepT.attach(goToSleep, FREE_TIME);
                #if DEBUG
                    advLED = 1;
                    scanLED = 1;
                #endif
                break;
            }
        default: return;
    }
}

void goToSleep(){
    WakeSleepT.detach();
    WakeSleepT.attach(WakeMeUp, SLEEP_TIME);
    ble.gap().stopAdvertising();
    ble.gap().stopScan();
    sleepFlag = 1;
}

void buzz(void){
        buzzer.write(0.5f);
        wait_ms(100);
        buzzer.write(0.0f);
        sleepFlag = 0;
}

void pulse_handler(void){
        #if DEBUG_ACC
            int_led = !int_led;
        #endif
        i2c_power.write(1.0F);
        buzzer_flag = 1;
        // Be awake some time
        //WakeSleepT.detach();
        //WakeSleepT.attach(goToSleep, AWAKE_TIME);
}

int main(void){   
    #if DEBUG
        awake = 1;
        advLED = 1;
        scanLED = 1;
    #endif
    WakeSleepT.attach(goToSleep, AWAKE_TIME);
    ble.init(bleInitComplete);
    ble.gap().setTxPower(txPower);
    GapAdvertisingData postavke = GapAdvertisingData();
    
    //ble.gap().setScanParams(SCAN_INTERVAL, SCAN_WINDOW);
    //ble.gap().setScanTimeout(0.5);
    //ble.gap().startScan(advertisementCallback);
    
    buzzer.period(0.001F);
    buzzer.write(0.0F);
    gyro_power.period(0.01F);
    gyro_power.write(1.0F);
    i2c_power.period(0.01F);
    i2c_power.write(1.0F);
    wait_ms(1000);
    
    /* Pulse interrupt detection */
    acc.set_register((char)CTRL_REG_4, (char) 0x04);        //  INT_EN_FF_MT Freefall/motion interrupt enabled
    wait_ms(1);
    acc.set_register((char)FF_MT_CFG, (char) 0b01011000);   //ELE, Motion Flag ON, YEFE, X Event Flag Enable
    wait_ms(1);        
    acc.set_register((char)CTRL_REG_5, (char) 0x00);        // INT_EN_FF_MT interrupt is router t0 INT2
    wait_ms(1);
    acc.set_register((char)FF_COUNT, (char) 0x08);          // Set Counter degister value (10ms)
    wait_ms(1);
    acc.set_register((char)FF_MT_THS, (char) 0x90);         // Set TH value for motion detection on 1 G (1/0.063) and DBCNTM = 1 (Increments or clears counter)
    wait_ms(1);
            
    /* Setup for the interrupt handler */
    //gyro_pulse.rise(&pulse_handler);                                                                                //  -------------------------------------
    acc.set_register((char)CTRL_REG_1, (char) 0x01);        // Flow data rate and Active mode           
    wait(1);
    
    __enable_irq();
    
    /* SpinWait for initialization to complete. This is necessary because the
     * BLE object is used in the main loop below. */
    while (ble.hasInitialized()  == false){
         /* spin loop */ 
    }
        
    while(true){
        if(sleepFlag){
            if(!awake) awake = 1;
            __WFI();
        }
        else{
            if(awake) awake = 0;
            ble.waitForEvent();
        }
    }
}