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

/**
 * @addtogroup t_gpio_basic_api
 * @{
 * @defgroup t_gpio_callback_trigger test_gpio_callback_trigger
 * @brief TestPurpose: verify zephyr gpio callback triggered
 * under different INT modes
 * @}
 */

#include "test_gpio.h"

static struct drv_data data;
static int cb_cnt;

static int pin_num(uint32_t pins)
{
	int ret = 0;

	while (pins >>= 1) {
		ret++;
	}
	return ret;
}

static void callback(struct device *dev,
		     struct gpio_callback *gpio_cb, uint32_t pins)
{
	/*= checkpoint: pins should be marked with correct pin number bit =*/
	assert_true(pin_num(pins) == PIN_IN, NULL);
	TC_PRINT("callback triggered: %d\n", ++cb_cnt);
	if (cb_cnt >= MAX_INT_CNT) {
		struct drv_data *drv_data = CONTAINER_OF(gpio_cb,
							 struct drv_data, gpio_cb);
		gpio_pin_write(dev, PIN_OUT,
			       (drv_data->mode & GPIO_INT_ACTIVE_HIGH) ? 0 : 1);
		gpio_pin_configure(dev, PIN_IN, GPIO_DIR_IN);
	}
}

static int test_callback(int mode)
{
	struct device *dev = device_get_binding(DEV_NAME);

	gpio_pin_disable_callback(dev, PIN_IN);
	gpio_pin_disable_callback(dev, PIN_OUT);

	/* 1. set PIN_OUT to initial state */
	if (gpio_pin_configure(dev, PIN_OUT, GPIO_DIR_OUT) != 0) {
		TC_ERROR("PIN_OUT config fail\n");
		return TC_FAIL;
	}
	if (gpio_pin_write(dev, PIN_OUT,
			   (mode & GPIO_INT_ACTIVE_HIGH) ? 0 : 1) != 0) {
		TC_ERROR("set PIN_OUT init voltage fail\n");
		return TC_FAIL;
	}

	/* 2. configure PIN_IN callback and trigger condition */
	if (gpio_pin_configure(dev, PIN_IN,
			       GPIO_DIR_IN | GPIO_INT | mode | GPIO_INT_DEBOUNCE) != 0) {
		TC_ERROR("config PIN_IN fail");
		goto err_exit;
	}

	struct drv_data *drv_data = &data;

	drv_data->mode = mode;
	gpio_init_callback(&drv_data->gpio_cb, callback, BIT(PIN_IN));
	if (gpio_add_callback(dev, &drv_data->gpio_cb) != 0) {
		TC_ERROR("set PIN_IN callback fail\n");
		return TC_FAIL;
	}

	/* 3. enable callback, trigger PIN_IN interrupt by operate PIN_OUT */
	cb_cnt = 0;
	gpio_pin_enable_callback(dev, PIN_IN);
	k_sleep(100);
	gpio_pin_write(dev, PIN_OUT, (mode & GPIO_INT_ACTIVE_HIGH) ? 1 : 0);
	k_sleep(1000);

	/*= checkpoint: check callback is triggered =*/
	TC_PRINT("check enabled callback\n");
	if ((mode & GPIO_INT_EDGE) == GPIO_INT_EDGE) {
		if (cb_cnt != 1) {
			TC_ERROR("not trigger callback correctly\n");
			goto err_exit;
		}
		goto pass_exit;
	}

	if ((mode & GPIO_INT_LEVEL) == GPIO_INT_LEVEL) {
		if (cb_cnt != MAX_INT_CNT) {
			TC_ERROR("not trigger callback correctly\n");
			goto err_exit;
		}
	}

pass_exit:
	gpio_remove_callback(dev, &drv_data->gpio_cb);
	return TC_PASS;

err_exit:
	gpio_remove_callback(dev, &drv_data->gpio_cb);
	return TC_FAIL;
}

/* export test cases */
void test_gpio_callback_edge_high(void)
{
	assert_true(
		test_callback(GPIO_INT_EDGE | GPIO_INT_ACTIVE_HIGH) == TC_PASS,
		NULL);
}

void test_gpio_callback_edge_low(void)
{
	assert_true(
		test_callback(GPIO_INT_EDGE | GPIO_INT_ACTIVE_LOW) == TC_PASS,
		NULL);
}

void test_gpio_callback_level_high(void)
{
	assert_true(
		test_callback(GPIO_INT_LEVEL | GPIO_INT_ACTIVE_HIGH) == TC_PASS,
		NULL);
}

void test_gpio_callback_level_low(void)
{
	assert_true(
		test_callback(GPIO_INT_LEVEL | GPIO_INT_ACTIVE_LOW) == TC_PASS,
		NULL);
}
