init
Dependencies: BLE_API mbed nRF51822
Revision 2:95c770f35636, committed 2015-08-17
- Comitter:
- jslater8
- Date:
- Mon Aug 17 09:49:55 2015 +0000
- Parent:
- 1:4bdebb81dcd5
- Commit message:
- Initial
Changed in this revision
--- 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(¶msOut)); + + ASSERT_NO_FAILURE(ble.gap().getPreferredConnectionParams(&temp)); + ASSERT_NO_FAILURE(ble.gap().setPreferredConnectionParams(¶msOut)); + + printf("ASSERTIONS DONE\r\n"); + ble.gap().getPreferredConnectionParams(¶ms); + 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