/******************************************************************************
* Copyright (C) 2023 Advanced Micro Devices, Inc. All Rights Reserved.
* SPDX-License-Identifier: MIT
******************************************************************************/
/*
 * helloworld.c: simple test application
 *
 * This application configures UART 16550 to baud rate 9600.
 * PS7 UART (Zynq) is not initialized by this application, since
 * bootrom/bsp configures it to baud rate 115200
 *
 * ------------------------------------------------
 * | UART TYPE   BAUD RATE                        |
 * ------------------------------------------------
 *   uartns550   9600
 *   uartlite    Configurable only in HW design
 *   ps7_uart    115200 (configured by bootrom/bsp)
 */

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xparameters.h"
#include "xscugic.h"
#include <stdint.h>
#include <unistd.h>

#include "spi.h"

spi_t spi;
static XScuGic IntcInstance;

void spi_handler(void* ref);

void init_interrupts()
{
    XScuGic_Config *IntcConfig;
    int status;

    /* Initialize the exception table */
    Xil_ExceptionInit();

    /* Look up the interrupt configuration */
    IntcConfig = XScuGic_LookupConfig(XPAR_SCUGIC_SINGLE_DEVICE_ID);
    if (IntcConfig == NULL) {
        xil_printf("Failed to lookup SCUGIC config.\r\n");
        return XST_FAILURE;
    }

    /* Initialize the interrupt controller driver so that it is ready to use */
    status = XScuGic_CfgInitialize(&IntcInstance, IntcConfig, IntcConfig->CpuBaseAddress);
    if (status != XST_SUCCESS) {
        xil_printf("Failed to initialize SCUGIC.\r\n");
        return XST_FAILURE;
    }

    /*
     * Connect the interrupt controller interrupt handler to the hardware interrupt
     * handling logic in the processor.
     */
    Xil_ExceptionRegisterHandler(
        XIL_EXCEPTION_ID_INT,
        (Xil_ExceptionHandler) XScuGic_InterruptHandler,
        &IntcInstance
    );

    /* Register (connect) your custom ISR to this interrupt */
    status = XScuGic_Connect(
        &IntcInstance,
		SPI0_INT_ID,
        (Xil_ExceptionHandler) spi_handler,
        NULL
    );
    if (status != XST_SUCCESS) {
        xil_printf("Failed to connect ISR.\r\n");
        return XST_FAILURE;
    }

    /* Enable the interrupt in the GIC */
    XScuGic_Enable(&IntcInstance, XIL_EXCEPTION_ID_INT);

    /* Enable interrupts in the Processor */
    Xil_ExceptionEnable();
}

void init_spi()
{
	spi_init(&spi, SPI0);
	spi_master_configure(&spi, false, false, SPI_MSB_FIRST, SPI_FRAME_16_BIT);
	spi_master_configure_speed(&spi, 4);
	spi_master_enable(&spi, true);
}

int main()
{
    init_platform();
    init_interrupts();
    init_spi();

    print("Hello World\n\r");
    print("Successfully ran Hello World application\n");

    xil_printf("This is the control register value: %d\r\n", spi.periph->CTRL);
    xil_printf("This is the status register value: %d\r\n", spi.periph->STATUS);

    uint16_t number = 0;
    #define MAX 10000
    while (true) {
      spi_transmit(&spi, &number, 1);
      uint16_t rx;
      spi_receive(&spi, &rx, 1);

      xil_printf("Sent new number: %d. Received: %d\r\n", number, rx);

      number++;
      number %= MAX;


      sleep(1);
    }

    cleanup_platform();
    return 0;
}

void spi_handler(void* ref)
{
	if (spi_can_transmit(&spi)) {
		// transmit from buffer?
	}
}
