/*
 * @file exo_io_al_stm32f7xx_i2c.c
 *
 * @brief This file contains wrapper function definition for I2C interface
 *
 * @copyright Copyright 2023 Antaris, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "exo_io_al_stm32f7xx_fmc_nor.h"
#include "exo_hal_common.h"
#include "exo_common.h"

#ifndef LINUX_TEMP_PORT
#include "stm32f7xx_hal.h"
#endif

NOR_HandleTypeDef hnor1;

void static MX_FMC_NOR_Init(ioal_fmc_nor_hdle* ioal_fmc_nor)
{
	FMC_NORSRAM_TimingTypeDef Timing = {0};
	HAL_NOR_DeInit(&hnor1);
	hnor1.Instance = FMC_NORSRAM_DEVICE;
	hnor1.Extended = FMC_NORSRAM_EXTENDED_DEVICE;
	/* hnor1.Init */
	hnor1.Init.NSBank = FMC_NORSRAM_BANK1;
	hnor1.Init.DataAddressMux = FMC_DATA_ADDRESS_MUX_DISABLE;
	hnor1.Init.MemoryType = FMC_MEMORY_TYPE_NOR;
	hnor1.Init.MemoryDataWidth = FMC_NORSRAM_MEM_BUS_WIDTH_16;
	hnor1.Init.BurstAccessMode = FMC_BURST_ACCESS_MODE_DISABLE;
	hnor1.Init.WaitSignalPolarity = FMC_WAIT_SIGNAL_POLARITY_LOW;
	hnor1.Init.WaitSignalActive = FMC_WAIT_TIMING_BEFORE_WS;
	hnor1.Init.WriteOperation = FMC_WRITE_OPERATION_ENABLE;
	hnor1.Init.WaitSignal = FMC_WAIT_SIGNAL_DISABLE;
	hnor1.Init.ExtendedMode = FMC_EXTENDED_MODE_DISABLE;
	hnor1.Init.AsynchronousWait = FMC_ASYNCHRONOUS_WAIT_ENABLE;
	hnor1.Init.WriteBurst = FMC_WRITE_BURST_DISABLE;
	hnor1.Init.ContinuousClock = FMC_CONTINUOUS_CLOCK_SYNC_ONLY;
	hnor1.Init.WriteFifo = FMC_WRITE_FIFO_ENABLE;
	hnor1.Init.PageSize = FMC_PAGE_SIZE_NONE;
	/* Timing */
	Timing.AddressSetupTime = 4;
	Timing.AddressHoldTime = 15;
	Timing.DataSetupTime = 20;
	Timing.BusTurnAroundDuration = 1;
	Timing.CLKDivision = 16;
	Timing.DataLatency = 17;
	Timing.AccessMode = FMC_ACCESS_MODE_A;
	/* ExtTiming */

	if (HAL_NOR_Init(&hnor1, &Timing, NULL) != HAL_OK)
	{
		ioal_error_handler();
	}
	ioal_fmc_nor->intf_gen_info.vdp_intf_inst_hdle = (void*)&hnor1;
	ioal_fmc_nor->intf_gen_info.state = IO_FREE_STATE;

}

/**
 * @brief  This API initializes the FMC NOR Flash
 */
hal_ret_sts io_hal_stm32f7xx_fmc_nor_init(ioal_fmc_nor_hdle* ioal_nor)
{
	MX_FMC_NOR_Init(ioal_nor);
	return HAL_SCS;
}

/**
 * @brief  This API receives data in master mode
 */
hal_ret_sts io_hal_stm32f7xx_fmc_nor_program_buffer(ioal_fmc_nor_hdle *ioal_nor, uint32 address, uint8 *data, uint32 buff_size)
{
	hal_ret_sts ret_sts = HAL_MAX_ERR;
	NOR_HandleTypeDef *hnor = ioal_nor->intf_gen_info.vdp_intf_inst_hdle;
	if(HAL_OK == HAL_NOR_ProgramBuffer(hnor, address, (uint16*)data, buff_size))
	{
		ret_sts = HAL_SCS;
	}
	else
	{
		ret_sts = HAL_IO_VDP_ERR;
	}
	return ret_sts;
}

/**
 * @brief  This API receives data in master mode
 */
hal_ret_sts io_hal_stm32f7xx_fmc_nor_program(ioal_fmc_nor_hdle *ioal_nor, uint32 address, uint16* data)
{
	hal_ret_sts ret_sts = HAL_MAX_ERR;
	NOR_HandleTypeDef *hnor = ioal_nor->intf_gen_info.vdp_intf_inst_hdle;
	if(HAL_OK == HAL_NOR_Program(hnor, (unsigned long int*)address, data))
	{
		ret_sts = HAL_SCS;
	}
	else
	{
		ret_sts = HAL_IO_VDP_ERR;
	}
	return ret_sts;
}

/**
 * @brief  This API receives data in master mode
 */
hal_ret_sts io_hal_stm32f7xx_fmc_nor_read(ioal_fmc_nor_hdle *ioal_nor, uint32* address, uint16* data)
{
	hal_ret_sts ret_sts = HAL_MAX_ERR;
	NOR_HandleTypeDef *hnor = ioal_nor->intf_gen_info.vdp_intf_inst_hdle;
	if(HAL_OK == HAL_NOR_Read(hnor, (unsigned long int*)address, data))
	{
		ret_sts = HAL_SCS;
	}
	else
	{
		ret_sts = HAL_IO_VDP_ERR;
	}
	return ret_sts;
}

/**
 * @brief  This API receives data in master mode
 */
hal_ret_sts io_hal_stm32f7xx_fmc_nor_read_buffer(ioal_fmc_nor_hdle *ioal_nor, uint32 address, uint8 *data, uint32 buff_size)
{
	hal_ret_sts ret_sts = HAL_MAX_ERR;
	NOR_HandleTypeDef *hnor = ioal_nor->intf_gen_info.vdp_intf_inst_hdle;
	if(HAL_OK == HAL_NOR_ReadBuffer(hnor, address, (uint16*)data, buff_size))
	{
		ret_sts = HAL_SCS;
	}
	else
	{
		ret_sts = HAL_IO_VDP_ERR;
	}
	return ret_sts;
}

/**
 * @brief  This API receives data in master mode
 */
hal_ret_sts io_hal_stm32f7xx_fmc_nor_erase_block(ioal_fmc_nor_hdle *ioal_nor, uint32 block_addr)
{
	hal_ret_sts ret_sts = HAL_MAX_ERR;
	NOR_HandleTypeDef *hnor = ioal_nor->intf_gen_info.vdp_intf_inst_hdle;
	if(HAL_OK == HAL_NOR_Erase_Block(hnor,block_addr,0))
	{
		ret_sts = HAL_SCS;
	}
	else
	{
		ret_sts = HAL_IO_VDP_ERR;
	}
	return ret_sts;
}

/**
 * @brief  This API receives data in master mode
 */
hal_ret_sts io_hal_stm32f7xx_fmc_nor_erase_chip(ioal_fmc_nor_hdle *ioal_nor)
{
	hal_ret_sts ret_sts = HAL_MAX_ERR;
	NOR_HandleTypeDef *hnor = ioal_nor->intf_gen_info.vdp_intf_inst_hdle;
	if(HAL_OK == HAL_NOR_Erase_Chip(hnor,0))
	{
		ret_sts = HAL_SCS;
	}
	else
	{
		ret_sts = HAL_IO_VDP_ERR;
	}
	return ret_sts;
}

/**
 * @brief  This API receives data in master mode
 */
ioal_nor_state_t io_hal_stm32f7xx_fmc_nor_get_state(ioal_fmc_nor_hdle *ioal_nor)
{
	NOR_HandleTypeDef *hnor = ioal_nor->intf_gen_info.vdp_intf_inst_hdle;
	return HAL_NOR_GetState(hnor);
}

/**
 * @brief  This API receives data in master mode
 */
ioal_nor_status_t io_hal_stm32f7xx_fmc_nor_get_status(ioal_fmc_nor_hdle *ioal_nor,uint32 address, uint32 timeout)
{
	NOR_HandleTypeDef *hnor = ioal_nor->intf_gen_info.vdp_intf_inst_hdle;
	return HAL_NOR_GetStatus(hnor,address,timeout);
}

/**
 * @brief  This API receives data in master mode
 */
hal_ret_sts io_hal_stm32f7xx_fmc_nor_write_enable(ioal_fmc_nor_hdle *ioal_nor)
{
	hal_ret_sts ret_sts = HAL_MAX_ERR;
	NOR_HandleTypeDef *hnor = ioal_nor->intf_gen_info.vdp_intf_inst_hdle;
	if(HAL_OK == HAL_NOR_WriteOperation_Enable(hnor))
	{
		ret_sts = HAL_SCS;
	}
	else
	{
		ret_sts = HAL_IO_VDP_ERR;
	}
	return ret_sts;
}

/**
 * @brief  This API receives data in master mode
 */
hal_ret_sts io_hal_stm32f7xx_fmc_nor_write_disable(ioal_fmc_nor_hdle *ioal_nor)
{
	hal_ret_sts ret_sts = HAL_MAX_ERR;
	NOR_HandleTypeDef *hnor = ioal_nor->intf_gen_info.vdp_intf_inst_hdle;
	if(HAL_OK == HAL_NOR_WriteOperation_Disable(hnor))
	{
		ret_sts = HAL_SCS;
	}
	else
	{
		ret_sts = HAL_IO_VDP_ERR;
	}
	return ret_sts;
}

/**
 * @brief  This API receives data in master mode
 */
hal_ret_sts io_hal_stm32f7xx_fmc_nor_return_to_read_mode(ioal_fmc_nor_hdle *ioal_nor)
{
	hal_ret_sts ret_sts = HAL_MAX_ERR;
	NOR_HandleTypeDef *hnor = ioal_nor->intf_gen_info.vdp_intf_inst_hdle;
	if(HAL_OK == HAL_NOR_ReturnToReadMode(hnor))
	{
		ret_sts = HAL_SCS;
	}
	else
	{
		ret_sts = HAL_IO_VDP_ERR;
	}
	return ret_sts;
}

/**
 * @brief  This API receives data in master mode
 */
hal_ret_sts io_hal_stm32f7xx_fmc_nor_read_id(ioal_fmc_nor_hdle *ioal_nor, ioal_nor_id_t *id)
{
	hal_ret_sts ret_sts = HAL_MAX_ERR;
	NOR_IDTypeDef pnor_id;
	NOR_HandleTypeDef *hnor = ioal_nor->intf_gen_info.vdp_intf_inst_hdle;
	if(HAL_OK == HAL_NOR_Read_ID(hnor,&pnor_id))
	{
		id->manufacturer_code=pnor_id.Manufacturer_Code;
		id->dvc_code1=pnor_id.Device_Code1;
		id->dvc_code1=pnor_id.Device_Code2;
		id->dvc_code1=pnor_id.Device_Code3;
		ret_sts = HAL_SCS;
	}
	else
	{
		ret_sts = HAL_IO_VDP_ERR;
	}
	return ret_sts;
}

/**
 * @brief  This API receives data in master mode
 */
hal_ret_sts io_hal_stm32f7xx_fmc_nor_read_cfi(ioal_fmc_nor_hdle *ioal_nor, ioal_nor_cfi_t* cfi)
{
	hal_ret_sts ret_sts = HAL_MAX_ERR;
	NOR_CFITypeDef pnor_cfi;
	NOR_HandleTypeDef *hnor = ioal_nor->intf_gen_info.vdp_intf_inst_hdle;
	if(HAL_OK == HAL_NOR_Read_CFI(hnor,&pnor_cfi))
	{
		cfi->cfi_1 = pnor_cfi.CFI_1;
		cfi->cfi_2 = pnor_cfi.CFI_2;
		cfi->cfi_3 = pnor_cfi.CFI_3;
		cfi->cfi_4 = pnor_cfi.CFI_4;
		ret_sts = HAL_SCS;
	}
	else
	{
		ret_sts = HAL_IO_VDP_ERR;
	}
	return ret_sts;
}

