239 lines
6.3 KiB
C++
239 lines
6.3 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, 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;
|
|
}
|