#include "gt1151.h"


volatile uint8_t gtIRQ = 0;
void IRAM_ATTR _gt_irq_handler() {
    noInterrupts();
    gtIRQ = 1;
    interrupts();
}

GT1151::GT1151(TwoWire* i2c) {
    wire = i2c;
}

void GT1151::setHandler(void (*handler)(int8_t, GTPoint*)) {
    touchHandler = handler;
}


void GT1151::armIRQ() {
    attachInterrupt(GT1151_INT_PIN, _gt_irq_handler, RISING);
}

void GT1151::onIRQ() {
    GTPoint points[CT_MAX_TOUCH];
    int16_t contacts = readInput((GTPoint *) &points);
    dev.holding = contacts > 0 && dev.pressing;
    dev.pressing = contacts > 0;
    if(dev.holding) {
        dev.dx = points[0].x - dev.points[0].x;
        dev.dy = points[0].y - dev.points[0].y;
    } else if(dev.pressing) {
        memcpy(dev.points,points,sizeof(GTPoint)*CT_MAX_TOUCH);
    }
    if (contacts < 0) return;
    if (contacts > 0) touchHandler(contacts, (GTPoint *)dev.points);
    WriteRegister(GT1151_COORD_ADDR, 0x00);
}


int16_t GT1151::readInput(GTPoint* points) {
    uint8_t* data = static_cast<uint8_t*>(static_cast<void*>(points));
    int touch_num;
    uint8_t regState;
    int error = !ReadRegister(GT1151_COORD_ADDR, &regState, 1);
    if ((regState & 0x80)==0) return -1;


    touch_num = regState & 0x0f;
    if(touch_num > 5) return -1;
    if (touch_num <= 0) return touch_num;


    error = !ReadRegister(GT1151_COORD_ADDR, data, sizeof(GTPoint) * touch_num);
    if (error) return -1;
    return touch_num;
}


void GT1151::Reset(void) {
    pinMode(GT1151_RESET_PIN, OUTPUT);
    pinMode(GT1151_INT_PIN, INPUT);
    digitalWrite(GT1151_RESET_PIN, HIGH);
    delay(100);
    digitalWrite(GT1151_RESET_PIN, LOW);
    delay(100);
    digitalWrite(GT1151_RESET_PIN, HIGH);
    delay(100);
}

void GT1151::ReadVersion(void) {
    uint8_t buf[4] = {};
    ReadRegister(GT1151_REG_ID, buf, 4);
}

void GT1151::begin(void) {
    delay(500);
    Reset();
    ReadVersion();
    armIRQ();
}

void GT1151::update() {

    noInterrupts();
    uint8_t irq = gtIRQ;
    gtIRQ = 0;
    interrupts();
    // Serial.printf("IRQ: %d\n",irq);
    if (irq) onIRQ();
    else dev.pressing = false;
}

bool GT1151::WriteRegister(uint16_t addr, uint8_t data) {
    wire->beginTransmission(GT1151_ADDRESS);
    wire->write(highByte(addr));
    wire->write(lowByte(addr));
    wire->write(data);
    wire->endTransmission();
    return true;
}

bool GT1151::ReadRegister(uint16_t addr,uint8_t data[],uint8_t length) {
    uint8_t ord(0);

    wire->beginTransmission(GT1151_ADDRESS);
    wire->write(highByte(addr));
    wire->write(lowByte(addr));
    wire->endTransmission();

    wire->requestFrom(static_cast<uint8_t>(GT1151_ADDRESS), length);

    while(wire->available()) {
        data[ord++] = wire->read();
    }

    return ord == length;
}