Windows CE串口驱动简析(3)-PDD层实现:RX,MODEM,LINE,IR部分(基于WinCE5.0 SMDK2410 BSP的Serial驱动)

接下来就是接收函数了:
15. GetWaterMarkBit和GetWaterMark
WaterMark存储的实际上是接收中断模式,对应与UFCON的第4,5位:

这两个函数用了s_HighWaterPairs这样一个结构数组来保存对应关系:
static PAIRS s_HighWaterPairs[] = { {0, 4 }, {1, 8 }, {2, 12 }, {3, 16 } };
GetWaterMarkBit用来获得s_HighWaterPairs的key值,也就是0,1,2,3中的一个,用m_dwWaterMark与这个数组成员的AssociatedValue的比较来获得.
BYTE CPdd2410Uart::GetWaterMarkBit() { BYTE bReturnKey = (BYTE)s_HighWaterPairs[0].Key; for (DWORD dwIndex=dim(s_HighWaterPairs)-1;dwIndex!=0; dwIndex --) { if (m_dwWaterMark>=s_HighWaterPairs[dwIndex].AssociatedValue) { bReturnKey = (BYTE)s_HighWaterPairs[dwIndex].Key; break; } } return bReturnKey; }
GetWaterMark用来获得s_HighWaterPairs的AssociatedValue值,也就是0,4,8,16中的一个,m_dwWaterMark必须为这4个值中的一个,如不是则取最较小相近的.
DWORD CPdd2410Uart::GetWaterMark() { BYTE bReturnValue = (BYTE)s_HighWaterPairs[0].AssociatedValue; for (DWORD dwIndex=dim(s_HighWaterPairs)-1;dwIndex!=0; dwIndex --) { if (m_dwWaterMark>=s_HighWaterPairs[dwIndex].AssociatedValue) { bReturnValue = (BYTE)s_HighWaterPairs[dwIndex].AssociatedValue; break; } } return bReturnValue; }
16. InitReceive
InitReceive负责初始化串口的数据接收功能. 和InitXmit一样有bool型一个参数,表示初始化还是解除初始化串口接收.
如果为TRUE,则先reset RX FIFO,设置UFCON Tx Trigger Level,写uWarterMarkBit,使能RX FIFO,清除error status,最后使能RX Timeout Interrupt,中断触发方式为level,接收模式为中断请求或轮询.
BOOL CPdd2410Uart::InitReceive(BOOL bInit) { m_HardwareLock.Lock(); if (bInit) { BYTE uWarterMarkBit = GetWaterMarkBit(); if (uWarterMarkBit> 3) uWarterMarkBit = 3; // Setup Receive FIFO. // Reset Receive Fifo. DWORD dwBit = m_pReg2410Uart->Read_UFCON(); dwBit |= (1<<1); dwBit &= ~(1<<0); m_pReg2410Uart->Write_UFCON( dwBit); // Set Trigger level to WaterMark. dwBit &= ~(3<<4); dwBit |= (uWarterMarkBit<<4); m_pReg2410Uart->Write_UFCON(dwBit); // Enable Receive FIFO. dwBit &= ~(1<<1); dwBit |= (1<<0); m_pReg2410Uart->Write_UFCON(dwBit); // Xmit Fifo Reset Done.. m_pReg2410Uart->Read_UERSTAT(); // Clean Line Interrupt. dwBit = m_pReg2410Uart->Read_UCON(); dwBit &= ~(3<<0); dwBit |= (1<<0)|(1<<7)|(1<<8); // Enable Rx Timeout and Level Interrupt Trigger. m_pReg2410Uart->Write_UCON(dwBit); EnableInterrupt(S2410UART_INT_RXD | S2410UART_INT_ERR ); } else { DisableInterrupt(S2410UART_INT_RXD | S2410UART_INT_ERR ); } m_HardwareLock.Unlock(); return TRUE; }
17.ReceiveInterruptHandler
同XmitInterruptHandler一样还有个处理接收中断的ReceiveInterruptHandler
ReceiveInterruptHandler首先检查buffer的有效性,然后读取UFSTAT获得当前接收FIFO字节数,如满则设置dwNumRxInFifo为16字节,然后从URXH寄存器读取dwNumRxInFifo字节数的数据到接收buffer,在读数据的过程中会调用GetLineStatus获取线路状态,并调用DataReplaced进行判断如果无错误进读数据.
ULONG CPdd2410Uart::ReceiveInterruptHandler(PUCHAR pRxBuffer,ULONG *pBufflen) { DEBUGMSG(ZONE_THREAD|ZONE_READ,(TEXT("+CPdd2410Uart::ReceiveInterruptHandler pRxBuffer=%x,*pBufflen=%x/r/n"), pRxBuffer,pBufflen!=NULL?*pBufflen:0)); DWORD dwBytesDropped = 0; if (pRxBuffer && pBufflen ) { DWORD dwBytesStored = 0 ; DWORD dwRoomLeft = *pBufflen; m_bReceivedCanceled = FALSE; m_HardwareLock.Lock(); while (dwRoomLeft && !m_bReceivedCanceled) { ULONG ulUFSTATE = m_pReg2410Uart->Read_UFSTAT(); DWORD dwNumRxInFifo = (ulUFSTATE & (0xf<<0)); if ((ulUFSTATE & (1<<8))!=0) // Overflow. Use FIFO depth (16); dwNumRxInFifo = SER2410_FIFO_DEPTH_RX; DEBUGMSG(ZONE_THREAD|ZONE_READ,(TEXT("CPdd2410Uart::ReceiveInterruptHandler ulUFSTATE=%x,UTRSTAT=%x, dwNumRxInFifo=%X/r/n"), ulUFSTATE, m_pReg2410Uart->Read_UTRSTAT(), dwNumRxInFifo)); if (dwNumRxInFifo) { ASSERT((m_pReg2410Uart->Read_UTRSTAT () & (1<<0))!=0); while (dwNumRxInFifo && dwRoomLeft) { UCHAR uLineStatus = GetLineStatus(); UCHAR uData = m_pReg2410Uart->Read_URXH(); if (DataReplaced(&uData,(uLineStatus & UERSTATE_PARITY_ERROR)!=0)) { *pRxBuffer++ = uData; dwRoomLeft--; dwBytesStored++; } dwNumRxInFifo --; } } else break; } if (m_bReceivedCanceled) dwBytesStored = 0; m_HardwareLock.Unlock(); *pBufflen = dwBytesStored; } else { ASSERT(FALSE); } DEBUGMSG(ZONE_THREAD|ZONE_READ,(TEXT("-CPdd2410Uart::ReceiveInterruptHandler pRxBuffer=%x,*pBufflen=%x,dwBytesDropped=%x/r/n"), pRxBuffer,pBufflen!=NULL?*pBufflen:0,dwBytesDropped)); return dwBytesDropped; }
18.CancelReceive
CancelReceive供驱动程序取消串口的数据接收.通过调用InitReceive(TRUE)来重新重新初始化串口,reset FIFO等.
ULONG CPdd2410Uart::CancelReceive() { m_bReceivedCanceled = TRUE; m_HardwareLock.Lock(); InitReceive(TRUE); m_HardwareLock.Unlock(); return 0; }
下面再来看看和MODEM相关的部分.
19. InitModem
InitModem初始化串口的MODEM功能.设置UMCON寄存器禁止AFC(Auto Flow Control)和使能RTS(Request To Send).
BOOL CPdd2410Uart::InitModem(BOOL bInit) { m_HardwareLock.Lock(); m_pReg2410Uart->Write_UMCON((1<<0)); // Disable AFC and Set RTS as default. m_HardwareLock.Unlock(); return TRUE; }  
20. GetModemStatus
GetModemStatus供驱动程序获取串口的MODEM状态. 通过读取UMSTAT寄存器来获取MODEM状态,进行事件通知或报告状态.
ULONG CPdd2410Uart::GetModemStatus() { m_HardwareLock.Lock(); ULONG ulReturn =0 ; ULONG Events = 0; UINT8 ubModemStatus = (UINT8) m_pReg2410Uart->Read_UMSTAT(); m_HardwareLock.Unlock(); // Event Notification. if (ubModemStatus & (1<<2)) Events |= EV_CTS; if (Events!=0) EventCallback(Events); // Report Modem Status; if ( ubModemStatus & (1<<0) ) ulReturn |= MS_CTS_ON; return ulReturn; }
21. SetRTS
设置RTS,根据输入参数来使能或禁止RTS.
void CPdd2410Uart::SetRTS(BOOL bSet) { m_HardwareLock.Lock(); ULONG ulData = m_pReg2410Uart->Read_UMCON(); if (bSet) { ulData |= (1<<0); } else ulData &= ~(1<<0); m_pReg2410Uart->Write_UMCON(ulData); m_HardwareLock.Unlock(); }
下面是线路相关处理函数:
22. InitLine
InitLine初始化串口的数据收发属性.这里就是使能或禁止串口ERR中断.
BOOL CPdd2410Uart::InitLine(BOOL bInit) { m_HardwareLock.Lock(); if (bInit) { // Set 8Bit,1Stop,NoParity,Normal Mode. //m_pReg2410Uart->Write_ULCON( (0x3<<0) | (0<<1) | (0<<3) | (0<<6) ); EnableInterrupt( S2410UART_INT_ERR ); } else { DisableInterrupt(S2410UART_INT_ERR ); } m_HardwareLock.Unlock(); return TRUE; }
23. GetLineStatus
GetLineStatus用来获取线路状态.读取UERSTAT寄存器来获得错误状态并返回或调用回调事件(Break Receive).
BYTE CPdd2410Uart::GetLineStatus() { m_HardwareLock.Lock(); ULONG ulData = m_pReg2410Uart->Read_UERSTAT(); m_HardwareLock.Unlock(); ULONG ulError = 0; if (ulData & (1<<0) ) { ulError |= CE_OVERRUN; } if (ulData & (1<<1)) { ulError |= CE_RXPARITY; } if (ulData & (1<<2)) { ulError |= CE_FRAME; } if (ulError) SetReceiveError(ulError); if (ulData & (1<<3)) { EventCallback(EV_BREAK); } return (UINT8)ulData; }
24. SetBreak
SetBreak用来向对端发出一个间断信号(指串口的发送数据引脚上持续一个数据帧事件的低电平).这里通过设置UCON的bit4.
void CPdd2410Uart::SetBreak(BOOL bSet) { m_HardwareLock.Lock(); ULONG ulData = m_pReg2410Uart->Read_UCON(); if (bSet) ulData |= (1<<4); else ulData &= ~(1<<4); m_pReg2410Uart->Write_UCON(ulData); m_HardwareLock.Unlock(); }
25.SetBaudRate
SetBaudRate设置波特率,调用CReg2410Uart类对象的Write_BaudRate来实现.
BOOL CPdd2410Uart::SetBaudRate(ULONG BaudRate,BOOL /*bIrModule*/) { m_HardwareLock.Lock(); BOOL bReturn = m_pReg2410Uart->Write_BaudRate(BaudRate); m_HardwareLock.Unlock(); return TRUE; }
26. SetByteSize
SetByteSize设置串口的数据帧中的数据位的位数,设置ULCON寄存器的0,1位来设置.
BOOL CPdd2410Uart::SetByteSize(ULONG ByteSize) { BOOL bRet = TRUE; m_HardwareLock.Lock(); ULONG ulData = m_pReg2410Uart->Read_ULCON() & (~0x3); switch ( ByteSize ) { case 5: break; case 6: ulData|= (1<<0); break; case 7: ulData |= (2<<0); break; case 8: ulData |= (3<<0); break; default: bRet = FALSE; break; } if (bRet) { m_pReg2410Uart->Write_ULCON(ulData); } m_HardwareLock.Unlock(); return bRet; }
27. SetParity
SetParity设置传输数据的校验方式(奇偶).通过设置ULCON的3,4,5位来实现.
BOOL CPdd2410Uart::SetParity(ULONG Parity) { BOOL bRet = TRUE; m_HardwareLock.Lock(); ULONG ulData = m_pReg2410Uart->Read_ULCON() & (~(0x7<<3)); switch ( Parity ) { case ODDPARITY: ulData |= (4<<3); break; case EVENPARITY: ulData |= (5<<3); break; case MARKPARITY: ulData |= (6<<3); break; case SPACEPARITY: ulData |= (7<<3); break; case NOPARITY: break; default: bRet = FALSE; break; } if (bRet) { m_pReg2410Uart->Write_ULCON(ulData); } m_HardwareLock.Unlock(); return bRet; }
28.SetStopBits
SetStopBits用来设置停止位.通过设置ULCON的第2位来实现.
BOOL CPdd2410Uart::SetStopBits(ULONG StopBits) { BOOL bRet = TRUE; m_HardwareLock.Lock(); ULONG ulData = m_pReg2410Uart->Read_ULCON() & (~(0x1<<2)); switch ( StopBits ) { case ONESTOPBIT : break; case TWOSTOPBITS : ulData |= (0x1<<2); break; default: bRet = FALSE; break; } if (bRet) { m_pReg2410Uart->Write_ULCON(ulData); } m_HardwareLock.Unlock(); return bRet; }
29.SetOutputMode
最后还有个IR处理函数SetOutputMode,这个函数有两个bool输入参数,UseIR表示是否启用红外输出模式,Use9Pin表示是否启用9针引脚工作模式.
SetOutputMode首先调用基类的SetOutputMode,然后根据UseIR来设置ULCON的第6位.
void CPdd2410Uart::SetOutputMode(BOOL UseIR, BOOL Use9Pin) { m_HardwareLock.Lock(); CSerialPDD::SetOutputMode(UseIR, Use9Pin); ULONG ulData = m_pReg2410Uart->Read_ULCON() & (~(0x1<<6)); ulData |= (UseIR?(0x1<<6):0); m_pReg2410Uart->Write_ULCON(ulData); m_HardwareLock.Unlock(); }
这里附上ULCON的具体位的含义:

更多对寄存器的操作请参考s3c2410A的datasheet.

CPdd2410Uart类基本介绍完了,这里介绍的都是需要实现的成员函数,还有些函数在基类CSerialPDD类中实现了,如SetReceiveError和GetReceiveError等.具体内容可以参考cserpdd.c中的CSerialPDD实现.

你可能感兴趣的:(thread,windows,buffer,byte,WinCE,events)