/*********************************************************************
 *                    Flowcode FAT16 Component Code
 *
 * File: PIC_FAT16.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
 ********************************************************************/

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

 Return & parameter types:
   void
   char
   short
   char*

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

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

[Settings]
CLSID={5C27C7B5-4BFE-43D8-AED0-E69E625936C7}
IsAnalogue=0
MultipleAllowed=1
Description=FAT16 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]
# char
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]
# char
1=1
2=1
3=1
4=1

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

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

[MacroNames]
Count=22
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_SPI_BYTE
16=MX_Init_Card
17=MX_Send_Buffer
18=MX_Get_Buffer
19=MX_Format_File_String
20=MX_Add_Sector_To_File
21=MX_Clear_Buffer
22=Read_Next_File_Sector

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

[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


[MacroParameters_Init_FAT]
Count=0

[MacroParamTypes_Init_FAT]


[MacroParameters_Open_File]
Count=1
1=File_Name

[MacroParamTypes_Open_File]
1=char*


[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=char


[MacroParameters_Append_String_To_File]
Count=1
1=String

[MacroParamTypes_Append_String_To_File]
1=char*


[MacroParameters_Write_File_Sector]
Count=0

[MacroParamTypes_Write_File_Sector]


[MacroParameters_Create_File]
Count=1
1=File_Name

[MacroParamTypes_Create_File]
1=char*


[MacroParameters_Delete_File]
Count=1
1=File_Name

[MacroParamTypes_Delete_File]
1=char*


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

[MacroParamTypes_Write_Byte_To_Buffer]
1=short
2=char


[MacroParameters_Read_Byte_From_Buffer]
Count=1
1=Address

[MacroParamTypes_Read_Byte_From_Buffer]
1=short


[MacroParameters_Open_Folder]
Count=1
1=Folder_Name

[MacroParamTypes_Open_Folder]
1=char*


[MacroParameters_Delete_File]
Count=1
1=Folder_Name

[MacroParamTypes_Delete_File]
1=char*


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

[MacroParamTypes_Scan_Current_Folder]
1=short
2=char


[MacroParameters_Read_Byte_From_Scan]
Count=1
1=idx

[MacroParamTypes_Read_Byte_From_Scan]
1=char

[MacroParameters_MX_SPI_BYTE]
Count=1
1=shift

[MacroParamTypes_MX_SPI_BYTE]
1=char

[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=char*


[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]

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

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

/*DefinesCode_Start*/

/**** Macro Substitutions ****
%a = Card Port Register
%b = Card Data Direction Register
%c = Chip Selection Pin
%d = Serial Clock
%e = Serial Data In
%f = Serial Data Out
%g = File Creation Time
%h = File Creation Date
%i = FAT System Type - FAT16 Only
%j = Unused
%k = Hardware SPI - 0 software, 1 hardware
******************************/

	//Flowcode Defines
	#define MX_CARD_PORT 			%a
	#define MX_CARD_TRIS 			%b
	#define MX_CARD_CS 				%c
	#define MX_CARD_SCK 			%d
	#define MX_CARD_SDI 			%e
	#define MX_CARD_SDO 			%f
	#define MX_FILE_CREATEDATE		%g
	#define MX_FILE_CREATETIME		%h
	#define MX_FAT_SYST				%i
	#define MX_EXT_NAME				%j
	#define MX_HW_SPI				%k
	#define MX_FAT_TYPE				0//%l		//0-FAT16(FAT) / 1-FAT32 / 2-FAT16&32

	#include <string.h>

	//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

	//Global Variables
	char mx_card_bufferl[256];				//512-Byte Global Buffer Variables
	char mx_card_bufferh[256];
	char mx_name_ext[12];					//11 byte fat file name: 8 char filename + 3 char extension
	char mx_file_entry;						//Directory entry of file
	char mx_sects_per_clust;				//Number of sectors per cluster    - Added BR 06/10
	unsigned int mx_root_sectors = 0;		//Number of sectors in the root directory
	unsigned int mx_fat_size = 0;			//FAT size in sectors
	unsigned long mx_fat_start = 0;			//Start address of FAT tables
	unsigned long mx_root_start = 0;		//Start address of root directory
	unsigned long mx_data_start = 0;		//Start address of the data
	unsigned long mx_file_size = 0;			//Size of file in bytes
	unsigned long mx_file_address = 0; 		//Start address of File
	unsigned long mx_file_sector = 1;		//Current sector of file
	unsigned long mx_folder_size = 0;		//Folder size in sectors
	unsigned long mx_folder_start = 0;		//Start address of Folder
	unsigned long mx_current_address = 0;	//Current address loaded in memory

	#if (MX_FAT_TYPE == 0)
		unsigned int mx_cluster = 2;		//Current data mx_cluster in the memory
		#define SECT_ADDR_LEN			2
		#define FATS_PER_SECT			(512 / 2)	//2 bytes per fat record
		#define NOT_ADDRESS_MARKER		0xFFF0
		#define MX_EOF_MARKER			0xFFF7
	#endif
	#if (MX_FAT_TYPE == 1)
		unsigned long mx_cluster = 2;		//Current data mx_cluster in the memory
		#define mx_fat_system  			1
		#define SECT_ADDR_LEN			4
		#define FATS_PER_SECT			(512 / 4)	//4 bytes per fat record
		#define NOT_ADDRESS_MARKER		0x0FFFFFF0
		#define MX_EOF_MARKER			0x0FFFFFF7
	#endif
	#if (MX_FAT_TYPE == 2)
		unsigned long mx_cluster = 2;		//Current data mx_cluster in the memory
		char mx_fat_system;						//Type of FAT file system in use on disk     - Added BR 07/10
		char SECT_ADDR_LEN;						//Defines become variables
		unsigned int FATS_PER_SECT;
		unsigned long NOT_ADDRESS_MARKER;
		unsigned long MX_EOF_MARKER;
	#endif

/*DefinesCode_End*/

/*InitialisationCode_Start*/

#if (MX_HW_SPI == 0)							//Software Mode

	//Configure Port Pin Data Direction
    clear_bit(MX_CARD_TRIS, MX_CARD_CS);		// CS Enable
    clear_bit(MX_CARD_TRIS, MX_CARD_SCK);		// SCK Output
    set_bit  (MX_CARD_TRIS, MX_CARD_SDI);		// SDI Input
    clear_bit(MX_CARD_TRIS, MX_CARD_SDO);		// SDO Output

	//Configure Port Pin Default Output
	set_bit(MX_CARD_PORT, MX_CARD_SCK);			// Initialise Clock
	set_bit(MX_CARD_PORT, MX_CARD_SDO);			// Initialise Output
	set_bit(MX_CARD_PORT, MX_CARD_SDI);			// Initialise Input
	set_bit(MX_CARD_PORT, MX_CARD_CS);			// Card Disable

#endif

#if (MX_HW_SPI == 1)							//Hardware Mode

	#ifndef MX_SPI
		#ifdef _BOOSTC
			#pragma error "Chip does not have SPI capability"
		#endif
		#ifdef HI_TECH_C
			#error Chip does not have SPI capability
		#endif
	#endif

	#ifdef MX_SPI_B
	    set_bit(trisb,MX_SPI_SDI);				// SDI Input
	    clear_bit(trisb,MX_SPI_SDO);			// SDO Output
	    clear_bit(trisb,MX_SPI_SCK);			// SCK Output
		clear_bit(MX_CARD_TRIS, MX_CARD_CS);	// CS Enable
	    set_bit(MX_CARD_PORT, MX_CARD_CS);		// Card Disable
	#endif

	#ifdef MX_SPI_C
	    set_bit(trisc,MX_SPI_SDI);				// SDI Input
	    clear_bit(trisc,MX_SPI_SDO);			// SDO Output
	    clear_bit(trisc,MX_SPI_SCK);			// SCK Output
	    clear_bit(MX_CARD_TRIS, MX_CARD_CS);	// CS Enable
		set_bit(MX_CARD_PORT, MX_CARD_CS);		// Card Disable
	#endif

	#ifdef MX_SPI_BCB
	    set_bit(trisb,MX_SPI_SDI);				// SDI Input
		clear_bit(trisc,MX_SPI_SDO);			// SDO Output
		clear_bit(trisb,MX_SPI_SCK);			// SCK Output
		clear_bit(MX_CARD_TRIS, MX_CARD_CS);	// CS Enable
		set_bit(MX_CARD_PORT, MX_CARD_CS);		// Card Disable
	#endif

	sspstat = 64;								// Configure SPI Peripheral

	#ifdef _BOOSTC
		#ifdef SSPCON							// SPI Low Speed for Initialise
			sspcon = 2;
			st_bit(sspcon, SSPEN);
		#endif
		#ifdef SSPCON1
			sspcon1 = 2;
			st_bit(sspcon1, SSPEN);
		#endif
	#endif

	#ifdef HI_TECH_C
		#ifdef sspcon							// SPI Low Speed for Initialise
			sspcon = 2;
			st_bit(sspcon, SSPEN);
		#endif
		#ifdef sspcon1
			sspcon1 = 2;
			st_bit(sspcon1, SSPEN);
		#endif
	#endif

#endif

/*InitialisationCode_End*/

/*InterruptCode_Start*/
/*InterruptCode_End*/


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


void Write_Byte_To_Buffer(short Address, char Data)
{
/*Macro_Write_Byte_To_Buffer_Start*/
	if (Address > 255)				//BufferH
	{
		Address = Address - 256;
		mx_card_bufferh[Address] = Data;
	}
	else							//BufferL
	{
		mx_card_bufferl[Address] = Data;
	}
/*Macro_Write_Byte_To_Buffer_End*/
}



char Read_Byte_From_Buffer(short Address)
{
/*Macro_Read_Byte_From_Buffer_Start*/
	if (Address > 255)						//BufferH
	{
		Address = Address - 256;
		return (mx_card_bufferh[Address]);
	}
	else return (mx_card_bufferl[Address]);	//BufferL
/*Macro_Read_Byte_From_Buffer_End*/
}



char Init_FAT (void)
{
/*Macro_Init_FAT_Start*/
	char retval;
	char i, num_fats;
	unsigned int bytes_per_sect = 0;
	unsigned int reserved_sectors;
	unsigned long partition_start = 0;  //Start address of the partition
	unsigned long root_size;			//Number of 32 byte root entries.

	retval = MX_Init_Card();											//Startup Card
	if (retval)
		return(retval);													//Startup error or no card
	retval = MX_Get_Buffer(0);											//Read Master Boot Record if available
	if (retval)
		return(retval);

	while (bytes_per_sect == 0)											//Search for valid partition table
	{
		partition_start = Read_Byte_From_Buffer(0x01C9);								//Read start address of partition
		partition_start = (partition_start << 8) | Read_Byte_From_Buffer(0x01C8);
		partition_start = (partition_start << 8) | Read_Byte_From_Buffer(0x01C7);
		partition_start = (partition_start << 8) | Read_Byte_From_Buffer(0x01C6);

		retval = MX_Get_Buffer(partition_start);										//Read Start of Partition (should also work for disks with no MBR or extended partitions)

		bytes_per_sect = Read_Byte_From_Buffer(0x0B);									//Bytes per sector - normally 512
		bytes_per_sect = bytes_per_sect | ( Read_Byte_From_Buffer(0x0C) << 8);
	}

	if (bytes_per_sect != 512)															//BR Added 06/10 - Confirm that sector is correct size
		return MX_ERR_SECTBYTES;

	mx_sects_per_clust = Read_Byte_From_Buffer(0x0D);									//Read number of sectors per mx_cluster

	reserved_sectors = Read_Byte_From_Buffer(0x0E);										//Number of reserved sectors
	reserved_sectors = reserved_sectors | ( Read_Byte_From_Buffer(0x0F) << 8);

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

	#if (MX_FAT_TYPE == 2)
		if ( Read_Byte_From_Buffer(0x55) == '3')											//Is this a FAT32 card?
		{
			mx_fat_system = 1;
			SECT_ADDR_LEN = 4;
			FATS_PER_SECT = 128;
			NOT_ADDRESS_MARKER = 0x0FFFFFF0;
			MX_EOF_MARKER = 0x0FFFFFF7;
		}
		else
		{
			mx_fat_system = 0;
			SECT_ADDR_LEN = 2;
			FATS_PER_SECT = 256;
			NOT_ADDRESS_MARKER = 0xFFF0;
			MX_EOF_MARKER = 0xFFF7;
		}
	#endif

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

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

		root_size = Read_Byte_From_Buffer(0x11);										//Size of root directory x 32 byte file/directory entries
		root_size = root_size | ( Read_Byte_From_Buffer(0x12) << 8);

		if(root_size == 0)																//if root size not defined here
		{
			root_size = Read_Byte_From_Buffer(0x24);									//Size of root directory x 32 byte file/directory entries
			root_size = root_size | ( Read_Byte_From_Buffer(0x25) << 8);
			root_size = root_size | ((long)  Read_Byte_From_Buffer(0x26) << 16);
			root_size = root_size | ((long)  Read_Byte_From_Buffer(0x27) << 24);
		}
		mx_root_sectors = (root_size * 32) / 512;										//Number of sectors in the root directory
		mx_fat_size = Read_Byte_From_Buffer(0x16);										//FAT size in sectors
		mx_fat_size = mx_fat_size | ( Read_Byte_From_Buffer(0x17) << 8);
		mx_root_start = mx_fat_start + (num_fats * mx_fat_size);						//start of the root directory in sectors
		mx_data_start = mx_root_start + mx_root_sectors;								//start of the data mx_clusters in sectors

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

		mx_root_sectors = mx_sects_per_clust;

		mx_fat_size = Read_Byte_From_Buffer(0x24);											//FAT size in sectors
		mx_fat_size = mx_fat_size | ( Read_Byte_From_Buffer(0x25) << 8);
		mx_fat_size = mx_fat_size | ( Read_Byte_From_Buffer(0x26) << 16);
		mx_fat_size = mx_fat_size | ( Read_Byte_From_Buffer(0x27) << 24);

		root_size = Read_Byte_From_Buffer(0x2C);										//first cluster address of root directory
		root_size = root_size | ( Read_Byte_From_Buffer(0x2D) << 8);
		root_size = root_size | ((long)  Read_Byte_From_Buffer(0x2E) << 16);
		root_size = root_size | ((long)  Read_Byte_From_Buffer(0x2F) << 24);

		mx_data_start = mx_fat_start + (num_fats * mx_fat_size);						//start of the root directory in sectors
		mx_root_start = mx_data_start + ((root_size - 2) * mx_sects_per_clust);			//Move to sector containing start of file

	#endif
	#if (MX_FAT_TYPE == 2)
		if (mx_fat_system == 0)																//FAT32 uses normal folder cluster for root
		{
			root_size = Read_Byte_From_Buffer(0x11);										//Size of root directory x 32 byte file/directory entries
			root_size = root_size | ( Read_Byte_From_Buffer(0x12) << 8);

			if(root_size == 0)																//if root size not defined here
			{
				root_size = Read_Byte_From_Buffer(0x24);									//Size of root directory x 32 byte file/directory entries
				root_size = root_size | ( Read_Byte_From_Buffer(0x25) << 8);
				root_size = root_size | ((long)  Read_Byte_From_Buffer(0x26) << 16);
				root_size = root_size | ((long)  Read_Byte_From_Buffer(0x27) << 24);
			}
			mx_root_sectors = (root_size * 32) / 512;										//Number of sectors in the root directory
			mx_fat_size = Read_Byte_From_Buffer(0x16);										//FAT size in sectors
			mx_fat_size = mx_fat_size | ( Read_Byte_From_Buffer(0x17) << 8);
			mx_root_start = mx_fat_start + (num_fats * mx_fat_size);						//start of the root directory in sectors
			mx_data_start = mx_root_start + mx_root_sectors;								//start of the data mx_clusters in sectors

		}
		if (mx_fat_system == 1)																//FAT32 uses normal folder cluster for root
		{
			mx_root_sectors = mx_sects_per_clust;

			mx_fat_size = Read_Byte_From_Buffer(0x24);											//FAT size in sectors
			mx_fat_size = mx_fat_size | ( Read_Byte_From_Buffer(0x25) << 8);
			mx_fat_size = mx_fat_size | ( Read_Byte_From_Buffer(0x26) << 16);
			mx_fat_size = mx_fat_size | ( Read_Byte_From_Buffer(0x27) << 24);

			root_size = Read_Byte_From_Buffer(0x2C);										//first cluster address of root directory
			root_size = root_size | ( Read_Byte_From_Buffer(0x2D) << 8);
			root_size = root_size | ((long)  Read_Byte_From_Buffer(0x2E) << 16);
			root_size = root_size | ((long)  Read_Byte_From_Buffer(0x2F) << 24);

			mx_data_start = mx_fat_start + (num_fats * mx_fat_size);						//start of the root directory in sectors
			mx_root_start = mx_data_start + ((root_size - 2) * mx_sects_per_clust);			//Move to sector containing start of file
		}
	#endif

	mx_folder_size = mx_root_sectors;
	mx_folder_start = mx_root_start;

	return retval;
/*Macro_Init_FAT_End*/
}



char Open_File (char* File_Name)
{
/*Macro_Open_File_Start*/

	char i;
	char name_comp[11];
	char address[4];
	int idx_fat;
	unsigned int scount;
	#if (MX_FAT_TYPE == 0)
		unsigned int fat_pointer = 0xFFFF;
	#endif
	#if (MX_FAT_TYPE == 1)
		unsigned long fat_pointer = 0x0FFFFFFF;
	#endif
	#if (MX_FAT_TYPE == 2)
		unsigned long fat_pointer;
		if (mx_fat_system == 0)
			fat_pointer = 0xFFFF;
		else fat_pointer = 0x0FFFFFFF;
	#endif
	unsigned long fat_address;

	MX_Format_File_String(File_Name, MSZ_File_Name);							//Convert filename to 8.3 format
	scount = 0;
	mx_current_address = mx_folder_start;										//Move to start of root
	while (scount < mx_folder_size)
	{
		MX_Get_Buffer(mx_current_address);										//Read sector of root directory
		for(i=0;i<16;i++)														//16 file or directory references per sector
		{
			name_comp[0] = Read_Byte_From_Buffer(0 + (i*32));					//Move DOS 8.3 Filename into 2nd comparison buffer
			name_comp[1] = Read_Byte_From_Buffer(1 + (i*32));
			name_comp[2] = Read_Byte_From_Buffer(2 + (i*32));
			name_comp[3] = Read_Byte_From_Buffer(3 + (i*32));
			name_comp[4] = Read_Byte_From_Buffer(4 + (i*32));
			name_comp[5] = Read_Byte_From_Buffer(5 + (i*32));
			name_comp[6] = Read_Byte_From_Buffer(6 + (i*32));
			name_comp[7] = Read_Byte_From_Buffer(7 + (i*32));
			name_comp[8] = Read_Byte_From_Buffer(8 + (i*32));
			name_comp[9] = Read_Byte_From_Buffer(9 + (i*32));
			name_comp[10] = Read_Byte_From_Buffer(10 + (i*32));

			if (FCI_COMPARE(mx_name_ext,11,name_comp,11,1) == 0)				//Perform filename comparison
			{
				mx_file_entry = i;												//Store file address
				mx_file_address = mx_current_address;
				mx_file_sector = 1;

				mx_cluster = Read_Byte_From_Buffer(26 + (i*32));									//Read Cluster of data start
				mx_cluster = mx_cluster | ( Read_Byte_From_Buffer(27 + (i*32)) << 8);
				#if (MX_FAT_TYPE == 1 || MX_FAT_TYPE == 2)
					if(mx_fat_system == 1)
					{
						mx_cluster = mx_cluster | ( (long) Read_Byte_From_Buffer(20 + (i*32)) << 16);
						mx_cluster = mx_cluster | ( (long) Read_Byte_From_Buffer(21 + (i*32)) << 24);
					}
				#endif

				mx_file_size = Read_Byte_From_Buffer(28 + (i*32));									//Read Filesize in bytes
				mx_file_size = mx_file_size | ( Read_Byte_From_Buffer(29 + (i*32)) << 8);
				mx_file_size = mx_file_size | ( (long) Read_Byte_From_Buffer(30 + (i*32)) << 16);
				mx_file_size = mx_file_size | ( (long) Read_Byte_From_Buffer(31 + (i*32)) << 24);

				if (mx_cluster == 0)																//Empty File - Assign a free mx_cluster
				{
					idx_fat = 1;
					fat_address = 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 == 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;
						}
						fat_pointer = Read_Byte_From_Buffer(idx_fat * SECT_ADDR_LEN);			//Extract data mx_cluster address
						fat_pointer = fat_pointer | ( Read_Byte_From_Buffer((idx_fat * SECT_ADDR_LEN) + 1) << 8);

						#if (MX_FAT_TYPE == 1 || MX_FAT_TYPE == 2)
							if(mx_fat_system == 1)
							{
								fat_pointer = fat_pointer | ((long) Read_Byte_From_Buffer((idx_fat * SECT_ADDR_LEN) + 2) << 16);
								fat_pointer = fat_pointer | ((long) Read_Byte_From_Buffer((idx_fat * SECT_ADDR_LEN) + 3) << 24);
							}
						#endif

					}

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

					MX_Get_Buffer(mx_current_address);												//Read sector of root directory containing file
					fat_address = ((fat_address - mx_fat_start) * FATS_PER_SECT) + idx_fat;
					mx_cluster = fat_address;
					Write_Byte_To_Buffer(26 + (i*32), mx_cluster);									//Write new mx_cluster value
					Write_Byte_To_Buffer(27 + (i*32), (mx_cluster >> 8));
					#if (MX_FAT_TYPE == 1 || MX_FAT_TYPE == 2)
						if(mx_fat_system == 1)
						{
							Write_Byte_To_Buffer(20 + (i*32), ((long) mx_cluster >> 16));
							Write_Byte_To_Buffer(21 + (i*32), ((long) mx_cluster >> 24));
						}
					#endif
					MX_Send_Buffer(mx_current_address);												//Write mx_cluster location to card
				}

				mx_current_address = mx_data_start + ((mx_cluster - 2) * mx_sects_per_clust);		//Move to sector containing start of file   - BR 06/10 was *32
				MX_Get_Buffer(mx_current_address);													//Read sector
				return MX_ACK_OK;
			}
		}
		mx_current_address = mx_current_address + 1;
		scount = scount + 1;																		//Move to next sector of folder
	}
	return MX_ERR_FILENOTFOUND;																		//File not found
/*Macro_Open_File_End*/
}


short Read_File_Length(void)
{
/*Macro_Read_File_Length_Start*/
	long temp;
	temp = mx_file_sector << 9;
	if (temp <= mx_file_size)					//If file size greater then sector limit
		return 512;								//Return Sector Full

	temp = mx_file_size % 512;
	return (temp);								//Return index of next available byte
/*Macro_Read_File_Length_End*/
}


char Read_File_Sector (void)
{
/*Macro_Read_File_Sector_Start*/
	return MX_Get_Buffer(mx_current_address);		//Read sector
/*Macro_Read_File_Sector_End*/
}



char Move_To_Next_File_Sector(char Force_Next_Sector)
{
/*Macro_Move_To_Next_File_Sector_Start*/
	char 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
		//mx_file_sector = mx_file_sector + 1;		//Increment file sector
		return MX_ACK_OK;
	}
	return retval;
/*Macro_Move_To_Next_File_Sector_End*/
}



char Append_String_To_File(char* String, char MSZ_String)
{
/*Macro_Append_String_To_File_Start*/
	char idx;

	//unsigned int fat_pointer = 0xFFFF;		//BR Unused Variable

	short length;
	char retval;
	char offset = 0;

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

	length = Read_File_Length();				//Get next empty character position
	while (length == 512)						//While characters 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 character in string
	{
		if((length + idx) == 512)				//if string extends onto another sector
		{
			length = 0;
			offset = idx;

			MX_Send_Buffer(mx_current_address);			//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 character from string into buffer
	}

	MX_Send_Buffer(mx_current_address);								//Write string data in current sector to card
	mx_file_size = mx_file_size + MSZ_String;								//Update file length
	MX_Get_Buffer(mx_file_address);									//Read file address
	Write_Byte_To_Buffer((28 + (mx_file_entry * 32)), mx_file_size);				//Update file length in buffer
	Write_Byte_To_Buffer((29 + (mx_file_entry * 32)), mx_file_size >> 8);
	Write_Byte_To_Buffer((30 + (mx_file_entry * 32)), mx_file_size >> 16);
	Write_Byte_To_Buffer((31 + (mx_file_entry * 32)), mx_file_size >> 24);
	MX_Send_Buffer(mx_file_address);									//Update file length on card
	MX_Send_Buffer(mx_file_address + mx_fat_size);						//Mirror data onto FAT 2
	MX_Get_Buffer(mx_current_address);									//Read current sector
	return MX_ACK_OK;														//String appended to file
/*Macro_Append_String_To_File_End*/
}



char Write_File_Sector (void)
{
/*Macro_Write_File_Sector_Start*/
	if ((mx_file_size >> 9) == (mx_file_sector - 1))	//Is this the last sector of the file
		mx_file_size = (mx_file_size + (512 - Read_File_Length()));

	MX_Send_Buffer(mx_current_address);								//Write string data in current sector to card
	MX_Get_Buffer(mx_file_address);									//Read file address
	Write_Byte_To_Buffer((28 + (mx_file_entry * 32)), mx_file_size);				//Update file length in buffer
	Write_Byte_To_Buffer((29 + (mx_file_entry * 32)), mx_file_size >> 8);
	Write_Byte_To_Buffer((30 + (mx_file_entry * 32)), mx_file_size >> 16);
	Write_Byte_To_Buffer((31 + (mx_file_entry * 32)), mx_file_size >> 24);
	MX_Send_Buffer(mx_file_address);									//Update file length on card
	MX_Send_Buffer(mx_file_address + mx_fat_size);						//Mirror data onto FAT 2
	MX_Get_Buffer(mx_current_address);									//Read current sector

	return MX_ACK_OK;
/*Macro_Write_File_Sector_End*/
}



char Create_File(char* File_Name)
{
/*Macro_Create_File_Start*/
	char i, j;

	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
	mx_current_address = mx_folder_start;								//Move to start of root
	while (mx_current_address < (mx_folder_start + mx_folder_size))
	{
		MX_Get_Buffer(mx_current_address);								//Read sector of root directory
		for(i=0;i<16;i++)											//16 file or directory references per sector
		{
			if (( Read_Byte_From_Buffer(i * 32) == 0xe5) || ( Read_Byte_From_Buffer(i * 32) == 0x00))		//Deleted or unused entry
			{
				for (j=0;j<11;j++)
				{
					Write_Byte_To_Buffer((i * 32) + j, mx_name_ext[j]);
				}
				Write_Byte_To_Buffer((i * 32) + 11, 0x20);						//File Attribute
				Write_Byte_To_Buffer((i * 32) + 12, 0x18);						//Reserved for NT
				Write_Byte_To_Buffer((i * 32) + 13, 0);							//Creation time
				Write_Byte_To_Buffer((i * 32) + 14, MX_FILE_CREATETIME);
				Write_Byte_To_Buffer((i * 32) + 15, MX_FILE_CREATETIME >> 8);
				Write_Byte_To_Buffer((i * 32) + 16, MX_FILE_CREATEDATE);		//Creation date
				Write_Byte_To_Buffer((i * 32) + 17, MX_FILE_CREATEDATE >> 8);
				Write_Byte_To_Buffer((i * 32) + 18, MX_FILE_CREATEDATE);		//Access date
				Write_Byte_To_Buffer((i * 32) + 19, MX_FILE_CREATEDATE >> 8);
				Write_Byte_To_Buffer((i * 32) + 20, 0x00);
				Write_Byte_To_Buffer((i * 32) + 21, 0x00);
				Write_Byte_To_Buffer((i * 32) + 22, MX_FILE_CREATETIME);		//Modified time 0 no modification entry
				Write_Byte_To_Buffer((i * 32) + 23, MX_FILE_CREATETIME >> 8);
				Write_Byte_To_Buffer((i * 32) + 24, MX_FILE_CREATEDATE);		//Modified date
				Write_Byte_To_Buffer((i * 32) + 25, MX_FILE_CREATEDATE >> 8);

				for (j=26;j<32;j++)												//Sector location and length
				{
					Write_Byte_To_Buffer((i * 32) + j, 0);
				}
				MX_Send_Buffer(mx_current_address);
				return MX_ACK_OK;												//File created
			}
		}
		mx_current_address = mx_current_address + 1;
	}
	return MX_ERR_ROOTFULL;														//No space left in root directory
/*Macro_Create_File_End*/
}



char Delete_File(char* File_Name)
{
/*Macro_Delete_File_Start*/
	unsigned int scount;
	char name_comp[11];
	unsigned long fat_address;
	char i;

	#if (MX_FAT_TYPE == 0)
		unsigned int temp_mx_cluster;
	#endif
	#if (MX_FAT_TYPE == 1 || MX_FAT_TYPE == 2)
		unsigned long temp_mx_cluster;
	#endif

	MX_Format_File_String(File_Name, MSZ_File_Name);						//Convert filename to 8.3 format
	scount = 0;
	mx_current_address = mx_folder_start;									//Move to start of root
	while (scount <= mx_folder_size)
	{
		MX_Get_Buffer(mx_current_address);									//Read sector of root directory
		for(i=0;i<16;i++)													//16 file or directory references per sector
		{
			name_comp[0] = Read_Byte_From_Buffer(0 + (i*32));							//Move DOS 8.3 Filename into 2nd comparison buffer
			name_comp[1] = Read_Byte_From_Buffer(1 + (i*32));
			name_comp[2] = Read_Byte_From_Buffer(2 + (i*32));
			name_comp[3] = Read_Byte_From_Buffer(3 + (i*32));
			name_comp[4] = Read_Byte_From_Buffer(4 + (i*32));
			name_comp[5] = Read_Byte_From_Buffer(5 + (i*32));
			name_comp[6] = Read_Byte_From_Buffer(6 + (i*32));
			name_comp[7] = Read_Byte_From_Buffer(7 + (i*32));
			name_comp[8] = Read_Byte_From_Buffer(8 + (i*32));
			name_comp[9] = Read_Byte_From_Buffer(9 + (i*32));
			name_comp[10] = Read_Byte_From_Buffer(10 + (i*32));

			if (FCI_COMPARE(mx_name_ext,11,name_comp,11,1) == 0)			//Perform filename comparison
			{
				mx_cluster = Read_Byte_From_Buffer(26 + (i*32));						//Read Cluster of data start
				mx_cluster = mx_cluster | ( Read_Byte_From_Buffer(27 + (i*32)) << 8);
				Write_Byte_To_Buffer(26 + (i*32), 0);								//Overwrite mx_cluster value
				Write_Byte_To_Buffer(27 + (i*32), 0);
				#if(MX_FAT_TYPE == 1 || MX_FAT_TYPE == 2)
					if (mx_fat_system == 1)
					{
						Write_Byte_To_Buffer(20 + (i*32), 0);
						Write_Byte_To_Buffer(21 + (i*32), 0);
					}
				#endif

				Write_Byte_To_Buffer(28 + (i*32), 0);								//Clear file size
				Write_Byte_To_Buffer(29 + (i*32), 0);
				Write_Byte_To_Buffer(30 + (i*32), 0);
				Write_Byte_To_Buffer(31 + (i*32), 0);
				Write_Byte_To_Buffer(0 + (i*32), 0xe5);								//Set first byte to free file flag
				MX_Send_Buffer(mx_current_address);							//Write the free file flag to the card

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

					fat_address = mx_fat_start;								//Move to start of FAT
					while(mx_cluster >= FATS_PER_SECT)
					{
						fat_address = fat_address + 1;						//Move to next sector of FAT
						mx_cluster = mx_cluster - FATS_PER_SECT;
					}
					MX_Get_Buffer(fat_address);								//Read FAT sector

					temp_mx_cluster = mx_cluster;
					mx_cluster = Read_Byte_From_Buffer(temp_mx_cluster * FATS_PER_SECT);			//Read next mx_cluster value
					mx_cluster = mx_cluster | ( Read_Byte_From_Buffer((temp_mx_cluster * FATS_PER_SECT) + 1) << 8);

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

					MX_Send_Buffer(fat_address);
					MX_Send_Buffer(fat_address + mx_fat_size);				//Mirror data onto FAT 2
				}
				return 0;													//File deleted correctly
			}
		}
		scount = scount + 1;
		mx_current_address = mx_current_address + 1;
	}
	return MX_ERR_FILENOTFOUND;												//File not found
/*Macro_Delete_File_End*/
}



char Open_Folder(char* Folder_Name)
{
/*Macro_Open_Folder_Start*/

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

	char i;
	unsigned int scount;
	char name_comp[11];

	//Root Directory
	if (Folder_Name[0] == 'r' && Folder_Name[1] == 'o' && Folder_Name[2] == 'o' && Folder_Name[3] == 't')
	{
		mx_folder_start = mx_root_start;		//Assign root start address to folder start
		mx_folder_size = mx_root_sectors;		//Assign root size to folder size
		return (0);								//Root Directory Specified
	}

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

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

	scount = 0;
	mx_current_address = mx_folder_start;										//Move to start of folder
	while (scount < mx_folder_size)
	{
		MX_Get_Buffer(mx_current_address);										//Read sector of root directory
		for(i=0;i<16;i++)														//16 file or directory references per sector
		{
			name_comp[0] = Read_Byte_From_Buffer(0 + (i*32));					//Move DOS 8.3 Filename into 2nd comparison buffer
			name_comp[1] = Read_Byte_From_Buffer(1 + (i*32));
			name_comp[2] = Read_Byte_From_Buffer(2 + (i*32));
			name_comp[3] = Read_Byte_From_Buffer(3 + (i*32));
			name_comp[4] = Read_Byte_From_Buffer(4 + (i*32));
			name_comp[5] = Read_Byte_From_Buffer(5 + (i*32));
			name_comp[6] = Read_Byte_From_Buffer(6 + (i*32));
			name_comp[7] = Read_Byte_From_Buffer(7 + (i*32));
			name_comp[8] = Read_Byte_From_Buffer(8 + (i*32));
			name_comp[9] = Read_Byte_From_Buffer(9 + (i*32));
			name_comp[10] = Read_Byte_From_Buffer(10 + (i*32));

			if (FCI_COMPARE(mx_name_ext,11,name_comp,11,1) == 0)				//Perform filename comparison
			{
				mx_cluster = Read_Byte_From_Buffer(26 + (i*32));							//Read Cluster of folder start
				mx_cluster = mx_cluster | ( Read_Byte_From_Buffer(27 + (i*32)) << 8);
				#if	(MX_FAT_TYPE == 1 || MX_FAT_TYPE == 2)
					if (mx_fat_system == 1)
					{
						mx_cluster = mx_cluster | ( Read_Byte_From_Buffer(20 + (i*32)) << 16);
						mx_cluster = mx_cluster | ( Read_Byte_From_Buffer(21 + (i*32)) << 24);
					}
				#endif

				if (mx_cluster > 1)
				{
					mx_folder_start = mx_data_start + ((mx_cluster - 2) * mx_sects_per_clust);		//Assign folder start address - BR 06/10 was * 32
					mx_folder_size = mx_sects_per_clust;											//Assign folder size - BR 06/10 was *32											//Assign folder size
				}
				else
				{
					mx_folder_start = mx_root_start;							//Assign root start address to folder start
					mx_folder_size = mx_root_sectors;							//Assign root size to folder size
				}
				return MX_ACK_OK;												//Folder found and moved
			}
		}
		mx_current_address = mx_current_address + 1;
		scount = scount + 1;													//Move to next sector of folder
	}
	return MX_ERR_FILENOTFOUND;													//Folder not found
/*Macro_Open_Folder_End*/
}


char Scan_Current_Folder(short Current_Idx, char Scan_Type)
{
/*Macro_Scan_Current_Folder_Start*/
	char i;

	if (Current_Idx < (mx_folder_size * 16))
	{
		mx_current_address = mx_folder_start;							//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
			mx_current_address = mx_current_address + 1;				//Increment sector address
		}

		MX_Get_Buffer(mx_current_address);								//Read sector of root directory

		if (( Read_Byte_From_Buffer(Current_Idx  * 32) == 0xe5) || ( Read_Byte_From_Buffer(Current_Idx  * 32) == 0x00) || ( Read_Byte_From_Buffer((Current_Idx * 32) + 2) == 0x00))		//Deleted or unused entry
			return MX_ACK_FILEEMPTY;									//Address is empty

		if(Scan_Type)	//scan for folder
		{
			if (( Read_Byte_From_Buffer((Current_Idx  * 32) + 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((Current_Idx  * 32) + 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++)
			mx_name_ext[i] = Read_Byte_From_Buffer((Current_Idx * 32) + 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 (mx_name_ext[i] == 0x20)								//If a padding space has been found
					break;
			}
			mx_name_ext[i] = '.';										//Add the '.' seperator to the filename
			mx_name_ext[i + 1] = Read_Byte_From_Buffer((Current_Idx * 32) + 8);
			mx_name_ext[i + 2] = Read_Byte_From_Buffer((Current_Idx * 32) + 9);
			mx_name_ext[i + 3] = Read_Byte_From_Buffer((Current_Idx * 32) + 10);
			for (i=i+4;i<12;i++)
				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*/
}


char Read_Byte_From_Scan(char idx)
{
/*Macro_Read_Byte_From_Scan_Start*/
	if(idx > 11)
		return 0;				//String buffer 12 chars long max
	return (mx_name_ext[idx]);	//Return character from string
/*Macro_Read_Byte_From_Scan_End*/
}



//Private Functon Definitions
char MX_SPI_BYTE(char shift)							// send character over SPI
{
/*Macro_MX_SPI_BYTE_Start*/

	#if (MX_HW_SPI == 0)								//Software Mode

		char idx;
		for (idx = 0; idx < 8; idx++)
		{
			if (test_bit(shift, 7))
				set_bit(MX_CARD_PORT, MX_CARD_SDO);		// Set SDO bit
			else
				clear_bit(MX_CARD_PORT, MX_CARD_SDO);	// Clear SDO bit

			shift = shift << 1;

			set_bit(MX_CARD_PORT, MX_CARD_SCK);			// SCK Output 1

			delay_us(1);	//Added BR 06/10

			if(test_bit(MX_CARD_PORT, MX_CARD_SDI))
				shift = shift | 0x01;
			else
				shift = shift & 0xFE;

			clear_bit(MX_CARD_PORT, MX_CARD_SCK);		// SCK Output 0
		}
		return shift;

	#endif

	#if (MX_HW_SPI == 1)								//Hardware Mode

		#ifndef MX_SPI
			#ifdef _BOOSTC
				#pragma error "Chip does not have SPI capability"
			#endif
			#ifdef HI_TECH_C
				#error Chip does not have SPI capability
			#endif
		#endif

		sspbuf = shift;									//write the Char
		while ((sspstat & 0x01) == 0);					//wait until sspbuf is empty
		shift = sspbuf;									//receive the Char
		return shift;

	#endif

/*Macro_MX_SPI_BYTE_End*/
}



char MX_Init_Card()
{
/*Macro_MX_Init_Card_Start*/
	char RetVal;
	short i;

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

	set_bit(MX_CARD_PORT, MX_CARD_CS);		//CARD-Disabled
	for(i = 0; i < 10; i++)					//Start CARD in SPI mode
	{
		MX_SPI_BYTE(0xFF);							//Send 10*8=80 clock pulses
	}
	clear_bit(MX_CARD_PORT, MX_CARD_CS);	//CARD-Enabled
	delay_us(50);							//Wait 50us

	//Command 0 - Goto Idle State - Resets card
	MX_SPI_BYTE(0x40);						//Send Command 0
	MX_SPI_BYTE(0x00);						//Arg3
	MX_SPI_BYTE(0x00);						//Arg2
	MX_SPI_BYTE(0x00);						//Arg1
	MX_SPI_BYTE(0x00);						//Arg0
	MX_SPI_BYTE(0x95);						//CRC
	MX_SPI_BYTE(0xFF);
	RetVal = MX_SPI_BYTE(0xFF);				//Wait for response of 1
	if (RetVal != 1)
		return MX_ERR_NOCARD;				//Card not initialising or not present

	set_bit(MX_CARD_PORT, MX_CARD_CS);		//CARD-Disabled
	delay_us(50);							//Wait 50us
	clear_bit(MX_CARD_PORT, MX_CARD_CS);	//CARD-Enabled - Command 0 complete

	//Command 1 - Send Operating Condition - Reports the status of the card
	i = 512;
	while ((RetVal != 0) && (i))			//Loop while processing command 1
	{
		i = i - 1;
		set_bit(MX_CARD_PORT, MX_CARD_CS);	//CARD-Disabled
		MX_SPI_BYTE(0xFF);
		MX_SPI_BYTE(0xFF);
		clear_bit(MX_CARD_PORT, MX_CARD_CS);//CARD-Enabled - Command 0 complete
		MX_SPI_BYTE(0x41);					//Send Command 1
		MX_SPI_BYTE(0x00);					//Arg3
		MX_SPI_BYTE(0x00);					//Arg2
		MX_SPI_BYTE(0x00);					//Arg1
		MX_SPI_BYTE(0x00);					//Arg0
		MX_SPI_BYTE(0xFF);					//CRC
		MX_SPI_BYTE(0xFF);
		RetVal = MX_SPI_BYTE(0xFF);			//Check Response
	}
	set_bit(MX_CARD_PORT, MX_CARD_CS);		//CARD-Disabled
	if (i == 0)
		return MX_ERR_NORESP;				//Card not responding

	#if (MX_HW_SPI == 1)					//Hardware Mode only
		#ifdef _BOOSTC
			#ifdef SSPCON							// SPI Low Speed for Initialise
				sspcon = 0;
				st_bit(sspcon, SSPEN);
			#endif
			#ifdef SSPCON1
				sspcon1 = 0;
				st_bit(sspcon1, SSPEN);
			#endif
		#endif

		#ifdef HI_TECH_C
			#ifdef sspcon							// SPI Low Speed for Initialise
				sspcon = 0;
				st_bit(sspcon, SSPEN);
			#endif
			#ifdef sspcon1
				sspcon1 = 0;
				st_bit(sspcon1, SSPEN);
			#endif
		#endif
	#endif

	return MX_ACK_OK;						//Card Ready
/*Macro_MX_Init_Card_End*/
}



char MX_Get_Buffer(long address)
{
/*Macro_MX_Get_Buffer_Start*/
	short idx;
	int CRC;
	char temp;
	unsigned int count;

	address = address << 9;

	MX_Clear_Buffer();
	clear_bit(MX_CARD_PORT, MX_CARD_CS);		//CARD-Enabled

	MX_SPI_BYTE(0xFF);							//Send Dummy Byte
	MX_SPI_BYTE(0x51);							//Send Read Command
	MX_SPI_BYTE(((long) address >> 24) & 0xFF);		//Send MSB Of Address
	MX_SPI_BYTE(((long) address >> 16) & 0xFF);
	MX_SPI_BYTE((address >> 8) & 0xFF);
	MX_SPI_BYTE(address & 0xFF);				//Send LSB Of Address
	MX_SPI_BYTE(0xFF);							//CRC unused

	temp = 0xFF;
	count = 10;
	while((temp == 0xFF) && count)
	{
		temp = MX_SPI_BYTE(0xFF);				//Wait for response
		count = count - 1;
	}
	if (count == 0)
	{
		set_bit(MX_CARD_PORT, MX_CARD_CS);			//CARD-Disabled
		return MX_ERR_NOACK;					//Read Not Acknowledged
	}

	temp = 0;
	count = 65000;
	while ((temp != 0xFE) && count)			//Wait for data ready
	{
		temp = MX_SPI_BYTE(0xFF);
		delay_us(10);
		count = count - 1;
	}
	if (count == 0)
		return MX_ERR_TOUT	;					//Read Timed Out

	for (idx=0; idx < 256; idx++)				//Read Low Buffer
	{
		mx_card_bufferl[idx] = MX_SPI_BYTE(0xFF);
	}

	for (idx=0; idx < 256; idx++)				//Read High Buffer
	{
		mx_card_bufferh[idx] = MX_SPI_BYTE(0xFF);
	}

	CRC = MX_SPI_BYTE(0xFF);					//Read 16-Bit CRC
	CRC = CRC << 8;
	CRC = CRC | MX_SPI_BYTE(0xFF);

	set_bit(MX_CARD_PORT, MX_CARD_CS);			//CARD-Disabled
	MX_SPI_BYTE(0xFF);							//Trailing byte
	return MX_ACK_OK;							//Read Complete
/*Macro_MX_Get_Buffer_End*/
}



void MX_Clear_Buffer(void)
{
/*Macro_MX_Clear_Buffer_Start*/
	short count;

	for (count = 0; count < 256; count++)
	{
		mx_card_bufferh[count] = 0x00;
		mx_card_bufferl[count] = 0x00;
	}
/*Macro_MX_Clear_Buffer_End*/
}


char MX_Send_Buffer(long address)
{
/*Macro_MX_Send_Buffer_Start*/
	int idx;
	char retval;

	address = address << 9;

	set_bit(MX_CARD_PORT, MX_CARD_CS);		//CARD-Disabled
	MX_SPI_BYTE(0xFF); 						//Padd Command
	clear_bit(MX_CARD_PORT, MX_CARD_CS);	//CARD-Enabled
	MX_SPI_BYTE(0x58);  					//Send command
	MX_SPI_BYTE(((long) address >> 24) & 0xFF);	//Send MSB Of Address
	MX_SPI_BYTE(((long) address >> 16) & 0xFF);
	MX_SPI_BYTE((address >> 8) & 0xFF);
	MX_SPI_BYTE(address & 0xFF);			//Send LSB Of Address
	MX_SPI_BYTE(0xFF);  					//Skip CRC Check
	idx = 1024;
	retval = MX_SPI_BYTE(0xFF);
	while ((retval == 0xFF) && idx)
	{
		retval = MX_SPI_BYTE(0xFF);  		//Wait for card
		idx = idx - 1;
	}
	if (idx == 0)
	{
		set_bit(MX_CARD_PORT, MX_CARD_CS);	//CARD-Disabled
		return MX_ERR_NOACK;				//Command not acknowledged
	}

	MX_SPI_BYTE(0xFE);						//Send Start Byte
	for (idx=0; idx < 256; idx++)			//Write Low Buffer
	{
		MX_SPI_BYTE(mx_card_bufferl[idx]);
	}
	for (idx=0; idx < 256; idx++)			//Write High Buffer
	{
		MX_SPI_BYTE(mx_card_bufferh[idx]);
	}
	MX_SPI_BYTE(0xFF);								//Send 2 dummy bytes to skip CRC
	MX_SPI_BYTE(0xFF);
	idx = 10000;
	retval = MX_SPI_BYTE(0xFF);						//Check if CARD is still busy
	while((retval != 0xFF) && idx)
	{
		retval = MX_SPI_BYTE(0xFF);					//Wait until CARD is not busy anymore
		idx = idx - 1;
	}
	if (idx == 0)
	{
		set_bit(MX_CARD_PORT, MX_CARD_CS);	//CARD-Disabled
		return MX_ERR_TOUT;					//Read timed out
	}
	set_bit(MX_CARD_PORT, MX_CARD_CS);		//CARD-Disabled
	return MX_ACK_OK;						//Write Complete
/*Macro_MX_Send_Buffer_End*/
}


void MX_Format_File_String(char* File_Name, char MSZ_File_Name)
{
/*Macro_MX_Format_File_String_Start*/
	char i;
	for (i=0;i<11;i++)
		mx_name_ext[i] = 0x20;											//Fill name variable with spaces

	FCI_TOUPPER(File_Name,MSZ_File_Name,File_Name,MSZ_File_Name);	//convert to uppercase

	for (i=0; i<8 && *File_Name != '.' && *File_Name; i++)			//Copy file name to comparison variable
		mx_name_ext[i] = *File_Name++;

	if(*File_Name == '.')											//Find the '.' seperator
	{
		File_Name++;												//and then shift the extension
		for(i=8;i<11 && *File_Name; i++)
			mx_name_ext[i] = *File_Name++;
	}
/*Macro_MX_Format_File_String_End*/
}



char Read_Next_File_Sector(void)
{
/*Macro_Read_Next_File_Sector_Start*/

	#if (MX_FAT_TYPE == 0)
		unsigned int temp_mx_cluster;
		unsigned int old_mx_cluster;
	#endif
	#if (MX_FAT_TYPE == 1 || MX_FAT_TYPE == 2)
		unsigned long temp_mx_cluster;
		unsigned long old_mx_cluster;
	#endif

	unsigned long fat_address;
	char retval;

	mx_current_address = mx_current_address + 1;								//Increment address
	if (((mx_current_address - mx_data_start) % mx_sects_per_clust) == 0)		//If end of mx_cluster reached then find next mx_cluster BR 06/10 was % 32
	{
		temp_mx_cluster = mx_cluster;
		fat_address = mx_fat_start;												//Move to start of FAT
		while (temp_mx_cluster >= FATS_PER_SECT)								//256 FAT16 / 128 FAT32 entries per sector
		{
			temp_mx_cluster = temp_mx_cluster - FATS_PER_SECT;
			fat_address = fat_address + 1;										//Increment sector of FAT
		}
		MX_Get_Buffer(fat_address);												//Read FAT sector
		old_mx_cluster = mx_cluster;
		mx_cluster = Read_Byte_From_Buffer(temp_mx_cluster * SECT_ADDR_LEN);	//Extract data mx_cluster address
		mx_cluster = mx_cluster | ( Read_Byte_From_Buffer((temp_mx_cluster * SECT_ADDR_LEN) + 1) << 8);

		#if	(MX_FAT_TYPE == 1 || MX_FAT_TYPE == 2)
			if (mx_fat_system == 1)
			{
				mx_cluster = mx_cluster | ((long) Read_Byte_From_Buffer((temp_mx_cluster * SECT_ADDR_LEN) + 2) << 16);
				mx_cluster = mx_cluster | ((long) Read_Byte_From_Buffer((temp_mx_cluster * SECT_ADDR_LEN) + 3) << 24);
			}
		#endif

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

			mx_current_address = mx_current_address - 1;						//Restore address
			mx_cluster = old_mx_cluster;										//Restore mx_cluster
			MX_Get_Buffer(mx_current_address);									//Read sector
			return retval;
		}

		mx_current_address = mx_data_start + ((mx_cluster - 2) * mx_sects_per_clust);			//Move to next sector in file   BR 06/10 was * 32
	}

	mx_file_sector = mx_file_sector + 1;										//Increment file sector

	return MX_Get_Buffer(mx_current_address);									//Read sector
/*Macro_Read_Next_File_Sector_End*/
}



void MX_Add_Sector_To_File (void)
{
/*Macro_MX_Add_Sector_To_File_Start*/
	unsigned long idx_fat;
	unsigned long fat_address;

	#if (MX_FAT_TYPE == 0)
		unsigned int fat_pointer = 0xFFFF;				//16-bit FAT pointer
	#endif
	#if (MX_FAT_TYPE == 1)
		unsigned long fat_pointer = 0x0FFFFFFF;			//32-bit FAT pointer
	#endif
	#if (MX_FAT_TYPE == 2)
		unsigned long fat_pointer;
		if (mx_fat_system == 1)
			fat_pointer = 0x0FFFFFFF;					//32-bit FAT pointer
		else
			fat_pointer = 0xFFFF;						//16-bit FAT pointer
	#endif

	idx_fat = 1;
	fat_address = 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 = (long) idx_fat + 1;					//Increment FAT address - Start at address 2
		if(idx_fat == 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;
		}
		fat_pointer = Read_Byte_From_Buffer(idx_fat * SECT_ADDR_LEN);			//Extract data mx_cluster address
		fat_pointer = fat_pointer | ( Read_Byte_From_Buffer((idx_fat * SECT_ADDR_LEN) + 1) << 8);
		#if (MX_FAT_TYPE == 1 || MX_FAT_TYPE == 2)
			if (mx_fat_system == 1)
			{
				fat_pointer = fat_pointer | ((long) Read_Byte_From_Buffer((idx_fat * SECT_ADDR_LEN) + 2) << 16);
				fat_pointer = fat_pointer | ((long) Read_Byte_From_Buffer((idx_fat * SECT_ADDR_LEN) + 3) << 24);
			}
		#endif
	}

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

	#if (MX_FAT_TYPE == 1 || MX_FAT_TYPE == 2)
		if (mx_fat_system == 1)
		{
			Write_Byte_To_Buffer(((idx_fat * SECT_ADDR_LEN) + 2), 0xFF);
			Write_Byte_To_Buffer(((idx_fat * SECT_ADDR_LEN) + 3), 0x0F);
		}
	#endif

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

	fat_address = ((fat_address - mx_fat_start) * FATS_PER_SECT) + idx_fat;
	idx_fat = mx_cluster;
	mx_cluster = fat_address;								//Store new mx_cluster address

	fat_address = mx_fat_start;
	while (idx_fat >= FATS_PER_SECT)
	{
		idx_fat = idx_fat - FATS_PER_SECT;
		fat_address = fat_address + 1;
	}
	MX_Get_Buffer(fat_address);
	Write_Byte_To_Buffer((idx_fat * SECT_ADDR_LEN), mx_cluster);				//Update old FAT address
	Write_Byte_To_Buffer(((idx_fat * SECT_ADDR_LEN) + 1), (mx_cluster >> 8));

	#if (MX_FAT_TYPE == 1 || MX_FAT_TYPE == 2)
		if (mx_fat_system == 1)
		{
			Write_Byte_To_Buffer(((idx_fat * SECT_ADDR_LEN) + 2), (long)(mx_cluster >> 16));
			Write_Byte_To_Buffer(((idx_fat * SECT_ADDR_LEN) + 3), (long)(mx_cluster >> 24));
		}
	#endif

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

	mx_file_sector = mx_file_sector + 1;						//Increment file sector
	mx_current_address = (long) mx_data_start + ((mx_cluster - 2) * mx_sects_per_clust);//Move to next sector in file		BR 06/10 was * 32
	MX_Get_Buffer(mx_current_address);
/*Macro_MX_Add_Sector_To_File_End*/
}


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

