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