Files
pip/piserial.cpp
2012-01-16 01:01:49 +04:00

302 lines
7.4 KiB
C++

/*
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 <http://www.gnu.org/licenses/>.
*/
#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, &times) == -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;
}