diff --git a/Makefile.am b/Makefile.am index 1882ceb07..e1be9ebb2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -6,8 +6,12 @@ if USE_BLUETOOL patchbluetool = PatchBlueTool endif +if USE_PREFSBUNDLE + patchbluetool = PrefsBundle +endif + AUTOMAKE_OPTIONS = foreign -SUBDIRS = src example $(springboardaccess) $(patchbluetool) +SUBDIRS = src example $(springboardaccess) $(prefsbundle) $(patchbluetool) iphone_ip=@IPHONE_IP@ install-iphone: src/BTdaemon diff --git a/config-cydia.sh b/config-cydia.sh index 0c74782a9..0d6460dde 100755 --- a/config-cydia.sh +++ b/config-cydia.sh @@ -1 +1 @@ -./configure --target=iphone --enable-launchd --enable-ldid --with-uart-speed=921600 \ No newline at end of file +./configure --target=iphone --enable-launchd --enable-ldid --with-prefsbundle --with-uart-speed=921600 \ No newline at end of file diff --git a/configure.in b/configure.in index cd3c31148..e1d5fcac8 100644 --- a/configure.in +++ b/configure.in @@ -12,6 +12,7 @@ AC_ARG_WITH(uart-speed, [AS_HELP_STRING([--with-uart-speed=uartSpeed], [Specify AC_ARG_ENABLE(bluetool, [AS_HELP_STRING([--disable-bluetool],[Disable init of Bluetooth module by BlueTool])], USE_BLUETOOL=$enableval, USE_BLUETOOL="DEFAULT") AC_ARG_ENABLE(springboard, [AS_HELP_STRING([--disable-springboard],[Disable display of BTstack status in SpringBoard])], USE_SPRINGBOARD=$enableval, USE_SPRINGBOARD="DEFAULT") AC_ARG_ENABLE(launchd, [AS_HELP_STRING([--enable-launchd],[Compiles BTdaemon for use by launchd])], USE_LAUNCHD=$enableval, USE_LAUNCHD="no") +AC_ARG_WITH(prefsbundle, [AS_HELP_STRING([--with-prefsbundle],[Compiles iPhone Preferences Bundle])], USE_PREFSBUNDLE=$enableval, USE_PREFSBUNDLE="no") AC_ARG_WITH(iphone-ip, [AS_HELP_STRING([--with-iphone-ip=192.168.1.5], [Specify IP address used by iPhone for installation (not supported yet)])], IPHONE_IP=$withval, IPHONE_IP="") AC_ARG_WITH(vendor-id, [AS_HELP_STRING([--with-vendor-id=vendorID], [Specify USB BT Dongle vendorID])], USB_VENDOR_ID=$withval, USB_VENDOR_ID="") AC_ARG_WITH(product-id, [AS_HELP_STRING([--with-product-id=productID], [Specify USB BT Dongle productID])], USB_PRODUCT_ID=$withval, USB_PRODUCT_ID="") @@ -189,6 +190,7 @@ fi AM_CONDITIONAL(USE_SPRINGBOARD, [test "x$USE_SPRINGBOARD" == "xyes"]) AM_CONDITIONAL(USE_BLUETOOL, [test "x$USE_BLUETOOL" == "xyes"]) +AM_CONDITIONAL(USE_PREFSBUNDLE, [test "x$USE_PREFSBUNDLE" == "xyes"]) # summary if test "x$HCI_TRANSPORT" = xUSB; then @@ -203,6 +205,7 @@ fi echo "USE_LAUNCHD: $USE_LAUNCHD" echo "USE_SPRINGBOARD: $USE_SPRINGBOARD" +echo "USE_PREFSBUNDLE: $USE_PREFSBUNDLE" echo "USE_COCOA_RUN_LOOP: $USE_COCOA_RUN_LOOP" echo "REMOTE_DEVICE_DB: $REMOTE_DEVICE_DB" echo diff --git a/include/btstack/hci_cmds.h b/include/btstack/hci_cmds.h index 13ed9623a..738a4330d 100644 --- a/include/btstack/hci_cmds.h +++ b/include/btstack/hci_cmds.h @@ -215,6 +215,7 @@ extern const hci_cmd_t btstack_get_version; extern const hci_cmd_t btstack_get_system_bluetooth_enabled; extern const hci_cmd_t btstack_set_system_bluetooth_enabled; extern const hci_cmd_t btstack_set_discoverable; +extern const hci_cmd_t btstack_set_bluetooth_enabled; // only used by btstack config extern const hci_cmd_t hci_accept_connection_request; extern const hci_cmd_t hci_authentication_requested; diff --git a/include/btstack/sdp_util.h b/include/btstack/sdp_util.h index 36bc9da7a..e457d0259 100644 --- a/include/btstack/sdp_util.h +++ b/include/btstack/sdp_util.h @@ -79,12 +79,33 @@ typedef enum { #define SDP_ClientExecutableURL 0x000b #define SDP_IconURL 0x000c #define SDP_AdditionalProtocolDescriptorList 0x000d +#define SDP_SupportedFormatsList 0x0303 + +// SERVICE CLASSES +#define SDP_OBEXObjectPush 0x1105 +#define SDP_OBEXFileTransfer 0x1106 +#define SDP_PublicBrowseGroup 0x1002 + +// PROTOCOLS +#define SDP_SDPProtocol 0x0001 +#define SDP_UDPProtocol 0x0002 +#define SDP_RFCOMMProtocol 0x0003 +#define SDP_OBEXProtocol 0x0008 +#define SDP_L2CAPProtocol 0x0100 // OFFSETS FOR LOCALIZED ATTRIBUTES - SDP_LanguageBaseAttributeIDList #define SDP_Offest_ServiceName 0x0000 #define SDP_Offest_ServiceDescription 0x0001 #define SDP_Offest_ProviderName 0x0002 +// OBEX +#define SDP_vCard_2_1 0x01 +#define SDP_vCard_3_0 0x02 +#define SDP_vCal_1_0 0x03 +#define SDP_iCal_2_0 0x04 +#define SDP_vNote 0x05 +#define SDP_vMessage 0x06 +#define SDP_OBEXFileTypeAny 0xFF #pragma mark DateElement void de_dump_data_element(uint8_t * record); diff --git a/src/daemon.c b/src/daemon.c index a87551fc5..ee91f8720 100644 --- a/src/daemon.c +++ b/src/daemon.c @@ -61,6 +61,7 @@ #ifdef USE_BLUETOOL #include "bt_control_iphone.h" +#include #endif #ifdef USE_SPRINGBOARD @@ -94,6 +95,7 @@ static void dummy_bluetooth_status_handler(BLUETOOTH_STATE state); static client_state_t * client_for_connection(connection_t *connection); static int clients_require_power_on(); static int clients_require_discoverable(); +static int clients_clear_power_request(); static void start_power_off_timer(); static void stop_power_off_timer(); @@ -106,6 +108,7 @@ 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 int global_enable = 0; static void dummy_bluetooth_status_handler(BLUETOOTH_STATE state){ printf("Bluetooth status: %u\n", state); @@ -173,6 +176,19 @@ static int btstack_command_handler(connection_t *connection, uint8_t *packet, ui // merge state hci_discoverable_control(clients_require_discoverable()); break; + case BTSTACK_SET_BLUETOOTH_ENABLED: + printf("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); @@ -359,6 +375,12 @@ static void power_notification_callback(POWER_NOTIFICATION_t notification){ } static void daemon_sigint_handler(int param){ + +#ifdef USE_BLUETOOL + // hack for celeste + notify_post("ch.ringwald.btstack.stopped"); +#endif + printf(" <= SIGINT received, shutting down..\n"); hci_power_control( HCI_POWER_OFF); hci_close(); @@ -497,6 +519,11 @@ int main (int argc, char * const * argv){ #endif socket_connection_register_packet_callback(daemon_client_handler); +#ifdef USE_BLUETOOL + // hack for celeste + notify_post("ch.ringwald.btstack.started"); +#endif + // go! run_loop_execute(); return 0; @@ -541,7 +568,18 @@ static client_state_t * client_for_connection(connection_t *connection) { return NULL; } +static int clients_clear_power_request(){ + linked_item_t *it; + for (it = (linked_item_t *) clients; it ; it = it->next){ + client_state_t * client_state = (client_state_t *) it; + client_state->power_mode = HCI_POWER_OFF; + } +} + static int clients_require_power_on(){ + + if (global_enable) return 1; + linked_item_t *it; for (it = (linked_item_t *) clients; it ; it = it->next){ client_state_t * client_state = (client_state_t *) it; diff --git a/src/hci.c b/src/hci.c index 03599c2ab..e4a731195 100644 --- a/src/hci.c +++ b/src/hci.c @@ -309,9 +309,15 @@ static void hci_shutdown_connection(hci_connection_t *conn){ log_dbg("Connection closed: handle %u, ", conn->con_handle); print_bd_addr( conn->address ); log_dbg("\n"); + + // cancel all l2cap connections + hci_emit_disconnection_complete(conn->con_handle, 0x16); // terminated by local host + run_loop_remove_timer(&conn->timeout); linked_list_remove(&hci_stack.connections, (linked_item_t *) conn); free( conn ); + + // now it's gone hci_emit_nr_connections_changed(); } @@ -843,6 +849,12 @@ void hci_run(){ break; } case 6: +#ifdef USE_BLUETOOL + hci_send_cmd(&hci_write_class_of_device, 0x007a020c); // Smartphone + break; + + case 7: +#endif #endif // done. hci_stack.state = HCI_STATE_WORKING; @@ -866,9 +878,6 @@ void hci_run(){ // send disconnected event right away - causes higher layer connections to get closed, too. hci_shutdown_connection(connection); - - // remove from table - hci_stack.connections = connection->item.next; return; } log_dbg("HCI_STATE_HALTING, calling off\n"); @@ -892,9 +901,6 @@ void hci_run(){ // send disconnected event right away - causes higher layer connections to get closed, too. hci_shutdown_connection(connection); - - // remove from table - hci_stack.connections = connection->item.next; return; } @@ -1015,6 +1021,18 @@ void hci_emit_connection_complete(hci_connection_t *conn){ hci_stack.packet_handler(HCI_EVENT_PACKET, event, len); } +void hci_emit_disconnection_complete(uint16_t handle, uint8_t reason){ + uint8_t len = 6; + uint8_t event[len]; + event[0] = HCI_EVENT_DISCONNECTION_COMPLETE; + event[1] = len - 3; + event[2] = 0; // status = OK + bt_store_16(event, 3, handle); + event[5] = reason; + hci_dump_packet( HCI_EVENT_PACKET, 0, event, len); + hci_stack.packet_handler(HCI_EVENT_PACKET, event, len); +} + void hci_emit_l2cap_check_timeout(hci_connection_t *conn){ uint8_t len = 4; uint8_t event[len]; diff --git a/src/hci.h b/src/hci.h index 5ad4181d9..d7b53e49e 100644 --- a/src/hci.h +++ b/src/hci.h @@ -92,6 +92,9 @@ extern "C" { // enable inquiry scan for this client #define BTSTACK_SET_DISCOVERABLE 0x07 +// set global Bluetooth state +#define BTSTACK_SET_BLUETOOTH_ENABLED 0x08 + // create l2cap channel: @param bd_addr(48), psm (16) #define L2CAP_CREATE_CHANNEL 0x20 @@ -270,6 +273,7 @@ uint16_t hci_max_acl_data_packet_length(); void hci_emit_state(); void hci_emit_connection_complete(hci_connection_t *conn); void hci_emit_l2cap_check_timeout(hci_connection_t *conn); +void hci_emit_disconnection_complete(uint16_t handle, uint8_t reason); void hci_emit_nr_connections_changed(); void hci_emit_hci_open_failed(); void hci_emit_btstack_version(); diff --git a/src/hci_cmds.c b/src/hci_cmds.c index eaf669928..3b7f7372e 100644 --- a/src/hci_cmds.c +++ b/src/hci_cmds.c @@ -295,7 +295,7 @@ OPCODE(OGF_CONTROLLER_BASEBAND, 0x36), "H" }; const hci_cmd_t hci_write_link_supervision_timeout = { OPCODE(OGF_CONTROLLER_BASEBAND, 0x37), "H2" -// handle, Range for N: 0x0001 – 0xFFFF Time (Range: 0.625ms – 40.9 sec) +// handle, Range for N: 0x0001 Р0xFFFF Time (Range: 0.625ms Р40.9 sec) }; const hci_cmd_t hci_write_inquiry_mode = { OPCODE(OGF_CONTROLLER_BASEBAND, 0x45), "1" @@ -354,7 +354,10 @@ const hci_cmd_t btstack_set_discoverable = { OPCODE(OGF_BTSTACK, BTSTACK_SET_DISCOVERABLE), "1" }; - +const hci_cmd_t btstack_set_bluetooth_enabled = { +// only used by btstack config +OPCODE(OGF_BTSTACK, BTSTACK_SET_BLUETOOTH_ENABLED), "1" +}; const hci_cmd_t l2cap_create_channel = { OPCODE(OGF_BTSTACK, L2CAP_CREATE_CHANNEL), "B2" diff --git a/src/hci_transport_h4.c b/src/hci_transport_h4.c index 8684863f0..17766e2f3 100644 --- a/src/hci_transport_h4.c +++ b/src/hci_transport_h4.c @@ -276,8 +276,13 @@ static void h4_statemachine(){ static int h4_process(struct data_source *ds) { if (hci_transport_h4->uart_fd == 0) return -1; + int read_now = bytes_to_read; + // if (read_now > 100) { + // read_now = 100; + // } + // read up to bytes_to_read data in - int bytes_read = read(hci_transport_h4->uart_fd, &hci_packet[read_pos], bytes_to_read); + ssize_t bytes_read = read(hci_transport_h4->uart_fd, &hci_packet[read_pos], read_now); // printf("h4_process: bytes read %u\n", bytes_read); if (bytes_read < 0) { return bytes_read; diff --git a/src/run_loop_posix.c b/src/run_loop_posix.c index 12a0ff806..e8b1ee99d 100644 --- a/src/run_loop_posix.c +++ b/src/run_loop_posix.c @@ -44,14 +44,19 @@ #include #include +void posix_dump_timer(); + // the run loop static linked_list_t data_sources; +static int data_sources_modified; static linked_list_t timers; /** * Add data_source to run_loop */ void posix_add_data_source(data_source_t *ds){ + data_sources_modified = 1; + // printf("posix_add_data_source %x with fd %u\n", (int) ds, ds->fd); linked_list_add(&data_sources, (linked_item_t *) ds); } @@ -59,6 +64,8 @@ void posix_add_data_source(data_source_t *ds){ * Remove data_source from run loop */ int posix_remove_data_source(data_source_t *ds){ + data_sources_modified = 1; + // printf("posix_remove_data_source %x\n", (int) ds); return linked_list_remove(&data_sources, (linked_item_t *) ds); } @@ -68,7 +75,11 @@ int posix_remove_data_source(data_source_t *ds){ void posix_add_timer(timer_source_t *ts){ linked_item_t *it; for (it = (linked_item_t *) &timers; it->next ; it = it->next){ - if (run_loop_timer_compare( (timer_source_t *) it->next, ts) >= 0) { + if ((timer_source_t *) it->next == ts){ + fprintf(stderr, "run_loop_timer_add error: timer to add already in list!\n"); + return; + } + if (run_loop_timer_compare( (timer_source_t *) it->next, ts) > 0) { break; } } @@ -83,6 +94,7 @@ void posix_add_timer(timer_source_t *ts){ */ int posix_remove_timer(timer_source_t *ts){ // printf("Removed timer %x at %u\n", (int) ts, (unsigned int) ts->timeout.tv_sec); + // posix_dump_timer(); return linked_list_remove(&timers, (linked_item_t *) ts); } @@ -141,14 +153,19 @@ void posix_execute() { // wait for ready FDs select( highest_fd+1 , &descriptors, NULL, NULL, timeout); - // process data sources - data_source_t *next; - for (ds = (data_source_t *) data_sources; ds != NULL ; ds = next){ - next = (data_source_t *) ds->item.next; // cache pointer to next data_source to allow data source to remove itself + // process data sources very carefully + // bt_control.close() triggered from a client can remove a different data source + + // printf("posix_execute: before ds check\n"); + data_sources_modified = 0; + for (ds = (data_source_t *) data_sources; !data_sources_modified && ds != NULL; ds = (data_source_t *) ds->item.next){ + // printf("posix_execute: check %x with fd %u\n", (int) ds, ds->fd); if (FD_ISSET(ds->fd, &descriptors)) { + // printf("posix_execute: process %x with fd %u\n", (int) ds, ds->fd); ds->process(ds); } } + // printf("posix_execute: after ds check\n"); // process timers // pre: 0 <= tv_usec < 1000000 @@ -157,6 +174,9 @@ void posix_execute() { ts = (timer_source_t *) timers; if (ts->timeout.tv_sec > current_tv.tv_sec) break; if (ts->timeout.tv_sec == current_tv.tv_sec && ts->timeout.tv_usec > current_tv.tv_usec) break; + // printf("posix_execute: process times %x\n", (int) ts); + + // remove timer before processing it to allow handler to re-register with run loop run_loop_remove_timer(ts); ts->process(ts); }