瀏覽代碼

File abstraction (work in progress)

main
PaulStoffregen 4 年之前
父節點
當前提交
507dc71293
共有 3 個檔案被更改,包括 237 行新增232 行删除
  1. +95
    -106
      File.cpp
  2. +107
    -73
      SD.cpp
  3. +35
    -53
      SD.h

+ 95
- 106
File.cpp 查看文件

@@ -1,151 +1,140 @@
/*

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.
#include <Arduino.h>
#include <SD.h>
#include <limits.h>

License: GNU General Public License V3
(Because sdfatlib is licensed with this.)
#ifndef __SD_t3_H__

(C) Copyright 2010 SparkFun Electronics
#include <utility/SdFat.h>
#include <utility/SdFatUtil.h>

*/

#include <SD.h>
#ifndef __SD_t3_H__
void SD_File::whoami()
{
//Serial.printf(" SD_File this=%x, f=%x\n", (int)this, (int)f.get());
Serial.printf(" SD_File this=%x, refcount=%u\n",
(int)this, getRefcount());
static int whoamicount = 0;
if (++whoamicount > 20) while (1) ;
}

/* for debugging file open/close leaks
uint8_t nfilecount=0;
*/

File::File(SdFile f, const char *n) {
// oh man you are kidding me, new() doesnt exist? Ok we do it by hand!
_file = (SdFile *)malloc(sizeof(SdFile));
if (_file) {
memcpy(_file, &f, sizeof(SdFile));
strncpy(_name, n, 12);
_name[12] = 0;
/* for debugging file open/close leaks
nfilecount++;
Serial.print("Created \"");
Serial.print(n);
Serial.print("\": ");
Serial.println(nfilecount, DEC);
*/
}
SD_File::SD_File(const SdFile &file, const char *n)
{
_file = new SdFile();
memcpy(_file, &file, sizeof(SdFile)); // should use a copy constructor?
strncpy(_name, n, 12);
_name[12] = 0;
//f = (File *)this;
}

File::File(void) {
_file = 0;
_name[0] = 0;
//Serial.print("Created empty file object");
SD_File::SD_File(void)
{
_file = nullptr;
_name[0] = 0;
//f = (File *)this;
}

File::~File(void) {
// Serial.print("Deleted file object");
SD_File::~SD_File(void)
{
close();
}

// returns a pointer to the file name
char *File::name(void) {
return _name;
const char * SD_File::name(void) {
return _name;
}

// a directory is a special type of file
boolean File::isDirectory(void) {
return (_file && _file->isDir());
bool SD_File::isDirectory(void)
{
return (_file && _file->isDir());
}


size_t File::write(uint8_t val) {
return write(&val, 1);
size_t SD_File::write(uint8_t val)
{
return write(&val, 1);
}

size_t File::write(const uint8_t *buf, size_t size) {
size_t t;
if (!_file) {
setWriteError();
return 0;
}
_file->clearWriteError();
t = _file->write(buf, size);
if (_file->getWriteError()) {
setWriteError();
return 0;
}
return t;
size_t SD_File::write(const void *buf, size_t size)
{
if (_file == nullptr) {
setWriteError();
return 0;
}
_file->clearWriteError();
size_t t = _file->write(buf, size);
if (_file->getWriteError()) {
setWriteError();
return 0;
}
return t;
}

int File::peek() {
if (! _file)
return 0;

int c = _file->read();
if (c != -1) _file->seekCur(-1);
return c;
int SD_File::peek()
{
if (_file == nullptr) return 0;
int c = _file->read();
if (c != -1) _file->seekCur(-1);
return c;
}

int File::read() {
if (_file)
return _file->read();
return -1;
int SD_File::read()
{
if (_file == nullptr) return -1;
return _file->read();
}

// buffered read for more efficient, high speed reading
int File::read(void *buf, uint16_t nbyte) {
if (_file)
return _file->read(buf, nbyte);
return 0;
size_t SD_File::read(void *buf, size_t nbyte) {
if (_file == nullptr) return 0;
return _file->read(buf, nbyte);
}

int File::available() {
if (! _file) return 0;
uint32_t n = size() - position();
return n > 0X7FFF ? 0X7FFF : n;
int SD_File::available()
{
if (_file == nullptr) return 0;
uint32_t n = size() - position();
if (n > INT_MAX) n = INT_MAX;
return n;
}

void File::flush() {
if (_file)
_file->sync();
void SD_File::flush()
{
if (_file == nullptr) return;
_file->sync();
}

boolean File::seek(uint32_t pos) {
if (! _file) return false;
return _file->seekSet(pos);
bool SD_File::seek(uint32_t pos, int mode)
{
if (_file == nullptr) return false;
return _file->seekSet(pos);
}

uint32_t File::position() {
if (! _file) return -1;
return _file->curPosition();
uint32_t SD_File::position() const
{
if (_file == nullptr) return 0;
return _file->curPosition();
}

uint32_t File::size() {
if (! _file) return 0;
return _file->fileSize();
uint32_t SD_File::size() const
{
if (_file == nullptr) return 0;
return _file->fileSize();
}

void File::close() {
if (_file) {
_file->close();
free(_file);
_file = 0;

/* for debugging file open/close leaks
nfilecount--;
Serial.print("Deleted ");
Serial.println(nfilecount, DEC);
*/
}
void SD_File::close()
{
if (_file == nullptr) return;
_file->close();
//delete _file; // TODO: how to handle this?
_file = nullptr;
}

File::operator bool() {
if (_file)
return _file->isOpen();
return false;
SD_File::operator bool() const
{
if (_file == nullptr) return false;
return _file->isOpen();
}
#endif

+ 107
- 73
SD.cpp 查看文件

@@ -1,3 +1,13 @@
#include <Arduino.h>
#include "SD.h"

#include <utility/SdFat.h>
#include <utility/SdFatUtil.h>




#if 1
/*

SD - a slightly more friendly wrapper for sdfatlib
@@ -17,11 +27,11 @@
`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
* 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
* 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
@@ -37,7 +47,7 @@

Implementation Notes

In order to handle multi-directory path traversal, functionality that
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
@@ -93,7 +103,7 @@ bool getNextPathComponent(const char *path, unsigned int *p_offset,
if (path[offset] == '/') {
offset++;
}
// Copy the next next path segment
while (bufferOffset < MAX_COMPONENT_LEN
&& (path[offset] != '/')
@@ -116,14 +126,14 @@ bool getNextPathComponent(const char *path, unsigned int *p_offset,



boolean walkPath(const char *filepath, SdFile& parentDir,
boolean (*callback)(SdFile& parentDir,
bool walkPath(const char *filepath, SdFile *parentDir,
bool (*callback)(SdFile *parentDir,
char *filePathComponent,
boolean isLastComponent,
bool 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
@@ -154,52 +164,52 @@ boolean walkPath(const char *filepath, SdFile& parentDir,
SdFile subfile1;
SdFile subfile2;

char buffer[PATH_COMPONENT_BUFFER_LEN];
char buffer[PATH_COMPONENT_BUFFER_LEN];

unsigned int offset = 0;

SdFile *p_parent;
SdFile *p_child;

SdFile *p_tmp_sdfile;
SdFile *p_tmp_sdfile;
p_child = &subfile1;
p_parent = &parentDir;
p_parent = parentDir;

while (true) {

boolean moreComponents = getNextPathComponent(filepath, &offset, buffer);
bool moreComponents = getNextPathComponent(filepath, &offset, buffer);

boolean shouldContinue = callback((*p_parent), buffer, !moreComponents, object);
bool 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) {
if (p_parent != parentDir) {
(*p_parent).close();
}
return false;
}
if (!moreComponents) {
break;
}
boolean exists = (*p_child).open(*p_parent, buffer, O_RDONLY);
bool 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) {
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) {
if (p_parent == parentDir) {
p_parent = &subfile2;
}

@@ -210,8 +220,8 @@ boolean walkPath(const char *filepath, SdFile& parentDir,
return false;
}
}
if (p_parent != &parentDir) {
if (p_parent != parentDir) {
(*p_parent).close(); // TODO: Return/ handle different?
}

@@ -231,8 +241,8 @@ boolean walkPath(const char *filepath, SdFile& parentDir,

*/

boolean callback_pathExists(SdFile& parentDir, char *filePathComponent,
boolean isLastComponent, void *object) {
bool callback_pathExists(SdFile *parentDir, char *filePathComponent,
bool isLastComponent, void *object) {
/*

Callback used to determine if a file/directory exists in parent
@@ -243,19 +253,19 @@ boolean callback_pathExists(SdFile& parentDir, char *filePathComponent,
*/
SdFile child;

boolean exists = child.open(parentDir, filePathComponent, O_RDONLY);
bool exists = child.open(parentDir, filePathComponent, O_RDONLY);
if (exists) {
child.close();
child.close();
}
return exists;
}



boolean callback_makeDirPath(SdFile& parentDir, char *filePathComponent,
boolean isLastComponent, void *object) {
bool callback_makeDirPath(SdFile *parentDir, char *filePathComponent,
bool isLastComponent, void *object) {
/*

Callback used to create a directory in the parent directory if
@@ -264,22 +274,22 @@ boolean callback_makeDirPath(SdFile& parentDir, char *filePathComponent,
Returns true if a directory was created or it already existed.

*/
boolean result = false;
bool 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) {
bool callback_openPath(SdFile *parentDir, char *filePathComponent,
bool isLastComponent, void *object) {

Callback used to open a file specified by a filepath that may
specify one or more directories above it.
@@ -309,16 +319,16 @@ boolean callback_openPath(SdFile& parentDir, char *filePathComponent,



boolean callback_remove(SdFile& parentDir, char *filePathComponent,
boolean isLastComponent, void *object) {
bool callback_remove(SdFile *parentDir, char *filePathComponent,
bool isLastComponent, void *object) {
if (isLastComponent) {
return SdFile::remove(parentDir, filePathComponent);
}
return true;
}

boolean callback_rmdir(SdFile& parentDir, char *filePathComponent,
boolean isLastComponent, void *object) {
bool callback_rmdir(SdFile *parentDir, char *filePathComponent,
bool isLastComponent, void *object) {
if (isLastComponent) {
SdFile f;
if (!f.open(parentDir, filePathComponent, O_READ)) return false;
@@ -333,7 +343,7 @@ boolean callback_rmdir(SdFile& parentDir, char *filePathComponent,



boolean SDClass::begin(uint8_t csPin) {
bool SDClass::begin(uint8_t csPin) {
/*

Performs the initialisation required by the sdfatlib library.
@@ -341,12 +351,16 @@ boolean SDClass::begin(uint8_t csPin) {
Return true if initialization succeeds, false otherwise.

*/
card = new Sd2Card();
volume = new SdVolume();
root = new SdFile();


if (root.isOpen()) root.close();
if (root->isOpen()) root->close();

return card.init(SPI_HALF_SPEED, csPin) &&
volume.init(card) &&
root.openRoot(volume);
return card->init(SPI_HALF_SPEED, csPin) &&
volume->init(card) &&
root->openRoot(volume);
}


@@ -362,7 +376,7 @@ SdFile SDClass::getParentDir(const char *filepath, int *index) {
// we'll use the pointers to swap between the two objects
SdFile *parent = &d1;
SdFile *subdir = &d2;
const char *origpath = filepath;

while (strchr(filepath, '/')) {
@@ -372,7 +386,7 @@ SdFile SDClass::getParentDir(const char *filepath, int *index) {
filepath++;
continue;
}
if (! strchr(filepath, '/')) {
// it was in the root directory, so leave now
break;
@@ -443,26 +457,44 @@ File SDClass::open(const char *filepath, uint8_t mode) {
filepath += pathidx;

if (! filepath[0]) {
// it was the directory itself!
return File(parentdir, "/");
}
// it was the directory itself!
Serial.println("it was the directory itself");

// Open the file itself
SdFile file;
File ret = File(new SD_File(parentdir, "/"));
ret.whoami();
return ret;
}

// failed to open a subdir!
if (!parentdir.isOpen())
return File();
if (!parentdir.isOpen()) {
return File();
}

// convert mode to underlying SdFat
if (mode == FILE_READ) {
mode = O_READ;
} else { // FILE_WRITE
mode = O_READ | O_WRITE | O_CREAT;
}

// Open the file itself
SdFile file;
if ( ! file.open(parentdir, filepath, mode)) {
return File();
return File();
}
// close the parent
parentdir.close();

if (mode & (O_APPEND | O_WRITE))
file.seekSet(file.fileSize());
return File(file, filepath);
if (mode & (O_APPEND | O_WRITE)) {
file.seekSet(file.fileSize());
}

File ret = File(new SD_File(file, filepath));

Serial.println("open() return:");
ret.whoami();
return ret;
//return SD_File(file, filepath);
}


@@ -502,7 +534,7 @@ File SDClass::open(char *filepath, uint8_t mode) {
*/


//boolean SDClass::close() {
//bool SDClass::close() {
// /*
//
// Closes the file opened by the `open` method.
@@ -512,7 +544,7 @@ File SDClass::open(char *filepath, uint8_t mode) {
//}


boolean SDClass::exists(const char *filepath) {
bool SDClass::exists(const char *filepath) {
/*

Returns true if the supplied file path exists.
@@ -522,7 +554,7 @@ boolean SDClass::exists(const char *filepath) {
}


//boolean SDClass::exists(char *filepath, SdFile& parentDir) {
//bool SDClass::exists(char *filepath, SdFile& parentDir) {
// /*
//
// Returns true if the supplied file path rooted at `parentDir`
@@ -533,35 +565,36 @@ boolean SDClass::exists(const char *filepath) {
//}


boolean SDClass::mkdir(const char *filepath) {
bool SDClass::mkdir(const 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(const char *filepath) {
bool SDClass::rmdir(const 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(const char *filepath) {
bool SDClass::remove(const char *filepath) {
return walkPath(filepath, root, callback_remove);
}


// allows you to recurse into a directory
File File::openNextFile(uint8_t mode) {
File SD_File::openNextFile(uint8_t mode)
{
dir_t p;

//Serial.print("\t\treading dir...");
@@ -594,7 +627,7 @@ File File::openNextFile(uint8_t mode) {

if (f.open(_file, name, mode)) {
//Serial.println("OK!");
return File(f, name);
return File(new SD_File(f, name));
} else {
//Serial.println("ugh");
return File();
@@ -605,10 +638,11 @@ File File::openNextFile(uint8_t mode) {
return File();
}

void File::rewindDirectory(void) {
void SD_File::rewindDirectory(void) {
if (isDirectory())
_file->rewind();
}

SDClass SD;
#endif
#endif

+ 35
- 53
SD.h 查看文件

@@ -1,75 +1,57 @@
#if defined(__arm__)
#include "SD_t3.h"
#endif
/*

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 <Arduino.h>
#include <FS.h>

#include <utility/SdFat.h>
#include <utility/SdFatUtil.h>

#define FILE_READ O_READ
#define FILE_WRITE (O_READ | O_WRITE | O_CREAT)

class File : public Stream {
private:
char _name[13]; // our name
SdFile *_file; // underlying file pointer
class Sd2Card;
class SdVolume;
class SdFile;

class SD_File : public File {
public:
File(SdFile f, const char *name); // wraps an underlying SdFile
File(void); // 'empty' constructor
~File(void); // destructor
SD_File(const SdFile &f, const char *name);
SD_File(void);
virtual ~SD_File(void);
virtual size_t write(uint8_t);
virtual size_t write(const uint8_t *buf, size_t size);
virtual size_t write(const void *buf, size_t size);
virtual int read();
virtual int peek();
virtual int available();
virtual void flush();
int read(void *buf, uint16_t nbyte);
boolean seek(uint32_t pos);
uint32_t position();
uint32_t size();
void close();
operator bool();
char * name();

boolean isDirectory(void);
File openNextFile(uint8_t mode = O_RDONLY);
void rewindDirectory(void);
virtual size_t read(void *buf, size_t nbyte);
virtual bool seek(uint32_t pos, int mode = 0);
virtual uint32_t position() const;
virtual uint32_t size() const;
virtual void close();
virtual operator bool() const;
virtual const char * name();
virtual boolean isDirectory(void);
virtual File openNextFile(uint8_t mode = 0 /*O_RDONLY*/) override;
virtual void rewindDirectory(void);
virtual void whoami();
using Print::write;
private:
char _name[13]; // our name
SdFile *_file; // underlying file pointer
};

class SDClass {


class SDClass : public FS {

private:
// These are required for initialisation and use of sdfatlib
Sd2Card card;
SdVolume volume;
SdFile root;
Sd2Card *card;
SdVolume *volume;
SdFile *root;
// my quick&dirty iterator, should be replaced
SdFile getParentDir(const char *filepath, int *indx);
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);
bool begin(uint8_t csPin = 10 /*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.
@@ -77,16 +59,16 @@ public:
File open(const char *filename, uint8_t mode = FILE_READ);

// Methods to determine if the requested file path exists.
boolean exists(const char *filepath);
bool exists(const char *filepath);

// Create the requested directory heirarchy--if intermediate directories
// do not exist they will be created.
boolean mkdir(const char *filepath);
bool mkdir(const char *filepath);
// Delete the file.
boolean remove(const char *filepath);
bool remove(const char *filepath);
boolean rmdir(const char *filepath);
bool rmdir(const char *filepath);

private:

@@ -97,7 +79,7 @@ private:
// It shouldn't be set directly--it is set via the parameters to `open`.
int fileOpenMode;
friend class File;
friend class SD_File;
friend boolean callback_openPath(SdFile&, char *, boolean, void *);
};


Loading…
取消
儲存