/**
 * @file   qspiIO.c
 * @author StepTechnica
 * @date   Sep. 05, 2025
 *
 * @brief Evaluation Board 用ソースファイル「MKY43依存部分」
 *
 * @copyright (C) 2022- StepTechnica Co.,Ltd.
 *
 * このソフトウェアは、コピー利用、配布、変更の追加、変更を加えたもの再配布、商用利用、有料販売など、どなたも自由にお使いいただくことができます。
 * このソフトウェアには保証はついていません。
 * このソフトウェアを利用したことで問題が起きた際に、ソフトウェアの製作者は一切の責任を負いません。
 *
 */

/* -----------------------------------------------------------------------------
 * #include
 */

#include "main.h"
#include "qspiIO.h"

#include "main.h"
#include <memory.h>
#include <stdint.h>
#include <stdbool.h>
#include "IB49config.h"

/* -----------------------------------------------------------------------------
 * #defineマクロ定義
 */

/* -----------------------------------------------------------------------------
 * 変数定義
 */
extern QSPI_HandleTypeDef hqspi;

QSPI_CommandTypeDef	rCommand;
QSPI_CommandTypeDef	wCommand;


/* -----------------------------------------------------------------------------
 * 関数プロトタイプ宣言
 */


int QSPI_Initialize(void);
int MKY_Read16(unsigned short offset);
int MKY_ReadBlock(unsigned short offset, void* block, unsigned short length);
int MKY_Write16(unsigned short offset, unsigned short value);
int MKY_WriteBlock(unsigned short offset, const void* block, unsigned short length);
int MKY_FillMemory(unsigned short offset, int value, unsigned short length);


/**
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * @brief：MKYデバイス初期化
 *
 * @note： 基板の設定を読み込み、初期値を格納する
 *
 * @param  none
 * @retval true : 正常終了
 *
 */
int QSPI_Initialize(void)
{
	if (isMODEon() == false) {
		//　for Quad-SPI (JP4:OPEN)
		rCommand.Instruction        = kSPI_CMD_READ;	// Read command
		rCommand.InstructionMode    = QSPI_INSTRUCTION_4_LINES;
		// rCommand.Address            = spi_addr;
		rCommand.AddressSize        = QSPI_ADDRESS_24_BITS;
		rCommand.AddressMode        = QSPI_ADDRESS_4_LINES;
		rCommand.AlternateBytes     = 0;
		rCommand.AlternateBytesSize = 0;
		rCommand.AlternateByteMode  = QSPI_ALTERNATE_BYTES_NONE;
		rCommand.DummyCycles        = DEF_SPI_DUMMY;
		// rCommand.NbData             = spi_size;		// Rx SIZE;
		rCommand.DataMode           = QSPI_DATA_4_LINES;
		rCommand.DdrMode            = QSPI_DDR_MODE_DISABLE;
		rCommand.DdrHoldHalfCycle   = 0;			// no data
		rCommand.SIOOMode           = QSPI_SIOO_INST_EVERY_CMD;

		//
		wCommand.Instruction        = kSPI_CMD_WRITE;	// Write command
		wCommand.InstructionMode    = QSPI_INSTRUCTION_4_LINES;
		// wCommand.Address            = spi_addr;			// SPI address
		wCommand.AddressSize        = QSPI_ADDRESS_24_BITS;
		wCommand.AddressMode        = QSPI_ADDRESS_4_LINES;
		wCommand.AlternateBytes     = 0;
		wCommand.AlternateBytesSize = 0;
		wCommand.AlternateByteMode  = QSPI_ALTERNATE_BYTES_NONE;
		wCommand.DummyCycles        = 0;
		// wCommand.NbData             = spi_size;						// Rx SIZE
		wCommand.DataMode           = QSPI_DATA_4_LINES;
		wCommand.DdrMode            = QSPI_DDR_MODE_DISABLE;
		wCommand.DdrHoldHalfCycle   = 0;							// no data
		wCommand.SIOOMode           = QSPI_SIOO_INST_EVERY_CMD;
	} else {
		//　for Single-SPI (JP4:SHORT)
		rCommand.Instruction        = kSPI_CMD_READ;	// Read command
		rCommand.InstructionMode    = QSPI_INSTRUCTION_1_LINE;
		// rCommand.Address            = spi_addr;
		rCommand.AddressSize        = QSPI_ADDRESS_24_BITS;
		rCommand.AddressMode        = QSPI_ADDRESS_1_LINE;
		rCommand.AlternateBytes     = 0;
		rCommand.AlternateBytesSize = 0;
		rCommand.AlternateByteMode  = QSPI_ALTERNATE_BYTES_NONE;
		//rCommand.DummyCycles        = DEF_SPI_DUMMY; // Single-SPIのときはダミービットなし
		// rCommand.NbData             = spi_size;		// Rx SIZE;
		rCommand.DataMode           = QSPI_DATA_1_LINE;
		rCommand.DdrMode            = QSPI_DDR_MODE_DISABLE;
		rCommand.DdrHoldHalfCycle   = 0;			// no data
		rCommand.SIOOMode           = QSPI_SIOO_INST_EVERY_CMD;

		//
		wCommand.Instruction        = kSPI_CMD_WRITE;	// Write command
		wCommand.InstructionMode    = QSPI_INSTRUCTION_1_LINE;
		// wCommand.Address            = spi_addr;			// SPI address
		wCommand.AddressSize        = QSPI_ADDRESS_24_BITS;
		wCommand.AddressMode        = QSPI_ADDRESS_1_LINE;
		wCommand.AlternateBytes     = 0;
		wCommand.AlternateBytesSize = 0;
		wCommand.AlternateByteMode  = QSPI_ALTERNATE_BYTES_NONE;
		wCommand.DummyCycles        = 0;
		// wCommand.NbData             = spi_size;						// Rx SIZE
		wCommand.DataMode           = QSPI_DATA_1_LINE;
		wCommand.DdrMode            = QSPI_DDR_MODE_DISABLE;
		wCommand.DdrHoldHalfCycle   = 0;							// no data
		wCommand.SIOOMode           = QSPI_SIOO_INST_EVERY_CMD;
	}

	return true;

}

/**
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * @brief：16ビットの値を読み出す
 *
 * @note：
 *
 * @param  unsigned offset : オフセットアドレス
 * @retval int : 読み出し値
 *
 */
int MKY_Read16(unsigned short offset)
{
	int 	rData;


	if( (offset + 2) > MKY_MEMORY_SIZE )
	{
		return 0;
	}

	if (MKY_ReadBlock(offset, &rData, 2) == 2) {
		return(rData);
	}
	return 0;
}

/**
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * @brief：ブロックで読み出し
 *
 * @note：
 *
 * @param  unsigned offset : オフセットアドレス
 * @param  void* v_block   : 格納するバッファ
 * @param  unsigned length : レングス
 * @retval int : 読み出したデータ数
 *
 */
int MKY_ReadBlock(unsigned short offset, void* v_block, unsigned short length)
{
	HAL_StatusTypeDef	stat;

	rCommand.Address            = offset;			// SPI address
	rCommand.NbData             = length;			// Write SIZE

	stat = HAL_QSPI_Command(&hqspi, &rCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE);
	if (stat == HAL_OK) {
		stat =HAL_QSPI_Receive(&hqspi, v_block, HAL_QPSI_TIMEOUT_DEFAULT_VALUE);
		if (stat == HAL_OK) {
			return(length);
		}

//        stat = HAL_QSPI_Receive_DMA(&hqspi, v_block);
//        if (stat == HAL_OK) {
//            /* wait for DMA */
//            while ((DMA2_Stream7->CR & DMA_SxCR_EN) == DMA_SxCR_EN) {
//            }
//            return (length);
//        }
	}

	return(-1);
}

/**
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * @brief：16ビットの値を書き込む
 *
 * @note：
 *
 * @param  unsigned offset : オフセットアドレス
 * @param  unsigned value  : 書き込む値
 * @retval false = 領域外
 *         true  = 書き込み実行
 *
 */
int MKY_Write16(unsigned short offset, unsigned short value)
{
	if( (offset + 2) > MKY_MEMORY_SIZE )
	{
		return false;
	}

	if (MKY_WriteBlock(offset, &value, 2) == 2) {
		return(true);
	}
		return false;
}

/**
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * @brief：ブロックで書き込む
 *
 * @note：
 *
 * @param  unsigned offset : オフセットアドレス
 * @param  void* v_block   : 書き込むデータのバッファ
 * @param  unsigned length : レングス
 * @retval int : 書き込んだデータ数
 *
 */
int MKY_WriteBlock(unsigned short offset, const void* v_block, unsigned short length)
{
	HAL_StatusTypeDef	stat;

	wCommand.Address            = offset;			// SPI address
	wCommand.NbData             = length;			// Write SIZE

	stat = HAL_QSPI_Command(&hqspi, &wCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE);
	if (stat == HAL_OK) {
//		stat =HAL_QSPI_Transmit(&hqspi, (uint8_t *)v_block, HAL_QPSI_TIMEOUT_DEFAULT_VALUE);
//		if (stat == HAL_OK) {
//			return(length);
//		}

        stat = HAL_QSPI_Transmit_DMA(&hqspi, (uint8_t *)v_block);
        if (stat == HAL_OK) {
            /* wait for DMA */
            while (QUADSPI->SR & QUADSPI_SR_BUSY) {
            }
            return (length);
        }
	}

	return(-1);
}

/**
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * @brief：同じ値を書き込む
 *
 * @note：
 *
 * @param  unsigned offset : オフセットアドレス
 * @param  int value       : 書き込むデータ
 * @param  unsigned length : レングス
 * @retval int : 書き込んだデータ数
 *
 */
int MKY_FillMemory(unsigned short offset, int value, unsigned short length)
{
	unsigned address = offset;
	unsigned count = 0;
	value &= 0xff;

	if( (address % 2) != 0 && (length > 0) )
	{
		return 0;
	}
	while( length > 0 )
	{
		MKY_Write16(address, value);
		address += 2;
		length -= 2;
		count += 2;
	}

	return count;
}

