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傳送的流程相似,不詳細介紹。