BLE Current Time Service

BLE Current Time Service (CTS) implementation.

supported only "Current Time" Characteristics.

https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx

I don't have a device corresponding to the CTS, I cannot check it. x)

Committer:
ohneta
Date:
Sat Oct 17 17:19:06 2015 +0000
Revision:
3:eb07c3c4bf5e
Parent:
2:27a6c04cadb2
Child:
4:ad8739f7e30a
a litte bug fix.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
ohneta 0:8c79e11bc3a1 1 /*
ohneta 0:8c79e11bc3a1 2 * BLE Current Time Service (subset)
ohneta 0:8c79e11bc3a1 3 *
ohneta 0:8c79e11bc3a1 4 * by ohneta/ Oct. 2015
ohneta 0:8c79e11bc3a1 5 */
ohneta 0:8c79e11bc3a1 6 #ifndef __BLE_CURRENT_TIME_SERVICE_H__
ohneta 0:8c79e11bc3a1 7 #define __BLE_CURRENT_TIME_SERVICE_H__
ohneta 0:8c79e11bc3a1 8
ohneta 1:c4b8028471f9 9 #include "ble/BLE.h"
ohneta 2:27a6c04cadb2 10 #include <time.h>
ohneta 2:27a6c04cadb2 11
ohneta 0:8c79e11bc3a1 12 //extern Serial pc;
ohneta 0:8c79e11bc3a1 13
ohneta 0:8c79e11bc3a1 14
ohneta 0:8c79e11bc3a1 15 enum BLE_DayofWeek {
ohneta 0:8c79e11bc3a1 16 notknown = 0,
ohneta 0:8c79e11bc3a1 17 Monday = 1,
ohneta 0:8c79e11bc3a1 18 Tuesday,
ohneta 0:8c79e11bc3a1 19 Wednesday,
ohneta 0:8c79e11bc3a1 20 Thursday,
ohneta 0:8c79e11bc3a1 21 Friday,
ohneta 0:8c79e11bc3a1 22 Saturday,
ohneta 0:8c79e11bc3a1 23 Sunday
ohneta 0:8c79e11bc3a1 24 };
ohneta 0:8c79e11bc3a1 25
ohneta 0:8c79e11bc3a1 26 typedef struct {
ohneta 0:8c79e11bc3a1 27 uint16_t year;
ohneta 0:8c79e11bc3a1 28 uint8_t month;
ohneta 0:8c79e11bc3a1 29 uint8_t day;
ohneta 0:8c79e11bc3a1 30 uint8_t hours;
ohneta 0:8c79e11bc3a1 31 uint8_t minutes;
ohneta 0:8c79e11bc3a1 32 uint8_t seconds;
ohneta 0:8c79e11bc3a1 33 } BLE_DateTime;
ohneta 0:8c79e11bc3a1 34
ohneta 0:8c79e11bc3a1 35 typedef struct : BLE_DateTime {
ohneta 0:8c79e11bc3a1 36 BLE_DayofWeek dayOfWeek;
ohneta 0:8c79e11bc3a1 37 } BLE_DayDateTime;
ohneta 0:8c79e11bc3a1 38
ohneta 3:eb07c3c4bf5e 39 typedef struct BLE_ExactTime256 : BLE_DayDateTime {
ohneta 0:8c79e11bc3a1 40 uint8_t fractions256;
ohneta 3:eb07c3c4bf5e 41 } BLE_ExactTime256;
ohneta 0:8c79e11bc3a1 42
ohneta 3:eb07c3c4bf5e 43 typedef struct BLE_CurrentTime : BLE_ExactTime256 {
ohneta 0:8c79e11bc3a1 44 uint8_t adjustReason;
ohneta 3:eb07c3c4bf5e 45 } BLE_CurrentTime;
ohneta 0:8c79e11bc3a1 46
ohneta 0:8c79e11bc3a1 47 #define BLE_CURRENT_TIME_CHAR_VALUE_SIZE 10
ohneta 0:8c79e11bc3a1 48
ohneta 0:8c79e11bc3a1 49 /**
ohneta 0:8c79e11bc3a1 50 *
ohneta 0:8c79e11bc3a1 51 */
ohneta 0:8c79e11bc3a1 52 class CurrentTimeService {
ohneta 0:8c79e11bc3a1 53
ohneta 0:8c79e11bc3a1 54 protected:
ohneta 0:8c79e11bc3a1 55 Ticker ticker;
ohneta 0:8c79e11bc3a1 56
ohneta 0:8c79e11bc3a1 57 /**
ohneta 0:8c79e11bc3a1 58 * ticker callback.
ohneta 0:8c79e11bc3a1 59 * interval = 1sec
ohneta 0:8c79e11bc3a1 60 */
ohneta 0:8c79e11bc3a1 61 void epochtimePeriodicCallback(void)
ohneta 0:8c79e11bc3a1 62 {
ohneta 0:8c79e11bc3a1 63 time_t tmpEpochTime = epochTimeByDateTimeBuffer();
ohneta 0:8c79e11bc3a1 64 tmpEpochTime++;
ohneta 0:8c79e11bc3a1 65 dataTimeBufferByEpochTime(&tmpEpochTime);
ohneta 0:8c79e11bc3a1 66 }
ohneta 0:8c79e11bc3a1 67
ohneta 0:8c79e11bc3a1 68 void dataTimeBufferByEpochTime(time_t *epochTime)
ohneta 0:8c79e11bc3a1 69 {
ohneta 0:8c79e11bc3a1 70 struct tm *tmPtr = localtime(epochTime);
ohneta 0:8c79e11bc3a1 71
ohneta 0:8c79e11bc3a1 72 *(uint16_t *)&valueBytes[0] = tmPtr->tm_year + 1900;
ohneta 0:8c79e11bc3a1 73 valueBytes[2] = tmPtr->tm_mon + 1;
ohneta 0:8c79e11bc3a1 74 valueBytes[3] = tmPtr->tm_mday;
ohneta 0:8c79e11bc3a1 75 valueBytes[4] = tmPtr->tm_hour;
ohneta 0:8c79e11bc3a1 76 valueBytes[5] = tmPtr->tm_min;
ohneta 0:8c79e11bc3a1 77 valueBytes[6] = tmPtr->tm_sec;
ohneta 0:8c79e11bc3a1 78 valueBytes[7] = (BLE_DayofWeek)((tmPtr->tm_wday == 0) ? 7 : tmPtr->tm_wday);
ohneta 0:8c79e11bc3a1 79 valueBytes[8] = 0x00;
ohneta 0:8c79e11bc3a1 80 valueBytes[9] = 0x00;
ohneta 0:8c79e11bc3a1 81
ohneta 0:8c79e11bc3a1 82 ble.gattServer().write(currentTimeCharacteristic.getValueHandle(), valueBytes, BLE_CURRENT_TIME_CHAR_VALUE_SIZE);
ohneta 0:8c79e11bc3a1 83 }
ohneta 0:8c79e11bc3a1 84
ohneta 0:8c79e11bc3a1 85 time_t epochTimeByDateTimeBuffer()
ohneta 0:8c79e11bc3a1 86 {
ohneta 0:8c79e11bc3a1 87 struct tm timep;
ohneta 0:8c79e11bc3a1 88 {
ohneta 0:8c79e11bc3a1 89 timep.tm_year = *(uint16_t *)&valueBytes[0] - 1900;
ohneta 0:8c79e11bc3a1 90 timep.tm_mon = valueBytes[2] - 1;
ohneta 0:8c79e11bc3a1 91 timep.tm_mday = valueBytes[3];
ohneta 0:8c79e11bc3a1 92 timep.tm_hour = valueBytes[4];
ohneta 0:8c79e11bc3a1 93 timep.tm_min = valueBytes[5];
ohneta 0:8c79e11bc3a1 94 timep.tm_sec = valueBytes[6];
ohneta 0:8c79e11bc3a1 95 timep.tm_isdst = 0;
ohneta 0:8c79e11bc3a1 96 }
ohneta 0:8c79e11bc3a1 97 time_t epochTime = mktime(&timep);
ohneta 0:8c79e11bc3a1 98
ohneta 0:8c79e11bc3a1 99 return epochTime;
ohneta 0:8c79e11bc3a1 100 }
ohneta 0:8c79e11bc3a1 101
ohneta 0:8c79e11bc3a1 102 public:
ohneta 0:8c79e11bc3a1 103 //------------------------------------------------------------------------------------
ohneta 0:8c79e11bc3a1 104 /**
ohneta 0:8c79e11bc3a1 105 *
ohneta 0:8c79e11bc3a1 106 */
ohneta 0:8c79e11bc3a1 107 CurrentTimeService(BLE &_ble, BLE_DateTime &initialDateTime) :
ohneta 0:8c79e11bc3a1 108 ble(_ble),
ohneta 0:8c79e11bc3a1 109 currentTimeCharacteristic( GattCharacteristic::UUID_CURRENT_TIME_CHAR,
ohneta 0:8c79e11bc3a1 110 valueBytes, BLE_CURRENT_TIME_CHAR_VALUE_SIZE, BLE_CURRENT_TIME_CHAR_VALUE_SIZE,
ohneta 0:8c79e11bc3a1 111 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ
ohneta 0:8c79e11bc3a1 112 | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY
ohneta 0:8c79e11bc3a1 113 | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE
ohneta 0:8c79e11bc3a1 114 )
ohneta 0:8c79e11bc3a1 115 {
ohneta 0:8c79e11bc3a1 116 writeDateTime(initialDateTime);
ohneta 0:8c79e11bc3a1 117 ticker.attach(this, &CurrentTimeService::epochtimePeriodicCallback, 1.0);
ohneta 0:8c79e11bc3a1 118
ohneta 0:8c79e11bc3a1 119 GattCharacteristic *charsTable[] = {&currentTimeCharacteristic};
ohneta 0:8c79e11bc3a1 120 GattService currentTimeService(GattService::UUID_CURRENT_TIME_SERVICE, charsTable, sizeof(charsTable) / sizeof(GattCharacteristic *) );
ohneta 0:8c79e11bc3a1 121
ohneta 0:8c79e11bc3a1 122 ble.addService(currentTimeService);
ohneta 0:8c79e11bc3a1 123 ble.onDataWritten(this, &CurrentTimeService::onDataWritten);
ohneta 0:8c79e11bc3a1 124 }
ohneta 0:8c79e11bc3a1 125
ohneta 0:8c79e11bc3a1 126 /**
ohneta 0:8c79e11bc3a1 127 */
ohneta 0:8c79e11bc3a1 128 void writeDateTime(BLE_DateTime &dateTime)
ohneta 0:8c79e11bc3a1 129 {
ohneta 0:8c79e11bc3a1 130 *(uint16_t *)&valueBytes[0] = dateTime.year;
ohneta 0:8c79e11bc3a1 131 valueBytes[2] = dateTime.month;
ohneta 0:8c79e11bc3a1 132 valueBytes[3] = dateTime.day;
ohneta 0:8c79e11bc3a1 133 valueBytes[4] = dateTime.hours;
ohneta 0:8c79e11bc3a1 134 valueBytes[5] = dateTime.minutes;
ohneta 0:8c79e11bc3a1 135 valueBytes[6] = dateTime.seconds;
ohneta 0:8c79e11bc3a1 136
ohneta 0:8c79e11bc3a1 137 // not support
ohneta 0:8c79e11bc3a1 138 valueBytes[7] = 0x00; // day of week
ohneta 0:8c79e11bc3a1 139 valueBytes[8] = 0x00; // Fractions256
ohneta 0:8c79e11bc3a1 140 valueBytes[9] = 0x00; // Adjust Reason
ohneta 0:8c79e11bc3a1 141 }
ohneta 0:8c79e11bc3a1 142
ohneta 0:8c79e11bc3a1 143 /**
ohneta 0:8c79e11bc3a1 144 */
ohneta 0:8c79e11bc3a1 145 void readDateTime(BLE_DateTime &dateTime)
ohneta 0:8c79e11bc3a1 146 {
ohneta 0:8c79e11bc3a1 147 dateTime.year = (uint16_t)valueBytes[0] << 8 | valueBytes[1];
ohneta 0:8c79e11bc3a1 148 dateTime.month = valueBytes[2];
ohneta 0:8c79e11bc3a1 149 dateTime.day = valueBytes[3];
ohneta 0:8c79e11bc3a1 150 dateTime.hours = valueBytes[4];
ohneta 0:8c79e11bc3a1 151 dateTime.minutes = valueBytes[5];
ohneta 0:8c79e11bc3a1 152 dateTime.seconds = valueBytes[6];
ohneta 0:8c79e11bc3a1 153 }
ohneta 0:8c79e11bc3a1 154
ohneta 0:8c79e11bc3a1 155
ohneta 0:8c79e11bc3a1 156 // for BLE GATT callback
ohneta 0:8c79e11bc3a1 157 // "WRITE" is optionaly
ohneta 0:8c79e11bc3a1 158 virtual void onDataWritten(const GattWriteCallbackParams *params)
ohneta 0:8c79e11bc3a1 159 {
ohneta 0:8c79e11bc3a1 160 if (params->handle == currentTimeCharacteristic.getValueHandle()) {
ohneta 0:8c79e11bc3a1 161 memcpy((void *)&valueBytes, params->data, params->len);
ohneta 0:8c79e11bc3a1 162 }
ohneta 0:8c79e11bc3a1 163 }
ohneta 0:8c79e11bc3a1 164
ohneta 0:8c79e11bc3a1 165 protected:
ohneta 0:8c79e11bc3a1 166 BLE &ble;
ohneta 0:8c79e11bc3a1 167 uint8_t valueBytes[BLE_CURRENT_TIME_CHAR_VALUE_SIZE];
ohneta 0:8c79e11bc3a1 168 GattCharacteristic currentTimeCharacteristic;
ohneta 0:8c79e11bc3a1 169
ohneta 0:8c79e11bc3a1 170
ohneta 0:8c79e11bc3a1 171
ohneta 0:8c79e11bc3a1 172 /*
ohneta 0:8c79e11bc3a1 173 // for debug infos.
ohneta 0:8c79e11bc3a1 174 void printExactTime256Buffer()
ohneta 0:8c79e11bc3a1 175 {
ohneta 3:eb07c3c4bf5e 176 BLE_CurrentTime currentTime;
ohneta 0:8c79e11bc3a1 177 currentTime.year = *((uint16_t *)&valueBytes[0]);
ohneta 0:8c79e11bc3a1 178 currentTime.month = valueBytes[2];
ohneta 0:8c79e11bc3a1 179 currentTime.day = valueBytes[3];
ohneta 0:8c79e11bc3a1 180 currentTime.hours = valueBytes[4];
ohneta 0:8c79e11bc3a1 181 currentTime.minutes = valueBytes[5];
ohneta 0:8c79e11bc3a1 182 currentTime.seconds = valueBytes[6];
ohneta 0:8c79e11bc3a1 183 currentTime.dayOfWeek = (BLE_DayofWeek)valueBytes[7];
ohneta 0:8c79e11bc3a1 184
ohneta 0:8c79e11bc3a1 185 pc.printf("%04d-%02d-%02d %02d:%02d:%02d [%02d]\n",
ohneta 0:8c79e11bc3a1 186 currentTime.year, currentTime.month, currentTime.day,
ohneta 0:8c79e11bc3a1 187 currentTime.hours, currentTime.minutes, currentTime.seconds,
ohneta 0:8c79e11bc3a1 188 currentTime.dayOfWeek );
ohneta 0:8c79e11bc3a1 189 }
ohneta 0:8c79e11bc3a1 190 */
ohneta 0:8c79e11bc3a1 191 };
ohneta 0:8c79e11bc3a1 192
ohneta 0:8c79e11bc3a1 193 #endif /* #ifndef __BLE_CURRENT_TIME_SERVICE_H__*/