1 /*
2 * Copyright (C) 2014 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 BLUEKITCHEN
24 * GMBH 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__ "inquiry.c"
39
40 /*
41 * inquiry.c
42 *
43 * basic inquiry scan with remote name lookup
44 */
45
46 #include <unistd.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50
51 #include "btstack_client.h"
52
53 #ifdef _WIN32
54 #include "btstack_run_loop_windows.h"
55 #else
56 #include "btstack_run_loop_posix.h"
57 #endif
58
59 #define MAX_DEVICES 10
60 struct device {
61 bd_addr_t address;
62 uint16_t clockOffset;
63 uint32_t classOfDevice;
64 uint8_t pageScanRepetitionMode;
65 uint8_t rssi;
66 uint8_t state; // 0 empty, 1 found, 2 remote name tried, 3 remote name found
67 };
68
69 #define INQUIRY_INTERVAL 5
70 struct device devices[MAX_DEVICES];
71 int deviceCount = 0;
72
73 enum STATE {INIT, W4_INQUIRY_MODE_COMPLETE, ACTIVE, DEVICE_NAME, REMOTE_NAME_REQUEST, REMOTE_NAME_INQUIRED, REMOTE_NAME_FETCHED} ;
74 enum STATE state = INIT;
75
getDeviceIndexForAddress(bd_addr_t addr)76 int getDeviceIndexForAddress( bd_addr_t addr){
77 int j;
78 for (j=0; j< deviceCount; j++){
79 if (bd_addr_cmp(addr, devices[j].address) == 0){
80 return j;
81 }
82 }
83 return -1;
84 }
85
start_scan(void)86 void start_scan(void){
87 printf("Starting inquiry scan..\n");
88 bt_send_cmd(&hci_inquiry, GAP_IAC_GENERAL_INQUIRY, INQUIRY_INTERVAL, 0);
89 }
90
has_more_remote_name_requests(void)91 int has_more_remote_name_requests(void){
92 int i;
93 for (i=0;i<deviceCount;i++) {
94 if (devices[i].state == REMOTE_NAME_REQUEST) return 1;
95 }
96 return 0;
97 }
98
do_next_remote_name_request(void)99 void do_next_remote_name_request(void){
100 int i;
101 for (i=0;i<deviceCount;i++) {
102 // remote name request
103 if (devices[i].state == REMOTE_NAME_REQUEST){
104 devices[i].state = REMOTE_NAME_INQUIRED;
105 printf("Get remote name of %s...\n", bd_addr_to_str(devices[i].address));
106 bt_send_cmd(&hci_remote_name_request, devices[i].address,
107 devices[i].pageScanRepetitionMode, 0, devices[i].clockOffset | 0x8000);
108 return;
109 }
110 }
111 }
112
113
packet_handler(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)114 static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
115 //static void packet_handler (uint8_t packet_type, uint8_t *packet, uint16_t size){
116 bd_addr_t addr;
117 int i;
118 int index;
119 int numResponses;
120
121 // printf("packet_handler: pt: 0x%02x, packet[0]: 0x%02x\n", packet_type, packet[0]);
122 if (packet_type != HCI_EVENT_PACKET) return;
123
124 uint8_t event = hci_event_packet_get_type(packet);
125
126 switch(state){
127
128 case INIT:
129 if (btstack_event_state_get_state(packet) == HCI_STATE_WORKING){
130 bt_send_cmd(&hci_write_inquiry_mode, 0x01); // with RSSI
131 state = W4_INQUIRY_MODE_COMPLETE;
132 }
133 break;
134
135 case W4_INQUIRY_MODE_COMPLETE:
136 switch(event){
137 case HCI_EVENT_COMMAND_COMPLETE:
138 if (hci_event_command_complete_get_command_opcode(packet) == HCI_OPCODE_HCI_WRITE_INQUIRY_MODE){
139 start_scan();
140 state = ACTIVE;
141 }
142 break;
143 case HCI_EVENT_COMMAND_STATUS:
144 if (hci_event_command_complete_get_command_opcode(packet) == HCI_OPCODE_HCI_WRITE_INQUIRY_MODE){
145 printf("Ignoring error (0x%x) from hci_write_inquiry_mode.\n", packet[2]);
146 start_scan();
147 state = ACTIVE;
148 }
149 break;
150 default:
151 break;
152 }
153
154 break;
155
156 case ACTIVE:
157 switch(event){
158 case HCI_EVENT_INQUIRY_RESULT:
159 case HCI_EVENT_INQUIRY_RESULT_WITH_RSSI:{
160 numResponses = hci_event_inquiry_result_get_num_responses(packet);
161 int offset = 3;
162 for (i=0; i<numResponses && deviceCount < MAX_DEVICES;i++){
163 reverse_bd_addr(&packet[offset], addr);
164 offset += 6;
165 index = getDeviceIndexForAddress(addr);
166 if (index >= 0) continue; // already in our list
167 memcpy(devices[deviceCount].address, addr, 6);
168
169 devices[deviceCount].pageScanRepetitionMode = packet[offset];
170 offset += 1;
171
172 if (event == HCI_EVENT_INQUIRY_RESULT){
173 offset += 2; // Reserved + Reserved
174 devices[deviceCount].classOfDevice = little_endian_read_24(packet, offset);
175 offset += 3;
176 devices[deviceCount].clockOffset = little_endian_read_16(packet, offset) & 0x7fff;
177 offset += 2;
178 devices[deviceCount].rssi = 0;
179 } else {
180 offset += 1; // Reserved
181 devices[deviceCount].classOfDevice = little_endian_read_24(packet, offset);
182 offset += 3;
183 devices[deviceCount].clockOffset = little_endian_read_16(packet, offset) & 0x7fff;
184 offset += 2;
185 devices[deviceCount].rssi = packet[offset];
186 offset += 1;
187 }
188 devices[deviceCount].state = REMOTE_NAME_REQUEST;
189 printf("Device found: %s with COD: 0x%06x, pageScan %d, clock offset 0x%04x, rssi 0x%02x\n", bd_addr_to_str(addr),
190 devices[deviceCount].classOfDevice, devices[deviceCount].pageScanRepetitionMode,
191 devices[deviceCount].clockOffset, devices[deviceCount].rssi);
192 deviceCount++;
193 }
194
195 break;
196 }
197
198 case HCI_EVENT_INQUIRY_COMPLETE:
199 for (i=0;i<deviceCount;i++) {
200 // retry remote name request
201 if (devices[i].state == REMOTE_NAME_INQUIRED)
202 devices[i].state = REMOTE_NAME_REQUEST;
203 }
204 if (has_more_remote_name_requests()){
205 do_next_remote_name_request();
206 break;
207 }
208 start_scan();
209 break;
210
211 case DAEMON_EVENT_REMOTE_NAME_CACHED:
212 reverse_bd_addr(&packet[3], addr);
213 printf("Cached remote name for %s: '%s'\n", bd_addr_to_str(addr), &packet[9]);
214 break;
215
216 case HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE:
217 reverse_bd_addr(&packet[3], addr);
218 index = getDeviceIndexForAddress(addr);
219 if (index >= 0) {
220 if (packet[2] == 0) {
221 printf("Name: '%s'\n", &packet[9]);
222 devices[index].state = REMOTE_NAME_FETCHED;
223 } else {
224 printf("Failed to get name: page timeout\n");
225 }
226 }
227 if (has_more_remote_name_requests()){
228 do_next_remote_name_request();
229 break;
230 }
231 start_scan();
232 break;
233
234 default:
235 break;
236 }
237 break;
238
239 default:
240 break;
241 }
242 }
243
main(int argc,const char * argv[])244 int main (int argc, const char * argv[]){
245 // start stack
246 #ifdef _WIN32
247 btstack_run_loop_init(btstack_run_loop_windows_get_instance());
248 #else
249 btstack_run_loop_init(btstack_run_loop_posix_get_instance());
250 #endif
251 int err = bt_open();
252 if (err) {
253 printf("Failed to open connection to BTdaemon\n");
254 return err;
255 }
256 // init table
257 int i; for (i=0;i<MAX_DEVICES;i++) devices[i].state = 0;
258
259 bt_register_packet_handler(packet_handler);
260 bt_send_cmd(&btstack_set_power_mode, HCI_POWER_ON );
261 btstack_run_loop_execute();
262 bt_close();
263 return 0;
264 }
265