#include "binary_protocol.h"
#include <stdio.h>
#include <string.h>
#include "ccittcrc.h"
#include <time.h>

BinaryProtocol::BinaryProtocol(QObject *parent) : QObject(parent)
{
    own_address = 0;
    header_detected = false;

    frameTimer = new QTimer(this);
    connect(frameTimer, SIGNAL(timeout()), this, SLOT(frameTimerTimeout()));
    frameTimer->setSingleShot(true);
}

BinaryProtocol::~BinaryProtocol()
{

}

void BinaryProtocol::frameTimerTimeout(void)
{
    header_detected = false;
    emit frameTimeout();
}

void BinaryProtocol::repeat(void)
{
    if (protocolLenOut > 0)
    {
        emit protocolWrite(protocolBuffOut, protocolLenOut);
    }
}

void BinaryProtocol::writeRaw(uint8_t *buff, size_t len)
{
    emit protocolWrite(buff, len);
}

void BinaryProtocol::send(uint8_t *buff, size_t len)
{
    uint16_t crc;
    protocolLenOut = 0;

    if (buff[0] == 0xFF)
    {
        error_count++;
    }

    if (own_address)
    {
        len++; //extra address byte in command
    }

    protocolBuffOut[protocolLenOut++] = BINARY_STX;

    protocolBuffOut[protocolLenOut++] = (len + 2) & 0xff;
    protocolBuffOut[protocolLenOut++] = ((len + 2) >> 8) & 0xff;

    protocolBuffOut[protocolLenOut++] = protocolBuffOut[1] ^ 0xff;
    protocolBuffOut[protocolLenOut++] = protocolBuffOut[2] ^ 0xff;


    if (own_address)
    {
        //address + command
        protocolBuffOut[protocolLenOut] = own_address;
        memcpy(&protocolBuffOut[protocolLenOut+1], buff, len-1);
    }
    else
    {
        memcpy(&protocolBuffOut[protocolLenOut], buff, len);
    }

    crc = GetCCITTCRC(&protocolBuffOut[protocolLenOut], len);

    protocolLenOut+=len;

    protocolBuffOut[protocolLenOut++] = (uint8_t)(crc & 0x00FF);
    protocolBuffOut[protocolLenOut++] = (uint8_t)((crc >> 8) & 0x00FF);

    emit protocolWrite(protocolBuffOut, protocolLenOut);
}

uint16_t BinaryProtocol::parse(uint8_t *buff, size_t len)
{
	size_t k;
    uint8_t cmd[5];
    uint16_t res = 1;
    static uint8_t header[5];
    //static uint32_t start_frame_time;

	for (k=0; k< len; k++)
	{
		header[0] = header[1];
		header[1] = header[2];
		header[2] = header[3];
		header[3] = header[4];
		header[4] = buff[k];

		if (header_detected == false)
		{
            frameTimer->start(500);
			if (header[0] == BINARY_STX && header[1] == (header[3] ^ 0xff) && header[2] == (header[4] ^ 0xff))
			{
				//header detected
				protocolReqLen = header[1] | (header[2] << 8);

				if (protocolReqLen > sizeof(protocolBuff))
				{
					continue;
				}
				protocolBuffIdx = 0;
				res = protocolReqLen;
				header_detected = true;
			}
		}
		else
		{
			protocolBuff[protocolBuffIdx++] = buff[k];
			if (protocolBuffIdx == protocolReqLen)
			{
				header_detected = false;
				if (GetCCITTCRC(protocolBuff, protocolBuffIdx - 2) != (uint16_t)(protocolBuff[protocolBuffIdx-2]) + (uint16_t)(protocolBuff[protocolBuffIdx-1] << 8))
				{
					cmd[0] = 0xff; //protocol error
					cmd[1] = 0xff;
					cmd[2] = 0x02; //wrong CRC
                    send(cmd, 3);
					if (buff[k] == BINARY_STX)
					{
						protocolBuffIdx = 0;
					}
					break;
                    emit frameError();
				}

                frameTimer->stop();

                if (own_address)
                {
                    if (protocolBuff[0] == own_address)
                    {
                        emit frameComplete(protocolBuff+1, protocolBuffIdx-3);
                    }
                }
                else
                {
                    emit frameComplete(protocolBuff, protocolBuffIdx-2);
                }

			}
		}
	}

	return res;
}

void BinaryProtocol::setAddress(uint8_t address)
{
    own_address = address;
}

uint8_t BinaryProtocol::getAddress(void)
{
    return own_address;
}
