void hci_run(){ hci_connection_t * connection; linked_item_t * it; if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return; // global/non-connection oriented commands // decline incoming connections if (hci_stack.decline_reason){ uint8_t reason = hci_stack.decline_reason; hci_stack.decline_reason = 0; hci_send_cmd(&hci_reject_connection_request, hci_stack.decline_addr, reason); } if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return; // send scan enable if (hci_stack.new_scan_enable_value != 0xff){ hci_send_cmd(&hci_write_scan_enable, hci_stack.new_scan_enable_value); hci_stack.new_scan_enable_value = 0xff; } // send pending HCI commands for (it = (linked_item_t *) hci_stack.connections; it ; it = it->next){ if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return; connection = (hci_connection_t *) it; if (connection->state == RECEIVED_CONNECTION_REQUEST){ log_info("sending hci_accept_connection_request\n"); hci_send_cmd(&hci_accept_connection_request, connection->address, 1); connection->state = ACCEPTED_CONNECTION_REQUEST; } if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return; if (connection->authentication_flags & HANDLE_LINK_KEY_REQUEST){ link_key_t link_key; log_info("responding to link key request\n"); if ( hci_stack.remote_device_db->get_link_key( &connection->address, &link_key)){ hci_send_cmd(&hci_link_key_request_reply, connection->address, &link_key); } else { hci_send_cmd(&hci_link_key_request_negative_reply, connection->address); } connection->authentication_flags &= ~HANDLE_LINK_KEY_REQUEST; } } if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return; switch (hci_stack.state){ case HCI_STATE_INITIALIZING: // log_info("hci_init: substate %u\n", hci_stack.substate); if (hci_stack.substate % 2) { // odd: waiting for command completion return; } switch (hci_stack.substate >> 1){ case 0: // RESET hci_send_cmd(&hci_reset); if (hci_stack.config == 0 || ((hci_uart_config_t *)hci_stack.config)->baudrate_main == 0){ // skip baud change hci_stack.substate = 4; // >> 1 = 2 } break; case 1: // SEND BAUD CHANGE hci_stack.control->baudrate_cmd(hci_stack.config, ((hci_uart_config_t *)hci_stack.config)->baudrate_main, hci_stack.hci_packet_buffer); hci_send_cmd_packet(hci_stack.hci_packet_buffer, 3 + hci_stack.hci_packet_buffer[2]); break; case 2: // LOCAL BAUD CHANGE hci_stack.hci_transport->set_baudrate(((hci_uart_config_t *)hci_stack.config)->baudrate_main); hci_stack.substate += 2; // break missing here for fall through case 3: // custom initialization if (hci_stack.control && hci_stack.control->next_cmd){ int valid_cmd = (*hci_stack.control->next_cmd)(hci_stack.config, hci_stack.hci_packet_buffer); if (valid_cmd){ int size = 3 + hci_stack.hci_packet_buffer[2]; hci_stack.hci_transport->send_packet(HCI_COMMAND_DATA_PACKET, hci_stack.hci_packet_buffer, size); hci_stack.substate = 4; // more init commands break; } log_info("hci_run: init script done\n\r"); } // otherwise continue hci_send_cmd(&hci_read_bd_addr); break; case 4: hci_send_cmd(&hci_read_buffer_size); break; case 5: // ca. 15 sec hci_send_cmd(&hci_write_page_timeout, 0x6000); break; case 6: hci_send_cmd(&hci_write_scan_enable, 2 | hci_stack.discoverable); // page scan break; case 7: #ifndef EMBEDDED { char hostname[30]; gethostname(hostname, 30); hostname[29] = '\0'; hci_send_cmd(&hci_write_local_name, hostname); break; } case 8: #ifdef USE_BLUETOOL hci_send_cmd(&hci_write_class_of_device, 0x007a020c); // Smartphone break; case 9: #endif #endif // done. hci_stack.state = HCI_STATE_WORKING; hci_emit_state(); break; default: break; } hci_stack.substate++; break; case HCI_STATE_HALTING: log_info("HCI_STATE_HALTING\n"); // close all open connections connection = (hci_connection_t *) hci_stack.connections; if (connection){ // send disconnect if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return; log_info("HCI_STATE_HALTING, connection %p, handle %u\n", connection, (uint16_t)connection->con_handle); hci_send_cmd(&hci_disconnect, connection->con_handle, 0x13); // remote closed connection // send disconnected event right away - causes higher layer connections to get closed, too. hci_shutdown_connection(connection); return; } log_info("HCI_STATE_HALTING, calling off\n"); // switch mode hci_power_control_off(); log_info("HCI_STATE_HALTING, emitting state\n"); hci_emit_state(); log_info("HCI_STATE_HALTING, done\n"); break; case HCI_STATE_FALLING_ASLEEP: switch(hci_stack.substate) { case 0: log_info("HCI_STATE_FALLING_ASLEEP\n"); // close all open connections connection = (hci_connection_t *) hci_stack.connections; #if defined(USE_POWERMANAGEMENT) && defined(USE_BLUETOOL) // don't close connections, if H4 supports power management if (bt_control_iphone_power_management_enabled()){ connection = NULL; } #endif if (connection){ // send disconnect if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return; log_info("HCI_STATE_FALLING_ASLEEP, connection %p, handle %u\n", connection, (uint16_t)connection->con_handle); hci_send_cmd(&hci_disconnect, connection->con_handle, 0x13); // remote closed connection // send disconnected event right away - causes higher layer connections to get closed, too. hci_shutdown_connection(connection); return; } // disable page and inquiry scan if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return; log_info("HCI_STATE_HALTING, disabling inq & page scans\n"); hci_send_cmd(&hci_write_scan_enable, 0); // none // continue in next sub state hci_stack.substate++; break; case 1: // wait for command complete "hci_write_scan_enable" in event_handler(); break; case 2: log_info("HCI_STATE_HALTING, calling sleep\n"); #if defined(USE_POWERMANAGEMENT) && defined(USE_BLUETOOL) // don't actually go to sleep, if H4 supports power management if (bt_control_iphone_power_management_enabled()){ // SLEEP MODE reached hci_stack.state = HCI_STATE_SLEEPING; hci_emit_state(); break; } #endif // switch mode hci_power_control_sleep(); // changes hci_stack.state to SLEEP hci_emit_state(); break; default: break; } break; default: break; } }
static int btstack_command_handler(connection_t *connection, uint8_t *packet, uint16_t size){ bd_addr_t addr; uint16_t cid; uint16_t psm; uint16_t service_channel; uint16_t mtu; uint8_t reason; uint8_t rfcomm_channel; uint8_t rfcomm_credits; uint32_t service_record_handle; client_state_t *client; uint16_t serviceSearchPatternLen; uint16_t attributeIDListLen; // BTstack internal commands - 16 Bit OpCode, 8 Bit ParamLen, Params... switch (READ_CMD_OCF(packet)){ case BTSTACK_GET_STATE: log_info("BTSTACK_GET_STATE"); hci_emit_state(); break; case BTSTACK_SET_POWER_MODE: log_info("BTSTACK_SET_POWER_MODE %u", packet[3]); // track client power requests client = client_for_connection(connection); if (!client) break; client->power_mode = packet[3]; // handle merged state if (!clients_require_power_on()){ start_power_off_timer(); } else if (!power_management_sleep) { stop_power_off_timer(); hci_power_control(HCI_POWER_ON); } break; case BTSTACK_GET_VERSION: log_info("BTSTACK_GET_VERSION"); hci_emit_btstack_version(); break; #ifdef USE_BLUETOOL case BTSTACK_SET_SYSTEM_BLUETOOTH_ENABLED: log_info("BTSTACK_SET_SYSTEM_BLUETOOTH_ENABLED %u", packet[3]); iphone_system_bt_set_enabled(packet[3]); hci_emit_system_bluetooth_enabled(iphone_system_bt_enabled()); break; case BTSTACK_GET_SYSTEM_BLUETOOTH_ENABLED: log_info("BTSTACK_GET_SYSTEM_BLUETOOTH_ENABLED"); hci_emit_system_bluetooth_enabled(iphone_system_bt_enabled()); break; #else case BTSTACK_SET_SYSTEM_BLUETOOTH_ENABLED: case BTSTACK_GET_SYSTEM_BLUETOOTH_ENABLED: hci_emit_system_bluetooth_enabled(0); break; #endif case BTSTACK_SET_DISCOVERABLE: log_info("BTSTACK_SET_DISCOVERABLE discoverable %u)", packet[3]); // track client discoverable requests client = client_for_connection(connection); if (!client) break; client->discoverable = packet[3]; // merge state hci_discoverable_control(clients_require_discoverable()); break; case BTSTACK_SET_BLUETOOTH_ENABLED: log_info("BTSTACK_SET_BLUETOOTH_ENABLED: %u\n", packet[3]); if (packet[3]) { // global enable global_enable = 1; hci_power_control(HCI_POWER_ON); } else { global_enable = 0; clients_clear_power_request(); hci_power_control(HCI_POWER_OFF); } break; case L2CAP_CREATE_CHANNEL_MTU: bt_flip_addr(addr, &packet[3]); psm = READ_BT_16(packet, 9); mtu = READ_BT_16(packet, 11); l2cap_create_channel_internal( connection, NULL, addr, psm, mtu); break; case L2CAP_CREATE_CHANNEL: bt_flip_addr(addr, &packet[3]); psm = READ_BT_16(packet, 9); l2cap_create_channel_internal( connection, NULL, addr, psm, 150); // until r865 break; case L2CAP_DISCONNECT: cid = READ_BT_16(packet, 3); reason = packet[5]; l2cap_disconnect_internal(cid, reason); break; case L2CAP_REGISTER_SERVICE: psm = READ_BT_16(packet, 3); mtu = READ_BT_16(packet, 5); l2cap_register_service_internal(connection, NULL, psm, mtu); break; case L2CAP_UNREGISTER_SERVICE: psm = READ_BT_16(packet, 3); l2cap_unregister_service_internal(connection, psm); break; case L2CAP_ACCEPT_CONNECTION: cid = READ_BT_16(packet, 3); l2cap_accept_connection_internal(cid); break; case L2CAP_DECLINE_CONNECTION: cid = READ_BT_16(packet, 3); reason = packet[7]; l2cap_decline_connection_internal(cid, reason); break; case RFCOMM_CREATE_CHANNEL: bt_flip_addr(addr, &packet[3]); rfcomm_channel = packet[9]; rfcomm_create_channel_internal( connection, &addr, rfcomm_channel ); break; case RFCOMM_CREATE_CHANNEL_WITH_CREDITS: bt_flip_addr(addr, &packet[3]); rfcomm_channel = packet[9]; rfcomm_credits = packet[10]; rfcomm_create_channel_with_initial_credits_internal( connection, &addr, rfcomm_channel, rfcomm_credits ); break; case RFCOMM_DISCONNECT: cid = READ_BT_16(packet, 3); reason = packet[5]; rfcomm_disconnect_internal(cid); break; case RFCOMM_REGISTER_SERVICE: rfcomm_channel = packet[3]; mtu = READ_BT_16(packet, 4); rfcomm_register_service_internal(connection, rfcomm_channel, mtu); break; case RFCOMM_REGISTER_SERVICE_WITH_CREDITS: rfcomm_channel = packet[3]; mtu = READ_BT_16(packet, 4); rfcomm_credits = packet[6]; rfcomm_register_service_with_initial_credits_internal(connection, rfcomm_channel, mtu, rfcomm_credits); break; case RFCOMM_UNREGISTER_SERVICE: service_channel = READ_BT_16(packet, 3); rfcomm_unregister_service_internal(service_channel); break; case RFCOMM_ACCEPT_CONNECTION: cid = READ_BT_16(packet, 3); rfcomm_accept_connection_internal(cid); break; case RFCOMM_DECLINE_CONNECTION: cid = READ_BT_16(packet, 3); reason = packet[7]; rfcomm_decline_connection_internal(cid); break; case RFCOMM_GRANT_CREDITS: cid = READ_BT_16(packet, 3); rfcomm_credits = packet[5]; rfcomm_grant_credits(cid, rfcomm_credits); break; case RFCOMM_PERSISTENT_CHANNEL: { if (remote_device_db) { // enforce \0 packet[3+248] = 0; rfcomm_channel = remote_device_db->persistent_rfcomm_channel((char*)&packet[3]); } else { // NOTE: hack for non-iOS platforms rfcomm_channel = rfcomm_channel_generator++; } log_info("RFCOMM_EVENT_PERSISTENT_CHANNEL %u", rfcomm_channel); uint8_t event[4]; event[0] = RFCOMM_EVENT_PERSISTENT_CHANNEL; event[1] = sizeof(event) - 2; event[2] = 0; event[3] = rfcomm_channel; hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event)); socket_connection_send_packet(connection, HCI_EVENT_PACKET, 0, (uint8_t *) event, sizeof(event)); break; } case SDP_REGISTER_SERVICE_RECORD: log_info("SDP_REGISTER_SERVICE_RECORD size %u\n", size); sdp_register_service_internal(connection, &packet[3]); break; case SDP_UNREGISTER_SERVICE_RECORD: service_record_handle = READ_BT_32(packet, 3); log_info("SDP_UNREGISTER_SERVICE_RECORD handle 0x%x ", service_record_handle); sdp_unregister_service_internal(connection, service_record_handle); break; case SDP_CLIENT_QUERY_RFCOMM_SERVICES: bt_flip_addr(addr, &packet[3]); serviceSearchPatternLen = de_get_len(&packet[9]); memcpy(serviceSearchPattern, &packet[9], serviceSearchPatternLen); sdp_query_rfcomm_register_callback(handle_sdp_rfcomm_service_result, connection); sdp_query_rfcomm_channel_and_name_for_search_pattern(addr, serviceSearchPattern); break; case SDP_CLIENT_QUERY_SERVICES: bt_flip_addr(addr, &packet[3]); sdp_parser_init(); sdp_parser_register_callback(handle_sdp_client_query_result); serviceSearchPatternLen = de_get_len(&packet[9]); memcpy(serviceSearchPattern, &packet[9], serviceSearchPatternLen); attributeIDListLen = de_get_len(&packet[9+serviceSearchPatternLen]); memcpy(attributeIDList, &packet[9+serviceSearchPatternLen], attributeIDListLen); sdp_client_query(addr, (uint8_t*)&serviceSearchPattern[0], (uint8_t*)&attributeIDList[0]); // sdp_general_query_for_uuid(addr, 0x1002); break; default: log_error("Error: command %u not implemented\n:", READ_CMD_OCF(packet)); break; } // verbose log info on command before dumped command unknown to PacketLogger or Wireshark hci_dump_packet( HCI_COMMAND_DATA_PACKET, 1, packet, size); return 0; }
int hci_power_control(HCI_POWER_MODE power_mode){ log_info("hci_power_control: %u, current mode %u\n", power_mode, hci_stack.state); int err = 0; switch (hci_stack.state){ case HCI_STATE_OFF: switch (power_mode){ case HCI_POWER_ON: err = hci_power_control_on(); if (err) return err; // set up state machine hci_stack.num_cmd_packets = 1; // assume that one cmd can be sent hci_stack.state = HCI_STATE_INITIALIZING; hci_stack.substate = 0; break; case HCI_POWER_OFF: // do nothing break; case HCI_POWER_SLEEP: // do nothing (with SLEEP == OFF) break; } break; case HCI_STATE_INITIALIZING: switch (power_mode){ case HCI_POWER_ON: // do nothing break; case HCI_POWER_OFF: // no connections yet, just turn it off hci_power_control_off(); break; case HCI_POWER_SLEEP: // no connections yet, just turn it off hci_power_control_sleep(); break; } break; case HCI_STATE_WORKING: switch (power_mode){ case HCI_POWER_ON: // do nothing break; case HCI_POWER_OFF: // see hci_run hci_stack.state = HCI_STATE_HALTING; break; case HCI_POWER_SLEEP: // see hci_run hci_stack.state = HCI_STATE_FALLING_ASLEEP; hci_stack.substate = 0; break; } break; case HCI_STATE_HALTING: switch (power_mode){ case HCI_POWER_ON: // set up state machine hci_stack.state = HCI_STATE_INITIALIZING; hci_stack.substate = 0; break; case HCI_POWER_OFF: // do nothing break; case HCI_POWER_SLEEP: // see hci_run hci_stack.state = HCI_STATE_FALLING_ASLEEP; hci_stack.substate = 0; break; } break; case HCI_STATE_FALLING_ASLEEP: switch (power_mode){ case HCI_POWER_ON: #if defined(USE_POWERMANAGEMENT) && defined(USE_BLUETOOL) // nothing to do, if H4 supports power management if (bt_control_iphone_power_management_enabled()){ hci_stack.state = HCI_STATE_INITIALIZING; hci_stack.substate = 6; break; } #endif // set up state machine hci_stack.num_cmd_packets = 1; // assume that one cmd can be sent hci_stack.state = HCI_STATE_INITIALIZING; hci_stack.substate = 0; break; case HCI_POWER_OFF: // see hci_run hci_stack.state = HCI_STATE_HALTING; break; case HCI_POWER_SLEEP: // do nothing break; } break; case HCI_STATE_SLEEPING: switch (power_mode){ case HCI_POWER_ON: #if defined(USE_POWERMANAGEMENT) && defined(USE_BLUETOOL) // nothing to do, if H4 supports power management if (bt_control_iphone_power_management_enabled()){ hci_stack.state = HCI_STATE_INITIALIZING; hci_stack.substate = 6; break; } #endif err = hci_power_control_wake(); if (err) return err; // set up state machine hci_stack.num_cmd_packets = 1; // assume that one cmd can be sent hci_stack.state = HCI_STATE_INITIALIZING; hci_stack.substate = 0; break; case HCI_POWER_OFF: hci_stack.state = HCI_STATE_HALTING; break; case HCI_POWER_SLEEP: // do nothing break; } break; } // create internal event hci_emit_state(); // trigger next/first action hci_run(); return 0; }