mirror of https://github.com/jeelabs/esp-link.git
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