/* ---------------------------------------------------------------------------
 * InternalFlash.c - v0.1                                (c) 2008 Micro-key bv
 * ---------------------------------------------------------------------------
 * Micro-key bv
 * Industrieweg 28, 9804 TG Noordhorn
 * Postbus 92, 9800 AB Zuidhorn
 * The Netherlands
 * Tel: +31 594 503020
 * Fax: +31 594 505825
 * Email: support@microkey.nl  
 * Web: www.microkey.nl
 * ---------------------------------------------------------------------------
 * Description: 
 * ---------------------------------------------------------------------------
 * Version(s):  0.1, Feb 11, 2008, FSc
 *                   Creation.
 * ---------------------------------------------------------------------------
 */

/* ---------------------------------------------------------------------------
 * System include files
 * ---------------------------------------------------------------------------
 */

/* ---------------------------------------------------------------------------
 * Application include files
 * ---------------------------------------------------------------------------
 */ 
#include "types.h"
#include "sys_config.h"
#include "InternalFlash.h"
#include "leds.h"
#include "sys_config.h"


/* ---------------------------------------------------------------------------
 * Local constant and macro definitions
 * ---------------------------------------------------------------------------
 */
#define IAP_LOCATION                0x7ffffff1

#define IAP_PREPARE_CMD             (50)
#define IAP_COPY_RAM2FLASH_CMD      (51)
#define IAP_ERASE_SECTORS_CMD       (52)
#define IAP_BLANK_CHECK_SECTORS_CMD (53)
#define IAP_READ_PART_ID_CMD        (54)
#define IAP_READ_BOOTCODE_V_CMD     (55)
#define IAP_COMPARE_CMD             (56)
#define IAP_REINVOKE_ISP_CMD        (57)


/* ---------------------------------------------------------------------------
 * Global variable definitions
 * ---------------------------------------------------------------------------
 */

/* ---------------------------------------------------------------------------
 * Local variable definitions
 * ---------------------------------------------------------------------------
 */
static unsigned int command[5]; 
static unsigned int result[2];

typedef void (*IAP)(unsigned int [],unsigned int[]);
IAP iap_entry;

/* ---------------------------------------------------------------------------
 * Local function definitions
 * ---------------------------------------------------------------------------
 */

/** \brief Initialises the internal flash module */
void iflashInit() 
{
	iap_entry=(IAP) IAP_LOCATION;
}

/** \brief Prepares the flash for erasing and programming (must be called before these actions)
 * 
 * This command must be executed before executing "Copy RAM to flash" or "Erase
 * Sector(s)" command. Successful execution of the "Copy RAM to flash" or "Erase
 * Sector(s)" command causes relevant sectors to be protected again. The boot
 * sector can not be prepared by this command. To prepare a single sector use the
 * same "Start" and "End" sector numbers
 * 
 * \param beginSector Start sector number (0-27)
 * \param endSector End Sector Number (should be greater than or equal to start sector number).
 * \retval CMD_SUCCESS prepare was succesfull
 * \retval BUSY
 * \retval INVALID_SECTOR
 */ 
iflashresult iflashPrepare(UINT8 beginSector, UINT8 endSector)
{
	// Build command 
	command[0] = IAP_PREPARE_CMD;
	command[1] = beginSector;
	command[2] = endSector;
	 
	//DISABLE_INTERRUPTS(); 

	iap_entry (command, result); 
	
	//ENABLE_INTERRUPTS();

	// readout result
	
	return result[0];
	//return CMD_SUCCESS;   
}

/** \brief Erases one sector on the internal flash
 * 
 * \param sector Sector nr to be erased (0-27)
 * \retval CMD_SUCCESS
 * \retval BUSY
 * \retval SECTOR_NOT_PREPARED_FOR_WRITE_OPERATION
 * \retval INVALID_SECTOR
 */
iflashresult iflashErase( UINT8 sector ) 
{
	// Build command 
	command[0] = IAP_ERASE_SECTORS_CMD;
	command[1] = sector;  // start sector
	command[2] = sector;  // end sector
	command[3] = CCLK/1000; // Clock frequency in kHz
	
	DISABLE_INTERRUPTS();

	iap_entry (command, result);
	
	ENABLE_INTERRUPTS();

	return result[0];
}


/** \brief Programs some data on the flash 
 * 
 * \param address Addres on flash to which the data must be programmed
 * \param dataLength Nr of bytes in data array (Should be 256 | 512 | 1024 | 4096.)
 * \param data The data-array that should be programmed
 * \retval CMD_SUCCESS
 * \retval SRC_ADDR_ERROR (Address not a word boundary)
 * \retval DST_ADDR_ERROR (Address not on correct boundary)
 * \retval SRC_ADDR_NOT_MAPPED
 * \retval DST_ADDR_NOT_MAPPED
 * \retval COUNT_ERROR (Byte count is not 256 | 512 | 1024 | 4096)
 * \retval SECTOR_NOT_PREPARED_FOR_WRITE_OPERATION
 * \retval BUSY
 */
iflashresult iflashProgram( UINT32 address, UINT16 dataLength, UINT8 *data)
{
	// Build command 
	command[0] = IAP_COPY_RAM2FLASH_CMD;
	command[1] = address;  // flash address
	command[2] = (UINT32)data;  // RAM address
	command[3] = dataLength; // Nr of bytes Should be 256 | 512 | 1024 | 4096.
	command[4] = CCLK/1000; // Clock frequency in kHz
	
	DISABLE_INTERRUPTS();  

	iap_entry (command, result);
	
	ENABLE_INTERRUPTS();
	
	return result[0];
}

/** \brief Compares the data with the data on the internal flash on location "address"
 *  
 * \param address Addres on flash to which the data must be programmed
 * \param dataLength Number of bytes to be compared; should be a multiple of 4.
 * \param data The data-array that should be programmed
 * \retval CMD_SUCCESS
 * \retval COMPARE_ERROR 
 * \retval COUNT_ERROR (Byte count is not a multiple of 4) 
 * \retval ADDR_ERROR 
 * \retval ADDR_NOT_MAPPED
 */
iflashresult iflashVerify( UINT32 address, UINT16 dataLength, UINT8 *data)
{
	// Build command 
	command[0] = IAP_COMPARE_CMD;
	command[1] = address;  // flash address
	command[2] = (UINT32)data;  // RAM address
	command[3] = dataLength; 
	
	iap_entry (command, result);
	
	return result[0];
}

/** \brief This command is used to read the part identification number.
 * 
 * \retval the Part identification number
 */
UINT32 iflashReadPartId()
{
	// Build command 
	command[0] = IAP_READ_PART_ID_CMD;
	
	iap_entry (command, result);
	
	return result[1];
}

/** \brief This command is used to read the boot code version number. */
UINT32 iflashReadBootcodeVersionNr()
{
	// Build command 
	command[0] = IAP_READ_BOOTCODE_V_CMD;
	
	iap_entry (command, result);
	
	return result[1];
}

