first release Intelligent Lumen iBeacon

Dependencies:   BLE_API mbed nRF51822

Branch:
INTELLIGENT_LUMEN_BEACON
Revision:
1:2e474d4e7092
Parent:
0:720b1ee20d33
--- a/main.cpp	Thu Sep 15 14:43:08 2016 +0000
+++ b/main.cpp	Mon Oct 17 07:41:30 2016 +0000
@@ -15,48 +15,217 @@
  */
 
 #include "mbed.h"
+#include <string.h>
+#include <stddef.h>
+#include <Serial.h>
 #include "ble/services/iBeacon.h"
 #include "ble/services/UARTService.h"
+#include "ble/services/DFUService.h"
+#include "nrf.h"
+#include "nrf_sdm.h"
 
 
+extern "C" {
+    #include "pstorage.h"
+}
+#include "nrf_error.h"
+
+#define _DEBUG 
+
 BLE ble;
-    
-void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
-{
-    BLE &ble          = params->ble;
-    ble_error_t error = params->error;
+UARTService *uarts;
+DFUService *dfus;
+iBeacon *ibeacon;
+pstorage_handle_t pstorageHandle;
+#ifdef _DEBUG
+Serial pc(USBTX, USBRX);
+#endif
+Ticker ticker;
 
-    if (error != BLE_ERROR_NONE) {
-        return;
+// Struct to hold persistent data across power cycles
+typedef struct PersistentData_t {
+    char name[32];
+    uint16_t majorNumber;
+    uint16_t minorNumber;
+    uint16_t txPower;
+} __attribute__ ((aligned (4)));
+PersistentData_t  persistentData;
+static const int PERSISTENT_DATA_ALIGNED_SIZE = sizeof(PersistentData_t); 
+
+/* Dummy callback handler needed by Nordic's pstorage module. */
+void pstorageNotificationCallback(
+            pstorage_handle_t *p_handle,
+            uint8_t            op_code,
+            uint32_t           result,
+            uint8_t *          p_data,
+            uint32_t           data_len){
+            /* APP_ERROR_CHECK(result); */
+}
+ 
+void pstorageLoad(){
+    if (pstorage_init()!=NRF_SUCCESS) {
     }
     
-    /**
-     * The Beacon payload has the following composition:
-     * 128-Bit / 16byte UUID = E2 0A 39 F4 73 F5 4B C4 A1 2F 17 D1 AD 07 A9 61
-     * Major/Minor  = 0x1122 / 0x3344
-     * Tx Power     = 0xC8 = 200, 2's compliment is 256-200 = (-56dB)
-     *
-     * Note: please remember to calibrate your beacons TX Power for more accurate results.
-     */
-    const uint8_t uuid[] = {0xE2, 0x0A, 0x39, 0xF4, 0x73, 0xF5, 0x4B, 0xC4,
-                            0xA1, 0x2F, 0x17, 0xD1, 0xAD, 0x07, 0xA9, 0x61};
-    uint16_t majorNumber = 1122;
-    uint16_t minorNumber = 3344;
-    uint16_t txPower     = 0x40;
-    iBeacon *ibeacon = new iBeacon(ble, uuid, majorNumber, minorNumber, txPower);
+    pstorage_module_param_t pstorageParams = {
+        .cb          = pstorageNotificationCallback,
+        .block_size  = PERSISTENT_DATA_ALIGNED_SIZE,
+        .block_count = 1
+    };
+    pstorage_register(&pstorageParams, &pstorageHandle);
+    if (pstorage_load(
+            reinterpret_cast<uint8_t *>(&persistentData),
+            &pstorageHandle, PERSISTENT_DATA_ALIGNED_SIZE, 0
+    ) != NRF_SUCCESS) {
+        // On failure zero out and let the service reset to defaults
+        sprintf(persistentData.name,"INTELLIGENTLUMEN");
+        persistentData.majorNumber=1234;
+        persistentData.minorNumber=5678;
+        persistentData.txPower=54;       
+    }
+}
+
+
+
+void pstorageSave() {
+    pstorage_store(
+            &pstorageHandle,
+            reinterpret_cast<uint8_t *>(&persistentData),
+            sizeof(PersistentData_t),
+            0 /* offset */
+    );
+    wait(2);
+}
+
+
 
-    ble.gap().setAdvertisingInterval(1000); /* 1000ms. */
-    ble.gap().startAdvertising();
+/* BLE UART data received callback */
+void onDataWritten(const GattWriteCallbackParams *params)
+{
+    char *bp = (char*)params->data;
+    bp[params->len]=0; //Fix string end with zero.
+    #ifdef _DEBUG
+    pc.printf("%s\r\n",bp);
+    #endif
+    char *token;
+    token = strtok(bp," ,");
+    if (token!=NULL) {
+        #ifdef _DEBUG
+        pc.printf("Recv: %s\r\n",token);
+        #endif
+        if (strcmp(token,"name")==0) {
+            token = strtok(NULL," ,");
+            if (token==NULL) {
+                #ifdef _DEBUG
+                pc.printf("Cfg error: invalid name \r\n");
+                #endif
+                return;
+            }
+            sprintf((char *)persistentData.name,"%s",token);
+        } else if (strcmp(token,"major")==0) {
+            token = strtok(NULL," ,");
+            if (token==NULL) {
+                #ifdef _DEBUG
+                pc.printf("Cfg error: invalid majorNumber \r\n");
+                #endif
+                return;
+            }
+            persistentData.majorNumber=atoi(token);
+        } else if (strcmp(token,"minor")==0) {
+            token = strtok(NULL," ,");
+            if (token==NULL) {
+                #ifdef _DEBUG
+                pc.printf("Cfg error: invalid minorNumber \r\n");
+                #endif
+                return;
+            }
+            persistentData.minorNumber=atoi(token);
+        } else if (strcmp(token,"rssi")==0) {
+            token = strtok(NULL," ,");
+            if (token==NULL) {
+                #ifdef _DEBUG
+                pc.printf("Cfg error: invalid txPower \r\n");
+                #endif
+                return;
+            }
+            persistentData.txPower=atoi(token);
+            #ifdef _DEBUG
+            pc.printf("Cfg txPower:%i\r\n",persistentData.txPower);
+            #endif
+        } else if (strcmp(token,"save")==0) {
+            pstorageSave();
+            #ifdef _DEBUG
+            pc.printf("Config name:%s major:%i minor:%i tx:%i\r\n",persistentData.name,persistentData.majorNumber,persistentData.minorNumber,persistentData.txPower);
+            #endif
+            NVIC_SystemReset();
+        } else if (strcmp(token,"dfu")==0) {
+            sd_power_gpregret_set(BOOTLOADER_DFU_START);
+            sd_softdevice_disable();
+            sd_softdevice_vector_table_base_set(NRF_UICR->BOOTLOADERADDR);
+            NVIC_SystemReset();
+        }
+    }
 }
+ 
+ 
+void connectionCallback(const Gap::ConnectionCallbackParams_t *params)
+{
+    #ifdef _DEBUG
+    pc.printf("Connected!\n");
+    #endif
+}
+ 
+void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *cbParams)
+{
+    #ifdef _DEBUG
+    pc.printf("Disconnected!\n");
+    pc.printf("Restarting the advertising process\n");
+    #endif
+    ble.startAdvertising();
+}
+
+ 
 
 int main(void)
 {
-    ble.init(bleInitComplete);
+    const uint8_t uuid[] = {0xE2, 0x0A, 0x39, 0xF4, 0x73, 0xF5, 0x4B, 0xC4,
+                            0xA1, 0x2F, 0x17, 0xD1, 0xAD, 0x07, 0xA9, 0x61};
+    #ifdef _DEBUG
+    pc.baud(9600);
+    pc.printf("INTELLIGENT LUMEN BEACON DFU v1.1\r\n");
+    #endif
+    
+    /* Load mayor minor and txpower from storage */
+    pstorageLoad();
+    #ifdef _DEBUG
+    pc.printf("Storage size:%i\r\n",PERSISTENT_DATA_ALIGNED_SIZE);
+    pc.printf("Config name:%s mayor:%i minor:%i tx:%i\r\n",persistentData.name,persistentData.majorNumber,persistentData.minorNumber,persistentData.txPower);
+    #endif
+    
+    ble.init();
+    while (!ble.hasInitialized()) { wait(0.5);/* wait for BLE initialization */ }
     
-    /* SpinWait for initialization to complete. This is necessary because the
-     * BLE object is used in the main loop below. */
-    while (!ble.hasInitialized()) { /* spin loop */ }
+    ble.gap().onDisconnection(disconnectionCallback);
+    ble.gap().onConnection(connectionCallback);
+    ble.accumulateAdvertisingPayload(GapAdvertisingData::SHORTENED_LOCAL_NAME,
+                                     (const uint8_t*)persistentData.name, strlen((const char*)persistentData.name));
+
+    UARTService uartService(ble);
+    uarts = &uartService;
+    DFUService dfu(ble);
+    dfus = &dfu;
+    ibeacon = new iBeacon(ble, uuid, persistentData.majorNumber, persistentData.minorNumber, persistentData.txPower);  
 
+    ble.onDataWritten(onDataWritten);
+
+    /* setup advertising */
+    ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED);
+    ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
+    ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS,
+                                     (const uint8_t *)UARTServiceUUID_reversed, sizeof(UARTServiceUUID_reversed));
+    ble.setAdvertisingInterval(100); /* 100ms; in multiples of 0.625ms. */
+    ble.gap().startAdvertising();
+        
+    
     while (true) {
         ble.waitForEvent(); // allows or low power operation
     }