/*
 * gat_i2c.c
 *
 *  Created on: Oct 11, 2024
 *      Author: true
 *
 * implements a shoddy i2c slave.
 * maximum speed 100KHz tested.
 * note: not yet tested.
 */

#include <CH59x_common.h>

#include "gat_gpio.h"

#include "comm/soft_i2c_slave.h"

#include <stdint.h>



#define GAT_ADDR_BASE       0x30
#define GAT_I2C_SPEED       100000

#define GAT_DATA_SIZE       256



struct I2CSoftSlave gat_slave;



enum {
    GAT_MODE_STARTING,
    GAT_MODE_READ,
    GAT_MODE_WRITE
};


uint8_t gat_state;
uint16_t gat_data_idx;
uint8_t gat_data[GAT_DATA_SIZE];



uint8_t gat_i2c_read_cb()
{
    uint8_t ret;

    switch (gat_state) {
        case GAT_MODE_STARTING: {
            gat_state = GAT_MODE_READ;
            // no break
        }
        case GAT_MODE_READ: {
            // can't read past end of buffer; just send 0xff
            if (gat_data_idx == GAT_DATA_SIZE) {
                ret = 0xff;
            } else {
                ret = gat_data[gat_data_idx & 0xff];
                if (gat_data_idx <= GAT_DATA_SIZE) gat_data_idx++;
            }
            return ret;
        }
        default: {
            return 0;
        }
    }
}

int8_t gat_i2c_write_cb(uint8_t dat)
{
    switch (gat_state) {

        case GAT_MODE_STARTING: {
            // master wrote our address
            gat_data_idx = dat;
            gat_state = GAT_MODE_WRITE;
            break;
        }
        case GAT_MODE_WRITE: {
            if (gat_data_idx >= GAT_DATA_SIZE) {
                return I2CSS_NACK;
            } else {
                gat_data[gat_data_idx++] = dat;
            }
            return I2CSS_OK;
        }
        default: {
            return I2CSS_NACK;
        }
    }
}

void gat_i2c_start_cb()
{
    gat_state = GAT_MODE_STARTING;
}



void gat_i2c_init()
{
    // determine I2C address from GP pin identification
    gat_slave.addr = gat_id + GAT_ADDR_BASE;

    // roughly guess bit time length for expected speed
    gat_slave.bit_time = GetSysClock() / GAT_I2C_SPEED / 4;

    // set up callbacks
    gat_slave.start_cb = gat_i2c_start_cb;
    gat_slave.rd_cb = gat_i2c_read_cb;
    gat_slave.wr_cb = gat_i2c_write_cb;

    // enable interrupt on SDA pin to detect start condition
    // this assumes GPIO has already been configured
}

void gat_i2c_irq_cb()
{
    i2css_start(&gat_slave);
}
