diff --git a/TODO.txt b/TODO.txt index e251f497c..33333557f 100644 --- a/TODO.txt +++ b/TODO.txt @@ -12,25 +12,16 @@ 2010-xxxx: Release 0.2 - revions xxx - limit size of /tmp/hci_dump.pklg to 1000 packets (max 1 MB) - power handling: handle power changes in all states, receive and handle power notifications, keep track of individual clients +- fixed bugs in cocoa run loop implementation +- automate scan enable management: hci_set_discoverable(bool) sets inquiry scan, page scan is always active NEXT: -- DONE: provide per client information: connection, power mode -- DONE: fix bug with run_loop_cocoa, after client disconnects - -- power handling - - DONE: add wake() to bt_control.h: OFF<->ON<->SLEEP (SLEEP -> OFF is possible) - - DONE: check if Bluetooth module can be woken up instantly with BlueTool on Broadcom chipsets -> yes - - check if Bluetooth module can be woken up instantly with BlueTool on CSR chipsets - - check apps for sleep mode compatibility - see what happens on ACTIVATED event - - Keyboard - - Mouse - - WeBe++ - - WiiMote example - - BTstackManager - -- automate scan enable management - - provide new "set discoverable (on/off)" command and store in per client information - - keep track of page scan enable -> active if l2cap services exist +- check apps for sleep mode/reactivated compatibility - see what happens on ACTIVATED event + - WiiMote example + - BTstackManager + - Keyboard + - Mouse + - WeBe++ - clean up components - consolidate iOS code in port_ios.m (bt_control_iphone.m, platform_iphone.m) @@ -39,15 +30,13 @@ NEXT: - add control of status bar icon to bt_control.h, too. - decide on configure flags - dynamic link BTdaemon against libBTstack.dylist - + - decide what to do with the CocoaTouch code. Options: - do nothing (potential problem with multiple dylibs in same process) - add it to libBTstack.dylib - provide a libBTstackCocoaTouch.dylib (less memory usage) - - move RFCOMM code into BTdaemon -- have a look at External Accessory interface by Apple - it's quite similar in function to BTstack - HCI CMD packet is limited to 1024 bytes payload. SDP records could be larger than that. Options: - provide a way to transfer SDP records in segments diff --git a/include/btstack/hci_cmds.h b/include/btstack/hci_cmds.h index 2b4a346db..f925490f4 100644 --- a/include/btstack/hci_cmds.h +++ b/include/btstack/hci_cmds.h @@ -118,9 +118,12 @@ extern "C" { // data: system bluetooth on/off (bool) #define BTSTACK_EVENT_SYSTEM_BLUETOOTH_ENABLED 0x64 -// data: event (8), len(8), status (8) == 0, address (48), name (1984 = 248 bytes) +// data: event (8), len(8), status (8) == 0, address (48), name (1984 bits = 248 bytes) #define BTSTACK_EVENT_REMOTE_NAME_CACHED 0x65 +// data: discoverable enabled (bool) +#define BTSTACK_EVENT_DISCOVERABLE_ENABLED 0x66 + // data: event (8), len(8), status (8), address(48), handle (16), psm (16), local_cid(16), remote_cid (16) #define L2CAP_EVENT_CHANNEL_OPENED 0x70 diff --git a/src/daemon.c b/src/daemon.c index 68a6ec31d..698f1b097 100644 --- a/src/daemon.c +++ b/src/daemon.c @@ -89,30 +89,30 @@ typedef struct { } client_state_t; -static hci_transport_t * transport; -static hci_uart_config_t config; - -static timer_source_t timeout; -static uint8_t timeout_active = 0; - -static int power_management_sleep = 0; - +#pragma mark prototypes static void dummy_bluetooth_status_handler(BLUETOOTH_STATE state); -static void (*bluetooth_status_handler)(BLUETOOTH_STATE state) = dummy_bluetooth_status_handler; - -static linked_list_t clients = NULL; // list of connected clients static client_state_t * client_for_connection(connection_t *connection); -static int clients_requires_power_on(); - +static int clients_require_power_on(); +static int clients_require_discoverable(); static void start_power_off_timer(); static void stop_power_off_timer(); +#pragma mark globals +static hci_transport_t * transport; +static hci_uart_config_t config; +static timer_source_t timeout; +static uint8_t timeout_active = 0; +static int power_management_sleep = 0; +static linked_list_t clients = NULL; // list of connected clients +static void (*bluetooth_status_handler)(BLUETOOTH_STATE state) = dummy_bluetooth_status_handler; + + static void dummy_bluetooth_status_handler(BLUETOOTH_STATE state){ printf("Bluetooth status: %u\n", state); }; static void daemon_no_connections_timeout(){ - if (clients_requires_power_on()) return; // false alarm :) + if (clients_require_power_on()) return; // false alarm :) printf("No active client connection for %u seconds -> POWER OFF\n", DAEMON_NO_ACTIVE_CLIENT_TIMEOUT/1000); hci_power_control(HCI_POWER_OFF); } @@ -140,7 +140,7 @@ static int btstack_command_handler(connection_t *connection, uint8_t *packet, ui if (!client) break; client->power_mode = packet[3]; // handle merged state - if (!clients_requires_power_on()){ + if (!clients_require_power_on()){ start_power_off_timer(); } else if (!power_management_sleep) { stop_power_off_timer(); @@ -153,7 +153,9 @@ static int btstack_command_handler(connection_t *connection, uint8_t *packet, ui #ifdef USE_BLUETOOL case BTSTACK_SET_SYSTEM_BLUETOOTH_ENABLED: iphone_system_bt_set_enabled(packet[3]); - // fall through .. :) + hci_emit_system_bluetooth_enabled(iphone_system_bt_enabled()); + break; + case BTSTACK_GET_SYSTEM_BLUETOOTH_ENABLED: hci_emit_system_bluetooth_enabled(iphone_system_bt_enabled()); break; @@ -163,6 +165,14 @@ static int btstack_command_handler(connection_t *connection, uint8_t *packet, ui hci_emit_system_bluetooth_enabled(0); break; #endif + case BTSTACK_SET_DISCOVERABLE: + // 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 L2CAP_CREATE_CHANNEL_MTU: bt_flip_addr(addr, &packet[3]); psm = READ_BT_16(packet, 9); @@ -252,8 +262,10 @@ static int daemon_client_handler(connection_t *connection, uint16_t packet_type, if (!client) break; linked_list_remove(&clients, (linked_item_t *) client); free(client); - printf("Client connection closed. clients_requires_power_on()=%u\n",clients_requires_power_on()); - if (!clients_requires_power_on()){ + // 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; @@ -333,7 +345,7 @@ static void power_notification_callback(POWER_NOTIFICATION_t notification){ case POWER_WILL_WAKE_UP: // assume that all clients use Bluetooth -> if connection, start Bluetooth power_management_sleep = 0; - if (clients_requires_power_on()) { + if (clients_require_power_on()) { hci_power_control(HCI_POWER_ON); } break; @@ -528,7 +540,7 @@ static client_state_t * client_for_connection(connection_t *connection) { return NULL; } -static int clients_requires_power_on(){ +static int clients_require_power_on(){ linked_item_t *it; for (it = (linked_item_t *) clients; it ; it = it->next){ client_state_t * client_state = (client_state_t *) it; @@ -538,3 +550,14 @@ static int clients_requires_power_on(){ } return 0; } + +static int clients_require_discoverable(){ + linked_item_t *it; + for (it = (linked_item_t *) clients; it ; it = it->next){ + client_state_t * client_state = (client_state_t *) it; + if (client_state->discoverable) { + return 1; + } + } + return 0; +} diff --git a/src/hci.c b/src/hci.c index 5f1e7e592..59407d93c 100644 --- a/src/hci.c +++ b/src/hci.c @@ -344,6 +344,9 @@ static void event_handler(uint8_t *packet, int size){ log_dbg("hci_read_buffer_size: size %u, count %u\n", hci_stack.acl_data_packet_length, hci_stack.total_num_acl_packets); } } + if (COMMAND_COMPLETE_EVENT(packet, hci_write_scan_enable)){ + hci_emit_discoverable_enabled(hci_stack.discoverable); + } break; case HCI_EVENT_NUMBER_OF_COMPLETED_PACKETS: @@ -758,6 +761,18 @@ int hci_power_control(HCI_POWER_MODE power_mode){ return 0; } +void hci_discoverable_control(uint8_t enable){ + if (enable) enable = 1; // normalize argument + + if (hci_stack.discoverable == enable){ + hci_emit_discoverable_enabled(hci_stack.discoverable); + return; + } + + hci_send_cmd(&hci_write_scan_enable, 2 | enable); // 1 = inq scan, 2 = page scan + hci_stack.discoverable = enable; +} + void hci_run(){ if (hci_stack.num_cmd_packets == 0) { @@ -1026,3 +1041,13 @@ void hci_emit_remote_name_cached(bd_addr_t *addr, device_name_t *name){ hci_dump_packet(HCI_EVENT_PACKET, 0, event, len); hci_stack.packet_handler(HCI_EVENT_PACKET, event, len); } + +void hci_emit_discoverable_enabled(uint8_t enabled){ + uint8_t len = 3; + uint8_t event[len]; + event[0] = BTSTACK_EVENT_DISCOVERABLE_ENABLED; + event[1] = len - 2; + event[2] = enabled; + hci_dump_packet( HCI_EVENT_PACKET, 0, event, len); + hci_stack.packet_handler(HCI_EVENT_PACKET, event, len); +} diff --git a/src/hci.h b/src/hci.h index 0470e20cb..136913574 100644 --- a/src/hci.h +++ b/src/hci.h @@ -89,6 +89,9 @@ extern "C" { // set system Bluetooth state #define BTSTACK_SET_SYSTEM_BLUETOOTH_ENABLED 0x06 +// enable inquiry scan for this client +#define BTSTACK_SET_DISCOVERABLE 0x07 + // create l2cap channel: @param bd_addr(48), psm (16) #define L2CAP_CREATE_CHANNEL 0x20 @@ -223,6 +226,9 @@ typedef struct { uint8_t substate; uint8_t cmds_ready; + /* */ + uint8_t discoverable; + } hci_stack_t; // create and send hci command packets based on a template and a list of parameters @@ -268,6 +274,7 @@ void hci_emit_hci_open_failed(); void hci_emit_btstack_version(); void hci_emit_system_bluetooth_enabled(uint8_t enabled); void hci_emit_remote_name_cached(bd_addr_t *addr, device_name_t *name); +void hci_emit_discoverable_enabled(uint8_t enabled); #if defined __cplusplus }