📄 comhand.cpp
字号:
{
goto Error;
}
// Send as many commands as we can in the time we have (make sure to send at least one command)
while (!g_pCmdQ->FEmpty())
{
// Delete whatever was in the command structure
delete pCmd;
pCmd = NULL;
// Get the next command
hr = g_pCmdQ->Get(pCmd, 0);
if (FAILED(hr))
{
goto Error;
}
// Send the command
if (!SendRILCmdHandleRsp(pRilDevice, pCmd, rfBackToCmdMode, fDummy))
{
goto Error;
}
DEBUGCHK(NULL == pCmd);
// If this command forced us to hangup the data connection, bail out
if (rfBackToCmdMode)
{
fRet = TRUE;
goto Error;
}
// See if we can send another command
if (!g_pCmdQ->Peek(pCmdPeeked) ||
!FEnoughTimeToSendCmd(pCmdPeeked, dwTimeAllowedInCmdMode - (GetTickCount() - dwStartTime)))
{
break;
}
}
pCmdPeeked = NULL;
// Return to the data mode
nAttempts = 0;
do
{
pCmd = new CCommand;
if (!pCmd ||
!pCmd->Init(NULL, "ATO\r", NULL,
CMDOPT_IGNORERSP | CMDOPT_REQUIRECONNECTRSP,
EXECTIME_API_DEFAULT,
g_TimeoutCmdOnline,
NULL, NULL, 0, 0, 0, APIID_NONE, NULL, NULL))
{
goto Error;
}
if (!SendRILCmdHandleRsp(pRilDevice, pCmd, rfBackToCmdMode, fATOTimedOut))
{
goto Error;
}
} while (!rfBackToCmdMode && fATOTimedOut && ++nAttempts < MAX_ATO_ATTEMPTS);
// If ATO timed out too many times, just assume we got stuck in command mode and hope for the best
// (The only other alternative is to reset the system)
if (fATOTimedOut)
{
(void)ExitDataMode();
rfBackToCmdMode=TRUE;
(void)pRilDevice->BroadcastRealBlobNotification(RIL_NOTIFY_CALLSTATECHANGED, NULL, 0);
}
fRet = TRUE;
Error:
if (!rfBackToCmdMode)
{
if (fPortInitSucceded)
{
// Reset old timeouts
(void)SetCommTimeouts(m_hDownstream, &ctOld);
// Reset old state
(void)SetCommState(m_hDownstream, &dcbOld);
}
// Reset the old comm mask
if (fEnteredExclusiveUse)
{
(void)SetCommMask(m_hDownstream, dwMask);
}
}
// Exit exclusive use mode
if (fEnteredExclusiveUse)
{
(void)ExitExclusiveUse();
}
delete pCmd;
return fRet;
}
//
//
//
BOOL CComHandle::FEnoughTimeToSendCmd(CCommand* pCmd, DWORD dwTimeLeft) const
{
// FUNCTION_TRACE(CComHandle::FEnoughTimeToSendCmd);
DEBUGCHK(NULL != pCmd);
BOOL fRet = (pCmd->GetExecTime() <= dwTimeLeft);
if (!fRet)
{
// This command will take too long to execute -- age the command
pCmd->Age();
}
return fRet;
}
//
//
//
void CComHandle::UpdateComStatData(const BOOL fRead, const DWORD dwBytes)
{
// FUNCTION_TRACE(CComHandle::UpdateComStatData);
SYNCBLOCK(m_csStats);
DEBUGCHK(FALSE != m_fInited);
UINT nBucketsToShift;
DWORD* pdwBuckets = (fRead ? m_rgdwReadStatBits : m_rgdwWriteStatBits);
DWORD* pdwLastTime = (fRead ? &m_dwReadStatTimestamp : &m_dwWriteStatTimestamp);
DWORD dwCurrentTime = GetTickCount();
BOOL fRet = FALSE;
DEBUGCHK(NULL != pdwBuckets);
if (dwCurrentTime != *pdwLastTime)
{
// Determine which bucket the new data goes into
nBucketsToShift = (dwCurrentTime - *pdwLastTime) / m_dwStatQuantum;
if (STAT_BUCKETS < nBucketsToShift)
{
nBucketsToShift = STAT_BUCKETS;
}
if (nBucketsToShift)
{
// Shift the data in buckets, if needed
if (STAT_BUCKETS > nBucketsToShift)
{
memmove(pdwBuckets + nBucketsToShift, pdwBuckets, (STAT_BUCKETS - nBucketsToShift) * sizeof(DWORD));
}
// Clear out all the new buckets upfront
memset(pdwBuckets, 0x00, nBucketsToShift * sizeof(DWORD));
}
// Place the new data into the first bucket
*pdwBuckets += (dwBytes * 8);
// Update the timestamp
*pdwLastTime = dwCurrentTime;
}
}
//
//
//
void CComHandle::CalculateComStats(DWORD& rdwReadBitsPerSec, DWORD& rdwWrittenBitsPerSec)
{
// FUNCTION_TRACE(CComHandle::CalculateComStats);
SYNCBLOCK(m_csStats);
DEBUGCHK(FALSE != m_fInited);
UINT i;
DWORD dwReadBitsPerQuantum = 0;
DWORD dwWrittenBitsPerQuantum = 0;
HANDLE hThread = GetCurrentThread();
DWORD dwOldPri;
// Switch to the highest priority
dwOldPri = GetThreadPriority(hThread);
(void)SetThreadPriority(hThread, THREAD_PRIORITY_HIGHEST);
// Update the read and write statistics
UpdateComStatData(TRUE, 0);
UpdateComStatData(FALSE, 0);
// Calculate weighted averages of data in read and write buckets (in bits per m_dwStatQuantum msec)
for (i = 0; i < STAT_BUCKETS; i++)
{
dwReadBitsPerQuantum += m_rgdwReadStatBits[i] * (STAT_BUCKETS - i) / STAT_BUCKET_WEIGHTS;
dwWrittenBitsPerQuantum += m_rgdwWriteStatBits[i] * (STAT_BUCKETS - i) / STAT_BUCKET_WEIGHTS;
}
// Convert the averages to bits per sec
rdwReadBitsPerSec = dwReadBitsPerQuantum * 1000 / m_dwStatQuantum;
rdwWrittenBitsPerSec = dwWrittenBitsPerQuantum * 1000 / m_dwStatQuantum;
DEBUGMSG(ZONE_TRACE, (TEXT("RILDrv : t : CComHandle::CalculateComStats : Com statistics: read - %d bits/sec, write - %d bits/sec\r\n"),
rdwReadBitsPerSec, rdwWrittenBitsPerSec));
// Switch back to the old priority
(void)SetThreadPriority(hThread, dwOldPri);
}
//
//
//
DWORD CComHandle::CalculateCmdModeTime()
{
// FUNCTION_TRACE(CComHandle::CalculateCmdModeTime);
DEBUGCHK(0 != m_dwDownstreamBaudRate);
DWORD dwReadBitsPerSec;
DWORD dwWriteBitsPerSec;
DWORD dwBitsPerSecOverAir;
DWORD dwBitsPerQuantumOverAir;
DWORD dwTimeToSendBitsToRadio;
// Calculate average read and write throughput
CalculateComStats(dwReadBitsPerSec, dwWriteBitsPerSec);
dwBitsPerSecOverAir = dwReadBitsPerSec + dwWriteBitsPerSec;
// Calculate how many bits go over the air in m_dwStatQuantum msec, given the average throughput
// we just calculated
dwBitsPerQuantumOverAir = dwBitsPerSecOverAir * m_dwStatQuantum / 1000;
// Calculate the time we need to send these bits to the radio
dwTimeToSendBitsToRadio = dwBitsPerQuantumOverAir * 1000 / m_dwDownstreamBaudRate;
// Calculate the time difference (i.e. the time during which the radio is idle while the bits are sent
// over the air)
return m_dwStatQuantum - dwTimeToSendBitsToRadio;
}
//
// Function passed to CQueue::ConditionalGet() below
//
BOOL FDialAnswerCommand(void* pItem, DWORD dwData)
{
FUNCTION_TRACE(FDialAnswerCommand);
DEBUGCHK(NULL != pItem);
DEBUGCHK(NULL == dwData);
CCommand* pCmd = (CCommand*)pItem;
return (pCmd->FDial() || pCmd->FAnswer());
}
//
//
//
DWORD WINAPI HangupThreadProc(LPVOID lpParameter)
{
FUNCTION_TRACE(HangupThreadProc);
CCommand* pNextCmd = NULL;
HANDLE hQuitEvent;
CComHandle* pComDevice;
CRilHandle* pRilDevice;
{
HANGUP_THREAD_DATA* phtd = (HANGUP_THREAD_DATA*)lpParameter;
DEBUGCHK(NULL != phtd);
DEBUGCHK(NULL != phtd->hQuitEvent);
DEBUGCHK(NULL != phtd->pComDevice);
DEBUGCHK(NULL != phtd->pRilDevice);
hQuitEvent = phtd->hQuitEvent;
pComDevice = phtd->pComDevice;
pRilDevice = phtd->pRilDevice;
delete phtd;
}
HANDLE hEvents[2] = {g_hNewDialOrHangupEvent, hQuitEvent};
DWORD dwWait;
for (;;)
{
dwWait = WaitForMultipleObjects(2, hEvents, FALSE, INFINITE);
if (dwWait != WAIT_OBJECT_0)
{
break;
}
if (SUCCEEDED(g_pCmdQ->ConditionalGet(FDialAnswerCommand, 0, pNextCmd, 0)))
{
// The first command in the queue is a dial or answer
// Because it hasn't been issued yet, we can abort it easily by
// removing the command and faking a response.
DEBUGCHK(NULL != pNextCmd);
DEBUGCHK(pNextCmd->FDial() || pNextCmd->FAnswer());
// Fake a NOCARRIER response (acceptable for both failed dial and answer commands)
pNextCmd->SendResponse(RIL_RESULT_NOCARRIER, NULL, 0);
delete pNextCmd;
pNextCmd = NULL;
}
else if (g_pCmdQ->Peek(pNextCmd) && pNextCmd->FHangup())
{
// The first command in the queue is a hangup, so the dial/answer has
// already been issued. We must abort the ongoing command.
DEBUGMSG(ZONE_INFO, (TEXT("RILDrv : i : HangupThreadProc : Aborting dial/answer\r\n")));
pComDevice->SetCancelledDial();
// Send AT/r to abort the call
// Don't remove the command from the queue; the command thread will wake up later and
// send an additional ATH\r in case the far end picked up before we got a chance to abort.
(void)pComDevice->WriteCmdsToComPort(pRilDevice, "AT\r", 3);
g_RilLog.LogEvent(RILLOG_ZONE_CMD, RILLOG_EVENT_SENDINGCMD, PrintableString("AT\r", 3));
}
}
(void)CloseHandle(hQuitEvent);
return 0;
}
#ifdef OEM1_DRIVER
//
// Wait for the radio signon message
//
BOOL CComHandle::WaitForRadioSignon(CRilHandle* const pRilDevice)
{
BOOL fRet = FALSE;
HRESULT hr = NOERROR;
CResponse* pRsp = NULL;
DEBUGMSG(ZONE_INFO, (TEXT("RILDrv : i : CComHandle::WaitForRadioSignon : Waiting for radio signon\r\n")));
// Let RIL know we're waiting for AT response
pRilDevice->StartWaitingForRsp(NULL);
// Get the response out of the Response Queue
hr = g_pRspQ->Get(pRsp, 60000);
// See if we couldn't get the response for some reason
if (SUCCEEDED(hr)) {
fRet = TRUE;
}
// Let RIL know we're not waiting for AT response anymore
pRilDevice->StopWaitingForRsp();
delete pRsp;
return fRet;
}
#endif // OEM1_DRIVER
//
// Send an RIL command to the downstream port
//
BOOL CComHandle::SendRILCmdHandleRsp(CRilHandle* const pRilDevice, CCommand*& rpCmd, BOOL& rfHungUp, BOOL& rfTimedOut)
{
// FUNCTION_TRACE(CComHandle::SendRILCmdHandleRsp);
DEBUGCHK(NULL != pRilDevice);
DEBUGCHK(NULL != rpCmd);
LPSTR szCmd = NULL;
CResponse* pRsp = NULL;
HANDLE hQuitEvent=NULL;
HRESULT hr = S_OK;
BOOL fRet = FALSE;
rfHungUp = FALSE;
rfTimedOut = FALSE;
DEBUGMSG(ZONE_TRACE, (TEXT("RILDrv : t : Executing command with ID: 0x%08x\r\n"), rpCmd->GetID()));
#ifdef GPRS_CONTEXT_CACHING
if (APIID_SETGPRSCONTEXT == rpCmd->GetAPIID())
{
szCmd = rpCmd->GetCmd();
if (IsGPRSContextCommandCached(szCmd))
{
// This exact set GPRS context command has already been sent down.
// some radios don't like this to be sent down again, and anyway, there's
// no point, so just NOOP
rpCmd->SetCmdOpt(CMDOPT_NOOP);
}
}
#endif // GPRS_CONTEXT_CACHING
// If this is a deactivate command and a CRING has been detected just before this
// we are likely in the scenario where a ATCI or non-S/R data call is being deactivated
// before processing the incoming voice call (Connection Manager functionality). Class
// B GPRS radios cannot process a GPRS deactivate request when a incoming call is
// not processed yet, so we fake a response to this deactivate request without sending
// it to the radio. Note that we depend on celltsp to deactivate the GPRS context after
// the voice call is hung up because there is a mismatch between celltsp's picture (deactivated)
// and the radio's picture of the context (activated) and celltsp forces its state on the radio.
if (rpCmd->CmdOptIsSet(CMDOPT_DEACT)) {
EnterCriticalSection(&g_csDeactCringLock);
if (TRUE == IncomingCallInProgress()) {
rpCmd->SetCmdOpt(CMDOPT_NOOP);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -