/*
 * Copyright (c) 2016 Intel Corporation
 *
 * SPDX-License-Identifier: Apache-2.0
 */

/*
 * @addtogroup test_aon_basic_operations
 * @{
 * @defgroup t_aon_periodic_timer test_aon_periodic_timer
 * @brief TestPurpose: verify AON timer works well
 * @details
 * - Test Steps
 *   -# Start AON timer and wait for the register change to propagate.
 *   -# Set timer to alarm every second.
 *   -# Sleep for a long time to wait for the alarm invoked.
 * - Expected Results
 *   -# AON counter runs at 32768Hz, which means the counter will decrease
 *	32768 in one second. Set AONT down counter initial value register to
 *	32768, so the alarm will be invoked every second.
 *
 *	Sleep for a little longer than 3 seconds, the timer ISR is expected
 *	to be invoked 3 times.
 * @}
 */

#include "test_aon.h"

#define ALARM_CNT 32768 /* about 1s */
#define SLEEP_TIME 3050 /* a little longer than 3s */

static volatile int actual_alarm_cnt;

static void aon_timer_callback(struct device *dev, void *user_data)
{
	TC_PRINT("Periodic timer callback invoked: %u\n", counter_read(dev));

	/* verify counter_get_pending_int() */
	if (counter_get_pending_int(dev)) {
		TC_PRINT("Counter interrupt is pending\n");
		actual_alarm_cnt++;
	}
}

static int test_timer(void)
{
	u32_t dummy_data = 30U;
	int expected_alarm_cnt = 0;
	struct device *aon_timer = device_get_binding(AON_TIMER);

	if (!aon_timer) {
		TC_PRINT("Cannot get AON Timer device\n");
		return TC_FAIL;
	}

	/* verify counter_start() */
	if (counter_start(aon_timer)) {
		TC_PRINT("Fail to start AON Timer device\n");
		return TC_FAIL;
	}

	/*
	 * The AON counter runs from the RTC clock at 32KHz (rather than
	 * the system clock which is 32MHz) so we need to spin for a few cycles
	 * allow the register change to propagate.
	 */
	k_sleep(10);
	TC_PRINT("Always-on timer started\n");

	/* verify counter_set_alarm() */
	if (counter_set_alarm(aon_timer, aon_timer_callback,
			      ALARM_CNT, (void *)&dummy_data)) {
		TC_PRINT("Fail to set alarm for AON Timer\n");
		return TC_FAIL;
	}

	/* long delay for the alarm and callback to happen */
	k_sleep(SLEEP_TIME);

	if (counter_set_alarm(aon_timer, NULL, 0, NULL)) {
		TC_PRINT("Periodic timer can not turn off\n");
		return TC_FAIL;
	}

	expected_alarm_cnt = (SLEEP_TIME/1000) / (32768/ALARM_CNT);

	TC_PRINT("expected_alarm_cnt = %d\n", expected_alarm_cnt);
	TC_PRINT("actual_alarm_cnt = %d\n", actual_alarm_cnt);

	if (actual_alarm_cnt != expected_alarm_cnt) {
		TC_PRINT("actual_alarm_cnt doesn't match expected_alarm_cnt\n");
		return TC_FAIL;
	}
	/*
	 * arduino_101 loader assumes the counter is running.
	 * If the counter is stopped, the next app you flash in
	 * cannot start without a hard reset or power cycle.
	 * So let's leave the counter in running state.
	 */
	return TC_PASS;
}

void test_aon_periodic_timer(void)
{
	zassert_true(test_timer() == TC_PASS, NULL);
}
