Esempio n. 1
0
File: hci.c Progetto: ajsb85/ioio
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);
            }
            connection->authentication_flags &= ~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, 2 | 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 & page scans\n");
                    hci_send_cmd(&hci_write_scan_enable, 0); // none
                    
                    // 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;
    }
}
Esempio n. 2
0
static int btstack_command_handler(connection_t *connection, uint8_t *packet, uint16_t size){
    
    bd_addr_t addr;
    uint16_t cid;
    uint16_t psm;
    uint16_t service_channel;
    uint16_t mtu;
    uint8_t  reason;
    uint8_t  rfcomm_channel;
    uint8_t  rfcomm_credits;
    uint32_t service_record_handle;
    client_state_t *client;
    
    uint16_t serviceSearchPatternLen;
    uint16_t attributeIDListLen;

    // BTstack internal commands - 16 Bit OpCode, 8 Bit ParamLen, Params...
    switch (READ_CMD_OCF(packet)){
        case BTSTACK_GET_STATE:
            log_info("BTSTACK_GET_STATE");
            hci_emit_state();
            break;
        case BTSTACK_SET_POWER_MODE:
            log_info("BTSTACK_SET_POWER_MODE %u", packet[3]);
            // track client power requests
            client = client_for_connection(connection);
            if (!client) break;
            client->power_mode = packet[3];
            // handle merged state
            if (!clients_require_power_on()){
                start_power_off_timer();
            } else if (!power_management_sleep) {
                stop_power_off_timer();
                hci_power_control(HCI_POWER_ON);
            }
            break;
        case BTSTACK_GET_VERSION:
            log_info("BTSTACK_GET_VERSION");
            hci_emit_btstack_version();
            break;   
#ifdef USE_BLUETOOL
        case BTSTACK_SET_SYSTEM_BLUETOOTH_ENABLED:
            log_info("BTSTACK_SET_SYSTEM_BLUETOOTH_ENABLED %u", packet[3]);
            iphone_system_bt_set_enabled(packet[3]);
            hci_emit_system_bluetooth_enabled(iphone_system_bt_enabled());
            break;
            
        case BTSTACK_GET_SYSTEM_BLUETOOTH_ENABLED:
            log_info("BTSTACK_GET_SYSTEM_BLUETOOTH_ENABLED");
            hci_emit_system_bluetooth_enabled(iphone_system_bt_enabled());
            break;
#else
        case BTSTACK_SET_SYSTEM_BLUETOOTH_ENABLED:
        case BTSTACK_GET_SYSTEM_BLUETOOTH_ENABLED:
            hci_emit_system_bluetooth_enabled(0);
            break;
#endif
        case BTSTACK_SET_DISCOVERABLE:
            log_info("BTSTACK_SET_DISCOVERABLE discoverable %u)", packet[3]);
            // 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 BTSTACK_SET_BLUETOOTH_ENABLED:
            log_info("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);
            mtu = READ_BT_16(packet, 11);
            l2cap_create_channel_internal( connection, NULL, addr, psm, mtu);
            break;
        case L2CAP_CREATE_CHANNEL:
            bt_flip_addr(addr, &packet[3]);
            psm = READ_BT_16(packet, 9);
            l2cap_create_channel_internal( connection, NULL, addr, psm, 150);   // until r865
            break;
        case L2CAP_DISCONNECT:
            cid = READ_BT_16(packet, 3);
            reason = packet[5];
            l2cap_disconnect_internal(cid, reason);
            break;
        case L2CAP_REGISTER_SERVICE:
            psm = READ_BT_16(packet, 3);
            mtu = READ_BT_16(packet, 5);
            l2cap_register_service_internal(connection, NULL, psm, mtu);
            break;
        case L2CAP_UNREGISTER_SERVICE:
            psm = READ_BT_16(packet, 3);
            l2cap_unregister_service_internal(connection, psm);
            break;
        case L2CAP_ACCEPT_CONNECTION:
            cid    = READ_BT_16(packet, 3);
            l2cap_accept_connection_internal(cid);
            break;
        case L2CAP_DECLINE_CONNECTION:
            cid    = READ_BT_16(packet, 3);
            reason = packet[7];
            l2cap_decline_connection_internal(cid, reason);
            break;
        case RFCOMM_CREATE_CHANNEL:
            bt_flip_addr(addr, &packet[3]);
            rfcomm_channel = packet[9];
            rfcomm_create_channel_internal( connection, &addr, rfcomm_channel );
            break;
        case RFCOMM_CREATE_CHANNEL_WITH_CREDITS:
            bt_flip_addr(addr, &packet[3]);
            rfcomm_channel = packet[9];
            rfcomm_credits = packet[10];
            rfcomm_create_channel_with_initial_credits_internal( connection, &addr, rfcomm_channel, rfcomm_credits );
            break;
        case RFCOMM_DISCONNECT:
            cid = READ_BT_16(packet, 3);
            reason = packet[5];
            rfcomm_disconnect_internal(cid);
            break;
        case RFCOMM_REGISTER_SERVICE:
            rfcomm_channel = packet[3];
            mtu = READ_BT_16(packet, 4);
            rfcomm_register_service_internal(connection, rfcomm_channel, mtu);
            break;
        case RFCOMM_REGISTER_SERVICE_WITH_CREDITS:
            rfcomm_channel = packet[3];
            mtu = READ_BT_16(packet, 4);
            rfcomm_credits = packet[6];
            rfcomm_register_service_with_initial_credits_internal(connection, rfcomm_channel, mtu, rfcomm_credits);
            break;
        case RFCOMM_UNREGISTER_SERVICE:
            service_channel = READ_BT_16(packet, 3);
            rfcomm_unregister_service_internal(service_channel);
            break;
        case RFCOMM_ACCEPT_CONNECTION:
            cid    = READ_BT_16(packet, 3);
            rfcomm_accept_connection_internal(cid);
            break;
        case RFCOMM_DECLINE_CONNECTION:
            cid    = READ_BT_16(packet, 3);
            reason = packet[7];
            rfcomm_decline_connection_internal(cid);
            break;            
        case RFCOMM_GRANT_CREDITS:
            cid    = READ_BT_16(packet, 3);
            rfcomm_credits = packet[5];
            rfcomm_grant_credits(cid, rfcomm_credits);
            break;
        case RFCOMM_PERSISTENT_CHANNEL: {
            if (remote_device_db) {
                // enforce \0
                packet[3+248] = 0;
                rfcomm_channel = remote_device_db->persistent_rfcomm_channel((char*)&packet[3]);
            } else {
                // NOTE: hack for non-iOS platforms
                rfcomm_channel = rfcomm_channel_generator++;
            }
            log_info("RFCOMM_EVENT_PERSISTENT_CHANNEL %u", rfcomm_channel);
            uint8_t event[4];
            event[0] = RFCOMM_EVENT_PERSISTENT_CHANNEL;
            event[1] = sizeof(event) - 2;
            event[2] = 0;
            event[3] = rfcomm_channel;
            hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event));
            socket_connection_send_packet(connection, HCI_EVENT_PACKET, 0, (uint8_t *) event, sizeof(event));
            break;
        }
            
        case SDP_REGISTER_SERVICE_RECORD:
            log_info("SDP_REGISTER_SERVICE_RECORD size %u\n", size);
            sdp_register_service_internal(connection, &packet[3]);
            break;
        case SDP_UNREGISTER_SERVICE_RECORD:
            service_record_handle = READ_BT_32(packet, 3);
            log_info("SDP_UNREGISTER_SERVICE_RECORD handle 0x%x ", service_record_handle);
            sdp_unregister_service_internal(connection, service_record_handle);
            break;
        case SDP_CLIENT_QUERY_RFCOMM_SERVICES: 
            bt_flip_addr(addr, &packet[3]);

            serviceSearchPatternLen = de_get_len(&packet[9]);
            memcpy(serviceSearchPattern, &packet[9], serviceSearchPatternLen);

            sdp_query_rfcomm_register_callback(handle_sdp_rfcomm_service_result, connection);
            sdp_query_rfcomm_channel_and_name_for_search_pattern(addr, serviceSearchPattern);

            break;
        case SDP_CLIENT_QUERY_SERVICES:
            bt_flip_addr(addr, &packet[3]);
            sdp_parser_init();
            sdp_parser_register_callback(handle_sdp_client_query_result);

            serviceSearchPatternLen = de_get_len(&packet[9]);
            memcpy(serviceSearchPattern, &packet[9], serviceSearchPatternLen);
            
            attributeIDListLen = de_get_len(&packet[9+serviceSearchPatternLen]); 
            memcpy(attributeIDList, &packet[9+serviceSearchPatternLen], attributeIDListLen);
            
            sdp_client_query(addr, (uint8_t*)&serviceSearchPattern[0], (uint8_t*)&attributeIDList[0]);

            // sdp_general_query_for_uuid(addr, 0x1002);
            break;
        default:
            log_error("Error: command %u not implemented\n:", READ_CMD_OCF(packet));
            break;
    }
    
    // verbose log info on command before dumped command unknown to PacketLogger or Wireshark
    hci_dump_packet( HCI_COMMAND_DATA_PACKET, 1, packet, size);

    return 0;
}
Esempio n. 3
0
File: hci.c Progetto: ajsb85/ioio
int hci_power_control(HCI_POWER_MODE power_mode){
    
    log_info("hci_power_control: %u, current mode %u\n", power_mode, hci_stack.state);
    
    int err = 0;
    switch (hci_stack.state){
            
        case HCI_STATE_OFF:
            switch (power_mode){
                case HCI_POWER_ON:
                    err = hci_power_control_on();
                    if (err) return err;
                    // set up state machine
                    hci_stack.num_cmd_packets = 1; // assume that one cmd can be sent
                    hci_stack.state = HCI_STATE_INITIALIZING;
                    hci_stack.substate = 0;
                    break;
                case HCI_POWER_OFF:
                    // do nothing
                    break;  
                case HCI_POWER_SLEEP:
                    // do nothing (with SLEEP == OFF)
                    break;
            }
            break;
            
        case HCI_STATE_INITIALIZING:
            switch (power_mode){
                case HCI_POWER_ON:
                    // do nothing
                    break;
                case HCI_POWER_OFF:
                    // no connections yet, just turn it off
                    hci_power_control_off();
                    break;  
                case HCI_POWER_SLEEP:
                    // no connections yet, just turn it off
                    hci_power_control_sleep();
                    break;
            }
            break;
            
        case HCI_STATE_WORKING:
            switch (power_mode){
                case HCI_POWER_ON:
                    // do nothing
                    break;
                case HCI_POWER_OFF:
                    // see hci_run
                    hci_stack.state = HCI_STATE_HALTING;
                    break;  
                case HCI_POWER_SLEEP:
                    // see hci_run
                    hci_stack.state = HCI_STATE_FALLING_ASLEEP;
                    hci_stack.substate = 0;
                    break;
            }
            break;
            
        case HCI_STATE_HALTING:
            switch (power_mode){
                case HCI_POWER_ON:
                    // set up state machine
                    hci_stack.state = HCI_STATE_INITIALIZING;
                    hci_stack.substate = 0;
                    break;
                case HCI_POWER_OFF:
                    // do nothing
                    break;  
                case HCI_POWER_SLEEP:
                    // see hci_run
                    hci_stack.state = HCI_STATE_FALLING_ASLEEP;
                    hci_stack.substate = 0;
                    break;
            }
            break;
            
        case HCI_STATE_FALLING_ASLEEP:
            switch (power_mode){
                case HCI_POWER_ON:

#if defined(USE_POWERMANAGEMENT) && defined(USE_BLUETOOL)
                    // nothing to do, if H4 supports power management
                    if (bt_control_iphone_power_management_enabled()){
                        hci_stack.state = HCI_STATE_INITIALIZING;
                        hci_stack.substate = 6;
                        break;
                    }
#endif
                    // set up state machine
                    hci_stack.num_cmd_packets = 1; // assume that one cmd can be sent
                    hci_stack.state = HCI_STATE_INITIALIZING;
                    hci_stack.substate = 0;
                    break;
                case HCI_POWER_OFF:
                    // see hci_run
                    hci_stack.state = HCI_STATE_HALTING;
                    break;  
                case HCI_POWER_SLEEP:
                    // do nothing
                    break;
            }
            break;
            
        case HCI_STATE_SLEEPING:
            switch (power_mode){
                case HCI_POWER_ON:
                    
#if defined(USE_POWERMANAGEMENT) && defined(USE_BLUETOOL)
                    // nothing to do, if H4 supports power management
                    if (bt_control_iphone_power_management_enabled()){
                        hci_stack.state = HCI_STATE_INITIALIZING;
                        hci_stack.substate = 6;
                        break;
                    }
#endif
                    err = hci_power_control_wake();
                    if (err) return err;
                    // set up state machine
                    hci_stack.num_cmd_packets = 1; // assume that one cmd can be sent
                    hci_stack.state = HCI_STATE_INITIALIZING;
                    hci_stack.substate = 0;
                    break;
                case HCI_POWER_OFF:
                    hci_stack.state = HCI_STATE_HALTING;
                    break;  
                case HCI_POWER_SLEEP:
                    // do nothing
                    break;
            }
            break;
    }

    // create internal event
	hci_emit_state();
    
	// trigger next/first action
	hci_run();
	
    return 0;
}