📄 recv.c
字号:
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Copyright (c) 1995-1998 Microsoft Corporation
Module Name:
recv.c
Abstract:
This file implements the IrDA Serial IR NDIS MAC driver receive
functions. This is provided as a sample to platform writers and is
expected to be able to be used without modification on most (if not
all) hardware platforms.
Functions:
IrsirReturnPacket
IrsirRxThread
RxFrame
RxReadByte
SetRxTimeouts
GetRxBuffer
ReturnRxBuffer
AddRxPendingBuffer
RemoveRxPendingBuffer
Notes:
--*/
#include "irsirp.h"
//
// Prototypes.
//
static BOOL
RxReadByte(
PIR_DEVICE pIrDevice,
LPBYTE lpRead,
LPDWORD lpcbRead
);
static BOOL
RxFrame(
PIR_DEVICE pIrDevice,
PRX_BUFFER pRxBuf
);
static __inline BOOL
SetRxTimeouts(
HANDLE hSerial,
DWORD dwReadInterval,
DWORD dwReadTotalMult,
DWORD dwReadTotalConst
);
static PRX_BUFFER
GetRxBuffer(
PIR_DEVICE pIrDevice
);
static __inline VOID
ReturnRxBuffer(
PIR_DEVICE pIrDevice,
PRX_BUFFER pRxBuf
);
static __inline VOID
AddRxPendingBuffer(
PIR_DEVICE pIrDevice,
PRX_BUFFER pRxBuf
);
static PRX_BUFFER
RemoveRxPendingBuffer(
PIR_DEVICE pIrDevice,
PNDIS_PACKET pNdisPacket
);
/*++
Function: IrsirReturnPacket
Description: Protocol is returning ownership of a receive packet to the
miniport.
Arguments:
pv_pIrDevice - Pointer to the device context.
pNdisPacket - Pointer to the returned NDIS packet.
Returns:
None.
Comments:
--*/
VOID
IrsirReturnPacket(
IN NDIS_HANDLE pv_pIrDevice,
IN PNDIS_PACKET pNdisPacket
)
{
PIR_DEVICE pIrDevice = pv_pIrDevice;
PRX_BUFFER pRxBuf;
DEBUGMSG(ZONE_RECV,
(TEXT("+IrsirReturnPacket(0x%.8X, 0x%.8X)\r\n"),
pIrDevice, pNdisPacket)
);
// Find buffer on pending queue.
pRxBuf = RemoveRxPendingBuffer(pIrDevice, pNdisPacket);
// We put it on the queue, it should be there now!!
ASSERT(pRxBuf != NULL);
// Return buffer to free queue.
ReturnRxBuffer(pIrDevice, pRxBuf);
DEBUGMSG(ZONE_RECV, (TEXT("-IrsirReturnPacket\r\n")));
return;
}
/*++
Function: IrsirRxThread
Description: Main receive thread. Collects frames and calls
NdisMIndicateReceivePacket to indicate the data
to the protocol.
Arguments:
pv_pIrDevice - Pointer the IR device object.
Returns:
DWORD - NDIS_STATUS_CLOSING.
Comments:
--*/
DWORD
IrsirRxThread(
LPVOID pv_pIrDevice
)
{
PIR_DEVICE pIrDevice = pv_pIrDevice;
PRX_BUFFER pRxBuf = NULL;
BOOL fSuccess;
PNDIS_BUFFER pNdisBuffer;
NDIS_STATUS status;
DWORD dwCommErrors;
BOOL fSwitchSuccessful;
NDIS_HANDLE hSwitchToMiniport;
DEBUGMSG(ZONE_INIT | ZONE_RECV,
(TEXT("+IrsirRxThread(0x%.8X)\r\n"),
pIrDevice)
);
//
// Set timeouts to 3ms.
//
// SetRxTimeouts(pIrDevice->hSerial, MAXDWORD, 0, 0);
SetRxTimeouts(pIrDevice->hSerial, MAXDWORD, MAXDWORD, 3);
//
// Before we go into our receive loop, clear the serial driver recv queue
// and errors to ensure that switching baud rates or setting up the dongle
// (in StartDevice) didn't generate spurious byte(s) or errors.
//
if (PurgeComm(pIrDevice->hSerial, PURGE_RXCLEAR) == FALSE)
{
DEBUGMSG(ZONE_ERROR,
(TEXT("IrSIR: PurgeComm failure %#x\r\n"), GetLastError()));
ASSERT(FALSE);
// Don't fail. Worst case, we get an unwanted media busy.
}
dwCommErrors = CE_FRAME | CE_RXPARITY | CE_OVERRUN;
if (ClearCommError(pIrDevice->hSerial, &dwCommErrors, NULL) == FALSE)
{
DEBUGMSG(ZONE_ERROR,
(TEXT("IrSIR: ClearCommError failure %#x\r\n"), GetLastError()));
ASSERT(FALSE);
// Don't fail. Worst case, we get an unwanted media busy.
}
while (1)
{
// Get us a buffer.
pRxBuf = GetRxBuffer(pIrDevice);
DEBUGMSG(ZONE_RECV, (TEXT("Using RX buffer = 0x%.8X\r\n"), pRxBuf));
if (pRxBuf == NULL)
{
ASSERT(FALSE);
break;
}
fSuccess = RxFrame(pIrDevice, pRxBuf);
if (fSuccess == FALSE)
{
// Return the buffer so we can clean up. The device was closed.
ReturnRxBuffer(pIrDevice, pRxBuf);
break;
}
// Fix up some packet fields.
NDIS_SET_PACKET_HEADER_SIZE(
pRxBuf->pPacket,
SLOW_IR_ADDR_SIZE + SLOW_IR_CONTROL_SIZE
);
// Adjust buffer size to actual size of data and not size of the
// buffer.
NdisQueryPacket(pRxBuf->pPacket, NULL, NULL, &pNdisBuffer, NULL);
NdisAdjustBufferLength(pNdisBuffer, pRxBuf->cbData);
// This forces NdisQueryPacket to recalculate #packets and #bytes.
pRxBuf->pPacket->Private.ValidCounts = FALSE;
// Put receive buffer on pending queue before we indicate to the
// protocol, just in case the protocol can somehow call
// NdisReturnPacket before we queue it. If the protocol returns
// the packet immediately, we will just dequeue.
AddRxPendingBuffer(pIrDevice, pRxBuf);
// Since this is an intermediate miniport, we must call
// NdisIMSwitchToMiniport to grab the miniport lock.
fSwitchSuccessful = NdisIMSwitchToMiniport(
pIrDevice->hNdisAdapter,
&hSwitchToMiniport
);
if (fSwitchSuccessful == FALSE)
{
// WinCE's NdisIMSwitchToMiniport should not fail.
ASSERT(FALSE);
}
IRSIR_LOG_NDIS_PACKET(LOG_RXFRAME, pRxBuf->pPacket);
DEBUG_PACKET(ZONE_SNIFFIR, pRxBuf->pPacket);
NdisMIndicateReceivePacket(
pIrDevice->hNdisAdapter,
&pRxBuf->pPacket,
1
);
status = NDIS_GET_PACKET_STATUS(pRxBuf->pPacket);
if (status != NDIS_STATUS_PENDING)
{
pRxBuf = RemoveRxPendingBuffer(pIrDevice, pRxBuf->pPacket);
ASSERT(pRxBuf != NULL);
DEBUGMSG(ZONE_RECV,
(TEXT(" Removing packet from pending queue.\r\n")));
ReturnRxBuffer(pIrDevice, pRxBuf);
pRxBuf = NULL;
}
else
{
// Protocol has retained ownership of packet. The miniport
// will regain ownership when IrsirReturnPacket is called.
DEBUGMSG(ZONE_RECV,
(TEXT(" Protocol has retained ownership of packet 0x%.8X.\r\n"),
pRxBuf->pPacket)
);
pRxBuf = NULL;
}
// Undo the call to NdisIMSwitchToMiniport.
NdisIMRevertBack(pIrDevice->hNdisAdapter, hSwitchToMiniport);
// SetThreadPriority(GetCurrentThread(), OldPriority);
}
DEBUGMSG(ZONE_INIT | ZONE_RECV, (TEXT("-IrsirRxThread\r\n")));
return (NDIS_STATUS_CLOSING);
}
/*++
Function: RxFrame
Description: Receives an entire frame into the given buffer.
Arguments:
pIrDevice - Pointer to our device object. This is so we can keep
track of our receive state and have our receive state
reset externally. Also, keep track of frames received,
frames dropped (bad FCSs), and overflows.
pRxBuf - Receive buffer to copy frame into.
Returns:
BOOL
Success - TRUE. A valid frame has been received into the buffer.
Failure - FALSE. Something bad happened. Generally should not
get this.
Comments:
NOTE: The state machine must reset the index to the data buffer
before going back to RX_STATE_BOF.
State Machine Algorithm:
-------------------------------------------------------------------
| Event/State || READY | BOF | IN_ESC | RX |
-------------------------------------------------------------------
-------------------------------------------------------------------
| || | | | |
| char = BOF || state = | | reset | reset |
| || BOF | | state = | state = |
| || | | BOF | BOF |
-------------------------------------------------------------------
| || | | error | |
| char = ESC || | state = | reset | state = |
| || | IN_ESC | state = | IN_ESC |
| || | | READY | |
-------------------------------------------------------------------
| || | | | if valid |
| char = EOF || | state = | error | FCS { |
| || | READY | reset | indicate |
| || | | state = | data |
| || | | READY | state = |
| || | | | READY } |
-------------------------------------------------------------------
| || | | complement| |
| char = || | state = | bit 6 of | data[] = |
| || | RX | char | char |
| || | | data[] = | |
| || | data[] = | char | |
| || | char | state = | |
| || | | RX | |
-------------------------------------------------------------------
--*/
BOOL
RxFrame(
PIR_DEVICE pIrDevice,
PRX_BUFFER pRxBuf
)
{
SLOW_IR_FCS_TYPE fcs;
BYTE bRead;
DWORD cbRead;
LPBYTE pData = pRxBuf->pbBuffer;
LPBYTE pLimit = pRxBuf->pbBuffer + pRxBuf->cbBuffer;
BOOL fSuccess = TRUE;
#ifdef DEBUG
DWORD cbTotalRead = 0;
#endif // DEBUG
ASSERT(pIrDevice != NULL);
ASSERT(pRxBuf != NULL);
DEBUGMSG(ZONE_RECV,
(TEXT("+RxFrame(0x%.8X, 0x%.8X [0x%.8X, %d])\r\n"),
pIrDevice, pRxBuf, pRxBuf->pbBuffer, pRxBuf->cbBuffer)
);
while (1)
{
if (pIrDevice->pCurrBaud->dwBPS == 576000 ||
pIrDevice->pCurrBaud->dwBPS == 1152000 ||
pIrDevice->pCurrBaud->dwBPS == 4000000 )
{
fSuccess = RecvFIR(pIrDevice, pRxBuf);
goto done;
}else{
if (pIrDevice->RxState == RX_STATE_SHUTDOWN)
{
fSuccess = FALSE;
goto done;
}
if (RxReadByte(pIrDevice, &bRead, &cbRead) == FALSE)
{
fSuccess = FALSE;
goto done;
}
ASSERT((cbRead == 1) || (cbRead == 0));
// Did we time-out?
if (cbRead == 0) { continue; }
#ifdef DEBUG
cbTotalRead++;
#endif // DEBUG
switch (pIrDevice->RxState)
{
case RX_STATE_READY:
if (bRead == SLOW_IR_BOF)
{
pIrDevice->RxState = RX_STATE_BOF;
pData = pRxBuf->pbBuffer;
}
// else - Ignore all other data.
break; // RX_STATE_READY.
case RX_STATE_BOF:
switch (bRead)
{
case SLOW_IR_BOF:
// Ignore.
break;
case SLOW_IR_ESC:
pIrDevice->RxState = RX_STATE_IN_ESC;
break;
case SLOW_IR_EOF:
pIrDevice->RxState = RX_STATE_READY;
break;
default:
// Should be first character.
ASSERT(pRxBuf->pbBuffer == pData);
pIrDevice->RxState = RX_STATE_RX;
*pData++ = bRead;
break;
}
break; // RX_STATE_BOF.
case RX_STATE_IN_ESC:
switch (bRead)
{
// If (ESC + BOF) Then state = BOF.
case SLOW_IR_BOF:
// Reset.
pIrDevice->RxState = RX_STATE_BOF;
pData = pRxBuf->pbBuffer;
DEBUGMSG(ZONE_ERROR, (TEXT("Rx:Invalid BOF[1].\r\n")));
break;
// If (ESC + (ESC || EOF)) Then state = READY.
case SLOW_IR_ESC:
case SLOW_IR_EOF:
pIrDevice->RxState = RX_STATE_READY;
DEBUGMSG(ZONE_ERROR, (TEXT("Rx:Protocol error[1].\r\n")));
break;
// Escape sequence for BOF, EOF or ESC.
case SLOW_IR_BOF^SLOW_IR_ESC_COMP:
case SLOW_IR_EOF^SLOW_IR_ESC_COMP:
case SLOW_IR_ESC^SLOW_IR_ESC_COMP:
// Fall through, do same as default.
// Unnecessary escape sequence.
default:
if (pData < pLimit)
{
pIrDevice->RxState = RX_STATE_RX;
*pData++ = bRead^SLOW_IR_ESC_COMP;
}
else
{
// Overflow. Reset.
pIrDevice->RxState = RX_STATE_READY;
pIrDevice->cPacketsRxOverflow++;
DEBUGMSG(ZONE_ERROR,
(TEXT("Rx:Overflow[1] count = %d.\r\n"),
pIrDevice->cPacketsRxOverflow)
);
}
break;
}
break; // RX_STATE_IN_ESC.
case RX_STATE_RX:
switch (bRead)
{
case SLOW_IR_BOF:
// Reset.
pIrDevice->RxState = RX_STATE_BOF;
pData = pRxBuf->pbBuffer;
DEBUGMSG(ZONE_ERROR, (TEXT("Rx:Invalid BOF[2].\r\n")));
break;
case SLOW_IR_ESC:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -