diff --git a/TODO.txt b/TODO.txt index e8c405985..d0448d482 100644 --- a/TODO.txt +++ b/TODO.txt @@ -3,11 +3,9 @@ Last milestone reached: Restart client app without restarting BTdaemon possible NEXT: -- client/server part using unix domain sockets (portable and fast) - iPhone status icon support - - create BTstack icon. Flipped B in red, or blue on orange - - bt_control_iphone.c -> bt_control_iphone.m // or objcSendMsg - call SpringBoard on/off BT +- client/server part using unix domain sockets (portable and fast) - automatic start/stop of BTdaemon - start BTdaemon by client lib - e.g. use popen and wait for initial "I'm ready" message diff --git a/configure.in b/configure.in index bbd116932..c64d416aa 100644 --- a/configure.in +++ b/configure.in @@ -9,6 +9,7 @@ AC_ARG_WITH(hci-transport, [AS_HELP_STRING([--with-hci-transport=transportType], AC_ARG_WITH(uart-device, [AS_HELP_STRING([--with-uart-device=uartDevice], [Specify BT UART device to use])], UART_DEVICE=$withval, UART_DEVICE="DEFAULT") AC_ARG_WITH(uart-speed, [AS_HELP_STRING([--with-uart-speed=uartSpeed], [Specify BT UART speed to use])], UART_SPEED=$withval, UART_SPEED="115200") 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_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="") @@ -21,6 +22,7 @@ AC_CANONICAL_HOST # Checks for programs. AC_PROG_CC AC_PROG_CPP +AC_PROG_OBJC AC_PROG_INSTALL AC_PROG_LN_S AC_PROG_MAKE_SET @@ -90,6 +92,10 @@ if test "x$target" = xiphone; then USE_BLUETOOL="yes" echo "USE_BLUETOOL=$USE_BLUETOOL" fi + if test "x$USE_SPRINGBOARD" = xDEFAULT ; then + USE_SPRINGBOARD="yes" + echo "USE_SPRINGBOARD=$USE_SPRINGBOARD" + fi else if test "x$UART_DEVICE" = xDEFAULT ; then UART_DEVICE=/dev/ttyS0 @@ -121,6 +127,9 @@ else if test "x$USE_BLUETOOL" = xyes; then echo "#define USE_BLUETOOL" >> config.h fi + if test "x$USE_SPRINGBOARD" = xyes; then + echo "#define USE_SPRINGBOARD" >> config.h + fi fi AC_SUBST(IPHONE_IP) diff --git a/project.xcodeproj/project.pbxproj b/project.xcodeproj/project.pbxproj index 9852687f0..47a1ad624 100644 --- a/project.xcodeproj/project.pbxproj +++ b/project.xcodeproj/project.pbxproj @@ -17,6 +17,7 @@ 9C1F0E9A0FDAE023008F472F /* run_loop.c in Sources */ = {isa = PBXBuildFile; fileRef = 9C1F0E980FDAE023008F472F /* run_loop.c */; }; 9C2071F310014D3200A07EA4 /* hci_transport_usb.c in Sources */ = {isa = PBXBuildFile; fileRef = 9C2071F210014D3200A07EA4 /* hci_transport_usb.c */; }; 9C46FC3A0FA906F700ABEF05 /* hci_transport_h4.c in Sources */ = {isa = PBXBuildFile; fileRef = 9C46FC360FA906F700ABEF05 /* hci_transport_h4.c */; }; + 9C6459E01037554B0081A00B /* platform_iphone.m in Sources */ = {isa = PBXBuildFile; fileRef = 9C6459DF1037554B0081A00B /* platform_iphone.m */; }; 9C7B5AC0100BD3340065D87E /* linked_list.c in Sources */ = {isa = PBXBuildFile; fileRef = 9C7B5ABF100BD3340065D87E /* linked_list.c */; }; 9C7B5D01100FC9AE0065D87E /* btstack.c in Sources */ = {isa = PBXBuildFile; fileRef = 9CC813A10FFC0774002816F9 /* btstack.c */; }; 9C7B5D03100FC9BB0065D87E /* test.c in Sources */ = {isa = PBXBuildFile; fileRef = 9C7B5B7E100D04450065D87E /* test.c */; }; @@ -60,6 +61,8 @@ 9C46FC360FA906F700ABEF05 /* hci_transport_h4.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; name = hci_transport_h4.c; path = src/hci_transport_h4.c; sourceTree = ""; }; 9C46FC370FA906F700ABEF05 /* hci_transport_h4.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; name = hci_transport_h4.h; path = src/hci_transport_h4.h; sourceTree = ""; }; 9C46FC380FA906F700ABEF05 /* hci_transport.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; name = hci_transport.h; path = src/hci_transport.h; sourceTree = ""; }; + 9C6459DE1037554B0081A00B /* platform_iphone.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = platform_iphone.h; path = src/platform_iphone.h; sourceTree = ""; }; + 9C6459DF1037554B0081A00B /* platform_iphone.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = platform_iphone.m; path = src/platform_iphone.m; sourceTree = ""; }; 9C7B5ABE100BD3340065D87E /* linked_list.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = linked_list.h; path = src/linked_list.h; sourceTree = ""; }; 9C7B5ABF100BD3340065D87E /* linked_list.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = linked_list.c; path = src/linked_list.c; sourceTree = ""; }; 9C7B5B7E100D04450065D87E /* test.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = test.c; path = example/test.c; sourceTree = ""; }; @@ -142,6 +145,8 @@ 9C00F7311017ACC3008DAB17 /* socket_connection.h */, 9C00F86210191097008DAB17 /* utils.c */, 9C00F86310191097008DAB17 /* utils.h */, + 9C6459DE1037554B0081A00B /* platform_iphone.h */, + 9C6459DF1037554B0081A00B /* platform_iphone.m */, ); name = Source; sourceTree = ""; @@ -245,6 +250,7 @@ 9C00F86510191097008DAB17 /* utils.c in Sources */, 9C00F87410191130008DAB17 /* l2cap_signaling.c in Sources */, 9CCE6CEA1025BD0000FCE9F4 /* hci.c in Sources */, + 9C6459E01037554B0081A00B /* platform_iphone.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/src/Makefile.am b/src/Makefile.am index 5dd34552e..97ccd0bd1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -15,6 +15,7 @@ BTdaemon_SOURCES = \ l2cap.c \ l2cap_signaling.c \ linked_list.c \ + platform_iphone.m \ run_loop.c \ socket_connection.c \ utils.c @@ -31,6 +32,7 @@ include_HEADERS = \ linked_list.h \ l2cap.h \ l2cap_signaling.h \ + platform_iphone.h \ run_loop.h \ socket_connection.h \ utils.h diff --git a/src/daemon.c b/src/daemon.c index 8c71d0ea6..25c51f0c5 100644 --- a/src/daemon.c +++ b/src/daemon.c @@ -42,8 +42,13 @@ static hci_uart_config_t config; static timer_t timeout; +static void dummy_bluetooth_status_handler(BLUETOOTH_STATE state){ + printf("Bluetooth status: %u\n", state); +}; +static void (*bluetooth_status_handler)(BLUETOOTH_STATE state) = dummy_bluetooth_status_handler; + static void daemon_no_connections_timeout(){ - printf("No connection for %u secondes -> POWER OFF\n", DAEMON_NO_CONNECTION_TIMEOUT); + printf("No connection for %u seconds -> POWER OFF\n", DAEMON_NO_CONNECTION_TIMEOUT); hci_power_control( HCI_POWER_OFF); } @@ -111,13 +116,37 @@ static int daemon_client_handler(connection_t *connection, uint16_t packet_type, default: break; } - // only one event so far: client connection died break; } return 0; } -void daemon_sigint_handler(int param){ +static void daemon_event_handler(uint8_t *packet, uint16_t size){ + // handle state event + if (packet[0] == HCI_EVENT_BTSTACK_WORKING){ + bluetooth_status_handler(BLUETOOTH_ON); + } + if (packet[0] == HCI_EVENT_BTSTACK_STATE){ + if (packet[2] == HCI_STATE_WORKING) { + bluetooth_status_handler(BLUETOOTH_ON); + } + if (packet[2] == HCI_STATE_OFF) { + bluetooth_status_handler(BLUETOOTH_OFF); + } + } + if (packet[0] == HCI_EVENT_NR_CONNECTIONS_CHANGED){ + if (packet[2]) { + bluetooth_status_handler(BLUETOOTH_ACTIVE); + } else { + bluetooth_status_handler(BLUETOOTH_ON); + } + } + + // forward event to clients + socket_connection_send_packet_all(HCI_EVENT_PACKET, 0, packet, size); +} + +static void daemon_sigint_handler(int param){ printf(" <= SIGINT received, shutting down..\n"); hci_power_control( HCI_POWER_OFF); printf("Good bye, see you.\n"); @@ -142,7 +171,11 @@ int main (int argc, const char * argv[]){ #ifdef USE_BLUETOOL control = &bt_control_iphone; #endif - + +#ifdef USE_SPRINGBOARD + bluetooth_status_handler = platform_iphone_status_handler +#endif + // @TODO: allow configuration per HCI CMD // use logger: format HCI_DUMP_PACKETLOGGER, HCI_DUMP_BLUEZ or HCI_DUMP_STDOUT @@ -154,7 +187,7 @@ int main (int argc, const char * argv[]){ // init L2CAP l2cap_init(); - + l2cap_register_event_packet_handler(daemon_event_handler); timeout.process = daemon_no_connections_timeout; // @TODO: make choice of socket server configurable (TCP and/or Unix Domain Socket) diff --git a/src/hci.c b/src/hci.c index bf2a1da40..af0b665e5 100644 --- a/src/hci.c +++ b/src/hci.c @@ -94,6 +94,15 @@ static hci_connection_t * connection_for_address(bd_addr_t address){ return NULL; } +/** + * count connections + */ +static int nr_hci_connections(){ + int count; + linked_item_t *it; + for (it = (linked_item_t *) hci_stack.connections; it ; it = it->next, count++); + return count; +} /** * Dummy handler called by HCI @@ -159,6 +168,8 @@ static void event_handler(uint8_t *packet, int size){ printf("New connection: handle %u, ", conn->con_handle); print_bd_addr( conn->address ); printf("\n"); + + hci_emit_nr_connections_changed(); } } } @@ -174,6 +185,7 @@ static void event_handler(uint8_t *packet, int size){ run_loop_remove_timer(&conn->timeout); linked_list_remove(&hci_stack.connections, (linked_item_t *) conn); free( conn ); + hci_emit_nr_connections_changed(); } } } @@ -273,6 +285,9 @@ int hci_power_control(HCI_POWER_MODE power_mode){ // power off hci_stack.control->off(hci_stack.config); + + // we're off now + hci_stack.state = HCI_STATE_OFF; } hci_emit_state(); @@ -411,3 +426,13 @@ void hci_emit_l2cap_check_timeout(hci_connection_t *conn){ hci_dump_packet( HCI_EVENT_PACKET, 0, event, len); hci_stack.event_packet_handler(event, len); } + +void hci_emit_nr_connections_changed(){ + uint8_t len = 3; + uint8_t event[len]; + event[0] = HCI_EVENT_NR_CONNECTIONS_CHANGED; + event[1] = 1; + event[2] = nr_hci_connections(); + hci_dump_packet( HCI_EVENT_PACKET, 0, event, len); + hci_stack.event_packet_handler(event, len); +} diff --git a/src/hci.h b/src/hci.h index ec31c0d3c..7e06022d1 100644 --- a/src/hci.h +++ b/src/hci.h @@ -33,6 +33,12 @@ typedef enum { SENT_DISCONNECT } CONNECTION_STATE; +typedef enum { + BLUETOOTH_OFF = 1, + BLUETOOTH_ON, + BLUETOOTH_ACTIVE +} BLUETOOTH_STATE; + typedef struct { // linked list - assert: first field linked_item_t item; @@ -115,3 +121,4 @@ int hci_send_acl_packet(uint8_t *packet, int size); 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_nr_connections_changed(); diff --git a/src/hci_cmds.h b/src/hci_cmds.h index de72c38b8..a938a338f 100644 --- a/src/hci_cmds.h +++ b/src/hci_cmds.h @@ -89,6 +89,8 @@ // data: event(8), len(8), handle(16) #define HCI_EVENT_L2CAP_TIMEOUT_CHECK 0x84 +// data: event(8), len(8), nr hci connections +#define HCI_EVENT_NR_CONNECTIONS_CHANGED 0x85 // data: event(8) #define DAEMON_CONNECTION_CLOSED 0xc0 diff --git a/src/l2cap.c b/src/l2cap.c index 1319d4dd6..2dd8a16f1 100644 --- a/src/l2cap.c +++ b/src/l2cap.c @@ -158,9 +158,6 @@ void l2cap_event_handler( uint8_t *packet, uint16_t size ){ // forward to higher layers (*event_packet_handler)(packet, size); - - // forward event to clients - socket_connection_send_packet_all(HCI_EVENT_PACKET, 0, packet, size); } void l2cap_signaling_handler(l2cap_channel_t *channel, uint8_t *packet, uint16_t size){ diff --git a/src/l2cap.h b/src/l2cap.h index 34b36f843..ff710010f 100644 --- a/src/l2cap.h +++ b/src/l2cap.h @@ -48,6 +48,7 @@ typedef struct { } l2cap_service_t; void l2cap_init(); +void l2cap_register_event_packet_handler(void (*handler)(uint8_t *packet, uint16_t size)); void l2cap_create_channel_internal(connection_t * connection, bd_addr_t address, uint16_t psm); void l2cap_disconnect_internal(uint16_t source_cid, uint8_t reason); void l2cap_send_internal(uint16_t source_cid, uint8_t *data, uint16_t len);