Auto updating alarm watch - accepts alarm settings from a BLE device like a Raspberry Pi and buzzes at the appropriate time - also displays binary time

Dependencies:   BLE_API mbed-src nRF51822 nrf51_rtc

Revision:
2:9090120e2656
Parent:
1:c3d7e673cdd2
Child:
3:a4b8d67de1b1
--- a/main.cpp	Tue Mar 10 16:50:59 2015 +0000
+++ b/main.cpp	Sun Jul 26 15:38:59 2015 +0000
@@ -1,8 +1,88 @@
 // BLE Alarm Watch
-// Based on BLE heart-rate-monitor from MBED team
+// Based on BLE examples on MBED
 // Rob Dobson, 2015
 
 #include "mbed.h"
+#include "BLE.h"
+#include "ButtonService.h"
+
+// BLE platform
+BLE ble;
+
+// Indicator LEDs
+DigitalOut  led1(LED1);
+
+// Button press to show time
+InterruptIn button(D8);
+
+// Device name - this is the visible name of device on BLE
+const static char     DEVICE_NAME[] = "Button";
+
+// TEST CODE
+static const uint16_t uuid16_list[] = {ButtonService::BUTTON_SERVICE_UUID};
+
+// TEST CODE
+ButtonService *buttonServicePtr;
+
+// Handle button press to read watch
+void buttonPressedCallback(void)
+{
+// TEST CODE
+    buttonServicePtr->updateButtonState(true);
+}
+
+// TEST CODE
+void buttonReleasedCallback(void)
+{
+// TEST CODE
+    buttonServicePtr->updateButtonState(false);
+}
+
+// Handle BLE disconnection - restart advertising
+void disconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t reason)
+{
+    ble.gap().startAdvertising();
+}
+
+// TEST CODE
+void periodicCallback(void)
+{
+    led1 = !led1; /* Do blinky on LED1 to indicate system aliveness. */
+}
+
+int main(void)
+{
+    // TEST CODE
+    led1 = 1;
+    Ticker ticker;
+    ticker.attach(periodicCallback, 1);
+    button.fall(buttonPressedCallback);
+    button.rise(buttonReleasedCallback);
+
+    // BLE init
+    ble.init();
+    ble.gap().onDisconnection(disconnectionCallback);
+
+    // TEST CODE
+    ButtonService buttonService(ble, false /* initial value for button pressed */);
+    buttonServicePtr = &buttonService;
+
+    // Setup advertising
+    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
+    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list));
+    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
+    ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
+    ble.gap().setAdvertisingInterval(1000); /* 1000ms. */
+    ble.gap().startAdvertising();
+
+    while (true) {
+        ble.waitForEvent();
+    }
+}
+
+/*
+
+#include "mbed.h"
 #include "BLEDevice.h"
 #include "DeviceInformationService.h"
 
@@ -27,7 +107,8 @@
 uint8_t curTimeBlock[SIZE_OF_TIME_BLOCK];
 
 // GATT Characteristic for time block
-ReadWriteGattCharacteristic<uint8_t> timeBlockCharacteristic(UUID_TIME_BLOCK_CHARACTERISTIC, timeBlockInitValue);
+GattCharacteristic timeBlockCharacteristic(UUID_TIME_BLOCK_CHARACTERISTIC, timeBlockInitValue, SIZE_OF_TIME_BLOCK, SIZE_OF_TIME_BLOCK,
+        GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ);
 
 // Callback when connection lost
 void disconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t reason)
@@ -41,7 +122,7 @@
 int writeSinceLast = 0;
 void periodicCallback(void)
 {
-    ledIndicator = !ledIndicator; /* Do blinky on LED1 while we're waiting for BLE events */
+    ledIndicator = !ledIndicator; 
     testOut = !testOut;
     tickCount++;
     if (tickCount > 100)
@@ -56,6 +137,10 @@
 {
     if ((params->charHandle == timeBlockCharacteristic.getValueHandle())) 
     {
+        // Validate time
+        int year = params->data[0] * 100 + params->data[1];
+        int month = params->data[2];
+        int day = params->data[3];
 //        && (params->len == SIZE_OF_TIME_BLOCK)
         writeSinceLast = params->len;
         memcpy(curTimeBlock, params->data, SIZE_OF_TIME_BLOCK);
@@ -87,28 +172,28 @@
     ble.addService(timeBlockService);
     
     // Setup advertising
-    /* BREDR_NOT_SUPPORTED means classic bluetooth not supported;
-    * LE_GENERAL_DISCOVERABLE means that this peripheral can be
-    * discovered by any BLE scanner--i.e. any phone. */
+    // BREDR_NOT_SUPPORTED means classic bluetooth not supported;
+    // LE_GENERAL_DISCOVERABLE means that this peripheral can be
+    // discovered by any BLE scanner--i.e. any phone.
     ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
     
     // Add services to payload
     ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list));
     
-    /* This is where we're collecting the device name into the advertisement payload. */
+    // This is where we're collecting the device name into the advertisement payload.
     ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
     
-    /* We'd like for this BLE peripheral to be connectable. */
+    // We'd like for this BLE peripheral to be connectable.
     ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
     
-    /* set the interval at which advertisements are sent out; this has
-    * an implication power consumption--radio activity being a
-    * biggest draw on average power. The other software controllable
-    * parameter which influences power is the radio's TX power
-    * level--there's an API to adjust that. */
-    ble.setAdvertisingInterval(Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(1000)); /* 1000ms. */
+    // set the interval at which advertisements are sent out; this has
+    // an implication power consumption--radio activity being a
+    // biggest draw on average power. The other software controllable
+    // parameter which influences power is the radio's TX power
+    // level--there's an API to adjust that.
+    ble.setAdvertisingInterval(Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(1000));
     
-    /* we're finally good to go with advertisements. */
+
     ble.startAdvertising();
     
     while (true) 
@@ -127,41 +212,5 @@
             writeSinceLast = 0;
         }
     }    
-//    /* Setup primary service. */
-//    uint8_t hrmCounter = 100; // init HRM to 100bps
-//    HeartRateService hrService(ble, hrmCounter, HeartRateService::LOCATION_FINGER);
-//
-//    /* Setup auxiliary service. */
-//    DeviceInformationService deviceInfo(ble, "ARM", "Model1", "SN1", "hw-rev1", "fw-rev1", "soft-rev1");
-//
-//    /* Setup advertising. */
-//    ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
-//    ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list));
-//    ble.accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_HEART_RATE_SENSOR);
-//    ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
-//    ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
-//    ble.setAdvertisingInterval(Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(1000));
-//    ble.startAdvertising();
-//
-//    // infinite loop
-//    while (1) {
-//        // check for trigger from periodicCallback()
-//        if (triggerSensorPolling && ble.getGapState().connected) {
-//            triggerSensorPolling = false;
-//
-//            // Do blocking calls or whatever is necessary for sensor polling.
-//            // In our case, we simply update the HRM measurement. 
-//            hrmCounter++;
-//            
-//            //  100 <= HRM bps <=175
-//            if (hrmCounter == 175) {
-//                hrmCounter = 100;
-//            }
-//            
-//            // update bps
-//            hrService.updateHeartRate(hrmCounter);
-//        } else {
-//            ble.waitForEvent(); // low power wait for event
-//        }
-//    }
 }
+*/