📄 serial.cpp
字号:
// Copyright (C) 1999-2005 Open Source Telecom Corporation.//// This program is free software; you can redistribute it and/or modify// it under the terms of the GNU General Public License as published by// the Free Software Foundation; either version 2 of the License, or// (at your option) any later version.// // This program is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU General Public License for more details.//// You should have received a copy of the GNU General Public License// along with this program; if not, write to the Free Software// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.// // As a special exception, you may use this file as part of a free software// library without restriction. Specifically, if other files instantiate// templates or use macros or inline functions from this file, or you compile// this file and link it with other files to produce an executable, this// file does not by itself cause the resulting executable to be covered by// the GNU General Public License. This exception does not however // invalidate any other reasons why the executable file might be covered by// the GNU General Public License. //// This exception applies only to the code released under the name GNU// Common C++. If you copy code from other releases into a copy of GNU// Common C++, as the General Public License permits, the exception does// not apply to the code that you add in this way. To avoid misleading// anyone as to the status of such modified files, you must delete// this exception notice from them.//// If you write modifications of your own for GNU Common C++, it is your choice// whether to permit this exception to apply to your modifications.// If you do not wish that, delete this exception notice.//#include <cc++/config.h>#ifdef CCXX_WITHOUT_EXTRAS#include <cc++/export.h>#endif#include <cc++/exception.h>#include <cc++/thread.h>#include <cc++/file.h>#ifndef CCXX_WITHOUT_EXTRAS#include <cc++/export.h>#endif#include <cc++/serial.h>#include "private.h"#include <cstdlib>#include <climits>#ifdef WIN32#define B256000 CBR_256000#define B128000 CBR_128000#define B115200 CBR_115200#define B57600 CBR_57600#define B56000 CBR_56000#define B38400 CBR_38400#define B19200 CBR_19200#define B14400 CBR_14400#define B9600 CBR_9600#define B4800 CBR_4800#define B2400 CBR_2400#define B1200 CBR_1200#define B600 CBR_600#define B300 CBR_300#define B110 CBR_110#include <io.h>#include <fcntl.h>#else#include <sys/ioctl.h>#include <termios.h>#endif#include <cerrno>#include <iostream>#ifdef CCXX_NAMESPACESnamespace ost {using std::streambuf;using std::iostream;using std::ios;#endif#ifndef MAX_INPUT#define MAX_INPUT 255#endif#ifndef MAX_CANON#define MAX_CANON MAX_INPUT#endif#ifdef __FreeBSD__#undef _PC_MAX_INPUT#undef _PC_MAX_CANON#endif#if defined(__QNX__)#define CRTSCTS (IHFLOW | OHFLOW)#endif#if defined(_THR_UNIXWARE) || defined(__hpux) || defined(_AIX) #include <sys/termiox.h>#define CRTSCTS (CTSXON | RTSXOFF)#endif// IRIX#ifndef CRTSCTS#ifdef CNEW_RTSCTS#define CRTSCTS (CNEW_RTSCTS)#endif#endif#if defined(CTSXON) && defined(RTSXOFF) && !defined(CRTSCTS) #define CRTSCTS (CTSXON | RTSXOFF)#endif#ifndef CRTSCTS#define CRTSCTS 0#endifSerial::Serial(const char *fname){ initSerial(); open(fname);#ifdef WIN32 if(dev == INVALID_HANDLE_VALUE)#else if(dev < 0)#endif { error(errOpenFailed); return; }#ifdef WIN32 COMMTIMEOUTS CommTimeOuts ; GetCommTimeouts(dev, &CommTimeOuts);// CommTimeOuts.ReadIntervalTimeout = MAXDWORD; CommTimeOuts.ReadIntervalTimeout = 0; CommTimeOuts.ReadTotalTimeoutMultiplier = 0 ; CommTimeOuts.ReadTotalTimeoutConstant = 0; CommTimeOuts.WriteTotalTimeoutMultiplier = 0 ; CommTimeOuts.WriteTotalTimeoutConstant = 1000; SetCommTimeouts(dev, &CommTimeOuts) ;#else if(!isatty(dev)) { Serial::close(); error(errOpenNoTty); return; }#endif}Serial::~Serial(){ endSerial();}void Serial::initConfig(void){#ifdef WIN32#define ASCII_XON 0x11#define ASCII_XOFF 0x13 DCB * attr = (DCB *)current; DCB * orig = (DCB *)original; attr->DCBlength = sizeof(DCB); orig->DCBlength = sizeof(DCB); GetCommState(dev, orig); GetCommState(dev, attr); attr->DCBlength = sizeof(DCB); attr->BaudRate = 1200; attr->Parity = NOPARITY; attr->ByteSize = 8; attr->XonChar = ASCII_XON; attr->XoffChar = ASCII_XOFF; attr->XonLim = 100; attr->XoffLim = 100; attr->fOutxDsrFlow = 0; attr->fDtrControl = DTR_CONTROL_ENABLE; attr->fOutxCtsFlow = 1; attr->fRtsControl = RTS_CONTROL_ENABLE; attr->fInX = attr->fOutX = 0; attr->fBinary = true; attr->fParity = true; SetCommState(dev, attr);#else struct termios *attr = (struct termios *)current; struct termios *orig = (struct termios *)original; long ioflags = fcntl(dev, F_GETFL); tcgetattr(dev, (struct termios *)original); tcgetattr(dev, (struct termios *)current); attr->c_oflag = attr->c_lflag = 0; attr->c_cflag = CLOCAL | CREAD | HUPCL; attr->c_iflag = IGNBRK; memset(attr->c_cc, 0, sizeof(attr->c_cc)); attr->c_cc[VMIN] = 1; // inherit original settings, maybe we should keep more?? cfsetispeed(attr, cfgetispeed(orig)); cfsetospeed(attr, cfgetospeed(orig)); attr->c_cflag |= orig->c_cflag & (CRTSCTS | CSIZE | PARENB | PARODD | CSTOPB); attr->c_iflag |= orig->c_iflag & (IXON | IXANY | IXOFF); tcsetattr(dev, TCSANOW, attr); fcntl(dev, F_SETFL, ioflags & ~O_NDELAY);#if defined(TIOCM_RTS) && defined(TIOCMODG) int mcs = 0; ioctl(dev, TIOCMODG, &mcs); mcs |= TIOCM_RTS; ioctl(dev, TIOCMODS, &mcs);#endif #ifdef _COHERENT ioctl(dev, TIOCSRTS, 0);#endif#endif // WIN32}void Serial::restore(void){#ifdef WIN32 memcpy(current, original, sizeof(DCB)); SetCommState(dev, (DCB *)current);#else memcpy(current, original, sizeof(struct termios)); tcsetattr(dev, TCSANOW, (struct termios *)current);#endif}void Serial::initSerial(void){ flags.thrown = false; flags.linebuf = false; errid = errSuccess; errstr = NULL; dev = INVALID_HANDLE_VALUE;#ifdef WIN32 current = new DCB; original = new DCB;#else current = new struct termios; original = new struct termios;#endif}void Serial::endSerial(void){#ifdef WIN32 if(dev == INVALID_HANDLE_VALUE && original) SetCommState(dev, (DCB *)original); if(current) delete (DCB *)current; if(original) delete (DCB *)original;#else if(dev < 0 && original) tcsetattr(dev, TCSANOW, (struct termios *)original); if(current) delete (struct termios *)current; if(original) delete (struct termios *)original;#endif Serial::close(); current = NULL; original = NULL;}Serial::Error Serial::error(Error err, char *errs){ errid = err; errstr = errs; if(!err) return err; if(flags.thrown) return err; // prevents recursive throws flags.thrown = true;#ifdef CCXX_EXCEPTIONS if(Thread::getException() == Thread::throwObject) throw((Serial *)this);#ifdef COMMON_STD_EXCEPTION else if(Thread::getException() == Thread::throwException) { if(!errs) errs = ""; throw SerException(String(errs)); }#endif#endif return err; }int Serial::setPacketInput(int size, unsigned char btimer){#ifdef WIN32 // Still to be done...... return 0;#else#ifdef _PC_MAX_INPUT int max = fpathconf(dev, _PC_MAX_INPUT);#else int max = MAX_INPUT;#endif struct termios *attr = (struct termios *)current; if(size > max) size = max; attr->c_cc[VEOL] = attr->c_cc[VEOL2] = 0; attr->c_cc[VMIN] = (unsigned char)size; attr->c_cc[VTIME] = btimer; attr->c_lflag &= ~ICANON; tcsetattr(dev, TCSANOW, attr); bufsize = size; return size;#endif}int Serial::setLineInput(char newline, char nl1){#ifdef WIN32 // Still to be done...... return 0;#else struct termios *attr = (struct termios *)current; attr->c_cc[VMIN] = attr->c_cc[VTIME] = 0; attr->c_cc[VEOL] = newline; attr->c_cc[VEOL2] = nl1; attr->c_lflag |= ICANON; tcsetattr(dev, TCSANOW, attr);#ifdef _PC_MAX_CANON bufsize = fpathconf(dev, _PC_MAX_CANON);#else bufsize = MAX_CANON;#endif return bufsize;#endif}void Serial::flushInput(void){#ifdef WIN32 PurgeComm(dev, PURGE_RXABORT | PURGE_RXCLEAR);#else tcflush(dev, TCIFLUSH);#endif}void Serial::flushOutput(void){#ifdef WIN32 PurgeComm(dev, PURGE_TXABORT | PURGE_TXCLEAR);#else tcflush(dev, TCOFLUSH);#endif}void Serial::waitOutput(void){#ifdef WIN32#else tcdrain(dev);#endif}Serial &Serial::operator=(const Serial &ser){ Serial::close(); if(ser.dev < 0) return *this;#ifdef WIN32 HANDLE process = GetCurrentProcess(); int result = DuplicateHandle(process, ser.dev, process, &dev, DUPLICATE_SAME_ACCESS, 0, 0); if (0 == result) { memcpy(current, ser.current, sizeof(DCB)); memcpy(original, ser.original, sizeof(DCB)); }#else dev = dup(ser.dev); memcpy(current, ser.current, sizeof(struct termios)); memcpy(original, ser.original, sizeof(struct termios));#endif return *this;}void Serial::open(const char * fname){#ifndef WIN32 int cflags = O_RDWR | O_NDELAY; dev = ::open(fname, cflags); if(dev > -1) initConfig();#else // open COMM device dev = CreateFile(fname, GENERIC_READ | GENERIC_WRITE, 0, // exclusive access NULL, // no security attrs OPEN_EXISTING, FILE_FLAG_OVERLAPPED | FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING, NULL); if(dev != INVALID_HANDLE_VALUE) initConfig();#endif}#ifdef WIN32int Serial::aRead(char * Data, const int Length){ unsigned long dwLength = 0, dwError, dwReadLength; COMSTAT cs; OVERLAPPED ol; // Return zero if handle is invalid if(dev == INVALID_HANDLE_VALUE) return 0; // Read max length or only what is available ClearCommError(dev, &dwError, &cs); // If not requiring an exact byte count, get whatever is available if(dwLength > (int)cs.cbInQue) dwReadLength = cs.cbInQue; else dwReadLength = Length; memset(&ol, 0, sizeof(OVERLAPPED)); ol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if(dwReadLength > 0) { if(ReadFile(dev, Data, dwReadLength, &dwLength, &ol) == FALSE) { if(GetLastError() == ERROR_IO_PENDING) { WaitForSingleObject(ol.hEvent, INFINITE); GetOverlappedResult(dev, &ol, &dwLength, TRUE); } else ClearCommError(dev, &dwError, &cs); } } if(ol.hEvent != INVALID_HANDLE_VALUE) CloseHandle(ol.hEvent); return dwLength;}int Serial::aWrite(const char * Data, const int Length){ COMSTAT cs; unsigned long dwError = 0; OVERLAPPED ol; // Clear the com port of any error condition prior to read ClearCommError(dev, &dwError, &cs); unsigned long retSize = 0; memset(&ol, 0, sizeof(OVERLAPPED)); ol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if(WriteFile(dev, Data, Length, &retSize, &ol) == FALSE) { if(GetLastError() == ERROR_IO_PENDING) { WaitForSingleObject(ol.hEvent, INFINITE); GetOverlappedResult(dev, &ol, &retSize, TRUE); } else ClearCommError(dev, &dwError, &cs); } if(ol.hEvent != INVALID_HANDLE_VALUE) CloseHandle(ol.hEvent); return retSize;}#elseint Serial::aRead(char *Data, const int Length){ return ::read(dev, Data, Length);}int Serial::aWrite(const char *Data, const int Length){ return ::write(dev, Data, Length);}#endifvoid Serial::close(){#ifdef WIN32 CloseHandle(dev);#else ::close(dev);#endif dev = INVALID_HANDLE_VALUE; }/*const int iAsync::getTimeOuts(unsigned long & readTimeout, unsigned long & writeTimeout){ return GetCommTimeouts(_TheHandle, &CommTimeOuts);}const int iAsync::setTimeOuts(unsigned long readTimeout, unsigned long writeTimeout){ COMMTIMEOUTS CommTimeOuts ; getTimeOuts(CommTimeOuts); CommTimeOuts.ReadIntervalTimeout = readTimeout; CommTimeOuts.ReadTotalTimeoutMultiplier = 0 ; CommTimeOuts.ReadTotalTimeoutConstant = 0; CommTimeOuts.WriteTotalTimeoutMultiplier = 0 ; CommTimeOuts.WriteTotalTimeoutConstant = 1000; return GetCommTimeouts(_TheHandle, &CommTimeOuts);} return SetCommTimeouts(_TheHandle, &CommTimeOuts) ;{ DCB dcb ; dcb.DCBlength = sizeof(DCB) ; GetCommState(_TheHandle, &dcb) ; // hardcode this stuff for now..... dcb.BaudRate = _TheBaudrate; dcb.ByteSize = 8; dcb.Parity = NOPARITY; dcb.StopBits = ONESTOPBIT; dcb.fOutxDsrFlow = 0; dcb.fDtrControl = DTR_CONTROL_ENABLE ; dcb.fOutxCtsFlow = 1; dcb.fRtsControl = RTS_CONTROL_HANDSHAKE ; dcb.fInX = dcb.fOutX = 0; dcb.XonChar = ASCII_XON; dcb.XoffChar = ASCII_XOFF; dcb.XonLim = 100; dcb.XoffLim = 100; // other various settings dcb.fBinary = TRUE; dcb.fParity = TRUE; GetCommState(_TheHandle, &dcb) ; dcb.DCBlength = sizeof(DCB) ; dcb.BaudRate = _TheBaudrate; SetCommState(_TheHandle, &dcb) ;}*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -