うおーるぼっとをiPhoneでコントロールするプログラムです。 iPhoneとはBTLEで接続しています。

Dependencies:   FatFileSystem HighSpeedAnalogIn TB6612FNG2 mbed

Committer:
jksoft
Date:
Fri May 10 11:48:07 2013 +0000
Revision:
0:373bcb197dc8
?????????

Who changed what in which revision?

UserRevisionLine numberNew contents of line
jksoft 0:373bcb197dc8 1 /*
jksoft 0:373bcb197dc8 2 * Copyright (C) 2009-2012 by Matthias Ringwald
jksoft 0:373bcb197dc8 3 *
jksoft 0:373bcb197dc8 4 * Redistribution and use in source and binary forms, with or without
jksoft 0:373bcb197dc8 5 * modification, are permitted provided that the following conditions
jksoft 0:373bcb197dc8 6 * are met:
jksoft 0:373bcb197dc8 7 *
jksoft 0:373bcb197dc8 8 * 1. Redistributions of source code must retain the above copyright
jksoft 0:373bcb197dc8 9 * notice, this list of conditions and the following disclaimer.
jksoft 0:373bcb197dc8 10 * 2. Redistributions in binary form must reproduce the above copyright
jksoft 0:373bcb197dc8 11 * notice, this list of conditions and the following disclaimer in the
jksoft 0:373bcb197dc8 12 * documentation and/or other materials provided with the distribution.
jksoft 0:373bcb197dc8 13 * 3. Neither the name of the copyright holders nor the names of
jksoft 0:373bcb197dc8 14 * contributors may be used to endorse or promote products derived
jksoft 0:373bcb197dc8 15 * from this software without specific prior written permission.
jksoft 0:373bcb197dc8 16 * 4. Any redistribution, use, or modification is done solely for
jksoft 0:373bcb197dc8 17 * personal benefit and not for any commercial purpose or for
jksoft 0:373bcb197dc8 18 * monetary gain.
jksoft 0:373bcb197dc8 19 *
jksoft 0:373bcb197dc8 20 * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
jksoft 0:373bcb197dc8 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
jksoft 0:373bcb197dc8 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
jksoft 0:373bcb197dc8 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
jksoft 0:373bcb197dc8 24 * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
jksoft 0:373bcb197dc8 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
jksoft 0:373bcb197dc8 26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
jksoft 0:373bcb197dc8 27 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
jksoft 0:373bcb197dc8 28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
jksoft 0:373bcb197dc8 29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
jksoft 0:373bcb197dc8 30 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
jksoft 0:373bcb197dc8 31 * SUCH DAMAGE.
jksoft 0:373bcb197dc8 32 *
jksoft 0:373bcb197dc8 33 * Please inquire about commercial licensing options at btstack@ringwald.ch
jksoft 0:373bcb197dc8 34 *
jksoft 0:373bcb197dc8 35 */
jksoft 0:373bcb197dc8 36
jksoft 0:373bcb197dc8 37 /*
jksoft 0:373bcb197dc8 38 * hci.c
jksoft 0:373bcb197dc8 39 *
jksoft 0:373bcb197dc8 40 * Created by Matthias Ringwald on 4/29/09.
jksoft 0:373bcb197dc8 41 *
jksoft 0:373bcb197dc8 42 */
jksoft 0:373bcb197dc8 43
jksoft 0:373bcb197dc8 44 #include "config.h"
jksoft 0:373bcb197dc8 45
jksoft 0:373bcb197dc8 46 #include "hci.h"
jksoft 0:373bcb197dc8 47
jksoft 0:373bcb197dc8 48 #include <stdarg.h>
jksoft 0:373bcb197dc8 49 #include <string.h>
jksoft 0:373bcb197dc8 50 #include <stdio.h>
jksoft 0:373bcb197dc8 51
jksoft 0:373bcb197dc8 52 #ifndef EMBEDDED
jksoft 0:373bcb197dc8 53 #include <unistd.h> // gethostbyname
jksoft 0:373bcb197dc8 54 #include <btstack/version.h>
jksoft 0:373bcb197dc8 55 #endif
jksoft 0:373bcb197dc8 56
jksoft 0:373bcb197dc8 57 #include "btstack_memory.h"
jksoft 0:373bcb197dc8 58 #include "debug.h"
jksoft 0:373bcb197dc8 59 #include "hci_dump.h"
jksoft 0:373bcb197dc8 60
jksoft 0:373bcb197dc8 61 #include <btstack/hci_cmds.h>
jksoft 0:373bcb197dc8 62
jksoft 0:373bcb197dc8 63 #define HCI_CONNECTION_TIMEOUT_MS 10000
jksoft 0:373bcb197dc8 64
jksoft 0:373bcb197dc8 65 #ifdef USE_BLUETOOL
jksoft 0:373bcb197dc8 66 #include "bt_control_iphone.h"
jksoft 0:373bcb197dc8 67 #endif
jksoft 0:373bcb197dc8 68
jksoft 0:373bcb197dc8 69 static void hci_update_scan_enable(void);
jksoft 0:373bcb197dc8 70
jksoft 0:373bcb197dc8 71 // the STACK is here
jksoft 0:373bcb197dc8 72 static hci_stack_t hci_stack;
jksoft 0:373bcb197dc8 73
jksoft 0:373bcb197dc8 74 /**
jksoft 0:373bcb197dc8 75 * get connection for a given handle
jksoft 0:373bcb197dc8 76 *
jksoft 0:373bcb197dc8 77 * @return connection OR NULL, if not found
jksoft 0:373bcb197dc8 78 */
jksoft 0:373bcb197dc8 79 hci_connection_t * connection_for_handle(hci_con_handle_t con_handle){
jksoft 0:373bcb197dc8 80 linked_item_t *it;
jksoft 0:373bcb197dc8 81 for (it = (linked_item_t *) hci_stack.connections; it ; it = it->next){
jksoft 0:373bcb197dc8 82 if ( ((hci_connection_t *) it)->con_handle == con_handle){
jksoft 0:373bcb197dc8 83 return (hci_connection_t *) it;
jksoft 0:373bcb197dc8 84 }
jksoft 0:373bcb197dc8 85 }
jksoft 0:373bcb197dc8 86 return NULL;
jksoft 0:373bcb197dc8 87 }
jksoft 0:373bcb197dc8 88
jksoft 0:373bcb197dc8 89 static void hci_connection_timeout_handler(timer_source_t *timer){
jksoft 0:373bcb197dc8 90 hci_connection_t * connection = (hci_connection_t *) linked_item_get_user(&timer->item);
jksoft 0:373bcb197dc8 91 #ifdef HAVE_TIME
jksoft 0:373bcb197dc8 92 struct timeval tv;
jksoft 0:373bcb197dc8 93 gettimeofday(&tv, NULL);
jksoft 0:373bcb197dc8 94 if (tv.tv_sec >= connection->timestamp.tv_sec + HCI_CONNECTION_TIMEOUT_MS/1000) {
jksoft 0:373bcb197dc8 95 // connections might be timed out
jksoft 0:373bcb197dc8 96 hci_emit_l2cap_check_timeout(connection);
jksoft 0:373bcb197dc8 97 }
jksoft 0:373bcb197dc8 98 #endif
jksoft 0:373bcb197dc8 99 #ifdef HAVE_TICK
jksoft 0:373bcb197dc8 100 if (embedded_get_ticks() > connection->timestamp + embedded_ticks_for_ms(HCI_CONNECTION_TIMEOUT_MS)){
jksoft 0:373bcb197dc8 101 // connections might be timed out
jksoft 0:373bcb197dc8 102 hci_emit_l2cap_check_timeout(connection);
jksoft 0:373bcb197dc8 103 }
jksoft 0:373bcb197dc8 104 #endif
jksoft 0:373bcb197dc8 105 run_loop_set_timer(timer, HCI_CONNECTION_TIMEOUT_MS);
jksoft 0:373bcb197dc8 106 run_loop_add_timer(timer);
jksoft 0:373bcb197dc8 107 }
jksoft 0:373bcb197dc8 108
jksoft 0:373bcb197dc8 109 static void hci_connection_timestamp(hci_connection_t *connection){
jksoft 0:373bcb197dc8 110 #ifdef HAVE_TIME
jksoft 0:373bcb197dc8 111 gettimeofday(&connection->timestamp, NULL);
jksoft 0:373bcb197dc8 112 #endif
jksoft 0:373bcb197dc8 113 #ifdef HAVE_TICK
jksoft 0:373bcb197dc8 114 connection->timestamp = embedded_get_ticks();
jksoft 0:373bcb197dc8 115 #endif
jksoft 0:373bcb197dc8 116 }
jksoft 0:373bcb197dc8 117
jksoft 0:373bcb197dc8 118 /**
jksoft 0:373bcb197dc8 119 * create connection for given address
jksoft 0:373bcb197dc8 120 *
jksoft 0:373bcb197dc8 121 * @return connection OR NULL, if no memory left
jksoft 0:373bcb197dc8 122 */
jksoft 0:373bcb197dc8 123 static hci_connection_t * create_connection_for_addr(bd_addr_t addr){
jksoft 0:373bcb197dc8 124 hci_connection_t * conn = (hci_connection_t *) btstack_memory_hci_connection_get();
jksoft 0:373bcb197dc8 125 if (!conn) return NULL;
jksoft 0:373bcb197dc8 126 BD_ADDR_COPY(conn->address, addr);
jksoft 0:373bcb197dc8 127 conn->con_handle = 0xffff;
jksoft 0:373bcb197dc8 128 conn->authentication_flags = AUTH_FLAGS_NONE;
jksoft 0:373bcb197dc8 129 linked_item_set_user(&conn->timeout.item, conn);
jksoft 0:373bcb197dc8 130 conn->timeout.process = hci_connection_timeout_handler;
jksoft 0:373bcb197dc8 131 hci_connection_timestamp(conn);
jksoft 0:373bcb197dc8 132 conn->acl_recombination_length = 0;
jksoft 0:373bcb197dc8 133 conn->acl_recombination_pos = 0;
jksoft 0:373bcb197dc8 134 conn->num_acl_packets_sent = 0;
jksoft 0:373bcb197dc8 135 linked_list_add(&hci_stack.connections, (linked_item_t *) conn);
jksoft 0:373bcb197dc8 136 return conn;
jksoft 0:373bcb197dc8 137 }
jksoft 0:373bcb197dc8 138
jksoft 0:373bcb197dc8 139 /**
jksoft 0:373bcb197dc8 140 * get connection for given address
jksoft 0:373bcb197dc8 141 *
jksoft 0:373bcb197dc8 142 * @return connection OR NULL, if not found
jksoft 0:373bcb197dc8 143 */
jksoft 0:373bcb197dc8 144 static hci_connection_t * connection_for_address(bd_addr_t address){
jksoft 0:373bcb197dc8 145 linked_item_t *it;
jksoft 0:373bcb197dc8 146 for (it = (linked_item_t *) hci_stack.connections; it ; it = it->next){
jksoft 0:373bcb197dc8 147 if ( ! BD_ADDR_CMP( ((hci_connection_t *) it)->address, address) ){
jksoft 0:373bcb197dc8 148 return (hci_connection_t *) it;
jksoft 0:373bcb197dc8 149 }
jksoft 0:373bcb197dc8 150 }
jksoft 0:373bcb197dc8 151 return NULL;
jksoft 0:373bcb197dc8 152 }
jksoft 0:373bcb197dc8 153
jksoft 0:373bcb197dc8 154 inline static void connectionSetAuthenticationFlags(hci_connection_t * conn, hci_authentication_flags_t flags){
jksoft 0:373bcb197dc8 155 conn->authentication_flags = (hci_authentication_flags_t)(conn->authentication_flags | flags);
jksoft 0:373bcb197dc8 156 }
jksoft 0:373bcb197dc8 157
jksoft 0:373bcb197dc8 158 inline static void connectionClearAuthenticationFlags(hci_connection_t * conn, hci_authentication_flags_t flags){
jksoft 0:373bcb197dc8 159 conn->authentication_flags = (hci_authentication_flags_t)(conn->authentication_flags & ~flags);
jksoft 0:373bcb197dc8 160 }
jksoft 0:373bcb197dc8 161
jksoft 0:373bcb197dc8 162
jksoft 0:373bcb197dc8 163 /**
jksoft 0:373bcb197dc8 164 * add authentication flags and reset timer
jksoft 0:373bcb197dc8 165 */
jksoft 0:373bcb197dc8 166 static void hci_add_connection_flags_for_flipped_bd_addr(uint8_t *bd_addr, hci_authentication_flags_t flags){
jksoft 0:373bcb197dc8 167 bd_addr_t addr;
jksoft 0:373bcb197dc8 168 bt_flip_addr(addr, *(bd_addr_t *) bd_addr);
jksoft 0:373bcb197dc8 169 hci_connection_t * conn = connection_for_address(addr);
jksoft 0:373bcb197dc8 170 if (conn) {
jksoft 0:373bcb197dc8 171 connectionSetAuthenticationFlags(conn, flags);
jksoft 0:373bcb197dc8 172 hci_connection_timestamp(conn);
jksoft 0:373bcb197dc8 173 }
jksoft 0:373bcb197dc8 174 }
jksoft 0:373bcb197dc8 175
jksoft 0:373bcb197dc8 176 int hci_authentication_active_for_handle(hci_con_handle_t handle){
jksoft 0:373bcb197dc8 177 hci_connection_t * conn = connection_for_handle(handle);
jksoft 0:373bcb197dc8 178 if (!conn) return 0;
jksoft 0:373bcb197dc8 179 if (!conn->authentication_flags) return 0;
jksoft 0:373bcb197dc8 180 if (conn->authentication_flags & SENT_LINK_KEY_REPLY) return 0;
jksoft 0:373bcb197dc8 181 if (conn->authentication_flags & RECV_LINK_KEY_NOTIFICATION) return 0;
jksoft 0:373bcb197dc8 182 return 1;
jksoft 0:373bcb197dc8 183 }
jksoft 0:373bcb197dc8 184
jksoft 0:373bcb197dc8 185 void hci_drop_link_key_for_bd_addr(bd_addr_t *addr){
jksoft 0:373bcb197dc8 186 if (hci_stack.remote_device_db) {
jksoft 0:373bcb197dc8 187 hci_stack.remote_device_db->delete_link_key(addr);
jksoft 0:373bcb197dc8 188 }
jksoft 0:373bcb197dc8 189 }
jksoft 0:373bcb197dc8 190
jksoft 0:373bcb197dc8 191
jksoft 0:373bcb197dc8 192 /**
jksoft 0:373bcb197dc8 193 * count connections
jksoft 0:373bcb197dc8 194 */
jksoft 0:373bcb197dc8 195 static int nr_hci_connections(void){
jksoft 0:373bcb197dc8 196 int count = 0;
jksoft 0:373bcb197dc8 197 linked_item_t *it;
jksoft 0:373bcb197dc8 198 for (it = (linked_item_t *) hci_stack.connections; it ; it = it->next, count++);
jksoft 0:373bcb197dc8 199 return count;
jksoft 0:373bcb197dc8 200 }
jksoft 0:373bcb197dc8 201
jksoft 0:373bcb197dc8 202 /**
jksoft 0:373bcb197dc8 203 * Dummy handler called by HCI
jksoft 0:373bcb197dc8 204 */
jksoft 0:373bcb197dc8 205 static void dummy_handler(uint8_t packet_type, uint8_t *packet, uint16_t size){
jksoft 0:373bcb197dc8 206 }
jksoft 0:373bcb197dc8 207
jksoft 0:373bcb197dc8 208 uint8_t hci_number_outgoing_packets(hci_con_handle_t handle){
jksoft 0:373bcb197dc8 209 hci_connection_t * connection = connection_for_handle(handle);
jksoft 0:373bcb197dc8 210 if (!connection) {
jksoft 0:373bcb197dc8 211 log_error("hci_number_outgoing_packets connectino for handle %u does not exist!\n", handle);
jksoft 0:373bcb197dc8 212 return 0;
jksoft 0:373bcb197dc8 213 }
jksoft 0:373bcb197dc8 214 return connection->num_acl_packets_sent;
jksoft 0:373bcb197dc8 215 }
jksoft 0:373bcb197dc8 216
jksoft 0:373bcb197dc8 217 uint8_t hci_number_free_acl_slots(){
jksoft 0:373bcb197dc8 218 uint8_t free_slots = hci_stack.total_num_acl_packets;
jksoft 0:373bcb197dc8 219 linked_item_t *it;
jksoft 0:373bcb197dc8 220 for (it = (linked_item_t *) hci_stack.connections; it ; it = it->next){
jksoft 0:373bcb197dc8 221 hci_connection_t * connection = (hci_connection_t *) it;
jksoft 0:373bcb197dc8 222 if (free_slots < connection->num_acl_packets_sent) {
jksoft 0:373bcb197dc8 223 log_error("hci_number_free_acl_slots: sum of outgoing packets > total acl packets!\n");
jksoft 0:373bcb197dc8 224 return 0;
jksoft 0:373bcb197dc8 225 }
jksoft 0:373bcb197dc8 226 free_slots -= connection->num_acl_packets_sent;
jksoft 0:373bcb197dc8 227 }
jksoft 0:373bcb197dc8 228 return free_slots;
jksoft 0:373bcb197dc8 229 }
jksoft 0:373bcb197dc8 230
jksoft 0:373bcb197dc8 231 int hci_can_send_packet_now(uint8_t packet_type){
jksoft 0:373bcb197dc8 232
jksoft 0:373bcb197dc8 233 // check for async hci transport implementations
jksoft 0:373bcb197dc8 234 if (hci_stack.hci_transport->can_send_packet_now){
jksoft 0:373bcb197dc8 235 if (!hci_stack.hci_transport->can_send_packet_now(packet_type)){
jksoft 0:373bcb197dc8 236 return 0;
jksoft 0:373bcb197dc8 237 }
jksoft 0:373bcb197dc8 238 }
jksoft 0:373bcb197dc8 239
jksoft 0:373bcb197dc8 240 // check regular Bluetooth flow control
jksoft 0:373bcb197dc8 241 switch (packet_type) {
jksoft 0:373bcb197dc8 242 case HCI_ACL_DATA_PACKET:
jksoft 0:373bcb197dc8 243 return hci_number_free_acl_slots();
jksoft 0:373bcb197dc8 244 case HCI_COMMAND_DATA_PACKET:
jksoft 0:373bcb197dc8 245 return hci_stack.num_cmd_packets;
jksoft 0:373bcb197dc8 246 default:
jksoft 0:373bcb197dc8 247 return 0;
jksoft 0:373bcb197dc8 248 }
jksoft 0:373bcb197dc8 249 }
jksoft 0:373bcb197dc8 250
jksoft 0:373bcb197dc8 251 int hci_send_acl_packet(uint8_t *packet, int size){
jksoft 0:373bcb197dc8 252
jksoft 0:373bcb197dc8 253 // check for free places on BT module
jksoft 0:373bcb197dc8 254 if (!hci_number_free_acl_slots()) return BTSTACK_ACL_BUFFERS_FULL;
jksoft 0:373bcb197dc8 255
jksoft 0:373bcb197dc8 256 hci_con_handle_t con_handle = READ_ACL_CONNECTION_HANDLE(packet);
jksoft 0:373bcb197dc8 257 hci_connection_t *connection = connection_for_handle( con_handle);
jksoft 0:373bcb197dc8 258 if (!connection) return 0;
jksoft 0:373bcb197dc8 259 hci_connection_timestamp(connection);
jksoft 0:373bcb197dc8 260
jksoft 0:373bcb197dc8 261 // count packet
jksoft 0:373bcb197dc8 262 connection->num_acl_packets_sent++;
jksoft 0:373bcb197dc8 263 // log_info("hci_send_acl_packet - handle %u, sent %u\n", connection->con_handle, connection->num_acl_packets_sent);
jksoft 0:373bcb197dc8 264
jksoft 0:373bcb197dc8 265 // send packet
jksoft 0:373bcb197dc8 266 int err = hci_stack.hci_transport->send_packet(HCI_ACL_DATA_PACKET, packet, size);
jksoft 0:373bcb197dc8 267
jksoft 0:373bcb197dc8 268 return err;
jksoft 0:373bcb197dc8 269 }
jksoft 0:373bcb197dc8 270
jksoft 0:373bcb197dc8 271 static void acl_handler(uint8_t *packet, int size){
jksoft 0:373bcb197dc8 272
jksoft 0:373bcb197dc8 273 // get info
jksoft 0:373bcb197dc8 274 hci_con_handle_t con_handle = READ_ACL_CONNECTION_HANDLE(packet);
jksoft 0:373bcb197dc8 275 hci_connection_t *conn = connection_for_handle(con_handle);
jksoft 0:373bcb197dc8 276 uint8_t acl_flags = READ_ACL_FLAGS(packet);
jksoft 0:373bcb197dc8 277 uint16_t acl_length = READ_ACL_LENGTH(packet);
jksoft 0:373bcb197dc8 278
jksoft 0:373bcb197dc8 279 // ignore non-registered handle
jksoft 0:373bcb197dc8 280 if (!conn){
jksoft 0:373bcb197dc8 281 log_error( "hci.c: acl_handler called with non-registered handle %u!\n" , con_handle);
jksoft 0:373bcb197dc8 282 return;
jksoft 0:373bcb197dc8 283 }
jksoft 0:373bcb197dc8 284
jksoft 0:373bcb197dc8 285 // update idle timestamp
jksoft 0:373bcb197dc8 286 hci_connection_timestamp(conn);
jksoft 0:373bcb197dc8 287
jksoft 0:373bcb197dc8 288 // handle different packet types
jksoft 0:373bcb197dc8 289 switch (acl_flags & 0x03) {
jksoft 0:373bcb197dc8 290
jksoft 0:373bcb197dc8 291 case 0x01: // continuation fragment
jksoft 0:373bcb197dc8 292
jksoft 0:373bcb197dc8 293 // sanity check
jksoft 0:373bcb197dc8 294 if (conn->acl_recombination_pos == 0) {
jksoft 0:373bcb197dc8 295 log_error( "ACL Cont Fragment but no first fragment for handle 0x%02x\n", con_handle);
jksoft 0:373bcb197dc8 296 return;
jksoft 0:373bcb197dc8 297 }
jksoft 0:373bcb197dc8 298
jksoft 0:373bcb197dc8 299 // append fragment payload (header already stored)
jksoft 0:373bcb197dc8 300 memcpy(&conn->acl_recombination_buffer[conn->acl_recombination_pos], &packet[4], acl_length );
jksoft 0:373bcb197dc8 301 conn->acl_recombination_pos += acl_length;
jksoft 0:373bcb197dc8 302
jksoft 0:373bcb197dc8 303 // log_error( "ACL Cont Fragment: acl_len %u, combined_len %u, l2cap_len %u\n", acl_length,
jksoft 0:373bcb197dc8 304 // conn->acl_recombination_pos, conn->acl_recombination_length);
jksoft 0:373bcb197dc8 305
jksoft 0:373bcb197dc8 306 // forward complete L2CAP packet if complete.
jksoft 0:373bcb197dc8 307 if (conn->acl_recombination_pos >= conn->acl_recombination_length + 4 + 4){ // pos already incl. ACL header
jksoft 0:373bcb197dc8 308
jksoft 0:373bcb197dc8 309 hci_stack.packet_handler(HCI_ACL_DATA_PACKET, conn->acl_recombination_buffer, conn->acl_recombination_pos);
jksoft 0:373bcb197dc8 310 // reset recombination buffer
jksoft 0:373bcb197dc8 311 conn->acl_recombination_length = 0;
jksoft 0:373bcb197dc8 312 conn->acl_recombination_pos = 0;
jksoft 0:373bcb197dc8 313 }
jksoft 0:373bcb197dc8 314 break;
jksoft 0:373bcb197dc8 315
jksoft 0:373bcb197dc8 316 case 0x02: { // first fragment
jksoft 0:373bcb197dc8 317
jksoft 0:373bcb197dc8 318 // sanity check
jksoft 0:373bcb197dc8 319 if (conn->acl_recombination_pos) {
jksoft 0:373bcb197dc8 320 log_error( "ACL First Fragment but data in buffer for handle 0x%02x\n", con_handle);
jksoft 0:373bcb197dc8 321 return;
jksoft 0:373bcb197dc8 322 }
jksoft 0:373bcb197dc8 323
jksoft 0:373bcb197dc8 324 // peek into L2CAP packet!
jksoft 0:373bcb197dc8 325 uint16_t l2cap_length = READ_L2CAP_LENGTH( packet );
jksoft 0:373bcb197dc8 326
jksoft 0:373bcb197dc8 327 // log_error( "ACL First Fragment: acl_len %u, l2cap_len %u\n", acl_length, l2cap_length);
jksoft 0:373bcb197dc8 328
jksoft 0:373bcb197dc8 329 // compare fragment size to L2CAP packet size
jksoft 0:373bcb197dc8 330 if (acl_length >= l2cap_length + 4){
jksoft 0:373bcb197dc8 331
jksoft 0:373bcb197dc8 332 // forward fragment as L2CAP packet
jksoft 0:373bcb197dc8 333 hci_stack.packet_handler(HCI_ACL_DATA_PACKET, packet, acl_length + 4);
jksoft 0:373bcb197dc8 334
jksoft 0:373bcb197dc8 335 } else {
jksoft 0:373bcb197dc8 336 // store first fragment and tweak acl length for complete package
jksoft 0:373bcb197dc8 337 memcpy(conn->acl_recombination_buffer, packet, acl_length + 4);
jksoft 0:373bcb197dc8 338 conn->acl_recombination_pos = acl_length + 4;
jksoft 0:373bcb197dc8 339 conn->acl_recombination_length = l2cap_length;
jksoft 0:373bcb197dc8 340 bt_store_16(conn->acl_recombination_buffer, 2, l2cap_length +4);
jksoft 0:373bcb197dc8 341 }
jksoft 0:373bcb197dc8 342 break;
jksoft 0:373bcb197dc8 343
jksoft 0:373bcb197dc8 344 }
jksoft 0:373bcb197dc8 345 default:
jksoft 0:373bcb197dc8 346 log_error( "hci.c: acl_handler called with invalid packet boundary flags %u\n", acl_flags & 0x03);
jksoft 0:373bcb197dc8 347 return;
jksoft 0:373bcb197dc8 348 }
jksoft 0:373bcb197dc8 349
jksoft 0:373bcb197dc8 350 // execute main loop
jksoft 0:373bcb197dc8 351 hci_run();
jksoft 0:373bcb197dc8 352 }
jksoft 0:373bcb197dc8 353
jksoft 0:373bcb197dc8 354 static void hci_shutdown_connection(hci_connection_t *conn){
jksoft 0:373bcb197dc8 355 log_info("Connection closed: handle %u, %s\n", conn->con_handle, bd_addr_to_str(conn->address));
jksoft 0:373bcb197dc8 356
jksoft 0:373bcb197dc8 357 // cancel all l2cap connections
jksoft 0:373bcb197dc8 358 hci_emit_disconnection_complete(conn->con_handle, 0x16); // terminated by local host
jksoft 0:373bcb197dc8 359
jksoft 0:373bcb197dc8 360 run_loop_remove_timer(&conn->timeout);
jksoft 0:373bcb197dc8 361
jksoft 0:373bcb197dc8 362 linked_list_remove(&hci_stack.connections, (linked_item_t *) conn);
jksoft 0:373bcb197dc8 363 btstack_memory_hci_connection_free( conn );
jksoft 0:373bcb197dc8 364
jksoft 0:373bcb197dc8 365 // now it's gone
jksoft 0:373bcb197dc8 366 hci_emit_nr_connections_changed();
jksoft 0:373bcb197dc8 367 }
jksoft 0:373bcb197dc8 368
jksoft 0:373bcb197dc8 369 static const uint16_t packet_type_sizes[] = {
jksoft 0:373bcb197dc8 370 0, HCI_ACL_2DH1_SIZE, HCI_ACL_3DH1_SIZE, HCI_ACL_DM1_SIZE,
jksoft 0:373bcb197dc8 371 HCI_ACL_DH1_SIZE, 0, 0, 0,
jksoft 0:373bcb197dc8 372 HCI_ACL_2DH3_SIZE, HCI_ACL_3DH3_SIZE, HCI_ACL_DM3_SIZE, HCI_ACL_DH3_SIZE,
jksoft 0:373bcb197dc8 373 HCI_ACL_2DH5_SIZE, HCI_ACL_3DH5_SIZE, HCI_ACL_DM5_SIZE, HCI_ACL_DH5_SIZE
jksoft 0:373bcb197dc8 374 };
jksoft 0:373bcb197dc8 375
jksoft 0:373bcb197dc8 376 static uint16_t hci_acl_packet_types_for_buffer_size(uint16_t buffer_size){
jksoft 0:373bcb197dc8 377 uint16_t packet_types = 0;
jksoft 0:373bcb197dc8 378 int i;
jksoft 0:373bcb197dc8 379 for (i=0;i<16;i++){
jksoft 0:373bcb197dc8 380 if (packet_type_sizes[i] == 0) continue;
jksoft 0:373bcb197dc8 381 if (packet_type_sizes[i] <= buffer_size){
jksoft 0:373bcb197dc8 382 packet_types |= 1 << i;
jksoft 0:373bcb197dc8 383 }
jksoft 0:373bcb197dc8 384 }
jksoft 0:373bcb197dc8 385 // flip bits for "may not be used"
jksoft 0:373bcb197dc8 386 packet_types ^= 0x3306;
jksoft 0:373bcb197dc8 387 return packet_types;
jksoft 0:373bcb197dc8 388 }
jksoft 0:373bcb197dc8 389
jksoft 0:373bcb197dc8 390 uint16_t hci_usable_acl_packet_types(void){
jksoft 0:373bcb197dc8 391 return hci_stack.packet_types;
jksoft 0:373bcb197dc8 392 }
jksoft 0:373bcb197dc8 393
jksoft 0:373bcb197dc8 394 uint8_t* hci_get_outgoing_acl_packet_buffer(void){
jksoft 0:373bcb197dc8 395 // hci packet buffer is >= acl data packet length
jksoft 0:373bcb197dc8 396 return hci_stack.hci_packet_buffer;
jksoft 0:373bcb197dc8 397 }
jksoft 0:373bcb197dc8 398
jksoft 0:373bcb197dc8 399 uint16_t hci_max_acl_data_packet_length(){
jksoft 0:373bcb197dc8 400 return hci_stack.acl_data_packet_length;
jksoft 0:373bcb197dc8 401 }
jksoft 0:373bcb197dc8 402
jksoft 0:373bcb197dc8 403 // avoid huge local variables
jksoft 0:373bcb197dc8 404 #ifndef EMBEDDED
jksoft 0:373bcb197dc8 405 static device_name_t device_name;
jksoft 0:373bcb197dc8 406 #endif
jksoft 0:373bcb197dc8 407 static void event_handler(uint8_t *packet, int size){
jksoft 0:373bcb197dc8 408 bd_addr_t addr;
jksoft 0:373bcb197dc8 409 uint8_t link_type;
jksoft 0:373bcb197dc8 410 hci_con_handle_t handle;
jksoft 0:373bcb197dc8 411 hci_connection_t * conn;
jksoft 0:373bcb197dc8 412 int i;
jksoft 0:373bcb197dc8 413
jksoft 0:373bcb197dc8 414 // printf("HCI:EVENT:%02x\n", packet[0]);
jksoft 0:373bcb197dc8 415
jksoft 0:373bcb197dc8 416 switch (packet[0]) {
jksoft 0:373bcb197dc8 417
jksoft 0:373bcb197dc8 418 case HCI_EVENT_COMMAND_COMPLETE:
jksoft 0:373bcb197dc8 419 // get num cmd packets
jksoft 0:373bcb197dc8 420 // log_info("HCI_EVENT_COMMAND_COMPLETE cmds old %u - new %u\n", hci_stack.num_cmd_packets, packet[2]);
jksoft 0:373bcb197dc8 421 hci_stack.num_cmd_packets = packet[2];
jksoft 0:373bcb197dc8 422
jksoft 0:373bcb197dc8 423 if (COMMAND_COMPLETE_EVENT(packet, hci_read_buffer_size)){
jksoft 0:373bcb197dc8 424 // from offset 5
jksoft 0:373bcb197dc8 425 // status
jksoft 0:373bcb197dc8 426 // "The HC_ACL_Data_Packet_Length return parameter will be used to determine the size of the L2CAP segments contained in ACL Data Packets"
jksoft 0:373bcb197dc8 427 hci_stack.acl_data_packet_length = READ_BT_16(packet, 6);
jksoft 0:373bcb197dc8 428 // ignore: SCO data packet len (8)
jksoft 0:373bcb197dc8 429 hci_stack.total_num_acl_packets = packet[9];
jksoft 0:373bcb197dc8 430 // ignore: total num SCO packets
jksoft 0:373bcb197dc8 431 if (hci_stack.state == HCI_STATE_INITIALIZING){
jksoft 0:373bcb197dc8 432 // determine usable ACL payload size
jksoft 0:373bcb197dc8 433 if (HCI_ACL_PAYLOAD_SIZE < hci_stack.acl_data_packet_length){
jksoft 0:373bcb197dc8 434 hci_stack.acl_data_packet_length = HCI_ACL_PAYLOAD_SIZE;
jksoft 0:373bcb197dc8 435 }
jksoft 0:373bcb197dc8 436 // determine usable ACL packet types
jksoft 0:373bcb197dc8 437 hci_stack.packet_types = hci_acl_packet_types_for_buffer_size(hci_stack.acl_data_packet_length);
jksoft 0:373bcb197dc8 438
jksoft 0:373bcb197dc8 439 log_info("hci_read_buffer_size: used size %u, count %u, packet types %04x\n",
jksoft 0:373bcb197dc8 440 hci_stack.acl_data_packet_length, hci_stack.total_num_acl_packets, hci_stack.packet_types);
jksoft 0:373bcb197dc8 441 }
jksoft 0:373bcb197dc8 442 }
jksoft 0:373bcb197dc8 443 // Dump local address
jksoft 0:373bcb197dc8 444 if (COMMAND_COMPLETE_EVENT(packet, hci_read_bd_addr)) {
jksoft 0:373bcb197dc8 445 bd_addr_t addr;
jksoft 0:373bcb197dc8 446 bt_flip_addr(addr, &packet[OFFSET_OF_DATA_IN_COMMAND_COMPLETE + 1]);
jksoft 0:373bcb197dc8 447 log_info("Local Address, Status: 0x%02x: Addr: %s\n",
jksoft 0:373bcb197dc8 448 packet[OFFSET_OF_DATA_IN_COMMAND_COMPLETE], bd_addr_to_str(addr));
jksoft 0:373bcb197dc8 449 }
jksoft 0:373bcb197dc8 450 if (COMMAND_COMPLETE_EVENT(packet, hci_write_scan_enable)){
jksoft 0:373bcb197dc8 451 hci_emit_discoverable_enabled(hci_stack.discoverable);
jksoft 0:373bcb197dc8 452 }
jksoft 0:373bcb197dc8 453 break;
jksoft 0:373bcb197dc8 454
jksoft 0:373bcb197dc8 455 case HCI_EVENT_COMMAND_STATUS:
jksoft 0:373bcb197dc8 456 // get num cmd packets
jksoft 0:373bcb197dc8 457 // log_info("HCI_EVENT_COMMAND_STATUS cmds - old %u - new %u\n", hci_stack.num_cmd_packets, packet[3]);
jksoft 0:373bcb197dc8 458 hci_stack.num_cmd_packets = packet[3];
jksoft 0:373bcb197dc8 459 break;
jksoft 0:373bcb197dc8 460
jksoft 0:373bcb197dc8 461 case HCI_EVENT_NUMBER_OF_COMPLETED_PACKETS:
jksoft 0:373bcb197dc8 462 for (i=0; i<packet[2];i++){
jksoft 0:373bcb197dc8 463 handle = READ_BT_16(packet, 3 + 2*i);
jksoft 0:373bcb197dc8 464 uint16_t num_packets = READ_BT_16(packet, 3 + packet[2]*2 + 2*i);
jksoft 0:373bcb197dc8 465 conn = connection_for_handle(handle);
jksoft 0:373bcb197dc8 466 if (!conn){
jksoft 0:373bcb197dc8 467 log_error("hci_number_completed_packet lists unused con handle %u\n", handle);
jksoft 0:373bcb197dc8 468 continue;
jksoft 0:373bcb197dc8 469 }
jksoft 0:373bcb197dc8 470 conn->num_acl_packets_sent -= num_packets;
jksoft 0:373bcb197dc8 471 // log_info("hci_number_completed_packet %u processed for handle %u, outstanding %u\n", num_packets, handle, conn->num_acl_packets_sent);
jksoft 0:373bcb197dc8 472 }
jksoft 0:373bcb197dc8 473 break;
jksoft 0:373bcb197dc8 474
jksoft 0:373bcb197dc8 475 case HCI_EVENT_CONNECTION_REQUEST:
jksoft 0:373bcb197dc8 476 bt_flip_addr(addr, &packet[2]);
jksoft 0:373bcb197dc8 477 // TODO: eval COD 8-10
jksoft 0:373bcb197dc8 478 link_type = packet[11];
jksoft 0:373bcb197dc8 479 log_info("Connection_incoming: %s, type %u\n", bd_addr_to_str(addr), link_type);
jksoft 0:373bcb197dc8 480 if (link_type == 1) { // ACL
jksoft 0:373bcb197dc8 481 conn = connection_for_address(addr);
jksoft 0:373bcb197dc8 482 if (!conn) {
jksoft 0:373bcb197dc8 483 conn = create_connection_for_addr(addr);
jksoft 0:373bcb197dc8 484 }
jksoft 0:373bcb197dc8 485 if (!conn) {
jksoft 0:373bcb197dc8 486 // CONNECTION REJECTED DUE TO LIMITED RESOURCES (0X0D)
jksoft 0:373bcb197dc8 487 hci_stack.decline_reason = 0x0d;
jksoft 0:373bcb197dc8 488 BD_ADDR_COPY(hci_stack.decline_addr, addr);
jksoft 0:373bcb197dc8 489 break;
jksoft 0:373bcb197dc8 490 }
jksoft 0:373bcb197dc8 491 conn->state = RECEIVED_CONNECTION_REQUEST;
jksoft 0:373bcb197dc8 492 hci_run();
jksoft 0:373bcb197dc8 493 } else {
jksoft 0:373bcb197dc8 494 // SYNCHRONOUS CONNECTION LIMIT TO A DEVICE EXCEEDED (0X0A)
jksoft 0:373bcb197dc8 495 hci_stack.decline_reason = 0x0a;
jksoft 0:373bcb197dc8 496 BD_ADDR_COPY(hci_stack.decline_addr, addr);
jksoft 0:373bcb197dc8 497 }
jksoft 0:373bcb197dc8 498 break;
jksoft 0:373bcb197dc8 499
jksoft 0:373bcb197dc8 500 case HCI_EVENT_CONNECTION_COMPLETE:
jksoft 0:373bcb197dc8 501 // Connection management
jksoft 0:373bcb197dc8 502 bt_flip_addr(addr, &packet[5]);
jksoft 0:373bcb197dc8 503 log_info("Connection_complete (status=%u) %s\n", packet[2], bd_addr_to_str(addr));
jksoft 0:373bcb197dc8 504 conn = connection_for_address(addr);
jksoft 0:373bcb197dc8 505 if (conn) {
jksoft 0:373bcb197dc8 506 if (!packet[2]){
jksoft 0:373bcb197dc8 507 conn->state = OPEN;
jksoft 0:373bcb197dc8 508 conn->con_handle = READ_BT_16(packet, 3);
jksoft 0:373bcb197dc8 509
jksoft 0:373bcb197dc8 510 // restart timer
jksoft 0:373bcb197dc8 511 run_loop_set_timer(&conn->timeout, HCI_CONNECTION_TIMEOUT_MS);
jksoft 0:373bcb197dc8 512 run_loop_add_timer(&conn->timeout);
jksoft 0:373bcb197dc8 513
jksoft 0:373bcb197dc8 514 log_info("New connection: handle %u, %s\n", conn->con_handle, bd_addr_to_str(conn->address));
jksoft 0:373bcb197dc8 515
jksoft 0:373bcb197dc8 516 hci_emit_nr_connections_changed();
jksoft 0:373bcb197dc8 517 } else {
jksoft 0:373bcb197dc8 518 // connection failed, remove entry
jksoft 0:373bcb197dc8 519 linked_list_remove(&hci_stack.connections, (linked_item_t *) conn);
jksoft 0:373bcb197dc8 520 btstack_memory_hci_connection_free( conn );
jksoft 0:373bcb197dc8 521
jksoft 0:373bcb197dc8 522 // if authentication error, also delete link key
jksoft 0:373bcb197dc8 523 if (packet[2] == 0x05) {
jksoft 0:373bcb197dc8 524 hci_drop_link_key_for_bd_addr(&addr);
jksoft 0:373bcb197dc8 525 }
jksoft 0:373bcb197dc8 526 }
jksoft 0:373bcb197dc8 527 }
jksoft 0:373bcb197dc8 528 break;
jksoft 0:373bcb197dc8 529
jksoft 0:373bcb197dc8 530 case HCI_EVENT_LINK_KEY_REQUEST:
jksoft 0:373bcb197dc8 531 log_info("HCI_EVENT_LINK_KEY_REQUEST\n");
jksoft 0:373bcb197dc8 532 hci_add_connection_flags_for_flipped_bd_addr(&packet[2], RECV_LINK_KEY_REQUEST);
jksoft 0:373bcb197dc8 533 if (!hci_stack.remote_device_db) break;
jksoft 0:373bcb197dc8 534 hci_add_connection_flags_for_flipped_bd_addr(&packet[2], HANDLE_LINK_KEY_REQUEST);
jksoft 0:373bcb197dc8 535 hci_run();
jksoft 0:373bcb197dc8 536 // request handled by hci_run() as HANDLE_LINK_KEY_REQUEST gets set
jksoft 0:373bcb197dc8 537 return;
jksoft 0:373bcb197dc8 538
jksoft 0:373bcb197dc8 539 case HCI_EVENT_LINK_KEY_NOTIFICATION:
jksoft 0:373bcb197dc8 540 hci_add_connection_flags_for_flipped_bd_addr(&packet[2], RECV_LINK_KEY_NOTIFICATION);
jksoft 0:373bcb197dc8 541 if (!hci_stack.remote_device_db) break;
jksoft 0:373bcb197dc8 542 bt_flip_addr(addr, &packet[2]);
jksoft 0:373bcb197dc8 543 hci_stack.remote_device_db->put_link_key(&addr, (link_key_t *) &packet[8]);
jksoft 0:373bcb197dc8 544 // still forward event to allow dismiss of pairing dialog
jksoft 0:373bcb197dc8 545 break;
jksoft 0:373bcb197dc8 546
jksoft 0:373bcb197dc8 547 case HCI_EVENT_PIN_CODE_REQUEST:
jksoft 0:373bcb197dc8 548 hci_add_connection_flags_for_flipped_bd_addr(&packet[2], RECV_PIN_CODE_REQUEST);
jksoft 0:373bcb197dc8 549 // PIN CODE REQUEST means the link key request didn't succee -> delete stored link key
jksoft 0:373bcb197dc8 550 if (!hci_stack.remote_device_db) break;
jksoft 0:373bcb197dc8 551 bt_flip_addr(addr, &packet[2]);
jksoft 0:373bcb197dc8 552 hci_stack.remote_device_db->delete_link_key(&addr);
jksoft 0:373bcb197dc8 553 break;
jksoft 0:373bcb197dc8 554
jksoft 0:373bcb197dc8 555 #ifndef EMBEDDED
jksoft 0:373bcb197dc8 556 case HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE:
jksoft 0:373bcb197dc8 557 if (!hci_stack.remote_device_db) break;
jksoft 0:373bcb197dc8 558 if (packet[2]) break; // status not ok
jksoft 0:373bcb197dc8 559 bt_flip_addr(addr, &packet[3]);
jksoft 0:373bcb197dc8 560 // fix for invalid remote names - terminate on 0xff
jksoft 0:373bcb197dc8 561 for (i=0; i<248;i++){
jksoft 0:373bcb197dc8 562 if (packet[9+i] == 0xff){
jksoft 0:373bcb197dc8 563 packet[9+i] = 0;
jksoft 0:373bcb197dc8 564 break;
jksoft 0:373bcb197dc8 565 }
jksoft 0:373bcb197dc8 566 }
jksoft 0:373bcb197dc8 567 memset(&device_name, 0, sizeof(device_name_t));
jksoft 0:373bcb197dc8 568 strncpy((char*) device_name, (char*) &packet[9], 248);
jksoft 0:373bcb197dc8 569 hci_stack.remote_device_db->put_name(&addr, &device_name);
jksoft 0:373bcb197dc8 570 break;
jksoft 0:373bcb197dc8 571
jksoft 0:373bcb197dc8 572 case HCI_EVENT_INQUIRY_RESULT:
jksoft 0:373bcb197dc8 573 case HCI_EVENT_INQUIRY_RESULT_WITH_RSSI:
jksoft 0:373bcb197dc8 574 if (!hci_stack.remote_device_db) break;
jksoft 0:373bcb197dc8 575 // first send inq result packet
jksoft 0:373bcb197dc8 576 hci_stack.packet_handler(HCI_EVENT_PACKET, packet, size);
jksoft 0:373bcb197dc8 577 // then send cached remote names
jksoft 0:373bcb197dc8 578 for (i=0; i<packet[2];i++){
jksoft 0:373bcb197dc8 579 bt_flip_addr(addr, &packet[3+i*6]);
jksoft 0:373bcb197dc8 580 if (hci_stack.remote_device_db->get_name(&addr, &device_name)){
jksoft 0:373bcb197dc8 581 hci_emit_remote_name_cached(&addr, &device_name);
jksoft 0:373bcb197dc8 582 }
jksoft 0:373bcb197dc8 583 }
jksoft 0:373bcb197dc8 584 return;
jksoft 0:373bcb197dc8 585 #endif
jksoft 0:373bcb197dc8 586
jksoft 0:373bcb197dc8 587 case HCI_EVENT_DISCONNECTION_COMPLETE:
jksoft 0:373bcb197dc8 588 if (!packet[2]){
jksoft 0:373bcb197dc8 589 handle = READ_BT_16(packet, 3);
jksoft 0:373bcb197dc8 590 hci_connection_t * conn = connection_for_handle(handle);
jksoft 0:373bcb197dc8 591 if (conn) {
jksoft 0:373bcb197dc8 592 hci_shutdown_connection(conn);
jksoft 0:373bcb197dc8 593 }
jksoft 0:373bcb197dc8 594 }
jksoft 0:373bcb197dc8 595 break;
jksoft 0:373bcb197dc8 596
jksoft 0:373bcb197dc8 597 case HCI_EVENT_HARDWARE_ERROR:
jksoft 0:373bcb197dc8 598 if(hci_stack.control->hw_error){
jksoft 0:373bcb197dc8 599 (*hci_stack.control->hw_error)();
jksoft 0:373bcb197dc8 600 }
jksoft 0:373bcb197dc8 601 break;
jksoft 0:373bcb197dc8 602
jksoft 0:373bcb197dc8 603 #ifdef HAVE_BLE
jksoft 0:373bcb197dc8 604 case HCI_EVENT_LE_META:
jksoft 0:373bcb197dc8 605 switch (packet[2]) {
jksoft 0:373bcb197dc8 606 case HCI_SUBEVENT_LE_CONNECTION_COMPLETE:
jksoft 0:373bcb197dc8 607 // Connection management
jksoft 0:373bcb197dc8 608 bt_flip_addr(addr, &packet[8]);
jksoft 0:373bcb197dc8 609 log_info("LE Connection_complete (status=%u) %s\n", packet[3], bd_addr_to_str(addr));
jksoft 0:373bcb197dc8 610 // LE connections are auto-accepted, so just create a connection if there isn't one already
jksoft 0:373bcb197dc8 611 conn = connection_for_address(addr);
jksoft 0:373bcb197dc8 612 if (packet[3]){
jksoft 0:373bcb197dc8 613 if (conn){
jksoft 0:373bcb197dc8 614 // outgoing connection failed, remove entry
jksoft 0:373bcb197dc8 615 linked_list_remove(&hci_stack.connections, (linked_item_t *) conn);
jksoft 0:373bcb197dc8 616 btstack_memory_hci_connection_free( conn );
jksoft 0:373bcb197dc8 617
jksoft 0:373bcb197dc8 618 }
jksoft 0:373bcb197dc8 619 // if authentication error, also delete link key
jksoft 0:373bcb197dc8 620 if (packet[3] == 0x05) {
jksoft 0:373bcb197dc8 621 hci_drop_link_key_for_bd_addr(&addr);
jksoft 0:373bcb197dc8 622 }
jksoft 0:373bcb197dc8 623 break;
jksoft 0:373bcb197dc8 624 }
jksoft 0:373bcb197dc8 625 if (!conn){
jksoft 0:373bcb197dc8 626 conn = create_connection_for_addr(addr);
jksoft 0:373bcb197dc8 627 }
jksoft 0:373bcb197dc8 628 if (!conn){
jksoft 0:373bcb197dc8 629 // no memory
jksoft 0:373bcb197dc8 630 break;
jksoft 0:373bcb197dc8 631 }
jksoft 0:373bcb197dc8 632
jksoft 0:373bcb197dc8 633 conn->state = OPEN;
jksoft 0:373bcb197dc8 634 conn->con_handle = READ_BT_16(packet, 4);
jksoft 0:373bcb197dc8 635
jksoft 0:373bcb197dc8 636 // TODO: store - role, peer address type, conn_interval, conn_latency, supervision timeout, master clock
jksoft 0:373bcb197dc8 637
jksoft 0:373bcb197dc8 638 // restart timer
jksoft 0:373bcb197dc8 639 // run_loop_set_timer(&conn->timeout, HCI_CONNECTION_TIMEOUT_MS);
jksoft 0:373bcb197dc8 640 // run_loop_add_timer(&conn->timeout);
jksoft 0:373bcb197dc8 641
jksoft 0:373bcb197dc8 642 log_info("New connection: handle %u, %s\n", conn->con_handle, bd_addr_to_str(conn->address));
jksoft 0:373bcb197dc8 643
jksoft 0:373bcb197dc8 644 hci_emit_nr_connections_changed();
jksoft 0:373bcb197dc8 645 break;
jksoft 0:373bcb197dc8 646
jksoft 0:373bcb197dc8 647 default:
jksoft 0:373bcb197dc8 648 break;
jksoft 0:373bcb197dc8 649 }
jksoft 0:373bcb197dc8 650 break;
jksoft 0:373bcb197dc8 651 #endif
jksoft 0:373bcb197dc8 652
jksoft 0:373bcb197dc8 653 default:
jksoft 0:373bcb197dc8 654 break;
jksoft 0:373bcb197dc8 655 }
jksoft 0:373bcb197dc8 656
jksoft 0:373bcb197dc8 657 // handle BT initialization
jksoft 0:373bcb197dc8 658 if (hci_stack.state == HCI_STATE_INITIALIZING){
jksoft 0:373bcb197dc8 659 // handle H4 synchronization loss on restart
jksoft 0:373bcb197dc8 660 // if (hci_stack.substate == 1 && packet[0] == HCI_EVENT_HARDWARE_ERROR){
jksoft 0:373bcb197dc8 661 // hci_stack.substate = 0;
jksoft 0:373bcb197dc8 662 // }
jksoft 0:373bcb197dc8 663 // handle normal init sequence
jksoft 0:373bcb197dc8 664 if (hci_stack.substate % 2){
jksoft 0:373bcb197dc8 665 // odd: waiting for event
jksoft 0:373bcb197dc8 666 if (packet[0] == HCI_EVENT_COMMAND_COMPLETE){
jksoft 0:373bcb197dc8 667 hci_stack.substate++;
jksoft 0:373bcb197dc8 668 }
jksoft 0:373bcb197dc8 669 }
jksoft 0:373bcb197dc8 670 }
jksoft 0:373bcb197dc8 671
jksoft 0:373bcb197dc8 672 // help with BT sleep
jksoft 0:373bcb197dc8 673 if (hci_stack.state == HCI_STATE_FALLING_ASLEEP
jksoft 0:373bcb197dc8 674 && hci_stack.substate == 1
jksoft 0:373bcb197dc8 675 && COMMAND_COMPLETE_EVENT(packet, hci_write_scan_enable)){
jksoft 0:373bcb197dc8 676 hci_stack.substate++;
jksoft 0:373bcb197dc8 677 }
jksoft 0:373bcb197dc8 678
jksoft 0:373bcb197dc8 679 hci_stack.packet_handler(HCI_EVENT_PACKET, packet, size);
jksoft 0:373bcb197dc8 680
jksoft 0:373bcb197dc8 681 // execute main loop
jksoft 0:373bcb197dc8 682 hci_run();
jksoft 0:373bcb197dc8 683 }
jksoft 0:373bcb197dc8 684
jksoft 0:373bcb197dc8 685 void packet_handler(uint8_t packet_type, uint8_t *packet, uint16_t size){
jksoft 0:373bcb197dc8 686 switch (packet_type) {
jksoft 0:373bcb197dc8 687 case HCI_EVENT_PACKET:
jksoft 0:373bcb197dc8 688 event_handler(packet, size);
jksoft 0:373bcb197dc8 689 break;
jksoft 0:373bcb197dc8 690 case HCI_ACL_DATA_PACKET:
jksoft 0:373bcb197dc8 691 acl_handler(packet, size);
jksoft 0:373bcb197dc8 692 break;
jksoft 0:373bcb197dc8 693 default:
jksoft 0:373bcb197dc8 694 break;
jksoft 0:373bcb197dc8 695 }
jksoft 0:373bcb197dc8 696 }
jksoft 0:373bcb197dc8 697
jksoft 0:373bcb197dc8 698 /** Register HCI packet handlers */
jksoft 0:373bcb197dc8 699 void hci_register_packet_handler(void (*handler)(uint8_t packet_type, uint8_t *packet, uint16_t size)){
jksoft 0:373bcb197dc8 700 hci_stack.packet_handler = handler;
jksoft 0:373bcb197dc8 701 }
jksoft 0:373bcb197dc8 702
jksoft 0:373bcb197dc8 703 void hci_init(hci_transport_t *transport, void *config, bt_control_t *control, remote_device_db_t const* remote_device_db){
jksoft 0:373bcb197dc8 704
jksoft 0:373bcb197dc8 705 // reference to use transport layer implementation
jksoft 0:373bcb197dc8 706 hci_stack.hci_transport = transport;
jksoft 0:373bcb197dc8 707
jksoft 0:373bcb197dc8 708 // references to used control implementation
jksoft 0:373bcb197dc8 709 hci_stack.control = control;
jksoft 0:373bcb197dc8 710
jksoft 0:373bcb197dc8 711 // reference to used config
jksoft 0:373bcb197dc8 712 hci_stack.config = config;
jksoft 0:373bcb197dc8 713
jksoft 0:373bcb197dc8 714 // no connections yet
jksoft 0:373bcb197dc8 715 hci_stack.connections = NULL;
jksoft 0:373bcb197dc8 716 hci_stack.discoverable = 0;
jksoft 0:373bcb197dc8 717 hci_stack.connectable = 0;
jksoft 0:373bcb197dc8 718
jksoft 0:373bcb197dc8 719 // no pending cmds
jksoft 0:373bcb197dc8 720 hci_stack.decline_reason = 0;
jksoft 0:373bcb197dc8 721 hci_stack.new_scan_enable_value = 0xff;
jksoft 0:373bcb197dc8 722
jksoft 0:373bcb197dc8 723 // higher level handler
jksoft 0:373bcb197dc8 724 hci_stack.packet_handler = dummy_handler;
jksoft 0:373bcb197dc8 725
jksoft 0:373bcb197dc8 726 // store and open remote device db
jksoft 0:373bcb197dc8 727 hci_stack.remote_device_db = remote_device_db;
jksoft 0:373bcb197dc8 728 if (hci_stack.remote_device_db) {
jksoft 0:373bcb197dc8 729 hci_stack.remote_device_db->open();
jksoft 0:373bcb197dc8 730 }
jksoft 0:373bcb197dc8 731
jksoft 0:373bcb197dc8 732 // max acl payload size defined in config.h
jksoft 0:373bcb197dc8 733 hci_stack.acl_data_packet_length = HCI_ACL_PAYLOAD_SIZE;
jksoft 0:373bcb197dc8 734
jksoft 0:373bcb197dc8 735 // register packet handlers with transport
jksoft 0:373bcb197dc8 736 transport->register_packet_handler(&packet_handler);
jksoft 0:373bcb197dc8 737
jksoft 0:373bcb197dc8 738 hci_stack.state = HCI_STATE_OFF;
jksoft 0:373bcb197dc8 739 }
jksoft 0:373bcb197dc8 740
jksoft 0:373bcb197dc8 741 void hci_close(){
jksoft 0:373bcb197dc8 742 // close remote device db
jksoft 0:373bcb197dc8 743 if (hci_stack.remote_device_db) {
jksoft 0:373bcb197dc8 744 hci_stack.remote_device_db->close();
jksoft 0:373bcb197dc8 745 }
jksoft 0:373bcb197dc8 746 while (hci_stack.connections) {
jksoft 0:373bcb197dc8 747 hci_shutdown_connection((hci_connection_t *) hci_stack.connections);
jksoft 0:373bcb197dc8 748 }
jksoft 0:373bcb197dc8 749 hci_power_control(HCI_POWER_OFF);
jksoft 0:373bcb197dc8 750 }
jksoft 0:373bcb197dc8 751
jksoft 0:373bcb197dc8 752 // State-Module-Driver overview
jksoft 0:373bcb197dc8 753 // state module low-level
jksoft 0:373bcb197dc8 754 // HCI_STATE_OFF off close
jksoft 0:373bcb197dc8 755 // HCI_STATE_INITIALIZING, on open
jksoft 0:373bcb197dc8 756 // HCI_STATE_WORKING, on open
jksoft 0:373bcb197dc8 757 // HCI_STATE_HALTING, on open
jksoft 0:373bcb197dc8 758 // HCI_STATE_SLEEPING, off/sleep close
jksoft 0:373bcb197dc8 759 // HCI_STATE_FALLING_ASLEEP on open
jksoft 0:373bcb197dc8 760
jksoft 0:373bcb197dc8 761 static int hci_power_control_on(void){
jksoft 0:373bcb197dc8 762
jksoft 0:373bcb197dc8 763 // power on
jksoft 0:373bcb197dc8 764 int err = 0;
jksoft 0:373bcb197dc8 765 if (hci_stack.control && hci_stack.control->on){
jksoft 0:373bcb197dc8 766 err = (*hci_stack.control->on)(hci_stack.config);
jksoft 0:373bcb197dc8 767 }
jksoft 0:373bcb197dc8 768 if (err){
jksoft 0:373bcb197dc8 769 log_error( "POWER_ON failed\n");
jksoft 0:373bcb197dc8 770 hci_emit_hci_open_failed();
jksoft 0:373bcb197dc8 771 return err;
jksoft 0:373bcb197dc8 772 }
jksoft 0:373bcb197dc8 773
jksoft 0:373bcb197dc8 774 // open low-level device
jksoft 0:373bcb197dc8 775 err = hci_stack.hci_transport->open(hci_stack.config);
jksoft 0:373bcb197dc8 776 if (err){
jksoft 0:373bcb197dc8 777 log_error( "HCI_INIT failed, turning Bluetooth off again\n");
jksoft 0:373bcb197dc8 778 if (hci_stack.control && hci_stack.control->off){
jksoft 0:373bcb197dc8 779 (*hci_stack.control->off)(hci_stack.config);
jksoft 0:373bcb197dc8 780 }
jksoft 0:373bcb197dc8 781 hci_emit_hci_open_failed();
jksoft 0:373bcb197dc8 782 return err;
jksoft 0:373bcb197dc8 783 }
jksoft 0:373bcb197dc8 784 return 0;
jksoft 0:373bcb197dc8 785 }
jksoft 0:373bcb197dc8 786
jksoft 0:373bcb197dc8 787 static void hci_power_control_off(void){
jksoft 0:373bcb197dc8 788
jksoft 0:373bcb197dc8 789 log_info("hci_power_control_off\n");
jksoft 0:373bcb197dc8 790
jksoft 0:373bcb197dc8 791 // close low-level device
jksoft 0:373bcb197dc8 792 hci_stack.hci_transport->close(hci_stack.config);
jksoft 0:373bcb197dc8 793
jksoft 0:373bcb197dc8 794 log_info("hci_power_control_off - hci_transport closed\n");
jksoft 0:373bcb197dc8 795
jksoft 0:373bcb197dc8 796 // power off
jksoft 0:373bcb197dc8 797 if (hci_stack.control && hci_stack.control->off){
jksoft 0:373bcb197dc8 798 (*hci_stack.control->off)(hci_stack.config);
jksoft 0:373bcb197dc8 799 }
jksoft 0:373bcb197dc8 800
jksoft 0:373bcb197dc8 801 log_info("hci_power_control_off - control closed\n");
jksoft 0:373bcb197dc8 802
jksoft 0:373bcb197dc8 803 hci_stack.state = HCI_STATE_OFF;
jksoft 0:373bcb197dc8 804 }
jksoft 0:373bcb197dc8 805
jksoft 0:373bcb197dc8 806 static void hci_power_control_sleep(void){
jksoft 0:373bcb197dc8 807
jksoft 0:373bcb197dc8 808 log_info("hci_power_control_sleep\n");
jksoft 0:373bcb197dc8 809
jksoft 0:373bcb197dc8 810 #if 0
jksoft 0:373bcb197dc8 811 // don't close serial port during sleep
jksoft 0:373bcb197dc8 812
jksoft 0:373bcb197dc8 813 // close low-level device
jksoft 0:373bcb197dc8 814 hci_stack.hci_transport->close(hci_stack.config);
jksoft 0:373bcb197dc8 815 #endif
jksoft 0:373bcb197dc8 816
jksoft 0:373bcb197dc8 817 // sleep mode
jksoft 0:373bcb197dc8 818 if (hci_stack.control && hci_stack.control->sleep){
jksoft 0:373bcb197dc8 819 (*hci_stack.control->sleep)(hci_stack.config);
jksoft 0:373bcb197dc8 820 }
jksoft 0:373bcb197dc8 821
jksoft 0:373bcb197dc8 822 hci_stack.state = HCI_STATE_SLEEPING;
jksoft 0:373bcb197dc8 823 }
jksoft 0:373bcb197dc8 824
jksoft 0:373bcb197dc8 825 static int hci_power_control_wake(void){
jksoft 0:373bcb197dc8 826
jksoft 0:373bcb197dc8 827 log_info("hci_power_control_wake\n");
jksoft 0:373bcb197dc8 828
jksoft 0:373bcb197dc8 829 // wake on
jksoft 0:373bcb197dc8 830 if (hci_stack.control && hci_stack.control->wake){
jksoft 0:373bcb197dc8 831 (*hci_stack.control->wake)(hci_stack.config);
jksoft 0:373bcb197dc8 832 }
jksoft 0:373bcb197dc8 833
jksoft 0:373bcb197dc8 834 #if 0
jksoft 0:373bcb197dc8 835 // open low-level device
jksoft 0:373bcb197dc8 836 int err = hci_stack.hci_transport->open(hci_stack.config);
jksoft 0:373bcb197dc8 837 if (err){
jksoft 0:373bcb197dc8 838 log_error( "HCI_INIT failed, turning Bluetooth off again\n");
jksoft 0:373bcb197dc8 839 if (hci_stack.control && hci_stack.control->off){
jksoft 0:373bcb197dc8 840 (*hci_stack.control->off)(hci_stack.config);
jksoft 0:373bcb197dc8 841 }
jksoft 0:373bcb197dc8 842 hci_emit_hci_open_failed();
jksoft 0:373bcb197dc8 843 return err;
jksoft 0:373bcb197dc8 844 }
jksoft 0:373bcb197dc8 845 #endif
jksoft 0:373bcb197dc8 846
jksoft 0:373bcb197dc8 847 return 0;
jksoft 0:373bcb197dc8 848 }
jksoft 0:373bcb197dc8 849
jksoft 0:373bcb197dc8 850
jksoft 0:373bcb197dc8 851 int hci_power_control(HCI_POWER_MODE power_mode){
jksoft 0:373bcb197dc8 852
jksoft 0:373bcb197dc8 853 log_info("hci_power_control: %u, current mode %u\n", power_mode, hci_stack.state);
jksoft 0:373bcb197dc8 854
jksoft 0:373bcb197dc8 855 int err = 0;
jksoft 0:373bcb197dc8 856 switch (hci_stack.state){
jksoft 0:373bcb197dc8 857
jksoft 0:373bcb197dc8 858 case HCI_STATE_OFF:
jksoft 0:373bcb197dc8 859 switch (power_mode){
jksoft 0:373bcb197dc8 860 case HCI_POWER_ON:
jksoft 0:373bcb197dc8 861 err = hci_power_control_on();
jksoft 0:373bcb197dc8 862 if (err) return err;
jksoft 0:373bcb197dc8 863 // set up state machine
jksoft 0:373bcb197dc8 864 hci_stack.num_cmd_packets = 1; // assume that one cmd can be sent
jksoft 0:373bcb197dc8 865 hci_stack.state = HCI_STATE_INITIALIZING;
jksoft 0:373bcb197dc8 866 hci_stack.substate = 0;
jksoft 0:373bcb197dc8 867 break;
jksoft 0:373bcb197dc8 868 case HCI_POWER_OFF:
jksoft 0:373bcb197dc8 869 // do nothing
jksoft 0:373bcb197dc8 870 break;
jksoft 0:373bcb197dc8 871 case HCI_POWER_SLEEP:
jksoft 0:373bcb197dc8 872 // do nothing (with SLEEP == OFF)
jksoft 0:373bcb197dc8 873 break;
jksoft 0:373bcb197dc8 874 }
jksoft 0:373bcb197dc8 875 break;
jksoft 0:373bcb197dc8 876
jksoft 0:373bcb197dc8 877 case HCI_STATE_INITIALIZING:
jksoft 0:373bcb197dc8 878 switch (power_mode){
jksoft 0:373bcb197dc8 879 case HCI_POWER_ON:
jksoft 0:373bcb197dc8 880 // do nothing
jksoft 0:373bcb197dc8 881 break;
jksoft 0:373bcb197dc8 882 case HCI_POWER_OFF:
jksoft 0:373bcb197dc8 883 // no connections yet, just turn it off
jksoft 0:373bcb197dc8 884 hci_power_control_off();
jksoft 0:373bcb197dc8 885 break;
jksoft 0:373bcb197dc8 886 case HCI_POWER_SLEEP:
jksoft 0:373bcb197dc8 887 // no connections yet, just turn it off
jksoft 0:373bcb197dc8 888 hci_power_control_sleep();
jksoft 0:373bcb197dc8 889 break;
jksoft 0:373bcb197dc8 890 }
jksoft 0:373bcb197dc8 891 break;
jksoft 0:373bcb197dc8 892
jksoft 0:373bcb197dc8 893 case HCI_STATE_WORKING:
jksoft 0:373bcb197dc8 894 switch (power_mode){
jksoft 0:373bcb197dc8 895 case HCI_POWER_ON:
jksoft 0:373bcb197dc8 896 // do nothing
jksoft 0:373bcb197dc8 897 break;
jksoft 0:373bcb197dc8 898 case HCI_POWER_OFF:
jksoft 0:373bcb197dc8 899 // see hci_run
jksoft 0:373bcb197dc8 900 hci_stack.state = HCI_STATE_HALTING;
jksoft 0:373bcb197dc8 901 break;
jksoft 0:373bcb197dc8 902 case HCI_POWER_SLEEP:
jksoft 0:373bcb197dc8 903 // see hci_run
jksoft 0:373bcb197dc8 904 hci_stack.state = HCI_STATE_FALLING_ASLEEP;
jksoft 0:373bcb197dc8 905 hci_stack.substate = 0;
jksoft 0:373bcb197dc8 906 break;
jksoft 0:373bcb197dc8 907 }
jksoft 0:373bcb197dc8 908 break;
jksoft 0:373bcb197dc8 909
jksoft 0:373bcb197dc8 910 case HCI_STATE_HALTING:
jksoft 0:373bcb197dc8 911 switch (power_mode){
jksoft 0:373bcb197dc8 912 case HCI_POWER_ON:
jksoft 0:373bcb197dc8 913 // set up state machine
jksoft 0:373bcb197dc8 914 hci_stack.state = HCI_STATE_INITIALIZING;
jksoft 0:373bcb197dc8 915 hci_stack.substate = 0;
jksoft 0:373bcb197dc8 916 break;
jksoft 0:373bcb197dc8 917 case HCI_POWER_OFF:
jksoft 0:373bcb197dc8 918 // do nothing
jksoft 0:373bcb197dc8 919 break;
jksoft 0:373bcb197dc8 920 case HCI_POWER_SLEEP:
jksoft 0:373bcb197dc8 921 // see hci_run
jksoft 0:373bcb197dc8 922 hci_stack.state = HCI_STATE_FALLING_ASLEEP;
jksoft 0:373bcb197dc8 923 hci_stack.substate = 0;
jksoft 0:373bcb197dc8 924 break;
jksoft 0:373bcb197dc8 925 }
jksoft 0:373bcb197dc8 926 break;
jksoft 0:373bcb197dc8 927
jksoft 0:373bcb197dc8 928 case HCI_STATE_FALLING_ASLEEP:
jksoft 0:373bcb197dc8 929 switch (power_mode){
jksoft 0:373bcb197dc8 930 case HCI_POWER_ON:
jksoft 0:373bcb197dc8 931
jksoft 0:373bcb197dc8 932 #if defined(USE_POWERMANAGEMENT) && defined(USE_BLUETOOL)
jksoft 0:373bcb197dc8 933 // nothing to do, if H4 supports power management
jksoft 0:373bcb197dc8 934 if (bt_control_iphone_power_management_enabled()){
jksoft 0:373bcb197dc8 935 hci_stack.state = HCI_STATE_INITIALIZING;
jksoft 0:373bcb197dc8 936 hci_stack.substate = 6;
jksoft 0:373bcb197dc8 937 break;
jksoft 0:373bcb197dc8 938 }
jksoft 0:373bcb197dc8 939 #endif
jksoft 0:373bcb197dc8 940 // set up state machine
jksoft 0:373bcb197dc8 941 hci_stack.num_cmd_packets = 1; // assume that one cmd can be sent
jksoft 0:373bcb197dc8 942 hci_stack.state = HCI_STATE_INITIALIZING;
jksoft 0:373bcb197dc8 943 hci_stack.substate = 0;
jksoft 0:373bcb197dc8 944 break;
jksoft 0:373bcb197dc8 945 case HCI_POWER_OFF:
jksoft 0:373bcb197dc8 946 // see hci_run
jksoft 0:373bcb197dc8 947 hci_stack.state = HCI_STATE_HALTING;
jksoft 0:373bcb197dc8 948 break;
jksoft 0:373bcb197dc8 949 case HCI_POWER_SLEEP:
jksoft 0:373bcb197dc8 950 // do nothing
jksoft 0:373bcb197dc8 951 break;
jksoft 0:373bcb197dc8 952 }
jksoft 0:373bcb197dc8 953 break;
jksoft 0:373bcb197dc8 954
jksoft 0:373bcb197dc8 955 case HCI_STATE_SLEEPING:
jksoft 0:373bcb197dc8 956 switch (power_mode){
jksoft 0:373bcb197dc8 957 case HCI_POWER_ON:
jksoft 0:373bcb197dc8 958
jksoft 0:373bcb197dc8 959 #if defined(USE_POWERMANAGEMENT) && defined(USE_BLUETOOL)
jksoft 0:373bcb197dc8 960 // nothing to do, if H4 supports power management
jksoft 0:373bcb197dc8 961 if (bt_control_iphone_power_management_enabled()){
jksoft 0:373bcb197dc8 962 hci_stack.state = HCI_STATE_INITIALIZING;
jksoft 0:373bcb197dc8 963 hci_stack.substate = 6;
jksoft 0:373bcb197dc8 964 hci_update_scan_enable();
jksoft 0:373bcb197dc8 965 break;
jksoft 0:373bcb197dc8 966 }
jksoft 0:373bcb197dc8 967 #endif
jksoft 0:373bcb197dc8 968 err = hci_power_control_wake();
jksoft 0:373bcb197dc8 969 if (err) return err;
jksoft 0:373bcb197dc8 970 // set up state machine
jksoft 0:373bcb197dc8 971 hci_stack.num_cmd_packets = 1; // assume that one cmd can be sent
jksoft 0:373bcb197dc8 972 hci_stack.state = HCI_STATE_INITIALIZING;
jksoft 0:373bcb197dc8 973 hci_stack.substate = 0;
jksoft 0:373bcb197dc8 974 break;
jksoft 0:373bcb197dc8 975 case HCI_POWER_OFF:
jksoft 0:373bcb197dc8 976 hci_stack.state = HCI_STATE_HALTING;
jksoft 0:373bcb197dc8 977 break;
jksoft 0:373bcb197dc8 978 case HCI_POWER_SLEEP:
jksoft 0:373bcb197dc8 979 // do nothing
jksoft 0:373bcb197dc8 980 break;
jksoft 0:373bcb197dc8 981 }
jksoft 0:373bcb197dc8 982 break;
jksoft 0:373bcb197dc8 983 }
jksoft 0:373bcb197dc8 984
jksoft 0:373bcb197dc8 985 // create internal event
jksoft 0:373bcb197dc8 986 hci_emit_state();
jksoft 0:373bcb197dc8 987
jksoft 0:373bcb197dc8 988 // trigger next/first action
jksoft 0:373bcb197dc8 989 hci_run();
jksoft 0:373bcb197dc8 990
jksoft 0:373bcb197dc8 991 return 0;
jksoft 0:373bcb197dc8 992 }
jksoft 0:373bcb197dc8 993
jksoft 0:373bcb197dc8 994 static void hci_update_scan_enable(void){
jksoft 0:373bcb197dc8 995 // 2 = page scan, 1 = inq scan
jksoft 0:373bcb197dc8 996 hci_stack.new_scan_enable_value = hci_stack.connectable << 1 | hci_stack.discoverable;
jksoft 0:373bcb197dc8 997 hci_run();
jksoft 0:373bcb197dc8 998 }
jksoft 0:373bcb197dc8 999
jksoft 0:373bcb197dc8 1000 void hci_discoverable_control(uint8_t enable){
jksoft 0:373bcb197dc8 1001 if (enable) enable = 1; // normalize argument
jksoft 0:373bcb197dc8 1002
jksoft 0:373bcb197dc8 1003 if (hci_stack.discoverable == enable){
jksoft 0:373bcb197dc8 1004 hci_emit_discoverable_enabled(hci_stack.discoverable);
jksoft 0:373bcb197dc8 1005 return;
jksoft 0:373bcb197dc8 1006 }
jksoft 0:373bcb197dc8 1007
jksoft 0:373bcb197dc8 1008 hci_stack.discoverable = enable;
jksoft 0:373bcb197dc8 1009 hci_update_scan_enable();
jksoft 0:373bcb197dc8 1010 }
jksoft 0:373bcb197dc8 1011
jksoft 0:373bcb197dc8 1012 void hci_connectable_control(uint8_t enable){
jksoft 0:373bcb197dc8 1013 if (enable) enable = 1; // normalize argument
jksoft 0:373bcb197dc8 1014
jksoft 0:373bcb197dc8 1015 // don't emit event
jksoft 0:373bcb197dc8 1016 if (hci_stack.connectable == enable) return;
jksoft 0:373bcb197dc8 1017
jksoft 0:373bcb197dc8 1018 hci_stack.connectable = enable;
jksoft 0:373bcb197dc8 1019 hci_update_scan_enable();
jksoft 0:373bcb197dc8 1020 }
jksoft 0:373bcb197dc8 1021
jksoft 0:373bcb197dc8 1022 void hci_run(){
jksoft 0:373bcb197dc8 1023
jksoft 0:373bcb197dc8 1024 hci_connection_t * connection;
jksoft 0:373bcb197dc8 1025 linked_item_t * it;
jksoft 0:373bcb197dc8 1026
jksoft 0:373bcb197dc8 1027 if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return;
jksoft 0:373bcb197dc8 1028
jksoft 0:373bcb197dc8 1029 // global/non-connection oriented commands
jksoft 0:373bcb197dc8 1030
jksoft 0:373bcb197dc8 1031 // decline incoming connections
jksoft 0:373bcb197dc8 1032 if (hci_stack.decline_reason){
jksoft 0:373bcb197dc8 1033 uint8_t reason = hci_stack.decline_reason;
jksoft 0:373bcb197dc8 1034 hci_stack.decline_reason = 0;
jksoft 0:373bcb197dc8 1035 hci_send_cmd(&hci_reject_connection_request, hci_stack.decline_addr, reason);
jksoft 0:373bcb197dc8 1036 }
jksoft 0:373bcb197dc8 1037
jksoft 0:373bcb197dc8 1038 if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return;
jksoft 0:373bcb197dc8 1039
jksoft 0:373bcb197dc8 1040 // send scan enable
jksoft 0:373bcb197dc8 1041 if (hci_stack.state == HCI_STATE_WORKING && hci_stack.new_scan_enable_value != 0xff){
jksoft 0:373bcb197dc8 1042 hci_send_cmd(&hci_write_scan_enable, hci_stack.new_scan_enable_value);
jksoft 0:373bcb197dc8 1043 hci_stack.new_scan_enable_value = 0xff;
jksoft 0:373bcb197dc8 1044 }
jksoft 0:373bcb197dc8 1045
jksoft 0:373bcb197dc8 1046 // send pending HCI commands
jksoft 0:373bcb197dc8 1047 for (it = (linked_item_t *) hci_stack.connections; it ; it = it->next){
jksoft 0:373bcb197dc8 1048
jksoft 0:373bcb197dc8 1049 if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return;
jksoft 0:373bcb197dc8 1050
jksoft 0:373bcb197dc8 1051 connection = (hci_connection_t *) it;
jksoft 0:373bcb197dc8 1052
jksoft 0:373bcb197dc8 1053 if (connection->state == RECEIVED_CONNECTION_REQUEST){
jksoft 0:373bcb197dc8 1054 log_info("sending hci_accept_connection_request\n");
jksoft 0:373bcb197dc8 1055 hci_send_cmd(&hci_accept_connection_request, connection->address, 1);
jksoft 0:373bcb197dc8 1056 connection->state = ACCEPTED_CONNECTION_REQUEST;
jksoft 0:373bcb197dc8 1057 }
jksoft 0:373bcb197dc8 1058
jksoft 0:373bcb197dc8 1059 if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return;
jksoft 0:373bcb197dc8 1060
jksoft 0:373bcb197dc8 1061 if (connection->authentication_flags & HANDLE_LINK_KEY_REQUEST){
jksoft 0:373bcb197dc8 1062 link_key_t link_key;
jksoft 0:373bcb197dc8 1063 log_info("responding to link key request\n");
jksoft 0:373bcb197dc8 1064 if ( hci_stack.remote_device_db->get_link_key( &connection->address, &link_key)){
jksoft 0:373bcb197dc8 1065 hci_send_cmd(&hci_link_key_request_reply, connection->address, &link_key);
jksoft 0:373bcb197dc8 1066 } else {
jksoft 0:373bcb197dc8 1067 hci_send_cmd(&hci_link_key_request_negative_reply, connection->address);
jksoft 0:373bcb197dc8 1068 }
jksoft 0:373bcb197dc8 1069 connectionClearAuthenticationFlags(connection, HANDLE_LINK_KEY_REQUEST);
jksoft 0:373bcb197dc8 1070 }
jksoft 0:373bcb197dc8 1071 }
jksoft 0:373bcb197dc8 1072
jksoft 0:373bcb197dc8 1073 if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return;
jksoft 0:373bcb197dc8 1074
jksoft 0:373bcb197dc8 1075 switch (hci_stack.state){
jksoft 0:373bcb197dc8 1076 case HCI_STATE_INITIALIZING:
jksoft 0:373bcb197dc8 1077 // log_info("hci_init: substate %u\n", hci_stack.substate);
jksoft 0:373bcb197dc8 1078 if (hci_stack.substate % 2) {
jksoft 0:373bcb197dc8 1079 // odd: waiting for command completion
jksoft 0:373bcb197dc8 1080 return;
jksoft 0:373bcb197dc8 1081 }
jksoft 0:373bcb197dc8 1082 switch (hci_stack.substate >> 1){
jksoft 0:373bcb197dc8 1083 case 0: // RESET
jksoft 0:373bcb197dc8 1084 hci_send_cmd(&hci_reset);
jksoft 0:373bcb197dc8 1085 if (hci_stack.config == 0 || ((hci_uart_config_t *)hci_stack.config)->baudrate_main == 0){
jksoft 0:373bcb197dc8 1086 // skip baud change
jksoft 0:373bcb197dc8 1087 hci_stack.substate = 4; // >> 1 = 2
jksoft 0:373bcb197dc8 1088 }
jksoft 0:373bcb197dc8 1089 break;
jksoft 0:373bcb197dc8 1090 case 1: // SEND BAUD CHANGE
jksoft 0:373bcb197dc8 1091 hci_stack.control->baudrate_cmd(hci_stack.config, ((hci_uart_config_t *)hci_stack.config)->baudrate_main, hci_stack.hci_packet_buffer);
jksoft 0:373bcb197dc8 1092 hci_send_cmd_packet(hci_stack.hci_packet_buffer, 3 + hci_stack.hci_packet_buffer[2]);
jksoft 0:373bcb197dc8 1093 break;
jksoft 0:373bcb197dc8 1094 case 2: // LOCAL BAUD CHANGE
jksoft 0:373bcb197dc8 1095 hci_stack.hci_transport->set_baudrate(((hci_uart_config_t *)hci_stack.config)->baudrate_main);
jksoft 0:373bcb197dc8 1096 hci_stack.substate += 2;
jksoft 0:373bcb197dc8 1097 // break missing here for fall through
jksoft 0:373bcb197dc8 1098
jksoft 0:373bcb197dc8 1099 case 3:
jksoft 0:373bcb197dc8 1100 // custom initialization
jksoft 0:373bcb197dc8 1101 if (hci_stack.control && hci_stack.control->next_cmd){
jksoft 0:373bcb197dc8 1102 int valid_cmd = (*hci_stack.control->next_cmd)(hci_stack.config, hci_stack.hci_packet_buffer);
jksoft 0:373bcb197dc8 1103 if (valid_cmd){
jksoft 0:373bcb197dc8 1104 int size = 3 + hci_stack.hci_packet_buffer[2];
jksoft 0:373bcb197dc8 1105 hci_stack.hci_transport->send_packet(HCI_COMMAND_DATA_PACKET, hci_stack.hci_packet_buffer, size);
jksoft 0:373bcb197dc8 1106 hci_stack.substate = 4; // more init commands
jksoft 0:373bcb197dc8 1107 break;
jksoft 0:373bcb197dc8 1108 }
jksoft 0:373bcb197dc8 1109 log_info("hci_run: init script done\n\r");
jksoft 0:373bcb197dc8 1110 }
jksoft 0:373bcb197dc8 1111 // otherwise continue
jksoft 0:373bcb197dc8 1112 hci_send_cmd(&hci_read_bd_addr);
jksoft 0:373bcb197dc8 1113 break;
jksoft 0:373bcb197dc8 1114 case 4:
jksoft 0:373bcb197dc8 1115 hci_send_cmd(&hci_read_buffer_size);
jksoft 0:373bcb197dc8 1116 break;
jksoft 0:373bcb197dc8 1117 case 5:
jksoft 0:373bcb197dc8 1118 // ca. 15 sec
jksoft 0:373bcb197dc8 1119 hci_send_cmd(&hci_write_page_timeout, 0x6000);
jksoft 0:373bcb197dc8 1120 break;
jksoft 0:373bcb197dc8 1121 case 6:
jksoft 0:373bcb197dc8 1122 hci_send_cmd(&hci_write_scan_enable, (hci_stack.connectable << 1) | hci_stack.discoverable); // page scan
jksoft 0:373bcb197dc8 1123 break;
jksoft 0:373bcb197dc8 1124 case 7:
jksoft 0:373bcb197dc8 1125 #ifndef EMBEDDED
jksoft 0:373bcb197dc8 1126 {
jksoft 0:373bcb197dc8 1127 char hostname[30];
jksoft 0:373bcb197dc8 1128 gethostname(hostname, 30);
jksoft 0:373bcb197dc8 1129 hostname[29] = '\0';
jksoft 0:373bcb197dc8 1130 hci_send_cmd(&hci_write_local_name, hostname);
jksoft 0:373bcb197dc8 1131 break;
jksoft 0:373bcb197dc8 1132 }
jksoft 0:373bcb197dc8 1133 case 8:
jksoft 0:373bcb197dc8 1134 #ifdef USE_BLUETOOL
jksoft 0:373bcb197dc8 1135 hci_send_cmd(&hci_write_class_of_device, 0x007a020c); // Smartphone
jksoft 0:373bcb197dc8 1136 break;
jksoft 0:373bcb197dc8 1137
jksoft 0:373bcb197dc8 1138 case 9:
jksoft 0:373bcb197dc8 1139 #endif
jksoft 0:373bcb197dc8 1140 #endif
jksoft 0:373bcb197dc8 1141 // done.
jksoft 0:373bcb197dc8 1142 hci_stack.state = HCI_STATE_WORKING;
jksoft 0:373bcb197dc8 1143 hci_emit_state();
jksoft 0:373bcb197dc8 1144 break;
jksoft 0:373bcb197dc8 1145 default:
jksoft 0:373bcb197dc8 1146 break;
jksoft 0:373bcb197dc8 1147 }
jksoft 0:373bcb197dc8 1148 hci_stack.substate++;
jksoft 0:373bcb197dc8 1149 break;
jksoft 0:373bcb197dc8 1150
jksoft 0:373bcb197dc8 1151 case HCI_STATE_HALTING:
jksoft 0:373bcb197dc8 1152
jksoft 0:373bcb197dc8 1153 log_info("HCI_STATE_HALTING\n");
jksoft 0:373bcb197dc8 1154 // close all open connections
jksoft 0:373bcb197dc8 1155 connection = (hci_connection_t *) hci_stack.connections;
jksoft 0:373bcb197dc8 1156 if (connection){
jksoft 0:373bcb197dc8 1157
jksoft 0:373bcb197dc8 1158 // send disconnect
jksoft 0:373bcb197dc8 1159 if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return;
jksoft 0:373bcb197dc8 1160
jksoft 0:373bcb197dc8 1161 log_info("HCI_STATE_HALTING, connection %p, handle %u\n", connection, (uint16_t)connection->con_handle);
jksoft 0:373bcb197dc8 1162 hci_send_cmd(&hci_disconnect, connection->con_handle, 0x13); // remote closed connection
jksoft 0:373bcb197dc8 1163
jksoft 0:373bcb197dc8 1164 // send disconnected event right away - causes higher layer connections to get closed, too.
jksoft 0:373bcb197dc8 1165 hci_shutdown_connection(connection);
jksoft 0:373bcb197dc8 1166 return;
jksoft 0:373bcb197dc8 1167 }
jksoft 0:373bcb197dc8 1168 log_info("HCI_STATE_HALTING, calling off\n");
jksoft 0:373bcb197dc8 1169
jksoft 0:373bcb197dc8 1170 // switch mode
jksoft 0:373bcb197dc8 1171 hci_power_control_off();
jksoft 0:373bcb197dc8 1172
jksoft 0:373bcb197dc8 1173 log_info("HCI_STATE_HALTING, emitting state\n");
jksoft 0:373bcb197dc8 1174 hci_emit_state();
jksoft 0:373bcb197dc8 1175 log_info("HCI_STATE_HALTING, done\n");
jksoft 0:373bcb197dc8 1176 break;
jksoft 0:373bcb197dc8 1177
jksoft 0:373bcb197dc8 1178 case HCI_STATE_FALLING_ASLEEP:
jksoft 0:373bcb197dc8 1179 switch(hci_stack.substate) {
jksoft 0:373bcb197dc8 1180 case 0:
jksoft 0:373bcb197dc8 1181 log_info("HCI_STATE_FALLING_ASLEEP\n");
jksoft 0:373bcb197dc8 1182 // close all open connections
jksoft 0:373bcb197dc8 1183 connection = (hci_connection_t *) hci_stack.connections;
jksoft 0:373bcb197dc8 1184
jksoft 0:373bcb197dc8 1185 #if defined(USE_POWERMANAGEMENT) && defined(USE_BLUETOOL)
jksoft 0:373bcb197dc8 1186 // don't close connections, if H4 supports power management
jksoft 0:373bcb197dc8 1187 if (bt_control_iphone_power_management_enabled()){
jksoft 0:373bcb197dc8 1188 connection = NULL;
jksoft 0:373bcb197dc8 1189 }
jksoft 0:373bcb197dc8 1190 #endif
jksoft 0:373bcb197dc8 1191 if (connection){
jksoft 0:373bcb197dc8 1192
jksoft 0:373bcb197dc8 1193 // send disconnect
jksoft 0:373bcb197dc8 1194 if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return;
jksoft 0:373bcb197dc8 1195
jksoft 0:373bcb197dc8 1196 log_info("HCI_STATE_FALLING_ASLEEP, connection %p, handle %u\n", connection, (uint16_t)connection->con_handle);
jksoft 0:373bcb197dc8 1197 hci_send_cmd(&hci_disconnect, connection->con_handle, 0x13); // remote closed connection
jksoft 0:373bcb197dc8 1198
jksoft 0:373bcb197dc8 1199 // send disconnected event right away - causes higher layer connections to get closed, too.
jksoft 0:373bcb197dc8 1200 hci_shutdown_connection(connection);
jksoft 0:373bcb197dc8 1201 return;
jksoft 0:373bcb197dc8 1202 }
jksoft 0:373bcb197dc8 1203
jksoft 0:373bcb197dc8 1204 // disable page and inquiry scan
jksoft 0:373bcb197dc8 1205 if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return;
jksoft 0:373bcb197dc8 1206
jksoft 0:373bcb197dc8 1207 log_info("HCI_STATE_HALTING, disabling inq cans\n");
jksoft 0:373bcb197dc8 1208 hci_send_cmd(&hci_write_scan_enable, hci_stack.connectable << 1); // drop inquiry scan but keep page scan
jksoft 0:373bcb197dc8 1209
jksoft 0:373bcb197dc8 1210 // continue in next sub state
jksoft 0:373bcb197dc8 1211 hci_stack.substate++;
jksoft 0:373bcb197dc8 1212 break;
jksoft 0:373bcb197dc8 1213 case 1:
jksoft 0:373bcb197dc8 1214 // wait for command complete "hci_write_scan_enable" in event_handler();
jksoft 0:373bcb197dc8 1215 break;
jksoft 0:373bcb197dc8 1216 case 2:
jksoft 0:373bcb197dc8 1217 log_info("HCI_STATE_HALTING, calling sleep\n");
jksoft 0:373bcb197dc8 1218 #if defined(USE_POWERMANAGEMENT) && defined(USE_BLUETOOL)
jksoft 0:373bcb197dc8 1219 // don't actually go to sleep, if H4 supports power management
jksoft 0:373bcb197dc8 1220 if (bt_control_iphone_power_management_enabled()){
jksoft 0:373bcb197dc8 1221 // SLEEP MODE reached
jksoft 0:373bcb197dc8 1222 hci_stack.state = HCI_STATE_SLEEPING;
jksoft 0:373bcb197dc8 1223 hci_emit_state();
jksoft 0:373bcb197dc8 1224 break;
jksoft 0:373bcb197dc8 1225 }
jksoft 0:373bcb197dc8 1226 #endif
jksoft 0:373bcb197dc8 1227 // switch mode
jksoft 0:373bcb197dc8 1228 hci_power_control_sleep(); // changes hci_stack.state to SLEEP
jksoft 0:373bcb197dc8 1229 hci_emit_state();
jksoft 0:373bcb197dc8 1230 break;
jksoft 0:373bcb197dc8 1231
jksoft 0:373bcb197dc8 1232 default:
jksoft 0:373bcb197dc8 1233 break;
jksoft 0:373bcb197dc8 1234 }
jksoft 0:373bcb197dc8 1235 break;
jksoft 0:373bcb197dc8 1236
jksoft 0:373bcb197dc8 1237 default:
jksoft 0:373bcb197dc8 1238 break;
jksoft 0:373bcb197dc8 1239 }
jksoft 0:373bcb197dc8 1240 }
jksoft 0:373bcb197dc8 1241
jksoft 0:373bcb197dc8 1242 int hci_send_cmd_packet(uint8_t *packet, int size){
jksoft 0:373bcb197dc8 1243 bd_addr_t addr;
jksoft 0:373bcb197dc8 1244 hci_connection_t * conn;
jksoft 0:373bcb197dc8 1245 // house-keeping
jksoft 0:373bcb197dc8 1246
jksoft 0:373bcb197dc8 1247 // create_connection?
jksoft 0:373bcb197dc8 1248 if (IS_COMMAND(packet, hci_create_connection)){
jksoft 0:373bcb197dc8 1249 bt_flip_addr(addr, &packet[3]);
jksoft 0:373bcb197dc8 1250 log_info("Create_connection to %s\n", bd_addr_to_str(addr));
jksoft 0:373bcb197dc8 1251 conn = connection_for_address(addr);
jksoft 0:373bcb197dc8 1252 if (conn) {
jksoft 0:373bcb197dc8 1253 // if connection exists
jksoft 0:373bcb197dc8 1254 if (conn->state == OPEN) {
jksoft 0:373bcb197dc8 1255 // and OPEN, emit connection complete command
jksoft 0:373bcb197dc8 1256 hci_emit_connection_complete(conn, 0);
jksoft 0:373bcb197dc8 1257 }
jksoft 0:373bcb197dc8 1258 // otherwise, just ignore as it is already in the open process
jksoft 0:373bcb197dc8 1259 return 0; // don't sent packet to controller
jksoft 0:373bcb197dc8 1260
jksoft 0:373bcb197dc8 1261 }
jksoft 0:373bcb197dc8 1262 // create connection struct and register, state = SENT_CREATE_CONNECTION
jksoft 0:373bcb197dc8 1263 conn = create_connection_for_addr(addr);
jksoft 0:373bcb197dc8 1264 if (!conn){
jksoft 0:373bcb197dc8 1265 // notify client that alloc failed
jksoft 0:373bcb197dc8 1266 hci_emit_connection_complete(conn, BTSTACK_MEMORY_ALLOC_FAILED);
jksoft 0:373bcb197dc8 1267 return 0; // don't sent packet to controller
jksoft 0:373bcb197dc8 1268 }
jksoft 0:373bcb197dc8 1269 conn->state = SENT_CREATE_CONNECTION;
jksoft 0:373bcb197dc8 1270 }
jksoft 0:373bcb197dc8 1271
jksoft 0:373bcb197dc8 1272 if (IS_COMMAND(packet, hci_link_key_request_reply)){
jksoft 0:373bcb197dc8 1273 hci_add_connection_flags_for_flipped_bd_addr(&packet[3], SENT_LINK_KEY_REPLY);
jksoft 0:373bcb197dc8 1274 }
jksoft 0:373bcb197dc8 1275 if (IS_COMMAND(packet, hci_link_key_request_negative_reply)){
jksoft 0:373bcb197dc8 1276 hci_add_connection_flags_for_flipped_bd_addr(&packet[3], SENT_LINK_KEY_NEGATIVE_REQUEST);
jksoft 0:373bcb197dc8 1277 }
jksoft 0:373bcb197dc8 1278 if (IS_COMMAND(packet, hci_pin_code_request_reply)){
jksoft 0:373bcb197dc8 1279 hci_add_connection_flags_for_flipped_bd_addr(&packet[3], SENT_PIN_CODE_REPLY);
jksoft 0:373bcb197dc8 1280 }
jksoft 0:373bcb197dc8 1281 if (IS_COMMAND(packet, hci_pin_code_request_negative_reply)){
jksoft 0:373bcb197dc8 1282 hci_add_connection_flags_for_flipped_bd_addr(&packet[3], SENT_PIN_CODE_NEGATIVE_REPLY);
jksoft 0:373bcb197dc8 1283 }
jksoft 0:373bcb197dc8 1284
jksoft 0:373bcb197dc8 1285 if (IS_COMMAND(packet, hci_delete_stored_link_key)){
jksoft 0:373bcb197dc8 1286 if (hci_stack.remote_device_db){
jksoft 0:373bcb197dc8 1287 bt_flip_addr(addr, &packet[3]);
jksoft 0:373bcb197dc8 1288 hci_stack.remote_device_db->delete_link_key(&addr);
jksoft 0:373bcb197dc8 1289 }
jksoft 0:373bcb197dc8 1290 }
jksoft 0:373bcb197dc8 1291
jksoft 0:373bcb197dc8 1292 hci_stack.num_cmd_packets--;
jksoft 0:373bcb197dc8 1293 return hci_stack.hci_transport->send_packet(HCI_COMMAND_DATA_PACKET, packet, size);
jksoft 0:373bcb197dc8 1294 }
jksoft 0:373bcb197dc8 1295
jksoft 0:373bcb197dc8 1296 /**
jksoft 0:373bcb197dc8 1297 * pre: numcmds >= 0 - it's allowed to send a command to the controller
jksoft 0:373bcb197dc8 1298 */
jksoft 0:373bcb197dc8 1299 int hci_send_cmd(const hci_cmd_t *cmd, ...){
jksoft 0:373bcb197dc8 1300 va_list argptr;
jksoft 0:373bcb197dc8 1301 va_start(argptr, cmd);
jksoft 0:373bcb197dc8 1302 uint16_t size = hci_create_cmd_internal(hci_stack.hci_packet_buffer, cmd, argptr);
jksoft 0:373bcb197dc8 1303 va_end(argptr);
jksoft 0:373bcb197dc8 1304 return hci_send_cmd_packet(hci_stack.hci_packet_buffer, size);
jksoft 0:373bcb197dc8 1305 }
jksoft 0:373bcb197dc8 1306
jksoft 0:373bcb197dc8 1307 // Create various non-HCI events.
jksoft 0:373bcb197dc8 1308 // TODO: generalize, use table similar to hci_create_command
jksoft 0:373bcb197dc8 1309
jksoft 0:373bcb197dc8 1310 void hci_emit_state(){
jksoft 0:373bcb197dc8 1311 log_info("BTSTACK_EVENT_STATE %u\n", hci_stack.state);
jksoft 0:373bcb197dc8 1312 uint8_t event[3];
jksoft 0:373bcb197dc8 1313 event[0] = BTSTACK_EVENT_STATE;
jksoft 0:373bcb197dc8 1314 event[1] = sizeof(event) - 2;
jksoft 0:373bcb197dc8 1315 event[2] = hci_stack.state;
jksoft 0:373bcb197dc8 1316 hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
jksoft 0:373bcb197dc8 1317 hci_stack.packet_handler(HCI_EVENT_PACKET, event, sizeof(event));
jksoft 0:373bcb197dc8 1318 }
jksoft 0:373bcb197dc8 1319
jksoft 0:373bcb197dc8 1320 void hci_emit_connection_complete(hci_connection_t *conn, uint8_t status){
jksoft 0:373bcb197dc8 1321 uint8_t event[13];
jksoft 0:373bcb197dc8 1322 event[0] = HCI_EVENT_CONNECTION_COMPLETE;
jksoft 0:373bcb197dc8 1323 event[1] = sizeof(event) - 2;
jksoft 0:373bcb197dc8 1324 event[2] = status;
jksoft 0:373bcb197dc8 1325 bt_store_16(event, 3, conn->con_handle);
jksoft 0:373bcb197dc8 1326 bt_flip_addr(&event[5], conn->address);
jksoft 0:373bcb197dc8 1327 event[11] = 1; // ACL connection
jksoft 0:373bcb197dc8 1328 event[12] = 0; // encryption disabled
jksoft 0:373bcb197dc8 1329 hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
jksoft 0:373bcb197dc8 1330 hci_stack.packet_handler(HCI_EVENT_PACKET, event, sizeof(event));
jksoft 0:373bcb197dc8 1331 }
jksoft 0:373bcb197dc8 1332
jksoft 0:373bcb197dc8 1333 void hci_emit_disconnection_complete(uint16_t handle, uint8_t reason){
jksoft 0:373bcb197dc8 1334 uint8_t event[6];
jksoft 0:373bcb197dc8 1335 event[0] = HCI_EVENT_DISCONNECTION_COMPLETE;
jksoft 0:373bcb197dc8 1336 event[1] = sizeof(event) - 2;
jksoft 0:373bcb197dc8 1337 event[2] = 0; // status = OK
jksoft 0:373bcb197dc8 1338 bt_store_16(event, 3, handle);
jksoft 0:373bcb197dc8 1339 event[5] = reason;
jksoft 0:373bcb197dc8 1340 hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
jksoft 0:373bcb197dc8 1341 hci_stack.packet_handler(HCI_EVENT_PACKET, event, sizeof(event));
jksoft 0:373bcb197dc8 1342 }
jksoft 0:373bcb197dc8 1343
jksoft 0:373bcb197dc8 1344 void hci_emit_l2cap_check_timeout(hci_connection_t *conn){
jksoft 0:373bcb197dc8 1345 log_info("L2CAP_EVENT_TIMEOUT_CHECK\n");
jksoft 0:373bcb197dc8 1346 uint8_t event[4];
jksoft 0:373bcb197dc8 1347 event[0] = L2CAP_EVENT_TIMEOUT_CHECK;
jksoft 0:373bcb197dc8 1348 event[1] = sizeof(event) - 2;
jksoft 0:373bcb197dc8 1349 bt_store_16(event, 2, conn->con_handle);
jksoft 0:373bcb197dc8 1350 hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
jksoft 0:373bcb197dc8 1351 hci_stack.packet_handler(HCI_EVENT_PACKET, event, sizeof(event));
jksoft 0:373bcb197dc8 1352 }
jksoft 0:373bcb197dc8 1353
jksoft 0:373bcb197dc8 1354 void hci_emit_nr_connections_changed(){
jksoft 0:373bcb197dc8 1355 log_info("BTSTACK_EVENT_NR_CONNECTIONS_CHANGED %u\n", nr_hci_connections());
jksoft 0:373bcb197dc8 1356 uint8_t event[3];
jksoft 0:373bcb197dc8 1357 event[0] = BTSTACK_EVENT_NR_CONNECTIONS_CHANGED;
jksoft 0:373bcb197dc8 1358 event[1] = sizeof(event) - 2;
jksoft 0:373bcb197dc8 1359 event[2] = nr_hci_connections();
jksoft 0:373bcb197dc8 1360 hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
jksoft 0:373bcb197dc8 1361 hci_stack.packet_handler(HCI_EVENT_PACKET, event, sizeof(event));
jksoft 0:373bcb197dc8 1362 }
jksoft 0:373bcb197dc8 1363
jksoft 0:373bcb197dc8 1364 void hci_emit_hci_open_failed(){
jksoft 0:373bcb197dc8 1365 log_info("BTSTACK_EVENT_POWERON_FAILED\n");
jksoft 0:373bcb197dc8 1366 uint8_t event[2];
jksoft 0:373bcb197dc8 1367 event[0] = BTSTACK_EVENT_POWERON_FAILED;
jksoft 0:373bcb197dc8 1368 event[1] = sizeof(event) - 2;
jksoft 0:373bcb197dc8 1369 hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
jksoft 0:373bcb197dc8 1370 hci_stack.packet_handler(HCI_EVENT_PACKET, event, sizeof(event));
jksoft 0:373bcb197dc8 1371 }
jksoft 0:373bcb197dc8 1372
jksoft 0:373bcb197dc8 1373 #ifndef EMBEDDED
jksoft 0:373bcb197dc8 1374 void hci_emit_btstack_version() {
jksoft 0:373bcb197dc8 1375 log_info("BTSTACK_EVENT_VERSION %u.%u\n", BTSTACK_MAJOR, BTSTACK_MINOR);
jksoft 0:373bcb197dc8 1376 uint8_t event[6];
jksoft 0:373bcb197dc8 1377 event[0] = BTSTACK_EVENT_VERSION;
jksoft 0:373bcb197dc8 1378 event[1] = sizeof(event) - 2;
jksoft 0:373bcb197dc8 1379 event[2] = BTSTACK_MAJOR;
jksoft 0:373bcb197dc8 1380 event[3] = BTSTACK_MINOR;
jksoft 0:373bcb197dc8 1381 bt_store_16(event, 4, BTSTACK_REVISION);
jksoft 0:373bcb197dc8 1382 hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
jksoft 0:373bcb197dc8 1383 hci_stack.packet_handler(HCI_EVENT_PACKET, event, sizeof(event));
jksoft 0:373bcb197dc8 1384 }
jksoft 0:373bcb197dc8 1385 #endif
jksoft 0:373bcb197dc8 1386
jksoft 0:373bcb197dc8 1387 void hci_emit_system_bluetooth_enabled(uint8_t enabled){
jksoft 0:373bcb197dc8 1388 log_info("BTSTACK_EVENT_SYSTEM_BLUETOOTH_ENABLED %u\n", enabled);
jksoft 0:373bcb197dc8 1389 uint8_t event[3];
jksoft 0:373bcb197dc8 1390 event[0] = BTSTACK_EVENT_SYSTEM_BLUETOOTH_ENABLED;
jksoft 0:373bcb197dc8 1391 event[1] = sizeof(event) - 2;
jksoft 0:373bcb197dc8 1392 event[2] = enabled;
jksoft 0:373bcb197dc8 1393 hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
jksoft 0:373bcb197dc8 1394 hci_stack.packet_handler(HCI_EVENT_PACKET, event, sizeof(event));
jksoft 0:373bcb197dc8 1395 }
jksoft 0:373bcb197dc8 1396
jksoft 0:373bcb197dc8 1397 void hci_emit_remote_name_cached(bd_addr_t *addr, device_name_t *name){
jksoft 0:373bcb197dc8 1398 uint8_t event[2+1+6+248+1]; // +1 for \0 in log_info
jksoft 0:373bcb197dc8 1399 event[0] = BTSTACK_EVENT_REMOTE_NAME_CACHED;
jksoft 0:373bcb197dc8 1400 event[1] = sizeof(event) - 2 - 1;
jksoft 0:373bcb197dc8 1401 event[2] = 0; // just to be compatible with HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE
jksoft 0:373bcb197dc8 1402 bt_flip_addr(&event[3], *addr);
jksoft 0:373bcb197dc8 1403 memcpy(&event[9], name, 248);
jksoft 0:373bcb197dc8 1404
jksoft 0:373bcb197dc8 1405 event[9+248] = 0; // assert \0 for log_info
jksoft 0:373bcb197dc8 1406 log_info("BTSTACK_EVENT_REMOTE_NAME_CACHED %s = '%s'\n", bd_addr_to_str(*addr), &event[9]);
jksoft 0:373bcb197dc8 1407
jksoft 0:373bcb197dc8 1408 hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event)-1);
jksoft 0:373bcb197dc8 1409 hci_stack.packet_handler(HCI_EVENT_PACKET, event, sizeof(event)-1);
jksoft 0:373bcb197dc8 1410 }
jksoft 0:373bcb197dc8 1411
jksoft 0:373bcb197dc8 1412 void hci_emit_discoverable_enabled(uint8_t enabled){
jksoft 0:373bcb197dc8 1413 log_info("BTSTACK_EVENT_DISCOVERABLE_ENABLED %u\n", enabled);
jksoft 0:373bcb197dc8 1414 uint8_t event[3];
jksoft 0:373bcb197dc8 1415 event[0] = BTSTACK_EVENT_DISCOVERABLE_ENABLED;
jksoft 0:373bcb197dc8 1416 event[1] = sizeof(event) - 2;
jksoft 0:373bcb197dc8 1417 event[2] = enabled;
jksoft 0:373bcb197dc8 1418 hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
jksoft 0:373bcb197dc8 1419 hci_stack.packet_handler(HCI_EVENT_PACKET, event, sizeof(event));
jksoft 0:373bcb197dc8 1420 }