/*
 * i2c_device.h
 *
 *  Created on: Oct 12, 2024
 *      Author: true
 */

#ifndef USER_I2C_DEVICE_H_
#define USER_I2C_DEVICE_H_

#include <ch32v00x.h>
#include <stdint.h>



enum i2cs_werr {
    I2CS_WRITE_NO_ERROR,
    I2CS_WRITE_WHEN_READ_ONLY,
    I2CS_WRITE_READ_ONLY_REGISTER,
    I2CS_WRITE_BEYOND_END
};

enum ch32sub_regmap {
    // read-only
    REG_INTR_FLAGS = 0x00,
    REG_RSVD_01,
    REG_BTN_PUSHED_LATCHED,     // buttons currently pushed.
    REG_BTN_PUSHED,             // buttons pushed. reading will clear this value.
    REG_BTN_HELD,               // buttons currently being held. reading will clear this value.
    REG_BTN_RELEASED,           // buttons released. reading will clear this value.
    REG_BTN1_MASK,              // raw bitmask of button 1 state
    REG_BTN2_MASK,              // button interrupt is cleared on read of ANY REG_BTNx_MASK register
    REG_BTN3_MASK,
    REG_BTN4_MASK,
    REG_BTN5_MASK,

    REG_WERR_HI = 0x0c,         // write error count, high byte
    REG_WERR_LO,                // write error count, low byte
    REG_IRDA_READ_HI,           // IrDA read packet length, hi byte (currently always 0)
    REG_IRDA_READ_LO,           // IrDA read packet length, lo byte

    // read-write
    REG_INTR_FLAGS_CLEAR = 0x10,
    REG_INTR_ENABLE,            // interrupt enable flags
    REG_BTN_DEBOUNCE_TIME,
    REG_BTN1_INT_ENABLE,        // button 1 interrupt mask
    REG_BTN2_INT_ENABLE,        // button 2 interrupt mask
    REG_BTN3_INT_ENABLE,        // button 3 interrupt mask
    REG_BTN4_INT_ENABLE,        // button 4 interrupt mask
    REG_BTN5_INT_ENABLE,        // button 5 interrupt mask

    REG_RGB_HWEN,               // high = RGB_HWEN hi, low = RGB_HWEN low

    REG_IRDA_TIMER = 0x1a,      // IrDA read/write packet attempt time in 1/10 second increments (max ~25.5s sending time)
    REG_IRDA_WRITE_RETRY,       // IrDA write packet retry timeout in 1/100 second increments (max ~2.5s per retry)
    REG_IRDA_MODE,              // IrDA mode. 0 = idle, 1 = transmit, 2 = receive
    REG_IRDA_WRITE_HI,          // IrDA write packet length, hi byte (currently ignored)
    REG_IRDA_WRITE_LO,          // IrDA write packet length, lo byte

    REG_BTN1_HOLD_HI = 0x20,    // btn initial hold time in 2ms increments, hi byte
    REG_BTN1_HOLD_LO,           // btn initial hold time in 2ms increments, lo byte
    REG_BTN2_HOLD_HI,
    REG_BTN2_HOLD_LO,
    REG_BTN3_HOLD_HI,
    REG_BTN3_HOLD_LO,
    REG_BTN4_HOLD_HI,
    REG_BTN4_HOLD_LO,
    REG_BTN5_HOLD_HI,
    REG_BTN5_HOLD_LO,

    REG_BTN1_REPEAT_HI = 0x30,  // btn repeat time in 2ms increments, hi byte
    REG_BTN1_REPEAT_LO,         // btn repeat time in 2ms increments, lo byte
    REG_BTN2_REPEAT_HI,
    REG_BTN2_REPEAT_LO,
    REG_BTN3_REPEAT_HI,
    REG_BTN3_REPEAT_LO,
    REG_BTN4_REPEAT_HI,
    REG_BTN4_REPEAT_LO,
    REG_BTN5_REPEAT_HI,
    REG_BTN5_REPEAT_LO,
};



typedef void (*i2c_write_callback_t)(uint16_t reg, uint16_t length);
typedef void (*i2c_werr_callback_t)(uint16_t reg, uint8_t data, uint8_t error);
typedef void (*i2c_read_callback_t)(uint16_t reg);

typedef struct i2c_slave_state {
    uint8_t  addr_write;                    // first 2 bytes address the register file
    uint16_t addr_req;                      // requested read/write index as sent by the master
    uint16_t position;                      // current read/write index within the register file
    volatile uint8_t* volatile reg_file;    // register file pointer
    uint16_t reg_len;                       // register file max length
    i2c_write_callback_t write_callback;
    i2c_werr_callback_t werr_callback;
    i2c_read_callback_t read_callback;
    uint8_t read_only;                      // flag to disallow writes
    uint8_t writing;                        // flag to indicate currently writing
} i2c_slave_state;



extern volatile uint8_t i2cs_reg[256*3];



void i2cs_init(uint8_t address, uint8_t read_only_mode);
void i2cs_append_flag(uint8_t flag);



#endif /* USER_I2C_DEVICE_H_ */
