IoT Empire / Mbed OS nrf-blinkysvc

Files at this revision

API Documentation at this revision

Comitter:
michaesc
Date:
Tue Mar 28 15:57:46 2017 +0000
Parent:
1:f8f97a4d8f02
Commit message:
Implemented Blinkyserv class and GATT derived service and characteristic logic.

Changed in this revision

source/Service.h Show annotated file Show diff for this revision Revisions of this file
source/main.cpp Show annotated file Show diff for this revision Revisions of this file
diff -r f8f97a4d8f02 -r 204381095967 source/Service.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/Service.h	Tue Mar 28 15:57:46 2017 +0000
@@ -0,0 +1,63 @@
+/* Blinky service application
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __BLE_BUTLED_SERVICE_H__
+#define __BLE_BUTLED_SERVICE_H__
+
+class Blinkyserv {
+public:
+    // These are stale UUIDs, not corresponding to Nordic
+    //const static uint16_t LED_SERVICE_UUID = 0xA002;
+    //const static uint16_t LED_STATE_CHARACTERISTIC_UUID = 0xA004;
+    //const static uint16_t BUT_STATE_CHARACTERISTIC_UUID = 0xA005;
+
+    // https://github.com/NordicSemiconductor/Android-nRF-Blinky/tree/master/app/src/main/java/no/nordicsemi/android/blinky/service/BlinkyManager.java
+    // BaseUUID = {0x23, 0xd1, 0xbc, 0xea, 0x5f, 0x78, 0x23, 0x15, 0xde, 0xef, 0x12, 0x12, 0x23, 0x15, 0x00, 0x00};
+    //const static UUID *LED_SERVICE_UUID = new UUID("00001523-1212-efde-1523-785feabcd123");
+    //std::shared_ptr<UUID> LED_SERVICE_UUID;
+    const UUID *LED_SERVICE_UUID;
+
+    Blinkyserv(BLEDevice &_ble, bool initialValueForLEDCharacteristic, bool initialValueForButCharacteristic) :
+        ble(_ble), ledState(UUID("00001525-1212-efde-1523-785feabcd123"), &initialValueForLEDCharacteristic),
+        butState(UUID("00001524-1212-efde-1523-785feabcd123"), &initialValueForButCharacteristic, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY)
+    {
+        // Service definition logic
+        GattCharacteristic *charTable[] = {&ledState, &butState};
+        LED_SERVICE_UUID = new UUID("00001523-1212-efde-1523-785feabcd123");
+
+        GattService GATTServ(static_cast<UUID>(*LED_SERVICE_UUID), charTable, sizeof(charTable) / sizeof(GattCharacteristic *));
+        ble.addService(GATTServ);
+    }
+
+    // FIXME: Does this need a butState equivalent?
+    GattAttribute::Handle_t getValueHandle() const {
+        return ledState.getValueHandle();
+    }
+
+    void updateButtonState(bool newState) { // Sets button state characteristic appropriately
+        //ble.gattServer().write(butState.getValueHandle(), (uint8_t *)&newState, sizeof(bool));
+        ble.updateCharacteristicValue(butState.getValueHandle(), (uint8_t *)&newState, sizeof(bool));
+    }
+
+private:
+    BLEDevice                         &ble;
+    ReadWriteGattCharacteristic<bool>  ledState;
+    ReadOnlyGattCharacteristic<bool>   butState;
+    ~Blinkyserv() {
+        delete LED_SERVICE_UUID;
+    }
+};
+
+#endif /* #ifndef __BLE_BUTLED_SERVICE_H__ */
\ No newline at end of file
diff -r f8f97a4d8f02 -r 204381095967 source/main.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/main.cpp	Tue Mar 28 15:57:46 2017 +0000
@@ -0,0 +1,209 @@
+/* Blinky service application
+ *
+ * This Bluetooth Smart application intends to serve as a substitute
+ * for existing applications implemented using the Nordic Semiconductor
+ * proprietary nRF 5 SDK. This application interfaces with example
+ * client applications such as the preexisting 'nRF Blinky' and
+ * 'nRF52 Blinky Web App', while complying with proprietary Nordic
+ * Semiconductor service and characteristic UUIDs.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <mbed.h>
+#include "ble/BLE.h"
+#include "ble/Gap.h"
+#include "Service.h"
+
+// FIXME: initializing has no effect!
+DigitalOut alivenessLED(LED1);
+DigitalOut actuatedLED(LED2);
+InterruptIn button(BUTTON1);
+
+enum { // Button!
+    RELEASED = 0,
+    PRESSED,
+    IDLE
+};
+
+// Stores the state of button sensor
+static uint8_t buttonState = IDLE;
+
+const static char DEVICE_NAME[] = "Lightsw"; // Seems this string has a limited maximum length?
+//static const uint16_t uuid16_list[] = {Blinkyserv::LED_SERVICE_UUID}; // Only works on short URLs
+//static const uint8_t uuid128_list[] = {0x0000, 0x1523, 0x1212, 0xefde, 0x1523, 0x785f, 0xeabc, 0xd123};
+
+Blinkyserv *blinkySvcptr;
+
+static EventQueue eventQueue(
+    /* event count */ 16 * /* event size */ 32
+);
+
+void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params)
+{
+    printf("Disconnected handle %u!\n", params->handle);
+    printf("Restarting the advertising process\n");
+    BLE::Instance().gap().startAdvertising();
+    actuatedLED = 1; // Reinitialize actuator,
+                     // according to svc value
+                     // initialValueForLEDCharacteristic
+}
+
+void connectionCallback(const Gap::ConnectionCallbackParams_t *params)
+{
+    printf("Connected handle %u!\n", params->handle);
+    printf("Stopping the advertising process\n");
+    BLE::Instance().gap().stopAdvertising();
+    alivenessLED = 1; // Indicate end of adverts
+}
+
+void blinkCallback(void)
+{
+    BLE &ble = BLE::Instance();
+
+    // Hack to avoid hung connections    
+    if (!ble.gap().getState().connected
+        && !ble.gap().getState().advertising) {
+        BLE::Instance().gap().startAdvertising();
+    }
+
+    // Indicate adverts by blinking a LED
+    if (ble.gap().getState().advertising) {
+        alivenessLED = !alivenessLED;
+    }
+}
+
+/**
+ * Allows the LED service to receive updates to the ledState characteristic.
+ *
+ * @param[in] params
+ *     Information about the characterisitc being updated.
+ */
+void onDataWrittenCallback(const GattWriteCallbackParams *params) {
+    if ((params->handle == blinkySvcptr->getValueHandle()) && (params->len == 1)) {
+        printf("Going to set the LED actuator!\n");
+        actuatedLED = !*(params->data); // Inverse
+    }
+}
+
+/**
+ * Allows the LED service to receive updates to the ledState characteristic.
+ */
+void onUpdatesCallback(Gap::Handle_t handle) {
+    printf("Notifications enabled for %d\n!", handle);
+}
+
+/* Callback user space helper method */
+void fall_handler_user_context(void) {
+    // Fall handler is called on button actions
+    blinkySvcptr->updateButtonState(buttonState);
+    buttonState = IDLE;
+}
+
+/* Callback user space helper method */
+void rise_handler_user_context(void) {
+    // Fall handler is called on button actions
+    blinkySvcptr->updateButtonState(buttonState);
+    buttonState = IDLE;
+}
+
+/* Note that the buttonPressedCallback() executes in interrupt context,
+ * so it is safer to access BLE device API from the main thread. For
+ * example, do not try to call printf(3) inside interrupt context! */
+void buttonPressedCallback(void)
+{
+    buttonState = PRESSED;
+    eventQueue.call(fall_handler_user_context);
+}
+
+/* Note that the buttonReleasedCallback() executes in interrupt context,
+ * so it is safer to access BLE device API from the main thread. For
+ * example, do not try to call printf(3) inside interrupt context! */
+void buttonReleasedCallback(void)
+{
+    buttonState = RELEASED;
+    eventQueue.call(rise_handler_user_context);
+}
+
+/**
+ * This function is called when the ble initialization process has failed
+ */
+void onBleInitError(BLE &ble, ble_error_t 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().onConnection(connectionCallback);
+    ble.gap().onDisconnection(disconnectionCallback);
+    ble.gattServer().onDataWritten(onDataWrittenCallback);
+    ble.gattServer().onUpdatesEnabled(onUpdatesCallback);
+
+    /* Setup primary service */
+    bool initialValueForLEDCharacteristic = false;
+    bool initialValueForButCharacteristic = false;
+    blinkySvcptr = new Blinkyserv(ble, initialValueForLEDCharacteristic, initialValueForButCharacteristic);
+
+    /* 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_LIST_128BIT_SERVICE_IDS, (uint8_t *) uuid128_list, sizeof(uuid128_list));
+    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS, blinkySvcptr->LED_SERVICE_UUID->getBaseUUID(), blinkySvcptr->LED_SERVICE_UUID->getLen());
+    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();
+}
+
+void scheduleBleEventsProcessing(BLE::OnEventsToProcessCallbackContext* context) {
+    BLE &ble = BLE::Instance();
+
+    // Finally redirect call to BLE callback handler
+    eventQueue.call(Callback<void()>(&ble, &BLE::processEvents));
+}
+
+int main()
+{
+    printf("Starting application main entry point...\n");
+    eventQueue.call_every(200, blinkCallback);
+
+    BLE &ble = BLE::Instance();
+    ble.onEventsToProcess(scheduleBleEventsProcessing);
+    ble.init(bleInitComplete);
+    
+    actuatedLED = 1; // initialize off
+    button.fall(buttonPressedCallback);
+    button.rise(buttonReleasedCallback);
+
+    eventQueue.dispatch_forever();
+
+    return 0;
+}
\ No newline at end of file