Exemplo n.º 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){
        hfp_service_level_connection_state++;
        if (rfcomm_can_send_packet_now(rfcomm_cid)) send_packet();
        return;
    }
    if (packet_type != HCI_EVENT_PACKET) return;
    uint8_t event = packet[0];
    bd_addr_t event_addr;

    switch (event) {
        case BTSTACK_EVENT_STATE:
            // bt stack activated, get started 
            if (packet[2] == HCI_STATE_WORKING){
                printf("Start SDP RFCOMM Query for UUID 0x%02x\n", SDP_Handsfree);
                // sdp_query_rfcomm_channel_and_name_for_uuid(remote, SDP_Handsfree);
            }
            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 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]);
            } else {
                // data: event(8), len(8), status (8), address (48), handle (16), server channel(8), rfcomm_cid(16), max frame size(16)
                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);
                break;
            }
            break;
        case DAEMON_EVENT_HCI_PACKET_SENT:
        case RFCOMM_EVENT_CREDITS:
            if (!rfcomm_cid) break;
            if (rfcomm_can_send_packet_now(rfcomm_cid)) send_packet();
            break;
        default:
            break;
    }
}
Exemplo n.º 2
0
static int hsp_hs_send_str_over_rfcomm(uint16_t cid, const char * command){
    if (!rfcomm_can_send_packet_now(rfcomm_cid)) return 1;
    int err = rfcomm_send(cid, (uint8_t*) command, strlen(command));
    if (err){
        log_info("rfcomm_send_internal -> error 0X%02x", err);
    }
    return err;
}
Exemplo n.º 3
0
int send_str_over_rfcomm(uint16_t cid, char * command){
    if (!rfcomm_can_send_packet_now(rfcomm_cid)) return 1;
    int err = rfcomm_send_internal(cid, (uint8_t*) command, strlen(command));
    if (err){
        printf("rfcomm_send_internal -> error 0X%02x", err);
    }
    return err;
}
Exemplo n.º 4
0
int send_str_over_rfcomm(uint16_t cid, char * command){
    if (!rfcomm_can_send_packet_now(cid)) return 1;
    int err = rfcomm_send_internal(cid, (uint8_t*) command, strlen(command));
    if (err){
        log_error("rfcomm_send_internal -> error 0x%02x \n", err);
    } 
    return 1;
}
Exemplo n.º 5
0
static int hsp_ag_send_str_over_rfcomm(uint16_t cid, char * command){
    if (!rfcomm_can_send_packet_now(cid)) return 1;
    int err = rfcomm_send_internal(cid, (uint8_t*) command, strlen(command));
    if (err){
        printf("rfcomm_send_internal -> error 0X%02x", err);
        return err;
    }
    printf("Send string: \"%s\"\n", command); 
    return err;
}
Exemplo n.º 6
0
static void hfp_run_for_context(hfp_connection_t *context){
    if (!context) return;
    if (!rfcomm_can_send_packet_now(context->rfcomm_cid)) return;
    
    if (context->command == HFP_CMD_UNKNOWN){
        context->ok_pending = 0;
        context->send_error = 0;
        context->command = HFP_CMD_NONE;
        hfp_ag_error(context->rfcomm_cid);
        return;
    }

    if (context->ok_pending){
        context->ok_pending = 0;
        context->command = HFP_CMD_NONE;
        hfp_ag_ok(context->rfcomm_cid);
        return;
    }

    if (context->send_error){
        context->send_error = 0;
        context->command = HFP_CMD_NONE;
        hfp_ag_error(context->rfcomm_cid); 
        return;
    }
    
    int done = hfp_ag_run_for_context_service_level_connection(context);
    if (!done){
        done = hfp_ag_run_for_context_service_level_connection_queries(context);
    } 

    if (!done){
        done = incoming_call_state_machine(context);
    }

    if (!done){  
        done = hfp_ag_run_for_audio_connection(context);
    }
    

    if (context->command == HFP_CMD_NONE && !done){
        log_info("context->command == HFP_CMD_NONE");
        switch(context->state){
            case HFP_W2_DISCONNECT_RFCOMM:
                context->state = HFP_W4_RFCOMM_DISCONNECTED;
                rfcomm_disconnect_internal(context->rfcomm_cid);
                break;
            default:
                break;
        }
    }
    if (done){
        context->command = HFP_CMD_NONE;
    }
}
Exemplo n.º 7
0
void hfp_run_for_context(hfp_connection_t *context){
    if (!context) return;

    if (!rfcomm_can_send_packet_now(context->rfcomm_cid)) return;

    // printf("AG hfp_run_for_context 1 state %d, command %d\n", context->state, context->command);
    if (context->send_ok){
        hfp_ag_ok(context->rfcomm_cid);
        context->send_ok = 0;
        return;
    }

    if (context->send_error){
        hfp_ag_error(context->rfcomm_cid); 
        context->send_error = 0;
        return;
    }
    int done;
    if (!rfcomm_can_send_packet_now(context->rfcomm_cid)) return;
    hfp_ag_run_for_context_service_level_connection(context);

    if (!rfcomm_can_send_packet_now(context->rfcomm_cid)) return;
    done = hfp_ag_run_for_context_service_level_connection_queries(context);
    if (!rfcomm_can_send_packet_now(context->rfcomm_cid) || done) return;
    done = hfp_ag_run_for_context_codecs_connection(context);

    if (context->command == HFP_CMD_NONE){
        switch(context->state){
            case HFP_W2_DISCONNECT_RFCOMM:
                // printf("rfcomm_disconnect_internal cid 0x%02x\n", context->rfcomm_cid);
                context->state = HFP_W4_RFCOMM_DISCONNECTED;
                rfcomm_disconnect_internal(context->rfcomm_cid);
                break;
            default:
                break;
        }
    }
    context->command = HFP_CMD_NONE;

}
Exemplo n.º 8
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 != HCI_EVENT_PACKET) return;
    uint8_t event = packet[0];

    switch (event) {
        case BTSTACK_EVENT_STATE:
            // bt stack activated, get started 
            if (packet[2] == HCI_STATE_WORKING){
                sdp_query_rfcomm_channel_and_name_for_uuid(remote, SDP_PublicBrowseGroup);
            }
            break;
        case RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE:
            // 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]);
            } else {
                // data: event(8), len(8), status (8), address (48), handle (16), server channel(8), rfcomm_cid(16), max frame size(16)
                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);
                if ((test_data_len > mtu)) {
                    test_data_len = mtu;
                }
                if (rfcomm_can_send_packet_now(rfcomm_cid)) send_packet();
                break;
            }
            break;
        case DAEMON_EVENT_HCI_PACKET_SENT:
        case RFCOMM_EVENT_CREDITS:
            if (rfcomm_can_send_packet_now(rfcomm_cid)) send_packet();
            break;
        default:
            break;
    }
}
Exemplo n.º 9
0
static void hfp_run_for_context(hfp_connection_t * connection){
    if (!connection) return;
    // printf("hfp send cmd: context %p, RFCOMM cid %u \n", connection, connection->rfcomm_cid );
    if (!rfcomm_can_send_packet_now(connection->rfcomm_cid)) return;
    
    switch (connection->state){
        case HFP_EXCHANGE_SUPPORTED_FEATURES:
            hfp_hs_exchange_supported_features_cmd(connection->rfcomm_cid);
            connection->state = HFP_W4_EXCHANGE_SUPPORTED_FEATURES;
            break;
        case HFP_NOTIFY_ON_CODECS:
            hfp_hs_retrieve_codec_cmd(connection->rfcomm_cid);
            connection->state = HFP_W4_NOTIFY_ON_CODECS;
            break;
        case HFP_RETRIEVE_INDICATORS:
            hfp_hs_retrieve_indicators_cmd(connection->rfcomm_cid);
            connection->state = HFP_W4_RETRIEVE_INDICATORS;
            break;
        case HFP_RETRIEVE_INDICATORS_STATUS:
            hfp_hs_retrieve_indicators_status_cmd(connection->rfcomm_cid);
            connection->state = HFP_W4_RETRIEVE_INDICATORS_STATUS;
            break;
        case HFP_ENABLE_INDICATORS_STATUS_UPDATE:
            hfp_hs_toggle_indicator_status_update_cmd(connection->rfcomm_cid, 1);
            connection->state = HFP_W4_ENABLE_INDICATORS_STATUS_UPDATE;
            break;
        case HFP_RETRIEVE_CAN_HOLD_CALL:
            hfp_hs_retrieve_can_hold_call_cmd(connection->rfcomm_cid);
            connection->state = HFP_W4_RETRIEVE_CAN_HOLD_CALL;
            break;
        case HFP_LIST_GENERIC_STATUS_INDICATORS:
            hfp_hs_list_supported_generic_status_indicators_cmd(connection->rfcomm_cid);
            connection->state = HFP_W4_LIST_GENERIC_STATUS_INDICATORS;
            break;
        case HFP_RETRIEVE_GENERIC_STATUS_INDICATORS:
            hfp_hs_retrieve_supported_generic_status_indicators_cmd(connection->rfcomm_cid);
            connection->state = HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS;
            break;
        case HFP_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS:
            hfp_hs_list_initital_supported_generic_status_indicators_cmd(connection->rfcomm_cid);
            connection->state = HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS;
            break;
        case HFP_ACTIVE:
            printf("HFP_ACTIVE\n");
            break;
        default:
            break;
    }
}
Exemplo n.º 10
0
void  heartbeat_handler(struct timer *ts){
    if (rfcomm_channel_id){
        static int counter = 0;
        char lineBuffer[30];
        sprintf(lineBuffer, "BTstack counter %04u\n\r", ++counter);
        puts(lineBuffer);
        if (rfcomm_can_send_packet_now(rfcomm_channel_id)) {
            int err = rfcomm_send_internal(rfcomm_channel_id, (uint8_t*) lineBuffer, strlen(lineBuffer));
            if (err) printf("rfcomm_send_internal -> error 0X%02x", err); 
        }   
    }
    
    run_loop_set_timer(ts, HEARTBEAT_PERIOD_MS);
    run_loop_add_timer(ts);
} 
Exemplo n.º 11
0
static void  heartbeat_handler(struct btstack_timer_source *ts){

    if (rfcomm_channel_id){
        static int counter = 0;
        char lineBuffer[30];
        sprintf(lineBuffer, "BTstack counter %04u\n\r", ++counter);
        printf(lineBuffer);
        if (rfcomm_can_send_packet_now(rfcomm_channel_id)){
            int err = rfcomm_send(rfcomm_channel_id, (uint8_t*) lineBuffer, strlen(lineBuffer));
            if (err) {
                printf("rfcomm_send -> error %d", err);
            }
        }   
    }
    
    btstack_run_loop_set_timer(ts, HEARTBEAT_PERIOD_MS);
    btstack_run_loop_add_timer(ts);
} 
Exemplo n.º 12
0
 /* LISTING_START(heartbeat): Combined Heartbeat handler */
static void  heartbeat_handler(struct timer *ts){

    counter++;
    counter_string_len = sprintf(counter_string, "BTstack counter %04u\n", counter);
    // printf("%s", counter_string);

    if (rfcomm_channel_id){
        if (rfcomm_can_send_packet_now(rfcomm_channel_id)){
            int err = rfcomm_send_internal(rfcomm_channel_id, (uint8_t*) counter_string, counter_string_len);
            if (err) {
                log_error("rfcomm_send_internal -> error 0X%02x", err);
            }
        }
    }

    if (le_notification_enabled) {
        att_server_notify(ATT_CHARACTERISTIC_0000FF11_0000_1000_8000_00805F9B34FB_01_VALUE_HANDLE, (uint8_t*) counter_string, counter_string_len);
    }
    run_loop_set_timer(ts, HEARTBEAT_PERIOD_MS);
    run_loop_add_timer(ts);
} 
Exemplo n.º 13
0
static void hsp_run(void){
    if (!rfcomm_can_send_packet_now(rfcomm_cid)) return;
    if (wait_ok) return;

    if (hsp_release_audio_connection){
        hsp_release_audio_connection = 0;
        wait_ok = 1;
        hsp_hs_send_str_over_rfcomm(rfcomm_cid, HSP_HS_AT_CKPD);
        return;
    }

    if (hsp_disconnect_rfcomm){
        hsp_disconnect_rfcomm = 0;
        hsp_establish_audio_connection = 0;
        rfcomm_disconnect_internal(rfcomm_cid);
        return;
    }

    if (hsp_establish_audio_connection){
        hsp_establish_audio_connection = 0;
        wait_ok = 1;
        hsp_hs_send_str_over_rfcomm(rfcomm_cid, HSP_HS_AT_CKPD);
        return;
    }
    
    if (hs_send_button_press){
        hs_send_button_press = 0;
        wait_ok = 1;
        hsp_hs_send_str_over_rfcomm(rfcomm_cid, HSP_HS_AT_CKPD);
        return;
    }

    switch (hsp_state){
        case HSP_SDP_QUERY_RFCOMM_CHANNEL:
            hsp_state = HSP_W4_SDP_QUERY_COMPLETE;
            sdp_query_rfcomm_channel_and_name_for_uuid(remote, SDP_Headset_AG);
            break;
        
        case HSP_AUDIO_CONNECTION_ESTABLISHED:
        case HSP_RFCOMM_CONNECTION_ESTABLISHED:

            if (hs_microphone_gain >= 0){
                char buffer[20];
                sprintf(buffer, "%s=%d\r\n", HSP_HS_MICROPHONE_GAIN, hs_microphone_gain);
                hsp_hs_send_str_over_rfcomm(rfcomm_cid, buffer);
                hs_microphone_gain = -1;
                break;
            }

            if (hs_speaker_gain >= 0){
                char buffer[20];
                sprintf(buffer, "%s=%d\r\n", HSP_HS_SPEAKER_GAIN, hs_speaker_gain);
                hsp_hs_send_str_over_rfcomm(rfcomm_cid, buffer);
                hs_speaker_gain = -1;
                break;
            }
            break;
        case HSP_W4_RFCOMM_DISCONNECTED:
            rfcomm_disconnect_internal(rfcomm_cid);
            break;
        default:
            break;
    }
}
Exemplo n.º 14
0
void hfp_run_for_context(hfp_connection_t *context) {
    // printf(" hfp_run_for_context \n");
    if (!context) return;
    if (!rfcomm_can_send_packet_now(context->rfcomm_cid)) return;
    //printf(" hfp_run_for_context 1 state %d, command %d\n", context->state, context->command);

    if (context->state == HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) {
        if (context->send_ok) {
            hfp_ag_ok(context->rfcomm_cid);
            context->send_ok = 0;
            return;
        }

        if (context->send_error) {
            hfp_ag_error(context->rfcomm_cid);
            context->send_error = 0;
            return;
        }

        if (context->enable_status_update_for_ag_indicators) {
            int i;
            for (i = 0; i < context->ag_indicators_nr; i++) {
                if (context->ag_indicators[i].enabled == 0) continue;
                if (context->ag_indicators[i].status_changed == 0) continue;
                hfp_ag_transfer_ag_indicators_status_cmd(context->rfcomm_cid, context->ag_indicators[i]);
                context->ag_indicators[i].status_changed = 0;
                return;
            }
        }

        if (context->enable_extended_audio_gateway_error_report) {
            if (context->extended_audio_gateway_error) {
                hfp_ag_report_extended_audio_gateway_error(context->rfcomm_cid, context->extended_audio_gateway_error);
                context->extended_audio_gateway_error = 0;
                return;
            }
        }
    }


    if (context->state == HFP_AUDIO_CONNECTION_ESTABLISHED) {
        // TODO
    }

    switch(context->command) {
    // START codec setup
    case HFP_CMD_TRIGGER_CODEC_CONNECTION_SETUP:
        if (!hfp_ag_choose_codec(context)) {
            hfp_ag_error(context->rfcomm_cid);
            break;
        }
        switch (context->state) {
        case HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED:
            // hfp_ag_ok(context->rfcomm_cid);
            context->negotiated_codec = hfp_ag_choose_codec(context);
            hfp_ag_cmd_confirm_codec(context->rfcomm_cid, context->negotiated_codec);
            context->state = HFP_SLE_W4_EXCHANGE_COMMON_CODEC;
            break;
        default:
            hfp_ag_error(context->rfcomm_cid);
            break;
        }
        break;

    case HFP_CMD_CONFIRM_COMMON_CODEC:
        hfp_ag_ok(context->rfcomm_cid);
        context->state = HFP_CODECS_CONNECTION_ESTABLISHED;
        break;
    // END codec setup

    case HFP_CMD_SUPPORTED_FEATURES:
        switch(context->state) {
        case HFP_W4_EXCHANGE_SUPPORTED_FEATURES:
            hfp_ag_exchange_supported_features_cmd(context->rfcomm_cid);
            if (has_codec_negotiation_feature(context)) {
                context->state = HFP_W4_NOTIFY_ON_CODECS;
                break;
            }
            context->state = HFP_W4_RETRIEVE_INDICATORS;
            break;
        default:
            break;
        }
        break;
    case HFP_CMD_AVAILABLE_CODECS:
        switch(context->state) {
        case HFP_W4_NOTIFY_ON_CODECS:
            hfp_ag_retrieve_codec_cmd(context->rfcomm_cid);
            context->state = HFP_W4_RETRIEVE_INDICATORS;
            break;
        default:
            break;
        }
        break;
    case HFP_CMD_INDICATOR:
        switch(context->state) {
        case HFP_W4_RETRIEVE_INDICATORS:
            if (context->retrieve_ag_indicators == 0) break;
            hfp_ag_retrieve_indicators_cmd(context->rfcomm_cid, context);
            context->state = HFP_W4_RETRIEVE_INDICATORS_STATUS;
            break;
        case HFP_W4_RETRIEVE_INDICATORS_STATUS:
            if (context->retrieve_ag_indicators_status == 0) break;
            hfp_ag_retrieve_indicators_status_cmd(context->rfcomm_cid);
            context->state = HFP_W4_ENABLE_INDICATORS_STATUS_UPDATE;
            break;
        default:
            break;
        }
        break;
    case HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE:
        switch(context->state) {
        case HFP_W4_ENABLE_INDICATORS_STATUS_UPDATE:
            hfp_ag_toggle_indicator_status_update_cmd(context->rfcomm_cid, 1);
            if (has_call_waiting_and_3way_calling_feature(context)) {
                context->state = HFP_W4_RETRIEVE_CAN_HOLD_CALL;
                break;
            }
            if (has_hf_indicators_feature(context)) {
                context->state = HFP_W4_LIST_GENERIC_STATUS_INDICATORS;
                break;
            }
            context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED;
            hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0);
            break;
        case HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED:
            // TODO
            break;
        default:
            break;
        }
        break;
    case HFP_CMD_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES:
        switch(context->state) {
        case HFP_W4_RETRIEVE_CAN_HOLD_CALL:
            hfp_ag_retrieve_can_hold_call_cmd(context->rfcomm_cid);
            if (has_hf_indicators_feature(context)) {
                context->state = HFP_W4_LIST_GENERIC_STATUS_INDICATORS;
                break;
            }
            context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED;
            hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0);
            break;
        default:
            break;
        }
        break;
    case HFP_CMD_GENERIC_STATUS_INDICATOR:
        switch(context->state) {
        case HFP_W4_LIST_GENERIC_STATUS_INDICATORS:
            if (context->list_generic_status_indicators == 0) break;
            hfp_ag_list_supported_generic_status_indicators_cmd(context->rfcomm_cid);
            context->state = HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS;
            context->list_generic_status_indicators = 0;
            break;
        case HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS:
            if (context->retrieve_generic_status_indicators == 0) break;
            hfp_ag_retrieve_supported_generic_status_indicators_cmd(context->rfcomm_cid);
            context->state = HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS;
            context->retrieve_generic_status_indicators = 0;
            break;
        case HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS:
            if (context->retrieve_generic_status_indicators_state == 0) break;
            hfp_ag_retrieve_initital_supported_generic_status_indicators_cmd(context->rfcomm_cid);
            context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED;
            context->retrieve_generic_status_indicators_state = 0;
            hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0);
            break;
        default:
            break;
        }
        break;
    case HFP_CMD_QUERY_OPERATOR_SELECTION:
        if (context->state != HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) break;
        if (context->operator_name_format == 1) {
            if (context->network_operator.format != 0) {
                hfp_ag_error(context->rfcomm_cid);
                break;
            }
            hfp_ag_ok(context->rfcomm_cid);
            context->operator_name_format = 0;
            break;
        }
        if (context->operator_name == 1) {
            hfp_ag_report_network_operator_name_cmd(context->rfcomm_cid, context->network_operator);
            context->operator_name = 0;
            break;
        }
        break;
    case HFP_CMD_NONE:
        switch(context->state) {
        case HFP_W2_DISCONNECT_RFCOMM:
            // printf("rfcomm_disconnect_internal cid 0x%02x\n", context->rfcomm_cid);
            context->state = HFP_W4_RFCOMM_DISCONNECTED;
            rfcomm_disconnect_internal(context->rfcomm_cid);
            break;
        default:
            break;
        }
        break;
    default:
        break;
    }
    // done
    context->command = HFP_CMD_NONE;
}
Exemplo n.º 15
0
static void hsp_run(void){

    if (wait_ok) return;

    if (hs_accept_sco_connection && hci_can_send_command_packet_now()){
        hs_accept_sco_connection = 0;
        
        log_info("HSP: sending hci_accept_connection_request.");
        // remote supported feature eSCO is set if link type is eSCO
        // eSCO: S4 - max latency == transmission interval = 0x000c == 12 ms, 
        uint16_t max_latency;
        uint8_t  retransmission_effort;
        uint16_t packet_types;
        
        if (hci_remote_esco_supported(rfcomm_handle)){
            max_latency = 0x000c;
            retransmission_effort = 0x02;
            packet_types = 0x388;
        } else {
            max_latency = 0xffff;
            retransmission_effort = 0xff;
            packet_types = 0x003f;
        }
        
        uint16_t sco_voice_setting = hci_get_sco_voice_setting();
        
        log_info("HFP: sending hci_accept_connection_request, sco_voice_setting %02x", sco_voice_setting);
        hci_send_cmd(&hci_accept_synchronous_connection, remote, 8000, 8000, max_latency, 
                        sco_voice_setting, retransmission_effort, packet_types);
        return;
    }

    if (hsp_release_audio_connection){
        if (!rfcomm_can_send_packet_now(rfcomm_cid)) {
            rfcomm_request_can_send_now_event(rfcomm_cid);
            return;
        }
        hsp_release_audio_connection = 0;
        wait_ok = 1;
        hsp_hs_send_str_over_rfcomm(rfcomm_cid, HSP_HS_AT_CKPD);
        return;
    }

    if (hsp_disconnect_rfcomm){
        hsp_disconnect_rfcomm = 0;
        hsp_establish_audio_connection = 0;
        rfcomm_disconnect(rfcomm_cid);
        return;
    }

    if (hsp_establish_audio_connection){
        if (!rfcomm_can_send_packet_now(rfcomm_cid)) {
            rfcomm_request_can_send_now_event(rfcomm_cid);
            return;
        }
        hsp_establish_audio_connection = 0;
        wait_ok = 1;
        hsp_hs_send_str_over_rfcomm(rfcomm_cid, HSP_HS_AT_CKPD);
        return;
    }
    
    if (hs_send_button_press){
        if (!rfcomm_can_send_packet_now(rfcomm_cid)) {
            rfcomm_request_can_send_now_event(rfcomm_cid);
            return;
        }
        hs_send_button_press = 0;
        wait_ok = 1;
        hsp_hs_send_str_over_rfcomm(rfcomm_cid, HSP_HS_AT_CKPD);
        return;
    }

    switch (hsp_state){
        case HSP_SDP_QUERY_RFCOMM_CHANNEL:
            hsp_state = HSP_W4_SDP_QUERY_COMPLETE;
            sdp_client_query_rfcomm_channel_and_name_for_uuid(&handle_query_rfcomm_event, remote, BLUETOOTH_SERVICE_CLASS_HEADSET_AUDIO_GATEWAY_AG);
            break;
        
        case HSP_AUDIO_CONNECTION_ESTABLISHED:
        case HSP_RFCOMM_CONNECTION_ESTABLISHED:

            if (hs_microphone_gain >= 0){
                if (!rfcomm_can_send_packet_now(rfcomm_cid)) {
                    rfcomm_request_can_send_now_event(rfcomm_cid);
                    return;
                }
                char buffer[20];
                sprintf(buffer, "%s=%d\r\n", HSP_HS_MICROPHONE_GAIN, hs_microphone_gain);
                hsp_hs_send_str_over_rfcomm(rfcomm_cid, buffer);
                hs_microphone_gain = -1;
                break;
            }

            if (hs_speaker_gain >= 0){
                if (!rfcomm_can_send_packet_now(rfcomm_cid)) {
                    rfcomm_request_can_send_now_event(rfcomm_cid);
                    return;
                }
                char buffer[20];
                sprintf(buffer, "%s=%d\r\n", HSP_HS_SPEAKER_GAIN, hs_speaker_gain);
                hsp_hs_send_str_over_rfcomm(rfcomm_cid, buffer);
                hs_speaker_gain = -1;
                break;
            }
            break;
        case HSP_W4_RFCOMM_DISCONNECTED:
            rfcomm_disconnect(rfcomm_cid);
            break;
        default:
            break;
    }
}