/*
 * Copyright 2009-2010  Stefan Gehn <stefan@srcbox.net>
 * 
 * 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 2 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 "SerialReader.hpp"
#include "settings.hpp"

#include <qextserialport.h>
#include <qdebug.h>


namespace IrTouch
{

SerialReader::SerialReader(): mSerialPort(0), mReadTimerId(-1)
{
	qDebug() << "SerialReader::SerialReader()";

	IrTouch::Settings *s = IrTouch::Settings::self();

  mSerialDeviceName = s->device();

  Packet::sFlipXPos = s->flipXPos();
  Packet::sCorrectXPos = s->correctXPos();
  Packet::sFlipYPos = s->flipYPos();
  Packet::sCorrectYPos = s->correctYPos();
  Packet::sCalibrationMatrix = s->calibrationMatrix();
  qDebug() << "Calibration Matrix:" << Packet::sCalibrationMatrix;

	startReader();
}

SerialReader::~SerialReader()
{
  qDebug() << "SerialReader::~SerialReader()";
	stopReader();
}

bool SerialReader::isActive() const
{
	return mSerialPort && mSerialPort->isOpen();
}

bool SerialReader::startReader()
{
  qDebug("SerialReader::startReader()");

  if (mSerialPort)
    return false;

  mSerialPort = new QextSerialPort(mSerialDeviceName, QextSerialPort::Polling);
  mSerialPort->setBaudRate(BAUD38400);
  mSerialPort->setFlowControl(FLOW_HARDWARE);
  mSerialPort->setParity(PAR_NONE);
  mSerialPort->setDataBits(DATA_8);
  mSerialPort->setStopBits(STOP_1);
  // timeout to wait for every incoming byte, this probably delays both
  // bytesAvailable() and read() methods for max. bytesToRead * timeout
  //
  // We don't want to wait/block for long and instead retry in the next call
  // to timerEvent()
  mSerialPort->setTimeout(250);

  if (!mSerialPort->open(QIODevice::ReadOnly))
  {
    qCritical() << "Opening port failed.";
    delete mSerialPort;
    mSerialPort = 0;
    return false;
  }

  // clear rs232 buffers
  mSerialPort->flush();

	// reading from serial is done in a timer-event
	mReadTimerId = startTimer(0);

#ifdef IRREADER_STATS
  mAvgPacketCnt = 0;
  mAvgPacketTime.start();
#endif

  return true;
}

void SerialReader::stopReader()
{
  qDebug("SerialReader::stopReader()");

  if (!mSerialPort)
    return;

  if (mReadTimerId != -1)
  {
    killTimer(mReadTimerId);
    mReadTimerId = -1;
  }

  if (mSerialPort->isOpen())
    mSerialPort->close();

  delete mSerialPort;
  mSerialPort = 0;
}

void SerialReader::timerEvent(QTimerEvent *event)
{
  Q_UNUSED(event);

  // -- read some data and append to previously unparsed data
  //    (note: maximum size for irpackets is about 60 bytes)
	QByteArray ar = mSerialPort->read(64);
	mData.append(ar);

  // -- decode some data (i.e. decode up to one irpacket)
  if (mData.isEmpty())
    return;

  if (mPacket.parse(mData) == true)
  {
    // finished parsing
    if (mPacket.isValid())
    {
      //qDebug() << "Finished parsing packet";
      emit parsedPacket(mPacket);
    }
    else
    {
      qWarning() << "Discarding invalid packet";
    }

#ifdef IRREADER_STATS
    mAvgPacketCnt++;
    if (mAvgPacketTime.elapsed() > 1000)
    {
      double elapsed = mAvgPacketTime.restart() / 1000.0;
			qDebug() << "~" << (mAvgPacketCnt / elapsed) << "packets/sec";
      mAvgPacketCnt = 0;
    }

    QTime now = QTime::currentTime();
		if (mAvgPacketCnt % 5 == 0)
    {
      int deltaPacket = mLastPacketTime.msecsTo(now);
			qDebug() << "delta time:" << deltaPacket << "msecs";
    }
    mLastPacketTime = now;
#endif

    mPacket.clear();
  }

  /*if (!mData.isEmpty())
    qDebug() << "Bytes left in buffer:" << mData.size();*/
}

} // namespace IrTouch

#include "moc_SerialReader.cpp"
