kindlebt
Bluetooth functionality for Kindle 11th gen and up
Loading...
Searching...
No Matches
compat_ace_implementations.c
1#include <kindlebt/compat_ace_implementations.h>
2
3#include <endian.h>
4#include <stdbool.h>
5#include <stdlib.h>
6#include <string.h>
7
8#include "log.h"
9
10#include <kindlebt/compat_ace_handler.h>
11#include <kindlebt/compat_ace_internals.h>
12#include <kindlebt/compat_ace_shims.h>
13#include <kindlebt/compat_ace_utils.h>
14#include <kindlebt/compat_acealloc.h>
15
23static uint16_t create_client_callback_mask(bleGattClientCallbacks_t* p_callbacks) {
24 uint16_t cback_mask = 0;
25 if (p_callbacks == NULL || p_callbacks->size == 0) return cback_mask;
26 cback_mask |= p_callbacks->on_ble_gattc_service_registered_cb
27 ? ACEBT_IPC_CBACK_MASK_GATTC_SERVICE_REGISTERED
28 : 0;
29 cback_mask |= p_callbacks->on_ble_gattc_service_discovered_cb
30 ? ACEBT_IPC_CBACK_MASK_GATTC_SERVICE_DISCOVERED
31 : 0;
32 cback_mask |= p_callbacks->on_ble_gattc_read_characteristics_cb
33 ? ACEBT_IPC_CBACK_MASK_GATTC_SERVICE_READ_CHARS
34 : 0;
35 cback_mask |= p_callbacks->on_ble_gattc_write_characteristics_cb
36 ? ACEBT_IPC_CBACK_MASK_GATTC_SERVICE_WRITE_CHARS
37 : 0;
38 cback_mask |= p_callbacks->notify_characteristics_cb
39 ? ACEBT_IPC_CBACK_MASK_GATTC_SERVICE_NOTIFY_CHARS
40 : 0;
41 cback_mask |= p_callbacks->on_ble_gattc_write_descriptor_cb
42 ? ACEBT_IPC_CBACK_MASK_GATTC_SERVICE_DESC_WRITE
43 : 0;
44 cback_mask |= p_callbacks->on_ble_gattc_read_descriptor_cb
45 ? ACEBT_IPC_CBACK_MASK_GATTC_SERVICE_DESC_READ
46 : 0;
47 cback_mask |= p_callbacks->on_ble_gattc_get_gatt_db_cb ? ACEBT_IPC_CBACK_MASK_GATTC_GET_DB : 0;
48 cback_mask |=
49 p_callbacks->on_ble_gattc_execute_write_cb ? ACEBT_IPC_CBACK_MASK_GATTC_EXECUTE_WRITE : 0;
50 return cback_mask;
51}
52
53status_t pre5170_bleRegisterGattClient(
54 sessionHandle session_handle, bleGattClientCallbacks_t* callbacks, bleAppId_t app_id
55) {
56 status_t status;
57 uint16_t mask = 0;
58 aipcHandles_t aipc_handle;
59 registerCbackGattcData_t manager_callbacks;
60
61 status = getSessionInfo(session_handle, &aipc_handle);
62 if (status != ACE_STATUS_OK) {
63 log_error("[%s()]: Couldn't get session info. Result %d", __func__, status);
64 return ACE_STATUS_BAD_PARAM;
65 }
66
67 dump_aipc_handle(aipc_handle);
68
69 mask = create_client_callback_mask(callbacks);
70 dump_mask_bits(mask);
71
72 // In theory this should match session_handle exactly
73 uint32_t temp_aipc = (aipc_handle.server_id << 16) + aipc_handle.callback_server_id;
74 log_debug("[%s()]: temp_aipc %u (0x%04x)", __func__, temp_aipc, temp_aipc);
75 aceBt_serializeGattcRegisterData(&manager_callbacks, temp_aipc, mask, app_id);
76 log_debug("[%s()]: Register GATT Client session handle %p", __func__, session_handle);
77
78 dump_registerCbackGattcData(&manager_callbacks);
79
80 status = registerBTClientData(session_handle, CALLBACK_INDEX_BLE_GATT_CLIENT, (void*)callbacks);
81 log_debug("[%s()]: registerBTClientData step. Result: %d", __func__, status);
82 if (status != ACEBT_STATUS_SUCCESS) return status;
83
84 status = registerBTEvtHandler(
85 session_handle, pre5170_gattc_cb_handler, ACE_BT_CALLBACK_GATTC_INIT,
86 ACE_BT_CALLBACK_GATTC_MAX
87 );
88 log_debug("[%s()]: registerBTEvtHandler step. Result: %d", __func__, status);
89 if (status != ACEBT_STATUS_SUCCESS) return status;
90
91 status = aipc_invoke_sync_call(
92 ACE_BT_BLE_REGISTER_GATT_CLIENT_API, (void*)&manager_callbacks, manager_callbacks.size
93 );
94 if (status != ACE_STATUS_OK) {
95 log_error(
96 "[%s()]: failed to register gatt client callbacks with server! result: %d", __func__,
97 status
98 );
99 registerBTClientData(session_handle, CALLBACK_INDEX_BLE_GATT_CLIENT, NULL);
100 registerBTEvtHandler(
101 session_handle, NULL, ACE_BT_CALLBACK_GATTC_INIT, ACE_BT_CALLBACK_GATTC_MAX
102 );
103 }
104
105 return status;
106}
107
108status_t pre5170_bleDeregisterGattClient(sessionHandle session_handle) {
109 status_t status;
110 gatt_request_unreg_t unregister;
111
112 status = getSessionInfo(session_handle, &unregister.h1);
113 if (status != ACE_STATUS_OK) {
114 log_error("[%s()]: Couldn't get session info. Result %d", __func__, status);
115 return ACE_STATUS_BAD_PARAM;
116 }
117
118 dump_aipc_handle(unregister.h1);
119
120 unregister.h2 = unregister.h1;
121 unregister.size = sizeof(unregister);
122
123 status =
124 aipc_invoke_sync_call(ACE_BT_BLE_UNREGISTER_GATT_CLIENT_API, &unregister, unregister.size);
125 if (status != ACE_STATUS_OK) {
126 log_error("[%s()]: Failed to send AIPC call %d", __func__, status);
127 }
128
129 return status;
130}
131
132status_t pre5170_bleDiscoverAllServices(sessionHandle session_handle, bleConnHandle conn_handle) {
133 log_debug("Called into pre 5.17 %s", __func__);
134
135 status_t status;
136 request_disc_all_svc_t data;
137
138 serialize_gattc_disc_all_svc(&data, (uint32_t)conn_handle);
139 status = aipc_invoke_sync_call(ACE_BT_BLE_GATT_CLIENT_DISC_ALL_SVC_API, &data, data.size);
140 if (status != ACE_STATUS_OK) {
141 log_error("[%s()]: Failed to send AIPC call. Status: %d", __func__, status);
142 }
143 return data.out_status;
144}
145
146status_t pre5170_bleGetService(bleConnHandle conn_handle) {
147 log_debug("Called into pre 5.17 %s", __func__);
148
149 status_t status;
150 gattc_get_db_data_t data;
151
152 serialize_ble_get_db_req(&data, (uint32_t)conn_handle, NULL);
153 dump_gattc_get_db_data_t(&data);
154
155 status = aipc_invoke_sync_call(ACE_BT_BLE_GATT_CLIENT_GET_SERVICE_API, &data, data.size);
156 if (status != ACE_STATUS_OK) {
157 log_error("[%s()]: Failed to send AIPC call. Status: %d", __func__, status);
158 }
159 return status;
160}
161
162status_t pre5170_bleReadCharacteristic(
163 sessionHandle session_handle, bleConnHandle conn_handle,
165) {
166 log_debug("Called into pre 5.17 %s", __func__);
167
168 status_t status;
169 aipcHandles_t handle;
170
171 status = getSessionInfo(session_handle, &handle);
172 if (status != ACE_STATUS_OK) {
173 log_error("[%s()]: Couldn't get session info. Result: %d", __func__, status);
174 return ACE_STATUS_BAD_PARAM;
175 }
176
177 acebt_gattc_read_chars_req_data_t data;
178 serialize_gattc_read_chars_req(&data, (uint32_t)conn_handle, chars_value);
179 log_debug("[%s()]: Serialize request, status: %d", __func__, data.status);
180
181 status = aipc_invoke_sync_call(ACE_BT_BLE_GATT_CLIENT_READ_CHARS_API, &data, data.size);
182 if (status != ACE_STATUS_OK) {
183 log_error("[%s()]: Failed to send AIPC call. Status: %d", __func__, status);
184 }
185 return status;
186}
187
188status_t pre5170_bleWriteCharacteristics(
189 sessionHandle session_handle, bleConnHandle conn_handle,
190 bleGattCharacteristicsValue_t* chars_value, responseType_t request_type
191) {
192 log_debug("Called into pre 5.17 %s", __func__);
193
194 status_t status;
195 aipcHandles_t handle;
196
197 status = getSessionInfo(session_handle, &handle);
198 if (status != ACE_STATUS_OK) {
199 log_error("[%s()]: Couldn't get session info. Result: %d", __func__, status);
200 return ACE_STATUS_BAD_PARAM;
201 }
202
203 uint8_t* out_data;
204 uint32_t out_len;
205
206 serialize_gattc_write_char_req(
207 (uint32_t)conn_handle, chars_value, &out_data, &out_len, request_type
208 );
209
210 if (out_data == NULL) {
211 log_error("[%s()]: Failed serialize_gattc_write_char_req", __func__);
212 return ACE_STATUS_GENERAL_ERROR;
213 }
214
215 status = aipc_invoke_sync_call(ACE_BT_BLE_GATT_CLIENT_WRITE_CHARS_API, out_data, out_len);
216 if (status != ACE_STATUS_OK) {
217 log_error("[%s()]: Failed to send AIPC call. Status: %d", __func__, status);
218 return status;
219 }
220
221 shadow_aceAlloc_free(out_data);
222
223 return status;
224}
225
226status_t pre5170_bleWriteDescriptor(
227 sessionHandle session_handle, bleConnHandle conn_handle,
228 bleGattCharacteristicsValue_t* chars_value, responseType_t request_type
229) {
230 log_debug("Called into pre 5.17 %s", __func__);
231
232 status_t status;
233 aipcHandles_t handle;
234
235 status = getSessionInfo(session_handle, &handle);
236 if (status != ACE_STATUS_OK) {
237 log_error("[%s()]: Couldn't get session info. Result: %d", __func__, status);
238 return ACE_STATUS_BAD_PARAM;
239 }
240
241 uint8_t* out_data;
242 uint32_t out_len;
243
244 serialize_gattc_write_desc_req(
245 (uint32_t)conn_handle, &chars_value->gattDescriptor, &out_data, &out_len, request_type
246 );
247 if (out_data == NULL) {
248 log_error("[%s()]: serialize_gattc_write_desc_req() failed", __func__);
249 return ACE_STATUS_GENERAL_ERROR;
250 }
251
252 status = aipc_invoke_sync_call(ACE_BT_BLE_GATT_CLIENT_WRITE_DESC_API, out_data, out_len);
253 if (status == ACE_STATUS_OK) {
254 status = ((const gattc_write_desc_data_t*)out_data)->status;
255 } else {
256 log_error("[%s()]: Failed to send AIPC call. Status: %d", __func__, status);
257 status = ACE_STATUS_BAD_PARAM;
258 }
259
260 shadow_aceAlloc_free(out_data);
261
262 return status;
263}
264
265status_t pre5170_bleSetNotification(
266 sessionHandle session_handle, bleConnHandle conn_handle,
267 bleGattCharacteristicsValue_t chars_value, bool enable
268) {
269 log_debug("Called into pre 5.17 %s", __func__);
270
271 status_t status;
272 aipcHandles_t handle;
273
274 status = getSessionInfo(session_handle, &handle);
275 if (status != ACE_STATUS_OK) {
276 log_error("[%s()]: Couldn't get session info. Result: %d", __func__, status);
277 return ACE_STATUS_BAD_PARAM;
278 }
279
280 gattc_set_notify_data_t data;
281 serialize_ble_set_notify(&data, (uint32_t)conn_handle, chars_value, enable);
282
283 status = aipc_invoke_sync_call(ACE_BT_BLE_GATT_CLIENT_SET_NOTIFY_API, &data, data.size);
284 if (status != ACE_STATUS_OK) {
285 log_error("[%s()]: Failed to send AIPC call. Status: %d", __func__, status);
286 return status;
287 }
288
289 struct aceBT_gattDescRec_t* desc_rec = NULL;
290 STAILQ_FOREACH(desc_rec, &chars_value.descList, link) {
291 if (desc_rec->value.is_set && desc_rec->value.is_notify) break;
292 }
293
294 if (desc_rec == NULL) {
295 log_error(
296 "[%s()]: Couldn't find CCCD descriptor. Are you sure this characteristic supports "
297 "notifications?",
298 __func__
299 );
300 return ACE_STATUS_BAD_PARAM;
301 }
302
303 // Store our enable/disable option as little endian directly
304 uint8_t subscription[2];
305 uint16_t le = htole16((uint16_t)enable);
306 memcpy(subscription, &le, sizeof(le));
307
308 // Set the linked list find as the main gattDescriptor for calls to WriteDescriptor
309 chars_value.gattDescriptor.gattRecord.handle = desc_rec->value.gattRecord.handle;
310 chars_value.gattDescriptor.blobValue.data = malloc(sizeof(subscription));
311 if (chars_value.gattDescriptor.blobValue.data == NULL) {
312 log_error("[%s()]: Couldn't allocate memory for CCCD descriptor?", __func__);
313 return ACE_STATUS_OUT_OF_MEMORY;
314 }
315 chars_value.gattDescriptor.blobValue.offset = 0;
316 chars_value.gattDescriptor.blobValue.size = sizeof(subscription);
317 memcpy(chars_value.gattDescriptor.blobValue.data, subscription, sizeof(subscription));
318
319 status = shim_bleWriteDescriptor(
320 session_handle, conn_handle, &chars_value, ACEBT_BLE_WRITE_TYPE_RESP_REQUIRED
321 );
322
323 return status;
324}
aceBT_bleGattClientCallbacks_t bleGattClientCallbacks_t
Callback struct of GATT Client Bluetooth operations.
aceBt_bleAppId_t bleAppId_t
BLE application type.
aceBT_responseType_t responseType_t
Type of write operation for a BLE characteristic.
ace_status_t status_t
Bluetooth API status codes.
aceBT_bleConnHandle bleConnHandle
Connection handle for the lifetime of a Bluetooth connection.
aceBT_sessionHandle sessionHandle
Session handle for the lifetime of the Bluetooth application.
aceBT_bleGattCharacteristicsValue_t bleGattCharacteristicsValue_t
BLE GATT Characteristic.