/* PIP - Platform Independent Primitives COM Copyright (C) 2012 Ivan Pelipenko peri4ko@gmail.com, Bychkov Andrey wapmobil@gmail.com 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 3 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, see . */ #include "piserial.h" PISerial::PISerial(const PIString & device, void * data_, ReadRetFunc slot): PIIODevice(device, ReadWrite) { piMonitor.serials++; setPriority(piHigh); path_ = device; data = data_; fd = -1; headerPtr = 0; params = 0; vtime = 1; ret_func_ = slot; #ifdef WINDOWS hCom = 0; #endif ispeed = ospeed = S115200; init(); } PISerial::PISerial(void * data_, ReadRetFunc slot): PIIODevice("", ReadWrite) { piMonitor.serials++; setPriority(piHigh); data = data_; fd = -1; headerPtr = 0; params = 0; vtime = 1; ret_func_ = slot; #ifdef WINDOWS hCom = 0; #endif ispeed = ospeed = S115200; init(); } PISerial::~PISerial() { piMonitor.serials--; } bool PISerial::closeDevice() { if (!isInitialized()) return true; if (isRunning()) { stop(); PIThread::terminate(); } #ifdef WINDOWS if (fd != -1) { SetCommState(hCom, &sdesc); SetCommMask(hCom, mask); CloseHandle(hCom); fd = -1; } #else if (fd != -1) { tcsetattr(fd, TCSANOW, &sdesc); ::close(fd); fd = -1; } #endif return true; } int PISerial::convertSpeed(PISerial::Speed speed) { switch (speed) { case S110: return B110; case S300: return B300; case S600: return B600; case S1200: return B1200; case S2400: return B2400; case S4800: return B4800; case S9600: return B9600; case S19200: return B19200; case S38400: return B38400; case S57600: return B57600; case S115200: return B115200; } return B115200; } bool PISerial::read(void * data, int size, double timeout_ms) { if (data == 0) return false; int ret, all = 0; if (timeout_ms > 0.) { setReadIsBlocking(false); all = ::read(fd, data, 1); timer.reset(); while (all < size && timer.elapsed_m() < timeout_ms) { ret = ::read(fd, &((uchar * )data)[all], size - all); if (ret > 0) all += ret; else msleep(1); } return (all == size); } else { setReadIsBlocking(true); all = ::read(fd, data, 1); while (all < size) { ret = ::read(fd, &((uchar * )data)[all], size - all); if (ret > 0) all += ret; } return (all == size); } return false; } bool PISerial::openDevice() { #ifdef WINDOWS DWORD da = 0, sm = 0; if (isReadable()) {ds |= GENERIC_READ; sm |= FILE_SHARE_READ;} if (isWriteable()) {ds |= GENERIC_WRITE; sm |= FILE_SHARE_WRITE;} hCom = CreateFileA(path_.data(), ds, sm, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0); if(hCom == INVALID_HANDLE_VALUE) { piCout << "[PISerial] Unable to open \"" << path_ << "\"" << endl; return false; } fd = 0; COMMTIMEOUTS times; times.ReadIntervalTimeout = vtime; times.ReadTotalTimeoutConstant = 1; times.ReadTotalTimeoutMultiplier = 0; times.WriteTotalTimeoutConstant = 1; times.WriteTotalTimeoutMultiplier = 0; if (SetCommTimeouts(hCom, ×) == -1) { piCout << "[PISerial] Unable to set timeouts for \"" << path_ << "\"" << endl; CloseHandle(hCom); fd = -1; return false; } GetCommMask(hCom, &mask); SetCommMask(hCom, EV_RXCHAR); GetCommState(hCom, &sdesc); desc = sdesc; desc.DCBlength = sizeof(desc); desc.BaudRate = convertSpeed(ispeed); desc.ByteSize = 8; if (params[PISerial::ParityControl]) { desc.fParity = 1; desc.Parity = params[PISerial::ParityOdd] ? 1 : 2; } desc.StopBits = params[PISerial::TwoStopBits] ? TWOSTOPBITS : ONESTOPBIT; if (SetCommState(hCom, &desc) == -1) { piCout << "[PISerial] Unable to set comm state for \"" << path_ << "\"" << endl; CloseHandle(hCom); fd = -1; return false; } #else int om = 0; switch (mode_) { case PIIODevice::ReadOnly: om = O_RDONLY; break; case PIIODevice::WriteOnly: om = O_WRONLY; break; case PIIODevice::ReadWrite: om = O_RDWR; break; } //cout << "init ser " << path_ << " mode " << om << endl; fd = ::open(path_.data(), O_NOCTTY | om); if(fd == -1) { piCout << "[PISerial] Unable to open \"" << path_ << "\"" << endl; return false; } fcntl(fd, F_SETFL, 0); tcgetattr(fd, &desc); sdesc = desc; desc.c_iflag = desc.c_oflag = desc.c_lflag = 0; desc.c_cflag = CLOCAL | CSIZE | CS8; if (isReadable()) desc.c_cflag |= CREAD; if (params[PISerial::TwoStopBits]) desc.c_cflag |= CSTOPB; if (params[PISerial::ParityControl]) { desc.c_iflag |= INPCK; desc.c_cflag |= PARENB; if (params[PISerial::ParityOdd]) desc.c_cflag |= PARODD; } desc.c_cc[VMIN] = 1; desc.c_cc[VTIME] = vtime; cfsetispeed(&desc, convertSpeed(ispeed)); cfsetospeed(&desc, convertSpeed(ospeed)); if(tcsetattr(fd, TCSANOW, &desc) < 0) { piCout << "[PISerial] Can`t set attributes for \"" << path_ << "\"" << endl; ::close(fd); return false; } tcflush(fd, TCIOFLUSH); //piCout << "[PISerial] Initialized " << path_ << endl; #endif return true; } int PISerial::write(const void * data, int max_size, bool wait) { //piCout << "[PISerial] send size: " << sizeof(data) << endl; if (fd == -1 || !canWrite()) { //piCout << "[PISerial] Can`t write to uninitialized COM" << endl; return -1; } #ifdef WINDOWS DWORD wrote; WriteFile(hCom, data, max_size, &wrote, 0); #else int wrote; wrote = ::write(fd, data, max_size); if (wait) tcdrain(fd); #endif return (int)wrote; //piCout << "[PISerial] Error while sending" << endl; //piCout << "[PISerial] Wrote " << wrote << " bytes in " << path_ << endl; }