Ejemplo n.º 1
0
// AG +VGS=5  [0..15] ; HS AT+VGM=6 | AG OK
void hsp_hs_set_speaker_gain(uint8_t gain){
    if (gain < 0 || gain >15) {
        log_info("Gain must be in interval [0..15], it is given %d", gain);
        return; 
    }
    hs_speaker_gain = gain;
    hsp_run();
}  
Ejemplo n.º 2
0
void hsp_hs_set_microphone_gain(uint8_t gain){
    if (gain < 0 || gain >15) {
        printf("Gain must be in interval [0..15], it is given %d\n", gain);
        return; 
    }
    hs_microphone_gain = gain;
    hsp_run();
}
Ejemplo n.º 3
0
void hsp_ag_set_microphone_gain(uint8_t gain){
    if (gain < 0 || gain >15) {
        log_error("Gain must be in interval [0..15], it is given %d", gain);
        return; 
    }
    ag_microphone_gain = gain;
    hsp_run();
}
Ejemplo n.º 4
0
// AG +VGS=5  [0..15] ; HS AT+VGM=6 | AG OK
void hsp_ag_set_speaker_gain(uint8_t gain){
    if (gain < 0 || gain >15) {
        printf("Gain must be in interval [0..15], it is given %d\n", gain);
        return; 
    }
    ag_speaker_gain = gain;
    hsp_run();
}  
Ejemplo n.º 5
0
void hsp_hs_establish_audio_connection(void){
    switch (hsp_state){
        case HSP_RFCOMM_CONNECTION_ESTABLISHED:
            hsp_establish_audio_connection = 1;
            hsp_state = HSP_W4_SCO_CONNECTED;
            break;
        case HSP_W4_RFCOMM_CONNECTED:
            hsp_state = HSP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN;
            break;
        default:
            break;
    }
    hsp_run();
}
Ejemplo n.º 6
0
void hsp_hs_disconnect(bd_addr_t bd_addr){
    switch (hsp_state){
        case HSP_ACTIVE:
            printf("HSP_W4_USER_ACTION\n");
            hsp_state = HSP_W4_USER_ACTION;
            hs_send_button_press = 1;
            break;
        case HSP_W4_RFCOMM_CONNECTED:
            printf("HSP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN \n");
            hsp_state = HSP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN;
            break;
        default:
            return;
    }
    hsp_run();
}
Ejemplo n.º 7
0
void hsp_ag_disconnect(void){
    switch (hsp_state){
        case HSP_ACTIVE:
            hsp_state = HSP_W2_DISCONNECT_SCO;
            break;
        case HSP_W2_CONNECT_SCO:
            hsp_state = HSP_W2_DISCONNECT_RFCOMM;
            break;

        case HSP_W4_RFCOMM_CONNECTED:
        case HSP_W4_SCO_CONNECTED:
            hsp_state = HSP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN;
            break;
        default:
            return;
    }
    hsp_run();
}
Ejemplo n.º 8
0
void hsp_hs_disconnect(void){
    hsp_hs_release_audio_connection();

    if (hsp_state < HSP_W4_RFCOMM_CONNECTED){
        hsp_state = HSP_IDLE;
        return;
    }

    if (hsp_state == HSP_W4_RFCOMM_CONNECTED){
        hsp_state = HSP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN;
        return;
    }

    if (hsp_state < HSP_W4_SCO_CONNECTED){
        hsp_state = HSP_W2_DISCONNECT_RFCOMM;
        return;
    }

    hsp_disconnect_rfcomm = 1;
    hsp_run();
}
Ejemplo n.º 9
0
void hsp_hs_send_button_press(void){
    if (hsp_state < HSP_RFCOMM_CONNECTION_ESTABLISHED || hsp_state >= HSP_W4_RFCOMM_DISCONNECTED) return;
    hs_send_button_press = 1;
    hsp_run();
}
Ejemplo n.º 10
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();
}
Ejemplo n.º 11
0
void hsp_hs_release_audio_connection(void){
    if (hsp_state >= HSP_W2_DISCONNECT_SCO) return;
    if (hsp_state < HSP_AUDIO_CONNECTION_ESTABLISHED) return;
    hsp_release_audio_connection = 1;
    hsp_run();
}
Ejemplo n.º 12
0
void hsp_hs_connect(bd_addr_t bd_addr){
    if (hsp_state != HSP_IDLE) return;
    hsp_state = HSP_SDP_QUERY_RFCOMM_CHANNEL;
    memcpy(remote, bd_addr, 6);
    hsp_run();
}
Ejemplo n.º 13
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){
        while (size > 0 && (packet[0] == '\n' || packet[0] == '\r')){
            size--;
            packet++;
        }
        if (strncmp((char *)packet, HSP_AG_RING, strlen(HSP_AG_RING)) == 0){
            hs_ring_received = 1;  
        } if (strncmp((char *)packet, HSP_AG_OK, strlen(HSP_AG_OK)) == 0){
            hs_ok_received = 1;  
            switch (hsp_state){
                case HSP_W4_RFCOMM_CONNECTED:
                    hsp_state = HSP_W2_CONNECT_SCO;
                    break;
                case HSP_W4_USER_ACTION:
                    hsp_state = HSP_W2_DISCONNECT_SCO;
                    break;
                default:
                    break;
            }
        } 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;
            // re-use incoming buffer to avoid reserving large buffers - ugly but efficient
            uint8_t * event = packet - 3;
            event[0] = HCI_EVENT_HSP_META;
            event[1] = size + 1;
            event[2] = HSP_SUBEVENT_AG_INDICATION;
            (*hsp_hs_callback)(event, size+3);
        }
        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 BTSTACK_EVENT_STATE:
            // bt stack activated, get started 
            if (packet[2] == HCI_STATE_WORKING){
                printf("BTstack activated, get started .\n");
            }
            break;

        case HCI_EVENT_PIN_CODE_REQUEST:
            // inform about pin code request
            printf("Pin code request - using '0000'\n\r");
            bt_flip_addr(event_addr, &packet[2]);
            hci_send_cmd(&hci_pin_code_request_reply, &event_addr, 4, "0000");
            break;
        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 is not established, status %u", status);
                exit(0);
                break;
            }
            switch (link_type){
                case 0x00:
                    printf("SCO Connection established. \n");
                    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:
                    printf("eSCO Connection established. \n");
                    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(HSP_SUBEVENT_AUDIO_CONNECTION_COMPLETE, 0);
            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);
            printf("RFCOMM channel %u requested for %s\n", packet[8], bd_addr_to_str(event_addr));
            rfcomm_accept_connection_internal(rfcomm_cid);
            
            hsp_state = HSP_W4_RFCOMM_CONNECTED;
            hs_send_button_press = 1;
            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 (packet[2]) {
                printf("RFCOMM channel open failed, status %u\n", packet[2]);
                hsp_hs_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);
                printf("RFCOMM channel open succeeded. New RFCOMM Channel ID %u, max frame size %u\n", rfcomm_cid, mtu);

                switch (hsp_state){
                    case HSP_W4_RFCOMM_CONNECTED:
                        hsp_state = HSP_W2_CONNECT_SCO;
                        hs_send_button_press = 1;
                        break;
                    case HSP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN:
                        hsp_state = HSP_W2_DISCONNECT_RFCOMM;
                        break;
                    default:
                        break;
                }
            }
            break;
        case DAEMON_EVENT_HCI_PACKET_SENT:
        case RFCOMM_EVENT_CREDITS:
            break;
        
        case HCI_EVENT_DISCONNECTION_COMPLETE:
            printf("HCI_EVENT_DISCONNECTION_COMPLETE \n");
            if (hsp_state != HSP_W4_SCO_DISCONNECTED){
                printf("received gap disconnect in wrong hsp state");
            }
            handle = READ_BT_16(packet,3);
            if (handle == sco_handle){
                sco_handle = 0;
                hsp_state = HSP_W2_DISCONNECT_RFCOMM;
                printf(" HSP_W2_DISCONNECT_RFCOMM\n");
                break;
            }
            break;
        case RFCOMM_EVENT_CHANNEL_CLOSED:
            printf(" RFCOMM_EVENT_CHANNEL_CLOSED\n");
            if (hsp_state != HSP_W4_RFCOMM_DISCONNECTED){
                printf("received RFCOMM disconnect in wrong hsp state");
            }
            printf("RFCOMM channel closed\n");
            hsp_hs_reset_state();
            emit_event(HSP_SUBEVENT_AUDIO_DISCONNECTION_COMPLETE,0);
            break;
        default:
            break;
    }
    hsp_run();
}
Ejemplo n.º 14
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();
}