Skip to content

Commit c5b3db5

Browse files
sticilfacehasenradball
authored andcommitted
Add FSTools with examples of how to convert between SPIFFS and LITTLEFS. (esp8266#7696)
* Add FSTools with examples of how to convert between SPIFFS and LITTLEFS. * Oops. Need to pass layout by reference in order to capture the correct address. Took a while to find that. There maybe a better way to store all these configs * Update FSTools.cpp fix ESP.h to Esp.h * Fix unused variable i * Parsed with restyle.sh. Compile with all errors. * remove unused variable * fix different sign complication error * Fix indentation to spaces Run test/restyle.sh Remove commented code Use #ifdef blocks for debugging. `DEBUG_ESP_CORE` and `DEBUG_ESP_PORT` use `static constexpr layout` which saves ROM ~500B for unused vars * Update FSTools.cpp Add yield in between file copy
1 parent e1146c3 commit c5b3db5

File tree

6 files changed

+623
-2
lines changed

6 files changed

+623
-2
lines changed

cores/esp8266/FS.h

+1-2
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,8 @@ class File : public Stream
9090
uint8_t obuf[256];
9191
size_t doneLen = 0;
9292
size_t sentLen;
93-
int i;
9493

95-
while (src.available() > sizeof(obuf)){
94+
while (src.available() > (int)sizeof(obuf)){
9695
src.read(obuf, sizeof(obuf));
9796
sentLen = write(obuf, sizeof(obuf));
9897
doneLen = doneLen + sentLen;

libraries/FSTools/FSTools.cpp

+254
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
#include "FSTools.h"
2+
#include "LittleFS.h"
3+
#include <spiffs_api.h>
4+
#include <Esp.h>
5+
6+
7+
8+
#if defined(DEBUG_ESP_CORE)
9+
#define FSTOOLSDEBUG(_1, ...) { DEBUG_ESP_PORT.printf_P( PSTR(_1),##__VA_ARGS__); }
10+
#else
11+
#define FSTOOLSDEBUG(...) {}
12+
#endif
13+
14+
15+
FSTools::FSTools()
16+
{
17+
18+
}
19+
20+
FSTools::~FSTools()
21+
{
22+
reset();
23+
}
24+
25+
26+
bool FSTools::attemptToMountFS(fs::FS & fs)
27+
{
28+
LittleFSConfig littleFSCfg(false);
29+
SPIFFSConfig SPIFFSCfg(false);
30+
// try to apply the "safe" no format config to the FS... doesn't matter which.. just need one to apply correctly..
31+
if (!fs.setConfig(littleFSCfg) && ! fs.setConfig(SPIFFSCfg))
32+
{
33+
return false;
34+
}
35+
return fs.begin();
36+
}
37+
38+
39+
bool FSTools::mountAlternativeFS(FST::FS_t type, const FST::layout & layout, bool keepMounted)
40+
{
41+
FSConfig * pCfg{nullptr};
42+
LittleFSConfig littleFSCfg(false);
43+
SPIFFSConfig SPIFFSCfg(false);
44+
reset();
45+
46+
switch (type)
47+
{
48+
case FST::SPIFFS :
49+
{
50+
_pFS.reset(new FS(FSImplPtr(new spiffs_impl::SPIFFSImpl(_getStartAddr(layout), _getSize(layout), layout.page, layout.block, 5))));
51+
pCfg = &SPIFFSCfg;
52+
break;
53+
}
54+
case FST::LITTLEFS :
55+
{
56+
_pFS.reset(new FS(FSImplPtr(new littlefs_impl::LittleFSImpl(_getStartAddr(layout), _getSize(layout), layout.page, layout.block, 5))));
57+
pCfg = &littleFSCfg;
58+
break;
59+
}
60+
};
61+
62+
if (_pFS && pCfg && _pFS->setConfig(*pCfg) && _pFS->begin())
63+
{
64+
if (!keepMounted)
65+
{
66+
_pFS->end();
67+
}
68+
_mounted = true;
69+
_layout = &layout;
70+
return true;
71+
}
72+
73+
if (_pFS)
74+
{
75+
_pFS.reset();
76+
}
77+
_mounted = false;
78+
return false;
79+
};
80+
81+
82+
bool FSTools::mounted()
83+
{
84+
return _mounted;
85+
};
86+
87+
88+
bool FSTools::moveFS(fs::FS & destinationFS)
89+
{
90+
uint32_t sourceFileCount = 0;
91+
uint32_t sourceByteTotal = 0;
92+
bool result = false;
93+
94+
if (!_mounted || !_pFS)
95+
{
96+
FSTOOLSDEBUG("Source FS not mounted\n");
97+
return false;
98+
}
99+
100+
uint32_t startSector = (ESP.getSketchSize() + FLASH_SECTOR_SIZE - 1) & (~(FLASH_SECTOR_SIZE - 1));
101+
uint32_t lowestFSStart = 0x40300000;
102+
103+
if (_layout)
104+
{
105+
lowestFSStart = _layout->startAddr;
106+
FSTOOLSDEBUG("_layout->startADDR = 0x%08x\n", _layout->startAddr);
107+
}
108+
109+
uint32_t endSector = lowestFSStart - 0x40200000;
110+
uint32_t tempFSsize = endSector - startSector;
111+
112+
FSTOOLSDEBUG("TempFS: start: %u, end: %u, size: %u, sketchSize = %u, _FS_start = %u\n", startSector, endSector, tempFSsize, ESP.getSketchSize(), (uint32_t)&_FS_start);
113+
114+
fileListIterator(*_pFS, "/", [&sourceFileCount, &sourceByteTotal, this](File & f)
115+
{
116+
if (f)
117+
{
118+
sourceFileCount++;
119+
sourceByteTotal += f.size();
120+
121+
#ifdef DEBUG_ESP_CORE
122+
_dumpFileInfo(f);
123+
#endif
124+
125+
}
126+
});
127+
128+
FSTOOLSDEBUG("%u Files Found Total Size = %u\n", sourceFileCount, sourceByteTotal);
129+
FSTOOLSDEBUG("Size of dummy FS = %u\n", tempFSsize);
130+
131+
FS tempFS = FS(FSImplPtr(new littlefs_impl::LittleFSImpl(startSector, tempFSsize, FS_PHYS_PAGE, FS_PHYS_BLOCK, 5)));
132+
133+
if (tempFS.format() && tempFS.begin())
134+
{
135+
if (_copyFS(*_pFS, tempFS))
136+
{
137+
FSTOOLSDEBUG("Files copied to temp File System\n");
138+
reset();
139+
if (destinationFS.format() && destinationFS.begin()) // must format then mount the new FS
140+
{
141+
if (_copyFS(tempFS, destinationFS))
142+
{
143+
FSTOOLSDEBUG("Files copied back to new FS\n");
144+
result = true;
145+
}
146+
}
147+
else
148+
{
149+
FSTOOLSDEBUG("Error Mounting\n");
150+
}
151+
}
152+
else
153+
{
154+
FSTOOLSDEBUG("Copy Failed\n");
155+
}
156+
tempFS.end();
157+
}
158+
else
159+
{
160+
FSTOOLSDEBUG("Failed to begin() TempFS\n");
161+
}
162+
return result;
163+
};
164+
165+
void FSTools::reset()
166+
{
167+
_mounted = false;
168+
_layout = nullptr;
169+
if (_pFS)
170+
{
171+
_pFS->end();
172+
_pFS.reset();
173+
}
174+
}
175+
176+
void FSTools::fileListIterator(FS & fs, const char * dirName, FST::FileCb Cb)
177+
{
178+
Dir dir = fs.openDir(dirName);
179+
while (dir.next())
180+
{
181+
if (dir.isFile())
182+
{
183+
File f = dir.openFile("r");
184+
if (Cb)
185+
{
186+
Cb(f);
187+
}
188+
}
189+
else
190+
{
191+
fileListIterator(fs, dir.fileName().c_str(), Cb);
192+
}
193+
}
194+
}
195+
196+
197+
uint32_t FSTools::_getStartAddr(const FST::layout & layout)
198+
{
199+
return (layout.startAddr - 0x40200000);
200+
}
201+
202+
uint32_t FSTools::_getSize(const FST::layout & layout)
203+
{
204+
return (layout.endAddr - layout.startAddr);
205+
}
206+
207+
#ifdef DEBUG_ESP_CORE
208+
void FSTools::_dumpFileInfo(File & f)
209+
{
210+
if (f)
211+
{
212+
DEBUG_ESP_PORT.printf_P(PSTR(" File: %-30s [%8uB]\n"), f.fullName(), f.size());
213+
}
214+
}
215+
#endif
216+
217+
bool FSTools::_copyFS(FS & sourceFS, FS & destFS)
218+
{
219+
uint32_t sourceFileCount = 0;
220+
uint32_t sourceByteTotal = 0;
221+
222+
fileListIterator(sourceFS, "/", [&sourceFileCount, &sourceByteTotal](File & f)
223+
{
224+
if (f)
225+
{
226+
sourceFileCount++;
227+
sourceByteTotal += f.size();
228+
}
229+
});
230+
231+
size_t count = 0;
232+
fileListIterator(sourceFS, "/", [&count, &destFS](File & sourceFile)
233+
{
234+
if (sourceFile)
235+
{
236+
File destFile = destFS.open(sourceFile.fullName(), "w");
237+
if (destFile)
238+
{
239+
destFile.setTimeout(5000); // this value was chosen empirically as it failed with default timeout.
240+
size_t written = destFile.write(sourceFile);
241+
if (written == sourceFile.size())
242+
{
243+
count++;
244+
}
245+
}
246+
destFile.close();
247+
sourceFile.close();
248+
yield();
249+
}
250+
});
251+
252+
return (count == sourceFileCount);
253+
254+
}

libraries/FSTools/FSTools.h

+91
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
#pragma once
2+
3+
#include <FS.h>
4+
#include <memory>
5+
#include <functional>
6+
/*
7+
8+
A temporary FS is made between the END of the sketch... and the start of the partition you try to mount, to maximise the available space for copying the FS.
9+
The WORST case this is at 0x40300000 which is for a 3m FS on 4m flash.. leaving 460Kb for copying.
10+
11+
*/
12+
13+
14+
15+
namespace FST
16+
{
17+
18+
struct layout
19+
{
20+
constexpr layout(uint32_t s, uint32_t e, uint32_t p, uint32_t b) : startAddr(s), endAddr(e), page(p), block(b) {};
21+
const uint32_t startAddr{0};
22+
const uint32_t endAddr{0};
23+
const uint32_t page{0};
24+
const uint32_t block{0};
25+
};
26+
27+
enum FS_t : uint8_t
28+
{
29+
SPIFFS,
30+
LITTLEFS
31+
};
32+
33+
static constexpr layout layout_512k32 = { 0x40273000, 0x4027B000, 0x100, 0x1000 };
34+
static constexpr layout layout_512k64 = { 0x4026B000, 0x4027B000, 0x100, 0x1000 };
35+
static constexpr layout layout_512k128 = { 0x4025B000, 0x4027B000, 0x100, 0x1000 };
36+
37+
static constexpr layout layout_1m64 = { 0x402EB000, 0x402FB000, 0x100, 0x1000 };
38+
static constexpr layout layout_1m128 = { 0x402DB000, 0x402FB000, 0x100, 0x1000 };
39+
static constexpr layout layout_1m144 = { 0x402D7000, 0x402FB000, 0x100, 0x1000 };
40+
static constexpr layout layout_1m160 = { 0x402D3000, 0x402FB000, 0x100, 0x1000 };
41+
static constexpr layout layout_1m192 = { 0x402CB000, 0x402FB000, 0x100, 0x1000 };
42+
static constexpr layout layout_1m256 = { 0x402BB000, 0x402FB000, 0x100, 0x1000 };
43+
static constexpr layout layout_1m512 = { 0x4027B000, 0x402FB000, 0x100, 0x2000 };
44+
45+
static constexpr layout layout_2m64 = { 0x403F0000, 0x403FB000, 0x100, 0x1000 };
46+
static constexpr layout layout_2m128 = { 0x403E0000, 0x403FB000, 0x100, 0x1000 };
47+
static constexpr layout layout_2m256 = { 0x403C0000, 0x403FB000, 0x100, 0x1000 };
48+
static constexpr layout layout_2m512 = { 0x40380000, 0x403FA000, 0x100, 0x2000 };
49+
static constexpr layout layout_2m1m = { 0x40300000, 0x403FA000, 0x100, 0x2000 };
50+
51+
static constexpr layout layout_4m1m = { 0x40500000, 0x405FA000, 0x100, 0x2000 };
52+
static constexpr layout layout_4m2m = { 0x40400000, 0x405FA000, 0x100, 0x2000 };
53+
static constexpr layout layout_4m3m = { 0x40300000, 0x405FA000, 0x100, 0x2000 };
54+
55+
static constexpr layout layout_8m6m = { 0x40400000, 0x409FA000, 0x100, 0x2000 };
56+
static constexpr layout layout_8m7m = { 0x40300000, 0x409FA000, 0x100, 0x2000 };
57+
58+
static constexpr layout layout_16m14m = { 0x40400000, 0x411FA000, 0x100, 0x2000 };
59+
static constexpr layout layout_16m15m = { 0x40300000, 0x411FA000, 0x100, 0x2000 };
60+
61+
typedef std::function<void(File & f)> FileCb;
62+
63+
};
64+
65+
66+
class FSTools
67+
{
68+
public:
69+
70+
FSTools();
71+
~FSTools();
72+
bool attemptToMountFS(fs::FS & fs);
73+
bool mountAlternativeFS(FST::FS_t type, const FST::layout & layout, bool keepMounted = false);
74+
bool mounted();
75+
bool moveFS(fs::FS & destinationFS);
76+
void reset();
77+
void fileListIterator(FS & fs, const char * dirName, FST::FileCb Cb);
78+
79+
private:
80+
uint32_t _getStartAddr(const FST::layout & layout);
81+
uint32_t _getSize(const FST::layout & layout);
82+
#ifdef DEBUG_ESP_CORE
83+
void _dumpFileInfo(File & f);
84+
#endif
85+
bool _copyFS(FS & sourceFS, FS & destFS);
86+
87+
std::unique_ptr<fs::FS> _pFS;
88+
bool _mounted{false};
89+
const FST::layout * _layout{nullptr};
90+
91+
};

0 commit comments

Comments
 (0)