MeterLogger
espfs.c
Go to the documentation of this file.
1 /*
2 This is a simple read-only implementation of a file system. It uses a block of data coming from the
3 mkespfsimg tool, and can use that block to do abstracted operations on the files that are in there.
4 It's written for use with httpd, but doesn't need to be used as such.
5 */
6 
7 /*
8  * ----------------------------------------------------------------------------
9  * "THE BEER-WARE LICENSE" (Revision 42):
10  * Jeroen Domburg <jeroen@spritesmods.com> wrote this file. As long as you retain
11  * this notice you can do whatever you want with this stuff. If we meet some day,
12  * and you think this stuff is worth it, you can buy me a beer in return.
13  * ----------------------------------------------------------------------------
14  */
15 
16 
17 //These routines can also be tested by comping them in with the espfstest tool. This
18 //simplifies debugging, but needs some slightly different headers. The #ifdef takes
19 //care of that.
20 
21 #ifdef __ets__
22 //esp build
23 #include <esp8266.h>
24 #include "debug.h"
25 #else
26 //Test build
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #define os_malloc malloc
31 #define os_free free
32 #define os_memcpy memcpy
33 #define os_strncmp strncmp
34 #define os_strcmp strcmp
35 #define os_strcpy strcpy
36 #define os_printf printf
37 #define ICACHE_FLASH_ATTR
38 extern char* espFsData;
39 #endif
40 
41 #include "../mkespfsimage/espfsformat.h"
42 #include "espfs.h"
43 #include "httpdconfig.h"
44 #ifdef EFS_HEATSHRINK
45 #include "heatshrink_decoder.h"
46 #endif
47 
48 
49 
50 
51 struct EspFsFile {
52  EspFsHeader *header;
54  int32_t posDecomp;
55  char *posStart;
56  char *posComp;
57  void *decompData;
58 };
59 
60 /*
61 Available locations, at least in my flash, with boundaries partially guessed. This
62 is using 0.9.1/0.9.2 SDK on a not-too-new module.
63 0x00000 (0x10000): Code/data (RAM data?)
64 0x10000 (0x02000): Gets erased by something?
65 0x12000 (0x2E000): Free (filled with zeroes) (parts used by ESPCloud and maybe SSL)
66 0x40000 (0x20000): Code/data (ROM data?)
67 0x60000 (0x1C000): Free
68 0x7c000 (0x04000): Param store
69 0x80000 - end of flash
70 
71 Accessing the flash through the mem emulation at 0x40200000 is a bit hairy: All accesses
72 *must* be aligned 32-bit accesses. Reading a short, byte or unaligned word will result in
73 a memory exception, crashing the program.
74 */
75 
76 
77 //Copies len bytes over from dst to src, but does it using *only*
78 //aligned 32-bit reads. Yes, it's no too optimized but it's short and sweet and it works.
79 
80 //ToDo: perhaps os_memcpy also does unaligned accesses?
81 void ICACHE_FLASH_ATTR memcpyAligned(char *dst, char *src, int len) {
82  int x;
83  int w, b;
84  for (x=0; x<len; x++) {
85  b=((int)src&3);
86  w=*((int *)(src-b));
87  if (b==0) *dst=(w>>0);
88  if (b==1) *dst=(w>>8);
89  if (b==2) *dst=(w>>16);
90  if (b==3) *dst=(w>>24);
91  dst++; src++;
92  }
93 }
94 
95 
96 //Open a file and return a pointer to the file desc struct.
98 #ifdef __ets__
99  char *p=(char *)(ESPFS_POS+0x40200000);
100 #else
101  char *p=espFsData;
102 #endif
103  char *hpos;
104  char namebuf[256];
105  EspFsHeader h;
106  EspFsFile *r;
107  //Strip initial slashes
108  while(fileName[0]=='/') fileName++;
109  //Go find that file!
110  while(1) {
111  hpos=p;
112  //Grab the next file header.
113  os_memcpy(&h, p, sizeof(EspFsHeader));
114  if (h.magic!=0x73665345) {
115  INFO("Magic mismatch. EspFS image broken.\n");
116  return NULL;
117  }
118  if (h.flags&FLAG_LASTFILE) {
119  INFO("End of image.\n");
120  return NULL;
121  }
122  //Grab the name of the file.
123  p+=sizeof(EspFsHeader);
124  os_memcpy(namebuf, p, sizeof(namebuf));
125 // INFO("Found file '%s'. Namelen=%x fileLenComp=%x, compr=%d flags=%d\n",
126 // namebuf, (unsigned int)h.nameLen, (unsigned int)h.fileLenComp, h.compression, h.flags);
127  if (os_strcmp(namebuf, fileName)==0) {
128  //Yay, this is the file we need!
129  p+=h.nameLen; //Skip to content.
130  r=(EspFsFile *)os_malloc(sizeof(EspFsFile)); //Alloc file desc mem
131 // INFO("Alloc %p\n", r);
132  if (r==NULL) return NULL;
133  r->header=(EspFsHeader *)hpos;
134  r->decompressor=h.compression;
135  r->posComp=p;
136  r->posStart=p;
137  r->posDecomp=0;
138  if (h.compression==COMPRESS_NONE) {
139  r->decompData=NULL;
140 #ifdef EFS_HEATSHRINK
141  } else if (h.compression==COMPRESS_HEATSHRINK) {
142  //File is compressed with Heatshrink.
143  char parm;
144  heatshrink_decoder *dec;
145  //Decoder params are stored in 1st byte.
146  memcpyAligned(&parm, r->posComp, 1);
147  r->posComp++;
148  INFO("Heatshrink compressed file; decode parms = %x\n", parm);
149  dec=heatshrink_decoder_alloc(16, (parm>>4)&0xf, parm&0xf);
150  r->decompData=dec;
151 #endif
152  } else {
153  INFO("Invalid compression: %d\n", h.compression);
154  return NULL;
155  }
156  return r;
157  }
158  //We don't need this file. Skip name and file
159  p+=h.nameLen+h.fileLenComp;
160  if ((int)p&3) p+=4-((int)p&3); //align to next 32bit val
161  }
162 }
163 
164 //Read len bytes from the given file into buff. Returns the actual amount of bytes read.
165 int ICACHE_FLASH_ATTR espFsRead(EspFsFile *fh, char *buff, int len) {
166  int flen;
167  if (fh==NULL) return 0;
168  //Cache file length.
169  memcpyAligned((char*)&flen, (char*)&fh->header->fileLenComp, 4);
170  //Do stuff depending on the way the file is compressed.
171  if (fh->decompressor==COMPRESS_NONE) {
172  int toRead;
173  toRead=flen-(fh->posComp-fh->posStart);
174  if (len>toRead) len=toRead;
175 // INFO("Reading %d bytes from %x\n", len, (unsigned int)fh->posComp);
176  memcpyAligned(buff, fh->posComp, len);
177  fh->posDecomp+=len;
178  fh->posComp+=len;
179 // INFO("Done reading %d bytes, pos=%x\n", len, fh->posComp);
180  return len;
181 #ifdef EFS_HEATSHRINK
182  } else if (fh->decompressor==COMPRESS_HEATSHRINK) {
183  int decoded=0;
184  unsigned int elen, rlen;
185  char ebuff[16];
187 // INFO("Alloc %p\n", dec);
188  while(decoded<len) {
189  //Feed data into the decompressor
190  //ToDo: Check ret val of heatshrink fns for errors
191  elen=flen-(fh->posComp - fh->posStart);
192  if (elen==0) return decoded; //file is read
193  if (elen>0) {
194  memcpyAligned(ebuff, fh->posComp, 16);
195  heatshrink_decoder_sink(dec, (uint8_t *)ebuff, (elen>16)?16:elen, &rlen);
196  fh->posComp+=rlen;
197  if (rlen==elen) {
199  }
200  }
201  //Grab decompressed data and put into buff
202  heatshrink_decoder_poll(dec, (uint8_t *)buff, len-decoded, &rlen);
203  fh->posDecomp+=rlen;
204  buff+=rlen;
205  decoded+=rlen;
206  }
207  return len;
208 #endif
209  }
210  return 0;
211 }
212 
213 //Close the file.
215  if (fh==NULL) return;
216 #ifdef EFS_HEATSHRINK
217  if (fh->decompressor==COMPRESS_HEATSHRINK) {
220 // INFO("Freed %p\n", dec);
221  }
222 #endif
223 // INFO("Freed %p\n", fh);
224  os_free(fh);
225 }
226 
227 
228 
HSD_poll_res heatshrink_decoder_poll(heatshrink_decoder *hsd, uint8_t *out_buf, size_t out_buf_size, size_t *output_size)
char * posStart
Definition: espfs.c:55
void * decompData
Definition: espfs.c:57
int32_t posDecomp
Definition: espfs.c:54
int ICACHE_FLASH_ATTR espFsRead(EspFsFile *fh, char *buff, int len)
Definition: espfs.c:165
#define NULL
Definition: def.h:47
#define ICACHE_FLASH_ATTR
Definition: c_types.h:99
void ICACHE_FLASH_ATTR espFsClose(EspFsFile *fh)
Definition: espfs.c:214
heatshrink_decoder * heatshrink_decoder_alloc(uint16_t input_buffer_size, uint8_t window_sz2, uint8_t lookahead_sz2)
void ICACHE_FLASH_ATTR memcpyAligned(char *dst, char *src, int len)
Definition: espfs.c:81
#define os_memcpy
Definition: osapi.h:36
void heatshrink_decoder_free(heatshrink_decoder *hsd)
#define os_strcmp
Definition: osapi.h:41
#define os_malloc(s)
Definition: mem.h:41
HSD_finish_res heatshrink_decoder_finish(heatshrink_decoder *hsd)
EspFsHeader * header
Definition: espfs.c:52
char decompressor
Definition: espfs.c:53
EspFsFile ICACHE_FLASH_ATTR * espFsOpen(char *fileName)
Definition: espfs.c:97
HSD_sink_res heatshrink_decoder_sink(heatshrink_decoder *hsd, uint8_t *in_buf, size_t size, size_t *input_size)
#define os_free(s)
Definition: mem.h:40
#define ESPFS_POS
Definition: httpdconfig.h:6
char * posComp
Definition: espfs.c:56
#define INFO(...)
Definition: debug.h:17