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); } connectionClearAuthenticationFlags(connection, 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, (hci_stack.connectable << 1) | 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 cans\n"); hci_send_cmd(&hci_write_scan_enable, hci_stack.connectable << 1); // drop inquiry scan but keep page scan // 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; } }
uint8_t test_ble(uint8_t ev, uint16_t lparam, void* rparam) { switch(ev) { case EVENT_WINDOW_CREATED: onoff = 0; data = 0; ble_advertise(0); hci_send_cmd_packet((uint8_t*)HCI_VS_Set_LE_Test_Mode_Parameters, sizeof(HCI_VS_Set_LE_Test_Mode_Parameters)); break; case EVENT_KEY_PRESSED: { if (lparam == KEY_ENTER) { onoff++; if (onoff == 9) onoff = 0; } if (lparam == KEY_UP && data < 37) { data++; } if (lparam == KEY_DOWN && data >= 0) { data--; } if (onoff == 0) { //switch off hci_send_cmd(&hci_le_test_end); } else { hci_send_cmd(&hci_le_transmitter_test, data, 0x25, onoff - 1); } window_invalid(NULL); break; } case EVENT_WINDOW_PAINT: { tContext *pContext = (tContext*)rparam; const char *text; GrContextForegroundSet(pContext, ClrBlack); GrRectFill(pContext, &client_clip); GrContextForegroundSet(pContext, ClrWhite); GrContextFontSet(pContext, (tFont*)&g_sFontGothic18); switch(onoff) { case 0: text = "BLE TX is off"; break; case 1: text = "PRBS 9"; break; case 2: text = "FOFO"; break; case 3: text = "ZOZO"; break; case 4: text = "PRBS 15"; break; case 5: text = "All Ones"; break; case 6: text = "All Zeros"; break; case 7: text = "OFOF"; break; case 8: text = "OZOZ"; break; } GrStringDraw(pContext, text, -1, 32, 50, 0); if (data >= 0) { char buf[32]; sprintf(buf, "Freqency: %dMhz", data < 40 ? 2402 + data * 2: 2403 + (data - 40) * 2); GrStringDraw(pContext, buf, -1, 5, 70, 0); } else { GrStringDraw(pContext, "Hoping mode", -1, 5, 70, 0); } window_button(pContext, KEY_UP, "+"); window_button(pContext, KEY_DOWN, "-"); window_button(pContext, KEY_ENTER, "Switch"); break; } case EVENT_WINDOW_CLOSING: if (onoff) { hci_send_cmd(&hci_le_test_end); } break; default: return 0; } return 1; }
uint8_t test_bluetooth(uint8_t ev, uint16_t lparam, void* rparam) { uint8_t buf[sizeof(HCI_VS_DRPb_Tester_Packet_TX_RX_Cmd)]; switch(ev) { case EVENT_WINDOW_CREATED: onoff = 0; data = 0; break; case EVENT_KEY_PRESSED: { if (lparam == KEY_ENTER) { onoff++; if (onoff == 10) onoff = 0; } if (lparam == KEY_UP && data <= 78) { data++; } if (lparam == KEY_DOWN && data >= -1) { data--; } switch(onoff) { case 0: buf[0] = 0x88; buf[1] = 0xFD; buf[2] = 0; hci_send_cmd_packet(buf, 3); break; default: memcpy(buf, HCI_VS_DRPb_Tester_Packet_TX_RX_Cmd, sizeof(HCI_VS_DRPb_Tester_Packet_TX_RX_Cmd)); if (data == -1) { buf[3] = 0x00; //hoping mode } else { buf[4] = data; } if (onoff != 0x09) buf[6] = onoff - 1; else buf[6] = onoff; switch(onoff) { case 1: buf[9] = 17; break; case 2: buf[9] = 27; break; case 3: buf[9] = 121; break; case 4: buf[9] = 183; break; case 5: buf[9] = 224; break; case 6: buf[9] = 255; break; case 7: buf[9] = 54; break; case 8: buf[9] = 255; break; case 9: buf[9] = 83; break; } hci_send_cmd_packet(buf, sizeof(HCI_VS_DRPb_Tester_Packet_TX_RX_Cmd)); break; } window_invalid(NULL); break; } case EVENT_WINDOW_PAINT: { tContext *pContext = (tContext*)rparam; const char *text; GrContextForegroundSet(pContext, ClrBlack); GrRectFill(pContext, &client_clip); GrContextForegroundSet(pContext, ClrWhite); GrContextFontSet(pContext, (tFont*)&g_sFontGothic18); switch(onoff) { case 0: text = "BT RX/TX is off"; break; case 1: text = "DM1"; break; case 2: text = "DH1"; break; case 3: text = "DM3"; break; case 4: text = "DH3"; break; case 5: text = "DM5"; break; case 6: text = "DH5"; break; case 7: text = "2-DH1"; break; case 8: text = "2-DH3"; break; case 9: text = "3-DH1"; break; } GrStringDraw(pContext, text, -1, 32, 50, 0); if (data >= 0) { char buf[32]; sprintf(buf, "Freqency: %dMhz", data < 40 ? 2402 + data * 2: 2403 + (data - 40) * 2); GrStringDraw(pContext, buf, -1, 5, 70, 0); } else { GrStringDraw(pContext, "Hoping mode", -1, 5, 70, 0); } window_button(pContext, KEY_UP, "+"); window_button(pContext, KEY_DOWN, "-"); window_button(pContext, KEY_ENTER, "Switch"); break; } case EVENT_WINDOW_CLOSING: if (onoff) { uint8_t buf[3]; buf[0] = 0x88; buf[1] = 0xFD; buf[2] = 0; hci_send_cmd_packet(buf, 3); } break; default: return 0; } return 1; }
static int daemon_client_handler(connection_t *connection, uint16_t packet_type, uint16_t channel, uint8_t *data, uint16_t length) { int err = 0; client_state_t * client; switch (packet_type) { case HCI_COMMAND_DATA_PACKET: if (READ_CMD_OGF(data) != OGF_BTSTACK) { // HCI Command hci_send_cmd_packet(data, length); } else { // BTstack command btstack_command_handler(connection, data, length); } break; case HCI_ACL_DATA_PACKET: err = hci_send_acl_packet(data, length); break; case L2CAP_DATA_PACKET: // process l2cap packet... err = l2cap_send_internal(channel, data, length); if (err == BTSTACK_ACL_BUFFERS_FULL) { l2cap_block_new_credits(1); } break; case RFCOMM_DATA_PACKET: // process l2cap packet... err = rfcomm_send_internal(channel, data, length); break; case DAEMON_EVENT_PACKET: switch (data[0]) { case DAEMON_EVENT_CONNECTION_OPENED: client = malloc(sizeof(client_state_t)); if (!client) break; // fail client->connection = connection; client->power_mode = HCI_POWER_OFF; client->discoverable = 0; linked_list_add(&clients, (linked_item_t *) client); break; case DAEMON_EVENT_CONNECTION_CLOSED: sdp_unregister_services_for_connection(connection); rfcomm_close_connection(connection); l2cap_close_connection(connection); client = client_for_connection(connection); if (!client) break; linked_list_remove(&clients, (linked_item_t *) client); free(client); // update discoverable mode hci_discoverable_control(clients_require_discoverable()); // start power off, if last active client if (!clients_require_power_on()) { start_power_off_timer(); } break; case DAEMON_NR_CONNECTIONS_CHANGED: log_info("Nr Connections changed, new %u\n",data[1]); break; default: break; } break; } if (err) { log_info("Daemon Handler: err %d\n", err); } return err; }