1*daa5f023SMatthias Ringwald /*
2*daa5f023SMatthias Ringwald * Copyright (C) 2024 BlueKitchen GmbH
3*daa5f023SMatthias Ringwald *
4*daa5f023SMatthias Ringwald * Redistribution and use in source and binary forms, with or without
5*daa5f023SMatthias Ringwald * modification, are permitted provided that the following conditions
6*daa5f023SMatthias Ringwald * are met:
7*daa5f023SMatthias Ringwald *
8*daa5f023SMatthias Ringwald * 1. Redistributions of source code must retain the above copyright
9*daa5f023SMatthias Ringwald * notice, this list of conditions and the following disclaimer.
10*daa5f023SMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright
11*daa5f023SMatthias Ringwald * notice, this list of conditions and the following disclaimer in the
12*daa5f023SMatthias Ringwald * documentation and/or other materials provided with the distribution.
13*daa5f023SMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of
14*daa5f023SMatthias Ringwald * contributors may be used to endorse or promote products derived
15*daa5f023SMatthias Ringwald * from this software without specific prior written permission.
16*daa5f023SMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for
17*daa5f023SMatthias Ringwald * personal benefit and not for any commercial purpose or for
18*daa5f023SMatthias Ringwald * monetary gain.
19*daa5f023SMatthias Ringwald *
20*daa5f023SMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21*daa5f023SMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22*daa5f023SMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23*daa5f023SMatthias Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
24*daa5f023SMatthias Ringwald * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25*daa5f023SMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26*daa5f023SMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27*daa5f023SMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28*daa5f023SMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29*daa5f023SMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30*daa5f023SMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31*daa5f023SMatthias Ringwald * SUCH DAMAGE.
32*daa5f023SMatthias Ringwald *
33*daa5f023SMatthias Ringwald * Please inquire about commercial licensing options at
34*daa5f023SMatthias Ringwald * [email protected]
35*daa5f023SMatthias Ringwald *
36*daa5f023SMatthias Ringwald */
37*daa5f023SMatthias Ringwald
38*daa5f023SMatthias Ringwald #define BTSTACK_FILE__ "link_loss_service_client.c"
39*daa5f023SMatthias Ringwald
40*daa5f023SMatthias Ringwald #include "btstack_config.h"
41*daa5f023SMatthias Ringwald
42*daa5f023SMatthias Ringwald #ifdef ENABLE_TESTING_SUPPORT
43*daa5f023SMatthias Ringwald #include <stdio.h>
44*daa5f023SMatthias Ringwald #include <unistd.h>
45*daa5f023SMatthias Ringwald #endif
46*daa5f023SMatthias Ringwald
47*daa5f023SMatthias Ringwald #include <stdint.h>
48*daa5f023SMatthias Ringwald #include <string.h>
49*daa5f023SMatthias Ringwald
50*daa5f023SMatthias Ringwald #include "ble/gatt_service_client.h"
51*daa5f023SMatthias Ringwald #include "ble/gatt-service/link_loss_service_client.h"
52*daa5f023SMatthias Ringwald
53*daa5f023SMatthias Ringwald #include "bluetooth_gatt.h"
54*daa5f023SMatthias Ringwald #include "btstack_debug.h"
55*daa5f023SMatthias Ringwald #include "btstack_event.h"
56*daa5f023SMatthias Ringwald
57*daa5f023SMatthias Ringwald // LLS Client
58*daa5f023SMatthias Ringwald static gatt_service_client_t lls_client;
59*daa5f023SMatthias Ringwald static btstack_linked_list_t lls_connections;
60*daa5f023SMatthias Ringwald
61*daa5f023SMatthias Ringwald static btstack_context_callback_registration_t lls_client_handle_can_send_now;
62*daa5f023SMatthias Ringwald
63*daa5f023SMatthias Ringwald static void lls_client_packet_handler_internal(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
64*daa5f023SMatthias Ringwald static void lls_client_handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
65*daa5f023SMatthias Ringwald static void lls_client_run_for_connection(void * context);
66*daa5f023SMatthias Ringwald
67*daa5f023SMatthias Ringwald // list of uuids
68*daa5f023SMatthias Ringwald static const uint16_t lls_uuid16s[LINK_LOSS_SERVICE_CLIENT_NUM_CHARACTERISTICS] = {
69*daa5f023SMatthias Ringwald ORG_BLUETOOTH_CHARACTERISTIC_ALERT_LEVEL
70*daa5f023SMatthias Ringwald };
71*daa5f023SMatthias Ringwald
72*daa5f023SMatthias Ringwald typedef enum {
73*daa5f023SMatthias Ringwald LLS_CLIENT_CHARACTERISTIC_INDEX_ALERT_LEVEL = 0,
74*daa5f023SMatthias Ringwald LLS_CLIENT_CHARACTERISTIC_INDEX_RFU
75*daa5f023SMatthias Ringwald } lls_client_characteristic_index_t;
76*daa5f023SMatthias Ringwald
77*daa5f023SMatthias Ringwald #ifdef ENABLE_TESTING_SUPPORT
78*daa5f023SMatthias Ringwald static char * lls_client_characteristic_name[] = {
79*daa5f023SMatthias Ringwald "ALERT_LEVEL",
80*daa5f023SMatthias Ringwald "RFU"
81*daa5f023SMatthias Ringwald };
82*daa5f023SMatthias Ringwald #endif
83*daa5f023SMatthias Ringwald
lls_client_get_connection_for_cid(uint16_t connection_cid)84*daa5f023SMatthias Ringwald static lls_client_connection_t * lls_client_get_connection_for_cid(uint16_t connection_cid){
85*daa5f023SMatthias Ringwald btstack_linked_list_iterator_t it;
86*daa5f023SMatthias Ringwald btstack_linked_list_iterator_init(&it, &lls_connections);
87*daa5f023SMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)){
88*daa5f023SMatthias Ringwald lls_client_connection_t * connection = (lls_client_connection_t *)btstack_linked_list_iterator_next(&it);
89*daa5f023SMatthias Ringwald if (gatt_service_client_get_connection_id(&connection->basic_connection) == connection_cid) {
90*daa5f023SMatthias Ringwald return connection;
91*daa5f023SMatthias Ringwald }
92*daa5f023SMatthias Ringwald }
93*daa5f023SMatthias Ringwald return NULL;
94*daa5f023SMatthias Ringwald }
95*daa5f023SMatthias Ringwald
lls_client_add_connection(lls_client_connection_t * connection)96*daa5f023SMatthias Ringwald static void lls_client_add_connection(lls_client_connection_t * connection){
97*daa5f023SMatthias Ringwald btstack_linked_list_add(&lls_connections, (btstack_linked_item_t*) connection);
98*daa5f023SMatthias Ringwald }
99*daa5f023SMatthias Ringwald
lls_client_finalize_connection(lls_client_connection_t * connection)100*daa5f023SMatthias Ringwald static void lls_client_finalize_connection(lls_client_connection_t * connection){
101*daa5f023SMatthias Ringwald btstack_linked_list_remove(&lls_connections, (btstack_linked_item_t*) connection);
102*daa5f023SMatthias Ringwald }
103*daa5f023SMatthias Ringwald
lls_client_replace_subevent_id_and_emit(btstack_packet_handler_t callback,uint8_t * packet,uint16_t size,uint8_t subevent_id)104*daa5f023SMatthias Ringwald static void lls_client_replace_subevent_id_and_emit(btstack_packet_handler_t callback, uint8_t * packet, uint16_t size, uint8_t subevent_id){
105*daa5f023SMatthias Ringwald UNUSED(size);
106*daa5f023SMatthias Ringwald btstack_assert(callback != NULL);
107*daa5f023SMatthias Ringwald // execute callback
108*daa5f023SMatthias Ringwald packet[2] = subevent_id;
109*daa5f023SMatthias Ringwald (*callback)(HCI_EVENT_PACKET, 0, packet, size);
110*daa5f023SMatthias Ringwald }
111*daa5f023SMatthias Ringwald
lls_client_connected(lls_client_connection_t * connection,uint8_t status,uint8_t * packet,uint16_t size)112*daa5f023SMatthias Ringwald static void lls_client_connected(lls_client_connection_t * connection, uint8_t status, uint8_t * packet, uint16_t size) {
113*daa5f023SMatthias Ringwald if (status == ERROR_CODE_SUCCESS){
114*daa5f023SMatthias Ringwald connection->state = LINK_LOSS_SERVICE_CLIENT_STATE_READY;
115*daa5f023SMatthias Ringwald } else {
116*daa5f023SMatthias Ringwald connection->state = LINK_LOSS_SERVICE_CLIENT_STATE_IDLE;
117*daa5f023SMatthias Ringwald }
118*daa5f023SMatthias Ringwald lls_client_replace_subevent_id_and_emit(connection->packet_handler, packet, size,
119*daa5f023SMatthias Ringwald GATTSERVICE_SUBEVENT_LLS_CLIENT_CONNECTED);
120*daa5f023SMatthias Ringwald }
121*daa5f023SMatthias Ringwald
lls_client_emit_uint8(uint16_t cid,btstack_packet_handler_t event_callback,uint8_t subevent,const uint8_t * data,uint16_t data_size)122*daa5f023SMatthias Ringwald static void lls_client_emit_uint8(uint16_t cid, btstack_packet_handler_t event_callback, uint8_t subevent, const uint8_t * data, uint16_t data_size){
123*daa5f023SMatthias Ringwald UNUSED(data_size);
124*daa5f023SMatthias Ringwald btstack_assert(event_callback != NULL);
125*daa5f023SMatthias Ringwald
126*daa5f023SMatthias Ringwald if (data_size != 1){
127*daa5f023SMatthias Ringwald return;
128*daa5f023SMatthias Ringwald }
129*daa5f023SMatthias Ringwald
130*daa5f023SMatthias Ringwald uint8_t event[6];
131*daa5f023SMatthias Ringwald uint16_t pos = 0;
132*daa5f023SMatthias Ringwald event[pos++] = HCI_EVENT_GATTSERVICE_META;
133*daa5f023SMatthias Ringwald event[pos++] = 4;
134*daa5f023SMatthias Ringwald event[pos++] = subevent;
135*daa5f023SMatthias Ringwald little_endian_store_16(event, pos, cid);
136*daa5f023SMatthias Ringwald pos+= 2;
137*daa5f023SMatthias Ringwald event[pos++] = data[0];
138*daa5f023SMatthias Ringwald
139*daa5f023SMatthias Ringwald (*event_callback)(HCI_EVENT_PACKET, 0, event, pos);
140*daa5f023SMatthias Ringwald }
141*daa5f023SMatthias Ringwald
142*daa5f023SMatthias Ringwald
lls_client_value_handle_for_index(lls_client_connection_t * connection)143*daa5f023SMatthias Ringwald static uint16_t lls_client_value_handle_for_index(lls_client_connection_t * connection){
144*daa5f023SMatthias Ringwald return connection->basic_connection.characteristics[connection->characteristic_index].value_handle;
145*daa5f023SMatthias Ringwald }
146*daa5f023SMatthias Ringwald
lls_client_emit_done_event(lls_client_connection_t * connection,uint8_t index,uint8_t status)147*daa5f023SMatthias Ringwald static void lls_client_emit_done_event(lls_client_connection_t * connection, uint8_t index, uint8_t status){
148*daa5f023SMatthias Ringwald btstack_assert(connection->packet_handler != NULL);
149*daa5f023SMatthias Ringwald
150*daa5f023SMatthias Ringwald uint16_t cid = connection->basic_connection.cid;
151*daa5f023SMatthias Ringwald uint16_t characteristic_uuid16 = gatt_service_client_characteristic_uuid16_for_index(&lls_client, index);
152*daa5f023SMatthias Ringwald
153*daa5f023SMatthias Ringwald uint8_t event[8];
154*daa5f023SMatthias Ringwald uint16_t pos = 0;
155*daa5f023SMatthias Ringwald event[pos++] = HCI_EVENT_GATTSERVICE_META;
156*daa5f023SMatthias Ringwald event[pos++] = sizeof(event) - 2;
157*daa5f023SMatthias Ringwald event[pos++] = GATTSERVICE_SUBEVENT_LLS_CLIENT_WRITE_DONE;
158*daa5f023SMatthias Ringwald
159*daa5f023SMatthias Ringwald little_endian_store_16(event, pos, cid);
160*daa5f023SMatthias Ringwald pos+= 2;
161*daa5f023SMatthias Ringwald little_endian_store_16(event, pos, characteristic_uuid16);
162*daa5f023SMatthias Ringwald pos+= 2;
163*daa5f023SMatthias Ringwald event[pos++] = status;
164*daa5f023SMatthias Ringwald (*connection->packet_handler)(HCI_EVENT_PACKET, 0, event, pos);
165*daa5f023SMatthias Ringwald }
166*daa5f023SMatthias Ringwald
167*daa5f023SMatthias Ringwald
lls_client_emit_read_event(lls_client_connection_t * connection,uint8_t index,uint8_t status,const uint8_t * data,uint16_t data_size)168*daa5f023SMatthias Ringwald static void lls_client_emit_read_event(lls_client_connection_t * connection, uint8_t index, uint8_t status, const uint8_t * data, uint16_t data_size){
169*daa5f023SMatthias Ringwald UNUSED(status);
170*daa5f023SMatthias Ringwald
171*daa5f023SMatthias Ringwald if ((data_size > 0) && (data == NULL)){
172*daa5f023SMatthias Ringwald return;
173*daa5f023SMatthias Ringwald }
174*daa5f023SMatthias Ringwald
175*daa5f023SMatthias Ringwald uint16_t characteristic_uuid16 = gatt_service_client_characteristic_uuid16_for_index(&lls_client, index);
176*daa5f023SMatthias Ringwald switch (characteristic_uuid16){
177*daa5f023SMatthias Ringwald case ORG_BLUETOOTH_CHARACTERISTIC_ALERT_LEVEL:
178*daa5f023SMatthias Ringwald lls_client_emit_uint8(connection->basic_connection.cid, connection->packet_handler, GATTSERVICE_SUBEVENT_LLS_CLIENT_ALERT_LEVEL, data, data_size);
179*daa5f023SMatthias Ringwald break;
180*daa5f023SMatthias Ringwald default:
181*daa5f023SMatthias Ringwald btstack_assert(false);
182*daa5f023SMatthias Ringwald break;
183*daa5f023SMatthias Ringwald }
184*daa5f023SMatthias Ringwald }
185*daa5f023SMatthias Ringwald
lls_client_can_query_characteristic(lls_client_connection_t * connection,lls_client_characteristic_index_t characteristic_index)186*daa5f023SMatthias Ringwald static uint8_t lls_client_can_query_characteristic(lls_client_connection_t * connection, lls_client_characteristic_index_t characteristic_index){
187*daa5f023SMatthias Ringwald uint8_t status = gatt_service_client_can_query_characteristic(&connection->basic_connection,
188*daa5f023SMatthias Ringwald (uint8_t) characteristic_index);
189*daa5f023SMatthias Ringwald if (status != ERROR_CODE_SUCCESS){
190*daa5f023SMatthias Ringwald return status;
191*daa5f023SMatthias Ringwald }
192*daa5f023SMatthias Ringwald return connection->state == LINK_LOSS_SERVICE_CLIENT_STATE_READY ? ERROR_CODE_SUCCESS : ERROR_CODE_CONTROLLER_BUSY;
193*daa5f023SMatthias Ringwald }
194*daa5f023SMatthias Ringwald
lls_client_request_send_gatt_query(lls_client_connection_t * connection,lls_client_characteristic_index_t characteristic_index)195*daa5f023SMatthias Ringwald static uint8_t lls_client_request_send_gatt_query(lls_client_connection_t * connection, lls_client_characteristic_index_t characteristic_index){
196*daa5f023SMatthias Ringwald connection->characteristic_index = characteristic_index;
197*daa5f023SMatthias Ringwald
198*daa5f023SMatthias Ringwald lls_client_handle_can_send_now.context = (void *)(uintptr_t)connection->basic_connection.cid;
199*daa5f023SMatthias Ringwald uint8_t status = gatt_client_request_to_send_gatt_query(&lls_client_handle_can_send_now, connection->basic_connection.con_handle);
200*daa5f023SMatthias Ringwald if (status != ERROR_CODE_SUCCESS){
201*daa5f023SMatthias Ringwald connection->state = LINK_LOSS_SERVICE_CLIENT_STATE_READY;
202*daa5f023SMatthias Ringwald }
203*daa5f023SMatthias Ringwald return status;
204*daa5f023SMatthias Ringwald }
205*daa5f023SMatthias Ringwald
lls_client_request_read_characteristic(uint16_t lls_cid,lls_client_characteristic_index_t characteristic_index)206*daa5f023SMatthias Ringwald static uint8_t lls_client_request_read_characteristic(uint16_t lls_cid, lls_client_characteristic_index_t characteristic_index){
207*daa5f023SMatthias Ringwald lls_client_connection_t * connection = lls_client_get_connection_for_cid(lls_cid);
208*daa5f023SMatthias Ringwald if (connection == NULL){
209*daa5f023SMatthias Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
210*daa5f023SMatthias Ringwald }
211*daa5f023SMatthias Ringwald uint8_t status = lls_client_can_query_characteristic(connection, characteristic_index);
212*daa5f023SMatthias Ringwald if (status != ERROR_CODE_SUCCESS){
213*daa5f023SMatthias Ringwald return status;
214*daa5f023SMatthias Ringwald }
215*daa5f023SMatthias Ringwald
216*daa5f023SMatthias Ringwald connection->state = LINK_LOSS_SERVICE_CLIENT_STATE_W2_READ_CHARACTERISTIC_VALUE;
217*daa5f023SMatthias Ringwald return lls_client_request_send_gatt_query(connection, characteristic_index);
218*daa5f023SMatthias Ringwald }
219*daa5f023SMatthias Ringwald
lls_client_request_write_characteristic(lls_client_connection_t * connection,lls_client_characteristic_index_t characteristic_index)220*daa5f023SMatthias Ringwald static uint8_t lls_client_request_write_characteristic(lls_client_connection_t * connection, lls_client_characteristic_index_t characteristic_index){
221*daa5f023SMatthias Ringwald connection->state = LINK_LOSS_SERVICE_CLIENT_STATE_W2_WRITE_CHARACTERISTIC_VALUE;
222*daa5f023SMatthias Ringwald return lls_client_request_send_gatt_query(connection, characteristic_index);
223*daa5f023SMatthias Ringwald }
224*daa5f023SMatthias Ringwald
lls_client_packet_handler_internal(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)225*daa5f023SMatthias Ringwald static void lls_client_packet_handler_internal(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
226*daa5f023SMatthias Ringwald UNUSED(channel);
227*daa5f023SMatthias Ringwald UNUSED(size);
228*daa5f023SMatthias Ringwald
229*daa5f023SMatthias Ringwald if (packet_type != HCI_EVENT_PACKET) return;
230*daa5f023SMatthias Ringwald lls_client_connection_t * connection;
231*daa5f023SMatthias Ringwald uint16_t cid;
232*daa5f023SMatthias Ringwald uint8_t status;
233*daa5f023SMatthias Ringwald
234*daa5f023SMatthias Ringwald switch(hci_event_packet_get_type(packet)){
235*daa5f023SMatthias Ringwald case HCI_EVENT_GATTSERVICE_META:
236*daa5f023SMatthias Ringwald switch (hci_event_gattservice_meta_get_subevent_code(packet)) {
237*daa5f023SMatthias Ringwald case GATTSERVICE_SUBEVENT_CLIENT_CONNECTED:
238*daa5f023SMatthias Ringwald cid = gattservice_subevent_client_connected_get_cid(packet);
239*daa5f023SMatthias Ringwald connection = lls_client_get_connection_for_cid(cid);
240*daa5f023SMatthias Ringwald btstack_assert(connection != NULL);
241*daa5f023SMatthias Ringwald
242*daa5f023SMatthias Ringwald #ifdef ENABLE_TESTING_SUPPORT
243*daa5f023SMatthias Ringwald {
244*daa5f023SMatthias Ringwald uint8_t i;
245*daa5f023SMatthias Ringwald for (i = LLS_CLIENT_CHARACTERISTIC_INDEX_ALERT_LEVEL;
246*daa5f023SMatthias Ringwald i < LLS_CLIENT_CHARACTERISTIC_INDEX_RFU; i++) {
247*daa5f023SMatthias Ringwald printf("0x%04X %s\n", connection->basic_connection.characteristics[i].value_handle,
248*daa5f023SMatthias Ringwald lls_client_characteristic_name[i]);
249*daa5f023SMatthias Ringwald }
250*daa5f023SMatthias Ringwald };
251*daa5f023SMatthias Ringwald #endif
252*daa5f023SMatthias Ringwald status = gattservice_subevent_client_connected_get_status(packet);
253*daa5f023SMatthias Ringwald lls_client_connected(connection, status, packet, size);
254*daa5f023SMatthias Ringwald break;
255*daa5f023SMatthias Ringwald
256*daa5f023SMatthias Ringwald case GATTSERVICE_SUBEVENT_CLIENT_DISCONNECTED:
257*daa5f023SMatthias Ringwald cid = gattservice_subevent_client_disconnected_get_cid(packet);
258*daa5f023SMatthias Ringwald connection = lls_client_get_connection_for_cid(cid);
259*daa5f023SMatthias Ringwald btstack_assert(connection != NULL);
260*daa5f023SMatthias Ringwald lls_client_finalize_connection(connection);
261*daa5f023SMatthias Ringwald lls_client_replace_subevent_id_and_emit(connection->packet_handler, packet, size,
262*daa5f023SMatthias Ringwald GATTSERVICE_SUBEVENT_LLS_CLIENT_DISCONNECTED);
263*daa5f023SMatthias Ringwald break;
264*daa5f023SMatthias Ringwald
265*daa5f023SMatthias Ringwald default:
266*daa5f023SMatthias Ringwald break;
267*daa5f023SMatthias Ringwald }
268*daa5f023SMatthias Ringwald break;
269*daa5f023SMatthias Ringwald
270*daa5f023SMatthias Ringwald default:
271*daa5f023SMatthias Ringwald break;
272*daa5f023SMatthias Ringwald }
273*daa5f023SMatthias Ringwald }
274*daa5f023SMatthias Ringwald
lls_client_handle_gatt_client_event(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)275*daa5f023SMatthias Ringwald static void lls_client_handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
276*daa5f023SMatthias Ringwald UNUSED(packet_type);
277*daa5f023SMatthias Ringwald UNUSED(channel);
278*daa5f023SMatthias Ringwald UNUSED(size);
279*daa5f023SMatthias Ringwald
280*daa5f023SMatthias Ringwald lls_client_connection_t * connection = NULL;
281*daa5f023SMatthias Ringwald uint16_t connection_id;
282*daa5f023SMatthias Ringwald
283*daa5f023SMatthias Ringwald switch(hci_event_packet_get_type(packet)){
284*daa5f023SMatthias Ringwald case GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT:
285*daa5f023SMatthias Ringwald connection_id = gatt_event_characteristic_value_query_result_get_connection_id(packet);
286*daa5f023SMatthias Ringwald connection = lls_client_get_connection_for_cid(connection_id);
287*daa5f023SMatthias Ringwald btstack_assert(connection != NULL);
288*daa5f023SMatthias Ringwald
289*daa5f023SMatthias Ringwald lls_client_emit_read_event(connection, connection->characteristic_index, ATT_ERROR_SUCCESS,
290*daa5f023SMatthias Ringwald gatt_event_characteristic_value_query_result_get_value(packet),
291*daa5f023SMatthias Ringwald gatt_event_characteristic_value_query_result_get_value_length(packet));
292*daa5f023SMatthias Ringwald
293*daa5f023SMatthias Ringwald connection->state = LINK_LOSS_SERVICE_CLIENT_STATE_READY;
294*daa5f023SMatthias Ringwald break;
295*daa5f023SMatthias Ringwald
296*daa5f023SMatthias Ringwald case GATT_EVENT_QUERY_COMPLETE:
297*daa5f023SMatthias Ringwald connection_id = gatt_event_query_complete_get_connection_id(packet);
298*daa5f023SMatthias Ringwald connection = lls_client_get_connection_for_cid(connection_id);
299*daa5f023SMatthias Ringwald btstack_assert(connection != NULL);
300*daa5f023SMatthias Ringwald
301*daa5f023SMatthias Ringwald connection->state = LINK_LOSS_SERVICE_CLIENT_STATE_READY;
302*daa5f023SMatthias Ringwald lls_client_emit_done_event(connection, connection->characteristic_index, gatt_event_query_complete_get_att_status(packet));
303*daa5f023SMatthias Ringwald break;
304*daa5f023SMatthias Ringwald
305*daa5f023SMatthias Ringwald default:
306*daa5f023SMatthias Ringwald break;
307*daa5f023SMatthias Ringwald }
308*daa5f023SMatthias Ringwald }
309*daa5f023SMatthias Ringwald
lls_client_serialize_characteristic_value_for_write(lls_client_connection_t * connection,uint8_t ** out_value)310*daa5f023SMatthias Ringwald static uint16_t lls_client_serialize_characteristic_value_for_write(lls_client_connection_t * connection, uint8_t ** out_value){
311*daa5f023SMatthias Ringwald uint16_t characteristic_uuid16 = gatt_service_client_characteristic_uuid16_for_index(&lls_client,
312*daa5f023SMatthias Ringwald connection->characteristic_index);
313*daa5f023SMatthias Ringwald *out_value = (uint8_t *)connection->write_buffer;
314*daa5f023SMatthias Ringwald
315*daa5f023SMatthias Ringwald switch (characteristic_uuid16){
316*daa5f023SMatthias Ringwald case ORG_BLUETOOTH_CHARACTERISTIC_ALERT_LEVEL:
317*daa5f023SMatthias Ringwald return 1;
318*daa5f023SMatthias Ringwald default:
319*daa5f023SMatthias Ringwald btstack_assert(false);
320*daa5f023SMatthias Ringwald break;
321*daa5f023SMatthias Ringwald }
322*daa5f023SMatthias Ringwald return 0;
323*daa5f023SMatthias Ringwald }
324*daa5f023SMatthias Ringwald
lls_client_run_for_connection(void * context)325*daa5f023SMatthias Ringwald static void lls_client_run_for_connection(void * context){
326*daa5f023SMatthias Ringwald uint16_t connection_id = (uint16_t)(uintptr_t)context;
327*daa5f023SMatthias Ringwald lls_client_connection_t * connection = lls_client_get_connection_for_cid(connection_id);
328*daa5f023SMatthias Ringwald
329*daa5f023SMatthias Ringwald btstack_assert(connection != NULL);
330*daa5f023SMatthias Ringwald uint16_t value_length;
331*daa5f023SMatthias Ringwald uint8_t * value;
332*daa5f023SMatthias Ringwald
333*daa5f023SMatthias Ringwald switch (connection->state){
334*daa5f023SMatthias Ringwald case LINK_LOSS_SERVICE_CLIENT_STATE_W2_READ_CHARACTERISTIC_VALUE:
335*daa5f023SMatthias Ringwald connection->state = LINK_LOSS_SERVICE_CLIENT_STATE_W4_READ_CHARACTERISTIC_VALUE_RESULT;
336*daa5f023SMatthias Ringwald
337*daa5f023SMatthias Ringwald (void) gatt_client_read_value_of_characteristic_using_value_handle_with_context(
338*daa5f023SMatthias Ringwald &lls_client_handle_gatt_client_event, connection->basic_connection.cid,
339*daa5f023SMatthias Ringwald lls_client_value_handle_for_index(connection), lls_client.service_id, connection->basic_connection.cid);
340*daa5f023SMatthias Ringwald break;
341*daa5f023SMatthias Ringwald
342*daa5f023SMatthias Ringwald case LINK_LOSS_SERVICE_CLIENT_STATE_W2_WRITE_CHARACTERISTIC_VALUE:
343*daa5f023SMatthias Ringwald connection->state = LINK_LOSS_SERVICE_CLIENT_STATE_W4_WRITE_CHARACTERISTIC_VALUE_RESULT;
344*daa5f023SMatthias Ringwald
345*daa5f023SMatthias Ringwald value_length = lls_client_serialize_characteristic_value_for_write(connection, &value);
346*daa5f023SMatthias Ringwald (void) gatt_client_write_value_of_characteristic_with_context(
347*daa5f023SMatthias Ringwald &lls_client_handle_gatt_client_event, connection->basic_connection.cid,
348*daa5f023SMatthias Ringwald lls_client_value_handle_for_index(connection),
349*daa5f023SMatthias Ringwald value_length, value, lls_client.service_id, connection->basic_connection.cid);
350*daa5f023SMatthias Ringwald
351*daa5f023SMatthias Ringwald break;
352*daa5f023SMatthias Ringwald
353*daa5f023SMatthias Ringwald default:
354*daa5f023SMatthias Ringwald break;
355*daa5f023SMatthias Ringwald }
356*daa5f023SMatthias Ringwald }
357*daa5f023SMatthias Ringwald
link_loss_service_client_init(void)358*daa5f023SMatthias Ringwald void link_loss_service_client_init(void){
359*daa5f023SMatthias Ringwald gatt_service_client_register_client(&lls_client, &lls_client_packet_handler_internal, lls_uuid16s, sizeof(lls_uuid16s)/sizeof(uint16_t));
360*daa5f023SMatthias Ringwald
361*daa5f023SMatthias Ringwald lls_client_handle_can_send_now.callback = &lls_client_run_for_connection;
362*daa5f023SMatthias Ringwald }
363*daa5f023SMatthias Ringwald
link_loss_service_client_connect(hci_con_handle_t con_handle,btstack_packet_handler_t packet_handler,lls_client_connection_t * lls_connection,gatt_service_client_characteristic_t * lls_storage_for_characteristics,uint8_t lls_characteristics_num,uint16_t * lls_cid)364*daa5f023SMatthias Ringwald uint8_t link_loss_service_client_connect(hci_con_handle_t con_handle,
365*daa5f023SMatthias Ringwald btstack_packet_handler_t packet_handler,
366*daa5f023SMatthias Ringwald lls_client_connection_t * lls_connection,
367*daa5f023SMatthias Ringwald gatt_service_client_characteristic_t * lls_storage_for_characteristics, uint8_t lls_characteristics_num,
368*daa5f023SMatthias Ringwald uint16_t * lls_cid
369*daa5f023SMatthias Ringwald ){
370*daa5f023SMatthias Ringwald
371*daa5f023SMatthias Ringwald btstack_assert(packet_handler != NULL);
372*daa5f023SMatthias Ringwald btstack_assert(lls_connection != NULL);
373*daa5f023SMatthias Ringwald btstack_assert(lls_characteristics_num == LINK_LOSS_SERVICE_CLIENT_NUM_CHARACTERISTICS);
374*daa5f023SMatthias Ringwald
375*daa5f023SMatthias Ringwald *lls_cid = 0;
376*daa5f023SMatthias Ringwald
377*daa5f023SMatthias Ringwald lls_connection->state = LINK_LOSS_SERVICE_CLIENT_STATE_W4_CONNECTION;
378*daa5f023SMatthias Ringwald lls_connection->packet_handler = packet_handler;
379*daa5f023SMatthias Ringwald
380*daa5f023SMatthias Ringwald uint8_t status = gatt_service_client_connect_primary_service_with_uuid16(con_handle,
381*daa5f023SMatthias Ringwald &lls_client,
382*daa5f023SMatthias Ringwald &lls_connection->basic_connection,
383*daa5f023SMatthias Ringwald ORG_BLUETOOTH_SERVICE_LINK_LOSS, 0,
384*daa5f023SMatthias Ringwald lls_storage_for_characteristics,
385*daa5f023SMatthias Ringwald lls_characteristics_num);
386*daa5f023SMatthias Ringwald
387*daa5f023SMatthias Ringwald if (status == ERROR_CODE_SUCCESS){
388*daa5f023SMatthias Ringwald lls_client_add_connection(lls_connection);
389*daa5f023SMatthias Ringwald *lls_cid = lls_connection->basic_connection.cid;
390*daa5f023SMatthias Ringwald }
391*daa5f023SMatthias Ringwald
392*daa5f023SMatthias Ringwald return status;
393*daa5f023SMatthias Ringwald }
394*daa5f023SMatthias Ringwald
link_loss_service_client_read_alert_level(uint16_t lls_cid)395*daa5f023SMatthias Ringwald uint8_t link_loss_service_client_read_alert_level(uint16_t lls_cid){
396*daa5f023SMatthias Ringwald return lls_client_request_read_characteristic(lls_cid, LLS_CLIENT_CHARACTERISTIC_INDEX_ALERT_LEVEL);
397*daa5f023SMatthias Ringwald }
398*daa5f023SMatthias Ringwald
link_loss_service_client_write_alert_level(uint16_t lls_cid,lls_alert_level_t alert_level)399*daa5f023SMatthias Ringwald uint8_t link_loss_service_client_write_alert_level(uint16_t lls_cid, lls_alert_level_t alert_level){
400*daa5f023SMatthias Ringwald lls_client_connection_t * connection = lls_client_get_connection_for_cid(lls_cid);
401*daa5f023SMatthias Ringwald if (connection == NULL){
402*daa5f023SMatthias Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
403*daa5f023SMatthias Ringwald }
404*daa5f023SMatthias Ringwald if (alert_level >= LLS_ALERT_LEVEL_RFU){
405*daa5f023SMatthias Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
406*daa5f023SMatthias Ringwald }
407*daa5f023SMatthias Ringwald
408*daa5f023SMatthias Ringwald lls_client_characteristic_index_t index = LLS_CLIENT_CHARACTERISTIC_INDEX_ALERT_LEVEL;
409*daa5f023SMatthias Ringwald
410*daa5f023SMatthias Ringwald uint8_t status = lls_client_can_query_characteristic(connection, index);
411*daa5f023SMatthias Ringwald if (status != ERROR_CODE_SUCCESS){
412*daa5f023SMatthias Ringwald return status;
413*daa5f023SMatthias Ringwald }
414*daa5f023SMatthias Ringwald
415*daa5f023SMatthias Ringwald connection->write_buffer[0] = (uint8_t)alert_level;
416*daa5f023SMatthias Ringwald return lls_client_request_write_characteristic(connection, index);
417*daa5f023SMatthias Ringwald }
418*daa5f023SMatthias Ringwald
link_loss_service_client_disconnect(uint16_t lls_cid)419*daa5f023SMatthias Ringwald uint8_t link_loss_service_client_disconnect(uint16_t lls_cid){
420*daa5f023SMatthias Ringwald lls_client_connection_t * connection = lls_client_get_connection_for_cid(lls_cid);
421*daa5f023SMatthias Ringwald if (connection == NULL){
422*daa5f023SMatthias Ringwald return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
423*daa5f023SMatthias Ringwald }
424*daa5f023SMatthias Ringwald return gatt_service_client_disconnect(&connection->basic_connection);
425*daa5f023SMatthias Ringwald }
426*daa5f023SMatthias Ringwald
link_loss_service_client_deinit(void)427*daa5f023SMatthias Ringwald void link_loss_service_client_deinit(void){
428*daa5f023SMatthias Ringwald gatt_service_client_unregister_client(&lls_client);
429*daa5f023SMatthias Ringwald }
430*daa5f023SMatthias Ringwald
431