parent
b736d77abb
commit
2bba5c13ed
After Width: | Height: | Size: 3.2 KiB |
@ -0,0 +1,7 @@ |
||||
<html> |
||||
<head><title>Test</title></head> |
||||
<body> |
||||
<h1>Test!</h1> |
||||
<p>Yay, the cpio filesystem thingy works. Click <a href="/test2.html">here</a> to see |
||||
if the 2nd page works too. |
||||
</p> |
@ -0,0 +1,7 @@ |
||||
<html> |
||||
<head><title>Test</title></head> |
||||
<body> |
||||
<h1>Test2!</h1> |
||||
<p>Here's an image of a cat (hopefully...)<br /> |
||||
<img src="cat.jpeg"> |
||||
</p> |
@ -0,0 +1,4 @@ |
||||
|
||||
|
||||
mkespfsimage: main.o |
||||
$(CC) -o mkespfsimage $<
|
@ -0,0 +1,31 @@ |
||||
#ifndef ESPROFSFORMAT_H |
||||
#define ESPROFSFORMAT_H |
||||
|
||||
/*
|
||||
Stupid cpio-like tool to make read-only 'filesystems' that live on the flash SPI chip of the module. |
||||
Can (will) use lzf compression (when I come around to it) to make shit quicker. Aligns names, files, |
||||
headers on 4-byte boundaries so the SPI abstraction hardware in the ESP8266 doesn't crap on itself
|
||||
when trying to do a <4byte or unaligned read. |
||||
*/ |
||||
|
||||
/*
|
||||
The idea 'borrows' from cpio: it's basically a concatenation of {header, filename, file} data. |
||||
Header, filename and file data is 32-bit aligned. The last file is indicated by data-less header |
||||
with the FLAG_LASTFILE flag set. |
||||
*/ |
||||
|
||||
|
||||
#define FLAG_LASTFILE (1<<0) |
||||
#define COMPRESS_NONE 0 |
||||
#define COMPRESS_LZF 1 |
||||
|
||||
typedef struct { |
||||
int32_t magic; |
||||
int8_t flags; |
||||
int8_t compression; |
||||
int16_t nameLen; |
||||
int32_t fileLenComp; |
||||
int32_t fileLenDecomp; |
||||
} EspFsHeader; |
||||
|
||||
#endif |
@ -0,0 +1,109 @@ |
||||
|
||||
#include <stdint.h> |
||||
#include <sys/types.h> |
||||
#include <sys/stat.h> |
||||
#include <fcntl.h> |
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <sys/mman.h> |
||||
#include <arpa/inet.h> |
||||
#include <string.h> |
||||
#include "espfsformat.h" |
||||
|
||||
//Routines to convert host format to the endianness used in the xtensa
|
||||
short htoxs(short in) { |
||||
char r[2]; |
||||
r[0]=in; |
||||
r[1]=in>>8; |
||||
return *((short *)r); |
||||
} |
||||
|
||||
int htoxl(int in) { |
||||
unsigned char r[4]; |
||||
r[0]=in; |
||||
r[1]=in>>8; |
||||
r[2]=in>>16; |
||||
r[3]=in>>24; |
||||
return *((int *)r); |
||||
} |
||||
|
||||
|
||||
void handleFile(int f, char *name) { |
||||
char *fdat; |
||||
off_t size; |
||||
EspFsHeader h; |
||||
int nameLen; |
||||
size=lseek(f, 0, SEEK_END); |
||||
fdat=mmap(NULL, size, PROT_READ, MAP_SHARED, f, 0); |
||||
if (fdat==MAP_FAILED) { |
||||
perror("mmap"); |
||||
return; |
||||
} |
||||
|
||||
//Fill header data
|
||||
h.magic=('E'<<0)+('S'<<8)+('f'<<16)+('s'<<24); |
||||
h.flags=0; |
||||
h.compression=COMPRESS_NONE; |
||||
nameLen=strlen(name)+1; |
||||
if (nameLen&3) nameLen+=4-(nameLen&3); //Round to next 32bit boundary
|
||||
h.nameLen=htoxs(nameLen); |
||||
h.fileLenComp=htoxl(size); |
||||
h.fileLenDecomp=htoxl(size); |
||||
|
||||
write(1, &h, sizeof(EspFsHeader)); |
||||
write(1, name, nameLen); //ToDo: this can eat up a few bytes after the buffer.
|
||||
write(1, fdat, size); |
||||
//Pad out to 32bit boundary
|
||||
while (size&3) { |
||||
write(1, "\000", 1); |
||||
size++; |
||||
} |
||||
munmap(fdat, size); |
||||
} |
||||
|
||||
//Write final dummy header with FLAG_LASTFILE set.
|
||||
void finishArchive() { |
||||
EspFsHeader h; |
||||
h.magic=('E'<<0)+('S'<<8)+('f'<<16)+('s'<<24); |
||||
h.flags=FLAG_LASTFILE; |
||||
h.compression=COMPRESS_NONE; |
||||
h.nameLen=htoxs(0); |
||||
h.fileLenComp=htoxl(0); |
||||
h.fileLenDecomp=htoxl(0); |
||||
write(1, &h, sizeof(EspFsHeader)); |
||||
} |
||||
|
||||
|
||||
int main(int argc, char **argv) { |
||||
int f; |
||||
char fileName[1024]; |
||||
char *realName; |
||||
struct stat statBuf; |
||||
int serr; |
||||
while(fgets(fileName, sizeof(fileName), stdin)) { |
||||
//Kill off '\n' at the end
|
||||
fileName[strlen(fileName)-1]=0; |
||||
//Only include files
|
||||
serr=stat(fileName, &statBuf); |
||||
if ((serr==0) && S_ISREG(statBuf.st_mode)) { |
||||
//Strip off './' or '/' madness.
|
||||
realName=fileName; |
||||
if (fileName[0]=='.') realName++; |
||||
if (realName[0]=='/') realName++; |
||||
f=open(fileName, O_RDONLY); |
||||
if (f>0) { |
||||
handleFile(f, realName); |
||||
fprintf(stderr, "%s\n", realName); |
||||
close(f); |
||||
} else { |
||||
perror(fileName); |
||||
} |
||||
} else { |
||||
if (serr!=0) { |
||||
perror(fileName); |
||||
} |
||||
} |
||||
} |
||||
finishArchive(); |
||||
} |
||||
|
@ -0,0 +1,114 @@ |
||||
#include "driver/uart.h" |
||||
#include "c_types.h" |
||||
#include "user_interface.h" |
||||
#include "espconn.h" |
||||
#include "mem.h" |
||||
#include "osapi.h" |
||||
#include "../mkespfsimage/espfsformat.h" |
||||
#include "espfs.h" |
||||
|
||||
struct EspFsFile { |
||||
EspFsHeader *header; |
||||
char decompressor; |
||||
int32_t posDecomp; |
||||
char *posStart; |
||||
char *posComp; |
||||
void *decompData; |
||||
}; |
||||
|
||||
/*
|
||||
Available locations, at least in my flash, with boundaries partially guessed: |
||||
0x00000 (0x10000): Code/data (RAM data?) |
||||
0x10000 (0x30000): Free (filled with zeroes) (parts used by ESPCloud and maybe SSL) |
||||
0x40000 (0x20000): Code/data (ROM data?) |
||||
0x60000 (0x1C000): Free |
||||
0x7c000 (0x04000): Param store |
||||
0x80000 - end of flash |
||||
|
||||
Accessing the flash through the mem emulation at 0x40200000 is a bit hairy: All accesses |
||||
*must* be aligned 32-bit accesses. Reading a short, byte or unaligned word will result in |
||||
a memory exception, crashing the program. |
||||
*/ |
||||
|
||||
|
||||
//Copies len bytes over from dst to src, but does it using *only*
|
||||
//aligned 32-bit reads.
|
||||
void memcpyAligned(char *dst, char *src, int len) { |
||||
int x; |
||||
int w, b; |
||||
for (x=0; x<len; x++) { |
||||
b=((int)src&3); |
||||
w=*((int *)(src-b)); |
||||
if (b==0) *dst=(w>>0); |
||||
if (b==1) *dst=(w>>8); |
||||
if (b==2) *dst=(w>>16); |
||||
if (b==3) *dst=(w>>24); |
||||
dst++; src++; |
||||
} |
||||
} |
||||
|
||||
|
||||
|
||||
EspFsFile *espFsOpen(char *fileName) { |
||||
char *p=(char *)(ESPFS_POS+0x40200000); |
||||
char *hpos; |
||||
char namebuf[256]; |
||||
EspFsHeader h; |
||||
EspFsFile *r; |
||||
//Skip initial slashes
|
||||
while(fileName[0]=='/') fileName++; |
||||
//Go find that file!
|
||||
while(1) { |
||||
hpos=p; |
||||
os_memcpy(&h, p, sizeof(EspFsHeader)); |
||||
//ToDo: check magic
|
||||
if (h.flags&FLAG_LASTFILE) { |
||||
// os_printf("End of archive.\n");
|
||||
return NULL; |
||||
} |
||||
p+=sizeof(EspFsHeader); |
||||
os_memcpy(namebuf, p, sizeof(namebuf)); |
||||
// os_printf("Found file %s . Namelen=%x fileLen=%x\n", namebuf, h.nameLen,h.fileLenComp);
|
||||
if (os_strcmp(namebuf, fileName)==0) { |
||||
p+=h.nameLen; |
||||
r=(EspFsFile *)os_malloc(sizeof(EspFsFile)); |
||||
if (r==NULL) return NULL; |
||||
r->header=(EspFsHeader *)hpos; |
||||
r->decompressor=h.compression; |
||||
r->posComp=p; |
||||
r->posStart=p; |
||||
r->posDecomp=0; |
||||
r->decompData=NULL; |
||||
//ToDo: Init any decompressor
|
||||
return r; |
||||
} |
||||
//Skip name and file
|
||||
p+=h.nameLen+h.fileLenComp; |
||||
if ((int)p&3) p+=4-((int)p&3); //align to next 32bit val
|
||||
// os_printf("Next addr = %x\n", (int)p);
|
||||
} |
||||
} |
||||
|
||||
|
||||
int espFsRead(EspFsFile *fh, char *buff, int len) { |
||||
if (fh==NULL) return 0; |
||||
if (fh->decompressor==COMPRESS_NONE) { |
||||
int toRead; |
||||
toRead=fh->header->fileLenComp-(fh->posComp-fh->posStart); |
||||
if (len>toRead) len=toRead; |
||||
// os_printf("Reading %d bytes from %x\n", len, fh->posComp);
|
||||
memcpyAligned(buff, fh->posComp, len); |
||||
fh->posDecomp+=len; |
||||
fh->posComp+=len; |
||||
// os_printf("Done reading %d bytes, pos=%x\n", len, fh->posComp);
|
||||
return len; |
||||
} |
||||
} |
||||
|
||||
void espFsClose(EspFsFile *fh) { |
||||
if (fh==NULL) return; |
||||
os_free(fh); |
||||
} |
||||
|
||||
|
||||
|
@ -0,0 +1,14 @@ |
||||
#ifndef ESPFS_H |
||||
#define ESPFS_H |
||||
|
||||
//Pos of esp fs in flash
|
||||
#define ESPFS_POS 0x20000 |
||||
|
||||
typedef struct EspFsFile EspFsFile; |
||||
|
||||
EspFsFile *espFsOpen(char *fileName); |
||||
int espFsRead(EspFsFile *fh, char *buff, int len); |
||||
void espFsClose(EspFsFile *fh); |
||||
|
||||
|
||||
#endif |
Loading…
Reference in new issue