2 #Generate a .c source that preinitializes a coffee file system
3 #David Kopf <dak664@embarqmail.com> July 2009
4 #For coffee file_header structure of
6 # coffee_page_t log_page;
7 # uint16_t log_records;
8 # uint16_t log_record_size;
9 # coffee_page_t max_pages;
10 # uint8_t deprecated_eof_hint;
12 # char name[COFFEE_NAME_LENGTH];
13 # } __attribute__((packed));
16 START
:$version="1.0 dak";
19 for($n=0;$n<=$#ARGV;$n++) {
22 $n++;$coffee_page_length=$ARGV[$n];
23 } elsif ($arg eq "-s") {
24 $n++;$coffee_sector_size=$ARGV[$n];
25 } elsif ($arg eq "-t") {
26 $n++;$coffee_page_t =$ARGV[$n];
27 } elsif ($arg eq "-f") {
28 $n++;$coffee_name_length=$ARGV[$n];
29 } elsif ($arg eq "-S") {
30 $n++;$sectionname=$ARGV[$n];
31 } elsif ($arg eq "-c") {
33 } elsif ($arg eq "-l") {
35 } elsif ($arg eq "-v") {
36 print "avr-makecoffeedata Version $version\n";
37 } elsif ($arg eq "-d") {
38 $n++;$directory=$ARGV[$n];
39 } elsif ($arg eq "-o") {
40 $n++;$outputfile=$ARGV[$n];
44 $coffee_page_length=256;
45 $coffee_sector_size=256;
47 $coffee_name_length=16;
50 $outputfile="httpd-fsdata.c";
52 $sectionname=".coffeefiles";
53 if (!$version) {goto START
;}
55 print "Usage: avr-makecoffeedata <option(s)> <-d input_directory> <-o output_file>\n";
56 print " Generates c source file to make a pre-initialized coffee file system\n";
57 print " The default output file is $outputfile\n";
58 print " The input directory structure is copied. If input_directory is specified\n";
59 print " it becomes the root \"/\". If no input_directory is specified the first\n";
60 print " subdirectory found in the current directory is used as the root.\n";
61 print " WARNING : If the output file exists it will be overwritten without confirmation\n\n";
62 print " Options are:\n";
63 print " -p pagesize Page size in bytes (default $coffee_page_length)\n";
64 print " -s sectorsize Sector size in bytes (default $coffee_sector_size)\n";
65 print " -t page_t Number of bytes in coffee_page_t (1,2,or 4, default $coffee_page_t)\n";
66 print " -f namesize File name field size in bytes (default $coffee_name_length)\n";
67 print " -S section Section name (default $sectionname)\n";
68 print " -c Complement the data, useful when flash is all 1s after erase\n";
69 print " -l Append a linked list of the file starting addresses\n";
70 print " -v Display the version number\n";
75 #printf "coffee_page_length=$coffee_page_length\n";
76 #printf "coffee_page_t=$coffee_page_t\n";
77 #printf "coffee_name_length=$coffee_name_length\n";
78 #printf "complement=$complement\n";
79 #printf "directory=$directory\n";
80 #printf "outputfile=$outputfile\n";
81 #printf "sectionname=$sectionname;
83 if ($coffee_page_t==1) {
85 } elsif ($coffee_page_t==2) {
87 } elsif ($coffee_page_t==4) {
88 $coffeemax=0xffffffff;
90 die "Unsupported coffee_page_t $coffee_page_t\n";
92 $coffee_header_length=2*$coffee_page_t+$coffee_name_length+6;
93 $null="0x00";if ($complement) {$null="0xff";}
94 #$tab="/t"; #optional tab string
95 $tab=" "; #optional tabs or spaces at beginning of line, e.g. "\t\t"
97 if (!open(OUTPUT
, "> $outputfile")) {die "Aborted: Could not create output file $outputfile";}
98 #awkward but could not figure out how to compare paths later unless the file exists -- dak
101 use Cwd
qw(abs_path);
102 if (!open(OUTPUT
, "> $outputfile")) {die "Aborted: Could not create output file $outputfile";}
103 $outputfile=abs_path
($outputfile);
105 if ($directory eq "") {
107 @files = grep { !/^\./ && !/(CVS|~)/ } readdir(DIR
);
109 foreach $file (@files) {
110 if(-d
$file && $file !~ /^\./) {
116 if ($directory eq "") {die "Aborted: No subdirectory in current directory";}
117 if (!chdir("$directory")) {die "Aborted: Directory \"$directory\" does not exist!";}
119 print "Processing directory $directory as root of coffee file system\n";
121 @files = grep { !/^\./ && !/(CVS|~)/ } readdir(DIR
);
124 foreach $file (@files) {
125 if(-d
$file && $file !~ /^\./) {
126 print "Adding subdirectory $file\n";
128 @newfiles = grep { !/^\./ && !/(CVS|~)/ } readdir(DIR
);
130 # printf "Adding files @newfiles\n";
131 @files = (@files, map { $_ = "$file/$_" } @newfiles);
136 print "Writing to $outputfile\n";
137 print(OUTPUT
"/**************Generated by /tools/avr-makecoffeedata*****************/\n");
138 print(OUTPUT
"/*For coffee filesystem of sector size $coffee_sector_size and header length $coffee_header_length bytes*/\n");
140 $n=0;$coffeesize=0;$coffeesectors=0;
141 foreach $file (@files) {if(-f
$file) {
142 if (length($file)>($coffee_name_length-1)) {die "Aborted: File name $file is too long";}
144 if (abs_path
("$file") eq abs_path
("$outputfile")) {
145 print "Skipping $outputfile for recursive input\n";
148 print "Adding $file\n";
150 open(FILE
, $file) || die "Aborted: Could not open file $file\n";
151 if (grep /.png/,$file) {binmode FILE
;}
152 if (grep /.jpg/,$file) {binmode FILE
;}
153 if (grep /.gif/,$file) {binmode FILE
;}
159 $file_length= -s FILE
;
160 $coffee_sectors=int(($coffee_header_length+$file_length+$coffee_sector_size-1)/$coffee_sector_size);
161 # $coffee_sectors=sprintf("%.0f",($coffee_header_length+$file_length+$coffee_sector_size-1)/$coffee_sector_size)-1;
162 $coffee_length=$coffee_sectors*$coffee_sector_size;
163 $flen[$n]=$file_length;
164 $clen[$n]=$coffee_length;
165 $n++;$coffeesectors+=$coffee_sectors;$coffeesize+=$coffee_length;
166 if ($coffeesectors>$coffeemax) {
167 print "Warning: sector number $coffeesectors overflows allocated sector size in coffee header\n";
169 print(OUTPUT
"\n__attribute__ ((section (\"$sectionname\")))\n");
170 print(OUTPUT
"volatile const char data".$fvar."[$coffee_length] = {\n");
171 print(OUTPUT
"$tab/* $file */\n$tab ");
172 #--------------------Header-----------------------------
174 for($j=0;$j<$coffee_page_t;$j++) {print (OUTPUT
"$null, ");}
175 #log_records, log_record_size
176 for($j=0;$j<4;$j++) {print (OUTPUT
"$null, ");}
178 if ($complement) {$coffee_sectors=$coffee_sectors^0xffffffff;}
179 if ($coffee_page_t==1) {
180 printf(OUTPUT
"0x%2.2x, ",($coffee_sectors )&0xff);
181 } elsif ($coffee_page_t==2) {
182 printf(OUTPUT
"0x%2.2x, ",($coffee_sectors>> 8)&0xff);
183 printf(OUTPUT
"0x%2.2x, ",($coffee_sectors )&0xff);
184 } elsif ($coffee_page_t==4) {
185 printf(OUTPUT
"0x%2.2x, ",($coffee_sectors>>24)&0xff);
186 printf(OUTPUT
"0x%2.2x, ",($coffee_sectors>>16)&0xff);
187 printf(OUTPUT
"0x%2.2x, ",($coffee_sectors>> 8)&0xff);
188 printf(OUTPUT
"0x%2.2x, ",($coffee_sectors )&0xff);
190 if ($complement) {$coffee_sectors=$coffee_sectors^0xffffffff;}
193 print(OUTPUT
"0xff, 0xfc,\n$tab");
195 print(OUTPUT
"0x00, 0x03,\n$tab");
199 for($j = 0; $j < length($file); $j++) {
200 $temp=unpack("C", substr($file, $j, 1));
201 if ($complement) {$temp=$temp^0xff;}
202 printf(OUTPUT
" %#02.2x,", $temp);
204 for(; $j < $coffee_name_length; $j++) {printf(OUTPUT
" $null,");}
205 print(OUTPUT
"\n$tab");
206 #------------------File Data---------------------------
207 $coffee_length-=$coffee_header_length;
209 while(read(FILE
, $data, 1)) {
210 $temp=unpack("C", $data);
211 if ($complement) {$temp=$temp^0xff;}
212 printf(OUTPUT
" 0x%2.2x,", $temp);
213 $i++;$coffee_length--;
215 print(OUTPUT
"\n$tab");
219 while (--$coffee_length>1) {
220 print (OUTPUT
" $null,");
222 print(OUTPUT
"\n$tab");
226 print (OUTPUT
" $null};\n");
229 push(@pfiles, $file);
233 #-------------------httpd_fsdata_file links-------------------
234 #The non-coffee PROGMEM flash file system for the Raven webserver uses a linked flash list as follows:
235 print(OUTPUT
"\n\n/* Structure of linked list (all offsets relative to start of section):\n");
236 print(OUTPUT
"struct httpd_fsdata_file {\n");
237 print(OUTPUT
"$tab const struct httpd_fsdata_file *next; //actual flash address of next link\n");
238 print(OUTPUT
"$tab const char *name; //offset to coffee file name\n");
239 print(OUTPUT
"$tab const char *data; //offset to coffee file data\n");
240 print(OUTPUT
"$tab const int len; //length of file data\n");
241 print(OUTPUT
"#if HTTPD_FS_STATISTICS == 1 //not enabled since list is in PROGMEM\n");
242 print(OUTPUT
"$tab u16_t count; //storage for file statistics\n");
243 print(OUTPUT
"#endif\n");
244 print(OUTPUT
"}\n*/\n");
246 # Note flash addresses above 0xffff require 32 bit pointers using pgm_read_byte_far,
247 # and the coffee file system is above that. So the addresses start from 0 which
248 # allows a 64K file system. The flash starting address is added in the read routine.
250 print(OUTPUT
"\n#define HTTPD_FS_ROOT file$fvars[$i - 1]\n\n");
252 for($i = 0; $i < @fvars; $i++) {
259 $data_offset=$data_offset+$clen[$i-1];
260 $prevfile = "file" . $fvars[$i - 1];
262 $filename_offset=$data_offset+6+2*$coffee_page_t;
263 $coffee_offset=$data_offset+$coffee_header_length;
264 if ($coffee_offset>0xffff) {print "Warning : Linked list offset field overflow\n";}
266 print(OUTPUT
"const struct httpd_fsdata_file");
267 for ($t=length($file);$t<16;$t++) {print(OUTPUT
" ")};
268 # for AVR, add PROGMEM here
269 print(OUTPUT
" file".$fvar."[] PROGMEM={{");
270 for ($t=length($prevfile);$t<20;$t++) {print(OUTPUT
" ")};
271 print(OUTPUT
"$prevfile, ");
272 printf(OUTPUT
"(const char *)0x%4.4x, ",$filename_offset);
273 printf(OUTPUT
"(const char *)0x%4.4x, ",$coffee_offset);
274 printf(OUTPUT
"%5u}};\n",$flen[$i]);
276 print(OUTPUT
"\n#define HTTPD_FS_NUMFILES $i\n");
278 print "All done, preallocated coffee files occupy $coffeesize bytes\n";