Versión de Firmware con funciones de RAM incorporadas.

Dependencies:   mbed

Fork of VmRecorderV1dot1 by virtualmech

Files at this revision

API Documentation at this revision

Comitter:
JuanManuelAmador
Date:
Mon Jun 15 15:34:27 2015 +0000
Child:
1:a3c9b672b8e2
Commit message:
prueba

Changed in this revision

Doggy/doggy.cpp Show annotated file Show diff for this revision Revisions of this file
Doggy/doggy.h Show annotated file Show diff for this revision Revisions of this file
Doggy/draw2D.cpp Show annotated file Show diff for this revision Revisions of this file
Doggy/globaldefs.h Show annotated file Show diff for this revision Revisions of this file
Doggy/patterns.h Show annotated file Show diff for this revision Revisions of this file
Doggy/xchar.cpp Show annotated file Show diff for this revision Revisions of this file
Doggy/xfont.h Show annotated file Show diff for this revision Revisions of this file
Doggy/xfont_11.h Show annotated file Show diff for this revision Revisions of this file
Doggy/xfont_8.h Show annotated file Show diff for this revision Revisions of this file
FatFileSystem/FATDirHandle.cpp Show annotated file Show diff for this revision Revisions of this file
FatFileSystem/FATDirHandle.h Show annotated file Show diff for this revision Revisions of this file
FatFileSystem/FATFileHandle.cpp Show annotated file Show diff for this revision Revisions of this file
FatFileSystem/FATFileHandle.h Show annotated file Show diff for this revision Revisions of this file
FatFileSystem/FATFileSystem.cpp Show annotated file Show diff for this revision Revisions of this file
FatFileSystem/FATFileSystem.h Show annotated file Show diff for this revision Revisions of this file
FatFileSystem/MemFileSystem.h Show annotated file Show diff for this revision Revisions of this file
FatFileSystem/diskio.cpp Show annotated file Show diff for this revision Revisions of this file
FatFileSystem/diskio.h Show annotated file Show diff for this revision Revisions of this file
FatFileSystem/ff.cpp Show annotated file Show diff for this revision Revisions of this file
FatFileSystem/ff.h Show annotated file Show diff for this revision Revisions of this file
FatFileSystem/ffconf.h Show annotated file Show diff for this revision Revisions of this file
FatFileSystem/integer.h Show annotated file Show diff for this revision Revisions of this file
FatFileSystem/option/ccsbcs.c Show annotated file Show diff for this revision Revisions of this file
FechaHora.cpp Show annotated file Show diff for this revision Revisions of this file
FechaHora.h Show annotated file Show diff for this revision Revisions of this file
FileManager/Configuracion.cpp Show annotated file Show diff for this revision Revisions of this file
FileManager/Configuracion.h Show annotated file Show diff for this revision Revisions of this file
FileManager/ParametrosCalibracion.cpp Show annotated file Show diff for this revision Revisions of this file
FileManager/ParametrosCalibracion.h Show annotated file Show diff for this revision Revisions of this file
FileManager/SistemaArchivos.cpp Show annotated file Show diff for this revision Revisions of this file
FileManager/SistemaArchivos.h Show annotated file Show diff for this revision Revisions of this file
KXR94/KXR94.cpp Show annotated file Show diff for this revision Revisions of this file
KXR94/KXR94.h Show annotated file Show diff for this revision Revisions of this file
MSCFileSystem.cpp Show annotated file Show diff for this revision Revisions of this file
MSCFileSystem.h Show annotated file Show diff for this revision Revisions of this file
Pantallas/ArchivoGuardado.cpp Show annotated file Show diff for this revision Revisions of this file
Pantallas/ArchivoGuardado.h Show annotated file Show diff for this revision Revisions of this file
Pantallas/AutoCalibracion.cpp Show annotated file Show diff for this revision Revisions of this file
Pantallas/AutoCalibracion.h Show annotated file Show diff for this revision Revisions of this file
Pantallas/Configuracion/FormaSelec.cpp Show annotated file Show diff for this revision Revisions of this file
Pantallas/Configuracion/FormaSelec.h Show annotated file Show diff for this revision Revisions of this file
Pantallas/Configuracion/IdiomaSelec.cpp Show annotated file Show diff for this revision Revisions of this file
Pantallas/Configuracion/IdiomaSelec.h Show annotated file Show diff for this revision Revisions of this file
Pantallas/Configuracion/RestaurarValores.cpp Show annotated file Show diff for this revision Revisions of this file
Pantallas/Configuracion/RestaurarValores.h Show annotated file Show diff for this revision Revisions of this file
Pantallas/Configuracion/VelAdquisicionSel.cpp Show annotated file Show diff for this revision Revisions of this file
Pantallas/Configuracion/VelAdquisicionSel.h Show annotated file Show diff for this revision Revisions of this file
Pantallas/FechaHoraConf.cpp Show annotated file Show diff for this revision Revisions of this file
Pantallas/FechaHoraConf.h Show annotated file Show diff for this revision Revisions of this file
Pantallas/GuardarOtroNombre.cpp Show annotated file Show diff for this revision Revisions of this file
Pantallas/GuardarOtroNombre.h Show annotated file Show diff for this revision Revisions of this file
Pantallas/GuardarViaje.cpp Show annotated file Show diff for this revision Revisions of this file
Pantallas/GuardarViaje.h Show annotated file Show diff for this revision Revisions of this file
Pantallas/NuevoViaje.cpp Show annotated file Show diff for this revision Revisions of this file
Pantallas/NuevoViaje.h Show annotated file Show diff for this revision Revisions of this file
Pantallas/OpcionesViaje.cpp Show annotated file Show diff for this revision Revisions of this file
Pantallas/OpcionesViaje.h Show annotated file Show diff for this revision Revisions of this file
Pantallas/Portada.cpp Show annotated file Show diff for this revision Revisions of this file
Pantallas/ViajesGuardados.cpp Show annotated file Show diff for this revision Revisions of this file
Pantallas/ViajesGuardados.h Show annotated file Show diff for this revision Revisions of this file
RingBuffer/Buffering.cpp Show annotated file Show diff for this revision Revisions of this file
RingBuffer/Buffering.h Show annotated file Show diff for this revision Revisions of this file
ScreenManager/ListaSelec.cpp Show annotated file Show diff for this revision Revisions of this file
ScreenManager/ListaSelec.h Show annotated file Show diff for this revision Revisions of this file
ScreenManager/Mensaje.cpp Show annotated file Show diff for this revision Revisions of this file
ScreenManager/Mensaje.h Show annotated file Show diff for this revision Revisions of this file
ScreenManager/Menu.cpp Show annotated file Show diff for this revision Revisions of this file
ScreenManager/Menu.h Show annotated file Show diff for this revision Revisions of this file
ScreenManager/Screen.cpp Show annotated file Show diff for this revision Revisions of this file
ScreenManager/ScreenManager.cpp Show annotated file Show diff for this revision Revisions of this file
ScreenManager/ScreenManager.h Show annotated file Show diff for this revision Revisions of this file
ScreenManager/SelecManager.cpp Show annotated file Show diff for this revision Revisions of this file
ScreenManager/SelecManager.h Show annotated file Show diff for this revision Revisions of this file
ScreenManager/Seleccion.cpp Show annotated file Show diff for this revision Revisions of this file
ScreenManager/Seleccion.h Show annotated file Show diff for this revision Revisions of this file
ScreenManager/Teclado.cpp Show annotated file Show diff for this revision Revisions of this file
ScreenManager/Teclado.h Show annotated file Show diff for this revision Revisions of this file
USBHostLite/usbhost_cpu.h Show annotated file Show diff for this revision Revisions of this file
USBHostLite/usbhost_err.h Show annotated file Show diff for this revision Revisions of this file
USBHostLite/usbhost_inc.h Show annotated file Show diff for this revision Revisions of this file
USBHostLite/usbhost_lpc17xx.cpp Show annotated file Show diff for this revision Revisions of this file
USBHostLite/usbhost_lpc17xx.h Show annotated file Show diff for this revision Revisions of this file
USBHostLite/usbhost_ms.cpp Show annotated file Show diff for this revision Revisions of this file
USBHostLite/usbhost_ms.h Show annotated file Show diff for this revision Revisions of this file
VmRecorderV1dot1.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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Doggy/doggy.cpp	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,152 @@
+#include "doggy.h"
+
+DogMLCD::DogMLCD( SPI& spi, PinName cs, PinName a0 ) : spi_(spi), cs_(cs), a0_(a0)
+{
+    //b_ = (char*)calloc( 1024, 1 );
+    XFont = xfont_8;
+    b_ = w_;
+    Clear();
+    const unsigned char c[] = { 
+        0x40,       // display start line + 0-63
+        0xa1,       // ADC set 0xA1 + 0 = normal (for reverse view) / +1 = reverse (for normal view)
+        0xc0,       // common output mode + 0 = normal / + 0xF  reverse
+        0xa6,       // dispaly mode 0xA6 + 0 = normal / 1 = reverse
+        0xa2,       // set bias 0xa20 + 0 = 1/9 / +1 = 1/7
+        0x2f,       // power control: 4 booster on + 2 regulator on + 1 follower on
+        0xf8, 0x00, // set booster ratio , value 0=4x, 1=5x, 2=6x
+        0x27,       // set voltage regulator (0x20) to 7
+        0x81, 0x18, // set electronic volume , value
+        0xac, 0x00, // static indicator set 0xAC +0 = off / +1 = on , 0 = flash mode
+        0xaf        // display 0xAE +0 = off / +1 = on
+    };
+    
+    spi_.format( 8, 0 );
+    spi_.frequency( 1000000 );
+    cs_ = 0;
+    a0_ = 0;    wait_us( DOGMLCD_TIME );
+    for( int i = 0 ; i < sizeof( c ); i++ )
+        spi_.write( c[i] );
+    cs_ = 1;
+}
+
+void DogMLCD::AttachScreen( char* screen )
+{
+    b_ = screen;
+}
+
+void DogMLCD::DetachScreen()
+{
+    b_ = w_;
+}
+
+#define FASTPOKE( x, y ) b_[ ( ( y & 56 ) << 4 ) + ( x & 127 ) ] |= DOGMLCD_on[ y & 7 ];
+#define FASTWIPE( x, y ) b_[ ( ( y & 56 ) << 4 ) + ( x & 127 ) ] &= DOGMLCD_off[ y & 7 ];
+#define FASTINV( x, y ) b_[ ( ( y & 56 ) << 4 ) + ( x & 127 ) ] ^= DOGMLCD_on[ y & 7 ];
+
+
+void DogMLCD::Poke( int x, int y )
+{
+    if( ( x & 0xFF80 ) == 0 && ( y & 0xFFC0 ) == 0 )
+        FASTPOKE( x, y )
+}
+void DogMLCD::Wipe( int x, int y )
+{
+    if( ( x & 0xFF80 ) == 0 && ( y & 0xFFC0 ) == 0 )
+        FASTWIPE( x, y )
+}
+void DogMLCD::Inv( int x, int y )
+{
+    if( ( x & 0xFF80 ) == 0 && ( y & 0xFFC0 ) == 0 )
+        FASTINV( x, y )
+}
+
+void DogMLCD::InvRect( int x0, int y0, int x1, int y1 )
+{
+    for(int i = y0; i < y1 + 1; i++){
+        for(int j = x0; j < x1 + 1; j++){
+            Inv(j,i);
+        }
+    }
+}
+void DogMLCD::Clear()
+{
+    int i = 1024;
+    char* p = b_;
+    while( i-- )
+        *p++ = 0;
+}
+void DogMLCD::Flush()
+{
+    char* p = b_;
+    spi_.format( 8, 0 );
+    spi_.frequency( DOGMLCD_MHZ );
+    cs_ = 0;
+    for( int page = 0xB0 ; page < 0xB8 ; page++ )
+    {
+        a0_ = 0;    wait_us( DOGMLCD_TIME );
+        spi_.write( page ); spi_.write( 0x10 ); spi_.write( 0x00 );
+        
+        a0_ = 1;    wait_us( DOGMLCD_TIME );
+        int i = 128;
+        while( i-- )
+            spi_.write( *p++ );
+    }
+    cs_ = 1;
+}
+void DogMLCD::Flush( unsigned char page, int x0, int x1 )
+{
+    page &= 7;
+    BOUND( x0, 0, 127 );
+    BOUND( x1, 0, 127 );
+    ORDER( x0 , x1 )
+    char* p = b_ + ( page << 7 ) + x0;
+    spi_.format( 8, 0 );
+    spi_.frequency( DOGMLCD_MHZ );
+    cs_ = 0;
+    a0_ = 0;    wait_us( DOGMLCD_TIME );
+    spi_.write( 0xB0 + page ); spi_.write( 0x10 ); spi_.write( 0x00 );
+        
+    a0_ = 1;    wait_us( DOGMLCD_TIME );
+    int i = x1 - x0 + 1;
+    while( i-- )
+        spi_.write( *p++ );
+    cs_ = 1;
+}
+void DogMLCD::Page( unsigned char page0, unsigned char page1 )
+{
+    page0 &= 7;
+    if( page1 == 0 ) page1 = page0;
+    else
+    {
+        page1 &= 7;
+        ORDER( page0, page1 );
+    }
+    char* p = b_ + ( page0 << 7 );
+    spi_.format( 8, 0 );
+    spi_.frequency( DOGMLCD_MHZ );
+    cs_ = 0;
+    for( int page = 0xB0 + page0 ; page <= ( 0xB0 + page1 ) ; page++ )
+    {
+        a0_ = 0;    wait_us( DOGMLCD_TIME );
+        spi_.write( page ); spi_.write( 0x10 ); spi_.write( 0x00 );
+        
+        a0_ = 1;    wait_us( DOGMLCD_TIME );
+        int i = 128;
+        while( i-- )
+            spi_.write( *p++ );
+    }
+    cs_ = 1;
+}
+void DogMLCD::Paste( char* screen, doggy_op op )
+{
+    int i = 1024;
+    char* p = b_;
+    char* q = screen;
+
+    if( op == poke )       while( i-- )  *p++ |= *q++;
+    else if( op == wipe )  while( i-- )  *p++ &= ~(*q++);
+    else                   while( i-- )  *p++ ^= *q++;
+}
+
+
+    
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Doggy/doggy.h	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,281 @@
+/* mbed DogM Graphic Display Library
+ * Copyright (c) 2011 Bernard Escaillas (www.midimetric.com)
+ */
+
+#ifndef DOGGY_H
+#define DOGGY_H
+
+#include "mbed.h"
+#include "globaldefs.h"
+#include "xfont.h"
+#include "xfont_8.h"
+#include "xfont_11.h"
+#include "patterns.h"
+
+/// DOGM LCD control class
+///
+/// Simple drawing and text rendering functions for DOGM-6 LCD
+/// It should work also with the DOGL.
+/// It does not handles up side down display.
+///
+/// DogM circuit used in the example:
+///
+/// 1/ LCD accesseories:
+///
+///    - LCD is powered from the 3.3V of the mbed. This configuration requires 9 x 1 uF capacitors as
+///    shown in the DogM datasheet. Personnaly i used 0.820 uF (or code 824) because i did not have 1 uFs...
+///    - Amber backlight requires resistors. The data sheet mentions 3 x 47 Ohms resitors (one on each led).
+///    actually, i added a 500 ohms pot and a 47 Ohms in serie to allow for backlight attenuation (and to
+///    extend its lifetime. Also, drawing too much current from the mbed 'steels' power from the LCD and
+///    reduces contrast...
+///
+/// 2/ mbed connection:
+///
+///    - dogm 40 (CS)    -->  mbed p8
+///    - dogm 39 (Reset) -->  +3.3V (always off to save one pin)
+///    - dogm 38 (A0)    -->  mbed p6 (unused miso pin)
+///    - dogm 37 (SCLK)  -->  mbed p7 (SPI clock)
+///    - dogm 36 (SI)    -->  mbed p5 (MOSI)
+///    - dogm 35 (VDD)   -->  +3.3V
+///    - dogm 34 (VVD2)  -->  +3.3V
+///    - dogm 33 (VSS)   -->  GND
+///    - dogm 32 to 21, see datasheet for condensers connection
+///
+/// 3/ SPI cnofiguration:
+///
+///    The datasheet states that the DogM handles data rates up to 10MHz
+///    This rate is probably achieved with independant current source for the backlight.
+///    This library uses by default a 1 MHz for the one time initialization (in case mbed
+///    is powering up also and current is not yet fully stabilized)
+///    It uses a 5MHz rate for work screen transfer.
+///    You can change this by modifying the #DEFINE DOGMLC_MHZ 5000000
+///    (use the #undef / #define pair in your code to redefine this constant)
+///    Increase the value to achieve faster transmission.
+///    Lower the value if some messages are lost.
+///
+/// Example:
+/// @code
+/// #include "mbed.h"
+/// #include "doggy.h"
+///
+/// SPI     spi( p5, NC, p7 ); // MOSI, MISCO, CLK
+/// DogMLCD dog( spi, p8, p6 ); // SPI, CS, A0
+///
+/// int main() 
+/// {
+///     // select font to use:
+///     dog.XFont = xfont_11;
+///
+///     // transmit currently empty work screen (to clear physical display):
+///     dog.Flush();
+///
+///     // create text with symbols:
+///     char formula[] = { 159, '(', 'x', ')', '=', '2', 227, '+', 's', 'i', 'n', '(', 224, ')', '/', 251, 'x' };
+///     // output text from point(0,0):
+///     dog.XString( 0, 0, formula );
+///
+///     // create text with variables and ouput from point (0,11):
+///     char buf[256];
+///     sprintf( buf, "%s=%f", "A", 15.894 );
+///     dog.XString( 0, 11, buf );
+/// 
+///     // paint rectangles with built-in patterns:
+///     dog.Rect(  0, 48,  15, 63, DOGMLCD_full );
+///     dog.Rect( 16, 48,  31, 63, DOGMLCD_dark );
+///     dog.Rect( 32, 48,  47, 63, DOGMLCD_grey );
+///     dog.Rect( 48, 48,  63, 63, DOGMLCD_lite );
+/// 
+///     // transmit work screen to physical screen:
+///     dog.Flush();
+/// }
+/// @endcode
+class DogMLCD
+{
+private:
+    char  w_[1024];                                         // work screen
+    char* b_;                                               // currently used screen
+    SPI& spi_;                                              // attached SPI instance
+    DigitalOut cs_, a0_;                                    // control pins
+
+public:
+
+// implementation in doggy.cpp:
+
+    /// Xfont assignment, assign example:  XFont = xfont_8; , values { xfont_8 (default), xfont_11 }
+    const XGlyph* XFont;
+    
+    /// Create DogMLCD instance and intialize display
+    ///
+    /// @param spi Instance object of an initialized SPI port (see SPI library)
+    /// @param cs Digital pin output to activate slave SPI
+    /// @param a0 Digital pin output to switch DogM from command mode to data mode 
+    DogMLCD( SPI& spi, PinName cs, PinName a0 );
+    
+    /// Use custom screen buffer
+    ///
+    /// @param screen pointer to an array of 1024 chars (128 colonnes of 8 pages)
+    void AttachScreen( char* screen );
+
+    /// Stop using custom screen buffer (revet to internal work screen)
+    void DetachScreen();
+    
+    /// Activate pixel
+    ///
+    /// @param x horizontal coordinate from 0 to 127 included
+    /// @param y vertical coordinate from 0 to 63
+    void Poke( int x, int y );
+
+    /// Clear pixel
+    ///
+    /// @param x horizontal coordinate from 0 to 127 included
+    /// @param y vertical coordinate from 0 to 63 included
+    void Wipe( int x, int y );
+
+    /// Invert pixel 
+    ///
+    /// @param x horizontal coordinate from 0 to 127 included
+    /// @param y vertical coordinate from 0 to 63 included
+    void Inv( int x, int y );
+    
+    /// Invert a rectangle of pixel 
+    ///
+    void InvRect( int x0, int y0, int x1, int y1 );
+
+    /// Clear virtual screen
+    ///
+    /// Note : to clear only a part of the screen, use Rect( ..., DOGMLCD_full, wipe );
+    void Clear();
+
+    /// Transmit virtual screen to physical display
+    ///
+    /// note: this is the more time consuming method, it should take about 3ms under normal conditions.
+    /// For faster transmit you can limit it to the part of the screen that has effectively changed
+    /// with Flush(page) or Flush(y0,y1) 
+    void Flush();
+
+    /// Transmit one virtual screen page (or part of it) to physical display
+    ///
+    /// Physical screen is organized into 8 horizontal bands called pages. Each band is 8 lines high.
+    /// @param page number of the page to transmit, from 0 to 7.
+    /// @param x0 horizontal coordinate of first pixel to transmit, from 0 to 127.
+    /// @param x1 horizontal coordinate of last pixel to transmit, from 0 to 127.
+    void Flush( unsigned char page, int x0 = 0, int x1 = 127 );
+
+    /// Transmit several pages of the virtual screen to physical display
+    ///
+    /// Physical screen is organized into 8 horizontal bands called pages. Each band is 8 lines high.
+    /// Call time is about 150 us + 400 us per page at 5MHz spi frequency
+    /// @param page0 number of the first page to transmit, from 0 to 7.
+    /// @param page1 number of the last page to transmit, from 1 to 7 (0 means ignore argument).
+    void Page( unsigned char page0, unsigned char page1 = 0 );
+
+    /// Paste a custom screen over the internal work screen using raster op
+    ///
+    /// @param screen pointer to a custom screen made of 1024 chars
+    /// @param op raster operation, can be { poke(default), wipe, inv }
+    void Paste( char* screen, doggy_op op = poke );
+    
+// implementation in draw2D.cpp:
+    
+    /// Draw an horizontal line 
+    ///
+    /// @param x0 left coordinate from 0 to 127 included
+    /// @param y  vertical coordinate from 0 to 63 included
+    /// @param x1 right coordinate from 0 to 127 included
+    /// @param op bit math operation (raster), values { poke (default), wipe, inv }
+    void LineH( int x0, int y, int x1, doggy_op op = poke );
+
+    /// Draw a vertical line 
+    ///
+    /// @param x horizontal coordinate from 0 to 127 included
+    /// @param y0 top coordinate from 0 to 63 included
+    /// @param y1 bottom coordinate from 0 to 63 included
+    /// @param op bit math operation (raster), values { poke (default), wipe, inv }
+    void LineV( int x, int y0, int y1, doggy_op op = poke );
+    
+    /// Draw an diagonal line
+    ///
+    /// @param x0 start horizontal coordinate from 0 to 127 included
+    /// @param y0 start vertical coordinate from 0 to 63 included
+    /// @param x1 end horizontal coordinate from 0 to 127 included
+    /// @param y1 end vertical coordinate from 0 to 63 included
+    void Line( int x0, int y0, int x1, int y1, doggy_op = poke );
+    
+    /// Draw an empty rectangle by combining 2 LineH and 2 LineV calls 
+    ///
+    /// @param x0 top left corner, horizontal coordinate from 0 to 127 included
+    /// @param y0 top left corner, vertical coordinate from 0 to 63 included
+    /// @param x1 bottom right corner, horizontal coordinate from 0 to 127 included
+    /// @param y1 bottom right corner, vertical coordinate from 0 to 63 included
+    /// @param op bit math operation (raster), values { poke (default), wipe, inv }
+    void Frame( int x0, int y0, int x1, int y1, doggy_op op = poke );
+
+    /// Draw a filled rectangle by applying bitmap patterns 
+    ///
+    /// Check patterns.h for built-in patterns names.
+    /// Use your own pattern by passing (const unsigned char[]){ col 1, col 2...,col 8 }
+    ///
+    /// @param x0 top left corner, horizontal coordinate from 0 to 127 included
+    /// @param y0 top left corner, vertical coordinate from 0 to 63 included
+    /// @param x1 bottom right corner, horizontal coordinate from 0 to 127 included
+    /// @param y1 bottom right corner, vertical coordinate from 0 to 63 included
+    /// @param pattern a 8x8 bitmap pattern defined by an array of 8 chars
+    /// @param op bit math operation (raster), values { poke (default), wipe, inv }
+    void Rect( int x0, int y0, int x1, int y0, const unsigned char* pattern = DOGMLCD_full, doggy_op op = poke );
+
+// Implementation in xchar.cpp:
+
+    /// Returns the XGlyph structure describing a single character bitmap 
+    ///
+    /// If code is not found in the font, returns the character of code 0 (an empty square)
+    ///
+    /// @param code character code 0, 32 ~ 255 (xfont actually implements the extended US ascii character set)
+    /// @return an XGlyph structure { code, width, height, ...crening..., ...bitmap chars... }
+    XGlyph GetGlyph( int code );
+
+    /// Draw a XFont style character at position (x,y) 
+    ///
+    /// @param x top left corner, horizontal coordinate from 0 to 127 included
+    /// @param y top left corner, vertical coordinate from 0 to 63 included
+    /// @param code US extended ascii code
+    /// @param op bottom right corner, vertical coordinate from 0 to 63 included
+    void XChar( int x, int y, int code, doggy_op op = poke );
+
+    /// Draw a XFont style character at position (x,y) 
+    ///
+    /// @param x top left corner, horizontal coordinate from 0 to 127 included
+    /// @param y top left corner, vertical coordinate from 0 to 63 included
+    /// @param f Xglyph structure of the character
+    /// @param op bit math operation (raster), values { poke (default), wipe, inv }
+    void XChar( int x, int y, XGlyph f, doggy_op op = poke );
+
+    /// Draw a XFont style sequence of characters starting at position (x,y) 
+    ///
+    /// Proportional font : Xfonts are proportionnal : i.e. not all characters have the same width.
+    ///
+    /// Crening (of Kerning): in most cases, there is a character spacing of one pixel beetween chars.
+    /// But some character combinations allow space saving. For instance, "T.", T followed by dot does not need
+    /// the extra pixel to ensure characters are not touching each other. Same for "aV" or "L'" or "=1" .
+    ///
+    /// New line: string can contain the new line '\\n' or (13)
+    ///
+    /// Wrapping: if the ouput reaches the right side of the screen, it will wrap to next line at position x.
+    /// wrapping is not space dependant, it happens anywhere in the string (inside words)
+    /// if wrapped line happens to begins with a space, the space is skipped
+    /// 
+    /// @param x top left corner, horizontal coordinate from 0 to 127 included
+    /// @param y top left corner, vertical coordinate from 0 to 63 included
+    /// @param f Xglyph structure of the character
+    /// @param op bit math operation (raster), values { poke (default), wipe, inv }
+    ///
+    /// @return the last y coordinate used to output chars (may be different than initial argument if string was wrapped)
+    int XString( int x, int y, const char* s, doggy_op op = poke );
+    int XString( int x, int y, int i, doggy_op = poke );
+    int XString( int x, int y, float f, doggy_op = poke );
+};
+
+/// Type definition for RasterOp
+///
+/// is a pointer to a metthod of DogMLCD taking two int arguments
+typedef void (DogMLCD::*RasterOp)(int,int);
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Doggy/draw2D.cpp	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,101 @@
+#include "doggy.h"
+
+void DogMLCD::LineH( int x0, int y, int x1, doggy_op raster )
+{
+    if( y & 0xFFC0 ) return; // line is out of screen
+    BOUND( x0, 0, 127 )
+    BOUND( x1, 0, 127 )
+    ORDER( x0, x1 )
+    
+    int n = x1 - x0 + 1;
+    char* p = b_ + (( y & 0x38 ) << 4) + x0;
+    if( raster == poke )
+    {
+        char b = DOGMLCD_on[ y & 7 ];
+        while( n-- )
+            *p++ |= b;
+    }
+    else if( raster == wipe )
+    {
+        char b = DOGMLCD_off[ y & 7 ];
+        while( n-- )
+            *p++ &= b;
+    }
+    else
+    {
+        char b = DOGMLCD_on[ y & 7 ];
+        while( n-- )
+            *p++ ^= b;
+    }
+}
+void DogMLCD::LineV( int x, int y0, int y1, doggy_op raster )
+{
+    if( x & 0xFF80 ) return; // line is out of screen
+    BOUND( y0, 0, 63 )
+    BOUND( y1, 0, 63 )
+    ORDER( y0, y1 )
+    RasterOp op = ((RasterOp[]){ &DogMLCD::Poke, &DogMLCD::Wipe, &DogMLCD::Inv })[raster];
+    for( int y = y0 ; y <= y1 ; y++ ) 
+        (this->*op)( x, y );
+}
+void DogMLCD::Line( int x0, int y0, int x1, int y1, doggy_op raster )
+{
+    bool steep = abs( y1 - y0 ) > abs( x1 - x0 );
+    if( steep ) { SWAP( x0, y0 ) SWAP( x1, y1 ) }
+    if( x0 > x1) { SWAP( x0, x1 ) SWAP( y0, y1 ) }
+
+    int dx = x1 - x0;
+    int dy = abs( y1 - y0 );
+    int e = dx / 2;
+    int ystep = y0 < y1 ? 1 : -1;
+    RasterOp op = ((RasterOp[]){ &DogMLCD::Poke, &DogMLCD::Wipe, &DogMLCD::Inv })[raster];
+    
+    if( steep ) for( int x = x0, y = y0 ; x <= x1 ; x++ )
+    {
+        (this->*op)( y, x );
+        if( ( e -= dy ) < 0 )
+        {
+            y += ystep;
+            e += dx;
+        }
+    }
+    else for( int x = x0, y = y0 ; x <= x1 ; x++ )
+    {
+        (this->*op)( x, y );
+        if( ( e -= dy ) < 0 )
+        {
+            y += ystep;
+            e += dx;
+        }
+    }
+}
+void DogMLCD::Frame( int x0, int y0, int x1, int y1, doggy_op raster )
+{
+    ORDER( x0, x1 )
+    ORDER( y0, y1 )
+    
+    LineH( x0, y0, x1, raster );
+    if( y1 > y0 ) LineH( x0, y1, x1, raster );
+    
+    y0++; // don't overlap at angles
+    y1--;
+    if( y1 >= y0 ) // don't overlap if horizontal lines where adjacent
+    {
+        LineV( x0, y0, y1, raster );
+        if( x1 > x0 ) LineV( x1, y0, y1, raster );
+    }
+}
+void DogMLCD::Rect( int x0, int y0, int x1, int y1, const unsigned char* p, doggy_op raster )
+{
+    BOUND( x0, 0, 127 )
+    BOUND( x1, 0, 127 )
+    BOUND( y0, 0, 63 )
+    BOUND( y1, 0, 63 )
+    ORDER( x0, x1 )
+    ORDER( y0, y1 )
+    RasterOp op = ((RasterOp[]){ &DogMLCD::Poke, &DogMLCD::Wipe, &DogMLCD::Inv })[raster];
+    for( int x = x0 ; x <= x1 ; x++ )
+        for( int y = y0 ; y <= y1 ; y++ )
+            if( p[x & 7] & ( 1 << ( y & 7 ) ) )
+                (this->*op)( x, y );
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Doggy/globaldefs.h	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,25 @@
+#ifndef GLOBALDEFS_H
+#define GLOBALDEFS_H
+
+/// SPI frequency for method DogMLCD::Flush()
+#define DOGMLCD_MHZ 18000000
+// Wait time after changing state of A0 in uS
+#define DOGMLCD_TIME 8
+
+#ifndef BOUND
+    #define BOUND(a,b,c) if( a < b ) a = b; else if( a > c ) a = c;
+#endif
+#ifndef SWAP
+    #define SWAP(a,b) { int c = a; a = b; b = c; }
+#endif
+#ifndef ORDER
+    #define ORDER(a,b) if( a > b ) { int c = a; a = b; b = c; }
+#endif
+
+const unsigned char DOGMLCD_on[] = { 1, 2, 4, 8, 16, 32, 64, 128 };
+const unsigned char DOGMLCD_off[]= { 254, 253, 251, 247, 239, 223, 191, 127 };
+
+/// Bit mpath operation (raster)
+typedef enum{ poke, wipe, inv } doggy_op;
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Doggy/patterns.h	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,17 @@
+#ifndef PATTERNS_H
+#define PATTERNS_H
+
+const unsigned char DOGMLCD_full[] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF };
+const unsigned char DOGMLCD_dark[] = { 0xFF,0x55,0xFF,0x55,0xFF,0x55,0xFF,0x55 };
+const unsigned char DOGMLCD_grey[] = { 0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA };
+const unsigned char DOGMLCD_lite[] = { 0x55,0x00,0x55,0x00,0x55,0x00,0x55,0x00 };
+const unsigned char DOGMLCD_void[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
+const unsigned char DOGMLCD_bars[] = { 0xFF,0x00,0xFF,0x00,0xFF,0x00,0xFF,0x00 };
+const unsigned char DOGMLCD_lito[] = { 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55 };
+const unsigned char DOGMLCD_wave[] = { 0x11,0x88,0x44,0x88,0x11,0x22,0x44,0x22 };
+const unsigned char DOGMLCD_diag[] = { 0x88,0x44,0x22,0x11,0x88,0x44,0x22,0x11 };
+const unsigned char DOGMLCD_slah[] = { 0x11,0x22,0x44,0x88,0x11,0x22,0x44,0x88 };
+const unsigned char DOGMLCD_cros[] = { 0x55,0x22,0x55,0x88,0x55,0x22,0x55,0x88 };
+const unsigned char DOGMLCD_grek[] = { 0x80,0xFE,0x02,0xFA,0x8A,0xBA,0xA2,0xBE };
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Doggy/xchar.cpp	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,90 @@
+#include "doggy.h"
+
+XGlyph DogMLCD::GetGlyph( int code )
+{
+    if( code > 31 && code < 256 )
+        return XFont[code - 31];
+    return XFont[0];
+}
+
+void DogMLCD::XChar( int x, int y, int code, doggy_op raster )
+{
+    XChar( x, y, GetGlyph( code ) );
+}
+void DogMLCD::XChar( int x, int y, XGlyph f, doggy_op raster )
+{
+    const char* p = f.bmp;
+    RasterOp op = ((RasterOp[]){ &DogMLCD::Poke, &DogMLCD::Wipe, &DogMLCD::Inv })[raster];
+    int y1 = y + f.hei;
+    for( int w = 0 ; w < f.wid ; w++ )
+    {
+        for( int z = y, m = 1 ; z < y1 ; z++ )
+        {
+            if( m == 256 ) { m = 1; p++; }
+            if( *p & m )
+                (this->*op)( x, z );
+            m <<= 1;
+        }
+        p++;
+        x++;
+    }
+}
+int DogMLCD::XString( int x, int y, int i, doggy_op raster )
+{
+    char buf[32];
+    sprintf( buf, "%d", i );
+    return XString( x, y, buf, raster );
+}
+int DogMLCD::XString( int x, int y, float f, doggy_op raster )
+{
+    char buf[32];
+    sprintf( buf, "%f", f );
+    return XString( x, y, buf, raster );
+}
+int DogMLCD::XString( int x, int y, const char* s, doggy_op raster )
+{
+    int oldx = x;
+    int trc = 0, brc = 0, inter = XFont[0].hei;
+    while( *s )
+    {
+        if( *s == 13 )
+        {
+            x = oldx;
+            y += inter;
+        }
+        else if( *s > 31 )
+        {
+            XGlyph f = GetGlyph( *s );
+            
+            while( ( x > 0 ) && ( trc + f.tlc ) > 0 && ( brc + f.blc ) > 0 )
+            {
+                x--;
+                trc--;
+                brc--;
+            }
+            
+            if( x + f.wid > 128 ) // simplified form of [ x + f.wid - 1 > 127 ]
+            {
+                x = oldx;
+                y += inter;
+                if( *s != 32 ) // don't ouput begining space on new line
+                {
+                    XChar( x, y, f, raster );
+                    x += f.wid + 1;
+                 }
+            }
+            else
+            {
+                XChar( x, y, f, raster );
+                x += f.wid + 1;
+            }
+            if( *s != 32 ) // for space keep crening of previous char
+            {
+                trc = f.trc;
+                brc = f.brc;
+            }
+        }
+        s++;
+    }
+    return y;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Doggy/xfont.h	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,15 @@
+#ifndef FONT_H
+#define FONT_H
+
+typedef struct {
+    unsigned char   cod; // unicode value
+    unsigned char   wid; // data width in pixels
+    unsigned char   hei; // data height in pixels (multiple of 8)
+    unsigned char   tlc; // form allows left top crening
+    unsigned char   trc; // form allows right top crening
+    unsigned char   blc; // form allows left bottom crening
+    unsigned char   brc; // form allows right bottom crening
+    const char*     bmp;
+} XGlyph;
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Doggy/xfont_11.h	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,231 @@
+#ifndef XFONT_11_H
+#define XFONT_11_H
+
+const XGlyph xfont_11[] = {
+    {   0, 6, 11, 0, 0, 0, 0, (const char[]){ 0xFF, 0x03, 0x10, 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, 0x02, 0xFF, 0x03 } },
+    {  32, 2, 11, 0, 0, 0, 0, (const char[]){ 0x00, 0x00, 0x00, 0x00 } },
+    {  33, 2, 11, 0, 0, 0, 0, (const char[]){ 0xBE, 0x01, 0xBE, 0x01 } },
+    {  34, 5, 11, 0, 0, 1, 1, (const char[]){ 0x0E, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x06, 0x00 } },
+    {  35, 7, 11, 0, 0, 0, 0, (const char[]){ 0x50, 0x00, 0xFC, 0x01, 0xFC, 0x01, 0x50, 0x00, 0xFC, 0x01, 0xFC, 0x01, 0x50, 0x00 } },
+    {  36, 7, 11, 0, 0, 0, 0, (const char[]){ 0x98, 0x00, 0xBC, 0x01, 0x24, 0x01, 0xFE, 0x03, 0x24, 0x01, 0xEC, 0x01, 0xC8, 0x00 } },
+    {  37, 8, 11, 0, 0, 0, 0, (const char[]){ 0x0C, 0x01, 0x9E, 0x00, 0x52, 0x00, 0xFE, 0x00, 0xFC, 0x01, 0x28, 0x01, 0xE4, 0x01, 0xC2, 0x00 } },
+    {  38, 7, 11, 0, 0, 0, 0, (const char[]){ 0xC8, 0x00, 0xFC, 0x01, 0x34, 0x01, 0x7C, 0x01, 0xC8, 0x01, 0xA0, 0x01, 0x20, 0x01 } },
+    {  39, 2, 11, 0, 0, 1, 1, (const char[]){ 0x0E, 0x00, 0x06, 0x00 } },
+    {  40, 4, 11, 0, 0, 0, 0, (const char[]){ 0xFC, 0x00, 0xFE, 0x01, 0x03, 0x03, 0x01, 0x02 } },
+    {  41, 4, 11, 0, 0, 0, 0, (const char[]){ 0x01, 0x02, 0x03, 0x03, 0xFE, 0x01, 0xFC, 0x00 } },
+    {  42, 6, 11, 0, 0, 0, 0, (const char[]){ 0x50, 0x00, 0x20, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0x20, 0x00, 0x50, 0x00 } },
+    {  43, 6, 11, 0, 0, 0, 0, (const char[]){ 0x20, 0x00, 0x20, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0x20, 0x00, 0x20, 0x00 } },
+    {  44, 3, 11, 1, 1, 0, 0, (const char[]){ 0x00, 0x04, 0x80, 0x03, 0x80, 0x01 } },
+    {  45, 6, 11, 1, 1, 0, 0, (const char[]){ 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00 } },
+    {  46, 2, 11, 2, 2, 0, 0, (const char[]){ 0x80, 0x01, 0x80, 0x01 } },
+    {  47, 5, 11, 1, 0, 0, 1, (const char[]){ 0x00, 0x07, 0xC0, 0x01, 0x70, 0x00, 0x1C, 0x00, 0x07, 0x00 } },
+    {  48, 6, 11, 0, 0, 0, 0, (const char[]){ 0xFC, 0x00, 0xFE, 0x01, 0x02, 0x01, 0x02, 0x01, 0xFE, 0x01, 0xFC, 0x00 } },
+    {  49, 4, 11, 0, 0, 1, 0, (const char[]){ 0x04, 0x00, 0x04, 0x00, 0xFE, 0x01, 0xFE, 0x01 } },
+    {  50, 6, 11, 0, 0, 0, 0, (const char[]){ 0x8C, 0x01, 0xCE, 0x01, 0x62, 0x01, 0x32, 0x01, 0x1E, 0x01, 0x0C, 0x01 } },
+    {  51, 6, 11, 0, 0, 0, 0, (const char[]){ 0x84, 0x00, 0x86, 0x01, 0x12, 0x01, 0x12, 0x01, 0xFE, 0x01, 0xEC, 0x00 } },
+    {  52, 6, 11, 0, 0, 0, 0, (const char[]){ 0x70, 0x00, 0x48, 0x00, 0x44, 0x00, 0xFE, 0x01, 0xFE, 0x01, 0x40, 0x00 } },
+    {  53, 6, 11, 0, 0, 0, 0, (const char[]){ 0xDE, 0x00, 0xDE, 0x01, 0x12, 0x01, 0x12, 0x01, 0xF2, 0x01, 0xE2, 0x00 } },
+    {  54, 6, 11, 0, 0, 0, 0, (const char[]){ 0xF8, 0x00, 0xFC, 0x01, 0x12, 0x01, 0x12, 0x01, 0xF2, 0x01, 0xE0, 0x00 } },
+    {  55, 6, 11, 0, 0, 0, 0, (const char[]){ 0x02, 0x00, 0x82, 0x01, 0xE2, 0x01, 0x7A, 0x00, 0x1E, 0x00, 0x06, 0x00 } },
+    {  56, 6, 11, 0, 0, 0, 0, (const char[]){ 0xEC, 0x00, 0xFE, 0x01, 0x12, 0x01, 0x12, 0x01, 0xFE, 0x01, 0xEC, 0x00 } },
+    {  57, 6, 11, 0, 0, 0, 0, (const char[]){ 0x1C, 0x00, 0x3E, 0x01, 0x22, 0x01, 0xA2, 0x01, 0xFE, 0x00, 0x7C, 0x00 } },
+    {  58, 2, 11, 0, 0, 0, 0, (const char[]){ 0x98, 0x01, 0x98, 0x01 } },
+    {  59, 3, 11, 0, 0, 0, 0, (const char[]){ 0x00, 0x04, 0x98, 0x03, 0x98, 0x01 } },
+    {  60, 5, 11, 0, 0, 0, 0, (const char[]){ 0x20, 0x00, 0x70, 0x00, 0xD8, 0x00, 0x8C, 0x01, 0x04, 0x01 } },
+    {  61, 6, 11, 1, 1, 0, 0, (const char[]){ 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00 } },
+    {  62, 5, 11, 0, 0, 0, 0, (const char[]){ 0x04, 0x01, 0x8C, 0x01, 0xD8, 0x00, 0x70, 0x00, 0x20, 0x00 } },
+    {  63, 6, 11, 0, 0, 0, 0, (const char[]){ 0x04, 0x00, 0x06, 0x00, 0xA2, 0x01, 0xB2, 0x01, 0x1E, 0x00, 0x0C, 0x00 } },
+    {  64, 8, 11, 0, 0, 0, 0, (const char[]){ 0x78, 0x00, 0x84, 0x00, 0x32, 0x01, 0x4A, 0x01, 0x4A, 0x01, 0x7A, 0x01, 0x42, 0x00, 0x7C, 0x00 } },
+    {  65, 7, 11, 0, 0, 0, 0, (const char[]){ 0xFC, 0x01, 0xFE, 0x01, 0x42, 0x00, 0x42, 0x00, 0x42, 0x00, 0xFE, 0x01, 0xFC, 0x01 } },
+    {  66, 7, 11, 0, 0, 0, 0, (const char[]){ 0xFE, 0x01, 0xFE, 0x01, 0x12, 0x01, 0x12, 0x01, 0x12, 0x01, 0xFE, 0x01, 0xEC, 0x00 } },
+    {  67, 7, 11, 0, 0, 0, 0, (const char[]){ 0xFC, 0x00, 0xFE, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x86, 0x01, 0x84, 0x00 } },
+    {  68, 7, 11, 0, 0, 0, 0, (const char[]){ 0xFE, 0x01, 0xFE, 0x01, 0x02, 0x01, 0x02, 0x01, 0x06, 0x01, 0xFC, 0x01, 0xF8, 0x00 } },
+    {  69, 7, 11, 0, 0, 0, 0, (const char[]){ 0xFE, 0x01, 0xFE, 0x01, 0x12, 0x01, 0x12, 0x01, 0x12, 0x01, 0x02, 0x01, 0x02, 0x01 } },
+    {  70, 7, 11, 0, 0, 0, 2, (const char[]){ 0xFE, 0x01, 0xFE, 0x01, 0x12, 0x00, 0x12, 0x00, 0x12, 0x00, 0x02, 0x00, 0x02, 0x00 } },
+    {  71, 7, 11, 0, 0, 0, 0, (const char[]){ 0xFC, 0x00, 0xFE, 0x01, 0x02, 0x01, 0x02, 0x01, 0x22, 0x01, 0xE6, 0x01, 0xE4, 0x00 } },
+    {  72, 7, 11, 0, 0, 0, 0, (const char[]){ 0xFE, 0x01, 0xFE, 0x01, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0xFE, 0x01, 0xFE, 0x01 } },
+    {  73, 4, 11, 0, 0, 0, 0, (const char[]){ 0x02, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0x02, 0x01 } },
+    {  74, 6, 11, 1, 0, 0, 0, (const char[]){ 0xC0, 0x00, 0xC0, 0x01, 0x02, 0x01, 0xFE, 0x01, 0xFE, 0x00, 0x02, 0x00 } },
+    {  75, 7, 11, 0, 0, 0, 0, (const char[]){ 0xFE, 0x01, 0xFE, 0x01, 0x30, 0x00, 0x78, 0x00, 0xCC, 0x00, 0x86, 0x01, 0x02, 0x01 } },
+    {  76, 6, 11, 0, 2, 0, 0, (const char[]){ 0xFE, 0x01, 0xFE, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01 } },
+    {  77, 8, 11, 0, 0, 0, 0, (const char[]){ 0xFE, 0x01, 0xFE, 0x01, 0x0C, 0x00, 0x18, 0x00, 0x18, 0x00, 0x0C, 0x00, 0xFE, 0x01, 0xFE, 0x01 } },
+    {  78, 8, 11, 0, 0, 0, 0, (const char[]){ 0xFE, 0x01, 0xFE, 0x01, 0x06, 0x00, 0x18, 0x00, 0x60, 0x00, 0x80, 0x01, 0xFE, 0x01, 0xFE, 0x01 } },
+    {  79, 7, 11, 0, 0, 0, 0, (const char[]){ 0xFC, 0x00, 0xFE, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0xFE, 0x01, 0xFC, 0x00 } },
+    {  80, 7, 11, 0, 0, 0, 1, (const char[]){ 0xFE, 0x01, 0xFE, 0x01, 0x42, 0x00, 0x42, 0x00, 0x42, 0x00, 0x7E, 0x00, 0x3C, 0x00 } },
+    {  81, 7, 11, 0, 0, 0, 0, (const char[]){ 0xFC, 0x00, 0xFE, 0x01, 0x02, 0x01, 0x42, 0x01, 0x82, 0x01, 0xFE, 0x03, 0xFC, 0x02 } },
+    {  82, 7, 11, 0, 0, 0, 0, (const char[]){ 0xFE, 0x01, 0xFE, 0x01, 0x42, 0x00, 0x42, 0x00, 0xC2, 0x00, 0x7E, 0x01, 0x3C, 0x01 } },
+    {  83, 7, 11, 0, 0, 0, 0, (const char[]){ 0x8C, 0x00, 0x9E, 0x01, 0x12, 0x01, 0x32, 0x01, 0x22, 0x01, 0xE6, 0x01, 0xC4, 0x00 } },
+    {  84, 6, 11, 0, 0, 2, 2, (const char[]){ 0x02, 0x00, 0x02, 0x00, 0xFE, 0x01, 0xFE, 0x01, 0x02, 0x00, 0x02, 0x00 } },
+    {  85, 7, 11, 0, 0, 0, 0, (const char[]){ 0xFE, 0x00, 0xFE, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0xFE, 0x01, 0xFE, 0x00 } },
+    {  86, 8, 11, 0, 0, 0, 0, (const char[]){ 0x0E, 0x00, 0x7E, 0x00, 0xF0, 0x01, 0x80, 0x01, 0x80, 0x01, 0xF0, 0x01, 0x7E, 0x00, 0x0E, 0x00 } },
+    {  87, 8, 11, 0, 0, 0, 0, (const char[]){ 0x7E, 0x00, 0xFE, 0x01, 0x80, 0x01, 0xF0, 0x00, 0xF0, 0x00, 0x80, 0x01, 0xFE, 0x01, 0xFE, 0x00 } },
+    {  88, 7, 11, 0, 0, 0, 0, (const char[]){ 0x86, 0x01, 0xCE, 0x01, 0x78, 0x00, 0x30, 0x00, 0x78, 0x00, 0xCE, 0x01, 0x86, 0x01 } },
+    {  89, 6, 11, 0, 0, 1, 1, (const char[]){ 0x1E, 0x00, 0x3E, 0x00, 0xE0, 0x01, 0xE0, 0x01, 0x3E, 0x00, 0x1E, 0x00 } },
+    {  90, 7, 11, 0, 0, 0, 0, (const char[]){ 0x82, 0x01, 0xC2, 0x01, 0x62, 0x01, 0x32, 0x01, 0x1A, 0x01, 0x0E, 0x01, 0x06, 0x01 } },
+    {  91, 4, 11, 0, 0, 0, 0, (const char[]){ 0xFF, 0x03, 0xFF, 0x03, 0x01, 0x02, 0x01, 0x02 } },
+    {  92, 5, 11, 0, 1, 0, 0, (const char[]){ 0x06, 0x00, 0x1E, 0x00, 0x78, 0x00, 0xE0, 0x01, 0x80, 0x01 } },
+    {  93, 4, 11, 0, 0, 0, 0, (const char[]){ 0x01, 0x02, 0x01, 0x02, 0xFF, 0x03, 0xFF, 0x03 } },
+    {  94, 7, 11, 0, 0, 1, 1, (const char[]){ 0x08, 0x00, 0x0C, 0x00, 0x06, 0x00, 0x03, 0x00, 0x06, 0x00, 0x0C, 0x00, 0x08, 0x00 } },
+    {  95, 6, 11, 1, 1, 0, 0, (const char[]){ 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01 } },
+    {  96, 3, 11, 0, 0, 1, 1, (const char[]){ 0x06, 0x00, 0x0E, 0x00, 0x10, 0x00 } },
+    {  97, 6, 11, 1, 0, 0, 0, (const char[]){ 0xC0, 0x00, 0xE8, 0x01, 0x28, 0x01, 0x28, 0x01, 0xF8, 0x01, 0xF8, 0x01 } },
+    {  98, 6, 11, 0, 1, 0, 0, (const char[]){ 0xFE, 0x01, 0xFE, 0x01, 0x08, 0x01, 0x08, 0x01, 0xF8, 0x01, 0xF0, 0x00 } },
+    {  99, 6, 11, 1, 1, 0, 0, (const char[]){ 0xF0, 0x00, 0xF8, 0x01, 0x08, 0x01, 0x08, 0x01, 0x98, 0x01, 0x90, 0x00 } },
+    { 100, 6, 11, 1, 0, 0, 0, (const char[]){ 0xF0, 0x00, 0xF8, 0x01, 0x08, 0x01, 0x08, 0x01, 0xFE, 0x01, 0xFE, 0x01 } },
+    { 101, 6, 11, 1, 1, 0, 0, (const char[]){ 0xF0, 0x00, 0xF8, 0x01, 0x28, 0x01, 0x28, 0x01, 0xB8, 0x01, 0xB0, 0x00 } },
+    { 102, 5, 11, 0, 0, 0, 1, (const char[]){ 0x08, 0x00, 0xFC, 0x01, 0xFE, 0x01, 0x0A, 0x00, 0x0A, 0x00 } },
+    { 103, 5, 11, 1, 1, 0, 0, (const char[]){ 0xF0, 0x00, 0xF8, 0x05, 0x08, 0x05, 0xF8, 0x07, 0xF0, 0x03 } },
+    { 104, 6, 11, 0, 1, 0, 0, (const char[]){ 0xFE, 0x01, 0xFE, 0x01, 0x08, 0x00, 0x08, 0x00, 0xF8, 0x01, 0xF0, 0x01 } },
+    { 105, 2, 11, 0, 0, 0, 0, (const char[]){ 0xFA, 0x01, 0xFA, 0x01 } },
+    { 106, 3, 11, 1, 0, 0, 0, (const char[]){ 0x00, 0x04, 0xFA, 0x07, 0xFA, 0x03 } },
+    { 107, 6, 11, 0, 1, 0, 0, (const char[]){ 0xFE, 0x01, 0xFE, 0x01, 0x20, 0x00, 0x70, 0x00, 0xD8, 0x01, 0x88, 0x01 } },
+    { 108, 2, 11, 1, 1, 0, 0, (const char[]){ 0xFE, 0x01, 0xFE, 0x01 } },
+    { 109, 8, 11, 0, 1, 1, 0, (const char[]){ 0xF0, 0x01, 0xF8, 0x01, 0x08, 0x00, 0xF8, 0x01, 0xF0, 0x01, 0x08, 0x00, 0xF8, 0x01, 0xF0, 0x01 } },
+    { 110, 6, 11, 1, 1, 0, 0, (const char[]){ 0x08, 0x00, 0xF8, 0x01, 0xF8, 0x01, 0x08, 0x00, 0xF8, 0x01, 0xF0, 0x01 } },
+    { 111, 6, 11, 0, 1, 0, 0, (const char[]){ 0xF0, 0x00, 0xF8, 0x01, 0x08, 0x01, 0x08, 0x01, 0xF8, 0x01, 0xF0, 0x00 } },
+    { 112, 6, 11, 1, 0, 0, 0, (const char[]){ 0xF8, 0x07, 0xF8, 0x07, 0x08, 0x01, 0x08, 0x01, 0xF8, 0x01, 0xF0, 0x00 } },
+    { 113, 6, 11, 0, 0, 0, 0, (const char[]){ 0xF0, 0x00, 0xF8, 0x01, 0x08, 0x01, 0x08, 0x01, 0xF8, 0x07, 0xF8, 0x07 } },
+    { 114, 6, 11, 0, 0, 1, 0, (const char[]){ 0x08, 0x00, 0xF8, 0x01, 0xF0, 0x01, 0x08, 0x00, 0x38, 0x00, 0x30, 0x00 } },
+    { 115, 5, 11, 0, 0, 0, 0, (const char[]){ 0x90, 0x00, 0xB8, 0x01, 0x68, 0x01, 0xD8, 0x01, 0x90, 0x00 } },
+    { 116, 4, 11, 0, 0, 1, 0, (const char[]){ 0x08, 0x00, 0xFC, 0x00, 0xFE, 0x01, 0x08, 0x01 } },
+    { 117, 6, 11, 0, 1, 0, 0, (const char[]){ 0xF8, 0x00, 0xF8, 0x01, 0x00, 0x01, 0xF8, 0x01, 0xF8, 0x01, 0x00, 0x01 } },
+    { 118, 7, 11, 0, 0, 0, 0, (const char[]){ 0x18, 0x00, 0x78, 0x00, 0xE0, 0x00, 0x80, 0x01, 0xE0, 0x00, 0x78, 0x00, 0x18, 0x00 } },
+    { 119, 8, 11, 0, 0, 0, 0, (const char[]){ 0xF8, 0x00, 0xF8, 0x01, 0x00, 0x01, 0xE0, 0x01, 0xE0, 0x01, 0x00, 0x01, 0xF8, 0x01, 0xF8, 0x00 } },
+    { 120, 6, 11, 0, 0, 0, 0, (const char[]){ 0x08, 0x01, 0x98, 0x01, 0xF0, 0x00, 0xF0, 0x00, 0x98, 0x01, 0x08, 0x01 } },
+    { 121, 5, 11, 0, 0, 0, 0, (const char[]){ 0xF8, 0x04, 0xF8, 0x05, 0x00, 0x05, 0xF8, 0x07, 0xF8, 0x03 } },
+    { 122, 6, 11, 0, 0, 0, 0, (const char[]){ 0x88, 0x01, 0xC8, 0x01, 0xE8, 0x01, 0x78, 0x01, 0x38, 0x01, 0x18, 0x01 } },
+    { 123, 4, 11, 0, 0, 0, 0, (const char[]){ 0x30, 0x00, 0xFE, 0x01, 0xCF, 0x03, 0x01, 0x02 } },
+    { 124, 2, 11, 0, 0, 0, 0, (const char[]){ 0xFF, 0x01, 0xFF, 0x01 } },
+    { 125, 4, 11, 0, 0, 0, 0, (const char[]){ 0x01, 0x02, 0xCF, 0x03, 0xFE, 0x01, 0x30, 0x00 } },
+    { 126, 8, 11, 0, 0, 0, 0, (const char[]){ 0x30, 0x00, 0x38, 0x00, 0x08, 0x00, 0x38, 0x00, 0x70, 0x00, 0x40, 0x00, 0x70, 0x00, 0x30, 0x00 } },
+    { 127, 6, 11, 0, 0, 0, 0, (const char[]){ 0x55, 0x01, 0xAA, 0x02, 0x55, 0x01, 0xAA, 0x02, 0x55, 0x01, 0xAA, 0x02 } },
+    { 128, 7, 11, 0, 0, 0, 0, (const char[]){ 0xFC, 0x00, 0xFE, 0x01, 0x02, 0x05, 0x02, 0x07, 0x02, 0x03, 0x86, 0x01, 0x84, 0x00 } },
+    { 129, 6, 11, 0, 1, 0, 0, (const char[]){ 0xF8, 0x00, 0xFA, 0x01, 0x00, 0x01, 0xFA, 0x01, 0xF8, 0x01, 0x00, 0x01 } },
+    { 130, 6, 11, 0, 0, 0, 0, (const char[]){ 0xF0, 0x00, 0xF8, 0x01, 0x2A, 0x01, 0x29, 0x01, 0xB8, 0x01, 0xB0, 0x00 } },
+    { 131, 6, 11, 0, 0, 0, 0, (const char[]){ 0xC0, 0x00, 0xEA, 0x01, 0x29, 0x01, 0x29, 0x01, 0xFA, 0x01, 0xF8, 0x01 } },
+    { 132, 6, 11, 0, 0, 0, 0, (const char[]){ 0xC0, 0x00, 0xEA, 0x01, 0x28, 0x01, 0x28, 0x01, 0xFA, 0x01, 0xF8, 0x01 } },
+    { 133, 6, 11, 0, 0, 0, 0, (const char[]){ 0xC0, 0x00, 0xE8, 0x01, 0x29, 0x01, 0x2A, 0x01, 0xF8, 0x01, 0xF8, 0x01 } },
+    { 134, 6, 11, 0, 0, 0, 0, (const char[]){ 0xC0, 0x00, 0xE8, 0x01, 0x2A, 0x01, 0x2A, 0x01, 0xF8, 0x01, 0xF8, 0x01 } },
+    { 135, 6, 11, 0, 0, 0, 0, (const char[]){ 0xF0, 0x00, 0xF8, 0x01, 0x08, 0x05, 0x08, 0x03, 0x98, 0x01, 0x90, 0x00 } },
+    { 136, 6, 11, 0, 0, 0, 0, (const char[]){ 0xF0, 0x00, 0xFA, 0x01, 0x29, 0x01, 0x29, 0x01, 0xBA, 0x01, 0xB0, 0x00 } },
+    { 137, 6, 11, 0, 0, 0, 0, (const char[]){ 0xF0, 0x00, 0xFA, 0x01, 0x28, 0x01, 0x28, 0x01, 0xBA, 0x01, 0xB0, 0x00 } },
+    { 138, 6, 11, 0, 0, 0, 0, (const char[]){ 0xF0, 0x00, 0xF8, 0x01, 0x29, 0x01, 0x2A, 0x01, 0xB8, 0x01, 0xB0, 0x00 } },
+    { 139, 4, 11, 0, 0, 0, 0, (const char[]){ 0x02, 0x00, 0xF8, 0x01, 0xF8, 0x01, 0x02, 0x00 } },
+    { 140, 4, 11, 0, 0, 0, 0, (const char[]){ 0x02, 0x00, 0xF9, 0x01, 0xF9, 0x01, 0x02, 0x00 } },
+    { 141, 2, 11, 0, 0, 0, 0, (const char[]){ 0xF9, 0x01, 0xFA, 0x01 } },
+    { 142, 7, 11, 0, 0, 0, 0, (const char[]){ 0xFC, 0x01, 0xFE, 0x01, 0x43, 0x00, 0x42, 0x00, 0x43, 0x00, 0xFE, 0x01, 0xFC, 0x01 } },
+    { 143, 7, 11, 0, 0, 0, 0, (const char[]){ 0xFC, 0x01, 0xFE, 0x01, 0x42, 0x00, 0x43, 0x00, 0x42, 0x00, 0xFE, 0x01, 0xFC, 0x01 } },
+    { 144, 7, 11, 0, 0, 0, 0, (const char[]){ 0xFE, 0x01, 0xFE, 0x01, 0x12, 0x01, 0x12, 0x01, 0x13, 0x01, 0x03, 0x01, 0x02, 0x01 } },
+    { 145, 8, 11, 1, 0, 0, 0, (const char[]){ 0xC0, 0x00, 0xE8, 0x01, 0x28, 0x01, 0xF0, 0x01, 0xF0, 0x01, 0x28, 0x01, 0x38, 0x01, 0xB0, 0x00 } },
+    { 146, 9, 11, 0, 0, 0, 0, (const char[]){ 0xF8, 0x01, 0xFC, 0x01, 0x46, 0x00, 0x46, 0x00, 0xFE, 0x01, 0xFE, 0x01, 0x12, 0x01, 0x12, 0x01, 0x02, 0x01 } },
+    { 147, 6, 11, 0, 0, 0, 0, (const char[]){ 0xF0, 0x00, 0xFA, 0x01, 0x09, 0x01, 0x09, 0x01, 0xFA, 0x01, 0xF0, 0x00 } },
+    { 148, 6, 11, 0, 0, 0, 0, (const char[]){ 0xF0, 0x00, 0xFA, 0x01, 0x08, 0x01, 0x08, 0x01, 0xFA, 0x01, 0xF0, 0x00 } },
+    { 149, 6, 11, 0, 0, 0, 0, (const char[]){ 0xF0, 0x00, 0xF8, 0x01, 0x09, 0x01, 0x0A, 0x01, 0xF8, 0x01, 0xF0, 0x00 } },
+    { 150, 6, 11, 0, 1, 0, 0, (const char[]){ 0xF8, 0x00, 0xFA, 0x01, 0x01, 0x01, 0xFA, 0x01, 0xF8, 0x01, 0x00, 0x01 } },
+    { 151, 6, 11, 0, 1, 0, 0, (const char[]){ 0xF8, 0x00, 0xF8, 0x01, 0x01, 0x01, 0xFA, 0x01, 0xF8, 0x01, 0x00, 0x01 } },
+    { 152, 5, 11, 0, 0, 0, 0, (const char[]){ 0xF8, 0x04, 0xFA, 0x05, 0x00, 0x05, 0xFA, 0x07, 0xF8, 0x03 } },
+    { 153, 7, 11, 0, 0, 0, 0, (const char[]){ 0xFC, 0x00, 0xFF, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xFC, 0x00 } },
+    { 154, 7, 11, 0, 0, 0, 0, (const char[]){ 0xFE, 0x00, 0xFD, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0xFD, 0x01, 0xFE, 0x00 } },
+    { 155, 7, 11, 0, 0, 0, 0, (const char[]){ 0xF0, 0x00, 0xF8, 0x01, 0x08, 0x01, 0x0E, 0x07, 0x08, 0x01, 0x98, 0x01, 0x90, 0x00 } },
+    { 156, 6, 11, 0, 0, 0, 0, (const char[]){ 0x14, 0x01, 0xFE, 0x01, 0xFA, 0x01, 0x12, 0x01, 0x06, 0x01, 0x04, 0x01 } },
+    { 157, 7, 11, 0, 0, 0, 0, (const char[]){ 0x28, 0x00, 0x3E, 0x00, 0x7E, 0x00, 0xE8, 0x01, 0x7E, 0x00, 0x3E, 0x00, 0x28, 0x00 } },
+    { 158, 7, 11, 0, 0, 0, 0, (const char[]){ 0x28, 0x00, 0xFC, 0x00, 0xEE, 0x01, 0x2A, 0x01, 0x2A, 0x01, 0x02, 0x01, 0x84, 0x00 } },
+    { 159, 6, 11, 0, 0, 0, 1, (const char[]){ 0x10, 0x01, 0xFC, 0x01, 0xFE, 0x00, 0x12, 0x00, 0x06, 0x00, 0x04, 0x00 } },
+    { 160, 6, 11, 0, 0, 0, 0, (const char[]){ 0xC0, 0x00, 0xE8, 0x01, 0x2A, 0x01, 0x29, 0x01, 0xF8, 0x01, 0xF8, 0x01 } },
+    { 161, 2, 11, 0, 0, 0, 0, (const char[]){ 0xFA, 0x01, 0xF9, 0x01 } },
+    { 162, 6, 11, 0, 0, 0, 0, (const char[]){ 0xF0, 0x00, 0xF8, 0x01, 0x0A, 0x01, 0x09, 0x01, 0xF8, 0x01, 0xF0, 0x00 } },
+    { 163, 6, 11, 0, 0, 0, 0, (const char[]){ 0xF8, 0x00, 0xF8, 0x01, 0x02, 0x01, 0xF9, 0x01, 0xF8, 0x01, 0x00, 0x01 } },
+    { 164, 6, 11, 0, 0, 0, 0, (const char[]){ 0x08, 0x00, 0xF9, 0x01, 0xF9, 0x01, 0x0A, 0x00, 0xFA, 0x01, 0xF0, 0x01 } },
+    { 165, 8, 11, 0, 0, 0, 0, (const char[]){ 0xFE, 0x01, 0xFE, 0x01, 0x07, 0x00, 0x19, 0x00, 0x62, 0x00, 0x82, 0x01, 0xFE, 0x01, 0xFE, 0x01 } },
+    { 166, 5, 11, 0, 0, 1, 1, (const char[]){ 0x06, 0x00, 0x0F, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x0E, 0x00 } },
+    { 167, 5, 11, 0, 0, 1, 1, (const char[]){ 0x06, 0x00, 0x0F, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x06, 0x00 } },
+    { 168, 6, 11, 1, 1, 0, 0, (const char[]){ 0x00, 0x03, 0x80, 0x07, 0xD8, 0x04, 0x58, 0x04, 0x00, 0x06, 0x00, 0x02 } },
+    { 169, 6, 11, 0, 0, 0, 0, (const char[]){ 0xE0, 0x01, 0xE0, 0x01, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00 } },
+    { 170, 6, 11, 0, 0, 0, 0, (const char[]){ 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0xE0, 0x01, 0xE0, 0x01 } },
+    { 171, 8, 11, 0, 0, 0, 0, (const char[]){ 0x9C, 0x00, 0xDC, 0x00, 0x60, 0x00, 0x30, 0x00, 0x58, 0x02, 0x2C, 0x03, 0xE4, 0x03, 0xC0, 0x02 } },
+    { 172, 8, 11, 0, 0, 0, 0, (const char[]){ 0x9C, 0x00, 0xDC, 0x00, 0x60, 0x00, 0x30, 0x00, 0x98, 0x01, 0x4C, 0x01, 0xE4, 0x03, 0xE0, 0x03 } },
+    { 173, 2, 11, 0, 0, 0, 0, (const char[]){ 0xFA, 0x03, 0xFA, 0x03 } },
+    { 174, 7, 11, 0, 0, 0, 0, (const char[]){ 0x20, 0x00, 0x70, 0x00, 0xD8, 0x00, 0xAC, 0x01, 0x70, 0x00, 0xD8, 0x00, 0x8C, 0x01 } },
+    { 175, 7, 11, 0, 0, 0, 0, (const char[]){ 0x8C, 0x01, 0xD8, 0x00, 0x70, 0x00, 0xAC, 0x01, 0xD8, 0x00, 0x70, 0x00, 0x20, 0x00 } },
+    { 176, 4, 11, 0, 0, 0, 0, (const char[]){ 0x00, 0x00, 0x55, 0x05, 0x00, 0x00, 0xAA, 0x0A } },
+    { 177, 4, 11, 0, 0, 0, 0, (const char[]){ 0x55, 0x05, 0xAA, 0x0A, 0x55, 0x05, 0xAA, 0x0A } },
+    { 178, 4, 11, 0, 0, 0, 0, (const char[]){ 0xFF, 0x0F, 0xAA, 0x0A, 0xFF, 0x0F, 0x55, 0x05 } },
+    { 179, 9, 11, 0, 0, 0, 0, (const char[]){ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
+    { 180, 9, 11, 0, 0, 0, 0, (const char[]){ 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
+    { 181, 9, 11, 0, 0, 0, 0, (const char[]){ 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
+    { 182, 9, 11, 0, 0, 0, 0, (const char[]){ 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0xFF, 0x0F, 0x00, 0x00, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
+    { 183, 9, 11, 0, 0, 0, 0, (const char[]){ 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0xE0, 0x0F, 0x20, 0x00, 0xE0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
+    { 184, 9, 11, 0, 0, 0, 0, (const char[]){ 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0xF0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
+    { 185, 9, 11, 0, 0, 0, 0, (const char[]){ 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0xDF, 0x0F, 0x00, 0x00, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
+    { 186, 9, 11, 0, 0, 0, 0, (const char[]){ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x0F, 0x00, 0x00, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
+    { 187, 9, 11, 0, 0, 0, 0, (const char[]){ 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0xD0, 0x0F, 0x10, 0x00, 0xF0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
+    { 188, 9, 11, 0, 0, 0, 0, (const char[]){ 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x5F, 0x00, 0x40, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
+    { 189, 9, 11, 0, 0, 0, 0, (const char[]){ 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x3F, 0x00, 0x20, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
+    { 190, 9, 11, 0, 0, 0, 0, (const char[]){ 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
+    { 191, 9, 11, 0, 0, 0, 0, (const char[]){ 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0xE0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
+    { 192, 9, 11, 0, 0, 0, 0, (const char[]){ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00 } },
+    { 193, 9, 11, 0, 0, 0, 0, (const char[]){ 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x3F, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00 } },
+    { 194, 9, 11, 0, 0, 0, 0, (const char[]){ 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0xE0, 0x0F, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00 } },
+    { 195, 9, 11, 0, 0, 0, 0, (const char[]){ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x0F, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00 } },
+    { 196, 9, 11, 0, 0, 0, 0, (const char[]){ 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00 } },
+    { 197, 9, 11, 0, 0, 0, 0, (const char[]){ 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0xFF, 0x0F, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00 } },
+    { 198, 9, 11, 0, 0, 0, 0, (const char[]){ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x0F, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00 } },
+    { 199, 9, 11, 0, 0, 0, 0, (const char[]){ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x0F, 0x00, 0x00, 0xFF, 0x0F, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00 } },
+    { 200, 9, 11, 0, 0, 0, 0, (const char[]){ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x40, 0x00, 0x5F, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00 } },
+    { 201, 9, 11, 0, 0, 0, 0, (const char[]){ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x0F, 0x10, 0x00, 0xD0, 0x0F, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00 } },
+    { 202, 9, 11, 0, 0, 0, 0, (const char[]){ 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x5F, 0x00, 0x40, 0x00, 0x5F, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00 } },
+    { 203, 9, 11, 0, 0, 0, 0, (const char[]){ 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0xD0, 0x0F, 0x10, 0x00, 0xD0, 0x0F, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00 } },
+    { 204, 9, 11, 0, 0, 0, 0, (const char[]){ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x0F, 0x00, 0x00, 0xDF, 0x0F, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00 } },
+    { 205, 9, 11, 0, 0, 0, 0, (const char[]){ 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00 } },
+    { 206, 9, 11, 0, 0, 0, 0, (const char[]){ 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0xDF, 0x0F, 0x00, 0x00, 0xDF, 0x0F, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00 } },
+    { 207, 9, 11, 0, 0, 0, 0, (const char[]){ 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x5F, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00 } },
+    { 208, 9, 11, 0, 0, 0, 0, (const char[]){ 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x3F, 0x00, 0x20, 0x00, 0x3F, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00 } },
+    { 209, 9, 11, 0, 0, 0, 0, (const char[]){ 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0xD0, 0x0F, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00 } },
+    { 210, 9, 11, 0, 0, 0, 0, (const char[]){ 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0xE0, 0x0F, 0x20, 0x00, 0xE0, 0x0F, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00 } },
+    { 211, 9, 11, 0, 0, 0, 0, (const char[]){ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x20, 0x00, 0x3F, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00 } },
+    { 212, 9, 11, 0, 0, 0, 0, (const char[]){ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00 } },
+    { 213, 9, 11, 0, 0, 0, 0, (const char[]){ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x0F, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00 } },
+    { 214, 9, 11, 0, 0, 0, 0, (const char[]){ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x0F, 0x20, 0x00, 0xE0, 0x0F, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00 } },
+    { 215, 9, 11, 0, 0, 0, 0, (const char[]){ 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0xFF, 0x0F, 0x20, 0x00, 0xFF, 0x0F, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00 } },
+    { 216, 9, 11, 0, 0, 0, 0, (const char[]){ 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0xFF, 0x0F, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00 } },
+    { 217, 9, 11, 0, 0, 0, 0, (const char[]){ 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
+    { 218, 9, 11, 0, 0, 0, 0, (const char[]){ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x0F, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00 } },
+    { 219, 8, 11, 0, 0, 0, 0, (const char[]){ 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F } },
+    { 220, 8, 11, 0, 0, 0, 0, (const char[]){ 0xC0, 0x0F, 0xC0, 0x0F, 0xC0, 0x0F, 0xC0, 0x0F, 0xC0, 0x0F, 0xC0, 0x0F, 0xC0, 0x0F, 0xC0, 0x0F } },
+    { 221, 4, 11, 0, 0, 0, 0, (const char[]){ 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F } },
+    { 222, 8, 11, 0, 0, 0, 0, (const char[]){ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F } },
+    { 223, 8, 11, 0, 0, 0, 0, (const char[]){ 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x00 } },
+    { 224, 8, 11, 0, 0, 0, 0, (const char[]){ 0xF0, 0x00, 0xF8, 0x01, 0x08, 0x01, 0x08, 0x01, 0xF8, 0x01, 0xF0, 0x00, 0x98, 0x01, 0x98, 0x01 } },
+    { 225, 8, 11, 0, 0, 0, 0, (const char[]){ 0x00, 0x02, 0xFE, 0x03, 0xFE, 0x01, 0x92, 0x00, 0x12, 0x01, 0x3E, 0x01, 0xEC, 0x01, 0xC0, 0x00 } },
+    { 226, 8, 11, 0, 0, 0, 0, (const char[]){ 0x08, 0x01, 0xF8, 0x01, 0xF8, 0x01, 0x08, 0x01, 0x08, 0x00, 0x08, 0x00, 0x18, 0x00, 0x18, 0x00 } },
+    { 227, 8, 11, 0, 0, 0, 0, (const char[]){ 0x08, 0x01, 0xF8, 0x01, 0xF8, 0x01, 0x08, 0x00, 0x08, 0x00, 0xF8, 0x01, 0xF8, 0x01, 0x08, 0x01 } },
+    { 228, 7, 11, 0, 0, 0, 0, (const char[]){ 0x86, 0x01, 0xCE, 0x01, 0x7A, 0x01, 0x32, 0x01, 0x02, 0x01, 0x86, 0x01, 0x86, 0x01 } },
+    { 229, 7, 11, 0, 0, 0, 0, (const char[]){ 0xF0, 0x00, 0xF8, 0x01, 0x08, 0x01, 0x08, 0x01, 0xF8, 0x01, 0xF8, 0x00, 0x18, 0x00 } },
+    { 230, 8, 11, 0, 0, 0, 0, (const char[]){ 0x08, 0x00, 0xF8, 0x07, 0xF8, 0x07, 0x00, 0x01, 0x00, 0x01, 0xF8, 0x00, 0xF8, 0x01, 0x08, 0x01 } },
+    { 231, 7, 11, 0, 0, 0, 0, (const char[]){ 0x02, 0x00, 0x02, 0x00, 0xFE, 0x00, 0xFE, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01 } },
+    { 232, 8, 11, 0, 0, 0, 0, (const char[]){ 0x30, 0x00, 0x78, 0x00, 0x4A, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0x4A, 0x01, 0x78, 0x00, 0x30, 0x00 } },
+    { 233, 9, 11, 0, 0, 0, 0, (const char[]){ 0xFC, 0x00, 0x02, 0x01, 0x7A, 0x01, 0x7A, 0x01, 0x22, 0x01, 0x7A, 0x01, 0x7A, 0x01, 0x02, 0x01, 0xFC, 0x00 } },
+    { 234, 8, 11, 0, 0, 0, 0, (const char[]){ 0x7C, 0x01, 0xFE, 0x01, 0x82, 0x01, 0x02, 0x00, 0x02, 0x00, 0x82, 0x01, 0xFE, 0x01, 0x7C, 0x01 } },
+    { 235, 6, 11, 0, 0, 0, 0, (const char[]){ 0xF6, 0x00, 0xFE, 0x01, 0x0A, 0x01, 0x0A, 0x01, 0xFA, 0x01, 0xFA, 0x00 } },
+    { 236, 8, 11, 0, 0, 0, 0, (const char[]){ 0xF0, 0x00, 0xF8, 0x01, 0x08, 0x01, 0xF8, 0x01, 0xF8, 0x01, 0x08, 0x01, 0xF8, 0x01, 0xF0, 0x00 } },
+    { 237, 8, 11, 0, 0, 0, 0, (const char[]){ 0xF0, 0x00, 0xF0, 0x01, 0x00, 0x01, 0xFC, 0x07, 0xFE, 0x07, 0x02, 0x01, 0xFE, 0x01, 0xFC, 0x00 } },
+    { 238, 7, 11, 0, 0, 0, 0, (const char[]){ 0x90, 0x00, 0x98, 0x01, 0x68, 0x01, 0x68, 0x01, 0x08, 0x01, 0x98, 0x01, 0x90, 0x00 } },
+    { 239, 7, 11, 0, 0, 0, 0, (const char[]){ 0xFC, 0x01, 0xFE, 0x01, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xFE, 0x01, 0xFC, 0x01 } },
+    { 240, 6, 11, 0, 0, 0, 0, (const char[]){ 0xA8, 0x00, 0xA8, 0x00, 0xA8, 0x00, 0xA8, 0x00, 0xA8, 0x00, 0xA8, 0x00 } },
+    { 241, 6, 11, 0, 0, 0, 0, (const char[]){ 0x10, 0x01, 0x10, 0x01, 0x7C, 0x01, 0x7C, 0x01, 0x10, 0x01, 0x10, 0x01 } },
+    { 242, 5, 11, 0, 0, 0, 0, (const char[]){ 0x82, 0x02, 0xC6, 0x02, 0x6C, 0x02, 0x38, 0x02, 0x10, 0x02 } },
+    { 243, 5, 11, 0, 0, 0, 0, (const char[]){ 0x10, 0x02, 0x38, 0x02, 0x6C, 0x02, 0xC6, 0x02, 0x82, 0x02 } },
+    { 244, 8, 11, 0, 0, 0, 2, (const char[]){ 0x00, 0x00, 0x00, 0x00, 0xFC, 0x0F, 0xFE, 0x0F, 0x03, 0x00, 0x03, 0x00, 0x06, 0x00, 0x04, 0x00 } },
+    { 245, 4, 11, 0, 0, 0, 0, (const char[]){ 0x00, 0x06, 0x00, 0x06, 0xFF, 0x07, 0xFF, 0x03 } },
+    { 246, 6, 11, 0, 0, 0, 0, (const char[]){ 0x20, 0x00, 0x20, 0x00, 0xAC, 0x01, 0xAC, 0x01, 0x20, 0x00, 0x20, 0x00 } },
+    { 247, 5, 11, 0, 0, 0, 0, (const char[]){ 0x90, 0x00, 0x48, 0x00, 0x90, 0x00, 0x20, 0x01, 0x90, 0x00 } },
+    { 248, 5, 11, 0, 0, 0, 0, (const char[]){ 0x0E, 0x00, 0x1F, 0x00, 0x11, 0x00, 0x1F, 0x00, 0x0E, 0x00 } },
+    { 249, 5, 11, 0, 0, 0, 0, (const char[]){ 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x30, 0x00, 0x00, 0x00 } },
+    { 250, 7, 11, 0, 0, 0, 0, (const char[]){ 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x78, 0x00, 0x78, 0x00, 0x30, 0x00, 0x00, 0x00 } },
+    { 251, 9, 11, 0, 2, 0, 3, (const char[]){ 0x02, 0x00, 0xFE, 0x03, 0xFE, 0x00, 0x30, 0x00, 0x0C, 0x00, 0x03, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00 } },
+    { 252, 6, 11, 0, 0, 1, 1, (const char[]){ 0x02, 0x00, 0x1E, 0x00, 0x1F, 0x00, 0x01, 0x00, 0x1F, 0x00, 0x1E, 0x00 } },
+    { 253, 6, 11, 0, 0, 1, 1, (const char[]){ 0x12, 0x00, 0x1B, 0x00, 0x19, 0x00, 0x15, 0x00, 0x17, 0x00, 0x12, 0x00 } },
+    { 254, 7, 11, 0, 0, 0, 0, (const char[]){ 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x78, 0x00, 0x78, 0x00, 0x78, 0x00, 0x00, 0x00 } },
+    { 255, 6, 11, 0, 0, 0, 0, (const char[]){ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }
+};
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Doggy/xfont_8.h	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,231 @@
+#ifndef XFONT_8_H
+#define XFONT_8_H
+
+const XGlyph xfont_8[] = {
+    {  0, 5, 8, 0, 0, 0, 0, (const char[]){ 0xFF, 0x81, 0x81, 0x81, 0xFF } },
+    { 32, 2, 8, 0, 0, 0, 0, (const char[]){ 0x00, 0x00 } },
+    { 33, 1, 8, 0, 0, 0, 0, (const char[]){ 0x2F } },                         //  !
+    { 34, 3, 8, 0, 0, 1, 1, (const char[]){ 0x03, 0x00, 0x03 } },             //  "
+    { 35, 5, 8, 0, 0, 0, 0, (const char[]){ 0x14, 0x3E, 0x14, 0x3E, 0x14 } }, //  #
+    { 36, 5, 8, 0, 0, 0, 0, (const char[]){ 0x24, 0x6A, 0x3E, 0x2B, 0x12 } }, //  $
+    { 37, 5, 8, 0, 0, 0, 0, (const char[]){ 0x22, 0x10, 0x08, 0x04, 0x22 } }, //  %
+    { 38, 5, 8, 0, 0, 0, 0, (const char[]){ 0x14, 0x2A, 0x2A, 0x14, 0x20 } }, //  &
+    { 39, 1, 8, 0, 0, 1, 1, (const char[]){ 0x03 } },                         //  '
+    { 40, 2, 8, 0, 0, 0, 0, (const char[]){ 0x1E, 0x21 } },                   //  (
+    { 41, 2, 8, 0, 0, 0, 0, (const char[]){ 0x21, 0x1E } },                   //  )
+    { 42, 5, 8, 0, 0, 0, 0, (const char[]){ 0x14, 0x08, 0x3E, 0x08, 0x14 } }, //  *
+    { 43, 5, 8, 0, 0, 0, 0, (const char[]){ 0x08, 0x08, 0x3E, 0x08, 0x08 } }, //  +
+    { 44, 4, 8, 2, 0, 1, 0, (const char[]){ 0x00, 0x80, 0x70, 0x30 } },       //  ,
+    { 45, 5, 8, 0, 0, 0, 0, (const char[]){ 0x08, 0x08, 0x08, 0x08, 0x08 } }, //  -
+    { 46, 5, 8, 2, 0, 0, 0, (const char[]){ 0x00, 0x00, 0x30, 0x30, 0x00 } }, //  .
+    { 47, 5, 8, 0, 0, 0, 0, (const char[]){ 0x20, 0x10, 0x08, 0x04, 0x02 } }, //  /
+    { 48, 5, 8, 0, 0, 0, 0, (const char[]){ 0x1E, 0x31, 0x2D, 0x23, 0x1E } }, //  0
+    { 49, 5, 8, 0, 0, 0, 0, (const char[]){ 0x00, 0x00, 0x02, 0x3F, 0x00 } }, //  1
+    { 50, 5, 8, 0, 0, 0, 0, (const char[]){ 0x22, 0x31, 0x29, 0x25, 0x22 } }, //  2
+    { 51, 5, 8, 0, 0, 0, 0, (const char[]){ 0x12, 0x21, 0x25, 0x25, 0x1A } }, //  3
+    { 52, 5, 8, 0, 0, 0, 0, (const char[]){ 0x18, 0x14, 0x12, 0x3F, 0x10 } }, //  4
+    { 53, 5, 8, 0, 0, 0, 0, (const char[]){ 0x17, 0x25, 0x25, 0x25, 0x19 } }, //  5
+    { 54, 5, 8, 0, 0, 0, 0, (const char[]){ 0x1E, 0x25, 0x25, 0x25, 0x18 } }, //  6
+    { 55, 5, 8, 0, 0, 0, 0, (const char[]){ 0x01, 0x01, 0x39, 0x05, 0x03 } }, //  7
+    { 56, 5, 8, 0, 0, 0, 0, (const char[]){ 0x1A, 0x25, 0x25, 0x25, 0x1A } }, //  8
+    { 57, 5, 8, 0, 0, 0, 0, (const char[]){ 0x06, 0x29, 0x29, 0x29, 0x1E } }, //  9
+    { 58, 4, 8, 2, 0, 2, 0, (const char[]){ 0x00, 0x00, 0x36, 0x36 } },       //  :
+    { 59, 4, 8, 2, 0, 1, 0, (const char[]){ 0x00, 0x80, 0x76, 0x36 } },       //  ;
+    { 60, 6, 8, 0, 0, 0, 0, (const char[]){ 0x08, 0x08, 0x14, 0x14, 0x22, 0x22 } }, //  <
+    { 61, 5, 8, 0, 0, 0, 0, (const char[]){ 0x14, 0x14, 0x14, 0x14, 0x14 } }, //  =
+    { 62, 6, 8, 0, 0, 0, 0, (const char[]){ 0x22, 0x22, 0x14, 0x14, 0x08, 0x08 } }, //  >
+    { 63, 5, 8, 0, 0, 0, 0, (const char[]){ 0x02, 0x01, 0x29, 0x05, 0x02 } }, //  ?
+    { 64, 6, 8, 0, 0, 0, 0, (const char[]){ 0x3E, 0x41, 0x5D, 0x55, 0x5E, 0x20 } }, //  @
+    { 65, 5, 8, 0, 0, 0, 0, (const char[]){ 0x3E, 0x09, 0x09, 0x09, 0x3E } }, //  
+    { 66, 5, 8, 0, 0, 0, 0, (const char[]){ 0x3F, 0x25, 0x25, 0x25, 0x1A } }, //  
+    { 67, 5, 8, 0, 0, 0, 0, (const char[]){ 0x1E, 0x21, 0x21, 0x21, 0x12 } }, //  
+    { 68, 5, 8, 0, 0, 0, 0, (const char[]){ 0x3F, 0x21, 0x21, 0x22, 0x1C } }, //  
+    { 69, 5, 8, 0, 0, 0, 0, (const char[]){ 0x3F, 0x25, 0x25, 0x25, 0x21 } }, //  
+    { 70, 5, 8, 0, 0, 0, 2, (const char[]){ 0x3F, 0x05, 0x05, 0x05, 0x01 } }, //  
+    { 71, 5, 8, 0, 0, 0, 0, (const char[]){ 0x1E, 0x21, 0x21, 0x29, 0x1A } }, //  
+    { 72, 5, 8, 0, 0, 0, 0, (const char[]){ 0x3F, 0x04, 0x04, 0x04, 0x3F } }, //  
+    { 73, 3, 8, 0, 0, 0, 0, (const char[]){ 0x21, 0x3F, 0x21 } },             //  I
+    { 74, 5, 8, 1, 0, 0, 0, (const char[]){ 0x18, 0x20, 0x21, 0x1F, 0x01 } }, //  
+    { 75, 5, 8, 0, 0, 0, 0, (const char[]){ 0x3F, 0x04, 0x04, 0x0A, 0x31 } }, //  
+    { 76, 5, 8, 0, 1, 0, 0, (const char[]){ 0x3F, 0x20, 0x20, 0x20, 0x20 } }, //  
+    { 77, 5, 8, 0, 0, 0, 0, (const char[]){ 0x3F, 0x02, 0x04, 0x02, 0x3F } }, //  
+    { 78, 5, 8, 0, 0, 0, 0, (const char[]){ 0x3F, 0x02, 0x04, 0x08, 0x3F } }, //  
+    { 79, 5, 8, 0, 0, 0, 0, (const char[]){ 0x1E, 0x21, 0x21, 0x21, 0x1E } }, //  
+    { 80, 5, 8, 0, 0, 0, 1, (const char[]){ 0x3F, 0x09, 0x09, 0x09, 0x06 } }, //  
+    { 81, 5, 8, 0, 0, 0, 0, (const char[]){ 0x1E, 0x21, 0x29, 0x31, 0x3E } }, //  
+    { 82, 5, 8, 0, 0, 0, 0, (const char[]){ 0x3F, 0x09, 0x09, 0x19, 0x26 } }, //  
+    { 83, 5, 8, 0, 0, 0, 0, (const char[]){ 0x12, 0x25, 0x25, 0x25, 0x1A } }, //  
+    { 84, 5, 8, 0, 0, 2, 2, (const char[]){ 0x01, 0x01, 0x3F, 0x01, 0x01 } }, //  
+    { 85, 5, 8, 0, 0, 0, 0, (const char[]){ 0x1F, 0x20, 0x20, 0x20, 0x1F } }, //  
+    { 86, 5, 8, 0, 0, 0, 0, (const char[]){ 0x03, 0x0C, 0x30, 0x0C, 0x03 } }, //  
+    { 87, 5, 8, 0, 0, 0, 0, (const char[]){ 0x1F, 0x20, 0x18, 0x20, 0x1F } }, //  
+    { 88, 5, 8, 0, 0, 0, 0, (const char[]){ 0x21, 0x12, 0x0C, 0x12, 0x21 } }, //  
+    { 89, 5, 8, 0, 0, 1, 1, (const char[]){ 0x03, 0x04, 0x38, 0x04, 0x03 } }, //  
+    { 90, 5, 8, 0, 0, 0, 0, (const char[]){ 0x31, 0x29, 0x25, 0x23, 0x21 } }, //  
+    { 91, 4, 8, 1, 0, 1, 0, (const char[]){ 0x00, 0x3F, 0x21, 0x21 } }, //  
+    { 92, 5, 8, 0, 0, 1, 0, (const char[]){ 0x02, 0x04, 0x08, 0x10, 0x20 } }, //  
+    { 93, 5, 8, 2, 0, 2, 0, (const char[]){ 0x00, 0x00, 0x21, 0x21, 0x3F } }, //  
+    { 94, 5, 8, 0, 0, 0, 0, (const char[]){ 0x04, 0x02, 0x01, 0x02, 0x04 } }, //  
+    { 95, 5, 8, 0, 0, 0, 0, (const char[]){ 0x20, 0x20, 0x20, 0x20, 0x20 } }, //  
+    { 96, 4, 8, 1, 0, 2, 0, (const char[]){ 0x00, 0x01, 0x03, 0x04 } }, //  
+    { 97, 4, 8, 1, 0, 0, 0, (const char[]){ 0x10, 0x2A, 0x2A, 0x3C } }, //  
+    { 98, 4, 8, 0, 0, 0, 0, (const char[]){ 0x3F, 0x24, 0x22, 0x1C } }, //  
+    { 99, 4, 8, 0, 0, 0, 0, (const char[]){ 0x1C, 0x22, 0x22, 0x14 } }, //  
+    { 100, 4, 8, 0, 0, 0, 0, (const char[]){ 0x1C, 0x22, 0x24, 0x3F } }, //  
+    { 101, 4, 8, 0, 0, 0, 0, (const char[]){ 0x1C, 0x2A, 0x2A, 0x2C } }, //  
+    { 102, 4, 8, 0, 0, 0, 1, (const char[]){ 0x3E, 0x09, 0x01, 0x02 } }, //  
+    { 103, 4, 8, 0, 0, 0, 0, (const char[]){ 0x0C, 0x52, 0x4A, 0x3C } }, //  
+    { 104, 4, 8, 0, 0, 1, 0, (const char[]){ 0x3F, 0x04, 0x02, 0x3C } }, //  
+    { 105, 1, 8, 0, 0, 0, 0, (const char[]){ 0x3D } }, //  i
+    { 106, 3, 8, 1, 0, 0, 0, (const char[]){ 0x40, 0x40, 0x3D } }, //  
+    { 107, 4, 8, 0, 0, 0, 0, (const char[]){ 0x3F, 0x08, 0x0C, 0x32 } }, //  
+    { 108, 1, 8, 0, 0, 0, 0, (const char[]){ 0x3F } }, //  l
+    { 109, 5, 8, 0, 0, 0, 0, (const char[]){ 0x3C, 0x02, 0x3C, 0x02, 0x3C } }, //  
+    { 110, 4, 8, 0, 0, 0, 0, (const char[]){ 0x3C, 0x02, 0x02, 0x3C } }, //  
+    { 111, 4, 8, 1, 1, 0, 0, (const char[]){ 0x1C, 0x22, 0x22, 0x1C } }, //  
+    { 112, 4, 8, 0, 0, 0, 0, (const char[]){ 0x7E, 0x22, 0x22, 0x1C } }, //  
+    { 113, 4, 8, 0, 0, 0, 0, (const char[]){ 0x1C, 0x22, 0x22, 0x7E } }, //  
+    { 114, 4, 8, 0, 0, 0, 1, (const char[]){ 0x02, 0x3C, 0x02, 0x02 } }, //  
+    { 115, 4, 8, 0, 0, 0, 0, (const char[]){ 0x24, 0x2A, 0x2A, 0x12 } }, //  
+    { 116, 4, 8, 0, 0, 1, 0, (const char[]){ 0x02, 0x1F, 0x22, 0x22 } }, //  
+    { 117, 4, 8, 0, 0, 0, 0, (const char[]){ 0x1E, 0x20, 0x20, 0x3E } }, //  
+    { 118, 5, 8, 0, 0, 0, 0, (const char[]){ 0x06, 0x18, 0x20, 0x3C, 0x02 } }, //  
+    { 119, 5, 8, 0, 0, 0, 0, (const char[]){ 0x1E, 0x20, 0x1C, 0x20, 0x1E } }, //  
+    { 120, 5, 8, 0, 0, 0, 0, (const char[]){ 0x22, 0x14, 0x08, 0x14, 0x22 } }, //  
+    { 121, 4, 8, 0, 0, 0, 0, (const char[]){ 0x0E, 0x50, 0x50, 0x3E } }, //  
+    { 122, 4, 8, 0, 0, 0, 0, (const char[]){ 0x22, 0x32, 0x2A, 0x26 } }, //  
+    { 123, 4, 8, 1, 0, 1, 0, (const char[]){ 0x00, 0x08, 0x36, 0x41 } }, //  
+    { 124, 3, 8, 2, 0, 2, 0, (const char[]){ 0x00, 0x00, 0x7F } }, //  
+    { 125, 4, 8, 1, 0, 1, 0, (const char[]){ 0x00, 0x41, 0x36, 0x08 } }, //  
+    { 126, 5, 8, 0, 0, 0, 0, (const char[]){ 0x08, 0x04, 0x08, 0x10, 0x08 } }, //  
+    { 127, 4, 8, 0, 1, 0, 1, (const char[]){ 0x2A, 0x55, 0x2A, 0x55 } }, //  
+    { 128, 5, 8, 0, 0, 0, 0, (const char[]){ 0x1E, 0xA1, 0x61, 0x21, 0x12 } }, //  
+    { 129, 4, 8, 0, 0, 0, 0, (const char[]){ 0x1D, 0x20, 0x20, 0x3D } }, //  
+    { 130, 4, 8, 0, 0, 0, 0, (const char[]){ 0x1C, 0x2A, 0x2B, 0x2D } }, //  
+    { 131, 4, 8, 0, 0, 0, 0, (const char[]){ 0x11, 0x2B, 0x2B, 0x3D } }, //  
+    { 132, 4, 8, 0, 0, 0, 0, (const char[]){ 0x11, 0x2A, 0x2A, 0x3D } }, //  
+    { 133, 4, 8, 0, 0, 0, 0, (const char[]){ 0x11, 0x2B, 0x2A, 0x3C } }, //  
+    { 134, 4, 8, 0, 0, 0, 0, (const char[]){ 0x10, 0x2A, 0x2B, 0x3C } }, //  
+    { 135, 4, 8, 0, 0, 0, 0, (const char[]){ 0x1C, 0xA2, 0x62, 0x14 } }, //  
+    { 136, 4, 8, 0, 0, 0, 0, (const char[]){ 0x1D, 0x2B, 0x2B, 0x2D } }, //  
+    { 137, 4, 8, 0, 0, 0, 0, (const char[]){ 0x1D, 0x2A, 0x2A, 0x2D } }, //  
+    { 138, 4, 8, 0, 0, 0, 0, (const char[]){ 0x1D, 0x2B, 0x2A, 0x2C } }, //  
+    { 139, 3, 8, 0, 0, 1, 1, (const char[]){ 0x01, 0x3C, 0x01 } }, //  
+    { 140, 5, 8, 0, 0, 1, 1, (const char[]){ 0x02, 0x01, 0x3D, 0x01, 0x02 } }, //  
+    { 141, 3, 8, 0, 0, 1, 1, (const char[]){ 0x01, 0x3D, 0x02 } }, //  
+    { 142, 5, 8, 0, 0, 0, 0, (const char[]){ 0x3C, 0x13, 0x12, 0x13, 0x3C } }, //  
+    { 143, 5, 8, 0, 0, 0, 0, (const char[]){ 0x3C, 0x12, 0x13, 0x12, 0x3C } }, //  
+    { 144, 5, 8, 0, 0, 0, 0, (const char[]){ 0x3E, 0x2A, 0x2A, 0x2B, 0x23 } }, //  
+    { 145, 6, 8, 0, 0, 0, 0, (const char[]){ 0x10, 0x2A, 0x2A, 0x3C, 0x2A, 0x2C } }, //  
+    { 146, 6, 8, 0, 0, 0, 0, (const char[]){ 0x3E, 0x11, 0x11, 0x3F, 0x25, 0x25 } }, //  
+    { 147, 4, 8, 0, 0, 0, 0, (const char[]){ 0x1D, 0x23, 0x23, 0x1D } }, //  
+    { 148, 4, 8, 0, 0, 0, 0, (const char[]){ 0x1D, 0x22, 0x22, 0x1D } }, //  
+    { 149, 4, 8, 0, 0, 0, 0, (const char[]){ 0x1D, 0x23, 0x22, 0x1C } }, //  
+    { 150, 4, 8, 0, 0, 0, 0, (const char[]){ 0x1D, 0x21, 0x21, 0x3D } }, //  
+    { 151, 4, 8, 0, 0, 0, 0, (const char[]){ 0x1D, 0x21, 0x22, 0x3C } }, //  
+    { 152, 4, 8, 0, 0, 0, 0, (const char[]){ 0x0D, 0x50, 0x50, 0x3D } }, //  
+    { 153, 5, 8, 0, 0, 0, 0, (const char[]){ 0x1C, 0x23, 0x22, 0x23, 0x1C } }, //  
+    { 154, 5, 8, 0, 0, 0, 0, (const char[]){ 0x1E, 0x21, 0x20, 0x21, 0x1E } }, //  
+    { 155, 5, 8, 0, 0, 0, 0, (const char[]){ 0x1C, 0x22, 0x63, 0x22, 0x14 } }, //  
+    { 156, 5, 8, 0, 0, 0, 0, (const char[]){ 0x26, 0x39, 0x29, 0x21, 0x22 } }, //  
+    { 157, 5, 8, 0, 0, 0, 0, (const char[]){ 0x0A, 0x0F, 0x3A, 0x0F, 0x0A } }, //  
+    { 158, 6, 8, 0, 0, 0, 0, (const char[]){ 0x14, 0x3E, 0x55, 0x55, 0x41, 0x22 } }, //  
+    { 159, 5, 8, 0, 0, 0, 1, (const char[]){ 0x48, 0x3E, 0x09, 0x01, 0x02 } }, //  
+    { 160, 4, 8, 0, 0, 0, 0, (const char[]){ 0x10, 0x2A, 0x2B, 0x3D } }, //  
+    { 161, 4, 8, 1, 0, 2, 1, (const char[]){ 0x00, 0x02, 0x3D, 0x01 } }, //  
+    { 162, 4, 8, 0, 0, 0, 0, (const char[]){ 0x1C, 0x22, 0x23, 0x1D } }, //  
+    { 163, 4, 8, 0, 0, 0, 0, (const char[]){ 0x1C, 0x22, 0x21, 0x3C } }, //  
+    { 164, 5, 8, 0, 0, 0, 0, (const char[]){ 0x0A, 0x39, 0x05, 0x06, 0x3A } }, //  
+    { 165, 5, 8, 0, 0, 0, 0, (const char[]){ 0x3E, 0x05, 0x09, 0x12, 0x3F } }, //  
+    { 166, 5, 8, 1, 0, 2, 1, (const char[]){ 0x00, 0x05, 0x0B, 0x09, 0x0E } }, //  
+    { 167, 5, 8, 1, 0, 2, 1, (const char[]){ 0x00, 0x06, 0x09, 0x09, 0x06 } }, //  
+    { 168, 5, 8, 1, 1, 0, 0, (const char[]){ 0x20, 0x50, 0x4A, 0x40, 0x20 } }, //  
+    { 169, 5, 8, 1, 0, 1, 0, (const char[]){ 0x00, 0x38, 0x08, 0x08, 0x08 } }, //  
+    { 170, 5, 8, 1, 0, 1, 0, (const char[]){ 0x00, 0x08, 0x08, 0x08, 0x38 } }, //  
+    { 171, 5, 8, 0, 0, 0, 0, (const char[]){ 0x11, 0x0F, 0x4C, 0x6A, 0x51 } }, //  
+    { 172, 5, 8, 0, 0, 0, 0, (const char[]){ 0x11, 0x0F, 0x3C, 0x22, 0x71 } }, //  
+    { 173, 3, 8, 2, 0, 2, 0, (const char[]){ 0x00, 0x00, 0x3D } }, //  
+    { 174, 6, 8, 0, 0, 0, 0, (const char[]){ 0x08, 0x14, 0x22, 0x08, 0x14, 0x22 } }, //  
+    { 175, 6, 8, 0, 0, 0, 0, (const char[]){ 0x22, 0x14, 0x08, 0x22, 0x14, 0x08 } }, //  
+    { 176, 4, 8, 0, 1, 0, 1, (const char[]){ 0x55, 0x00, 0x55, 0x00 } }, //  
+    { 177, 4, 8, 0, 1, 0, 1, (const char[]){ 0x55, 0xAA, 0x55, 0xAA } }, //  
+    { 178, 4, 8, 0, 1, 0, 1, (const char[]){ 0xFF, 0xAA, 0xFF, 0xAA } }, //  
+    { 179, 7, 8, 0, 1, 0, 1, (const char[]){ 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00 } }, //  
+    { 180, 7, 8, 0, 1, 0, 1, (const char[]){ 0x08, 0x08, 0x08, 0xFF, 0x00, 0x00, 0x00 } }, //  
+    { 181, 7, 8, 0, 1, 0, 1, (const char[]){ 0x14, 0x14, 0x14, 0xFF, 0x00, 0x00, 0x00 } }, //  
+    { 182, 7, 8, 0, 1, 0, 1, (const char[]){ 0x08, 0x08, 0xFF, 0x00, 0xFF, 0x00, 0x00 } }, //  
+    { 183, 7, 8, 0, 1, 0, 1, (const char[]){ 0x08, 0x08, 0xF8, 0x08, 0xF8, 0x00, 0x00 } }, //  
+    { 184, 7, 8, 0, 1, 0, 1, (const char[]){ 0x14, 0x14, 0x14, 0xFC, 0x00, 0x00, 0x00 } }, //  
+    { 185, 7, 8, 0, 1, 0, 1, (const char[]){ 0x14, 0x14, 0xF7, 0x00, 0xFF, 0x00, 0x00 } }, //  
+    { 186, 7, 8, 0, 1, 0, 1, (const char[]){ 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00 } }, //  
+    { 187, 7, 8, 0, 1, 0, 1, (const char[]){ 0x14, 0x14, 0xF4, 0x04, 0xFC, 0x00, 0x00 } }, //  
+    { 188, 7, 8, 0, 1, 0, 1, (const char[]){ 0x14, 0x14, 0x17, 0x10, 0x1F, 0x00, 0x00 } }, //  
+    { 189, 7, 8, 0, 1, 0, 1, (const char[]){ 0x08, 0x08, 0x0F, 0x08, 0x0F, 0x00, 0x00 } }, //  
+    { 190, 7, 8, 0, 1, 0, 1, (const char[]){ 0x14, 0x14, 0x14, 0x1F, 0x00, 0x00, 0x00 } }, //  
+    { 191, 7, 8, 0, 1, 0, 1, (const char[]){ 0x08, 0x08, 0x08, 0xF8, 0x00, 0x00, 0x00 } }, //  
+    { 192, 7, 8, 0, 1, 0, 1, (const char[]){ 0x00, 0x00, 0x00, 0x0F, 0x08, 0x08, 0x08 } }, //  
+    { 193, 7, 8, 0, 1, 0, 1, (const char[]){ 0x08, 0x08, 0x08, 0x0F, 0x08, 0x08, 0x08 } }, //  
+    { 194, 7, 8, 0, 1, 0, 1, (const char[]){ 0x08, 0x08, 0x08, 0xF8, 0x08, 0x08, 0x08 } }, //  
+    { 195, 7, 8, 0, 1, 0, 1, (const char[]){ 0x00, 0x00, 0x00, 0xFF, 0x08, 0x08, 0x08 } }, //  
+    { 196, 7, 8, 0, 1, 0, 1, (const char[]){ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 } }, //  
+    { 197, 7, 8, 0, 1, 0, 1, (const char[]){ 0x08, 0x08, 0x08, 0xFF, 0x08, 0x08, 0x08 } }, //  
+    { 198, 7, 8, 0, 1, 0, 1, (const char[]){ 0x00, 0x00, 0x00, 0xFF, 0x14, 0x14, 0x14 } }, //  
+    { 199, 7, 8, 0, 1, 0, 1, (const char[]){ 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x08, 0x08 } }, //  
+    { 200, 7, 8, 0, 1, 0, 1, (const char[]){ 0x00, 0x00, 0x1F, 0x10, 0x17, 0x14, 0x14 } }, //  
+    { 201, 7, 8, 0, 1, 0, 1, (const char[]){ 0x00, 0x00, 0xFC, 0x04, 0xF4, 0x14, 0x14 } }, //  
+    { 202, 7, 8, 0, 1, 0, 1, (const char[]){ 0x14, 0x14, 0x17, 0x10, 0x17, 0x14, 0x14 } }, //  
+    { 203, 7, 8, 0, 1, 0, 1, (const char[]){ 0x14, 0x14, 0xF4, 0x04, 0xF4, 0x14, 0x14 } }, //  
+    { 204, 7, 8, 0, 1, 0, 1, (const char[]){ 0x00, 0x00, 0xFF, 0x00, 0xF7, 0x14, 0x14 } }, //  
+    { 205, 7, 8, 0, 1, 0, 1, (const char[]){ 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14 } }, //  
+    { 206, 7, 8, 0, 1, 0, 1, (const char[]){ 0x14, 0x14, 0xF7, 0x00, 0xF7, 0x14, 0x14 } }, //  
+    { 207, 7, 8, 0, 1, 0, 1, (const char[]){ 0x14, 0x14, 0x14, 0x17, 0x14, 0x14, 0x14 } }, //  
+    { 208, 7, 8, 0, 1, 0, 1, (const char[]){ 0x08, 0x08, 0x0F, 0x08, 0x0F, 0x08, 0x08 } }, //  
+    { 209, 7, 8, 0, 1, 0, 1, (const char[]){ 0x14, 0x14, 0x14, 0xF4, 0x14, 0x14, 0x14 } }, //  
+    { 210, 7, 8, 0, 1, 0, 1, (const char[]){ 0x08, 0x08, 0xF8, 0x08, 0xF8, 0x08, 0x08 } }, //  
+    { 211, 7, 8, 0, 1, 0, 1, (const char[]){ 0x00, 0x00, 0x0F, 0x08, 0x0F, 0x08, 0x08 } }, //  
+    { 212, 7, 8, 0, 1, 0, 1, (const char[]){ 0x00, 0x00, 0x00, 0x1F, 0x14, 0x14, 0x14 } }, //  
+    { 213, 7, 8, 0, 1, 0, 1, (const char[]){ 0x00, 0x00, 0x00, 0xFC, 0x14, 0x14, 0x14 } }, //  
+    { 214, 7, 8, 0, 1, 0, 1, (const char[]){ 0x00, 0x00, 0xF8, 0x08, 0xF8, 0x08, 0x08 } }, //  
+    { 215, 7, 8, 0, 1, 0, 1, (const char[]){ 0x08, 0x08, 0xFF, 0x08, 0xFF, 0x08, 0x08 } }, //  
+    { 216, 7, 8, 0, 1, 0, 1, (const char[]){ 0x14, 0x14, 0x14, 0xFF, 0x14, 0x14, 0x14 } }, //  
+    { 217, 7, 8, 0, 1, 0, 1, (const char[]){ 0x08, 0x08, 0x08, 0x0F, 0x00, 0x00, 0x00 } }, //  
+    { 218, 7, 8, 0, 1, 0, 1, (const char[]){ 0x00, 0x00, 0x00, 0xF8, 0x08, 0x08, 0x08 } }, //  
+    { 219, 7, 8, 0, 1, 0, 1, (const char[]){ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } }, //  
+    { 220, 7, 8, 0, 1, 0, 1, (const char[]){ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0 } }, //  
+    { 221, 7, 8, 0, 1, 0, 1, (const char[]){ 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00 } }, //  
+    { 222, 7, 8, 0, 1, 0, 1, (const char[]){ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF } }, //  
+    { 223, 7, 8, 0, 1, 0, 1, (const char[]){ 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F } }, //  
+    { 224, 6, 8, 0, 0, 0, 0, (const char[]){ 0x18, 0x24, 0x24, 0x18, 0x24, 0x24 } }, //  
+    { 225, 6, 8, 1, 0, 0, 0, (const char[]){ 0x40, 0x3E, 0x2A, 0x4A, 0x4C, 0x30 } }, //  
+    { 226, 6, 8, 0, 0, 0, 0, (const char[]){ 0x22, 0x3E, 0x22, 0x02, 0x02, 0x06 } }, //  
+    { 227, 6, 8, 0, 0, 0, 0, (const char[]){ 0x22, 0x3E, 0x02, 0x02, 0x3E, 0x22 } }, //  
+    { 228, 6, 8, 0, 0, 0, 0, (const char[]){ 0x33, 0x2D, 0x21, 0x21, 0x21, 0x33 } }, //  
+    { 229, 6, 8, 0, 0, 0, 0, (const char[]){ 0x18, 0x24, 0x24, 0x24, 0x1C, 0x04 } }, //  
+    { 230, 6, 8, 0, 0, 0, 0, (const char[]){ 0x04, 0x7C, 0x20, 0x20, 0x1C, 0x24 } }, //  
+    { 231, 6, 8, 1, 0, 1, 0, (const char[]){ 0x00, 0x02, 0x02, 0x1E, 0x22, 0x22 } }, //  
+    { 232, 7, 8, 0, 0, 0, 0, (const char[]){ 0x08, 0x14, 0x55, 0x7F, 0x55, 0x14, 0x08 } }, //  
+    { 233, 7, 8, 0, 0, 0, 0, (const char[]){ 0x3E, 0x41, 0x5D, 0x49, 0x5D, 0x41, 0x3E } }, //  
+    { 234, 6, 8, 0, 0, 0, 0, (const char[]){ 0x2E, 0x31, 0x01, 0x01, 0x31, 0x2E } }, //  
+    { 235, 6, 8, 0, 0, 0, 0, (const char[]){ 0x00, 0x1B, 0x25, 0x25, 0x25, 0x18 } }, //  
+    { 236, 7, 8, 0, 0, 0, 0, (const char[]){ 0x18, 0x24, 0x24, 0x18, 0x24, 0x24, 0x18 } }, //  
+    { 237, 6, 8, 0, 0, 0, 0, (const char[]){ 0x00, 0x1C, 0x20, 0x7C, 0x22, 0x1C } }, //  
+    { 238, 6, 8, 0, 0, 0, 0, (const char[]){ 0x14, 0x2A, 0x2A, 0x2A, 0x22, 0x16 } }, //  
+    { 239, 5, 8, 0, 0, 0, 0, (const char[]){ 0x3C, 0x02, 0x02, 0x02, 0x3C } }, //  
+    { 240, 5, 8, 0, 0, 0, 0, (const char[]){ 0x2A, 0x2A, 0x2A, 0x2A, 0x2A } }, //  
+    { 241, 5, 8, 0, 0, 0, 0, (const char[]){ 0x44, 0x44, 0x5F, 0x44, 0x44 } }, //  
+    { 242, 6, 8, 0, 0, 0, 0, (const char[]){ 0x51, 0x51, 0x4A, 0x4A, 0x44, 0x44 } }, //  
+    { 243, 6, 8, 0, 0, 0, 0, (const char[]){ 0x44, 0x44, 0x4A, 0x4A, 0x51, 0x51 } }, //  
+    { 244, 5, 8, 2, 0, 2, 0, (const char[]){ 0x00, 0x00, 0xFE, 0x01, 0x02 } }, //  
+    { 245, 3, 8, 0, 0, 0, 0, (const char[]){ 0x20, 0x40, 0x3F } }, //  
+    { 246, 5, 8, 0, 0, 0, 0, (const char[]){ 0x08, 0x08, 0x2A, 0x08, 0x08 } }, //  
+    { 247, 5, 8, 0, 0, 0, 0, (const char[]){ 0x24, 0x12, 0x24, 0x48, 0x24 } }, //  
+    { 248, 5, 8, 0, 0, 1, 1, (const char[]){ 0x00, 0x06, 0x09, 0x09, 0x06 } }, //  
+    { 249, 4, 8, 2, 0, 2, 0, (const char[]){ 0x00, 0x00, 0x00, 0x08 } }, //  
+    { 250, 5, 8, 2, 0, 2, 0, (const char[]){ 0x00, 0x00, 0x08, 0x1C, 0x08 } }, //  
+    { 251, 6, 8, 0, 0, 0, 2, (const char[]){ 0x02, 0x7E, 0x30, 0x0C, 0x02, 0x02 } }, //  
+    { 252, 5, 8, 1, 0, 2, 1, (const char[]){ 0x00, 0x01, 0x0E, 0x01, 0x0E } }, //  
+    { 253, 5, 8, 2, 0, 2, 1, (const char[]){ 0x00, 0x00, 0x09, 0x0D, 0x0A } }, //  
+    { 254, 5, 8, 2, 0, 2, 0, (const char[]){ 0x00, 0x00, 0x1C, 0x1C, 0x1C } }, //  
+    { 255, 5, 8, 0, 0, 0, 0, (const char[]){ 0x00, 0x00, 0x00, 0x00, 0x00 } }
+};
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FatFileSystem/FATDirHandle.cpp	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,66 @@
+/* mbed Microcontroller Library - FATDirHandle
+ * Copyright (c) 2008, sford
+ */
+ 
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "ff.h"
+#include "FATDirHandle.h"
+#include "FATFileSystem.h"
+
+namespace mbed {
+
+FATDirHandle::FATDirHandle(const FATFS_DIR &the_dir) {
+    dir = the_dir;
+}
+
+int FATDirHandle::closedir() {
+    delete this;
+    return 0;
+}
+
+struct dirent *FATDirHandle::readdir() {
+    FILINFO finfo;
+
+#if _USE_LFN
+    finfo.lfname = cur_entry.d_name;
+    finfo.lfsize = sizeof(cur_entry.d_name);
+#endif // _USE_LFN
+
+    FRESULT res = f_readdir(&dir, &finfo);
+
+#if _USE_LFN
+    if(res != 0 || finfo.fname[0]==0) {
+        return NULL;
+    } else {
+        if(cur_entry.d_name[0]==0) {
+            // No long filename so use short filename.
+            memcpy(cur_entry.d_name, finfo.fname, sizeof(finfo.fname));
+        }
+        return &cur_entry;
+    }
+#else
+    if(res != 0 || finfo.fname[0]==0) {
+        return NULL;
+    } else {
+        memcpy(cur_entry.d_name, finfo.fname, sizeof(finfo.fname));
+        return &cur_entry;
+    }
+#endif /* _USE_LFN */
+}
+
+void FATDirHandle::rewinddir() {
+    dir.index = 0;
+}
+
+off_t FATDirHandle::telldir() {
+    return dir.index;
+}
+
+void FATDirHandle::seekdir(off_t location) {
+    dir.index = location;
+}
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FatFileSystem/FATDirHandle.h	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,31 @@
+/* mbed Microcontroller Library - FATDirHandle
+ * Copyright (c) 2008, sford
+ */
+
+#ifndef MBED_FATDIRHANDLE_H
+#define MBED_FATDIRHANDLE_H
+
+#include "DirHandle.h"
+#include "ff.h"
+
+namespace mbed {
+
+class FATDirHandle : public DirHandle {
+
+ public:
+    FATDirHandle(const FATFS_DIR &the_dir);
+    virtual int closedir();
+    virtual struct dirent *readdir();
+    virtual void rewinddir();
+    virtual off_t telldir();
+    virtual void seekdir(off_t location);
+
+ private:
+    FATFS_DIR dir;
+    struct dirent cur_entry;
+
+};
+
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FatFileSystem/FATFileHandle.cpp	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,102 @@
+/* mbed Microcontroller Library - FATFileHandle
+ * Copyright (c) 2008, sford
+ */
+
+#include "FATFileHandle.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "ff.h"
+#include "FATFileSystem.h"
+
+namespace mbed {
+
+#if FFSDEBUG_ENABLED
+static const char *FR_ERRORS[] = {
+    "FR_OK = 0", 
+    "FR_NOT_READY",          
+    "FR_NO_FILE",              
+    "FR_NO_PATH",             
+    "FR_INVALID_NAME",     
+    "FR_INVALID_DRIVE",      
+    "FR_DENIED",              
+    "FR_EXIST",              
+    "FR_RW_ERROR",          
+    "FR_WRITE_PROTECTED", 
+    "FR_NOT_ENABLED",    
+    "FR_NO_FILESYSTEM",    
+    "FR_INVALID_OBJECT",    
+    "FR_MKFS_ABORTED"    
+};
+#endif
+
+FATFileHandle::FATFileHandle(FIL fh) { 
+    _fh = fh;
+}
+    
+int FATFileHandle::close() {
+    FFSDEBUG("close\n");
+    int retval = f_close(&_fh);
+    delete this;
+    return retval;
+}
+
+ssize_t FATFileHandle::write(const void* buffer, size_t length) {
+    FFSDEBUG("write(%d)\n", length);
+    UINT n;
+    FRESULT res = f_write(&_fh, buffer, length, &n);
+    if(res) { 
+        FFSDEBUG("f_write() failed (%d, %s)", res, FR_ERRORS[res]);
+        return -1;
+    }
+    return n;
+}
+        
+ssize_t FATFileHandle::read(void* buffer, size_t length) {
+    FFSDEBUG("read(%d)\n", length);
+    UINT n;
+    FRESULT res = f_read(&_fh, buffer, length, &n);
+    if(res) {
+        FFSDEBUG("f_read() failed (%d, %s)\n", res, FR_ERRORS[res]);
+        return -1;
+    }
+    return n;
+}
+        
+int FATFileHandle::isatty() {
+    return 0;
+}
+        
+off_t FATFileHandle::lseek(off_t position, int whence) {
+    FFSDEBUG("lseek(%i,%i)\n",position,whence);
+    if(whence == SEEK_END) {
+        position += _fh.fsize;
+    } else if(whence==SEEK_CUR) {
+        position += _fh.fptr;
+    }
+    FRESULT res = f_lseek(&_fh, position);
+    if(res) {
+        FFSDEBUG("lseek failed (%d, %s)\n", res, FR_ERRORS[res]);
+        return -1;
+    } else {
+        FFSDEBUG("lseek OK, returning %i\n", _fh.fptr);
+        return _fh.fptr;
+    }
+}
+        
+int FATFileHandle::fsync() {
+    FFSDEBUG("fsync()\n");
+    FRESULT res = f_sync(&_fh);
+    if (res) {
+        FFSDEBUG("f_sync() failed (%d, %s)\n", res, FR_ERRORS[res]);
+        return -1;
+    }
+    return 0;
+}
+
+off_t FATFileHandle::flen() {
+    FFSDEBUG("flen\n");
+    return _fh.fsize;
+}
+
+} // namespace mbed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FatFileSystem/FATFileHandle.h	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,33 @@
+/* mbed Microcontroller Library - FATFileHandle
+ * Copyright (c) 2008, sford
+ */
+
+#ifndef MBED_FATFILEHANDLE_H
+#define MBED_FATFILEHANDLE_H
+
+#include "FileHandle.h"
+#include "ff.h"
+
+namespace mbed {
+
+class FATFileHandle : public FileHandle {
+public:
+
+    FATFileHandle(FIL fh);
+    virtual int close();
+    virtual ssize_t write(const void* buffer, size_t length);
+    virtual ssize_t read(void* buffer, size_t length);
+    virtual int isatty();
+    virtual off_t lseek(off_t position, int whence);
+    virtual int fsync();
+    virtual off_t flen();
+
+protected:
+
+    FIL _fh;
+
+};
+
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FatFileSystem/FATFileSystem.cpp	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,134 @@
+/* mbed Microcontroller Library - FATFileSystem
+ * Copyright (c) 2008, sford
+ */
+
+#include "FATFileSystem.h"
+
+#include "mbed.h"
+
+#include "FileSystemLike.h"
+#include "FATFileHandle.h"
+#include "FATDirHandle.h"
+#include "ff.h"
+//#include "Debug.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+DWORD get_fattime (void) {
+    return 999;
+}
+
+namespace mbed {
+
+#if FFSDEBUG_ENABLED
+static const char *FR_ERRORS[] = {
+    "FR_OK = 0", 
+    "FR_NOT_READY",          
+    "FR_NO_FILE",              
+    "FR_NO_PATH",             
+    "FR_INVALID_NAME",     
+    "FR_INVALID_DRIVE",      
+    "FR_DENIED",              
+    "FR_EXIST",              
+    "FR_RW_ERROR",          
+    "FR_WRITE_PROTECTED", 
+    "FR_NOT_ENABLED",    
+    "FR_NO_FILESYSTEM",    
+    "FR_INVALID_OBJECT",    
+    "FR_MKFS_ABORTED"    
+};
+#endif
+
+FATFileSystem *FATFileSystem::_ffs[_VOLUMES] = {0};
+
+FATFileSystem::FATFileSystem(const char* n) : FileSystemLike(n) {
+    FFSDEBUG("FATFileSystem(%s)\n", n);
+    for(int i=0; i<_VOLUMES; i++) {
+        if(_ffs[i] == 0) {
+            _ffs[i] = this;
+            _fsid = i;
+            FFSDEBUG("Mounting [%s] on ffs drive [%d]\n", _name, _fsid);
+            f_mount(i, &_fs);
+            return;
+        }
+    }
+    error("Couldn't create %s in FATFileSystem::FATFileSystem\n",n);
+}
+    
+FATFileSystem::~FATFileSystem() {
+    for(int i=0; i<_VOLUMES; i++) {
+        if(_ffs[i] == this) {
+            _ffs[i] = 0;
+            f_mount(i, NULL);
+        }
+    }
+}
+    
+FileHandle *FATFileSystem::open(const char* name, int flags) {
+    FFSDEBUG("open(%s) on filesystem [%s], drv [%d]\n", name, _name, _fsid);
+    char n[64];
+    sprintf(n, "%d:/%s", _fsid, name);
+
+    /* POSIX flags -> FatFS open mode */
+    BYTE openmode;
+    if(flags & O_RDWR) {
+        openmode = FA_READ|FA_WRITE;
+    } else if(flags & O_WRONLY) {
+        openmode = FA_WRITE;
+    } else {
+        openmode = FA_READ;
+    }
+    if(flags & O_CREAT) {
+        if(flags & O_TRUNC) {
+            openmode |= FA_CREATE_ALWAYS;
+        } else {
+            openmode |= FA_OPEN_ALWAYS;
+        }
+    }
+
+    FIL fh;
+    FRESULT res = f_open(&fh, n, openmode);
+    if(res) { 
+        FFSDEBUG("f_open('w') failed (%d, %s)\n", res, FR_ERRORS[res]);
+        return NULL;
+    }
+    if(flags & O_APPEND) {
+        f_lseek(&fh, fh.fsize);
+    }
+    return new FATFileHandle(fh);
+}
+    
+int FATFileSystem::remove(const char *filename) {
+    FRESULT res = f_unlink(filename);
+    if(res) { 
+        FFSDEBUG("f_unlink() failed (%d, %s)\n", res, FR_ERRORS[res]);
+        return -1;
+    }
+    return 0;
+}
+
+int FATFileSystem::format() {
+    FFSDEBUG("format()\n");
+    FRESULT res = f_mkfs(_fsid, 0, 512); // Logical drive number, Partitioning rule, Allocation unit size (bytes per cluster)
+    if(res) {
+        FFSDEBUG("f_mkfs() failed (%d, %s)\n", res, FR_ERRORS[res]);
+        return -1;
+    }
+    return 0;
+}
+
+DirHandle *FATFileSystem::opendir(const char *name) {
+    FATFS_DIR dir;
+    FRESULT res = f_opendir(&dir, name);
+    if(res != 0) {
+        return NULL;
+    }
+    return new FATDirHandle(dir);
+}
+
+int FATFileSystem::mkdir(const char *name, mode_t mode) {
+    FRESULT res = f_mkdir(name);
+    return res == 0 ? 0 : -1;
+}
+
+} // namespace mbed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FatFileSystem/FATFileSystem.h	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,61 @@
+/* mbed Microcontroller Library - FATFileSystem
+ * Copyright (c) 2008, sford
+ */
+
+/* Library: FATFileSystem.h
+ * A library of stuff to make a fat filesystem on top of a block device
+ */
+
+#ifndef MBED_FATFILESYSTEM_H
+#define MBED_FATFILESYSTEM_H
+
+#ifndef FFSDEBUG_ENABLED
+#define FFSDEBUG_ENABLED 0
+#endif
+
+#if FFSDEBUG_ENABLED
+#define FFSDEBUG(FMT, ...) printf(FMT, ##__VA_ARGS__)
+#else
+#define FFSDEBUG(FMT, ...)
+#endif
+
+#include "FileSystemLike.h"
+#include "FileHandle.h"
+#include "ff.h"
+#include "diskio.h"
+
+namespace mbed {
+/* Class: FATFileSystem
+ * The class itself
+ */
+class FATFileSystem : public FileSystemLike {
+public:
+
+	FATFileSystem(const char* n);
+	virtual ~FATFileSystem();
+	
+	/* Function: open
+       * open a file on the filesystem. never called directly
+       */
+	virtual FileHandle *open(const char* name, int flags);
+	virtual int remove(const char *filename);
+	virtual int format();
+        virtual DirHandle *opendir(const char *name);
+        virtual int mkdir(const char *name, mode_t mode);
+	
+    FATFS _fs;            					// Work area (file system object) for logical drive	
+    static FATFileSystem *_ffs[_VOLUMES];	// FATFileSystem objects, as parallel to FatFs drives array
+	int _fsid;
+	
+	virtual int disk_initialize() { return 0; }
+	virtual int disk_status() { return 0; }
+	virtual int disk_read(char *buffer, int sector) = 0;
+	virtual int disk_write(const char *buffer, int sector) = 0;
+	virtual int disk_sync() { return 0; }
+	virtual int disk_sectors() = 0;
+	 
+};
+	
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FatFileSystem/MemFileSystem.h	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,75 @@
+/* mbed Microcontroller Library - MemFileSystem
+ * Copyright (c) 2008, sford
+ */
+
+
+#ifndef MBED_MEMFILESYSTEM_H
+#define MBED_MEMFILESYSTEM_H
+
+#include "FATFileSystem.h"
+
+namespace mbed {
+
+class MemFileSystem : public FATFileSystem {
+public:
+
+    // 2000 sectors, each 512 bytes (malloced as required)
+    char *sectors[2000];
+
+    MemFileSystem(const char* name) : FATFileSystem(name) {
+        memset(sectors, 0, sizeof(sectors));
+    }
+
+    virtual ~MemFileSystem() {
+        for(int i = 0; i < 2000; i++) {
+            if(sectors[i]) {
+                free(sectors[i]);
+            }
+        }
+    }
+
+    // read a sector in to the buffer, return 0 if ok
+    virtual int disk_read(char *buffer, int sector) {
+        if(sectors[sector] == 0) {
+            // nothing allocated means sector is empty
+            memset(buffer, 0, 512);
+        } else {
+            memcpy(buffer, sectors[sector], 512);
+        }
+        return 0;
+    }
+
+    // write a sector from the buffer, return 0 if ok
+    virtual int disk_write(const char *buffer, int sector) {
+        // if buffer is zero deallocate sector
+        char zero[512];
+        memset(zero, 0, 512);
+        if(memcmp(zero, buffer, 512)==0) {
+            if(sectors[sector] != 0) {
+                free(sectors[sector]);
+                sectors[sector] = 0;
+            }
+            return 0;
+        }
+        // else allocate a sector if needed, and write
+        if(sectors[sector] == 0) {
+            char *sec = (char*)malloc(512);
+            if(sec==0) {
+                return 1; // out of memory
+            }
+            sectors[sector] = sec;
+        }
+        memcpy(sectors[sector], buffer, 512);
+        return 0;
+    }
+        
+    // return the number of sectors
+    virtual int disk_sectors() {
+        return sizeof(sectors)/sizeof(sectors[0]);
+    }
+
+};
+    
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FatFileSystem/diskio.cpp	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,105 @@
+/*-----------------------------------------------------------------------*/
+/* 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 <stdio.h>
+#include <string.h>
+#include "FATFileSystem.h"
+
+#include "mbed.h"
+
+DSTATUS disk_initialize (
+	BYTE drv				/* Physical drive nmuber (0..) */
+) 
+{
+	FFSDEBUG("disk_initialize on drv [%d]\n", drv);
+	return (DSTATUS)FATFileSystem::_ffs[drv]->disk_initialize();
+}
+
+DSTATUS disk_status (
+	BYTE drv		/* Physical drive nmuber (0..) */
+) 
+{
+	FFSDEBUG("disk_status on drv [%d]\n", drv);
+	return (DSTATUS)FATFileSystem::_ffs[drv]->disk_status();
+}
+
+DRESULT disk_read (
+	BYTE drv,		/* Physical drive nmuber (0..) */
+	BYTE *buff,		/* Data buffer to store read data */
+	DWORD sector,	/* Sector address (LBA) */
+	BYTE count		/* Number of sectors to read (1..255) */
+)
+{
+	FFSDEBUG("disk_read(sector %d, count %d) on drv [%d]\n", sector, count, drv);
+	for(DWORD s=sector; s<sector+count; s++) {
+		FFSDEBUG(" disk_read(sector %d)\n", s);
+		int res = FATFileSystem::_ffs[drv]->disk_read((char*)buff, s);
+		if(res) {
+			return RES_PARERR;
+		}
+		buff += 512;
+	}
+	return RES_OK;
+}
+
+#if _READONLY == 0
+DRESULT disk_write (
+	BYTE drv,			/* Physical drive nmuber (0..) */
+	const BYTE *buff,	/* Data to be written */
+	DWORD sector,		/* Sector address (LBA) */
+	BYTE count			/* Number of sectors to write (1..255) */
+)
+{
+	FFSDEBUG("disk_write(sector %d, count %d) on drv [%d]\n", sector, count, drv);
+	for(DWORD s=sector; s<sector+count; s++) {
+		FFSDEBUG(" disk_write(sector %d)\n", s);
+		int res = FATFileSystem::_ffs[drv]->disk_write((char*)buff, s);
+		if(res) {
+			return RES_PARERR;
+		}
+		buff += 512;
+	}
+	return RES_OK;
+}
+#endif /* _READONLY */
+
+DRESULT disk_ioctl (
+	BYTE drv,		/* Physical drive nmuber (0..) */
+	BYTE ctrl,		/* Control code */
+	void *buff		/* Buffer to send/receive control data */
+)
+{
+	FFSDEBUG("disk_ioctl(%d)\n", ctrl);
+	switch(ctrl) {
+		case CTRL_SYNC:
+			if(FATFileSystem::_ffs[drv] == NULL) {
+				return RES_NOTRDY;
+			} else if(FATFileSystem::_ffs[drv]->disk_sync()) {
+				return RES_ERROR;
+			} 
+			return RES_OK;
+		case GET_SECTOR_COUNT:
+			if(FATFileSystem::_ffs[drv] == NULL) {
+				return RES_NOTRDY;
+			} else {
+				int res = FATFileSystem::_ffs[drv]->disk_sectors();
+				if(res > 0) {
+					*((DWORD*)buff) = res; // minimum allowed
+					return RES_OK;
+				} else {
+					return RES_ERROR;
+				}
+			}
+		case GET_BLOCK_SIZE:
+			*((DWORD*)buff) = 1; // default when not known
+			return RES_OK;
+
+	}
+	return RES_PARERR;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FatFileSystem/diskio.h	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,78 @@
+/*-----------------------------------------------------------------------
+/  Low level disk interface modlue include file
+/-----------------------------------------------------------------------*/
+
+#ifndef _DISKIO
+
+#define _READONLY	0	/* 1: Remove write functions */
+#define _USE_IOCTL	1	/* 1: Use disk_ioctl fucntion */
+
+#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 */
+
+int assign_drives (int, int);
+DSTATUS disk_initialize (BYTE);
+DSTATUS disk_status (BYTE);
+DRESULT disk_read (BYTE, BYTE*, DWORD, BYTE);
+#if	_READONLY == 0
+DRESULT disk_write (BYTE, const BYTE*, DWORD, BYTE);
+#endif
+DRESULT disk_ioctl (BYTE, BYTE, void*);
+
+
+
+/* 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 fucntion */
+
+/* Generic command (defined for FatFs) */
+#define CTRL_SYNC			0	/* Flush disk cache (for write functions) */
+#define GET_SECTOR_COUNT	1	/* Get media size (for only f_mkfs()) */
+#define GET_SECTOR_SIZE		2	/* Get sector size (for multiple sector size (_MAX_SS >= 1024)) */
+#define GET_BLOCK_SIZE		3	/* Get erase block size (for only f_mkfs()) */
+#define CTRL_ERASE_SECTOR	4	/* Force erased a block of sectors (for only _USE_ERASE) */
+
+/* Generic command */
+#define CTRL_POWER			5	/* Get/Set power status */
+#define CTRL_LOCK			6	/* Lock/Unlock media removal */
+#define CTRL_EJECT			7	/* Eject media */
+
+/* MMC/SDC specific ioctl command */
+#define MMC_GET_TYPE		10	/* Get card type */
+#define MMC_GET_CSD			11	/* Get CSD */
+#define MMC_GET_CID			12	/* Get CID */
+#define MMC_GET_OCR			13	/* Get OCR */
+#define MMC_GET_SDSTAT		14	/* Get SD status */
+
+/* ATA/CF specific ioctl command */
+#define ATA_GET_REV			20	/* Get F/W revision */
+#define ATA_GET_MODEL		21	/* Get model name */
+#define ATA_GET_SN			22	/* Get serial number */
+
+/* NAND specific ioctl command */
+#define NAND_FORMAT			30	/* Create physical format */
+
+
+#define _DISKIO
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FatFileSystem/ff.cpp	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,4077 @@
+/*----------------------------------------------------------------------------/
+/  FatFs - FAT file system module  R0.09                  (C)ChaN, 2011
+/-----------------------------------------------------------------------------/
+/ 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 terms.
+/
+/  Copyright (C) 2011, 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) partition.
+/ 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 algorithm 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 physical 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 configuration option. (_FS_TINY)
+/                   Added long file name feature.
+/                   Added multiple code page feature.
+/                   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 feature.
+/ 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.
+/
+/ May 15,'10 R0.08  Added a memory configuration option. (_USE_LFN = 3)
+/                   Added file lock feature. (_FS_SHARE)
+/                   Added fast seek feature. (_USE_FASTSEEK)
+/                   Changed some types on the API, XCHAR->TCHAR.
+/                   Changed fname member in the FILINFO structure on Unicode cfg.
+/                   String functions support UTF-8 encoding files on Unicode cfg.
+/ Aug 16,'10 R0.08a Added f_getcwd(). (_FS_RPATH = 2)
+/                   Added sector erase feature. (_USE_ERASE)
+/                   Moved file lock semaphore table from fs object to the bss.
+/                   Fixed a wrong directory entry is created on non-LFN cfg when the given name contains ';'.
+/                   Fixed f_mkfs() creates wrong FAT32 volume.
+/ Jan 15,'11 R0.08b Fast seek feature is also applied to f_read() and f_write().
+/                   f_lseek() reports required table size on creating CLMP.
+/                   Extended format syntax of f_printf function.
+/                   Ignores duplicated directory separators in given path names.
+/
+/ Sep 06,'11 R0.09  f_mkfs() supports multiple partition to finish the multiple partition feature.
+/                   Added f_fdisk(). (_MULTI_PARTITION = 2)
+/---------------------------------------------------------------------------*/
+
+#include "ff.h"			/* FatFs configurations and declarations */
+#include "diskio.h"		/* Declarations of low level disk I/O functions */
+
+
+/*--------------------------------------------------------------------------
+
+   Module Private Definitions
+
+---------------------------------------------------------------------------*/
+
+#if _FATFS != 6502	/* Revision ID */
+#error Wrong include file (ff.h).
+#endif
+
+
+/* Definitions on sector size */
+#if _MAX_SS != 512 && _MAX_SS != 1024 && _MAX_SS != 2048 && _MAX_SS != 4096
+#error Wrong sector size.
+#endif
+#if _MAX_SS != 512
+#define	SS(fs)	((fs)->ssize)	/* Variable sector size */
+#else
+#define	SS(fs)	512U			/* Fixed sector size */
+#endif
+
+
+/* Reentrancy related */
+#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); }
+
+
+/* File shareing feature */
+#if _FS_SHARE
+#if _FS_READONLY
+#error _FS_SHARE must be 0 on read-only cfg.
+#endif
+typedef struct {
+	FATFS *fs;				/* File ID 1, volume (NULL:blank entry) */
+	DWORD clu;				/* File ID 2, directory */
+	WORD idx;				/* File ID 3, directory index */
+	WORD ctr;				/* File open counter, 0:none, 0x01..0xFF:read open count, 0x100:write mode */
+} FILESEM;
+#endif
+
+
+/* Misc definitions */
+#define LD_CLUST(dir)	(((DWORD)LD_WORD(dir+DIR_FstClusHI)<<16) | LD_WORD(dir+DIR_FstClusLO))
+#define ST_CLUST(dir,cl) {ST_WORD(dir+DIR_FstClusLO, cl); ST_WORD(dir+DIR_FstClusHI, (DWORD)cl>>16);}
+
+
+/* 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) */
+#if _USE_LFN
+#error Cannot use LFN feature without valid code page.
+#endif
+#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'))
+#define IsDigit(c)	(((c)>='0')&&((c)<='9'))
+
+#if _DF1S		/* Code page is DBCS */
+
+#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			/* Code page is SBCS */
+
+#define IsDBCS1(c)	0
+#define IsDBCS2(c)	0
+
+#endif /* _DF1S */
+
+
+/* Name status flags */
+#define NS			11		/* Index of name status byte in fn[] */
+#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 */
+
+
+/* FAT sub-type boundaries */
+/* Note that the FAT spec by Microsoft says 4085 but Windows works with 4087! */
+#define MIN_FAT16	4086	/* Minimum number of clusters for FAT16 */
+#define	MIN_FAT32	65526	/* Minimum number of clusters for FAT32 */
+
+
+/* FatFs refers the members in the FAT structures as byte array instead of
+/ structure member because the structure is not binary compatible between
+/ different platforms */
+
+#define BS_jmpBoot			0	/* Jump instruction (3) */
+#define BS_OEMName			3	/* OEM name (8) */
+#define BPB_BytsPerSec		11	/* Sector size [byte] (2) */
+#define BPB_SecPerClus		13	/* Cluster size [sector] (1) */
+#define BPB_RsvdSecCnt		14	/* Size of reserved area [sector] (2) */
+#define BPB_NumFATs			16	/* Number of FAT copies (1) */
+#define BPB_RootEntCnt		17	/* Number of root dir entries for FAT12/16 (2) */
+#define BPB_TotSec16		19	/* Volume size [sector] (2) */
+#define BPB_Media			21	/* Media descriptor (1) */
+#define BPB_FATSz16			22	/* FAT size [sector] (2) */
+#define BPB_SecPerTrk		24	/* Track size [sector] (2) */
+#define BPB_NumHeads		26	/* Number of heads (2) */
+#define BPB_HiddSec			28	/* Number of special hidden sectors (4) */
+#define BPB_TotSec32		32	/* Volume size [sector] (4) */
+#define BS_DrvNum			36	/* Physical drive number (2) */
+#define BS_BootSig			38	/* Extended boot signature (1) */
+#define BS_VolID			39	/* Volume serial number (4) */
+#define BS_VolLab			43	/* Volume label (8) */
+#define BS_FilSysType		54	/* File system type (1) */
+#define BPB_FATSz32			36	/* FAT size [sector] (4) */
+#define BPB_ExtFlags		40	/* Extended flags (2) */
+#define BPB_FSVer			42	/* File system version (2) */
+#define BPB_RootClus		44	/* Root dir first cluster (4) */
+#define BPB_FSInfo			48	/* Offset of FSInfo sector (2) */
+#define BPB_BkBootSec		50	/* Offset of backup boot sectot (2) */
+#define BS_DrvNum32			64	/* Physical drive number (2) */
+#define BS_BootSig32		66	/* Extended boot signature (1) */
+#define BS_VolID32			67	/* Volume serial number (4) */
+#define BS_VolLab32			71	/* Volume label (8) */
+#define BS_FilSysType32		82	/* File system type (1) */
+#define	FSI_LeadSig			0	/* FSI: Leading signature (4) */
+#define	FSI_StrucSig		484	/* FSI: Structure signature (4) */
+#define	FSI_Free_Count		488	/* FSI: Number of free clusters (4) */
+#define	FSI_Nxt_Free		492	/* FSI: Last allocated cluster (4) */
+#define MBR_Table			446	/* MBR: Partition table offset (2) */
+#define	SZ_PTE				16	/* MBR: Size of a partition table entry */
+#define BS_55AA				510	/* Boot sector signature (2) */
+
+#define	DIR_Name			0	/* Short file name (11) */
+#define	DIR_Attr			11	/* Attribute (1) */
+#define	DIR_NTres			12	/* NT flag (1) */
+#define	DIR_CrtTime			14	/* Created time (2) */
+#define	DIR_CrtDate			16	/* Created date (2) */
+#define	DIR_FstClusHI		20	/* Higher 16-bit of first cluster (2) */
+#define	DIR_WrtTime			22	/* Modified time (2) */
+#define	DIR_WrtDate			24	/* Modified date (2) */
+#define	DIR_FstClusLO		26	/* Lower 16-bit of first cluster (2) */
+#define	DIR_FileSize		28	/* File size (4) */
+#define	LDIR_Ord			0	/* LFN entry order and LLE flag (1) */
+#define	LDIR_Attr			11	/* LFN attribute (1) */
+#define	LDIR_Type			12	/* LFN type (1) */
+#define	LDIR_Chksum			13	/* Sum of corresponding SFN entry */
+#define	LDIR_FstClusLO		26	/* Filled by zero (0) */
+#define	SZ_DIR				32		/* Size of a directory entry */
+#define	LLE					0x40	/* Last long entry flag in LDIR_Ord */
+#define	DDE					0xE5	/* Deleted directory enrty mark in DIR_Name[0] */
+#define	NDDE				0x05	/* Replacement of a character collides with DDE */
+
+
+/*------------------------------------------------------------*/
+/* Module private work area                                   */
+/*------------------------------------------------------------*/
+/* Note that uninitialized variables with static duration are
+/  zeroed/nulled at start-up. If not, the compiler or start-up
+/  routine is out of ANSI-C standard.
+*/
+
+#if _VOLUMES
+static
+FATFS *FatFs[_VOLUMES];	/* Pointer to the file system objects (logical drives) */
+#else
+#error Number of volumes must not be 0.
+#endif
+
+static
+WORD Fsid;				/* File system mount ID */
+
+#if _FS_RPATH
+static
+BYTE CurrVol;			/* Current drive */
+#endif
+
+#if _FS_SHARE
+static
+FILESEM	Files[_FS_SHARE];	/* File lock semaphores */
+#endif
+
+#if _USE_LFN == 0			/* No LFN feature */
+#define	DEF_NAMEBUF			BYTE sfn[12]
+#define INIT_BUF(dobj)		(dobj).fn = sfn
+#define	FREE_BUF()
+
+#elif _USE_LFN == 1			/* LFN feature with static working buffer */
+static WCHAR LfnBuf[_MAX_LFN+1];
+#define	DEF_NAMEBUF			BYTE sfn[12]
+#define INIT_BUF(dobj)		{ (dobj).fn = sfn; (dobj).lfn = LfnBuf; }
+#define	FREE_BUF()
+
+#elif _USE_LFN == 2 		/* LFN feature with dynamic working buffer on the stack */
+#define	DEF_NAMEBUF			BYTE sfn[12]; WCHAR lbuf[_MAX_LFN+1]
+#define INIT_BUF(dobj)		{ (dobj).fn = sfn; (dobj).lfn = lbuf; }
+#define	FREE_BUF()
+
+#elif _USE_LFN == 3 		/* LFN feature with dynamic working buffer on the heap */
+#define	DEF_NAMEBUF			BYTE sfn[12]; WCHAR *lfn
+#define INIT_BUF(dobj)		{ lfn = ff_memalloc((_MAX_LFN + 1) * 2); \
+							  if (!lfn) LEAVE_FF((dobj).fs, FR_NOT_ENOUGH_CORE); \
+							  (dobj).lfn = lfn;	(dobj).fn = sfn; }
+#define	FREE_BUF()			ff_memfree(lfn)
+
+#else
+#error Wrong LFN configuration.
+#endif
+
+
+
+
+/*--------------------------------------------------------------------------
+
+   Module Private Functions
+
+---------------------------------------------------------------------------*/
+
+
+/*-----------------------------------------------------------------------*/
+/* String functions                                                      */
+/*-----------------------------------------------------------------------*/
+
+/* Copy memory to memory */
+static
+void mem_cpy (void* dst, const void* src, UINT cnt) {
+	BYTE *d = (BYTE*)dst;
+	const BYTE *s = (const BYTE*)src;
+
+#if _WORD_ACCESS == 1
+	while (cnt >= sizeof(int)) {
+		*(int*)d = *(int*)s;
+		d += sizeof(int); s += sizeof(int);
+		cnt -= sizeof(int);
+	}
+#endif
+	while (cnt--)
+		*d++ = *s++;
+}
+
+/* Fill memory */
+static
+void mem_set (void* dst, int val, UINT cnt) {
+	BYTE *d = (BYTE*)dst;
+
+	while (cnt--)
+		*d++ = (BYTE)val;
+}
+
+/* Compare memory to memory */
+static
+int mem_cmp (const void* dst, const void* src, UINT cnt) {
+	const BYTE *d = (const BYTE *)dst, *s = (const BYTE *)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
+int 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
+
+
+
+/*-----------------------------------------------------------------------*/
+/* File shareing control functions                                       */
+/*-----------------------------------------------------------------------*/
+#if _FS_SHARE
+
+static
+FRESULT chk_lock (	/* Check if the file can be accessed */
+	FATFS_DIR* dj,		/* Directory object pointing the file to be checked */
+	int acc			/* Desired access (0:Read, 1:Write, 2:Delete/Rename) */
+)
+{
+	UINT i, be;
+
+	/* Search file semaphore table */
+	for (i = be = 0; i < _FS_SHARE; i++) {
+		if (Files[i].fs) {	/* Existing entry */
+			if (Files[i].fs == dj->fs &&	 	/* Check if the file matched with an open file */
+				Files[i].clu == dj->sclust &&
+				Files[i].idx == dj->index) break;
+		} else {			/* Blank entry */
+			be++;
+		}
+	}
+	if (i == _FS_SHARE)	/* The file is not opened */
+		return (be || acc == 2) ? FR_OK : FR_TOO_MANY_OPEN_FILES;	/* Is there a blank entry for new file? */
+
+	/* The file has been opened. Reject any open against writing file and all write mode open */
+	return (acc || Files[i].ctr == 0x100) ? FR_LOCKED : FR_OK;
+}
+
+
+static
+int enq_lock (void)	/* Check if an entry is available for a new file */
+{
+	UINT i;
+
+	for (i = 0; i < _FS_SHARE && Files[i].fs; i++) ;
+	return (i == _FS_SHARE) ? 0 : 1;
+}
+
+
+static
+UINT inc_lock (	/* Increment file open counter and returns its index (0:int error) */
+	FATFS_DIR* dj,	/* Directory object pointing the file to register or increment */
+	int acc		/* Desired access mode (0:Read, !0:Write) */
+)
+{
+	UINT i;
+
+
+	for (i = 0; i < _FS_SHARE; i++) {	/* Find the file */
+		if (Files[i].fs == dj->fs &&
+			Files[i].clu == dj->sclust &&
+			Files[i].idx == dj->index) break;
+	}
+
+	if (i == _FS_SHARE) {				/* Not opened. Register it as new. */
+		for (i = 0; i < _FS_SHARE && Files[i].fs; i++) ;
+		if (i == _FS_SHARE) return 0;	/* No space to register (int err) */
+		Files[i].fs = dj->fs;
+		Files[i].clu = dj->sclust;
+		Files[i].idx = dj->index;
+		Files[i].ctr = 0;
+	}
+
+	if (acc && Files[i].ctr) return 0;	/* Access violation (int err) */
+
+	Files[i].ctr = acc ? 0x100 : Files[i].ctr + 1;	/* Set semaphore value */
+
+	return i + 1;
+}
+
+
+static
+FRESULT dec_lock (	/* Decrement file open counter */
+	UINT i			/* Semaphore index */
+)
+{
+	WORD n;
+	FRESULT res;
+
+
+	if (--i < _FS_SHARE) {
+		n = Files[i].ctr;
+		if (n == 0x100) n = 0;
+		if (n) n--;
+		Files[i].ctr = n;
+		if (!n) Files[i].fs = 0;
+		res = FR_OK;
+	} else {
+		res = FR_INT_ERR;
+	}
+	return res;
+}
+
+
+static
+void clear_lock (	/* Clear lock entries of the volume */
+	FATFS *fs
+)
+{
+	UINT i;
+
+	for (i = 0; i < _FS_SHARE; i++) {
+		if (Files[i].fs == fs) Files[i].fs = 0;
+	}
+}
+#endif
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Change window offset                                                  */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT move_window (
+	FATFS *fs,		/* File system object */
+	DWORD sector	/* Sector number to make appearance 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->drv, fs->win, wsect, 1) != RES_OK)
+				return FR_DISK_ERR;
+			fs->wflag = 0;
+			if (wsect < (fs->fatbase + fs->fsize)) {	/* In FAT area */
+				BYTE nf;
+				for (nf = fs->n_fats; nf > 1; nf--) {	/* Reflect the change to all FAT copies */
+					wsect += fs->fsize;
+					disk_write(fs->drv, fs->win, wsect, 1);
+				}
+			}
+		}
+#endif
+		if (sector) {
+			if (disk_read(fs->drv, 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;
+			/* Create FSInfo structure */
+			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);
+			/* Write it into the FSInfo sector */
+			disk_write(fs->drv, 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->drv, CTRL_SYNC, 0) != RES_OK)
+			res = FR_DISK_ERR;
+	}
+
+	return res;
+}
+#endif
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* 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->n_fatent - 2)) return 0;		/* Invalid cluster# */
+	return clst * fs->csize + fs->database;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* FAT access - Read value of a FAT entry                                */
+/*-----------------------------------------------------------------------*/
+
+
+DWORD get_fat (	/* 0xFFFFFFFF:Disk error, 1:Internal error, Else:Cluster status */
+	FATFS *fs,	/* File system object */
+	DWORD clst	/* Cluster# to get the link information */
+)
+{
+	UINT wc, bc;
+	BYTE *p;
+
+
+	if (clst < 2 || clst >= fs->n_fatent)	/* Chack range */
+		return 1;
+
+	switch (fs->fs_type) {
+	case FS_FAT12 :
+		bc = (UINT)clst; bc += bc / 2;
+		if (move_window(fs, fs->fatbase + (bc / SS(fs)))) break;
+		wc = fs->win[bc % SS(fs)]; bc++;
+		if (move_window(fs, fs->fatbase + (bc / SS(fs)))) break;
+		wc |= fs->win[bc % SS(fs)] << 8;
+		return (clst & 1) ? (wc >> 4) : (wc & 0xFFF);
+
+	case FS_FAT16 :
+		if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 2)))) break;
+		p = &fs->win[clst * 2 % SS(fs)];
+		return LD_WORD(p);
+
+	case FS_FAT32 :
+		if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4)))) break;
+		p = &fs->win[clst * 4 % SS(fs)];
+		return LD_DWORD(p) & 0x0FFFFFFF;
+	}
+
+	return 0xFFFFFFFF;	/* An error occurred 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->n_fatent - 1 */
+	DWORD val	/* New value to mark the cluster */
+)
+{
+	UINT bc;
+	BYTE *p;
+	FRESULT res;
+
+
+	if (clst < 2 || clst >= fs->n_fatent) {	/* Check range */
+		res = FR_INT_ERR;
+
+	} else {
+		switch (fs->fs_type) {
+		case FS_FAT12 :
+			bc = clst; bc += bc / 2;
+			res = move_window(fs, fs->fatbase + (bc / SS(fs)));
+			if (res != FR_OK) break;
+			p = &fs->win[bc % SS(fs)];
+			*p = (clst & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val;
+			bc++;
+			fs->wflag = 1;
+			res = move_window(fs, fs->fatbase + (bc / SS(fs)));
+			if (res != FR_OK) break;
+			p = &fs->win[bc % SS(fs)];
+			*p = (clst & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F));
+			break;
+
+		case FS_FAT16 :
+			res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 2)));
+			if (res != FR_OK) break;
+			p = &fs->win[clst * 2 % SS(fs)];
+			ST_WORD(p, (WORD)val);
+			break;
+
+		case FS_FAT32 :
+			res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 4)));
+			if (res != FR_OK) break;
+			p = &fs->win[clst * 4 % SS(fs)];
+			val |= LD_DWORD(p) & 0xF0000000;
+			ST_DWORD(p, 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 _USE_ERASE
+	DWORD scl = clst, ecl = clst, resion[2];
+#endif
+
+	if (clst < 2 || clst >= fs->n_fatent) {	/* Check range */
+		res = FR_INT_ERR;
+
+	} else {
+		res = FR_OK;
+		while (clst < fs->n_fatent) {			/* 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;
+			}
+#if _USE_ERASE
+			if (ecl + 1 == nxt) {	/* Next cluster is contiguous */
+				ecl = nxt;
+			} else {				/* End of contiguous clusters */ 
+				resion[0] = clust2sect(fs, scl);					/* Start sector */
+				resion[1] = clust2sect(fs, ecl) + fs->csize - 1;	/* End sector */
+				disk_ioctl(fs->drv, CTRL_ERASE_SECTOR, resion);		/* Erase the block */
+				scl = ecl = nxt;
+			}
+#endif
+			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;
+	FRESULT res;
+
+
+	if (clst == 0) {		/* Create a new chain */
+		scl = fs->last_clust;			/* Get suggested start point */
+		if (!scl || scl >= fs->n_fatent) scl = 1;
+	}
+	else {					/* Stretch the current chain */
+		cs = get_fat(fs, clst);			/* Check the cluster status */
+		if (cs < 2) return 1;			/* It is an invalid cluster */
+		if (cs < fs->n_fatent) return cs;	/* It is already followed by next cluster */
+		scl = clst;
+	}
+
+	ncl = scl;				/* Start cluster */
+	for (;;) {
+		ncl++;							/* Next cluster */
+		if (ncl >= fs->n_fatent) {		/* Wrap around */
+			ncl = 2;
+			if (ncl > scl) return 0;	/* No free cluster */
+		}
+		cs = get_fat(fs, ncl);			/* Get the cluster status */
+		if (cs == 0) break;				/* Found a free cluster */
+		if (cs == 0xFFFFFFFF || cs == 1)/* An error occurred */
+			return cs;
+		if (ncl == scl) return 0;		/* No free cluster */
+	}
+
+	res = put_fat(fs, ncl, 0x0FFFFFFF);	/* Mark the new cluster "last link" */
+	if (res == FR_OK && clst != 0) {
+		res = put_fat(fs, clst, ncl);	/* Link it to the previous one if needed */
+	}
+	if (res == FR_OK) {
+		fs->last_clust = ncl;			/* Update FSINFO */
+		if (fs->free_clust != 0xFFFFFFFF) {
+			fs->free_clust--;
+			fs->fsi_flag = 1;
+		}
+	} else {
+		ncl = (res == FR_DISK_ERR) ? 0xFFFFFFFF : 1;
+	}
+
+	return ncl;		/* Return new cluster number or error code */
+}
+#endif /* !_FS_READONLY */
+
+
+
+/*-----------------------------------------------------------------------*/
+/* FAT handling - Convert offset into cluster with link map table        */
+/*-----------------------------------------------------------------------*/
+
+#if _USE_FASTSEEK
+static
+DWORD clmt_clust (	/* <2:Error, >=2:Cluster number */
+	FIL* fp,		/* Pointer to the file object */
+	DWORD ofs		/* File offset to be converted to cluster# */
+)
+{
+	DWORD cl, ncl, *tbl;
+
+
+	tbl = fp->cltbl + 1;	/* Top of CLMT */
+	cl = ofs / SS(fp->fs) / fp->fs->csize;	/* Cluster order from top of the file */
+	for (;;) {
+		ncl = *tbl++;			/* Number of cluters in the fragment */
+		if (!ncl) return 0;		/* End of table? (error) */
+		if (cl < ncl) break;	/* In this fragment? */
+		cl -= ncl; tbl++;		/* Next fragment */
+	}
+	return cl + *tbl;	/* Return the cluster number */
+}
+#endif	/* _USE_FASTSEEK */
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Directory handling - Set directory index                              */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT dir_sdi (
+	FATFS_DIR *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->n_fatent)	/* 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 (root-dir in FAT12/16) */
+		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) / SZ_DIR);	/* Sector# */
+	}
+	else {				/* Dynamic table (sub-dirs or root-dir in FAT32) */
+		ic = SS(dj->fs) / SZ_DIR * 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->n_fatent)	/* 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) / SZ_DIR);	/* Sector# */
+	}
+
+	dj->dir = dj->fs->win + (idx % (SS(dj->fs) / SZ_DIR)) * SZ_DIR;	/* 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 stretch */
+	FATFS_DIR *dj,		/* Pointer to directory object */
+	int stretch		/* 0: Do not stretch table, 1: Stretch table if needed */
+)
+{
+	DWORD clst;
+	WORD i;
+
+
+	stretch = stretch;		/* To suppress warning on read-only cfg. */
+	i = dj->index + 1;
+	if (!i || !dj->sect)	/* Report EOT when index has reached 65535 */
+		return FR_NO_FILE;
+
+	if (!(i % (SS(dj->fs) / SZ_DIR))) {	/* 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) / SZ_DIR)) & (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->n_fatent) {					/* When it reached end of dynamic table */
+#if !_FS_READONLY
+					BYTE c;
+					if (!stretch) return FR_NO_FILE;			/* When do not stretch, report EOT */
+					clst = create_chain(dj->fs, dj->clust);		/* Stretch 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 stretched 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) / SZ_DIR)) * SZ_DIR;
+
+	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
+int cmp_lfn (			/* 1:Matched, 0:Not matched */
+	WCHAR *lfnbuf,		/* Pointer to the LFN to be compared */
+	BYTE *dir			/* Pointer to the directory entry containing a part of LFN */
+)
+{
+	UINT i, s;
+	WCHAR wc, uc;
+
+
+	i = ((dir[LDIR_Ord] & ~LLE) - 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 0;				/* Not matched */
+		} else {
+			if (uc != 0xFFFF) return 0;	/* Check filler */
+		}
+	} while (++s < 13);				/* Repeat until all chars in the entry are checked */
+
+	if ((dir[LDIR_Ord] & LLE) && wc && lfnbuf[i])	/* Last segment matched but different length */
+		return 0;
+
+	return 1;						/* The part of LFN matched */
+}
+
+
+
+static
+int pick_lfn (			/* 1:Succeeded, 0:Buffer overflow */
+	WCHAR *lfnbuf,		/* Pointer to the Unicode-LFN buffer */
+	BYTE *dir			/* Pointer to the directory entry */
+)
+{
+	UINT 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 0;	/* Buffer overflow? */
+			lfnbuf[i++] = wc = uc;			/* Store it */
+		} else {
+			if (uc != 0xFFFF) return 0;		/* Check filler */
+		}
+	} while (++s < 13);						/* Read all character in the entry */
+
+	if (dir[LDIR_Ord] & LLE) {				/* Put terminator if it is the last LFN part */
+		if (i >= _MAX_LFN) return 0;		/* Buffer overflow? */
+		lfnbuf[i] = 0;
+	}
+
+	return 1;
+}
+
+
+#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 */
+)
+{
+	UINT 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 |= LLE;	/* 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 generated SFN */
+	const BYTE *src,	/* Pointer to source SFN to be modified */
+	const WCHAR *lfn,	/* Pointer to LFN */
+	WORD seq			/* Sequence number */
+)
+{
+	BYTE ns[8], c;
+	UINT i, j;
+
+
+	mem_cpy(dst, src, 11);
+
+	if (seq > 5) {	/* On many collisions, generate a hash number instead of sequential number */
+		do seq = (seq >> 1) + (seq << 15) + (WORD)*lfn++; while (*lfn);
+	}
+
+	/* itoa (hexdecimal) */
+	i = 7;
+	do {
+		c = (seq % 16) + '0';
+		if (c > '9') c += 7;
+		ns[i--] = c;
+		seq /= 16;
+	} while (seq);
+	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;
+	UINT 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 (
+	FATFS_DIR *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_sdi(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 == DDE || ((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 & LLE) {		/* Is it start of LFN sequence? */
+						sum = dir[LDIR_Chksum];
+						c &= ~LLE; 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, 0);		/* Next entry */
+	} while (res == FR_OK);
+
+	return res;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Read an object from the directory                                     */
+/*-----------------------------------------------------------------------*/
+#if _FS_MINIMIZE <= 1
+static
+FRESULT dir_read (
+	FATFS_DIR *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 == DDE || (!_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 & LLE) {			/* Is it start of LFN sequence? */
+					sum = dir[LDIR_Chksum];
+					c &= ~LLE; 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 != DDE && (_FS_RPATH || c != '.') && !(dir[DIR_Attr] & AM_VOL))	/* Is it a valid entry? */
+			break;
+#endif
+		res = dir_next(dj, 0);				/* 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 */
+	FATFS_DIR *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))		/* Cannot create dot entry */
+		return FR_INVALID_NAME;
+
+	if (sn[NS] & NS_LOSS) {			/* When LFN is out of 8.3 format, generate a numbered name */
+		fn[NS] = 0; dj->lfn = 0;			/* 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 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_sdi(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 == DDE || c == 0) {	/* Is it a blank entry? */
+			if (n == 0) is = dj->index;	/* First index of the contiguous entry */
+			if (++n == ne) break;	/* A contiguous entry that required count is found */
+		} else {
+			n = 0;					/* Not a blank entry. Restart to search */
+		}
+		res = dir_next(dj, 1);		/* Next entry with table stretch */
+	} while (res == FR_OK);
+
+	if (res == FR_OK && ne > 1) {	/* Initialize LFN entry if needed */
+		res = dir_sdi(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, 0);	/* Next entry */
+			} while (res == FR_OK && --ne);
+		}
+	}
+
+#else	/* Non LFN configuration */
+	res = dir_sdi(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 == DDE || c == 0) break;	/* Is it a blank entry? */
+			res = dir_next(dj, 1);			/* Next entry with table stretch */
+		} 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, SZ_DIR);	/* Clean the entry */
+			mem_cpy(dir, dj->fn, 11);	/* Put SFN */
+#if _USE_LFN
+			dir[DIR_NTres] = *(dj->fn+NS) & (NS_BODY | NS_EXT);	/* Put NT flag */
+#endif
+			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 */
+	FATFS_DIR *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_sdi(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 = DDE;			/* 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, 0);		/* Next entry */
+		} while (res == FR_OK);
+		if (res == FR_NO_FILE) res = FR_INT_ERR;
+	}
+
+#else			/* Non LFN configuration */
+	res = dir_sdi(dj, dj->index);
+	if (res == FR_OK) {
+		res = move_window(dj->fs, dj->sect);
+		if (res == FR_OK) {
+			*dj->dir = DDE;			/* 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 (
+	FATFS_DIR *dj,			/* Pointer to the directory object */
+	const TCHAR **path	/* Pointer to pointer to the segment in the path string */
+)
+{
+#ifdef _EXCVT
+	static const BYTE excvt[] = _EXCVT;	/* Upper conversion table for extended chars */
+#endif
+
+#if _USE_LFN	/* LFN configuration */
+	BYTE b, cf;
+	WCHAR w, *lfn;
+	UINT i, ni, si, di;
+	const TCHAR *p;
+
+	/* Create LFN in Unicode */
+	for (p = *path; *p == '/' || *p == '\\'; p++) ;	/* Strip duplicated separator */
+	lfn = dj->lfn;
+	si = di = 0;
+	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)) {				/* Check if it is a DBC 1st byte (always false on SBCS cfg) */
+			b = (BYTE)p[si++];			/* Get 2nd byte */
+			if (!IsDBCS2(b))
+				return FR_INVALID_NAME;	/* Reject invalid sequence */
+			w = (w << 8) + b;			/* Create a DBC */
+		}
+		w = ff_convert(w, 1);			/* Convert ANSI/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];						/* Return 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 nul 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 end 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 = excvt[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 (always false on SBCS cfg) */
+			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] == DDE) dj->fn[0] = NDDE;	/* 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;
+	UINT ni, si, i;
+	const char *p;
+
+	/* Create file name in directory form */
+	for (p = *path; *p == '/' || *p == '\\'; p++) ;	/* Strip duplicated separator */
+	sfn = dj->fn;
+	mem_set(sfn, ' ', 11);
+	si = i = b = 0; ni = 8;
+#if _FS_RPATH
+	if (p[si] == '.') { /* Is this a dot entry? */
+		for (;;) {
+			c = (BYTE)p[si++];
+			if (c != '.' || si >= 3) break;
+			sfn[i++] = c;
+		}
+		if (c != '/' && c != '\\' && c > ' ') return FR_INVALID_NAME;
+		*path = &p[si];									/* Return 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 = (BYTE)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? */
+			b |= 3;						/* Eliminate NT flag */
+#ifdef _EXCVT
+			c = excvt[c-0x80];			/* Upper conversion (SBCS) */
+#else
+#if !_DF1S	/* ASCII only cfg */
+			return FR_INVALID_NAME;
+#endif
+#endif
+		}
+		if (IsDBCS1(c)) {				/* Check if it is a DBC 1st byte (always false on SBCS cfg) */
+			d = (BYTE)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];						/* Return 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 nul string */
+	if (sfn[0] == DDE) sfn[0] = NDDE;	/* When first char collides with DDE, replace it with 0x05 */
+
+	if (ni == 8) b <<= 2;
+	if ((b & 0x03) == 0x01) c |= NS_EXT;	/* NT flag (Name extension has only small capital) */
+	if ((b & 0x0C) == 0x04) c |= NS_BODY;	/* NT flag (Name body 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 */
+	FATFS_DIR *dj,			/* Pointer to the directory object */
+	FILINFO *fno	 	/* Pointer to the file information to be filled */
+)
+{
+	UINT i;
+	BYTE nt, *dir;
+	TCHAR *p, c;
+
+
+	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 == NDDE) c = (TCHAR)DDE;
+			if (_USE_LFN && (nt & NS_BODY) && IsUpper(c)) c += 0x20;
+#if _LFN_UNICODE
+			if (IsDBCS1(c) && i < 7 && IsDBCS2(dir[i+1]))
+				c = (c << 8) | dir[++i];
+			c = ff_convert(c, 1);
+			if (!c) c = '?';
+#endif
+			*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;
+#if _LFN_UNICODE
+				if (IsDBCS1(c) && i < 10 && IsDBCS2(dir[i+1]))
+					c = (c << 8) | dir[++i];
+				c = ff_convert(c, 1);
+				if (!c) c = '?';
+#endif
+				*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;		/* Terminate SFN str by a \0 */
+
+#if _USE_LFN
+	if (fno->lfname && fno->lfsize) {
+		TCHAR *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 (always false on SBCS cfg) */
+					tp[i++] = (TCHAR)(w >> 8);
+#endif
+				if (i >= fno->lfsize - 1) { i = 0; break; }	/* Buffer overflow, no LFN */
+				tp[i++] = (TCHAR)w;
+			}
+		}
+		tp[i] = 0;	/* Terminate the LFN str by a \0 */
+	}
+#endif
+}
+#endif /* _FS_MINIMIZE <= 1 */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Follow a file path                                                    */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT follow_path (	/* FR_OK(0): successful, !=0: error code */
+	FATFS_DIR *dj,			/* Directory object to return last directory and found object */
+	const TCHAR *path	/* Full-path string to find a file or directory */
+)
+{
+	FRESULT res;
+	BYTE *dir, ns;
+
+
+#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 separator */
+		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 < ' ') {			/* Nul path means the start directory itself */
+		res = dir_sdi(dj, 0);
+		dj->dir = 0;
+
+	} else {							/* Follow path */
+		for (;;) {
+			res = create_name(dj, &path);	/* Get a segment */
+			if (res != FR_OK) break;
+			res = dir_find(dj);				/* Find it */
+			ns = *(dj->fn+NS);
+			if (res != FR_OK) {				/* Failed to find the object */
+				if (res != FR_NO_FILE) break;	/* Abort if any hard error occured */
+				/* Object not found */
+				if (_FS_RPATH && (ns & NS_DOT)) {	/* If dot entry is not exit */
+					dj->sclust = 0; dj->dir = 0;	/* It is the root dir */
+					res = FR_OK;
+					if (!(ns & NS_LAST)) continue;
+				} else {							/* Could not find the object */
+					if (!(ns & NS_LAST)) res = FR_NO_PATH;
+				}
+				break;
+			}
+			if (ns & NS_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 = LD_CLUST(dir);
+		}
+	}
+
+	return res;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Load a sector and check if it is an FAT Volume Boot Record            */
+/*-----------------------------------------------------------------------*/
+
+static
+BYTE check_fs (	/* 0:FAT-VBR, 1:Valid BR but not FAT, 2:Not a BR, 3:Disk 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->drv, 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;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Check if the file system object is valid or not                       */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT chk_mounted (	/* FR_OK(0): successful, !=0: any error occurred */
+	const TCHAR **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, b, pi, *tbl;
+	UINT vol;
+	DSTATUS stat;
+	DWORD bsect, fasize, tsect, sysect, nclst, szbfat;
+	WORD nrsv;
+	const TCHAR *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 = CurrVol;					/* Use current drive */
+#else
+		vol = 0;						/* Use drive 0 */
+#endif
+	}
+
+	/* Check if the file system object is valid or not */
+	if (vol >= _VOLUMES) 				/* Is the drive number valid? */
+		return FR_INVALID_DRIVE;
+	*rfs = fs = FatFs[vol];				/* Return 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->drv);
+		if (!(stat & STA_NOINIT)) {		/* and the physical drive is kept initialized (has not been changed), */
+			if (!_FS_READONLY && chk_wp && (stat & STA_PROTECT))	/* Check write protection if needed */
+				return FR_WRITE_PROTECTED;
+			return FR_OK;				/* The file system object is valid */
+		}
+	}
+
+	/* The file system object is not valid. */
+	/* Following code attempts to mount the volume. (analyze BPB and initialize the fs object) */
+
+	fs->fs_type = 0;					/* Clear the file system object */
+	fs->drv = LD2PD(vol);				/* Bind the logical drive and a physical drive */
+	stat = disk_initialize(fs->drv);	/* Initialize low level disk I/O layer */
+	if (stat & STA_NOINIT)				/* Check if the initialization succeeded */
+		return FR_NOT_READY;			/* Failed to initialize due to no media or hard error */
+	if (!_FS_READONLY && chk_wp && (stat & STA_PROTECT))	/* Check disk write protection if needed */
+		return FR_WRITE_PROTECTED;
+#if _MAX_SS != 512						/* Get disk sector size (variable sector size cfg only) */
+	if (disk_ioctl(fs->drv, GET_SECTOR_SIZE, &fs->ssize) != RES_OK)
+		return FR_DISK_ERR;
+#endif
+	/* Search FAT partition on the drive. Supports only generic partitionings, FDISK and SFD. */
+	fmt = check_fs(fs, bsect = 0);		/* Load sector 0 and check if it is an FAT-VBR (in SFD) */
+	if (LD2PT(vol) && !fmt) fmt = 1;	/* Force non-SFD if the volume is forced partition */
+	if (fmt == 1) {						/* Not an FAT-VBR, the physical drive can be partitioned */
+		/* Check the partition listed in the partition table */
+		pi = LD2PT(vol);
+		if (pi) pi--;
+		tbl = &fs->win[MBR_Table + pi * SZ_PTE];/* 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) return FR_NO_FILESYSTEM;		/* No FAT volume is found */
+
+	/* An FAT volume is found. Following code initializes the file system object */
+
+	if (LD_WORD(fs->win+BPB_BytsPerSec) != SS(fs))		/* (BPB_BytsPerSec must be equal to the physical sector size) */
+		return FR_NO_FILESYSTEM;
+
+	fasize = LD_WORD(fs->win+BPB_FATSz16);				/* Number of sectors per FAT */
+	if (!fasize) fasize = LD_DWORD(fs->win+BPB_FATSz32);
+	fs->fsize = fasize;
+
+	fs->n_fats = b = fs->win[BPB_NumFATs];				/* Number of FAT copies */
+	if (b != 1 && b != 2) return FR_NO_FILESYSTEM;		/* (Must be 1 or 2) */
+	fasize *= b;										/* Number of sectors for FAT area */
+
+	fs->csize = b = fs->win[BPB_SecPerClus];			/* Number of sectors per cluster */
+	if (!b || (b & (b - 1))) return FR_NO_FILESYSTEM;	/* (Must be power of 2) */
+
+	fs->n_rootdir = LD_WORD(fs->win+BPB_RootEntCnt);	/* Number of root directory entries */
+	if (fs->n_rootdir % (SS(fs) / SZ_DIR)) return FR_NO_FILESYSTEM;	/* (BPB_RootEntCnt must be sector aligned) */
+
+	tsect = LD_WORD(fs->win+BPB_TotSec16);				/* Number of sectors on the volume */
+	if (!tsect) tsect = LD_DWORD(fs->win+BPB_TotSec32);
+
+	nrsv = LD_WORD(fs->win+BPB_RsvdSecCnt);				/* Number of reserved sectors */
+	if (!nrsv) return FR_NO_FILESYSTEM;					/* (BPB_RsvdSecCnt must not be 0) */
+
+	/* Determine the FAT sub type */
+	sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZ_DIR);	/* RSV+FAT+FATFS_DIR */
+	if (tsect < sysect) return FR_NO_FILESYSTEM;		/* (Invalid volume size) */
+	nclst = (tsect - sysect) / fs->csize;				/* Number of clusters */
+	if (!nclst) return FR_NO_FILESYSTEM;				/* (Invalid volume size) */
+	fmt = FS_FAT12;
+	if (nclst >= MIN_FAT16) fmt = FS_FAT16;
+	if (nclst >= MIN_FAT32) fmt = FS_FAT32;
+
+	/* Boundaries and Limits */
+	fs->n_fatent = nclst + 2;							/* Number of FAT entries */
+	fs->database = bsect + sysect;						/* Data start sector */
+	fs->fatbase = bsect + nrsv; 						/* FAT start sector */
+	if (fmt == FS_FAT32) {
+		if (fs->n_rootdir) return FR_NO_FILESYSTEM;		/* (BPB_RootEntCnt must be 0) */
+		fs->dirbase = LD_DWORD(fs->win+BPB_RootClus);	/* Root directory start cluster */
+		szbfat = fs->n_fatent * 4;						/* (Required FAT size) */
+	} else {
+		if (!fs->n_rootdir)	return FR_NO_FILESYSTEM;	/* (BPB_RootEntCnt must not be 0) */
+		fs->dirbase = fs->fatbase + fasize;				/* Root directory start sector */
+		szbfat = (fmt == FS_FAT16) ?					/* (Required FAT size) */
+			fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1);
+	}
+	if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs))	/* (BPB_FATSz must not be less than required) */
+		return FR_NO_FILESYSTEM;
+
+#if !_FS_READONLY
+	/* Initialize cluster allocation information */
+	fs->free_clust = 0xFFFFFFFF;
+	fs->last_clust = 0;
+
+	/* Get fsinfo if available */
+	if (fmt == FS_FAT32) {
+	 	fs->fsi_flag = 0;
+		fs->fsi_sector = bsect + LD_WORD(fs->win+BPB_FSInfo);
+		if (disk_read(fs->drv, 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->id = ++Fsid;		/* File system mount ID */
+	fs->winsect = 0;		/* Invalidate sector cache */
+	fs->wflag = 0;
+#if _FS_RPATH
+	fs->cdir = 0;			/* Current directory (root dir) */
+#endif
+#if _FS_SHARE				/* Clear file lock semaphores */
+	clear_lock(fs);
+#endif
+
+	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->drv) & STA_NOINIT)
+		return FR_NOT_READY;
+
+	return FR_OK;
+}
+
+
+
+
+/*--------------------------------------------------------------------------
+
+   Public Functions
+
+--------------------------------------------------------------------------*/
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Mount/Unmount a Logical 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 >= _VOLUMES)		/* Check if the drive number is valid */
+		return FR_INVALID_DRIVE;
+	rfs = FatFs[vol];			/* Get current fs object */
+
+	if (rfs) {
+#if _FS_SHARE
+		clear_lock(rfs);
+#endif
+#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 TCHAR *path,	/* Pointer to the file name */
+	BYTE mode			/* Access mode and file open mode flags */
+)
+{
+	FRESULT res;
+	FATFS_DIR dj;
+	BYTE *dir;
+	DEF_NAMEBUF;
+
+
+	fp->fs = 0;			/* 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_READ));
+#else
+	mode &= FA_READ;
+	res = chk_mounted(&path, &dj.fs, 0);
+#endif
+	INIT_BUF(dj);
+	if (res == FR_OK)
+		res = follow_path(&dj, path);	/* Follow the file path */
+	dir = dj.dir;
+
+#if !_FS_READONLY	/* R/W configuration */
+	if (res == FR_OK) {
+		if (!dir)	/* Current dir itself */
+			res = FR_INVALID_NAME;
+#if _FS_SHARE
+		else
+			res = chk_lock(&dj, (mode & ~FA_READ) ? 1 : 0);
+#endif
+	}
+	/* Create or Open a file */
+	if (mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) {
+		DWORD dw, cl;
+
+		if (res != FR_OK) {					/* No file, create new */
+			if (res == FR_NO_FILE)			/* There is no file to open, create a new entry */
+#if _FS_SHARE
+				res = enq_lock() ? dir_register(&dj) : FR_TOO_MANY_OPEN_FILES;
+#else
+				res = dir_register(&dj);
+#endif
+			mode |= FA_CREATE_ALWAYS;		/* File is created */
+			dir = dj.dir;					/* New entry */
+		}
+		else {								/* Any object is already existing */
+			if (dir[DIR_Attr] & (AM_RDO | AM_DIR)) {	/* Cannot overwrite it (R/O or FATFS_DIR) */
+				res = FR_DENIED;
+			} else {
+				if (mode & FA_CREATE_NEW)	/* Cannot create as new file */
+					res = FR_EXIST;
+			}
+		}
+		if (res == FR_OK && (mode & FA_CREATE_ALWAYS)) {	/* Truncate it if overwrite mode */
+			dw = get_fattime();					/* Created time */
+			ST_DWORD(dir+DIR_CrtTime, dw);
+			dir[DIR_Attr] = 0;					/* Reset attribute */
+			ST_DWORD(dir+DIR_FileSize, 0);		/* size = 0 */
+			cl = LD_CLUST(dir);					/* Get start cluster */
+			ST_CLUST(dir, 0);					/* cluster = 0 */
+			dj.fs->wflag = 1;
+			if (cl) {							/* Remove the cluster chain if exist */
+				dw = dj.fs->winsect;
+				res = remove_chain(dj.fs, cl);
+				if (res == FR_OK) {
+					dj.fs->last_clust = cl - 1;	/* Reuse the cluster hole */
+					res = move_window(dj.fs, dw);
+				}
+			}
+		}
+	}
+	else {	/* Open an existing file */
+		if (res == FR_OK) {						/* Follow succeeded */
+			if (dir[DIR_Attr] & AM_DIR) {		/* It is a directory */
+				res = FR_NO_FILE;
+			} else {
+				if ((mode & FA_WRITE) && (dir[DIR_Attr] & AM_RDO)) /* R/O violation */
+					res = FR_DENIED;
+			}
+		}
+	}
+	if (res == FR_OK) {
+		if (mode & FA_CREATE_ALWAYS)			/* Set file change flag if created or overwritten */
+			mode |= FA__WRITTEN;
+		fp->dir_sect = dj.fs->winsect;			/* Pointer to the directory entry */
+		fp->dir_ptr = dir;
+#if _FS_SHARE
+		fp->lockid = inc_lock(&dj, (mode & ~FA_READ) ? 1 : 0);
+		if (!fp->lockid) res = FR_INT_ERR;
+#endif
+	}
+
+#else				/* R/O configuration */
+	if (res == FR_OK) {					/* Follow succeeded */
+		if (!dir) {						/* Current dir itself */
+			res = FR_INVALID_NAME;
+		} else {
+			if (dir[DIR_Attr] & AM_DIR)	/* It is a directory */
+				res = FR_NO_FILE;
+		}
+	}
+#endif
+	FREE_BUF();
+
+	if (res == FR_OK) {
+		fp->flag = mode;					/* File access mode */
+		fp->sclust = LD_CLUST(dir);			/* File start cluster */
+		fp->fsize = LD_DWORD(dir+DIR_FileSize);	/* File size */
+		fp->fptr = 0;						/* File pointer */
+		fp->dsect = 0;
+#if _USE_FASTSEEK
+		fp->cltbl = 0;						/* Normal seek mode */
+#endif
+		fp->fs = dj.fs; fp->id = dj.fs->id;	/* Validate file object */
+	}
+
+	LEAVE_FF(dj.fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* 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 csect, *rbuff = (BYTE*)buff;
+
+
+	*br = 0;	/* Initialize byte counter */
+
+	res = validate(fp->fs, fp->id);				/* Check validity */
+	if (res != FR_OK) LEAVE_FF(fp->fs, res);
+	if (fp->flag & FA__ERROR)					/* Aborted file? */
+		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 read */
+		rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) {
+		if ((fp->fptr % SS(fp->fs)) == 0) {		/* On the sector boundary? */
+			csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1));	/* Sector offset in the cluster */
+			if (!csect) {						/* On the cluster boundary? */
+				if (fp->fptr == 0) {			/* On the top of the file? */
+					clst = fp->sclust;			/* Follow from the origin */
+				} else {						/* Middle or end of the file */
+#if _USE_FASTSEEK
+					if (fp->cltbl)
+						clst = clmt_clust(fp, fp->fptr);	/* Get cluster# from the CLMT */
+					else
+#endif
+						clst = get_fat(fp->fs, fp->clust);	/* Follow cluster chain on the FAT */
+				}
+				if (clst < 2) ABORT(fp->fs, FR_INT_ERR);
+				if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
+				fp->clust = clst;				/* Update current cluster */
+			}
+			sect = clust2sect(fp->fs, fp->clust);	/* Get current sector */
+			if (!sect) ABORT(fp->fs, FR_INT_ERR);
+			sect += csect;
+			cc = btr / SS(fp->fs);				/* When remaining bytes >= sector size, */
+			if (cc) {							/* Read maximum contiguous sectors directly */
+				if (csect + cc > fp->fs->csize)	/* Clip at cluster boundary */
+					cc = fp->fs->csize - csect;
+				if (disk_read(fp->fs->drv, rbuff, sect, (BYTE)cc) != RES_OK)
+					ABORT(fp->fs, FR_DISK_ERR);
+#if !_FS_READONLY && _FS_MINIMIZE <= 2			/* Replace one of the read sectors with cached data if it contains a dirty sector */
+#if _FS_TINY
+				if (fp->fs->wflag && fp->fs->winsect - sect < cc)
+					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)
+					mem_cpy(rbuff + ((fp->dsect - sect) * SS(fp->fs)), fp->buf, SS(fp->fs));
+#endif
+#endif
+				rcnt = SS(fp->fs) * cc;			/* Number of bytes transferred */
+				continue;
+			}
+#if !_FS_TINY
+			if (fp->dsect != sect) {			/* Load data sector if not in cache */
+#if !_FS_READONLY
+				if (fp->flag & FA__DIRTY) {		/* Write-back dirty sector cache */
+					if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
+						ABORT(fp->fs, FR_DISK_ERR);
+					fp->flag &= ~FA__DIRTY;
+				}
+#endif
+				if (disk_read(fp->fs->drv, fp->buf, sect, 1) != RES_OK)	/* Fill sector cache */
+					ABORT(fp->fs, FR_DISK_ERR);
+			}
+#endif
+			fp->dsect = sect;
+		}
+		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;
+	BYTE csect;
+
+
+	*bw = 0;	/* Initialize byte counter */
+
+	res = validate(fp->fs, fp->id);			/* Check validity */
+	if (res != FR_OK) LEAVE_FF(fp->fs, res);
+	if (fp->flag & FA__ERROR)				/* Aborted file? */
+		LEAVE_FF(fp->fs, FR_INT_ERR);
+	if (!(fp->flag & FA_WRITE))				/* Check access mode */
+		LEAVE_FF(fp->fs, FR_DENIED);
+	if ((DWORD)(fp->fsize + btw) < fp->fsize) btw = 0;	/* File size cannot reach 4GB */
+
+	for ( ;  btw;							/* Repeat until all data written */
+		wbuff += wcnt, fp->fptr += wcnt, *bw += wcnt, btw -= wcnt) {
+		if ((fp->fptr % SS(fp->fs)) == 0) {	/* On the sector boundary? */
+			csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1));	/* Sector offset in the cluster */
+			if (!csect) {					/* On the cluster boundary? */
+				if (fp->fptr == 0) {		/* On the top of the file? */
+					clst = fp->sclust;		/* Follow from the origin */
+					if (clst == 0)			/* When no cluster is allocated, */
+						fp->sclust = clst = create_chain(fp->fs, 0);	/* Create a new cluster chain */
+				} else {					/* Middle or end of the file */
+#if _USE_FASTSEEK
+					if (fp->cltbl)
+						clst = clmt_clust(fp, fp->fptr);	/* Get cluster# from the CLMT */
+					else
+#endif
+						clst = create_chain(fp->fs, fp->clust);	/* Follow or stretch cluster chain on the FAT */
+				}
+				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->clust = clst;			/* Update current cluster */
+			}
+#if _FS_TINY
+			if (fp->fs->winsect == fp->dsect && move_window(fp->fs, 0))	/* Write-back sector cache */
+				ABORT(fp->fs, FR_DISK_ERR);
+#else
+			if (fp->flag & FA__DIRTY) {		/* Write-back sector cache */
+				if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
+					ABORT(fp->fs, FR_DISK_ERR);
+				fp->flag &= ~FA__DIRTY;
+			}
+#endif
+			sect = clust2sect(fp->fs, fp->clust);	/* Get current sector */
+			if (!sect) ABORT(fp->fs, FR_INT_ERR);
+			sect += csect;
+			cc = btw / SS(fp->fs);			/* When remaining bytes >= sector size, */
+			if (cc) {						/* Write maximum contiguous sectors directly */
+				if (csect + cc > fp->fs->csize)	/* Clip at cluster boundary */
+					cc = fp->fs->csize - csect;
+				if (disk_write(fp->fs->drv, 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 invalidated 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 invalidated by the direct write */
+					mem_cpy(fp->buf, wbuff + ((fp->dsect - sect) * SS(fp->fs)), SS(fp->fs));
+					fp->flag &= ~FA__DIRTY;
+				}
+#endif
+				wcnt = SS(fp->fs) * cc;		/* Number of bytes transferred */
+				continue;
+			}
+#if _FS_TINY
+			if (fp->fptr >= fp->fsize) {	/* Avoid silly cache 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 cache with file data */
+				if (fp->fptr < fp->fsize &&
+					disk_read(fp->fs->drv, fp->buf, sect, 1) != RES_OK)
+						ABORT(fp->fs, FR_DISK_ERR);
+			}
+#endif
+			fp->dsect = sect;
+		}
+		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 change 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->drv, 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_CLUST(dir, fp->sclust);					/* Update start cluster */
+				tim = get_fattime();						/* Update 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
+	FATFS *fs = fp->fs;
+	res = validate(fs, fp->id);
+	if (res == FR_OK) fp->fs = 0;	/* Discard file object */
+	LEAVE_FF(fs, res);
+
+#else
+	res = f_sync(fp);		/* Flush cached data */
+#if _FS_SHARE
+	if (res == FR_OK) {		/* Decrement open counter */
+#if _FS_REENTRANT
+		res = validate(fp->fs, fp->id);
+		if (res == FR_OK) {
+			res = dec_lock(fp->lockid);	
+			unlock_fs(fp->fs, FR_OK);
+		}
+#else
+		res = dec_lock(fp->lockid);
+#endif
+	}
+#endif
+	if (res == FR_OK) fp->fs = 0;	/* Discard file object */
+	return res;
+#endif
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Current Drive/Directory Handlings                                     */
+/*-----------------------------------------------------------------------*/
+
+#if _FS_RPATH >= 1
+
+FRESULT f_chdrive (
+	BYTE drv		/* Drive number */
+)
+{
+	if (drv >= _VOLUMES) return FR_INVALID_DRIVE;
+
+	CurrVol = drv;
+
+	return FR_OK;
+}
+
+
+
+FRESULT f_chdir (
+	const TCHAR *path	/* Pointer to the directory path */
+)
+{
+	FRESULT res;
+	FATFS_DIR dj;
+	DEF_NAMEBUF;
+
+
+	res = chk_mounted(&path, &dj.fs, 0);
+	if (res == FR_OK) {
+		INIT_BUF(dj);
+		res = follow_path(&dj, path);		/* Follow the path */
+		FREE_BUF();
+		if (res == FR_OK) {					/* Follow completed */
+			if (!dj.dir) {
+				dj.fs->cdir = dj.sclust;	/* Start directory itself */
+			} else {
+				if (dj.dir[DIR_Attr] & AM_DIR)	/* Reached to the directory */
+					dj.fs->cdir = LD_CLUST(dj.dir);
+				else
+					res = FR_NO_PATH;		/* Reached but a file */
+			}
+		}
+		if (res == FR_NO_FILE) res = FR_NO_PATH;
+	}
+
+	LEAVE_FF(dj.fs, res);
+}
+
+
+#if _FS_RPATH >= 2
+FRESULT f_getcwd (
+	TCHAR *path,	/* Pointer to the directory path */
+	UINT sz_path	/* Size of path */
+)
+{
+	FRESULT res;
+	FATFS_DIR dj;
+	UINT i, n;
+	DWORD ccl;
+	TCHAR *tp;
+	FILINFO fno;
+	DEF_NAMEBUF;
+
+
+	*path = 0;
+	res = chk_mounted((const TCHAR**)&path, &dj.fs, 0);	/* Get current volume */
+	if (res == FR_OK) {
+		INIT_BUF(dj);
+		i = sz_path;		/* Bottom of buffer (dir stack base) */
+		dj.sclust = dj.fs->cdir;			/* Start to follow upper dir from current dir */
+		while ((ccl = dj.sclust) != 0) {	/* Repeat while current dir is a sub-dir */
+			res = dir_sdi(&dj, 1);			/* Get parent dir */
+			if (res != FR_OK) break;
+			res = dir_read(&dj);
+			if (res != FR_OK) break;
+			dj.sclust = LD_CLUST(dj.dir);	/* Goto parent dir */
+			res = dir_sdi(&dj, 0);
+			if (res != FR_OK) break;
+			do {							/* Find the entry links to the child dir */
+				res = dir_read(&dj);
+				if (res != FR_OK) break;
+				if (ccl == LD_CLUST(dj.dir)) break;	/* Found the entry */
+				res = dir_next(&dj, 0);	
+			} while (res == FR_OK);
+			if (res == FR_NO_FILE) res = FR_INT_ERR;/* It cannot be 'not found'. */
+			if (res != FR_OK) break;
+#if _USE_LFN
+			fno.lfname = path;
+			fno.lfsize = i;
+#endif
+			get_fileinfo(&dj, &fno);		/* Get the dir name and push it to the buffer */
+			tp = fno.fname;
+			if (_USE_LFN && *path) tp = path;
+			for (n = 0; tp[n]; n++) ;
+			if (i < n + 3) {
+				res = FR_NOT_ENOUGH_CORE; break;
+			}
+			while (n) path[--i] = tp[--n];
+			path[--i] = '/';
+		}
+		tp = path;
+		if (res == FR_OK) {
+			*tp++ = '0' + CurrVol;			/* Put drive number */
+			*tp++ = ':';
+			if (i == sz_path) {				/* Root-dir */
+				*tp++ = '/';
+			} else {						/* Sub-dir */
+				do		/* Add stacked path str */
+					*tp++ = path[i++];
+				while (i < sz_path);
+			}
+		}
+		*tp = 0;
+		FREE_BUF();
+	}
+
+	LEAVE_FF(dj.fs, res);
+}
+#endif /* _FS_RPATH >= 2 */
+#endif /* _FS_RPATH >= 1 */
+
+
+
+#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;
+
+
+	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 _USE_FASTSEEK
+	if (fp->cltbl) {	/* Fast seek */
+		DWORD cl, pcl, ncl, tcl, dsc, tlen, ulen, *tbl;
+
+		if (ofs == CREATE_LINKMAP) {	/* Create CLMT */
+			tbl = fp->cltbl;
+			tlen = *tbl++; ulen = 2;	/* Given table size and required table size */
+			cl = fp->sclust;			/* Top of the chain */
+			if (cl) {
+				do {
+					/* Get a fragment */
+					tcl = cl; ncl = 0; ulen += 2;	/* Top, length and used items */
+					do {
+						pcl = cl; ncl++;
+						cl = get_fat(fp->fs, cl);
+						if (cl <= 1) ABORT(fp->fs, FR_INT_ERR);
+						if (cl == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
+					} while (cl == pcl + 1);
+					if (ulen <= tlen) {		/* Store the length and top of the fragment */
+						*tbl++ = ncl; *tbl++ = tcl;
+					}
+				} while (cl < fp->fs->n_fatent);	/* Repeat until end of chain */
+			}
+			*fp->cltbl = ulen;	/* Number of items used */
+			if (ulen <= tlen)
+				*tbl = 0;		/* Terminate table */
+			else
+				res = FR_NOT_ENOUGH_CORE;	/* Given table size is smaller than required */
+
+		} else {						/* Fast seek */
+			if (ofs > fp->fsize)		/* Clip offset at the file size */
+				ofs = fp->fsize;
+			fp->fptr = ofs;				/* Set file pointer */
+			if (ofs) {
+				fp->clust = clmt_clust(fp, ofs - 1);
+				dsc = clust2sect(fp->fs, fp->clust);
+				if (!dsc) ABORT(fp->fs, FR_INT_ERR);
+				dsc += (ofs - 1) / SS(fp->fs) & (fp->fs->csize - 1);
+				if (fp->fptr % SS(fp->fs) && dsc != fp->dsect) {	/* Refill sector cache if needed */
+#if !_FS_TINY
+#if !_FS_READONLY
+					if (fp->flag & FA__DIRTY) {		/* Write-back dirty sector cache */
+						if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
+							ABORT(fp->fs, FR_DISK_ERR);
+						fp->flag &= ~FA__DIRTY;
+					}
+#endif
+					if (disk_read(fp->fs->drv, fp->buf, dsc, 1) != RES_OK)	/* Load current sector */
+						ABORT(fp->fs, FR_DISK_ERR);
+#endif
+					fp->dsect = dsc;
+				}
+			}
+		}
+	} else
+#endif
+
+	/* Normal Seek */
+	{
+		DWORD clst, bcs, nsect, ifptr;
+
+		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;
+		if (ofs) {
+			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->clust;
+			} else {									/* When seek to back cluster, */
+				clst = fp->sclust;						/* 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->sclust = clst;
+				}
+#endif
+				fp->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 stretch 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->n_fatent) ABORT(fp->fs, FR_INT_ERR);
+					fp->clust = clst;
+					fp->fptr += bcs;
+					ofs -= bcs;
+				}
+				fp->fptr += ofs;
+				if (ofs % SS(fp->fs)) {
+					nsect = clust2sect(fp->fs, clst);	/* Current sector */
+					if (!nsect) ABORT(fp->fs, FR_INT_ERR);
+					nsect += ofs / SS(fp->fs);
+				}
+			}
+		}
+		if (fp->fptr % SS(fp->fs) && nsect != fp->dsect) {	/* Fill sector cache if needed */
+#if !_FS_TINY
+#if !_FS_READONLY
+			if (fp->flag & FA__DIRTY) {			/* Write-back dirty sector cache */
+				if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
+					ABORT(fp->fs, FR_DISK_ERR);
+				fp->flag &= ~FA__DIRTY;
+			}
+#endif
+			if (disk_read(fp->fs->drv, fp->buf, nsect, 1) != RES_OK)	/* Fill sector cache */
+				ABORT(fp->fs, FR_DISK_ERR);
+#endif
+			fp->dsect = nsect;
+		}
+#if !_FS_READONLY
+		if (fp->fptr > fp->fsize) {			/* Set file change 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 (
+	FATFS_DIR *dj,			/* Pointer to directory object to create */
+	const TCHAR *path	/* Pointer to the directory path */
+)
+{
+	FRESULT res;
+	DEF_NAMEBUF;
+
+
+	res = chk_mounted(&path, &dj->fs, 0);
+	if (res == FR_OK) {
+		INIT_BUF(*dj);
+		res = follow_path(dj, path);			/* Follow the path to the directory */
+		FREE_BUF();
+		if (res == FR_OK) {						/* Follow completed */
+			if (dj->dir) {						/* It is not the root dir */
+				if (dj->dir[DIR_Attr] & AM_DIR) {	/* The object is a directory */
+					dj->sclust = LD_CLUST(dj->dir);
+				} else {						/* The object is not a directory */
+					res = FR_NO_PATH;
+				}
+			}
+			if (res == FR_OK) {
+				dj->id = dj->fs->id;
+				res = dir_sdi(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 (
+	FATFS_DIR *dj,			/* Pointer to the open directory object */
+	FILINFO *fno		/* Pointer to file information to return */
+)
+{
+	FRESULT res;
+	DEF_NAMEBUF;
+
+
+	res = validate(dj->fs, dj->id);			/* Check validity of the object */
+	if (res == FR_OK) {
+		if (!fno) {
+			res = dir_sdi(dj, 0);			/* Rewind the directory object */
+		} else {
+			INIT_BUF(*dj);
+			res = dir_read(dj);				/* Read an directory item */
+			if (res == FR_NO_FILE) {		/* Reached end of dir */
+				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, 0);		/* Increment index for next */
+				if (res == FR_NO_FILE) {
+					dj->sect = 0;
+					res = FR_OK;
+				}
+			}
+			FREE_BUF();
+		}
+	}
+
+	LEAVE_FF(dj->fs, res);
+}
+
+
+
+#if _FS_MINIMIZE == 0
+/*-----------------------------------------------------------------------*/
+/* Get File Status                                                       */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_stat (
+	const TCHAR *path,	/* Pointer to the file path */
+	FILINFO *fno		/* Pointer to file information to return */
+)
+{
+	FRESULT res;
+	FATFS_DIR dj;
+	DEF_NAMEBUF;
+
+
+	res = chk_mounted(&path, &dj.fs, 0);
+	if (res == FR_OK) {
+		INIT_BUF(dj);
+		res = follow_path(&dj, path);	/* Follow the file path */
+		if (res == FR_OK) {				/* Follow completed */
+			if (dj.dir)		/* Found an object */
+				get_fileinfo(&dj, fno);
+			else			/* It is root dir */
+				res = FR_INVALID_NAME;
+		}
+		FREE_BUF();
+	}
+
+	LEAVE_FF(dj.fs, res);
+}
+
+
+
+#if !_FS_READONLY
+/*-----------------------------------------------------------------------*/
+/* Get Number of Free Clusters                                           */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_getfree (
+	const TCHAR *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) {
+		/* If free_clust is valid, return it without full cluster scan */
+		if ((*fatfs)->free_clust <= (*fatfs)->n_fatent - 2) {
+			*nclst = (*fatfs)->free_clust;
+		} else {
+			/* 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) { res = FR_DISK_ERR; break; }
+					if (stat == 1) { res = FR_INT_ERR; break; }
+					if (stat == 0) n++;
+				} while (++clst < (*fatfs)->n_fatent);
+			} else {
+				clst = (*fatfs)->n_fatent;
+				sect = (*fatfs)->fatbase;
+				i = 0; p = 0;
+				do {
+					if (!i) {
+						res = move_window(*fatfs, sect++);
+						if (res != FR_OK) break;
+						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, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* 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) {
+		if (fp->flag & FA__ERROR) {			/* Check abort flag */
+			res = FR_INT_ERR;
+		} else {
+			if (!(fp->flag & FA_WRITE))		/* Check access mode */
+				res = FR_DENIED;
+		}
+	}
+	if (res == FR_OK) {
+		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->sclust);
+				fp->sclust = 0;
+			} else {				/* When truncate a part of the file, remove remaining clusters */
+				ncl = get_fat(fp->fs, fp->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->n_fatent) {
+					res = put_fat(fp->fs, fp->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 TCHAR *path		/* Pointer to the file or directory path */
+)
+{
+	FRESULT res;
+	FATFS_DIR dj, sdj;
+	BYTE *dir;
+	DWORD dclst;
+	DEF_NAMEBUF;
+
+
+	res = chk_mounted(&path, &dj.fs, 1);
+	if (res == FR_OK) {
+		INIT_BUF(dj);
+		res = follow_path(&dj, path);		/* Follow the file path */
+		if (_FS_RPATH && res == FR_OK && (dj.fn[NS] & NS_DOT))
+			res = FR_INVALID_NAME;			/* Cannot remove dot entry */
+#if _FS_SHARE
+		if (res == FR_OK) res = chk_lock(&dj, 2);	/* Cannot remove open file */
+#endif
+		if (res == FR_OK) {					/* The object is accessible */
+			dir = dj.dir;
+			if (!dir) {
+				res = FR_INVALID_NAME;		/* Cannot remove the start directory */
+			} else {
+				if (dir[DIR_Attr] & AM_RDO)
+					res = FR_DENIED;		/* Cannot remove R/O object */
+			}
+			dclst = LD_CLUST(dir);
+			if (res == FR_OK && (dir[DIR_Attr] & AM_DIR)) {	/* Is it a sub-dir? */
+				if (dclst < 2) {
+					res = FR_INT_ERR;
+				} else {
+					mem_cpy(&sdj, &dj, sizeof(FATFS_DIR));	/* Check if the sub-dir is empty or not */
+					sdj.sclust = dclst;
+					res = dir_sdi(&sdj, 2);		/* Exclude dot entries */
+					if (res == FR_OK) {
+						res = dir_read(&sdj);
+						if (res == FR_OK			/* Not empty dir */
+#if _FS_RPATH
+						|| dclst == sdj.fs->cdir	/* Current dir */
+#endif
+						) res = FR_DENIED;
+						if (res == FR_NO_FILE) res = FR_OK;	/* Empty */
+					}
+				}
+			}
+			if (res == FR_OK) {
+				res = dir_remove(&dj);		/* Remove the directory entry */
+				if (res == FR_OK) {
+					if (dclst)				/* Remove the cluster chain if exist */
+						res = remove_chain(dj.fs, dclst);
+					if (res == FR_OK) res = sync(dj.fs);
+				}
+			}
+		}
+		FREE_BUF();
+	}
+	LEAVE_FF(dj.fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Create a Directory                                                    */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_mkdir (
+	const TCHAR *path		/* Pointer to the directory path */
+)
+{
+	FRESULT res;
+	FATFS_DIR dj;
+	BYTE *dir, n;
+	DWORD dsc, dcl, pcl, tim = get_fattime();
+	DEF_NAMEBUF;
+
+
+	res = chk_mounted(&path, &dj.fs, 1);
+	if (res == FR_OK) {
+		INIT_BUF(dj);
+		res = follow_path(&dj, path);			/* Follow the file path */
+		if (res == FR_OK) res = FR_EXIST;		/* Any object with same name is already existing */
+		if (_FS_RPATH && res == FR_NO_FILE && (dj.fn[NS] & NS_DOT))
+			res = FR_INVALID_NAME;
+		if (res == FR_NO_FILE) {				/* Can create a new directory */
+			dcl = create_chain(dj.fs, 0);		/* Allocate a cluster for the new directory table */
+			res = FR_OK;
+			if (dcl == 0) res = FR_DENIED;		/* No space to allocate a new cluster */
+			if (dcl == 1) res = FR_INT_ERR;
+			if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR;
+			if (res == FR_OK)					/* Flush FAT */
+				res = move_window(dj.fs, 0);
+			if (res == FR_OK) {					/* Initialize the new directory table */
+				dsc = clust2sect(dj.fs, dcl);
+				dir = dj.fs->win;
+				mem_set(dir, 0, SS(dj.fs));
+				mem_set(dir+DIR_Name, ' ', 8+3);	/* Create "." entry */
+				dir[DIR_Name] = '.';
+				dir[DIR_Attr] = AM_DIR;
+				ST_DWORD(dir+DIR_WrtTime, tim);
+				ST_CLUST(dir, dcl);
+				mem_cpy(dir+SZ_DIR, dir, SZ_DIR); 	/* Create ".." entry */
+				dir[33] = '.'; pcl = dj.sclust;
+				if (dj.fs->fs_type == FS_FAT32 && pcl == dj.fs->dirbase)
+					pcl = 0;
+				ST_CLUST(dir+SZ_DIR, pcl);
+				for (n = dj.fs->csize; n; n--) {	/* Write dot entries and clear following sectors */
+					dj.fs->winsect = dsc++;
+					dj.fs->wflag = 1;
+					res = move_window(dj.fs, 0);
+					if (res != FR_OK) break;
+					mem_set(dir, 0, SS(dj.fs));
+				}
+			}
+			if (res == FR_OK) res = dir_register(&dj);	/* Register the object to the directoy */
+			if (res != FR_OK) {
+				remove_chain(dj.fs, dcl);			/* Could not register, remove cluster chain */
+			} else {
+				dir = dj.dir;
+				dir[DIR_Attr] = AM_DIR;				/* Attribute */
+				ST_DWORD(dir+DIR_WrtTime, tim);		/* Created time */
+				ST_CLUST(dir, dcl);					/* Table start cluster */
+				dj.fs->wflag = 1;
+				res = sync(dj.fs);
+			}
+		}
+		FREE_BUF();
+	}
+
+	LEAVE_FF(dj.fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Change Attribute                                                      */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_chmod (
+	const TCHAR *path,	/* Pointer to the file path */
+	BYTE value,			/* Attribute bits */
+	BYTE mask			/* Attribute mask to change */
+)
+{
+	FRESULT res;
+	FATFS_DIR dj;
+	BYTE *dir;
+	DEF_NAMEBUF;
+
+
+	res = chk_mounted(&path, &dj.fs, 1);
+	if (res == FR_OK) {
+		INIT_BUF(dj);
+		res = follow_path(&dj, path);		/* Follow the file path */
+		FREE_BUF();
+		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 TCHAR *path,	/* Pointer to the file/directory name */
+	const FILINFO *fno	/* Pointer to the time stamp to be set */
+)
+{
+	FRESULT res;
+	FATFS_DIR dj;
+	BYTE *dir;
+	DEF_NAMEBUF;
+
+
+	res = chk_mounted(&path, &dj.fs, 1);
+	if (res == FR_OK) {
+		INIT_BUF(dj);
+		res = follow_path(&dj, path);	/* Follow the file path */
+		FREE_BUF();
+		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 TCHAR *path_old,	/* Pointer to the old name */
+	const TCHAR *path_new	/* Pointer to the new name */
+)
+{
+	FRESULT res;
+	FATFS_DIR djo, djn;
+	BYTE buf[21], *dir;
+	DWORD dw;
+	DEF_NAMEBUF;
+
+
+	res = chk_mounted(&path_old, &djo.fs, 1);
+	if (res == FR_OK) {
+		djn.fs = djo.fs;
+		INIT_BUF(djo);
+		res = follow_path(&djo, path_old);		/* Check old object */
+		if (_FS_RPATH && res == FR_OK && (djo.fn[NS] & NS_DOT))
+			res = FR_INVALID_NAME;
+#if _FS_SHARE
+		if (res == FR_OK) res = chk_lock(&djo, 2);
+#endif
+		if (res == FR_OK) {						/* Old object is found */
+			if (!djo.dir) {						/* Is root dir? */
+				res = FR_NO_FILE;
+			} else {
+				mem_cpy(buf, djo.dir+DIR_Attr, 21);		/* Save the object information except for name */
+				mem_cpy(&djn, &djo, sizeof(FATFS_DIR));		/* Check new object */
+				res = follow_path(&djn, path_new);
+				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? */
+/* Start critical section that any interruption or error can cause cross-link */
+					res = dir_register(&djn);			/* Register the new entry */
+					if (res == FR_OK) {
+						dir = djn.dir;					/* Copy object information except for name */
+						mem_cpy(dir+13, buf+2, 19);
+						dir[DIR_Attr] = buf[0] | AM_ARC;
+						djo.fs->wflag = 1;
+						if (djo.sclust != djn.sclust && (dir[DIR_Attr] & AM_DIR)) {		/* Update .. entry in the directory if needed */
+							dw = clust2sect(djn.fs, LD_CLUST(dir));
+							if (!dw) {
+								res = FR_INT_ERR;
+							} else {
+								res = move_window(djn.fs, dw);
+								dir = djn.fs->win+SZ_DIR;	/* .. entry */
+								if (res == FR_OK && dir[1] == '.') {
+									dw = (djn.fs->fs_type == FS_FAT32 && djn.sclust == djn.fs->dirbase) ? 0 : djn.sclust;
+									ST_CLUST(dir, dw);
+									djn.fs->wflag = 1;
+								}
+							}
+						}
+						if (res == FR_OK) {
+							res = dir_remove(&djo);		/* Remove old entry */
+							if (res == FR_OK)
+								res = sync(djo.fs);
+						}
+					}
+/* End critical section */
+				}
+			}
+		}
+		FREE_BUF();
+	}
+	LEAVE_FF(djo.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 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;
+	BYTE csect;
+
+
+	*bf = 0;	/* Initialize byte counter */
+
+	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)(0, 0);					/* Repeat until all data transferred or stream becomes busy */
+		fp->fptr += rcnt, *bf += rcnt, btr -= rcnt) {
+		csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1));	/* Sector offset in the cluster */
+		if ((fp->fptr % SS(fp->fs)) == 0) {			/* On the sector boundary? */
+			if (!csect) {							/* On the cluster boundary? */
+				clst = (fp->fptr == 0) ?			/* On the top of the file? */
+					fp->sclust : get_fat(fp->fs, fp->clust);
+				if (clst <= 1) ABORT(fp->fs, FR_INT_ERR);
+				if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
+				fp->clust = clst;					/* Update current cluster */
+			}
+		}
+		sect = clust2sect(fp->fs, fp->clust);		/* Get current data sector */
+		if (!sect) ABORT(fp->fs, FR_INT_ERR);
+		sect += csect;
+		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		/* Number of root dir entries for FAT12/16 */
+#define N_FATS		1		/* Number of FAT copies (1 or 2) */
+
+
+FRESULT f_mkfs (
+	BYTE drv,		/* Logical drive number */
+	BYTE sfd,		/* Partitioning rule 0:FDISK, 1:SFD */
+	UINT au			/* Allocation unit size [bytes] */
+)
+{
+	static const WORD vst[] = { 1024,   512,  256,  128,   64,    32,   16,    8,    4,    2,   0};
+	static const WORD cst[] = {32768, 16384, 8192, 4096, 2048, 16384, 8192, 4096, 2048, 1024, 512};
+	BYTE fmt, md, sys, *tbl, pdrv, part;
+	DWORD n_clst, vs, n, wsect;
+	UINT i;
+	DWORD b_vol, b_fat, b_dir, b_data;	/* LBA */
+	DWORD n_vol, n_rsv, n_fat, n_dir;	/* Size */
+	FATFS *fs;
+	DSTATUS stat;
+
+
+	/* Check mounted drive and clear work area */
+	if (drv >= _VOLUMES) return FR_INVALID_DRIVE;
+	if (sfd > 1) return FR_INVALID_PARAMETER;
+	if (au & (au - 1)) return FR_INVALID_PARAMETER;
+	fs = FatFs[drv];
+	if (!fs) return FR_NOT_ENABLED;
+	fs->fs_type = 0;
+	pdrv = LD2PD(drv);	/* Physical drive */
+	part = LD2PT(drv);	/* Partition (0:auto detect, 1-4:get from partition table)*/
+
+	/* Get disk statics */
+	stat = disk_initialize(pdrv);
+	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(pdrv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK || SS(fs) > _MAX_SS)
+		return FR_DISK_ERR;
+#endif
+	if (_MULTI_PARTITION && part) {
+		/* Get partition information from partition table in the MBR */
+		if (disk_read(pdrv, fs->win, 0, 1) != RES_OK) return FR_DISK_ERR;
+		if (LD_WORD(fs->win+BS_55AA) != 0xAA55) return FR_MKFS_ABORTED;
+		tbl = &fs->win[MBR_Table + (part - 1) * SZ_PTE];
+		if (!tbl[4]) return FR_MKFS_ABORTED;	/* No partition? */
+		b_vol = LD_DWORD(tbl+8);	/* Volume start sector */
+		n_vol = LD_DWORD(tbl+12);	/* Volume size */
+	} else {
+		/* Create a partition in this function */
+		if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &n_vol) != RES_OK || n_vol < 128)
+			return FR_DISK_ERR;
+		b_vol = (sfd) ? 0 : 63;		/* Volume start sector */
+		n_vol -= b_vol;				/* Volume size */
+	}
+
+	if (!au) {				/* AU auto selection */
+		vs = n_vol / (2000 / (SS(fs) / 512));
+		for (i = 0; vs < vst[i]; i++) ;
+		au = cst[i];
+	}
+	au /= SS(fs);		/* Number of sectors per cluster */
+	if (au == 0) au = 1;
+	if (au > 128) au = 128;
+
+	/* Pre-compute number of clusters and FAT syb-type */
+	n_clst = n_vol / au;
+	fmt = FS_FAT12;
+	if (n_clst >= MIN_FAT16) fmt = FS_FAT16;
+	if (n_clst >= MIN_FAT32) fmt = FS_FAT32;
+
+	/* Determine offset and size of FAT structure */
+	if (fmt == FS_FAT32) {
+		n_fat = ((n_clst * 4) + 8 + SS(fs) - 1) / SS(fs);
+		n_rsv = 32;
+		n_dir = 0;
+	} else {
+		n_fat = (fmt == FS_FAT12) ? (n_clst * 3 + 1) / 2 + 3 : (n_clst * 2) + 4;
+		n_fat = (n_fat + SS(fs) - 1) / SS(fs);
+		n_rsv = 1;
+		n_dir = (DWORD)N_ROOTDIR * SZ_DIR / SS(fs);
+	}
+	b_fat = b_vol + n_rsv;				/* FAT area start sector */
+	b_dir = b_fat + n_fat * N_FATS;		/* Directory area start sector */
+	b_data = b_dir + n_dir;				/* Data area start sector */
+	if (n_vol < b_data + au - b_vol) return FR_MKFS_ABORTED;	/* Too small volume */
+
+	/* Align data start sector to erase block boundary (for flash memory media) */
+	if (disk_ioctl(pdrv, GET_BLOCK_SIZE, &n) != RES_OK || !n || n > 32768) n = 1;
+	n = (b_data + n - 1) & ~(n - 1);	/* Next nearest erase block from current data start */
+	n = (n - b_data) / N_FATS;
+	if (fmt == FS_FAT32) {		/* FAT32: Move FAT offset */
+		n_rsv += n;
+		b_fat += n;
+	} else {					/* FAT12/16: Expand FAT size */
+		n_fat += n;
+	}
+
+	/* Determine number of clusters and final check of validity of the FAT sub-type */
+	n_clst = (n_vol - n_rsv - n_fat * N_FATS - n_dir) / au;
+	if (   (fmt == FS_FAT16 && n_clst < MIN_FAT16)
+		|| (fmt == FS_FAT32 && n_clst < MIN_FAT32))
+		return FR_MKFS_ABORTED;
+
+	switch (fmt) {	/* Determine system ID for partition table */
+	case FS_FAT12:	sys = 0x01; break;
+	case FS_FAT16:	sys = (n_vol < 0x10000) ? 0x04 : 0x06; break;
+	default: 		sys = 0x0C;
+	}
+
+	if (_MULTI_PARTITION && part) {
+		/* Update system ID in the partition table */
+		tbl = &fs->win[MBR_Table + (part - 1) * SZ_PTE];
+		tbl[4] = sys;
+		if (disk_write(pdrv, fs->win, 0, 1) != RES_OK) return FR_DISK_ERR;
+		md = 0xF8;
+	} else {
+		if (sfd) {	/* No patition table (SFD) */
+			md = 0xF0;
+		} else {	/* Create partition table (FDISK) */
+			mem_set(fs->win, 0, SS(fs));
+			tbl = fs->win+MBR_Table;	/* Create partiton table for single partition in the drive */
+			tbl[1] = 1;						/* Partition start head */
+			tbl[2] = 1;						/* Partition start sector */
+			tbl[3] = 0;						/* Partition start cylinder */
+			tbl[4] = sys;					/* System type */
+			tbl[5] = 254;					/* Partition end head */
+			n = (b_vol + n_vol) / 63 / 255;
+			tbl[6] = (BYTE)((n >> 2) | 63);	/* Partiiton end sector */
+			tbl[7] = (BYTE)n;				/* End cylinder */
+			ST_DWORD(tbl+8, 63);			/* Partition start in LBA */
+			ST_DWORD(tbl+12, n_vol);		/* Partition size in LBA */
+			ST_WORD(fs->win+BS_55AA, 0xAA55);	/* MBR signature */
+			if (disk_write(pdrv, fs->win, 0, 1) != RES_OK)	/* Write it to the MBR sector */
+				return FR_DISK_ERR;
+			md = 0xF8;
+		}
+	}
+
+	/* Create BPB in the VBR */
+	tbl = fs->win;							/* Clear sector */
+	mem_set(tbl, 0, SS(fs));
+	mem_cpy(tbl, "\xEB\xFE\x90" "MSDOS5.0", 11);/* Boot jump code, OEM name */
+	i = SS(fs);								/* Sector size */
+	ST_WORD(tbl+BPB_BytsPerSec, i);
+	tbl[BPB_SecPerClus] = (BYTE)au;			/* Sectors per cluster */
+	ST_WORD(tbl+BPB_RsvdSecCnt, n_rsv);		/* Reserved sectors */
+	tbl[BPB_NumFATs] = N_FATS;				/* Number of FATs */
+	i = (fmt == FS_FAT32) ? 0 : N_ROOTDIR;	/* Number of rootdir entries */
+	ST_WORD(tbl+BPB_RootEntCnt, i);
+	if (n_vol < 0x10000) {					/* Number of total sectors */
+		ST_WORD(tbl+BPB_TotSec16, n_vol);
+	} else {
+		ST_DWORD(tbl+BPB_TotSec32, n_vol);
+	}
+	tbl[BPB_Media] = md;					/* Media descriptor */
+	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_vol);		/* Hidden sectors */
+	n = get_fattime();						/* Use current time as VSN */
+	if (fmt == FS_FAT32) {
+		ST_DWORD(tbl+BS_VolID32, n);		/* VSN */
+		ST_DWORD(tbl+BPB_FATSz32, n_fat);	/* Number of sectors per FAT */
+		ST_DWORD(tbl+BPB_RootClus, 2);		/* Root directory start cluster (2) */
+		ST_WORD(tbl+BPB_FSInfo, 1);			/* FSInfo record offset (VBR+1) */
+		ST_WORD(tbl+BPB_BkBootSec, 6);		/* Backup boot record offset (VBR+6) */
+		tbl[BS_DrvNum32] = 0x80;			/* Drive number */
+		tbl[BS_BootSig32] = 0x29;			/* Extended boot signature */
+		mem_cpy(tbl+BS_VolLab32, "NO NAME    " "FAT32   ", 19);	/* Volume label, FAT signature */
+	} else {
+		ST_DWORD(tbl+BS_VolID, n);			/* VSN */
+		ST_WORD(tbl+BPB_FATSz16, n_fat);	/* Number of sectors 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 label, FAT signature */
+	}
+	ST_WORD(tbl+BS_55AA, 0xAA55);			/* Signature (Offset is fixed here regardless of sector size) */
+	if (disk_write(pdrv, tbl, b_vol, 1) != RES_OK)	/* Write it to the VBR sector */
+		return FR_DISK_ERR;
+	if (fmt == FS_FAT32)							/* Write backup VBR if needed (VBR+6) */
+		disk_write(pdrv, tbl, b_vol + 6, 1);
+
+	/* Initialize FAT area */
+	wsect = b_fat;
+	for (i = 0; i < N_FATS; i++) {		/* Initialize each FAT copy */
+		mem_set(tbl, 0, SS(fs));			/* 1st sector of the FAT  */
+		n = md;								/* Media descriptor byte */
+		if (fmt != FS_FAT32) {
+			n |= (fmt == FS_FAT12) ? 0x00FFFF00 : 0xFFFFFF00;
+			ST_DWORD(tbl+0, n);				/* Reserve cluster #0-1 (FAT12/16) */
+		} else {
+			n |= 0xFFFFFF00;
+			ST_DWORD(tbl+0, n);				/* Reserve cluster #0-1 (FAT32) */
+			ST_DWORD(tbl+4, 0xFFFFFFFF);
+			ST_DWORD(tbl+8, 0x0FFFFFFF);	/* Reserve cluster #2 for root dir */
+		}
+		if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK)
+			return FR_DISK_ERR;
+		mem_set(tbl, 0, SS(fs));			/* Fill following FAT entries with zero */
+		for (n = 1; n < n_fat; n++) {		/* This loop may take a time on FAT32 volume due to many single sector writes */
+			if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK)
+				return FR_DISK_ERR;
+		}
+	}
+
+	/* Initialize root directory */
+	i = (fmt == FS_FAT32) ? au : n_dir;
+	do {
+		if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK)
+			return FR_DISK_ERR;
+	} while (--i);
+
+#if _USE_ERASE	/* Erase data area if needed */
+	{
+		DWORD eb[2];
+
+		eb[0] = wsect; eb[1] = wsect + (n_clst - ((fmt == FS_FAT32) ? 1 : 0)) * au - 1;
+		disk_ioctl(pdrv, CTRL_ERASE_SECTOR, eb);
+	}
+#endif
+
+	/* Create FSInfo if needed */
+	if (fmt == FS_FAT32) {
+		ST_DWORD(tbl+FSI_LeadSig, 0x41615252);
+		ST_DWORD(tbl+FSI_StrucSig, 0x61417272);
+		ST_DWORD(tbl+FSI_Free_Count, n_clst - 1);	/* Number of free clusters */
+		ST_DWORD(tbl+FSI_Nxt_Free, 2);				/* Last allocated cluster# */
+		ST_WORD(tbl+BS_55AA, 0xAA55);
+		disk_write(pdrv, tbl, b_vol + 1, 1);	/* Write original (VBR+1) */
+		disk_write(pdrv, tbl, b_vol + 7, 1);	/* Write backup (VBR+7) */
+	}
+
+	return (disk_ioctl(pdrv, CTRL_SYNC, 0) == RES_OK) ? FR_OK : FR_DISK_ERR;
+}
+
+
+#if _MULTI_PARTITION == 2
+/*-----------------------------------------------------------------------*/
+/* Divide Physical Drive                                                 */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_fdisk (
+	BYTE pdrv,			/* Physical drive number */
+	const DWORD szt[],	/* Pointer to the size table for each partitions */
+	void* work			/* Pointer to the working buffer */
+)
+{
+	UINT i, n, sz_cyl, tot_cyl, b_cyl, e_cyl, p_cyl;
+	BYTE s_hd, e_hd, *p, *buf = (BYTE*)work;
+	DSTATUS stat;
+	DWORD sz_disk, sz_part, s_part;
+
+
+	stat = disk_initialize(pdrv);
+	if (stat & STA_NOINIT) return FR_NOT_READY;
+	if (stat & STA_PROTECT) return FR_WRITE_PROTECTED;
+	if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_disk)) return FR_DISK_ERR;
+
+	/* Determine CHS in the table regardless of the drive geometry */
+	for (n = 16; n < 256 && sz_disk / n / 63 > 1024; n *= 2) ;
+	if (n == 256) n--;
+	e_hd = n - 1;
+	sz_cyl = 63 * n;
+	tot_cyl = sz_disk / sz_cyl;
+
+	/* Create partition table */
+	mem_set(buf, 0, _MAX_SS);
+	p = buf + MBR_Table; b_cyl = 0;
+	for (i = 0; i < 4; i++, p += SZ_PTE) {
+		p_cyl = (szt[i] <= 100) ? (DWORD)tot_cyl * szt[i] / 100 : szt[i] / sz_cyl;
+		if (!p_cyl) continue;
+		s_part = (DWORD)sz_cyl * b_cyl;
+		sz_part = (DWORD)sz_cyl * p_cyl;
+		if (i == 0) {	/* Exclude first track of cylinder 0 */
+			s_hd = 1;
+			s_part += 63; sz_part -= 63;
+		} else {
+			s_hd = 0;
+		}
+		e_cyl = b_cyl + p_cyl - 1;
+		if (e_cyl >= tot_cyl) return FR_INVALID_PARAMETER;
+
+		/* Set partition table */
+		p[1] = s_hd;						/* Start head */
+		p[2] = (BYTE)((b_cyl >> 2) + 1);	/* Start sector */
+		p[3] = (BYTE)b_cyl;					/* Start cylinder */
+		p[4] = 0x06;						/* System type (temporary setting) */
+		p[5] = e_hd;						/* End head */
+		p[6] = (BYTE)((e_cyl >> 2) + 63);	/* End sector */
+		p[7] = (BYTE)e_cyl;					/* End cylinder */
+		ST_DWORD(p + 8, s_part);			/* Start sector in LBA */
+		ST_DWORD(p + 12, sz_part);			/* Partition size */
+
+		/* Next partition */
+		b_cyl += p_cyl;
+	}
+	ST_WORD(p, 0xAA55);
+
+	/* Write it to the MBR */
+	return (disk_write(pdrv, buf, 0, 1) || disk_ioctl(pdrv, CTRL_SYNC, 0)) ? FR_DISK_ERR : FR_OK;
+}
+
+
+#endif /* _MULTI_PARTITION == 2 */
+#endif /* _USE_MKFS && !_FS_READONLY */
+
+
+
+
+#if _USE_STRFUNC
+/*-----------------------------------------------------------------------*/
+/* Get a string from the file                                            */
+/*-----------------------------------------------------------------------*/
+TCHAR* f_gets (
+	TCHAR* buff,	/* Pointer to the string buffer to read */
+	int len,		/* Size of string buffer (characters) */
+	FIL* fil		/* Pointer to the file object */
+)
+{
+	int n = 0;
+	TCHAR c, *p = buff;
+	BYTE s[2];
+	UINT rc;
+
+
+	while (n < len - 1) {			/* Read bytes until buffer gets filled */
+		f_read(fil, s, 1, &rc);
+		if (rc != 1) break;			/* Break on EOF or error */
+		c = s[0];
+#if _LFN_UNICODE					/* Read a character in UTF-8 encoding */
+		if (c >= 0x80) {
+			if (c < 0xC0) continue;	/* Skip stray trailer */
+			if (c < 0xE0) {			/* Two-byte sequense */
+				f_read(fil, s, 1, &rc);
+				if (rc != 1) break;
+				c = ((c & 0x1F) << 6) | (s[0] & 0x3F);
+				if (c < 0x80) c = '?';
+			} else {
+				if (c < 0xF0) {		/* Three-byte sequense */
+					f_read(fil, s, 2, &rc);
+					if (rc != 2) break;
+					c = (c << 12) | ((s[0] & 0x3F) << 6) | (s[1] & 0x3F);
+					if (c < 0x800) c = '?';
+				} else {			/* Reject four-byte sequense */
+					c = '?';
+				}
+			}
+		}
+#endif
+#if _USE_STRFUNC >= 2
+		if (c == '\r') continue;	/* Strip '\r' */
+#endif
+		*p++ = c;
+		n++;
+		if (c == '\n') break;		/* Break on EOL */
+	}
+	*p = 0;
+	return n ? buff : 0;			/* 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 (
+	TCHAR c,	/* A character to be output */
+	FIL* fil	/* Pointer to the file object */
+)
+{
+	UINT bw, btw;
+	BYTE s[3];
+
+
+#if _USE_STRFUNC >= 2
+	if (c == '\n') f_putc ('\r', fil);	/* LF -> CRLF conversion */
+#endif
+
+#if _LFN_UNICODE	/* Write the character in UTF-8 encoding */
+	if (c < 0x80) {			/* 7-bit */
+		s[0] = (BYTE)c;
+		btw = 1;
+	} else {
+		if (c < 0x800) {	/* 11-bit */
+			s[0] = (BYTE)(0xC0 | (c >> 6));
+			s[1] = (BYTE)(0x80 | (c & 0x3F));
+			btw = 2;
+		} else {			/* 16-bit */
+			s[0] = (BYTE)(0xE0 | (c >> 12));
+			s[1] = (BYTE)(0x80 | ((c >> 6) & 0x3F));
+			s[2] = (BYTE)(0x80 | (c & 0x3F));
+			btw = 3;
+		}
+	}
+#else				/* Write the character without conversion */
+	s[0] = (BYTE)c;
+	btw = 1;
+#endif
+	f_write(fil, s, btw, &bw);		/* Write the char to the file */
+	return (bw == btw) ? 1 : EOF;	/* Return the result */
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Put a string to the file                                              */
+/*-----------------------------------------------------------------------*/
+int f_puts (
+	const TCHAR* 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 TCHAR* str,	/* Pointer to the format string */
+	...					/* Optional arguments... */
+)
+{
+	va_list arp;
+	BYTE f, r;
+	UINT i, j, w;
+	ULONG v;
+	TCHAR c, d, s[16], *p;
+	int res, chc, 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 character */
+			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++;
+		} else {
+			if (c == '-') {			/* Flag: left justified */
+				f = 2; c = *str++;
+			}
+		}
+		while (IsDigit(c)) {		/* Precision */
+			w = w * 10 + c - '0';
+			c = *str++;
+		}
+		if (c == 'l' || c == 'L') {	/* Prefix: Size is long int */
+			f |= 4; c = *str++;
+		}
+		if (!c) break;
+		d = c;
+		if (IsLower(d)) d -= 0x20;
+		switch (d) {				/* Type is... */
+		case 'S' :					/* String */
+			p = va_arg(arp, TCHAR*);
+			for (j = 0; p[j]; j++) ;
+			chc = 0;
+			if (!(f & 2)) {
+				while (j++ < w) chc += (cc = f_putc(' ', fil));
+			}
+			chc += (cc = f_puts(p, fil));
+			while (j++ < w) chc += (cc = f_putc(' ', fil));
+			if (cc != EOF) cc = chc;
+			continue;
+		case 'C' :					/* Character */
+			cc = f_putc((TCHAR)va_arg(arp, int), fil); continue;
+		case 'B' :					/* Binary */
+			r = 2; break;
+		case 'O' :					/* Octal */
+			r = 8; break;
+		case 'D' :					/* Signed decimal */
+		case 'U' :					/* Unsigned decimal */
+			r = 10; break;
+		case 'X' :					/* Hexdecimal */
+			r = 16; break;
+		default:					/* Unknown type (passthrough) */
+			cc = f_putc(c, fil); continue;
+		}
+
+		/* Get an argument and put it in numeral */
+		v = (f & 4) ? (ULONG)va_arg(arp, long) : ((d == 'D') ? (ULONG)(long)va_arg(arp, int) : (ULONG)va_arg(arp, unsigned int));
+		if (d == 'D' && (v & 0x80000000)) {
+			v = 0 - v;
+			f |= 8;
+		}
+		i = 0;
+		do {
+			d = (TCHAR)(v % r); v /= r;
+			if (d > 9) d += (c == 'x') ? 0x27 : 0x07;
+			s[i++] = d + '0';
+		} while (v && i < sizeof(s) / sizeof(s[0]));
+		if (f & 8) s[i++] = '-';
+		j = i; d = (f & 1) ? '0' : ' ';
+		res = 0;
+		while (!(f & 2) && j++ < w) res += (cc = f_putc(d, fil));
+		do res += (cc = f_putc(s[--i], fil)); while(i);
+		while (j++ < w) res += (cc = f_putc(' ', fil));
+		if (cc != EOF) cc = res;
+	}
+
+	va_end(arp);
+	return (cc == EOF) ? cc : res;
+}
+
+#endif /* !_FS_READONLY */
+#endif /* _USE_STRFUNC */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FatFileSystem/ff.h	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,337 @@
+/*---------------------------------------------------------------------------/
+/  FatFs - FAT file system module include file  R0.09     (C)ChaN, 2011
+/----------------------------------------------------------------------------/
+/ 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) 2011, 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	6502	/* Revision ID */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "integer.h"	/* Basic integer types */
+#include "ffconf.h"		/* FatFs configuration options */
+
+#if _FATFS != _FFCONF
+#error Wrong configuration file (ffconf.h).
+#endif
+
+
+
+/* Definitions of volume management */
+
+#if _MULTI_PARTITION		/* Multiple partition configuration */
+typedef struct {
+	BYTE pd;	/* Physical drive number */
+	BYTE pt;	/* Partition: 0:Auto detect, 1-4:Forced partition) */
+} PARTITION;
+extern PARTITION VolToPart[];	/* Volume - Partition resolution table */
+#define LD2PD(vol) (VolToPart[vol].pd)	/* Get physical drive number */
+#define LD2PT(vol) (VolToPart[vol].pt)	/* Get partition index */
+
+#else						/* Single partition configuration */
+#define LD2PD(vol) (vol)	/* Each logical drive is bound to the same physical drive number */
+#define LD2PT(vol) 0		/* Always mounts the 1st partition or in SFD */
+
+#endif
+
+
+
+/* Type of path name strings on FatFs API */
+
+#if _LFN_UNICODE			/* Unicode string */
+#if !_USE_LFN
+#error _LFN_UNICODE must be 0 in non-LFN cfg.
+#endif
+#ifndef _INC_TCHAR
+typedef WCHAR TCHAR;
+#define _T(x) L ## x
+#define _TEXT(x) L ## x
+#endif
+
+#else						/* ANSI/OEM string */
+#ifndef _INC_TCHAR
+typedef char TCHAR;
+#define _T(x) x
+#define _TEXT(x) x
+#endif
+
+#endif
+
+
+
+/* File system object structure (FATFS) */
+
+typedef struct {
+	BYTE	fs_type;		/* FAT sub-type (0:Not mounted) */
+	BYTE	drv;			/* Physical drive number */
+	BYTE	csize;			/* Sectors per cluster (1,2,4...128) */
+	BYTE	n_fats;			/* Number of FAT copies (1,2) */
+	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 (FAT12/16) */
+#if _MAX_SS != 512
+	WORD	ssize;			/* Bytes per sector (512, 1024, 2048 or 4096) */
+#endif
+#if _FS_REENTRANT
+	_SYNC_t	sobj;			/* Identifier of sync object */
+#endif
+#if !_FS_READONLY
+	DWORD	last_clust;		/* Last allocated cluster */
+	DWORD	free_clust;		/* Number of free clusters */
+	DWORD	fsi_sector;		/* fsinfo sector (FAT32) */
+#endif
+#if _FS_RPATH
+	DWORD	cdir;			/* Current directory start cluster (0:root) */
+#endif
+	DWORD	n_fatent;		/* Number of FAT entries (= number of clusters + 2) */
+	DWORD	fsize;			/* Sectors per FAT */
+	DWORD	fatbase;		/* FAT start sector */
+	DWORD	dirbase;		/* Root directory start sector (FAT32:Cluster#) */
+	DWORD	database;		/* Data start sector */
+	DWORD	winsect;		/* Current sector appearing in the win[] */
+	BYTE	win[_MAX_SS];	/* Disk access window for Directory, FAT (and Data on tiny cfg) */
+} FATFS;
+
+
+
+/* File object structure (FIL) */
+
+typedef struct {
+	FATFS*	fs;				/* Pointer to the owner file system object */
+	WORD	id;				/* Owner file system mount ID */
+	BYTE	flag;			/* File status flags */
+	BYTE	pad1;
+	DWORD	fptr;			/* File read/write pointer (0 on file open) */
+	DWORD	fsize;			/* File size */
+	DWORD	sclust;			/* File start cluster (0 when fsize==0) */
+	DWORD	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 _USE_FASTSEEK
+	DWORD*	cltbl;			/* Pointer to the cluster link map table (null on file open) */
+#endif
+#if _FS_SHARE
+	UINT	lockid;			/* File lock ID (index of file semaphore table) */
+#endif
+#if !_FS_TINY
+	BYTE	buf[_MAX_SS];	/* File data read/write buffer */
+#endif
+} FIL;
+
+
+
+/* Directory object structure (FATFS_DIR) */
+
+typedef struct {
+	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:Root dir) */
+	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
+} FATFS_DIR;
+
+
+
+/* File status structure (FILINFO) */
+
+typedef struct {
+	DWORD	fsize;			/* File size */
+	WORD	fdate;			/* Last modified date */
+	WORD	ftime;			/* Last modified time */
+	BYTE	fattrib;		/* Attribute */
+	TCHAR	fname[13];		/* Short file name (8.3 format) */
+#if _USE_LFN
+	TCHAR*	lfname;			/* Pointer to the LFN buffer */
+	UINT 	lfsize;			/* Size of LFN buffer in TCHAR */
+#endif
+} FILINFO;
+
+
+
+/* File function return code (FRESULT) */
+
+typedef enum {
+	FR_OK = 0,				/* (0) Succeeded */
+	FR_DISK_ERR,			/* (1) A hard error occured in the low level disk I/O layer */
+	FR_INT_ERR,				/* (2) Assertion failed */
+	FR_NOT_READY,			/* (3) The physical drive cannot work */
+	FR_NO_FILE,				/* (4) Could not find the file */
+	FR_NO_PATH,				/* (5) Could not find the path */
+	FR_INVALID_NAME,		/* (6) The path name format is invalid */
+	FR_DENIED,				/* (7) Acces denied due to prohibited access or directory full */
+	FR_EXIST,				/* (8) Acces denied due to prohibited access */
+	FR_INVALID_OBJECT,		/* (9) The file/directory object is invalid */
+	FR_WRITE_PROTECTED,		/* (10) The physical drive is write protected */
+	FR_INVALID_DRIVE,		/* (11) The logical drive number is invalid */
+	FR_NOT_ENABLED,			/* (12) The volume has no work area */
+	FR_NO_FILESYSTEM,		/* (13) There is no valid FAT volume */
+	FR_MKFS_ABORTED,		/* (14) The f_mkfs() aborted due to any parameter error */
+	FR_TIMEOUT,				/* (15) Could not get a grant to access the volume within defined period */
+	FR_LOCKED,				/* (16) The operation is rejected according to the file shareing policy */
+	FR_NOT_ENOUGH_CORE,		/* (17) LFN working buffer could not be allocated */
+	FR_TOO_MANY_OPEN_FILES,	/* (18) Number of open files > _FS_SHARE */
+	FR_INVALID_PARAMETER	/* (19) Given parameter is invalid */
+} FRESULT;
+
+
+
+/*--------------------------------------------------------------*/
+/* FatFs module application interface                           */
+
+FRESULT f_mount (BYTE, FATFS*);						/* Mount/Unmount a logical drive */
+FRESULT f_open (FIL*, const TCHAR*, BYTE);			/* Open or create a file */
+FRESULT f_read (FIL*, void*, UINT, UINT*);			/* Read data from 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 (FATFS_DIR*, const TCHAR*);				/* Open an existing directory */
+FRESULT f_readdir (FATFS_DIR*, FILINFO*);					/* Read a directory item */
+FRESULT f_stat (const TCHAR*, FILINFO*);			/* Get file status */
+FRESULT f_write (FIL*, const void*, UINT, UINT*);	/* Write data to a file */
+FRESULT f_getfree (const TCHAR*, 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 TCHAR*);					/* Delete an existing file or directory */
+FRESULT	f_mkdir (const TCHAR*);						/* Create a new directory */
+FRESULT f_chmod (const TCHAR*, BYTE, BYTE);			/* Change attriburte of the file/dir */
+FRESULT f_utime (const TCHAR*, const FILINFO*);		/* Change timestamp of the file/dir */
+FRESULT f_rename (const TCHAR*, const TCHAR*);		/* Rename/Move a file or directory */
+FRESULT f_chdrive (BYTE);							/* Change current drive */
+FRESULT f_chdir (const TCHAR*);						/* Change current directory */
+FRESULT f_getcwd (TCHAR*, UINT);					/* Get current directory */
+FRESULT f_forward (FIL*, UINT(*)(const BYTE*,UINT), UINT, UINT*);	/* Forward data to the stream */
+FRESULT f_mkfs (BYTE, BYTE, UINT);					/* Create a file system on the drive */
+FRESULT	f_fdisk (BYTE, const DWORD[], void*);		/* Divide a physical drive into some partitions */
+int f_putc (TCHAR, FIL*);							/* Put a character to the file */
+int f_puts (const TCHAR*, FIL*);					/* Put a string to the file */
+int f_printf (FIL*, const TCHAR*, ...);				/* Put a formatted string to the file */
+TCHAR* f_gets (TCHAR*, 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)
+#define f_tell(fp) ((fp)->fptr)
+#define f_size(fp) ((fp)->fsize)
+
+#ifndef EOF
+#define EOF (-1)
+#endif
+
+
+
+
+/*--------------------------------------------------------------*/
+/* Additional user defined functions                            */
+
+/* RTC function */
+#if !_FS_READONLY
+DWORD get_fattime (void);
+#endif
+
+/* Unicode support functions */
+#if _USE_LFN						/* Unicode - OEM code conversion */
+WCHAR ff_convert (WCHAR, UINT);		/* OEM-Unicode bidirectional conversion */
+WCHAR ff_wtoupper (WCHAR);			/* Unicode upper-case conversion */
+#if _USE_LFN == 3					/* Memory functions */
+void* ff_memalloc (UINT);			/* Allocate memory block */
+void ff_memfree (void*);			/* Free memory block */
+#endif
+#endif
+
+/* Sync functions */
+#if _FS_REENTRANT
+int ff_cre_syncobj (BYTE, _SYNC_t*);/* Create a sync object */
+int ff_req_grant (_SYNC_t);			/* Lock sync object */
+void ff_rel_grant (_SYNC_t);		/* Unlock sync object */
+int ff_del_syncobj (_SYNC_t);		/* Delete a sync object */
+#endif
+
+
+
+
+/*--------------------------------------------------------------*/
+/* Flags and offset address                                     */
+
+
+/* File access control and file status flags (FIL.flag) */
+
+#define	FA_READ				0x01
+#define	FA_OPEN_EXISTING	0x00
+#define FA__ERROR			0x80
+
+#if !_FS_READONLY
+#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
+
+
+/* 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 */
+
+
+/* Fast seek feature */
+#define CREATE_LINKMAP	0xFFFFFFFF
+
+
+
+/*--------------------------------*/
+/* 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
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _FATFS */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FatFileSystem/ffconf.h	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,190 @@
+/*---------------------------------------------------------------------------/
+/  FatFs - FAT file system module configuration file  R0.09  (C)ChaN, 2011
+/----------------------------------------------------------------------------/
+/
+/ CAUTION! Do not forget to make clean the project after any changes to
+/ the configuration options.
+/
+/----------------------------------------------------------------------------*/
+#ifndef _FFCONF
+#define _FFCONF 6502	/* Revision ID */
+
+
+/*---------------------------------------------------------------------------/
+/ Functions and Buffer Configurations
+/----------------------------------------------------------------------------*/
+
+#define	_FS_TINY		0	/* 0:Normal or 1:Tiny */
+/* 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:Read/Write or 1:Read only */
+/* 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 to 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 1.
+/   3: f_lseek is removed in addition to 2. */
+
+
+#define	_USE_STRFUNC	0	/* 0:Disable or 1-2:Enable */
+/* To enable string functions, set _USE_STRFUNC to 1 or 2. */
+
+
+#define	_USE_MKFS		1	/* 0:Disable or 1:Enable */
+/* To enable f_mkfs function, set _USE_MKFS to 1 and set _FS_READONLY to 0 */
+
+
+#define	_USE_FORWARD	0	/* 0:Disable or 1:Enable */
+/* To enable f_forward function, set _USE_FORWARD to 1 and set _FS_TINY to 1. */
+
+
+#define	_USE_FASTSEEK	0	/* 0:Disable or 1:Enable */
+/* To enable fast seek feature, set _USE_FASTSEEK to 1. */
+
+
+
+/*---------------------------------------------------------------------------/
+/ Locale and Namespace Configurations
+/----------------------------------------------------------------------------*/
+
+#define _CODE_PAGE	858
+/* 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 to 3 */
+#define	_MAX_LFN	255		/* Maximum LFN length to handle (12 to 255) */
+/* The _USE_LFN option switches the LFN support.
+/
+/   0: Disable LFN feature. _MAX_LFN and _LFN_UNICODE have no effect.
+/   1: Enable LFN with static working buffer on the BSS. Always NOT reentrant.
+/   2: Enable LFN with dynamic working buffer on the STACK.
+/   3: Enable LFN with dynamic working buffer on the HEAP.
+/
+/  The LFN working buffer occupies (_MAX_LFN + 1) * 2 bytes. To enable LFN,
+/  Unicode handling functions ff_convert() and ff_wtoupper() must be added
+/  to the project. When enable to use heap, memory control functions
+/  ff_memalloc() and ff_memfree() must be added to the project. */
+
+
+#define	_LFN_UNICODE	0	/* 0:ANSI/OEM or 1:Unicode */
+/* 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 to 2 */
+/* The _FS_RPATH option configures relative path feature.
+/
+/   0: Disable relative path feature and remove related functions.
+/   1: Enable relative path. f_chdrive() and f_chdir() are available.
+/   2: f_getcwd() is available in addition to 1.
+/
+/  Note that output of the f_readdir fnction is affected by this option. */
+
+
+
+/*---------------------------------------------------------------------------/
+/ Physical Drive Configurations
+/----------------------------------------------------------------------------*/
+
+#define _VOLUMES	4
+/* Number of volumes (logical drives) to be used. */
+
+
+#define	_MAX_SS		512		/* 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 on-board flash memory, floppy disk and optical disk.
+/  When _MAX_SS is larger than 512, it configures FatFs to variable sector size
+/  and GET_SECTOR_SIZE command must be implememted to the disk_ioctl function. */
+
+
+#define	_MULTI_PARTITION	0	/* 0:Single partition, 1/2:Enable multiple partition */
+/* When set to 0, each volume is bound to the same physical drive number and
+/ it can mount only first primaly partition. When it is set to 1, each volume
+/ is tied to the partitions listed in VolToPart[]. */
+
+
+#define	_USE_ERASE	0	/* 0:Disable or 1:Enable */
+/* To enable sector erase feature, set _USE_ERASE to 1. CTRL_ERASE_SECTOR command
+/  should be added to the disk_ioctl functio. */
+
+
+
+/*---------------------------------------------------------------------------/
+/ System Configurations
+/----------------------------------------------------------------------------*/
+
+#define _WORD_ACCESS	0	/* 0 or 1 */
+/* Set 0 first and it is always compatible with all platforms. The _WORD_ACCESS
+/  option defines which access method is used to the word data on the FAT volume.
+/
+/   0: Byte-by-byte access.
+/   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.
+*/
+
+
+/* A header file that defines sync object types on the O/S, such as
+/  windows.h, ucos_ii.h and semphr.h, must be included prior to ff.h. */
+
+#define _FS_REENTRANT	0		/* 0:Disable or 1:Enable */
+#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 (thread safe) 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. */
+
+
+#define	_FS_SHARE	0	/* 0:Disable or >=1:Enable */
+/* To enable file shareing feature, set _FS_SHARE to 1 or greater. The value
+   defines how many files can be opened simultaneously. */
+
+
+#endif /* _FFCONFIG */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FatFileSystem/integer.h	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,37 @@
+/*-------------------------------------------*/
+/* Integer type definitions for FatFs module */
+/*-------------------------------------------*/
+
+#ifndef _INTEGER
+#define _INTEGER
+
+#ifdef _WIN32	/* FatFs development platform */
+
+#include <windows.h>
+#include <tchar.h>
+
+#else			/* Embedded platform */
+
+/* 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 */
+typedef 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;
+
+#endif
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FatFileSystem/option/ccsbcs.c	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,540 @@
+/*------------------------------------------------------------------------*/
+/* Unicode - Local code bidirectional converter  (C)ChaN, 2009            */
+/* (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, 0x042B, 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, 0x00DB, 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. Remove from the project.
+#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;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FechaHora.cpp	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,174 @@
+#include "FechaHora.h"
+
+void FechaHora::update(){
+    time(&rawtime);
+    timeinfo = localtime(&rawtime);
+}
+
+void FechaHora::updateRawTime(){   // Actualiza el número de segundos desde el 1 de enero de 1970
+    rawtime = mktime(timeinfo);
+    set_time(rawtime);
+}
+
+// Funciones que devuelven la fecha y hora como enteros
+int FechaHora::getNsecond(){
+    return timeinfo->tm_sec;
+}
+
+int FechaHora::getNminute(){
+    return timeinfo->tm_min;
+}
+
+int FechaHora::getNhour(){
+    return timeinfo->tm_hour;
+}
+
+int FechaHora::getNday(){
+    return timeinfo->tm_mday;
+}
+
+int FechaHora::getNmonth(){
+    return timeinfo->tm_mon + 1;
+}
+
+int FechaHora::getNyear(){     // años desde 1900
+    return timeinfo->tm_year;
+}
+
+// Funciones que configuran la fecha y hora
+void FechaHora::setNsecond(int n){
+    timeinfo->tm_sec = n;
+}
+
+void FechaHora::setNminute(int n){
+    timeinfo->tm_min = n;
+}
+
+void FechaHora::setNhour(int n){
+    timeinfo->tm_hour = n;
+}
+
+void FechaHora::setNday(int n){
+    timeinfo->tm_mday = n;
+}
+
+void FechaHora::setNmonth(int n){
+    timeinfo->tm_mon = (n - 1);
+}
+
+void FechaHora::setNyear(int n){      // años desde 1900
+    timeinfo->tm_year = n;
+}
+
+char *FechaHora::getFechaHora(){
+    char aux[5];
+    memset(fechaHoraFormat,'\0',strlen(fechaHoraFormat));
+    
+    getDay(aux);    
+    strncpy(fechaHoraFormat, aux, 2);
+    
+    strcat(fechaHoraFormat, "-");
+    
+    getMonth(aux);
+    strncat(fechaHoraFormat, aux, 2);
+    
+    strcat(fechaHoraFormat, "-");
+    
+    getYear(aux);
+    strncat(fechaHoraFormat, aux, 4);
+    
+    strcat(fechaHoraFormat, " ");
+    
+    getHour(aux);
+    strncat(fechaHoraFormat, aux, 2);
+    
+    strcat(fechaHoraFormat, ";");
+    
+    getMinute(aux);
+    strncat(fechaHoraFormat, aux, 2);
+    
+    strcat(fechaHoraFormat, ";");
+    
+    getSecond(aux);
+    strncat(fechaHoraFormat, aux, 2);
+    
+    return fechaHoraFormat;
+}
+
+char *FechaHora::getFecha(){
+    char aux[5];
+    memset(fechaHoraFormat,'\0',strlen(fechaHoraFormat));
+    
+    getDay(aux);    
+    strncpy(fechaHoraFormat, aux, 2);
+    
+    strcat(fechaHoraFormat, "-");
+    
+    getMonth(aux);
+    strncat(fechaHoraFormat, aux, 2);
+    
+    strcat(fechaHoraFormat, "-");
+    
+    getYear(aux);
+    strncat(fechaHoraFormat, aux, 4);
+    
+    return fechaHoraFormat;
+}
+
+char *FechaHora::getHora(){
+    char aux[5];
+    memset(fechaHoraFormat,'\0',strlen(fechaHoraFormat));
+    
+    getHour(aux);
+    strncpy(fechaHoraFormat, aux, 2);
+    
+    strcat(fechaHoraFormat, ";");
+    
+    getMinute(aux);
+    strncat(fechaHoraFormat, aux, 2);
+    
+    strcat(fechaHoraFormat, ";");
+    
+    getSecond(aux);
+    strncat(fechaHoraFormat, aux, 2);
+    
+    return fechaHoraFormat;
+}
+
+
+// Funciones que devuelven la hora
+void FechaHora::getSecond(char buff[]){
+    intTo2char(timeinfo->tm_sec, buff);    
+}
+void FechaHora::getMinute(char buff[]){
+    intTo2char(timeinfo->tm_min, buff); 
+}
+void FechaHora::getHour(char buff[]){
+    intTo2char(timeinfo->tm_hour, buff); 
+}
+
+// Funciones que devuelven la fecha
+void FechaHora::getDay(char buff[]){
+    intTo2char(timeinfo->tm_mday, buff); 
+}
+void FechaHora::getMonth(char buff[]){
+    intTo2char(timeinfo->tm_mon+1, buff); 
+}
+void FechaHora::getYear(char buff[]){
+    int year = 1900 + timeinfo->tm_year;
+    intTo4char(year, buff);
+}
+
+// La siguiente función devuelve los dos caracteres correspondientes a las dos cifras de un número entre 0 y 99 pasado como argumento (sin signo)
+void FechaHora::intTo2char(int value, char buff[]){
+    buff[0] = value/10 + '0';   // Decenas
+    buff[1] = value - ((int)(value/10))*10 + '0';   // unidades
+}
+
+// La siguiente función devuelve los dos caracteres correspondientes a las dos cifras de un número entre 0 y 99 pasado como argumento (sin signo)
+void FechaHora::intTo4char(int value, char buff[]){
+    buff[0] = value/1000 + '0';   // Millares
+    buff[1] = ((int)(value - ((int)(value/1000))*1000))/100 + '0';   // Centenas
+    buff[2] = (value - (buff[0] - '0')*1000 - (buff[1] - '0')*100)/10 + '0';
+    buff[3] = (value - (buff[0] - '0')*1000 - (buff[1] - '0')*100 - (buff[2] - '0')*10) + '0';    
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FechaHora.h	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,69 @@
+/**
+ * @author Juan Manuel Amador Olivares (virtualmech)
+ */
+#ifndef FECHAHORA_H
+#define FECHAHORA_H
+
+#include "mbed.h"
+#include <time.h>
+#include <string.h> 
+
+// Clase que controla la fecha y la hora del dispositivo
+class FechaHora{
+    public:
+    
+    // LLamar esta función para antes de llamar las funciones que devuelven la fecha y hora para actualizarlas internamente
+    void update();
+    
+    void updateRawTime();   // Actualiza el número de segundos desde el 1 de enero de 1970
+    
+    //Esta función devuelve la fecha y la hora con le siguiente formato: XX-XX-XX XX;XX;XX
+    char *getFechaHora();
+    
+    // Estas dos funciones devuelven la fecha o la hora individualmente
+    char *getFecha();
+    char *getHora();
+    
+    // Funciones que devuelven la hora como caracteres
+    void getSecond(char buff[]);
+    void getMinute(char buff[]);
+    void getHour(char buff[]);
+    
+    // Funciones que devuelven la fecha como caracteres
+    void getDay(char buff[]);
+    void getMonth(char buff[]);
+    void getYear(char buff[]);
+    
+    // Funciones que devuelven la fecha y hora como enteros
+    int getNsecond();
+    int getNminute();
+    int getNhour();
+    
+    int getNday();
+    int getNmonth();
+    int getNyear();      // años desde 1900
+    
+    // Funciones que configuran la fecha y hora
+    void setNsecond(int n);
+    void setNminute(int n);
+    void setNhour(int n);
+    
+    void setNday(int n);
+    void setNmonth(int n);
+    void setNyear(int n);      // años desde 1900
+    
+    private:
+    char fechaHoraFormat[32];
+    time_t rawtime;
+    struct tm * timeinfo;
+    
+    // La siguiente función devuelve los dos caracteres correspondientes a las dos cifras de un número entre 0 y 99 pasado como argumento (sin signo)
+    void intTo2char(int value, char buff[]);
+    
+    // La siguiente función devuelve los cuatro caracteres correspondientes a las dos cifras de un número entre 0 y 9999 pasado como argumento (sin signo)
+    void intTo4char(int value, char buff[]);
+    
+};
+
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FileManager/Configuracion.cpp	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,111 @@
+#include "Configuracion.h"
+
+extern ScreenManager SC;
+extern SelecManager SM;
+
+Configuracion::Configuracion(){
+    // Se lee el archivo de configuración, en caso de no existir se crea
+    FILE* file;    
+    if((file = fopen("/local/Config.vme","r")) == NULL){
+        setDefaults();
+        createFile();        
+    }else{  // El archivo ya existe
+        getParam(file, "adquisitionvelocity", velocidadAdquisicion);
+        getParam(file, "languaje", idioma);
+        getParam(file, "selectiontype", formaSeleccion);       
+    }
+    // Se cierra el fichero
+    if(file != NULL){
+        fclose(file);
+    }
+}
+
+void Configuracion::restoreSettings(){
+    setDefaults();
+    createFile();
+}
+
+void Configuracion::setDefaults(){
+    strcpy(velocidadAdquisicion, "1000");
+    strcpy(idioma, "spanish");
+    strcpy(formaSeleccion, "shading");
+    
+    // Además del fichero de configuración se cambia la configuración actual de la interfaz
+    char aux[16];
+    // Se selecciona el idioma
+    getIdioma(aux);
+    if(strcmp(aux, "spanish") == 0){        
+        SC.selectGroup(0);
+    }else if(strcmp(aux, "english") == 0){
+        SC.selectGroup(1);
+    }
+    // Se selecciona el modo de selección
+    getFormaSeleccion(aux);
+    if(strcmp(aux, "shading") == 0){        
+        SM.setInverterSelection();
+    }else if(strcmp(aux, "framing") == 0){
+        SM.setRectSelection();
+    }
+}
+
+// Esta función busca el valor del parámetro nameParam y lo guarda en buf
+// Para ello se recorrera cada una de las lineas del archivo de configuración hasta encontrarlo y leer su valor
+// Recordar: El archivo de configuración tiene le siguiente formato
+// nombreParámetro valorParámetro
+void Configuracion::getParam(FILE* file, char nameParam[], char buf[]){
+    // se calcula la longitud del nombre del parámetro
+    int lenParam = strlen(nameParam);
+    char aux[NCARACTERESLECTURA];
+    bool encontrado = false;
+    while(!encontrado && (!feof(file))){ // Solo se para de leer si se ha llegado al fin de fichero o se ha encontrado el valor del parámetro
+        // Se lee una linea
+        fgets(aux, NCARACTERESLECTURA, file);
+        if(strncmp(nameParam, aux, lenParam)== 0){
+            // Se ha encontrado la línea del parámetro que está guardada en aux
+            // se guarda el valor del parámetro (que empieza después de un espacio desde el nombre del parámetro y acaba antes del salto de línea)
+            // Antes se calcula cuantos caracteres tiene el valor del parámetro
+            // que será la longitud de la línea menos a longitud del nombre del parámetro - 2 (un caracter que es el espacio y el caracter final \n que tampoco debe copiarse
+            for(int i = 0; i < strlen(aux) - lenParam - 2; i++){
+                buf[i] = aux[i + lenParam + 1]; // +1 porque se empieza a guardar a partir del espacio entre el nombre y el valor
+            }            
+            encontrado = true;
+        }
+    }        
+}
+
+void Configuracion::createFile(){
+    FILE* file = fopen("/local/Config.vme","w");
+    fprintf(file, "adquisitionvelocity %s\n", velocidadAdquisicion);
+    fprintf(file, "languaje %s\n", idioma);
+    fprintf(file, "selectiontype %s\n", formaSeleccion);
+    fclose(file);
+}
+
+void Configuracion::setVelocidadAdquision(int nuevaVelocidadAdqusicion){
+    sprintf(velocidadAdquisicion,"%d",nuevaVelocidadAdqusicion);
+    createFile();
+}
+void Configuracion::setIdioma(char nuevoIdioma[]){
+    strcpy(idioma, nuevoIdioma);
+    createFile();
+}
+void Configuracion::setFormaSeleccion(char nuevaFormaSeleccion[]){
+    strcpy(formaSeleccion, nuevaFormaSeleccion);
+    createFile();
+}
+
+int Configuracion::getVelocidadAdquisicion(){
+    return atoi(velocidadAdquisicion);
+}
+
+void Configuracion::getVelocidadAdquisicionString(char buff[]){
+    strcpy(buff, velocidadAdquisicion);
+}
+
+void Configuracion::getIdioma(char buf[]){
+    strcpy(buf, idioma);
+}
+
+void Configuracion::getFormaSeleccion(char buf[]){
+    strcpy(buf, formaSeleccion);
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FileManager/Configuracion.h	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,48 @@
+/**
+ * @author Juan Manuel Amador Olivares (virtualmech)
+ */
+#ifndef CONFIGURACION_H
+#define CONFIGURACION_H
+
+#define NCARACTERES 16
+#define NCARACTERESLECTURA 64
+
+#include "mbed.h"
+#include "ScreenManager.h"
+#include "SelecManager.h"
+#include <string.h>
+#include <stdlib.h>
+
+// CLase encargada de guardar y cargar la configuración
+class Configuracion{
+    public:
+    Configuracion();    // EL construtor carga los valores de configuracion o crea una configuracion inicial en caso de no existir
+    
+    void getVelocidadAdquisicionString(char buff[]);
+    int getVelocidadAdquisicion();
+    void getIdioma(char buf[]);
+    void getFormaSeleccion(char buf[]);
+    
+    void setVelocidadAdquision(int nuevaVelocidadAdqusicion);
+    void setIdioma(char nuevoIdioma[]);
+    void setFormaSeleccion(char nuevaFormaSeleccion[]);
+    
+    
+    void restoreSettings(); // Vuelve a los valóres de fábrica
+    
+    private:
+    // Parámetros
+    char velocidadAdquisicion[NCARACTERES];
+    char idioma[NCARACTERES];
+    char formaSeleccion[NCARACTERES];
+    
+    void getParam(FILE* file, char nameParam[], char buf[]);
+    void createFile();      // Crea o sobreescribe un archivo con los parámetros de configuración
+    
+    void setDefaults(); // Carga los valores predeterminados
+    
+    
+};
+
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FileManager/ParametrosCalibracion.cpp	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,56 @@
+#include "ParametrosCalibracion.h"
+
+extern ScreenManager SC;
+extern SelecManager SM;
+
+
+void ParametrosCalibracion::leerValores(float* valores){    // Esta función guarda en un array de 6 float los valores de calibración
+    // Se lee el archivo de valores de calibracion
+    FILE* file;    
+    if((file = fopen("/local/Calibrat.vme","rb")) == NULL){  // Si no existe 
+        // Se crea un fichero con valores por defecto
+        createDefaults();
+        // Se devuelven los valores por defecto
+        valores[0] = AX;      
+        valores[1] = AY;
+        valores[2] = AZ;
+        valores[3] = KX;
+        valores[4] = KY;
+        valores[5] = KZ;
+    }else{  // El archivo ya existe
+        // Se leen los 6 valores y se guardan en la dirección pasada como argumento
+        fread(valores, 4, 6, file);
+    }
+    // Se cierra el fichero
+    if(file != NULL){
+        fclose(file);
+    }
+}
+
+void ParametrosCalibracion::createDefaults(){    // Esta función guarda en un array de 6 float los valores de calibración
+    // Se cre un archivo con los valores por defecto de calibración
+    FILE* file;    
+    file = fopen("/local/Calibrat.vme","wb");
+    
+    // datos a aguradar en el fichero
+    float datos[] = {AX, AY, AZ, KX, KY, KZ};
+    
+    // Tamaño de los datos: 32 bits (4 bytes), número de datos : 6    
+    fwrite(datos, 4, 6, file);
+    
+    // Se cierra el fichero    
+    fclose(file);
+}
+    
+// Guarda 6 nuevos valores de calibración 
+void ParametrosCalibracion::saveValores(float valores[]){    // Esta función guarda en un array de 6 float los valores de calibración
+    // Se cre un archivo con los valores por defecto de calibración
+    FILE* file;    
+    file = fopen("/local/Calibrat.vme","wb");
+    
+    // Tamaño de los datos: 32 bits (4 bytes), número de datos: 6    
+    fwrite(valores, 4, 6, file);
+    
+    // Se cierra el fichero    
+    fclose(file);
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FileManager/ParametrosCalibracion.h	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,37 @@
+/**
+ * @author Juan Manuel Amador Olivares (virtualmech)
+ */
+#ifndef PARAMETROSCALIBRACION_H
+#define PARAMETROSCALIBRACION_H
+
+#define NCARACTERES 16
+#define NCARACTERESLECTURA 64
+
+#include "mbed.h"
+#include "ScreenManager.h"
+#include "SelecManager.h"
+#include <string.h>
+#include <stdlib.h>
+
+// Valores de calibración por defecto
+// OFFSET
+#define AX 2086.500488
+#define AY 2070.410645
+#define AZ 2057.436523
+// Sensibilidad
+#define KX 0.011837
+#define KY 0.011808
+#define KZ 0.011850
+
+// Clase encargada de guardar y cargar los parámetros de calibración del sensor
+// En total son 6 parámetros:
+// 3 de offset y 3 de conversión a unidades física
+class ParametrosCalibracion{
+    public:        
+    static void leerValores(float* valores);    // Esta función guarda en un array de 6 float los valores de calibración    
+    static void createDefaults();      // Crea un fichero de valores de calibración. Dichos valores serán los valores por defecto
+    static void saveValores(float valores[]);          // Guarda 6 nuevos valores de calibración
+};
+
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FileManager/SistemaArchivos.cpp	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,186 @@
+#include "SistemaArchivos.h"
+
+extern ScreenManager SC;
+extern MSCFileSystem msc;
+
+extern DigitalOut myled;
+
+SistemaArchivos::SistemaArchivos(){
+    nViajes = 0;
+}
+
+void SistemaArchivos::addElement(char newElement[]){
+    FILE* file = fopen("/local/RideList.vme","a");
+    fprintf(file, "%s\n", newElement);
+    fclose(file);
+}
+
+int SistemaArchivos::reloadRideNames(){
+    // Se reinicia el número de viajes
+    nViajes = 0;
+    // Se abre el archivo de nombres de viajes
+    FILE* file = fopen("/local/RideList.vme","r");
+    if(file == NULL){
+        return 1;
+    }else{
+        while(!feof(file)){ // Mientras no se haya llegado al fin de fichero
+            //strcpy(names[nViajes], readTextLine(file));
+            fgets(names[nViajes], NCARACTERES, file);
+            // Se borra el último caracter de la cadena, el caracter '\n'
+            deleteLastChar(names[nViajes]);
+            //fscanf(file, "%s", names[nViajes]);
+            nViajes++;
+        }
+        // La última cadena es '\n', esta no se contara como cadena
+        nViajes--;
+        fclose(file);
+        return 0;
+    }
+}
+
+int SistemaArchivos::deleteRide(char *fileName){   // Borra los archivos asociados a un viaje, y lo borra de la lista de viajes
+    char file[64]; 
+
+    // Primero se intenta borrar el archivo de la memoria flash
+    strcpy(file, "/usb/");
+    strcat(file, fileName);
+    strcat(file, ".txt"); 
+    
+    if(remove(file) != 0){  // Si no se pudo borrar se devuelve un 1
+        return 1;
+    }else{      // Si se borró el archivo se borra también de la lista de viajes
+        // Para ello primero se borra el viaje del array "names"
+        // Procedimiento:
+        // - Se busca el nombre en la lista
+        // - Una vez encontrada su posición todos los elementos por debajo de este se suben una posición
+        int pos = 0;      
+        
+        // - Se busca el nombre en la lista
+        while(strcmp(names[pos], fileName)){
+            pos++;
+        }
+        
+        // En este momento la variable "pos" guarda la posición de memoria de el elemento a borrar
+        // Se aumenta en uno este índice para subir de posición los elementos por debajo de este
+        pos++;
+        
+        // - Una vez encontrada su posición todos los elementos por debajo de este se suben una posición
+        for (int i = pos; i < nViajes; i++){ 
+            strcpy(names[i-1], names[i]);
+        }
+        
+        // El número de viajes es una unidad menor
+        nViajes--;
+        
+        // Se guarda la nueva lista de viajes
+        saveRideList();
+        
+        return 0;
+    }
+}
+
+int SistemaArchivos::renameRide(char *fileName, char *newName){   // Cambia el nombre de los archivos asociados a un viaje, y de la lista de viajes
+    char oldFile[64]; 
+    char newFile[64];
+
+    // Primero se intenta cambiar el nombre del archivo de la memoria flash
+    strcpy(oldFile, "/usb/");
+    strcat(oldFile, fileName);
+    strcat(oldFile, ".txt"); 
+    
+    strcpy(newFile, "/usb/");
+    strcat(newFile, newName);
+    strcat(newFile, ".txt"); 
+    
+    if(file_rename(oldFile, newFile) != 0){  // Si no se pudo borrar se devuelve un 1
+        return 1;
+    }else{      // Si se cambió el nombre del archivo también se cambia el nombre en la lista de viajes
+        // Procedimiento:
+        // - Se busca el nombre antiguo en la lista
+        // - Una vez encontrada su posición se cambia su nombre
+        int pos = 0;      
+        
+        // - Se busca el nombre antiguo en la lista
+        while(strcmp(names[pos], fileName)){
+            pos++;
+        }
+        
+        // - Una vez encontrada su posición se cambia su nombre
+        strcpy(names[pos], newName);
+        
+        // Se guarda la nueva lista de viajes
+        saveRideList();
+        
+        return 0;
+    }
+}
+
+bool SistemaArchivos::alredyExist(char *name){
+    bool value = false;
+    for(int i = 0; i < nViajes; i++){
+        if(!strcmp(names[i], name)){
+            value = true;
+        }
+    }
+    return value;
+}
+
+void SistemaArchivos::saveRideList(){
+    // Se sobreescribe el archivo "RideList.vme" con la lista de el array nombres
+    FILE* file = fopen("/local/RideList.vme","w");
+    for(int i = 0; i < nViajes; i++){
+        fprintf(file, "%s\n", names[i]);
+    }   
+    fclose(file);
+}    
+
+char* SistemaArchivos::getNameRide(int nameNumber){
+    return names[nameNumber];    
+}
+
+int SistemaArchivos::getNrides(){
+    return nViajes;
+}
+
+//***********************************************************
+// file_rename: renames a file.
+//    Kind of hoakey as it moves data instead of adjusting
+//    the file name in the directory. 
+//    Checks to insure the file was renamed.
+//    Returns -1 = error; 0 = success
+//***********************************************************
+int SistemaArchivos::file_rename(const char *oldfile, const char *newfile) {
+    int retval = 0;
+    int ch;
+ 
+    FILE *fpold = fopen(oldfile, "r");
+    if(fpold == NULL) {
+        retval = (-1);
+    }else{ 
+        FILE *fpnew = fopen(newfile, "w");
+        
+        while (1) {  
+            ch = fgetc(fpold); 
+            if (ch == EOF) break;
+            fputc(ch, fpnew);  
+        }
+        
+        fclose(fpnew);
+        fclose(fpold);
+     
+        fpnew = fopen(newfile, "r");
+        if(fpnew == NULL) {
+            retval = (-1);
+        } 
+        else {
+            remove(oldfile);
+        }
+        fclose(fpnew);
+    }
+    return (retval);
+}
+
+void SistemaArchivos::deleteLastChar(char *str){     // Borra el último caracter de una cadena
+    str[strlen(str)-1] = '\0';
+}
+    
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FileManager/SistemaArchivos.h	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,60 @@
+/**
+ * @author Juan Manuel Amador Olivares (virtualmech)
+ */
+#ifndef SISTEMAARCHIVOS_H
+#define SISTEMAARCHIVOS_H
+
+#define NMAXVIAJES 100
+#define NCARACTERES 28
+#define NCARACTERESLECTURA 64
+
+#include "mbed.h"
+#include "ScreenManager.h"
+#include "MSCFileSystem.h"
+#include "SelecManager.h"
+#include <string.h>
+#include <stdlib.h>
+
+// Esta clase va a gestionar los archivos que guardan los datos recogidos del acelerómetro
+// La filosofía de funcionamiento es la siguiente:
+// En la memoria flash externa se guardarán los archivos con los datos
+// Como se va a necesitar cargar estos archivos en otro momento o incluso cambiarles el nombre, se guardará en la memoria flash de la mbed una lista con los nombres de los archivosde datos y así independientemente de su nombre 
+// puedan encontrarse y cargarse.
+// En definitiva esta clase controlará esta lista de nombres de archivos
+class SistemaArchivos{
+    public:
+    SistemaArchivos();    // EL construtor carga los valores de configuracion o crea una configuracion inicial en caso de no existir
+    
+    void addElement(char newElement[]);  // Esta función añade un nuevo nombre de archivo a la lista
+    
+    int reloadRideNames();             // Esta función carga en memoria los nombres de los viajes guardados en el archivo RideList.txt y guarda el número de viajes
+                                        // Devuelve 0 si se recargo correctamente o 1 si no se pudo acceder al archivo de la lista de viajes.
+    char *getNameRide(int nameNumber);               // Esta función devuelve un puntero a la lista de nombres de los viajes
+    int getNrides();
+    
+    bool alredyExist(char *name);       // Comprueba si nombre pasado como argumento está o no en la lista de nombres de los viajes
+    
+    int file_rename(const char *oldfile, const char *newfile);  // Cambia el nombre de un archivo de la memoria flash
+    
+    // Funciones para modificar la lista de viajes: "RideList.txt", antes de usar estas funciones
+    // llamar a la función "reloadRideNames() para actualizar la lista de viajes en memoria
+    // También modifican los archivos en la memoria flash
+    // Estas funciones devuelven 0 en caso de haber podido ejecutarse correctamente o 1 en caso de error    
+    int deleteRide(char *fileName);   // Borra los archivos asociados a un viaje, y lo borra de la lista de viajes    
+    int renameRide(char *fileName, char *newName);   // Cambia el nombre de los archivos asociados a un viaje, y de la lista de viajes    
+    
+    
+    private:
+    
+    char names[NMAXVIAJES][NCARACTERES];
+    
+    void saveRideList();     // Guarda en el archivo "RideList.txt" la lista de nombres guardados en el array names sobreescribiendo los anteriores
+                            // Devuelve 1 si no se ha podido acceder al archivo
+    
+    int nViajes;
+    
+    void deleteLastChar(char *str);     // Borra el último caracter de una cadena
+};
+
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/KXR94/KXR94.cpp	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,88 @@
+/**
+ * @author Juan Manuel Amador Olivares (virtualmech)
+ */
+
+#include "KXR94.h"
+
+KXR94::KXR94(PinName mosi, PinName miso, PinName sck, PinName cs) : spi_(mosi, miso, sck), nCS_(cs) 
+{
+    // Se configura el puerto SPI
+    spi_.frequency(4000000);        // El máximo según el datasheet es 5MHz
+    spi_.format(8,0);
+        
+    // Se prepara el acelerómetro para comenzar las lecturas
+    AcelerometroWakeUp();   
+}
+
+void KXR94::ReadAccels_KXR94(int* Acc) {
+    char x_lsb, x_msb;
+    char y_lsb, y_msb;
+    char z_lsb, z_msb;
+    signed short ax, ay, az;   
+
+    //------------X----------------    
+    nCS_ = 0;
+    spi_.write(CONVERTX);
+    wait_us(40);
+    x_msb = spi_.write(0x00);   // Dummy byte
+    x_lsb = spi_.write(0x00);   // Dummy byte
+    nCS_ = 1;
+    wait_us(1);   
+    ax = (x_msb << 8) |  x_lsb ;   // combineer msb en lsb
+    ax = ax >> 4;                  // Get rid of four non-value bits in LSB
+    ax &=~0xF000;
+    //------------Y----------------
+    nCS_ = 0;
+    spi_.write(CONVERTY);
+    wait_us(40);
+    y_msb = spi_.write(0x00);   // Dummy byte
+    y_lsb = spi_.write(0x00);   // Dummy byte
+    nCS_ = 1;
+    wait_us(1);  
+    ay = (y_msb << 8) | y_lsb;     // combineer msb en lsb
+    ay = ay >> 4;                  // Get rid of four non-value bits in LSB
+    ay &=~0xF000;
+    //------------Z----------------
+    nCS_ = 0;
+    spi_.write(CONVERTZ);
+    wait_us(40);
+    z_msb = spi_.write(0x00);   // Dummy byte
+    z_lsb = spi_.write(0x00);   // Dummy byte
+    nCS_ = 1;
+    wait_us(1);  
+    az = (z_msb << 8) |  z_lsb;    //  combineer msb en lsb
+    az = az >> 4;                  // Get rid of four non-value bits in LSB    
+    az &=~0xF000;
+
+    Acc[0] = ax;
+    Acc[1] = ay;
+    Acc[2] = az;
+}
+
+//-----------------READ OUT the X-Y-Z values---------------
+char KXR94::read_reg() {
+    char byte;
+    nCS_ = 0;
+    spi_.write(READREG);
+    byte = spi_.write(0x00);   // Dummy byte
+    nCS_ = 1;
+    wait_us(1);
+    return byte;
+}
+
+void KXR94::AcelerometroSleep(void)
+{
+    nCS_ = 0;
+    spi_.write(WRITEREG);
+    spi_.write(0x00);   // Enable = 0
+    nCS_ = 1;
+    wait_us(1);
+}  
+void KXR94::AcelerometroWakeUp(void)
+{
+    nCS_ = 0;
+    spi_.write(WRITEREG);
+    spi_.write(0x04);   // Enable = 1
+    nCS_ = 1;
+    wait_us(1);
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/KXR94/KXR94.h	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,60 @@
+/**
+ * @author Juan Manuel Amador Olivares (virtualmech)
+ */
+
+#ifndef KXR94_H
+#define KXR94_H
+ 
+#include "mbed.h"
+
+#define CONVERTX       0x00
+#define CONVERTY       0x01
+#define CONVERTZ       0x02
+#define READREG        0x03
+#define WRITEREG       0x04
+#define CONVERTAUX     0x05
+
+
+/*-------------Hardware connections-------------
+VIO----- mbed Vout (3.3 Volt)
+SDI----- mbed mosi (p5)
+SDO----- mbed miso (p6)
+SCK----- mbed sck  (p7)
+CS------ mbed (p8)          // chip select
+GND----- mbed GND (0 Volt)
+VDO----- mbed Vout (3.3 Volt)
+there are no additional external components used
+//----------------------------------------------*/
+
+/**
+ * KXR94 triple axis, digital interface, accelerometer.
+ */
+class KXR94 {
+
+public:
+    /**
+     * Constructor.
+     *
+     * @param mosi mbed pin to use for MOSI line of SPI interface.
+     * @param miso mbed pin to use for MISO line of SPI interface.
+     * @param sck mbed pin to use for SCK line of SPI interface.
+     * @param cs mbed pin to use for not chip select line of SPI interface.
+     */
+    KXR94(PinName mosi, PinName miso, PinName sck, PinName cs);
+    
+    void write_reg(char data);
+    char read_reg();
+
+    void ReadAccels_KXR94(int*);
+    
+    void AcelerometroSleep(void);                    //Pone el acelerometro en sleep mode para no consumir energía
+    void AcelerometroWakeUp(void);                   //Pone el acelerometro preparado para medir
+    
+    private:
+
+    SPI        spi_;
+    DigitalOut nCS_;
+
+};
+
+#endif /* KXR94_H */
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MSCFileSystem.cpp	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,113 @@
+/* USB Mass Storage device file system
+ * Copyrigh (c) 2010, Igor Skochinsky
+ * based on SDFileStorage
+ * Copyright (c) 2008-2009, sford
+ */
+ 
+/* Introduction
+ * ------------
+ * TODO: write one
+ * we're basically using NXP's USBHotLite sample code, just plugging in our own FAT library
+ */
+ 
+#include "MSCFileSystem.h"
+#include "usbhost_inc.h"
+
+MSCFileSystem::MSCFileSystem(const char* name) :
+  FATFileSystem(name)
+{
+}
+
+void print_inquiry(USB_INT08U *inqReply)
+{
+    // see USB Mass Storage Class – UFI Command Specification,
+    // 4.2 INQUIRY Command
+    printf("Inquiry reply:\n");
+    uint8_t tmp = inqReply[0]&0x1F;
+    printf("Peripheral device type: %02Xh\n", tmp);
+    if ( tmp == 0 )
+        printf("\t- Direct access (floppy)\n");
+    else if ( tmp == 0x1F )
+        printf("\t- none (no FDD connected)\n");
+    else
+        printf("\t- unknown type\n");
+    tmp = inqReply[1] >> 7;
+    printf("Removable Media Bit: %d\n", tmp);
+    tmp = inqReply[2] & 3;
+    printf("ANSI Version: %02Xh\n", tmp);
+    if ( tmp != 0 )
+        printf("\t- warning! must be 0\n");
+    tmp = (inqReply[2]>>3) & 3;
+    printf("ECMA Version: %02Xh\n", tmp);
+    if ( tmp != 0 )
+        printf("\t- warning! should be 0\n");
+    tmp = inqReply[2]>>6;
+    printf("ISO Version: %02Xh\n", tmp);
+    if ( tmp != 0 )
+        printf("\t- warning! should be 0\n");
+    tmp = inqReply[3] & 0xF;
+    printf("Response Data Format: %02Xh\n", tmp);
+    if ( tmp != 1 )
+        printf("\t- warning! should be 1\n");
+    tmp = inqReply[4];
+    printf("Additional length: %02Xh\n", tmp);
+    if ( tmp != 0x1F )
+        printf("\t- warning! should be 1Fh\n");
+    printf("Vendor Information: '%.8s'\n", &inqReply[8]);
+    printf("Product Identification: '%.16s'\n", &inqReply[16]);
+    printf("Product Revision: '%.4s'\n", &inqReply[32]);        
+}
+
+int MSCFileSystem::initialise_msc()
+{
+    USB_INT32S  rc;
+    USB_INT08U  inquiryResult[INQUIRY_LENGTH];
+    
+    //print_clock();
+    Host_Init();               /* Initialize the  host controller                                    */
+    rc = Host_EnumDev();       /* Enumerate the device connected                                            */
+    if (rc != OK)
+    {
+        fprintf(stderr, "Could not enumerate device: %d\n", rc);
+        return rc;
+    }
+        
+    
+    /* Initialize the mass storage and scsi interfaces */
+    rc = MS_Init( &_blkSize, &_numBlks, inquiryResult );
+    if (rc != OK)
+    {
+        fprintf(stderr, "Could not initialize mass storage interface: %d\n", rc);
+        return rc;
+    }
+    printf("Successfully initialized mass storage interface; %d blocks of size %d\n", _numBlks, _blkSize);
+    print_inquiry(inquiryResult);
+    // FATFileSystem supports only 512-byte blocks
+    return _blkSize == 512 ? OK : 1;
+}
+
+int MSCFileSystem::disk_initialize()
+{
+    if ( initialise_msc() != OK )
+        return 1;
+        
+    return 0;
+}
+
+int MSCFileSystem::disk_write(const char *buffer, int block_number)
+{
+    if ( OK == MS_BulkSend(block_number, 1, (USB_INT08U *)buffer) )
+        return 0;
+    return 1;
+}
+
+int MSCFileSystem::disk_read(char *buffer, int block_number)
+{
+    if ( OK == MS_BulkRecv(block_number, 1, (USB_INT08U *)buffer) )
+        return 0;
+    return 1;
+}
+
+int MSCFileSystem::disk_status() { return 0; }
+int MSCFileSystem::disk_sync() { return 0; }
+int MSCFileSystem::disk_sectors() { return _numBlks; }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MSCFileSystem.h	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,49 @@
+/* USB Mass Storage device file system
+ * Copyrigh (c) 2010, Igor Skochinsky
+ * based on SDFileStorage
+ * Copyright (c) 2008-2009, sford
+ */
+ 
+#ifndef MSCFILESYSTEM_H
+#define MSCFILESYSTEM_H
+
+#include "mbed.h"
+#include "FATFileSystem.h"
+
+/* Class: MSCFileSystem
+ *  Access the filesystem on an attached USB mass storage device (e.g. a memory stick)
+ *
+ * Example:
+ * > MSCFileSystem msc("msc");
+ * > 
+ * > int main() {
+ * >     FILE *fp = fopen("/msc/myfile.txt", "w");
+ * >     fprintf(fp, "Hello World!\n");
+ * >     fclose(fp);
+ * > }
+ */
+class MSCFileSystem : public FATFileSystem {
+public:
+
+    /* Constructor: MSCFileSystem
+     *  Create the File System for accessing a USB mass storage device
+     *
+     * Parameters:
+     *  name - The name used to access the filesystem
+     */
+    MSCFileSystem(const char* name);
+    virtual int disk_initialize();
+    virtual int disk_write(const char *buffer, int block_number);
+    virtual int disk_read(char *buffer, int block_number);    
+    virtual int disk_status();
+    virtual int disk_sync();
+    virtual int disk_sectors();
+
+protected:
+
+    int initialise_msc();
+    uint32_t _numBlks;
+    uint32_t _blkSize;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pantallas/ArchivoGuardado.cpp	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,55 @@
+/**
+ * @author Juan Manuel Amador Olivares (virtualmech)
+ */
+#include "ArchivoGuardado.h"
+
+extern ScreenManager SC;
+extern FechaHora FH;
+
+ArchivoGuardado::ArchivoGuardado(char nextScreen[], char newAdvice[], char newnameTitle[], char newdateTitle[], char newtimeTitle[]){
+    strcpy(nextScreenID, nextScreen);
+    strcpy(advice, newAdvice);
+    
+    strcpy(nameTitle, newnameTitle);
+    strcpy(dateTitle, newdateTitle);
+    strcpy(timeTitle, newtimeTitle);
+}
+
+void ArchivoGuardado::button5pressed(DogMLCD* lcd){
+    SC.changeScreen(nextScreenID);
+}
+
+void ArchivoGuardado::initialize(DogMLCD* lcd){    
+    // select font to use:
+    lcd->XFont = xfont_8;
+    
+    // Se escribe el nombre
+    lcd->XString(OFFSETXTITLES, OFFSETY, nameTitle);
+    
+    // NOTA: No se debe llamar a FHupdate() porque sino se actualizaría la hora y lo que queremos mostrar es la hora del último archivo guardado que fue la última vez que se actualizo la hora
+    char fileName[64];
+    char auxTime[64];    
+    strcpy(auxTime, FH.getFechaHora());
+    strcpy(fileName, "RAW");
+    strcat(fileName, auxTime);
+    lcd->XString(OFFSETX - 2, OFFSETY + 8, fileName);   // Cambiar
+    
+    // Se escribe la fecha
+    lcd->XString(OFFSETXTITLES, OFFSETY + 8*2, dateTitle);
+    lcd->XString(OFFSETX, OFFSETY + 8*3, FH.getFecha()); // Cambiar
+    
+    // Se escribe el tiempo
+    lcd->XString(OFFSETXTITLES, OFFSETY + 8*4, timeTitle);
+    
+    char aux[16];
+    strcpy(aux, FH.getHora());
+    aux[2] = ':';
+    aux[5] = ':';
+    lcd->XString(OFFSETX, OFFSETY + 8*5, aux); // Cambiar
+    
+    // Se escribe el consejo en la parte inferior de la pantalla
+    lcd->XString(OFFSETX, HEIGHT - 8, advice);
+    
+    // transmit work screen to physical screen:
+    lcd->Flush();
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pantallas/ArchivoGuardado.h	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,38 @@
+/**
+ * @author Juan Manuel Amador Olivares (virtualmech)
+ */
+#ifndef ARCHIVOGUARDADO_H
+#define ARCHIVOGUARDADO_H
+
+#include "Seleccion.h"
+#include "FechaHora.h"
+#include "doggy.h"
+
+#define MAXCARACTER 22      // Número máximo de caracteres de cada elemento
+#define OFFSETX 4            // Espacio en pixeles que se deja antes de escribir una linea de caracteres
+#define OFFSETXTITLES 16            // Espacio en pixeles que se deja antes de escribir una linea de caracteres
+#define OFFSETY 4            // Espacio en pixeles que se deja antes de escribir una linea de caracteres
+
+// Lista de elementos seleccionables. Tamaño de caracteres 8. 
+class ArchivoGuardado: public Seleccion{
+    public:
+    ArchivoGuardado(char nextScreen[], char newAdvice[], char newnameTitle[], char newdateTitle[], char newtimeTitle[]);
+    virtual void initialize(DogMLCD* lcd);
+    
+    virtual void button5pressed(DogMLCD* lcd);     // Esta función se llama cuando el botón central es pulsado, definirla para añadir funcionalidades  
+    
+    void setName(char newName[]);
+    void setDate(char newDate[]);
+    void setTime(char newTime[]);
+    
+    private:    
+    char nextScreenID[NCARSCREEN];
+    char advice[MAXCARACTER + 10];
+    char nameTitle[MAXCARACTER];
+    char dateTitle[MAXCARACTER];
+    char timeTitle[MAXCARACTER];
+    
+
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pantallas/AutoCalibracion.cpp	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,506 @@
+#include "AutoCalibracion.h"
+/// ACELEROMETRO DIGITAL///
+extern KXR94 kionix;
+
+extern ScreenManager SC;
+extern SistemaArchivos SA;
+extern Configuracion config;
+extern MSCFileSystem msc;
+
+extern DigitalIn boton5;
+extern DigitalIn boton6;
+
+void AutoCalibracion::initialize(DogMLCD* lcd){  
+    pasoCalibracion = 0;        // Pantalla de introduccion
+    
+    mediaXpos = 0;
+    mediaYpos = 0;
+    mediaZpos = 0;
+    mediaXneg = 0;
+    mediaYneg = 0;
+    mediaZneg = 0;    
+    
+    // Inicilización de las variables
+    pulsado5 = false;
+    pulsado6 = false;
+    leyendoDatos = false;
+    
+    char idioma[16];
+    // Se selecciona el idioma
+    config.getIdioma(idioma);
+    
+    // select font to use:
+    lcd->XFont = xfont_11;
+
+    // output title text
+    if(strcmp(idioma, "spanish") == 0){        
+        lcd->XString( OFFSETX, OFFSETY, "Autocalibraci\242n");
+    }else if(strcmp(idioma, "english") == 0){
+        lcd->XString( OFFSETX, OFFSETY, "Autocalibration");
+    }
+    
+    lcd->XFont = xfont_8;
+    
+    if(strcmp(idioma, "spanish") == 0){        
+        lcd->XString( OFFSETX, OFFSETY + OFFSETMSG, "Siga los pasos siguientes");        
+        lcd->XString( OFFSETX, OFFSETY + OFFSETMSG + 8, "para calibrar el");
+        lcd->XString( OFFSETX, OFFSETY + OFFSETMSG + 8*2, "dispositivo.");
+    }else if(strcmp(idioma, "english") == 0){
+        lcd->XString( OFFSETX, OFFSETY + OFFSETMSG, "Follow next steps to");
+        lcd->XString( OFFSETX, OFFSETY + OFFSETMSG + 8, "calibrate the device.");
+    }        
+
+    // transmit work screen to physical screen:
+    lcd->Flush();       
+    
+    // Se prepara el acelerómetro
+    kionix.AcelerometroWakeUp();
+    // select font to use:
+    lcd->XFont = xfont_11;
+    
+    // output msg2 text
+    if(strcmp(idioma, "spanish") == 0){        
+        lcd->XString( OFFSETX, HEIGHT -1 - 18, "OK para continuar.");
+    }else if(strcmp(idioma, "english") == 0){
+        lcd->XString( OFFSETX, HEIGHT -1 - 18, "OK to continue.");
+    }
+    
+    // transmit work screen to physical screen:
+    lcd->Flush();    
+}
+
+void AutoCalibracion::update(DogMLCD* lcd){
+    // Si se están leyendo datos se comprueba si se ha tomado el número de medidas deseadas
+    if(leyendoDatos){       
+        if(datosCapturados >= NDATOSPASO){          // Se ha acabado la lectura de los datos      
+            // Se para la lectura de datos              
+            tickerLectura.detach();
+            
+            leyendoDatos = false;
+            
+            // Se guarda el valor de la media en su variable correspondiente
+            // Dependiendo del paso nos interesa sumar un eje en concreto
+            switch(pasoCalibracion){
+                case 1:
+                    mediaXpos = mediaAux/NDATOSPASO;
+                    //mediaZpos = mediaAux;
+                break;
+                    
+                case 2:
+                    mediaXneg = mediaAux/NDATOSPASO;
+                    //mediaXneg = mediaAux;
+                break;
+                
+                case 3:
+                    mediaYneg = mediaAux/NDATOSPASO;
+                    //mediaXpos = mediaAux;
+                break;
+                    
+                case 4:
+                    mediaYpos = mediaAux/NDATOSPASO;
+                    //mediaYpos = mediaAux;
+                break;
+                    
+                case 5:
+                    mediaZpos = mediaAux/NDATOSPASO;
+                    //mediaYneg = mediaAux;
+                break;
+                    
+                case 6:
+                    mediaZneg = mediaAux/NDATOSPASO;
+                    //mediaZneg = mediaAux;
+                    
+                    // Una vez terminado el paso 6 ya se tienen los datos suficientes para calcular los parámetros de calibración
+                    // Primero se calculan los factores de conversión a unidades físicas
+                    float newKX;
+                    float newKY;
+                    float newKZ;
+                    if(mediaXpos >= mediaXneg){
+                        newKX = (2.0*ACELGRAVEDAD)/(mediaXpos - mediaXneg);
+                    }else{
+                        newKX = (2.0*ACELGRAVEDAD)/(mediaXneg - mediaXpos);
+                    }
+                    
+                    if(mediaYpos >= mediaYneg){
+                        newKY = (2.0*ACELGRAVEDAD)/(mediaYpos - mediaYneg);
+                    }else{
+                        newKY = (2.0*ACELGRAVEDAD)/(mediaYneg - mediaYpos);
+                    }
+                    
+                    if(mediaZpos >= mediaZneg){
+                        newKZ = (2.0*ACELGRAVEDAD)/(mediaZpos - mediaZneg);
+                    }else{
+                        newKZ = (2.0*ACELGRAVEDAD)/(mediaZneg - mediaZpos);
+                    }
+                    
+                    // Se calcula el offset de cada eje                    
+                    float newAX;
+                    float newAY;
+                    float newAZ;
+                    
+                    //if(mediaXpos >= mediaXneg){
+                        //newAX = mediaXpos - (ACELGRAVEDAD/KX);
+                    /*}else{
+                        newAX = mediaXneg - (ACELGRAVEDAD/KX);
+                    }*/
+                    
+                    //if(mediaYpos >= mediaYneg){
+                        //newAY = mediaYpos - (ACELGRAVEDAD/KY);
+                    /*}else{
+                        newAY = mediaYneg - (ACELGRAVEDAD/KY);
+                    }*/
+                    
+                    //if(mediaZpos >= mediaZneg){
+                        //newAZ = mediaZpos - (ACELGRAVEDAD/KZ);
+                    /*}else{
+                        newAZ = mediaZneg - (ACELGRAVEDAD/KZ);
+                    }*/
+                    
+                    newAX = (mediaXpos + mediaXneg)/2.0;
+                    newAY = (mediaYpos + mediaYneg)/2.0;
+                    newAZ = (mediaZpos + mediaZneg)/2.0;
+                    
+                    float param[] = {newAX, newAY, newAZ, newKX, newKY, newKZ};
+                    
+                    /*FILE* fp = fopen("/local/prueba1.txt","w");
+                    fprintf(fp, "%f\n%f\n\n%f\n%f\n\n%f\n%f\n\n%f\n%f\n%f\n\n%f\n%f\n%f\n", mediaYpos, mediaYneg, mediaXpos, mediaXneg, mediaZneg, mediaZpos, newAX, newAY, newAZ, newKX, newKY, newKZ);
+                    fclose(fp);*/
+                    
+                    // Se guardan los nuevos valores de calibración
+                    ParametrosCalibracion::saveValores(param);
+                    
+                break;
+            }
+            
+            pasoCalibracion++;
+            
+            // Se pinta la siguiente pantalla
+            lcd->Flush();
+            
+        }
+    }
+    
+    // Botón OK
+    if(boton5 == 1){
+        pulsado5 = true;
+    }else{
+        if(pulsado5 == true){   // El boton ha sido pulsado
+            pulsado5 = false;            
+            if(!leyendoDatos){      // Si el viaje no habia comenzado
+                leyendoDatos = true;
+                
+                // Se borra la pantalla
+                lcd->Clear();   
+                
+                char idioma[16];
+                // Se selecciona el idioma
+                config.getIdioma(idioma);  
+                
+                // select font to use:
+                lcd->XFont = xfont_11; 
+                
+                // Algunos mensajes son comunes para todos los pasos
+                // output msg2 text
+                if(strcmp(idioma, "spanish") == 0){        
+                    lcd->XString( OFFSETX, HEIGHT -1 - 18, "OK para continuar.");
+                }else if(strcmp(idioma, "english") == 0){
+                    lcd->XString( OFFSETX, HEIGHT -1 - 18, "OK to continue.");
+                }           
+                
+                // Dependiendo del paso nos interesa sumar un eje en concreto
+                switch(pasoCalibracion){
+                    case 0:
+                        // Se pasa directamente al Paso 1
+                        leyendoDatos = false;
+                                                
+                        // select font to use:
+                        lcd->XFont = xfont_11;
+                        
+                        // output title text
+                        if(strcmp(idioma, "spanish") == 0){        
+                            lcd->XString( OFFSETX, OFFSETY, "Paso 1");
+                        }else if(strcmp(idioma, "english") == 0){
+                            lcd->XString( OFFSETX, OFFSETY, "Step 1");
+                        }
+                        
+                        lcd->XFont = xfont_8;
+                        
+                        if(strcmp(idioma, "spanish") == 0){        
+                            lcd->XString( OFFSETX, OFFSETY + OFFSETMSG, "Coloque la cara derecha del");
+                            lcd->XString( OFFSETX, OFFSETY + OFFSETMSG + 8, "dispositivo sobre una");
+                            lcd->XString( OFFSETX, OFFSETY + OFFSETMSG + 8*2, "superficie plana.");
+                        }else if(strcmp(idioma, "english") == 0){
+                            lcd->XString( OFFSETX, OFFSETY + OFFSETMSG, "Place the right side of the");
+                            lcd->XString( OFFSETX, OFFSETY + OFFSETMSG + 8, "device on a flat surface.");
+                        }           
+                        
+                        // Se prepara el acelerómetro
+                        kionix.AcelerometroWakeUp();                       
+                        
+                        // Se pinta la siguiente pantalla
+                        lcd->Flush();
+                        pasoCalibracion++;
+                    break;
+                        
+                    case 1:
+                        // Lectura de datos del paso 1, se prepara la pantalla del paso 2
+                                                
+                        // select font to use:
+                        lcd->XFont = xfont_11;
+                        
+                        // output title text
+                        if(strcmp(idioma, "spanish") == 0){        
+                            lcd->XString( OFFSETX, OFFSETY, "Paso 2");
+                        }else if(strcmp(idioma, "english") == 0){
+                            lcd->XString( OFFSETX, OFFSETY, "Step 2");
+                        }
+                        
+                        lcd->XFont = xfont_8;
+                        
+                        if(strcmp(idioma, "spanish") == 0){        
+                            lcd->XString( OFFSETX, OFFSETY + OFFSETMSG, "Coloque la cara izquierda del");
+                            lcd->XString( OFFSETX, OFFSETY + OFFSETMSG + 8, "dispositivo sobre una");
+                            lcd->XString( OFFSETX, OFFSETY + OFFSETMSG + 8*2, "superficie plana.");
+                        }else if(strcmp(idioma, "english") == 0){
+                            lcd->XString( OFFSETX, OFFSETY + OFFSETMSG, "Place the left side of the");
+                            lcd->XString( OFFSETX, OFFSETY + OFFSETMSG + 8, "device on a flat surface.");
+                        }
+                        
+                        mediaAux = 0;
+                        datosCapturados = 0;
+                        
+                        // Se espera unos segundos antes de comenzar a tomar medidas  para asegurar las vibraciones debidas
+                        // a la pulsación del botón no interfieren en las medidas
+                        wait(OFFSETTIEMPO);
+                        // Se comienza a leer el acelerómetro
+                        tickerLectura.attach_us(this, &AutoCalibracion::LeeAcelerometro, USENTREDATOS);           
+                                          
+                    break;
+                        
+                    case 2:
+                    
+                        // Lectura de datos del paso 1, se prepara la pantalla del paso 3
+                                                
+                        // select font to use:
+                        lcd->XFont = xfont_11;
+                        
+                        // output title text
+                        if(strcmp(idioma, "spanish") == 0){        
+                            lcd->XString( OFFSETX, OFFSETY, "Paso 3");
+                        }else if(strcmp(idioma, "english") == 0){
+                            lcd->XString( OFFSETX, OFFSETY, "Step 3");
+                        }
+                        
+                        lcd->XFont = xfont_8;
+                        
+                        if(strcmp(idioma, "spanish") == 0){        
+                            lcd->XString( OFFSETX, OFFSETY + OFFSETMSG, "Coloque la cara superior del");
+                            lcd->XString( OFFSETX, OFFSETY + OFFSETMSG + 8, "dispositivo sobre una");
+                            lcd->XString( OFFSETX, OFFSETY + OFFSETMSG + 8*2, "superficie plana.");
+                        }else if(strcmp(idioma, "english") == 0){
+                            lcd->XString( OFFSETX, OFFSETY + OFFSETMSG, "Place the top side of the");
+                            lcd->XString( OFFSETX, OFFSETY + OFFSETMSG + 8, "device on a flat surface.");
+                        }
+                        
+                        mediaAux = 0;
+                        datosCapturados = 0;
+                        
+                        // Se espera unos segundos antes de comenzar a tomar medidas  para asegurar las vibraciones debidas
+                        // a la pulsación del botón no interfieren en las medidas
+                        wait(OFFSETTIEMPO);
+                        // Se comienza a leer el acelerómetro
+                        tickerLectura.attach_us(this, &AutoCalibracion::LeeAcelerometro, USENTREDATOS);    
+
+                    break;
+                        
+                    case 3:                    
+                    
+                        // Lectura de datos del paso 1, se prepara la pantalla del paso 4
+                                                
+                        // select font to use:
+                        lcd->XFont = xfont_11;
+                        
+                        // output title text
+                        if(strcmp(idioma, "spanish") == 0){        
+                            lcd->XString( OFFSETX, OFFSETY, "Paso 4");
+                        }else if(strcmp(idioma, "english") == 0){
+                            lcd->XString( OFFSETX, OFFSETY, "Step 4");
+                        }
+                        
+                        lcd->XFont = xfont_8;
+                        
+                        if(strcmp(idioma, "spanish") == 0){        
+                            lcd->XString( OFFSETX, OFFSETY + OFFSETMSG, "Coloque la cara inferior del");
+                            lcd->XString( OFFSETX, OFFSETY + OFFSETMSG + 8, "dispositivo sobre una");
+                            lcd->XString( OFFSETX, OFFSETY + OFFSETMSG + 8*2, "superficie plana.");
+                        }else if(strcmp(idioma, "english") == 0){
+                            lcd->XString( OFFSETX, OFFSETY + OFFSETMSG, "Place the bottom side of the");
+                            lcd->XString( OFFSETX, OFFSETY + OFFSETMSG + 8, "device on a flat surface.");
+                        }
+                        
+                        mediaAux = 0;
+                        datosCapturados = 0;
+                        
+                        // Se espera unos segundos antes de comenzar a tomar medidas  para asegurar las vibraciones debidas
+                        // a la pulsación del botón no interfieren en las medidas
+                        wait(OFFSETTIEMPO);
+                        // Se comienza a leer el acelerómetro
+                        tickerLectura.attach_us(this, &AutoCalibracion::LeeAcelerometro, USENTREDATOS);    
+    
+                    break;
+                        
+                    case 4:
+                    
+                        // Lectura de datos del paso 1, se prepara la pantalla del paso 5
+                                                
+                        // select font to use:
+                        lcd->XFont = xfont_11;
+                        
+                        // output title text
+                        if(strcmp(idioma, "spanish") == 0){        
+                            lcd->XString( OFFSETX, OFFSETY, "Paso 5");
+                        }else if(strcmp(idioma, "english") == 0){
+                            lcd->XString( OFFSETX, OFFSETY, "Step 5");
+                        }
+                        
+                        lcd->XFont = xfont_8;
+                        
+                        if(strcmp(idioma, "spanish") == 0){        
+                            lcd->XString( OFFSETX, OFFSETY + OFFSETMSG, "Coloque la cara frontal del");
+                            lcd->XString( OFFSETX, OFFSETY + OFFSETMSG + 8, "dispositivo sobre una");
+                            lcd->XString( OFFSETX, OFFSETY + OFFSETMSG + 8*2, "superficie plana.");
+                        }else if(strcmp(idioma, "english") == 0){
+                            lcd->XString( OFFSETX, OFFSETY + OFFSETMSG, "Place the front side of the");
+                            lcd->XString( OFFSETX, OFFSETY + OFFSETMSG + 8, "device on a flat surface.");
+                        }
+                        
+                        mediaAux = 0;
+                        datosCapturados = 0;
+                        
+                        // Se espera unos segundos antes de comenzar a tomar medidas  para asegurar las vibraciones debidas
+                        // a la pulsación del botón no interfieren en las medidas
+                        wait(OFFSETTIEMPO);
+                        // Se comienza a leer el acelerómetro
+                        tickerLectura.attach_us(this, &AutoCalibracion::LeeAcelerometro, USENTREDATOS);    
+
+                    break;
+                        
+                    case 5:
+                    
+                        // Lectura de datos del paso 1, se prepara la pantalla del paso 6
+                                                
+                        // select font to use:
+                        lcd->XFont = xfont_11;
+                        
+                        // output title text
+                        if(strcmp(idioma, "spanish") == 0){        
+                            lcd->XString( OFFSETX, OFFSETY, "Paso 6");
+                        }else if(strcmp(idioma, "english") == 0){
+                            lcd->XString( OFFSETX, OFFSETY, "Step 6");
+                        }
+                        
+                        lcd->XFont = xfont_8;
+                        
+                        if(strcmp(idioma, "spanish") == 0){        
+                            lcd->XString( OFFSETX, OFFSETY + OFFSETMSG, "Coloque la cara trasera del");
+                            lcd->XString( OFFSETX, OFFSETY + OFFSETMSG + 8, "dispositivo sobre una");
+                            lcd->XString( OFFSETX, OFFSETY + OFFSETMSG + 8*2, "superficie plana.");
+                        }else if(strcmp(idioma, "english") == 0){
+                            lcd->XString( OFFSETX, OFFSETY + OFFSETMSG, "Place the rear side of the");
+                            lcd->XString( OFFSETX, OFFSETY + OFFSETMSG + 8, "device on a flat surface.");
+                        }
+                        
+                        mediaAux = 0;
+                        datosCapturados = 0;
+                        
+                        // Se espera unos segundos antes de comenzar a tomar medidas  para asegurar las vibraciones debidas
+                        // a la pulsación del botón no interfieren en las medidas
+                        wait(OFFSETTIEMPO*2);
+                        // Se comienza a leer el acelerómetro
+                        tickerLectura.attach_us(this, &AutoCalibracion::LeeAcelerometro, USENTREDATOS);    
+
+                    break;
+                        
+                    case 6:
+                        
+                        // select font to use:
+                        lcd->XFont = xfont_11;
+                        
+                        // output title text
+                        if(strcmp(idioma, "spanish") == 0){        
+                            lcd->XString( OFFSETX + 28, OFFSETY + 8, "Calibraci\242n");
+                            lcd->XString( OFFSETX + 28, OFFSETY + 8 + 12, "completada.");
+                        }else if(strcmp(idioma, "english") == 0){
+                            lcd->XString( OFFSETX + 28, OFFSETY + 8, "Calibration");
+                            lcd->XString( OFFSETX + 28, OFFSETY + 8 + 12, "completed.");
+                        }
+                        
+                        mediaAux = 0;
+                        datosCapturados = 0;
+                        
+                        // Se espera unos segundos antes de comenzar a tomar medidas  para asegurar las vibraciones debidas
+                        // a la pulsación del botón no interfieren en las medidas
+                        wait(OFFSETTIEMPO);
+                        // Se comienza a leer el acelerómetro
+                        tickerLectura.attach_us(this, &AutoCalibracion::LeeAcelerometro, USENTREDATOS);                   
+
+                    break;
+                    
+                    case 7:
+                        // Se duerme el acelerómetro                
+                        kionix.AcelerometroSleep();                           
+                        // Se vuelve a la pantalla de configuración
+                        SC.changeScreen("configuracion");
+                    break;
+                }
+            }
+        }
+    }
+
+    // Botón atrás
+    if(boton6 == 1){
+        pulsado6 = true;
+    }else{
+        if(pulsado6 == true){
+            pulsado6 = false;
+            // En cualquier momento puede volverse atrás (al menú de configuración) parando el proceso actual y perdiendo todos los datos que se hayan guardado de la calibración hasta el mommento, teniendo que repetir el proceso     
+            // Se duerme el acelerómetro                
+            kionix.AcelerometroSleep();  
+            SC.changeScreen("configuracion");
+        }
+    }   
+}
+
+void AutoCalibracion::LeeAcelerometro()
+{
+    kionix.ReadAccels_KXR94(readings);
+    
+    // Dependiendo del paso nos interesa sumar un eje en concreto
+    switch(pasoCalibracion){
+        case 1:
+            mediaAux += readings[0];
+        break;
+            
+        case 2:
+            mediaAux += readings[0];
+        break;
+            
+        case 3:
+            mediaAux += readings[1];
+        break;
+            
+        case 4:
+            mediaAux += readings[1];
+        break;
+            
+        case 5:
+            mediaAux += readings[2];
+        break;
+            
+        case 6:
+            mediaAux += readings[2];
+        break;
+    }
+        
+    datosCapturados++;
+} 
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pantallas/AutoCalibracion.h	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,53 @@
+/**
+ * @author Juan Manuel Amador Olivares (virtualmech)
+ */
+#ifndef AUTOCALIBRACION_H
+#define AUTOCALIBRACION_H
+
+#include "mbed.h"
+#include "SistemaArchivos.h"
+#include "ScreenManager.h"
+#include "MSCFileSystem.h"
+#include "Configuracion.h"
+#include "KXR94.h"
+#include "Buffering.h"
+#include <stdlib.h>
+#include "ParametrosCalibracion.h"
+
+#define MAXCAR 32
+#define OFFSETX 4            // Espacio en pixeles que se deja antes de escribir una linea de caracteres
+#define OFFSETY 2            // Espacio en pixeles que se deja antes de escribir una linea de caracteres en la parte superior
+#define OFFSETMSG 12
+
+#define OFFSETTIEMPO 2       // Tiempo que se espera desde que se pulsa el botón OK hasta que se comienza a tomar medidas (en segundos)
+#define NDATOSPASO 1000      // Número de datos que se leerán en cada paso para hacer las medias
+#define USENTREDATOS 1000         // Tiempo entre la lectura de cada dato en microsegundos       
+
+#define ACELGRAVEDAD 9.81
+
+class AutoCalibracion : public Screen {
+    public:
+        virtual void initialize(DogMLCD* lcd);
+        virtual void update(DogMLCD* lcd);
+    
+    private:    
+        bool pulsado5;
+        bool pulsado6;
+        bool leyendoDatos;      // Indica si el viaje está o no en proceso
+        
+        char pasoCalibracion;       // Paso actual de los 7 pasos para calibrar el dispositivo
+        
+        int readings[3]; //Lectura aceleraciones sensor digital
+        float mediaXpos, mediaYpos, mediaZpos, mediaXneg, mediaYneg, mediaZneg;   //  Variables que guardan las medias medidas en cada paso
+        int datosCapturados;    // Numero de datos que se han leído en cada paso
+        float mediaAux;   // En esta variable se va calculando la media a medida que llegan los datos
+        
+        float aXr, aYr, aZr;            //Tiempo y medidas de aceleracion leidos del buffer
+        //unsigned int contDatos;     //Contador de datos
+        unsigned int ContadorDatos;
+        
+        Ticker tickerLectura;       
+        void LeeAcelerometro();
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pantallas/Configuracion/FormaSelec.cpp	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,24 @@
+/**
+ * @author Juan Manuel Amador Olivares (virtualmech)
+ */
+#include "FormaSelec.h"
+
+extern SelecManager SM;
+extern Configuracion config;
+
+void FormaSelec::button5pressed(DogMLCD* lcd){
+    // Se cambia la forma de selección actual y se guarda en la configuración
+    switch(getSelect()){
+        // sombreado
+        case 0:
+            config.setFormaSeleccion("shading");
+            SM.setInverterSelection();
+            break;
+        // Encuadrado
+        case 1:
+            config.setFormaSeleccion("framing");
+            SM.setRectSelection();
+            break;
+    }
+    ListaSelec::button5pressed(lcd);
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pantallas/Configuracion/FormaSelec.h	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,17 @@
+/**
+ * @author Juan Manuel Amador Olivares (virtualmech)
+ */
+#ifndef FORMASELEC_H
+#define FORMASELEC_H
+
+#include "SelecManager.h"
+#include "ListaSelec.h"
+#include "Configuracion.h"
+
+// Lista de elementos seleccionables. Tamaño de caracteres 8. 
+class FormaSelec: public ListaSelec{
+    public:
+    virtual void button5pressed(DogMLCD* lcd); 
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pantallas/Configuracion/IdiomaSelec.cpp	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,24 @@
+/**
+ * @author Juan Manuel Amador Olivares (virtualmech)
+ */
+#include "IdiomaSelec.h"
+
+extern ScreenManager SC;
+extern Configuracion config;
+
+void IdiomaSelec::button5pressed(DogMLCD* lcd){
+    // Se cambia el idioma actual y se guarda tambien en el fichero de configuracion
+    switch(getSelect()){
+        // Español
+        case 0:
+            config.setIdioma("spanish");
+            SC.selectGroup(0);
+            break;
+        // Inglés
+        case 1:
+            config.setIdioma("english");
+            SC.selectGroup(1);
+            break;
+    }
+    ListaSelec::button5pressed(lcd);
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pantallas/Configuracion/IdiomaSelec.h	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,16 @@
+/**
+ * @author Juan Manuel Amador Olivares (virtualmech)
+ */
+#ifndef IDIOMASELEC_H
+#define IDIOMASELEC_H
+
+#include "ListaSelec.h"
+#include "Configuracion.h"
+
+// Lista de elementos seleccionables. Tamaño de caracteres 8. 
+class IdiomaSelec: public ListaSelec{
+    public:
+    virtual void button5pressed(DogMLCD* lcd); 
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pantallas/Configuracion/RestaurarValores.cpp	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,30 @@
+/**
+ * @author Juan Manuel Amador Olivares (virtualmech)
+ */
+#include "RestaurarValores.h"
+
+extern Configuracion config;
+
+RestaurarValores::RestaurarValores(char message[]){
+    strcpy(advice, message);
+}
+
+void RestaurarValores::initialize(DogMLCD* lcd){
+    lcd->XFont = xfont_8;
+    lcd->XString(OFFSETX, OFFSETY, advice);
+    Menu::initialize(lcd);
+}
+
+void RestaurarValores::button5pressed(DogMLCD* lcd){
+    // Se cambia el idioma actual y se guarda tambien en el fichero de configuracion
+    switch(getSelect()){
+        // No se restaura la configuración
+        case 0:
+            break;
+        // Se restaura La configuración
+        case 1:
+            config.restoreSettings();
+            break;
+    }
+    Menu::button5pressed(lcd);
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pantallas/Configuracion/RestaurarValores.h	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,26 @@
+/**
+ * @author Juan Manuel Amador Olivares (virtualmech)
+ */
+#ifndef RESTAURARVALORES_H
+#define RESTAURARVALORES_H
+
+#define OFFSETX 4            // Espacio en pixeles que se deja antes de escribir una linea de caracteres
+#define OFFSETY 4            // Espacio en pixeles que se deja antes de escribir una linea de caracteres en la parte superior
+
+#include "Menu.h"
+#include "Configuracion.h"
+#include <string.h>
+
+// Lista de elementos seleccionables. Tamaño de caracteres 8. 
+class RestaurarValores: public Menu{
+    public:
+    RestaurarValores(char message[]);
+    virtual void initialize(DogMLCD* lcd);    
+    virtual void button5pressed(DogMLCD* lcd);
+    
+private:
+    char advice[64];
+    
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pantallas/Configuracion/VelAdquisicionSel.cpp	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,21 @@
+/**
+ * @author Juan Manuel Amador Olivares (virtualmech)
+ */
+#include "VelAdquisicionSel.h"
+
+extern Configuracion config;
+
+void VelAdquisicionSel::button5pressed(DogMLCD* lcd){
+    // Se cambia el idioma actual y se guarda tambien en el fichero de configuracion
+    switch(getSelect()){
+        // 1000 Hz
+        case 0:
+            config.setVelocidadAdquision(1000);
+            break;
+        // 320 Hz
+        case 1:
+            config.setVelocidadAdquision(320);
+            break;
+    }
+    ListaSelec::button5pressed(lcd);
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pantallas/Configuracion/VelAdquisicionSel.h	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,16 @@
+/**
+ * @author Juan Manuel Amador Olivares (virtualmech)
+ */
+#ifndef VELADQUISICIONSEL_H
+#define VELADQUISICIONSEL_H
+
+#include "ListaSelec.h"
+#include "Configuracion.h"
+
+// Lista de elementos seleccionables. Tamaño de caracteres 8. 
+class VelAdquisicionSel: public ListaSelec{
+    public:
+    virtual void button5pressed(DogMLCD* lcd); 
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pantallas/FechaHoraConf.cpp	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,479 @@
+/**
+ * @author Juan Manuel Amador Olivares (virtualmech)
+ */
+#include "FechaHoraConf.h"
+
+extern ScreenManager SC;
+extern FechaHora FH;
+
+extern DigitalIn boton1;
+extern DigitalIn boton2;
+extern DigitalIn boton3;
+extern DigitalIn boton4;
+extern DigitalIn boton5;
+
+extern DigitalOut myled;
+
+extern Timer t;
+
+FechaHoraConf::FechaHoraConf(char newAdvice[], char newAdvice2[], char newAdvice3[], char newdateTitle[], char newtimeTitle[]){
+    strcpy(advice, newAdvice);
+    strcpy(advice2, newAdvice2);
+    strcpy(advice3, newAdvice3);
+
+    strcpy(dateTitle, newdateTitle);
+    strcpy(timeTitle, newtimeTitle);
+}
+
+// Tecla arriba
+void FechaHoraConf::button1pressed(DogMLCD* lcd){
+    char aux[5];
+    switch(getSelect()){
+        // día
+        case 0:
+            // Dependiendo del mes el límite del dia es diferente
+            if(FH.getNmonth() == 2 && FH.getNday()+1 > 28){       // Febrero
+                FH.setNday(1);
+            }else if((FH.getNmonth() == 1 || FH.getNmonth() == 3 || FH.getNmonth() == 5 || FH.getNmonth() == 7 || FH.getNmonth() == 8 || FH.getNmonth() == 10 || FH.getNmonth() == 12) && FH.getNday()+1 > 31){    // Meses con 31 días
+                FH.setNday(1);                
+            }else if((FH.getNmonth() == 4 || FH.getNmonth() == 6 || FH.getNmonth() == 9 || FH.getNmonth() == 11) && FH.getNday()+1 > 30){    // Meses con 31 días
+                FH.setNday(1);            
+            }else{  // sino se aumenta un día
+                FH.setNday(FH.getNday()+1);
+            }
+            
+            // Se actualiza el tiempo bruto
+            FH.updateRawTime();
+            
+            // Se cambia el texto de pantalla
+            FH.getDay(aux);
+            aux[2] = '\0';
+            changeElementText(aux, getSelect(), lcd);
+                           
+            // Se redibuja la selección
+            dibujarSeleccion(getSelect(), lcd);
+            break;
+        // mes
+        case 1:
+            // Si el mes es mayor que 12 se devuelve al 1
+            if((FH.getNmonth()+1) > 12){
+                FH.setNmonth(1);
+            }else{  // sino se aumenta un mes
+                FH.setNmonth(FH.getNmonth()+1);
+            }
+            
+            // Se actualiza el tiempo bruto
+            FH.updateRawTime();
+            
+            // Se cambia el texto de pantalla
+            FH.getMonth(aux);
+            aux[2] = '\0';
+            changeElementText(aux, getSelect(), lcd);
+                           
+            // Se redibuja la selección
+            dibujarSeleccion(getSelect(), lcd);
+            break;
+        // año
+        case 2:
+            // Si el año es mayor que 1099(2999) se devuelve al 0(1900)
+            if((FH.getNyear()+1) > 1099){
+                FH.setNyear(0);
+            }else{  // sino se aumenta un año
+                FH.setNyear(FH.getNyear()+1);
+            }
+            
+            // Se actualiza el tiempo bruto
+            FH.updateRawTime();
+            
+            // Se cambia el texto de pantalla
+            FH.getYear(aux);
+            aux[4] = '\0';
+            changeElementText(aux, getSelect(), lcd);
+                           
+            // Se redibuja la selección
+            dibujarSeleccion(getSelect(), lcd);
+            break;
+        // hora
+        case 3:
+            // Si la hora es mayor que 23 se devuelve al 0
+            if((FH.getNhour()+1) > 23){
+                FH.setNhour(0);
+            }else{  // sino se aumenta una hora
+                FH.setNhour(FH.getNhour()+1);
+            }
+            
+            // Se actualiza el tiempo bruto
+            FH.updateRawTime();
+            
+            // Se cambia el texto de pantalla
+            FH.getHour(aux);
+            aux[2] = '\0';
+            changeElementText(aux, getSelect(), lcd);
+                           
+            // Se redibuja la selección
+            dibujarSeleccion(getSelect(), lcd);
+            break;   
+        // minuto
+        case 4:
+            // Si el minuto es mayor que 59 se devuelve al 0
+            if((FH.getNminute()+1) > 59){
+                FH.setNminute(0);
+            }else{  // sino se aumenta un minuto
+                FH.setNminute(FH.getNminute()+1);
+            }
+            
+            // Se actualiza el tiempo bruto
+            FH.updateRawTime();
+            
+            // Se cambia el texto de pantalla
+            FH.getMinute(aux);
+            aux[2] = '\0';
+            changeElementText(aux, getSelect(), lcd);
+                           
+            // Se redibuja la selección
+            dibujarSeleccion(getSelect(), lcd);
+            break;
+        // segundo
+        case 5:
+            // Si el segundo es mayor que 59 se devuelve al 0
+            if((FH.getNsecond()+1) > 59){
+                FH.setNsecond(0);
+            }else{  // sino se aumenta un segundo
+                FH.setNsecond(FH.getNsecond()+1);
+            }
+            
+            // Se actualiza el tiempo bruto
+            FH.updateRawTime();
+            
+            // Se cambia el texto de pantalla
+            FH.getSecond(aux);
+            aux[2] = '\0';
+            changeElementText(aux, getSelect(), lcd);
+                           
+            // Se redibuja la selección
+            dibujarSeleccion(getSelect(), lcd);
+            break;
+    }
+    // transmit work screen to physical screen:
+    lcd->Flush();
+}
+
+// Tecla abajo
+void FechaHoraConf::button4pressed(DogMLCD* lcd){
+    char aux[5];
+    switch(getSelect()){
+        // día
+        case 0:
+            // Dependiendo del mes el límite del dia es diferente
+            if(FH.getNmonth() == 2 && FH.getNday()-1 < 0){       // Febrero
+                FH.setNday(28);
+            }else if((FH.getNmonth() == 1 || FH.getNmonth() == 3 || FH.getNmonth() == 5 || FH.getNmonth() == 7 || FH.getNmonth() == 8 || FH.getNmonth() == 10 || FH.getNmonth() == 12) && FH.getNday()-1 < 0){    // Meses con 31 días
+                FH.setNday(31);                
+            }else if((FH.getNmonth() == 4 || FH.getNmonth() == 6 || FH.getNmonth() == 9 || FH.getNmonth() == 11) && FH.getNday()-1 < 0){    // Meses con 31 días
+                FH.setNday(30);            
+            }else{  // sino se aumenta un día
+                FH.setNday(FH.getNday()-1);
+            }
+            
+            // Se actualiza el tiempo bruto
+            FH.updateRawTime();
+            
+            // Se cambia el texto de pantalla
+            FH.getDay(aux);
+            aux[2] = '\0';
+            changeElementText(aux, getSelect(), lcd);
+                           
+            // Se redibuja la selección
+            dibujarSeleccion(getSelect(), lcd);
+            break;
+        // mes
+        case 1:
+            // Si el mes es mayor que 12 se devuelve al 1
+            if((FH.getNmonth()-1) < 1){
+                FH.setNmonth(12);
+            }else{  // sino se aumenta un mes
+                FH.setNmonth(FH.getNmonth()-1);
+            }
+            
+            // Se actualiza el tiempo bruto
+            FH.updateRawTime();
+            
+            // Se cambia el texto de pantalla
+            FH.getMonth(aux);
+            aux[2] = '\0';
+            changeElementText(aux, getSelect(), lcd);
+                           
+            // Se redibuja la selección
+            dibujarSeleccion(getSelect(), lcd);
+            break;
+        // año
+        case 2:
+            // Si el año es mayor que 1099(2999) se devuelve al 0(1900)
+            if((FH.getNyear()-1) < 0){
+                FH.setNyear(1099);
+            }else{  // sino se aumenta un año
+                FH.setNyear(FH.getNyear()-1);
+            }
+            
+            // Se actualiza el tiempo bruto
+            FH.updateRawTime();
+            
+            // Se cambia el texto de pantalla
+            FH.getYear(aux);
+            aux[4] = '\0';
+            changeElementText(aux, getSelect(), lcd);
+                           
+            // Se redibuja la selección
+            dibujarSeleccion(getSelect(), lcd);
+            break;
+        // hora
+        case 3:
+            // Si la hora es mayor que 23 se devuelve al 0
+            if((FH.getNhour()-1) < 0){
+                FH.setNhour(23);
+            }else{  // sino se aumenta una hora
+                FH.setNhour(FH.getNhour()-1);
+            }
+            
+            // Se actualiza el tiempo bruto
+            FH.updateRawTime();
+            
+            // Se cambia el texto de pantalla
+            FH.getHour(aux);
+            aux[2] = '\0';
+            changeElementText(aux, getSelect(), lcd);
+                           
+            // Se redibuja la selección
+            dibujarSeleccion(getSelect(), lcd);
+            break;   
+        // minuto
+        case 4:
+            // Si el minuto es mayor que 59 se devuelve al 0
+            if((FH.getNminute()-1) < 0){
+                FH.setNminute(59);
+            }else{  // sino se aumenta un minuto
+                FH.setNminute(FH.getNminute()-1);
+            }
+            
+            // Se actualiza el tiempo bruto
+            FH.updateRawTime();
+            
+            // Se cambia el texto de pantalla
+            FH.getMinute(aux);
+            aux[2] = '\0';
+            changeElementText(aux, getSelect(), lcd);
+                           
+            // Se redibuja la selección
+            dibujarSeleccion(getSelect(), lcd);
+            break;
+        // segundo
+        case 5:
+            // Si el segundo es mayor que 59 se devuelve al 0
+            if((FH.getNsecond()-1) < 0){
+                FH.setNsecond(59);
+            }else{  // sino se aumenta un segundo
+                FH.setNsecond(FH.getNsecond()-1);
+            }
+            
+            // Se actualiza el tiempo bruto
+            FH.updateRawTime();
+            
+            // Se cambia el texto de pantalla
+            FH.getSecond(aux);
+            aux[2] = '\0';
+            changeElementText(aux, getSelect(), lcd);
+                           
+            // Se redibuja la selección
+            dibujarSeleccion(getSelect(), lcd);
+            break;
+    }
+    // transmit work screen to physical screen:
+    lcd->Flush();
+}
+
+// Tecla izquierda
+void FechaHoraConf::button2pressed(DogMLCD* lcd){
+    // Sólo se puede mover la seleccón a la izquierda si no se está en el elemento 0
+    if(getSelect() > 0){
+        // Se deselecciona el elemento seleccionado actualmente
+        borrarSeleccion(getSelect(), lcd);
+        setSelect(getSelect()-1);
+        // Se pinta la nueva selección
+        dibujarSeleccion(getSelect(), lcd);
+        
+        // transmit work screen to physical screen:
+        lcd->Flush();  
+    }    
+}
+
+// Tecla derecha
+void FechaHoraConf::button3pressed(DogMLCD* lcd){
+    // Sólo se puede mover la seleccón a la derecha si no se está en el elemento 5
+    if(getSelect() < 5){
+        // Se deselecciona el elemento seleccionado actualmente
+        borrarSeleccion(getSelect(), lcd);
+        setSelect(getSelect()+1);
+        // Se pinta la nueva selección
+        dibujarSeleccion(getSelect(), lcd);
+        
+        // transmit work screen to physical screen:
+        lcd->Flush();  
+    }
+}
+
+void FechaHoraConf::button5pressed(DogMLCD* lcd){
+    
+}
+
+void FechaHoraConf::initialize(DogMLCD* lcd){
+    // Se borran los elementos anteriores
+    borrarElementos();
+        
+    // select font to use:
+    lcd->XFont = xfont_8;
+    
+    FH.update();    // Se actualiza la fecha y hora
+    // Se inicia el temporizador que se usará para actualizar la hora
+    t.reset();
+    t.start();
+    
+    // Se escribe el título de fecha
+    lcd->XString(OFFSETXTITLES, OFFSETY + 8*0, dateTitle);
+    
+    // Se escribe el título de hora
+    lcd->XString(OFFSETXTITLES, OFFSETY + 8*2, timeTitle);
+    
+    char aux[5];
+    
+    // Se añade el elemento día
+    FH.getDay(aux);
+    aux[2] = '\0';
+    addElement(aux, OFFSETX, OFFSETY + 8*1); 
+    
+    // Se añade el elemento mes
+    FH.getMonth(aux);
+    aux[2] = '\0';
+    addElement(aux, OFFSETX+21, OFFSETY + 8*1);    
+    
+    // Se añade el elemento año
+    FH.getYear(aux);
+    aux[4] = '\0';
+    addElement(aux, OFFSETX+42, OFFSETY + 8*1);
+    
+    // Se añade el elemento hora
+    FH.getHour(aux);
+    aux[2] = '\0';
+    addElement(aux, OFFSETX, OFFSETY + 8*3);    
+    
+    // Se añade el elemento minuto
+    FH.getMinute(aux);
+    aux[2] = '\0';
+    addElement(aux, OFFSETX+21, OFFSETY + 8*3);    
+    
+    // Se añade el elemento segundo
+    FH.getSecond(aux);
+    aux[2] = '\0';
+    addElement(aux, OFFSETX+42, OFFSETY + 8*3);
+    
+    // Se muestran dos puntos para separar cada uno de los valores
+    lcd->XString(20,OFFSETY + 8, ":");
+    lcd->XString(41,OFFSETY + 8, ":");
+    lcd->XString(20,OFFSETY + 8*3, ":");
+    lcd->XString(41,OFFSETY + 8*3, ":");
+    
+    // Se muestran todos los elementos
+    for(int i = 0; i < nElementos; i++){
+        lcd->XString(elementPos[i][0], elementPos[i][1], element[i]);
+    }
+    
+    setSelect(0);
+    // Se dibuja la selección por defecto    
+    dibujarSeleccion(getSelect(), lcd);
+    
+    // Se escribe el consejo en la parte inferior de la pantalla
+    lcd->XString(OFFSETX, HEIGHT - 8*3, advice);
+    lcd->XString(OFFSETX, HEIGHT - 8*2, advice2);
+    lcd->XString(OFFSETX, HEIGHT - 8, advice3);
+    
+    // transmit work screen to physical screen:
+    lcd->Flush();
+}
+
+void FechaHoraConf::dibujarSeleccion(char nElemento, DogMLCD* lcd){
+    if(nElemento == 2){ // Si el elemento es el 2 (el del año) el recuadro de selección es más grande
+        drawSelection(elementPos[nElemento][0]-2, elementPos[nElemento][1]-2, ANCHOSELECCION4, ALTOSELECCION, lcd);
+    }else{
+        drawSelection(elementPos[nElemento][0]-2, elementPos[nElemento][1]-2, ANCHOSELECCION2, ALTOSELECCION, lcd);
+    }
+}
+
+void FechaHoraConf::borrarSeleccion(char nElemento, DogMLCD* lcd){
+    if(nElemento == 2){ // Si el elemento es el 2 (el del año) el recuadro de selección es más grande
+        drawDeselection(elementPos[nElemento][0]-2, elementPos[nElemento][1]-2, ANCHOSELECCION4, ALTOSELECCION, lcd);
+    }else{
+        drawDeselection(elementPos[nElemento][0]-2, elementPos[nElemento][1]-2, ANCHOSELECCION2, ALTOSELECCION, lcd);
+    }
+}
+
+void FechaHoraConf::update(DogMLCD* lcd){
+    // Si no se está en los segundos se actualiza cada segundo la hora
+    if(getSelect() < 5){
+        if(t.read_ms() >= 1000){
+            t.reset();
+            t.start();
+            // Se actualiza la hora
+            FH.update();
+            
+            char aux[5];
+            // Se cambian los valores de los segundos, los minutos y las horas
+            // Se añade el elemento hora
+            FH.getHour(aux);
+            aux[2] = '\0';
+            changeElementText(aux, 3, lcd);
+            
+            // Se añade el elemento minuto
+            FH.getMinute(aux);
+            aux[2] = '\0';
+            changeElementText(aux, 4, lcd);
+            
+            // Se añade el elemento segundo
+            FH.getSecond(aux);
+            aux[2] = '\0';
+            changeElementText(aux, 5, lcd);
+            
+            // Si la seleccion estaba en alguno de estos elementos se ha borrado, así que se vuelve a pintar
+            if(getSelect() > 2){                
+                dibujarSeleccion(getSelect(), lcd);
+            }
+            
+            // transmit work screen to physical screen:
+            lcd->Flush();
+        }
+    }
+    
+    // Se llama a la función padre
+    Seleccion::update(lcd);
+}
+
+void FechaHoraConf::changeElementText(char newText[], int nElemento, DogMLCD* lcd){
+    // Se borra valor actual
+    if(nElemento == 2){ // Si el elemento es el 2 (el del año) el recuadro de selección es más grande
+        lcd->Rect(elementPos[nElemento][0]-2, elementPos[nElemento][1]-2, elementPos[nElemento][0]-2 + ANCHOSELECCION4, elementPos[nElemento][1]-2 + ALTOSELECCION, DOGMLCD_full, wipe);
+    }else{
+        lcd->Rect(elementPos[nElemento][0]-2, elementPos[nElemento][1]-2, elementPos[nElemento][0]-2 + ANCHOSELECCION2, elementPos[nElemento][1]-2 + ALTOSELECCION, DOGMLCD_full, wipe);
+    }
+    // Se actualiza el texto del elemento
+    strcpy(element[nElemento], newText);
+    
+    // Se pinta el nuevo texto
+    lcd->XString(elementPos[nElemento][0], elementPos[nElemento][1], element[nElemento]);
+}
+    
+
+int FechaHoraConf::addElement(char text[], char posX, char posY){
+    strcpy(element[nElementos], text);
+    elementPos[nElementos][0] = posX;
+    elementPos[nElementos][1] = posY;
+    nElementos++;
+    return nElementos - 1;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pantallas/FechaHoraConf.h	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,55 @@
+/**
+ * @author Juan Manuel Amador Olivares (virtualmech)
+ */
+#ifndef FECHAHORACONF_H
+#define FECHAHORACONF_H
+
+#include "Seleccion.h"
+#include "FechaHora.h"
+#include "doggy.h"
+
+#define NELEMENTS 6          // Número de elementos seleccionables de esta pantalla
+
+#define MAXCARACTER 22      // Número máximo de caracteres de cada elemento
+#define OFFSETX 4            // Espacio en pixeles que se deja antes de escribir una linea de caracteres
+#define OFFSETXTITLES 16            // Espacio en pixeles que se deja antes de escribir una linea de caracteres
+#define OFFSETY 4            // Espacio en pixeles que se deja antes de escribir una linea de caracteres
+
+#define ANCHOSELECCION2 16  // Ancho del recuadro de selección de dos caracteres
+#define ANCHOSELECCION4 32  // Ancho del recuadro de selección de cuatro caracteres
+#define ALTOSELECCION 9    // Alto del recuadro de selección
+
+// Lista de elementos seleccionables. Tamaño de caracteres 8. 
+class FechaHoraConf: public Seleccion{
+    public:
+    FechaHoraConf(char newAdvice[], char newAdvice2[], char newAdvice3[], char newdateTitle[], char newtimeTitle[]);
+    virtual void initialize(DogMLCD* lcd);
+    virtual void update(DogMLCD* lcd);
+    
+    virtual void button1pressed(DogMLCD* lcd);     // Esta función se llama cuando el botón superior es pulsado, definirla para añadir funcionalidades
+    virtual void button2pressed(DogMLCD* lcd);     // Esta función se llama cuando el botón superior es pulsado, definirla para añadir funcionalidades
+    virtual void button3pressed(DogMLCD* lcd);     // Esta función se llama cuando el botón superior es pulsado, definirla para añadir funcionalidades
+    virtual void button4pressed(DogMLCD* lcd);     // Esta función se llama cuando el botón inferior es pulsado, definirla para añadir funcionalidades
+    virtual void button5pressed(DogMLCD* lcd);     // Esta función se llama cuando el botón central es pulsado, definirla para añadir funcionalidades
+    
+    int addElement(char text[], char posX, char posY);                 // Añade un elemento seleccionable a la pantalla
+    void changeElementText(char newText[], int nElemento, DogMLCD* lcd);
+    
+    private:    
+    
+    char element[NELEMENTS][5];     // Variable que guarda los elementos seleccionables de la pantalla
+    char elementPos[NELEMENTS][2];  // Guarda la posición de los elementos de la pantalla
+    
+    char advice[MAXCARACTER*3];
+    char advice2[MAXCARACTER*2];
+    char advice3[MAXCARACTER*2];
+    char dateTitle[MAXCARACTER];
+    char timeTitle[MAXCARACTER];
+    
+    void dibujarSeleccion(char nElemento, DogMLCD* lcd);
+    void borrarSeleccion(char nElemento, DogMLCD* lcd);
+    
+
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pantallas/GuardarOtroNombre.cpp	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,106 @@
+/**
+ * @author Juan Manuel Amador Olivares (virtualmech)
+ */
+#include "GuardarOtroNombre.h"
+
+extern FechaHora FH;
+extern ScreenManager SC;
+extern SistemaArchivos SA;
+extern MSCFileSystem msc;
+extern Teclado keyboard;
+
+extern Mensaje guardadoCorrect;
+extern Mensaje guardadoCorrectEN;
+
+extern Mensaje nombreExistente;
+extern Mensaje nombreExistenteEN;
+
+extern DigitalOut myled;
+
+GuardarOtroNombre::GuardarOtroNombre(char nextScreen[], char newAdvice[], char newWaitMsg[]):Mensaje(nextScreen, newAdvice){
+    nombreAntiguo = NULL;
+    strcpy(waitMsg, newWaitMsg);
+}
+
+void GuardarOtroNombre::setNombreAntiguo(char *oldName){
+    nombreAntiguo = oldName;
+}
+
+void GuardarOtroNombre::disableNombreAntiguo(){
+    nombreAntiguo = NULL;
+}
+
+void GuardarOtroNombre::initialize(DogMLCD* lcd){
+    // select font to use:
+    lcd->XFont = xfont_11;  
+    // Se pinta un mensaje de espera
+    lcd->XString(OFFSETX + 8, 23, waitMsg);
+    // Se envía a la pantalla física
+    lcd->Flush();
+    // Se deja la pantalla en blanco para cuando se acabe de cambair de nombre el archivo
+    lcd->Clear();
+    
+    // Se cambia el nombre del archivo del propio USB    
+    char oldFile[64];
+    char newName[64];
+    char aux[64];
+    
+    // Si el nombreAntiguo vale NULL se toma como nombre antiguo la última fecha y hora guardado    
+    if(nombreAntiguo == NULL){
+        strcpy(aux, FH.getFechaHora());
+        strcpy(oldFile, "/usb/RAW");
+        strcat(oldFile, aux);
+        strcat(oldFile, ".txt");
+    }else{
+        strcpy(oldFile, "/usb/");
+        strcat(oldFile, nombreAntiguo);
+        strcat(oldFile, ".txt");
+    }
+    
+    // Si el archivo no se puede cargar se pasa a la pantalla que avisa que el USB está lleno o desconectado    
+    FILE* file;
+    file = fopen(oldFile, "r");
+    if(file == NULL){
+        SC.changeScreen("USBdesconectado");        
+    }else{
+        // Se cierra el archivo
+        fclose(file);
+        // El nombre nuevo se toma de el texto introducido con el teclado
+        strcpy(aux, keyboard.getNombre());
+        // Se comprueba si ya existe un fichero con este nombre
+        if(SA.alredyExist(aux)){
+            // Se configura la pantalla siguiente según si se está guardan un viaje nuevo con otro nombre o se está cambiando el nombre a uno ya existente
+            if(nombreAntiguo != NULL){  // Se debe de volver a la pantalla de opciones del viaje
+                nombreExistente.setNextScreen("rOptions");
+                nombreExistente.setBackScreen("rOptions");
+                nombreExistenteEN.setNextScreen("rOptions");
+                nombreExistenteEN.setBackScreen("rOptions");
+            }else{                  // Se debe volver a la pantalla de guardado de nuevo viaje
+                nombreExistente.setNextScreen("guardaViaje");
+                nombreExistente.setBackScreen("guardaViaje");
+                nombreExistenteEN.setNextScreen("guardaViaje");
+                nombreExistenteEN.setBackScreen("guardaViaje");
+            }
+            SC.changeScreen("alredyExist");                      
+        }else{        
+            // Se va a guardar cno otro nombre el archivo asi que
+            if(nombreAntiguo != NULL){
+                SA.renameRide(nombreAntiguo, aux);            
+            }else{  // Se guarda el nuevo nombre del archivo en la lista de nombres de los viajes sólo si nombreAntiguo vale NULL
+                strcpy(newName, "/usb/");
+                strcat(newName, aux);
+                strcat(newName, ".txt");
+                SA.file_rename(oldFile, newName);
+                strcpy(newName, keyboard.getNombre());
+                SA.addElement(newName);
+            }
+            
+            // Se muestra el mensaje de archivo guardado correctamente por pantalla
+            Mensaje::initialize(lcd);
+        }
+    }
+}
+
+void GuardarOtroNombre::button5pressed(DogMLCD* lcd){    
+    Mensaje::button5pressed(lcd);    
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pantallas/GuardarOtroNombre.h	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,33 @@
+/**
+ * @author Juan Manuel Amador Olivares (virtualmech)
+ */
+#ifndef GUARDAROTRONOMBRE_H
+#define GUARDAROTRONOMBRE_H
+
+#include "Mensaje.h"
+#include "SistemaArchivos.h"
+#include "MSCFileSystem.h"
+#include "ScreenManager.h"
+#include "FechaHora.h"
+#include "Teclado.h"
+
+// Lista de elementos seleccionables. Tamaño de caracteres 8. 
+class GuardarOtroNombre: public Mensaje{
+    public:
+    GuardarOtroNombre(char nextScreen[], char newAdvice[], char newWaitMsg[]);
+    
+    virtual void initialize(DogMLCD* lcd);
+    
+    virtual void button5pressed(DogMLCD* lcd);
+    
+    void setNombreAntiguo(char *oldName);     // Configura el nombre antiguo del archivo al que se le va a cambiar el nombre
+                                                // si vale NULL se considera que el nombre antiguo es el guardado por el sistema de fecha y hora (nombres por defecto)
+    void disableNombreAntiguo();            // Pone nombre antiguo a NULL
+    
+    private:
+    
+    char *nombreAntiguo;
+    char waitMsg[MAXCARACTER];
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pantallas/GuardarViaje.cpp	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,62 @@
+/**
+ * @author Juan Manuel Amador Olivares (virtualmech)
+ */
+#include "GuardarViaje.h"
+
+extern FechaHora FH;
+extern ScreenManager SC;
+extern SistemaArchivos SA;
+extern MSCFileSystem msc;
+extern Teclado keyboard;
+
+extern GuardarOtroNombre guardadoCorrect;
+extern GuardarOtroNombre guardadoCorrectEN;
+
+extern DigitalOut myled;
+
+void GuardarViaje::button5pressed(DogMLCD* lcd){
+    bool llamarRaiz = true;     // Se usa para llamar o no a la función padre (para controlar los cambios de pantalla)
+    // Se cambia el idioma actual y se guarda tambien en el fichero de configuracion
+    switch(getSelect()){
+        char fileName[64];
+        char auxTime[64];  
+        // Volver al menú
+        case 0:
+            // Se guarda el nombre del archivo en la lista de nombres de los viajes              
+            strcpy(auxTime, FH.getFechaHora());
+            strcpy(fileName, "RAW");
+            strcat(fileName, auxTime);
+            SA.addElement(fileName);            
+            break;
+            
+        // Cambiar nombre
+        case 1:
+            guardadoCorrect.setNextScreen("menu");
+            guardadoCorrectEN.setNextScreen("menu");
+            guardadoCorrect.setBackScreen("menu");
+            guardadoCorrectEN.setBackScreen("menu");
+            guardadoCorrect.disableNombreAntiguo();
+            guardadoCorrectEN.disableNombreAntiguo();
+            keyboard.setBackScreen("guardaViaje");
+            keyboard.setNextScreen("fileSaved");
+            break;
+        // Borrar el archivo
+        case 2:
+            llamarRaiz = false;
+            // Se borrar el archivo del último viaje        
+            strcpy(auxTime, FH.getFechaHora());
+            strcpy(fileName, "/usb/RAW");
+            strcat(fileName, auxTime);
+            strcat(fileName, ".txt");     
+            
+            if(remove(fileName) != 0){  // Si no se pudo borrar se avisa por pantalla de USB 
+                SC.changeScreen("USBdesconectado");
+            }else{
+                SC.changeScreen("archivoBorrado");
+            }
+            break;
+    }
+    if(llamarRaiz){
+        Menu::button5pressed(lcd);
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pantallas/GuardarViaje.h	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,21 @@
+/**
+ * @author Juan Manuel Amador Olivares (virtualmech)
+ */
+#ifndef GUARDARVIAJE_H
+#define GUARDARVIAJE_H
+
+#include "Menu.h"
+#include "SistemaArchivos.h"
+#include "MSCFileSystem.h"
+#include "ScreenManager.h"
+#include "FechaHora.h"
+#include "Teclado.h"
+#include "GuardarOtroNombre.h"
+
+// Lista de elementos seleccionables. Tamaño de caracteres 8. 
+class GuardarViaje: public Menu{
+    public:
+    virtual void button5pressed(DogMLCD* lcd);
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pantallas/NuevoViaje.cpp	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,360 @@
+#include "NuevoViaje.h"
+/// ACELEROMETRO DIGITAL///
+KXR94 kionix(p11,p12,p13,p21);
+
+extern ScreenManager SC;
+extern SistemaArchivos SA;
+extern Configuracion config;
+extern MSCFileSystem msc;
+extern FechaHora FH;
+
+extern DigitalOut myled;
+extern DigitalIn boton5;
+extern DigitalIn boton6;
+
+extern Timer t; // Temporizador usado para controlar la animación de la pantalla
+
+NuevoViaje::NuevoViaje(char newtitle[], char newsubtitle[], char newmsg11[], char newmsg12[], char newmsg2[]){
+    strcpy(title, newtitle);
+    strcpy(subtitle, newsubtitle);
+    strcpy(msg11, newmsg11);
+    strcpy(msg12, newmsg12);
+    strcpy(msg2, newmsg2);
+}  
+
+void NuevoViaje::initialize(DogMLCD* lcd){  
+    // Inicilización de las variables
+    aXanterior = 0;
+    aYanterior = 0;
+    aZanterior = 0;    
+    
+    ContadorDatos = 0;
+    pulsado5 = false;
+    pulsado6 = false;
+    leyendoDatos = false;
+    PasoTiempo = 1.0e6/config.getVelocidadAdquisicion();
+    
+    // select font to use:
+    lcd->XFont = xfont_11;
+
+    // output title text
+    lcd->XString( OFFSETX, OFFSETY, title);
+    
+    lcd->XFont = xfont_8;
+    
+    // output subtitle text
+    char aux[MAXCAR*2];
+    char aux2[MAXCAR];
+    strcpy(aux, subtitle);
+    config.getVelocidadAdquisicionString(aux2);
+    strcat(aux, aux2);
+    strcat(aux, " Hz");
+    lcd->XString( OFFSETX, OFFSETY + 11, aux);
+    
+    // output msg2 text
+    lcd->XString( OFFSETX, HEIGHT -1 - 8, msg2);
+    
+    // Se pinta el recuadro del gráfico animado
+    lcd->Frame(POSX0, POSY0, POSX0 + WIDTHFRAME, POSY0 + HEIGHTFRAME);
+    
+    // Se pinta el recuadro lleno que se moverá dentro dle recuadro pintado anteriormente
+    lcd->Rect(POSX0 + 1, POSY0 + 1, POSX0 + 1 + WIDTHRECT, POSY0 + HEIGHTFRAME);
+    
+    // Se inicializa el sentido de la animación (sentido en el que se mueve incialmente el recuadro
+    posXF = POSX0 + 1 + WIDTHRECT;
+    sentidoAnimacion = true;
+
+    // transmit work screen to physical screen:
+    lcd->Flush(); 
+    
+    // se actualiza la fecha
+    FH.update();
+    
+    // El archivo donde se guardarán los datos es la fecha y hora con formato con la extensión .txt
+    char fileName[64];
+    char auxTime[64];
+    
+    strcpy(auxTime, FH.getFechaHora());
+    strcpy(fileName, "/usb/RAW");
+    strcat(fileName, auxTime);
+    strcat(fileName, ".txt");    
+    
+    // Se prepara el USB para escribir en él
+    // Si el USB está desconectado se avisa del error
+    if(msc.disk_initialize()){
+        SC.changeScreen("USBdesconectado");
+    }    
+    
+    // Se inicia el contador para comprobar si el USB se ha quedado colgado y se activa el ticker que cumple esta función
+    //t.start();
+    // Cada segundo se comprueba si el USB se ha quedado colgado (o no está conectado)
+    //USBcolgado.attach(this, &NuevoViaje::compruebaUSB, 1);
+     
+    fp = fopen(fileName, "w");
+    if(fp == NULL){     // Si el USB está desconectado o lleno se avisa por pantalla y se vuelve al menú
+        // Se desactiva y reseta el timer
+        /*t.stop();
+        t.reset();
+        USBcolgado.detach();*/
+        SC.changeScreen("USBdesconectado");
+    }else{  // Si no se prepara el acelerómetro para comenzar con las lecturas    
+        // Se cargan los valores de calibración del acelerómetro
+        ParametrosCalibracion::leerValores(valoresCal);
+        
+        /*FILE* fp = fopen("/local/prueba2.txt","w");
+        fprintf(fp, "%f\n%f\n%f\n%f\n%f\n%f\n", valoresCal[0], valoresCal[1], valoresCal[2], valoresCal[3], valoresCal[4], valoresCal[5]);
+        fclose(fp);*/
+        
+        // Se crean los buffer donde se guardarán los datos        
+        buff_aX = new Buffering();
+        buff_aY = new Buffering();
+        buff_aZ = new Buffering();
+        
+        kionix.AcelerometroWakeUp();
+        // Hasta que no está preparado no se muestra el mensaje de "OK para comenzar"
+        // output msg11 text
+        // select font to use:
+        lcd->XFont = xfont_11;
+        lcd->XString(OFFSETX, HEIGHT -1 - 8 - 11, msg11);  // Se pinta más arriba para que haya más espacio
+        
+        // transmit work screen to physical screen:
+        lcd->Flush();        
+    }
+    
+    // Debug
+    //llamadasTicker = 0;
+}
+    
+void NuevoViaje::update(DogMLCD* lcd){    
+    // ANIMACIÓN
+    // Si se están leyendo datos
+    if(leyendoDatos){
+        if(t.read_ms() >= UPDATETIME){           
+            // Se procede de forma distinta según el sentido de movimiento del recuadro
+            if(sentidoAnimacion){       // Derecha       
+                // Se pinta la siguiente columna del recuadro
+                lcd->LineV(posXF + 1, POSY0 + 1, POSY0 + HEIGHTFRAME-1);
+                
+                // Se borra la correspondiente para que el recuadro siga teniendo el mismo tamaño
+                lcd->LineV(posXF - WIDTHRECT, POSY0 + 1, POSY0 + HEIGHTFRAME-1, wipe);        
+                posXF++;
+                
+                // Si se ha llegado al final del frame, se cambia de sentido y se sitúa la variable posXF en la izquierda del recuadro animado
+                if(posXF >= POSX0 + WIDTHFRAME - 1){
+                    sentidoAnimacion = false;
+                    posXF = POSX0 + WIDTHFRAME - WIDTHRECT;
+                }
+            }else{                      // Izquierda
+                // Se pinta la siguiente columna del recuadro
+                lcd->LineV(posXF - 1, POSY0 + 1, POSY0 + HEIGHTFRAME-1);
+                
+                // Se borra la correspondiente para que el recuadro siga teniendo el mismo tamaño
+                lcd->LineV(posXF + WIDTHRECT - 1, POSY0 + 1, POSY0 + HEIGHTFRAME-1, wipe);
+                posXF--;
+                
+                // Si se ha llegado al final del frame, se cambia de sentido y se sitúa la variable posXF en la derecha del recudro animado
+                if(posXF <= POSX0 + 2){
+                    sentidoAnimacion = true;
+                    posXF = POSX0 + 1 + WIDTHRECT;
+                }
+            }
+            
+            // Se envía a la pantalla la actualización(tener cuidado con las páginas que se envían)
+            lcd->Flush(3, 0, posXF+WIDTHRECT+1);
+            lcd->Flush(4, 0, posXF+WIDTHRECT+1);
+            
+            // Se resetea el contador
+            t.reset();     
+        }
+    }
+    
+    if(boton5 == 1){
+        pulsado5 = true;
+    }else{
+        if(pulsado5 == true){   // El boton ha sido pulsado
+            pulsado5 = false;            
+            if(!leyendoDatos){      // Si el viaje no habia comenzado
+                // Primero hay que comprobar si el USB está desconectado
+                leyendoDatos = true;
+                // Se inicia el timer que controlará el temporizador
+                t.reset();
+                t.start();
+                
+                // Debug
+                /*time.reset();
+                time.start();*/
+                
+                // Se comienza a leer el acelerómetro
+                tickerLectura.attach_us(this, &NuevoViaje::LeeAcelerometroBuffer, PasoTiempo);
+                // Se cambia el mensaje 11 por el 12
+                // para ello se pinta un rectángulo vacío en la posición de los caracteres anteriores y se pinta encima los nuevos caracteres
+                int y0 = HEIGHT -1 - 8 - 11;
+                for(int i = 0; i < WIDTH; i++){
+                    for(int k = y0; k < (y0 + 11); k++){
+                        lcd->Wipe(i,k);
+                    }
+                }
+                
+                // select font to use:
+                lcd->XFont = xfont_11;
+                
+                // output msg11 text
+                lcd->XString( OFFSETX, HEIGHT -1 - 8 - 11, msg12);  // Se pinta más arriba para que haya más espacio
+                
+                // transmit work screen to physical screen:
+                lcd->Flush();           
+            }else{  // Si el viaje estaba en curso y se desea finalizar
+            
+                // Se duerme el acelerómetro                
+                kionix.AcelerometroSleep();                
+                tickerLectura.detach();
+                
+                fclose(fp); //cierra fichero con datos en el USB
+                // Se deja libre la memoria de los buffer              
+                delete buff_aX;
+                delete buff_aY;
+                delete buff_aZ;
+                
+                // Se para el temporizador
+                t.stop();
+                
+                // Debug
+                //time.stop();
+                
+                // Debug
+                /*FILE* fp = fopen("/local/prueba3.txt","w");
+                fprintf(fp, "%d, %d", ContadorDatos, llamadasTicker);
+                fclose(fp);       */         
+                
+                // Se pasa a la pantalla de guardado del viaje
+                SC.changeScreen("archivoGuardado");                
+            }
+        }
+    }
+    
+    // Botón atrás
+    if(boton6 == 1){
+        pulsado6 = true;
+    }else{
+        if(pulsado6 == true){
+            pulsado6 = false;
+            // Solo se volverá al menú si el viaje no está en proceso
+            if(!leyendoDatos){
+                fclose(fp); //cierra fichero con datos en el USB                
+                // Se duerme el acelerómetro                
+                kionix.AcelerometroSleep();  
+                // Se deja libre la memoria de los buffer
+                delete buff_aX;
+                delete buff_aY;
+                delete buff_aZ;
+                SC.changeScreen("menu");
+            }
+            
+        }
+    }
+    // Siempre que existan datos por guardar, se guardan en el USB
+    GuardaDatosBuffer();
+}
+
+void NuevoViaje::LeeAcelerometroBuffer()
+{
+    // Debug
+    //llamadasTicker++;
+    
+    kionix.ReadAccels_KXR94(readings);
+    
+    aaX = (int16_t)readings[0];
+    aaY = (int16_t)readings[1];
+    aaZ = (int16_t)readings[2];
+
+    buff_aX->put(aaX);   
+    buff_aY->put(aaY);
+    buff_aZ->put(aaZ);
+}      
+        
+void NuevoViaje::GuardaDatosBuffer()
+{
+    bool empty = buff_aX->isEmpty();
+    
+    int dif;          //Diferencia entre writting index y riding index. El buffer se llena cuando esta diferencia alcanza el tamaño del buffer
+    float tiempo;     //Tiempo en segundos    
+    
+    if(empty == false)
+    {     
+        aXr = buff_aX->get(); 
+        aYr = buff_aY->get(); 
+        aZr = buff_aZ->get();
+        
+        // Debug
+        // Usar las líneas de código inferiores para depurar el buffering
+        /*int wi = buff_aX->getWritingIndex();
+        int ri = buff_aX->getReadingIndex();
+        int dif = buff_aX->getDif();*/
+        
+        aX = (-1.0)*((float)aXr-(valoresCal[0]))*valoresCal[3];
+        aY = (-1.0)*((float)aYr-(valoresCal[1]))*valoresCal[4];
+        aZ = (-1.0)*((float)aZr-(valoresCal[2]))*valoresCal[5];
+        // Para evitar algunos fallos por saturación todo valor mayor que 20 se le da el valor del punto anterior
+        if(aX > 20.0){
+          aX = aXanterior;
+        }
+        if(aY > 20.0){
+          aY = aYanterior;
+        }
+        if(aZ > 20.0){
+          aZ = aZanterior;
+        }
+        
+        // También se debe calcular la saturación en 0, por ello si un valor es menor (en valor absoluto)
+        // que la precisión del acelerómetro se le da también el valor del punto anterior
+        if(aX*1000 == 0.0000 ){
+            aX = aXanterior;
+        }
+        if(aY*1000 == 0.0000){
+            aY = aYanterior;
+        }
+        if(aZ*1000 == 0.0000){
+            aZ = aZanterior;
+        }        
+        
+        aXanterior = aX;
+        aYanterior = aY;
+        aZanterior = aZ;  
+    
+    
+        tiempo = ((float)ContadorDatos)*((float)PasoTiempo)/1.0e6;
+        ContadorDatos++;
+        
+        //if(fprintf(fp,"%f %f %f %f\n", tiempo, aXr, aYr, aZr) < 0){   // Pruebas
+        if(fprintf(fp,"%f %f %f %f\n", tiempo, aX, aY, aZ) < 0){
+        //if(fprintf(fp,"%f\n", tiempo) < 0){    // Pruebas
+        //if(fprintf(fp,"%f %f %f %f %d %d %d\n", tiempo, aX, aY, aZ, wi, ri, dif) < 0){    // pruebas
+        //if(fprintf(fp,"%d %f %f %f %d %d %d\n", time.read_us(), aX, aY, aZ, wi, ri, dif) < 0){    // pruebas
+        //if(fprintf(fp,"%f %f %f %f %d %d %d\n", tiempo, aX, aY, aZ, llamadasTicker, ContadorDatos, llamadasTicker-ContadorDatos) < 0){    // pruebas
+            // Si se sigue estando en la pantalla de NuevoViaje se aborta la lectura de datos y se muestra por pantalla que el USB ha sido desconectado
+            if(strcmp(SC.getCurrentScreen(), "viaje") == 0){
+                
+                // Se duerme el acelerómetro                
+                kionix.AcelerometroSleep();                
+                tickerLectura.detach();
+                fclose(fp); //cierra fichero con datos en el USB
+                // Se deja libre la memoria de los buffer
+                delete buff_aX;
+                delete buff_aY;
+                delete buff_aZ;
+                myled = 1;
+                SC.changeScreen("USBdesconectado");
+            }
+        }    
+        
+        // Debug
+        // Código para ralentizar la mbed
+        /*for(int i = 0; i< 10000000; i++){
+            int prueba34 = prueba34*prueba34/17*23425434;
+        }*/
+    }
+}
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pantallas/NuevoViaje.h	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,82 @@
+/**
+ * @author Juan Manuel Amador Olivares (virtualmech)
+ * Pantalla de nuevo viaje. En esta se leeran los datos del acelerómetro y se guardarán en memoria, si es necesario utilizando buffering
+ * Mientras se elle también se mostrará una pequeña animación para que de la sensación de que el dispositivo está leyendo datos
+ */
+#ifndef NUEVOVIAJE_H
+#define NUEVOVIAJE_H
+
+#include "mbed.h"
+#include "SistemaArchivos.h"
+#include "ScreenManager.h"
+#include "MSCFileSystem.h"
+#include "Configuracion.h"
+#include "FechaHora.h"
+#include "KXR94.h"
+#include "Buffering.h"
+#include <stdlib.h>
+#include "ParametrosCalibracion.h"
+
+#define TUSBCOLGADO 2 // tiempo en segundos que se espera a que responda el USB, en caso contrario se considera que se ha quedado colgado
+
+#define MAXCAR 32
+#define OFFSETX 4            // Espacio en pixeles que se deja antes de escribir una linea de caracteres
+#define OFFSETY 2            // Espacio en pixeles que se deja antes de escribir una linea de caracteres en la parte superior
+//#define SIZEBUFF 250            // Tamaño del buffer de datos
+
+#define COUNTPRECISION 0.00958  // Precisión del dispositivo (mínimo valor de cambio teórico, se calcula como: 4*g/2^12)
+
+// Definiciones gráfico animado
+#define POSX0 13
+#define WIDTHFRAME 100
+#define POSY0 23
+#define HEIGHTFRAME 17
+
+#define WIDTHRECT 10    // Ancho del recuadro interior que se mueve a medida que se gravan los datos, el alto del recuadro es el máximo que cabe dentro del frame (8 pixeles, el alto de una página)
+#define UPDATETIME 15  // Tiempo en ms que tarda en avanzar una columna el recuadro del gráfico animado
+
+class NuevoViaje : public Screen {
+    public:
+        NuevoViaje(char newtitle[], char newsubtitle[], char newmsg11[], char newmsg12[], char newmsg2[]);
+        virtual void initialize(DogMLCD* lcd);
+        virtual void update(DogMLCD* lcd);
+    
+    private:    
+        char title[MAXCAR];
+        char subtitle[MAXCAR];
+        char msg11[MAXCAR];
+        char msg12[MAXCAR];
+        char msg2[MAXCAR];
+        bool pulsado5;
+        bool pulsado6;
+        bool leyendoDatos;      // Indica si el viaje está o no en proceso
+        unsigned int PasoTiempo;    // Guarda el tiempo en microsegundos que debe de pasar entre cada lectura
+        
+        Buffering *buff_aX;
+        Buffering *buff_aZ;
+        Buffering *buff_aY;
+        
+        FILE * fp;     // Puntero al fichero donde se escribirán los datos
+        
+        float valoresCal[6];        // Valores de calibración del acelerómetro
+        int readings[3];            //Lectura aceleraciones sensor digital
+        float aX, aY, aZ;            //Medidas de aceleracion
+        float aXanterior, aYanterior, aZanterior;            //Medidas de aceleracion del punto anterior
+        int16_t aaX, aaY, aaZ;       //Medidas de aceleracion y tiempo 
+        
+        float aXr, aYr, aZr;            // Tiempo y medidas de aceleracion leidos del buffer
+        unsigned int ContadorDatos;
+        
+        Ticker tickerLectura;
+        void LeeAcelerometroBuffer();
+        void GuardaDatosBuffer();
+        
+        bool sentidoAnimacion;  // Sentido del movimiento del recuadro de la animación (true: derecha, false: izquierda)
+        char posXF;             // Guarda la posición de la última columna del recuadro de la animación que ha sido pintado
+        
+        // Debug
+        /*unsigned int llamadasTicker;
+        Timer time;*/
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pantallas/OpcionesViaje.cpp	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,47 @@
+/**
+ * @author Juan Manuel Amador Olivares (virtualmech)
+ */
+#include "OpcionesViaje.h"
+
+extern ScreenManager SC;
+extern SistemaArchivos SA;
+extern Teclado keyboard;
+extern GuardarOtroNombre guardadoCorrect;
+extern GuardarOtroNombre guardadoCorrectEN;
+
+extern DigitalOut myled;
+
+void OpcionesViaje::button5pressed(DogMLCD* lcd){
+    bool llamarRaiz = true;     // Se usa para llamar o no a la función padre (para controlar los cambios de pantalla)
+    // Se cambia el idioma actual y se guarda tambien en el fichero de configuracion
+    switch(getSelect()){
+        // Cambiar nombre
+        case 0:
+            guardadoCorrect.setNextScreen("listadoViajes");
+            guardadoCorrectEN.setNextScreen("listadoViajes");
+            guardadoCorrect.setBackScreen("listadoViajes");
+            guardadoCorrectEN.setBackScreen("listadoViajes");
+            guardadoCorrect.setNombreAntiguo(nombreViaje);
+            guardadoCorrectEN.setNombreAntiguo(nombreViaje);
+            keyboard.setBackScreen("rOptions");
+            keyboard.setNextScreen("fileSaved");       
+            break;
+        // Borrar viaje    
+        case 1:
+            llamarRaiz = false;    
+            
+            if(SA.deleteRide(nombreViaje)){  // Si no se pudo borrar se avisa por pantalla de USB 
+                SC.changeScreen("USBdesconectado");
+            }else{
+                SC.changeScreen("archivoBorrado");
+            }
+            break;            
+    }
+    if(llamarRaiz){
+        Menu::button5pressed(lcd);
+    }
+}
+
+void OpcionesViaje::setViaje(char *nombre){
+    nombreViaje = nombre;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pantallas/OpcionesViaje.h	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,27 @@
+/**
+ * @author Juan Manuel Amador Olivares (virtualmech)
+ */
+#ifndef OPCIONESVIAJE_H
+#define OPCIONESVIAJE_H
+
+#include "Menu.h"
+#include "SistemaArchivos.h"
+#include "MSCFileSystem.h"
+#include "ScreenManager.h"
+#include "FechaHora.h"
+#include "Teclado.h"
+#include "GuardarOtroNombre.h"
+
+// Lista de elementos seleccionables. Tamaño de caracteres 8. 
+class OpcionesViaje: public Menu{
+    public:
+    virtual void button5pressed(DogMLCD* lcd);
+    
+    void setViaje(char *nombre);  // Configura el viaje sobre el que actuará este menú
+    
+    private:
+    
+    char *nombreViaje;
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pantallas/Portada.cpp	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,855 @@
+#include "mbed.h"
+#include "ScreenManager.h"
+
+#define ANCHO 128
+#define ALTO 26
+#define XPOS 0
+#define YPOS 11
+
+extern ScreenManager SC;
+
+class Portada : public Screen {
+    
+    public:
+    virtual void initialize(DogMLCD* lcd){
+        
+        lcd->Clear();
+        
+
+        lcd->Poke(XPOS + 122, YPOS);
+        
+        lcd->Poke(XPOS + 121, YPOS + 1);
+        lcd->Poke(XPOS + 122, YPOS + 1);
+        lcd->Poke(XPOS + 123, YPOS + 1);
+        
+        lcd->Poke(XPOS + 121, YPOS + 2);
+        lcd->Poke(XPOS + 122, YPOS + 2);
+        lcd->Poke(XPOS + 123, YPOS + 2);
+        
+        lcd->Poke(XPOS + 121, YPOS + 3);
+        lcd->Poke(XPOS + 122, YPOS + 3);
+        lcd->Poke(XPOS + 123, YPOS + 3);
+        
+        lcd->Poke(XPOS + 121, YPOS + 4);
+        lcd->Poke(XPOS + 122, YPOS + 4);
+        lcd->Poke(XPOS + 123, YPOS + 4);
+        
+        lcd->Poke(XPOS + 120, YPOS + 5);
+        lcd->Poke(XPOS + 121, YPOS + 5);
+        lcd->Poke(XPOS + 122, YPOS + 5);
+        lcd->Poke(XPOS + 123, YPOS + 5);
+        lcd->Poke(XPOS + 124, YPOS + 5);
+        
+        lcd->Poke(XPOS + 117, YPOS + 6);
+        lcd->Poke(XPOS + 118, YPOS + 6);
+        lcd->Poke(XPOS + 119, YPOS + 6);
+        lcd->Poke(XPOS + 120, YPOS + 6);
+        lcd->Poke(XPOS + 121, YPOS + 6);
+        lcd->Poke(XPOS + 122, YPOS + 6);
+        lcd->Poke(XPOS + 123, YPOS + 6);
+        lcd->Poke(XPOS + 124, YPOS + 6);
+        lcd->Poke(XPOS + 125, YPOS + 6);
+        
+        lcd->Poke(XPOS + 116, YPOS + 7);
+        lcd->Poke(XPOS + 117, YPOS + 7);
+        lcd->Poke(XPOS + 118, YPOS + 7);
+        lcd->Poke(XPOS + 119, YPOS + 7);
+        lcd->Poke(XPOS + 120, YPOS + 7);
+        lcd->Poke(XPOS + 121, YPOS + 7);
+        lcd->Poke(XPOS + 122, YPOS + 7);
+        lcd->Poke(XPOS + 123, YPOS + 7);
+        lcd->Poke(XPOS + 124, YPOS + 7);
+        lcd->Poke(XPOS + 125, YPOS + 7);
+        lcd->Poke(XPOS + 126, YPOS + 7);
+        
+        lcd->Poke(XPOS + 13, YPOS + 8);
+        lcd->Poke(XPOS + 14, YPOS + 8);
+        lcd->Poke(XPOS + 110, YPOS + 8);
+        lcd->Poke(XPOS + 111, YPOS + 8);
+        lcd->Poke(XPOS + 116, YPOS + 8);
+        lcd->Poke(XPOS + 117, YPOS + 8);
+        lcd->Poke(XPOS + 118, YPOS + 8);
+        lcd->Poke(XPOS + 119, YPOS + 8);
+        lcd->Poke(XPOS + 120, YPOS + 8);
+        lcd->Poke(XPOS + 121, YPOS + 8);
+        lcd->Poke(XPOS + 123, YPOS + 8);
+        lcd->Poke(XPOS + 124, YPOS + 8);
+        lcd->Poke(XPOS + 125, YPOS + 8);
+        lcd->Poke(XPOS + 126, YPOS + 8);
+        lcd->Poke(XPOS + 127, YPOS + 8);
+        
+        lcd->Poke(XPOS + 12, YPOS + 9);
+        lcd->Poke(XPOS + 13, YPOS + 9);
+        lcd->Poke(XPOS + 14, YPOS + 9);
+        lcd->Poke(XPOS + 15, YPOS + 9);
+        lcd->Poke(XPOS + 29, YPOS + 9);
+        lcd->Poke(XPOS + 61, YPOS + 9);
+        lcd->Poke(XPOS + 62, YPOS + 9);
+        lcd->Poke(XPOS + 109, YPOS + 9);
+        lcd->Poke(XPOS + 110, YPOS + 9);
+        lcd->Poke(XPOS + 111, YPOS + 9);
+        lcd->Poke(XPOS + 117, YPOS + 9);
+        lcd->Poke(XPOS + 118, YPOS + 9);
+        lcd->Poke(XPOS + 119, YPOS + 9);
+        lcd->Poke(XPOS + 124, YPOS + 9);
+        lcd->Poke(XPOS + 125, YPOS + 9);
+        lcd->Poke(XPOS + 126, YPOS + 9);
+        lcd->Poke(XPOS + 127, YPOS + 9);
+        
+        lcd->Poke(XPOS + 12, YPOS + 10);
+        lcd->Poke(XPOS + 13, YPOS + 10);
+        lcd->Poke(XPOS + 14, YPOS + 10);
+        lcd->Poke(XPOS + 15, YPOS + 10);
+        lcd->Poke(XPOS + 28, YPOS + 10);
+        lcd->Poke(XPOS + 29, YPOS + 10);
+        lcd->Poke(XPOS + 61, YPOS + 10);
+        lcd->Poke(XPOS + 62, YPOS + 10);
+        lcd->Poke(XPOS + 109, YPOS + 10);
+        lcd->Poke(XPOS + 110, YPOS + 10);
+        lcd->Poke(XPOS + 111, YPOS + 10);
+        lcd->Poke(XPOS + 125, YPOS + 10);
+        lcd->Poke(XPOS + 126, YPOS + 10);
+        lcd->Poke(XPOS + 127, YPOS + 10);
+        
+        lcd->Poke(XPOS + 13, YPOS + 11);
+        lcd->Poke(XPOS + 14, YPOS + 11);
+        lcd->Poke(XPOS + 28, YPOS + 11);
+        lcd->Poke(XPOS + 29, YPOS + 11);
+        lcd->Poke(XPOS + 61, YPOS + 11);
+        lcd->Poke(XPOS + 62, YPOS + 11);
+        lcd->Poke(XPOS + 109, YPOS + 11);
+        lcd->Poke(XPOS + 110, YPOS + 11);
+        lcd->Poke(XPOS + 111, YPOS + 11);
+        
+        lcd->Poke(XPOS + 28, YPOS + 12);
+        lcd->Poke(XPOS + 29, YPOS + 12);
+        lcd->Poke(XPOS + 61, YPOS + 12);
+        lcd->Poke(XPOS + 62, YPOS + 12);
+        lcd->Poke(XPOS + 109, YPOS + 12);
+        lcd->Poke(XPOS + 110, YPOS + 12);
+        lcd->Poke(XPOS + 111, YPOS + 12);
+        
+        lcd->Poke(XPOS + 1, YPOS + 13);
+        lcd->Poke(XPOS + 9, YPOS + 13);
+        lcd->Poke(XPOS + 13, YPOS + 13);
+        lcd->Poke(XPOS + 14, YPOS + 13);
+        lcd->Poke(XPOS + 17, YPOS + 13);
+        lcd->Poke(XPOS + 18, YPOS + 13);
+        lcd->Poke(XPOS + 21, YPOS + 13);
+        lcd->Poke(XPOS + 22, YPOS + 13);
+        lcd->Poke(XPOS + 23, YPOS + 13);        
+        lcd->Poke(XPOS + 27, YPOS + 13);
+        lcd->Poke(XPOS + 28, YPOS + 13);
+        lcd->Poke(XPOS + 29, YPOS + 13);
+        lcd->Poke(XPOS + 30, YPOS + 13);
+        lcd->Poke(XPOS + 37, YPOS + 13);
+        lcd->Poke(XPOS + 50, YPOS + 13);
+        lcd->Poke(XPOS + 51, YPOS + 13);
+        lcd->Poke(XPOS + 52, YPOS + 13);
+        lcd->Poke(XPOS + 53, YPOS + 13);
+        lcd->Poke(XPOS + 54, YPOS + 13);
+        lcd->Poke(XPOS + 55, YPOS + 13);
+        lcd->Poke(XPOS + 56, YPOS + 13);
+        lcd->Poke(XPOS + 61, YPOS + 13);
+        lcd->Poke(XPOS + 62, YPOS + 13);
+        lcd->Poke(XPOS + 66, YPOS + 13);
+        lcd->Poke(XPOS + 70, YPOS + 13);
+        lcd->Poke(XPOS + 71, YPOS + 13);
+        lcd->Poke(XPOS + 72, YPOS + 13);
+        lcd->Poke(XPOS + 77, YPOS + 13);
+        lcd->Poke(XPOS + 78, YPOS + 13);
+        lcd->Poke(XPOS + 79, YPOS + 13);
+        lcd->Poke(XPOS + 87, YPOS + 13);
+        lcd->Poke(XPOS + 88, YPOS + 13);
+        lcd->Poke(XPOS + 90, YPOS + 13);
+        lcd->Poke(XPOS + 91, YPOS + 13);
+        lcd->Poke(XPOS + 100, YPOS + 13);
+        lcd->Poke(XPOS + 101, YPOS + 13);
+        lcd->Poke(XPOS + 102, YPOS + 13);
+        lcd->Poke(XPOS + 103, YPOS + 13);
+        lcd->Poke(XPOS + 109, YPOS + 13);
+        lcd->Poke(XPOS + 110, YPOS + 13);
+        lcd->Poke(XPOS + 111, YPOS + 13);
+        lcd->Poke(XPOS + 114, YPOS + 13);
+        lcd->Poke(XPOS + 115, YPOS + 13);
+        lcd->Poke(XPOS + 116, YPOS + 13);
+        lcd->Poke(XPOS + 117, YPOS + 13);
+        
+        lcd->Poke(XPOS + 0, YPOS + 14);
+        lcd->Poke(XPOS + 1, YPOS + 14);
+        lcd->Poke(XPOS + 2, YPOS + 14);
+        lcd->Poke(XPOS + 8, YPOS + 14);
+        lcd->Poke(XPOS + 9, YPOS + 14);
+        lcd->Poke(XPOS + 10, YPOS + 14);
+        lcd->Poke(XPOS + 13, YPOS + 14);
+        lcd->Poke(XPOS + 14, YPOS + 14);
+        lcd->Poke(XPOS + 17, YPOS + 14);
+        lcd->Poke(XPOS + 18, YPOS + 14);
+        lcd->Poke(XPOS + 19, YPOS + 14);
+        lcd->Poke(XPOS + 20, YPOS + 14);
+        lcd->Poke(XPOS + 21, YPOS + 14);
+        lcd->Poke(XPOS + 22, YPOS + 14);
+        lcd->Poke(XPOS + 23, YPOS + 14);
+        lcd->Poke(XPOS + 24, YPOS + 14);
+        lcd->Poke(XPOS + 26, YPOS + 14);
+        lcd->Poke(XPOS + 27, YPOS + 14);
+        lcd->Poke(XPOS + 28, YPOS + 14);
+        lcd->Poke(XPOS + 29, YPOS + 14);
+        lcd->Poke(XPOS + 30, YPOS + 14);
+        lcd->Poke(XPOS + 31, YPOS + 14);
+        lcd->Poke(XPOS + 32, YPOS + 14);
+        lcd->Poke(XPOS + 36, YPOS + 14);
+        lcd->Poke(XPOS + 37, YPOS + 14);
+        lcd->Poke(XPOS + 38, YPOS + 14);
+        lcd->Poke(XPOS + 44, YPOS + 14);
+        lcd->Poke(XPOS + 45, YPOS + 14);
+        lcd->Poke(XPOS + 49, YPOS + 14);
+        lcd->Poke(XPOS + 50, YPOS + 14);
+        lcd->Poke(XPOS + 51, YPOS + 14);
+        lcd->Poke(XPOS + 52, YPOS + 14);
+        lcd->Poke(XPOS + 53, YPOS + 14);
+        lcd->Poke(XPOS + 54, YPOS + 14);
+        lcd->Poke(XPOS + 55, YPOS + 14);
+        lcd->Poke(XPOS + 56, YPOS + 14);
+        lcd->Poke(XPOS + 57, YPOS + 14);
+        lcd->Poke(XPOS + 61, YPOS + 14);
+        lcd->Poke(XPOS + 62, YPOS + 14);
+        lcd->Poke(XPOS + 65, YPOS + 14);
+        lcd->Poke(XPOS + 66, YPOS + 14);
+        lcd->Poke(XPOS + 67, YPOS + 14);
+        lcd->Poke(XPOS + 69, YPOS + 14);
+        lcd->Poke(XPOS + 70, YPOS + 14);
+        lcd->Poke(XPOS + 71, YPOS + 14);
+        lcd->Poke(XPOS + 72, YPOS + 14);
+        lcd->Poke(XPOS + 73, YPOS + 14);
+        lcd->Poke(XPOS + 76, YPOS + 14);
+        lcd->Poke(XPOS + 77, YPOS + 14);
+        lcd->Poke(XPOS + 78, YPOS + 14);
+        lcd->Poke(XPOS + 79, YPOS + 14);
+        lcd->Poke(XPOS + 80, YPOS + 14);
+        lcd->Poke(XPOS + 86, YPOS + 14);
+        lcd->Poke(XPOS + 87, YPOS + 14);
+        lcd->Poke(XPOS + 88, YPOS + 14);
+        lcd->Poke(XPOS + 90, YPOS + 14);
+        lcd->Poke(XPOS + 91, YPOS + 14);
+        lcd->Poke(XPOS + 92, YPOS + 14);        
+        lcd->Poke(XPOS + 99, YPOS + 14);
+        lcd->Poke(XPOS + 100, YPOS + 14);
+        lcd->Poke(XPOS + 101, YPOS + 14);
+        lcd->Poke(XPOS + 102, YPOS + 14);
+        lcd->Poke(XPOS + 103, YPOS + 14);
+        lcd->Poke(XPOS + 104, YPOS + 14);
+        lcd->Poke(XPOS + 105, YPOS + 14);        
+        lcd->Poke(XPOS + 109, YPOS + 14);
+        lcd->Poke(XPOS + 110, YPOS + 14);
+        lcd->Poke(XPOS + 111, YPOS + 14);        
+        lcd->Poke(XPOS + 113, YPOS + 14);
+        lcd->Poke(XPOS + 114, YPOS + 14);
+        lcd->Poke(XPOS + 115, YPOS + 14);
+        lcd->Poke(XPOS + 116, YPOS + 14);
+        lcd->Poke(XPOS + 117, YPOS + 14);
+        lcd->Poke(XPOS + 118, YPOS + 14);
+        
+        lcd->Poke(XPOS + 0, YPOS + 15);
+        lcd->Poke(XPOS + 1, YPOS + 15);
+        lcd->Poke(XPOS + 2, YPOS + 15);
+        lcd->Poke(XPOS + 8, YPOS + 15);
+        lcd->Poke(XPOS + 9, YPOS + 15);
+        lcd->Poke(XPOS + 10, YPOS + 15);
+        lcd->Poke(XPOS + 13, YPOS + 15);
+        lcd->Poke(XPOS + 14, YPOS + 15);
+        lcd->Poke(XPOS + 17, YPOS + 15);
+        lcd->Poke(XPOS + 18, YPOS + 15);
+        lcd->Poke(XPOS + 19, YPOS + 15);
+        lcd->Poke(XPOS + 20, YPOS + 15);
+        lcd->Poke(XPOS + 21, YPOS + 15);
+        lcd->Poke(XPOS + 22, YPOS + 15);
+        lcd->Poke(XPOS + 23, YPOS + 15);
+        lcd->Poke(XPOS + 24, YPOS + 15);
+        lcd->Poke(XPOS + 27, YPOS + 15);
+        lcd->Poke(XPOS + 28, YPOS + 15);
+        lcd->Poke(XPOS + 29, YPOS + 15);
+        lcd->Poke(XPOS + 30, YPOS + 15);
+        lcd->Poke(XPOS + 36, YPOS + 15);
+        lcd->Poke(XPOS + 37, YPOS + 15);
+        lcd->Poke(XPOS + 38, YPOS + 15);
+        lcd->Poke(XPOS + 44, YPOS + 15);
+        lcd->Poke(XPOS + 45, YPOS + 15);
+        lcd->Poke(XPOS + 48, YPOS + 15);
+        lcd->Poke(XPOS + 49, YPOS + 15);
+        lcd->Poke(XPOS + 50, YPOS + 15);
+        lcd->Poke(XPOS + 51, YPOS + 15);
+        lcd->Poke(XPOS + 52, YPOS + 15);
+        lcd->Poke(XPOS + 54, YPOS + 15);
+        lcd->Poke(XPOS + 55, YPOS + 15);
+        lcd->Poke(XPOS + 56, YPOS + 15);
+        lcd->Poke(XPOS + 57, YPOS + 15);
+        lcd->Poke(XPOS + 58, YPOS + 15);
+        lcd->Poke(XPOS + 61, YPOS + 15);
+        lcd->Poke(XPOS + 62, YPOS + 15);
+        lcd->Poke(XPOS + 65, YPOS + 15);
+        lcd->Poke(XPOS + 66, YPOS + 15);
+        lcd->Poke(XPOS + 67, YPOS + 15);
+        lcd->Poke(XPOS + 68, YPOS + 15);
+        lcd->Poke(XPOS + 69, YPOS + 15);
+        lcd->Poke(XPOS + 70, YPOS + 15);
+        lcd->Poke(XPOS + 71, YPOS + 15);
+        lcd->Poke(XPOS + 72, YPOS + 15);
+        lcd->Poke(XPOS + 73, YPOS + 15);
+        lcd->Poke(XPOS + 74, YPOS + 15);
+        lcd->Poke(XPOS + 75, YPOS + 15);
+        lcd->Poke(XPOS + 76, YPOS + 15);
+        lcd->Poke(XPOS + 77, YPOS + 15);
+        lcd->Poke(XPOS + 78, YPOS + 15);
+        lcd->Poke(XPOS + 79, YPOS + 15);
+        lcd->Poke(XPOS + 80, YPOS + 15);
+        lcd->Poke(XPOS + 81, YPOS + 15);
+        lcd->Poke(XPOS + 85, YPOS + 15);
+        lcd->Poke(XPOS + 86, YPOS + 15);
+        lcd->Poke(XPOS + 87, YPOS + 15);
+        lcd->Poke(XPOS + 88, YPOS + 15);
+        lcd->Poke(XPOS + 90, YPOS + 15);
+        lcd->Poke(XPOS + 91, YPOS + 15);
+        lcd->Poke(XPOS + 92, YPOS + 15);     
+        lcd->Poke(XPOS + 93, YPOS + 15);
+        lcd->Poke(XPOS + 98, YPOS + 15);
+        lcd->Poke(XPOS + 99, YPOS + 15);
+        lcd->Poke(XPOS + 100, YPOS + 15);
+        lcd->Poke(XPOS + 104, YPOS + 15);
+        lcd->Poke(XPOS + 105, YPOS + 15);
+        lcd->Poke(XPOS + 106, YPOS + 15);         
+        lcd->Poke(XPOS + 109, YPOS + 15);
+        lcd->Poke(XPOS + 110, YPOS + 15);
+        lcd->Poke(XPOS + 111, YPOS + 15);   
+        lcd->Poke(XPOS + 112, YPOS + 15);      
+        lcd->Poke(XPOS + 113, YPOS + 15);
+        lcd->Poke(XPOS + 114, YPOS + 15);
+        lcd->Poke(XPOS + 115, YPOS + 15);
+        lcd->Poke(XPOS + 116, YPOS + 15);
+        lcd->Poke(XPOS + 117, YPOS + 15);
+        lcd->Poke(XPOS + 118, YPOS + 15);
+        lcd->Poke(XPOS + 119, YPOS + 15);
+        
+        lcd->Poke(XPOS + 1, YPOS + 16);
+        lcd->Poke(XPOS + 2, YPOS + 16);
+        lcd->Poke(XPOS + 8, YPOS + 16);
+        lcd->Poke(XPOS + 9, YPOS + 16);
+        lcd->Poke(XPOS + 13, YPOS + 16);
+        lcd->Poke(XPOS + 14, YPOS + 16);
+        lcd->Poke(XPOS + 17, YPOS + 16);
+        lcd->Poke(XPOS + 18, YPOS + 16);
+        lcd->Poke(XPOS + 19, YPOS + 16);
+        lcd->Poke(XPOS + 20, YPOS + 16);
+        lcd->Poke(XPOS + 23, YPOS + 16);
+        lcd->Poke(XPOS + 28, YPOS + 16);
+        lcd->Poke(XPOS + 29, YPOS + 16);
+        lcd->Poke(XPOS + 36, YPOS + 16);
+        lcd->Poke(XPOS + 37, YPOS + 16);
+        lcd->Poke(XPOS + 38, YPOS + 16);
+        lcd->Poke(XPOS + 44, YPOS + 16);
+        lcd->Poke(XPOS + 45, YPOS + 16);
+        lcd->Poke(XPOS + 48, YPOS + 16);
+        lcd->Poke(XPOS + 49, YPOS + 16);
+        lcd->Poke(XPOS + 50, YPOS + 16);
+        lcd->Poke(XPOS + 55, YPOS + 16);
+        lcd->Poke(XPOS + 56, YPOS + 16);
+        lcd->Poke(XPOS + 57, YPOS + 16);
+        lcd->Poke(XPOS + 58, YPOS + 16);
+        lcd->Poke(XPOS + 61, YPOS + 16);
+        lcd->Poke(XPOS + 62, YPOS + 16);
+        lcd->Poke(XPOS + 65, YPOS + 16);
+        lcd->Poke(XPOS + 66, YPOS + 16);
+        lcd->Poke(XPOS + 67, YPOS + 16);
+        lcd->Poke(XPOS + 68, YPOS + 16);
+        lcd->Poke(XPOS + 72, YPOS + 16);
+        lcd->Poke(XPOS + 73, YPOS + 16);
+        lcd->Poke(XPOS + 74, YPOS + 16);
+        lcd->Poke(XPOS + 75, YPOS + 16);
+        lcd->Poke(XPOS + 79, YPOS + 16);
+        lcd->Poke(XPOS + 80, YPOS + 16);
+        lcd->Poke(XPOS + 81, YPOS + 16);
+        lcd->Poke(XPOS + 84, YPOS + 16);
+        lcd->Poke(XPOS + 85, YPOS + 16);
+        lcd->Poke(XPOS + 86, YPOS + 16);
+        lcd->Poke(XPOS + 87, YPOS + 16);
+        lcd->Poke(XPOS + 91, YPOS + 16);
+        lcd->Poke(XPOS + 92, YPOS + 16);     
+        lcd->Poke(XPOS + 93, YPOS + 16);
+        lcd->Poke(XPOS + 97, YPOS + 16);
+        lcd->Poke(XPOS + 98, YPOS + 16);
+        lcd->Poke(XPOS + 99, YPOS + 16);
+        lcd->Poke(XPOS + 105, YPOS + 16);
+        lcd->Poke(XPOS + 106, YPOS + 16);         
+        lcd->Poke(XPOS + 109, YPOS + 16);
+        lcd->Poke(XPOS + 110, YPOS + 16);
+        lcd->Poke(XPOS + 111, YPOS + 16);   
+        lcd->Poke(XPOS + 112, YPOS + 16);      
+        lcd->Poke(XPOS + 113, YPOS + 16);
+        lcd->Poke(XPOS + 116, YPOS + 16);
+        lcd->Poke(XPOS + 117, YPOS + 16);
+        lcd->Poke(XPOS + 118, YPOS + 16);
+        lcd->Poke(XPOS + 119, YPOS + 16);
+        
+        lcd->Poke(XPOS + 1, YPOS + 17);
+        lcd->Poke(XPOS + 2, YPOS + 17);
+        lcd->Poke(XPOS + 3, YPOS + 17);
+        lcd->Poke(XPOS + 7, YPOS + 17);
+        lcd->Poke(XPOS + 8, YPOS + 17);
+        lcd->Poke(XPOS + 9, YPOS + 17);
+        lcd->Poke(XPOS + 13, YPOS + 17);
+        lcd->Poke(XPOS + 14, YPOS + 17);
+        lcd->Poke(XPOS + 17, YPOS + 17);
+        lcd->Poke(XPOS + 18, YPOS + 17);
+        lcd->Poke(XPOS + 19, YPOS + 17);
+        lcd->Poke(XPOS + 28, YPOS + 17);
+        lcd->Poke(XPOS + 29, YPOS + 17);
+        lcd->Poke(XPOS + 36, YPOS + 17);
+        lcd->Poke(XPOS + 37, YPOS + 17);
+        lcd->Poke(XPOS + 38, YPOS + 17);
+        lcd->Poke(XPOS + 44, YPOS + 17);
+        lcd->Poke(XPOS + 45, YPOS + 17);
+        lcd->Poke(XPOS + 49, YPOS + 17);
+        lcd->Poke(XPOS + 55, YPOS + 17);
+        lcd->Poke(XPOS + 56, YPOS + 17);
+        lcd->Poke(XPOS + 57, YPOS + 17);
+        lcd->Poke(XPOS + 58, YPOS + 17);
+        lcd->Poke(XPOS + 61, YPOS + 17);
+        lcd->Poke(XPOS + 62, YPOS + 17);
+        lcd->Poke(XPOS + 65, YPOS + 17);
+        lcd->Poke(XPOS + 66, YPOS + 17);
+        lcd->Poke(XPOS + 67, YPOS + 17);
+        lcd->Poke(XPOS + 72, YPOS + 17);
+        lcd->Poke(XPOS + 73, YPOS + 17);
+        lcd->Poke(XPOS + 74, YPOS + 17);
+        lcd->Poke(XPOS + 79, YPOS + 17);
+        lcd->Poke(XPOS + 80, YPOS + 17);
+        lcd->Poke(XPOS + 81, YPOS + 17);
+        lcd->Poke(XPOS + 84, YPOS + 17);
+        lcd->Poke(XPOS + 85, YPOS + 17);
+        lcd->Poke(XPOS + 86, YPOS + 17);
+        lcd->Poke(XPOS + 92, YPOS + 17);     
+        lcd->Poke(XPOS + 93, YPOS + 17);
+        lcd->Poke(XPOS + 94, YPOS + 17);
+        lcd->Poke(XPOS + 97, YPOS + 17);
+        lcd->Poke(XPOS + 98, YPOS + 17);
+        lcd->Poke(XPOS + 105, YPOS + 17);
+        lcd->Poke(XPOS + 106, YPOS + 17);         
+        lcd->Poke(XPOS + 109, YPOS + 17);
+        lcd->Poke(XPOS + 110, YPOS + 17);
+        lcd->Poke(XPOS + 111, YPOS + 17);   
+        lcd->Poke(XPOS + 112, YPOS + 17);      
+        lcd->Poke(XPOS + 117, YPOS + 17);
+        lcd->Poke(XPOS + 118, YPOS + 17);
+        lcd->Poke(XPOS + 119, YPOS + 17);
+        
+        lcd->Poke(XPOS + 2, YPOS + 18);
+        lcd->Poke(XPOS + 3, YPOS + 18);
+        lcd->Poke(XPOS + 7, YPOS + 18);
+        lcd->Poke(XPOS + 8, YPOS + 18);
+        lcd->Poke(XPOS + 13, YPOS + 18);
+        lcd->Poke(XPOS + 14, YPOS + 18);
+        lcd->Poke(XPOS + 17, YPOS + 18);
+        lcd->Poke(XPOS + 18, YPOS + 18);
+        lcd->Poke(XPOS + 19, YPOS + 18);
+        lcd->Poke(XPOS + 28, YPOS + 18);
+        lcd->Poke(XPOS + 29, YPOS + 18);
+        lcd->Poke(XPOS + 36, YPOS + 18);
+        lcd->Poke(XPOS + 37, YPOS + 18);
+        lcd->Poke(XPOS + 38, YPOS + 18);
+        lcd->Poke(XPOS + 44, YPOS + 18);
+        lcd->Poke(XPOS + 45, YPOS + 18);
+        lcd->Poke(XPOS + 55, YPOS + 18);
+        lcd->Poke(XPOS + 56, YPOS + 18);
+        lcd->Poke(XPOS + 57, YPOS + 18);
+        lcd->Poke(XPOS + 58, YPOS + 18);
+        lcd->Poke(XPOS + 61, YPOS + 18);
+        lcd->Poke(XPOS + 62, YPOS + 18);
+        lcd->Poke(XPOS + 65, YPOS + 18);
+        lcd->Poke(XPOS + 66, YPOS + 18);
+        lcd->Poke(XPOS + 67, YPOS + 18);
+        lcd->Poke(XPOS + 72, YPOS + 18);
+        lcd->Poke(XPOS + 73, YPOS + 18);
+        lcd->Poke(XPOS + 74, YPOS + 18);
+        lcd->Poke(XPOS + 79, YPOS + 18);
+        lcd->Poke(XPOS + 80, YPOS + 18);
+        lcd->Poke(XPOS + 81, YPOS + 18);
+        lcd->Poke(XPOS + 84, YPOS + 18);
+        lcd->Poke(XPOS + 85, YPOS + 18);
+        lcd->Poke(XPOS + 86, YPOS + 18);
+        lcd->Poke(XPOS + 92, YPOS + 18);     
+        lcd->Poke(XPOS + 93, YPOS + 18);
+        lcd->Poke(XPOS + 94, YPOS + 18);
+        lcd->Poke(XPOS + 97, YPOS + 18);
+        lcd->Poke(XPOS + 98, YPOS + 18);        
+        lcd->Poke(XPOS + 109, YPOS + 18);
+        lcd->Poke(XPOS + 110, YPOS + 18);
+        lcd->Poke(XPOS + 111, YPOS + 18);       
+        lcd->Poke(XPOS + 117, YPOS + 18);
+        lcd->Poke(XPOS + 118, YPOS + 18);
+        lcd->Poke(XPOS + 119, YPOS + 18);
+        
+        lcd->Poke(XPOS + 2, YPOS + 19);
+        lcd->Poke(XPOS + 3, YPOS + 19);
+        lcd->Poke(XPOS + 7, YPOS + 19);
+        lcd->Poke(XPOS + 8, YPOS + 19);
+        lcd->Poke(XPOS + 13, YPOS + 19);
+        lcd->Poke(XPOS + 14, YPOS + 19);
+        lcd->Poke(XPOS + 17, YPOS + 19);
+        lcd->Poke(XPOS + 18, YPOS + 19);
+        lcd->Poke(XPOS + 19, YPOS + 19);
+        lcd->Poke(XPOS + 28, YPOS + 19);
+        lcd->Poke(XPOS + 29, YPOS + 19);
+        lcd->Poke(XPOS + 36, YPOS + 19);
+        lcd->Poke(XPOS + 37, YPOS + 19);
+        lcd->Poke(XPOS + 38, YPOS + 19);
+        lcd->Poke(XPOS + 44, YPOS + 19);
+        lcd->Poke(XPOS + 45, YPOS + 19);
+        lcd->Poke(XPOS + 50, YPOS + 19);
+        lcd->Poke(XPOS + 51, YPOS + 19);
+        lcd->Poke(XPOS + 54, YPOS + 19);
+        lcd->Poke(XPOS + 55, YPOS + 19);
+        lcd->Poke(XPOS + 56, YPOS + 19);
+        lcd->Poke(XPOS + 57, YPOS + 19);
+        lcd->Poke(XPOS + 58, YPOS + 19);
+        lcd->Poke(XPOS + 61, YPOS + 19);
+        lcd->Poke(XPOS + 62, YPOS + 19);
+        lcd->Poke(XPOS + 65, YPOS + 19);
+        lcd->Poke(XPOS + 66, YPOS + 19);
+        lcd->Poke(XPOS + 67, YPOS + 19);
+        lcd->Poke(XPOS + 72, YPOS + 19);
+        lcd->Poke(XPOS + 73, YPOS + 19);
+        lcd->Poke(XPOS + 74, YPOS + 19);
+        lcd->Poke(XPOS + 79, YPOS + 19);
+        lcd->Poke(XPOS + 80, YPOS + 19);
+        lcd->Poke(XPOS + 81, YPOS + 19);
+        lcd->Poke(XPOS + 84, YPOS + 19);
+        lcd->Poke(XPOS + 85, YPOS + 19);
+        lcd->Poke(XPOS + 86, YPOS + 19);
+        lcd->Poke(XPOS + 87, YPOS + 19);
+        lcd->Poke(XPOS + 88, YPOS + 19);
+        lcd->Poke(XPOS + 90, YPOS + 19);
+        lcd->Poke(XPOS + 91, YPOS + 19);
+        lcd->Poke(XPOS + 92, YPOS + 19);     
+        lcd->Poke(XPOS + 93, YPOS + 19);
+        lcd->Poke(XPOS + 97, YPOS + 19);
+        lcd->Poke(XPOS + 98, YPOS + 19);        
+        lcd->Poke(XPOS + 109, YPOS + 19);
+        lcd->Poke(XPOS + 110, YPOS + 19);
+        lcd->Poke(XPOS + 111, YPOS + 19);       
+        lcd->Poke(XPOS + 117, YPOS + 19);
+        lcd->Poke(XPOS + 118, YPOS + 19);
+        lcd->Poke(XPOS + 119, YPOS + 19);
+        
+        lcd->Poke(XPOS + 2, YPOS + 20);
+        lcd->Poke(XPOS + 3, YPOS + 20);
+        lcd->Poke(XPOS + 7, YPOS + 20);
+        lcd->Poke(XPOS + 8, YPOS + 20);
+        lcd->Poke(XPOS + 13, YPOS + 20);
+        lcd->Poke(XPOS + 14, YPOS + 20);
+        lcd->Poke(XPOS + 17, YPOS + 20);
+        lcd->Poke(XPOS + 18, YPOS + 20);
+        lcd->Poke(XPOS + 19, YPOS + 20);
+        lcd->Poke(XPOS + 28, YPOS + 20);
+        lcd->Poke(XPOS + 29, YPOS + 20);
+        lcd->Poke(XPOS + 36, YPOS + 20);
+        lcd->Poke(XPOS + 37, YPOS + 20);
+        lcd->Poke(XPOS + 38, YPOS + 20);
+        lcd->Poke(XPOS + 44, YPOS + 20);
+        lcd->Poke(XPOS + 45, YPOS + 20);
+        lcd->Poke(XPOS + 49, YPOS + 20);
+        lcd->Poke(XPOS + 50, YPOS + 20);
+        lcd->Poke(XPOS + 51, YPOS + 20);
+        lcd->Poke(XPOS + 56, YPOS + 20);
+        lcd->Poke(XPOS + 57, YPOS + 20);
+        lcd->Poke(XPOS + 58, YPOS + 20);
+        lcd->Poke(XPOS + 61, YPOS + 20);
+        lcd->Poke(XPOS + 62, YPOS + 20);
+        lcd->Poke(XPOS + 65, YPOS + 20);
+        lcd->Poke(XPOS + 66, YPOS + 20);
+        lcd->Poke(XPOS + 67, YPOS + 20);
+        lcd->Poke(XPOS + 72, YPOS + 20);
+        lcd->Poke(XPOS + 73, YPOS + 20);
+        lcd->Poke(XPOS + 74, YPOS + 20);
+        lcd->Poke(XPOS + 79, YPOS + 20);
+        lcd->Poke(XPOS + 80, YPOS + 20);
+        lcd->Poke(XPOS + 81, YPOS + 20);
+        lcd->Poke(XPOS + 84, YPOS + 20);
+        lcd->Poke(XPOS + 85, YPOS + 20);
+        lcd->Poke(XPOS + 86, YPOS + 20);
+        lcd->Poke(XPOS + 97, YPOS + 20);
+        lcd->Poke(XPOS + 98, YPOS + 20);        
+        lcd->Poke(XPOS + 109, YPOS + 20);
+        lcd->Poke(XPOS + 110, YPOS + 20);
+        lcd->Poke(XPOS + 111, YPOS + 20);       
+        lcd->Poke(XPOS + 117, YPOS + 20);
+        lcd->Poke(XPOS + 118, YPOS + 20);
+        lcd->Poke(XPOS + 119, YPOS + 20);
+        
+        lcd->Poke(XPOS + 3, YPOS + 21);
+        lcd->Poke(XPOS + 4, YPOS + 21);
+        lcd->Poke(XPOS + 6, YPOS + 21);
+        lcd->Poke(XPOS + 7, YPOS + 21);
+        lcd->Poke(XPOS + 13, YPOS + 21);
+        lcd->Poke(XPOS + 14, YPOS + 21);
+        lcd->Poke(XPOS + 17, YPOS + 21);
+        lcd->Poke(XPOS + 18, YPOS + 21);
+        lcd->Poke(XPOS + 19, YPOS + 21);
+        lcd->Poke(XPOS + 28, YPOS + 21);
+        lcd->Poke(XPOS + 29, YPOS + 21);
+        lcd->Poke(XPOS + 36, YPOS + 21);
+        lcd->Poke(XPOS + 37, YPOS + 21);
+        lcd->Poke(XPOS + 38, YPOS + 21);
+        lcd->Poke(XPOS + 44, YPOS + 21);
+        lcd->Poke(XPOS + 45, YPOS + 21);
+        lcd->Poke(XPOS + 48, YPOS + 21);
+        lcd->Poke(XPOS + 49, YPOS + 21);
+        lcd->Poke(XPOS + 50, YPOS + 21);
+        lcd->Poke(XPOS + 56, YPOS + 21);
+        lcd->Poke(XPOS + 57, YPOS + 21);
+        lcd->Poke(XPOS + 58, YPOS + 21);
+        lcd->Poke(XPOS + 61, YPOS + 21);
+        lcd->Poke(XPOS + 62, YPOS + 21);
+        lcd->Poke(XPOS + 65, YPOS + 21);
+        lcd->Poke(XPOS + 66, YPOS + 21);
+        lcd->Poke(XPOS + 67, YPOS + 21);
+        lcd->Poke(XPOS + 72, YPOS + 21);
+        lcd->Poke(XPOS + 73, YPOS + 21);
+        lcd->Poke(XPOS + 74, YPOS + 21);
+        lcd->Poke(XPOS + 79, YPOS + 21);
+        lcd->Poke(XPOS + 80, YPOS + 21);
+        lcd->Poke(XPOS + 81, YPOS + 21);
+        lcd->Poke(XPOS + 84, YPOS + 21);
+        lcd->Poke(XPOS + 85, YPOS + 21);
+        lcd->Poke(XPOS + 86, YPOS + 21);
+        lcd->Poke(XPOS + 97, YPOS + 21);
+        lcd->Poke(XPOS + 98, YPOS + 21);        
+        lcd->Poke(XPOS + 99, YPOS + 21);
+        lcd->Poke(XPOS + 106, YPOS + 21);
+        lcd->Poke(XPOS + 109, YPOS + 21);
+        lcd->Poke(XPOS + 110, YPOS + 21);
+        lcd->Poke(XPOS + 111, YPOS + 21);       
+        lcd->Poke(XPOS + 117, YPOS + 21);
+        lcd->Poke(XPOS + 118, YPOS + 21);
+        lcd->Poke(XPOS + 119, YPOS + 21);
+        
+        lcd->Poke(XPOS + 3, YPOS + 22);
+        lcd->Poke(XPOS + 4, YPOS + 22);
+        lcd->Poke(XPOS + 5, YPOS + 22);
+        lcd->Poke(XPOS + 6, YPOS + 22);
+        lcd->Poke(XPOS + 7, YPOS + 22);
+        lcd->Poke(XPOS + 13, YPOS + 22);
+        lcd->Poke(XPOS + 14, YPOS + 22);
+        lcd->Poke(XPOS + 17, YPOS + 22);
+        lcd->Poke(XPOS + 18, YPOS + 22);
+        lcd->Poke(XPOS + 19, YPOS + 22);
+        lcd->Poke(XPOS + 28, YPOS + 22);
+        lcd->Poke(XPOS + 29, YPOS + 22);
+        lcd->Poke(XPOS + 36, YPOS + 22);
+        lcd->Poke(XPOS + 37, YPOS + 22);
+        lcd->Poke(XPOS + 38, YPOS + 22);
+        lcd->Poke(XPOS + 43, YPOS + 22);
+        lcd->Poke(XPOS + 44, YPOS + 22);
+        lcd->Poke(XPOS + 45, YPOS + 22);
+        lcd->Poke(XPOS + 48, YPOS + 22);
+        lcd->Poke(XPOS + 49, YPOS + 22);
+        lcd->Poke(XPOS + 50, YPOS + 22);
+        lcd->Poke(XPOS + 55, YPOS + 22);
+        lcd->Poke(XPOS + 56, YPOS + 22);
+        lcd->Poke(XPOS + 57, YPOS + 22);
+        lcd->Poke(XPOS + 58, YPOS + 22);
+        lcd->Poke(XPOS + 61, YPOS + 22);
+        lcd->Poke(XPOS + 62, YPOS + 22);
+        lcd->Poke(XPOS + 65, YPOS + 22);
+        lcd->Poke(XPOS + 66, YPOS + 22);
+        lcd->Poke(XPOS + 67, YPOS + 22);
+        lcd->Poke(XPOS + 72, YPOS + 22);
+        lcd->Poke(XPOS + 73, YPOS + 22);
+        lcd->Poke(XPOS + 74, YPOS + 22);
+        lcd->Poke(XPOS + 79, YPOS + 22);
+        lcd->Poke(XPOS + 80, YPOS + 22);
+        lcd->Poke(XPOS + 81, YPOS + 22);
+        lcd->Poke(XPOS + 84, YPOS + 22);
+        lcd->Poke(XPOS + 85, YPOS + 22);
+        lcd->Poke(XPOS + 86, YPOS + 22);
+        lcd->Poke(XPOS + 93, YPOS + 22);
+        lcd->Poke(XPOS + 94, YPOS + 22);
+        lcd->Poke(XPOS + 97, YPOS + 22);
+        lcd->Poke(XPOS + 98, YPOS + 22);        
+        lcd->Poke(XPOS + 99, YPOS + 22);
+        lcd->Poke(XPOS + 105, YPOS + 22);
+        lcd->Poke(XPOS + 106, YPOS + 22);
+        lcd->Poke(XPOS + 107, YPOS + 22);
+        lcd->Poke(XPOS + 109, YPOS + 22);
+        lcd->Poke(XPOS + 110, YPOS + 22);
+        lcd->Poke(XPOS + 111, YPOS + 22);       
+        lcd->Poke(XPOS + 117, YPOS + 22);
+        lcd->Poke(XPOS + 118, YPOS + 22);
+        lcd->Poke(XPOS + 119, YPOS + 22);
+        
+        lcd->Poke(XPOS + 4, YPOS + 23);
+        lcd->Poke(XPOS + 5, YPOS + 23);
+        lcd->Poke(XPOS + 6, YPOS + 23);
+        lcd->Poke(XPOS + 13, YPOS + 23);
+        lcd->Poke(XPOS + 14, YPOS + 23);
+        lcd->Poke(XPOS + 17, YPOS + 23);
+        lcd->Poke(XPOS + 18, YPOS + 23);
+        lcd->Poke(XPOS + 19, YPOS + 23);
+        lcd->Poke(XPOS + 28, YPOS + 23);
+        lcd->Poke(XPOS + 29, YPOS + 23);
+        lcd->Poke(XPOS + 36, YPOS + 23);
+        lcd->Poke(XPOS + 37, YPOS + 23);
+        lcd->Poke(XPOS + 38, YPOS + 23);
+        lcd->Poke(XPOS + 39, YPOS + 23);
+        lcd->Poke(XPOS + 42, YPOS + 23);
+        lcd->Poke(XPOS + 43, YPOS + 23);
+        lcd->Poke(XPOS + 44, YPOS + 23);
+        lcd->Poke(XPOS + 45, YPOS + 23);
+        lcd->Poke(XPOS + 48, YPOS + 23);
+        lcd->Poke(XPOS + 49, YPOS + 23);
+        lcd->Poke(XPOS + 50, YPOS + 23);
+        lcd->Poke(XPOS + 54, YPOS + 23);
+        lcd->Poke(XPOS + 55, YPOS + 23);
+        lcd->Poke(XPOS + 56, YPOS + 23);
+        lcd->Poke(XPOS + 57, YPOS + 23);
+        lcd->Poke(XPOS + 58, YPOS + 23);
+        lcd->Poke(XPOS + 61, YPOS + 23);
+        lcd->Poke(XPOS + 62, YPOS + 23);
+        lcd->Poke(XPOS + 65, YPOS + 23);
+        lcd->Poke(XPOS + 66, YPOS + 23);
+        lcd->Poke(XPOS + 67, YPOS + 23);
+        lcd->Poke(XPOS + 72, YPOS + 23);
+        lcd->Poke(XPOS + 73, YPOS + 23);
+        lcd->Poke(XPOS + 74, YPOS + 23);
+        lcd->Poke(XPOS + 79, YPOS + 23);
+        lcd->Poke(XPOS + 80, YPOS + 23);
+        lcd->Poke(XPOS + 81, YPOS + 23);
+        lcd->Poke(XPOS + 85, YPOS + 23);
+        lcd->Poke(XPOS + 86, YPOS + 23);
+        lcd->Poke(XPOS + 87, YPOS + 23);
+        lcd->Poke(XPOS + 92, YPOS + 23);
+        lcd->Poke(XPOS + 93, YPOS + 23);
+        lcd->Poke(XPOS + 94, YPOS + 23);
+        lcd->Poke(XPOS + 98, YPOS + 23);
+        lcd->Poke(XPOS + 99, YPOS + 23);        
+        lcd->Poke(XPOS + 100, YPOS + 23);
+        lcd->Poke(XPOS + 104, YPOS + 23);
+        lcd->Poke(XPOS + 105, YPOS + 23);
+        lcd->Poke(XPOS + 106, YPOS + 23);
+        lcd->Poke(XPOS + 109, YPOS + 23);
+        lcd->Poke(XPOS + 110, YPOS + 23);
+        lcd->Poke(XPOS + 111, YPOS + 23);       
+        lcd->Poke(XPOS + 117, YPOS + 23);
+        lcd->Poke(XPOS + 118, YPOS + 23);
+        lcd->Poke(XPOS + 119, YPOS + 23);
+        
+        lcd->Poke(XPOS + 5, YPOS + 25);
+        lcd->Poke(XPOS + 13, YPOS + 25);
+        lcd->Poke(XPOS + 14, YPOS + 25);
+        lcd->Poke(XPOS + 17, YPOS + 25);
+        lcd->Poke(XPOS + 18, YPOS + 25);
+        lcd->Poke(XPOS + 19, YPOS + 25);
+        lcd->Poke(XPOS + 29, YPOS + 25);
+        lcd->Poke(XPOS + 30, YPOS + 25);
+        lcd->Poke(XPOS + 31, YPOS + 25);
+        lcd->Poke(XPOS + 32, YPOS + 25);
+        lcd->Poke(XPOS + 38, YPOS + 25);
+        lcd->Poke(XPOS + 39, YPOS + 25);
+        lcd->Poke(XPOS + 40, YPOS + 25);
+        lcd->Poke(XPOS + 44, YPOS + 25);
+        lcd->Poke(XPOS + 45, YPOS + 25);
+        lcd->Poke(XPOS + 50, YPOS + 25);
+        lcd->Poke(XPOS + 51, YPOS + 25);
+        lcd->Poke(XPOS + 57, YPOS + 25);
+        lcd->Poke(XPOS + 58, YPOS + 25);
+        lcd->Poke(XPOS + 61, YPOS + 25);
+        lcd->Poke(XPOS + 62, YPOS + 25);
+        lcd->Poke(XPOS + 66, YPOS + 25);
+        lcd->Poke(XPOS + 73, YPOS + 25);
+        lcd->Poke(XPOS + 80, YPOS + 25);
+        lcd->Poke(XPOS + 87, YPOS + 25);
+        lcd->Poke(XPOS + 88, YPOS + 25);
+        lcd->Poke(XPOS + 89, YPOS + 25);
+        lcd->Poke(XPOS + 90, YPOS + 25);
+        lcd->Poke(XPOS + 91, YPOS + 25);
+        lcd->Poke(XPOS + 92, YPOS + 25);      
+        lcd->Poke(XPOS + 100, YPOS + 25);
+        lcd->Poke(XPOS + 101, YPOS + 25);
+        lcd->Poke(XPOS + 102, YPOS + 25);
+        lcd->Poke(XPOS + 103, YPOS + 25);
+        lcd->Poke(XPOS + 104, YPOS + 25);
+        lcd->Poke(XPOS + 110, YPOS + 25);
+        lcd->Poke(XPOS + 111, YPOS + 25);       
+        lcd->Poke(XPOS + 117, YPOS + 25);
+        lcd->Poke(XPOS + 118, YPOS + 25);
+        lcd->Poke(XPOS + 119, YPOS + 25);
+        
+        lcd->Poke(XPOS + 4, YPOS + 24);
+        lcd->Poke(XPOS + 5, YPOS + 24);
+        lcd->Poke(XPOS + 6, YPOS + 24);
+        lcd->Poke(XPOS + 13, YPOS + 24);
+        lcd->Poke(XPOS + 14, YPOS + 24);
+        lcd->Poke(XPOS + 17, YPOS + 24);
+        lcd->Poke(XPOS + 18, YPOS + 24);
+        lcd->Poke(XPOS + 19, YPOS + 24);
+        lcd->Poke(XPOS + 28, YPOS + 24);
+        lcd->Poke(XPOS + 29, YPOS + 24);
+        lcd->Poke(XPOS + 30, YPOS + 24);
+        lcd->Poke(XPOS + 31, YPOS + 24);
+        lcd->Poke(XPOS + 32, YPOS + 24);
+        lcd->Poke(XPOS + 33, YPOS + 24);
+        lcd->Poke(XPOS + 37, YPOS + 24);
+        lcd->Poke(XPOS + 38, YPOS + 24);
+        lcd->Poke(XPOS + 39, YPOS + 24);
+        lcd->Poke(XPOS + 40, YPOS + 24);
+        lcd->Poke(XPOS + 41, YPOS + 24);
+        lcd->Poke(XPOS + 42, YPOS + 24);
+        lcd->Poke(XPOS + 44, YPOS + 24);
+        lcd->Poke(XPOS + 45, YPOS + 24);
+        lcd->Poke(XPOS + 49, YPOS + 24);
+        lcd->Poke(XPOS + 50, YPOS + 24);
+        lcd->Poke(XPOS + 51, YPOS + 24);
+        lcd->Poke(XPOS + 54, YPOS + 24);
+        lcd->Poke(XPOS + 55, YPOS + 24);
+        lcd->Poke(XPOS + 56, YPOS + 24);
+        lcd->Poke(XPOS + 57, YPOS + 24);
+        lcd->Poke(XPOS + 58, YPOS + 24);
+        lcd->Poke(XPOS + 59, YPOS + 24);
+        lcd->Poke(XPOS + 61, YPOS + 24);
+        lcd->Poke(XPOS + 62, YPOS + 24);
+        lcd->Poke(XPOS + 65, YPOS + 24);
+        lcd->Poke(XPOS + 66, YPOS + 24);
+        lcd->Poke(XPOS + 67, YPOS + 24);
+        lcd->Poke(XPOS + 72, YPOS + 24);
+        lcd->Poke(XPOS + 73, YPOS + 24);
+        lcd->Poke(XPOS + 74, YPOS + 24);
+        lcd->Poke(XPOS + 79, YPOS + 24);
+        lcd->Poke(XPOS + 80, YPOS + 24);
+        lcd->Poke(XPOS + 81, YPOS + 24);
+        lcd->Poke(XPOS + 86, YPOS + 24);
+        lcd->Poke(XPOS + 87, YPOS + 24);
+        lcd->Poke(XPOS + 88, YPOS + 24);
+        lcd->Poke(XPOS + 89, YPOS + 24);
+        lcd->Poke(XPOS + 90, YPOS + 24);
+        lcd->Poke(XPOS + 91, YPOS + 24);
+        lcd->Poke(XPOS + 92, YPOS + 24);
+        lcd->Poke(XPOS + 93, YPOS + 24);
+        lcd->Poke(XPOS + 99, YPOS + 24);        
+        lcd->Poke(XPOS + 100, YPOS + 24);
+        lcd->Poke(XPOS + 101, YPOS + 24);
+        lcd->Poke(XPOS + 102, YPOS + 24);
+        lcd->Poke(XPOS + 103, YPOS + 24);
+        lcd->Poke(XPOS + 104, YPOS + 24);
+        lcd->Poke(XPOS + 105, YPOS + 24);
+        lcd->Poke(XPOS + 109, YPOS + 24);
+        lcd->Poke(XPOS + 110, YPOS + 24);
+        lcd->Poke(XPOS + 111, YPOS + 24);       
+        lcd->Poke(XPOS + 117, YPOS + 24);
+        lcd->Poke(XPOS + 118, YPOS + 24);
+        lcd->Poke(XPOS + 119, YPOS + 24);
+        
+        lcd->Flush();
+        wait(2);
+        SC.changeScreen("menu");
+    }
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pantallas/ViajesGuardados.cpp	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,55 @@
+/**
+ * @author Juan Manuel Amador Olivares (virtualmech)
+ */
+#include "ViajesGuardados.h"
+
+extern ScreenManager SC;
+extern SistemaArchivos SA;
+
+extern OpcionesViaje opcionesViaje;
+extern OpcionesViaje opcionesViajeEN;
+
+extern DigitalOut myled;
+
+ViajesGuardados::ViajesGuardados(char newNoRides[]){
+    strcpy(noRides, newNoRides);
+}
+
+void ViajesGuardados::initialize(DogMLCD* lcd){
+    ifContinuar = true;
+    // Se borran los elementos añadidos anteriormente
+    borrarElementos();
+    // Se cargan los viajes guardados
+    SA.reloadRideNames();
+    if(SA.getNrides() > 0){   // Si hay algún viaje guardado
+        // Se añaden a la lista de elementos los viajes guardados
+        for(int i = 0; i < SA.getNrides(); i++){
+            addElement(SA.getNameRide(i), "rOptions");
+        }
+        ListaSelec::initialize(lcd);
+    }else{  // Si no existe nigún viaje guardado
+        // Se muestra por pantalla un mensaje informándolo
+        // select font to use:
+        lcd->XFont = xfont_8;
+        
+        // Se desabilita el botón "continuar"
+        ifContinuar = false;
+        
+        // Se escribe el nombre
+        lcd->XString(OFFSETX, OFFSETY, noRides);
+        
+        // transmit work screen to physical screen:
+        lcd->Flush();
+    }
+}
+
+void ViajesGuardados::button5pressed(DogMLCD* lcd){
+    // Se le pasa a la pantalla de menú del viaje el nombre del viaje seleccionado
+    opcionesViaje.setViaje(getElement(getSelect()));
+    opcionesViajeEN.setViaje(getElement(getSelect()));
+    
+    // Se llama a la función padre
+    if(ifContinuar){
+        ListaSelec::button5pressed(lcd);
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pantallas/ViajesGuardados.h	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,25 @@
+/**
+ * @author Juan Manuel Amador Olivares (virtualmech)
+ */
+#ifndef VIAJESGUARDADOS_H
+#define VIAJESGUARDADOS_H
+
+#include "ListaSelec.h"
+#include "SistemaArchivos.h"
+#include "OpcionesViaje.h"
+#include "doggy.h"
+
+// Lista de elementos seleccionables. Tamaño de caracteres 8. 
+class ViajesGuardados: public ListaSelec{
+    public:
+    ViajesGuardados(char newNoRides[]);
+    virtual void initialize(DogMLCD* lcd);
+    virtual void button5pressed(DogMLCD* lcd);     // Esta función se llama cuando el botón central es pulsado, definirla para añadir funcionalidades
+    
+    private:    
+    char noRides[MAXCARACTER8];       // Aviso de que no existen viajes guardados
+    bool ifContinuar;       // Valdrá true si el botón continuar puede usarse para pasar al siguiente menú
+
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RingBuffer/Buffering.cpp	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,91 @@
+#include "Buffering.h"
+ 
+Buffering::Buffering()
+{
+    for(int i = 0; i < BUFFERSIZE; i++){
+        data[i] = 0;
+    }
+    windex = 0;
+    rindex = 0;
+    full = false;
+    empty = true;
+    bufSize = BUFFERSIZE;
+}
+ 
+void Buffering::put(int16_t val)
+{
+    if(!full)
+    {
+        data[windex] = val;
+        windex++;
+        empty = false;
+        if(windex >= bufSize)
+        {
+            windex = 0;
+        }
+        if(getDif() >= bufSize - 1){
+            full = true;
+        }
+        /*if(windex >= rindex)
+        {
+            full = true;
+        }*/
+    }
+}
+ 
+int16_t Buffering::get()
+{  
+    int16_t temp = 0;
+    if(!empty)
+    {
+        temp = data[rindex];
+        data[rindex] = 0;
+        full = false;
+        rindex++;
+        if(rindex >= bufSize)
+        {
+            rindex = 0;
+        }
+        if(getDif() == 0){
+            empty = true;
+        }
+        /*if(rindex >= windex)
+        {
+            empty = true;
+        }*/
+    }
+    return temp;
+}
+ 
+bool Buffering::isFull()
+{
+    return full;
+}
+ 
+bool Buffering::isEmpty()
+{
+    return empty;
+}
+ 
+int Buffering::getSize()
+{
+    return bufSize;
+}
+ 
+unsigned int Buffering::getWritingIndex()
+{
+    return windex;
+}
+
+unsigned int Buffering::getReadingIndex()
+{
+    return rindex;
+}   
+
+unsigned int Buffering::getDif()
+{
+        unsigned int dif = 0;
+        if((int)(windex-rindex)>=0) { dif = windex-rindex; }
+        else { dif = bufSize+windex-rindex; }   
+        return dif;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RingBuffer/Buffering.h	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,30 @@
+#ifndef BUFFERING_H
+#define BUFFERING_H
+ 
+#include "mbed.h"
+
+#define BUFFERSIZE 600
+// Buffering de datos tipo float
+class Buffering
+{
+private:
+    int16_t data[BUFFERSIZE];
+    unsigned int windex;
+    unsigned int rindex;
+    bool full;
+    bool empty;
+    unsigned int bufSize;
+public:
+    Buffering();
+    void put(int16_t val);
+    int16_t get();
+    int getSize();
+    bool isFull();
+    bool isEmpty();
+    unsigned int getWritingIndex();
+    unsigned int getReadingIndex();
+    unsigned int getDif();
+};
+ 
+#endif // BUFFERING_H
+            
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ScreenManager/ListaSelec.cpp	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,102 @@
+#include "mbed.h"
+#include "ListaSelec.h"
+
+extern ScreenManager SC;
+
+extern DigitalIn boton1;
+extern DigitalIn boton4;
+extern DigitalIn boton5;
+
+void ListaSelec::DrawElements(DogMLCD* lcd){
+    for(int i = 0; i < SCREENLINES; i++){
+        if((i + topElement) < nElementos){
+            lcd->XString(OFFSETX, HEIGHTCARACTER8*i + 1 + OFFSETY, list[i + topElement]);
+        }
+    }
+    drawSelection(OFFSETX-1, HEIGHTCARACTER8*posMark + OFFSETY, WIDTH-OFFSETX, HEIGHTCARACTER8, lcd);
+}
+   
+void ListaSelec::initialize(DogMLCD* lcd){
+    // Se inicializa la selección
+    setSelect(0);
+    topElement = 0;
+    posMark = 0;
+    lastPosMark = 0;
+    
+    // select font to use:
+    lcd->XFont = xfont_8;
+    
+    // Se pintan los elementos de la lista
+    DrawElements(lcd);
+          
+    // transmit work screen to physical screen:
+    lcd->Flush();
+}
+
+// El botón 1 sube la selección al elemento superior al actual
+void ListaSelec::button1pressed(DogMLCD* lcd){
+    // Si sales de los elementos seleccionables no se cambia de selección
+    if((getSelect()-1) >= 0){
+        // Se selecciona el elemento
+        setSelect(getSelect()-1);
+        // Si se ha seleccionado un elemento superior que no está siendo mostrado en la pantalla
+        if(getSelect() < topElement){
+            // Se sube hacia arriba el top element (se le resta 1) y se pintan de nuevo los elementos de pantalla
+            topElement--;
+            lcd->Clear();
+            DrawElements(lcd);
+        }else{
+            // Sino se mueve el marcador de selección        
+            lastPosMark = posMark;
+            posMark--;    
+            drawDeselection(OFFSETX-1, HEIGHTCARACTER8*lastPosMark + OFFSETY, WIDTH-OFFSETX , HEIGHTCARACTER8, lcd);
+            drawSelection(OFFSETX-1, HEIGHTCARACTER8*posMark + OFFSETY, WIDTH-OFFSETX, HEIGHTCARACTER8, lcd);
+        }
+        // transmit work screen to physical screen:
+        lcd->Flush();
+    }
+}
+
+// El botón 4 baja la selección al elemento superior al actual
+void ListaSelec::button4pressed(DogMLCD* lcd){
+    // Si sales de los elementos seleccionables no se cambia de selección
+    if((getSelect()+1) <= (nElementos - 1)){
+        // Se selecciona el elemento
+        setSelect(getSelect()+1);
+        // Si se ha seleccionado un elemento inferior que no está siendo mostrado en la pantalla
+        if(getSelect() > (topElement + SCREENLINES - 1)){
+            lcd->Clear();           
+            topElement++;
+            DrawElements(lcd);
+        }else{
+            // Sino se mueve el marcador de selección     
+            lastPosMark = posMark;
+            posMark++;   
+            drawDeselection(OFFSETX-1, HEIGHTCARACTER8*lastPosMark + OFFSETY, WIDTH-OFFSETX, HEIGHTCARACTER8, lcd);
+            drawSelection(OFFSETX-1, HEIGHTCARACTER8*posMark + OFFSETY, WIDTH-OFFSETX, HEIGHTCARACTER8, lcd);
+        }
+        // transmit work screen to physical screen:
+        lcd->Flush();
+    }
+}
+
+    // El botón 5 envía a la pantalla correspondiente según el elemento seleccionado
+void ListaSelec::button5pressed(DogMLCD* lcd){
+    SC.changeScreen(nextScreenID[getSelect()]);
+}
+
+// Añade un elemento al menu con el texto especificado en el primer argumento
+// cada elemento nos enviará a la pantalla con el identificador del segundo argumento
+// Devuelve el identificador del elemento añadido
+int ListaSelec::addElement(char text[], char nameNextScreen[NCARSCREEN]){
+    //strcpy(list[nElementos], text);
+    list[nElementos] = text;
+    //strcpy(nextScreenID[nElementos], nameNextScreen);
+    nextScreenID[nElementos] = nameNextScreen;
+    nElementos++;
+    return nElementos - 1;
+}
+
+char *ListaSelec::getElement(int index){
+    return list[index];
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ScreenManager/ListaSelec.h	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,41 @@
+/**
+ * @author Juan Manuel Amador Olivares (virtualmech)
+ */
+#ifndef LISTASELEC_H
+#define LISTASELEC_H
+
+#include "Seleccion.h"
+#include "doggy.h"
+
+#define OFFSETX 4            // Espacio en pixeles que se deja antes de escribir una linea de caracteres
+#define OFFSETY 4            // Espacio en pixeles que se deja antes de escribir una linea de caracteres en la parte superior
+#define MAXCARACTER8 19      // Número máximo de caracteres de cada elemento
+#define HEIGHTCARACTER8 8     // Anchura de un caracter de media
+#define SCREENLINES 7             // Número máximo de filas mostrados simultáneamente en pantalla
+#define MAXLINES8 100            // Número máximo de filas (cada fila es un elemento)
+
+// Lista de elementos seleccionables. Tamaño de caracteres 8. 
+class ListaSelec: public Seleccion{
+    public:
+    
+    virtual void initialize(DogMLCD* lcd);
+    int addElement(char text[], char nameNextScreen[NCARSCREEN]);
+    char *getElement(int index);
+    
+    void DrawElements(DogMLCD* lcd);    // Pinta a partir del elemento superior, todos los que sea posible hasta ocupar la pantalla (valor de elementos dado por SCREENLINES)
+    
+    virtual void button1pressed(DogMLCD* lcd);     // Esta función se llama cuando el botón superior es pulsado, definirla para añadir funcionalidades
+    virtual void button4pressed(DogMLCD* lcd);     // Esta función se llama cuando el botón inferior es pulsado, definirla para añadir funcionalidades
+    virtual void button5pressed(DogMLCD* lcd);     // Esta función se llama cuando el botón central es pulsado, definirla para añadir funcionalidades
+        
+    private:
+    //char list[MAXLINES8][MAXCARACTER8];      // Lista con las opciones seleccionables
+    char *list[MAXLINES8];      // Lista con las opciones seleccionables
+    char *nextScreenID[MAXLINES8];               // Guarda el nombre de las pantallas a la que debe dirigirse si se elige un elemento
+    //char nextScreenID[MAXLINES8][NCARSCREEN];               // Guarda el nombre de las pantallas a la que debe dirigirse si se elige un elemento
+    int topElement;
+    int posMark;                                // Posicion del marcador de seleccion
+    int lastPosMark;                             // Últim posición del marcador de seleccion
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ScreenManager/Mensaje.cpp	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,70 @@
+#include "mbed.h"
+#include "Mensaje.h"
+
+extern ScreenManager SC;
+extern DigitalIn boton5;
+
+Mensaje::Mensaje(char nextScreen[], char newAdvice[]){
+    strcpy(nextScreenID, nextScreen);
+    strcpy(advice, newAdvice);
+}
+
+void Mensaje::setNextScreen(char nameScreen[NCARSCREEN]){
+    strcpy(nextScreenID, nameScreen);
+}
+    
+void Mensaje::initialize(DogMLCD* lcd){   
+
+    // select font to use:
+    lcd->XFont = xfont_11;
+    
+    // Para pintar los elementos del menú primero
+    // se calcula la posición del primer elemento y el offset hasta el siguiente elemento (eje vertical)
+    int offset  = HEIGHT/(nElementos + 1);
+    int posy0 = offset - SEMIHEIGHTFONT;
+    
+    // Se pintan los elementos del menu con dos particularidades:
+    // - El elemento seleccionado se pinta "seleccionado"
+    // - Los elementos se pintan centrados
+    
+    for(int i = 0; i < nElementos; i++){
+        posElement[i][2] = widthElement(i, lcd);
+        posElement[i][0] = (WIDTH - posElement[i][2])/2;
+        posElement[i][1] = offset*(i) + posy0;;
+        lcd->XString(posElement[i][0], posElement[i][1], list[i]);
+    }
+    
+    // select font to use:
+    lcd->XFont = xfont_8;
+    
+    // Se escribe el consejo en la parte inferior de la pantalla
+    lcd->XString(OFFSETX, HEIGHT - 8, advice);
+    
+    // transmit work screen to physical screen:
+    lcd->Flush();
+}
+
+// El botón 5 envía a la pantalla correspondiente según el elemento seleccionado
+void Mensaje::button5pressed(DogMLCD* lcd){
+    SC.changeScreen(nextScreenID);
+}
+
+// Añade un elemento al menu con el texto especificado en el primer argumento
+// cada elemento nos enviará a la pantalla con el identificador del segundo argumento
+// Devuelve el identificador del elemento añadido
+int Mensaje::addElement(char text[]){
+    strcpy(list[nElementos], text);
+    nElementos++;
+    return nElementos - 1;
+}
+
+
+// Devuelve el ancho del elemento
+// Para ello lo recorre sumando los pixeles que ocupa cada caracter
+int Mensaje::widthElement(int element, DogMLCD* lcd){
+    int width = 0;
+    for(int i = 0; i < (strlen(list[element])); i++){
+        width += lcd->GetGlyph(list[element][i]).wid + 1;
+    }
+    return width;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ScreenManager/Mensaje.h	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,40 @@
+/**
+ * @author Juan Manuel Amador Olivares (virtualmech)
+ */
+#ifndef MENSAJE_H
+#define MENSAJE_H
+
+#include "Seleccion.h"
+#include "doggy.h"
+
+#define SEMIHEIGHTFONT 5    // La mitad de la altura de un caracter
+#define MAXCARACTER 28      // Número máximo de caracteres de cada elemento
+#define HEIGHTCARACTER 11     // Anchura de un caracter de media
+#define MAXLINES 5            // Número máximo de filas (cada fila es un elemento)
+#define OFFSETX 4            // Espacio en pixeles que se deja antes de escribir una linea de caracteres
+
+// EL menu es una lista de selección con los elementos equiespeciados, no centrados en la esquina superior izquierda
+// como en una lista de selección normal. Además el texto es de tamaño 11.
+class Mensaje : public Seleccion {
+    public:
+    Mensaje(char nextScreen[], char newAdvice[]);
+    
+    void setNextScreen(char nameScreen[NCARSCREEN]);
+    
+    virtual void initialize(DogMLCD* lcd);
+    int addElement(char text[]);
+    
+    virtual void button5pressed(DogMLCD* lcd);     // Esta función se llama cuando el botón central es pulsado, definirla para añadir funcionalidades  
+        
+    private:
+    char list[MAXLINES][MAXCARACTER];      // Lista con las opciones del menu. Pueden ser com máximo 5 con una longitud máxima de 24 caracteres
+    int posElement[MAXLINES][3];           // Guarda las posición y tamaños de cada elemento (0 = posx, 1 = posy, 2 = ancho)
+    char nextScreenID[NCARSCREEN];
+    char advice[MAXCARACTER];
+    
+    // Devuelve el ancho del elemento
+    // Para ello lo recorre sumando los pixeles que ocupa cada caracter
+    int widthElement(int element, DogMLCD* lcd);       
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ScreenManager/Menu.cpp	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,90 @@
+#include "mbed.h"
+#include "Menu.h"
+
+extern ScreenManager SC;
+
+extern DigitalIn boton1;
+extern DigitalIn boton4;
+extern DigitalIn boton5;
+    
+void Menu::initialize(DogMLCD* lcd){
+    // Se inicializa la selección
+    setSelect(0);
+    
+    // select font to use:
+    lcd->XFont = xfont_11;
+    
+    // Para pintar los elementos del menú primero
+    // se calcula la posición del primer elemento y el offset hasta el siguiente elemento (eje vertical)
+    int offset  = HEIGHT/(nElementos + 1);
+    int posy0 = offset - SEMIHEIGHTFONT;
+    
+    // Se pintan los elementos del menu con dos particularidades:
+    // - El elemento seleccionado se pinta "seleccionado"
+    // - Los elementos se pintan centrados
+    
+    for(int i = 0; i < nElementos; i++){
+        posElement[i][2] = widthElement(i, lcd);
+        posElement[i][0] = (WIDTH - posElement[i][2])/2;
+        posElement[i][1] = offset*(i) + posy0;;
+        lcd->XString(posElement[i][0], posElement[i][1], list[i]);
+        // Si el elemento está seleccionado se marca con la forma de selección correspondiente
+        if(i == getSelect()){
+            drawSelection(posElement[i][0]-2, posElement[i][1]-1, posElement[i][2]+2, HEIGHTCARACTER+2, lcd);
+        }
+    }
+    
+    // transmit work screen to physical screen:
+    lcd->Flush();
+}
+
+// El botón 1 sube la selección al elemento superior al actual
+void Menu::button1pressed(DogMLCD* lcd){
+    // Si sales de los elementos seleccionables no se cambia de selección
+    if((getSelect()-1) >= 0){
+        setSelect(getSelect()-1);
+        drawDeselection(posElement[getLastSelect()][0]-2, posElement[getLastSelect()][1]-1, posElement[getLastSelect()][2]+2, HEIGHTCARACTER+2, lcd);
+        drawSelection(posElement[getSelect()][0]-2, posElement[getSelect()][1]-1, posElement[getSelect()][2]+2, HEIGHTCARACTER+2, lcd);
+        // transmit work screen to physical screen:
+        lcd->Flush();
+    }
+}
+
+// El botón 4 baja la selección al elemento superior al actual
+void Menu::button4pressed(DogMLCD* lcd){
+    // Si sales de los elementos seleccionables no se cambia de selección
+    if((getSelect()+1) <= (nElementos - 1)){
+        setSelect(getSelect()+1);
+        drawDeselection(posElement[getLastSelect()][0]-2, posElement[getLastSelect()][1]-1, posElement[getLastSelect()][2]+2, HEIGHTCARACTER+2, lcd);
+        drawSelection(posElement[getSelect()][0]-2, posElement[getSelect()][1]-1, posElement[getSelect()][2]+2, HEIGHTCARACTER+2, lcd);
+        // transmit work screen to physical screen:
+        lcd->Flush();
+    }
+}
+
+// El botón 5 envía a la pantalla correspondiente según el elemento seleccionado
+void Menu::button5pressed(DogMLCD* lcd){
+    SC.changeScreen(nextScreenID[getSelect()]);
+}
+
+// Añade un elemento al menu con el texto especificado en el primer argumento
+// cada elemento nos enviará a la pantalla con el identificador del segundo argumento
+// Devuelve el identificador del elemento añadido
+int Menu::addElement(char text[], char nameNextScreen[NCARSCREEN]){
+    strcpy(list[nElementos], text);
+    strcpy(nextScreenID[nElementos], nameNextScreen);
+    nElementos++;
+    return nElementos - 1;
+}
+
+
+// Devuelve el ancho del elemento
+// Para ello lo recorre sumando los pixeles que ocupa cada caracter
+int Menu::widthElement(int element, DogMLCD* lcd){
+    int width = 0;
+    for(int i = 0; i < (strlen(list[element])); i++){
+        width += lcd->GetGlyph(list[element][i]).wid + 1;
+    }
+    return width;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ScreenManager/Menu.h	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,39 @@
+/**
+ * @author Juan Manuel Amador Olivares (virtualmech)
+ */
+#ifndef MENU_H
+#define MENU_H
+
+#include "Seleccion.h"
+#include "doggy.h"
+
+
+#define SEMIHEIGHTFONT 5    // La mitad de la altura de un caracter
+#define MAXCARACTER 22      // Número máximo de caracteres de cada elemento
+#define HEIGHTCARACTER 11     // Anchura de un caracter de media
+#define MAXLINES 5            // Número máximo de filas (cada fila es un elemento)
+#define OFFSETX 4            // Espacio en pixeles que se deja antes de escribir una linea de caracteres
+#define OFFSETY 4            // Espacio en pixeles que se deja antes de escribir una linea de caracteres en la parte superior
+
+// EL menu es una lista de selección con los elementos equiespeciados, no centrados en la esquina superior izquierda
+// como en una lista de selección normal. Además el texto es de tamaño 11.
+class Menu : public Seleccion {
+    public:
+    virtual void initialize(DogMLCD* lcd);
+    int addElement(char text[], char nameNextScreen[NCARSCREEN]);
+    
+    virtual void button1pressed(DogMLCD* lcd);     // Esta función se llama cuando el botón superior es pulsado, definirla para añadir funcionalidades
+    virtual void button4pressed(DogMLCD* lcd);     // Esta función se llama cuando el botón inferior es pulsado, definirla para añadir funcionalidades
+    virtual void button5pressed(DogMLCD* lcd);     // Esta función se llama cuando el botón central es pulsado, definirla para añadir funcionalidades  
+        
+    private:
+    char list[MAXLINES][MAXCARACTER];      // Lista con las opciones del menu. Pueden ser com máximo 5 con una longitud máxima de 24 caracteres
+    int posElement[5][3];           // Guarda las posición y tamaños de cada elemento (0 = posx, 1 = posy, 2 = ancho)
+    char nextScreenID[5][NCARSCREEN];
+    
+    // Devuelve el ancho del elemento
+    // Para ello lo recorre sumando los pixeles que ocupa cada caracter
+    int widthElement(int element, DogMLCD* lcd);       
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ScreenManager/Screen.cpp	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,15 @@
+/**
+ * @author Juan Manuel Amador Olivares (virtualmech)
+ */
+
+#include "doggy.h"
+
+#define WIDTH 128
+#define HEIGHT 64
+
+class Screen {
+
+public:
+    virtual void initialize(DogMLCD* lcd){}
+    virtual void update(DogMLCD* lcd){}
+};
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ScreenManager/ScreenManager.cpp	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,73 @@
+/**
+ * @author Juan Manuel Amador Olivares (virtualmech)
+ */
+ 
+#include "ScreenManager.h"
+
+ScreenManager::ScreenManager(DogMLCD* lcdScreen){
+    currentGroupID = 0;
+    currentScreen = 0;
+    lastScreen = 0;
+    for(int i = 0; i < NIDIOMAS; i++){
+        nScreens[i] = 0;
+    }
+    lcd = lcdScreen;
+}
+
+void ScreenManager::selectGroup(int groupID){
+    currentGroupID = groupID;
+}
+
+int ScreenManager::addScreen(Screen* screen, char name[16], int groupID){   // Devuelve el índice asignado a la nueva pantalla
+    screens[groupID][nScreens[groupID]] = screen;
+    strcpy(screenName[groupID][nScreens[groupID]],name);
+    nScreens[groupID]++;
+    return nScreens[groupID] - 1;
+}    
+
+void ScreenManager::changeScreen(char nameNextScreen[16]){
+    // se busca el identificador numérico de la lista de pantallas según el nombre pasado a la función
+    // para ello se recorre la lista de pantallas
+    int nextScreen;
+    for(int i = 0; i < nScreens[currentGroupID]; i++){
+        if(strcmp(nameNextScreen, screenName[currentGroupID][i]) == 0){
+            nextScreen = i;
+        }
+    }
+    // Se selecciona la siguiente pantala
+    lastScreen = currentScreen;
+    currentScreen = nextScreen;
+    // Se borra la pantalla para dejar paso a la pantalla siguiente
+    lcd->Clear();
+    lcd->Flush();
+    // Se inicializa la pantalla siguiente
+    screens[currentGroupID][currentScreen]->initialize(lcd);
+}
+
+char *ScreenManager::getCurrentScreen(){
+    return screenName[currentGroupID][currentScreen];
+}
+
+int ScreenManager::getnScreen(int groupID){
+    return nScreens[groupID];
+}
+
+void ScreenManager::getLastScreen(char buff[]){
+    strcpy(buff, screenName[currentGroupID][lastScreen]);
+}
+
+int ScreenManager::getCurrentGroupID(){
+    return currentGroupID;
+}
+
+void ScreenManager::backScreen(){
+    changeScreen(screenName[currentGroupID][lastScreen]);
+}
+
+void ScreenManager::initialize(){
+    screens[currentGroupID][currentScreen]->initialize(lcd);
+}
+    
+void ScreenManager::update(){
+    screens[currentGroupID][currentScreen]->update(lcd);
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ScreenManager/ScreenManager.h	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,47 @@
+/**
+ * @author Juan Manuel Amador Olivares (virtualmech)
+ */
+#ifndef SCREENMANAGER_H
+#define SCREENMANAGER_H
+
+#define NUMSCREENS 25
+#define NIDIOMAS 2
+#define NCARSCREEN 16
+
+#include "Screen.cpp"
+#include <string.h> 
+
+class ScreenManager {
+
+public:
+    /**
+     * Constructor.
+     *
+     */
+    ScreenManager(DogMLCD* lcdScreen);
+    
+    void selectGroup(int groupID);      // Se selecciona el grupo mostrado actualmente. Llamamar a esta funcioón justo antes de cambiar a una pantalla o llamar initialize para que se muestre la actual correctamente
+    int addScreen(Screen* screen, char name[NCARSCREEN], int groupID);   // Devuelve el índice asignado a la nueva pantalla
+    void changeScreen(char nameNextScreen[NCARSCREEN]);  
+    void backScreen();               // Vuelve a la pantalla anterior, devuelve el índice de la pantalla anterior
+    void getLastScreen(char buff[]);    // Devuelve el nombre de la pantalla anterior
+    int getnScreen(int groupID);       // Devuelve el número de pantallas
+    int getCurrentGroupID();            //Devuelve el grupo de patallas seleccionado actual
+    char *getCurrentScreen();      // Devuelve el nombre de la pantalla actual
+    
+    void initialize();  // Iniciliza la pantalla actual
+    void update();
+    
+    
+    private:
+    int currentGroupID; // Grupo actual
+    int currentScreen;  // Índice de la pantalla actual
+    int lastScreen;     // Índice de la pantalla anterior
+    int nScreens[NIDIOMAS];       // Número total de pantallas añadidas de cada grupo
+    Screen* screens[NIDIOMAS][NUMSCREENS];
+    char screenName[NIDIOMAS][NUMSCREENS][NCARSCREEN];
+    DogMLCD* lcd;
+
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ScreenManager/SelecManager.cpp	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,27 @@
+#include "SelecManager.h"
+
+SelecManager::SelecManager(){
+    nScreens = 0;
+}
+
+int SelecManager::addScreen(Seleccion *screen){
+    screens[nScreens] = screen;
+    nScreens++;
+    return nScreens -1;
+}
+
+void SelecManager::setInverterSelection(){
+    for(int i = 0; i < nScreens; i++){
+        screens[i]->setInverterSelection();
+    }
+}
+
+void SelecManager::setRectSelection(){
+    for(int i = 0; i < nScreens; i++){
+        screens[i]->setRectSelection();
+    }
+}
+
+int SelecManager::getnScreens(){
+    return nScreens;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ScreenManager/SelecManager.h	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,34 @@
+/**
+ * @author Juan Manuel Amador Olivares (virtualmech)
+ */
+#ifndef SELECMANAGER_H
+#define SELECMANAGER_H
+
+#define NSELECSCREEN 25   // Número máximo de pantallas seleccionables
+
+#include "Seleccion.h"
+
+// Esta clase se encarga de gestionar los elementos comunes de las pantallas con elementos seleecionables como por ejemplo la forma de selección
+class SelecManager {
+
+public:
+    /**
+     * Constructor.
+     *
+     */
+    SelecManager();
+    
+    int addScreen(Seleccion* screen);   // Devuelve el número de identificación en la lista de pantallas seleccionables
+    
+    void setInverterSelection();      // Configura la forma de selección de inversión de pixeles del elemento
+    
+    void setRectSelection();         // Configura la forma de selección mediante rectángulos delimitadores  
+    
+    int getnScreens();
+    
+private:
+    int nScreens;
+    Seleccion* screens[NSELECSCREEN];  // Lista de pantallas seleccionables
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ScreenManager/Seleccion.cpp	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,168 @@
+/**
+ * @author Juan Manuel Amador Olivares (virtualmech)
+ */ 
+#include "Seleccion.h"
+
+extern ScreenManager SC;
+
+extern DigitalIn boton1;
+extern DigitalIn boton2;
+extern DigitalIn boton3;
+extern DigitalIn boton4;
+extern DigitalIn boton5;
+extern DigitalIn boton6;
+
+Seleccion::Seleccion(){
+    // Se inicializan las variables
+    invType = true;
+    nElementos = 0;
+    select = 0;
+    lastSelect = 0;
+    pulsado1 = false;
+    pulsado2 = false;
+    pulsado3 = false;
+    pulsado4 = false;
+    pulsado5 = false;
+    pulsado6 = false;
+    backScreen = false;
+}
+
+void Seleccion::borrarElementos(){
+    // para borrar los elementos existentes sólo hay que reiniciar el número de elementos
+    nElementos = 0;
+}
+
+void Seleccion::setInverterSelection(){
+    invType = true;
+}
+
+void Seleccion::setRectSelection(){
+    invType = false;
+}
+
+int Seleccion::getSelect(){
+    return select;
+}
+
+void Seleccion::setSelect(int newSelect){
+    lastSelect = select;
+    select = newSelect;
+}
+
+int Seleccion::getLastSelect(){
+    return lastSelect;
+}
+
+bool Seleccion::getSelectType(){
+    return invType;
+}
+
+void Seleccion::drawSelection(int x, int y, int width, int height, DogMLCD* lcd){
+    // Se pinta de distinta manera dependiendo de la forma de selección
+    if(invType){
+        lcd->InvRect(x, y, x+width, y+height);
+    }else{
+        lcd->Frame(x, y, x+width, y+height);
+    }
+}
+
+void Seleccion::drawDeselection(int x, int y, int width, int height, DogMLCD* lcd){
+    // Se pinta de distinta manera dependiendo de la forma de selección
+    if(invType){
+        lcd->InvRect(x, y, x+width, y+height);
+    }else{
+        lcd->Frame(x, y, x+width, y+height, wipe);
+    }
+}
+
+// En esta función se comprueba si se han pulsado los botones
+void Seleccion::update(DogMLCD* lcd){
+    if(boton1 == 1){
+        // Se espera a que se suelte el botón
+        pulsado1 = true;
+    }else{
+        if(pulsado1 == true){
+            // Antes de cambiar de pantalla se llama la siguiente funcion con la que se puede añadir funcionalidad
+            button1pressed(lcd);
+            // Se inicializa la variable que controla la pulsación
+            pulsado1 = false;
+        }
+    }
+    if(boton2 == 1){
+        // Se espera a que se suelte el botón
+        pulsado2 = true;
+    }else{
+        if(pulsado2 == true){
+            // Antes de cambiar de pantalla se llama la siguiente funcion con la que se puede añadir funcionalidad
+            button2pressed(lcd);
+            // Se inicializa la variable que controla la pulsación
+            pulsado2 = false;
+        }
+    }
+    if(boton3 == 1){
+        // Se espera a que se suelte el botón
+        pulsado3 = true;
+    }else{
+        if(pulsado3 == true){
+            // Antes de cambiar de pantalla se llama la siguiente funcion con la que se puede añadir funcionalidad
+            button3pressed(lcd);
+            // Se inicializa la variable que controla la pulsación
+            pulsado3 = false;
+        }
+    }
+    if(boton4 == 1){
+        // Se espera a que se suelte el botón
+        pulsado4 = true;
+    }else{
+        if(pulsado4 == true){
+            // Antes de cambiar de pantalla se llama la siguiente funcion con la que se puede añadir funcionalidad
+            button4pressed(lcd);
+            // Se inicializa la variable que controla la pulsación
+            pulsado4 = false;
+        }
+    }
+    if(boton5 == 1){
+        // Se espera a que se suelte el botón
+        pulsado5 = true;
+    }else{
+        if(pulsado5 == true){
+            // Antes de cambiar de pantalla se llama la siguiente funcion con la que se puede añadir funcionalidad
+            button5pressed(lcd);
+            // Se inicializa la variable que controla la pulsación
+            pulsado5 = false;
+        }
+    }
+    if(boton6 == 1){
+        // Se espera a que se suelte el botón
+        pulsado6 = true;
+    }else{
+        if(pulsado6 == true){
+            // Antes de cambiar de pantalla se llama la siguiente funcion con la que se puede añadir funcionalidad
+            button6pressed(lcd);
+            // Se inicializa la variable que controla la pulsación
+            pulsado6 = false;
+        }
+    }
+}
+
+// Esta función guarda la pantalla a la que se debe volver en caso de ser pulsado el boton atras
+void Seleccion::setBackScreen(char nameScreen[NCARSCREEN]){
+    strcpy(nameBackScreen, nameScreen);
+    backScreen = true;
+}
+
+// Esta función desactiva volver a la pantalla anterior (si la pantalla no vuelve a ninguna pantalla debe usarse)
+void Seleccion::disableBackScreen(){
+    backScreen = false;
+}
+
+void Seleccion::button1pressed(DogMLCD* lcd){}
+void Seleccion::button2pressed(DogMLCD* lcd){}
+void Seleccion::button3pressed(DogMLCD* lcd){}
+void Seleccion::button4pressed(DogMLCD* lcd){}
+void Seleccion::button5pressed(DogMLCD* lcd){}
+void Seleccion::button6pressed(DogMLCD* lcd){
+    if(backScreen){
+        SC.changeScreen(nameBackScreen);
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ScreenManager/Seleccion.h	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,63 @@
+/**
+ * @author Juan Manuel Amador Olivares (virtualmech)
+ */
+#ifndef SELECCION_H
+#define SELECCION_H
+
+#include "ScreenManager.h"
+#include "doggy.h"
+
+// Esta clase es la base de pantallas en las que haya objetos sleccionables
+// como menus o listas
+class Seleccion: public Screen { 
+
+ public:
+    int nElementos;     // Número de elementos en la lista de selección
+    
+    void borrarElementos();     // Borra los elementos existentes
+    
+    Seleccion();
+    
+    virtual void update(DogMLCD* lcd);
+    
+    void setInverterSelection();
+    
+    void setRectSelection();
+    
+    int getSelect();
+    
+    void setSelect(int newSelect);  // Se selecciona un elemento
+    
+    int getLastSelect();
+    
+    bool getSelectType();
+    
+    void drawSelection(int x, int y, int width, int height, DogMLCD* lcd);
+    
+    void drawDeselection(int x, int y, int width, int height, DogMLCD* lcd);
+    
+    virtual void button1pressed(DogMLCD* lcd);     // Esta función se llama cuando el botón superior es pulsado, definirla para añadir funcionalidades
+    virtual void button2pressed(DogMLCD* lcd);     // Esta función se llama cuando el botón izquierdo es pulsado, definirla para añadir funcionalidades
+    virtual void button3pressed(DogMLCD* lcd);     // Esta función se llama cuando el botón derecho es pulsado, definirla para añadir funcionalidades
+    virtual void button4pressed(DogMLCD* lcd);     // Esta función se llama cuando el botón inferior es pulsado, definirla para añadir funcionalidades
+    virtual void button5pressed(DogMLCD* lcd);     // Esta función se llama cuando el botón central es pulsado, definirla para añadir funcionalidades
+    virtual void button6pressed(DogMLCD* lcd);     // Esta función se llama cuando el botón atras es pulsado, definirla para añadir funcionalidades
+    char nameBackScreen[NCARSCREEN];
+    bool backScreen;        // true si existe pagina atras, sino no se puede volver a la página anterior pulsando el boton correspondiente
+    void setBackScreen(char nameScreen[NCARSCREEN]);
+    void disableBackScreen();
+    
+    private:
+    int select;         // Elemento seleccionado de la lista de elementos
+    int lastSelect;     // Anterior elemento seleccionado
+    bool invType;       // Indica el tipo de selección. true: invirtiendo, false: pintando un recuadro
+            
+    bool pulsado1;
+    bool pulsado2;
+    bool pulsado3;
+    bool pulsado4;
+    bool pulsado5;
+    bool pulsado6;
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ScreenManager/Teclado.cpp	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,465 @@
+#include "mbed.h"
+#include "Teclado.h"
+
+extern ScreenManager SC;
+
+extern DigitalIn boton1;
+extern DigitalIn boton2;
+extern DigitalIn boton3;
+extern DigitalIn boton4;
+extern DigitalIn boton5;
+
+extern DigitalOut myled;
+   
+void Teclado::initialize(DogMLCD* lcd){
+    // Se inicializa la variable que guarda el último nombre introducido
+    for(int i = 0; i < MAXCARACTERESESCRITURA; i++){
+        nombre[i] = 0;
+    }
+    
+    // Se inicializa la selección
+    setSelect(0);
+
+    indiceEscritura = 0;
+        
+    mostrarRecuadro(lcd);
+    
+    // Por defecto se muestran caracteres de letras minusculas
+    asignarMinusculas();
+    ifMayus = false;
+    
+    // Se muestran los caracteres normales    
+    mostrarCaracteres(lcd);
+    
+    // Se muestran los caracteres especiales
+    mostrarEspeciales(lcd);  
+    
+    // Se inicializa la selección
+    Xsel = 0;
+    Ysel = 0;
+    lastXsel = 0;
+    lastYsel = 0;
+    // Se pinta la selección por defecto
+    drawSelection(OFFSETX-2, WRITTENSPACE, CARACTER11, CARACTER11, lcd);
+    
+    // transmit work screen to physical screen:
+    lcd->Flush();  
+
+}
+
+// El botón 5 envía a la pantalla correspondiente según el elemento seleccionado
+void Teclado::button5pressed(DogMLCD* lcd){
+    
+    // Si no es una tecla especial
+    if(m[Ysel][Xsel] > ULTIMOCARACTERESPECIAL){
+        // select font to use:
+        lcd->XFont = xfont_8;
+        if(indiceEscritura < MAXCARACTERESESCRITURA){
+            // Si se ha pulsado sobre un caracter normal se añade este al recuadro donde se muestra lo escrito
+            if(m[Ysel][Xsel] > ULTIMOCARACTERESPECIAL){   // Si el elemento no es un caracter o tecla especial
+                // Se asigna el caracter en la cedena
+                nombre[indiceEscritura] = m[Ysel][Xsel];
+                indiceEscritura++;
+                // Se actualiza el caracter finde cadena
+                if(indiceEscritura < MAXCARACTERESESCRITURA){
+                    nombre[indiceEscritura] = '\0';
+                }
+                
+                // Se borra la cadena mostrada actualmente
+                lcd->Rect(POSCADENAX,1,WIDTH-2, WRITTENSPACE-2, DOGMLCD_full, wipe);
+                
+                // Se escribe la nueva cadena
+                lcd->XString(POSCADENAX, 1, nombre);
+            }
+        }
+    }else{      // Teclas especiales
+        if(m[Ysel][Xsel] == SPACEBAR){  // Barra espaciadora
+            // Se aplica un espacio
+            nombre[indiceEscritura] = ' ';
+            indiceEscritura++;
+            // Se actualiza el caracter fin de cadena
+            if(indiceEscritura < MAXCARACTERESESCRITURA){
+                nombre[indiceEscritura] = '\0';
+            }
+        }else if(m[Ysel][Xsel] == MAYUS){
+            // Se intercambian los caracteres actuales mayúsculas/minúculas
+            // Primero se limpia la pantalla
+            lcd->Clear();            
+            mostrarRecuadro(lcd);
+            // Se asignan los caracteres que corresponden
+            if(ifMayus){                
+                asignarMinusculas();
+                ifMayus = false;
+            }else{
+                asignarMayusculas();
+                ifMayus = true;
+            }
+            // Se muestran los caracteres normales    
+            mostrarCaracteres(lcd);
+            
+            // Se muestran los caracteres especiales
+            mostrarEspeciales(lcd);  
+            
+            // Se escribe la selección del mayus
+            drawSelection(OFFSETX-2 + Xsel*CARACTER11, WRITTENSPACE + Ysel*CARACTER11, CARACTER11, CARACTER11-1, lcd);
+            
+            // select font to use:
+            lcd->XFont = xfont_8;
+            
+            // Se escribe la nueva cadena
+            lcd->XString(POSCADENAX, 1, nombre);
+            
+            // transmit work screen to physical screen:
+            lcd->Flush();  
+        }else if(m[Ysel][Xsel] == BACK){
+            // Se borra el último caracter de la cadena escribiendo en su lugar un caracter fin de cadena
+            if(indiceEscritura > 0){ // Si hay algo que borrar
+                indiceEscritura--;
+                nombre[indiceEscritura] = '\0';
+                
+                // Se borra la cadena mostrada actualmente
+                lcd->Rect(POSCADENAX,1,WIDTH-2, WRITTENSPACE-2, DOGMLCD_full, wipe);
+                
+                // Se escribe la nueva cadena
+                lcd->XString(POSCADENAX, 1, nombre);
+            }
+        }else if(m[Ysel][Xsel] == APLICAR){
+            SC.changeScreen(nameNextScreen);
+        }
+    }
+    
+    // transmit work screen to physical screen:
+    lcd->Flush();
+}
+
+void Teclado::mostrarEspeciales(DogMLCD* lcd){
+    // Se pinta la flecha de borrado de caracteres
+    lcd->Rect(OFFSETX + CARACTER11*10 + 2, WRITTENSPACE + CARACTER11*3 + 3, OFFSETX + CARACTER11*10 + 2 + 6, WRITTENSPACE + CARACTER11*3 + 3 + 5);
+    lcd->LineV(OFFSETX + CARACTER11*10 + 1, WRITTENSPACE + CARACTER11*3 + 4, WRITTENSPACE + CARACTER11*3 + 7);
+    lcd->LineV(OFFSETX + CARACTER11*10, WRITTENSPACE + CARACTER11*3 + 5, WRITTENSPACE + CARACTER11*3 + 6);
+    
+    // Se pinta la flecha de mayus
+    lcd->Rect(OFFSETX + 2, WRITTENSPACE + CARACTER11*4 + 5, OFFSETX + 2 + 3, WRITTENSPACE + CARACTER11*4 + 5 + 4);
+    lcd->LineH(OFFSETX + 1, WRITTENSPACE + CARACTER11*4 + 4, OFFSETX + 1 + 5);
+    lcd->LineH(OFFSETX + 2, WRITTENSPACE + CARACTER11*4 + 3, OFFSETX + 2 + 3);
+    lcd->LineH(OFFSETX + 3, WRITTENSPACE + CARACTER11*4 + 2, OFFSETX + 3 + 1);
+    
+    // Se pinta el intro (abarca el espacio de dos elementos de la matriz)
+    lcd->Rect(OFFSETX + CARACTER11*10 + 5, WRITTENSPACE + CARACTER11*4 + 1, OFFSETX + CARACTER11*10 + 5 + 2, WRITTENSPACE + CARACTER11*4 + 5);
+    lcd->Rect(OFFSETX + CARACTER11*9 + 3, WRITTENSPACE + CARACTER11*4 + 6, OFFSETX + CARACTER11*9 + 3 + 15, WRITTENSPACE + CARACTER11*4 + 6 + 2);
+    lcd->LineV(OFFSETX + CARACTER11*9 + 2, WRITTENSPACE + CARACTER11*4 + 5, WRITTENSPACE + CARACTER11*4 + 5 + 4);
+    lcd->LineV(OFFSETX + CARACTER11*9 + 1, WRITTENSPACE + CARACTER11*4 + 6, WRITTENSPACE + CARACTER11*4 + 6 + 2);
+    lcd->LineV(OFFSETX + CARACTER11*9 , WRITTENSPACE + CARACTER11*4 + 7, WRITTENSPACE + CARACTER11*4 + 7);
+    
+    // Se pinta la barra espaciadora (abarca el espacio de 8 elementos de la matriz)
+    lcd->Rect(OFFSETX + CARACTER11 + 3, WRITTENSPACE + CARACTER11*4 + 6, OFFSETX + CARACTER11 + 79, WRITTENSPACE + CARACTER11*4 + 6 + 1);
+    lcd->Rect(OFFSETX + CARACTER11 + 3, WRITTENSPACE + CARACTER11*4 + 2, OFFSETX + CARACTER11 + 3 + 1, WRITTENSPACE + CARACTER11*4 + 2 + 3);
+    lcd->Rect(OFFSETX + CARACTER11 + 78, WRITTENSPACE + CARACTER11*4 + 2, OFFSETX + CARACTER11 + 79, WRITTENSPACE + CARACTER11*4 + 2 + 3);
+}
+
+void Teclado::seleccionarAplicar(DogMLCD* lcd){
+    drawSelection(OFFSETX + CARACTER11 + 84, WRITTENSPACE + CARACTER11*4, 24, 10, lcd);
+}
+
+void Teclado::deseleccionarAplicar(DogMLCD* lcd){
+    drawDeselection(OFFSETX + CARACTER11 + 84, WRITTENSPACE + CARACTER11*4, 24, 10, lcd);
+}
+
+void Teclado::seleccionarBarraEspaciadora(DogMLCD* lcd){
+    drawSelection(OFFSETX + CARACTER11 - 1, WRITTENSPACE + CARACTER11*4, 84, 10, lcd);
+}
+
+void Teclado::deseleccionarBarraEspaciadora(DogMLCD* lcd){
+    drawDeselection(OFFSETX + CARACTER11 - 1, WRITTENSPACE + CARACTER11*4, 84, 10, lcd);
+}
+
+void Teclado::mostrarCaracteres(DogMLCD* lcd){
+    // select font to use:
+    lcd->XFont = xfont_11;
+    
+    // Se recorre la matriz mostrando todo lo que no sean caracteres o teclas especiales
+    for(int i = 0; i < FILASMATRIZ; i++){
+        for(int j = 0; j < COLUMNASMATRIZ; j++){
+            if(m[i][j] > ULTIMOCARACTERESPECIAL){   // SI el elemento no es un caracter o tecla especial
+                // se muestra
+                lcd->XChar(OFFSETX + CARACTER11*j, WRITTENSPACE + CARACTER11*i, m[i][j]);
+            }
+        }
+    }   
+}
+
+void Teclado::mostrarRecuadro(DogMLCD* lcd){
+    lcd->Frame(0, 0,WIDTH-1, WRITTENSPACE-1);
+}
+
+// El botón 1 sube la selección al elemento superior al actual
+void Teclado::button1pressed(DogMLCD* lcd){
+    // Si sales de los elementos seleccionables no se cambia de selección
+    if((Ysel - 1) >= 0){
+        // Si se venía de la última fila (teclas especiales)
+        if(Ysel == (FILASMATRIZ-1) ){         
+            // Si se venía la barra espaciadora se selecciona esta
+            if(m[Ysel][Xsel] == SPACEBAR){
+                deseleccionarBarraEspaciadora(lcd);
+            }else if(m[Ysel][Xsel] == APLICAR){ // Si se venía de la tecla aplicar se selecciona esta
+                deseleccionarAplicar(lcd);
+            }else{
+                // se venía del mayus mayus
+                drawDeselection(OFFSETX-2 + Xsel*CARACTER11, WRITTENSPACE + Ysel*CARACTER11, CARACTER11, CARACTER11-1, lcd);
+            }
+        }else{
+            // Se deselecciona la tecla anterior
+            drawDeselection(OFFSETX-2 + Xsel*CARACTER11, WRITTENSPACE + Ysel*CARACTER11, CARACTER11, CARACTER11, lcd);
+        }
+        
+        // Se selecciona el nuevo elemento
+        Ysel--;
+        
+        // Se escribe la nueva selección
+        drawSelection(OFFSETX-2 + Xsel*CARACTER11, WRITTENSPACE + Ysel*CARACTER11, CARACTER11, CARACTER11, lcd);
+        
+        // transmit work screen to physical screen:
+        lcd->Flush();
+    }
+}
+
+// El botón 2 desplaza la selección al elemento izquierdo al actual
+void Teclado::button2pressed(DogMLCD* lcd){
+    // Si sales de los elementos seleccionables no se cambia de selección
+    if((Xsel - 1) >= 0){
+        // Si se está en la última fila
+        if(Ysel == (FILASMATRIZ-1) ){
+            // Se se venía de la tecla aplicar
+            if(m[Ysel][Xsel] == APLICAR){
+                deseleccionarAplicar(lcd);
+                seleccionarBarraEspaciadora(lcd);
+                // Se mueven dos elementos a la izquierda
+                Xsel -= 2;
+            }else{
+                deseleccionarBarraEspaciadora(lcd);
+                // Se mueve la selección al elemento de la izquierda
+                Xsel = 0;
+                // Se escribe la nueva selección (la selección es CARACTER11-1 por razones de espacio) (tecla mayus)
+                drawSelection(OFFSETX-2 + Xsel*CARACTER11, WRITTENSPACE + Ysel*CARACTER11, CARACTER11, CARACTER11-1, lcd);
+            }
+        }else{        
+            // Se borra la selección anterior
+            drawDeselection(OFFSETX-2 + Xsel*CARACTER11, WRITTENSPACE + Ysel*CARACTER11, CARACTER11, CARACTER11, lcd);
+            // Se selecciona el nuevo elemento
+            Xsel--;
+            // Se escribe la nueva selección
+            drawSelection(OFFSETX-2 + Xsel*CARACTER11, WRITTENSPACE + Ysel*CARACTER11, CARACTER11, CARACTER11, lcd);
+        }
+        // transmit work screen to physical screen:
+        lcd->Flush();
+    }
+}
+
+// El botón 3 desplaza la selección al elemento derecho al actual
+void Teclado::button3pressed(DogMLCD* lcd){
+    // Si sales de los elementos seleccionables no se cambia de selección
+    if((Xsel + 1) < COLUMNASMATRIZ){
+        // Si se está en la última fila
+        if(Ysel == (FILASMATRIZ-1) ){
+            // Se se venía de la tecla mayus
+            if(m[Ysel][Xsel] == MAYUS){
+                drawDeselection(OFFSETX-2 + Xsel*CARACTER11, WRITTENSPACE + Ysel*CARACTER11, CARACTER11, CARACTER11-1, lcd);
+                seleccionarBarraEspaciadora(lcd);
+                // Se mueven un elemento a la derecha
+                Xsel++;
+            }else if(m[Ysel][Xsel] == SPACEBAR){    //si se venía de la barra espaciadora
+                deseleccionarBarraEspaciadora(lcd);
+                // Se mueve la selección al penultimo elemento
+                Xsel = 9;
+                // Se escribe la nueva selección (la selección es CARACTER11-1 por razones de espacio) (tecla mayus)
+                seleccionarAplicar(lcd);
+            }
+        }else{            
+            // Se borra la selección anterior
+            drawDeselection(OFFSETX-2 + Xsel*CARACTER11, WRITTENSPACE + Ysel*CARACTER11, CARACTER11, CARACTER11, lcd);
+            // Se selecciona el nuevo elemento
+            Xsel++;
+            // Se escribe la nueva selección
+            drawSelection(OFFSETX-2 + Xsel*CARACTER11, WRITTENSPACE + Ysel*CARACTER11, CARACTER11, CARACTER11, lcd);
+        }
+        
+        // transmit work screen to physical screen:
+        lcd->Flush();
+    }
+}
+
+// El botón 4 baja la selección al elemento superior al actual
+void Teclado::button4pressed(DogMLCD* lcd){
+    // Si sales de los elementos seleccionables no se cambia de selección
+    if((Ysel + 1) < FILASMATRIZ){
+        // Se borra la selección anterior
+        drawDeselection(OFFSETX-2 + Xsel*CARACTER11, WRITTENSPACE + Ysel*CARACTER11, CARACTER11, CARACTER11, lcd);
+        // Se selecciona el nuevo elemento
+        Ysel++;
+        
+        // Si la siguiente fila es la última (teclas especiales)
+        if(Ysel == (FILASMATRIZ-1) ){
+            // Se guarda la última tecla que estaba seleccionada
+            lastXsel = Xsel;
+            lastYsel = Ysel-1;          
+            // Si se va hacia la barra espaciadora se selecciona esta
+            if(m[Ysel][Xsel] == SPACEBAR){
+                seleccionarBarraEspaciadora(lcd);
+            }else if(m[Ysel][Xsel] == APLICAR){ // Si se va hacia la tecla aplicar se selecciona esta
+                seleccionarAplicar(lcd);
+            }else{
+                // Se escribe la nueva selección (la selección es CARACTER11-1 por razones de espacio) (tecla mayus)
+                drawSelection(OFFSETX-2 + Xsel*CARACTER11, WRITTENSPACE + Ysel*CARACTER11, CARACTER11, CARACTER11-1, lcd);
+            }
+        }else{
+            // Se escribe la nueva selección
+            drawSelection(OFFSETX-2 + Xsel*CARACTER11, WRITTENSPACE + Ysel*CARACTER11, CARACTER11, CARACTER11, lcd);
+        }
+        
+        // transmit work screen to physical screen:
+        lcd->Flush();
+    }
+}
+
+char *Teclado::getNombre(){
+    return nombre;
+}
+
+// Esta función guarda la pantalla a la que se debe volver en caso de ser pulsado el boton atras
+void Teclado::setNextScreen(char nameScreen[NCARSCREEN]){
+    strcpy(nameNextScreen, nameScreen);
+}
+
+void Teclado::asignarMinusculas(){
+    // Primera fila
+    m[0][0] = 'q';
+    m[0][1] = 'w';     
+    m[0][2] = 'e';
+    m[0][3] = 'r';
+    m[0][4] = 't';
+    m[0][5] = 'y';
+    m[0][6] = 'u';     
+    m[0][7] = 'i';
+    m[0][8] = 'o';
+    m[0][9] = 'p';
+    m[0][10] = '(';
+    
+    // Segunda fila
+    m[1][0] = 'a';
+    m[1][1] = 's';     
+    m[1][2] = 'd';
+    m[1][3] = 'f';
+    m[1][4] = 'g';
+    m[1][5] = 'h';
+    m[1][6] = 'j';     
+    m[1][7] = 'k';
+    m[1][8] = 'l';
+    m[1][9] = 164;
+    m[1][10] = ')';
+    
+    // Tercera fila
+    m[2][0] = 'z';
+    m[2][1] = 'x';     
+    m[2][2] = 'c';
+    m[2][3] = 'v';
+    m[2][4] = 'b';
+    m[2][5] = 'n';
+    m[2][6] = 'm';     
+    m[2][7] = ',';
+    m[2][8] = '.';
+    m[2][9] = ';';
+    m[2][10] = '_';
+    
+    // Cuarta fila
+    m[3][0] = '1';
+    m[3][1] = '2';     
+    m[3][2] = '3';
+    m[3][3] = '4';
+    m[3][4] = '5';
+    m[3][5] = '6';
+    m[3][6] = '7';     
+    m[3][7] = '8';
+    m[3][8] = '9';
+    m[3][9] = '0';
+    m[3][10] = BACK;
+    
+    // Quinta fila
+    m[4][0] = MAYUS;
+    m[4][1] = SPACEBAR;
+    m[4][2] = SPACEBAR;
+    m[4][3] = SPACEBAR;
+    m[4][4] = SPACEBAR;
+    m[4][5] = SPACEBAR;
+    m[4][6] = SPACEBAR;     
+    m[4][7] = SPACEBAR;
+    m[4][8] = SPACEBAR;
+    m[4][9] = APLICAR;
+    m[4][10] = APLICAR;
+}
+
+void Teclado::asignarMayusculas(){
+    // Primera fila
+    m[0][0] = 'Q';
+    m[0][1] = 'W';     
+    m[0][2] = 'E';
+    m[0][3] = 'R';
+    m[0][4] = 'T';
+    m[0][5] = 'Y';
+    m[0][6] = 'U';     
+    m[0][7] = 'I';
+    m[0][8] = 'O';
+    m[0][9] = 'P';
+    m[0][10] = '(';
+    
+    // Segunda fila
+    m[1][0] = 'A';
+    m[1][1] = 'S';     
+    m[1][2] = 'D';
+    m[1][3] = 'F';
+    m[1][4] = 'G';
+    m[1][5] = 'H';
+    m[1][6] = 'J';     
+    m[1][7] = 'K';
+    m[1][8] = 'L';
+    m[1][9] = 165;
+    m[1][10] = ')';
+    
+    // Tercera fila
+    m[2][0] = 'Z';
+    m[2][1] = 'X';     
+    m[2][2] = 'C';
+    m[2][3] = 'V';
+    m[2][4] = 'B';
+    m[2][5] = 'N';
+    m[2][6] = 'M';     
+    m[2][7] = ',';
+    m[2][8] = '.';
+    m[2][9] = ';';
+    m[2][10] = '_';
+    
+    // Cuarta fila
+    m[3][0] = '1';
+    m[3][1] = '2';     
+    m[3][2] = '3';
+    m[3][3] = '4';
+    m[3][4] = '5';
+    m[3][5] = '6';
+    m[3][6] = '7';     
+    m[3][7] = '8';
+    m[3][8] = '9';
+    m[3][9] = '0';
+    m[3][10] = BACK;
+    
+    // Quinta fila
+    m[4][0] = MAYUS;
+    m[4][1] = SPACEBAR;
+    m[4][2] = SPACEBAR;
+    m[4][3] = SPACEBAR;
+    m[4][4] = SPACEBAR;
+    m[4][5] = SPACEBAR;
+    m[4][6] = SPACEBAR;     
+    m[4][7] = SPACEBAR;
+    m[4][8] = SPACEBAR;
+    m[4][9] = APLICAR;
+    m[4][10] = APLICAR;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ScreenManager/Teclado.h	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,85 @@
+/**
+ * @author Juan Manuel Amador Olivares (virtualmech)
+ */
+#ifndef TECLADO_H
+#define TECLADO_H
+
+#include "Seleccion.h"
+#include "doggy.h"
+
+#define POSCADENAX 3
+#define OFFSETX 4            // Espacio en pixeles que se deja antes de escribir una linea de caracteres
+#define OFFSETY 4            // Espacio en pixeles que se deja antes de escribir una linea de caracteres en la parte superior
+#define CARACTER11 11     // Anchura de un caracter de media
+#define CARACTER8 8     // Anchura de un caracter de media
+#define WRITTENSPACE 9    // Pixeles de alto que requiere el espacio donde se irá mostrando lo que se está escribiendo con el teclado
+#define MAXCARACTERESESCRITURA 19   // Máximos caracteres que se pueden escribir para el nombre del archivo
+
+#define FILASMATRIZ 5
+#define COLUMNASMATRIZ 11
+
+
+/***************************
+    Para controlar la posición del teclado se va a hacer una matriz de 11x5. A cada elemento de la matriz se le asignará un valor (la letra correspondiente)
+    y valores especiales las teclas especiales:
+    
+    0-> espacio vacio
+    1-> borrar
+    2-> mayus
+    3-> barra espaciadora
+    4-> Aplicar
+    **************************/
+#define BACK 1
+#define MAYUS 2
+#define SPACEBAR 3
+#define APLICAR 4
+    
+#define ULTIMOCARACTERESPECIAL 4        // Se va a usar para comprobar si un elemento de la matrzi es un caracter especial o tecla especial
+
+
+// Lista de elementos seleccionables. Tamaño de caracteres 8. 
+class Teclado: public Seleccion{
+    public:
+    
+    virtual void initialize(DogMLCD* lcd);
+    int addElement(char text[], char nameNextScreen[NCARSCREEN]);
+    
+    char *getNombre();  // Devuelve un puntero al último nombre escrito con el teclado
+    
+    void setNextScreen(char nameScreen[NCARSCREEN]);
+    
+    virtual void button1pressed(DogMLCD* lcd);     // Esta función se llama cuando el botón superior es pulsado, definirla para añadir funcionalidades
+    virtual void button2pressed(DogMLCD* lcd);     // Esta función se llama cuando el botón superior es pulsado, definirla para añadir funcionalidades
+    virtual void button3pressed(DogMLCD* lcd);     // Esta función se llama cuando el botón superior es pulsado, definirla para añadir funcionalidades
+    virtual void button4pressed(DogMLCD* lcd);     // Esta función se llama cuando el botón inferior es pulsado, definirla para añadir funcionalidades
+    virtual void button5pressed(DogMLCD* lcd);     // Esta función se llama cuando el botón central es pulsado, definirla para añadir funcionalidades
+        
+    private:
+    
+    char nameNextScreen[NCARSCREEN];
+    
+    char m[FILASMATRIZ][COLUMNASMATRIZ];    
+    char Xsel, Ysel, lastXsel, lastYsel;          // posición x e y en la matriz del elemento seleccionado y el anterior
+    
+    char nombre[MAXCARACTERESESCRITURA+1];  // Guarda la cadena con el nombre escrito
+    char indiceEscritura;   // Indica por donde se va escribiendo en el recuadro
+
+    void mostrarCaracteres(DogMLCD* lcd);       // Muestra los caracteres de la matriz
+    void mostrarEspeciales(DogMLCD* lcd);       // Muestra los caracteres especiales
+    void asignarMinusculas();                   // Asigna a la matriz valores de caracteres de las letras minusculas
+    void asignarMayusculas();                   // Asigna a la matriz valores de caracteres de las letras minusculas
+    
+    void mostrarRecuadro(DogMLCD* lcd);         // Muestra el recuadro que señala lo que se está escribiendo
+    
+    // Cuadros seleccionables especiales
+    void seleccionarBarraEspaciadora(DogMLCD* lcd);
+    void deseleccionarBarraEspaciadora(DogMLCD* lcd);
+    
+    void seleccionarAplicar(DogMLCD* lcd);
+    void deseleccionarAplicar(DogMLCD* lcd);
+    
+    bool ifMayus;
+
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostLite/usbhost_cpu.h	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,35 @@
+/*
+**************************************************************************************************************
+*                                                 NXP USB Host Stack
+*
+*                                     (c) Copyright 2008, NXP SemiConductors
+*                                     (c) Copyright 2008, OnChip  Technologies LLC
+*                                                 All Rights Reserved
+*
+*                                                  www.nxp.com
+*                                               www.onchiptech.com
+*
+* File           : usbhost_cpu.h
+* Programmer(s)  : Ravikanth.P
+* Version        :
+*
+**************************************************************************************************************
+*/
+
+#ifndef  USBHOST_CPU_H
+#define  USBHOST_CPU_H
+
+/*
+**************************************************************************************************************
+*                                           TYPE DEFINITIONS OF DATA TYPES
+**************************************************************************************************************
+*/
+
+typedef  unsigned int    USB_INT32U;
+typedef  signed   int    USB_INT32S;
+typedef  unsigned short  USB_INT16U;
+typedef  signed   short  USB_INT16S;
+typedef  unsigned char   USB_INT08U;
+typedef  signed   char   USB_INT08S;
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostLite/usbhost_err.h	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,63 @@
+/*
+**************************************************************************************************************
+*                                                 NXP USB Host Stack
+*
+*                                     (c) Copyright 2008, NXP SemiConductors
+*                                     (c) Copyright 2008, OnChip  Technologies LLC
+*                                                 All Rights Reserved
+*
+*                                                  www.nxp.com
+*                                               www.onchiptech.com
+*
+* File           : usbhost_err.h
+* Programmer(s)  : Ravikanth.P
+* Version        :
+*
+**************************************************************************************************************
+*/
+
+#ifndef  USBHOST_ERR_H
+#define  USBHOST_ERR_H
+
+
+/*
+**************************************************************************************************************
+*                                        GENERAL DEFINITIONS
+**************************************************************************************************************
+*/
+
+#define  OK                        0
+#define  MATCH_FOUND               0
+
+/*
+**************************************************************************************************************
+*                                HOST CONTROLLER SPECIFIC ERROR CODES
+**************************************************************************************************************
+*/
+
+#define  ERR_TD_FAIL              -1
+
+/*
+**************************************************************************************************************
+*                                  MASS STORAGE SPECIFIC ERROR CODES
+**************************************************************************************************************
+*/
+
+#define  ERR_MS_CMD_FAILED       -10
+#define  ERR_BAD_CONFIGURATION   -11
+#define  ERR_NO_MS_INTERFACE     -12
+
+/*
+**************************************************************************************************************
+*                                      FAT SPECIFIC ERROR CODES
+**************************************************************************************************************
+*/
+
+#define  MATCH_NOT_FOUND         -20
+#define  ERR_FAT_NOT_SUPPORTED   -21
+#define  ERR_OPEN_LIMIT_REACHED  -22
+#define  ERR_INVALID_BOOT_SIG    -23
+#define  ERR_INVALID_BOOT_SEC    -24
+#define  ERR_ROOT_DIR_FULL       -25
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostLite/usbhost_inc.h	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,39 @@
+/*
+**************************************************************************************************************
+*                                                 NXP USB Host Stack
+*
+*                                     (c) Copyright 2008, NXP SemiConductors
+*                                     (c) Copyright 2008, OnChip  Technologies LLC
+*                                                 All Rights Reserved
+*
+*                                                  www.nxp.com
+*                                               www.onchiptech.com
+*
+* File           : usbhost_inc.h
+* Programmer(s)  : Ravikanth.P
+* Version        :
+*
+**************************************************************************************************************
+*/
+
+#ifndef  USBHOST_INC_H
+#define  USBHOST_INC_H
+
+/*
+**************************************************************************************************************
+*                                       INCLUDE HEADER FILES
+**************************************************************************************************************
+*/
+
+#include  "usbhost_cpu.h"
+#include  "usbhost_err.h"
+#include  "usbhost_lpc17xx.h"
+#include  "usbhost_ms.h"
+#include  "mbed.h"
+
+
+#ifdef TARGET_LPC2368
+#error "There is no USB host on the LPC2368!"
+#endif
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostLite/usbhost_lpc17xx.cpp	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,824 @@
+/*
+**************************************************************************************************************
+*                                                 NXP USB Host Stack
+*
+*                                     (c) Copyright 2008, NXP SemiConductors
+*                                     (c) Copyright 2008, OnChip  Technologies LLC
+*                                                 All Rights Reserved
+*
+*                                                  www.nxp.com
+*                                               www.onchiptech.com
+*
+* File           : usbhost_lpc17xx.c
+* Programmer(s)  : Ravikanth.P
+* Version        :
+*
+**************************************************************************************************************
+*/
+ 
+/*
+**************************************************************************************************************
+*                                            INCLUDE HEADER FILES
+**************************************************************************************************************
+*/
+#include "mbed.h"
+#include  "usbhost_lpc17xx.h"
+
+extern DigitalOut myled;
+extern Timer t;
+
+/*
+**************************************************************************************************************
+*                                              GLOBAL VARIABLES
+**************************************************************************************************************
+*/
+int gUSBConnected;
+
+volatile  USB_INT32U   HOST_RhscIntr = 0;         /* Root Hub Status Change interrupt                       */
+volatile  USB_INT32U   HOST_WdhIntr  = 0;         /* Semaphore to wait until the TD is submitted            */
+volatile  USB_INT08U   HOST_TDControlStatus = 0;
+volatile  HCED        *EDCtrl;                    /* Control endpoint descriptor structure                  */
+volatile  HCED        *EDBulkIn;                  /* BulkIn endpoint descriptor  structure                  */
+volatile  HCED        *EDBulkOut;                 /* BulkOut endpoint descriptor structure                  */
+volatile  HCTD        *TDHead;                    /* Head transfer descriptor structure                     */
+volatile  HCTD        *TDTail;                    /* Tail transfer descriptor structure                     */
+volatile  HCCA        *Hcca;                      /* Host Controller Communications Area structure          */ 
+          USB_INT16U  *TDBufNonVol;               /* Identical to TDBuffer just to reduce compiler warnings */
+volatile  USB_INT08U  *TDBuffer;                  /* Current Buffer Pointer of transfer descriptor          */
+
+// USB host structures
+// AHB SRAM block 1
+#define HOSTBASEADDR 0x2007C000
+// reserve memory for the linker
+static USB_INT08U HostBuf[0x200] __attribute__((at(HOSTBASEADDR)));
+/*
+**************************************************************************************************************
+*                                         DELAY IN MILLI SECONDS
+*
+* Description: This function provides a delay in milli seconds
+*
+* Arguments  : delay    The delay required
+*
+* Returns    : None
+*
+**************************************************************************************************************
+*/
+
+void  Host_DelayMS (USB_INT32U  delay)
+{
+    volatile  USB_INT32U  i;
+
+
+    for (i = 0; i < delay; i++) {
+        Host_DelayUS(1000);
+    }
+}
+
+/*
+**************************************************************************************************************
+*                                         DELAY IN MICRO SECONDS
+*
+* Description: This function provides a delay in micro seconds
+*
+* Arguments  : delay    The delay required
+*
+* Returns    : None
+*
+**************************************************************************************************************
+*/
+
+void  Host_DelayUS (USB_INT32U  delay)
+{
+    volatile  USB_INT32U  i;
+
+
+    for (i = 0; i < (4 * delay); i++) {    /* This logic was tested. It gives app. 1 micro sec delay        */
+        ;
+    }
+}
+
+// bits of the USB/OTG clock control register
+#define HOST_CLK_EN     (1<<0)
+#define DEV_CLK_EN      (1<<1)
+#define PORTSEL_CLK_EN  (1<<3)
+#define AHB_CLK_EN      (1<<4)
+
+// bits of the USB/OTG clock status register
+#define HOST_CLK_ON     (1<<0)
+#define DEV_CLK_ON      (1<<1)
+#define PORTSEL_CLK_ON  (1<<3)
+#define AHB_CLK_ON      (1<<4)
+
+// we need host clock, OTG/portsel clock and AHB clock
+#define CLOCK_MASK (HOST_CLK_EN | PORTSEL_CLK_EN | AHB_CLK_EN)
+
+/*
+**************************************************************************************************************
+*                                         INITIALIZE THE HOST CONTROLLER
+*
+* Description: This function initializes lpc17xx host controller
+*
+* Arguments  : None
+*
+* Returns    : 
+*
+**************************************************************************************************************
+*/
+void  Host_Init (void)
+{
+    PRINT_Log("In Host_Init\n");
+    NVIC_DisableIRQ(USB_IRQn);                           /* Disable the USB interrupt source           */
+    
+    // turn on power for USB
+    LPC_SC->PCONP       |= (1UL<<31);
+    // Enable USB host clock, port selection and AHB clock
+    LPC_USB->USBClkCtrl |= CLOCK_MASK;
+    // Wait for clocks to become available
+    while ((LPC_USB->USBClkSt & CLOCK_MASK) != CLOCK_MASK)
+        ;
+    
+    // it seems the bits[0:1] mean the following
+    // 0: U1=device, U2=host
+    // 1: U1=host, U2=host
+    // 2: reserved
+    // 3: U1=host, U2=device
+    // NB: this register is only available if OTG clock (aka "port select") is enabled!!
+    // since we don't care about port 2, set just bit 0 to 1 (U1=host)
+    LPC_USB->OTGStCtrl |= 1;
+    
+    // now that we've configured the ports, we can turn off the portsel clock
+    LPC_USB->USBClkCtrl &= ~PORTSEL_CLK_EN;
+    
+    // power pins are not connected on mbed, so we can skip them
+    /* P1[18] = USB_UP_LED, 01 */
+    /* P1[19] = /USB_PPWR,     10 */
+    /* P1[22] = USB_PWRD, 10 */
+    /* P1[27] = /USB_OVRCR, 10 */
+    /*LPC_PINCON->PINSEL3 &= ~((3<<4) | (3<<6) | (3<<12) | (3<<22));  
+    LPC_PINCON->PINSEL3 |=  ((1<<4)|(2<<6) | (2<<12) | (2<<22));   // 0x00802080
+    */
+
+    // configure USB D+/D- pins
+    /* P0[29] = USB_D+, 01 */
+    /* P0[30] = USB_D-, 01 */
+    LPC_PINCON->PINSEL1 &= ~((3<<26) | (3<<28));  
+    LPC_PINCON->PINSEL1 |=  ((1<<26)|(1<<28));     // 0x14000000
+        
+    PRINT_Log("Initializing Host Stack\n");
+
+    Hcca       = (volatile  HCCA       *)(HostBuf+0x000);
+    TDHead     = (volatile  HCTD       *)(HostBuf+0x100);
+    TDTail     = (volatile  HCTD       *)(HostBuf+0x110);
+    EDCtrl     = (volatile  HCED       *)(HostBuf+0x120); 
+    EDBulkIn   = (volatile  HCED       *)(HostBuf+0x130);
+    EDBulkOut  = (volatile  HCED       *)(HostBuf+0x140);
+    TDBuffer   = (volatile  USB_INT08U *)(HostBuf+0x150);
+    
+    /* Initialize all the TDs, EDs and HCCA to 0  */
+    Host_EDInit(EDCtrl);
+    Host_EDInit(EDBulkIn);
+    Host_EDInit(EDBulkOut);
+    Host_TDInit(TDHead);
+    Host_TDInit(TDTail);
+    Host_HCCAInit(Hcca);
+    
+    Host_DelayMS(50);                                   /* Wait 50 ms before apply reset              */
+    LPC_USB->HcControl       = 0;                       /* HARDWARE RESET                             */
+    LPC_USB->HcControlHeadED = 0;                       /* Initialize Control list head to Zero       */
+    LPC_USB->HcBulkHeadED    = 0;                       /* Initialize Bulk list head to Zero          */
+    
+                                                        /* SOFTWARE RESET                             */
+    LPC_USB->HcCommandStatus = OR_CMD_STATUS_HCR;
+    LPC_USB->HcFmInterval    = DEFAULT_FMINTERVAL;      /* Write Fm Interval and Largest Data Packet Counter */
+
+                                                        /* Put HC in operational state                */
+    LPC_USB->HcControl  = (LPC_USB->HcControl & (~OR_CONTROL_HCFS)) | OR_CONTROL_HC_OPER;
+    LPC_USB->HcRhStatus = OR_RH_STATUS_LPSC;            /* Set Global Power                           */
+    
+    LPC_USB->HcHCCA = (USB_INT32U)Hcca;
+    LPC_USB->HcInterruptStatus |= LPC_USB->HcInterruptStatus;                   /* Clear Interrrupt Status                    */
+
+
+    LPC_USB->HcInterruptEnable  = OR_INTR_ENABLE_MIE |
+                         OR_INTR_ENABLE_WDH |
+                         OR_INTR_ENABLE_RHSC;
+
+    NVIC_SetPriority(USB_IRQn, 0);       /* highest priority */
+    /* Enable the USB Interrupt */
+    NVIC_EnableIRQ(USB_IRQn);
+    PRINT_Log("Host Initialized\n");
+}
+
+/*
+**************************************************************************************************************
+*                                         INTERRUPT SERVICE ROUTINE
+*
+* Description: This function services the interrupt caused by host controller
+*
+* Arguments  : None
+*
+* Returns    : None
+*
+**************************************************************************************************************
+*/
+
+void USB_IRQHandler (void) __irq
+{
+    USB_INT32U   int_status;
+    USB_INT32U   ie_status;
+
+    int_status    = LPC_USB->HcInterruptStatus;                          /* Read Interrupt Status                */
+    ie_status     = LPC_USB->HcInterruptEnable;                          /* Read Interrupt enable status         */
+ 
+    if (!(int_status & ie_status)) {
+        return;
+    } else {
+
+        int_status = int_status & ie_status;
+        if (int_status & OR_INTR_STATUS_RHSC) {                 /* Root hub status change interrupt     */
+            if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_CSC) {
+                if (LPC_USB->HcRhStatus & OR_RH_STATUS_DRWE) {
+                    /*
+                     * When DRWE is on, Connect Status Change
+                     * means a remote wakeup event.
+                    */
+                    HOST_RhscIntr = 1;// JUST SOMETHING FOR A BREAKPOINT
+                }
+                else {
+                    /*
+                     * When DRWE is off, Connect Status Change
+                     * is NOT a remote wakeup event
+                    */
+                    if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_CCS) {
+                        if (!gUSBConnected) {
+                            HOST_TDControlStatus = 0;
+                            HOST_WdhIntr = 0;
+                            HOST_RhscIntr = 1;
+                            gUSBConnected = 1;
+                        }
+                        else
+                            PRINT_Log("Spurious status change (connected)?\n");
+                    } else {
+                        if (gUSBConnected) {
+                            LPC_USB->HcInterruptEnable = 0; // why do we get multiple disc. rupts???
+                            HOST_RhscIntr = 0;
+                            gUSBConnected = 0;
+                        }
+                        else
+                            PRINT_Log("Spurious status change (disconnected)?\n");
+                    }
+                }
+                LPC_USB->HcRhPortStatus1 = OR_RH_PORT_CSC;
+            }
+            if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_PRSC) {
+                LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC;
+            }
+        }
+        if (int_status & OR_INTR_STATUS_WDH) {                  /* Writeback Done Head interrupt        */
+            HOST_WdhIntr = 1;
+            HOST_TDControlStatus = (TDHead->Control >> 28) & 0xf;
+        }            
+        LPC_USB->HcInterruptStatus = int_status;                         /* Clear interrupt status register      */
+    }
+    return;
+}
+
+/*
+**************************************************************************************************************
+*                                     PROCESS TRANSFER DESCRIPTOR
+*
+* Description: This function processes the transfer descriptor
+*
+* Arguments  : ed            Endpoint descriptor that contains this transfer descriptor
+*              token         SETUP, IN, OUT
+*              buffer        Current Buffer Pointer of the transfer descriptor
+*              buffer_len    Length of the buffer
+*
+* Returns    : OK       if TD submission is successful
+*              ERROR    if TD submission fails
+*
+**************************************************************************************************************
+*/
+
+USB_INT32S  Host_ProcessTD (volatile  HCED       *ed,
+                            volatile  USB_INT32U  token,
+                            volatile  USB_INT08U *buffer,
+                                      USB_INT32U  buffer_len)
+{
+    volatile  USB_INT32U   td_toggle;
+
+
+    if (ed == EDCtrl) {
+        if (token == TD_SETUP) {
+            td_toggle = TD_TOGGLE_0;
+        } else {
+            td_toggle = TD_TOGGLE_1;
+        }
+    } else {
+        td_toggle = 0;
+    }
+    TDHead->Control = (TD_ROUNDING    |
+                      token           |
+                      TD_DELAY_INT(0) |                           
+                      td_toggle       |
+                      TD_CC);
+    TDTail->Control = 0;
+    TDHead->CurrBufPtr   = (USB_INT32U) buffer;
+    TDTail->CurrBufPtr   = 0;
+    TDHead->Next         = (USB_INT32U) TDTail;
+    TDTail->Next         = 0;
+    TDHead->BufEnd       = (USB_INT32U)(buffer + (buffer_len - 1));
+    TDTail->BufEnd       = 0;
+
+    ed->HeadTd  = (USB_INT32U)TDHead | ((ed->HeadTd) & 0x00000002);
+    ed->TailTd  = (USB_INT32U)TDTail;
+    ed->Next    = 0;
+
+    if (ed == EDCtrl) {
+        LPC_USB->HcControlHeadED = (USB_INT32U)ed;
+        LPC_USB->HcCommandStatus = LPC_USB->HcCommandStatus | OR_CMD_STATUS_CLF;
+        LPC_USB->HcControl       = LPC_USB->HcControl       | OR_CONTROL_CLE;
+    } else {
+        LPC_USB->HcBulkHeadED    = (USB_INT32U)ed;
+        LPC_USB->HcCommandStatus = LPC_USB->HcCommandStatus | OR_CMD_STATUS_BLF;
+        LPC_USB->HcControl       = LPC_USB->HcControl       | OR_CONTROL_BLE;
+    }    
+
+    Host_WDHWait();
+
+//    if (!(TDHead->Control & 0xF0000000)) {
+    if (!HOST_TDControlStatus) {
+        return (OK);
+    } else {      
+        return (ERR_TD_FAIL);
+    }
+}
+
+/*
+**************************************************************************************************************
+*                                       ENUMERATE THE DEVICE
+*
+* Description: This function is used to enumerate the device connected
+*
+* Arguments  : None
+*
+* Returns    : None
+*
+**************************************************************************************************************
+*/
+
+USB_INT32S  Host_EnumDev (void)
+{
+    USB_INT32S  rc;
+
+    PRINT_Log("Connect a Mass Storage device\n");
+    while (!HOST_RhscIntr)
+        __WFI();
+    myled = 1;
+    Host_DelayMS(100);                             /* USB 2.0 spec says atleast 50ms delay beore port reset */
+    LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRS; // Initiate port reset
+    while (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_PRS)
+        __WFI(); // Wait for port reset to complete...
+    LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC; // ...and clear port reset signal
+    Host_DelayMS(200);                                                 /* Wait for 100 MS after port reset  */
+
+    EDCtrl->Control = 8 << 16;                                         /* Put max pkt size = 8              */
+                                                                       /* Read first 8 bytes of device desc */
+    rc = HOST_GET_DESCRIPTOR(USB_DESCRIPTOR_TYPE_DEVICE, 0, TDBuffer, 8);
+    if (rc != OK) {
+        PRINT_Err(rc);
+        return (rc);
+    }
+    EDCtrl->Control = TDBuffer[7] << 16;                               /* Get max pkt size of endpoint 0    */
+    rc = HOST_SET_ADDRESS(1);                                          /* Set the device address to 1       */
+    if (rc != OK) {
+        PRINT_Err(rc);
+        return (rc);
+    }
+    Host_DelayMS(2);
+    EDCtrl->Control = (EDCtrl->Control) | 1;                          /* Modify control pipe with address 1 */
+                                                                      /* Get the configuration descriptor   */
+    rc = HOST_GET_DESCRIPTOR(USB_DESCRIPTOR_TYPE_CONFIGURATION, 0, TDBuffer, 9);
+    if (rc != OK) {
+        PRINT_Err(rc);
+        return (rc);
+    }
+                                                                       /* Get the first configuration data  */
+    rc = HOST_GET_DESCRIPTOR(USB_DESCRIPTOR_TYPE_CONFIGURATION, 0, TDBuffer, ReadLE16U(&TDBuffer[2]));
+    if (rc != OK) {
+        PRINT_Err(rc);
+        return (rc);
+    }
+    rc = MS_ParseConfiguration();                                      /* Parse the configuration           */
+    if (rc != OK) {
+        PRINT_Err(rc);
+        return (rc);
+    }
+    rc = USBH_SET_CONFIGURATION(1);                                    /* Select device configuration 1     */
+    if (rc != OK) {
+        PRINT_Err(rc);
+    }
+    Host_DelayMS(100);                                               /* Some devices may require this delay */
+    return (rc);
+}
+
+/*
+**************************************************************************************************************
+*                                        RECEIVE THE CONTROL INFORMATION
+*
+* Description: This function is used to receive the control information
+*
+* Arguments  : bm_request_type
+*              b_request
+*              w_value
+*              w_index
+*              w_length
+*              buffer
+*
+* Returns    : OK       if Success
+*              ERROR    if Failed
+*
+**************************************************************************************************************
+*/
+   
+USB_INT32S  Host_CtrlRecv (         USB_INT08U   bm_request_type,
+                                    USB_INT08U   b_request,
+                                    USB_INT16U   w_value,
+                                    USB_INT16U   w_index,
+                                    USB_INT16U   w_length,
+                          volatile  USB_INT08U  *buffer)
+{
+    USB_INT32S  rc;
+
+
+    Host_FillSetup(bm_request_type, b_request, w_value, w_index, w_length);
+    rc = Host_ProcessTD(EDCtrl, TD_SETUP, TDBuffer, 8);
+    if (rc == OK) {
+        if (w_length) {
+            rc = Host_ProcessTD(EDCtrl, TD_IN, TDBuffer, w_length);
+        }
+        if (rc == OK) {
+            rc = Host_ProcessTD(EDCtrl, TD_OUT, NULL, 0);
+        }
+    }
+    return (rc);
+}
+
+/*
+**************************************************************************************************************
+*                                         SEND THE CONTROL INFORMATION
+*
+* Description: This function is used to send the control information
+*
+* Arguments  : None
+*
+* Returns    : OK                      if Success
+*              ERR_INVALID_BOOTSIG    if Failed
+*
+**************************************************************************************************************
+*/
+
+USB_INT32S  Host_CtrlSend (          USB_INT08U   bm_request_type,
+                                     USB_INT08U   b_request,
+                                     USB_INT16U   w_value,
+                                     USB_INT16U   w_index,
+                                     USB_INT16U   w_length,
+                           volatile  USB_INT08U  *buffer)
+{
+    USB_INT32S  rc;
+
+
+    Host_FillSetup(bm_request_type, b_request, w_value, w_index, w_length);
+
+    rc = Host_ProcessTD(EDCtrl, TD_SETUP, TDBuffer, 8);
+    if (rc == OK) {
+        if (w_length) {
+            rc = Host_ProcessTD(EDCtrl, TD_OUT, TDBuffer, w_length);
+        }
+        if (rc == OK) {
+            rc = Host_ProcessTD(EDCtrl, TD_IN, NULL, 0);
+        }
+    }
+    return (rc);
+}
+
+/*
+**************************************************************************************************************
+*                                          FILL SETUP PACKET
+*
+* Description: This function is used to fill the setup packet
+*
+* Arguments  : None
+*
+* Returns    : OK                      if Success
+*              ERR_INVALID_BOOTSIG    if Failed
+*
+**************************************************************************************************************
+*/
+
+void  Host_FillSetup (USB_INT08U   bm_request_type,
+                      USB_INT08U   b_request,
+                      USB_INT16U   w_value,
+                      USB_INT16U   w_index,
+                      USB_INT16U   w_length)
+{
+    int i;
+    for (i=0;i<w_length;i++)
+        TDBuffer[i] = 0;
+    
+    TDBuffer[0] = bm_request_type;
+    TDBuffer[1] = b_request;
+    WriteLE16U(&TDBuffer[2], w_value);
+    WriteLE16U(&TDBuffer[4], w_index);
+    WriteLE16U(&TDBuffer[6], w_length);
+}
+
+
+
+/*
+**************************************************************************************************************
+*                                         INITIALIZE THE TRANSFER DESCRIPTOR
+*
+* Description: This function initializes transfer descriptor
+*
+* Arguments  : Pointer to TD structure
+*
+* Returns    : None
+*
+**************************************************************************************************************
+*/
+
+void  Host_TDInit (volatile  HCTD *td)
+{
+
+    td->Control    = 0;
+    td->CurrBufPtr = 0;
+    td->Next       = 0;
+    td->BufEnd     = 0;
+}
+
+/*
+**************************************************************************************************************
+*                                         INITIALIZE THE ENDPOINT DESCRIPTOR
+*
+* Description: This function initializes endpoint descriptor
+*
+* Arguments  : Pointer to ED strcuture
+*
+* Returns    : None
+*
+**************************************************************************************************************
+*/
+
+void  Host_EDInit (volatile  HCED *ed)
+{
+
+    ed->Control = 0;
+    ed->TailTd  = 0;
+    ed->HeadTd  = 0;
+    ed->Next    = 0;
+}
+
+/*
+**************************************************************************************************************
+*                                 INITIALIZE HOST CONTROLLER COMMUNICATIONS AREA
+*
+* Description: This function initializes host controller communications area
+*
+* Arguments  : Pointer to HCCA
+*
+* Returns    : 
+*
+**************************************************************************************************************
+*/
+
+void  Host_HCCAInit (volatile  HCCA  *hcca)
+{
+    USB_INT32U  i;
+
+
+    for (i = 0; i < 32; i++) {
+
+        hcca->IntTable[i] = 0;
+        hcca->FrameNumber = 0;
+        hcca->DoneHead    = 0;
+    }
+
+}
+
+/*
+**************************************************************************************************************
+*                                         WAIT FOR WDH INTERRUPT
+*
+* Description: This function is infinite loop which breaks when ever a WDH interrupt rises
+*
+* Arguments  : None
+*
+* Returns    : None
+*
+**************************************************************************************************************
+*/
+
+void  Host_WDHWait (void)
+{
+  while (!HOST_WdhIntr)
+      __WFI();
+
+  HOST_WdhIntr = 0;
+}
+
+/*
+**************************************************************************************************************
+*                                         READ LE 32U
+*
+* Description: This function is used to read an unsigned integer from a character buffer in the platform
+*              containing little endian processor
+*
+* Arguments  : pmem    Pointer to the character buffer
+*
+* Returns    : val     Unsigned integer
+*
+**************************************************************************************************************
+*/
+
+USB_INT32U  ReadLE32U (volatile  USB_INT08U  *pmem)
+{
+    USB_INT32U val = *(USB_INT32U*)pmem;
+#ifdef __BIG_ENDIAN
+    return __REV(val);
+#else
+    return val;
+#endif    
+}
+
+/*
+**************************************************************************************************************
+*                                        WRITE LE 32U
+*
+* Description: This function is used to write an unsigned integer into a charecter buffer in the platform 
+*              containing little endian processor.
+*
+* Arguments  : pmem    Pointer to the charecter buffer
+*              val     Integer value to be placed in the charecter buffer
+*
+* Returns    : None
+*
+**************************************************************************************************************
+*/
+
+void  WriteLE32U (volatile  USB_INT08U  *pmem,
+                            USB_INT32U   val)
+{
+#ifdef __BIG_ENDIAN
+    *(USB_INT32U*)pmem = __REV(val);
+#else
+    *(USB_INT32U*)pmem = val;
+#endif
+}
+
+/*
+**************************************************************************************************************
+*                                          READ LE 16U
+*
+* Description: This function is used to read an unsigned short integer from a charecter buffer in the platform
+*              containing little endian processor
+*
+* Arguments  : pmem    Pointer to the charecter buffer
+*
+* Returns    : val     Unsigned short integer
+*
+**************************************************************************************************************
+*/
+
+USB_INT16U  ReadLE16U (volatile  USB_INT08U  *pmem)
+{
+    USB_INT16U val = *(USB_INT16U*)pmem;
+#ifdef __BIG_ENDIAN
+    return __REV16(val);
+#else
+    return val;
+#endif    
+}
+
+/*
+**************************************************************************************************************
+*                                         WRITE LE 16U
+*
+* Description: This function is used to write an unsigned short integer into a charecter buffer in the
+*              platform containing little endian processor
+*
+* Arguments  : pmem    Pointer to the charecter buffer
+*              val     Value to be placed in the charecter buffer
+*
+* Returns    : None
+*
+**************************************************************************************************************
+*/
+
+void  WriteLE16U (volatile  USB_INT08U  *pmem,
+                            USB_INT16U   val)
+{
+#ifdef __BIG_ENDIAN
+    *(USB_INT16U*)pmem = (__REV16(val) & 0xFFFF);
+#else
+    *(USB_INT16U*)pmem = val;
+#endif
+}
+
+/*
+**************************************************************************************************************
+*                                         READ BE 32U
+*
+* Description: This function is used to read an unsigned integer from a charecter buffer in the platform
+*              containing big endian processor
+*
+* Arguments  : pmem    Pointer to the charecter buffer
+*
+* Returns    : val     Unsigned integer
+*
+**************************************************************************************************************
+*/
+
+USB_INT32U  ReadBE32U (volatile  USB_INT08U  *pmem)
+{
+    USB_INT32U val = *(USB_INT32U*)pmem;
+#ifdef __BIG_ENDIAN
+    return val;
+#else
+    return __REV(val);
+#endif
+}
+
+/*
+**************************************************************************************************************
+*                                         WRITE BE 32U
+*
+* Description: This function is used to write an unsigned integer into a charecter buffer in the platform
+*              containing big endian processor
+*
+* Arguments  : pmem    Pointer to the charecter buffer
+*              val     Value to be placed in the charecter buffer
+*
+* Returns    : None
+*
+**************************************************************************************************************
+*/
+
+void  WriteBE32U (volatile  USB_INT08U  *pmem,
+                            USB_INT32U   val)
+{
+#ifdef __BIG_ENDIAN
+    *(USB_INT32U*)pmem = val;
+#else
+    *(USB_INT32U*)pmem = __REV(val);
+#endif
+}
+
+/*
+**************************************************************************************************************
+*                                         READ BE 16U
+*
+* Description: This function is used to read an unsigned short integer from a charecter buffer in the platform
+*              containing big endian processor
+*
+* Arguments  : pmem    Pointer to the charecter buffer
+*
+* Returns    : val     Unsigned short integer
+*
+**************************************************************************************************************
+*/
+
+USB_INT16U  ReadBE16U (volatile  USB_INT08U  *pmem)
+{
+    USB_INT16U val = *(USB_INT16U*)pmem;
+#ifdef __BIG_ENDIAN
+    return val;
+#else
+    return __REV16(val);
+#endif    
+}
+
+/*
+**************************************************************************************************************
+*                                         WRITE BE 16U
+*
+* Description: This function is used to write an unsigned short integer into the charecter buffer in the
+*              platform containing big endian processor
+*
+* Arguments  : pmem    Pointer to the charecter buffer
+*              val     Value to be placed in the charecter buffer
+*
+* Returns    : None
+*
+**************************************************************************************************************
+*/
+
+void  WriteBE16U (volatile  USB_INT08U  *pmem,
+                            USB_INT16U   val)
+{
+#ifdef __BIG_ENDIAN
+    *(USB_INT16U*)pmem = val;
+#else
+    *(USB_INT16U*)pmem = (__REV16(val) & 0xFFFF);
+#endif
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostLite/usbhost_lpc17xx.h	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,254 @@
+/*
+**************************************************************************************************************
+*                                                 NXP USB Host Stack
+*
+*                                     (c) Copyright 2008, NXP SemiConductors
+*                                     (c) Copyright 2008, OnChip  Technologies LLC
+*                                                 All Rights Reserved
+*
+*                                                  www.nxp.com
+*                                               www.onchiptech.com
+*
+* File           : usbhost_lpc17xx.h
+* Programmer(s)  : Ravikanth.P
+* Version        :
+*
+**************************************************************************************************************
+*/
+
+#ifndef USBHOST_LPC17xx_H
+#define USBHOST_LPC17xx_H
+
+/*
+**************************************************************************************************************
+*                                       INCLUDE HEADER FILES
+**************************************************************************************************************
+*/
+
+#include    "usbhost_inc.h"
+
+/*
+**************************************************************************************************************
+*                                        PRINT CONFIGURATION
+**************************************************************************************************************
+*/
+
+#define  PRINT_ENABLE         1
+
+#if PRINT_ENABLE
+#define  PRINT_Log(...)       printf(__VA_ARGS__)
+#define  PRINT_Err(rc)        printf("ERROR: In %s at Line %u - rc = %d\n", __FUNCTION__, __LINE__, rc)
+
+#else 
+#define  PRINT_Log(...)       do {} while(0)
+#define  PRINT_Err(rc)        do {} while(0)
+
+#endif
+
+/*
+**************************************************************************************************************
+*                                        GENERAL DEFINITIONS
+**************************************************************************************************************
+*/
+
+#define  DESC_LENGTH(x)  x[0]
+#define  DESC_TYPE(x)    x[1]
+
+
+#define  HOST_GET_DESCRIPTOR(descType, descIndex, data, length)                      \
+         Host_CtrlRecv(USB_DEVICE_TO_HOST | USB_RECIPIENT_DEVICE, GET_DESCRIPTOR,    \
+         (descType << 8)|(descIndex), 0, length, data)
+
+#define  HOST_SET_ADDRESS(new_addr)                                                  \
+         Host_CtrlSend(USB_HOST_TO_DEVICE | USB_RECIPIENT_DEVICE, SET_ADDRESS,       \
+         new_addr, 0, 0, NULL)
+
+#define  USBH_SET_CONFIGURATION(configNum)                                           \
+         Host_CtrlSend(USB_HOST_TO_DEVICE | USB_RECIPIENT_DEVICE, SET_CONFIGURATION, \
+         configNum, 0, 0, NULL)
+
+#define  USBH_SET_INTERFACE(ifNum, altNum)                                           \
+         Host_CtrlSend(USB_HOST_TO_DEVICE | USB_RECIPIENT_INTERFACE, SET_INTERFACE,  \
+         altNum, ifNum, 0, NULL)
+
+/*
+**************************************************************************************************************
+*                                  OHCI OPERATIONAL REGISTER FIELD DEFINITIONS
+**************************************************************************************************************
+*/
+
+                                            /* ------------------ HcControl Register ---------------------  */
+#define  OR_CONTROL_CLE                 0x00000010
+#define  OR_CONTROL_BLE                 0x00000020
+#define  OR_CONTROL_HCFS                0x000000C0
+#define  OR_CONTROL_HC_OPER             0x00000080
+                                            /* ----------------- HcCommandStatus Register ----------------- */
+#define  OR_CMD_STATUS_HCR              0x00000001
+#define  OR_CMD_STATUS_CLF              0x00000002
+#define  OR_CMD_STATUS_BLF              0x00000004
+                                            /* --------------- HcInterruptStatus Register ----------------- */
+#define  OR_INTR_STATUS_WDH             0x00000002
+#define  OR_INTR_STATUS_RHSC            0x00000040
+                                            /* --------------- HcInterruptEnable Register ----------------- */
+#define  OR_INTR_ENABLE_WDH             0x00000002
+#define  OR_INTR_ENABLE_RHSC            0x00000040
+#define  OR_INTR_ENABLE_MIE             0x80000000
+                                            /* ---------------- HcRhDescriptorA Register ------------------ */
+#define  OR_RH_STATUS_LPSC              0x00010000
+#define  OR_RH_STATUS_DRWE              0x00008000
+                                            /* -------------- HcRhPortStatus[1:NDP] Register -------------- */
+#define  OR_RH_PORT_CCS                 0x00000001
+#define  OR_RH_PORT_PRS                 0x00000010
+#define  OR_RH_PORT_CSC                 0x00010000
+#define  OR_RH_PORT_PRSC                0x00100000
+
+
+/*
+**************************************************************************************************************
+*                                               FRAME INTERVAL
+**************************************************************************************************************
+*/
+
+#define  FI                     0x2EDF           /* 12000 bits per frame (-1)                               */
+#define  DEFAULT_FMINTERVAL     ((((6 * (FI - 210)) / 7) << 16) | FI)
+
+/*
+**************************************************************************************************************
+*                                       TRANSFER DESCRIPTOR CONTROL FIELDS
+**************************************************************************************************************
+*/
+
+#define  TD_ROUNDING        (USB_INT32U) (0x00040000)        /* Buffer Rounding                             */
+#define  TD_SETUP           (USB_INT32U)(0)                  /* Direction of Setup Packet                   */
+#define  TD_IN              (USB_INT32U)(0x00100000)         /* Direction In                                */
+#define  TD_OUT             (USB_INT32U)(0x00080000)         /* Direction Out                               */
+#define  TD_DELAY_INT(x)    (USB_INT32U)((x) << 21)          /* Delay Interrupt                             */
+#define  TD_TOGGLE_0        (USB_INT32U)(0x02000000)         /* Toggle 0                                    */
+#define  TD_TOGGLE_1        (USB_INT32U)(0x03000000)         /* Toggle 1                                    */
+#define  TD_CC              (USB_INT32U)(0xF0000000)         /* Completion Code                             */
+
+/*
+**************************************************************************************************************
+*                                       USB STANDARD REQUEST DEFINITIONS
+**************************************************************************************************************
+*/
+
+#define  USB_DESCRIPTOR_TYPE_DEVICE                     1
+#define  USB_DESCRIPTOR_TYPE_CONFIGURATION              2
+#define  USB_DESCRIPTOR_TYPE_INTERFACE                  4
+#define  USB_DESCRIPTOR_TYPE_ENDPOINT                   5
+                                                    /*  ----------- Control RequestType Fields  ----------- */
+#define  USB_DEVICE_TO_HOST         0x80
+#define  USB_HOST_TO_DEVICE         0x00
+#define  USB_REQUEST_TYPE_CLASS     0x20
+#define  USB_RECIPIENT_DEVICE       0x00
+#define  USB_RECIPIENT_INTERFACE    0x01
+                                                    /* -------------- USB Standard Requests  -------------- */
+#define  SET_ADDRESS                 5
+#define  GET_DESCRIPTOR              6
+#define  SET_CONFIGURATION           9
+#define  SET_INTERFACE              11
+
+/*
+**************************************************************************************************************
+*                                       TYPE DEFINITIONS
+**************************************************************************************************************
+*/
+
+typedef struct hcEd {                       /* ----------- HostController EndPoint Descriptor ------------- */
+    volatile  USB_INT32U  Control;              /* Endpoint descriptor control                              */
+    volatile  USB_INT32U  TailTd;               /* Physical address of tail in Transfer descriptor list     */
+    volatile  USB_INT32U  HeadTd;               /* Physcial address of head in Transfer descriptor list     */
+    volatile  USB_INT32U  Next;                 /* Physical address of next Endpoint descriptor             */
+} HCED;
+
+typedef struct hcTd {                       /* ------------ HostController Transfer Descriptor ------------ */
+    volatile  USB_INT32U  Control;              /* Transfer descriptor control                              */
+    volatile  USB_INT32U  CurrBufPtr;           /* Physical address of current buffer pointer               */
+    volatile  USB_INT32U  Next;                 /* Physical pointer to next Transfer Descriptor             */
+    volatile  USB_INT32U  BufEnd;               /* Physical address of end of buffer                        */
+} HCTD;
+
+typedef struct hcca {                       /* ----------- Host Controller Communication Area ------------  */
+    volatile  USB_INT32U  IntTable[32];         /* Interrupt Table                                          */
+    volatile  USB_INT32U  FrameNumber;          /* Frame Number                                             */
+    volatile  USB_INT32U  DoneHead;             /* Done Head                                                */
+    volatile  USB_INT08U  Reserved[116];        /* Reserved for future use                                  */
+    volatile  USB_INT08U  Unknown[4];           /* Unused                                                   */
+} HCCA;
+
+/*
+**************************************************************************************************************
+*                                     EXTERN DECLARATIONS
+**************************************************************************************************************
+*/
+
+extern  volatile  HCED        *EDBulkIn;        /* BulkIn endpoint descriptor  structure                    */
+extern  volatile  HCED        *EDBulkOut;       /* BulkOut endpoint descriptor structure                    */
+extern  volatile  HCTD        *TDHead;          /* Head transfer descriptor structure                       */
+extern  volatile  HCTD        *TDTail;          /* Tail transfer descriptor structure                       */
+extern  volatile  USB_INT08U  *TDBuffer;        /* Current Buffer Pointer of transfer descriptor            */
+
+/*
+**************************************************************************************************************
+*                                       FUNCTION PROTOTYPES
+**************************************************************************************************************
+*/
+
+void        Host_Init     (void);
+
+extern "C" void USB_IRQHandler(void)  __irq;
+
+USB_INT32S  Host_EnumDev  (void);
+
+USB_INT32S  Host_ProcessTD(volatile  HCED       *ed,
+                           volatile  USB_INT32U  token,
+                           volatile  USB_INT08U *buffer,
+                                     USB_INT32U  buffer_len);
+
+void        Host_DelayUS  (          USB_INT32U    delay);
+void        Host_DelayMS  (          USB_INT32U    delay);
+
+
+void        Host_TDInit   (volatile  HCTD *td);
+void        Host_EDInit   (volatile  HCED *ed);
+void        Host_HCCAInit (volatile  HCCA  *hcca);
+
+USB_INT32S  Host_CtrlRecv (          USB_INT08U   bm_request_type,
+                                     USB_INT08U   b_request,
+                                     USB_INT16U   w_value,
+                                     USB_INT16U   w_index,
+                                     USB_INT16U   w_length,
+                           volatile  USB_INT08U  *buffer);
+
+USB_INT32S  Host_CtrlSend (          USB_INT08U   bm_request_type,
+                                     USB_INT08U   b_request,
+                                     USB_INT16U   w_value,
+                                     USB_INT16U   w_index,
+                                     USB_INT16U   w_length,
+                           volatile  USB_INT08U  *buffer);
+
+void        Host_FillSetup(          USB_INT08U   bm_request_type,
+                                     USB_INT08U   b_request,
+                                     USB_INT16U   w_value,
+                                     USB_INT16U   w_index,
+                                     USB_INT16U   w_length);
+
+
+void        Host_WDHWait  (void);
+
+
+USB_INT32U  ReadLE32U     (volatile  USB_INT08U  *pmem);
+void        WriteLE32U    (volatile  USB_INT08U  *pmem,
+                                     USB_INT32U   val);
+USB_INT16U  ReadLE16U     (volatile  USB_INT08U  *pmem);
+void        WriteLE16U    (volatile  USB_INT08U  *pmem,
+                                     USB_INT16U   val);
+USB_INT32U  ReadBE32U     (volatile  USB_INT08U  *pmem);
+void        WriteBE32U    (volatile  USB_INT08U  *pmem,
+                                     USB_INT32U   val);
+USB_INT16U  ReadBE16U     (volatile  USB_INT08U  *pmem);
+void        WriteBE16U    (volatile  USB_INT08U  *pmem,
+                                     USB_INT16U   val);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostLite/usbhost_ms.cpp	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,455 @@
+/*
+**************************************************************************************************************
+*                                                 NXP USB Host Stack
+*
+*                                     (c) Copyright 2008, NXP SemiConductors
+*                                     (c) Copyright 2008, OnChip  Technologies LLC
+*                                                 All Rights Reserved
+*
+*                                                  www.nxp.com
+*                                               www.onchiptech.com
+*
+* File           : usbhost_ms.c
+* Programmer(s)  : Ravikanth.P
+* Version        :
+*
+**************************************************************************************************************
+*/
+
+/*
+**************************************************************************************************************
+*                                       INCLUDE HEADER FILES
+**************************************************************************************************************
+*/
+
+#include  "usbhost_ms.h"
+
+/*
+**************************************************************************************************************
+*                                         GLOBAL VARIABLES
+**************************************************************************************************************
+*/
+
+USB_INT32U  MS_BlkSize;
+
+/*
+**************************************************************************************************************
+*                                      INITIALIZE MASS STORAGE INTERFACE
+*
+* Description: This function initializes the mass storage interface
+*
+* Arguments  : None
+*
+* Returns    : OK                      if Success
+*              ERR_INVALID_BOOTSIG    if Failed
+*
+**************************************************************************************************************
+*/
+
+USB_INT32S MS_Init (USB_INT32U *blkSize, USB_INT32U *numBlks, USB_INT08U *inquiryResult)
+{
+    USB_INT08U  retry;
+    USB_INT32S  rc;
+
+    MS_GetMaxLUN();                                                    /* Get maximum logical unit number   */
+    retry  = 80;
+    while(retry) {
+        rc = MS_TestUnitReady();                                       /* Test whether the unit is ready    */
+        if (rc == OK) {
+            break;
+        }
+        MS_GetSenseInfo();                                             /* Get sense information             */
+        retry--;
+    }
+    if (rc != OK) {
+        PRINT_Err(rc);
+        return (rc);
+    }
+    rc = MS_ReadCapacity(numBlks, blkSize);                         /* Read capacity of the disk         */
+    MS_BlkSize = *blkSize;                        // Set global
+    rc = MS_Inquire (inquiryResult);
+    return (rc);
+}
+/*
+**************************************************************************************************************
+*                                         PARSE THE CONFIGURATION
+*
+* Description: This function is used to parse the configuration
+*
+* Arguments  : None
+*
+* Returns    : OK                      if Success
+*              ERR_INVALID_BOOTSIG    if Failed
+*
+**************************************************************************************************************
+*/
+
+USB_INT32S  MS_ParseConfiguration (void)
+{
+    volatile  USB_INT08U  *desc_ptr;
+              USB_INT08U   ms_int_found;
+
+
+    desc_ptr     = TDBuffer;
+    ms_int_found = 0;
+
+    if (desc_ptr[1] != USB_DESCRIPTOR_TYPE_CONFIGURATION) {    
+        return (ERR_BAD_CONFIGURATION);
+    }
+    desc_ptr += desc_ptr[0];
+
+    while (desc_ptr != TDBuffer + ReadLE16U(&TDBuffer[2])) {
+
+        switch (desc_ptr[1]) {
+
+            case USB_DESCRIPTOR_TYPE_INTERFACE:                       /* If it is an interface descriptor   */
+                 if (desc_ptr[5] == MASS_STORAGE_CLASS &&             /* check if the class is mass storage */
+                     desc_ptr[6] == MASS_STORAGE_SUBCLASS_SCSI &&     /* check if the subclass is SCSI      */
+                     desc_ptr[7] == MASS_STORAGE_PROTOCOL_BO) {       /* check if the protocol is Bulk only */
+                     ms_int_found = 1;
+                     desc_ptr    += desc_ptr[0];                      /* Move to next descriptor start      */
+                 }
+                 break;
+
+            case USB_DESCRIPTOR_TYPE_ENDPOINT:                        /* If it is an endpoint descriptor    */
+                 if ((desc_ptr[3] & 0x03) == 0x02) {                  /* If it is Bulk endpoint             */
+                     if (desc_ptr[2] & 0x80) {                        /* If it is In endpoint               */
+                         EDBulkIn->Control =  1                             |      /* USB address           */
+                                              ((desc_ptr[2] & 0x7F) << 7)   |      /* Endpoint address      */
+                                              (2 << 11)                     |      /* direction             */
+                                              (ReadLE16U(&desc_ptr[4]) << 16);     /* MaxPkt Size           */
+                         desc_ptr += desc_ptr[0];                     /* Move to next descriptor start      */
+                     } else {                                         /* If it is Out endpoint              */
+                         EDBulkOut->Control = 1                             |      /* USB address           */
+                                              ((desc_ptr[2] & 0x7F) << 7)   |      /* Endpoint address      */
+                                              (1 << 11)                     |      /* direction             */
+                                              (ReadLE16U(&desc_ptr[4]) << 16);     /* MaxPkt Size           */
+                         desc_ptr += desc_ptr[0];                     /* Move to next descriptor start      */
+                     }
+                 } else {                                             /* If it is not bulk end point        */
+                     desc_ptr += desc_ptr[0];                         /* Move to next descriptor start      */
+                 }
+                 break;
+
+            default:                                 /* If the descriptor is neither interface nor endpoint */
+                 desc_ptr += desc_ptr[0];                             /* Move to next descriptor start      */
+                 break;
+        }
+    }
+    if (ms_int_found) {
+        PRINT_Log("Mass Storage device connected\n");
+        return (OK);
+    } else {
+        PRINT_Log("Not a Mass Storage device\n");
+        return (ERR_NO_MS_INTERFACE);
+    }
+}
+
+/*
+**************************************************************************************************************
+*                                         GET MAXIMUM LOGICAL UNIT
+*
+* Description: This function returns the maximum logical unit from the device
+*
+* Arguments  : None
+*
+* Returns    : OK                      if Success
+*              ERR_INVALID_BOOTSIG    if Failed
+*
+**************************************************************************************************************
+*/
+
+USB_INT32S  MS_GetMaxLUN (void)
+{
+    USB_INT32S  rc;
+
+
+    rc = Host_CtrlRecv(USB_DEVICE_TO_HOST | USB_REQUEST_TYPE_CLASS | USB_RECIPIENT_INTERFACE,
+                       MS_GET_MAX_LUN_REQ,
+                       0,
+                       0,
+                       1,
+                       TDBuffer);
+    return (rc); 
+}
+
+/*
+**************************************************************************************************************
+*                                          GET SENSE INFORMATION
+*
+* Description: This function is used to get sense information from the device
+*
+* Arguments  : None
+*
+* Returns    : OK       if Success
+*              ERROR    if Failed
+*
+**************************************************************************************************************
+*/
+
+USB_INT32S  MS_GetSenseInfo (void)
+{
+    USB_INT32S  rc;
+
+
+    Fill_MSCommand(0, 0, 0, MS_DATA_DIR_IN, SCSI_CMD_REQUEST_SENSE, 6);
+    rc = Host_ProcessTD(EDBulkOut, TD_OUT, TDBuffer, CBW_SIZE);
+    if (rc == OK) {
+        rc = Host_ProcessTD(EDBulkIn, TD_IN, TDBuffer, 18);
+        if (rc == OK) {
+            rc = Host_ProcessTD(EDBulkIn, TD_IN, TDBuffer, CSW_SIZE);
+            if (rc == OK) {
+                if (TDBuffer[12] != 0) {
+                    rc = ERR_MS_CMD_FAILED;
+                }
+            }
+        }
+    }
+    return (rc);
+}
+
+/*
+**************************************************************************************************************
+*                                           TEST UNIT READY
+*
+* Description: This function is used to test whether the unit is ready or not
+*
+* Arguments  : None
+*
+* Returns    : OK       if Success
+*              ERROR    if Failed
+*
+**************************************************************************************************************
+*/
+
+USB_INT32S  MS_TestUnitReady (void)
+{
+    USB_INT32S  rc;
+
+
+    Fill_MSCommand(0, 0, 0, MS_DATA_DIR_NONE, SCSI_CMD_TEST_UNIT_READY, 6);
+    rc = Host_ProcessTD(EDBulkOut, TD_OUT, TDBuffer, CBW_SIZE);
+    if (rc == OK) {
+        rc = Host_ProcessTD(EDBulkIn, TD_IN, TDBuffer, CSW_SIZE);
+        if (rc == OK) {        
+            if (TDBuffer[12] != 0) {
+                rc = ERR_MS_CMD_FAILED;
+            }
+        }
+    }
+    return (rc);
+}
+
+/*
+**************************************************************************************************************
+*                                            READ CAPACITY
+*
+* Description: This function is used to read the capacity of the mass storage device
+*
+* Arguments  : None
+*
+* Returns    : OK       if Success
+*              ERROR    if Failed
+*
+**************************************************************************************************************
+*/
+
+USB_INT32S MS_ReadCapacity (USB_INT32U *numBlks, USB_INT32U *blkSize)
+{
+    USB_INT32S  rc;
+
+
+    Fill_MSCommand(0, 0, 0, MS_DATA_DIR_IN, SCSI_CMD_READ_CAPACITY, 10);
+    rc = Host_ProcessTD(EDBulkOut, TD_OUT, TDBuffer, CBW_SIZE);
+    if (rc == OK) {
+        rc = Host_ProcessTD(EDBulkIn, TD_IN, TDBuffer, 8);
+        if (rc == OK) {
+            if (numBlks)
+                *numBlks = ReadBE32U(&TDBuffer[0]);
+            if (blkSize)
+                *blkSize = ReadBE32U(&TDBuffer[4]);
+            rc = Host_ProcessTD(EDBulkIn, TD_IN, TDBuffer, CSW_SIZE);
+            if (rc == OK) {
+                if (TDBuffer[12] != 0) {
+                    rc = ERR_MS_CMD_FAILED;
+                }
+            }
+        }
+    }
+    return (rc);
+}
+
+
+
+USB_INT32S MS_Inquire (USB_INT08U *response)
+{
+    USB_INT32S rc;
+    USB_INT32U i;
+
+    Fill_MSCommand(0, 0, 0, MS_DATA_DIR_IN, SCSI_CMD_INQUIRY, 6);
+    rc = Host_ProcessTD(EDBulkOut, TD_OUT, TDBuffer, CBW_SIZE);
+    if (rc == OK) {
+        rc = Host_ProcessTD(EDBulkIn, TD_IN, TDBuffer, INQUIRY_LENGTH);
+        if (rc == OK) {
+            if (response) {
+                for ( i = 0; i < INQUIRY_LENGTH; i++ )
+                    *response++ = *TDBuffer++;
+#if 0
+                MemCpy (response, TDBuffer, INQUIRY_LENGTH);
+                StrNullTrailingSpace (response->vendorID, SCSI_INQUIRY_VENDORCHARS);
+                StrNullTrailingSpace (response->productID, SCSI_INQUIRY_PRODUCTCHARS);
+                StrNullTrailingSpace (response->productRev, SCSI_INQUIRY_REVCHARS);
+#endif
+            }
+            rc = Host_ProcessTD(EDBulkIn, TD_IN, TDBuffer, CSW_SIZE);
+            if (rc == OK) {
+                if (TDBuffer[12] != 0) {    // bCSWStatus byte
+                    rc = ERR_MS_CMD_FAILED;
+                }
+            }
+        }
+    }
+    return (rc);
+}
+
+/*
+**************************************************************************************************************
+*                                         RECEIVE THE BULK DATA
+*
+* Description: This function is used to receive the bulk data
+*
+* Arguments  : None
+*
+* Returns    : OK                      if Success
+*              ERR_INVALID_BOOTSIG    if Failed
+*
+**************************************************************************************************************
+*/
+    
+USB_INT32S  MS_BulkRecv (          USB_INT32U   block_number,
+                                   USB_INT16U   num_blocks,
+                         volatile  USB_INT08U  *user_buffer)
+{
+    USB_INT32S  rc;
+    int i;
+    volatile USB_INT08U *c = user_buffer;
+    for (i=0;i<MS_BlkSize*num_blocks;i++)
+        *c++ = 0;
+
+
+    Fill_MSCommand(block_number, MS_BlkSize, num_blocks, MS_DATA_DIR_IN, SCSI_CMD_READ_10, 10);
+
+    rc = Host_ProcessTD(EDBulkOut, TD_OUT, TDBuffer, CBW_SIZE);
+    if (rc == OK) {
+        rc = Host_ProcessTD(EDBulkIn, TD_IN, user_buffer, MS_BlkSize * num_blocks);
+        if (rc == OK) {
+            rc = Host_ProcessTD(EDBulkIn, TD_IN, TDBuffer, CSW_SIZE);
+            if (rc == OK) {
+                if (TDBuffer[12] != 0) {
+                    rc = ERR_MS_CMD_FAILED;
+                }
+            }
+        }
+    }
+    return (rc);
+}
+
+/*
+**************************************************************************************************************
+*                                         SEND BULK DATA
+*
+* Description: This function is used to send the bulk data
+*
+* Arguments  : None
+*
+* Returns    : OK                      if Success
+*              ERR_INVALID_BOOTSIG    if Failed
+*
+**************************************************************************************************************
+*/
+
+USB_INT32S  MS_BulkSend (          USB_INT32U   block_number,
+                                   USB_INT16U   num_blocks,
+                         volatile  USB_INT08U  *user_buffer)
+{
+    USB_INT32S  rc;
+
+
+    Fill_MSCommand(block_number, MS_BlkSize, num_blocks, MS_DATA_DIR_OUT, SCSI_CMD_WRITE_10, 10);
+
+    rc = Host_ProcessTD(EDBulkOut, TD_OUT, TDBuffer, CBW_SIZE);
+    if (rc == OK) {
+        rc = Host_ProcessTD(EDBulkOut, TD_OUT, user_buffer, MS_BlkSize * num_blocks);
+        if (rc == OK) {
+            rc = Host_ProcessTD(EDBulkIn, TD_IN, TDBuffer, CSW_SIZE);
+            if (rc == OK) {
+                if (TDBuffer[12] != 0) {
+                    rc = ERR_MS_CMD_FAILED;
+                }
+            }
+        }
+    }
+    return (rc);
+}
+
+/*
+**************************************************************************************************************
+*                                         FILL MASS STORAGE COMMAND
+*
+* Description: This function is used to fill the mass storage command
+*
+* Arguments  : None
+*
+* Returns    : OK                      if Success
+*              ERR_INVALID_BOOTSIG    if Failed
+*
+**************************************************************************************************************
+*/
+
+void  Fill_MSCommand (USB_INT32U   block_number,
+                      USB_INT32U   block_size,
+                      USB_INT16U   num_blocks,
+                      MS_DATA_DIR  direction,
+                      USB_INT08U   scsi_cmd,
+                      USB_INT08U   scsi_cmd_len)
+{
+            USB_INT32U  data_len;
+    static  USB_INT32U  tag_cnt = 0;
+            USB_INT32U  cnt;
+
+
+    for (cnt = 0; cnt < CBW_SIZE; cnt++) {
+         TDBuffer[cnt] = 0;
+    }
+    switch(scsi_cmd) {
+
+        case SCSI_CMD_TEST_UNIT_READY:
+             data_len = 0;
+             break;
+        case SCSI_CMD_READ_CAPACITY:
+             data_len = 8;
+             break;
+        case SCSI_CMD_REQUEST_SENSE:
+             data_len = 18;
+             break;
+        case SCSI_CMD_INQUIRY:
+             data_len = 36;
+             break;
+        default:
+             data_len = block_size * num_blocks;
+             break;
+    }
+    WriteLE32U(TDBuffer, CBW_SIGNATURE);
+    WriteLE32U(&TDBuffer[4], tag_cnt);
+    WriteLE32U(&TDBuffer[8], data_len);
+    TDBuffer[12]     = (direction == MS_DATA_DIR_NONE) ? 0 : direction;
+    TDBuffer[14]     = scsi_cmd_len;                                   /* Length of the CBW                 */
+    TDBuffer[15]     = scsi_cmd;
+    if ((scsi_cmd     == SCSI_CMD_REQUEST_SENSE)
+     || (scsi_cmd     == SCSI_CMD_INQUIRY)) {
+        TDBuffer[19] = (USB_INT08U)data_len;
+    } else {
+        WriteBE32U(&TDBuffer[17], block_number);
+    }
+    WriteBE16U(&TDBuffer[22], num_blocks);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostLite/usbhost_ms.h	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,101 @@
+/*
+**************************************************************************************************************
+*                                                 NXP USB Host Stack
+*
+*                                     (c) Copyright 2008, NXP SemiConductors
+*                                     (c) Copyright 2008, OnChip  Technologies LLC
+*                                                 All Rights Reserved
+*
+*                                                  www.nxp.com
+*                                               www.onchiptech.com
+*
+* File           : usbhost_ms.h
+* Programmer(s)  : Ravikanth.P
+* Version        :
+*
+**************************************************************************************************************
+*/
+
+#ifndef  USBHOST_MS_H
+#define  USBHOST_MS_H
+
+/*
+**************************************************************************************************************
+*                                       INCLUDE HEADER FILES
+**************************************************************************************************************
+*/
+
+#include  "usbhost_inc.h"
+
+/*
+**************************************************************************************************************
+*                               MASS STORAGE SPECIFIC DEFINITIONS
+**************************************************************************************************************
+*/
+
+#define    MS_GET_MAX_LUN_REQ            0xFE
+#define    MASS_STORAGE_CLASS            0x08
+#define    MASS_STORAGE_SUBCLASS_SCSI    0x06
+#define    MASS_STORAGE_PROTOCOL_BO      0x50
+
+#define    INQUIRY_LENGTH                36
+/*
+**************************************************************************************************************
+*                                  SCSI SPECIFIC DEFINITIONS
+**************************************************************************************************************
+*/
+
+#define  CBW_SIGNATURE               0x43425355
+#define  CSW_SIGNATURE               0x53425355
+#define  CBW_SIZE                      31
+#define  CSW_SIZE                      13
+#define  CSW_CMD_PASSED              0x00
+#define  SCSI_CMD_REQUEST_SENSE      0x03
+#define  SCSI_CMD_TEST_UNIT_READY    0x00
+#define  SCSI_CMD_INQUIRY            0x12
+#define  SCSI_CMD_READ_10            0x28
+#define  SCSI_CMD_READ_CAPACITY      0x25
+#define  SCSI_CMD_WRITE_10           0x2A
+
+/*
+**************************************************************************************************************
+*                                       TYPE DEFINITIONS
+**************************************************************************************************************
+*/
+
+typedef enum  ms_data_dir {
+
+    MS_DATA_DIR_IN     = 0x80,
+    MS_DATA_DIR_OUT    = 0x00,
+    MS_DATA_DIR_NONE   = 0x01
+
+} MS_DATA_DIR;
+
+/*
+**************************************************************************************************************
+*                                     FUNCTION PROTOTYPES
+**************************************************************************************************************
+*/
+
+USB_INT32S  MS_BulkRecv          (          USB_INT32U    block_number,
+                                            USB_INT16U    num_blocks,
+                                  volatile  USB_INT08U   *user_buffer);
+
+USB_INT32S  MS_BulkSend          (          USB_INT32U    block_number,
+                                            USB_INT16U    num_blocks,
+                                  volatile  USB_INT08U   *user_buffer);
+USB_INT32S  MS_ParseConfiguration(void);
+USB_INT32S  MS_TestUnitReady     (void);
+USB_INT32S  MS_ReadCapacity (USB_INT32U *numBlks, USB_INT32U *blkSize);
+USB_INT32S  MS_GetMaxLUN         (void);
+USB_INT32S  MS_GetSenseInfo      (void);
+USB_INT32S  MS_Init (USB_INT32U *blkSize, USB_INT32U *numBlks, USB_INT08U *inquiryResult);
+USB_INT32S  MS_Inquire (USB_INT08U *response);
+
+void        Fill_MSCommand       (          USB_INT32U    block_number,
+                                            USB_INT32U    block_size,
+                                            USB_INT16U    num_blocks,
+                                            MS_DATA_DIR   direction,
+                                            USB_INT08U    scsi_cmd,
+                                            USB_INT08U    scsi_cmd_len);
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/VmRecorderV1dot1.cpp	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,428 @@
+#include "mbed.h"
+#include "MSCFileSystem.h"
+#include "Configuracion.h"
+#include "SistemaArchivos.h"
+#include "FechaHora.h"
+#include "SelecManager.h"
+#include "ScreenManager.h"
+#include "Portada.cpp"
+#include "Menu.h"
+#include "ListaSelec.h"
+#include "IdiomaSelec.h"
+#include "FormaSelec.h"
+#include "VelAdquisicionSel.h"
+#include "RestaurarValores.h"
+#include "Mensaje.h"
+#include "NuevoViaje.h"
+#include "GuardarViaje.h"
+#include "ArchivoGuardado.h"
+#include "ViajesGuardados.h"
+#include "Teclado.h"
+#include "GuardarOtroNombre.h"
+#include "OpcionesViaje.h"
+#include "FechaHoraConf.h"
+#include "AutoCalibracion.h"
+
+//DEFINICIONES
+#define ESPANOL 0
+#define INGLES 1
+
+/// PEN DRIVE ///
+MSCFileSystem msc("usb");
+
+/// MEMORIA FLASH LOCAL DE LA MBED ///
+LocalFileSystem local("local");               // Create the local filesystem under the name "local"
+Configuracion config = Configuracion();
+SistemaArchivos SA = SistemaArchivos();
+
+// Fecha y hora
+FechaHora FH;
+
+/********************************************
+        PANTALLAS
+ ********************************************/
+SPI     spi( p5, NC, p7 ); // MOSI, MISO, CLK
+DogMLCD dog( spi, p10, p8); // SPI, CS, A0
+
+ScreenManager SC(&dog); // Screen Manager
+SelecManager SM;  // gestiona las pantallas que tienen elementos seleccionables
+
+Portada portadaVm = Portada();
+Screen* pportadaVm = &portadaVm;
+
+Menu menu = Menu();
+Screen* pmenu = &menu;
+Seleccion* psmenu = &menu;
+
+Teclado keyboard = Teclado();
+Screen* pkeyboard = &keyboard;
+Seleccion* pskeyboard = &keyboard;
+
+ViajesGuardados listaViajes = ViajesGuardados("No existen viajes"); 
+Screen* plistaViajes = &listaViajes;
+Seleccion* pslistaViajes = &listaViajes;
+
+ListaSelec configuracion = ListaSelec();
+Screen* pconfiguracion = &configuracion;
+Seleccion* psconfiguracion = &configuracion;
+
+RestaurarValores restaurar = RestaurarValores("\250Est\240 seguro?");
+Screen* prestaurar = &restaurar;
+Seleccion*  psrestaurar = &restaurar;
+
+IdiomaSelec idioma = IdiomaSelec();
+Screen* pidioma = &idioma;
+Seleccion* psidioma = &idioma;
+
+FormaSelec formaSelec = FormaSelec();
+Screen* pformaSelec = &formaSelec;
+Seleccion* psformaSelec = &formaSelec;
+
+VelAdquisicionSel velAdquisionSel = VelAdquisicionSel();
+Screen* pvelAdquisionSel = &velAdquisionSel;
+Seleccion* psvelAdquisionSel = &velAdquisionSel;
+
+NuevoViaje nuevoViaje = NuevoViaje("Adquiriendo datos", "Frecuencia: ", "OK para comenzar.", "OK para finalizar.", "Pulse atr\240s para cancelar.");
+Screen* pnuevoViaje = &nuevoViaje;
+
+Mensaje noUSB = Mensaje("menu", "Pulse OK para volver.");
+Screen* pnoUSB = &noUSB;
+
+GuardarOtroNombre guardadoCorrect = GuardarOtroNombre("menu", "Pulse OK para continuar.", "Espere por favor");
+Screen* pguardadoCorrect = &guardadoCorrect;
+
+GuardarViaje guardaViaje = GuardarViaje();
+Screen* pguardaViaje = &guardaViaje;
+Seleccion* psguardaViaje = &guardaViaje;
+
+OpcionesViaje opcionesViaje = OpcionesViaje();
+Screen* popcionesViaje = &opcionesViaje;
+Seleccion* psopcionesViaje = &opcionesViaje;
+
+ArchivoGuardado archivoGuardado = ArchivoGuardado("guardaViaje", "Pulse OK para continuar.", "Archivo guardado:", "Fecha:", "Hora:");
+Screen* parchivoGuardado = &archivoGuardado;
+
+Mensaje archivoBorrado = Mensaje("menu", "Pulse OK para continuar.");
+Screen* parchivoBorrado = &archivoBorrado;
+
+Mensaje nombreExistente = Mensaje("guardaViaje", "Pulse OK para volver.");
+Screen* pnombreExistente = &nombreExistente;
+
+FechaHoraConf fechaHoraConf = FechaHoraConf("Pulse las teclas arriba y", "abajo para cambiar los", "valores.", "Fecha:", "Hora:");
+Screen* pfechaHoraConf = &fechaHoraConf;
+Seleccion* psfechaHoraConf = &fechaHoraConf;
+
+AutoCalibracion calibrando = AutoCalibracion();
+Screen* pcalibrando = &calibrando;
+
+// Inglés
+Menu menuEN = Menu();
+Screen* pmenuEN = &menuEN;
+Seleccion* psmenuEN = &menuEN;
+
+ViajesGuardados listaViajesEN = ViajesGuardados("No travels");
+Screen* plistaViajesEN = &listaViajesEN;
+Seleccion* pslistaViajesEN = &listaViajesEN;
+
+ListaSelec configuracionEN = ListaSelec();
+Screen* pconfiguracionEN = &configuracionEN;
+Seleccion* psconfiguracionEN = &configuracionEN;
+
+RestaurarValores restaurarEN = RestaurarValores("Are you sure?");
+Screen* prestaurarEN = &restaurarEN;
+Seleccion*  psrestaurarEN = &restaurarEN;
+
+IdiomaSelec idiomaEN = IdiomaSelec();
+Screen* pidiomaEN = &idiomaEN;
+Seleccion* psidiomaEN = &idiomaEN;
+
+FormaSelec formaSelecEN = FormaSelec();
+Screen* pformaSelecEN = &formaSelecEN;
+Seleccion* psformaSelecEN = &formaSelecEN;
+
+NuevoViaje nuevoViajeEN = NuevoViaje("Acquiring data", "Frecuency: ", "Press OK to start.", "Press OK to finish.", "Press back to cancel.");
+Screen* pnuevoViajeEN = &nuevoViajeEN;
+
+Mensaje noUSBEN = Mensaje("menu", "Press OK to back.");
+Screen* pnoUSBEN = &noUSBEN;
+
+GuardarOtroNombre guardadoCorrectEN = GuardarOtroNombre("menu", "Press OK to continue.", "Please wait");
+Screen* pguardadoCorrectEN = &guardadoCorrectEN;
+
+GuardarViaje guardaViajeEN = GuardarViaje();
+Screen* pguardaViajeEN = &guardaViajeEN;
+Seleccion* psguardaViajeEN = &guardaViajeEN;
+
+OpcionesViaje opcionesViajeEN = OpcionesViaje();
+Screen* popcionesViajeEN = &opcionesViajeEN;
+Seleccion* psopcionesViajeEN = &opcionesViajeEN;
+
+ArchivoGuardado archivoGuardadoEN = ArchivoGuardado("guardaViaje", "Press OK to continue.", "Saved file:", "date:", "Time:");
+Screen* parchivoGuardadoEN = &archivoGuardadoEN;
+
+Mensaje archivoBorradoEN = Mensaje("menu", "Press OK to continue.");
+Screen* parchivoBorradoEN = &archivoBorradoEN;
+
+Mensaje nombreExistenteEN = Mensaje("guardaViaje", "Press OK to back.");
+Screen* pnombreExistenteEN = &nombreExistenteEN;
+
+FechaHoraConf fechaHoraConfEN = FechaHoraConf("Press the up and down keys to change values.", "", "", "Date:", "Time:");
+Screen* pfechaHoraConfEN = &fechaHoraConfEN;
+Seleccion* psfechaHoraConfEN = &fechaHoraConfEN;
+
+/********************************************/
+
+/********************************************
+    BOTONES
+ ********************************************/
+DigitalIn boton1(p30);
+DigitalIn boton2(p29);
+DigitalIn boton3(p28);
+DigitalIn boton4(p27);
+DigitalIn boton5(p26);
+DigitalIn boton6(p14);
+/********************************************/
+
+DigitalOut myled(LED2);
+
+Timer t;
+
+int main() 
+{   
+    /********************************************
+        PANTALLAS
+    ********************************************/
+    /******************* Se añaden las pantallas al ScreenManager ******************************/
+    
+    // Portada inicial
+    SC.addScreen(pportadaVm, "portada", ESPANOL);
+    SC.addScreen(pportadaVm, "portada", INGLES);
+    
+    // Menu principal
+    menu.addElement("Nuevo viaje", "viaje");
+    menu.addElement("Viajes guardados", "listadoViajes");
+    menu.addElement("Configuraci\242n", "configuracion");
+    menu.setSelect(0);
+    SC.addScreen(pmenu, "menu", ESPANOL);
+    SM.addScreen(psmenu);
+    
+    menuEN.addElement("New ride", "viaje");
+    menuEN.addElement("Saved rides", "listadoViajes");
+    menuEN.addElement("Settings", "configuracion");
+    menuEN.setSelect(0);
+    SC.addScreen(pmenuEN, "menu", INGLES);
+    SM.addScreen(psmenuEN);
+    
+    // Pantalla teclado
+    keyboard.setSelect(0);
+    SC.addScreen(pkeyboard, "teclado", ESPANOL);    // El teclado es el mismo para todos los idiomas
+    SC.addScreen(pkeyboard, "teclado", INGLES);
+    SM.addScreen(pskeyboard);
+    
+    // Pantalla de autocalibración
+    SC.addScreen(pcalibrando, "calibrate", ESPANOL);    // La pantalla de calibración es la misma para todos los idiomas (el idioma se controla en el propio código de la pantalla)
+    SC.addScreen(pcalibrando, "calibrate", INGLES);
+    
+    // Lista de viajes guardados
+    listaViajes.setBackScreen("menu");
+    SC.addScreen(plistaViajes, "listadoViajes", ESPANOL);
+    SM.addScreen(pslistaViajes);
+    
+    listaViajesEN.setBackScreen("menu");
+    SC.addScreen(plistaViajesEN, "listadoViajes", INGLES);
+    SM.addScreen(pslistaViajesEN);
+    
+    // Lista de configuración
+    configuracion.addElement("Velocidad de adquisici\242n", "velAdquisionSel");
+    configuracion.addElement("Idioma", "idioma");
+    configuracion.addElement("Visualizaci\242n", "formaSelec");
+    configuracion.addElement("Ajustar fecha y hora", "confFecha");
+    configuracion.addElement("Autocalibraci\242n", "calibrate");
+    configuracion.addElement("Valores de f\240brica", "restaurar");
+    configuracion.setBackScreen("menu");
+    SC.addScreen(pconfiguracion, "configuracion", 0);
+    SM.addScreen(psconfiguracion);
+    
+    configuracionEN.addElement("Sample Rate", "velAdquisionSel");
+    configuracionEN.addElement("Languaje", "idioma");
+    configuracionEN.addElement("Visualization", "formaSelec");
+    configuracionEN.addElement("Set date and time", "confFecha");
+    configuracionEN.addElement("Autocalibration", "calibrate");
+    configuracionEN.addElement("Restore default settings", "restaurar");
+    configuracionEN.setBackScreen("menu");
+    SC.addScreen(pconfiguracionEN, "configuracion", 1);
+    SM.addScreen(psconfiguracionEN);
+    
+    // Pantalla de restauración de datos de fábrica
+    restaurar.addElement("No restaurar", "configuracion");
+    restaurar.addElement("resturar", "configuracion");
+    restaurar.setBackScreen("configuracion");
+    SC.addScreen(prestaurar, "restaurar", 0);
+    SM.addScreen(psrestaurar);
+    
+    restaurarEN.addElement("do not restore", "configuracion");
+    restaurarEN.addElement("restore", "configuracion");
+    restaurarEN.setBackScreen("configuracion");
+    SC.addScreen(prestaurarEN, "restaurar", 1);
+    SM.addScreen(psrestaurarEN); 
+    
+    // pantalla de selección de idioma
+    idioma.addElement("Espa\244ol", "configuracion");
+    idioma.addElement("Ingl\202s", "configuracion");
+    idioma.setBackScreen("configuracion");
+    SC.addScreen(pidioma, "idioma", 0);
+    SM.addScreen(psidioma);
+    
+    idiomaEN.addElement("Spanish", "configuracion");
+    idiomaEN.addElement("English", "configuracion");
+    idiomaEN.setBackScreen("configuracion");
+    SC.addScreen(pidiomaEN, "idioma", 1);
+    SM.addScreen(psidiomaEN);
+    
+    // Pantalla de selección de la forma de selección
+    formaSelec.addElement("Sombreado", "configuracion");
+    formaSelec.addElement("Encuadrado", "configuracion");
+    formaSelec.setBackScreen("configuracion");
+    SC.addScreen(pformaSelec, "formaSelec", 0);
+    SM.addScreen(psformaSelec);
+    
+    formaSelecEN.addElement("Shading", "configuracion");
+    formaSelecEN.addElement("Framing", "configuracion");
+    formaSelecEN.setBackScreen("configuracion");
+    SC.addScreen(pformaSelecEN, "formaSelec", 1);
+    SM.addScreen(psformaSelecEN);  
+    
+    // Pantalla de selección de la velocidad de adquisición
+    velAdquisionSel.addElement("1000 Hz", "configuracion");
+    velAdquisionSel.addElement("320 Hz", "configuracion");
+    velAdquisionSel.setBackScreen("configuracion");
+    SC.addScreen(pvelAdquisionSel, "velAdquisionSel", ESPANOL);
+    SC.addScreen(pvelAdquisionSel, "velAdquisionSel", INGLES);   // Como sólo se muestran valores y sus unidades no es necesaria esta pantalla en otros idiomas
+    SM.addScreen(psvelAdquisionSel);
+    
+    // Pantalla de cambio de fecha y hora
+    fechaHoraConf.setSelect(0);
+    fechaHoraConf.setBackScreen("configuracion");
+    SC.addScreen(pfechaHoraConf, "confFecha", ESPANOL);
+    SM.addScreen(psfechaHoraConf);
+    
+    fechaHoraConfEN.setSelect(0);
+    fechaHoraConfEN.setBackScreen("configuracion");
+    SC.addScreen(pfechaHoraConfEN, "confFecha", INGLES);
+    SM.addScreen(psfechaHoraConfEN);
+    
+    // Pantalla de nuevo viaje
+    SC.addScreen(pnuevoViaje, "viaje", 0);
+    SC.addScreen(pnuevoViajeEN, "viaje", 1);
+    
+    // Mensaje de USB lleno o desconectado
+    noUSB.addElement("USB desconectado");
+    noUSB.addElement("o lleno");
+    noUSB.setBackScreen("menu");
+    SC.addScreen(pnoUSB, "USBdesconectado", 0);
+    
+    noUSBEN.addElement("USB disconected");
+    noUSBEN.addElement("or full");
+    noUSBEN.setBackScreen("menu");
+    SC.addScreen(pnoUSBEN, "USBdesconectado", 1);
+    
+    // Archivo guardado correctamente (Mensaje)
+    guardadoCorrect.addElement("Archivo guardado");
+    guardadoCorrect.addElement("correctamente");
+    guardadoCorrect.setBackScreen("menu");
+    SC.addScreen(pguardadoCorrect, "fileSaved", ESPANOL);
+    
+    guardadoCorrectEN.addElement("File saved");
+    guardadoCorrectEN.addElement("correctly");
+    guardadoCorrectEN.setBackScreen("menu");
+    SC.addScreen(pguardadoCorrectEN, "fileSaved", INGLES);
+    
+    // Pantalla de guardado de viaje
+    guardaViaje.addElement("Volver al men\243", "menu");
+    //guardaViaje.addElement("Postprocesado", "menu");
+    guardaViaje.addElement("Cambiar nombre", "teclado");
+    guardaViaje.addElement("Borrar", "archivoBorrado");
+    guardaViaje.setSelect(0);
+    SC.addScreen(pguardaViaje, "guardaViaje", ESPANOL);
+    SM.addScreen(psguardaViaje);
+    
+    guardaViajeEN.addElement("Back to menu", "menu");
+    //guardaViajeEN.addElement("Postprocessing", "menu");
+    guardaViajeEN.addElement("Rename", "teclado");
+    guardaViajeEN.addElement("Delete", "archivoBorrado");
+    guardaViajeEN.setSelect(0);
+    SC.addScreen(pguardaViajeEN, "guardaViaje", INGLES);
+    SM.addScreen(psguardaViajeEN);
+    
+    // Pantalla de las opciones de un viaje cuando accedes a él mediante la lista de viajes
+    opcionesViaje.addElement("Cambiar nombre", "teclado");
+    opcionesViaje.addElement("Borrar", "listadoViajes");
+    opcionesViaje.setSelect(0);
+    opcionesViaje.setBackScreen("listadoViajes");
+    SC.addScreen(popcionesViaje, "rOptions", ESPANOL);
+    SM.addScreen(psopcionesViaje);
+    
+    opcionesViajeEN.addElement("Rename", "teclado");
+    opcionesViajeEN.addElement("Delete", "listadoViajes");
+    opcionesViajeEN.setSelect(0);
+    opcionesViajeEN.setBackScreen("listadoViajes");
+    SC.addScreen(popcionesViajeEN, "rOptions", INGLES);
+    SM.addScreen(psopcionesViajeEN);
+    
+    // Mensaje de archivo guardado
+    SC.addScreen(parchivoGuardado, "archivoGuardado", ESPANOL);
+    SC.addScreen(parchivoGuardadoEN, "archivoGuardado", INGLES);
+    
+    // Mensaje de archivo borrado
+    archivoBorrado.addElement("Viaje borrado");
+    archivoBorrado.addElement("correctamente");
+    archivoBorrado.setBackScreen("menu");
+    SC.addScreen(parchivoBorrado, "archivoBorrado", ESPANOL);
+    
+    archivoBorradoEN.addElement("Deleted file");
+    archivoBorradoEN.addElement("corretly");
+    archivoBorradoEN.setBackScreen("menu");
+    SC.addScreen(parchivoBorradoEN, "archivoBorrado", INGLES);
+    
+    // Mensade de existencia de un viaje con el mismo nombre
+    nombreExistente.addElement("Ya existe un");
+    nombreExistente.addElement("viaje con el");
+    nombreExistente.addElement("nombre introducido.");
+    nombreExistente.setBackScreen("guardaViaje");
+    SC.addScreen(pnombreExistente, "alredyExist", ESPANOL);
+    
+    nombreExistenteEN.addElement("Alredy exist a");
+    nombreExistenteEN.addElement("ride with the");
+    nombreExistenteEN.addElement("entered name");
+    nombreExistenteEN.setBackScreen("guardaViaje");
+    SC.addScreen(pnombreExistenteEN, "alredyExist", INGLES);
+    
+    /****************************************/
+    
+    /********************************************
+        CARGA DE LA CONFIGURACIÓN
+    ********************************************/
+    char aux[16];
+    // Se selecciona el idioma
+    config.getIdioma(aux);
+    if(strcmp(aux, "spanish") == 0){        
+        SC.selectGroup(0);
+    }else if(strcmp(aux, "english") == 0){
+        SC.selectGroup(1);
+    }
+    
+    // Se selecciona el modo de selección
+    config.getFormaSeleccion(aux);
+    if(strcmp(aux, "shading") == 0){        
+        SM.setInverterSelection();
+    }else if(strcmp(aux, "framing") == 0){
+        SM.setRectSelection();
+    }
+    
+    /****************************************/
+        
+    SC.initialize();
+    while(1){
+        SC.update();
+    }       
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Mon Jun 15 15:34:27 2015 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/04dd9b1680ae
\ No newline at end of file