/*
 * ch32sub.c
 *
 * the sub MCU is responsible for the following:
 * - user buttons (complete handling / filtering)
 * - rgb chip hw enable / disable
 * - IrDA rx/tx and IrDA transciever enable / disable
 * - accelerometer hardware interrupt
 *
 *  Created on: Oct 11, 2024
 *      Author: true
 */

#include "ch32sub.h"
#include "port_intr.h"

// interrupt callbacks
#include "ui/btn.h"



volatile uint8_t intr_pending = 0;

static void (*intr_cb[8])() = {
        btn_intr,
        0,
        0,
        0,
        0,
        0,
        0,
        0
};



__HIGH_CODE
void ch32sub_read(uint16_t reg, uint8_t *dat, uint8_t len)
{
    i2c_read_reg16(SUB_I2C_ADDR, reg, dat, len);
}

__HIGH_CODE
void ch32sub_write(uint16_t reg, uint8_t *dat, uint8_t len)
{
    i2c_write_reg16(SUB_I2C_ADDR, reg, dat, len);
}

__HIGH_CODE
uint8_t ch32sub_read_1b(uint16_t reg)
{
    uint8_t ret;

    ch32sub_read(reg, &ret, 1);

    return ret;
}

__HIGH_CODE
void ch32sub_write_1b(uint16_t reg, uint8_t dat)
{
    i2c_addr(SUB_I2C_ADDR, 0);
    i2c_wr(reg >> 8);
    i2c_wr(reg & 0xff);
    i2c_wr(dat);
    i2c_stop();
}

void ch32sub_isr()
{
    intr_pending = 1;
}

void ch32sub_process()
{
    uint8_t flags;
    uint8_t clear = 0;
    uint8_t i;

    if (intr_pending) {
        intr_pending = 0;

        // get flags
        flags = ch32sub_read_1b(REG_INTR_FLAGS);

        // process flags
        for (i = 0; i < 8; i++) {
            if (flags & (1 << i)) {
                if (intr_cb[i]) {
                    clear |= (1 << i);
                    intr_cb[i]();
                }
                else {
                    // unhandled interrupt; clear it?
                    // ch32sub_write_1b(REG_INTR_FLAGS, i << 1);
                }
            }
        }

        // clear flags
        ch32sub_write_1b(REG_INTR_FLAGS_CLEAR, clear);
    }
}

void ch32sub_init()
{
    // configure interrupt pin as pull-up
    // interrupt driven by CH32V003 is open drain active-lo
    GPIOB_ModeCfg(SUB_INTR_PIN, GPIO_ModeIN_PU);
    // configure interrupt to be rising edge
    GPIOB_ITModeCfg(SUB_INTR_PIN, GPIO_ITMode_RiseEdge);

    // register interrupt handler
    // note: this is handled as "high priority" within the interrupt handler now.
    // port_intr_cb_register(PORT_INTR_GPIOB, SUB_INTR_PIN_NR, ch32sub_isr);

    // clear any interrupts now, to start from clean slate
    ch32sub_write_1b(REG_INTR_FLAGS_CLEAR, 0xff);
}

void ch32sub_rgb_hwen(uint8_t en)
{
    ch32sub_write_1b(REG_RGB_HWEN, en);
}

void ch32sub_intr_defaults()
{
    int8_t i;
    uint8_t dat[5];

    // we want interrupted for all button events
    for (i = 0; i < 5; i++) {
        dat[i] = BTN_PUSH | BTN_HOLD | BTN_RELEASE;
    }

    // enable button interrupt sources
    ch32sub_write(REG_BTN1_INT_ENABLE, dat, 5);

    // enable all interrupt flags we care about
    dat[0] = INT_BTN | INT_UTX_DONE | INT_UTX_TIMEOUT | INT_UTX_ERROR | INT_URX_RCVD;
    ch32sub_write_1b(REG_INTR_ENABLE, dat[0]);
}
