1. 程式人生 > >7 android QMI機制---modem訊息傳送

7 android QMI機制---modem訊息傳送

原文:https://blog.csdn.net/u012439416/article/details/74277592 

7 modem訊息傳送

一般BP側處理完請求後,都會迴應一個響應給AP,一般是用巨集QMI_SVC_PKT_PUSH將要作為響應

的訊息傳送出去。qmi_svc_utils.h中QMI_SVC_PKT_PUSH定義如下,

#define QMI_SVC_PKT_PUSH(pkt,val,len) ( len == dsm_pushdown_packed(pkt,\

val,\ len,\ DSM_DS_SMALL_ITEM_POOL ) )

將val裡面的資料,傳len個長度到pkt的buffer裡面,然後傳送出去。Val和len是我們要作為響應的資料

和資料包大小。QMI_SVC_PKT_PUSH()只能傳單一的引數,根據上文說明的QMUX訊息中TLV格式

的原理,可以用多個QMI_SVC_PKT_PUSH連著用,這樣可以將多個數據或引數打包到同一條訊息中傳送。

例如,在voice服務中,用多個QMI_SVC_PKT_PUSH回傳訊息。
QMI_SVC_PKT_PUSH(&response, (void*)&info->call_id, sizeof(info->call_id))) )
•••
QMI_SVC_PKT_PUSH(&response, (void *)&tag, VOICEI_TLV_TAG_SIZE)
•••

最後還要記得寫上TLV的總長度,和標誌位。標誌位必須和AP側發出的請求相對應,如AP側發出請求為0x21,

返回的標誌位rec_tag也必須為0x21,方便返回AP後查表處理。將TLV訊息放入response這個buffer後,

會繼續打包QMUX的訊息頭,然後通過函式qmi_mmode_svc_send_response()傳送出去。呼叫流程圖如下,

/* Send the response */

status = qmi_mmode_svc_send_response( &common_hdr,cmd_buf_p, msg_ptr);

回傳的訊息也是需要嚴格按照QMUX訊息的格式的, qmi_mmode_svc_send_response方法中按照格式對

QMUX訊息進行重組,

msg_hdr.common_hdr.client_id      = common_hdr->client_id; 
msg_hdr.common_hdr.qmi_instance   = common_hdr->qmi_instance;  
msg_hdr.common_hdr.service        = common_hdr->service;  
msg_hdr.common_hdr.transaction_id = x_p->x_id;
msg_hdr.msg_ctl_flag = QMI_FLAG_MSGTYPE_RESP;
if( x_p->n_cmds > 1 )
{
  msg_hdr.msg_ctl_flag |= QMI_FLAG_MASK_COMPOUND;
}
msg_hdr.msg_len  = (uint16) dsm_length_packet(msg_ptr);
qmi_framework_svc_send_response( &msg_hdr, msg_ptr );

指標msg_ptr,讀取x_p->resp_list[]中的響應訊息,msg_hdr為qmux訊息的頭。通過函式

qmi_framework_svc_send_respnse()發到qmi_framework,這只是qmi_framework的一個介面,

會呼叫qmi_frameworki_svc_send方法,直接呼叫qmi_frameworki_svc_send方法,
tatus = qmi_frameworki_svc_send( msg_hdr, 
                               QMI_CMD_FRAMEWORK_SEND_RESPONSE,
                               msg_ptr );

qmi_frameworki_svc_send方法首先對接收到QMUX訊息進行處理,將訊息頭和內容放到結構體

qmi_framework_msg_buf的成員變數中,

memscpy( &qmi_framework_msg_buf->msg_hdr, sizeof (*msg_hdr), msg_hdr, 
          sizeof (*msg_hdr) );
qmi_framework_msg_buf->dsm_item = msg_ptr;

然後呼叫qmi_framework_process_svc_send方法,

return qmi_framework_process_svc_send((void *)qmi_framework_msg_buf, qmi_cmd );

qmi_framework_process_svc_send方法首先校驗QMI服務給qmi_framework發出的command,

判斷這次從BP側發出的訊息是一個響應AP側請求的response還是主動發給AP的一個indicated

if((qmi_cmd_id_e_type)qmi_cmd == QMI_CMD_FRAMEWORK_SEND_RESPONSE )
  {
    msg_type = QMI_FLAG_MSGTYPE_RESP;
  }
  else if((qmi_cmd_id_e_type)qmi_cmd == QMI_CMD_FRAMEWORK_SEND_IND)
  {
    msg_type = QMI_FLAG_MSGTYPE_IND;

然後判斷訊息頭的有效性,最後通過函式qmi_frameworki_qmux_send()傳送到BP側QMI的介面,

if (FALSE == qmi_frameworki_validate_msg_hdr(msg_hdr, msg_type ))
{
  LOG_MSG_ERROR_1 ("Msg header validation failed - unable to send Response for cmd %d",
                   msg_hdr->msg_ctl_flag);
    goto func_end;
  }
  return qmi_frameworki_qmux_send(msg_buf, msg_type, ind_cmd_id, msg_ptr);
qmi_frameworki_qmux_send方法首先會對QMUX訊息進行一個過濾,如果訊息異常,則丟棄

if ( qmi_svc_filter_message( (qmi_instance_e_type) 
msg_buf->msg_hdr.common_hdr.qmi_instance, msg_buf->msg_hdr.common_hdr.service,
            msg_type, int_cmd_id) )
{
•••

然後呼叫QMUX層的介面qmux_sio_send方法進行處理,

qmux_sio_send ( (qmi_instance_e_type)msg_buf->msg_hdr.common_hdr.qmi_instance, 
  msg_buf->msg_hdr.common_hdr.service, msg_buf->msg_hdr.common_hdr.client_id, msg_ptr);

qmux_sio_send方法首先呼叫dsm_length_packet方法對訊息進行組裝,

if( dsm_length_packet(qmux_sdu) == 0)

然後組合上IF Type完成整個訊息重組,

if type = (byte)qmux_state[ qmi_instance ].io.port_info.frame_mode;

最後通過IO口的傳輸函式傳送到AP側,

if( QMUX_DEVSTREAM_CONTROL != qmux_state[qmi_instance].io.port_info.qmi_stream )
  {
    sio_transmit( qmux_state[qmi_instance].io.sio_handle, qmux_sdu );
  }
  else
  {
    sio_control_transmit( qmux_state[qmi_instance].io.sio_handle, qmux_sdu );
  }

這樣,訊息就從modem側發出來了。

8 QCRLC訊息接收

在qmi_qmux.c的qmi_qmux_pwr_up_init方法中,

QMI_QMUX_IO_PLATFORM_PWR_UP_INIT(qmi_qmux_rx_msg,qmi_qmux_event_cb);

qmi_qmux_rx_msg會接收處理BP側回發的訊息, 主要是對從BP側接收到的訊息進行解包,

判斷BP側的訊息型別是響應還是指示,轉發給上層client端處理。根據QMUX訊息結構的長度,

選擇是用1個位元組的方式讀取還是2個位元組的方式讀取,

/* Read the I/F byte, make sure it is a 1 */
READ_8_BIT_VAL(msg_ptr,i_f_byte);
 
if (i_f_byte != 1)
{
    QMI_ERR_MSG_1 ("qmi_qmux: Received invalid I/F byte = %d\n",i_f_byte);
     return;
}
/* Read the message length */
READ_16_BIT_VAL(msg_ptr, length);

判斷訊息型別是BP側群發的廣播,還是專門針對某個client端的響應。

if (client_id == QMI_QMUX_INVALID_QMI_CLIENT_ID)
{
      qmi_qmux_rx_client_broadcast (conn_id, service_id, client_id, control_flags,
                   msg_ptr, msg_len);
}
else
{
   qmi_qmux_rx_client_msg (conn_id, service_id, client_id, control_flags,
                     msg_ptr, msg_len);
    }

接下去的流程,和之前AP傳送的流程相似,不詳細介紹。