#include "solari_rtc.h"

#define LOG_LEVEL CONFIG_LOG_DEFAULT_LEVEL
LOG_MODULE_REGISTER(rtc, LOG_LEVEL_ERR);

#define DELAY 1000000  //1s
#define ALARM_CHANNEL_ID 0

struct counter_alarm_cfg alarm_cfg;
const struct device *counter_dev;

#define TIMER DT_LABEL(DT_NODELABEL(rtc0))

static void (*p_rtc_callback)(uint32_t elapsed_s);
static int now_sec = 0;
static uint32_t s_epoch = 0;

static void epoch_update(const struct device *counter_dev)
{
	uint32_t now_ticks;
	int now_usec;
	int err;
	static uint32_t old_ticks = 0;

	err = counter_get_value(counter_dev, &now_ticks);
	if (err) {
		LOG_ERR("Failed to read counter value (err %d)", err);
		return;
	}

	now_usec = counter_ticks_to_us(counter_dev, now_ticks - old_ticks);
	now_sec = (int)(now_usec / USEC_PER_SEC);
	s_epoch += now_sec;

	old_ticks = now_ticks;
}

static void test_counter_interrupt_fn(const struct device *counter_dev,
				      uint8_t chan_id, uint32_t ticks,
				      void *user_data)
{
	int err;

	epoch_update(counter_dev);

	err = counter_set_channel_alarm(counter_dev, ALARM_CHANNEL_ID,
					user_data);
	if (err != 0) {
		LOG_ERR("Alarm could not be set\n");
	}

	//Application Callback
	(*p_rtc_callback)(now_sec);
}

static int rtc_init(void)
{
	LOG_INF("Counter alarm sample\n\n");
	counter_dev = device_get_binding(TIMER);
	LOG_INF("My name is %s\n",counter_dev->name);
	if (counter_dev == NULL) {
		LOG_ERR("Device not found\n");
		return -1;
	}

	return 0;
}

static int rtc_set_callback(void (*p_fn)(uint32_t))
{
	int ret = 0;
	if(p_fn == NULL)
		ret =  -1;
	else
		p_rtc_callback = p_fn;

	return ret;
}

static int rtc_set_alarm(uint32_t s)
{
	int err = 0;
	counter_start(counter_dev);
	alarm_cfg.flags = 0;
	alarm_cfg.ticks = counter_us_to_ticks(counter_dev, s*DELAY);
	alarm_cfg.callback = test_counter_interrupt_fn;
	alarm_cfg.user_data = &alarm_cfg;

	epoch_update(counter_dev);
	err = counter_set_channel_alarm(counter_dev, ALARM_CHANNEL_ID,
					&alarm_cfg);
	LOG_INF("Set RTC WakeUp in %u sec (%u ticks)\n",
	       (uint32_t)(counter_ticks_to_us(counter_dev,
					   alarm_cfg.ticks) / USEC_PER_SEC),
	       alarm_cfg.ticks);

	if (-EINVAL == err) {
		LOG_ERR("Alarm settings invalid\n");
	} else if (-ENOTSUP == err) {
		LOG_ERR("Alarm setting request not supported\n");
	} else if (err != 0) {
		LOG_ERR("Error\n");
	}

	return err;
}

static void rtc_set_data_time (	uint32_t epoch_now_s )
{
	s_epoch = epoch_now_s;
}

static uint32_t rtc_get_data_time (void)
{
	return s_epoch;
}

static rtc_t rtc = {
	.init = &rtc_init,
	.set_callback = &rtc_set_callback,
	.set_alarm = &rtc_set_alarm,
	.set_data_time = &rtc_set_data_time,
	.get_data_time = &rtc_get_data_time
};

//public declaration
rtc_t* p_rtc = &rtc;