1204 lines
31 KiB
C++
1204 lines
31 KiB
C++
#include "stdafx.h"
|
|
|
|
#include <process.h>
|
|
|
|
#include "CMMIO_SERIAL.H "
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////
|
|
#define LONG_TIMEOUT 5000
|
|
|
|
/*
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Code - Text for debug window
|
|
static char Codes[][6] =
|
|
{
|
|
"<NUL>","<SOH>","<STX>","<ETX>","<EOT>","<ENQ>","<ACK>","<BEL>",
|
|
"<BS>","<HT>","<LF>","<VT>","<FF>","<CR>","<SO>","<SI>","<DLE>",
|
|
"<DC1>","<DC2>","<DC3>","<DC4>","<NAK>","<SYN>","<ETB>","<CAN>",
|
|
"<EM>","<SUB>","<ESC>","<FS>","<GS>","<RS>","<VS>"
|
|
};
|
|
*/
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CSerial() : Constructor
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CSerialTask() : Function to run ReceiveTask() method as a task
|
|
//
|
|
|
|
unsigned int WINAPI CSerialTask(LPVOID CSerialPtr)
|
|
{
|
|
TRACE( TEXT("Serial task has started \n") );
|
|
// Call the ControlTask function in the specified plugin
|
|
((CSerial *)CSerialPtr)->ReceiveTask();
|
|
|
|
TRACE( TEXT("Serial task has completed \n") );
|
|
|
|
_endthreadex(0);
|
|
|
|
return(0);
|
|
}
|
|
|
|
CSerial::CSerial()
|
|
{
|
|
// Serial port is not open
|
|
m_PortHandle = INVALID_HANDLE_VALUE;
|
|
|
|
// Default port settings
|
|
m_Port = 1;
|
|
m_Baud = CBR_115200;
|
|
m_Parity ='N';
|
|
m_Bits = 8;
|
|
m_StopBits = 1;
|
|
m_HandShake =CS_HANDSHAKE_FOR_SO7;
|
|
m_RXTimeout = CS_DEFAULT_RX_TIMEOUT;
|
|
m_TXTimeout = CS_DEFAULT_TX_TIMEOUT;
|
|
m_iRecvState=FALSE;
|
|
m_csRecv=_T("");
|
|
m_iRecvByte=0;
|
|
// Everything else set to NULL
|
|
m_ThreadHandle = NULL;
|
|
//m_TXHead = NULL;
|
|
//m_TXTail = NULL;
|
|
//m_RXHead = NULL;
|
|
//m_RXTail =NULL;
|
|
memset( &m_ReceiveOLap, 0, sizeof( OVERLAPPED ));
|
|
memset( &m_TransmitOLap, 0, sizeof( OVERLAPPED ));
|
|
memset( &m_ReadOLap, 0, sizeof( OVERLAPPED ));
|
|
memset( &m_WriteOLap, 0, sizeof( OVERLAPPED ));
|
|
|
|
m_hWaitCMMResponse = CreateEvent( NULL, TRUE, FALSE, NULL );
|
|
m_hNewRx = CreateEvent( NULL, TRUE, FALSE, NULL ); // to trigger OnRx
|
|
|
|
//m_RXTempPtr = NULL;
|
|
m_DebugInPtr = 0;
|
|
m_DebugCount = 0;
|
|
m_Item = 0;
|
|
m_MaxTXRetries = 5;
|
|
|
|
/*
|
|
// CriticalSection for locking lists
|
|
InitializeCriticalSection( &m_QueueLock );
|
|
InitializeCriticalSection( &m_WriteLock );
|
|
InitializeCriticalSection( &m_ReadLock );
|
|
*/
|
|
// IsValidBuffer = FALSE;
|
|
CurrentPointer = 0;
|
|
|
|
m_hWaitCMMResponse = CreateEvent( NULL, TRUE, FALSE, NULL );
|
|
m_hNewRx = CreateEvent( NULL, TRUE, FALSE, NULL ); // to trigger OnRx
|
|
// pParent = NULL;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// ~CSerial() : Destructor - Close the port and free up the CriticalSection
|
|
|
|
CSerial::~CSerial()
|
|
{
|
|
if( IsOpen( ) )
|
|
{
|
|
TRACE(TEXT("Warning : closing serial port in destructor\n"));
|
|
Close();
|
|
}
|
|
while(GetNextReceived())
|
|
; // mp 3/3/99 prevents leaks
|
|
/*
|
|
DeleteCriticalSection( &m_QueueLock );
|
|
DeleteCriticalSection( &m_ReadLock );
|
|
DeleteCriticalSection( &m_WriteLock );
|
|
*/
|
|
// close the overlapped io event
|
|
CloseHandle( m_ReadOLap.hEvent );
|
|
CloseHandle( m_WriteOLap.hEvent );
|
|
//
|
|
CloseHandle( m_hWaitCMMResponse );
|
|
CloseHandle( m_hNewRx);
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// OpenPort() : Opens the serial port using the parameters set by default
|
|
// or a call to SetPort
|
|
|
|
DWORD CSerial::Open()
|
|
{
|
|
CString PortName;
|
|
COMMTIMEOUTS CommTimeOut;
|
|
int Ok;
|
|
unsigned int ThreadID;
|
|
|
|
// Ensure the debug window is registered
|
|
// RegisterDebugWindow( );
|
|
|
|
// Close the port incase it is already open
|
|
Close( );
|
|
|
|
// Start of assuming the worst
|
|
Ok = FALSE;
|
|
|
|
// Format the file name and open it
|
|
// COM<number> opens ports from 1..9 for two-difit ports it's becessary to use \\\\.\\COM<num>
|
|
#if 0
|
|
PortName.Format( TEXT("\\\\.\\COM%d"), m_Port );
|
|
#else
|
|
PortName.Format( TEXT("COM%d"), m_Port );
|
|
#endif
|
|
m_PortHandle = CreateFile( PortName, GENERIC_WRITE | GENERIC_READ, 0, NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
|
|
NULL );
|
|
if( IsOpen( ) )
|
|
{
|
|
// Setup the port according to the stored parameters
|
|
if( ProgramPort( m_Port, m_Baud, m_Parity, m_Bits, m_StopBits, m_HandShake ) )
|
|
{
|
|
// Setup the timeouts
|
|
CommTimeOut.ReadIntervalTimeout = 25;
|
|
CommTimeOut.ReadTotalTimeoutMultiplier = 1;
|
|
CommTimeOut.ReadTotalTimeoutConstant = 0;
|
|
CommTimeOut.WriteTotalTimeoutMultiplier = 0;
|
|
CommTimeOut.WriteTotalTimeoutConstant = m_TXTimeout;
|
|
if( SetCommTimeouts( m_PortHandle, &CommTimeOut ) )
|
|
{
|
|
// Setup the buffer sizes
|
|
if( SetupComm( m_PortHandle, 2048, 2048 ) )
|
|
{
|
|
// Setup the event masks for the monitoring task
|
|
if( SetCommMask( m_PortHandle, EV_RXCHAR | EV_TXEMPTY | EV_BREAK |
|
|
EV_CTS | EV_DSR | EV_ERR | EV_RLSD ) )
|
|
{
|
|
// Initialise the Overlapping structures and start the
|
|
// monitoring task
|
|
m_ReceiveOLap.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
|
|
m_TransmitOLap.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
|
|
m_ThreadHandle = (HANDLE)_beginthreadex( NULL, 0, CSerialTask, this,
|
|
0, &ThreadID );
|
|
//Sleep(1000);
|
|
Ok = TRUE;
|
|
}
|
|
}
|
|
}
|
|
// clear msg waiting
|
|
m_iNbMsgWaiting = 0;
|
|
}
|
|
|
|
// Things have gone wrong so close the port
|
|
if( Ok == FALSE )
|
|
{
|
|
TRACE(_T("CmmIO> Port OPEN issue -> CLOSED\n"),Ok);
|
|
Close( );
|
|
}
|
|
}
|
|
TRACE(_T("CmmIO> Port OPEN = %d \n"),Ok);
|
|
// Return the state
|
|
return( IsOpen( ) );
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// IsOpen() : returns true if the serial port is open
|
|
//
|
|
|
|
int CSerial::IsOpen( )
|
|
{
|
|
return( m_PortHandle != INVALID_HANDLE_VALUE );
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// SetPort() : Store the serial settings. If the port is open then these
|
|
// settings are applied now
|
|
|
|
int CSerial::SetPort(int Port,int Baud,char Parity,int Bits,int StopBits,int HandShake)
|
|
{
|
|
// Use the current settings if the value has the default of 0
|
|
m_Port = Port;
|
|
if(Baud == 0)
|
|
Baud = m_Baud;
|
|
if(Parity == 0)
|
|
Parity = m_Parity;
|
|
if(Bits == 0)
|
|
Bits = m_Bits;
|
|
if(StopBits == 0)
|
|
StopBits = m_StopBits;
|
|
|
|
// If the values are ok then store them
|
|
if( ProgramPort( Port, Baud, Parity, Bits, StopBits, HandShake ) )
|
|
{
|
|
m_Port = Port;
|
|
m_Baud = Baud;
|
|
m_Parity = Parity;
|
|
m_Bits = Bits;
|
|
m_StopBits = StopBits;
|
|
m_HandShake = HandShake;
|
|
return(TRUE);
|
|
}
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// GetPortData() : return the current settings
|
|
//
|
|
|
|
void CSerial::GetPortData(int *Port,int *Baud,char *Parity,int *Bits,int *StopBits,int *HandShake)
|
|
{
|
|
// return the requested settings
|
|
if( Port )
|
|
*Port = m_Port;
|
|
if( m_Baud )
|
|
*Baud = m_Baud;
|
|
if( Parity )
|
|
*Parity = m_Parity;
|
|
if( Bits )
|
|
*Bits = m_Bits;
|
|
if( StopBits )
|
|
*StopBits = m_StopBits;
|
|
if( HandShake )
|
|
*HandShake = m_HandShake;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// ClosePort() : Close the port and shut down the monitoring thread
|
|
//
|
|
|
|
DWORD CSerial::Close()
|
|
{
|
|
//struct SerialList *Free;
|
|
HANDLE Port;
|
|
|
|
// If the port is open then close it
|
|
if( IsOpen( ) )
|
|
{
|
|
Port = m_PortHandle;
|
|
m_PortHandle = INVALID_HANDLE_VALUE;
|
|
CloseHandle( Port );
|
|
if( WaitForSingleObject( m_ThreadHandle, (5 * LONG_TIMEOUT) ) != WAIT_OBJECT_0 )
|
|
TRACE( TEXT("ERR:Serial port thread failed to terminate\n") );
|
|
m_ThreadHandle = NULL;
|
|
CloseHandle( m_ReceiveOLap.hEvent );
|
|
CloseHandle( m_TransmitOLap.hEvent );
|
|
}
|
|
|
|
CMMIO::Close();
|
|
//ZH
|
|
/*
|
|
// Delete the contents of the temp rx pointer if any
|
|
delete[] m_RXTempPtr;
|
|
m_RXTempPtr = NULL;
|
|
|
|
// Clear down all internal lists
|
|
EnterCriticalSection( &m_QueueLock );
|
|
while( m_RXHead )
|
|
{
|
|
Free = m_RXHead;
|
|
m_RXHead = m_RXHead->Next;
|
|
delete[] Free->Buffer;
|
|
delete Free;
|
|
}
|
|
m_RXHead = NULL;
|
|
while( m_TXHead )
|
|
{
|
|
Free = m_TXHead;
|
|
m_TXHead = m_TXHead->Next;
|
|
delete[] Free->Buffer;
|
|
delete Free;
|
|
}
|
|
m_TXHead = NULL;
|
|
|
|
LeaveCriticalSection( &m_QueueLock );
|
|
*/
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Send functions // [8/11/2004]
|
|
//
|
|
|
|
DWORD CSerial::Send(LPCSTR buffer, int l, BOOL /*needsResponse=FALSE*/)
|
|
{
|
|
|
|
return ( WritePort ((const char*) buffer, (DWORD) l));
|
|
}
|
|
/*
|
|
DWORD CSerial::Send(CString buffer)
|
|
{
|
|
char LocBuffer[MAX_OUTPUT_BUFFER_SIZE];
|
|
int length = buffer.GetLength ();
|
|
if (length >MAX_OUTPUT_BUFFER_SIZE)
|
|
{
|
|
length = MAX_OUTPUT_BUFFER_SIZE;
|
|
}
|
|
unsigned short* ptr = (unsigned short*)buffer.GetBuffer (MAX_OUTPUT_BUFFER_SIZE);
|
|
for (int i=0;i<length;i++)
|
|
{
|
|
LocBuffer[i] = (char)(ptr[i] & 0xff);
|
|
}
|
|
DWORD res = Send(LocBuffer,length);
|
|
return res;
|
|
}
|
|
*/
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// WritePort() : Writes the specifed bytes to the serial port
|
|
//
|
|
|
|
DWORD CSerial::WritePort(const char *Buffer,DWORD Bytes)
|
|
{
|
|
DWORD BytesWritten, TotalWritten, Error;
|
|
BOOL WriteState;
|
|
int Retrys;
|
|
|
|
TotalWritten=0;
|
|
|
|
// Check that the port is open
|
|
if( IsOpen( ) )
|
|
{
|
|
// Enter a critical section incase this is been used from multiple threads
|
|
//EnterCriticalSection(&m_WriteLock);
|
|
|
|
// The following retry loop is required because a TRACE output from NT running
|
|
// in remote debug mode will kill any tranmission on any serial port !!!!!!!
|
|
// don`t you just love NT.
|
|
Retrys = 0;
|
|
do
|
|
{
|
|
Retrys++;
|
|
BytesWritten = 0;
|
|
// Write the data
|
|
WriteState = WriteFile( m_PortHandle, &Buffer[TotalWritten],
|
|
Bytes-TotalWritten, &BytesWritten,
|
|
&m_WriteOLap );
|
|
if( !WriteState )
|
|
{
|
|
Sleep(50);
|
|
// Ensure the write is going on in the background
|
|
if( GetLastError() == ERROR_IO_PENDING )
|
|
{
|
|
// And wait for it to finish
|
|
WaitForSingleObject( m_WriteOLap.hEvent, LONG_TIMEOUT ); // GER
|
|
GetOverlappedResult( m_PortHandle, &m_WriteOLap, &BytesWritten,
|
|
FALSE );
|
|
}
|
|
else
|
|
{
|
|
// Gone wrong so clear any erros
|
|
ClearCommError( m_PortHandle, &Error, NULL );
|
|
BytesWritten= 0 ;
|
|
}
|
|
}
|
|
TotalWritten += BytesWritten;
|
|
|
|
}
|
|
while( Retrys <= m_MaxTXRetries && TotalWritten < Bytes );
|
|
|
|
//ZH
|
|
/*
|
|
// Written some bytes so add then to the debug list
|
|
if( BytesWritten )
|
|
AddToDebug( Buffer, BytesWritten, 2 );
|
|
*/
|
|
// Remember to leave the critical section
|
|
//LeaveCriticalSection( &m_WriteLock );
|
|
}
|
|
|
|
return( TotalWritten );
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// ReceiveTask() : Internal function, this runs as a thread and provides the
|
|
// OnRecieve and OnTransmit events
|
|
|
|
void CSerial::ReceiveTask( void )
|
|
{
|
|
//DWORD BytesWritten;
|
|
DWORD Events;
|
|
unsigned long State;
|
|
|
|
do
|
|
{
|
|
Events=0;
|
|
|
|
// Wait for a comm event
|
|
State=WaitCommEvent(m_PortHandle,&Events,&m_ReceiveOLap);
|
|
if(!State)
|
|
{
|
|
// Since we are using overlapping IO we may have to wait
|
|
// for the result
|
|
if(GetLastError() == ERROR_IO_PENDING)
|
|
GetOverlappedResult(m_PortHandle,&m_ReceiveOLap,&State,TRUE);
|
|
}
|
|
//m_iRecvState=FALSE;
|
|
// If we have a result then OK otherwise the event was probable
|
|
// the serial port being closed and we shall exit the loop
|
|
if( State && IsOpen( ) )
|
|
{
|
|
// Check the events and act accordingly
|
|
if( Events & EV_RXCHAR )
|
|
{
|
|
OnReceive( );
|
|
}
|
|
//ZH
|
|
/*
|
|
if( Events & EV_TXEMPTY )
|
|
{
|
|
if( m_TXHead )
|
|
{
|
|
GetOverlappedResult(m_PortHandle,&m_TransmitOLap,&BytesWritten,TRUE);
|
|
if( BytesWritten )
|
|
AddToDebug( m_TXHead->Buffer, BytesWritten, 2 );
|
|
OnTransmit( 0, BytesWritten );
|
|
SendBuffer(TRUE);
|
|
}
|
|
}
|
|
*/
|
|
if(Events & EV_BREAK)
|
|
TRACE(_T("Break detected\n"));
|
|
if(Events & EV_CTS)
|
|
TRACE(_T("CTS Changed State\n"));
|
|
if(Events & EV_DSR)
|
|
TRACE(_T("DSR Changed State\n"));
|
|
if(Events & EV_ERR)
|
|
TRACE(_T("Line error\n"));
|
|
if(Events & EV_RLSD)
|
|
TRACE(_T("EV_RLSD error\n"));
|
|
}
|
|
|
|
// Go round while the port is open
|
|
}
|
|
while( IsOpen( ) );
|
|
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// OnReceive() : Default OnReceive()
|
|
// V114
|
|
|
|
void CSerial::OnReceive()
|
|
{
|
|
// Dummy OnReceieve if not used
|
|
char s[255]={0};
|
|
CStringA csTemp;
|
|
s[1]='\0';
|
|
CurrentPointer = 0;
|
|
int num=0;
|
|
|
|
num = ReadPort(s, 255);
|
|
//for (int i=0;i<num;i++)
|
|
//{
|
|
// csTemp
|
|
// m_csRecv+=csTemp;
|
|
//}
|
|
|
|
if (num!=0)
|
|
{
|
|
csTemp.Format("%s",s);
|
|
m_csRecv=csTemp;
|
|
m_iRecvByte=num;
|
|
m_iRecvState=TRUE;
|
|
}
|
|
|
|
//LineReceive(s, num);
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// ReadPort() : Read the specifed number of bytes.
|
|
//
|
|
|
|
DWORD CSerial::ReadPort(char *Buffer,DWORD Bytes)
|
|
{
|
|
DWORD BytesRead,Error;
|
|
BOOL ReadState;
|
|
|
|
BytesRead = 0;
|
|
// Check the port is open
|
|
if( IsOpen( ) )
|
|
{
|
|
// Enter a critical section incase this is been used from multiple threads
|
|
// EnterCriticalSection(&m_ReadLock);
|
|
// Start the read
|
|
ReadState = ReadFile(m_PortHandle,Buffer,Bytes,&BytesRead,&m_ReadOLap);
|
|
if( !ReadState )
|
|
{
|
|
Sleep(50);
|
|
// the specifed number of bytes were not available so
|
|
// the read will continue in the background aslong as
|
|
// GetLastError() returns ERROR_IO_PENDING
|
|
if( GetLastError() == ERROR_IO_PENDING )
|
|
{
|
|
// Wait for the read to complete
|
|
WaitForSingleObject( m_ReadOLap.hEvent, LONG_TIMEOUT ); // GER
|
|
|
|
// get the result of the read
|
|
if( GetOverlappedResult( m_PortHandle, &m_ReadOLap, &BytesRead, FALSE ) == 0 )
|
|
Error = GetLastError();
|
|
}
|
|
else
|
|
{
|
|
// Gone wrong so clear any erros
|
|
ClearCommError( m_PortHandle, &Error, NULL );
|
|
BytesRead = 0 ;
|
|
}
|
|
}
|
|
|
|
//ZH
|
|
/*
|
|
// Read some bytes so add then to the debug list
|
|
if( BytesRead )
|
|
AddToDebug( Buffer, BytesRead, 1 );
|
|
*/
|
|
// LeaveCriticalSection( &m_ReadLock );
|
|
}
|
|
|
|
return(BytesRead);
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// ReadPort() : Read the specifed number of bytes into a CString class.
|
|
//
|
|
#if 0
|
|
DWORD CSerial::ReadPort(CString &Buffer,DWORD Bytes)
|
|
{
|
|
DWORD BytesRead;
|
|
|
|
USES_CONVERSION;
|
|
BytesRead = ReadPort( T2A(Buffer.GetBuffer( Bytes + 1 )), Bytes );
|
|
Buffer.ReleaseBuffer( );
|
|
|
|
return(BytesRead);
|
|
}
|
|
#endif
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// ProgramPort() : Internal function to setup the serial port
|
|
//
|
|
|
|
int CSerial::ProgramPort(int Port,int Baud,char Parity,int Bits,int StopBits,int HandShake)
|
|
{
|
|
CString Param,Params;
|
|
DCB SerialDCB;
|
|
int Ok;
|
|
|
|
// Build up the serial port settings
|
|
Params.Format( TEXT("com%d"), Port );
|
|
Param.Format( TEXT(" baud=%d"), Baud );
|
|
Params += Param;
|
|
Param.Format( TEXT(" parity=%c"), Parity );
|
|
Params += Param;
|
|
Param.Format( TEXT(" data=%d"), Bits );
|
|
Params += Param;
|
|
Param.Format( TEXT(" stop=%d"), StopBits );
|
|
Params += Param;
|
|
Ok = FALSE;
|
|
memset( (void *)&SerialDCB, 0, sizeof(SerialDCB) );
|
|
SerialDCB.DCBlength = sizeof(SerialDCB);
|
|
|
|
// Place them in the DCB structure, this also validates them if the
|
|
// serial port is not open
|
|
if( BuildCommDCB( Params, &SerialDCB ) )
|
|
{
|
|
// If the port is open
|
|
if( IsOpen( ) )
|
|
{
|
|
// Set the handshake bits
|
|
switch(HandShake)
|
|
{
|
|
case CS_HANDSHAKE_RTSCTS:
|
|
SerialDCB.fOutxCtsFlow = TRUE;
|
|
SerialDCB.fRtsControl = RTS_CONTROL_HANDSHAKE;
|
|
SerialDCB.fDtrControl = DTR_CONTROL_ENABLE;
|
|
break;
|
|
case CS_HANDSHAKE_RTSCTS_DTRDSR:
|
|
SerialDCB.fOutxCtsFlow = TRUE;
|
|
SerialDCB.fRtsControl = RTS_CONTROL_HANDSHAKE;
|
|
SerialDCB.fOutxDsrFlow = TRUE;
|
|
SerialDCB.fDtrControl = DTR_CONTROL_HANDSHAKE;
|
|
break;
|
|
case CS_HANDSHAKE_XONXOFF:
|
|
SerialDCB.fOutX = TRUE;
|
|
SerialDCB.fInX = TRUE;
|
|
SerialDCB.XonChar = 17;
|
|
SerialDCB.XoffChar = 19;
|
|
SerialDCB.fRtsControl = RTS_CONTROL_DISABLE;
|
|
SerialDCB.fDtrControl = DTR_CONTROL_DISABLE;
|
|
break;
|
|
case CS_HANDSHAKE_NONE:
|
|
SerialDCB.fRtsControl = RTS_CONTROL_ENABLE;
|
|
SerialDCB.fDtrControl = DTR_CONTROL_ENABLE;
|
|
break;
|
|
case CS_HANDSHAKE_FOR_SO7:
|
|
SerialDCB.XonChar = 17;
|
|
SerialDCB.XoffChar = 19;
|
|
SerialDCB.fRtsControl = RTS_CONTROL_DISABLE;
|
|
SerialDCB.fDtrControl = DTR_CONTROL_DISABLE;
|
|
SerialDCB.fDsrSensitivity=FALSE;
|
|
SerialDCB.XonLim=512;
|
|
SerialDCB.XoffLim=1;
|
|
break;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// Finally apply the params to the port
|
|
if(SetCommState( m_PortHandle, &SerialDCB ) )
|
|
{
|
|
Ok = TRUE;
|
|
}
|
|
else
|
|
{
|
|
GetCommState(m_PortHandle, &SerialDCB);
|
|
SerialDCB.BaudRate = Baud; // set the baud rate
|
|
SerialDCB.ByteSize = (BYTE)Bits; // data size, xmit, and rcv
|
|
SerialDCB.StopBits = (BYTE)StopBits; // one stop bit
|
|
switch(Parity)
|
|
{
|
|
case 'O':
|
|
case 'o':
|
|
SerialDCB.Parity = ODDPARITY; // odd parity bit
|
|
break;
|
|
case 'E':
|
|
case 'e':
|
|
SerialDCB.Parity = EVENPARITY; // even parity bit
|
|
break;
|
|
default:
|
|
SerialDCB.Parity = NOPARITY; // no parity bit
|
|
break;
|
|
|
|
}
|
|
// Set the handshake bits
|
|
switch(HandShake)
|
|
{
|
|
case CS_HANDSHAKE_RTSCTS:
|
|
SerialDCB.fOutxCtsFlow = TRUE;
|
|
SerialDCB.fRtsControl = RTS_CONTROL_HANDSHAKE;
|
|
SerialDCB.fDtrControl = DTR_CONTROL_ENABLE;
|
|
break;
|
|
case CS_HANDSHAKE_XONXOFF:
|
|
SerialDCB.fOutX = TRUE;
|
|
SerialDCB.fInX = TRUE;
|
|
SerialDCB.XonChar = 17;
|
|
SerialDCB.XoffChar = 19;
|
|
SerialDCB.fRtsControl = RTS_CONTROL_DISABLE;
|
|
SerialDCB.fDtrControl = DTR_CONTROL_DISABLE;
|
|
break;
|
|
case CS_HANDSHAKE_NONE:
|
|
SerialDCB.fRtsControl = RTS_CONTROL_ENABLE;
|
|
SerialDCB.fDtrControl = DTR_CONTROL_ENABLE;
|
|
break;
|
|
case CS_HANDSHAKE_FOR_SO7:
|
|
SerialDCB.XonChar = 17;
|
|
SerialDCB.XoffChar = 19;
|
|
SerialDCB.fRtsControl = RTS_CONTROL_DISABLE;
|
|
SerialDCB.fDtrControl = DTR_CONTROL_DISABLE;
|
|
SerialDCB.fDsrSensitivity=FALSE;
|
|
SerialDCB.XonLim=512;
|
|
SerialDCB.XoffLim=1;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// Finally apply the params to the port
|
|
if(SetCommState( m_PortHandle, &SerialDCB ) )
|
|
{
|
|
Ok = TRUE;
|
|
}
|
|
}
|
|
TRACE(_T("CmmIO> Port was OPEN, ProgramPort done \n"));
|
|
}
|
|
else
|
|
{
|
|
TRACE(_T("CmmIO> Port was not OPEN ProgramPort not done \n"));
|
|
Ok = TRUE;
|
|
}
|
|
}
|
|
return(Ok);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// OnTransmit() : Default OnTransmit()
|
|
//
|
|
|
|
void CSerial::OnTransmit(int /*Item*/, DWORD /*Error*/)
|
|
{
|
|
// Dummy OnTransmit if not used
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// SetTimeouts() : Sets the rx and tx timeouts
|
|
//
|
|
|
|
void CSerial::SetTimeouts( int RXTimeout, int TXTimeout )
|
|
{
|
|
COMMTIMEOUTS CommTimeOut;
|
|
|
|
// Store the timeouts
|
|
m_RXTimeout = RXTimeout;
|
|
m_TXTimeout = TXTimeout;
|
|
|
|
// If the port is open then configure the port also
|
|
// Currently we only use the Fixed timeouts
|
|
if( IsOpen( ) )
|
|
{
|
|
CommTimeOut.ReadIntervalTimeout = 25;
|
|
CommTimeOut.ReadTotalTimeoutMultiplier = 1;
|
|
CommTimeOut.ReadTotalTimeoutConstant = 0;
|
|
CommTimeOut.WriteTotalTimeoutMultiplier = 0;
|
|
CommTimeOut.WriteTotalTimeoutConstant = m_TXTimeout;
|
|
SetCommTimeouts( m_PortHandle, &CommTimeOut );
|
|
}
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// AddToDebug() : Add the data to the debug output. State is 1 = rx 2 = tx
|
|
// 3 = user
|
|
|
|
void CSerial::AddToDebug( const char * /*Ptr*/, DWORD /*BytesToCopy*/, int /*State*/ )
|
|
{
|
|
//ZH
|
|
#if 0
|
|
// We are messing with pointers so use the CriticalSection
|
|
EnterCriticalSection(&m_QueueLock);
|
|
|
|
// If ptr = NULL the change to string containing <NULL>
|
|
if( Ptr == NULL )
|
|
{
|
|
BytesToCopy = 0;
|
|
//Ptr = _T("<NULL>");
|
|
Ptr = "<NULL>";
|
|
}
|
|
|
|
// If zero length then use length of string instead
|
|
if( BytesToCopy == 0)
|
|
BytesToCopy = strlen( Ptr );
|
|
|
|
// If length of data is greater then the debug buffer then just
|
|
// use the end of the data
|
|
if(BytesToCopy > CS_DEBUG_SIZE)
|
|
{
|
|
Ptr += BytesToCopy - CS_DEBUG_SIZE;
|
|
BytesToCopy = CS_DEBUG_SIZE;
|
|
}
|
|
|
|
// If the data will wrap around then just copy the first block
|
|
if( ( m_DebugInPtr + BytesToCopy ) > CS_DEBUG_SIZE)
|
|
{
|
|
// Copy data to the end of the debug buffer
|
|
memcpy(m_DebugData + m_DebugInPtr, Ptr, CS_DEBUG_SIZE - m_DebugInPtr);
|
|
memset(m_DebugState + m_DebugInPtr, State, CS_DEBUG_SIZE - m_DebugInPtr);
|
|
m_DebugWnd.AddData( m_DebugData + m_DebugInPtr,
|
|
m_DebugState + m_DebugInPtr,
|
|
CS_DEBUG_SIZE - m_DebugInPtr );
|
|
|
|
// Move on by the amount copied
|
|
Ptr += CS_DEBUG_SIZE - m_DebugInPtr;
|
|
BytesToCopy -= CS_DEBUG_SIZE - m_DebugInPtr;
|
|
|
|
// Point at the begining of the buffer
|
|
m_DebugInPtr = 0;
|
|
}
|
|
|
|
// Copy the rest into the buffer
|
|
memcpy(m_DebugData + m_DebugInPtr, Ptr, BytesToCopy);
|
|
memset(m_DebugState + m_DebugInPtr, State, BytesToCopy);
|
|
m_DebugWnd.AddData( m_DebugData + m_DebugInPtr,
|
|
m_DebugState + m_DebugInPtr, BytesToCopy );
|
|
m_DebugInPtr += BytesToCopy;
|
|
m_DebugCount += BytesToCopy;
|
|
|
|
// Keep a count of howmany bytes are in the buffer
|
|
if( m_DebugCount > CS_DEBUG_SIZE )
|
|
m_DebugCount = CS_DEBUG_SIZE;
|
|
|
|
// All done so out of the CriticalSection
|
|
LeaveCriticalSection(&m_QueueLock);
|
|
#endif
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// FlushPort() : Removes all characters in the serial buffer
|
|
//
|
|
/*
|
|
int CSerial::FlushPort(void)
|
|
{
|
|
int TXTimeout,RXTimeout;
|
|
char FlushBuffer[256];
|
|
DWORD BytesRead,BytesTotal;
|
|
struct SerialList *Free;
|
|
|
|
if( IsOpen( ) )
|
|
{
|
|
// We are messing with pointers so use the CriticalSection
|
|
EnterCriticalSection(&m_QueueLock);
|
|
|
|
// Make a copy of the timeouts and set back to the defaults
|
|
RXTimeout = m_RXTimeout;
|
|
TXTimeout = m_TXTimeout;
|
|
SetTimeouts( 10, 10 );
|
|
|
|
// Read all data from the port
|
|
BytesTotal=0;
|
|
while( ( BytesRead = ReadPort( FlushBuffer, 256 ) ) == 256 )
|
|
BytesTotal+=BytesRead;
|
|
BytesTotal+=BytesRead;
|
|
|
|
// Clear the Received list
|
|
while(m_RXHead)
|
|
{
|
|
Free=m_RXHead;
|
|
m_RXHead=m_RXHead->Next;
|
|
delete[] Free->Buffer;
|
|
delete Free;
|
|
}
|
|
|
|
// put the timeouts back
|
|
SetTimeouts( RXTimeout, TXTimeout );
|
|
|
|
m_iNbMsgWaiting = 0;
|
|
|
|
// All done so out of the CriticalSection
|
|
LeaveCriticalSection(&m_QueueLock);
|
|
}
|
|
return(BytesTotal);
|
|
}
|
|
*/
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// MaxPort() :
|
|
//
|
|
|
|
int CSerial::MaxPort()
|
|
{
|
|
// return the max port, :-)
|
|
return(8);
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Transmit() : Adds data into a list to be transmitted when possible.
|
|
// the function OnTransmit() will be called for each block of
|
|
// data sent.
|
|
//
|
|
|
|
int CSerial::Transmit(const char * /*Buffer*/,DWORD /*Bytes*/)
|
|
{
|
|
/*
|
|
struct SerialList *Ptr;
|
|
int Start;
|
|
|
|
// Is the port open
|
|
if( IsOpen( ) )
|
|
{
|
|
TRACE(_T("CmmIo> Port OPEN ... transmitting %d bytes \n"),Bytes);
|
|
// Yes so CriticalSection again
|
|
EnterCriticalSection(&m_QueueLock);
|
|
// Create a new list entry structure for the block of data
|
|
Ptr = new struct SerialList;
|
|
Ptr->Buffer = new char[Bytes];
|
|
Ptr->Bytes = Bytes;
|
|
Ptr->Next = NULL;
|
|
Ptr->Item = m_Item++;
|
|
if(Ptr->Item == 0 )
|
|
Ptr->Item = m_Item++;
|
|
memcpy( Ptr->Buffer, Buffer, Bytes );
|
|
|
|
// Add it into the list
|
|
if( m_TXTail )
|
|
{
|
|
Start = FALSE;
|
|
m_TXTail->Next = Ptr;
|
|
}
|
|
else
|
|
{
|
|
Start = TRUE;
|
|
m_TXHead = Ptr;
|
|
}
|
|
m_TXTail = Ptr;
|
|
|
|
// If the list was empty then start sending the data, otherwise
|
|
// it will be sentout when the previous data has been sent
|
|
if(Start)
|
|
SendBuffer(FALSE);
|
|
|
|
// All done so out of the CriticalSection
|
|
LeaveCriticalSection(&m_QueueLock);
|
|
|
|
//return the ID for this block
|
|
return( Ptr->Item );
|
|
}
|
|
else{
|
|
TRACE(_T("CmmIo> Port NOT OPEN ... FAILED TO TRANSMIT %d bytes \n"),Bytes);
|
|
}
|
|
*/
|
|
|
|
return(0);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// AddReceived() : Helper function, this adds a block of data to a list which
|
|
// read back by GetNextReceived()
|
|
//
|
|
|
|
/*
|
|
int CSerial::AddReceived( const char *Buffer,DWORD Bytes)
|
|
{
|
|
DWORD index = 0; //primary buffer index
|
|
struct SerialList *Ptr;
|
|
static char Buffer2[1000]; // result buffer
|
|
static char* pBuffer2 = &Buffer2[0];
|
|
unsigned char c;
|
|
bool bArmed;
|
|
int count;
|
|
static int escape = 0;
|
|
static int tilde = 0;
|
|
static int tildeseqcount = 0;
|
|
|
|
bool bDone = false;
|
|
bool bEventRequest = false;
|
|
|
|
// ATLTRACE("AddReceived> pBuffer2 = %x\n",pBuffer2);
|
|
// ATLTRACE("Content %s\n",Buffer);
|
|
if (Bytes==0){
|
|
// TRACE("CMMIO> Exiting , no real input");
|
|
return TRUE;
|
|
}
|
|
do {
|
|
bArmed = false;
|
|
for (;index<Bytes;index++){
|
|
c=Buffer[index] & 0xff;
|
|
//ATLTRACE("== %02x% ==\n",c); //copy char one by one
|
|
if ((c!='\r') && (c!='\n') && bArmed){ // out of CR/LF sequence...
|
|
break;
|
|
}
|
|
else if((c=='\r') || (c=='\n') || (c < 32)){ // Don't work with unprintable characters line 0 -GER
|
|
if (index !=0) bArmed = true;// don't make an empty record if LF is first char !
|
|
// but still skip it
|
|
}
|
|
else {
|
|
*(pBuffer2++) = c ; //copy char one by one
|
|
//new
|
|
if (tilde){
|
|
if(++tildeseqcount == 2) bArmed = true;
|
|
}
|
|
if (escape ==1){
|
|
if(c!='z' && c!='O')bArmed = true; //not a CLP or PRB
|
|
else escape = 0; // reset if part of POS / POINT Msg
|
|
}
|
|
///n
|
|
}
|
|
|
|
if( c>0x80 ){
|
|
++ escape; // max will be 1
|
|
// ATLTRACE(" ESCAPE ___>> %d\n",escape);
|
|
}
|
|
|
|
if( c=='~' ){
|
|
++ tilde; // max = 1
|
|
// ATLTRACE(" TILDE ESC___>> %d\n",tilde);
|
|
}
|
|
|
|
}
|
|
if (index == Bytes) bDone=true;
|
|
// else TRACE("\nCMMIO> (Serial)Splitting received stream....\n");
|
|
|
|
// We are messing with pointers so use the CriticalSection
|
|
if (bArmed ){
|
|
EnterCriticalSection(&m_QueueLock);
|
|
//Allocate a new list and add it in
|
|
count = pBuffer2-(&Buffer2[0]);
|
|
Ptr = new struct SerialList;
|
|
Ptr->Buffer = new char[count + 1 ];
|
|
Ptr->Bytes = count;
|
|
Ptr->Next = NULL;
|
|
memcpy( Ptr->Buffer, Buffer2, count );
|
|
Ptr->Buffer[count] = 0;
|
|
|
|
memcpy(m_sLastMessage,Buffer2,count); //copy to last message
|
|
m_sLastMessage[count]=0;
|
|
|
|
if( m_RXTail )
|
|
m_RXTail->Next = Ptr;
|
|
else
|
|
m_RXHead = Ptr;
|
|
m_RXTail = Ptr;
|
|
|
|
// All done so out of the CriticalSection
|
|
++m_iNbMsgWaiting;
|
|
LeaveCriticalSection( &m_QueueLock );
|
|
pBuffer2=&Buffer2[0]; // reset out buffer
|
|
count = 0;
|
|
escape = 0;
|
|
//new
|
|
tilde = 0;
|
|
tildeseqcount = 0;
|
|
///n
|
|
|
|
bEventRequest = true;
|
|
}
|
|
} while (!bDone);
|
|
// ATLTRACE ("CMMIO> Done\n");
|
|
|
|
//ZH
|
|
#if 0
|
|
if(bEventRequest){
|
|
if (!(pParent->m_bNoFireEvent)) {
|
|
// ATLTRACE("CmmIO Serial> Setting Event m_hNewRx \n");
|
|
SetEvent(m_hNewRx);// tell the system to fire event if needed...
|
|
}
|
|
else {
|
|
// ATLTRACE("CmmIO Serial> Setting Event pParent->m_hCmmResponded \n");
|
|
// SetEvent(pParent->m_hCmmResponded);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// if(bEventRequest){
|
|
// if (pParent){
|
|
// SetEvent(pParent->m_hCmmResponded);
|
|
// }
|
|
// }
|
|
|
|
// else ATLTRACE("--- AddReceived> Leaving with part of msg in buffer, pBuffer2= %x\n",pBuffer2);
|
|
return(TRUE);
|
|
}
|
|
*/
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// GetNextReceived() : Helper function, receives messages placed in the queue
|
|
// by AddReceievd()
|
|
//
|
|
//ZH
|
|
/*
|
|
char *CSerial::GetNextReceived(void)
|
|
{
|
|
struct SerialList *Free;
|
|
|
|
// If there is a previous block then delete it
|
|
delete[] m_RXTempPtr;
|
|
m_RXTempPtr = NULL;
|
|
|
|
// We are messing with pointers so use the CriticalSection
|
|
EnterCriticalSection(&m_QueueLock);
|
|
|
|
// If there any more to return
|
|
if( m_RXHead )
|
|
{
|
|
Free = m_RXHead;
|
|
m_RXHead = m_RXHead->Next;
|
|
|
|
// Point the temp pointer at the block
|
|
m_RXTempPtr = Free->Buffer;
|
|
|
|
// delete the list entry
|
|
delete Free;
|
|
--m_iNbMsgWaiting; // mp
|
|
}
|
|
if( m_RXHead == NULL )
|
|
m_RXTail = NULL;
|
|
|
|
// All done so out of the CriticalSection
|
|
LeaveCriticalSection( &m_QueueLock );
|
|
|
|
return( m_RXTempPtr );
|
|
}
|
|
*/
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// HexToInt() : Helper function, converts the specifed number of bytes from
|
|
// ascii hex
|
|
//
|
|
|
|
int CSerial::HexToInt(char *Data, int Bytes)
|
|
{
|
|
int Byte;
|
|
int HexChar, Value;
|
|
|
|
Value = 0;
|
|
for( Byte = 0; Byte < Bytes; Byte++ )
|
|
{
|
|
Value <<= 4;
|
|
HexChar = *Data++ -= '0';
|
|
if( HexChar > 32 )
|
|
HexChar -= 39;
|
|
else if( HexChar > 9 )
|
|
HexChar -= 7;
|
|
Value += HexChar;
|
|
}
|
|
|
|
return( Value );
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Private functions
|
|
//
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// RegisterDebugWindow() : Registers the window class for the debug window.
|
|
//
|
|
//ZH
|
|
/*
|
|
void CSerial::RegisterDebugWindow()
|
|
{
|
|
// Register the CSerialRaw window for future use
|
|
WNDCLASS wndcls;
|
|
memset( &wndcls, 0, sizeof( WNDCLASS ) );
|
|
wndcls.lpfnWndProc = DefWindowProc;
|
|
wndcls.hInstance = AfxGetInstanceHandle( );
|
|
wndcls.hCursor = LoadCursor( NULL, IDC_ARROW );
|
|
wndcls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
|
|
wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
|
|
wndcls.lpszClassName = TEXT("CSerial");
|
|
AfxRegisterClass( &wndcls );
|
|
}
|
|
*/
|
|
|
|
|
|
|
|
#if 0
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// SendBuffer() : Internal function, this writes the next block of data
|
|
// queued to the serial port.
|
|
|
|
void CSerial::SendBuffer(int Next)
|
|
{
|
|
struct SerialList *Free;
|
|
// DWORD BytesWritten;
|
|
|
|
// We are messing with pointers so use the CriticalSection
|
|
EnterCriticalSection(&m_QueueLock);
|
|
|
|
// If we been told to go the next then do it
|
|
if(Next && m_TXHead)
|
|
{
|
|
Free=m_TXHead;
|
|
m_TXHead=m_TXHead->Next;
|
|
delete[] Free->Buffer;
|
|
delete Free;
|
|
|
|
}
|
|
|
|
// If there is still some data then send it
|
|
if(m_TXHead)
|
|
// WriteFile(m_PortHandle,m_TXHead->Buffer,m_TXHead->Bytes,&BytesWritten,&m_TransmitOLap);
|
|
WritePort(m_TXHead->Buffer,m_TXHead->Bytes);
|
|
else
|
|
m_TXTail=NULL;
|
|
|
|
// All done so out of the CriticalSection
|
|
LeaveCriticalSection(&m_QueueLock);
|
|
}
|
|
#endif
|