#include <stdint.h>
#include "nrf_drv_clock.h"
#include "nrf_pwr_mgmt.h"
#include "nrf_drv_wdt.h"
#include "nrfx_wdt.h"
#include "nrf_delay.h"
#include "app_timer.h"
#include "app_scheduler.h"
#include "nrf_power.h"
#include "tp_logic.h"

#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"

APP_TIMER_DEF(m_feed_wdt);

static void wdt_feed_handler(void *p_context)
{
    nrfx_wdt_feed();
    // NRF_LOG_DEBUG("wdt feed!");
}

static void wdt_init(void)
{
    nrf_drv_wdt_channel_id m_channel_id;

    nrf_drv_wdt_config_t config = NRF_DRV_WDT_DEAFULT_CONFIG;
    /* NOTE: WDT 中断中可以花费的最长时间为两个 32768[Hz] clock 周期. */
    APP_ERROR_CHECK(nrf_drv_wdt_init(&config, NULL));
    APP_ERROR_CHECK(nrf_drv_wdt_channel_alloc(&m_channel_id));
    nrf_drv_wdt_enable();
    nrfx_wdt_feed();
    nrf_delay_us(300);

    APP_ERROR_CHECK(app_timer_create(&m_feed_wdt, APP_TIMER_MODE_REPEATED, wdt_feed_handler));
    APP_ERROR_CHECK(app_timer_start(m_feed_wdt, APP_TIMER_TICKS(5000), NULL));
}

static void print_reset_reason(void)
{
    char *reset_str[] = { [0] = "pin",     [1] = "watchdog", [2] = "soft", [3] = "CPU lock-up", [15] = "GPIO",
                          [16] = "LPCOMP", [17] = "debug",   [18] = "NFC", [19] = "VBUS" };

    uint32_t rc = nrf_power_resetreas_get();
    nrf_power_resetreas_clear(rc);

    for (int32_t i = 0; i < sizeof(reset_str) / sizeof(reset_str[0]); ++i) {
        if ((rc & (1 << i)) != 0) {
            NRF_LOG_WARNING("Reset reason: %s", reset_str[i]);
        }
    }
}

static void modules_init(void)
{
    NRF_POWER->DCDCEN = 1;

    APP_ERROR_CHECK(NRF_LOG_INIT(app_timer_cnt_get));
    NRF_LOG_DEFAULT_BACKENDS_INIT();
    NRF_LOG_WARNING("<Throughput Test>");
    print_reset_reason();

    APP_ERROR_CHECK(nrf_drv_clock_init());
    nrf_drv_clock_lfclk_request(NULL);
    while (!nrf_drv_clock_lfclk_is_running()) {}
    APP_ERROR_CHECK(app_timer_init());
    APP_SCHED_INIT(32, 8);
    APP_ERROR_CHECK(nrf_pwr_mgmt_init());
    wdt_init();
}

/**
 * @brief Function for application main entry.
 */
int main(void)
{
    modules_init();
    tp_logic_init();

    NRF_LOG_INFO("Enter main loop...");
    while (true) {
        app_sched_execute();
        if (NRF_LOG_PROCESS() == false) {
            nrf_pwr_mgmt_run();
        }
    }
}
