init

Dependencies:   BLE_API mbed nRF51822

Files at this revision

API Documentation at this revision

Comitter:
jslater8
Date:
Mon Aug 17 09:49:55 2015 +0000
Parent:
1:4bdebb81dcd5
Commit message:
Initial

Changed in this revision

BLE_API.lib Show annotated file Show diff for this revision Revisions of this file
ButtonService.h Show annotated file Show diff for this revision Revisions of this file
LEDService.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
nRF51822.lib Show annotated file Show diff for this revision Revisions of this file
--- a/BLE_API.lib	Mon Jul 27 07:30:47 2015 +0000
+++ b/BLE_API.lib	Mon Aug 17 09:49:55 2015 +0000
@@ -1,1 +1,1 @@
-http://mbed.org/teams/Bluetooth-Low-Energy/code/BLE_API/#6884e374e2eb
+http://mbed.org/teams/Bluetooth-Low-Energy/code/BLE_API/#8d316a3271a8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ButtonService.h	Mon Aug 17 09:49:55 2015 +0000
@@ -0,0 +1,42 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * 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_BUTTON_SERVICE_H__
+#define __BLE_BUTTON_SERVICE_H__
+ 
+class ButtonService {
+public:
+    const static uint16_t BUTTON_SERVICE_UUID              = 0xA002;
+    const static uint16_t BUTTON_STATE_CHARACTERISTIC_UUID = 0xA003;
+ 
+    ButtonService(BLE &_ble, bool buttonPressedInitial) :
+        ble(_ble), buttonState(BUTTON_STATE_CHARACTERISTIC_UUID, &buttonPressedInitial, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY)
+    {
+        GattCharacteristic *charTable[] = {&buttonState};
+        GattService         buttonService(ButtonService::BUTTON_SERVICE_UUID, charTable, sizeof(charTable) / sizeof(GattCharacteristic *));
+        ble.gattServer().addService(buttonService);
+    }
+ 
+    void updateButtonState(bool newState) {
+        ble.gattServer().write(buttonState.getValueHandle(), (uint8_t *)&newState, sizeof(bool));
+    }
+ 
+private:
+    BLE                              &ble;
+    ReadOnlyGattCharacteristic<bool>  buttonState;
+};
+ 
+#endif /* #ifndef __BLE_BUTTON_SERVICE_H__ */
\ No newline at end of file
--- a/LEDService.h	Mon Jul 27 07:30:47 2015 +0000
+++ b/LEDService.h	Mon Aug 17 09:49:55 2015 +0000
@@ -13,15 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- 
+
 #ifndef __BLE_LED_SERVICE_H__
 #define __BLE_LED_SERVICE_H__
- 
+
 class LEDService {
 public:
     const static uint16_t LED_SERVICE_UUID              = 0xA000;
     const static uint16_t LED_STATE_CHARACTERISTIC_UUID = 0xA001;
- 
+
     LEDService(BLEDevice &_ble, bool initialValueForLEDCharacteristic) :
         ble(_ble), ledState(LED_STATE_CHARACTERISTIC_UUID, &initialValueForLEDCharacteristic)
     {
@@ -29,14 +29,14 @@
         GattService         ledService(LED_SERVICE_UUID, charTable, sizeof(charTable) / sizeof(GattCharacteristic *));
         ble.addService(ledService);
     }
- 
+
     GattAttribute::Handle_t getValueHandle() const {
         return ledState.getValueHandle();
     }
- 
+
 private:
     BLEDevice                         &ble;
     ReadWriteGattCharacteristic<bool>  ledState;
 };
- 
-#endif /* #ifndef __BLE_LED_SERVICE_H__ */
\ No newline at end of file
+
+#endif /* #ifndef __BLE_LED_SERVICE_H__ */
--- a/main.cpp	Mon Jul 27 07:30:47 2015 +0000
+++ b/main.cpp	Mon Aug 17 09:49:55 2015 +0000
@@ -20,167 +20,197 @@
 #include "ble/services/BatteryService.h"
 #include "ble/services/DeviceInformationService.h"
 #include "LEDService.h"
-
-#define BLE_CHECK(X)  (X == BLE_ERROR_NONE) ? (printf("{{success}}\r\n")) : printf("{{failure}} %s at line %u ERROR CODE: %u\r\n", #X, __LINE__, (X));
-#define BLE_EQUAL(X,Y) ((X)==(Y)) ? (printf("{{sucess}}\n")) : printf("{{failure}}\n");
+#include "ButtonService.h"
 
-BLE  ble;
-DigitalOut led1(LED1);
-Gap::Address_t address;
-Gap::AddressType_t *addressType;
+#define ASSERT_NO_FAILURE(CMD) do { \
+                    ble_error_t error = (CMD); \
+                    if (error == BLE_ERROR_NONE){ \
+                        printf("{{success}}\r\n"); \
+                    } else{ \
+                        printf("{{failure}} %s at line %u ERROR CODE: %u\r\n", #CMD, __LINE__, (error)); \
+                        return; \
+                    } \
+                    }while (0)
+#define CHECK_EQUALS(X,Y)    ((X)==(Y)) ? (printf("{{success}}\r\n")) : printf("{{failure}}\r\n");
 
-const static char     DEVICE_NAME[]        = "HRMTEST";
-static const uint16_t uuid16_list[]        = {GattService::UUID_HEART_RATE_SERVICE,
-                                              GattService::UUID_DEVICE_INFORMATION_SERVICE,
-                                              LEDService::LED_SERVICE_UUID};
-static volatile bool  triggerSensorPolling = false;
+BLE                   ble;
+Gap::Address_t        address;
+GapAdvertisingData::Appearance appearance;
+
+const static char     DEVICE_NAME[] = "HRMTEST";
+static const uint16_t uuid16_list[] = {GattService::UUID_HEART_RATE_SERVICE,
+                                       GattService::UUID_DEVICE_INFORMATION_SERVICE,
+                                       LEDService::LED_SERVICE_UUID};
+
+ButtonService *btnServicePtr;
 
 void disconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t reason)
 {
     ble.gap().startAdvertising(); // restart advertising
 }
 
-void periodicCallback(void)
-{
-    led1 = !led1; /* Do blinky on LED1 while we're waiting for BLE events */
-
-    /* Note that the periodicCallback() executes in interrupt context, so it is safer to do
-     * heavy-weight sensor polling from the main thread. */
+void connectionCallback(const Gap::ConnectionCallbackParams_t *params){
+    printf("Connected to: %d:%d:%d:%d:%d:%d\n",
+           params->peerAddr[0], params->peerAddr[1], params->peerAddr[2], params->peerAddr[3], params->peerAddr[4], params->peerAddr[5]);
 }
 
-void connectionCallback(const Gap::ConnectionCallbackParams_t *params){
-    printf("Connected to: %d:%d:%d:%d:%d:%d\n", params->peerAddr[0], params->peerAddr[1], params->peerAddr[2], params->peerAddr[3], params->peerAddr[4], params->peerAddr[5]);
-    
-}
-
-void dataReadCallback(const GattReadCallbackParams *params){
-        printf("%d\n",  params->data[1]);
-} 
-
-void testDeviceName(){
-    if (ble.gap().getState().connected){
+void testDeviceName()
+{
+    if (ble.gap().getState().connected) {
         printf("Device must be disconnected\n");
         return;
     }
-    uint8_t deviceName[10];
-    uint8_t deviceNameIn[] = {0x4A, 0x4F, 0x53, 0x48, 0x54, 0x45, 0x53, 0x54, 0x00};
-    unsigned length = 10;
-    BLE_CHECK(ble.gap().setDeviceName(deviceNameIn));
+
+    uint8_t  deviceNameIn[] = "Josh-test";
+    ASSERT_NO_FAILURE(ble.gap().setDeviceName(deviceNameIn));
     wait(0.5);
-    BLE_CHECK(ble.gap().getDeviceName(deviceName, &length));
-    wait(0.5);
-    for (int i = 0; i < length; i++){
-        printf("%02x ", deviceName[i]);
+
+    const size_t MAX_DEVICE_NAME_LEN = 50;
+    uint8_t  deviceName[MAX_DEVICE_NAME_LEN];
+    unsigned length = MAX_DEVICE_NAME_LEN;
+    ASSERT_NO_FAILURE(ble.gap().getDeviceName(deviceName, &length));
+    printf("ASSERTIONS DONE\r\n");
+    for (unsigned i = 0; i < length; i++) {
+        printf("%c", deviceName[i]);
     }
     printf("\r\n");
-    for (int i = 0; i < 8; i++){
-        printf("%02x ", deviceNameIn[i]);    
+    for (unsigned i = 0; i < strlen((char *)deviceNameIn); i++) {
+        printf("%c", deviceNameIn[i]);
     }
     printf("\r\n");
 }
 
-void testAppearance(){
-    if ((ble.gap().getState().connected)){
+void testAppearance()
+{
+    if ((ble.gap().getState().connected)) {
         printf("Device must be disconnected\n");
         return;
     }
-    GapAdvertisingData::Appearance appearance;
-    BLE_CHECK(ble.gap().setAppearance(GapAdvertisingData::GENERIC_PHONE));
-    wait(0.5);
-    BLE_CHECK(ble.gap().getAppearance(&appearance));
-    wait(0.5);
-    printf("%d\r\n",appearance);
-} 
 
-void connParams(){
-    if ((ble.gap().getState().connected)){
+    ASSERT_NO_FAILURE(ble.gap().setAppearance(GapAdvertisingData::GENERIC_PHONE));
+    ASSERT_NO_FAILURE(ble.gap().getAppearance(&appearance));
+    printf("ASSERTIONS DONE\r\n");
+    printf("%d\r\n", appearance);
+}
+
+void connParams()
+{
+    if ((ble.gap().getState().connected)) {
         printf("Device must be disconnected\n");
         return;
     }
+
     Gap::ConnectionParams_t params;
-    Gap::ConnectionParams_t paramsOut = {50,500,0,500};
+    Gap::ConnectionParams_t paramsOut = {50, 500, 0, 500};
     Gap::ConnectionParams_t temp;
-    BLE_CHECK(ble.gap().getPreferredConnectionParams(&temp));
-    BLE_CHECK(ble.gap().setPreferredConnectionParams(&paramsOut));
+
+    ASSERT_NO_FAILURE(ble.gap().getPreferredConnectionParams(&temp));
+    ASSERT_NO_FAILURE(ble.gap().setPreferredConnectionParams(&paramsOut));
+    
+    printf("ASSERTIONS DONE\r\n");
+    
     ble.gap().getPreferredConnectionParams(&params);
+
     printf("%d\n", params.minConnectionInterval);
     printf("%d\n", params.maxConnectionInterval);
     printf("%d\n", params.slaveLatency);
     printf("%d\n", params.connectionSupervisionTimeout);
+
     ble.gap().setPreferredConnectionParams(&temp);
-    
-} 
+}
+
+void notificationTest(void) {
+    btnServicePtr->updateButtonState(true);
+}
+
+void commandInterpreter(void)
+{
+    const static size_t MAX_SIZEOF_COMMAND = 50;
+    while (true) {
+        char command[MAX_SIZEOF_COMMAND];
+        scanf("%s", command);
+
+        if (!strcmp(command, "setDeviceName")) {
+            testDeviceName();
+        } else if (!strcmp(command, "appearance")) {
+            testAppearance();
+        } else if (!strcmp(command, "connParam")) {
+            connParams();
+        } else if (!strcmp(command, "notification")) {
+            notificationTest();
+        }
+    }
+}
 
-void commandInterpreter(void){
-    char command[50];
-    while(1){
-        scanf("%s", command);
-        if (!strcmp(command, "setDeviceName")) testDeviceName();
-        else if (!strcmp(command, "setAppearance")) testAppearance();
-        else if (!strcmp(command, "testConnectionParams")) connParams();
+/**
+ * @return 0 if basic assumptions are validated. Non-zero returns are used to
+ *     terminate the second-level python script early.
+ */
+unsigned verifyBasicAssumptions()
+{
+    ble.gap().onDisconnection(disconnectionCallback);
+    ble.gap().onConnection(connectionCallback);
+
+    /* Setup advertising. */
+    if (ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE)) {
+        return 1;
+    }
+    if (ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list))) {
+        return 1;
     }
+    if (ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_HEART_RATE_SENSOR)) {
+        return 1;
+    }
+    if (ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME))) {
+        return 1;
+    }
+    ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
+    ble.gap().setAdvertisingInterval(1000); /* 1000ms */
+
+    if (ble.gap().startAdvertising()) {
+        return 1;
+    }
+    
+    const char *version = ble.getVersion();
+    printf("%s\r\n", version);
+    if (!strcmp(version, "")) return 1;
+    return 0;
 }
 
 int main(void)
 {
-    led1 = 1;
-    Ticker ticker;
-    ticker.attach(periodicCallback, 1); // blink LED every second
-    
-    BLE_CHECK(ble.init());
-    ble.gap().onDisconnection(disconnectionCallback);
-    ble.gap().onConnection(connectionCallback);
-    /* Setup primary service. */
-    uint8_t hrmCounter = 100; // init HRM to 100bps
-    HeartRateService hrService(ble, hrmCounter, HeartRateService::LOCATION_FINGER);
-    
-    bool initialValueForLEDCharacteristic = false;
-    LEDService ledService(ble, initialValueForLEDCharacteristic);
+    unsigned errorCode = ble.init();
+    if (errorCode == 0) {
+        uint8_t                   hrmCounter = 100; // init HRM to 100bps
+        HeartRateService         *hrService  = new HeartRateService(ble, hrmCounter, HeartRateService::LOCATION_FINGER);
+
+        bool                      initialValueForLEDCharacteristic = false;
+        LEDService               *ledService                       = new LEDService(ble, initialValueForLEDCharacteristic);
 
-    /* Setup auxiliary service. */
-    DeviceInformationService deviceInfo(ble, "ARM", "Model1", "SN1", "hw-rev1", "fw-rev1", "soft-rev1");
+        DeviceInformationService *deviceInfo = new DeviceInformationService(ble, "ARM", "Model1", "SN1", "hw-rev1", "fw-rev1", "soft-rev1");
+        
+        btnServicePtr = new ButtonService(ble, false); 
+    }
+    errorCode |= verifyBasicAssumptions();
+    if (errorCode == 0) {
+        printf("{{success}}\r\n{{end}}\r\n"); /* hand over control from the host test to the python script. */
+    } else {
+        printf("{{failure}}\r\n{{end}}\r\n"); /* hand over control from the host test to the python script. */
+    }
 
-    /* Setup advertising. */
-    BLE_CHECK(ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE));
-    BLE_CHECK(ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list)));
-    BLE_CHECK(ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_HEART_RATE_SENSOR));
-    BLE_CHECK(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 */
+    unsigned synchronize;
+    scanf("%u", &synchronize);
 
-    BLE_CHECK(ble.gap().startAdvertising());
-    BLE_CHECK(ble.gap().getAddress(addressType, address));
-    printf("{{success}}" "\n" "{{end}}" "\n");
-    int x;
-    scanf("%d" , &x);
+    if (errorCode != 0) {
+        printf("Initial basic assumptions failed\r\n");
+        return -1;
+    }
+
+    Gap::AddressType_t addressType;
+    ASSERT_NO_FAILURE(ble.gap().getAddress(&addressType, address));
+
+    /* write out the MAC address to allow the second level python script to target this device. */
     printf("%d:%d:%d:%d:%d:%d\n", address[0], address[1], address[2], address[3], address[4], address[5]);
+
     commandInterpreter();
-/*
-    scanf("%d", &x);
-    testDeviceName();
-    //printf("%d\n",ble.gattServer().onDataRead(dataReadCallback));
-    scanf("%d", &x);
-    testAppearance();
-    scanf("%d", &x);
-    connParams();
-    // 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
-        }
-    }
-*/
 }
--- a/nRF51822.lib	Mon Jul 27 07:30:47 2015 +0000
+++ b/nRF51822.lib	Mon Aug 17 09:49:55 2015 +0000
@@ -1,1 +1,1 @@
-http://mbed.org/teams/Nordic-Semiconductor/code/nRF51822/#7455428e5ddb
+http://mbed.org/teams/Nordic-Semiconductor/code/nRF51822/#ca9c9c2cfc6a