Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/Duet3D/RepRapFirmware.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Crocker <dcrocker@eschertech.com>2018-03-24 18:26:14 +0300
committerDavid Crocker <dcrocker@eschertech.com>2018-03-24 18:26:14 +0300
commit8713f3b323ea9fece4bd58b3578c3ff66fb79888 (patch)
tree127f53b1638c093bc01a6aa9d009b4f715f49f92 /src/Storage
parent6e147c74951bacbce5ffb73d301a6beeed4a9596 (diff)
parenta9767cc77a03a5564faf935f7ca6e6790a8aa744 (diff)
Merged changes from dev branch as at version 1.21
Diffstat (limited to 'src/Storage')
-rw-r--r--src/Storage/CRC32.cpp74
-rw-r--r--src/Storage/CRC32.h27
-rw-r--r--src/Storage/FileData.h31
-rw-r--r--src/Storage/FileStore.cpp208
-rw-r--r--src/Storage/FileStore.h46
-rw-r--r--src/Storage/FileWriteBuffer.h55
-rw-r--r--src/Storage/MassStorage.h67
7 files changed, 406 insertions, 102 deletions
diff --git a/src/Storage/CRC32.cpp b/src/Storage/CRC32.cpp
new file mode 100644
index 00000000..88142ac9
--- /dev/null
+++ b/src/Storage/CRC32.cpp
@@ -0,0 +1,74 @@
+#include "CRC32.h"
+
+const uint32_t CRC32::CRC_32_TAB[256] = {
+ /*
+ CRC polynomial 0xedb88320
+ This table can also be generated in runtime
+ */
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
+ 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
+ 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
+ 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
+ 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
+ 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
+ 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
+ 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
+ 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
+ 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
+ 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
+ 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
+ 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
+ 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
+ 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
+ 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
+ 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
+ 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+};
+
+CRC32::CRC32()
+{
+ Reset();
+}
+
+void CRC32::Update(char c)
+{
+ crc = (CRC_32_TAB[(crc ^ c) & 0xFF] ^ (crc >> 8));
+}
+
+void CRC32::Update(const char *c, size_t len)
+{
+ for (size_t i = 0; i < len; ++i)
+ {
+ Update(c[i]);
+ }
+}
+
+void CRC32::Reset()
+{
+ crc = 0xffffffff;
+} \ No newline at end of file
diff --git a/src/Storage/CRC32.h b/src/Storage/CRC32.h
new file mode 100644
index 00000000..06bcfe13
--- /dev/null
+++ b/src/Storage/CRC32.h
@@ -0,0 +1,27 @@
+#ifndef CRC32_H
+#define CRC32_H
+
+#include <cstdint> // for uint32_t
+#include <cstddef> // for size_t
+
+class CRC32
+{
+private:
+ static const uint32_t CRC_32_TAB[];
+ uint32_t crc;
+
+public:
+ CRC32();
+ void Update(char c);
+ void Update(const char *c, size_t len);
+ void Reset();
+ uint32_t Get() const;
+
+};
+
+inline uint32_t CRC32::Get() const
+{
+ return ~crc;
+}
+
+#endif \ No newline at end of file
diff --git a/src/Storage/FileData.h b/src/Storage/FileData.h
index 00c7e47f..683b4165 100644
--- a/src/Storage/FileData.h
+++ b/src/Storage/FileData.h
@@ -19,7 +19,7 @@ class FileData
public:
friend class FileGCodeInput;
- FileData() : f(NULL) {}
+ FileData() : f(nullptr) {}
// Set this to refer to a newly-opened file
void Set(FileStore* pfile)
@@ -28,14 +28,14 @@ public:
f = pfile;
}
- bool IsLive() const { return f != NULL; }
+ bool IsLive() const { return f != nullptr; }
bool Close()
{
- if (f != NULL)
+ if (f != nullptr)
{
bool ok = f->Close();
- f = NULL;
+ f = nullptr;
return ok;
}
return false;
@@ -46,7 +46,7 @@ public:
return f->Read(b);
}
- int Read(char* buf, size_t nBytes)
+ int Read(char *buf, size_t nBytes)
{
return f->Read(buf, nBytes);
}
@@ -56,7 +56,17 @@ public:
return f->Write(b);
}
- bool Write(const char *s, unsigned int len)
+ bool Write(const char *s)
+ {
+ return f->Write(s, strlen(s));
+ }
+
+ bool Write(const char *s, size_t len)
+ {
+ return f->Write(s, len);
+ }
+
+ bool Write(const uint8_t *s, size_t len)
{
return f->Write(s, len);
}
@@ -76,11 +86,6 @@ public:
return f->Seek(position);
}
- float FractionRead() const
- {
- return (f == NULL ? -1.0 : f->FractionRead());
- }
-
FilePosition Length() const
{
return f->Length();
@@ -91,7 +96,7 @@ public:
{
Close();
f = other.f;
- if (f != NULL)
+ if (f != nullptr)
{
f->Duplicate();
}
@@ -110,7 +115,7 @@ private:
void Init()
{
- f = NULL;
+ f = nullptr;
}
// Private assignment operator to prevent us assigning these objects
diff --git a/src/Storage/FileStore.cpp b/src/Storage/FileStore.cpp
index d650da2d..86c24893 100644
--- a/src/Storage/FileStore.cpp
+++ b/src/Storage/FileStore.cpp
@@ -8,8 +8,9 @@
uint32_t FileStore::longestWriteTime = 0;
-FileStore::FileStore(Platform* p) : platform(p)
+FileStore::FileStore() : writeBuffer(nullptr)
{
+ Init();
}
void FileStore::Init()
@@ -21,13 +22,27 @@ void FileStore::Init()
}
// Invalidate the file if it uses the specified FATFS object
-void FileStore::Invalidate(const FATFS *fs)
+bool FileStore::Invalidate(const FATFS *fs, bool doClose)
{
if (file.fs == fs)
{
- Init();
- file.fs = nullptr;
+ if (doClose)
+ {
+ (void)ForceClose();
+ }
+ else
+ {
+ file.fs = nullptr;
+ if (writeBuffer != nullptr)
+ {
+ reprap.GetPlatform().GetMassStorage()->ReleaseWriteBuffer(writeBuffer);
+ writeBuffer = nullptr;
+ }
+ Init();
+ }
+ return true;
}
+ return false;
}
// Return true if the file is open on the specified file system
@@ -38,55 +53,62 @@ bool FileStore::IsOpenOn(const FATFS *fs) const
// Open a local file (for example on an SD card).
// This is protected - only Platform can access it.
-bool FileStore::Open(const char* directory, const char* fileName, bool write)
+bool FileStore::Open(const char* directory, const char* fileName, OpenMode mode)
{
- const char* location = (directory != nullptr)
- ? platform->GetMassStorage()->CombineName(directory, fileName)
- : fileName;
- writing = write;
+ const char* const location = (directory != nullptr)
+ ? reprap.GetPlatform().GetMassStorage()->CombineName(directory, fileName)
+ : fileName;
+ writing = (mode == OpenMode::write || mode == OpenMode::append);
- // Try to create the path of this file if we want to write to it
if (writing)
{
- char filePathBuffer[FILENAME_LENGTH];
- StringRef filePath(filePathBuffer, FILENAME_LENGTH);
+ // Try to create the path of this file if we want to write to it
+ String<MaxFilenameLength> filePath;
filePath.copy(location);
- bool isVolume = isdigit(filePath[0]);
- for(size_t i = 1; i < filePath.strlen(); i++)
+ size_t i = (isdigit(filePath[0]) && filePath[1] == ':') ? 2 : 0;
+ if (filePath[i] == '/')
+ {
+ ++i;
+ }
+
+ while (i < filePath.strlen())
{
if (filePath[i] == '/')
{
- if (isVolume)
- {
- isVolume = false;
- continue;
- }
-
filePath[i] = 0;
- if (!platform->GetMassStorage()->DirectoryExists(filePath.Pointer()) && !platform->GetMassStorage()->MakeDirectory(filePath.Pointer()))
+ if (!reprap.GetPlatform().GetMassStorage()->DirectoryExists(filePath.Pointer()) && !reprap.GetPlatform().GetMassStorage()->MakeDirectory(filePath.Pointer()))
{
- platform->MessageF(GENERIC_MESSAGE, "Failed to create directory %s while trying to open file %s\n",
- filePath.Pointer(), location);
+ reprap.GetPlatform().MessageF(ErrorMessage, "Failed to create directory %s while trying to open file %s\n", filePath.Pointer(), location);
return false;
}
filePath[i] = '/';
}
+ ++i;
}
+
+ // Also try to allocate a write buffer so we can perform faster writes
+ // We only do this if the mode is write, not append, because we don't want to use up a large buffer to append messages to the log file,
+ // especially as we need to flush messages to SD card regularly.
+ // Currently, append mode is used only for the log file.
+ writeBuffer = (mode == OpenMode::write) ? reprap.GetPlatform().GetMassStorage()->AllocateWriteBuffer() : nullptr;
}
- FRESULT openReturn = f_open(&file, location, (writing) ? FA_CREATE_ALWAYS | FA_WRITE : FA_OPEN_EXISTING | FA_READ);
+ const FRESULT openReturn = f_open(&file, location,
+ (mode == OpenMode::write) ? FA_CREATE_ALWAYS | FA_WRITE
+ : (mode == OpenMode::append) ? FA_WRITE | FA_OPEN_ALWAYS
+ : FA_OPEN_EXISTING | FA_READ);
if (openReturn != FR_OK)
{
// We no longer report an error if opening a file in read mode fails unless debugging is enabled, because sometimes that is quite normal.
// It is up to the caller to report an error if necessary.
if (reprap.Debug(modulePlatform))
{
- platform->MessageF(GENERIC_MESSAGE, "Can't open %s to %s, error code %d\n", location, (writing) ? "write" : "read", openReturn);
+ reprap.GetPlatform().MessageF(ErrorMessage, "Can't open %s to %s, error code %d\n", location, (writing) ? "write" : "read", openReturn);
}
return false;
}
-
+ crc.Reset();
inUse = true;
openCount = 1;
return true;
@@ -96,12 +118,14 @@ void FileStore::Duplicate()
{
if (!inUse)
{
- platform->Message(GENERIC_MESSAGE, "Error: Attempt to dup a non-open file.\n");
- return;
+ reprap.GetPlatform().Message(ErrorMessage, "Attempt to dup a non-open file.\n");
+ }
+ else
+ {
+ irqflags_t flags = cpu_irq_save();
+ ++openCount;
+ cpu_irq_restore(flags);
}
- irqflags_t flags = cpu_irq_save();
- ++openCount;
- cpu_irq_restore(flags);
}
// This may be called from an ISR, in which case we need to defer the close
@@ -114,7 +138,7 @@ bool FileStore::Close()
return false;
}
- irqflags_t flags = cpu_irq_save();
+ const irqflags_t flags = cpu_irq_save();
if (openCount > 1)
{
--openCount;
@@ -129,11 +153,11 @@ bool FileStore::Close()
if (!inUse)
{
- platform->Message(GENERIC_MESSAGE, "Error: Attempt to close a non-open file.\n");
+ reprap.GetPlatform().Message(ErrorMessage, "Attempt to close a non-open file.\n");
return false;
}
- irqflags_t flags = cpu_irq_save();
+ const irqflags_t flags = cpu_irq_save();
--openCount;
bool leaveOpen = (openCount != 0);
cpu_irq_restore(flags);
@@ -143,16 +167,28 @@ bool FileStore::Close()
return true;
}
+ return ForceClose();
+}
+
+bool FileStore::ForceClose()
+{
bool ok = true;
if (writing)
{
ok = Flush();
}
- FRESULT fr = f_close(&file);
+ if (writeBuffer != nullptr)
+ {
+ reprap.GetPlatform().GetMassStorage()->ReleaseWriteBuffer(writeBuffer);
+ writeBuffer = nullptr;
+ }
+
+ const FRESULT fr = f_close(&file);
inUse = false;
writing = false;
closeRequested = false;
+ openCount = 0;
return ok && fr == FR_OK;
}
@@ -160,7 +196,7 @@ bool FileStore::Seek(FilePosition pos)
{
if (!inUse)
{
- platform->Message(GENERIC_MESSAGE, "Error: Attempt to seek on a non-open file.\n");
+ reprap.GetPlatform().Message(ErrorMessage, "Attempt to seek on a non-open file.\n");
return false;
}
FRESULT fr = f_lseek(&file, pos);
@@ -169,7 +205,12 @@ bool FileStore::Seek(FilePosition pos)
FilePosition FileStore::Position() const
{
- return file.fptr;
+ return (inUse) ? file.fptr : 0;
+}
+
+uint32_t FileStore::ClusterSize() const
+{
+ return (inUse) ? file.fs->csize * 512u : 1; // we divide by the cluster size so return 1 not 0 if there is an error
}
#if 0 // not currently used
@@ -183,21 +224,11 @@ FilePosition FileStore::Length() const
{
if (!inUse)
{
- platform->Message(GENERIC_MESSAGE, "Error: Attempt to size non-open file.\n");
+ reprap.GetPlatform().Message(ErrorMessage, "Attempt to size non-open file.\n");
return 0;
}
- return file.fsize;
-}
-
-float FileStore::FractionRead() const
-{
- FilePosition len = Length();
- if (len == 0)
- {
- return 0.0;
- }
- return (float)Position() / (float)len;
+ return (writeBuffer != nullptr) ? file.fsize + writeBuffer->BytesStored() : file.fsize;
}
// Single character read
@@ -211,7 +242,7 @@ int FileStore::Read(char* extBuf, size_t nBytes)
{
if (!inUse)
{
- platform->Message(GENERIC_MESSAGE, "Error: Attempt to read from a non-open file.\n");
+ reprap.GetPlatform().Message(ErrorMessage, "Attempt to read from a non-open file.\n");
return -1;
}
@@ -219,7 +250,7 @@ int FileStore::Read(char* extBuf, size_t nBytes)
FRESULT readStatus = f_read(&file, extBuf, nBytes, &bytes_read);
if (readStatus != FR_OK)
{
- platform->Message(GENERIC_MESSAGE, "Error: Cannot read file.\n");
+ reprap.GetPlatform().Message(ErrorMessage, "Cannot read file.\n");
return -1;
}
return (int)bytes_read;
@@ -259,6 +290,19 @@ int FileStore::ReadLine(char* buf, size_t nBytes)
return i;
}
+FRESULT FileStore::Store(const char *s, size_t len, size_t *bytesWritten)
+{
+ uint32_t time = micros();
+ crc.Update(s, len);
+ FRESULT writeStatus = f_write(&file, s, len, bytesWritten);
+ time = micros() - time;
+ if (time > longestWriteTime)
+ {
+ longestWriteTime = time;
+ }
+ return writeStatus;
+}
+
bool FileStore::Write(char b)
{
return Write(&b, sizeof(char));
@@ -273,22 +317,42 @@ bool FileStore::Write(const char *s, size_t len)
{
if (!inUse)
{
- platform->Message(GENERIC_MESSAGE, "Error: Attempt to write block to a non-open file.\n");
+ reprap.GetPlatform().Message(ErrorMessage, "Attempt to write block to a non-open file.\n");
return false;
}
- size_t bytesWritten;
- uint32_t time = micros();
-
- FRESULT writeStatus = f_write(&file, s, len, &bytesWritten);
- time = micros() - time;
- if (time > longestWriteTime)
+ size_t totalBytesWritten = 0;
+ FRESULT writeStatus = FR_OK;
+ if (writeBuffer == nullptr)
{
- longestWriteTime = time;
+ writeStatus = Store(s, len, &totalBytesWritten);
}
- if ((writeStatus != FR_OK) || (bytesWritten != len))
+ else
{
- platform->Message(GENERIC_MESSAGE, "Error: Cannot write to file. Drive may be full.\n");
+ do
+ {
+ size_t bytesStored = writeBuffer->Store(s + totalBytesWritten, len - totalBytesWritten);
+ if (writeBuffer->BytesLeft() == 0)
+ {
+ const size_t bytesToWrite = writeBuffer->BytesStored();
+ size_t bytesWritten;
+ writeStatus = Store(writeBuffer->Data(), bytesToWrite, &bytesWritten);
+ writeBuffer->DataTaken();
+
+ if (bytesToWrite != bytesWritten)
+ {
+ // Something went wrong
+ break;
+ }
+ }
+ totalBytesWritten += bytesStored;
+ }
+ while (writeStatus == FR_OK && totalBytesWritten != len);
+ }
+
+ if ((writeStatus != FR_OK) || (totalBytesWritten != len))
+ {
+ reprap.GetPlatform().Message(ErrorMessage, "Failed to write to file. Drive may be full.\n");
return false;
}
return true;
@@ -298,9 +362,27 @@ bool FileStore::Flush()
{
if (!inUse)
{
- platform->Message(GENERIC_MESSAGE, "Error: Attempt to flush a non-open file.\n");
+ reprap.GetPlatform().Message(ErrorMessage, "Attempt to flush a non-open file.\n");
return false;
}
+
+ if (writeBuffer != nullptr)
+ {
+ const size_t bytesToWrite = writeBuffer->BytesStored();
+ if (bytesToWrite != 0)
+ {
+ size_t bytesWritten;
+ const FRESULT writeStatus = Store(writeBuffer->Data(), bytesToWrite, &bytesWritten);
+ writeBuffer->DataTaken();
+
+ if ((writeStatus != FR_OK) || (bytesToWrite != bytesWritten))
+ {
+ reprap.GetPlatform().Message(ErrorMessage, "Failed to write to file. Drive may be full.\n");
+ return false;
+ }
+ }
+ }
+
return f_sync(&file) == FR_OK;
}
@@ -319,7 +401,7 @@ bool FileStore::SetClusterMap(uint32_t tbl[])
{
if (!inUse)
{
- platform->Message(GENERIC_MESSAGE, "Error: Attempt to set cluster map for a non-open file.\n");
+ platform->Message(ErrorMessage, "attempt to set cluster map for a non-open file.\n");
return false;
}
diff --git a/src/Storage/FileStore.h b/src/Storage/FileStore.h
index 364bdc8f..5651b0bd 100644
--- a/src/Storage/FileStore.h
+++ b/src/Storage/FileStore.h
@@ -5,57 +5,75 @@
#include "Core.h"
#include "Libraries/Fatfs/ff.h"
-
-const size_t FileBufLen = 256; // 512 would be more efficient, but need to free up some RAM first
+#include "CRC32.h"
class Platform;
+class FileWriteBuffer;
+
+enum class OpenMode : uint8_t
+{
+ read, // open an existing file for reading
+ write, // write a file, replacing any existing file of the same name
+ append // append to an existing file, or create a new file if it is not found
+};
class FileStore
{
public:
+ FileStore();
+
+ bool Open(const char* directory, const char* fileName, OpenMode mode);
bool Read(char& b); // Read 1 byte
int Read(char* buf, size_t nBytes); // Read a block of nBytes length
int ReadLine(char* buf, size_t nBytes); // As Read but stop after '\n' or '\r\n' and null-terminate
bool Write(char b); // Write 1 byte
bool Write(const char *s, size_t len); // Write a block of len bytes
+ bool Write(const uint8_t *s, size_t len); // Write a block of len bytes
bool Write(const char* s); // Write a string
bool Close(); // Shut the file and tidy up
+ bool ForceClose();
bool Seek(FilePosition pos); // Jump to pos in the file
FilePosition Position() const; // Return the current position in the file, assuming we are reading the file
+ uint32_t ClusterSize() const; // Cluster size in bytes
+ FilePosition Length() const; // File size in bytes
#if 0 // not currently used
bool GoToEnd(); // Position the file at the end (so you can write on the end).
#endif
- FilePosition Length() const; // File size in bytes
- float FractionRead() const; // How far in we are
+
void Duplicate(); // Create a second reference to this file
bool Flush(); // Write remaining buffer data
- void Invalidate(const FATFS *fs); // Invalidate the file if it uses the specified FATFS object
+ bool Invalidate(const FATFS *fs, bool doClose); // Invalidate the file if it uses the specified FATFS object
bool IsOpenOn(const FATFS *fs) const; // Return true if the file is open on the specified file system
+ uint32_t GetCRC32() const;
#if 0 // not currently used
bool SetClusterMap(uint32_t[]); // Provide a cluster map for fast seeking
#endif
static float GetAndClearLongestWriteTime(); // Return the longest time it took to write a block to a file, in milliseconds
- friend class Platform;
-
-protected:
-
- FileStore(Platform* p);
- void Init();
- bool Open(const char* directory, const char* fileName, bool write);
+ friend class MassStorage;
private:
- Platform* platform;
+ void Init();
+ FRESULT Store(const char *s, size_t len, size_t *bytesWritten); // Write data to the non-volatile storage
- FIL file;
+ FIL file;
+ FileWriteBuffer *writeBuffer;
volatile unsigned int openCount;
volatile bool closeRequested;
bool inUse;
bool writing;
+ CRC32 crc;
static uint32_t longestWriteTime;
};
+inline bool FileStore::Write(const uint8_t *s, size_t len) { return Write(reinterpret_cast<const char *>(s), len); }
+
+inline uint32_t FileStore::GetCRC32() const
+{
+ return crc.Get();
+}
+
#endif
diff --git a/src/Storage/FileWriteBuffer.h b/src/Storage/FileWriteBuffer.h
new file mode 100644
index 00000000..d5198e8c
--- /dev/null
+++ b/src/Storage/FileWriteBuffer.h
@@ -0,0 +1,55 @@
+/*
+ * FileWriteBuffer.h
+ *
+ * Created on: 19 May 2017
+ * Author: Christian
+ */
+
+#ifndef SRC_STORAGE_FILEWRITEBUFFER_H_
+#define SRC_STORAGE_FILEWRITEBUFFER_H_
+
+#include "RepRapFirmware.h"
+
+#if SAM4E || SAM4S || SAME70
+const size_t NumFileWriteBuffers = 2; // Number of write buffers
+const size_t FileWriteBufLen = 8192; // Size of each write buffer
+#else
+const size_t NumFileWriteBuffers = 1;
+const size_t FileWriteBufLen = 4096;
+#endif
+
+// Class to cache data that is about to be written to the SD card. This is NOT a ring buffer,
+// instead it just provides simple interfaces to cache a certain amount of data so that fewer
+// f_write() calls are needed. This effectively improves upload speeds.
+class FileWriteBuffer
+{
+public:
+ FileWriteBuffer(FileWriteBuffer *n) : next(n), index(0) { }
+
+ FileWriteBuffer *Next() const { return next; }
+ void SetNext(FileWriteBuffer *n) { next = n; }
+
+ char *Data() { return reinterpret_cast<char *>(data32); }
+ const char *Data() const { return reinterpret_cast<const char *>(data32); }
+ const size_t BytesStored() const { return index; }
+ const size_t BytesLeft() const { return FileWriteBufLen - index; }
+
+ size_t Store(const char *data, size_t length); // Stores some data and returns how much could be stored
+ void DataTaken() { index = 0; } // Called to indicate that the buffer has been written
+
+private:
+ FileWriteBuffer *next;
+
+ size_t index;
+ uint32_t data32[FileWriteBufLen / sizeof(uint32_t)]; // 32-bit aligned buffer for better HSMCI performance
+};
+
+inline size_t FileWriteBuffer::Store(const char *data, size_t length)
+{
+ size_t bytesToStore = min<size_t>(BytesLeft(), length);
+ memcpy(Data() + index, data, bytesToStore);
+ index += bytesToStore;
+ return bytesToStore;
+}
+
+#endif
diff --git a/src/Storage/MassStorage.h b/src/Storage/MassStorage.h
index 25ed0aee..42302f74 100644
--- a/src/Storage/MassStorage.h
+++ b/src/Storage/MassStorage.h
@@ -3,27 +3,30 @@
#include "RepRapFirmware.h"
#include "Pins.h"
+#include "FileWriteBuffer.h"
#include "Libraries/Fatfs/ff.h"
+#include "GCodes/GCodeResult.h"
+#include "FileStore.h"
#include <ctime>
// Info returned by FindFirst/FindNext calls
struct FileInfo
{
bool isDirectory;
- char fileName[FILENAME_LENGTH];
- unsigned long size;
+ char fileName[MaxFilenameLength];
+ uint32_t size;
time_t lastModified;
};
class MassStorage
{
public:
-
+ FileStore* OpenFile(const char* directory, const char* fileName, OpenMode mode);
bool FindFirst(const char *directory, FileInfo &file_info);
bool FindNext(FileInfo &file_info);
const char* GetMonthName(const uint8_t month);
const char* CombineName(const char* directory, const char* fileName);
- bool Delete(const char* directory, const char* fileName);
+ bool Delete(const char* directory, const char* fileName, bool silent = false);
bool MakeDirectory(const char *parentDir, const char *dirName);
bool MakeDirectory(const char *directory);
bool Rename(const char *oldFilename, const char *newFilename);
@@ -33,26 +36,66 @@ public:
bool DirectoryExists(const char* directory, const char* subDirectory);
time_t GetLastModifiedTime(const char* directory, const char *fileName) const;
bool SetLastModifiedTime(const char* directory, const char *file, time_t time);
- bool Mount(size_t card, StringRef& reply, bool reportSuccess);
- bool Unmount(size_t card, StringRef& reply);
- bool IsDriveMounted(size_t drive) const { return drive < NumSdCards && isMounted[drive]; }
+ GCodeResult Mount(size_t card, const StringRef& reply, bool reportSuccess);
+ GCodeResult Unmount(size_t card, const StringRef& reply);
+ bool IsDriveMounted(size_t drive) const { return drive < NumSdCards && info[drive].isMounted; }
bool CheckDriveMounted(const char* path);
+ bool IsCardDetected(size_t card) const;
+ unsigned int InvalidateFiles(const FATFS *fs, bool doClose); // Invalidate all open files on the specified file system, returning the number of files invalidated
+ bool AnyFileOpen(const FATFS *fs) const; // Return true if any files are open on the file system
+ void CloseAllFiles();
+ unsigned int GetNumFreeFiles() const;
+ void Spin();
+
+ enum class InfoResult : uint8_t
+ {
+ badSlot = 0,
+ noCard = 1,
+ ok = 2
+ };
+
+ InfoResult GetCardInfo(size_t slot, uint64_t& capacity, uint64_t& freeSpace, uint32_t& speed, uint32_t& clSize);
friend class Platform;
+friend class FileStore;
protected:
-
MassStorage(Platform* p);
void Init();
+ FileWriteBuffer *AllocateWriteBuffer();
+ void ReleaseWriteBuffer(FileWriteBuffer *buffer);
+
private:
+ enum class CardDetectState : uint8_t
+ {
+ notPresent = 0,
+ inserting,
+ present,
+ removing
+ };
+
+ struct SdCardInfo
+ {
+ FATFS fileSystem;
+ uint32_t cdChangedTime;
+ uint32_t mountStartTime;
+ Pin cdPin;
+ bool mounting;
+ bool isMounted;
+ CardDetectState cardState;
+ };
+
+ bool InternalUnmount(size_t card, bool doClose);
static time_t ConvertTimeStamp(uint16_t fdate, uint16_t ftime);
- Platform* platform;
- FATFS fileSystems[NumSdCards];
+ SdCardInfo info[NumSdCards];
+
DIR findDir;
- bool isMounted[NumSdCards];
- char combinedName[FILENAME_LENGTH + 1];
+ char combinedName[MaxFilenameLength + 1];
+ FileWriteBuffer *freeWriteBuffers;
+
+ FileStore files[MAX_FILES];
};
#endif