#include <stdarg.h>
#include <stdio.h>

#include "FreeRTOS.h"
#include "task.h"

#include "xspi.h"		/* SPI device driver */
#include "xspi_l.h"

#include "xstatus.h"
#include "xil_printf.h"
#include "project.h"
#include "ad9081_api/adi_inc/adi_cms_api_common.h"

#define MAX_LOG_LINE_LENGTH     1000
#define RESET_PIN_REG_ADDR      0x40050008
#define RESET_PIN_BIT_MASK      0x20

static XSpi SpiInstance;


int32_t ad9081_hal_init() {
	int Status;
	XSpi_Config *ConfigPtr;	/* Pointer to Configuration data */

	/*
	 * Initialize the SPI driver so that it is  ready to use.
	 */
	ConfigPtr = XSpi_LookupConfig(XPAR_SPI_0_DEVICE_ID);
	if (ConfigPtr == NULL) {
		return XST_DEVICE_NOT_FOUND;
	}

	Status = XSpi_CfgInitialize(&SpiInstance, ConfigPtr,
				  ConfigPtr->BaseAddress);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	if (SpiInstance.SpiMode != XSP_STANDARD_MODE) {
		return XST_SUCCESS;
	}

	/*
	 * Set the Spi device as a master and in loopback mode.
	 */
	Status = XSpi_SetOptions(&SpiInstance, XSP_MASTER_OPTION);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	/*
	 * Start the SPI driver so that the device is enabled.
	 */
	XSpi_Start(&SpiInstance);

	/*
	 * Disable Global interrupt to use polled mode operation
	 */
	XSpi_IntrGlobalDisable(&SpiInstance);

	XSpi_SetSlaveSelect(&SpiInstance, 1);

	return XST_SUCCESS;

}

int32_t ad9081_hal_log_write(void *user_data, int32_t log_type, const char *comment, va_list argp) {
    int32_t err;
    char log_msg[MAX_LOG_LINE_LENGTH] = {0};
    const char *log_type_str;

    log_type_str = "MESSAGE:";
    if ((log_type & ADI_CMS_LOG_WARN) > 0)
        log_type_str = "WARNING:";
    if ((log_type & ADI_CMS_LOG_ERR)  > 0)
        log_type_str = "ERROR  :";

    err = snprintf(log_msg + strlen(log_msg), MAX_LOG_LINE_LENGTH, "%s ", log_type_str);
    if (err < 0)
       return API_CMS_ERROR_LOG_WRITE;
    if (vsprintf(log_msg + strlen(log_msg), comment, argp) < 0)
        return API_CMS_ERROR_LOG_WRITE;
    xil_printf("%s\r\n", log_msg);
    // if (fprintf(g_log_fd, "%s\n", log_msg) < 0)
    //     return API_CMS_ERROR_LOG_WRITE;
    
    return API_CMS_ERROR_OK;
}

int32_t ad9081_hal_wait_us(void *user_data, uint32_t time_us) {
	u32 num_ticks = time_us / TICK_PERIOD_US;
	if (num_ticks == 0) {
		num_ticks = 1;
	}

    vTaskDelay(num_ticks);

    return API_CMS_ERROR_OK;
}

int32_t ad9081_hal_spi_xfer_ad9081(void *user_data, uint8_t *in_data, uint8_t *out_data, uint32_t size_bytes) {
	int ret = XSpi_Transfer(&SpiInstance, in_data, out_data, size_bytes);
	if (ret == XST_SUCCESS) {
		return API_CMS_ERROR_OK;
	} else {
		printf("SPI Error %d\n", ret);
		return API_CMS_ERROR_ERROR;
	}


}

int32_t ad9081_hal_hw_rst_pin_ctrl_ad9081(void *user_data, uint8_t pin_level) {
    uint32_t tmp_val;
    tmp_val = Xil_In32(RESET_PIN_REG_ADDR);
    if (pin_level) {
        tmp_val |= RESET_PIN_BIT_MASK;
    } else {
        tmp_val &= (~RESET_PIN_BIT_MASK);
    }
    xil_printf("bla 0x%x\r\n", tmp_val);
    Xil_Out32(RESET_PIN_REG_ADDR, tmp_val);
    return API_CMS_ERROR_OK;
}
