Example #1
0
static void hfp_ag_run_for_context_service_level_connection(hfp_connection_t * context){
    if (context->state >= HFP_CODECS_CONNECTION_ESTABLISHED) return;
    printf(" AG run for context_service_level_connection \n");

    switch(context->command){
        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;
                case HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED:
                    context->suggested_codec = hfp_ag_suggest_codec(context);
                    printf("received BAC == new HF codecs, suggested codec %d\n", context->suggested_codec);
                    hfp_ag_ok(context->rfcomm_cid);
                    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;
                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;

        default:
            break;
    }
}
Example #2
0
static int hfp_ag_run_for_context_codecs_connection(hfp_connection_t * context){
    if (context->state <= HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED ||
        context->state > HFP_CODECS_CONNECTION_ESTABLISHED) return 0;

    int done = 0;
    printf(" AG run for context_codecs_connection: ");
    switch (context->state){
        case HFP_SLE_W2_EXCHANGE_COMMON_CODEC:
            if (context->ag_trigger_codec_connection_setup){ // received BCS
                printf(" send BCS \n");
                context->ag_trigger_codec_connection_setup = 0;
                context->state = HFP_SLE_W4_EXCHANGE_COMMON_CODEC;
                context->suggested_codec = hfp_ag_suggest_codec(context);
                hfp_ag_cmd_suggest_codec(context->rfcomm_cid, context->suggested_codec);
                done = 1;
                break;
            }
            break;
        case HFP_SLE_W4_EXCHANGE_COMMON_CODEC:
            switch(context->command){
                case HFP_CMD_AVAILABLE_CODECS:
                    if (context->notify_ag_on_new_codecs){ // received BAC
                        printf(" received BAC\n");
                        context->notify_ag_on_new_codecs = 0;
                        if (context->suggested_codec != hfp_ag_suggest_codec(context)){
                            context->suggested_codec = hfp_ag_suggest_codec(context);
                            context->state = HFP_SLE_W4_EXCHANGE_COMMON_CODEC;
                        }
                        hfp_ag_ok(context->rfcomm_cid);
                        done = 1;
                        break;
                    }
                    break;
                case HFP_CMD_HF_CONFIRMED_CODEC:
                    printf(" received AT+BCS\n");
                    if (context->codec_confirmed != context->suggested_codec){
                        context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED;
                        hfp_ag_error(context->rfcomm_cid);
                        done = 1;
                        break;
                    } 
                    context->negotiated_codec = context->codec_confirmed;
                    context->state = HFP_CODECS_CONNECTION_ESTABLISHED;
                    hfp_emit_event(hfp_callback, HFP_SUBEVENT_CODECS_CONNECTION_COMPLETE, 0);
                    hfp_ag_ok(context->rfcomm_cid);
                    done = 1;
                    break; 
                default:
                    break;
            }
            break;
            
        case HFP_CODECS_CONNECTION_ESTABLISHED:
            switch(context->command){
                case HFP_CMD_AVAILABLE_CODECS:

                    if (context->notify_ag_on_new_codecs){ // received BAC
                        context->notify_ag_on_new_codecs = 0;
                        if (context->suggested_codec != hfp_ag_suggest_codec(context)){
                            context->suggested_codec = hfp_ag_suggest_codec(context);
                            context->state = HFP_SLE_W4_EXCHANGE_COMMON_CODEC;
                        }
                        hfp_ag_ok(context->rfcomm_cid);
                        done = 1;
                        break;
                    }
                    break;
                case HFP_CMD_AG_SUGGESTED_CODEC:
                    if (context->ag_trigger_codec_connection_setup){ 
                        context->ag_trigger_codec_connection_setup = 0;
                        if (context->negotiated_codec != hfp_ag_suggest_codec(context)){
                            context->state = HFP_SLE_W4_EXCHANGE_COMMON_CODEC;
                            context->suggested_codec = hfp_ag_suggest_codec(context);
                            hfp_ag_cmd_suggest_codec(context->rfcomm_cid, context->suggested_codec);
                            done = 1;
                            break;
                        }
                    }
                    break;
                default:
                    break;
            }

        default:
            break;
    }
    return done;
}
Example #3
0
void hfp_handle_hci_event(hfp_callback_t callback, uint8_t packet_type, uint8_t *packet, uint16_t size){
    bd_addr_t event_addr;
    uint16_t rfcomm_cid, handle;
    hfp_connection_t * context = NULL;

    switch (packet[0]) {
        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 RFCOMM_EVENT_INCOMING_CONNECTION:
            // data: event (8), len(8), address(48), channel (8), rfcomm_cid (16)
            bt_flip_addr(event_addr, &packet[2]); 
            context = get_hfp_connection_context_for_bd_addr(event_addr);
            
            if (!context || context->state != HFP_IDLE) return;

            context->rfcomm_cid = READ_BT_16(packet, 9);
            context->state = HFP_W4_RFCOMM_CONNECTED;
            printf("RFCOMM channel %u requested for %s\n", context->rfcomm_cid, bd_addr_to_str(context->remote_addr));
            rfcomm_accept_connection_internal(context->rfcomm_cid);
            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)
            printf("RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE packet_handler type %u, packet[0] %x\n", packet_type, packet[0]);
            bt_flip_addr(event_addr, &packet[3]); 
            context = get_hfp_connection_context_for_bd_addr(event_addr);
            if (!context || context->state != HFP_W4_RFCOMM_CONNECTED) return;
            
            if (packet[2]) {
                hfp_emit_event(callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, packet[2]);
                remove_hfp_connection_context(context);
            } else {
                context->con_handle = READ_BT_16(packet, 9);
                context->rfcomm_cid = READ_BT_16(packet, 12);
                uint16_t mtu = READ_BT_16(packet, 14);
                printf("RFCOMM channel open succeeded. Context %p, RFCOMM Channel ID 0x%02x, max frame size %u\n", context, context->rfcomm_cid, mtu);
                        
                switch (context->state){
                    case HFP_W4_RFCOMM_CONNECTED:
                        context->state = HFP_EXCHANGE_SUPPORTED_FEATURES;
                        break;
                    case HFP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN:
                        context->state = HFP_W2_DISCONNECT_RFCOMM;
                        printf("Shutting down RFCOMM.\n");
                        break;
                    default:
                        break;
                }
            }
            break;
        
        case HCI_EVENT_SYNCHRONOUS_CONNECTION_COMPLETE:{
            int index = 2;
            uint8_t status = packet[index++];
            uint16_t 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);
                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);

            context = get_hfp_connection_context_for_bd_addr(address);

            if (context->state == HFP_W4_CONNECTION_ESTABLISHED_TO_SHUTDOWN){
                context->state = HFP_W2_DISCONNECT_SCO;
                break;
            }
            
            context->sco_handle = sco_handle;
            context->state = HFP_AUDIO_CONNECTION_ESTABLISHED;
            hfp_emit_event(callback, HFP_SUBEVENT_AUDIO_CONNECTION_COMPLETE, packet[2]);
            break;                
        }

        case RFCOMM_EVENT_CHANNEL_CLOSED:
            rfcomm_cid = READ_BT_16(packet,2);
            context = get_hfp_connection_context_for_rfcomm_cid(rfcomm_cid);
            if (!context) break;
            if (context->state == HFP_W4_RFCOMM_DISCONNECTED_AND_RESTART){
                context->state = HFP_IDLE;
                hfp_establish_service_level_connection(context->remote_addr, context->service_uuid);
                break;
            }
            
            remove_hfp_connection_context(context);
            hfp_emit_event(callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED, 0);
            break;

        case HCI_EVENT_DISCONNECTION_COMPLETE:
            handle = READ_BT_16(packet,3);
            context = get_hfp_connection_context_for_handle(handle);
            if (!context) break;
            if (context->state == HFP_W4_RFCOMM_DISCONNECTED_AND_RESTART){
                context->state = HFP_IDLE;
                hfp_establish_service_level_connection(context->remote_addr, context->service_uuid);
                break;
            }
            hfp_emit_event(callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED, packet[2]);
            remove_hfp_connection_context(context);
            break;

        default:
            break;
    }
}
Example #4
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;
}
Example #5
0
static int incoming_call_state_machine(hfp_connection_t * context){
    if (!context->run_call_state_machine) return 0;
    if (context->state < HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) return 0;

    // printf(" -> State machine: Incoming Call\n");
    hfp_ag_indicator_t * indicator;
    if (context->command == HFP_CMD_HANG_UP_CALL){
        context->terminate_call = 1;
        hfp_ag_ok(context->rfcomm_cid);
        return 1;
    }

    if (context->terminate_call){
        printf(" -> State machine: Terminate Incoming Call\n");
        indicator = get_ag_indicator_for_name("call");
        if (!indicator) return 0;

        indicator->status = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS;
        context->terminate_call = 0;
        context->run_call_state_machine = 0;
        hfp_emit_event(hfp_callback, HFP_SUBEVENT_CALL_TERMINATED, 0);
        hfp_ag_transfer_ag_indicators_status_cmd(context->rfcomm_cid, indicator);
        return 1;
    }

    int done = 0;
    switch (context->call_state){
        case HFP_CALL_IDLE:
            //printf(" HFP_CALL_TRIGGER_AUDIO_CONNECTION \n");
            indicator = get_ag_indicator_for_name("callsetup");
            if (!indicator) return 0;

            indicator->status = HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS;
            hfp_ag_transfer_ag_indicators_status_cmd(context->rfcomm_cid, indicator);
            
            if (use_in_band_tone(context)){
                context->call_state = HFP_CALL_TRIGGER_AUDIO_CONNECTION;
            } else {
                context->call_state = HFP_CALL_RING;;
                hfp_emit_event(hfp_callback, HFP_SUBEVENT_START_RINGINIG, 0);
            }
            return 1;

        case HFP_CALL_RING:
            //printf(" HFP_CALL_RING \n");
            context->call_state = HFP_CALL_W4_ANSWER;
            hfp_ag_ring(context->rfcomm_cid);
            return 1;

        case HFP_CALL_W4_ANSWER:
            //printf(" HFP_CALL_W4_ANSWER, cmd %d \n", context->command);
            if (context->command != HFP_CMD_CALL_ANSWERED) return 0;
            context->call_state = HFP_CALL_TRANSFER_CALL_STATUS;
            hfp_emit_event(hfp_callback, HFP_SUBEVENT_STOP_RINGINIG, 0);
            hfp_ag_ok(context->rfcomm_cid);
            return 1;

        case HFP_CALL_TRANSFER_CALL_STATUS:
            //printf(" HFP_CALL_TRANSFER_CALL_STATUS \n");
            context->call_state = HFP_CALL_TRANSFER_CALLSETUP_STATUS;
            indicator = get_ag_indicator_for_name("call");
            indicator->status = HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT;
            hfp_ag_transfer_ag_indicators_status_cmd(context->rfcomm_cid, indicator);
            return 1;

        case HFP_CALL_TRANSFER_CALLSETUP_STATUS:
            //printf(" HFP_CALL_TRANSFER_CALLSETUP_STATUS \n");
            if (use_in_band_tone(context)){
                context->call_state = HFP_CALL_ACTIVE;
            } else {
                context->call_state = HFP_CALL_TRIGGER_AUDIO_CONNECTION;
            }
            
            indicator = get_ag_indicator_for_name("callsetup");
            indicator->status = HFP_HELDCALL_STATUS_NO_CALLS_HELD;
            hfp_ag_transfer_ag_indicators_status_cmd(context->rfcomm_cid, indicator);
            return 1;
        case HFP_CALL_TRIGGER_AUDIO_CONNECTION:
            //printf(" HFP_CALL_TRIGGER_AUDIO_CONNECTION \n");
            context->call_state = HFP_CALL_W4_AUDIO_CONNECTION;
            hfp_ag_establish_audio_connection(context->remote_addr);
            break;

        case HFP_CALL_W4_AUDIO_CONNECTION:
            //printf(" HFP_CALL_W4_AUDIO_CONNECTION \n");
            if (context->state < HFP_AUDIO_CONNECTION_ESTABLISHED) return 0;
            
            if (use_in_band_tone(context)){
                context->call_state = HFP_CALL_W4_ANSWER;
                hfp_emit_event(hfp_callback, HFP_SUBEVENT_START_RINGINIG, 0);
            } else {
                context->call_state = HFP_CALL_ACTIVE;
            }
            return 0;
        case HFP_CALL_ACTIVE:
            printf(" HFP_CALL_ACTIVE \n");
            break;
        default:
            break;
    }
    return done;
}
Example #6
0
static int hfp_ag_run_for_context_service_level_connection(hfp_connection_t * context){
    if (context->state >= HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) return 0;
    int done = 0;
    // printf(" -> State machine: SLC\n");
    
    switch(context->command){
        case HFP_CMD_SUPPORTED_FEATURES:
            switch(context->state){
                case HFP_W4_EXCHANGE_SUPPORTED_FEATURES:
                case HFP_EXCHANGE_SUPPORTED_FEATURES:
                    if (has_codec_negotiation_feature(context)){
                        context->state = HFP_W4_NOTIFY_ON_CODECS;
                    } else {
                        context->state = HFP_W4_RETRIEVE_INDICATORS;
                    }
                    hfp_ag_exchange_supported_features_cmd(context->rfcomm_cid);
                    return 1;
                default:
                    break;
            }
            break;
        case HFP_CMD_AVAILABLE_CODECS:
            done = codecs_exchange_state_machine(context);

            if (context->codecs_state == HFP_CODECS_RECEIVED_LIST){
                context->state = HFP_W4_RETRIEVE_INDICATORS;
            }
            return done;

        case HFP_CMD_RETRIEVE_AG_INDICATORS:
            if (context->state != HFP_W4_RETRIEVE_INDICATORS) break;
            context->state = HFP_W4_RETRIEVE_INDICATORS_STATUS;
            hfp_ag_retrieve_indicators_cmd(context->rfcomm_cid, context);
            return 1;
        
        case HFP_CMD_RETRIEVE_AG_INDICATORS_STATUS:
            if (context->state != HFP_W4_RETRIEVE_INDICATORS_STATUS) break;
            context->state = HFP_W4_ENABLE_INDICATORS_STATUS_UPDATE;
            hfp_ag_retrieve_indicators_status_cmd(context->rfcomm_cid);
            return 1;

        case HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE:
            if (context->state != HFP_W4_ENABLE_INDICATORS_STATUS_UPDATE) break;
            if (has_call_waiting_and_3way_calling_feature(context)){
                context->state = HFP_W4_RETRIEVE_CAN_HOLD_CALL;
            } else if (has_hf_indicators_feature(context)){
                context->state = HFP_W4_LIST_GENERIC_STATUS_INDICATORS;
            } else {
                context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED;
                hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0);
            }
            hfp_ag_set_indicator_status_update_cmd(context->rfcomm_cid, 1);
            return 1;
                
        case HFP_CMD_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES:
            if (context->state != HFP_W4_RETRIEVE_CAN_HOLD_CALL) break;
            if (has_hf_indicators_feature(context)){
                context->state = HFP_W4_LIST_GENERIC_STATUS_INDICATORS;
            } else {
                context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED;
                hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0);
            }
            hfp_ag_retrieve_can_hold_call_cmd(context->rfcomm_cid);
            return 1;
        
        case HFP_CMD_LIST_GENERIC_STATUS_INDICATORS:
            if (context->state != HFP_W4_LIST_GENERIC_STATUS_INDICATORS) break;
            context->state = HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS;
            hfp_ag_list_supported_generic_status_indicators_cmd(context->rfcomm_cid);
            return 1;

        case HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS:
            if (context->state != HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS) break;
            context->state = HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS; 
            hfp_ag_retrieve_supported_generic_status_indicators_cmd(context->rfcomm_cid);
            return 1;

        case HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS_STATE:
            if (context->state != HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS) break;
            context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED;
            hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0);
            hfp_ag_retrieve_initital_supported_generic_status_indicators_cmd(context->rfcomm_cid);
            return 1;
        default:
            break;
    }
    return done;
}
Example #7
0
static int codecs_exchange_state_machine(hfp_connection_t * context){
    /* events ( == commands):
        HFP_CMD_AVAILABLE_CODECS == received AT+BAC with list of codecs
        HFP_CMD_TRIGGER_CODEC_CONNECTION_SETUP:
            hf_trigger_codec_connection_setup == received BCC
            ag_trigger_codec_connection_setup == received from AG to send BCS
        HFP_CMD_HF_CONFIRMED_CODEC == received AT+BCS
    */
            
     switch (context->codecs_state){
        case HFP_CODECS_RECEIVED_TRIGGER_CODEC_EXCHANGE:
            context->command = HFP_CMD_AG_SEND_COMMON_CODEC;
            break;
        case HFP_CODECS_AG_RESEND_COMMON_CODEC:
            context->command = HFP_CMD_AG_SEND_COMMON_CODEC;
            break;
        default:
            break;
    }

    // printf(" -> State machine: CC\n");
    
    switch (context->command){
        case HFP_CMD_AVAILABLE_CODECS:
            //printf("HFP_CODECS_RECEIVED_LIST \n");
            if (context->state < HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED){
                context->codecs_state = HFP_CODECS_RECEIVED_LIST;
                hfp_ag_ok(context->rfcomm_cid);
                return 1;    
            }

            switch (context->codecs_state){
                case HFP_CODECS_AG_SENT_COMMON_CODEC:
                case HFP_CODECS_EXCHANGED:
                    context->codecs_state = HFP_CODECS_AG_RESEND_COMMON_CODEC;
                    break;
                default:
                    break;
            }
            hfp_ag_ok(context->rfcomm_cid);
            return 1;
        
        case HFP_CMD_TRIGGER_CODEC_CONNECTION_SETUP:
            //printf(" HFP_CMD_TRIGGER_CODEC_CONNECTION_SETUP \n");
            context->codecs_state = HFP_CODECS_RECEIVED_TRIGGER_CODEC_EXCHANGE;
            hfp_ag_ok(context->rfcomm_cid);
            return 1;
        
        case HFP_CMD_AG_SEND_COMMON_CODEC:
            //printf(" HFP_CMD_AG_SEND_COMMON_CODEC \n");
            context->codecs_state = HFP_CODECS_AG_SENT_COMMON_CODEC;
            context->suggested_codec = hfp_ag_suggest_codec(context);
            hfp_ag_cmd_suggest_codec(context->rfcomm_cid, context->suggested_codec);
            return 1;

        case HFP_CMD_HF_CONFIRMED_CODEC:
            //printf("HFP_CMD_HF_CONFIRMED_CODEC \n");
            if (context->codec_confirmed != context->suggested_codec){
                context->codecs_state = HFP_CODECS_ERROR;
                hfp_ag_error(context->rfcomm_cid);
                return 1;
            } 
            context->negotiated_codec = context->codec_confirmed;
            context->codecs_state = HFP_CODECS_EXCHANGED;
            hfp_emit_event(hfp_callback, HFP_SUBEVENT_CODECS_CONNECTION_COMPLETE, 0);
            hfp_ag_ok(context->rfcomm_cid);           
            return 1; 
        default:
            break;
    }
    return 0;
}