#ifdef __cplusplus
extern "C"
{
#endif

#include <stdbool.h>
#include <stdint.h>

#include "boards.h"

#include "app_error.h"
#include "app_timer.h"
#include "bsp.h"
#include "bsp_btn_ant.h"
#include "hardfault.h"
#include "nrf_sdh.h"
#include "nrf_sdh_ant.h"

#include "nrf.h"
#include "nrf_delay.h"
#include "nrf_gpio.h"
#include "nrf_drv_spis.h"
#include "nrf_spis.h"
#include "nrf_pwr_mgmt.h"
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"

#if (1 == NRFX_SPIS0_ENABLED)
    #define SPIS0_INSTANCE 0
#endif

#if (1 == NRFX_SPIS1_ENABLED)
    #define SPIS1_INSTANCE 1
#endif

#if (1 == NRFX_SPIS2_ENABLED)
    #define SPIS2_INSTANCE 2
#endif

    static const nrf_drv_spis_t spis = NRF_DRV_SPIS_INSTANCE(SPIS1_INSTANCE); ///< SPI Instance
    static volatile bool        spis_xfer_done;                               ///< Flag used to indicate that SPIS instance completed the transfer.
    static volatile size_t      rxAmount = 0;
    static volatile size_t      txAmount = 0;

    static void spis_event_handler(nrf_drv_spis_event_t event)
    {
        if (event.evt_type == NRF_DRV_SPIS_XFER_DONE)
        {
            spis_xfer_done = true;
            rxAmount       = event.rx_amount;
            txAmount       = event.tx_amount;
        }
    }

    static void log_init(void)
    {
        ret_code_t err_code = NRF_LOG_INIT(NULL);

        APP_ERROR_CHECK(err_code);

        NRF_LOG_DEFAULT_BACKENDS_INIT();
    }

    static void spis_init(void)
    {
        // Enable the constant latency sub power mode to minimize the time it takes
        // for the SPIS peripheral to become active after the CSN line is asserted

        NRF_POWER->TASKS_CONSTLAT = 1;

        nrf_drv_spis_config_t spis_config = NRF_DRV_SPIS_DEFAULT_CONFIG;

        spis_config.csn_pin    = APP_SPIS_CS_PIN;
        spis_config.miso_pin   = APP_SPIS_MISO_PIN;
        spis_config.mosi_pin   = APP_SPIS_MOSI_PIN;
        spis_config.sck_pin    = APP_SPIS_SCK_PIN;
        spis_config.csn_pullup = NRF_GPIO_PIN_PULLUP;

        ret_code_t err_code = nrf_drv_spis_init(&spis, &spis_config, spis_event_handler);

        APP_ERROR_CHECK(err_code);
    }

    const uint8_t leds_list[LEDS_NUMBER] = LEDS_LIST;

    int main(void)
    {
        log_init();
        spis_init();

        LEDS_CONFIGURE(LEDS_MASK);

        int     idx = 0;
        uint8_t txBuffer[2][32];
        uint8_t rxBuffer[32];

        while (1)
        {
            spis_xfer_done = false;

            memset(rxBuffer, 0, 32);

#if 0
            ret_code_t err_code =  nrf_drv_spis_buffers_set(&spis, &txBuffer[idx % 2][0], 32, rxBuffer, 32);
#else
        ret_code_t err_code = nrf_drv_spis_buffers_set(&spis, nullptr, 0, rxBuffer, 32);
#endif

            APP_ERROR_CHECK(err_code);

            while (!spis_xfer_done)
            {
                __WFE();
            }

            LEDS_INVERT(1 << leds_list[idx]);

            NRF_LOG_INFO("Transfer ready  tx = %d, rx = %d, rxBuffer = %s\r\n", txAmount, rxAmount, rxBuffer);
            NRF_LOG_FLUSH();

            ++idx;

            if (idx >= LEDS_NUMBER)
            {
                idx = 0;
            }
        }
    }

#ifdef __cplusplus
}
#endif
