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