📄 mdd.c
字号:
}
/* Free our resources */
if ( pSerialHead->hSerialEvent )
CloseHandle(pSerialHead->hSerialEvent);
if ( pSerialHead->hKillDispatchThread )
CloseHandle(pSerialHead->hKillDispatchThread);
if ( pSerialHead->hTransmitEvent )
CloseHandle(pSerialHead->hTransmitEvent);
if ( pSerialHead->hReadEvent )
CloseHandle(pSerialHead->hReadEvent);
DeleteCriticalSection(&(pSerialHead->ReceiveCritSec1));
DeleteCriticalSection(&(pSerialHead->TransmitCritSec1));
DeleteCriticalSection(&(pSerialHead->RxBufferInfo.CS));
DeleteCriticalSection(&(pSerialHead->TxBufferInfo.CS));
DeleteCriticalSection(&(pSerialHead->OpenCS));
if ( pSerialHead->RxBufferInfo.RxCharBuffer )
LocalFree(pSerialHead->RxBufferInfo.RxCharBuffer);
/* Now, call HW specific deinit function */
if ( pSerialHead->pHWObj && pSerialHead->pHWObj->pFuncTbl ) {
DEBUGMSG (ZONE_INIT, (TEXT("About to call HWDeinit\r\n")));
pSerialHead->pHWObj->pFuncTbl->HWDeinit(pSerialHead->pHWHead);
DEBUGMSG (ZONE_INIT, (TEXT("Returned from HWDeinit\r\n")));
}
LocalFree(pSerialHead);
DEBUGMSG (ZONE_INIT|ZONE_FUNCTION, (TEXT("-COM_Deinit\r\n")));
return(TRUE);
}
/*
@doc EXTERNAL
@func ULONG | COM_Read | Allows application to receive characters from
* serial port. This routine sets the buffer and bufferlength to be used
* by the reading thread. It also enables reception and controlling when
* to return to the user. It writes to the referent of the fourth argument
* the number of bytes transacted. It returns the status of the call.
*
* Exported to users.
@rdesc This routine returns: -1 if error, or number of bytes read.
*/
ULONG
COM_Read(
HANDLE pHead, //@parm [IN] HANDLE returned by COM_Open
PUCHAR pTargetBuffer, //@parm [IN,OUT] Pointer to valid memory.
ULONG BufferLength //@parm [IN] Size in bytes of pTargetBuffer.
)
{
PHW_OPEN_INFO pOpenHead = (PHW_OPEN_INFO)pHead;
PHW_INDEP_INFO pSerialHead = pOpenHead->pSerialHead;
PHW_VTBL pFuncTbl = pSerialHead->pHWObj->pFuncTbl;
PVOID pHWHead = pSerialHead->pHWHead;
ULONG Ticks;
ULONG Timeout;
ULONG BytesRead = 0;
ULONG IntervalTimeout; // The interval timeout
ULONG AddIntervalTimeout;
ULONG TotalTimeout; // The Total Timeout
ULONG TimeSpent = 0; // How much time have we been waiting?
ULONG Len;
DEBUGMSG (ZONE_USR_READ|ZONE_FUNCTION,
(TEXT("+COM_READ(0x%X,0x%X,%d)\r\n"),
pHead, pTargetBuffer, BufferLength));
// Check to see that the call is valid.
if ( !pSerialHead || !pSerialHead->OpenCnt ) {
DEBUGMSG (ZONE_USR_READ|ZONE_ERROR,
(TEXT("COM_READ, device not open\r\n") ));
SetLastError (ERROR_INVALID_HANDLE);
return(ULONG)-1;
}
// Make sure the caller has access permissions
if ( !(pOpenHead->AccessCode & GENERIC_READ) ) {
DEBUGMSG(ZONE_USR_READ|ZONE_ERROR,
(TEXT("COM_Read: Access permission failure x%X\n\r"),
pOpenHead->AccessCode));
SetLastError (ERROR_INVALID_ACCESS);
return(ULONG)-1;
}
#ifdef DEBUG
if ( IsBadWritePtr(pTargetBuffer, BufferLength) ) {
BytesRead = (ULONG)-1;
SetLastError(ERROR_INVALID_PARAMETER);
return(ULONG)-1;
}
#endif
COM_INC_USAGE_CNT(pOpenHead);
/* Practice safe threading.
*/
EnterCriticalSection(&(pSerialHead->ReceiveCritSec1));
/* Compute total time to wait. Take product and add constant.
*/
if ( MAXDWORD != pSerialHead->CommTimeouts.ReadTotalTimeoutMultiplier ) {
TotalTimeout = pSerialHead->CommTimeouts.ReadTotalTimeoutMultiplier*BufferLength +
pSerialHead->CommTimeouts.ReadTotalTimeoutConstant;
// Because we are using FIFO and water level is set to 8, we have to do following
AddIntervalTimeout=pSerialHead->CommTimeouts.ReadTotalTimeoutMultiplier*8;
} else {
TotalTimeout = pSerialHead->CommTimeouts.ReadTotalTimeoutConstant;
AddIntervalTimeout=0;
}
IntervalTimeout = pSerialHead->CommTimeouts.ReadIntervalTimeout;
if (IntervalTimeout < MAXDWORD - AddIntervalTimeout) {
IntervalTimeout +=AddIntervalTimeout;
};
DEBUGMSG (ZONE_USR_READ, (TEXT("TotalTimeout:%d\r\n"), TotalTimeout));
while ( BufferLength ) {
DEBUGMSG (ZONE_USR_READ,
(TEXT("Top of Loop Fifo(R=%d,W=%d,L=%d,BA=%d)\r\n"),
RxRead(pSerialHead), RxWrite(pSerialHead),
RxLength(pSerialHead),
RxBytesAvail(pSerialHead)));
if ( RxBytesAvail(pSerialHead) ) {
RxEnterCS(pSerialHead);
// Copy the data over
// This only copies the continous portion, This will cause a loop
// if the receive data spans the end of the buffer.
Len = MIN(RxBytesAvail(pSerialHead),
RxLength(pSerialHead)-RxRead(pSerialHead));
Len = MIN(Len, BufferLength);
DEBUGMSG (ZONE_USR_READ, (TEXT("About to copy %d bytes\r\n"), Len));
memcpy (pTargetBuffer, RxBuffRead(pSerialHead), Len);
// Update Fifo info
RxRead(pSerialHead) += Len;
RxRead(pSerialHead) %= RxLength(pSerialHead);
// Update all the pointers.
BufferLength -= Len;
pTargetBuffer += Len;
BytesRead += Len;
RxLeaveCS(pSerialHead);
} else {
// Wait for a serial event?
if ( (IntervalTimeout == MAXDWORD) && (TotalTimeout == 0) ) {
// For some reason this means don't wait.
break;
}
if ( (IntervalTimeout == 0) && (TotalTimeout == 0) ) {
// Not completely clear but this could mean wait
// for ever
Timeout = INFINITE;
} else if ( TotalTimeout == 0 ) {
if ( !BytesRead ) {
// On first character we only use total timeout
Timeout = INFINITE;
} else {
// No total timeout in use. Just use interval timer
Timeout = IntervalTimeout;
}
} else {
// Total timeout is valid
if ( TimeSpent >= TotalTimeout ) {
// Timed out.
break;
}
Timeout = TotalTimeout - TimeSpent;
// On first byte we only use interval timeout
// on subsequent we use minimum of Interval and Timeout
if ( BytesRead && (IntervalTimeout != 0) ) {
Timeout = MIN(Timeout, IntervalTimeout);
}
// Yet another special case.
if ( BytesRead &&
(MAXDWORD == pSerialHead->CommTimeouts.ReadTotalTimeoutMultiplier) &&
(MAXDWORD == IntervalTimeout) ) {
// If Interval==MAXDWORD, Mult=MAXDWORD, 0<Const<MAXDWORD
// then return immediately if there is data.
// else wait up to Const time for data
break;
}
}
Ticks = GetTickCount();
DEBUGMSG (ZONE_USR_READ, (TEXT("About to wait %dms\r\n"), Timeout));
pSerialHead->fAbortRead = 0;
if ( WAIT_TIMEOUT == WaitForSingleObject (pSerialHead->hReadEvent,
Timeout) ) {
// Timeout
break;
}
// Since ticks is a ULONG this handles wrap.
Ticks = GetTickCount() - Ticks;
TimeSpent += Ticks;
// In the absense of WaitForMultipleObjects, we use flags to
// handle errors/aborts. Check for aborts or asynchronous closes.
if ( pSerialHead->fAbortRead ) {
DEBUGMSG(ZONE_USR_READ,(TEXT("COM_Read - Aborting read\r\n")));
break;
}
if ( !pSerialHead->OpenCnt ) {
DEBUGMSG(ZONE_USR_READ|ZONE_ERROR,
(TEXT("COM_Read - device was closed\n\r")));
SetLastError(ERROR_INVALID_HANDLE);
break;
}
}
// Are we below the SW flow control limits?
if ( pSerialHead->DCB.fInX && pSerialHead->SentXoff &&
(pSerialHead->DCB.XoffLim <
(RxLength(pSerialHead) - RxBytesAvail(pSerialHead))) ) {
PHWOBJ pHWObj = pSerialHead->pHWObj;
DEBUGMSG (ZONE_FLOW, (TEXT("Sending XON\r\n")));
pSerialHead->SentXoff = 0;
if ( !pSerialHead->DCB.fTXContinueOnXoff ) {
pSerialHead->StopXmit = 0;
}
pHWObj->pFuncTbl->HWXmitComChar(pSerialHead->pHWHead,
pSerialHead->DCB.XonChar);
}
// Are we below the HW flow control limits?
if ( 2*RxBytesAvail(pSerialHead) < RxLength(pSerialHead) ) {
// When buffer is less then 1/2 full we set RTS/DTR
if ( pSerialHead->RtsFlow &&
(pSerialHead->DCB.fRtsControl == RTS_CONTROL_HANDSHAKE) ) {
DEBUGMSG (ZONE_USR_READ|ZONE_FLOW,
(TEXT("RTS_CONTROL_HANDSHAKE Setting RTS\r\n")));
pSerialHead->RtsFlow = 0;
pFuncTbl->HWSetRTS(pHWHead);
}
if ( pSerialHead->DtrFlow &&
(pSerialHead->DCB.fDtrControl == DTR_CONTROL_HANDSHAKE) ) {
DEBUGMSG (ZONE_USR_READ|ZONE_FLOW,
(TEXT("DTR_CONTROL_HANDSHAKE Setting DTR\r\n")));
pSerialHead->DtrFlow = 0;
pFuncTbl->HWSetDTR(pHWHead);
}
}
}
DEBUGMSG (ZONE_USR_READ, (TEXT("ReceiveBytes exiting\r\n")));
LeaveCriticalSection(&(pSerialHead->ReceiveCritSec1));
DEBUGMSG (ZONE_USR_READ|ZONE_FUNCTION,
(TEXT("-COM_READ: returning %d (total %d, dropped %d,%d)\r\n"),
BytesRead, pSerialHead->RxBytes, pSerialHead->DroppedBytesMDD,pSerialHead->DroppedBytesPDD));
COM_DEC_USAGE_CNT(pOpenHead);
return(BytesRead);
}
/*
@doc EXTERNAL
@func ULONG | COM_Write | Allows application to transmit bytes to the serial port. Exported to users.
*
@rdesc It returns the number of bytes written or -1 if error.
*
*
*/
ULONG
COM_Write(HANDLE pHead, /*@parm [IN] HANDLE returned by COM_Open.*/
PUCHAR pSourceBytes, /*@parm [IN] Pointer to bytes to be written.*/
ULONG NumberOfBytes /*@parm [IN] Number of bytes to be written. */
)
{
PHW_OPEN_INFO pOpenHead = (PHW_OPEN_INFO)pHead;
PHW_INDEP_INFO pSerialHead = pOpenHead->pSerialHead;
ULONG BytesWritten = 0;
ULONG TotalWritten = 0;
PHWOBJ pHWObj = NULL;
PVOID pHWHead = NULL;
PHW_VTBL pFuncTbl = NULL;
ULONG TotalTimeout; // The Total Timeout
ULONG Timeout; // The Timeout value actually used
ULONG WaitReturn;
Sleep(10);
DEBUGMSG (ZONE_WRITE|ZONE_FUNCTION,
(TEXT("+COM_WRITE(0x%X, 0x%X, %d)\r\n"), pHead,
pSourceBytes, NumberOfBytes));
// Check validity of handle
if ( !pSerialHead || !pSerialHead->OpenCnt ) {
DEBUGMSG (ZONE_WRITE|ZONE_ERROR,
(TEXT("COM_WRITE, device not open\r\n") ));
SetLastError (ERROR_INVALID_HANDLE);
return(ULONG)-1;
}
// Make sure the caller has access permissions
if ( !(pOpenHead->AccessCode & GENERIC_WRITE) ) {
DEBUGMSG(ZONE_USR_READ|ZONE_ERROR,
(TEXT("COM_Write: Access permission failure x%X\n\r"),
pOpenHead->AccessCode));
SetLastError (ERROR_INVALID_ACCESS);
return(ULONG)-1;
}
#ifdef DEBUG
if ( IsBadReadPtr(pSourceBytes, NumberOfBytes) ) {
DEBUGMSG (ZONE_WRITE|ZONE_ERROR,
(TEXT("COM_WRITE, bad read pointer\r\n") ));
SetLastError(ERROR_INVALID_PARAMETER);
return(ULONG)-1;
}
#endif
COM_INC_USAGE_CNT(pOpenHead);
pHWObj = pSerialHead->pHWObj;
pHWHead = pSerialHead->pHWHead;
pFuncTbl = pHWObj->pFuncTbl;
pSerialHead->fAbortTransmit = 0;
// Clear any pending event
WaitForSingleObject(pSerialHead->hTransmitEvent,0);
/* Lock out other threads from messing with these pointers.
*/
DEBUGMSG (ZONE_WRITE, (TEXT("COM_Write wait for CritSec %x.\r\n"),
&(pSerialHead->TransmitCritSec1)));
EnterCriticalSection(&(pSerialHead->TransmitCritSec1));
DEBUGMSG (ZONE_WRITE, (TEXT("COM_Write Got Cr
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -