Example #1
0
static void packet_handler (void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
    //printf("packet_handler type %u, packet[0] %x\n", packet_type, packet[0]);
    if (packet_type == RFCOMM_DATA_PACKET){
        // skip over leading newline
        while (size > 0 && (packet[0] == '\n' || packet[0] == '\r')){
            size--;
            packet++;
        }
        if (strncmp((char *)packet, HSP_AG_RING, strlen(HSP_AG_RING)) == 0){
            emit_ring_event();
        } else if (strncmp((char *)packet, HSP_AG_OK, strlen(HSP_AG_OK)) == 0){
           wait_ok = 0;
        } else if (strncmp((char *)packet, HSP_MICROPHONE_GAIN, strlen(HSP_MICROPHONE_GAIN)) == 0){
            uint8_t gain = (uint8_t)atoi((char*)&packet[strlen(HSP_MICROPHONE_GAIN)]);
            emit_event(HSP_SUBEVENT_MICROPHONE_GAIN_CHANGED, gain);
        
        } else if (strncmp((char *)packet, HSP_SPEAKER_GAIN, strlen(HSP_SPEAKER_GAIN)) == 0){
            uint8_t gain = (uint8_t)atoi((char*)&packet[strlen(HSP_SPEAKER_GAIN)]);
            emit_event(HSP_SUBEVENT_SPEAKER_GAIN_CHANGED, gain);
        } else {
            if (!hsp_hs_callback) return;
            // strip trailing newline
            while (size > 0 && (packet[size-1] == '\n' || packet[size-1] == '\r')){
                size--;
            }
            // add trailing \0
            packet[size] = 0;
            // re-use incoming buffer to avoid reserving large buffers - ugly but efficient
            uint8_t * event = packet - 4;
            event[0] = HCI_EVENT_HSP_META;
            event[1] = size + 2;
            event[2] = HSP_SUBEVENT_AG_INDICATION;
            event[3] = size;
            (*hsp_hs_callback)(event, size+4);
        }
        hsp_run();
        return;
    }

    if (packet_type != HCI_EVENT_PACKET) return;
    uint8_t event = packet[0];
    bd_addr_t event_addr;
    uint16_t handle;

    switch (event) {
        case HCI_EVENT_SYNCHRONOUS_CONNECTION_COMPLETE:{
            if (hsp_state < HSP_RFCOMM_CONNECTION_ESTABLISHED) return;
            int index = 2;
            uint8_t status = packet[index++];
            sco_handle = READ_BT_16(packet, index);
            index+=2;
            bd_addr_t address; 
            memcpy(address, &packet[index], 6);
            index+=6;
            uint8_t link_type = packet[index++];
            uint8_t transmission_interval = packet[index++];  // measured in slots
            uint8_t retransmission_interval = packet[index++];// measured in slots
            uint16_t rx_packet_length = READ_BT_16(packet, index); // measured in bytes
            index+=2;
            uint16_t tx_packet_length = READ_BT_16(packet, index); // measured in bytes
            index+=2;
            uint8_t air_mode = packet[index];

            if (status != 0){
                log_error("(e)SCO Connection failed, status %u", status);
                emit_event_audio_connected(status, sco_handle);
                hsp_state = HSP_RFCOMM_CONNECTION_ESTABLISHED ;
                break;
            }

            switch (link_type){
                case 0x00:
                    log_info("SCO Connection established.");
                    if (transmission_interval != 0) log_error("SCO Connection: transmission_interval not zero: %d.", transmission_interval);
                    if (retransmission_interval != 0) log_error("SCO Connection: retransmission_interval not zero: %d.", retransmission_interval);
                    if (rx_packet_length != 0) log_error("SCO Connection: rx_packet_length not zero: %d.", rx_packet_length);
                    if (tx_packet_length != 0) log_error("SCO Connection: tx_packet_length not zero: %d.", tx_packet_length);
                    break;
                case 0x02:
                    log_info("eSCO Connection established.");
                    break;
                default:
                    log_error("(e)SCO reserved link_type 0x%2x", link_type);
                    break;
            }
            log_info("sco_handle 0x%2x, address %s, transmission_interval %u slots, retransmission_interval %u slots, " 
                 " rx_packet_length %u bytes, tx_packet_length %u bytes, air_mode 0x%2x (0x02 == CVSD)", sco_handle,
                 bd_addr_to_str(address), transmission_interval, retransmission_interval, rx_packet_length, tx_packet_length, air_mode);

            // forward event to app
            hsp_hs_callback(packet, size);

            hsp_state = HSP_AUDIO_CONNECTION_ESTABLISHED;
            emit_event_audio_connected(status, sco_handle);
            break;                
        }

        case RFCOMM_EVENT_INCOMING_CONNECTION:
            // data: event (8), len(8), address(48), channel (8), rfcomm_cid (16)
            if (hsp_state != HSP_IDLE) return;

            bt_flip_addr(event_addr, &packet[2]); 
            rfcomm_cid = READ_BT_16(packet, 9);
            log_info("RFCOMM channel %u requested for %s", packet[8], bd_addr_to_str(event_addr));
            hsp_state = HSP_W4_RFCOMM_CONNECTED;
            rfcomm_accept_connection_internal(rfcomm_cid);
            break;

        case RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE:
            // printf("RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE packet_handler type %u, packet[0] %x\n", packet_type, packet[0]);
            // data: event(8), len(8), status (8), address (48), handle(16), server channel(8), rfcomm_cid(16), max frame size(16)
            if (hsp_state != HSP_W4_RFCOMM_CONNECTED) return;
            if (packet[2]) {
                log_info("RFCOMM channel open failed, status %u", packet[2]);
                hsp_state = HSP_IDLE;
                hsp_hs_reset_state();
            } else {
                // data: event(8) , len(8), status (8), address (48), handle (16), server channel(8), rfcomm_cid(16), max frame size(16)
                rfcomm_handle = READ_BT_16(packet, 9);
                rfcomm_cid = READ_BT_16(packet, 12);
                mtu = READ_BT_16(packet, 14);
                log_info("RFCOMM channel open succeeded. New RFCOMM Channel ID %u, max frame size %u, handle %02x", rfcomm_cid, mtu, rfcomm_handle);
                hsp_state = HSP_RFCOMM_CONNECTION_ESTABLISHED;
            }
            emit_event(HSP_SUBEVENT_RFCOMM_CONNECTION_COMPLETE, packet[2]);
            break;
        case BTSTACK_EVENT_STATE:
        case DAEMON_EVENT_HCI_PACKET_SENT:
        case HCI_EVENT_NUMBER_OF_COMPLETED_PACKETS:
        case RFCOMM_EVENT_CREDITS:
            hsp_hs_callback(packet, size);
            break;
        
        case HCI_EVENT_DISCONNECTION_COMPLETE:
            handle = READ_BT_16(packet,3);
            if (handle == sco_handle){
                sco_handle = 0;
                hsp_state = HSP_RFCOMM_CONNECTION_ESTABLISHED;
                emit_event(HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE,0);
                break;
            } 
            if (handle == rfcomm_handle) {
                rfcomm_handle = 0;
                hsp_state = HSP_IDLE;
                emit_event(HSP_SUBEVENT_RFCOMM_DISCONNECTION_COMPLETE,0);
                hsp_hs_reset_state();
            }
            break;
        case RFCOMM_EVENT_CHANNEL_CLOSED:
            hsp_hs_reset_state();
            hsp_hs_callback(packet, size);
            break;
        default:
            break;
    }
    hsp_run();
}
Example #2
0
static void packet_handler (void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
    // log_info("packet_handler type %u, packet[0] %x", packet_type, packet[0]);
    if (packet_type == RFCOMM_DATA_PACKET){
        while (size > 0 && (packet[0] == '\n' || packet[0] == '\r')){
            size--;
            packet++;
        }

        if (strncmp((char *)packet, HSP_HS_BUTTON_PRESS, strlen(HSP_HS_BUTTON_PRESS)) == 0){
            log_info("Received button press %s", HSP_HS_BUTTON_PRESS);
            ag_num_button_press_received++;
            ag_send_ok = 1;
            if (hsp_state == HSP_ACTIVE && ag_num_button_press_received >=2){
                ag_num_button_press_received = 0;
                hsp_state = HSP_W2_DISCONNECT_SCO;
            }
        } else if (strncmp((char *)packet, HSP_HS_MICROPHONE_GAIN, strlen(HSP_HS_MICROPHONE_GAIN)) == 0){
            uint8_t gain = (uint8_t)atoi((char*)&packet[strlen(HSP_HS_MICROPHONE_GAIN)]);
            ag_send_ok = 1;
            emit_event(HSP_SUBEVENT_MICROPHONE_GAIN_CHANGED, gain);
        
        } else if (strncmp((char *)packet, HSP_HS_SPEAKER_GAIN, strlen(HSP_HS_SPEAKER_GAIN)) == 0){
            uint8_t gain = (uint8_t)atoi((char*)&packet[strlen(HSP_HS_SPEAKER_GAIN)]);
            ag_send_ok = 1;
            emit_event(HSP_SUBEVENT_SPEAKER_GAIN_CHANGED, gain);

        } else if (strncmp((char *)packet, "AT+", 3) == 0){
            ag_send_error = 1;
            if (!hsp_ag_callback) return;
            // re-use incoming buffer to avoid reserving large buffers - ugly but efficient
            uint8_t * event = packet - 4;
            event[0] = HCI_EVENT_HSP_META;
            event[1] = size + 2;
            event[2] = HSP_SUBEVENT_HS_COMMAND;
            event[3] = size;
            (*hsp_ag_callback)(event, size+4);
        }

        hsp_run();
        return;
    }

    if (packet_type != HCI_EVENT_PACKET) return;
    uint8_t event = packet[0];
    bd_addr_t event_addr;
    uint16_t handle;

    switch (event) {
        case HCI_EVENT_SYNCHRONOUS_CONNECTION_COMPLETE:{
            int index = 2;
            uint8_t status = packet[index++];
            sco_handle = READ_BT_16(packet, index);
            index+=2;
            bd_addr_t address; 
            memcpy(address, &packet[index], 6);
            index+=6;
            uint8_t link_type = packet[index++];
            uint8_t transmission_interval = packet[index++];  // measured in slots
            uint8_t retransmission_interval = packet[index++];// measured in slots
            uint16_t rx_packet_length = READ_BT_16(packet, index); // measured in bytes
            index+=2;
            uint16_t tx_packet_length = READ_BT_16(packet, index); // measured in bytes
            index+=2;
            uint8_t air_mode = packet[index];

            if (status != 0){
                log_error("(e)SCO Connection failed, status %u", status);
                emit_event_audio_connected(status, sco_handle);
                break;
            }
            switch (link_type){
                case 0x00:
                    log_info("SCO Connection established.");
                    if (transmission_interval != 0) log_error("SCO Connection: transmission_interval not zero: %d.", transmission_interval);
                    if (retransmission_interval != 0) log_error("SCO Connection: retransmission_interval not zero: %d.", retransmission_interval);
                    if (rx_packet_length != 0) log_error("SCO Connection: rx_packet_length not zero: %d.", rx_packet_length);
                    if (tx_packet_length != 0) log_error("SCO Connection: tx_packet_length not zero: %d.", tx_packet_length);
                    break;
                case 0x02:
                    log_info("eSCO Connection established.");
                    break;
                default:
                    log_error("(e)SCO reserved link_type 0x%2x", link_type);
                    break;
            }
            log_info("sco_handle 0x%2x, address %s, transmission_interval %u slots, retransmission_interval %u slots, " 
                 " rx_packet_length %u bytes, tx_packet_length %u bytes, air_mode 0x%2x (0x02 == CVSD)", sco_handle,
                 bd_addr_to_str(address), transmission_interval, retransmission_interval, rx_packet_length, tx_packet_length, air_mode);

            if (hsp_state == HSP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN){
                hsp_state = HSP_W2_DISCONNECT_SCO;
                break;
            }

            hsp_state = HSP_ACTIVE;
            emit_event_audio_connected(status, sco_handle);
            break;                
        }

        case RFCOMM_EVENT_INCOMING_CONNECTION:
            // data: event (8), len(8), address(48), channel (8), rfcomm_cid (16)
            if (hsp_state != HSP_IDLE) return;

            bt_flip_addr(event_addr, &packet[2]); 
            rfcomm_cid = READ_BT_16(packet, 9);
            log_info("RFCOMM channel %u requested for %s", packet[8], bd_addr_to_str(event_addr));
            rfcomm_accept_connection_internal(rfcomm_cid);

            hsp_state = HSP_W4_RFCOMM_CONNECTED;
            break;

        case RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE:
            log_info("RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE packet_handler type %u, packet[0] %x", packet_type, packet[0]);
            // data: event(8), len(8), status (8), address (48), handle(16), server channel(8), rfcomm_cid(16), max frame size(16)
            if (packet[2]) {
                log_info("RFCOMM channel open failed, status %u§", packet[2]);
                hsp_ag_reset_state();
                emit_event(HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE, packet[2]);
            } else {
                // data: event(8) , len(8), status (8), address (48), handle (16), server channel(8), rfcomm_cid(16), max frame size(16)
                rfcomm_handle = READ_BT_16(packet, 9);
                rfcomm_cid = READ_BT_16(packet, 12);
                mtu = READ_BT_16(packet, 14);
                log_info("RFCOMM channel open succeeded. New RFCOMM Channel ID %u, max frame size %u, state %d", rfcomm_cid, mtu, hsp_state);

                switch (hsp_state){
                    case HSP_W4_RFCOMM_CONNECTED:
                        ag_num_button_press_received = 0;
                        hsp_state = HSP_W2_CONNECT_SCO;
                        break;
                    case HSP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN:
                        hsp_state = HSP_W2_DISCONNECT_RFCOMM;
                        break;
                    default:
                        log_error("no valid state");
                        break;
                }
            }
            break;
        case DAEMON_EVENT_HCI_PACKET_SENT:
        case RFCOMM_EVENT_CREDITS:
            break;
        
        case HCI_EVENT_DISCONNECTION_COMPLETE:
            handle = READ_BT_16(packet,3);
            if (handle == sco_handle){
                log_info("SCO disconnected, w2 disconnect RFCOMM");
                sco_handle = 0;
                hsp_state = HSP_W2_DISCONNECT_RFCOMM;
                break;
            }
            break;
        case RFCOMM_EVENT_CHANNEL_CLOSED:
            log_info("RFCOMM channel closed");
            hsp_ag_reset_state();
            emit_event(HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE,0);
            break;
        default:
            break;
    }
    hsp_run();
}