/*
 * Copyright (c) 2016 Open-RnD Sp. z o.o.
 * Copyright (c) 2020 Nordic Semiconductor ASA
 *
 * SPDX-License-Identifier: Apache-2.0
 */


#include <zephyr/zephyr.h>
#include <zephyr/device.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/sys/util.h>
#include <zephyr/sys/printk.h>
#include <inttypes.h>
#include <nrfx_gpiote.h>
#include <hal/nrf_saadc.h>

#include <nrfx_dppi.h>
#include <helpers/nrfx_gppi.h>
#include <hal/nrf_power.h>
#include <hal/nrf_clock.h>

#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(current);

#define KHZ_CLOCK_PIN   29
#define UNUSED_INTERRUPT_PIN   23
#define TOGGLE_PIN 27

static uint8_t interrupt_channel;
static uint8_t gpio_channel;
static uint8_t gppi_channel;


void button_pressed(const struct device *dev, struct gpio_callback *cb,
		    uint32_t pins)
{
	printk("Button pressed at %" PRIu32 "\n", k_cycle_get_32());
}


void configureNrfxGpioInterrupt(uint32_t pin)
{
	static const nrfx_gpiote_in_config_t pin_interrupt_config = {
		.sense = NRF_GPIOTE_POLARITY_HITOLO,
		.pull = GPIO_PIN_CNF_PULL_Disabled, //NRF_GPIO_PIN_PULLUP,
		.is_watcher = false,
		.hi_accuracy = true,
		.skip_gpio_setup = false,
	};

	nrfx_gpiote_in_init(pin, &pin_interrupt_config, button_pressed);
	nrfx_gpiote_in_event_enable(pin, false);

	uint32_t clock_event_address = nrf_gpiote_event_address_get(NRF_GPIOTE, nrfx_gpiote_in_event_get(pin));

	// uint32_t task_address = nrf_saadc_task_address_get(NRF_SAADC, NRF_SAADC_TASK_SAMPLE);


    uint32_t task_address = nrf_clock_task_address_get(NRF_CLOCK_S, NRF_CLOCK_TASK_HFCLKSTOP);

	// ppi_init_channel_one
    nrfx_dppi_channel_alloc(&interrupt_channel);
    nrfx_gppi_channel_endpoints_setup(interrupt_channel, clock_event_address, task_address);
    nrfx_dppi_channel_enable(interrupt_channel);
}


static void configureSleepWakePinToggle()
{
	nrfx_err_t err;

	/* Connect GPIOTE_0 IRQ to nrfx_gpiote_irq_handler */
	IRQ_CONNECT(DT_IRQN(DT_NODELABEL(gpiote)),
		    DT_IRQ(DT_NODELABEL(gpiote), priority),
		    nrfx_isr, nrfx_gpiote_irq_handler, 0);

	/* Initialize GPIOTE (the interrupt priority passed as the parameter
	 * here is ignored, see nrfx_glue.h).
	 */
	err = nrfx_gpiote_init(0);
	if (err != NRFX_SUCCESS) {
		LOG_ERR("nrfx_gpiote_init error: 0x%08X", err);
		return;
	}

	err = nrfx_gpiote_channel_alloc(&gpio_channel);
	if (err != NRFX_SUCCESS) {
		LOG_ERR("Failed to allocate gpio_channel, error: 0x%08X", err);
		return;
	}

	/* Initialize output pin. SET task will turn the LED on,
	 * CLR will turn it off and OUT will toggle it.
	 */
	static const nrfx_gpiote_output_config_t output_config = {
		.drive = NRF_GPIO_PIN_S0S1,
		.input_connect = NRF_GPIO_PIN_INPUT_DISCONNECT,
		.pull = NRF_GPIO_PIN_NOPULL,
	};
	const nrfx_gpiote_task_config_t task_config = {
		.task_ch = gpio_channel,
		.polarity = NRF_GPIOTE_POLARITY_TOGGLE,
		.init_val = 1,
	};
	err = nrfx_gpiote_output_configure(TOGGLE_PIN,
					   &output_config,
					   &task_config);
	if (err != NRFX_SUCCESS) {
		LOG_ERR("nrfx_gpiote_output_configure error: 0x%08X", err);
		return;
	}

	nrfx_gpiote_out_task_enable(TOGGLE_PIN);

	LOG_INF("nrfx_gpiote initialized");

	/* Allocate a (G)PPI channel. */
	err = nrfx_gppi_channel_alloc(&gppi_channel);
	if (err != NRFX_SUCCESS) {
		LOG_ERR("nrfx_gppi_channel_alloc error: 0x%08X", err);
		return;
	}

	/* Configure endpoints of the channel so that the input pin event is
	 * connected with the output pin OUT task. This means that each time
	 * the button is pressed, the LED pin will be toggled.
	 */
	nrfx_gppi_channel_endpoints_setup(gppi_channel,
		nrf_power_event_address_get(NRF_POWER_S, NRF_POWER_EVENT_SLEEPENTER), // wake/sleep event
		nrfx_gpiote_out_task_addr_get(TOGGLE_PIN));

	nrfx_gppi_channel_endpoints_setup(gppi_channel,
		nrf_power_event_address_get(NRF_POWER_S, NRF_POWER_EVENT_SLEEPEXIT), // wake/sleep event
		nrfx_gpiote_out_task_addr_get(TOGGLE_PIN));


	/* Enable the channel. */
	nrfx_gppi_channels_enable(BIT(gppi_channel));

	LOG_INF("(D)PPI configured");
}

void main(void)
{

    // Ensure we're running at the lower frequency - 128 MHz with a /2 clock divider = 64 MHz
    NRF_CLOCK_S->HFCLKCTRL = (CLOCK_HFCLKCTRL_HCLK_Div2 << CLOCK_HFCLKCTRL_HCLK_Pos);

    k_msleep(2500);

	// includes turning on gpiote via nrfx_gpiote_init
	configureSleepWakePinToggle();

	configureNrfxGpioInterrupt(UNUSED_INTERRUPT_PIN);

    while (1) {

        k_msleep(1000);
    }
}
