#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/counter.h>


static void timer0_callback(const struct device *dev, uint8_t chan_id, uint32_t ticks, void *user_data)
{
    printk("TIMER0 - Channel: %d Ticks: %d\n", chan_id, ticks);
}

static void timer1_callback(const struct device *dev, uint8_t chan_id, uint32_t ticks, void *user_data)
{
    printk("TIMER1 Channel: %d Ticks: %d\n", chan_id, ticks);
}

static void timer2_callback(const struct device *dev, uint8_t chan_id, uint32_t ticks, void *user_data)
{
    printk("TIMER2 Channel: %d Ticks: %d\n", chan_id, ticks);
}

static void timer3_callback(const struct device *dev, uint8_t chan_id, uint32_t ticks, void *user_data)
{
    printk("TIMER3 Channel: %d Ticks: %d\n", chan_id, ticks);
}

static void timer4_callback(const struct device *dev, uint8_t chan_id, uint32_t ticks, void *user_data)
{
    printk("TIMER4 Channel: %d Ticks: %d\n", chan_id, ticks);
}

void check_channel_alarm_error(const char* name, int error, int channel)
{
    if(error)
    {
        printf("%s error: %d - failed to set alarm on channel %d\n", name, error, channel);
    }
}

void check_device_ready(const char* name, const struct device* dev)
{
    if( !device_is_ready(dev) )
    {
        printk("%s error: device init failed\n", name);
    }
}

void setup_timer(const char* name, const struct device* dev, struct counter_alarm_cfg* config)
{
    check_device_ready(name, dev);

    for(int channel = 0; channel < 4; ++channel)
    {
        int error = counter_set_channel_alarm(dev, channel, config);
        check_channel_alarm_error(name, error, channel);
    }
}

void start_timer(const char* name, const struct device* dev)
{
    int error = counter_start(dev);
    if(error)
    {
        printf("%s error: %d - failed to start timer\n", name, error);
    }

}

int main(void)
{
    // const struct device *timer0_dev = DEVICE_DT_GET(DT_NODELABEL(timer0));
    // struct counter_alarm_cfg timer0_alarm_config = {
    //     .callback = timer0_callback,
    //     .ticks = counter_us_to_ticks(timer0_dev, 500000),
    //     .flags = COUNTER_ALARM_CFG_EXPIRE_WHEN_LATE, 
    // };
    // setup_timer("timer0", timer0_dev, &timer0_alarm_config);
    // start_timer("timer0", timer0_dev);

    const struct device *timer1_dev = DEVICE_DT_GET(DT_NODELABEL(timer1));
    struct counter_alarm_cfg timer1_alarm_config = {
        .callback = timer1_callback,
        .ticks = counter_us_to_ticks(timer1_dev, 500000),
        .flags = COUNTER_ALARM_CFG_EXPIRE_WHEN_LATE, 
    };
    setup_timer("timer1", timer1_dev, &timer1_alarm_config);
    start_timer("timer1", timer1_dev);

    const struct device *timer2_dev = DEVICE_DT_GET(DT_NODELABEL(timer2));
    struct counter_alarm_cfg timer2_alarm_config = {
        .callback = timer2_callback,
        .ticks = counter_us_to_ticks(timer2_dev, 500000),
        .flags = COUNTER_ALARM_CFG_EXPIRE_WHEN_LATE, 
    };
    setup_timer("timer2", timer2_dev, &timer2_alarm_config);
    start_timer("timer2", timer2_dev);

    const struct device *timer3_dev = DEVICE_DT_GET(DT_NODELABEL(timer3));
    struct counter_alarm_cfg timer3_alarm_config = {
        .callback = timer3_callback,
        .ticks = counter_us_to_ticks(timer3_dev, 500000),
        .flags = COUNTER_ALARM_CFG_EXPIRE_WHEN_LATE, 
    };
    setup_timer("timer3", timer3_dev, &timer3_alarm_config);
    start_timer("timer3", timer3_dev);

    const struct device *timer4_dev = DEVICE_DT_GET(DT_NODELABEL(timer4));
    struct counter_alarm_cfg timer4_alarm_config = {
        .callback = timer4_callback,
        .ticks = counter_us_to_ticks(timer4_dev, 500000),
        .flags = COUNTER_ALARM_CFG_EXPIRE_WHEN_LATE, 
    };
    setup_timer("timer4", timer4_dev, &timer4_alarm_config);
    start_timer("timer4", timer4_dev);
    
    while(1)
    {
        k_msleep(1000);
    }

    return 0;
}