mirror of
https://github.com/arduino/Arduino.git
synced 2024-12-01 12:24:14 +01:00
Removing sdfatlib examples.
This commit is contained in:
parent
743d3707d1
commit
28d1b15283
@ -1,122 +0,0 @@
|
||||
// A simple data logger for the Arduino analog pins
|
||||
#define LOG_INTERVAL 1000 // mills between entries
|
||||
#define SENSOR_COUNT 3 // number of analog pins to log
|
||||
#define ECHO_TO_SERIAL 1 // echo data to serial port
|
||||
#define WAIT_TO_START 1 // Wait for serial input in setup()
|
||||
#define SYNC_INTERVAL 1000 // mills between calls to sync()
|
||||
uint32_t syncTime = 0; // time of last sync()
|
||||
|
||||
#include <SdFat.h>
|
||||
#include <SdFatUtil.h>
|
||||
|
||||
Sd2Card card;
|
||||
SdVolume volume;
|
||||
SdFile root;
|
||||
SdFile file;
|
||||
|
||||
// store error strings in flash to save RAM
|
||||
#define error(s) error_P(PSTR(s))
|
||||
|
||||
void error_P(const char* str) {
|
||||
PgmPrint("error: ");
|
||||
SerialPrintln_P(str);
|
||||
if (card.errorCode()) {
|
||||
PgmPrint("SD error: ");
|
||||
Serial.print(card.errorCode(), HEX);
|
||||
Serial.print(',');
|
||||
Serial.println(card.errorData(), HEX);
|
||||
}
|
||||
while(1);
|
||||
}
|
||||
|
||||
void setup(void) {
|
||||
Serial.begin(9600);
|
||||
Serial.println();
|
||||
|
||||
#if WAIT_TO_START
|
||||
Serial.println("Type any character to start");
|
||||
while (!Serial.available());
|
||||
#endif //WAIT_TO_START
|
||||
|
||||
// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
|
||||
// breadboards. use SPI_FULL_SPEED for better performance.
|
||||
if (!card.init(SPI_HALF_SPEED)) error("card.init failed");
|
||||
|
||||
// initialize a FAT volume
|
||||
if (!volume.init(&card)) error("volume.init failed");
|
||||
|
||||
// open root directory
|
||||
if (!root.openRoot(&volume)) error("openRoot failed");
|
||||
|
||||
// create a new file
|
||||
char name[] = "LOGGER00.CSV";
|
||||
for (uint8_t i = 0; i < 100; i++) {
|
||||
name[6] = i/10 + '0';
|
||||
name[7] = i%10 + '0';
|
||||
if (file.open(&root, name, O_CREAT | O_EXCL | O_WRITE)) break;
|
||||
}
|
||||
if (!file.isOpen()) error ("file.create");
|
||||
Serial.print("Logging to: ");
|
||||
Serial.println(name);
|
||||
|
||||
// write header
|
||||
file.writeError = 0;
|
||||
file.print("millis");
|
||||
#if ECHO_TO_SERIAL
|
||||
Serial.print("millis");
|
||||
#endif //ECHO_TO_SERIAL
|
||||
|
||||
#if SENSOR_COUNT > 6
|
||||
#error SENSOR_COUNT too large
|
||||
#endif //SENSOR_COUNT
|
||||
|
||||
for (uint8_t i = 0; i < SENSOR_COUNT; i++) {
|
||||
file.print(",sens");file.print(i, DEC);
|
||||
#if ECHO_TO_SERIAL
|
||||
Serial.print(",sens");Serial.print(i, DEC);
|
||||
#endif //ECHO_TO_SERIAL
|
||||
}
|
||||
file.println();
|
||||
#if ECHO_TO_SERIAL
|
||||
Serial.println();
|
||||
#endif //ECHO_TO_SERIAL
|
||||
|
||||
if (file.writeError || !file.sync()) {
|
||||
error("write header failed");
|
||||
}
|
||||
}
|
||||
|
||||
void loop(void) {
|
||||
// clear print error
|
||||
file.writeError = 0;
|
||||
delay((LOG_INTERVAL -1) - (millis() % LOG_INTERVAL));
|
||||
|
||||
// log time
|
||||
uint32_t m = millis();
|
||||
file.print(m);
|
||||
#if ECHO_TO_SERIAL
|
||||
Serial.print(m);
|
||||
#endif //ECHO_TO_SERIAL
|
||||
|
||||
// add sensor data
|
||||
for (uint8_t ia = 0; ia < SENSOR_COUNT; ia++) {
|
||||
uint16_t data = analogRead(ia);
|
||||
file.print(',');
|
||||
file.print(data);
|
||||
#if ECHO_TO_SERIAL
|
||||
Serial.print(',');
|
||||
Serial.print(data);
|
||||
#endif //ECHO_TO_SERIAL
|
||||
}
|
||||
file.println();
|
||||
#if ECHO_TO_SERIAL
|
||||
Serial.println();
|
||||
#endif //ECHO_TO_SERIAL
|
||||
|
||||
if (file.writeError) error("write data failed");
|
||||
|
||||
//don't sync too often - requires 2048 bytes of I/O to SD card
|
||||
if ((millis() - syncTime) < SYNC_INTERVAL) return;
|
||||
syncTime = millis();
|
||||
if (!file.sync()) error("sync failed");
|
||||
}
|
@ -1,77 +0,0 @@
|
||||
/*
|
||||
* Append Example
|
||||
*
|
||||
* This sketch shows how to use open for append and the Arduino Print class
|
||||
* with SdFat.
|
||||
*/
|
||||
#include <SdFat.h>
|
||||
#include <SdFatUtil.h> // use functions to print strings from flash memory
|
||||
|
||||
Sd2Card card;
|
||||
SdVolume volume;
|
||||
SdFile root;
|
||||
SdFile file;
|
||||
|
||||
// store error strings in flash to save RAM
|
||||
#define error(s) error_P(PSTR(s))
|
||||
|
||||
void error_P(const char* str) {
|
||||
PgmPrint("error: ");
|
||||
SerialPrintln_P(str);
|
||||
if (card.errorCode()) {
|
||||
PgmPrint("SD error: ");
|
||||
Serial.print(card.errorCode(), HEX);
|
||||
Serial.print(',');
|
||||
Serial.println(card.errorData(), HEX);
|
||||
}
|
||||
while(1);
|
||||
}
|
||||
|
||||
void setup(void) {
|
||||
Serial.begin(9600);
|
||||
Serial.println();
|
||||
PgmPrintln("Type any character to start");
|
||||
while (!Serial.available());
|
||||
|
||||
// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
|
||||
// breadboards. use SPI_FULL_SPEED for better performance.
|
||||
if (!card.init(SPI_HALF_SPEED)) error("card.init failed");
|
||||
|
||||
// initialize a FAT volume
|
||||
if (!volume.init(&card)) error("volume.init failed");
|
||||
|
||||
// open the root directory
|
||||
if (!root.openRoot(&volume)) error("openRoot failed");
|
||||
|
||||
char name[] = "APPEND.TXT";
|
||||
PgmPrint("Appending to: ");
|
||||
Serial.println(name);
|
||||
|
||||
// clear write error
|
||||
file.writeError = false;
|
||||
|
||||
for (uint8_t i = 0; i < 100; i++) {
|
||||
// O_CREAT - create the file if it does not exist
|
||||
// O_APPEND - seek to the end of the file prior to each write
|
||||
// O_WRITE - open for write
|
||||
if (!file.open(&root, name, O_CREAT | O_APPEND | O_WRITE)) {
|
||||
error("open failed");
|
||||
}
|
||||
// print 100 lines to file
|
||||
for (uint8_t j = 0; j < 100; j++) {
|
||||
file.print("line ");
|
||||
file.print(j, DEC);
|
||||
file.print(" of pass ");
|
||||
file.print(i, DEC);
|
||||
file.print(" millis = ");
|
||||
file.println(millis());
|
||||
}
|
||||
if (file.writeError) error("write failed");
|
||||
if (!file.close()) error("close failed");
|
||||
if (i > 0 && i%25 == 0)Serial.println();
|
||||
Serial.print('.');
|
||||
}
|
||||
Serial.println();
|
||||
Serial.println("Done");
|
||||
}
|
||||
void loop(void){}
|
@ -1,104 +0,0 @@
|
||||
/*
|
||||
* This sketch is a simple write/read benchmark.
|
||||
*/
|
||||
#include <SdFat.h>
|
||||
#include <SdFatUtil.h>
|
||||
|
||||
#define FILE_SIZE_MB 5
|
||||
#define FILE_SIZE (1000000UL*FILE_SIZE_MB)
|
||||
#define BUF_SIZE 100
|
||||
|
||||
uint8_t buf[BUF_SIZE];
|
||||
|
||||
Sd2Card card;
|
||||
SdVolume volume;
|
||||
SdFile root;
|
||||
SdFile file;
|
||||
|
||||
// store error strings in flash to save RAM
|
||||
#define error(s) error_P(PSTR(s))
|
||||
|
||||
void error_P(const char* str)
|
||||
{
|
||||
PgmPrint("error: ");
|
||||
SerialPrintln_P(str);
|
||||
if (card.errorCode()) {
|
||||
PgmPrint("SD error: ");
|
||||
Serial.print(card.errorCode(), HEX);
|
||||
Serial.print(',');
|
||||
Serial.println(card.errorData(), HEX);
|
||||
}
|
||||
while(1);
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
PgmPrintln("Type any character to start");
|
||||
while (!Serial.available());
|
||||
|
||||
PgmPrint("Free RAM: ");
|
||||
Serial.println(FreeRam());
|
||||
|
||||
// initialize the SD card at SPI_FULL_SPEED for best performance.
|
||||
// try SPI_HALF_SPEED if bus errors occur.
|
||||
if (!card.init(SPI_FULL_SPEED)) error("card.init failed");
|
||||
|
||||
// initialize a FAT volume
|
||||
if (!volume.init(&card)) error("volume.init failed!");
|
||||
|
||||
PgmPrint("Type is FAT");
|
||||
Serial.println(volume.fatType(), DEC);
|
||||
|
||||
if (!root.openRoot(&volume)) error("openRoot failed");
|
||||
|
||||
// open or create file - truncate existing file.
|
||||
if (!file.open(&root, "BENCH.DAT", O_CREAT | O_TRUNC | O_RDWR)) {
|
||||
error("open failed");
|
||||
}
|
||||
|
||||
// fill buf with known data
|
||||
for (uint16_t i = 0; i < (BUF_SIZE-2); i++) {
|
||||
buf[i] = 'A' + (i % 26);
|
||||
}
|
||||
buf[BUF_SIZE-2] = '\r';
|
||||
buf[BUF_SIZE-1] = '\n';
|
||||
|
||||
PgmPrint("File size ");
|
||||
Serial.print(FILE_SIZE_MB);
|
||||
PgmPrintln(" MB");
|
||||
PgmPrintln("Starting write test. Please wait up to a minute");
|
||||
|
||||
// do write test
|
||||
uint32_t n = FILE_SIZE/sizeof(buf);
|
||||
uint32_t t = millis();
|
||||
for (uint32_t i = 0; i < n; i++) {
|
||||
if (file.write(buf, sizeof(buf)) != sizeof(buf)) {
|
||||
error("write failed");
|
||||
}
|
||||
}
|
||||
t = millis() - t;
|
||||
file.sync();
|
||||
double r = (double)file.fileSize()/t;
|
||||
PgmPrint("Write ");
|
||||
Serial.print(r);
|
||||
PgmPrintln(" KB/sec");
|
||||
Serial.println();
|
||||
PgmPrintln("Starting read test. Please wait up to a minute");
|
||||
|
||||
// do read test
|
||||
file.rewind();
|
||||
t = millis();
|
||||
for (uint32_t i = 0; i < n; i++) {
|
||||
if (file.read(buf, sizeof(buf)) != sizeof(buf)) {
|
||||
error("read failed");
|
||||
}
|
||||
}
|
||||
t = millis() - t;
|
||||
r = (double)file.fileSize()/t;
|
||||
PgmPrint("Read ");
|
||||
Serial.print(r);
|
||||
PgmPrintln(" KB/sec");
|
||||
PgmPrintln("Done");
|
||||
}
|
||||
|
||||
void loop() { }
|
@ -1,82 +0,0 @@
|
||||
/*
|
||||
* Copy Example - only runs on chips with 2K or more RAM
|
||||
*
|
||||
* This sketch copies the file APPEND.TXT, created by the
|
||||
* SdFatAppend.pde example, to the file ACOPY.TXT.
|
||||
*/
|
||||
#include <SdFat.h>
|
||||
#include <SdFatUtil.h> // use functions to print strings from flash memory
|
||||
|
||||
Sd2Card card;
|
||||
SdVolume volume;
|
||||
SdFile root;
|
||||
SdFile from; // read file
|
||||
SdFile copy; // write file
|
||||
|
||||
// large buffer to test for bugs. 512 bytes runs much faster.
|
||||
char buf[600];
|
||||
|
||||
// store error strings in flash to save RAM
|
||||
#define error(s) error_P(PSTR(s))
|
||||
|
||||
void error_P(const char* str) {
|
||||
PgmPrint("error: ");
|
||||
SerialPrintln_P(str);
|
||||
if (card.errorCode()) {
|
||||
PgmPrint("SD error: ");
|
||||
Serial.print(card.errorCode(), HEX);
|
||||
Serial.print(',');
|
||||
Serial.println(card.errorData(), HEX);
|
||||
}
|
||||
while(1);
|
||||
}
|
||||
|
||||
void setup(void) {
|
||||
Serial.begin(9600);
|
||||
Serial.println();
|
||||
PgmPrintln("Type any character to start");
|
||||
while (!Serial.available());
|
||||
|
||||
PgmPrint("FreeRam: ");
|
||||
Serial.println(FreeRam());
|
||||
|
||||
// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
|
||||
// breadboards. use SPI_FULL_SPEED for better performance.
|
||||
if (!card.init(SPI_HALF_SPEED)) error("card.init failed");
|
||||
|
||||
// initialize a FAT volume
|
||||
if (!volume.init(&card)) error("volume.init failed");
|
||||
|
||||
// open the root directory
|
||||
if (!root.openRoot(&volume)) error("openRoot failed");
|
||||
|
||||
strcpy_P(buf, PSTR("APPEND.TXT"));
|
||||
// open for read
|
||||
if (!from.open(&root, buf, O_READ)) {
|
||||
PgmPrint("Can't open ");
|
||||
Serial.println(buf);
|
||||
PgmPrintln("Run the append example to create the file.");
|
||||
error("from.open failed");
|
||||
}
|
||||
strcpy_P(buf, PSTR("ACOPY.TXT"));
|
||||
// create if needed, truncate to zero length, open for write
|
||||
if (!copy.open(&root, buf, O_CREAT | O_TRUNC | O_WRITE)) {
|
||||
error("copy.open failed");
|
||||
}
|
||||
// count for printing periods
|
||||
uint16_t p = 0;
|
||||
int16_t n;
|
||||
while ((n = from.read(buf, sizeof(buf))) > 0) {
|
||||
if (copy.write(buf, n) != n) error("write failed");
|
||||
// print progress periods
|
||||
if (!(p++ % 25)) Serial.print('.');
|
||||
if (!(p % 500)) Serial.println();
|
||||
}
|
||||
Serial.println();
|
||||
if (n != 0) error ("read");
|
||||
// force write of directory entry and last data
|
||||
if (!copy.close()) error("copy.close failed");
|
||||
PgmPrintln("Copy done.");
|
||||
}
|
||||
|
||||
void loop(void) {}
|
@ -1,340 +0,0 @@
|
||||
// Ladyada's logger modified by Bill Greiman to use the SdFat library
|
||||
|
||||
// this is a generic logger that does checksum testing so the data written should be always good
|
||||
// Assumes a sirf III chipset logger attached to pin 0 and 1
|
||||
|
||||
#include <SdFat.h>
|
||||
#include <SdFatUtil.h>
|
||||
#include <avr/sleep.h>
|
||||
|
||||
// macros to use PSTR
|
||||
#define putstring(str) SerialPrint_P(PSTR(str))
|
||||
#define putstring_nl(str) SerialPrintln_P(PSTR(str))
|
||||
|
||||
// power saving modes
|
||||
#define SLEEPDELAY 0
|
||||
#define TURNOFFGPS 0
|
||||
#define LOG_RMC_FIXONLY 1
|
||||
|
||||
Sd2Card card;
|
||||
SdVolume volume;
|
||||
SdFile root;
|
||||
SdFile f;
|
||||
|
||||
#define led1Pin 4
|
||||
#define led2Pin 3
|
||||
#define powerPin 2
|
||||
|
||||
#define BUFFSIZE 75
|
||||
char buffer[BUFFSIZE];
|
||||
uint8_t bufferidx = 0;
|
||||
uint8_t fix = 0; // current fix data
|
||||
uint8_t i;
|
||||
|
||||
/* EXAMPLE
|
||||
|
||||
$PSRF103,<msg>,<mode>,<rate>,<cksumEnable>*CKSUM<CR><LF>
|
||||
|
||||
<msg> 00=GGA,01=GLL,02=GSA,03=GSV,04=RMC,05=VTG
|
||||
<mode> 00=SetRate,01=Query
|
||||
<rate> Output every <rate>seconds, off=00,max=255
|
||||
<cksumEnable> 00=disable Checksum,01=Enable checksum for specified message
|
||||
Note: checksum is required
|
||||
|
||||
Example 1: Query the GGA message with checksum enabled
|
||||
$PSRF103,00,01,00,01*25
|
||||
|
||||
Example 2: Enable VTG message for a 1Hz constant output with checksum enabled
|
||||
$PSRF103,05,00,01,01*20
|
||||
|
||||
Example 3: Disable VTG message
|
||||
$PSRF103,05,00,00,01*21
|
||||
|
||||
*/
|
||||
|
||||
#define SERIAL_SET "$PSRF100,01,4800,08,01,00*0E\r\n"
|
||||
|
||||
// GGA-Global Positioning System Fixed Data, message 103,00
|
||||
#define LOG_GGA 0
|
||||
#define GGA_ON "$PSRF103,00,00,01,01*25\r\n"
|
||||
#define GGA_OFF "$PSRF103,00,00,00,01*24\r\n"
|
||||
|
||||
// GLL-Geographic Position-Latitude/Longitude, message 103,01
|
||||
#define LOG_GLL 0
|
||||
#define GLL_ON "$PSRF103,01,00,01,01*26\r\n"
|
||||
#define GLL_OFF "$PSRF103,01,00,00,01*27\r\n"
|
||||
|
||||
// GSA-GNSS DOP and Active Satellites, message 103,02
|
||||
#define LOG_GSA 0
|
||||
#define GSA_ON "$PSRF103,02,00,01,01*27\r\n"
|
||||
#define GSA_OFF "$PSRF103,02,00,00,01*26\r\n"
|
||||
|
||||
// GSV-GNSS Satellites in View, message 103,03
|
||||
#define LOG_GSV 0
|
||||
#define GSV_ON "$PSRF103,03,00,01,01*26\r\n"
|
||||
#define GSV_OFF "$PSRF103,03,00,00,01*27\r\n"
|
||||
|
||||
// RMC-Recommended Minimum Specific GNSS Data, message 103,04
|
||||
#define LOG_RMC 1
|
||||
#define RMC_ON "$PSRF103,04,00,01,01*21\r\n"
|
||||
#define RMC_OFF "$PSRF103,04,00,00,01*20\r\n"
|
||||
|
||||
// VTG-Course Over Ground and Ground Speed, message 103,05
|
||||
#define LOG_VTG 0
|
||||
#define VTG_ON "$PSRF103,05,00,01,01*20\r\n"
|
||||
#define VTG_OFF "$PSRF103,05,00,00,01*21\r\n"
|
||||
|
||||
// Switch Development Data Messages On/Off, message 105
|
||||
#define LOG_DDM 1
|
||||
#define DDM_ON "$PSRF105,01*3E\r\n"
|
||||
#define DDM_OFF "$PSRF105,00*3F\r\n"
|
||||
|
||||
#define USE_WAAS 0 // useful in US, but slower fix
|
||||
#define WAAS_ON "$PSRF151,01*3F\r\n" // the command for turning on WAAS
|
||||
#define WAAS_OFF "$PSRF151,00*3E\r\n" // the command for turning off WAAS
|
||||
|
||||
// read a Hex value and return the decimal equivalent
|
||||
uint8_t parseHex(char c) {
|
||||
if (c < '0')
|
||||
return 0;
|
||||
if (c <= '9')
|
||||
return c - '0';
|
||||
if (c < 'A')
|
||||
return 0;
|
||||
if (c <= 'F')
|
||||
return (c - 'A')+10;
|
||||
}
|
||||
|
||||
// blink out an error code
|
||||
void error(uint8_t errno) {
|
||||
if (card.errorCode()) {
|
||||
putstring("SD error: ");
|
||||
Serial.print(card.errorCode(), HEX);
|
||||
Serial.print(',');
|
||||
Serial.println(card.errorData(), HEX);
|
||||
}
|
||||
while(1) {
|
||||
for (i=0; i<errno; i++) {
|
||||
digitalWrite(led1Pin, HIGH);
|
||||
digitalWrite(led2Pin, HIGH);
|
||||
delay(100);
|
||||
digitalWrite(led1Pin, LOW);
|
||||
digitalWrite(led2Pin, LOW);
|
||||
delay(100);
|
||||
}
|
||||
for (; i<10; i++) {
|
||||
delay(200);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setup() {
|
||||
WDTCSR |= (1 << WDCE) | (1 << WDE);
|
||||
WDTCSR = 0;
|
||||
Serial.begin(4800);
|
||||
putstring_nl("\r\nGPSlogger");
|
||||
pinMode(led1Pin, OUTPUT);
|
||||
pinMode(led2Pin, OUTPUT);
|
||||
pinMode(powerPin, OUTPUT);
|
||||
digitalWrite(powerPin, LOW);
|
||||
|
||||
// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
|
||||
// breadboards. use SPI_FULL_SPEED for better performance.
|
||||
if (!card.init(SPI_HALF_SPEED)) {
|
||||
putstring_nl("Card init. failed!");
|
||||
error(1);
|
||||
}
|
||||
if (!volume.init(&card)) {
|
||||
putstring_nl("No partition!");
|
||||
error(2);
|
||||
}
|
||||
if(!root.openRoot(&volume)) {
|
||||
putstring_nl("Can't! open root dir");
|
||||
error(3);
|
||||
}
|
||||
strcpy(buffer, "GPSLOG00.TXT");
|
||||
for (i = 0; i < 100; i++) {
|
||||
buffer[6] = '0' + i/10;
|
||||
buffer[7] = '0' + i%10;
|
||||
// create if does not exist, do not open existing, write, sync after write
|
||||
if (f.open(&root, buffer, O_CREAT | O_EXCL | O_WRITE | O_SYNC)) break;
|
||||
}
|
||||
|
||||
if(!f.isOpen()) {
|
||||
putstring("couldnt create "); Serial.println(buffer);
|
||||
error(3);
|
||||
}
|
||||
putstring("writing to "); Serial.println(buffer);
|
||||
putstring_nl("ready!");
|
||||
|
||||
putstring(SERIAL_SET);
|
||||
delay(250);
|
||||
|
||||
if (LOG_DDM)
|
||||
putstring(DDM_ON);
|
||||
else
|
||||
putstring(DDM_OFF);
|
||||
delay(250);
|
||||
|
||||
if (LOG_GGA)
|
||||
putstring(GGA_ON);
|
||||
else
|
||||
putstring(GGA_OFF);
|
||||
delay(250);
|
||||
|
||||
if (LOG_GLL)
|
||||
putstring(GLL_ON);
|
||||
else
|
||||
putstring(GLL_OFF);
|
||||
delay(250);
|
||||
|
||||
if (LOG_GSA)
|
||||
putstring(GSA_ON);
|
||||
else
|
||||
putstring(GSA_OFF);
|
||||
delay(250);
|
||||
|
||||
if (LOG_GSV)
|
||||
putstring(GSV_ON);
|
||||
else
|
||||
putstring(GSV_OFF);
|
||||
delay(250);
|
||||
|
||||
if (LOG_RMC)
|
||||
putstring(RMC_ON);
|
||||
else
|
||||
putstring(RMC_OFF);
|
||||
delay(250);
|
||||
|
||||
if (LOG_VTG)
|
||||
putstring(VTG_ON);
|
||||
else
|
||||
putstring(VTG_OFF);
|
||||
delay(250);
|
||||
|
||||
if (USE_WAAS)
|
||||
putstring(WAAS_ON);
|
||||
else
|
||||
putstring(WAAS_OFF);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
//Serial.println(Serial.available(), DEC);
|
||||
char c;
|
||||
uint8_t sum;
|
||||
|
||||
// read one 'line'
|
||||
if (Serial.available()) {
|
||||
c = Serial.read();
|
||||
//Serial.print(c, BYTE);
|
||||
if (bufferidx == 0) {
|
||||
while (c != '$')
|
||||
c = Serial.read(); // wait till we get a $
|
||||
}
|
||||
buffer[bufferidx] = c;
|
||||
|
||||
//Serial.print(c, BYTE);
|
||||
if (c == '\n') {
|
||||
//putstring_nl("EOL");
|
||||
//Serial.print(buffer);
|
||||
buffer[bufferidx+1] = 0; // terminate it
|
||||
|
||||
if (buffer[bufferidx-4] != '*') {
|
||||
// no checksum?
|
||||
Serial.print('*', BYTE);
|
||||
bufferidx = 0;
|
||||
return;
|
||||
}
|
||||
// get checksum
|
||||
sum = parseHex(buffer[bufferidx-3]) * 16;
|
||||
sum += parseHex(buffer[bufferidx-2]);
|
||||
|
||||
// check checksum
|
||||
for (i=1; i < (bufferidx-4); i++) {
|
||||
sum ^= buffer[i];
|
||||
}
|
||||
if (sum != 0) {
|
||||
//putstring_nl("Cxsum mismatch");
|
||||
Serial.print('~', BYTE);
|
||||
bufferidx = 0;
|
||||
return;
|
||||
}
|
||||
// got good data!
|
||||
|
||||
if (strstr(buffer, "GPRMC")) {
|
||||
// find out if we got a fix
|
||||
char *p = buffer;
|
||||
p = strchr(p, ',')+1;
|
||||
p = strchr(p, ',')+1; // skip to 3rd item
|
||||
|
||||
if (p[0] == 'V') {
|
||||
digitalWrite(led1Pin, LOW);
|
||||
fix = 0;
|
||||
} else {
|
||||
digitalWrite(led1Pin, HIGH);
|
||||
fix = 1;
|
||||
}
|
||||
}
|
||||
if (LOG_RMC_FIXONLY) {
|
||||
if (!fix) {
|
||||
Serial.print('_', BYTE);
|
||||
bufferidx = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
// rad. lets log it!
|
||||
Serial.print(buffer);
|
||||
Serial.print('#', BYTE);
|
||||
digitalWrite(led2Pin, HIGH); // sets the digital pin as output
|
||||
|
||||
// Bill Greiman - need to write bufferidx + 1 bytes to getCR/LF
|
||||
bufferidx++;
|
||||
|
||||
if(f.write((uint8_t *) buffer, bufferidx) != bufferidx) {
|
||||
putstring_nl("can't write!");
|
||||
error(4);
|
||||
}
|
||||
|
||||
digitalWrite(led2Pin, LOW);
|
||||
|
||||
bufferidx = 0;
|
||||
|
||||
// turn off GPS module?
|
||||
if (TURNOFFGPS) {
|
||||
digitalWrite(powerPin, HIGH);
|
||||
}
|
||||
|
||||
sleep_sec(SLEEPDELAY);
|
||||
digitalWrite(powerPin, LOW);
|
||||
return;
|
||||
}
|
||||
bufferidx++;
|
||||
if (bufferidx == BUFFSIZE-1) {
|
||||
Serial.print('!', BYTE);
|
||||
bufferidx = 0;
|
||||
}
|
||||
} else {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void sleep_sec(uint8_t x) {
|
||||
while (x--) {
|
||||
// set the WDT to wake us up!
|
||||
WDTCSR |= (1 << WDCE) | (1 << WDE); // enable watchdog & enable changing it
|
||||
WDTCSR = (1<< WDE) | (1 <<WDP2) | (1 << WDP1);
|
||||
WDTCSR |= (1<< WDIE);
|
||||
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
|
||||
sleep_enable();
|
||||
sleep_mode();
|
||||
sleep_disable();
|
||||
}
|
||||
}
|
||||
|
||||
SIGNAL(WDT_vect) {
|
||||
WDTCSR |= (1 << WDCE) | (1 << WDE);
|
||||
WDTCSR = 0;
|
||||
}
|
||||
|
||||
/* End code */
|
@ -1,387 +0,0 @@
|
||||
// Ladyada's logger modified by Bill Greiman to use the SdFat library
|
||||
// this is a generic logger that does checksum testing so the data written should be always good
|
||||
// Assumes a sirf III chipset logger attached to pin 0 and 1
|
||||
|
||||
uint8_t sensorCount = 3; //number of analog pins to log
|
||||
|
||||
#include <SdFat.h>
|
||||
#include <SdFatUtil.h>
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
#define isdigit(x) ( x >= '0' && x <= '9')
|
||||
|
||||
//extern uint16_t _end;
|
||||
|
||||
Sd2Card card;
|
||||
SdVolume volume;
|
||||
SdFile root;
|
||||
SdFile f;
|
||||
|
||||
#define led1Pin 4 // LED1 connected to digital pin 4
|
||||
#define led2Pin 3 // LED2 connected to digital pin 3
|
||||
#define powerpin 2 // GPS power control
|
||||
|
||||
// set the RX_BUFFER_SIZE to 32!
|
||||
#define BUFFSIZE 73 // we buffer one NMEA sentence at a time, 83 bytes is longer than the max length
|
||||
char buffer[BUFFSIZE]; // this is the double buffer
|
||||
char buffer2[12];
|
||||
|
||||
uint8_t bufferidx = 0;
|
||||
uint32_t tmp;
|
||||
#define LOG_RMC 1 // essential location data
|
||||
#define RMC_ON "$PSRF103,4,0,1,1*21\r\n" // the command we send to turn RMC on (1 hz rate)
|
||||
#define RMC_OFF "$PSRF103,4,0,0,1*20\r\n" // the command we send to turn RMC off
|
||||
|
||||
#define LOG_GGA 0 // contains fix, hdop & vdop data
|
||||
#define GGA_ON "$PSRF103,0,0,1,1*25\r\n" // the command we send to turn GGA on (1 hz rate)
|
||||
#define GGA_OFF "$PSRF103,0,0,0,1*24\r\n" // the command we send to turn GGA off
|
||||
|
||||
#define LOG_GSA 0 // satellite data
|
||||
#define GSA_ON "$PSRF103,2,0,1,1*27\r\n" // the command we send to turn GSA on (1 hz rate)
|
||||
#define GSA_OFF "$PSRF103,2,0,0,1*26\r\n" // the command we send to turn GSA off
|
||||
|
||||
#define LOG_GSV 0 // detailed satellite data
|
||||
#define GSV_ON "$PSRF103,3,0,1,1*26\r\n" // the command we send to turn GSV on (1 hz rate)
|
||||
#define GSV_OFF "$PSRF103,3,0,0,1*27\r\n" // the command we send to turn GSV off
|
||||
|
||||
#define LOG_GLL 0 // Loran-compatibility data
|
||||
// this isnt output by default
|
||||
|
||||
#define USE_WAAS 1 // useful in US, but slower fix
|
||||
#define WAAS_ON "$PSRF151,1*3F\r\n" // the command for turning on WAAS
|
||||
#define WAAS_OFF "$PSRF151,0*3E\r\n" // the command for turning off WAAS
|
||||
|
||||
#define LOG_RMC_FIXONLY 1 // log only when we get RMC's with fix?
|
||||
uint8_t fix = 0; // current fix data
|
||||
|
||||
// macros to use PSTR
|
||||
#define putstring(str) SerialPrint_P(PSTR(str))
|
||||
#define putstring_nl(str) SerialPrintln_P(PSTR(str))
|
||||
|
||||
// read a Hex value and return the decimal equivalent
|
||||
uint8_t parseHex(char c) {
|
||||
if (c < '0')
|
||||
return 0;
|
||||
if (c <= '9')
|
||||
return c - '0';
|
||||
if (c < 'A')
|
||||
return 0;
|
||||
if (c <= 'F')
|
||||
return (c - 'A')+10;
|
||||
}
|
||||
|
||||
uint8_t i;
|
||||
|
||||
// blink out an error code
|
||||
void error(uint8_t errno) {
|
||||
if (card.errorCode()) {
|
||||
putstring("SD error: ");
|
||||
Serial.print(card.errorCode(), HEX);
|
||||
Serial.print(',');
|
||||
Serial.println(card.errorData(), HEX);
|
||||
}
|
||||
while(1) {
|
||||
for (i=0; i<errno; i++) {
|
||||
digitalWrite(led1Pin, HIGH);
|
||||
digitalWrite(led2Pin, HIGH);
|
||||
delay(100);
|
||||
digitalWrite(led1Pin, LOW);
|
||||
digitalWrite(led2Pin, LOW);
|
||||
delay(100);
|
||||
}
|
||||
for (; i<10; i++) {
|
||||
delay(200);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setup() { // run once, when the sketch starts
|
||||
Serial.begin(4800);
|
||||
putstring_nl("GPSlogger");
|
||||
pinMode(led1Pin, OUTPUT); // sets the digital pin as output
|
||||
pinMode(led2Pin, OUTPUT); // sets the digital pin as output
|
||||
pinMode(powerpin, OUTPUT);
|
||||
digitalWrite(powerpin, LOW);
|
||||
|
||||
// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
|
||||
// breadboards. use SPI_FULL_SPEED for better performance.
|
||||
if (!card.init(SPI_HALF_SPEED)) {
|
||||
putstring_nl("Card init. failed!");
|
||||
error(1);
|
||||
}
|
||||
if (!volume.init(&card)) {
|
||||
putstring_nl("No partition!");
|
||||
error(2);
|
||||
}
|
||||
if (!root.openRoot(&volume)) {
|
||||
putstring_nl("Can't open root dir");
|
||||
error(3);
|
||||
}
|
||||
strcpy(buffer, "GPSLOG00.CSV");
|
||||
for (i = 0; i < 100; i++) {
|
||||
buffer[6] = '0' + i/10;
|
||||
buffer[7] = '0' + i%10;
|
||||
if (f.open(&root, buffer, O_CREAT | O_EXCL | O_WRITE)) break;
|
||||
}
|
||||
|
||||
if(!f.isOpen()) {
|
||||
putstring("couldnt create "); Serial.println(buffer);
|
||||
error(3);
|
||||
}
|
||||
putstring("writing to "); Serial.println(buffer);
|
||||
putstring_nl("ready!");
|
||||
|
||||
// write header
|
||||
if (sensorCount > 6) sensorCount = 6;
|
||||
strncpy_P(buffer, PSTR("time,lat,long,speed,date,sens0,sens1,sens2,sens3,sens4,sens5"), 24 + 6*sensorCount);
|
||||
Serial.println(buffer);
|
||||
// clear print error
|
||||
f.writeError = 0;
|
||||
f.println(buffer);
|
||||
if (f.writeError || !f.sync()) {
|
||||
putstring_nl("can't write header!");
|
||||
error(5);
|
||||
}
|
||||
|
||||
delay(1000);
|
||||
|
||||
putstring("\r\n");
|
||||
#if USE_WAAS == 1
|
||||
putstring(WAAS_ON); // turn on WAAS
|
||||
#else
|
||||
putstring(WAAS_OFF); // turn on WAAS
|
||||
#endif
|
||||
|
||||
#if LOG_RMC == 1
|
||||
putstring(RMC_ON); // turn on RMC
|
||||
#else
|
||||
putstring(RMC_OFF); // turn off RMC
|
||||
#endif
|
||||
|
||||
#if LOG_GSV == 1
|
||||
putstring(GSV_ON); // turn on GSV
|
||||
#else
|
||||
putstring(GSV_OFF); // turn off GSV
|
||||
#endif
|
||||
|
||||
#if LOG_GSA == 1
|
||||
putstring(GSA_ON); // turn on GSA
|
||||
#else
|
||||
putstring(GSA_OFF); // turn off GSA
|
||||
#endif
|
||||
|
||||
#if LOG_GGA == 1
|
||||
putstring(GGA_ON); // turn on GGA
|
||||
#else
|
||||
putstring(GGA_OFF); // turn off GGA
|
||||
#endif
|
||||
}
|
||||
|
||||
void loop() { // run over and over again
|
||||
|
||||
//Serial.println(Serial.available(), DEC);
|
||||
char c;
|
||||
uint8_t sum;
|
||||
|
||||
// read one 'line'
|
||||
if (Serial.available()) {
|
||||
c = Serial.read();
|
||||
//Serial.print(c, BYTE);
|
||||
if (bufferidx == 0) {
|
||||
while (c != '$')
|
||||
c = Serial.read(); // wait till we get a $
|
||||
}
|
||||
buffer[bufferidx] = c;
|
||||
|
||||
//Serial.print(c, BYTE);
|
||||
if (c == '\n') {
|
||||
//putstring_nl("EOL");
|
||||
//Serial.print(buffer);
|
||||
buffer[bufferidx+1] = 0; // terminate it
|
||||
|
||||
if (buffer[bufferidx-4] != '*') {
|
||||
// no checksum?
|
||||
Serial.print('*', BYTE);
|
||||
bufferidx = 0;
|
||||
return;
|
||||
}
|
||||
// get checksum
|
||||
sum = parseHex(buffer[bufferidx-3]) * 16;
|
||||
sum += parseHex(buffer[bufferidx-2]);
|
||||
|
||||
// check checksum
|
||||
for (i=1; i < (bufferidx-4); i++) {
|
||||
sum ^= buffer[i];
|
||||
}
|
||||
if (sum != 0) {
|
||||
//putstring_nl("Cxsum mismatch");
|
||||
Serial.print('~', BYTE);
|
||||
bufferidx = 0;
|
||||
return;
|
||||
}
|
||||
// got good data!
|
||||
|
||||
if (strstr(buffer, "GPRMC")) {
|
||||
// find out if we got a fix
|
||||
char *p = buffer;
|
||||
p = strchr(p, ',')+1;
|
||||
p = strchr(p, ',')+1; // skip to 3rd item
|
||||
|
||||
if (p[0] == 'V') {
|
||||
digitalWrite(led1Pin, LOW);
|
||||
fix = 0;
|
||||
} else {
|
||||
digitalWrite(led1Pin, HIGH);
|
||||
fix = 1;
|
||||
}
|
||||
} else {
|
||||
// not GPRMC
|
||||
bufferidx = 0;
|
||||
return;
|
||||
}
|
||||
#if LOG_RMC_FIXONLY
|
||||
if (!fix) {
|
||||
Serial.print('_', BYTE);
|
||||
bufferidx = 0;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
// rad. lets print it!
|
||||
|
||||
Serial.print(buffer);
|
||||
|
||||
// time to clean up the string
|
||||
// find time
|
||||
char *p = buffer;
|
||||
p = strchr(p, ',')+1;
|
||||
buffer[0] = p[0];
|
||||
buffer[1] = p[1];
|
||||
buffer[2] = ':';
|
||||
buffer[3] = p[2];
|
||||
buffer[4] = p[3];
|
||||
buffer[5] = ':';
|
||||
buffer[6] = p[4];
|
||||
buffer[7] = p[5];
|
||||
// we ignore milliseconds
|
||||
buffer[8] = ',';
|
||||
|
||||
p = strchr(buffer+8, ',')+1;
|
||||
// skip past 'active' flag
|
||||
p = strchr(p, ',')+1;
|
||||
// find lat
|
||||
p = strchr(p, ',')+1;
|
||||
|
||||
buffer[9] = '+';
|
||||
buffer[10] = p[0];
|
||||
buffer[11] = p[1];
|
||||
buffer[12] = ' ';
|
||||
strncpy(buffer+13, p+2, 7);
|
||||
buffer[20] = ',';
|
||||
|
||||
p = strchr(buffer+21, ',')+1;
|
||||
if (p[0] == 'S')
|
||||
buffer[9] = '-';
|
||||
|
||||
// find long
|
||||
p = strchr(p, ',')+1;
|
||||
buffer[21] = '+';
|
||||
buffer[22] = p[0];
|
||||
buffer[23] = p[1];
|
||||
buffer[24] = p[2];
|
||||
buffer[25] = ' ';
|
||||
strncpy(buffer+26, p+3, 7);
|
||||
buffer[33] = ',';
|
||||
|
||||
p = strchr(buffer+34, ',')+1;
|
||||
if (p[0] == 'W')
|
||||
buffer[21] = '-';
|
||||
|
||||
// find speed
|
||||
p = strchr(p, ',')+1;
|
||||
tmp = 0;
|
||||
if (p[0] != ',') {
|
||||
// ok there is some sort of speed
|
||||
while (p[0] != '.' && p[0] != ',') {
|
||||
tmp *= 10;
|
||||
tmp += p[0] - '0';
|
||||
p++;
|
||||
}
|
||||
tmp *= 10;
|
||||
if (isdigit(p[1]))
|
||||
tmp += p[1] - '0'; // tenths
|
||||
tmp *= 10;
|
||||
if (isdigit(p[2]))
|
||||
tmp += p[2] - '0'; // hundredths
|
||||
|
||||
// tmp is knots * 100
|
||||
// convert to mph (1.15 mph = 1 knot)
|
||||
tmp *= 115;
|
||||
// -OR- convert km/h
|
||||
// tmp *= 185
|
||||
}
|
||||
tmp /= 100;
|
||||
|
||||
buffer[34] = (tmp / 10000) + '0';
|
||||
tmp %= 10000;
|
||||
buffer[35] = (tmp / 1000) + '0';
|
||||
tmp %= 1000;
|
||||
buffer[36] = (tmp / 100) + '0';
|
||||
tmp %= 100;
|
||||
buffer[37] = '.';
|
||||
buffer[38] = (tmp / 10) + '0';
|
||||
tmp %= 10;
|
||||
buffer[39] = tmp + '0';
|
||||
|
||||
buffer[40] = ',';
|
||||
p = strchr(p, ',')+1;
|
||||
// skip past bearing
|
||||
p = strchr(p, ',')+1;
|
||||
//mod for bug when speed,bearing are missing (bill greiman)
|
||||
uint8_t date[6];
|
||||
for (uint8_t id = 0; id < 6; id++) date[id] = p[id];
|
||||
// get date into 2001-01-31 style
|
||||
buffer[41] = '2';
|
||||
buffer[42] = '0';
|
||||
buffer[43] = date[4];
|
||||
buffer[44] = date[5];
|
||||
buffer[45] = '-';
|
||||
buffer[46] = date[2];
|
||||
buffer[47] = date[3];
|
||||
buffer[48] = '-';
|
||||
buffer[49] = date[0];
|
||||
buffer[50] = date[1];
|
||||
buffer[51] = 0;
|
||||
digitalWrite(led2Pin, HIGH);
|
||||
if(f.write((uint8_t *) buffer, 51) != 51) {
|
||||
putstring_nl("can't write fix!");
|
||||
return;
|
||||
}
|
||||
Serial.print(buffer);
|
||||
// clear print error
|
||||
f.writeError = 0;
|
||||
// add sensor data
|
||||
for (uint8_t ia = 0; ia < sensorCount; ia++) {
|
||||
Serial.print(',');
|
||||
f.print(',');
|
||||
uint16_t data = analogRead(ia);
|
||||
Serial.print(data);
|
||||
f.print(data);
|
||||
}
|
||||
Serial.println();
|
||||
f.println();
|
||||
if (f.writeError || !f.sync()) {
|
||||
putstring_nl("can't write data!");
|
||||
error(4);
|
||||
}
|
||||
digitalWrite(led2Pin, LOW);
|
||||
bufferidx = 0;
|
||||
return;
|
||||
}
|
||||
bufferidx++;
|
||||
if (bufferidx == BUFFSIZE-1) {
|
||||
Serial.print('!', BYTE);
|
||||
bufferidx = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,180 +0,0 @@
|
||||
/*
|
||||
* This sketch attempts to initialize a SD card and analyze its structure.
|
||||
*/
|
||||
#include <SdFat.h>
|
||||
#include <SdFatUtil.h>
|
||||
|
||||
// offset to partition table
|
||||
#define PART_OFFSET (512-64-2)
|
||||
|
||||
Sd2Card card;
|
||||
SdVolume vol;
|
||||
|
||||
//global for card erase sector size
|
||||
uint32_t sectorSize;
|
||||
|
||||
void sdError(void) {
|
||||
PgmPrintln("SD error");
|
||||
PgmPrint("errorCode: ");
|
||||
Serial.println(card.errorCode(), HEX);
|
||||
PgmPrint("errorData: ");
|
||||
Serial.println(card.errorData(), HEX);
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t cidDmp(void) {
|
||||
cid_t cid;
|
||||
if (!card.readCID(&cid)) {
|
||||
PgmPrint("readCID failed");
|
||||
sdError();
|
||||
return false;
|
||||
}
|
||||
PgmPrint("\nManufacturer ID: ");
|
||||
Serial.println(cid.mid, HEX);
|
||||
PgmPrint("OEM ID: ");
|
||||
Serial.print(cid.oid[0]);
|
||||
Serial.println(cid.oid[1]);
|
||||
PgmPrint("Product: ");
|
||||
for (uint8_t i = 0; i < 5; i++) {
|
||||
Serial.print(cid.pnm[i]);
|
||||
}
|
||||
PgmPrint("\nVersion: ");
|
||||
Serial.print(cid.prv_n, DEC);
|
||||
Serial.print('.');
|
||||
Serial.println(cid.prv_m, DEC);
|
||||
PgmPrint("Serial number: ");
|
||||
Serial.println(cid.psn);
|
||||
PgmPrint("Manufacturing date: ");
|
||||
Serial.print(cid.mdt_month);
|
||||
Serial.print('/');
|
||||
Serial.println(2000 + cid.mdt_year_low + (cid.mdt_year_high <<4));
|
||||
Serial.println();
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t csdDmp(void) {
|
||||
csd_t csd;
|
||||
uint8_t eraseSingleBlock;
|
||||
uint32_t cardSize = card.cardSize();
|
||||
if (cardSize == 0 || !card.readCSD(&csd)) {
|
||||
PgmPrintln("readCSD failed");
|
||||
sdError();
|
||||
return false;
|
||||
}
|
||||
if (csd.v1.csd_ver == 0) {
|
||||
eraseSingleBlock = csd.v1.erase_blk_en;
|
||||
sectorSize = (csd.v1.sector_size_high << 1) | csd.v1.sector_size_low;
|
||||
}
|
||||
else if (csd.v2.csd_ver == 1) {
|
||||
eraseSingleBlock = csd.v2.erase_blk_en;
|
||||
sectorSize = (csd.v2.sector_size_high << 1) | csd.v2.sector_size_low;
|
||||
}
|
||||
else {
|
||||
PgmPrintln("csd version error");
|
||||
return false;
|
||||
}
|
||||
sectorSize++;
|
||||
PgmPrint("cardSize: ");
|
||||
Serial.print(cardSize);
|
||||
PgmPrintln(" (512 byte blocks)");
|
||||
PgmPrint("flashEraseSize: ");
|
||||
Serial.print(sectorSize, DEC);
|
||||
PgmPrintln(" blocks");
|
||||
PgmPrint("eraseSingleBlock: ");
|
||||
if (eraseSingleBlock) {
|
||||
PgmPrintln("true");
|
||||
}
|
||||
else {
|
||||
PgmPrintln("false");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// print partition table
|
||||
uint8_t partDmp(void) {
|
||||
part_t pt;
|
||||
PgmPrintln("\npart,boot,type,start,length");
|
||||
for (uint8_t ip = 1; ip < 5; ip++) {
|
||||
if (!card.readData(0, PART_OFFSET + 16*(ip-1), 16, (uint8_t *)&pt)) {
|
||||
PgmPrint("read partition table failed");
|
||||
sdError();
|
||||
return false;
|
||||
}
|
||||
Serial.print(ip, DEC);
|
||||
Serial.print(',');
|
||||
Serial.print(pt.boot,HEX);
|
||||
Serial.print(',');
|
||||
Serial.print(pt.type, HEX);
|
||||
Serial.print(',');
|
||||
Serial.print(pt.firstSector);
|
||||
Serial.print(',');
|
||||
Serial.println(pt.totalSectors);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void volDmp(void) {
|
||||
PgmPrint("\nVolume is FAT");
|
||||
Serial.println(vol.fatType(), DEC);
|
||||
PgmPrint("blocksPerCluster: ");
|
||||
Serial.println(vol.blocksPerCluster(), DEC);
|
||||
PgmPrint("clusterCount: ");
|
||||
Serial.println(vol.clusterCount());
|
||||
PgmPrint("fatStartBlock: ");
|
||||
Serial.println(vol.fatStartBlock());
|
||||
PgmPrint("fatCount: ");
|
||||
Serial.println(vol.fatCount(), DEC);
|
||||
PgmPrint("blocksPerFat: ");
|
||||
Serial.println(vol.blocksPerFat());
|
||||
PgmPrint("rootDirStart: ");
|
||||
Serial.println(vol.rootDirStart());
|
||||
PgmPrint("dataStartBlock: ");
|
||||
Serial.println(vol.dataStartBlock());
|
||||
if (vol.dataStartBlock()%sectorSize) {
|
||||
PgmPrintln("Data area is not aligned on flash erase boundaries!");
|
||||
}
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
PgmPrintln("\ntype any character to start");
|
||||
while (!Serial.available());
|
||||
Serial.flush();
|
||||
uint32_t t = millis();
|
||||
// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
|
||||
// breadboards. use SPI_FULL_SPEED for better performance.
|
||||
uint8_t r = card.init(SPI_HALF_SPEED);
|
||||
t = millis() - t;
|
||||
if (!r) {
|
||||
PgmPrintln("\ncard.init failed");
|
||||
sdError();
|
||||
return;
|
||||
}
|
||||
PgmPrint("\ninit time: ");
|
||||
Serial.println(t);
|
||||
PgmPrint("\nCard type: ");
|
||||
switch(card.type()) {
|
||||
case SD_CARD_TYPE_SD1:
|
||||
PgmPrintln("SD1");
|
||||
break;
|
||||
case SD_CARD_TYPE_SD2:
|
||||
PgmPrintln("SD2");
|
||||
break;
|
||||
case SD_CARD_TYPE_SDHC:
|
||||
PgmPrintln("SDHC");
|
||||
break;
|
||||
default:
|
||||
PgmPrintln("Unknown");
|
||||
}
|
||||
if(!cidDmp()) return;
|
||||
if(!csdDmp()) return;
|
||||
if(!partDmp()) return;
|
||||
if (!vol.init(&card)) {
|
||||
PgmPrintln("\nvol.init failed");
|
||||
sdError();
|
||||
return;
|
||||
}
|
||||
volDmp();
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
/*
|
||||
* This sketch will list all files in the root directory and
|
||||
* then do a recursive list of all directories on the SD card.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <SdFat.h>
|
||||
#include <SdFatUtil.h>
|
||||
|
||||
Sd2Card card;
|
||||
SdVolume volume;
|
||||
SdFile root;
|
||||
|
||||
// store error strings in flash to save RAM
|
||||
#define error(s) error_P(PSTR(s))
|
||||
|
||||
void error_P(const char* str) {
|
||||
PgmPrint("error: ");
|
||||
SerialPrintln_P(str);
|
||||
if (card.errorCode()) {
|
||||
PgmPrint("SD error: ");
|
||||
Serial.print(card.errorCode(), HEX);
|
||||
Serial.print(',');
|
||||
Serial.println(card.errorData(), HEX);
|
||||
}
|
||||
while(1);
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
PgmPrintln("Type any character to start");
|
||||
while (!Serial.available());
|
||||
|
||||
PgmPrint("Free RAM: ");
|
||||
Serial.println(FreeRam());
|
||||
|
||||
// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
|
||||
// breadboards. use SPI_FULL_SPEED for better performance.
|
||||
if (!card.init(SPI_HALF_SPEED)) error("card.init failed!");
|
||||
|
||||
// initialize a FAT volume
|
||||
if (!volume.init(&card)) error("vol.init failed!");
|
||||
|
||||
PgmPrint("Volume is FAT");
|
||||
Serial.println(volume.fatType(),DEC);
|
||||
Serial.println();
|
||||
|
||||
if (!root.openRoot(&volume)) error("openRoot failed");
|
||||
|
||||
// list file in root with date and size
|
||||
PgmPrintln("Files found in root:");
|
||||
root.ls(LS_DATE | LS_SIZE);
|
||||
Serial.println();
|
||||
|
||||
// Recursive list of all directories
|
||||
PgmPrintln("Files found in all dirs:");
|
||||
root.ls(LS_R);
|
||||
|
||||
Serial.println();
|
||||
PgmPrintln("Done");
|
||||
}
|
||||
|
||||
void loop() { }
|
@ -1,150 +0,0 @@
|
||||
/*
|
||||
* This sketch is a test of subdirectory and file creation.
|
||||
* It also tests allocation of clusters to directories.
|
||||
*
|
||||
* It will create two subdirectories and create enough files
|
||||
* to force the allocation of a cluster to each directory.
|
||||
*
|
||||
* More than 3000 files may be created on a FAT32 volume.
|
||||
*
|
||||
* Note: Some cards may 'stutter' others just get slow due
|
||||
* to the number of flash erases this program causes.
|
||||
*/
|
||||
#include <SdFat.h>
|
||||
#include <SdFatUtil.h>
|
||||
|
||||
Sd2Card card;
|
||||
SdVolume volume;
|
||||
SdFile root;
|
||||
|
||||
// store error strings in flash to save RAM
|
||||
#define error(s) error_P(PSTR(s))
|
||||
|
||||
void error_P(const char* str) {
|
||||
PgmPrint("error: ");
|
||||
SerialPrintln_P(str);
|
||||
if (card.errorCode()) {
|
||||
PgmPrint("SD error: ");
|
||||
Serial.print(card.errorCode(), HEX);
|
||||
Serial.print(',');
|
||||
Serial.println(card.errorData(), HEX);
|
||||
}
|
||||
while(1);
|
||||
}
|
||||
/*
|
||||
* create enough files to force a cluster to be allocated to dir.
|
||||
*/
|
||||
void dirAllocTest(SdFile &dir) {
|
||||
char buf[13], name[13];
|
||||
SdFile file;
|
||||
uint16_t n;
|
||||
uint32_t size = dir.fileSize();
|
||||
|
||||
// create files and write name to file
|
||||
for (n = 0; ; n++){
|
||||
// make file name
|
||||
sprintf(name, "%u.TXT", n);
|
||||
|
||||
// open start time
|
||||
uint32_t t0 = millis();
|
||||
if (!file.open(&dir, name, O_WRITE | O_CREAT | O_EXCL)) {
|
||||
error("open for write failed");
|
||||
}
|
||||
|
||||
// open end time and write start time
|
||||
uint32_t t1 = millis();
|
||||
// write file name to file
|
||||
file.print(name);
|
||||
if (!file.close()) error("close write");
|
||||
|
||||
// write end time
|
||||
uint32_t t2 = millis();
|
||||
PgmPrint("WR ");
|
||||
Serial.print(n);
|
||||
Serial.print(' ');
|
||||
|
||||
// print time to create file
|
||||
Serial.print(t1 - t0);
|
||||
Serial.print(' ');
|
||||
|
||||
// print time to write file
|
||||
Serial.println(t2 - t1);
|
||||
|
||||
// directory size will change when a cluster is added
|
||||
if (dir.fileSize() != size) break;
|
||||
}
|
||||
|
||||
// read files and check content
|
||||
for (uint16_t i = 0; i <= n; i++) {
|
||||
sprintf(name, "%u.TXT", i);
|
||||
|
||||
// open start time
|
||||
uint32_t t0 = millis();
|
||||
if (!file.open(&dir, name, O_READ)) {
|
||||
error("open for read failed");
|
||||
}
|
||||
|
||||
// open end time and read start time
|
||||
uint32_t t1 = millis();
|
||||
int16_t nr = file.read(buf, 13);
|
||||
if (nr < 5) error("file.read failed");
|
||||
|
||||
// read end time
|
||||
uint32_t t2 = millis();
|
||||
|
||||
// check file content
|
||||
if (strlen(name) != nr || strncmp(name, buf, nr)) {
|
||||
error("content compare failed");
|
||||
}
|
||||
if (!file.close()) error("close read failed");
|
||||
|
||||
PgmPrint("RD ");
|
||||
Serial.print(i);
|
||||
Serial.print(' ');
|
||||
|
||||
// print open time
|
||||
Serial.print(t1 - t0);
|
||||
Serial.print(' ');
|
||||
|
||||
// print read time
|
||||
Serial.println(t2 - t1);
|
||||
}
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
PgmPrintln("Type any character to start");
|
||||
while (!Serial.available());
|
||||
|
||||
// initialize the SD card at SPI_FULL_SPEED for best performance.
|
||||
// try SPI_HALF_SPEED if bus errors occur.
|
||||
if (!card.init(SPI_FULL_SPEED)) error("card.init failed");
|
||||
|
||||
// initialize a FAT volume
|
||||
if (!volume.init(&card)) error("volume.init failed");
|
||||
|
||||
// open the root directory
|
||||
if (!root.openRoot(&volume)) error("openRoot failed");
|
||||
|
||||
// write files to root if FAT32
|
||||
if (volume.fatType() == 32) {
|
||||
PgmPrintln("Writing files to root");
|
||||
dirAllocTest(root);
|
||||
}
|
||||
|
||||
// create sub1 and write files
|
||||
SdFile sub1;
|
||||
if (!sub1.makeDir(&root, "SUB1")) error("makdeDir SUB1 failed");
|
||||
PgmPrintln("Writing files to SUB1");
|
||||
dirAllocTest(sub1);
|
||||
|
||||
// create sub2 and write files
|
||||
SdFile sub2;
|
||||
if (!sub2.makeDir(&sub1, "SUB2")) error("makeDir SUB2 failed");
|
||||
PgmPrintln("Writing files to SUB2");
|
||||
dirAllocTest(sub2);
|
||||
|
||||
PgmPrintln("Done");
|
||||
}
|
||||
|
||||
void loop() { }
|
@ -1,71 +0,0 @@
|
||||
/*
|
||||
* Print Example
|
||||
*
|
||||
* This sketch shows how to use the Arduino Print class with SdFat.
|
||||
*/
|
||||
#include <SdFat.h>
|
||||
#include <SdFatUtil.h> // use functions to print strings from flash memory
|
||||
|
||||
Sd2Card card;
|
||||
SdVolume volume;
|
||||
SdFile root;
|
||||
SdFile file;
|
||||
|
||||
// store error strings in flash to save RAM
|
||||
#define error(s) error_P(PSTR(s))
|
||||
|
||||
void error_P(const char* str) {
|
||||
PgmPrint("error: ");
|
||||
SerialPrintln_P(str);
|
||||
if (card.errorCode()) {
|
||||
PgmPrint("SD error: ");
|
||||
Serial.print(card.errorCode(), HEX);
|
||||
Serial.print(',');
|
||||
Serial.println(card.errorData(), HEX);
|
||||
}
|
||||
while(1);
|
||||
}
|
||||
|
||||
void setup(void) {
|
||||
Serial.begin(9600);
|
||||
Serial.println();
|
||||
PgmPrintln("Type any character to start");
|
||||
while (!Serial.available());
|
||||
|
||||
// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
|
||||
// breadboards. use SPI_FULL_SPEED for better performance.
|
||||
if (!card.init(SPI_HALF_SPEED)) error("card.init failed");
|
||||
|
||||
// initialize a FAT volume
|
||||
if (!volume.init(&card)) error("volume.init failed");
|
||||
|
||||
// open the root directory
|
||||
if (!root.openRoot(&volume)) error("openRoot failed");
|
||||
|
||||
// create a new file
|
||||
char name[] = "PRINT00.TXT";
|
||||
for (uint8_t i = 0; i < 100; i++) {
|
||||
name[5] = i/10 + '0';
|
||||
name[6] = i%10 + '0';
|
||||
// only create new file for write
|
||||
if (file.open(&root, name, O_CREAT | O_EXCL | O_WRITE)) break;
|
||||
}
|
||||
if (!file.isOpen()) error ("file.create");
|
||||
PgmPrintln("Printing to: ");
|
||||
Serial.println(name);
|
||||
|
||||
// clear print error
|
||||
file.writeError = 0;
|
||||
|
||||
// print 100 line to file
|
||||
for (uint8_t i = 0; i < 100; i++) {
|
||||
file.print("line ");
|
||||
file.print(i, DEC);
|
||||
file.print(" millis = ");
|
||||
file.println(millis());
|
||||
}
|
||||
// force write of all data to the SD card
|
||||
if (file.writeError || !file.sync()) error ("print or sync");
|
||||
PgmPrintln("Done");
|
||||
}
|
||||
void loop(void){}
|
@ -1,186 +0,0 @@
|
||||
/*
|
||||
* This sketch illustrates raw write functions in SdFat that
|
||||
* can be used for high speed data logging. These functions
|
||||
* are used in the WaveRP library to record audio with the
|
||||
* Adafruit Wave Shield using the built-in Arduino ADC.
|
||||
*
|
||||
* The WaveRP library captures data from the ADC in an ISR
|
||||
* that is driven driven by timer one. Data is collected in
|
||||
* two 512 byte buffers and written to the SD card.
|
||||
*
|
||||
* This sketch simulates logging from a source that produces
|
||||
* data at a constant rate of one block every MILLIS_PER_BLOCK.
|
||||
*
|
||||
* If a high quality SanDisk card is used with this sketch
|
||||
* no overruns occur and the maximum block write time is
|
||||
* 2 millis.
|
||||
*
|
||||
* Note: WaveRP creates a very large file then truncates it
|
||||
* to the length that is used for a recording. It only takes
|
||||
* a few seconds to erase a 500 MB file since the card only
|
||||
* marks the blocks as erased; no data transfer is required.
|
||||
*/
|
||||
|
||||
#include <SdFat.h>
|
||||
#include <SdFatUtil.h>
|
||||
|
||||
// number of blocks in the contiguous file
|
||||
#define BLOCK_COUNT 10000UL
|
||||
|
||||
// time to produce a block of data
|
||||
#define MILLIS_PER_BLOCK 10
|
||||
|
||||
Sd2Card card;
|
||||
SdVolume volume;
|
||||
SdFile root;
|
||||
SdFile file;
|
||||
|
||||
uint32_t bgnBlock, endBlock;
|
||||
|
||||
// store error strings in flash to save RAM
|
||||
#define error(s) error_P(PSTR(s))
|
||||
|
||||
void error_P(const char* str) {
|
||||
PgmPrint("error: ");
|
||||
SerialPrintln_P(str);
|
||||
if (card.errorCode()) {
|
||||
PgmPrint("SD error: ");
|
||||
Serial.print(card.errorCode(), HEX);
|
||||
Serial.print(',');
|
||||
Serial.println(card.errorData(), HEX);
|
||||
}
|
||||
while(1);
|
||||
}
|
||||
|
||||
void setup(void) {
|
||||
Serial.begin(9600);
|
||||
}
|
||||
|
||||
void loop(void) {
|
||||
Serial.flush();
|
||||
PgmPrintln("Type any character to start");
|
||||
while (!Serial.available());
|
||||
|
||||
// initialize the SD card
|
||||
uint32_t t = millis();
|
||||
|
||||
// initialize the SD card at SPI_FULL_SPEED for best performance.
|
||||
// try SPI_HALF_SPEED if bus errors occur.
|
||||
if (!card.init(SPI_FULL_SPEED)) error("card.init failed");
|
||||
|
||||
t = millis() - t;
|
||||
|
||||
PgmPrint("Card init time: ");
|
||||
Serial.print(t);
|
||||
PgmPrintln(" millis");
|
||||
|
||||
// initialize a FAT volume
|
||||
if (!volume.init(&card)) error("volume.init failed");
|
||||
|
||||
// open the root directory
|
||||
if (!root.openRoot(&volume)) error("openRoot failed");
|
||||
|
||||
// delete possible existing file
|
||||
SdFile::remove(&root, "RAW.TXT");
|
||||
|
||||
// create a contiguous file
|
||||
if (!file.createContiguous(&root, "RAW.TXT", 512UL*BLOCK_COUNT)) {
|
||||
error("createContiguous failed");
|
||||
}
|
||||
// get the location of the file's blocks
|
||||
if (!file.contiguousRange(&bgnBlock, &endBlock)) {
|
||||
error("contiguousRange failed");
|
||||
}
|
||||
//*********************NOTE**************************************
|
||||
// NO SdFile calls are allowed while cache is used for raw writes
|
||||
//***************************************************************
|
||||
|
||||
// clear the cache and use it as a 512 byte buffer
|
||||
uint8_t* pCache = volume.cacheClear();
|
||||
|
||||
// fill cache with eight lines of 64 bytes each
|
||||
memset(pCache, ' ', 512);
|
||||
for (uint16_t i = 0; i < 512; i += 64) {
|
||||
// put line number at end of line then CR/LF
|
||||
pCache[i + 61] = '0' + (i/64);
|
||||
pCache[i + 62] = '\r';
|
||||
pCache[i + 63] = '\n';
|
||||
}
|
||||
|
||||
PgmPrint("Start raw write of ");
|
||||
Serial.print(file.fileSize());
|
||||
PgmPrintln(" bytes at");
|
||||
|
||||
Serial.print(512000UL/MILLIS_PER_BLOCK);
|
||||
PgmPrintln(" bytes per second");
|
||||
|
||||
PgmPrint("Please wait ");
|
||||
Serial.print((BLOCK_COUNT*MILLIS_PER_BLOCK)/1000UL);
|
||||
PgmPrintln(" seconds");
|
||||
|
||||
// tell card to setup for multiple block write with pre-erase
|
||||
if (!card.erase(bgnBlock, endBlock)) error("card.erase failed");
|
||||
if (!card.writeStart(bgnBlock, BLOCK_COUNT)) {
|
||||
error("writeStart failed");
|
||||
}
|
||||
// init stats
|
||||
uint16_t overruns = 0;
|
||||
uint16_t maxWriteTime = 0;
|
||||
t = millis();
|
||||
uint32_t tNext = t;
|
||||
|
||||
// write data
|
||||
for (uint32_t b = 0; b < BLOCK_COUNT; b++) {
|
||||
// write must be done by this time
|
||||
tNext += MILLIS_PER_BLOCK;
|
||||
|
||||
// put block number at start of first line in block
|
||||
uint32_t n = b;
|
||||
for (int8_t d = 5; d >= 0; d--){
|
||||
pCache[d] = n || d == 5 ? n % 10 + '0' : ' ';
|
||||
n /= 10;
|
||||
}
|
||||
// write a 512 byte block
|
||||
uint32_t tw = micros();
|
||||
if (!card.writeData(pCache)) error("writeData failed");
|
||||
tw = micros() - tw;
|
||||
|
||||
// check for max write time
|
||||
if (tw > maxWriteTime) {
|
||||
maxWriteTime = tw;
|
||||
}
|
||||
// check for overrun
|
||||
if (millis() > tNext) {
|
||||
overruns++;
|
||||
// advance time to reflect overrun
|
||||
tNext = millis();
|
||||
}
|
||||
else {
|
||||
// wait for time to write next block
|
||||
while(millis() < tNext);
|
||||
}
|
||||
}
|
||||
// total write time
|
||||
t = millis() - t;
|
||||
|
||||
// end multiple block write mode
|
||||
if (!card.writeStop()) error("writeStop failed");
|
||||
|
||||
PgmPrintln("Done");
|
||||
|
||||
PgmPrint("Overruns: ");
|
||||
Serial.println(overruns);
|
||||
|
||||
PgmPrint("Elapsed time: ");
|
||||
Serial.print(t);
|
||||
PgmPrintln(" millis");
|
||||
|
||||
PgmPrint("Max write time: ");
|
||||
Serial.print(maxWriteTime);
|
||||
PgmPrintln(" micros");
|
||||
|
||||
// close files for next pass of loop
|
||||
root.close();
|
||||
file.close();
|
||||
Serial.println();
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
/*
|
||||
* This sketch reads and prints the file
|
||||
* PRINT00.TXT created by SdFatPrint.pde or
|
||||
* WRITE00.TXT created by SdFatWrite.pde
|
||||
*/
|
||||
#include <SdFat.h>
|
||||
#include <SdFatUtil.h>
|
||||
|
||||
Sd2Card card;
|
||||
SdVolume volume;
|
||||
SdFile root;
|
||||
SdFile file;
|
||||
|
||||
// store error strings in flash to save RAM
|
||||
#define error(s) error_P(PSTR(s))
|
||||
|
||||
void error_P(const char* str) {
|
||||
PgmPrint("error: ");
|
||||
SerialPrintln_P(str);
|
||||
if (card.errorCode()) {
|
||||
PgmPrint("SD error: ");
|
||||
Serial.print(card.errorCode(), HEX);
|
||||
Serial.print(',');
|
||||
Serial.println(card.errorData(), HEX);
|
||||
}
|
||||
while(1);
|
||||
}
|
||||
|
||||
void setup(void) {
|
||||
Serial.begin(9600);
|
||||
Serial.println();
|
||||
Serial.println("type any character to start");
|
||||
while (!Serial.available());
|
||||
Serial.println();
|
||||
|
||||
// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
|
||||
// breadboards. use SPI_FULL_SPEED for better performance.
|
||||
if (!card.init(SPI_HALF_SPEED)) error("card.init failed");
|
||||
|
||||
// initialize a FAT volume
|
||||
if (!volume.init(&card)) error("volume.init failed");
|
||||
|
||||
// open the root directory
|
||||
if (!root.openRoot(&volume)) error("openRoot failed");
|
||||
|
||||
// open a file
|
||||
if (file.open(&root, "PRINT00.TXT", O_READ)) {
|
||||
Serial.println("Opened PRINT00.TXT");
|
||||
}
|
||||
else if (file.open(&root, "WRITE00.TXT", O_READ)) {
|
||||
Serial.println("Opened WRITE00.TXT");
|
||||
}
|
||||
else{
|
||||
error("file.open failed");
|
||||
}
|
||||
Serial.println();
|
||||
|
||||
// copy file to serial port
|
||||
int16_t n;
|
||||
uint8_t buf[7];// nothing special about 7, just a lucky number.
|
||||
while ((n = file.read(buf, sizeof(buf))) > 0) {
|
||||
for (uint8_t i = 0; i < n; i++) Serial.print(buf[i]);
|
||||
}
|
||||
/* easier way
|
||||
int16_t c;
|
||||
while ((c = file.read()) > 0) Serial.print((char)c);
|
||||
*/
|
||||
Serial.println("\nDone");
|
||||
}
|
||||
|
||||
void loop(void) {}
|
@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Remove Example
|
||||
*
|
||||
* This sketch shows how to use remove() to delete
|
||||
* the file created by the SdFatAppend.pde example.
|
||||
*/
|
||||
#include <SdFat.h>
|
||||
#include <SdFatUtil.h> // use functions to print strings from flash memory
|
||||
|
||||
Sd2Card card;
|
||||
SdVolume volume;
|
||||
SdFile root;
|
||||
SdFile file;
|
||||
|
||||
// store error strings in flash to save RAM
|
||||
#define error(s) error_P(PSTR(s))
|
||||
|
||||
void error_P(const char* str) {
|
||||
PgmPrint("error: ");
|
||||
SerialPrintln_P(str);
|
||||
if (card.errorCode()) {
|
||||
PgmPrint("SD error: ");
|
||||
Serial.print(card.errorCode(), HEX);
|
||||
Serial.print(',');
|
||||
Serial.println(card.errorData(), HEX);
|
||||
}
|
||||
while(1);
|
||||
}
|
||||
|
||||
void setup(void) {
|
||||
Serial.begin(9600);
|
||||
Serial.println();
|
||||
PgmPrintln("Type any character to start");
|
||||
while (!Serial.available());
|
||||
|
||||
// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
|
||||
// breadboards. use SPI_FULL_SPEED for better performance.
|
||||
if (!card.init(SPI_HALF_SPEED)) error("card.init failed");
|
||||
|
||||
// initialize a FAT volume
|
||||
if (!volume.init(&card)) error("volume.init failed");
|
||||
|
||||
// open the root directory
|
||||
if (!root.openRoot(&volume)) error("openRoot failed");
|
||||
|
||||
char name[] = "APPEND.TXT";
|
||||
if (!file.open(&root, name, O_WRITE)) {
|
||||
PgmPrint("Can't open ");
|
||||
Serial.println(name);
|
||||
PgmPrintln("Run the append example to create the file.");
|
||||
error("file.open failed");
|
||||
}
|
||||
if (!file.remove()) error("file.remove failed");
|
||||
Serial.print(name);
|
||||
PgmPrintln(" deleted.");
|
||||
}
|
||||
|
||||
void loop(void) {}
|
@ -1,72 +0,0 @@
|
||||
/*
|
||||
* Rewrite Example
|
||||
*
|
||||
* This sketch shows how to rewrite part of a line in the middle
|
||||
* of the file created by the SdFatAppend.pde example.
|
||||
*
|
||||
* Check around line 30 of pass 50 of APPEND.TXT after running this sketch.
|
||||
*/
|
||||
#include <SdFat.h>
|
||||
#include <SdFatUtil.h> // use functions to print strings from flash memory
|
||||
|
||||
Sd2Card card;
|
||||
SdVolume volume;
|
||||
SdFile root;
|
||||
SdFile file;
|
||||
|
||||
// store error strings in flash to save RAM
|
||||
#define error(s) error_P(PSTR(s))
|
||||
|
||||
void error_P(const char* str) {
|
||||
PgmPrint("error: ");
|
||||
SerialPrintln_P(str);
|
||||
if (card.errorCode()) {
|
||||
PgmPrint("SD error: ");
|
||||
Serial.print(card.errorCode(), HEX);
|
||||
Serial.print(',');
|
||||
Serial.println(card.errorData(), HEX);
|
||||
}
|
||||
while(1);
|
||||
}
|
||||
|
||||
void setup(void) {
|
||||
Serial.begin(9600);
|
||||
Serial.println();
|
||||
PgmPrintln("Type any character to start");
|
||||
while (!Serial.available());
|
||||
|
||||
// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
|
||||
// breadboards. use SPI_FULL_SPEED for better performance.
|
||||
if (!card.init(SPI_HALF_SPEED)) error("card.init failed");
|
||||
|
||||
// initialize a FAT volume
|
||||
if (!volume.init(&card)) error("volume.init failed");
|
||||
|
||||
// open the root directory
|
||||
if (!root.openRoot(&volume)) error("openRoot failed");
|
||||
|
||||
char name[] = "APPEND.TXT";
|
||||
// open for read and write
|
||||
if (!file.open(&root, name, O_RDWR)) {
|
||||
PgmPrint("Can't open ");
|
||||
Serial.println(name);
|
||||
PgmPrintln("Run the append example to create the file.");
|
||||
error("file.open failed");
|
||||
}
|
||||
// seek to middle of file
|
||||
if (!file.seekSet(file.fileSize()/2)) error("file.seekSet failed");
|
||||
// find end of line
|
||||
int16_t c;
|
||||
while ((c = file.read()) > 0 && c != '\n');
|
||||
if (c < 0) error("file.read failed");
|
||||
// clear write error flag
|
||||
file.writeError = false;
|
||||
// rewrite the begining of the line at the current position
|
||||
file.write("**rewrite**");
|
||||
if (file.writeError) error("file.write failed");
|
||||
if (!file.close()) error("file.close failed");
|
||||
Serial.print(name);
|
||||
PgmPrintln(" rewrite done.");
|
||||
}
|
||||
|
||||
void loop(void) {}
|
@ -1,111 +0,0 @@
|
||||
/*
|
||||
* This sketch will remove the files and directories
|
||||
* created by the SdFatMakeDir.pde sketch.
|
||||
*
|
||||
* Performance is erratic due to the large number
|
||||
* of flash erase operations caused by many random
|
||||
* writes to file structures.
|
||||
*/
|
||||
#include <SdFat.h>
|
||||
#include <SdFatUtil.h>
|
||||
|
||||
Sd2Card card;
|
||||
SdVolume volume;
|
||||
SdFile root;
|
||||
|
||||
// store error strings in flash to save RAM
|
||||
#define error(s) error_P(PSTR(s))
|
||||
|
||||
void error_P(const char* str) {
|
||||
PgmPrint("error: ");
|
||||
SerialPrintln_P(str);
|
||||
if (card.errorCode()) {
|
||||
PgmPrint("SD error: ");
|
||||
Serial.print(card.errorCode(), HEX);
|
||||
Serial.print(',');
|
||||
Serial.println(card.errorData(), HEX);
|
||||
}
|
||||
while(1);
|
||||
}
|
||||
/*
|
||||
* remove all files in dir.
|
||||
*/
|
||||
void deleteFiles(SdFile &dir) {
|
||||
char name[13];
|
||||
SdFile file;
|
||||
|
||||
// open and delete files
|
||||
for (uint16_t n = 0; ; n++){
|
||||
sprintf(name, "%u.TXT", n);
|
||||
|
||||
// open start time
|
||||
uint32_t t0 = millis();
|
||||
|
||||
// assume done if open fails
|
||||
if (!file.open(&dir, name, O_WRITE)) return;
|
||||
|
||||
// open end time and remove start time
|
||||
uint32_t t1 = millis();
|
||||
if (!file.remove()) error("file.remove failed");
|
||||
|
||||
// remove end time
|
||||
uint32_t t2 = millis();
|
||||
|
||||
PgmPrint("RM ");
|
||||
Serial.print(n);
|
||||
Serial.print(' ');
|
||||
|
||||
// open time
|
||||
Serial.print(t1 - t0);
|
||||
Serial.print(' ');
|
||||
|
||||
// remove time
|
||||
Serial.println(t2 - t1);
|
||||
}
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
PgmPrintln("Type any character to start");
|
||||
while (!Serial.available());
|
||||
|
||||
// initialize the SD card at SPI_FULL_SPEED for best performance.
|
||||
// try SPI_HALF_SPEED if bus errors occur.
|
||||
if (!card.init(SPI_FULL_SPEED)) error("card.init failed");
|
||||
|
||||
// initialize a FAT volume
|
||||
if (!volume.init(&card)) error("volume.init failed");
|
||||
|
||||
// open the root directory
|
||||
if (!root.openRoot(&volume)) error("openRoot failed");
|
||||
|
||||
// delete files in root if FAT32
|
||||
if (volume.fatType() == 32) {
|
||||
PgmPrintln("Remove files in root");
|
||||
deleteFiles(root);
|
||||
}
|
||||
|
||||
// open SUB1 and delete files
|
||||
SdFile sub1;
|
||||
if (!sub1.open(&root, "SUB1", O_READ)) error("open SUB1 failed");
|
||||
PgmPrintln("Remove files in SUB1");
|
||||
deleteFiles(sub1);
|
||||
|
||||
// open SUB2 and delete files
|
||||
SdFile sub2;
|
||||
if (!sub2.open(&sub1, "SUB2", O_READ)) error("open SUB2 failed");
|
||||
PgmPrintln("Remove files in SUB2");
|
||||
deleteFiles(sub2);
|
||||
|
||||
// remove SUB2
|
||||
if (!sub2.rmDir()) error("sub2.rmDir failed");
|
||||
PgmPrintln("SUB2 removed");
|
||||
|
||||
// remove SUB1
|
||||
if (!sub1.rmDir()) error("sub1.rmDir failed");
|
||||
PgmPrintln("SUB1 removed");
|
||||
|
||||
PgmPrintln("Done");
|
||||
}
|
||||
|
||||
void loop() { }
|
@ -1,98 +0,0 @@
|
||||
/*
|
||||
* This sketch reads and prints the tail of all files
|
||||
* created by SdFatAppend.pde, SdFatPrint.pde, and
|
||||
* SdFatWrite.pde.
|
||||
*/
|
||||
#include <SdFat.h>
|
||||
#include <SdFatUtil.h>
|
||||
|
||||
Sd2Card card;
|
||||
SdVolume volume;
|
||||
SdFile root;
|
||||
SdFile file;
|
||||
|
||||
// store error strings in flash to save RAM
|
||||
#define error(s) error_P(PSTR(s))
|
||||
|
||||
void error_P(const char* str) {
|
||||
PgmPrint("error: ");
|
||||
SerialPrintln_P(str);
|
||||
if (card.errorCode()) {
|
||||
PgmPrint("SD error: ");
|
||||
Serial.print(card.errorCode(), HEX);
|
||||
Serial.print(',');
|
||||
Serial.println(card.errorData(), HEX);
|
||||
}
|
||||
while(1);
|
||||
}
|
||||
|
||||
void setup(void) {
|
||||
Serial.begin(9600);
|
||||
Serial.println();
|
||||
Serial.println("type any character to start");
|
||||
while (!Serial.available());
|
||||
Serial.println();
|
||||
|
||||
// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
|
||||
// breadboards. use SPI_FULL_SPEED for better performance.
|
||||
if (!card.init(SPI_HALF_SPEED)) error("card.init failed");
|
||||
|
||||
// initialize a FAT volume
|
||||
if (!volume.init(&card)) error("volume.init failed");
|
||||
|
||||
// open the root directory
|
||||
if (!root.openRoot(&volume)) error("openRoot failed");
|
||||
}
|
||||
|
||||
/*
|
||||
* Print tail of all SdFat example files
|
||||
*/
|
||||
void loop(void) {
|
||||
dir_t dir;
|
||||
char name[13];
|
||||
|
||||
// read next directory entry
|
||||
if (root.readDir(&dir) != sizeof(dir)) {
|
||||
Serial.println("End of Directory");
|
||||
while(1);
|
||||
}
|
||||
|
||||
// check for file name "APPEND.TXT", "PRINT*.TXT"
|
||||
// or "WRITE*.TXT"
|
||||
// first 8 bytes are blank filled name
|
||||
// last three bytes are blank filled extension
|
||||
if ((strncmp((char *)dir.name, "APPEND ", 8) &&
|
||||
strncmp((char *)dir.name, "PRINT", 5) &&
|
||||
strncmp((char *)dir.name, "WRITE", 5)) ||
|
||||
strncmp((char *)&dir.name[8], "TXT", 3)) {
|
||||
return;
|
||||
}
|
||||
// format file name
|
||||
SdFile::dirName(dir, name);
|
||||
|
||||
// remember position in root dir
|
||||
uint32_t pos = root.curPosition();
|
||||
|
||||
// open file
|
||||
if (!file.open(&root, name, O_READ)) error("file.open failed");
|
||||
|
||||
// restore root position
|
||||
if (!root.seekSet(pos)) error("root.seekSet failed");
|
||||
|
||||
// print file name message
|
||||
Serial.print("Tail of: ");
|
||||
Serial.println(name);
|
||||
|
||||
// position to tail of file
|
||||
if (file.fileSize() > 100) {
|
||||
if (!file.seekSet(file.fileSize() - 100)) error("file.seekSet failed");
|
||||
}
|
||||
int16_t c;
|
||||
// find end of line
|
||||
while ((c = file.read()) > 0 && c != '\n');
|
||||
|
||||
// print rest of file
|
||||
while ((c = file.read()) > 0) Serial.print((char)c);
|
||||
file.close();
|
||||
Serial.println();
|
||||
}
|
@ -1,182 +0,0 @@
|
||||
/*
|
||||
* This sketch tests the dateTimeCallback() function
|
||||
* and the timestamp() function.
|
||||
*/
|
||||
#include <SdFat.h>
|
||||
#include <SdFatUtil.h> // use PgmPrint
|
||||
/*
|
||||
* date/time values for debug
|
||||
* normally supplied by a real-time clock or GPS
|
||||
*/
|
||||
// date 2009-10-01 1-Oct-09
|
||||
uint16_t year = 2009;
|
||||
uint8_t month = 10;
|
||||
uint8_t day = 1;
|
||||
|
||||
// time 20:30:40
|
||||
uint8_t hour = 20;
|
||||
uint8_t minute = 30;
|
||||
uint8_t second = 40;
|
||||
/*
|
||||
* User provided date time callback function.
|
||||
* See SdFile::dateTimeCallback() for usage.
|
||||
*/
|
||||
void dateTime(uint16_t* date, uint16_t* time) {
|
||||
// User gets date and time from GPS or real-time
|
||||
// clock in real callback function
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
Sd2Card card;
|
||||
SdVolume volume;
|
||||
SdFile root;
|
||||
SdFile file;
|
||||
|
||||
// store error strings in flash to save RAM
|
||||
#define error(s) error_P(PSTR(s))
|
||||
|
||||
void error_P(const char* str) {
|
||||
PgmPrint("error: ");
|
||||
SerialPrintln_P(str);
|
||||
if (card.errorCode()) {
|
||||
PgmPrint("SD error: ");
|
||||
Serial.print(card.errorCode(), HEX);
|
||||
Serial.print(',');
|
||||
Serial.println(card.errorData(), HEX);
|
||||
}
|
||||
while(1);
|
||||
}
|
||||
/*
|
||||
* Function to print all timestamps.
|
||||
*/
|
||||
void printTimestamps(SdFile& f) {
|
||||
dir_t d;
|
||||
if (!f.dirEntry(&d)) error("f.dirEntry failed");
|
||||
|
||||
PgmPrint("Creation: ");
|
||||
f.printFatDate(d.creationDate);
|
||||
Serial.print(' ');
|
||||
f.printFatTime(d.creationTime);
|
||||
Serial.println();
|
||||
|
||||
PgmPrint("Modify: ");
|
||||
f.printFatDate(d.lastWriteDate);
|
||||
Serial.print(' ');
|
||||
f.printFatTime(d.lastWriteTime);
|
||||
Serial.println();
|
||||
|
||||
PgmPrint("Access: ");
|
||||
f.printFatDate(d.lastAccessDate);
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
void setup(void) {
|
||||
Serial.begin(9600);
|
||||
Serial.println();
|
||||
PgmPrintln("Type any character to start");
|
||||
while (!Serial.available());
|
||||
|
||||
// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
|
||||
// breadboards. use SPI_FULL_SPEED for better performance.
|
||||
if (!card.init(SPI_HALF_SPEED)) error("card.init failed");
|
||||
|
||||
// initialize a FAT volume
|
||||
if (!volume.init(&card)) error("volume.init failed");
|
||||
|
||||
// open the root directory
|
||||
if (!root.openRoot(&volume)) error("openRoot failed");
|
||||
|
||||
// remove files if they exist
|
||||
SdFile::remove(&root, "CALLBACK.TXT");
|
||||
SdFile::remove(&root, "DEFAULT.TXT");
|
||||
SdFile::remove(&root, "STAMP.TXT");
|
||||
|
||||
// create a new file with default timestamps
|
||||
if (!file.open(&root, "DEFAULT.TXT", O_CREAT | O_WRITE)) {
|
||||
error("open DEFAULT.TXT failed");
|
||||
}
|
||||
Serial.println();
|
||||
PgmPrintln("Open with default times");
|
||||
printTimestamps(file);
|
||||
|
||||
// close file
|
||||
file.close();
|
||||
/*
|
||||
* Test the date time callback function.
|
||||
*
|
||||
* dateTimeCallback() sets the function
|
||||
* that is called when a file is created
|
||||
* or when a file's directory entry is
|
||||
* modified by sync().
|
||||
*
|
||||
* The callback can be disabled by the call
|
||||
* SdFile::dateTimeCallbackCancel()
|
||||
*/
|
||||
// set date time callback function
|
||||
SdFile::dateTimeCallback(dateTime);
|
||||
|
||||
// create a new file with callback timestamps
|
||||
if (!file.open(&root, "CALLBACK.TXT", O_CREAT | O_WRITE)) {
|
||||
error("open CALLBACK.TXT failed");
|
||||
}
|
||||
Serial.println();
|
||||
PgmPrintln("Open with callback times");
|
||||
printTimestamps(file);
|
||||
|
||||
// change call back date
|
||||
day += 1;
|
||||
|
||||
// must add two to see change since FAT second field is 5-bits
|
||||
second += 2;
|
||||
|
||||
// modify file by writing a byte
|
||||
file.write('t');
|
||||
|
||||
// force dir update
|
||||
file.sync();
|
||||
|
||||
Serial.println();
|
||||
PgmPrintln("Times after write");
|
||||
printTimestamps(file);
|
||||
|
||||
// close file
|
||||
file.close();
|
||||
/*
|
||||
* Test timestamp() function
|
||||
*
|
||||
* Cancel callback so sync will not
|
||||
* change access/modify timestamp
|
||||
*/
|
||||
SdFile::dateTimeCallbackCancel();
|
||||
|
||||
// create a new file with default timestamps
|
||||
if (!file.open(&root, "STAMP.TXT", O_CREAT | O_WRITE)) {
|
||||
error("open STAMP.TXT failed");
|
||||
}
|
||||
// set creation date time
|
||||
if (!file.timestamp(T_CREATE, 2009, 11, 10, 1, 2, 3)) {
|
||||
error("set create time failed");
|
||||
}
|
||||
// set write/modification date time
|
||||
if (!file.timestamp(T_WRITE, 2009, 11, 11, 4, 5, 6)) {
|
||||
error("set write time failed");
|
||||
}
|
||||
// set access date
|
||||
if (!file.timestamp(T_ACCESS, 2009, 11, 12, 7, 8, 9)) {
|
||||
error("set access time failed");
|
||||
}
|
||||
Serial.println();
|
||||
PgmPrintln("Times after timestamp() calls");
|
||||
printTimestamps(file);
|
||||
|
||||
file.close();
|
||||
Serial.println();
|
||||
PgmPrintln("Done");
|
||||
}
|
||||
|
||||
void loop(void){}
|
@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Truncate Example
|
||||
*
|
||||
* This sketch shows how to use truncate() to remove the last
|
||||
* half of the file created by the SdFatAppend.pde example.
|
||||
*/
|
||||
#include <SdFat.h>
|
||||
#include <SdFatUtil.h> // use functions to print strings from flash memory
|
||||
|
||||
Sd2Card card;
|
||||
SdVolume volume;
|
||||
SdFile root;
|
||||
SdFile file;
|
||||
|
||||
// store error strings in flash to save RAM
|
||||
#define error(s) error_P(PSTR(s))
|
||||
|
||||
void error_P(const char* str) {
|
||||
PgmPrint("error: ");
|
||||
SerialPrintln_P(str);
|
||||
if (card.errorCode()) {
|
||||
PgmPrint("SD error: ");
|
||||
Serial.print(card.errorCode(), HEX);
|
||||
Serial.print(',');
|
||||
Serial.println(card.errorData(), HEX);
|
||||
}
|
||||
while(1);
|
||||
}
|
||||
|
||||
void setup(void) {
|
||||
Serial.begin(9600);
|
||||
Serial.println();
|
||||
PgmPrintln("Type any character to start");
|
||||
while (!Serial.available());
|
||||
|
||||
// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
|
||||
// breadboards. use SPI_FULL_SPEED for better performance.
|
||||
if (!card.init(SPI_HALF_SPEED)) error("card.init failed");
|
||||
|
||||
// initialize a FAT volume
|
||||
if (!volume.init(&card)) error("volume.init failed");
|
||||
|
||||
// open the root directory
|
||||
if (!root.openRoot(&volume)) error("openRoot failed");
|
||||
|
||||
char name[] = "APPEND.TXT";
|
||||
// open for read and write
|
||||
if (!file.open(&root, name, O_RDWR)) {
|
||||
PgmPrint("Can't open ");
|
||||
Serial.println(name);
|
||||
PgmPrintln("Run the append example to create the file.");
|
||||
error("file.open failed");
|
||||
}
|
||||
// seek to middle of file
|
||||
if (!file.seekSet(file.fileSize()/2)) error("file.seekSet failed");
|
||||
// find end of line
|
||||
int16_t c;
|
||||
while ((c = file.read()) > 0 && c != '\n');
|
||||
if (c < 0) error("file.read failed");
|
||||
// truncate at current position
|
||||
if (!file.truncate(file.curPosition())) error("file.truncate failed");
|
||||
Serial.print(name);
|
||||
PgmPrintln(" truncated.");
|
||||
}
|
||||
|
||||
void loop(void) {}
|
@ -1,98 +0,0 @@
|
||||
/*
|
||||
* Write Example
|
||||
*
|
||||
* This sketch creates a new file and writes 100 lines to the file.
|
||||
* No error checks on write in this example.
|
||||
*/
|
||||
|
||||
#include <SdFat.h>
|
||||
#include <SdFatUtil.h>
|
||||
|
||||
Sd2Card card;
|
||||
SdVolume volume;
|
||||
SdFile root;
|
||||
SdFile file;
|
||||
|
||||
// store error strings in flash to save RAM
|
||||
#define error(s) error_P(PSTR(s))
|
||||
|
||||
void error_P(const char* str) {
|
||||
PgmPrint("error: ");
|
||||
SerialPrintln_P(str);
|
||||
if (card.errorCode()) {
|
||||
PgmPrint("SD error: ");
|
||||
Serial.print(card.errorCode(), HEX);
|
||||
Serial.print(',');
|
||||
Serial.println(card.errorData(), HEX);
|
||||
}
|
||||
while(1);
|
||||
}
|
||||
/*
|
||||
* Write CR LF to a file
|
||||
*/
|
||||
void writeCRLF(SdFile& f) {
|
||||
f.write((uint8_t*)"\r\n", 2);
|
||||
}
|
||||
/*
|
||||
* Write an unsigned number to a file
|
||||
*/
|
||||
void writeNumber(SdFile& f, uint32_t n) {
|
||||
uint8_t buf[10];
|
||||
uint8_t i = 0;
|
||||
do {
|
||||
i++;
|
||||
buf[sizeof(buf) - i] = n%10 + '0';
|
||||
n /= 10;
|
||||
} while (n);
|
||||
f.write(&buf[sizeof(buf) - i], i);
|
||||
}
|
||||
/*
|
||||
* Write a string to a file
|
||||
*/
|
||||
void writeString(SdFile& f, char *str) {
|
||||
uint8_t n;
|
||||
for (n = 0; str[n]; n++);
|
||||
f.write((uint8_t *)str, n);
|
||||
}
|
||||
|
||||
void setup(void) {
|
||||
Serial.begin(9600);
|
||||
Serial.println();
|
||||
Serial.println("Type any character to start");
|
||||
while (!Serial.available());
|
||||
|
||||
// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
|
||||
// breadboards. use SPI_FULL_SPEED for better performance.
|
||||
if (!card.init(SPI_HALF_SPEED)) error("card.init failed");
|
||||
|
||||
// initialize a FAT volume
|
||||
if (!volume.init(&card)) error("volume.init failed");
|
||||
|
||||
// open the root directory
|
||||
if (!root.openRoot(&volume)) error("openRoot failed");
|
||||
|
||||
// create a new file
|
||||
char name[] = "WRITE00.TXT";
|
||||
for (uint8_t i = 0; i < 100; i++) {
|
||||
name[5] = i/10 + '0';
|
||||
name[6] = i%10 + '0';
|
||||
if (file.open(&root, name, O_CREAT | O_EXCL | O_WRITE)) break;
|
||||
}
|
||||
if (!file.isOpen()) error ("file.create");
|
||||
Serial.print("Writing to: ");
|
||||
Serial.println(name);
|
||||
|
||||
// write 100 line to file
|
||||
for (uint8_t i = 0; i < 100; i++) {
|
||||
writeString(file, "line ");
|
||||
writeNumber(file, i);
|
||||
writeString(file, " millis = ");
|
||||
writeNumber(file, millis());
|
||||
writeCRLF(file);
|
||||
}
|
||||
// close file and force write of all data to the SD card
|
||||
file.close();
|
||||
Serial.println("Done");
|
||||
}
|
||||
|
||||
void loop(void) {}
|
Loading…
Reference in New Issue
Block a user