/* * Function: w32DeviceInputStream_getReadCountNC * Purpose: Check serial port device event * Signature: ()I * Return: 0 - Fail * none zero - succeeds */ int w32DeviceInputStream_getReadCountNC(JNIEnv *jenv, jobject jobj) { DWORD dwCommEvent = 0; HANDLE osHandle; jclass jc; jclass ec; jfieldID jf; jint fd = -1; int dc = 0; // Get the exception class. ec = (*jenv)->FindClass(jenv, "java/io/IOException"); assert(ec); // Get the file descriptor. jc = (*jenv)->GetObjectClass(jenv, jobj); assertexc(jc); jf = (*jenv)->GetFieldID(jenv, jc, "fd", "I"); assertexc(jf); fd = (*jenv)->GetIntField(jenv, jobj, jf); if (fd == -1) { (*jenv)->ThrowNew(jenv, ec, ""); } osHandle = (HANDLE)fd; if(!GetCommMask( osHandle, &dwCommEvent )) return GetLastError(); dwCommEvent |= EV_RXCHAR; if( !SetCommMask( osHandle, dwCommEvent )) return GetLastError(); if( !WaitCommEvent( osHandle, &dwCommEvent, NULL )) return GetLastError(); return (dwCommEvent&EV_RXCHAR); } /* w32DeviceInputStream_getReadCountNC() */
bool cSerialStream::isRinging() { DWORD mask; CHECK(GetCommMask(m_serialHandle.getHandle()->getHandle(), &mask)); return (mask & EV_RING) == EV_RING; }
// Wait up to msec for data to become available for reading. // return 0 if timeout, or non-zero if one or more bytes are // received and can be read. -1 if an error occurs int Serial::Input_wait(int msec) { if (!port_is_open) return -1; #if defined(LINUX) || defined(MACOSX) fd_set rfds; struct timeval tv; tv.tv_sec = msec / 1000; tv.tv_usec = (msec % 1000) * 1000; FD_ZERO(&rfds); FD_SET(port_fd, &rfds); return select(port_fd+1, &rfds, NULL, NULL, &tv); #elif defined(WINDOWS) // http://msdn2.microsoft.com/en-us/library/aa363479(VS.85).aspx // http://msdn2.microsoft.com/en-us/library/aa363424(VS.85).aspx // http://source.winehq.org/WineAPI/WaitCommEvent.html COMSTAT st; DWORD errmask=0, eventmask=EV_RXCHAR, ret; OVERLAPPED ov; int r; // first, request comm event when characters arrive if (!SetCommMask(port_handle, EV_RXCHAR)) return -1; // look if there are characters in the buffer already if (!ClearCommError(port_handle, &errmask, &st)) return -1; //printf("Input_wait, %lu buffered, timeout = %d ms\n", st.cbInQue, msec); if (st.cbInQue > 0) return 1; ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (ov.hEvent == NULL) return -1; ov.Internal = ov.InternalHigh = 0; ov.Offset = ov.OffsetHigh = 0; if (WaitCommEvent(port_handle, &eventmask, &ov)) { //printf("Input_wait, WaitCommEvent, immediate success\n"); r = 1; } else { if (GetLastError() == ERROR_IO_PENDING) { ret = WaitForSingleObject(ov.hEvent, msec); if (ret == WAIT_OBJECT_0) { //printf("Input_wait, WaitCommEvent, delayed success\n"); r = 1; } else if (ret == WAIT_TIMEOUT) { //printf("Input_wait, WaitCommEvent, timeout\n"); GetCommMask(port_handle, &eventmask); r = 0; } else { // WAIT_FAILED or WAIT_ABANDONED //printf("Input_wait, WaitCommEvent, delayed error\n"); r = -1; } } else { //printf("Input_wait, WaitCommEvent, immediate error\n"); r = -1; } } SetCommMask(port_handle, 0); CloseHandle(ov.hEvent); return r; #endif }
/*================================================================= * Function ID : GetEventMask * Input : void * Output : DWORD& dwMask * Author : * Date : 2006 2 * Return : TRUE/FALSE * Description : 设置超时时间 * Notice : * : * *=================================================================*/ bool CComSmart::GetEventMask(DWORD& dwMask) { if( !GetCommMask(m_handle, &dwMask) ) { sprintf(m_szErrorText,"GetEventMask()出错[%ld]!", GetLastError()); return false; } return true; }
void CSerialPort::GetMask(DWORD& dwMask) { ASSERT(IsOpen()); if (!GetCommMask(m_hComm, &dwMask)) { TRACE(_T("Failed in call to GetCommMask\n")); AfxThrowSerialException(); } }
void EIO_Set(uv_work_t* req) { SetBaton* data = static_cast<SetBaton*>(req->data); if (data->rts) { EscapeCommFunction((HANDLE)data->fd, SETRTS); } else { EscapeCommFunction((HANDLE)data->fd, CLRRTS); } if (data->dtr) { EscapeCommFunction((HANDLE)data->fd, SETDTR); } else { EscapeCommFunction((HANDLE)data->fd, CLRDTR); } if (data->brk) { EscapeCommFunction((HANDLE)data->fd, SETBREAK); } else { EscapeCommFunction((HANDLE)data->fd, CLRBREAK); } DWORD bits = 0; GetCommMask((HANDLE)data->fd, &bits); bits &= ~(EV_CTS | EV_DSR); if (data->cts) { bits |= EV_CTS; } if (data->dsr) { bits |= EV_DSR; } if (!SetCommMask((HANDLE)data->fd, bits)) { ErrorCodeToString("Setting options on COM port (SetCommMask)", GetLastError(), data->errorString); return; } }
void EIO_Set(uv_work_t* req) { SetBaton* data = static_cast<SetBaton*>(req->data); if (data->rts) { EscapeCommFunction((HANDLE)data->fd, SETRTS); } else { EscapeCommFunction((HANDLE)data->fd, CLRRTS); } if (data->dtr) { EscapeCommFunction((HANDLE)data->fd, SETDTR); } else { EscapeCommFunction((HANDLE)data->fd, CLRDTR); } if (data->brk) { EscapeCommFunction((HANDLE)data->fd, SETBREAK); } else { EscapeCommFunction((HANDLE)data->fd, CLRBREAK); } DWORD bits = 0; GetCommMask((HANDLE)data->fd, &bits); bits &= ~(EV_CTS | EV_DSR); if (data->cts) { bits |= EV_CTS; } if (data->dsr) { bits |= EV_DSR; } // TODO check for error data->result = SetCommMask((HANDLE)data->fd, bits); }
// // The CommThread Function. ///线程函数 ///监视线程的大致流程: ///检查串口-->进入循环{WaitCommEvent(不阻塞询问)询问事件-->如果有事件来到-->到相应处理(关闭\读\写)} // DWORD WINAPI CSerialPort::CommThread(LPVOID pParam) { // Cast the void pointer passed to the thread back to // a pointer of CSerialPort class CSerialPort *port = (CSerialPort*)pParam; // Set the status variable in the dialog class to // TRUE to indicate the thread is running. ///TRUE表示线程正在运行 port->m_bThreadAlive = TRUE; // Misc. variables DWORD BytesTransfered = 0; DWORD Event = 0; DWORD CommEvent = 0; DWORD dwError = 0; COMSTAT comstat; BOOL bResult = TRUE; // Clear comm buffers at startup ///开始时清除串口缓冲 if (port->m_hComm) // check if the port is opened PurgeComm(port->m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT); // begin forever loop. This loop will run as long as the thread is alive. ///只要线程存在就不断读取数据 for (;;) { // Make a call to WaitCommEvent(). This call will return immediatly // because our port was created as an async port (FILE_FLAG_OVERLAPPED // and an m_OverlappedStructerlapped structure specified). This call will cause the // m_OverlappedStructerlapped element m_OverlappedStruct.hEvent, which is part of the m_hEventArray to // be placed in a non-signeled state if there are no bytes available to be read, // or to a signeled state if there are bytes available. If this event handle // is set to the non-signeled state, it will be set to signeled when a // character arrives at the port. // we do this for each port! /* WaitCommEvent函数第3个参数1pOverlapped可以是一个OVERLAPPED结构的变量指针 ,也可以是NULL,当用NULL时,表示该函数是同步的,否则表示该函数是异步的。 调用WaitCommEvent时,如果异步操作不能立即完成,会立即返回FALSE,系统在 WaitCommEvent返回前将OVERLAPPED结构成员hEvent设为无信号状态,等到产生通信 事件时,系统将其置有信号 */ bResult = WaitCommEvent(port->m_hComm, &Event, &port->m_ov);///表示该函数是异步的 if (!bResult) { // If WaitCommEvent() returns FALSE, process the last error to determin // the reason.. ///如果WaitCommEvent返回Error为FALSE,则查询错误信息 switch (dwError = GetLastError()) { case ERROR_IO_PENDING: ///正常情况,没有字符可读 { // This is a normal return value if there are no bytes // to read at the port. // Do nothing and continue break; } case 87:///系统错误 { // Under Windows NT, this value is returned for some reason. // I have not investigated why, but it is also a valid reply // Also do nothing and continue. break; } default:///发生其他错误,其中有串口读写中断开串口连接的错误 { // All other error codes indicate a serious error has // occured. Process this error. port->ProcessErrorMessage("WaitCommEvent()"); break; } } } else ///WaitCommEvent()能正确返回 { // If WaitCommEvent() returns TRUE, check to be sure there are // actually bytes in the buffer to read. // // If you are reading more than one byte at a time from the buffer // (which this program does not do) you will have the situation occur // where the first byte to arrive will cause the WaitForMultipleObjects() // function to stop waiting. The WaitForMultipleObjects() function // resets the event handle in m_OverlappedStruct.hEvent to the non-signelead state // as it returns. // // If in the time between the reset of this event and the call to // ReadFile() more bytes arrive, the m_OverlappedStruct.hEvent handle will be set again // to the signeled state. When the call to ReadFile() occurs, it will // read all of the bytes from the buffer, and the program will // loop back around to WaitCommEvent(). // // At this point you will be in the situation where m_OverlappedStruct.hEvent is set, // but there are no bytes available to read. If you proceed and call // ReadFile(), it will return immediatly due to the async port setup, but // GetOverlappedResults() will not return until the next character arrives. // // It is not desirable for the GetOverlappedResults() function to be in // this state. The thread shutdown event (event 0) and the WriteFile() // event (Event2) will not work if the thread is blocked by GetOverlappedResults(). // // The solution to this is to check the buffer with a call to ClearCommError(). // This call will reset the event handle, and if there are no bytes to read // we can loop back through WaitCommEvent() again, then proceed. // If there are really bytes to read, do nothing and proceed. bResult = ClearCommError(port->m_hComm, &dwError, &comstat); if (comstat.cbInQue == 0) continue; } // end if bResult ///主等待函数,会阻塞线程 // Main wait function. This function will normally block the thread // until one of nine events occur that require action. ///等待3个事件:关断/读/写,有一个事件发生就返回 Event = WaitForMultipleObjects(3, ///3个事件 port->m_hEventArray, ///事件数组 FALSE, ///有一个事件发生就返回 INFINITE);///超时时间 switch (Event) { case 0: { // Shutdown event. This is event zero so it will be // the higest priority and be serviced first. ///关断事件,关闭串口 CloseHandle(port->m_hComm); port->m_hComm=NULL; port->m_bThreadAlive = FALSE; // Kill this thread. break is not needed, but makes me feel better. //AfxEndThread(100); ::ExitThread(100); break; } case 1: // read event 将定义的各种消息发送出去 { GetCommMask(port->m_hComm, &CommEvent); if (CommEvent & EV_RXCHAR) //接收到字符,并置于输入缓冲区中 ReceiveChar(port); if (CommEvent & EV_CTS) //CTS信号状态发生变化 ::SendMessage(port->m_pOwner, WM_COMM_CTS_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr); if (CommEvent & EV_RXFLAG) //接收到事件字符,并置于输入缓冲区中 ::SendMessage(port->m_pOwner, WM_COMM_RXFLAG_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr); if (CommEvent & EV_BREAK) //输入中发生中断 ::SendMessage(port->m_pOwner, WM_COMM_BREAK_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr); if (CommEvent & EV_ERR) //发生线路状态错误,线路状态错误包括CE_FRAME,CE_OVERRUN和CE_RXPARITY ::SendMessage(port->m_pOwner, WM_COMM_ERR_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr); if (CommEvent & EV_RING) //检测到振铃指示 ::SendMessage(port->m_pOwner, WM_COMM_RING_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr); break; } case 2: // write event 发送数据 { // Write character event from port WriteChar(port); break; } default: { AfxMessageBox("接收有问题!"); break; } } // end switch } // close forever loop return 0; }
// // The CommThread Function. // UINT CSerialPort::CommThread(LPVOID pParam) { // Cast the void pointer passed to the thread back to // a pointer of CSerialPort class CSerialPort *port = (CSerialPort*)pParam; // Set the status variable in the dialog class to // TRUE to indicate the thread is running. port->m_bThreadAlive = TRUE; // Misc. variables DWORD BytesTransfered = 0; DWORD Event = 0; DWORD CommEvent = 0; DWORD dwError = 0; static COMSTAT comstat; BOOL bResult = TRUE; // Clear comm buffers at startup if (port->m_hComm) // check if the port is opened PurgeComm(port->m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT); // begin forever loop. This loop will run as long as the thread is alive. for (;;) { // Make a call to WaitCommEvent(). This call will return immediatly // because our port was created as an async port (FILE_FLAG_OVERLAPPED // and an m_OverlappedStructerlapped structure specified). This call will cause the // m_OverlappedStructerlapped element m_OverlappedStruct.hEvent, which is part of the m_hEventArray to // be placed in a non-signeled state if there are no bytes available to be read, // or to a signeled state if there are bytes available. If this event handle // is set to the non-signeled state, it will be set to signeled when a // character arrives at the port. // we do this for each port! bResult = WaitCommEvent(port->m_hComm, &Event, &port->m_ov); if (!bResult) { // If WaitCommEvent() returns FALSE, process the last error to determin // the reason.. switch (dwError = GetLastError()) { case ERROR_IO_PENDING: { // This is a normal return value if there are no bytes // to read at the port. // Do nothing and continue break; } case 87: { // Under Windows NT, this value is returned for some reason. // I have not investigated why, but it is also a valid reply // Also do nothing and continue. break; } default: { // All other error codes indicate a serious error has // occured. Process this error. port->ProcessErrorMessage("WaitCommEvent()"); break; } } } else { // If WaitCommEvent() returns TRUE, check to be sure there are // actually bytes in the buffer to read. // // If you are reading more than one byte at a time from the buffer // (which this program does not do) you will have the situation occur // where the first byte to arrive will cause the WaitForMultipleObjects() // function to stop waiting. The WaitForMultipleObjects() function // resets the event handle in m_OverlappedStruct.hEvent to the non-signelead state // as it returns. // // If in the time between the reset of this event and the call to // ReadFile() more bytes arrive, the m_OverlappedStruct.hEvent handle will be set again // to the signeled state. When the call to ReadFile() occurs, it will // read all of the bytes from the buffer, and the program will // loop back around to WaitCommEvent(). // // At this point you will be in the situation where m_OverlappedStruct.hEvent is set, // but there are no bytes available to read. If you proceed and call // ReadFile(), it will return immediatly due to the async port setup, but // GetOverlappedResults() will not return until the next character arrives. // // It is not desirable for the GetOverlappedResults() function to be in // this state. The thread shutdown event (event 0) and the WriteFile() // event (Event2) will not work if the thread is blocked by GetOverlappedResults(). // // The solution to this is to check the buffer with a call to ClearCommError(). // This call will reset the event handle, and if there are no bytes to read // we can loop back through WaitCommEvent() again, then proceed. // If there are really bytes to read, do nothing and proceed. bResult = ClearCommError(port->m_hComm, &dwError, &comstat); if (comstat.cbInQue == 0) continue; } // end if bResult // Main wait function. This function will normally block the thread // until one of nine events occur that require action. Event = WaitForMultipleObjects(3, port->m_hEventArray, FALSE, INFINITE); switch (Event) { case 0: { // Shutdown event. This is event zero so it will be // the higest priority and be serviced first. port->m_bThreadAlive = FALSE; // Kill this thread. break is not needed, but makes me feel better. AfxEndThread(100); break; } case 1: // read event { GetCommMask(port->m_hComm, &CommEvent); if (CommEvent & EV_CTS) ::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_CTS_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr); if (CommEvent & EV_RXFLAG) ::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_RXFLAG_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr); if (CommEvent & EV_BREAK) ::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_BREAK_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr); if (CommEvent & EV_ERR) ::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_ERR_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr); if (CommEvent & EV_RING) ::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_RING_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr); if (CommEvent & EV_RXCHAR) // Receive character event from port. ReceiveChar(port, comstat); break; } case 2: // write event { // Write character event from port WriteChar(port); break; } } // end switch } // close forever loop return 0; }
int RS232Interface::OpenSerial(int no) { UserDebug1(UserApp1, "RS232Interface::OpenSerial(%d) I\n", no); int ret_val = E2ERR_OPENFAILED; if (no >= 1 && no <= MAX_COMPORTS) { #ifdef _WINDOWS char str[MAXPATH]; snprintf(str, MAXPATH, "%s%d", profile->GetDevName(), no); hCom = CreateFile(str, GENERIC_READ | GENERIC_WRITE, 0, /* comm devices must be opened w/exclusive-access */ NULL, /* no security attrs */ OPEN_EXISTING, /* comm devices must use OPEN_EXISTING */ 0, /* not overlapped I/O */ NULL /* hTemplate must be NULL for comm devices */ ); if ( hCom != INVALID_HANDLE_VALUE ) { GetCommState(hCom, &old_dcb); GetCommTimeouts(hCom, &old_timeout); GetCommMask(hCom, &old_mask); if (wait_endTX_mode) SetCommMask(hCom, EV_TXEMPTY); else SetCommMask(hCom, 0); SetSerialTimeouts(); SetSerialParams(); ret_val = OK; } #else #ifdef _LINUX_ char devname[MAXPATH]; int chars_read; no--; //linux call ttyS0 --> COM1, ttyS1 --> COM2, etc.. // implement device locking in /var/lock/LCK..ttySx snprintf(lockname, MAXPATH, "%s/LCK..%s%d", profile->GetLockDir(), profile->GetDevName(), no); UserDebug1(UserApp2, "RS232Interface::OpenSerial() now lock the device %s\n", lockname); fd = open ((const char *)lockname,O_RDWR|O_EXCL|O_CREAT); if (fd < 0) { fd = open ((const char *)lockname,O_RDONLY); lockname[0]=0; UserDebug1(UserApp2, "RS232Interface::OpenSerial Can't lock port %d\n", no); if (fd < 0) return ret_val; chars_read = read(fd,devname,MAXLINESIZE-1); devname[chars_read]=0; UserDebug1(UserApp2, "RS232Interface::OpenSeriial locked by %s\n", devname); close(fd); return ret_val; } snprintf(devname, MAXPATH, "%10d\n", (int) getpid() ); write(fd, devname, strlen(devname)); close(fd); fd = INVALID_HANDLE_VALUE; snprintf(devname, MAXPATH, "%s/%s%d", profile->GetDevDir(), profile->GetDevName(), no); UserDebug1(UserApp2, "RS232Interface::OpenSerial() now open the device %s\n", devname); fd = open ((const char *)devname, O_RDWR|O_NONBLOCK|O_EXCL); // fd = open ((const char *)devname, O_RDWR); UserDebug1(UserApp2, "RS232Interface::OpenSerial open result = %d\n", fd); if (fd < 0) { UserDebug1(UserApp2, "RS232Interface::OpenSerial can't open the device %s\n", devname); unlink(lockname); return ret_val; } // Check for the needed IOCTLS #if defined(TIOCSBRK) && defined(TIOCCBRK) //check if available for compilation // Check if available during runtime if ((ioctl(fd,TIOCSBRK,0) == -1) || (ioctl(fd,TIOCCBRK,0) == -1)) { UserDebug(UserApp2, "RS232Interface::OpenPort IOCTL not available\n"); return ret_val; } #else close(fd); fd = INVALID_HANDLE_VALUE; unlink(lockname); return ret_val; #endif /*TIOCSBRK*/ /* open sets RTS and DTR, reset it */ #if defined(TIOCMGET) && defined(TIOCMSET) //check if available for compilation int flags; if (ioctl(fd,TIOCMGET, &flags)== -1) { UserDebug(UserApp2, "RS232Interface::OpenPort IOCTL not available\n"); close(fd); fd = INVALID_HANDLE_VALUE; unlink(lockname); return ret_val; } else { flags &= ~(TIOCM_RTS|TIOCM_DTR); if (ioctl(fd,TIOCMSET, &flags)== -1) { UserDebug(UserApp2, "RS232Interface::OpenPort IOCTL not available\n"); close(fd); fd = INVALID_HANDLE_VALUE; unlink(lockname); return ret_val; } } #endif /*TIOCMGET */ UserDebug(UserApp2, "RS232Interface::OpenPort GETATTR\n"); if (tcgetattr(fd, &old_termios) == -1) { UserDebug(UserApp2, "RS232Interface::OpenPort GETATTR failed\n"); close(fd); fd = INVALID_HANDLE_VALUE; unlink(lockname); return ret_val; } UserDebug(UserApp2, "RS232Interface::OpenPort SetTimeouts && Params\n"); if ( SetSerialTimeouts() != OK ) { UserDebug(UserApp2, "RS232Interface::OpenPort SetSerialTimeouts() failed\n"); close(fd); fd = INVALID_HANDLE_VALUE; unlink(lockname); } else if ( SetSerialParams() != OK ) { UserDebug(UserApp2, "RS232Interface::OpenPort SetSerialParams() failed\n"); close(fd); fd = INVALID_HANDLE_VALUE; unlink(lockname); } else { fd_clear_flag(fd, O_NONBLOCK); //Restore to blocking mode ret_val = OK; } #endif /*_LINUX_*/ #endif } UserDebug1(UserApp2, "RS232Interface::OpenSerial() = %d O\n", ret_val); return ret_val; }
int main(int argc, char *argv[]) { HANDLE hCommPort; const char* config_file = ".\\serie.ini"; unsigned int baud_rate = GetPrivateProfileInt("Configuracion", "Velocidad", 9600, config_file); unsigned int data_bits = GetPrivateProfileInt("Configuracion", "BitsDatos", 8, config_file); unsigned int stop_bits = GetPrivateProfileInt("Configuracion", "BitsParada", 2, config_file); char port_name[30]; unsigned int _len = GetPrivateProfileString("Configuracion", "Puerto", "COM1", port_name, sizeof(port_name), config_file); char parity[20]; unsigned int _parity_len = GetPrivateProfileString("Configuracion", "Paridad", "Sin paridad", parity, sizeof(parity), config_file); printf("Datos: %d %d %d %s %s\n", baud_rate, data_bits, stop_bits, port_name, parity); //-- Abre el puerto serie hCommPort = serie_abrir(port_name, baud_rate, data_bits, stop_bits, parity); if (hCommPort == INVALID_HANDLE_VALUE) { perror("ERROR: No se puede acceder al puerto serie."); exit(2); } DWORD mask; if (!GetCommMask(hCommPort, &mask)) { perror("GetCommMask"); exit(3); } if (!SetCommMask(hCommPort, mask | EV_ERR)) { perror("SetCommMask"); exit(4); } printf("Pulse la tecla ESC para empezar a leer\n"); while ( _getch() != ESC ) { /* Do nothing */ } //-- Crea el hilo encargado de la lectura de datos del puerto serie HANDLE hHiloLectura; DWORD idHiloLectura; hHiloLectura = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)HiloLectura, &hCommPort, 0, &idHiloLectura); if (hHiloLectura == NULL) { perror("ERROR: No se puede crear el hilo de lectura"); exit(5); } printf("Pulse la tecla ESC para salir\n"); //-- Bucle principal de escritura por el puerto serie char c; do { c = _getch(); if (c != ESC) { serie_escribir(hCommPort, &c, sizeof(c)); } } while (c != ESC); //-- Termina el hilo de lectura TerminateThread(hHiloLectura, 0); CloseHandle(hHiloLectura); //-- Cierra el puerto serie serie_cerrar(hCommPort); system("PAUSE"); return 0; }
DWORD HiloLectura(LPDWORD lpParam) { DWORD dwEvtMask; OVERLAPPED ov = { 0 }; ov.hEvent = CreateEvent(0, TRUE, 0, 0); //-- Recoge el manejador del puerto serie HANDLE hCommPort = (HANDLE)*lpParam; char szDatos[MAXCHARS + 1]; DWORD dwErrors; //-- Bucle infinito de lectura while (TRUE) { if (!WaitCommEvent(hCommPort, &dwEvtMask, &ov)) {} if (!ClearCommError(hCommPort, &dwErrors, NULL)) { perror("ClearCommError"); continue; } if (dwErrors & CE_FRAME) { printf("Frame error\n"); } if (dwErrors & CE_RXPARITY) { printf("Parity error\n"); } if (dwErrors & CE_OVERRUN) { printf("Overrun\n"); } if (dwErrors & CE_BREAK) { printf("CE_BREAK\n"); } if (dwErrors & CE_RXOVER) { printf("CE_RXOVER\n"); } //-- Espera a que haya algo que leer if (WAIT_OBJECT_0 == WaitForSingleObject(ov.hEvent, INFINITE)) { DWORD dwMask; if (GetCommMask(hCommPort, &dwMask)) { if (dwMask & EV_TXEMPTY) { ResetEvent(ov.hEvent); continue; } } //-- Lee los datos del puerto serie if (serie_leer(hCommPort, szDatos, sizeof(szDatos)) > 0) printf("%s", szDatos); else printf("serie_leer returned 0"); //-- Reinicia el estado del evento ResetEvent(ov.hEvent); } } return 0; }
int SIO_WaitForData(SIO_INFO *s,long timedelay) { #ifdef WINDOWS int ret; long tms; DWORD err; DWORD emask; COMMTIMEOUTS ct; COMSTAT comstat; /* sanity check */ if (s==NULL) return -1; tms=timedelay/1000; tms+=ADD_DELAY; ret=0; GetCommTimeouts(s->fd,&ct); if (timedelay==SIO_READ_WAIT_FOREVER) { ct.ReadIntervalTimeout=MAXDWORD; ct.ReadTotalTimeoutMultiplier=0; ct.ReadTotalTimeoutConstant=MAXDWORD; } else { ct.ReadIntervalTimeout=tms; ct.ReadTotalTimeoutMultiplier=10; ct.ReadTotalTimeoutConstant=tms; /* ct.ReadIntervalTimeout=10; ct.ReadTotalTimeoutMultiplier=10; ct.ReadTotalTimeoutConstant=100; */ } SetCommTimeouts(s->fd,&ct); /* have a quick look to see if there is data in the buffers * still ... and return notification to the caller without * doing any of the messy thread stuff with timeouts */ ClearCommError(s->fd,&emask,&comstat); if (comstat.cbInQue>0) return(1); #if 0 /* now wait for a character to arrive ... unfortunately this * operation does not have any form of timeout on it which * makes it rather useless for detecting IO! */ emask=EV_RXCHAR|EV_ERR|EV_RLSD|EV_CTS|EV_DSR; ret=WaitCommEvent(s->fd,&emask,NULL); if (ret) { /* we have a character we can read ... */ return(1); } else { err=GetLastError(); return(-1); } #endif /* get the worker thread to start doing something */ s->eventMask=EV_RXCHAR|EV_ERR|EV_RLSD|EV_CTS|EV_DSR; /* Custom: DCD? */ #ifdef NO_THREADS /* use overlapped I/O notification to simulate having * a timeout on WaitCommEvent() */ sio_init_overlapped(s); if (WaitCommEvent(s->fd,&s->eventMask,s->overlapped)==FALSE) { err=GetLastError(); if (err==ERROR_IO_PENDING) { if (sio_wait_overlapped(s,timedelay)) { return(1); } else { return(-1); } } } else { return(1); } #else /* !NO_THREADS */ /* this thread stuff works fine under Win95 but doesn't under WinNT */ SetEvent(s->hStartWait); err=WaitForSingleObject(s->hFinishedWait,tms); switch(err) { case WAIT_OBJECT_0: return(1); case WAIT_ABANDONED: case WAIT_TIMEOUT: default: { DWORD oldMask; /* make WaitCommEvent return in the worker thread */ GetCommMask(s->fd,&oldMask); SetCommMask(s->fd,0); SetCommMask(s->fd,oldMask); } return(-1); } #endif /* NO_THREADS */ #elif defined( __palmos__ ) Long timeout; /* sanity check */ if (s==NULL) return -1; if( timedelay==SIO_READ_WAIT_FOREVER ) { timeout = -1; } else { timeout = ( ( timedelay * sysTicksPerSecond ) / 1000000 ) + 1; } if( SerReceiveWait( s->fd, 1, (Long) timeout )!=0 ) return( -1 ); return( 1 ); #else /* !WINDOWS && !__palmos__ */ int ret; fd_set readfds; struct timeval tv, *tvwait; /* sanity check */ if (s==NULL) return -1; /* isn't the Unix way of doing this so much more elegant :-) */ FD_ZERO(&readfds); FD_SET(s->fd,&readfds); tv.tv_sec=0; tv.tv_usec=timedelay; if (timedelay==SIO_READ_WAIT_FOREVER) tvwait=NULL; else tvwait=&tv; ret=select(s->fd+1,&readfds,NULL,NULL,tvwait); /* if there is one descriptor ready for read then it is * a success ... so we can just use the return from select */ return(ret); #endif /* WINDOWS */ }
unsigned __stdcall CSerialCommHelper::ThreadFn(void*pvParam) { CSerialCommHelper* CommHelper = (CSerialCommHelper*) pvParam ; bool condition = true; DWORD EventMask=0; OVERLAPPED ov; memset(&ov,0,sizeof(ov)); ov.hEvent = CreateEvent( 0,true,0,0); HANDLE Handles[2]; Handles[0] = CommHelper->ThreadTerm; DWORD Wait; SetEvent(CommHelper->ThreadStarted); while ( condition ) { BOOL res = ::WaitCommEvent(CommHelper->CommPort,&EventMask, &ov) ; if ( !res ) { g_assert( GetLastError () == ERROR_IO_PENDING); } Handles[1] = ov.hEvent ; Wait = WaitForMultipleObjects (2,Handles,FALSE,INFINITE); switch ( Wait ) { case WAIT_OBJECT_0: { _endthreadex(1); } break; case WAIT_OBJECT_0 + 1: { DWORD Mask; if (GetCommMask(CommHelper->CommPort,&Mask) ) { if ( Mask == EV_TXEMPTY ) { MTXDBG(CRITICAL,_("Data sent")); ResetEvent ( ov.hEvent ); continue; } } //read data here... int accum = 0; CommHelper->SerialBuffer.LockBuffer(); try { std::string Debug; BOOL res = FALSE; DWORD BytesRead = 0; OVERLAPPED ovRead; memset(&ovRead,0,sizeof(ovRead)); ovRead.hEvent = CreateEvent( 0,true,0,0); do { ResetEvent( ovRead.hEvent ); char Tmp[1]; int iSize = sizeof ( Tmp ); memset(Tmp,0,sizeof Tmp); res = ::ReadFile(CommHelper->CommPort,Tmp,sizeof(Tmp),&BytesRead,&ovRead); if (!res ) { condition = FALSE; break; } if ( BytesRead > 0 ) { CommHelper->SerialBuffer.AddData ( Tmp,BytesRead ); accum += BytesRead; } }while (0);// BytesRead > 0 ); CloseHandle(ovRead.hEvent ); } catch(...) { g_assert(0); } //if we are not in started state then we should flush the queue...( we would still read the data) if (CommHelper->GetCurrentState() != SS_Started ) { accum = 0; CommHelper->SerialBuffer.Flush (); } CommHelper->SerialBuffer.UnLockBuffer(); MTXDBG(CRITICAL,_("RCSeri: Q Unlocked:")); if ( accum > 0 ) { MTXDBG(CRITICAL,_("CSerialCommHelper(worker thread): SetDataReadEvent() len:{%d} data:{%s}"),accum,(CommHelper->SerialBuffer.GetData()).c_str () ); CommHelper->SetDataReadEvent(); } ResetEvent ( ov.hEvent ); } break; }//switch } return 0; }
BOOL DmKdInitComPort( BOOL KdModemControl ) { char ComPortName[16]; ULONG Baud; DCB LocalDcb; COMMTIMEOUTS To; DWORD mask; Baud = (ULONG)KdOptions[KDO_BAUDRATE].value; sprintf( ComPortName, "\\\\.\\com%d", (ULONG)KdOptions[KDO_PORT].value ); // // Open the device // DmKdComPort = CreateFile( (PSZ)ComPortName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL ); if ( DmKdComPort == (HANDLE)-1 ) { return FALSE; } SetupComm(DmKdComPort,(DWORD)4096,(DWORD)4096); // // Create the events used by the overlapped structures for the // read and write. // ReadOverlapped.hEvent = CreateEvent( NULL, TRUE, FALSE,NULL ); if (!ReadOverlapped.hEvent) { return FALSE; } WriteOverlapped.hEvent = CreateEvent( NULL, TRUE, FALSE,NULL ); if (!WriteOverlapped.hEvent) { return FALSE; } ReadOverlapped.Offset = 0; ReadOverlapped.OffsetHigh = 0; WriteOverlapped.Offset = 0; WriteOverlapped.OffsetHigh = 0; // // Set up the Comm port.... // if (!GetCommState( DmKdComPort, &LocalDcb )) { return FALSE; } LocalDcb.BaudRate = Baud; LocalDcb.ByteSize = 8; LocalDcb.Parity = NOPARITY; LocalDcb.StopBits = ONESTOPBIT; LocalDcb.fDtrControl = DTR_CONTROL_ENABLE; LocalDcb.fRtsControl = RTS_CONTROL_ENABLE; LocalDcb.fBinary = TRUE; LocalDcb.fOutxCtsFlow = FALSE; LocalDcb.fOutxDsrFlow = FALSE; LocalDcb.fOutX = FALSE; LocalDcb.fInX = FALSE; if (!SetCommState( DmKdComPort, &LocalDcb )) { return FALSE; } // // Set the normal read and write timeout time. // The symbols are 10 millisecond intervals. // To.ReadIntervalTimeout = 0; To.ReadTotalTimeoutMultiplier = 0; To.ReadTotalTimeoutConstant = 4 * 1000; To.WriteTotalTimeoutMultiplier = 0; To.WriteTotalTimeoutConstant = 4 * 1000; if (!SetCommTimeouts( DmKdComPort, &To )) { return FALSE; } DmKdComEvent = 0; if (KdModemControl) { // // Debugger is being run over a modem. Set event to watch // carrier detect. // GetCommMask (DmKdComPort, &mask); mask = mask | EV_ERR; // | EV_RLSD; if (!SetCommMask (DmKdComPort, mask)) { return FALSE; } EventOverlapped.hEvent = CreateEvent( NULL, TRUE, FALSE,NULL ); if (!EventOverlapped.hEvent) { return FALSE; } EventOverlapped.Offset = 0; EventOverlapped.OffsetHigh = 0; DmKdComEvent = 1; // Fake an event, so modem status will be checked } InitializeCriticalSection(&csComPort); InitializeCriticalSection(&csPacket); return TRUE; }