bool Comm::setupdcb(int rate_arg)//设置DCB,先获取DCB配置,再设置,最后看是否设置//好 { DCB dcb; int rate = rate_arg; memset(&dcb, 0, sizeof(dcb));//在一段内存块中填充某个给定的值,是对较大的结构//体或数组进行清零操作的一种最快方法 if (!GetCommState(hComm, &dcb))//获取当前DCB配置 { ProcessErrorMessage("GetCommState()"); return FALSE; } // set DCB to configure the serial port dcb.DCBlength = sizeof(dcb); /* ---------- Serial Port Config ------- */ dcb.BaudRate = rate; dcb.Parity = NOPARITY; dcb.fParity = 0; dcb.StopBits = ONESTOPBIT; dcb.ByteSize = 8; dcb.fOutxCtsFlow = 0; dcb.fOutxDsrFlow = 0; dcb.fDtrControl = DTR_CONTROL_DISABLE; dcb.fDsrSensitivity = 0; dcb.fRtsControl = RTS_CONTROL_DISABLE; dcb.fOutX = 0; dcb.fInX = 0; /* ----------------- misc parameters ----- */ dcb.fErrorChar = 0; dcb.fBinary = 1; dcb.fNull = 0; dcb.fAbortOnError = 0; dcb.wReserved = 0; dcb.XonLim = 2; dcb.XoffLim = 4; dcb.XonChar = 0x13; dcb.XoffChar = 0x19; dcb.EvtChar = 0; // set DCB if (!SetCommState(hComm, &dcb)) { ProcessErrorMessage("SetCommState()"); return false; } else return true; }
bool Comm::setuptimeout(DWORD ReadInterval, DWORD ReadTotalMultiplier, DWORD ReadTotalconstant, DWORD WriteTotalMultiplier, DWORD WriteTotalconstant) { COMMTIMEOUTS timeouts; timeouts.ReadIntervalTimeout = ReadInterval; timeouts.ReadTotalTimeoutConstant = ReadTotalconstant; timeouts.ReadTotalTimeoutMultiplier = ReadTotalMultiplier; timeouts.WriteTotalTimeoutConstant = WriteTotalconstant; timeouts.WriteTotalTimeoutMultiplier = WriteTotalMultiplier; if (!SetCommTimeouts(hComm, &timeouts)) { ProcessErrorMessage("SetCommTimeouts()"); return false; } else return true; }
// // Initialize the port. This can be port 1 to MaxSerialPortNum. ///初始化串口。只能是1-MaxSerialPortNum // //parity: // n=none // e=even // o=odd // m=mark // s=space //data: // 5,6,7,8 //stop: // 1,1.5,2 // BOOL CSerialPort::InitPort(HWND pPortOwner, // the owner (CWnd) of the port (receives message) UINT portnr, // portnumber (1..MaxSerialPortNum) UINT baud, // baudrate char parity, // parity UINT databits, // databits UINT stopbits, // stopbits DWORD dwCommEvents, // EV_RXCHAR, EV_CTS etc UINT writebuffersize,// size to the writebuffer DWORD ReadIntervalTimeout, DWORD ReadTotalTimeoutMultiplier, DWORD ReadTotalTimeoutConstant, DWORD WriteTotalTimeoutMultiplier, DWORD WriteTotalTimeoutConstant ) { assert(portnr > 0 && portnr < 200); assert(pPortOwner != NULL); // if the thread is alive: Kill if (m_bThreadAlive) { do { SetEvent(m_hShutdownEvent); } while (m_bThreadAlive); //TRACE("Thread ended\n"); } // create events if (m_ov.hEvent != NULL) ResetEvent(m_ov.hEvent); else m_ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (m_hWriteEvent != NULL) ResetEvent(m_hWriteEvent); else m_hWriteEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (m_hShutdownEvent != NULL) ResetEvent(m_hShutdownEvent); else m_hShutdownEvent = CreateEvent(NULL, TRUE, FALSE, NULL); // initialize the event objects ///事件数组初始化,设定优先级别 m_hEventArray[0] = m_hShutdownEvent; // highest priority m_hEventArray[1] = m_ov.hEvent; m_hEventArray[2] = m_hWriteEvent; // initialize critical section ///初始化临界资源 InitializeCriticalSection(&m_csCommunicationSync); // set buffersize for writing and save the owner m_pOwner = pPortOwner; if (m_szWriteBuffer != NULL) delete [] m_szWriteBuffer; m_szWriteBuffer = new char[writebuffersize]; m_nPortNr = portnr; m_nWriteBufferSize = writebuffersize; m_dwCommEvents = dwCommEvents; BOOL bResult = FALSE; CString szPort; //char *szBaud = new char[50]; /* 多个线程操作相同的数据时,一般是需要按顺序访问的,否则会引导数据错乱, 无法控制数据,变成随机变量。为解决这个问题,就需要引入互斥变量,让每 个线程都按顺序地访问变量。这样就需要使用EnterCriticalSection和 LeaveCriticalSection函数。 */ // now it critical! EnterCriticalSection(&m_csCommunicationSync); // if the port is already opened: close it ///串口已打开就关掉 if (m_hComm != NULL) { CloseHandle(m_hComm); m_hComm = NULL; } // prepare port strings szPort.Format("\\\\.\\COM%d", portnr);///可以显示COM10以上端口//add by itas109 2014-01-09 // stop is index 0 = 1 1=1.5 2=2 int mystop; int myparity; switch(stopbits) { case 0: mystop = ONESTOPBIT; break; case 1: mystop = ONE5STOPBITS; break; case 2: mystop = TWOSTOPBITS; break; } myparity = 0; parity = toupper(parity); switch(parity) { case 'N': myparity = 0; break; case 'O': myparity = 1; break; case 'E': myparity = 2; break; case 'M': myparity = 3; break; case 'S': myparity = 4; break; } //sprintf(szBaud, "baud=%d parity=%c data=%d stop=%d", baud, parity, databits, mystop); // get a handle to the port /* 通信程序在CreateFile处指定串口设备及相关的操作属性,再返回一个句柄, 该句柄将被用于后续的通信操作,并贯穿整个通信过程串口打开后,其属性 被设置为默认值,根据具体需要,通过调用GetCommState(hComm,&&dcb)读取 当前串口设备控制块DCB设置,修改后通过SetCommState(hComm,&&dcb)将其写 入。运用ReadFile()与WriteFile()这两个API函数实现串口读写操作,若为异 步通信方式,两函数中最后一个参数为指向OVERLAPPED结构的非空指针,在读 写函数返回值为FALSE的情况下,调用GetLastError()函数,返回值为ERROR_IO_PENDING, 表明I/O操作悬挂,即操作转入后台继续执行。此时,可以用WaitForSingleObject() 来等待结束信号并设置最长等待时间 */ m_hComm = CreateFile(szPort, // communication port string (COMX) GENERIC_READ | GENERIC_WRITE, // read/write types 0, // comm devices must be opened with exclusive access NULL, // no security attributes OPEN_EXISTING, // comm devices must use OPEN_EXISTING FILE_FLAG_OVERLAPPED, // Async I/O 0); // template must be 0 for comm devices ///创建失败 if (m_hComm == INVALID_HANDLE_VALUE) { // port not found //delete [] szBaud; return FALSE; } // set the timeout values ///设置超时 m_CommTimeouts.ReadIntervalTimeout = ReadIntervalTimeout * 1000; m_CommTimeouts.ReadTotalTimeoutMultiplier = ReadTotalTimeoutMultiplier * 1000; m_CommTimeouts.ReadTotalTimeoutConstant = ReadTotalTimeoutConstant * 1000; m_CommTimeouts.WriteTotalTimeoutMultiplier = WriteTotalTimeoutMultiplier * 1000; m_CommTimeouts.WriteTotalTimeoutConstant = WriteTotalTimeoutConstant * 1000; // configure ///配置 ///分别调用Windows API设置串口参数 if (SetCommTimeouts(m_hComm, &m_CommTimeouts))///设置超时 { /* 若对端口数据的响应时间要求较严格,可采用事件驱动方式。 事件驱动方式通过设置事件通知,当所希望的事件发生时,Windows 发出该事件已发生的通知,这与DOS环境下的中断方式很相似。Windows 定义了9种串口通信事件,较常用的有以下三种: EV_RXCHAR:接收到一个字节,并放入输入缓冲区; EV_TXEMPTY:输出缓冲区中的最后一个字符,发送出去; EV_RXFLAG:接收到事件字符(DCB结构中EvtChar成员),放入输入缓冲区 在用SetCommMask()指定了有用的事件后,应用程序可调用WaitCommEvent()来等待事 件的发生。SetCommMask(hComm,0)可使WaitCommEvent()中止 */ if (SetCommMask(m_hComm, dwCommEvents))///设置通信事件 { if (GetCommState(m_hComm, &m_dcb))///获取当前DCB参数 { //m_dcb.EvtChar = 'q'; //m_dcb.fRtsControl = RTS_CONTROL_ENABLE; // set RTS bit high! m_dcb.BaudRate = baud; // add by mrlong m_dcb.Parity = myparity; m_dcb.ByteSize = databits; m_dcb.StopBits = mystop; m_dcb.fBinary = TRUE;// 指定是否允许二进制模式 m_dcb.fParity = TRUE;// 指定是否允许奇偶校验 //m_dcb.EvtChar = 'q'; //if (BuildCommDCB(szBaud, &m_dcb))///填写DCB结构 //{ if (SetCommState(m_hComm, &m_dcb))///配置DCB ; // normal operation... continue else ProcessErrorMessage("SetCommState()"); //} //else // ProcessErrorMessage("BuildCommDCB()"); } else ProcessErrorMessage("GetCommState()"); } else ProcessErrorMessage("SetCommMask()"); } else ProcessErrorMessage("SetCommTimeouts()"); //delete [] szBaud; // flush the port ///终止读写并清空接收和发送 PurgeComm(m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT); // release critical section ///释放临界资源 LeaveCriticalSection(&m_csCommunicationSync); //TRACE("Initialisation for communicationport %d completed.\nUse Startmonitor to communicate.\n", portnr); return TRUE; }
// // Initialize the port. This can be port 1 to 4. // BOOL CSerialPort::InitPort(CWnd* pPortOwner, // the owner (CWnd) of the port (receives message) UINT portnr, // portnumber (1..4) UINT baud, // baudrate char parity, // parity UINT databits, // databits UINT stopbits, // stopbits DWORD dwCommEvents, // EV_RXCHAR, EV_CTS etc UINT writebuffersize) // size to the writebuffer { //assert(portnr > 0 && portnr < 5); assert(pPortOwner != NULL); // if the thread is alive: Kill if (m_bThreadAlive) { do { SetEvent(m_hShutdownEvent); } while (m_bThreadAlive); TRACE("Thread ended\n"); } // create events if (m_ov.hEvent != NULL) ResetEvent(m_ov.hEvent); m_ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (m_hWriteEvent != NULL) ResetEvent(m_hWriteEvent); m_hWriteEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (m_hShutdownEvent != NULL) ResetEvent(m_hShutdownEvent); m_hShutdownEvent = CreateEvent(NULL, TRUE, FALSE, NULL); // initialize the event objects m_hEventArray[0] = m_hShutdownEvent; // highest priority m_hEventArray[1] = m_ov.hEvent; m_hEventArray[2] = m_hWriteEvent; // initialize critical section InitializeCriticalSection(&m_csCommunicationSync); // set buffersize for writing and save the owner m_pOwner = pPortOwner; if (m_szWriteBuffer != NULL) delete [] m_szWriteBuffer; m_szWriteBuffer = new char[writebuffersize]; m_nPortNr = portnr; m_nWriteBufferSize = writebuffersize; m_dwCommEvents = dwCommEvents; BOOL bResult = FALSE; char *szPort = new char[50]; char *szBaud = new char[50]; // now it critical! EnterCriticalSection(&m_csCommunicationSync); // if the port is already opened: close it if (m_hComm != NULL) { CloseHandle(m_hComm); m_hComm = NULL; } // prepare port strings sprintf(szPort, "COM%d", portnr); sprintf(szBaud, "baud=%d parity=%c data=%d stop=%d", baud, parity, databits, stopbits); // get a handle to the port m_hComm = CreateFile(szPort, // communication port string (COMX) GENERIC_READ | GENERIC_WRITE, // read/write types 0, // comm devices must be opened with exclusive access NULL, // no security attributes OPEN_EXISTING, // comm devices must use OPEN_EXISTING FILE_FLAG_OVERLAPPED, // Async I/O 0); // template must be 0 for comm devices if (m_hComm == INVALID_HANDLE_VALUE) { // port not found delete [] szPort; delete [] szBaud; return FALSE; } // set the timeout values m_CommTimeouts.ReadIntervalTimeout = 1000; m_CommTimeouts.ReadTotalTimeoutMultiplier = 1000; m_CommTimeouts.ReadTotalTimeoutConstant = 1000; m_CommTimeouts.WriteTotalTimeoutMultiplier = 1000; m_CommTimeouts.WriteTotalTimeoutConstant = 1000; // configure if (SetCommTimeouts(m_hComm, &m_CommTimeouts)) { if (SetCommMask(m_hComm, dwCommEvents)) { if (GetCommState(m_hComm, &m_dcb)) { m_dcb.fRtsControl = RTS_CONTROL_ENABLE; // set RTS bit high! if (BuildCommDCB(szBaud, &m_dcb)) { if (SetCommState(m_hComm, &m_dcb)) ; // normal operation... continue else ProcessErrorMessage("SetCommState()"); } else ProcessErrorMessage("BuildCommDCB()"); } else ProcessErrorMessage("GetCommState()"); } else ProcessErrorMessage("SetCommMask()"); } else ProcessErrorMessage("SetCommTimeouts()"); delete [] szPort; delete [] szBaud; // flush the port PurgeComm(m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT); // release critical section LeaveCriticalSection(&m_csCommunicationSync); TRACE("Initialisation for communicationport %d completed.\nUse Startmonitor to communicate.\n", portnr); return TRUE; }
bool Comm::WriteChar(BYTE* m_szWriteBuffer, DWORD m_nToSend) { BOOL bWrite = TRUE; BOOL bResult = TRUE; DWORD BytesSent = 0; HANDLE m_hWriteEvent = NULL; ResetEvent(m_hWriteEvent); if (bWrite) { m_ov.Offset = 0; m_ov.OffsetHigh = 0; // Clear buffer bResult = WriteFile(hComm, // Handle to COMM Port, 串口的句柄 m_szWriteBuffer, // Pointer to message buffer in calling finction // 即以该指针的值为首地址的nNumberOfBytesToWrite // 个字节的数据将要写入串口的发送数据缓冲区 m_nToSend, // Length of message to send, 要写入的数据的字节数 &BytesSent, // Where to store the number of bytes sent // 指向指向一个DWORD数值,该数值返回实际写入的字节数 &m_ov); // Overlapped structure // 重叠操作时,该参数指向一个OVERLAPPED结构, // 同步操作时,该参数为NULL if (!bResult) // 当ReadFile和WriteFile返回FALSE时,不一定就是操作失 //败,线程应该调用GetLastError函数分析返回的结果 { DWORD dwError = GetLastError(); switch (dwError) { case ERROR_IO_PENDING: //GetLastError函数返回 //ERROR_IO_PENDING。这说明重叠操作还未完成 { // continue to GetOverlappedResults() BytesSent = 0; bWrite = FALSE; break; } default: { // all other error codes // all other error codes ProcessErrorMessage("WriteFile()"); break; } } } } // end if(bWrite) if (!bWrite) { bWrite = TRUE; bResult = GetOverlappedResult(hComm, // Handle to COMM port &m_ov, // Overlapped structure &BytesSent, // Stores number of bytes sent TRUE); // Wait flag // deal with the error code if (!bResult) { ProcessErrorMessage("GetOverlappedResults() in WriteFile()"); } } // end if (!bWrite) // Verify that the data size send equals what we tried to send if (BytesSent != m_nToSend) { printf("WARNING: WriteFile() error.. Bytes Sent: %d; Message Length: %d\n", BytesSent, strlen((char*)m_szWriteBuffer)); } return true; }
// // Initialize the port. This can be port 1 to 20. //初始化串口 BOOL CSerialPortPC::InitPort(CWnd* pPortOwner, // the owner (CWnd) of the port (receives message) UINT portnr, // portnumber (1..99) UINT baud, // baudrate char parity, // parity UINT databits, // databits UINT stopbits, // stopbits DWORD dwCommEvents, // EV_RXCHAR, EV_CTS etc UINT writebuffersize) // size to the writebuffer { assert(portnr > 0 && portnr < 100);//增加串口号 assert计算表达式如果其值为假(即为0),会调用abort来终止程序运行 assert(pPortOwner != NULL); VERIFY(portnr > 0 && portnr < 100);//增加串口号 assert计算表达式如果其值为假(即为0),会调用abort来终止程序运行 VERIFY(pPortOwner != NULL); // if the thread is alive: Kill线程在的话关闭它 if (m_bThreadAlive) { do { SetEvent(m_hShutdownEvent); } while (m_bThreadAlive); TRACE("Thread ended\n"); } // create events创建事件 if (m_ov.hEvent != NULL) ResetEvent(m_ov.hEvent); else m_ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); //HANDLE CreateEvent(LPSECURITY_ATTRIBUTES lpEventAttributes安全属性,一个指向SECURITY_ATTRIBUTES结构的指针,确定返回的句柄是否可被子进程继承如果是NULL此句柄不能被继承 //BOOL bManualReset复位方式,若是TRUE必须用ResetEvent函数来手工将事件复原到无信号状态若为FALSE当事件被一个等待线程释放后系统将自动将事件状态复原为无信号状态 //BOOL bInitialState初始状态,指定事件对象的初始状态。如果为TRUE,初始状态为有信号状态,否则为无信号状态 //LPCTSTR lpName若为NULL,创建一个无名的事件对象。对象名称,指定事件的对象的名称,是一个以0结束的字符串指针名称的字符格式限定在MAX_PATH之内,名字是对大小写敏感的) if (m_hWriteEvent != NULL) ResetEvent(m_hWriteEvent); else m_hWriteEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (m_hShutdownEvent != NULL) ResetEvent(m_hShutdownEvent); else m_hShutdownEvent = CreateEvent(NULL, TRUE, FALSE, NULL); // initialize the event objects事件数组初始化设定优先级别 m_hEventArray[0] = m_hShutdownEvent; // highest priority m_hEventArray[1] = m_ov.hEvent; m_hEventArray[2] = m_hWriteEvent; // initialize critical section初始化一个临界资源对象 InitializeCriticalSection(&m_csCommunicationSync); // set buffersize for writing and save the owner m_pOwner = pPortOwner; if (m_szWriteBuffer != NULL) delete [] m_szWriteBuffer; m_szWriteBuffer = new TCHAR[writebuffersize]; m_nPortNr = portnr; m_nPortNum = m_nPortNr; m_nWriteBufferSize = writebuffersize; m_dwCommEvents = dwCommEvents; BOOL bResult = FALSE; char *szPort = new char[50]; char *szBaud = new char[50]; // now it critical! //多个线程操作相同的数据时,一般是需要按顺序访问的,否则会引导数据错乱,无法控制数据,变成随机变量。为解决这个问题,就需要引入互斥变量,让每个线程 //都按顺序地访问变量。为解决这个问题,就需要引入互斥变量,让每个线程都按顺序地访问变量。这样就需要使用EnterCriticalSection和LeaveCriticalSection函数 //进入临界区。 //Sleep(1); EnterCriticalSection(&m_csCommunicationSync); // if the port is already opened: close it //串口已经打开的就关闭它 if (m_hComm != NULL) { CloseHandle(m_hComm);//用于关闭对象,函数原型为BOOL CloseHandle(HANDLE hObject);如果函数执行成功返回TRUE m_hComm = NULL; } // prepare port strings //串口参数 sprintf_s(szPort,50, ("COM%d"), portnr);//把portnr打印成一个字符串保存在szPort中 sprintf_s(szBaud,50, "baud=%d parity=%c data=%d stop=%d", baud, parity, databits, stopbits);//把baud parity等保存在szBaud中这一句很重要郁闷了很久 for(int i =0;i<10;i++) { Sleep(1); m_hComm = CreateFile(szPort,GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_FLAG_OVERLAPPED, 0); if(m_hComm!=INVALID_HANDLE_VALUE) { break; } } /* // get a handle to the port //通信程序在CreateFile处指定串口设备及相关的操作属性,再返回一个句柄,该句柄被用于后续的通信操作,并贯穿整个通信过程。串口打开后,其属性被设置为默认值, //根据具体需要,通过调用GetCommState(hComm,&&dcb)读取当前串口设备控制块DCB设置,修改后通过SetCommState(hComm,&&dcb)将其写入。运用ReadFile()与WriteFile() //这两个API函数实现串口读写操作,若为异步通信方式,两函数中最后一个参数为指向OVERLAPPED结构的非空指针,在读写函数返回值为FALSE的情况下,调用GetLastError() //函数,返回值为ERROR_IO_PENDING,表明I/O操作悬挂,即操作转入后台继续执行。此时,可以用WaitForSingleObject()来等待结束信号并设置最长等待时间。 m_hComm = CreateFile(szPort, // communication port string (COMX)串口号 GENERIC_READ | GENERIC_WRITE, // read/write types可以读写 0, // comm devices must be opened with exclusive access独占方式打开串口 NULL, // no security attributes无安全属性 OPEN_EXISTING, // comm devices must use OPEN_EXISTING FILE_FLAG_OVERLAPPED, // Async I/O异步IO 0); // template must be 0 for comm devices //如果创建不成功,错误处理 */ if (m_hComm == INVALID_HANDLE_VALUE) { // port not found delete [] szPort; delete [] szBaud; return FALSE; } // set the timeout values //设置超时上限(异步邋IO) m_CommTimeouts.ReadIntervalTimeout = 1000; m_CommTimeouts.ReadTotalTimeoutMultiplier = 1000; m_CommTimeouts.ReadTotalTimeoutConstant = 1000; m_CommTimeouts.WriteTotalTimeoutMultiplier = 1000; m_CommTimeouts.WriteTotalTimeoutConstant = 1000; // configure //分别调用Windows API设置串口参数 /******************************************************* 若对端口数据的响应时间要求较严格,可采用事件驱动方式。 事件驱动方式通过设置事件通知,当所希望的事件发生时,Windows 发出该事件已发生的通知,这与DOS环境下的中断方式很相似。Windows 定义了9种串口通信事件,较常用的有以下三种: EV_RXCHAR:接收到一个字节,并放入输入缓冲区; EV_TXEMPTY:输出缓冲区中的最后一个字符,发送出去; EV_RXFLAG:接收到事件字符(DCB结构中EvtChar成员),放入输入缓冲区 在用SetCommMask()指定了有用的事件后,应用程序可调用WaitCommEvent()来等待事 件的发生。SetCommMask(hComm,0)可使WaitCommEvent()中止。 **************************************************************/ if (SetCommTimeouts(m_hComm, &m_CommTimeouts))//设置超时 { if (SetCommMask(m_hComm, dwCommEvents))//设置通信事件 { if (GetCommState(m_hComm, &m_dcb))//获取当前DCB参数 { m_dcb.EvtChar = 'q';//设置字体字符 m_dcb.fRtsControl = RTS_CONTROL_ENABLE; // set RTS bit high! if (BuildCommDCB(szBaud, &m_dcb))//填写DCB结构 { if (SetCommState(m_hComm, &m_dcb))//配置DCB ; // normal operation... continue else ProcessErrorMessage("SetCommState()"); } else ProcessErrorMessage("BuildCommDCB()"); } else ProcessErrorMessage("GetCommState()"); } else ProcessErrorMessage("SetCommMask()"); } else ProcessErrorMessage("SetCommTimeouts()"); delete [] szPort; delete [] szBaud; // flush the port //终止读写并清空接收和发送 PurgeComm(m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT); //PURGE_RXCLEAR清空接收缓冲区 清空发送缓冲区 即使接收(读操作)没有完成也立即终止所有的重叠接收操作,立即返回 ...发送(写)...发送... // release critical section //出临界区 LeaveCriticalSection(&m_csCommunicationSync); //Sleep(1); TRACE("Initialisation for communicationport %d completed.\nUse Startmonitor to communicate.\n", portnr); return TRUE; }
// // Initialize the port. This can be port 1 to 4. // BOOL CSerialPort::InitPort(LPCTSTR pCommPort, // portnumber (COM1..COM4) UINT baud, // baudrate BYTE parity, // parity UINT databits, // databits UINT stopbits, // stopbits DWORD dwCommEvents // EV_RXCHAR, EV_CTS etc) ) { // if the thread is alive: Kill if (m_bThreadAlive) { do { SetEvent(m_hShutdownEvent); } while (m_bThreadAlive); TRACE(_T("InitPort Thread ended\n")); } // create events if (m_ov.hEvent != NULL) { ResetEvent(m_ov.hEvent); } else { m_ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); } if (m_hWriteEvent != NULL) { ResetEvent(m_hWriteEvent); } else { m_hWriteEvent = CreateEvent(NULL, TRUE, FALSE, NULL); } if (m_hShutdownEvent != NULL) { ResetEvent(m_hShutdownEvent); } else { m_hShutdownEvent = CreateEvent(NULL, TRUE, FALSE, NULL); } // initialize the event objects m_hEventArray[0] = m_hShutdownEvent; // highest priority m_hEventArray[1] = m_ov.hEvent; m_hEventArray[2] = m_hWriteEvent; // initialize critical section InitializeCriticalSection(&m_csCommunicationSync); // set buffersize for writing and save the owner memset(m_szWriteBuffer,0,sizeof(m_szWriteBuffer)); m_nWriteBufferSize = sizeof(m_szWriteBuffer); m_dwCommEvents = dwCommEvents; BOOL bResult = FALSE; // now it critical! EnterCriticalSection(&m_csCommunicationSync); // if the port is already opened: close it if (m_hComm != NULL) { CloseHandle(m_hComm); m_hComm = NULL; } // prepare port strings m_nPortNr.Format(_T("\\\\.\\%s"),pCommPort); // get a handle to the port m_hComm = CreateFile(m_nPortNr, // communication port string (COMX) GENERIC_READ | GENERIC_WRITE, // read/write types 0, // comm devices must be opened with exclusive access NULL, // no security attributes OPEN_EXISTING, // comm devices must use OPEN_EXISTING FILE_FLAG_OVERLAPPED, // Async I/O 0); // template must be 0 for comm devices if (m_hComm == INVALID_HANDLE_VALUE) { // port not found return FALSE; } // set the timeout values m_CommTimeouts.ReadIntervalTimeout = 1000; m_CommTimeouts.ReadTotalTimeoutMultiplier = 0; m_CommTimeouts.ReadTotalTimeoutConstant = 1000; m_CommTimeouts.WriteTotalTimeoutMultiplier = 5; m_CommTimeouts.WriteTotalTimeoutConstant = 1000; // configure if (SetCommTimeouts(m_hComm, &m_CommTimeouts)) { if (SetCommMask(m_hComm, dwCommEvents)) { if (GetCommState(m_hComm, &m_dcb)) { //DCB m_dcb.BaudRate = baud; m_dcb.fBinary = TRUE; m_dcb.fParity = FALSE; m_dcb.fOutxCtsFlow = FALSE; m_dcb.fOutxDsrFlow = FALSE; m_dcb.fDtrControl = DTR_CONTROL_ENABLE; m_dcb.fRtsControl = RTS_CONTROL_ENABLE; m_dcb.fOutX = FALSE; m_dcb.fInX = FALSE; m_dcb.ByteSize = 8; m_dcb.Parity = parity; m_dcb.StopBits = ONESTOPBIT; m_dcb.EvtChar = 0x0; SetCommState(m_hComm, &m_dcb); if (!SetCommState(m_hComm, &m_dcb)) { ProcessErrorMessage(0);//"SetCommState()" } } else { ProcessErrorMessage(1);//"GetCommState()" } } else { ProcessErrorMessage(2);//"SetCommMask()" } } else { ProcessErrorMessage(3);//"SetCommTimeouts()" } // flush the port PurgeComm(m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT); // release critical section LeaveCriticalSection(&m_csCommunicationSync); TRACE(_T("Initialisation for communicationport completed.\nUse Startmonitor to communicate.\n")); return TRUE; }
// // Initialize the port. This can be port 1 to 4. // // //parity: // n=none // e=even // o=odd // m=mark // s=space //data: // 5,6,7,8 //stop: // 1,1.5,2 // BOOL CSerialPort::InitPort(CWnd* pPortOwner, // the owner (CWnd) of the port (receives message) UINT portnr, // portnumber (1..4) UINT baud, // baudrate char parity, // parity UINT databits, // databits UINT stopbits, // stopbits DWORD dwCommEvents, // EV_RXCHAR, EV_CTS etc UINT writebuffersize,// size to the writebuffer DWORD ReadIntervalTimeout, DWORD ReadTotalTimeoutMultiplier, DWORD ReadTotalTimeoutConstant, DWORD WriteTotalTimeoutMultiplier, DWORD WriteTotalTimeoutConstant ) { assert(portnr > 0 && portnr < 5); assert(pPortOwner != NULL); // if the thread is alive: Kill if (m_bThreadAlive) { do { SetEvent(m_hShutdownEvent); } while (m_bThreadAlive); TRACE("Thread ended\n"); } // create events if (m_ov.hEvent != NULL) ResetEvent(m_ov.hEvent); else m_ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (m_hWriteEvent != NULL) ResetEvent(m_hWriteEvent); else m_hWriteEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (m_hShutdownEvent != NULL) ResetEvent(m_hShutdownEvent); else m_hShutdownEvent = CreateEvent(NULL, TRUE, FALSE, NULL); // initialize the event objects m_hEventArray[0] = m_hShutdownEvent; // highest priority m_hEventArray[1] = m_ov.hEvent; m_hEventArray[2] = m_hWriteEvent; // initialize critical section InitializeCriticalSection(&m_csCommunicationSync); // set buffersize for writing and save the owner m_pOwner = pPortOwner; if (m_szWriteBuffer != NULL) delete [] m_szWriteBuffer; m_szWriteBuffer = new unsigned char[writebuffersize]; m_nPortNr = portnr; m_nWriteBufferSize = writebuffersize; m_dwCommEvents = dwCommEvents; BOOL bResult = FALSE; char *szPort = new char[50]; TCHAR *szBaud = new TCHAR[50]; // now it critical! EnterCriticalSection(&m_csCommunicationSync); // if the port is already opened: close it if (m_hComm != NULL) { CloseHandle(m_hComm); m_hComm = NULL; } // prepare port strings //_stprintf(szPort, TEXT("COM%d"), portnr); sprintf(szPort, "COM%d", portnr); // stop is index 0 = 1 1=1.5 2=2 int mystop; int myparity; switch(stopbits) { case 0: mystop = ONESTOPBIT; break; case 1: mystop = ONE5STOPBITS; break; case 2: mystop = TWOSTOPBITS; break; } myparity = 0; switch(parity) { case 'N': myparity = 0; break; case 'E': myparity = 1; break; case 'O': myparity = 2; break; case 'M': myparity = 3; break; case 'S': myparity = 4; break; } _stprintf_s(szBaud, 49, TEXT("baud=%d parity=%c data=%d stop=%d"), baud, parity, databits, mystop); // get a handle to the port m_hComm = CreateFileA(szPort, // communication port string (COMX) GENERIC_READ | GENERIC_WRITE, // read/write types 0, // comm devices must be opened with exclusive access NULL, // no security attributes OPEN_EXISTING, // comm devices must use OPEN_EXISTING 0,//FILE_FLAG_OVERLAPPED, // Async I/O 0); // template must be 0 for comm devices if (m_hComm == INVALID_HANDLE_VALUE) { // port not found delete [] szPort; delete [] szBaud; return FALSE; } // set the timeout values m_CommTimeouts.ReadIntervalTimeout = ReadIntervalTimeout * 1000; m_CommTimeouts.ReadTotalTimeoutMultiplier = ReadTotalTimeoutMultiplier * 1000; m_CommTimeouts.ReadTotalTimeoutConstant = ReadTotalTimeoutConstant * 1000; m_CommTimeouts.WriteTotalTimeoutMultiplier = WriteTotalTimeoutMultiplier * 1000; m_CommTimeouts.WriteTotalTimeoutConstant = WriteTotalTimeoutConstant * 1000; // configure if (SetCommTimeouts(m_hComm, &m_CommTimeouts)) { if (SetCommMask(m_hComm, dwCommEvents)) { if (GetCommState(m_hComm, &m_dcb)) { m_dcb.EvtChar = 'q'; m_dcb.fRtsControl = RTS_CONTROL_ENABLE; // set RTS bit high! m_dcb.BaudRate = baud; // add by mrlong m_dcb.Parity = myparity; m_dcb.ByteSize = databits; m_dcb.StopBits = mystop; if (BuildCommDCB(szBaud, &m_dcb)) { if (SetCommState(m_hComm, &m_dcb)) ; // normal operation... continue else { DWORD dwError = GetLastError(); ProcessErrorMessage("SetCommState()"); } } else { ProcessErrorMessage("BuildCommDCB()"); } } else ProcessErrorMessage("GetCommState()"); } else ProcessErrorMessage("SetCommMask()"); } else ProcessErrorMessage("SetCommTimeouts()"); delete [] szPort; delete [] szBaud; // flush the port PurgeComm(m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT); // release critical section LeaveCriticalSection(&m_csCommunicationSync); TRACE("Initialisation for communicationport %d completed.\nUse Startmonitor to communicate.\n", portnr); return TRUE; }