/* 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): PIThread() { piMonitor.serials++; setPriority(piHigh); data = data_; devName = name; fd = -1; dataSize = headerSize = 0; headerPtr = 0; hbuffer = pbuffer = 0; ret_func = slot; memset(buffer, 0, BUFFER_SIZE); memset(sbuffer, 0, BUFFER_SIZE); #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() { sbuffIndex = 0; startIndex = 0; backIndex = 0; tryagain = first = false; hbuffer = new char[headerSize]; pbuffer = new char[dataSize]; if (!init()) stop(); } void PISerial::run() { if (dataSize == 0) return; char b; uint i = 0; int j; #ifdef WINDOWS WaitCommEvent(hCom, 0, 0); ReadFile(hCom, buffer, dataSize, &readed, 0); #else readed = read(fd, buffer, BUFFER_SIZE); #endif if (headerSize > 0) { while (i < readed) { //cout << sbuffIndex << ";" << startIndex << endl; if (!tryagain) { b = buffer[i]; sbuffer[sbuffIndex] = b; } else { backIndex++; if (backIndex == headerSize + dataSize) tryagain = false; } if (first) { if (sbuffIndex-startIndex == headerSize + dataSize - 1) { //cout << "vsdfgvb" << endl; memcpy(pbuffer,&sbuffer[startIndex+headerSize],dataSize); if (ret_func(data, pbuffer, dataSize)) { startIndex = 0; sbuffIndex = -1; } else { //startIndex++; memcpy(sbuffer, hbuffer, headerSize); memcpy(&sbuffer[headerSize], pbuffer, dataSize); backIndex = 0; tryagain = true; startIndex = 1; sbuffIndex = -1; } first = false; } } else { if (sbuffIndex - startIndex == headerSize - 1) { memcpy(hbuffer, &sbuffer[startIndex], headerSize); for (j = 0; j < headerSize; ++j) { if (hbuffer[j] != ((char*)headerPtr)[j]) { startIndex++; //cout << "no" << endl; break; } } if (j == headerSize) { first = true; mheader.resize(headerSize); memcpy(mheader.data(),headerPtr,headerSize); //cout << "yes" << endl; } } } sbuffIndex++; if (sbuffIndex >= BUFFER_SIZE) { if (first) { memcpy(pbuffer, &sbuffer[startIndex + headerSize], BUFFER_SIZE - startIndex - headerSize); memcpy(sbuffer, hbuffer, headerSize); memcpy(&sbuffer[headerSize], pbuffer, BUFFER_SIZE - startIndex - headerSize); sbuffIndex = BUFFER_SIZE - startIndex - 1; } else { memcpy(sbuffer, hbuffer, headerSize); sbuffIndex = headerSize - 1; startIndex = 0; } } if (!tryagain) i++; } } else { for (uint i = 0; i < readed; ++i) { b = buffer[i]; sbuffer[sbuffIndex] = b; if (sbuffIndex == dataSize - 1) { if (ret_func != 0) ret_func(data, sbuffer, dataSize); sbuffIndex = -1; } sbuffIndex++; } } } void PISerial::end() { terminate(); if (pbuffer != 0) { delete pbuffer; pbuffer = 0; } if (hbuffer != 0) { delete hbuffer; hbuffer = 0; } } 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(char * 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; }