For Terrance

Dependencies:   mbed

Files at this revision

API Documentation at this revision

Comitter:
emh203
Date:
Wed Jun 13 15:10:06 2012 +0000
Commit message:

Changed in this revision

Code/ADC.c Show annotated file Show diff for this revision Revisions of this file
Code/Configuration.c Show annotated file Show diff for this revision Revisions of this file
Code/DataTypes.c Show annotated file Show diff for this revision Revisions of this file
Code/FixedMath.c Show annotated file Show diff for this revision Revisions of this file
Code/GFX.c Show annotated file Show diff for this revision Revisions of this file
Code/KeyValue.c Show annotated file Show diff for this revision Revisions of this file
Code/Serial.c Show annotated file Show diff for this revision Revisions of this file
Code/SmartSwitch.c Show annotated file Show diff for this revision Revisions of this file
Code/System.c Show annotated file Show diff for this revision Revisions of this file
Code/Terminal.cpp Show annotated file Show diff for this revision Revisions of this file
Code/chan_fat_fs/diskio.c Show annotated file Show diff for this revision Revisions of this file
Code/chan_fat_fs/diskio.h Show annotated file Show diff for this revision Revisions of this file
Code/chan_fat_fs/ff.c Show annotated file Show diff for this revision Revisions of this file
Code/chan_fat_fs/ff.h Show annotated file Show diff for this revision Revisions of this file
Code/chan_fat_fs/ffconf.h Show annotated file Show diff for this revision Revisions of this file
Code/chan_fat_fs/integer.h Show annotated file Show diff for this revision Revisions of this file
Code/chan_fat_fs/option/ccsbcs.c Show annotated file Show diff for this revision Revisions of this file
Code/integer.h Show annotated file Show diff for this revision Revisions of this file
DataTypes.h Show annotated file Show diff for this revision Revisions of this file
Headers/ADC.h Show annotated file Show diff for this revision Revisions of this file
Headers/Configuration.h Show annotated file Show diff for this revision Revisions of this file
Headers/FIRMWARE_VERSION.h Show annotated file Show diff for this revision Revisions of this file
Headers/FixedMath.h Show annotated file Show diff for this revision Revisions of this file
Headers/GFX.h Show annotated file Show diff for this revision Revisions of this file
Headers/KeyValue.h Show annotated file Show diff for this revision Revisions of this file
Headers/Serial.h Show annotated file Show diff for this revision Revisions of this file
Headers/SmartSwitch.h Show annotated file Show diff for this revision Revisions of this file
Headers/System.h Show annotated file Show diff for this revision Revisions of this file
Headers/Terminal.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r 085749c8446f Code/ADC.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Code/ADC.c	Wed Jun 13 15:10:06 2012 +0000
@@ -0,0 +1,141 @@
+#include "System.h"
+
+volatile float BatteryVoltage = 0;
+volatile float RobotBusVoltageHR = 0;
+volatile float RobotBusCurrentHR = 0;
+
+float HighResRobotBusVoltageScalingFactor;
+float HighResRobotBusVoltageOffset;
+float HighResRobotBusCurrentScalingFactor;
+
+SIGNED_DWORD    ExtADCRobotVoltage=0;
+SIGNED_DWORD    ExtADCRobotCurrent=0;
+
+AnalogIn BatteryChannel(p17);
+AnalogIn RobotBusCurrentChannel(p20);
+AnalogIn RobotBusVoltageChannel(p19);
+AnalogIn SelfCurrentChannel(p18);
+
+Ticker  BatteryCheck;
+Ticker  InputPowerCheck;
+
+SPI ADCSPI(p11, p12, p13); 
+DigitalOut ConversionStart(p14);
+
+void CheckBattery();
+void CheckInputPower();
+
+SIGNED_DWORD VFilter[64];
+SIGNED_DWORD IFilter[64];
+WORD FilterIndex;
+
+SIGNED_DWORD VBattFilter[8];
+WORD VBattFilterIndex;
+
+DigitalOut PING(LED3);
+DigitalOut PONG(LED4);
+
+volatile BOOL ADCDataRdy;
+
+
+void InitADC()
+{
+    HighResRobotBusVoltageScalingFactor = U1_VREF * ((R2 + R4)/(R4)) * VSCALE_ADJUST;
+    HighResRobotBusVoltageOffset = INPUT_DIODE_DROP*2;
+    HighResRobotBusCurrentScalingFactor = U1_VREF * ((R6+R7)/R7) ;
+    
+    ACS576_ISCALE = ACS576_ISCALE * ACS576_ISCALE_ADJUST; 
+          
+    ADCSPI.format(16,0);
+       
+    ConversionStart = 0;
+        
+    BatteryCheck.attach(&CheckBattery,0.1);
+    InputPowerCheck.attach(&CheckInputPower,(1.0/(SAMPLE_RATE*16)));
+ }
+
+void CheckBattery()
+{
+    int i;
+    SIGNED_DWORD TempSum = 0;
+    
+    VBattFilter[VBattFilterIndex++] = BatteryChannel.read_u16(); 
+    VBattFilterIndex &= 0x7;
+    
+    for(i=0;i<8;i++)
+    {
+        TempSum += VBattFilter[i];
+    } 
+    
+    BatteryVoltage = (float)((TempSum>>3))/65535.0f *  MBED_VREF * ((R17+R15)/R15);
+}
+
+void CheckInputPower()
+{
+    SIGNED_DWORD TempSumV,TempSumI;
+    int i;
+  
+    ConversionStart = 1;
+    VFilter[FilterIndex] = (SIGNED_WORD)(ADCSPI.write(0x0000));
+    IFilter[FilterIndex] = (SIGNED_WORD)(ADCSPI.write(0x0000));
+    FilterIndex++;
+    ConversionStart = 0; 
+    
+    //oversample and average   
+   if(FilterIndex ==16)
+   {
+       ADCDataRdy = TRUE;
+        FilterIndex = 0;
+        TempSumV=0;
+        TempSumI=0;
+        for(i=0;i<32;i++)
+        {
+            TempSumV+=VFilter[i];
+            TempSumI+=IFilter[i];
+         }
+       
+        ExtADCRobotCurrent = TempSumV>>4;
+        ExtADCRobotVoltage = TempSumI>>4;
+    
+        RobotBusVoltageHR = ((((float)(ExtADCRobotVoltage)/(32768.0f)) * HighResRobotBusVoltageScalingFactor + HighResRobotBusVoltageOffset))- VOFFSET_ADJUST;
+        RobotBusCurrentHR = (((((float)(ExtADCRobotCurrent)/(32768.0f)) * HighResRobotBusCurrentScalingFactor) -ACS576_VOFFSET) * ACS576_ISCALE) - ACS576_IOFFSET_TRIM; 
+        
+        if(SystemState == SYSTEM_STATE_LOGGING)
+        {
+           
+             if (MyDataBlock.WriteOutPtr >MyDataBlock.ReadInPtr)
+             {
+                  ReadWriteDifferential = (DATA_BLOCK_SIZE - MyDataBlock.WriteOutPtr +  MyDataBlock.ReadInPtr);
+             }
+             else
+             {
+                  ReadWriteDifferential = ( MyDataBlock.ReadInPtr - MyDataBlock.WriteOutPtr);
+             }
+    
+             if(ReadWriteDifferential >= DATA_BLOCK_SIZE - 1)
+             {
+                DataLogError = TRUE;
+                ErrorMsg = "Overrun!";
+             }
+             else
+             {
+                 MyDataBlock.Voltage[MyDataBlock.ReadInPtr] =  RobotBusVoltageHR;
+                 MyDataBlock.Current[MyDataBlock.ReadInPtr] =  RobotBusCurrentHR;
+                        
+                 MyDataBlock.ReadInPtr++;
+                 
+                 if(MyDataBlock.ReadInPtr == DATA_BLOCK_SIZE)
+                 {
+                    MyDataBlock.ReadInPtr = 0;
+                 }
+             }
+         }
+         else
+         {
+              ReadWriteDifferential = 0;
+         }
+     }
+}
+
+
+
diff -r 000000000000 -r 085749c8446f Code/Configuration.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Code/Configuration.c	Wed Jun 13 15:10:06 2012 +0000
@@ -0,0 +1,379 @@
+#include "System.h"
+
+LocalFileSystem LocalFS("local"); 
+
+CHAR LineBuf[128];
+
+//Voltage Divider for the Li_poly Battery
+float R17,R15;
+#define R17_DEFAULT  (float)(10000.0)
+#define R15_DEFAULT  (float)(10000.0)
+
+//Voltage Divider for input voltage measurement
+float R2,R4;
+#define R2_DEFAULT  (float)(100000.0)
+#define R4_DEFAULT  (float)(3300.0)
+
+//Voltage Divider for current voltage measurement (to the 16-bit ADC)
+float R6,R7;
+#define R6_DEFAULT (float) (10000.0)
+#define R7_DEFAULT  (float)(10000.0)
+
+//Voltage Divider for current voltage measurement (to the 12-bit ADC)
+float R8,R9;
+#define R8_DEFAULT  (float)(5100.0)
+#define R9_DEFAULT  (float)(10000.0)
+
+//value of the 2.5Voltage reference
+float U1_VREF;
+#define U1_VREF_DEFAULT    (float)(2.5)
+
+//value of the MBED Voltage reference
+float MBED_VREF;
+#define MBED_VREF_DEFAULT    (float)(3.3)
+
+//value of the input diode drop
+float INPUT_DIODE_DROP;
+#define INPUT_DIODE_DROP_DEFAULT   (float)(0.601)
+
+
+//used for self current 
+float R22;
+#define R22_DEFAULT 0.5
+
+float R18;
+#define R18_DEFAULT 200
+
+float R19;
+#define R19_DEFAULT 200
+
+float R20;
+#define R20_DEFAULT 10000
+
+
+//Parameters for the ACS576 Current Sensor
+
+float ACS576_VOFFSET;
+#define ACS576_VOFFSET_DEFAULT              (2.5)
+
+float ACS576_ISCALE; 
+#define ACS576_ISCALE_DEFAULT              (25.0)
+
+float ACS576_ISCALE_ADJUST; 
+#define ACS576_ISCALE_ADJUST_DEFAULT         (1.0)
+
+float ACS576_IOFFSET_TRIM; 
+#define ACS576_IOFFSET_TRIM_DEFAULT        (0.0)
+
+//Used to correct the input voltage measurement
+float  VSCALE_ADJUST; 
+#define VSCALE_ADJUST_DEFAULT        (1.0)
+
+float  VOFFSET_ADJUST; 
+#define VOFFSET_ADJUST_DEFAULT        (0.0)
+
+//Sampling Parameters
+float   SAMPLE_RATE;
+DWORD   WRITE_BLOCK_THRESH;
+
+CHAR ID[MAX_ID_LENGTH+1];
+#define ID_DEFAULT "No ID"
+
+void LoadDefaults()
+{
+    strcpy(ID,ID_DEFAULT);
+
+    VOFFSET_ADJUST = VOFFSET_ADJUST_DEFAULT;
+    VSCALE_ADJUST  = VSCALE_ADJUST_DEFAULT;
+    
+    R17 = R17_DEFAULT;
+    R15 = R15_DEFAULT;
+
+    R2 = R2_DEFAULT;
+    R4 = R4_DEFAULT;
+
+    R6 = R6_DEFAULT;
+    R7 = R7_DEFAULT;
+    
+    R8 = R8_DEFAULT;
+    R9 = R9_DEFAULT;
+    
+    R18 = R18_DEFAULT;
+    R19 = R19_DEFAULT;
+    R20 = R20_DEFAULT;
+    R22 = R22_DEFAULT;
+    
+    U1_VREF = U1_VREF_DEFAULT;
+    MBED_VREF = MBED_VREF_DEFAULT;
+    
+    INPUT_DIODE_DROP =  INPUT_DIODE_DROP_DEFAULT;
+    
+    ACS576_VOFFSET = ACS576_VOFFSET_DEFAULT;
+
+    ACS576_ISCALE =  ACS576_ISCALE_DEFAULT;
+    ACS576_ISCALE_ADJUST = ACS576_ISCALE_ADJUST_DEFAULT;
+    
+    ACS576_IOFFSET_TRIM = ACS576_IOFFSET_TRIM_DEFAULT;
+    
+    SAMPLE_RATE = SAMPLE_RATE_DEFAULT;
+    WRITE_BLOCK_THRESH = WRITE_BLOCK_THRESH_DEFAULT;
+}
+
+void ExportConfigurationSettings()
+{
+    FILE *MyConfigFile = fopen("/local/config.txt","w");
+    
+    
+    fprintf(MyConfigFile,"ACS576_ISCALE_ADJUST = %.3f  \r\n",ACS576_ISCALE_ADJUST); 
+    fprintf(MyConfigFile,"ACS576_IOFFSET_TRIM = %.3f  \r\n",ACS576_IOFFSET_TRIM);
+    
+    fprintf(MyConfigFile,"VSCALE_ADJUST = %.3f  \r\n",VSCALE_ADJUST);
+    fprintf(MyConfigFile,"VOFFSET_ADJUST = %.3f  \r\n",VOFFSET_ADJUST);
+    
+    fprintf(MyConfigFile,"R17 = %.1f  \r\n",R17);
+    fprintf(MyConfigFile,"R15 = %.1f  \r\n",R15);
+
+    fprintf(MyConfigFile,"R2 = %.1f  \r\n",R2);
+    fprintf(MyConfigFile,"R4 = %.1f  \r\n", R4);
+
+    fprintf(MyConfigFile,"R6 = %.1f  \r\n",R6);
+    fprintf(MyConfigFile,"R7 = %.1f  \r\n",R7);
+    
+    fprintf(MyConfigFile,"R8 = %.1f  \r\n",R8);
+    fprintf(MyConfigFile,"R9 = %.1f  \r\n",R9);
+    
+    fprintf(MyConfigFile,"R18 = %.1f  \r\n",R18);
+    fprintf(MyConfigFile,"R19 = %.1f  \r\n",R19);
+    fprintf(MyConfigFile,"R20 = %.1f  \r\n",R20);
+    fprintf(MyConfigFile,"R22 = %.1f  \r\n",R22);
+    
+    fprintf(MyConfigFile,"U1_VREF = %.3f  \r\n",U1_VREF);
+    fprintf(MyConfigFile,"MBED_VREF = %.3f  \r\n",MBED_VREF);
+    
+    fprintf(MyConfigFile,"INPUT_DIODE_DROP = %.3f  \r\n",INPUT_DIODE_DROP);
+    
+    fprintf(MyConfigFile,"ACS576_VOFFSET = %.3f  \r\n",ACS576_VOFFSET);
+
+    fprintf(MyConfigFile,"ACS576_ISCALE = %.3f  \r\n", ACS576_ISCALE_DEFAULT);
+   
+    
+    fprintf(MyConfigFile,"SAMPLE_RATE = %.1f  \r\n",SAMPLE_RATE);
+    fprintf(MyConfigFile,"WRITE_BLOCK_THRESH = %d  \r\n",WRITE_BLOCK_THRESH);
+  
+    fprintf(MyConfigFile,"ID = %s    \r\n",ID);
+  
+  
+    fclose(MyConfigFile);
+}
+
+//This is a very "static implementation.  Just does string compares.  Would be nice to have a table like feature in the future
+void  ParseKeyValue(const CHAR *Key,const CHAR *Value)
+{
+    WORD i;
+    
+     if(!strcmp(Key,(CHAR *)"R17"))
+    {
+        R17 = atof(Value);
+        PrintfEnqueue(&PCBackDoorTx,"R17 assigned a value of %.3f",R17);
+    }
+    else if(!strcmp(Key,"R15"))
+    {
+        R15 = atof(Value);
+        PrintfEnqueue(&PCBackDoorTx,"R15 assigned a value of %.3f",R15);
+    }
+    else if(!strcmp(Key,"R2"))
+    {
+        R2 = atof(Value);
+        PrintfEnqueue(&PCBackDoorTx,"R2 assigned a value of %.3f",R2);
+    }
+    else if(!strcmp(Key,"R4"))
+    {
+        R4 = atof(Value);
+        PrintfEnqueue(&PCBackDoorTx,"R4 assigned a value of %.3f",R4);
+    }
+    else if(!strcmp(Key,"R6"))
+    {
+        R6 = atof(Value);
+        PrintfEnqueue(&PCBackDoorTx,"R6 assigned a value of %.3f",R6);
+    }
+    else if(!strcmp(Key,"R7"))
+    {
+        R7 = atof(Value);
+        PrintfEnqueue(&PCBackDoorTx,"R7 assigned a value of %.3f",R7);
+    }
+    else if(!strcmp(Key,"R8"))
+    {
+        R8 = atof(Value);
+        PrintfEnqueue(&PCBackDoorTx,"R8 assigned a value of %.3f",R8);
+    }
+    else if(!strcmp(Key,"R9"))
+    {
+        R9 = atof(Value);
+        PrintfEnqueue(&PCBackDoorTx,"R9 assigned a value of %.3f",R9);
+    }
+    else if(!strcmp(Key,"U1_VREF"))
+    {
+        U1_VREF = atof(Value);
+        PrintfEnqueue(&PCBackDoorTx,"U1_VREF assigned a value of %.3f",U1_VREF);
+    }
+    else if(!strcmp(Key,"MBED_VREF"))
+    {
+        MBED_VREF = atof(Value);
+        PrintfEnqueue(&PCBackDoorTx,"MBED_VREF assigned a value of %.3f",MBED_VREF);
+    }
+    else if(!strcmp(Key,"INPUT_DIODE_DROP"))
+    {
+        INPUT_DIODE_DROP = atof(Value);
+        PrintfEnqueue(&PCBackDoorTx,"INPUT_DIODE_DROP assigned a value of %.3f",INPUT_DIODE_DROP);
+    }
+    else if(!strcmp(Key,"ACS576_VOFFSET"))
+    {
+        ACS576_VOFFSET = atof(Value);
+        PrintfEnqueue(&PCBackDoorTx,"ACS576_VOFFSET assigned a value of %.3f", ACS576_VOFFSET);
+    }
+    else if(!strcmp(Key,"ACS576_ISCALE"))
+    {
+        ACS576_ISCALE = atof(Value);
+        PrintfEnqueue(&PCBackDoorTx,"ACS576_ISCALE assigned a value of %.3f", ACS576_ISCALE);
+    }
+     else if(!strcmp(Key,"ACS576_ISCALE_ADJUST"))
+    {
+        ACS576_ISCALE_ADJUST = atof(Value);
+        PrintfEnqueue(&PCBackDoorTx,"ACS576_ISCALE_ADJUST assigned a value of %.3f", ACS576_ISCALE_ADJUST);
+    }
+    else if(!strcmp(Key,"ACS576_IOFFSET_TRIM"))
+    {
+        ACS576_IOFFSET_TRIM = atof(Value);
+        PrintfEnqueue(&PCBackDoorTx,"ACS576_IOFFSET_TRIM assigned a value of %.3f",  ACS576_IOFFSET_TRIM);
+    }
+    else if(!strcmp(Key,"R18"))
+    {
+        R18 = atof(Value);
+        PrintfEnqueue(&PCBackDoorTx,"R18 assigned a value of %.3f",  R18);
+    }
+    else if(!strcmp(Key,"R19"))
+    {
+        R19 = atof(Value);
+        PrintfEnqueue(&PCBackDoorTx,"R19 assigned a value of %.3f",  R19);
+    }
+    else if(!strcmp(Key,"R20"))
+    {
+        R20 = atof(Value);
+        PrintfEnqueue(&PCBackDoorTx,"R20 assigned a value of %.3f",  R20);
+    }
+    else if(!strcmp(Key,"R22"))
+    {
+        R22 = atof(Value);
+        PrintfEnqueue(&PCBackDoorTx,"R22 assigned a value of %.3f",  R22);
+    }
+    else if(!strcmp(Key,"VSCALE_ADJUST"))
+    {
+        VSCALE_ADJUST = atof(Value);
+        PrintfEnqueue(&PCBackDoorTx,"VSCALE_ADJUST assigned a value of %.3f",  VSCALE_ADJUST);
+    }
+    else if(!strcmp(Key,"VOFFSET_ADJUST"))
+    {
+        VOFFSET_ADJUST = atof(Value);
+        PrintfEnqueue(&PCBackDoorTx,"VOFFSET_ADJUST assigned a value of %.3f",  VOFFSET_ADJUST);
+    }
+    else if(!strcmp(Key,"SAMPLE_RATE"))
+    {
+        SAMPLE_RATE = atof(Value);
+         
+           if(SAMPLE_RATE < MIN_SAMPLE_RATE || SAMPLE_RATE > MAX_SAMPLE_RATE)
+           {
+               PrintfEnqueue(&PCBackDoorTx,"Illegal SAMPLE_RATE of %.1f was specified. %.1f is being used",SAMPLE_RATE,SAMPLE_RATE_DEFAULT);
+                SAMPLE_RATE = SAMPLE_RATE_DEFAULT;
+            }
+            else
+            {
+                    PrintfEnqueue(&PCBackDoorTx,"SAMPLE_RATE assigned a value of %.1f",  SAMPLE_RATE);
+            }
+    }
+    
+    else if(!strcmp(Key,"WRITE_BLOCK_THRESH"))
+    {
+         WRITE_BLOCK_THRESH = (DWORD)atof(Value);
+         
+           if(WRITE_BLOCK_THRESH < MIN_WRITE_BLOCK_THRESH|| WRITE_BLOCK_THRESH > MAX_WRITE_BLOCK_THRESH)
+           {
+                PrintfEnqueue(&PCBackDoorTx,"Illegal WRITE_BLOCK_THRESH of %d was specified. %d is being used\r\n",WRITE_BLOCK_THRESH,WRITE_BLOCK_THRESH_DEFAULT);
+                PrintfEnqueue(&PCBackDoorTx,"WRITE_BLOCK_THRESH must be between %d and %d",MIN_WRITE_BLOCK_THRESH, MAX_WRITE_BLOCK_THRESH); 
+             
+                WRITE_BLOCK_THRESH = WRITE_BLOCK_THRESH_DEFAULT;
+            }
+            else
+            {
+                    PrintfEnqueue(&PCBackDoorTx,"WRITE_BLOCK_THRESH assigned a value of %d",  WRITE_BLOCK_THRESH);
+            }
+    }
+    else if(!strcmp(Key,"ID"))
+    {
+        if(strlen(Value)>MAX_ID_LENGTH)
+        {
+             PrintfEnqueue(&PCBackDoorTx,"ID must be %d characters or less.  Truncating...",  MAX_ID_LENGTH); 
+             for(i=0;i<MAX_ID_LENGTH;i++)
+             {
+                ID[i] = Value[i];
+                ID[MAX_ID_LENGTH] = NULL;
+             }         
+        } 
+        else
+        {
+          strcpy(ID,Value);
+        }     
+      
+        PrintfEnqueue(&PCBackDoorTx,"ID assigned a value of %s",  ID);  
+    }
+    else
+    {
+        PrintfEnqueue(&PCBackDoorTx,"%s key is not recognized parameter",Key);
+    }
+   
+    PrintfEnqueue(&PCBackDoorTx,"\r\n");
+
+}
+
+void LoadConfiguration()
+{
+    WORD CurrentLine = 1;
+    
+    LoadDefaults();
+
+    SmartSwitch_SetBackLightColor(3,3,3);
+    GFX_FullDisplayBufferClear(&BackBuffer);
+    GFX_DrawString(&BackBuffer,"Loading Config",0,0,&Font3x5);
+    GFX_DumpRenderContextToPhysicalScreen(&BackBuffer);
+    
+    FILE *MyConfigFile = fopen("/local/config.txt","r");
+    
+    if(!MyConfigFile)
+    {
+        PrintfEnqueue(&PCBackDoorTx,"Could not open configuration files. Using Defaults....\r\n");
+        wait(1);
+        return;
+    }
+    
+    PrintfEnqueue(&PCBackDoorTx,"Config file found.  Parsing.....\r\n\r\n");
+  
+    while(fgets(LineBuf,sizeof(LineBuf),MyConfigFile))
+    {
+       if(KeyValueSplit(LineBuf,Key,Value))
+       {
+             ParseKeyValue(Key,Value);
+       }
+       else
+       {
+           PrintfEnqueue(&PCBackDoorTx,"No valid key=value pair on line %d\r\n",CurrentLine);
+       }
+       
+       CurrentLine++;
+    }
+    
+    fclose(MyConfigFile);
+    
+    PrintfEnqueue(&PCBackDoorTx,"\r\n\r\n>");
+}
+
+
+
diff -r 000000000000 -r 085749c8446f Code/DataTypes.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Code/DataTypes.c	Wed Jun 13 15:10:06 2012 +0000
@@ -0,0 +1,193 @@
+#include "System.h"
+
+CHAR StringBuffer[256];
+
+SIGNED_WORD ByteStackPush(ByteStack * Stack,BYTE Val) {
+    if (Stack->Ptr == Stack->Size-1) {
+        return STACK_FULL;
+    } else {
+        Stack->Ptr++;
+        Stack->StackSpace[Stack->Ptr] = Val;
+        return STACK_PUSH_OK;
+    }
+}
+
+SIGNED_WORD ByteStackPOP(ByteStack * Stack) {
+    if (Stack->Ptr == 0) {
+        return STACK_EMPTY;
+    } else {
+        Stack->Ptr--;
+        return Stack->StackSpace[Stack->Ptr];
+    }
+}
+
+SIGNED_BYTE BitStackPush(BitStack * Stack,BOOL Val) {
+    WORD Offset;
+    BYTE Mask;
+
+    if (Stack->Ptr == Stack->Size-1) {
+        return STACK_FULL;
+    } else {
+
+        Stack->Ptr++;
+        Offset = (Stack->Ptr)>>3;
+        Mask = 0x01<<(Stack->Ptr&0x07);
+
+        if (Val) {
+            Stack->StackSpace[Offset] |= Mask;
+        } else {
+            Stack->StackSpace[Offset] &= ~Mask;
+        }
+
+        return STACK_PUSH_OK;
+    }
+}
+
+SIGNED_BYTE BitStackPop(BitStack * Stack) {
+    WORD Offset;
+    BYTE Mask;
+
+    if (Stack->Ptr == 0) {
+        return STACK_EMPTY;
+    } else {
+
+        Stack->Ptr++;
+        Offset = (Stack->Ptr)>>3;
+        Mask = 0x01<<(Stack->Ptr&0x07);
+
+        if (Stack->StackSpace[Offset] | Mask) {
+            return TRUE;
+        } else {
+            return FALSE;
+        }
+    }
+}
+
+#ifndef INLINE_BITPLANE_PUT
+void BitPlane_Put(BitPlane  * BP, WORD X,WORD Y, BOOL Value)
+{
+    WORD Offset;
+    BYTE Mask;
+    
+    Offset = (Y * ((BP->SizeX)>>3)) + (X>>3);
+    Mask = 0x01 << (X & 0x07);
+
+    if(Value)
+    {
+        BP->BitPlaneSpace[Offset] |= Mask;
+    }
+    else
+    {
+        BP->BitPlaneSpace[Offset] &= ~Mask;
+    }
+}
+#endif
+
+#ifndef INLINE_BITPLANE_GET
+BOOL BitPlane_Get(BitPlane  * BP, WORD X,WORD Y)
+{
+    WORD Offset;
+    BYTE Mask;
+ 
+    Offset = (Y * ((BP->SizeX)>>3)) + (X>>3);
+    Mask = 0x01 << (X & 0x07);
+
+    if((BP->BitPlaneSpace[Offset])&Mask)
+    {
+        return TRUE;
+    }
+    else
+    {
+        return FALSE;
+    }
+}
+#endif
+void BitPlane_Clear(BitPlane  * BP) {
+    WORD PlaneSpaceSize;
+    WORD i;
+
+    PlaneSpaceSize = ((BP->SizeX)>>3) * BP->SizeY;
+
+    for (i=0;i<PlaneSpaceSize;i++) {
+        BP->BitPlaneSpace[i] = 0;
+    }
+}
+
+
+
+void InitByteQueue(ByteQueue *BQ,WORD Size,BYTE * Storage) {
+    WORD i;
+
+    BQ->QueueSize = Size;
+    BQ->ReadPtr=0;
+    BQ->WritePtr=0;
+    BQ->QueueStorage = Storage;
+
+    for (i=0;i<BQ->QueueSize;i++) {
+        BQ->QueueStorage[i] = 0;
+    }
+}
+
+WORD BytesInQueue(ByteQueue *BQ) {
+    if (BQ->ReadPtr > BQ->WritePtr) {
+        return (BQ->QueueSize - BQ->ReadPtr + BQ->WritePtr);
+    } else if (BQ->WritePtr > BQ->ReadPtr) {
+        return     (BQ->WritePtr - BQ->ReadPtr);
+    } else {
+        return 0;
+    }
+}
+
+SIGNED_WORD ByteEnqueue(ByteQueue *BQ,BYTE Val) {
+    if (BytesInQueue(BQ) == BQ->QueueSize) {
+        return QUEUE_FULL;
+    } else {
+        BQ->QueueStorage[BQ->WritePtr] = Val;
+        BQ->WritePtr++;
+
+        if (BQ->WritePtr >= BQ->QueueSize) {
+            BQ->WritePtr = 0;
+        }
+        return QUEUE_OK;
+    }
+}
+
+SIGNED_WORD ByteArrayEnqueue(ByteQueue *BQ,BYTE *Buf,WORD Len) {
+    WORD i;
+    for (i=0;i<Len;i++) {
+        ByteEnqueue(BQ,Buf[i]);
+    }
+    return QUEUE_OK;
+}
+
+SIGNED_WORD PrintfEnqueue(ByteQueue *BQ, const char *FormatString,...)
+{
+ 
+     va_list argptr; 
+     va_start(argptr,FormatString); 
+     vsprintf((CHAR *)StringBuffer,FormatString,argptr);
+     va_end(argptr);   
+     
+     ByteArrayEnqueue(BQ,(BYTE *)StringBuffer,strlen(StringBuffer));
+           
+    return QUEUE_OK;
+}
+
+
+
+
+SIGNED_WORD ByteDequeue(ByteQueue *BQ,BYTE *Val) {
+
+    if (BytesInQueue(BQ) == 0) {
+        return QUEUE_EMPTY;
+    } else {
+        *Val  = BQ->QueueStorage[BQ->ReadPtr];
+
+        BQ->ReadPtr++;
+
+        if (BQ->ReadPtr >= BQ->QueueSize) {
+            BQ->ReadPtr = 0;
+        }
+        return QUEUE_OK;
+    }
+}
\ No newline at end of file
diff -r 000000000000 -r 085749c8446f Code/FixedMath.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Code/FixedMath.c	Wed Jun 13 15:10:06 2012 +0000
@@ -0,0 +1,71 @@
+#include "FixedMath.h"
+
+
+const FIXED_1_14 Fixed_1_14_SineTable [256] = { 0x0000,0x0192,0x0324,0x04B5,0x0646,0x07D6,0x0964,0x0AF1,
+												0x0C7C,0x0E06,0x0F8D,0x1112,0x1294,0x1413,0x1590,0x1709,
+												0x187E,0x19EF,0x1B5D,0x1CC6,0x1E2B,0x1F8C,0x20E7,0x223D,
+												0x238E,0x24DA,0x2620,0x2760,0x289A,0x29CE,0x2AFB,0x2C21,
+												0x2D41,0x2E5A,0x2F6C,0x3076,0x3179,0x3274,0x3368,0x3453,
+												0x3537,0x3612,0x36E5,0x37B0,0x3871,0x392B,0x39DB,0x3A82,
+												0x3B21,0x3BB6,0x3C42,0x3CC5,0x3D3F,0x3DAF,0x3E15,0x3E72,
+												0x3EC5,0x3F0F,0x3F4F,0x3F85,0x3FB1,0x3FD4,0x3FEC,0x3FFB,
+												0x4000,0x3FFB,0x3FEC,0x3FD4,0x3FB1,0x3F85,0x3F4F,0x3F0F,
+												0x3EC5,0x3E72,0x3E15,0x3DAF,0x3D3F,0x3CC5,0x3C42,0x3BB6,
+												0x3B21,0x3A82,0x39DB,0x392B,0x3871,0x37B0,0x36E5,0x3612,
+												0x3537,0x3453,0x3368,0x3274,0x3179,0x3076,0x2F6C,0x2E5A,
+												0x2D41,0x2C21,0x2AFB,0x29CE,0x289A,0x2760,0x2620,0x24DA,
+												0x238E,0x223D,0x20E7,0x1F8C,0x1E2B,0x1CC6,0x1B5D,0x19EF,
+												0x187E,0x1709,0x1590,0x1413,0x1294,0x1112,0x0F8D,0x0E06,
+												0x0C7C,0x0AF1,0x0964,0x07D6,0x0646,0x04B5,0x0324,0x0192,
+												0x0000,0xFE6E,0xFCDC,0xFB4B,0xF9BA,0xF82A,0xF69C,0xF50F,
+												0xF384,0xF1FA,0xF073,0xEEEE,0xED6C,0xEBED,0xEA70,0xE8F7,
+												0xE782,0xE611,0xE4A3,0xE33A,0xE1D5,0xE074,0xDF19,0xDDC3,
+												0xDC72,0xDB26,0xD9E0,0xD8A0,0xD766,0xD632,0xD505,0xD3DF,
+												0xD2BF,0xD1A6,0xD094,0xCF8A,0xCE87,0xCD8C,0xCC98,0xCBAD,
+												0xCAC9,0xC9EE,0xC91B,0xC850,0xC78F,0xC6D5,0xC625,0xC57E,
+												0xC4DF,0xC44A,0xC3BE,0xC33B,0xC2C1,0xC251,0xC1EB,0xC18E,
+												0xC13B,0xC0F1,0xC0B1,0xC07B,0xC04F,0xC02C,0xC014,0xC005,
+												0xC000,0xC005,0xC014,0xC02C,0xC04F,0xC07B,0xC0B1,0xC0F1,
+												0xC13B,0xC18E,0xC1EB,0xC251,0xC2C1,0xC33B,0xC3BE,0xC44A,
+												0xC4DF,0xC57E,0xC625,0xC6D5,0xC78F,0xC850,0xC91B,0xC9EE,
+												0xCAC9,0xCBAD,0xCC98,0xCD8C,0xCE87,0xCF8A,0xD094,0xD1A6,
+												0xD2BF,0xD3DF,0xD505,0xD632,0xD766,0xD8A0,0xD9E0,0xDB26,
+												0xDC72,0xDDC3,0xDF19,0xE074,0xE1D5,0xE33A,0xE4A3,0xE611,
+												0xE782,0xE8F7,0xEA70,0xEBED,0xED6C,0xEEEE,0xF073,0xF1FA,
+												0xF384,0xF50F,0xF69C,0xF82A,0xF9BA,0xFB4B,0xFCDC,0xFE6E};
+												
+const FIXED_7_8 Fixed_7_8_SineTable [256] = { 	0x0000,0x0006,0x000D,0x0013,0x0019,0x001F,0x0026,0x002C,
+												0x0032,0x0038,0x003E,0x0044,0x004A,0x0050,0x0056,0x005C,
+												0x0062,0x0068,0x006D,0x0073,0x0079,0x007E,0x0084,0x0089,
+												0x008E,0x0093,0x0098,0x009D,0x00A2,0x00A7,0x00AC,0x00B1,
+												0x00B5,0x00B9,0x00BE,0x00C2,0x00C6,0x00CA,0x00CE,0x00D1,
+												0x00D5,0x00D8,0x00DC,0x00DF,0x00E2,0x00E5,0x00E7,0x00EA,
+												0x00ED,0x00EF,0x00F1,0x00F3,0x00F5,0x00F7,0x00F8,0x00FA,
+												0x00FB,0x00FC,0x00FD,0x00FE,0x00FF,0x00FF,0x0100,0x0100,
+												0x0100,0x0100,0x0100,0x00FF,0x00FF,0x00FE,0x00FD,0x00FC,
+												0x00FB,0x00FA,0x00F8,0x00F7,0x00F5,0x00F3,0x00F1,0x00EF,
+												0x00ED,0x00EA,0x00E7,0x00E5,0x00E2,0x00DF,0x00DC,0x00D8,
+												0x00D5,0x00D1,0x00CE,0x00CA,0x00C6,0x00C2,0x00BE,0x00B9,
+												0x00B5,0x00B1,0x00AC,0x00A7,0x00A2,0x009D,0x0098,0x0093,
+												0x008E,0x0089,0x0084,0x007E,0x0079,0x0073,0x006D,0x0068,
+												0x0062,0x005C,0x0056,0x0050,0x004A,0x0044,0x003E,0x0038,
+												0x0032,0x002C,0x0026,0x001F,0x0019,0x0013,0x000D,0x0006,
+												0x0000,0xFFFA,0xFFF3,0xFFED,0xFFE7,0xFFE1,0xFFDA,0xFFD4,
+												0xFFCE,0xFFC8,0xFFC2,0xFFBC,0xFFB6,0xFFB0,0xFFAA,0xFFA4,
+												0xFF9E,0xFF98,0xFF93,0xFF8D,0xFF87,0xFF82,0xFF7C,0xFF77,
+												0xFF72,0xFF6D,0xFF68,0xFF63,0xFF5E,0xFF59,0xFF54,0xFF4F,
+												0xFF4B,0xFF47,0xFF42,0xFF3E,0xFF3A,0xFF36,0xFF32,0xFF2F,
+												0xFF2B,0xFF28,0xFF24,0xFF21,0xFF1E,0xFF1B,0xFF19,0xFF16,
+												0xFF13,0xFF11,0xFF0F,0xFF0D,0xFF0B,0xFF09,0xFF08,0xFF06,
+												0xFF05,0xFF04,0xFF03,0xFF02,0xFF01,0xFF01,0xFF00,0xFF00,
+												0xFF00,0xFF00,0xFF00,0xFF01,0xFF01,0xFF02,0xFF03,0xFF04,
+												0xFF05,0xFF06,0xFF08,0xFF09,0xFF0B,0xFF0D,0xFF0F,0xFF11,
+												0xFF13,0xFF16,0xFF19,0xFF1B,0xFF1E,0xFF21,0xFF24,0xFF28,
+												0xFF2B,0xFF2F,0xFF32,0xFF36,0xFF3A,0xFF3E,0xFF42,0xFF47,
+												0xFF4B,0xFF4F,0xFF54,0xFF59,0xFF5E,0xFF63,0xFF68,0xFF6D,
+												0xFF72,0xFF77,0xFF7C,0xFF82,0xFF87,0xFF8D,0xFF93,0xFF98,
+												0xFF9E,0xFFA4,0xFFAA,0xFFB0,0xFFB6,0xFFBC,0xFFC2,0xFFC8,
+												0xFFCE,0xFFD4,0xFFDA,0xFFE1,0xFFE7,0xFFED,0xFFF3,0xFFFA};
+												
+												
+												
\ No newline at end of file
diff -r 000000000000 -r 085749c8446f Code/GFX.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Code/GFX.c	Wed Jun 13 15:10:06 2012 +0000
@@ -0,0 +1,860 @@
+#include "DataTypes.h"
+#include "GFX.h"
+#include "SmartSwitch.h"
+#include "FixedMath.h"
+
+//Linking Functions to Physical Screen
+//***********************************************************************************
+
+void GFX_InitPhysicalScreen()
+{
+     InitSmartSwitch();
+}
+
+void GFX_DumpRenderContextToPhysicalScreen(RenderContext *Image)
+{
+   int x,y;
+   
+   SmartSwitch_SS = 0;
+   SmartSwitchWriteByte(SMART_SWITCH_CMD_DISPLAY_DATA);
+   
+   for(y=0;y<PHYSICAL_DISPLAY_YRES;y++)
+   {
+       for(x=0;x<PHYSICAL_DISPLAY_X_WIDTH_IN_BYTES;x++)
+       {
+          SmartSwitchWriteByte(Image->RenderPlane.BitPlaneSpace[(y*PHYSICAL_DISPLAY_X_WIDTH_IN_BYTES) + (PHYSICAL_DISPLAY_X_WIDTH_IN_BYTES - x - 1)]);
+       }
+   }
+   SmartSwitch_SS = 1;
+}
+
+void GFX_PowerUpScreen()
+{
+    PowerUpSmartSwitch();
+}
+
+void GFX_PowerDownScreen()
+{
+    PowerDownSmartSwitch();
+}
+
+//Device Independent Functions
+//***********************************************************************************
+
+//Reserve Space for the backbuffer
+
+RenderContext BackBuffer;
+BYTE BackBufferRenderPlaneSpace[PHYSICAL_DISPLAY_PLANE_BUFFER_SIZE];
+
+
+//FontData
+
+#define FONT5x7_FONT_WIDTH 5
+#define FONT5x7_FONT_HEIGHT 8
+#define FONT5x7_FONT_ELEMENTS 128
+#define FONT5x7_FONT_COLUMN_SIZE_IN_BYTE  1
+
+BYTE FontTable_Font5x7 [640] = {
+0x00 ,0x08 ,0x0C ,0xFA ,0x81 ,0xFA ,0x0C ,0x08 ,0x00 ,0x00 ,0x00 ,0x10 ,0x30 ,0x5F ,0x81 ,0x5F ,
+0x30 ,0x10 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,
+0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,
+0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,
+0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,
+0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,
+0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,
+0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,
+0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,
+0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,
+0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0xBE ,0x00 ,0x00 ,0x00 ,0x00 ,0x06 ,0x00 ,0x06 ,0x00 ,0x00 ,0x28 ,
+0xFE ,0x28 ,0xFE ,0x28 ,0x48 ,0xFE ,0x54 ,0xFE ,0x24 ,0x06 ,0xE6 ,0x10 ,0xCE ,0xC0 ,0x60 ,0x92 ,
+0x94 ,0x78 ,0x10 ,0x06 ,0x00 ,0x00 ,0x00 ,0x00 ,0x7C ,0x82 ,0x00 ,0x00 ,0x00 ,0x82 ,0x7C ,0x00 ,
+0x00 ,0x00 ,0x54 ,0x38 ,0xFE ,0x38 ,0x54 ,0x10 ,0x10 ,0x7C ,0x10 ,0x10 ,0x80 ,0x60 ,0x00 ,0x00 ,
+0x00 ,0x10 ,0x10 ,0x10 ,0x10 ,0x10 ,0x80 ,0x00 ,0x00 ,0x00 ,0x00 ,0xC0 ,0x30 ,0x0C ,0x02 ,0x00 ,
+0x7C ,0xA2 ,0x92 ,0x8A ,0x7C ,0x88 ,0x84 ,0xFE ,0x80 ,0x80 ,0x84 ,0xC2 ,0xA2 ,0x92 ,0x8C ,0x44 ,
+0x92 ,0x92 ,0x92 ,0x6C ,0x10 ,0x18 ,0x14 ,0xFE ,0x10 ,0x4E ,0x8A ,0x8A ,0x8A ,0x72 ,0x7C ,0x92 ,
+0x92 ,0x92 ,0x64 ,0x02 ,0xC2 ,0x22 ,0x12 ,0x0E ,0x6C ,0x92 ,0x92 ,0x92 ,0x6C ,0x0C ,0x92 ,0x92 ,
+0x92 ,0x7C ,0x48 ,0x00 ,0x00 ,0x00 ,0x00 ,0x80 ,0x68 ,0x00 ,0x00 ,0x00 ,0x10 ,0x28 ,0x44 ,0x82 ,
+0x00 ,0x28 ,0x28 ,0x28 ,0x28 ,0x00 ,0x82 ,0x44 ,0x28 ,0x10 ,0x00 ,0x04 ,0x02 ,0xA2 ,0x12 ,0x0C ,
+0x3C ,0x42 ,0x9A ,0xA2 ,0x1C ,0xF8 ,0x14 ,0x12 ,0x14 ,0xF8 ,0xFE ,0x92 ,0x92 ,0x92 ,0x6C ,0x7C ,
+0x82 ,0x82 ,0x82 ,0x44 ,0xFE ,0x82 ,0x82 ,0x44 ,0x38 ,0xFE ,0x92 ,0x92 ,0x82 ,0x82 ,0xFE ,0x12 ,
+0x12 ,0x02 ,0x02 ,0x7C ,0x92 ,0x92 ,0x92 ,0x74 ,0xFE ,0x10 ,0x10 ,0x10 ,0xFE ,0x82 ,0x82 ,0xFE ,
+0x82 ,0x82 ,0x40 ,0x80 ,0x80 ,0x80 ,0x7E ,0xFE ,0x10 ,0x28 ,0x44 ,0x82 ,0xFE ,0x80 ,0x80 ,0x80 ,
+0x00 ,0xFE ,0x04 ,0x08 ,0x04 ,0xFE ,0xFE ,0x04 ,0x18 ,0x20 ,0xFE ,0x7C ,0x82 ,0x82 ,0x82 ,0x7C ,
+0xFE ,0x12 ,0x12 ,0x12 ,0x0C ,0x7C ,0x82 ,0xA2 ,0xC2 ,0xFC ,0xFE ,0x12 ,0x32 ,0x52 ,0x8C ,0x4C ,
+0x92 ,0x92 ,0x92 ,0x64 ,0x02 ,0x02 ,0xFE ,0x02 ,0x02 ,0x7E ,0x80 ,0x80 ,0x80 ,0x7E ,0x3E ,0x40 ,
+0x80 ,0x40 ,0x3E ,0xFE ,0x40 ,0x20 ,0x40 ,0xFE ,0xC6 ,0x28 ,0x10 ,0x28 ,0xC6 ,0x02 ,0x04 ,0xF8 ,
+0x04 ,0x02 ,0xC2 ,0xA2 ,0x92 ,0x8A ,0x86 ,0xFE ,0x82 ,0x82 ,0x00 ,0x00 ,0x02 ,0x0C ,0x30 ,0xC0 ,
+0x00 ,0x82 ,0x82 ,0xFE ,0x00 ,0x00 ,0x04 ,0x02 ,0x04 ,0x00 ,0x00 ,0x80 ,0x80 ,0x80 ,0x80 ,0x80 ,
+0x06 ,0x08 ,0x00 ,0x00 ,0x00 ,0x70 ,0x88 ,0x88 ,0x70 ,0x80 ,0xFC ,0x90 ,0x90 ,0x60 ,0x00 ,0x70 ,
+0x88 ,0x88 ,0x88 ,0x00 ,0x60 ,0x90 ,0x90 ,0x7C ,0x80 ,0x70 ,0xA8 ,0xA8 ,0x90 ,0x00 ,0x10 ,0xF8 ,
+0x14 ,0x04 ,0x00 ,0x98 ,0xA4 ,0xA4 ,0x78 ,0x00 ,0xFC ,0x20 ,0x10 ,0xE0 ,0x00 ,0xE8 ,0x00 ,0x00 ,
+0x00 ,0x00 ,0x40 ,0x80 ,0x80 ,0x74 ,0x00 ,0xFC ,0x20 ,0x50 ,0x88 ,0x00 ,0xFC ,0x00 ,0x00 ,0x00 ,
+0x00 ,0xF0 ,0x08 ,0x30 ,0x08 ,0xF0 ,0xF8 ,0x08 ,0x08 ,0xF0 ,0x00 ,0x70 ,0x88 ,0x88 ,0x70 ,0x00 ,
+0xF8 ,0x24 ,0x24 ,0x18 ,0x00 ,0x18 ,0x24 ,0x24 ,0xF8 ,0x00 ,0xF0 ,0x08 ,0x08 ,0x10 ,0x00 ,0x90 ,
+0xA8 ,0xA8 ,0x48 ,0x00 ,0x08 ,0x7C ,0x88 ,0x00 ,0x00 ,0x78 ,0x80 ,0x80 ,0x78 ,0x00 ,0x38 ,0x40 ,
+0x80 ,0x40 ,0x38 ,0x78 ,0x80 ,0x40 ,0x80 ,0x78 ,0x88 ,0x50 ,0x20 ,0x50 ,0x88 ,0x08 ,0x10 ,0xE0 ,
+0x10 ,0x08 ,0xC8 ,0xA8 ,0x98 ,0x00 ,0x00 ,0x10 ,0x6C ,0x82 ,0x00 ,0x00 ,0xFE ,0x00 ,0x00 ,0x00 ,
+0x00 ,0x82 ,0x6C ,0x10 ,0x00 ,0x00 ,0x08 ,0x04 ,0x08 ,0x10 ,0x08 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00  };
+
+BYTE CharacterWidthTable_Font5x7   [128] = {
+0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,
+0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,
+0x05 ,0x01 ,0x03 ,0x05 ,0x05 ,0x05 ,0x05 ,0x01 ,0x02 ,0x02 ,0x05 ,0x05 ,0x02 ,0x05 ,0x01 ,0x04 ,
+0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x01 ,0x01 ,0x04 ,0x04 ,0x04 ,0x05 ,
+0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x04 ,0x05 ,0x05 ,0x05 ,
+0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x03 ,0x04 ,0x05 ,0x03 ,0x05 ,
+0x02 ,0x05 ,0x04 ,0x04 ,0x05 ,0x04 ,0x04 ,0x04 ,0x04 ,0x01 ,0x04 ,0x04 ,0x01 ,0x05 ,0x04 ,0x05 ,
+0x05 ,0x05 ,0x04 ,0x04 ,0x03 ,0x04 ,0x05 ,0x05 ,0x05 ,0x05 ,0x03 ,0x03 ,0x01 ,0x05 ,0x05 ,0x05  };
+
+#define FONT3x5_FONT_WIDTH 3
+#define FONT3x5_FONT_HEIGHT 5
+#define FONT3x5_ELEMENTS 128
+#define FONT3x5_FONT_COLUMN_SIZE_IN_BYTE  1
+
+
+BYTE FontTable_Font3x5 [384] = {
+0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,
+0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,
+0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,
+0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,
+0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,
+0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,
+0x00 ,0x00 ,0x00 ,0x17 ,0x00 ,0x00 ,0x03 ,0x00 ,0x03 ,0x0E ,0x1F ,0x0E ,0x14 ,0x1F ,0x0A ,0x00 ,
+0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x03 ,0x00 ,0x00 ,0x0E ,0x11 ,0x00 ,0x11 ,0x0E ,0x00 ,0x15 ,0x0E ,
+0x15 ,0x04 ,0x0E ,0x04 ,0x10 ,0x08 ,0x00 ,0x04 ,0x04 ,0x04 ,0x10 ,0x00 ,0x00 ,0x18 ,0x04 ,0x03 ,
+0x0E ,0x11 ,0x0E ,0x12 ,0x1F ,0x10 ,0x19 ,0x15 ,0x16 ,0x11 ,0x15 ,0x0A ,0x07 ,0x04 ,0x1F ,0x17 ,
+0x15 ,0x09 ,0x1E ,0x15 ,0x18 ,0x01 ,0x1D ,0x03 ,0x1B ,0x15 ,0x1B ,0x06 ,0x15 ,0x0E ,0x0A ,0x00 ,
+0x00 ,0x10 ,0x0A ,0x00 ,0x04 ,0x0A ,0x11 ,0x00 ,0x00 ,0x00 ,0x11 ,0x0A ,0x04 ,0x01 ,0x15 ,0x02 ,
+0x09 ,0x15 ,0x0E ,0x1E ,0x05 ,0x1E ,0x1F ,0x15 ,0x0A ,0x0E ,0x11 ,0x0A ,0x1F ,0x11 ,0x0E ,0x1F ,
+0x15 ,0x11 ,0x1F ,0x05 ,0x05 ,0x1E ,0x15 ,0x1D ,0x1F ,0x04 ,0x1F ,0x11 ,0x1F ,0x11 ,0x08 ,0x10 ,
+0x0F ,0x1F ,0x06 ,0x19 ,0x1F ,0x10 ,0x10 ,0x1F ,0x02 ,0x1F ,0x1F ,0x06 ,0x1F ,0x1F ,0x11 ,0x1F ,
+0x1F ,0x05 ,0x07 ,0x1F ,0x19 ,0x1F ,0x1F ,0x0D ,0x16 ,0x16 ,0x15 ,0x1D ,0x01 ,0x1F ,0x01 ,0x1F ,
+0x10 ,0x1F ,0x0F ,0x10 ,0x0F ,0x1F ,0x08 ,0x1F ,0x1B ,0x04 ,0x1B ,0x01 ,0x1E ,0x01 ,0x19 ,0x15 ,
+0x13 ,0x1F ,0x11 ,0x00 ,0x03 ,0x0C ,0x10 ,0x11 ,0x1F ,0x00 ,0x02 ,0x01 ,0x02 ,0x10 ,0x10 ,0x10 ,
+0x01 ,0x02 ,0x00 ,0x08 ,0x14 ,0x1C ,0x1F ,0x14 ,0x08 ,0x0C ,0x12 ,0x12 ,0x08 ,0x14 ,0x1F ,0x0C ,
+0x16 ,0x16 ,0x14 ,0x0E ,0x05 ,0x06 ,0x15 ,0x0F ,0x1F ,0x04 ,0x18 ,0x1D ,0x00 ,0x00 ,0x10 ,0x0D ,
+0x00 ,0x1F ,0x0C ,0x12 ,0x1F ,0x00 ,0x00 ,0x1C ,0x08 ,0x1C ,0x1C ,0x02 ,0x1C ,0x0C ,0x12 ,0x0C ,
+0x1E ,0x05 ,0x02 ,0x02 ,0x05 ,0x1E ,0x1C ,0x02 ,0x04 ,0x14 ,0x1A ,0x00 ,0x04 ,0x1E ,0x04 ,0x1E ,
+0x10 ,0x1E ,0x0E ,0x10 ,0x0E ,0x1C ,0x08 ,0x1C ,0x12 ,0x0C ,0x12 ,0x12 ,0x0C ,0x02 ,0x12 ,0x1A ,
+0x16 ,0x04 ,0x0E ,0x11 ,0x1F ,0x00 ,0x00 ,0x11 ,0x0E ,0x04 ,0x02 ,0x02 ,0x04 ,0x00 ,0x00 ,0x00  };
+
+
+BYTE CharacterWidthTable_Font3x5 [128] = {
+0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,
+0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,
+0x03 ,0x01 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x01 ,0x02 ,0x03 ,0x03 ,0x03 ,0x02 ,0x03 ,0x01 ,0x03 ,
+0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x01 ,0x02 ,0x03 ,0x03 ,0x03 ,0x03 ,
+0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,
+0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x02 ,0x03 ,0x02 ,0x03 ,0x03 ,
+0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x01 ,0x03 ,0x03 ,0x01 ,0x03 ,0x03 ,0x03 ,
+0x03 ,0x03 ,0x03 ,0x02 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x01 ,0x03 ,0x03 ,0x03  };
+
+GFXFont Font5x7;
+GFXFont Font3x5;
+
+void GFX_Init()
+{
+    
+    //Staticially Allocate and setup the backbuffer space;
+    
+    BackBuffer.RenderPlane.BitPlaneSpace = &BackBufferRenderPlaneSpace[0];
+   
+    BackBuffer.SizeX = BACK_BUFFER_SIZE_X;
+    BackBuffer.SizeY = BACK_BUFFER_SIZE_Y;
+
+    BackBuffer.RenderPlane.SizeX = BACK_BUFFER_SIZE_X;
+    BackBuffer.RenderPlane.SizeY = BACK_BUFFER_SIZE_Y;
+
+    
+    GFX_FullDisplayBufferClear(&BackBuffer);
+
+    //Initialize the stock fonts
+
+    Font5x7.CharacterWidthTable = (BYTE *)CharacterWidthTable_Font5x7;
+    Font5x7.FontBuffer = (BYTE *)FontTable_Font5x7;
+    Font5x7.FontHeight = FONT5x7_FONT_HEIGHT;
+    Font5x7.FontWidth = FONT5x7_FONT_WIDTH;
+    Font5x7.BytesPerColumn = FONT5x7_FONT_COLUMN_SIZE_IN_BYTE;
+
+    Font3x5.CharacterWidthTable = (BYTE *)CharacterWidthTable_Font3x5;
+    Font3x5.FontBuffer = (BYTE *)FontTable_Font3x5;
+    Font3x5.FontHeight = FONT3x5_FONT_HEIGHT;
+    Font3x5.FontWidth = FONT3x5_FONT_WIDTH;
+    Font3x5.BytesPerColumn = FONT3x5_FONT_COLUMN_SIZE_IN_BYTE;
+    
+    GFX_InitPhysicalScreen();
+    
+}
+
+
+
+void GFX_FullDisplayBufferClear(RenderContext *Image)
+{
+    BitPlane_Clear(&Image->RenderPlane);
+}
+
+
+void GFX_PutPixel(RenderContext *Image, SIGNED_WORD x, SIGNED_WORD y)
+{
+    if((x<Image->SizeX) && (y<Image->SizeY) && (x>=0) && (y>=0))
+    {
+         BitPlane_Put(&Image->RenderPlane,x,y,TRUE);
+    }
+}
+
+
+
+#ifndef _INLINE_GFX_GET_PIXEL
+BYTE GFX_GetPixel(RenderContext *Image, SIGNED_WORD x, SIGNED_WORD y)
+{
+    BYTE PixelColor = 0;
+    
+    if((x<Image->SizeX) && (y<Image->SizeY) && (x>=0) && (y>=0))
+    {
+        
+        if(BitPlane_Get(&Image->RedBitPlane,x,y))
+            PixelColor |= BICOLOR_RED;
+            
+        if(BitPlane_Get(&Image->GreenBitPlane,x,y))
+            PixelColor |= BICOLOR_GREEN;
+    }
+    
+    return PixelColor;
+}
+#endif
+
+
+void GFX_DrawHline(RenderContext *Image, SIGNED_WORD XStart, SIGNED_WORD XStop, SIGNED_WORD Y)
+{
+    SIGNED_WORD LineStart;
+    SIGNED_WORD LineStop;
+    WORD i;
+    
+    if((Y<Image->SizeY)  && (Y>=0))
+    {
+        if(XStart>XStop)
+        {
+            LineStart = XStop;    
+            LineStop = XStart;
+        }    
+        else
+        {
+            LineStart = XStart;    
+            LineStop = XStop;
+        }
+        
+        if(LineStart<0)
+        {
+            LineStart = 0;
+        }
+    
+        if(LineStop>Image->SizeX)
+        {
+            LineStop =     Image->SizeX-1;
+        }
+    
+        if(LineStart == LineStop)
+        {
+            GFX_PutPixel(Image,LineStart,Y);    
+        }
+        else
+        {
+            for(i=LineStart; i<=LineStop ; i++)
+            {
+                GFX_PutPixel(Image,i,Y);    
+            }
+        }    
+    }    
+    
+}
+
+
+
+ void GFX_DrawVline(RenderContext *Image, SIGNED_WORD YStart, SIGNED_WORD YStop, SIGNED_WORD X)
+{
+    SIGNED_WORD LineStart;
+    SIGNED_WORD LineStop;
+    SIGNED_WORD i;
+
+    if((X<Image->SizeX) && (X>=0))
+    {
+    
+        if(YStart>YStop)
+        {
+            LineStart = YStop;    
+            LineStop = YStart;
+        }    
+        else
+        {
+            LineStart = YStart;    
+            LineStop = YStop;
+        }
+        
+        if(LineStart<0)
+        {
+            LineStart = 0;
+        }
+    
+
+        if(LineStop>Image->SizeY)
+        {
+            LineStop =     Image->SizeY-1;
+        }
+    
+        for(i=LineStart; i<=LineStop ; i++)
+        {
+            GFX_PutPixel(Image,X,i);    
+        }    
+    }    
+}
+
+
+void GFX_DrawLine(RenderContext * Image, SIGNED_WORD X1,SIGNED_WORD Y1, SIGNED_WORD X2,SIGNED_WORD Y2)
+{
+    //A simple Implementation of Bresenham's line Algorithm
+    SIGNED_WORD StartX,StopX,StartY,StopY;
+    SIGNED_WORD dX,dY;
+    SIGNED_WORD Y_Numerator;
+    SIGNED_WORD X_Numerator;
+    SIGNED_WORD Y;
+    SIGNED_WORD X;
+    SIGNED_WORD i;
+    BOOL YDir = 0;
+    //First Make sure that it is left to right
+    //If not them flop them
+    if(X2>X1)
+    {
+        StartX = X1;
+        StopX = X2;    
+        StartY = Y1;
+        StopY = Y2;    
+    }    
+    else
+    {
+        StartX = X2;
+        StopX = X1;    
+        StartY = Y2;
+        StopY = Y1;    
+    }
+    GFX_PutPixel(Image, StopX,StopY);
+    if(StopY>=StartY)
+    {
+        dY = StopY - StartY;
+        YDir = 0;
+    }
+    else
+    {
+        dY = StartY - StopY;
+        YDir = 1;
+    }
+    dX = StopX - StartX;
+    //Now, if the slope is less greater than one,  we need to swap all X/Y operations
+    if(dY<=dX)
+    {
+        //Slope is less than one, proceed at normal and step along the x axis
+        Y=StartY;   //start the whole part of the Y value at the starting pixeel.
+        X=StartX;
+        //We need to start the numerator of the fraction half way through the fraction so evertyhing rounds at
+        //fraction midpoint
+        Y_Numerator = dX>>1;   //The fraction demonimator is assumeed to be dX
+                                // out fixed point Y value is  Y + (Y_Numerator / dX)
+                                //Every time we step the X coordinate by one, we need to step
+                                //out Y coordinate by dY/dX.  We do this by just adding dY to our
+                                //numerator.  When the numerator gets bigger than the
+                                //denomiator, the increment the whole part by one and decrement the numerator
+                                //by the denominator
+        for(i=0;i<dX;i++)
+        {
+            GFX_PutPixel(Image,X,Y);
+            X++;
+            //Now do all the fractional stuff
+            Y_Numerator += dY;
+            if(Y_Numerator >= dX)
+            {    
+                Y_Numerator-=dX;
+                if(StopY > StartY)
+                {
+                    Y++;
+                }
+                else
+                {
+                    Y--;    
+                }
+            }
+        }
+    }
+    else
+    {
+        //Same as before by step along the y axis.    
+        Y=StartY;   
+        X=StartX;
+        X_Numerator = dY>>1;   
+        for(i=0;i<dY;i++)
+        {
+            GFX_PutPixel(Image,X,Y);
+            //Now do all the fractional stuff
+            if(YDir)
+            {
+                Y--;
+            }
+            else
+            {
+                Y++;
+            }
+            X_Numerator += dX;
+            if(X_Numerator >= dY)
+            {    
+                X_Numerator-=dY;
+                if(StopX > StartX)
+                {
+                    X++;
+                }
+                else
+                {
+                    X--;    
+                }
+            }
+        }
+    }
+}
+
+
+
+
+
+void GFX_DrawBox(RenderContext *Image, GFXDisplayBox *Box)
+{
+    GFX_DrawHline(Image,Box->P1.X,Box->P2.X,Box->P1.Y);
+    GFX_DrawHline(Image,Box->P1.X,Box->P2.X,Box->P2.Y);
+    GFX_DrawVline(Image,Box->P1.Y,Box->P2.Y,Box->P1.X);
+    GFX_DrawVline(Image,Box->P1.Y,Box->P2.Y,Box->P2.X);
+}
+
+
+
+SIGNED_WORD GFX_DrawCharacter(RenderContext * Image,BYTE Character,SIGNED_WORD StartX, SIGNED_WORD StartY, GFXFont * MyFont)
+{
+    BYTE i,j,Mask;
+    WORD CharStartIndex,ColumnStartIndex,ByteOffset;
+
+    CharStartIndex = (Character * (MyFont->BytesPerColumn) * (MyFont->FontWidth));
+
+    for(j=0;j<MyFont->CharacterWidthTable[Character];j++)
+        {
+            //Draw the current slice
+            ColumnStartIndex = j* (MyFont->BytesPerColumn);
+
+            for(i=0;i<MyFont->FontHeight;i++)
+            {
+                ByteOffset = i>>3;
+                Mask = 0x01 << (i&0x07);
+            
+                if( (MyFont->FontBuffer[CharStartIndex + ColumnStartIndex + ByteOffset]) & Mask)
+                {
+                    GFX_PutPixel(Image, StartX, StartY + i);
+                }        
+            }
+          StartX++;
+        }
+    return StartX;
+}
+
+
+SIGNED_WORD GFX_GetStringWidth(CHAR * String,GFXFont * MyFont)
+{
+    BYTE Ptr = 0;
+    BYTE NextChar;
+    SIGNED_WORD StringSize = 0;
+    
+    NextChar = String[Ptr];
+    Ptr++;
+    
+    while((NextChar!=0) && (Ptr <GFX_MAX_STRING_LEN))
+    {
+        StringSize += MyFont->CharacterWidthTable[NextChar] + 1;
+        NextChar = String[Ptr];
+        Ptr++;
+    }
+    
+    return StringSize;
+}
+
+void GFX_DrawCenteredString(RenderContext * Image,CHAR * String,SIGNED_WORD StartX, SIGNED_WORD StartY, GFXFont * MyFont)
+{
+    StartX -= (GFX_GetStringWidth(String,MyFont)>>1);
+    GFX_DrawString(Image,String,StartX,StartY,MyFont);
+}
+
+void GFX_DrawString(RenderContext * Image,CHAR * String,SIGNED_WORD StartX, SIGNED_WORD StartY, GFXFont * MyFont)
+{
+
+BYTE Ptr = 0;
+BYTE NextChar;
+
+NextChar = String[Ptr];
+
+    while((NextChar!=0) && (Ptr <GFX_MAX_STRING_LEN))
+    {
+        StartX = GFX_DrawCharacter(Image,NextChar,StartX,StartY,MyFont);
+        Ptr++;
+        NextChar = String[Ptr];
+        StartX++;
+    }
+
+}
+
+
+CHAR GFXStringBuf[64];
+
+void  GFX_printf(RenderContext * Image,SIGNED_WORD StartX, SIGNED_WORD StartY, GFXFont * MyFont, const char *FormatString,...)
+{
+     va_list argptr; 
+     va_start(argptr,FormatString); 
+     vsprintf((CHAR *)GFXStringBuf,FormatString,argptr);
+     va_end(argptr);   
+     
+     GFX_DrawString(Image,GFXStringBuf,StartX,StartY,MyFont);
+}
+
+
+
+void GFX_DrawListPrimitive(RenderContext * Image,GFXListPrimitive *LP)
+{
+    BYTE Points;
+    BYTE i;
+    
+    if(LP->NumPoints >1)
+    {    
+
+        switch(LP->DrawMode)
+        {
+
+        default:
+        case GFX_LIST_PRIMITIVE_CLOSED:
+             for(i=1;i<LP->NumPoints;i++)
+                    {
+                        GFX_DrawLine(Image,(SIGNED_WORD)(LP->PointList[i-1].X + LP->Center.X),(SIGNED_WORD)(LP->PointList[i-1].Y + LP->Center.Y),
+                                          (SIGNED_WORD)(LP->PointList[i].X + LP->Center.X),(SIGNED_WORD)(LP->PointList[i].Y + LP->Center.Y));
+                    }
+                        GFX_DrawLine(Image,(SIGNED_WORD)(LP->PointList[LP->NumPoints-1].X + LP->Center.X),(SIGNED_WORD)(LP->PointList[LP->NumPoints-1].Y + LP->Center.Y),
+                                          (SIGNED_WORD)(LP->PointList[0].X + LP->Center.X),(SIGNED_WORD)(LP->PointList[0].Y + LP->Center.Y));
+            break;
+
+        case GFX_LIST_PRIMITIVE_CONNECTED:
+            for(i=1;i<LP->NumPoints;i++)
+                    {
+                        GFX_DrawLine(Image,(SIGNED_WORD)(LP->PointList[i-1].X + LP->Center.X),(SIGNED_WORD)(LP->PointList[i-1].Y + LP->Center.Y),
+                                          (SIGNED_WORD)(LP->PointList[i].X + LP->Center.X),(SIGNED_WORD)(LP->PointList[i].Y + LP->Center.Y));
+                    }
+            break;
+
+        case GFX_LIST_PRIMITIVE_DISCONNECTED:
+                    Points = LP->NumPoints>>1;
+                    for(i=0;i<Points;i++)
+                    {
+                        GFX_DrawLine(Image,(SIGNED_WORD)(LP->PointList[i*2].X + LP->Center.X),(SIGNED_WORD)(LP->PointList[i*2].Y + LP->Center.Y),
+                                          (SIGNED_WORD)(LP->PointList[i*2+1].X + LP->Center.X),(SIGNED_WORD)(LP->PointList[i*2+1].Y + LP->Center.Y));
+                    }
+            break;
+            
+        case GFX_LIST_PRIMITIVE_CLOSED_YFLIPPED:
+             for(i=1;i<LP->NumPoints;i++)
+                    {
+                        GFX_DrawLine(Image,(SIGNED_WORD)(LP->PointList[i-1].X + LP->Center.X),(SIGNED_WORD)(-LP->PointList[i-1].Y + LP->Center.Y),
+                                          (SIGNED_WORD)(LP->PointList[i].X + LP->Center.X),(SIGNED_WORD)(-LP->PointList[i].Y + LP->Center.Y));
+                    }
+                        GFX_DrawLine(Image,(SIGNED_WORD)(LP->PointList[LP->NumPoints-1].X + LP->Center.X),(SIGNED_WORD)(-LP->PointList[LP->NumPoints-1].Y + LP->Center.Y),
+                                          (SIGNED_WORD)(LP->PointList[0].X + LP->Center.X),(SIGNED_WORD)(-LP->PointList[0].Y + LP->Center.Y));
+            break;
+
+        case GFX_LIST_PRIMITIVE_CONNECTED_YFLIPPED:
+            for(i=1;i<LP->NumPoints;i++)
+                    {
+                        GFX_DrawLine(Image,(SIGNED_WORD)(LP->PointList[i-1].X + LP->Center.X),(SIGNED_WORD)(-LP->PointList[i-1].Y + LP->Center.Y),
+                                          (SIGNED_WORD)(LP->PointList[i].X + LP->Center.X),(SIGNED_WORD)(-LP->PointList[i].Y + LP->Center.Y));
+                    }
+            break;
+
+        case GFX_LIST_PRIMITIVE_DISCONNECTED_YFLIPPED:
+                    Points = LP->NumPoints>>1;
+                    for(i=0;i<Points;i++)
+                    {
+                        GFX_DrawLine(Image,(SIGNED_WORD)(LP->PointList[i*2].X + LP->Center.X),(SIGNED_WORD)(-LP->PointList[i*2].Y + LP->Center.Y),
+                                          (SIGNED_WORD)(LP->PointList[i*2+1].X + LP->Center.X),(SIGNED_WORD)(-LP->PointList[i*2+1].Y + LP->Center.Y));
+                    }
+            break;
+
+        }
+    }
+}
+
+
+
+
+void GFX_DrawScaledListPrimitive(RenderContext * Image,GFXListPrimitive *LP , FIXED_7_8 Scale)
+{
+    BYTE Points;
+    BYTE i;
+    GFXRelativePoint TransformedPoint[2] = {0};
+
+    if(LP->NumPoints >1)
+    {    
+        switch(LP->DrawMode)
+        {
+
+        default:
+        case GFX_LIST_PRIMITIVE_CLOSED:
+             for(i=1;i<LP->NumPoints;i++)
+                    {
+
+                    TransformedPoint[0].X = FMul_15_0to7_8(LP->PointList[i-1].X,Scale)     + LP->Center.X;
+                    TransformedPoint[0].Y = FMul_15_0to7_8(LP->PointList[i-1].Y,Scale)   + LP->Center.Y;
+                    TransformedPoint[1].X = FMul_15_0to7_8(LP->PointList[i].X,Scale)     + LP->Center.X;
+                    TransformedPoint[1].Y = FMul_15_0to7_8(LP->PointList[i].Y,Scale)     + LP->Center.Y;
+
+                    GFX_DrawLine(Image,TransformedPoint[0].X,TransformedPoint[0].Y,
+                                      TransformedPoint[1].X,TransformedPoint[1].Y);
+
+                     }
+
+                     TransformedPoint[0].X = FMul_15_0to7_8(LP->PointList[LP->NumPoints-1].X,Scale)   + LP->Center.X;
+                     TransformedPoint[0].Y = FMul_15_0to7_8(LP->PointList[LP->NumPoints-1].Y,Scale)   + LP->Center.Y;
+                     TransformedPoint[1].X = FMul_15_0to7_8(LP->PointList[0].X,Scale)                 + LP->Center.X;
+                     TransformedPoint[1].Y = FMul_15_0to7_8(LP->PointList[0].Y,Scale)                 + LP->Center.Y;
+
+                     GFX_DrawLine(Image,TransformedPoint[0].X,TransformedPoint[0].Y,
+                                      TransformedPoint[1].X,TransformedPoint[1].Y);
+
+            break;
+
+        case GFX_LIST_PRIMITIVE_CONNECTED:
+            for(i=1;i<LP->NumPoints;i++)
+                    {
+                        TransformedPoint[0].X = FMul_15_0to7_8(LP->PointList[i-1].X,Scale)     + LP->Center.X;
+                        TransformedPoint[0].Y = FMul_15_0to7_8(LP->PointList[i-1].Y,Scale)   + LP->Center.Y;
+                        TransformedPoint[1].X = FMul_15_0to7_8(LP->PointList[i].X,Scale)     + LP->Center.X;
+                        TransformedPoint[1].Y = FMul_15_0to7_8(LP->PointList[i].Y,Scale)     + LP->Center.Y;
+                        
+                        GFX_DrawLine(Image,TransformedPoint[0].X,TransformedPoint[0].Y,
+                                      TransformedPoint[1].X,TransformedPoint[1].Y);
+                    }
+            break;
+
+        case GFX_LIST_PRIMITIVE_DISCONNECTED:
+                    Points = LP->NumPoints>>1;
+                    
+                    for(i=0;i<Points;i++)
+                    {
+                        TransformedPoint[0].X = FMul_15_0to7_8(LP->PointList[i*2].X,Scale)        + LP->Center.X;
+                        TransformedPoint[0].Y = FMul_15_0to7_8(LP->PointList[i*2].Y,Scale)        + LP->Center.Y;
+                        TransformedPoint[1].X = FMul_15_0to7_8(LP->PointList[(i*2)+1].X,Scale)   + LP->Center.X;
+                        TransformedPoint[1].Y = FMul_15_0to7_8(LP->PointList[(i*2)+1].Y,Scale)   + LP->Center.Y;
+
+                        GFX_DrawLine(Image,TransformedPoint[0].X,TransformedPoint[0].Y,
+                                      TransformedPoint[1].X,TransformedPoint[1].Y);
+                    }
+            break;
+
+        }
+
+    }
+
+}
+
+void GFX_DrawRotatedListPrimitive(RenderContext * Image,GFXListPrimitive *LP , BYTE Angle, BYTE Color)
+{
+    BYTE Points;
+    BYTE i;
+
+    GFXRelativePoint TransformedPoint[2] = {0};
+
+    if(LP->NumPoints >1)
+    {
+        //If we are drawing non connected points,  there must be an even number of them.
+        switch(LP->DrawMode)
+        {
+            case GFX_LIST_PRIMITIVE_DISCONNECTED:
+    
+                Points = LP->NumPoints>>1;
+                
+                for(i=0;i<Points;i++)
+                {
+    
+                    TransformedPoint[0].X = FMul_15_0to1_14((LP->PointList[i*2].X), Fixed_1_14_SineTable[(Angle + 64)&0xff]) - 
+                                            FMul_15_0to1_14(LP->PointList[i*2].Y, Fixed_1_14_SineTable[Angle]);
+    
+                    TransformedPoint[0].Y = FMul_15_0to1_14(LP->PointList[i*2].X, Fixed_1_14_SineTable[Angle ]) + 
+                                            FMul_15_0to1_14(LP->PointList[i*2].Y, Fixed_1_14_SineTable[(Angle + 64)&0xff]);
+    
+                    TransformedPoint[1].X = FMul_15_0to1_14(LP->PointList[(i*2)+1].X, Fixed_1_14_SineTable[(Angle + 64)&0xff]) - 
+                                            FMul_15_0to1_14(LP->PointList[(i*2)+1].Y, Fixed_1_14_SineTable[Angle]);
+    
+                    TransformedPoint[1].Y = FMul_15_0to1_14(LP->PointList[(i*2)+1].X, Fixed_1_14_SineTable[Angle]) + 
+                                            FMul_15_0to1_14(LP->PointList[(i*2)+1].Y, Fixed_1_14_SineTable[(Angle + 64)&0xff]);
+    
+    
+                    TransformedPoint[0].X += LP->Center.X;
+                    TransformedPoint[0].Y += LP->Center.Y;
+                    TransformedPoint[1].X += LP->Center.X;
+                    TransformedPoint[1].Y += LP->Center.Y;
+    
+    
+                    GFX_DrawLine(Image,(TransformedPoint[0].X + LP->Center.X),(TransformedPoint[0].Y  + LP->Center.Y),
+                                      (TransformedPoint[1].X + LP->Center.X),(TransformedPoint[1].Y + LP->Center.Y));
+                }
+            break;
+        
+            case GFX_LIST_PRIMITIVE_CONNECTED:
+            
+                for(i=1;i<LP->NumPoints;i++)
+                {
+    
+                    TransformedPoint[0].X = (FMul_15_0to1_14(LP->PointList[i-1].X, Fixed_1_14_SineTable[(Angle + 64)&0xff]) - 
+                                            FMul_15_0to1_14(LP->PointList[i-1].Y, Fixed_1_14_SineTable[Angle])  );
+    
+                    TransformedPoint[0].Y = ( FMul_15_0to1_14(LP->PointList[i-1].X, Fixed_1_14_SineTable[Angle]) + 
+                                            FMul_15_0to1_14(LP->PointList[i-1].Y, Fixed_1_14_SineTable[(Angle + 64)&0xff] ) );
+    
+                    TransformedPoint[1].X = (FMul_15_0to1_14(LP->PointList[i].X, Fixed_1_14_SineTable[(Angle + 64)&0xff]) - 
+                                             FMul_15_0to1_14(LP->PointList[i].Y, Fixed_1_14_SineTable[Angle]) );
+    
+                    TransformedPoint[1].Y = (FMul_15_0to1_14(LP->PointList[i].X, Fixed_1_14_SineTable[Angle]) + 
+                                            FMul_15_0to1_14(LP->PointList[i].Y, Fixed_1_14_SineTable[(Angle + 64)&0xff]));
+                    
+                    TransformedPoint[0].X +=  LP->Center.X;
+                    TransformedPoint[0].Y +=  LP->Center.Y;
+                    TransformedPoint[1].X +=  LP->Center.X;
+                    TransformedPoint[1].Y +=  LP->Center.Y;
+    
+                    GFX_DrawLine(Image,(TransformedPoint[0].X),(TransformedPoint[0].Y),
+                                      (TransformedPoint[1].X),(TransformedPoint[1].Y));
+    
+                }
+            break;
+            default:
+            case GFX_LIST_PRIMITIVE_CLOSED:
+                
+                    for(i=1;i<LP->NumPoints;i++)
+                    {
+        
+                        TransformedPoint[0].X = (FMul_15_0to1_14(LP->PointList[i-1].X, Fixed_1_14_SineTable[(Angle + 64)&0xff]) - 
+                                                FMul_15_0to1_14(LP->PointList[i-1].Y, Fixed_1_14_SineTable[Angle])  );
+        
+                        TransformedPoint[0].Y = ( FMul_15_0to1_14(LP->PointList[i-1].X, Fixed_1_14_SineTable[Angle]) + 
+                                                FMul_15_0to1_14(LP->PointList[i-1].Y, Fixed_1_14_SineTable[(Angle + 64)&0xff] ) );
+        
+                        TransformedPoint[1].X = (FMul_15_0to1_14(LP->PointList[i].X, Fixed_1_14_SineTable[(Angle + 64)&0xff]) - 
+                                                 FMul_15_0to1_14(LP->PointList[i].Y, Fixed_1_14_SineTable[Angle]) );
+        
+                        TransformedPoint[1].Y = (FMul_15_0to1_14(LP->PointList[i].X, Fixed_1_14_SineTable[Angle]) + 
+                                                FMul_15_0to1_14(LP->PointList[i].Y, Fixed_1_14_SineTable[(Angle + 64)&0xff]));
+                        
+                        TransformedPoint[0].X +=  LP->Center.X;
+                        TransformedPoint[0].Y +=  LP->Center.Y;
+                        TransformedPoint[1].X +=  LP->Center.X;
+                        TransformedPoint[1].Y +=  LP->Center.Y;
+        
+                        GFX_DrawLine(Image,(TransformedPoint[0].X),(TransformedPoint[0].Y),
+                                          (TransformedPoint[1].X),(TransformedPoint[1].Y));
+                    }
+                    
+                        TransformedPoint[0].X = (FMul_15_0to1_14(LP->PointList[LP->NumPoints-1].X, Fixed_1_14_SineTable[(Angle + 64)&0xff]) - 
+                                                FMul_15_0to1_14(LP->PointList[LP->NumPoints-1].Y, Fixed_1_14_SineTable[Angle])  );
+        
+                        TransformedPoint[0].Y = ( FMul_15_0to1_14(LP->PointList[LP->NumPoints-1].X, Fixed_1_14_SineTable[Angle]) + 
+                                                FMul_15_0to1_14(LP->PointList[LP->NumPoints-1].Y, Fixed_1_14_SineTable[(Angle + 64)&0xff] ) );
+        
+                        TransformedPoint[1].X = (FMul_15_0to1_14(LP->PointList[0].X, Fixed_1_14_SineTable[(Angle + 64)&0xff]) - 
+                                                 FMul_15_0to1_14(LP->PointList[0].Y, Fixed_1_14_SineTable[Angle]) );
+        
+                        TransformedPoint[1].Y = (FMul_15_0to1_14(LP->PointList[0].X, Fixed_1_14_SineTable[Angle]) + 
+                                                FMul_15_0to1_14(LP->PointList[0].Y, Fixed_1_14_SineTable[(Angle + 64)&0xff]));
+                        
+                        TransformedPoint[0].X +=  LP->Center.X;
+                        TransformedPoint[0].Y +=  LP->Center.Y;
+                        TransformedPoint[1].X +=  LP->Center.X;
+                        TransformedPoint[1].Y +=  LP->Center.Y;
+        
+                        GFX_DrawLine(Image,(TransformedPoint[0].X),(TransformedPoint[0].Y),
+                                          (TransformedPoint[1].X),(TransformedPoint[1].Y));
+                break;
+        }
+    }
+}
+/*
+void GFX_DrawScaledRotatedListPrimitive(BiColorRenderContext * Image,GFXListPrimitive *LP , BYTE Angle,GFXFixed_7_8 Scale, BYTE Color)
+{
+    BYTE Points;
+    BYTE i;
+    
+    GFXRelativePoint TransformedPoint[2];
+
+    if(LP->NumPoints >1)
+    {
+        //If we are drawing non connected points,  there must be an even number of them.
+        if(LP->Connected == FALSE)
+        {
+            Points = LP->NumPoints>>1;
+            
+            for(i=0;i<Points;i++)
+            {
+
+                TransformedPoint[0].X = FMul_15_0to0_15(LP->PointList[i*2].X, Fixed_0_15_SineTable[(Angle + 64)&0xff]) - 
+                                        FMul_15_0to0_15(LP->PointList[i*2].Y, Fixed_0_15_SineTable[Angle]);
+
+                TransformedPoint[0].Y = FMul_15_0to0_15(LP->PointList[i*2].X, Fixed_0_15_SineTable[Angle ]) + 
+                                        FMul_15_0to0_15(LP->PointList[i*2].Y, Fixed_0_15_SineTable[(Angle + 64)&0xff]);
+
+                TransformedPoint[1].X = FMul_15_0to0_15(LP->PointList[(i*2)+1].X, Fixed_0_15_SineTable[(Angle + 64)&0xff]) - 
+                                        FMul_15_0to0_15(LP->PointList[(i*2)+1].Y, Fixed_0_15_SineTable[Angle]);
+
+                TransformedPoint[1].Y = FMul_15_0to0_15(LP->PointList[(i*2)+1].X, Fixed_0_15_SineTable[Angle ]) + 
+                                        FMul_15_0to0_15(LP->PointList[(i*2)+1].Y, Fixed_0_15_SineTable[(Angle + 64)&0xff]);
+
+
+                TransformedPoint[0].X = FMul_15_0to7_8(TransformedPoint[0].X,Scale) + LP->Center.X;
+                TransformedPoint[0].Y = FMul_15_0to7_8(TransformedPoint[0].Y,Scale)  + LP->Center.Y;
+                TransformedPoint[1].X = FMul_15_0to7_8(TransformedPoint[1].X,Scale) + LP->Center.X;
+                TransformedPoint[1].Y = FMul_15_0to7_8(TransformedPoint[1].Y,Scale)  + LP->Center.Y;
+
+                GFX_DrawLine(Image,(TransformedPoint[0].X),(TransformedPoint[0].Y),
+                                  (TransformedPoint[1].X),(TransformedPoint[1].Y),Color);
+            
+            }
+        
+        }
+        else
+        {
+            for(i=1;i<LP->NumPoints;i++)
+            {
+
+                TransformedPoint[0].X = (     FMul_15_0to0_15(LP->PointList[i-1].X, Fixed_0_15_SineTable[(Angle + 64)&0xff]) - 
+                                        FMul_15_0to0_15(LP->PointList[i-1].Y, Fixed_0_15_SineTable[Angle])  ) ;
+
+                TransformedPoint[0].Y = ( FMul_15_0to0_15(LP->PointList[i-1].X, Fixed_0_15_SineTable[Angle ]) + 
+                                        FMul_15_0to0_15(LP->PointList[i-1].Y, Fixed_0_15_SineTable[(Angle + 64)&0xff] ) );
+
+                TransformedPoint[1].X = (FMul_15_0to0_15(LP->PointList[i].X, Fixed_0_15_SineTable[(Angle + 64)&0xff]) - 
+                                         FMul_15_0to0_15(LP->PointList[i].Y, Fixed_0_15_SineTable[Angle]) ) ;
+
+                TransformedPoint[1].Y = (FMul_15_0to0_15(LP->PointList[i].X, Fixed_0_15_SineTable[Angle ]) + 
+                                        FMul_15_0to0_15(LP->PointList[i].Y, Fixed_0_15_SineTable[(Angle + 64)&0xff]) ) ;
+
+
+                TransformedPoint[0].X = FMul_15_0to7_8(TransformedPoint[0].X,Scale)  +    LP->Center.X;
+                TransformedPoint[0].Y = FMul_15_0to7_8(TransformedPoint[0].Y,Scale)+ LP->Center.Y;
+                TransformedPoint[1].X = FMul_15_0to7_8(TransformedPoint[1].X,Scale)  +    LP->Center.X;
+                TransformedPoint[1].Y = FMul_15_0to7_8(TransformedPoint[1].Y,Scale)+ LP->Center.Y;
+
+                GFX_DrawLine(Image,(TransformedPoint[0].X),(TransformedPoint[0].Y),
+                                  (TransformedPoint[1].X),(TransformedPoint[1].Y),Color);
+
+            }
+        
+        }
+    }
+}
+
+*/
+
+
diff -r 000000000000 -r 085749c8446f Code/KeyValue.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Code/KeyValue.c	Wed Jun 13 15:10:06 2012 +0000
@@ -0,0 +1,69 @@
+#include "System.h"
+
+
+CHAR Key[64];
+CHAR Value[64];
+
+BOOL KeyValueSplit(CHAR *LineBuf,CHAR *Key,CHAR *Value)
+{
+    BOOL FoundKey = FALSE;
+    
+    DWORD StringLength;
+    
+    
+    StringLength = strlen(LineBuf);
+    
+   
+    if(LineBuf[StringLength-3] == '\r' || LineBuf[StringLength-3] == '\n')
+    {
+        LineBuf[StringLength-3] = NULL;
+    }
+    
+    if(LineBuf[StringLength-2] == '\r' || LineBuf[StringLength-2] == '\n')
+    {
+        LineBuf[StringLength-2] = NULL;
+    }
+    
+    if(LineBuf[StringLength-1] == '\r' || LineBuf[StringLength-1] == '\n')
+    {
+        LineBuf[StringLength-1] = NULL;
+    }
+    
+    while(*LineBuf!=NULL)
+    {
+        if(FoundKey == FALSE)
+        {
+            if(*LineBuf > 32)
+            {
+               if(*LineBuf == '=')
+               {
+                  *Key = NULL;
+                  FoundKey = TRUE;
+               } 
+               else
+               {
+                   *Key = *LineBuf;
+                   Key++;
+               }
+            }
+        }
+        else
+        {
+            if(*LineBuf > 32)
+                {
+                   *Value = *LineBuf;
+                    Value++;
+                }
+        }    
+        
+        LineBuf++;
+    }
+    
+    
+    //make sure the strings are terminated
+    *Key = NULL;
+    *Value = NULL;
+
+    return FoundKey;
+}
+
diff -r 000000000000 -r 085749c8446f Code/Serial.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Code/Serial.c	Wed Jun 13 15:10:06 2012 +0000
@@ -0,0 +1,55 @@
+#include "System.h"
+
+ByteQueue PCBackDoorTx,PCBackDoorRx;
+BYTE PCBackDoorTx_Queue_Storage[PC_BACKDOOR_TX_QUEUE_SIZE];
+BYTE PCBackDoorRx_Queue_Storage[PC_BACKDOOR_RX_QUEUE_SIZE];
+
+Serial PCBackDoor(USBTX, USBRX); 
+Ticker PCBackDoorTxQueueCheck;
+
+//IRQ for when data is received
+void PCBackDoorRxIRQ();
+void PCBackDoorMoveTxQueue();
+
+void InitPCBackDoor()
+{
+    InitByteQueue(&PCBackDoorTx,PC_BACKDOOR_TX_QUEUE_SIZE,&PCBackDoorTx_Queue_Storage[0]);
+    InitByteQueue(&PCBackDoorRx,PC_BACKDOOR_RX_QUEUE_SIZE,&PCBackDoorRx_Queue_Storage[0]);
+    
+    PCBackDoor.baud(57600);
+    PCBackDoor.format(8,Serial::None,1);  
+ 
+    
+    //The Rx IRQ wil fill up my big software Rx Queue
+    PCBackDoor.attach(&PCBackDoorRxIRQ);
+    
+    //Periodicically check my outgoing Tx Queue (every 1 mS)
+   PCBackDoorTxQueueCheck.attach_us(&PCBackDoorMoveTxQueue,500);
+}
+
+void PCBackDoorMoveTxQueue()
+{
+    BYTE Temp;
+    
+    while(PCBackDoor.writeable())
+    {
+        if(BytesInQueue(&PCBackDoorTx) == 0)
+        {
+            break;
+        }
+        else
+        {
+            ByteDequeue(&PCBackDoorTx,&Temp);
+            PCBackDoor.putc(Temp);
+        }
+    }
+ 
+}
+
+void PCBackDoorRxIRQ()
+{
+   while(PCBackDoor.readable())
+    {
+         ByteEnqueue(&PCBackDoorRx,(BYTE)PCBackDoor.getc());   
+    }
+}
\ No newline at end of file
diff -r 000000000000 -r 085749c8446f Code/SmartSwitch.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Code/SmartSwitch.c	Wed Jun 13 15:10:06 2012 +0000
@@ -0,0 +1,114 @@
+#include "System.h"
+
+DigitalOut EnableSmartSwitchPower(p27);
+DigitalOut SmartSwitch_SS(p24);
+DigitalOut SmartSwitch_SCK(p25);
+DigitalOut SmartSwitch_SDI(p26);
+
+void SmartSwitch_ImageDump(BYTE *Img)
+{
+   int i;
+   
+   SmartSwitch_SS = 0;
+   SmartSwitchWriteByte(SMART_SWITCH_CMD_DISPLAY_DATA);
+   
+   for(i=0;i<256;i++)
+   {
+    SmartSwitchWriteByte(Img[i]);
+   }
+   
+   SmartSwitch_SS = 1;
+}
+
+void SmartSwitchClear()
+{
+   int i;
+   
+   SmartSwitch_SS = 0;
+   SmartSwitchWriteByte(SMART_SWITCH_CMD_DISPLAY_DATA);
+   
+   for(i=0;i<256;i++)
+   {
+    SmartSwitchWriteByte(0x00);
+   }
+   
+   SmartSwitch_SS = 1;
+}
+
+void SmartSwitch_Reset()
+{
+   SmartSwitch_SS = 0;
+   SmartSwitchWriteByte(SMART_SWITCH_CMD_RESET);
+   SmartSwitchWriteByte(SMART_SWITCH_CMD_RESET_PARAMETER);
+   SmartSwitch_SS = 1;
+}
+
+void SmartSwitch_SetBackLightColor(BYTE Red,BYTE Green,BYTE Blue)
+{
+   SmartSwitch_SS = 0;
+   SmartSwitchWriteByte(SMART_SWITCH_CMD_SET_BACKLIGHT_COLOR);
+   SmartSwitchWriteByte(Red<<6 | Green<<4 | Blue <<2 | 0x3);
+   SmartSwitch_SS = 1;
+}
+
+void SmartSwitch_SetBackLightColor2(BYTE RGB)
+{
+   SmartSwitch_SS = 0;
+   SmartSwitchWriteByte(SMART_SWITCH_CMD_SET_BACKLIGHT_COLOR);
+   SmartSwitchWriteByte(RGB<<2 | 0x3);
+   SmartSwitch_SS = 1;
+}
+
+void SmartSwitch_SetBrightnss(BYTE Brightness)
+{
+   SmartSwitch_SS = 0;
+   SmartSwitchWriteByte(SMART_SWITCH_CMD_SET_BRIGHTNESS);
+   SmartSwitchWriteByte(Brightness<<5 | 0x1F);
+   SmartSwitch_SS = 1;
+}
+
+
+
+void InitSmartSwitch()
+{
+   SmartSwitch_SS = 1;
+   SmartSwitch_SCK = 1;
+   SmartSwitch_SDI = 1;
+   PowerUpSmartSwitch();
+   SmartSwitch_Reset();
+   
+}
+
+void PowerUpSmartSwitch()
+{
+    EnableSmartSwitchPower = 1;
+}
+
+void PowerDownSmartSwitch()
+{
+    EnableSmartSwitchPower = 0;
+}
+
+void SmartSwitchWriteByte(BYTE DataOut)
+{
+    BYTE i;
+    
+    SmartSwitch_SCK = 1;
+    
+    for(i=0;i<8;i++)
+    {
+        if(DataOut & (0x01<<(7-i)))
+        {
+            SmartSwitch_SDI = 1;
+        }
+        else
+        {
+            SmartSwitch_SDI = 0;
+        }
+   
+     SmartSwitch_SCK = 0;
+     SmartSwitch_SCK = 1;
+    }
+}
+
+
diff -r 000000000000 -r 085749c8446f Code/System.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Code/System.c	Wed Jun 13 15:10:06 2012 +0000
@@ -0,0 +1,829 @@
+#include "System.h"
+
+DigitalOut EXT_LED0(LED2);
+DigitalOut ETH_LED_GREEN(p29);
+DigitalOut ETH_LED_YELLOW(p30);
+DigitalIn  ActionButton(p28);
+DigitalIn  SDCardDetect(p9);
+Ticker  SystemTick;
+
+WORD UpdateHostTerminalTick;
+WORD DisplayUpdateTick;
+WORD ButtonCheckTick;
+WORD DisplayShutOffTick;
+
+BYTE SystemState;
+CHAR DTBuf[32];
+CHAR DataLineBuf[256];
+
+//*****************************************************************
+//smart Display related stuff
+//*****************************************************************
+
+#define DISPLAY_MEASUREMENTS       0x00
+#define DISPLAY_BATTERY            0x01
+#define DISPLAY_DATE_TIME          0x02
+#define DISPLAY_CARD_STATUS        0x03
+#define DISPLAY_BUFFER_STATS       0x04
+#define DISPLAY_FIRMWARE_VERSION   0x05
+#define DISPLAY_ID                 0x06
+#define DISPLAY_OFF                0xFF
+
+#define NUM_DISPLAYS               7
+#define DISPLAY_SHUTOFF_TIME    10000
+
+BYTE DisplayMode;
+BYTE LastBackLightColor = 0;
+
+//*****************************************************************
+//Action Button Related stuff
+//*****************************************************************
+#define WAITING_FOR_PRESS   0x00
+#define WAITING_FOR_RELEASE 0x01
+
+BYTE PreviousButtonState;   
+BYTE CurrentButtonState;   
+WORD ButtonHoldTime;
+BYTE ButtonCheckState;
+void ActionButtonHandler(WORD ButtonPressTime);
+
+//*****************************************************************
+//Terminal Related stuff
+//*****************************************************************
+
+//#define MAX_TERMINAL_LINE_CHARS 128
+//CHAR TerminalLineBuf[MAX_TERMINAL_LINE_CHARS];
+//BYTE TerminalPos;
+time_t CurrentTime_InSec;
+tm *CurrentTime;
+BOOL ProcessTerminalLine(CHAR * LineIn);
+BOOL CheckForTime(CHAR *LineIn);
+BOOL CheckForDate(CHAR *LineIn);
+BOOL CheckForTimeInit(CHAR * LineIn);
+BOOL CheckforConfig(CHAR *LineIn);
+
+//*****************************************************************
+//Logging Related Stuff
+//*****************************************************************
+CHAR CurrentLogFileName[256];
+BOOL InitDataLog();
+BOOL DataLogError;
+CHAR *ErrorMsg;
+
+void CreateLogFileName();
+
+FATFS MyFileSystem;
+FIL  CurrentLogFileHandle;
+
+//DataBlock MyDataBlock[2];
+DataBlock MyDataBlock;
+
+BYTE ActiveDataBlock;
+DWORD   DataBlocksWritten;
+DWORD   DataPointIndex;
+SIGNED_DWORD ReadWriteDifferential;
+
+DWORD   WritesSinceLastFlush;
+
+#define BINARY_WRITE_CACHE_THRESHOLD   512
+BYTE    BinaryDataCache[BINARY_WRITE_CACHE_THRESHOLD + 64];
+DWORD   BinaryDataCachePtr;
+
+#define NUM_WRITES_BEFORE_FLUSH (10)
+
+//*****************************************************************
+//Misc System Related Stuff
+//*****************************************************************
+void SystemTickIrq();
+void AdjustIOffset();
+
+void InitRobotPowerMeasurementSystem()
+{
+    InitDataBlocks(&MyDataBlock);
+     
+    ActiveDataBlock = 0;
+    DataBlocksWritten = 0;
+    DataPointIndex = 0;
+    
+    SystemTick.attach_us(&SystemTickIrq,10000);
+    CurrentTime_InSec = time(NULL);
+  
+    DataLogError = FALSE;
+}
+
+
+void InitDataBlocks(DataBlock * DB)
+{
+    int i;
+  
+    for(i=0;i<DATA_BLOCK_SIZE;i++)
+    {
+        DB->Voltage[i] = 0;
+        DB->Current[i] = 0;
+    }
+    
+     DB->WriteOutPtr = 0;
+     DB->ReadInPtr = 0;
+}
+
+
+void EnterSystemState(BYTE NextState)
+{
+    switch(NextState)
+    {
+        default:
+        case SYSTEM_STATE_INIT:
+            DisplayMode = DISPLAY_MEASUREMENTS;
+            SystemState = NextState;
+        break;
+        
+        case SYSTEM_STATE_LOGGING:
+              DisplayMode = DISPLAY_CARD_STATUS;
+              
+              if(InitDataLog() == FALSE)
+              {
+                SystemState = NextState;
+              
+              }
+              else
+              {
+                SystemState = SYSTEM_STATE_IDLE;
+              }
+              
+        break;
+        
+        case SYSTEM_STATE_IDLE:
+            DisplayMode = DISPLAY_CARD_STATUS;
+            if(SystemState == SYSTEM_STATE_LOGGING)
+            {
+                f_close(&CurrentLogFileHandle);
+                f_mount(0,NULL);
+                PrintfEnqueue(&PCBackDoorTx,"Logging terminated on file %s\r\n>",CurrentLogFileName);
+            }
+            
+            SystemState = NextState;
+        break;
+    }
+}
+
+BOOL InitDataLog()
+{
+    UINT BytesWritten;
+    
+    PrintfEnqueue(&PCBackDoorTx,"\r\n\r\bInitializing Data log....\r\n");
+    CreateLogFileName();
+    PrintfEnqueue(&PCBackDoorTx,"Filename: %s\r\n",CurrentLogFileName);
+    PrintfEnqueue(&PCBackDoorTx,"Attempting File Open....\r\n");
+   
+    BinaryDataCachePtr = 0;
+    WritesSinceLastFlush = 0;
+    
+    f_mount(0,&MyFileSystem);
+    if(f_open(&CurrentLogFileHandle,&CurrentLogFileName[0],FA_WRITE | FA_OPEN_ALWAYS) != FR_OK)
+      {
+                DataLogError = TRUE;
+                PrintfEnqueue(&PCBackDoorTx,"Could not open file!\r\n>");
+                ErrorMsg = "Write Error!";
+                return TRUE;
+      }
+    
+     DataBlocksWritten = 0;
+     DataPointIndex = 0;
+     
+     DataLogError = FALSE;
+     PrintfEnqueue(&PCBackDoorTx,"Writing Headers....\r\n");
+     time(&CurrentTime_InSec);
+     strftime(DTBuf,128, "%Y.%m.%d", localtime(&CurrentTime_InSec));
+     f_printf(&CurrentLogFileHandle, "Date      %s\r\n",DTBuf);
+     strftime(DTBuf,128, "%H:%M:%S", localtime(&CurrentTime_InSec));
+     f_printf(&CurrentLogFileHandle, "Time      %s\r\n\n",DTBuf);
+     sprintf(DTBuf, "Sample Rate   %.1f Hz\r\n\r\n",SAMPLE_RATE);
+     f_write(&CurrentLogFileHandle,DTBuf,strlen(DTBuf),&BytesWritten);
+     PrintfEnqueue(&PCBackDoorTx,"Headers Written.... Starting log\r\n");
+    
+    
+    PrintfEnqueue(&PCBackDoorTx,"\r\n>"); 
+
+    return FALSE;
+}
+
+
+void CreateLogFileName()
+{
+     time(&CurrentTime_InSec);
+     strftime(CurrentLogFileName,256, "F%Y.%m.%d.%H.%M.%S.csv", localtime(&CurrentTime_InSec));
+}     
+
+
+
+void SystemTickIrq()
+{
+    if(UpdateHostTerminalTick<0xFFFF)
+        UpdateHostTerminalTick++;
+        
+    if(DisplayUpdateTick<0xFFFF)
+        DisplayUpdateTick++;
+        
+    if(ButtonCheckTick<0xFFFF)
+         ButtonCheckTick++;
+         
+     if(DisplayShutOffTick<0xFFFF)
+        DisplayShutOffTick++;
+}
+
+void InitButton()
+{
+    ButtonCheckState = WAITING_FOR_PRESS;
+    ButtonCheckTick = 0;
+    PreviousButtonState = FALSE;
+    CurrentButtonState = FALSE;
+
+}
+void CheckButton()
+{
+    if(ButtonCheckTick>0)
+    {
+        ButtonCheckTick = 0;
+        
+        PreviousButtonState = CurrentButtonState;
+        CurrentButtonState = ActionButton.read();    
+    
+        switch(ButtonCheckState)
+        {
+            default:
+            case WAITING_FOR_PRESS:
+            
+            if(CurrentButtonState == TRUE && PreviousButtonState == FALSE)
+            {
+                ButtonCheckState = WAITING_FOR_RELEASE; 
+            }
+            
+            ButtonHoldTime = 0;
+            
+            break;
+                        
+            case WAITING_FOR_RELEASE:
+            
+            if(CurrentButtonState == TRUE && PreviousButtonState == TRUE)
+            {
+                ButtonHoldTime++;
+            }
+            else if(CurrentButtonState == FALSE && PreviousButtonState == TRUE)
+            {
+                ActionButtonHandler(ButtonHoldTime);
+                ButtonCheckState = WAITING_FOR_PRESS;    
+            }
+            else
+            {
+               ButtonCheckState = WAITING_FOR_PRESS;    
+            }
+            break;
+        }
+    }
+}
+
+
+void ActionButtonHandler(WORD ButtonPressTime)
+{
+    DisplayShutOffTick = 0;
+
+    if(ButtonPressTime<50)
+    {
+       if(DisplayMode == DISPLAY_OFF)
+       {
+         PowerUpSmartSwitch();
+         SmartSwitch_Reset();
+         SmartSwitchClear();
+         DisplayMode = DISPLAY_MEASUREMENTS;
+       }
+       else
+       {
+       
+            if(DataLogError == TRUE)
+            {
+                DataLogError = FALSE;
+            }
+            else
+            {
+                DisplayMode++;
+               
+                if(DisplayMode >= NUM_DISPLAYS)
+                {
+                    DisplayMode = 0;
+                }
+            }
+        }
+    }
+    
+    else if(ButtonPressTime>100 && ButtonPressTime<500)
+    {
+        switch(SystemState)
+        {
+            default:
+            case SYSTEM_STATE_IDLE:
+               switch(DisplayMode)
+               {
+                   default:
+                 
+                    break;
+               
+                    case DISPLAY_MEASUREMENTS:
+                        AdjustIOffset();
+                    break;
+                    
+                    
+                    case DISPLAY_FIRMWARE_VERSION:
+                        LoadConfiguration();
+                    break;
+                    
+                    
+                    case DISPLAY_CARD_STATUS:
+                         if(SDCardDetect == 1)
+                            {
+                                EnterSystemState(SYSTEM_STATE_LOGGING);
+                            }
+                    break;
+               }
+            break;
+            
+         
+            case SYSTEM_STATE_LOGGING:
+              EnterSystemState(SYSTEM_STATE_IDLE);
+             // unmount the file system
+              f_mount(0,NULL);
+            break;
+        }
+    }
+}
+
+void AdjustIOffset()
+{
+    DWORD SamplesToTake;
+    DWORD i;
+    float RunningSum = 0;
+    
+    PrintfEnqueue(&PCBackDoorTx,"Zeroing ACS576.....\r\n");
+    
+    ADCDataRdy=0;
+    
+    SamplesToTake = (DWORD)(SAMPLE_RATE)*2;
+    
+    for(i=0;i<SamplesToTake;i++)
+    {
+        SmartSwitch_SetBackLightColor2((BYTE)((float)i/(float)SamplesToTake * 64));
+        
+        while(ADCDataRdy == FALSE)
+        {
+        
+        }
+        ADCDataRdy = FALSE;
+        RunningSum += RobotBusCurrentHR;
+    }
+    
+    ACS576_IOFFSET_TRIM += RunningSum / SamplesToTake;
+
+    SmartSwitch_SetBackLightColor(3,3,3);
+    
+    PrintfEnqueue(&PCBackDoorTx,"Exporting new configuration file.....\r\n>");
+    
+    ExportConfigurationSettings();
+}
+
+
+/*void UpdateHostTerminal()
+{
+ BYTE NextCharIn;
+ 
+    if(BytesInQueue(&PCBackDoorRx)>0)
+    {
+        ByteDequeue(&PCBackDoorRx,&NextCharIn);
+        
+        switch(NextCharIn)
+        {
+            case '\r':
+             
+             TerminalLineBuf[TerminalPos++] = 0x0;
+             ByteEnqueue(&PCBackDoorTx,NextCharIn);
+             ProcessTerminalLine(TerminalLineBuf);
+             ByteEnqueue(&PCBackDoorTx,'\n');
+             ByteEnqueue(&PCBackDoorTx,'>');
+             TerminalPos = 0;
+              
+            break;
+            
+            case '\b':
+                if(TerminalPos > 0)
+                {
+                    TerminalPos--;    
+                    ByteEnqueue(&PCBackDoorTx,NextCharIn);
+                }
+            break;
+            
+            default:
+                
+                if(NextCharIn > 32)
+                {
+                    if(TerminalPos < MAX_TERMINAL_LINE_CHARS-1)
+                    {
+                         TerminalLineBuf[TerminalPos++] = NextCharIn;
+                           ByteEnqueue(&PCBackDoorTx,NextCharIn);
+                    }
+                }
+            
+            break;
+        
+        }
+    }
+ 
+}
+*/
+
+BOOL ProcessTerminalLine(CHAR * LineIn)
+{
+    CheckForTime(LineIn);
+    CheckForDate(LineIn);
+    CheckForTimeInit(LineIn);
+    CheckforConfig(LineIn);
+    return TRUE;
+}
+
+BOOL CheckforConfig(CHAR *LineIn)
+{
+    if(!strcmp(LineIn,"config"))
+    {
+        LoadConfiguration();
+    }
+    return TRUE;
+}
+
+
+BOOL CheckForTimeInit(CHAR * LineIn)
+{
+    if(!strcmp(LineIn,"tinit"))
+    {
+        set_time(1256729737);
+       PrintfEnqueue(&PCBackDoorTx,"\r\nTime Reset\r\n");
+    }
+    
+    return TRUE;
+
+}
+
+BOOL CheckForTime(CHAR *LineIn)
+{
+    int Hour,Minute,Second=0;
+    int Items;
+    BOOL Error = FALSE;
+     time_t TimeStampTemp;
+    
+    
+    Items = sscanf(LineIn, "time=%d : %d  : %d", &Hour, &Minute, &Second);
+    if(Items == 3)
+    {
+        PrintfEnqueue(&PCBackDoorTx,"\r\n");
+        if(Hour>23)
+        {
+            PrintfEnqueue(&PCBackDoorTx,"Hour entry must be between 0 and 24\r\n");
+            Error = TRUE;
+        }
+        if(Minute>60)
+        {
+            PrintfEnqueue(&PCBackDoorTx,"Minute entry must be between 0 and 60\r\n");
+            Error = TRUE;
+        }
+        if(Second>60)
+        {
+            PrintfEnqueue(&PCBackDoorTx,"Second entry must be between 0 and 60\r\n");
+            Error = TRUE;
+        }
+        
+        if(Error == TRUE)
+        {
+         PrintfEnqueue(&PCBackDoorTx,"Error in time format.  Time not changed.\r\n");
+        }
+        else
+        {
+            TimeStampTemp = time(NULL);
+            //convert to tm struct 
+            CurrentTime = localtime(&TimeStampTemp);
+            //dump in our new valus
+            CurrentTime->tm_sec = Second;
+            CurrentTime->tm_min = Minute;
+            CurrentTime->tm_hour = Hour;
+            //set the new time
+            set_time(mktime(CurrentTime));
+            PrintfEnqueue(&PCBackDoorTx,"Time set to %d:%d:%d\r\n",Hour,Minute,Second);
+        }
+     
+      }
+   return FALSE;
+}
+
+BOOL CheckForDate(CHAR *LineIn)
+{
+    int Day,Month,Year=0;
+    int Items;
+    BOOL Error = FALSE;
+    time_t TimeStampTemp;
+    
+    Items = sscanf(LineIn, "date=%d / %d  / %d", &Month, &Day, &Year);
+    if(Items == 3)
+    {
+        PrintfEnqueue(&PCBackDoorTx,"\r\n");
+        if(Month>12 || Month < 1)
+        {
+            PrintfEnqueue(&PCBackDoorTx,"Month entry must be between 1 and 12\r\n");
+            Error = TRUE;
+        }
+        if(Day>31 || Day<1)
+        {
+            PrintfEnqueue(&PCBackDoorTx,"Day entry must be between 1 and 31\r\n");
+            Error = TRUE;
+        }
+        if(Year<1900)
+        {
+            PrintfEnqueue(&PCBackDoorTx,"Year entry must be greater than 1900\r\n");
+            Error = TRUE;
+        }
+        
+        if(Error == TRUE)
+        {
+         PrintfEnqueue(&PCBackDoorTx,"Error in time format.  Date not changed.\r\n");
+        }
+        else
+        {
+            //Get the current time in seconds since unix epoch
+            TimeStampTemp = time(NULL);
+            //convert to tm struct fom
+            CurrentTime = localtime(&TimeStampTemp);
+            //dump in our new valus
+            CurrentTime->tm_mon = Month-1;
+            CurrentTime->tm_mday = Day;
+            CurrentTime->tm_year = Year - 1900;
+            //set the new time
+            set_time(mktime(CurrentTime));
+            PrintfEnqueue(&PCBackDoorTx,"Date set to %d/%d/%d\r\n",Month,Day,Year);
+        }
+     
+      }
+   return FALSE;
+}
+
+
+
+void UpdateDisplay()
+{
+
+    if(DisplayShutOffTick > DISPLAY_SHUTOFF_TIME)
+    {
+        DisplayMode = DISPLAY_OFF;
+        SmartSwitchClear();
+       PowerDownSmartSwitch();
+    }
+    else
+    {
+        if(DisplayUpdateTick > 25)
+        {
+            GFX_FullDisplayBufferClear(&BackBuffer);
+            DisplayUpdateTick = 0;
+                switch(DisplayMode)
+                {
+                    default:
+                    case DISPLAY_MEASUREMENTS:
+                      SmartSwitch_SetBackLightColor(3,3,3);
+                       GFX_DrawString(&BackBuffer,"Robot Bus",0,0,&Font5x7);
+                       GFX_DrawHline(&BackBuffer,0,PHYSICAL_DISPLAY_XRES-1,10);
+                       GFX_DrawHline(&BackBuffer,0,PHYSICAL_DISPLAY_XRES-1,11);
+                       GFX_DrawHline(&BackBuffer,0,PHYSICAL_DISPLAY_XRES-1,12);
+                        
+                       GFX_printf(&BackBuffer,0,16,&Font5x7,"V: %.2fv",RobotBusVoltageHR);
+                       GFX_printf(&BackBuffer,0,24,&Font5x7,"I: %.2fa",RobotBusCurrentHR);
+                    break;
+                    
+                   
+                    case DISPLAY_BATTERY:
+                       SmartSwitch_SetBackLightColor(3,3,0);
+                       GFX_DrawString(&BackBuffer,"Battery",0,0,&Font5x7);
+                       GFX_DrawHline(&BackBuffer,0,PHYSICAL_DISPLAY_XRES-1,10);
+                       GFX_DrawHline(&BackBuffer,0,PHYSICAL_DISPLAY_XRES-1,11);
+                       GFX_DrawHline(&BackBuffer,0,PHYSICAL_DISPLAY_XRES-1,12);
+                        
+                       GFX_printf(&BackBuffer,0,16,&Font5x7,"V: %.1fv",BatteryVoltage);
+                      
+                    break;
+                    
+                     case DISPLAY_DATE_TIME:
+                       SmartSwitch_SetBackLightColor(1,3,0);
+                       GFX_DrawString(&BackBuffer,"Date/Time",0,0,&Font5x7);
+                       GFX_DrawHline(&BackBuffer,0,PHYSICAL_DISPLAY_XRES-1,10);
+                       GFX_DrawHline(&BackBuffer,0,PHYSICAL_DISPLAY_XRES-1,11);
+                       GFX_DrawHline(&BackBuffer,0,PHYSICAL_DISPLAY_XRES-1,12);
+                        
+                       time(&CurrentTime_InSec);
+                       strftime(DTBuf, 32, "%m.%d.%Y", localtime(&CurrentTime_InSec));
+                       GFX_printf(&BackBuffer,0,16,&Font5x7,"%s",DTBuf);
+                      
+                       strftime(DTBuf, 32, "%H:%M:%S", localtime(&CurrentTime_InSec));
+                       GFX_printf(&BackBuffer,0,24,&Font5x7,"%s",DTBuf);
+                    break;
+                    
+                     case DISPLAY_BUFFER_STATS:
+                     SmartSwitch_SetBackLightColor(3,3,3);
+                     GFX_DrawString(&BackBuffer,"Buf Status",0,0,&Font5x7);
+                     GFX_DrawHline(&BackBuffer,0,PHYSICAL_DISPLAY_XRES-1,10);
+                     GFX_DrawHline(&BackBuffer,0,PHYSICAL_DISPLAY_XRES-1,11);
+                     GFX_DrawHline(&BackBuffer,0,PHYSICAL_DISPLAY_XRES-1,12);
+                     GFX_printf(&BackBuffer,0,16,&Font3x5,"R/W Diff:");
+                     GFX_printf(&BackBuffer,0,24,&Font3x5,"%04d/%d",ReadWriteDifferential,DATA_BLOCK_SIZE);
+                    break;
+                    
+                    case DISPLAY_FIRMWARE_VERSION:
+                     SmartSwitch_SetBackLightColor(3,3,3);
+                     GFX_DrawString(&BackBuffer,"Firmware Version",0,0,&Font3x5);
+                     GFX_DrawHline(&BackBuffer,0,PHYSICAL_DISPLAY_XRES-1,10);
+                     GFX_DrawHline(&BackBuffer,0,PHYSICAL_DISPLAY_XRES-1,11);
+                     GFX_DrawHline(&BackBuffer,0,PHYSICAL_DISPLAY_XRES-1,12);
+                     GFX_printf(&BackBuffer,19,20,&Font5x7,"%d.%d",FIRMWARE_VERSION_MAJOR,FIRMWARE_VERSION_MINOR);
+                    break;
+                    
+                    case DISPLAY_ID:
+                     SmartSwitch_SetBackLightColor(3,3,3);
+                     GFX_DrawString(&BackBuffer,"ID",0,0,&Font3x5);
+                     GFX_DrawHline(&BackBuffer,0,PHYSICAL_DISPLAY_XRES-1,10);
+                     GFX_DrawHline(&BackBuffer,0,PHYSICAL_DISPLAY_XRES-1,11);
+                     GFX_DrawHline(&BackBuffer,0,PHYSICAL_DISPLAY_XRES-1,12);
+                     GFX_printf(&BackBuffer,0,20,&Font5x7,"%s",ID);
+                    break;
+                    
+                    case DISPLAY_CARD_STATUS:
+                                         
+                      if(SDCardDetect == 1)
+                      {
+                        
+                          switch(SystemState)
+                          {
+                            default:
+                            case SYSTEM_STATE_IDLE:
+                                switch(LastBackLightColor)
+                                 {
+                                    default:
+                                    case SMART_SWITCH_BACKLIGHT_GREEN:
+                                         LastBackLightColor = SMART_SWITCH_BACKLIGHT_YELLOW;  
+                                         SmartSwitch_SetBackLightColor2(LastBackLightColor);
+                                    break;
+                                    
+                                    case SMART_SWITCH_BACKLIGHT_YELLOW:
+                                        LastBackLightColor = SMART_SWITCH_BACKLIGHT_GREEN;
+                                        SmartSwitch_SetBackLightColor2(LastBackLightColor);
+                                    break;
+                                  }
+                               
+                               
+                              if(DataLogError == TRUE)
+                              {
+                                   GFX_DrawString(&BackBuffer,"Error!",0,0,&Font5x7); 
+                                   GFX_DrawString(&BackBuffer,ErrorMsg,0,16,&Font3x5);
+                              }  
+                              else
+                              { 
+                                  GFX_DrawString(&BackBuffer,"SD Detected",0,16,&Font5x7);
+                                  GFX_DrawString(&BackBuffer,"Idle....",0,0,&Font5x7);
+                                  GFX_DrawString(&BackBuffer,"Not Logging",0,24,&Font5x7);    
+                              }
+                            break;
+                         
+                         
+                            case SYSTEM_STATE_LOGGING:
+                                SmartSwitch_SetBackLightColor2(SMART_SWITCH_BACKLIGHT_GREEN);
+                               
+                                GFX_DrawString(&BackBuffer,"Logging Data....",0,0,&Font5x7);
+                                GFX_DrawString(&BackBuffer,&CurrentLogFileName[4],0,16,&Font5x7);
+                                GFX_printf(&BackBuffer,0,26,&Font3x5,"Block: %d",DataBlocksWritten);
+                                
+                            break;
+                         }
+                      }
+                      else
+                      {
+                          GFX_DrawString(&BackBuffer,"No SD Card!",0,0,&Font5x7);
+                          
+                            switch(LastBackLightColor)
+                            {
+                                default:
+                                case SMART_SWITCH_BACKLIGHT_RED:
+                                     LastBackLightColor = SMART_SWITCH_BACKLIGHT_YELLOW;  
+                                     SmartSwitch_SetBackLightColor2(LastBackLightColor);
+                                break;
+                                
+                                case SMART_SWITCH_BACKLIGHT_YELLOW:
+                                    LastBackLightColor = SMART_SWITCH_BACKLIGHT_RED;
+                                    SmartSwitch_SetBackLightColor2(LastBackLightColor);
+                                break;
+                              }
+                      } 
+                    
+                       GFX_DrawHline(&BackBuffer,0,PHYSICAL_DISPLAY_XRES-1,10);
+                       GFX_DrawHline(&BackBuffer,0,PHYSICAL_DISPLAY_XRES-1,11);
+                       GFX_DrawHline(&BackBuffer,0,PHYSICAL_DISPLAY_XRES-1,12);
+                    
+                    break;
+                }
+             GFX_DumpRenderContextToPhysicalScreen(&BackBuffer);
+        }
+    }
+}
+
+
+void CheckSDCardStatus()
+{
+    //Make sure that the SD card stays in while logging
+    switch(SystemState)
+    {
+        case SYSTEM_STATE_LOGGING:
+            if(SDCardDetect == 0)
+            {
+                //Gracefully shut the logging system down.....
+                EnterSystemState(SYSTEM_STATE_IDLE);
+            }
+        break;
+        
+        default:
+        break;
+    } 
+}
+
+
+void LogData()
+{
+    WORD i;
+    int ElementsToWrite;
+    UINT BytesWritten;
+    
+    if(RobotBusVoltageHR < 9)
+    {
+        EnterSystemState(SYSTEM_STATE_IDLE);
+        return;
+    }
+    
+    if(DataLogError == TRUE)
+    {
+        EnterSystemState(SYSTEM_STATE_IDLE);
+    }
+    else
+    {
+        if(MyDataBlock.ReadInPtr < MyDataBlock.WriteOutPtr)
+        {
+           ElementsToWrite =  MyDataBlock.ReadInPtr + (DATA_BLOCK_SIZE - MyDataBlock.WriteOutPtr);
+        }
+        else
+        {
+            ElementsToWrite = MyDataBlock.ReadInPtr - MyDataBlock.WriteOutPtr;
+        }
+        
+        if(ElementsToWrite > WRITE_BLOCK_THRESH)
+        {
+                for(i=0;i<ElementsToWrite;i++)
+                {
+                    BinaryDataCachePtr += sprintf((char *)&BinaryDataCache[BinaryDataCachePtr],"%d,%.2f,%.2f\r\n",DataPointIndex,MyDataBlock.Voltage[MyDataBlock.WriteOutPtr],MyDataBlock.Current[MyDataBlock.WriteOutPtr]);
+                    if(BinaryDataCachePtr>=BINARY_WRITE_CACHE_THRESHOLD)
+                    {
+                        EXT_LED0 = 1;  
+                        f_write(&CurrentLogFileHandle,BinaryDataCache,BinaryDataCachePtr,&BytesWritten);
+                        
+                        BinaryDataCachePtr = 0;
+                      
+                        EXT_LED0=0;
+                    }
+                    DataPointIndex++;
+                    MyDataBlock.WriteOutPtr++;
+                    if(MyDataBlock.WriteOutPtr == DATA_BLOCK_SIZE)
+                    {
+                        MyDataBlock.WriteOutPtr = 0;
+                    }
+                }
+                if(WritesSinceLastFlush > NUM_WRITES_BEFORE_FLUSH)
+                 {
+                            f_close(&CurrentLogFileHandle);
+                            WritesSinceLastFlush = 0;
+                            f_open(&CurrentLogFileHandle,&CurrentLogFileName[0],FA_WRITE | FA_OPEN_ALWAYS);
+                            f_lseek(&CurrentLogFileHandle, CurrentLogFileHandle.fsize);
+                 }
+               DataBlocksWritten++;
+      }
+    }
+}
+
+
+
+void DisplayBootMsg()
+{
+   PrintfEnqueue(&PCBackDoorTx,"\r\n\r\n");
+   PrintfEnqueue(&PCBackDoorTx,".______     _______. __    __            ___      .______       __   \r\n");
+   PrintfEnqueue(&PCBackDoorTx,"|   _  \\   /       ||  |  |  |          /   \\     |   _  \\     |  |  \r\n");
+   PrintfEnqueue(&PCBackDoorTx,"|  |_)  | |   (----`|  |  |  |  ______ /  ^  \\    |  |_)  |    |  |  \r\n");   
+   PrintfEnqueue(&PCBackDoorTx,"|   ___/   \\   \\    |  |  |  | |______/  /_\\  \\   |      /     |  |  \r\n");
+   PrintfEnqueue(&PCBackDoorTx,"|  |   .----)   |   |  `--'  |       /  _____  \\  |  |\\  \\----.|  `----.\r\n");
+   PrintfEnqueue(&PCBackDoorTx,"| _|   |_______/     \\______/       /__/     \\__\\ | _| `._____||_______|\r\n");
+   PrintfEnqueue(&PCBackDoorTx,"---------------------------------------------------------------------------\r\n");
+   PrintfEnqueue(&PCBackDoorTx,"HyPER MPMC Control Terminal\r\n\r\n>");
+}
\ No newline at end of file
diff -r 000000000000 -r 085749c8446f Code/Terminal.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Code/Terminal.cpp	Wed Jun 13 15:10:06 2012 +0000
@@ -0,0 +1,279 @@
+#include "System.h"
+
+
+//*****************************************************************
+//Terminal Related stuff
+//*****************************************************************
+
+#define MAX_TERMINAL_LINE_CHARS 128
+#define MAX_TERMINAL_CMD_CHARS 32
+CHAR TerminalLineBuf[MAX_TERMINAL_LINE_CHARS];
+BYTE TerminalPos;
+CHAR TerminalCmdBuf[MAX_TERMINAL_CMD_CHARS+1];
+CHAR TerminalArgs[MAX_TERMINAL_LINE_CHARS-MAX_TERMINAL_CMD_CHARS];
+BYTE NextCharIn;
+BOOL CmdFound;
+
+
+ 
+#define NUM_TERMINAL_CMDS    7
+
+char *TerminalCommands[NUM_TERMINAL_CMDS] = {"help","reboot","v","i","Time","Date","RTC_Init"};
+
+typedef void (*TerminalCallback)(char *);
+
+
+void TerminalCmd_Help(char *arg);
+void TerminalCmd_Reboot(char *arg);
+void TerminalCmd_v(char *arg);
+void TerminalCmd_i(char *arg);
+void TerminalCmd_Time(char *arg);
+void TerminalCmd_Date(char *arg);
+void TerminalCmd_RTC_Init(char *arg);
+
+TerminalCallback TerminalCallbacks[NUM_TERMINAL_CMDS] ={TerminalCmd_Help};
+
+void InitTerminal()
+{
+    //Initialize the terminal command callbacks
+    TerminalCallbacks[0] = TerminalCmd_Help;
+    TerminalCallbacks[1] = TerminalCmd_Reboot;
+    TerminalCallbacks[2] = TerminalCmd_v;
+    TerminalCallbacks[3] = TerminalCmd_i;
+    TerminalCallbacks[4] = TerminalCmd_Time;
+    TerminalCallbacks[5] = TerminalCmd_Date;
+    TerminalCallbacks[6] = TerminalCmd_RTC_Init;
+}
+
+
+extern "C" void mbed_reset();
+
+void TerminalCmd_RTC_Init(char *arg);
+{
+   set_time(1256729737);
+   PrintfEnqueue(&PCBackDoorTx,"\r\nTime Reset\r\n");
+}
+
+
+void TerminalCmd_Time(char *arg)
+{
+ int Hour,Minute,Second=0;
+    int Items;
+    BOOL Error = FALSE;
+    time_t TimeStampTemp;
+    
+    
+    Items = sscanf(LineIn, "time=%d : %d  : %d", &Hour, &Minute, &Second);
+    if(Items == 3)
+    {
+        PrintfEnqueue(&PCBackDoorTx,"\r\n");
+        if(Hour>23)
+        {
+            PrintfEnqueue(&PCBackDoorTx,"Hour entry must be between 0 and 24\r\n");
+            Error = TRUE;
+        }
+        if(Minute>60)
+        {
+            PrintfEnqueue(&PCBackDoorTx,"Minute entry must be between 0 and 60\r\n");
+            Error = TRUE;
+        }
+        if(Second>60)
+        {
+            PrintfEnqueue(&PCBackDoorTx,"Second entry must be between 0 and 60\r\n");
+            Error = TRUE;
+        }
+        
+        if(Error == TRUE)
+        {
+         PrintfEnqueue(&PCBackDoorTx,"Error in time format.  Time not changed.\r\n");
+        }
+        else
+        {
+            TimeStampTemp = time(NULL);
+            //convert to tm struct 
+            CurrentTime = localtime(&TimeStampTemp);
+            //dump in our new valus
+            CurrentTime->tm_sec = Second;
+            CurrentTime->tm_min = Minute;
+            CurrentTime->tm_hour = Hour;
+            //set the new time
+            set_time(mktime(CurrentTime));
+            PrintfEnqueue(&PCBackDoorTx,"Time set to %d:%d:%d\r\n",Hour,Minute,Second);
+        }
+     
+      }
+}
+
+void TerminalCmd_Date(char *arg)
+{
+ int Day,Month,Year=0;
+    int Items;
+    BOOL Error = FALSE;
+    time_t TimeStampTemp;
+    
+    Items = sscanf(LineIn, "date=%d / %d  / %d", &Month, &Day, &Year);
+    if(Items == 3)
+    {
+        PrintfEnqueue(&PCBackDoorTx,"\r\n");
+        if(Month>12 || Month < 1)
+        {
+            PrintfEnqueue(&PCBackDoorTx,"Month entry must be between 1 and 12\r\n");
+            Error = TRUE;
+        }
+        if(Day>31 || Day<1)
+        {
+            PrintfEnqueue(&PCBackDoorTx,"Day entry must be between 1 and 31\r\n");
+            Error = TRUE;
+        }
+        if(Year<1900)
+        {
+            PrintfEnqueue(&PCBackDoorTx,"Year entry must be greater than 1900\r\n");
+            Error = TRUE;
+        }
+        
+        if(Error == TRUE)
+        {
+         PrintfEnqueue(&PCBackDoorTx,"Error in time format.  Date not changed.\r\n");
+        }
+        else
+        {
+            //Get the current time in seconds since unix epoch
+            TimeStampTemp = time(NULL);
+            //convert to tm struct fom
+            CurrentTime = localtime(&TimeStampTemp);
+            //dump in our new valus
+            CurrentTime->tm_mon = Month-1;
+            CurrentTime->tm_mday = Day;
+            CurrentTime->tm_year = Year - 1900;
+            //set the new time
+            set_time(mktime(CurrentTime));
+            PrintfEnqueue(&PCBackDoorTx,"Date set to %d/%d/%d\r\n",Month,Day,Year);
+        }
+     
+      }
+}
+
+void TerminalCmd_v(char *arg)
+{
+   //   PrintfEnqueue(&PCBackDoorTx,"\r\nVbus: %.1f\r\n",Vout);
+}
+
+void TerminalCmd_i(char *arg)
+{
+//      PrintfEnqueue(&PCBackDoorTx,"\r\nIbus: %.1f\r\n",Iout);
+}
+
+void TerminalCmd_Help(char *arg)
+{
+    BYTE i;
+
+      PrintfEnqueue(&PCBackDoorTx,"\r\n\r\bCommandList:\r\n");
+      PrintfEnqueue(&PCBackDoorTx,"----------------------\r\n");
+
+    for(i=0;i<NUM_TERMINAL_CMDS;i++)
+    {
+         PrintfEnqueue(&PCBackDoorTx,"%s\r\n",TerminalCommands[i]);    
+    }
+
+}
+
+void TerminalCmd_Reboot(char *arg)
+{
+       mbed_reset();
+}
+
+void TerminalCmd_Strip(char *arg)
+{
+        PrintfEnqueue(&PCBackDoorTx,"\r\n%s\r\n", arg);
+}
+
+void ProcessTerminal()
+{
+
+      BYTE i,j;
+
+    if(BytesInQueue(&PCBackDoorRx)>0)
+    {
+        ByteDequeue(&PCBackDoorRx,&NextCharIn);
+        
+        switch(NextCharIn)
+        {
+            case '\r':
+             
+             TerminalLineBuf[TerminalPos++] = 0x0;
+             ByteEnqueue(&PCBackDoorTx,NextCharIn);
+            
+             if(TerminalPos > 1)
+             {
+                 //find the command
+                 i=0;
+                 while(TerminalLineBuf[i]>0x20 &&  TerminalLineBuf[i]<0x7f)
+                 {
+                      TerminalCmdBuf[i] = TerminalLineBuf[i];
+                      i++;
+    
+                    if(i==MAX_TERMINAL_CMD_CHARS)
+                        {
+                         break;
+                        }
+                 }
+                    
+                TerminalCmdBuf[i] = 0;
+                TerminalCmdBuf[i+1] = 0;
+            
+                strcpy(TerminalArgs,&TerminalLineBuf[i]);
+
+                CmdFound = FALSE;
+                for(j=0;j<NUM_TERMINAL_CMDS;j++)
+                {           
+                    if(strcmp(TerminalCmdBuf,TerminalCommands[j]) == 0)
+                    {
+                        if(TerminalCallbacks[j] != NULL)
+                            TerminalCallbacks[j](TerminalArgs);
+                    
+                        CmdFound = TRUE;
+                        break;
+                    }             
+                }        
+                if(CmdFound == FALSE)
+                {
+                   PrintfEnqueue(&PCBackDoorTx,"%s command not recognized.\r\n", TerminalCmdBuf);
+                }
+              }    
+             ByteEnqueue(&PCBackDoorTx,'\n');
+             ByteEnqueue(&PCBackDoorTx,'>');
+             TerminalPos = 0;
+            
+            break;
+            
+            case '\b':
+                if(TerminalPos > 0)
+                {
+                    TerminalPos--;    
+                    ByteEnqueue(&PCBackDoorTx,NextCharIn);
+                }
+            break;
+            
+            default:
+                
+                if(TerminalPos == 0 && NextCharIn == 0x020)
+                {
+                     //Do nothing if space bar is pressed at begining of line    
+                }
+                   else if(NextCharIn >= 0x20 && NextCharIn<0x7F)
+                {
+                    
+                    if(TerminalPos < MAX_TERMINAL_LINE_CHARS-1)
+                    {
+                         TerminalLineBuf[TerminalPos++] = NextCharIn;
+                           ByteEnqueue(&PCBackDoorTx,NextCharIn);
+                    }
+                }
+            
+            break;
+        
+        }
+    }
+ 
+}
+
diff -r 000000000000 -r 085749c8446f Code/chan_fat_fs/diskio.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Code/chan_fat_fs/diskio.c	Wed Jun 13 15:10:06 2012 +0000
@@ -0,0 +1,300 @@
+/*-----------------------------------------------------------------------*/
+/* Low level disk I/O module skeleton for FatFs     (C)ChaN, 2007        */
+/*-----------------------------------------------------------------------*/
+/* This is a stub disk I/O module that acts as front end of the existing */
+/* disk I/O modules and attach it to FatFs module with common interface. */
+/*-----------------------------------------------------------------------*/
+
+#include "diskio.h"
+#include "mbed.h"
+
+
+//******************************************************************************************************************
+// MBED SPI/CS Select functions.... Modify for your layout.
+//**************************************************************************************
+
+SPI _spi(p5, p6, p7); // mosi, miso, sclk
+DigitalOut _cs(p8);
+
+//******************************************************************************************************************
+// Low Level Sector Access Function Prototypes('C' Castrated versions of Simon Ford's C++ MBED SDFileSystem class
+//******************************************************************************************************************
+int _cmd(int cmd, int arg);
+int _read(BYTE *buffer, int length);
+int _write(BYTE *buffer, int length);
+int ext_bits(BYTE *data, int msb, int lsb);
+int _sd_sectors();
+int _sectors;
+
+#define SD_COMMAND_TIMEOUT 5000
+
+
+//******************************************************************************************************************
+// Sector Access functions for CHAN FatFs 
+//******************************************************************************************************************
+
+DRESULT disk_ioctl (
+    BYTE drv,        /* Physical drive nmuber (0..) */
+    BYTE ctrl,        /* Control code */
+    void *buff        /* Buffer to send/receive control data */
+)
+{
+    DRESULT res;
+
+    switch(ctrl)
+    {
+        case CTRL_SYNC:
+             res = RES_OK;
+        break;
+    
+        case GET_SECTOR_SIZE:
+              res = RES_OK;
+            *(WORD *)buff = 512;
+        break;
+        
+        case GET_SECTOR_COUNT:
+            res = RES_OK;
+           *(DWORD *)buff = (WORD)_sd_sectors();
+        break;
+        
+        case GET_BLOCK_SIZE:
+         res = RES_OK;
+          *(DWORD *)buff = 1;
+        break;
+        
+        default:
+        res = RES_OK;
+        break;
+    }
+    return res;
+}
+
+DSTATUS disk_initialize(BYTE Drive) {
+
+    _spi.frequency(100000); // Set to 100kHz for initialisation
+    
+    // Initialise the card by clocking it a bit (cs = 1)
+    for(int i=0; i<16; i++) {   
+        _spi.write(0xFF);
+    }
+
+    // send CMD0, should return with all zeros except IDLE STATE set (bit 0)
+    if(_cmd(0, 0) != 0x01) { 
+        fprintf(stderr, "Not in idle state\n");
+        return STA_NOINIT;
+    }
+    
+    // ACMD41 to give host capacity support (repeat until not busy)
+    // ACMD41 is application specific command, so we send APP_CMD (CMD55) beforehand
+    for(int i=0;; i++) {
+        _cmd(55, 0); 
+        int response = _cmd(41, 0);
+        if(response == 0) { 
+            break;
+        } else if(i > SD_COMMAND_TIMEOUT) {
+            fprintf(stderr, "Timeout waiting for card\n");
+            return STA_NOINIT;
+        }    
+    }
+
+    _sectors = _sd_sectors();
+
+    // Set block length to 512 (CMD16)
+    if(_cmd(16, 512) != 0) {
+        fprintf(stderr, "Set block timeout\n");
+        return STA_NOINIT;
+    }
+        
+    _spi.frequency(10000000); // Set to 10MHz for data transfer
+    return 0;
+}
+
+DRESULT disk_write(BYTE Drive,const BYTE * Buffer, DWORD SectorNumber, BYTE SectorCount)
+{
+    BYTE i;
+    
+    BYTE * MyBufOut = (BYTE *)Buffer;
+    
+    for(i=0;i<SectorCount;i++)
+    {
+        // set write address for single block (CMD24)
+        if(_cmd(24, (SectorNumber + i) * 512 ) != 0) {
+            return RES_ERROR;
+        }
+
+        // send the data block
+        _write(MyBufOut, 512);    
+        
+        MyBufOut+=512;
+    }
+    return RES_OK;    
+}
+
+DRESULT disk_read(BYTE Drive, BYTE * Buffer,DWORD SectorNumber, BYTE SectorCount)
+{        
+    BYTE i;
+    for(i=0;i<SectorCount;i++)
+    {
+        // set read address for single block (CMD17)
+        if(_cmd(17, (SectorNumber+i) * 512) != 0)
+        {
+            return RES_ERROR;
+        }
+        // receive the data
+        _read(Buffer, 512);
+       
+        Buffer+=512;
+    }
+     return RES_OK;
+}
+
+
+DWORD get_fattime(void)
+{
+    time_t CurrentTimeStamp;
+    tm *CurrentLocalTime;
+    DWORD FATFSTimeCode;
+        
+    CurrentTimeStamp = time(NULL);
+    CurrentLocalTime = localtime(&CurrentTimeStamp);
+        
+        //Map the tm struct time into the FatFs time code    
+    FATFSTimeCode =  ((CurrentLocalTime->tm_year-80)<<25) | 
+                     ((CurrentLocalTime->tm_mon+1)<<21)   | 
+                     ((CurrentLocalTime->tm_mday)<<16)    | 
+                     ((CurrentLocalTime->tm_hour)<<11)    |
+                     ((CurrentLocalTime->tm_min)<<5)     | 
+                     ((CurrentLocalTime->tm_sec));
+
+   return FATFSTimeCode;
+}
+
+DSTATUS disk_status(BYTE Drive)
+{
+    return 0;
+}
+
+//**************************************************************************************
+// Low Level Sector Access Functions (Castrated versions of Simon Fords C++ MBED class
+//**************************************************************************************
+
+int _cmd(int cmd, int arg) {
+    _cs = 0; 
+
+    // send a command
+    _spi.write(0x40 | cmd);
+    _spi.write(arg >> 24);
+    _spi.write(arg >> 16);
+    _spi.write(arg >> 8);
+    _spi.write(arg >> 0);
+    _spi.write(0x95);
+
+    // wait for the repsonse (response[7] == 0)
+    for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
+        int response = _spi.write(0xFF);
+        if(!(response & 0x80)) {
+            _cs = 1;
+            return response;
+        }
+    }
+    _cs = 1;
+    return -1; // timeout
+}
+
+int _read(BYTE *buffer, int length) {
+    _cs = 0;
+
+    // read until start byte (0xFF)
+    while(_spi.write(0xFF) != 0xFE);
+
+    // read data
+    for(int i=0; i<length; i++) {
+        buffer[i] = _spi.write(0xFF);
+    }
+    _spi.write(0xFF); // checksum
+    _spi.write(0xFF);
+
+    _cs = 1;    
+    return 0;
+}
+
+int _write(BYTE *buffer, int length) {
+    _cs = 0;
+    
+    // indicate start of block
+    _spi.write(0xFE);
+    
+    // write the data
+    for(int i=0; i<length; i++) {
+        _spi.write(buffer[i]);
+    }
+    
+    // write the checksum
+    _spi.write(0xFF); 
+    _spi.write(0xFF);
+
+    // check the repsonse token
+    if((_spi.write(0xFF) & 0x1F) != 0x05) {
+        _cs = 1; 
+        return 1;
+    }
+
+    // wait for write to finish
+    while(_spi.write(0xFF) == 0);
+
+    _cs = 1; 
+    return 0;
+}
+
+int ext_bits(BYTE *data, int msb, int lsb) {
+    int bits = 0;
+    int size = 1 + msb - lsb; 
+    for(int i=0; i<size; i++) {
+        int position = lsb + i;
+        int byte = 15 - (position >> 3);
+        int bit = position & 0x7;
+        int value = (data[byte] >> bit) & 1;
+        bits |= value << i;
+    }
+    return bits;
+}
+
+int _sd_sectors() {
+
+    // CMD9, Response R2 (R1 byte + 16-byte block read)
+    if(_cmd(9, 0) != 0) {
+        fprintf(stderr, "Didn't get a response from the disk\n");
+        return 0;
+    }
+    
+    BYTE csd[16];    
+    if(_read(csd, 16) != 0) {
+        fprintf(stderr, "Couldn't read csd response from disk\n");
+        return 0;
+    }
+
+    // csd_structure : csd[127:126]
+    // c_size        : csd[73:62]
+    // c_size_mult   : csd[49:47]
+    // read_bl_len   : csd[83:80] 
+
+    int csd_structure = ext_bits(csd, 127, 126);
+    int c_size = ext_bits(csd, 73, 62);
+    int c_size_mult = ext_bits(csd, 49, 47);
+    int read_bl_len = ext_bits(csd, 83, 80);
+    
+    if(csd_structure != 0) {
+        fprintf(stderr, "This disk tastes funny! I only know about type 0 CSD structures");
+        return 0;
+    }
+                            
+    int blocks = (c_size + 1) * (1 << (c_size_mult + 2));
+    int block_size = 1 << read_bl_len;
+
+    if(block_size != 512) {
+        fprintf(stderr, "This disk tastes funny! I only like 512 byte blocks (%d)\r\n",block_size);
+        return 0;
+    }
+    
+    return blocks;
+}
diff -r 000000000000 -r 085749c8446f Code/chan_fat_fs/diskio.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Code/chan_fat_fs/diskio.h	Wed Jun 13 15:10:06 2012 +0000
@@ -0,0 +1,68 @@
+/*-----------------------------------------------------------------------
+/  Low level disk interface modlue include file  R0.07   (C)ChaN, 2009
+/-----------------------------------------------------------------------*/
+
+#ifndef _DISKIO
+
+#define _READONLY    0    /* 1: Read-only mode */
+#define _USE_IOCTL    1
+
+#include "integer.h"
+
+/* Status of Disk Functions */
+typedef BYTE    DSTATUS;
+
+/* Results of Disk Functions */
+typedef enum {
+    RES_OK = 0,        /* 0: Successful */
+    RES_ERROR,        /* 1: R/W Error */
+    RES_WRPRT,        /* 2: Write Protected */
+    RES_NOTRDY,        /* 3: Not Ready */
+    RES_PARERR        /* 4: Invalid Parameter */
+} DRESULT;
+
+
+/*---------------------------------------*/
+/* Prototypes for disk control functions */
+
+extern BOOL assign_drives (int argc, char *argv[]);
+extern DSTATUS disk_initialize (BYTE);
+extern DSTATUS disk_status (BYTE);
+extern DRESULT disk_read (BYTE, BYTE*, DWORD, BYTE);
+extern DRESULT disk_write (BYTE, const BYTE*, DWORD, BYTE);
+extern DRESULT disk_ioctl (BYTE, BYTE, void*);
+
+extern int _sd_sectors();
+
+
+/* Disk Status Bits (DSTATUS) */
+
+#define STA_NOINIT        0x01    /* Drive not initialized */
+#define STA_NODISK        0x02    /* No medium in the drive */
+#define STA_PROTECT        0x04    /* Write protected */
+
+
+/* Command code for disk_ioctrl() */
+
+/* Generic command */
+#define CTRL_SYNC            0    /* Mandatory for write functions */
+#define GET_SECTOR_COUNT    1    /* Mandatory for only f_mkfs() */
+#define GET_SECTOR_SIZE        2    /* Mandatory for multiple sector size cfg */
+#define GET_BLOCK_SIZE        3    /* Mandatory for only f_mkfs() */
+#define CTRL_POWER            4
+#define CTRL_LOCK            5
+#define CTRL_EJECT            6
+/* MMC/SDC command */
+#define MMC_GET_TYPE        10
+#define MMC_GET_CSD            11
+#define MMC_GET_CID            12
+#define MMC_GET_OCR            13
+#define MMC_GET_SDSTAT        14
+/* ATA/CF command */
+#define ATA_GET_REV            20
+#define ATA_GET_MODEL        21
+#define ATA_GET_SN            22
+
+
+#define _DISKIO
+#endif
diff -r 000000000000 -r 085749c8446f Code/chan_fat_fs/ff.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Code/chan_fat_fs/ff.c	Wed Jun 13 15:10:06 2012 +0000
@@ -0,0 +1,3153 @@
+/*----------------------------------------------------------------------------/
+/  FatFs - FAT file system module  R0.07e                    (C)ChaN, 2009
+/-----------------------------------------------------------------------------/
+/ FatFs module is a generic FAT file system module for small embedded systems.
+/ This is a free software that opened for education, research and commercial
+/ developments under license policy of following trems.
+/
+/  Copyright (C) 2009, ChaN, all right reserved.
+/
+/ * The FatFs module is a free software and there is NO WARRANTY.
+/ * No restriction on use. You can use, modify and redistribute it for
+/   personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY.
+/ * Redistributions of source code must retain the above copyright notice.
+/
+/-----------------------------------------------------------------------------/
+/ Feb 26,'06 R0.00  Prototype.
+/
+/ Apr 29,'06 R0.01  First stable version.
+/
+/ Jun 01,'06 R0.02  Added FAT12 support.
+/                   Removed unbuffered mode.
+/                   Fixed a problem on small (<32M) patition.
+/ Jun 10,'06 R0.02a Added a configuration option (_FS_MINIMUM).
+/
+/ Sep 22,'06 R0.03  Added f_rename().
+/                   Changed option _FS_MINIMUM to _FS_MINIMIZE.
+/ Dec 11,'06 R0.03a Improved cluster scan algolithm to write files fast.
+/                   Fixed f_mkdir() creates incorrect directory on FAT32.
+/
+/ Feb 04,'07 R0.04  Supported multiple drive system.
+/                   Changed some interfaces for multiple drive system.
+/                   Changed f_mountdrv() to f_mount().
+/                   Added f_mkfs().
+/ Apr 01,'07 R0.04a Supported multiple partitions on a plysical drive.
+/                   Added a capability of extending file size to f_lseek().
+/                   Added minimization level 3.
+/                   Fixed an endian sensitive code in f_mkfs().
+/ May 05,'07 R0.04b Added a configuration option _USE_NTFLAG.
+/                   Added FSInfo support.
+/                   Fixed DBCS name can result FR_INVALID_NAME.
+/                   Fixed short seek (<= csize) collapses the file object.
+/
+/ Aug 25,'07 R0.05  Changed arguments of f_read(), f_write() and f_mkfs().
+/                   Fixed f_mkfs() on FAT32 creates incorrect FSInfo.
+/                   Fixed f_mkdir() on FAT32 creates incorrect directory.
+/ Feb 03,'08 R0.05a Added f_truncate() and f_utime().
+/                   Fixed off by one error at FAT sub-type determination.
+/                   Fixed btr in f_read() can be mistruncated.
+/                   Fixed cached sector is not flushed when create and close
+/                   without write.
+/
+/ Apr 01,'08 R0.06  Added fputc(), fputs(), fprintf() and fgets().
+/                   Improved performance of f_lseek() on moving to the same
+/                   or following cluster.
+/
+/ Apr 01,'09 R0.07  Merged Tiny-FatFs as a buffer configuration option.
+/                   Added long file name support.
+/                   Added multiple code page support.
+/                   Added re-entrancy for multitask operation.
+/                   Added auto cluster size selection to f_mkfs().
+/                   Added rewind option to f_readdir().
+/                   Changed result code of critical errors.
+/                   Renamed string functions to avoid name collision.
+/ Apr 14,'09 R0.07a Separated out OS dependent code on reentrant cfg.
+/                   Added multiple sector size support.
+/ Jun 21,'09 R0.07c Fixed f_unlink() can return FR_OK on error.
+/                   Fixed wrong cache control in f_lseek().
+/                   Added relative path feature.
+/                   Added f_chdir() and f_chdrive().
+/                   Added proper case conversion to extended char.
+/ Nov 03,'09 R0.07e Separated out configuration options from ff.h to ffconf.h.
+/                   Fixed f_unlink() fails to remove a sub-dir on _FS_RPATH.
+/                   Fixed name matching error on the 13 char boundary.
+/                   Added a configuration option, _LFN_UNICODE.
+/                   Changed f_readdir() to return the SFN with always upper
+/                   case on non-LFN cfg.
+/---------------------------------------------------------------------------*/
+
+#include "ff.h"            /* FatFs configurations and declarations */
+#include "diskio.h"        /* Declarations of low level disk I/O functions */
+
+/*--------------------------------------------------------------------------
+
+   Module Private Definitions
+
+---------------------------------------------------------------------------*/
+
+#if _FATFS != 0x007E
+#error Wrong include file (ff.h).
+#endif
+
+#if _FS_REENTRANT
+#if _USE_LFN == 1
+#error Static LFN work area must not be used in re-entrant configuration.
+#endif
+#define    ENTER_FF(fs)        { if (!lock_fs(fs)) return FR_TIMEOUT; }
+#define    LEAVE_FF(fs, res)    { unlock_fs(fs, res); return res; }
+
+#else
+#define    ENTER_FF(fs)
+#define LEAVE_FF(fs, res)    return res
+
+#endif
+
+#define    ABORT(fs, res)        { fp->flag |= FA__ERROR; LEAVE_FF(fs, res); }
+
+#ifndef NULL
+#define    NULL    0
+#endif
+
+/* Name status flags */
+#define NS            11        /* Offset of name status byte */
+#define NS_LOSS        0x01    /* Out of 8.3 format */
+#define NS_LFN        0x02    /* Force to create LFN entry */
+#define NS_LAST        0x04    /* Last segment */
+#define NS_BODY        0x08    /* Lower case flag (body) */
+#define NS_EXT        0x10    /* Lower case flag (ext) */
+#define NS_DOT        0x20    /* Dot entry */
+
+
+
+
+/*--------------------------------------------------------------------------
+
+   Private Work Area
+
+---------------------------------------------------------------------------*/
+
+#if _DRIVES < 1 || _DRIVES > 9
+#error Number of drives must be 1-9.
+#endif
+static
+FATFS *FatFs[_DRIVES];    /* Pointer to the file system objects (logical drives) */
+
+static
+WORD Fsid;                /* File system mount ID */
+
+#if _FS_RPATH
+static
+BYTE Drive;                /* Current drive */
+#endif
+
+
+#if _USE_LFN == 1    /* LFN with static LFN working buffer */
+static
+WCHAR LfnBuf[_MAX_LFN + 1];
+#define    NAMEBUF(sp,lp)    BYTE sp[12]; WCHAR *lp = LfnBuf
+#define INITBUF(dj,sp,lp)    dj.fn = sp; dj.lfn = lp
+
+#elif _USE_LFN > 1    /* LFN with dynamic LFN working buffer */
+#define    NAMEBUF(sp,lp)    BYTE sp[12]; WCHAR lbuf[_MAX_LFN + 1], *lp = lbuf
+#define INITBUF(dj,sp,lp)    dj.fn = sp; dj.lfn = lp
+
+#else                /* No LFN */
+#define    NAMEBUF(sp,lp)    BYTE sp[12]
+#define INITBUF(dj,sp,lp)    dj.fn = sp
+
+#endif
+
+
+
+
+/*--------------------------------------------------------------------------
+
+   Module Private Functions
+
+---------------------------------------------------------------------------*/
+
+
+/*-----------------------------------------------------------------------*/
+/* String functions                                                      */
+/*-----------------------------------------------------------------------*/
+
+/* Copy memory to memory */
+static
+void mem_cpy (void* dst, const void* src, int cnt) {
+    char *d = (char*)dst;
+    const char *s = (const char *)src;
+    while (cnt--) *d++ = *s++;
+}
+
+/* Fill memory */
+static
+void mem_set (void* dst, int val, int cnt) {
+    char *d = (char*)dst;
+    while (cnt--) *d++ = (char)val;
+}
+
+/* Compare memory to memory */
+static
+int mem_cmp (const void* dst, const void* src, int cnt) {
+    const char *d = (const char *)dst, *s = (const char *)src;
+    int r = 0;
+    while (cnt-- && (r = *d++ - *s++) == 0) ;
+    return r;
+}
+
+/* Check if chr is contained in the string */
+static
+int chk_chr (const char* str, int chr) {
+    while (*str && *str != chr) str++;
+    return *str;
+}
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Request/Release grant to access the volume                            */
+/*-----------------------------------------------------------------------*/
+#if _FS_REENTRANT
+
+static
+BOOL lock_fs (
+    FATFS *fs        /* File system object */
+)
+{
+    return ff_req_grant(fs->sobj);
+}
+
+
+static
+void unlock_fs (
+    FATFS *fs,        /* File system object */
+    FRESULT res        /* Result code to be returned */
+)
+{
+    if (res != FR_NOT_ENABLED &&
+        res != FR_INVALID_DRIVE &&
+        res != FR_INVALID_OBJECT &&
+        res != FR_TIMEOUT) {
+        ff_rel_grant(fs->sobj);
+    }
+}
+#endif
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Change window offset                                                  */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT move_window (
+    FATFS *fs,        /* File system object */
+    DWORD sector    /* Sector number to make apperance in the fs->win[] */
+)                    /* Move to zero only writes back dirty window */
+{
+    DWORD wsect;
+
+
+    wsect = fs->winsect;
+    if (wsect != sector) {    /* Changed current window */
+#if !_FS_READONLY
+        if (fs->wflag) {    /* Write back dirty window if needed */
+            if (disk_write(fs->drive, fs->win, wsect, 1) != RES_OK)
+                return FR_DISK_ERR;
+            fs->wflag = 0;
+            if (wsect < (fs->fatbase + fs->sects_fat)) {    /* In FAT area */
+                BYTE nf;
+                for (nf = fs->n_fats; nf > 1; nf--) {    /* Refrect the change to all FAT copies */
+                    wsect += fs->sects_fat;
+                    disk_write(fs->drive, fs->win, wsect, 1);
+                }
+            }
+        }
+#endif
+        if (sector) {
+            if (disk_read(fs->drive, fs->win, sector, 1) != RES_OK)
+                return FR_DISK_ERR;
+            fs->winsect = sector;
+        }
+    }
+
+    return FR_OK;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Clean-up cached data                                                  */
+/*-----------------------------------------------------------------------*/
+#if !_FS_READONLY
+static
+FRESULT sync (    /* FR_OK: successful, FR_DISK_ERR: failed */
+    FATFS *fs    /* File system object */
+)
+{
+    FRESULT res;
+
+
+    res = move_window(fs, 0);
+    if (res == FR_OK) {
+        /* Update FSInfo sector if needed */
+        if (fs->fs_type == FS_FAT32 && fs->fsi_flag) {
+            fs->winsect = 0;
+            mem_set(fs->win, 0, 512);
+            ST_WORD(fs->win+BS_55AA, 0xAA55);
+            ST_DWORD(fs->win+FSI_LeadSig, 0x41615252);
+            ST_DWORD(fs->win+FSI_StrucSig, 0x61417272);
+            ST_DWORD(fs->win+FSI_Free_Count, fs->free_clust);
+            ST_DWORD(fs->win+FSI_Nxt_Free, fs->last_clust);
+            disk_write(fs->drive, fs->win, fs->fsi_sector, 1);
+            fs->fsi_flag = 0;
+        }
+        /* Make sure that no pending write process in the physical drive */
+        if (disk_ioctl(fs->drive, CTRL_SYNC, (void*)NULL) != RES_OK)
+            res = FR_DISK_ERR;
+    }
+
+    return res;
+}
+#endif
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* FAT access - Read value of a FAT entry                                */
+/*-----------------------------------------------------------------------*/
+
+
+DWORD get_fat (    /* 0xFFFFFFFF:Disk error, 1:Interal error, Else:Cluster status */
+    FATFS *fs,    /* File system object */
+    DWORD clst    /* Cluster# to get the link information */
+)
+{
+    UINT wc, bc;
+    DWORD fsect;
+
+
+    if (clst < 2 || clst >= fs->max_clust)    /* Range check */
+        return 1;
+
+    fsect = fs->fatbase;
+    switch (fs->fs_type) {
+    case FS_FAT12 :
+        bc = clst; bc += bc / 2;
+        if (move_window(fs, fsect + (bc / SS(fs)))) break;
+        wc = fs->win[bc & (SS(fs) - 1)]; bc++;
+        if (move_window(fs, fsect + (bc / SS(fs)))) break;
+        wc |= (WORD)fs->win[bc & (SS(fs) - 1)] << 8;
+        return (clst & 1) ? (wc >> 4) : (wc & 0xFFF);
+
+    case FS_FAT16 :
+        if (move_window(fs, fsect + (clst / (SS(fs) / 2)))) break;
+        return LD_WORD(&fs->win[((WORD)clst * 2) & (SS(fs) - 1)]);
+
+    case FS_FAT32 :
+        if (move_window(fs, fsect + (clst / (SS(fs) / 4)))) break;
+        return LD_DWORD(&fs->win[((WORD)clst * 4) & (SS(fs) - 1)]) & 0x0FFFFFFF;
+    }
+
+    return 0xFFFFFFFF;    /* An error occured at the disk I/O layer */
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* FAT access - Change value of a FAT entry                              */
+/*-----------------------------------------------------------------------*/
+#if !_FS_READONLY
+
+FRESULT put_fat (
+    FATFS *fs,    /* File system object */
+    DWORD clst,    /* Cluster# to be changed in range of 2 to fs->max_clust - 1 */
+    DWORD val    /* New value to mark the cluster */
+)
+{
+    UINT bc;
+    BYTE *p;
+    DWORD fsect;
+    FRESULT res;
+
+
+    if (clst < 2 || clst >= fs->max_clust) {    /* Range check */
+        res = FR_INT_ERR;
+
+    } else {
+        fsect = fs->fatbase;
+        switch (fs->fs_type) {
+        case FS_FAT12 :
+            bc = clst; bc += bc / 2;
+            res = move_window(fs, fsect + (bc / SS(fs)));
+            if (res != FR_OK) break;
+            p = &fs->win[bc & (SS(fs) - 1)];
+            *p = (clst & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val;
+            bc++;
+            fs->wflag = 1;
+            res = move_window(fs, fsect + (bc / SS(fs)));
+            if (res != FR_OK) break;
+            p = &fs->win[bc & (SS(fs) - 1)];
+            *p = (clst & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F));
+            break;
+
+        case FS_FAT16 :
+            res = move_window(fs, fsect + (clst / (SS(fs) / 2)));
+            if (res != FR_OK) break;
+            ST_WORD(&fs->win[((WORD)clst * 2) & (SS(fs) - 1)], (WORD)val);
+            break;
+
+        case FS_FAT32 :
+            res = move_window(fs, fsect + (clst / (SS(fs) / 4)));
+            if (res != FR_OK) break;
+            ST_DWORD(&fs->win[((WORD)clst * 4) & (SS(fs) - 1)], val);
+            break;
+
+        default :
+            res = FR_INT_ERR;
+        }
+        fs->wflag = 1;
+    }
+
+    return res;
+}
+#endif /* !_FS_READONLY */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* FAT handling - Remove a cluster chain                                 */
+/*-----------------------------------------------------------------------*/
+#if !_FS_READONLY
+static
+FRESULT remove_chain (
+    FATFS *fs,            /* File system object */
+    DWORD clst            /* Cluster# to remove a chain from */
+)
+{
+    FRESULT res;
+    DWORD nxt;
+
+
+    if (clst < 2 || clst >= fs->max_clust) {    /* Check the range of cluster# */
+        res = FR_INT_ERR;
+
+    } else {
+        res = FR_OK;
+        while (clst < fs->max_clust) {            /* Not a last link? */
+            nxt = get_fat(fs, clst);            /* Get cluster status */
+            if (nxt == 0) break;                /* Empty cluster? */
+            if (nxt == 1) { res = FR_INT_ERR; break; }    /* Internal error? */
+            if (nxt == 0xFFFFFFFF) { res = FR_DISK_ERR; break; }    /* Disk error? */
+            res = put_fat(fs, clst, 0);            /* Mark the cluster "empty" */
+            if (res != FR_OK) break;
+            if (fs->free_clust != 0xFFFFFFFF) {    /* Update FSInfo */
+                fs->free_clust++;
+                fs->fsi_flag = 1;
+            }
+            clst = nxt;    /* Next cluster */
+        }
+    }
+
+    return res;
+}
+#endif
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* FAT handling - Stretch or Create a cluster chain                      */
+/*-----------------------------------------------------------------------*/
+#if !_FS_READONLY
+static
+DWORD create_chain (    /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */
+    FATFS *fs,            /* File system object */
+    DWORD clst            /* Cluster# to stretch. 0 means create a new chain. */
+)
+{
+    DWORD cs, ncl, scl, mcl;
+
+
+    mcl = fs->max_clust;
+    if (clst == 0) {        /* Create new chain */
+        scl = fs->last_clust;            /* Get suggested start point */
+        if (scl == 0 || scl >= mcl) scl = 1;
+    }
+    else {                    /* Stretch existing chain */
+        cs = get_fat(fs, clst);            /* Check the cluster status */
+        if (cs < 2) return 1;            /* It is an invalid cluster */
+        if (cs < mcl) return cs;        /* It is already followed by next cluster */
+        scl = clst;
+    }
+
+    ncl = scl;                /* Start cluster */
+    for (;;) {
+        ncl++;                            /* Next cluster */
+        if (ncl >= mcl) {                /* Wrap around */
+            ncl = 2;
+            if (ncl > scl) return 0;    /* No free custer */
+        }
+        cs = get_fat(fs, ncl);            /* Get the cluster status */
+        if (cs == 0) break;                /* Found a free cluster */
+        if (cs == 0xFFFFFFFF || cs == 1)/* An error occured */
+            return cs;
+        if (ncl == scl) return 0;        /* No free custer */
+    }
+
+    if (put_fat(fs, ncl, 0x0FFFFFFF))    /* Mark the new cluster "in use" */
+        return 0xFFFFFFFF;
+    if (clst != 0) {                    /* Link it to the previous one if needed */
+        if (put_fat(fs, clst, ncl))
+            return 0xFFFFFFFF;
+    }
+
+    fs->last_clust = ncl;                /* Update FSINFO */
+    if (fs->free_clust != 0xFFFFFFFF) {
+        fs->free_clust--;
+        fs->fsi_flag = 1;
+    }
+
+    return ncl;        /* Return new cluster number */
+}
+#endif /* !_FS_READONLY */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Get sector# from cluster#                                             */
+/*-----------------------------------------------------------------------*/
+
+
+DWORD clust2sect (    /* !=0: Sector number, 0: Failed - invalid cluster# */
+    FATFS *fs,        /* File system object */
+    DWORD clst        /* Cluster# to be converted */
+)
+{
+    clst -= 2;
+    if (clst >= (fs->max_clust - 2)) return 0;        /* Invalid cluster# */
+    return clst * fs->csize + fs->database;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Directory handling - Seek directory index                             */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT dir_seek (
+    eDIR *dj,        /* Pointer to directory object */
+    WORD idx        /* Directory index number */
+)
+{
+    DWORD clst;
+    WORD ic;
+
+
+    dj->index = idx;
+    clst = dj->sclust;
+    if (clst == 1 || clst >= dj->fs->max_clust)    /* Check start cluster range */
+        return FR_INT_ERR;
+    if (!clst && dj->fs->fs_type == FS_FAT32)    /* Replace cluster# 0 with root cluster# if in FAT32 */
+        clst = dj->fs->dirbase;
+
+    if (clst == 0) {    /* Static table */
+        dj->clust = clst;
+        if (idx >= dj->fs->n_rootdir)        /* Index is out of range */
+            return FR_INT_ERR;
+        dj->sect = dj->fs->dirbase + idx / (SS(dj->fs) / 32);    /* Sector# */
+    }
+    else {                /* Dynamic table */
+        ic = SS(dj->fs) / 32 * dj->fs->csize;    /* Entries per cluster */
+        while (idx >= ic) {    /* Follow cluster chain */
+            clst = get_fat(dj->fs, clst);                /* Get next cluster */
+            if (clst == 0xFFFFFFFF) return FR_DISK_ERR;    /* Disk error */
+            if (clst < 2 || clst >= dj->fs->max_clust)    /* Reached to end of table or int error */
+                return FR_INT_ERR;
+            idx -= ic;
+        }
+        dj->clust = clst;
+        dj->sect = clust2sect(dj->fs, clst) + idx / (SS(dj->fs) / 32);    /* Sector# */
+    }
+
+    dj->dir = dj->fs->win + (idx % (SS(dj->fs) / 32)) * 32;    /* Ptr to the entry in the sector */
+
+    return FR_OK;    /* Seek succeeded */
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Directory handling - Move directory index next                        */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT dir_next (    /* FR_OK:Succeeded, FR_NO_FILE:End of table, FR_DENIED:EOT and could not streach */
+    eDIR *dj,        /* Pointer to directory object */
+    BOOL streach    /* FALSE: Do not streach table, TRUE: Streach table if needed */
+)
+{
+    DWORD clst;
+    WORD i;
+
+
+    i = dj->index + 1;
+    if (!i || !dj->sect)    /* Report EOT when index has reached 65535 */
+        return FR_NO_FILE;
+
+    if (!(i % (SS(dj->fs) / 32))) {    /* Sector changed? */
+        dj->sect++;                    /* Next sector */
+
+        if (dj->clust == 0) {    /* Static table */
+            if (i >= dj->fs->n_rootdir)    /* Report EOT when end of table */
+                return FR_NO_FILE;
+        }
+        else {                    /* Dynamic table */
+            if (((i / (SS(dj->fs) / 32)) & (dj->fs->csize - 1)) == 0) {    /* Cluster changed? */
+                clst = get_fat(dj->fs, dj->clust);                /* Get next cluster */
+                if (clst <= 1) return FR_INT_ERR;
+                if (clst == 0xFFFFFFFF) return FR_DISK_ERR;
+                if (clst >= dj->fs->max_clust) {                /* When it reached end of dynamic table */
+#if !_FS_READONLY
+                    BYTE c;
+                    if (!streach) return FR_NO_FILE;            /* When do not streach, report EOT */
+                    clst = create_chain(dj->fs, dj->clust);        /* Streach cluster chain */
+                    if (clst == 0) return FR_DENIED;            /* No free cluster */
+                    if (clst == 1) return FR_INT_ERR;
+                    if (clst == 0xFFFFFFFF) return FR_DISK_ERR;
+                    /* Clean-up streached table */
+                    if (move_window(dj->fs, 0)) return FR_DISK_ERR;    /* Flush active window */
+                    mem_set(dj->fs->win, 0, SS(dj->fs));            /* Clear window buffer */
+                    dj->fs->winsect = clust2sect(dj->fs, clst);    /* Cluster start sector */
+                    for (c = 0; c < dj->fs->csize; c++) {        /* Fill the new cluster with 0 */
+                        dj->fs->wflag = 1;
+                        if (move_window(dj->fs, 0)) return FR_DISK_ERR;
+                        dj->fs->winsect++;
+                    }
+                    dj->fs->winsect -= c;                        /* Rewind window address */
+#else
+                    return FR_NO_FILE;            /* Report EOT */
+#endif
+                }
+                dj->clust = clst;                /* Initialize data for new cluster */
+                dj->sect = clust2sect(dj->fs, clst);
+            }
+        }
+    }
+
+    dj->index = i;
+    dj->dir = dj->fs->win + (i % (SS(dj->fs) / 32)) * 32;
+
+    return FR_OK;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* LFN handling - Test/Pick/Fit an LFN segment from/to directory entry   */
+/*-----------------------------------------------------------------------*/
+#if _USE_LFN
+static
+const BYTE LfnOfs[] = {1,3,5,7,9,14,16,18,20,22,24,28,30};    /* Offset of LFN chars in the directory entry */
+
+
+static
+BOOL cmp_lfn (            /* TRUE:Matched, FALSE:Not matched */
+    WCHAR *lfnbuf,        /* Pointer to the LFN to be compared */
+    BYTE *dir            /* Pointer to the directory entry containing a part of LFN */
+)
+{
+    int i, s;
+    WCHAR wc, uc;
+
+
+    i = ((dir[LDIR_Ord] & 0xBF) - 1) * 13;    /* Get offset in the LFN buffer */
+    s = 0; wc = 1;
+    do {
+        uc = LD_WORD(dir+LfnOfs[s]);    /* Pick an LFN character from the entry */
+        if (wc) {    /* Last char has not been processed */
+            wc = ff_wtoupper(uc);        /* Convert it to upper case */
+            if (i >= _MAX_LFN || wc != ff_wtoupper(lfnbuf[i++]))    /* Compare it */
+                return FALSE;            /* Not matched */
+        } else {
+            if (uc != 0xFFFF) return FALSE;    /* Check filler */
+        }
+    } while (++s < 13);                /* Repeat until all chars in the entry are checked */
+
+    if ((dir[LDIR_Ord] & 0x40) && wc && lfnbuf[i])    /* Last segment matched but different length */
+        return FALSE;
+
+    return TRUE;                    /* The part of LFN matched */
+}
+
+
+
+static
+BOOL pick_lfn (            /* TRUE:Succeeded, FALSE:Buffer overflow */
+    WCHAR *lfnbuf,        /* Pointer to the Unicode-LFN buffer */
+    BYTE *dir            /* Pointer to the directory entry */
+)
+{
+    int i, s;
+    WCHAR wc, uc;
+
+
+    i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13;    /* Offset in the LFN buffer */
+
+    s = 0; wc = 1;
+    do {
+        uc = LD_WORD(dir+LfnOfs[s]);            /* Pick an LFN character from the entry */
+        if (wc) {    /* Last char has not been processed */
+            if (i >= _MAX_LFN) return FALSE;    /* Buffer overflow? */
+            lfnbuf[i++] = wc = uc;                /* Store it */
+        } else {
+            if (uc != 0xFFFF) return FALSE;        /* Check filler */
+        }
+    } while (++s < 13);                        /* Read all character in the entry */
+
+    if (dir[LDIR_Ord] & 0x40) {                /* Put terminator if it is the last LFN part */
+        if (i >= _MAX_LFN) return FALSE;    /* Buffer overflow? */
+        lfnbuf[i] = 0;
+    }
+
+    return TRUE;
+}
+
+
+#if !_FS_READONLY
+static
+void fit_lfn (
+    const WCHAR *lfnbuf,    /* Pointer to the LFN buffer */
+    BYTE *dir,                /* Pointer to the directory entry */
+    BYTE ord,                /* LFN order (1-20) */
+    BYTE sum                /* SFN sum */
+)
+{
+    int i, s;
+    WCHAR wc;
+
+
+    dir[LDIR_Chksum] = sum;            /* Set check sum */
+    dir[LDIR_Attr] = AM_LFN;        /* Set attribute. LFN entry */
+    dir[LDIR_Type] = 0;
+    ST_WORD(dir+LDIR_FstClusLO, 0);
+
+    i = (ord - 1) * 13;                /* Get offset in the LFN buffer */
+    s = wc = 0;
+    do {
+        if (wc != 0xFFFF) wc = lfnbuf[i++];    /* Get an effective char */
+        ST_WORD(dir+LfnOfs[s], wc);    /* Put it */
+        if (!wc) wc = 0xFFFF;        /* Padding chars following last char */
+    } while (++s < 13);
+    if (wc == 0xFFFF || !lfnbuf[i]) ord |= 0x40;    /* Bottom LFN part is the start of LFN sequence */
+    dir[LDIR_Ord] = ord;            /* Set the LFN order */
+}
+
+#endif
+#endif
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Create numbered name                                                  */
+/*-----------------------------------------------------------------------*/
+#if _USE_LFN
+void gen_numname (
+    BYTE *dst,            /* Pointer to genartated SFN */
+    const BYTE *src,    /* Pointer to source SFN to be modified */
+    const WCHAR *lfn,    /* Pointer to LFN */
+    WORD num            /* Sequense number */
+)
+{
+    char ns[8];
+    int i, j;
+
+
+    mem_cpy(dst, src, 11);
+
+    if (num > 5) {    /* On many collisions, generate a hash number instead of sequencial number */
+        do num = (num >> 1) + (num << 15) + (WORD)*lfn++; while (*lfn);
+    }
+
+    /* itoa */
+    i = 7;
+    do {
+        ns[i--] = (num % 10) + '0';
+        num /= 10;
+    } while (num);
+    ns[i] = '~';
+
+    /* Append the number */
+    for (j = 0; j < i && dst[j] != ' '; j++) {
+        if (IsDBCS1(dst[j])) {
+            if (j == i - 1) break;
+            j++;
+        }
+    }
+    do {
+        dst[j++] = (i < 8) ? ns[i++] : ' ';
+    } while (j < 8);
+}
+#endif
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Calculate sum of an SFN                                               */
+/*-----------------------------------------------------------------------*/
+#if _USE_LFN
+static
+BYTE sum_sfn (
+    const BYTE *dir        /* Ptr to directory entry */
+)
+{
+    BYTE sum = 0;
+    int n = 11;
+
+    do sum = (sum >> 1) + (sum << 7) + *dir++; while (--n);
+    return sum;
+}
+#endif
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Directory handling - Find an object in the directory                  */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT dir_find (
+    eDIR *dj            /* Pointer to the directory object linked to the file name */
+)
+{
+    FRESULT res;
+    BYTE c, *dir;
+#if _USE_LFN
+    BYTE a, ord, sum;
+#endif
+
+    res = dir_seek(dj, 0);            /* Rewind directory object */
+    if (res != FR_OK) return res;
+
+#if _USE_LFN
+    ord = sum = 0xFF;
+#endif
+    do {
+        res = move_window(dj->fs, dj->sect);
+        if (res != FR_OK) break;
+        dir = dj->dir;                    /* Ptr to the directory entry of current index */
+        c = dir[DIR_Name];
+        if (c == 0) { res = FR_NO_FILE; break; }    /* Reached to end of table */
+#if _USE_LFN    /* LFN configuration */
+        a = dir[DIR_Attr] & AM_MASK;
+        if (c == 0xE5 || ((a & AM_VOL) && a != AM_LFN)) {    /* An entry without valid data */
+            ord = 0xFF;
+        } else {
+            if (a == AM_LFN) {            /* An LFN entry is found */
+                if (dj->lfn) {
+                    if (c & 0x40) {        /* Is it start of LFN sequence? */
+                        sum = dir[LDIR_Chksum];
+                        c &= 0xBF; ord = c;    /* LFN start order */
+                        dj->lfn_idx = dj->index;
+                    }
+                    /* Check validity of the LFN entry and compare it with given name */
+                    ord = (c == ord && sum == dir[LDIR_Chksum] && cmp_lfn(dj->lfn, dir)) ? ord - 1 : 0xFF;
+                }
+            } else {                    /* An SFN entry is found */
+                if (!ord && sum == sum_sfn(dir)) break;    /* LFN matched? */
+                ord = 0xFF; dj->lfn_idx = 0xFFFF;    /* Reset LFN sequence */
+                if (!(dj->fn[NS] & NS_LOSS) && !mem_cmp(dir, dj->fn, 11)) break;    /* SFN matched? */
+            }
+        }
+#else        /* Non LFN configuration */
+        if (!(dir[DIR_Attr] & AM_VOL) && !mem_cmp(dir, dj->fn, 11)) /* Is it a valid entry? */
+            break;
+#endif
+        res = dir_next(dj, FALSE);        /* Next entry */
+    } while (res == FR_OK);
+
+    return res;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Read an object from the directory                                     */
+/*-----------------------------------------------------------------------*/
+#if _FS_MINIMIZE <= 1
+static
+FRESULT dir_read (
+    eDIR *dj            /* Pointer to the directory object that pointing the entry to be read */
+)
+{
+    FRESULT res;
+    BYTE c, *dir;
+#if _USE_LFN
+    BYTE a, ord = 0xFF, sum = 0xFF;
+#endif
+
+    res = FR_NO_FILE;
+    while (dj->sect) {
+        res = move_window(dj->fs, dj->sect);
+        if (res != FR_OK) break;
+        dir = dj->dir;                    /* Ptr to the directory entry of current index */
+        c = dir[DIR_Name];
+        if (c == 0) { res = FR_NO_FILE; break; }    /* Reached to end of table */
+#if _USE_LFN    /* LFN configuration */
+        a = dir[DIR_Attr] & AM_MASK;
+        if (c == 0xE5 || (!_FS_RPATH && c == '.') || ((a & AM_VOL) && a != AM_LFN)) {    /* An entry without valid data */
+            ord = 0xFF;
+        } else {
+            if (a == AM_LFN) {            /* An LFN entry is found */
+                if (c & 0x40) {            /* Is it start of LFN sequence? */
+                    sum = dir[LDIR_Chksum];
+                    c &= 0xBF; ord = c;
+                    dj->lfn_idx = dj->index;
+                }
+                /* Check LFN validity and capture it */
+                ord = (c == ord && sum == dir[LDIR_Chksum] && pick_lfn(dj->lfn, dir)) ? ord - 1 : 0xFF;
+            } else {                    /* An SFN entry is found */
+                if (ord || sum != sum_sfn(dir))    /* Is there a valid LFN? */
+                    dj->lfn_idx = 0xFFFF;        /* It has no LFN. */
+                break;
+            }
+        }
+#else        /* Non LFN configuration */
+        if (c != 0xE5 && (_FS_RPATH || c != '.') && !(dir[DIR_Attr] & AM_VOL))    /* Is it a valid entry? */
+            break;
+#endif
+        res = dir_next(dj, FALSE);                /* Next entry */
+        if (res != FR_OK) break;
+    }
+
+    if (res != FR_OK) dj->sect = 0;
+
+    return res;
+}
+#endif
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Register an object to the directory                                   */
+/*-----------------------------------------------------------------------*/
+#if !_FS_READONLY
+static
+FRESULT dir_register (    /* FR_OK:Successful, FR_DENIED:No free entry or too many SFN collision, FR_DISK_ERR:Disk error */
+    eDIR *dj                /* Target directory with object name to be created */
+)
+{
+    FRESULT res;
+    BYTE c, *dir;
+#if _USE_LFN    /* LFN configuration */
+    WORD n, ne, is;
+    BYTE sn[12], *fn, sum;
+    WCHAR *lfn;
+
+
+    fn = dj->fn; lfn = dj->lfn;
+    mem_cpy(sn, fn, 12);
+
+    if (_FS_RPATH && (sn[NS] & NS_DOT)) return FR_INVALID_NAME;    /* Cannot create dot entry */
+
+    if (sn[NS] & NS_LOSS) {            /* When LFN is out of 8.3 format, generate a numbered name */
+        fn[NS] = 0; dj->lfn = NULL;            /* Find only SFN */
+        for (n = 1; n < 100; n++) {
+            gen_numname(fn, sn, lfn, n);    /* Generate a numbered name */
+            res = dir_find(dj);                /* Check if the name collides with existing SFN */
+            if (res != FR_OK) break;
+        }
+        if (n == 100) return FR_DENIED;        /* Abort if too many collisions */
+        if (res != FR_NO_FILE) return res;    /* Abort if the result is other than 'not collided' */
+        fn[NS] = sn[NS]; dj->lfn = lfn;
+    }
+
+    if (sn[NS] & NS_LFN) {            /* When LFN is to be created, reserve reserve an SFN + LFN entries. */
+        for (ne = 0; lfn[ne]; ne++) ;
+        ne = (ne + 25) / 13;
+    } else {                        /* Otherwise reserve only an SFN entry. */
+        ne = 1;
+    }
+
+    /* Reserve contiguous entries */
+    res = dir_seek(dj, 0);
+    if (res != FR_OK) return res;
+    n = is = 0;
+    do {
+        res = move_window(dj->fs, dj->sect);
+        if (res != FR_OK) break;
+        c = *dj->dir;                /* Check the entry status */
+        if (c == 0xE5 || c == 0) {    /* Is it a blank entry? */
+            if (n == 0) is = dj->index;    /* First index of the contigulus entry */
+            if (++n == ne) break;    /* A contiguous entry that requiered count is found */
+        } else {
+            n = 0;                    /* Not a blank entry. Restart to search */
+        }
+        res = dir_next(dj, TRUE);    /* Next entry with table streach */
+    } while (res == FR_OK);
+
+    if (res == FR_OK && ne > 1) {    /* Initialize LFN entry if needed */
+        res = dir_seek(dj, is);
+        if (res == FR_OK) {
+            sum = sum_sfn(dj->fn);    /* Sum of the SFN tied to the LFN */
+            ne--;
+            do {                    /* Store LFN entries in bottom first */
+                res = move_window(dj->fs, dj->sect);
+                if (res != FR_OK) break;
+                fit_lfn(dj->lfn, dj->dir, (BYTE)ne, sum);
+                dj->fs->wflag = 1;
+                res = dir_next(dj, FALSE);    /* Next entry */
+            } while (res == FR_OK && --ne);
+        }
+    }
+
+#else    /* Non LFN configuration */
+    res = dir_seek(dj, 0);
+    if (res == FR_OK) {
+        do {    /* Find a blank entry for the SFN */
+            res = move_window(dj->fs, dj->sect);
+            if (res != FR_OK) break;
+            c = *dj->dir;
+            if (c == 0xE5 || c == 0) break;    /* Is it a blank entry? */
+            res = dir_next(dj, TRUE);        /* Next entry with table streach */
+        } while (res == FR_OK);
+    }
+#endif
+
+    if (res == FR_OK) {        /* Initialize the SFN entry */
+        res = move_window(dj->fs, dj->sect);
+        if (res == FR_OK) {
+            dir = dj->dir;
+            mem_set(dir, 0, 32);        /* Clean the entry */
+            mem_cpy(dir, dj->fn, 11);    /* Put SFN */
+            dir[DIR_NTres] = *(dj->fn+NS) & (NS_BODY | NS_EXT);    /* Put NT flag */
+            dj->fs->wflag = 1;
+        }
+    }
+
+    return res;
+}
+#endif /* !_FS_READONLY */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Remove an object from the directory                                   */
+/*-----------------------------------------------------------------------*/
+#if !_FS_READONLY && !_FS_MINIMIZE
+static
+FRESULT dir_remove (    /* FR_OK: Successful, FR_DISK_ERR: A disk error */
+    eDIR *dj                /* Directory object pointing the entry to be removed */
+)
+{
+    FRESULT res;
+#if _USE_LFN    /* LFN configuration */
+    WORD i;
+
+    i = dj->index;    /* SFN index */
+    res = dir_seek(dj, (WORD)((dj->lfn_idx == 0xFFFF) ? i : dj->lfn_idx));    /* Goto the SFN or top of the LFN entries */
+    if (res == FR_OK) {
+        do {
+            res = move_window(dj->fs, dj->sect);
+            if (res != FR_OK) break;
+            *dj->dir = 0xE5;            /* Mark the entry "deleted" */
+            dj->fs->wflag = 1;
+            if (dj->index >= i) break;    /* When reached SFN, all entries of the object has been deleted. */
+            res = dir_next(dj, FALSE);    /* Next entry */
+        } while (res == FR_OK);
+        if (res == FR_NO_FILE) res = FR_INT_ERR;
+    }
+
+#else            /* Non LFN configuration */
+    res = dir_seek(dj, dj->index);
+    if (res == FR_OK) {
+        res = move_window(dj->fs, dj->sect);
+        if (res == FR_OK) {
+            *dj->dir = 0xE5;            /* Mark the entry "deleted" */
+            dj->fs->wflag = 1;
+        }
+    }
+#endif
+
+    return res;
+}
+#endif /* !_FS_READONLY */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Pick a segment and create the object name in directory form           */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT create_name (
+    eDIR *dj,            /* Pointer to the directory object */
+    const XCHAR **path    /* Pointer to pointer to the segment in the path string */
+)
+{
+#ifdef _EXCVT
+    static const BYTE cvt[] = _EXCVT;
+#endif
+
+#if _USE_LFN    /* LFN configuration */
+    BYTE b, cf;
+    WCHAR w, *lfn;
+    int i, ni, si, di;
+    const XCHAR *p;
+
+    /* Create LFN in Unicode */
+    si = di = 0;
+    p = *path;
+    lfn = dj->lfn;
+    for (;;) {
+        w = p[si++];                    /* Get a character */
+        if (w < ' ' || w == '/' || w == '\\') break;    /* Break on end of segment */
+        if (di >= _MAX_LFN)                /* Reject too long name */
+            return FR_INVALID_NAME;
+#if !_LFN_UNICODE
+        w &= 0xFF;
+        if (IsDBCS1(w)) {                /* If it is a DBC 1st byte */
+            b = p[si++];                /* Get 2nd byte */
+            if (!IsDBCS2(b))            /* Reject invalid code for DBC */
+                return FR_INVALID_NAME;
+            w = (w << 8) + b;
+        }
+        w = ff_convert(w, 1);            /* Convert OEM to Unicode */
+        if (!w) return FR_INVALID_NAME;    /* Reject invalid code */
+#endif
+        if (w < 0x80 && chk_chr("\"*:<>\?|\x7F", w)) /* Reject illegal chars for LFN */
+            return FR_INVALID_NAME;
+        lfn[di++] = w;                    /* Store the Unicode char */
+    }
+    *path = &p[si];                        /* Rerurn pointer to the next segment */
+    cf = (w < ' ') ? NS_LAST : 0;        /* Set last segment flag if end of path */
+#if _FS_RPATH
+    if ((di == 1 && lfn[di - 1] == '.') || /* Is this a dot entry? */
+        (di == 2 && lfn[di - 1] == '.' && lfn[di - 2] == '.')) {
+        lfn[di] = 0;
+        for (i = 0; i < 11; i++)
+            dj->fn[i] = (i < di) ? '.' : ' ';
+        dj->fn[i] = cf | NS_DOT;        /* This is a dot entry */
+        return FR_OK;
+    }
+#endif
+    while (di) {                        /* Strip trailing spaces and dots */
+        w = lfn[di - 1];
+        if (w != ' ' && w != '.') break;
+        di--;
+    }
+    if (!di) return FR_INVALID_NAME;    /* Reject null string */
+
+    lfn[di] = 0;                        /* LFN is created */
+
+    /* Create SFN in directory form */
+    mem_set(dj->fn, ' ', 11);
+    for (si = 0; lfn[si] == ' ' || lfn[si] == '.'; si++) ;    /* Strip leading spaces and dots */
+    if (si) cf |= NS_LOSS | NS_LFN;
+    while (di && lfn[di - 1] != '.') di--;    /* Find extension (di<=si: no extension) */
+
+    b = i = 0; ni = 8;
+    for (;;) {
+        w = lfn[si++];                    /* Get an LFN char */
+        if (!w) break;                    /* Break on enf of the LFN */
+        if (w == ' ' || (w == '.' && si != di)) {    /* Remove spaces and dots */
+            cf |= NS_LOSS | NS_LFN; continue;
+        }
+
+        if (i >= ni || si == di) {        /* Extension or end of SFN */
+            if (ni == 11) {                /* Long extension */
+                cf |= NS_LOSS | NS_LFN; break;
+            }
+            if (si != di) cf |= NS_LOSS | NS_LFN;    /* Out of 8.3 format */
+            if (si > di) break;            /* No extension */
+            si = di; i = 8; ni = 11;    /* Enter extension section */
+            b <<= 2; continue;
+        }
+
+        if (w >= 0x80) {                /* Non ASCII char */
+#ifdef _EXCVT
+            w = ff_convert(w, 0);        /* Unicode -> OEM code */
+            if (w) w = cvt[w - 0x80];    /* Convert extended char to upper (SBCS) */
+#else
+            w = ff_convert(ff_wtoupper(w), 0);    /* Upper converted Unicode -> OEM code */
+#endif
+            cf |= NS_LFN;                /* Force create LFN entry */
+        }
+
+        if (_DF1S && w >= 0x100) {        /* Double byte char */
+            if (i >= ni - 1) {
+                cf |= NS_LOSS | NS_LFN; i = ni; continue;
+            }
+            dj->fn[i++] = (BYTE)(w >> 8);
+        } else {                        /* Single byte char */
+            if (!w || chk_chr("+,;[=]", w)) {        /* Replace illegal chars for SFN */
+                w = '_'; cf |= NS_LOSS | NS_LFN;    /* Lossy conversion */
+            } else {
+                if (IsUpper(w)) {        /* ASCII large capital */
+                    b |= 2;
+                } else {
+                    if (IsLower(w)) {    /* ASCII small capital */
+                        b |= 1; w -= 0x20;
+                    }
+                }
+            }
+        }
+        dj->fn[i++] = (BYTE)w;
+    }
+
+    if (dj->fn[0] == 0xE5) dj->fn[0] = 0x05;    /* If the first char collides with deleted mark, replace it with 0x05 */
+
+    if (ni == 8) b <<= 2;
+    if ((b & 0x0C) == 0x0C || (b & 0x03) == 0x03)    /* Create LFN entry when there are composite capitals */
+        cf |= NS_LFN;
+    if (!(cf & NS_LFN)) {                        /* When LFN is in 8.3 format without extended char, NT flags are created */
+        if ((b & 0x03) == 0x01) cf |= NS_EXT;    /* NT flag (Extension has only small capital) */
+        if ((b & 0x0C) == 0x04) cf |= NS_BODY;    /* NT flag (Filename has only small capital) */
+    }
+
+    dj->fn[NS] = cf;    /* SFN is created */
+
+    return FR_OK;
+
+
+#else    /* Non-LFN configuration */
+    BYTE b, c, d, *sfn;
+    int ni, si, i;
+    const char *p;
+
+    /* Create file name in directory form */
+    sfn = dj->fn;
+    mem_set(sfn, ' ', 11);
+    si = i = b = 0; ni = 8;
+    p = *path;
+#if _FS_RPATH
+    if (p[si] == '.') { /* Is this a dot entry? */
+        for (;;) {
+            c = p[si++];
+            if (c != '.' || si >= 3) break;
+            sfn[i++] = c;
+        }
+        if (c != '/' && c != '\\' && c > ' ') return FR_INVALID_NAME;
+        *path = &p[si];                                    /* Rerurn pointer to the next segment */
+        sfn[NS] = (c <= ' ') ? NS_LAST | NS_DOT : NS_DOT;    /* Set last segment flag if end of path */
+        return FR_OK;
+    }
+#endif
+    for (;;) {
+        c = p[si++];
+        if (c <= ' ' || c == '/' || c == '\\') break;    /* Break on end of segment */
+        if (c == '.' || i >= ni) {
+            if (ni != 8 || c != '.') return FR_INVALID_NAME;
+            i = 8; ni = 11;
+            b <<= 2; continue;
+        }
+        if (c >= 0x80) {                /* Extended char */
+#ifdef _EXCVT
+            c = cvt[c - 0x80];            /* Convert extend char (SBCS) */
+#else
+            b |= 3;                        /* Eliminate NT flag if ext char is exist */
+#if !_DF1S    /* ASCII only cfg */
+            return FR_INVALID_NAME;
+#endif
+#endif
+        }
+        if (IsDBCS1(c)) {                /* DBC 1st byte? */
+            d = p[si++];                /* Get 2nd byte */
+            if (!IsDBCS2(d) || i >= ni - 1)    /* Reject invalid DBC */
+                return FR_INVALID_NAME;
+            sfn[i++] = c;
+            sfn[i++] = d;
+        } else {                        /* Single byte code */
+            if (chk_chr(" \"*+,[=]|\x7F", c))    /* Reject illegal chrs for SFN */
+                return FR_INVALID_NAME;
+            if (IsUpper(c)) {            /* ASCII large capital? */
+                b |= 2;
+            } else {
+                if (IsLower(c)) {        /* ASCII small capital? */
+                    b |= 1; c -= 0x20;
+                }
+            }
+            sfn[i++] = c;
+        }
+    }
+    *path = &p[si];                        /* Rerurn pointer to the next segment */
+    c = (c <= ' ') ? NS_LAST : 0;        /* Set last segment flag if end of path */
+
+    if (!i) return FR_INVALID_NAME;        /* Reject null string */
+    if (sfn[0] == 0xE5) sfn[0] = 0x05;    /* When first char collides with 0xE5, replace it with 0x05 */
+
+    if (ni == 8) b <<= 2;
+    if ((b & 0x03) == 0x01) c |= NS_EXT;    /* NT flag (Extension has only small capital) */
+    if ((b & 0x0C) == 0x04) c |= NS_BODY;    /* NT flag (Filename has only small capital) */
+
+    sfn[NS] = c;        /* Store NT flag, File name is created */
+
+    return FR_OK;
+#endif
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Get file information from directory entry                             */
+/*-----------------------------------------------------------------------*/
+#if _FS_MINIMIZE <= 1
+static
+void get_fileinfo (        /* No return code */
+    eDIR *dj,            /* Pointer to the directory object */
+    FILINFO *fno         /* Pointer to the file information to be filled */
+)
+{
+    int i;
+    BYTE c, nt, *dir;
+    char *p;
+
+
+    p = fno->fname;
+    if (dj->sect) {
+        dir = dj->dir;
+        nt = dir[DIR_NTres];        /* NT flag */
+        for (i = 0; i < 8; i++) {    /* Copy name body */
+            c = dir[i];
+            if (c == ' ') break;
+            if (c == 0x05) c = 0xE5;
+            if (_USE_LFN && (nt & NS_BODY) && IsUpper(c)) c += 0x20;
+            *p++ = c;
+        }
+        if (dir[8] != ' ') {        /* Copy name extension */
+            *p++ = '.';
+            for (i = 8; i < 11; i++) {
+                c = dir[i];
+                if (c == ' ') break;
+                if (_USE_LFN && (nt & NS_EXT) && IsUpper(c)) c += 0x20;
+                *p++ = c;
+            }
+        }
+        fno->fattrib = dir[DIR_Attr];                /* Attribute */
+        fno->fsize = LD_DWORD(dir+DIR_FileSize);    /* Size */
+        fno->fdate = LD_WORD(dir+DIR_WrtDate);        /* Date */
+        fno->ftime = LD_WORD(dir+DIR_WrtTime);        /* Time */
+    }
+    *p = 0;
+
+#if _USE_LFN
+    if (fno->lfname) {
+        XCHAR *tp = fno->lfname;
+        WCHAR w, *lfn;
+
+        i = 0;
+        if (dj->sect && dj->lfn_idx != 0xFFFF) {/* Get LFN if available */
+            lfn = dj->lfn;
+            while ((w = *lfn++) != 0) {            /* Get an LFN char */
+#if !_LFN_UNICODE
+                w = ff_convert(w, 0);            /* Unicode -> OEM conversion */
+                if (!w) { i = 0; break; }        /* Could not convert, no LFN */
+                if (_DF1S && w >= 0x100)        /* Put 1st byte if it is a DBC */
+                    tp[i++] = (XCHAR)(w >> 8);
+#endif
+                if (i >= fno->lfsize - 1) { i = 0; break; }    /* Buffer overrun, no LFN */
+                tp[i++] = (XCHAR)w;
+            }
+        }
+        tp[i] = 0;    /* Terminator */
+    }
+#endif
+}
+#endif /* _FS_MINIMIZE <= 1 */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Follow a file path                                                    */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT follow_path (    /* FR_OK(0): successful, !=0: error code */
+    eDIR *dj,            /* Directory object to return last directory and found object */
+    const XCHAR *path    /* Full-path string to find a file or directory */
+)
+{
+    FRESULT res;
+    BYTE *dir, last;
+
+
+    while (!_USE_LFN && *path == ' ') path++;    /* Skip leading spaces */
+#if _FS_RPATH
+    if (*path == '/' || *path == '\\') { /* There is a heading separator */
+        path++;    dj->sclust = 0;        /* Strip it and start from the root dir */
+    } else {                            /* No heading saparator */
+        dj->sclust = dj->fs->cdir;    /* Start from the current dir */
+    }
+#else
+    if (*path == '/' || *path == '\\')    /* Strip heading separator if exist */
+        path++;
+    dj->sclust = 0;                        /* Start from the root dir */
+#endif
+
+    if ((UINT)*path < ' ') {            /* Null path means the start directory itself */
+        res = dir_seek(dj, 0);
+        dj->dir = NULL;
+
+    } else {                            /* Follow path */
+        for (;;) {
+            res = create_name(dj, &path);    /* Get a segment */
+            if (res != FR_OK) break;
+            res = dir_find(dj);                /* Find it */
+            last = *(dj->fn+NS) & NS_LAST;
+            if (res != FR_OK) {                /* Could not find the object */
+                if (res == FR_NO_FILE && !last)
+                    res = FR_NO_PATH;
+                break;
+            }
+            if (last) break;                /* Last segment match. Function completed. */
+            dir = dj->dir;                    /* There is next segment. Follow the sub directory */
+            if (!(dir[DIR_Attr] & AM_DIR)) { /* Cannot follow because it is a file */
+                res = FR_NO_PATH; break;
+            }
+            dj->sclust = ((DWORD)LD_WORD(dir+DIR_FstClusHI) << 16) | LD_WORD(dir+DIR_FstClusLO);
+        }
+    }
+
+    return res;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Load boot record and check if it is an FAT boot record                */
+/*-----------------------------------------------------------------------*/
+
+static
+BYTE check_fs (    /* 0:The FAT boot record, 1:Valid boot record but not an FAT, 2:Not a boot record, 3:Error */
+    FATFS *fs,    /* File system object */
+    DWORD sect    /* Sector# (lba) to check if it is an FAT boot record or not */
+)
+{
+    if (disk_read(fs->drive, fs->win, sect, 1) != RES_OK)    /* Load boot record */
+        return 3;
+    if (LD_WORD(&fs->win[BS_55AA]) != 0xAA55)        /* Check record signature (always placed at offset 510 even if the sector size is >512) */
+        return 2;
+
+    if ((LD_DWORD(&fs->win[BS_FilSysType]) & 0xFFFFFF) == 0x544146)    /* Check "FAT" string */
+        return 0;
+    if ((LD_DWORD(&fs->win[BS_FilSysType32]) & 0xFFFFFF) == 0x544146)
+        return 0;
+
+    return 1;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Make sure that the file system is valid                               */
+/*-----------------------------------------------------------------------*/
+
+
+FRESULT chk_mounted (    /* FR_OK(0): successful, !=0: any error occured */
+    const XCHAR **path,    /* Pointer to pointer to the path name (drive number) */
+    FATFS **rfs,        /* Pointer to pointer to the found file system object */
+    BYTE chk_wp            /* !=0: Check media write protection for write access */
+)
+{
+    BYTE fmt, *tbl;
+    UINT vol;
+    DSTATUS stat;
+    DWORD bsect, fsize, tsect, mclst;
+    const XCHAR *p = *path;
+    FATFS *fs;
+
+    /* Get logical drive number from the path name */
+    vol = p[0] - '0';                /* Is there a drive number? */
+    if (vol <= 9 && p[1] == ':') {    /* Found a drive number, get and strip it */
+        p += 2; *path = p;            /* Return pointer to the path name */
+    } else {                        /* No drive number is given */
+#if _FS_RPATH
+        vol = Drive;                /* Use current drive */
+#else
+        vol = 0;                    /* Use drive 0 */
+#endif
+    }
+
+    /* Check if the logical drive is valid or not */
+    if (vol >= _DRIVES)             /* Is the drive number valid? */
+        return FR_INVALID_DRIVE;
+    *rfs = fs = FatFs[vol];            /* Returen pointer to the corresponding file system object */
+    if (!fs) return FR_NOT_ENABLED;    /* Is the file system object available? */
+
+    ENTER_FF(fs);                    /* Lock file system */
+
+    if (fs->fs_type) {                /* If the logical drive has been mounted */
+        stat = disk_status(fs->drive);
+        if (!(stat & STA_NOINIT)) {    /* and the physical drive is kept initialized (has not been changed), */
+#if !_FS_READONLY
+            if (chk_wp && (stat & STA_PROTECT))    /* Check write protection if needed */
+                return FR_WRITE_PROTECTED;
+#endif
+            return FR_OK;            /* The file system object is valid */
+        }
+    }
+
+    /* The logical drive must be mounted. Following code attempts to mount the volume */
+
+    fs->fs_type = 0;                    /* Clear the file system object */
+    fs->drive = (BYTE)LD2PD(vol);        /* Bind the logical drive and a physical drive */
+    stat = disk_initialize(fs->drive);    /* Initialize low level disk I/O layer */
+    if (stat & STA_NOINIT)                /* Check if the drive is ready */
+        return FR_NOT_READY;
+#if _MAX_SS != 512                        /* Get disk sector size if needed */
+    if (disk_ioctl(fs->drive, GET_SECTOR_SIZE, &SS(fs)) != RES_OK || SS(fs) > _MAX_SS)
+        return FR_NO_FILESYSTEM;
+#endif
+#if !_FS_READONLY
+    if (chk_wp && (stat & STA_PROTECT))    /* Check disk write protection if needed */
+        return FR_WRITE_PROTECTED;
+#endif
+    /* Search FAT partition on the drive */
+    fmt = check_fs(fs, bsect = 0);        /* Check sector 0 as an SFD format */
+    if (fmt == 1) {                        /* Not an FAT boot record, it may be patitioned */
+        /* Check a partition listed in top of the partition table */
+        tbl = &fs->win[MBR_Table + LD2PT(vol) * 16];    /* Partition table */
+        if (tbl[4]) {                                    /* Is the partition existing? */
+            bsect = LD_DWORD(&tbl[8]);                    /* Partition offset in LBA */
+            fmt = check_fs(fs, bsect);                    /* Check the partition */
+        }
+    }
+    if (fmt == 3) return FR_DISK_ERR;
+    if (fmt || LD_WORD(fs->win+BPB_BytsPerSec) != SS(fs))    /* No valid FAT patition is found */
+        return FR_NO_FILESYSTEM;
+
+    /* Initialize the file system object */
+    fsize = LD_WORD(fs->win+BPB_FATSz16);                /* Number of sectors per FAT */
+    if (!fsize) fsize = LD_DWORD(fs->win+BPB_FATSz32);
+    fs->sects_fat = fsize;
+    fs->n_fats = fs->win[BPB_NumFATs];                    /* Number of FAT copies */
+    fsize *= fs->n_fats;                                /* (Number of sectors in FAT area) */
+    fs->fatbase = bsect + LD_WORD(fs->win+BPB_RsvdSecCnt); /* FAT start sector (lba) */
+    fs->csize = fs->win[BPB_SecPerClus];                /* Number of sectors per cluster */
+    fs->n_rootdir = LD_WORD(fs->win+BPB_RootEntCnt);    /* Nmuber of root directory entries */
+    tsect = LD_WORD(fs->win+BPB_TotSec16);                /* Number of sectors on the volume */
+    if (!tsect) tsect = LD_DWORD(fs->win+BPB_TotSec32);
+    fs->max_clust = mclst = (tsect                        /* Last cluster# + 1 (Number of clusters + 2) */
+        - LD_WORD(fs->win+BPB_RsvdSecCnt) - fsize - fs->n_rootdir / (SS(fs)/32)
+        ) / fs->csize + 2;
+
+    fmt = FS_FAT12;                                        /* Determine the FAT sub type */
+    if (mclst >= 0xFF7) fmt = FS_FAT16;                    /* Number of clusters >= 0xFF5 */
+    if (mclst >= 0xFFF7) fmt = FS_FAT32;                /* Number of clusters >= 0xFFF5 */
+
+    if (fmt == FS_FAT32)
+        fs->dirbase = LD_DWORD(fs->win+BPB_RootClus);    /* Root directory start cluster */
+    else
+        fs->dirbase = fs->fatbase + fsize;                /* Root directory start sector (lba) */
+    fs->database = fs->fatbase + fsize + fs->n_rootdir / (SS(fs)/32);    /* Data start sector (lba) */
+
+#if !_FS_READONLY
+    /* Initialize allocation information */
+    fs->free_clust = 0xFFFFFFFF;
+    fs->wflag = 0;
+    /* Get fsinfo if needed */
+    if (fmt == FS_FAT32) {
+         fs->fsi_flag = 0;
+        fs->fsi_sector = bsect + LD_WORD(fs->win+BPB_FSInfo);
+        if (disk_read(fs->drive, fs->win, fs->fsi_sector, 1) == RES_OK &&
+            LD_WORD(fs->win+BS_55AA) == 0xAA55 &&
+            LD_DWORD(fs->win+FSI_LeadSig) == 0x41615252 &&
+            LD_DWORD(fs->win+FSI_StrucSig) == 0x61417272) {
+            fs->last_clust = LD_DWORD(fs->win+FSI_Nxt_Free);
+            fs->free_clust = LD_DWORD(fs->win+FSI_Free_Count);
+        }
+    }
+#endif
+    fs->fs_type = fmt;        /* FAT sub-type */
+    fs->winsect = 0;        /* Invalidate sector cache */
+#if _FS_RPATH
+    fs->cdir = 0;            /* Current directory (root dir) */
+#endif
+    fs->id = ++Fsid;        /* File system mount ID */
+
+    return FR_OK;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Check if the file/dir object is valid or not                          */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT validate (    /* FR_OK(0): The object is valid, !=0: Invalid */
+    FATFS *fs,        /* Pointer to the file system object */
+    WORD id            /* Member id of the target object to be checked */
+)
+{
+    if (!fs || !fs->fs_type || fs->id != id)
+        return FR_INVALID_OBJECT;
+
+    ENTER_FF(fs);        /* Lock file system */
+
+    if (disk_status(fs->drive) & STA_NOINIT)
+        return FR_NOT_READY;
+
+    return FR_OK;
+}
+
+
+
+
+/*--------------------------------------------------------------------------
+
+   Public Functions
+
+--------------------------------------------------------------------------*/
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Mount/Unmount a Locical Drive                                         */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_mount (
+    BYTE vol,        /* Logical drive number to be mounted/unmounted */
+    FATFS *fs        /* Pointer to new file system object (NULL for unmount)*/
+)
+{
+    FATFS *rfs;
+
+
+    if (vol >= _DRIVES)                /* Check if the drive number is valid */
+        return FR_INVALID_DRIVE;
+    rfs = FatFs[vol];                /* Get current fs object */
+
+    if (rfs) {
+#if _FS_REENTRANT                    /* Discard sync object of the current volume */
+        if (!ff_del_syncobj(rfs->sobj)) return FR_INT_ERR;
+#endif
+        rfs->fs_type = 0;            /* Clear old fs object */
+    }
+
+    if (fs) {
+        fs->fs_type = 0;            /* Clear new fs object */
+#if _FS_REENTRANT                    /* Create sync object for the new volume */
+        if (!ff_cre_syncobj(vol, &fs->sobj)) return FR_INT_ERR;
+#endif
+    }
+    FatFs[vol] = fs;                /* Register new fs object */
+
+    return FR_OK;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Open or Create a File                                                 */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_open (
+    FIL *fp,            /* Pointer to the blank file object */
+    const XCHAR *path,    /* Pointer to the file name */
+    BYTE mode            /* Access mode and file open mode flags */
+)
+{
+    FRESULT res;
+    eDIR dj;
+    NAMEBUF(sfn, lfn);
+    BYTE *dir;
+
+
+    fp->fs = NULL;        /* Clear file object */
+#if !_FS_READONLY
+    mode &= (FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW);
+    res = chk_mounted(&path, &dj.fs, (BYTE)(mode & (FA_WRITE | FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)));
+#else
+    mode &= FA_READ;
+    res = chk_mounted(&path, &dj.fs, 0);
+#endif
+    if (res != FR_OK) LEAVE_FF(dj.fs, res);
+    INITBUF(dj, sfn, lfn);
+    res = follow_path(&dj, path);    /* Follow the file path */
+
+#if !_FS_READONLY
+    /* Create or Open a file */
+    if (mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) {
+        DWORD ps, cl;
+
+        if (res != FR_OK) {            /* No file, create new */
+            if (res == FR_NO_FILE)    /* There is no file to open, create a new entry */
+                res = dir_register(&dj);
+            if (res != FR_OK) LEAVE_FF(dj.fs, res);
+            mode |= FA_CREATE_ALWAYS;
+            dir = dj.dir;            /* Created entry (SFN entry) */
+        }
+        else {                        /* Any object is already existing */
+            if (mode & FA_CREATE_NEW)            /* Cannot create new */
+                LEAVE_FF(dj.fs, FR_EXIST);
+            dir = dj.dir;
+            if (!dir || (dir[DIR_Attr] & (AM_RDO | AM_DIR)))    /* Cannot overwrite it (R/O or DIR) */
+                LEAVE_FF(dj.fs, FR_DENIED);
+            if (mode & FA_CREATE_ALWAYS) {        /* Resize it to zero on over write mode */
+                cl = ((DWORD)LD_WORD(dir+DIR_FstClusHI) << 16) | LD_WORD(dir+DIR_FstClusLO);    /* Get start cluster */
+                ST_WORD(dir+DIR_FstClusHI, 0);    /* cluster = 0 */
+                ST_WORD(dir+DIR_FstClusLO, 0);
+                ST_DWORD(dir+DIR_FileSize, 0);    /* size = 0 */
+                dj.fs->wflag = 1;
+                ps = dj.fs->winsect;            /* Remove the cluster chain */
+                if (cl) {
+                    res = remove_chain(dj.fs, cl);
+                    if (res) LEAVE_FF(dj.fs, res);
+                    dj.fs->last_clust = cl - 1;    /* Reuse the cluster hole */
+                }
+                res = move_window(dj.fs, ps);
+                if (res != FR_OK) LEAVE_FF(dj.fs, res);
+            }
+        }
+        if (mode & FA_CREATE_ALWAYS) {
+            dir[DIR_Attr] = 0;                    /* Reset attribute */
+            ps = get_fattime();
+            ST_DWORD(dir+DIR_CrtTime, ps);        /* Created time */
+            dj.fs->wflag = 1;
+            mode |= FA__WRITTEN;                /* Set file changed flag */
+        }
+    }
+    /* Open an existing file */
+    else {
+#endif /* !_FS_READONLY */
+        if (res != FR_OK) LEAVE_FF(dj.fs, res);    /* Follow failed */
+        dir = dj.dir;
+        if (!dir || (dir[DIR_Attr] & AM_DIR))    /* It is a directory */
+            LEAVE_FF(dj.fs, FR_NO_FILE);
+#if !_FS_READONLY
+        if ((mode & FA_WRITE) && (dir[DIR_Attr] & AM_RDO)) /* R/O violation */
+            LEAVE_FF(dj.fs, FR_DENIED);
+    }
+    fp->dir_sect = dj.fs->winsect;        /* Pointer to the directory entry */
+    fp->dir_ptr = dj.dir;
+#endif
+    fp->flag = mode;                    /* File access mode */
+    fp->org_clust =                        /* File start cluster */
+        ((DWORD)LD_WORD(dir+DIR_FstClusHI) << 16) | LD_WORD(dir+DIR_FstClusLO);
+    fp->fsize = LD_DWORD(dir+DIR_FileSize);    /* File size */
+    fp->fptr = 0; fp->csect = 255;        /* File pointer */
+    fp->dsect = 0;
+    fp->fs = dj.fs; fp->id = dj.fs->id;    /* Owner file system object of the file */
+
+    LEAVE_FF(dj.fs, FR_OK);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Read File                                                             */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_read (
+    FIL *fp,         /* Pointer to the file object */
+    void *buff,        /* Pointer to data buffer */
+    UINT btr,        /* Number of bytes to read */
+    UINT *br        /* Pointer to number of bytes read */
+)
+{
+    FRESULT res;
+    DWORD clst, sect, remain;
+    UINT rcnt, cc;
+    BYTE *rbuff = (BYTE *)buff;
+
+
+    *br = 0;    /* Initialize bytes read */
+
+    res = validate(fp->fs, fp->id);                    /* Check validity of the object */
+    if (res != FR_OK) LEAVE_FF(fp->fs, res);
+    if (fp->flag & FA__ERROR)                        /* Check abort flag */
+        LEAVE_FF(fp->fs, FR_INT_ERR);
+    if (!(fp->flag & FA_READ))                         /* Check access mode */
+        LEAVE_FF(fp->fs, FR_DENIED);
+    remain = fp->fsize - fp->fptr;
+    if (btr > remain) btr = (UINT)remain;            /* Truncate btr by remaining bytes */
+
+    for ( ;  btr;                                    /* Repeat until all data transferred */
+        rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) {
+        if ((fp->fptr % SS(fp->fs)) == 0) {            /* On the sector boundary? */
+            if (fp->csect >= fp->fs->csize) {        /* On the cluster boundary? */
+                clst = (fp->fptr == 0) ?            /* On the top of the file? */
+                    fp->org_clust : get_fat(fp->fs, fp->curr_clust);
+                if (clst <= 1) ABORT(fp->fs, FR_INT_ERR);
+                if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
+                fp->curr_clust = clst;                /* Update current cluster */
+                fp->csect = 0;                        /* Reset sector offset in the cluster */
+            }
+            sect = clust2sect(fp->fs, fp->curr_clust);    /* Get current sector */
+            if (!sect) ABORT(fp->fs, FR_INT_ERR);
+            sect += fp->csect;
+            cc = btr / SS(fp->fs);                    /* When remaining bytes >= sector size, */
+            if (cc) {                                /* Read maximum contiguous sectors directly */
+                if (fp->csect + cc > fp->fs->csize)    /* Clip at cluster boundary */
+                    cc = fp->fs->csize - fp->csect;
+                if (disk_read(fp->fs->drive, rbuff, sect, (BYTE)cc) != RES_OK)
+                    ABORT(fp->fs, FR_DISK_ERR);
+#if !_FS_READONLY && _FS_MINIMIZE <= 2
+#if _FS_TINY
+                if (fp->fs->wflag && fp->fs->winsect - sect < cc)        /* Replace one of the read sectors with cached data if it contains a dirty sector */
+                    mem_cpy(rbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), fp->fs->win, SS(fp->fs));
+#else
+                if ((fp->flag & FA__DIRTY) && fp->dsect - sect < cc)    /* Replace one of the read sectors with cached data if it contains a dirty sector */
+                    mem_cpy(rbuff + ((fp->dsect - sect) * SS(fp->fs)), fp->buf, SS(fp->fs));
+#endif
+#endif
+                fp->csect += (BYTE)cc;                /* Next sector address in the cluster */
+                rcnt = SS(fp->fs) * cc;                /* Number of bytes transferred */
+                continue;
+            }
+#if !_FS_TINY
+#if !_FS_READONLY
+            if (fp->flag & FA__DIRTY) {            /* Write sector I/O buffer if needed */
+                if (disk_write(fp->fs->drive, fp->buf, fp->dsect, 1) != RES_OK)
+                    ABORT(fp->fs, FR_DISK_ERR);
+                fp->flag &= ~FA__DIRTY;
+            }
+#endif
+            if (fp->dsect != sect) {            /* Fill sector buffer with file data */
+                if (disk_read(fp->fs->drive, fp->buf, sect, 1) != RES_OK)
+                    ABORT(fp->fs, FR_DISK_ERR);
+            }
+#endif
+            fp->dsect = sect;
+            fp->csect++;                            /* Next sector address in the cluster */
+        }
+        rcnt = SS(fp->fs) - (fp->fptr % SS(fp->fs));    /* Get partial sector data from sector buffer */
+        if (rcnt > btr) rcnt = btr;
+#if _FS_TINY
+        if (move_window(fp->fs, fp->dsect))            /* Move sector window */
+            ABORT(fp->fs, FR_DISK_ERR);
+        mem_cpy(rbuff, &fp->fs->win[fp->fptr % SS(fp->fs)], rcnt);    /* Pick partial sector */
+#else
+        mem_cpy(rbuff, &fp->buf[fp->fptr % SS(fp->fs)], rcnt);    /* Pick partial sector */
+#endif
+    }
+
+    LEAVE_FF(fp->fs, FR_OK);
+}
+
+
+
+
+#if !_FS_READONLY
+/*-----------------------------------------------------------------------*/
+/* Write File                                                            */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_write (
+    FIL *fp,            /* Pointer to the file object */
+    const void *buff,    /* Pointer to the data to be written */
+    UINT btw,            /* Number of bytes to write */
+    UINT *bw            /* Pointer to number of bytes written */
+)
+{
+    FRESULT res;
+    DWORD clst, sect;
+    UINT wcnt, cc;
+    const BYTE *wbuff = (const BYTE *)buff;
+
+
+    *bw = 0;    /* Initialize bytes written */
+
+    res = validate(fp->fs, fp->id);                    /* Check validity of the object */
+    if (res != FR_OK) LEAVE_FF(fp->fs, res);
+    if (fp->flag & FA__ERROR)                        /* Check abort flag */
+        LEAVE_FF(fp->fs, FR_INT_ERR);
+    if (!(fp->flag & FA_WRITE))                        /* Check access mode */
+        LEAVE_FF(fp->fs, FR_DENIED);
+    if (fp->fsize + btw < fp->fsize) btw = 0;        /* File size cannot reach 4GB */
+
+    for ( ;  btw;                                    /* Repeat until all data transferred */
+        wbuff += wcnt, fp->fptr += wcnt, *bw += wcnt, btw -= wcnt) {
+        if ((fp->fptr % SS(fp->fs)) == 0) {            /* On the sector boundary? */
+            if (fp->csect >= fp->fs->csize) {        /* On the cluster boundary? */
+                if (fp->fptr == 0) {                /* On the top of the file? */
+                    clst = fp->org_clust;            /* Follow from the origin */
+                    if (clst == 0)                    /* When there is no cluster chain, */
+                        fp->org_clust = clst = create_chain(fp->fs, 0);    /* Create a new cluster chain */
+                } else {                            /* Middle or end of the file */
+                    clst = create_chain(fp->fs, fp->curr_clust);            /* Follow or streach cluster chain */
+                }
+                if (clst == 0) break;                /* Could not allocate a new cluster (disk full) */
+                if (clst == 1) ABORT(fp->fs, FR_INT_ERR);
+                if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
+                fp->curr_clust = clst;                /* Update current cluster */
+                fp->csect = 0;                        /* Reset sector address in the cluster */
+            }
+#if _FS_TINY
+            if (fp->fs->winsect == fp->dsect && move_window(fp->fs, 0))    /* Write back data buffer prior to following direct transfer */
+                ABORT(fp->fs, FR_DISK_ERR);
+#else
+            if (fp->flag & FA__DIRTY) {        /* Write back data buffer prior to following direct transfer */
+                if (disk_write(fp->fs->drive, fp->buf, fp->dsect, 1) != RES_OK)
+                    ABORT(fp->fs, FR_DISK_ERR);
+                fp->flag &= ~FA__DIRTY;
+            }
+#endif
+            sect = clust2sect(fp->fs, fp->curr_clust);    /* Get current sector */
+            if (!sect) ABORT(fp->fs, FR_INT_ERR);
+            sect += fp->csect;
+            cc = btw / SS(fp->fs);                    /* When remaining bytes >= sector size, */
+            if (cc) {                                /* Write maximum contiguous sectors directly */
+                if (fp->csect + cc > fp->fs->csize)    /* Clip at cluster boundary */
+                    cc = fp->fs->csize - fp->csect;
+                if (disk_write(fp->fs->drive, wbuff, sect, (BYTE)cc) != RES_OK)
+                    ABORT(fp->fs, FR_DISK_ERR);
+#if _FS_TINY
+                if (fp->fs->winsect - sect < cc) {    /* Refill sector cache if it gets dirty by the direct write */
+                    mem_cpy(fp->fs->win, wbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), SS(fp->fs));
+                    fp->fs->wflag = 0;
+                }
+#else
+                if (fp->dsect - sect < cc) {        /* Refill sector cache if it gets dirty by the direct write */
+                    mem_cpy(fp->buf, wbuff + ((fp->dsect - sect) * SS(fp->fs)), SS(fp->fs));
+                    fp->flag &= ~FA__DIRTY;
+                }
+#endif
+                fp->csect += (BYTE)cc;                /* Next sector address in the cluster */
+                wcnt = SS(fp->fs) * cc;                /* Number of bytes transferred */
+                continue;
+            }
+#if _FS_TINY
+            if (fp->fptr >= fp->fsize) {            /* Avoid silly buffer filling at growing edge */
+                if (move_window(fp->fs, 0)) ABORT(fp->fs, FR_DISK_ERR);
+                fp->fs->winsect = sect;
+            }
+#else
+            if (fp->dsect != sect) {                /* Fill sector buffer with file data */
+                if (fp->fptr < fp->fsize &&
+                    disk_read(fp->fs->drive, fp->buf, sect, 1) != RES_OK)
+                        ABORT(fp->fs, FR_DISK_ERR);
+            }
+#endif
+            fp->dsect = sect;
+            fp->csect++;                            /* Next sector address in the cluster */
+        }
+        wcnt = SS(fp->fs) - (fp->fptr % SS(fp->fs));    /* Put partial sector into file I/O buffer */
+        if (wcnt > btw) wcnt = btw;
+#if _FS_TINY
+        if (move_window(fp->fs, fp->dsect))            /* Move sector window */
+            ABORT(fp->fs, FR_DISK_ERR);
+        mem_cpy(&fp->fs->win[fp->fptr % SS(fp->fs)], wbuff, wcnt);    /* Fit partial sector */
+        fp->fs->wflag = 1;
+#else
+        mem_cpy(&fp->buf[fp->fptr % SS(fp->fs)], wbuff, wcnt);    /* Fit partial sector */
+        fp->flag |= FA__DIRTY;
+#endif
+    }
+
+    if (fp->fptr > fp->fsize) fp->fsize = fp->fptr;    /* Update file size if needed */
+    fp->flag |= FA__WRITTEN;                        /* Set file changed flag */
+
+    LEAVE_FF(fp->fs, FR_OK);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Synchronize the File Object                                           */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_sync (
+    FIL *fp        /* Pointer to the file object */
+)
+{
+    FRESULT res;
+    DWORD tim;
+    BYTE *dir;
+
+
+    res = validate(fp->fs, fp->id);        /* Check validity of the object */
+    if (res == FR_OK) {
+        if (fp->flag & FA__WRITTEN) {    /* Has the file been written? */
+#if !_FS_TINY    /* Write-back dirty buffer */
+            if (fp->flag & FA__DIRTY) {
+                if (disk_write(fp->fs->drive, fp->buf, fp->dsect, 1) != RES_OK)
+                    LEAVE_FF(fp->fs, FR_DISK_ERR);
+                fp->flag &= ~FA__DIRTY;
+            }
+#endif
+            /* Update the directory entry */
+            res = move_window(fp->fs, fp->dir_sect);
+            if (res == FR_OK) {
+                dir = fp->dir_ptr;
+                dir[DIR_Attr] |= AM_ARC;                    /* Set archive bit */
+                ST_DWORD(dir+DIR_FileSize, fp->fsize);        /* Update file size */
+                ST_WORD(dir+DIR_FstClusLO, fp->org_clust);    /* Update start cluster */
+                ST_WORD(dir+DIR_FstClusHI, fp->org_clust >> 16);
+                tim = get_fattime();            /* Updated time */
+                ST_DWORD(dir+DIR_WrtTime, tim);
+                fp->flag &= ~FA__WRITTEN;
+                fp->fs->wflag = 1;
+                res = sync(fp->fs);
+            }
+        }
+    }
+
+    LEAVE_FF(fp->fs, res);
+}
+
+#endif /* !_FS_READONLY */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Close File                                                            */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_close (
+    FIL *fp        /* Pointer to the file object to be closed */
+)
+{
+    FRESULT res;
+
+
+#if _FS_READONLY
+    res = validate(fp->fs, fp->id);
+    if (res == FR_OK) fp->fs = NULL;
+    LEAVE_FF(fp->fs, res);
+#else
+    res = f_sync(fp);
+    if (res == FR_OK) fp->fs = NULL;
+    return res;
+#endif
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Change Current Drive/Directory                                        */
+/*-----------------------------------------------------------------------*/
+
+#if _FS_RPATH
+
+FRESULT f_chdrive (
+    BYTE drv        /* Drive number */
+)
+{
+    if (drv >= _DRIVES) return FR_INVALID_DRIVE;
+
+    Drive = drv;
+
+    return FR_OK;
+}
+
+
+
+
+FRESULT f_chdir (
+    const XCHAR *path    /* Pointer to the directory path */
+)
+{
+    FRESULT res;
+    DIR dj;
+    NAMEBUF(sfn, lfn);
+    BYTE *dir;
+
+
+    res = chk_mounted(&path, &dj.fs, 0);
+    if (res == FR_OK) {
+        INITBUF(dj, sfn, lfn);
+        res = follow_path(&dj, path);        /* Follow the file path */
+        if (res == FR_OK) {                    /* Follow completed */
+            dir = dj.dir;                    /* Pointer to the entry */
+            if (!dir) {
+                dj.fs->cdir = 0;            /* No entry (root dir) */
+            } else {
+                if (dir[DIR_Attr] & AM_DIR)    /* Reached to the dir */
+                    dj.fs->cdir = ((DWORD)LD_WORD(dir+DIR_FstClusHI) << 16) | LD_WORD(dir+DIR_FstClusLO);
+                else
+                    res = FR_NO_PATH;        /* Could not reach the dir (it is a file) */
+            }
+        }
+        if (res == FR_NO_FILE) res = FR_NO_PATH;
+    }
+
+    LEAVE_FF(dj.fs, res);
+}
+
+#endif
+
+
+
+#if _FS_MINIMIZE <= 2
+/*-----------------------------------------------------------------------*/
+/* Seek File R/W Pointer                                                 */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_lseek (
+    FIL *fp,        /* Pointer to the file object */
+    DWORD ofs        /* File pointer from top of file */
+)
+{
+    FRESULT res;
+    DWORD clst, bcs, nsect, ifptr;
+
+
+    res = validate(fp->fs, fp->id);        /* Check validity of the object */
+    if (res != FR_OK) LEAVE_FF(fp->fs, res);
+    if (fp->flag & FA__ERROR)            /* Check abort flag */
+        LEAVE_FF(fp->fs, FR_INT_ERR);
+    if (ofs > fp->fsize                    /* In read-only mode, clip offset with the file size */
+#if !_FS_READONLY
+         && !(fp->flag & FA_WRITE)
+#endif
+        ) ofs = fp->fsize;
+
+    ifptr = fp->fptr;
+    fp->fptr = nsect = 0; fp->csect = 255;
+    if (ofs > 0) {
+        bcs = (DWORD)fp->fs->csize * SS(fp->fs);    /* Cluster size (byte) */
+        if (ifptr > 0 &&
+            (ofs - 1) / bcs >= (ifptr - 1) / bcs) {    /* When seek to same or following cluster, */
+            fp->fptr = (ifptr - 1) & ~(bcs - 1);    /* start from the current cluster */
+            ofs -= fp->fptr;
+            clst = fp->curr_clust;
+        } else {                                    /* When seek to back cluster, */
+            clst = fp->org_clust;                    /* start from the first cluster */
+#if !_FS_READONLY
+            if (clst == 0) {                        /* If no cluster chain, create a new chain */
+                clst = create_chain(fp->fs, 0);
+                if (clst == 1) ABORT(fp->fs, FR_INT_ERR);
+                if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
+                fp->org_clust = clst;
+            }
+#endif
+            fp->curr_clust = clst;
+        }
+        if (clst != 0) {
+            while (ofs > bcs) {                        /* Cluster following loop */
+#if !_FS_READONLY
+                if (fp->flag & FA_WRITE) {            /* Check if in write mode or not */
+                    clst = create_chain(fp->fs, clst);    /* Force streached if in write mode */
+                    if (clst == 0) {                /* When disk gets full, clip file size */
+                        ofs = bcs; break;
+                    }
+                } else
+#endif
+                    clst = get_fat(fp->fs, clst);    /* Follow cluster chain if not in write mode */
+                if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
+                if (clst <= 1 || clst >= fp->fs->max_clust) ABORT(fp->fs, FR_INT_ERR);
+                fp->curr_clust = clst;
+                fp->fptr += bcs;
+                ofs -= bcs;
+            }
+            fp->fptr += ofs;
+            fp->csect = (BYTE)(ofs / SS(fp->fs));    /* Sector offset in the cluster */
+            if (ofs % SS(fp->fs)) {
+                nsect = clust2sect(fp->fs, clst);    /* Current sector */
+                if (!nsect) ABORT(fp->fs, FR_INT_ERR);
+                nsect += fp->csect;
+                fp->csect++;
+            }
+        }
+    }
+    if (fp->fptr % SS(fp->fs) && nsect != fp->dsect) {
+#if !_FS_TINY
+#if !_FS_READONLY
+        if (fp->flag & FA__DIRTY) {            /* Write-back dirty buffer if needed */
+            if (disk_write(fp->fs->drive, fp->buf, fp->dsect, 1) != RES_OK)
+                ABORT(fp->fs, FR_DISK_ERR);
+            fp->flag &= ~FA__DIRTY;
+        }
+#endif
+        if (disk_read(fp->fs->drive, fp->buf, nsect, 1) != RES_OK)
+            ABORT(fp->fs, FR_DISK_ERR);
+#endif
+        fp->dsect = nsect;
+    }
+#if !_FS_READONLY
+    if (fp->fptr > fp->fsize) {            /* Set changed flag if the file size is extended */
+        fp->fsize = fp->fptr;
+        fp->flag |= FA__WRITTEN;
+    }
+#endif
+
+    LEAVE_FF(fp->fs, res);
+}
+
+
+
+
+#if _FS_MINIMIZE <= 1
+/*-----------------------------------------------------------------------*/
+/* Create a Directroy Object                                             */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_opendir (
+    eDIR *dj,            /* Pointer to directory object to create */
+    const XCHAR *path    /* Pointer to the directory path */
+)
+{
+    FRESULT res;
+    NAMEBUF(sfn, lfn);
+    BYTE *dir;
+
+
+    res = chk_mounted(&path, &dj->fs, 0);
+    if (res == FR_OK) {
+        INITBUF((*dj), sfn, lfn);
+        res = follow_path(dj, path);            /* Follow the path to the directory */
+        if (res == FR_OK) {                        /* Follow completed */
+            dir = dj->dir;
+            if (dir) {                            /* It is not the root dir */
+                if (dir[DIR_Attr] & AM_DIR) {    /* The object is a directory */
+                    dj->sclust = ((DWORD)LD_WORD(dir+DIR_FstClusHI) << 16) | LD_WORD(dir+DIR_FstClusLO);
+                } else {                        /* The object is not a directory */
+                    res = FR_NO_PATH;
+                }
+            }
+            if (res == FR_OK) {
+                dj->id = dj->fs->id;
+                res = dir_seek(dj, 0);            /* Rewind dir */
+            }
+        }
+        if (res == FR_NO_FILE) res = FR_NO_PATH;
+    }
+
+    LEAVE_FF(dj->fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Read Directory Entry in Sequense                                      */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_readdir (
+    eDIR *dj,            /* Pointer to the open directory object */
+    FILINFO *fno        /* Pointer to file information to return */
+)
+{
+    FRESULT res;
+    NAMEBUF(sfn, lfn);
+
+
+    res = validate(dj->fs, dj->id);            /* Check validity of the object */
+    if (res == FR_OK) {
+        INITBUF((*dj), sfn, lfn);
+        if (!fno) {
+            res = dir_seek(dj, 0);
+        } else {
+            res = dir_read(dj);
+            if (res == FR_NO_FILE) {
+                dj->sect = 0;
+                res = FR_OK;
+            }
+            if (res == FR_OK) {                /* A valid entry is found */
+                get_fileinfo(dj, fno);        /* Get the object information */
+                res = dir_next(dj, FALSE);    /* Increment index for next */
+                if (res == FR_NO_FILE) {
+                    dj->sect = 0;
+                    res = FR_OK;
+                }
+            }
+        }
+    }
+
+    LEAVE_FF(dj->fs, res);
+}
+
+
+
+#if _FS_MINIMIZE == 0
+/*-----------------------------------------------------------------------*/
+/* Get File Status                                                       */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_stat (
+    const XCHAR *path,    /* Pointer to the file path */
+    FILINFO *fno        /* Pointer to file information to return */
+)
+{
+    FRESULT res;
+    eDIR dj;
+    NAMEBUF(sfn, lfn);
+
+
+    res = chk_mounted(&path, &dj.fs, 0);
+    if (res == FR_OK) {
+        INITBUF(dj, sfn, lfn);
+        res = follow_path(&dj, path);    /* Follow the file path */
+        if (res == FR_OK) {                /* Follwo completed */
+            if (dj.dir)    /* Found an object */
+                get_fileinfo(&dj, fno);
+            else        /* It is root dir */
+                res = FR_INVALID_NAME;
+        }
+    }
+
+    LEAVE_FF(dj.fs, res);
+}
+
+
+
+#if !_FS_READONLY
+/*-----------------------------------------------------------------------*/
+/* Get Number of Free Clusters                                           */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_getfree (
+    const XCHAR *path,    /* Pointer to the logical drive number (root dir) */
+    DWORD *nclst,        /* Pointer to the variable to return number of free clusters */
+    FATFS **fatfs        /* Pointer to pointer to corresponding file system object to return */
+)
+{
+    FRESULT res;
+    DWORD n, clst, sect, stat;
+    UINT i;
+    BYTE fat, *p;
+
+
+    /* Get drive number */
+    res = chk_mounted(&path, fatfs, 0);
+    if (res != FR_OK) LEAVE_FF(*fatfs, res);
+
+    /* If number of free cluster is valid, return it without cluster scan. */
+    if ((*fatfs)->free_clust <= (*fatfs)->max_clust - 2) {
+        *nclst = (*fatfs)->free_clust;
+        LEAVE_FF(*fatfs, FR_OK);
+    }
+
+    /* Get number of free clusters */
+    fat = (*fatfs)->fs_type;
+    n = 0;
+    if (fat == FS_FAT12) {
+        clst = 2;
+        do {
+            stat = get_fat(*fatfs, clst);
+            if (stat == 0xFFFFFFFF) LEAVE_FF(*fatfs, FR_DISK_ERR);
+            if (stat == 1) LEAVE_FF(*fatfs, FR_INT_ERR);
+            if (stat == 0) n++;
+        } while (++clst < (*fatfs)->max_clust);
+    } else {
+        clst = (*fatfs)->max_clust;
+        sect = (*fatfs)->fatbase;
+        i = 0; p = 0;
+        do {
+            if (!i) {
+                res = move_window(*fatfs, sect++);
+                if (res != FR_OK)
+                    LEAVE_FF(*fatfs, res);
+                p = (*fatfs)->win;
+                i = SS(*fatfs);
+            }
+            if (fat == FS_FAT16) {
+                if (LD_WORD(p) == 0) n++;
+                p += 2; i -= 2;
+            } else {
+                if ((LD_DWORD(p) & 0x0FFFFFFF) == 0) n++;
+                p += 4; i -= 4;
+            }
+        } while (--clst);
+    }
+    (*fatfs)->free_clust = n;
+    if (fat == FS_FAT32) (*fatfs)->fsi_flag = 1;
+    *nclst = n;
+
+    LEAVE_FF(*fatfs, FR_OK);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Truncate File                                                         */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_truncate (
+    FIL *fp        /* Pointer to the file object */
+)
+{
+    FRESULT res;
+    DWORD ncl;
+
+
+    res = validate(fp->fs, fp->id);        /* Check validity of the object */
+    if (res != FR_OK) LEAVE_FF(fp->fs, res);
+    if (fp->flag & FA__ERROR)            /* Check abort flag */
+        LEAVE_FF(fp->fs, FR_INT_ERR);
+    if (!(fp->flag & FA_WRITE))            /* Check access mode */
+        LEAVE_FF(fp->fs, FR_DENIED);
+
+    if (fp->fsize > fp->fptr) {
+        fp->fsize = fp->fptr;    /* Set file size to current R/W point */
+        fp->flag |= FA__WRITTEN;
+        if (fp->fptr == 0) {    /* When set file size to zero, remove entire cluster chain */
+            res = remove_chain(fp->fs, fp->org_clust);
+            fp->org_clust = 0;
+        } else {                /* When truncate a part of the file, remove remaining clusters */
+            ncl = get_fat(fp->fs, fp->curr_clust);
+            res = FR_OK;
+            if (ncl == 0xFFFFFFFF) res = FR_DISK_ERR;
+            if (ncl == 1) res = FR_INT_ERR;
+            if (res == FR_OK && ncl < fp->fs->max_clust) {
+                res = put_fat(fp->fs, fp->curr_clust, 0x0FFFFFFF);
+                if (res == FR_OK) res = remove_chain(fp->fs, ncl);
+            }
+        }
+    }
+    if (res != FR_OK) fp->flag |= FA__ERROR;
+
+    LEAVE_FF(fp->fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Delete a File or Directory                                            */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_unlink (
+    const XCHAR *path        /* Pointer to the file or directory path */
+)
+{
+    FRESULT res;
+    eDIR dj, sdj;
+    NAMEBUF(sfn, lfn);
+    BYTE *dir;
+    DWORD dclst;
+
+
+    res = chk_mounted(&path, &dj.fs, 1);
+    if (res != FR_OK) LEAVE_FF(dj.fs, res);
+
+    INITBUF(dj, sfn, lfn);
+    res = follow_path(&dj, path);            /* Follow the file path */
+    if (_FS_RPATH && res == FR_OK && (dj.fn[NS] & NS_DOT))
+        res = FR_INVALID_NAME;
+    if (res != FR_OK) LEAVE_FF(dj.fs, res); /* Follow failed */
+
+    dir = dj.dir;
+    if (!dir)                                /* Is it the root directory? */
+        LEAVE_FF(dj.fs, FR_INVALID_NAME);
+    if (dir[DIR_Attr] & AM_RDO)                /* Is it a R/O object? */
+        LEAVE_FF(dj.fs, FR_DENIED);
+    dclst = ((DWORD)LD_WORD(dir+DIR_FstClusHI) << 16) | LD_WORD(dir+DIR_FstClusLO);
+
+    if (dir[DIR_Attr] & AM_DIR) {            /* It is a sub-directory */
+        if (dclst < 2) LEAVE_FF(dj.fs, FR_INT_ERR);
+        mem_cpy(&sdj, &dj, sizeof(eDIR));    /* Check if the sub-dir is empty or not */
+        sdj.sclust = dclst;
+        res = dir_seek(&sdj, 2);
+        if (res != FR_OK) LEAVE_FF(dj.fs, res);
+        res = dir_read(&sdj);
+        if (res == FR_OK) res = FR_DENIED;    /* Not empty sub-dir */
+        if (res != FR_NO_FILE) LEAVE_FF(dj.fs, res);
+    }
+
+    res = dir_remove(&dj);                    /* Remove directory entry */
+    if (res == FR_OK) {
+        if (dclst)
+            res = remove_chain(dj.fs, dclst);    /* Remove the cluster chain */
+        if (res == FR_OK) res = sync(dj.fs);
+    }
+
+    LEAVE_FF(dj.fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Create a Directory                                                    */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_mkdir (
+    const XCHAR *path        /* Pointer to the directory path */
+)
+{
+    FRESULT res;
+    eDIR dj;
+    NAMEBUF(sfn, lfn);
+    BYTE *dir, n;
+    DWORD dsect, dclst, pclst, tim;
+
+
+    res = chk_mounted(&path, &dj.fs, 1);
+    if (res != FR_OK) LEAVE_FF(dj.fs, res);
+
+    INITBUF(dj, sfn, lfn);
+    res = follow_path(&dj, path);            /* Follow the file path */
+    if (res == FR_OK) res = FR_EXIST;        /* Any file or directory is already existing */
+    if (_FS_RPATH && res == FR_NO_FILE && (dj.fn[NS] & NS_DOT))
+        res = FR_INVALID_NAME;
+    if (res != FR_NO_FILE)                    /* Any error occured */
+        LEAVE_FF(dj.fs, res);
+
+    dclst = create_chain(dj.fs, 0);            /* Allocate a new cluster for new directory table */
+    res = FR_OK;
+    if (dclst == 0) res = FR_DENIED;
+    if (dclst == 1) res = FR_INT_ERR;
+    if (dclst == 0xFFFFFFFF) res = FR_DISK_ERR;
+    if (res == FR_OK)
+        res = move_window(dj.fs, 0);
+    if (res != FR_OK) LEAVE_FF(dj.fs, res);
+    dsect = clust2sect(dj.fs, dclst);
+
+    dir = dj.fs->win;                        /* Initialize the new directory table */
+    mem_set(dir, 0, SS(dj.fs));
+    mem_set(dir+DIR_Name, ' ', 8+3);        /* Create "." entry */
+    dir[DIR_Name] = '.';
+    dir[DIR_Attr] = AM_DIR;
+    tim = get_fattime();
+    ST_DWORD(dir+DIR_WrtTime, tim);
+    ST_WORD(dir+DIR_FstClusLO, dclst);
+    ST_WORD(dir+DIR_FstClusHI, dclst >> 16);
+    mem_cpy(dir+32, dir, 32);             /* Create ".." entry */
+    dir[33] = '.';
+    pclst = dj.sclust;
+    if (dj.fs->fs_type == FS_FAT32 && pclst == dj.fs->dirbase)
+        pclst = 0;
+    ST_WORD(dir+32+DIR_FstClusLO, pclst);
+    ST_WORD(dir+32+DIR_FstClusHI, pclst >> 16);
+    for (n = 0; n < dj.fs->csize; n++) {    /* Write dot entries and clear left sectors */
+        dj.fs->winsect = dsect++;
+        dj.fs->wflag = 1;
+        res = move_window(dj.fs, 0);
+        if (res) LEAVE_FF(dj.fs, res);
+        mem_set(dir, 0, SS(dj.fs));
+    }
+
+    res = dir_register(&dj);
+    if (res != FR_OK) {
+        remove_chain(dj.fs, dclst);
+    } else {
+        dir = dj.dir;
+        dir[DIR_Attr] = AM_DIR;                    /* Attribute */
+        ST_DWORD(dir+DIR_WrtTime, tim);            /* Crated time */
+        ST_WORD(dir+DIR_FstClusLO, dclst);        /* Table start cluster */
+        ST_WORD(dir+DIR_FstClusHI, dclst >> 16);
+        dj.fs->wflag = 1;
+        res = sync(dj.fs);
+    }
+
+    LEAVE_FF(dj.fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Change File Attribute                                                 */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_chmod (
+    const XCHAR *path,    /* Pointer to the file path */
+    BYTE value,            /* Attribute bits */
+    BYTE mask            /* Attribute mask to change */
+)
+{
+    FRESULT res;
+    eDIR dj;
+    NAMEBUF(sfn, lfn);
+    BYTE *dir;
+
+
+    res = chk_mounted(&path, &dj.fs, 1);
+    if (res == FR_OK) {
+        INITBUF(dj, sfn, lfn);
+        res = follow_path(&dj, path);        /* Follow the file path */
+        if (_FS_RPATH && res == FR_OK && (dj.fn[NS] & NS_DOT))
+            res = FR_INVALID_NAME;
+        if (res == FR_OK) {
+            dir = dj.dir;
+            if (!dir) {                        /* Is it a root directory? */
+                res = FR_INVALID_NAME;
+            } else {                        /* File or sub directory */
+                mask &= AM_RDO|AM_HID|AM_SYS|AM_ARC;    /* Valid attribute mask */
+                dir[DIR_Attr] = (value & mask) | (dir[DIR_Attr] & (BYTE)~mask);    /* Apply attribute change */
+                dj.fs->wflag = 1;
+                res = sync(dj.fs);
+            }
+        }
+    }
+
+    LEAVE_FF(dj.fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Change Timestamp                                                      */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_utime (
+    const XCHAR *path,    /* Pointer to the file/directory name */
+    const FILINFO *fno    /* Pointer to the timestamp to be set */
+)
+{
+    FRESULT res;
+    eDIR dj;
+    NAMEBUF(sfn, lfn);
+    BYTE *dir;
+
+
+    res = chk_mounted(&path, &dj.fs, 1);
+    if (res == FR_OK) {
+        INITBUF(dj, sfn, lfn);
+        res = follow_path(&dj, path);    /* Follow the file path */
+        if (_FS_RPATH && res == FR_OK && (dj.fn[NS] & NS_DOT))
+            res = FR_INVALID_NAME;
+        if (res == FR_OK) {
+            dir = dj.dir;
+            if (!dir) {                /* Root directory */
+                res = FR_INVALID_NAME;
+            } else {                /* File or sub-directory */
+                ST_WORD(dir+DIR_WrtTime, fno->ftime);
+                ST_WORD(dir+DIR_WrtDate, fno->fdate);
+                dj.fs->wflag = 1;
+                res = sync(dj.fs);
+            }
+        }
+    }
+
+    LEAVE_FF(dj.fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Rename File/Directory                                                 */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_rename (
+    const XCHAR *path_old,    /* Pointer to the old name */
+    const XCHAR *path_new    /* Pointer to the new name */
+)
+{
+    FRESULT res;
+    eDIR dj_old, dj_new;
+    NAMEBUF(sfn, lfn);
+    BYTE buf[21], *dir;
+    DWORD dw;
+
+
+    INITBUF(dj_old, sfn, lfn);
+    res = chk_mounted(&path_old, &dj_old.fs, 1);
+    if (res == FR_OK) {
+        dj_new.fs = dj_old.fs;
+        res = follow_path(&dj_old, path_old);    /* Check old object */
+        if (_FS_RPATH && res == FR_OK && (dj_old.fn[NS] & NS_DOT))
+            res = FR_INVALID_NAME;
+    }
+    if (res != FR_OK) LEAVE_FF(dj_old.fs, res);    /* The old object is not found */
+
+    if (!dj_old.dir) LEAVE_FF(dj_old.fs, FR_NO_FILE);    /* Is root dir? */
+    mem_cpy(buf, dj_old.dir+DIR_Attr, 21);        /* Save the object information */
+
+    mem_cpy(&dj_new, &dj_old, sizeof(eDIR));
+    res = follow_path(&dj_new, path_new);        /* Check new object */
+    if (res == FR_OK) res = FR_EXIST;            /* The new object name is already existing */
+    if (res == FR_NO_FILE) {                     /* Is it a valid path and no name collision? */
+        res = dir_register(&dj_new);            /* Register the new object */
+        if (res == FR_OK) {
+            dir = dj_new.dir;                    /* Copy object information into new entry */
+            mem_cpy(dir+13, buf+2, 19);
+            dir[DIR_Attr] = buf[0] | AM_ARC;
+            dj_old.fs->wflag = 1;
+            if (dir[DIR_Attr] & AM_DIR) {        /* Update .. entry in the directory if needed */
+                dw = clust2sect(dj_new.fs, (DWORD)LD_WORD(dir+DIR_FstClusHI) | LD_WORD(dir+DIR_FstClusLO));
+                if (!dw) {
+                    res = FR_INT_ERR;
+                } else {
+                    res = move_window(dj_new.fs, dw);
+                    dir = dj_new.fs->win+32;
+                    if (res == FR_OK && dir[1] == '.') {
+                        dw = (dj_new.fs->fs_type == FS_FAT32 && dj_new.sclust == dj_new.fs->dirbase) ? 0 : dj_new.sclust;
+                        ST_WORD(dir+DIR_FstClusLO, dw);
+                        ST_WORD(dir+DIR_FstClusHI, dw >> 16);
+                        dj_new.fs->wflag = 1;
+                    }
+                }
+            }
+            if (res == FR_OK) {
+                res = dir_remove(&dj_old);            /* Remove old entry */
+                if (res == FR_OK)
+                    res = sync(dj_old.fs);
+            }
+        }
+    }
+
+    LEAVE_FF(dj_old.fs, res);
+}
+
+#endif /* !_FS_READONLY */
+#endif /* _FS_MINIMIZE == 0 */
+#endif /* _FS_MINIMIZE <= 1 */
+#endif /* _FS_MINIMIZE <= 2 */
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Forward data to the stream directly (Available on only _FS_TINY cfg)  */
+/*-----------------------------------------------------------------------*/
+#if _USE_FORWARD && _FS_TINY
+
+FRESULT f_forward (
+    FIL *fp,                         /* Pointer to the file object */
+    UINT (*func)(const BYTE*,UINT),    /* Pointer to the streaming function */
+    UINT btr,                        /* Number of bytes to forward */
+    UINT *bf                        /* Pointer to number of bytes forwarded */
+)
+{
+    FRESULT res;
+    DWORD remain, clst, sect;
+    UINT rcnt;
+
+
+    *bf = 0;
+
+    res = validate(fp->fs, fp->id);                    /* Check validity of the object */
+    if (res != FR_OK) LEAVE_FF(fp->fs, res);
+    if (fp->flag & FA__ERROR)                        /* Check error flag */
+        LEAVE_FF(fp->fs, FR_INT_ERR);
+    if (!(fp->flag & FA_READ))                        /* Check access mode */
+        LEAVE_FF(fp->fs, FR_DENIED);
+
+    remain = fp->fsize - fp->fptr;
+    if (btr > remain) btr = (UINT)remain;            /* Truncate btr by remaining bytes */
+
+    for ( ;  btr && (*func)(NULL, 0);                /* Repeat until all data transferred or stream becomes busy */
+        fp->fptr += rcnt, *bf += rcnt, btr -= rcnt) {
+        if ((fp->fptr % SS(fp->fs)) == 0) {            /* On the sector boundary? */
+            if (fp->csect >= fp->fs->csize) {        /* On the cluster boundary? */
+                clst = (fp->fptr == 0) ?            /* On the top of the file? */
+                    fp->org_clust : get_fat(fp->fs, fp->curr_clust);
+                if (clst <= 1) ABORT(fp->fs, FR_INT_ERR);
+                if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
+                fp->curr_clust = clst;                /* Update current cluster */
+                fp->csect = 0;                        /* Reset sector address in the cluster */
+            }
+            fp->csect++;                            /* Next sector address in the cluster */
+        }
+        sect = clust2sect(fp->fs, fp->curr_clust);    /* Get current data sector */
+        if (!sect) ABORT(fp->fs, FR_INT_ERR);
+        sect += fp->csect - 1;
+        if (move_window(fp->fs, sect))                /* Move sector window */
+            ABORT(fp->fs, FR_DISK_ERR);
+        fp->dsect = sect;
+        rcnt = SS(fp->fs) - (WORD)(fp->fptr % SS(fp->fs));    /* Forward data from sector window */
+        if (rcnt > btr) rcnt = btr;
+        rcnt = (*func)(&fp->fs->win[(WORD)fp->fptr % SS(fp->fs)], rcnt);
+        if (!rcnt) ABORT(fp->fs, FR_INT_ERR);
+    }
+
+    LEAVE_FF(fp->fs, FR_OK);
+}
+#endif /* _USE_FORWARD */
+
+
+
+#if _USE_MKFS && !_FS_READONLY
+/*-----------------------------------------------------------------------*/
+/* Create File System on the Drive                                       */
+/*-----------------------------------------------------------------------*/
+#define N_ROOTDIR    512            /* Multiple of 32 and <= 2048 */
+#define N_FATS        1            /* 1 or 2 */
+#define MAX_SECTOR    131072000UL    /* Maximum partition size */
+#define MIN_SECTOR    2000UL        /* Minimum partition size */
+
+
+FRESULT f_mkfs (
+    BYTE drv,            /* Logical drive number */
+    BYTE partition,        /* Partitioning rule 0:FDISK, 1:SFD */
+    WORD allocsize        /* Allocation unit size [bytes] */
+)
+{
+    static const DWORD sstbl[] = { 2048000, 1024000, 512000, 256000, 128000, 64000, 32000, 16000, 8000, 4000,   0 };
+    static const WORD cstbl[] =  {   32768,   16384,   8192,   4096,   2048, 16384,  8192,  4096, 2048, 1024, 512 };
+    BYTE fmt, m, *tbl;
+    DWORD b_part, b_fat, b_dir, b_data;        /* Area offset (LBA) */
+    DWORD n_part, n_rsv, n_fat, n_dir;        /* Area size */
+    DWORD n_clst, d, n;
+    WORD as;
+    FATFS *fs;
+    DSTATUS stat;
+
+
+    /* Check validity of the parameters */
+    if (drv >= _DRIVES) return FR_INVALID_DRIVE;
+    if (partition >= 2) return FR_MKFS_ABORTED;
+
+    /* Check mounted drive and clear work area */
+    fs = FatFs[drv];
+    if (!fs) return FR_NOT_ENABLED;
+    fs->fs_type = 0;
+    drv = LD2PD(drv);
+
+    /* Get disk statics */
+    stat = disk_initialize(drv);
+    if (stat & STA_NOINIT) return FR_NOT_READY;
+    if (stat & STA_PROTECT) return FR_WRITE_PROTECTED;
+#if _MAX_SS != 512                        /* Get disk sector size */
+    if (disk_ioctl(drv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK
+        || SS(fs) > _MAX_SS)
+        return FR_MKFS_ABORTED;
+#endif
+    if (disk_ioctl(drv, GET_SECTOR_COUNT, &n_part) != RES_OK || n_part < MIN_SECTOR)
+        return FR_MKFS_ABORTED;
+    if (n_part > MAX_SECTOR) n_part = MAX_SECTOR;
+    b_part = (!partition) ? 63 : 0;        /* Boot sector */
+    n_part -= b_part;
+    for (d = 512; d <= 32768U && d != allocsize; d <<= 1) ;    /* Check validity of the allocation unit size */
+    if (d != allocsize) allocsize = 0;
+    if (!allocsize) {                    /* Auto selection of cluster size */
+        d = n_part;
+        for (as = SS(fs); as > 512U; as >>= 1) d >>= 1;
+        for (n = 0; d < sstbl[n]; n++) ;
+        allocsize = cstbl[n];
+    }
+    if (allocsize < SS(fs)) allocsize = SS(fs);
+
+    allocsize /= SS(fs);        /* Number of sectors per cluster */
+
+    /* Pre-compute number of clusters and FAT type */
+    n_clst = n_part / allocsize;
+    fmt = FS_FAT12;
+    if (n_clst >= 0xFF5) fmt = FS_FAT16;
+    if (n_clst >= 0xFFF5) fmt = FS_FAT32;
+
+    /* Determine offset and size of FAT structure */
+    switch (fmt) {
+    case FS_FAT12:
+        n_fat = ((n_clst * 3 + 1) / 2 + 3 + SS(fs) - 1) / SS(fs);
+        n_rsv = 1 + partition;
+        n_dir = N_ROOTDIR * 32 / SS(fs);
+        break;
+    case FS_FAT16:
+        n_fat = ((n_clst * 2) + 4 + SS(fs) - 1) / SS(fs);
+        n_rsv = 1 + partition;
+        n_dir = N_ROOTDIR * 32 / SS(fs);
+        break;
+    default:
+        n_fat = ((n_clst * 4) + 8 + SS(fs) - 1) / SS(fs);
+        n_rsv = 33 - partition;
+        n_dir = 0;
+    }
+    b_fat = b_part + n_rsv;            /* FATs start sector */
+    b_dir = b_fat + n_fat * N_FATS;    /* Directory start sector */
+    b_data = b_dir + n_dir;            /* Data start sector */
+
+    /* Align data start sector to erase block boundary (for flash memory media) */
+    if (disk_ioctl(drv, GET_BLOCK_SIZE, &n) != RES_OK) return FR_MKFS_ABORTED;
+    n = (b_data + n - 1) & ~(n - 1);
+    n_fat += (n - b_data) / N_FATS;
+    /* b_dir and b_data are no longer used below */
+
+    /* Determine number of cluster and final check of validity of the FAT type */
+    n_clst = (n_part - n_rsv - n_fat * N_FATS - n_dir) / allocsize;
+    if (   (fmt == FS_FAT16 && n_clst < 0xFF5)
+        || (fmt == FS_FAT32 && n_clst < 0xFFF5))
+        return FR_MKFS_ABORTED;
+
+    /* Create partition table if needed */
+    if (!partition) {
+        DWORD n_disk = b_part + n_part;
+
+        mem_set(fs->win, 0, SS(fs));
+        tbl = fs->win+MBR_Table;
+        ST_DWORD(tbl, 0x00010180);        /* Partition start in CHS */
+        if (n_disk < 63UL * 255 * 1024) {    /* Partition end in CHS */
+            n_disk = n_disk / 63 / 255;
+            tbl[7] = (BYTE)n_disk;
+            tbl[6] = (BYTE)((n_disk >> 2) | 63);
+        } else {
+            ST_WORD(&tbl[6], 0xFFFF);
+        }
+        tbl[5] = 254;
+        if (fmt != FS_FAT32)            /* System ID */
+            tbl[4] = (n_part < 0x10000) ? 0x04 : 0x06;
+        else
+            tbl[4] = 0x0c;
+        ST_DWORD(tbl+8, 63);            /* Partition start in LBA */
+        ST_DWORD(tbl+12, n_part);        /* Partition size in LBA */
+        ST_WORD(tbl+64, 0xAA55);        /* Signature */
+        if (disk_write(drv, fs->win, 0, 1) != RES_OK)
+            return FR_DISK_ERR;
+        partition = 0xF8;
+    } else {
+        partition = 0xF0;
+    }
+
+    /* Create boot record */
+    tbl = fs->win;                                /* Clear buffer */
+    mem_set(tbl, 0, SS(fs));
+    ST_DWORD(tbl+BS_jmpBoot, 0x90FEEB);            /* Boot code (jmp $, nop) */
+    ST_WORD(tbl+BPB_BytsPerSec, SS(fs));        /* Sector size */
+    tbl[BPB_SecPerClus] = (BYTE)allocsize;        /* Sectors per cluster */
+    ST_WORD(tbl+BPB_RsvdSecCnt, n_rsv);            /* Reserved sectors */
+    tbl[BPB_NumFATs] = N_FATS;                    /* Number of FATs */
+    ST_WORD(tbl+BPB_RootEntCnt, SS(fs) / 32 * n_dir); /* Number of rootdir entries */
+    if (n_part < 0x10000) {                        /* Number of total sectors */
+        ST_WORD(tbl+BPB_TotSec16, n_part);
+    } else {
+        ST_DWORD(tbl+BPB_TotSec32, n_part);
+    }
+    tbl[BPB_Media] = partition;                    /* Media descripter */
+    ST_WORD(tbl+BPB_SecPerTrk, 63);                /* Number of sectors per track */
+    ST_WORD(tbl+BPB_NumHeads, 255);                /* Number of heads */
+    ST_DWORD(tbl+BPB_HiddSec, b_part);            /* Hidden sectors */
+    n = get_fattime();                            /* Use current time as a VSN */
+    if (fmt != FS_FAT32) {
+        ST_DWORD(tbl+BS_VolID, n);                /* Volume serial number */
+        ST_WORD(tbl+BPB_FATSz16, n_fat);        /* Number of secters per FAT */
+        tbl[BS_DrvNum] = 0x80;                    /* Drive number */
+        tbl[BS_BootSig] = 0x29;                    /* Extended boot signature */
+        mem_cpy(tbl+BS_VolLab, "NO NAME    FAT     ", 19);    /* Volume lavel, FAT signature */
+    } else {
+        ST_DWORD(tbl+BS_VolID32, n);            /* Volume serial number */
+        ST_DWORD(tbl+BPB_FATSz32, n_fat);        /* Number of secters per FAT */
+        ST_DWORD(tbl+BPB_RootClus, 2);            /* Root directory cluster (2) */
+        ST_WORD(tbl+BPB_FSInfo, 1);                /* FSInfo record offset (bs+1) */
+        ST_WORD(tbl+BPB_BkBootSec, 6);            /* Backup boot record offset (bs+6) */
+        tbl[BS_DrvNum32] = 0x80;                /* Drive number */
+        tbl[BS_BootSig32] = 0x29;                /* Extended boot signature */
+        mem_cpy(tbl+BS_VolLab32, "NO NAME    FAT32   ", 19);    /* Volume lavel, FAT signature */
+    }
+    ST_WORD(tbl+BS_55AA, 0xAA55);                /* Signature */
+    if (SS(fs) > 512U) {
+        ST_WORD(tbl+SS(fs)-2, 0xAA55);
+    }
+    if (disk_write(drv, tbl, b_part+0, 1) != RES_OK)
+        return FR_DISK_ERR;
+    if (fmt == FS_FAT32)
+        disk_write(drv, tbl, b_part+6, 1);
+
+    /* Initialize FAT area */
+    for (m = 0; m < N_FATS; m++) {
+        mem_set(tbl, 0, SS(fs));        /* 1st sector of the FAT  */
+        if (fmt != FS_FAT32) {
+            n = (fmt == FS_FAT12) ? 0x00FFFF00 : 0xFFFFFF00;
+            n |= partition;
+            ST_DWORD(tbl, n);                /* Reserve cluster #0-1 (FAT12/16) */
+        } else {
+            ST_DWORD(tbl+0, 0xFFFFFFF8);    /* Reserve cluster #0-1 (FAT32) */
+            ST_DWORD(tbl+4, 0xFFFFFFFF);
+            ST_DWORD(tbl+8, 0x0FFFFFFF);    /* Reserve cluster #2 for root dir */
+        }
+        if (disk_write(drv, tbl, b_fat++, 1) != RES_OK)
+            return FR_DISK_ERR;
+        mem_set(tbl, 0, SS(fs));        /* Following FAT entries are filled by zero */
+        for (n = 1; n < n_fat; n++) {
+            if (disk_write(drv, tbl, b_fat++, 1) != RES_OK)
+                return FR_DISK_ERR;
+        }
+    }
+
+    /* Initialize Root directory */
+    m = (BYTE)((fmt == FS_FAT32) ? allocsize : n_dir);
+    do {
+        if (disk_write(drv, tbl, b_fat++, 1) != RES_OK)
+            return FR_DISK_ERR;
+    } while (--m);
+
+    /* Create FSInfo record if needed */
+    if (fmt == FS_FAT32) {
+        ST_WORD(tbl+BS_55AA, 0xAA55);
+        ST_DWORD(tbl+FSI_LeadSig, 0x41615252);
+        ST_DWORD(tbl+FSI_StrucSig, 0x61417272);
+        ST_DWORD(tbl+FSI_Free_Count, n_clst - 1);
+        ST_DWORD(tbl+FSI_Nxt_Free, 0xFFFFFFFF);
+        disk_write(drv, tbl, b_part+1, 1);
+        disk_write(drv, tbl, b_part+7, 1);
+    }
+
+    return (disk_ioctl(drv, CTRL_SYNC, (void*)NULL) == RES_OK) ? FR_OK : FR_DISK_ERR;
+}
+
+#endif /* _USE_MKFS && !_FS_READONLY */
+
+
+
+
+#if _USE_STRFUNC
+/*-----------------------------------------------------------------------*/
+/* Get a string from the file                                            */
+/*-----------------------------------------------------------------------*/
+char* f_gets (
+    char* buff,    /* Pointer to the string buffer to read */
+    int len,    /* Size of string buffer */
+    FIL* fil    /* Pointer to the file object */
+)
+{
+    int i = 0;
+    char *p = buff;
+    UINT rc;
+
+
+    while (i < len - 1) {            /* Read bytes until buffer gets filled */
+        f_read(fil, p, 1, &rc);
+        if (rc != 1) break;            /* Break when no data to read */
+#if _USE_STRFUNC >= 2
+        if (*p == '\r') continue;    /* Strip '\r' */
+#endif
+        i++;
+        if (*p++ == '\n') break;    /* Break when reached end of line */
+    }
+    *p = 0;
+    return i ? buff : NULL;            /* When no data read (eof or error), return with error. */
+}
+
+
+
+#if !_FS_READONLY
+#include <stdarg.h>
+/*-----------------------------------------------------------------------*/
+/* Put a character to the file                                           */
+/*-----------------------------------------------------------------------*/
+int f_putc (
+    int chr,    /* A character to be output */
+    FIL* fil    /* Ponter to the file object */
+)
+{
+    UINT bw;
+    char c;
+
+
+#if _USE_STRFUNC >= 2
+    if (chr == '\n') f_putc ('\r', fil);    /* LF -> CRLF conversion */
+#endif
+    if (!fil) {    /* Special value may be used to switch the destination to any other device */
+    /*    put_console(chr);    */
+        return chr;
+    }
+    c = (char)chr;
+    f_write(fil, &c, 1, &bw);    /* Write a byte to the file */
+    return bw ? chr : EOF;        /* Return the result */
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Put a string to the file                                              */
+/*-----------------------------------------------------------------------*/
+int f_puts (
+    const char* str,    /* Pointer to the string to be output */
+    FIL* fil            /* Pointer to the file object */
+)
+{
+    int n;
+
+
+    for (n = 0; *str; str++, n++) {
+        if (f_putc(*str, fil) == EOF) return EOF;
+    }
+    return n;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Put a formatted string to the file                                    */
+/*-----------------------------------------------------------------------*/
+int f_printf (
+    FIL* fil,            /* Pointer to the file object */
+    const char* str,    /* Pointer to the format string */
+    ...                    /* Optional arguments... */
+)
+{
+    va_list arp;
+    UCHAR c, f, r;
+    ULONG val;
+    char s[16];
+    int i, w, res, cc;
+
+
+    va_start(arp, str);
+
+    for (cc = res = 0; cc != EOF; res += cc) {
+        c = *str++;
+        if (c == 0) break;            /* End of string */
+        if (c != '%') {                /* Non escape cahracter */
+            cc = f_putc(c, fil);
+            if (cc != EOF) cc = 1;
+            continue;
+        }
+        w = f = 0;
+        c = *str++;
+        if (c == '0') {                /* Flag: '0' padding */
+            f = 1; c = *str++;
+        }
+        while (c >= '0' && c <= '9') {    /* Precision */
+            w = w * 10 + (c - '0');
+            c = *str++;
+        }
+        if (c == 'l') {                /* Prefix: Size is long int */
+            f |= 2; c = *str++;
+        }
+        if (c == 's') {                /* Type is string */
+            cc = f_puts(va_arg(arp, char*), fil);
+            continue;
+        }
+        if (c == 'c') {                /* Type is character */
+            cc = f_putc(va_arg(arp, int), fil);
+            if (cc != EOF) cc = 1;
+            continue;
+        }
+        r = 0;
+        if (c == 'd') r = 10;        /* Type is signed decimal */
+        if (c == 'u') r = 10;        /* Type is unsigned decimal */
+        if (c == 'X') r = 16;        /* Type is unsigned hexdecimal */
+        if (r == 0) break;            /* Unknown type */
+        if (f & 2) {                /* Get the value */
+            val = (ULONG)va_arg(arp, long);
+        } else {
+            val = (c == 'd') ? (ULONG)(long)va_arg(arp, int) : (ULONG)va_arg(arp, unsigned int);
+        }
+        /* Put numeral string */
+        if (c == 'd') {
+            if (val & 0x80000000) {
+                val = 0 - val;
+                f |= 4;
+            }
+        }
+        i = sizeof(s) - 1; s[i] = 0;
+        do {
+            c = (UCHAR)(val % r + '0');
+            if (c > '9') c += 7;
+            s[--i] = c;
+            val /= r;
+        } while (i && val);
+        if (i && (f & 4)) s[--i] = '-';
+        w = sizeof(s) - 1 - w;
+        while (i && i > w) s[--i] = (f & 1) ? '0' : ' ';
+        cc = f_puts(&s[i], fil);
+    }
+
+    va_end(arp);
+    return (cc == EOF) ? cc : res;
+}
+
+#endif /* !_FS_READONLY */
+#endif /* _USE_STRFUNC */
diff -r 000000000000 -r 085749c8446f Code/chan_fat_fs/ff.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Code/chan_fat_fs/ff.h	Wed Jun 13 15:10:06 2012 +0000
@@ -0,0 +1,596 @@
+/*---------------------------------------------------------------------------/
+/  FatFs - FAT file system module include file  R0.07e       (C)ChaN, 2009
+/----------------------------------------------------------------------------/
+/ FatFs module is a generic FAT file system module for small embedded systems.
+/ This is a free software that opened for education, research and commercial
+/ developments under license policy of following trems.
+/
+/  Copyright (C) 2009, ChaN, all right reserved.
+/
+/ * The FatFs module is a free software and there is NO WARRANTY.
+/ * No restriction on use. You can use, modify and redistribute it for
+/   personal, non-profit or commercial product UNDER YOUR RESPONSIBILITY.
+/ * Redistributions of source code must retain the above copyright notice.
+/----------------------------------------------------------------------------*/
+
+#ifndef _FATFS
+#define _FATFS    0x007E
+
+#include "integer.h"    /* Basic integer types */
+#include "ffconf.h"        /* FatFs configuration options */
+
+#if _FATFS != _FFCONFIG
+#error Wrong configuration file (ffconf.h).
+#endif
+
+
+/* DBCS code ranges and SBCS extend char conversion table */
+
+#if _CODE_PAGE == 932    /* Japanese Shift-JIS */
+#define _DF1S    0x81    /* DBC 1st byte range 1 start */
+#define _DF1E    0x9F    /* DBC 1st byte range 1 end */
+#define _DF2S    0xE0    /* DBC 1st byte range 2 start */
+#define _DF2E    0xFC    /* DBC 1st byte range 2 end */
+#define _DS1S    0x40    /* DBC 2nd byte range 1 start */
+#define _DS1E    0x7E    /* DBC 2nd byte range 1 end */
+#define _DS2S    0x80    /* DBC 2nd byte range 2 start */
+#define _DS2E    0xFC    /* DBC 2nd byte range 2 end */
+
+#elif _CODE_PAGE == 936    /* Simplified Chinese GBK */
+#define _DF1S    0x81
+#define _DF1E    0xFE
+#define _DS1S    0x40
+#define _DS1E    0x7E
+#define _DS2S    0x80
+#define _DS2E    0xFE
+
+#elif _CODE_PAGE == 949    /* Korean */
+#define _DF1S    0x81
+#define _DF1E    0xFE
+#define _DS1S    0x41
+#define _DS1E    0x5A
+#define _DS2S    0x61
+#define _DS2E    0x7A
+#define _DS3S    0x81
+#define _DS3E    0xFE
+
+#elif _CODE_PAGE == 950    /* Traditional Chinese Big5 */
+#define _DF1S    0x81
+#define _DF1E    0xFE
+#define _DS1S    0x40
+#define _DS1E    0x7E
+#define _DS2S    0xA1
+#define _DS2E    0xFE
+
+#elif _CODE_PAGE == 437    /* U.S. (OEM) */
+#define _DF1S    0
+#define _EXCVT {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F,0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+                0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+                0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 720    /* Arabic (OEM) */
+#define _DF1S    0
+#define _EXCVT {0x80,0x81,0x45,0x41,0x84,0x41,0x86,0x43,0x45,0x45,0x45,0x49,0x49,0x8D,0x8E,0x8F,0x90,0x92,0x92,0x93,0x94,0x95,0x49,0x49,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+                0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+                0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 737    /* Greek (OEM) */
+#define _DF1S    0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x92,0x92,0x93,0x94,0x95,0x96,0x97,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87, \
+                0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0xAA,0x92,0x93,0x94,0x95,0x96,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+                0x97,0xEA,0xEB,0xEC,0xE4,0xED,0xEE,0xE7,0xE8,0xF1,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 775    /* Baltic (OEM) */
+#define _DF1S    0
+#define _EXCVT {0x80,0x9A,0x91,0xA0,0x8E,0x95,0x8F,0x80,0xAD,0xED,0x8A,0x8A,0xA1,0x8D,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0x95,0x96,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \
+                0xA0,0xA1,0xE0,0xA3,0xA3,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xA5,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+                0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE3,0xE8,0xE8,0xEA,0xEA,0xEE,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 850    /* Multilingual Latin 1 (OEM) */
+#define _DF1S    0
+#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0xDE,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x59,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \
+                0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+                0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE7,0xE9,0xEA,0xEB,0xED,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 852    /* Latin 2 (OEM) */
+#define _DF1S    0
+#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xDE,0x8F,0x80,0x9D,0xD3,0x8A,0x8A,0xD7,0x8D,0x8E,0x8F,0x90,0x91,0x91,0xE2,0x99,0x95,0x95,0x97,0x97,0x99,0x9A,0x9B,0x9B,0x9D,0x9E,0x9F, \
+                0xB5,0xD6,0xE0,0xE9,0xA4,0xA4,0xA6,0xA6,0xA8,0xA8,0xAA,0x8D,0xAC,0xB8,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBD,0xBF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC6,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD2,0xD3,0xD2,0xD5,0xD6,0xD7,0xB7,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+                0xE0,0xE1,0xE2,0xE3,0xE3,0xD5,0xE6,0xE6,0xE8,0xE9,0xE8,0xEB,0xED,0xED,0xDD,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xEB,0xFC,0xFC,0xFE,0xFF}
+
+#elif _CODE_PAGE == 855    /* Cyrillic (OEM) */
+#define _DF1S    0
+#define _EXCVT {0x81,0x81,0x83,0x83,0x85,0x85,0x87,0x87,0x89,0x89,0x8B,0x8B,0x8D,0x8D,0x8F,0x8F,0x91,0x91,0x93,0x93,0x95,0x95,0x97,0x97,0x99,0x99,0x9B,0x9B,0x9D,0x9D,0x9F,0x9F, \
+                0xA1,0xA1,0xA3,0xA3,0xA5,0xA5,0xA7,0xA7,0xA9,0xA9,0xAB,0xAB,0xAD,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB6,0xB6,0xB8,0xB8,0xB9,0xBA,0xBB,0xBC,0xBE,0xBE,0xBF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD3,0xD3,0xD5,0xD5,0xD7,0xD7,0xDD,0xD9,0xDA,0xDB,0xDC,0xDD,0xE0,0xDF, \
+                0xE0,0xE2,0xE2,0xE4,0xE4,0xE6,0xE6,0xE8,0xE8,0xEA,0xEA,0xEC,0xEC,0xEE,0xEE,0xEF,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 857    /* Turkish (OEM) */
+#define _DF1S    0
+#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0x98,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x98,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9E, \
+                0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA6,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+                0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xDE,0x59,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 858    /* Multilingual Latin 1 + Euro (OEM) */
+#define _DF1S    0
+#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0xDE,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x59,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \
+                0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+                0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE7,0xE9,0xEA,0xEB,0xED,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 862    /* Hebrew (OEM) */
+#define _DF1S    0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+                0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+                0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 866    /* Russian (OEM) */
+#define _DF1S    0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+                0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+                0x90,0x91,0x92,0x93,0x9d,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 874    /* Thai (OEM, Windows) */
+#define _DF1S    0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+                0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+                0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 1250 /* Central Europe (Windows) */
+#define _DF1S    0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x8D,0x8E,0x8F, \
+                0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xA3,0xB4,0xB5,0xB6,0xB7,0xB8,0xA5,0xAA,0xBB,0xBC,0xBD,0xBC,0xAF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xFF}
+
+#elif _CODE_PAGE == 1251 /* Cyrillic (Windows) */
+#define _DF1S    0
+#define _EXCVT {0x80,0x81,0x82,0x82,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x80,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x8D,0x8E,0x8F, \
+                0xA0,0xA2,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB2,0xA5,0xB5,0xB6,0xB7,0xA8,0xB9,0xAA,0xBB,0xA3,0xBD,0xBD,0xAF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF}
+
+#elif _CODE_PAGE == 1252 /* Latin 1 (Windows) */
+#define _DF1S    0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0xAd,0x9B,0x8C,0x9D,0xAE,0x9F, \
+                0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x9F}
+
+#elif _CODE_PAGE == 1253 /* Greek (Windows) */
+#define _DF1S    0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+                0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xA2,0xB8,0xB9,0xBA, \
+                0xE0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xF2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xFB,0xBC,0xFD,0xBF,0xFF}
+
+#elif _CODE_PAGE == 1254 /* Turkish (Windows) */
+#define _DF1S    0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x9D,0x9E,0x9F, \
+                0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x9F}
+
+#elif _CODE_PAGE == 1255 /* Hebrew (Windows) */
+#define _DF1S    0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+                0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+                0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 1256 /* Arabic (Windows) */
+#define _DF1S    0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x8C,0x9D,0x9E,0x9F, \
+                0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+                0x41,0xE1,0x41,0xE3,0xE4,0xE5,0xE6,0x43,0x45,0x45,0x45,0x45,0xEC,0xED,0x49,0x49,0xF0,0xF1,0xF2,0xF3,0x4F,0xF5,0xF6,0xF7,0xF8,0x55,0xFA,0x55,0x55,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 1257 /* Baltic (Windows) */
+#define _DF1S    0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+                0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xA8,0xB9,0xAA,0xBB,0xBC,0xBD,0xBE,0xAF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xFF}
+
+#elif _CODE_PAGE == 1258 /* Vietnam (OEM, Windows) */
+#define _DF1S    0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0xAC,0x9D,0x9E,0x9F, \
+                0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xEC,0xCD,0xCE,0xCF,0xD0,0xD1,0xF2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xFE,0x9F}
+
+#elif _CODE_PAGE == 1    /* ASCII (for only non-LFN cfg) */
+#define _DF1S    0
+
+#else
+#error Unknown code page
+
+#endif
+
+
+
+/* Character code support macros */
+
+#define IsUpper(c)    (((c)>='A')&&((c)<='Z'))
+#define IsLower(c)    (((c)>='a')&&((c)<='z'))
+
+#if _DF1S        /* DBCS configuration */
+
+#ifdef _DF2S    /* Two 1st byte areas */
+#define IsDBCS1(c)    (((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E) || ((BYTE)(c) >= _DF2S && (BYTE)(c) <= _DF2E))
+#else            /* One 1st byte area */
+#define IsDBCS1(c)    ((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E)
+#endif
+
+#ifdef _DS3S    /* Three 2nd byte areas */
+#define IsDBCS2(c)    (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E) || ((BYTE)(c) >= _DS3S && (BYTE)(c) <= _DS3E))
+#else            /* Two 2nd byte areas */
+#define IsDBCS2(c)    (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E))
+#endif
+
+#else            /* SBCS configuration */
+
+#define IsDBCS1(c)    0
+#define IsDBCS2(c)    0
+
+#endif /* _DF1S */
+
+
+
+/* Definitions corresponds to multi partition */
+
+#if _MULTI_PARTITION        /* Multiple partition configuration */
+
+typedef struct _PARTITION {
+    BYTE pd;    /* Physical drive# */
+    BYTE pt;    /* Partition # (0-3) */
+} PARTITION;
+
+extern
+const PARTITION Drives[];            /* Logical drive# to physical location conversion table */
+#define LD2PD(drv) (Drives[drv].pd)    /* Get physical drive# */
+#define LD2PT(drv) (Drives[drv].pt)    /* Get partition# */
+
+#else                        /* Single partition configuration */
+
+#define LD2PD(drv) (drv)    /* Physical drive# is equal to the logical drive# */
+#define LD2PT(drv) 0        /* Always mounts the 1st partition */
+
+#endif
+
+
+
+/* Definitions corresponds to multiple sector size */
+
+#if _MAX_SS == 512        /* Single sector size */
+#define    SS(fs)    512U
+
+#elif _MAX_SS == 1024 || _MAX_SS == 2048 || _MAX_SS == 4096    /* Multiple sector size */
+#define    SS(fs)    ((fs)->s_size)
+
+#else
+#error Sector size must be 512, 1024, 2048 or 4096.
+
+#endif
+
+
+
+/* Type of file name on FatFs API */
+
+#if _LFN_UNICODE && _USE_LFN
+typedef WCHAR XCHAR;    /* Unicode */
+#else
+typedef char XCHAR;        /* SBCS, DBCS */
+#endif
+
+
+
+/* File system object structure */
+
+typedef struct _FATFS_ {
+    BYTE    fs_type;    /* FAT sub type */
+    BYTE    drive;        /* Physical drive number */
+    BYTE    csize;        /* Number of sectors per cluster */
+    BYTE    n_fats;        /* Number of FAT copies */
+    BYTE    wflag;        /* win[] dirty flag (1:must be written back) */
+    BYTE    fsi_flag;    /* fsinfo dirty flag (1:must be written back) */
+    WORD    id;            /* File system mount ID */
+    WORD    n_rootdir;    /* Number of root directory entries (0 on FAT32) */
+#if _FS_REENTRANT
+    _SYNC_t    sobj;        /* Identifier of sync object */
+#endif
+#if _MAX_SS != 512
+    WORD    s_size;        /* Sector size */
+#endif
+#if !_FS_READONLY
+    DWORD    last_clust;    /* Last allocated cluster */
+    DWORD    free_clust;    /* Number of free clusters */
+    DWORD    fsi_sector;    /* fsinfo sector */
+#endif
+#if _FS_RPATH
+    DWORD    cdir;        /* Current directory (0:root)*/
+#endif
+    DWORD    sects_fat;    /* Sectors per fat */
+    DWORD    max_clust;    /* Maximum cluster# + 1. Number of clusters is max_clust - 2 */
+    DWORD    fatbase;    /* FAT start sector */
+    DWORD    dirbase;    /* Root directory start sector (Cluster# on FAT32) */
+    DWORD    database;    /* Data start sector */
+    DWORD    winsect;    /* Current sector appearing in the win[] */
+    BYTE    win[_MAX_SS];/* Disk access window for Directory/FAT */
+} FATFS;
+
+
+
+/* Directory object structure */
+
+typedef struct _DIR_ {
+    FATFS*    fs;            /* Pointer to the owner file system object */
+    WORD    id;            /* Owner file system mount ID */
+    WORD    index;        /* Current read/write index number */
+    DWORD    sclust;        /* Table start cluster (0:Static table) */
+    DWORD    clust;        /* Current cluster */
+    DWORD    sect;        /* Current sector */
+    BYTE*    dir;        /* Pointer to the current SFN entry in the win[] */
+    BYTE*    fn;            /* Pointer to the SFN (in/out) {file[8],ext[3],status[1]} */
+#if _USE_LFN
+    WCHAR*    lfn;        /* Pointer to the LFN working buffer */
+    WORD    lfn_idx;    /* Last matched LFN index number (0xFFFF:No LFN) */
+#endif
+} eDIR;
+
+
+
+/* File object structure */
+
+typedef struct _FIL_ {
+    FATFS*    fs;            /* Pointer to the owner file system object */
+    WORD    id;            /* Owner file system mount ID */
+    BYTE    flag;        /* File status flags */
+    BYTE    csect;        /* Sector address in the cluster */
+    DWORD    fptr;        /* File R/W pointer */
+    DWORD    fsize;        /* File size */
+    DWORD    org_clust;    /* File start cluster */
+    DWORD    curr_clust;    /* Current cluster */
+    DWORD    dsect;        /* Current data sector */
+#if !_FS_READONLY
+    DWORD    dir_sect;    /* Sector containing the directory entry */
+    BYTE*    dir_ptr;    /* Ponter to the directory entry in the window */
+#endif
+#if !_FS_TINY
+    BYTE    buf[_MAX_SS];/* File R/W buffer */
+#endif
+} FIL;
+
+
+
+/* File status structure */
+
+typedef struct _FILINFO_ {
+    DWORD    fsize;        /* File size */
+    WORD    fdate;        /* Last modified date */
+    WORD    ftime;        /* Last modified time */
+    BYTE    fattrib;    /* Attribute */
+    char    fname[13];    /* Short file name (8.3 format) */
+#if _USE_LFN
+    XCHAR*    lfname;        /* Pointer to the LFN buffer */
+    int     lfsize;        /* Size of LFN buffer [chrs] */
+#endif
+} FILINFO;
+
+
+
+/* File function return code (FRESULT) */
+
+typedef enum {
+    FR_OK = 0,            /* 0 */
+    FR_DISK_ERR,        /* 1 */
+    FR_INT_ERR,            /* 2 */
+    FR_NOT_READY,        /* 3 */
+    FR_NO_FILE,            /* 4 */
+    FR_NO_PATH,            /* 5 */
+    FR_INVALID_NAME,    /* 6 */
+    FR_DENIED,            /* 7 */
+    FR_EXIST,            /* 8 */
+    FR_INVALID_OBJECT,    /* 9 */
+    FR_WRITE_PROTECTED,    /* 10 */
+    FR_INVALID_DRIVE,    /* 11 */
+    FR_NOT_ENABLED,        /* 12 */
+    FR_NO_FILESYSTEM,    /* 13 */
+    FR_MKFS_ABORTED,    /* 14 */
+    FR_TIMEOUT            /* 15 */
+} FRESULT;
+
+
+
+/*--------------------------------------------------------------*/
+/* FatFs module application interface                           */
+
+FRESULT f_mount (BYTE, FATFS*);                        /* Mount/Unmount a logical drive */
+FRESULT f_open (FIL*, const XCHAR*, BYTE);            /* Open or create a file */
+FRESULT f_read (FIL*, void*, UINT, UINT*);            /* Read data from a file */
+FRESULT f_write (FIL*, const void*, UINT, UINT*);    /* Write data to a file */
+FRESULT f_lseek (FIL*, DWORD);                        /* Move file pointer of a file object */
+FRESULT f_close (FIL*);                                /* Close an open file object */
+FRESULT f_opendir (eDIR*, const XCHAR*);                /* Open an existing directory */
+FRESULT f_readdir (eDIR*, FILINFO*);                    /* Read a directory item */
+FRESULT f_stat (const XCHAR*, FILINFO*);            /* Get file status */
+FRESULT f_getfree (const XCHAR*, DWORD*, FATFS**);    /* Get number of free clusters on the drive */
+FRESULT f_truncate (FIL*);                            /* Truncate file */
+FRESULT f_sync (FIL*);                                /* Flush cached data of a writing file */
+FRESULT f_unlink (const XCHAR*);                    /* Delete an existing file or directory */
+FRESULT    f_mkdir (const XCHAR*);                        /* Create a new directory */
+FRESULT f_chmod (const XCHAR*, BYTE, BYTE);            /* Change attriburte of the file/dir */
+FRESULT f_utime (const XCHAR*, const FILINFO*);        /* Change timestamp of the file/dir */
+FRESULT f_rename (const XCHAR*, const XCHAR*);        /* Rename/Move a file or directory */
+FRESULT f_forward (FIL*, UINT(*)(const BYTE*,UINT), UINT, UINT*);    /* Forward data to the stream */
+FRESULT f_mkfs (BYTE, BYTE, WORD);                    /* Create a file system on the drive */
+FRESULT f_chdir (const XCHAR*);                        /* Change current directory */
+FRESULT f_chdrive (BYTE);                            /* Change current drive */
+
+#if _USE_STRFUNC
+int f_putc (int, FIL*);                                /* Put a character to the file */
+int f_puts (const char*, FIL*);                        /* Put a string to the file */
+int f_printf (FIL*, const char*, ...);                /* Put a formatted string to the file */
+char* f_gets (char*, int, FIL*);                    /* Get a string from the file */
+#define f_eof(fp) (((fp)->fptr == (fp)->fsize) ? 1 : 0)
+#define f_error(fp) (((fp)->flag & FA__ERROR) ? 1 : 0)
+#ifndef EOF
+#define EOF -1
+#endif
+#endif
+
+
+
+/*--------------------------------------------------------------*/
+/* User defined functions                                       */
+
+/* Real time clock */
+#if !_FS_READONLY
+DWORD get_fattime (void);    /* 31-25: Year(0-127 org.1980), 24-21: Month(1-12), 20-16: Day(1-31) */
+                            /* 15-11: Hour(0-23), 10-5: Minute(0-59), 4-0: Second(0-29 *2) */
+#endif
+
+/* Unicode - OEM code conversion */
+#if _USE_LFN
+WCHAR ff_convert (WCHAR, UINT);
+WCHAR ff_wtoupper (WCHAR);
+#endif
+
+/* Sync functions */
+#if _FS_REENTRANT
+BOOL ff_cre_syncobj(BYTE, _SYNC_t*);
+BOOL ff_del_syncobj(_SYNC_t);
+BOOL ff_req_grant(_SYNC_t);
+void ff_rel_grant(_SYNC_t);
+#endif
+
+
+
+/*--------------------------------------------------------------*/
+/* Flags and offset address                                     */
+
+
+/* File access control and file status flags (FIL.flag) */
+
+#define    FA_READ                0x01
+#define    FA_OPEN_EXISTING    0x00
+#if _FS_READONLY == 0
+#define    FA_WRITE            0x02
+#define    FA_CREATE_NEW        0x04
+#define    FA_CREATE_ALWAYS    0x08
+#define    FA_OPEN_ALWAYS        0x10
+#define FA__WRITTEN            0x20
+#define FA__DIRTY            0x40
+#endif
+#define FA__ERROR            0x80
+
+
+/* FAT sub type (FATFS.fs_type) */
+
+#define FS_FAT12    1
+#define FS_FAT16    2
+#define FS_FAT32    3
+
+
+/* File attribute bits for directory entry */
+
+#define    AM_RDO    0x01    /* Read only */
+#define    AM_HID    0x02    /* Hidden */
+#define    AM_SYS    0x04    /* System */
+#define    AM_VOL    0x08    /* Volume label */
+#define AM_LFN    0x0F    /* LFN entry */
+#define AM_DIR    0x10    /* Directory */
+#define AM_ARC    0x20    /* Archive */
+#define AM_MASK    0x3F    /* Mask of defined bits */
+
+
+/* FatFs refers the members in the FAT structures with byte offset instead
+/ of structure member because there are incompatibility of the packing option
+/ between various compilers. */
+
+#define BS_jmpBoot            0
+#define BS_OEMName            3
+#define BPB_BytsPerSec        11
+#define BPB_SecPerClus        13
+#define BPB_RsvdSecCnt        14
+#define BPB_NumFATs            16
+#define BPB_RootEntCnt        17
+#define BPB_TotSec16        19
+#define BPB_Media            21
+#define BPB_FATSz16            22
+#define BPB_SecPerTrk        24
+#define BPB_NumHeads        26
+#define BPB_HiddSec            28
+#define BPB_TotSec32        32
+#define BS_55AA                510
+
+#define BS_DrvNum            36
+#define BS_BootSig            38
+#define BS_VolID            39
+#define BS_VolLab            43
+#define BS_FilSysType        54
+
+#define BPB_FATSz32            36
+#define BPB_ExtFlags        40
+#define BPB_FSVer            42
+#define BPB_RootClus        44
+#define BPB_FSInfo            48
+#define BPB_BkBootSec        50
+#define BS_DrvNum32            64
+#define BS_BootSig32        66
+#define BS_VolID32            67
+#define BS_VolLab32            71
+#define BS_FilSysType32        82
+
+#define    FSI_LeadSig            0
+#define    FSI_StrucSig        484
+#define    FSI_Free_Count        488
+#define    FSI_Nxt_Free        492
+
+#define MBR_Table            446
+
+#define    DIR_Name            0
+#define    DIR_Attr            11
+#define    DIR_NTres            12
+#define    DIR_CrtTime            14
+#define    DIR_CrtDate            16
+#define    DIR_FstClusHI        20
+#define    DIR_WrtTime            22
+#define    DIR_WrtDate            24
+#define    DIR_FstClusLO        26
+#define    DIR_FileSize        28
+#define    LDIR_Ord            0
+#define    LDIR_Attr            11
+#define    LDIR_Type            12
+#define    LDIR_Chksum            13
+#define    LDIR_FstClusLO        26
+
+
+
+/*--------------------------------*/
+/* Multi-byte word access macros  */
+
+#if _WORD_ACCESS == 1    /* Enable word access to the FAT structure */
+#define    LD_WORD(ptr)        (WORD)(*(WORD*)(BYTE*)(ptr))
+#define    LD_DWORD(ptr)        (DWORD)(*(DWORD*)(BYTE*)(ptr))
+#define    ST_WORD(ptr,val)    *(WORD*)(BYTE*)(ptr)=(WORD)(val)
+#define    ST_DWORD(ptr,val)    *(DWORD*)(BYTE*)(ptr)=(DWORD)(val)
+#else                    /* Use byte-by-byte access to the FAT structure */
+#define    LD_WORD(ptr)        (WORD)(((WORD)*(BYTE*)((ptr)+1)<<8)|(WORD)*(BYTE*)(ptr))
+#define    LD_DWORD(ptr)        (DWORD)(((DWORD)*(BYTE*)((ptr)+3)<<24)|((DWORD)*(BYTE*)((ptr)+2)<<16)|((WORD)*(BYTE*)((ptr)+1)<<8)|*(BYTE*)(ptr))
+#define    ST_WORD(ptr,val)    *(BYTE*)(ptr)=(BYTE)(val); *(BYTE*)((ptr)+1)=(BYTE)((WORD)(val)>>8)
+#define    ST_DWORD(ptr,val)    *(BYTE*)(ptr)=(BYTE)(val); *(BYTE*)((ptr)+1)=(BYTE)((WORD)(val)>>8); *(BYTE*)((ptr)+2)=(BYTE)((DWORD)(val)>>16); *(BYTE*)((ptr)+3)=(BYTE)((DWORD)(val)>>24)
+#endif
+
+
+#endif /* _FATFS */
diff -r 000000000000 -r 085749c8446f Code/chan_fat_fs/ffconf.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Code/chan_fat_fs/ffconf.h	Wed Jun 13 15:10:06 2012 +0000
@@ -0,0 +1,166 @@
+/*---------------------------------------------------------------------------/
+/  FatFs - FAT file system module configuration file  R0.07e  (C)ChaN, 2009
+/----------------------------------------------------------------------------/
+/
+/ CAUTION! Do not forget to make clean the project after any changes to
+/ the configuration options.
+/
+/----------------------------------------------------------------------------*/
+#ifndef _FFCONFIG
+#define _FFCONFIG 0x007E
+
+
+/*---------------------------------------------------------------------------/
+/ Function and Buffer Configurations
+/----------------------------------------------------------------------------*/
+
+#define    _FS_TINY    0        /* 0 or 1 */
+/* When _FS_TINY is set to 1, FatFs uses the sector buffer in the file system
+/  object instead of the sector buffer in the individual file object for file
+/  data transfer. This reduces memory consumption 512 bytes each file object. */
+
+
+#define _FS_READONLY    0    /* 0 or 1 */
+/* Setting _FS_READONLY to 1 defines read only configuration. This removes
+/  writing functions, f_write, f_sync, f_unlink, f_mkdir, f_chmod, f_rename,
+/  f_truncate and useless f_getfree. */
+
+
+#define _FS_MINIMIZE    0    /* 0, 1, 2 or 3 */
+/* The _FS_MINIMIZE option defines minimization level to remove some functions.
+/
+/   0: Full function.
+/   1: f_stat, f_getfree, f_unlink, f_mkdir, f_chmod, f_truncate and f_rename
+/      are removed.
+/   2: f_opendir and f_readdir are removed in addition to level 1.
+/   3: f_lseek is removed in addition to level 2. */
+
+
+#define    _USE_STRFUNC    1    /* 0, 1 or 2 */
+/* To enable string functions, set _USE_STRFUNC to 1 or 2. */
+
+
+#define    _USE_MKFS    0        /* 0 or 1 */
+/* To enable f_mkfs function, set _USE_MKFS to 1 and set _FS_READONLY to 0 */
+
+
+#define    _USE_FORWARD    0    /* 0 or 1 */
+/* To enable f_forward function, set _USE_FORWARD to 1 and set _FS_TINY to 1. */
+
+
+
+/*---------------------------------------------------------------------------/
+/ Locale and Namespace Configurations
+/----------------------------------------------------------------------------*/
+
+#define _CODE_PAGE    437
+/* The _CODE_PAGE specifies the OEM code page to be used on the target system.
+/  Incorrect setting of the code page can cause a file open failure.
+/
+/   932  - Japanese Shift-JIS (DBCS, OEM, Windows)
+/   936  - Simplified Chinese GBK (DBCS, OEM, Windows)
+/   949  - Korean (DBCS, OEM, Windows)
+/   950  - Traditional Chinese Big5 (DBCS, OEM, Windows)
+/   1250 - Central Europe (Windows)
+/   1251 - Cyrillic (Windows)
+/   1252 - Latin 1 (Windows)
+/   1253 - Greek (Windows)
+/   1254 - Turkish (Windows)
+/   1255 - Hebrew (Windows)
+/   1256 - Arabic (Windows)
+/   1257 - Baltic (Windows)
+/   1258 - Vietnam (OEM, Windows)
+/   437  - U.S. (OEM)
+/   720  - Arabic (OEM)
+/   737  - Greek (OEM)
+/   775  - Baltic (OEM)
+/   850  - Multilingual Latin 1 (OEM)
+/   858  - Multilingual Latin 1 + Euro (OEM)
+/   852  - Latin 2 (OEM)
+/   855  - Cyrillic (OEM)
+/   866  - Russian (OEM)
+/   857  - Turkish (OEM)
+/   862  - Hebrew (OEM)
+/   874  - Thai (OEM, Windows)
+/    1    - ASCII only (Valid for non LFN cfg.)
+*/
+
+
+#define    _USE_LFN    1        /* 0, 1 or 2 */
+#define    _MAX_LFN    255        /* Maximum LFN length to handle (12 to 255) */
+/* The _USE_LFN option switches the LFN support.
+/
+/   0: Disable LFN. _MAX_LFN and _LFN_UNICODE have no effect.
+/   1: Enable LFN with static working buffer on the bss. NOT REENTRANT.
+/   2: Enable LFN with dynamic working buffer on the STACK.
+/
+/  The LFN working buffer occupies (_MAX_LFN + 1) * 2 bytes. When enable LFN,
+/  two Unicode handling functions ff_convert() and ff_wtoupper() must be added
+/  to the project. */
+
+
+#define    _LFN_UNICODE    0    /* 0 or 1 */
+/* To switch the character code set on FatFs API to Unicode,
+/  enable LFN feature and set _LFN_UNICODE to 1.
+*/
+
+
+#define _FS_RPATH    0        /* 0 or 1 */
+/* When _FS_RPATH is set to 1, relative path feature is enabled and f_chdir,
+/  f_chdrive function are available.
+/  Note that output of the f_readdir fnction is affected by this option. */
+
+
+
+/*---------------------------------------------------------------------------/
+/ Physical Drive Configurations
+/----------------------------------------------------------------------------*/
+
+#define _DRIVES        1
+/* Number of volumes (logical drives) to be used. */
+
+
+#define    _MAX_SS        1024        /* 512, 1024, 2048 or 4096 */
+/* Maximum sector size to be handled.
+/  Always set 512 for memory card and hard disk but a larger value may be
+/  required for floppy disk (512/1024) and optical disk (512/2048).
+/  When _MAX_SS is larger than 512, GET_SECTOR_SIZE command must be implememted
+/  to the disk_ioctl function. */
+
+
+#define    _MULTI_PARTITION    0    /* 0 or 1 */
+/* When _MULTI_PARTITION is set to 0, each volume is bound to the same physical
+/ drive number and can mount only first primaly partition. When it is set to 1,
+/ each volume is tied to the partitions listed in Drives[]. */
+
+
+
+/*---------------------------------------------------------------------------/
+/ System Configurations
+/----------------------------------------------------------------------------*/
+
+#define _WORD_ACCESS    0    /* 0 or 1 */
+/* The _WORD_ACCESS option defines which access method is used to the word
+/  data on the FAT volume.
+/
+/   0: Byte-by-byte access. Always compatible with all platforms.
+/   1: Word access. Do not choose this unless following condition is met.
+/
+/  When the byte order on the memory is big-endian or address miss-aligned
+/  word access results incorrect behavior, the _WORD_ACCESS must be set to 0.
+/  If it is not the case, the value can also be set to 1 to improve the
+/  performance and code size. */
+
+
+#define _FS_REENTRANT    0        /* 0 or 1 */
+#define _FS_TIMEOUT        1000    /* Timeout period in unit of time ticks */
+#define    _SYNC_t            HANDLE    /* O/S dependent type of sync object. e.g. HANDLE, OS_EVENT*, ID and etc.. */
+/* The _FS_REENTRANT option switches the reentrancy of the FatFs module.
+/
+/   0: Disable reentrancy. _SYNC_t and _FS_TIMEOUT have no effect.
+/   1: Enable reentrancy. Also user provided synchronization handlers,
+/      ff_req_grant, ff_rel_grant, ff_del_syncobj and ff_cre_syncobj
+/      function must be added to the project. */
+
+
+#endif /* _FFCONFIG */
diff -r 000000000000 -r 085749c8446f Code/chan_fat_fs/integer.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Code/chan_fat_fs/integer.h	Wed Jun 13 15:10:06 2012 +0000
@@ -0,0 +1,39 @@
+/*-------------------------------------------*/
+/* Integer type definitions for FatFs module */
+/*-------------------------------------------*/
+
+#ifndef _INTEGER
+
+#if 0
+#include <windows.h>
+#else
+
+/* These types must be 16-bit, 32-bit or larger integer */
+typedef int                INT;
+typedef unsigned int    UINT;
+
+/* These types must be 8-bit integer */
+
+#define CHAR  char
+//typedef signed char       CHAR;
+typedef unsigned char    UCHAR;
+typedef unsigned char    BYTE;
+
+/* These types must be 16-bit integer */
+typedef short            SHORT;
+typedef unsigned short    USHORT;
+typedef unsigned short    WORD;
+typedef unsigned short    WCHAR;
+
+/* These types must be 32-bit integer */
+typedef long             LONG;
+typedef unsigned long    ULONG;
+typedef unsigned long    DWORD;
+
+/* Boolean type */
+typedef enum { FALSE = 0, TRUE } BOOL;
+
+#endif
+
+#define _INTEGER
+#endif
diff -r 000000000000 -r 085749c8446f Code/chan_fat_fs/option/ccsbcs.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Code/chan_fat_fs/option/ccsbcs.c	Wed Jun 13 15:10:06 2012 +0000
@@ -0,0 +1,538 @@
+/* (SBCS code pages)                                                      */
+/*------------------------------------------------------------------------*/
+/*  437   U.S. (OEM)
+/   720   Arabic (OEM)
+/   1256  Arabic (Windows)
+/   737   Greek (OEM)
+/   1253  Greek (Windows)
+/   1250  Central Europe (Windows)
+/   775   Baltic (OEM)
+/   1257  Baltic (Windows)
+/   850   Multilingual Latin 1 (OEM)
+/   852   Latin 2 (OEM)
+/   1252  Latin 1 (Windows)
+/   855   Cyrillic (OEM)
+/   1251  Cyrillic (Windows)
+/   866   Russian (OEM)
+/   857   Turkish (OEM)
+/   1254  Turkish (Windows)
+/   858   Multilingual Latin 1 + Euro (OEM)
+/   862   Hebrew (OEM)
+/   1255  Hebrew (Windows)
+/   874   Thai (OEM, Windows)
+/   1258  Vietnam (OEM, Windows)
+*/
+
+#include "../ff.h"
+
+
+#if _CODE_PAGE == 437
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {    /*  CP437(0x80-0xFF) to Unicode conversion table */
+    0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7,
+    0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
+    0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9,
+    0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192,
+    0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA,
+    0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
+    0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
+    0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
+    0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
+    0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
+    0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
+    0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
+    0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4,
+    0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
+    0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248,
+    0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 720
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {    /*  CP720(0x80-0xFF) to Unicode conversion table */
+    0x0000, 0x0000, 0x00E9, 0x00E2, 0x0000, 0x00E0, 0x0000, 0x00E7,
+    0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0651, 0x0652, 0x00F4, 0x00A4, 0x0640, 0x00FB, 0x00F9,
+    0x0621, 0x0622, 0x0623, 0x0624, 0x00A3, 0x0625, 0x0626, 0x0627,
+    0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F,
+    0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x00AB, 0x00BB,
+    0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
+    0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
+    0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
+    0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
+    0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
+    0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
+    0x0636, 0x0637, 0x0638, 0x0639, 0x063A, 0x0641, 0x00B5, 0x0642,
+    0x0643, 0x0644, 0x0645, 0x0646, 0x0647, 0x0648, 0x0649, 0x064A,
+    0x2261, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F, 0xO650, 0x2248,
+    0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 737
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {    /*  CP737(0x80-0xFF) to Unicode conversion table */
+    0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398,
+    0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, 0x03A0,
+    0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9,
+    0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8,
+    0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0,
+    0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8,
+    0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
+    0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
+    0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
+    0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
+    0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
+    0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
+    0x03C9, 0x03AC, 0x03AD, 0x03AE, 0x03CA, 0x03AF, 0x03CC, 0x03CD,
+    0x03CB, 0x03CE, 0x0386, 0x0388, 0x0389, 0x038A, 0x038C, 0x038E,
+    0x038F, 0x00B1, 0x2265, 0x2264, 0x03AA, 0x03AB, 0x00F7, 0x2248,
+    0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 775
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {    /*  CP775(0x80-0xFF) to Unicode conversion table */
+    0x0106, 0x00FC, 0x00E9, 0x0101, 0x00E4, 0x0123, 0x00E5, 0x0107,
+    0x0142, 0x0113, 0x0156, 0x0157, 0x012B, 0x0179, 0x00C4, 0x00C5,
+    0x00C9, 0x00E6, 0x00C6, 0x014D, 0x00F6, 0x0122, 0x00A2, 0x015A,
+    0x015B, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x00A4,
+    0x0100, 0x012A, 0x00F3, 0x017B, 0x017C, 0x017A, 0x201D, 0x00A6,
+    0x00A9, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x0141, 0x00AB, 0x00BB,
+    0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0104, 0x010C, 0x0118,
+    0x0116, 0x2563, 0x2551, 0x2557, 0x255D, 0x012E, 0x0160, 0x2510,
+    0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0172, 0x016A,
+    0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x017D,
+    0x0105, 0x010D, 0x0119, 0x0117, 0x012F, 0x0161, 0x0173, 0x016B,
+    0x017E, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
+    0x00D3, 0x00DF, 0x014C, 0x0143, 0x00F5, 0x00D5, 0x00B5, 0x0144,
+    0x0136, 0x0137, 0x013B, 0x013C, 0x0146, 0x0112, 0x0145, 0x2019,
+    0x00AD, 0x00B1, 0x201C, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x201E,
+    0x00B0, 0x2219, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 850
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {    /*  CP850(0x80-0xFF) to Unicode conversion table */
+    0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7,
+    0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
+    0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9,
+    0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192,
+    0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA,
+    0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
+    0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0,
+    0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510,
+    0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3,
+    0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
+    0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x0131, 0x00CD, 0x00CE,
+    0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580,
+    0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE,
+    0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4,
+    0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8,
+    0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 852
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {    /*  CP852(0x80-0xFF) to Unicode conversion table */
+    0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x016F, 0x0107, 0x00E7,
+    0x0142, 0x00EB, 0x0150, 0x0151, 0x00EE, 0x0179, 0x00C4, 0x0106,
+    0x00C9, 0x0139, 0x013A, 0x00F4, 0x00F6, 0x013D, 0x013E, 0x015A,
+    0x015B, 0x00D6, 0x00DC, 0x0164, 0x0165, 0x0141, 0x00D7, 0x010D,
+    0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x0104, 0x0105, 0x017D, 0x017E,
+    0x0118, 0x0119, 0x00AC, 0x017A, 0x010C, 0x015F, 0x00AB, 0x00BB,
+    0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x011A,
+    0x015E, 0x2563, 0x2551, 0x2557, 0x255D, 0x017B, 0x017C, 0x2510,
+    0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0102, 0x0103,
+    0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
+    0x0111, 0x0110, 0x010E, 0x00CB, 0x010F, 0x0147, 0x00CD, 0x00CE,
+    0x011B, 0x2518, 0x250C, 0x2588, 0x2584, 0x0162, 0x016E, 0x2580,
+    0x00D3, 0x00DF, 0x00D4, 0x0143, 0x0144, 0x0148, 0x0160, 0x0161,
+    0x0154, 0x00DA, 0x0155, 0x0170, 0x00FD, 0x00DD, 0x0163, 0x00B4,
+    0x00AD, 0x02DD, 0x02DB, 0x02C7, 0x02D8, 0x00A7, 0x00F7, 0x00B8,
+    0x00B0, 0x00A8, 0x02D9, 0x0171, 0x0158, 0x0159, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 855
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {    /*  CP855(0x80-0xFF) to Unicode conversion table */
+    0x0452, 0x0402, 0x0453, 0x0403, 0x0451, 0x0401, 0x0454, 0x0404,
+    0x0455, 0x0405, 0x0456, 0x0406, 0x0457, 0x0407, 0x0458, 0x0408,
+    0x0459, 0x0409, 0x045A, 0x040A, 0x045B, 0x040B, 0x045C, 0x040C,
+    0x045E, 0x040E, 0x045F, 0x040F, 0x044E, 0x042E, 0x044A, 0x042A,
+    0x0430, 0x0410, 0x0431, 0x0411, 0x0446, 0x0426, 0x0434, 0x0414,
+    0x0435, 0x0415, 0x0444, 0x0424, 0x0433, 0x0413, 0x00AB, 0x00BB,
+    0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0445, 0x0425, 0x0438,
+    0x0418, 0x2563, 0x2551, 0x2557, 0x255D, 0x0439, 0x0419, 0x2510,
+    0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x043A, 0x041A,
+    0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
+    0x043B, 0x041B, 0x043C, 0x041C, 0x043D, 0x041D, 0x043E, 0x041E,
+    0x043F, 0x2518, 0x250C, 0x2588, 0x2584, 0x041F, 0x044F, 0x2580,
+    0x042F, 0x0440, 0x0420, 0x0441, 0x0421, 0x0442, 0x0422, 0x0443,
+    0x0423, 0x0436, 0x0416, 0x0432, 0x0412, 0x044C, 0x042C, 0x2116,
+    0x00AD, 0x044B, 0x042B, 0x0437, 0x0417, 0x0448, 0x0428, 0x044D,
+    0x042D, 0x0449, 0x0429, 0x0447, 0x0427, 0x00A7, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 857
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {    /*  CP857(0x80-0xFF) to Unicode conversion table */
+    0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7,
+    0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0131, 0x00C4, 0x00C5,
+    0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9,
+    0x0130, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x015E, 0x015F,
+    0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x011E, 0x011F,
+    0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
+    0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0,
+    0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510,
+    0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3,
+    0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
+    0x00BA, 0x00AA, 0x00CA, 0x00CB, 0x00C8, 0x0000, 0x00CD, 0x00CE,
+    0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580,
+    0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x0000,
+    0x00D7, 0x00DA, 0x00DB, 0x00D9, 0x00EC, 0x00FF, 0x00AF, 0x00B4,
+    0x00AD, 0x00B1, 0x0000, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8,
+    0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 858
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {    /*  CP858(0x80-0xFF) to Unicode conversion table */
+    0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7,
+    0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
+    0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9,
+    0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192,
+    0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA,
+    0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
+    0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0,
+    0x00A9, 0x2563, 0x2551, 0x2557, 0x2550, 0x00A2, 0x00A5, 0x2510,
+    0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3,
+    0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
+    0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x20AC, 0x00CD, 0x00CE,
+    0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00C6, 0x00CC, 0x2580,
+    0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE,
+    0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4,
+    0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8,
+    0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 862
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {    /*  CP862(0x80-0xFF) to Unicode conversion table */
+    0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7,
+    0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
+    0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7,
+    0x05E8, 0x05E9, 0x05EA, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192,
+    0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA,
+    0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
+    0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
+    0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
+    0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
+    0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
+    0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
+    0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
+    0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4,
+    0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
+    0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248,
+    0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 866
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {    /*  CP866(0x80-0xFF) to Unicode conversion table */
+    0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,
+    0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
+    0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427,
+    0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
+    0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
+    0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
+    0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
+    0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
+    0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
+    0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
+    0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
+    0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
+    0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
+    0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
+    0x0401, 0x0451, 0x0404, 0x0454, 0x0407, 0x0457, 0x040E, 0x045E,
+    0x00B0, 0x2219, 0x00B7, 0x221A, 0x2116, 0x00A4, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 874
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {    /*  CP874(0x80-0xFF) to Unicode conversion table */
+    0x20AC, 0x0000, 0x0000, 0x0000, 0x0000, 0x2026, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x00A0, 0x0E01, 0x0E02, 0x0E03, 0x0E04, 0x0E05, 0x0E06, 0x0E07,
+    0x0E08, 0x0E09, 0x0E0A, 0x0E0B, 0x0E0C, 0x0E0D, 0x0E0E, 0x0E0F,
+    0x0E10, 0x0E11, 0x0E12, 0x0E13, 0x0E14, 0x0E15, 0x0E16, 0x0E17,
+    0x0E18, 0x0E19, 0x0E1A, 0x0E1B, 0x0E1C, 0x0E1D, 0x0E1E, 0x0E1F,
+    0x0E20, 0x0E21, 0x0E22, 0x0E23, 0x0E24, 0x0E25, 0x0E26, 0x0E27,
+    0x0E28, 0x0E29, 0x0E2A, 0x0E2B, 0x0E2C, 0x0E2D, 0x0E2E, 0x0E2F,
+    0x0E30, 0x0E31, 0x0E32, 0x0E33, 0x0E34, 0x0E35, 0x0E36, 0x0E37,
+    0x0E38, 0x0E39, 0x0E3A, 0x0000, 0x0000, 0x0000, 0x0000, 0x0E3F,
+    0x0E40, 0x0E41, 0x0E42, 0x0E43, 0x0E44, 0x0E45, 0x0E46, 0x0E47,
+    0x0E48, 0x0E49, 0x0E4A, 0x0E4B, 0x0E4C, 0x0E4D, 0x0E4E, 0x0E4F,
+    0x0E50, 0x0E51, 0x0E52, 0x0E53, 0x0E54, 0x0E55, 0x0E56, 0x0E57,
+    0x0E58, 0x0E59, 0x0E5A, 0x0E5B, 0x0000, 0x0000, 0x0000, 0x0000
+};
+
+#elif _CODE_PAGE == 1250
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {    /*  CP1250(0x80-0xFF) to Unicode conversion table */
+    0x20AC, 0x0000, 0x201A, 0x0000, 0x201E, 0x2026, 0x2020, 0x2021,
+    0x0000, 0x2030, 0x0160, 0x2039, 0x015A, 0x0164, 0x017D, 0x0179,
+    0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+    0x0000, 0x2122, 0x0161, 0x203A, 0x015B, 0x0165, 0x017E, 0x017A,
+    0x00A0, 0x02C7, 0x02D8, 0x0141, 0x00A4, 0x0104, 0x00A6, 0x00A7,
+    0x00A8, 0x00A9, 0x015E, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x017B,
+    0x00B0, 0x00B1, 0x02DB, 0x0142, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+    0x00B8, 0x0105, 0x015F, 0x00BB, 0x013D, 0x02DD, 0x013E, 0x017C,
+    0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7,
+    0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E,
+    0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7,
+    0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF,
+    0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7,
+    0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B, 0x00ED, 0x00EE, 0x010F,
+    0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x00F7,
+    0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, 0x0163, 0x02D9
+};
+
+#elif _CODE_PAGE == 1251
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {    /*  CP1251(0x80-0xFF) to Unicode conversion table */
+    0x0402, 0x0403, 0x201A, 0x0453, 0x201E, 0x2026, 0x2020, 0x2021,
+    0x20AC, 0x2030, 0x0409, 0x2039, 0x040A, 0x040C, 0x040B, 0x040F,
+    0x0452, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+    0x0000, 0x2111, 0x0459, 0x203A, 0x045A, 0x045C, 0x045B, 0x045F,
+    0x00A0, 0x040E, 0x045E, 0x0408, 0x00A4, 0x0490, 0x00A6, 0x00A7,
+    0x0401, 0x00A9, 0x0404, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x0407,
+    0x00B0, 0x00B1, 0x0406, 0x0456, 0x0491, 0x00B5, 0x00B6, 0x00B7,
+    0x0451, 0x2116, 0x0454, 0x00BB, 0x0458, 0x0405, 0x0455, 0x0457,
+    0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,
+    0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
+    0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427,
+    0x0428, 0x0429, 0x042A, 0x042D, 0x042C, 0x042D, 0x042E, 0x042F,
+    0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
+    0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
+    0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
+    0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F
+};
+
+#elif _CODE_PAGE == 1252
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {    /*  CP1252(0x80-0xFF) to Unicode conversion table */
+    0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
+    0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0x0000, 0x017D, 0x0000,
+    0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+    0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0x0000, 0x017E, 0x0178,
+    0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+    0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+    0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+    0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
+    0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
+    0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
+    0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
+    0x00D8, 0x00D9, 0x00DA, 0x00BD, 0x00DC, 0x00DD, 0x00DE, 0x00DF,
+    0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
+    0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
+    0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7,
+    0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF
+};
+
+#elif _CODE_PAGE == 1253
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {    /*  CP1253(0x80-0xFF) to Unicode conversion table */
+    0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
+    0x0000, 0x2030, 0x0000, 0x2039, 0x000C, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+    0x0000, 0x2122, 0x0000, 0x203A, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x00A0, 0x0385, 0x0386, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+    0x00A8, 0x00A9, 0x0000, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x2015,
+    0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x0384, 0x00B5, 0x00B6, 0x00B7,
+    0x0388, 0x0389, 0x038A, 0x00BB, 0x038C, 0x00BD, 0x038E, 0x038F,
+    0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397,
+    0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F,
+    0x03A0, 0x03A1, 0x0000, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7,
+    0x03A8, 0x03A9, 0x03AA, 0x03AD, 0x03AC, 0x03AD, 0x03AE, 0x03AF,
+    0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7,
+    0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
+    0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7,
+    0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0x0000
+};
+
+#elif _CODE_PAGE == 1254
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {    /*  CP1254(0x80-0xFF) to Unicode conversion table */
+    0x20AC, 0x0000, 0x210A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
+    0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+    0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0x0000, 0x0000, 0x0178,
+    0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+    0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+    0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+    0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
+    0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
+    0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
+    0x011E, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
+    0x00D8, 0x00D9, 0x00DA, 0x00BD, 0x00DC, 0x0130, 0x015E, 0x00DF,
+    0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
+    0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
+    0x011F, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7,
+    0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0131, 0x015F, 0x00FF
+};
+
+#elif _CODE_PAGE == 1255
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {    /*  CP1255(0x80-0xFF) to Unicode conversion table */
+    0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
+    0x02C6, 0x2030, 0x0000, 0x2039, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+    0x02DC, 0x2122, 0x0000, 0x203A, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+    0x00A8, 0x00A9, 0x00D7, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+    0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+    0x00B8, 0x00B9, 0x00F7, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
+    0x05B0, 0x05B1, 0x05B2, 0x05B3, 0x05B4, 0x05B5, 0x05B6, 0x05B7,
+    0x05B8, 0x05B9, 0x0000, 0x05BB, 0x05BC, 0x05BD, 0x05BE, 0x05BF,
+    0x05C0, 0x05C1, 0x05C2, 0x05C3, 0x05F0, 0x05F1, 0x05F2, 0x05F3,
+    0x05F4, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7,
+    0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
+    0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7,
+    0x05E8, 0x05E9, 0x05EA, 0x0000, 0x0000, 0x200E, 0x200F, 0x0000
+};
+
+#elif _CODE_PAGE == 1256
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {    /*  CP1256(0x80-0xFF) to Unicode conversion table */
+    0x20AC, 0x067E, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
+    0x02C6, 0x2030, 0x0679, 0x2039, 0x0152, 0x0686, 0x0698, 0x0688,
+    0x06AF, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+    0x06A9, 0x2122, 0x0691, 0x203A, 0x0153, 0x200C, 0x200D, 0x06BA,
+    0x00A0, 0x060C, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+    0x00A8, 0x00A9, 0x06BE, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+    0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+    0x00B8, 0x00B9, 0x061B, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x061F,
+    0x06C1, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627,
+    0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F,
+    0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x00D7,
+    0x0637, 0x0638, 0x0639, 0x063A, 0x0640, 0x0640, 0x0642, 0x0643,
+    0x00E0, 0x0644, 0x00E2, 0x0645, 0x0646, 0x0647, 0x0648, 0x00E7,
+    0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x0649, 0x064A, 0x00EE, 0x00EF,
+    0x064B, 0x064C, 0x064D, 0x064E, 0x00F4, 0x064F, 0x0650, 0x00F7,
+    0x0651, 0x00F9, 0x0652, 0x00FB, 0x00FC, 0x200E, 0x200F, 0x06D2
+}
+
+#elif _CODE_PAGE == 1257
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {    /*  CP1257(0x80-0xFF) to Unicode conversion table */
+    0x20AC, 0x0000, 0x201A, 0x0000, 0x201E, 0x2026, 0x2020, 0x2021,
+    0x0000, 0x2030, 0x0000, 0x2039, 0x0000, 0x00A8, 0x02C7, 0x00B8,
+    0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+    0x0000, 0x2122, 0x0000, 0x203A, 0x0000, 0x00AF, 0x02DB, 0x0000,
+    0x00A0, 0x0000, 0x00A2, 0x00A3, 0x00A4, 0x0000, 0x00A6, 0x00A7,
+    0x00D8, 0x00A9, 0x0156, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+    0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+    0x00B8, 0x00B9, 0x0157, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00E6,
+    0x0104, 0x012E, 0x0100, 0x0106, 0x00C4, 0x00C5, 0x0118, 0x0112,
+    0x010C, 0x00C9, 0x0179, 0x0116, 0x0122, 0x0136, 0x012A, 0x013B,
+    0x0160, 0x0143, 0x0145, 0x00D3, 0x014C, 0x00D5, 0x00D6, 0x00D7,
+    0x0172, 0x0141, 0x015A, 0x016A, 0x00DC, 0x017B, 0x017D, 0x00DF,
+    0x0105, 0x012F, 0x0101, 0x0107, 0x00E4, 0x00E5, 0x0119, 0x0113,
+    0x010D, 0x00E9, 0x017A, 0x0117, 0x0123, 0x0137, 0x012B, 0x013C,
+    0x0161, 0x0144, 0x0146, 0x00F3, 0x014D, 0x00F5, 0x00F6, 0x00F7,
+    0x0173, 0x014E, 0x015B, 0x016B, 0x00FC, 0x017C, 0x017E, 0x02D9
+};
+
+#elif _CODE_PAGE == 1258
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {    /*  CP1258(0x80-0xFF) to Unicode conversion table */
+    0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
+    0x02C6, 0x2030, 0x0000, 0x2039, 0x0152, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+    0x02DC, 0x2122, 0x0000, 0x203A, 0x0153, 0x0000, 0x0000, 0x0178,
+    0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+    0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+    0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+    0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
+    0x00C0, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
+    0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x0300, 0x00CD, 0x00CE, 0x00CF,
+    0x0110, 0x00D1, 0x0309, 0x00D3, 0x00D4, 0x01A0, 0x00D6, 0x00D7,
+    0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x01AF, 0x0303, 0x00DF,
+    0x00E0, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
+    0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x0301, 0x00ED, 0x00EE, 0x00EF,
+    0x0111, 0x00F1, 0x0323, 0x00F3, 0x00F4, 0x01A1, 0x00F6, 0x00F7,
+    0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x01B0, 0x20AB, 0x00FF
+};
+
+#endif
+
+
+#if !_TBLDEF || !_USE_LFN
+#error This file is not needed in current configuration
+#endif
+
+
+WCHAR ff_convert (    /* Converted character, Returns zero on error */
+    WCHAR    src,    /* Character code to be converted */
+    UINT    dir        /* 0: Unicode to OEMCP, 1: OEMCP to Unicode */
+)
+{
+    WCHAR c;
+
+
+    if (src < 0x80) {    /* ASCII */
+        c = src;
+
+    } else {
+        if (dir) {        /* OEMCP to Unicode */
+            c = (src >= 0x100) ? 0 : Tbl[src - 0x80];
+
+        } else {        /* Unicode to OEMCP */
+            for (c = 0; c < 0x80; c++) {
+                if (src == Tbl[c]) break;
+            }
+            c = (c + 0x80) & 0xFF;
+        }
+    }
+
+    return c;
+}
+
+
+WCHAR ff_wtoupper (    /* Upper converted character */
+    WCHAR chr        /* Input character */
+)
+{
+    static const WCHAR tbl_lower[] = { 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0xA1, 0x00A2, 0x00A3, 0x00A5, 0x00AC, 0x00AF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0x0FF, 0x101, 0x103, 0x105, 0x107, 0x109, 0x10B, 0x10D, 0x10F, 0x111, 0x113, 0x115, 0x117, 0x119, 0x11B, 0x11D, 0x11F, 0x121, 0x123, 0x125, 0x127, 0x129, 0x12B, 0x12D, 0x12F, 0x131, 0x133, 0x135, 0x137, 0x13A, 0x13C, 0x13E, 0x140, 0x142, 0x144, 0x146, 0x148, 0x14B, 0x14D, 0x14F, 0x151, 0x153, 0x155, 0x157, 0x159, 0x15B, 0x15D, 0x15F, 0x161, 0x163, 0x165, 0x167, 0x169, 0x16B, 0x16D, 0x16F, 0x171, 0x173, 0x175, 0x177, 0x17A, 0x17C, 0x17E, 0x192, 0x3B1, 0x3B2, 0x3B3, 0x3B4, 0x3B5, 0x3B6, 0x3B7, 0x3B8, 0x3B9, 0x3BA, 0x3BB, 0x3BC, 0x3BD, 0x3BE, 0x3BF, 0x3C0, 0x3C1, 0x3C3, 0x3C4, 0x3C5, 0x3C6, 0x3C7, 0x3C8, 0x3C9, 0x3CA, 0x430, 0x431, 0x432, 0x433, 0x434, 0x435, 0x436, 0x437, 0x438, 0x439, 0x43A, 0x43B, 0x43C, 0x43D, 0x43E, 0x43F, 0x440, 0x441, 0x442, 0x443, 0x444, 0x445, 0x446, 0x447, 0x448, 0x449, 0x44A, 0x44B, 0x44C, 0x44D, 0x44E, 0x44F, 0x451, 0x452, 0x453, 0x454, 0x455, 0x456, 0x457, 0x458, 0x459, 0x45A, 0x45B, 0x45C, 0x45E, 0x45F, 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177, 0x2178, 0x2179, 0x217A, 0x217B, 0x217C, 0x217D, 0x217E, 0x217F, 0xFF41, 0xFF42, 0xFF43, 0xFF44, 0xFF45, 0xFF46, 0xFF47, 0xFF48, 0xFF49, 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D, 0xFF4E, 0xFF4F, 0xFF50, 0xFF51, 0xFF52, 0xFF53, 0xFF54, 0xFF55, 0xFF56, 0xFF57, 0xFF58, 0xFF59, 0xFF5A, 0 };
+    static const WCHAR tbl_upper[] = { 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x21, 0xFFE0, 0xFFE1, 0xFFE5, 0xFFE2, 0xFFE3, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0x178, 0x100, 0x102, 0x104, 0x106, 0x108, 0x10A, 0x10C, 0x10E, 0x110, 0x112, 0x114, 0x116, 0x118, 0x11A, 0x11C, 0x11E, 0x120, 0x122, 0x124, 0x126, 0x128, 0x12A, 0x12C, 0x12E, 0x130, 0x132, 0x134, 0x136, 0x139, 0x13B, 0x13D, 0x13F, 0x141, 0x143, 0x145, 0x147, 0x14A, 0x14C, 0x14E, 0x150, 0x152, 0x154, 0x156, 0x158, 0x15A, 0x15C, 0x15E, 0x160, 0x162, 0x164, 0x166, 0x168, 0x16A, 0x16C, 0x16E, 0x170, 0x172, 0x174, 0x176, 0x179, 0x17B, 0x17D, 0x191, 0x391, 0x392, 0x393, 0x394, 0x395, 0x396, 0x397, 0x398, 0x399, 0x39A, 0x39B, 0x39C, 0x39D, 0x39E, 0x39F, 0x3A0, 0x3A1, 0x3A3, 0x3A4, 0x3A5, 0x3A6, 0x3A7, 0x3A8, 0x3A9, 0x3AA, 0x410, 0x411, 0x412, 0x413, 0x414, 0x415, 0x416, 0x417, 0x418, 0x419, 0x41A, 0x41B, 0x41C, 0x41D, 0x41E, 0x41F, 0x420, 0x421, 0x422, 0x423, 0x424, 0x425, 0x426, 0x427, 0x428, 0x429, 0x42A, 0x42B, 0x42C, 0x42D, 0x42E, 0x42F, 0x401, 0x402, 0x403, 0x404, 0x405, 0x406, 0x407, 0x408, 0x409, 0x40A, 0x40B, 0x40C, 0x40E, 0x40F, 0x2160, 0x2161, 0x2162, 0x2163, 0x2164, 0x2165, 0x2166, 0x2167, 0x2168, 0x2169, 0x216A, 0x216B, 0x216C, 0x216D, 0x216E, 0x216F, 0xFF21, 0xFF22, 0xFF23, 0xFF24, 0xFF25, 0xFF26, 0xFF27, 0xFF28, 0xFF29, 0xFF2A, 0xFF2B, 0xFF2C, 0xFF2D, 0xFF2E, 0xFF2F, 0xFF30, 0xFF31, 0xFF32, 0xFF33, 0xFF34, 0xFF35, 0xFF36, 0xFF37, 0xFF38, 0xFF39, 0xFF3A, 0 };
+    int i;
+
+
+    for (i = 0; tbl_lower[i] && chr != tbl_lower[i]; i++) ;
+
+    return tbl_lower[i] ? tbl_upper[i] : chr;
+}
diff -r 000000000000 -r 085749c8446f Code/integer.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Code/integer.h	Wed Jun 13 15:10:06 2012 +0000
@@ -0,0 +1,39 @@
+/*-------------------------------------------*/
+/* Integer type definitions for FatFs module */
+/*-------------------------------------------*/
+
+#ifndef _INTEGER
+
+#if 0
+#include <windows.h>
+#else
+
+/* These types must be 16-bit, 32-bit or larger integer */
+typedef int                INT;
+typedef unsigned int    UINT;
+
+/* These types must be 8-bit integer */
+
+#define CHAR  char
+//typedef signed char       CHAR;
+typedef unsigned char    UCHAR;
+typedef unsigned char    BYTE;
+
+/* These types must be 16-bit integer */
+typedef short            SHORT;
+typedef unsigned short    USHORT;
+typedef unsigned short    WORD;
+typedef unsigned short    WCHAR;
+
+/* These types must be 32-bit integer */
+typedef long             LONG;
+typedef unsigned long    ULONG;
+typedef unsigned long    DWORD;
+
+/* Boolean type */
+typedef enum { FALSE = 0, TRUE } BOOL;
+
+#endif
+
+#define _INTEGER
+#endif
diff -r 000000000000 -r 085749c8446f DataTypes.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DataTypes.h	Wed Jun 13 15:10:06 2012 +0000
@@ -0,0 +1,139 @@
+#include <stdio.h>
+#include <stdarg.h>
+#include "ff.h"
+
+#define INLINE_BITPLANE_PUT
+#define INLINE_BITPLANE_GET
+
+#ifndef DATATYPES_H_
+#define DATATYPES_H_
+
+//#define BYTE unsigned char
+#define WORD unsigned short
+#define DWORD unsigned long
+
+#define SIGNED_BYTE signed char
+#define SIGNED_WORD signed short
+#define SIGNED_DWORD signed int
+
+//#define CHAR char
+
+#define BOOL BYTE
+
+#ifndef TRUE
+#define TRUE 1
+#endif  
+
+
+#ifndef FALSE
+#define FALSE 0
+#endif  
+
+#ifndef YEP
+#define YEP TRUE
+#endif  
+
+
+#ifndef NOPE
+#define NOPE FALSE
+#endif  
+
+
+#define STACK_FULL       -1
+#define STACK_EMPTY      -2
+#define STACK_PUSH_OK     0
+
+#define QUEUE_FULL       -1
+#define QUEUE_EMPTY      -2
+#define QUEUE_OK          0
+
+
+typedef struct{
+
+            BYTE *StackSpace;
+            WORD Ptr;
+            WORD Size;
+}    ByteStack;
+
+typedef struct{
+            BYTE *StackSpace;
+            BYTE Ptr;
+            BYTE Size;
+} BitStack;
+
+typedef struct {
+                
+         BYTE *BitPlaneSpace;
+
+        WORD SizeX; // must be a BYTE aligned
+        WORD SizeY;
+        
+} BitPlane;
+
+
+typedef struct {
+    
+    WORD ReadPtr;
+    WORD WritePtr;
+    WORD QueueSize;
+    BYTE *QueueStorage;
+    
+} ByteQueue;
+
+
+
+#ifdef INLINE_BITPLANE_PUT
+    inline void BitPlane_Put(BitPlane  * BP, WORD X,WORD Y, BOOL Value)
+    {
+        WORD Offset;
+        BYTE Mask;
+        
+        Offset = (Y * ((BP->SizeX)>>3)) + (X>>3);
+        Mask = 0x01 << (X & 0x07);
+    
+        if(Value)
+        {
+            BP->BitPlaneSpace[Offset] |= Mask;
+        }
+        else
+        {
+            BP->BitPlaneSpace[Offset] &= ~Mask;
+        }
+    }
+#else
+    void BitPlane_Put(BitPlane  * BP, WORD X,WORD Y, BOOL Value);
+#endif
+
+#ifdef INLINE_BITPLANE_GET
+    inline BOOL BitPlane_Get(BitPlane  * BP, WORD X,WORD Y)
+    {
+        WORD Offset;
+        BYTE Mask;
+     
+        Offset = (Y * ((BP->SizeX)>>3)) + (X>>3);
+        Mask = 0x01 << (X & 0x07);
+    
+        if((BP->BitPlaneSpace[Offset])&Mask)
+        {
+            return TRUE;
+        }
+        else
+        {
+            return FALSE;
+        }
+    }
+#else
+    BOOL BitPlane_Get(BitPlane  * BP, WORD X,WORD Y);
+#endif
+
+
+void BitPlane_Clear(BitPlane  * BP);
+
+void InitByteQueue(ByteQueue *BQ,WORD Size,BYTE * Storage);
+WORD BytesInQueue(ByteQueue *BQ);
+SIGNED_WORD ByteDequeue(ByteQueue *BQ,BYTE *Val);
+SIGNED_WORD ByteEnqueue(ByteQueue *BQ,BYTE Val);
+SIGNED_WORD ByteArrayEnqueue(ByteQueue *BQ,BYTE *Buf,WORD Len);
+SIGNED_WORD PrintfEnqueue(ByteQueue *BQ, const char *FormatString,...);
+
+#endif /*DATATYPES_H_*/
\ No newline at end of file
diff -r 000000000000 -r 085749c8446f Headers/ADC.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Headers/ADC.h	Wed Jun 13 15:10:06 2012 +0000
@@ -0,0 +1,17 @@
+#ifndef _ADC_H_
+#define _ADC_H_
+
+extern volatile float BatteryVoltage;
+extern volatile float RobotBusVoltageHR;
+extern volatile float RobotBusCurrentHR;
+extern volatile BOOL ADCDataRdy;
+
+
+void InitADC();
+
+
+#define MIN_SAMPLE_RATE     1.0f
+#define MAX_SAMPLE_RATE     1000.0f
+
+
+#endif
\ No newline at end of file
diff -r 000000000000 -r 085749c8446f Headers/Configuration.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Headers/Configuration.h	Wed Jun 13 15:10:06 2012 +0000
@@ -0,0 +1,58 @@
+#include "DataTypes.h"
+
+#ifndef _CONFIGURATION_H_
+#define _CONFIGURATION_H_
+
+void LoadDefaults();
+void LoadConfiguration();
+BOOL KeyValueSplit(const CHAR *LineBuf,CHAR Key,CHAR *Value);
+void ToLowerCase(CHAR *LineBuf);
+void ExportConfigurationSettings();
+
+//Voltage Divider for the Li_poly Battery
+extern float R17,R15;
+
+//Voltage Divider for input voltage measurement
+extern float R2,R4;
+
+//Voltage Divider for current voltage measurement (to the 16-bit ADC)
+extern float R6,R7;
+
+//Voltage Divider for current voltage measurement (to the 12-bit ADC)
+extern float R8,R9;
+
+//value of the 2.5Voltage reference
+extern float U1_VREF;
+//value of the MBED Voltage reference
+extern float MBED_VREF;
+
+//Input diode drops
+extern float INPUT_DIODE_DROP;
+
+
+//Parameters for the ACS576 Current Sensor
+extern float ACS576_VOFFSET;
+extern float ACS576_ISCALE; 
+extern float ACS576_IOFFSET_TRIM; 
+extern float ACS576_ISCALE_ADJUST; 
+
+//for self current measurement
+extern float R18;
+extern float R19;
+extern float R20;
+extern float R22;
+
+extern  float   SAMPLE_RATE;
+extern  DWORD   WRITE_BLOCK_THRESH;
+
+#define SAMPLE_RATE_DEFAULT                  (250.0)
+#define WRITE_BLOCK_THRESH_DEFAULT           (128)
+
+#define MAX_ID_LENGTH   8
+extern CHAR ID[MAX_ID_LENGTH+1];
+
+//Used to correct the input voltage measurement
+extern float  VSCALE_ADJUST; 
+extern float  VOFFSET_ADJUST; 
+
+#endif
diff -r 000000000000 -r 085749c8446f Headers/FIRMWARE_VERSION.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Headers/FIRMWARE_VERSION.h	Wed Jun 13 15:10:06 2012 +0000
@@ -0,0 +1,7 @@
+#ifndef FIRMWARE_VERSION_H
+#define FIRMWARE_VERSION_H
+
+#define FIRMWARE_VERSION_MAJOR  (1)
+#define FIRMWARE_VERSION_MINOR  (0)
+
+#endif
diff -r 000000000000 -r 085749c8446f Headers/FixedMath.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Headers/FixedMath.h	Wed Jun 13 15:10:06 2012 +0000
@@ -0,0 +1,63 @@
+#include "DataTypes.h"
+
+#ifndef FIXEDMATH_H_
+#define FIXEDMATH_H_
+
+
+typedef SIGNED_WORD FIXED_7_8;
+typedef SIGNED_WORD FIXED_9_6;
+
+typedef SIGNED_WORD FIXED_0_15;
+typedef SIGNED_WORD FIXED_1_14;
+
+
+extern const FIXED_1_14 Fixed_1_14_SineTable [256];
+extern const FIXED_7_8 Fixed_7_8_SineTable [256];
+
+#define FMul_15_0(A,B)             (FIXED_0_15)(((FIXED_0_15)(A) * (FIXED_0_15 )(B))>>15)
+#define FMul_7_8to0_15(A,B)        (FIXED_7_8)(((FIXED_7_8)(A) * (FIXED_0_15)(B))>>15)
+#define FMul_15_0to7_8(A,B)        (SIGNED_WORD)(((SIGNED_WORD)(A) * (FIXED_7_8)(B))>>8)
+
+
+
+#define INT_7_8(A)                (SIGNED_WORD)(A>>8)
+#define INT_TO_7_8(A)            ((FIXED_7_8)(A)<<8)
+#define FRAC_7_8(A)                (FIXED_7_8)(A&0xFF)
+
+#define INT_9_6(A)                (SIGNED_WORD)(A>>6)
+#define INT_TO_9_6(A)            ((FIXED_9_6)(A)<<6)
+#define FRAC_6_9(A)                (FIXED_9_6)(A&0x3F)
+
+
+
+//#define FMul_15_0to0_15            (SIGNED_WORD)(((SIGNED_WORD)(A) * (FIXED_0_15)(B))>>16)
+inline SIGNED_WORD FMul_15_0to0_15(SIGNED_WORD A,SIGNED_WORD B)
+{
+    return  (((long)(A) * (long)(B))>>15);
+}
+
+inline SIGNED_WORD FMul_15_0to1_14(SIGNED_WORD A,SIGNED_WORD B)
+{
+    long temp;
+    temp = (((long)(A) * (long)(B))>>13);
+    if(temp&0x01)
+    {
+        temp = temp>>1;
+        temp = temp +1;
+    }
+    else
+    {
+        temp = temp>>1;
+    }
+    return  temp;
+}
+
+//inline SIGNED_WORD ABS(A)
+//{
+    //if(A<0)
+        //return -A;
+    //else
+        //return A;    
+//}
+
+#endif /*FIXEDMATH_H_*/
diff -r 000000000000 -r 085749c8446f Headers/GFX.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Headers/GFX.h	Wed Jun 13 15:10:06 2012 +0000
@@ -0,0 +1,143 @@
+#include "DataTypes.h"
+#include "FixedMath.h"
+
+#define _INLINE_GFX_GET_PIXEL
+#define _INLINE_GFX_PUT_PIXEL
+
+
+#ifndef _GFX_H
+#define _GFX_H
+
+
+
+typedef struct 
+{
+    SIGNED_WORD X;
+    SIGNED_WORD Y;    
+} GFXDisplayPoint;
+
+
+typedef struct 
+{
+    BitPlane RenderPlane;
+    WORD SizeX;
+    WORD SizeY;
+    
+} RenderContext;
+
+
+typedef struct 
+{
+    GFXDisplayPoint P1;
+    GFXDisplayPoint P2;    
+} GFXDisplayBox;
+
+
+typedef struct 
+{
+    BYTE FontWidth;
+    BYTE FontHeight;
+    BYTE BytesPerColumn;
+    BYTE *FontBuffer;    
+    BYTE *CharacterWidthTable;
+
+} GFXFont;
+
+typedef struct
+    {
+        SIGNED_WORD X;
+        SIGNED_WORD Y;
+    } GFXRelativePoint;
+
+typedef struct 
+    {
+            GFXDisplayPoint Center;
+            BYTE NumPoints;
+            BYTE DrawMode;
+            GFXRelativePoint *PointList;
+    } GFXListPrimitive;
+
+
+#define GFX_LIST_PRIMITIVE_CONNECTED        0x01
+#define GFX_LIST_PRIMITIVE_DISCONNECTED        0x02
+#define GFX_LIST_PRIMITIVE_CLOSED            0x03
+
+#define GFX_LIST_PRIMITIVE_CONNECTED_YFLIPPED            0x04
+#define GFX_LIST_PRIMITIVE_DISCONNECTED_YFLIPPED        0x05
+#define GFX_LIST_PRIMITIVE_CLOSED_YFLIPPED                0x06
+
+#define BICOLOR_BLACK    0
+#define BICOLOR_RED        0x1    
+#define BICOLOR_GREEN    0x2
+#define BICOLOR_YELLOW    0x3
+
+#define GFX_MAX_STRING_LEN 32
+
+//System/Hardware specific stuff
+void GFX_InitPhysicalScreen();
+void GFX_DumpRenderContextToPhysicalScreen(RenderContext *Image);
+void GFX_Init();
+void GFX_PowerUpScreen();
+void GFX_PowerDownScreen();
+
+//Device indepedent Functions
+void GFX_FullDisplayBufferClear(RenderContext *Image);
+void GFX_PutPixel(RenderContext *Image, SIGNED_WORD x, SIGNED_WORD y);
+void GFX_DrawHline(RenderContext *Image, SIGNED_WORD XStart, SIGNED_WORD XStop, SIGNED_WORD Y);
+void GFX_DrawVline(RenderContext *Image, SIGNED_WORD YStart, SIGNED_WORD YStop, SIGNED_WORD X);
+void GFX_DrawLine(RenderContext *Image, SIGNED_WORD X1,SIGNED_WORD Y1, SIGNED_WORD X2,SIGNED_WORD Y2);
+void GFX_DrawBox(RenderContext *Image, GFXDisplayBox *Box);
+SIGNED_WORD GFX_DrawCharacter(RenderContext *Image, BYTE Character, SIGNED_WORD StartX, SIGNED_WORD StartY, GFXFont *MyFont);
+SIGNED_WORD GFX_GetStringWidth(CHAR * String,GFXFont * MyFont);
+void GFX_DrawString(RenderContext * Image,CHAR * String,SIGNED_WORD StartX, SIGNED_WORD StartY, GFXFont * MyFont);
+void  GFX_printf(RenderContext * Image,SIGNED_WORD StartX, SIGNED_WORD StartY, GFXFont * MyFont, const char *FormatString,...);
+void GFX_DrawCenteredString(RenderContext * Image,CHAR * String,SIGNED_WORD StartX, SIGNED_WORD StartY, GFXFont * MyFont);
+void GFX_DrawListPrimitive(RenderContext * Image,GFXListPrimitive *LP);
+void GFX_DrawScaledListPrimitive(RenderContext * Image,GFXListPrimitive *LP , FIXED_7_8 Scale);
+void GFX_DrawRotatedListPrimitive(RenderContext * Image,GFXListPrimitive *LP , BYTE Angle);
+//void GFX_AddRotatedListPrimitive(RenderContext * Image,GFXListPrimitive *LP , BYTE Angle);
+//void GFX_DrawScaledRotatedListPrimitive(RenderContext * Image,GFXListPrimitive *LP , BYTE Angle,GFXFixed_7_8 Scale);
+
+
+
+#ifdef _INLINE_GFX_GET_PIXEL
+inline BYTE GFX_GetPixel(RenderContext *Image, SIGNED_WORD x, SIGNED_WORD y)
+{
+    BYTE PixelColor = 0;
+    
+    if((x<Image->SizeX) && (y<Image->SizeY) && (x>=0) && (y>=0))
+    {
+        
+        if(BitPlane_Get(&Image->RenderPlane,x,y))
+            PixelColor = TRUE;
+
+    }
+    
+    return PixelColor;
+}
+#else
+    BYTE GFX_GetPixel(RenderContext *Image, SIGNED_WORD x, SIGNED_WORD y);
+#endif
+
+
+extern RenderContext BackBuffer;
+extern GFXFont Font5x7;
+extern GFXFont Font3x5;
+
+
+#define BACK_BUFFER_SIZE_X    (64)
+#define BACK_BUFFER_SIZE_Y  (32)
+
+#define PHYSICAL_DISPLAY_XRES                (BYTE)(64)
+#define PHYSICAL_DISPLAY_YRES                (BYTE)(32)
+#define DISPLAY_X_WIDTH_BYTE                (PHYSICAL_DISPLAY_XRES>>3)
+#define DISPLAY_BUFFER_TOTAL_SIZE             (DISPLAY_X_WIDTH_BYTE*PHYSICAL_DISPLAY_YRES*2)
+#define GREEN_DATA_BUFFER_OFFSET              (DISPLAY_X_WIDTH_BYTE * PHYSICAL_DISPLAY_YRES)
+#define PHYSICAL_DISPLAY_X_WIDTH_IN_BYTES   (PHYSICAL_DISPLAY_XRES>>3)
+#define PHYSICAL_DISPLAY_PLANE_BUFFER_SIZE  (PHYSICAL_DISPLAY_X_WIDTH_IN_BYTES * PHYSICAL_DISPLAY_YRES)
+#define PHYSICAL_DISPLAY_BUFFER_TOTAL_SIZE  (PHYSICAL_DISPLAY_X_WIDTH_IN_BYTES * PHYSICAL_DISPLAY_YRES*2)
+
+
+#endif
+
+
diff -r 000000000000 -r 085749c8446f Headers/KeyValue.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Headers/KeyValue.h	Wed Jun 13 15:10:06 2012 +0000
@@ -0,0 +1,12 @@
+#include "DataTypes.h"
+
+#ifndef _KEY_VALUE_H
+#define _KEY_VALUE_H
+
+BOOL KeyValueSplit(CHAR *LineBuf,CHAR *Key,CHAR *Value);
+
+
+extern CHAR Key[64];
+extern CHAR Value[64];
+
+#endif
\ No newline at end of file
diff -r 000000000000 -r 085749c8446f Headers/Serial.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Headers/Serial.h	Wed Jun 13 15:10:06 2012 +0000
@@ -0,0 +1,12 @@
+#ifndef SERIAL_H
+#define SERIAL_H
+
+#define PC_BACKDOOR_TX_QUEUE_SIZE    2048
+#define PC_BACKDOOR_RX_QUEUE_SIZE   128
+extern ByteQueue PCBackDoorTx,PCBackDoorRx;
+
+extern Serial PCBackDoor;
+void InitPCBackDoor();
+
+#endif
+
diff -r 000000000000 -r 085749c8446f Headers/SmartSwitch.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Headers/SmartSwitch.h	Wed Jun 13 15:10:06 2012 +0000
@@ -0,0 +1,34 @@
+#include "System.h"
+
+#ifndef SMART_SWITCH_H
+#define SMART_SWITCH_H
+
+extern DigitalOut EnableSmartSwitchPower;
+extern DigitalOut SmartSwitch_SS;
+extern DigitalOut SmartSwitch_SCK;
+extern DigitalOut SmartSwitch_SDI;
+
+#define SMART_SWITCH_CMD_DISPLAY_DATA           0x55
+#define SMART_SWITCH_CMD_SET_BACKLIGHT_COLOR    0x40
+#define SMART_SWITCH_CMD_SET_BRIGHTNESS         0x41
+#define SMART_SWITCH_CMD_RESET                  0x5E
+#define SMART_SWITCH_CMD_RESET_PARAMETER        0x03
+
+#define SMART_SWITCH_BACKLIGHT_RED          (0x03<<4)
+#define SMART_SWITCH_BACKLIGHT_YELLOW       (0x03<<4)|(0x03<<2)
+#define SMART_SWITCH_BACKLIGHT_GREEN        (0x03<<2)
+
+
+
+void SmartSwitch_Reset();
+void SmartSwitch_SetBackLightColor(BYTE Red,BYTE Green,BYTE Blue);
+void SmartSwitch_SetBrightnss(BYTE Brightness);
+void InitSmartSwitch();
+void PowerUpSmartSwitch();
+void PowerDownSmartSwitch();
+void SmartSwitchWriteByte(BYTE DataOut);
+void SmartSwitch_SetBackLightColor2(BYTE RGB);
+void SmartSwitch_ImageDump(BYTE *Img);
+void SmartSwitchClear();
+
+#endif
\ No newline at end of file
diff -r 000000000000 -r 085749c8446f Headers/System.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Headers/System.h	Wed Jun 13 15:10:06 2012 +0000
@@ -0,0 +1,58 @@
+#ifndef _SYSTEM_H
+#define _SYSTEM_H
+
+
+#include "DataTypes.h"
+#include "mbed.h"
+#include "Serial.h"
+#include "ADC.h"
+#include "Configuration.h"
+#include "stdio.h"
+#include "FixedMath.h"
+#include "KeyValue.h"
+#include "SmartSwitch.h"
+#include "GFX.h"
+#include "ff.h"
+#include "FIRMWARE_VERSION.h"
+#include "Terminal.h"
+
+#define SYSTEM_STATE_INIT       0   
+#define SYSTEM_STATE_LOGGING    1    
+#define SYSTEM_STATE_IDLE       2
+
+void EnterSystemState(BYTE NextState);
+void InitButton();
+void InitRobotPowerMeasurementSystem();
+
+void CheckButton();
+void UpdateDisplay();
+void CheckSDCardStatus();
+void UpdateHostTerminal();
+
+extern BYTE SystemState;
+
+#define DATA_BLOCK_SIZE    1024
+
+typedef struct {
+
+    float   Voltage[DATA_BLOCK_SIZE];
+    float   Current[DATA_BLOCK_SIZE];
+
+   SIGNED_DWORD  WriteOutPtr;
+   SIGNED_DWORD   ReadInPtr;
+     
+}DataBlock;
+
+extern DataBlock MyDataBlock;
+extern SIGNED_DWORD ReadWriteDifferential;
+
+#define MIN_WRITE_BLOCK_THRESH                (16)
+#define MAX_WRITE_BLOCK_THRESH                ((DATA_BLOCK_SIZE/2)-1)
+
+void InitDataBlocks(DataBlock * DB);
+extern BOOL DataLogError;
+extern CHAR *ErrorMsg;
+void LogData();
+void DisplayBootMsg();
+
+#endif
\ No newline at end of file
diff -r 000000000000 -r 085749c8446f Headers/Terminal.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Headers/Terminal.h	Wed Jun 13 15:10:06 2012 +0000
@@ -0,0 +1,13 @@
+#ifndef _TERMINAL_H
+#define _TERMINAL_H
+
+
+void InitTerminal();
+void ProcessTerminal();
+
+#endif
+
+
+
+
+
diff -r 000000000000 -r 085749c8446f main.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Wed Jun 13 15:10:06 2012 +0000
@@ -0,0 +1,42 @@
+#include "System.h"
+
+int main()
+ {
+    InitPCBackDoor();
+    GFX_Init();
+    InitButton();
+    LoadConfiguration();
+    InitADC();
+    InitTerminal();
+    InitRobotPowerMeasurementSystem();
+    EnterSystemState(SYSTEM_STATE_INIT);
+   DisplayBootMsg();
+   
+    while(TRUE) 
+    {
+    
+        switch(SystemState)
+        {
+            default:
+            case SYSTEM_STATE_INIT:
+                EnterSystemState(SYSTEM_STATE_IDLE);
+            break;
+            
+            case SYSTEM_STATE_LOGGING:
+                ProcessTerminal();    
+                CheckButton();
+                UpdateDisplay();
+                CheckSDCardStatus();
+                LogData();
+            break;
+       
+            case SYSTEM_STATE_IDLE:
+                 ProcessTerminal();
+                CheckButton();
+                UpdateDisplay();
+            break;
+        
+        }     
+    }
+}
+
diff -r 000000000000 -r 085749c8446f mbed.bld
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Wed Jun 13 15:10:06 2012 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/078e4b97a13e