高通9X07模块QMI架构使用入门

QMI(Qualcomm Message Interface) 高通用来替代OneRPC/DM的协议,用来与modem通信。
本文是摸索高通QMI机制一点经验,重点解读了如果建立拨号连接,仅供参考。qmi详细使用参考:高通QMI协议

1 QMI协议常用组件

  • DMS(设备管理Device Management)
    提供查询设备信息功能
    参考: qmi/device_management_service_v01.h
  • NAS(网络访问Network Access)
    提供网络管理功能
    参考:qmi/network_access_service_v01.h
  • WDS(数据连接)
    参考:qmi/wireless_data_service_v01.h
  • UIM(管理User Identity Module)
    提供查询UIM卡信息
    参考:qmi/user_identity_module_v01.h
  • CTL(控制服务)
    用户发起其他服务请求前,必须先申请 ClientID, 这个ID就是由控制服务分配的, 这个服务永远在线
    参考:qmi/control_service_v01.h
  • 数据(拨号服务)
    建立数据连接
    参考:data/qualcomm_mobile_access_point_msgr_v01.h

每个服务模块都定义了 请求响应通知Indication, 请求分为同步和异步,其中异步请求的结果通过indication通知。

2 QMI举例

越来越多9X07模块被用于物联网,那么首要解决的问题即建立数据连接,所以本文使用QMI建立数据网络连接示意。

2.1 QMI初始化及释放

9X07模块提供了qcmap_msgr服务来进行拨号,通过与dsi_netctrl对比,qcmap_msgr接口更清晰,而且操作也简单。
AP侧使用QMI架构和modem通信初始化流程是固定的:

qcmap_msgr_get_service_object_v01查询服务对象 =>
qmi_client_notifier_init初始化client通知信息 =>
qmi_client_get_service_list查询支持的服务列表个数 =>
qmi_client_get_service_list查询支持的服务列表信息 =>
qmi_client_init使用其中一个服务信息初始化client
参考代码:

void qcmap_ppp_init(qcmap_ppp_t *self,client_status_ind_t client_cb_ind) {
    qmi_idl_service_object_type qcmap_msgr_qmi_idl_service_object;
    uint32_t num_services = 0, num_entries = 0;
    qmi_service_info info[10];
    qmi_client_error_type qmi_error, qmi_err_code = QMI_NO_ERR;

    assert(self);
    
    self->qcmap_msgr_enable = FALSE;
    self->qmi_qcmap_msgr_handle = 0;
    self->mobile_ap_handle = 0;

    qcmap_msgr_qmi_idl_service_object = qcmap_msgr_get_service_object_v01;//when faild, add your trick for this~

    if (qcmap_msgr_qmi_idl_service_object == NULL)
    {
        LOG("qcmap_msgr service object not available");
        return;
    }

    qmi_error = qmi_client_notifier_init(qcmap_msgr_qmi_idl_service_object,
                                        &self->qmi_qcmap_msgr_os_params,
                                        &self->qmi_qcmap_msgr_notifier);
    if (qmi_error < 0)
    {
        LOG("qmi_client_notifier_init(qcmap_msgr) returned %d", qmi_error);
        return;
    }

    /* Check if the service is up, if not wait on a signal */
    while(1)
    {
        qmi_error = qmi_client_get_service_list(qcmap_msgr_qmi_idl_service_object,
                                                NULL,
                                                NULL,
                                                &num_services);
        LOG("qmi_client_get_service_list: %d",qmi_error);

        if(qmi_error == QMI_NO_ERR)
            break;
        /* wait for server to come up */
        QMI_CCI_OS_SIGNAL_WAIT(&self->qmi_qcmap_msgr_os_params, 0);
    }

    num_entries = num_services;

    LOG("qmi_client_get_service_list: num_e %d num_s %d", num_entries, num_services);
    /* The server has come up, store the information in info variable */
    qmi_error = qmi_client_get_service_list(qcmap_msgr_qmi_idl_service_object,
                                            info,
                                            &num_entries,
                                            &num_services);

    LOG("qmi_client_get_service_list: num_e %d num_s %d error %d", num_entries, num_services, qmi_error);

    if (qmi_error != QMI_NO_ERR)
    {
        qmi_client_release(self->qmi_qcmap_msgr_notifier);
        self->qmi_qcmap_msgr_notifier = NULL;
        LOG("Can not get qcmap_msgr service list %d",
            qmi_error);
        return;
    }

    qmi_error = qmi_client_init(&info[0],
                                qcmap_msgr_qmi_idl_service_object,
                                client_cb_ind,
                                NULL,
                                NULL,
                                &self->qmi_qcmap_msgr_handle);

    LOG("qmi_client_init: %d", qmi_error);

    if (qmi_error != QMI_NO_ERR)
    {
        qmi_client_release(self->qmi_qcmap_msgr_notifier);
        self->qmi_qcmap_msgr_notifier = NULL;
        LOG("Can not init qcmap_msgr client %d", qmi_error);
        return;
    }
}

对应释放过程比较简单,主要是释放client初始化信息:

static void qcmap_ppp_uninit(qcmap_ppp_t *self) {
    qmi_client_error_type qmi_error;
    assert(self);

    qmi_error = qmi_client_release(self->qmi_qcmap_msgr_notifier);
    self->qmi_qcmap_msgr_notifier = NULL;

    if (qmi_error != QMI_NO_ERR)
    {
        LOG("Can not release client qcmap notifier %d",qmi_error);
    }

    qmi_error = qmi_client_release(self->qmi_qcmap_msgr_handle);
    self->qmi_qcmap_msgr_handle = NULL;

    if (qmi_error != QMI_NO_ERR)
    {
        LOG("Can not release client qcmap handle %d",qmi_error);
    }
}
2.2 建立/关闭拨号连接

建立拨号步骤:使能AP,连接服务

  • 使能ap
/* Enable MobileAP */
static boolean qcmap_ppp_enable(qcmap_ppp_t *self) {
    qmi_client_error_type qmi_error, qmi_err_code = QMI_NO_ERR;
    qcmap_msgr_mobile_ap_enable_resp_msg_v01 qcmap_enable_resp_msg_v01;
    qcmap_msgr_mobile_ap_status_ind_register_req_msg_v01 qcmap_mobile_ap_status_ind_reg;
    qcmap_msgr_wwan_status_ind_register_req_msg_v01 wwan_status_ind_reg;
    qcmap_msgr_station_mode_status_ind_register_req_msg_v01 qcmap_station_mode_status_ind_reg;
    qcmap_msgr_mobile_ap_status_ind_register_resp_msg_v01 qcmap_mobile_ap_status_ind_rsp;
    qcmap_msgr_wwan_status_ind_register_resp_msg_v01 wwan_status_ind_rsp;
    qcmap_msgr_station_mode_status_ind_register_resp_msg_v01 qcmap_station_mode_status_ind_rsp;

    memset(&qcmap_enable_resp_msg_v01, 0, sizeof(qcmap_msgr_mobile_ap_enable_resp_msg_v01));
    memset(&wwan_status_ind_reg, 0, sizeof(qcmap_msgr_wwan_status_ind_register_req_msg_v01));
    memset(&wwan_status_ind_rsp, 0, sizeof(qcmap_msgr_wwan_status_ind_register_resp_msg_v01));
    wwan_status_ind_reg.register_indication = 1;

    qmi_error = qmi_client_send_msg_sync(self->qmi_qcmap_msgr_handle,
                                            QMI_QCMAP_MSGR_WWAN_STATUS_IND_REG_REQ_V01,
                                            (void*)&wwan_status_ind_reg,
                                            sizeof(qcmap_msgr_wwan_status_ind_register_req_msg_v01),
                                            (void*)&wwan_status_ind_rsp,
                                            sizeof(qcmap_msgr_wwan_status_ind_register_resp_msg_v01),
                                            QCMAP_MSGR_QMI_TIMEOUT_VALUE);

    LOG("qmi_client_send_msg_sync: error %d result %d",
                    qmi_error, wwan_status_ind_rsp.resp.result);

    if (( qmi_error == QMI_TIMEOUT_ERR ) ||
        ( qmi_error != QMI_NO_ERR ) ||
        ( wwan_status_ind_rsp.resp.result != QMI_NO_ERR ))
    {
        LOG("Can not register for wwan status %d : %d",
                    qmi_error, wwan_status_ind_rsp.resp.error);
        return FALSE;
    }
    LOG("Registered for wwan status");

    memset(&qcmap_mobile_ap_status_ind_reg, 0, sizeof(qcmap_msgr_mobile_ap_status_ind_register_req_msg_v01));
    memset(&qcmap_mobile_ap_status_ind_rsp, 0, sizeof(qcmap_msgr_mobile_ap_status_ind_register_resp_msg_v01));
    qcmap_mobile_ap_status_ind_reg.register_indication = 1;

    qmi_error = qmi_client_send_msg_sync(self->qmi_qcmap_msgr_handle,
                                        QMI_QCMAP_MSGR_MOBILE_AP_STATUS_IND_REG_REQ_V01,
                                        (void*)&qcmap_mobile_ap_status_ind_reg,
                                        sizeof(qcmap_msgr_mobile_ap_status_ind_register_req_msg_v01),
                                        (void*)&qcmap_mobile_ap_status_ind_rsp,
                                        sizeof(qcmap_msgr_mobile_ap_status_ind_register_resp_msg_v01),
                                        QCMAP_MSGR_QMI_TIMEOUT_VALUE);

    LOG("qmi_client_send_msg_sync: error %d result %d",
                    qmi_error, qcmap_mobile_ap_status_ind_rsp.resp.result);
    if ( ( qmi_error == QMI_TIMEOUT_ERR ) ||
        ( qmi_error != QMI_NO_ERR ) ||
        ( qcmap_mobile_ap_status_ind_rsp.resp.result != QMI_NO_ERR ))
    {
        LOG("Can not register for mobile ap status %d : %d",
                    qmi_error, qcmap_mobile_ap_status_ind_rsp.resp.error);
        return FALSE;
    }
    LOG("Registered for mobile ap status");

    memset(&qcmap_station_mode_status_ind_reg, 0, sizeof(qcmap_msgr_station_mode_status_ind_register_req_msg_v01));
    memset(&qcmap_station_mode_status_ind_rsp, 0, sizeof(qcmap_msgr_station_mode_status_ind_register_resp_msg_v01));
    qcmap_station_mode_status_ind_reg.register_indication = 1;

    qmi_error = qmi_client_send_msg_sync(self->qmi_qcmap_msgr_handle,
                        QMI_QCMAP_MSGR_STATION_MODE_STATUS_IND_REG_REQ_V01,
                        (void*)&qcmap_station_mode_status_ind_reg,
                        sizeof(qcmap_msgr_station_mode_status_ind_register_req_msg_v01),
                        (void*)&qcmap_station_mode_status_ind_rsp,
                        sizeof(qcmap_msgr_station_mode_status_ind_register_resp_msg_v01),
                        QCMAP_MSGR_QMI_TIMEOUT_VALUE);

    LOG("qmi_client_send_msg_sync: error %d result %d",
            qmi_error, qcmap_station_mode_status_ind_rsp.resp.result);
    if ( ( qmi_error == QMI_TIMEOUT_ERR ) ||
        ( qmi_error != QMI_NO_ERR ) ||
        ( qcmap_station_mode_status_ind_rsp.resp.result != QMI_NO_ERR ))
    {
        LOG("Can not register for station mode indications %d : %d",
                    qmi_error, qcmap_station_mode_status_ind_rsp.resp.error);
        return FALSE;
    }
    LOG("Registered for station mode status");

    qmi_error = qmi_client_send_msg_sync(self->qmi_qcmap_msgr_handle,
                                        QMI_QCMAP_MSGR_MOBILE_AP_ENABLE_REQ_V01,
                                        NULL,
                                        0,
                                        (void*)&qcmap_enable_resp_msg_v01,
                                        sizeof(qcmap_msgr_mobile_ap_enable_resp_msg_v01),
                                        QCMAP_MSGR_QMI_TIMEOUT_VALUE);
    LOG("qmi_client_send_msg_sync: error %d result %d valid %d",
                    qmi_error, qcmap_enable_resp_msg_v01.resp.result, qcmap_enable_resp_msg_v01.mobile_ap_handle_valid);
    if (( qmi_error == QMI_TIMEOUT_ERR ) ||
        ( qmi_error != QMI_NO_ERR ) ||
        ( qcmap_enable_resp_msg_v01.resp.result != QMI_NO_ERR) ||
        ( qcmap_enable_resp_msg_v01.mobile_ap_handle_valid != TRUE ))
    {
        LOG("Can not enable qcmap %d : %d",
            qmi_error, qcmap_enable_resp_msg_v01.resp.error);
        return FALSE;
    }

    if( qcmap_enable_resp_msg_v01.mobile_ap_handle > 0 )
    {
        self->mobile_ap_handle = qcmap_enable_resp_msg_v01.mobile_ap_handle;
        self->qcmap_msgr_enable = TRUE;
        LOG("QCMAP Enabled\n");
        return TRUE;
    }
    else
    {
        LOG("QCMAP Enable Failure\n");
    }

    return FALSE;
}
  • 去使能
/* Disable MobileAP */
static boolean qcmap_ppp_disable(qcmap_ppp_t *self) {
    qcmap_msgr_mobile_ap_disable_req_msg_v01 qcmap_disable_req_msg_v01;
    qcmap_msgr_mobile_ap_disable_resp_msg_v01 qcmap_disable_resp_msg_v01;
    qmi_client_error_type qmi_error = QMI_NO_ERR;

    

    if (!self->qcmap_msgr_enable)
    {
        /* QCMAP is not enabled */
        LOG("QCMAP not enabled\n");
        return FALSE;
    }

    qcmap_disable_req_msg_v01.mobile_ap_handle = self->mobile_ap_handle;
    qmi_error = qmi_client_send_msg_sync(self->qmi_qcmap_msgr_handle,
                                        QMI_QCMAP_MSGR_MOBILE_AP_DISABLE_REQ_V01,
                                        &qcmap_disable_req_msg_v01,
                                        sizeof(qcmap_msgr_mobile_ap_disable_req_msg_v01),
                                        &qcmap_disable_resp_msg_v01,
                                        sizeof(qcmap_msgr_mobile_ap_disable_resp_msg_v01),
                                        QCMAP_MSGR_QMI_TIMEOUT_VALUE);

    if ( ( qmi_error == QMI_TIMEOUT_ERR ) ||
        ( qmi_error != QMI_NO_ERR ) ||
        ( (qcmap_disable_resp_msg_v01.resp.error != QMI_ERR_NO_EFFECT_V01 &&
            qcmap_disable_resp_msg_v01.resp.error != QMI_ERR_NONE_V01)) ||
        ( qcmap_disable_resp_msg_v01.resp.result != QMI_NO_ERR ))
    {
        LOG( "Can not disable qcmap %d : %d",
            qmi_error, qcmap_disable_resp_msg_v01.resp.error);
        return FALSE;
    }

    /*.If backhaul is not connected, Mobileap will be disabled instantly. And since
        call back function is being called much before the response pending flag is set to TRUE,
        responses are not sent to the client.
        Hence, we set qcmap_disable_resp_msg_v01.resp.error to QMI_ERR_NO_EFFECT_V01
        So that the caller of this function sends a response back to the client. (Used for IoE 9x25)
        */
    if (qcmap_disable_resp_msg_v01.resp.error == QMI_ERR_NO_EFFECT_V01)
        LOG( "Already disable qcmap %d", qcmap_disable_resp_msg_v01.resp.error);

    self->mobile_ap_handle = 0;
    self->qcmap_msgr_enable = FALSE;
    return TRUE;
}
  • 连接服务
/* ConnectBackHaul */
static boolean qcmap_ppp_connect(qcmap_ppp_t *self) {
    int qcmap_msgr_errno;
    int ret = 0;
    qcmap_msgr_wwan_call_type_v01 call_type = QCMAP_MSGR_WWAN_CALL_TYPE_V4_V01;

    qcmap_msgr_bring_up_wwan_req_msg_v01 qcmap_bring_up_wwan_req_msg;
    qcmap_msgr_bring_up_wwan_resp_msg_v01 qcmap_bring_up_wwan_resp_msg;
    qmi_client_error_type qmi_error;

    


    /* Bring up the data call. */
    LOG("Bring up wwan");
    qcmap_bring_up_wwan_req_msg.mobile_ap_handle = self->mobile_ap_handle;
    qcmap_bring_up_wwan_req_msg.call_type_valid = TRUE;

    qcmap_bring_up_wwan_req_msg.call_type = call_type;

    qmi_error = qmi_client_send_msg_sync(self->qmi_qcmap_msgr_handle,
                                        QMI_QCMAP_MSGR_BRING_UP_WWAN_REQ_V01,
                                        &qcmap_bring_up_wwan_req_msg,
                                        sizeof(qcmap_msgr_bring_up_wwan_req_msg_v01),
                                        &qcmap_bring_up_wwan_resp_msg,
                                        sizeof(qcmap_msgr_bring_up_wwan_resp_msg_v01),
                                        QCMAP_MSGR_QMI_TIMEOUT_VALUE);

    if ( ( qmi_error == QMI_TIMEOUT_ERR ) ||
        ( qmi_error != QMI_NO_ERR ) ||
        ( qcmap_bring_up_wwan_resp_msg.resp.result != QMI_NO_ERR ) )
    {
    LOG("Can not bring up wwan qcmap %d : %d",
        qmi_error, qcmap_bring_up_wwan_resp_msg.resp.error);
    return FALSE;
    }

    /*
    If WWAN is already enabled, and we are trying to enable again from a different client,
    set error number to QMI_ERR_NO_EFFECT_V01, so that the correspondingclient can be
    informed. We hit this scenario in the following case:
    1. Start QCMAP_CLI and enable Backhaul.
    2. Start MCM_MOBILEAP_CLI and try enabling backhaul again.
    */
    if (call_type == QCMAP_MSGR_WWAN_CALL_TYPE_V4_V01 &&
        qcmap_bring_up_wwan_resp_msg.conn_status ==
        QCMAP_MSGR_WWAN_STATUS_CONNECTED_V01)
    {
    LOG("WWAN is already enabled.");
    }
    else if (call_type == QCMAP_MSGR_WWAN_CALL_TYPE_V6_V01 &&
        qcmap_bring_up_wwan_resp_msg.conn_status ==
        QCMAP_MSGR_WWAN_STATUS_IPV6_CONNECTED_V01)
    {
    LOG("IPv6 WWAN is already enabled.");
    }
    else
    LOG("Bringing up wwan...");
    return TRUE;
}
  • 断开服务
/* DisconnectBackHual */
static boolean qcmap_ppp_disconnect(qcmap_ppp_t *self) {
    qcmap_msgr_wwan_call_type_v01 call_type = QCMAP_MSGR_WWAN_CALL_TYPE_V4_V01;

    qcmap_msgr_tear_down_wwan_req_msg_v01 qcmap_tear_down_wwan_req_msg;
    qcmap_msgr_tear_down_wwan_resp_msg_v01 qcmap_tear_down_wwan_resp_msg;
    qmi_client_error_type qmi_error;
    

    LOG("Bringing down wwan");
    qcmap_tear_down_wwan_req_msg.mobile_ap_handle = self->mobile_ap_handle;

    qcmap_tear_down_wwan_req_msg.call_type_valid = TRUE;

    qcmap_tear_down_wwan_req_msg.call_type = call_type;

    qmi_error = qmi_client_send_msg_sync(self->qmi_qcmap_msgr_handle,
                                        QMI_QCMAP_MSGR_TEAR_DOWN_WWAN_REQ_V01,
                                        &qcmap_tear_down_wwan_req_msg,
                                        sizeof(qcmap_msgr_tear_down_wwan_req_msg_v01),
                                        &qcmap_tear_down_wwan_resp_msg,
                                        sizeof(qcmap_msgr_tear_down_wwan_resp_msg_v01),
                                        QCMAP_MSGR_QMI_TIMEOUT_VALUE);

    if ( ( qmi_error == QMI_TIMEOUT_ERR ) ||
        ( qmi_error != QMI_NO_ERR) ||
        ( qcmap_tear_down_wwan_resp_msg.resp.result != QMI_NO_ERR ) )
    {
    LOG("Can not tear down wwan qcmap %d : %d",
        qmi_error, qcmap_tear_down_wwan_resp_msg.resp.error);
    return FALSE;
    }

    /*
        If WWAN is already disabled, and we are trying to disable again from a different client,
        set error number to QMI_ERR_NO_EFFECT_V01, so that the correspondingclient can be
        informed. We hit this scenario in the following case:
        1. Start QCMAP_CLI and enable Backhaul.
        2. Start MCM_MOBILEAP_CLI and try enabling backhaul again.
        3. Disable backhaul from the 1st client.
        4. Now from the 2nd client.
    */
    if (call_type == QCMAP_MSGR_WWAN_CALL_TYPE_V4_V01 &&
        qcmap_tear_down_wwan_resp_msg.conn_status ==
        QCMAP_MSGR_WWAN_STATUS_DISCONNECTED_V01)
    {
        LOG("WWAN is already disabled.");
    }
    else if (call_type == QCMAP_MSGR_WWAN_CALL_TYPE_V6_V01 &&
        qcmap_tear_down_wwan_resp_msg.conn_status ==
        QCMAP_MSGR_WWAN_STATUS_IPV6_DISCONNECTED_V01)
    {
        LOG("IPv6 WWAN is already disabled.");
    }
    else
        LOG("Tearing down wwan...");
    return TRUE;
}

/* Get WWAN Statistics. */
static boolean qcmap_ppp_get_statistics(qcmap_ppp_t *self, qcmap_msgr_ip_family_enum_v01 ip_family, qcmap_msgr_wwan_statistics_type_v01 *wwan_stats) {
    qcmap_msgr_get_wwan_stats_req_msg_v01 get_wwan_stats_req_msg;
    qcmap_msgr_get_wwan_stats_resp_msg_v01 get_wwan_stats_resp_msg;
    qmi_client_error_type qmi_error;

    

    get_wwan_stats_req_msg.mobile_ap_handle = self->mobile_ap_handle;
    get_wwan_stats_req_msg.ip_family = ip_family;

    qmi_error = qmi_client_send_msg_sync(self->qmi_qcmap_msgr_handle,
                                        QMI_QCMAP_MSGR_GET_WWAN_STATS_REQ_V01,
                                        &get_wwan_stats_req_msg,
                                        sizeof(qcmap_msgr_get_wwan_stats_req_msg_v01),
                                        &get_wwan_stats_resp_msg,
                                        sizeof(qcmap_msgr_get_wwan_stats_resp_msg_v01),
                                        QCMAP_MSGR_QMI_TIMEOUT_VALUE);

    if ( ( qmi_error == QMI_TIMEOUT_ERR ) ||
        ( qmi_error != QMI_NO_ERR ) ||
        ( get_wwan_stats_resp_msg.resp.result != QMI_NO_ERR ) )
    {
    LOG("Can not get wwan stats %d : %d",
        qmi_error, get_wwan_stats_resp_msg.resp.error);
    return FALSE;
    }

    wwan_stats->bytes_rx = get_wwan_stats_resp_msg.wwan_stats.bytes_rx;
    wwan_stats->bytes_tx = get_wwan_stats_resp_msg.wwan_stats.bytes_tx;
    wwan_stats->pkts_rx = get_wwan_stats_resp_msg.wwan_stats.pkts_rx;
    wwan_stats->pkts_tx = get_wwan_stats_resp_msg.wwan_stats.pkts_tx;
    wwan_stats->pkts_dropped_rx = get_wwan_stats_resp_msg.wwan_stats.pkts_dropped_rx;
    wwan_stats->pkts_dropped_tx = get_wwan_stats_resp_msg.wwan_stats.pkts_dropped_tx;
    LOG("Get WWAN Stats succeeded...");
    return TRUE;
}

/* Reset WWAN Statistics. */
static boolean qcmap_ppp_reset_statistics(qcmap_ppp_t *self, qcmap_msgr_ip_family_enum_v01 ip_family) {
    qcmap_msgr_reset_wwan_stats_req_msg_v01 reset_wwan_stats_req_msg;
    qcmap_msgr_reset_wwan_stats_resp_msg_v01 reset_wwan_stats_resp_msg;
    qmi_client_error_type qmi_error;

    

    reset_wwan_stats_req_msg.mobile_ap_handle = self->mobile_ap_handle;
    reset_wwan_stats_req_msg.ip_family = ip_family;

    qmi_error = qmi_client_send_msg_sync(self->qmi_qcmap_msgr_handle,
                                        QMI_QCMAP_MSGR_RESET_WWAN_STATS_REQ_V01,
                                        &reset_wwan_stats_req_msg,
                                        sizeof(qcmap_msgr_reset_wwan_stats_req_msg_v01),
                                        &reset_wwan_stats_resp_msg,
                                        sizeof(qcmap_msgr_reset_wwan_stats_resp_msg_v01),
                                        QCMAP_MSGR_QMI_TIMEOUT_VALUE);

    if ( ( qmi_error == QMI_TIMEOUT_ERR ) ||
        ( qmi_error != QMI_NO_ERR ) ||
        ( reset_wwan_stats_resp_msg.resp.result != QMI_NO_ERR ) )
    {
        LOG("Can not reset wwan stats %d : %d",
            qmi_error, reset_wwan_stats_resp_msg.resp.error);
            return FALSE;
    }

    LOG("Reset WWAN Stats succeeded...");
    return TRUE;
}

/* Enable/Disable Autoconnect mode */
static boolean qcmap_ppp_set_auto_connect(qcmap_ppp_t *self, boolean enable) {
    qcmap_msgr_set_auto_connect_req_msg_v01 set_auto_connect_req_msg;
    qcmap_msgr_set_auto_connect_resp_msg_v01 set_auto_connect_resp_msg;
    qmi_client_error_type qmi_error;

    

    set_auto_connect_req_msg.mobile_ap_handle = self->mobile_ap_handle;
    set_auto_connect_req_msg.enable = enable;

    qmi_error = qmi_client_send_msg_sync(self->qmi_qcmap_msgr_handle,
                                        QMI_QCMAP_MSGR_SET_AUTO_CONNECT_REQ_V01,
                                        &set_auto_connect_req_msg,
                                        sizeof(qcmap_msgr_set_auto_connect_req_msg_v01),
                                        &set_auto_connect_resp_msg,
                                        sizeof(qcmap_msgr_set_auto_connect_resp_msg_v01),
                                        QCMAP_MSGR_QMI_TIMEOUT_VALUE);
    if ( ( qmi_error == QMI_TIMEOUT_ERR ) ||
        ( qmi_error != QMI_NO_ERR ) ||
        ( set_auto_connect_resp_msg.resp.result != QMI_NO_ERR ) )
    {
    LOG("Can not set auto connect flag %d : %d",
            qmi_error, set_auto_connect_resp_msg.resp.error);
        return FALSE;
    }

    LOG("Auto Connect Mode Set succeeded...");
    return TRUE;
}

至此,就可以完成拨号的连接和断开。

2.3 PPP状态

如果关注状态通知,需要处理知函数client_cb_ind中状态通知。主要包含了建立拨号成功/失败,网络状态变化(切换网络模式)的断开通知等。

static void qcmap_ppp_ind(
    qmi_client_type user_handle,
    unsigned int msg_id,
    void *ind_buf,
    unsigned int ind_buf_len,
    void *ind_cb_data )
{
    qmi_client_error_type qmi_error;
    LOG("qcmap_msgr_qmi_qcmap_ind: user_handle %X msg_id %d ind_buf_len %d.", user_handle, msg_id, ind_buf_len);
}
2.4 建立连接可选项
  • 禁用ipv6

static boolean qcmap_ppp_disable_ipv6(qcmap_ppp_t *self) {
    int qcmap_msgr_errno;
    int ret = 0;
    qcmap_msgr_disable_ipv6_req_msg_v01 qcmap_disable_ipv6_req_msg;
    qcmap_msgr_disable_ipv6_resp_msg_v01 qcmap_disable_ipv6_resp_msg;
    qmi_client_error_type qmi_error;

    /* Enable IPV6. */
    LOG("Disable IPV6");
    qcmap_disable_ipv6_req_msg.mobile_ap_handle = self->mobile_ap_handle;

    qmi_error = qmi_client_send_msg_sync(self->qmi_qcmap_msgr_handle,
                                        QMI_QCMAP_MSGR_DISABLE_IPV6_REQ_V01,
                                        &qcmap_disable_ipv6_req_msg,
                                        sizeof(qcmap_msgr_disable_ipv6_req_msg_v01),
                                        &qcmap_disable_ipv6_resp_msg,
                                        sizeof(qcmap_msgr_disable_ipv6_resp_msg_v01),
                                        QCMAP_MSGR_QMI_TIMEOUT_VALUE);

    if ( ( qmi_error == QMI_TIMEOUT_ERR ) ||
        ( qmi_error != QMI_NO_ERR ) ||
        ( qcmap_disable_ipv6_resp_msg.resp.result != QMI_NO_ERR ) )
    {
    LOG("Can not disable ipv6 %d : %d",
        qmi_error, qcmap_disable_ipv6_resp_msg.resp.error);
    return FALSE;
    }

    LOG("Disabled IPV6...");
    return TRUE;
}
  • 配置自动连接(没测试出效果)
/* Enable/Disable Autoconnect mode */
static boolean qcmap_ppp_set_auto_connect(qcmap_ppp_t *self, boolean enable) {
    qcmap_msgr_set_auto_connect_req_msg_v01 set_auto_connect_req_msg;
    qcmap_msgr_set_auto_connect_resp_msg_v01 set_auto_connect_resp_msg;
    qmi_client_error_type qmi_error;

    

    set_auto_connect_req_msg.mobile_ap_handle = self->mobile_ap_handle;
    set_auto_connect_req_msg.enable = enable;

    qmi_error = qmi_client_send_msg_sync(self->qmi_qcmap_msgr_handle,
                                        QMI_QCMAP_MSGR_SET_AUTO_CONNECT_REQ_V01,
                                        &set_auto_connect_req_msg,
                                        sizeof(qcmap_msgr_set_auto_connect_req_msg_v01),
                                        &set_auto_connect_resp_msg,
                                        sizeof(qcmap_msgr_set_auto_connect_resp_msg_v01),
                                        QCMAP_MSGR_QMI_TIMEOUT_VALUE);
    if ( ( qmi_error == QMI_TIMEOUT_ERR ) ||
        ( qmi_error != QMI_NO_ERR ) ||
        ( set_auto_connect_resp_msg.resp.result != QMI_NO_ERR ) )
    {
    LOG("Can not set auto connect flag %d : %d",
            qmi_error, set_auto_connect_resp_msg.resp.error);
        return FALSE;
    }

    LOG("Auto Connect Mode Set succeeded...");
    return TRUE;
}
  • 查询wwan统计信息(流量)
/* Get WWAN Status */
static boolean qcmap_ppp_get_status(qcmap_ppp_t *self, qcmap_msgr_wwan_status_enum_v01 *v4_status, qcmap_msgr_wwan_status_enum_v01 *v6_status) {
    qmi_client_error_type qmi_error, qmi_err_code = QMI_NO_ERR;
    qcmap_msgr_wwan_status_req_msg_v01 wan_status_req;
    qcmap_msgr_wwan_status_resp_msg_v01 wan_status_resp;
    

    memset(&wan_status_resp, 0, sizeof(qcmap_msgr_wwan_status_resp_msg_v01));
    wan_status_req.mobile_ap_handle = self->mobile_ap_handle;
    wan_status_req.call_type_valid = 1;
    wan_status_req.call_type = QCMAP_MSGR_WWAN_CALL_TYPE_V4_V01;
    qmi_error = qmi_client_send_msg_sync(self->qmi_qcmap_msgr_handle,
                                        QMI_QCMAP_MSGR_WWAN_STATUS_REQ_V01,
                                        &wan_status_req,
                                        sizeof(qcmap_msgr_wwan_status_req_msg_v01),
                                        (void*)&wan_status_resp,
                                        sizeof(qcmap_msgr_wwan_status_resp_msg_v01),
                                        QCMAP_MSGR_QMI_TIMEOUT_VALUE);

    LOG("qmi_client_send_msg_sync(enable): error %d result %d",
        qmi_error, wan_status_resp.resp.result);

    if ( ( qmi_error == QMI_TIMEOUT_ERR ) ||
        ( qmi_error != QMI_NO_ERR ) ||
        ( wan_status_resp.resp.result != QMI_NO_ERR ) )
    {
    LOG("Can not get IPV4 WAN status  %d : %d",
        qmi_error, wan_status_resp.resp.error);
    return FALSE;
    }
    if(wan_status_resp.conn_status_valid ==1)
    {
    *v4_status=wan_status_resp.conn_status;
    if(wan_status_resp.conn_status == QCMAP_MSGR_WWAN_STATUS_CONNECTING_V01)
    {
        LOG(" IPV4 WWAN is Connecting \n");
    }
    else if(wan_status_resp.conn_status == QCMAP_MSGR_WWAN_STATUS_CONNECTED_V01)
    {
        LOG(" IPV4 WWAN is connected \n");
    }
    else if(wan_status_resp.conn_status == QCMAP_MSGR_WWAN_STATUS_DISCONNECTING_V01)
    {
        LOG(" IPV4 WWAN is Disconnecting \n");
    }
    else if(wan_status_resp.conn_status == QCMAP_MSGR_WWAN_STATUS_DISCONNECTED_V01)
    {
        LOG(" IPV4 WWAN is Disconnected \n");
    }
    }

#ifdef ENABLE_IPV6
    memset(&wan_status_resp, 0, sizeof(qcmap_msgr_wwan_status_resp_msg_v01));
    wan_status_req.mobile_ap_handle = self->mobile_ap_handle;
    wan_status_req.call_type_valid = 1;
    wan_status_req.call_type = QCMAP_MSGR_WWAN_CALL_TYPE_V6_V01;
    qmi_error = qmi_client_send_msg_sync(self->qmi_qcmap_msgr_handle,
                                        QMI_QCMAP_MSGR_WWAN_STATUS_REQ_V01,
                                        &wan_status_req,
                                        sizeof(qcmap_msgr_wwan_status_req_msg_v01),
                                        (void*)&wan_status_resp,
                                        sizeof(qcmap_msgr_wwan_status_resp_msg_v01),
                                        QCMAP_MSGR_QMI_TIMEOUT_VALUE);

    LOG("qmi_client_send_msg_sync(enable): error %d result %d",
        qmi_error, wan_status_resp.resp.result);

    if ( ( qmi_error == QMI_TIMEOUT_ERR ) ||
        ( qmi_error != QMI_NO_ERR ) ||
        ( wan_status_resp.resp.result != QMI_NO_ERR ) )
    {
        LOG("Can not get IPV6 WAN status %d : %d",
            qmi_error, wan_status_resp.resp.error);
        return FALSE;
    }
    if(wan_status_resp.conn_status_valid == 1)
    {
    *v6_status=wan_status_resp.conn_status;
    if(wan_status_resp.conn_status == QCMAP_MSGR_WWAN_STATUS_IPV6_CONNECTING_V01)
    {
        LOG(" IPV6 WWAN is Connecting \n");
    }
    else if(wan_status_resp.conn_status == QCMAP_MSGR_WWAN_STATUS_IPV6_CONNECTED_V01)
    {
        LOG(" IPV6 WWAN is connected \n");
    }
    else if(wan_status_resp.conn_status == QCMAP_MSGR_WWAN_STATUS_IPV6_DISCONNECTING_V01)
    {
        LOG(" IPV6 WWAN is Disconnecting \n");
    }
    else if(wan_status_resp.conn_status == QCMAP_MSGR_WWAN_STATUS_IPV6_DISCONNECTED_V01)
    {
        LOG(" IPV6 WWAN is Disconnected \n");
    }
    }
#endif

    return TRUE;
}

综上,基本用到的就这些接口了,比起直接使用高通提供的QCMAP_Client类接口,本文实现更原生、灵活,经过验证可以在国内多家9X07模块上正确稳定的执行。

3 其他组件服务功能

请自行研究实现,不做赘述了。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容