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)
CurrentTimeService.h@3:eb07c3c4bf5e, 2015-10-17 (annotated)
- 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?
User | Revision | Line number | New 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[] = {¤tTimeCharacteristic}; |
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__*/ |