#ifndef _MSC_VER //linux #include #include #include #include #include #include #endif #include "Serial.h" #include #include #include #ifdef DEBUG #include #include #endif std::string writeLastError() { #ifdef _MSC_VER LPVOID lpMsgBuf; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT), (LPSTR) &lpMsgBuf, 0, NULL); std::ostringstream out; out << "Error " << lpMsgBuf; return out.str(); #else //linux return std::string( strerror(errno) ); #endif } CSerial::CSerial() { mIsopen = false; } CSerial::CSerial(char* port, Baudrate bitrate) { mPortstr = port; mBitrate = bitrate; mIsopen = false; #ifdef _MSC_VER openWindows(); #else openLinux(); #endif } CSerial::~CSerial(void) { close(); } void CSerial::open(char* port, Baudrate bitrate) { if (mIsopen) throw std::runtime_error("Port already opened"); mPortstr = port; mBitrate = bitrate; #ifdef _MSC_VER openWindows(); #else openLinux(); #endif } #ifdef _MSC_VER void CSerial::openWindows() { mComport = CreateFile( mPortstr, GENERIC_READ|GENERIC_WRITE,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0); if (mComport == INVALID_HANDLE_VALUE) { throw std::runtime_error(writeLastError().c_str()); } DCB dcb; dcb.DCBlength = sizeof(DCB); mDcbRestore.DCBlength = sizeof(DCB); if (!GetCommState(mComport,&dcb) || !GetCommState(mComport,&mDcbRestore)) { std::string error = writeLastError(); CloseHandle(mComport); throw std::exception(error.c_str()); } dcb.BaudRate = convertBaudrate(mBitrate); dcb.ByteSize = 8; dcb.Parity = NOPARITY; dcb.StopBits = ONESTOPBIT; dcb.fDtrControl = DTR_CONTROL_DISABLE; dcb.fRtsControl = RTS_CONTROL_DISABLE; dcb.fParity = false; dcb.fDsrSensitivity = false; if (!SetCommState(mComport,&dcb)) { std::string error = writeLastError(); CloseHandle(mComport); throw std::runtime_error( error ); } mIsopen = true; } #endif #ifndef _MSC_VER void CSerial::openLinux() { termios newtio; mFiledescriptor = ::open(mPortstr, O_RDWR | O_NOCTTY | O_NONBLOCK); if (mFiledescriptor < 0) throw std::runtime_error( writeLastError() ); tcgetattr(mFiledescriptor, &mOldtio); bzero(&newtio, sizeof(newtio) ); // use a std. 8N1 config newtio.c_cflag = convertBaudrate(mBitrate) | CS8 | CLOCAL | CREAD; newtio.c_iflag = IGNPAR; newtio.c_oflag = 0; // set input mode (non-canonical, no echo,...) newtio.c_lflag = 0; newtio.c_cc[VTIME] = 0; // inter-character timer unused newtio.c_cc[VMIN] = 0; // blocking read until 1 chars received tcflush(mFiledescriptor, TCIFLUSH); tcsetattr(mFiledescriptor, TCSANOW, &newtio); mIsopen = true; } #endif void CSerial::close() { if (mIsopen) { #ifdef _MSC_VER while (getComstat().cbOutQue >0) Sleep(5); SetCommState(mComport,&mDcbRestore); CloseHandle(mComport); #else // linux close() tcdrain(mFiledescriptor); tcsetattr(mFiledescriptor, TCSADRAIN, &mOldtio); //restore settings, when all data is written ::close(mFiledescriptor); //close()== system-call #endif mIsopen = false; } } int CSerial::readByte() { unsigned char out; int size = readBytes(&out,1); if (size == 0) return 256; return out; } void CSerial::writeByte(unsigned char out) { writeBytes(&out,1); } int CSerial::convertBaudrate(Baudrate rate) { int retval=0; #ifdef _MSC_VER switch( rate ) { case Baud300: retval = 300; break; case Baud600: retval = 600; break; case Baud1200: retval = 1200; break; case Baud2400: retval = 2400; break; case Baud4800: retval = 4800; break; case Baud9600: retval = 9600; break; case Baud19200: retval = 19200; break; case Baud38400: retval = 38400; break; case Baud57600: retval = 57600; break; case Baud115200: retval = 115200; break; } #else switch (rate) { case Baud300: retval = B300; break; case Baud600: retval = B600; break; case Baud1200: retval = B1200; break; case Baud2400: retval = B2400; break; case Baud4800: retval = B4800; break; case Baud9600: retval = B9600; break; case Baud19200: retval = B19200; break; case Baud38400: retval = B38400; break; case Baud57600: retval = B57600; break; case Baud115200: retval = B115200; break; } #endif return retval; } #ifdef _MSC_VER COMSTAT CSerial::getComstat() const { if (!mIsopen) throw std::exception("Port not opened"); COMSTAT stat; DWORD x; ClearCommError(mComport,&x,&stat); return stat; } #endif int CSerial::bytesReady() const { #ifdef _MSC_VER return getComstat().cbInQue; #else return 0; #endif } int CSerial::outQueueSize() const { #ifdef _MSC_VER return getComstat().cbOutQue; #else return 0; #endif } // Debug function // void CSerial::printByte(char* description, unsigned char byte) { #ifdef DEBUG std::cout << description << " : " << (int) byte << "/" << std::setw(2) << std::setfill('0') << std::hex << (int) byte << std::endl; std::cout << std::dec; #endif } void CSerial::writeBytes(unsigned char* buf, unsigned int len) { if (!mIsopen) throw std::runtime_error("Port not opened"); #ifdef _MSC_VER writeBytesWindows(buf,len); #else writeBytesLinux(buf,len); #endif } #ifdef _MSC_VER void CSerial::writeBytesWindows(unsigned char* buf, unsigned int len) { unsigned int size; while (getComstat().cbOutQue >0) Sleep(2); WriteFile(mComport,buf,len,&size, NULL); if (size != len) { std::string error = writeLastError(); CloseHandle(mComport); throw std::exception(error.c_str()); } } #else void CSerial::writeBytesLinux(unsigned char* buf, unsigned int len) { int size = write(mFiledescriptor, &buf, len); Sleep(50); //tcdrain(mFiledescriptor); if (size != len) throw std::runtime_error(writeLastError() ); } #endif int CSerial::readBytes(unsigned char *buf, unsigned int maxLen) { if (!mIsopen) throw std::runtime_error("Port not opened"); #ifdef _MSC_VER return readBytesWindows(buf,maxLen); #else return readBytesLinux(buf,maxLen); #endif } #ifdef _MSC_VER int CSerial::readBytesWindows(unsigned char* buf, unsigned int maxLen) { unsigned long size; ReadFile(mComport, buf, maxLen, &size, 0); return size; } #else int CSerial::readBytesLinux(unsigned char* buf, unsigned int maxLen) { return read(mFiledescriptor, buf, maxLen); } #endif