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
Diff: main.cpp
- 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 -// } -// } } +*/