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