Geo beacon for VF.

Dependencies:   MMA8452 aconno_bsp adc52832_common

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /*
00002  *
00003  *  Made by Jurica Resetar @ aconno
00004  *  aconno.de
00005  *  All rights reserved.
00006  *
00007  */
00008 
00009 #include "mbed.h"
00010 #include "ble/BLE.h"
00011 #include "GapAdvertisingData.h"
00012 #include "acd52832_bsp.h"
00013 #include "mma8452.h"
00014 #include "AckService.h"
00015 #include "nrf52_uart.h"
00016 #include "nrf52_digital.h"
00017 #include "acn_nrf52_pwm.h"
00018 
00019 #define DEBUG               (0)
00020 #define DEBUG_ACC           (0)
00021 #define DEBUG_PRINT_UART    (0)
00022 #define DEBUG_MAC           (0)
00023 #define DEBUG_CONNECTION    (0)
00024 #define DEBUG_WAKEUP_BUZZER (0)
00025 
00026 #define ACN_FREIGHT         (1)
00027 
00028 #define USE_ACC             (0)
00029 
00030 #define SLEEP_TIME_S              (4.00)           /* Sleep time (in s)          */
00031 #define ADV_TIMER_TIME_S          (1.00)           /* Advertising time (in s)    */
00032 #define FREE_TIME_S               (0.1)            /* Time between end of a scanning and sleep mode */
00033 #define AWAKE_TIME_S              (ADV_TIMER_TIME_S+FREE_TIME_S)      /* Was 0.15 */
00034 #define SHORT_SLEEP_TIME_S        (0.5)            /* Shorter sleep time (s) */
00035 #define SHORT_SLEEP_TIME_PERIOD_S (10)             /* Time after a last scanned advertisment. In the period, sleep time is SHORT_SLEEP_TIME */
00036 #define BUZZER_FREQUENCY_Hz       (4000)
00037 
00038 #define BUZZ_TIME_S         (1)     /* Buzz time in s */
00039 #define ADV_INTERVAL        (100)   /* Advertising interval (in ms) */
00040 #define UUID_SIZE_B         (16)
00041 
00042 /* Static constants for the accelerometer */
00043 #define WHO_AM_I            0x0D           /* Type 'read' : This should return the device id of 0x2A */
00044 #define OUT_Z_MSB           0x05           /* Type 'read' : z axis - 8 most significatn bit of a 12 bit sample */
00045 #define ACC_POWER           (p11)
00046 #define I2C_DATA            (p20)
00047 #define I2C_CLK             (p17)
00048 #define INT2_PIN            (p15)
00049 #define BUZZER              (p18)
00050 
00051 #if ACN_FREIGHT
00052 #define LED_BLINK_HALF_T    (0.5)
00053 #endif
00054 #define BUZZER_ON_TIME_S    (0.250)
00055 #define BUZZER_OFF_TIME_S   (0.050)
00056 
00057 /* LEDs */
00058 #define RED_LED             (p31)
00059 #define GREEN_LED           (p2)
00060 #define BLUE_LED            (p3)
00061 
00062 /* I2C power */
00063 #define I2C_POWER           (p5)
00064 
00065 /* UART pins */
00066 #define UART_TX             (p25)
00067 #define UART_RX             (p26)
00068 
00069 #if DEBUG_PRINT_UART
00070     #include "nrf52_uart.h"
00071     NRF52_UART uart(UART_TX, UART_RX, Baud9600);
00072     char buffer[255];
00073     #define SEND(...) {uint8_t len = sprintf(buffer, __VA_ARGS__); uart.send(buffer, len);}
00074 #else
00075     #define SEND(...)
00076 #endif
00077 
00078 
00079 #if ACN_FREIGHT
00080 
00081 /* Aconno ID universal to all projects */
00082 #define ACONNO_ID               (0x69)
00083 /* Internal unique product identification. When doing new projects, just
00084  * increment old project ID by one. */
00085 #define PRODUCT_ID              (0x03)
00086 /* Version of the firmware. Start from zero and go upwards. */
00087 #define VERSION                 (0x02)
00088 
00089 /* Manufacturer that will sell the product. 0x0059 for general use case. */
00090 #define MANUFACTURER_ID         (0x0059)
00091 
00092 struct __attribute__((packed, aligned(1))) AdvertisingFormat
00093 {
00094     uint16_t manufacturerID;
00095     uint8_t aconnoID;
00096     uint8_t productID;
00097     uint8_t version;
00098 };
00099 
00100 #endif
00101 
00102 
00103 uint8_t sleepFlag = true;
00104 uint8_t UUID[UUID_SIZE_B] = {0xE1, 0x61, 0x35, 0xBA, 0xC0, 0xEC, 0x47, 0x2A, 0x98, 0x00, 0xAF, 0x18, 0x43, 0xFF, 0x05, 0x00};
00105 uint8_t startBuzz[2] = {0xBA, 0xBE};
00106 uint8_t stopBuzz[2] = {0xDE, 0xAD};
00107 uint8_t myMacAddress[6] = {};   
00108 uint8_t buzzer_flag = 0;
00109 
00110 enum RadioState{
00111     OFF,
00112     ADVERTISING,
00113     SCANNING,
00114 };
00115 
00116 enum RadioState radioState = OFF;
00117 
00118 void GoToSleep();
00119 void StartAdvertising();
00120 void startScanning();
00121 void WakeMeUp();
00122 
00123 Ticker WakeSleepT;
00124 Ticker sleepChanger;
00125 Ticker toggleBuzzer;
00126 #if ACN_FREIGHT
00127     Ticker toggleLed;
00128 #endif
00129 NRF52_PWM buzzer(NRF_PWM2);
00130 
00131 #if USE_ACC
00132     DigitalOut accPower(ACC_POWER);
00133     DigitalOut i2cPower(I2C_POWER);
00134     InterruptIn accPulse(INT2_PIN);
00135     Acc_MMA8452 acc(I2C_DATA, I2C_CLK, MMA8452_ADDRESS);
00136 
00137 #endif
00138 BLE &ble = BLE::Instance();
00139 ACKService<4> *ackServicePtr;
00140 
00141 #if DEBUG || DEBUG_MAC || DEBUG_CONNECTION
00142     NRF52_DigitalOut advLED(RED_LED);         // Red
00143     NRF52_DigitalOut scanLED(BLUE_LED);        // Blue
00144     NRF52_DigitalOut connectedLED(GREEN_LED);   // Green
00145 #endif
00146 
00147 #if DEBUG_ACC
00148     NRF52_DigitalOut int_led(RED_LED);
00149     NRF52_DigitalOut act_led(RED_LED);
00150 #endif
00151 
00152 #if ACN_FREIGHT
00153     NRF52_DigitalOut signal_led(RED_LED);
00154 #endif
00155 
00156 #if ACN_FREIGHT
00157 void ledToggle(){
00158     signal_led.toggle();
00159 }
00160 #endif
00161 
00162 void buzzerToggle(){
00163     static uint8_t initState = 1;
00164     if(initState){
00165         // initial state is off
00166         buzzer.enable(BUZZER_FREQUENCY_Hz);
00167         buzzer.enableChannel(0, BUZZER);
00168         buzzer.setDuty(0,0.5f);    
00169         initState = 0;
00170         toggleBuzzer.detach();
00171         toggleBuzzer.attach(buzzerToggle, BUZZER_OFF_TIME_S);
00172     }
00173     else{
00174         buzzer.enable(0);
00175         buzzer.setDuty(0, 0);
00176         buzzer.disable();    
00177         initState = 1;
00178         toggleBuzzer.detach();
00179         toggleBuzzer.attach(buzzerToggle, BUZZER_ON_TIME_S);
00180     }
00181 }
00182 
00183 void buzzerStart(){
00184     buzzer.enable(BUZZER_FREQUENCY_Hz);
00185     buzzer.enableChannel(0, BUZZER);
00186     buzzer.setDuty(0,0.5f);
00187 }
00188 void buzzerStop(){
00189     buzzer.enable(0);
00190     buzzer.setDuty(0, 0);
00191     buzzer.disable();
00192 }
00193 
00194 void onConnectionCallback(const Gap::ConnectionCallbackParams_t *params){   
00195     #if DEBUG_CONNECTION
00196         scanLED = !scanLED;       // Blue
00197         wait_ms(100);
00198         scanLED = !scanLED;       // Blue
00199         wait_ms(100);
00200         scanLED = !scanLED;       // Blue
00201         wait_ms(100);
00202         scanLED = !scanLED;       // Blue
00203         wait_ms(100);
00204         scanLED = !scanLED;       // Blue
00205         wait_ms(100);
00206         scanLED = !scanLED;       // Blue
00207         wait_ms(100);
00208         scanLED = 1;              // Blue
00209     #endif
00210     WakeSleepT.detach();
00211     sleepFlag = false;
00212 }
00213 
00214 
00215 /* Restart Advertising on disconnection*/
00216 void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params){
00217     buzzerStop();
00218     #if DEBUG_CONNECTION
00219         advLED = !advLED;       // RED
00220         wait_ms(100);
00221         advLED = !advLED;
00222         wait_ms(100);
00223         advLED = !advLED;
00224         wait_ms(100);
00225         advLED = !advLED;
00226         wait_ms(100);
00227         advLED = 1;
00228         wait_ms(100);
00229         advLED = 1;
00230     #endif
00231     WakeSleepT.attach(WakeMeUp, FREE_TIME_S);
00232     sleepFlag = true;
00233     
00234 }
00235 
00236 void onDataWrittenCallback(const GattWriteCallbackParams *params) {
00237     if(params->handle == ackServicePtr->getACKCharacteristicHandle()){
00238         // Something is written into AckCharacteristic
00239         if(params->data[0] == startBuzz[0]){
00240             if(params->data[1] == startBuzz[1]){
00241                 #if DEBUG_CONNECTION
00242                     connectedLED = !connectedLED;       // BLUE
00243                     wait_ms(100);
00244                     connectedLED = !connectedLED;
00245                     wait_ms(100);
00246                     connectedLED = !connectedLED;
00247                     wait_ms(100);
00248                     connectedLED = !connectedLED;
00249                     wait_ms(100);
00250                     connectedLED = !connectedLED;
00251                     wait_ms(100);
00252                     connectedLED = 1;
00253                     wait_ms(100);
00254                 #endif    
00255                 //buzzerStart();
00256                 toggleBuzzer.attach(buzzerToggle, BUZZER_ON_TIME_S);
00257                 #if ACN_FREIGHT
00258                     toggleLed.attach(ledToggle, LED_BLINK_HALF_T);
00259                 #endif
00260                 return;
00261             }
00262         }
00263         else if(params->data[0] == stopBuzz[0]){
00264             if(params->data[1] == stopBuzz[1]){
00265                 toggleBuzzer.detach();
00266                 buzzerStop();
00267                 #if ACN_FREIGHT
00268                     toggleLed.detach();
00269                     signal_led = 1;
00270                 #endif
00271                 WakeSleepT.detach();
00272                 WakeSleepT.attach(WakeMeUp, FREE_TIME_S);
00273                 ble.disconnect(Gap::LOCAL_HOST_TERMINATED_CONNECTION);
00274             }
00275         }
00276     }
00277     else{
00278         // Execute this for wrong data written into characteristic
00279         return;
00280     }
00281 }
00282 
00283 /**
00284  * This function is called when the ble initialization process has failed
00285  */
00286 void onBleInitError(BLE &ble, ble_error_t error){
00287     /* Avoid compiler warnings */
00288     (void) ble;
00289     (void) error;
00290     /* Initialization error handling should go here */
00291 }
00292 
00293 /**
00294  * Callback triggered when the ble initialization process has finished
00295  */
00296 void bleInitComplete(BLE::InitializationCompleteCallbackContext *params){
00297     BLE&        ble   = params->ble;
00298     ble_error_t error = params->error;
00299 
00300     if (error != BLE_ERROR_NONE) {
00301         /* In case of error, forward the error handling to onBleInitError */
00302         onBleInitError(ble, error);
00303         return;
00304     }
00305 
00306     /* Ensure that it is the default instance of BLE */
00307     if(ble.getInstanceID() != BLE::DEFAULT_INSTANCE) {
00308         return;
00309     }
00310     
00311     uint8_t init_values[4] = {0,0,0,0};
00312     /* Get my MAC address */
00313     BLEProtocol::AddressType_t temp_address_type;
00314     ble.gap().getAddress(&temp_address_type, myMacAddress);
00315     ackServicePtr = new ACKService<4>(ble, init_values);
00316     ackServicePtr->updateMacAddress(myMacAddress);    // Update MAC address
00317     
00318     ble.gap().onDisconnection(disconnectionCallback);
00319     ble.gap().onConnection(onConnectionCallback);         
00320     ble.gattServer().onDataWritten(onDataWrittenCallback);
00321     
00322 #if ACN_FREIGHT
00323     AdvertisingFormat msd;
00324     
00325     msd.manufacturerID = MANUFACTURER_ID;
00326     msd.aconnoID = ACONNO_ID;
00327     msd.productID = PRODUCT_ID;
00328     msd.version = VERSION;
00329     
00330     ble.gap().accumulateAdvertisingPayload(
00331         GapAdvertisingData::MANUFACTURER_SPECIFIC_DATA,
00332         (uint8_t*)&msd, sizeof(msd));
00333 #endif
00334     
00335     ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::INCOMPLETE_LIST_128BIT_SERVICE_IDS, (uint8_t*)UUID, sizeof(UUID));
00336     ble.gap().setAdvertisingInterval(ADV_INTERVAL);  // --> Has to be at least 100ms!
00337 }
00338 
00339 
00340 
00341 void startAdvertising(){    
00342     ble.gap().startAdvertising();
00343     #if DEBUG
00344         advLED = 0;
00345         scanLED = 1;
00346     #endif
00347     WakeSleepT.detach();
00348     WakeSleepT.attach(WakeMeUp, ADV_TIMER_TIME_S);    // Call the wakeMeUp function
00349 }
00350 
00351 void WakeMeUp(){
00352     sleepFlag = false;
00353     switch(radioState){
00354         case OFF:{
00355                 radioState = ADVERTISING;
00356                 startAdvertising();
00357                 break;
00358             }
00359         case ADVERTISING:{
00360                 radioState = OFF;
00361                 WakeSleepT.detach();
00362                 WakeSleepT.attach(GoToSleep, FREE_TIME_S);
00363                 break;
00364             }
00365         default: return;
00366     }
00367 }
00368 
00369 void GoToSleep(){
00370     WakeSleepT.detach();
00371     WakeSleepT.attach(WakeMeUp, SLEEP_TIME_S);
00372     ble.gap().stopAdvertising();
00373     sleepFlag = true;
00374     #if DEBUG
00375         advLED = 1;
00376         scanLED = 1;
00377     #endif
00378 }
00379 
00380 #if USE_ACC
00381     void pulse_handler(){
00382     #if DEBUG_WAKEUP_BUZZER
00383         buzzerStart();
00384         wait_ms(50);
00385         buzzerStop();
00386     #endif
00387     #if DEBUG_ACC
00388         int_led = !int_led;
00389     #endif
00390     }
00391 #endif
00392 
00393 int main(){
00394     #if DEBUG || DEBUG_MAC
00395         advLED = 1;
00396         scanLED = 1;
00397         connectedLED = 1;
00398     #endif
00399     
00400     #if USE_ACC
00401         accPower = 1;
00402         i2cPower = 1;
00403     #endif 
00404 
00405     #if ACN_FREIGHT
00406         signal_led = 1;
00407     #endif
00408     
00409     ble.init(bleInitComplete);
00410     /* SpinWait for initialization to complete. This is necessary because the BLE object is used in the main loop below. */
00411     while (ble.hasInitialized()  == false){ /* spin loop */ }
00412     __enable_irq();
00413             
00414     buzzerStart();
00415     wait_ms(500);
00416     buzzerStop();
00417         
00418     WakeSleepT.attach(GoToSleep, AWAKE_TIME_S);
00419     
00420     while(true){   
00421         ble.waitForEvent();
00422     }
00423 }