/*
* Unofficial Qt Serial Port Library
*
* Copyright (c) 2010 Inbiza Systems Inc. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser 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 Lesser General Public License
* along with this program. If not, see
*
* author labs@inbiza.com
*/
#include
#include
#include
#include
#include
#include
#include "receiver.h"
extern TNX::QSerialPort defaultSerPort;
Receiver::Receiver(QObject *parent)
: QObject(parent), serialPort_(defaultSerPort), timeoutTimer_(0), readBuffer_(NULL),
dataSetSize_(0), bufferSize_(0), doRestartTimer_(false), totalBytesRead_(0)
{
#if defined(Q_OS_WIN)
serialPort_.setPortName("COM3");
#else
serialPort_.setPortName("/dev/ttyS0");
#endif
socket_ = new QUdpSocket(this);
listenPort_ = 7865;
udpPortNo_ = 7865;
udpIp_ = "193.168.0.52";
}
Receiver::Receiver(TNX::QSerialPort &serPort, const QString &udpAddr, int listenPort, int bufferSize,
QObject *parent)
: QObject(parent), serialPort_(serPort), listenPort_(listenPort), timeoutTimer_(0), readBuffer_(NULL),
dataSetSize_(0), bufferSize_(bufferSize), doRestartTimer_(false), totalBytesRead_(0)
{
if ( udpAddr.split(":").count() > 1 ) {
udpIp_ = udpAddr.split(":").at(0);
udpPortNo_ = udpAddr.split(":").at(1).toInt();
}
else {
udpPortNo_ = udpAddr.toInt();
}
socket_ = new QUdpSocket(this);
}
Receiver::~Receiver()
{
}
bool Receiver::start()
{
if ( !socket_->open(QIODevice::ReadWrite) )
qFatal("Cannot open UDP port: \"%d\". Giving up.", udpPortNo_);
connect(socket_, SIGNAL(readyRead()), SLOT(onControlDataReceived()));
if ( !socket_->bind(listenPort_) )
qFatal("Cannot bind to port: \"%d\". Giving up.", listenPort_);
if ( serialPort_.open() ) {
serialPort_.flushInBuffer();
serialPort_.flushOutBuffer();
}
else {
qFatal("Cannot open serial port: \"%s\". Giving up.", qPrintable(serialPort_.errorString()));
}
qDebug() << "Getting ready for receiving data via " << serialPort_.portName();
qDebug() << "Control channel @ UDP port " << listenPort_;
connect(&serialPort_, SIGNAL(readyRead()), SLOT(onDataReceived()));
return true;
}
bool Receiver::stop()
{
disconnect(socket_, SIGNAL(readyRead()), this, SLOT(onControlDataReceived()));
socket_->close();
if ( !serialPort_.isOpen() ) {
return true;
}
else {
qDebug() << "Number of bytes in serial port buffer: " << serialPort_.bytesAvailable();
delete[] readBuffer_;
readBuffer_ = NULL;
disconnect(&serialPort_, SIGNAL(readyRead()), this, SLOT(onDataReceived()));
serialPort_.close();
}
return true;
}
void Receiver::timerEvent(QTimerEvent *event)
{
killTimer(event->timerId());
// make sure that we don't leak timer
Q_ASSERT( timeoutTimer_ == event->timerId() );
timeoutTimer_ = 0;
qDebug() << "Timeout occurred while waiting for more data.";
qDebug() << "Number of pending bytes: " << serialPort_.bytesAvailable();
qDebug() << "Number of total bytes read: " << totalBytesRead_;
socket_->writeDatagram(QString("RECV___END@Transfer %1 - Total bytes: %2 - Received bytes: %3 - Pending bytes: %4")
.arg("*****failed *** TIMEOUT ****!")
.arg(dataSetSize_)
.arg(totalBytesRead_)
.arg(serialPort_.bytesAvailable()).toLatin1(),
QHostAddress(udpIp_), udpPortNo_);
serialPort_.flushInBuffer();
dataSetSize_ = 0;
delete[] readBuffer_;
readBuffer_ = NULL;
}
void Receiver::onControlDataReceived()
{
using TNX::QPortSettings;
QByteArray recv = socket_->read(1000);
if ( recv.left(10) == "SEND_START" ) {
doRestartTimer_ = true;
delete[] readBuffer_;
readBuffer_ = NULL;
if ( timeoutTimer_ != 0 ) {
killTimer(timeoutTimer_);
serialPort_.flushInBuffer();
qDebug() << "!!!!! Operation canceled by transmitter. Starting a new transmission.";
}
// change port settings
dataSetSize_ = recv.right(recv.size() - 11).split('@').at(0).toInt();
QString settings = recv.right(recv.size() - 11).split('@').at(1); // excluding @ as well
std::cout << "Expecting " << dataSetSize_ << " bytes @" << qPrintable(settings)
<< " Time: " << qPrintable(QDateTime::currentDateTime().toString("hh:mm:ss.zzz"));
// make sure that this platform support given settings
QPortSettings ps;
if ( !ps.set(settings) ) {
socket_->writeDatagram("RECV_USSET", QHostAddress(udpIp_), udpPortNo_);
std::cout << " -- unsupported settings" << std::endl;
}
else {
readBuffer_ = new char[dataSetSize_];
serialPort_.setPortSettings(ps);
timeoutTimer_ = startTimer(5000);
socket_->writeDatagram("RECV_READY", QHostAddress(udpIp_), udpPortNo_);
}
}
else if ( recv.left(10) == "SEND___END" ) {
// do nothing
std::cout << "." << std::endl;
}
else if ( recv.left(10) == "SIG_CTS_RQ" ) {
socket_->writeDatagram(QString("SIG_CTS___@%1").arg(sigValToString(serialPort_.cts())).toAscii(),
QHostAddress(udpIp_), udpPortNo_);
}
else if ( recv.left(10) == "SIG_DSR_RQ" ) {
socket_->writeDatagram(QString("SIG_DSR___@%1").arg(sigValToString(serialPort_.dsr())).toAscii(),
QHostAddress(udpIp_), udpPortNo_);
}
else if ( recv.left(10) == "SIG_DCD_RQ" ) {
socket_->writeDatagram(QString("SIG_DCD___@%1").arg(sigValToString(serialPort_.dcd())).toAscii(),
QHostAddress(udpIp_), udpPortNo_);
}
else if ( recv.left(10) == "SIG_RI__RQ" ) {
socket_->writeDatagram(QString("SIG_RI____@%1").arg(sigValToString(serialPort_.ri())).toAscii(),
QHostAddress(udpIp_), udpPortNo_);
}
else if ( recv.left(10) == "SIG_TEST_S" ) {
serialPort_.setRts(true);
serialPort_.setDtr(true);
socket_->writeDatagram("SIG_TEST_R", QHostAddress(udpIp_), udpPortNo_);
}
}
void Receiver::onDataReceived()
{
using namespace TNX;
static qint64 read = 0;
static qint64 offset = 0;
if ( !readBuffer_ ) {
std::cout << "Received data when expecting nothing. Not good." << std::endl;
return;
}
killTimer(timeoutTimer_);
timeoutTimer_ = startTimer(5000);
if ( doRestartTimer_ ) {
doRestartTimer_ = false;
readTimer_.restart();
read = 0LL; // duplication: in case that timeout occurs
offset = 0LL;
}
offset = read;
read += serialPort_.read(readBuffer_+ ((int)offset), (bufferSize_ <= 0 ? (dataSetSize_ - (int)read) : bufferSize_));
totalBytesRead_ = read;
if ( read == dataSetSize_ ) {
int elapsed = readTimer_.elapsed();
killTimer(timeoutTimer_);
timeoutTimer_ = 0;
int total = 0;
for (int i=0; i < dataSetSize_; i++) {
total += (int)readBuffer_[i];
}
bool correct = (total == ((dataSetSize_ / 64) * (63*64/2)));
read = 0LL;
offset = 0LL;
socket_->writeDatagram(QString("RECV___END@Transfer %1 - Total bytes: %2 - Elapsed time: %3ms")
.arg(correct?"is completed successfully":"failed *** data corrupted!")
.arg(dataSetSize_)
.arg(elapsed).toLatin1(),
QHostAddress(udpIp_), udpPortNo_);
dataSetSize_ = 0;
delete[] readBuffer_;
readBuffer_ = NULL;
}
}