#include "lattice_com_reign.h"
#include "ui_lattice_com_reign.h"

#include <QTime>

lattice_com_reign::lattice_com_reign(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::lattice_com_reign)
{
    ui->setupUi(this);
    log = "";
    on_com_reflesh_clicked();
    tmr.setInterval(200);
    tmr.setSingleShot(false);
    //tmr.setTimerType();
    QObject::connect(&tmr, SIGNAL(timeout()), this, SLOT (com_data_received()));
    //QObject::connect(&com, SIGNAL(readyRead()), this, SLOT (com_data_received()));
    QWidget* widgets_unlocked[] = { ui->com_tx };
    for (int i = 0; i < sizeof(widgets_unlocked)/sizeof(QWidget*); i++)
        widgets_unlocked[i]->setEnabled(com.isOpen());
    tmr.start(200);
    i2c_data.clear();
}

lattice_com_reign::~lattice_com_reign()
{
    delete ui;
}

void lattice_com_reign::on_com_reflesh_clicked()
{
    com_list = QSerialPortInfo::availablePorts();
    for (int i = 0; i < com_list.length(); i++) {
        //toLog ("COM: " +  com_list.at(i).portName() + ", DESC: " + com_list.at(i).description());
        //if (com_list.at(i).portName() == "ttyUSB0")
        //    com_list.removeAt(i);
    }
    QObject::disconnect(ui->com_list, SIGNAL(currentIndexChanged(int)), this, SLOT(on_com_list_currentIndexChanged(int)));
    for (int i = ui->com_list->count(); i >=0; i--)
        ui->com_list->removeItem(i);
    for (int i = 0; i < com_list.length(); i++)
        ui->com_list->addItem(com_list.at(i).portName());
    QObject::connect(ui->com_list, SIGNAL(currentIndexChanged(int)), this, SLOT(on_com_list_currentIndexChanged(int)));    
    ui->com_list->setToolTip(com_list.at(ui->com_list->currentIndex()).description());
}

void lattice_com_reign::on_com_list_currentIndexChanged(int index)
{
    ui->com_list->setToolTip(com_list.at(index).description());
}

void lattice_com_reign::on_connect_clicked()
{
    QWidget* widgets_locked[] = { ui->com_list, ui->com_reflesh };
    QWidget* widgets_unlocked[] = { ui->com_tx };
    if (ui->connect->text() == "Connect")   {
        com.setPortName(com_list.at(ui->com_list->currentIndex()).portName());
        if (com.open(QSerialPort::ReadWrite))   {
            com.setParity(QSerialPort::NoParity);
            com.setDataBits(QSerialPort::Data8);
            com.setStopBits(QSerialPort::OneStop);
            com.setFlowControl(QSerialPort::NoFlowControl);
            com.setBaudRate(921600);
            ui->connect->setText("Disconnect");
            toLog ("COM " + com.portName() + " OPENED OK");
        }
        else
            toLog ("COM " + com.portName() + " OPEN ERROR");
    }
    else    {
        com.close();
        toLog ("COM " + com.portName() + " CLOSED");
        ui->connect->setText("Connect");
    }
    for (int i = 0; i < sizeof(widgets_locked)/sizeof(QWidget*); i++)
        widgets_locked[i]->setEnabled(!com.isOpen());
    for (int i = 0; i < sizeof(widgets_unlocked)/sizeof(QWidget*); i++)
        widgets_unlocked[i]->setEnabled(com.isOpen());
}

void lattice_com_reign::toLog(QString str)
{
    log = QTime::currentTime().toString("HH:mm:ss") + "\t" + str + "\n" + log;
    ui->log->setText("LOG\n\n" + log);
}

void lattice_com_reign::on_com_tx_clicked()
{
    QByteArray a;
    a.push_back(ui->byte_to_transmit->value());
    com.write(a);
    toLog ("BYTE " + QString::number(ui->byte_to_transmit->value(), 16) + " TX");
}

void lattice_com_reign::com_data_received()
{
    static int last_com_lines[3] = { 0, 0, 0 };
    static int com_lines[3];
    ui->time->setText(QTime::currentTime().toString("HH:mm:ss"));
    if (com.isOpen() == false)
        return;
    QByteArray bytes_read = com.readAll();
    QString i2c_data_str = "";
    QString com_outs_now = "CTS ";/*
    if (com.isRequestToSend())      com_outs_now = com_outs_now + "1, DTR ";
    else                            com_outs_now = com_outs_now + "0, DTR ";
    if (com.isDataTerminalReady())  com_outs_now = com_outs_now + "1";
    else                            com_outs_now = com_outs_now + "0";*/
    int pinout = com.pinoutSignals();
#if 0
    if (pinout & (QSerialPort::ClearToSendSignal))         com_outs_now = com_outs_now + "1, DSR ";
    else                                                   com_outs_now = com_outs_now + "0, DSR ";
    if (pinout & (QSerialPort::DataSetReadySignal))        com_outs_now = com_outs_now + "1, DCD ";
    else                                                   com_outs_now = com_outs_now + "0, DCD ";
    if (pinout & (QSerialPort::DataCarrierDetectSignal))   com_outs_now = com_outs_now + "1";
    else                                                   com_outs_now = com_outs_now + "0";
#else
    com_lines[0] = 0; com_lines[1] = 0; com_lines[2] = 0;
    if (pinout & (QSerialPort::ClearToSendSignal))         com_lines[0] = 1;
    if (pinout & (QSerialPort::DataSetReadySignal))        com_lines[1] = 1;
    if (pinout & (QSerialPort::DataCarrierDetectSignal))   com_lines[2] = 1;
    //if ()
#endif
    /*if (com_outs_now != com_outs)   {
        com_outs = com_outs_now;
        toLog(com_outs);
    }*/
    if (bytes_read.length() == 0)   {
        if (i2c_data.length() != 0) {
            if (i2c_data.length() >= 3) {
                if (((i2c_data.at(2) == 0x0A) && (i2c_data.at(3) == 0)) || ((i2c_data.at(2) == 0x1E) && (i2c_data.at(3) == 0)) \
                        || ((i2c_data.at(2) == 0x05) && (i2c_data.at(3) == 1)) || ((i2c_data.at(2) == 0) && (i2c_data.at(3) == 0)))
                    i2c_data_str = "I2C DATA TO HOST: ";
                else
                    i2c_data_str = "I2C DATA FROM HOST: ";
            }
            else
                i2c_data_str = "I2C DATA FROM HOST: ";
            for (int i = 0; i < i2c_data.length(); i++)
                i2c_data_str = i2c_data_str + QString::number(i2c_data.at(i) & 0xFF, 16) + " ";
            i2c_data.clear();
            toLog (i2c_data_str);
        }
        ui->read_progress->setText("");
        return;
    }
    for (int i = 0; i < bytes_read.length(); i++)   {
        //toLog ("RECEIVED BYTE " + QString::number(((int)(bytes_read.at(i)) & 0xFF), 16));// + ", PINOUT " + QString::number(pinout, 16));
        i2c_data.push_back(bytes_read.at(i));
        if (i2c_data.length() > 2)  {
            if (((i2c_data.at(i2c_data.length() - 1) & 0xFF) == 0xFF) && ((i2c_data.at(i2c_data.length() - 2) & 0xFF) == 0xFF))   {
                if (i2c_data.length() >= 3) {
                    if (((i2c_data.at(2) == 0x0A) && (i2c_data.at(3) == 0)) || ((i2c_data.at(2) == 0x1E) && (i2c_data.at(3) == 0)) \
                            || ((i2c_data.at(2) == 0x05) && (i2c_data.at(3) == 1)) || ((i2c_data.at(2) == 0) && (i2c_data.at(3) == 0)))
                        i2c_data_str = "I2C DATA TO HOST: ";
                    else
                        i2c_data_str = "I2C DATA FROM HOST: ";
                }
                else
                    i2c_data_str = "I2C DATA FROM HOST: ";
                for (int i = 0; i < (i2c_data.length() - 2); i++)
                    i2c_data_str = i2c_data_str + QString::number(i2c_data.at(i) & 0xFF, 16) + " ";
                i2c_data.clear();
                i2c_data.push_back(0xFF);   i2c_data.push_back(0xFF);
                toLog (i2c_data_str);
            }
            //qDebug ("I2C DATA LEN %d, LAST DATA %d %d", i2c_data.length(), i2c_data.at(i2c_data.length() - 1), i2c_data.at(i2c_data.length() - 2));
        }
        ui->read_progress->setText("Reading " + QString::number(i2c_data.length()));
    }
}

void lattice_com_reign::on_clear_log_clicked()
{
    log = "";
    ui->log->setText("LOG\n\n" + log);
}

#if 0
/*
 * Scan a report descriptor before the device is added to the bus.
 * Sets device groups and other properties that determine what driver
 * to load.
 */
int lattice_com_reign::hid_scan_report(__u8* stt, __u8* stp)//(struct hid_device *hid)
{
    struct hid_parser parser;//struct hid_parser *parser;
    struct hid_item item;
    __u8 *start = stt;//hid->dev_rdesc;
    __u8 *end = stp;//start + hid->dev_rsize;
    static int (*dispatch_type[])(struct hid_parser *parser,
                      struct hid_item *item) = {
        hid_scan_main,
        hid_parser_global,
        hid_parser_local,
        hid_parser_reserved
    };

    //parser = vzalloc(sizeof(struct hid_parser));
    //if (!parser)
    //    return -ENOMEM;

    parser.device = hid;
    //hid->group = HID_GROUP_GENERIC;

    /*
     * The parsing is simpler than the one in hid_open_report() as we should
     * be robust against hid errors. Those errors will be raised by
     * hid_open_report() anyway.
     */
    while ((start = fetch_item(start, end, &item)) != NULL)
        dispatch_type[item.type](&parser, &item);

    /*
     * Handle special flags set during scanning.
     */
    if ((parser.scan_flags & HID_SCAN_FLAG_MT_WIN_8) &&
        (hid->group == HID_GROUP_MULTITOUCH))
        hid->group = HID_GROUP_MULTITOUCH_WIN_8;

    /*
     * Vendor specific handlings
     */
#if 0
    switch (hid->vendor) {
    case USB_VENDOR_ID_WACOM:
        hid->group = HID_GROUP_WACOM;
        break;
    case USB_VENDOR_ID_SYNAPTICS:
        if (hid->group == HID_GROUP_GENERIC)
            if ((parser->scan_flags & HID_SCAN_FLAG_VENDOR_SPECIFIC)
                && (parser->scan_flags & HID_SCAN_FLAG_GD_POINTER))
                /*
                 * hid-rmi should take care of them,
                 * not hid-generic
                 */
                hid->group = HID_GROUP_RMI;
        break;
    }
#endif

    //kfree(parser->collection_stack);
    //vfree(parser);
    return 0;
}
#endif
