xref: /btstack/src/ble/gatt-service/tx_power_service_client.c (revision a9cf7f9930c9913f5db5dac4868cf961b259846d)
1*a9cf7f99SMatthias Ringwald /*
2*a9cf7f99SMatthias Ringwald  * Copyright (C) 2024 BlueKitchen GmbH
3*a9cf7f99SMatthias Ringwald  *
4*a9cf7f99SMatthias Ringwald  * Redistribution and use in source and binary forms, with or without
5*a9cf7f99SMatthias Ringwald  * modification, are permitted provided that the following conditions
6*a9cf7f99SMatthias Ringwald  * are met:
7*a9cf7f99SMatthias Ringwald  *
8*a9cf7f99SMatthias Ringwald  * 1. Redistributions of source code must retain the above copyright
9*a9cf7f99SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer.
10*a9cf7f99SMatthias Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
11*a9cf7f99SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer in the
12*a9cf7f99SMatthias Ringwald  *    documentation and/or other materials provided with the distribution.
13*a9cf7f99SMatthias Ringwald  * 3. Neither the name of the copyright holders nor the names of
14*a9cf7f99SMatthias Ringwald  *    contributors may be used to endorse or promote products derived
15*a9cf7f99SMatthias Ringwald  *    from this software without specific prior written permission.
16*a9cf7f99SMatthias Ringwald  * 4. Any redistribution, use, or modification is done solely for
17*a9cf7f99SMatthias Ringwald  *    personal benefit and not for any commercial purpose or for
18*a9cf7f99SMatthias Ringwald  *    monetary gain.
19*a9cf7f99SMatthias Ringwald  *
20*a9cf7f99SMatthias Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21*a9cf7f99SMatthias Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22*a9cf7f99SMatthias Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23*a9cf7f99SMatthias Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
24*a9cf7f99SMatthias Ringwald  * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25*a9cf7f99SMatthias Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26*a9cf7f99SMatthias Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27*a9cf7f99SMatthias Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28*a9cf7f99SMatthias Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29*a9cf7f99SMatthias Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30*a9cf7f99SMatthias Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31*a9cf7f99SMatthias Ringwald  * SUCH DAMAGE.
32*a9cf7f99SMatthias Ringwald  *
33*a9cf7f99SMatthias Ringwald  * Please inquire about commercial licensing options at
34*a9cf7f99SMatthias Ringwald  * [email protected]
35*a9cf7f99SMatthias Ringwald  *
36*a9cf7f99SMatthias Ringwald  */
37*a9cf7f99SMatthias Ringwald 
38*a9cf7f99SMatthias Ringwald #define BTSTACK_FILE__ "tx_power_service_client.c"
39*a9cf7f99SMatthias Ringwald 
40*a9cf7f99SMatthias Ringwald #include "btstack_config.h"
41*a9cf7f99SMatthias Ringwald 
42*a9cf7f99SMatthias Ringwald #ifdef ENABLE_TESTING_SUPPORT
43*a9cf7f99SMatthias Ringwald #include <stdio.h>
44*a9cf7f99SMatthias Ringwald #include <unistd.h>
45*a9cf7f99SMatthias Ringwald #endif
46*a9cf7f99SMatthias Ringwald 
47*a9cf7f99SMatthias Ringwald #include <stdint.h>
48*a9cf7f99SMatthias Ringwald #include <string.h>
49*a9cf7f99SMatthias Ringwald 
50*a9cf7f99SMatthias Ringwald #include "ble/gatt_service_client.h"
51*a9cf7f99SMatthias Ringwald #include "ble/gatt-service/tx_power_service_client.h"
52*a9cf7f99SMatthias Ringwald 
53*a9cf7f99SMatthias Ringwald #include "bluetooth_gatt.h"
54*a9cf7f99SMatthias Ringwald #include "btstack_debug.h"
55*a9cf7f99SMatthias Ringwald #include "btstack_event.h"
56*a9cf7f99SMatthias Ringwald 
57*a9cf7f99SMatthias Ringwald // IAS Client
58*a9cf7f99SMatthias Ringwald static gatt_service_client_t txps_client;
59*a9cf7f99SMatthias Ringwald static btstack_linked_list_t txps_connections;
60*a9cf7f99SMatthias Ringwald 
61*a9cf7f99SMatthias Ringwald static btstack_context_callback_registration_t txps_client_handle_can_send_now;
62*a9cf7f99SMatthias Ringwald 
63*a9cf7f99SMatthias Ringwald static void txps_client_packet_handler_internal(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
64*a9cf7f99SMatthias Ringwald static void txps_client_handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
65*a9cf7f99SMatthias Ringwald static void txps_client_run_for_connection(void * context);
66*a9cf7f99SMatthias Ringwald 
67*a9cf7f99SMatthias Ringwald // list of uuids
68*a9cf7f99SMatthias Ringwald static const uint16_t txps_uuid16s[TX_POWER_SERVICE_CLIENT_NUM_CHARACTERISTICS] = {
69*a9cf7f99SMatthias Ringwald     ORG_BLUETOOTH_CHARACTERISTIC_TX_POWER_LEVEL
70*a9cf7f99SMatthias Ringwald };
71*a9cf7f99SMatthias Ringwald 
72*a9cf7f99SMatthias Ringwald typedef enum {
73*a9cf7f99SMatthias Ringwald     TXPS_CLIENT_CHARACTERISTIC_INDEX_TX_POWER_LEVEL = 0,
74*a9cf7f99SMatthias Ringwald     TXPS_CLIENT_CHARACTERISTIC_INDEX_RFU
75*a9cf7f99SMatthias Ringwald } txps_client_characteristic_index_t;
76*a9cf7f99SMatthias Ringwald 
77*a9cf7f99SMatthias Ringwald #ifdef ENABLE_TESTING_SUPPORT
78*a9cf7f99SMatthias Ringwald static const char * txps_characteristic_names[] = {
79*a9cf7f99SMatthias Ringwald     "TX_POWER_LEVEL",
80*a9cf7f99SMatthias Ringwald     "RFU"
81*a9cf7f99SMatthias Ringwald };
82*a9cf7f99SMatthias Ringwald #endif
83*a9cf7f99SMatthias Ringwald 
84*a9cf7f99SMatthias Ringwald 
txps_client_get_connection_for_cid(uint16_t connection_cid)85*a9cf7f99SMatthias Ringwald static txps_client_connection_t * txps_client_get_connection_for_cid(uint16_t connection_cid){
86*a9cf7f99SMatthias Ringwald     btstack_linked_list_iterator_t it;
87*a9cf7f99SMatthias Ringwald     btstack_linked_list_iterator_init(&it,  &txps_connections);
88*a9cf7f99SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
89*a9cf7f99SMatthias Ringwald         txps_client_connection_t * connection = (txps_client_connection_t *)btstack_linked_list_iterator_next(&it);
90*a9cf7f99SMatthias Ringwald         if (gatt_service_client_get_connection_id(&connection->basic_connection) == connection_cid) {
91*a9cf7f99SMatthias Ringwald             return connection;
92*a9cf7f99SMatthias Ringwald         }
93*a9cf7f99SMatthias Ringwald     }
94*a9cf7f99SMatthias Ringwald     return NULL;
95*a9cf7f99SMatthias Ringwald }
96*a9cf7f99SMatthias Ringwald 
txps_client_add_connection(txps_client_connection_t * connection)97*a9cf7f99SMatthias Ringwald static void txps_client_add_connection(txps_client_connection_t * connection){
98*a9cf7f99SMatthias Ringwald     btstack_linked_list_add(&txps_connections, (btstack_linked_item_t*) connection);
99*a9cf7f99SMatthias Ringwald }
100*a9cf7f99SMatthias Ringwald 
txps_client_finalize_connection(txps_client_connection_t * connection)101*a9cf7f99SMatthias Ringwald static void txps_client_finalize_connection(txps_client_connection_t * connection){
102*a9cf7f99SMatthias Ringwald     btstack_linked_list_remove(&txps_connections, (btstack_linked_item_t*) connection);
103*a9cf7f99SMatthias Ringwald }
104*a9cf7f99SMatthias Ringwald 
105*a9cf7f99SMatthias Ringwald 
txps_client_replace_subevent_id_and_emit(btstack_packet_handler_t callback,uint8_t * packet,uint16_t size,uint8_t subevent_id)106*a9cf7f99SMatthias Ringwald static void txps_client_replace_subevent_id_and_emit(btstack_packet_handler_t callback, uint8_t * packet, uint16_t size, uint8_t subevent_id){
107*a9cf7f99SMatthias Ringwald     UNUSED(size);
108*a9cf7f99SMatthias Ringwald     btstack_assert(callback != NULL);
109*a9cf7f99SMatthias Ringwald     // execute callback
110*a9cf7f99SMatthias Ringwald     packet[2] = subevent_id;
111*a9cf7f99SMatthias Ringwald     (*callback)(HCI_EVENT_PACKET, 0, packet, size);
112*a9cf7f99SMatthias Ringwald }
113*a9cf7f99SMatthias Ringwald 
txps_client_connected(txps_client_connection_t * connection,uint8_t status,uint8_t * packet,uint16_t size)114*a9cf7f99SMatthias Ringwald static void txps_client_connected(txps_client_connection_t * connection, uint8_t status, uint8_t * packet, uint16_t size) {
115*a9cf7f99SMatthias Ringwald     if (status == ERROR_CODE_SUCCESS){
116*a9cf7f99SMatthias Ringwald         connection->state = TX_POWER_SERVICE_CLIENT_STATE_READY;
117*a9cf7f99SMatthias Ringwald     } else {
118*a9cf7f99SMatthias Ringwald         connection->state = TX_POWER_SERVICE_CLIENT_STATE_IDLE;
119*a9cf7f99SMatthias Ringwald     }
120*a9cf7f99SMatthias Ringwald     txps_client_replace_subevent_id_and_emit(connection->packet_handler, packet, size,
121*a9cf7f99SMatthias Ringwald                                              GATTSERVICE_SUBEVENT_TXPS_CLIENT_CONNECTED);
122*a9cf7f99SMatthias Ringwald }
123*a9cf7f99SMatthias Ringwald 
txps_client_emit_uint8(uint16_t cid,btstack_packet_handler_t event_callback,uint8_t subevent,const uint8_t * data,uint16_t data_size)124*a9cf7f99SMatthias Ringwald static void txps_client_emit_uint8(uint16_t cid, btstack_packet_handler_t event_callback, uint8_t subevent, const uint8_t * data, uint16_t data_size){
125*a9cf7f99SMatthias Ringwald     UNUSED(data_size);
126*a9cf7f99SMatthias Ringwald     btstack_assert(event_callback != NULL);
127*a9cf7f99SMatthias Ringwald 
128*a9cf7f99SMatthias Ringwald     if (data_size != 1){
129*a9cf7f99SMatthias Ringwald         return;
130*a9cf7f99SMatthias Ringwald     }
131*a9cf7f99SMatthias Ringwald 
132*a9cf7f99SMatthias Ringwald     uint8_t event[6];
133*a9cf7f99SMatthias Ringwald     uint16_t pos = 0;
134*a9cf7f99SMatthias Ringwald     event[pos++] = HCI_EVENT_GATTSERVICE_META;
135*a9cf7f99SMatthias Ringwald     event[pos++] = 4;
136*a9cf7f99SMatthias Ringwald     event[pos++] = subevent;
137*a9cf7f99SMatthias Ringwald     little_endian_store_16(event, pos, cid);
138*a9cf7f99SMatthias Ringwald     pos+= 2;
139*a9cf7f99SMatthias Ringwald     event[pos++] = data[0];
140*a9cf7f99SMatthias Ringwald 
141*a9cf7f99SMatthias Ringwald     (*event_callback)(HCI_EVENT_PACKET, 0, event, pos);
142*a9cf7f99SMatthias Ringwald }
143*a9cf7f99SMatthias Ringwald 
txps_client_value_handle_for_index(txps_client_connection_t * connection)144*a9cf7f99SMatthias Ringwald static uint16_t txps_client_value_handle_for_index(txps_client_connection_t * connection){
145*a9cf7f99SMatthias Ringwald     return connection->basic_connection.characteristics[connection->characteristic_index].value_handle;
146*a9cf7f99SMatthias Ringwald }
147*a9cf7f99SMatthias Ringwald 
148*a9cf7f99SMatthias Ringwald 
txps_client_emit_read_event(txps_client_connection_t * connection,uint8_t index,uint8_t status,const uint8_t * data,uint16_t data_size)149*a9cf7f99SMatthias Ringwald static void txps_client_emit_read_event(txps_client_connection_t * connection, uint8_t index, uint8_t status, const uint8_t * data, uint16_t data_size){
150*a9cf7f99SMatthias Ringwald     UNUSED(status);
151*a9cf7f99SMatthias Ringwald 
152*a9cf7f99SMatthias Ringwald     if ((data_size > 0) && (data == NULL)){
153*a9cf7f99SMatthias Ringwald         return;
154*a9cf7f99SMatthias Ringwald     }
155*a9cf7f99SMatthias Ringwald 
156*a9cf7f99SMatthias Ringwald     uint16_t characteristic_uuid16 = gatt_service_client_characteristic_uuid16_for_index(&txps_client, index);
157*a9cf7f99SMatthias Ringwald     switch (characteristic_uuid16){
158*a9cf7f99SMatthias Ringwald         case ORG_BLUETOOTH_CHARACTERISTIC_TX_POWER_LEVEL:
159*a9cf7f99SMatthias Ringwald            txps_client_emit_uint8(connection->basic_connection.cid,  connection->packet_handler, GATTSERVICE_SUBEVENT_TXPS_CLIENT_TX_POWER_LEVEL, data, data_size);
160*a9cf7f99SMatthias Ringwald            break;
161*a9cf7f99SMatthias Ringwald         default:
162*a9cf7f99SMatthias Ringwald             btstack_assert(false);
163*a9cf7f99SMatthias Ringwald             break;
164*a9cf7f99SMatthias Ringwald     }
165*a9cf7f99SMatthias Ringwald }
166*a9cf7f99SMatthias Ringwald 
txps_client_can_query_characteristic(txps_client_connection_t * connection,txps_client_characteristic_index_t characteristic_index)167*a9cf7f99SMatthias Ringwald static uint8_t txps_client_can_query_characteristic(txps_client_connection_t * connection, txps_client_characteristic_index_t characteristic_index){
168*a9cf7f99SMatthias Ringwald     uint8_t status = gatt_service_client_can_query_characteristic(&connection->basic_connection,
169*a9cf7f99SMatthias Ringwald                                                                   (uint8_t) characteristic_index);
170*a9cf7f99SMatthias Ringwald     if (status != ERROR_CODE_SUCCESS){
171*a9cf7f99SMatthias Ringwald         return status;
172*a9cf7f99SMatthias Ringwald     }
173*a9cf7f99SMatthias Ringwald     return connection->state == TX_POWER_SERVICE_CLIENT_STATE_READY ? ERROR_CODE_SUCCESS : ERROR_CODE_CONTROLLER_BUSY;
174*a9cf7f99SMatthias Ringwald }
175*a9cf7f99SMatthias Ringwald 
txps_client_request_send_gatt_query(txps_client_connection_t * connection,txps_client_characteristic_index_t characteristic_index)176*a9cf7f99SMatthias Ringwald static uint8_t txps_client_request_send_gatt_query(txps_client_connection_t * connection, txps_client_characteristic_index_t characteristic_index){
177*a9cf7f99SMatthias Ringwald     connection->characteristic_index = characteristic_index;
178*a9cf7f99SMatthias Ringwald 
179*a9cf7f99SMatthias Ringwald     txps_client_handle_can_send_now.context = (void *)(uintptr_t)connection->basic_connection.cid;
180*a9cf7f99SMatthias Ringwald     uint8_t status = gatt_client_request_to_send_gatt_query(&txps_client_handle_can_send_now, connection->basic_connection.con_handle);
181*a9cf7f99SMatthias Ringwald     if (status != ERROR_CODE_SUCCESS){
182*a9cf7f99SMatthias Ringwald         connection->state = TX_POWER_SERVICE_CLIENT_STATE_READY;
183*a9cf7f99SMatthias Ringwald     }
184*a9cf7f99SMatthias Ringwald     return status;
185*a9cf7f99SMatthias Ringwald }
186*a9cf7f99SMatthias Ringwald 
txps_client_request_read_characteristic(uint16_t cid,txps_client_characteristic_index_t characteristic_index)187*a9cf7f99SMatthias Ringwald static uint8_t txps_client_request_read_characteristic(uint16_t cid, txps_client_characteristic_index_t characteristic_index){
188*a9cf7f99SMatthias Ringwald     txps_client_connection_t * connection = txps_client_get_connection_for_cid(cid);
189*a9cf7f99SMatthias Ringwald     if (connection == NULL){
190*a9cf7f99SMatthias Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
191*a9cf7f99SMatthias Ringwald     }
192*a9cf7f99SMatthias Ringwald     uint8_t status = txps_client_can_query_characteristic(connection, characteristic_index);
193*a9cf7f99SMatthias Ringwald     if (status != ERROR_CODE_SUCCESS){
194*a9cf7f99SMatthias Ringwald         return status;
195*a9cf7f99SMatthias Ringwald     }
196*a9cf7f99SMatthias Ringwald 
197*a9cf7f99SMatthias Ringwald     connection->state = TX_POWER_SERVICE_CLIENT_STATE_W2_READ_CHARACTERISTIC_VALUE;
198*a9cf7f99SMatthias Ringwald     return txps_client_request_send_gatt_query(connection, characteristic_index);
199*a9cf7f99SMatthias Ringwald }
200*a9cf7f99SMatthias Ringwald 
txps_client_packet_handler_internal(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)201*a9cf7f99SMatthias Ringwald static void txps_client_packet_handler_internal(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
202*a9cf7f99SMatthias Ringwald     UNUSED(channel);
203*a9cf7f99SMatthias Ringwald     UNUSED(size);
204*a9cf7f99SMatthias Ringwald 
205*a9cf7f99SMatthias Ringwald     if (packet_type != HCI_EVENT_PACKET) return;
206*a9cf7f99SMatthias Ringwald     txps_client_connection_t * connection;
207*a9cf7f99SMatthias Ringwald     uint16_t cid;
208*a9cf7f99SMatthias Ringwald     uint8_t status;
209*a9cf7f99SMatthias Ringwald 
210*a9cf7f99SMatthias Ringwald     switch(hci_event_packet_get_type(packet)){
211*a9cf7f99SMatthias Ringwald         case HCI_EVENT_GATTSERVICE_META:
212*a9cf7f99SMatthias Ringwald             switch (hci_event_gattservice_meta_get_subevent_code(packet)) {
213*a9cf7f99SMatthias Ringwald                 case GATTSERVICE_SUBEVENT_CLIENT_CONNECTED:
214*a9cf7f99SMatthias Ringwald                     cid = gattservice_subevent_client_connected_get_cid(packet);
215*a9cf7f99SMatthias Ringwald                     connection = txps_client_get_connection_for_cid(cid);
216*a9cf7f99SMatthias Ringwald                     btstack_assert(connection != NULL);
217*a9cf7f99SMatthias Ringwald 
218*a9cf7f99SMatthias Ringwald #ifdef ENABLE_TESTING_SUPPORT
219*a9cf7f99SMatthias Ringwald                     gatt_service_client_dump_characteristic_value_handles(&connection->basic_connection,
220*a9cf7f99SMatthias Ringwald                                                                           txps_characteristic_names);
221*a9cf7f99SMatthias Ringwald #endif
222*a9cf7f99SMatthias Ringwald                     status = gattservice_subevent_client_connected_get_status(packet);
223*a9cf7f99SMatthias Ringwald                     txps_client_connected(connection, status, packet, size);
224*a9cf7f99SMatthias Ringwald                     break;
225*a9cf7f99SMatthias Ringwald 
226*a9cf7f99SMatthias Ringwald                 case GATTSERVICE_SUBEVENT_CLIENT_DISCONNECTED:
227*a9cf7f99SMatthias Ringwald                     // TODO reset client
228*a9cf7f99SMatthias Ringwald                     cid = gattservice_subevent_client_disconnected_get_cid(packet);
229*a9cf7f99SMatthias Ringwald                     connection = txps_client_get_connection_for_cid(cid);
230*a9cf7f99SMatthias Ringwald                     btstack_assert(connection != NULL);
231*a9cf7f99SMatthias Ringwald                     txps_client_finalize_connection(connection);
232*a9cf7f99SMatthias Ringwald                     txps_client_replace_subevent_id_and_emit(connection->packet_handler, packet, size,
233*a9cf7f99SMatthias Ringwald                                                             GATTSERVICE_SUBEVENT_TXPS_CLIENT_DISCONNECTED);
234*a9cf7f99SMatthias Ringwald                     break;
235*a9cf7f99SMatthias Ringwald 
236*a9cf7f99SMatthias Ringwald                 default:
237*a9cf7f99SMatthias Ringwald                     break;
238*a9cf7f99SMatthias Ringwald             }
239*a9cf7f99SMatthias Ringwald             break;
240*a9cf7f99SMatthias Ringwald 
241*a9cf7f99SMatthias Ringwald         default:
242*a9cf7f99SMatthias Ringwald             break;
243*a9cf7f99SMatthias Ringwald     }
244*a9cf7f99SMatthias Ringwald }
245*a9cf7f99SMatthias Ringwald 
txps_client_handle_gatt_client_event(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)246*a9cf7f99SMatthias Ringwald static void txps_client_handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
247*a9cf7f99SMatthias Ringwald     UNUSED(packet_type);
248*a9cf7f99SMatthias Ringwald     UNUSED(channel);
249*a9cf7f99SMatthias Ringwald     UNUSED(size);
250*a9cf7f99SMatthias Ringwald 
251*a9cf7f99SMatthias Ringwald     txps_client_connection_t * connection = NULL;
252*a9cf7f99SMatthias Ringwald     uint16_t connection_id;
253*a9cf7f99SMatthias Ringwald 
254*a9cf7f99SMatthias Ringwald     switch(hci_event_packet_get_type(packet)){
255*a9cf7f99SMatthias Ringwald         case GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT:
256*a9cf7f99SMatthias Ringwald             connection_id = gatt_event_characteristic_value_query_result_get_connection_id(packet);
257*a9cf7f99SMatthias Ringwald             connection = txps_client_get_connection_for_cid(connection_id);
258*a9cf7f99SMatthias Ringwald             btstack_assert(connection != NULL);
259*a9cf7f99SMatthias Ringwald 
260*a9cf7f99SMatthias Ringwald             txps_client_emit_read_event(connection, connection->characteristic_index, ATT_ERROR_SUCCESS,
261*a9cf7f99SMatthias Ringwald                 gatt_event_characteristic_value_query_result_get_value(packet),
262*a9cf7f99SMatthias Ringwald                 gatt_event_characteristic_value_query_result_get_value_length(packet));
263*a9cf7f99SMatthias Ringwald 
264*a9cf7f99SMatthias Ringwald             connection->state = TX_POWER_SERVICE_CLIENT_STATE_READY;
265*a9cf7f99SMatthias Ringwald             break;
266*a9cf7f99SMatthias Ringwald 
267*a9cf7f99SMatthias Ringwald         case GATT_EVENT_QUERY_COMPLETE:
268*a9cf7f99SMatthias Ringwald             connection_id = gatt_event_query_complete_get_connection_id(packet);
269*a9cf7f99SMatthias Ringwald             connection = txps_client_get_connection_for_cid(connection_id);
270*a9cf7f99SMatthias Ringwald             btstack_assert(connection != NULL);
271*a9cf7f99SMatthias Ringwald 
272*a9cf7f99SMatthias Ringwald             connection->state = TX_POWER_SERVICE_CLIENT_STATE_READY;
273*a9cf7f99SMatthias Ringwald             break;
274*a9cf7f99SMatthias Ringwald 
275*a9cf7f99SMatthias Ringwald         default:
276*a9cf7f99SMatthias Ringwald             break;
277*a9cf7f99SMatthias Ringwald     }
278*a9cf7f99SMatthias Ringwald }
279*a9cf7f99SMatthias Ringwald 
txps_client_run_for_connection(void * context)280*a9cf7f99SMatthias Ringwald static void txps_client_run_for_connection(void * context){
281*a9cf7f99SMatthias Ringwald     uint16_t connection_id = (hci_con_handle_t)(uintptr_t)context;
282*a9cf7f99SMatthias Ringwald     txps_client_connection_t * connection = txps_client_get_connection_for_cid(connection_id);
283*a9cf7f99SMatthias Ringwald 
284*a9cf7f99SMatthias Ringwald     btstack_assert(connection != NULL);
285*a9cf7f99SMatthias Ringwald 
286*a9cf7f99SMatthias Ringwald     switch (connection->state){
287*a9cf7f99SMatthias Ringwald         case TX_POWER_SERVICE_CLIENT_STATE_W2_READ_CHARACTERISTIC_VALUE:
288*a9cf7f99SMatthias Ringwald             connection->state = TX_POWER_SERVICE_CLIENT_STATE_W4_READ_CHARACTERISTIC_VALUE_RESULT;
289*a9cf7f99SMatthias Ringwald 
290*a9cf7f99SMatthias Ringwald             (void) gatt_client_read_value_of_characteristic_using_value_handle_with_context(
291*a9cf7f99SMatthias Ringwald                 &txps_client_handle_gatt_client_event, connection->basic_connection.cid,
292*a9cf7f99SMatthias Ringwald                 txps_client_value_handle_for_index(connection), txps_client.service_id, connection->basic_connection.cid);
293*a9cf7f99SMatthias Ringwald             break;
294*a9cf7f99SMatthias Ringwald 
295*a9cf7f99SMatthias Ringwald         default:
296*a9cf7f99SMatthias Ringwald             break;
297*a9cf7f99SMatthias Ringwald     }
298*a9cf7f99SMatthias Ringwald }
299*a9cf7f99SMatthias Ringwald 
tx_power_service_client_init(void)300*a9cf7f99SMatthias Ringwald void tx_power_service_client_init(void){
301*a9cf7f99SMatthias Ringwald     gatt_service_client_register_client(&txps_client, &txps_client_packet_handler_internal, txps_uuid16s, sizeof(txps_uuid16s)/sizeof(uint16_t));
302*a9cf7f99SMatthias Ringwald 
303*a9cf7f99SMatthias Ringwald     txps_client_handle_can_send_now.callback = &txps_client_run_for_connection;
304*a9cf7f99SMatthias Ringwald }
305*a9cf7f99SMatthias Ringwald 
tx_power_service_client_connect(hci_con_handle_t con_handle,btstack_packet_handler_t packet_handler,txps_client_connection_t * txps_connection,gatt_service_client_characteristic_t * txps_storage_for_characteristics,uint8_t txps_characteristics_num,uint16_t * txps_cid)306*a9cf7f99SMatthias Ringwald uint8_t tx_power_service_client_connect(hci_con_handle_t con_handle,
307*a9cf7f99SMatthias Ringwald     btstack_packet_handler_t packet_handler,
308*a9cf7f99SMatthias Ringwald     txps_client_connection_t * txps_connection,
309*a9cf7f99SMatthias Ringwald     gatt_service_client_characteristic_t * txps_storage_for_characteristics, uint8_t txps_characteristics_num,
310*a9cf7f99SMatthias Ringwald     uint16_t * txps_cid
311*a9cf7f99SMatthias Ringwald ){
312*a9cf7f99SMatthias Ringwald 
313*a9cf7f99SMatthias Ringwald     btstack_assert(packet_handler != NULL);
314*a9cf7f99SMatthias Ringwald     btstack_assert(txps_connection != NULL);
315*a9cf7f99SMatthias Ringwald     btstack_assert(txps_characteristics_num == TX_POWER_SERVICE_CLIENT_NUM_CHARACTERISTICS);
316*a9cf7f99SMatthias Ringwald 
317*a9cf7f99SMatthias Ringwald     *txps_cid = 0;
318*a9cf7f99SMatthias Ringwald 
319*a9cf7f99SMatthias Ringwald     txps_connection->state = TX_POWER_SERVICE_CLIENT_STATE_W4_CONNECTION;
320*a9cf7f99SMatthias Ringwald     txps_connection->packet_handler = packet_handler;
321*a9cf7f99SMatthias Ringwald 
322*a9cf7f99SMatthias Ringwald     uint8_t status = gatt_service_client_connect_primary_service_with_uuid16(con_handle,
323*a9cf7f99SMatthias Ringwald                                                                              &txps_client,
324*a9cf7f99SMatthias Ringwald                                                                              &txps_connection->basic_connection,
325*a9cf7f99SMatthias Ringwald                                                                              ORG_BLUETOOTH_SERVICE_TX_POWER, 0,
326*a9cf7f99SMatthias Ringwald                                                                              txps_storage_for_characteristics,
327*a9cf7f99SMatthias Ringwald                                                                              txps_characteristics_num);
328*a9cf7f99SMatthias Ringwald     if (status == ERROR_CODE_SUCCESS){
329*a9cf7f99SMatthias Ringwald         txps_client_add_connection(txps_connection);
330*a9cf7f99SMatthias Ringwald         *txps_cid = txps_connection->basic_connection.cid;
331*a9cf7f99SMatthias Ringwald     }
332*a9cf7f99SMatthias Ringwald 
333*a9cf7f99SMatthias Ringwald     return status;
334*a9cf7f99SMatthias Ringwald }
335*a9cf7f99SMatthias Ringwald 
tx_power_service_client_read_tx_power_level(uint16_t txps_cid)336*a9cf7f99SMatthias Ringwald uint8_t tx_power_service_client_read_tx_power_level(uint16_t txps_cid){
337*a9cf7f99SMatthias Ringwald     return txps_client_request_read_characteristic(txps_cid, TXPS_CLIENT_CHARACTERISTIC_INDEX_TX_POWER_LEVEL);
338*a9cf7f99SMatthias Ringwald }
339*a9cf7f99SMatthias Ringwald 
tx_power_service_client_deinit(void)340*a9cf7f99SMatthias Ringwald void tx_power_service_client_deinit(void){
341*a9cf7f99SMatthias Ringwald     gatt_service_client_unregister_client(&txps_client);
342*a9cf7f99SMatthias Ringwald }
343*a9cf7f99SMatthias Ringwald 
344