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_bleCleanupGattService(bleGattsService_t* service, int no_svc) {
163 log_debug("Called into pre 5.17 %s", __func__);
164
165 cleanup_all_service(service, no_svc);
166 return ACE_STATUS_OK;
167}
168
169status_t pre5170_bleReadCharacteristic(
170 sessionHandle session_handle, bleConnHandle conn_handle,
172) {
173 log_debug("Called into pre 5.17 %s", __func__);
174
175 status_t status;
176 aipcHandles_t handle;
177
178 status = getSessionInfo(session_handle, &handle);
179 if (status != ACE_STATUS_OK) {
180 log_error("[%s()]: Couldn't get session info. Result: %d", __func__, status);
181 return ACE_STATUS_BAD_PARAM;
182 }
183
184 acebt_gattc_read_chars_req_data_t data;
185 serialize_gattc_read_chars_req(&data, (uint32_t)conn_handle, chars_value);
186 log_debug("[%s()]: Serialize request, status: %d", __func__, data.status);
187
188 status = aipc_invoke_sync_call(ACE_BT_BLE_GATT_CLIENT_READ_CHARS_API, &data, data.size);
189 if (status != ACE_STATUS_OK) {
190 log_error("[%s()]: Failed to send AIPC call. Status: %d", __func__, status);
191 }
192 return status;
193}
194
195status_t pre5170_bleWriteCharacteristics(
196 sessionHandle session_handle, bleConnHandle conn_handle,
197 bleGattCharacteristicsValue_t* chars_value, responseType_t request_type
198) {
199 log_debug("Called into pre 5.17 %s", __func__);
200
201 status_t status;
202 aipcHandles_t handle;
203
204 status = getSessionInfo(session_handle, &handle);
205 if (status != ACE_STATUS_OK) {
206 log_error("[%s()]: Couldn't get session info. Result: %d", __func__, status);
207 return ACE_STATUS_BAD_PARAM;
208 }
209
210 uint8_t* out_data;
211 uint32_t out_len;
212
213 serialize_gattc_write_char_req(
214 (uint32_t)conn_handle, chars_value, &out_data, &out_len, request_type
215 );
216
217 if (out_data == NULL) {
218 log_error("[%s()]: Failed serialize_gattc_write_char_req", __func__);
219 return ACE_STATUS_GENERAL_ERROR;
220 }
221
222 status = aipc_invoke_sync_call(ACE_BT_BLE_GATT_CLIENT_WRITE_CHARS_API, out_data, out_len);
223 if (status != ACE_STATUS_OK) {
224 log_error("[%s()]: Failed to send AIPC call. Status: %d", __func__, status);
225 return status;
226 }
227
228 shadow_aceAlloc_free(out_data);
229
230 return status;
231}
232
233status_t pre5170_bleWriteDescriptor(
234 sessionHandle session_handle, bleConnHandle conn_handle,
235 bleGattCharacteristicsValue_t* chars_value, responseType_t request_type
236) {
237 log_debug("Called into pre 5.17 %s", __func__);
238
239 status_t status;
240 aipcHandles_t handle;
241
242 status = getSessionInfo(session_handle, &handle);
243 if (status != ACE_STATUS_OK) {
244 log_error("[%s()]: Couldn't get session info. Result: %d", __func__, status);
245 return ACE_STATUS_BAD_PARAM;
246 }
247
248 uint8_t* out_data;
249 uint32_t out_len;
250
251 serialize_gattc_write_desc_req(
252 (uint32_t)conn_handle, &chars_value->gattDescriptor, &out_data, &out_len, request_type
253 );
254 if (out_data == NULL) {
255 log_error("[%s()]: serialize_gattc_write_desc_req() failed", __func__);
256 return ACE_STATUS_GENERAL_ERROR;
257 }
258
259 status = aipc_invoke_sync_call(ACE_BT_BLE_GATT_CLIENT_WRITE_DESC_API, out_data, out_len);
260 if (status == ACE_STATUS_OK) {
261 status = ((const gattc_write_desc_data_t*)out_data)->status;
262 } else {
263 log_error("[%s()]: Failed to send AIPC call. Status: %d", __func__, status);
264 status = ACE_STATUS_BAD_PARAM;
265 }
266
267 shadow_aceAlloc_free(out_data);
268
269 return status;
270}
271
272status_t pre5170_bleSetNotification(
273 sessionHandle session_handle, bleConnHandle conn_handle,
274 bleGattCharacteristicsValue_t chars_value, bool enable
275) {
276 log_debug("Called into pre 5.17 %s", __func__);
277
278 status_t status;
279 aipcHandles_t handle;
280
281 status = getSessionInfo(session_handle, &handle);
282 if (status != ACE_STATUS_OK) {
283 log_error("[%s()]: Couldn't get session info. Result: %d", __func__, status);
284 return ACE_STATUS_BAD_PARAM;
285 }
286
287 gattc_set_notify_data_t data;
288 serialize_ble_set_notify(&data, (uint32_t)conn_handle, chars_value, enable);
289
290 status = aipc_invoke_sync_call(ACE_BT_BLE_GATT_CLIENT_SET_NOTIFY_API, &data, data.size);
291 if (status != ACE_STATUS_OK) {
292 log_error("[%s()]: Failed to send AIPC call. Status: %d", __func__, status);
293 return status;
294 }
295
296 struct aceBT_gattDescRec_t* desc_rec = NULL;
297 STAILQ_FOREACH(desc_rec, &chars_value.descList, link) {
298 if (desc_rec->value.is_set && desc_rec->value.is_notify) break;
299 }
300
301 if (desc_rec == NULL) {
302 log_error(
303 "[%s()]: Couldn't find CCCD descriptor. Are you sure this characteristic supports "
304 "notifications?",
305 __func__
306 );
307 return ACE_STATUS_BAD_PARAM;
308 }
309
310 // Store our enable/disable option as little endian directly
311 uint8_t subscription[2];
312 uint16_t le = htole16((uint16_t)enable);
313 memcpy(subscription, &le, sizeof(le));
314
315 // Set the linked list find as the main gattDescriptor for calls to WriteDescriptor
316 chars_value.gattDescriptor.gattRecord.handle = desc_rec->value.gattRecord.handle;
317 chars_value.gattDescriptor.blobValue.data = malloc(sizeof(subscription));
318 if (chars_value.gattDescriptor.blobValue.data == NULL) {
319 log_error("[%s()]: Couldn't allocate memory for CCCD descriptor?", __func__);
320 return ACE_STATUS_OUT_OF_MEMORY;
321 }
322 chars_value.gattDescriptor.blobValue.offset = 0;
323 chars_value.gattDescriptor.blobValue.size = sizeof(subscription);
324 memcpy(chars_value.gattDescriptor.blobValue.data, subscription, sizeof(subscription));
325
326 status = shim_bleWriteDescriptor(
327 session_handle, conn_handle, &chars_value, ACEBT_BLE_WRITE_TYPE_RESP_REQUIRED
328 );
329
330 return status;
331}
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_bleGattsService_t bleGattsService_t
Structure for a GATT Server service.
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.