From 174a0c1c8d4a5183616f89c4f14b8b88926d49b0 Mon Sep 17 00:00:00 2001 From: Milanka Ringwald Date: Tue, 2 Mar 2021 15:30:56 +0100 Subject: [PATCH] ble/battery_service_client: implement query services --- example/Makefile.inc | 1 + example/gatt_battery_query.c | 55 +++--- src/ble/battery_service_client.c | 231 ++++++++++++++++++++++ src/ble/battery_service_client.h | 91 +++++++++ src/ble/hids_client.h | 3 +- src/btstack.h | 1 + src/btstack_defines.h | 9 + src/btstack_event.h | 28 +++ src/btstack_memory.c | 203 ++++++++++++------- src/btstack_memory.h | 13 +- test/btstack_memory/btstack_memory_test.c | 168 ++++++++++++---- tool/btstack_memory_generator.py | 3 +- 12 files changed, 664 insertions(+), 142 deletions(-) create mode 100644 src/ble/battery_service_client.c create mode 100644 src/ble/battery_service_client.h diff --git a/example/Makefile.inc b/example/Makefile.inc index a47de356e..39a74da50 100644 --- a/example/Makefile.inc +++ b/example/Makefile.inc @@ -84,6 +84,7 @@ GATT_SERVER += \ GATT_CLIENT += \ gatt_client.c \ + battery_service_client.c \ PAN += \ pan.c \ diff --git a/example/gatt_battery_query.c b/example/gatt_battery_query.c index 9f14ab412..b24111fd9 100644 --- a/example/gatt_battery_query.c +++ b/example/gatt_battery_query.c @@ -85,9 +85,7 @@ static bd_addr_t cmdline_addr; static int cmdline_addr_found = 0; static hci_con_handle_t connection_handle; -static uint16_t battery_service_uuid = 0x180F; -static uint16_t battery_level_characteristic_uuid = 0x2a19; -static gatt_client_service_t battery_service; +static uint16_t battery_service_cid; static gatt_client_characteristic_t battery_level_characteristic; static gc_state_t state = TC_IDLE; @@ -142,12 +140,6 @@ static void dump_characteristic(gatt_client_characteristic_t * characteristic){ printf("\n"); } -static void dump_service(gatt_client_service_t * service){ - printf(" * service: [0x%04x-0x%04x], uuid ", service->start_group_handle, service->end_group_handle); - printUUID(service->uuid128, service->uuid16); - printf("\n"); -} - static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ UNUSED(packet_type); @@ -157,28 +149,31 @@ static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint int status; uint8_t battery_level; - switch(state){ - case TC_W4_SERVICE_RESULT: - switch(hci_event_packet_get_type(packet)){ - case GATT_EVENT_SERVICE_QUERY_RESULT: - gatt_event_service_query_result_get_service(packet, &battery_service); - dump_service(&battery_service); - break; - case GATT_EVENT_QUERY_COMPLETE: - if (packet[4] != 0){ - printf("SERVICE_QUERY_RESULT - Error status %x.\n", packet[4]); - add_to_blacklist(report.address); - gap_disconnect(connection_handle); - break; - } + if (hci_event_packet_get_type(packet) != HCI_EVENT_GATTSERVICE_META){ + return; + } + + switch (hci_event_gattservice_meta_get_subevent_code(packet)){ + case GATTSERVICE_SUBEVENT_BATTERY_SERVICE_NUM_INSTANCES: + status = gattservice_subevent_battery_service_num_instances_get_status(packet); + switch (status){ + case ERROR_CODE_SUCCESS: + case ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE: state = TC_W4_CHARACTERISTIC_RESULT; - printf("\nSearch for battery level characteristic.\n"); - gatt_client_discover_characteristics_for_service_by_uuid16(handle_gatt_client_event, connection_handle, &battery_service, battery_level_characteristic_uuid); break; default: + printf("SERVICE_QUERY_RESULT - Error status %x.\n", packet[4]); + add_to_blacklist(report.address); + gap_disconnect(connection_handle); break; } break; + default: + break; + } + + + switch(state){ case TC_W4_CHARACTERISTIC_RESULT: switch(hci_event_packet_get_type(packet)){ @@ -257,7 +252,8 @@ static void hci_event_handler(uint8_t packet_type, uint16_t channel, uint8_t *pa UNUSED(size); if (packet_type != HCI_EVENT_PACKET) return; - + uint8_t status; + uint8_t event = hci_event_packet_get_type(packet); switch (event) { case BTSTACK_EVENT_STATE: @@ -297,8 +293,10 @@ static void hci_event_handler(uint8_t packet_type, uint16_t channel, uint8_t *pa // initialize gatt client context with handle, and add it to the list of active clients // query primary services printf("\nSearch for battery service.\n"); - state = TC_W4_SERVICE_RESULT; - gatt_client_discover_primary_services_by_uuid16(handle_gatt_client_event, connection_handle, battery_service_uuid); + status = battery_service_client_connect(connection_handle, handle_gatt_client_event, &battery_service_cid); + if (status == ERROR_CODE_SUCCESS){ + state = TC_W4_SERVICE_RESULT; + } break; case HCI_EVENT_DISCONNECTION_COMPLETE: // unregister listener @@ -359,6 +357,7 @@ int btstack_main(int argc, const char * argv[]){ // GATT Client setup gatt_client_init(); + battery_service_client_init(); sm_init(); sm_set_io_capabilities(IO_CAPABILITY_NO_INPUT_NO_OUTPUT); diff --git a/src/ble/battery_service_client.c b/src/ble/battery_service_client.c new file mode 100644 index 000000000..8b858319c --- /dev/null +++ b/src/ble/battery_service_client.c @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2021 BlueKitchen GmbH + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * 4. Any redistribution, use, or modification is done solely for + * personal benefit and not for any commercial purpose or for + * monetary gain. + * + * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS + * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Please inquire about commercial licensing options at + * contact@bluekitchen-gmbh.com + * + */ + +#define BTSTACK_FILE__ "battery_service_client.c" + +#include "btstack_config.h" + +#include +#include + + +#include "battery_service_client.h" + + +#include "btstack_memory.h" +#include "ble/att_db.h" +#include "ble/core.h" +#include "ble/gatt_client.h" +#include "ble/sm.h" +#include "bluetooth_gatt.h" +#include "btstack_debug.h" +#include "btstack_event.h" +#include "btstack_run_loop.h" +#include "gap.h" + + +static btstack_linked_list_t clients; +static uint16_t battery_service_cid_counter = 0; + +static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); + +static uint16_t battery_service_get_next_cid(void){ + if (battery_service_cid_counter == 0xffff) { + battery_service_cid_counter = 1; + } else { + battery_service_cid_counter++; + } + return battery_service_cid_counter; +} + +static battery_service_client_t * battery_service_create_client(hci_con_handle_t con_handle, uint16_t cid){ + battery_service_client_t * client = btstack_memory_battery_service_client_get(); + if (!client){ + log_error("Not enough memory to create client"); + return NULL; + } + client->state = BATTERY_SERVICE_IDLE; + client->cid = cid; + client->con_handle = con_handle; + btstack_linked_list_add(&clients, (btstack_linked_item_t *) client); + return client; +} + +static battery_service_client_t * battery_service_get_client_for_con_handle(hci_con_handle_t con_handle){ + btstack_linked_list_iterator_t it; + btstack_linked_list_iterator_init(&it, &clients); + while (btstack_linked_list_iterator_has_next(&it)){ + battery_service_client_t * client = (battery_service_client_t *)btstack_linked_list_iterator_next(&it); + if (client->con_handle != con_handle) continue; + return client; + } + return NULL; +} + +static battery_service_client_t * battery_service_get_client_for_cid(uint16_t battery_service_cid){ + btstack_linked_list_iterator_t it; + btstack_linked_list_iterator_init(&it, &clients); + while (btstack_linked_list_iterator_has_next(&it)){ + battery_service_client_t * client = (battery_service_client_t *)btstack_linked_list_iterator_next(&it); + if (client->cid != battery_service_cid) continue; + return client; + } + return NULL; +} + +static void battery_service_emit_instances(battery_service_client_t * client, uint8_t status, uint8_t num_instances){ + uint8_t event[7]; + int pos = 0; + event[pos++] = HCI_EVENT_GATTSERVICE_META; + event[pos++] = sizeof(event) - 2; + event[pos++] = GATTSERVICE_SUBEVENT_BATTERY_SERVICE_NUM_INSTANCES; + little_endian_store_16(event, pos, client->cid); + pos += 2; + event[pos++] = status; + event[pos++] = num_instances; + + if (client->client_handler != NULL){ + (*client->client_handler)(HCI_EVENT_PACKET, 0, event, sizeof(event)); + } +} + +static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ + UNUSED(packet_type); // ok: only hci events + UNUSED(channel); // ok: there is no channel + UNUSED(size); // ok: fixed format events read from HCI buffer + + battery_service_client_t * client; + + uint8_t status; + + switch(hci_event_packet_get_type(packet)){ + case GATT_EVENT_SERVICE_QUERY_RESULT: + client = battery_service_get_client_for_con_handle(gatt_event_service_query_result_get_handle(packet)); + if (!client){ + log_error("No client for handle 0x%02x", gatt_event_service_query_result_get_handle(packet)); + break; + } + + if (client->state != BATTERY_SERVICE_W4_SERVICE_RESULT) { + battery_service_emit_instances(client, GATT_CLIENT_IN_WRONG_STATE, 0); + break; + } + + if (client->num_battery_services < MAX_NUM_BATTERY_SERVICES){ + gatt_event_service_query_result_get_service(packet, &client->services[client->num_battery_services]); + } + client->num_battery_services++; + break; + + case GATT_EVENT_QUERY_COMPLETE: + client = battery_service_get_client_for_con_handle(gatt_event_query_complete_get_handle(packet)); + if (!client){ + log_error("No client for handle 0x%02x", gatt_event_query_complete_get_handle(packet)); + break; + } + + status = gatt_event_query_complete_get_att_status(packet); + if (status != ERROR_CODE_SUCCESS){ + battery_service_emit_instances(client, status, 0); + break; + } + + if (client->num_battery_services > MAX_NUM_BATTERY_SERVICES) { + battery_service_emit_instances(client, ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE, client->num_battery_services); + client->num_battery_services = MAX_NUM_BATTERY_SERVICES; + } else { + battery_service_emit_instances(client, status, client->num_battery_services); + } + + client->state = BATTERY_SERVICE_W4_CHARACTERISTIC_RESULT; + client->battery_services_index = 0; + gatt_client_discover_characteristics_for_service_by_uuid16(handle_gatt_client_event, client->con_handle, &client->services[client->battery_services_index], ORG_BLUETOOTH_CHARACTERISTIC_BATTERY_LEVEL); + break; + + + default: + break; + } +} + +static void battery_service_run_for_client(battery_service_client_t * client){ + uint8_t status; + switch (client->state){ + case BATTERY_SERVICE_W2_QUERY_SERVICE: + client->state = BATTERY_SERVICE_W4_SERVICE_RESULT; + status = gatt_client_discover_primary_services_by_uuid16(handle_gatt_client_event, client->con_handle, ORG_BLUETOOTH_SERVICE_BATTERY_SERVICE); + // TODO handle status + break; + default: + break; + } +} + +uint8_t battery_service_client_connect(hci_con_handle_t con_handle, btstack_packet_handler_t callback, uint16_t * battery_service_cid){ + battery_service_client_t * client = battery_service_get_client_for_con_handle(con_handle); + + if (client){ + return ERROR_CODE_COMMAND_DISALLOWED; + } + + uint16_t cid = battery_service_get_next_cid(); + if (battery_service_cid != NULL) { + *battery_service_cid = cid; + } + + client = battery_service_create_client(con_handle, cid); + if (!client) return BTSTACK_MEMORY_ALLOC_FAILED; + + client->client_handler = callback; + client->state = BATTERY_SERVICE_W2_QUERY_SERVICE; + battery_service_run_for_client(client); + return ERROR_CODE_SUCCESS; +} + +uint8_t battery_service_client_disconnect(uint16_t battery_service_cid){ + battery_service_client_t * client = battery_service_get_client_for_cid(battery_service_cid); + if (!client){ + return ERROR_CODE_SUCCESS; + } + // TODO + return ERROR_CODE_SUCCESS; +} + +void battery_service_client_init(void){} + +void battery_service_client_deinit(void){} + diff --git a/src/ble/battery_service_client.h b/src/ble/battery_service_client.h new file mode 100644 index 000000000..57fc31305 --- /dev/null +++ b/src/ble/battery_service_client.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2021 BlueKitchen GmbH + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * 4. Any redistribution, use, or modification is done solely for + * personal benefit and not for any commercial purpose or for + * monetary gain. + * + * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS + * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Please inquire about commercial licensing options at + * contact@bluekitchen-gmbh.com + * + */ + +#ifndef BATTERY_SERVICE_CLIENT_H +#define BATTERY_SERVICE_CLIENT_H + +#include +#include "btstack_defines.h" +#include "bluetooth.h" +#include "btstack_linked_list.h" +#include "ble/gatt_client.h" + + +#if defined __cplusplus +extern "C" { +#endif + +#ifndef MAX_NUM_BATTERY_SERVICES +#define MAX_NUM_BATTERY_SERVICES 3 +#endif + +/* API_START */ + +typedef enum { + BATTERY_SERVICE_IDLE, + BATTERY_SERVICE_W2_QUERY_SERVICE, + BATTERY_SERVICE_W4_SERVICE_RESULT, + BATTERY_SERVICE_W4_CHARACTERISTIC_RESULT, + BATTERY_SERVICE_W4_BATTERY_DATA +} battery_service_state_t; + +typedef struct { + btstack_linked_item_t item; + + hci_con_handle_t con_handle; + uint16_t cid; + battery_service_state_t state; + btstack_packet_handler_t client_handler; + + uint8_t battery_services_index; + uint8_t num_battery_services; + gatt_client_service_t services[MAX_NUM_BATTERY_SERVICES]; +} battery_service_client_t; + +void battery_service_client_init(void); +void battery_service_client_deinit(void); + +uint8_t battery_service_client_connect(hci_con_handle_t con_handle, btstack_packet_handler_t callback, uint16_t * battery_service_cid); +uint8_t battery_service_client_disconnect(uint16_t battery_service_cid); + +/* API_END */ + +#if defined __cplusplus +} +#endif + +#endif diff --git a/src/ble/hids_client.h b/src/ble/hids_client.h index 60048b07c..98eb653c7 100644 --- a/src/ble/hids_client.h +++ b/src/ble/hids_client.h @@ -43,8 +43,9 @@ extern "C" { #endif #include +#include "classic/hid.h" #include "btstack_defines.h" - + /* API_START */ void hids_client_init(void); diff --git a/src/btstack.h b/src/btstack.h index 0dbfcbba7..6e9eccb0c 100644 --- a/src/btstack.h +++ b/src/btstack.h @@ -81,6 +81,7 @@ #include "ble/att_db_util.h" #include "ble/att_dispatch.h" #include "ble/att_server.h" +#include "ble/battery_service_client.h" #include "ble/gatt-service/battery_service_server.h" #include "ble/gatt-service/cycling_power_service_server.h" #include "ble/gatt-service/cycling_speed_and_cadence_service_server.h" diff --git a/src/btstack_defines.h b/src/btstack_defines.h index 4fc7a25ea..7674d0b4c 100644 --- a/src/btstack_defines.h +++ b/src/btstack_defines.h @@ -1102,6 +1102,7 @@ typedef uint8_t sm_key_t[16]; */ #define GATT_EVENT_CAN_WRITE_WITHOUT_RESPONSE 0xAC + /** * @format 1BH * @param address_type @@ -3067,6 +3068,14 @@ typedef uint8_t sm_key_t[16]; */ #define GATTSERVICE_SUBEVENT_CYCLING_POWER_BROADCAST_STOP 0x03 +/** + * @format 1211 + * @param subevent_code + * @param cid + * @param status + * @param num_instances +*/ +#define GATTSERVICE_SUBEVENT_BATTERY_SERVICE_NUM_INSTANCES 0x04 // MAP Meta Event Group diff --git a/src/btstack_event.h b/src/btstack_event.h index f6c1c90c8..66f827b82 100644 --- a/src/btstack_event.h +++ b/src/btstack_event.h @@ -9066,6 +9066,34 @@ static inline uint16_t gattservice_subevent_cycling_power_broadcast_stop_get_con return little_endian_read_16(event, 3); } +/** + * @brief Get field cid from event GATTSERVICE_SUBEVENT_BATTERY_SERVICE_NUM_INSTANCES + * @param event packet + * @return cid + * @note: btstack_type 2 + */ +static inline uint16_t gattservice_subevent_battery_service_num_instances_get_cid(const uint8_t * event){ + return little_endian_read_16(event, 3); +} +/** + * @brief Get field status from event GATTSERVICE_SUBEVENT_BATTERY_SERVICE_NUM_INSTANCES + * @param event packet + * @return status + * @note: btstack_type 1 + */ +static inline uint8_t gattservice_subevent_battery_service_num_instances_get_status(const uint8_t * event){ + return event[5]; +} +/** + * @brief Get field num_instances from event GATTSERVICE_SUBEVENT_BATTERY_SERVICE_NUM_INSTANCES + * @param event packet + * @return num_instances + * @note: btstack_type 1 + */ +static inline uint8_t gattservice_subevent_battery_service_num_instances_get_num_instances(const uint8_t * event){ + return event[6]; +} + /** * @brief Get field map_cid from event MAP_SUBEVENT_CONNECTION_OPENED * @param event packet diff --git a/src/btstack_memory.c b/src/btstack_memory.c index 9c727b3b1..f002b9a9c 100644 --- a/src/btstack_memory.c +++ b/src/btstack_memory.c @@ -715,20 +715,31 @@ hid_host_connection_t * btstack_memory_hid_host_connection_get(void){ return NULL; } void btstack_memory_hid_host_connection_free(hid_host_connection_t *hid_host_connection){ - // silence compiler warning about unused parameter in a portable way - (void) hid_host_connection; + UNUSED(hid_host_connection); }; #endif #elif defined(HAVE_MALLOC) + +typedef struct { + btstack_memory_buffer_t tracking; + hid_host_connection_t data; +} btstack_memory_hid_host_connection_t; + hid_host_connection_t * btstack_memory_hid_host_connection_get(void){ - void * buffer = malloc(sizeof(hid_host_connection_t)); + btstack_memory_hid_host_connection_t * buffer = (btstack_memory_hid_host_connection_t *) malloc(sizeof(btstack_memory_hid_host_connection_t)); if (buffer){ - memset(buffer, 0, sizeof(hid_host_connection_t)); + memset(buffer, 0, sizeof(btstack_memory_hid_host_connection_t)); + btstack_memory_tracking_add(&buffer->tracking); + return &buffer->data; + } else { + return NULL; } - return (hid_host_connection_t *) buffer; } void btstack_memory_hid_host_connection_free(hid_host_connection_t *hid_host_connection){ - free(hid_host_connection); + // reconstruct buffer start + btstack_memory_buffer_t * buffer = &((btstack_memory_buffer_t *) hid_host_connection)[-1]; + btstack_memory_tracking_remove(buffer); + free(buffer); } #endif @@ -1026,6 +1037,63 @@ void btstack_memory_avrcp_browsing_connection_free(avrcp_browsing_connection_t * #endif #ifdef ENABLE_BLE +// MARK: battery_service_client_t +#if !defined(HAVE_MALLOC) && !defined(MAX_NR_BATTERY_SERVICE_CLIENTS) + #if defined(MAX_NO_BATTERY_SERVICE_CLIENTS) + #error "Deprecated MAX_NO_BATTERY_SERVICE_CLIENTS defined instead of MAX_NR_BATTERY_SERVICE_CLIENTS. Please update your btstack_config.h to use MAX_NR_BATTERY_SERVICE_CLIENTS." + #else + #define MAX_NR_BATTERY_SERVICE_CLIENTS 0 + #endif +#endif + +#ifdef MAX_NR_BATTERY_SERVICE_CLIENTS +#if MAX_NR_BATTERY_SERVICE_CLIENTS > 0 +static battery_service_client_t battery_service_client_storage[MAX_NR_BATTERY_SERVICE_CLIENTS]; +static btstack_memory_pool_t battery_service_client_pool; +battery_service_client_t * btstack_memory_battery_service_client_get(void){ + void * buffer = btstack_memory_pool_get(&battery_service_client_pool); + if (buffer){ + memset(buffer, 0, sizeof(battery_service_client_t)); + } + return (battery_service_client_t *) buffer; +} +void btstack_memory_battery_service_client_free(battery_service_client_t *battery_service_client){ + btstack_memory_pool_free(&battery_service_client_pool, battery_service_client); +} +#else +battery_service_client_t * btstack_memory_battery_service_client_get(void){ + return NULL; +} +void btstack_memory_battery_service_client_free(battery_service_client_t *battery_service_client){ + UNUSED(battery_service_client); +}; +#endif +#elif defined(HAVE_MALLOC) + +typedef struct { + btstack_memory_buffer_t tracking; + battery_service_client_t data; +} btstack_memory_battery_service_client_t; + +battery_service_client_t * btstack_memory_battery_service_client_get(void){ + btstack_memory_battery_service_client_t * buffer = (btstack_memory_battery_service_client_t *) malloc(sizeof(btstack_memory_battery_service_client_t)); + if (buffer){ + memset(buffer, 0, sizeof(btstack_memory_battery_service_client_t)); + btstack_memory_tracking_add(&buffer->tracking); + return &buffer->data; + } else { + return NULL; + } +} +void btstack_memory_battery_service_client_free(battery_service_client_t *battery_service_client){ + // reconstruct buffer start + btstack_memory_buffer_t * buffer = &((btstack_memory_buffer_t *) battery_service_client)[-1]; + btstack_memory_tracking_remove(buffer); + free(buffer); +} +#endif + + // MARK: gatt_client_t #if !defined(HAVE_MALLOC) && !defined(MAX_NR_GATT_CLIENTS) #if defined(MAX_NO_GATT_CLIENTS) @@ -1083,63 +1151,6 @@ void btstack_memory_gatt_client_free(gatt_client_t *gatt_client){ #endif -// MARK: whitelist_entry_t -#if !defined(HAVE_MALLOC) && !defined(MAX_NR_WHITELIST_ENTRIES) - #if defined(MAX_NO_WHITELIST_ENTRIES) - #error "Deprecated MAX_NO_WHITELIST_ENTRIES defined instead of MAX_NR_WHITELIST_ENTRIES. Please update your btstack_config.h to use MAX_NR_WHITELIST_ENTRIES." - #else - #define MAX_NR_WHITELIST_ENTRIES 0 - #endif -#endif - -#ifdef MAX_NR_WHITELIST_ENTRIES -#if MAX_NR_WHITELIST_ENTRIES > 0 -static whitelist_entry_t whitelist_entry_storage[MAX_NR_WHITELIST_ENTRIES]; -static btstack_memory_pool_t whitelist_entry_pool; -whitelist_entry_t * btstack_memory_whitelist_entry_get(void){ - void * buffer = btstack_memory_pool_get(&whitelist_entry_pool); - if (buffer){ - memset(buffer, 0, sizeof(whitelist_entry_t)); - } - return (whitelist_entry_t *) buffer; -} -void btstack_memory_whitelist_entry_free(whitelist_entry_t *whitelist_entry){ - btstack_memory_pool_free(&whitelist_entry_pool, whitelist_entry); -} -#else -whitelist_entry_t * btstack_memory_whitelist_entry_get(void){ - return NULL; -} -void btstack_memory_whitelist_entry_free(whitelist_entry_t *whitelist_entry){ - UNUSED(whitelist_entry); -}; -#endif -#elif defined(HAVE_MALLOC) - -typedef struct { - btstack_memory_buffer_t tracking; - whitelist_entry_t data; -} btstack_memory_whitelist_entry_t; - -whitelist_entry_t * btstack_memory_whitelist_entry_get(void){ - btstack_memory_whitelist_entry_t * buffer = (btstack_memory_whitelist_entry_t *) malloc(sizeof(btstack_memory_whitelist_entry_t)); - if (buffer){ - memset(buffer, 0, sizeof(btstack_memory_whitelist_entry_t)); - btstack_memory_tracking_add(&buffer->tracking); - return &buffer->data; - } else { - return NULL; - } -} -void btstack_memory_whitelist_entry_free(whitelist_entry_t *whitelist_entry){ - // reconstruct buffer start - btstack_memory_buffer_t * buffer = &((btstack_memory_buffer_t *) whitelist_entry)[-1]; - btstack_memory_tracking_remove(buffer); - free(buffer); -} -#endif - - // MARK: sm_lookup_entry_t #if !defined(HAVE_MALLOC) && !defined(MAX_NR_SM_LOOKUP_ENTRIES) #if defined(MAX_NO_SM_LOOKUP_ENTRIES) @@ -1197,6 +1208,63 @@ void btstack_memory_sm_lookup_entry_free(sm_lookup_entry_t *sm_lookup_entry){ #endif +// MARK: whitelist_entry_t +#if !defined(HAVE_MALLOC) && !defined(MAX_NR_WHITELIST_ENTRIES) + #if defined(MAX_NO_WHITELIST_ENTRIES) + #error "Deprecated MAX_NO_WHITELIST_ENTRIES defined instead of MAX_NR_WHITELIST_ENTRIES. Please update your btstack_config.h to use MAX_NR_WHITELIST_ENTRIES." + #else + #define MAX_NR_WHITELIST_ENTRIES 0 + #endif +#endif + +#ifdef MAX_NR_WHITELIST_ENTRIES +#if MAX_NR_WHITELIST_ENTRIES > 0 +static whitelist_entry_t whitelist_entry_storage[MAX_NR_WHITELIST_ENTRIES]; +static btstack_memory_pool_t whitelist_entry_pool; +whitelist_entry_t * btstack_memory_whitelist_entry_get(void){ + void * buffer = btstack_memory_pool_get(&whitelist_entry_pool); + if (buffer){ + memset(buffer, 0, sizeof(whitelist_entry_t)); + } + return (whitelist_entry_t *) buffer; +} +void btstack_memory_whitelist_entry_free(whitelist_entry_t *whitelist_entry){ + btstack_memory_pool_free(&whitelist_entry_pool, whitelist_entry); +} +#else +whitelist_entry_t * btstack_memory_whitelist_entry_get(void){ + return NULL; +} +void btstack_memory_whitelist_entry_free(whitelist_entry_t *whitelist_entry){ + UNUSED(whitelist_entry); +}; +#endif +#elif defined(HAVE_MALLOC) + +typedef struct { + btstack_memory_buffer_t tracking; + whitelist_entry_t data; +} btstack_memory_whitelist_entry_t; + +whitelist_entry_t * btstack_memory_whitelist_entry_get(void){ + btstack_memory_whitelist_entry_t * buffer = (btstack_memory_whitelist_entry_t *) malloc(sizeof(btstack_memory_whitelist_entry_t)); + if (buffer){ + memset(buffer, 0, sizeof(btstack_memory_whitelist_entry_t)); + btstack_memory_tracking_add(&buffer->tracking); + return &buffer->data; + } else { + return NULL; + } +} +void btstack_memory_whitelist_entry_free(whitelist_entry_t *whitelist_entry){ + // reconstruct buffer start + btstack_memory_buffer_t * buffer = &((btstack_memory_buffer_t *) whitelist_entry)[-1]; + btstack_memory_tracking_remove(buffer); + free(buffer); +} +#endif + + #endif #ifdef ENABLE_MESH @@ -1659,15 +1727,18 @@ void btstack_memory_init(void){ #endif #endif #ifdef ENABLE_BLE +#if MAX_NR_BATTERY_SERVICE_CLIENTS > 0 + btstack_memory_pool_create(&battery_service_client_pool, battery_service_client_storage, MAX_NR_BATTERY_SERVICE_CLIENTS, sizeof(battery_service_client_t)); +#endif #if MAX_NR_GATT_CLIENTS > 0 btstack_memory_pool_create(&gatt_client_pool, gatt_client_storage, MAX_NR_GATT_CLIENTS, sizeof(gatt_client_t)); #endif -#if MAX_NR_WHITELIST_ENTRIES > 0 - btstack_memory_pool_create(&whitelist_entry_pool, whitelist_entry_storage, MAX_NR_WHITELIST_ENTRIES, sizeof(whitelist_entry_t)); -#endif #if MAX_NR_SM_LOOKUP_ENTRIES > 0 btstack_memory_pool_create(&sm_lookup_entry_pool, sm_lookup_entry_storage, MAX_NR_SM_LOOKUP_ENTRIES, sizeof(sm_lookup_entry_t)); #endif +#if MAX_NR_WHITELIST_ENTRIES > 0 + btstack_memory_pool_create(&whitelist_entry_pool, whitelist_entry_storage, MAX_NR_WHITELIST_ENTRIES, sizeof(whitelist_entry_t)); +#endif #endif #ifdef ENABLE_MESH #if MAX_NR_MESH_NETWORK_PDUS > 0 diff --git a/src/btstack_memory.h b/src/btstack_memory.h index 063aa5d14..9e2a3691c 100644 --- a/src/btstack_memory.h +++ b/src/btstack_memory.h @@ -52,11 +52,12 @@ extern "C" { #endif #include "btstack_config.h" - + // Core #include "hci.h" #include "l2cap.h" + // Classic #include "classic/avdtp_sink.h" #include "classic/avdtp_source.h" @@ -69,9 +70,11 @@ extern "C" { #include "classic/rfcomm.h" #include "classic/sdp_server.h" + // BLE #ifdef ENABLE_BLE #include "ble/gatt_client.h" +#include "ble/battery_service_client.h" #include "ble/sm.h" #endif @@ -155,13 +158,15 @@ void btstack_memory_avrcp_browsing_connection_free(avrcp_browsing_connection_t #endif #ifdef ENABLE_BLE -// gatt_client, whitelist_entry, sm_lookup_entry +// battery_service_client, gatt_client, sm_lookup_entry, whitelist_entry +battery_service_client_t * btstack_memory_battery_service_client_get(void); +void btstack_memory_battery_service_client_free(battery_service_client_t *battery_service_client); gatt_client_t * btstack_memory_gatt_client_get(void); void btstack_memory_gatt_client_free(gatt_client_t *gatt_client); -whitelist_entry_t * btstack_memory_whitelist_entry_get(void); -void btstack_memory_whitelist_entry_free(whitelist_entry_t *whitelist_entry); sm_lookup_entry_t * btstack_memory_sm_lookup_entry_get(void); void btstack_memory_sm_lookup_entry_free(sm_lookup_entry_t *sm_lookup_entry); +whitelist_entry_t * btstack_memory_whitelist_entry_get(void); +void btstack_memory_whitelist_entry_free(whitelist_entry_t *whitelist_entry); #endif #ifdef ENABLE_MESH // mesh_network_pdu, mesh_segmented_pdu, mesh_upper_transport_pdu, mesh_network_key, mesh_transport_key, mesh_virtual_address, mesh_subnet diff --git a/test/btstack_memory/btstack_memory_test.c b/test/btstack_memory/btstack_memory_test.c index 433236906..9ee99090f 100644 --- a/test/btstack_memory/btstack_memory_test.c +++ b/test/btstack_memory/btstack_memory_test.c @@ -506,6 +506,48 @@ TEST(btstack_memory, hfp_connection_NotEnoughBuffers){ +TEST(btstack_memory, hid_host_connection_GetAndFree){ + hid_host_connection_t * context; +#ifdef HAVE_MALLOC + context = btstack_memory_hid_host_connection_get(); + CHECK(context != NULL); + btstack_memory_hid_host_connection_free(context); +#else +#ifdef MAX_NR_HID_HOST_CONNECTIONS + // single + context = btstack_memory_hid_host_connection_get(); + CHECK(context != NULL); + btstack_memory_hid_host_connection_free(context); +#else + // none + context = btstack_memory_hid_host_connection_get(); + CHECK(context == NULL); + btstack_memory_hid_host_connection_free(context); +#endif +#endif +} + +TEST(btstack_memory, hid_host_connection_NotEnoughBuffers){ + hid_host_connection_t * context; +#ifdef HAVE_MALLOC + simulate_no_memory = 1; +#else +#ifdef MAX_NR_HID_HOST_CONNECTIONS + int i; + // alloc all static buffers + for (i = 0; i < MAX_NR_HID_HOST_CONNECTIONS; i++){ + context = btstack_memory_hid_host_connection_get(); + CHECK(context != NULL); + } +#endif +#endif + // get one more + context = btstack_memory_hid_host_connection_get(); + CHECK(context == NULL); +} + + + TEST(btstack_memory, service_record_item_GetAndFree){ service_record_item_t * context; #ifdef HAVE_MALLOC @@ -718,6 +760,48 @@ TEST(btstack_memory, avrcp_browsing_connection_NotEnoughBuffers){ #ifdef ENABLE_BLE +TEST(btstack_memory, battery_service_client_GetAndFree){ + battery_service_client_t * context; +#ifdef HAVE_MALLOC + context = btstack_memory_battery_service_client_get(); + CHECK(context != NULL); + btstack_memory_battery_service_client_free(context); +#else +#ifdef MAX_NR_BATTERY_SERVICE_CLIENTS + // single + context = btstack_memory_battery_service_client_get(); + CHECK(context != NULL); + btstack_memory_battery_service_client_free(context); +#else + // none + context = btstack_memory_battery_service_client_get(); + CHECK(context == NULL); + btstack_memory_battery_service_client_free(context); +#endif +#endif +} + +TEST(btstack_memory, battery_service_client_NotEnoughBuffers){ + battery_service_client_t * context; +#ifdef HAVE_MALLOC + simulate_no_memory = 1; +#else +#ifdef MAX_NR_BATTERY_SERVICE_CLIENTS + int i; + // alloc all static buffers + for (i = 0; i < MAX_NR_BATTERY_SERVICE_CLIENTS; i++){ + context = btstack_memory_battery_service_client_get(); + CHECK(context != NULL); + } +#endif +#endif + // get one more + context = btstack_memory_battery_service_client_get(); + CHECK(context == NULL); +} + + + TEST(btstack_memory, gatt_client_GetAndFree){ gatt_client_t * context; #ifdef HAVE_MALLOC @@ -760,48 +844,6 @@ TEST(btstack_memory, gatt_client_NotEnoughBuffers){ -TEST(btstack_memory, whitelist_entry_GetAndFree){ - whitelist_entry_t * context; -#ifdef HAVE_MALLOC - context = btstack_memory_whitelist_entry_get(); - CHECK(context != NULL); - btstack_memory_whitelist_entry_free(context); -#else -#ifdef MAX_NR_WHITELIST_ENTRIES - // single - context = btstack_memory_whitelist_entry_get(); - CHECK(context != NULL); - btstack_memory_whitelist_entry_free(context); -#else - // none - context = btstack_memory_whitelist_entry_get(); - CHECK(context == NULL); - btstack_memory_whitelist_entry_free(context); -#endif -#endif -} - -TEST(btstack_memory, whitelist_entry_NotEnoughBuffers){ - whitelist_entry_t * context; -#ifdef HAVE_MALLOC - simulate_no_memory = 1; -#else -#ifdef MAX_NR_WHITELIST_ENTRIES - int i; - // alloc all static buffers - for (i = 0; i < MAX_NR_WHITELIST_ENTRIES; i++){ - context = btstack_memory_whitelist_entry_get(); - CHECK(context != NULL); - } -#endif -#endif - // get one more - context = btstack_memory_whitelist_entry_get(); - CHECK(context == NULL); -} - - - TEST(btstack_memory, sm_lookup_entry_GetAndFree){ sm_lookup_entry_t * context; #ifdef HAVE_MALLOC @@ -842,6 +884,48 @@ TEST(btstack_memory, sm_lookup_entry_NotEnoughBuffers){ CHECK(context == NULL); } + + +TEST(btstack_memory, whitelist_entry_GetAndFree){ + whitelist_entry_t * context; +#ifdef HAVE_MALLOC + context = btstack_memory_whitelist_entry_get(); + CHECK(context != NULL); + btstack_memory_whitelist_entry_free(context); +#else +#ifdef MAX_NR_WHITELIST_ENTRIES + // single + context = btstack_memory_whitelist_entry_get(); + CHECK(context != NULL); + btstack_memory_whitelist_entry_free(context); +#else + // none + context = btstack_memory_whitelist_entry_get(); + CHECK(context == NULL); + btstack_memory_whitelist_entry_free(context); +#endif +#endif +} + +TEST(btstack_memory, whitelist_entry_NotEnoughBuffers){ + whitelist_entry_t * context; +#ifdef HAVE_MALLOC + simulate_no_memory = 1; +#else +#ifdef MAX_NR_WHITELIST_ENTRIES + int i; + // alloc all static buffers + for (i = 0; i < MAX_NR_WHITELIST_ENTRIES; i++){ + context = btstack_memory_whitelist_entry_get(); + CHECK(context != NULL); + } +#endif +#endif + // get one more + context = btstack_memory_whitelist_entry_get(); + CHECK(context == NULL); +} + #endif #ifdef ENABLE_MESH diff --git a/tool/btstack_memory_generator.py b/tool/btstack_memory_generator.py index c2b291c1b..35703700e 100755 --- a/tool/btstack_memory_generator.py +++ b/tool/btstack_memory_generator.py @@ -80,6 +80,7 @@ extern "C" { // BLE #ifdef ENABLE_BLE #include "ble/gatt_client.h" +#include "ble/battery_service_client.h" #include "ble/sm.h" #endif @@ -292,7 +293,7 @@ list_of_classic_structs = [ ["avrcp_browsing_connection"], ] list_of_le_structs = [ - ["gatt_client", "whitelist_entry", "sm_lookup_entry"], + ["battery_service_client", "gatt_client", "sm_lookup_entry", "whitelist_entry"], ] list_of_mesh_structs = [ ['mesh_network_pdu', 'mesh_segmented_pdu', 'mesh_upper_transport_pdu', 'mesh_network_key', 'mesh_transport_key', 'mesh_virtual_address', 'mesh_subnet']