Skip to content

Instantly share code, notes, and snippets.

@ColeMurray
Last active August 16, 2021 04:52
Show Gist options
  • Save ColeMurray/df341c8eba0c12465057b9349a9f86ae to your computer and use it in GitHub Desktop.
Save ColeMurray/df341c8eba0c12465057b9349a9f86ae to your computer and use it in GitHub Desktop.
A patch adding local time information characteristic reading the NRF5 SDK for the ble_cts_c client

NRF5 SDK 17.0.2 ble_cts_c Patch

This patch adds support for local time information characteristic from the Current Time Service.

It adds an additional handle and data structure for storing the local time information.

typedef struct ATTR_PACKED {
    int8_t timezone_offset; // offset from UTC in increments of 15
    uint8_t dst_offset;
} local_time_info_char_t;

To apply the patch:

patch ble_cts_c.c ble_cts_c.c.patch
patch ble_cts_c.h ble_cts_c.h.patch
+++ ble_cts_c.c 2021-08-15 18:42:45.000000000 -0700
@@ -56,6 +56,8 @@
#define CTS_C_CURRENT_TIME_EXPECTED_LENGTH 10 /**< | Year |Month |Day |Hours |Minutes |Seconds |Weekday |Fraction|Reason |
| 2 bytes |1 byte |1 byte |1 byte |1 byte |1 byte |1 byte |1 byte |1 byte | = 10 bytes. */
+static void current_time_read(ble_cts_c_t * p_cts, ble_evt_t const * p_ble_evt);
+static void local_time_information_read(ble_cts_c_t * p_cts, ble_evt_t const * p_ble_evt);
/**@brief Function for intercepting errors of GATTC and the BLE GATT Queue.
*
@@ -106,13 +108,17 @@
// Find the handles of the Current Time characteristic.
for (uint32_t i = 0; i < p_evt->params.discovered_db.char_count; i++)
{
- if (p_evt->params.discovered_db.charateristics[i].characteristic.uuid.uuid ==
- BLE_UUID_CURRENT_TIME_CHAR)
- {
- // Found Current Time characteristic. Store CCCD and value handle and break.
- evt.params.char_handles.cts_handle = p_chars->characteristic.handle_value;
- evt.params.char_handles.cts_cccd_handle = p_chars->cccd_handle;
- break;
+ switch(p_chars[i].characteristic.uuid.uuid) {
+ case BLE_UUID_LOCAL_TIME_INFORMATION_CHAR:
+ NRF_LOG_INFO("Local Time Information discovered at peer.");
+ evt.params.char_handles.ltis_handle = p_chars[i].characteristic.handle_value;
+ break;
+ case BLE_UUID_CURRENT_TIME_CHAR:
+ evt.params.char_handles.cts_handle = p_chars[i].characteristic.handle_value;
+ evt.params.char_handles.cts_cccd_handle = p_chars[i].cccd_handle;
+ break;
+ default:
+ break;
}
}
@@ -151,6 +157,7 @@
p_cts->error_handler = p_cts_init->error_handler;
p_cts->conn_handle = BLE_CONN_HANDLE_INVALID;
p_cts->char_handles.cts_handle = BLE_GATT_HANDLE_INVALID;
+ p_cts->char_handles.ltis_handle = BLE_GATT_HANDLE_INVALID;
p_cts->char_handles.cts_cccd_handle = BLE_GATT_HANDLE_INVALID;
p_cts->p_gatt_queue = p_cts_init->p_gatt_queue;
@@ -261,6 +268,32 @@
}
+
+static void on_read_rsp(ble_cts_c_t * p_cts, ble_evt_t const * p_ble_evt) {
+ ret_code_t err_code;
+ ble_gattc_evt_read_rsp_t const * p_response = &p_ble_evt->evt.gattc_evt.params.read_rsp;
+
+ // Check if the event is on the link for this instance and the event handler is present.
+ if ((p_cts->evt_handler == NULL) ||
+ (p_cts->conn_handle != p_ble_evt->evt.gattc_evt.conn_handle))
+ {
+ return;
+ }
+
+ if ( (p_cts->char_handles.ltis_handle != BLE_GATT_HANDLE_INVALID)
+ && (p_response->handle == p_cts->char_handles.ltis_handle)
+ && (p_cts->evt_handler != NULL))
+ {
+ local_time_information_read(p_cts, p_ble_evt);
+ } else if ( (p_cts->char_handles.cts_handle != BLE_GATT_HANDLE_INVALID)
+ && (p_response->handle == p_cts->char_handles.cts_handle)
+ && (p_cts->evt_handler != NULL))
+ {
+ current_time_read(p_cts, p_ble_evt);
+ }
+}
+
+
/**@brief Function for reading the Current Time. The time is decoded, and then validated.
* Depending on the outcome, the CTS event handler will be called with
* the Current Time event or an invalid time event.
@@ -310,6 +343,61 @@
}
}
+/** @brief Function for decoding a local_time_information payload
+ * @param[in] p_local_time_info Local Time Info structure.
+ * @param[in] p_data Pointer to the buffer containing the Local Time Information.
+ * @param[in] length Length of the buffer containing the Local Time Information.
+ *
+ * @retval NRF_SUCCESS If the time struct is valid.
+ * @retval NRF_ERROR_DATA_SIZE If the length does not match the expected size of the data.
+ */
+static uint32_t local_time_information_decode(local_time_info_char_t *p_local_time_info,
+ uint8_t const * p_data,
+ uint32_t const length)
+{
+ if (length != 2)
+ {
+ return NRF_ERROR_DATA_SIZE;
+ }
+
+ memcpy(p_local_time_info, p_data, sizeof(local_time_info_char_t));
+
+ return NRF_SUCCESS;
+}
+
+
+/**@brief Function for reading the Current Time. The time is decoded, and then validated.
+ * Depending on the outcome, the CTS event handler will be called with
+ * the Current Time event or an invalid time event.
+ *
+ * @param[in] p_cts Current Time Service client structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+
+static void local_time_information_read(ble_cts_c_t * p_cts, ble_evt_t const * p_ble_evt)
+{
+ ble_cts_c_evt_t evt;
+ uint32_t err_code = NRF_SUCCESS;
+
+ if (p_ble_evt->evt.gattc_evt.gatt_status == BLE_GATT_STATUS_SUCCESS)
+ {
+ err_code = local_time_information_decode(&evt.params.local_time_info,
+ p_ble_evt->evt.gattc_evt.params.read_rsp.data,
+ sizeof(local_time_info_char_t));
+
+ if (err_code != NRF_SUCCESS)
+ {
+ // The data length was invalid. Decoding was not completed.
+ evt.evt_type = BLE_CTS_C_EVT_INVALID_LOCAL_TIME;
+ } else {
+ evt.evt_type = BLE_CTS_C_EVT_LOCAL_TIME_INFO;
+ }
+ p_cts->evt_handler(p_cts, &evt);
+ }
+}
+
+
+
/**@brief Function for handling the Disconnect event.
*
@@ -333,6 +421,7 @@
p_cts->evt_handler(p_cts, &evt);
p_cts->char_handles.cts_handle = BLE_GATT_HANDLE_INVALID;
+ p_cts->char_handles.ltis_handle = BLE_GATT_HANDLE_INVALID;
p_cts->char_handles.cts_cccd_handle = BLE_GATT_HANDLE_INVALID;
}
}
@@ -346,7 +435,7 @@
switch (p_ble_evt->header.evt_id)
{
case BLE_GATTC_EVT_READ_RSP:
- current_time_read(p_cts, p_ble_evt);
+ on_read_rsp(p_cts, p_ble_evt);
break;
case BLE_GAP_EVT_DISCONNECTED:
@@ -380,6 +469,26 @@
return nrf_ble_gq_item_add(p_cts->p_gatt_queue, &read_req, p_cts->conn_handle);
}
+uint32_t ble_cts_c_local_time_information_read(ble_cts_c_t const * p_cts)
+{
+ if (!ble_cts_c_is_cts_discovered(p_cts))
+ {
+ return NRF_ERROR_NOT_FOUND;
+ }
+
+ nrf_ble_gq_req_t read_req;
+
+ memset(&read_req, 0, sizeof(nrf_ble_gq_req_t));
+
+ read_req.type = NRF_BLE_GQ_REQ_GATTC_READ;
+ read_req.error_handler.cb = gatt_error_handler;
+ read_req.error_handler.p_ctx = (ble_cts_c_t *)p_cts;
+ read_req.params.gattc_read.handle = p_cts->char_handles.ltis_handle;
+ read_req.params.gattc_read.offset = 0;
+
+ return nrf_ble_gq_item_add(p_cts->p_gatt_queue, &read_req, p_cts->conn_handle);
+}
+
uint32_t ble_cts_c_handles_assign(ble_cts_c_t * p_cts,
const uint16_t conn_handle,
@@ -392,6 +501,7 @@
{
p_cts->char_handles.cts_cccd_handle = p_peer_handles->cts_cccd_handle;
p_cts->char_handles.cts_handle = p_peer_handles->cts_handle;
+ p_cts->char_handles.ltis_handle = p_peer_handles->ltis_handle;
}
return nrf_ble_gq_conn_handle_register(p_cts->p_gatt_queue, conn_handle);
+++ ble_cts_c.h 2021-08-15 18:39:52.000000000 -0700
@@ -141,6 +141,12 @@
adjust_reason_t adjust_reason;
} current_time_char_t;
+
+typedef struct ATTR_PACKED {
+ int8_t timezone_offset; // offset from UTC in increments of 15
+ uint8_t dst_offset;
+} local_time_info_char_t;
+
// Forward declaration of the ble_cts_c_t type.
typedef struct ble_cts_c_s ble_cts_c_t;
@@ -151,13 +157,16 @@
BLE_CTS_C_EVT_DISCOVERY_FAILED, /**< The Current Time Service was not found at the peer. */
BLE_CTS_C_EVT_DISCONN_COMPLETE, /**< Event indicating that the Current Time Service Client module finished processing the BLE_GAP_EVT_DISCONNECTED event. This event is triggered only if a valid instance of the Current Time Service was found at the server. The application can use this event to do a cleanup related to the Current Time Service client.*/
BLE_CTS_C_EVT_CURRENT_TIME, /**< A new Current Time reading has been received. */
- BLE_CTS_C_EVT_INVALID_TIME /**< The Current Time value received from the peer is invalid.*/
+ BLE_CTS_C_EVT_INVALID_TIME, /**< The Current Time value received from the peer is invalid.*/
+ BLE_CTS_C_EVT_LOCAL_TIME_INFO, /**< The Local Time Information value received has been received */
+ BLE_CTS_C_EVT_INVALID_LOCAL_TIME /**< The Local Time Information value received is invalid */
} ble_cts_c_evt_type_t;
/**@brief Structure containing the handles related to the Heart Rate Service found on the peer. */
typedef struct
{
uint16_t cts_handle; /**< Handle of the Current Time characteristic, as provided by the SoftDevice. */
+ uint16_t ltis_handle; /**< Handle of the Local time information characteristic, as provided by the SoftDevice. */
uint16_t cts_cccd_handle; /**< Handle of the CCCD of the Current Time characteristic. */
} ble_cts_c_handles_t;
@@ -170,6 +179,7 @@
{
current_time_char_t current_time; /**< Current Time characteristic data. This is filled when the evt_type is @ref BLE_CTS_C_EVT_CURRENT_TIME. */
ble_cts_c_handles_t char_handles; /**< Handles related to Current Time, found on the peer device. This is filled when the evt_type is @ref BLE_HRS_C_EVT_DISCOVERY_COMPLETE.*/
+ local_time_info_char_t local_time_info; /** < Local Time information characteristic data. */
} params;
} ble_cts_c_evt_t;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment