diff --git a/TODO.txt b/TODO.txt index 6e0781199..01bf66e78 100644 --- a/TODO.txt +++ b/TODO.txt @@ -3,7 +3,6 @@ Last milestone reached: Restart client app without restarting BTdaemon possible NEXT: -- automatic turn off Bluetooth after X minutes idle - turn off Bluetooth on ctrl-c - automatic start/stop of BTdaemon - start BTdaemon by client lib diff --git a/src/daemon.c b/src/daemon.c index a641ea1cf..583a267fe 100644 --- a/src/daemon.c +++ b/src/daemon.c @@ -34,9 +34,18 @@ #include "hci_transport_usb.h" #endif +#define DAEMON_NO_CONNECTION_TIMEOUT 60 + static hci_transport_t * transport; static hci_uart_config_t config; +static timer_t timeout; + +static void daemon_no_connections_timeout(){ + printf("No connection for %u secondes -> POWER OFF\n", DAEMON_NO_CONNECTION_TIMEOUT); + hci_power_control( HCI_POWER_OFF); +} + static int btstack_command_handler(connection_t *connection, uint8_t *packet, uint16_t size){ // BTstack Commands hci_dump_packet( HCI_COMMAND_DATA_PACKET, 1, packet, size); @@ -86,8 +95,22 @@ static int daemon_client_handler(connection_t *connection, uint16_t packet_type, l2cap_send_internal(channel, data, length); break; case DAEMON_EVENT_PACKET: + switch (data[0]) { + case DAEMON_CONNECTION_CLOSED: + l2cap_close_channels_for_connection(connection); + break; + case DAEMON_NR_CONNECTIONS_CHANGED: + // printf("Nr Connections changed, new %u\n", data[1]); + if (data[1]) { + run_loop_remove_timer(&timeout); + } else { + run_loop_set_timer(&timeout, DAEMON_NO_CONNECTION_TIMEOUT); + run_loop_add_timer(&timeout); + } + default: + break; + } // only one event so far: client connection died - l2cap_close_channels_for_connection(connection); break; } return 0; @@ -123,7 +146,9 @@ int main (int argc, const char * argv[]){ // init L2CAP l2cap_init(); - + + timeout.process = daemon_no_connections_timeout; + // @TODO: make choice of socket server configurable (TCP and/or Unix Domain Socket) // @TODO: make port and/or socket configurable per config.h diff --git a/src/hci_cmds.h b/src/hci_cmds.h index cf356f08c..de72c38b8 100644 --- a/src/hci_cmds.h +++ b/src/hci_cmds.h @@ -72,7 +72,7 @@ #define HCI_EVENT_DATA_BUFFER_OVERFLOW 0x1A #define HCI_EVENT_MAX_SLOTS_CHANGED 0x1B #define HCI_EVENT_READ_CLOCK_OFFSET_COMPLETE 0x1C -#define NECTEVENT_ION_PACKET_TYPE_CHANGED 0x1D +#define HCI_EVENT_PACKET_TYPE_CHANGED 0x1D #define HCI_EVENT_INQUIRY_RESULT_WITH_RSSI 0x22 #define HCI_EVENT_VENDOR_SPECIFIC 0xFF @@ -90,6 +90,12 @@ #define HCI_EVENT_L2CAP_TIMEOUT_CHECK 0x84 +// data: event(8) +#define DAEMON_CONNECTION_CLOSED 0xc0 + +// data: event(8), nr_connections(8) +#define DAEMON_NR_CONNECTIONS_CHANGED 0xc1 + #define COMMAND_COMPLETE_EVENT(event,cmd) ( event[0] == HCI_EVENT_COMMAND_COMPLETE && READ_BT_16(event,3) == cmd.opcode) #define IS_COMMAND(packet, command) (READ_BT_16(packet,0) == command.opcode) diff --git a/src/hci_transport.h b/src/hci_transport.h index 07a223401..25f1b966d 100644 --- a/src/hci_transport.h +++ b/src/hci_transport.h @@ -36,6 +36,7 @@ // extension for client/server communication #define L2CAP_DATA_PACKET 0x05 + #define DAEMON_EVENT_PACKET 0x06 typedef struct { diff --git a/src/socket_connection.c b/src/socket_connection.c index 65a3820d5..604ad5f42 100644 --- a/src/socket_connection.c +++ b/src/socket_connection.c @@ -114,15 +114,31 @@ connection_t * socket_connection_register_new_connection(int fd){ return conn; } +void static socket_connection_emit_nr_connections(){ + linked_item_t *it; + uint8_t nr_connections = 0; + for (it = (linked_item_t *) connections; it != NULL ; it = it->next, nr_connections++); + + uint8_t event[2]; + event[0] = DAEMON_NR_CONNECTIONS_CHANGED; + event[1] = nr_connections; + (*socket_connection_packet_callback)(NULL, DAEMON_EVENT_PACKET, 0, (uint8_t *) &event, 2); + // printf("Nr connections changed,.. new %u\n", nr_connections); +} + int socket_connection_hci_process(struct data_source *ds) { connection_t *conn = (connection_t *) ds; int bytes_read = read(ds->fd, &conn->buffer[conn->bytes_read], conn->bytes_to_read); if (bytes_read <= 0){ // connection broken (no particular channel, no date yet) - (*socket_connection_packet_callback)(conn, DAEMON_EVENT_PACKET, 0, NULL, 0); + uint8_t event[1]; + event[0] = DAEMON_CONNECTION_CLOSED; + (*socket_connection_packet_callback)(conn, DAEMON_EVENT_PACKET, 0, (uint8_t *) &event, 1); // free connection socket_connection_free_connection(linked_item_get_user(&ds->item)); + + socket_connection_emit_nr_connections(); return 0; } conn->bytes_read += bytes_read; @@ -161,6 +177,7 @@ static int socket_connection_accept(struct data_source *socket_ds) { printf("socket_connection_accept new connection %u\n", fd); socket_connection_register_new_connection(fd); + socket_connection_emit_nr_connections(); return 0; }