Add FAT16 library
authorBernie Innocenti <bernie@codewiz.org>
Sun, 20 Mar 2011 22:31:35 +0000 (18:31 -0400)
committerBernie Innocenti <bernie@codewiz.org>
Sun, 20 Mar 2011 22:31:35 +0000 (18:31 -0400)
54 files changed:
FAT16/byteordering.c [new file with mode: 0644]
FAT16/byteordering.h [new file with mode: 0644]
FAT16/examples/FAT16_ReadExample/FAT16_ReadExample.pde [new file with mode: 0644]
FAT16/examples/FAT16_ReadExample/applet/FAT16/byteordering.c.o [new file with mode: 0644]
FAT16/examples/FAT16_ReadExample/applet/FAT16/fat.c.o [new file with mode: 0644]
FAT16/examples/FAT16_ReadExample/applet/FAT16/partition.c.o [new file with mode: 0644]
FAT16/examples/FAT16_ReadExample/applet/FAT16/sd_raw.c.o [new file with mode: 0644]
FAT16/examples/FAT16_ReadExample/applet/FAT16_ReadExample.cpp [new file with mode: 0644]
FAT16/examples/FAT16_ReadExample/applet/FAT16_ReadExample.cpp.eep [new file with mode: 0644]
FAT16/examples/FAT16_ReadExample/applet/FAT16_ReadExample.cpp.elf [new file with mode: 0644]
FAT16/examples/FAT16_ReadExample/applet/FAT16_ReadExample.cpp.hex [new file with mode: 0644]
FAT16/examples/FAT16_ReadExample/applet/FAT16_ReadExample.cpp.o [new file with mode: 0644]
FAT16/examples/FAT16_ReadExample/applet/HardwareSerial.cpp.o [new file with mode: 0644]
FAT16/examples/FAT16_ReadExample/applet/Print.cpp.o [new file with mode: 0644]
FAT16/examples/FAT16_ReadExample/applet/WInterrupts.c.o [new file with mode: 0644]
FAT16/examples/FAT16_ReadExample/applet/WMath.cpp.o [new file with mode: 0644]
FAT16/examples/FAT16_ReadExample/applet/core.a [new file with mode: 0644]
FAT16/examples/FAT16_ReadExample/applet/pins_arduino.c.o [new file with mode: 0644]
FAT16/examples/FAT16_ReadExample/applet/wiring.c.o [new file with mode: 0644]
FAT16/examples/FAT16_ReadExample/applet/wiring_analog.c.o [new file with mode: 0644]
FAT16/examples/FAT16_ReadExample/applet/wiring_digital.c.o [new file with mode: 0644]
FAT16/examples/FAT16_ReadExample/applet/wiring_pulse.c.o [new file with mode: 0644]
FAT16/examples/FAT16_ReadExample/applet/wiring_shift.c.o [new file with mode: 0644]
FAT16/examples/FAT16_WriteExample/FAT16_WriteExample.pde [new file with mode: 0644]
FAT16/examples/FAT16_WriteExample/applet/FAT16/byteordering.c.o [new file with mode: 0644]
FAT16/examples/FAT16_WriteExample/applet/FAT16/fat.c.o [new file with mode: 0644]
FAT16/examples/FAT16_WriteExample/applet/FAT16/partition.c.o [new file with mode: 0644]
FAT16/examples/FAT16_WriteExample/applet/FAT16/sd_raw.c.o [new file with mode: 0644]
FAT16/examples/FAT16_WriteExample/applet/FAT16_WriteExample.cpp [new file with mode: 0644]
FAT16/examples/FAT16_WriteExample/applet/FAT16_WriteExample.cpp.eep [new file with mode: 0644]
FAT16/examples/FAT16_WriteExample/applet/FAT16_WriteExample.cpp.elf [new file with mode: 0644]
FAT16/examples/FAT16_WriteExample/applet/FAT16_WriteExample.cpp.hex [new file with mode: 0644]
FAT16/examples/FAT16_WriteExample/applet/FAT16_WriteExample.cpp.o [new file with mode: 0644]
FAT16/examples/FAT16_WriteExample/applet/HardwareSerial.cpp.o [new file with mode: 0644]
FAT16/examples/FAT16_WriteExample/applet/Print.cpp.o [new file with mode: 0644]
FAT16/examples/FAT16_WriteExample/applet/WInterrupts.c.o [new file with mode: 0644]
FAT16/examples/FAT16_WriteExample/applet/WMath.cpp.o [new file with mode: 0644]
FAT16/examples/FAT16_WriteExample/applet/core.a [new file with mode: 0644]
FAT16/examples/FAT16_WriteExample/applet/pins_arduino.c.o [new file with mode: 0644]
FAT16/examples/FAT16_WriteExample/applet/wiring.c.o [new file with mode: 0644]
FAT16/examples/FAT16_WriteExample/applet/wiring_analog.c.o [new file with mode: 0644]
FAT16/examples/FAT16_WriteExample/applet/wiring_digital.c.o [new file with mode: 0644]
FAT16/examples/FAT16_WriteExample/applet/wiring_pulse.c.o [new file with mode: 0644]
FAT16/examples/FAT16_WriteExample/applet/wiring_shift.c.o [new file with mode: 0644]
FAT16/fat.c [new file with mode: 0644]
FAT16/fat.h [new file with mode: 0644]
FAT16/fat_config.h [new file with mode: 0644]
FAT16/partition.c [new file with mode: 0644]
FAT16/partition.h [new file with mode: 0644]
FAT16/partition_config.h [new file with mode: 0644]
FAT16/sd-reader_config.h [new file with mode: 0644]
FAT16/sd_raw.c [new file with mode: 0644]
FAT16/sd_raw.h [new file with mode: 0644]
FAT16/sd_raw_config.h [new file with mode: 0644]

diff --git a/FAT16/byteordering.c b/FAT16/byteordering.c
new file mode 100644 (file)
index 0000000..69330c9
--- /dev/null
@@ -0,0 +1,62 @@
+
+/*
+ * Copyright (c) 2006-2009 by Roland Riegel <feedback@roland-riegel.de>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either the GNU General Public License version 2
+ * or the GNU Lesser General Public License version 2.1, both as
+ * published by the Free Software Foundation.
+ */
+
+#include "byteordering.h"
+
+/**
+ * \addtogroup byteordering
+ *
+ * Architecture-dependent handling of byte-ordering.
+ *
+ * @{
+ */
+/**
+ * \file
+ * Byte-order handling implementation (license: GPLv2 or LGPLv2.1)
+ *
+ * \author Roland Riegel
+ */
+
+#if !(__AVR__)
+/**
+ * Converts a 16-bit integer to little-endian byte order.
+ *
+ * Use this function on variable values instead of the
+ * macro HTOL16(). This saves code size.
+ *
+ * \param[in] h A 16-bit integer in host byte order.
+ * \returns The given 16-bit integer converted to little-endian byte order.
+ */
+uint16_t htol16(uint16_t h)
+{
+    return HTOL16(h);
+}
+#endif
+
+#if !(__AVR__)
+/**
+ * Converts a 32-bit integer to little-endian byte order.
+ *
+ * Use this function on variable values instead of the
+ * macro HTOL32(). This saves code size.
+ *
+ * \param[in] h A 32-bit integer in host byte order.
+ * \returns The given 32-bit integer converted to little-endian byte order.
+ */
+uint32_t htol32(uint32_t h)
+{
+    return HTOL32(h);
+}
+#endif
+
+/**
+ * @}
+ */
+
diff --git a/FAT16/byteordering.h b/FAT16/byteordering.h
new file mode 100644 (file)
index 0000000..48ddffe
--- /dev/null
@@ -0,0 +1,137 @@
+
+/*
+ * Copyright (c) 2006-2009 by Roland Riegel <feedback@roland-riegel.de>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either the GNU General Public License version 2
+ * or the GNU Lesser General Public License version 2.1, both as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef BYTEORDERING_H
+#define BYTEORDERING_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * \addtogroup byteordering
+ *
+ * @{
+ */
+/**
+ * \file
+ * Byte-order handling header (license: GPLv2 or LGPLv2.1)
+ *
+ * \author Roland Riegel
+ */
+
+/**
+ * \def HTOL16(val)
+ *
+ * Converts a 16-bit integer to little-endian byte order.
+ *
+ * Use this macro for compile time constants only. For variable values
+ * use the function htol16() instead. This saves code size.
+ *
+ * \param[in] val A 16-bit integer in host byte order.
+ * \returns The given 16-bit integer converted to little-endian byte order.
+ */
+/**
+ * \def HTOL32(val)
+ *
+ * Converts a 32-bit integer to little-endian byte order.
+ *
+ * Use this macro for compile time constants only. For variable values
+ * use the function htol32() instead. This saves code size.
+ *
+ * \param[in] val A 32-bit integer in host byte order.
+ * \returns The given 32-bit integer converted to little-endian byte order.
+ */
+
+#if __AVR__
+#define HTOL16(val) (val)
+#define HTOL32(val) (val)
+#elif defined(BIG_ENDIAN)
+#define HTOL16(val) ((((uint16_t) (val)) << 8) | \
+                     (((uint16_t) (val)) >> 8)   \
+                    )
+#define HTOL32(val) (((((uint32_t) (val)) & 0x000000ff) << 24) | \
+                     ((((uint32_t) (val)) & 0x0000ff00) <<  8) | \
+                     ((((uint32_t) (val)) & 0x00ff0000) >>  8) | \
+                     ((((uint32_t) (val)) & 0xff000000) >> 24)   \
+                    )
+#else
+#error "Endianess undefined! Please define LITTLE_ENDIAN=1 or BIG_ENDIAN=1."
+#endif
+
+uint16_t htol16(uint16_t h);
+uint32_t htol32(uint32_t h);
+
+/**
+ * Converts a 16-bit integer to host byte order.
+ *
+ * Use this macro for compile time constants only. For variable values
+ * use the function ltoh16() instead. This saves code size.
+ *
+ * \param[in] val A 16-bit integer in little-endian byte order.
+ * \returns The given 16-bit integer converted to host byte order.
+ */
+#define LTOH16(val) HTOL16(val)
+
+/**
+ * Converts a 32-bit integer to host byte order.
+ *
+ * Use this macro for compile time constants only. For variable values
+ * use the function ltoh32() instead. This saves code size.
+ *
+ * \param[in] val A 32-bit integer in little-endian byte order.
+ * \returns The given 32-bit integer converted to host byte order.
+ */
+#define LTOH32(val) HTOL32(val)
+
+/**
+ * Converts a 16-bit integer to host byte order.
+ *
+ * Use this function on variable values instead of the
+ * macro LTOH16(). This saves code size.
+ *
+ * \param[in] l A 16-bit integer in little-endian byte order.
+ * \returns The given 16-bit integer converted to host byte order.
+ */
+#define ltoh16(l) htol16(l)
+
+/**
+ * Converts a 32-bit integer to host byte order.
+ *
+ * Use this function on variable values instead of the
+ * macro LTOH32(). This saves code size.
+ *
+ * \param[in] l A 32-bit integer in little-endian byte order.
+ * \returns The given 32-bit integer converted to host byte order.
+ */
+#define ltoh32(l) htol32(l)
+
+
+/**
+ * @}
+ */
+
+#if __AVR__
+#define htol16(h) (h)
+#define htol32(h) (h)
+#else
+uint16_t htol16(uint16_t h);
+uint32_t htol32(uint32_t h);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/FAT16/examples/FAT16_ReadExample/FAT16_ReadExample.pde b/FAT16/examples/FAT16_ReadExample/FAT16_ReadExample.pde
new file mode 100644 (file)
index 0000000..5bae1dc
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+FAT16 ReadFile Example
+SparkFun Electronics
+Written by Ryan Owens
+3/16/2010
+
+Code Description: Uses an Arduino Duemillanove or Arduino Pro to read the file contents of each file on an SD card.
+
+Circuit Description: Uses the SparkFun microSD shield. (http://www.sparkfun.com/commerce/product_info.php?products_id=9520)
+
+Attributions: Special thanks to Roland Riegel for providing an open source FAT library 
+for AVR microcontrollers. See more of his projects here:
+http://www.roland-riegel.de/
+
+This code is provided under the Creative Commons Attribution License. More information can be found here:
+http://creativecommons.org/licenses/by/3.0/
+
+(Use our code freely! Please just remember to give us credit where it's due. Thanks!)
+*/
+
+//Add libraries to support FAT16 on the SD Card.
+//(Note: If you already have these libraries installed in the directory, they'll have to remove in order to compile this.)
+#include <byteordering.h>
+#include <fat.h>
+#include <fat_config.h>
+#include <partition.h>
+#include <partition_config.h>
+#include <sd-reader_config.h>
+#include <sd_raw.h>
+#include <sd_raw_config.h>
+
+//Define the pin numbers
+#define CS    8
+#define MOSI    11
+#define MISO    12
+#define SCK    13
+
+//This is the amount of data to be fetched from the SD card for each read.
+#define BUFFERSIZE     256
+
+unsigned char buffer[BUFFERSIZE];
+char file_name[30];
+
+struct fat_dir_struct* dd;             //FAT16 directory
+struct fat_dir_entry_struct dir_entry; //FAT16 directory entry (A.K.A. a file)
+
+struct fat_fs_struct* fs;              //FAT16 File System
+struct partition_struct* partition;    //FAT16 Partition
+
+struct fat_file_struct * file_handle;  //FAT16 File Handle
+
+void setup()
+{
+    //Set up the pins for the Serial communication
+    pinMode(0, INPUT);
+    pinMode(1, OUTPUT);
+    Serial.begin(9600);
+    //Set up the pins for the microSD shield
+    pinMode(CS, OUTPUT);
+    pinMode(MOSI, OUTPUT);
+    pinMode(MISO, INPUT);
+    pinMode(SCK, OUTPUT);
+    pinMode(10, OUTPUT);
+}
+
+void loop()
+{
+    int bytes_read=0; //Keeps track of how many bytes are read when accessing a file on the SD card.
+
+    init_filesystem(); //Initialize the FAT16 file system on the SD card.
+  
+    //Get the next file in the directory
+    while(get_next_filename(dd, file_name)){
+        //Open the file        
+        file_handle=open_file_in_dir(fs, dd, file_name);
+        //Read up to 512 bytes from the file
+        bytes_read = fat_read_file(file_handle, buffer, BUFFERSIZE);
+        //Print whatever we just got from the file
+        Serial.println((const char *)buffer);
+        //Keep reading from the file until we reach the end (nothing more is read from the file)
+        while(bytes_read > 0){
+            //If there's more to be read from the file, go get it.
+            bytes_read = fat_read_file(file_handle, buffer, BUFFERSIZE);
+            //Print the contents that have been read
+            Serial.println((const char *)buffer);
+        }
+        //Close the file before moving on to the next one.
+        fat_close_file(file_handle);
+        delay(1000);
+        Serial.println("Next File...");
+    }
+    while(1);
+}
+
+uint8_t find_file_in_dir(struct fat_fs_struct* fs, struct fat_dir_struct* dd, const char* name, struct fat_dir_entry_struct* dir_entry)
+{
+       fat_reset_dir(dd);      //Make sure to start from the beginning of the directory!
+    while(fat_read_dir(dd, dir_entry))
+    {
+        if(strcmp(dir_entry->long_name, name) == 0)
+        {
+            //fat_reset_dir(dd);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+struct fat_file_struct* open_file_in_dir(struct fat_fs_struct* fs, struct fat_dir_struct* dd, const char* name)
+{
+    struct fat_dir_entry_struct file_entry;
+    if(!find_file_in_dir(fs, dd, name, &file_entry))
+        return 0;
+
+    return fat_open_file(fs, &file_entry);
+}
+
+char init_filesystem(void)
+{
+       //setup sd card slot 
+       if(!sd_raw_init())
+       {
+               return 0;
+       }
+
+       //open first partition
+       partition = partition_open(sd_raw_read,
+                                                                       sd_raw_read_interval,
+#if SD_RAW_WRITE_SUPPORT
+                                                                       sd_raw_write,
+                                                                       sd_raw_write_interval,
+#else
+                                                                       0,
+                                                                       0,
+#endif
+                                                                       0
+                                                          );
+
+       if(!partition)
+       {
+               //If the partition did not open, assume the storage device
+               //is a "superfloppy", i.e. has no MBR.
+               partition = partition_open(sd_raw_read,
+                                                                  sd_raw_read_interval,
+#if SD_RAW_WRITE_SUPPORT
+                                                                  sd_raw_write,
+                                                                  sd_raw_write_interval,
+#else
+                                                                  0,
+                                                                  0,
+#endif
+                                                                  -1
+                                                                 );
+               if(!partition)
+               {
+                       return 0;
+               }
+       }
+
+       //Open file system
+       fs = fat_open(partition);
+       if(!fs)
+       {
+               return 0;
+       }
+
+       //Open root directory
+       fat_get_dir_entry_of_path(fs, "/", &dir_entry);
+       dd=fat_open_dir(fs, &dir_entry);
+       
+       if(!dd)
+       {
+               return 0;
+       }
+       return 1;
+}
+
+char get_next_filename(struct fat_dir_struct* cur_dir, char * new_file)
+{
+    //'dir_entry' is a global variable of type directory_entry_struct
+
+    //Get the next file from the root directory
+    if(fat_read_dir(cur_dir, &dir_entry))
+    {
+       sprintf(new_file, "%s", dir_entry.long_name);
+        Serial.println((const char *)new_file);
+        return 1;
+    }
+    //If another file isn't found, return 0
+    return 0;
+}
+
+\r
diff --git a/FAT16/examples/FAT16_ReadExample/applet/FAT16/byteordering.c.o b/FAT16/examples/FAT16_ReadExample/applet/FAT16/byteordering.c.o
new file mode 100644 (file)
index 0000000..07d283e
Binary files /dev/null and b/FAT16/examples/FAT16_ReadExample/applet/FAT16/byteordering.c.o differ
diff --git a/FAT16/examples/FAT16_ReadExample/applet/FAT16/fat.c.o b/FAT16/examples/FAT16_ReadExample/applet/FAT16/fat.c.o
new file mode 100644 (file)
index 0000000..1125cad
Binary files /dev/null and b/FAT16/examples/FAT16_ReadExample/applet/FAT16/fat.c.o differ
diff --git a/FAT16/examples/FAT16_ReadExample/applet/FAT16/partition.c.o b/FAT16/examples/FAT16_ReadExample/applet/FAT16/partition.c.o
new file mode 100644 (file)
index 0000000..f5741e1
Binary files /dev/null and b/FAT16/examples/FAT16_ReadExample/applet/FAT16/partition.c.o differ
diff --git a/FAT16/examples/FAT16_ReadExample/applet/FAT16/sd_raw.c.o b/FAT16/examples/FAT16_ReadExample/applet/FAT16/sd_raw.c.o
new file mode 100644 (file)
index 0000000..b020ac4
Binary files /dev/null and b/FAT16/examples/FAT16_ReadExample/applet/FAT16/sd_raw.c.o differ
diff --git a/FAT16/examples/FAT16_ReadExample/applet/FAT16_ReadExample.cpp b/FAT16/examples/FAT16_ReadExample/applet/FAT16_ReadExample.cpp
new file mode 100644 (file)
index 0000000..e20ecc6
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+FAT16 ReadFile Example
+SparkFun Electronics
+Written by Ryan Owens
+3/16/2010
+
+Code Description: Uses an Arduino Duemillanove or Arduino Pro to read the file contents of each file on an SD card.
+
+Circuit Description: Uses the SparkFun microSD shield. (http://www.sparkfun.com/commerce/product_info.php?products_id=9520)
+
+Attributions: Special thanks to Roland Riegel for providing an open source FAT library 
+for AVR microcontrollers. See more of his projects here:
+http://www.roland-riegel.de/
+
+This code is provided under the Creative Commons Attribution License. More information can be found here:
+http://creativecommons.org/licenses/by/3.0/
+
+(Use our code freely! Please just remember to give us credit where it's due. Thanks!)
+*/
+
+//Add libraries to support FAT16 on the SD Card.
+//(Note: If you already have these libraries installed in the directory, they'll have to remove in order to compile this.)
+#include <byteordering.h>
+#include <fat.h>
+#include <fat_config.h>
+#include <partition.h>
+#include <partition_config.h>
+#include <sd-reader_config.h>
+#include <sd_raw.h>
+#include <sd_raw_config.h>
+
+//Define the pin numbers
+#define CS    8
+#define MOSI    11
+#define MISO    12
+#define SCK    13
+
+//This is the amount of data to be fetched from the SD card for each read.
+#define BUFFERSIZE     256
+
+#include "WProgram.h"
+void setup();
+void loop();
+uint8_t find_file_in_dir(struct fat_fs_struct* fs, struct fat_dir_struct* dd, const char* name, struct fat_dir_entry_struct* dir_entry);
+struct fat_file_struct* open_file_in_dir(struct fat_fs_struct* fs, struct fat_dir_struct* dd, const char* name);
+char init_filesystem(void);
+char get_next_filename(struct fat_dir_struct* cur_dir, char * new_file);
+unsigned char buffer[BUFFERSIZE];
+char file_name[30];
+
+struct fat_dir_struct* dd;             //FAT16 directory
+struct fat_dir_entry_struct dir_entry; //FAT16 directory entry (A.K.A. a file)
+
+struct fat_fs_struct* fs;              //FAT16 File System
+struct partition_struct* partition;    //FAT16 Partition
+
+struct fat_file_struct * file_handle;  //FAT16 File Handle
+
+void setup()
+{
+    //Set up the pins for the Serial communication
+    pinMode(0, INPUT);
+    pinMode(1, OUTPUT);
+    Serial.begin(9600);
+    //Set up the pins for the microSD shield
+    pinMode(CS, OUTPUT);
+    pinMode(MOSI, OUTPUT);
+    pinMode(MISO, INPUT);
+    pinMode(SCK, OUTPUT);
+    pinMode(10, OUTPUT);
+}
+
+void loop()
+{
+    int bytes_read=0; //Keeps track of how many bytes are read when accessing a file on the SD card.
+
+    init_filesystem(); //Initialize the FAT16 file system on the SD card.
+  
+    //Get the next file in the directory
+    while(get_next_filename(dd, file_name)){
+        //Open the file        
+        file_handle=open_file_in_dir(fs, dd, file_name);
+        //Read up to 512 bytes from the file
+        bytes_read = fat_read_file(file_handle, buffer, BUFFERSIZE);
+        //Print whatever we just got from the file
+        Serial.println((const char *)buffer);
+        //Keep reading from the file until we reach the end (nothing more is read from the file)
+        while(bytes_read > 0){
+            //If there's more to be read from the file, go get it.
+            bytes_read = fat_read_file(file_handle, buffer, BUFFERSIZE);
+            //Print the contents that have been read
+            Serial.println((const char *)buffer);
+        }
+        //Close the file before moving on to the next one.
+        fat_close_file(file_handle);
+        delay(1000);
+        Serial.println("Next File...");
+    }
+    while(1);
+}
+
+uint8_t find_file_in_dir(struct fat_fs_struct* fs, struct fat_dir_struct* dd, const char* name, struct fat_dir_entry_struct* dir_entry)
+{
+       fat_reset_dir(dd);      //Make sure to start from the beginning of the directory!
+    while(fat_read_dir(dd, dir_entry))
+    {
+        if(strcmp(dir_entry->long_name, name) == 0)
+        {
+            //fat_reset_dir(dd);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+struct fat_file_struct* open_file_in_dir(struct fat_fs_struct* fs, struct fat_dir_struct* dd, const char* name)
+{
+    struct fat_dir_entry_struct file_entry;
+    if(!find_file_in_dir(fs, dd, name, &file_entry))
+        return 0;
+
+    return fat_open_file(fs, &file_entry);
+}
+
+char init_filesystem(void)
+{
+       //setup sd card slot 
+       if(!sd_raw_init())
+       {
+               return 0;
+       }
+
+       //open first partition
+       partition = partition_open(sd_raw_read,
+                                                                       sd_raw_read_interval,
+#if SD_RAW_WRITE_SUPPORT
+                                                                       sd_raw_write,
+                                                                       sd_raw_write_interval,
+#else
+                                                                       0,
+                                                                       0,
+#endif
+                                                                       0
+                                                          );
+
+       if(!partition)
+       {
+               //If the partition did not open, assume the storage device
+               //is a "superfloppy", i.e. has no MBR.
+               partition = partition_open(sd_raw_read,
+                                                                  sd_raw_read_interval,
+#if SD_RAW_WRITE_SUPPORT
+                                                                  sd_raw_write,
+                                                                  sd_raw_write_interval,
+#else
+                                                                  0,
+                                                                  0,
+#endif
+                                                                  -1
+                                                                 );
+               if(!partition)
+               {
+                       return 0;
+               }
+       }
+
+       //Open file system
+       fs = fat_open(partition);
+       if(!fs)
+       {
+               return 0;
+       }
+
+       //Open root directory
+       fat_get_dir_entry_of_path(fs, "/", &dir_entry);
+       dd=fat_open_dir(fs, &dir_entry);
+       
+       if(!dd)
+       {
+               return 0;
+       }
+       return 1;
+}
+
+char get_next_filename(struct fat_dir_struct* cur_dir, char * new_file)
+{
+    //'dir_entry' is a global variable of type directory_entry_struct
+
+    //Get the next file from the root directory
+    if(fat_read_dir(cur_dir, &dir_entry))
+    {
+       sprintf(new_file, "%s", dir_entry.long_name);
+        Serial.println((const char *)new_file);
+        return 1;
+    }
+    //If another file isn't found, return 0
+    return 0;
+}
+
+
+
+int main(void)
+{
+       init();
+
+       setup();
+    
+       for (;;)
+               loop();
+        
+       return 0;
+}
+
diff --git a/FAT16/examples/FAT16_ReadExample/applet/FAT16_ReadExample.cpp.eep b/FAT16/examples/FAT16_ReadExample/applet/FAT16_ReadExample.cpp.eep
new file mode 100644 (file)
index 0000000..1996e8f
--- /dev/null
@@ -0,0 +1 @@
+:00000001FF\r
diff --git a/FAT16/examples/FAT16_ReadExample/applet/FAT16_ReadExample.cpp.elf b/FAT16/examples/FAT16_ReadExample/applet/FAT16_ReadExample.cpp.elf
new file mode 100644 (file)
index 0000000..3a694d3
Binary files /dev/null and b/FAT16/examples/FAT16_ReadExample/applet/FAT16_ReadExample.cpp.elf differ
diff --git a/FAT16/examples/FAT16_ReadExample/applet/FAT16_ReadExample.cpp.hex b/FAT16/examples/FAT16_ReadExample/applet/FAT16_ReadExample.cpp.hex
new file mode 100644 (file)
index 0000000..6d9a1c7
--- /dev/null
@@ -0,0 +1,509 @@
+:100000000C9462000C948A000C948A000C948A0070\r
+:100010000C948A000C948A000C948A000C948A0038\r
+:100020000C948A000C948A000C948A000C948A0028\r
+:100030000C948A000C948A000C948A000C948A0018\r
+:100040000C94890C0C948A000C94550D0C948A0025\r
+:100050000C948A000C948A000C948A000C948A00F8\r
+:100060000C948A000C948A000000000024002700F1\r
+:100070002A0000000000250028002B0000000000DE\r
+:1000800023002600290004040404040404040202DA\r
+:100090000202020203030303030301020408102007\r
+:1000A0004080010204081020010204081020000012\r
+:1000B0000007000201000003040600000000000029\r
+:1000C00000009E0E11241FBECFEFD8E0DEBFCDBFD3\r
+:1000D00011E0A0E0B1E0E8E8FFE102C005900D9278\r
+:1000E000A632B107D9F715E0A6E2B1E001C01D9232\r
+:1000F000A13EB107E1F710E0C4ECD0E004C02297C4\r
+:10010000FE010E94BE0FC23CD107C9F70E94820CBB\r
+:100110000C94C20F0C940000FB01DC0102C00190A2\r
+:100120000D9241505040D8F70895FC0181918617F7\r
+:1001300021F08823D9F7992708953197CF010895A1\r
+:10014000FB01DC018D91019080190110D9F3990B0D\r
+:100150000895FB01DC0101900D920020E1F7089564\r
+:10016000FB01DC014150504030F08D91019080192D\r
+:1001700019F40020B9F7881B990B0895DF93CF93EA\r
+:1001800000D0CDB7DEB7DC01009781F16230710598\r
+:1001900068F1ED91FC911197660F771F80E090E078\r
+:1001A00016962D913D914D915C911997620F731F99\r
+:1001B000841F951F0190F081E02DAE014F5F5F4FCE\r
+:1001C00022E030E00995882389F029813A812115C0\r
+:1001D000310571F08FEF273F380741F0C901409694\r
+:1001E000079720F08FEF283F380710F020E030E02D\r
+:1001F000C9010F900F90CF91DF910895FC010097F6\r
+:1002000011F01182108208952F923F924F925F92C7\r
+:100210006F927F928F929F92AF92BF92CF92DF9216\r
+:10022000EF92FF920F931F93DF93CF93CDB7DEB77B\r
+:100230002A970FB6F894DEBF0FBECDBF2C017A838C\r
+:1002400069835C834B83009709F409C1672B09F428\r
+:1002500006C1452B09F403C1DC019D96AD90BD900C\r
+:10026000CD90DC90D09795962D913D914D915C91DC\r
+:100270009897EB81FC81CF01A0E0B0E08A0D9B1D37\r
+:10028000AC1DBD1D281739074A075B0740F4B901AB\r
+:100290006A197B097C836B83672B09F4E3C0D20165\r
+:1002A000ED91FC91119720883188D196ED91FC91C8\r
+:1002B000D297FA87E987EF2BF1F593962D913C9130\r
+:1002C00094973A872987232B39F4A114B104C104E8\r
+:1002D000D10409F4C7C0C3C0A114B104C104D1043E\r
+:1002E00051F1860175013101882499246627772709\r
+:1002F000CB0166197709880999096D837E838F83FD\r
+:10030000988714C0D2018D919C9169857A850E944D\r
+:10031000BE009A878987892B09F4A1C06D817E81EF\r
+:100320008F819885E60EF71E081F191FE614F70443\r
+:100330000805190538F7089421083108A220B320D0\r
+:100340000894211C311CCB80DC80D201ED90FC9004\r
+:10035000E114F10409F1E985FA85E230F105E0F0F4\r
+:100360003297BF0180E090E03296FA87E987D701A3\r
+:1003700050962D913C91519740E050E00E94390FEA\r
+:100380009B01AC01F70182899389A489B589280F63\r
+:10039000391F4A1F5B1F04C020E030E040E050E0FE\r
+:1003A00081010A191B09C016D10608F48601D7017C\r
+:1003B000ED91FC91C501A0E0B0E0280F391F4A1F64\r
+:1003C0005B1F0190F081E02DCA01B90149815A817A\r
+:1003D00098010995882341F1C01AD10AC801A0E00B\r
+:1003E000B0E0F20125A536A547A550A9280F391F71\r
+:1003F0004A1F5B1FD2019D962D933D934D935C93B5\r
+:10040000D097C8018A0D9B1D82159305A0F08D9190\r
+:100410009C9169857A850E94BE009A878987892B7D\r
+:1004200041F4F20112AA11AA4B815C814C195D09B9\r
+:100430001BC0AA24BB24E985FA85D201D296FC937D\r
+:10044000EE93D197C114D10439F029813A81200F5C\r
+:10045000311F3A83298379CF4B815C8105C04FEFEF\r
+:100460005FEF02C040E050E0CA012A960FB6F89450\r
+:10047000DEBF0FBECDBFCF91DF911F910F91FF90D7\r
+:10048000EF90DF90CF90BF90AF909F908F907F9034\r
+:100490006F905F904F903F902F900895FC010097D0\r
+:1004A00011F480E0089583A194A196A785A710AACE\r
+:1004B00017A681E00895CF92DF92EF92FF920F93FB\r
+:1004C0001F93CF93DF938C016A017B01A901D901AE\r
+:1004D000CD91DC91119712968D919C9113978096F6\r
+:1004E00013969C938E931297F8018081853E09F4B0\r
+:1004F000BAC0882309F4B7C08FA198A5A9A5BAA549\r
+:100500000097A105B10521F4CFA2D8A6E9A6FAA6C5\r
+:10051000209709F4AAC00115110509F4A6C0D80155\r
+:100520009C91992309F4A1C01B968C918F30A1F561\r
+:10053000892F90E08F7390702DE030E0829FA001B2\r
+:10054000839F500D929F500D11244D50504010929A\r
+:1005500027011092260111C0AC0FBD1FF901E15F08\r
+:10056000FE4F8081F801E80FF11D80818C932F5F91\r
+:100570003F4F30932701209326012091260130918F\r
+:1005800027012D30310508F06EC0DA01A20FB31F2C\r
+:10059000AF31B10508F367C08881882309F04FC0E7\r
+:1005A000B801DE01780120E0F70190819032A1F0DE\r
+:1005B0009C93F801848583FF08C0F7018081813412\r
+:1005C00020F08B3510F4905E9C932F5F0894E11C13\r
+:1005D000F11C1196283041F78881853011F485EEA1\r
+:1005E0008883D80118968C91803211F4322F23C061\r
+:1005F000FE01E20FF11D8EE28083322F3F5F2C5F00\r
+:10060000FB0190859032B9F0FE01E30FF11D90835C\r
+:10061000D8011C968C9184FF09C0DB0118968C913F\r
+:10062000813420F08B3510F4905E90833F5F6F5FD4\r
+:100630007F4F321729F7FE01E30FF11D1082F801F9\r
+:10064000838588A3828D938D9AA389A3848D958DAC\r
+:10065000A68DB78D8BA39CA3ADA3BEA381E0DA01C9\r
+:1006600014968C9302C081E001C080E0DF91CF91AD\r
+:100670001F910F91FF90EF90DF90CF9008952F92F0\r
+:100680003F924F925F926F927F928F929F92AF9222\r
+:10069000BF92CF92DF92EF92FF920F931F93DF935F\r
+:1006A000CF93CDB7DEB7A7970FB6F894DEBF0FBED6\r
+:1006B000CDBF2C017FA36EA3009709F4B1C06115D3\r
+:1006C000710509F4ADC0DC018D909C901197F40187\r
+:1006D000208831889D96AD90BC909E979F966D9096\r
+:1006E0007C90D0978BE2DB011D928A95E9F7FE01A1\r
+:1006F000319685E0DF011D928A95E9F7A114B104D6\r
+:1007000009F076C0F4012288338886899789281AEF\r
+:10071000390A6EC0730100E010E0A114B10441F485\r
+:10072000D40156966D917D918D919C9159972DC0D4\r
+:100730008114910421F1B2E0AB16B10400F1EEEFA7\r
+:10074000FFEFAE0EBF1EB50180E090E022E030E08A\r
+:10075000A20EB31ED40150962D913C91519740E0CA\r
+:1007600050E00E94390F9B01AC01F401828993890A\r
+:10077000A489B589280F391F4A1F5B1F04C020E0D8\r
+:1007800030E040E050E0CA01B9016E0D7F1D801FCE\r
+:10079000911F1C821B82D401ED91FC9181010619ED\r
+:1007A00017090280F381E02DAE014A5F5F4F20E21E\r
+:1007B00030E0ABE5EA2EA2E0FA2E6E010894C11CEF\r
+:1007C000D11C0995882361F18B819C81680E791E6B\r
+:1007D0006214730488F0C401B5010E94BE005C017C\r
+:1007E00066247724009741F4F201A3A0B4A008C0C6\r
+:1007F0002EA13FA13A8329838D81882309F48ACFD2\r
+:10080000D2019E96BC92AE929D97D0967C926E92AB\r
+:100810009F97EEA1FFA18081882319F081E001C09C\r
+:1008200080E0A7960FB6F894DEBF0FBECDBFCF9184\r
+:10083000DF911F910F91FF90EF90DF90CF90BF90CD\r
+:10084000AF909F908F907F906F905F904F903F9070\r
+:100850002F9008952F923F924F925F926F927F92C6\r
+:100860008F929F92AF92BF92CF92DF92EF92FF92C0\r
+:100870000F931F93DF93CF93CDB7DEB7A8970FB633\r
+:10088000F894DEBF0FBECDBF98A78FA3009709F4E1\r
+:100890005CC1DC0114968D919C911597892B09F40C\r
+:1008A00054C116968D919C911797892B09F44DC1CF\r
+:1008B00068C1E8E2F1E08AE1DF011D928A95E9F77B\r
+:1008C000EFA1F8A5F0932901E09328012184328457\r
+:1008D0004384548459E0220C331C441C551C5A9503\r
+:1008E000D1F7C201B101655F7F4F8F4F9F4F0190DC\r
+:1008F000F081E02DAE014F5F5F4F29E130E00995B7\r
+:10090000882309F445C1E981FA81FBA3EAA32C817C\r
+:100910003D81FB81FCA34E818F8198859EA38DA391\r
+:10092000E985FA856C857D856E887F88888C998CB1\r
+:10093000611471048104910431F4309709F428C1E1\r
+:100940003F01882499246115710509F421C1C90169\r
+:10095000A0E0B0E08E8F9F8FA8A3B9A380E090E0C5\r
+:10096000242F30E040E050E00E94390F6A8F7B8FE7\r
+:100970008C8F9D8F840173012E8D3F8D48A159A1CD\r
+:10098000E21AF30A040B150BE61AF70A080B190B07\r
+:100990008AA19BA101972DA13EA145E0220F331F03\r
+:1009A0004A95E1F7820F931F6AA17BA10E94580F1D\r
+:1009B00080E090E0E61AF70A080B190B8CA1282FAB\r
+:1009C00030E040E050E0C801B7010E947F0F79019C\r
+:1009D0008A0195EFE9169FE0F90690E0090790E09B\r
+:1009E000190708F4D5C0A5EFEA16AFEFFA06A0E0A4\r
+:1009F0000A07A0E01A0728F486E0EFA1F8A580878F\r
+:100A000005C08BE0AFA1B8A518968C9388E1EAE207\r
+:100A1000F1E0DF011D928A95E9F7EAA1FBA15F01F0\r
+:100A2000CC24DD24C401B301A60195010E94390F35\r
+:100A300060932A0170932B0180932C0190932D01D8\r
+:100A4000C601B5012E8D3F8D48A159A10E94390FD5\r
+:100A5000260E371E481E591E20922E0130922F015D\r
+:100A60004092300150923101AFA1B8A518968C91F7\r
+:100A7000863029F064E070E080E090E004C062E03D\r
+:100A800070E080E090E022E030E040E050E0E20EF4\r
+:100A9000F31E041F151FA80197010E94390F6093D0\r
+:100AA00032017093330180933401909335014AA150\r
+:100AB0005BA150933701409336015CA1852F90E0F4\r
+:100AC000DC01EAA1FBA1AE9FC001AF9F900DBE9FCC\r
+:100AD000900D112490933901809338016A8D7B8D9C\r
+:100AE0008C8D9D8DA60195010E94390F20912E01BC\r
+:100AF00030912F014091300150913101620F731FED\r
+:100B0000841F951F60933E0170933F0180934001C5\r
+:100B100090934101ADA1BEA19D0140E050E0B5E040\r
+:100B2000220F331F441F551FBA95D1F7620F731F51\r
+:100B3000841F951F60933A0170933B0180933C01A1\r
+:100B400090933D0128E231E002C020E030E0C9018D\r
+:100B5000A8960FB6F894DEBF0FBECDBFCF91DF9140\r
+:100B60001F910F91FF90EF90DF90CF90BF90AF90CB\r
+:100B70009F908F907F906F905F904F903F902F90BD\r
+:100B800008958091280190912901892BF1F691CE49\r
+:100B90001092290110922801D8CFCF93DF93AC0196\r
+:100BA000DB01009789F16115710571F190968C91C7\r
+:100BB000909784FF29C08091750190917601892BCF\r
+:100BC00019F4E5E7F1E008C08091A6019091A70132\r
+:100BD000892BD1F4E6EAF1E09F012E5F3F4FBD0182\r
+:100BE0008BE2EB010990BE01E90109929E0181505F\r
+:100BF000C1F75183408391968D919C91929796A7CE\r
+:100C000085A710AA17A602C0E0E0F0E0CF01DF91AF\r
+:100C1000CF910895CF93DF939C01FB01009731F0B2\r
+:100C20006115710519F080A184FF23C020E030E038\r
+:100C3000C901DF91CF910895C4E4D1E0DF018BE2D7\r
+:100C40000D9009928150E1F73093430120934201C6\r
+:100C500010926F0110927001109271011092720146\r
+:100C600081A192A1909374018093730122E431E0F9\r
+:100C7000DFCF8091420190914301892BB9F6DCCFFF\r
+:100C80006F927F928F929F92AF92BF92CF92DF929C\r
+:100C9000EF92FF920F931F93CF93DF934C01EB01E1\r
+:100CA0007A01009709F467C06115710509F463C002\r
+:100CB0008881882309F45FC04115510509F45BC0A0\r
+:100CC0008F3209F421968BE2F70111928A95E9F7A8\r
+:100CD00080E1F70180A3370101C0E5018881882305\r
+:100CE00009F44BC0C401B7010E94CD056C01009707\r
+:100CF00009F441C0CE016FE270E00E9495000097B8\r
+:100D000039F0482F4C1B5C010894A11CB11C2AC06F\r
+:100D1000FE0101900020E9F731974E2F4C1B5E0138\r
+:100D2000A40EB11C1FC0F30101900020E9F7319718\r
+:100D3000E619F709E017F107B9F4CE01B301A801EC\r
+:100D40000E94B000009781F4F601118210820C0F0E\r
+:100D50001D1FF8018081882381F0F70180A184FDA7\r
+:100D6000BCCF09C0042F10E0C601B7010E943F03A9\r
+:100D70008823C9F612C080E001C081E0DF91CF91E5\r
+:100D80001F910F91FF90EF90DF90CF90BF90AF90A9\r
+:100D90009F908F907F906F900895F601118210823E\r
+:100DA0009DCF8F929F92AF92BF92CF92DF92EF92A0\r
+:100DB000FF920F93DF93CF93CDB7DEB760970FB657\r
+:100DC000F894DEBF0FBECDBF7C016B015A01490113\r
+:100DD000009709F493C06115710509F48FC00430C0\r
+:100DE0000CF08CC007FD1DC0602F772767FD709544\r
+:100DF000E4E0660F771FEA95E1F762547E4F88279B\r
+:100E000077FD8095982FAE014F5F5F4F20E130E076\r
+:100E1000F7010995882309F471C08D81882309F4AD\r
+:100E20006DC08091DF01882309F068C07CC08D818E\r
+:100E30008093DF012A8530E040E050E0542F432FBB\r
+:100E4000322F22278B8590E0A0E0B0E0DC019927CB\r
+:100E50008827282B392B4A2B5B2B898590E0A0E033\r
+:100E6000B0E0282B392B4A2B5B2B8C8590E0A0E03F\r
+:100E7000B0E0B82FAA2799278827282B392B4A2B8F\r
+:100E80005B2B2093E0013093E1014093E20150930A\r
+:100E9000E3012E8530E040E050E0542F432F322F05\r
+:100EA00022278F8590E0A0E0B0E0DC019927882719\r
+:100EB000282B392B4A2B5B2B8D8590E0A0E0B0E0EE\r
+:100EC000282B392B4A2B5B2B888990E0A0E0B0E0DF\r
+:100ED000B82FAA2799278827282B392B4A2B5B2B39\r
+:100EE0002093E4013093E5014093E6015093E7013C\r
+:100EF00003C08FEF8093DF019F0102C020E030E04C\r
+:100F0000C90160960FB6F894DEBF0FBECDBFCF917A\r
+:100F1000DF910F91FF90EF90DF90CF90BF90AF9057\r
+:100F20009F908F900895E7EDF1E081E1DF011D9240\r
+:100F30008A95E9F7F092D801E092D701D092DA01D0\r
+:100F4000C092D901B092DC01A092DB019092DE0147\r
+:100F50008092DD0107FF6BCFCCCF282F8FEF8EBDA6\r
+:100F60000DB407FEFDCF8DB58F778DBD8EB5822F69\r
+:100F700080648EBD0DB407FEFDCF8DB58F778DBD1E\r
+:100F8000872F9927AA27BB278EBD0DB407FEFDCF5B\r
+:100F90008DB58F778DBDCB01AA27BB278EBD0DB434\r
+:100FA00007FEFDCF8DB58F778DBDBB27A72F962F61\r
+:100FB000852F8EBD0DB407FEFDCF8DB58F778DBD0E\r
+:100FC0004EBD0DB407FEFDCF8DB58F778DBD2223AD\r
+:100FD00019F0283069F406C085E98EBD0DB407FE0E\r
+:100FE000FDCF0BC087E88EBD0DB407FEFDCF05C059\r
+:100FF0008FEF8EBD0DB407FEFDCF8DB58F778DBD04\r
+:101000001092E9011092E80120E030E09FEF13C058\r
+:101010009EBD0DB407FEFDCF8DB58F778DBD8EB50E\r
+:10102000A9014F5F5F4F8F3F29F03093E901209373\r
+:10103000E80108959A012A30310550F33093E9010F\r
+:101040002093E8018FEF08952F923F924F925F9285\r
+:101050006F927F928F929F92AF92BF92CF92DF92C8\r
+:10106000EF92FF920F931F93CF93DF934B015C019D\r
+:101070002A01390133243A9422242394AFC0E40195\r
+:10108000D170CE01A0E0B0E085017401E81AF90A40\r
+:101090000A0B1B0BC12CB2E0DB2ECC1ADD0A6C1440\r
+:1010A0007D0408F463018091EA039091EB03A09121\r
+:1010B000EC03B091ED03E816F9060A071B07F9F0F7\r
+:1010C0000E940809882309F48FC0209729F480E042\r
+:1010D000C81682E0D80658F4C801B7014AEE51E0BC\r
+:1010E00020E032E00E942209882309F47DC0E092CA\r
+:1010F000EA03F092EB030093EC031093ED038AEE06\r
+:10110000481681E0580671F09E0126513E4FC901F4\r
+:10111000B201A6010E948C001092EE036C147D04B3\r
+:1011200009F460C0289888E1B801A7010E94AD07C2\r
+:10113000882311F0289A58C08EEF8EBD0DB407FE9B\r
+:10114000FDCF8DB58F778DBD1092E9011092E8012A\r
+:10115000EAEEF1E020E030E00BC080818EBD0DB4FE\r
+:1011600007FEFDCF31968DB58F778DBD2F5F3F4F39\r
+:1011700082E02030380788F33093E9012093E801BA\r
+:101180003EBC0DB407FEFDCF8DB58F778DBD3EBC47\r
+:101190000DB407FEFDCF8DB58F778DBD3EBC0DB470\r
+:1011A00007FEFDCF8DB58F778DBD8EB58F3FB1F723\r
+:1011B0008EBD0DB407FEFDCF8DB58F778DBD8EB57D\r
+:1011C000289A4C0C5D1CC601A0E0B0E0880E991E68\r
+:1011D000AA1EBB1E6C187D082092EE0361147104D8\r
+:1011E00009F04DCF81E001C080E0DF91CF911F91E8\r
+:1011F0000F91FF90EF90DF90CF90BF90AF909F90B6\r
+:101200008F907F906F905F904F903F902F900895B8\r
+:101210008091EE03882311F081E008956091EA0344\r
+:101220007091EB038091EC039091ED034AEE51E055\r
+:1012300020E032E00E942408882319F081E08093A6\r
+:10124000EE0308953F924F925F926F927F928F923A\r
+:101250009F92AF92BF92CF92DF92EF92FF920F9345\r
+:101260001F93CF93DF933B014C016A012901332483\r
+:101270003A9496C01FEFA12E11E0B12EA620B72000\r
+:10128000C501A0E0B0E084017301E81AF90A0A0B75\r
+:101290001B0BC0E0D2E0CA19DB094C165D0608F44E\r
+:1012A000E2018091EA039091EB03A091EC03B091ED\r
+:1012B000ED03E816F9060A071B0709F45EC00E9451\r
+:1012C0000809882309F471C0289881E1B801A701B1\r
+:1012D0000E94AD07882319F0289A80E066C03EBCC2\r
+:1012E0000DB407FEFDCF8DB58F778DBD8EB58E3FCA\r
+:1012F000B1F7EAEEF1E020E030E00BC03EBC0DB407\r
+:1013000007FEFDCF8DB58F778DBD8EB581932F5F95\r
+:101310003F4F82E02030380788F33093E901209373\r
+:10132000E801E092EA03F092EB030093EC031093E0\r
+:10133000ED03950126513E4FC601B901AE010E9451\r
+:101340008C003EBC0DB407FEFDCF8DB58F778DBDF3\r
+:101350008EB53EBC0DB407FEFDCF8DB58F778DBD2C\r
+:101360008EB5289A3EBC0DB407FEFDCFCC0EDD1E17\r
+:101370008DB58F778DBD8EB50AC0950126513E4F34\r
+:10138000C601B901AE010E948C00CC0EDD1E4C1AC4\r
+:101390005D0ACE01A0E0B0E0680E791E8A1E9B1E99\r
+:1013A0004114510409F066CF81E0DF91CF911F9184\r
+:1013B0000F91FF90EF90DF90CF90BF90AF909F90F4\r
+:1013C0008F907F906F905F904F903F9008952F92F5\r
+:1013D0003F924F925F926F927F928F929F92AF92C5\r
+:1013E000BF92CF92DF92EF92FF920F931F93DF9302\r
+:1013F000CF9300D000D0CDB7DEB74B015C013A01EE\r
+:101400003C832B832701DA82C98241155105A9F15A\r
+:101410002115310591F10217130778F1E114F10458\r
+:1014200061F119013094219431083394021B130B9C\r
+:101430006901EE24FF24C501B401A3012B813C8185\r
+:101440000E9422098823C9F0C301B501A4012981A2\r
+:101450003A81F2010995882391F0020D131D8B81C9\r
+:101460009C81800F911F2B813C818217930738F05C\r
+:101470008C0C9D1CAE1CBF1CDECF80E001C081E047\r
+:101480000F900F900F900F90CF91DF911F910F91C0\r
+:10149000FF90EF90DF90CF90BF90AF909F908F9094\r
+:1014A0007F906F905F904F903F902F9008951F9383\r
+:1014B000CF93DF93239A259A209A24982C9A289ADE\r
+:1014C00083E58CBD8DB58E7F8DBD1092EF0320E03E\r
+:1014D00030E09FEF0AC09EBD0DB407FEFDCF8DB575\r
+:1014E0008F778DBD8EB52F5F3F4F2A30310598F332\r
+:1014F0003093E9012093E80128981092E9011092B5\r
+:10150000E80180E040E050E060E070E00E94AD075C\r
+:10151000182F813079F08091E8019091E90121E064\r
+:101520008F3F920709F44DC001969093E901809393\r
+:10153000E801E7CF87E340E050E060E070E00E9420\r
+:10154000AD0789E240E050E060E070E00E94AD0746\r
+:1015500082FD02C01093EF031092E9011092E8019E\r
+:101560008091EF03C82FD0E0C370D070209749F06E\r
+:1015700087E340E050E060E070E00E94AD0789E260\r
+:1015800001C081E040E050E060E070E00E94AD0703\r
+:1015900080FF0EC08091E8019091E9012FE78F3F15\r
+:1015A000920779F001969093E9018093E801DECFEC\r
+:1015B00080E140E052E060E070E00E94AD078823E7\r
+:1015C00019F0289A80E022C0289A8CB58C7F8CBDB7\r
+:1015D0008DB581608DBD8FEF9FEFAFEFBFEF809333\r
+:1015E000EA039093EB03A093EC03B093ED0381E047\r
+:1015F0008093EE0360E070E080E090E04AEE51E01E\r
+:1016000020E032E00E942209811181E0DF91CF9138\r
+:101610001F9108954F925F926F927F928F929F9247\r
+:10162000AF92BF92CF92DF92EF92FF920F931F93F0\r
+:10163000CF93DF935B016C014A01E9013801270177\r
+:101640004115510571F10115110559F1FF242115BD\r
+:10165000310511F5FF24F3941FC0C401B601A501A3\r
+:101660009201F30109958C010097E9F0FF2019F42C\r
+:10167000C817D907B0F0C601B501A40198010E94AE\r
+:101680002408882371F0C801A0E0B0E0A80EB91EBC\r
+:10169000CA1EDB1EC01BD10BFF20F9F62097E9F60E\r
+:1016A00002C080E001C081E0DF91CF911F910F91D6\r
+:1016B000FF90EF90DF90CF90BF90AF909F908F9072\r
+:1016C0007F906F905F904F900895CF93DF93EB01E1\r
+:1016D00060E175E00E943F03882359F0CE0160E18C\r
+:1016E00075E00E94A9008EEC95E0BE010E942E0FCD\r
+:1016F00081E0DF91CF9108950F930E94570A8823CC\r
+:1017000009F445C082E299E067EE79E044E258E0EE\r
+:101710002AE03BE000E00E94D10690933E058093D2\r
+:101720003D05892B89F482E299E067EE79E044E295\r
+:1017300058E02AE03BE00FEF0E94D10690933E056F\r
+:1017400080933D05892B19F180913D0590913E05CF\r
+:101750000E942A0490933C0580933B050097B9F0C2\r
+:1017600060E071E040E155E00E94400680913B0559\r
+:1017700090913C0560E175E00E94CD0590930F05C6\r
+:1017800080930E0520E0892B19F021E001C020E0B4\r
+:10179000822F0F910895EF92FF920F931F93CF9393\r
+:1017A000DF93EB018A017901CB010E944E0208C050\r
+:1017B000C701B8010E94A000009711F481E006C0A3\r
+:1017C000CE01B7010E943F03882391F7DF91CF91AB\r
+:1017D0001F910F91FF90EF900895EF92FF920F935A\r
+:1017E0001F93DF93CF93CDB7DEB7AB970FB6F894C7\r
+:1017F000DEBF0FBECDBF8C017E010894E11CF11C41\r
+:1018000097010E94CB0B882319F420E030E005C03B\r
+:10181000C801B7010E940A069C01C901AB960FB628\r
+:10182000F894DEBF0FBECDBFCF91DF911F910F9116\r
+:10183000FF90EF900895CF93DF930E947C0B32C00E\r
+:1018400060910E0570910F0580913B0590913C05CC\r
+:1018500040EF54E00E94ED0B9093400580933F05CC\r
+:1018600060EF73E040E051E00E940401EC018EEC77\r
+:1018700095E060EF73E00E942E0F80913F059091FC\r
+:1018800040051C161D0664F30E94FE0068EE73E01E\r
+:1018900080E090E00E94D10C8EEC95E062E071E077\r
+:1018A0000E942E0F80910E0590910F0560EF74E05D\r
+:1018B0000E94650B882321F6FFCF80E060E00E9444\r
+:1018C000350D81E061E00E94350D8EEC95E040E839\r
+:1018D00055E260E070E00E94920D88E061E00E94B5\r
+:1018E000350D8BE061E00E94350D8CE060E00E94D8\r
+:1018F000350D8DE061E00E94350D8AE061E00E94C7\r
+:10190000350D08950E94FB0C0E945D0C0E941B0C7B\r
+:10191000FDCF1F920F920FB60F9211242F933F937A\r
+:101920008F939F93AF93BF93809145059091460508\r
+:10193000A0914705B0914805309149050196A11D38\r
+:10194000B11D232F2D5F2D3720F02D570196A11D9E\r
+:10195000B11D209349058093450590934605A093BA\r
+:101960004705B09348058091410590914205A091AB\r
+:101970004305B09144050196A11DB11D8093410519\r
+:1019800090934205A0934305B0934405BF91AF9156\r
+:101990009F918F913F912F910F900FBE0F901F90AD\r
+:1019A0001895EF92FF920F931F937B018C018FB7D5\r
+:1019B000F894409145055091460560914705709116\r
+:1019C00048058FBF2FB7F894809145059091460543\r
+:1019D000A0914705B09148052FBF841B950BA60B1E\r
+:1019E000B70BE816F9060A071B0760F71F910F915E\r
+:1019F000FF90EF900895789484B5826084BD84B59B\r
+:101A0000816084BD85B5826085BD85B5816085BDF9\r
+:101A1000EEE6F0E0808181608083E1E8F0E08081A3\r
+:101A200082608083808181608083E0E8F0E0808153\r
+:101A300081608083E1EBF0E0808184608083E0EB73\r
+:101A4000F0E0808181608083EAE7F0E0808184605B\r
+:101A500080838081826080838081816080838081B7\r
+:101A6000806880831092C1000895282F30E0C9015A\r
+:101A700086569F4FFC0194912A573F4FF90184915C\r
+:101A8000882391F0E82FF0E0EE0FFF1FE859FF4F99\r
+:101A9000A591B491662329F48C91909589238C9318\r
+:101AA00008958C91892B8C9308951F920F920FB6F5\r
+:101AB0000F9211242F933F934F935F936F937F93D4\r
+:101AC0008F939F93AF93BF93EF93FF934091C60083\r
+:101AD000E091CA05F091CB05CF01019660E870E076\r
+:101AE0000E946C0F9C018091CC059091CD05281728\r
+:101AF000390739F0E65BFA4F40833093CB052093EA\r
+:101B0000CA05FF91EF91BF91AF919F918F917F9106\r
+:101B10006F915F914F913F912F910F900FBE0F905A\r
+:101B20001F9018955F926F927F928F929F92AF92C3\r
+:101B3000BF92CF92DF92EF92FF920F931F93CF93BA\r
+:101B4000DF93EC013A014B01413482E458078FE006\r
+:101B5000680780E078070CF07FC060E874E88EE1E9\r
+:101B600090E0A40193010E94A10F21503040404019\r
+:101B70005040CA01B90122E030E040E050E00E944C\r
+:101B8000A10F59016A01A601950120953095409554\r
+:101B9000509594E0220F331F441F551F9A95D1F79B\r
+:101BA00060E074E284EF90E00E94A10FCA01B901E5\r
+:101BB0002FEF30E040E050E00E94390FA401930184\r
+:101BC0000E94A10FC90181509F4F181619061CF4DD\r
+:101BD000522E5A9403C055245394521A60E079E06F\r
+:101BE0008DE390E0A40193010E94A10F21503040A9\r
+:101BF00040405040CA01B90122E030E040E050E0EE\r
+:101C00000E94A10F209530954095509583E0220FBA\r
+:101C1000331F441F551F8A95D1F760E074E284EFAB\r
+:101C200090E00E94A10FCA01B9012FEF30E040E01F\r
+:101C300050E00E94390FA40193010E94A10FC90135\r
+:101C400081509F4F181619061CF4822F815002C034\r
+:101C500081E0821B851500F5E885F98581E090E03B\r
+:101C60000A8802C0880F991F0A94E2F7808360E017\r
+:101C700079E08DE390E0A40193010E94A10F21502F\r
+:101C8000304040405040CA01B90122E030E040E01D\r
+:101C900050E00E94A10F04C0E885F98510829501EB\r
+:101CA000EC81FD813083EE81FF812083EA85FB8515\r
+:101CB000208141E050E0CA010E8402C0880F991FC4\r
+:101CC0000A94E2F7282B2083EA85FB852081CA014C\r
+:101CD0000F8402C0880F991F0A94E2F7282B2083F3\r
+:101CE000EA85FB858081088802C0440F551F0A944D\r
+:101CF000E2F7842B8083DF91CF911F910F91FF90AA\r
+:101D0000EF90DF90CF90BF90AF909F908F907F909B\r
+:101D10006F905F900895FC01A085B18521898C9119\r
+:101D200090E0022E02C0959587950A94E2F780FF15\r
+:101D3000F6CF0484F585E02D6083089580E291E07C\r
+:101D40009093CF058093CE058AE495E09093D105DA\r
+:101D50008093D00585EC90E09093D3058093D205D5\r
+:101D600084EC90E09093D5058093D40580EC90E0CE\r
+:101D70009093D7058093D60581EC90E09093D90598\r
+:101D80008093D80586EC90E09093DB058093DA058C\r
+:101D900084E08093DC0583E08093DD0587E0809319\r
+:101DA000DE0585E08093DF0581E08093E0050895FE\r
+:101DB0000F931F93CF93DF938C01EB0109C0219602\r
+:101DC000D801ED91FC910190F081E02DC8010995B9\r
+:101DD00068816623A1F7DF91CF911F910F9108953C\r
+:101DE000EF92FF920F931F93CF93DF938C017B01B0\r
+:101DF000EA010CC0D7016D917D01D801ED91FC91F4\r
+:101E00000190F081E02DC80109952197209791F765\r
+:101E1000DF91CF911F910F91FF90EF900895DC011A\r
+:101E2000ED91FC910280F381E02D099508950F93C7\r
+:101E30001F938C01DC01ED91FC910190F081E02D6C\r
+:101E40006DE00995D801ED91FC910190F081E02DB4\r
+:101E5000C8016AE009951F910F9108950F931F9390\r
+:101E60008C010E940F0FC8010E94170F1F910F9144\r
+:101E70000895629FD001739FF001829FE00DF11DD4\r
+:101E8000649FE00DF11D929FF00D839FF00D749FF4\r
+:101E9000F00D659FF00D9927729FB00DE11DF91FA0\r
+:101EA000639FB00DE11DF91FBD01CF0111240895FD\r
+:101EB000AA1BBB1B51E107C0AA1FBB1FA617B70770\r
+:101EC00010F0A61BB70B881F991F5A95A9F780958C\r
+:101ED0009095BC01CD01089597FB092E07260AD0E5\r
+:101EE00077FD04D0E5DF06D000201AF470956195E7\r
+:101EF0007F4F0895F6F7909581959F4F0895A1E241\r
+:101F00001A2EAA1BBB1BFD010DC0AA1FBB1FEE1F73\r
+:101F1000FF1FA217B307E407F50720F0A21BB30BBE\r
+:101F2000E40BF50B661F771F881F991F1A9469F73A\r
+:101F300060957095809590959B01AC01BD01CF0196\r
+:101F4000089597FB092E05260ED057FD04D0D7DF44\r
+:101F50000AD0001C38F450954095309521953F4F9C\r
+:101F60004F4F5F4F0895F6F7909580957095619566\r
+:101F70007F4F8F4F9F4F0895EE0FFF1F0590F491F5\r
+:081F8000E02D0994F894FFCF55\r
+:101F88002F004E6578742046696C652E2E2E000150\r
+:101F9800030507090E10121416181C1E0000000075\r
+:061FA8008B0ED80EF00EB6\r
+:00000001FF\r
diff --git a/FAT16/examples/FAT16_ReadExample/applet/FAT16_ReadExample.cpp.o b/FAT16/examples/FAT16_ReadExample/applet/FAT16_ReadExample.cpp.o
new file mode 100644 (file)
index 0000000..5d241a8
Binary files /dev/null and b/FAT16/examples/FAT16_ReadExample/applet/FAT16_ReadExample.cpp.o differ
diff --git a/FAT16/examples/FAT16_ReadExample/applet/HardwareSerial.cpp.o b/FAT16/examples/FAT16_ReadExample/applet/HardwareSerial.cpp.o
new file mode 100644 (file)
index 0000000..d5af083
Binary files /dev/null and b/FAT16/examples/FAT16_ReadExample/applet/HardwareSerial.cpp.o differ
diff --git a/FAT16/examples/FAT16_ReadExample/applet/Print.cpp.o b/FAT16/examples/FAT16_ReadExample/applet/Print.cpp.o
new file mode 100644 (file)
index 0000000..c63f9bf
Binary files /dev/null and b/FAT16/examples/FAT16_ReadExample/applet/Print.cpp.o differ
diff --git a/FAT16/examples/FAT16_ReadExample/applet/WInterrupts.c.o b/FAT16/examples/FAT16_ReadExample/applet/WInterrupts.c.o
new file mode 100644 (file)
index 0000000..52801e4
Binary files /dev/null and b/FAT16/examples/FAT16_ReadExample/applet/WInterrupts.c.o differ
diff --git a/FAT16/examples/FAT16_ReadExample/applet/WMath.cpp.o b/FAT16/examples/FAT16_ReadExample/applet/WMath.cpp.o
new file mode 100644 (file)
index 0000000..d8792d0
Binary files /dev/null and b/FAT16/examples/FAT16_ReadExample/applet/WMath.cpp.o differ
diff --git a/FAT16/examples/FAT16_ReadExample/applet/core.a b/FAT16/examples/FAT16_ReadExample/applet/core.a
new file mode 100644 (file)
index 0000000..c16866b
Binary files /dev/null and b/FAT16/examples/FAT16_ReadExample/applet/core.a differ
diff --git a/FAT16/examples/FAT16_ReadExample/applet/pins_arduino.c.o b/FAT16/examples/FAT16_ReadExample/applet/pins_arduino.c.o
new file mode 100644 (file)
index 0000000..c1fa9f5
Binary files /dev/null and b/FAT16/examples/FAT16_ReadExample/applet/pins_arduino.c.o differ
diff --git a/FAT16/examples/FAT16_ReadExample/applet/wiring.c.o b/FAT16/examples/FAT16_ReadExample/applet/wiring.c.o
new file mode 100644 (file)
index 0000000..394cbe8
Binary files /dev/null and b/FAT16/examples/FAT16_ReadExample/applet/wiring.c.o differ
diff --git a/FAT16/examples/FAT16_ReadExample/applet/wiring_analog.c.o b/FAT16/examples/FAT16_ReadExample/applet/wiring_analog.c.o
new file mode 100644 (file)
index 0000000..619dd14
Binary files /dev/null and b/FAT16/examples/FAT16_ReadExample/applet/wiring_analog.c.o differ
diff --git a/FAT16/examples/FAT16_ReadExample/applet/wiring_digital.c.o b/FAT16/examples/FAT16_ReadExample/applet/wiring_digital.c.o
new file mode 100644 (file)
index 0000000..02809ce
Binary files /dev/null and b/FAT16/examples/FAT16_ReadExample/applet/wiring_digital.c.o differ
diff --git a/FAT16/examples/FAT16_ReadExample/applet/wiring_pulse.c.o b/FAT16/examples/FAT16_ReadExample/applet/wiring_pulse.c.o
new file mode 100644 (file)
index 0000000..354b096
Binary files /dev/null and b/FAT16/examples/FAT16_ReadExample/applet/wiring_pulse.c.o differ
diff --git a/FAT16/examples/FAT16_ReadExample/applet/wiring_shift.c.o b/FAT16/examples/FAT16_ReadExample/applet/wiring_shift.c.o
new file mode 100644 (file)
index 0000000..2f318d0
Binary files /dev/null and b/FAT16/examples/FAT16_ReadExample/applet/wiring_shift.c.o differ
diff --git a/FAT16/examples/FAT16_WriteExample/FAT16_WriteExample.pde b/FAT16/examples/FAT16_WriteExample/FAT16_WriteExample.pde
new file mode 100644 (file)
index 0000000..9322df3
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+FAT16 WriteFile Example Sketch
+SparkFun Electronics
+Written by Ryan Owens
+3/16/2010
+
+Code Description: Uses an Arduino Duemillanove or Arduino Pro to write a string to a file.
+
+Circuit Description: Uses the SparkFun microSD shield. (http://www.sparkfun.com/commerce/product_info.php?products_id=9520)
+
+Attributions: Special thanks to Roland Riegel for providing an open source FAT library 
+for AVR microcontrollers. See more of his projects here:
+http://www.roland-riegel.de/
+
+This code is provided under the Creative Commons Attribution License. More information can be found here:
+http://creativecommons.org/licenses/by/3.0/
+
+(Use our code freely! Please just remember to give us credit where it's due. Thanks!)
+*/
+
+//Add libraries to support FAT16 on the SD Card.
+//(Note: If you already have these libraries installed in the directory, they'll have to remove in order to compile this.)
+#include <byteordering.h>
+#include <fat.h>
+#include <fat_config.h>
+#include <partition.h>
+#include <partition_config.h>
+#include <sd-reader_config.h>
+#include <sd_raw.h>
+#include <sd_raw_config.h>
+
+//Define the pin numbers
+#define CS    8
+#define MOSI    11
+#define MISO    12
+#define SCK    13
+
+//This is the amount of data to be fetched from the SD card for each read.
+#define BUFFERSIZE     256
+
+char buffer[BUFFERSIZE]="Testing\n";
+char file_name[30];
+
+struct fat_dir_struct* dd;             //FAT16 directory
+struct fat_dir_entry_struct dir_entry; //FAT16 directory entry (A.K.A. a file)
+
+struct fat_fs_struct* fs;              //FAT16 File System
+struct partition_struct* partition;    //FAT16 Partition
+
+struct fat_file_struct * file_handle;  //FAT16 File Handle
+
+void setup()
+{
+    //Set up the pins for the Serial communication
+    pinMode(0, INPUT);
+    pinMode(1, OUTPUT);
+    Serial.begin(9600);
+    //Set up the pins for the microSD shield
+    pinMode(CS, OUTPUT);
+    pinMode(MOSI, OUTPUT);
+    pinMode(MISO, INPUT);
+    pinMode(SCK, OUTPUT);
+    pinMode(10, OUTPUT);
+}
+
+void loop()
+{
+  int bytes_read=0; //Keeps track of how many bytes are read when accessing a file on the SD card.
+  int count=0;
+
+  init_filesystem();   //Initialize the FAT16 file system on the SD card.
+  
+  //Create a file named Test.txt. If the file already exists, delete it and create a new one.
+  if(!fat_create_file(dd, "Test.txt", &dir_entry)){
+      fat_delete_file(fs, &dir_entry);
+      fat_create_file(dd, "Test.txt", &dir_entry);
+  }
+  //Open the file that's just been created
+  file_handle=open_file_in_dir(fs, dd, "Test.txt");
+  //Write some initial data to the file
+  fat_write_file(file_handle, (const uint8_t*)buffer, strlen(buffer));
+  sd_raw_sync();    //An SD sync must be performed after each write operation
+  fat_close_file(file_handle);    //Close the file.
+  while(1){
+      //Open the file (now we're at the beginning of the file again.
+      open_file_in_dir(fs, dd, "Test.txt");
+      //Read the contents of the file (up to 512 bytes)
+      bytes_read = fat_read_file(file_handle, (uint8_t*)buffer, BUFFERSIZE);
+      //Print the contents of the file
+      Serial.println((const char*)buffer);
+      //Now go to the end of the file to write some data.
+      fat_seek_file(file_handle, 0, FAT_SEEK_END);
+      sprintf(buffer, "%d", count++);
+      //Write the new 'buffer' string to the end of the file
+      fat_write_file(file_handle, (const uint8_t*)buffer, strlen(buffer));
+      sd_raw_sync();
+      //Close the file, we're finished!
+      fat_close_file(file_handle);
+      delay(1000);
+  }
+  
+  while(1);
+}
+
+uint8_t find_file_in_dir(struct fat_fs_struct* fs, struct fat_dir_struct* dd, const char* name, struct fat_dir_entry_struct* dir_entry)
+{
+       fat_reset_dir(dd);      //Make sure to start from the beginning of the directory!
+    while(fat_read_dir(dd, dir_entry))
+    {
+        if(strcmp(dir_entry->long_name, name) == 0)
+        {
+            //fat_reset_dir(dd);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+struct fat_file_struct* open_file_in_dir(struct fat_fs_struct* fs, struct fat_dir_struct* dd, const char* name)
+{
+    struct fat_dir_entry_struct file_entry;
+    if(!find_file_in_dir(fs, dd, name, &file_entry))
+        return 0;
+
+    return fat_open_file(fs, &file_entry);
+}
+
+char init_filesystem(void)
+{
+       //setup sd card slot 
+       if(!sd_raw_init())
+       {
+               return 0;
+       }
+
+       //open first partition
+       partition = partition_open(sd_raw_read,
+                                                                       sd_raw_read_interval,
+#if SD_RAW_WRITE_SUPPORT
+                                                                       sd_raw_write,
+                                                                       sd_raw_write_interval,
+#else
+                                                                       0,
+                                                                       0,
+#endif
+                                                                       0
+                                                          );
+
+       if(!partition)
+       {
+               //If the partition did not open, assume the storage device
+               //is a "superfloppy", i.e. has no MBR.
+               partition = partition_open(sd_raw_read,
+                                                                  sd_raw_read_interval,
+#if SD_RAW_WRITE_SUPPORT
+                                                                  sd_raw_write,
+                                                                  sd_raw_write_interval,
+#else
+                                                                  0,
+                                                                  0,
+#endif
+                                                                  -1
+                                                                 );
+               if(!partition)
+               {
+                       return 0;
+               }
+       }
+
+       //Open file system
+       fs = fat_open(partition);
+       if(!fs)
+       {
+               return 0;
+       }
+
+       //Open root directory
+       fat_get_dir_entry_of_path(fs, "/", &dir_entry);
+       dd=fat_open_dir(fs, &dir_entry);
+       
+       if(!dd)
+       {
+               return 0;
+       }
+       return 1;
+}
+
+char get_next_filename(struct fat_dir_struct* cur_dir, char * new_file)
+{
+    //'dir_entry' is a global variable of type directory_entry_struct
+
+    //Get the next file from the root directory
+    if(fat_read_dir(cur_dir, &dir_entry))
+    {
+       sprintf(new_file, "%s", dir_entry.long_name);
+        Serial.println((const char *)new_file);
+        return 1;
+    }
+    //If another file isn't found, return 0
+    return 0;
+}
+
+\r
diff --git a/FAT16/examples/FAT16_WriteExample/applet/FAT16/byteordering.c.o b/FAT16/examples/FAT16_WriteExample/applet/FAT16/byteordering.c.o
new file mode 100644 (file)
index 0000000..07d283e
Binary files /dev/null and b/FAT16/examples/FAT16_WriteExample/applet/FAT16/byteordering.c.o differ
diff --git a/FAT16/examples/FAT16_WriteExample/applet/FAT16/fat.c.o b/FAT16/examples/FAT16_WriteExample/applet/FAT16/fat.c.o
new file mode 100644 (file)
index 0000000..1125cad
Binary files /dev/null and b/FAT16/examples/FAT16_WriteExample/applet/FAT16/fat.c.o differ
diff --git a/FAT16/examples/FAT16_WriteExample/applet/FAT16/partition.c.o b/FAT16/examples/FAT16_WriteExample/applet/FAT16/partition.c.o
new file mode 100644 (file)
index 0000000..f5741e1
Binary files /dev/null and b/FAT16/examples/FAT16_WriteExample/applet/FAT16/partition.c.o differ
diff --git a/FAT16/examples/FAT16_WriteExample/applet/FAT16/sd_raw.c.o b/FAT16/examples/FAT16_WriteExample/applet/FAT16/sd_raw.c.o
new file mode 100644 (file)
index 0000000..b020ac4
Binary files /dev/null and b/FAT16/examples/FAT16_WriteExample/applet/FAT16/sd_raw.c.o differ
diff --git a/FAT16/examples/FAT16_WriteExample/applet/FAT16_WriteExample.cpp b/FAT16/examples/FAT16_WriteExample/applet/FAT16_WriteExample.cpp
new file mode 100644 (file)
index 0000000..7fb0ea7
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+FAT16 WriteFile Example Sketch
+SparkFun Electronics
+Written by Ryan Owens
+3/16/2010
+
+Code Description: Uses an Arduino Duemillanove or Arduino Pro to write a string to a file.
+
+Circuit Description: Uses the SparkFun microSD shield. (http://www.sparkfun.com/commerce/product_info.php?products_id=9520)
+
+Attributions: Special thanks to Roland Riegel for providing an open source FAT library 
+for AVR microcontrollers. See more of his projects here:
+http://www.roland-riegel.de/
+
+This code is provided under the Creative Commons Attribution License. More information can be found here:
+http://creativecommons.org/licenses/by/3.0/
+
+(Use our code freely! Please just remember to give us credit where it's due. Thanks!)
+*/
+
+//Add libraries to support FAT16 on the SD Card.
+//(Note: If you already have these libraries installed in the directory, they'll have to remove in order to compile this.)
+#include <byteordering.h>
+#include <fat.h>
+#include <fat_config.h>
+#include <partition.h>
+#include <partition_config.h>
+#include <sd-reader_config.h>
+#include <sd_raw.h>
+#include <sd_raw_config.h>
+
+//Define the pin numbers
+#define CS    8
+#define MOSI    11
+#define MISO    12
+#define SCK    13
+
+//This is the amount of data to be fetched from the SD card for each read.
+#define BUFFERSIZE     256
+
+#include "WProgram.h"
+void setup();
+void loop();
+uint8_t find_file_in_dir(struct fat_fs_struct* fs, struct fat_dir_struct* dd, const char* name, struct fat_dir_entry_struct* dir_entry);
+struct fat_file_struct* open_file_in_dir(struct fat_fs_struct* fs, struct fat_dir_struct* dd, const char* name);
+char init_filesystem(void);
+char get_next_filename(struct fat_dir_struct* cur_dir, char * new_file);
+char buffer[BUFFERSIZE]="Testing\n";
+char file_name[30];
+
+struct fat_dir_struct* dd;             //FAT16 directory
+struct fat_dir_entry_struct dir_entry; //FAT16 directory entry (A.K.A. a file)
+
+struct fat_fs_struct* fs;              //FAT16 File System
+struct partition_struct* partition;    //FAT16 Partition
+
+struct fat_file_struct * file_handle;  //FAT16 File Handle
+
+void setup()
+{
+    //Set up the pins for the Serial communication
+    pinMode(0, INPUT);
+    pinMode(1, OUTPUT);
+    Serial.begin(9600);
+    //Set up the pins for the microSD shield
+    pinMode(CS, OUTPUT);
+    pinMode(MOSI, OUTPUT);
+    pinMode(MISO, INPUT);
+    pinMode(SCK, OUTPUT);
+    pinMode(10, OUTPUT);
+}
+
+void loop()
+{
+  int bytes_read=0; //Keeps track of how many bytes are read when accessing a file on the SD card.
+  int count=0;
+
+  init_filesystem();   //Initialize the FAT16 file system on the SD card.
+  
+  //Create a file named Test.txt. If the file already exists, delete it and create a new one.
+  if(!fat_create_file(dd, "Test.txt", &dir_entry)){
+      fat_delete_file(fs, &dir_entry);
+      fat_create_file(dd, "Test.txt", &dir_entry);
+  }
+  //Open the file that's just been created
+  file_handle=open_file_in_dir(fs, dd, "Test.txt");
+  //Write some initial data to the file
+  fat_write_file(file_handle, (const uint8_t*)buffer, strlen(buffer));
+  sd_raw_sync();    //An SD sync must be performed after each write operation
+  fat_close_file(file_handle);    //Close the file.
+  while(1){
+      //Open the file (now we're at the beginning of the file again.
+      open_file_in_dir(fs, dd, "Test.txt");
+      //Read the contents of the file (up to 512 bytes)
+      bytes_read = fat_read_file(file_handle, (uint8_t*)buffer, BUFFERSIZE);
+      //Print the contents of the file
+      Serial.println((const char*)buffer);
+      //Now go to the end of the file to write some data.
+      fat_seek_file(file_handle, 0, FAT_SEEK_END);
+      sprintf(buffer, "%d", count++);
+      //Write the new 'buffer' string to the end of the file
+      fat_write_file(file_handle, (const uint8_t*)buffer, strlen(buffer));
+      sd_raw_sync();
+      //Close the file, we're finished!
+      fat_close_file(file_handle);
+      delay(1000);
+  }
+  
+  while(1);
+}
+
+uint8_t find_file_in_dir(struct fat_fs_struct* fs, struct fat_dir_struct* dd, const char* name, struct fat_dir_entry_struct* dir_entry)
+{
+       fat_reset_dir(dd);      //Make sure to start from the beginning of the directory!
+    while(fat_read_dir(dd, dir_entry))
+    {
+        if(strcmp(dir_entry->long_name, name) == 0)
+        {
+            //fat_reset_dir(dd);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+struct fat_file_struct* open_file_in_dir(struct fat_fs_struct* fs, struct fat_dir_struct* dd, const char* name)
+{
+    struct fat_dir_entry_struct file_entry;
+    if(!find_file_in_dir(fs, dd, name, &file_entry))
+        return 0;
+
+    return fat_open_file(fs, &file_entry);
+}
+
+char init_filesystem(void)
+{
+       //setup sd card slot 
+       if(!sd_raw_init())
+       {
+               return 0;
+       }
+
+       //open first partition
+       partition = partition_open(sd_raw_read,
+                                                                       sd_raw_read_interval,
+#if SD_RAW_WRITE_SUPPORT
+                                                                       sd_raw_write,
+                                                                       sd_raw_write_interval,
+#else
+                                                                       0,
+                                                                       0,
+#endif
+                                                                       0
+                                                          );
+
+       if(!partition)
+       {
+               //If the partition did not open, assume the storage device
+               //is a "superfloppy", i.e. has no MBR.
+               partition = partition_open(sd_raw_read,
+                                                                  sd_raw_read_interval,
+#if SD_RAW_WRITE_SUPPORT
+                                                                  sd_raw_write,
+                                                                  sd_raw_write_interval,
+#else
+                                                                  0,
+                                                                  0,
+#endif
+                                                                  -1
+                                                                 );
+               if(!partition)
+               {
+                       return 0;
+               }
+       }
+
+       //Open file system
+       fs = fat_open(partition);
+       if(!fs)
+       {
+               return 0;
+       }
+
+       //Open root directory
+       fat_get_dir_entry_of_path(fs, "/", &dir_entry);
+       dd=fat_open_dir(fs, &dir_entry);
+       
+       if(!dd)
+       {
+               return 0;
+       }
+       return 1;
+}
+
+char get_next_filename(struct fat_dir_struct* cur_dir, char * new_file)
+{
+    //'dir_entry' is a global variable of type directory_entry_struct
+
+    //Get the next file from the root directory
+    if(fat_read_dir(cur_dir, &dir_entry))
+    {
+       sprintf(new_file, "%s", dir_entry.long_name);
+        Serial.println((const char *)new_file);
+        return 1;
+    }
+    //If another file isn't found, return 0
+    return 0;
+}
+
+
+
+int main(void)
+{
+       init();
+
+       setup();
+    
+       for (;;)
+               loop();
+        
+       return 0;
+}
+
diff --git a/FAT16/examples/FAT16_WriteExample/applet/FAT16_WriteExample.cpp.eep b/FAT16/examples/FAT16_WriteExample/applet/FAT16_WriteExample.cpp.eep
new file mode 100644 (file)
index 0000000..1996e8f
--- /dev/null
@@ -0,0 +1 @@
+:00000001FF\r
diff --git a/FAT16/examples/FAT16_WriteExample/applet/FAT16_WriteExample.cpp.elf b/FAT16/examples/FAT16_WriteExample/applet/FAT16_WriteExample.cpp.elf
new file mode 100644 (file)
index 0000000..a82c1fa
Binary files /dev/null and b/FAT16/examples/FAT16_WriteExample/applet/FAT16_WriteExample.cpp.elf differ
diff --git a/FAT16/examples/FAT16_WriteExample/applet/FAT16_WriteExample.cpp.hex b/FAT16/examples/FAT16_WriteExample/applet/FAT16_WriteExample.cpp.hex
new file mode 100644 (file)
index 0000000..8e576ae
--- /dev/null
@@ -0,0 +1,883 @@
+:100000000C9462000C948A000C948A000C948A0070\r
+:100010000C948A000C948A000C948A000C948A0038\r
+:100020000C948A000C948A000C948A000C948A0028\r
+:100030000C948A000C948A000C948A000C948A0018\r
+:100040000C9480170C948A000C944C180C948A0021\r
+:100050000C948A000C948A000C948A000C948A00F8\r
+:100060000C948A000C948A000000000024002700F1\r
+:100070002A0000000000250028002B0000000000DE\r
+:1000800023002600290004040404040404040202DA\r
+:100090000202020203030303030301020408102007\r
+:1000A0004080010204081020010204081020000012\r
+:1000B0000007000201000003040600000000000029\r
+:1000C0000000951911241FBECFEFD8E0DEBFCDBFD1\r
+:1000D00012E0A0E0B1E0E4EEF5E302C005900D927D\r
+:1000E000A632B107D9F715E0A6E2B2E001C01D9231\r
+:1000F000A33CB107E1F710E0C4ECD0E004C02297C4\r
+:10010000FE010E94B51AC23CD107C9F70E947917B7\r
+:100110000C94F01A0C940000FB01DC0102C0019069\r
+:100120000D9241505040D8F70895DC0101C06D9305\r
+:1001300041505040E0F70895FC018191861721F06D\r
+:100140008823D9F7992708953197CF010895FB01A6\r
+:10015000DC018D91019080190110D9F3990B08955C\r
+:10016000FB01DC014150504030F08D91019080192D\r
+:1001700019F40020B9F7881B990B0895FB01DC01E5\r
+:100180004150504048F001900D920020C9F701C045\r
+:100190001D9241505040E0F70895FC0181E090E04D\r
+:1001A0000190061609F4CF010020D1F701970895B8\r
+:1001B000AEE0B0E0EEEDF0E00C94C71A0D891E89B8\r
+:1001C00086E08C831A8309838FEF9FE79E838D835C\r
+:1001D0009E01275E3F4FCE0101966F89788DA90160\r
+:1001E0000E94FC002F813885020F131FF801108236\r
+:1001F0002E96E4E00C94E31AABE0B0E0E2E0F1E02C\r
+:100200000C94B91A3C012B015A01FC011782168289\r
+:10021000838181FD03C06FEF7FEFC6C19AE0892E15\r
+:100220001E010894211C311CF3012381F20123FDDE\r
+:10023000859123FF81912F01882309F4B2C1853272\r
+:1002400039F423FD859123FF81912F01853229F413\r
+:1002500090E0B3010E94EF02E7CF982FFF24EE2435\r
+:100260009924FFE1FF15D0F09B3269F09C3228F40D\r
+:10027000903259F0933291F40EC09D3249F0903390\r
+:1002800069F441E024C052E0F52A84E0F82A28C04D\r
+:1002900098E0F92A25C0E0E1FE2A22C0F7FC29C037\r
+:1002A000892F80538A3070F4F6FE05C0989C902CFC\r
+:1002B0001124980E15C0E89CE02C1124E80EF0E201\r
+:1002C000FF2A0EC09E3229F4F6FC6BC140E4F42AEA\r
+:1002D00007C09C3619F450E8F52A02C0983649F454\r
+:1002E000F20123FD959123FF91912F01992309F0AC\r
+:1002F000B8CF892F8554833018F08052833038F47A\r
+:1003000044E050E0A40EB51E5FE359830FC093365E\r
+:1003100031F0933779F0933509F056C020C0F501DC\r
+:100320008081898342E050E0A40EB51E610101E0A6\r
+:1003300010E012C0F501C080D180F6FC03C06FEF61\r
+:100340007FEF02C0692D70E042E050E0A40EB51EC0\r
+:10035000C6010E94E4028C015FE7F52214C0F5019A\r
+:10036000C080D180F6FC03C06FEF7FEF02C0692D23\r
+:1003700070E042E050E0A40EB51EC6010E94D90212\r
+:100380008C0150E8F52AF3FE07C01AC080E290E025\r
+:10039000B3010E94EF02EA948E2D90E0081719072E\r
+:1003A000A8F30EC0F601F7FC8591F7FE81916F016D\r
+:1003B00090E0B3010E94EF02E110EA940150104076\r
+:1003C0000115110579F7EAC0943611F0993669F5EF\r
+:1003D000F7FE08C0F501208131814281538184E01C\r
+:1003E00090E00AC0F501808191819C01442737FD8E\r
+:1003F0004095542F82E090E0A80EB91E9FE6F922A6\r
+:1004000057FF09C050954095309521953F4F4F4F6C\r
+:100410005F4FE0E8FE2ACA01B901A1012AE030E0FD\r
+:100420000E941B03D82ED21840C0953729F41F2DE7\r
+:100430001F7E2AE030E01DC01F2D197F9F3661F01E\r
+:10044000903720F4983509F0ACC00FC0903739F0E0\r
+:10045000983709F0A6C004C028E030E00AC0106157\r
+:1004600014FD146020E130E004C014FD166020E1AA\r
+:1004700032E017FF08C0F5016081718182819381AC\r
+:1004800044E050E008C0F50180819181BC0180E02A\r
+:1004900090E042E050E0A40EB51EA1010E941B03B3\r
+:1004A000D82ED2188FE7F82EF122F6FE0BC05EEFA1\r
+:1004B000F522D91438F4F4FE07C0F2FC05C08FEE23\r
+:1004C000F82202C01D2D01C0192DF4FE0DC0FE0141\r
+:1004D000ED0DF11D8081803319F499EEF92208C0E9\r
+:1004E0001F5FF2FE05C003C08F2D867809F01F5FE5\r
+:1004F0000F2DF3FC14C0F0FE0FC01E1510F09D2C44\r
+:100500000BC09D2C9E0C911A1E2D06C080E290E01F\r
+:10051000B3010E94EF021F5F1E15C0F304C01E1539\r
+:1005200010F4E11A01C0EE2404FF0FC080E390E054\r
+:10053000B3010E94EF0202FF1DC001FD03C088E766\r
+:1005400090E00EC088E590E00BC0802F867891F097\r
+:1005500001FF02C08BE201C080E2F7FC8DE290E077\r
+:10056000B3010E94EF0206C080E390E0B3010E9455\r
+:10057000EF029A94D914C0F3DA94F101ED0DF11D54\r
+:10058000808190E0B3010E94EF02DD20A9F706C050\r
+:1005900080E290E0B3010E94EF02EA94EE20C1F7FE\r
+:1005A00043CEF30166817781CB012B96E2E10C9477\r
+:1005B000D51AFC010590615070400110D8F7809564\r
+:1005C00090958E0F9F1F0895FC016150704001901F\r
+:1005D0000110D8F7809590958E0F9F1F08950F9367\r
+:1005E0001F93CF93DF938C01EB018B8181FF1BC0A5\r
+:1005F00082FF0DC02E813F818C819D812817390794\r
+:1006000064F4E881F9810193F983E88306C0E88501\r
+:10061000F985802F0995892B31F48E819F81019670\r
+:100620009F838E8302C00FEF1FEFC801DF91CF9130\r
+:100630001F910F910895FA01AA27283051F1203116\r
+:1006400081F1E8946F936E7F6E5F7F4F8F4F9F4F66\r
+:10065000AF4FB1E03ED0B4E03CD0670F781F891FA8\r
+:100660009A1FA11D680F791F8A1F911DA11D6A0F76\r
+:10067000711D811D911DA11D20D009F468943F9129\r
+:100680002AE0269F11243019305D3193DEF6CF0128\r
+:100690000895462F4770405D4193B3E00FD0C9F7EE\r
+:1006A000F6CF462F4F70405D4A3318F0495D31FD5B\r
+:1006B0004052419302D0A9F7EACFB4E0A6959795AE\r
+:1006C000879577956795BA95C9F700976105710584\r
+:1006D00008959B01AC010A2E0694579547953795CE\r
+:1006E0002795BA95C9F7620F731F841F951FA01D28\r
+:1006F0000895DF93CF9300D0CDB7DEB7DC0100972C\r
+:1007000081F16230710568F1ED91FC911197660FEE\r
+:10071000771F80E090E016962D913D914D915C9170\r
+:100720001997620F731F841F951F0190F081E02DB0\r
+:10073000AE014F5F5F4F22E030E00995882389F0DA\r
+:1007400029813A812115310571F08FEF273F380754\r
+:1007500041F0C9014096079720F08FEF283F3807F6\r
+:1007600010F020E030E0C9010F900F90CF91DF91A1\r
+:1007700008954F925F926F927F928F929F92AF9265\r
+:10078000BF92CF92DF92EF92FF920F931F93DF936E\r
+:10079000CF9300D0CDB7DEB75C01009709F449C014\r
+:1007A0006230710508F445C0DC0116966D907D90AD\r
+:1007B0008D909C9019972E010894411C511C660F36\r
+:1007C000771F7B0100E010E0E60CF71C081D191DE7\r
+:1007D000D501ED91FC910190F081E02DC801B701A8\r
+:1007E000A20122E030E00995882319F1C980DA805E\r
+:1007F000C114D10401F1C60140960897D0F0B8EFBA\r
+:10080000CB16BFEFDB0610F0CC24DD241A82198250\r
+:10081000D501ED91FC910480F581E02DC801B7016F\r
+:10082000A20122E030E00995B601C114D10439F6E5\r
+:1008300002C080E001C081E00F900F90CF91DF9166\r
+:100840001F910F91FF90EF90DF90CF90BF90AF90EE\r
+:100850009F908F907F906F905F904F9008952F9210\r
+:100860003F924F925F926F927F928F929F92AF9240\r
+:10087000BF92CF92DF92EF92FF920F931F93DF937D\r
+:10088000CF93CDB7DEB72A970FB6F894DEBF0FBE71\r
+:10089000CDBF3C012B01009709F48FC0DC01ED9125\r
+:1008A000FC911197208131813A87298724803580F6\r
+:1008B00016968D919D910D90BC91A02D8D839E8358\r
+:1008C000AF83B887F30182859385A485B585B695F6\r
+:1008D000A795979587959C838B834A01CC24DD242B\r
+:1008E00042E0A42EB12C41C0C501880F991F7C01A4\r
+:1008F00000E010E02D813E814F815885E20EF31E0D\r
+:10090000041F151FC801B701AE014F5F5F4F22E002\r
+:1009100030E0A985BA85FD010995882309F44DC009\r
+:1009200089819A81892BF1F4C114D10429F4EFEF64\r
+:10093000FFEFFA83E98302C0DA82C982C801B701F6\r
+:10094000AE014F5F5F4F22E030E0F101099588234F\r
+:1009500091F00894810891088114910411F46501C3\r
+:100960000CC065010894A11CB11C2B813C81A2160E\r
+:10097000B30608F4B9CF8928E1F432E043165104F4\r
+:10098000F0F0DA82C982440C551CB20180E090E09C\r
+:100990002D813E814F815885620F731F841F951FE3\r
+:1009A000AE014F5F5F4F22E030E0F10109958823EF\r
+:1009B00031F4C301B6010E94B903CC24DD24C60181\r
+:1009C0002A960FB6F894DEBF0FBECDBFCF91DF9150\r
+:1009D0001F910F91FF90EF90DF90CF90BF90AF905D\r
+:1009E0009F908F907F906F905F904F903F902F904F\r
+:1009F000089580E190E00895FC01009711F01182C4\r
+:100A0000108208952F923F924F925F926F927F9241\r
+:100A10008F929F92AF92BF92CF92DF92EF92FF920E\r
+:100A20000F931F93DF93CF93CDB7DEB72A970FB6FF\r
+:100A3000F894DEBF0FBECDBF2C017A8369835C833F\r
+:100A40004B83009709F409C1672B09F406C1452BB4\r
+:100A500009F403C1DC019D96AD90BD90CD90DC9072\r
+:100A6000D09795962D913D914D915C919897EB8102\r
+:100A7000FC81CF01A0E0B0E08A0D9B1DAC1DBD1D27\r
+:100A8000281739074A075B0740F4B9016A197B093F\r
+:100A90007C836B83672B09F4E3C0D201ED91FC9159\r
+:100AA000119720883188D196ED91FC91D297FA87E1\r
+:100AB000E987EF2BF1F593962D913C9194973A8726\r
+:100AC0002987232B39F4A114B104C104D10409F4FA\r
+:100AD000C7C0C3C0A114B104C104D10451F186013F\r
+:100AE000750131018824992466277727CB0166197F\r
+:100AF0007709880999096D837E838F83988714C04D\r
+:100B0000D2018D919C9169857A850E9479039A879B\r
+:100B10008987892B09F4A1C06D817E818F81988599\r
+:100B2000E60EF71E081F191FE614F704080519053D\r
+:100B300038F7089421083108A220B3200894211C1A\r
+:100B4000311CCB80DC80D201ED90FC90E114F104EB\r
+:100B500009F1E985FA85E230F105E0F03297BF014D\r
+:100B600080E090E03296FA87E987D70150962D9180\r
+:100B70003C91519740E050E00E94301A9B01AC013B\r
+:100B8000F70182899389A489B589280F391F4A1FE3\r
+:100B90005B1F04C020E030E040E050E081010A1912\r
+:100BA0001B09C016D10608F48601D701ED91FC910E\r
+:100BB000C501A0E0B0E0280F391F4A1F5B1F01905C\r
+:100BC000F081E02DCA01B90149815A819801099546\r
+:100BD000882341F1C01AD10AC801A0E0B0E0F201B7\r
+:100BE00025A536A547A550A9280F391F4A1F5B1F09\r
+:100BF000D2019D962D933D934D935C93D097C80160\r
+:100C00008A0D9B1D82159305A0F08D919C9169859D\r
+:100C10007A850E9479039A878987892B41F4F201AA\r
+:100C200012AA11AA4B815C814C195D091BC0AA2430\r
+:100C3000BB24E985FA85D201D296FC93EE93D19735\r
+:100C4000C114D10439F029813A81200F311F3A8330\r
+:100C5000298379CF4B815C8105C04FEF5FEF02C0E4\r
+:100C600040E050E0CA012A960FB6F894DEBF0FBEEE\r
+:100C7000CDBFCF91DF911F910F91FF90EF90DF904B\r
+:100C8000CF90BF90AF909F908F907F906F905F902C\r
+:100C90004F903F902F900895FC01009711F480E051\r
+:100CA000089583A194A196A785A710AA17A681E00D\r
+:100CB0000895CF92DF92EF92FF920F931F93CF93FD\r
+:100CC000DF938C016A017B01A901D901CD91DC91EF\r
+:100CD000119712968D919C911397809613969C93E1\r
+:100CE0008E931297F8018081853E09F4BAC088235B\r
+:100CF00009F4B7C08FA198A5A9A5BAA50097A10529\r
+:100D0000B10521F4CFA2D8A6E9A6FAA6209709F446\r
+:100D1000AAC00115110509F4A6C0D8019C91992318\r
+:100D200009F4A1C01B968C918F30A1F5892F90E01A\r
+:100D30008F7390702DE030E0829FA001839F500D53\r
+:100D4000929F500D11244D50504010922702109246\r
+:100D5000260211C0AC0FBD1FF901E25FFD4F80817B\r
+:100D6000F801E80FF11D80818C932F5F3F4F309386\r
+:100D700027022093260220912602309127022D304F\r
+:100D8000310508F06EC0DA01A20FB31FAF31B10513\r
+:100D900008F367C08881882309F04FC0B801DE01DD\r
+:100DA000780120E0F70190819032A1F09C93F80146\r
+:100DB000848583FF08C0F7018081813420F08B3562\r
+:100DC00010F4905E9C932F5F0894E11CF11C119627\r
+:100DD000283041F78881853011F485EE8883D80169\r
+:100DE00018968C91803211F4322F23C0FE01E20F4D\r
+:100DF000F11D8EE28083322F3F5F2C5FFB019085D7\r
+:100E00009032B9F0FE01E30FF11D9083D8011C96DA\r
+:100E10008C9184FF09C0DB0118968C91813420F0FD\r
+:100E20008B3510F4905E90833F5F6F5F7F4F32177A\r
+:100E300029F7FE01E30FF11D1082F801838588A3D5\r
+:100E4000828D938D9AA389A3848D958DA68DB78D60\r
+:100E50008BA39CA3ADA3BEA381E0DA0114968C936F\r
+:100E600002C081E001C080E0DF91CF911F910F911E\r
+:100E7000FF90EF90DF90CF9008957F928F929F9296\r
+:100E8000AF92BF92CF92DF92EF92FF920F931F9398\r
+:100E9000DF93CF93CDB7DEB72C970FB6F894DEBFB4\r
+:100EA0000FBECDBF6C015B01009709F453C0611503\r
+:100EB000710509F44FC0DB019796ED90FD900D91FF\r
+:100EC0001C919A97E114F1040105110509F442C03F\r
+:100ED0004E010894811C911C75EE772ED601ED9180\r
+:100EE000FC910190F081E02DC801B701A4012CE034\r
+:100EF00030E00995882371F17982D601ED91FC915A\r
+:100F00000480F581E02DC801B701A4012CE030E098\r
+:100F100009958823F9F08C858F3049F480E290E0C0\r
+:100F2000A0E0B0E0E80EF91E0A1F1B1FD7CFD501C5\r
+:100F300091966D917C9192976115710539F0C6017A\r
+:100F40000E94B90320E030E0882311F021E030E076\r
+:100F5000822F01C080E02C960FB6F894DEBF0FBE42\r
+:100F6000CDBFCF91DF911F910F91FF90EF90DF9058\r
+:100F7000CF90BF90AF909F908F907F900895CF9229\r
+:100F8000DF92EF92FF920F931F93DF93CF93CDB732\r
+:100F9000DEB760970FB6F894DEBF0FBECDBF8C01F1\r
+:100FA0006230710510F480E035C0009729F440E00C\r
+:100FB00050E060E070E016C06250704080E090E069\r
+:100FC000F8012089318940E050E00E94301AAB01DD\r
+:100FD000BC01F80182899389A489B589480F591FFA\r
+:100FE0006A1F7B1FDE01119680E1FD0111928A9537\r
+:100FF000E9F7F8018081918120893189FC01C6805F\r
+:10100000D780CB01BA01AD0109EF14E0EE24FF2433\r
+:10101000F601099560960FB6F894DEBF0FBECDBFFE\r
+:10102000CF91DF911F910F91FF90EF90DF90CF90C4\r
+:1010300008952F923F924F925F926F927F928F927C\r
+:101040009F92AF92BF92CF92DF92EF92FF920F9357\r
+:101050001F93DF93CF93CDB7DEB7A7970FB6F89462\r
+:10106000DEBF0FBECDBF2C017FA36EA3009709F496\r
+:10107000B1C06115710509F4ADC0DC018D909C9083\r
+:101080001197F401208831889D96AD90BC909E9771\r
+:101090009F966D907C90D0978BE2DB011D928A9594\r
+:1010A000E9F7FE01319685E0DF011D928A95E9F7A7\r
+:1010B000A114B10409F076C0F4012288338886892E\r
+:1010C0009789281A390A6EC0730100E010E0A11454\r
+:1010D000B10441F4D40156966D917D918D919C910E\r
+:1010E00059972DC08114910421F1B2E0AB16B104DF\r
+:1010F00000F1EEEFFFEFAE0EBF1EB50180E090E015\r
+:1011000022E030E0A20EB31ED40150962D913C9106\r
+:10111000519740E050E00E94301A9B01AC01F4016D\r
+:1011200082899389A489B589280F391F4A1F5B1FBB\r
+:1011300004C020E030E040E050E0CA01B9016E0D8B\r
+:101140007F1D801F911F1C821B82D401ED91FC9199\r
+:101150008101061917090280F381E02DAE014A5F73\r
+:101160005F4F20E230E0A9E5EA2EA6E0FA2E6E01FC\r
+:101170000894C11CD11C0995882361F18B819C8145\r
+:10118000680E791E6214730488F0C401B5010E94D0\r
+:1011900079035C0166247724009741F4F201A3A04F\r
+:1011A000B4A008C02EA13FA13A8329838D81882352\r
+:1011B00009F48ACFD2019E96BC92AE929D97D096AA\r
+:1011C0007C926E929F97EEA1FFA18081882319F0F7\r
+:1011D00081E001C080E0A7960FB6F894DEBF0FBE95\r
+:1011E000CDBFCF91DF911F910F91FF90EF90DF90D6\r
+:1011F000CF90BF90AF909F908F907F906F905F90B7\r
+:101200004F903F902F9008952F923F924F925F9270\r
+:101210006F927F928F929F92AF92BF92CF92DF9206\r
+:10122000EF92FF920F931F93DF93CF93CDB7DEB76B\r
+:10123000A8970FB6F894DEBF0FBECDBF98A78FA3B7\r
+:10124000009709F45CC1DC0114968D919C9115976F\r
+:10125000892B09F454C116968D919C911797892B6F\r
+:1012600009F44DC168C1E8E2F2E08AE1DF011D92B4\r
+:101270008A95E9F7EFA1F8A5F0932902E0932802F7\r
+:10128000218432844384548459E0220C331C441C4E\r
+:10129000551C5A95D1F7C201B101655F7F4F8F4F41\r
+:1012A0009F4F0190F081E02DAE014F5F5F4F29E12C\r
+:1012B00030E00995882309F445C1E981FA81FBA34F\r
+:1012C000EAA32C813D81FB81FCA34E818F8198850F\r
+:1012D0009EA38DA3E985FA856C857D856E887F88C0\r
+:1012E000888C998C611471048104910431F43097D5\r
+:1012F00009F428C13F01882499246115710509F476\r
+:1013000021C1C901A0E0B0E08E8F9F8FA8A3B9A32F\r
+:1013100080E090E0242F30E040E050E00E94301A5E\r
+:101320006A8F7B8F8C8F9D8F840173012E8D3F8DF3\r
+:1013300048A159A1E21AF30A040B150BE61AF70AA1\r
+:10134000080B190B8AA19BA101972DA13EA145E095\r
+:10135000220F331F4A95E1F7820F931F6AA17BA1E9\r
+:101360000E944F1A80E090E0E61AF70A080B190B6A\r
+:101370008CA1282F30E040E050E0C801B7010E9466\r
+:10138000761A79018A0195EFE9169FE0F90690E057\r
+:10139000090790E0190708F4D5C0A5EFEA16AFEFEA\r
+:1013A000FA06A0E00A07A0E01A0728F486E0EFA1F9\r
+:1013B000F8A5808705C08BE0AFA1B8A518968C93DF\r
+:1013C00088E1EAE2F2E0DF011D928A95E9F7EAA1FD\r
+:1013D000FBA15F01CC24DD24C401B301A60195016A\r
+:1013E0000E94301A60932A0270932B0280932C0281\r
+:1013F00090932D02C601B5012E8D3F8D48A159A1B4\r
+:101400000E94301A260E371E481E591E20922E02A8\r
+:1014100030922F024092300250923102AFA1B8A513\r
+:1014200018968C91863029F064E070E080E090E0BE\r
+:1014300004C062E070E080E090E022E030E040E054\r
+:1014400050E0E20EF31E041F151FA80197010E9431\r
+:10145000301A609332027093330280933402909377\r
+:1014600035024AA15BA150933702409336025CA13A\r
+:10147000852F90E0DC01EAA1FBA1AE9FC001AF9FE8\r
+:10148000900DBE9F900D11249093390280933802E5\r
+:101490006A8D7B8D8C8D9D8DA60195010E94301AE1\r
+:1014A00020912E0230912F02409130025091310252\r
+:1014B000620F731F841F951F60933E0270933F025B\r
+:1014C0008093400290934102ADA1BEA19D0140E0F6\r
+:1014D00050E0B5E0220F331F441F551FBA95D1F7D6\r
+:1014E000620F731F841F951F60933A0270933B0233\r
+:1014F00080933C0290933D0228E232E002C020E05B\r
+:1015000030E0C901A8960FB6F894DEBF0FBECDBF7C\r
+:10151000CF91DF911F910F91FF90EF90DF90CF90CF\r
+:10152000BF90AF909F908F907F906F905F904F9003\r
+:101530003F902F9008958091280290912902892B45\r
+:10154000F1F691CE1092290210922802D8CF2F9254\r
+:101550003F924F925F926F927F928F929F92AF9243\r
+:10156000BF92CF92DF92EF92FF920F931F93DF9380\r
+:10157000CF9300D00F92CDB7DEB71C019B0100972F\r
+:1015800009F4D2C04115510509F4CEC0FA01019009\r
+:101590000020E9F7E41BF50BCF010B966DE070E03E\r
+:1015A0000E944F1A862F8F5F8B83D90193964D909F\r
+:1015B0005C9094974114510451F0AA24BB24650116\r
+:1015C000EE24FF2487016624772443010BC0F10138\r
+:1015D000E688F788008D118D6288738884889588E5\r
+:1015E000570168011A82E614F7040805190509F085\r
+:1015F0006EC04114510409F497C0E114F1040105CF\r
+:10160000110589F1C101B2010E947903009751F5DA\r
+:10161000C101B20141E050E00E942F048C0100970B\r
+:1016200009F482C002501040B80180E090E00E5FE3\r
+:101630001F4FD10150962D913C91519740E050E0C1\r
+:101640000E94301A5B016C01F10182899389A4899F\r
+:10165000B589A80EB91ECA1EDB1EC101B8010E94C1\r
+:10166000BF0765C02C01F2E04F16510420F4EE24B0\r
+:10167000FF2487011DC02EEF3FEF420E531EB20123\r
+:1016800080E090E0A2E0B0E04A0E5B1EF10120890C\r
+:10169000318940E050E00E94301A7B018C01F10159\r
+:1016A00082899389A489B589E80EF91E0A1F1B1F38\r
+:1016B000D10150968D919C9151973C018824992499\r
+:1016C0006E0C7F1C801E911E570168011A82D10189\r
+:1016D000ED91FC910190F081E02DC801B701AE01C0\r
+:1016E0004F5F5F4F21E030E009958823E9F0898161\r
+:1016F000853E11F0882379F4BA81BF5FBA83EB810C\r
+:10170000BE17A8F480E290E0A0E0B0E0E80EF91E79\r
+:101710000A1F1B1F68CF80E290E0A0E0B0E0E80E57\r
+:10172000F91E0A1F1B1F5CCFAA24BB246501B5014B\r
+:10173000C6010F900F900F90CF91DF911F910F91E5\r
+:10174000FF90EF90DF90CF90BF90AF909F908F90E1\r
+:101750007F906F905F904F903F902F9008953F92B1\r
+:101760004F925F926F927F928F929F92AF92BF92B1\r
+:10177000CF92DF92EF92FF920F931F93DF93CF935D\r
+:10178000CDB7DEB7A0970FB6F894DEBF0FBECDBFC2\r
+:10179000FC018B01009709F424C16115710509F45E\r
+:1017A00020C10190F081E02D44805580DB019796A7\r
+:1017B000AD90BD90CD90DC909A97E62E912EFB01D6\r
+:1017C00001900020E9F73197FE2EF61A8F2D90E058\r
+:1017D0000C966DE070E00E94631A762ECE010196A1\r
+:1017E00060E270E04BE050E00E949500C8016EE2BC\r
+:1017F00070E00E94CD00FC010097E1F09C012F5F9A\r
+:101800003F4F81818823B1F0D9010D900020E9F785\r
+:101810001197A21BB30B8A2F8095F80EBE01675F4C\r
+:101820007F4F4A2FA43008F043E0CB01B90150E0CC\r
+:101830000E948C00CE010196B8E0BF1588F06E2D95\r
+:10184000792D4F2D50E00E948C00F80180818E325E\r
+:1018500031F581818E3209F482818823F9F01FC02D\r
+:10186000DC018E2D992D9C01F90188E001900D92EB\r
+:101870008150E1F7D80191968C91982F92959F70A5\r
+:10188000803A10F4905D01C09F598F708A3010F437\r
+:10189000805D01C08F599F83888701C0772489812B\r
+:1018A000853E11F485E0898385E1FE013C96DF01E8\r
+:1018B0001D928A95E9F7F80180A18C8781A192A1F8\r
+:1018C0009C8F8B8F83A194A1A5A1B6A18D8F9E8F94\r
+:1018D000AF8FB8A3672D70E0E5E0660F771FEA953C\r
+:1018E000E1F780E090E06A0D7B1D8C1D9D1DAE012F\r
+:1018F0004F5F5F4F20E230E0F2010995882309F441\r
+:1019000070C0E98081E090E09093270280932602E6\r
+:10191000FE01329621E030E00AC08E2D8695E794D4\r
+:10192000EE24E794E82A8191E80E2F5F3F4F2B3099\r
+:10193000310598F33093270220932602F72C4E01AD\r
+:101940000894811C911C7DE0372E6FE0662E44C008\r
+:10195000C4016FEF70E040E250E00E949500F39CFC\r
+:10196000D00111241D97A00FB11F91E0F401E90FE0\r
+:10197000F11D8C918083892F8F5FF401E80FF11D99\r
+:1019800010829E5F9B3019F09A3121F402C09EE0D4\r
+:1019900001C09CE18C91882321F09F3110F41196B5\r
+:1019A000E5CFF982F71419F48F2D806489836C8652\r
+:1019B000EE861D861B8E1C8EC601B501A40120E299\r
+:1019C00030E0F201099580E290E0A0E0B0E0A80EDE\r
+:1019D000B91ECA1EDB1EFA94FF2009F0B9CF81E0C0\r
+:1019E00001C080E0A0960FB6F894DEBF0FBECDBF59\r
+:1019F000CF91DF911F910F91FF90EF90DF90CF90EB\r
+:101A0000BF90AF909F908F907F906F905F904F901E\r
+:101A10003F900895AF92BF92CF92DF92EF92FF92E4\r
+:101A20000F931F93CF93DF938C017B01EA01009703\r
+:101A300009F448C06115710509F444C0FB018081B7\r
+:101A4000882309F43FC041155105E1F1B42EAD2EB4\r
+:101A5000C801BE010E941908882379F0C7016B2DC7\r
+:101A60007A2D0E94A700009799F7F80183A194A10D\r
+:101A700096A785A710AA17A625C0F801C080D18017\r
+:101A80008BE2FE0111928A95E9F78B2D9A2DB70111\r
+:101A90004FE150E00E94BE00C601B801AE010E94B5\r
+:101AA000A70A6FA378A789A79AA761157105810571\r
+:101AB000910541F0C601BE010E94AF0B882319F0C9\r
+:101AC00081E001C080E0DF91CF911F910F91FF90E5\r
+:101AD000EF90DF90CF90BF90AF9008954F925F92BC\r
+:101AE0006F927F928F929F92AF92BF92CF92DF922E\r
+:101AF000EF92FF920F931F93DF93CF93CDB7DEB793\r
+:101B00002A970FB6F894DEBF0FBECDBF2C015A0145\r
+:101B10006B01009709F4E5C0DC0193960D911C91CF\r
+:101B20009497ED91FC91208931890115110599F067\r
+:101B3000AB82BC82CD82DE8239018824992422279F\r
+:101B40003327A90126193709480959092F833887EE\r
+:101B500049875A8720C0411551056105710509F46F\r
+:101B6000A9C0E6CFD2018D919C91B8010E94790362\r
+:101B70000097D9F0EB80FC800D811E812F81388584\r
+:101B800049855A85E20EF31E041F151FEB82FC8265\r
+:101B90000D831E838C018B819C81AD81BE81681673\r
+:101BA00079068A069B06F0F2B4C078016B817C81CD\r
+:101BB0008D819E81660D771D881D991D6150704035\r
+:101BC00080409040A40193010E94761AD2018D9129\r
+:101BD0009C91B801A9010E942F04009709F481C0CB\r
+:101BE000012B21F4F20194A383A37C01D2019596E9\r
+:101BF000AD92BD92CD92DC929897A114B104C1042C\r
+:101C0000D10421F494961C921E929397F201819133\r
+:101C10009191BF010E94AF0B882309F462C0A11407\r
+:101C2000B104C104D10429F4F20180819181B7018A\r
+:101C30003FC00B811C812D813E816016710682069A\r
+:101C40009306C0F1D2010D911C910115110591F17E\r
+:101C5000B2E0EB16F10470F1C801B7010E947903FC\r
+:101C60004C018FEF9FEF9A838983D801ED91FC910E\r
+:101C70001197EE0CFF1CB70180E090E016962D91B5\r
+:101C80003D914D915C911997620F731F841F951FB1\r
+:101C90000480F581E02DAE014F5F5F4F22E030E020\r
+:101CA0000995882339F08114910421F0C801B40109\r
+:101CB0000E94B903F20185A596A5A7A5B0A9A8160B\r
+:101CC000B906CA06DB0658F4D2019D96AD92BD92C4\r
+:101CD000CD92DC92D097D2961C921E92D19781E041\r
+:101CE00001C080E02A960FB6F894DEBF0FBECDBFCC\r
+:101CF000CF91DF911F910F91FF90EF90DF90CF90E8\r
+:101D0000BF90AF909F908F907F906F905F904F901B\r
+:101D1000089578010115110509F448CF67CFCF92D6\r
+:101D2000DF92EF92FF920F931F93CF93DF93EC011B\r
+:101D30006B01009709F445C06115710509F441C0B4\r
+:101D40008DA59EA5AFA5B8A9413059F0413018F036\r
+:101D50004230B9F50CC0FB01E080F18002811381B3\r
+:101D600013C0FB01E080F1800281138109C0FB01F7\r
+:101D7000E080F180028113818DA19EA1AFA1B8A561\r
+:101D8000E80EF91E0A1F1B1F8DA19EA1AFA1B8A5C9\r
+:101D90008E159F05A007B10738F4CE01B801A70141\r
+:101DA0000E946E0D882369F0EDA6FEA60FA718AB62\r
+:101DB0001AAA19AAF601E082F1820283138381E054\r
+:101DC00001C080E0DF91CF911F910F91FF90EF90C4\r
+:101DD000DF90CF9008952F923F924F925F926F9233\r
+:101DE0007F928F929F92AF92BF92CF92DF92EF92AB\r
+:101DF000FF920F931F93DF93CF9300D000D000D0BA\r
+:101E0000CDB7DEB79E838D837A8369835C834B83F2\r
+:101E1000009709F441C1672B09F43EC1452B09F431\r
+:101E20003BC1DC019D968D909D90AD90BC90D0976C\r
+:101E3000FC0185A196A1A7A1B0A588159905AA05C1\r
+:101E4000BB0508F429C10190F081E02D208831887C\r
+:101E5000AD81BE81D1960D911C91D29701151105CE\r
+:101E600009F055C093960D911C9194970115110599\r
+:101E7000A9F481149104A104B10409F00DC1CF01AA\r
+:101E800060E070E041E050E00E942F048C01ED81A1\r
+:101E9000FE8194A383A3009709F4FEC0AD81BE81A7\r
+:101EA0009D96CD90DD90ED90FC90D097C114D1041B\r
+:101EB000E104F10421F52BC0C418D508E608F708A1\r
+:101EC000ED81FE8180819181B8010E9479030097A4\r
+:101ED00011F08C0117C0C114D104E104F10409F020\r
+:101EE000DBC0AD81BE818D919C91B80141E050E095\r
+:101EF0000E942F04009709F4CFC08C0103C0210178\r
+:101F000066247724C414D504E604F704A8F60894DC\r
+:101F100021083108822093200894211C311CAB80B9\r
+:101F2000BC80ED81FE81C080D180C114D104F9F064\r
+:101F300002301105E0F002501040B80180E090E05E\r
+:101F40000E5F1F4FD60150962D913C91519740E066\r
+:101F500050E00E94301A9B01AC01F60182899389FE\r
+:101F6000A489B589280F391F4A1F5B1F04C020E0D0\r
+:101F700030E040E050E07101E818F908AE14BF0409\r
+:101F800008F47501D601ED91FC91C401A0E0B0E028\r
+:101F9000280F391F4A1F5B1F0480F581E02DCA01FD\r
+:101FA000B90149815A8197010995882309F448C0EC\r
+:101FB000AE18BF08C701A0E0B0E0ED81FE8125A505\r
+:101FC00036A547A550A9280F391F4A1F5B1F25A713\r
+:101FD00036A747A750ABC701880D991D82159305F9\r
+:101FE00008F180819181B8010E947903009711F076\r
+:101FF0008C0116C0A114B10459F0ED81FE818081DD\r
+:102000009181B80141E050E00E942F04009739F41B\r
+:10201000AD81BE81D2961C921E92D19711C08C01C7\r
+:1020200088249924ED81FE8112AB01ABA114B10487\r
+:1020300039F089819A818E0D9F1D9A83898371CF92\r
+:10204000ED81FE8185A596A5A7A5B0A9E5A0F6A07E\r
+:1020500007A110A5E816F9060A071B07C0F485A317\r
+:1020600096A3A7A3B0A781919191BF010E94AF0B46\r
+:10207000882369F4AD81BE819D96AD90BC909E97FA\r
+:10208000AE18BF08FD01E5A6F6A607A710AB4B8169\r
+:102090005C814A195B0902C04FEF5FEFCA012696C7\r
+:1020A0000FB6F894DEBF0FBECDBFCF91DF911F9169\r
+:1020B0000F91FF90EF90DF90CF90BF90AF909F90E7\r
+:1020C0008F907F906F905F904F903F902F900895EA\r
+:1020D000CF93DF93AC01DB01009789F161157105A6\r
+:1020E00071F190968C91909784FF29C08091750230\r
+:1020F00090917602892B19F4E5E7F2E008C080910F\r
+:10210000A6029091A702892BD1F4E6EAF2E09F01A2\r
+:102110002E5F3F4FBD018BE2EB010990BE01E9014B\r
+:1021200009929E018150C1F75183408391968D9110\r
+:102130009C91929796A785A710AA17A602C0E0E0E7\r
+:10214000F0E0CF01DF91CF910895CF93DF939C0111\r
+:10215000FB01009731F06115710519F080A184FF32\r
+:1021600023C020E030E0C901DF91CF910895C4E49D\r
+:10217000D2E0DF018BE20D9009928150E1F73093BC\r
+:1021800043022093420210926F021092700210924A\r
+:1021900071021092720281A192A1909374028093B5\r
+:1021A000730222E432E0DFCF809142029091430239\r
+:1021B000892BB9F6DCCF6F927F928F929F92AF926C\r
+:1021C000BF92CF92DF92EF92FF920F931F93CF9324\r
+:1021D000DF934C01EB017A01009709F467C06115A8\r
+:1021E000710509F463C08881882309F45FC0411533\r
+:1021F000510509F45BC08F3209F421968BE2F70197\r
+:1022000011928A95E9F780E1F70180A3370101C0B7\r
+:10221000E5018881882309F44BC0C401B7010E94FD\r
+:1022200068106C01009709F441C0CE016FE270E0C4\r
+:102230000E949C00009739F0482F4C1B5C010894C9\r
+:10224000A11CB11C2AC0FE0101900020E9F73197C2\r
+:102250004E2F4C1B5E01A40EB11C1FC0F301019058\r
+:102260000020E9F73197E619F709E017F107B9F40B\r
+:10227000CE01B301A8010E94B000009781F4F601DD\r
+:10228000118210820C0F1D1FF8018081882381F0BC\r
+:10229000F70180A184FDBCCF09C0042F10E0C60166\r
+:1022A000B7010E9419088823C9F612C080E001C056\r
+:1022B00081E0DF91CF911F910F91FF90EF90DF9020\r
+:1022C000CF90BF90AF909F908F907F906F90089528\r
+:1022D000F601118210829DCF8F929F92AF92BF9292\r
+:1022E000CF92DF92EF92FF920F93DF93CF93CDB710\r
+:1022F000DEB760970FB6F894DEBF0FBECDBF7C018E\r
+:102300006B015A014901009709F493C061157105E9\r
+:1023100009F48FC004300CF08CC007FD1DC0602F85\r
+:10232000772767FD7095E4E0660F771FEA95E1F780\r
+:1023300062547E4F882777FD8095982FAE014F5FBE\r
+:102340005F4F20E130E0F7010995882309F471C05F\r
+:102350008D81882309F46DC08091DF02882309F004\r
+:1023600068C07CC08D818093DF022A8530E040E028\r
+:1023700050E0542F432F322F22278B8590E0A0E08E\r
+:10238000B0E0DC0199278827282B392B4A2B5B2BBF\r
+:10239000898590E0A0E0B0E0282B392B4A2B5B2BFD\r
+:1023A0008C8590E0A0E0B0E0B82FAA279927882775\r
+:1023B000282B392B4A2B5B2B2093E0023093E10230\r
+:1023C0004093E2025093E3022E8530E040E050E07B\r
+:1023D000542F432F322F22278F8590E0A0E0B0E0CA\r
+:1023E000DC0199278827282B392B4A2B5B2B8D85DD\r
+:1023F00090E0A0E0B0E0282B392B4A2B5B2B88899A\r
+:1024000090E0A0E0B0E0B82FAA2799278827282BD2\r
+:10241000392B4A2B5B2B2093E4023093E502409347\r
+:10242000E6025093E70203C08FEF8093DF029F0123\r
+:1024300002C020E030E0C90160960FB6F894DEBF1C\r
+:102440000FBECDBFCF91DF910F91FF90EF90DF9046\r
+:10245000CF90BF90AF909F908F900895E7EDF2E0FE\r
+:1024600081E1DF011D928A95E9F7F092D802E092AE\r
+:10247000D702D092DA02C092D902B092DC02A092C6\r
+:10248000DB029092DE028092DD0207FF6BCFCCCFA1\r
+:10249000282F8FEF8EBD0DB407FEFDCF8DB58F7742\r
+:1024A0008DBD8EB5822F80648EBD0DB407FEFDCF2D\r
+:1024B0008DB58F778DBD872F9927AA27BB278EBD16\r
+:1024C0000DB407FEFDCF8DB58F778DBDCB01AA274B\r
+:1024D000BB278EBD0DB407FEFDCF8DB58F778DBDAB\r
+:1024E000BB27A72F962F852F8EBD0DB407FEFDCFDE\r
+:1024F0008DB58F778DBD4EBD0DB407FEFDCF8DB56B\r
+:102500008F778DBD222319F0283069F406C085E944\r
+:102510008EBD0DB407FEFDCF0BC087E88EBD0DB498\r
+:1025200007FEFDCF05C08FEF8EBD0DB407FEFDCFBA\r
+:102530008DB58F778DBD1092E9021092E80220E0F0\r
+:1025400030E09FEF13C09EBD0DB407FEFDCF8DB5EB\r
+:102550008F778DBD8EB5A9014F5F5F4F8F3F29F0FB\r
+:102560003093E9022093E80208959A012A30310558\r
+:1025700050F33093E9022093E8028FEF08952F92F1\r
+:102580003F924F925F926F927F928F929F92AF9203\r
+:10259000BF92CF92DF92EF92FF920F931F93CF9350\r
+:1025A000DF934B015C012A01390133243A94222440\r
+:1025B0002394AFC0E401D170CE01A0E0B0E085016A\r
+:1025C0007401E81AF90A0A0B1B0BC12CB2E0DB2ECE\r
+:1025D000CC1ADD0A6C147D0408F463018091EA04CE\r
+:1025E0009091EB04A091EC04B091ED04E816F9068B\r
+:1025F0000A071B07F9F00E94A313882309F48FC070\r
+:10260000209729F480E0C81682E0D80658F4C80163\r
+:10261000B7014AEE52E020E032E00E94BD13882369\r
+:1026200009F47DC0E092EA04F092EB040093EC041C\r
+:102630001093ED048AEE481682E0580671F09E0170\r
+:1026400026513D4FC901B201A6010E948C00109293\r
+:10265000EE046C147D0409F460C0289888E1B80188\r
+:10266000A7010E944812882311F0289A58C08EEFC3\r
+:102670008EBD0DB407FEFDCF8DB58F778DBD109249\r
+:10268000E9021092E802EAEEF2E020E030E00BC04E\r
+:1026900080818EBD0DB407FEFDCF31968DB58F774D\r
+:1026A0008DBD2F5F3F4F82E02030380788F3309395\r
+:1026B000E9022093E8023EBC0DB407FEFDCF8DB5C4\r
+:1026C0008F778DBD3EBC0DB407FEFDCF8DB58F77E6\r
+:1026D0008DBD3EBC0DB407FEFDCF8DB58F778DBD92\r
+:1026E0008EB58F3FB1F78EBD0DB407FEFDCF8DB512\r
+:1026F0008F778DBD8EB5289A4C0C5D1CC601A0E06D\r
+:10270000B0E0880E991EAA1EBB1E6C187D08209290\r
+:10271000EE046114710409F04DCF81E001C080E046\r
+:10272000DF91CF911F910F91FF90EF90DF90CF90AD\r
+:10273000BF90AF909F908F907F906F905F904F90E1\r
+:102740003F902F9008958091EE04882311F081E04E\r
+:1027500008956091EA047091EB048091EC049091EB\r
+:10276000ED044AEE52E020E032E00E94BF128823DE\r
+:1027700019F081E08093EE0408953F924F925F92AA\r
+:102780006F927F928F929F92AF92BF92CF92DF9281\r
+:10279000EF92FF920F931F93CF93DF933B014C0176\r
+:1027A0006A01290133243A9496C01FEFA12E11E04B\r
+:1027B000B12EA620B720C501A0E0B0E084017301CE\r
+:1027C000E81AF90A0A0B1B0BC0E0D2E0CA19DB09B0\r
+:1027D0004C165D0608F4E2018091EA049091EB0446\r
+:1027E000A091EC04B091ED04E816F9060A071B0766\r
+:1027F00009F45EC00E94A313882309F471C02898CD\r
+:1028000081E1B801A7010E944812882319F0289A93\r
+:1028100080E066C03EBC0DB407FEFDCF8DB58F775E\r
+:102820008DBD8EB58E3FB1F7EAEEF2E020E030E0EC\r
+:102830000BC03EBC0DB407FEFDCF8DB58F778DBDAF\r
+:102840008EB581932F5F3F4F82E02030380788F3A9\r
+:102850003093E9022093E802E092EA04F092EB045C\r
+:102860000093EC041093ED04950126513D4FC601F1\r
+:10287000B901AE010E948C003EBC0DB407FEFDCF35\r
+:102880008DB58F778DBD8EB53EBC0DB407FEFDCFE7\r
+:102890008DB58F778DBD8EB5289A3EBC0DB407FEE1\r
+:1028A000FDCFCC0EDD1E8DB58F778DBD8EB50AC0E8\r
+:1028B000950126513D4FC601B901AE010E948C0021\r
+:1028C000CC0EDD1E4C1A5D0ACE01A0E0B0E0680E11\r
+:1028D000791E8A1E9B1E4114510409F066CF81E0C7\r
+:1028E000DF91CF911F910F91FF90EF90DF90CF90EC\r
+:1028F000BF90AF909F908F907F906F905F904F9020\r
+:102900003F9008952F923F924F925F926F927F92E5\r
+:102910008F929F92AF92BF92CF92DF92EF92FF92EF\r
+:102920000F931F93DF93CF9300D000D0CDB7DEB7C6\r
+:102930004B015C013A013C832B832701DA82C98277\r
+:1029400041155105A9F12115310591F10217130720\r
+:1029500078F1E114F10461F1190130942194310806\r
+:102960003394021B130B6901EE24FF24C501B4014B\r
+:10297000A3012B813C810E94BD138823C9F0C301B0\r
+:10298000B501A40129813A81F2010995882391F0CA\r
+:10299000020D131D8B819C81800F911F2B813C8127\r
+:1029A0008217930738F08C0C9D1CAE1CBF1CDECF29\r
+:1029B00080E001C081E00F900F900F900F90CF91B9\r
+:1029C000DF911F910F91FF90EF90DF90CF90BF901C\r
+:1029D000AF909F908F907F906F905F904F903F90BF\r
+:1029E0002F9008951F93CF93DF93239A259A209ACF\r
+:1029F00024982C9A289A83E58CBD8DB58E7F8DBD49\r
+:102A00001092EF0420E030E09FEF0AC09EBD0DB4AD\r
+:102A100007FEFDCF8DB58F778DBD8EB52F5F3F4FF4\r
+:102A20002A30310598F33093E9022093E802289880\r
+:102A30001092E9021092E80280E040E050E060E08D\r
+:102A400070E00E944812182F813079F08091E802DE\r
+:102A50009091E90221E08F3F920709F44DC0019661\r
+:102A60009093E9028093E802E7CF87E340E050E0EB\r
+:102A700060E070E00E94481289E240E050E060E0CF\r
+:102A800070E00E94481282FD02C01093EF04109281\r
+:102A9000E9021092E8028091EF04C82FD0E0C370E1\r
+:102AA000D070209749F087E340E050E060E070E0AC\r
+:102AB0000E94481289E201C081E040E050E060E0FD\r
+:102AC00070E00E94481280FF0EC08091E802909151\r
+:102AD000E9022FE78F3F920779F001969093E90280\r
+:102AE0008093E802DECF80E140E052E060E070E0F9\r
+:102AF0000E944812882319F0289A80E022C0289A60\r
+:102B00008CB58C7F8CBD8DB581608DBD8FEF9FEFB7\r
+:102B1000AFEFBFEF8093EA049093EB04A093EC0433\r
+:102B2000B093ED0481E08093EE0460E070E080E01B\r
+:102B300090E04AEE52E020E032E00E94BD138111A5\r
+:102B400081E0DF91CF911F9108954F925F926F9234\r
+:102B50007F928F929F92AF92BF92CF92DF92EF922D\r
+:102B6000FF920F931F93CF93DF935B016C014A0198\r
+:102B7000E901380127014115510571F101151105D0\r
+:102B800059F1FF242115310511F5FF24F3941FC0DD\r
+:102B9000C401B601A5019201F30109958C010097CA\r
+:102BA000E9F0FF2019F4C817D907B0F0C601B50144\r
+:102BB000A40198010E94BF12882371F0C801A0E00F\r
+:102BC000B0E0A80EB91ECA1EDB1EC01BD10BFF2031\r
+:102BD000F9F62097E9F602C080E001C081E0DF91BC\r
+:102BE000CF911F910F91FF90EF90DF90CF90BF900A\r
+:102BF000AF909F908F907F906F905F904F900895CF\r
+:102C00000F930E94F214882309F445C08DEB93E1E1\r
+:102C100062E874E14FEB52E125EA35E100E00E9401\r
+:102C20006C119093200580931F05892B89F48DEBFF\r
+:102C300093E162E874E14FEB52E125EA35E10FEFF1\r
+:102C40000E946C119093200580931F05892B19F128\r
+:102C500080911F05909120050E94040990931E0504\r
+:102C600080931D050097B9F060E071E042EF54E0F9\r
+:102C70000E94DB1080911D0590911E0562EF74E0AB\r
+:102C80000E9468109093F1048093F00420E0892B57\r
+:102C900019F021E001C020E0822F0F910895EF92FA\r
+:102CA000FF920F931F93CF93DF93EB018A0179017A\r
+:102CB000CB010E944C0608C0C701B8010E94A700C2\r
+:102CC000009711F481E006C0CE01B7010E941908F7\r
+:102CD000882391F7DF91CF911F910F91FF90EF9093\r
+:102CE0000895EF92FF920F931F93DF93CF93CDB789\r
+:102CF000DEB7AB970FB6F894DEBF0FBECDBF8C0129\r
+:102D00007E010894E11CF11C97010E944F16882354\r
+:102D100019F420E030E005C0C801B7010E94A510F9\r
+:102D20009C01C901AB960FB6F894DEBF0FBECDBFB4\r
+:102D3000CF91DF911F910F91FF90EF900895CF9267\r
+:102D4000DF92EF92FF920F931F93CF93DF930E9436\r
+:102D500000168091F0049091F10462E071E042EF7E\r
+:102D600054E00E940A0D882391F480911D059091F2\r
+:102D70001E0562EF74E00E943D078091F00490917F\r
+:102D8000F10462E071E042EF54E00E940A0D6091AC\r
+:102D9000F0047091F10480911D0590911E0542E0B0\r
+:102DA00051E00E94711690932205809321050EE058\r
+:102DB00011E0F80101900020E9F73197E01BF10BD9\r
+:102DC000B801AF010E94EB0E0E94A3138091210570\r
+:102DD000909122050E94FC04C0E0D0E078018BE0D5\r
+:102DE000C82E81E0D82E6091F0047091F10480919A\r
+:102DF0001D0590911E0542E051E00E9471168091E0\r
+:102E00002105909122056EE071E040E051E00E94C2\r
+:102E1000020580EB95E06EE071E00E94251A80913A\r
+:102E200021059091220560E070E042E00E948F0E43\r
+:102E30008E010F5F1F4F00D000D000D0EDB7FEB75E\r
+:102E40003196ADB7BEB71296FC92EE921197D3822F\r
+:102E5000C282D583C4830E94D800F701019000206C\r
+:102E6000E9F73197EE50F1408DB79EB706960FB651\r
+:102E7000F8949EBF0FBE8DBF8091210590912205D1\r
+:102E8000B701AF010E94EB0E0E94A31380912105B0\r
+:102E9000909122050E94FC0468EE73E080E090E0CF\r
+:102EA0000E94C817E8019FCF80E060E00E942C18C4\r
+:102EB00081E061E00E942C1880EB95E040E855E24B\r
+:102EC00060E070E00E94891888E061E00E942C18A0\r
+:102ED0008BE061E00E942C188CE060E00E942C18CE\r
+:102EE0008DE061E00E942C188AE061E00E942C18BD\r
+:102EF00008950E94F2170E9454170E949F16FDCF5A\r
+:102F00001F920F920FB60F9211242F933F938F931E\r
+:102F10009F93AF93BF938091270590912805A0912F\r
+:102F20002905B0912A0530912B050196A11DB11DEF\r
+:102F3000232F2D5F2D3720F02D570196A11DB11D98\r
+:102F400020932B058093270590932805A0932905AE\r
+:102F5000B0932A058091230590912405A091250521\r
+:102F6000B09126050196A11DB11D80932305909374\r
+:102F70002405A0932505B0932605BF91AF919F919D\r
+:102F80008F913F912F910F900FBE0F901F9018952A\r
+:102F9000EF92FF920F931F937B018C018FB7F894F0\r
+:102FA00040912705509128056091290570912A05C7\r
+:102FB0008FBF2FB7F8948091270590912805A09195\r
+:102FC0002905B0912A052FBF841B950BA60BB70BC3\r
+:102FD000E816F9060A071B0760F71F910F91FF908B\r
+:102FE000EF900895789484B5826084BD84B5816043\r
+:102FF00084BD85B5826085BD85B5816085BDEEE601\r
+:10300000F0E0808181608083E1E8F0E0808182608F\r
+:103010008083808181608083E0E8F0E0808181604E\r
+:103020008083E1EBF0E0808184608083E0EBF0E07E\r
+:10303000808181608083EAE7F0E080818460808322\r
+:1030400080818260808380818160808380818068CC\r
+:1030500080831092C1000895282F30E0C901865660\r
+:103060009F4FFC0194912A573F4FF9018491882387\r
+:1030700091F0E82FF0E0EE0FFF1FE859FF4FA59108\r
+:10308000B491662329F48C91909589238C930895AB\r
+:103090008C91892B8C9308951F920F920FB60F92EB\r
+:1030A00011242F933F934F935F936F937F938F934D\r
+:1030B0009F93AF93BF93EF93FF934091C600E0912E\r
+:1030C000AC05F091AD05CF01019660E870E00E947B\r
+:1030D000631A9C018091AE059091AF0528173907BE\r
+:1030E00039F0E45DFA4F40833093AD052093AC0591\r
+:1030F000FF91EF91BF91AF919F918F917F916F91D0\r
+:103100005F914F913F912F910F900FBE0F901F90A5\r
+:1031100018955F926F927F928F929F92AF92BF921B\r
+:10312000CF92DF92EF92FF920F931F93CF93DF9393\r
+:10313000EC013A014B01413482E458078FE0680703\r
+:1031400080E078070CF07FC060E874E88EE190E0E2\r
+:10315000A40193010E94981A2150304040405040F1\r
+:10316000CA01B90122E030E040E050E00E94981A24\r
+:1031700059016A01A6019501209530954095509519\r
+:1031800094E0220F331F441F551F9A95D1F760E03A\r
+:1031900074E284EF90E00E94981ACA01B9012FEFFF\r
+:1031A00030E040E050E00E94301AA40193010E94F8\r
+:1031B000981AC90181509F4F181619061CF4522EF7\r
+:1031C0005A9403C055245394521A60E079E08DE379\r
+:1031D00090E0A40193010E94981A21503040404091\r
+:1031E0005040CA01B90122E030E040E050E00E94C6\r
+:1031F000981A209530954095509583E0220F331F03\r
+:10320000441F551F8A95D1F760E074E284EF90E087\r
+:103210000E94981ACA01B9012FEF30E040E050E057\r
+:103220000E94301AA40193010E94981AC90181508A\r
+:103230009F4F181619061CF4822F815002C081E09E\r
+:10324000821B851500F5E885F98581E090E00A8804\r
+:1032500002C0880F991F0A94E2F7808360E079E04A\r
+:103260008DE390E0A40193010E94981A2150304010\r
+:1032700040405040CA01B90122E030E040E050E057\r
+:103280000E94981A04C0E885F98510829501EC81A6\r
+:10329000FD813083EE81FF812083EA85FB852081DB\r
+:1032A00041E050E0CA010E8402C0880F991F0A94C1\r
+:1032B000E2F7282B2083EA85FB852081CA010F8451\r
+:1032C00002C0880F991F0A94E2F7282B2083EA8511\r
+:1032D000FB858081088802C0440F551F0A94E2F7DD\r
+:1032E000842B8083DF91CF911F910F91FF90EF90FE\r
+:1032F000DF90CF90BF90AF909F908F907F906F9016\r
+:103300005F900895FC01A085B18521898C9190E0A2\r
+:10331000022E02C0959587950A94E2F780FFF6CFBA\r
+:103320000484F585E02D608308958FE192E0909309\r
+:10333000B1058093B0058CE295E09093B30580933E\r
+:10334000B20585EC90E09093B5058093B40584ECCC\r
+:1033500090E09093B7058093B60580EC90E0909351\r
+:10336000B9058093B80581EC90E09093BB058093FC\r
+:10337000BA0586EC90E09093BD058093BC0584E08F\r
+:103380008093BE0583E08093BF0587E08093C005EE\r
+:1033900085E08093C10581E08093C20508950F9375\r
+:1033A0001F93CF93DF938C01EB0109C02196D801C5\r
+:1033B000ED91FC910190F081E02DC80109956881A3\r
+:1033C0006623A1F7DF91CF911F910F910895EF929E\r
+:1033D000FF920F931F93CF93DF938C017B01EA0140\r
+:1033E0000CC0D7016D917D01D801ED91FC91019048\r
+:1033F000F081E02DC80109952197209791F7DF9181\r
+:10340000CF911F910F91FF90EF900895DC01ED9106\r
+:10341000FC910280F381E02D099508950F931F938D\r
+:103420008C01DC01ED91FC910190F081E02D6DE0CB\r
+:103430000995D801ED91FC910190F081E02DC80132\r
+:103440006AE009951F910F9108950F931F938C01C6\r
+:103450000E94061AC8010E940E1A1F910F9108952A\r
+:10346000629FD001739FF001829FE00DF11D649F68\r
+:10347000E00DF11D929FF00D839FF00D749FF00DF4\r
+:10348000659FF00D9927729FB00DE11DF91F639F95\r
+:10349000B00DE11DF91FBD01CF0111240895AA1B34\r
+:1034A000BB1B51E107C0AA1FBB1FA617B70710F02F\r
+:1034B000A61BB70B881F991F5A95A9F78095909561\r
+:1034C000BC01CD01089597FB092E07260AD077FD90\r
+:1034D00004D0E5DF06D000201AF4709561957F4F87\r
+:1034E0000895F6F7909581959F4F0895A1E21A2EC1\r
+:1034F000AA1BBB1BFD010DC0AA1FBB1FEE1FFF1F98\r
+:10350000A217B307E407F50720F0A21BB30BE40BE7\r
+:10351000F50B661F771F881F991F1A9469F760952E\r
+:103520007095809590959B01AC01BD01CF010895E8\r
+:1035300097FB092E05260ED057FD04D0D7DF0AD001\r
+:10354000001C38F450954095309521953F4F4F4FD2\r
+:103550005F4F0895F6F790958095709561957F4F30\r
+:103560008F4F9F4F0895EE0FFF1F0590F491E02DB0\r
+:1035700009942F923F924F925F926F927F928F9217\r
+:103580009F92AF92BF92CF92DF92EF92FF920F93F2\r
+:103590001F93CF93DF93CDB7DEB7CA1BDB0B0FB6FC\r
+:1035A000F894DEBF0FBECDBF09942A8839884888B9\r
+:1035B0005F846E847D848C849B84AA84B984C8844F\r
+:1035C000DF80EE80FD800C811B81AA81B981CE0F46\r
+:1035D000D11D0FB6F894DEBF0FBECDBFED0108952B\r
+:0435E000F894FFCF8D\r
+:1035E4002F00546573742E74787400256400546538\r
+:1035F4007374696E670A0000000000000000000098\r
+:1036040000000000000000000000000000000000B6\r
+:1036140000000000000000000000000000000000A6\r
+:103624000000000000000000000000000000000096\r
+:103634000000000000000000000000000000000086\r
+:103644000000000000000000000000000000000076\r
+:103654000000000000000000000000000000000066\r
+:103664000000000000000000000000000000000056\r
+:103674000000000000000000000000000000000046\r
+:103684000000000000000000000000000000000036\r
+:103694000000000000000000000000000000000026\r
+:1036A4000000000000000000000000000000000016\r
+:1036B4000000000000000000000000000000000006\r
+:1036C40000000000000000000000000000000000F6\r
+:1036D40000000000000000000000000000000000E6\r
+:1036E40000000000000000000000000000000103D2\r
+:1036F4000507090E10121416181C1E000000008283\r
+:0637040019CF19E71900BE\r
+:00000001FF\r
diff --git a/FAT16/examples/FAT16_WriteExample/applet/FAT16_WriteExample.cpp.o b/FAT16/examples/FAT16_WriteExample/applet/FAT16_WriteExample.cpp.o
new file mode 100644 (file)
index 0000000..70062d7
Binary files /dev/null and b/FAT16/examples/FAT16_WriteExample/applet/FAT16_WriteExample.cpp.o differ
diff --git a/FAT16/examples/FAT16_WriteExample/applet/HardwareSerial.cpp.o b/FAT16/examples/FAT16_WriteExample/applet/HardwareSerial.cpp.o
new file mode 100644 (file)
index 0000000..d5af083
Binary files /dev/null and b/FAT16/examples/FAT16_WriteExample/applet/HardwareSerial.cpp.o differ
diff --git a/FAT16/examples/FAT16_WriteExample/applet/Print.cpp.o b/FAT16/examples/FAT16_WriteExample/applet/Print.cpp.o
new file mode 100644 (file)
index 0000000..c63f9bf
Binary files /dev/null and b/FAT16/examples/FAT16_WriteExample/applet/Print.cpp.o differ
diff --git a/FAT16/examples/FAT16_WriteExample/applet/WInterrupts.c.o b/FAT16/examples/FAT16_WriteExample/applet/WInterrupts.c.o
new file mode 100644 (file)
index 0000000..52801e4
Binary files /dev/null and b/FAT16/examples/FAT16_WriteExample/applet/WInterrupts.c.o differ
diff --git a/FAT16/examples/FAT16_WriteExample/applet/WMath.cpp.o b/FAT16/examples/FAT16_WriteExample/applet/WMath.cpp.o
new file mode 100644 (file)
index 0000000..d8792d0
Binary files /dev/null and b/FAT16/examples/FAT16_WriteExample/applet/WMath.cpp.o differ
diff --git a/FAT16/examples/FAT16_WriteExample/applet/core.a b/FAT16/examples/FAT16_WriteExample/applet/core.a
new file mode 100644 (file)
index 0000000..41cf0b4
Binary files /dev/null and b/FAT16/examples/FAT16_WriteExample/applet/core.a differ
diff --git a/FAT16/examples/FAT16_WriteExample/applet/pins_arduino.c.o b/FAT16/examples/FAT16_WriteExample/applet/pins_arduino.c.o
new file mode 100644 (file)
index 0000000..c1fa9f5
Binary files /dev/null and b/FAT16/examples/FAT16_WriteExample/applet/pins_arduino.c.o differ
diff --git a/FAT16/examples/FAT16_WriteExample/applet/wiring.c.o b/FAT16/examples/FAT16_WriteExample/applet/wiring.c.o
new file mode 100644 (file)
index 0000000..394cbe8
Binary files /dev/null and b/FAT16/examples/FAT16_WriteExample/applet/wiring.c.o differ
diff --git a/FAT16/examples/FAT16_WriteExample/applet/wiring_analog.c.o b/FAT16/examples/FAT16_WriteExample/applet/wiring_analog.c.o
new file mode 100644 (file)
index 0000000..619dd14
Binary files /dev/null and b/FAT16/examples/FAT16_WriteExample/applet/wiring_analog.c.o differ
diff --git a/FAT16/examples/FAT16_WriteExample/applet/wiring_digital.c.o b/FAT16/examples/FAT16_WriteExample/applet/wiring_digital.c.o
new file mode 100644 (file)
index 0000000..02809ce
Binary files /dev/null and b/FAT16/examples/FAT16_WriteExample/applet/wiring_digital.c.o differ
diff --git a/FAT16/examples/FAT16_WriteExample/applet/wiring_pulse.c.o b/FAT16/examples/FAT16_WriteExample/applet/wiring_pulse.c.o
new file mode 100644 (file)
index 0000000..354b096
Binary files /dev/null and b/FAT16/examples/FAT16_WriteExample/applet/wiring_pulse.c.o differ
diff --git a/FAT16/examples/FAT16_WriteExample/applet/wiring_shift.c.o b/FAT16/examples/FAT16_WriteExample/applet/wiring_shift.c.o
new file mode 100644 (file)
index 0000000..2f318d0
Binary files /dev/null and b/FAT16/examples/FAT16_WriteExample/applet/wiring_shift.c.o differ
diff --git a/FAT16/fat.c b/FAT16/fat.c
new file mode 100644 (file)
index 0000000..c3e2d39
--- /dev/null
@@ -0,0 +1,2326 @@
+
+/* 
+ * Copyright (c) 2006-2009 by Roland Riegel <feedback@roland-riegel.de>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either the GNU General Public License version 2
+ * or the GNU Lesser General Public License version 2.1, both as
+ * published by the Free Software Foundation.
+ */
+
+#include "byteordering.h"
+#include "partition.h"
+#include "fat.h"
+#include "fat_config.h"
+#include "sd-reader_config.h"
+
+#include <cfg/debug.h>
+
+#include <string.h>
+
+#if USE_DYNAMIC_MEMORY
+    #include <stdlib.h>
+#endif
+
+/**
+ * \addtogroup fat FAT support
+ *
+ * This module implements FAT16/FAT32 read and write access.
+ * 
+ * The following features are supported:
+ * - File names up to 31 characters long.
+ * - Unlimited depth of subdirectories.
+ * - Short 8.3 and long filenames.
+ * - Creating and deleting files.
+ * - Reading and writing from and to files.
+ * - File resizing.
+ * - File sizes of up to 4 gigabytes.
+ * 
+ * @{
+ */
+/**
+ * \file
+ * FAT implementation (license: GPLv2 or LGPLv2.1)
+ *
+ * \author Roland Riegel
+ */
+
+/**
+ * \addtogroup fat_config FAT configuration
+ * Preprocessor defines to configure the FAT implementation.
+ */
+
+/**
+ * \addtogroup fat_fs FAT access
+ * Basic functions for handling a FAT filesystem.
+ */
+
+/**
+ * \addtogroup fat_file FAT file functions
+ * Functions for managing files.
+ */
+
+/**
+ * \addtogroup fat_dir FAT directory functions
+ * Functions for managing directories.
+ */
+
+/**
+ * @}
+ */
+
+#define FAT16_CLUSTER_FREE 0x0000
+#define FAT16_CLUSTER_RESERVED_MIN 0xfff0
+#define FAT16_CLUSTER_RESERVED_MAX 0xfff6
+#define FAT16_CLUSTER_BAD 0xfff7
+#define FAT16_CLUSTER_LAST_MIN 0xfff8
+#define FAT16_CLUSTER_LAST_MAX 0xffff
+
+#define FAT32_CLUSTER_FREE 0x00000000
+#define FAT32_CLUSTER_RESERVED_MIN 0x0ffffff0
+#define FAT32_CLUSTER_RESERVED_MAX 0x0ffffff6
+#define FAT32_CLUSTER_BAD 0x0ffffff7
+#define FAT32_CLUSTER_LAST_MIN 0x0ffffff8
+#define FAT32_CLUSTER_LAST_MAX 0x0fffffff
+
+#define FAT_DIRENTRY_DELETED 0xe5
+#define FAT_DIRENTRY_LFNLAST (1 << 6)
+#define FAT_DIRENTRY_LFNSEQMASK ((1 << 6) - 1)
+
+/* Each entry within the directory table has a size of 32 bytes
+ * and either contains a 8.3 DOS-style file name or a part of a
+ * long file name, which may consist of several directory table
+ * entries at once.
+ *
+ * multi-byte integer values are stored little-endian!
+ *
+ * 8.3 file name entry:
+ * ====================
+ * offset  length  description
+ *      0       8  name (space padded)
+ *      8       3  extension (space padded)
+ *     11       1  attributes (FAT_ATTRIB_*)
+ *
+ * long file name (lfn) entry ordering for a single file name:
+ * ===========================================================
+ * LFN entry n
+ *     ...
+ * LFN entry 2
+ * LFN entry 1
+ * 8.3 entry (see above)
+ * 
+ * lfn entry:
+ * ==========
+ * offset  length  description
+ *      0       1  ordinal field
+ *      1       2  unicode character 1
+ *      3       3  unicode character 2
+ *      5       3  unicode character 3
+ *      7       3  unicode character 4
+ *      9       3  unicode character 5
+ *     11       1  attribute (always 0x0f)
+ *     12       1  type (reserved, always 0)
+ *     13       1  checksum
+ *     14       2  unicode character 6
+ *     16       2  unicode character 7
+ *     18       2  unicode character 8
+ *     20       2  unicode character 9
+ *     22       2  unicode character 10
+ *     24       2  unicode character 11
+ *     26       2  cluster (unused, always 0)
+ *     28       2  unicode character 12
+ *     30       2  unicode character 13
+ * 
+ * The ordinal field contains a descending number, from n to 1.
+ * For the n'th lfn entry the ordinal field is or'ed with 0x40.
+ * For deleted lfn entries, the ordinal field is set to 0xe5.
+ */
+
+struct fat_header_struct
+{
+    offset_t size;
+
+    offset_t fat_offset;
+    uint32_t fat_size;
+
+    uint16_t sector_size;
+    uint16_t cluster_size;
+
+    offset_t cluster_zero_offset;
+
+    offset_t root_dir_offset;
+#if FAT_FAT32_SUPPORT
+    cluster_t root_dir_cluster;
+#endif
+};
+
+struct fat_fs_struct
+{
+    struct partition_struct* partition;
+    struct fat_header_struct header;
+};
+
+struct fat_file_struct
+{
+    struct fat_fs_struct* fs;
+    struct fat_dir_entry_struct dir_entry;
+    offset_t pos;
+    cluster_t pos_cluster;
+};
+
+struct fat_dir_struct
+{
+    struct fat_fs_struct* fs;
+    struct fat_dir_entry_struct dir_entry;
+    cluster_t entry_cluster;
+    uint16_t entry_offset;
+};
+
+struct fat_read_dir_callback_arg
+{
+    struct fat_dir_entry_struct* dir_entry;
+    uintptr_t bytes_read;
+    uint8_t finished;
+};
+
+struct fat_usage_count_callback_arg
+{
+    cluster_t cluster_count;
+    uintptr_t buffer_size;
+};
+
+uint16_t i=0;
+
+#if !USE_DYNAMIC_MEMORY
+static struct fat_fs_struct fat_fs_handles[FAT_FS_COUNT];
+static struct fat_file_struct fat_file_handles[FAT_FILE_COUNT];
+static struct fat_dir_struct fat_dir_handles[FAT_DIR_COUNT];
+#endif
+
+static uint8_t fat_read_header(struct fat_fs_struct* fs);
+static cluster_t fat_get_next_cluster(const struct fat_fs_struct* fs, cluster_t cluster_num);
+static offset_t fat_cluster_offset(const struct fat_fs_struct* fs, cluster_t cluster_num);
+static uint8_t fat_dir_entry_read_callback(uint8_t* buffer, offset_t offset, void* p);
+static uint8_t fat_interpret_dir_entry(struct fat_dir_entry_struct* dir_entry, const uint8_t* raw_entry);
+
+static uint8_t fat_get_fs_free_16_callback(uint8_t* buffer, offset_t offset, void* p);
+#if FAT_FAT32_SUPPORT
+static uint8_t fat_get_fs_free_32_callback(uint8_t* buffer, offset_t offset, void* p);
+#endif
+
+#if FAT_WRITE_SUPPORT
+static cluster_t fat_append_clusters(const struct fat_fs_struct* fs, cluster_t cluster_num, cluster_t count);
+static uint8_t fat_free_clusters(const struct fat_fs_struct* fs, cluster_t cluster_num);
+static uint8_t fat_terminate_clusters(const struct fat_fs_struct* fs, cluster_t cluster_num);
+static uint8_t fat_clear_cluster(const struct fat_fs_struct* fs, cluster_t cluster_num);
+static uintptr_t fat_clear_cluster_callback(uint8_t* buffer, offset_t offset, void* p);
+static offset_t fat_find_offset_for_dir_entry(const struct fat_fs_struct* fs, const struct fat_dir_struct* parent, const struct fat_dir_entry_struct* dir_entry);
+static uint8_t fat_write_dir_entry(const struct fat_fs_struct* fs, struct fat_dir_entry_struct* dir_entry);
+#if FAT_DATETIME_SUPPORT
+static void fat_set_file_modification_date(struct fat_dir_entry_struct* dir_entry, uint16_t year, uint8_t month, uint8_t day);
+static void fat_set_file_modification_time(struct fat_dir_entry_struct* dir_entry, uint8_t hour, uint8_t min, uint8_t sec);
+#endif
+#endif
+
+/**
+ * \ingroup fat_fs
+ * Opens a FAT filesystem.
+ *
+ * \param[in] partition Discriptor of partition on which the filesystem resides.
+ * \returns 0 on error, a FAT filesystem descriptor on success.
+ * \see fat_close
+ */
+struct fat_fs_struct* fat_open(struct partition_struct* partition)
+{
+    if(!partition ||
+#if FAT_WRITE_SUPPORT
+       !partition->device_write ||
+       !partition->device_write_interval
+#else
+       0
+#endif
+      )
+        return 0;
+
+#if USE_DYNAMIC_MEMORY
+    struct fat_fs_struct* fs = malloc(sizeof(*fs));
+    if(!fs)
+        return 0;
+#else
+    struct fat_fs_struct* fs = fat_fs_handles;
+    uint8_t i;
+    for(i = 0; i < FAT_FS_COUNT; ++i)
+    {
+        if(!fs->partition)
+            break;
+
+        ++fs;
+    }
+    if(i >= FAT_FS_COUNT)
+        return 0;
+#endif
+
+    memset(fs, 0, sizeof(*fs));
+
+    fs->partition = partition;
+    if(!fat_read_header(fs))
+    {
+#if USE_DYNAMIC_MEMORY
+        free(fs);
+#else
+        fs->partition = 0;
+#endif
+        return 0;
+    }
+    
+    return fs;
+}
+
+/**
+ * \ingroup fat_fs
+ * Closes a FAT filesystem.
+ *
+ * When this function returns, the given filesystem descriptor
+ * will be invalid.
+ *
+ * \param[in] fs The filesystem to close.
+ * \see fat_open
+ */
+void fat_close(struct fat_fs_struct* fs)
+{
+    if(!fs)
+        return;
+
+#if USE_DYNAMIC_MEMORY
+    free(fs);
+#else
+    fs->partition = 0;
+#endif
+}
+
+/**
+ * \ingroup fat_fs
+ * Reads and parses the header of a FAT filesystem.
+ *
+ * \param[inout] fs The filesystem for which to parse the header.
+ * \returns 0 on failure, 1 on success.
+ */
+uint8_t fat_read_header(struct fat_fs_struct* fs)
+{
+    if(!fs)
+        return 0;
+
+    struct partition_struct* partition = fs->partition;
+    if(!partition)
+        return 0;
+
+    /* read fat parameters */
+#if FAT_FAT32_SUPPORT
+    uint8_t buffer[37];
+#else
+    uint8_t buffer[25];
+#endif
+    offset_t partition_offset = (offset_t) partition->offset * 512;
+    if(!partition->device_read(partition_offset + 0x0b, buffer, sizeof(buffer)))
+        return 0;
+
+    uint16_t bytes_per_sector = ltoh16(*((uint16_t*) &buffer[0x00]));
+    uint16_t reserved_sectors = ltoh16(*((uint16_t*) &buffer[0x03]));
+    uint8_t sectors_per_cluster = buffer[0x02];
+    uint8_t fat_copies = buffer[0x05];
+    uint16_t max_root_entries = ltoh16(*((uint16_t*) &buffer[0x06]));
+    uint16_t sector_count_16 = ltoh16(*((uint16_t*) &buffer[0x08]));
+    uint16_t sectors_per_fat = ltoh16(*((uint16_t*) &buffer[0x0b]));
+    uint32_t sector_count = ltoh32(*((uint32_t*) &buffer[0x15]));
+#if FAT_FAT32_SUPPORT
+    uint32_t sectors_per_fat32 = ltoh32(*((uint32_t*) &buffer[0x19]));
+    uint32_t cluster_root_dir = ltoh32(*((uint32_t*) &buffer[0x21]));
+#endif
+
+    if(sector_count == 0)
+    {
+        if(sector_count_16 == 0)
+            /* illegal volume size */
+            return 0;
+        else
+            sector_count = sector_count_16;
+    }
+#if FAT_FAT32_SUPPORT
+    if(sectors_per_fat != 0)
+        sectors_per_fat32 = sectors_per_fat;
+    else if(sectors_per_fat32 == 0)
+        /* this is neither FAT16 nor FAT32 */
+        return 0;
+#else
+    if(sectors_per_fat == 0)
+        /* this is not a FAT16 */
+        return 0;
+#endif
+
+    /* determine the type of FAT we have here */
+    uint32_t data_sector_count = sector_count
+                                 - reserved_sectors
+#if FAT_FAT32_SUPPORT
+                                 - sectors_per_fat32 * fat_copies
+#else
+                                 - (uint32_t) sectors_per_fat * fat_copies
+#endif
+                                 - ((max_root_entries * 32 + bytes_per_sector - 1) / bytes_per_sector);
+    uint32_t data_cluster_count = data_sector_count / sectors_per_cluster;
+    if(data_cluster_count < 4085)
+        /* this is a FAT12, not supported */
+        return 0;
+    else if(data_cluster_count < 65525)
+        /* this is a FAT16 */
+        partition->type = PARTITION_TYPE_FAT16;
+    else
+        /* this is a FAT32 */
+        partition->type = PARTITION_TYPE_FAT32;
+
+    /* fill header information */
+    struct fat_header_struct* header = &fs->header;
+    memset(header, 0, sizeof(*header));
+    
+    header->size = (offset_t) sector_count * bytes_per_sector;
+
+    header->fat_offset = /* jump to partition */
+                         partition_offset +
+                         /* jump to fat */
+                         (offset_t) reserved_sectors * bytes_per_sector;
+    header->fat_size = (data_cluster_count + 2) * (partition->type == PARTITION_TYPE_FAT16 ? 2 : 4);
+
+    header->sector_size = bytes_per_sector;
+    header->cluster_size = (uint16_t) bytes_per_sector * sectors_per_cluster;
+
+#if FAT_FAT32_SUPPORT
+    if(partition->type == PARTITION_TYPE_FAT16)
+#endif
+    {
+        header->root_dir_offset = /* jump to fats */
+                                  header->fat_offset +
+                                  /* jump to root directory entries */
+                                  (offset_t) fat_copies * sectors_per_fat * bytes_per_sector;
+
+        header->cluster_zero_offset = /* jump to root directory entries */
+                                      header->root_dir_offset +
+                                      /* skip root directory entries */
+                                      (offset_t) max_root_entries * 32;
+    }
+#if FAT_FAT32_SUPPORT
+    else
+    {
+        header->cluster_zero_offset = /* jump to fats */
+                                      header->fat_offset +
+                                      /* skip fats */
+                                      (offset_t) fat_copies * sectors_per_fat32 * bytes_per_sector;
+
+        header->root_dir_cluster = cluster_root_dir;
+    }
+#endif
+
+    return 1;
+}
+
+/**
+ * \ingroup fat_fs
+ * Retrieves the next following cluster of a given cluster.
+ *
+ * Using the filesystem file allocation table, this function returns
+ * the number of the cluster containing the data directly following
+ * the data within the cluster with the given number.
+ *
+ * \param[in] fs The filesystem for which to determine the next cluster.
+ * \param[in] cluster_num The number of the cluster for which to determine its successor.
+ * \returns The wanted cluster number, or 0 on error.
+ */
+cluster_t fat_get_next_cluster(const struct fat_fs_struct* fs, cluster_t cluster_num)
+{
+    if(!fs || cluster_num < 2)
+        return 0;
+
+#if FAT_FAT32_SUPPORT
+    if(fs->partition->type == PARTITION_TYPE_FAT32)
+    {
+        /* read appropriate fat entry */
+        uint32_t fat_entry;
+        if(!fs->partition->device_read(fs->header.fat_offset + cluster_num * sizeof(fat_entry), (uint8_t*) &fat_entry, sizeof(fat_entry)))
+            return 0;
+
+        /* determine next cluster from fat */
+        cluster_num = ltoh32(fat_entry);
+        
+        if(cluster_num == FAT32_CLUSTER_FREE ||
+           cluster_num == FAT32_CLUSTER_BAD ||
+           (cluster_num >= FAT32_CLUSTER_RESERVED_MIN && cluster_num <= FAT32_CLUSTER_RESERVED_MAX) ||
+           (cluster_num >= FAT32_CLUSTER_LAST_MIN && cluster_num <= FAT32_CLUSTER_LAST_MAX))
+            return 0;
+    }
+    else
+#endif
+    {
+        /* read appropriate fat entry */
+        uint16_t fat_entry;
+        if(!fs->partition->device_read(fs->header.fat_offset + cluster_num * sizeof(fat_entry), (uint8_t*) &fat_entry, sizeof(fat_entry)))
+            return 0;
+
+        /* determine next cluster from fat */
+        cluster_num = ltoh16(fat_entry);
+        
+        if(cluster_num == FAT16_CLUSTER_FREE ||
+           cluster_num == FAT16_CLUSTER_BAD ||
+           (cluster_num >= FAT16_CLUSTER_RESERVED_MIN && cluster_num <= FAT16_CLUSTER_RESERVED_MAX) ||
+           (cluster_num >= FAT16_CLUSTER_LAST_MIN && cluster_num <= FAT16_CLUSTER_LAST_MAX))
+            return 0;
+    }
+
+    return cluster_num;
+}
+
+#if FAT_WRITE_SUPPORT
+/**
+ * \ingroup fat_fs
+ * Appends a new cluster chain to an existing one.
+ *
+ * Set cluster_num to zero to create a completely new one.
+ *
+ * \param[in] fs The file system on which to operate.
+ * \param[in] cluster_num The cluster to which to append the new chain.
+ * \param[in] count The number of clusters to allocate.
+ * \returns 0 on failure, the number of the first new cluster on success.
+ */
+cluster_t fat_append_clusters(const struct fat_fs_struct* fs, cluster_t cluster_num, cluster_t count)
+{
+    if(!fs)
+        return 0;
+
+    device_read_t device_read = fs->partition->device_read;
+    device_write_t device_write = fs->partition->device_write;
+    offset_t fat_offset = fs->header.fat_offset;
+    cluster_t count_left = count;
+    cluster_t cluster_next = 0;
+    cluster_t cluster_max;
+    uint16_t fat_entry16;
+#if FAT_FAT32_SUPPORT
+    uint32_t fat_entry32;
+    uint8_t is_fat32 = (fs->partition->type == PARTITION_TYPE_FAT32);
+
+    if(is_fat32)
+        cluster_max = fs->header.fat_size / sizeof(fat_entry32);
+    else
+#endif
+        cluster_max = fs->header.fat_size / sizeof(fat_entry16);
+
+       cluster_t cluster_new=0;
+    for(cluster_new = 2; cluster_new < cluster_max; ++cluster_new)
+    {
+#if FAT_FAT32_SUPPORT
+        if(is_fat32)
+        {
+            if(!device_read(fat_offset + cluster_new * sizeof(fat_entry32), (uint8_t*) &fat_entry32, sizeof(fat_entry32)))
+                return 0;
+        }
+        else
+#endif
+        {
+            if(!device_read(fat_offset + cluster_new * sizeof(fat_entry16), (uint8_t*) &fat_entry16, sizeof(fat_entry16)))
+                return 0;
+        }
+
+#if FAT_FAT32_SUPPORT
+        if(is_fat32)
+        {
+            /* check if this is a free cluster */
+            if(fat_entry32 != HTOL32(FAT32_CLUSTER_FREE))
+                continue;
+
+            /* allocate cluster */
+            if(cluster_next == 0)
+                fat_entry32 = HTOL32(FAT32_CLUSTER_LAST_MAX);
+            else
+                fat_entry32 = htol32(cluster_next);
+
+            if(!device_write(fat_offset + cluster_new * sizeof(fat_entry32), (uint8_t*) &fat_entry32, sizeof(fat_entry32)))
+                break;
+        }
+        else
+#endif
+        {
+            /* check if this is a free cluster */
+            if(fat_entry16 != HTOL16(FAT16_CLUSTER_FREE))
+                continue;
+
+            /* allocate cluster */
+            if(cluster_next == 0)
+                fat_entry16 = HTOL16(FAT16_CLUSTER_LAST_MAX);
+            else
+                fat_entry16 = htol16((uint16_t) cluster_next);
+
+            if(!device_write(fat_offset + cluster_new * sizeof(fat_entry16), (uint8_t*) &fat_entry16, sizeof(fat_entry16)))
+                break;
+        }
+
+        cluster_next = cluster_new;
+        if(--count_left == 0)
+            break;
+    }
+
+    do
+    {
+        if(count_left > 0)
+            break;
+
+        /* We allocated a new cluster chain. Now join
+         * it with the existing one (if any).
+         */
+        if(cluster_num >= 2)
+        {
+#if FAT_FAT32_SUPPORT
+            if(is_fat32)
+            {
+                fat_entry32 = htol32(cluster_next);
+
+                if(!device_write(fat_offset + cluster_num * sizeof(fat_entry32), (uint8_t*) &fat_entry32, sizeof(fat_entry32)))
+                    break;
+            }
+            else
+#endif
+            {
+                fat_entry16 = htol16((uint16_t) cluster_next);
+
+                if(!device_write(fat_offset + cluster_num * sizeof(fat_entry16), (uint8_t*) &fat_entry16, sizeof(fat_entry16)))
+                    break;
+            }
+        }
+
+        return cluster_next;
+
+    } while(0);
+
+    /* No space left on device or writing error.
+     * Free up all clusters already allocated.
+     */
+    fat_free_clusters(fs, cluster_next);
+
+    return 0;
+}
+#endif
+
+#if  FAT_WRITE_SUPPORT
+/**
+ * \ingroup fat_fs
+ * Frees a cluster chain, or a part thereof.
+ *
+ * Marks the specified cluster and all clusters which are sequentially
+ * referenced by it as free. They may then be used again for future
+ * file allocations.
+ *
+ * \note If this function is used for freeing just a part of a cluster
+ *       chain, the new end of the chain is not correctly terminated
+ *       within the FAT. Use fat_terminate_clusters() instead.
+ *
+ * \param[in] fs The filesystem on which to operate.
+ * \param[in] cluster_num The starting cluster of the chain which to free.
+ * \returns 0 on failure, 1 on success.
+ * \see fat_terminate_clusters
+ */
+uint8_t fat_free_clusters(const struct fat_fs_struct* fs, cluster_t cluster_num)
+{
+    if(!fs || cluster_num < 2)
+        return 0;
+
+    offset_t fat_offset = fs->header.fat_offset;
+#if FAT_FAT32_SUPPORT
+    if(fs->partition->type == PARTITION_TYPE_FAT32)
+    {
+        uint32_t fat_entry;
+        while(cluster_num)
+        {
+            if(!fs->partition->device_read(fat_offset + cluster_num * sizeof(fat_entry), (uint8_t*) &fat_entry, sizeof(fat_entry)))
+                return 0;
+
+            /* get next cluster of current cluster before freeing current cluster */
+            uint32_t cluster_num_next = ltoh32(fat_entry);
+
+            if(cluster_num_next == FAT32_CLUSTER_FREE)
+                return 1;
+            if(cluster_num_next == FAT32_CLUSTER_BAD ||
+               (cluster_num_next >= FAT32_CLUSTER_RESERVED_MIN &&
+                cluster_num_next <= FAT32_CLUSTER_RESERVED_MAX
+               )
+              )
+                return 0;
+            if(cluster_num_next >= FAT32_CLUSTER_LAST_MIN && cluster_num_next <= FAT32_CLUSTER_LAST_MAX)
+                cluster_num_next = 0;
+
+            /* free cluster */
+            fat_entry = HTOL32(FAT32_CLUSTER_FREE);
+            fs->partition->device_write(fat_offset + cluster_num * sizeof(fat_entry), (uint8_t*) &fat_entry, sizeof(fat_entry));
+
+            /* We continue in any case here, even if freeing the cluster failed.
+             * The cluster is lost, but maybe we can still free up some later ones.
+             */
+
+            cluster_num = cluster_num_next;
+        }
+    }
+    else
+#endif
+    {
+        uint16_t fat_entry;
+        while(cluster_num)
+        {
+            if(!fs->partition->device_read(fat_offset + cluster_num * sizeof(fat_entry), (uint8_t*) &fat_entry, sizeof(fat_entry)))
+                return 0;
+
+            /* get next cluster of current cluster before freeing current cluster */
+            uint16_t cluster_num_next = ltoh16(fat_entry);
+
+            if(cluster_num_next == FAT16_CLUSTER_FREE)
+                return 1;
+            if(cluster_num_next == FAT16_CLUSTER_BAD ||
+               (cluster_num_next >= FAT16_CLUSTER_RESERVED_MIN &&
+                cluster_num_next <= FAT16_CLUSTER_RESERVED_MAX
+               )
+              )
+                return 0;
+            if(cluster_num_next >= FAT16_CLUSTER_LAST_MIN && cluster_num_next <= FAT16_CLUSTER_LAST_MAX)
+                cluster_num_next = 0;
+
+            /* free cluster */
+            fat_entry = HTOL16(FAT16_CLUSTER_FREE);
+            fs->partition->device_write(fat_offset + cluster_num * sizeof(fat_entry), (uint8_t*) &fat_entry, sizeof(fat_entry));
+
+            /* We continue in any case here, even if freeing the cluster failed.
+             * The cluster is lost, but maybe we can still free up some later ones.
+             */
+
+            cluster_num = cluster_num_next;
+        }
+    }
+
+    return 1;
+}
+#endif
+
+#if  FAT_WRITE_SUPPORT
+/**
+ * \ingroup fat_fs
+ * Frees a part of a cluster chain and correctly terminates the rest.
+ *
+ * Marks the specified cluster as the new end of a cluster chain and
+ * frees all following clusters.
+ *
+ * \param[in] fs The filesystem on which to operate.
+ * \param[in] cluster_num The new end of the cluster chain.
+ * \returns 0 on failure, 1 on success.
+ * \see fat_free_clusters
+ */
+uint8_t fat_terminate_clusters(const struct fat_fs_struct* fs, cluster_t cluster_num)
+{
+    if(!fs || cluster_num < 2)
+        return 0;
+
+    /* fetch next cluster before overwriting the cluster entry */
+    cluster_t cluster_num_next = fat_get_next_cluster(fs, cluster_num);
+
+    /* mark cluster as the last one */
+#if FAT_FAT32_SUPPORT
+    if(fs->partition->type == PARTITION_TYPE_FAT32)
+    {
+        uint32_t fat_entry = HTOL32(FAT32_CLUSTER_LAST_MAX);
+        if(!fs->partition->device_write(fs->header.fat_offset + cluster_num * sizeof(fat_entry), (uint8_t*) &fat_entry, sizeof(fat_entry)))
+            return 0;
+    }
+    else
+#endif
+    {
+        uint16_t fat_entry = HTOL16(FAT16_CLUSTER_LAST_MAX);
+        if(!fs->partition->device_write(fs->header.fat_offset + cluster_num * sizeof(fat_entry), (uint8_t*) &fat_entry, sizeof(fat_entry)))
+            return 0;
+    }
+
+    /* free remaining clusters */
+    if(cluster_num_next)
+        return fat_free_clusters(fs, cluster_num_next);
+    else
+        return 1;
+}
+#endif
+
+#if  FAT_WRITE_SUPPORT
+/**
+ * \ingroup fat_fs
+ * Clears a single cluster.
+ *
+ * The complete cluster is filled with zeros.
+ *
+ * \param[in] fs The filesystem on which to operate.
+ * \param[in] cluster_num The cluster to clear.
+ * \returns 0 on failure, 1 on success.
+ */
+uint8_t fat_clear_cluster(const struct fat_fs_struct* fs, cluster_t cluster_num)
+{
+    if(cluster_num < 2)
+        return 0;
+
+    offset_t cluster_offset = fat_cluster_offset(fs, cluster_num);
+
+    uint8_t zero[16];
+    memset(zero, 0, sizeof(zero));
+    return fs->partition->device_write_interval(cluster_offset,
+                                                zero,
+                                                fs->header.cluster_size,
+                                                fat_clear_cluster_callback,
+                                                0
+                                               );
+}
+#endif
+
+#if  FAT_WRITE_SUPPORT
+/**
+ * \ingroup fat_fs
+ * Callback function for clearing a cluster.
+ */
+uintptr_t fat_clear_cluster_callback(uint8_t* buffer, offset_t offset, void* p)
+{
+    return 16;
+}
+#endif
+
+/**
+ * \ingroup fat_fs
+ * Calculates the offset of the specified cluster.
+ *
+ * \param[in] fs The filesystem on which to operate.
+ * \param[in] cluster_num The cluster whose offset to calculate.
+ * \returns The cluster offset.
+ */
+offset_t fat_cluster_offset(const struct fat_fs_struct* fs, cluster_t cluster_num)
+{
+    if(!fs || cluster_num < 2)
+        return 0;
+
+    return fs->header.cluster_zero_offset + (offset_t) (cluster_num - 2) * fs->header.cluster_size;
+}
+
+/**
+ * \ingroup fat_file
+ * Retrieves the directory entry of a path.
+ *
+ * The given path may both describe a file or a directory.
+ *
+ * \param[in] fs The FAT filesystem on which to search.
+ * \param[in] path The path of which to read the directory entry.
+ * \param[out] dir_entry The directory entry to fill.
+ * \returns 0 on failure, 1 on success.
+ * \see fat_read_dir
+ */
+uint8_t fat_get_dir_entry_of_path(struct fat_fs_struct* fs, const char* path, struct fat_dir_entry_struct* dir_entry)
+{
+    if(!fs || !path || path[0] == '\0' || !dir_entry)
+        return 0;
+
+    if(path[0] == '/')
+        ++path;
+
+    /* begin with the root directory */
+    memset(dir_entry, 0, sizeof(*dir_entry));
+    dir_entry->attributes = FAT_ATTRIB_DIR;
+
+    while(1)
+    {
+        if(path[0] == '\0')
+            return 1;
+
+        struct fat_dir_struct* dd = fat_open_dir(fs, dir_entry);
+        if(!dd)
+            break;
+
+        /* extract the next hierarchy we will search for */
+        const char* sub_path = strchr(path, '/');
+        uint8_t length_to_sep;
+        if(sub_path)
+        {
+            length_to_sep = sub_path - path;
+            ++sub_path;
+        }
+        else
+        {
+            length_to_sep = strlen(path);
+            sub_path = path + length_to_sep;
+        }
+        
+        /* read directory entries */
+        while(fat_read_dir(dd, dir_entry))
+        {
+            /* check if we have found the next hierarchy */
+            if((strlen(dir_entry->long_name) != length_to_sep ||
+                strncmp(path, dir_entry->long_name, length_to_sep) != 0))
+                continue;
+
+            fat_close_dir(dd);
+            dd = 0;
+
+            if(path[length_to_sep] == '\0')
+                /* we iterated through the whole path and have found the file */
+                return 1;
+
+            if(dir_entry->attributes & FAT_ATTRIB_DIR)
+            {
+                /* we found a parent directory of the file we are searching for */
+                path = sub_path;
+                break;
+            }
+
+            /* a parent of the file exists, but not the file itself */
+            return 0;
+        }
+
+        fat_close_dir(dd);
+    }
+    
+    return 0;
+}
+
+/**
+ * \ingroup fat_file
+ * Opens a file on a FAT filesystem.
+ *
+ * \param[in] fs The filesystem on which the file to open lies.
+ * \param[in] dir_entry The directory entry of the file to open.
+ * \returns The file handle, or 0 on failure.
+ * \see fat_close_file
+ */
+struct fat_file_struct* fat_open_file(struct fat_fs_struct* fs, const struct fat_dir_entry_struct* dir_entry)
+{
+    if(!fs || !dir_entry || (dir_entry->attributes & FAT_ATTRIB_DIR))
+        return 0;
+
+#if USE_DYNAMIC_MEMORY
+    struct fat_file_struct* fd = malloc(sizeof(*fd));
+    if(!fd)
+        return 0;
+#else
+    struct fat_file_struct* fd = fat_file_handles;
+    uint8_t i;
+    for(i = 0; i < FAT_FILE_COUNT; ++i)
+    {
+        if(!fd->fs)
+            break;
+
+        ++fd;
+    }
+    if(i >= FAT_FILE_COUNT)
+        return 0;
+#endif
+    
+    memcpy(&fd->dir_entry, dir_entry, sizeof(*dir_entry));
+    fd->fs = fs;
+    fd->pos = 0;
+    fd->pos_cluster = dir_entry->cluster;
+
+    return fd;
+}
+
+/**
+ * \ingroup fat_file
+ * Closes a file.
+ *
+ * \param[in] fd The file handle of the file to close.
+ * \see fat_open_file
+ */
+void fat_close_file(struct fat_file_struct* fd)
+{
+    if(fd)
+#if USE_DYNAMIC_MEMORY
+        free(fd);
+#else
+        fd->fs = 0;
+#endif
+}
+
+/**
+ * \ingroup fat_file
+ * Reads data from a file.
+ * 
+ * The data requested is read from the current file location.
+ *
+ * \param[in] fd The file handle of the file from which to read.
+ * \param[out] buffer The buffer into which to write.
+ * \param[in] buffer_len The amount of data to read.
+ * \returns The number of bytes read, 0 on end of file, or -1 on failure.
+ * \see fat_write_file
+ */
+intptr_t fat_read_file(struct fat_file_struct* fd, uint8_t* buffer, uintptr_t buffer_len)
+{
+    /* check arguments */
+    if(!fd || !buffer || buffer_len < 1)
+        return -1;
+
+    /* determine number of bytes to read */
+    if(fd->pos + buffer_len > fd->dir_entry.file_size)
+        buffer_len = fd->dir_entry.file_size - fd->pos;
+    if(buffer_len == 0)
+        return 0;
+    
+    uint16_t cluster_size = fd->fs->header.cluster_size;
+    cluster_t cluster_num = fd->pos_cluster;
+    uintptr_t buffer_left = buffer_len;
+    uint16_t first_cluster_offset = (uint16_t) (fd->pos & (cluster_size - 1));
+
+    /* find cluster in which to start reading */
+    if(!cluster_num)
+    {
+        cluster_num = fd->dir_entry.cluster;
+        
+        if(!cluster_num)
+        {
+            if(!fd->pos)
+                return 0;
+            else
+                return -1;
+        }
+
+        if(fd->pos)
+        {
+            uint32_t pos = fd->pos;
+            while(pos >= cluster_size)
+            {
+                pos -= cluster_size;
+                cluster_num = fat_get_next_cluster(fd->fs, cluster_num);
+                if(!cluster_num)
+                    return -1;
+            }
+        }
+    }
+    
+    /* read data */
+    do
+    {
+        /* calculate data size to copy from cluster */
+        offset_t cluster_offset = fat_cluster_offset(fd->fs, cluster_num) + first_cluster_offset;
+        uint16_t copy_length = cluster_size - first_cluster_offset;
+        if(copy_length > buffer_left)
+            copy_length = buffer_left;
+
+        /* read data */
+        if(!fd->fs->partition->device_read(cluster_offset, buffer, copy_length))
+            return buffer_len - buffer_left;
+
+        /* calculate new file position */
+        buffer += copy_length;
+        buffer_left -= copy_length;
+        fd->pos += copy_length;
+
+        if(first_cluster_offset + copy_length >= cluster_size)
+        {
+            /* we are on a cluster boundary, so get the next cluster */
+            if((cluster_num = fat_get_next_cluster(fd->fs, cluster_num)))
+            {
+                first_cluster_offset = 0;
+            }
+            else
+            {
+                fd->pos_cluster = 0;
+                return buffer_len - buffer_left;
+            }
+        }
+
+        fd->pos_cluster = cluster_num;
+
+    } while(buffer_left > 0); /* check if we are done */
+
+    return buffer_len;
+}
+
+/**
+ * \ingroup fat_file
+ * Writes data to a file.
+ * 
+ * The data is written to the current file location.
+ *
+ * \param[in] fd The file handle of the file to which to write.
+ * \param[in] buffer The buffer from which to read the data to be written.
+ * \param[in] buffer_len The amount of data to write.
+ * \returns The number of bytes written, 0 on disk full, or -1 on failure.
+ * \see fat_read_file
+ */
+intptr_t fat_write_file(struct fat_file_struct* fd, const uint8_t* buffer, uintptr_t buffer_len)
+{
+    /* check arguments */
+    if(!fd || !buffer || buffer_len < 1)
+        return -1;
+    if(fd->pos > fd->dir_entry.file_size)
+        return -1;
+
+    uint16_t cluster_size = fd->fs->header.cluster_size;
+    cluster_t cluster_num = fd->pos_cluster;
+    uintptr_t buffer_left = buffer_len;
+    uint16_t first_cluster_offset = (uint16_t) (fd->pos & (cluster_size - 1));
+
+    /* find cluster in which to start writing */
+    if(!cluster_num)
+    {
+        cluster_num = fd->dir_entry.cluster;
+        
+        if(!cluster_num)
+        {
+            if(!fd->pos)
+            {
+                /* empty file */
+                fd->dir_entry.cluster = cluster_num = fat_append_clusters(fd->fs, 0, 1);
+                if(!cluster_num)
+                    return -1;
+            }
+            else
+            {
+                return -1;
+            }
+        }
+
+        if(fd->pos)
+        {
+            uint32_t pos = fd->pos;
+            cluster_t cluster_num_next;
+            while(pos >= cluster_size)
+            {
+                pos -= cluster_size;
+                cluster_num_next = fat_get_next_cluster(fd->fs, cluster_num);
+                if(!cluster_num_next && pos == 0)
+                    /* the file exactly ends on a cluster boundary, and we append to it */
+                    cluster_num_next = fat_append_clusters(fd->fs, cluster_num, 1);
+                if(!cluster_num_next)
+                    return -1;
+
+                cluster_num = cluster_num_next;
+            }
+        }
+    }
+    
+    /* write data */
+    do
+    {
+        /* calculate data size to write to cluster */
+        offset_t cluster_offset = fat_cluster_offset(fd->fs, cluster_num) + first_cluster_offset;
+        uint16_t write_length = cluster_size - first_cluster_offset;
+        if(write_length > buffer_left)
+            write_length = buffer_left;
+
+        /* write data which fits into the current cluster */
+        if(!fd->fs->partition->device_write(cluster_offset, buffer, write_length))
+            break;
+
+        /* calculate new file position */
+        buffer += write_length;
+        buffer_left -= write_length;
+        fd->pos += write_length;
+
+        if(first_cluster_offset + write_length >= cluster_size)
+        {
+            /* we are on a cluster boundary, so get the next cluster */
+            cluster_t cluster_num_next = fat_get_next_cluster(fd->fs, cluster_num);
+            if(!cluster_num_next && buffer_left > 0)
+                /* we reached the last cluster, append a new one */
+                cluster_num_next = fat_append_clusters(fd->fs, cluster_num, 1);
+            if(!cluster_num_next)
+            {
+                fd->pos_cluster = 0;
+                break;
+            }
+
+            cluster_num = cluster_num_next;
+            first_cluster_offset = 0;
+        }
+
+        fd->pos_cluster = cluster_num;
+
+    } while(buffer_left > 0); /* check if we are done */
+
+    /* update directory entry */
+    if(fd->pos > fd->dir_entry.file_size)
+    {
+        uint32_t size_old = fd->dir_entry.file_size;
+
+        /* update file size */
+        fd->dir_entry.file_size = fd->pos;
+        /* write directory entry */
+        if(!fat_write_dir_entry(fd->fs, &fd->dir_entry))
+        {
+            /* We do not return an error here since we actually wrote
+             * some data to disk. So we calculate the amount of data
+             * we wrote to disk and which lies within the old file size.
+             */
+            buffer_left = fd->pos - size_old;
+            fd->pos = size_old;
+        }
+    }
+
+    return buffer_len - buffer_left;
+}
+
+/**
+ * \ingroup fat_file
+ * Repositions the read/write file offset.
+ *
+ * Changes the file offset where the next call to fat_read_file()
+ * or fat_write_file() starts reading/writing.
+ *
+ * If the new offset is beyond the end of the file, fat_resize_file()
+ * is implicitly called, i.e. the file is expanded.
+ *
+ * The new offset can be given in different ways determined by
+ * the \c whence parameter:
+ * - \b FAT_SEEK_SET: \c *offset is relative to the beginning of the file.
+ * - \b FAT_SEEK_CUR: \c *offset is relative to the current file position.
+ * - \b FAT_SEEK_END: \c *offset is relative to the end of the file.
+ *
+ * The resulting absolute offset is written to the location the \c offset
+ * parameter points to.
+ * 
+ * \param[in] fd The file decriptor of the file on which to seek.
+ * \param[in,out] offset A pointer to the new offset, as affected by the \c whence
+ *                   parameter. The function writes the new absolute offset
+ *                   to this location before it returns.
+ * \param[in] whence Affects the way \c offset is interpreted, see above.
+ * \returns 0 on failure, 1 on success.
+ */
+uint8_t fat_seek_file(struct fat_file_struct* fd, int32_t* offset, uint8_t whence)
+{
+    if(!fd || !offset)
+        return 0;
+
+    uint32_t new_pos = fd->pos;
+    switch(whence)
+    {
+        case FAT_SEEK_SET:
+            new_pos = *offset;
+            break;
+        case FAT_SEEK_CUR:
+            new_pos += *offset;
+            break;
+        case FAT_SEEK_END:
+            new_pos = fd->dir_entry.file_size + *offset;
+            break;
+        default:
+            return 0;
+    }
+
+    if(new_pos > fd->dir_entry.file_size
+#if FAT_WRITE_SUPPORT
+       && !fat_resize_file(fd, new_pos)
+#endif
+       )
+        return 0;
+
+    fd->pos = new_pos;
+    fd->pos_cluster = 0;
+
+    *offset = (int32_t) new_pos;
+    return 1;
+}
+
+#if  FAT_WRITE_SUPPORT
+/**
+ * \ingroup fat_file
+ * Resizes a file to have a specific size.
+ *
+ * Enlarges or shrinks the file pointed to by the file descriptor to have
+ * exactly the specified size.
+ *
+ * If the file is truncated, all bytes having an equal or larger offset
+ * than the given size are lost. If the file is expanded, the additional
+ * bytes are allocated.
+ *
+ * \note Please be aware that this function just allocates or deallocates disk
+ * space, it does not explicitely clear it. To avoid data leakage, this
+ * must be done manually.
+ *
+ * \param[in] fd The file decriptor of the file which to resize.
+ * \param[in] size The new size of the file.
+ * \returns 0 on failure, 1 on success.
+ */
+uint8_t fat_resize_file(struct fat_file_struct* fd, uint32_t size)
+{
+    if(!fd)
+        return 0;
+
+    cluster_t cluster_num = fd->dir_entry.cluster;
+    uint16_t cluster_size = fd->fs->header.cluster_size;
+    uint32_t size_new = size;
+
+    do
+    {
+        if(cluster_num == 0 && size_new == 0)
+            /* the file stays empty */
+            break;
+
+        /* seek to the next cluster as long as we need the space */
+        while(size_new > cluster_size)
+        {
+            /* get next cluster of file */
+            cluster_t cluster_num_next = fat_get_next_cluster(fd->fs, cluster_num);
+            if(cluster_num_next)
+            {
+                cluster_num = cluster_num_next;
+                size_new -= cluster_size;
+            }
+            else
+            {
+                break;
+            }
+        }
+
+        if(size_new > cluster_size || cluster_num == 0)
+        {
+            /* Allocate new cluster chain and append
+             * it to the existing one, if available.
+             */
+            cluster_t cluster_count = (size_new + cluster_size - 1) / cluster_size;
+            cluster_t cluster_new_chain = fat_append_clusters(fd->fs, cluster_num, cluster_count);
+            if(!cluster_new_chain)
+                return 0;
+
+            if(!cluster_num)
+            {
+                cluster_num = cluster_new_chain;
+                fd->dir_entry.cluster = cluster_num;
+            }
+        }
+
+        /* write new directory entry */
+        fd->dir_entry.file_size = size;
+        if(size == 0)
+            fd->dir_entry.cluster = 0;
+        if(!fat_write_dir_entry(fd->fs, &fd->dir_entry))
+            return 0;
+
+        if(size == 0)
+        {
+            /* free all clusters of file */
+            fat_free_clusters(fd->fs, cluster_num);
+        }
+        else if(size_new <= cluster_size)
+        {
+            /* free all clusters no longer needed */
+            fat_terminate_clusters(fd->fs, cluster_num);
+        }
+
+    } while(0);
+
+    /* correct file position */
+    if(size < fd->pos)
+    {
+        fd->pos = size;
+        fd->pos_cluster = 0;
+    }
+
+    return 1;
+}
+#endif
+
+/**
+ * \ingroup fat_dir
+ * Opens a directory.
+ *
+ * \param[in] fs The filesystem on which the directory to open resides.
+ * \param[in] dir_entry The directory entry which stands for the directory to open.
+ * \returns An opaque directory descriptor on success, 0 on failure.
+ * \see fat_close_dir
+ */
+struct fat_dir_struct* fat_open_dir(struct fat_fs_struct* fs, const struct fat_dir_entry_struct* dir_entry)
+{
+    if(!fs || !dir_entry || !(dir_entry->attributes & FAT_ATTRIB_DIR))
+        return 0;
+
+#if USE_DYNAMIC_MEMORY
+    struct fat_dir_struct* dd = malloc(sizeof(*dd));
+    if(!dd)
+        return 0;
+#else
+    struct fat_dir_struct* dd = fat_dir_handles;
+    uint8_t i;
+    for(i = 0; i < FAT_DIR_COUNT; ++i)
+    {
+        if(!dd->fs)
+            break;
+
+        ++dd;
+    }
+    if(i >= FAT_DIR_COUNT)
+        return 0;
+#endif
+    
+    memcpy(&dd->dir_entry, dir_entry, sizeof(*dir_entry));
+    dd->fs = fs;
+    dd->entry_cluster = dir_entry->cluster;
+    dd->entry_offset = 0;
+
+    return dd;
+}
+
+/**
+ * \ingroup fat_dir
+ * Closes a directory descriptor.
+ *
+ * This function destroys a directory descriptor which was
+ * previously obtained by calling fat_open_dir(). When this
+ * function returns, the given descriptor will be invalid.
+ *
+ * \param[in] dd The directory descriptor to close.
+ * \see fat_open_dir
+ */
+void fat_close_dir(struct fat_dir_struct* dd)
+{
+    if(dd)
+#if USE_DYNAMIC_MEMORY
+        free(dd);
+#else
+        dd->fs = 0;
+#endif
+}
+
+/**
+ * \ingroup fat_dir
+ * Reads the next directory entry contained within a parent directory.
+ *
+ * \param[in] dd The descriptor of the parent directory from which to read the entry.
+ * \param[out] dir_entry Pointer to a buffer into which to write the directory entry information.
+ * \returns 0 on failure, 1 on success.
+ * \see fat_reset_dir
+ */
+uint8_t fat_read_dir(struct fat_dir_struct* dd, struct fat_dir_entry_struct* dir_entry)
+{
+    if(!dd || !dir_entry)
+        return 0;
+
+    /* get current position of directory handle */
+    struct fat_fs_struct* fs = dd->fs;
+    const struct fat_header_struct* header = &fs->header;
+    uint16_t cluster_size = header->cluster_size;
+    cluster_t cluster_num = dd->entry_cluster;
+    uint16_t cluster_offset = dd->entry_offset;
+    struct fat_read_dir_callback_arg arg;
+
+    /* reset directory entry */
+    memset(dir_entry, 0, sizeof(*dir_entry));
+
+    /* reset callback arguments */
+    memset(&arg, 0, sizeof(arg));
+    arg.dir_entry = dir_entry;
+
+    /* check if we read from the root directory */
+    if(cluster_num == 0)
+    {
+#if FAT_FAT32_SUPPORT
+        if(fs->partition->type == PARTITION_TYPE_FAT32)
+            cluster_num = header->root_dir_cluster;
+        else
+#endif
+            cluster_size = header->cluster_zero_offset - header->root_dir_offset;
+    }
+
+    /* read entries */
+    uint8_t buffer[32];
+    while(!arg.finished)
+    {
+        /* read directory entries up to the cluster border */
+        uint16_t cluster_left = cluster_size - cluster_offset;
+        uint32_t pos = cluster_offset;
+        if(cluster_num == 0)
+            pos += header->root_dir_offset;
+        else
+            pos += fat_cluster_offset(fs, cluster_num);
+
+        arg.bytes_read = 0;
+        if(!fs->partition->device_read_interval(pos,
+                                                buffer,
+                                                sizeof(buffer),
+                                                cluster_left,
+                                                fat_dir_entry_read_callback,
+                                                &arg)
+          )
+            return 0;
+
+        cluster_offset += arg.bytes_read;
+
+        if(cluster_offset >= cluster_size)
+        {
+            /* we reached the cluster border and switch to the next cluster */
+            cluster_offset = 0;
+
+            /* get number of next cluster */
+            if(!(cluster_num = fat_get_next_cluster(fs, cluster_num)))
+            {
+                /* directory entry not found, reset directory handle */
+                cluster_num = dd->dir_entry.cluster;
+                break;
+            }
+        }
+    }
+
+    dd->entry_cluster = cluster_num;
+    dd->entry_offset = cluster_offset;
+
+    return dir_entry->long_name[0] != '\0' ? 1 : 0;
+}
+
+/**
+ * \ingroup fat_dir
+ * Resets a directory handle.
+ *
+ * Resets the directory handle such that reading restarts
+ * with the first directory entry.
+ *
+ * \param[in] dd The directory handle to reset.
+ * \returns 0 on failure, 1 on success.
+ * \see fat_read_dir
+ */
+uint8_t fat_reset_dir(struct fat_dir_struct* dd)
+{
+    if(!dd)
+        return 0;
+
+    dd->entry_cluster = dd->dir_entry.cluster;
+    dd->entry_offset = 0;
+    return 1;
+}
+
+/**
+ * \ingroup fat_fs
+ * Callback function for reading a directory entry.
+ */
+uint8_t fat_dir_entry_read_callback(uint8_t* buffer, offset_t offset, void* p)
+{
+    struct fat_read_dir_callback_arg* arg = p;
+    struct fat_dir_entry_struct* dir_entry = arg->dir_entry;
+
+    arg->bytes_read += 32;
+
+    /* skip deleted or empty entries */
+    if(buffer[0] == FAT_DIRENTRY_DELETED || !buffer[0])
+        return 1;
+
+    if(!dir_entry->entry_offset)
+        dir_entry->entry_offset = offset;
+    
+    switch(fat_interpret_dir_entry(dir_entry, buffer))
+    {
+        case 0: /* failure */
+        {
+            return 0;
+        }
+        case 1: /* buffer successfully parsed, continue */
+        {
+            return 1;
+        }
+        case 2: /* directory entry complete, finish */
+        {
+            arg->finished = 1;
+            return 0;
+        }
+    }
+
+    return 0;
+}
+
+/**
+ * \ingroup fat_fs
+ * Interprets a raw directory entry and puts the contained
+ * information into the directory entry.
+ * 
+ * For a single file there may exist multiple directory
+ * entries. All except the last one are lfn entries, which
+ * contain parts of the long filename. The last directory
+ * entry is a traditional 8.3 style one. It contains all
+ * other information like size, cluster, date and time.
+ * 
+ * \param[in,out] dir_entry The directory entry to fill.
+ * \param[in] raw_entry A pointer to 32 bytes of raw data.
+ * \returns 0 on failure, 1 on success and 2 if the
+ *          directory entry is complete.
+ */
+uint8_t fat_interpret_dir_entry(struct fat_dir_entry_struct* dir_entry, const uint8_t* raw_entry)
+{
+    if(!dir_entry || !raw_entry || !raw_entry[0])
+        return 0;
+
+    char* long_name = dir_entry->long_name;
+    if(raw_entry[11] == 0x0f)
+    {
+        /* Lfn supports unicode, but we do not, for now.
+         * So we assume pure ascii and read only every
+         * second byte.
+         */
+        uint16_t char_offset = ((raw_entry[0] & 0x3f) - 1) * 13;
+        const uint8_t char_mapping[] = { 1, 3, 5, 7, 9, 14, 16, 18, 20, 22, 24, 28, 30 };
+        for(i = 0; i <= 12 && char_offset + i < sizeof(dir_entry->long_name) - 1; ++i)
+            long_name[char_offset + i] = raw_entry[char_mapping[i]];
+
+        return 1;
+    }
+    else
+    {
+        /* if we do not have a long name, take the short one */
+        if(long_name[0] == '\0')
+        {
+            uint8_t i;
+            for(i = 0; i < 8; ++i)
+            {
+                if(raw_entry[i] == ' ')
+                    break;
+                long_name[i] = raw_entry[i];
+
+                /* Windows NT and later versions do not store LFN entries
+                 * for 8.3 names which have a lowercase basename, extension
+                 * or both when everything else is uppercase. They use two
+                 * extra bits to signal a lowercase basename or extension.
+                 */
+                if((raw_entry[12] & 0x08) && raw_entry[i] >= 'A' && raw_entry[i] <= 'Z')
+                    long_name[i] += 'a' - 'A';
+            }
+            if(long_name[0] == 0x05)
+                long_name[0] = (char) FAT_DIRENTRY_DELETED;
+
+            if(raw_entry[8] != ' ')
+            {
+                long_name[i++] = '.';
+
+                uint8_t j = 8;
+                for(; j < 11; ++j)
+                {
+                    if(raw_entry[j] == ' ')
+                        break;
+                    long_name[i] = raw_entry[j];
+
+                    /* See above for the lowercase 8.3 name handling of
+                     * Windows NT and later.
+                     */
+                    if((raw_entry[12] & 0x10) && raw_entry[j] >= 'A' && raw_entry[j] <= 'Z')
+                        long_name[i] += 'a' - 'A';
+
+                    ++i;
+                }
+            } 
+
+            long_name[i] = '\0';
+        }
+        
+        /* extract properties of file and store them within the structure */
+        dir_entry->attributes = raw_entry[11];
+        dir_entry->cluster = ltoh16(*((uint16_t*) &raw_entry[26]));
+#if FAT_FAT32_SUPPORT
+        dir_entry->cluster |= ((cluster_t) ltoh16(*((uint16_t*) &raw_entry[20]))) << 16;
+#endif
+        dir_entry->file_size = ltoh32(*((uint32_t*) &raw_entry[28]));
+
+#if FAT_DATETIME_SUPPORT
+        dir_entry->modification_time = ltoh16(*((uint16_t*) &raw_entry[22]));
+        dir_entry->modification_date = ltoh16(*((uint16_t*) &raw_entry[24]));
+#endif
+
+        return 2;
+    }
+}
+
+#if  FAT_WRITE_SUPPORT
+/**
+ * \ingroup fat_fs
+ * Searches for space where to store a directory entry.
+ *
+ * \param[in] fs The filesystem on which to operate.
+ * \param[in] parent The directory in which to search.
+ * \param[in] dir_entry The directory entry for which to search space.
+ * \returns 0 on failure, a device offset on success.
+ */
+offset_t fat_find_offset_for_dir_entry(const struct fat_fs_struct* fs, const struct fat_dir_struct* parent, const struct fat_dir_entry_struct* dir_entry)
+{
+    if(!fs || !dir_entry)
+        return 0;
+
+    /* search for a place where to write the directory entry to disk */
+    uint8_t free_dir_entries_needed = (strlen(dir_entry->long_name) + 12) / 13 + 1;
+    uint8_t free_dir_entries_found = 0;
+    cluster_t cluster_num = parent->dir_entry.cluster;
+    offset_t dir_entry_offset = 0;
+    offset_t offset = 0;
+    offset_t offset_to = 0;
+#if FAT_FAT32_SUPPORT
+    uint8_t is_fat32 = (fs->partition->type == PARTITION_TYPE_FAT32);
+#endif
+
+    if(cluster_num == 0)
+    {
+#if FAT_FAT32_SUPPORT
+        if(is_fat32)
+        {
+            cluster_num = fs->header.root_dir_cluster;
+        }
+        else
+#endif
+        {
+            /* we read/write from the root directory entry */
+            offset = fs->header.root_dir_offset;
+            offset_to = fs->header.cluster_zero_offset;
+            dir_entry_offset = offset;
+        }
+    }
+    
+    while(1)
+    {
+        if(offset == offset_to)
+        {
+            if(cluster_num == 0)
+                /* We iterated through the whole root directory and
+                 * could not find enough space for the directory entry.
+                 */
+                return 0;
+
+            if(offset)
+            {
+                /* We reached a cluster boundary and have to
+                 * switch to the next cluster.
+                 */
+
+                cluster_t cluster_next = fat_get_next_cluster(fs, cluster_num);
+                if(!cluster_next)
+                {
+                    cluster_next = fat_append_clusters(fs, cluster_num, 1);
+                    if(!cluster_next)
+                        return 0;
+
+                    /* we appended a new cluster and know it is free */
+                    dir_entry_offset = fs->header.cluster_zero_offset +
+                                       (offset_t) (cluster_next - 2) * fs->header.cluster_size;
+
+                    /* clear cluster to avoid garbage directory entries */
+                    fat_clear_cluster(fs, cluster_next);
+
+                    break;
+                }
+                cluster_num = cluster_next;
+            }
+
+            offset = fat_cluster_offset(fs, cluster_num);
+            offset_to = offset + fs->header.cluster_size;
+            dir_entry_offset = offset;
+            free_dir_entries_found = 0;
+        }
+        
+        /* read next lfn or 8.3 entry */
+        uint8_t first_char;
+        if(!fs->partition->device_read(offset, &first_char, sizeof(first_char)))
+            return 0;
+
+        /* check if we found a free directory entry */
+        if(first_char == FAT_DIRENTRY_DELETED || !first_char)
+        {
+            /* check if we have the needed number of available entries */
+            ++free_dir_entries_found;
+            if(free_dir_entries_found >= free_dir_entries_needed)
+                break;
+
+            offset += 32;
+        }
+        else
+        {
+            offset += 32;
+            dir_entry_offset = offset;
+            free_dir_entries_found = 0;
+        }
+    }
+
+    return dir_entry_offset;
+}
+#endif
+
+#if  FAT_WRITE_SUPPORT
+/**
+ * \ingroup fat_fs
+ * Writes a directory entry to disk.
+ *
+ * \note The file name is not checked for invalid characters.
+ *
+ * \note The generation of the short 8.3 file name is quite
+ * simple. The first eight characters are used for the filename.
+ * The extension, if any, is made up of the first three characters
+ * following the last dot within the long filename. If the
+ * filename (without the extension) is longer than eight characters,
+ * the lower byte of the cluster number replaces the last two
+ * characters to avoid name clashes. In any other case, it is your
+ * responsibility to avoid name clashes.
+ *
+ * \param[in] fs The filesystem on which to operate.
+ * \param[in] dir_entry The directory entry to write.
+ * \returns 0 on failure, 1 on success.
+ */
+uint8_t fat_write_dir_entry(const struct fat_fs_struct* fs, struct fat_dir_entry_struct* dir_entry)
+{
+    if(!fs || !dir_entry)
+        return 0;
+    
+#if FAT_DATETIME_SUPPORT
+    {
+        uint16_t year;
+        uint8_t month;
+        uint8_t day;
+        uint8_t hour;
+        uint8_t min;
+        uint8_t sec;
+
+        fat_get_datetime(&year, &month, &day, &hour, &min, &sec);
+        fat_set_file_modification_date(dir_entry, year, month, day);
+        fat_set_file_modification_time(dir_entry, hour, min, sec);
+    }
+#endif
+
+    device_write_t device_write = fs->partition->device_write;
+    offset_t offset = dir_entry->entry_offset;
+    const char* name = dir_entry->long_name;
+    uint8_t name_len = strlen(name);
+    uint8_t lfn_entry_count = (name_len + 12) / 13;
+    uint8_t buffer[32];
+
+    /* write 8.3 entry */
+
+    /* generate 8.3 file name */
+    memset(&buffer[0], ' ', 11);
+    char* name_ext = strrchr(name, '.');
+    if(name_ext && *++name_ext)
+    {
+        uint8_t name_ext_len = strlen(name_ext);
+        name_len -= name_ext_len + 1;
+
+        if(name_ext_len > 3)
+            name_ext_len = 3;
+        
+        memcpy(&buffer[8], name_ext, name_ext_len);
+    }
+    
+    if(name_len <= 8)
+    {
+        memcpy(buffer, name, name_len);
+
+        /* For now, we create lfn entries for all files,
+         * except the "." and ".." directory references.
+         * This is to avoid difficulties with capitalization,
+         * as 8.3 filenames allow uppercase letters only.
+         *
+         * Theoretically it would be possible to leave
+         * the 8.3 entry alone if the basename and the
+         * extension have no mixed capitalization.
+         */
+        if(name[0] == '.' &&
+           ((name[1] == '.' && name[2] == '\0') ||
+            name[1] == '\0')
+          )
+            lfn_entry_count = 0;
+    }
+    else
+    {
+        memcpy(buffer, name, 8);
+
+        /* Minimize 8.3 name clashes by appending
+         * the lower byte of the cluster number.
+         */
+        uint8_t num = dir_entry->cluster & 0xff;
+
+        buffer[6] = (num < 0xa0) ? ('0' + (num >> 4)) : ('a' + (num >> 4));
+        num &= 0x0f;
+        buffer[7] = (num < 0x0a) ? ('0' + num) : ('a' + num);
+    }
+    if(buffer[0] == FAT_DIRENTRY_DELETED)
+        buffer[0] = 0x05;
+
+    /* fill directory entry buffer */
+    memset(&buffer[11], 0, sizeof(buffer) - 11);
+    buffer[0x0b] = dir_entry->attributes;
+#if FAT_DATETIME_SUPPORT
+    *((uint16_t*) &buffer[0x16]) = htol16(dir_entry->modification_time);
+    *((uint16_t*) &buffer[0x18]) = htol16(dir_entry->modification_date);
+#endif
+#if FAT_FAT32_SUPPORT
+    *((uint16_t*) &buffer[0x14]) = htol16((uint16_t) (dir_entry->cluster >> 16));
+#endif
+    *((uint16_t*) &buffer[0x1a]) = htol16(dir_entry->cluster);
+    *((uint32_t*) &buffer[0x1c]) = htol32(dir_entry->file_size);
+
+    /* write to disk */
+    if(!device_write(offset + (uint16_t) lfn_entry_count * 32, buffer, sizeof(buffer)))
+        return 0;
+    
+    /* calculate checksum of 8.3 name */
+    uint8_t checksum = buffer[0];
+    for(i = 1; i < 11; ++i)
+        checksum = ((checksum >> 1) | (checksum << 7)) + buffer[i];
+    
+    /* write lfn entries */
+       uint8_t lfn_entry=0;
+    for(lfn_entry = lfn_entry_count; lfn_entry > 0; --lfn_entry)
+    {
+        memset(buffer, 0xff, sizeof(buffer));
+        
+        /* set file name */
+        const char* long_name_curr = name + (lfn_entry - 1) * 13;
+        uint8_t i = 1;
+        while(i < 0x1f)
+        {
+            buffer[i++] = *long_name_curr;
+            buffer[i++] = 0;
+
+            switch(i)
+            {
+                case 0x0b:
+                    i = 0x0e;
+                    break;
+                case 0x1a:
+                    i = 0x1c;
+                    break;
+            }
+
+            if(!*long_name_curr++)
+                break;
+        }
+        
+        /* set index of lfn entry */
+        buffer[0x00] = lfn_entry;
+        if(lfn_entry == lfn_entry_count)
+            buffer[0x00] |= FAT_DIRENTRY_LFNLAST;
+
+        /* mark as lfn entry */
+        buffer[0x0b] = 0x0f;
+
+        /* set 8.3 checksum */
+        buffer[0x0d] = checksum;
+
+        /* clear reserved bytes */
+        buffer[0x0c] = 0;
+        buffer[0x1a] = 0;
+        buffer[0x1b] = 0;
+
+        /* write entry */
+        device_write(offset, buffer, sizeof(buffer));
+    
+        offset += sizeof(buffer);
+    }
+    
+    return 1;
+}
+#endif
+
+/**
+ * \ingroup fat_file
+ * Creates a file.
+ *
+ * Creates a file and obtains the directory entry of the
+ * new file. If the file to create already exists, the
+ * directory entry of the existing file will be returned
+ * within the dir_entry parameter.
+ *
+ * \note The file name is not checked for invalid characters.
+ *
+ * \note The generation of the short 8.3 file name is quite
+ * simple. The first eight characters are used for the filename.
+ * The extension, if any, is made up of the first three characters
+ * following the last dot within the long filename. If the
+ * filename (without the extension) is longer than eight characters,
+ * the lower byte of the cluster number replaces the last two
+ * characters to avoid name clashes. In any other case, it is your
+ * responsibility to avoid name clashes.
+ *
+ * \param[in] parent The handle of the directory in which to create the file.
+ * \param[in] file The name of the file to create.
+ * \param[out] dir_entry The directory entry to fill for the new file.
+ * \returns 0 on failure, 1 on success.
+ * \see fat_delete_file
+ */
+uint8_t fat_create_file(struct fat_dir_struct* parent, const char* file, struct fat_dir_entry_struct* dir_entry)
+{
+    if(!parent || !file || !file[0] || !dir_entry)
+        return 0;
+
+    /* check if the file already exists */
+    while(1)
+    {
+        if(!fat_read_dir(parent, dir_entry))
+            break;
+
+        if(strcmp(file, dir_entry->long_name) == 0)
+        {
+            fat_reset_dir(parent);
+            return 0;
+        }
+    }
+
+    struct fat_fs_struct* fs = parent->fs;
+
+    /* prepare directory entry with values already known */
+    memset(dir_entry, 0, sizeof(*dir_entry));
+    strncpy(dir_entry->long_name, file, sizeof(dir_entry->long_name) - 1);
+
+    /* find place where to store directory entry */
+    if(!(dir_entry->entry_offset = fat_find_offset_for_dir_entry(fs, parent, dir_entry)))
+        return 0;
+    
+    /* write directory entry to disk */
+    if(!fat_write_dir_entry(fs, dir_entry))
+        return 0;
+    
+    return 1;
+}
+
+/**
+ * \ingroup fat_file
+ * Deletes a file or directory.
+ *
+ * If a directory is deleted without first deleting its
+ * subdirectories and files, disk space occupied by these
+ * files will get wasted as there is no chance to release
+ * it and mark it as free.
+ * 
+ * \param[in] fs The filesystem on which to operate.
+ * \param[in] dir_entry The directory entry of the file to delete.
+ * \returns 0 on failure, 1 on success.
+ * \see fat_create_file
+ */
+uint8_t fat_delete_file(struct fat_fs_struct* fs, struct fat_dir_entry_struct* dir_entry)
+{
+    if(!fs || !dir_entry)
+        return 0;
+
+    /* get offset of the file's directory entry */
+    offset_t dir_entry_offset = dir_entry->entry_offset;
+    if(!dir_entry_offset)
+        return 0;
+
+    uint8_t buffer[12];
+    while(1)
+    {
+        /* read directory entry */
+        if(!fs->partition->device_read(dir_entry_offset, buffer, sizeof(buffer)))
+            return 0;
+        
+        /* mark the directory entry as deleted */
+        buffer[0] = FAT_DIRENTRY_DELETED;
+        
+        /* write back entry */
+        if(!fs->partition->device_write(dir_entry_offset, buffer, sizeof(buffer)))
+            return 0;
+
+        /* check if we deleted the whole entry */
+        if(buffer[11] != 0x0f)
+            break;
+
+        dir_entry_offset += 32;
+    }
+
+    /* We deleted the directory entry. The next thing to do is
+     * marking all occupied clusters as free.
+     */
+    return (dir_entry->cluster == 0 || fat_free_clusters(fs, dir_entry->cluster));
+}
+
+/**
+ * \ingroup fat_dir
+ * Creates a directory.
+ *
+ * Creates a directory and obtains its directory entry.
+ * If the directory to create already exists, its
+ * directory entry will be returned within the dir_entry
+ * parameter.
+ *
+ * \note The notes which apply to fat_create_file also
+ * apply to this function.
+ *
+ * \param[in] parent The handle of the parent directory of the new directory.
+ * \param[in] dir The name of the directory to create.
+ * \param[out] dir_entry The directory entry to fill for the new directory.
+ * \returns 0 on failure, 1 on success.
+ * \see fat_delete_dir
+ */
+uint8_t fat_create_dir(struct fat_dir_struct* parent, const char* dir, struct fat_dir_entry_struct* dir_entry)
+{
+    if(!parent || !dir || !dir[0] || !dir_entry)
+        return 0;
+
+    /* check if the file or directory already exists */
+    while(fat_read_dir(parent, dir_entry))
+    {
+        if(strcmp(dir, dir_entry->long_name) == 0)
+        {
+            fat_reset_dir(parent);
+            return 0;
+        }
+    }
+
+    struct fat_fs_struct* fs = parent->fs;
+
+    /* allocate cluster which will hold directory entries */
+    cluster_t dir_cluster = fat_append_clusters(fs, 0, 1);
+    if(!dir_cluster)
+        return 0;
+
+    /* clear cluster to prevent bogus directory entries */
+    fat_clear_cluster(fs, dir_cluster);
+    
+    memset(dir_entry, 0, sizeof(*dir_entry));
+    dir_entry->attributes = FAT_ATTRIB_DIR;
+
+    /* create "." directory self reference */
+    dir_entry->entry_offset = fs->header.cluster_zero_offset +
+                              (offset_t) (dir_cluster - 2) * fs->header.cluster_size;
+    dir_entry->long_name[0] = '.';
+    dir_entry->cluster = dir_cluster;
+    if(!fat_write_dir_entry(fs, dir_entry))
+    {
+        fat_free_clusters(fs, dir_cluster);
+        return 0;
+    }
+
+    /* create ".." parent directory reference */
+    dir_entry->entry_offset += 32;
+    dir_entry->long_name[1] = '.';
+    dir_entry->cluster = parent->dir_entry.cluster;
+    if(!fat_write_dir_entry(fs, dir_entry))
+    {
+        fat_free_clusters(fs, dir_cluster);
+        return 0;
+    }
+
+    /* fill directory entry */
+    strncpy(dir_entry->long_name, dir, sizeof(dir_entry->long_name) - 1);
+    dir_entry->cluster = dir_cluster;
+
+    /* find place where to store directory entry */
+    if(!(dir_entry->entry_offset = fat_find_offset_for_dir_entry(fs, parent, dir_entry)))
+    {
+        fat_free_clusters(fs, dir_cluster);
+        return 0;
+    }
+
+    /* write directory to disk */
+    if(!fat_write_dir_entry(fs, dir_entry))
+    {
+        fat_free_clusters(fs, dir_cluster);
+        return 0;
+    }
+
+    return 1;
+}
+
+/**
+ * \ingroup fat_dir
+ * Deletes a directory.
+ *
+ * This is just a synonym for fat_delete_file().
+ * If a directory is deleted without first deleting its
+ * subdirectories and files, disk space occupied by these
+ * files will get wasted as there is no chance to release
+ * it and mark it as free.
+ * 
+ * \param[in] fs The filesystem on which to operate.
+ * \param[in] dir_entry The directory entry of the directory to delete.
+ * \returns 0 on failure, 1 on success.
+ * \see fat_create_dir
+ */
+#ifdef DOXYGEN
+uint8_t fat_delete_dir(struct fat_fs_struct* fs, struct fat_dir_entry_struct* dir_entry);
+#endif
+
+#if  FAT_DATETIME_SUPPORT
+/**
+ * \ingroup fat_file
+ * Returns the modification date of a file.
+ *
+ * \param[in] dir_entry The directory entry of which to return the modification date.
+ * \param[out] year The year the file was last modified.
+ * \param[out] month The month the file was last modified.
+ * \param[out] day The day the file was last modified.
+ */
+void fat_get_file_modification_date(const struct fat_dir_entry_struct* dir_entry, uint16_t* year, uint8_t* month, uint8_t* day)
+{
+    if(!dir_entry)
+        return;
+
+    *year = 1980 + ((dir_entry->modification_date >> 9) & 0x7f);
+    *month = (dir_entry->modification_date >> 5) & 0x0f;
+    *day = (dir_entry->modification_date >> 0) & 0x1f;
+}
+#endif
+
+#if  FAT_DATETIME_SUPPORT
+/**
+ * \ingroup fat_file
+ * Returns the modification time of a file.
+ *
+ * \param[in] dir_entry The directory entry of which to return the modification time.
+ * \param[out] hour The hour the file was last modified.
+ * \param[out] min The min the file was last modified.
+ * \param[out] sec The sec the file was last modified.
+ */
+void fat_get_file_modification_time(const struct fat_dir_entry_struct* dir_entry, uint8_t* hour, uint8_t* min, uint8_t* sec)
+{
+    if(!dir_entry)
+        return;
+
+    *hour = (dir_entry->modification_time >> 11) & 0x1f;
+    *min = (dir_entry->modification_time >> 5) & 0x3f;
+    *sec = ((dir_entry->modification_time >> 0) & 0x1f) * 2;
+}
+#endif
+
+#if  (FAT_WRITE_SUPPORT && FAT_DATETIME_SUPPORT)
+/**
+ * \ingroup fat_file
+ * Sets the modification time of a date.
+ *
+ * \param[in] dir_entry The directory entry for which to set the modification date.
+ * \param[in] year The year the file was last modified.
+ * \param[in] month The month the file was last modified.
+ * \param[in] day The day the file was last modified.
+ */
+void fat_set_file_modification_date(struct fat_dir_entry_struct* dir_entry, uint16_t year, uint8_t month, uint8_t day)
+{
+    if(!dir_entry)
+        return;
+
+    dir_entry->modification_date =
+        ((year - 1980) << 9) |
+        ((uint16_t) month << 5) |
+        ((uint16_t) day << 0);
+}
+#endif
+
+#if  (FAT_WRITE_SUPPORT && FAT_DATETIME_SUPPORT)
+/**
+ * \ingroup fat_file
+ * Sets the modification time of a file.
+ *
+ * \param[in] dir_entry The directory entry for which to set the modification time.
+ * \param[in] hour The year the file was last modified.
+ * \param[in] min The month the file was last modified.
+ * \param[in] sec The day the file was last modified.
+ */
+void fat_set_file_modification_time(struct fat_dir_entry_struct* dir_entry, uint8_t hour, uint8_t min, uint8_t sec)
+{
+    if(!dir_entry)
+        return;
+
+    dir_entry->modification_time =
+        ((uint16_t) hour << 11) |
+        ((uint16_t) min << 5) |
+        ((uint16_t) sec >> 1) ;
+}
+#endif
+
+/**
+ * \ingroup fat_fs
+ * Returns the amount of total storage capacity of the filesystem in bytes.
+ *
+ * \param[in] fs The filesystem on which to operate.
+ * \returns 0 on failure, the filesystem size in bytes otherwise.
+ */
+offset_t fat_get_fs_size(const struct fat_fs_struct* fs)
+{
+    if(!fs)
+        return 0;
+
+#if FAT_FAT32_SUPPORT
+    if(fs->partition->type == PARTITION_TYPE_FAT32)
+        return (offset_t) (fs->header.fat_size / 4 - 2) * fs->header.cluster_size;
+    else
+#endif
+        return (offset_t) (fs->header.fat_size / 2 - 2) * fs->header.cluster_size;
+}
+
+/**
+ * \ingroup fat_fs
+ * Returns the amount of free storage capacity on the filesystem in bytes.
+ *
+ * \note As the FAT filesystem is cluster based, this function does not
+ *       return continuous values but multiples of the cluster size.
+ *
+ * \param[in] fs The filesystem on which to operate.
+ * \returns 0 on failure, the free filesystem space in bytes otherwise.
+ */
+offset_t fat_get_fs_free(const struct fat_fs_struct* fs)
+{
+    if(!fs)
+        return 0;
+
+    uint8_t fat[32];
+    struct fat_usage_count_callback_arg count_arg;
+    count_arg.cluster_count = 0;
+    count_arg.buffer_size = sizeof(fat);
+
+    offset_t fat_offset = fs->header.fat_offset;
+    uint32_t fat_size = fs->header.fat_size;
+    while(fat_size > 0)
+    {
+        uintptr_t length = UINTPTR_MAX - 1;
+        if(fat_size < length)
+            length = fat_size;
+
+        if(!fs->partition->device_read_interval(fat_offset,
+                                                fat,
+                                                sizeof(fat),
+                                                length,
+#if FAT_FAT32_SUPPORT
+                                                (fs->partition->type == PARTITION_TYPE_FAT16) ?
+                                                    fat_get_fs_free_16_callback :
+                                                    fat_get_fs_free_32_callback,
+#else
+                                                fat_get_fs_free_16_callback,
+#endif
+                                                &count_arg
+                                               )
+          )
+            return 0;
+
+        fat_offset += length;
+        fat_size -= length;
+    }
+
+    return (offset_t) count_arg.cluster_count * fs->header.cluster_size;
+}
+
+/**
+ * \ingroup fat_fs
+ * Callback function used for counting free clusters in a FAT.
+ */
+uint8_t fat_get_fs_free_16_callback(uint8_t* buffer, offset_t offset, void* p)
+{
+    struct fat_usage_count_callback_arg* count_arg = (struct fat_usage_count_callback_arg*) p;
+    uintptr_t buffer_size = count_arg->buffer_size;
+
+       uintptr_t j=0;
+    for(j = 0; i < buffer_size; j += 2, buffer += 2)
+    {
+        uint16_t cluster = *((uint16_t*) &buffer[0]);
+        if(cluster == HTOL16(FAT16_CLUSTER_FREE))
+            ++(count_arg->cluster_count);
+    }
+
+    return 1;
+}
+
+#if  FAT_FAT32_SUPPORT
+/**
+ * \ingroup fat_fs
+ * Callback function used for counting free clusters in a FAT32.
+ */
+uint8_t fat_get_fs_free_32_callback(uint8_t* buffer, offset_t offset, void* p)
+{
+    struct fat_usage_count_callback_arg* count_arg = (struct fat_usage_count_callback_arg*) p;
+    uintptr_t buffer_size = count_arg->buffer_size;
+
+    for(i = 0; i < buffer_size; i += 4, buffer += 4)
+    {
+        uint32_t cluster = *((uint32_t*) &buffer[0]);
+        if(cluster == HTOL32(FAT32_CLUSTER_FREE))
+            ++(count_arg->cluster_count);
+    }
+
+    return 1;
+}
+#endif
+
diff --git a/FAT16/fat.h b/FAT16/fat.h
new file mode 100644 (file)
index 0000000..846dccc
--- /dev/null
@@ -0,0 +1,129 @@
+
+/*
+ * Copyright (c) 2006-2009 by Roland Riegel <feedback@roland-riegel.de>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either the GNU General Public License version 2
+ * or the GNU Lesser General Public License version 2.1, both as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef FAT_H
+#define FAT_H
+
+#include <stdint.h>
+#include "fat_config.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * \addtogroup fat
+ *
+ * @{
+ */
+/**
+ * \file
+ * FAT header (license: GPLv2 or LGPLv2.1)
+ *
+ * \author Roland Riegel
+ */
+
+/**
+ * \addtogroup fat_file
+ * @{
+ */
+
+/** The file is read-only. */
+#define FAT_ATTRIB_READONLY (1 << 0)
+/** The file is hidden. */
+#define FAT_ATTRIB_HIDDEN (1 << 1)
+/** The file is a system file. */
+#define FAT_ATTRIB_SYSTEM (1 << 2)
+/** The file is empty and has the volume label as its name. */
+#define FAT_ATTRIB_VOLUME (1 << 3)
+/** The file is a directory. */
+#define FAT_ATTRIB_DIR (1 << 4)
+/** The file has to be archived. */
+#define FAT_ATTRIB_ARCHIVE (1 << 5)
+
+/** The given offset is relative to the beginning of the file. */
+#define FAT_SEEK_SET 0
+/** The given offset is relative to the current read/write position. */
+#define FAT_SEEK_CUR 1
+/** The given offset is relative to the end of the file. */
+#define FAT_SEEK_END 2
+
+/**
+ * @}
+ */
+
+struct partition_struct;
+struct fat_fs_struct;
+struct fat_file_struct;
+struct fat_dir_struct;
+
+/**
+ * \ingroup fat_file
+ * Describes a directory entry.
+ */
+struct fat_dir_entry_struct
+{
+    /** The file's name, truncated to 31 characters. */
+    char long_name[32];
+    /** The file's attributes. Mask of the FAT_ATTRIB_* constants. */
+    uint8_t attributes;
+#if FAT_DATETIME_SUPPORT
+    /** Compressed representation of modification time. */
+    uint16_t modification_time;
+    /** Compressed representation of modification date. */
+    uint16_t modification_date;
+#endif
+    /** The cluster in which the file's first byte resides. */
+    cluster_t cluster;
+    /** The file's size. */
+    uint32_t file_size;
+    /** The total disk offset of this directory entry. */
+    offset_t entry_offset;
+};
+
+struct fat_fs_struct* fat_open(struct partition_struct* partition);
+void fat_close(struct fat_fs_struct* fs);
+
+struct fat_file_struct* fat_open_file(struct fat_fs_struct* fs, const struct fat_dir_entry_struct* dir_entry);
+void fat_close_file(struct fat_file_struct* fd);
+intptr_t fat_read_file(struct fat_file_struct* fd, uint8_t* buffer, uintptr_t buffer_len);
+intptr_t fat_write_file(struct fat_file_struct* fd, const uint8_t* buffer, uintptr_t buffer_len);
+uint8_t fat_seek_file(struct fat_file_struct* fd, int32_t* offset, uint8_t whence);
+uint8_t fat_resize_file(struct fat_file_struct* fd, uint32_t size);
+
+struct fat_dir_struct* fat_open_dir(struct fat_fs_struct* fs, const struct fat_dir_entry_struct* dir_entry);
+void fat_close_dir(struct fat_dir_struct* dd);
+uint8_t fat_read_dir(struct fat_dir_struct* dd, struct fat_dir_entry_struct* dir_entry);
+uint8_t fat_reset_dir(struct fat_dir_struct* dd);
+
+uint8_t fat_create_file(struct fat_dir_struct* parent, const char* file, struct fat_dir_entry_struct* dir_entry);
+uint8_t fat_delete_file(struct fat_fs_struct* fs, struct fat_dir_entry_struct* dir_entry);
+uint8_t fat_create_dir(struct fat_dir_struct* parent, const char* dir, struct fat_dir_entry_struct* dir_entry);
+#define fat_delete_dir fat_delete_file
+
+void fat_get_file_modification_date(const struct fat_dir_entry_struct* dir_entry, uint16_t* year, uint8_t* month, uint8_t* day);
+void fat_get_file_modification_time(const struct fat_dir_entry_struct* dir_entry, uint8_t* hour, uint8_t* min, uint8_t* sec);
+
+uint8_t fat_get_dir_entry_of_path(struct fat_fs_struct* fs, const char* path, struct fat_dir_entry_struct* dir_entry);
+
+offset_t fat_get_fs_size(const struct fat_fs_struct* fs);
+offset_t fat_get_fs_free(const struct fat_fs_struct* fs);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/FAT16/fat_config.h b/FAT16/fat_config.h
new file mode 100644 (file)
index 0000000..cb053a5
--- /dev/null
@@ -0,0 +1,111 @@
+
+/*
+ * Copyright (c) 2006-2009 by Roland Riegel <feedback@roland-riegel.de>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either the GNU General Public License version 2
+ * or the GNU Lesser General Public License version 2.1, both as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef FAT_CONFIG_H
+#define FAT_CONFIG_H
+
+#include <stdint.h>
+#include "sd_raw_config.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * \addtogroup fat
+ *
+ * @{
+ */
+/**
+ * \file
+ * FAT configuration (license: GPLv2 or LGPLv2.1)
+ */
+
+/**
+ * \ingroup fat_config
+ * Controls FAT write support.
+ *
+ * Set to 1 to enable FAT write support, set to 0 to disable it.
+ */
+#define FAT_WRITE_SUPPORT 1
+
+/**
+ * \ingroup fat_config
+ * Controls FAT date and time support.
+ * 
+ * Set to 1 to enable FAT date and time stamping support.
+ */
+#define FAT_DATETIME_SUPPORT 0
+
+/**
+ * \ingroup fat_config
+ * Controls FAT32 support.
+ *
+ * Set to 1 to enable FAT32 support.
+ */
+#define FAT_FAT32_SUPPORT SD_RAW_SDHC
+//#define FAT_FAT32_SUPPORT 1
+
+/**
+ * \ingroup fat_config
+ * Determines the function used for retrieving current date and time.
+ *
+ * Define this to the function call which shall be used to retrieve
+ * current date and time.
+ *
+ * \note Used only when FAT_DATETIME_SUPPORT is 1.
+ *
+ * \param[out] year Pointer to a \c uint16_t which receives the current year.
+ * \param[out] month Pointer to a \c uint8_t which receives the current month.
+ * \param[out] day Pointer to a \c uint8_t which receives the current day.
+ * \param[out] hour Pointer to a \c uint8_t which receives the current hour.
+ * \param[out] min Pointer to a \c uint8_t which receives the current minute.
+ * \param[out] sec Pointer to a \c uint8_t which receives the current sec.
+ */
+#define fat_get_datetime(year, month, day, hour, min, sec) \
+    get_datetime(year, month, day, hour, min, sec)
+/* forward declaration for the above */
+void get_datetime(uint16_t* year, uint8_t* month, uint8_t* day, uint8_t* hour, uint8_t* min, uint8_t* sec);
+
+/**
+ * \ingroup fat_config
+ * Maximum number of filesystem handles.
+ */
+#define FAT_FS_COUNT 1
+
+/**
+ * \ingroup fat_config
+ * Maximum number of file handles.
+ */
+#define FAT_FILE_COUNT 1
+
+/**
+ * \ingroup fat_config
+ * Maximum number of directory handles.
+ */
+#define FAT_DIR_COUNT 2
+
+/**
+ * @}
+ */
+
+#if FAT_FAT32_SUPPORT
+    typedef uint32_t cluster_t;
+#else
+    typedef uint16_t cluster_t;
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/FAT16/partition.c b/FAT16/partition.c
new file mode 100644 (file)
index 0000000..9f1d5b6
--- /dev/null
@@ -0,0 +1,160 @@
+
+/*
+ * Copyright (c) 2006-2009 by Roland Riegel <feedback@roland-riegel.de>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either the GNU General Public License version 2
+ * or the GNU Lesser General Public License version 2.1, both as
+ * published by the Free Software Foundation.
+ */
+
+#include "partition.h"
+#include "partition_config.h"
+#include "sd-reader_config.h"
+
+#include <string.h>
+
+#if USE_DYNAMIC_MEMORY
+    #include <stdlib.h>
+#endif
+
+/**
+ * \addtogroup partition Partition table support
+ *
+ * Support for reading partition tables and access to partitions.
+ *
+ * @{
+ */
+/**
+ * \file
+ * Partition table implementation (license: GPLv2 or LGPLv2.1)
+ *
+ * \author Roland Riegel
+ */
+
+/**
+ * \addtogroup partition_config Configuration of partition table support
+ * Preprocessor defines to configure the partition support.
+ */
+
+#if !USE_DYNAMIC_MEMORY
+static struct partition_struct partition_handles[PARTITION_COUNT];
+#endif
+
+/**
+ * Opens a partition.
+ *
+ * Opens a partition by its index number and returns a partition
+ * handle which describes the opened partition.
+ *
+ * \note This function does not support extended partitions.
+ *
+ * \param[in] device_read A function pointer which is used to read from the disk.
+ * \param[in] device_read_interval A function pointer which is used to read in constant intervals from the disk.
+ * \param[in] device_write A function pointer which is used to write to the disk.
+ * \param[in] device_write_interval A function pointer which is used to write a data stream to disk.
+ * \param[in] index The index of the partition which should be opened, range 0 to 3.
+ *                  A negative value is allowed as well. In this case, the partition opened is
+ *                  not checked for existance, begins at offset zero, has a length of zero
+ *                  and is of an unknown type. Use this in case you want to open the whole device
+ *                  as a single partition (e.g. for "super floppy" use).
+ * \returns 0 on failure, a partition descriptor on success.
+ * \see partition_close
+ */
+struct partition_struct* partition_open(device_read_t device_read, device_read_interval_t device_read_interval, device_write_t device_write, device_write_interval_t device_write_interval, int8_t index)
+{
+    struct partition_struct* new_partition = 0;
+    uint8_t buffer[0x10];
+
+    if(!device_read || !device_read_interval || index >= 4)
+        return 0;
+
+    if(index >= 0)
+    {
+        /* read specified partition table index */
+        if(!device_read(0x01be + index * 0x10, buffer, sizeof(buffer)))
+            return 0;
+
+        /* abort on empty partition entry */
+        if(buffer[4] == 0x00)
+            return 0;
+    }
+
+    /* allocate partition descriptor */
+#if USE_DYNAMIC_MEMORY
+    new_partition = malloc(sizeof(*new_partition));
+    if(!new_partition)
+        return 0;
+#else
+    new_partition = partition_handles;
+    uint8_t i;
+    for(i = 0; i < PARTITION_COUNT; ++i)
+    {
+        if(new_partition->type == PARTITION_TYPE_FREE)
+            break;
+
+        ++new_partition;
+    }
+    if(i >= PARTITION_COUNT)
+        return 0;
+#endif
+
+    memset(new_partition, 0, sizeof(*new_partition));
+
+    /* fill partition descriptor */
+    new_partition->device_read = device_read;
+    new_partition->device_read_interval = device_read_interval;
+    new_partition->device_write = device_write;
+    new_partition->device_write_interval = device_write_interval;
+
+    if(index >= 0)
+    {
+        new_partition->type = buffer[4];
+        new_partition->offset = ((uint32_t) buffer[8]) |
+                                ((uint32_t) buffer[9] << 8) |
+                                ((uint32_t) buffer[10] << 16) |
+                                ((uint32_t) buffer[11] << 24);
+        new_partition->length = ((uint32_t) buffer[12]) |
+                                ((uint32_t) buffer[13] << 8) |
+                                ((uint32_t) buffer[14] << 16) |
+                                ((uint32_t) buffer[15] << 24);
+    }
+    else
+    {
+        new_partition->type = 0xff;
+    }
+
+    return new_partition;
+}
+
+/**
+ * Closes a partition.
+ *
+ * This function destroys a partition descriptor which was
+ * previously obtained from a call to partition_open().
+ * When this function returns, the given descriptor will be
+ * invalid.
+ *
+ * \param[in] partition The partition descriptor to destroy.
+ * \returns 0 on failure, 1 on success.
+ * \see partition_open
+ */
+uint8_t partition_close(struct partition_struct* partition)
+{
+    if(!partition)
+        return 0;
+
+    /* destroy partition descriptor */
+#if USE_DYNAMIC_MEMORY
+    free(partition);
+#else
+    partition->type = PARTITION_TYPE_FREE;
+#endif
+
+    return 1;
+}
+
+/**
+ * @}
+ */
+
diff --git a/FAT16/partition.h b/FAT16/partition.h
new file mode 100644 (file)
index 0000000..433f1fe
--- /dev/null
@@ -0,0 +1,212 @@
+
+/*
+ * Copyright (c) 2006-2009 by Roland Riegel <feedback@roland-riegel.de>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either the GNU General Public License version 2
+ * or the GNU Lesser General Public License version 2.1, both as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef PARTITION_H
+#define PARTITION_H
+
+#include <stdint.h>
+#include "sd_raw_config.h"
+#include "partition_config.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * \addtogroup partition
+ *
+ * @{
+ */
+/**
+ * \file
+ * Partition table header (license: GPLv2 or LGPLv2.1)
+ *
+ * \author Roland Riegel
+ */
+
+/**
+ * The partition table entry is not used.
+ */
+#define PARTITION_TYPE_FREE 0x00
+/**
+ * The partition contains a FAT12 filesystem.
+ */
+#define PARTITION_TYPE_FAT12 0x01
+/**
+ * The partition contains a FAT16 filesystem with 32MB maximum.
+ */
+#define PARTITION_TYPE_FAT16_32MB 0x04
+/**
+ * The partition is an extended partition with its own partition table.
+ */
+#define PARTITION_TYPE_EXTENDED 0x05
+/**
+ * The partition contains a FAT16 filesystem.
+ */
+#define PARTITION_TYPE_FAT16 0x06
+/**
+ * The partition contains a FAT32 filesystem.
+ */
+#define PARTITION_TYPE_FAT32 0x0b
+/**
+ * The partition contains a FAT32 filesystem with LBA.
+ */
+#define PARTITION_TYPE_FAT32_LBA 0x0c
+/**
+ * The partition contains a FAT16 filesystem with LBA.
+ */
+#define PARTITION_TYPE_FAT16_LBA 0x0e
+/**
+ * The partition is an extended partition with LBA.
+ */
+#define PARTITION_TYPE_EXTENDED_LBA 0x0f
+/**
+ * The partition has an unknown type.
+ */
+#define PARTITION_TYPE_UNKNOWN 0xff
+
+/**
+ * A function pointer used to read from the partition.
+ *
+ * \param[in] offset The offset on the device where to start reading.
+ * \param[out] buffer The buffer into which to place the data.
+ * \param[in] length The count of bytes to read.
+ */
+typedef uint8_t (*device_read_t)(offset_t offset, uint8_t* buffer, uintptr_t length);
+/**
+ * A function pointer passed to a \c device_read_interval_t.
+ *
+ * \param[in] buffer The buffer which contains the data just read.
+ * \param[in] offset The offset from which the data in \c buffer was read.
+ * \param[in] p An opaque pointer.
+ * \see device_read_interval_t
+ */
+typedef uint8_t (*device_read_callback_t)(uint8_t* buffer, offset_t offset, void* p);
+/**
+ * A function pointer used to continuously read units of \c interval bytes
+ * and call a callback function.
+ *
+ * This function starts reading at the specified offset. Every \c interval bytes,
+ * it calls the callback function with the associated data buffer.
+ *
+ * By returning zero, the callback may stop reading.
+ *
+ * \param[in] offset Offset from which to start reading.
+ * \param[in] buffer Pointer to a buffer which is at least interval bytes in size.
+ * \param[in] interval Number of bytes to read before calling the callback function.
+ * \param[in] length Number of bytes to read altogether.
+ * \param[in] callback The function to call every interval bytes.
+ * \param[in] p An opaque pointer directly passed to the callback function.
+ * \returns 0 on failure, 1 on success
+ * \see device_read_t
+ */
+typedef uint8_t (*device_read_interval_t)(offset_t offset, uint8_t* buffer, uintptr_t interval, uintptr_t length, device_read_callback_t callback, void* p);
+/**
+ * A function pointer used to write to the partition.
+ *
+ * \param[in] offset The offset on the device where to start writing.
+ * \param[in] buffer The buffer which to write.
+ * \param[in] length The count of bytes to write.
+ */
+typedef uint8_t (*device_write_t)(offset_t offset, const uint8_t* buffer, uintptr_t length);
+/**
+ * A function pointer passed to a \c device_write_interval_t.
+ *
+ * \param[in] buffer The buffer which receives the data to write.
+ * \param[in] offset The offset to which the data in \c buffer will be written.
+ * \param[in] p An opaque pointer.
+ * \returns The number of bytes put into \c buffer
+ * \see device_write_interval_t
+ */
+typedef uintptr_t (*device_write_callback_t)(uint8_t* buffer, offset_t offset, void* p);
+/**
+ * A function pointer used to continuously write a data stream obtained from
+ * a callback function.
+ *
+ * This function starts writing at the specified offset. To obtain the
+ * next bytes to write, it calls the callback function. The callback fills the
+ * provided data buffer and returns the number of bytes it has put into the buffer.
+ *
+ * By returning zero, the callback may stop writing.
+ *
+ * \param[in] offset Offset where to start writing.
+ * \param[in] buffer Pointer to a buffer which is used for the callback function.
+ * \param[in] length Number of bytes to write in total. May be zero for endless writes.
+ * \param[in] callback The function used to obtain the bytes to write.
+ * \param[in] p An opaque pointer directly passed to the callback function.
+ * \returns 0 on failure, 1 on success
+ * \see device_write_t
+ */
+typedef uint8_t (*device_write_interval_t)(offset_t offset, uint8_t* buffer, uintptr_t length, device_write_callback_t callback, void* p);
+
+/**
+ * Describes a partition.
+ */
+struct partition_struct
+{
+    /**
+     * The function which reads data from the partition.
+     *
+     * \note The offset given to this function is relative to the whole disk,
+     *       not to the start of the partition.
+     */
+    device_read_t device_read;
+    /**
+     * The function which repeatedly reads a constant amount of data from the partition.
+     *
+     * \note The offset given to this function is relative to the whole disk,
+     *       not to the start of the partition.
+     */
+    device_read_interval_t device_read_interval;
+    /**
+     * The function which writes data to the partition.
+     *
+     * \note The offset given to this function is relative to the whole disk,
+     *       not to the start of the partition.
+     */
+    device_write_t device_write;
+    /**
+     * The function which repeatedly writes data to the partition.
+     *
+     * \note The offset given to this function is relative to the whole disk,
+     *       not to the start of the partition.
+     */
+    device_write_interval_t device_write_interval;
+
+    /**
+     * The type of the partition.
+     *
+     * Compare this value to the PARTITION_TYPE_* constants.
+     */
+    uint8_t type;
+    /**
+     * The offset in blocks on the disk where this partition starts.
+     */
+    uint32_t offset;
+    /**
+     * The length in blocks of this partition.
+     */
+    uint32_t length;
+};
+
+struct partition_struct* partition_open(device_read_t device_read, device_read_interval_t device_read_interval, device_write_t device_write, device_write_interval_t device_write_interval, int8_t index);
+uint8_t partition_close(struct partition_struct* partition);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/FAT16/partition_config.h b/FAT16/partition_config.h
new file mode 100644 (file)
index 0000000..0040378
--- /dev/null
@@ -0,0 +1,44 @@
+
+/*
+ * Copyright (c) 2006-2009 by Roland Riegel <feedback@roland-riegel.de>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either the GNU General Public License version 2
+ * or the GNU Lesser General Public License version 2.1, both as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef PARTITION_CONFIG_H
+#define PARTITION_CONFIG_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * \addtogroup partition
+ *
+ * @{
+ */
+/**
+ * \file
+ * Partition configuration (license: GPLv2 or LGPLv2.1)
+ */
+
+/**
+ * \ingroup partition_config
+ * Maximum number of partition handles.
+ */
+#define PARTITION_COUNT 1
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/FAT16/sd-reader_config.h b/FAT16/sd-reader_config.h
new file mode 100644 (file)
index 0000000..0819f05
--- /dev/null
@@ -0,0 +1,53 @@
+
+/*
+ * Copyright (c) 2006-2009 by Roland Riegel <feedback@roland-riegel.de>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either the GNU General Public License version 2
+ * or the GNU Lesser General Public License version 2.1, both as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef SD_READER_CONFIG_H
+#define SD_READER_CONFIG_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * \addtogroup config Sd-reader configuration
+ *
+ * @{
+ */
+
+/**
+ * \file
+ * Common sd-reader configuration used by all modules (license: GPLv2 or LGPLv2.1)
+ *
+ * \note This file contains only configuration items relevant to
+ * all sd-reader implementation files. For module specific configuration
+ * options, please see the files fat_config.h, partition_config.h
+ * and sd_raw_config.h.
+ */
+
+/**
+ * Controls allocation of memory.
+ *
+ * Set to 1 to use malloc()/free() for allocation of structures
+ * like file and directory handles, set to 0 to use pre-allocated
+ * fixed-size handle arrays.
+ */
+#define USE_DYNAMIC_MEMORY 0
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/FAT16/sd_raw.c b/FAT16/sd_raw.c
new file mode 100644 (file)
index 0000000..10cddbb
--- /dev/null
@@ -0,0 +1,1011 @@
+
+/*
+ * Copyright (c) 2006-2009 by Roland Riegel <feedback@roland-riegel.de>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either the GNU General Public License version 2
+ * or the GNU Lesser General Public License version 2.1, both as
+ * published by the Free Software Foundation.
+ */
+
+#include <string.h>
+#include <avr/io.h>
+#include "sd_raw.h"
+//ADDED!
+#include <stdlib.h>
+#include <stdio.h>
+#include <avr/io.h>
+#include <avr/interrupt.h>
+
+#include <cfg/debug.h>
+
+/**
+ * \addtogroup sd_raw MMC/SD/SDHC card raw access
+ *
+ * This module implements read and write access to MMC, SD
+ * and SDHC cards. It serves as a low-level driver for the
+ * higher level modules such as partition and file system
+ * access.
+ *
+ * @{
+ */
+/**
+ * \file
+ * MMC/SD/SDHC raw access implementation (license: GPLv2 or LGPLv2.1)
+ *
+ * \author Roland Riegel
+ */
+
+/**
+ * \addtogroup sd_raw_config MMC/SD configuration
+ * Preprocessor defines to configure the MMC/SD support.
+ */
+
+/**
+ * @}
+ */
+
+/* commands available in SPI mode */
+
+/* CMD0: response R1 */
+#define CMD_GO_IDLE_STATE 0x00
+/* CMD1: response R1 */
+#define CMD_SEND_OP_COND 0x01
+/* CMD8: response R7 */
+#define CMD_SEND_IF_COND 0x08
+/* CMD9: response R1 */
+#define CMD_SEND_CSD 0x09
+/* CMD10: response R1 */
+#define CMD_SEND_CID 0x0a
+/* CMD12: response R1 */
+#define CMD_STOP_TRANSMISSION 0x0c
+/* CMD13: response R2 */
+#define CMD_SEND_STATUS 0x0d
+/* CMD16: arg0[31:0]: block length, response R1 */
+#define CMD_SET_BLOCKLEN 0x10
+/* CMD17: arg0[31:0]: data address, response R1 */
+#define CMD_READ_SINGLE_BLOCK 0x11
+/* CMD18: arg0[31:0]: data address, response R1 */
+#define CMD_READ_MULTIPLE_BLOCK 0x12
+/* CMD24: arg0[31:0]: data address, response R1 */
+#define CMD_WRITE_SINGLE_BLOCK 0x18
+/* CMD25: arg0[31:0]: data address, response R1 */
+#define CMD_WRITE_MULTIPLE_BLOCK 0x19
+/* CMD27: response R1 */
+#define CMD_PROGRAM_CSD 0x1b
+/* CMD28: arg0[31:0]: data address, response R1b */
+#define CMD_SET_WRITE_PROT 0x1c
+/* CMD29: arg0[31:0]: data address, response R1b */
+#define CMD_CLR_WRITE_PROT 0x1d
+/* CMD30: arg0[31:0]: write protect data address, response R1 */
+#define CMD_SEND_WRITE_PROT 0x1e
+/* CMD32: arg0[31:0]: data address, response R1 */
+#define CMD_TAG_SECTOR_START 0x20
+/* CMD33: arg0[31:0]: data address, response R1 */
+#define CMD_TAG_SECTOR_END 0x21
+/* CMD34: arg0[31:0]: data address, response R1 */
+#define CMD_UNTAG_SECTOR 0x22
+/* CMD35: arg0[31:0]: data address, response R1 */
+#define CMD_TAG_ERASE_GROUP_START 0x23
+/* CMD36: arg0[31:0]: data address, response R1 */
+#define CMD_TAG_ERASE_GROUP_END 0x24
+/* CMD37: arg0[31:0]: data address, response R1 */
+#define CMD_UNTAG_ERASE_GROUP 0x25
+/* CMD38: arg0[31:0]: stuff bits, response R1b */
+#define CMD_ERASE 0x26
+/* ACMD41: arg0[31:0]: OCR contents, response R1 */
+#define CMD_SD_SEND_OP_COND 0x29
+/* CMD42: arg0[31:0]: stuff bits, response R1b */
+#define CMD_LOCK_UNLOCK 0x2a
+/* CMD55: arg0[31:0]: stuff bits, response R1 */
+#define CMD_APP 0x37
+/* CMD58: arg0[31:0]: stuff bits, response R3 */
+#define CMD_READ_OCR 0x3a
+/* CMD59: arg0[31:1]: stuff bits, arg0[0:0]: crc option, response R1 */
+#define CMD_CRC_ON_OFF 0x3b
+
+/* command responses */
+/* R1: size 1 byte */
+#define R1_IDLE_STATE 0
+#define R1_ERASE_RESET 1
+#define R1_ILL_COMMAND 2
+#define R1_COM_CRC_ERR 3
+#define R1_ERASE_SEQ_ERR 4
+#define R1_ADDR_ERR 5
+#define R1_PARAM_ERR 6
+/* R1b: equals R1, additional busy bytes */
+/* R2: size 2 bytes */
+#define R2_CARD_LOCKED 0
+#define R2_WP_ERASE_SKIP 1
+#define R2_ERR 2
+#define R2_CARD_ERR 3
+#define R2_CARD_ECC_FAIL 4
+#define R2_WP_VIOLATION 5
+#define R2_INVAL_ERASE 6
+#define R2_OUT_OF_RANGE 7
+#define R2_CSD_OVERWRITE 7
+#define R2_IDLE_STATE (R1_IDLE_STATE + 8)
+#define R2_ERASE_RESET (R1_ERASE_RESET + 8)
+#define R2_ILL_COMMAND (R1_ILL_COMMAND + 8)
+#define R2_COM_CRC_ERR (R1_COM_CRC_ERR + 8)
+#define R2_ERASE_SEQ_ERR (R1_ERASE_SEQ_ERR + 8)
+#define R2_ADDR_ERR (R1_ADDR_ERR + 8)
+#define R2_PARAM_ERR (R1_PARAM_ERR + 8)
+/* R3: size 5 bytes */
+#define R3_OCR_MASK (0xffffffffUL)
+#define R3_IDLE_STATE (R1_IDLE_STATE + 32)
+#define R3_ERASE_RESET (R1_ERASE_RESET + 32)
+#define R3_ILL_COMMAND (R1_ILL_COMMAND + 32)
+#define R3_COM_CRC_ERR (R1_COM_CRC_ERR + 32)
+#define R3_ERASE_SEQ_ERR (R1_ERASE_SEQ_ERR + 32)
+#define R3_ADDR_ERR (R1_ADDR_ERR + 32)
+#define R3_PARAM_ERR (R1_PARAM_ERR + 32)
+/* Data Response: size 1 byte */
+#define DR_STATUS_MASK 0x0e
+#define DR_STATUS_ACCEPTED 0x05
+#define DR_STATUS_CRC_ERR 0x0a
+#define DR_STATUS_WRITE_ERR 0x0c
+
+/* status bits for card types */
+#define SD_RAW_SPEC_1 0
+#define SD_RAW_SPEC_2 1
+#define SD_RAW_SPEC_SDHC 2
+
+#if !SD_RAW_SAVE_RAM
+/* static data buffer for acceleration */
+static uint8_t raw_block[512];
+/* offset where the data within raw_block lies on the card */
+static offset_t raw_block_address;
+#if SD_RAW_WRITE_BUFFERING
+/* flag to remember if raw_block was written to the card */
+static uint8_t raw_block_written;
+#endif
+#endif
+
+/* card type state */
+static uint8_t sd_raw_card_type;
+
+/* private helper functions */
+static void sd_raw_send_byte(uint8_t b);
+static uint8_t sd_raw_rec_byte(void);
+static uint8_t sd_raw_send_command(uint8_t command, uint32_t arg);
+
+uint16_t i2 = 0;
+
+/**
+ * \ingroup sd_raw
+ * Initializes memory card communication.
+ *
+ * \returns 0 on failure, 1 on success.
+ */
+uint8_t sd_raw_init()
+{
+    /* enable inputs for reading card status */
+    configure_pin_available();
+    configure_pin_locked();
+
+    /* enable outputs for MOSI, SCK, SS, input for MISO */
+    configure_pin_mosi();
+    configure_pin_sck();
+    configure_pin_ss();
+    configure_pin_miso();
+       PORTB |= (1<<DDB4);
+
+    unselect_card();
+
+    /* initialize SPI with lowest frequency; max. 400kHz during identification mode of card */
+    SPCR = (0 << SPIE) | /* SPI Interrupt Enable */
+           (1 << SPE)  | /* SPI Enable */
+           (0 << DORD) | /* Data Order: MSB first */
+           (1 << MSTR) | /* Master mode */
+           (0 << CPOL) | /* Clock Polarity: SCK low when idle */
+           (0 << CPHA);// | /* Clock Phase: sample on rising SCK edge */
+           //(1 << SPR1) | /* Clock Frequency: f_OSC / 128 */
+           //(1 << SPR0);
+    //SPSR &= ~(1 << SPI2X); /* No doubled clock frequency */
+    SPSR |= (1 << SPI2X);
+
+    /* initialization procedure */
+    sd_raw_card_type = 0;
+    
+    if(!sd_raw_available())
+        return 0;
+
+    /* card needs 74 cycles minimum to start up */
+    for(i2 = 0; i2 < 10; ++i2)
+    {
+        /* wait 8 clock cycles */
+        sd_raw_rec_byte();
+    }
+
+    /* address card */
+    select_card();
+
+    /* reset card */
+    uint8_t response;
+    for(i2 = 0; ; ++i2)
+    {
+        response = sd_raw_send_command(CMD_GO_IDLE_STATE, 0);
+               //uart_putw_hex(response);
+               //uart_puts("\r\n");
+        if(response == (1 << R1_IDLE_STATE))
+            break;
+
+        if(i2 == 0x1ff)
+        {
+            unselect_card();
+                       //uart_puts_p(PSTR("No Response to Idle\n"));
+            return 0;
+        }
+    }
+
+#if SD_RAW_SDHC
+    /* check for version of SD card specification */
+    response = sd_raw_send_command(CMD_SEND_IF_COND, 0x100 /* 2.7V - 3.6V */ | 0xaa /* test pattern */);
+    if((response & (1 << R1_ILL_COMMAND)) == 0)
+    {
+        sd_raw_rec_byte();
+        sd_raw_rec_byte();
+        if((sd_raw_rec_byte() & 0x01) == 0)
+            return 0; /* card operation voltage range doesn't match */
+        if(sd_raw_rec_byte() != 0xaa)
+            return 0; /* wrong test pattern */
+
+        /* card conforms to SD 2 card specification */
+        sd_raw_card_type |= (1 << SD_RAW_SPEC_2);
+    }
+    else
+#endif
+    {
+        /* determine SD/MMC card type */
+        sd_raw_send_command(CMD_APP, 0);
+        response = sd_raw_send_command(CMD_SD_SEND_OP_COND, 0);
+        if((response & (1 << R1_ILL_COMMAND)) == 0)
+        {
+            /* card conforms to SD 1 card specification */
+            sd_raw_card_type |= (1 << SD_RAW_SPEC_1);
+        }
+        else
+        {
+            /* MMC card */
+        }
+    }
+
+    /* wait for card to get ready */
+    for(i2 = 0; ; ++i2)
+    {
+        if(sd_raw_card_type & ((1 << SD_RAW_SPEC_1) | (1 << SD_RAW_SPEC_2)))
+        {
+            uint32_t arg = 0;
+#if SD_RAW_SDHC
+            if(sd_raw_card_type & (1 << SD_RAW_SPEC_2))
+                arg = 0x40000000;
+#endif
+            sd_raw_send_command(CMD_APP, 0);
+            response = sd_raw_send_command(CMD_SD_SEND_OP_COND, arg);
+        }
+        else
+        {
+            response = sd_raw_send_command(CMD_SEND_OP_COND, 0);
+        }
+
+        if((response & (1 << R1_IDLE_STATE)) == 0)
+            break;
+
+        if(i2 == 0x7fff)
+        {
+            unselect_card();
+                       //uart_puts_p(PSTR("No Response to Ready...\n"));
+            return 0;
+        }
+    }
+
+#if SD_RAW_SDHC
+    if(sd_raw_card_type & (1 << SD_RAW_SPEC_2))
+    {
+        if(sd_raw_send_command(CMD_READ_OCR, 0))
+        {
+            unselect_card();
+            return 0;
+        }
+
+        if(sd_raw_rec_byte() & 0x40)
+            sd_raw_card_type |= (1 << SD_RAW_SPEC_SDHC);
+
+        sd_raw_rec_byte();
+        sd_raw_rec_byte();
+        sd_raw_rec_byte();
+    }
+#endif
+
+    /* set block size to 512 bytes */
+    if(sd_raw_send_command(CMD_SET_BLOCKLEN, 512))
+    {
+        unselect_card();
+               //uart_puts_p(PSTR("Failed at 'set block size'\n"));
+        return 0;
+    }
+
+    /* deaddress card */
+    unselect_card();
+
+    /* switch to highest SPI frequency possible */
+    SPCR &= ~((1 << SPR1) | (1 << SPR0)); /* Clock Frequency: f_OSC / 4 */
+    SPSR |= (1 << SPI2X); /* Doubled Clock Frequency: f_OSC / 2 */
+
+#if !SD_RAW_SAVE_RAM
+    /* the first block is likely to be accessed first, so precache it here */
+    raw_block_address = (offset_t) -1;
+#if SD_RAW_WRITE_BUFFERING
+    raw_block_written = 1;
+#endif
+    if(!sd_raw_read(0, raw_block, sizeof(raw_block))){
+                       //uart_puts_p(PSTR("Failed at Raw Save RAM\n"));
+                       return 0;
+               }
+#endif
+
+    return 1;
+}
+
+/**
+ * \ingroup sd_raw
+ * Checks wether a memory card is located in the slot.
+ *
+ * \returns 1 if the card is available, 0 if it is not.
+ */
+uint8_t sd_raw_available()
+{
+    return get_pin_available() == 0x00;
+}
+
+/**
+ * \ingroup sd_raw
+ * Checks wether the memory card is locked for write access.
+ *
+ * \returns 1 if the card is locked, 0 if it is not.
+ */
+uint8_t sd_raw_locked()
+{
+    return get_pin_locked() == 0x00;
+}
+
+/**
+ * \ingroup sd_raw
+ * Sends a raw byte to the memory card.
+ *
+ * \param[in] b The byte to sent.
+ * \see sd_raw_rec_byte
+ */
+void sd_raw_send_byte(uint8_t b)
+{
+    SPDR = b;
+    /* wait for byte to be shifted out */
+    while(!(SPSR & (1 << SPIF)));
+    SPSR &= ~(1 << SPIF);
+}
+
+/**
+ * \ingroup sd_raw
+ * Receives a raw byte from the memory card.
+ *
+ * \returns The byte which should be read.
+ * \see sd_raw_send_byte
+ */
+uint8_t sd_raw_rec_byte(void)
+{
+    /* send dummy data for receiving some */
+    SPDR = 0xff;
+    while(!(SPSR & (1 << SPIF)));
+    SPSR &= ~(1 << SPIF);
+
+    return SPDR;
+}
+
+/**
+ * \ingroup sd_raw
+ * Send a command to the memory card which responses with a R1 response (and possibly others).
+ *
+ * \param[in] command The command to send.
+ * \param[in] arg The argument for command.
+ * \returns The command answer.
+ */
+uint8_t sd_raw_send_command(uint8_t command, uint32_t arg)
+{
+    uint8_t response;
+
+    /* wait some clock cycles */
+    sd_raw_rec_byte();
+
+    /* send command via SPI */
+    sd_raw_send_byte(0x40 | command);
+    sd_raw_send_byte((arg >> 24) & 0xff);
+    sd_raw_send_byte((arg >> 16) & 0xff);
+    sd_raw_send_byte((arg >> 8) & 0xff);
+    sd_raw_send_byte((arg >> 0) & 0xff);
+    switch(command)
+    {
+        case CMD_GO_IDLE_STATE:
+           sd_raw_send_byte(0x95);
+           break;
+        case CMD_SEND_IF_COND:
+           sd_raw_send_byte(0x87);
+           break;
+        default:
+           sd_raw_send_byte(0xff);
+           break;
+    }
+    
+    /* receive response */
+    for(i2 = 0; i2 < 10; ++i2)
+    {
+        response = sd_raw_rec_byte();
+        if(response != 0xff)
+            break;
+    }
+
+    return response;
+}
+
+/**
+ * \ingroup sd_raw
+ * Reads raw data from the card.
+ *
+ * \param[in] offset The offset from which to read.
+ * \param[out] buffer The buffer into which to write the data.
+ * \param[in] length The number of bytes to read.
+ * \returns 0 on failure, 1 on success.
+ * \see sd_raw_read_interval, sd_raw_write, sd_raw_write_interval
+ */
+uint8_t sd_raw_read(offset_t offset, uint8_t* buffer, uintptr_t length)
+{
+    offset_t block_address;
+    uint16_t block_offset;
+    uint16_t read_length;
+    while(length > 0)
+    {
+        /* determine byte count to read at once */
+        block_offset = offset & 0x01ff;
+        block_address = offset - block_offset;
+        read_length = 512 - block_offset; /* read up to block border */
+        if(read_length > length)
+            read_length = length;
+        
+#if !SD_RAW_SAVE_RAM
+        /* check if the requested data is cached */
+        if(block_address != raw_block_address)
+#endif
+        {
+#if SD_RAW_WRITE_BUFFERING
+            if(!sd_raw_sync())
+                return 0;
+#endif
+
+            /* address card */
+            select_card();
+
+            /* send single block request */
+#if SD_RAW_SDHC
+            if(sd_raw_send_command(CMD_READ_SINGLE_BLOCK, (sd_raw_card_type & (1 << SD_RAW_SPEC_SDHC) ? block_address / 512 : block_address)))
+#else
+            if(sd_raw_send_command(CMD_READ_SINGLE_BLOCK, block_address))
+#endif
+            {
+                unselect_card();
+                return 0;
+            }
+
+            /* wait for data block (start byte 0xfe) */
+            while(sd_raw_rec_byte() != 0xfe);
+
+#if SD_RAW_SAVE_RAM
+            /* read byte block */
+            uint16_t read_to = block_offset + read_length;
+            for(i2 = 0; i < 512; ++i)
+            {
+                uint8_t b = sd_raw_rec_byte();
+                if(i >= block_offset && i < read_to)
+                    *buffer++ = b;
+            }
+#else
+            /* read byte block */
+            uint8_t* cache = raw_block;
+            for(i2 = 0; i2 < 512; ++i2)
+                *cache++ = sd_raw_rec_byte();
+            raw_block_address = block_address;
+
+            memcpy(buffer, raw_block + block_offset, read_length);
+            buffer += read_length;
+#endif
+            
+            /* read crc16 */
+            sd_raw_rec_byte();
+            sd_raw_rec_byte();
+            
+            /* deaddress card */
+            unselect_card();
+
+            /* let card some time to finish */
+            sd_raw_rec_byte();
+        }
+#if !SD_RAW_SAVE_RAM
+        else
+        {
+            /* use cached data */
+            memcpy(buffer, raw_block + block_offset, read_length);
+            buffer += read_length;
+        }
+#endif
+
+        length -= read_length;
+        offset += read_length;
+    }
+
+    return 1;
+}
+
+/**
+ * \ingroup sd_raw
+ * Continuously reads units of \c interval bytes and calls a callback function.
+ *
+ * This function starts reading at the specified offset. Every \c interval bytes,
+ * it calls the callback function with the associated data buffer.
+ *
+ * By returning zero, the callback may stop reading.
+ *
+ * \note Within the callback function, you can not start another read or
+ *       write operation.
+ * \note This function only works if the following conditions are met:
+ *       - (offset - (offset % 512)) % interval == 0
+ *       - length % interval == 0
+ *
+ * \param[in] offset Offset from which to start reading.
+ * \param[in] buffer Pointer to a buffer which is at least interval bytes in size.
+ * \param[in] interval Number of bytes to read before calling the callback function.
+ * \param[in] length Number of bytes to read altogether.
+ * \param[in] callback The function to call every interval bytes.
+ * \param[in] p An opaque pointer directly passed to the callback function.
+ * \returns 0 on failure, 1 on success
+ * \see sd_raw_write_interval, sd_raw_read, sd_raw_write
+ */
+uint8_t sd_raw_read_interval(offset_t offset, uint8_t* buffer, uintptr_t interval, uintptr_t length, sd_raw_read_interval_handler_t callback, void* p)
+{
+    if(!buffer || interval == 0 || length < interval || !callback)
+        return 0;
+
+#if !SD_RAW_SAVE_RAM
+    while(length >= interval)
+    {
+        /* as reading is now buffered, we directly
+         * hand over the request to sd_raw_read()
+         */
+        if(!sd_raw_read(offset, buffer, interval))
+            return 0;
+        if(!callback(buffer, offset, p))
+            break;
+        offset += interval;
+        length -= interval;
+    }
+
+    return 1;
+#else
+    /* address card */
+    select_card();
+
+    uint16_t block_offset;
+    uint16_t read_length;
+    uint8_t* buffer_cur;
+    uint8_t finished = 0;
+    do
+    {
+        /* determine byte count to read at once */
+        block_offset = offset & 0x01ff;
+        read_length = 512 - block_offset;
+        
+        /* send single block request */
+#if SD_RAW_SDHC
+        if(sd_raw_send_command(CMD_READ_SINGLE_BLOCK, (sd_raw_card_type & (1 << SD_RAW_SPEC_SDHC) ? offset / 512 : offset - block_offset)))
+#else
+        if(sd_raw_send_command(CMD_READ_SINGLE_BLOCK, offset - block_offset))
+#endif
+        {
+            unselect_card();
+            return 0;
+        }
+
+        /* wait for data block (start byte 0xfe) */
+        while(sd_raw_rec_byte() != 0xfe);
+
+        /* read up to the data of interest */
+        for(i2 = 0; i < block_offset; ++i)
+            sd_raw_rec_byte();
+
+        /* read interval bytes of data and execute the callback */
+        do
+        {
+            if(read_length < interval || length < interval)
+                break;
+
+            buffer_cur = buffer;
+            for(i2 = 0; i < interval; ++i)
+                *buffer_cur++ = sd_raw_rec_byte();
+
+            if(!callback(buffer, offset + (512 - read_length), p))
+            {
+                finished = 1;
+                break;
+            }
+
+            read_length -= interval;
+            length -= interval;
+
+        } while(read_length > 0 && length > 0);
+        
+        /* read rest of data block */
+        while(read_length-- > 0)
+            sd_raw_rec_byte();
+        
+        /* read crc16 */
+        sd_raw_rec_byte();
+        sd_raw_rec_byte();
+
+        if(length < interval)
+            break;
+
+        offset = offset - block_offset + 512;
+
+    } while(!finished);
+    
+    /* deaddress card */
+    unselect_card();
+
+    /* let card some time to finish */
+    sd_raw_rec_byte();
+
+    return 1;
+#endif
+}
+
+#if SD_RAW_WRITE_SUPPORT
+/**
+ * \ingroup sd_raw
+ * Writes raw data to the card.
+ *
+ * \note If write buffering is enabled, you might have to
+ *       call sd_raw_sync() before disconnecting the card
+ *       to ensure all remaining data has been written.
+ *
+ * \param[in] offset The offset where to start writing.
+ * \param[in] buffer The buffer containing the data to be written.
+ * \param[in] length The number of bytes to write.
+ * \returns 0 on failure, 1 on success.
+ * \see sd_raw_write_interval, sd_raw_read, sd_raw_read_interval
+ */
+uint8_t sd_raw_write(offset_t offset, const uint8_t* buffer, uintptr_t length)
+{
+    if(sd_raw_locked())
+        return 0;
+
+    offset_t block_address;
+    uint16_t block_offset;
+    uint16_t write_length;
+    while(length > 0)
+    {
+        /* determine byte count to write at once */
+        block_offset = offset & 0x01ff;
+        block_address = offset - block_offset;
+        write_length = 512 - block_offset; /* write up to block border */
+        if(write_length > length)
+            write_length = length;
+        
+        /* Merge the data to write with the content of the block.
+         * Use the cached block if available.
+         */
+        if(block_address != raw_block_address)
+        {
+#if SD_RAW_WRITE_BUFFERING
+            if(!sd_raw_sync())
+                return 0;
+#endif
+            if(block_offset || write_length < 512)
+            {
+                if(!sd_raw_read(block_address, raw_block, sizeof(raw_block)))
+                    return 0;
+            }
+            raw_block_address = block_address;
+        }
+
+        if(buffer != raw_block)
+        {
+            memcpy(raw_block + block_offset, buffer, write_length);
+
+#if SD_RAW_WRITE_BUFFERING
+            raw_block_written = 0;
+
+            if(length == write_length)
+                return 1;
+#endif
+        }
+
+        /* address card */
+        select_card();
+
+        /* send single block request */
+#if SD_RAW_SDHC
+        if(sd_raw_send_command(CMD_WRITE_SINGLE_BLOCK, (sd_raw_card_type & (1 << SD_RAW_SPEC_SDHC) ? block_address / 512 : block_address)))
+#else
+        if(sd_raw_send_command(CMD_WRITE_SINGLE_BLOCK, block_address))
+#endif
+        {
+            unselect_card();
+            return 0;
+        }
+
+        /* send start byte */
+        sd_raw_send_byte(0xfe);
+
+        /* write byte block */
+        uint8_t* cache = raw_block;
+        for(i2 = 0; i2 < 512; ++i2)
+            sd_raw_send_byte(*cache++);
+
+        /* write dummy crc16 */
+        sd_raw_send_byte(0xff);
+        sd_raw_send_byte(0xff);
+
+        /* wait while card is busy */
+        while(sd_raw_rec_byte() != 0xff);
+        sd_raw_rec_byte();
+
+        /* deaddress card */
+        unselect_card();
+
+        buffer += write_length;
+        offset += write_length;
+        length -= write_length;
+
+#if SD_RAW_WRITE_BUFFERING
+        raw_block_written = 1;
+#endif
+    }
+
+    return 1;
+}
+#endif
+
+#if SD_RAW_WRITE_SUPPORT
+/**
+ * \ingroup sd_raw
+ * Writes a continuous data stream obtained from a callback function.
+ *
+ * This function starts writing at the specified offset. To obtain the
+ * next bytes to write, it calls the callback function. The callback fills the
+ * provided data buffer and returns the number of bytes it has put into the buffer.
+ *
+ * By returning zero, the callback may stop writing.
+ *
+ * \param[in] offset Offset where to start writing.
+ * \param[in] buffer Pointer to a buffer which is used for the callback function.
+ * \param[in] length Number of bytes to write in total. May be zero for endless writes.
+ * \param[in] callback The function used to obtain the bytes to write.
+ * \param[in] p An opaque pointer directly passed to the callback function.
+ * \returns 0 on failure, 1 on success
+ * \see sd_raw_read_interval, sd_raw_write, sd_raw_read
+ */
+uint8_t sd_raw_write_interval(offset_t offset, uint8_t* buffer, uintptr_t length, sd_raw_write_interval_handler_t callback, void* p)
+{
+#if SD_RAW_SAVE_RAM
+    #error "SD_RAW_WRITE_SUPPORT is not supported together with SD_RAW_SAVE_RAM"
+#endif
+
+    if(!buffer || !callback)
+        return 0;
+
+    uint8_t endless = (length == 0);
+    while(endless || length > 0)
+    {
+        uint16_t bytes_to_write = callback(buffer, offset, p);
+        if(!bytes_to_write)
+            break;
+        if(!endless && bytes_to_write > length)
+            return 0;
+
+        /* as writing is always buffered, we directly
+         * hand over the request to sd_raw_write()
+         */
+        if(!sd_raw_write(offset, buffer, bytes_to_write))
+            return 0;
+
+        offset += bytes_to_write;
+        length -= bytes_to_write;
+    }
+
+    return 1;
+}
+#endif
+
+#if SD_RAW_WRITE_SUPPORT
+/**
+ * \ingroup sd_raw
+ * Writes the write buffer's content to the card.
+ *
+ * \note When write buffering is enabled, you should
+ *       call this function before disconnecting the
+ *       card to ensure all remaining data has been
+ *       written.
+ *
+ * \returns 0 on failure, 1 on success.
+ * \see sd_raw_write
+ */
+uint8_t sd_raw_sync()
+{
+#if SD_RAW_WRITE_BUFFERING
+    if(raw_block_written)
+        return 1;
+    if(!sd_raw_write(raw_block_address, raw_block, sizeof(raw_block)))
+        return 0;
+    raw_block_written = 1;
+#endif
+    return 1;
+}
+#endif
+
+/**
+ * \ingroup sd_raw
+ * Reads informational data from the card.
+ *
+ * This function reads and returns the card's registers
+ * containing manufacturing and status information.
+ *
+ * \note: The information retrieved by this function is
+ *        not required in any way to operate on the card,
+ *        but it might be nice to display some of the data
+ *        to the user.
+ *
+ * \param[in] info A pointer to the structure into which to save the information.
+ * \returns 0 on failure, 1 on success.
+ */
+uint8_t sd_raw_get_info(struct sd_raw_info* info)
+{
+    if(!info || !sd_raw_available())
+        return 0;
+
+    memset(info, 0, sizeof(*info));
+
+    select_card();
+
+    /* read cid register */
+    if(sd_raw_send_command(CMD_SEND_CID, 0))
+    {
+        unselect_card();
+        return 0;
+    }
+    while(sd_raw_rec_byte() != 0xfe);
+    for(i2 = 0; i2 < 18; ++i2)
+    {
+        uint8_t b = sd_raw_rec_byte();
+
+        switch(i2)
+        {
+            case 0:
+                info->manufacturer = b;
+                break;
+            case 1:
+            case 2:
+                info->oem[i2 - 1] = b;
+                break;
+            case 3:
+            case 4:
+            case 5:
+            case 6:
+            case 7:
+                info->product[i2 - 3] = b;
+                break;
+            case 8:
+                info->revision = b;
+                break;
+            case 9:
+            case 10:
+            case 11:
+            case 12:
+                info->serial |= (uint32_t) b << ((12 - i2) * 8);
+                break;
+            case 13:
+                info->manufacturing_year = b << 4;
+                break;
+            case 14:
+                info->manufacturing_year |= b >> 4;
+                info->manufacturing_month = b & 0x0f;
+                break;
+        }
+    }
+
+    /* read csd register */
+    uint8_t csd_read_bl_len = 0;
+    uint8_t csd_c_size_mult = 0;
+#if SD_RAW_SDHC
+    uint16_t csd_c_size = 0;
+#else
+    uint32_t csd_c_size = 0;
+#endif
+    if(sd_raw_send_command(CMD_SEND_CSD, 0))
+    {
+        unselect_card();
+        return 0;
+    }
+    while(sd_raw_rec_byte() != 0xfe);
+    for(i2 = 0; i2 < 18; ++i2)
+    {
+        uint8_t b = sd_raw_rec_byte();
+
+        if(i2 == 14)
+        {
+            if(b & 0x40)
+                info->flag_copy = 1;
+            if(b & 0x20)
+                info->flag_write_protect = 1;
+            if(b & 0x10)
+                info->flag_write_protect_temp = 1;
+            info->format = (b & 0x0c) >> 2;
+        }
+        else
+        {
+#if SD_RAW_SDHC
+            if(sd_raw_card_type & (1 << SD_RAW_SPEC_2))
+            {
+                switch(i)
+                {
+                    case 7:
+                        b &= 0x3f;
+                    case 8:
+                    case 9:
+                        csd_c_size <<= 8;
+                        csd_c_size |= b;
+                        break;
+                }
+                if(i2 == 9)
+                {
+                    ++csd_c_size;
+                    info->capacity = (offset_t) csd_c_size * 512 * 1024;
+                }
+            }
+            else
+#endif
+            {
+                switch(i2)
+                {
+                    case 5:
+                        csd_read_bl_len = b & 0x0f;
+                        break;
+                    case 6:
+                        csd_c_size = b & 0x03;
+                        csd_c_size <<= 8;
+                        break;
+                    case 7:
+                        csd_c_size |= b;
+                        csd_c_size <<= 2;
+                        break;
+                    case 8:
+                        csd_c_size |= b >> 6;
+                        ++csd_c_size;
+                        break;
+                    case 9:
+                        csd_c_size_mult = b & 0x03;
+                        csd_c_size_mult <<= 1;
+                        break;
+                    case 10:
+                        csd_c_size_mult |= b >> 7;
+
+                        info->capacity = (uint32_t) csd_c_size << (csd_c_size_mult + csd_read_bl_len + 2);
+
+                        break;
+                }
+            }
+        }
+    }
+
+    unselect_card();
+
+    return 1;
+}
+
diff --git a/FAT16/sd_raw.h b/FAT16/sd_raw.h
new file mode 100644 (file)
index 0000000..549c080
--- /dev/null
@@ -0,0 +1,148 @@
+
+/*
+ * Copyright (c) 2006-2009 by Roland Riegel <feedback@roland-riegel.de>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either the GNU General Public License version 2
+ * or the GNU Lesser General Public License version 2.1, both as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef SD_RAW_H
+#define SD_RAW_H
+
+#include <stdint.h>
+#include "sd_raw_config.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * \addtogroup sd_raw
+ *
+ * @{
+ */
+/**
+ * \file
+ * MMC/SD/SDHC raw access header (license: GPLv2 or LGPLv2.1)
+ *
+ * \author Roland Riegel
+ */
+
+/**
+ * The card's layout is harddisk-like, which means it contains
+ * a master boot record with a partition table.
+ */
+#define SD_RAW_FORMAT_HARDDISK 0
+/**
+ * The card contains a single filesystem and no partition table.
+ */
+#define SD_RAW_FORMAT_SUPERFLOPPY 1
+/**
+ * The card's layout follows the Universal File Format.
+ */
+#define SD_RAW_FORMAT_UNIVERSAL 2
+/**
+ * The card's layout is unknown.
+ */
+#define SD_RAW_FORMAT_UNKNOWN 3
+
+/**
+ * This struct is used by sd_raw_get_info() to return
+ * manufacturing and status information of the card.
+ */
+struct sd_raw_info
+{
+    /**
+     * A manufacturer code globally assigned by the SD card organization.
+     */
+    uint8_t manufacturer;
+    /**
+     * A string describing the card's OEM or content, globally assigned by the SD card organization.
+     */
+    uint8_t oem[3];
+    /**
+     * A product name.
+     */
+    uint8_t product[6];
+    /**
+     * The card's revision, coded in packed BCD.
+     *
+     * For example, the revision value \c 0x32 means "3.2".
+     */
+    uint8_t revision;
+    /**
+     * A serial number assigned by the manufacturer.
+     */
+    uint32_t serial;
+    /**
+     * The year of manufacturing.
+     *
+     * A value of zero means year 2000.
+     */
+    uint8_t manufacturing_year;
+    /**
+     * The month of manufacturing.
+     */
+    uint8_t manufacturing_month;
+    /**
+     * The card's total capacity in bytes.
+     */
+    offset_t capacity;
+    /**
+     * Defines wether the card's content is original or copied.
+     *
+     * A value of \c 0 means original, \c 1 means copied.
+     */
+    uint8_t flag_copy;
+    /**
+     * Defines wether the card's content is write-protected.
+     *
+     * \note This is an internal flag and does not represent the
+     *       state of the card's mechanical write-protect switch.
+     */
+    uint8_t flag_write_protect;
+    /**
+     * Defines wether the card's content is temporarily write-protected.
+     *
+     * \note This is an internal flag and does not represent the
+     *       state of the card's mechanical write-protect switch.
+     */
+    uint8_t flag_write_protect_temp;
+    /**
+     * The card's data layout.
+     *
+     * See the \c SD_RAW_FORMAT_* constants for details.
+     *
+     * \note This value is not guaranteed to match reality.
+     */
+    uint8_t format;
+};
+
+typedef uint8_t (*sd_raw_read_interval_handler_t)(uint8_t* buffer, offset_t offset, void* p);
+typedef uintptr_t (*sd_raw_write_interval_handler_t)(uint8_t* buffer, offset_t offset, void* p);
+
+uint8_t sd_raw_init(void);
+uint8_t sd_raw_available(void);
+uint8_t sd_raw_locked(void);
+
+uint8_t sd_raw_read(offset_t offset, uint8_t* buffer, uintptr_t length);
+uint8_t sd_raw_read_interval(offset_t offset, uint8_t* buffer, uintptr_t interval, uintptr_t length, sd_raw_read_interval_handler_t callback, void* p);
+uint8_t sd_raw_write(offset_t offset, const uint8_t* buffer, uintptr_t length);
+uint8_t sd_raw_write_interval(offset_t offset, uint8_t* buffer, uintptr_t length, sd_raw_write_interval_handler_t callback, void* p);
+uint8_t sd_raw_sync(void);
+
+uint8_t sd_raw_get_info(struct sd_raw_info* info);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/FAT16/sd_raw_config.h b/FAT16/sd_raw_config.h
new file mode 100644 (file)
index 0000000..afe6969
--- /dev/null
@@ -0,0 +1,146 @@
+
+/*
+ * Copyright (c) 2006-2009 by Roland Riegel <feedback@roland-riegel.de>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either the GNU General Public License version 2
+ * or the GNU Lesser General Public License version 2.1, both as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef SD_RAW_CONFIG_H
+#define SD_RAW_CONFIG_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * \addtogroup sd_raw
+ *
+ * @{
+ */
+/**
+ * \file
+ * MMC/SD support configuration (license: GPLv2 or LGPLv2.1)
+ */
+
+/**
+ * \ingroup sd_raw_config
+ * Controls MMC/SD write support.
+ *
+ * Set to 1 to enable MMC/SD write support, set to 0 to disable it.
+ */
+#define SD_RAW_WRITE_SUPPORT 1
+
+/**
+ * \ingroup sd_raw_config
+ * Controls MMC/SD write buffering.
+ *
+ * Set to 1 to buffer write accesses, set to 0 to disable it.
+ *
+ * \note This option has no effect when SD_RAW_WRITE_SUPPORT is 0.
+ */
+#define SD_RAW_WRITE_BUFFERING 1
+
+/**
+ * \ingroup sd_raw_config
+ * Controls MMC/SD access buffering.
+ * 
+ * Set to 1 to save static RAM, but be aware that you will
+ * lose performance.
+ *
+ * \note When SD_RAW_WRITE_SUPPORT is 1, SD_RAW_SAVE_RAM will
+ *       be reset to 0.
+ */
+#define SD_RAW_SAVE_RAM 1
+
+/**
+ * \ingroup sd_raw_config
+ * Controls support for SDHC cards.
+ *
+ * Set to 1 to support so-called SDHC memory cards, i.e. SD
+ * cards with more than 2 gigabytes of memory.
+ */
+#define SD_RAW_SDHC 0
+
+/**
+ * @}
+ */
+
+/* defines for customisation of sd/mmc port access */
+/*#if defined(__AVR_ATmega8__) || \
+    defined(__AVR_ATmega48__) || \
+    defined(__AVR_ATmega88__) || \
+    defined(__AVR_ATmega168__) || \
+    defined(__AVR_ATmega328__) || \
+       defined(__AVR_atmega328p__)
+*/
+    #define configure_pin_mosi() DDRB |= (1 << DDB3)
+    #define configure_pin_sck() DDRB |= (1 << DDB5)
+    #define configure_pin_ss() DDRB |= (1 << DDB0)
+    #define configure_pin_miso() DDRB &= ~(1 << DDB4)
+
+    #define select_card() PORTB &= ~(1 << PINB0)
+    #define unselect_card() PORTB |= (1 << PINB0)
+/*
+#elif defined(__AVR_ATmega16__) || \
+      defined(__AVR_ATmega32__)
+    #define configure_pin_mosi() DDRB |= (1 << DDB5)
+    #define configure_pin_sck() DDRB |= (1 << DDB7)
+    #define configure_pin_ss() DDRB |= (1 << DDB4)
+    #define configure_pin_miso() DDRB &= ~(1 << DDB6)
+
+    #define select_card() PORTB &= ~(1 << PB4)
+    #define unselect_card() PORTB |= (1 << PB4)
+#elif defined(__AVR_ATmega64__) || \
+      defined(__AVR_ATmega128__) || \
+      defined(__AVR_ATmega169__)
+    #define configure_pin_mosi() DDRB |= (1 << DDB2)
+    #define configure_pin_sck() DDRB |= (1 << DDB1)
+    #define configure_pin_ss() DDRB |= (1 << DDB0)
+    #define configure_pin_miso() DDRB &= ~(1 << DDB3)
+
+    #define select_card() PORTB &= ~(1 << PB0)
+    #define unselect_card() PORTB |= (1 << PB0)
+#else
+    #error "no sd/mmc pin mapping available!"
+#endif
+*/
+/*
+#define configure_pin_available() DDRC &= ~(1 << DDC4)
+#define configure_pin_locked() DDRC &= ~(1 << DDC5)
+
+#define get_pin_available() ((PINC >> PINC4) & 0x01)
+#define get_pin_locked() ((PINC >> PINC5) & 0x01)
+*/
+#define configure_pin_available() //NOTHING
+#define configure_pin_locked() //Nothing
+
+#define get_pin_available() 0
+#define get_pin_locked() 1
+
+#if SD_RAW_SDHC
+    typedef uint64_t offset_t;
+#else
+    typedef uint32_t offset_t;
+#endif
+
+/* configuration checks */
+#if SD_RAW_WRITE_SUPPORT
+#undef SD_RAW_SAVE_RAM
+#define SD_RAW_SAVE_RAM 0
+#else
+#undef SD_RAW_WRITE_BUFFERING
+#define SD_RAW_WRITE_BUFFERING 0
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+