Incoming call handling problem in RIL - Part 1

當有 incoming call 時,GSM module 會一直傳進

+CRING: VOICE

這時候以 CResponse::ParseNotification() parse 得知有 incoming call

 else if (MatchStringBeginning(szPointer, "+CRING: ", szPointer)) 

{ 

// Ring notification 

//NKDbgPrintfW(TEXT("Derek: Ringing...\r\n")); 

// Need to ask for the call list to send the differences. The new incoming call better 

// be in the call list of the radio. 

SetupCallListEvaluation (); 

if (!ParseExtRing(szPointer)) 

{ 

goto Error; 

} 

}

SetupCallListEvaluation() 將 AT+CLCC 放進 queue 並指定 callback function 以請求 modem 將目前有的 call list 傳回

QueueCmdIgnoreRsp(APIID_GETCALLLIST, "AT+CLCC\r", CMDOPT_NONE /* CMDOPT_IGNORERSP */, g_TimeoutCmdInit, (PFN_CMD_PARSE) PreParseGetCallList, NULL, 0, 0, 0);

在接到 AT+CLCC 的 response 時 function PreParseGetCallList() 會負責以 LocalParseGetCallList() 處理,並將 parse 的結果 - call list 存入 global table 中,然後送出 call list 改變的通知。

HRESULT PreParseGetCallList(LPCSTR szRsp, void*& pBlob, UINT& cbBlob) 
{ 

HRESULT hReturnValue; 

FUNCTION_TRACE(PreParseGetCallList); 

RETAILMSG(1, (TEXT("PreParseGetCallList : i : \r\n"))); 

EnterCriticalSection(&g_csCallStates); 

hReturnValue = LocalParseGetCallList (true, szRsp, pBlob, cbBlob); 

SendCallListChangedNotification (); 

LeaveCriticalSection(&g_csCallStates); 

return (hReturnValue); 
}

通知發出後返回 CResponse::ParseNotification(),接著呼叫 CResponse::ParseExtRing() 取得 call type (在這個例子是 voice call,其他還有像是 fax, data 之類的)

 if (MatchStringBeginning(rszPointer, "AUX ", rszPointer)) 

{ 

// The AUX indicates the alternate line. 

rri.dwAddressId = 1; 

} 

if (MatchStringBeginning(rszPointer, "ASYNC\r", rszPointer)) 

{ 

rri.dwCallType = RIL_CALLTYPE_DATA; 

rri.rsiServiceInfo.fSynchronous = FALSE; 

rri.rsiServiceInfo.fTransparent = TRUE; 

} 

else if (MatchStringBeginning(rszPointer, "SYNC\r", rszPointer)) 

{ 

rri.dwCallType = RIL_CALLTYPE_DATA; 

rri.rsiServiceInfo.fSynchronous = TRUE; 

rri.rsiServiceInfo.fTransparent = TRUE; 

} 

else if (MatchStringBeginning(rszPointer, "REL ASYNC\r", rszPointer)) 

{ 

rri.dwCallType = RIL_CALLTYPE_DATA; 

rri.rsiServiceInfo.fSynchronous = FALSE; 

rri.rsiServiceInfo.fTransparent = FALSE; 

} 

else if (MatchStringBeginning(rszPointer, "REL SYNC\r", rszPointer)) 

{ 

rri.dwCallType = RIL_CALLTYPE_DATA; 

rri.rsiServiceInfo.fSynchronous = TRUE; 

rri.rsiServiceInfo.fTransparent = FALSE; 

} 

else if (MatchStringBeginning(rszPointer, "FAX\r", rszPointer)) 

{ 

rri.dwCallType = RIL_CALLTYPE_FAX; 

} 

else if (MatchStringBeginning(rszPointer, "VOICE\r", rszPointer)) 

{ 

rri.dwCallType = RIL_CALLTYPE_VOICE; // default value 

if (g_rfExternalCalltypeDetermination) 

{ 

if (!DetermineRingingCalltype(&rri.dwCallType)) 

{ 

// Delay the notification until we know the calltype 

// Walk back over the  

rszPointer -= 1; 

// Make sure we don't try to broadcast a null response 

m_fUnsolicited = TRUE; 

return TRUE; 

} 

} 

} 

else 

{ 

// Skip to the next  

fPostfixFound = FindRspPostfix(rszPointer, rszPointer); 

DEBUGCHK(FALSE != fPostfixFound); 

rri.dwCallType = RIL_CALLTYPE_UNKNOWN; 

}

如果 parse 不到合適的 type 就會被設成 RIL_CALLTYPE_UNKNOWN。

AT+CLCC 的 modem response 範例如下

+CLCC: 1,1,4,0,0,"0227583788",129OK

PreParseGetCallList() 會以 LocalParseGetCallList() 處理之。第 1 個欄位是 call ID

 // Parse "" 

if (!ParseUInt(szRsp, TRUE, nValue, szRsp)) { 

goto Continue; 

} 

rgrci[nUsed].dwID = nValue; 

rgrci[nUsed].dwParams |= RIL_PARAM_CI_ID;

第 2 個欄位是 direction,也就是這通電話是接進來的還是打出去的

 // Parse "," 

if (!MatchStringBeginning(szRsp, ",", szRsp) || 

!ParseUIntAndVerifyAbove(szRsp, TRUE, 2, nValue, szRsp)) { 

goto Continue; 

} 

rgrci[nUsed].dwDirection = (nValue ? RIL_CALLDIR_INCOMING : RIL_CALLDIR_OUTGOING); 

rgrci[nUsed].dwParams |= RIL_PARAM_CI_DIRECTION;

第 3 個欄位是 status

 // Parse "," 

if (!MatchStringBeginning(szRsp, ",", szRsp) || 

!ParseUIntAndVerifyAbove(szRsp, TRUE, NUM_CALLSTATS, nValue, szRsp)) { 

goto Continue; 

} 

rgrci[nUsed].dwStatus = g_rgdwCallStats[nValue]; 

rgrci[nUsed].dwParams |= RIL_PARAM_CI_STATUS; 

switch (g_rgdwCallStats[nValue]) 

{ 

case RIL_CALLSTAT_INCOMING: 

case RIL_CALLSTAT_WAITING: 

bIncomingCall = TRUE; 

} 

if (true == bSaveDataInGlobals) 

{ 

g_rgfCallStates[nCid].dwStatus = g_rgdwCallStats[nValue]; 

g_rgfCallStates[nCid].dwParams |= RIL_PARAM_CI_CPISTATUS; 

switch (g_rgfCallStates[nCid].dwStatus) 

{ 

case RIL_CALLSTAT_ALERTING: 

case RIL_CALLSTAT_DIALING: 

g_rgfCallStates[nCid].dwStatus = RIL_CPISTAT_NEW_OUTGOING; 

break; 

case RIL_CALLSTAT_INCOMING: 

case RIL_CALLSTAT_WAITING: 

g_rgfCallStates[nCid].dwStatus = RIL_CPISTAT_NEW_INCOMING; 

break; 

case RIL_CALLSTAT_ACTIVE: 

g_rgfCallStates[nCid].dwStatus = RIL_CPISTAT_CONNECTED; 

break; 

case RIL_CALLSTAT_ONHOLD: 

g_rgfCallStates[nCid].dwStatus = RIL_CPISTAT_ONHOLD; 

break; 

default: 

g_rgfCallStates[nCid].dwStatus = RIL_CPISTAT_UNKNOWN; 

g_rgfCallStates[nCid].dwParams &= ~RIL_PARAM_CI_CPISTATUS; 

break; 

} 

}

第 4 個欄位是 type

 // Parse "," 

if (!MatchStringBeginning(szRsp, ",", szRsp) || 

!ParseUIntAndVerifyAbove(szRsp, TRUE, NUM_CALLTYPES, nValue, szRsp)) { 

goto Continue; 

} 

rgrci[nUsed].dwType = g_rgdwCallTypes[nValue]; 

rgrci[nUsed].dwParams |= RIL_PARAM_CI_TYPE; 

if (true == bSaveDataInGlobals) 

{ 

g_rgfCallStates[nCid].dwType = g_rgdwCallTypes[nValue]; 

g_rgfCallStates[nCid].dwParams |= RIL_PARAM_CI_TYPE; 

}

第 5 個欄位是 parse multiparty。1 為 multiparty,0 為 single party

 // Parse "," 

if (!MatchStringBeginning(szRsp, ",", szRsp) || 

!ParseUIntAndVerifyAbove(szRsp, TRUE, 2, nValue, szRsp)) { 

goto Continue; 

} 

rgrci[nUsed].dwMultiparty = (nValue ? RIL_CALL_MULTIPARTY : RIL_CALL_SINGLEPARTY); 

rgrci[nUsed].dwParams |= RIL_PARAM_CI_MULTIPARTY; 

if (true == bSaveDataInGlobals) 

{ 

g_rgfCallStates[nCid].dwMultiparty = (nValue ? RIL_CALL_MULTIPARTY : RIL_CALL_SINGLEPARTY); 

g_rgfCallStates[nCid].dwParams |= RIL_PARAM_CI_MULTIPARTY; 

}

最後取得 address 及其 type,並將 AT address 轉成 RIL address

 // Parse "," 

if (MatchStringBeginning(szRsp, ",", szRsp)) { 

// Parse "

," if (ParseString(szRsp, szAddress, MAXLENGTH_ADDRESS, szRsp)) { if (!MatchStringBeginning(szRsp, ",", szRsp) || !ParseUIntAndVerifyAbove(szRsp, FALSE, 0x100, nValue, szRsp) || !StringToRILAddress(szAddress, (BYTE)nValue, rgrci[nUsed].raAddress)) { goto Continue; } rgrci[nUsed].dwParams |= RIL_PARAM_CI_ADDRESS; if (true == bSaveDataInGlobals) { g_rgfCallStates[nCid].dwParams |= RIL_PARAM_CI_ADDRESS; StringToRILAddress(szAddress, (BYTE)nValue, g_rgfCallStates[nCid].raAddress); } } else { // If we couldn't parse an address, then it might be empty, // meaning the ID is blocked. Since the address parameter // is present, make sure the type also exists before continuing. if (!MatchStringBeginning(szRsp, ",", szRsp) || !ParseUIntAndVerifyAbove(szRsp, FALSE, 0x100, nValue, szRsp)) { goto Continue; } } // Parse "," if (MatchStringBeginning(szRsp, ",", szRsp)) { // Parse "" if (!ParseQuotedEncodedString(g_rppPDDParams->etEncodingTECharset, szRsp, rgrci[nUsed].wszDescription, rgrci[nUsed].wszDescription + MAXLENGTH_DESCRIPTION)) { goto Continue; } rgrci[nUsed].dwParams |= RIL_PARAM_CI_DESCRIPTION; if (true == bSaveDataInGlobals) { g_rgfCallStates[nCid].dwParams |= RIL_PARAM_CI_DESCRIPTION; StringCchCopyNW(g_rgfCallStates[nCid].wszDescription, MAXLENGTH_DESCRIPTION, rgrci[nUsed].wszDescription, MAXLENGTH_DESCRIPTION-1); } } }

在這個 function return 前,會執行

SetBacklightIncomingCall(bIncomingCall);

閃動畫面提醒使用者有 incoming call。

以下為執行時記錄下來的 log

SetupCallListEvaluation : i 
RILDrv : t : CRilHandle::BroadcastNotification : Broadcasting notification 0x10001 
RIL_IOControl: dwCode=IOCTL_RIL_GETNEXTNOTIFICATION (5), dwLenIn=0x0, dwLenOut=0x100 
CResponse::ParseNotification(): Before ParseRspPrefix(): <0d><0a>+CLCC: 1,1,4,0,0,"0227583788",129<0d><0a><0d><0a>OK<0d><0a> 
RIL_IOControl: dwCode=IOCTL_RIL_GETNEXTNOTIFICATION (5), dwLenIn=0x0, dwLenOut=0x100 
RIL_IOControl: dwCode=IOCTL_RIL_GETNEXTNOTIFICATION (5), dwLenIn=0x0, dwLenOut=0x100 
RIL_IOControl: dwCode=IOCTL_RIL_GETNEXTNOTIFICATION (5), dwLenIn=0x0, dwLenOut=0x100 
PreParseGetCallList : i : 
RILDrv : i : CALL_LIST : cid = 1, status = 2, params = bb 
RILDrv : i : CLCC : CallInfoSize = 1 
RILDrv : i : CLCC : cid = 1, status = 5, params = 3f 
RILDrv : i : CALL_LIST : cid = 1, status = 2, params = bb 
RILDrv : i : ParseGetCallList : sizeof(rgfNewCallsInProgress) = 40 
RILDrv : t : CRilHandle::BroadcastNotification : Broadcasting notification 0x1000b