/* PIP - Platform Independent Primitives COM Copyright (C) 2011 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(PIString name, void * data_, SerialFunc slot, SerialHeaderFunc slot_header): PIThread() { piMonitor.serials++; setPriority(piHigh); data = data_; devName = name; fd = -1; missed = 0; dataSize = headerSize = 0; headerPtr = 0; ret_func = slot; ret_func_header = slot_header; #ifdef WINDOWS hCom = 0; #endif ispeed = ospeed = S115200; } PISerial::~PISerial() { piMonitor.serials--; terminate(); } void PISerial::terminate() { if (!initialized()) return; 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 } 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; } void PISerial::begin() { allReaded = addSize = curInd = 0; first = false; packetSize = headerSize + dataSize; if (headerSize > 0) mheader.resize(headerSize); if (!init()) stop(); } void PISerial::run() { if (dataSize == 0) return; while (allReaded < packetSize + addSize) { #ifdef WINDOWS WaitCommEvent(hCom, 0, 0); ReadFile(hCom, &buffer[allReaded], SERIAL_BUFFER_SIZE, &readed, 0); #else readed = read(fd, &buffer[allReaded], SERIAL_BUFFER_SIZE); #endif allReaded += readed; } if (headerSize > 0) { if (allReaded + curInd >= SERIAL_BUFFER_SIZE) { memcpy(sbuffer, buffer, SERIAL_BUFFER_SIZE); memcpy(buffer, &sbuffer[SERIAL_BUFFER_SIZE - packetSize], allReaded); allReaded = packetSize; addSize = curInd = 0; } while (!ret_func_header(data, (uchar * )headerPtr, &buffer[curInd], headerSize)) { curInd++; missed++; if (curInd > addSize) { addSize += packetSize; return; } } memcpy(mheader.data(), &buffer[curInd + headerSize], headerSize); if (!ret_func(data, &buffer[curInd + headerSize], dataSize)) { curInd++; missed++; return; } memcpy(sbuffer, buffer, allReaded); memcpy(buffer, &sbuffer[packetSize + curInd], allReaded); allReaded -= packetSize + curInd; curInd = addSize = 0; } else { ret_func(data, buffer, dataSize); memcpy(sbuffer, buffer, allReaded); memcpy(buffer, &sbuffer[packetSize], allReaded); allReaded -= packetSize; } } void PISerial::end() { terminate(); } bool PISerial::init() { #ifdef WINDOWS hCom = CreateFileA(devName.stdString().c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0); if(hCom == INVALID_HANDLE_VALUE) { cout << "[PISerial] Unable to open \"" << devName << "\"" << endl; return false; } fd = 0; COMMTIMEOUTS times; times.ReadIntervalTimeout = 1; times.ReadTotalTimeoutConstant = 1; times.ReadTotalTimeoutMultiplier = 0; times.WriteTotalTimeoutConstant = 0; times.WriteTotalTimeoutMultiplier = 1; if (SetCommTimeouts(hCom, ×) == -1) { cout << "[PISerial] Unable to set timeouts for \"" << devName << "\"" << 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) { cout << "[PISerial] Unable to set comm state for \"" << devName << "\"" << endl; CloseHandle(hCom); fd = -1; return false; } #else fd = open(devName.data(), O_NOCTTY | O_RDWR); if(fd == -1) { cout << "[PISerial] Unable to open \"" << devName << "\"" << 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 | CREAD | CSIZE; 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] = 0; desc.c_cc[VTIME] = 1; cfsetispeed(&desc, convertSpeed(ispeed)); cfsetospeed(&desc, convertSpeed(ospeed)); if(tcsetattr(fd, TCSANOW, &desc) < 0) { cout << "[PISerial] Can`t set attributes for \"" << devName << "\"" << endl; close(fd); return false; } tcflush(fd, TCIOFLUSH); //cout << "[PISerial] Initialized " << devName << endl; #endif return true; } bool PISerial::send(uchar * data, int size) { //cout << "[PISerial] send size: " << sizeof(data) << endl; if (fd == -1) { //cout << "[PISerial] Can`t write to uninitialized COM" << endl; return false; } #ifdef WINDOWS DWORD wrote; WriteFile(hCom, data, size, &wrote, 0); #else int wrote; wrote = write(fd, data, size); #endif if ((int)wrote != size) { //cout << "[PISerial] Error while sending" << endl; return false; } //cout << "[PISerial] Wrote " << wrote << " bytes in " << devName << endl; return true; }