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
main.cpp
- Committer:
- Bobty
- Date:
- 2015-07-27
- Revision:
- 4:f0b030a3223f
- Parent:
- 3:a4b8d67de1b1
- Child:
- 5:2682353a8c32
File content as of revision 4:f0b030a3223f:
// BLE Alarm Watch
// Based on BLE examples on MBED
// Rob Dobson, 2015
#include "mbed.h"
#include "BLE.h"
#include "ButtonService.h"
#include "WatchTimeService.h"
#include "nrf51_rtc.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[] = "JoesAlarm";
// UUIDs of services offered
static const uint16_t uuid16_list[] = {ButtonService::BUTTON_SERVICE_UUID, WatchTimeService::WATCHTIME_SERVICE_UUID};
// Service offering to read and set the time on the watch
WatchTimeService *pWatchTimeService;
// TEST CODE
int callbackCount = 0;
uint8_t testbuf[WatchTimeService::WatchTime_BlockSize];
time_t retval = 0;
int servcode = 0;
int buflen = 0;
int mycode = 0;
int offs = 0;
int butcode = 0;
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. */
// Update the rtc library time (it says in the notes on the rtc lib that this needs to happen
// more than once every few hundred seconds to avoid a rollover
rtc.time();
}
time_t watchTimeToUnix(const uint8_t* pWatchTime)
{
struct tm tminfo;
tminfo.tm_year = int(pWatchTime[0])*256 + pWatchTime[1] - 1900;
tminfo.tm_mon = pWatchTime[2] - 1;
tminfo.tm_mday = pWatchTime[3];
tminfo.tm_hour = pWatchTime[4];
tminfo.tm_min = pWatchTime[5];
tminfo.tm_sec = pWatchTime[6];
tminfo.tm_isdst = -1;
time_t timest = mktime(&tminfo);
return timest;
}
void onDataWrittenCallback(const GattWriteCallbackParams *params)
{
// TEST code
callbackCount++;
memcpy(testbuf, params->data, WatchTimeService::WatchTime_BlockSize);
servcode = params->handle;
buflen = params->len;
mycode = pWatchTimeService->getValueHandle();
butcode = buttonServicePtr->getValueHandle();
offs = params->offset;
// Check if this is time setting
if (pWatchTimeService->getValueHandle() == params->handle)
{
if (params->len == WatchTimeService::WatchTime_BlockSize)
{
time_t timest = watchTimeToUnix(params->data);
retval = timest;
if (timest != -1)
rtc.set_time(timest);
}
}
}
// TEST CODE
void print_time()
{
time_t rawtime=rtc.time();
// massage the time into a human-friendly format for printing
struct tm * timeinfo;
timeinfo = localtime(&rawtime);
char date[24];
strftime(date,sizeof(date),"%H:%M:%S on %m/%d/%G",timeinfo);
printf("The current time is %s.\r\n",date);
}
int main(void)
{
printf("AlarmWatch\r\n");
// TEST CODE
memset(testbuf, 0, WatchTimeService::WatchTime_BlockSize);
int loopCount = 0;
led1 = 1;
Ticker ticker;
ticker.attach(periodicCallback, 1);
button.fall(buttonPressedCallback);
button.rise(buttonReleasedCallback);
// BLE init
ble.init();
ble.gap().onDisconnection(disconnectionCallback);
ble.onDataWritten(onDataWrittenCallback);
// TEST CODE
ButtonService buttonService(ble, false /* initial value for button pressed */);
buttonServicePtr = &buttonService;
// Watch Time Service
uint8_t initialTime[] = { uint8_t(2015/256), uint8_t(2015%256), 7, 26, 12, 8, 0 };
WatchTimeService watchTimeService(ble, initialTime);
pWatchTimeService = &watchTimeService;
// 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();
loopCount++;
if (loopCount < 5)
continue;
loopCount = 0;
time_t rawtime;
struct tm * timeinfo;
time (&rawtime);
timeinfo = localtime (&rawtime);
printf ("Current local time and date: %s callbacks %d retval %d\r\n", asctime(timeinfo), callbackCount, retval);
printf ("Timest %02x %02x %02x %02x %02x %02x %02x %ld\r\n", testbuf[0],
testbuf[1], testbuf[2], testbuf[3], testbuf[4], testbuf[5], testbuf[6], retval);
printf ("serv %d buflen %d mycode %d offs %d butcode %d\r\n", servcode, buflen, mycode, offs, butcode);
printf ("val %ld\r\n", watchTimeService.getValueHandle());
print_time();
}
}
/*
#include "mbed.h"
#include "BLEDevice.h"
#include "DeviceInformationService.h"
// BLE Device etc
BLEDevice ble;
DigitalOut ledIndicator(LED1);
DigitalOut testOut(p1);
// Device name
const static char DEVICE_NAME[] = "JOESALARM";
// UUID for CurTimeService & TimeBlockCharacteristic
const uint16_t UUID_CUR_TIME_SERVICE = 0xA000;
const uint16_t UUID_TIME_BLOCK_CHARACTERISTIC = 0xA001;
// List of supported service UUIDs
static const uint16_t uuid16_list[] = {UUID_CUR_TIME_SERVICE};
// Time is packed in an array of bytes
const int SIZE_OF_TIME_BLOCK = 7;
uint8_t timeBlockInitValue[SIZE_OF_TIME_BLOCK];
uint8_t curTimeBlock[SIZE_OF_TIME_BLOCK];
// GATT Characteristic for time block
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)
{
ble.startAdvertising(); // restart advertising
}
// Callback for ticker
int tickCount = 0;
bool showInfo = false;
int writeSinceLast = 0;
void periodicCallback(void)
{
ledIndicator = !ledIndicator;
testOut = !testOut;
tickCount++;
if (tickCount > 100)
{
showInfo = true;
tickCount = 0;
}
}
// Data written callback
void onDataWrittenCallback(const GattCharacteristicWriteCBParams *params)
{
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);
}
writeSinceLast = true;
}
// Main
int main(void)
{
ledIndicator = 0;
testOut = 0;
// Ticker is interrupt driven
Ticker ticker;
ticker.attach_us(periodicCallback, 100000);
// Initial value for the time block characteristic
memset(timeBlockInitValue, 0, sizeof(timeBlockInitValue));
// Init BLE and register callbacks
ble.init();
ble.onDisconnection(disconnectionCallback);
ble.onDataWritten(onDataWrittenCallback);
// Add the time setting service
GattCharacteristic *charTable[] = {&timeBlockCharacteristic};
GattService timeBlockService(UUID_CUR_TIME_SERVICE, charTable, sizeof(charTable) / sizeof(GattCharacteristic *));
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.
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.
ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
// 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));
ble.startAdvertising();
while (true)
{
ble.waitForEvent();
if (showInfo)
{
printf("Time info: ");
for (int i = 0; i < SIZE_OF_TIME_BLOCK; i++)
{
printf("%02d", curTimeBlock[i]);
}
printf(" - writeSinceLast %d\r\n", writeSinceLast);
showInfo = false;
writeSinceLast = 0;
}
}
}
*/