2014-09-26 08:45:34 +00:00
/*
2015-02-06 11:25:18 +00:00
* Copyright ( C ) 2014 BlueKitchen GmbH
2014-09-26 08:45:34 +00:00
*
* 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 .
2015-02-06 11:25:18 +00:00
* 4. Any redistribution , use , or modification is done solely for
* personal benefit and not for any commercial purpose or for
* monetary gain .
2014-09-26 08:45:34 +00:00
*
2015-02-06 11:25:18 +00:00
* THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
2014-09-26 08:45:34 +00:00
* ` ` AS IS ' ' AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT
* LIMITED TO , THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
2021-11-02 09:31:00 +01:00
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED . IN NO EVENT SHALL BLUEKITCHEN
* GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT , INDIRECT ,
2014-09-26 08:45:34 +00:00
* 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 .
*
2015-02-06 11:25:18 +00:00
* Please inquire about commercial licensing options at
* contact @ bluekitchen - gmbh . com
*
2014-09-26 08:45:34 +00:00
*/
2019-05-11 19:31:55 +02:00
# define BTSTACK_FILE__ "gatt_battery_query.c"
2017-03-24 23:39:20 +01:00
2014-10-16 09:15:23 +00:00
// *****************************************************************************
2021-03-05 18:29:49 +01:00
/* EXAMPLE_START(gatt_battery_query): GATT Battery Service Client
2020-10-23 09:54:54 +02:00
*
2021-03-05 18:29:49 +01:00
* @ text This example demonstrates how to use the GATT Battery Service client to
* receive battery level information . The client supports querying of multiple
* battery services instances of on the remote device .
* The example scans for remote devices and connects to the first found device
* and starts the battery service client .
2020-10-23 09:54:54 +02:00
*/
2021-03-05 18:29:49 +01:00
// *****************************************************************************
2014-09-26 08:45:34 +00:00
# include <stdint.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
2016-02-18 16:16:46 +01:00
# include "btstack.h"
2019-03-28 09:52:12 +01:00
// gatt_battery_query.gatt contains the declaration of the provided GATT Services + Characteristics
// gatt_battery_query.h contains the binary representation of gatt_battery_query.gatt
// it is generated by the build system by calling: $BTSTACK_ROOT/tool/compile_gatt.py gatt_battery_query.gatt gatt_battery_query.h
// it needs to be regenerated when the GATT Database declared in gatt_battery_query.gatt file is modified
2017-03-24 14:47:52 +01:00
# include "gatt_battery_query.h"
2014-09-26 08:45:34 +00:00
typedef struct advertising_report {
uint8_t type ;
uint8_t event_type ;
uint8_t address_type ;
bd_addr_t address ;
uint8_t rssi ;
uint8_t length ;
2016-04-01 16:08:15 +02:00
const uint8_t * data ;
2014-09-26 08:45:34 +00:00
} advertising_report_t ;
2021-03-04 10:20:31 +01:00
static enum {
APP_STATE_IDLE ,
APP_STATE_W4_SCAN_RESULT ,
APP_STATE_W4_CONNECT ,
APP_STATE_CONNECTED
} app_state ;
2014-09-26 08:45:34 +00:00
2016-06-03 15:54:29 +02:00
static int blacklist_index = 0 ;
static bd_addr_t blacklist [ 20 ] ;
static advertising_report_t report ;
2021-03-04 10:20:31 +01:00
static hci_con_handle_t connection_handle ;
static uint16_t battery_service_cid ;
2016-02-12 14:22:33 +01:00
2018-07-05 22:13:46 +02:00
static bd_addr_t cmdline_addr ;
2014-09-26 08:45:34 +00:00
static int cmdline_addr_found = 0 ;
2016-02-03 21:55:36 +01:00
static btstack_packet_callback_registration_t hci_event_callback_registration ;
2014-09-26 08:45:34 +00:00
2021-03-05 18:29:49 +01:00
/* @section Main Application Setup
*
* @ text The Listing MainConfiguration shows how to setup Battery Service client .
* Besides calling init ( ) method for each service , you ' ll also need to register HCI packet handler
* to handle advertisements , as well as connect and disconect events .
*
* @ text Handling of GATT Battery Service events will be later delegated to a sepparate packet
* handler , i . e . gatt_client_event_handler .
*
* @ note There are two additional files associated with this client to allow a remote device to query out GATT database :
* - gatt_battary_query . gatt - contains the declaration of the provided GATT Services and Characteristics .
* - gatt_battary_query . h - contains the binary representation of gatt_battary_query . gatt .
*
* gatt_battary_query . h is generated by the build system by calling :
* $ BTSTACK_ROOT / tool / compile_gatt . py gatt_battary_query . gatt gatt_battary_query . h
* This file needs to be regenerated when the GATT Database declared in gatt_battary_query . gatt file is modified .
*/
/* LISTING_START(MainConfiguration): Setup Device Battery Client service */
static void hci_event_handler ( uint8_t packet_type , uint16_t channel , uint8_t * packet , uint16_t size ) ;
static void gatt_client_event_handler ( uint8_t packet_type , uint16_t channel , uint8_t * packet , uint16_t size ) ;
static void battery_service_client_setup ( void ) {
// Init L2CAP
l2cap_init ( ) ;
// Setup ATT server - only needed if LE Peripheral does ATT queries on its own, e.g. Android phones
att_server_init ( profile_data , NULL , NULL ) ;
// GATT Client setup
gatt_client_init ( ) ;
// Device Information Service Client setup
battery_service_client_init ( ) ;
sm_init ( ) ;
sm_set_io_capabilities ( IO_CAPABILITY_NO_INPUT_NO_OUTPUT ) ;
hci_event_callback_registration . callback = & hci_event_handler ;
hci_add_event_handler ( & hci_event_callback_registration ) ;
}
/* LISTING_END */
2016-06-03 15:58:50 +02:00
static int blacklist_size ( void ) {
2016-06-03 15:54:29 +02:00
return sizeof ( blacklist ) / sizeof ( bd_addr_t ) ;
}
static int blacklist_contains ( bd_addr_t addr ) {
int i ;
for ( i = 0 ; i < blacklist_size ( ) ; i + + ) {
if ( bd_addr_cmp ( addr , blacklist [ i ] ) = = 0 ) return 1 ;
}
return 0 ;
}
static void add_to_blacklist ( bd_addr_t addr ) {
2021-03-04 10:36:07 +01:00
printf ( " %s added to blacklist (no battery service found). \n " , bd_addr_to_str ( addr ) ) ;
2016-06-03 15:54:29 +02:00
bd_addr_copy ( blacklist [ blacklist_index ] , addr ) ;
blacklist_index = ( blacklist_index + 1 ) % blacklist_size ( ) ;
}
2021-03-04 10:20:31 +01:00
static void dump_advertising_report ( uint8_t * packet ) {
bd_addr_t address ;
gap_event_advertising_report_get_address ( packet , address ) ;
printf ( " * adv. event: evt-type %u, addr-type %u, addr %s, rssi %u, length adv %u, data: " ,
gap_event_advertising_report_get_advertising_event_type ( packet ) ,
gap_event_advertising_report_get_address_type ( packet ) ,
bd_addr_to_str ( address ) ,
gap_event_advertising_report_get_rssi ( packet ) ,
gap_event_advertising_report_get_data_length ( packet ) ) ;
printf_hexdump ( gap_event_advertising_report_get_data ( packet ) , gap_event_advertising_report_get_data_length ( packet ) ) ;
2014-09-26 08:45:34 +00:00
}
2021-03-05 18:29:49 +01:00
/* LISTING_START(packetHandler): Packet Handler */
2016-02-04 17:45:02 +01:00
static void hci_event_handler ( uint8_t packet_type , uint16_t channel , uint8_t * packet , uint16_t size ) {
2021-03-05 18:29:49 +01:00
/* LISTING_PAUSE */
2016-12-22 22:16:16 +01:00
UNUSED ( channel ) ;
UNUSED ( size ) ;
2021-03-05 18:29:49 +01:00
/* LISTING_RESUME */
2021-03-04 10:20:31 +01:00
bd_addr_t address ;
if ( packet_type ! = HCI_EVENT_PACKET ) {
return ;
}
2021-03-02 15:30:56 +01:00
2021-03-04 10:20:31 +01:00
switch ( hci_event_packet_get_type ( packet ) ) {
2021-03-05 18:29:49 +01:00
/* LISTING_PAUSE */
2014-09-26 08:45:34 +00:00
case BTSTACK_EVENT_STATE :
// BTstack activated, get started
2016-04-01 16:23:28 +02:00
if ( btstack_event_state_get_state ( packet ) ! = HCI_STATE_WORKING ) break ;
2014-09-26 08:45:34 +00:00
if ( cmdline_addr_found ) {
2016-06-03 15:54:29 +02:00
printf ( " Connect to %s \n " , bd_addr_to_str ( cmdline_addr ) ) ;
2021-03-04 10:20:31 +01:00
app_state = APP_STATE_W4_CONNECT ;
2016-02-12 17:04:41 +01:00
gap_connect ( cmdline_addr , 0 ) ;
2014-09-26 08:45:34 +00:00
break ;
}
2016-06-03 15:54:29 +02:00
printf ( " Start scanning! \n " ) ;
2021-03-04 10:20:31 +01:00
app_state = APP_STATE_W4_SCAN_RESULT ;
2016-02-12 17:04:41 +01:00
gap_set_scan_parameters ( 0 , 0x0030 , 0x0030 ) ;
gap_start_scan ( ) ;
2014-09-26 08:45:34 +00:00
break ;
2021-03-04 10:20:31 +01:00
2016-03-07 17:19:53 +01:00
case GAP_EVENT_ADVERTISING_REPORT :
2021-03-04 10:20:31 +01:00
if ( app_state ! = APP_STATE_W4_SCAN_RESULT ) return ;
gap_event_advertising_report_get_address ( packet , address ) ;
if ( blacklist_contains ( address ) ) {
2016-06-03 15:54:29 +02:00
break ;
}
2021-03-04 10:20:31 +01:00
dump_advertising_report ( packet ) ;
2014-09-26 08:45:34 +00:00
// stop scanning, and connect to the device
2021-03-04 10:20:31 +01:00
app_state = APP_STATE_W4_CONNECT ;
2016-02-12 17:04:41 +01:00
gap_stop_scan ( ) ;
2016-06-03 15:54:29 +02:00
printf ( " Stop scan. Connect to device with addr %s. \n " , bd_addr_to_str ( report . address ) ) ;
2016-02-12 17:04:41 +01:00
gap_connect ( report . address , report . address_type ) ;
2014-09-26 08:45:34 +00:00
break ;
2021-03-04 10:20:31 +01:00
2021-03-05 18:29:49 +01:00
/* LISTING_RESUME */
2014-09-26 08:45:34 +00:00
case HCI_EVENT_LE_META :
2021-03-05 18:29:49 +01:00
// Wait for connection complete
2016-04-01 16:28:01 +02:00
if ( hci_event_le_meta_get_subevent_code ( packet ) ! = HCI_SUBEVENT_LE_CONNECTION_COMPLETE ) break ;
2021-03-05 18:29:49 +01:00
/* LISTING_PAUSE */
2021-03-04 10:20:31 +01:00
if ( app_state ! = APP_STATE_W4_CONNECT ) return ;
2021-03-05 18:29:49 +01:00
/* LISTING_RESUME */
// Get connection handle from event
2016-02-19 11:11:57 +01:00
connection_handle = hci_subevent_le_connection_complete_get_connection_handle ( packet ) ;
2021-03-04 10:20:31 +01:00
2021-03-05 18:29:49 +01:00
// Connect to remote Battery Service.
// On succesful connection, the client tries to register for notifications. If notifications
// are not supported by remote Battery Service, the client will automatically poll the battery level - here every 2 seconds.
// If poll_interval_ms is 0, polling is disabled, and only notifications will be received (for manual polling,
// see battery_service_client.h).
// All GATT Battery Service events are handled by the gatt_client_event_handler.
2021-03-08 17:53:00 +01:00
( void ) battery_service_client_connect ( connection_handle , gatt_client_event_handler , 2000 , & battery_service_cid ) ;
2021-03-04 10:20:31 +01:00
app_state = APP_STATE_CONNECTED ;
printf ( " Battery service connected. \n " ) ;
2014-09-26 08:45:34 +00:00
break ;
2021-03-04 10:20:31 +01:00
2014-09-26 08:45:34 +00:00
case HCI_EVENT_DISCONNECTION_COMPLETE :
2019-05-24 09:37:45 +02:00
connection_handle = HCI_CON_HANDLE_INVALID ;
2021-03-04 10:20:31 +01:00
// Disconnect battery service
battery_service_client_disconnect ( battery_service_cid ) ;
2016-06-03 15:54:29 +02:00
2021-03-05 18:29:49 +01:00
/* LISTING_PAUSE */
2016-06-03 15:54:29 +02:00
if ( cmdline_addr_found ) {
2021-03-04 10:20:31 +01:00
printf ( " Disconnected %s \n " , bd_addr_to_str ( cmdline_addr ) ) ;
2017-01-07 21:45:39 +01:00
return ;
2016-06-03 15:54:29 +02:00
}
2021-03-05 18:29:49 +01:00
/* LISTING_RESUME */
2021-03-04 10:20:31 +01:00
printf ( " Disconnected %s \n " , bd_addr_to_str ( report . address ) ) ;
2016-06-03 15:54:29 +02:00
printf ( " Restart scan. \n " ) ;
2021-03-04 10:20:31 +01:00
app_state = APP_STATE_W4_SCAN_RESULT ;
2016-06-03 15:54:29 +02:00
gap_start_scan ( ) ;
2014-09-26 08:45:34 +00:00
break ;
default :
break ;
}
}
2021-03-05 18:29:49 +01:00
/* LISTING_END */
/* LISTING_START(gatt_client_event_handler): GATT Client Event Handler */
// The gatt_client_event_handler receives following events from remote device:
// - GATTSERVICE_SUBEVENT_BATTERY_SERVICE_CONNECTED
// - GATTSERVICE_SUBEVENT_BATTERY_SERVICE_LEVEL
//
static void gatt_client_event_handler ( uint8_t packet_type , uint16_t channel , uint8_t * packet , uint16_t size ) {
/* LISTING_PAUSE */
UNUSED ( packet_type ) ;
UNUSED ( channel ) ;
UNUSED ( size ) ;
/* LISTING_RESUME */
uint8_t status ;
uint8_t att_status ;
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_CONNECTED :
status = gattservice_subevent_battery_service_connected_get_status ( packet ) ;
switch ( status ) {
case ERROR_CODE_SUCCESS :
printf ( " Battery service client connected, found %d services, poll bitmap 0x%02x \n " ,
gattservice_subevent_battery_service_connected_get_num_instances ( packet ) ,
gattservice_subevent_battery_service_connected_get_poll_bitmap ( packet ) ) ;
break ;
default :
2023-01-10 11:32:31 +01:00
printf ( " Battery service client connection failed, status 0x%02x. \n " , status ) ;
2021-03-05 18:29:49 +01:00
add_to_blacklist ( report . address ) ;
gap_disconnect ( connection_handle ) ;
break ;
}
break ;
case GATTSERVICE_SUBEVENT_BATTERY_SERVICE_LEVEL :
att_status = gattservice_subevent_battery_service_level_get_att_status ( packet ) ;
if ( att_status ! = ATT_ERROR_SUCCESS ) {
printf ( " Battery level read failed, ATT Error 0x%02x \n " , att_status ) ;
} else {
printf ( " Service index: %d, Battery level: %d \n " ,
gattservice_subevent_battery_service_level_get_sevice_index ( packet ) ,
gattservice_subevent_battery_service_level_get_level ( packet ) ) ;
}
break ;
default :
break ;
}
}
/* LISTING_END */
2014-09-26 08:45:34 +00:00
2014-11-14 20:42:29 +00:00
int btstack_main ( int argc , const char * argv [ ] ) ;
int btstack_main ( int argc , const char * argv [ ] ) {
2021-03-04 10:20:31 +01:00
// parse address if command line arguments are provided
2014-09-26 08:45:34 +00:00
int arg = 1 ;
cmdline_addr_found = 0 ;
while ( arg < argc ) {
2016-06-03 15:54:29 +02:00
if ( ! strcmp ( argv [ arg ] , " -a " ) | | ! strcmp ( argv [ arg ] , " --address " ) ) {
2014-09-26 08:45:34 +00:00
arg + + ;
2016-06-03 15:54:29 +02:00
cmdline_addr_found = sscanf_bd_addr ( argv [ arg ] , cmdline_addr ) ;
arg + + ;
if ( ! cmdline_addr_found ) exit ( 1 ) ;
2014-09-26 08:45:34 +00:00
continue ;
}
2021-03-04 10:20:31 +01:00
fprintf ( stderr , " \n Usage: %s [-a|--address aa:bb:cc:dd:ee:ff] \n " , argv [ 0 ] ) ;
fprintf ( stderr , " If no argument is provided, GATT browser will start scanning and connect to the first found device. \n To connect to a specific device use argument [-a]. \n \n " ) ;
2014-09-26 08:45:34 +00:00
return 0 ;
2016-06-03 15:54:29 +02:00
}
2017-05-22 22:04:20 +02:00
( void ) argv ;
2021-03-04 10:20:31 +01:00
2021-03-05 18:29:49 +01:00
battery_service_client_setup ( ) ;
2018-08-24 10:03:14 +02:00
2021-03-04 10:20:31 +01:00
app_state = APP_STATE_IDLE ;
2018-08-24 10:03:14 +02:00
2014-09-26 08:45:34 +00:00
// turn on!
hci_power_control ( HCI_POWER_ON ) ;
2015-03-31 14:01:58 +02:00
2014-09-26 08:45:34 +00:00
return 0 ;
}
2020-10-23 09:54:54 +02:00
/* EXAMPLE_END */
2014-09-26 08:45:34 +00:00