| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264 |
- /*
- * Copyright (C) 2014 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__ "gap_inquiry.c"
- // *****************************************************************************
- /* EXAMPLE_START(gap_inquiry): GAP Inquiry Example
- *
- * @text The Generic Access Profile (GAP) defines how Bluetooth devices discover
- * and establish a connection with each other. In this example, the application
- * discovers surrounding Bluetooth devices and collects their Class of Device
- * (CoD), page scan mode, clock offset, and RSSI. After that, the remote name of
- * each device is requested. In the following section we outline the Bluetooth
- * logic part, i.e., how the packet handler handles the asynchronous events and
- * data packets.
- */
- // *****************************************************************************
- #include <stdint.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include "btstack.h"
-
- #define MAX_DEVICES 20
- enum DEVICE_STATE { REMOTE_NAME_REQUEST, REMOTE_NAME_INQUIRED, REMOTE_NAME_FETCHED };
- struct device {
- bd_addr_t address;
- uint8_t pageScanRepetitionMode;
- uint16_t clockOffset;
- enum DEVICE_STATE state;
- };
- #define INQUIRY_INTERVAL 5
- struct device devices[MAX_DEVICES];
- int deviceCount = 0;
- enum STATE {INIT, ACTIVE} ;
- enum STATE state = INIT;
- static btstack_packet_callback_registration_t hci_event_callback_registration;
- static int getDeviceIndexForAddress( bd_addr_t addr){
- int j;
- for (j=0; j< deviceCount; j++){
- if (bd_addr_cmp(addr, devices[j].address) == 0){
- return j;
- }
- }
- return -1;
- }
- static void start_scan(void){
- printf("Starting inquiry scan..\n");
- gap_inquiry_start(INQUIRY_INTERVAL);
- }
- static int has_more_remote_name_requests(void){
- int i;
- for (i=0;i<deviceCount;i++) {
- if (devices[i].state == REMOTE_NAME_REQUEST) return 1;
- }
- return 0;
- }
- static void do_next_remote_name_request(void){
- int i;
- for (i=0;i<deviceCount;i++) {
- // remote name request
- if (devices[i].state == REMOTE_NAME_REQUEST){
- devices[i].state = REMOTE_NAME_INQUIRED;
- printf("Get remote name of %s...\n", bd_addr_to_str(devices[i].address));
- gap_remote_name_request( devices[i].address, devices[i].pageScanRepetitionMode, devices[i].clockOffset | 0x8000);
- return;
- }
- }
- }
- static void continue_remote_names(void){
- if (has_more_remote_name_requests()){
- do_next_remote_name_request();
- return;
- }
- start_scan();
- }
- /* @section Bluetooth Logic
- *
- * @text The Bluetooth logic is implemented as a state machine within the packet
- * handler. In this example, the following states are passed sequentially:
- * INIT, and ACTIVE.
- */
- static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
- UNUSED(channel);
- UNUSED(size);
- bd_addr_t addr;
- int i;
- int index;
-
- if (packet_type != HCI_EVENT_PACKET) return;
- uint8_t event = hci_event_packet_get_type(packet);
- switch(state){
- /* @text In INIT, an inquiry scan is started, and the application transits to
- * ACTIVE state.
- */
- case INIT:
- switch(event){
- case BTSTACK_EVENT_STATE:
- if (btstack_event_state_get_state(packet) == HCI_STATE_WORKING){
- start_scan();
- state = ACTIVE;
- }
- break;
- default:
- break;
- }
- break;
- /* @text In ACTIVE, the following events are processed:
- * - GAP Inquiry result event: BTstack provides a unified inquiry result that contain
- * Class of Device (CoD), page scan mode, clock offset. RSSI and name (from EIR) are optional.
- * - Inquiry complete event: the remote name is requested for devices without a fetched
- * name. The state of a remote name can be one of the following:
- * REMOTE_NAME_REQUEST, REMOTE_NAME_INQUIRED, or REMOTE_NAME_FETCHED.
- * - Remote name request complete event: the remote name is stored in the table and the
- * state is updated to REMOTE_NAME_FETCHED. The query of remote names is continued.
- */
- case ACTIVE:
- switch(event){
- case GAP_EVENT_INQUIRY_RESULT:
- if (deviceCount >= MAX_DEVICES) break; // already full
- gap_event_inquiry_result_get_bd_addr(packet, addr);
- index = getDeviceIndexForAddress(addr);
- if (index >= 0) break; // already in our list
- memcpy(devices[deviceCount].address, addr, 6);
- devices[deviceCount].pageScanRepetitionMode = gap_event_inquiry_result_get_page_scan_repetition_mode(packet);
- devices[deviceCount].clockOffset = gap_event_inquiry_result_get_clock_offset(packet);
- // print info
- printf("Device found: %s ", bd_addr_to_str(addr));
- printf("with COD: 0x%06x, ", (unsigned int) gap_event_inquiry_result_get_class_of_device(packet));
- printf("pageScan %d, ", devices[deviceCount].pageScanRepetitionMode);
- printf("clock offset 0x%04x",devices[deviceCount].clockOffset);
- if (gap_event_inquiry_result_get_rssi_available(packet)){
- printf(", rssi %d dBm", (int8_t) gap_event_inquiry_result_get_rssi(packet));
- }
- if (gap_event_inquiry_result_get_name_available(packet)){
- char name_buffer[240];
- int name_len = gap_event_inquiry_result_get_name_len(packet);
- memcpy(name_buffer, gap_event_inquiry_result_get_name(packet), name_len);
- name_buffer[name_len] = 0;
- printf(", name '%s'", name_buffer);
- devices[deviceCount].state = REMOTE_NAME_FETCHED;;
- } else {
- devices[deviceCount].state = REMOTE_NAME_REQUEST;
- }
- printf("\n");
- deviceCount++;
- break;
- case GAP_EVENT_INQUIRY_COMPLETE:
- for (i=0;i<deviceCount;i++) {
- // retry remote name request
- if (devices[i].state == REMOTE_NAME_INQUIRED)
- devices[i].state = REMOTE_NAME_REQUEST;
- }
- continue_remote_names();
- break;
- case HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE:
- reverse_bd_addr(&packet[3], addr);
- index = getDeviceIndexForAddress(addr);
- if (index >= 0) {
- if (packet[2] == 0) {
- printf("Name: '%s'\n", &packet[9]);
- devices[index].state = REMOTE_NAME_FETCHED;
- } else {
- printf("Failed to get name: page timeout\n");
- }
- }
- continue_remote_names();
- break;
- default:
- break;
- }
- break;
-
- default:
- break;
- }
- }
- /* @text For more details on discovering remote devices, please see
- * Section on [GAP](../profiles/#sec:GAPdiscoverRemoteDevices).
- */
- /* @section Main Application Setup
- *
- * @text Listing MainConfiguration shows main application code.
- * It registers the HCI packet handler and starts the Bluetooth stack.
- */
- /* LISTING_START(MainConfiguration): Setup packet handler for GAP inquiry */
- int btstack_main(int argc, const char * argv[]);
- int btstack_main(int argc, const char * argv[]) {
- (void)argc;
- (void)argv;
- // enabled EIR
- hci_set_inquiry_mode(INQUIRY_MODE_RSSI_AND_EIR);
- hci_event_callback_registration.callback = &packet_handler;
- hci_add_event_handler(&hci_event_callback_registration);
- // turn on!
- hci_power_control(HCI_POWER_ON);
-
- return 0;
- }
- /* LISTING_END */
- /* EXAMPLE_END */
|