1
0
mirror of https://github.com/arduino/Arduino.git synced 2024-11-29 10:24:12 +01:00

Merge branch 'master' into new-extension

This commit is contained in:
David A. Mellis 2010-12-17 09:12:36 -05:00
commit 3e31777fec
65 changed files with 6932 additions and 416 deletions

View File

@ -43,6 +43,7 @@
excludes="**/tools/format/**" excludes="**/tools/format/**"
encoding="UTF-8" encoding="UTF-8"
includeAntRuntime="false" includeAntRuntime="false"
debug="true"
classpath="../core/core.jar; ${env.JAVA_HOME}/lib/tools.jar; lib/ant.jar; lib/ant-launcher.jar; lib/apple.jar; lib/ecj.jar; lib/jna.jar; lib/RXTXcomm.jar" /> classpath="../core/core.jar; ${env.JAVA_HOME}/lib/tools.jar; lib/ant.jar; lib/ant-launcher.jar; lib/apple.jar; lib/ecj.jar; lib/jna.jar; lib/RXTXcomm.jar" />
</target> </target>

View File

@ -41,9 +41,9 @@ import processing.core.*;
* files and images, etc) that comes from that. * files and images, etc) that comes from that.
*/ */
public class Base { public class Base {
public static final int REVISION = 21; public static final int REVISION = 22;
/** This might be replaced by main() if there's a lib/version.txt file. */ /** This might be replaced by main() if there's a lib/version.txt file. */
static String VERSION_NAME = "0021"; static String VERSION_NAME = "0022";
/** Set true if this a proper release rather than a numbered revision. */ /** Set true if this a proper release rather than a numbered revision. */
static public boolean RELEASE = false; static public boolean RELEASE = false;

View File

@ -898,23 +898,7 @@ public class Editor extends JFrame implements RunnerListener {
//public SerialMenuListener() { } //public SerialMenuListener() { }
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
if(serialMenu == null) { selectSerialPort(((JCheckBoxMenuItem)e.getSource()).getText());
System.out.println("serialMenu is null");
return;
}
int count = serialMenu.getItemCount();
for (int i = 0; i < count; i++) {
((JCheckBoxMenuItem)serialMenu.getItem(i)).setState(false);
}
JCheckBoxMenuItem item = (JCheckBoxMenuItem)e.getSource();
item.setState(true);
String name = item.getText();
//System.out.println(item.getLabel());
Preferences.set("serial.port", name);
serialMonitor.closeSerialPort();
serialMonitor.setVisible(false);
serialMonitor = new SerialMonitor(Preferences.get("serial.port"));
//System.out.println("set to " + get("serial.port"));
} }
/* /*
@ -929,6 +913,34 @@ public class Editor extends JFrame implements RunnerListener {
*/ */
} }
protected void selectSerialPort(String name) {
if(serialMenu == null) {
System.out.println("serialMenu is null");
return;
}
if (name == null) {
System.out.println("name is null");
return;
}
JCheckBoxMenuItem selection = null;
for (int i = 0; i < serialMenu.getItemCount(); i++) {
JCheckBoxMenuItem item = ((JCheckBoxMenuItem)serialMenu.getItem(i));
if (item == null) {
System.out.println("name is null");
continue;
}
item.setState(false);
if (name.equals(item.getText())) selection = item;
}
if (selection != null) selection.setState(true);
//System.out.println(item.getLabel());
Preferences.set("serial.port", name);
serialMonitor.closeSerialPort();
serialMonitor.setVisible(false);
serialMonitor = new SerialMonitor(Preferences.get("serial.port"));
//System.out.println("set to " + get("serial.port"));
}
protected void populateSerialMenu() { protected void populateSerialMenu() {
// getting list of ports // getting list of ports
@ -2271,6 +2283,31 @@ public class Editor extends JFrame implements RunnerListener {
} }
public boolean serialPrompt() {
populateSerialMenu();
int count = serialMenu.getItemCount();
Object[] names = new Object[count];
for (int i = 0; i < count; i++) {
names[i] = ((JCheckBoxMenuItem)serialMenu.getItem(i)).getText();
}
String result = (String)
JOptionPane.showInputDialog(this,
"Serial port " +
Preferences.get("serial.port") +
" not found.\n" +
"Retry the upload with another serial port?",
"Serial port not found",
JOptionPane.PLAIN_MESSAGE,
null,
names,
0);
if (result == null) return false;
selectSerialPort(result);
return true;
}
/** /**
* Called by Sketch &rarr; Export. * Called by Sketch &rarr; Export.
* Handles calling the export() function on sketch, and * Handles calling the export() function on sketch, and
@ -2311,6 +2348,9 @@ public class Editor extends JFrame implements RunnerListener {
} else { } else {
// error message will already be visible // error message will already be visible
} }
} catch (SerialNotFoundException e) {
if (serialPrompt()) run();
else statusNotice("Upload canceled.");
} catch (RunnerException e) { } catch (RunnerException e) {
//statusError("Error during upload."); //statusError("Error during upload.");
//e.printStackTrace(); //e.printStackTrace();

View File

@ -150,7 +150,7 @@ public class Serial implements SerialPortEventListener {
} }
if (port == null) { if (port == null) {
throw new SerialException("Serial port '" + iname + "' not found. Did you select the right one from the Tools > Serial Port menu?"); throw new SerialNotFoundException("Serial port '" + iname + "' not found. Did you select the right one from the Tools > Serial Port menu?");
} }
} }

View File

@ -0,0 +1,39 @@
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Copyright (c) 2007 David A. Mellis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package processing.app;
public class SerialNotFoundException extends SerialException {
public SerialNotFoundException() {
super();
}
public SerialNotFoundException(String message) {
super(message);
}
public SerialNotFoundException(String message, Throwable cause) {
super(message, cause);
}
public SerialNotFoundException(Throwable cause) {
super(cause);
}
}

View File

@ -1529,7 +1529,7 @@ public class Sketch {
* Handle export to applet. * Handle export to applet.
*/ */
public boolean exportApplet(String appletPath, boolean verbose) public boolean exportApplet(String appletPath, boolean verbose)
throws RunnerException, IOException { throws RunnerException, IOException, SerialException {
// Make sure the user didn't hide the sketch folder // Make sure the user didn't hide the sketch folder
ensureExistence(); ensureExistence();
@ -1593,7 +1593,7 @@ public class Sketch {
protected String upload(String buildPath, String suggestedClassName, boolean verbose) protected String upload(String buildPath, String suggestedClassName, boolean verbose)
throws RunnerException { throws RunnerException, SerialException {
Uploader uploader; Uploader uploader;

View File

@ -29,6 +29,7 @@ package processing.app.debug;
import processing.app.Base; import processing.app.Base;
import processing.app.Preferences; import processing.app.Preferences;
import processing.app.Serial; import processing.app.Serial;
import processing.app.SerialException;
import java.io.*; import java.io.*;
import java.util.*; import java.util.*;
@ -43,7 +44,7 @@ public class AvrdudeUploader extends Uploader {
// XXX: add support for uploading sketches using a programmer // XXX: add support for uploading sketches using a programmer
public boolean uploadUsingPreferences(String buildPath, String className, boolean verbose) public boolean uploadUsingPreferences(String buildPath, String className, boolean verbose)
throws RunnerException { throws RunnerException, SerialException {
this.verbose = verbose; this.verbose = verbose;
Map<String, String> boardPreferences = Base.getBoardPreferences(); Map<String, String> boardPreferences = Base.getBoardPreferences();
String uploadUsing = boardPreferences.get("upload.using"); String uploadUsing = boardPreferences.get("upload.using");
@ -71,7 +72,7 @@ public class AvrdudeUploader extends Uploader {
} }
private boolean uploadViaBootloader(String buildPath, String className) private boolean uploadViaBootloader(String buildPath, String className)
throws RunnerException { throws RunnerException, SerialException {
Map<String, String> boardPreferences = Base.getBoardPreferences(); Map<String, String> boardPreferences = Base.getBoardPreferences();
List commandDownloader = new ArrayList(); List commandDownloader = new ArrayList();
String protocol = boardPreferences.get("upload.protocol"); String protocol = boardPreferences.get("upload.protocol");

View File

@ -93,72 +93,72 @@ public class Compiler implements MessageConsumer {
List<File> objectFiles = new ArrayList<File>(); List<File> objectFiles = new ArrayList<File>();
List includePaths = new ArrayList(); // 0. include paths for core + all libraries
includePaths.add(corePath);
String runtimeLibraryName = buildPath + File.separator + "core.a"; List includePaths = new ArrayList();
includePaths.add(corePath);
for (File file : sketch.getImportedLibraries()) {
includePaths.add(file.getPath());
}
// 1. compile the core, outputting .o files to <buildPath> and then // 1. compile the sketch (already in the buildPath)
// collecting them into the core.a library file.
List<File> coreObjectFiles = objectFiles.addAll(
compileFiles(avrBasePath, buildPath, includePaths, compileFiles(avrBasePath, buildPath, includePaths,
findFilesInPath(corePath, "S", true), findFilesInPath(buildPath, "S", false),
findFilesInPath(corePath, "c", true), findFilesInPath(buildPath, "c", false),
findFilesInPath(corePath, "cpp", true), findFilesInPath(buildPath, "cpp", false),
boardPreferences); boardPreferences));
List baseCommandAR = new ArrayList(Arrays.asList(new String[] { // 2. compile the libraries, outputting .o files to: <buildPath>/<library>/
avrBasePath + "avr-ar",
"rcs",
runtimeLibraryName
}));
for(File file : coreObjectFiles) { for (File libraryFolder : sketch.getImportedLibraries()) {
List commandAR = new ArrayList(baseCommandAR); File outputFolder = new File(buildPath, libraryFolder.getName());
commandAR.add(file.getAbsolutePath()); File utilityFolder = new File(libraryFolder, "utility");
execAsynchronously(commandAR); createFolder(outputFolder);
} // this library can use includes in its utility/ folder
includePaths.add(utilityFolder.getAbsolutePath());
objectFiles.addAll(
compileFiles(avrBasePath, outputFolder.getAbsolutePath(), includePaths,
findFilesInFolder(libraryFolder, "S", false),
findFilesInFolder(libraryFolder, "c", false),
findFilesInFolder(libraryFolder, "cpp", false),
boardPreferences));
outputFolder = new File(outputFolder, "utility");
createFolder(outputFolder);
objectFiles.addAll(
compileFiles(avrBasePath, outputFolder.getAbsolutePath(), includePaths,
findFilesInFolder(utilityFolder, "S", false),
findFilesInFolder(utilityFolder, "c", false),
findFilesInFolder(utilityFolder, "cpp", false),
boardPreferences));
// other libraries should not see this library's utility/ folder
includePaths.remove(includePaths.size() - 1);
}
// 2. compile the libraries, outputting .o files to: <buildPath>/<library>/ // 3. compile the core, outputting .o files to <buildPath> and then
// collecting them into the core.a library file.
// use library directories as include paths for all libraries includePaths.clear();
for (File file : sketch.getImportedLibraries()) { includePaths.add(corePath); // include path for core only
includePaths.add(file.getPath()); List<File> coreObjectFiles =
} compileFiles(avrBasePath, buildPath, includePaths,
findFilesInPath(corePath, "S", true),
findFilesInPath(corePath, "c", true),
findFilesInPath(corePath, "cpp", true),
boardPreferences);
for (File libraryFolder : sketch.getImportedLibraries()) { String runtimeLibraryName = buildPath + File.separator + "core.a";
File outputFolder = new File(buildPath, libraryFolder.getName()); List baseCommandAR = new ArrayList(Arrays.asList(new String[] {
File utilityFolder = new File(libraryFolder, "utility"); avrBasePath + "avr-ar",
createFolder(outputFolder); "rcs",
// this library can use includes in its utility/ folder runtimeLibraryName
includePaths.add(utilityFolder.getAbsolutePath()); }));
objectFiles.addAll( for(File file : coreObjectFiles) {
compileFiles(avrBasePath, outputFolder.getAbsolutePath(), includePaths, List commandAR = new ArrayList(baseCommandAR);
findFilesInFolder(libraryFolder, "S", false), commandAR.add(file.getAbsolutePath());
findFilesInFolder(libraryFolder, "c", false), execAsynchronously(commandAR);
findFilesInFolder(libraryFolder, "cpp", false), }
boardPreferences));
outputFolder = new File(outputFolder, "utility");
createFolder(outputFolder);
objectFiles.addAll(
compileFiles(avrBasePath, outputFolder.getAbsolutePath(), includePaths,
findFilesInFolder(utilityFolder, "S", false),
findFilesInFolder(utilityFolder, "c", false),
findFilesInFolder(utilityFolder, "cpp", false),
boardPreferences));
// other libraries should not see this library's utility/ folder
includePaths.remove(includePaths.size() - 1);
}
// 3. compile the sketch (already in the buildPath)
objectFiles.addAll(
compileFiles(avrBasePath, buildPath, includePaths,
findFilesInPath(buildPath, "S", false),
findFilesInPath(buildPath, "c", false),
findFilesInPath(buildPath, "cpp", false),
boardPreferences));
// 4. link it all together into the .elf file // 4. link it all together into the .elf file

View File

@ -29,6 +29,8 @@ package processing.app.debug;
import processing.app.Base; import processing.app.Base;
import processing.app.Preferences; import processing.app.Preferences;
import processing.app.Serial; import processing.app.Serial;
import processing.app.SerialException;
import processing.app.SerialNotFoundException;
import java.io.*; import java.io.*;
import java.util.*; import java.util.*;
@ -63,11 +65,11 @@ public abstract class Uploader implements MessageConsumer {
} }
public abstract boolean uploadUsingPreferences(String buildPath, String className, boolean verbose) public abstract boolean uploadUsingPreferences(String buildPath, String className, boolean verbose)
throws RunnerException; throws RunnerException, SerialException;
public abstract boolean burnBootloader(String target, String programmer) throws RunnerException; public abstract boolean burnBootloader(String target, String programmer) throws RunnerException;
protected void flushSerialBuffer() throws RunnerException { protected void flushSerialBuffer() throws RunnerException, SerialException {
// Cleanup the serial buffer // Cleanup the serial buffer
try { try {
Serial serialPort = new Serial(); Serial serialPort = new Serial();
@ -90,6 +92,8 @@ public abstract class Uploader implements MessageConsumer {
serialPort.setRTS(true); serialPort.setRTS(true);
serialPort.dispose(); serialPort.dispose();
} catch (SerialNotFoundException e) {
throw e;
} catch(Exception e) { } catch(Exception e) {
e.printStackTrace(); e.printStackTrace();
throw new RunnerException(e.getMessage()); throw new RunnerException(e.getMessage());

View File

@ -114,6 +114,26 @@ public class DiscourseFormat {
" has been copied to the clipboard."); " has been copied to the clipboard.");
} }
/**
* Append a char to a stringbuffer while escaping for proper display in HTML.
* @param c input char to escape
* @param buffer StringBuffer to append html-safe version of c to.
*/
private void appendToHTML(char c, StringBuffer buffer) {
if (!html) {
buffer.append(c);
} else if (c == '<') {
buffer.append("&lt;");
} else if (c == '>') {
buffer.append("&gt;");
} else if (c == '&') {
buffer.append("&amp;");
} else if (c > 127) {
buffer.append("&#" + ((int) c) + ";"); // use unicode entity
} else {
buffer.append(c); // normal character
}
}
// A terrible headache... // A terrible headache...
public void appendFormattedLine(StringBuffer cf, int line) { public void appendFormattedLine(StringBuffer cf, int line) {
@ -138,7 +158,7 @@ public class DiscourseFormat {
if (tokenMarker == null) { if (tokenMarker == null) {
for (int j = 0; j < segmentCount; j++) { for (int j = 0; j < segmentCount; j++) {
char c = segmentArray[j + segmentOffset]; char c = segmentArray[j + segmentOffset];
cf = cf.append(c); appendToHTML(c, cf);
// int charWidth; // int charWidth;
// if (c == '\t') { // if (c == '\t') {
// charWidth = (int) painter.nextTabStop(width, j) - width; // charWidth = (int) painter.nextTabStop(width, j) - width;
@ -171,7 +191,7 @@ public class DiscourseFormat {
if (id == Token.END) { if (id == Token.END) {
char c = segmentArray[segmentOffset + offset]; char c = segmentArray[segmentOffset + offset];
if (segmentOffset + offset < limit) { if (segmentOffset + offset < limit) {
cf.append(c); appendToHTML(c, cf);
} else { } else {
cf.append('\n'); cf.append('\n');
} }
@ -203,7 +223,7 @@ public class DiscourseFormat {
// cf.append(' '); // cf.append(' ');
// } // }
} else { } else {
cf.append(c); appendToHTML(c, cf);
} }
// Place close tags [/] // Place close tags [/]
if (j == (length - 1) && id != Token.NULL && styles[id].isBold()) if (j == (length - 1) && id != Token.NULL && styles[id].isBold())

View File

@ -314,7 +314,7 @@
<target name="linux-run" depends="linux-build" <target name="linux-run" depends="linux-build"
description="Run Linux version"> description="Run Linux version">
<exec executable="./arduino" dir="linux/work" spawn="false"/> <exec executable="./linux/work/arduino" spawn="false"/>
</target> </target>
<target name="linux-dist" depends="linux-build" <target name="linux-dist" depends="linux-build"

View File

@ -10,11 +10,11 @@ for LIB in \
lib/*.jar \ lib/*.jar \
; ;
do do
CLASSPATH="${CLASSPATH}:${APPDIR}/${LIB}" CLASSPATH="${CLASSPATH}:${LIB}"
done done
export CLASSPATH export CLASSPATH
LD_LIBRARY_PATH=`pwd`/lib:${LD_LIBRARY_PATH} LD_LIBRARY_PATH=`pwd`/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}
export LD_LIBRARY_PATH export LD_LIBRARY_PATH
export PATH="${APPDIR}/java/bin:${PATH}" export PATH="${APPDIR}/java/bin:${PATH}"

View File

@ -7,11 +7,11 @@
<!-- all these need to change for new releases --> <!-- all these need to change for new releases -->
<key>CFBundleGetInfoString</key> <key>CFBundleGetInfoString</key>
<string>0021</string> <string>0022</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>0021</string> <string>0022</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>0021</string> <string>0022</string>
<!-- now stop changing things and get outta here --> <!-- now stop changing things and get outta here -->
<key>CFBundleAllowMixedLocalizations</key> <key>CFBundleAllowMixedLocalizations</key>

View File

@ -0,0 +1,85 @@
/*
Character analysis operators
Examples using the character analysis operators.
Send any byte and the sketch will tell you about it.
created 29 Nov 2010
by Tom Igoe
This example code is in the public domain.
*/
void setup() {
// Open serial communications:
Serial.begin(9600);
// send an intro:
Serial.println("send any byte and I'll tell you everything I can about it");
Serial.println();
}
void loop() {
// get any incoming bytes:
if (Serial.available() > 0) {
int thisChar = Serial.read();
// say what was sent:
Serial.print("You sent me: \'");
Serial.write(thisChar);
Serial.print("\' ASCII Value: ");
Serial.println(thisChar);
// analyze what was sent:
if(isAlphaNumeric(thisChar)) {
Serial.println("it's alphanumeric");
}
if(isAlpha(thisChar)) {
Serial.println("it's alphabetic");
}
if(isAscii(thisChar)) {
Serial.println("it's ASCII");
}
if(isWhitespace(thisChar)) {
Serial.println("it's whitespace");
}
if(isControl(thisChar)) {
Serial.println("it's a control character");
}
if(isDigit(thisChar)) {
Serial.println("it's a numeric digit");
}
if(isGraph(thisChar)) {
Serial.println("it's a printable character that's not whitespace");
}
if(isLowerCase(thisChar)) {
Serial.println("it's lower case");
}
if(isPrintable(thisChar)) {
Serial.println("it's printable");
}
if(isPunct(thisChar)) {
Serial.println("it's punctuation");
}
if(isSpace(thisChar)) {
Serial.println("it's a space character");
}
if(isUpperCase(thisChar)) {
Serial.println("it's upper case");
}
if (isHexadecimalDigit(thisChar)) {
Serial.println("it's a valid hexadecimaldigit (i.e. 0 - 9, a - F, or A - F)");
}
// add some space and ask for another byte:
Serial.println();
Serial.println("Give me another byte:");
Serial.println();
}
}

View File

@ -0,0 +1,47 @@
/*
String to Integer conversion
Reads a serial input string until it sees a newline, then converts
the string to a number if the characters are digits.
The circuit:
No external components needed.
created 29 Nov 2010
by Tom Igoe
This example code is in the public domain.
*/
String inString = ""; // string to hold input
void setup() {
// Initialize serial communications:
Serial.begin(9600);
}
void loop() {
// Read serial input:
while (Serial.available() > 0) {
int inChar = Serial.read();
if (isDigit(inChar)) {
// convert the incoming byte to a char
// and add it to the string:
inString += (char)inChar;
}
// if you get a newline, print the string,
// then the string's value:
if (inChar == '\n') {
Serial.print("Value:");
Serial.println(inString.toInt());
Serial.print("String: ");
Serial.println(inString);
// clear the string for new input:
inString = "";
}
}
}

View File

@ -0,0 +1,230 @@
/*
Serial RGB controller
Reads a serial input string looking for three comma-separated
integers with a newline at the end. Values should be between
0 and 255. The sketch uses those values to set the color
of an RGB LED attached to pins 9 - 11.
The circuit:
* Common-anode RGB LED cathodes attached to pins 9 - 11
* LED anode connected to pin 13
To turn on any given channel, set the pin LOW.
To turn off, set the pin HIGH. The higher the analogWrite level,
the lower the brightness.
created 29 Nov 2010
by Tom Igoe
This example code is in the public domain.
*/
String inString = ""; // string to hold input
int currentColor = 0;
int red, green, blue = 0;
void setup() {
// Initialize serial communications:
Serial.begin(9600);
// set LED cathode pins as outputs:
pinMode(9, OUTPUT);
pinMode(10, OUTPUT);
pinMode(11, OUTPUT);
// turn on pin 13 to power the LEDs:
pinMode(13, OUTPUT);
digitalWrite(13, HIGH);
}
void loop() {
int inChar;
// Read serial input:
if (Serial.available() > 0) {
inChar = Serial.read();
}
if (isDigit(inChar)) {
// convert the incoming byte to a char
// and add it to the string:
inString += (char)inChar;
}
// if you get a comma, convert to a number,
// set the appropriate color, and increment
// the color counter:
if (inChar == ',') {
// do something different for each value of currentColor:
switch (currentColor) {
case 0: // 0 = red
red = inString.toInt();
// clear the string for new input:
inString = "";
break;
case 1: // 1 = green:
green = inString.toInt();
// clear the string for new input:
inString = "";
break;
}
currentColor++;
}
// if you get a newline, you know you've got
// the last color, i.e. blue:
if (inChar == '\n') {
blue = inString.toInt();
// set the levels of the LED.
// subtract value from 255 because a higher
// analogWrite level means a dimmer LED, since
// you're raising the level on the anode:
analogWrite(11, 255 - red);
analogWrite(9, 255 - green);
analogWrite(10, 255 - blue);
// print the colors:
Serial.print("Red: ");
Serial.print(red);
Serial.print(", Green: ");
Serial.print(green);
Serial.print(", Blue: ");
Serial.println(blue);
// clear the string for new input:
inString = "";
// reset the color counter:
currentColor = 0;
}
}
/*
Here's a Processing sketch that will draw a color wheel and send a serial
string with the color you click on:
// Subtractive Color Wheel with Serial
// Based on a Processing example by Ira Greenberg.
// Serial output added by Tom Igoe
//
// The primaries are red, yellow, and blue. The secondaries are green,
// purple, and orange. The tertiaries are yellow-orange, red-orange,
// red-purple, blue-purple, blue-green, and yellow-green.
//
// Create a shade or tint of the subtractive color wheel using
// SHADE or TINT parameters.
// Updated 29 November 2010.
import processing.serial.*;
int segs = 12;
int steps = 6;
float rotAdjust = TWO_PI / segs / 2;
float radius;
float segWidth;
float interval = TWO_PI / segs;
Serial myPort;
void setup() {
size(200, 200);
background(127);
smooth();
ellipseMode(RADIUS);
noStroke();
// make the diameter 90% of the sketch area
radius = min(width, height) * 0.45;
segWidth = radius / steps;
// swap which line is commented out to draw the other version
// drawTintWheel();
drawShadeWheel();
// open the first serial port in your computer's list
myPort = new Serial(this, Serial.list()[0], 9600);
}
void drawShadeWheel() {
for (int j = 0; j < steps; j++) {
color[] cols = {
color(255-(255/steps)*j, 255-(255/steps)*j, 0),
color(255-(255/steps)*j, (255/1.5)-((255/1.5)/steps)*j, 0),
color(255-(255/steps)*j, (255/2)-((255/2)/steps)*j, 0),
color(255-(255/steps)*j, (255/2.5)-((255/2.5)/steps)*j, 0),
color(255-(255/steps)*j, 0, 0),
color(255-(255/steps)*j, 0, (255/2)-((255/2)/steps)*j),
color(255-(255/steps)*j, 0, 255-(255/steps)*j),
color((255/2)-((255/2)/steps)*j, 0, 255-(255/steps)*j),
color(0, 0, 255-(255/steps)*j),
color(0, 255-(255/steps)*j, (255/2.5)-((255/2.5)/steps)*j),
color(0, 255-(255/steps)*j, 0),
color((255/2)-((255/2)/steps)*j, 255-(255/steps)*j, 0)
};
for (int i = 0; i < segs; i++) {
fill(cols[i]);
arc(width/2, height/2, radius, radius,
interval*i+rotAdjust, interval*(i+1)+rotAdjust);
}
radius -= segWidth;
}
}
void drawTintWheel() {
for (int j = 0; j < steps; j++) {
color[] cols = {
color((255/steps)*j, (255/steps)*j, 0),
color((255/steps)*j, ((255/1.5)/steps)*j, 0),
color((255/steps)*j, ((255/2)/steps)*j, 0),
color((255/steps)*j, ((255/2.5)/steps)*j, 0),
color((255/steps)*j, 0, 0),
color((255/steps)*j, 0, ((255/2)/steps)*j),
color((255/steps)*j, 0, (255/steps)*j),
color(((255/2)/steps)*j, 0, (255/steps)*j),
color(0, 0, (255/steps)*j),
color(0, (255/steps)*j, ((255/2.5)/steps)*j),
color(0, (255/steps)*j, 0),
color(((255/2)/steps)*j, (255/steps)*j, 0)
};
for (int i = 0; i < segs; i++) {
fill(cols[i]);
arc(width/2, height/2, radius, radius,
interval*i+rotAdjust, interval*(i+1)+rotAdjust);
}
radius -= segWidth;
}
}
void draw() {
// nothing happens here
}
void mouseReleased() {
// get the color of the mouse position's pixel:
color targetColor = get(mouseX, mouseY);
// get the component values:
int r = int(red(targetColor));
int g = int(green(targetColor));
int b = int(blue(targetColor));
// make a comma-separated string:
String colorString = r + "," + g + "," + b + "\n";
// send it out the serial port:
myPort.write(colorString );
}
*/

View File

@ -1,3 +1,65 @@
ARDUINO 0022
[core / libraries]
* Adding an SD card library based on sdfatlib by Bill Greiman and the
MemoryCard library by Philip Lindsay (follower) for SparkFun.
http://arduino.cc/en/Reference/SD
* Added character manipulation macros (from Wiring): isAlphaNumeric(),
isAlpha(), isAscii(), isWhitespace(), isControl(), isDigit(), isGraph(),
isLowerCase(), isPrintable(), isPunct(), isSpace(), isUpperCase(),
isHexadecimalDigit(), toAscii(), toLowerCase(), toLowerCase().
http://code.google.com/p/arduino/issues/detail?id=418
* Added String.toInt() function.
* Refactoring core to use register-based, not CPU-based, #ifdefs.
Patch by Mark Sproul.
http://code.google.com/p/arduino/issues/detail?id=307
http://code.google.com/p/arduino/issues/detail?id=315
http://code.google.com/p/arduino/issues/detail?id=316
http://code.google.com/p/arduino/issues/detail?id=323
http://code.google.com/p/arduino/issues/detail?id=324
http://code.google.com/p/arduino/issues/detail?id=340
* Modification of serial baud rate calculation to match bootloader and 8U2
firmware at 57600 baud.
http://code.google.com/p/arduino/issues/detail?id=394
* Fixed bug in tone() function.
http://code.google.com/p/arduino/issues/detail?id=361
* Fixed SPI.setClockDivider() function.
http://code.google.com/p/arduino/issues/detail?id=365
* Hardware serial receive interrupt optimization.
http://code.google.com/p/arduino/issues/detail?id=391
* Applying the timeout parameter of pulseIn() during measurement of the
pulse, not just while waiting for it.
[environment]
* Fixed problem with copy as html and angle brackets.
http://code.google.com/p/arduino/issues/detail?id=29
* Showing serial port selection dialog if serial port not found on upload.
* Remembering serial monitor window size and line ending selection.
http://code.google.com/p/arduino/issues/detail?id=96
http://code.google.com/p/arduino/issues/detail?id=330
* Replaced oro.jar regular expressions with java.regex ones (patch by
Eberhard Fahle and Christian Maglie).
http://code.google.com/p/arduino/issues/detail?id=171
* Building the user sketch before the core or libraries, so errors appear
faster. Patch by William Westfield and Paul Stoffregen.
http://code.google.com/p/arduino/issues/detail?id=393
* Setting application icon under Windows.
ARDUINO 0021 - 2010.10.02 ARDUINO 0021 - 2010.10.02
* Modifying VID / PID combination in 8U2 firmwares. * Modifying VID / PID combination in 8U2 firmwares.

View File

@ -65,7 +65,7 @@ struct ring_buffer
inline void store_char(unsigned char c, ring_buffer *rx_buffer) inline void store_char(unsigned char c, ring_buffer *rx_buffer)
{ {
int i = (rx_buffer->head + 1) % RX_BUFFER_SIZE; int i = (unsigned int)(rx_buffer->head + 1) % RX_BUFFER_SIZE;
// if we should be storing the received character into the location // if we should be storing the received character into the location
// just before the tail (meaning that the head would advance to the // just before the tail (meaning that the head would advance to the
@ -194,22 +194,16 @@ HardwareSerial::HardwareSerial(ring_buffer *rx_buffer,
void HardwareSerial::begin(long baud) void HardwareSerial::begin(long baud)
{ {
uint16_t baud_setting; uint16_t baud_setting;
bool use_u2x; bool use_u2x = true;
// U2X mode is needed for baud rates higher than (CPU Hz / 16) #if F_CPU == 16000000UL
if (baud > F_CPU / 16) { // hardcoded exception for compatibility with the bootloader shipped
use_u2x = true; // with the Duemilanove and previous boards and the firmware on the 8U2
} else { // on the Uno and Mega 2560.
// figure out if U2X mode would allow for a better connection if (baud == 57600) {
use_u2x = false;
// calculate the percent difference between the baud-rate specified and
// the real baud rate for both U2X and non-U2X mode (0-255 error percent)
uint8_t nonu2x_baud_error = abs((int)(255-((F_CPU/(16*(((F_CPU/8/baud-1)/2)+1))*255)/baud)));
uint8_t u2x_baud_error = abs((int)(255-((F_CPU/(8*(((F_CPU/4/baud-1)/2)+1))*255)/baud)));
// prefer non-U2X mode because it handles clock skew better
use_u2x = (nonu2x_baud_error > u2x_baud_error);
} }
#endif
if (use_u2x) { if (use_u2x) {
*_ucsra = 1 << _u2x; *_ucsra = 1 << _u2x;
@ -237,7 +231,7 @@ void HardwareSerial::end()
int HardwareSerial::available(void) int HardwareSerial::available(void)
{ {
return (RX_BUFFER_SIZE + _rx_buffer->head - _rx_buffer->tail) % RX_BUFFER_SIZE; return (unsigned int)(RX_BUFFER_SIZE + _rx_buffer->head - _rx_buffer->tail) % RX_BUFFER_SIZE;
} }
int HardwareSerial::peek(void) int HardwareSerial::peek(void)
@ -256,7 +250,7 @@ int HardwareSerial::read(void)
return -1; return -1;
} else { } else {
unsigned char c = _rx_buffer->buffer[_rx_buffer->tail]; unsigned char c = _rx_buffer->buffer[_rx_buffer->tail];
_rx_buffer->tail = (_rx_buffer->tail + 1) % RX_BUFFER_SIZE; _rx_buffer->tail = (unsigned int)(_rx_buffer->tail + 1) % RX_BUFFER_SIZE;
return c; return c;
} }
} }

View File

@ -28,6 +28,7 @@ class Stream : public Print
public: public:
virtual int available() = 0; virtual int available() = 0;
virtual int read() = 0; virtual int read() = 0;
virtual int peek() = 0;
virtual void flush() = 0; virtual void flush() = 0;
}; };

View File

@ -533,8 +533,12 @@ ISR(TIMER2_COMPA_vect)
} }
else else
{ {
disableTimer(2); // need to call noTone() so that the tone_pins[] entry is reset, so the
*timer2_pin_port &= ~(timer2_pin_mask); // keep pin low after stop // timer gets initialized next time we call tone().
// XXX: this assumes timer 2 is always the first one used.
noTone(tone_pins[0]);
// disableTimer(2);
// *timer2_pin_port &= ~(timer2_pin_mask); // keep pin low after stop
} }
} }

View File

@ -0,0 +1,168 @@
/*
WCharacter.h - Character utility functions for Wiring & Arduino
Copyright (c) 2010 Hernando Barragan. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef Character_h
#define Character_h
#include <ctype.h>
// WCharacter.h prototypes
inline boolean isAlphaNumeric(int c) __attribute__((always_inline));
inline boolean isAlpha(int c) __attribute__((always_inline));
inline boolean isAscii(int c) __attribute__((always_inline));
inline boolean isWhitespace(int c) __attribute__((always_inline));
inline boolean isControl(int c) __attribute__((always_inline));
inline boolean isDigit(int c) __attribute__((always_inline));
inline boolean isGraph(int c) __attribute__((always_inline));
inline boolean isLowerCase(int c) __attribute__((always_inline));
inline boolean isPrintable(int c) __attribute__((always_inline));
inline boolean isPunct(int c) __attribute__((always_inline));
inline boolean isSpace(int c) __attribute__((always_inline));
inline boolean isUpperCase(int c) __attribute__((always_inline));
inline boolean isHexadecimalDigit(int c) __attribute__((always_inline));
inline int toAscii(int c) __attribute__((always_inline));
inline int toLowerCase(int c) __attribute__((always_inline));
inline int toUpperCase(int c)__attribute__((always_inline));
// Checks for an alphanumeric character.
// It is equivalent to (isalpha(c) || isdigit(c)).
inline boolean isAlphaNumeric(int c)
{
return ( isalnum(c) == 0 ? false : true);
}
// Checks for an alphabetic character.
// It is equivalent to (isupper(c) || islower(c)).
inline boolean isAlpha(int c)
{
return ( isalpha(c) == 0 ? false : true);
}
// Checks whether c is a 7-bit unsigned char value
// that fits into the ASCII character set.
inline boolean isAscii(int c)
{
return ( isascii (c) == 0 ? false : true);
}
// Checks for a blank character, that is, a space or a tab.
inline boolean isWhitespace(int c)
{
return ( isblank (c) == 0 ? false : true);
}
// Checks for a control character.
inline boolean isControl(int c)
{
return ( iscntrl (c) == 0 ? false : true);
}
// Checks for a digit (0 through 9).
inline boolean isDigit(int c)
{
return ( isdigit (c) == 0 ? false : true);
}
// Checks for any printable character except space.
inline boolean isGraph(int c)
{
return ( isgraph (c) == 0 ? false : true);
}
// Checks for a lower-case character.
inline boolean isLowerCase(int c)
{
return (islower (c) == 0 ? false : true);
}
// Checks for any printable character including space.
inline boolean isPrintable(int c)
{
return ( isprint (c) == 0 ? false : true);
}
// Checks for any printable character which is not a space
// or an alphanumeric character.
inline boolean isPunct(int c)
{
return ( ispunct (c) == 0 ? false : true);
}
// Checks for white-space characters. For the avr-libc library,
// these are: space, formfeed ('\f'), newline ('\n'), carriage
// return ('\r'), horizontal tab ('\t'), and vertical tab ('\v').
inline boolean isSpace(int c)
{
return ( isspace (c) == 0 ? false : true);
}
// Checks for an uppercase letter.
inline boolean isUpperCase(int c)
{
return ( isupper (c) == 0 ? false : true);
}
// Checks for a hexadecimal digits, i.e. one of 0 1 2 3 4 5 6 7
// 8 9 a b c d e f A B C D E F.
inline boolean isHexadecimalDigit(int c)
{
return ( isxdigit (c) == 0 ? false : true);
}
// Converts c to a 7-bit unsigned char value that fits into the
// ASCII character set, by clearing the high-order bits.
inline int toAscii(int c)
{
return toascii (c);
}
// Warning:
// Many people will be unhappy if you use this function.
// This function will convert accented letters into random
// characters.
// Converts the letter c to lower case, if possible.
inline int toLowerCase(int c)
{
return tolower (c);
}
// Converts the letter c to upper case, if possible.
inline int toUpperCase(int c)
{
return toupper (c);
}
#endif

View File

@ -10,6 +10,7 @@
#include "wiring.h" #include "wiring.h"
#ifdef __cplusplus #ifdef __cplusplus
#include "WCharacter.h"
#include "WString.h" #include "WString.h"
#include "HardwareSerial.h" #include "HardwareSerial.h"

View File

@ -150,14 +150,16 @@ const String & String::operator+=( const String &other )
_length += other._length; _length += other._length;
if ( _length > _capacity ) if ( _length > _capacity )
{ {
char *temp = _buffer; char *temp = (char *)realloc(_buffer, _length + 1);
getBuffer( _length ); if ( temp != NULL ) {
if ( _buffer != NULL ) _buffer = temp;
strcpy( _buffer, temp ); _capacity = _length;
free(temp); } else {
_length -= other._length;
return *this;
}
} }
if ( _buffer != NULL ) strcat( _buffer, other._buffer );
strcat( _buffer, other._buffer );
return *this; return *this;
} }
@ -434,3 +436,8 @@ void String::toCharArray(char *buf, unsigned int bufsize)
strncpy(buf, _buffer, len); strncpy(buf, _buffer, len);
buf[len] = 0; buf[len] = 0;
} }
long String::toInt() {
return atol(_buffer);
}

View File

@ -78,6 +78,7 @@ class String
String trim( ) const; String trim( ) const;
void getBytes(unsigned char *buf, unsigned int bufsize); void getBytes(unsigned char *buf, unsigned int bufsize);
void toCharArray(char *buf, unsigned int bufsize); void toCharArray(char *buf, unsigned int bufsize);
long toInt( );
const String& concat( const String &str ); const String& concat( const String &str );
String replace( char oldChar, char newChar ); String replace( char oldChar, char newChar );
String replace( const String& match, const String& replace ); String replace( const String& match, const String& replace );

View File

@ -96,6 +96,7 @@ extern "C"{
#define bitClear(value, bit) ((value) &= ~(1UL << (bit))) #define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit)) #define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit))
typedef unsigned int word; typedef unsigned int word;
#define bit(b) (1UL << (b)) #define bit(b) (1UL << (b))

View File

@ -55,12 +55,15 @@ unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout)
return 0; return 0;
// wait for the pulse to stop // wait for the pulse to stop
while ((*portInputRegister(port) & bit) == stateMask) while ((*portInputRegister(port) & bit) == stateMask) {
if (numloops++ == maxloops)
return 0;
width++; width++;
}
// convert the reading to microseconds. The loop has been determined // convert the reading to microseconds. The loop has been determined
// to be 10 clock cycles long and have about 16 clocks between the edge // to be 20 clock cycles long and have about 16 clocks between the edge
// and the start of the loop. There will be some error introduced by // and the start of the loop. There will be some error introduced by
// the interrupt handlers. // the interrupt handlers.
return clockCyclesToMicroseconds(width * 10 + 16); return clockCyclesToMicroseconds(width * 21 + 16);
} }

View File

@ -1,131 +1,131 @@
:20000000A2C00000BBC00000B9C00000B7C00000B5C00000B3C00000B1C00000AFC000004B :20000000A2C00000BBC00000B9C00000B7C00000B5C00000B3C00000B1C00000AFC000004B
:20002000ADC00000ABC00000A9C0000023C40000A5C00000A3C00000A1C000009FC0000010 :20002000ADC00000ABC00000A9C000005AC400001EC40000A3C00000A1C000009FC000005C
:200040009DC000009BC0000099C0000097C0000095C0000093C0000091C0000004C100007A :200040009DC000009BC0000099C0000097C0000095C0000093C0000091C0000014C100006A
:200060008DC000008BC0000089C0000087C0000085C0000083C0000081C000007FC0000050 :200060008DC000008BC0000089C0000087C0000085C0000083C0000081C000007FC0000050
:200080007DC000007BC0000079C0000077C0000075C0000073C000001201100102000008E2 :200080007DC000007BC0000079C0000077C0000075C0000073C000001201100102000008E2
:2000A0004123100000000102DC0109023E00020100C0320904000001020201000524000171 :2000A0004123100001000102DC0109023E00020100C0320904000001020201000524000170
:2000C00010042402060524060001070582030800FF09040100020A000000070504024000AC :2000C00010042402060524060001070582030800FF09040100020A000000070504024000AC
:2000E0000007058302400000040309043203410072006400750069006E006F0020002800CC :2000E0000107058302400001040309043203410072006400750069006E006F0020002800CA
:200100007700770077002E00610072006400750069006E006F002E0063006300290000003D :200100007700770077002E00610072006400750069006E006F002E0063006300290000003D
:200120002403410072006400750069006E006F0020004D00650067006100200032003500A5 :200120002403410072006400750069006E006F0020004D00650067006100200032003500A5
:2001400036003000000011241FBECFEFD2E0DEBFCDBF11E0A0E0B1E0E0E7FFE002C005908F :2001400036003000000011241FBECFEFD2E0DEBFCDBF11E0A0E0B1E0E0EDFFE002C0059089
:200160000D92A631B107D9F712E0A6E1B1E001C01D92A033B107E1F7E2D0F8C641CF9C0187 :200160000D92A631B107D9F712E0A6E1B1E001C01D92AF32B107E1F7F1D028C741CF9C0139
:20018000DC01AE57BF4FED91FC91119741911196FC93EE9380589F4FE817F90711F42D93A9 :20018000DC01AE57BF4FED91FC91119741911196FC93EE9380589F4FE817F90711F42D93A9
:2001A0003C939FB7F894F901EC57FF4F8081815080839FBF842F089508950895FC0184893C :2001A0003C939FB7F894F901EC57FF4F8081815080839FBF842F0895DF92EF92FF920F935B
:2001C000813019F0823019F404C090E303C090E001C090E28389823009F498608589873091 :2001C0001F93FC018489813019F0823021F405C040E3D42E04C0DD2402C030E2D32E838952
:2001E00031F0883031F0863029F4926003C0946001C096601092C9001092C8001092CA0091 :2001E000823011F488E0D82A8589873031F0883031F0863031F482E003C084E001C086E094
:200200002785308941895289203081EE380780E0480780E0580711F082E001C080E08093D1 :20020000D82A1092C9001092C8001092CA00E784F0880189128980E0E81681EEF80680E068
:20022000C80088E98093C9009093CA00203081EE380780E0480780E0580719F420E130E032 :20022000080780E0180719F420E130E00FC0C801B701969587957795679560587B47814E2A
:200240000DC0CA01B901969587957795679560587B47814E9F4F68D6215030403093CD0017 :200240009F4FA8019701A0D6215030403093CD002093CC00D092CA0080E0E81681EEF80612
:200260002093CC0008951F920F920FB60F9211242F938F939F93EF93FF939091CE0080914B :2002600080E0080780E0180711F082E001C080E08093C80088E98093C9001F910F91FF9005
:2002800027028430F1F4E0919901F0919A019083E0919901F0919A01CF01019690939A0116 :20028000EF90DF9008951F920F920FB60F9211242F938F939F93EF93FF939091CE008EB38C
:2002A000809399018959914021F489E191E0928381839FB7F89480919D018F5F80939D01A5 :2002A0008430F1F4E0919901F0919A019083E0919901F0919A01CF01019690939A0180930C
:2002C0009FBFFF91EF919F918F912F910F900FBE0F901F901895FC01858580FF02C05F98FA :2002C00099018959914021F489E191E0928381839FB7F89480919D018F5F80939D019FBF3A
:2002E00008955F9A089580E091E0B4C580E091E067C584B7877F84BF28E10FB6F8942093F3 :2002E000FF91EF919F918F912F910F900FBE0F901F901895FC01858580FF02C05F9808959B
:200300006000109260000FBE87E690E09093CD008093CC0086E08093CA001092C8002093A2 :200300005F9A089580E091E0D5C580E091E088C584B7877F84BF28E10FB6F89420936000CD
:20032000C900539A5A9A8AB180638AB98BB180638BB995D284E085BD5F9A579A08950F9319 :20032000109260000FBE87E690E09093CD008093CC0086E08093CA001092C8002093C90019
:200340001F93CF93DF93D5DF2FB7F8948EE991E090931F0280931E02909321028093200217 :20034000539A5A9A8AB180638AB98BB180638BB983D284E085BD5F9A579A08950F931F9322
:200360002FBF2FB7F89489E191E090939A018093990190939C0180939B012FBF7894CEE9B7 :20036000CF93DF93D5DF2FB7F8948EE991E090931F0280931E0290932102809320022FBFBB
:20038000D1E003E080E091E08DD49C0197FD23C08FB7F894909122028FBF9038E1F0E09114 :200380002FB7F89489E191E090939A018093990190939C0180939B012FBF7894CEE9D1E0D4
:2003A0001E02F0911F022083E0911E02F0911F02CF01019690931F0280931E028E51924016 :2003A00003E08FB7F894909122028FBF903809F180E091E0ABD497FD1CC0E0911E02F09161
:2003C00011F4D283C1839FB7F894809122028F5F809322029FBF8FB7F89410919D018FBF86 :2003C0001F028083E0911E02F0911F02CF01019690931F0280931E028E51924011F4D283DD
:2003E000A89902C0113678F1A89A80919D01882361F05D980093160108C089E191E0BFDE7E :2003E000C1839FB7F894809122028F5F809322029FBF8FB7F89410919D018FBFA89902C0BD
:20040000682F80E091E0B7D411501123B1F780911601882351F08091160181508093160175 :20040000113678F1A89A80919D01882361F05D980093160108C089E191E0B1DE682F80E077
:2004200080911601882309F45D9A80911701882351F0809117018150809317018091170192 :2004200091E0DAD411501123B1F780911601882351F0809116018150809316018091160101
:20044000882309F45C9A8FB7F894909122028FBF992369F08EE991E092DE982F8091C8008C :20044000882309F45D9A80911701882351F08091170181508093170180911701882309F4F2
:2004600085FFFCCF9093CE005C980093170180E091E071D403D486CFDA01923049F09330C2 :200460005C9A8FB7F894909122028FBF992369F08EE991E084DE982F8091C80085FFFCCFD3
:2004800061F09130F9F4E8E9F0E022E130E01EC0EAEAF0E02EE330E019C0813049F0813092 :200480009093CE005C980093170180E091E095D42AD487CFDA01923049F0933061F0913093
:2004A00018F0823079F408C0E8EEF0E0849107C0ECEEF0E0849103C0E0E2F1E08491282F4A :2004A000F9F4E8E9F0E022E130E01EC0EAEAF0E02EE330E019C0813049F0813018F08230CA
:2004C00030E004C0E0E0F0E020E030E0ED93FC93C901089528E030E040E003C04F5F220F58 :2004C00079F408C0E8EEF0E0849107C0ECEEF0E0849103C0E0E2F1E08491282F30E004C010
:2004E000331F28173907D0F3842F8295807F08958093E9008091EB0081608093EB00109289 :2004E000E0E0F0E020E030E0ED93FC93C901089528E030E040E003C04F5F220F331F28177B
:20050000ED006093EC004093ED008091EE00881F8827881F08951092F40090E09093E900A4 :200500003907D0F3842F8295807F08958093E9008091EB0081608093EB001092ED00609319
:200520001092F0001092E8001092ED008091EB008E7F8093EB009F5F953081F70895809120 :20052000EC004093ED008091EE00881F8827881F08951092F40090E09093E9001092F000D2
:20054000280288239CF404C0809127028823B9F08091E80082FFF8CF8091E8008B77809395 :200540001092E8001092ED008091EB008E7F8093EB009F5F953081F70895809127028823BE
:20056000E800089580912702882349F08091E80080FFF8CF8091E8008E778093E800089503 :200560008CF403C08EB38823B1F08091E80082FFF9CF8091E8008B778093E80008958EB395
:2005800094E68091EC0080FF05C08091E80080FF05C025C08091E80082FD21C080912702EB :20058000882349F08091E80080FFF9CF8091E8008E778093E800089594E68091EC0080FFAB
:2005A000882311F482E0089580912702853011F483E008958091EB0085FF02C081E0089558 :2005A00005C08091E80080FF05C023C08091E80082FD1FC08EB3882311F482E008958EB3CE
:2005C0008091E10082FFDDCF8091E1008B7F8093E100992311F484E008959150D2CF80E068 :2005C000853011F483E008958091EB0085FF02C081E008958091E10082FFDFCF8091E1000E
:2005E00008959C0140912E0250912F024617570718F4F90120E03AC06115710511F0AB015A :2005E0008B7F8093E100992311F484E008959150D4CF80E008959C0140912D0250912E020C
:20060000F8CF8091E8008E778093E80040E050E0F0CF8091E80083FF02C081E008958091BF :200600004617570718F4F90120E038C06115710511F0AB01F8CF8091E8008E778093E800C8
:20062000E80082FD31C080912702882399F180912702853089F18091E80080FF17C090911A :2006200040E050E0F0CF8091E80083FF02C081E008958091E80082FD2DC08EB3882381F1AD
:20064000F20006C081918093F100415050409F5F4115510511F09830A8F320E0983009F4D8 :200640008EB3853079F18091E80080FF17C09091F20006C081918093F100415050409F5FDD
:2006600021E08091E8008E778093E8004115510581F6222371F608C080912702882351F0C3 :200660004115510511F09830A8F320E0983009F421E08091E8008E778093E80041155105FF
:2006800080912702853041F08091E80082FFF4CF80E0089582E0089583E008959C01409193 :2006800091F6222381F606C08EB3882349F08EB3853041F08091E80082FFF6CF80E00895C9
:2006A0002E0250912F024617570710F490E03DC06115710511F0AB01F9CF8091E8008E776D :2006A00082E0089583E008959C0140912D0250912E024617570710F490E03BC06115710577
:2006C0008093E80040E050E0F1CF8091E80083FF02C081E008958091E80082FD34C0809157 :2006C00011F0AB01F9CF8091E8008E778093E80040E050E0F1CF8091E80083FF02C081E0FE
:2006E00027028823B1F1809127028530A1F18091E80080FF1AC08091F20009C0F9012F5F5D :2006E00008958091E80082FD30C08EB3882399F18EB3853091F18091E80080FF1AC08091A4
:200700003F4FE491E093F100415050408F5F4115510511F0883090F390E0883009F491E0E5 :20070000F20009C0F9012F5F3F4FE491E093F100415050408F5F4115510511F0883090F338
:200720008091E8008E778093E8004115510569F6992359F608C080912702882351F08091AB :2007200090E0883009F491E08091E8008E778093E8004115510579F6992369F606C08EB3ED
:200740002702853041F08091E80082FFF4CF80E0089582E0089583E008959C0161157105C8 :20074000882349F08EB3853041F08091E80082FFF6CF80E0089582E0089583E008959C01B6
:2007600029F48091E8008B778093E800F90122C08091E80083FF02C081E008958091270215 :200760006115710529F48091E8008B778093E800F90120C08091E80083FF02C081E0089565
:20078000882351F180912702853041F18091E80082FFEECF06C08091F100819361507040D7 :200780008EB3882339F18EB3853031F18091E80082FFF0CF06C08091F100819361507040B5
:2007A00021F08091F2008823B1F78091E8008B778093E80061157105D9F608C0809127021F :2007A00021F08091F2008823B1F78091E8008B778093E80061157105E9F606C08EB388235F
:2007C000882351F080912702853041F08091E80080FFF4CF80E0089582E0089583E00895D6 :2007C00049F08EB3853041F08091E80080FFF6CF80E0089582E0089583E0089542D044D05A
:2007E00043D045D01092270210922502109224021092230284E089BD89B5826089BD09B4E1 :2007E0001EBA10922502109224021092230284E089BD89B5826089BD09B400FEFDCF809121
:2008000000FEFDCF8091D800982F9F779093D80080688093D800809163008E7F8093630083 :20080000D800982F9F779093D80080688093D800809163008E7F809363008091D8008F7D69
:200820008091D8008F7D8093D8008091E0008E7F8093E0008091E1008E7F8093E1008091E3 :200820008093D8008091E0008E7F8093E0008091E1008E7F8093E1008091E2008160809302
:20084000E20081608093E2008091E100877F8093E1008091E20088608093E2000895C0DFE8 :20084000E2008091E100877F8093E1008091E20088608093E2000895C1DF81E08093260221
:2008600081E08093260208951092E20008951092E10008951F920F920FB60F9211242F934F :2008600008951092E20008951092E10008951F920F920FB60F9211241F932F933F934F9385
:200880003F934F935F936F937F938F939F93AF93BF93EF93FF938091E10080FF1CC0809144 :200880005F936F937F938F939F93AF93BF93EF93FF93E9EEF0E0108117701082E0EFF0E066
:2008A000E20080FF18C08091E1008E7F8093E1008091E2008E7F8093E2008091E200806143 :2008A0008081877F80837894C3D0F894A9EEB0E01C92E0EFF0E08081886080831C93FF9164
:2008C0008093E2008091D80080628093D80019BC1092270272DC8091E10084FF2AC080910F :2008C000EF91BF91AF919F918F917F916F915F914F913F912F911F910F900FBE0F901F90DE
:2008E000E20084FF26C084E089BD89B5826089BD09B400FEFDCF8091D8008F7D8093D80036 :2008E00018951F920F920FB60F9211242F933F934F935F936F937F938F939F93AF93BF93FA
:200900008091E1008F7E8093E1008091E2008F7E8093E2008091E20081608093E200809115 :20090000EF93FF938091E10080FF1BC08091E20080FF17C08091E1008E7F8093E10080912A
:200920002502882311F481E001C084E08093270243DC8091E10083FF23C08091E20083FF33 :20092000E2008E7F8093E2008091E20080618093E2008091D80080628093D80019BC1EBAA7
:200940001FC08091E100877F8093E10082E080932702109225028091E1008E7F8093E10072 :20094000D1D18091E10084FF29C08091E20084FF25C084E089BD89B5826089BD09B400FE71
:200960008091E2008E7F8093E2008091E20080618093E200D0DD80E060E042E0B9DD7DD166 :20096000FDCF8091D8008F7D8093D8008091E1008F7E8093E1008091E2008F7E8093E200E3
:200980008091E10082FF0AC08091E20082FF06C08091E1008B7F8093E1006FD1FF91EF91A0 :200980008091E20081608093E20080912502882311F481E001C084E08EBBA4D18091E10070
:2009A000BF91AF919F918F917F916F915F914F913F912F910F900FBE0F901F9018951F93CE :2009A00083FF27C08091E20083FF23C08091E100877F8093E10082E08EBB10922502809105
:2009C000DF93CF93CDB7DEB7AC970FB6F894DEBF0FBECDBFE8E2F2E08091F100819322E0EC :2009C000E1008E7F8093E1008091E2008E7F8093E2008091E20080618093E200AADD80E090
:2009E000E033F207C9F78091280230912902353009F487C0363040F43130C9F1313070F0E5 :2009E00060E042E093DD8091F00088608093F00079D18091E10082FF0AC08091E20082FF3E
:200A0000333009F021C133C0383009F4F2C0393009F401C1363009F017C194C0803821F012 :200A000006C08091E1008B7F8093E1006BD1FF91EF91BF91AF919F918F917F916F915F91F4
:200A2000823809F011C108C09091230280912402882399F0926011C080912C0287708093AC :200A20004F913F912F910F900FBE0F901F9018951F93DF93CF93CDB7DEB7AC970FB6F894AC
:200A4000E9008091EB0090E025E0969587952A95E1F7982F91701092E9008091E800877F0C :200A4000DEBF0FBECDBFE7E2F2E08091F100819322E0EF32F207C9F78091270230912802EE
:200A60008093E8009093F1001092F100CDC0882319F0823009F0E8C090E08F719070009739 :200A6000353009F487C0363040F43130C9F1313070F0333009F01DC133C0383009F4EFC016
:200A800021F0029709F0E1C00CC080912A02813009F0DBC010922402333069F58093240202 :200A8000393009F4FEC0363009F013C192C0803821F0823809F00DC108C090912302809144
:200AA0002AC080912A02882331F520912C02277009F4CBC02093E9008091EB0080FFC5C0A4 :200AA0002402882399F0926011C080912B0287708093E9008091EB0090E025E09695879530
:200AC000333021F48091EB00806213C08091EB0080618093EB0081E090E002C0880F991F30 :200AC0002A95E1F7982F91701092E9008091E800877F8093E8009093F1001092F100CAC001
:200AE0002A95E2F78093EA001092EA008091EB0088608093EB001092E9008091E800877F69 :200AE000882319F0823009F0E4C090E08F719070009721F0029709F0DDC00CC080912902A4
:200B000086C0882309F0A0C010912A028091E800877F8093E80013DD05C08091270288232A :200B0000813009F0D7C010922402333069F5809324022AC080912902882331F520912B02FD
:200B200009F493C08091E80080FFF7CF812F8F7711F492E001C093E090932702806880937F :200B2000277009F4C7C02093E9008091EB0080FFC1C0333021F48091EB00806213C08091C8
:200B4000E30083C08058823008F07EC080912A0290912B0223E08C3D920799F55FB7F8948F :200B4000EB0080618093EB0081E090E002C0880F991F2A95E2F78093EA001092EA008091B7
:200B6000DE0115964EE020E030E061E2E42FF0E060935700849120FF03C082958F704F5F82 :200B6000EB0088608093EB001092E9008091E800877F83C0882309F09CC0109129028091FA
:200B8000982F9F70892F805D8A3308F0895F8C9311961C9211972F5F3F4F129624313105E2 :200B8000E800877F8093E800E8DC04C08EB3882309F490C08091E80080FFF8CF812F8F77B6
:200BA00029F75FBF8AE28B8383E08C838091E800877F8093E800CE0103966AE270E011DD1F :200BA00011F492E001C093E09EBB80688093E30081C08058823008F07CC0809129029091F7
:200BC00012C060912C02AE014F5F5F4F55DCBC01009709F43AC08091E800877F8093E800A3 :200BC0002A0223E08C3D920799F55FB7F894DE0115964EE020E030E061E2E42FF0E0609373
:200BE00089819A815BDD8091E8008B778093E8002CC0803849F58091E800877F8093E800C6 :200BE0005700849120FF03C082958F704F5F982F9F70892F805D8A3308F0895F8C93119615
:200C0000809125028093F1008091E8008E778093E80095DC1AC08823B9F490912A029230ED :200C00001C9211972F5F3F4F12962431310529F75FBF8AE28B8383E08C838091E800877F06
:200C2000A0F48091E800877F8093E8009093250286DC80912502882311F483E001C084E00A :200C20008093E800CE0103966AE270E0E4DC11C060912B02AE014F5F5F4F2CDCBC0100979F
:200C40008093270253DB01C04EDB8091E80083FF0AC08091EB0080628093EB008091E80026 :200C4000C9F18091E800877F8093E80089819A812BDD8091E8008B778093E8002BC080381A
:200C6000877F8093E800AC960FB6F894DEBF0FBECDBFCF91DF911F91089508951F9380916D :200C600041F58091E800877F8093E800809125028093F1008091E8008E778093E8006DDCC6
:200C80002702882361F01091E9001092E9008091E80083FF01C093DE17701093E9001F91AA :200C800019C08823B1F490912902923098F48091E800877F8093E800909325025EDC809102
:200CA00008950895FC0180912702843021F587859089A189B2890097A105B105E1F08581A5 :200CA0002502882311F483E001C084E08EBB2DDB01C028DB8091E80083FF0AC08091EB007F
:200CC0008093E9008091E80082FF15C08091F200882319F42FEF3FEF04C08091F100282FA5 :200CC00080628093EB008091E800877F8093E800AC960FB6F894DEBF0FBECDBFCF91DF91E1
:200CE00030E08091F200882341F48091E8008B778093E80002C02FEF3FEFC9010895FC0199 :200CE0001F91089508951F938EB3882361F01091E9001092E9008091E80083FF01C098DE54
:200D000080912702843011F587859089A189B2890097A105B105D1F081818093E900809192 :200D000017701093E9001F9108950895FC018EB3843021F587859089A189B2890097A10507
:200D2000F2008823A9F09091E8008091E8008E778093E80095FD0CC023DC982F882349F46F :200D2000B105E1F085818093E9008091E80082FF15C08091F200882319F42FEF3FEF04C010
:200D40008091E8008E778093E80003C092E001C090E0892F0895FC0180912702843051F4AF :200D40008091F100282F30E08091F200882341F48091E8008B778093E80002C02FEF3FEF43
:200D600087859089A189B2890097A105B10511F0CF01C5CF08951F93FC01162F80912702C6 :200D6000C9010895FC018EB3843011F587859089A189B2890097A105B105D1F081818093C1
:200D80008430D9F487859089A189B2890097A105B10599F081818093E9008091E80085FD53 :200D8000E9008091F2008823A9F09091E8008091E8008E778093E80095FD0CC0FDDB982F24
:200DA00008C08091E8008E778093E800E9DB882329F41093F10080E001C082E01F91089582 :200DA000882349F48091E8008E778093E80003C092E001C090E0892F0895FC018EB38430A5
:200DC0000F931F93CF93DF93EC010D96FC0189E0DF011D928A95E9F72A813B8109818C8169 :200DC00051F487859089A189B2890097A105B10511F0CF01C7CF08951F93FC01162F8EB318
:200DE000882311F410E001C014E0C90173DB182B1260802F61E8412F7BDB882329F12E819F :200DE0008430D9F487859089A189B2890097A105B10599F081818093E9008091E80085FDF3
:200E00003F810D818885882311F410E001C014E0C90160DB182B1260802F60E8412F68DBBE :200E000008C08091E8008E778093E800C5DB882329F41093F10080E001C082E01F91089545
:200E2000882391F02A853B8509858C85882311F410E001C014E0C9014DDB182B1260802FCD :200E20000F931F93CF93DF93EC010D96FC0189E0DF011D928A95E9F72A813B8109818C8108
:200E400061EC412F55DB01C080E0DF91CF911F910F910895CF93DF93EC018091E80083FF8B :200E4000882311F410E001C014E0C90151DB182B1260802F61E8412F59DB882329F12E8182
:200E600060C0888190E020912C0230912D022817390709F056C080912902813261F0823288 :200E60003F810D818885882311F410E001C014E0C9013EDB182B1260802F60E8412F46DBA2
:200E800020F4803209F04DC019C0823269F1833209F047C038C080912802813A09F041C002 :200E8000882391F02A853B8509858C85882311F410E001C014E0C9012BDB182B1260802F8F
:200EA0008091E800877F8093E800CE010F9667E070E097DB8091E8008B7713C080912802B2 :200EA00061EC412F33DB01C080E0DF91CF911F910F910895CF93DF93EC018091E80083FF4D
:200EC000813279F58091E800877F8093E800CE010F9667E070E041DCCE0170D98091E800BE :200EC00060C0888190E020912B0230912C022817390709F056C080912802813261F082322B
:200EE0008E778093E8001DC0809128028132C9F48091E800877F8093E80080912A028D871F :200EE00020F4803209F04DC019C0823269F1833209F047C038C080912702813A09F041C0A3
:200F0000CE01E9D90DC080912802813251F48091E800877F8093E800CE0160912A02C1DEBB :200F00008091E800877F8093E800CE010F9667E070E071DB8091E8008B7713C08091270278
:200F20000EDBDF91CF910895A1E21A2EAA1BBB1BFD010DC0AA1FBB1FEE1FFF1FA217B307E9 :200F2000813279F58091E800877F8093E800CE010F9667E070E013DCCE013ED98091E800BD
:200F4000E407F50720F0A21BB30BE40BF50B661F771F881F991F1A9469F760957095809599 :200F40008E778093E8001DC0809127028132C9F48091E800877F8093E800809129028D87C0
:200F600090959B01AC01BD01CF010895F894FFCF00034000000440000002080000000000ED :200F6000CE01C8D90DC080912702813251F48091E800877F8093E800CE0160912902C5DE7A
:200F8000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6B :200F8000ECDADF91CF910895A1E21A2EAA1BBB1BFD010DC0AA1FBB1FEE1FFF1FA217B307AC
:200FA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF51 :200FA000E407F50720F0A21BB30BE40BF50B661F771F881F991F1A9469F760957095809539
:200FC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF31 :200FC00090959B01AC01BD01CF010895F894FFCF000340000004400000020800000000008D
:200FE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF11 :200FE000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0B
:201000004BC0000064C0000062C0000060C000005EC000005CC000005AC0000058C00000F3 :201000004BC0000064C0000062C0000060C000005EC000005CC000005AC0000058C00000F3
:2010200056C0000054C0000052C00000CBC400004EC000004CC000004AC0000048C00000B9 :2010200056C0000054C0000052C00000CBC400004EC000004CC000004AC0000048C00000B9
:2010400046C0000044C0000042C0000040C000003EC000003CC000003AC0000038C0000098 :2010400046C0000044C0000042C0000040C000003EC000003CC000003AC0000038C0000098

View File

@ -1,130 +1,130 @@
:200000009CC00000B5C00000B3C00000B1C00000AFC00000ADC00000ABC00000A9C000007B :200000009CC00000B5C00000B3C00000B1C00000AFC00000ADC00000ABC00000A9C000007B
:20002000A7C00000A5C00000A3C000001DC400009FC000009DC000009BC0000099C0000040 :20002000A7C00000A5C00000A3C0000054C4000018C400009DC000009BC0000099C000008C
:2000400097C0000095C0000093C0000091C000008FC000008DC000008BC00000FEC00000AB :2000400097C0000095C0000093C0000091C000008FC000008DC000008BC000000EC100009A
:2000600087C0000085C0000083C0000081C000007FC000007DC000007BC0000079C0000080 :2000600087C0000085C0000083C0000081C000007FC000007DC000007BC0000079C0000080
:2000800077C0000075C0000073C0000071C000006FC000006DC00000120110010200000806 :2000800077C0000075C0000073C0000071C000006FC000006DC00000120110010200000806
:2000A0004123010000000102DC0109023E00020100C0320904000001020201000524000180 :2000A0004123010001000102DC0109023E00020100C032090400000102020100052400017F
:2000C00010042402060524060001070582030800FF09040100020A000000070504024000AC :2000C00010042402060524060001070582030800FF09040100020A000000070504024000AC
:2000E0000007058302400000040309043203410072006400750069006E006F0020002800CC :2000E0000107058302400001040309043203410072006400750069006E006F0020002800CA
:200100007700770077002E00610072006400750069006E006F002E0063006300290000003D :200100007700770077002E00610072006400750069006E006F002E0063006300290000003D
:200120001803410072006400750069006E006F00200055006E006F00000011241FBECFEFB0 :200120001803410072006400750069006E006F00200055006E006F00000011241FBECFEFB0
:20014000D2E0DEBFCDBF11E0A0E0B1E0E4E6FFE002C005900D92A631B107D9F712E0A6E14B :20014000D2E0DEBFCDBF11E0A0E0B1E0E4ECFFE002C005900D92A631B107D9F712E0A6E145
:20016000B1E001C01D92A033B107E1F7E2D0F8C647CF9C01DC01AE57BF4FED91FC91119755 :20016000B1E001C01D92AF32B107E1F7F1D028C747CF9C01DC01AE57BF4FED91FC91119707
:2001800041911196FC93EE9380589F4FE817F90711F42D933C939FB7F894F901EC57FF4F10 :2001800041911196FC93EE9380589F4FE817F90711F42D933C939FB7F894F901EC57FF4F10
:2001A0008081815080839FBF842F089508950895FC018489813019F0823019F404C090E3C8 :2001A0008081815080839FBF842F0895DF92EF92FF920F931F93FC018489813019F082306F
:2001C00003C090E001C090E28389823009F498608589873031F0883031F0863029F4926082 :2001C00021F405C040E3D42E04C0DD2402C030E2D32E8389823011F488E0D82A8589873094
:2001E00003C0946001C096601092C9001092C8001092CA002785308941895289203081EE87 :2001E00031F0883031F0863031F482E003C084E001C086E0D82A1092C9001092C800109201
:20020000380780E0480780E0580711F082E001C080E08093C80088E98093C9009093CA0098 :20020000CA00E784F0880189128980E0E81681EEF80680E0080780E0180719F420E130E035
:20022000203081EE380780E0480780E0580719F420E130E00DC0CA01B9019695879577958F :200220000FC0C801B701969587957795679560587B47814E9F4FA8019701A0D62150304050
:20024000679560587B47814E9F4F68D6215030403093CD002093CC0008951F920F920FB689 :200240003093CD002093CC00D092CA0080E0E81681EEF80680E0080780E0180711F082E047
:200260000F9211242F938F939F93EF93FF939091CE00809127028430F1F4E0919901F09130 :2002600001C080E08093C80088E98093C9001F910F91FF90EF90DF9008951F920F920FB6B4
:200280009A019083E0919901F0919A01CF01019690939A01809399018959914021F489E185 :200280000F9211242F938F939F93EF93FF939091CE008EB38430F1F4E0919901F0919A016E
:2002A00091E0928381839FB7F89480919D018F5F80939D019FBFFF91EF919F918F912F9106 :2002A0009083E0919901F0919A01CF01019690939A01809399018959914021F489E191E08F
:2002C0000F900FBE0F901F901895FC01858580FF02C05F9808955F9A089580E091E0B4C5FB :2002C000928381839FB7F89480919D018F5F80939D019FBFFF91EF919F918F912F910F90B8
:2002E00080E091E067C584B7877F84BF28E10FB6F89420936000109260000FBE87E690E064 :2002E0000FBE0F901F901895FC01858580FF02C05F9808955F9A089580E091E0D5C580E0F9
:200300009093CD008093CC0086E08093CA001092C8002093C900539A5A9A8AB180638AB9A3 :2003000091E088C584B7877F84BF28E10FB6F89420936000109260000FBE87E690E090935F
:200320008BB180638BB995D284E085BD5F9A579A08950F931F93CF93DF93D5DF2FB7F89478 :20032000CD008093CC0086E08093CA001092C8002093C900539A5A9A8AB180638AB98BB16A
:200340008EE991E090931F0280931E0290932102809320022FBF2FB7F89489E191E0909365 :2003400080638BB983D284E085BD5F9A579A08950F931F93CF93DF93D5DF2FB7F8948EE92F
:200360009A018093990190939C0180939B012FBF7894CEE9D1E003E080E091E08DD49C01B2 :2003600091E090931F0280931E0290932102809320022FBF2FB7F89489E191E090939A0121
:2003800097FD23C08FB7F894909122028FBF9038E1F0E0911E02F0911F022083E0911E0281 :200380008093990190939C0180939B012FBF7894CEE9D1E003E08FB7F894909122028FBF97
:2003A000F0911F02CF01019690931F0280931E028E51924011F4D283C1839FB7F89480917B :2003A000903809F180E091E0ABD497FD1CC0E0911E02F0911F028083E0911E02F0911F0252
:2003C00022028F5F809322029FBF8FB7F89410919D018FBFA89902C0113678F1A89A809111 :2003C000CF01019690931F0280931E028E51924011F4D283C1839FB7F894809122028F5FEB
:2003E0009D01882361F05D980093160108C089E191E0BFDE682F80E091E0B7D411501123FC :2003E000809322029FBF8FB7F89410919D018FBFA89902C0113678F1A89A80919D018823BA
:20040000B1F780911601882351F08091160181508093160180911601882309F45D9A809125 :2004000061F05D980093160108C089E191E0B1DE682F80E091E0DAD411501123B1F7809156
:200420001701882351F08091170181508093170180911701882309F45C9A8FB7F8949091D9 :200420001601882351F08091160181508093160180911601882309F45D9A809117018823FB
:2004400022028FBF992369F08EE991E092DE982F8091C80085FFFCCF9093CE005C98009356 :2004400051F08091170181508093170180911701882309F45C9A8FB7F894909122028FBF0A
:20046000170180E091E071D403D486CFDA01923049F0933061F09130F9F4E8E9F0E022E1E6 :20046000992369F08EE991E084DE982F8091C80085FFFCCF9093CE005C980093170180E03E
:2004800030E01EC0EAEAF0E02EE330E019C0813049F0813018F0823079F408C0E8EEF0E0A0 :2004800091E095D42AD487CFDA01923049F0933061F09130F9F4E8E9F0E022E130E01EC004
:2004A000849107C0ECEEF0E0849103C0E0E2F1E08491282F30E004C0E0E0F0E020E030E06B :2004A000EAEAF0E02EE330E019C0813049F0813018F0823079F408C0E8EEF0E0849107C092
:2004C000ED93FC93C901089528E030E040E003C04F5F220F331F28173907D0F3842F82956E :2004C000ECEEF0E0849103C0E0E2F1E08491282F30E004C0E0E0F0E020E030E0ED93FC9318
:2004E000807F08958093E9008091EB0081608093EB001092ED006093EC004093ED0080914A :2004E000C901089528E030E040E003C04F5F220F331F28173907D0F3842F8295807F0895C1
:20050000EE00881F8827881F08951092F40090E09093E9001092F0001092E8001092ED0096 :200500008093E9008091EB0081608093EB001092ED006093EC004093ED008091EE00881F30
:200520008091EB008E7F8093EB009F5F953081F708958091280288239CF404C08091270268 :200520008827881F08951092F40090E09093E9001092F0001092E8001092ED008091EB000F
:200540008823B9F08091E80082FFF8CF8091E8008B778093E800089580912702882349F055 :200540008E7F8093EB009F5F953081F708958091270288238CF403C08EB38823B1F08091F2
:200560008091E80080FFF8CF8091E8008E778093E800089594E68091EC0080FF05C08091DA :20056000E80082FFF9CF8091E8008B778093E80008958EB3882349F08091E80080FFF9CF52
:20058000E80080FF05C025C08091E80082FD21C080912702882311F482E0089580912702CE :200580008091E8008E778093E800089594E68091EC0080FF05C08091E80080FF05C023C0EA
:2005A000853011F483E008958091EB0085FF02C081E008958091E10082FFDDCF8091E10030 :2005A0008091E80082FD1FC08EB3882311F482E008958EB3853011F483E008958091EB00FD
:2005C0008B7F8093E100992311F484E008959150D2CF80E008959C0140912E0250912F022C :2005C00085FF02C081E008958091E10082FFDFCF8091E1008B7F8093E100992311F484E0A1
:2005E0004617570718F4F90120E03AC06115710511F0AB01F8CF8091E8008E778093E800E7 :2005E00008959150D4CF80E008959C0140912D0250912E024617570718F4F90120E038C076
:2006000040E050E0F0CF8091E80083FF02C081E008958091E80082FD31C080912702882342 :200600006115710511F0AB01F8CF8091E8008E778093E80040E050E0F0CF8091E80083FFF7
:2006200099F180912702853089F18091E80080FF17C09091F20006C081918093F1004150F8 :2006200002C081E008958091E80082FD2DC08EB3882381F18EB3853079F18091E80080FF5F
:2006400050409F5F4115510511F09830A8F320E0983009F421E08091E8008E778093E8003D :2006400017C09091F20006C081918093F100415050409F5F4115510511F09830A8F320E0A5
:200660004115510581F6222371F608C080912702882351F080912702853041F08091E800A4 :20066000983009F421E08091E8008E778093E8004115510591F6222381F606C08EB388231A
:2006800082FFF4CF80E0089582E0089583E008959C0140912E0250912F024617570710F4AB :2006800049F08EB3853041F08091E80082FFF6CF80E0089582E0089583E008959C01409151
:2006A00090E03DC06115710511F0AB01F9CF8091E8008E778093E80040E050E0F1CF809152 :2006A0002D0250912E024617570710F490E03BC06115710511F0AB01F9CF8091E8008E7771
:2006C000E80083FF02C081E008958091E80082FD34C0809127028823B1F18091270285300E :2006C0008093E80040E050E0F1CF8091E80083FF02C081E008958091E80082FD30C08EB32B
:2006E000A1F18091E80080FF1AC08091F20009C0F9012F5F3F4FE491E093F100415050403A :2006E000882399F18EB3853091F18091E80080FF1AC08091F20009C0F9012F5F3F4FE491A4
:200700008F5F4115510511F0883090F390E0883009F491E08091E8008E778093E80041151E :20070000E093F100415050408F5F4115510511F0883090F390E0883009F491E08091E800EF
:20072000510569F6992359F608C080912702882351F080912702853041F08091E80082FF71 :200720008E778093E8004115510579F6992369F606C08EB3882349F08EB3853041F0809160
:20074000F4CF80E0089582E0089583E008959C016115710529F48091E8008B778093E8003E :20074000E80082FFF6CF80E0089582E0089583E008959C016115710529F48091E8008B77CE
:20076000F90122C08091E80083FF02C081E0089580912702882351F180912702853041F11A :200760008093E800F90120C08091E80083FF02C081E008958EB3882339F18EB3853031F13B
:200780008091E80082FFEECF06C08091F10081936150704021F08091F2008823B1F780916D :200780008091E80082FFF0CF06C08091F10081936150704021F08091F2008823B1F780916B
:2007A000E8008B778093E80061157105D9F608C080912702882351F080912702853041F08B :2007A000E8008B778093E80061157105E9F606C08EB3882349F08EB3853041F08091E8007E
:2007C0008091E80080FFF4CF80E0089582E0089583E0089543D045D0109227021092250226 :2007C00080FFF6CF80E0089582E0089583E0089542D044D01EBA10922502109224021092A8
:2007E000109224021092230284E089BD89B5826089BD09B400FEFDCF8091D800982F9F770D :2007E000230284E089BD89B5826089BD09B400FEFDCF8091D800982F9F779093D800806894
:200800009093D80080688093D800809163008E7F809363008091D8008F7D8093D800809122 :200800008093D800809163008E7F809363008091D8008F7D8093D8008091E0008E7F809305
:20082000E0008E7F8093E0008091E1008E7F8093E1008091E20081608093E2008091E1002A :20082000E0008091E1008E7F8093E1008091E20081608093E2008091E100877F8093E10030
:20084000877F8093E1008091E20088608093E2000895C0DF81E08093260208951092E200D5 :200840008091E20088608093E2000895C1DF81E08093260208951092E20008951092E100AE
:2008600008951092E10008951F920F920FB60F9211242F933F934F935F936F937F938F9330 :2008600008951F920F920FB60F9211241F932F933F934F935F936F937F938F939F93AF932A
:200880009F93AF93BF93EF93FF938091E10080FF1CC08091E20080FF18C08091E1008E7FE8 :20088000BF93EF93FF93E9EEF0E0108117701082E0EFF0E08081877F80837894C3D0F894CD
:2008A0008093E1008091E2008E7F8093E2008091E20080618093E2008091D80080628093A8 :2008A000A9EEB0E01C92E0EFF0E08081886080831C93FF91EF91BF91AF919F918F917F9129
:2008C000D80019BC1092270272DC8091E10084FF2AC08091E20084FF26C084E089BD89B5AF :2008C0006F915F914F913F912F911F910F900FBE0F901F9018951F920F920FB60F921124B4
:2008E000826089BD09B400FEFDCF8091D8008F7D8093D8008091E1008F7E8093E100809165 :2008E0002F933F934F935F936F937F938F939F93AF93BF93EF93FF938091E10080FF1BC034
:20090000E2008F7E8093E2008091E20081608093E20080912502882311F481E001C084E0BC :200900008091E20080FF17C08091E1008E7F8093E1008091E2008E7F8093E2008091E200B3
:200920008093270243DC8091E10083FF23C08091E20083FF1FC08091E100877F8093E100C5 :2009200080618093E2008091D80080628093D80019BC1EBAD1D18091E10084FF29C080916D
:2009400082E080932702109225028091E1008E7F8093E1008091E2008E7F8093E200809137 :20094000E20084FF25C084E089BD89B5826089BD09B400FEFDCF8091D8008F7D8093D800D6
:20096000E20080618093E200D0DD80E060E042E0B9DD7DD18091E10082FF0AC08091E2003C :200960008091E1008F7E8093E1008091E2008F7E8093E2008091E20081608093E2008091B5
:2009800082FF06C08091E1008B7F8093E1006FD1FF91EF91BF91AF919F918F917F916F91E0 :200980002502882311F481E001C084E08EBBA4D18091E10083FF27C08091E20083FF23C089
:2009A0005F914F913F912F910F900FBE0F901F9018951F93DF93CF93CDB7DEB7AC970FB6C9 :2009A0008091E100877F8093E10082E08EBB109225028091E1008E7F8093E1008091E200F1
:2009C000F894DEBF0FBECDBFE8E2F2E08091F100819322E0E033F207C9F780912802309119 :2009C0008E7F8093E2008091E20080618093E200AADD80E060E042E093DD8091F0008860AA
:2009E0002902353009F487C0363040F43130C9F1313070F0333009F021C133C0383009F417 :2009E0008093F00079D18091E10082FF0AC08091E20082FF06C08091E1008B7F8093E10043
:200A0000F2C0393009F401C1363009F017C194C0803821F0823809F011C108C09091230215 :200A00006BD1FF91EF91BF91AF919F918F917F916F915F914F913F912F910F900FBE0F902F
:200A200080912402882399F0926011C080912C0287708093E9008091EB0090E025E09695BA :200A20001F9018951F93DF93CF93CDB7DEB7AC970FB6F894DEBF0FBECDBFE7E2F2E0809185
:200A400087952A95E1F7982F91701092E9008091E800877F8093E8009093F1001092F100EF :200A4000F100819322E0EF32F207C9F78091270230912802353009F487C0363040F43130EC
:200A6000CDC0882319F0823009F0E8C090E08F719070009721F0029709F0E1C00CC08091BA :200A6000C9F1313070F0333009F01DC133C0383009F4EFC0393009F4FEC0363009F013C163
:200A80002A02813009F0DBC010922402333069F5809324022AC080912A02882331F520917A :200A800092C0803821F0823809F00DC108C09091230280912402882399F0926011C080916D
:200AA0002C02277009F4CBC02093E9008091EB0080FFC5C0333021F48091EB00806213C024 :200AA0002B0287708093E9008091EB0090E025E0969587952A95E1F7982F91701092E90074
:200AC0008091EB0080618093EB0081E090E002C0880F991F2A95E2F78093EA001092EA0038 :200AC0008091E800877F8093E8009093F1001092F100CAC0882319F0823009F0E4C090E078
:200AE0008091EB0088608093EB001092E9008091E800877F86C0882309F0A0C010912A0273 :200AE0008F719070009721F0029709F0DDC00CC080912902813009F0D7C0109224023330AB
:200B00008091E800877F8093E80013DD05C080912702882309F493C08091E80080FFF7CFB3 :200B000069F5809324022AC080912902882331F520912B02277009F4C7C02093E9008091A1
:200B2000812F8F7711F492E001C093E09093270280688093E30083C08058823008F07EC027 :200B2000EB0080FFC1C0333021F48091EB00806213C08091EB0080618093EB0081E090E0F5
:200B400080912A0290912B0223E08C3D920799F55FB7F894DE0115964EE020E030E061E26A :200B400002C0880F991F2A95E2F78093EA001092EA008091EB0088608093EB001092E900F6
:200B6000E42FF0E060935700849120FF03C082958F704F5F982F9F70892F805D8A3308F06D :200B60008091E800877F83C0882309F09CC0109129028091E800877F8093E800E8DC04C0E5
:200B8000895F8C9311961C9211972F5F3F4F12962431310529F75FBF8AE28B8383E08C83D8 :200B80008EB3882309F490C08091E80080FFF8CF812F8F7711F492E001C093E09EBB80683B
:200BA0008091E800877F8093E800CE0103966AE270E011DD12C060912C02AE014F5F5F4F4D :200BA0008093E30081C08058823008F07CC08091290290912A0223E08C3D920799F55FB7AE
:200BC00055DCBC01009709F43AC08091E800877F8093E80089819A815BDD8091E8008B7747 :200BC000F894DE0115964EE020E030E061E2E42FF0E060935700849120FF03C082958F7044
:200BE0008093E8002CC0803849F58091E800877F8093E800809125028093F1008091E800E9 :200BE0004F5F982F9F70892F805D8A3308F0895F8C9311961C9211972F5F3F4F129624310A
:200C00008E778093E80095DC1AC08823B9F490912A029230A0F48091E800877F8093E80094 :200C0000310529F75FBF8AE28B8383E08C838091E800877F8093E800CE0103966AE270E076
:200C20009093250286DC80912502882311F483E001C084E08093270253DB01C04EDB809133 :200C2000E4DC11C060912B02AE014F5F5F4F2CDCBC010097C9F18091E800877F8093E800EA
:200C4000E80083FF0AC08091EB0080628093EB008091E800877F8093E800AC960FB6F894F7 :200C400089819A812BDD8091E8008B778093E8002BC0803841F58091E800877F8093E8009E
:200C6000DEBF0FBECDBFCF91DF911F91089508951F9380912702882361F01091E9001092B0 :200C6000809125028093F1008091E8008E778093E8006DDC19C08823B1F4909129029230BF
:200C8000E9008091E80083FF01C093DE17701093E9001F9108950895FC01809127028430D6 :200C800098F48091E800877F8093E800909325025EDC80912502882311F483E001C084E0DA
:200CA00021F587859089A189B2890097A105B105E1F085818093E9008091E80082FF15C07F :200CA0008EBB2DDB01C028DB8091E80083FF0AC08091EB0080628093EB008091E800877FFF
:200CC0008091F200882319F42FEF3FEF04C08091F100282F30E08091F200882341F48091EC :200CC0008093E800AC960FB6F894DEBF0FBECDBFCF91DF911F91089508951F938EB3882338
:200CE000E8008B778093E80002C02FEF3FEFC9010895FC0180912702843011F58785908984 :200CE00061F01091E9001092E9008091E80083FF01C098DE17701093E9001F9108950895DF
:200D0000A189B2890097A105B105D1F081818093E9008091F2008823A9F09091E80080915B :200D0000FC018EB3843021F587859089A189B2890097A105B105E1F085818093E90080916A
:200D2000E8008E778093E80095FD0CC023DC982F882349F48091E8008E778093E80003C003 :200D2000E80082FF15C08091F200882319F42FEF3FEF04C08091F100282F30E08091F2003E
:200D400092E001C090E0892F0895FC0180912702843051F487859089A189B2890097A105A4 :200D4000882341F48091E8008B778093E80002C02FEF3FEFC9010895FC018EB3843011F550
:200D6000B10511F0CF01C5CF08951F93FC01162F809127028430D9F487859089A189B28982 :200D600087859089A189B2890097A105B105D1F081818093E9008091F2008823A9F09091CF
:200D80000097A105B10599F081818093E9008091E80085FD08C08091E8008E778093E8009D :200D8000E8008091E8008E778093E80095FD0CC0FDDB982F882349F48091E8008E7780937C
:200DA000E9DB882329F41093F10080E001C082E01F9108950F931F93CF93DF93EC010D968B :200DA000E80003C092E001C090E0892F0895FC018EB3843051F487859089A189B289009738
:200DC000FC0189E0DF011D928A95E9F72A813B8109818C81882311F410E001C014E0C90102 :200DC000A105B10511F0CF01C7CF08951F93FC01162F8EB38430D9F487859089A189B28973
:200DE00073DB182B1260802F61E8412F7BDB882329F12E813F810D818885882311F410E0C3 :200DE0000097A105B10599F081818093E9008091E80085FD08C08091E8008E778093E8003D
:200E000001C014E0C90160DB182B1260802F60E8412F68DB882391F02A853B8509858C857F :200E0000C5DB882329F41093F10080E001C082E01F9108950F931F93CF93DF93EC010D964E
:200E2000882311F410E001C014E0C9014DDB182B1260802F61EC412F55DB01C080E0DF9189 :200E2000FC0189E0DF011D928A95E9F72A813B8109818C81882311F410E001C014E0C901A1
:200E4000CF911F910F910895CF93DF93EC018091E80083FF60C0888190E020912C023091D0 :200E400051DB182B1260802F61E8412F59DB882329F12E813F810D818885882311F410E0A6
:200E60002D022817390709F056C080912902813261F0823220F4803209F04DC019C0823268 :200E600001C014E0C9013EDB182B1260802F60E8412F46DB882391F02A853B8509858C8563
:200E800069F1833209F047C038C080912802813A09F041C08091E800877F8093E800CE0192 :200E8000882311F410E001C014E0C9012BDB182B1260802F61EC412F33DB01C080E0DF916D
:200EA0000F9667E070E097DB8091E8008B7713C080912802813279F58091E800877F809348 :200EA000CF911F910F910895CF93DF93EC018091E80083FF60C0888190E020912B02309171
:200EC000E800CE010F9667E070E041DCCE0170D98091E8008E778093E8001DC080912802D9 :200EC0002C022817390709F056C080912802813261F0823220F4803209F04DC019C082320A
:200EE0008132C9F48091E800877F8093E80080912A028D87CE01E9D90DC0809128028132EB :200EE00069F1833209F047C038C080912702813A09F041C08091E800877F8093E800CE0133
:200F000051F48091E800877F8093E800CE0160912A02C1DE0EDBDF91CF910895A1E21A2EE6 :200F00000F9667E070E071DB8091E8008B7713C080912702813279F58091E800877F80930E
:200F2000AA1BBB1BFD010DC0AA1FBB1FEE1FFF1FA217B307E407F50720F0A21BB30BE40BA9 :200F2000E800CE010F9667E070E013DCCE013ED98091E8008E778093E8001DC080912702D9
:200F4000F50B661F771F881F991F1A9469F760957095809590959B01AC01BD01CF01089561 :200F40008132C9F48091E800877F8093E800809129028D87CE01C8D90DC0809127028132AD
:200F6000F894FFCF00034000000440000002080000000000000000000000FFFFFFFFFFFF8C :200F600051F48091E800877F8093E800CE0160912902C5DEECDADF91CF910895A1E21A2EA6
:200F8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF71 :200F8000AA1BBB1BFD010DC0AA1FBB1FEE1FFF1FA217B307E407F50720F0A21BB30BE40B49
:200FA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF51 :200FA000F50B661F771F881F991F1A9469F760957095809590959B01AC01BD01CF01089501
:200FC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF31 :200FC000F894FFCF00034000000440000002080000000000000000000000FFFFFFFFFFFF2C
:200FE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF11 :200FE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF11
:201000004BC0000064C0000062C0000060C000005EC000005CC000005AC0000058C00000F3 :201000004BC0000064C0000062C0000060C000005EC000005CC000005AC0000058C00000F3
:2010200056C0000054C0000052C00000CBC400004EC000004CC000004AC0000048C00000B9 :2010200056C0000054C0000052C00000CBC400004EC000004CC000004AC0000048C00000B9

View File

@ -0,0 +1,256 @@
:10000000A2C00000BBC00000B9C00000B7C0000023
:10001000B5C00000B3C00000B1C00000AFC0000018
:10002000ADC00000ABC00000A9C000005AC4000071
:100030001EC40000A3C00000A1C000009FC00000BB
:100040009DC000009BC0000099C0000097C0000048
:1000500095C0000093C0000091C0000014C10000D2
:100060008DC000008BC0000089C0000087C0000068
:1000700085C0000083C0000081C000007FC0000078
:100080007DC000007BC0000079C0000077C0000088
:1000900075C0000073C000001201100102000008CA
:1000A0004123100001000102DC0109023E000201AF
:1000B00000C0320904000001020201000524000111
:1000C0001004240206052406000107058203080027
:1000D000FF09040100020A000000070504024000B5
:1000E00001070583024000010403090432034100B3
:1000F00072006400750069006E006F002000280027
:100100007700770077002E006100720064007500B0
:1001100069006E006F002E0063006300290000007C
:100120002403410072006400750069006E006F00D6
:1001300020004D006500670061002000320035009E
:1001400036003000000011241FBECFEFD2E0DEBF2A
:10015000CDBF11E0A0E0B1E0E0EDFFE002C005900E
:100160000D92A631B107D9F712E0A6E1B1E001C0C6
:100170001D92AF32B107E1F7F1D028C741CF9C0102
:10018000DC01AE57BF4FED91FC9111974191119653
:10019000FC93EE9380589F4FE817F90711F42D93C5
:1001A0003C939FB7F894F901EC57FF4F8081815041
:1001B00080839FBF842F0895DF92EF92FF920F9369
:1001C0001F93FC018489813019F0823021F405C02D
:1001D00040E3D42E04C0DD2402C030E2D32E838954
:1001E000823011F488E0D82A8589873031F0883050
:1001F00031F0863031F482E003C084E001C086E053
:10020000D82A1092C9001092C8001092CA00E78440
:10021000F0880189128980E0E81681EEF80680E016
:10022000080780E0180719F420E130E00FC0C8018A
:10023000B701969587957795679560587B47814E6E
:100240009F4FA8019701A0D6215030403093CD0098
:100250002093CC00D092CA0080E0E81681EEF80628
:1002600080E0080780E0180711F082E001C080E01C
:100270008093C80088E98093C9001F910F91FF9077
:10028000EF90DF9008951F920F920FB60F921124F6
:100290002F938F939F93EF93FF939091CE008EB304
:1002A0008430F1F4E0919901F0919A019083E0910A
:1002B0009901F0919A01CF01019690939A01809350
:1002C00099018959914021F489E191E092838183D8
:1002D0009FB7F89480919D018F5F80939D019FBF90
:1002E000FF91EF919F918F912F910F900FBE0F90E3
:1002F0001F901895FC01858580FF02C05F980895C6
:100300005F9A089580E091E0D5C580E091E088C5CE
:1003100084B7877F84BF28E10FB6F89420936000EC
:10032000109260000FBE87E690E09093CD0080931E
:10033000CC0086E08093CA001092C8002093C900C8
:10034000539A5A9A8AB180638AB98BB180638BB908
:1003500083D284E085BD5F9A579A08950F931F93C7
:10036000CF93DF93D5DF2FB7F8948EE991E0909388
:100370001F0280931E0290932102809320022FBFC0
:100380002FB7F89489E191E090939A0180939901B5
:1003900090939C0180939B012FBF7894CEE9D1E08C
:1003A00003E08FB7F894909122028FBF903809F143
:1003B00080E091E0ABD497FD1CC0E0911E02F0916B
:1003C0001F028083E0911E02F0911F02CF0101966F
:1003D00090931F0280931E028E51924011F4D2839B
:1003E000C1839FB7F894809122028F5F809322028D
:1003F0009FBF8FB7F89410919D018FBFA89902C03D
:10040000113678F1A89A80919D01882361F05D985A
:100410000093160108C089E191E0B1DE682F80E009
:1004200091E0DAD411501123B1F78091160188239D
:1004300051F0809116018150809316018091160130
:10044000882309F45D9A80911701882351F08091E7
:10045000170181508093170180911701882309F4B7
:100460005C9A8FB7F894909122028FBF992369F01C
:100470008EE991E084DE982F8091C80085FFFCCF43
:100480009093CE005C980093170180E091E095D4A2
:100490002AD487CFDA01923049F0933061F091305D
:1004A000F9F4E8E9F0E022E130E01EC0EAEAF0E029
:1004B0002EE330E019C0813049F0813018F08230ED
:1004C00079F408C0E8EEF0E0849107C0ECEEF0E0CB
:1004D000849103C0E0E2F1E08491282F30E004C071
:1004E000E0E0F0E020E030E0ED93FC93C9010895F6
:1004F00028E030E040E003C04F5F220F331F281791
:100500003907D0F3842F8295807F08958093E90086
:100510008091EB0081608093EB001092ED0060937E
:10052000EC004093ED008091EE00881F8827881F23
:1005300008951092F40090E09093E9001092F0007A
:100540001092E8001092ED008091EB008E7F809376
:10055000EB009F5F953081F70895809127028823F3
:100560008CF403C08EB38823B1F08091E80082FF41
:10057000F9CF8091E8008B778093E80008958EB3DF
:10058000882349F08091E80080FFF9CF8091E8004E
:100590008E778093E800089594E68091EC0080FFC8
:1005A00005C08091E80080FF05C023C08091E8006D
:1005B00082FD1FC08EB3882311F482E008958EB3AC
:1005C000853011F483E008958091EB0085FF02C02F
:1005D00081E008958091E10082FFDFCF8091E1000A
:1005E0008B7F8093E100992311F484E0089591506A
:1005F000D4CF80E008959C0140912D0250912E02AD
:100600004617570718F4F90120E038C06115710545
:1006100011F0AB01F8CF8091E8008E778093E8006D
:1006200040E050E0F0CF8091E80083FF02C081E01D
:1006300008958091E80082FD2DC08EB3882381F15A
:100640008EB3853079F18091E80080FF17C09091DA
:10065000F20006C081918093F100415050409F5FAD
:100660004115510511F09830A8F320E0983009F4B5
:1006700021E08091E8008E778093E80041155105D4
:1006800091F6222381F606C08EB3882349F08EB3FB
:10069000853041F08091E80082FFF6CF80E0089538
:1006A00082E0089583E008959C0140912D025091CD
:1006B0002E024617570710F490E03BC061157105F4
:1006C00011F0AB01F9CF8091E8008E778093E800BC
:1006D00040E050E0F1CF8091E80083FF02C081E06C
:1006E00008958091E80082FD30C08EB3882399F18F
:1006F0008EB3853091F18091E80080FF1AC080911F
:10070000F20009C0F9012F5F3F4FE491E093F1003F
:10071000415050408F5F4115510511F0883090F3E2
:1007200090E0883009F491E08091E8008E77809322
:10073000E8004115510579F6992369F606C08EB394
:10074000882349F08EB3853041F08091E80082FF24
:10075000F6CF80E0089582E0089583E008959C013B
:100760006115710529F48091E8008B778093E8008A
:10077000F90120C08091E80083FF02C081E0089564
:100780008EB3882339F18EB3853031F18091E80042
:1007900082FFF0CF06C08091F100819361507040DC
:1007A00021F08091F2008823B1F78091E8008B77E7
:1007B0008093E80061157105E9F606C08EB38823C1
:1007C00049F08EB3853041F08091E80080FFF6CF8C
:1007D00080E0089582E0089583E0089542D044D0F7
:1007E0001EBA10922502109224021092230284E075
:1007F00089BD89B5826089BD09B400FEFDCF8091B5
:10080000D800982F9F779093D80080688093D80065
:10081000809163008E7F809363008091D8008F7DEC
:100820008093D8008091E0008E7F8093E0008091DB
:10083000E1008E7F8093E1008091E20081608093EF
:10084000E2008091E100877F8093E1008091E200E7
:1008500088608093E2000895C1DF81E080932602E2
:1008600008951092E20008951092E10008951F92F9
:100870000F920FB60F9211241F932F933F934F9314
:100880005F936F937F938F939F93AF93BF93EF93F8
:10089000FF93E9EEF0E0108117701082E0EFF0E0D6
:1008A0008081877F80837894C3D0F894A9EEB0E0EC
:1008B0001C92E0EFF0E08081886080831C93FF91C0
:1008C000EF91BF91AF919F918F917F916F915F91C8
:1008D0004F913F912F911F910F900FBE0F901F903E
:1008E00018951F920F920FB60F9211242F933F93DA
:1008F0004F935F936F937F938F939F93AF93BF9328
:10090000EF93FF938091E10080FF1BC08091E20094
:1009100080FF17C08091E1008E7F8093E10080917D
:10092000E2008E7F8093E2008091E20080618093FC
:10093000E2008091D80080628093D80019BC1EBA72
:10094000D1D18091E10084FF29C08091E20084FF31
:1009500025C084E089BD89B5826089BD09B400FEE7
:10096000FDCF8091D8008F7D8093D8008091E100E9
:100970008F7E8093E1008091E2008F7E8093E20081
:100980008091E20081608093E200809125028823BB
:1009900011F481E001C084E08EBBA4D18091E1001C
:1009A00083FF27C08091E20083FF23C08091E10094
:1009B000877F8093E10082E08EBB109225028091B8
:1009C000E1008E7F8093E1008091E2008E7F809332
:1009D000E2008091E20080618093E200AADD80E085
:1009E00060E042E093DD8091F00088608093F00049
:1009F00079D18091E10082FF0AC08091E20082FFFC
:100A000006C08091E1008B7F8093E1006BD1FF9164
:100A1000EF91BF91AF919F918F917F916F915F9176
:100A20004F913F912F910F900FBE0F901F901895EF
:100A30001F93DF93CF93CDB7DEB7AC970FB6F89483
:100A4000DEBF0FBECDBFE7E2F2E08091F1008193FF
:100A500022E0EF32F207C9F7809127023091280295
:100A6000353009F487C0363040F43130C9F13130C7
:100A700070F0333009F01DC133C0383009F4EFC0D5
:100A8000393009F4FEC0363009F013C192C0803805
:100A900021F0823809F00DC108C0909123028091A5
:100AA0002402882399F0926011C080912B028770F4
:100AB0008093E9008091EB0090E025E09695879582
:100AC0002A95E1F7982F91701092E9008091E80043
:100AD000877F8093E8009093F1001092F100CAC0E4
:100AE000882319F0823009F0E4C090E08F71907093
:100AF000009721F0029709F0DDC00CC08091290217
:100B0000813009F0D7C010922402333069F5809308
:100B100024022AC080912902882331F520912B02DA
:100B2000277009F4C7C02093E9008091EB0080FF93
:100B3000C1C0333021F48091EB00806213C08091FA
:100B4000EB0080618093EB0081E090E002C0880FB1
:100B5000991F2A95E2F78093EA001092EA008091AB
:100B6000EB0088608093EB001092E9008091E80030
:100B7000877F83C0882309F09CC01091290280914F
:100B8000E800877F8093E800E8DC04C08EB3882308
:100B900009F490C08091E80080FFF8CF812F8F7713
:100BA00011F492E001C093E09EBB80688093E30063
:100BB00081C08058823008F07CC0809129029091D9
:100BC0002A0223E08C3D920799F55FB7F894DE0185
:100BD00015964EE020E030E061E2E42FF0E0609313
:100BE0005700849120FF03C082958F704F5F982F2C
:100BF0009F70892F805D8A3308F0895F8C931196EE
:100C00001C9211972F5F3F4F12962431310529F71F
:100C10005FBF8AE28B8383E08C838091E800877FCB
:100C20008093E800CE0103966AE270E0E4DC11C034
:100C300060912B02AE014F5F5F4F2CDCBC0100972F
:100C4000C9F18091E800877F8093E80089819A81CB
:100C50002BDD8091E8008B778093E8002BC08038F3
:100C600041F58091E800877F8093E800809125021C
:100C70008093F1008091E8008E778093E8006DDC2E
:100C800019C08823B1F490912902923098F4809190
:100C9000E800877F8093E800909325025EDC8091D6
:100CA0002502882311F483E001C084E08EBB2DDB94
:100CB00001C028DB8091E80083FF0AC08091EB002F
:100CC00080628093EB008091E800877F8093E8004A
:100CD000AC960FB6F894DEBF0FBECDBFCF91DF91BB
:100CE0001F91089508951F938EB3882361F010918A
:100CF000E9001092E9008091E80083FF01C098DECE
:100D000017701093E9001F9108950895FC018EB3A8
:100D1000843021F587859089A189B2890097A10542
:100D2000B105E1F085818093E9008091E80082FFC0
:100D300015C08091F200882319F42FEF3FEF04C013
:100D40008091F100282F30E08091F200882341F457
:100D50008091E8008B778093E80002C02FEF3FEF8F
:100D6000C9010895FC018EB3843011F587859089FF
:100D7000A189B2890097A105B105D1F08181809345
:100D8000E9008091F2008823A9F09091E800809119
:100D9000E8008E778093E80095FD0CC0FDDB982F6E
:100DA000882349F48091E8008E778093E80003C09F
:100DB00092E001C090E0892F0895FC018EB3843049
:100DC00051F487859089A189B2890097A105B10561
:100DD00011F0CF01C7CF08951F93FC01162F8EB3DA
:100DE0008430D9F487859089A189B2890097A105BB
:100DF000B10599F081818093E9008091E80085FD3B
:100E000008C08091E8008E778093E800C5DB8823D6
:100E100029F41093F10080E001C082E01F91089551
:100E20000F931F93CF93DF93EC010D96FC0189E0A4
:100E3000DF011D928A95E9F72A813B8109818C8126
:100E4000882311F410E001C014E0C90151DB182B14
:100E50001260802F61E8412F59DB882329F12E8110
:100E60003F810D818885882311F410E001C014E0D2
:100E7000C9013EDB182B1260802F60E8412F46DB52
:100E8000882391F02A853B8509858C85882311F478
:100E900010E001C014E0C9012BDB182B1260802F79
:100EA00061EC412F33DB01C080E0DF91CF911F91D6
:100EB0000F910895CF93DF93EC018091E80083FFB9
:100EC00060C0888190E020912B0230912C0228177D
:100ED000390709F056C080912802813261F08232D0
:100EE00020F4803209F04DC019C0823269F183329A
:100EF00009F047C038C080912702813A09F041C00B
:100F00008091E800877F8093E800CE010F9667E02C
:100F100070E071DB8091E8008B7713C0809127022D
:100F2000813279F58091E800877F8093E800CE01D7
:100F30000F9667E070E013DCCE013ED98091E800A7
:100F40008E778093E8001DC0809127028132C9F41A
:100F50008091E800877F8093E800809129028D8747
:100F6000CE01C8D90DC080912702813251F4809101
:100F7000E800877F8093E800CE0160912902C5DEFA
:100F8000ECDADF91CF910895A1E21A2EAA1BBB1BC8
:100F9000FD010DC0AA1FBB1FEE1FFF1FA217B30745
:100FA000E407F50720F0A21BB30BE40BF50B661F5B
:100FB000771F881F991F1A9469F76095709580951F
:100FC00090959B01AC01BD01CF010895F894FFCF2E
:100FD0000003400000044000000208000000000080
:060FE0000000000000000B
:00000001FF

View File

@ -0,0 +1,256 @@
:100000009CC00000B5C00000B3C00000B1C000003B
:10001000AFC00000ADC00000ABC00000A9C0000030
:10002000A7C00000A5C00000A3C0000054C4000089
:1000300018C400009DC000009BC0000099C00000D3
:1000400097C0000095C0000093C0000091C0000060
:100050008FC000008DC000008BC000000EC10000EA
:1000600087C0000085C0000083C0000081C0000080
:100070007FC000007DC000007BC0000079C0000090
:1000800077C0000075C0000073C0000071C00000A0
:100090006FC000006DC000001201100102000008D6
:1000A0004123010001000102DC0109023E000201BE
:1000B00000C0320904000001020201000524000111
:1000C0001004240206052406000107058203080027
:1000D000FF09040100020A000000070504024000B5
:1000E00001070583024000010403090432034100B3
:1000F00072006400750069006E006F002000280027
:100100007700770077002E006100720064007500B0
:1001100069006E006F002E0063006300290000007C
:100120001803410072006400750069006E006F00E2
:10013000200055006E006F00000011241FBECFEF9D
:10014000D2E0DEBFCDBF11E0A0E0B1E0E4ECFFE023
:1001500002C005900D92A631B107D9F712E0A6E1D1
:10016000B1E001C01D92AF32B107E1F7F1D028C76D
:1001700047CF9C01DC01AE57BF4FED91FC91119729
:1001800041911196FC93EE9380589F4FE817F90721
:1001900011F42D933C939FB7F894F901EC57FF4F5E
:1001A0008081815080839FBF842F0895DF92EF92DA
:1001B000FF920F931F93FC018489813019F08230E4
:1001C00021F405C040E3D42E04C0DD2402C030E297
:1001D000D32E8389823011F488E0D82A858987302C
:1001E00031F0883031F0863031F482E003C084E0B1
:1001F00001C086E0D82A1092C9001092C80010925F
:10020000CA00E784F0880189128980E0E81681EE4F
:10021000F80680E0080780E0180719F420E130E0D4
:100220000FC0C801B7019695879577956795605877
:100230007B47814E9F4FA8019701A0D621503040A7
:100240003093CD002093CC00D092CA0080E0E81615
:1002500081EEF80680E0080780E0180711F082E0E0
:1002600001C080E08093C80088E98093C9001F9195
:100270000F91FF90EF90DF9008951F920F920FB6AD
:100280000F9211242F938F939F93EF93FF9390914D
:10029000CE008EB38430F1F4E0919901F0919A018F
:1002A0009083E0919901F0919A01CF01019690938A
:1002B0009A01809399018959914021F489E191E053
:1002C000928381839FB7F89480919D018F5F809383
:1002D0009D019FBFFF91EF919F918F912F910F9063
:1002E0000FBE0F901F901895FC01858580FF02C0FE
:1002F0005F9808955F9A089580E091E0D5C580E009
:1003000091E088C584B7877F84BF28E10FB6F89451
:1003100020936000109260000FBE87E690E09093FB
:10032000CD008093CC0086E08093CA001092C80074
:100330002093C900539A5A9A8AB180638AB98BB1C3
:1003400080638BB983D284E085BD5F9A579A089504
:100350000F931F93CF93DF93D5DF2FB7F8948EE9D8
:1003600091E090931F0280931E029093210280934C
:1003700020022FBF2FB7F89489E191E090939A0162
:100380008093990190939C0180939B012FBF789457
:10039000CEE9D1E003E08FB7F894909122028FBFAD
:1003A000903809F180E091E0ABD497FD1CC0E0915A
:1003B0001E02F0911F028083E0911E02F0911F0245
:1003C000CF01019690931F0280931E028E5192409E
:1003D00011F4D283C1839FB7F894809122028F5F7A
:1003E000809322029FBF8FB7F89410919D018FBF19
:1003F000A89902C0113678F1A89A80919D018823AE
:1004000061F05D980093160108C089E191E0B1DECA
:10041000682F80E091E0DAD411501123B1F7809178
:100420001601882351F080911601815080931601A6
:1004300080911601882309F45D9A80911701882321
:1004400051F080911701815080931701809117011D
:10045000882309F45C9A8FB7F894909122028FBF99
:10046000992369F08EE991E084DE982F8091C8008D
:1004700085FFFCCF9093CE005C980093170180E03D
:1004800091E095D42AD487CFDA01923049F09330A5
:1004900061F09130F9F4E8E9F0E022E130E01EC0CB
:1004A000EAEAF0E02EE330E019C0813049F0813013
:1004B00018F0823079F408C0E8EEF0E0849107C0CB
:1004C000ECEEF0E0849103C0E0E2F1E08491282FAB
:1004D00030E004C0E0E0F0E020E030E0ED93FC9399
:1004E000C901089528E030E040E003C04F5F220FCB
:1004F000331F28173907D0F3842F8295807F089502
:100500008093E9008091EB0081608093EB00109272
:10051000ED006093EC004093ED008091EE00881FA9
:100520008827881F08951092F40090E09093E900C6
:100530001092F0001092E8001092ED008091EB0014
:100540008E7F8093EB009F5F953081F708958091B7
:10055000270288238CF403C08EB38823B1F08091E6
:10056000E80082FFF9CF8091E8008B778093E80064
:1005700008958EB3882349F08091E80080FFF9CF79
:100580008091E8008E778093E800089594E680914A
:10059000EC0080FF05C08091E80080FF05C023C00B
:1005A0008091E80082FD1FC08EB3882311F482E0A1
:1005B00008958EB3853011F483E008958091EB00A7
:1005C00085FF02C081E008958091E10082FFDFCFC6
:1005D0008091E1008B7F8093E100992311F484E006
:1005E00008959150D4CF80E008959C0140912D0250
:1005F00050912E024617570718F4F90120E038C031
:100600006115710511F0AB01F8CF8091E8008E778C
:100610008093E80040E050E0F0CF8091E80083FF55
:1006200002C081E008958091E80082FD2DC08EB364
:10063000882381F18EB3853079F18091E80080FFC5
:1006400017C09091F20006C081918093F100415053
:1006500050409F5F4115510511F09830A8F320E0FC
:10066000983009F421E08091E8008E778093E800CB
:100670004115510591F6222381F606C08EB38823D9
:1006800049F08EB3853041F08091E80082FFF6CFCB
:1006900080E0089582E0089583E008959C014091F0
:1006A0002D0250912E024617570710F490E03BC0E0
:1006B0006115710511F0AB01F9CF8091E8008E77DB
:1006C0008093E80040E050E0F1CF8091E80083FFA4
:1006D00002C081E008958091E80082FD30C08EB3B1
:1006E000882399F18EB3853091F18091E80080FFE5
:1006F0001AC08091F20009C0F9012F5F3F4FE491C9
:10070000E093F100415050408F5F4115510511F0C9
:10071000883090F390E0883009F491E08091E8000F
:100720008E778093E8004115510579F6992369F693
:1007300006C08EB3882349F08EB3853041F0809196
:10074000E80082FFF6CF80E0089582E0089583E01C
:1007500008959C016115710529F48091E8008B775B
:100760008093E800F90120C08091E80083FF02C077
:1007700081E008958EB3882339F18EB3853031F14D
:100780008091E80082FFF0CF06C08091F100819354
:100790006150704021F08091F2008823B1F7809180
:1007A000E8008B778093E80061157105E9F606C0D3
:1007B0008EB3882349F08EB3853041F08091E800F4
:1007C00080FFF6CF80E0089582E0089583E00895E9
:1007D00042D044D01EBA10922502109224021092E8
:1007E000230284E089BD89B5826089BD09B400FE19
:1007F000FDCF8091D800982F9F779093D800806884
:100800008093D800809163008E7F809363008091F5
:10081000D8008F7D8093D8008091E0008E7F8093F8
:10082000E0008091E1008E7F8093E1008091E20002
:1008300081608093E2008091E100877F8093E100F6
:100840008091E20088608093E2000895C1DF81E03A
:100850008093260208951092E20008951092E1001C
:1008600008951F920F920FB60F9211241F932F938A
:100870003F934F935F936F937F938F939F93AF9328
:10088000BF93EF93FF93E9EEF0E0108117701082B1
:10089000E0EFF0E08081877F80837894C3D0F89484
:1008A000A9EEB0E01C92E0EFF0E0808188608083E8
:1008B0001C93FF91EF91BF91AF919F918F917F9189
:1008C0006F915F914F913F912F911F910F900FBEAC
:1008D0000F901F9018951F920F920FB60F92112430
:1008E0002F933F934F935F936F937F938F939F9338
:1008F000AF93BF93EF93FF938091E10080FF1BC004
:100900008091E20080FF17C08091E1008E7F80938C
:10091000E1008091E2008E7F8093E2008091E2000E
:1009200080618093E2008091D80080628093D8003B
:1009300019BC1EBAD1D18091E10084FF29C08091F9
:10094000E20084FF25C084E089BD89B5826089BD4D
:1009500009B400FEFDCF8091D8008F7D8093D80030
:100960008091E1008F7E8093E1008091E2008F7E94
:100970008093E2008091E20081608093E2008091A8
:100980002502882311F481E001C084E08EBBA4D14C
:100990008091E10083FF27C08091E20083FF23C0A4
:1009A0008091E100877F8093E10082E08EBB10920E
:1009B00025028091E1008E7F8093E1008091E2002A
:1009C0008E7F8093E2008091E20080618093E2005C
:1009D000AADD80E060E042E093DD8091F000886075
:1009E0008093F00079D18091E10082FF0AC080916C
:1009F000E20082FF06C08091E1008B7F8093E100DE
:100A00006BD1FF91EF91BF91AF919F918F917F91AA
:100A10006F915F914F913F912F910F900FBE0F906B
:100A20001F9018951F93DF93CF93CDB7DEB7AC9788
:100A30000FB6F894DEBF0FBECDBFE7E2F2E08091C3
:100A4000F100819322E0EF32F207C9F7809127028B
:100A500030912802353009F487C0363040F4313007
:100A6000C9F1313070F0333009F01DC133C0383076
:100A700009F4EFC0393009F4FEC0363009F013C173
:100A800092C0803821F0823809F00DC108C09091E1
:100A9000230280912402882399F0926011C08091F2
:100AA0002B0287708093E9008091EB0090E025E0B5
:100AB000969587952A95E1F7982F91701092E90005
:100AC0008091E800877F8093E8009093F100109276
:100AD000F100CAC0882319F0823009F0E4C090E028
:100AE0008F719070009721F0029709F0DDC00CC063
:100AF00080912902813009F0D7C01092240233304E
:100B000069F5809324022AC080912902882331F557
:100B100020912B02277009F4C7C02093E90080912F
:100B2000EB0080FFC1C0333021F48091EB00806284
:100B300013C08091EB0080618093EB0081E090E036
:100B400002C0880F991F2A95E2F78093EA0010925D
:100B5000EA008091EB0088608093EB001092E9003E
:100B60008091E800877F83C0882309F09CC01091A2
:100B700029028091E800877F8093E800E8DC04C0C8
:100B80008EB3882309F490C08091E80080FFF8CFED
:100B9000812F8F7711F492E001C093E09EBB8068B3
:100BA0008093E30081C08058823008F07CC080913F
:100BB000290290912A0223E08C3D920799F55FB7B4
:100BC000F894DE0115964EE020E030E061E2E42F7B
:100BD000F0E060935700849120FF03C082958F70EE
:100BE0004F5F982F9F70892F805D8A3308F0895F4F
:100BF0008C9311961C9211972F5F3F4F12962431C0
:100C0000310529F75FBF8AE28B8383E08C83809173
:100C1000E800877F8093E800CE0103966AE270E0E7
:100C2000E4DC11C060912B02AE014F5F5F4F2CDC02
:100C3000BC010097C9F18091E800877F8093E800AC
:100C400089819A812BDD8091E8008B778093E80081
:100C50002BC0803841F58091E800877F8093E800C1
:100C6000809125028093F1008091E8008E77809337
:100C7000E8006DDC19C08823B1F49091290292300C
:100C800098F48091E800877F8093E8009093250294
:100C90005EDC80912502882311F483E001C084E0AA
:100CA0008EBB2DDB01C028DB8091E80083FF0AC0EA
:100CB0008091EB0080628093EB008091E800877F59
:100CC0008093E800AC960FB6F894DEBF0FBECDBFA0
:100CD000CF91DF911F91089508951F938EB38823BC
:100CE00061F01091E9001092E9008091E80083FF23
:100CF00001C098DE17701093E9001F9108950895C0
:100D0000FC018EB3843021F587859089A189B28951
:100D10000097A105B105E1F085818093E9008091FC
:100D2000E80082FF15C08091F200882319F42FEFAC
:100D30003FEF04C08091F100282F30E08091F20055
:100D4000882341F48091E8008B778093E80002C00B
:100D50002FEF3FEFC9010895FC018EB3843011F5E8
:100D600087859089A189B2890097A105B105D1F045
:100D700081818093E9008091F2008823A9F090910D
:100D8000E8008091E8008E778093E80095FD0CC024
:100D9000FDDB982F882349F48091E8008E778093BB
:100DA000E80003C092E001C090E0892F0895FC01A3
:100DB0008EB3843051F487859089A189B2890097D8
:100DC000A105B10511F0CF01C7CF08951F93FC0114
:100DD000162F8EB38430D9F487859089A189B28982
:100DE0000097A105B10599F081818093E900809178
:100DF000E80085FD08C08091E8008E778093E800C8
:100E0000C5DB882329F41093F10080E001C082E063
:100E10001F9108950F931F93CF93DF93EC010D96CD
:100E2000FC0189E0DF011D928A95E9F72A813B8167
:100E300009818C81882311F410E001C014E0C901FC
:100E400051DB182B1260802F61E8412F59DB88237A
:100E500029F12E813F810D818885882311F410E0CE
:100E600001C014E0C9013EDB182B1260802F60E83E
:100E7000412F46DB882391F02A853B8509858C85A7
:100E8000882311F410E001C014E0C9012BDB182BFA
:100E90001260802F61EC412F33DB01C080E0DF91D5
:100EA000CF911F910F910895CF93DF93EC01809123
:100EB000E80083FF60C0888190E020912B02309190
:100EC0002C022817390709F056C080912802813278
:100ED00061F0823220F4803209F04DC019C08232B4
:100EE00069F1833209F047C038C080912702813A06
:100EF00009F041C08091E800877F8093E800CE012F
:100F00000F9667E070E071DB8091E8008B7713C08B
:100F100080912702813279F58091E800877F809364
:100F2000E800CE010F9667E070E013DCCE013ED9F9
:100F30008091E8008E778093E8001DC080912702A1
:100F40008132C9F48091E800877F8093E800809126
:100F500029028D87CE01C8D90DC080912702813228
:100F600051F48091E800877F8093E800CE01609182
:100F70002902C5DEECDADF91CF910895A1E21A2EA5
:100F8000AA1BBB1BFD010DC0AA1FBB1FEE1FFF1F2D
:100F9000A217B307E407F50720F0A21BB30BE40B7D
:100FA000F50B661F771F881F991F1A9469F76095C4
:100FB0007095809590959B01AC01BD01CF0108957E
:040FC000F894FFCFD3
:100FC400000340000004400000020800000000008C
:060FD40000000000000017
:00000001FF

View File

@ -88,10 +88,15 @@ int main(void)
for (;;) for (;;)
{ {
/* Read bytes from the USB OUT endpoint into the USART transmit buffer */ /* Only try to read in bytes from the CDC interface if the transmit buffer is not full */
int16_t ReceivedByte = CDC_Device_ReceiveByte(&VirtualSerial_CDC_Interface); if (!(RingBuffer_IsFull(&USBtoUSART_Buffer)))
if (!(ReceivedByte < 0) && !(RingBuffer_IsFull(&USBtoUSART_Buffer))) {
RingBuffer_Insert(&USBtoUSART_Buffer, ReceivedByte); int16_t ReceivedByte = CDC_Device_ReceiveByte(&VirtualSerial_CDC_Interface);
/* Read bytes from the USB OUT endpoint into the USART transmit buffer */
if (!(ReceivedByte < 0))
RingBuffer_Insert(&USBtoUSART_Buffer, ReceivedByte);
}
/* Check if the UART receive buffer flush timer has expired or the buffer is nearly full */ /* Check if the UART receive buffer flush timer has expired or the buffer is nearly full */
RingBuff_Count_t BufferCount = RingBuffer_GetCount(&USARTtoUSB_Buffer); RingBuff_Count_t BufferCount = RingBuffer_GetCount(&USARTtoUSB_Buffer);
@ -150,25 +155,10 @@ void SetupHardware(void)
AVR_RESET_LINE_DDR |= AVR_RESET_LINE_MASK; AVR_RESET_LINE_DDR |= AVR_RESET_LINE_MASK;
} }
/** Event handler for the library USB Connection event. */
void EVENT_USB_Device_Connect(void)
{
}
/** Event handler for the library USB Disconnection event. */
void EVENT_USB_Device_Disconnect(void)
{
}
/** Event handler for the library USB Configuration Changed event. */ /** Event handler for the library USB Configuration Changed event. */
void EVENT_USB_Device_ConfigurationChanged(void) void EVENT_USB_Device_ConfigurationChanged(void)
{ {
CDC_Device_ConfigureEndpoints(&VirtualSerial_CDC_Interface);
if (!(CDC_Device_ConfigureEndpoints(&VirtualSerial_CDC_Interface)))
;
} }
/** Event handler for the library USB Unhandled Control Request event. */ /** Event handler for the library USB Unhandled Control Request event. */
@ -217,12 +207,13 @@ void EVENT_CDC_Device_LineEncodingChanged(USB_ClassInfo_CDC_Device_t* const CDCI
UCSR1C = 0; UCSR1C = 0;
/* Special case 57600 baud for compatibility with the ATmega328 bootloader. */ /* Special case 57600 baud for compatibility with the ATmega328 bootloader. */
UCSR1A = (CDCInterfaceInfo->State.LineEncoding.BaudRateBPS == 57600) ? 0 : (1 << U2X1);
UCSR1B = ((1 << RXCIE1) | (1 << TXEN1) | (1 << RXEN1));
UCSR1C = ConfigMask;
UBRR1 = (CDCInterfaceInfo->State.LineEncoding.BaudRateBPS == 57600) UBRR1 = (CDCInterfaceInfo->State.LineEncoding.BaudRateBPS == 57600)
? SERIAL_UBBRVAL(CDCInterfaceInfo->State.LineEncoding.BaudRateBPS) ? SERIAL_UBBRVAL(CDCInterfaceInfo->State.LineEncoding.BaudRateBPS)
: SERIAL_2X_UBBRVAL(CDCInterfaceInfo->State.LineEncoding.BaudRateBPS); : SERIAL_2X_UBBRVAL(CDCInterfaceInfo->State.LineEncoding.BaudRateBPS);
UCSR1C = ConfigMask;
UCSR1A = (CDCInterfaceInfo->State.LineEncoding.BaudRateBPS == 57600) ? 0 : (1 << U2X1);
UCSR1B = ((1 << RXCIE1) | (1 << TXEN1) | (1 << RXEN1));
} }
/** ISR to manage the reception of data from the serial port, placing received bytes into a circular buffer /** ISR to manage the reception of data from the serial port, placing received bytes into a circular buffer
@ -245,11 +236,7 @@ void EVENT_CDC_Device_ControLineStateChanged(USB_ClassInfo_CDC_Device_t* const C
bool CurrentDTRState = (CDCInterfaceInfo->State.ControlLineStates.HostToDevice & CDC_CONTROL_LINE_OUT_DTR); bool CurrentDTRState = (CDCInterfaceInfo->State.ControlLineStates.HostToDevice & CDC_CONTROL_LINE_OUT_DTR);
if (CurrentDTRState) if (CurrentDTRState)
{ AVR_RESET_LINE_PORT &= ~AVR_RESET_LINE_MASK;
AVR_RESET_LINE_PORT &= ~AVR_RESET_LINE_MASK;
}
else else
{ AVR_RESET_LINE_PORT |= AVR_RESET_LINE_MASK;
AVR_RESET_LINE_PORT |= AVR_RESET_LINE_MASK;
}
} }

View File

@ -68,7 +68,7 @@ USB_Descriptor_Device_t PROGMEM DeviceDescriptor =
.VendorID = 0x03EB, // Atmel .VendorID = 0x03EB, // Atmel
.ProductID = 0x204B, // LUFA USB to Serial Demo Application .ProductID = 0x204B, // LUFA USB to Serial Demo Application
.ReleaseNumber = 0x0000, .ReleaseNumber = 0x0001,
.ManufacturerStrIndex = 0x01, .ManufacturerStrIndex = 0x01,
.ProductStrIndex = 0x02, .ProductStrIndex = 0x02,
@ -172,7 +172,7 @@ USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor =
.EndpointAddress = (ENDPOINT_DESCRIPTOR_DIR_OUT | CDC_RX_EPNUM), .EndpointAddress = (ENDPOINT_DESCRIPTOR_DIR_OUT | CDC_RX_EPNUM),
.Attributes = (EP_TYPE_BULK | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA), .Attributes = (EP_TYPE_BULK | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
.EndpointSize = CDC_TXRX_EPSIZE, .EndpointSize = CDC_TXRX_EPSIZE,
.PollingIntervalMS = 0x00 .PollingIntervalMS = 0x01
}, },
.CDC_DataInEndpoint = .CDC_DataInEndpoint =
@ -182,7 +182,7 @@ USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor =
.EndpointAddress = (ENDPOINT_DESCRIPTOR_DIR_IN | CDC_TX_EPNUM), .EndpointAddress = (ENDPOINT_DESCRIPTOR_DIR_IN | CDC_TX_EPNUM),
.Attributes = (EP_TYPE_BULK | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA), .Attributes = (EP_TYPE_BULK | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
.EndpointSize = CDC_TXRX_EPSIZE, .EndpointSize = CDC_TXRX_EPSIZE,
.PollingIntervalMS = 0x00 .PollingIntervalMS = 0x01
} }
}; };

View File

@ -131,7 +131,8 @@ LUFA_OPTS = -D USB_DEVICE_ONLY
LUFA_OPTS += -D FIXED_CONTROL_ENDPOINT_SIZE=8 LUFA_OPTS += -D FIXED_CONTROL_ENDPOINT_SIZE=8
LUFA_OPTS += -D FIXED_NUM_CONFIGURATIONS=1 LUFA_OPTS += -D FIXED_NUM_CONFIGURATIONS=1
LUFA_OPTS += -D USE_FLASH_DESCRIPTORS LUFA_OPTS += -D USE_FLASH_DESCRIPTORS
#LUFA_OPTS += -D INTERRUPT_CONTROL_ENDPOINT LUFA_OPTS += -D INTERRUPT_CONTROL_ENDPOINT
LUFA_OPTS += -D DEVICE_STATE_AS_GPIOR=0
LUFA_OPTS += -D USE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)" LUFA_OPTS += -D USE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)"

View File

@ -0,0 +1,108 @@
// Tests writing to and reading from a file, in particular the
// the Stream implementation (e.g. read() and peek()).
#include <SD.h>
#include <ArduinoTestSuite.h>
void setup()
{
int startMemoryUsage = ATS_GetFreeMemory();
boolean b;
File f;
ATS_begin("Arduino", "SD Test");
ATS_PrintTestStatus("SD.begin()", b = SD.begin(4));
if (!b) goto done;
f = SD.open("test.txt", FILE_TRUNCATE);
ATS_PrintTestStatus("SD.open()", f);
if (!f) goto done;
f.print("1234");
f.close();
f = SD.open("test.txt", FILE_TRUNCATE);
ATS_PrintTestStatus("SD.open()", f);
if (!f) goto done;
f.print("abcde");
f.close();
f = SD.open("test.txt", FILE_APPEND);
ATS_PrintTestStatus("SD.open()", f);
if (!f) goto done;
f.print("fgh");
f.close();
f = SD.open("test.txt");
ATS_PrintTestStatus("SD.open()", f);
if (!f) goto done;
ATS_PrintTestStatus("read()", f.read() == 'a');
ATS_PrintTestStatus("peek()", f.peek() == 'b');
ATS_PrintTestStatus("read()", f.read() == 'b');
ATS_PrintTestStatus("read()", f.read() == 'c');
ATS_PrintTestStatus("peek()", f.peek() == 'd');
ATS_PrintTestStatus("peek()", f.peek() == 'd');
ATS_PrintTestStatus("peek()", f.peek() == 'd');
ATS_PrintTestStatus("peek()", f.peek() == 'd');
ATS_PrintTestStatus("read()", f.read() == 'd');
ATS_PrintTestStatus("available()", f.available() != 0);
ATS_PrintTestStatus("read()", f.read() == 'e');
ATS_PrintTestStatus("available()", f.available() != 0);
ATS_PrintTestStatus("peek()", f.peek() == 'f');
ATS_PrintTestStatus("read()", f.read() == 'f');
ATS_PrintTestStatus("peek()", f.peek() == 'g');
ATS_PrintTestStatus("available()", f.available() != 0);
ATS_PrintTestStatus("peek()", f.peek() == 'g');
ATS_PrintTestStatus("read()", f.read() == 'g');
ATS_PrintTestStatus("available()", f.available() != 0);
ATS_PrintTestStatus("available()", f.available() != 0);
ATS_PrintTestStatus("available()", f.available() != 0);
ATS_PrintTestStatus("peek()", f.peek() == 'h');
ATS_PrintTestStatus("read()", f.read() == 'h');
ATS_PrintTestStatus("available()", f.available() == 0);
ATS_PrintTestStatus("peek()", f.peek() == -1);
ATS_PrintTestStatus("read()", f.read() == -1);
ATS_PrintTestStatus("peek()", f.peek() == -1);
ATS_PrintTestStatus("read()", f.read() == -1);
f.close();
f = SD.open("test2.txt", FILE_TRUNCATE);
ATS_PrintTestStatus("SD.open()", f);
if (!f) goto done;
f.print("ABC");
f.close();
f = SD.open("test.txt");
ATS_PrintTestStatus("SD.open()", f);
if (!f) goto done;
ATS_PrintTestStatus("peek()", f.peek() == 'a');
f.close();
f = SD.open("test2.txt");
ATS_PrintTestStatus("SD.open()", f);
if (!f) goto done;
ATS_PrintTestStatus("peek()", f.peek() == 'A');
ATS_PrintTestStatus("read()", f.read() == 'A');
f.close();
done:
ATS_ReportMemoryUsage(startMemoryUsage);
ATS_end();
}
void loop() {}

View File

@ -0,0 +1,78 @@
#include <SD.h>
#include <ArduinoTestSuite.h>
void setup()
{
int startMemoryUsage = ATS_GetFreeMemory();
boolean b;
File f;
ATS_begin("Arduino", "SD Files Test");
ATS_PrintTestStatus("SD.begin()", b = SD.begin(4));
if (!b) goto done;
ATS_PrintTestStatus("!SD.exists()", !SD.exists("asdf.txt"));
ATS_PrintTestStatus("SD.open()", f = SD.open("asdf.txt", FILE_TRUNCATE)); f.close();
ATS_PrintTestStatus("SD.exists()", SD.exists("asdf.txt"));
ATS_PrintTestStatus("SD.exists()", SD.exists("/asdf.txt"));
ATS_PrintTestStatus("SD.remove()", SD.remove("asdf.txt"));
ATS_PrintTestStatus("!SD.exists()", !SD.exists("asdf.txt"));
ATS_PrintTestStatus("!SD.exists()", !SD.exists("asdf"));
ATS_PrintTestStatus("SD.mkdir()", SD.mkdir("asdf"));
ATS_PrintTestStatus("SD.exists()", SD.exists("asdf"));
ATS_PrintTestStatus("SD.exists()", SD.exists("/asdf"));
ATS_PrintTestStatus("SD.exists()", SD.exists("asdf/"));
ATS_PrintTestStatus("SD.rmdir()", SD.rmdir("asdf"));
ATS_PrintTestStatus("!SD.exists()", !SD.exists("asdf"));
ATS_PrintTestStatus("SD.mkdir()", SD.mkdir("x/y/z"));
ATS_PrintTestStatus("SD.exists()", SD.exists("x"));
ATS_PrintTestStatus("SD.exists()", SD.exists("x/"));
ATS_PrintTestStatus("SD.exists()", SD.exists("x/y"));
ATS_PrintTestStatus("SD.exists()", SD.exists("x/y/"));
ATS_PrintTestStatus("SD.exists()", SD.exists("x/y/z"));
ATS_PrintTestStatus("SD.exists()", SD.exists("x/y/z/"));
ATS_PrintTestStatus("SD.exists()", SD.exists("/x/y/z/"));
ATS_PrintTestStatus("SD.rmdir()", SD.rmdir("x/y/z"));
ATS_PrintTestStatus("SD.exists()", SD.exists("x"));
ATS_PrintTestStatus("SD.exists()", SD.exists("x/y"));
ATS_PrintTestStatus("!SD.exists()", !SD.exists("x/y/z"));
ATS_PrintTestStatus("SD.rmdir()", SD.rmdir("x/y/"));
ATS_PrintTestStatus("SD.exists()", SD.exists("x"));
ATS_PrintTestStatus("!SD.exists()", !SD.exists("x/y"));
ATS_PrintTestStatus("!SD.exists()", !SD.exists("x/y/z"));
ATS_PrintTestStatus("SD.rmdir()", SD.rmdir("/x"));
ATS_PrintTestStatus("!SD.exists()", !SD.exists("x"));
ATS_PrintTestStatus("!SD.exists()", !SD.exists("x/y"));
ATS_PrintTestStatus("!SD.exists()", !SD.exists("x/y/z"));
ATS_PrintTestStatus("!SD.open()", !(f = SD.open("asdf/asdf.txt", FILE_TRUNCATE))); f.close();
ATS_PrintTestStatus("!SD.exists()", !SD.exists("asdf"));
ATS_PrintTestStatus("!SD.exists()", !SD.exists("asdf.txt"));
ATS_PrintTestStatus("!SD.exists()", !SD.exists("asdf/asdf.txt"));
ATS_PrintTestStatus("SD.mkdir()", SD.mkdir("asdf"));
ATS_PrintTestStatus("SD.exists()", SD.exists("asdf"));
ATS_PrintTestStatus("SD.open()", f = SD.open("asdf/asdf.txt", FILE_TRUNCATE)); f.close();
ATS_PrintTestStatus("SD.exists()", SD.exists("asdf/asdf.txt"));
ATS_PrintTestStatus("!SD.rmdir()", !SD.rmdir("asdf"));
ATS_PrintTestStatus("SD.exists()", SD.exists("asdf"));
ATS_PrintTestStatus("SD.exists()", SD.exists("asdf/asdf.txt"));
ATS_PrintTestStatus("SD.remove()", SD.remove("asdf/asdf.txt"));
ATS_PrintTestStatus("!SD.exists()", !SD.exists("asdf/asdf.txt"));
ATS_PrintTestStatus("SD.exists()", SD.exists("asdf"));
ATS_PrintTestStatus("SD.rmdir()", SD.rmdir("asdf"));
ATS_PrintTestStatus("!SD.exists()", !SD.exists("asdf"));
done:
ATS_ReportMemoryUsage(startMemoryUsage);
ATS_end();
}
void loop() {}

2
libraries/LiquidCrystal/LiquidCrystal.cpp Executable file → Normal file
View File

@ -122,7 +122,7 @@ void LiquidCrystal::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) {
write4bits(0x03); write4bits(0x03);
delayMicroseconds(150); delayMicroseconds(150);
// finally, set to 8-bit interface // finally, set to 4-bit interface
write4bits(0x02); write4bits(0x02);
} else { } else {
// this is according to the hitachi HD44780 datasheet // this is according to the hitachi HD44780 datasheet

View File

@ -16,6 +16,7 @@
* LCD D5 pin to digital pin 4 * LCD D5 pin to digital pin 4
* LCD D6 pin to digital pin 3 * LCD D6 pin to digital pin 3
* LCD D7 pin to digital pin 2 * LCD D7 pin to digital pin 2
* LCD R/W pin to ground
* 10K resistor: * 10K resistor:
* ends to +5V and ground * ends to +5V and ground
* wiper to LCD VO pin (pin 3) * wiper to LCD VO pin (pin 3)
@ -26,8 +27,8 @@
by Limor Fried (http://www.ladyada.net) by Limor Fried (http://www.ladyada.net)
example added 9 Jul 2009 example added 9 Jul 2009
by Tom Igoe by Tom Igoe
modified 25 July 2009 modified 22 Nov 2010
by David A. Mellis by Tom Igoe
This example code is in the public domain. This example code is in the public domain.

View File

@ -16,6 +16,7 @@
* LCD D5 pin to digital pin 4 * LCD D5 pin to digital pin 4
* LCD D6 pin to digital pin 3 * LCD D6 pin to digital pin 3
* LCD D7 pin to digital pin 2 * LCD D7 pin to digital pin 2
* LCD R/W pin to ground
* 10K resistor: * 10K resistor:
* ends to +5V and ground * ends to +5V and ground
* wiper to LCD VO pin (pin 3) * wiper to LCD VO pin (pin 3)
@ -26,7 +27,7 @@
by Limor Fried (http://www.ladyada.net) by Limor Fried (http://www.ladyada.net)
example added 9 Jul 2009 example added 9 Jul 2009
by Tom Igoe by Tom Igoe
modified 8 Feb 2010 modified 22 Nov 2010
by Tom Igoe by Tom Igoe
This example code is in the public domain. This example code is in the public domain.

View File

@ -17,6 +17,7 @@
* LCD D5 pin to digital pin 4 * LCD D5 pin to digital pin 4
* LCD D6 pin to digital pin 3 * LCD D6 pin to digital pin 3
* LCD D7 pin to digital pin 2 * LCD D7 pin to digital pin 2
* LCD R/W pin to ground
* 10K resistor: * 10K resistor:
* ends to +5V and ground * ends to +5V and ground
* wiper to LCD VO pin (pin 3) * wiper to LCD VO pin (pin 3)
@ -27,7 +28,7 @@
by Limor Fried (http://www.ladyada.net) by Limor Fried (http://www.ladyada.net)
example added 9 Jul 2009 example added 9 Jul 2009
by Tom Igoe by Tom Igoe
modified 8 Feb 2010 modified 22 Nov 2010
by Tom Igoe by Tom Igoe
This example code is in the public domain. This example code is in the public domain.

View File

@ -17,6 +17,7 @@
* LCD D5 pin to digital pin 4 * LCD D5 pin to digital pin 4
* LCD D6 pin to digital pin 3 * LCD D6 pin to digital pin 3
* LCD D7 pin to digital pin 2 * LCD D7 pin to digital pin 2
* LCD R/W pin to ground
* 10K resistor: * 10K resistor:
* ends to +5V and ground * ends to +5V and ground
* wiper to LCD VO pin (pin 3) * wiper to LCD VO pin (pin 3)
@ -27,7 +28,7 @@
by Limor Fried (http://www.ladyada.net) by Limor Fried (http://www.ladyada.net)
example added 9 Jul 2009 example added 9 Jul 2009
by Tom Igoe by Tom Igoe
modified 8 Feb 2010 modified 22 Nov 2010
by Tom Igoe by Tom Igoe
This example code is in the public domain. This example code is in the public domain.

View File

@ -16,6 +16,7 @@
* LCD D5 pin to digital pin 4 * LCD D5 pin to digital pin 4
* LCD D6 pin to digital pin 3 * LCD D6 pin to digital pin 3
* LCD D7 pin to digital pin 2 * LCD D7 pin to digital pin 2
* LCD R/W pin to ground
* 10K resistor: * 10K resistor:
* ends to +5V and ground * ends to +5V and ground
* wiper to LCD VO pin (pin 3) * wiper to LCD VO pin (pin 3)
@ -26,7 +27,7 @@
by Limor Fried (http://www.ladyada.net) by Limor Fried (http://www.ladyada.net)
example added 9 Jul 2009 example added 9 Jul 2009
by Tom Igoe by Tom Igoe
modified 8 Feb 2010 modified 22 Nov 2010
by Tom Igoe by Tom Igoe
This example code is in the public domain. This example code is in the public domain.

View File

@ -17,6 +17,7 @@
* LCD D5 pin to digital pin 4 * LCD D5 pin to digital pin 4
* LCD D6 pin to digital pin 3 * LCD D6 pin to digital pin 3
* LCD D7 pin to digital pin 2 * LCD D7 pin to digital pin 2
* LCD R/W pin to ground
* 10K resistor: * 10K resistor:
* ends to +5V and ground * ends to +5V and ground
* wiper to LCD VO pin (pin 3) * wiper to LCD VO pin (pin 3)
@ -27,8 +28,8 @@
by Limor Fried (http://www.ladyada.net) by Limor Fried (http://www.ladyada.net)
example added 9 Jul 2009 example added 9 Jul 2009
by Tom Igoe by Tom Igoe
modified 25 July 2009 modified 22 Nov 2010
by David A. Mellis by Tom Igoe
This example code is in the public domain. This example code is in the public domain.

View File

@ -16,6 +16,7 @@
* LCD D5 pin to digital pin 4 * LCD D5 pin to digital pin 4
* LCD D6 pin to digital pin 3 * LCD D6 pin to digital pin 3
* LCD D7 pin to digital pin 2 * LCD D7 pin to digital pin 2
* LCD R/W pin to ground
* 10K resistor: * 10K resistor:
* ends to +5V and ground * ends to +5V and ground
* wiper to LCD VO pin (pin 3) * wiper to LCD VO pin (pin 3)
@ -26,7 +27,7 @@
by Limor Fried (http://www.ladyada.net) by Limor Fried (http://www.ladyada.net)
example added 9 Jul 2009 example added 9 Jul 2009
by Tom Igoe by Tom Igoe
modified 8 Feb 2010 modified 22 Nov 2010
by Tom Igoe by Tom Igoe
This example code is in the public domain. This example code is in the public domain.

View File

@ -16,6 +16,7 @@
* LCD D5 pin to digital pin 4 * LCD D5 pin to digital pin 4
* LCD D6 pin to digital pin 3 * LCD D6 pin to digital pin 3
* LCD D7 pin to digital pin 2 * LCD D7 pin to digital pin 2
* LCD R/W pin to ground
* 10K resistor: * 10K resistor:
* ends to +5V and ground * ends to +5V and ground
* wiper to LCD VO pin (pin 3) * wiper to LCD VO pin (pin 3)
@ -26,8 +27,8 @@
by Limor Fried (http://www.ladyada.net) by Limor Fried (http://www.ladyada.net)
example added 9 Jul 2009 example added 9 Jul 2009
by Tom Igoe by Tom Igoe
modified 25 July 2009 modified 22 Nov 2010
by David A. Mellis by Tom Igoe
This example code is in the public domain. This example code is in the public domain.

View File

@ -16,6 +16,7 @@
* LCD D5 pin to digital pin 4 * LCD D5 pin to digital pin 4
* LCD D6 pin to digital pin 3 * LCD D6 pin to digital pin 3
* LCD D7 pin to digital pin 2 * LCD D7 pin to digital pin 2
* LCD R/W pin to ground
* 10K resistor: * 10K resistor:
* ends to +5V and ground * ends to +5V and ground
* wiper to LCD VO pin (pin 3) * wiper to LCD VO pin (pin 3)
@ -26,7 +27,7 @@
by Limor Fried (http://www.ladyada.net) by Limor Fried (http://www.ladyada.net)
example added 9 Jul 2009 example added 9 Jul 2009
by Tom Igoe by Tom Igoe
modified 8 Feb 2010 modified 22 Nov 2010
by Tom Igoe by Tom Igoe
This example code is in the public domain. This example code is in the public domain.

60
libraries/SD/File.cpp Normal file
View File

@ -0,0 +1,60 @@
/*
SD - a slightly more friendly wrapper for sdfatlib
This library aims to expose a subset of SD card functionality
in the form of a higher level "wrapper" object.
License: GNU General Public License V3
(Because sdfatlib is licensed with this.)
(C) Copyright 2010 SparkFun Electronics
*/
#include <SD.h>
void File::write(uint8_t val) {
SD.file.write(val);
}
void File::write(const char *str) {
SD.file.write(str);
}
void File::write(const uint8_t *buf, size_t size) {
SD.file.write(buf, size);
}
int File::peek() {
if (SD.c != -1) return SD.c;
SD.c = SD.file.read();
return SD.c;
}
int File::read() {
if (SD.c != -1) {
int tmp = SD.c;
SD.c = -1;
return tmp;
}
return SD.file.read();
}
int File::available() {
if (SD.c != -1) return 1;
SD.c = SD.file.read();
return SD.c != -1;
}
void File::flush() {
SD.file.sync();
}
void File::close() {
SD.file.close();
}
File::operator bool() {
return SD.file.isOpen();
}

11
libraries/SD/README.txt Normal file
View File

@ -0,0 +1,11 @@
** SD - a slightly more friendly wrapper for sdfatlib **
This library aims to expose a subset of SD card functionality in the
form of a higher level "wrapper" object.
License: GNU General Public License V3
(Because sdfatlib is licensed with this.)
(C) Copyright 2010 SparkFun Electronics

437
libraries/SD/SD.cpp Normal file
View File

@ -0,0 +1,437 @@
/*
SD - a slightly more friendly wrapper for sdfatlib
This library aims to expose a subset of SD card functionality
in the form of a higher level "wrapper" object.
License: GNU General Public License V3
(Because sdfatlib is licensed with this.)
(C) Copyright 2010 SparkFun Electronics
This library provides four key benefits:
* Including `SD.h` automatically creates a global
`SD` object which can be interacted with in a similar
manner to other standard global objects like `Serial` and `Ethernet`.
* Boilerplate initialisation code is contained in one method named
`begin` and no further objects need to be created in order to access
the SD card.
* Calls to `open` can supply a full path name including parent
directories which simplifies interacting with files in subdirectories.
* Utility methods are provided to determine whether a file exists
and to create a directory heirarchy.
Note however that not all functionality provided by the underlying
sdfatlib library is exposed.
*/
/*
Implementation Notes
In order to handle multi-directory path traversal, functionality that
requires this ability is implemented as callback functions.
Individual methods call the `walkPath` function which performs the actual
directory traversal (swapping between two different directory/file handles
along the way) and at each level calls the supplied callback function.
Some types of functionality will take an action at each level (e.g. exists
or make directory) which others will only take an action at the bottom
level (e.g. open).
*/
#include "SD.h"
// Used by `getNextPathComponent`
#define MAX_COMPONENT_LEN 12 // What is max length?
#define PATH_COMPONENT_BUFFER_LEN MAX_COMPONENT_LEN+1
bool getNextPathComponent(char *path, unsigned int *p_offset,
char *buffer) {
/*
Parse individual path components from a path.
e.g. after repeated calls '/foo/bar/baz' will be split
into 'foo', 'bar', 'baz'.
This is similar to `strtok()` but copies the component into the
supplied buffer rather than modifying the original string.
`buffer` needs to be PATH_COMPONENT_BUFFER_LEN in size.
`p_offset` needs to point to an integer of the offset at
which the previous path component finished.
Returns `true` if more components remain.
Returns `false` if this is the last component.
(This means path ended with 'foo' or 'foo/'.)
*/
// TODO: Have buffer local to this function, so we know it's the
// correct length?
int bufferOffset = 0;
int offset = *p_offset;
// Skip root or other separator
if (path[offset] == '/') {
offset++;
}
// Copy the next next path segment
while (bufferOffset < MAX_COMPONENT_LEN
&& (path[offset] != '/')
&& (path[offset] != '\0')) {
buffer[bufferOffset++] = path[offset++];
}
buffer[bufferOffset] = '\0';
// Skip trailing separator so we can determine if this
// is the last component in the path or not.
if (path[offset] == '/') {
offset++;
}
*p_offset = offset;
return (path[offset] != '\0');
}
boolean walkPath(char *filepath, SdFile& parentDir,
boolean (*callback)(SdFile& parentDir,
char *filePathComponent,
boolean isLastComponent,
void *object),
void *object = NULL) {
/*
When given a file path (and parent directory--normally root),
this function traverses the directories in the path and at each
level calls the supplied callback function while also providing
the supplied object for context if required.
e.g. given the path '/foo/bar/baz'
the callback would be called at the equivalent of
'/foo', '/foo/bar' and '/foo/bar/baz'.
The implementation swaps between two different directory/file
handles as it traverses the directories and does not use recursion
in an attempt to use memory efficiently.
If a callback wishes to stop the directory traversal it should
return false--in this case the function will stop the traversal,
tidy up and return false.
If a directory path doesn't exist at some point this function will
also return false and not subsequently call the callback.
If a directory path specified is complete, valid and the callback
did not indicate the traversal should be interrupted then this
function will return true.
*/
SdFile subfile1;
SdFile subfile2;
char buffer[PATH_COMPONENT_BUFFER_LEN];
unsigned int offset = 0;
SdFile *p_parent;
SdFile *p_child;
SdFile *p_tmp_sdfile;
p_child = &subfile1;
p_parent = &parentDir;
while (true) {
boolean moreComponents = getNextPathComponent(filepath, &offset, buffer);
boolean shouldContinue = callback((*p_parent), buffer, !moreComponents, object);
if (!shouldContinue) {
// TODO: Don't repeat this code?
// If it's one we've created then we
// don't need the parent handle anymore.
if (p_parent != &parentDir) {
(*p_parent).close();
}
return false;
}
if (!moreComponents) {
break;
}
boolean exists = (*p_child).open(*p_parent, buffer, O_RDONLY);
// If it's one we've created then we
// don't need the parent handle anymore.
if (p_parent != &parentDir) {
(*p_parent).close();
}
// Handle case when it doesn't exist and we can't continue...
if (exists) {
// We alternate between two file handles as we go down
// the path.
if (p_parent == &parentDir) {
p_parent = &subfile2;
}
p_tmp_sdfile = p_parent;
p_parent = p_child;
p_child = p_tmp_sdfile;
} else {
return false;
}
}
if (p_parent != &parentDir) {
(*p_parent).close(); // TODO: Return/ handle different?
}
return true;
}
/*
The callbacks used to implement various functionality follow.
Each callback is supplied with a parent directory handle,
character string with the name of the current file path component,
a flag indicating if this component is the last in the path and
a pointer to an arbitrary object used for context.
*/
boolean callback_pathExists(SdFile& parentDir, char *filePathComponent,
boolean isLastComponent, void *object) {
/*
Callback used to determine if a file/directory exists in parent
directory.
Returns true if file path exists.
*/
SdFile child;
boolean exists = child.open(parentDir, filePathComponent, O_RDONLY);
if (exists) {
child.close();
}
return exists;
}
boolean callback_makeDirPath(SdFile& parentDir, char *filePathComponent,
boolean isLastComponent, void *object) {
/*
Callback used to create a directory in the parent directory if
it does not already exist.
Returns true if a directory was created or it already existed.
*/
boolean result = false;
SdFile child;
result = callback_pathExists(parentDir, filePathComponent, isLastComponent, object);
if (!result) {
result = child.makeDir(parentDir, filePathComponent);
}
return result;
}
boolean callback_openPath(SdFile& parentDir, char *filePathComponent,
boolean isLastComponent, void *object) {
/*
Callback used to open a file specified by a filepath that may
specify one or more directories above it.
Expects the context object to be an instance of `SDClass` and
will use the `file` property of the instance to open the requested
file/directory with the associated file open mode property.
Always returns true if the directory traversal hasn't reached the
bottom of the directory heirarchy.
Returns false once the file has been opened--to prevent the traversal
from descending further. (This may be unnecessary.)
*/
if (isLastComponent) {
SDClass *p_SD = static_cast<SDClass*>(object);
p_SD->file.open(parentDir, filePathComponent, p_SD->fileOpenMode);
p_SD->c = -1;
// TODO: Return file open result?
return false;
}
return true;
}
boolean callback_remove(SdFile& parentDir, char *filePathComponent,
boolean isLastComponent, void *object) {
if (isLastComponent) {
return SdFile::remove(parentDir, filePathComponent);
}
return true;
}
boolean callback_rmdir(SdFile& parentDir, char *filePathComponent,
boolean isLastComponent, void *object) {
if (isLastComponent) {
SdFile f;
if (!f.open(parentDir, filePathComponent, O_READ)) return false;
return f.rmDir();
}
return true;
}
/* Implementation of class used to create `SDCard` object. */
boolean SDClass::begin(uint8_t csPin) {
/*
Performs the initialisation required by the sdfatlib library.
Return true if initialization succeeds, false otherwise.
*/
return card.init(SPI_HALF_SPEED, csPin) &&
volume.init(card) &&
root.openRoot(volume);
}
File SDClass::open(char *filepath, uint8_t mode) {
/*
Open the supplied file path for reading or writing.
The file content can be accessed via the `file` property of
the `SDClass` object--this property is currently
a standard `SdFile` object from `sdfatlib`.
Defaults to read only.
If `write` is true, default action (when `append` is true) is to
append data to the end of the file.
If `append` is false then the file will be truncated first.
If the file does not exist and it is opened for writing the file
will be created.
An attempt to open a file for reading that does not exist is an
error.
*/
// TODO: Allow for read&write? (Possibly not, as it requires seek.)
fileOpenMode = mode;
walkPath(filepath, root, callback_openPath, this);
return File();
}
//boolean SDClass::close() {
// /*
//
// Closes the file opened by the `open` method.
//
// */
// file.close();
//}
boolean SDClass::exists(char *filepath) {
/*
Returns true if the supplied file path exists.
*/
return walkPath(filepath, root, callback_pathExists);
}
//boolean SDClass::exists(char *filepath, SdFile& parentDir) {
// /*
//
// Returns true if the supplied file path rooted at `parentDir`
// exists.
//
// */
// return walkPath(filepath, parentDir, callback_pathExists);
//}
boolean SDClass::mkdir(char *filepath) {
/*
Makes a single directory or a heirarchy of directories.
A rough equivalent to `mkdir -p`.
*/
return walkPath(filepath, root, callback_makeDirPath);
}
boolean SDClass::rmdir(char *filepath) {
/*
Makes a single directory or a heirarchy of directories.
A rough equivalent to `mkdir -p`.
*/
return walkPath(filepath, root, callback_rmdir);
}
boolean SDClass::remove(char *filepath) {
return walkPath(filepath, root, callback_remove);
}
SDClass SD;

88
libraries/SD/SD.h Normal file
View File

@ -0,0 +1,88 @@
/*
SD - a slightly more friendly wrapper for sdfatlib
This library aims to expose a subset of SD card functionality
in the form of a higher level "wrapper" object.
License: GNU General Public License V3
(Because sdfatlib is licensed with this.)
(C) Copyright 2010 SparkFun Electronics
*/
#ifndef __SD_H__
#define __SD_H__
#include <WProgram.h>
#include <utility/SdFat.h>
#include <utility/SdFatUtil.h>
#define FILE_READ O_READ
#define FILE_TRUNCATE (O_WRITE | O_CREAT | O_TRUNC)
#define FILE_APPEND (O_WRITE | O_CREAT | O_APPEND)
class File : public Stream {
public:
virtual void write(uint8_t);
virtual void write(const char *str);
virtual void write(const uint8_t *buf, size_t size);
virtual int read();
virtual int peek();
virtual int available();
virtual void flush();
void close();
operator bool();
};
class SDClass {
private:
// These are required for initialisation and use of sdfatlib
Sd2Card card;
SdVolume volume;
SdFile root;
public:
// This needs to be called to set up the connection to the SD card
// before other methods are used.
boolean begin(uint8_t csPin = SD_CHIP_SELECT_PIN);
// Open the specified file/directory with the supplied mode (e.g. read or
// write, etc). Returns a File object for interacting with the file.
// Note that currently only one file can be open at a time.
File open(char *filename, uint8_t mode = FILE_READ);
// Methods to determine if the requested file path exists.
boolean exists(char *filepath);
// Create the requested directory heirarchy--if intermediate directories
// do not exist they will be created.
boolean mkdir(char *filepath);
// Delete the file.
boolean remove(char *filepath);
boolean rmdir(char *filepath);
private:
SdFile file;
// This is used to determine the mode used to open a file
// it's here because it's the easiest place to pass the
// information through the directory walking function. But
// it's probably not the best place for it.
// It shouldn't be set directly--it is set via the parameters to `open`.
int fileOpenMode;
int c;
friend class File;
friend boolean callback_openPath(SdFile&, char *, boolean, void *);
};
extern SDClass SD;
#endif

View File

@ -0,0 +1,85 @@
/*
SD card datalogger
This example shows how to log data from three analog sensors
to an SD card using the SD library.
The circuit:
* analog sensors on analog ins 0, 1, and 2
* SD card attached to SPI bus as follows:
** MOSI - pin 11
** MISO - pin 12
** CLK - pin 13
** CS - pin 4
created 24 Nov 2010
updated 2 Dec 2010
by Tom Igoe
This example code is in the public domain.
*/
#include <SD.h>
// On the Ethernet Shield, CS is pin 4. Note that even if it's not
// used as the CS pin, the hardware CS pin (10 on most Arduino boards,
// 53 on the Mega) must be left as an output or the SD library
// functions will not work.
const int chipSelect = 4;
void setup()
{
Serial.begin(9600);
Serial.print("Initializing SD card...");
// make sure that the default chip select pin is set to
// output, even if you don't use it:
pinMode(10, OUTPUT);
// see if the card is present and can be initialized:
if (!SD.begin(chipSelect)) {
Serial.println("Card failed, or not present");
// don't do anything more:
return;
}
Serial.println("card initialized.");
}
void loop()
{
// make a string for assembling the data to log:
String dataString = "";
// read three sensors and append to the string:
for (int analogPin = 0; analogPin < 3; analogPin++) {
int sensor = analogRead(analogPin);
dataString += String(sensor);
if (analogPin < 2) {
dataString += ",";
}
}
// open the file:
File dataFile = SD.open("datalog.txt", FILE_APPEND);
// if the file is available, write to it:
if (dataFile) {
dataFile.println(dataString);
dataFile.close();
// print to the serial port too:
Serial.println(dataString);
}
// if the file isn't open, pop up an error:
else {
Serial.println("error opening datalog.txt");
}
}

View File

@ -0,0 +1,78 @@
/*
SD card basic file example
This example shows how to create and destroy an SD card file
The circuit:
* SD card attached to SPI bus as follows:
** MOSI - pin 11
** MISO - pin 12
** CLK - pin 13
** CS - pin 4
created Nov 2010
by David A. Mellis
updated 2 Dec 2010
by Tom Igoe
This example code is in the public domain.
*/
#include <SD.h>
File myFile;
void setup()
{
Serial.begin(9600);
Serial.print("Initializing SD card...");
// On the Ethernet Shield, CS is pin 4. It's set as an output by default.
// Note that even if it's not used as the CS pin, the hardware SS pin
// (10 on most Arduino boards, 53 on the Mega) must be left as an output
// or the SD library functions will not work.
pinMode(10, OUTPUT);
if (!SD.begin(4)) {
Serial.println("initialization failed!");
return;
}
Serial.println("initialization done.");
if (SD.exists("example.txt")) {
Serial.println("example.txt exists.");
}
else {
Serial.println("example.txt doesn't exist.");
}
// open a new file and immediately close it:
Serial.println("Creating example.txt...");
myFile = SD.open("example.txt", FILE_TRUNCATE);
myFile.close();
// Check to see if the file exists:
if (SD.exists("example.txt")) {
Serial.println("example.txt exists.");
}
else {
Serial.println("example.txt doesn't exist.");
}
// delete the file:
Serial.println("Removing example.txt...");
SD.remove("example.txt");
if (SD.exists("example.txt")){
Serial.println("example.txt exists.");
}
else {
Serial.println("example.txt doesn't exist.");
}
}
void loop()
{
// nothing happens after setup finishes.
}

View File

@ -0,0 +1,78 @@
/*
SD card read/write
This example shows how to read and write data to and from an SD card file
The circuit:
* SD card attached to SPI bus as follows:
** MOSI - pin 11
** MISO - pin 12
** CLK - pin 13
** CS - pin 4
created Nov 2010
by David A. Mellis
updated 2 Dec 2010
by Tom Igoe
This example code is in the public domain.
*/
#include <SD.h>
File myFile;
void setup()
{
Serial.begin(9600);
Serial.print("Initializing SD card...");
// On the Ethernet Shield, CS is pin 4. It's set as an output by default.
// Note that even if it's not used as the CS pin, the hardware SS pin
// (10 on most Arduino boards, 53 on the Mega) must be left as an output
// or the SD library functions will not work.
pinMode(10, OUTPUT);
if (!SD.begin(4)) {
Serial.println("initialization failed!");
return;
}
Serial.println("initialization done.");
// open a file:
myFile = SD.open("test.txt", FILE_TRUNCATE);
// if the file opened okay, write to it:
if (myFile) {
Serial.print("Writing to test.txt...");
myFile.println("testing 1, 2, 3.");
// close the file:
myFile.close();
Serial.println("done.");
} else {
// if the file didn't open, print an error:
Serial.println("error opening test.txt");
}
// re-open the file for reading:
myFile = SD.open("test.txt");
if (myFile) {
Serial.println("test.txt:");
// read from the file until there's nothing else in it:
while (myFile.available()) {
Serial.write(myFile.read());
}
// close the file:
myFile.close();
} else {
// if the file didn't open, print an error:
Serial.println("error opening test.txt");
}
}
void loop()
{
// nothing happens after setup
}

29
libraries/SD/keywords.txt Normal file
View File

@ -0,0 +1,29 @@
#######################################
# Syntax Coloring Map SD
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
SD KEYWORD1
File KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
begin KEYWORD2
exists KEYWORD2
mkdir KEYWORD2
remove KEYWORD2
rmdir KEYWORD2
open KEYWORD2
close KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
FILE_READ LITERAL1
FILE_TRUNCATE LITERAL1
FILE_APPEND LITERAL1

View File

@ -0,0 +1,418 @@
/* Arduino SdFat Library
* Copyright (C) 2009 by William Greiman
*
* This file is part of the Arduino SdFat Library
*
* This Library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This Library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the Arduino SdFat Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#ifndef FatStructs_h
#define FatStructs_h
/**
* \file
* FAT file structures
*/
/*
* mostly from Microsoft document fatgen103.doc
* http://www.microsoft.com/whdc/system/platform/firmware/fatgen.mspx
*/
//------------------------------------------------------------------------------
/** Value for byte 510 of boot block or MBR */
uint8_t const BOOTSIG0 = 0X55;
/** Value for byte 511 of boot block or MBR */
uint8_t const BOOTSIG1 = 0XAA;
//------------------------------------------------------------------------------
/**
* \struct partitionTable
* \brief MBR partition table entry
*
* A partition table entry for a MBR formatted storage device.
* The MBR partition table has four entries.
*/
struct partitionTable {
/**
* Boot Indicator . Indicates whether the volume is the active
* partition. Legal values include: 0X00. Do not use for booting.
* 0X80 Active partition.
*/
uint8_t boot;
/**
* Head part of Cylinder-head-sector address of the first block in
* the partition. Legal values are 0-255. Only used in old PC BIOS.
*/
uint8_t beginHead;
/**
* Sector part of Cylinder-head-sector address of the first block in
* the partition. Legal values are 1-63. Only used in old PC BIOS.
*/
unsigned beginSector : 6;
/** High bits cylinder for first block in partition. */
unsigned beginCylinderHigh : 2;
/**
* Combine beginCylinderLow with beginCylinderHigh. Legal values
* are 0-1023. Only used in old PC BIOS.
*/
uint8_t beginCylinderLow;
/**
* Partition type. See defines that begin with PART_TYPE_ for
* some Microsoft partition types.
*/
uint8_t type;
/**
* head part of cylinder-head-sector address of the last sector in the
* partition. Legal values are 0-255. Only used in old PC BIOS.
*/
uint8_t endHead;
/**
* Sector part of cylinder-head-sector address of the last sector in
* the partition. Legal values are 1-63. Only used in old PC BIOS.
*/
unsigned endSector : 6;
/** High bits of end cylinder */
unsigned endCylinderHigh : 2;
/**
* Combine endCylinderLow with endCylinderHigh. Legal values
* are 0-1023. Only used in old PC BIOS.
*/
uint8_t endCylinderLow;
/** Logical block address of the first block in the partition. */
uint32_t firstSector;
/** Length of the partition, in blocks. */
uint32_t totalSectors;
};
/** Type name for partitionTable */
typedef struct partitionTable part_t;
//------------------------------------------------------------------------------
/**
* \struct masterBootRecord
*
* \brief Master Boot Record
*
* The first block of a storage device that is formatted with a MBR.
*/
struct masterBootRecord {
/** Code Area for master boot program. */
uint8_t codeArea[440];
/** Optional WindowsNT disk signature. May contain more boot code. */
uint32_t diskSignature;
/** Usually zero but may be more boot code. */
uint16_t usuallyZero;
/** Partition tables. */
part_t part[4];
/** First MBR signature byte. Must be 0X55 */
uint8_t mbrSig0;
/** Second MBR signature byte. Must be 0XAA */
uint8_t mbrSig1;
};
/** Type name for masterBootRecord */
typedef struct masterBootRecord mbr_t;
//------------------------------------------------------------------------------
/**
* \struct biosParmBlock
*
* \brief BIOS parameter block
*
* The BIOS parameter block describes the physical layout of a FAT volume.
*/
struct biosParmBlock {
/**
* Count of bytes per sector. This value may take on only the
* following values: 512, 1024, 2048 or 4096
*/
uint16_t bytesPerSector;
/**
* Number of sectors per allocation unit. This value must be a
* power of 2 that is greater than 0. The legal values are
* 1, 2, 4, 8, 16, 32, 64, and 128.
*/
uint8_t sectorsPerCluster;
/**
* Number of sectors before the first FAT.
* This value must not be zero.
*/
uint16_t reservedSectorCount;
/** The count of FAT data structures on the volume. This field should
* always contain the value 2 for any FAT volume of any type.
*/
uint8_t fatCount;
/**
* For FAT12 and FAT16 volumes, this field contains the count of
* 32-byte directory entries in the root directory. For FAT32 volumes,
* this field must be set to 0. For FAT12 and FAT16 volumes, this
* value should always specify a count that when multiplied by 32
* results in a multiple of bytesPerSector. FAT16 volumes should
* use the value 512.
*/
uint16_t rootDirEntryCount;
/**
* This field is the old 16-bit total count of sectors on the volume.
* This count includes the count of all sectors in all four regions
* of the volume. This field can be 0; if it is 0, then totalSectors32
* must be non-zero. For FAT32 volumes, this field must be 0. For
* FAT12 and FAT16 volumes, this field contains the sector count, and
* totalSectors32 is 0 if the total sector count fits
* (is less than 0x10000).
*/
uint16_t totalSectors16;
/**
* This dates back to the old MS-DOS 1.x media determination and is
* no longer usually used for anything. 0xF8 is the standard value
* for fixed (non-removable) media. For removable media, 0xF0 is
* frequently used. Legal values are 0xF0 or 0xF8-0xFF.
*/
uint8_t mediaType;
/**
* Count of sectors occupied by one FAT on FAT12/FAT16 volumes.
* On FAT32 volumes this field must be 0, and sectorsPerFat32
* contains the FAT size count.
*/
uint16_t sectorsPerFat16;
/** Sectors per track for interrupt 0x13. Not used otherwise. */
uint16_t sectorsPerTrtack;
/** Number of heads for interrupt 0x13. Not used otherwise. */
uint16_t headCount;
/**
* Count of hidden sectors preceding the partition that contains this
* FAT volume. This field is generally only relevant for media
* visible on interrupt 0x13.
*/
uint32_t hidddenSectors;
/**
* This field is the new 32-bit total count of sectors on the volume.
* This count includes the count of all sectors in all four regions
* of the volume. This field can be 0; if it is 0, then
* totalSectors16 must be non-zero.
*/
uint32_t totalSectors32;
/**
* Count of sectors occupied by one FAT on FAT32 volumes.
*/
uint32_t sectorsPerFat32;
/**
* This field is only defined for FAT32 media and does not exist on
* FAT12 and FAT16 media.
* Bits 0-3 -- Zero-based number of active FAT.
* Only valid if mirroring is disabled.
* Bits 4-6 -- Reserved.
* Bit 7 -- 0 means the FAT is mirrored at runtime into all FATs.
* -- 1 means only one FAT is active; it is the one referenced in bits 0-3.
* Bits 8-15 -- Reserved.
*/
uint16_t fat32Flags;
/**
* FAT32 version. High byte is major revision number.
* Low byte is minor revision number. Only 0.0 define.
*/
uint16_t fat32Version;
/**
* Cluster number of the first cluster of the root directory for FAT32.
* This usually 2 but not required to be 2.
*/
uint32_t fat32RootCluster;
/**
* Sector number of FSINFO structure in the reserved area of the
* FAT32 volume. Usually 1.
*/
uint16_t fat32FSInfo;
/**
* If non-zero, indicates the sector number in the reserved area
* of the volume of a copy of the boot record. Usually 6.
* No value other than 6 is recommended.
*/
uint16_t fat32BackBootBlock;
/**
* Reserved for future expansion. Code that formats FAT32 volumes
* should always set all of the bytes of this field to 0.
*/
uint8_t fat32Reserved[12];
};
/** Type name for biosParmBlock */
typedef struct biosParmBlock bpb_t;
//------------------------------------------------------------------------------
/**
* \struct fat32BootSector
*
* \brief Boot sector for a FAT16 or FAT32 volume.
*
*/
struct fat32BootSector {
/** X86 jmp to boot program */
uint8_t jmpToBootCode[3];
/** informational only - don't depend on it */
char oemName[8];
/** BIOS Parameter Block */
bpb_t bpb;
/** for int0x13 use value 0X80 for hard drive */
uint8_t driveNumber;
/** used by Windows NT - should be zero for FAT */
uint8_t reserved1;
/** 0X29 if next three fields are valid */
uint8_t bootSignature;
/** usually generated by combining date and time */
uint32_t volumeSerialNumber;
/** should match volume label in root dir */
char volumeLabel[11];
/** informational only - don't depend on it */
char fileSystemType[8];
/** X86 boot code */
uint8_t bootCode[420];
/** must be 0X55 */
uint8_t bootSectorSig0;
/** must be 0XAA */
uint8_t bootSectorSig1;
};
//------------------------------------------------------------------------------
// End Of Chain values for FAT entries
/** FAT16 end of chain value used by Microsoft. */
uint16_t const FAT16EOC = 0XFFFF;
/** Minimum value for FAT16 EOC. Use to test for EOC. */
uint16_t const FAT16EOC_MIN = 0XFFF8;
/** FAT32 end of chain value used by Microsoft. */
uint32_t const FAT32EOC = 0X0FFFFFFF;
/** Minimum value for FAT32 EOC. Use to test for EOC. */
uint32_t const FAT32EOC_MIN = 0X0FFFFFF8;
/** Mask a for FAT32 entry. Entries are 28 bits. */
uint32_t const FAT32MASK = 0X0FFFFFFF;
/** Type name for fat32BootSector */
typedef struct fat32BootSector fbs_t;
//------------------------------------------------------------------------------
/**
* \struct directoryEntry
* \brief FAT short directory entry
*
* Short means short 8.3 name, not the entry size.
*
* Date Format. A FAT directory entry date stamp is a 16-bit field that is
* basically a date relative to the MS-DOS epoch of 01/01/1980. Here is the
* format (bit 0 is the LSB of the 16-bit word, bit 15 is the MSB of the
* 16-bit word):
*
* Bits 9-15: Count of years from 1980, valid value range 0-127
* inclusive (1980-2107).
*
* Bits 5-8: Month of year, 1 = January, valid value range 1-12 inclusive.
*
* Bits 0-4: Day of month, valid value range 1-31 inclusive.
*
* Time Format. A FAT directory entry time stamp is a 16-bit field that has
* a granularity of 2 seconds. Here is the format (bit 0 is the LSB of the
* 16-bit word, bit 15 is the MSB of the 16-bit word).
*
* Bits 11-15: Hours, valid value range 0-23 inclusive.
*
* Bits 5-10: Minutes, valid value range 0-59 inclusive.
*
* Bits 0-4: 2-second count, valid value range 0-29 inclusive (0 - 58 seconds).
*
* The valid time range is from Midnight 00:00:00 to 23:59:58.
*/
struct directoryEntry {
/**
* Short 8.3 name.
* The first eight bytes contain the file name with blank fill.
* The last three bytes contain the file extension with blank fill.
*/
uint8_t name[11];
/** Entry attributes.
*
* The upper two bits of the attribute byte are reserved and should
* always be set to 0 when a file is created and never modified or
* looked at after that. See defines that begin with DIR_ATT_.
*/
uint8_t attributes;
/**
* Reserved for use by Windows NT. Set value to 0 when a file is
* created and never modify or look at it after that.
*/
uint8_t reservedNT;
/**
* The granularity of the seconds part of creationTime is 2 seconds
* so this field is a count of tenths of a second and its valid
* value range is 0-199 inclusive. (WHG note - seems to be hundredths)
*/
uint8_t creationTimeTenths;
/** Time file was created. */
uint16_t creationTime;
/** Date file was created. */
uint16_t creationDate;
/**
* Last access date. Note that there is no last access time, only
* a date. This is the date of last read or write. In the case of
* a write, this should be set to the same date as lastWriteDate.
*/
uint16_t lastAccessDate;
/**
* High word of this entry's first cluster number (always 0 for a
* FAT12 or FAT16 volume).
*/
uint16_t firstClusterHigh;
/** Time of last write. File creation is considered a write. */
uint16_t lastWriteTime;
/** Date of last write. File creation is considered a write. */
uint16_t lastWriteDate;
/** Low word of this entry's first cluster number. */
uint16_t firstClusterLow;
/** 32-bit unsigned holding this file's size in bytes. */
uint32_t fileSize;
};
//------------------------------------------------------------------------------
// Definitions for directory entries
//
/** Type name for directoryEntry */
typedef struct directoryEntry dir_t;
/** escape for name[0] = 0XE5 */
uint8_t const DIR_NAME_0XE5 = 0X05;
/** name[0] value for entry that is free after being "deleted" */
uint8_t const DIR_NAME_DELETED = 0XE5;
/** name[0] value for entry that is free and no allocated entries follow */
uint8_t const DIR_NAME_FREE = 0X00;
/** file is read-only */
uint8_t const DIR_ATT_READ_ONLY = 0X01;
/** File should hidden in directory listings */
uint8_t const DIR_ATT_HIDDEN = 0X02;
/** Entry is for a system file */
uint8_t const DIR_ATT_SYSTEM = 0X04;
/** Directory entry contains the volume label */
uint8_t const DIR_ATT_VOLUME_ID = 0X08;
/** Entry is for a directory */
uint8_t const DIR_ATT_DIRECTORY = 0X10;
/** Old DOS archive bit for backup support */
uint8_t const DIR_ATT_ARCHIVE = 0X20;
/** Test value for long name entry. Test is
(d->attributes & DIR_ATT_LONG_NAME_MASK) == DIR_ATT_LONG_NAME. */
uint8_t const DIR_ATT_LONG_NAME = 0X0F;
/** Test mask for long name entry */
uint8_t const DIR_ATT_LONG_NAME_MASK = 0X3F;
/** defined attribute bits */
uint8_t const DIR_ATT_DEFINED_BITS = 0X3F;
/** Directory entry is part of a long name */
static inline uint8_t DIR_IS_LONG_NAME(const dir_t* dir) {
return (dir->attributes & DIR_ATT_LONG_NAME_MASK) == DIR_ATT_LONG_NAME;
}
/** Mask for file/subdirectory tests */
uint8_t const DIR_ATT_FILE_TYPE_MASK = (DIR_ATT_VOLUME_ID | DIR_ATT_DIRECTORY);
/** Directory entry is for a file */
static inline uint8_t DIR_IS_FILE(const dir_t* dir) {
return (dir->attributes & DIR_ATT_FILE_TYPE_MASK) == 0;
}
/** Directory entry is for a subdirectory */
static inline uint8_t DIR_IS_SUBDIR(const dir_t* dir) {
return (dir->attributes & DIR_ATT_FILE_TYPE_MASK) == DIR_ATT_DIRECTORY;
}
/** Directory entry is for a file or subdirectory */
static inline uint8_t DIR_IS_FILE_OR_SUBDIR(const dir_t* dir) {
return (dir->attributes & DIR_ATT_VOLUME_ID) == 0;
}
#endif // FatStructs_h

View File

@ -0,0 +1,644 @@
/* Arduino Sd2Card Library
* Copyright (C) 2009 by William Greiman
*
* This file is part of the Arduino Sd2Card Library
*
* This Library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This Library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the Arduino Sd2Card Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include <WProgram.h>
#include "Sd2Card.h"
//------------------------------------------------------------------------------
#ifndef SOFTWARE_SPI
// functions for hardware SPI
/** Send a byte to the card */
static void spiSend(uint8_t b) {
SPDR = b;
while (!(SPSR & (1 << SPIF)));
}
/** Receive a byte from the card */
static uint8_t spiRec(void) {
spiSend(0XFF);
return SPDR;
}
#else // SOFTWARE_SPI
//------------------------------------------------------------------------------
/** nop to tune soft SPI timing */
#define nop asm volatile ("nop\n\t")
//------------------------------------------------------------------------------
/** Soft SPI receive */
uint8_t spiRec(void) {
uint8_t data = 0;
// no interrupts during byte receive - about 8 us
cli();
// output pin high - like sending 0XFF
fastDigitalWrite(SPI_MOSI_PIN, HIGH);
for (uint8_t i = 0; i < 8; i++) {
fastDigitalWrite(SPI_SCK_PIN, HIGH);
// adjust so SCK is nice
nop;
nop;
data <<= 1;
if (fastDigitalRead(SPI_MISO_PIN)) data |= 1;
fastDigitalWrite(SPI_SCK_PIN, LOW);
}
// enable interrupts
sei();
return data;
}
//------------------------------------------------------------------------------
/** Soft SPI send */
void spiSend(uint8_t data) {
// no interrupts during byte send - about 8 us
cli();
for (uint8_t i = 0; i < 8; i++) {
fastDigitalWrite(SPI_SCK_PIN, LOW);
fastDigitalWrite(SPI_MOSI_PIN, data & 0X80);
data <<= 1;
fastDigitalWrite(SPI_SCK_PIN, HIGH);
}
// hold SCK high for a few ns
nop;
nop;
nop;
nop;
fastDigitalWrite(SPI_SCK_PIN, LOW);
// enable interrupts
sei();
}
#endif // SOFTWARE_SPI
//------------------------------------------------------------------------------
// send command and return error code. Return zero for OK
uint8_t Sd2Card::cardCommand(uint8_t cmd, uint32_t arg) {
// end read if in partialBlockRead mode
readEnd();
// select card
chipSelectLow();
// wait up to 300 ms if busy
waitNotBusy(300);
// send command
spiSend(cmd | 0x40);
// send argument
for (int8_t s = 24; s >= 0; s -= 8) spiSend(arg >> s);
// send CRC
uint8_t crc = 0XFF;
if (cmd == CMD0) crc = 0X95; // correct crc for CMD0 with arg 0
if (cmd == CMD8) crc = 0X87; // correct crc for CMD8 with arg 0X1AA
spiSend(crc);
// wait for response
for (uint8_t i = 0; ((status_ = spiRec()) & 0X80) && i != 0XFF; i++);
return status_;
}
//------------------------------------------------------------------------------
/**
* Determine the size of an SD flash memory card.
*
* \return The number of 512 byte data blocks in the card
* or zero if an error occurs.
*/
uint32_t Sd2Card::cardSize(void) {
csd_t csd;
if (!readCSD(&csd)) return 0;
if (csd.v1.csd_ver == 0) {
uint8_t read_bl_len = csd.v1.read_bl_len;
uint16_t c_size = (csd.v1.c_size_high << 10)
| (csd.v1.c_size_mid << 2) | csd.v1.c_size_low;
uint8_t c_size_mult = (csd.v1.c_size_mult_high << 1)
| csd.v1.c_size_mult_low;
return (uint32_t)(c_size + 1) << (c_size_mult + read_bl_len - 7);
} else if (csd.v2.csd_ver == 1) {
uint32_t c_size = ((uint32_t)csd.v2.c_size_high << 16)
| (csd.v2.c_size_mid << 8) | csd.v2.c_size_low;
return (c_size + 1) << 10;
} else {
error(SD_CARD_ERROR_BAD_CSD);
return 0;
}
}
//------------------------------------------------------------------------------
void Sd2Card::chipSelectHigh(void) {
digitalWrite(chipSelectPin_, HIGH);
}
//------------------------------------------------------------------------------
void Sd2Card::chipSelectLow(void) {
digitalWrite(chipSelectPin_, LOW);
}
//------------------------------------------------------------------------------
/** Erase a range of blocks.
*
* \param[in] firstBlock The address of the first block in the range.
* \param[in] lastBlock The address of the last block in the range.
*
* \note This function requests the SD card to do a flash erase for a
* range of blocks. The data on the card after an erase operation is
* either 0 or 1, depends on the card vendor. The card must support
* single block erase.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
*/
uint8_t Sd2Card::erase(uint32_t firstBlock, uint32_t lastBlock) {
if (!eraseSingleBlockEnable()) {
error(SD_CARD_ERROR_ERASE_SINGLE_BLOCK);
goto fail;
}
if (type_ != SD_CARD_TYPE_SDHC) {
firstBlock <<= 9;
lastBlock <<= 9;
}
if (cardCommand(CMD32, firstBlock)
|| cardCommand(CMD33, lastBlock)
|| cardCommand(CMD38, 0)) {
error(SD_CARD_ERROR_ERASE);
goto fail;
}
if (!waitNotBusy(SD_ERASE_TIMEOUT)) {
error(SD_CARD_ERROR_ERASE_TIMEOUT);
goto fail;
}
chipSelectHigh();
return true;
fail:
chipSelectHigh();
return false;
}
//------------------------------------------------------------------------------
/** Determine if card supports single block erase.
*
* \return The value one, true, is returned if single block erase is supported.
* The value zero, false, is returned if single block erase is not supported.
*/
uint8_t Sd2Card::eraseSingleBlockEnable(void) {
csd_t csd;
return readCSD(&csd) ? csd.v1.erase_blk_en : 0;
}
//------------------------------------------------------------------------------
/**
* Initialize an SD flash memory card.
*
* \param[in] sckRateID SPI clock rate selector. See setSckRate().
* \param[in] chipSelectPin SD chip select pin number.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure. The reason for failure
* can be determined by calling errorCode() and errorData().
*/
uint8_t Sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin) {
errorCode_ = inBlock_ = partialBlockRead_ = type_ = 0;
chipSelectPin_ = chipSelectPin;
// 16-bit init start time allows over a minute
uint16_t t0 = (uint16_t)millis();
uint32_t arg;
// set pin modes
pinMode(chipSelectPin_, OUTPUT);
chipSelectHigh();
pinMode(SPI_MISO_PIN, INPUT);
pinMode(SPI_MOSI_PIN, OUTPUT);
pinMode(SPI_SCK_PIN, OUTPUT);
#ifndef SOFTWARE_SPI
// SS must be in output mode even it is not chip select
pinMode(SS_PIN, OUTPUT);
digitalWrite(SS_PIN, HIGH); // disable any SPI device using hardware SS pin
// Enable SPI, Master, clock rate f_osc/128
SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0);
// clear double speed
SPSR &= ~(1 << SPI2X);
#endif // SOFTWARE_SPI
// must supply min of 74 clock cycles with CS high.
for (uint8_t i = 0; i < 10; i++) spiSend(0XFF);
chipSelectLow();
// command to go idle in SPI mode
while ((status_ = cardCommand(CMD0, 0)) != R1_IDLE_STATE) {
if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) {
error(SD_CARD_ERROR_CMD0);
goto fail;
}
}
// check SD version
if ((cardCommand(CMD8, 0x1AA) & R1_ILLEGAL_COMMAND)) {
type(SD_CARD_TYPE_SD1);
} else {
// only need last byte of r7 response
for (uint8_t i = 0; i < 4; i++) status_ = spiRec();
if (status_ != 0XAA) {
error(SD_CARD_ERROR_CMD8);
goto fail;
}
type(SD_CARD_TYPE_SD2);
}
// initialize card and send host supports SDHC if SD2
arg = type() == SD_CARD_TYPE_SD2 ? 0X40000000 : 0;
while ((status_ = cardAcmd(ACMD41, arg)) != R1_READY_STATE) {
// check for timeout
if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) {
error(SD_CARD_ERROR_ACMD41);
goto fail;
}
}
// if SD2 read OCR register to check for SDHC card
if (type() == SD_CARD_TYPE_SD2) {
if (cardCommand(CMD58, 0)) {
error(SD_CARD_ERROR_CMD58);
goto fail;
}
if ((spiRec() & 0XC0) == 0XC0) type(SD_CARD_TYPE_SDHC);
// discard rest of ocr - contains allowed voltage range
for (uint8_t i = 0; i < 3; i++) spiRec();
}
chipSelectHigh();
#ifndef SOFTWARE_SPI
return setSckRate(sckRateID);
#else // SOFTWARE_SPI
return true;
#endif // SOFTWARE_SPI
fail:
chipSelectHigh();
return false;
}
//------------------------------------------------------------------------------
/**
* Enable or disable partial block reads.
*
* Enabling partial block reads improves performance by allowing a block
* to be read over the SPI bus as several sub-blocks. Errors may occur
* if the time between reads is too long since the SD card may timeout.
* The SPI SS line will be held low until the entire block is read or
* readEnd() is called.
*
* Use this for applications like the Adafruit Wave Shield.
*
* \param[in] value The value TRUE (non-zero) or FALSE (zero).)
*/
void Sd2Card::partialBlockRead(uint8_t value) {
readEnd();
partialBlockRead_ = value;
}
//------------------------------------------------------------------------------
/**
* Read a 512 byte block from an SD card device.
*
* \param[in] block Logical block to be read.
* \param[out] dst Pointer to the location that will receive the data.
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
*/
uint8_t Sd2Card::readBlock(uint32_t block, uint8_t* dst) {
return readData(block, 0, 512, dst);
}
//------------------------------------------------------------------------------
/**
* Read part of a 512 byte block from an SD card.
*
* \param[in] block Logical block to be read.
* \param[in] offset Number of bytes to skip at start of block
* \param[out] dst Pointer to the location that will receive the data.
* \param[in] count Number of bytes to read
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
*/
uint8_t Sd2Card::readData(uint32_t block,
uint16_t offset, uint16_t count, uint8_t* dst) {
uint16_t n;
if (count == 0) return true;
if ((count + offset) > 512) {
goto fail;
}
if (!inBlock_ || block != block_ || offset < offset_) {
block_ = block;
// use address if not SDHC card
if (type()!= SD_CARD_TYPE_SDHC) block <<= 9;
if (cardCommand(CMD17, block)) {
error(SD_CARD_ERROR_CMD17);
goto fail;
}
if (!waitStartBlock()) {
goto fail;
}
offset_ = 0;
inBlock_ = 1;
}
#ifdef OPTIMIZE_HARDWARE_SPI
// start first spi transfer
SPDR = 0XFF;
// skip data before offset
for (;offset_ < offset; offset_++) {
while (!(SPSR & (1 << SPIF)));
SPDR = 0XFF;
}
// transfer data
n = count - 1;
for (uint16_t i = 0; i < n; i++) {
while (!(SPSR & (1 << SPIF)));
dst[i] = SPDR;
SPDR = 0XFF;
}
// wait for last byte
while (!(SPSR & (1 << SPIF)));
dst[n] = SPDR;
#else // OPTIMIZE_HARDWARE_SPI
// skip data before offset
for (;offset_ < offset; offset_++) {
spiRec();
}
// transfer data
for (uint16_t i = 0; i < count; i++) {
dst[i] = spiRec();
}
#endif // OPTIMIZE_HARDWARE_SPI
offset_ += count;
if (!partialBlockRead_ || offset_ >= 512) {
// read rest of data, checksum and set chip select high
readEnd();
}
return true;
fail:
chipSelectHigh();
return false;
}
//------------------------------------------------------------------------------
/** Skip remaining data in a block when in partial block read mode. */
void Sd2Card::readEnd(void) {
if (inBlock_) {
// skip data and crc
#ifdef OPTIMIZE_HARDWARE_SPI
// optimize skip for hardware
SPDR = 0XFF;
while (offset_++ < 513) {
while (!(SPSR & (1 << SPIF)));
SPDR = 0XFF;
}
// wait for last crc byte
while (!(SPSR & (1 << SPIF)));
#else // OPTIMIZE_HARDWARE_SPI
while (offset_++ < 514) spiRec();
#endif // OPTIMIZE_HARDWARE_SPI
chipSelectHigh();
inBlock_ = 0;
}
}
//------------------------------------------------------------------------------
/** read CID or CSR register */
uint8_t Sd2Card::readRegister(uint8_t cmd, void* buf) {
uint8_t* dst = reinterpret_cast<uint8_t*>(buf);
if (cardCommand(cmd, 0)) {
error(SD_CARD_ERROR_READ_REG);
goto fail;
}
if (!waitStartBlock()) goto fail;
// transfer data
for (uint16_t i = 0; i < 16; i++) dst[i] = spiRec();
spiRec(); // get first crc byte
spiRec(); // get second crc byte
chipSelectHigh();
return true;
fail:
chipSelectHigh();
return false;
}
//------------------------------------------------------------------------------
/**
* Set the SPI clock rate.
*
* \param[in] sckRateID A value in the range [0, 6].
*
* The SPI clock will be set to F_CPU/pow(2, 1 + sckRateID). The maximum
* SPI rate is F_CPU/2 for \a sckRateID = 0 and the minimum rate is F_CPU/128
* for \a scsRateID = 6.
*
* \return The value one, true, is returned for success and the value zero,
* false, is returned for an invalid value of \a sckRateID.
*/
uint8_t Sd2Card::setSckRate(uint8_t sckRateID) {
if (sckRateID > 6) {
error(SD_CARD_ERROR_SCK_RATE);
return false;
}
// see avr processor datasheet for SPI register bit definitions
if ((sckRateID & 1) || sckRateID == 6) {
SPSR &= ~(1 << SPI2X);
} else {
SPSR |= (1 << SPI2X);
}
SPCR &= ~((1 <<SPR1) | (1 << SPR0));
SPCR |= (sckRateID & 4 ? (1 << SPR1) : 0)
| (sckRateID & 2 ? (1 << SPR0) : 0);
return true;
}
//------------------------------------------------------------------------------
// wait for card to go not busy
uint8_t Sd2Card::waitNotBusy(uint16_t timeoutMillis) {
uint16_t t0 = millis();
do {
if (spiRec() == 0XFF) return true;
}
while (((uint16_t)millis() - t0) < timeoutMillis);
return false;
}
//------------------------------------------------------------------------------
/** Wait for start block token */
uint8_t Sd2Card::waitStartBlock(void) {
uint16_t t0 = millis();
while ((status_ = spiRec()) == 0XFF) {
if (((uint16_t)millis() - t0) > SD_READ_TIMEOUT) {
error(SD_CARD_ERROR_READ_TIMEOUT);
goto fail;
}
}
if (status_ != DATA_START_BLOCK) {
error(SD_CARD_ERROR_READ);
goto fail;
}
return true;
fail:
chipSelectHigh();
return false;
}
//------------------------------------------------------------------------------
/**
* Writes a 512 byte block to an SD card.
*
* \param[in] blockNumber Logical block to be written.
* \param[in] src Pointer to the location of the data to be written.
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
*/
uint8_t Sd2Card::writeBlock(uint32_t blockNumber, const uint8_t* src) {
#if SD_PROTECT_BLOCK_ZERO
// don't allow write to first block
if (blockNumber == 0) {
error(SD_CARD_ERROR_WRITE_BLOCK_ZERO);
goto fail;
}
#endif // SD_PROTECT_BLOCK_ZERO
// use address if not SDHC card
if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9;
if (cardCommand(CMD24, blockNumber)) {
error(SD_CARD_ERROR_CMD24);
goto fail;
}
if (!writeData(DATA_START_BLOCK, src)) goto fail;
// wait for flash programming to complete
if (!waitNotBusy(SD_WRITE_TIMEOUT)) {
error(SD_CARD_ERROR_WRITE_TIMEOUT);
goto fail;
}
// response is r2 so get and check two bytes for nonzero
if (cardCommand(CMD13, 0) || spiRec()) {
error(SD_CARD_ERROR_WRITE_PROGRAMMING);
goto fail;
}
chipSelectHigh();
return true;
fail:
chipSelectHigh();
return false;
}
//------------------------------------------------------------------------------
/** Write one data block in a multiple block write sequence */
uint8_t Sd2Card::writeData(const uint8_t* src) {
// wait for previous write to finish
if (!waitNotBusy(SD_WRITE_TIMEOUT)) {
error(SD_CARD_ERROR_WRITE_MULTIPLE);
chipSelectHigh();
return false;
}
return writeData(WRITE_MULTIPLE_TOKEN, src);
}
//------------------------------------------------------------------------------
// send one block of data for write block or write multiple blocks
uint8_t Sd2Card::writeData(uint8_t token, const uint8_t* src) {
#ifdef OPTIMIZE_HARDWARE_SPI
// send data - optimized loop
SPDR = token;
// send two byte per iteration
for (uint16_t i = 0; i < 512; i += 2) {
while (!(SPSR & (1 << SPIF)));
SPDR = src[i];
while (!(SPSR & (1 << SPIF)));
SPDR = src[i+1];
}
// wait for last data byte
while (!(SPSR & (1 << SPIF)));
#else // OPTIMIZE_HARDWARE_SPI
spiSend(token);
for (uint16_t i = 0; i < 512; i++) {
spiSend(src[i]);
}
#endif // OPTIMIZE_HARDWARE_SPI
spiSend(0xff); // dummy crc
spiSend(0xff); // dummy crc
status_ = spiRec();
if ((status_ & DATA_RES_MASK) != DATA_RES_ACCEPTED) {
error(SD_CARD_ERROR_WRITE);
chipSelectHigh();
return false;
}
return true;
}
//------------------------------------------------------------------------------
/** Start a write multiple blocks sequence.
*
* \param[in] blockNumber Address of first block in sequence.
* \param[in] eraseCount The number of blocks to be pre-erased.
*
* \note This function is used with writeData() and writeStop()
* for optimized multiple block writes.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
*/
uint8_t Sd2Card::writeStart(uint32_t blockNumber, uint32_t eraseCount) {
#if SD_PROTECT_BLOCK_ZERO
// don't allow write to first block
if (blockNumber == 0) {
error(SD_CARD_ERROR_WRITE_BLOCK_ZERO);
goto fail;
}
#endif // SD_PROTECT_BLOCK_ZERO
// send pre-erase count
if (cardAcmd(ACMD23, eraseCount)) {
error(SD_CARD_ERROR_ACMD23);
goto fail;
}
// use address if not SDHC card
if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9;
if (cardCommand(CMD25, blockNumber)) {
error(SD_CARD_ERROR_CMD25);
goto fail;
}
return true;
fail:
chipSelectHigh();
return false;
}
//------------------------------------------------------------------------------
/** End a write multiple blocks sequence.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
*/
uint8_t Sd2Card::writeStop(void) {
if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail;
spiSend(STOP_TRAN_TOKEN);
if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail;
chipSelectHigh();
return true;
fail:
error(SD_CARD_ERROR_STOP_TRAN);
chipSelectHigh();
return false;
}

View File

@ -0,0 +1,233 @@
/* Arduino Sd2Card Library
* Copyright (C) 2009 by William Greiman
*
* This file is part of the Arduino Sd2Card Library
*
* This Library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This Library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the Arduino Sd2Card Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#ifndef Sd2Card_h
#define Sd2Card_h
/**
* \file
* Sd2Card class
*/
#include "Sd2PinMap.h"
#include "SdInfo.h"
/** Set SCK to max rate of F_CPU/2. See Sd2Card::setSckRate(). */
uint8_t const SPI_FULL_SPEED = 0;
/** Set SCK rate to F_CPU/4. See Sd2Card::setSckRate(). */
uint8_t const SPI_HALF_SPEED = 1;
/** Set SCK rate to F_CPU/8. Sd2Card::setSckRate(). */
uint8_t const SPI_QUARTER_SPEED = 2;
/**
* Define MEGA_SOFT_SPI non-zero to use software SPI on Mega Arduinos.
* Pins used are SS 10, MOSI 11, MISO 12, and SCK 13.
*
* MEGA_SOFT_SPI allows an unmodified Adafruit GPS Shield to be used
* on Mega Arduinos. Software SPI works well with GPS Shield V1.1
* but many SD cards will fail with GPS Shield V1.0.
*/
#define MEGA_SOFT_SPI 0
//------------------------------------------------------------------------------
#if MEGA_SOFT_SPI && (defined(__AVR_ATmega1280__)||defined(__AVR_ATmega2560__))
#define SOFTWARE_SPI
#endif // MEGA_SOFT_SPI
//------------------------------------------------------------------------------
// SPI pin definitions
//
#ifndef SOFTWARE_SPI
// hardware pin defs
/**
* SD Chip Select pin
*
* Warning if this pin is redefined the hardware SS will pin will be enabled
* as an output by init(). An avr processor will not function as an SPI
* master unless SS is set to output mode.
*/
/** The default chip select pin for the SD card is SS. */
uint8_t const SD_CHIP_SELECT_PIN = SS_PIN;
// The following three pins must not be redefined for hardware SPI.
/** SPI Master Out Slave In pin */
uint8_t const SPI_MOSI_PIN = MOSI_PIN;
/** SPI Master In Slave Out pin */
uint8_t const SPI_MISO_PIN = MISO_PIN;
/** SPI Clock pin */
uint8_t const SPI_SCK_PIN = SCK_PIN;
/** optimize loops for hardware SPI */
#define OPTIMIZE_HARDWARE_SPI
#else // SOFTWARE_SPI
// define software SPI pins so Mega can use unmodified GPS Shield
/** SPI chip select pin */
uint8_t const SD_CHIP_SELECT_PIN = 10;
/** SPI Master Out Slave In pin */
uint8_t const SPI_MOSI_PIN = 11;
/** SPI Master In Slave Out pin */
uint8_t const SPI_MISO_PIN = 12;
/** SPI Clock pin */
uint8_t const SPI_SCK_PIN = 13;
#endif // SOFTWARE_SPI
//------------------------------------------------------------------------------
/** Protect block zero from write if nonzero */
#define SD_PROTECT_BLOCK_ZERO 1
/** init timeout ms */
uint16_t const SD_INIT_TIMEOUT = 2000;
/** erase timeout ms */
uint16_t const SD_ERASE_TIMEOUT = 10000;
/** read timeout ms */
uint16_t const SD_READ_TIMEOUT = 300;
/** write time out ms */
uint16_t const SD_WRITE_TIMEOUT = 600;
//------------------------------------------------------------------------------
// SD card errors
/** timeout error for command CMD0 */
uint8_t const SD_CARD_ERROR_CMD0 = 0X1;
/** CMD8 was not accepted - not a valid SD card*/
uint8_t const SD_CARD_ERROR_CMD8 = 0X2;
/** card returned an error response for CMD17 (read block) */
uint8_t const SD_CARD_ERROR_CMD17 = 0X3;
/** card returned an error response for CMD24 (write block) */
uint8_t const SD_CARD_ERROR_CMD24 = 0X4;
/** WRITE_MULTIPLE_BLOCKS command failed */
uint8_t const SD_CARD_ERROR_CMD25 = 0X05;
/** card returned an error response for CMD58 (read OCR) */
uint8_t const SD_CARD_ERROR_CMD58 = 0X06;
/** SET_WR_BLK_ERASE_COUNT failed */
uint8_t const SD_CARD_ERROR_ACMD23 = 0X07;
/** card's ACMD41 initialization process timeout */
uint8_t const SD_CARD_ERROR_ACMD41 = 0X08;
/** card returned a bad CSR version field */
uint8_t const SD_CARD_ERROR_BAD_CSD = 0X09;
/** erase block group command failed */
uint8_t const SD_CARD_ERROR_ERASE = 0X0A;
/** card not capable of single block erase */
uint8_t const SD_CARD_ERROR_ERASE_SINGLE_BLOCK = 0X0B;
/** Erase sequence timed out */
uint8_t const SD_CARD_ERROR_ERASE_TIMEOUT = 0X0C;
/** card returned an error token instead of read data */
uint8_t const SD_CARD_ERROR_READ = 0X0D;
/** read CID or CSD failed */
uint8_t const SD_CARD_ERROR_READ_REG = 0X0E;
/** timeout while waiting for start of read data */
uint8_t const SD_CARD_ERROR_READ_TIMEOUT = 0X0F;
/** card did not accept STOP_TRAN_TOKEN */
uint8_t const SD_CARD_ERROR_STOP_TRAN = 0X10;
/** card returned an error token as a response to a write operation */
uint8_t const SD_CARD_ERROR_WRITE = 0X11;
/** attempt to write protected block zero */
uint8_t const SD_CARD_ERROR_WRITE_BLOCK_ZERO = 0X12;
/** card did not go ready for a multiple block write */
uint8_t const SD_CARD_ERROR_WRITE_MULTIPLE = 0X13;
/** card returned an error to a CMD13 status check after a write */
uint8_t const SD_CARD_ERROR_WRITE_PROGRAMMING = 0X14;
/** timeout occurred during write programming */
uint8_t const SD_CARD_ERROR_WRITE_TIMEOUT = 0X15;
/** incorrect rate selected */
uint8_t const SD_CARD_ERROR_SCK_RATE = 0X16;
//------------------------------------------------------------------------------
// card types
/** Standard capacity V1 SD card */
uint8_t const SD_CARD_TYPE_SD1 = 1;
/** Standard capacity V2 SD card */
uint8_t const SD_CARD_TYPE_SD2 = 2;
/** High Capacity SD card */
uint8_t const SD_CARD_TYPE_SDHC = 3;
//------------------------------------------------------------------------------
/**
* \class Sd2Card
* \brief Raw access to SD and SDHC flash memory cards.
*/
class Sd2Card {
public:
/** Construct an instance of Sd2Card. */
Sd2Card(void) : errorCode_(0), inBlock_(0), partialBlockRead_(0), type_(0) {}
uint32_t cardSize(void);
uint8_t erase(uint32_t firstBlock, uint32_t lastBlock);
uint8_t eraseSingleBlockEnable(void);
/**
* \return error code for last error. See Sd2Card.h for a list of error codes.
*/
uint8_t errorCode(void) const {return errorCode_;}
/** \return error data for last error. */
uint8_t errorData(void) const {return status_;}
/**
* Initialize an SD flash memory card with default clock rate and chip
* select pin. See sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin).
*/
uint8_t init(void) {
return init(SPI_FULL_SPEED, SD_CHIP_SELECT_PIN);
}
/**
* Initialize an SD flash memory card with the selected SPI clock rate
* and the default SD chip select pin.
* See sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin).
*/
uint8_t init(uint8_t sckRateID) {
return init(sckRateID, SD_CHIP_SELECT_PIN);
}
uint8_t init(uint8_t sckRateID, uint8_t chipSelectPin);
void partialBlockRead(uint8_t value);
/** Returns the current value, true or false, for partial block read. */
uint8_t partialBlockRead(void) const {return partialBlockRead_;}
uint8_t readBlock(uint32_t block, uint8_t* dst);
uint8_t readData(uint32_t block,
uint16_t offset, uint16_t count, uint8_t* dst);
/**
* Read a cards CID register. The CID contains card identification
* information such as Manufacturer ID, Product name, Product serial
* number and Manufacturing date. */
uint8_t readCID(cid_t* cid) {
return readRegister(CMD10, cid);
}
/**
* Read a cards CSD register. The CSD contains Card-Specific Data that
* provides information regarding access to the card's contents. */
uint8_t readCSD(csd_t* csd) {
return readRegister(CMD9, csd);
}
void readEnd(void);
uint8_t setSckRate(uint8_t sckRateID);
/** Return the card type: SD V1, SD V2 or SDHC */
uint8_t type(void) const {return type_;}
uint8_t writeBlock(uint32_t blockNumber, const uint8_t* src);
uint8_t writeData(const uint8_t* src);
uint8_t writeStart(uint32_t blockNumber, uint32_t eraseCount);
uint8_t writeStop(void);
private:
uint32_t block_;
uint8_t chipSelectPin_;
uint8_t errorCode_;
uint8_t inBlock_;
uint16_t offset_;
uint8_t partialBlockRead_;
uint8_t status_;
uint8_t type_;
// private functions
uint8_t cardAcmd(uint8_t cmd, uint32_t arg) {
cardCommand(CMD55, 0);
return cardCommand(cmd, arg);
}
uint8_t cardCommand(uint8_t cmd, uint32_t arg);
void error(uint8_t code) {errorCode_ = code;}
uint8_t readRegister(uint8_t cmd, void* buf);
uint8_t sendWriteCommand(uint32_t blockNumber, uint32_t eraseCount);
void chipSelectHigh(void);
void chipSelectLow(void);
void type(uint8_t value) {type_ = value;}
uint8_t waitNotBusy(uint16_t timeoutMillis);
uint8_t writeData(uint8_t token, const uint8_t* src);
uint8_t waitStartBlock(void);
};
#endif // Sd2Card_h

View File

@ -0,0 +1,353 @@
/* Arduino SdFat Library
* Copyright (C) 2010 by William Greiman
*
* This file is part of the Arduino SdFat Library
*
* This Library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This Library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the Arduino SdFat Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
// Warning this file was generated by a program.
#ifndef Sd2PinMap_h
#define Sd2PinMap_h
#include <avr/io.h>
//------------------------------------------------------------------------------
/** struct for mapping digital pins */
struct pin_map_t {
volatile uint8_t* ddr;
volatile uint8_t* pin;
volatile uint8_t* port;
uint8_t bit;
};
//------------------------------------------------------------------------------
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
// Mega
// Two Wire (aka I2C) ports
uint8_t const SDA_PIN = 20;
uint8_t const SCL_PIN = 21;
// SPI port
uint8_t const SS_PIN = 53;
uint8_t const MOSI_PIN = 51;
uint8_t const MISO_PIN = 50;
uint8_t const SCK_PIN = 52;
static const pin_map_t digitalPinMap[] = {
{&DDRE, &PINE, &PORTE, 0}, // E0 0
{&DDRE, &PINE, &PORTE, 1}, // E1 1
{&DDRE, &PINE, &PORTE, 4}, // E4 2
{&DDRE, &PINE, &PORTE, 5}, // E5 3
{&DDRG, &PING, &PORTG, 5}, // G5 4
{&DDRE, &PINE, &PORTE, 3}, // E3 5
{&DDRH, &PINH, &PORTH, 3}, // H3 6
{&DDRH, &PINH, &PORTH, 4}, // H4 7
{&DDRH, &PINH, &PORTH, 5}, // H5 8
{&DDRH, &PINH, &PORTH, 6}, // H6 9
{&DDRB, &PINB, &PORTB, 4}, // B4 10
{&DDRB, &PINB, &PORTB, 5}, // B5 11
{&DDRB, &PINB, &PORTB, 6}, // B6 12
{&DDRB, &PINB, &PORTB, 7}, // B7 13
{&DDRJ, &PINJ, &PORTJ, 1}, // J1 14
{&DDRJ, &PINJ, &PORTJ, 0}, // J0 15
{&DDRH, &PINH, &PORTH, 1}, // H1 16
{&DDRH, &PINH, &PORTH, 0}, // H0 17
{&DDRD, &PIND, &PORTD, 3}, // D3 18
{&DDRD, &PIND, &PORTD, 2}, // D2 19
{&DDRD, &PIND, &PORTD, 1}, // D1 20
{&DDRD, &PIND, &PORTD, 0}, // D0 21
{&DDRA, &PINA, &PORTA, 0}, // A0 22
{&DDRA, &PINA, &PORTA, 1}, // A1 23
{&DDRA, &PINA, &PORTA, 2}, // A2 24
{&DDRA, &PINA, &PORTA, 3}, // A3 25
{&DDRA, &PINA, &PORTA, 4}, // A4 26
{&DDRA, &PINA, &PORTA, 5}, // A5 27
{&DDRA, &PINA, &PORTA, 6}, // A6 28
{&DDRA, &PINA, &PORTA, 7}, // A7 29
{&DDRC, &PINC, &PORTC, 7}, // C7 30
{&DDRC, &PINC, &PORTC, 6}, // C6 31
{&DDRC, &PINC, &PORTC, 5}, // C5 32
{&DDRC, &PINC, &PORTC, 4}, // C4 33
{&DDRC, &PINC, &PORTC, 3}, // C3 34
{&DDRC, &PINC, &PORTC, 2}, // C2 35
{&DDRC, &PINC, &PORTC, 1}, // C1 36
{&DDRC, &PINC, &PORTC, 0}, // C0 37
{&DDRD, &PIND, &PORTD, 7}, // D7 38
{&DDRG, &PING, &PORTG, 2}, // G2 39
{&DDRG, &PING, &PORTG, 1}, // G1 40
{&DDRG, &PING, &PORTG, 0}, // G0 41
{&DDRL, &PINL, &PORTL, 7}, // L7 42
{&DDRL, &PINL, &PORTL, 6}, // L6 43
{&DDRL, &PINL, &PORTL, 5}, // L5 44
{&DDRL, &PINL, &PORTL, 4}, // L4 45
{&DDRL, &PINL, &PORTL, 3}, // L3 46
{&DDRL, &PINL, &PORTL, 2}, // L2 47
{&DDRL, &PINL, &PORTL, 1}, // L1 48
{&DDRL, &PINL, &PORTL, 0}, // L0 49
{&DDRB, &PINB, &PORTB, 3}, // B3 50
{&DDRB, &PINB, &PORTB, 2}, // B2 51
{&DDRB, &PINB, &PORTB, 1}, // B1 52
{&DDRB, &PINB, &PORTB, 0}, // B0 53
{&DDRF, &PINF, &PORTF, 0}, // F0 54
{&DDRF, &PINF, &PORTF, 1}, // F1 55
{&DDRF, &PINF, &PORTF, 2}, // F2 56
{&DDRF, &PINF, &PORTF, 3}, // F3 57
{&DDRF, &PINF, &PORTF, 4}, // F4 58
{&DDRF, &PINF, &PORTF, 5}, // F5 59
{&DDRF, &PINF, &PORTF, 6}, // F6 60
{&DDRF, &PINF, &PORTF, 7}, // F7 61
{&DDRK, &PINK, &PORTK, 0}, // K0 62
{&DDRK, &PINK, &PORTK, 1}, // K1 63
{&DDRK, &PINK, &PORTK, 2}, // K2 64
{&DDRK, &PINK, &PORTK, 3}, // K3 65
{&DDRK, &PINK, &PORTK, 4}, // K4 66
{&DDRK, &PINK, &PORTK, 5}, // K5 67
{&DDRK, &PINK, &PORTK, 6}, // K6 68
{&DDRK, &PINK, &PORTK, 7} // K7 69
};
//------------------------------------------------------------------------------
#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__)
// Sanguino
// Two Wire (aka I2C) ports
uint8_t const SDA_PIN = 17;
uint8_t const SCL_PIN = 18;
// SPI port
uint8_t const SS_PIN = 4;
uint8_t const MOSI_PIN = 5;
uint8_t const MISO_PIN = 6;
uint8_t const SCK_PIN = 7;
static const pin_map_t digitalPinMap[] = {
{&DDRB, &PINB, &PORTB, 0}, // B0 0
{&DDRB, &PINB, &PORTB, 1}, // B1 1
{&DDRB, &PINB, &PORTB, 2}, // B2 2
{&DDRB, &PINB, &PORTB, 3}, // B3 3
{&DDRB, &PINB, &PORTB, 4}, // B4 4
{&DDRB, &PINB, &PORTB, 5}, // B5 5
{&DDRB, &PINB, &PORTB, 6}, // B6 6
{&DDRB, &PINB, &PORTB, 7}, // B7 7
{&DDRD, &PIND, &PORTD, 0}, // D0 8
{&DDRD, &PIND, &PORTD, 1}, // D1 9
{&DDRD, &PIND, &PORTD, 2}, // D2 10
{&DDRD, &PIND, &PORTD, 3}, // D3 11
{&DDRD, &PIND, &PORTD, 4}, // D4 12
{&DDRD, &PIND, &PORTD, 5}, // D5 13
{&DDRD, &PIND, &PORTD, 6}, // D6 14
{&DDRD, &PIND, &PORTD, 7}, // D7 15
{&DDRC, &PINC, &PORTC, 0}, // C0 16
{&DDRC, &PINC, &PORTC, 1}, // C1 17
{&DDRC, &PINC, &PORTC, 2}, // C2 18
{&DDRC, &PINC, &PORTC, 3}, // C3 19
{&DDRC, &PINC, &PORTC, 4}, // C4 20
{&DDRC, &PINC, &PORTC, 5}, // C5 21
{&DDRC, &PINC, &PORTC, 6}, // C6 22
{&DDRC, &PINC, &PORTC, 7}, // C7 23
{&DDRA, &PINA, &PORTA, 7}, // A7 24
{&DDRA, &PINA, &PORTA, 6}, // A6 25
{&DDRA, &PINA, &PORTA, 5}, // A5 26
{&DDRA, &PINA, &PORTA, 4}, // A4 27
{&DDRA, &PINA, &PORTA, 3}, // A3 28
{&DDRA, &PINA, &PORTA, 2}, // A2 29
{&DDRA, &PINA, &PORTA, 1}, // A1 30
{&DDRA, &PINA, &PORTA, 0} // A0 31
};
//------------------------------------------------------------------------------
#elif defined(__AVR_ATmega32U4__)
// Teensy 2.0
// Two Wire (aka I2C) ports
uint8_t const SDA_PIN = 6;
uint8_t const SCL_PIN = 5;
// SPI port
uint8_t const SS_PIN = 0;
uint8_t const MOSI_PIN = 2;
uint8_t const MISO_PIN = 3;
uint8_t const SCK_PIN = 1;
static const pin_map_t digitalPinMap[] = {
{&DDRB, &PINB, &PORTB, 0}, // B0 0
{&DDRB, &PINB, &PORTB, 1}, // B1 1
{&DDRB, &PINB, &PORTB, 2}, // B2 2
{&DDRB, &PINB, &PORTB, 3}, // B3 3
{&DDRB, &PINB, &PORTB, 7}, // B7 4
{&DDRD, &PIND, &PORTD, 0}, // D0 5
{&DDRD, &PIND, &PORTD, 1}, // D1 6
{&DDRD, &PIND, &PORTD, 2}, // D2 7
{&DDRD, &PIND, &PORTD, 3}, // D3 8
{&DDRC, &PINC, &PORTC, 6}, // C6 9
{&DDRC, &PINC, &PORTC, 7}, // C7 10
{&DDRD, &PIND, &PORTD, 6}, // D6 11
{&DDRD, &PIND, &PORTD, 7}, // D7 12
{&DDRB, &PINB, &PORTB, 4}, // B4 13
{&DDRB, &PINB, &PORTB, 5}, // B5 14
{&DDRB, &PINB, &PORTB, 6}, // B6 15
{&DDRF, &PINF, &PORTF, 7}, // F7 16
{&DDRF, &PINF, &PORTF, 6}, // F6 17
{&DDRF, &PINF, &PORTF, 5}, // F5 18
{&DDRF, &PINF, &PORTF, 4}, // F4 19
{&DDRF, &PINF, &PORTF, 1}, // F1 20
{&DDRF, &PINF, &PORTF, 0}, // F0 21
{&DDRD, &PIND, &PORTD, 4}, // D4 22
{&DDRD, &PIND, &PORTD, 5}, // D5 23
{&DDRE, &PINE, &PORTE, 6} // E6 24
};
//------------------------------------------------------------------------------
#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
// Teensy++ 1.0 & 2.0
// Two Wire (aka I2C) ports
uint8_t const SDA_PIN = 1;
uint8_t const SCL_PIN = 0;
// SPI port
uint8_t const SS_PIN = 20;
uint8_t const MOSI_PIN = 22;
uint8_t const MISO_PIN = 23;
uint8_t const SCK_PIN = 21;
static const pin_map_t digitalPinMap[] = {
{&DDRD, &PIND, &PORTD, 0}, // D0 0
{&DDRD, &PIND, &PORTD, 1}, // D1 1
{&DDRD, &PIND, &PORTD, 2}, // D2 2
{&DDRD, &PIND, &PORTD, 3}, // D3 3
{&DDRD, &PIND, &PORTD, 4}, // D4 4
{&DDRD, &PIND, &PORTD, 5}, // D5 5
{&DDRD, &PIND, &PORTD, 6}, // D6 6
{&DDRD, &PIND, &PORTD, 7}, // D7 7
{&DDRE, &PINE, &PORTE, 0}, // E0 8
{&DDRE, &PINE, &PORTE, 1}, // E1 9
{&DDRC, &PINC, &PORTC, 0}, // C0 10
{&DDRC, &PINC, &PORTC, 1}, // C1 11
{&DDRC, &PINC, &PORTC, 2}, // C2 12
{&DDRC, &PINC, &PORTC, 3}, // C3 13
{&DDRC, &PINC, &PORTC, 4}, // C4 14
{&DDRC, &PINC, &PORTC, 5}, // C5 15
{&DDRC, &PINC, &PORTC, 6}, // C6 16
{&DDRC, &PINC, &PORTC, 7}, // C7 17
{&DDRE, &PINE, &PORTE, 6}, // E6 18
{&DDRE, &PINE, &PORTE, 7}, // E7 19
{&DDRB, &PINB, &PORTB, 0}, // B0 20
{&DDRB, &PINB, &PORTB, 1}, // B1 21
{&DDRB, &PINB, &PORTB, 2}, // B2 22
{&DDRB, &PINB, &PORTB, 3}, // B3 23
{&DDRB, &PINB, &PORTB, 4}, // B4 24
{&DDRB, &PINB, &PORTB, 5}, // B5 25
{&DDRB, &PINB, &PORTB, 6}, // B6 26
{&DDRB, &PINB, &PORTB, 7}, // B7 27
{&DDRA, &PINA, &PORTA, 0}, // A0 28
{&DDRA, &PINA, &PORTA, 1}, // A1 29
{&DDRA, &PINA, &PORTA, 2}, // A2 30
{&DDRA, &PINA, &PORTA, 3}, // A3 31
{&DDRA, &PINA, &PORTA, 4}, // A4 32
{&DDRA, &PINA, &PORTA, 5}, // A5 33
{&DDRA, &PINA, &PORTA, 6}, // A6 34
{&DDRA, &PINA, &PORTA, 7}, // A7 35
{&DDRE, &PINE, &PORTE, 4}, // E4 36
{&DDRE, &PINE, &PORTE, 5}, // E5 37
{&DDRF, &PINF, &PORTF, 0}, // F0 38
{&DDRF, &PINF, &PORTF, 1}, // F1 39
{&DDRF, &PINF, &PORTF, 2}, // F2 40
{&DDRF, &PINF, &PORTF, 3}, // F3 41
{&DDRF, &PINF, &PORTF, 4}, // F4 42
{&DDRF, &PINF, &PORTF, 5}, // F5 43
{&DDRF, &PINF, &PORTF, 6}, // F6 44
{&DDRF, &PINF, &PORTF, 7} // F7 45
};
//------------------------------------------------------------------------------
#else // defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
// 168 and 328 Arduinos
// Two Wire (aka I2C) ports
uint8_t const SDA_PIN = 18;
uint8_t const SCL_PIN = 19;
// SPI port
uint8_t const SS_PIN = 10;
uint8_t const MOSI_PIN = 11;
uint8_t const MISO_PIN = 12;
uint8_t const SCK_PIN = 13;
static const pin_map_t digitalPinMap[] = {
{&DDRD, &PIND, &PORTD, 0}, // D0 0
{&DDRD, &PIND, &PORTD, 1}, // D1 1
{&DDRD, &PIND, &PORTD, 2}, // D2 2
{&DDRD, &PIND, &PORTD, 3}, // D3 3
{&DDRD, &PIND, &PORTD, 4}, // D4 4
{&DDRD, &PIND, &PORTD, 5}, // D5 5
{&DDRD, &PIND, &PORTD, 6}, // D6 6
{&DDRD, &PIND, &PORTD, 7}, // D7 7
{&DDRB, &PINB, &PORTB, 0}, // B0 8
{&DDRB, &PINB, &PORTB, 1}, // B1 9
{&DDRB, &PINB, &PORTB, 2}, // B2 10
{&DDRB, &PINB, &PORTB, 3}, // B3 11
{&DDRB, &PINB, &PORTB, 4}, // B4 12
{&DDRB, &PINB, &PORTB, 5}, // B5 13
{&DDRC, &PINC, &PORTC, 0}, // C0 14
{&DDRC, &PINC, &PORTC, 1}, // C1 15
{&DDRC, &PINC, &PORTC, 2}, // C2 16
{&DDRC, &PINC, &PORTC, 3}, // C3 17
{&DDRC, &PINC, &PORTC, 4}, // C4 18
{&DDRC, &PINC, &PORTC, 5} // C5 19
};
#endif // defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
//------------------------------------------------------------------------------
static const uint8_t digitalPinCount = sizeof(digitalPinMap)/sizeof(pin_map_t);
uint8_t badPinNumber(void)
__attribute__((error("Pin number is too large or not a constant")));
static inline __attribute__((always_inline))
uint8_t getPinMode(uint8_t pin) {
if (__builtin_constant_p(pin) && pin < digitalPinCount) {
return (*digitalPinMap[pin].ddr >> digitalPinMap[pin].bit) & 1;
} else {
return badPinNumber();
}
}
static inline __attribute__((always_inline))
void setPinMode(uint8_t pin, uint8_t mode) {
if (__builtin_constant_p(pin) && pin < digitalPinCount) {
if (mode) {
*digitalPinMap[pin].ddr |= 1 << digitalPinMap[pin].bit;
} else {
*digitalPinMap[pin].ddr &= ~(1 << digitalPinMap[pin].bit);
}
} else {
badPinNumber();
}
}
static inline __attribute__((always_inline))
uint8_t fastDigitalRead(uint8_t pin) {
if (__builtin_constant_p(pin) && pin < digitalPinCount) {
return (*digitalPinMap[pin].pin >> digitalPinMap[pin].bit) & 1;
} else {
return badPinNumber();
}
}
static inline __attribute__((always_inline))
void fastDigitalWrite(uint8_t pin, uint8_t value) {
if (__builtin_constant_p(pin) && pin < digitalPinCount) {
if (value) {
*digitalPinMap[pin].port |= 1 << digitalPinMap[pin].bit;
} else {
*digitalPinMap[pin].port &= ~(1 << digitalPinMap[pin].bit);
}
} else {
badPinNumber();
}
}
#endif // Sd2PinMap_h

View File

@ -0,0 +1,547 @@
/* Arduino SdFat Library
* Copyright (C) 2009 by William Greiman
*
* This file is part of the Arduino SdFat Library
*
* This Library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This Library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the Arduino SdFat Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#ifndef SdFat_h
#define SdFat_h
/**
* \file
* SdFile and SdVolume classes
*/
#include <avr/pgmspace.h>
#include "Sd2Card.h"
#include "FatStructs.h"
#include "Print.h"
//------------------------------------------------------------------------------
/**
* Allow use of deprecated functions if non-zero
*/
#define ALLOW_DEPRECATED_FUNCTIONS 1
//------------------------------------------------------------------------------
// forward declaration since SdVolume is used in SdFile
class SdVolume;
//==============================================================================
// SdFile class
// flags for ls()
/** ls() flag to print modify date */
uint8_t const LS_DATE = 1;
/** ls() flag to print file size */
uint8_t const LS_SIZE = 2;
/** ls() flag for recursive list of subdirectories */
uint8_t const LS_R = 4;
// use the gnu style oflag in open()
/** open() oflag for reading */
uint8_t const O_READ = 0X01;
/** open() oflag - same as O_READ */
uint8_t const O_RDONLY = O_READ;
/** open() oflag for write */
uint8_t const O_WRITE = 0X02;
/** open() oflag - same as O_WRITE */
uint8_t const O_WRONLY = O_WRITE;
/** open() oflag for reading and writing */
uint8_t const O_RDWR = (O_READ | O_WRITE);
/** open() oflag mask for access modes */
uint8_t const O_ACCMODE = (O_READ | O_WRITE);
/** The file offset shall be set to the end of the file prior to each write. */
uint8_t const O_APPEND = 0X04;
/** synchronous writes - call sync() after each write */
uint8_t const O_SYNC = 0X08;
/** create the file if nonexistent */
uint8_t const O_CREAT = 0X10;
/** If O_CREAT and O_EXCL are set, open() shall fail if the file exists */
uint8_t const O_EXCL = 0X20;
/** truncate the file to zero length */
uint8_t const O_TRUNC = 0X40;
// flags for timestamp
/** set the file's last access date */
uint8_t const T_ACCESS = 1;
/** set the file's creation date and time */
uint8_t const T_CREATE = 2;
/** Set the file's write date and time */
uint8_t const T_WRITE = 4;
// values for type_
/** This SdFile has not been opened. */
uint8_t const FAT_FILE_TYPE_CLOSED = 0;
/** SdFile for a file */
uint8_t const FAT_FILE_TYPE_NORMAL = 1;
/** SdFile for a FAT16 root directory */
uint8_t const FAT_FILE_TYPE_ROOT16 = 2;
/** SdFile for a FAT32 root directory */
uint8_t const FAT_FILE_TYPE_ROOT32 = 3;
/** SdFile for a subdirectory */
uint8_t const FAT_FILE_TYPE_SUBDIR = 4;
/** Test value for directory type */
uint8_t const FAT_FILE_TYPE_MIN_DIR = FAT_FILE_TYPE_ROOT16;
/** date field for FAT directory entry */
static inline uint16_t FAT_DATE(uint16_t year, uint8_t month, uint8_t day) {
return (year - 1980) << 9 | month << 5 | day;
}
/** year part of FAT directory date field */
static inline uint16_t FAT_YEAR(uint16_t fatDate) {
return 1980 + (fatDate >> 9);
}
/** month part of FAT directory date field */
static inline uint8_t FAT_MONTH(uint16_t fatDate) {
return (fatDate >> 5) & 0XF;
}
/** day part of FAT directory date field */
static inline uint8_t FAT_DAY(uint16_t fatDate) {
return fatDate & 0X1F;
}
/** time field for FAT directory entry */
static inline uint16_t FAT_TIME(uint8_t hour, uint8_t minute, uint8_t second) {
return hour << 11 | minute << 5 | second >> 1;
}
/** hour part of FAT directory time field */
static inline uint8_t FAT_HOUR(uint16_t fatTime) {
return fatTime >> 11;
}
/** minute part of FAT directory time field */
static inline uint8_t FAT_MINUTE(uint16_t fatTime) {
return(fatTime >> 5) & 0X3F;
}
/** second part of FAT directory time field */
static inline uint8_t FAT_SECOND(uint16_t fatTime) {
return 2*(fatTime & 0X1F);
}
/** Default date for file timestamps is 1 Jan 2000 */
uint16_t const FAT_DEFAULT_DATE = ((2000 - 1980) << 9) | (1 << 5) | 1;
/** Default time for file timestamp is 1 am */
uint16_t const FAT_DEFAULT_TIME = (1 << 11);
//------------------------------------------------------------------------------
/**
* \class SdFile
* \brief Access FAT16 and FAT32 files on SD and SDHC cards.
*/
class SdFile : public Print {
public:
/** Create an instance of SdFile. */
SdFile(void) : type_(FAT_FILE_TYPE_CLOSED) {}
/**
* writeError is set to true if an error occurs during a write().
* Set writeError to false before calling print() and/or write() and check
* for true after calls to print() and/or write().
*/
bool writeError;
/**
* Cancel unbuffered reads for this file.
* See setUnbufferedRead()
*/
void clearUnbufferedRead(void) {
flags_ &= ~F_FILE_UNBUFFERED_READ;
}
uint8_t close(void);
uint8_t contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock);
uint8_t createContiguous(SdFile* dirFile,
const char* fileName, uint32_t size);
/** \return The current cluster number for a file or directory. */
uint32_t curCluster(void) const {return curCluster_;}
/** \return The current position for a file or directory. */
uint32_t curPosition(void) const {return curPosition_;}
/**
* Set the date/time callback function
*
* \param[in] dateTime The user's call back function. The callback
* function is of the form:
*
* \code
* void dateTime(uint16_t* date, uint16_t* time) {
* uint16_t year;
* uint8_t month, day, hour, minute, second;
*
* // User gets date and time from GPS or real-time clock here
*
* // return date using FAT_DATE macro to format fields
* *date = FAT_DATE(year, month, day);
*
* // return time using FAT_TIME macro to format fields
* *time = FAT_TIME(hour, minute, second);
* }
* \endcode
*
* Sets the function that is called when a file is created or when
* a file's directory entry is modified by sync(). All timestamps,
* access, creation, and modify, are set when a file is created.
* sync() maintains the last access date and last modify date/time.
*
* See the timestamp() function.
*/
static void dateTimeCallback(
void (*dateTime)(uint16_t* date, uint16_t* time)) {
dateTime_ = dateTime;
}
/**
* Cancel the date/time callback function.
*/
static void dateTimeCallbackCancel(void) {
// use explicit zero since NULL is not defined for Sanguino
dateTime_ = 0;
}
/** \return Address of the block that contains this file's directory. */
uint32_t dirBlock(void) const {return dirBlock_;}
uint8_t dirEntry(dir_t* dir);
/** \return Index of this file's directory in the block dirBlock. */
uint8_t dirIndex(void) const {return dirIndex_;}
static void dirName(const dir_t& dir, char* name);
/** \return The total number of bytes in a file or directory. */
uint32_t fileSize(void) const {return fileSize_;}
/** \return The first cluster number for a file or directory. */
uint32_t firstCluster(void) const {return firstCluster_;}
/** \return True if this is a SdFile for a directory else false. */
uint8_t isDir(void) const {return type_ >= FAT_FILE_TYPE_MIN_DIR;}
/** \return True if this is a SdFile for a file else false. */
uint8_t isFile(void) const {return type_ == FAT_FILE_TYPE_NORMAL;}
/** \return True if this is a SdFile for an open file/directory else false. */
uint8_t isOpen(void) const {return type_ != FAT_FILE_TYPE_CLOSED;}
/** \return True if this is a SdFile for a subdirectory else false. */
uint8_t isSubDir(void) const {return type_ == FAT_FILE_TYPE_SUBDIR;}
/** \return True if this is a SdFile for the root directory. */
uint8_t isRoot(void) const {
return type_ == FAT_FILE_TYPE_ROOT16 || type_ == FAT_FILE_TYPE_ROOT32;
}
void ls(uint8_t flags = 0, uint8_t indent = 0);
uint8_t makeDir(SdFile* dir, const char* dirName);
uint8_t open(SdFile* dirFile, uint16_t index, uint8_t oflag);
uint8_t open(SdFile* dirFile, const char* fileName, uint8_t oflag);
uint8_t openRoot(SdVolume* vol);
static void printDirName(const dir_t& dir, uint8_t width);
static void printFatDate(uint16_t fatDate);
static void printFatTime(uint16_t fatTime);
static void printTwoDigits(uint8_t v);
/**
* Read the next byte from a file.
*
* \return For success read returns the next byte in the file as an int.
* If an error occurs or end of file is reached -1 is returned.
*/
int16_t read(void) {
uint8_t b;
return read(&b, 1) == 1 ? b : -1;
}
int16_t read(void* buf, uint16_t nbyte);
int8_t readDir(dir_t* dir);
static uint8_t remove(SdFile* dirFile, const char* fileName);
uint8_t remove(void);
/** Set the file's current position to zero. */
void rewind(void) {
curPosition_ = curCluster_ = 0;
}
uint8_t rmDir(void);
uint8_t rmRfStar(void);
/** Set the files position to current position + \a pos. See seekSet(). */
uint8_t seekCur(uint32_t pos) {
return seekSet(curPosition_ + pos);
}
/**
* Set the files current position to end of file. Useful to position
* a file for append. See seekSet().
*/
uint8_t seekEnd(void) {return seekSet(fileSize_);}
uint8_t seekSet(uint32_t pos);
/**
* Use unbuffered reads to access this file. Used with Wave
* Shield ISR. Used with Sd2Card::partialBlockRead() in WaveRP.
*
* Not recommended for normal applications.
*/
void setUnbufferedRead(void) {
if (isFile()) flags_ |= F_FILE_UNBUFFERED_READ;
}
uint8_t timestamp(uint8_t flag, uint16_t year, uint8_t month, uint8_t day,
uint8_t hour, uint8_t minute, uint8_t second);
uint8_t sync(void);
/** Type of this SdFile. You should use isFile() or isDir() instead of type()
* if possible.
*
* \return The file or directory type.
*/
uint8_t type(void) const {return type_;}
uint8_t truncate(uint32_t size);
/** \return Unbuffered read flag. */
uint8_t unbufferedRead(void) const {
return flags_ & F_FILE_UNBUFFERED_READ;
}
/** \return SdVolume that contains this file. */
SdVolume* volume(void) const {return vol_;}
void write(uint8_t b);
int16_t write(const void* buf, uint16_t nbyte);
void write(const char* str);
void write_P(PGM_P str);
void writeln_P(PGM_P str);
//------------------------------------------------------------------------------
#if ALLOW_DEPRECATED_FUNCTIONS
// Deprecated functions - suppress cpplint warnings with NOLINT comment
/** \deprecated Use:
* uint8_t SdFile::contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock);
*/
uint8_t contiguousRange(uint32_t& bgnBlock, uint32_t& endBlock) { // NOLINT
return contiguousRange(&bgnBlock, &endBlock);
}
/** \deprecated Use:
* uint8_t SdFile::createContiguous(SdFile* dirFile,
* const char* fileName, uint32_t size)
*/
uint8_t createContiguous(SdFile& dirFile, // NOLINT
const char* fileName, uint32_t size) {
return createContiguous(&dirFile, fileName, size);
}
/**
* \deprecated Use:
* static void SdFile::dateTimeCallback(
* void (*dateTime)(uint16_t* date, uint16_t* time));
*/
static void dateTimeCallback(
void (*dateTime)(uint16_t& date, uint16_t& time)) { // NOLINT
oldDateTime_ = dateTime;
dateTime_ = dateTime ? oldToNew : 0;
}
/** \deprecated Use: uint8_t SdFile::dirEntry(dir_t* dir); */
uint8_t dirEntry(dir_t& dir) {return dirEntry(&dir);} // NOLINT
/** \deprecated Use:
* uint8_t SdFile::makeDir(SdFile* dir, const char* dirName);
*/
uint8_t makeDir(SdFile& dir, const char* dirName) { // NOLINT
return makeDir(&dir, dirName);
}
/** \deprecated Use:
* uint8_t SdFile::open(SdFile* dirFile, const char* fileName, uint8_t oflag);
*/
uint8_t open(SdFile& dirFile, // NOLINT
const char* fileName, uint8_t oflag) {
return open(&dirFile, fileName, oflag);
}
/** \deprecated Do not use in new apps */
uint8_t open(SdFile& dirFile, const char* fileName) { // NOLINT
return open(dirFile, fileName, O_RDWR);
}
/** \deprecated Use:
* uint8_t SdFile::open(SdFile* dirFile, uint16_t index, uint8_t oflag);
*/
uint8_t open(SdFile& dirFile, uint16_t index, uint8_t oflag) { // NOLINT
return open(&dirFile, index, oflag);
}
/** \deprecated Use: uint8_t SdFile::openRoot(SdVolume* vol); */
uint8_t openRoot(SdVolume& vol) {return openRoot(&vol);} // NOLINT
/** \deprecated Use: int8_t SdFile::readDir(dir_t* dir); */
int8_t readDir(dir_t& dir) {return readDir(&dir);} // NOLINT
/** \deprecated Use:
* static uint8_t SdFile::remove(SdFile* dirFile, const char* fileName);
*/
static uint8_t remove(SdFile& dirFile, const char* fileName) { // NOLINT
return remove(&dirFile, fileName);
}
//------------------------------------------------------------------------------
// rest are private
private:
static void (*oldDateTime_)(uint16_t& date, uint16_t& time); // NOLINT
static void oldToNew(uint16_t* date, uint16_t* time) {
uint16_t d;
uint16_t t;
oldDateTime_(d, t);
*date = d;
*time = t;
}
#endif // ALLOW_DEPRECATED_FUNCTIONS
private:
// bits defined in flags_
// should be 0XF
static uint8_t const F_OFLAG = (O_ACCMODE | O_APPEND | O_SYNC);
// available bits
static uint8_t const F_UNUSED = 0X30;
// use unbuffered SD read
static uint8_t const F_FILE_UNBUFFERED_READ = 0X40;
// sync of directory entry required
static uint8_t const F_FILE_DIR_DIRTY = 0X80;
// make sure F_OFLAG is ok
#if ((F_UNUSED | F_FILE_UNBUFFERED_READ | F_FILE_DIR_DIRTY) & F_OFLAG)
#error flags_ bits conflict
#endif // flags_ bits
// private data
uint8_t flags_; // See above for definition of flags_ bits
uint8_t type_; // type of file see above for values
uint32_t curCluster_; // cluster for current file position
uint32_t curPosition_; // current file position in bytes from beginning
uint32_t dirBlock_; // SD block that contains directory entry for file
uint8_t dirIndex_; // index of entry in dirBlock 0 <= dirIndex_ <= 0XF
uint32_t fileSize_; // file size in bytes
uint32_t firstCluster_; // first cluster of file
SdVolume* vol_; // volume where file is located
// private functions
uint8_t addCluster(void);
uint8_t addDirCluster(void);
dir_t* cacheDirEntry(uint8_t action);
static void (*dateTime_)(uint16_t* date, uint16_t* time);
static uint8_t make83Name(const char* str, uint8_t* name);
uint8_t openCachedEntry(uint8_t cacheIndex, uint8_t oflags);
dir_t* readDirCache(void);
};
//==============================================================================
// SdVolume class
/**
* \brief Cache for an SD data block
*/
union cache_t {
/** Used to access cached file data blocks. */
uint8_t data[512];
/** Used to access cached FAT16 entries. */
uint16_t fat16[256];
/** Used to access cached FAT32 entries. */
uint32_t fat32[128];
/** Used to access cached directory entries. */
dir_t dir[16];
/** Used to access a cached MasterBoot Record. */
mbr_t mbr;
/** Used to access to a cached FAT boot sector. */
fbs_t fbs;
};
//------------------------------------------------------------------------------
/**
* \class SdVolume
* \brief Access FAT16 and FAT32 volumes on SD and SDHC cards.
*/
class SdVolume {
public:
/** Create an instance of SdVolume */
SdVolume(void) :allocSearchStart_(2), fatType_(0) {}
/** Clear the cache and returns a pointer to the cache. Used by the WaveRP
* recorder to do raw write to the SD card. Not for normal apps.
*/
static uint8_t* cacheClear(void) {
cacheFlush();
cacheBlockNumber_ = 0XFFFFFFFF;
return cacheBuffer_.data;
}
/**
* Initialize a FAT volume. Try partition one first then try super
* floppy format.
*
* \param[in] dev The Sd2Card where the volume is located.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure. Reasons for
* failure include not finding a valid partition, not finding a valid
* FAT file system or an I/O error.
*/
uint8_t init(Sd2Card* dev) { return init(dev, 1) ? true : init(dev, 0);}
uint8_t init(Sd2Card* dev, uint8_t part);
// inline functions that return volume info
/** \return The volume's cluster size in blocks. */
uint8_t blocksPerCluster(void) const {return blocksPerCluster_;}
/** \return The number of blocks in one FAT. */
uint32_t blocksPerFat(void) const {return blocksPerFat_;}
/** \return The total number of clusters in the volume. */
uint32_t clusterCount(void) const {return clusterCount_;}
/** \return The shift count required to multiply by blocksPerCluster. */
uint8_t clusterSizeShift(void) const {return clusterSizeShift_;}
/** \return The logical block number for the start of file data. */
uint32_t dataStartBlock(void) const {return dataStartBlock_;}
/** \return The number of FAT structures on the volume. */
uint8_t fatCount(void) const {return fatCount_;}
/** \return The logical block number for the start of the first FAT. */
uint32_t fatStartBlock(void) const {return fatStartBlock_;}
/** \return The FAT type of the volume. Values are 12, 16 or 32. */
uint8_t fatType(void) const {return fatType_;}
/** \return The number of entries in the root directory for FAT16 volumes. */
uint32_t rootDirEntryCount(void) const {return rootDirEntryCount_;}
/** \return The logical block number for the start of the root directory
on FAT16 volumes or the first cluster number on FAT32 volumes. */
uint32_t rootDirStart(void) const {return rootDirStart_;}
/** return a pointer to the Sd2Card object for this volume */
static Sd2Card* sdCard(void) {return sdCard_;}
//------------------------------------------------------------------------------
#if ALLOW_DEPRECATED_FUNCTIONS
// Deprecated functions - suppress cpplint warnings with NOLINT comment
/** \deprecated Use: uint8_t SdVolume::init(Sd2Card* dev); */
uint8_t init(Sd2Card& dev) {return init(&dev);} // NOLINT
/** \deprecated Use: uint8_t SdVolume::init(Sd2Card* dev, uint8_t vol); */
uint8_t init(Sd2Card& dev, uint8_t part) { // NOLINT
return init(&dev, part);
}
#endif // ALLOW_DEPRECATED_FUNCTIONS
//------------------------------------------------------------------------------
private:
// Allow SdFile access to SdVolume private data.
friend class SdFile;
// value for action argument in cacheRawBlock to indicate read from cache
static uint8_t const CACHE_FOR_READ = 0;
// value for action argument in cacheRawBlock to indicate cache dirty
static uint8_t const CACHE_FOR_WRITE = 1;
static cache_t cacheBuffer_; // 512 byte cache for device blocks
static uint32_t cacheBlockNumber_; // Logical number of block in the cache
static Sd2Card* sdCard_; // Sd2Card object for cache
static uint8_t cacheDirty_; // cacheFlush() will write block if true
static uint32_t cacheMirrorBlock_; // block number for mirror FAT
//
uint32_t allocSearchStart_; // start cluster for alloc search
uint8_t blocksPerCluster_; // cluster size in blocks
uint32_t blocksPerFat_; // FAT size in blocks
uint32_t clusterCount_; // clusters in one FAT
uint8_t clusterSizeShift_; // shift to convert cluster count to block count
uint32_t dataStartBlock_; // first data block number
uint8_t fatCount_; // number of FATs on volume
uint32_t fatStartBlock_; // start block for first FAT
uint8_t fatType_; // volume type (12, 16, OR 32)
uint16_t rootDirEntryCount_; // number of entries in FAT16 root dir
uint32_t rootDirStart_; // root start block for FAT16, cluster for FAT32
//----------------------------------------------------------------------------
uint8_t allocContiguous(uint32_t count, uint32_t* curCluster);
uint8_t blockOfCluster(uint32_t position) const {
return (position >> 9) & (blocksPerCluster_ - 1);}
uint32_t clusterStartBlock(uint32_t cluster) const {
return dataStartBlock_ + ((cluster - 2) << clusterSizeShift_);}
uint32_t blockNumber(uint32_t cluster, uint32_t position) const {
return clusterStartBlock(cluster) + blockOfCluster(position);}
static uint8_t cacheFlush(void);
static uint8_t cacheRawBlock(uint32_t blockNumber, uint8_t action);
static void cacheSetDirty(void) {cacheDirty_ |= CACHE_FOR_WRITE;}
static uint8_t cacheZeroBlock(uint32_t blockNumber);
uint8_t chainSize(uint32_t beginCluster, uint32_t* size) const;
uint8_t fatGet(uint32_t cluster, uint32_t* value) const;
uint8_t fatPut(uint32_t cluster, uint32_t value);
uint8_t fatPutEOC(uint32_t cluster) {
return fatPut(cluster, 0x0FFFFFFF);
}
uint8_t freeChain(uint32_t cluster);
uint8_t isEOC(uint32_t cluster) const {
return cluster >= (fatType_ == 16 ? FAT16EOC_MIN : FAT32EOC_MIN);
}
uint8_t readBlock(uint32_t block, uint8_t* dst) {
return sdCard_->readBlock(block, dst);}
uint8_t readData(uint32_t block, uint16_t offset,
uint16_t count, uint8_t* dst) {
return sdCard_->readData(block, offset, count, dst);
}
uint8_t writeBlock(uint32_t block, const uint8_t* dst) {
return sdCard_->writeBlock(block, dst);
}
};
#endif // SdFat_h

View File

@ -0,0 +1,70 @@
/* Arduino SdFat Library
* Copyright (C) 2008 by William Greiman
*
* This file is part of the Arduino SdFat Library
*
* This Library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This Library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with the Arduino SdFat Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#ifndef SdFatUtil_h
#define SdFatUtil_h
/**
* \file
* Useful utility functions.
*/
#include <WProgram.h>
#include <avr/pgmspace.h>
/** Store and print a string in flash memory.*/
#define PgmPrint(x) SerialPrint_P(PSTR(x))
/** Store and print a string in flash memory followed by a CR/LF.*/
#define PgmPrintln(x) SerialPrintln_P(PSTR(x))
/** Defined so doxygen works for function definitions. */
#define NOINLINE __attribute__((noinline))
//------------------------------------------------------------------------------
/** Return the number of bytes currently free in RAM. */
static int FreeRam(void) {
extern int __bss_end;
extern int* __brkval;
int free_memory;
if (reinterpret_cast<int>(__brkval) == 0) {
// if no heap use from end of bss section
free_memory = reinterpret_cast<int>(&free_memory)
- reinterpret_cast<int>(&__bss_end);
} else {
// use from top of stack to heap
free_memory = reinterpret_cast<int>(&free_memory)
- reinterpret_cast<int>(__brkval);
}
return free_memory;
}
//------------------------------------------------------------------------------
/**
* %Print a string in flash memory to the serial port.
*
* \param[in] str Pointer to string stored in flash memory.
*/
static NOINLINE void SerialPrint_P(PGM_P str) {
for (uint8_t c; (c = pgm_read_byte(str)); str++) Serial.print(c);
}
//------------------------------------------------------------------------------
/**
* %Print a string in flash memory followed by a CR/LF.
*
* \param[in] str Pointer to string stored in flash memory.
*/
static NOINLINE void SerialPrintln_P(PGM_P str) {
SerialPrint_P(str);
Serial.println();
}
#endif // #define SdFatUtil_h

View File

@ -0,0 +1,202 @@
/* Arduino SdFat Library
* Copyright (C) 2009 by William Greiman
*
* This file is part of the Arduino SdFat Library
*
* This Library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This Library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the Arduino SdFat Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
/**
\mainpage Arduino SdFat Library
<CENTER>Copyright &copy; 2009 by William Greiman
</CENTER>
\section Intro Introduction
The Arduino SdFat Library is a minimal implementation of FAT16 and FAT32
file systems on SD flash memory cards. Standard SD and high capacity
SDHC cards are supported.
The SdFat only supports short 8.3 names.
The main classes in SdFat are Sd2Card, SdVolume, and SdFile.
The Sd2Card class supports access to standard SD cards and SDHC cards. Most
applications will only need to call the Sd2Card::init() member function.
The SdVolume class supports FAT16 and FAT32 partitions. Most applications
will only need to call the SdVolume::init() member function.
The SdFile class provides file access functions such as open(), read(),
remove(), write(), close() and sync(). This class supports access to the root
directory and subdirectories.
A number of example are provided in the SdFat/examples folder. These were
developed to test SdFat and illustrate its use.
SdFat was developed for high speed data recording. SdFat was used to implement
an audio record/play class, WaveRP, for the Adafruit Wave Shield. This
application uses special Sd2Card calls to write to contiguous files in raw mode.
These functions reduce write latency so that audio can be recorded with the
small amount of RAM in the Arduino.
\section SDcard SD\SDHC Cards
Arduinos access SD cards using the cards SPI protocol. PCs, Macs, and
most consumer devices use the 4-bit parallel SD protocol. A card that
functions well on A PC or Mac may not work well on the Arduino.
Most cards have good SPI read performance but cards vary widely in SPI
write performance. Write performance is limited by how efficiently the
card manages internal erase/remapping operations. The Arduino cannot
optimize writes to reduce erase operations because of its limit RAM.
SanDisk cards generally have good write performance. They seem to have
more internal RAM buffering than other cards and therefore can limit
the number of flash erase operations that the Arduino forces due to its
limited RAM.
\section Hardware Hardware Configuration
SdFat was developed using an
<A HREF = "http://www.adafruit.com/"> Adafruit Industries</A>
<A HREF = "http://www.ladyada.net/make/waveshield/"> Wave Shield</A>.
The hardware interface to the SD card should not use a resistor based level
shifter. SdFat sets the SPI bus frequency to 8 MHz which results in signal
rise times that are too slow for the edge detectors in many newer SD card
controllers when resistor voltage dividers are used.
The 5 to 3.3 V level shifter for 5 V Arduinos should be IC based like the
74HC4050N based circuit shown in the file SdLevel.png. The Adafruit Wave Shield
uses a 74AHC125N. Gravitech sells SD and MicroSD Card Adapters based on the
74LCX245.
If you are using a resistor based level shifter and are having problems try
setting the SPI bus frequency to 4 MHz. This can be done by using
card.init(SPI_HALF_SPEED) to initialize the SD card.
\section comment Bugs and Comments
If you wish to report bugs or have comments, send email to fat16lib@sbcglobal.net.
\section SdFatClass SdFat Usage
SdFat uses a slightly restricted form of short names.
Only printable ASCII characters are supported. No characters with code point
values greater than 127 are allowed. Space is not allowed even though space
was allowed in the API of early versions of DOS.
Short names are limited to 8 characters followed by an optional period (.)
and extension of up to 3 characters. The characters may be any combination
of letters and digits. The following special characters are also allowed:
$ % ' - _ @ ~ ` ! ( ) { } ^ # &
Short names are always converted to upper case and their original case
value is lost.
\note
The Arduino Print class uses character
at a time writes so it was necessary to use a \link SdFile::sync() sync() \endlink
function to control when data is written to the SD card.
\par
An application which writes to a file using \link Print::print() print()\endlink,
\link Print::println() println() \endlink
or \link SdFile::write write() \endlink must call \link SdFile::sync() sync() \endlink
at the appropriate time to force data and directory information to be written
to the SD Card. Data and directory information are also written to the SD card
when \link SdFile::close() close() \endlink is called.
\par
Applications must use care calling \link SdFile::sync() sync() \endlink
since 2048 bytes of I/O is required to update file and
directory information. This includes writing the current data block, reading
the block that contains the directory entry for update, writing the directory
block back and reading back the current data block.
It is possible to open a file with two or more instances of SdFile. A file may
be corrupted if data is written to the file by more than one instance of SdFile.
\section HowTo How to format SD Cards as FAT Volumes
You should use a freshly formatted SD card for best performance. FAT
file systems become slower if many files have been created and deleted.
This is because the directory entry for a deleted file is marked as deleted,
but is not deleted. When a new file is created, these entries must be scanned
before creating the file, a flaw in the FAT design. Also files can become
fragmented which causes reads and writes to be slower.
Microsoft operating systems support removable media formatted with a
Master Boot Record, MBR, or formatted as a super floppy with a FAT Boot Sector
in block zero.
Microsoft operating systems expect MBR formatted removable media
to have only one partition. The first partition should be used.
Microsoft operating systems do not support partitioning SD flash cards.
If you erase an SD card with a program like KillDisk, Most versions of
Windows will format the card as a super floppy.
The best way to restore an SD card's format is to use SDFormatter
which can be downloaded from:
http://www.sdcard.org/consumers/formatter/
SDFormatter aligns flash erase boundaries with file
system structures which reduces write latency and file system overhead.
SDFormatter does not have an option for FAT type so it may format
small cards as FAT12.
After the MBR is restored by SDFormatter you may need to reformat small
cards that have been formatted FAT12 to force the volume type to be FAT16.
If you reformat the SD card with an OS utility, choose a cluster size that
will result in:
4084 < CountOfClusters && CountOfClusters < 65525
The volume will then be FAT16.
If you are formatting an SD card on OS X or Linux, be sure to use the first
partition. Format this partition with a cluster count in above range.
\section References References
Adafruit Industries:
http://www.adafruit.com/
http://www.ladyada.net/make/waveshield/
The Arduino site:
http://www.arduino.cc/
For more information about FAT file systems see:
http://www.microsoft.com/whdc/system/platform/firmware/fatgen.mspx
For information about using SD cards as SPI devices see:
http://www.sdcard.org/developers/tech/sdcard/pls/Simplified_Physical_Layer_Spec.pdf
The ATmega328 datasheet:
http://www.atmel.com/dyn/resources/prod_documents/doc8161.pdf
*/

View File

@ -0,0 +1,1252 @@
/* Arduino SdFat Library
* Copyright (C) 2009 by William Greiman
*
* This file is part of the Arduino SdFat Library
*
* This Library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This Library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the Arduino SdFat Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include <SdFat.h>
#include <avr/pgmspace.h>
#include <WProgram.h>
//------------------------------------------------------------------------------
// callback function for date/time
void (*SdFile::dateTime_)(uint16_t* date, uint16_t* time) = NULL;
#if ALLOW_DEPRECATED_FUNCTIONS
// suppress cpplint warnings with NOLINT comment
void (*SdFile::oldDateTime_)(uint16_t& date, uint16_t& time) = NULL; // NOLINT
#endif // ALLOW_DEPRECATED_FUNCTIONS
//------------------------------------------------------------------------------
// add a cluster to a file
uint8_t SdFile::addCluster() {
if (!vol_->allocContiguous(1, &curCluster_)) return false;
// if first cluster of file link to directory entry
if (firstCluster_ == 0) {
firstCluster_ = curCluster_;
flags_ |= F_FILE_DIR_DIRTY;
}
return true;
}
//------------------------------------------------------------------------------
// Add a cluster to a directory file and zero the cluster.
// return with first block of cluster in the cache
uint8_t SdFile::addDirCluster(void) {
if (!addCluster()) return false;
// zero data in cluster insure first cluster is in cache
uint32_t block = vol_->clusterStartBlock(curCluster_);
for (uint8_t i = vol_->blocksPerCluster_; i != 0; i--) {
if (!SdVolume::cacheZeroBlock(block + i - 1)) return false;
}
// Increase directory file size by cluster size
fileSize_ += 512UL << vol_->clusterSizeShift_;
return true;
}
//------------------------------------------------------------------------------
// cache a file's directory entry
// return pointer to cached entry or null for failure
dir_t* SdFile::cacheDirEntry(uint8_t action) {
if (!SdVolume::cacheRawBlock(dirBlock_, action)) return NULL;
return SdVolume::cacheBuffer_.dir + dirIndex_;
}
//------------------------------------------------------------------------------
/**
* Close a file and force cached data and directory information
* to be written to the storage device.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* Reasons for failure include no file is open or an I/O error.
*/
uint8_t SdFile::close(void) {
if (!sync())return false;
type_ = FAT_FILE_TYPE_CLOSED;
return true;
}
//------------------------------------------------------------------------------
/**
* Check for contiguous file and return its raw block range.
*
* \param[out] bgnBlock the first block address for the file.
* \param[out] endBlock the last block address for the file.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* Reasons for failure include file is not contiguous, file has zero length
* or an I/O error occurred.
*/
uint8_t SdFile::contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock) {
// error if no blocks
if (firstCluster_ == 0) return false;
for (uint32_t c = firstCluster_; ; c++) {
uint32_t next;
if (!vol_->fatGet(c, &next)) return false;
// check for contiguous
if (next != (c + 1)) {
// error if not end of chain
if (!vol_->isEOC(next)) return false;
*bgnBlock = vol_->clusterStartBlock(firstCluster_);
*endBlock = vol_->clusterStartBlock(c)
+ vol_->blocksPerCluster_ - 1;
return true;
}
}
}
//------------------------------------------------------------------------------
/**
* Create and open a new contiguous file of a specified size.
*
* \note This function only supports short DOS 8.3 names.
* See open() for more information.
*
* \param[in] dirFile The directory where the file will be created.
* \param[in] fileName A valid DOS 8.3 file name.
* \param[in] size The desired file size.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* Reasons for failure include \a fileName contains
* an invalid DOS 8.3 file name, the FAT volume has not been initialized,
* a file is already open, the file already exists, the root
* directory is full or an I/O error.
*
*/
uint8_t SdFile::createContiguous(SdFile* dirFile,
const char* fileName, uint32_t size) {
// don't allow zero length file
if (size == 0) return false;
if (!open(dirFile, fileName, O_CREAT | O_EXCL | O_RDWR)) return false;
// calculate number of clusters needed
uint32_t count = ((size - 1) >> (vol_->clusterSizeShift_ + 9)) + 1;
// allocate clusters
if (!vol_->allocContiguous(count, &firstCluster_)) {
remove();
return false;
}
fileSize_ = size;
// insure sync() will update dir entry
flags_ |= F_FILE_DIR_DIRTY;
return sync();
}
//------------------------------------------------------------------------------
/**
* Return a files directory entry
*
* \param[out] dir Location for return of the files directory entry.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
*/
uint8_t SdFile::dirEntry(dir_t* dir) {
// make sure fields on SD are correct
if (!sync()) return false;
// read entry
dir_t* p = cacheDirEntry(SdVolume::CACHE_FOR_READ);
if (!p) return false;
// copy to caller's struct
memcpy(dir, p, sizeof(dir_t));
return true;
}
//------------------------------------------------------------------------------
/**
* Format the name field of \a dir into the 13 byte array
* \a name in standard 8.3 short name format.
*
* \param[in] dir The directory structure containing the name.
* \param[out] name A 13 byte char array for the formatted name.
*/
void SdFile::dirName(const dir_t& dir, char* name) {
uint8_t j = 0;
for (uint8_t i = 0; i < 11; i++) {
if (dir.name[i] == ' ')continue;
if (i == 8) name[j++] = '.';
name[j++] = dir.name[i];
}
name[j] = 0;
}
//------------------------------------------------------------------------------
/** List directory contents to Serial.
*
* \param[in] flags The inclusive OR of
*
* LS_DATE - %Print file modification date
*
* LS_SIZE - %Print file size.
*
* LS_R - Recursive list of subdirectories.
*
* \param[in] indent Amount of space before file name. Used for recursive
* list to indicate subdirectory level.
*/
void SdFile::ls(uint8_t flags, uint8_t indent) {
dir_t* p;
rewind();
while ((p = readDirCache())) {
// done if past last used entry
if (p->name[0] == DIR_NAME_FREE) break;
// skip deleted entry and entries for . and ..
if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') continue;
// only list subdirectories and files
if (!DIR_IS_FILE_OR_SUBDIR(p)) continue;
// print any indent spaces
for (int8_t i = 0; i < indent; i++) Serial.print(' ');
// print file name with possible blank fill
printDirName(*p, flags & (LS_DATE | LS_SIZE) ? 14 : 0);
// print modify date/time if requested
if (flags & LS_DATE) {
printFatDate(p->lastWriteDate);
Serial.print(' ');
printFatTime(p->lastWriteTime);
}
// print size if requested
if (!DIR_IS_SUBDIR(p) && (flags & LS_SIZE)) {
Serial.print(' ');
Serial.print(p->fileSize);
}
Serial.println();
// list subdirectory content if requested
if ((flags & LS_R) && DIR_IS_SUBDIR(p)) {
uint16_t index = curPosition()/32 - 1;
SdFile s;
if (s.open(this, index, O_READ)) s.ls(flags, indent + 2);
seekSet(32 * (index + 1));
}
}
}
//------------------------------------------------------------------------------
// format directory name field from a 8.3 name string
uint8_t SdFile::make83Name(const char* str, uint8_t* name) {
uint8_t c;
uint8_t n = 7; // max index for part before dot
uint8_t i = 0;
// blank fill name and extension
while (i < 11) name[i++] = ' ';
i = 0;
while ((c = *str++) != '\0') {
if (c == '.') {
if (n == 10) return false; // only one dot allowed
n = 10; // max index for full 8.3 name
i = 8; // place for extension
} else {
// illegal FAT characters
PGM_P p = PSTR("|<>^+=?/[];,*\"\\");
uint8_t b;
while ((b = pgm_read_byte(p++))) if (b == c) return false;
// check size and only allow ASCII printable characters
if (i > n || c < 0X21 || c > 0X7E)return false;
// only upper case allowed in 8.3 names - convert lower to upper
name[i++] = c < 'a' || c > 'z' ? c : c + ('A' - 'a');
}
}
// must have a file name, extension is optional
return name[0] != ' ';
}
//------------------------------------------------------------------------------
/** Make a new directory.
*
* \param[in] dir An open SdFat instance for the directory that will containing
* the new directory.
*
* \param[in] dirName A valid 8.3 DOS name for the new directory.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* Reasons for failure include this SdFile is already open, \a dir is not a
* directory, \a dirName is invalid or already exists in \a dir.
*/
uint8_t SdFile::makeDir(SdFile* dir, const char* dirName) {
dir_t d;
// create a normal file
if (!open(dir, dirName, O_CREAT | O_EXCL | O_RDWR)) return false;
// convert SdFile to directory
flags_ = O_READ;
type_ = FAT_FILE_TYPE_SUBDIR;
// allocate and zero first cluster
if (!addDirCluster())return false;
// force entry to SD
if (!sync()) return false;
// cache entry - should already be in cache due to sync() call
dir_t* p = cacheDirEntry(SdVolume::CACHE_FOR_WRITE);
if (!p) return false;
// change directory entry attribute
p->attributes = DIR_ATT_DIRECTORY;
// make entry for '.'
memcpy(&d, p, sizeof(d));
for (uint8_t i = 1; i < 11; i++) d.name[i] = ' ';
d.name[0] = '.';
// cache block for '.' and '..'
uint32_t block = vol_->clusterStartBlock(firstCluster_);
if (!SdVolume::cacheRawBlock(block, SdVolume::CACHE_FOR_WRITE)) return false;
// copy '.' to block
memcpy(&SdVolume::cacheBuffer_.dir[0], &d, sizeof(d));
// make entry for '..'
d.name[1] = '.';
if (dir->isRoot()) {
d.firstClusterLow = 0;
d.firstClusterHigh = 0;
} else {
d.firstClusterLow = dir->firstCluster_ & 0XFFFF;
d.firstClusterHigh = dir->firstCluster_ >> 16;
}
// copy '..' to block
memcpy(&SdVolume::cacheBuffer_.dir[1], &d, sizeof(d));
// set position after '..'
curPosition_ = 2 * sizeof(d);
// write first block
return SdVolume::cacheFlush();
}
//------------------------------------------------------------------------------
/**
* Open a file or directory by name.
*
* \param[in] dirFile An open SdFat instance for the directory containing the
* file to be opened.
*
* \param[in] fileName A valid 8.3 DOS name for a file to be opened.
*
* \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive
* OR of flags from the following list
*
* O_READ - Open for reading.
*
* O_RDONLY - Same as O_READ.
*
* O_WRITE - Open for writing.
*
* O_WRONLY - Same as O_WRITE.
*
* O_RDWR - Open for reading and writing.
*
* O_APPEND - If set, the file offset shall be set to the end of the
* file prior to each write.
*
* O_CREAT - If the file exists, this flag has no effect except as noted
* under O_EXCL below. Otherwise, the file shall be created
*
* O_EXCL - If O_CREAT and O_EXCL are set, open() shall fail if the file exists.
*
* O_SYNC - Call sync() after each write. This flag should not be used with
* write(uint8_t), write_P(PGM_P), writeln_P(PGM_P), or the Arduino Print class.
* These functions do character at a time writes so sync() will be called
* after each byte.
*
* O_TRUNC - If the file exists and is a regular file, and the file is
* successfully opened and is not read only, its length shall be truncated to 0.
*
* \note Directory files must be opened read only. Write and truncation is
* not allowed for directory files.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* Reasons for failure include this SdFile is already open, \a difFile is not
* a directory, \a fileName is invalid, the file does not exist
* or can't be opened in the access mode specified by oflag.
*/
uint8_t SdFile::open(SdFile* dirFile, const char* fileName, uint8_t oflag) {
uint8_t dname[11];
dir_t* p;
// error if already open
if (isOpen())return false;
if (!make83Name(fileName, dname)) return false;
vol_ = dirFile->vol_;
dirFile->rewind();
// bool for empty entry found
uint8_t emptyFound = false;
// search for file
while (dirFile->curPosition_ < dirFile->fileSize_) {
uint8_t index = 0XF & (dirFile->curPosition_ >> 5);
p = dirFile->readDirCache();
if (p == NULL) return false;
if (p->name[0] == DIR_NAME_FREE || p->name[0] == DIR_NAME_DELETED) {
// remember first empty slot
if (!emptyFound) {
emptyFound = true;
dirIndex_ = index;
dirBlock_ = SdVolume::cacheBlockNumber_;
}
// done if no entries follow
if (p->name[0] == DIR_NAME_FREE) break;
} else if (!memcmp(dname, p->name, 11)) {
// don't open existing file if O_CREAT and O_EXCL
if ((oflag & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) return false;
// open found file
return openCachedEntry(0XF & index, oflag);
}
}
// only create file if O_CREAT and O_WRITE
if ((oflag & (O_CREAT | O_WRITE)) != (O_CREAT | O_WRITE)) return false;
// cache found slot or add cluster if end of file
if (emptyFound) {
p = cacheDirEntry(SdVolume::CACHE_FOR_WRITE);
if (!p) return false;
} else {
if (dirFile->type_ == FAT_FILE_TYPE_ROOT16) return false;
// add and zero cluster for dirFile - first cluster is in cache for write
if (!dirFile->addDirCluster()) return false;
// use first entry in cluster
dirIndex_ = 0;
p = SdVolume::cacheBuffer_.dir;
}
// initialize as empty file
memset(p, 0, sizeof(dir_t));
memcpy(p->name, dname, 11);
// set timestamps
if (dateTime_) {
// call user function
dateTime_(&p->creationDate, &p->creationTime);
} else {
// use default date/time
p->creationDate = FAT_DEFAULT_DATE;
p->creationTime = FAT_DEFAULT_TIME;
}
p->lastAccessDate = p->creationDate;
p->lastWriteDate = p->creationDate;
p->lastWriteTime = p->creationTime;
// force write of entry to SD
if (!SdVolume::cacheFlush()) return false;
// open entry in cache
return openCachedEntry(dirIndex_, oflag);
}
//------------------------------------------------------------------------------
/**
* Open a file by index.
*
* \param[in] dirFile An open SdFat instance for the directory.
*
* \param[in] index The \a index of the directory entry for the file to be
* opened. The value for \a index is (directory file position)/32.
*
* \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive
* OR of flags O_READ, O_WRITE, O_TRUNC, and O_SYNC.
*
* See open() by fileName for definition of flags and return values.
*
*/
uint8_t SdFile::open(SdFile* dirFile, uint16_t index, uint8_t oflag) {
// error if already open
if (isOpen())return false;
// don't open existing file if O_CREAT and O_EXCL - user call error
if ((oflag & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) return false;
vol_ = dirFile->vol_;
// seek to location of entry
if (!dirFile->seekSet(32 * index)) return false;
// read entry into cache
dir_t* p = dirFile->readDirCache();
if (p == NULL) return false;
// error if empty slot or '.' or '..'
if (p->name[0] == DIR_NAME_FREE ||
p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') {
return false;
}
// open cached entry
return openCachedEntry(index & 0XF, oflag);
}
//------------------------------------------------------------------------------
// open a cached directory entry. Assumes vol_ is initializes
uint8_t SdFile::openCachedEntry(uint8_t dirIndex, uint8_t oflag) {
// location of entry in cache
dir_t* p = SdVolume::cacheBuffer_.dir + dirIndex;
// write or truncate is an error for a directory or read-only file
if (p->attributes & (DIR_ATT_READ_ONLY | DIR_ATT_DIRECTORY)) {
if (oflag & (O_WRITE | O_TRUNC)) return false;
}
// remember location of directory entry on SD
dirIndex_ = dirIndex;
dirBlock_ = SdVolume::cacheBlockNumber_;
// copy first cluster number for directory fields
firstCluster_ = (uint32_t)p->firstClusterHigh << 16;
firstCluster_ |= p->firstClusterLow;
// make sure it is a normal file or subdirectory
if (DIR_IS_FILE(p)) {
fileSize_ = p->fileSize;
type_ = FAT_FILE_TYPE_NORMAL;
} else if (DIR_IS_SUBDIR(p)) {
if (!vol_->chainSize(firstCluster_, &fileSize_)) return false;
type_ = FAT_FILE_TYPE_SUBDIR;
} else {
return false;
}
// save open flags for read/write
flags_ = oflag & (O_ACCMODE | O_SYNC | O_APPEND);
// set to start of file
curCluster_ = 0;
curPosition_ = 0;
// truncate file to zero length if requested
if (oflag & O_TRUNC) return truncate(0);
return true;
}
//------------------------------------------------------------------------------
/**
* Open a volume's root directory.
*
* \param[in] vol The FAT volume containing the root directory to be opened.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* Reasons for failure include the FAT volume has not been initialized
* or it a FAT12 volume.
*/
uint8_t SdFile::openRoot(SdVolume* vol) {
// error if file is already open
if (isOpen()) return false;
if (vol->fatType() == 16) {
type_ = FAT_FILE_TYPE_ROOT16;
firstCluster_ = 0;
fileSize_ = 32 * vol->rootDirEntryCount();
} else if (vol->fatType() == 32) {
type_ = FAT_FILE_TYPE_ROOT32;
firstCluster_ = vol->rootDirStart();
if (!vol->chainSize(firstCluster_, &fileSize_)) return false;
} else {
// volume is not initialized or FAT12
return false;
}
vol_ = vol;
// read only
flags_ = O_READ;
// set to start of file
curCluster_ = 0;
curPosition_ = 0;
// root has no directory entry
dirBlock_ = 0;
dirIndex_ = 0;
return true;
}
//------------------------------------------------------------------------------
/** %Print the name field of a directory entry in 8.3 format to Serial.
*
* \param[in] dir The directory structure containing the name.
* \param[in] width Blank fill name if length is less than \a width.
*/
void SdFile::printDirName(const dir_t& dir, uint8_t width) {
uint8_t w = 0;
for (uint8_t i = 0; i < 11; i++) {
if (dir.name[i] == ' ')continue;
if (i == 8) {
Serial.print('.');
w++;
}
Serial.print(dir.name[i]);
w++;
}
if (DIR_IS_SUBDIR(&dir)) {
Serial.print('/');
w++;
}
while (w < width) {
Serial.print(' ');
w++;
}
}
//------------------------------------------------------------------------------
/** %Print a directory date field to Serial.
*
* Format is yyyy-mm-dd.
*
* \param[in] fatDate The date field from a directory entry.
*/
void SdFile::printFatDate(uint16_t fatDate) {
Serial.print(FAT_YEAR(fatDate));
Serial.print('-');
printTwoDigits(FAT_MONTH(fatDate));
Serial.print('-');
printTwoDigits(FAT_DAY(fatDate));
}
//------------------------------------------------------------------------------
/** %Print a directory time field to Serial.
*
* Format is hh:mm:ss.
*
* \param[in] fatTime The time field from a directory entry.
*/
void SdFile::printFatTime(uint16_t fatTime) {
printTwoDigits(FAT_HOUR(fatTime));
Serial.print(':');
printTwoDigits(FAT_MINUTE(fatTime));
Serial.print(':');
printTwoDigits(FAT_SECOND(fatTime));
}
//------------------------------------------------------------------------------
/** %Print a value as two digits to Serial.
*
* \param[in] v Value to be printed, 0 <= \a v <= 99
*/
void SdFile::printTwoDigits(uint8_t v) {
char str[3];
str[0] = '0' + v/10;
str[1] = '0' + v % 10;
str[2] = 0;
Serial.print(str);
}
//------------------------------------------------------------------------------
/**
* Read data from a file starting at the current position.
*
* \param[out] buf Pointer to the location that will receive the data.
*
* \param[in] nbyte Maximum number of bytes to read.
*
* \return For success read() returns the number of bytes read.
* A value less than \a nbyte, including zero, will be returned
* if end of file is reached.
* If an error occurs, read() returns -1. Possible errors include
* read() called before a file has been opened, corrupt file system
* or an I/O error occurred.
*/
int16_t SdFile::read(void* buf, uint16_t nbyte) {
uint8_t* dst = reinterpret_cast<uint8_t*>(buf);
// error if not open or write only
if (!isOpen() || !(flags_ & O_READ)) return -1;
// max bytes left in file
if (nbyte > (fileSize_ - curPosition_)) nbyte = fileSize_ - curPosition_;
// amount left to read
uint16_t toRead = nbyte;
while (toRead > 0) {
uint32_t block; // raw device block number
uint16_t offset = curPosition_ & 0X1FF; // offset in block
if (type_ == FAT_FILE_TYPE_ROOT16) {
block = vol_->rootDirStart() + (curPosition_ >> 9);
} else {
uint8_t blockOfCluster = vol_->blockOfCluster(curPosition_);
if (offset == 0 && blockOfCluster == 0) {
// start of new cluster
if (curPosition_ == 0) {
// use first cluster in file
curCluster_ = firstCluster_;
} else {
// get next cluster from FAT
if (!vol_->fatGet(curCluster_, &curCluster_)) return -1;
}
}
block = vol_->clusterStartBlock(curCluster_) + blockOfCluster;
}
uint16_t n = toRead;
// amount to be read from current block
if (n > (512 - offset)) n = 512 - offset;
// no buffering needed if n == 512 or user requests no buffering
if ((unbufferedRead() || n == 512) &&
block != SdVolume::cacheBlockNumber_) {
if (!vol_->readData(block, offset, n, dst)) return -1;
dst += n;
} else {
// read block to cache and copy data to caller
if (!SdVolume::cacheRawBlock(block, SdVolume::CACHE_FOR_READ)) return -1;
uint8_t* src = SdVolume::cacheBuffer_.data + offset;
uint8_t* end = src + n;
while (src != end) *dst++ = *src++;
}
curPosition_ += n;
toRead -= n;
}
return nbyte;
}
//------------------------------------------------------------------------------
/**
* Read the next directory entry from a directory file.
*
* \param[out] dir The dir_t struct that will receive the data.
*
* \return For success readDir() returns the number of bytes read.
* A value of zero will be returned if end of file is reached.
* If an error occurs, readDir() returns -1. Possible errors include
* readDir() called before a directory has been opened, this is not
* a directory file or an I/O error occurred.
*/
int8_t SdFile::readDir(dir_t* dir) {
int8_t n;
// if not a directory file or miss-positioned return an error
if (!isDir() || (0X1F & curPosition_)) return -1;
while ((n = read(dir, sizeof(dir_t))) == sizeof(dir_t)) {
// last entry if DIR_NAME_FREE
if (dir->name[0] == DIR_NAME_FREE) break;
// skip empty entries and entry for . and ..
if (dir->name[0] == DIR_NAME_DELETED || dir->name[0] == '.') continue;
// return if normal file or subdirectory
if (DIR_IS_FILE_OR_SUBDIR(dir)) return n;
}
// error, end of file, or past last entry
return n < 0 ? -1 : 0;
}
//------------------------------------------------------------------------------
// Read next directory entry into the cache
// Assumes file is correctly positioned
dir_t* SdFile::readDirCache(void) {
// error if not directory
if (!isDir()) return NULL;
// index of entry in cache
uint8_t i = (curPosition_ >> 5) & 0XF;
// use read to locate and cache block
if (read() < 0) return NULL;
// advance to next entry
curPosition_ += 31;
// return pointer to entry
return (SdVolume::cacheBuffer_.dir + i);
}
//------------------------------------------------------------------------------
/**
* Remove a file.
*
* The directory entry and all data for the file are deleted.
*
* \note This function should not be used to delete the 8.3 version of a
* file that has a long name. For example if a file has the long name
* "New Text Document.txt" you should not delete the 8.3 name "NEWTEX~1.TXT".
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* Reasons for failure include the file read-only, is a directory,
* or an I/O error occurred.
*/
uint8_t SdFile::remove(void) {
// free any clusters - will fail if read-only or directory
if (!truncate(0)) return false;
// cache directory entry
dir_t* d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE);
if (!d) return false;
// mark entry deleted
d->name[0] = DIR_NAME_DELETED;
// set this SdFile closed
type_ = FAT_FILE_TYPE_CLOSED;
// write entry to SD
return SdVolume::cacheFlush();
}
//------------------------------------------------------------------------------
/**
* Remove a file.
*
* The directory entry and all data for the file are deleted.
*
* \param[in] dirFile The directory that contains the file.
* \param[in] fileName The name of the file to be removed.
*
* \note This function should not be used to delete the 8.3 version of a
* file that has a long name. For example if a file has the long name
* "New Text Document.txt" you should not delete the 8.3 name "NEWTEX~1.TXT".
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* Reasons for failure include the file is a directory, is read only,
* \a dirFile is not a directory, \a fileName is not found
* or an I/O error occurred.
*/
uint8_t SdFile::remove(SdFile* dirFile, const char* fileName) {
SdFile file;
if (!file.open(dirFile, fileName, O_WRITE)) return false;
return file.remove();
}
//------------------------------------------------------------------------------
/** Remove a directory file.
*
* The directory file will be removed only if it is empty and is not the
* root directory. rmDir() follows DOS and Windows and ignores the
* read-only attribute for the directory.
*
* \note This function should not be used to delete the 8.3 version of a
* directory that has a long name. For example if a directory has the
* long name "New folder" you should not delete the 8.3 name "NEWFOL~1".
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* Reasons for failure include the file is not a directory, is the root
* directory, is not empty, or an I/O error occurred.
*/
uint8_t SdFile::rmDir(void) {
// must be open subdirectory
if (!isSubDir()) return false;
rewind();
// make sure directory is empty
while (curPosition_ < fileSize_) {
dir_t* p = readDirCache();
if (p == NULL) return false;
// done if past last used entry
if (p->name[0] == DIR_NAME_FREE) break;
// skip empty slot or '.' or '..'
if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') continue;
// error not empty
if (DIR_IS_FILE_OR_SUBDIR(p)) return false;
}
// convert empty directory to normal file for remove
type_ = FAT_FILE_TYPE_NORMAL;
flags_ |= O_WRITE;
return remove();
}
//------------------------------------------------------------------------------
/** Recursively delete a directory and all contained files.
*
* This is like the Unix/Linux 'rm -rf *' if called with the root directory
* hence the name.
*
* Warning - This will remove all contents of the directory including
* subdirectories. The directory will then be removed if it is not root.
* The read-only attribute for files will be ignored.
*
* \note This function should not be used to delete the 8.3 version of
* a directory that has a long name. See remove() and rmDir().
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
*/
uint8_t SdFile::rmRfStar(void) {
rewind();
while (curPosition_ < fileSize_) {
SdFile f;
// remember position
uint16_t index = curPosition_/32;
dir_t* p = readDirCache();
if (!p) return false;
// done if past last entry
if (p->name[0] == DIR_NAME_FREE) break;
// skip empty slot or '.' or '..'
if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') continue;
// skip if part of long file name or volume label in root
if (!DIR_IS_FILE_OR_SUBDIR(p)) continue;
if (!f.open(this, index, O_READ)) return false;
if (f.isSubDir()) {
// recursively delete
if (!f.rmRfStar()) return false;
} else {
// ignore read-only
f.flags_ |= O_WRITE;
if (!f.remove()) return false;
}
// position to next entry if required
if (curPosition_ != (32*(index + 1))) {
if (!seekSet(32*(index + 1))) return false;
}
}
// don't try to delete root
if (isRoot()) return true;
return rmDir();
}
//------------------------------------------------------------------------------
/**
* Sets a file's position.
*
* \param[in] pos The new position in bytes from the beginning of the file.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
*/
uint8_t SdFile::seekSet(uint32_t pos) {
// error if file not open or seek past end of file
if (!isOpen() || pos > fileSize_) return false;
if (type_ == FAT_FILE_TYPE_ROOT16) {
curPosition_ = pos;
return true;
}
if (pos == 0) {
// set position to start of file
curCluster_ = 0;
curPosition_ = 0;
return true;
}
// calculate cluster index for cur and new position
uint32_t nCur = (curPosition_ - 1) >> (vol_->clusterSizeShift_ + 9);
uint32_t nNew = (pos - 1) >> (vol_->clusterSizeShift_ + 9);
if (nNew < nCur || curPosition_ == 0) {
// must follow chain from first cluster
curCluster_ = firstCluster_;
} else {
// advance from curPosition
nNew -= nCur;
}
while (nNew--) {
if (!vol_->fatGet(curCluster_, &curCluster_)) return false;
}
curPosition_ = pos;
return true;
}
//------------------------------------------------------------------------------
/**
* The sync() call causes all modified data and directory fields
* to be written to the storage device.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* Reasons for failure include a call to sync() before a file has been
* opened or an I/O error.
*/
uint8_t SdFile::sync(void) {
// only allow open files and directories
if (!isOpen()) return false;
if (flags_ & F_FILE_DIR_DIRTY) {
dir_t* d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE);
if (!d) return false;
// do not set filesize for dir files
if (!isDir()) d->fileSize = fileSize_;
// update first cluster fields
d->firstClusterLow = firstCluster_ & 0XFFFF;
d->firstClusterHigh = firstCluster_ >> 16;
// set modify time if user supplied a callback date/time function
if (dateTime_) {
dateTime_(&d->lastWriteDate, &d->lastWriteTime);
d->lastAccessDate = d->lastWriteDate;
}
// clear directory dirty
flags_ &= ~F_FILE_DIR_DIRTY;
}
return SdVolume::cacheFlush();
}
//------------------------------------------------------------------------------
/**
* Set a file's timestamps in its directory entry.
*
* \param[in] flags Values for \a flags are constructed by a bitwise-inclusive
* OR of flags from the following list
*
* T_ACCESS - Set the file's last access date.
*
* T_CREATE - Set the file's creation date and time.
*
* T_WRITE - Set the file's last write/modification date and time.
*
* \param[in] year Valid range 1980 - 2107 inclusive.
*
* \param[in] month Valid range 1 - 12 inclusive.
*
* \param[in] day Valid range 1 - 31 inclusive.
*
* \param[in] hour Valid range 0 - 23 inclusive.
*
* \param[in] minute Valid range 0 - 59 inclusive.
*
* \param[in] second Valid range 0 - 59 inclusive
*
* \note It is possible to set an invalid date since there is no check for
* the number of days in a month.
*
* \note
* Modify and access timestamps may be overwritten if a date time callback
* function has been set by dateTimeCallback().
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
*/
uint8_t SdFile::timestamp(uint8_t flags, uint16_t year, uint8_t month,
uint8_t day, uint8_t hour, uint8_t minute, uint8_t second) {
if (!isOpen()
|| year < 1980
|| year > 2107
|| month < 1
|| month > 12
|| day < 1
|| day > 31
|| hour > 23
|| minute > 59
|| second > 59) {
return false;
}
dir_t* d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE);
if (!d) return false;
uint16_t dirDate = FAT_DATE(year, month, day);
uint16_t dirTime = FAT_TIME(hour, minute, second);
if (flags & T_ACCESS) {
d->lastAccessDate = dirDate;
}
if (flags & T_CREATE) {
d->creationDate = dirDate;
d->creationTime = dirTime;
// seems to be units of 1/100 second not 1/10 as Microsoft states
d->creationTimeTenths = second & 1 ? 100 : 0;
}
if (flags & T_WRITE) {
d->lastWriteDate = dirDate;
d->lastWriteTime = dirTime;
}
SdVolume::cacheSetDirty();
return sync();
}
//------------------------------------------------------------------------------
/**
* Truncate a file to a specified length. The current file position
* will be maintained if it is less than or equal to \a length otherwise
* it will be set to end of file.
*
* \param[in] length The desired length for the file.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* Reasons for failure include file is read only, file is a directory,
* \a length is greater than the current file size or an I/O error occurs.
*/
uint8_t SdFile::truncate(uint32_t length) {
// error if not a normal file or read-only
if (!isFile() || !(flags_ & O_WRITE)) return false;
// error if length is greater than current size
if (length > fileSize_) return false;
// fileSize and length are zero - nothing to do
if (fileSize_ == 0) return true;
// remember position for seek after truncation
uint32_t newPos = curPosition_ > length ? length : curPosition_;
// position to last cluster in truncated file
if (!seekSet(length)) return false;
if (length == 0) {
// free all clusters
if (!vol_->freeChain(firstCluster_)) return false;
firstCluster_ = 0;
} else {
uint32_t toFree;
if (!vol_->fatGet(curCluster_, &toFree)) return false;
if (!vol_->isEOC(toFree)) {
// free extra clusters
if (!vol_->freeChain(toFree)) return false;
// current cluster is end of chain
if (!vol_->fatPutEOC(curCluster_)) return false;
}
}
fileSize_ = length;
// need to update directory entry
flags_ |= F_FILE_DIR_DIRTY;
if (!sync()) return false;
// set file to correct position
return seekSet(newPos);
}
//------------------------------------------------------------------------------
/**
* Write data to an open file.
*
* \note Data is moved to the cache but may not be written to the
* storage device until sync() is called.
*
* \param[in] buf Pointer to the location of the data to be written.
*
* \param[in] nbyte Number of bytes to write.
*
* \return For success write() returns the number of bytes written, always
* \a nbyte. If an error occurs, write() returns -1. Possible errors
* include write() is called before a file has been opened, write is called
* for a read-only file, device is full, a corrupt file system or an I/O error.
*
*/
int16_t SdFile::write(const void* buf, uint16_t nbyte) {
// convert void* to uint8_t* - must be before goto statements
const uint8_t* src = reinterpret_cast<const uint8_t*>(buf);
// number of bytes left to write - must be before goto statements
uint16_t nToWrite = nbyte;
// error if not a normal file or is read-only
if (!isFile() || !(flags_ & O_WRITE)) goto writeErrorReturn;
// seek to end of file if append flag
if ((flags_ & O_APPEND) && curPosition_ != fileSize_) {
if (!seekEnd()) goto writeErrorReturn;
}
while (nToWrite > 0) {
uint8_t blockOfCluster = vol_->blockOfCluster(curPosition_);
uint16_t blockOffset = curPosition_ & 0X1FF;
if (blockOfCluster == 0 && blockOffset == 0) {
// start of new cluster
if (curCluster_ == 0) {
if (firstCluster_ == 0) {
// allocate first cluster of file
if (!addCluster()) goto writeErrorReturn;
} else {
curCluster_ = firstCluster_;
}
} else {
uint32_t next;
if (!vol_->fatGet(curCluster_, &next)) return false;
if (vol_->isEOC(next)) {
// add cluster if at end of chain
if (!addCluster()) goto writeErrorReturn;
} else {
curCluster_ = next;
}
}
}
// max space in block
uint16_t n = 512 - blockOffset;
// lesser of space and amount to write
if (n > nToWrite) n = nToWrite;
// block for data write
uint32_t block = vol_->clusterStartBlock(curCluster_) + blockOfCluster;
if (n == 512) {
// full block - don't need to use cache
// invalidate cache if block is in cache
if (SdVolume::cacheBlockNumber_ == block) {
SdVolume::cacheBlockNumber_ = 0XFFFFFFFF;
}
if (!vol_->writeBlock(block, src)) goto writeErrorReturn;
src += 512;
} else {
if (blockOffset == 0 && curPosition_ >= fileSize_) {
// start of new block don't need to read into cache
if (!SdVolume::cacheFlush()) goto writeErrorReturn;
SdVolume::cacheBlockNumber_ = block;
SdVolume::cacheSetDirty();
} else {
// rewrite part of block
if (!SdVolume::cacheRawBlock(block, SdVolume::CACHE_FOR_WRITE)) {
goto writeErrorReturn;
}
}
uint8_t* dst = SdVolume::cacheBuffer_.data + blockOffset;
uint8_t* end = dst + n;
while (dst != end) *dst++ = *src++;
}
nToWrite -= n;
curPosition_ += n;
}
if (curPosition_ > fileSize_) {
// update fileSize and insure sync will update dir entry
fileSize_ = curPosition_;
flags_ |= F_FILE_DIR_DIRTY;
} else if (dateTime_ && nbyte) {
// insure sync will update modified date and time
flags_ |= F_FILE_DIR_DIRTY;
}
if (flags_ & O_SYNC) {
if (!sync()) goto writeErrorReturn;
}
return nbyte;
writeErrorReturn:
// return for write error
writeError = true;
return -1;
}
//------------------------------------------------------------------------------
/**
* Write a byte to a file. Required by the Arduino Print class.
*
* Use SdFile::writeError to check for errors.
*/
void SdFile::write(uint8_t b) {
write(&b, 1);
}
//------------------------------------------------------------------------------
/**
* Write a string to a file. Used by the Arduino Print class.
*
* Use SdFile::writeError to check for errors.
*/
void SdFile::write(const char* str) {
write(str, strlen(str));
}
//------------------------------------------------------------------------------
/**
* Write a PROGMEM string to a file.
*
* Use SdFile::writeError to check for errors.
*/
void SdFile::write_P(PGM_P str) {
for (uint8_t c; (c = pgm_read_byte(str)); str++) write(c);
}
//------------------------------------------------------------------------------
/**
* Write a PROGMEM string followed by CR/LF to a file.
*
* Use SdFile::writeError to check for errors.
*/
void SdFile::writeln_P(PGM_P str) {
write_P(str);
println();
}

View File

@ -0,0 +1,232 @@
/* Arduino Sd2Card Library
* Copyright (C) 2009 by William Greiman
*
* This file is part of the Arduino Sd2Card Library
*
* This Library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This Library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the Arduino Sd2Card Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#ifndef SdInfo_h
#define SdInfo_h
#include <stdint.h>
// Based on the document:
//
// SD Specifications
// Part 1
// Physical Layer
// Simplified Specification
// Version 2.00
// September 25, 2006
//
// www.sdcard.org/developers/tech/sdcard/pls/Simplified_Physical_Layer_Spec.pdf
//------------------------------------------------------------------------------
// SD card commands
/** GO_IDLE_STATE - init card in spi mode if CS low */
uint8_t const CMD0 = 0X00;
/** SEND_IF_COND - verify SD Memory Card interface operating condition.*/
uint8_t const CMD8 = 0X08;
/** SEND_CSD - read the Card Specific Data (CSD register) */
uint8_t const CMD9 = 0X09;
/** SEND_CID - read the card identification information (CID register) */
uint8_t const CMD10 = 0X0A;
/** SEND_STATUS - read the card status register */
uint8_t const CMD13 = 0X0D;
/** READ_BLOCK - read a single data block from the card */
uint8_t const CMD17 = 0X11;
/** WRITE_BLOCK - write a single data block to the card */
uint8_t const CMD24 = 0X18;
/** WRITE_MULTIPLE_BLOCK - write blocks of data until a STOP_TRANSMISSION */
uint8_t const CMD25 = 0X19;
/** ERASE_WR_BLK_START - sets the address of the first block to be erased */
uint8_t const CMD32 = 0X20;
/** ERASE_WR_BLK_END - sets the address of the last block of the continuous
range to be erased*/
uint8_t const CMD33 = 0X21;
/** ERASE - erase all previously selected blocks */
uint8_t const CMD38 = 0X26;
/** APP_CMD - escape for application specific command */
uint8_t const CMD55 = 0X37;
/** READ_OCR - read the OCR register of a card */
uint8_t const CMD58 = 0X3A;
/** SET_WR_BLK_ERASE_COUNT - Set the number of write blocks to be
pre-erased before writing */
uint8_t const ACMD23 = 0X17;
/** SD_SEND_OP_COMD - Sends host capacity support information and
activates the card's initialization process */
uint8_t const ACMD41 = 0X29;
//------------------------------------------------------------------------------
/** status for card in the ready state */
uint8_t const R1_READY_STATE = 0X00;
/** status for card in the idle state */
uint8_t const R1_IDLE_STATE = 0X01;
/** status bit for illegal command */
uint8_t const R1_ILLEGAL_COMMAND = 0X04;
/** start data token for read or write single block*/
uint8_t const DATA_START_BLOCK = 0XFE;
/** stop token for write multiple blocks*/
uint8_t const STOP_TRAN_TOKEN = 0XFD;
/** start data token for write multiple blocks*/
uint8_t const WRITE_MULTIPLE_TOKEN = 0XFC;
/** mask for data response tokens after a write block operation */
uint8_t const DATA_RES_MASK = 0X1F;
/** write data accepted token */
uint8_t const DATA_RES_ACCEPTED = 0X05;
//------------------------------------------------------------------------------
typedef struct CID {
// byte 0
uint8_t mid; // Manufacturer ID
// byte 1-2
char oid[2]; // OEM/Application ID
// byte 3-7
char pnm[5]; // Product name
// byte 8
unsigned prv_m : 4; // Product revision n.m
unsigned prv_n : 4;
// byte 9-12
uint32_t psn; // Product serial number
// byte 13
unsigned mdt_year_high : 4; // Manufacturing date
unsigned reserved : 4;
// byte 14
unsigned mdt_month : 4;
unsigned mdt_year_low :4;
// byte 15
unsigned always1 : 1;
unsigned crc : 7;
}cid_t;
//------------------------------------------------------------------------------
// CSD for version 1.00 cards
typedef struct CSDV1 {
// byte 0
unsigned reserved1 : 6;
unsigned csd_ver : 2;
// byte 1
uint8_t taac;
// byte 2
uint8_t nsac;
// byte 3
uint8_t tran_speed;
// byte 4
uint8_t ccc_high;
// byte 5
unsigned read_bl_len : 4;
unsigned ccc_low : 4;
// byte 6
unsigned c_size_high : 2;
unsigned reserved2 : 2;
unsigned dsr_imp : 1;
unsigned read_blk_misalign :1;
unsigned write_blk_misalign : 1;
unsigned read_bl_partial : 1;
// byte 7
uint8_t c_size_mid;
// byte 8
unsigned vdd_r_curr_max : 3;
unsigned vdd_r_curr_min : 3;
unsigned c_size_low :2;
// byte 9
unsigned c_size_mult_high : 2;
unsigned vdd_w_cur_max : 3;
unsigned vdd_w_curr_min : 3;
// byte 10
unsigned sector_size_high : 6;
unsigned erase_blk_en : 1;
unsigned c_size_mult_low : 1;
// byte 11
unsigned wp_grp_size : 7;
unsigned sector_size_low : 1;
// byte 12
unsigned write_bl_len_high : 2;
unsigned r2w_factor : 3;
unsigned reserved3 : 2;
unsigned wp_grp_enable : 1;
// byte 13
unsigned reserved4 : 5;
unsigned write_partial : 1;
unsigned write_bl_len_low : 2;
// byte 14
unsigned reserved5: 2;
unsigned file_format : 2;
unsigned tmp_write_protect : 1;
unsigned perm_write_protect : 1;
unsigned copy : 1;
unsigned file_format_grp : 1;
// byte 15
unsigned always1 : 1;
unsigned crc : 7;
}csd1_t;
//------------------------------------------------------------------------------
// CSD for version 2.00 cards
typedef struct CSDV2 {
// byte 0
unsigned reserved1 : 6;
unsigned csd_ver : 2;
// byte 1
uint8_t taac;
// byte 2
uint8_t nsac;
// byte 3
uint8_t tran_speed;
// byte 4
uint8_t ccc_high;
// byte 5
unsigned read_bl_len : 4;
unsigned ccc_low : 4;
// byte 6
unsigned reserved2 : 4;
unsigned dsr_imp : 1;
unsigned read_blk_misalign :1;
unsigned write_blk_misalign : 1;
unsigned read_bl_partial : 1;
// byte 7
unsigned reserved3 : 2;
unsigned c_size_high : 6;
// byte 8
uint8_t c_size_mid;
// byte 9
uint8_t c_size_low;
// byte 10
unsigned sector_size_high : 6;
unsigned erase_blk_en : 1;
unsigned reserved4 : 1;
// byte 11
unsigned wp_grp_size : 7;
unsigned sector_size_low : 1;
// byte 12
unsigned write_bl_len_high : 2;
unsigned r2w_factor : 3;
unsigned reserved5 : 2;
unsigned wp_grp_enable : 1;
// byte 13
unsigned reserved6 : 5;
unsigned write_partial : 1;
unsigned write_bl_len_low : 2;
// byte 14
unsigned reserved7: 2;
unsigned file_format : 2;
unsigned tmp_write_protect : 1;
unsigned perm_write_protect : 1;
unsigned copy : 1;
unsigned file_format_grp : 1;
// byte 15
unsigned always1 : 1;
unsigned crc : 7;
}csd2_t;
//------------------------------------------------------------------------------
// union of old and new style CSD register
union csd_t {
csd1_t v1;
csd2_t v2;
};
#endif // SdInfo_h

View File

@ -0,0 +1,295 @@
/* Arduino SdFat Library
* Copyright (C) 2009 by William Greiman
*
* This file is part of the Arduino SdFat Library
*
* This Library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This Library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the Arduino SdFat Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include <SdFat.h>
//------------------------------------------------------------------------------
// raw block cache
// init cacheBlockNumber_to invalid SD block number
uint32_t SdVolume::cacheBlockNumber_ = 0XFFFFFFFF;
cache_t SdVolume::cacheBuffer_; // 512 byte cache for Sd2Card
Sd2Card* SdVolume::sdCard_; // pointer to SD card object
uint8_t SdVolume::cacheDirty_ = 0; // cacheFlush() will write block if true
uint32_t SdVolume::cacheMirrorBlock_ = 0; // mirror block for second FAT
//------------------------------------------------------------------------------
// find a contiguous group of clusters
uint8_t SdVolume::allocContiguous(uint32_t count, uint32_t* curCluster) {
// start of group
uint32_t bgnCluster;
// flag to save place to start next search
uint8_t setStart;
// set search start cluster
if (*curCluster) {
// try to make file contiguous
bgnCluster = *curCluster + 1;
// don't save new start location
setStart = false;
} else {
// start at likely place for free cluster
bgnCluster = allocSearchStart_;
// save next search start if one cluster
setStart = 1 == count;
}
// end of group
uint32_t endCluster = bgnCluster;
// last cluster of FAT
uint32_t fatEnd = clusterCount_ + 1;
// search the FAT for free clusters
for (uint32_t n = 0;; n++, endCluster++) {
// can't find space checked all clusters
if (n >= clusterCount_) return false;
// past end - start from beginning of FAT
if (endCluster > fatEnd) {
bgnCluster = endCluster = 2;
}
uint32_t f;
if (!fatGet(endCluster, &f)) return false;
if (f != 0) {
// cluster in use try next cluster as bgnCluster
bgnCluster = endCluster + 1;
} else if ((endCluster - bgnCluster + 1) == count) {
// done - found space
break;
}
}
// mark end of chain
if (!fatPutEOC(endCluster)) return false;
// link clusters
while (endCluster > bgnCluster) {
if (!fatPut(endCluster - 1, endCluster)) return false;
endCluster--;
}
if (*curCluster != 0) {
// connect chains
if (!fatPut(*curCluster, bgnCluster)) return false;
}
// return first cluster number to caller
*curCluster = bgnCluster;
// remember possible next free cluster
if (setStart) allocSearchStart_ = bgnCluster + 1;
return true;
}
//------------------------------------------------------------------------------
uint8_t SdVolume::cacheFlush(void) {
if (cacheDirty_) {
if (!sdCard_->writeBlock(cacheBlockNumber_, cacheBuffer_.data)) {
return false;
}
// mirror FAT tables
if (cacheMirrorBlock_) {
if (!sdCard_->writeBlock(cacheMirrorBlock_, cacheBuffer_.data)) {
return false;
}
cacheMirrorBlock_ = 0;
}
cacheDirty_ = 0;
}
return true;
}
//------------------------------------------------------------------------------
uint8_t SdVolume::cacheRawBlock(uint32_t blockNumber, uint8_t action) {
if (cacheBlockNumber_ != blockNumber) {
if (!cacheFlush()) return false;
if (!sdCard_->readBlock(blockNumber, cacheBuffer_.data)) return false;
cacheBlockNumber_ = blockNumber;
}
cacheDirty_ |= action;
return true;
}
//------------------------------------------------------------------------------
// cache a zero block for blockNumber
uint8_t SdVolume::cacheZeroBlock(uint32_t blockNumber) {
if (!cacheFlush()) return false;
// loop take less flash than memset(cacheBuffer_.data, 0, 512);
for (uint16_t i = 0; i < 512; i++) {
cacheBuffer_.data[i] = 0;
}
cacheBlockNumber_ = blockNumber;
cacheSetDirty();
return true;
}
//------------------------------------------------------------------------------
// return the size in bytes of a cluster chain
uint8_t SdVolume::chainSize(uint32_t cluster, uint32_t* size) const {
uint32_t s = 0;
do {
if (!fatGet(cluster, &cluster)) return false;
s += 512UL << clusterSizeShift_;
} while (!isEOC(cluster));
*size = s;
return true;
}
//------------------------------------------------------------------------------
// Fetch a FAT entry
uint8_t SdVolume::fatGet(uint32_t cluster, uint32_t* value) const {
if (cluster > (clusterCount_ + 1)) return false;
uint32_t lba = fatStartBlock_;
lba += fatType_ == 16 ? cluster >> 8 : cluster >> 7;
if (lba != cacheBlockNumber_) {
if (!cacheRawBlock(lba, CACHE_FOR_READ)) return false;
}
if (fatType_ == 16) {
*value = cacheBuffer_.fat16[cluster & 0XFF];
} else {
*value = cacheBuffer_.fat32[cluster & 0X7F] & FAT32MASK;
}
return true;
}
//------------------------------------------------------------------------------
// Store a FAT entry
uint8_t SdVolume::fatPut(uint32_t cluster, uint32_t value) {
// error if reserved cluster
if (cluster < 2) return false;
// error if not in FAT
if (cluster > (clusterCount_ + 1)) return false;
// calculate block address for entry
uint32_t lba = fatStartBlock_;
lba += fatType_ == 16 ? cluster >> 8 : cluster >> 7;
if (lba != cacheBlockNumber_) {
if (!cacheRawBlock(lba, CACHE_FOR_READ)) return false;
}
// store entry
if (fatType_ == 16) {
cacheBuffer_.fat16[cluster & 0XFF] = value;
} else {
cacheBuffer_.fat32[cluster & 0X7F] = value;
}
cacheSetDirty();
// mirror second FAT
if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_;
return true;
}
//------------------------------------------------------------------------------
// free a cluster chain
uint8_t SdVolume::freeChain(uint32_t cluster) {
// clear free cluster location
allocSearchStart_ = 2;
do {
uint32_t next;
if (!fatGet(cluster, &next)) return false;
// free cluster
if (!fatPut(cluster, 0)) return false;
cluster = next;
} while (!isEOC(cluster));
return true;
}
//------------------------------------------------------------------------------
/**
* Initialize a FAT volume.
*
* \param[in] dev The SD card where the volume is located.
*
* \param[in] part The partition to be used. Legal values for \a part are
* 1-4 to use the corresponding partition on a device formatted with
* a MBR, Master Boot Record, or zero if the device is formatted as
* a super floppy with the FAT boot sector in block zero.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure. Reasons for
* failure include not finding a valid partition, not finding a valid
* FAT file system in the specified partition or an I/O error.
*/
uint8_t SdVolume::init(Sd2Card* dev, uint8_t part) {
uint32_t volumeStartBlock = 0;
sdCard_ = dev;
// if part == 0 assume super floppy with FAT boot sector in block zero
// if part > 0 assume mbr volume with partition table
if (part) {
if (part > 4)return false;
if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) return false;
part_t* p = &cacheBuffer_.mbr.part[part-1];
if ((p->boot & 0X7F) !=0 ||
p->totalSectors < 100 ||
p->firstSector == 0) {
// not a valid partition
return false;
}
volumeStartBlock = p->firstSector;
}
if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) return false;
bpb_t* bpb = &cacheBuffer_.fbs.bpb;
if (bpb->bytesPerSector != 512 ||
bpb->fatCount == 0 ||
bpb->reservedSectorCount == 0 ||
bpb->sectorsPerCluster == 0) {
// not valid FAT volume
return false;
}
fatCount_ = bpb->fatCount;
blocksPerCluster_ = bpb->sectorsPerCluster;
// determine shift that is same as multiply by blocksPerCluster_
clusterSizeShift_ = 0;
while (blocksPerCluster_ != (1 << clusterSizeShift_)) {
// error if not power of 2
if (clusterSizeShift_++ > 7) return false;
}
blocksPerFat_ = bpb->sectorsPerFat16 ?
bpb->sectorsPerFat16 : bpb->sectorsPerFat32;
fatStartBlock_ = volumeStartBlock + bpb->reservedSectorCount;
// count for FAT16 zero for FAT32
rootDirEntryCount_ = bpb->rootDirEntryCount;
// directory start for FAT16 dataStart for FAT32
rootDirStart_ = fatStartBlock_ + bpb->fatCount * blocksPerFat_;
// data start for FAT16 and FAT32
dataStartBlock_ = rootDirStart_ + ((32 * bpb->rootDirEntryCount + 511)/512);
// total blocks for FAT16 or FAT32
uint32_t totalBlocks = bpb->totalSectors16 ?
bpb->totalSectors16 : bpb->totalSectors32;
// total data blocks
clusterCount_ = totalBlocks - (dataStartBlock_ - volumeStartBlock);
// divide by cluster size to get cluster count
clusterCount_ >>= clusterSizeShift_;
// FAT type is determined by cluster count
if (clusterCount_ < 4085) {
fatType_ = 12;
} else if (clusterCount_ < 65525) {
fatType_ = 16;
} else {
rootDirStart_ = bpb->fat32RootCluster;
fatType_ = 32;
}
return true;
}

View File

@ -1,4 +1,4 @@
0021 arduino 0022 arduino
Fix Linux make.sh, etc. scripts Fix Linux make.sh, etc. scripts
Test on Linux. Test on Linux.