/*********************************************************************
 *                    Flowcode FAT File System Component Code
 *
 * File: FAT.c
 *
 * (c) 2009 Matrix Multimedia Ltd.
 * http://www.matrixmultimedia.com
 *
 * Software License Agreement
 *
 * The software supplied herewith by Matrix Multimedia Ltd (the
 * “Company”) for its Flowcode graphical programming language is
 * intended and supplied to you, the Company’s customer, for use
 * solely and exclusively on the Company's products. The software
 * is owned by the Company, and is protected under applicable
 * copyright laws. All rights are reserved. Any use in violation
 * of the foregoing restrictions may subject the user to criminal
 * sanctions under applicable laws, as well as to civil liability
 * for the breach of the terms and conditions of this licence.
 *
 * THIS SOFTWARE IS PROVIDED IN AN “AS IS” CONDITION. NO WARRANTIES,
 * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED
 * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT,
 * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR
 * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
 *
 * Changelog:
 *
 *  date  | by | description
 * -------+----+-----------------------------------------------------
 * 050508 | BR | Created
 * 140508 | BR | Function Cleanup
 * 260309 | BR | Moved private functions from AddDefines section
 * 130509 | BR | Added % definitions to DefinesCode section
 * 190509 | BR | Added hardware SPI functionality
 * 090909 | BR | Fixed while i++ problem
 * 090909 | BR | Ported to HiTECH Compiler.
 * 131109 | BR | Fixed #pragma error HITECH problem
 * 210110 | BR | Added a second check to initialise function to get around a crashing problem.
 * 130610 | BR | Fixed bug when working with cards that do not have a cluster size of 32 sectors
 * 130610 | BR | Fixed a bug with bit bang routine when working with slightly less responsive cards
 * 020710 | BR | Added FAT32 functionality
 * 020710 | BR | Added combined intelligent FAT16 and FAT32 sensing compatibility
 * 231110 | BR | Attempt to fix slight problem with long typecasting
 * 170311 | BR | Fix to startup when the first sector is the first sector of a partition
 * 230311 | BR | Changed code to work for hitech and boostc without ifdefs
 * 260411 | BR | Changed delay in SPI_BYTE function to 10us instead of 1us
 * 050911 | BR | Converted to Universal FAT16 Component Code File
 * 011211 | BR | Updated FC_CAL_Bit functions
 * 021211 | BR | Converted to new dynamic defines mechanism
 * 151211 | BR | Converted FAT code to use structures to speed up component and save memory
 *        |    |
 * 020212 | ST | Fixed a couple of typos causing compilation errors (defect #216)
 * 280212 | BR | Minor bug fix Reserved Sectors calculation
 * 180412 | LM | Added component initialisation in Init_FAT
 * 180412 | LM | Increased timeout in Init_FAT and returned Timeout Error if GetAck times out
 * 180412 | LM | Scan_Current_Folder returns char not short
 * 200412 | LM | MOD_ID define fix
 * 140512 | LM | Removed Initialisation code as it is now done as part of Init_FAT()

 * 150612 | LM | Re-written based on FC5_PIC_FAT16, now using low level SPI in Firmware
 *        |    | This will give us the ability to maintain the component here,
 *        |    | rather than needing firmware updates.
 *        |    | Nb. Only supported from version 3 of GPS module
 *        |    | and version 4 of Serial module.
 * 200612 | LM | Modifications to allow multiple FAT components in MIAC System
 * 200712 | LM | Support for custom module CAN ID
 * 200712 | BR | Minor bug fix edits for SDHC, better card support and SPI speed control
 * 310812 | BR | Fixed a bug in the format file string function where a non variable based filename is used
 * 030912 | BR | Fixed a number of bugs causing write errors and added a few minor optimisations
 * 040912 | LM | merged above (3) changes into MS version
 * 040912 | BR | Added multiple file variables to allow for concurrent file access
 * 180912 | BR | Fixed minor potential bug in the set file index function
 ********************************************************************/

/*********************************************************************

 Return & parameter types:
   void
   MX_UINT8
   MX_SINT16
   MX_STRING

 Pin directions:
   0 = OUTPUT
   2 = INPUT
   3 = BIDIRECTIONAL

**********************************************************************

[Settings]
CLSID={5C27C7B5-4BFE-43D8-AED0-E69E625936C7}
IsAnalogue=0
MultipleAllowed=1
Description=FAT File System Flowcode Component

**********************************************************************

[Port]
DesiredPort=0
PortMandatory=0
SamePortAsID=0

[Pins]
Count=4
1=Chip Select
2=Clock
3=Data in
4=Data out

[PinPort]
# PORTA = 0
# PORTB = 1
# PORTC = 2
# PORTD = 3
# PORTE = 4
1=0
2=0
3=0
4=0

[PinDesiredBit]
1=2
2=3
3=4
4=5

[PinDirection]
# DIR_INPUT = 2
# DIR_OUTPUT = 0
# DIR_BIDIRECTIONAL = 3
1=0
2=0
3=0
4=0

[PinMustUsePort]
# MX_UINT8
1=1
2=1
3=1
4=1

[SamePortAsPinX]
# -1 = any pin
# otherwise, the pin number
1=-1
2=0
3=0
4=0

[PinMustUsePin]
# MX_UINT8
1=1
2=1
3=1
4=1

[PinValue]
# MX_UINT8 (0 = off, 1 = on)
1=0
2=0
3=0
4=0

**********************************************************************

[MacroNames]
Count=23
1=Init_FAT
2=Open_File
3=Read_File_Sector
4=Read_File_Length
5=Move_To_Next_File_Sector
6=Append_String_To_File
7=Write_File_Sector
8=Create_File
9=Delete_File
10=Write_Byte_To_Buffer
11=Read_Byte_From_Buffer
12=Open_Folder
13=Scan_Current_Folder
14=Read_Byte_From_Scan
15=MX_Init_Card
16=MX_Send_Buffer
17=MX_Get_Buffer
18=MX_Format_File_String
19=MX_Add_Sector_To_File
20=MX_Clear_Buffer
21=Read_Next_File_Sector
22=MX_Send_Cmd
23=Set_File_Index

[MacroReturns]
1=MX_UINT8
2=MX_UINT8
3=MX_UINT8
4=MX_SINT16
5=MX_UINT8
6=MX_UINT8
7=MX_UINT8
8=MX_UINT8
9=MX_UINT8
10=void
11=MX_UINT8
12=MX_UINT8
13=MX_SINT16
14=MX_UINT8
15=MX_UINT8
16=MX_UINT8
17=MX_UINT8
18=void
19=void
20=void
21=MX_UINT8
22=MX_UINT8
23=void

[MacroIsPrivate]
1=0
2=0
3=0
4=0
5=0
6=0
7=0
8=0
9=0
10=0
11=0
12=0
13=0
14=0
15=1
16=1
17=1
18=1
19=1
20=1
21=1
22=1
23=0


[MacroParameters_Init_FAT]
Count=0

[MacroParamTypes_Init_FAT]


[MacroParameters_Open_File]
Count=1
1=File_Name

[MacroParamTypes_Open_File]
1=MX_STRING


[MacroParameters_Read_File_Sector]
Count=0

[MacroParamTypes_Read_File_Sector]


[MacroParameters_Read_File_Length]
Count=0

[MacroParamTypes_Read_File_Length]


[MacroParameters_Move_To_Next_File_Sector]
Count=1
1=Force_Next_Sector

[MacroParamTypes_Move_To_Next_File_Sector]
1=MX_UINT8


[MacroParameters_Append_String_To_File]
Count=1
1=String

[MacroParamTypes_Append_String_To_File]
1=MX_STRING


[MacroParameters_Write_File_Sector]
Count=0

[MacroParamTypes_Write_File_Sector]


[MacroParameters_Create_File]
Count=1
1=File_Name

[MacroParamTypes_Create_File]
1=MX_STRING


[MacroParameters_Delete_File]
Count=1
1=File_Name

[MacroParamTypes_Delete_File]
1=MX_STRING


[MacroParameters_Write_Byte_To_Buffer]
Count=2
1=Address
2=Data

[MacroParamTypes_Write_Byte_To_Buffer]
1=MX_SINT16
2=MX_UINT8


[MacroParameters_Read_Byte_From_Buffer]
Count=1
1=Address

[MacroParamTypes_Read_Byte_From_Buffer]
1=MX_SINT16


[MacroParameters_Open_Folder]
Count=1
1=Folder_Name

[MacroParamTypes_Open_Folder]
1=MX_STRING


[MacroParameters_Scan_Current_Folder]
Count=2
1=Current_Idx
2=Scan_Type

[MacroParamTypes_Scan_Current_Folder]
1=MX_SINT16
2=MX_UINT8


[MacroParameters_Read_Byte_From_Scan]
Count=1
1=idx

[MacroParamTypes_Read_Byte_From_Scan]
1=MX_UINT8


[MacroParameters_MX_Init_Card]
Count=0

[MacroParamTypes_MX_Init_Card]


[MacroParameters_MX_Send_Buffer]
Count=1
1=address

[MacroParamTypes_MX_Send_Buffer]
1=long

[MacroParameters_MX_Get_Buffer]
Count=1
1=address

[MacroParamTypes_MX_Get_Buffer]
1=long

[MacroParameters_MX_Format_File_String]
Count=1
1=File_Name

[MacroParamTypes_MX_Format_File_String]
1=MX_STRING


[MacroParameters_Read_Next_File_Sector]
Count=0

[MacroParamTypes_Read_Next_File_Sector]


[MacroParameters_MX_Add_Sector_To_File]
Count=0

[MacroParamTypes_MX_Add_Sector_To_File]


[MacroParameters_MX_Clear_Buffer]
Count=0

[MacroParamTypes_MX_Clear_Buffer]


[MacroParameters_MX_Send_Cmd]
Count=2
1=Cmd
2=Addr

[MacroParamTypes_MX_Send_Cmd]
1=MX_UINT8
2=MX_UINT32

[MacroParameters_Set_File_Index]
Count=1
1=File_Index

[MacroParamTypes_Set_File_Index]
1=MX_UINT8

 ********************************************************************/

/********************************************************************
 * ADDITIONAL CODE
 ********************************************************************/

/*DefinesCode_Start*/

/**** Macro Substitutions ****
a = Unique Ref
b = SPI Channel
c = MOSI Pin
d = MOSI Port
e = MISO Pin
f = MISO Port
g = SCK Pin
h = SCK Port
i = CS Pin
j = CS Port
k = File Creation Time
l = File Creation Date
m = FAT System Type - 0=FAT16 Only / 1=FAT32 Only / 2=FAT16&32
x = MIAC System ordinal
y = MIAC System module type
******************************/



extern void %a_SPI_Master_Init ();
extern void %a_SPI_Master_Uninit ();
extern MX_UINT8 %a_SPI_Master_Byte (MX_UINT8 DataOut);
extern void %a_SPI_Set_Prescaler (MX_UINT8 Prescaler);

//Flowcode Defines
#define %a_FILE_CREATEDATE		%l
#define %a_FILE_CREATETIME		%k
#define %a_FAT_TYPE				%m		//0-FAT16(FAT) / 1-FAT32 / 2-FAT16&32

//!!EDIT HERE TO CHANGE MAX NO OF FILES!!
#define %a_CONCURRENT_FILES		1		//%n

#include <string.h>

//SD commands, many of these are not used here
#ifndef	MX_FAT_COMMANDS
	#define	MX_FAT_COMMANDS
	#define GO_IDLE_STATE            0
	#define SEND_OP_COND             1
	#define SEND_IF_COND			 8
	#define SEND_CSD                 9
	#define STOP_TRANSMISSION        12
	#define SEND_STATUS              13
	#define SET_BLOCK_LEN            16
	#define READ_SINGLE_BLOCK        17
	#define READ_MULTIPLE_BLOCKS     18
	#define WRITE_SINGLE_BLOCK       24
	#define WRITE_MULTIPLE_BLOCKS    25
	#define ERASE_BLOCK_START_ADDR   32
	#define ERASE_BLOCK_END_ADDR     33
	#define ERASE_SELECTED_BLOCKS    38
	#define SD_SEND_OP_COND			 41   //ACMD
	#define APP_CMD					 55
	#define READ_OCR				 58
	#define CRC_ON_OFF               59
#endif


#ifndef	MX_FAT_ERR_FLAGS
	#define MX_FAT_ERR_FLAGS

	//Common Defines
#define MX_ERR_NOCARD			0xFF
#define MX_ERR_NORESP			0xFE
#define MX_ERR_NOACK			0xFD
#define MX_ERR_TOUT				0xFC
#define MX_ERR_RESERVED			0xFB
#define MX_ERR_BAD				0xFA
#define MX_ERR_FREE				0xF0
#define MX_ERR_FILENOTFOUND		0xEF
#define MX_ERR_ROOTFULL			0xEE
#define MX_ERR_SECTBYTES		0xED
#define MX_ACK_FILEEMPTY		0x03
#define MX_ACK_FILETYPE			0x02
#define MX_ACK_EOF				0x01
#define MX_ACK_OK				0x00
#endif

//Global Variables
MX_UINT8 %a_mx_card_bufferl[256];		//512-Byte Global Buffer Variables
MX_UINT8 %a_mx_card_bufferh[256];
MX_UINT8 %a_mx_name_ext[12];			//11 byte fat file name: 8 MX_UINT8 filename + 3 MX_UINT8 extension

//Card Specific Variables
MX_UINT8 %a_mx_sects_per_clust;			//Number of sectors per cluster    - Added BR 06/10
MX_UINT8 %a_mx_sdhc_flag = 0;			//Standard / SDHC mode
MX_UINT8 %a_mx_card_type;
MX_UINT16 %a_mx_root_sectors = 0;		//Number of sectors in the root directory
MX_UINT16 %a_mx_fat_size = 0;			//FAT size in sectors
MX_UINT32 %a_mx_fat_start = 0;			//Start address of FAT tables
MX_UINT32 %a_mx_root_start = 0;			//Start address of root directory
MX_UINT32 %a_mx_data_start = 0;			//Start address of the data

//File Specific Variables
MX_UINT8 %a_mx_file_entry[%a_CONCURRENT_FILES];			//Directory entry of file
MX_UINT32 %a_mx_file_size[%a_CONCURRENT_FILES];			//Size of file in bytes
MX_UINT32 %a_mx_file_address[%a_CONCURRENT_FILES]; 		//Start address of File
MX_UINT32 %a_mx_file_pointer[%a_CONCURRENT_FILES];		//Current address loaded in memory
MX_UINT32 %a_mx_file_sector[%a_CONCURRENT_FILES];		//Current sector of file
MX_UINT32 %a_mx_folder_size[%a_CONCURRENT_FILES];		//Folder size in sectors
MX_UINT32 %a_mx_folder_start[%a_CONCURRENT_FILES];		//Start address of Folder
MX_UINT8 %a_mx_file_idx = 0;

//FAT Specific Variables
#if (%a_FAT_TYPE == 0)
	MX_UINT16 %a_mx_cluster = 2;		//Current data %a_mx_cluster in the memory
	#define %a_SECT_ADDR_LEN			2
	#define %a_FATS_PER_SECT			(512 / 2)	//2 bytes per fat record
	#define %a_NOT_ADDRESS_MARKER		0xFFF0
	#define %a_MX_EOF_MARKER			0xFFF7
#endif
#if (%a_FAT_TYPE == 1)
	MX_UINT32 %a_mx_cluster = 2;		//Current data %a_mx_cluster in the memory
	#define %a_mx_fat_system  			1
	#define %a_SECT_ADDR_LEN			4
	#define %a_FATS_PER_SECT			(512 / 4)	//4 bytes per fat record
	#define %a_NOT_ADDRESS_MARKER		0x0FFFFFF0
	#define %a_MX_EOF_MARKER			0x0FFFFFF7
#endif
#if (%a_FAT_TYPE == 2)
	MX_UINT32 %a_mx_cluster = 2;		//Current data %a_mx_cluster in the memory
	MX_UINT8 %a_mx_fat_system;						//Type of FAT file system in use on disk     - Added BR 07/10
	MX_UINT8 %a_SECT_ADDR_LEN;						//Defines become variables
	MX_UINT16 %a_FATS_PER_SECT;
	MX_UINT32 %a_NOT_ADDRESS_MARKER;
	MX_UINT32 %a_MX_EOF_MARKER;
#endif


/**  MIAC SPI drivers for SD CARD **/

MX_UINT8 %a_SPI_Prescaler = 1;	// start at highest speed

void %a_SPI_Set_Prescaler (MX_UINT8 Prescaler)
{
	%a_SPI_Prescaler = Prescaler;
}

void %a_SPI_Master_Init()
{
#if (%y != MX_MIAC_MM_MIAC_BASE)
	MX_UINT8 SPI2CON1 = 0x1c;
	switch(%a_SPI_Prescaler)
	{
		case  1: SPI2CON1 = 0x1f; break;
		case  4: SPI2CON1 = 0x1e; break;
		case 16: SPI2CON1 = 0x1d; break;
		default: SPI2CON1 = 0x1c; break;	// default to 64
	}
	MIAC_CAN_TX[0] = SPI2CON1;
	MIAC_CAN_TX[1] = 0;	// CKP
	MIAC_CAN_TX[2] = 1;	// CKE
	MIAC_CAN_TX[3] = 1;	// SMP
	MIAC_Module_WR(MOD_CAN_ID_%y_%x, 360, 4,1,0);
	MIAC_Module_GetAck(MOD_CAN_ID_%y_%x, 360, 200);
#endif
}

void %a_SPI_Master_Uninit()
{
}

void %a_SPI_Master_CS (MX_UINT8 State)
{
#if (%y != MX_MIAC_MM_MIAC_BASE)
	MIAC_CAN_TX[0] = State;
	MIAC_Module_WR(MOD_CAN_ID_%y_%x, 361, 1,1,0);
	MIAC_Module_GetAck(MOD_CAN_ID_%y_%x, 361, 200);
#endif
}

MX_UINT8 %a_SPI_Master_Byte (MX_UINT8 DataOut)
{
#if (%y != MX_MIAC_MM_MIAC_BASE)
	MIAC_CAN_TX[0] = DataOut;
	MIAC_Module_WR(MOD_CAN_ID_%y_%x, 362, 1,1,0);
	MIAC_Module_GetAck(MOD_CAN_ID_%y_%x, 362, 200);
	return MIAC_CAN_RX[0];
#endif
}

/*DefinesCode_End*/

/*InitialisationCode_Start*/
/*InitialisationCode_End*/

/*InterruptCode_Start*/
/*InterruptCode_End*/


/********************************************************************
 * FUNCTIONS
 ********************************************************************/


void Write_Byte_To_Buffer(MX_SINT16 Address, MX_UINT8 Data)
{
/*Macro_Write_Byte_To_Buffer_Start*/

	if (Address > 255)				//BufferH
	{
		Address = Address - 256;
		%a_mx_card_bufferh[Address] = Data;
	}
	else							//BufferL
	{
		%a_mx_card_bufferl[Address] = Data;
	}

/*Macro_Write_Byte_To_Buffer_End*/
}



MX_UINT8 Read_Byte_From_Buffer(MX_SINT16 Address)
{
/*Macro_Read_Byte_From_Buffer_Start*/

	if (Address > 255)						//BufferH
	{
		Address = Address - 256;
		return (%a_mx_card_bufferh[Address]);
	}
	else return (%a_mx_card_bufferl[Address]);	//BufferL

/*Macro_Read_Byte_From_Buffer_End*/
}



MX_UINT8 Init_FAT (void)
{
/*Macro_Init_FAT_Start*/

	MX_UINT8 retval;
	MX_UINT8 i, num_fats;
	MX_UINT16 bytes_per_sect = 0;
	MX_UINT16 reserved_sectors;
	MX_UINT32 partition_start = 0;  //Start address of the partition
	MX_UINT32 root_size; 			//Number of 32 byte root entries.
	MX_Union32 Temp32;
	MX_Union16 Temp16;

	retval = MX_Init_Card(); //Startup Card
	if (retval)
	{
		%a_SPI_Set_Prescaler(4);	//Try again at a lower speed 1:64

			retval = MX_Init_Card(); 	//Read Master Boot Record if available

			if (retval)
	return(retval); //Startup error or no card
	}

	delay_ms(50);

	retval = MX_Get_Buffer(0); //Read Master Boot Record if available

		if (retval)
			return MX_ERR_SECTBYTES;

	i = Read_Byte_From_Buffer(0);

	if(i!=0xE9 && i!=0xEB)
	{
		Temp16.AsByte[0] = Read_Byte_From_Buffer(510);
		Temp16.AsByte[1] = Read_Byte_From_Buffer(511);

		if (Temp16.AsInt != 0xaa55)
			return MX_ERR_SECTBYTES;

		Temp32.AsByte[0] = Read_Byte_From_Buffer(454);
		Temp32.AsByte[1] = Read_Byte_From_Buffer(455);
		Temp32.AsByte[2] = Read_Byte_From_Buffer(456);
		Temp32.AsByte[3] = Read_Byte_From_Buffer(457);
		partition_start = Temp32.AsLong;

		MX_Get_Buffer(partition_start);

		i = Read_Byte_From_Buffer(0);

		if (i!=0xE9 && i!=0xEB)
			return MX_ERR_SECTBYTES;
	}


		Temp16.AsByte[0] = Read_Byte_From_Buffer(0x0B); //Bytes per sector - normally 512
		Temp16.AsByte[1] = Read_Byte_From_Buffer(0x0C);
		bytes_per_sect = Temp16.AsInt;

	if (bytes_per_sect != 512)
		return MX_ERR_SECTBYTES;

	%a_mx_sects_per_clust = Read_Byte_From_Buffer(0x0D);								//Read number of sectors per %a_mx_cluster

	Temp16.AsByte[0] = Read_Byte_From_Buffer(0x0E);										//Number of reserved sectors
	Temp16.AsByte[1] = Read_Byte_From_Buffer(0x0F);
	reserved_sectors = Temp16.AsInt;

	num_fats = Read_Byte_From_Buffer(0x10);											//Num of copies of FAT - normally 2

	#if (%a_FAT_TYPE == 2)
		if ( Read_Byte_From_Buffer(0x55) == '3')									//Is this a FAT32 card?
		{
			%a_mx_fat_system = 1;
			%a_SECT_ADDR_LEN = 4;
			%a_FATS_PER_SECT = 128;
			%a_NOT_ADDRESS_MARKER = 0x0FFFFFF0;
			%a_MX_EOF_MARKER = 0x0FFFFFF7;
		}
		else
		{
			%a_mx_fat_system = 0;
			%a_SECT_ADDR_LEN = 2;
			%a_FATS_PER_SECT = 256;
			%a_NOT_ADDRESS_MARKER = 0xFFF0;
			%a_MX_EOF_MARKER = 0xFFF7;
		}
	#endif

	%a_mx_fat_start = partition_start + reserved_sectors;									//start of FAT address space in sectors


	#if (%a_FAT_TYPE == 0)																//FAT32 uses normal folder cluster for root

		Temp16.AsByte[0] = Read_Byte_From_Buffer(0x11);										//Size of root directory x 32 byte file/directory entries
		Temp16.AsByte[1] = Read_Byte_From_Buffer(0x12);
		root_size = Temp16.AsInt;

		if(root_size == 0)																//if root size not defined here
		{
			Temp32.AsByte[0] = Read_Byte_From_Buffer(0x24);									//Size of root directory x 32 byte file/directory entries
			Temp32.AsByte[1] = Read_Byte_From_Buffer(0x25);
			Temp32.AsByte[2] = Read_Byte_From_Buffer(0x26);
			Temp32.AsByte[3] = Read_Byte_From_Buffer(0x27);
			root_size = Temp32.AsLong;
		}
		%a_mx_root_sectors = root_size >> 4;												//Number of sectors in the root directory

		Temp16.AsByte[0] = Read_Byte_From_Buffer(0x16);										//FAT size in sectors
		Temp16.AsByte[1] = Read_Byte_From_Buffer(0x17);
		%a_mx_fat_size = Temp16.AsInt;

		%a_mx_root_start = %a_mx_fat_start + (num_fats * %a_mx_fat_size);						//start of the root directory in sectors
		%a_mx_data_start = %a_mx_root_start + %a_mx_root_sectors;								//start of the data %a_mx_clusters in sectors

	#endif
	#if (%a_FAT_TYPE == 1)																//FAT32 uses normal folder cluster for root

		%a_mx_root_sectors = %a_mx_sects_per_clust;

		Temp32.AsByte[0] = Read_Byte_From_Buffer(0x24);											//FAT size in sectors
		Temp32.AsByte[1] = Read_Byte_From_Buffer(0x25);
		Temp32.AsByte[2] = Read_Byte_From_Buffer(0x26);
		Temp32.AsByte[3] = Read_Byte_From_Buffer(0x27);
		%a_mx_fat_size = Temp32.AsLong;

		Temp32.AsByte[0] = Read_Byte_From_Buffer(0x2C);										//first cluster address of root directory
		Temp32.AsByte[1] = Read_Byte_From_Buffer(0x2D);
		Temp32.AsByte[2] = Read_Byte_From_Buffer(0x2E);
		Temp32.AsByte[3] = Read_Byte_From_Buffer(0x2F);
		root_size = Temp32.AsLong;

		%a_mx_data_start = %a_mx_fat_start + (num_fats * %a_mx_fat_size);						//start of the root directory in sectors
		%a_mx_root_start = %a_mx_data_start + ((root_size - 2) * %a_mx_sects_per_clust);			//Move to sector containing start of file

	#endif
	#if (%a_FAT_TYPE == 2)
		if (%a_mx_fat_system == 0)																//FAT32 uses normal folder cluster for root
		{
			Temp16.AsByte[0] = Read_Byte_From_Buffer(0x11);										//Size of root directory x 32 byte file/directory entries
			Temp16.AsByte[1] = Read_Byte_From_Buffer(0x12);
			root_size = Temp16.AsInt;

			if(root_size == 0)																//if root size not defined here
			{
				Temp32.AsByte[0] = Read_Byte_From_Buffer(0x24);									//Size of root directory x 32 byte file/directory entries
				Temp32.AsByte[1] = Read_Byte_From_Buffer(0x25);
				Temp32.AsByte[2] = Read_Byte_From_Buffer(0x26);
				Temp32.AsByte[3] = Read_Byte_From_Buffer(0x27);
				root_size = Temp32.AsLong;
			}
			%a_mx_root_sectors = root_size >> 4;												//Number of sectors in the root directory

			Temp16.AsByte[0] = Read_Byte_From_Buffer(0x16);										//FAT size in sectors
			Temp16.AsByte[1] = Read_Byte_From_Buffer(0x17);
			%a_mx_fat_size = Temp16.AsInt;

			%a_mx_root_start = %a_mx_fat_start + (num_fats * %a_mx_fat_size);						//start of the root directory in sectors
			%a_mx_data_start = %a_mx_root_start + %a_mx_root_sectors;								//start of the data %a_mx_clusters in sectors

		}
		if (%a_mx_fat_system == 1)																//FAT32 uses normal folder cluster for root
		{
			%a_mx_root_sectors = %a_mx_sects_per_clust;

			Temp32.AsByte[0] = Read_Byte_From_Buffer(0x24);										//FAT size in sectors
			Temp32.AsByte[1] = Read_Byte_From_Buffer(0x25);
			Temp32.AsByte[2] = Read_Byte_From_Buffer(0x26);
			Temp32.AsByte[3] = Read_Byte_From_Buffer(0x27);
			%a_mx_fat_size = Temp32.AsLong;

			Temp32.AsByte[0] = Read_Byte_From_Buffer(0x2C);										//first cluster address of root directory
			Temp32.AsByte[1] = Read_Byte_From_Buffer(0x2D);
			Temp32.AsByte[2] = Read_Byte_From_Buffer(0x2E);
			Temp32.AsByte[3] = Read_Byte_From_Buffer(0x2F);
			root_size = Temp32.AsLong;

			%a_mx_data_start = %a_mx_fat_start + (num_fats * %a_mx_fat_size);						//start of the root directory in sectors
			%a_mx_root_start = %a_mx_data_start + ((root_size - 2) * %a_mx_sects_per_clust);			//Move to sector containing start of file
		}
	#endif

	for (i = 0; i < %a_CONCURRENT_FILES; i++)													//Init all file folders to root
	{
		%a_mx_folder_size[i] = %a_mx_root_sectors;
		%a_mx_folder_start[i] = %a_mx_root_start;
	}

	return retval;

/*Macro_Init_FAT_End*/
}



MX_UINT8 Open_File (MX_STRING File_Name)
{
/*Macro_Open_File_Start*/

	MX_UINT8 i;
	MX_UINT8 name_comp[11];
	MX_UINT16 idx_fat;
	MX_UINT16 Idx;

	#if (%a_FAT_TYPE == 0)
		MX_UINT16 fat_pointer = 0xFFFF;
	#endif
	#if (%a_FAT_TYPE == 1)
		MX_UINT32 fat_pointer = 0x0FFFFFFF;
	#endif
	#if (%a_FAT_TYPE == 2)
		MX_UINT32 fat_pointer;
		if (%a_mx_fat_system == 0)
			fat_pointer = 0xFFFF;
		else fat_pointer = 0x0FFFFFFF;
	#endif
	MX_UINT32 fat_address;

	MX_Union32 Temp32;

	MX_Format_File_String(File_Name, MSZ_File_Name);							//Convert filename to 8.3 format

	%a_mx_file_pointer[%a_mx_file_idx] = %a_mx_folder_start[%a_mx_file_idx];								//Move to start of root
	while (%a_mx_file_pointer[%a_mx_file_idx] < (%a_mx_folder_start[%a_mx_file_idx] + %a_mx_folder_size[%a_mx_file_idx]))
	{
		MX_Get_Buffer(%a_mx_file_pointer[%a_mx_file_idx]);								//Read sector of root directory
		for(i=0;i<16;i++)														//16 file or directory references per sector
		{
			Idx = i << 5;

			name_comp[0] = Read_Byte_From_Buffer(0 + Idx);					//Move DOS 8.3 Filename into 2nd comparison buffer
			name_comp[1] = Read_Byte_From_Buffer(1 + Idx);
			name_comp[2] = Read_Byte_From_Buffer(2 + Idx);
			name_comp[3] = Read_Byte_From_Buffer(3 + Idx);
			name_comp[4] = Read_Byte_From_Buffer(4 + Idx);
			name_comp[5] = Read_Byte_From_Buffer(5 + Idx);
			name_comp[6] = Read_Byte_From_Buffer(6 + Idx);
			name_comp[7] = Read_Byte_From_Buffer(7 + Idx);
			name_comp[8] = Read_Byte_From_Buffer(8 + Idx);
			name_comp[9] = Read_Byte_From_Buffer(9 + Idx);
			name_comp[10] = Read_Byte_From_Buffer(10 + Idx);

			/*
			//Debug Information
			if(name_comp[0] > 'A')
			{
				FCD_LCDDisplay0_Clear();
				FCD_LCDDisplay0_PrintString(%a_mx_name_ext, 11);
				FCD_LCDDisplay0_Cursor(0,1);
				FCD_LCDDisplay0_PrintString(name_comp, 11);
				FCD_LCDDisplay0_Cursor(13,1);
				FCD_LCDDisplay0_PrintNumber(FCI_COMPARE(%a_mx_name_ext,11,name_comp,11,1));
				delay_s(2);
			}*/

			if (FCI_COMPARE(%a_mx_name_ext,11,name_comp,11,1) == 0)				//Perform filename comparison
			{
				%a_mx_file_entry[%a_mx_file_idx] = i;									//Store file address
				%a_mx_file_address[%a_mx_file_idx] = %a_mx_file_pointer[%a_mx_file_idx];
				%a_mx_file_sector[%a_mx_file_idx] = 1;

				Temp32.AsByte[0] = Read_Byte_From_Buffer(26 + Idx);				//Read Cluster of data start
				Temp32.AsByte[1] = Read_Byte_From_Buffer(27 + Idx);
				Temp32.AsByte[2] = 0;
				Temp32.AsByte[3] = 0;

				#if (%a_FAT_TYPE == 1 || %a_FAT_TYPE == 2)
					if(%a_mx_fat_system == 1)
					{
						Temp32.AsByte[2] = Read_Byte_From_Buffer(20 + Idx);
						Temp32.AsByte[3] = Read_Byte_From_Buffer(21 + Idx);
					}
				#endif

				%a_mx_cluster = Temp32.AsLong;

				Temp32.AsByte[0] = Read_Byte_From_Buffer(28 + Idx);				//Read Filesize in bytes
				Temp32.AsByte[1] = Read_Byte_From_Buffer(29 + Idx);
				Temp32.AsByte[2] = Read_Byte_From_Buffer(30 + Idx);
				Temp32.AsByte[3] = Read_Byte_From_Buffer(31 + Idx);
				%a_mx_file_size[%a_mx_file_idx] = Temp32.AsLong;

				if (%a_mx_cluster == 0)											//Empty File - Assign a free %a_mx_cluster
				{
					idx_fat = 1;
					fat_address = %a_mx_fat_start;								//Move to start of FAT
					MX_Get_Buffer(fat_address);								//Read FAT sector
					while (fat_pointer != 0)								//Scan FAT for free entry
					{
						idx_fat = idx_fat + 1;
						if(idx_fat == %a_FATS_PER_SECT)				//If at the end of the FAT sector
						{
							fat_address = fat_address + 1;
							MX_Get_Buffer(fat_address);						//Read next FAT sector
							idx_fat = 0;
						}

						Temp32.AsByte[0] = Read_Byte_From_Buffer(idx_fat * %a_SECT_ADDR_LEN);			//Extract data %a_mx_cluster address
						Temp32.AsByte[1] = Read_Byte_From_Buffer((idx_fat * %a_SECT_ADDR_LEN) + 1);
						Temp32.AsByte[2] = 0;
						Temp32.AsByte[3] = 0;

						#if (%a_FAT_TYPE == 1 || %a_FAT_TYPE == 2)
							if(%a_mx_fat_system == 1)
							{
								Temp32.AsByte[2] = Read_Byte_From_Buffer((idx_fat * %a_SECT_ADDR_LEN) + 2);
								Temp32.AsByte[3] = Read_Byte_From_Buffer((idx_fat * %a_SECT_ADDR_LEN) + 3);

							}
						#endif

						fat_pointer = Temp32.AsLong;
					}

					Write_Byte_To_Buffer((idx_fat * %a_SECT_ADDR_LEN), 0xFF);						//Write end of file marker into new FAT address
					Write_Byte_To_Buffer(((idx_fat * %a_SECT_ADDR_LEN) + 1), 0xFF);
					#if (%a_FAT_TYPE == 1 || %a_FAT_TYPE == 2)
						if(%a_mx_fat_system == 1)
						{
							Write_Byte_To_Buffer(((idx_fat * %a_SECT_ADDR_LEN) + 2), 0xFF);
							Write_Byte_To_Buffer(((idx_fat * %a_SECT_ADDR_LEN) + 3), 0x0F);
						}
					#endif
					MX_Send_Buffer(fat_address);
					MX_Send_Buffer(fat_address + %a_mx_fat_size);										//Mirror data onto FAT 2

					MX_Get_Buffer(%a_mx_file_pointer[%a_mx_file_idx]);												//Read sector of root directory containing file
					fat_address = ((fat_address - %a_mx_fat_start) * %a_FATS_PER_SECT) + idx_fat;
					%a_mx_cluster = fat_address;

					Temp32.AsLong = %a_mx_cluster;

					Write_Byte_To_Buffer(26 + Idx, Temp32.AsByte[0]);									//Write new %a_mx_cluster value
					Write_Byte_To_Buffer(27 + Idx, Temp32.AsByte[1]);
					#if (%a_FAT_TYPE == 1 || %a_FAT_TYPE == 2)
						if(%a_mx_fat_system == 1)
						{
							Write_Byte_To_Buffer(20 + Idx, Temp32.AsByte[2]);
							Write_Byte_To_Buffer(21 + Idx, Temp32.AsByte[3]);
						}
					#endif
					MX_Send_Buffer(%a_mx_file_pointer[%a_mx_file_idx]);												//Write %a_mx_cluster location to card
				}

				%a_mx_file_pointer[%a_mx_file_idx] = %a_mx_data_start + ((%a_mx_cluster - 2) * %a_mx_sects_per_clust);		//Move to sector containing start of file   - BR 06/10 was *32
				MX_Get_Buffer(%a_mx_file_pointer[%a_mx_file_idx]);													//Read sector
				return MX_ACK_OK;
			}
		}
		%a_mx_file_pointer[%a_mx_file_idx] = %a_mx_file_pointer[%a_mx_file_idx] + 1;											//Move to next sector of folder
	}
	return MX_ERR_FILENOTFOUND;																		//File not found

/*Macro_Open_File_End*/
}


MX_SINT16 Read_File_Length(void)
{
/*Macro_Read_File_Length_Start*/

	long temp;
	temp = %a_mx_file_sector[%a_mx_file_idx] << 9;
	if (temp <= %a_mx_file_size[%a_mx_file_idx])			//If file size greater then sector limit
		return 512;								//Return Sector Full

	temp = %a_mx_file_size[%a_mx_file_idx] % 512;
	return (temp);								//Return index of next available byte

/*Macro_Read_File_Length_End*/
}


MX_UINT8 Read_File_Sector (void)
{
/*Macro_Read_File_Sector_Start*/

	return MX_Get_Buffer(%a_mx_file_pointer[%a_mx_file_idx]);		//Read sector

/*Macro_Read_File_Sector_End*/
}



MX_UINT8 Move_To_Next_File_Sector(MX_UINT8 Force_Next_Sector)
{
/*Macro_Move_To_Next_File_Sector_Start*/

	MX_UINT8 retval;
	retval = Read_Next_File_Sector();				//Try to move to the next sector
	if (Force_Next_Sector)							//If forcing next sector
	{
		if(retval != 0x01)
			return retval;							//Next sector exists and has been read (0) or error with sector chain

		MX_Add_Sector_To_File();					//If last sector in FAT chain then create new link
		//%a_mx_file_sector[%a_mx_file_idx] = %a_mx_file_sector[%a_mx_file_idx] + 1;		//Increment file sector
		return MX_ACK_OK;
	}
	return retval;

/*Macro_Move_To_Next_File_Sector_End*/
}



MX_UINT8 Append_String_To_File(MX_STRING String, MX_UINT8 MSZ_String)
{
/*Macro_Append_String_To_File_Start*/

	MX_UINT8 idx;
	MX_SINT16 length;
	MX_UINT8 retval;
	MX_UINT8 offset = 0;
	MX_UINT16 Idx16;

	MX_Union32 Temp32;

	for (idx=0;idx<MSZ_String;idx++)
	{
		if(String[idx] == 0)
			MSZ_String = idx;
	}

	length = Read_File_Length();				//Get next empty MX_UINT8acter position
	while (length == 512)						//While MX_UINT8acters in sector full
	{
		retval = Read_Next_File_Sector();		//Load next sector
		if (retval == 0x01)						//If end of file then next sector will be empty
			length = -1;
		else
			length = Read_File_Length();		//Else end of data located in this sector
	}

	if (length == -1)
		length = 512;

	for (idx = 0; idx < MSZ_String; idx++)		//Loop through each MX_UINT8acter in string
	{
		if((length + idx) == 512)				//if string extends onto another sector
		{
			length = 0;
			offset = idx;

			MX_Send_Buffer(%a_mx_file_pointer[%a_mx_file_idx]);							//Write string data in current sector to card
			retval = Read_Next_File_Sector();		//Load next sector

			if (retval == 0x01)
			{
				MX_Add_Sector_To_File();			//If last sector in FAT chain then create new link
			}

			if (retval > 0x01)
				return retval;										//Error occurred - return error
		}

		Write_Byte_To_Buffer((length + (idx - offset)), String[idx]);		//Write MX_UINT8acter from string into buffer
	}

	MX_Send_Buffer(%a_mx_file_pointer[%a_mx_file_idx]);									//Write string data in current sector to card
	%a_mx_file_size[%a_mx_file_idx] = %a_mx_file_size[%a_mx_file_idx] + MSZ_String;	//Update file length
	MX_Get_Buffer(%a_mx_file_address[%a_mx_file_idx]);							//Read file address

	Temp32.AsLong = %a_mx_file_size[%a_mx_file_idx];

	Idx16 = 28 + (%a_mx_file_entry[%a_mx_file_idx] << 5);

	Write_Byte_To_Buffer(Idx16++, Temp32.AsByte[0]);				//Update file length in buffer
	Write_Byte_To_Buffer(Idx16++, Temp32.AsByte[1]);
	Write_Byte_To_Buffer(Idx16++, Temp32.AsByte[2]);
	Write_Byte_To_Buffer(Idx16, Temp32.AsByte[3]);

	MX_Send_Buffer(%a_mx_file_address[%a_mx_file_idx]);							//Update file length on card
	MX_Send_Buffer(%a_mx_file_address[%a_mx_file_idx] + %a_mx_fat_size);		//Mirror data onto FAT 2
	MX_Get_Buffer(%a_mx_file_pointer[%a_mx_file_idx]);									//Read current sector
	return MX_ACK_OK;														//String appended to file

/*Macro_Append_String_To_File_End*/
}



MX_UINT8 Write_File_Sector (void)
{
/*Macro_Write_File_Sector_Start*/

	short Idx;

	MX_Union32 Temp32;

	if ((%a_mx_file_size[%a_mx_file_idx] >> 9) == (%a_mx_file_sector[%a_mx_file_idx] - 1))					//Is this the last sector of the file
		%a_mx_file_size[%a_mx_file_idx] = (%a_mx_file_size[%a_mx_file_idx] + (512 - Read_File_Length()));

	MX_Send_Buffer(%a_mx_file_pointer[%a_mx_file_idx]);									//Write string data in current sector to card
	MX_Get_Buffer(%a_mx_file_address[%a_mx_file_idx]);							//Read file address

	Temp32.AsLong = %a_mx_file_size[%a_mx_file_idx];

	Idx = 28 + (%a_mx_file_entry[%a_mx_file_idx] << 5);
	Write_Byte_To_Buffer(Idx++, Temp32.AsByte[0]);					//Update file length in buffer
	Write_Byte_To_Buffer(Idx++, Temp32.AsByte[1]);
	Write_Byte_To_Buffer(Idx++, Temp32.AsByte[2]);
	Write_Byte_To_Buffer(Idx, Temp32.AsByte[3]);

	MX_Send_Buffer(%a_mx_file_address[%a_mx_file_idx]);							//Update file length on card
	MX_Send_Buffer(%a_mx_file_address[%a_mx_file_idx] + %a_mx_fat_size);		//Mirror data onto FAT 2
	MX_Get_Buffer(%a_mx_file_pointer[%a_mx_file_idx]);									//Read current sector

	return MX_ACK_OK;

/*Macro_Write_File_Sector_End*/
}



MX_UINT8 Create_File(MX_STRING File_Name)
{
/*Macro_Create_File_Start*/

	MX_UINT8 i, j;
	MX_UINT16 Idx;

	MX_Union16 Temp16;

	if ( Open_File(File_Name, MSZ_File_Name) != MX_ERR_FILENOTFOUND )
		return 0x01;													//File Already exists

	//MX_Format_File_String(File_Name, MSZ_File_Name);					//Convert filename to 8.3 format - Not needed as open_file calls this
	%a_mx_file_pointer[%a_mx_file_idx] = %a_mx_folder_start[%a_mx_file_idx];								//Move to start of root
	while (%a_mx_file_pointer[%a_mx_file_idx] < (%a_mx_folder_start[%a_mx_file_idx] + %a_mx_folder_size[%a_mx_file_idx]))
	{
		MX_Get_Buffer(%a_mx_file_pointer[%a_mx_file_idx]);								//Read sector of root directory
		for(i=0;i<16;i++)												//16 file or directory references per sector
		{
			Idx = i << 5;
			j = Read_Byte_From_Buffer(Idx);
			if (( j == 0xe5) || ( j == 0x00))							//Deleted or unused entry
			{
				for (j=0;j<11;j++)
				{
					Write_Byte_To_Buffer(Idx++, %a_mx_name_ext[j]);
				}

				Write_Byte_To_Buffer(Idx++, 0x20);						//File Attribute
				Write_Byte_To_Buffer(Idx++, 0x18);						//Reserved for NT
				Write_Byte_To_Buffer(Idx++, 0);							//Creation time
				Temp16.AsInt = %a_FILE_CREATETIME;
				Write_Byte_To_Buffer(Idx++, Temp16.AsByte[0]);
				Write_Byte_To_Buffer(Idx++, Temp16.AsByte[1]);
				Temp16.AsInt = %a_FILE_CREATEDATE;
				Write_Byte_To_Buffer(Idx++, Temp16.AsByte[0]);		//Creation date
				Write_Byte_To_Buffer(Idx++, Temp16.AsByte[1]);
				Write_Byte_To_Buffer(Idx++, Temp16.AsByte[0]);		//Access date
				Write_Byte_To_Buffer(Idx++, Temp16.AsByte[1]);
				Write_Byte_To_Buffer(Idx++, 0x00);
				Write_Byte_To_Buffer(Idx++, 0x00);
				Temp16.AsInt = %a_FILE_CREATETIME;
				Write_Byte_To_Buffer(Idx++, Temp16.AsByte[0]);		//Modified time 0 no modification entry
				Write_Byte_To_Buffer(Idx++, Temp16.AsByte[1]);
				Temp16.AsInt = %a_FILE_CREATEDATE;
				Write_Byte_To_Buffer(Idx++, Temp16.AsByte[0]);		//Modified date
				Write_Byte_To_Buffer(Idx++, Temp16.AsByte[1]);

				for (j=26;j<32;j++)												//Sector location and length
				{
					Write_Byte_To_Buffer(Idx++, 0);
				}
				MX_Send_Buffer(%a_mx_file_pointer[%a_mx_file_idx]);
				return MX_ACK_OK;												//File created
			}
		}
		%a_mx_file_pointer[%a_mx_file_idx] = %a_mx_file_pointer[%a_mx_file_idx] + 1;
	}
	return MX_ERR_ROOTFULL;														//No space left in root directory

/*Macro_Create_File_End*/
}



MX_UINT8 Delete_File(MX_STRING File_Name)
{
/*Macro_Delete_File_Start*/

	MX_UINT8 name_comp[11];
	MX_UINT32 fat_address;
	MX_UINT8 i;
	MX_UINT16 Idx;

	MX_Union16 Temp16;

	#if (%a_FAT_TYPE == 0)
		MX_UINT16 temp_mx_cluster;
	#endif
	#if (%a_FAT_TYPE == 1 || %a_FAT_TYPE == 2)
		MX_UINT32 temp_mx_cluster;
	#endif

	MX_Format_File_String(File_Name, MSZ_File_Name);						//Convert filename to 8.3 format
	%a_mx_file_pointer[%a_mx_file_idx] = %a_mx_folder_start[%a_mx_file_idx];									//Move to start of root

	while (%a_mx_file_pointer[%a_mx_file_idx] <= (%a_mx_folder_start[%a_mx_file_idx] + %a_mx_folder_size[%a_mx_file_idx]))
	{
		MX_Get_Buffer(%a_mx_file_pointer[%a_mx_file_idx]);									//Read sector of root directory
		for(i=0;i<16;i++)													//16 file or directory references per sector
		{
			Idx = i << 5;

			name_comp[0] = Read_Byte_From_Buffer(Idx);						//Move DOS 8.3 Filename into 2nd comparison buffer
			name_comp[1] = Read_Byte_From_Buffer(1 + Idx);
			name_comp[2] = Read_Byte_From_Buffer(2 + Idx);
			name_comp[3] = Read_Byte_From_Buffer(3 + Idx);
			name_comp[4] = Read_Byte_From_Buffer(4 + Idx);
			name_comp[5] = Read_Byte_From_Buffer(5 + Idx);
			name_comp[6] = Read_Byte_From_Buffer(6 + Idx);
			name_comp[7] = Read_Byte_From_Buffer(7 + Idx);
			name_comp[8] = Read_Byte_From_Buffer(8 + Idx);
			name_comp[9] = Read_Byte_From_Buffer(9 + Idx);
			name_comp[10] = Read_Byte_From_Buffer(10 + Idx);

			if (FCI_COMPARE(%a_mx_name_ext,11,name_comp,11,1) == 0)				//Perform filename comparison
			{
				Temp16.AsByte[0] = Read_Byte_From_Buffer(26 + Idx);				//Read Cluster of data start
				Temp16.AsByte[1] = Read_Byte_From_Buffer(27 + Idx);
				%a_mx_cluster = Temp16.AsInt;

				Write_Byte_To_Buffer(26 + Idx, 0);								//Overwrite %a_mx_cluster value
				Write_Byte_To_Buffer(27 + Idx, 0);
				#if(%a_FAT_TYPE == 1 || %a_FAT_TYPE == 2)
					if (%a_mx_fat_system == 1)
					{
						Write_Byte_To_Buffer(20 + Idx, 0);
						Write_Byte_To_Buffer(21 + Idx, 0);
					}
				#endif

				Write_Byte_To_Buffer(28 + Idx, 0);								//Clear file size
				Write_Byte_To_Buffer(29 + Idx, 0);
				Write_Byte_To_Buffer(30 + Idx, 0);
				Write_Byte_To_Buffer(31 + Idx, 0);
				Write_Byte_To_Buffer(Idx, 0xe5);								//Set first byte to free file flag
				MX_Send_Buffer(%a_mx_file_pointer[%a_mx_file_idx]);							//Write the free file flag to the card

				while (%a_mx_cluster >= 0x02 && %a_mx_cluster <= (%a_MX_EOF_MARKER + 1))			//While end of file not reached
				{
					if (%a_mx_cluster > %a_MX_EOF_MARKER)
						return 0xFE;										//Problem with FAT entry

					fat_address = %a_mx_fat_start;								//Move to start of FAT
					while(%a_mx_cluster >= %a_FATS_PER_SECT)
					{
						fat_address = fat_address + 1;						//Move to next sector of FAT
						%a_mx_cluster = %a_mx_cluster - %a_FATS_PER_SECT;
					}
					MX_Get_Buffer(fat_address);								//Read FAT sector

					temp_mx_cluster = %a_mx_cluster;
					Temp16.AsByte[0] = Read_Byte_From_Buffer(temp_mx_cluster * %a_FATS_PER_SECT);			//Read next %a_mx_cluster value
					Temp16.AsByte[1] = Read_Byte_From_Buffer((temp_mx_cluster * %a_FATS_PER_SECT) + 1);
					%a_mx_cluster = Temp16.AsInt;

					Write_Byte_To_Buffer((temp_mx_cluster * %a_FATS_PER_SECT), 0x00);				//Overwrite FAT entry
					Write_Byte_To_Buffer(((temp_mx_cluster * %a_FATS_PER_SECT) + 1), 0x00);

					MX_Send_Buffer(fat_address);
					MX_Send_Buffer(fat_address + %a_mx_fat_size);				//Mirror data onto FAT 2
				}
				return 0;													//File deleted correctly
			}
		}
		%a_mx_file_pointer[%a_mx_file_idx] = %a_mx_file_pointer[%a_mx_file_idx] + 1;
	}
	return MX_ERR_FILENOTFOUND;												//File not found

/*Macro_Delete_File_End*/
}



MX_UINT8 Open_Folder(MX_STRING Folder_Name)
{
/*Macro_Open_Folder_Start*/

// ".." - Up a level
// "root" - Root directory
// "foldername" - Down a level

	MX_UINT8 i;
	MX_UINT8 name_comp[11];
	MX_UINT16 Idx;

	MX_Union32 Temp32;

	//Root Directory
	if (Folder_Name[0] == 'r' && Folder_Name[1] == 'o' && Folder_Name[2] == 'o' && Folder_Name[3] == 't')
	{
		%a_mx_folder_start[%a_mx_file_idx] = %a_mx_root_start;		//Assign root start address to folder start
		%a_mx_folder_size[%a_mx_file_idx] = %a_mx_root_sectors;		//Assign root size to folder size
		return (0);								//Root Directory Specified
	}

	//Up a level
	if (Folder_Name[0] == '.' && Folder_Name[1] == '.')
	{
		%a_mx_name_ext[0] = 0x2E;			// Assign search string with ".."
		%a_mx_name_ext[1] = 0x2E;
		%a_mx_name_ext[2] = 0x20;
		%a_mx_name_ext[3] = 0x20;
		%a_mx_name_ext[4] = 0x20;
		%a_mx_name_ext[5] = 0x20;
		%a_mx_name_ext[6] = 0x20;
		%a_mx_name_ext[7] = 0x20;
		%a_mx_name_ext[8] = 0x20;
		%a_mx_name_ext[9] = 0x20;
		%a_mx_name_ext[10] = 0x20;
	}

	else
		MX_Format_File_String(Folder_Name, MSZ_Folder_Name);					//Format folder string to match 8 MX_UINT8acter folder name

	%a_mx_file_pointer[%a_mx_file_idx] = %a_mx_folder_start[%a_mx_file_idx];							//Move to start of folder

	while (%a_mx_file_pointer[%a_mx_file_idx] < (%a_mx_folder_start[%a_mx_file_idx] + %a_mx_folder_size[%a_mx_file_idx]))
	{
		MX_Get_Buffer(%a_mx_file_pointer[%a_mx_file_idx]);										//Read sector of root directory
		for(i=0;i<16;i++)														//16 file or directory references per sector
		{
			Idx = i << 5;

			name_comp[0] = Read_Byte_From_Buffer(Idx);					//Move DOS 8.3 Filename into 2nd comparison buffer
			name_comp[1] = Read_Byte_From_Buffer(1 + Idx);
			name_comp[2] = Read_Byte_From_Buffer(2 + Idx);
			name_comp[3] = Read_Byte_From_Buffer(3 + Idx);
			name_comp[4] = Read_Byte_From_Buffer(4 + Idx);
			name_comp[5] = Read_Byte_From_Buffer(5 + Idx);
			name_comp[6] = Read_Byte_From_Buffer(6 + Idx);
			name_comp[7] = Read_Byte_From_Buffer(7 + Idx);
			name_comp[8] = Read_Byte_From_Buffer(8 + Idx);
			name_comp[9] = Read_Byte_From_Buffer(9 + Idx);
			name_comp[10] = Read_Byte_From_Buffer(10 + Idx);

			if (FCI_COMPARE(%a_mx_name_ext,11,name_comp,11,1) == 0)				//Perform filename comparison
			{
				Temp32.AsByte[0] = Read_Byte_From_Buffer(26 + Idx);							//Read Cluster of folder start
				Temp32.AsByte[1] = Read_Byte_From_Buffer(27 + Idx);
				Temp32.AsByte[2] = 0;
				Temp32.AsByte[3] = 0;

				#if	(%a_FAT_TYPE == 1 || %a_FAT_TYPE == 2)
					if (%a_mx_fat_system == 1)
					{
						Temp32.AsByte[2] = Read_Byte_From_Buffer(20 + Idx);
						Temp32.AsByte[3] = Read_Byte_From_Buffer(21 + Idx);
					}
				#endif

				%a_mx_cluster = Temp32.AsLong;

				if (%a_mx_cluster > 1)
				{
					%a_mx_folder_start[%a_mx_file_idx] = %a_mx_data_start + ((%a_mx_cluster - 2) * %a_mx_sects_per_clust);		//Assign folder start address - BR 06/10 was * 32
					%a_mx_folder_size[%a_mx_file_idx] = %a_mx_sects_per_clust;											//Assign folder size - BR 06/10 was *32											//Assign folder size
				}
				else
				{
					%a_mx_folder_start[%a_mx_file_idx] = %a_mx_root_start;							//Assign root start address to folder start
					%a_mx_folder_size[%a_mx_file_idx] = %a_mx_root_sectors;							//Assign root size to folder size
				}
				return MX_ACK_OK;												//Folder found and moved
			}
		}
		%a_mx_file_pointer[%a_mx_file_idx] = %a_mx_file_pointer[%a_mx_file_idx] + 1;							//Move to next sector of folder
	}
	return MX_ERR_FILENOTFOUND;													//Folder not found

/*Macro_Open_Folder_End*/
}


MX_UINT8 Scan_Current_Folder(MX_SINT16 Current_Idx, MX_UINT8 Scan_Type)
{
/*Macro_Scan_Current_Folder_Start*/

	MX_UINT8 i;
	MX_UINT16 Idx;

	if (Current_Idx < (%a_mx_folder_size[%a_mx_file_idx] * 16))
	{
		%a_mx_file_pointer[%a_mx_file_idx] = %a_mx_folder_start[%a_mx_file_idx];			//Move to start of folder
		while(Current_Idx >= 16)										//While address is not in the current sector
		{
			Current_Idx = Current_Idx - 16;								//Modify address value
			%a_mx_file_pointer[%a_mx_file_idx] = %a_mx_file_pointer[%a_mx_file_idx] + 1;			//Increment sector address
		}

		MX_Get_Buffer(%a_mx_file_pointer[%a_mx_file_idx]);							//Read sector of root directory

		Idx = Current_Idx * 32;

		i = Read_Byte_From_Buffer(Idx);
		if ((i == 0xe5) || (i == 0x00))  								//Deleted or unused entry
			return MX_ACK_FILEEMPTY;									//Address is empty

		if ( Read_Byte_From_Buffer((Idx) + 2) == 0x00)
			return MX_ACK_FILEEMPTY;									//Address is empty

		if(Scan_Type)	//scan for folder
		{
			if (( Read_Byte_From_Buffer(Idx + 11) & 0x10) == 0)			//If a file has been found
				return MX_ACK_FILETYPE;									//Address in use but incorrect data type
		}
		else			//scan for file
		{
			if (( Read_Byte_From_Buffer(Idx + 11) & 0x20) == 0)			//If a folder has been found
				return MX_ACK_FILETYPE;									//Address in use but incorrect data type
		}

		for (i=0;i<11;i++)
			%a_mx_name_ext[i] = Read_Byte_From_Buffer(Idx + i);			//Read string from address

		if(Scan_Type == 0)												//If scanning for a file then rearrange 8.3 filename back into string
		{
			for (i=0;i<7;i++)
			{
				if (%a_mx_name_ext[i] == 0x20)								//If a padding space has been found
					break;
			}
			%a_mx_name_ext[i] = '.';										//Add the '.' seperator to the filename
			%a_mx_name_ext[i + 1] = Read_Byte_From_Buffer(Idx + 8);
			%a_mx_name_ext[i + 2] = Read_Byte_From_Buffer(Idx + 9);
			%a_mx_name_ext[i + 3] = Read_Byte_From_Buffer(Idx + 10);
			for (i=i+4;i<12;i++)
				%a_mx_name_ext[i] = ' ';
		}
		return MX_ACK_OK;												//File/folder found and stored into string array
	}
	return MX_ACK_EOF;													//End of folder reached

/*Macro_Scan_Current_Folder_End*/
}


MX_UINT8 Read_Byte_From_Scan(MX_UINT8 idx)
{
/*Macro_Read_Byte_From_Scan_Start*/

	if(idx > 11)
		return 0;				//String buffer 12 MX_UINT8s long max
	return (%a_mx_name_ext[idx]);	//Return MX_UINT8acter from string

/*Macro_Read_Byte_From_Scan_End*/
}


MX_UINT8 MX_Init_Card()
{
/*Macro_MX_Init_Card_Start*/

	MX_UINT8 RetVal, SD_version;
	MX_SINT16 i;

	%a_SPI_Master_CS(1);	// Chip Select pin is disabled

	//Init SPI
	%a_SPI_Master_Init();							//Call initialise function

	delay_ms(50);														//Wait for card to power up

	for(i = 0; i < 10; i++)												//Start CARD in SPI mode
	{
		%a_SPI_Master_Byte(0xFF);					//Send 10*8=80 clock pulses
	}

	%a_SPI_Master_CS(0);		// Chip Select pin is enabled
	i=0;

	do
	{
		RetVal = MX_Send_Cmd(GO_IDLE_STATE, 0x00000000);					//Command 0 - Goto Idle State - Resets card
		i++;
		if (i > 0x20)
		{
			%a_SPI_Master_CS(1);
			return MX_ERR_NOCARD;
		}

	} while(RetVal != 0x01);

	%a_SPI_Master_CS(1);		// Chip Select pin is disabled

	%a_SPI_Master_Byte(0xFF);
	%a_SPI_Master_Byte(0xFF);

	SD_version = 2;
	i=0;

	do
	{
		RetVal = MX_Send_Cmd(SEND_IF_COND,0x000001AA); //Check power supply status, mendatory for SDHC card
		i++;
		if(i>0xfe)
		{
			  SD_version = 1;
			  %a_mx_card_type = 1;
			  break;
		} //time out

	}while(RetVal != 0x01);

	i=0;

	do
	{
		RetVal = MX_Send_Cmd(APP_CMD, 0x00000000); //CMD55, must be sent before sending any ACMD command
		RetVal = MX_Send_Cmd(SD_SEND_OP_COND, 0x40000000); //ACMD41

		i++;
		if(i>0xfe)
	   	{
			%a_SPI_Master_CS(1);		// Chip Select pin is disabled
		  	return MX_ERR_NORESP;  //time out, card initialization failed
		}

	}while(RetVal != 0x00);

	i = 0;
	%a_mx_sdhc_flag = 0;

	if (SD_version == 2)
	{
	   do
	   {
		 RetVal = MX_Send_Cmd(READ_OCR, 0x00000000);
		 i++;
		 if(i>0xfe)
		 {
		   %a_mx_card_type = 0;
		   break;
		 } //time out

	   }while(RetVal != 0x00);

	   if(%a_mx_sdhc_flag == 1) %a_mx_card_type = 2;
	   else %a_mx_card_type = 3;
	}

	//Need a good way of applying this speed update!!!

	//%a_SPI_Master_Uninit();				//Disable Low Speed
	//%a_FAT.AsByteus_mode = 1;					//SPI Bus Mode	//Check this value
	//%a_SPI_Master_Init ();				//Enable Hi Speed

	%a_SPI_Set_Prescaler(1);

	return MX_ACK_OK;						//Card Ready

/*Macro_MX_Init_Card_End*/
}



MX_UINT8 MX_Get_Buffer(MX_UINT32 address)
{
/*Macro_MX_Get_Buffer_Start*/

	MX_SINT16 idx;
	MX_UINT8 temp;
	MX_UINT16 count;

	if(%a_mx_sdhc_flag == 0)
		address = address << 9;

	MX_Clear_Buffer();

	temp = MX_Send_Cmd(READ_SINGLE_BLOCK, address);

	if (temp != 0)
	{
		%a_SPI_Master_CS(1);			//CARD-Disabled
		%a_SPI_Master_Byte(0xFF);
		return MX_ERR_NOACK;													//Read Not Acknowledged
	}

	%a_SPI_Master_CS(0);			//CARD Enabled

	count = 10000;
	do
	{
		temp = %a_SPI_Master_Byte(0xFF);
	}
	while ((temp != 0xFE) && (count--));			//Wait for data ready

	if (count == 0)
	{
		%a_SPI_Master_CS(1);			//CARD-Disabled
		return MX_ERR_TOUT	;													//Read Timed Out
	}

	for (idx=0; idx < 256; idx++)												//Read Low Buffer
	{
		%a_mx_card_bufferl[idx] = %a_SPI_Master_Byte(0xFF);
	}

	for (idx=0; idx < 256; idx++)												//Read High Buffer
	{
		%a_mx_card_bufferh[idx] = %a_SPI_Master_Byte(0xFF);
	}

	%a_SPI_Master_Byte(0xFF);													//Skip 16-Bit CRC
	%a_SPI_Master_Byte(0xFF);

	%a_SPI_Master_Byte(0xFF);													//Trailing byte

	%a_SPI_Master_CS(1);				// Chip Select pin is disabled
	return MX_ACK_OK;															//Read Complete

/*Macro_MX_Get_Buffer_End*/
}



void MX_Clear_Buffer(void)
{
/*Macro_MX_Clear_Buffer_Start*/

	MX_SINT16 count;

	for (count = 0; count < 256; count++)
	{
		%a_mx_card_bufferh[count] = 0x00;
		%a_mx_card_bufferl[count] = 0x00;
	}

/*Macro_MX_Clear_Buffer_End*/
}


MX_UINT8 MX_Send_Buffer(MX_UINT32 address)
{
/*Macro_MX_Send_Buffer_Start*/

	MX_UINT16 idx;
	MX_UINT8 retval;

	if(%a_mx_sdhc_flag == 0)
		address = address << 9;

	retval = MX_Send_Cmd(WRITE_SINGLE_BLOCK, address);

	if (retval)
	{
		%a_SPI_Master_CS(1);			//CARD-Disabled
		%a_SPI_Master_Byte(0xFF);
		return MX_ERR_NOACK;													//Command not acknowledged
	}

	%a_SPI_Master_CS(0);			//CARD Enable

	%a_SPI_Master_Byte(0xFE);													//Send Start Byte
	for (idx=0; idx < 256; idx++)												//Write Low Buffer
	{
		%a_SPI_Master_Byte(%a_mx_card_bufferl[idx]);
	}
	for (idx=0; idx < 256; idx++)												//Write High Buffer
	{
		%a_SPI_Master_Byte(%a_mx_card_bufferh[idx]);
	}
	%a_SPI_Master_Byte(0xFF);								//Send 2 dummy bytes to skip CRC
	%a_SPI_Master_Byte(0xFF);

	retval = %a_SPI_Master_Byte(0xFF);					//Check if CARD is still busy
	if((retval & 0x1F) != 0x05)
	{
		%a_SPI_Master_CS(1);				// Chip Select pin is disabled
		return MX_ERR_TOUT;					//Read timed out
	}

	//Wait for card to complete writing
	idx = 0;
	while (!%a_SPI_Master_Byte(0xFF))
	{
		if(idx++ > 0xfffe)
		{
			%a_SPI_Master_CS(1);			// Chip Select pin is disabled
			return MX_ERR_TOUT;				//Read timed out
		}
	}

	%a_SPI_Master_CS(1);			//CARD disable
	%a_SPI_Master_Byte(0xFF);
	%a_SPI_Master_CS(0);			//CARD Enable

	//double check that card is no longer busy
	idx = 0;
	while (!%a_SPI_Master_Byte(0xFF))
	{
		if(idx++ > 0xfffe)
		{
			%a_SPI_Master_CS(1);			// Chip Select pin is disabled
			return MX_ERR_TOUT;				//Read timed out
		}
	}

	%a_SPI_Master_CS(1);			//CARD disable

	return MX_ACK_OK;						//Write Complete

/*Macro_MX_Send_Buffer_End*/
}


void MX_Format_File_String(MX_STRING File_Name, MX_UINT8 MSZ_File_Name)
{
/*Macro_MX_Format_File_String_Start*/

	MX_UINT8 	i, j;
	MX_UINT8	filename[12];

	for (i=0;i<11;i++)
	{
		%a_mx_name_ext[i] = 0x20;									//Fill name variable with spaces
	}

	FCI_TOUPPER(File_Name, MSZ_File_Name, (char *) filename, 12);			//convert to uppercase

	for (i=0; i<8; i++)	//Copy file name to comparison variable
	{
		if (filename[i] == '.')
			break;
		if (filename[i] == 0)
			break;

		%a_mx_name_ext[i] = filename[i];
	}

	if(filename[i] == '.')											//Find the '.' seperator
	{
		i++;
		j = i;														//and then shift the extension
		for(i=8;i<11; i++)
		{
			if (filename[j] == 0)
				break;

			%a_mx_name_ext[i] = filename[j];
			j++;
		}
	}

	/*
	//Debug Information
	FCD_LCDDisplay0_Clear();
	FCD_LCDDisplay0_PrintString(filename, 12);
	FCD_LCDDisplay0_Cursor(0,1);
	FCD_LCDDisplay0_PrintString(%a_mx_name_ext, 12);
	delay_s(2); */


/*Macro_MX_Format_File_String_End*/
}



MX_UINT8 Read_Next_File_Sector(void)
{
/*Macro_Read_Next_File_Sector_Start*/

	#if (%a_FAT_TYPE == 0)
		MX_UINT16 temp_mx_cluster;
		MX_UINT16 old_mx_cluster;
	#endif
	#if (%a_FAT_TYPE == 1 || %a_FAT_TYPE == 2)
		MX_UINT32 temp_mx_cluster;
		MX_UINT32 old_mx_cluster;
	#endif

	MX_UINT32 fat_address;
	MX_UINT8 retval;

	MX_Union32 Temp32;

	%a_mx_file_pointer[%a_mx_file_idx] = %a_mx_file_pointer[%a_mx_file_idx] + 1;								//Increment address
	if (((%a_mx_file_pointer[%a_mx_file_idx] - %a_mx_data_start) % %a_mx_sects_per_clust) == 0)		//If end of %a_mx_cluster reached then find next %a_mx_cluster BR 06/10 was % 32
	{
		temp_mx_cluster = %a_mx_cluster;
		fat_address = %a_mx_fat_start;												//Move to start of FAT
		while (temp_mx_cluster >= %a_FATS_PER_SECT)								//256 FAT16 / 128 FAT32 entries per sector
		{
			temp_mx_cluster = temp_mx_cluster - %a_FATS_PER_SECT;
			fat_address = fat_address + 1;										//Increment sector of FAT
		}
		MX_Get_Buffer(fat_address);												//Read FAT sector
		old_mx_cluster = %a_mx_cluster;

		Temp32.AsByte[0] = Read_Byte_From_Buffer(temp_mx_cluster * %a_SECT_ADDR_LEN);	//Extract data %a_mx_cluster address
		Temp32.AsByte[1] = Read_Byte_From_Buffer((temp_mx_cluster * %a_SECT_ADDR_LEN) + 1);
		Temp32.AsByte[2] = 0;
		Temp32.AsByte[3] = 0;

		#if	(%a_FAT_TYPE == 1 || %a_FAT_TYPE == 2)
			if (%a_mx_fat_system == 1)
			{
				Temp32.AsByte[2] = Read_Byte_From_Buffer((temp_mx_cluster * %a_SECT_ADDR_LEN) + 2);
				Temp32.AsByte[3] = Read_Byte_From_Buffer((temp_mx_cluster * %a_SECT_ADDR_LEN) + 3);
			}
		#endif

		%a_mx_cluster = Temp32.AsLong;

		if (%a_mx_cluster == 0 || %a_mx_cluster >= %a_NOT_ADDRESS_MARKER)							//If not an address
		{
			if (%a_mx_cluster > %a_MX_EOF_MARKER)
				retval = MX_ACK_EOF;											//End of file
			if (%a_mx_cluster < %a_MX_EOF_MARKER)
				retval = MX_ERR_RESERVED;										//Reserved %a_mx_cluster
			if (%a_mx_cluster == %a_MX_EOF_MARKER)
				retval = MX_ERR_BAD;											//Bad %a_mx_cluster
			if (%a_mx_cluster == 0)
				retval = MX_ERR_FREE;											//Free %a_mx_cluster - Fat Error

			%a_mx_file_pointer[%a_mx_file_idx] = %a_mx_file_pointer[%a_mx_file_idx] - 1;						//Restore address
			%a_mx_cluster = old_mx_cluster;										//Restore %a_mx_cluster
			MX_Get_Buffer(%a_mx_file_pointer[%a_mx_file_idx]);									//Read sector
			return retval;
		}

		%a_mx_file_pointer[%a_mx_file_idx] = %a_mx_data_start + ((%a_mx_cluster - 2) * %a_mx_sects_per_clust);			//Move to next sector in file   BR 06/10 was * 32
	}

	%a_mx_file_sector[%a_mx_file_idx] = %a_mx_file_sector[%a_mx_file_idx] + 1;										//Increment file sector

	return MX_Get_Buffer(%a_mx_file_pointer[%a_mx_file_idx]);									//Read sector

/*Macro_Read_Next_File_Sector_End*/
}



void MX_Add_Sector_To_File (void)
{
/*Macro_MX_Add_Sector_To_File_Start*/

	MX_UINT32 idx_fat;
	MX_UINT32 fat_address;

	#if (%a_FAT_TYPE == 0)
		MX_UINT16 fat_pointer = 0xFFFF;				//16-bit FAT pointer
	#endif
	#if (%a_FAT_TYPE == 1)
		MX_UINT32 fat_pointer = 0x0FFFFFFF;			//32-bit FAT pointer
	#endif
	#if (%a_FAT_TYPE == 2)
		MX_UINT32 fat_pointer;
		if (%a_mx_fat_system == 1)
			fat_pointer = 0x0FFFFFFF;					//32-bit FAT pointer
		else
			fat_pointer = 0xFFFF;						//16-bit FAT pointer
	#endif

	MX_Union32 Temp32;

	idx_fat = 1;
	fat_address = %a_mx_fat_start;							//Move to start of FAT
	MX_Get_Buffer(fat_address);							//Read FAT sector
	while (fat_pointer > 0)								//Scan FAT for free entry
	{
		idx_fat = (MX_UINT32) idx_fat + 1;					//Increment FAT address - Start at address 2
		if(idx_fat == %a_FATS_PER_SECT)					//If at the end of the FAT sector
		{
			fat_address = fat_address + 1;
			MX_Get_Buffer(fat_address);					//Read next FAT sector
			idx_fat = 0;
		}

		Temp32.AsByte[0] = Read_Byte_From_Buffer(idx_fat * %a_SECT_ADDR_LEN);			//Extract data %a_mx_cluster address
		Temp32.AsByte[1] = Read_Byte_From_Buffer((idx_fat * %a_SECT_ADDR_LEN) + 1);
		Temp32.AsByte[2] = 0;
		Temp32.AsByte[3] = 0;

		#if (%a_FAT_TYPE == 1 || %a_FAT_TYPE == 2)
			if (%a_mx_fat_system == 1)
			{
				Temp32.AsByte[2] = Read_Byte_From_Buffer((idx_fat * %a_SECT_ADDR_LEN) + 2);
				Temp32.AsByte[3] = Read_Byte_From_Buffer((idx_fat * %a_SECT_ADDR_LEN) + 3);
			}
		#endif

		fat_pointer = Temp32.AsLong;
	}

	Write_Byte_To_Buffer((idx_fat * %a_SECT_ADDR_LEN), 0xFF);					//Write end of file marker into new FAT address
	Write_Byte_To_Buffer(((idx_fat * %a_SECT_ADDR_LEN) + 1), 0xFF);

	#if (%a_FAT_TYPE == 1 || %a_FAT_TYPE == 2)
		if (%a_mx_fat_system == 1)
		{
			Write_Byte_To_Buffer(((idx_fat * %a_SECT_ADDR_LEN) + 2), 0xFF);
			Write_Byte_To_Buffer(((idx_fat * %a_SECT_ADDR_LEN) + 3), 0x0F);
		}
	#endif

	MX_Send_Buffer(fat_address);
	MX_Send_Buffer(fat_address + %a_mx_fat_size);				//Mirror data onto FAT 2

	fat_address = ((fat_address - %a_mx_fat_start) * %a_FATS_PER_SECT) + idx_fat;
	idx_fat = %a_mx_cluster;
	%a_mx_cluster = fat_address;								//Store new %a_mx_cluster address

	fat_address = %a_mx_fat_start;
	while (idx_fat >= %a_FATS_PER_SECT)
	{
		idx_fat = idx_fat - %a_FATS_PER_SECT;
		fat_address = fat_address + 1;
	}
	MX_Get_Buffer(fat_address);

	Temp32.AsLong = %a_mx_cluster;

	Write_Byte_To_Buffer((idx_fat * %a_SECT_ADDR_LEN), Temp32.AsByte[0]);				//Update old FAT address
	Write_Byte_To_Buffer(((idx_fat * %a_SECT_ADDR_LEN) + 1), Temp32.AsByte[1]);

	#if (%a_FAT_TYPE == 1 || %a_FAT_TYPE == 2)
		if (%a_mx_fat_system == 1)
		{
			Write_Byte_To_Buffer(((idx_fat * %a_SECT_ADDR_LEN) + 2), Temp32.AsByte[2]);
			Write_Byte_To_Buffer(((idx_fat * %a_SECT_ADDR_LEN) + 3), Temp32.AsByte[3]);
		}
	#endif

	MX_Send_Buffer(fat_address);
	MX_Send_Buffer(fat_address + %a_mx_fat_size);				//Mirror data onto FAT 2

	%a_mx_file_sector[%a_mx_file_idx] = %a_mx_file_sector[%a_mx_file_idx] + 1;					//Increment file sector
	%a_mx_file_pointer[%a_mx_file_idx] = (MX_UINT32) %a_mx_data_start + ((%a_mx_cluster - 2) * %a_mx_sects_per_clust);//Move to next sector in file		BR 06/10 was * 32
	MX_Get_Buffer(%a_mx_file_pointer[%a_mx_file_idx]);

/*Macro_MX_Add_Sector_To_File_End*/
}


MX_UINT8 MX_Send_Cmd(MX_UINT8 Cmd, MX_UINT32 Addr)
{
/*Macro_MX_Send_Cmd_Start*/

	MX_UINT8 i, RetVal;
	MX_Union32 Addr32;

	Addr32.AsLong = Addr;

	%a_SPI_Master_CS(0);		//CARD-Enabled

	%a_SPI_Master_Byte(Cmd | 0x40);										//Send Command 0
	%a_SPI_Master_Byte(Addr32.AsByte[3]);								//Arg3
	%a_SPI_Master_Byte(Addr32.AsByte[2]);								//Arg2
	%a_SPI_Master_Byte(Addr32.AsByte[1]);								//Arg1
	%a_SPI_Master_Byte(Addr32.AsByte[0]);								//Arg0

	if(Cmd == SEND_IF_COND)	 					//it is compulsory to send correct CRC for CMD8 (CRC=0x87) & CMD0 (CRC=0x95)
	  	%a_SPI_Master_Byte(0x87);    			//for remaining commands, CRC is ignored in SPI mode
	else
	  	%a_SPI_Master_Byte(0x95);

	i = 0xfe;
	do
	{
		RetVal = %a_SPI_Master_Byte(0xFF);				//Wait for response of 1
		if (RetVal != 0xff) break;
	} while ( --i > 0);

	if((RetVal == 0x00) && (Cmd == READ_OCR))  	//checking response of CMD58
	{
		i = %a_SPI_Master_Byte(0xFF) & 0x40;    //first byte of the OCR register (bit 31:24)
		if(i == 0x40) %a_mx_sdhc_flag = 1;  		//we need it to verify SDHC card
		else %a_mx_sdhc_flag = 0;

		%a_SPI_Master_Byte(0xFF); 				//remaining 3 bytes of the OCR register are ignored here
		%a_SPI_Master_Byte(0xFF); 				//one can use these bytes to check power supply limits of SD
		%a_SPI_Master_Byte(0xFF);
	}

	%a_SPI_Master_Byte(0xFF);
	%a_SPI_Master_CS(1);		//CARD disabled

	return (RetVal);

/*Macro_MX_Send_Cmd_End*/
}


void Set_File_Index (MX_UINT8 File_Index)
{
/*Macro_Set_File_Index_Start*/

	if (File_Index < %a_CONCURRENT_FILES)
		%a_mx_file_idx = File_Index;

/*Macro_Set_File_Index_End*/
}


//Potential Further Commands
//MX_UINT8 Modify_File_Access_Stats(MX_UINT8 Day, MX_UINT8 Month, MX_SINT16 Year, MX_UINT8 Hours, MX_UINT8 Minutes, MX_UINT8 Seconds)
//MX_UINT8 Erase_Disk(void)
//MX_UINT8 Format_Disk(void)
//MX_UINT8 Rename_File(MX_STRING Filename, MX_STRING New_Filename){}
//MX_UINT8 Move_File(MX_STRING Filename, MX_STRING New_Folder){}
//MX_UINT8 Copy_File(MX_STRING Filename, MX_STRING New_Filename){}
//MX_UINT8 Delete_Current_Folder(){}
//MX_UINT8 Create_Folder(MX_STRING Folder_Name){}
//MX_UINT8 Modify_File_Properties(MX_UINT8 properties){}
//

