ESP_IOT v2.5
IOT ESP Coding
SPIFFModule.cpp
Go to the documentation of this file.
1
2#include "SPIFFModule.h"
3
4#ifdef USE_SPIFF_MODULE
5
6#define SPIFF_FILE_NAME (char*)"/messages.txt"
7
8#include "FS.h"
9#include "SPIFFS.h"
10
11/* You only need to format SPIFFS the first time you run a
12 test or else use the SPIFFS plugin to create a partition
13 https://github.com/me-no-dev/arduino-esp32fs-plugin */
14
15//! @see https://techtutorialsx.com/2019/06/02/esp8266-spiffs-reading-a-file/
16#define FORMAT_SPIFFS_IF_FAILED true
17
18//!helper for using the spiff or not..
19boolean useSpiff()
20{
22
23}
24
25//!list the directory of the SPIFF
26void listDir(fs::FS &fs, const char * dirname, uint8_t levels)
27{
28 if (!useSpiff())
29 return;
30
31 SerialDebug.printf("Listing directory: %s\r\n", dirname);
32
33 File root = fs.open(dirname);
34 if(!root){
35 SerialDebug.println("- failed to open directory");
36 return;
37 }
38 if(!root.isDirectory()){
39 SerialDebug.println(" - not a directory");
40 return;
41 }
42
43 File file = root.openNextFile();
44 while(file){
45 if(file.isDirectory()){
46 SerialDebug.print(" DIR : ");
47 SerialDebug.println(file.name());
48 if(levels){
49 //listDir(fs, file.path(), levels -1);
50 listDir(fs, file.name(), levels -1);
51
52 }
53 } else {
54 SerialDebug.print(" FILE: ");
55 SerialDebug.print(file.name());
56 SerialDebug.print("\tSIZE: ");
57 SerialDebug.println(file.size());
58 }
59 file = root.openNextFile();
60 }
61}
62
63//!reads the file name specified. The result is SerialDebug.write
64void readFile(fs::FS &fs, const char * path)
65{
66 if (!useSpiff())
67 return;
68
69 SerialDebug.printf("Reading file: %s\r\n", path);
70
71 File file = fs.open(path);
72 if(!file || file.isDirectory()){
73 SerialDebug.println("- failed to open file for reading");
74 return;
75 }
76
77 SerialDebug.println("- read from file:");
78 while(file.available()){
79 SerialDebug.write(file.read());
80 }
81 file.close();
82}
83
84//!writes the message to the file specified
85void writeFile(fs::FS &fs, const char * path, const char * message)
86{
87 if (!useSpiff())
88 return;
89
90 SerialDebug.printf("Writing file: %s\r\n", path);
91
92 File file = fs.open(path, FILE_WRITE);
93 if(!file){
94 SerialDebug.println("- failed to open file for writing");
95 return;
96 }
97 if(file.print(message)){
98 SerialDebug.println("- file written");
99 } else {
100 SerialDebug.println("- write failed");
101 }
102 file.close();
103}
104
105//! appends the message to the file
106void appendFile(fs::FS &fs, const char * path, const char * message)
107{
108 if (!useSpiff())
109 return;
110
111 SerialLots.printf("Appending to file: %s\r\n", path);
112
113 File file = fs.open(path, FILE_APPEND);
114 if(!file){
115 SerialDebug.println("- failed to open file for appending");
116 return;
117 }
118 if(file.print(message)){
119 SerialLots.println("- message appended");
120 } else {
121 SerialDebug.println("- append failed");
122 }
123 file.close();
124}
125
126//! renames the file
127void renameFile(fs::FS &fs, const char * path1, const char * path2)
128{
129 if (!useSpiff())
130 return;
131
132 SerialLots.printf("Renaming file %s to %s\r\n", path1, path2);
133 if (fs.rename(path1, path2)) {
134 SerialLots.println("- file renamed");
135 } else {
136 SerialDebug.println("- rename failed");
137 }
138}
139
140//!deletes the file specified
141void deleteFile(fs::FS &fs, const char * path)
142{
143 if (!useSpiff())
144 return;
145
146 SerialLots.printf("Deleting file: %s\r\n", path);
147 if(fs.remove(path)){
148 SerialLots.println("- file deleted");
149 } else {
150 SerialDebug.println("- delete failed");
151 }
152}
153
154#ifdef NOT_USED
155void testFileIO(fs::FS &fs, const char * path)
156{
157 SerialLots.printf("Testing file I/O with %s\r\n", path);
158
159 static uint8_t buf[512];
160 size_t len = 0;
161 File file = fs.open(path, FILE_WRITE);
162 if(!file){
163 SerialDebug.println("- failed to open file for writing");
164 return;
165 }
166
167 size_t i;
168 SerialDebug.print("- writing" );
169 uint32_t start = millis();
170 for(i=0; i<2048; i++){
171 if ((i & 0x001F) == 0x001F){
172 SerialDebug.print(".");
173 }
174 file.write(buf, 512);
175 }
176 SerialDebug.println("");
177 uint32_t end = millis() - start;
178 SerialDebug.printf(" - %u bytes written in %u ms\r\n", 2048 * 512, end);
179 file.close();
180
181 file = fs.open(path);
182 start = millis();
183 end = start;
184 i = 0;
185 if(file && !file.isDirectory()){
186 len = file.size();
187 size_t flen = len;
188 start = millis();
189 SerialDebug.print("- reading" );
190 while(len){
191 size_t toRead = len;
192 if(toRead > 512){
193 toRead = 512;
194 }
195 file.read(buf, toRead);
196 if ((i++ & 0x001F) == 0x001F){
197 SerialDebug.print(".");
198 }
199 len -= toRead;
200 }
201 SerialDebug.println("");
202 end = millis() - start;
203 SerialDebug.printf("- %u bytes read in %u ms\r\n", flen, end);
204 file.close();
205 } else {
206 SerialDebug.println("- failed to open file for reading");
207 }
208}
209#endif
210
211
212 // writeFile(SPIFFS, "/hello.txt", "Hello ESP ");
213 //appendFile(SPIFFS, "/hello.txt", "Another line of text\r\n");
214
215 // appendFile(SPIFFS, "/hello.txt", "World!\r\n");
216
217
218 //readFile(SPIFFS, "/hello.txt");
219 // renameFile(SPIFFS, "/hello.txt", "/foo.txt");
220 // readFile(SPIFFS, "/foo.txt");
221 // deleteFile(SPIFFS, "/foo.txt");
222 // testFileIO(SPIFFS, "/test.txt");
223 // deleteFile(SPIFFS, "/test.txt");
224 //SerialDebug.println( "Test complete" );
225
226//! The SPIFF module is for storing messages that are retrievable later as it stores on a folder area of the ESP chip
227
228//!print a string to spiff (a new line is added)
229void println_SPIFFModule(char *string)
230{
231 print_SPIFFModule(string);
232 print_SPIFFModule((char*)"\r\n");
233}
234
235//!print a string to spiff (NO new line is added)
236void print_SPIFFModule(char *string)
237{
238 appendFile(SPIFFS, SPIFF_FILE_NAME, string);
239}
240//!print a int to spiff (NO new line is added)
241void printInt_SPIFFModule(int val)
242{
243 char str[20];
244 sprintf(str,"%d",val);
246}
247
248//! delete the spiff files..
250{
251 deleteFile(SPIFFS, SPIFF_FILE_NAME);
252}
253
254//! prints the spiff file to the SerialDebug output
256{
257 readFile(SPIFFS, SPIFF_FILE_NAME);
258}
259
260//!reads the file name specified. returning the number of lines..
261int linesInFile_SPIFFModule(fs::FS &fs, const char * path)
262{
263
264 if (!useSpiff())
265 return 0;
266
267 //count the lines
268 int lines = 0;
269 File file = fs.open(path);
270 if(!file || file.isDirectory()){
271 SerialDebug.println("- failed to open file for reading");
272 return lines;
273 }
274
275 while(file.available()){
276 lines++;
277 file.readString();
278 }
279 file.close();
280 return lines;
281}
282
283//! sends SPIFF module strings over MQTT, starting at the number back specified. This will use the current users MQTT credentials..
284void sendStrings_SPIFFModule(int numberOfLines)
285{
286 if (!useSpiff())
287 return;
288
289 SerialDebug.println("sendStrings_SPIFFModule");
290
291 fs::FS fs = SPIFFS;
292 char *path = SPIFF_FILE_NAME;
293 int linesMax = linesInFile_SPIFFModule(SPIFFS, SPIFF_FILE_NAME);
294 SerialDebug.printf("linesMax = %d\n", linesMax);
295 //somehow send over MQTT..
296#ifdef USE_MQTT_NETWORKING
297 if (numberOfLines > 20)
298 numberOfLines = 5;
299
300
301 //fast forward lines - numberOfLines
302 // eg. if # = 100, but only want last 10, then
303 int skipLines = linesMax - numberOfLines;
304 if (skipLines < 0)
305 skipLines = 0;
306
307 File file = fs.open(path);
308 if(!file || file.isDirectory()){
309 SerialDebug.println("- failed to open file for reading");
310 return;
311 }
312
313 int counter = 0;
314 while(file.available() && counter < skipLines){
315 file.readString();
316 counter++;
317 }
318#ifdef NOT_WORKING_YET
319
320 //!send a header
321 sendMessageNoChangeMQTT((char*)"Sending Post Mortum Debug");
322 counter = 0;
323 char buffer[200];
324 //now the rest of the lines can be sent..
325 while(file.available() && counter < 5)
326 {
327 String line = file.readString();
328 SerialDebug.println(line);
329 //char * cstr = new char [str.length()+1];
330 if (line)
331 {
332 //strcpy (buffer, line.c_str());
333 strcpy (buffer, (char*)"ScottyBoy");
334
335 //send the string verbatum..
337 }
338 counter++;
339 }
340 file.close();
341 //!send a header
342 sendMessageNoChangeMQTT((char*)"Done Post Mortum Debug");
343#else
344 sendMessageNoChangeMQTT((char*)"Sending Post Mortum Debug ..todo");
345
346#endif
347#endif
348}
349
350//!writes a FB to a file..
351void writeFB_SPIFFModule(
352 uint8_t * buf, /*!< Pointer to the pixel data */
353 size_t len, /*!< Length of the buffer in bytes */
354 char *fileName)
355{
356 if (!useSpiff())
357 return;
358
359 File file = SPIFFS.open(fileName, FILE_WRITE);
360 if(!file){
361 SerialDebug.println("- failed to open file for writing");
362 return;
363 }
364 if(file.write(buf,len)){
365 SerialDebug.println("- file written");
366 } else {
367 SerialDebug.println("- write failed");
368 }
369 file.close();
370}
371
372//! the setup for this module
374{
375 SerialDebug.println("SPIFFS setup");
376
377 if (!useSpiff())
378 {
379 SerialDebug.println("not being used: SPIFFS");
380
381 return;
382 }
383
384 if(!SPIFFS.begin(FORMAT_SPIFFS_IF_FAILED)){
385 SerialDebug.println("SPIFFS Mount Failed");
386 return;
387 }
388 listDir(SPIFFS, "/", 0);
389
390//testing:
391 boolean test1 = false;
392 if (test1)
393 {
394 // try reading the file
396 }
397
398 boolean test2 = false;
399 if (test2)
400 {
401 // try reading the file
403 }
404}
405
406//! a loop if anything (nothing right now)
407void loop_SPIFFModule()
408{
409}
410
411//!prints a timestamp
413{
414 if (!useSpiff())
415 return;
416
417 print_SPIFFModule((char*)" time: ");
419 print_SPIFFModule((char*)": ");
420}
421
422#ifdef M5_CAPTURE_SCREEN
423/***************************************************************************************
424 * Function name: M5Screen2bmp
425 * Description: Dump the screen to a WiFi client
426 * Image file format: Content-type:image/bmp
427 * return value: always true
428 ***************************************************************************************/
429bool M5Screen2bmp(WiFiClient &client){
430 TFT_eSprite canvas = TFT_eSprite(&M5.Lcd);
431
432 int image_height = M5.Lcd.height();
433 int image_width = M5.Lcd.width();
434
435 //https://docs.m5stack.com/en/api/core2/lcd_api
436 canvas.createSprite(image_width, image_height);
437 //canvas.println("HELLO M5 Canvas");
438 canvas.fillSprite(RED);
439 canvas.fillCircle(100,100,20,GREEN);
440 canvas.pushSprite(0,0,WHITE);
441
442 const uint pad=(4-(3*image_width)%4)%4;
443 uint filesize=54+(3*image_width+pad)*image_height;
444 unsigned char header[54] = {
445 'B','M', // BMP signature (Windows 3.1x, 95, NT, …)
446 0,0,0,0, // image file size in bytes
447 0,0,0,0, // reserved
448 54,0,0,0, // start of pixel array
449 40,0,0,0, // info header size
450 0,0,0,0, // image width
451 0,0,0,0, // image height
452 1,0, // number of color planes
453 24,0, // bits per pixel
454 0,0,0,0, // compression
455 0,0,0,0, // image size (can be 0 for uncompressed images)
456 0,0,0,0, // horizontal resolution (dpm)
457 0,0,0,0, // vertical resolution (dpm)
458 0,0,0,0, // colors in color table (0 = none)
459 0,0,0,0 };// important color count (0 = all colors are important)
460 // fill filesize, width and heigth in the header array
461 for(uint i=0; i<4; i++) {
462 header[ 2+i] = (char)((filesize>>(8*i))&255);
463 header[18+i] = (char)((image_width >>(8*i))&255);
464 header[22+i] = (char)((image_height >>(8*i))&255);
465 }
466 // write the header to the file
467 client.write(header, 54);
468
469 // To keep the required memory low, the image is captured line by line
470 unsigned char line_data[image_width*3+pad];
471 // initialize padded pixel with 0
472 for(int i=(image_width-1)*3; i<(image_width*3+pad); i++){
473 line_data[i]=0;
474 }
475 // The coordinate origin of a BMP image is at the bottom left.
476 // Therefore, the image must be read from bottom to top.
477 for(int y=image_height; y>0; y--){
478 // get one line of the screen content
479 // M5.Lcd.readRectRGB(0, y-1, image_width, 1, line_data);
480 canvas.readRectRGB(0, y-1, image_width, 1, line_data);
481
482 // BMP color order is: Blue, Green, Red
483 // return values from readRectRGB is: Red, Green, Blue
484 // therefore: R und B need to be swapped
485 for(int x=0; x<image_width; x++){
486 unsigned char r_buff = line_data[x*3];
487 SerialTemp.print(r_buff);
488 line_data[x*3] = line_data[x*3+2];
489 line_data[x*3+2] = r_buff;
490 }
491 SerialTemp.println();
492 // write the line to the file
493 client.write(line_data, (image_width*3)+pad);
494 }
495 return true;
496}
497
498//!https://github.com/m5stack/M5StickC/issues/74
499//!Says replace M5.Lcd with LCD::canvas
500
501//!save the screen to the SPIFF .. testing
502//!@see https://github.com/electricidea/M5Stack-Screen-Capture
503//!@see https://www.hackster.io/hague/m5stack-screen-capture-and-remote-control-142cfe
504//!
505/***************************************************************************************
506 * Function name: M5Screen2bmp
507 * Description: Dump the screen to a bmp image File
508 * Image file format: .bmp
509 * return value: true: succesfully wrote screen to file
510 * false: unabel to open file for writing
511 * example for screen capture onto SD-Card:
512 * M5Screen2bmp(SD, "/screen.bmp");
513 * inspired by: https://stackoverflow.com/a/58395323
514 ***************************************************************************************/
515bool M5Screen2bmp(fs::FS &fs, const char * path){
516 // Open file for writing
517 // The existing image file will be replaced
518 File file = fs.open(path, FILE_WRITE);
519 if(file){
520 // M5Stack: TFT_WIDTH = 240 / TFT_HEIGHT = 320
521 // M5StickC: TFT_WIDTH = 80 / TFT_HEIGHT = 160
522 // M5StickCplus: TFT_WIDTH = 135 / TFT_HEIGHT = 240
523 int image_height = M5.Lcd.height();
524 int image_width = M5.Lcd.width();
525 SerialDebug.printf("Saving screen to bmp file (%d,%d)\n", image_width, image_height);
526
527 // horizontal line must be a multiple of 4 bytes long
528 // add padding to fill lines with 0
529 const uint pad=(4-(3*image_width)%4)%4;
530 // header size is 54 bytes:
531 // File header = 14 bytes
532 // Info header = 40 bytes
533 uint filesize=54+(3*image_width+pad)*image_height;
534 unsigned char header[54] = {
535 'B','M', // BMP signature (Windows 3.1x, 95, NT, …)
536 0,0,0,0, // image file size in bytes
537 0,0,0,0, // reserved
538 54,0,0,0, // start of pixel array
539 40,0,0,0, // info header size
540 0,0,0,0, // image width
541 0,0,0,0, // image height
542 1,0, // number of color planes
543 24,0, // bits per pixel
544 0,0,0,0, // compression
545 0,0,0,0, // image size (can be 0 for uncompressed images)
546 0,0,0,0, // horizontal resolution (dpm)
547 0,0,0,0, // vertical resolution (dpm)
548 0,0,0,0, // colors in color table (0 = none)
549 0,0,0,0 };// important color count (0 = all colors are important)
550 // fill filesize, width and heigth in the header array
551 for(uint i=0; i<4; i++) {
552 header[ 2+i] = (char)((filesize>>(8*i))&255);
553 header[18+i] = (char)((image_width >>(8*i))&255);
554 header[22+i] = (char)((image_height >>(8*i))&255);
555 }
556 // write the header to the file
557 file.write(header, 54);
558
559 // To keep the required memory low, the image is captured line by line
560 unsigned char line_data[image_width*3+pad];
561 // initialize padded pixel with 0
562 for(int i=(image_width-1)*3; i<(image_width*3+pad); i++){
563 line_data[i]=0;
564 }
565 // The coordinate origin of a BMP image is at the bottom left.
566 // Therefore, the image must be read from bottom to top.
567 for(int y=image_height; y>0; y--){
568 // get one line of the screen content
569 M5.Lcd.readRectRGB(0, y-1, image_width, 1, line_data);
570 // BMP color order is: Blue, Green, Red
571 // return values from readRectRGB is: Red, Green, Blue
572 // therefore: R und B need to be swapped
573 for(int x=0; x<image_width; x++){
574 unsigned char r_buff = line_data[x*3];
575 line_data[x*3] = line_data[x*3+2];
576 line_data[x*3+2] = r_buff;
577 }
578 // write the line to the file
579 file.write(line_data, (image_width*3)+pad);
580 }
581 file.close();
582 return true;
583 }
584 else
585 {
586 SerialDebug.printf(" *** Cannot open file: %s\n", path);
587 }
588 return false;
589}
590#else
591
592#endif // M5_CAPTURE_SCREEN
593
594//!save the screen to a file on the SPIFF
596{
597#define SPIFF_SCREEN_FILE_NAME (char*)"/M5Screen.bmp"
598
599#ifdef M5_CAPTURE_SCREEN
600 boolean linesMax = M5Screen2bmp(SPIFFS, SPIFF_SCREEN_FILE_NAME);
601
602 listDir(SPIFFS, "/", 0);
603#endif
604}
605
606#else //**** PLACEHOLDERS so the callers don't need ifdef
607
608//!save the screen to a file on the SPIFF
610{
611
612}
613
614//!print a string to spiff (a new line is added)
615void println_SPIFFModule(char *string)
616{
617
618}
619
620//!print a string to spiff (NO new line is added)
621void print_SPIFFModule(char *string)
622{
623
624}
625
626//!print a int to spiff (NO new line is added)
628{
629
630}
631
632//! delete the spiff files..
634{
635
636}
637
638//! prints the spiff file to the SerialDebug output
640{
641
642}
643
644//! sends SPIFF module strings over MQTT, starting at the number back specified. This will use the current users MQTT credentials..
645void sendStrings_SPIFFModule(int numberOfLines)
646{
647
648}
649
650//! the setup for this module
652{
653
654}
655
656//! a loop if anything (nothing right now)
658{
659
660}
661
662//!prints a timestamp
664{
665
666}
667#endif // USE_SPIFF_MODULE
void sendMessageNoChangeMQTT(char *message)
just send a message but without any extras
int getTimeStamp_mainModule()
boolean getPreferenceBoolean_mainModule(int preferenceID)
called to set a preference (which will be an identifier and a string, which can be converted to a num...
#define PREFERENCE_USE_SPIFF_SETTING
8.22.22 to turn on/off SPIFF use
void loop_SPIFFModule()
a loop if anything (nothing right now)
void println_SPIFFModule(char *string)
print a string to spiff (a new line is added)
void printInt_SPIFFModule(int val)
print a int to spiff (NO new line is added)
void sendStrings_SPIFFModule(int numberOfLines)
sends SPIFF module strings over MQTT, starting at the number back specified. This will use the curren...
void printTimestamp_SPIFFModule()
prints a timestamp
void printFile_SPIFFModule()
prints the spiff file to the SerialDebug output
void print_SPIFFModule(char *string)
print a string to spiff (NO new line is added)
void deleteFiles_SPIFFModule()
delete the spiff files..
void setup_SPIFFModule()
the setup for this module
void saveScreen_SPIFFModule()
save the screen to a file on the SPIFF
Definition: WebServer.h:62