#include "../stdafx.h" #include #include "CMMIO_SERIAL.H " #include using namespace std; ////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////// #define LONG_TIMEOUT 5000 #define MAXBLOCK 4096 /* ///////////////////////////////////////////////////////////////////////////// // Code - Text for debug window static char Codes[][6] = { "","","","","","","","", "","","","","","","","","", "","","","","","","","", "","","","","","","" }; */ ///////////////////////////////////////////////////////////////////////////// // CPSerial() : 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 static_cast(CSerialPtr)->ReceiveTask(); TRACE(TEXT("Serial task has completed \n")); _endthreadex(0); return (0); } CPSerial::CPSerial() { // Serial port is not open m_PortHandle = INVALID_HANDLE_VALUE; m_IsWrtingData = FALSE; // 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_iRecvBytes = 0; memset(m_RecvData, 0,MAX_RECIEVE_BUFFER_SIZE); // Everything else set to NULL m_ThreadHandle = nullptr; //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)); //1、CreateEvent 创建事件。 //函数原型如下所示,一共四个参数: //HANDLE CreateEvent( // LPSECURITY_ATTRIBUTES lpEventAttributes, // SECURITY_ATTRIBUTES结构指针,可为NULL // BOOL bManualReset, // 手动/自动 // // TRUE:表示手动,在WaitForSingleObject后必须手动调用ResetEvent清除信号 // // FALSE:表示自动,在WaitForSingleObject后,系统自动清除事件信号 // BOOL bInitialState, //初始状态,FALSE为无信号,TRUE为有信号 // LPCTSTR lpName //事件的名称 //); //2、SetEvent:设置为激活触发状态。 //3、ResetEvent:设置为未激活触发状态。 //4、WaitForSingleObject:检测信号,如果未激活,代码就会处于挂起状态,不再往下执行。 //———————————————— //版权声明:本文为CSDN博主「AI浩」的原创文章,遵循CC 4.0 BY - SA版权协议,转载请附上原文出处链接及本声明。 //原文链接:https ://blog.csdn.net/hhhhhhhhhhwwwwwwwwww/article/details/108380956 m_hWaitCMMResponse = CreateEvent(nullptr, TRUE, FALSE, nullptr); m_hNewRx = CreateEvent(nullptr, TRUE, FALSE, nullptr); // to trigger OnRx m_ReadOLap.hEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr); //m_RXTempPtr = NULL; m_DebugInPtr = 0; m_DebugCount = 0; m_Item = 0; m_MaxTXRetries = 5; m_iRecvCount = 252; /* // CriticalSection for locking lists InitializeCriticalSection( &m_QueueLock ); InitializeCriticalSection( &m_WriteLock ); InitializeCriticalSection( &m_ReadLock ); */ // IsValidBuffer = FALSE; CurrentPointer = 0; m_hWaitCMMResponse = CreateEvent(nullptr, TRUE, FALSE, nullptr); m_hNewRx = CreateEvent(nullptr, TRUE, FALSE, nullptr); // to trigger OnRx // pParent = NULL; } ///////////////////////////////////////////////////////////////////////////// // ~CPSerial() : Destructor - Close the port and free up the CriticalSection CPSerial::~CPSerial() { 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 CPSerial::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 opens ports from 1..9 for two-difit ports it's becessary to use \\\\.\\COM #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, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, nullptr); if (IsOpen()) { // Setup the port according to the stored parameters if (ProgramPort(m_Port, m_Baud, m_Parity, m_Bits, m_StopBits, m_HandShake)) { TRACE(_T("CmmIO> Port OPEN %s, m_Baud\n", m_Port, m_Baud), Ok); //printf("m_Baud: %d\n", m_Baud); // Setup the timeouts CommTimeOut.ReadIntervalTimeout = 25; CommTimeOut.ReadTotalTimeoutMultiplier = 1; CommTimeOut.ReadTotalTimeoutConstant = 1; CommTimeOut.WriteTotalTimeoutMultiplier = 1; 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 // 设置你关心的事件, 当此事件发生时, 将得到事件通知, 通过SetCommMask函数设置, SetCommMask函数两个参数, 第一个为串口句柄, 第二个为事件, 可通过位或的方式指定多个事件,如下: // BOOL WINAPI SetCommMask( // __in HANDLE hFile, // __in DWORD dwEvtMask); //示例代码: // SetCommMask(m_hCom, EV_RXCHAR); // EV_RXCHAR事件指当输入缓冲区内有数据时, 通过WaitCommEvent函数可获得通知, 其他事件同理, 其他事件还有EV_BREAK / EV_CTS / EV_RING等, if (SetCommMask(m_PortHandle, EV_RXCHAR | EV_TXEMPTY | EV_BREAK | EV_CTS | EV_DSR | EV_ERR | EV_RLSD)) { // Initialize the Overlapping structures and start the // monitoring task m_ReceiveOLap.hEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr); m_TransmitOLap.hEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr); m_ThreadHandle = (HANDLE)_beginthreadex(nullptr, 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 CPSerial::IsOpen() { return (m_PortHandle != INVALID_HANDLE_VALUE); } ///////////////////////////////////////////////////////////////////////////// // SetPort() : Store the serial settings. If the port is open then these // settings are applied now int CPSerial::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 (HandShake == 0) HandShake = m_HandShake; // 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 CPSerial::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; } DWORD CPSerial::SendWriteFile(const char* Buffer, DWORD Bytes) { DWORD BytesWritten; BOOL WriteState; WriteState = WriteFile(m_PortHandle, &Buffer[0], Bytes, &BytesWritten, &m_WriteOLap); return WriteState; } ///////////////////////////////////////////////////////////////////////////// // ClosePort() : Close the port and shut down the monitoring thread // DWORD CPSerial::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 = nullptr; 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 CPSerial::Send(LPCSTR buffer, int l, BOOL /*needsResponse=FALSE*/) { m_IsWrtingData = TRUE; return (WritePort(buffer, static_cast(l))); } /* DWORD CPSerial::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 0) { //PURGE_TXABORT | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_RXCLEAR //分别表示: //立即中断写操作并清空输出缓冲区 | 清空输出缓冲区 | 立即中断读操作并清空输入缓冲区 | 清空输入缓冲区 PurgeComm(m_PortHandle, PURGE_RXABORT | PURGE_RXCLEAR); return 0; } dwLength = (static_cast(MaxLength) < ComStat.cbInQue ? MaxLength : ComStat.cbInQue); //memset(abIn, 0, MaxLength); //如果有字符即读入, 这种策略下无法解决读入的字符不是完整的一帧的问题 if (dwLength) { //BOOL ReadFile( // HANDLE hFile, //文件的句柄 // LPVOID lpBuffer, //用于保存读入数据的一个缓冲区 // DWORD nNumberOfBytesToRead, //要读入的字节数 // LPDWORD lpNumberOfBytesRead, //指向实际读取字节数的指针 // LPOVERLAPPED lpOverlapped // //如文件打开时指定了FILE_FLAG_OVERLAPPED,那么必须,用这个参数引用一个特殊的结构。 // //该结构定义了一次异步读取操作。否则,应将这个参数设为NULL //); JudgeRead = ReadFile(m_PortHandle, abIn, dwLength, &dwLength, &m_ReceiveOLap); //读出字符至abIn处 if (!JudgeRead) { //如果重叠操作未完成,等待直到操作完成 if (GetLastError() == ERROR_IO_PENDING) { // WaitForSingleObject(m_osRead.hEvent,INFINITE); GetOverlappedResult(m_PortHandle, &m_ReceiveOLap, &dwLength, TRUE); //等待一次异步读取完成 m_ReceiveOLap.Offset = 0; // m_osRead.Offset=(m_osRead.Offset+dwLength)%MAXBLOCK; //等待一次异步操作超时的情况下,GetOverlappedResult返回FALSE,同时GetLastError返回ERROR_IO_INCOMPLETE /* if (WaitForSingleObject(m_osRead.hEvent, 1000) == WAIT_TIMEOUT) { dwLength = 0; } */ } //异常情况 else { dwLength = 0; } } } return dwLength; } int CPSerial::Receive(void* buf, int maxlen, bool sync) { //HANDLE hCom = *(HANDLE*)m_PortHandle; if (sync) { //同步方式 DWORD wCount = maxlen; //成功读取的数据字节数 BOOL bReadStat = ReadFile(m_PortHandle, //串口句柄 buf, //数据首地址 wCount, //要读取的数据最大字节数 &wCount, //DWORD*,用来接收返回成功读取的数据字节数 NULL); //NULL为同步发送,OVERLAPPED*为异步发送 if (!bReadStat) { return 0; } return wCount; } else { //异步方式 DWORD wCount = maxlen; //成功读取的数据字节数 DWORD dwErrorFlags; //错误标志 COMSTAT comStat; //通讯状态 OVERLAPPED m_osRead; //异步输入输出结构体 //创建一个用于OVERLAPPED的事件处理,不会真正用到,但系统要求这么做 memset(&m_osRead, 0, sizeof(m_osRead)); //m_osRead.hEvent = CreateEvent(NULL, TRUE, FALSE, L"ReadEvent"); ClearCommError(m_PortHandle, &dwErrorFlags, &comStat); //清除通讯错误,获得设备当前状态 if (!comStat.cbInQue)return 0; //如果输入缓冲区字节数为0,则返回false BOOL bReadStat = ReadFile(m_PortHandle, //串口句柄 buf, //数据首地址 wCount, //要读取的数据最大字节数 &wCount, //DWORD*,用来接收返回成功读取的数据字节数 &m_osRead); //NULL为同步发送,OVERLAPPED*为异步发送 if (!bReadStat) { if (GetLastError() == ERROR_IO_PENDING) //如果串口正在读取中 { //GetOverlappedResult函数的最后一个参数设为TRUE //函数会一直等待,直到读操作完成或由于错误而返回 GetOverlappedResult(m_PortHandle, &m_osRead, &wCount, TRUE); /* memcpy(m_RecvData, buf, wCount); m_iRecvBytes = wCount; m_iRecvState = true;*/ } else { ClearCommError(m_PortHandle, &dwErrorFlags, &comStat); //清除通讯错误 CloseHandle(m_osRead.hEvent); //关闭并释放hEvent的内存 return 0; } } return wCount; } } /* // C prototype : void HexToStr(char *pszDest, byte *pbSrc, int nLen) // parameter(s): [OUT] pszDest - 存放目标字符串 // [IN] pbSrc - 输入16进制数的起始地址 // [IN] nLen - 16进制数的字节数 // return value: // remarks : 将16进制数转化为字符串 */ void CPSerial::hex2str(char* pszDest, byte* pbSrc, int nLen) { char ddl, ddh; for (int i = 0; i < nLen; i++) { ddh = 48 + pbSrc[i] / 16; ddl = 48 + pbSrc[i] % 16; if (ddh > 57) ddh = ddh + 7; if (ddl > 57) ddl = ddl + 7; pszDest[i * 2] = ddh; pszDest[i * 2 + 1] = ddl; } pszDest[nLen * 2] = '\0'; } ///////////////////////////////////////////////////////////////////////////// // ReceiveTask() : Internal function, this runs as a thread and provides the // OnRecieve and OnTransmit events void CPSerial::ReceiveTask(void) { //DWORD BytesWritten; DWORD Events; unsigned long State; int temp_Packlen = 0; //临时存放包长度 do { Sleep(3); BYTE abIn[MAXBLOCK]; int len; //len = ReadBlock(abIn, MAXBLOCK); //读取一包串口数据 len = Receive(abIn, MAXBLOCK, 0);//方式2 if ((len > 0) && (len < MAX_RECIEVE_BUFFER_SIZE)) { //memset(m_RecvData, 0, m_iRecvBytes); if (m_bDebug) { auto pszDest = new char[len * 2 + 1]; hex2str(pszDest, abIn, len); printf("kaishi len=%d, m_iExpectBytes=%d, %s\n", len, m_iExpectBytes, pszDest); //打印单包数据,每次可以从这里得到单包数据 } // 第一层判断,当前接收正好为期望返回 if (len == m_iExpectBytes) { memcpy(m_RecvData, abIn, len); m_iRecvBytes = len; m_iRecvState = true; printf("====="); temp_Packlen = 0; } // 第二层判断,当前接收为期望返回的一部分 else if (len < m_iExpectBytes) { memcpy(m_RecvData + temp_Packlen, abIn, len); temp_Packlen += len; //打印拼包后的数据 auto pszDest = new char[m_iRecvBytes * 2 + 1]; hex2str(pszDest, m_RecvData, m_iRecvBytes); printf("pinbao = %d %s\n", m_iRecvBytes, pszDest); // 第三层判断,当前接收为期望返回的最后一部分 if (temp_Packlen == m_iExpectBytes) { m_iRecvBytes = temp_Packlen; m_iRecvState = true; printf("pinbao========"); } } // 第四层判断,当前接收为期望返回的超出部分,以实际接收为准 else if (len > m_iExpectBytes) { memcpy(m_RecvData, abIn, len); m_iRecvBytes = len; m_iRecvState = true; printf(">>>>>>>>>>>>========"); temp_Packlen = 0; } } // 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()); } #if 0 void CPSerial::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()); } #endif ///////////////////////////////////////////////////////////////////////////// // OnReceive() : Default OnReceive() // V114 void CPSerial::OnReceive() { // Dummy OnReceieve if not used char s[MAX_RECIEVE_BUFFER_SIZE] = {0}; s[1] = '\0'; CurrentPointer = 0; int num = 0; if (m_HandShake == CS_HANDSHAKE_FOR_TRESASTR_E) { num = ReadPort(s, MAX_RECIEVE_BUFFER_SIZE); if ((num > 0) && (num < MAX_RECIEVE_BUFFER_SIZE)) { if (m_IsWrtingData) { memset(m_RecvData, 0,MAX_RECIEVE_BUFFER_SIZE); m_IsWrtingData = FALSE; m_iRecvBytes = 0; } TRACE1("----RECV%d----\r\n", num); TRACE3("%02X %02X %02X ", s[0], s[1], s[2]); TRACE3("%02X %02X %02X ", s[3], s[4], s[5]); TRACE3("%02X %02X %02X\r\n", s[6], s[7], s[8]); for (int i = 0; i < num; i++) { m_RecvData[m_iRecvBytes++] = s[i]; } m_iRecvState = TRUE; } } else { num = ReadPort(s, m_iRecvCount); printf("----Data received:: %d----\r\n", num); if ((num > 0) && (num < MAX_RECIEVE_BUFFER_SIZE)) { // memset(m_RecvData,0,m_iRecvBytes); memcpy(m_RecvData, s, num); m_iRecvBytes = num; m_iRecvState = TRUE; for (int i = 0; i < num; i++) { printf(" %02X ", m_RecvData[i]); } } } LineReceive(s, num); } ///////////////////////////////////////////////////////////////////////////// // ReadPort() : Read the specifed number of bytes. // DWORD CPSerial::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(5); // 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, nullptr); 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 CPSerial::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 CPSerial::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(&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.fDsrSensitivity = FALSE; SerialDCB.XonChar = 17; SerialDCB.XoffChar = 19; SerialDCB.fOutX = FALSE; SerialDCB.fInX = FALSE; SerialDCB.fErrorChar = FALSE; SerialDCB.fRtsControl = RTS_CONTROL_ENABLE; SerialDCB.fDtrControl = DTR_CONTROL_ENABLE; SerialDCB.fOutxCtsFlow = FALSE; SerialDCB.fOutxDsrFlow = FALSE; SerialDCB.XonLim = 2048; SerialDCB.XoffLim = 512; break; case CS_HANDSHAKE_FOR_TRESASTR_E: SerialDCB.EofChar = 26; SerialDCB.XonChar = 17; SerialDCB.XoffChar = 19; SerialDCB.fOutX = TRUE; SerialDCB.fInX = TRUE; SerialDCB.fRtsControl = RTS_CONTROL_DISABLE; SerialDCB.fDtrControl = DTR_CONTROL_ENABLE; SerialDCB.fDsrSensitivity = FALSE; SerialDCB.XonLim = 256; SerialDCB.XoffLim = 256; 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 = static_cast(Bits); // data size, xmit, and rcv SerialDCB.StopBits = static_cast(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.fDsrSensitivity = FALSE; SerialDCB.XonChar = 17; SerialDCB.XoffChar = 19; SerialDCB.fOutX = FALSE; SerialDCB.fInX = FALSE; SerialDCB.fErrorChar = FALSE; SerialDCB.fRtsControl = RTS_CONTROL_ENABLE; SerialDCB.fDtrControl = DTR_CONTROL_ENABLE; SerialDCB.fOutxCtsFlow = FALSE; SerialDCB.fOutxDsrFlow = FALSE; SerialDCB.XonLim = 2048; SerialDCB.XoffLim = 512; break; case CS_HANDSHAKE_FOR_TRESASTR_E: SerialDCB.EofChar = 26; SerialDCB.XonChar = 17; SerialDCB.XoffChar = 19; SerialDCB.fOutX = TRUE; SerialDCB.fInX = TRUE; SerialDCB.fRtsControl = RTS_CONTROL_DISABLE; SerialDCB.fDtrControl = DTR_CONTROL_ENABLE; SerialDCB.fDsrSensitivity = FALSE; SerialDCB.XonLim = 256; SerialDCB.XoffLim = 256; 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, Program Port not done!\n")); Ok = TRUE; } } return (Ok); } ///////////////////////////////////////////////////////////////////////////// // OnTransmit() : Default OnTransmit() // void CPSerial::OnTransmit(int /*Item*/, DWORD /*Error*/) { // Dummy OnTransmit if not used } ///////////////////////////////////////////////////////////////////////////// // SetTimeouts() : Sets the rx and tx timeouts // void CPSerial::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 CPSerial::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 if( Ptr == NULL ) { BytesToCopy = 0; //Ptr = _T(""); Ptr = ""; } // 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 CPSerial::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 CPSerial::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 CPSerial::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 CPSerial::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 (;index0x80 ){ ++ 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 *CPSerial::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 CPSerial::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); } //字节数据转换为16进制字符串 CString CPSerial::HexToStr(const char* pData, int nLen) { CString str; CString strTemp; for (int i = 0; i < nLen; i++) { strTemp.Format(_T(" %02X "), pData[i]); str += strTemp; } return str; } //unsigned char CPSerial::HexCharToByte(char ch) //{ // if ((ch >= '0') && (ch <= '9')) // return ch - '0'; // if ((ch >= 'A') && (ch <= 'F')) // return ch - 'A' + 10; // if ((ch >= 'a') && (ch <= 'f')) // return ch - 'a' + 10; // return 0; //} ///////////////////////////////////////////////////////////////////////////// // Private functions // ///////////////////////////////////////////////////////////////////////////// // RegisterDebugWindow() : Registers the window class for the debug window. // //ZH /* void CPSerial::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("CPSerial"); AfxRegisterClass( &wndcls ); } */ #if 0 ///////////////////////////////////////////////////////////////////////////// // SendBuffer() : Internal function, this writes the next block of data // queued to the serial port. void CPSerial::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