xref: /btstack/src/ble/gatt-service/hids_client.c (revision cf26c8fbbf161f7e5ee9327de39264752c730a34)
1fc975d0eSMilanka Ringwald /*
2fc975d0eSMilanka Ringwald  * Copyright (C) 2021 BlueKitchen GmbH
3fc975d0eSMilanka Ringwald  *
4fc975d0eSMilanka Ringwald  * Redistribution and use in source and binary forms, with or without
5fc975d0eSMilanka Ringwald  * modification, are permitted provided that the following conditions
6fc975d0eSMilanka Ringwald  * are met:
7fc975d0eSMilanka Ringwald  *
8fc975d0eSMilanka Ringwald  * 1. Redistributions of source code must retain the above copyright
9fc975d0eSMilanka Ringwald  *    notice, this list of conditions and the following disclaimer.
10fc975d0eSMilanka Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
11fc975d0eSMilanka Ringwald  *    notice, this list of conditions and the following disclaimer in the
12fc975d0eSMilanka Ringwald  *    documentation and/or other materials provided with the distribution.
13fc975d0eSMilanka Ringwald  * 3. Neither the name of the copyright holders nor the names of
14fc975d0eSMilanka Ringwald  *    contributors may be used to endorse or promote products derived
15fc975d0eSMilanka Ringwald  *    from this software without specific prior written permission.
16fc975d0eSMilanka Ringwald  * 4. Any redistribution, use, or modification is done solely for
17fc975d0eSMilanka Ringwald  *    personal benefit and not for any commercial purpose or for
18fc975d0eSMilanka Ringwald  *    monetary gain.
19fc975d0eSMilanka Ringwald  *
20fc975d0eSMilanka Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21fc975d0eSMilanka Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22fc975d0eSMilanka Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23fc975d0eSMilanka Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
24fc975d0eSMilanka Ringwald  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25fc975d0eSMilanka Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26fc975d0eSMilanka Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27fc975d0eSMilanka Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28fc975d0eSMilanka Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29fc975d0eSMilanka Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30fc975d0eSMilanka Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31fc975d0eSMilanka Ringwald  * SUCH DAMAGE.
32fc975d0eSMilanka Ringwald  *
33fc975d0eSMilanka Ringwald  * Please inquire about commercial licensing options at
34fc975d0eSMilanka Ringwald  * [email protected]
35fc975d0eSMilanka Ringwald  *
36fc975d0eSMilanka Ringwald  */
37fc975d0eSMilanka Ringwald 
38fc975d0eSMilanka Ringwald #define BTSTACK_FILE__ "hids_client.c"
39fc975d0eSMilanka Ringwald 
40fc975d0eSMilanka Ringwald #include "btstack_config.h"
41fc975d0eSMilanka Ringwald 
42fc975d0eSMilanka Ringwald #include <stdint.h>
43fc975d0eSMilanka Ringwald #include <string.h>
44fc975d0eSMilanka Ringwald 
45*cf26c8fbSMilanka Ringwald #include "ble/gatt-service/hids_client.h"
46fc975d0eSMilanka Ringwald 
47*cf26c8fbSMilanka Ringwald #include "btstack_memory.h"
48fc975d0eSMilanka Ringwald #include "ble/att_db.h"
49fc975d0eSMilanka Ringwald #include "ble/core.h"
50fc975d0eSMilanka Ringwald #include "ble/gatt_client.h"
51fc975d0eSMilanka Ringwald #include "ble/sm.h"
52*cf26c8fbSMilanka Ringwald #include "bluetooth_gatt.h"
53fc975d0eSMilanka Ringwald #include "btstack_debug.h"
54fc975d0eSMilanka Ringwald #include "btstack_event.h"
55fc975d0eSMilanka Ringwald #include "btstack_run_loop.h"
56fc975d0eSMilanka Ringwald #include "gap.h"
57fc975d0eSMilanka Ringwald 
58*cf26c8fbSMilanka Ringwald static btstack_linked_list_t clients;
59*cf26c8fbSMilanka Ringwald static uint16_t hids_cid_counter = 0;
60fc975d0eSMilanka Ringwald 
61*cf26c8fbSMilanka Ringwald static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
62*cf26c8fbSMilanka Ringwald 
63*cf26c8fbSMilanka Ringwald static uint16_t hids_get_next_cid(void){
64*cf26c8fbSMilanka Ringwald     if (hids_cid_counter == 0xffff) {
65*cf26c8fbSMilanka Ringwald         hids_cid_counter = 1;
66*cf26c8fbSMilanka Ringwald     } else {
67*cf26c8fbSMilanka Ringwald         hids_cid_counter++;
68*cf26c8fbSMilanka Ringwald     }
69*cf26c8fbSMilanka Ringwald     return hids_cid_counter;
70fc975d0eSMilanka Ringwald }
71fc975d0eSMilanka Ringwald 
72*cf26c8fbSMilanka Ringwald static hids_client_t * hids_create_client(hci_con_handle_t con_handle, uint16_t cid){
73*cf26c8fbSMilanka Ringwald     hids_client_t * client = btstack_memory_hids_client_get();
74*cf26c8fbSMilanka Ringwald     if (!client){
75*cf26c8fbSMilanka Ringwald         log_error("Not enough memory to create client");
76*cf26c8fbSMilanka Ringwald         return NULL;
77*cf26c8fbSMilanka Ringwald     }
78*cf26c8fbSMilanka Ringwald     client->state = HIDS_CLIENT_STATE_IDLE;
79*cf26c8fbSMilanka Ringwald     client->cid = cid;
80*cf26c8fbSMilanka Ringwald     client->con_handle = con_handle;
81fc975d0eSMilanka Ringwald 
82*cf26c8fbSMilanka Ringwald     client->num_instances = 0;
83*cf26c8fbSMilanka Ringwald     btstack_linked_list_add(&clients, (btstack_linked_item_t *) client);
84*cf26c8fbSMilanka Ringwald     return client;
85fc975d0eSMilanka Ringwald }
86fc975d0eSMilanka Ringwald 
87*cf26c8fbSMilanka Ringwald static void hids_finalize_client(hids_client_t * client){
88*cf26c8fbSMilanka Ringwald     btstack_linked_list_remove(&clients, (btstack_linked_item_t *) client);
89*cf26c8fbSMilanka Ringwald     btstack_memory_hids_client_free(client);
90fc975d0eSMilanka Ringwald }
91*cf26c8fbSMilanka Ringwald 
92*cf26c8fbSMilanka Ringwald static hids_client_t * hids_get_client_for_con_handle(hci_con_handle_t con_handle){
93*cf26c8fbSMilanka Ringwald     btstack_linked_list_iterator_t it;
94*cf26c8fbSMilanka Ringwald     btstack_linked_list_iterator_init(&it, &clients);
95*cf26c8fbSMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
96*cf26c8fbSMilanka Ringwald         hids_client_t * client = (hids_client_t *)btstack_linked_list_iterator_next(&it);
97*cf26c8fbSMilanka Ringwald         if (client->con_handle != con_handle) continue;
98*cf26c8fbSMilanka Ringwald         return client;
99*cf26c8fbSMilanka Ringwald     }
100*cf26c8fbSMilanka Ringwald     return NULL;
101*cf26c8fbSMilanka Ringwald }
102*cf26c8fbSMilanka Ringwald 
103*cf26c8fbSMilanka Ringwald static hids_client_t * hids_get_client_for_cid(uint16_t hids_cid){
104*cf26c8fbSMilanka Ringwald     btstack_linked_list_iterator_t it;
105*cf26c8fbSMilanka Ringwald     btstack_linked_list_iterator_init(&it, &clients);
106*cf26c8fbSMilanka Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
107*cf26c8fbSMilanka Ringwald         hids_client_t * client = (hids_client_t *)btstack_linked_list_iterator_next(&it);
108*cf26c8fbSMilanka Ringwald         if (client->cid != hids_cid) continue;
109*cf26c8fbSMilanka Ringwald         return client;
110*cf26c8fbSMilanka Ringwald     }
111*cf26c8fbSMilanka Ringwald     return NULL;
112*cf26c8fbSMilanka Ringwald }
113*cf26c8fbSMilanka Ringwald 
114*cf26c8fbSMilanka Ringwald static void hids_emit_connection_established(hids_client_t * client, uint8_t status){
115*cf26c8fbSMilanka Ringwald     uint8_t event[7];
116*cf26c8fbSMilanka Ringwald     int pos = 0;
117*cf26c8fbSMilanka Ringwald     event[pos++] = HCI_EVENT_GATTSERVICE_META;
118*cf26c8fbSMilanka Ringwald     event[pos++] = sizeof(event) - 2;
119*cf26c8fbSMilanka Ringwald     event[pos++] = GATTSERVICE_SUBEVENT_HID_SERVICE_CONNECTED;
120*cf26c8fbSMilanka Ringwald     little_endian_store_16(event, pos, client->cid);
121*cf26c8fbSMilanka Ringwald     pos += 2;
122*cf26c8fbSMilanka Ringwald     event[pos++] = status;
123*cf26c8fbSMilanka Ringwald     event[pos++] = client->num_instances;
124*cf26c8fbSMilanka Ringwald     (*client->client_handler)(HCI_EVENT_PACKET, 0, event, sizeof(event));
125*cf26c8fbSMilanka Ringwald }
126*cf26c8fbSMilanka Ringwald 
127*cf26c8fbSMilanka Ringwald 
128*cf26c8fbSMilanka Ringwald static void hids_run_for_client(hids_client_t * client){
129*cf26c8fbSMilanka Ringwald     uint8_t att_status;
130*cf26c8fbSMilanka Ringwald 
131*cf26c8fbSMilanka Ringwald     switch (client->state){
132*cf26c8fbSMilanka Ringwald         case HIDS_CLIENT_STATE_W2_QUERY_SERVICE:
133*cf26c8fbSMilanka Ringwald             client->state = HIDS_CLIENT_STATE_W4_SERVICE_RESULT;
134*cf26c8fbSMilanka Ringwald             att_status = gatt_client_discover_primary_services_by_uuid16(handle_gatt_client_event, client->con_handle, ORG_BLUETOOTH_SERVICE_HUMAN_INTERFACE_DEVICE);
135*cf26c8fbSMilanka Ringwald             // TODO handle status
136*cf26c8fbSMilanka Ringwald             UNUSED(att_status);
137*cf26c8fbSMilanka Ringwald             break;
138*cf26c8fbSMilanka Ringwald 
139*cf26c8fbSMilanka Ringwald         case HIDS_CLIENT_STATE_W2_QUERY_CHARACTERISTIC:
140*cf26c8fbSMilanka Ringwald             break;
141*cf26c8fbSMilanka Ringwald 
142*cf26c8fbSMilanka Ringwald         case HIDS_CLIENT_STATE_CONNECTED:
143*cf26c8fbSMilanka Ringwald             break;
144*cf26c8fbSMilanka Ringwald         default:
145*cf26c8fbSMilanka Ringwald             break;
146*cf26c8fbSMilanka Ringwald     }
147*cf26c8fbSMilanka Ringwald }
148*cf26c8fbSMilanka Ringwald 
149*cf26c8fbSMilanka Ringwald static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
150*cf26c8fbSMilanka Ringwald     UNUSED(packet_type);
151*cf26c8fbSMilanka Ringwald     UNUSED(channel);
152*cf26c8fbSMilanka Ringwald     UNUSED(size);
153*cf26c8fbSMilanka Ringwald 
154*cf26c8fbSMilanka Ringwald     hids_client_t * client;
155*cf26c8fbSMilanka Ringwald     uint8_t att_status;
156*cf26c8fbSMilanka Ringwald 
157*cf26c8fbSMilanka Ringwald     switch(hci_event_packet_get_type(packet)){
158*cf26c8fbSMilanka Ringwald         case GATT_EVENT_SERVICE_QUERY_RESULT:
159*cf26c8fbSMilanka Ringwald             client = hids_get_client_for_con_handle(gatt_event_service_query_result_get_handle(packet));
160*cf26c8fbSMilanka Ringwald             btstack_assert(client != NULL);
161*cf26c8fbSMilanka Ringwald 
162*cf26c8fbSMilanka Ringwald             break;
163*cf26c8fbSMilanka Ringwald 
164*cf26c8fbSMilanka Ringwald         case GATT_EVENT_QUERY_COMPLETE:
165*cf26c8fbSMilanka Ringwald             client = hids_get_client_for_con_handle(gatt_event_query_complete_get_handle(packet));
166*cf26c8fbSMilanka Ringwald             btstack_assert(client != NULL);
167*cf26c8fbSMilanka Ringwald 
168*cf26c8fbSMilanka Ringwald             att_status = gatt_event_query_complete_get_att_status(packet);
169*cf26c8fbSMilanka Ringwald 
170*cf26c8fbSMilanka Ringwald             switch (client->state){
171*cf26c8fbSMilanka Ringwald                 case HIDS_CLIENT_STATE_W4_SERVICE_RESULT:
172*cf26c8fbSMilanka Ringwald 
173*cf26c8fbSMilanka Ringwald                     break;
174*cf26c8fbSMilanka Ringwald                 default:
175*cf26c8fbSMilanka Ringwald                     break;
176*cf26c8fbSMilanka Ringwald             }
177*cf26c8fbSMilanka Ringwald             break;
178*cf26c8fbSMilanka Ringwald 
179*cf26c8fbSMilanka Ringwald         default:
180*cf26c8fbSMilanka Ringwald             break;
181*cf26c8fbSMilanka Ringwald     }
182*cf26c8fbSMilanka Ringwald }
183*cf26c8fbSMilanka Ringwald 
184*cf26c8fbSMilanka Ringwald uint8_t hids_client_connect(hci_con_handle_t con_handle, btstack_packet_handler_t packet_handler, uint16_t * hids_cid){
185*cf26c8fbSMilanka Ringwald     btstack_assert(packet_handler != NULL);
186*cf26c8fbSMilanka Ringwald 
187*cf26c8fbSMilanka Ringwald     hids_client_t * client = hids_get_client_for_con_handle(con_handle);
188*cf26c8fbSMilanka Ringwald     if (client != NULL){
189*cf26c8fbSMilanka Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
190*cf26c8fbSMilanka Ringwald     }
191*cf26c8fbSMilanka Ringwald 
192*cf26c8fbSMilanka Ringwald     uint16_t cid = hids_get_next_cid();
193*cf26c8fbSMilanka Ringwald     if (hids_cid != NULL) {
194*cf26c8fbSMilanka Ringwald         *hids_cid = cid;
195*cf26c8fbSMilanka Ringwald     }
196*cf26c8fbSMilanka Ringwald 
197*cf26c8fbSMilanka Ringwald     client = hids_create_client(con_handle, cid);
198*cf26c8fbSMilanka Ringwald     if (client == NULL) {
199*cf26c8fbSMilanka Ringwald         return BTSTACK_MEMORY_ALLOC_FAILED;
200*cf26c8fbSMilanka Ringwald     }
201*cf26c8fbSMilanka Ringwald 
202*cf26c8fbSMilanka Ringwald     client->client_handler = packet_handler;
203*cf26c8fbSMilanka Ringwald     client->state = HIDS_CLIENT_STATE_W2_QUERY_SERVICE;
204*cf26c8fbSMilanka Ringwald 
205*cf26c8fbSMilanka Ringwald     hids_run_for_client(client);
206*cf26c8fbSMilanka Ringwald     return ERROR_CODE_SUCCESS;
207*cf26c8fbSMilanka Ringwald }
208*cf26c8fbSMilanka Ringwald 
209*cf26c8fbSMilanka Ringwald uint8_t hids_client_disconnect(uint16_t hids_cid){
210*cf26c8fbSMilanka Ringwald     hids_client_t * client = hids_get_client_for_cid(hids_cid);
211*cf26c8fbSMilanka Ringwald     if (client == NULL){
212*cf26c8fbSMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
213*cf26c8fbSMilanka Ringwald     }
214*cf26c8fbSMilanka Ringwald     // finalize connection
215*cf26c8fbSMilanka Ringwald     hids_finalize_client(client);
216*cf26c8fbSMilanka Ringwald     return ERROR_CODE_SUCCESS;
217*cf26c8fbSMilanka Ringwald }
218*cf26c8fbSMilanka Ringwald 
219*cf26c8fbSMilanka Ringwald void hids_client_init(void){}
220*cf26c8fbSMilanka Ringwald 
221*cf26c8fbSMilanka Ringwald void hids_client_deinit(void){}
222