/*
 * Copyright (c) 2019 Nordic Semiconductor ASA
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include "retained.h"

#include <inttypes.h>
#include <stdio.h>

#include <zephyr/device.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/hwinfo.h>
#include <zephyr/drivers/comparator.h>
#include <zephyr/kernel.h>
#include <zephyr/pm/device.h>
#include <zephyr/sys/poweroff.h>
#include <zephyr/sys/util.h>

#include <zephyr/devicetree.h>
#include <zephyr/drivers/gpio.h>

#include <zephyr/pm/device_runtime.h>
#include <zephyr/pm/device.h>
#include <zephyr/pm/pm.h>
#include <zephyr/sys/reboot.h>
#include <zephyr/sys/poweroff.h>

#if defined(CONFIG_GRTC_WAKEUP_ENABLE)
#include <zephyr/drivers/timer/nrf_grtc_timer.h>
//#define DEEP_SLEEP_TIME_S 2
#define DEEP_SLEEP_TIME_S 30
#endif

//#if defined(CONFIG_GPIO_WAKEUP_ENABLE)
#if 0
static const struct gpio_dt_spec sw0 = GPIO_DT_SPEC_GET(DT_ALIAS(sw0), gpios);
#endif
#if defined(CONFIG_LPCOMP_WAKEUP_ENABLE)
static const struct device *comp_dev = DEVICE_DT_GET(DT_NODELABEL(comp));
#endif

//const struct device *const spis_dev = DEVICE_DT_GET(DT_NODELABEL(spi00));

//#define MY_SPI_SLAVE DT_NODELABEL(spi00)
//#define MY_GPIO_NODE_BLE_IRQ DT_NODELABEL(my_ble_irq_node) // Matches the label in DTS

//const struct device *spi_dev;
//static const struct gpio_dt_spec my_output_ble_irq;

void print_reset_cause(void)
{
	uint32_t reset_cause;

	hwinfo_get_reset_cause(&reset_cause);
	if (reset_cause & RESET_DEBUG) {
		printf("Reset by debugger.\n");
	} else if (reset_cause & RESET_CLOCK) {
		printf("Wakeup from System OFF by GRTC.\n");
	} else  {
		printf("Other wake up cause 0x%08X.\n", reset_cause);
	}
}

#if 0
bool DbgBusy = false;
#endif

__attribute__((optimize("O0")))
int main(void)
{
	int rc;
	
	if (IS_ENABLED(CONFIG_APP_USE_RETAINED_MEM)) {
		bool retained_ok = retained_validate();

		/* Increment for this boot attempt and update. */
		retained.boots += 1;
		retained_update();

		printf("Retained data: %s\n", retained_ok ? "valid" : "INVALID");
		printf("Boot count: %u\n", retained.boots);
		printf("Off count: %u\n", retained.off_count);
		printf("Active Ticks: %" PRIu64 "\n", retained.uptime_sum);
	} else {
		printf("Retained data not supported\n");
	}

#if defined(CONFIG_GRTC_WAKEUP_ENABLE)
	int err = z_nrf_grtc_wakeup_prepare(DEEP_SLEEP_TIME_S * USEC_PER_SEC);

	if (err < 0) {
		printk("Unable to prepare GRTC as a wake up source (err = %d).\n", err);
	} else {
		printk("Entering system off; wait %u seconds to restart\n", DEEP_SLEEP_TIME_S);
	}
#endif

//#if defined(CONFIG_GPIO_WAKEUP_ENABLE)
#if 0

	/* configure sw0 as input, interrupt as level active to allow wake-up */
	rc = gpio_pin_configure_dt(&sw0, GPIO_INPUT);
	if (rc < 0) {
		printf("Could not configure sw0 GPIO (%d)\n", rc);
		return 0;
	}

	rc = gpio_pin_interrupt_configure_dt(&sw0, GPIO_INT_LEVEL_ACTIVE);
	if (rc < 0) {
		printf("Could not configure sw0 GPIO interrupt (%d)\n", rc);
		return 0;
	}

	printf("Entering system off; press sw0 to restart\n");
#endif

#if defined(CONFIG_LPCOMP_WAKEUP_ENABLE)
	comparator_set_trigger(comp_dev, COMPARATOR_TRIGGER_BOTH_EDGES);
	comparator_trigger_is_pending(comp_dev);
	printf("Entering system off; change signal level at comparator input to restart\n");
#endif

	if (IS_ENABLED(CONFIG_APP_USE_RETAINED_MEM)) {
		/* Update the retained state */
		retained.off_count += 1;
		retained_update();
	}

	hwinfo_clear_reset_cause();

#if 0
	spi_dev = DEVICE_DT_GET(MY_SPI_SLAVE); 

	if (spi_dev == NULL) 
	{
		// printk("SPI Device is Null!");
		printf("spi dev is null \r\n");
		return;
	}
	
    if (!device_is_ready(spi_dev)) 
	{
		printf("device is not ready \r\n");
    }

	// Disable device runtime power management to
	// take control over device power state
	pm_device_runtime_disable(spi_dev);

	int ret = pm_device_action_run(spi_dev, PM_DEVICE_ACTION_SUSPEND);
	
	// Check if any device is busy
	if (pm_device_is_any_busy() == 0) 
	{
//		printf("System is idle and devices are suspended.\n");
		DbgBusy = false;
	} else 
	{
//		printf("Devices are busy, system cannot deep sleep.\n");
		DbgBusy = true;
	}
#endif	
	
//#define SCK_PIN	12	// P2.01
//#define MISO_PIN	13	// P2.02
//#define BLE_IRQ	14	// P2.03
//#define MOSI_PIN	15	// P2.04
//#define CSN_PIN	16	// P2.05

	// Configure P2.01 as Input, Disconnected, No Pull
	NRF_P2->PIN_CNF[1] = (GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos) |
                     (GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos) |
                     (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos);

	// Configure P2.02 as Input, Disconnected, No Pull
	NRF_P2->PIN_CNF[2] = (GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos) |
                     (GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos) |
                     (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos);

	// Configure P2.04 as Input, Disconnected, No Pull
	NRF_P2->PIN_CNF[4] = (GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos) |
                     (GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos) |
                     (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos);

	// Configure P2.03 as Input, Disconnected, No Pull
//	NRF_P2->PIN_CNF[3] = (GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos) |
//                     (GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos) |
//                     (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos);
	// Configure P2.03 as Input, Disconnected, with Pull Up
	NRF_P2->PIN_CNF[3] = (GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos) |
                     (GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos) |
                     (GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos);

	// Configure P2.05 as Input, Disconnected, with Pull Up
	NRF_P2->PIN_CNF[5] = (GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos) |
                     (GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos) |
                     (GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos);
					 
	// Configure P2.07 as Input, Disconnected, No Pull
	NRF_P2->PIN_CNF[7] = (GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos) |
                     (GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos) |
                     (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos);

	// Configure P2.08 as Input, Disconnected, No Pull
	NRF_P2->PIN_CNF[8] = (GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos) |
                     (GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos) |
                     (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos);
					 
    k_sleep(K_MSEC(3000));  // 3 seconds, prior to sys power off.
	
	sys_poweroff();		 // System Power Off test, we'll never leave here, for 1 uA test.
//	k_sleep(K_FOREVER);  // System Idle On test, we'll never leave here, for 3 uA test.
	
	while(1)
	{
 	  k_sleep(K_USEC(50));  // 0.050 ms - approx 2 mA here.  we never get here.
	}

	return 0;
}
