/*! \brief Open a communication channel to the given port info. \details If the baudrate in \a portInfo is set to XBR_Invalid, the baud rate is automatically detected if possible. \param portInfo The details of the port that should be opened. Depending on the type of interface, parts of this parameter may be ignored. \param readBufSize The size of the read buffer in bytes (if appliccable to the device) \param writeBufSize The size of the write buffer in bytes (if appliccable to the device) \param options The options to enable (flow control, stop bits) \returns XRV_OK if the device was opened successfully */ XsResultValue SerialInterface::open(const XsPortInfo& portInfo, uint32_t readBufSize, uint32_t writeBufSize, PortOptions options) { m_endTime = 0; JLDEBUG(gJournal, portInfo); if (isOpen()) { JLALERT(gJournal, "Port " << portInfo.portName() << " is already open"); return (m_lastResult = XRV_ALREADYOPEN); } m_baudrate = portInfo.baudrate(); if (options&PO_RtsCtsFlowControl) JLTRACE(gJournal, "Requested RTS/CTS flow control"); if (options&PO_DtrDsrFlowControl) JLTRACE(gJournal, "Requested DTR/DSR flow control"); if (options&PO_XonXoffFlowControl) JLTRACE(gJournal, "Requested Xon/Xoff flow control"); #ifdef _WIN32 XsResultValue fail = XRV_OK; char winPortName[256]; // Open port sprintf(winPortName, "\\\\.\\%s", portInfo.portName().c_str()); m_handle = CreateFileA(winPortName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); if (m_handle == INVALID_HANDLE_VALUE) { JLDEBUG(gJournal, "Port " << portInfo.portName() << " cannot be opened"); return (m_lastResult = XRV_INPUTCANNOTBEOPENED); } DCB commState; //!< Stored settings about the serial port commState.DCBlength = sizeof(DCB); //Get the current state & then change it if (!GetCommState(m_handle, &commState)) // Get current state fail = XRV_ERROR; commState.BaudRate = (int) portInfo.baudrate(); // Setup the baud rate commState.Parity = NOPARITY; // Setup the Parity commState.ByteSize = 8; // Setup the data bits commState.StopBits = (options&PO_TwoStopBits)?TWOSTOPBITS:ONESTOPBIT; // Setup flow control commState.fDsrSensitivity = (options&PO_DtrDsrFlowControl)?TRUE:FALSE; commState.fOutxDsrFlow = (options&PO_DtrDsrFlowControl)?DTR_CONTROL_HANDSHAKE:DTR_CONTROL_DISABLE; commState.fOutxCtsFlow = (options&PO_RtsCtsFlowControl)?TRUE:FALSE; commState.fRtsControl = (options&PO_RtsCtsFlowControl)?RTS_CONTROL_HANDSHAKE:RTS_CONTROL_ENABLE; commState.fOutX = (options&PO_XonXoffFlowControl)?TRUE:FALSE; commState.fInX = commState.fOutX; if (!SetCommState(m_handle, (LPDCB)&commState)) // Set new state { // Bluetooth ports cannot always be opened with 2 stopbits // Now try to open port with 1 stopbit. commState.StopBits = ONESTOPBIT; if (!SetCommState(m_handle, (LPDCB)&commState)) fail = XRV_INPUTCANNOTBEOPENED; } std::string tmp = portInfo.portName().toStdString(); m_port = atoi(&tmp.c_str()[3]); sprintf(m_portname, "%s", tmp.c_str()); if (setTimeout(20)) fail = m_lastResult; // Other initialization functions if ((options&PO_DtrDsrFlowControl) == 0) { if (!EscapeCommFunction(m_handle, SETDTR)) // Set DTR (Calibration sensors need DTR to startup, won't hurt otherwise fail = XRV_ERROR; } if (!SetupComm(m_handle,readBufSize,writeBufSize)) // Set queue size fail = XRV_ERROR; // Remove any 'old' data in buffer //PurgeComm(m_handle, PURGE_TXCLEAR | PURGE_RXCLEAR); if (!PurgeComm(m_handle, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR)) fail = XRV_ERROR; if (fail != XRV_OK) { CloseHandle(m_handle); //lint !e534 m_handle = INVALID_HANDLE_VALUE; return (m_lastResult = fail); } #else // !_WIN32 (void)readBufSize; (void)writeBufSize; // Open port std::string pn = portInfo.portName().toStdString(); m_handle = ::open(pn.c_str(), O_RDWR | O_NOCTTY); // O_RDWR: Read+Write // O_NOCTTY: Raw input, no "controlling terminal" // O_NDELAY: Don't care about DCD signal if (m_handle < 0) { // Port not open return m_lastResult = XRV_INPUTCANNOTBEOPENED; } // Check if the file is already opened by someome else (other thread/process) if (flock(m_handle, LOCK_EX | LOCK_NB)) { closeLive(); return m_lastResult = XRV_INPUTCANNOTBEOPENED; } /* Start configuring of port for non-canonical transfer mode */ // Get current options for the port if (tcgetattr(m_handle, &m_commState) != 0) return XRV_ERROR; // Set baudrate. if (cfsetispeed(&m_commState, portInfo.baudrate()) != 0) return XRV_ERROR; if (cfsetospeed(&m_commState, portInfo.baudrate()) != 0) return XRV_ERROR; // Enable the receiver and set local mode m_commState.c_cflag |= (CLOCAL | CREAD); // Set character size to data bits and set no parity Mask the characte size bits m_commState.c_cflag &= ~(CSIZE|PARENB|PARODD); m_commState.c_cflag |= CS8; // Select 8 data bits m_commState.c_cflag = setBitsEnabled(m_commState.c_cflag, (tcflag_t)CSTOPB, (options&PO_TwoStopBits) == PO_TwoStopBits); // Hardware flow control m_commState.c_cflag = setBitsEnabled(m_commState.c_cflag, (tcflag_t)CRTSCTS, (options&PO_RtsCtsFlowControl) == PO_RtsCtsFlowControl); #ifdef CDTRDSR m_commState.c_cflag = setBitsEnabled(m_commState.c_cflag, (tcflag_t)CDTRDSR, (options&PO_DtrDsrFlowControl) == PO_DtrDsrFlowControl); #endif m_commState.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|ICANON|ISIG|IEXTEN); // Software flow control m_commState.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|INPCK|ISTRIP|INLCR|IGNCR|ICRNL); m_commState.c_iflag = setBitsEnabled(m_commState.c_iflag, (tcflag_t)(IXON|IXOFF), options&PO_XonXoffFlowControl); // Set Raw output m_commState.c_oflag &= ~OPOST; // Timeout 0.001 sec for first byte, read minimum of 0 bytes m_commState.c_cc[VMIN] = 0; m_commState.c_cc[VTIME] = (m_timeout+99)/100; // 1 // Set the new options for the port if (tcsetattr(m_handle,TCSANOW, &m_commState) != 0) return XRV_INPUTCANNOTBEOPENED; #if defined(JLLOGLEVEL) && JLLOGLEVEL <= JLL_ALERT termios checkCommState; if (tcgetattr(m_handle, &checkCommState) != 0) return XRV_ERROR; if (cfgetispeed(&checkCommState) != portInfo.baudrate()) JLALERT(gJournal, "Set baudrate doesn't match requested baudrate"); if (cfgetospeed(&checkCommState) != portInfo.baudrate()) JLALERT(gJournal, "Set baudrate doesn't match requested baudrate"); if (options&PO_RtsCtsFlowControl && !(checkCommState.c_cflag&CRTSCTS)) JLALERT(gJournal, "Requested RTS/CTS flow control, but could not be set."); if (options&PO_DtrDsrFlowControl && #ifdef CDTRDSR !(checkCommState.c_cflag&CDTRDSR) #else false #endif ) JLALERT(gJournal, "Requested DTR/DSR flow control, but could not be set."); if (options&PO_XonXoffFlowControl && !((checkCommState.c_iflag&(IXON|IXOFF)) == (IXON|IXOFF))) JLALERT(gJournal, "Requested Xon/Xoff flow control, but could not be set."); #endif // JLLOGLEVEL < JLL_ALERT #if defined(JLLOGLEVEL) && JLLOGLEVEL <= JLL_DEBUG #define CHECK_COMMSTATE(req, res, field)\ if (req.field != res.field) \ {\ JLDEBUG(gJournal, "field " << #field << " does not match");\ JLDEBUG(gJournal, "actual : " << std::oct << (uint64_t)res.field);\ JLDEBUG(gJournal, "expected: " << std::oct << (uint64_t)req.field);\ } #else #define CHECK_COMMSTATE(req, res, field) #endif CHECK_COMMSTATE(m_commState, checkCommState, c_cflag); CHECK_COMMSTATE(m_commState, checkCommState, c_iflag); CHECK_COMMSTATE(m_commState, checkCommState, c_oflag); CHECK_COMMSTATE(m_commState, checkCommState, c_cc[VMIN]); CHECK_COMMSTATE(m_commState, checkCommState, c_cc[VTIME]); m_port = 1; sprintf(m_portname, "%s", pn.c_str()); tcflush(m_handle, TCIOFLUSH); // setting RTS and DTR; RTS for Xbus Master, DTR for calibration sensors int cmbits; if (ioctl(m_handle, TIOCMGET, &cmbits) < 0) { JLDEBUG(gJournal, "TIOCMGET failed, which is OK for USB connected MkIV devices"); } if ((options&PO_RtsCtsFlowControl) == 0) cmbits = setBitsEnabled(cmbits, TIOCM_RTS, true); // else don't touch them cmbits = setBitsEnabled(cmbits, TIOCM_DTR, !(options&PO_DtrDsrFlowControl)); if (ioctl(m_handle, TIOCMSET, &cmbits) < 0) { JLDEBUG(gJournal, "TIOCMSET failed, which is OK for USB connected MkIV devices"); } #endif // !_WIN32 JLDEBUG(gJournal, "Port " << portInfo.portName().toStdString() << " opened"); return (m_lastResult = XRV_OK); }
void serialFlushOutput(SerialPort *SP) { PurgeComm(SP->comPort, PURGE_TXCLEAR); }
// // 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; }
// // 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; char *szPort = new char[50]; 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 sprintf(szPort, "\\\\.\\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 [] 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 ///配置 ///分别调用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; //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); // release critical section ///释放临界资源 LeaveCriticalSection(&m_csCommunicationSync); //TRACE("Initialisation for communicationport %d completed.\nUse Startmonitor to communicate.\n", portnr); return TRUE; }
int ComRWTool::OpenCom(const char* pPort, int nBaudRate, int nParity, int nByteSize, int nStopBits) { if (m_bOpen) { return COMMUN_ERROR_OK; } if (pPort == NULL) { return COMMUN_ERROR_BAD_PARARM; } string strCom = pPort; if (strCom.find("\\\\.\\") == strCom.npos) { strCom = "\\\\.\\" + strCom; } if(m_hComm != NULL) { CloseHandle(m_hComm); m_hComm = NULL; } DCB dcb; // 串口控制块 COMMTIMEOUTS timeouts = { // 串口超时控制参数 100, // 读字符间隔超时时间: 100 ms 1, // 读操作时每字符的时间: 1 ms (n个字符总共为n ms) 500, // 基本的(额外的)读超时时间: 500 ms 1, // 写操作时每字符的时间: 1 ms (n个字符总共为n ms) 100}; // 基本的(额外的)写超时时间: 100 ms m_hComm = CreateFileA(strCom.c_str(), // 串口名称或设备路径 GENERIC_READ | GENERIC_WRITE, // 读写方式 0, // 共享方式:独占 NULL, // 默认的安全描述符 OPEN_EXISTING, // 创建方式 0, // 不需设置文件属性 NULL); // 不需参照模板文件 if(m_hComm == NULL || m_hComm == INVALID_HANDLE_VALUE) { CK_OutputDebugString("打开串口失败 err:%d",GetLastError()); return COMMUN_ERROR_FAIL; // 打开串口失败 } GetCommState(m_hComm, &dcb); // 取DCB dcb.BaudRate = nBaudRate; dcb.ByteSize = nByteSize; dcb.Parity = nParity; dcb.StopBits = nStopBits; SetCommState(m_hComm, &dcb); // 设置DCB SetupComm(m_hComm, 4096, 1024); // 设置输入输出缓冲区大小 SetCommTimeouts(m_hComm, &timeouts); // 设置超时 PurgeComm(m_hComm ,PURGE_TXCLEAR|PURGE_RXCLEAR); m_strPort = pPort; GetCommState(m_hComm, &dcb); m_hQuitEvent = CreateEvent(NULL,TRUE,FALSE,NULL); if (NULL == m_hQuitEvent) { CK_OutputDebugString("COM:Create m_hEventQuit failed!err:%d",GetLastError()); CloseCom(); return COMMUN_ERROR_HANDLE_FAILED; } m_bOpen = true; return COMMUN_ERROR_OK; }
void CKerrControl::InitControllers() { // Kerr controller require the ID of each Servo sub-controller to be initialized at startup // All controllers start with ID=0, but only the first will respond. // So we change first one to 1, and the second to 2. /* From the Kerr "Arduino-Servo SC" user's manual: PicSrvSC.pdf (page 6): 1. On power-up, all modules assume a default address of 0x00, and each will set its ADDR_OUT signal HIGH. Furthermore, a module’s communications will be disabled completely until its ADDR_IN signal goes LOW. If the ADDR_OUT and ADDR_IN signals are daisy-chained as described above, all modules will be disabled except for the module furthest from the host. 2. The host starts by sending a Set Address command to module 0, changing its address to a value of 1. A side affect of the Set Address command is that the module will lower the its ADDR_OUT signal. 3. At this point, the next module in line is enabled with an address of 0. The host then sends a command to module 0 to change its address to a value of 2. 4. This process is continued until all modules have been assigned unique addresses. */ if( m_ControllerIDsInitialized ) { return; // only do once! } m_ControllerIDsInitialized = TRUE; // Send a bunch of zeros to get the Kerr control synchronized m_KerrCmd.ID = 0; // Address of Servo to access use 0 for initial start-up m_KerrCmd.Command = 0; m_KerrCmd.Data[0] = 0; m_KerrCmd.Data[1] = 0; m_KerrCmd.Data[2] = 0; m_KerrCmd.Data[3] = 0; m_KerrCmd.Data[4] = 0; m_KerrCmd.Data[5] = 0; m_KerrCmd.Data[6] = 0; m_KerrCmd.Data[7] = 0; m_KerrCmd.Data[8] = 0; m_KerrCmd.Data[9] = 0; m_KerrCmd.Data[10] = 0; m_KerrCmd.Data[11] = 0; m_KerrCmd.Data[12] = 0; m_KerrCmd.Data[13] = 0; m_KerrCmd.Data[14] = 0; m_KerrCmd.Data[15] = 0; SendCmd(16,0, FALSE); // no response expected, just flushing the port m_KerrCmd.ID = 0; // Address of Servo to access use 0 for initial start-up m_KerrCmd.Command = 0x0E; // Send NOP to just get a status back (which is ignored) SendCmd(0, 0, FALSE); m_KerrCmd.ID = 0xFF; // Address of Servo - FF = all servos (default group) m_KerrCmd.Command = KERR_CMD_HARD_RESET; // High Nibble contains number of Data Bytes SendCmd(0,0, FALSE); // No response to Reset command Sleep(100); // Purge the comm port input and output of junk if( (INVALID_HANDLE_VALUE != g_hKerrServoCommPort) && (SIMULATED_SIO_HANDLE != g_hKerrServoCommPort) ) { if( !PurgeComm(g_hKerrServoCommPort, (PURGE_TXCLEAR | PURGE_RXCLEAR)) ) { ROBOT_ASSERT(0); // Purge failed. Need to call GetLastError(). } } // Set the first servo controller ID m_KerrCmd.ID = 0; // Address of Servo to access use 0 for initial start-up m_KerrCmd.Command = KERR_CMD_SET_ADDRESS + 0x20; // High Nibble contains number of Data Bytes m_KerrCmd.Data[0] = KERR_ARM_MOTOR_ID_RIGHT; // Individual Address = 1 m_KerrCmd.Data[1] = 0xFF; // No Group Address SendCmd(2); Sleep(100); // Set the second servo controller ID m_KerrCmd.ID = 0; // Address of Servo to access use 0 for initial start-up m_KerrCmd.Command = KERR_CMD_SET_ADDRESS + 0x20; // High Nibble contains number of Data Bytes m_KerrCmd.Data[0] = KERR_ARM_MOTOR_ID_LEFT; // Individual Address = 2 m_KerrCmd.Data[1] = 0xFF; // No Group Address SendCmd(2); // Set the Amplifier Gain m_KerrCmd.ID = KERR_ARM_MOTOR_ID_RIGHT; // Address of Servo m_KerrCmd.Command = 0xF6; m_KerrCmd.Data[0] = 0x64; m_KerrCmd.Data[1] = 0x00; m_KerrCmd.Data[2] = 0xE8; m_KerrCmd.Data[3] = 0x03; m_KerrCmd.Data[4] = 0x00; m_KerrCmd.Data[5] = 0x00; m_KerrCmd.Data[6] = 0x00; m_KerrCmd.Data[7] = 0x00; m_KerrCmd.Data[8] = 0xFF; m_KerrCmd.Data[9] = 0x00; m_KerrCmd.Data[10] = 0xA0; m_KerrCmd.Data[11] = 0x0F; m_KerrCmd.Data[12] = 0x01; m_KerrCmd.Data[13] = 0x01; m_KerrCmd.Data[14] = 0x01; SendCmd(15); m_KerrCmd.ID = KERR_ARM_MOTOR_ID_LEFT; // Address of Servo m_KerrCmd.Command = 0xF6; m_KerrCmd.Data[0] = 0x64; m_KerrCmd.Data[1] = 0x00; m_KerrCmd.Data[2] = 0xE8; m_KerrCmd.Data[3] = 0x03; m_KerrCmd.Data[4] = 0x00; m_KerrCmd.Data[5] = 0x00; m_KerrCmd.Data[6] = 0x00; m_KerrCmd.Data[7] = 0x00; m_KerrCmd.Data[8] = 0xFF; m_KerrCmd.Data[9] = 0x00; m_KerrCmd.Data[10] = 0xA0; m_KerrCmd.Data[11] = 0x0F; m_KerrCmd.Data[12] = 0x01; m_KerrCmd.Data[13] = 0x01; m_KerrCmd.Data[14] = 0x01; SendCmd(15); // In case the arm was up when reset, the counter is now not at zero // so, reset it to get it close enough to allow home calibration to work right m_KerrCmd.ID = KERR_ARM_MOTOR_ID_RIGHT; // First Arm m_KerrCmd.Command = KERR_CMD_RESET_POS; // High Nibble contains number of Data Bytes (none) SendCmd(0); m_KerrCmd.ID = KERR_ARM_MOTOR_ID_LEFT; // Second Arm m_KerrCmd.Command = KERR_CMD_RESET_POS; // High Nibble contains number of Data Bytes (none) SendCmd(0); }
/** * シリアルポートをオープンする. * * @param devfile シリアルポートのデバイスファイル名. * @param baud ボーレート. * * @retval !NULL ハンドラ。 * @retval NULL 失敗。 */ SERIAL *serial_open(const char *devfile, const enum SerialBaud baud) { DCB param; int baudrate = 0; /* * シリアルデスクリプタの管理領域を確保する. */ SERIAL *s = (SERIAL *) malloc(sizeof(SERIAL)); if (s == NULL) { return NULL; } /* * ポート名を決定する. */ if (strstr(devfile, "\\\\.\\") == NULL) { strcpy(s->devfile, "\\\\.\\"); } else { strcpy(s->devfile, ""); } strcat(s->devfile, devfile); /* * ポートを開く. */ s->handle = CreateFile( s->devfile, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); if (s->handle == INVALID_HANDLE_VALUE) { free(s); return NULL; } /* * ポートの設定を行う。 */ if (!GetCommState(s->handle, ¶m)) { free(s); return NULL; } switch (baud) { case SerialBaud2400: param.BaudRate = CBR_2400; break; case SerialBaud4800: param.BaudRate = CBR_4800; break; case SerialBaud9600: param.BaudRate = CBR_9600; break; case SerialBaud19200: param.BaudRate = CBR_19200; break; case SerialBaud38400: param.BaudRate = CBR_38400; break; default: param.BaudRate = CBR_9600; break; } param.ByteSize = 8; param.StopBits = ONESTOPBIT; param.Parity = NOPARITY; if(!SetCommState(s->handle, ¶m)){ free(s); return NULL; } /* * バッファの内容を捨てる. */ PurgeComm(s->handle, PURGE_RXCLEAR); PurgeComm(s->handle, PURGE_TXCLEAR); PurgeComm(s->handle, PURGE_RXABORT); PurgeComm(s->handle, PURGE_TXABORT); return s; }
int open_comport() { #ifdef ALLEGRO_WINDOWS DCB dcb; COMMTIMEOUTS timeouts; DWORD bytes_written; char temp_str[16]; #endif if (comport.status == READY) // if the comport is open, close_comport(); // close it #ifdef ALLEGRO_WINDOWS // Naming of serial ports 10 and higher: See // http://www.connecttech.com/KnowledgeDatabase/kdb227.htm // http://support.microsoft.com/?id=115831 sprintf(temp_str, "\\\\.\\COM%i", comport.number + 1); com_port = CreateFile(temp_str, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0); if (com_port == INVALID_HANDLE_VALUE) { comport.status = NOT_OPEN; //port was not open return -1; // return error } // Setup comport GetCommState(com_port, &dcb); dcb.BaudRate = comport.baud_rate; dcb.ByteSize = 8; dcb.StopBits = ONESTOPBIT; dcb.fParity = FALSE; dcb.Parity = NOPARITY; dcb.fOutxCtsFlow = FALSE; dcb.fOutxDsrFlow = FALSE; dcb.fOutX = FALSE; dcb.fInX = FALSE; dcb.fDtrControl = DTR_CONTROL_ENABLE; dcb.fRtsControl = RTS_CONTROL_ENABLE; dcb.fDsrSensitivity = FALSE; dcb.fErrorChar = FALSE; dcb.fAbortOnError = FALSE; SetCommState(com_port, &dcb); // Setup comm timeouts timeouts.ReadIntervalTimeout = MAXWORD; timeouts.ReadTotalTimeoutMultiplier = 0; timeouts.ReadTotalTimeoutConstant = 0; timeouts.WriteTotalTimeoutMultiplier = TX_TIMEOUT_MULTIPLIER; timeouts.WriteTotalTimeoutConstant = TX_TIMEOUT_CONSTANT; SetCommTimeouts(com_port, &timeouts); // Hack to get around Windows 2000 multiplying timeout values by 15 GetCommTimeouts(com_port, &timeouts); if (TX_TIMEOUT_MULTIPLIER > 0) timeouts.WriteTotalTimeoutMultiplier = TX_TIMEOUT_MULTIPLIER * TX_TIMEOUT_MULTIPLIER / timeouts.WriteTotalTimeoutMultiplier; if (TX_TIMEOUT_CONSTANT > 0) timeouts.WriteTotalTimeoutConstant = TX_TIMEOUT_CONSTANT * TX_TIMEOUT_CONSTANT / timeouts.WriteTotalTimeoutConstant; SetCommTimeouts(com_port, &timeouts); // If the port is Bluetooth, make sure device is active PurgeComm(com_port, PURGE_TXCLEAR|PURGE_RXCLEAR); WriteFile(com_port, "?\r", 2, &bytes_written, 0); if (bytes_written != 2) // If Tx timeout occured { PurgeComm(com_port, PURGE_TXCLEAR|PURGE_RXCLEAR); CloseHandle(com_port); comport.status = NOT_OPEN; //port was not open return -1; } #else com_port = comm_port_init(comport.number); comm_port_set_baud_rate(com_port, comport.baud_rate); comm_port_set_parity(com_port, NO_PARITY); comm_port_set_data_bits(com_port, BITS_8); comm_port_set_stop_bits(com_port, STOP_1); comm_port_set_flow_control(com_port, NO_CONTROL); if (comm_port_install_handler(com_port) != 1) { comport.status = NOT_OPEN; //port was not open return -1; // return error } #endif serial_time_out = FALSE; comport.status = READY; return 0; // everything is okay }
DWORD WINAPI CommMonitor( LPSTR lpData) { CommData SYSTEMTIME SystemTime; int i,nItemCount,nPackLen=0; BYTE PackFun ; BOOL OddFlag=FALSE; LPSTR lpPointer,lptemp1,lptemp2,hRXBuffer=(LPSTR)RxBuffer; char *p_ACK1="\x10\x31"; char *p_ACK0="\x10\x30"; Init() ResetOpPointer() ResetRxPointer() nItemCount =0; FillDevName() SetCommWaitMask(EV_RXFLAG) PurgeComm( hComm, PURGE_RXCLEAR ); while (TRUE) { WaitEvent(EV_RXFLAG) GetInQueueLength(dwReadLength) ReadCommBlock(dwReadLength) lptemp1=strbchrnb(lpRxPointer,'[',1,(int)dwReadLength+5); PackFun= *(lptemp1+c_FuncNumOff); { case '0': case 'D': ResetRxPointer() ResetOpPointer() continue; case '1': if (lptemp1!=lpOpPointer) { for (i=0;*hRXBuffer!='[';hRXBuffer++,i++); memmove(lpOpPointer ,hRXBuffer , (int)(lpRxPointer-hRXBuffer)); lpRxPointer=lpRxPointer-i; hRXBuffer=(LPSTR)RxBuffer; } continue; case '5': if ((*lpOpPointer)!='[') { for (i=0;*hRXBuffer!='[';hRXBuffer++,i++); memmove(lpOpPointer ,hRXBuffer , (int)(lpRxPointer-hRXBuffer)); lpRxPointer=lpRxPointer-i; hRXBuffer=(LPSTR)RxBuffer; continue; case '9': break; default : continue; } wSampleID =(int)StrToInt(lpOpPointer+7,5); GetLocalTime(&SystemTime); lpPointer=strchrnb(lpOpPointer+1,'[',2,70); while(*(lpPointer+2)=='2') { FillSampleID(nItemCount, wSampleID) lptemp1=strchrnb(lpPointer,',',1,4)+1; lptemp2=strchrnb(lptemp1,',',1,5); FillItemName(nItemCount, lptemp1,(lptemp2-lptemp1)) lptemp1=strchrnb(lptemp2+1,',',2,20)+1; for (;*lptemp1==' ';lptemp1++); lptemp2=strchrnb(lptemp1,',',1,10); FillResult(nItemCount,lptemp1,(int)(lptemp2-lptemp1)) FillDate(nItemCount, SystemTime.wYear, SystemTime.wMonth, SystemTime.wDay, SystemTime.wHour) lpPointer=strchrnb(lptemp2+1,'[',1,40); nItemCount++; } if(nItemCount>0) { (*lpResultProcessRoutine)(lpDevice->nDevNO, OutResult, nItemCount); lpDevice->dwRecordCount+=nItemCount; } nItemCount=0; // nPackLen=0; ResetRxPointer() ResetOpPointer() hRXBuffer=(LPSTR)RxBuffer; } return TRUE; } // end of CommWatchProc() void WINAPI BeforeSetCommState(DCB *pComDcb) { pComDcb->EvtChar ='['; }
int xbee_ser_open( xbee_serial_t *serial, uint32_t baudrate) { char buffer[sizeof("\\\\.\\COM9999")]; HANDLE hCom; COMMTIMEOUTS timeouts; int err; if (serial == NULL || serial->comport > 9999) { #ifdef XBEE_SERIAL_VERBOSE printf( "%s: -EINVAL (serial=%p)\n", __FUNCTION__, serial); #endif return -EINVAL; } // if XBee's existing hCom handle is not null, need to close it // (unless we're just changing the baud rate?) // Assume serial port has not changed if port is already open, and skip the // CreateFile step. if (serial->hCom) { // serial port is already open hCom = serial->hCom; serial->hCom = NULL; #ifdef XBEE_SERIAL_VERBOSE printf( "%s: port already open (hCom=%p)\n", __FUNCTION__, hCom); #endif } else { snprintf( buffer, sizeof buffer, "\\\\.\\COM%u", serial->comport); hCom = CreateFile( buffer, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hCom == INVALID_HANDLE_VALUE) { #ifdef XBEE_SERIAL_VERBOSE printf( "%s: error %lu opening handle to %s\n", __FUNCTION__, GetLastError(), buffer); #endif return -EIO; } } // set up a transmit and receive buffers SetupComm( hCom, XBEE_SER_RX_BUFSIZE, XBEE_SER_TX_BUFSIZE); /* Set the COMMTIMEOUTS structure. Per MSDN documentation for ReadIntervalTimeout, "A value of MAXDWORD, combined with zero values for both the ReadTotalTimeoutConstant and ReadTotalTimeoutMultiplier members, specifies that the read operation is to return immediately with the bytes that have already been received, even if no bytes have been received." */ if (!GetCommTimeouts( hCom, &timeouts)) { #ifdef XBEE_SERIAL_VERBOSE printf( "%s: %s failed (%lu initializing COM%u)\n", __FUNCTION__, "GetCommTimeouts", GetLastError(), serial->comport); #endif CloseHandle( hCom); return -EIO; } timeouts.ReadIntervalTimeout = MAXDWORD; timeouts.ReadTotalTimeoutMultiplier = 0; timeouts.ReadTotalTimeoutConstant = 0; if (!SetCommTimeouts( hCom, &timeouts)) { #ifdef XBEE_SERIAL_VERBOSE printf( "%s: %s failed (%lu initializing COM%u)\n", __FUNCTION__, "SetCommTimeouts", GetLastError(), serial->comport); #endif CloseHandle( hCom); return -EIO; } PurgeComm( hCom, PURGE_TXCLEAR | PURGE_TXABORT | PURGE_RXCLEAR | PURGE_RXABORT); serial->hCom = hCom; err = xbee_ser_baudrate( serial, baudrate); if (err) { serial->hCom = NULL; return err; } #ifdef XBEE_SERIAL_VERBOSE printf( "%s: SUCCESS COM%u opened (hCom=%p, baud=%u)\n", __FUNCTION__, serial->comport, hCom, baudrate); #endif return 0; }
// // 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; }
/****************************************************************************** * Name: ProcessCommRequests * * Purpose: worker thread function that communicates with the com port ******************************************************************************/ UINT AFX_CDECL ProcessCommRequests( LPVOID lParam) { if( !lParam) return 2; DWORD dwWait; // loop ends by returning on error or when the terminate flag is set while( TRUE) { dwWait = WaitForSingleObject( COMMEVENT, TIMEOUT); while( dwWait!=WAIT_OBJECT_0) { // check for error if( dwWait==WAIT_ABANDONED_0 || dwWait == WAIT_FAILED) { ResetEvent( COMMEVENT); PurgeComm( HPORT, PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR); return 1; } // check for termination if( TERMINATE_FLAG) { ResetEvent( COMMEVENT); PurgeComm( HPORT, PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR); return 0; } dwWait = WaitForSingleObject( COMMEVENT, TIMEOUT); } CCommRequest* pRequest = (((CCommDevice*)lParam)->m_pRequest); switch( pRequest->m_dwRequestType) { case REQUEST_READ: { // clear request error field pRequest->m_dwRequestError = ERR_NOERROR; DWORD dwBytesRead = READFILE( pRequest->m_lpszResult, pRequest->m_dwResultLength, pRequest->m_dwMaxTries, pRequest->m_dwTimeout); pRequest->m_dwResultLength = dwBytesRead; pRequest->m_dwRequestError = COMMSTATE; COMMSTATE = ERR_NOERROR; ((CCommDevice*)lParam)->m_pRequest = NULL; ResetEvent( COMMEVENT); if( !dwBytesRead) { switch( pRequest->m_dwRequestError) { case ERR_PORTERROR: case ERR_NOPORTLOCK: case ERR_NODATALOCK: { if( pRequest->m_pWindow && ::IsWindow( pRequest->m_pWindow->m_hWnd)) pRequest->m_pWindow->PostMessage( WM_COMM_REQUEST_COMPLETE, 0, (long)pRequest); else if( pRequest->m_pCompleteFunction) (*pRequest->m_pCompleteFunction)( pRequest); return 1; } case ERR_TERMINATED: { if( pRequest->m_pWindow && ::IsWindow( pRequest->m_pWindow->m_hWnd)) pRequest->m_pWindow->PostMessage( WM_COMM_REQUEST_COMPLETE, 0, (long)pRequest); else if( pRequest->m_pCompleteFunction) (*pRequest->m_pCompleteFunction)( pRequest); return 0; } } } if( pRequest->m_pWindow && ::IsWindow( pRequest->m_pWindow->m_hWnd)) pRequest->m_pWindow->PostMessage( WM_COMM_REQUEST_COMPLETE, 0, (long)pRequest); else if( pRequest->m_pCompleteFunction) (*pRequest->m_pCompleteFunction)( pRequest); break; } case REQUEST_WRITE: { // clear request error field pRequest->m_dwRequestError = ERR_NOERROR; DWORD dwBytesWritten = WRITEFILE( pRequest->m_lpszData, pRequest->m_dwDataLength); pRequest->m_dwDataLength = dwBytesWritten; pRequest->m_dwRequestError = COMMSTATE; COMMSTATE = ERR_NOERROR; ((CCommDevice*)lParam)->m_pRequest = NULL; ResetEvent( COMMEVENT); if( !dwBytesWritten) { switch( pRequest->m_dwRequestError) { case ERR_PORTERROR: case ERR_NOPORTLOCK: { if( pRequest->m_pWindow && ::IsWindow( pRequest->m_pWindow->m_hWnd)) pRequest->m_pWindow->PostMessage( WM_COMM_REQUEST_COMPLETE, 0, (long)pRequest); else if( pRequest->m_pCompleteFunction) (*pRequest->m_pCompleteFunction)( pRequest); return 1; } case ERR_TERMINATED: { if( pRequest->m_pWindow && ::IsWindow( pRequest->m_pWindow->m_hWnd)) pRequest->m_pWindow->PostMessage( WM_COMM_REQUEST_COMPLETE, 0, (long)pRequest); else if( pRequest->m_pCompleteFunction) (*pRequest->m_pCompleteFunction)( pRequest); return 0; } } } if( pRequest->m_pWindow && ::IsWindow( pRequest->m_pWindow->m_hWnd)) pRequest->m_pWindow->PostMessage( WM_COMM_REQUEST_COMPLETE, 0, (long)pRequest); else if( pRequest->m_pCompleteFunction) (*pRequest->m_pCompleteFunction)( pRequest); break; } case REQUEST_COMMAND: { // clear request error field pRequest->m_dwRequestError = ERR_NOERROR; DWORD dwBytesRead = COMMAND( pRequest->m_lpszData, pRequest->m_dwDataLength, pRequest->m_lpszResult, pRequest->m_dwResultLength, pRequest->m_dwMaxTries, pRequest->m_dwTimeout); pRequest->m_dwResultLength = dwBytesRead; pRequest->m_dwRequestError = COMMSTATE; COMMSTATE = ERR_NOERROR; ((CCommDevice*)lParam)->m_pRequest = NULL; ResetEvent( COMMEVENT); if( !dwBytesRead) { switch( pRequest->m_dwRequestError) { case ERR_PORTERROR: case ERR_NOPORTLOCK: case ERR_NODATALOCK: { if( pRequest->m_pWindow && ::IsWindow( pRequest->m_pWindow->m_hWnd)) pRequest->m_pWindow->PostMessage( WM_COMM_REQUEST_COMPLETE, 0, (long)pRequest); else if( pRequest->m_pCompleteFunction) (*pRequest->m_pCompleteFunction)( pRequest); return 1; } case ERR_TERMINATED: { if( pRequest->m_pWindow && ::IsWindow( pRequest->m_pWindow->m_hWnd)) pRequest->m_pWindow->PostMessage( WM_COMM_REQUEST_COMPLETE, 0, (long)pRequest); else if( pRequest->m_pCompleteFunction) (*pRequest->m_pCompleteFunction)( pRequest); return 0; } } } if( pRequest->m_pWindow && ::IsWindow( pRequest->m_pWindow->m_hWnd)) pRequest->m_pWindow->PostMessage( WM_COMM_REQUEST_COMPLETE, 0, (long)pRequest); else if( pRequest->m_pCompleteFunction) (*pRequest->m_pCompleteFunction)( pRequest); break; } case REQUEST_SPECIAL: { // clear request error field pRequest->m_dwRequestError = ERR_NOERROR; HANDLESPECIALREQUEST( pRequest); COMMSTATE = ERR_NOERROR; ((CCommDevice*)lParam)->m_pRequest = NULL; ResetEvent( COMMEVENT); switch( pRequest->m_dwRequestError) { case ERR_PORTERROR: case ERR_NOPORTLOCK: case ERR_NODATALOCK: { if( pRequest->m_pWindow && ::IsWindow( pRequest->m_pWindow->m_hWnd)) pRequest->m_pWindow->PostMessage( WM_COMM_REQUEST_COMPLETE, 0, (long)pRequest); else if( pRequest->m_pCompleteFunction) (*pRequest->m_pCompleteFunction)( pRequest); return 1; } case ERR_TERMINATED: { if( pRequest->m_pWindow && ::IsWindow( pRequest->m_pWindow->m_hWnd)) pRequest->m_pWindow->PostMessage( WM_COMM_REQUEST_COMPLETE, 0, (long)pRequest); else if( pRequest->m_pCompleteFunction) (*pRequest->m_pCompleteFunction)( pRequest); return 0; } } if( pRequest->m_pWindow && ::IsWindow( pRequest->m_pWindow->m_hWnd)) pRequest->m_pWindow->PostMessage( WM_COMM_REQUEST_COMPLETE, 0, (long)pRequest); else if( pRequest->m_pCompleteFunction) (*pRequest->m_pCompleteFunction)( pRequest); break; } case REQUEST_CALLBACK: default: { // clear any previous request errors pRequest->m_dwRequestError = ERR_NOERROR; ((CCommDevice*)lParam)->m_pRequest = NULL; ResetEvent( COMMEVENT); if( pRequest->m_pWindow && ::IsWindow( pRequest->m_pWindow->m_hWnd)) pRequest->m_pWindow->PostMessage( WM_COMM_REQUEST_COMPLETE, 0, (long)pRequest); else if( pRequest->m_pCompleteFunction) (*pRequest->m_pCompleteFunction)( pRequest); break; } } } }
/****************************************************************************** * Name: CCommDevice::Read (poll driven) * * Purpose: read data directly from the port ******************************************************************************/ DWORD CCommDevice::Read( LPTSTR data, DWORD dataLength, DWORD dwMaxTries, DWORD dwTimeout) { DWORD dwBytesRead; DWORD dwTries = 1; LPTSTR pByte = data; // clear any previous error m_dwCommState = ERR_NOERROR; // initialize the data buffer memset( data, 0, dataLength); // make sure the port is not in use DWORD dwWait = WaitForSingleObject( m_hPortMutex, INFINITE); if( dwWait!=WAIT_OBJECT_0) { m_dwCommState = ERR_NOPORTLOCK; ReleaseMutex( m_hPortMutex); return 0; } //P added to purge the port before read & write PurgeComm( m_hPort, PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR); // check for termination if( m_bCancel) { m_bCancel = FALSE; m_dwCommState = ERR_CANCELLED; PurgeComm( m_hPort, PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR); ReleaseMutex( m_hPortMutex); return 0; } if( m_bTerminate) { m_dwCommState = ERR_TERMINATED; PurgeComm( m_hPort, PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR); ReleaseMutex( m_hPortMutex); return 0; } // clear any previous errors DWORD errors; if( !ClearCommError( m_hPort, &errors, NULL)) { m_dwCommState = ERR_PORTERROR; ReleaseMutex( m_hPortMutex); return 0; } ASSERT( errors == NULL); RetryRead: // get the data do { if( !ReadFile( m_hPort, pByte, 1, &dwBytesRead, NULL)) { m_dwCommState = ERR_PORTERROR; ReleaseMutex( m_hPortMutex); return (DWORD)(pByte - data); } // if we timed out and haven't read anything check terminate // and cancel operation flags otherwise just stay in the loop // until we receive something if( !dwBytesRead && !(pByte - data)) { if( m_bCancel) { m_bCancel = FALSE; m_dwCommState = ERR_CANCELLED; PurgeComm( m_hPort, PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR); ReleaseMutex( m_hPortMutex); return 0; } if( m_bTerminate) { m_dwCommState = ERR_TERMINATED; PurgeComm( m_hPort, PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR); ReleaseMutex( m_hPortMutex); return 0; } if( !dwMaxTries || dwTries < dwMaxTries) { dwTries++; dwBytesRead = 1; // don't let loop terminate Sleep( dwTimeout); } else m_dwCommState = ERR_MAXTRIES; } else if (dwBytesRead) { // We got a character if (m_bParseCRLF) { if (*pByte==m_EOLChar) // Use EOL's to terminate event break; else if (*pByte!= m_LFChar) pByte++; } else pByte++; } } while( (dwBytesRead == 1) && (dataLength ? ((DWORD)(pByte - data) < dataLength) : TRUE)); if (m_bParseCRLF) { *pByte = '\0'; for(; pByte>data; pByte--) { if (*(pByte-1)=='\r' || *(pByte-1)=='\n') *(pByte-1) = '\0'; else break; } } DWORD len = (pByte - data); if (m_bParseCRLF && len==0 && (!dwMaxTries || dwTries<dwMaxTries)) goto RetryRead; TRACE( "Received %ld bytes: %s\n", len, data); ReleaseMutex( m_hPortMutex); return len; }
bool COMPort::Purge(DWORD dwFlags) { return PurgeComm((HANDLE(portHandle)), dwFlags); }
// // The CommThread Calculator. // 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; COMSTAT comstat = {0}; 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() // Calculator to stop waiting. The WaitForMultipleObjects() Calculator // 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() Calculator 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 Calculator. This Calculator 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_RXCHAR) //接收到字符,并置于输入缓冲区中 ReceiveChar(port, comstat); if (CommEvent & EV_CTS) //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) //发生线路状态错误,线路状态错误包括CE_FRAME,CE_OVERRUN和CE_RXPARITY ::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); break; } case 2: // write event { // Write character event from port WriteChar(port); break; } } // end switch } // close forever loop return 0; }
/*------------------------------------------- | Name:startAsyncRs232 | Description: | Parameters: | Return Type: | Comments: | See: ---------------------------------------------*/ int startAsyncRs2322(void) { FILE *stream= (FILE *)0; uart2_config config={DFLT_SPEED,DFLT_PARITY,DFLT_DATA,DFLT_STOPBIT}; int com_no=0; //const static char strConfig[]="COM1: baud=9600 parity=N data=8 stop=1"; if( (stream = fopen( "lepton_com.conf", "r" )) == NULL ) { printf( "error: lepton_com.conf was not opened\nuse default com:%s\r\n", DFLT_USE_COM); }else{ printf( "lepton_com.conf was opened\n" ); if(fscanf(stream,"com : %s",USE_COM)<0) printf( "cannot find com parameter\n" ); //if com no >9 workaround with specific string format sscanf(USE_COM,"COM%d",&com_no); if(com_no>9){ sprintf(USE_COM,"\\\\.\\COM%d",(com_no)); } } hRS232PhysicalSimEvent=CreateEvent(NULL,FALSE,FALSE,NULL); hCom = CreateFile(USE_COM, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL ); if(hCom==INVALID_HANDLE_VALUE) return -1; //set comm setRs2322(&config); // purge any information in the buffer PurgeComm( hCom, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR ); // ClearCommBreak(hCom); // //EscapeCommFunction( hCom, SETDTR ) ; // get any early notifications SetCommMask(hCom, EV_RXFLAG|EV_RXCHAR|EV_TXEMPTY); // setup device buffers SetupComm( hCom, 4096, 4096 ); // bComStopped=COM_START; hComThread = CreateThread( (LPSECURITY_ATTRIBUTES) NULL, 0, (LPTHREAD_START_ROUTINE) comThread2, NULL, 0, &dwThreadID ); if(hComThread==INVALID_HANDLE_VALUE) return -1; printf("uart started\n"); return 0; }
// // 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; }
//清空输入输出缓冲区 BOOL ComRWTool::ClearComBuffer() { return PurgeComm(m_hComm ,PURGE_TXCLEAR|PURGE_RXCLEAR); }
void raw_serial::flush( _u32 flags) { PurgeComm(_serial_handle, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR ); }
Serial::Serial(char *portName) { //We're not yet connected this->connected = false; //Try to connect to the given port throuh CreateFile this->hSerial = CreateFile(portName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); //Check if the connection was successfull if (this->hSerial == INVALID_HANDLE_VALUE) { //If not success full display an Error if (GetLastError() == ERROR_FILE_NOT_FOUND){ //Print Error if neccessary printf("ERROR: Handle was not attached. Reason: %s not available.\n", portName); } else { printf("ERROR!!!"); } } else { //If connected we try to set the comm parameters DCB dcbSerialParams = { 0 }; //Try to get the current if (!GetCommState(this->hSerial, &dcbSerialParams)) { //If impossible, show an error printf("failed to get current serial parameters!"); } else { //Define serial connection parameters for the arduino board dcbSerialParams.BaudRate = CBR_115200; dcbSerialParams.ByteSize = 8; dcbSerialParams.StopBits = ONESTOPBIT; dcbSerialParams.Parity = NOPARITY; //Setting the DTR to Control_Enable ensures that the Arduino is properly //reset upon establishing a connection dcbSerialParams.fDtrControl = DTR_CONTROL_ENABLE; //Set the parameters and check for their proper application if (!SetCommState(hSerial, &dcbSerialParams)) { printf("ALERT: Could not set Serial Port parameters"); } else { //If everything went fine we're connected this->connected = true; //Flush any remaining characters in the buffers PurgeComm(this->hSerial, PURGE_RXCLEAR | PURGE_TXCLEAR); //We wait 2s as the arduino board will be reseting Sleep(ARDUINO_WAIT_TIME); } } } }
int serialCancelOutput (SerialDevice *serial) { if (PurgeComm(serial->package.fileHandle, PURGE_TXCLEAR)) return 1; logWindowsSystemError("PurgeComm"); return 0; }
DWORD WINAPI CommMonitor( LPSTR lpData) { //监控串口接收数据,并完成数据格式分析,将结果放入结果队列 CommData SYSTEMTIME SystemTime; int nItemCount,TrayNum,CupNum;//样本项目号,盘号,杯号 BYTE SampleIDLen ;//数据包功能号,样本ID长度 WORD wSampleNo; bool blogfile; int i,ByteRecieved; bool isdataPacket=FALSE; char DataBuffer[200];// 数据缓冲区! CHAR TempWorkingID[c_MaxWorkingIDLength+1];//样本号,chj char LSampleID[5]; Init() ResetOpPointer() ResetRxPointer() nItemCount =0; FillDevName() SetCommWaitMask(EV_RXCHAR) PurgeComm( hComm, PURGE_RXCLEAR ); blogfile=NewLogFile("Syn_ELISE.txt"); WriteCommChar(XON) while (TRUE) { WaitEvent(EV_RXCHAR) do { ReadFile(hComm, &RxChar, 1, &dwReadLength, NULL); if(RxChar==STX) isdataPacket=TRUE; if(isdataPacket) { DataBuffer[i]=RxChar; i++; } if(RxChar==ENQ||RxChar==EOT) { break; } if(((RxChar==ETX)|(RxChar==ETB))&(isdataPacket)) { //DataBuffer[i]=RxChar; ByteRecieved=i; break; } }while(dwReadLength==1); i=0; if((RxChar==ETX)) { while(DataBuffer[i]!=STX) i++; } lpOpPointer=&DataBuffer[i]; if (blogfile) { WriteLogData(hLogFile,lpOpPointer,ByteRecieved); } switch (RxChar) { case ENQ: // Sleep(300); TransmitCommChar(hComm,ACK); break; case ETB: case ETX: //先进行校验的计算,若为正常接受则进行结果处理! //目前,由于资料校验和的计算方法与结果包中数据不符!尚未加校验计算 /* 需要到仪器上读出数据包进行分析 */ switch(*(lpOpPointer+2)) { case 'H': break; case 'P': break; case 'O': nItemCount=0; TrayNum=(int)StrToInt(lpOpPointer+c_TrayNumEOff,c_TrayNumLen); CupNum=(int)StrToInt(lpOpPointer+c_CupNumEOff,c_CupNumLen); wSampleNo =(int)StrToInt(lpOpPointer+c_SequenceNoOff,c_SequenceNoLen); _itoa(wSampleNo,LSampleID,10); TempWorkingID[0]=lpDevice->DevItemType; memset(&TempWorkingID[1],0x30,5); SampleIDLen=strlen(LSampleID); strncpy(&TempWorkingID[6-SampleIDLen],&LSampleID[0],SampleIDLen); TempWorkingID[6]='\0'; break; //继续接收 case 'R': FillSampleID(nItemCount, wSampleNo) strncpy(OutResult[nItemCount].WorkingID,TempWorkingID,7);//填写工作单号 OutResult[nItemCount].ItemNo=nItemCount+1; FillItemName(nItemCount,lpOpPointer+c_ItemNameOff ,c_ItemNameLen) if (OutResult[nItemCount].ItemID[1]==124)//'|' 如果项目名称长度为1则添加字符串尾标志-ASCII 码值为 0 { OutResult[nItemCount].ItemID[1]='\0'; FillResult(nItemCount,lpOpPointer+c_ResultOff-2,c_ResultLen) } else FillResult(nItemCount,lpOpPointer+c_ResultOff,c_ResultLen) OutResult[nItemCount].ItemNo=nItemCount+1; //填日期 GetSystemTime(&SystemTime); FillDate(nItemCount, SystemTime.wYear, SystemTime.wMonth, SystemTime.wDay, SystemTime.wHour,SystemTime.wMinute,SystemTime.wSecond) nItemCount++; (*lpResultProcessRoutine)(lpDevice->nDevNO, &OutResult[nItemCount-1], 1); lpDevice->dwRecordCount+=1; break; case 'L': break; } // Sleep(300); TransmitCommChar(hComm,ACK); break; case EOT: //结果入队列 default: TransmitCommChar(hComm,ACK); break; }
BOOL CComPort::Purge(const DWORD dwFlags) const { return PurgeComm(m_hCom,dwFlags); }
// // Write a character. // void CSerialPort::WriteChar(CSerialPort* port) { BOOL bWrite = TRUE; BOOL bResult = TRUE; DWORD BytesSent = 0; DWORD SendLen = port->m_nWriteSize; ResetEvent(port->m_hWriteEvent); // Gain ownership of the critical section EnterCriticalSection(&port->m_csCommunicationSync); if (bWrite) { // Initailize variables port->m_ov.Offset = 0; port->m_ov.OffsetHigh = 0; // Clear buffer PurgeComm(port->m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT); bResult = WriteFile(port->m_hComm, // Handle to COMM Port port->m_szWriteBuffer, // Pointer to message buffer in calling finction SendLen, // add by mrlong //strlen((char*)port->m_szWriteBuffer), // Length of message to send &BytesSent, // Where to store the number of bytes sent &port->m_ov); // Overlapped structure // deal with any error codes if (!bResult) { DWORD dwError = GetLastError(); switch (dwError) { case ERROR_IO_PENDING: { // continue to GetOverlappedResults() BytesSent = 0; bWrite = FALSE; break; } default: { // all other error codes port->ProcessErrorMessage("WriteFile()"); } } } else { LeaveCriticalSection(&port->m_csCommunicationSync); } } // end if(bWrite) if (!bWrite) { bWrite = TRUE; bResult = GetOverlappedResult(port->m_hComm, // Handle to COMM port &port->m_ov, // Overlapped structure &BytesSent, // Stores number of bytes sent TRUE); // Wait flag LeaveCriticalSection(&port->m_csCommunicationSync); // deal with the error code if (!bResult) { port->ProcessErrorMessage("GetOverlappedResults() in WriteFile()"); } } // end if (!bWrite) // Verify that the data size send equals what we tried to send if (BytesSent != SendLen /*strlen((char*)port->m_szWriteBuffer)*/) // add by { //TRACE("WARNING: WriteFile() error.. Bytes Sent: %d; Message Length: %d\n", BytesSent, strlen((char*)port->m_szWriteBuffer)); } }
////////////////////////////////////////////////////////////////////////////////////////// // Open a communication channel to the given serial port name. XsensResultValue Cmt1s::open( const char* portName, const uint32_t baudRate, uint32_t readBufSize, uint32_t writeBufSize) { MRPT_UNUSED_PARAM(readBufSize); MRPT_UNUSED_PARAM(writeBufSize); m_endTime = 0; CMT1LOG("L1: Open port %s at %d baud\n", portName, baudRate); if (m_isOpen) { CMT1LOG("L1: Port already open\n"); return (m_lastResult = XRV_ALREADYOPEN); } m_baudrate = baudRate; #ifdef _WIN32 char winPortName[32]; // Open port sprintf(winPortName, "\\\\.\\%s", portName); m_handle = CreateFileA( winPortName, GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr); if (m_handle == INVALID_HANDLE_VALUE) { CMT1LOG("L1: Port cannot be opened\n"); return (m_lastResult = XRV_INPUTCANNOTBEOPENED); } // Once here, port is open m_isOpen = true; // Get the current state & then change it GetCommState(m_handle, &m_commState); // Get current state m_commState.BaudRate = baudRate; // Setup the baud rate m_commState.Parity = NOPARITY; // Setup the Parity m_commState.ByteSize = 8; // Setup the data bits m_commState.StopBits = TWOSTOPBITS; // Setup the stop bits m_commState.fDsrSensitivity = FALSE; // Setup the flow control m_commState.fOutxCtsFlow = FALSE; // NoFlowControl: m_commState.fOutxDsrFlow = FALSE; m_commState.fOutX = FALSE; m_commState.fInX = FALSE; if (!SetCommState(m_handle, (LPDCB)&m_commState)) { // Set new state // Bluetooth ports cannot always be opened with 2 stopbits // Now try to open port with 1 stopbit. m_commState.StopBits = ONESTOPBIT; if (!SetCommState(m_handle, (LPDCB)&m_commState)) { CloseHandle(m_handle); m_handle = INVALID_HANDLE_VALUE; m_isOpen = false; return (m_lastResult = XRV_INPUTCANNOTBEOPENED); } } m_port = atoi(&portName[3]); sprintf(m_portname, "%s", portName); setTimeout(m_timeout); // Other initialization functions EscapeCommFunction(m_handle, SETRTS); // Enable RTS (for Xbus Master use) // Set DTR (Calibration sensors need DTR to startup, won't hurt otherwise EscapeCommFunction(m_handle, SETDTR); SetupComm(m_handle, readBufSize, writeBufSize); // Set queue size // Remove any 'old' data in buffer // PurgeComm(m_handle, PURGE_TXCLEAR | PURGE_RXCLEAR); PurgeComm( m_handle, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR); #else // !_WIN32 // Open port m_handle = ::open(portName, O_RDWR | O_NOCTTY); // O_RDWR: Read+Write // O_NOCTTY: Raw input, no "controlling terminal" // O_NDELAY: Don't care about DCD signal if (m_handle < 0) { // Port not open return m_lastResult = XRV_INPUTCANNOTBEOPENED; } // Once here, port is open m_isOpen = true; /* Start configuring of port for non-canonical transfer mode */ // Get current options for the port tcgetattr(m_handle, &m_commState); // Set baudrate. cfsetispeed(&m_commState, baudRate); cfsetospeed(&m_commState, baudRate); // Enable the receiver and set local mode m_commState.c_cflag |= (CLOCAL | CREAD); // Set character size to data bits and set no parity Mask the characte size // bits m_commState.c_cflag &= ~(CSIZE | PARENB); m_commState.c_cflag |= CS8; // Select 8 data bits m_commState.c_cflag |= CSTOPB; // send 2 stop bits // Disable hardware flow control m_commState.c_cflag &= ~CRTSCTS; m_commState.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); // Disable software flow control m_commState.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); // Set Raw output m_commState.c_oflag &= ~OPOST; // Timeout 0.001 sec for first byte, read minimum of 0 bytes m_commState.c_cc[VMIN] = 0; m_commState.c_cc[VTIME] = (m_timeout + 99) / 100; // 1 // Set the new options for the port tcsetattr(m_handle, TCSANOW, &m_commState); m_port = 0; sprintf(m_portname, "%s", portName); tcflush(m_handle, TCIOFLUSH); // setting RTS and DTR; RTS for Xbus Master, DTR for calibration sensors int cmbits; if (ioctl(m_handle, TIOCMGET, &cmbits) < 0) { return (m_lastResult = XRV_ERROR); } cmbits |= TIOCM_RTS | TIOCM_DTR; if (ioctl(m_handle, TIOCMSET, &cmbits) < 0) { return (m_lastResult = XRV_ERROR); } #endif // !_WIN32 CMT1LOG("L1: Port opened\n"); return (m_lastResult = XRV_OK); }
void SerialPort::Flush() { PurgeComm(hPort, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR); BufferedPort::Flush(); }
DWORD WINAPI CommMonitor( LPSTR lpData) { //监控串口接收数据,并完成数据格式分析,将结果放入结果队列 int nItemCount,SampleIDLen,nDataOff,nResultLen,iSampleID; bool bLogFile; char TempWorkingID[7]; LPSTR lpPointer; //应答包 char * p_Ack="\x2\x6\x3"; char * p_Nak="\x2\x16\x3"; char * p_IntSessionTXT="\x2I\x20\x3"; char * p_ReleaseMaster="\x2M\x20\x20\x20\x20\x20\x3"; char PackageType; char SampleID[10]; SYSTEMTIME SystemTime; CommData //通信类型1'、1''、2、3、4、5 Init() ResetOpPointer() FillDevName() SetCommWaitMask(EV_RXFLAG) PurgeComm( hComm, PURGE_RXCLEAR ); memset(lpOpPointer , 0, c_RxBufferLength ); if(NewLogFile("AEROSET.txt")) { bLogFile=TRUE; } while (TRUE) { WaitEvent(EV_RXFLAG)//等待接受数据包 GetInQueueLength(dwReadLength)//分析数据 ReadCommBlock(dwReadLength) PackageType=*(lpOpPointer+1);//数据包的类型 if(bLogFile) { WriteLogData(hLogFile,lpOpPointer,dwReadLength); } //校验接收到的数据,若正确,则处理,否则给否定应答。 /* checksum calculation */ /*结果的数据块中可能包含病人信息、ID信息、结果数据等组。*/ PackageType=*(lpOpPointer+1); switch(PackageType) { case 'Q': WriteCommBlock(p_Ack,3)//肯定应答 //WriteCommChar(ACK) break; case 'R': //结果处理 WriteCommBlock(p_Ack,3)//肯定应答 iSampleID=StrToInt(lpOpPointer+c_SampleIDOff,c_SamlpeIDLen); itoa(iSampleID,&SampleID[0],10); SampleIDLen=strlen(SampleID); TempWorkingID[0]=lpDevice->DevItemType; if(SampleIDLen>=6) { strncpy(&TempWorkingID[1],&SampleID[SampleIDLen-5],5); } else strncpy(&TempWorkingID[6-SampleIDLen],SampleID,SampleIDLen); TempWorkingID[6]='\0'; GetLocalTime(&SystemTime); nItemCount=0; for(nDataOff =c_DataOff; *(lpOpPointer+nDataOff)!=ETB ;) { strncpy(OutResult[nItemCount].WorkingID,TempWorkingID,7); OutResult[nItemCount].ItemNo=nItemCount+1; lpPointer=lpOpPointer+nDataOff; DeleSpace(4) strncpy(OutResult[nItemCount].ItemID,lpPointer,nResultLen); OutResult[nItemCount].ItemID[nResultLen]='\0'; lpPointer=lpOpPointer+nDataOff+c_ResultOff; DeleSpace(c_ResultLen ) FillResult(nItemCount, lpPointer ,nResultLen ) FillDate(nItemCount, SystemTime.wYear, SystemTime.wMonth, SystemTime.wDay, SystemTime.wHour,SystemTime.wMinute,SystemTime.wSecond) nDataOff = nDataOff + c_OneDataLen; nItemCount++; } if(nItemCount>0) { (*lpResultProcessRoutine)(lpDevice->nDevNO, OutResult, nItemCount); lpDevice->dwRecordCount+=nItemCount; } //WriteCommChar(ACK) /// WriteCommBlock(p_Ack,3)//肯定应答 break; case ACK: case NAK: break; } ResetRxPointer() } if(bLogFile) { CloseLogFile(hLogFile); } return TRUE; } // end of CommWatchProc()
void EIO_Open(uv_work_t* req) { OpenBaton* data = static_cast<OpenBaton*>(req->data); // data->path is char[1024] but on Windows it has the form "COMx\0" or "COMxx\0" // We want to prepend "\\\\.\\" to it before we call CreateFile strncpy(data->path + 20, data->path, 10); strncpy(data->path, "\\\\.\\", 4); strncpy(data->path + 4, data->path + 20, 10); HANDLE file = CreateFile( data->path, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); if (file == INVALID_HANDLE_VALUE) { DWORD errorCode = GetLastError(); char temp[100]; _snprintf(temp, sizeof(temp), "Opening %s", data->path); ErrorCodeToString(temp, errorCode, data->errorString); return; } bufferSize = data->bufferSize; if(bufferSize > MAX_BUFFER_SIZE) { bufferSize = MAX_BUFFER_SIZE; } DCB dcb = { 0 }; dcb.DCBlength = sizeof(DCB); if(!BuildCommDCB("9600,n,8,1", &dcb)) { ErrorCodeToString("BuildCommDCB", GetLastError(), data->errorString); return; } dcb.fBinary = true; dcb.BaudRate = data->baudRate; dcb.ByteSize = data->dataBits; switch(data->parity) { case SERIALPORT_PARITY_NONE: dcb.Parity = NOPARITY; break; case SERIALPORT_PARITY_MARK: dcb.Parity = MARKPARITY; break; case SERIALPORT_PARITY_EVEN: dcb.Parity = EVENPARITY; break; case SERIALPORT_PARITY_ODD: dcb.Parity = ODDPARITY; break; case SERIALPORT_PARITY_SPACE: dcb.Parity = SPACEPARITY; break; } switch(data->stopBits) { case SERIALPORT_STOPBITS_ONE: dcb.StopBits = ONESTOPBIT; break; case SERIALPORT_STOPBITS_ONE_FIVE: dcb.StopBits = ONE5STOPBITS; break; case SERIALPORT_STOPBITS_TWO: dcb.StopBits = TWOSTOPBITS; break; } if(!SetCommState(file, &dcb)) { ErrorCodeToString("SetCommState", GetLastError(), data->errorString); return; } // Set the com port read/write timeouts DWORD serialBitsPerByte = 8/*std data bits*/ + 1/*start bit*/; serialBitsPerByte += (data->parity == SERIALPORT_PARITY_NONE ) ? 0 : 1; serialBitsPerByte += (data->stopBits == SERIALPORT_STOPBITS_ONE) ? 1 : 2; DWORD msPerByte = (data->baudRate > 0) ? ((1000 * serialBitsPerByte + data->baudRate - 1) / data->baudRate) : 1; if (msPerByte < 1) { msPerByte = 1; } COMMTIMEOUTS commTimeouts = {0}; commTimeouts.ReadIntervalTimeout = msPerByte; // Minimize chance of concatenating of separate serial port packets on read commTimeouts.ReadTotalTimeoutMultiplier = 0; // Do not allow big read timeout when big read buffer used commTimeouts.ReadTotalTimeoutConstant = 1000; // Total read timeout (period of read loop) commTimeouts.WriteTotalTimeoutConstant = 1000; // Const part of write timeout commTimeouts.WriteTotalTimeoutMultiplier = msPerByte; // Variable part of write timeout (per byte) if(!SetCommTimeouts(file, &commTimeouts)) { ErrorCodeToString("SetCommTimeouts", GetLastError(), data->errorString); return; } // Remove garbage data in RX/TX queues PurgeComm(file, PURGE_RXCLEAR); PurgeComm(file, PURGE_TXCLEAR); data->result = (int)file; }
/*! * Open the specified device at a specified baud and create a new device handle * \param[in] deviceName Device name / address (COM21 , /dev/ttys0, depending on platform) * \param[in] baudRate Baudrate to be used * \param[out] pHandle Device handle returned * \return SBG_NO_ERROR if the device could be oppened properly */ SbgErrorCode sbgDeviceOpen(const char *deviceName, uint32 baudRate, SbgDeviceHandle *pHandle) { char errorMsg[256]; char comPortPath[32]; COMMTIMEOUTS comTimeOut; DCB comState; uint32 deviceNum; HANDLE hSerialDevice; // // First check if we have a valid pHandle // if (pHandle) { // // Extract device number // if (sscanf_s(deviceName, "COM%i", &deviceNum) == 1) { // // Build our com port path // sprintf_s(comPortPath, 32, "\\\\.\\COM%i", deviceNum); // // Init our com port // hSerialDevice = CreateFile(comPortPath, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hSerialDevice != INVALID_HANDLE_VALUE) { // // Define our device handle // *pHandle = hSerialDevice; // // Purge our com port // if (PurgeComm(hSerialDevice, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR)) { // // Retreives current com state and com timeout // if ( (GetCommState(hSerialDevice, &comState)) && (GetCommTimeouts(hSerialDevice, &comTimeOut)) ) { // // Define common attributes // comState.BaudRate= baudRate; comState.Parity= NOPARITY; comState.ByteSize= 8; comState.StopBits= ONESTOPBIT; // // Disable flow control // comState.fDsrSensitivity = FALSE; comState.fOutxCtsFlow = FALSE; comState.fOutxDsrFlow = FALSE; comState.fOutX = FALSE; comState.fInX = FALSE; // // Define timeout attributes (0 ms read timeout) // comTimeOut.ReadIntervalTimeout = MAXDWORD; comTimeOut.ReadTotalTimeoutMultiplier = 0; comTimeOut.ReadTotalTimeoutConstant = 0; comTimeOut.WriteTotalTimeoutConstant = 0; comTimeOut.WriteTotalTimeoutMultiplier = 0; // // Configure our com port // if ( (SetCommState(hSerialDevice, &comState)) && (SetCommTimeouts(hSerialDevice, &comTimeOut)) ) { // // Wait until our com port has been configured by windows // sbgSleep(60); // // Define our COM port buffer size // if (SetupComm(hSerialDevice, SBG_SERIAL_RX_BUFFER_SIZE, SBG_SERIAL_TX_BUFFER_SIZE)) { // // Purge our communication // return sbgDeviceFlush(hSerialDevice); } else { sbgGetWindowsErrorMsg(errorMsg); fprintf(stderr, "sbgDeviceOpen: Unable to define buffer size: %s.\n", errorMsg); } } else { sbgGetWindowsErrorMsg(errorMsg); fprintf(stderr, "sbgDeviceOpen: Unable to set com state and/or timeout: %s.\n", errorMsg); } } else { sbgGetWindowsErrorMsg(errorMsg); fprintf(stderr, "sbgDeviceOpen: Unable to retreive com state and/or timeout: %s.\n", errorMsg); } } else { sbgGetWindowsErrorMsg(errorMsg); fprintf(stderr, "sbgDeviceOpen: Unable to purge com port %i: %s.\n", deviceNum, errorMsg); } // // Close our device if only some part has been initialised // sbgDeviceClose(hSerialDevice); } else { // // We have an invalid device handle // *pHandle = SBG_INVALID_DEVICE_HANDLE; sbgGetWindowsErrorMsg(errorMsg); fprintf(stderr, "sbgDeviceOpen: Unable to open com port %i: %s\n", deviceNum, errorMsg); } return SBG_ERROR; } else { fprintf(stderr, "sbgDeviceOpen: Invalid deviceName: %s\n", deviceName); return SBG_INVALID_PARAMETER; } } else { fprintf(stderr, "sbgDeviceOpen: pHandle == NULL for deviceName: %s\n", deviceName); return SBG_NULL_POINTER; } }