From 450aa16a5bc30dcaeca2a9ce52d208d5406aed53 Mon Sep 17 00:00:00 2001 From: dak664 Date: Wed, 15 Jul 2009 22:06:23 +0000 Subject: [PATCH] Added input args and optional complemented output --- tools/avr-makecoffeedata | 235 +++++++++++++++++++++++++++++++-------- 1 file changed, 189 insertions(+), 46 deletions(-) diff --git a/tools/avr-makecoffeedata b/tools/avr-makecoffeedata index af53b65fd..b8ef7b985 100644 --- a/tools/avr-makecoffeedata +++ b/tools/avr-makecoffeedata @@ -1,7 +1,7 @@ #!/usr/bin/perl #Generate a .c source that preinitializes a coffee file system #David Kopf July 2009 -#Assumes coffee file_header structure is +#For coffee file_header structure of #struct file_header { # coffee_page_t log_page; # uint16_t log_records; @@ -11,40 +11,143 @@ # uint8_t flags; # char name[COFFEE_NAME_LENGTH]; # } __attribute__((packed)); + +goto DEFAULTS; +START:$version="1.0 dak"; + +#Process options +for($n=0;$n<=$#ARGV;$n++) { + $arg=$ARGV[$n]; + if ($arg eq "-p") { + $n++;$coffee_page_length=$ARGV[$n]; + } elsif ($arg eq "-s") { + $n++;$coffee_sector_size=$ARGV[$n]; + } elsif ($arg eq "-t") { + $n++;$coffee_page_t =$ARGV[$n]; + } elsif ($arg eq "-f") { + $n++;$coffee_name_length=$ARGV[$n]; + } elsif ($arg eq "-S") { + $n++;$sectionname=$ARGV[$n]; + } elsif ($arg eq "-c") { + $complement=1; + } elsif ($arg eq "-l") { + $linkedlist=1; + } elsif ($arg eq "-v") { + print "avr-makecoffeedata Version $version\n"; + } elsif ($arg eq "-d") { + $n++;$directory=$ARGV[$n]; + } elsif ($arg eq "-o") { + $n++;$outputfile=$ARGV[$n]; + } else { +DEFAULTS: +#Set up defaults +$coffee_page_length=256; +$coffee_sector_size=256; $coffee_page_t=1; $coffee_name_length=16; +$complement=0; +$directory=""; +$outputfile="httpd-fsdata.c"; +$linkedlist=0; +$sectionname=".coffeefiles"; +if (!$version) {goto START;} + print "\n"; + print "Usage: avr-makecoffeedata <-d input_directory> <-o output_file>\n"; + print " Generates c source file to make a pre-initialized coffee file system\n"; + print " The default output file is $outputfile\n"; + print " The input directory structure is copied. If input_directory is specified\n"; + print " it becomes the root \"/\". If no input_directory is specified the first\n"; + print " subdirectory found in the current directory is used as the root.\n"; + print " WARNING : If the output file exists it will be overwritten without confirmation\n\n"; + print " Options are:\n"; + print " -p pagesize Page size in bytes (default $coffee_page_length)\n"; + print " -s sectorsize Sector size in bytes (default $coffee_sector_size)\n"; + print " -t page_t Number of bytes in coffee_page_t (1,2,or 4, default $coffee_page_t)\n"; + print " -f namesize File name field size in bytes (default $coffee_name_length)\n"; + print " -S section Section name (default $sectionname)\n"; + print " -c Complement the data, useful when flash is all 1s after erase\n"; + print " -l Append a linked list of the file starting addresses\n"; + print " -v Display the version number\n"; + exit; + } +} + +#printf "coffee_page_length=$coffee_page_length\n"; +#printf "coffee_page_t=$coffee_page_t\n"; +#printf "coffee_name_length=$coffee_name_length\n"; +#printf "complement=$complement\n"; +#printf "directory=$directory\n"; +#printf "outputfile=$outputfile\n"; +#printf "sectionname=$sectionname; + +if ($coffee_page_t==1) { + $coffeemax=0xff; +} elsif ($coffee_page_t==2) { + $coffeemax=0xffff; +} elsif ($coffee_page_t==4) { + $coffeemax=0xffffffff; +} else { + die "Unsupported coffee_page_t $coffee_page_t\n"; +} $coffee_header_length=2*$coffee_page_t+$coffee_name_length+6; -#coffee_sector_size is the number of bytes in the smallest allocated block of the coffee file system -$coffee_sector_size=256; +$null="0x00";if ($complement) {$null="0xff";} +#$tab="/t"; #optional tab string +$tab=" "; #optional tabs or spaces at beginning of line, e.g. "\t\t" -open(OUTPUT, "> httpd-coffeefsdata.c"); +if (!open(OUTPUT, "> $outputfile")) {die "Aborted: Could not create output file $outputfile";} +#awkward but could not figure out how to compare paths later unless the file exists -- dak +print(OUTPUT "\n"); +close($outputfile); +use Cwd qw(abs_path); +if (!open(OUTPUT, "> $outputfile")) {die "Aborted: Could not create output file $outputfile";} +$outputfile=abs_path($outputfile); -chdir("httpd-fs"); +if ($directory eq "") { + opendir(DIR, "."); + @files = grep { !/^\./ && !/(CVS|~)/ } readdir(DIR); + closedir(DIR); + foreach $file (@files) { + if(-d $file && $file !~ /^\./) { + $directory=$file; + break; + } + } +} +if ($directory eq "") {die "Aborted: No subdirectory in current directory";} +if (!chdir("$directory")) {die "Aborted: Directory \"$directory\" does not exist!";} +print "Processing directory $directory as root of coffee file system\n"; opendir(DIR, "."); @files = grep { !/^\./ && !/(CVS|~)/ } readdir(DIR); closedir(DIR); foreach $file (@files) { -# $dirname = fileparse($file); if(-d $file && $file !~ /^\./) { - print "Processing directory $file\n"; + print "Adding subdirectory $file\n"; opendir(DIR, $file); @newfiles = grep { !/^\./ && !/(CVS|~)/ } readdir(DIR); closedir(DIR); - printf "Adding files @newfiles\n"; +# printf "Adding files @newfiles\n"; @files = (@files, map { $_ = "$file/$_" } @newfiles); next; } } + +print "Writing to $outputfile\n"; print(OUTPUT "/**************Generated by /tools/avr-makecoffeedata*****************/\n"); print(OUTPUT "/*For coffee filesystem of sector size $coffee_sector_size and header length $coffee_header_length bytes*/\n"); +$n=0;$coffeesize=0;$coffeesectors=0; foreach $file (@files) {if(-f $file) { - if (length($file)>($coffee_name_length-1)) {die "$file: name is too long!";} - print "Adding file $file\n"; + if (length($file)>($coffee_name_length-1)) {die "Aborted: File name $file is too long";} + + if (abs_path("$file") eq abs_path("$outputfile")) { + print "Skipping $outputfile for recursive input\n"; + next; + } + print "Adding $file\n"; - open(FILE, $file) || die "Could not open file $file\n"; + open(FILE, $file) || die "Aborted: Could not open file $file\n"; if (grep /.png/,$file) {binmode FILE;} if (grep /.jpg/,$file) {binmode FILE;} if (grep /.gif/,$file) {binmode FILE;} @@ -57,18 +160,24 @@ foreach $file (@files) {if(-f $file) { $coffee_sectors=int(($coffee_header_length+$file_length+$coffee_sector_size-1)/$coffee_sector_size); # $coffee_sectors=sprintf("%.0f",($coffee_header_length+$file_length+$coffee_sector_size-1)/$coffee_sector_size)-1; $coffee_length=$coffee_sectors*$coffee_sector_size; - # for AVR, add PROGMEM here - print(OUTPUT "\n__attribute__ ((section (\".coffeedata\")))\n"); - print(OUTPUT "static const char data".$fvar."[$coffee_length] PROGMEM = {\n"); - print(OUTPUT "\t/* $file */\n\t "); + $flen[$n]=$file_length; + $clen[$n]=$coffee_length; + $n++;$coffeesectors+=$coffee_sectors;$coffeesize+=$coffee_length; + if ($coffeesectors>$coffeemax) { + print "Warning: sector number $coffeesectors overflows allocated sector size in coffee header\n"; + } + print(OUTPUT "\n__attribute__ ((section (\"$sectionname\")))\n"); + print(OUTPUT "volatile const char data".$fvar."[$coffee_length] = {\n"); + print(OUTPUT "$tab/* $file */\n$tab "); #--------------------Header----------------------------- #log_page - for($j=0;$j<$coffee_page_t;$j++) {print (OUTPUT "0x00, ");} + for($j=0;$j<$coffee_page_t;$j++) {print (OUTPUT "$null, ");} #log_records, log_record_size - for($j=0;$j<4;$j++) {print (OUTPUT "0x00, ");} + for($j=0;$j<4;$j++) {print (OUTPUT "$null, ");} #max_pages - if ($coffee_page_t==1) { - printf(OUTPUT "0x%2.2x, ",$coffee_sectors); + if ($complement) {$coffee_sectors=$coffee_sectors^0xffffffff;} + if ($coffee_page_t==1) { + printf(OUTPUT "0x%2.2x, ",($coffee_sectors )&0xff); } elsif ($coffee_page_t==2) { printf(OUTPUT "0x%2.2x, ",($coffee_sectors>> 8)&0xff); printf(OUTPUT "0x%2.2x, ",($coffee_sectors )&0xff); @@ -77,59 +186,93 @@ foreach $file (@files) {if(-f $file) { printf(OUTPUT "0x%2.2x, ",($coffee_sectors>>16)&0xff); printf(OUTPUT "0x%2.2x, ",($coffee_sectors>> 8)&0xff); printf(OUTPUT "0x%2.2x, ",($coffee_sectors )&0xff); - } else { - die "Unsupported coffee_page_t $coffee_page_t\n"; } + if ($complement) {$coffee_sectors=$coffee_sectors^0xffffffff;} #eof hint and flags - print(OUTPUT "0x00, 0x03,\n\t"); + if ($complement) { + print(OUTPUT "0xff, 0xfc,\n$tab"); + } else { + print(OUTPUT "0x00, 0x03,\n$tab"); + } + #file name for($j = 0; $j < length($file); $j++) { - printf(OUTPUT " %#02.2x,", unpack("C", substr($file, $j, 1))); + $temp=unpack("C", substr($file, $j, 1)); + if ($complement) {$temp=$temp^0xff;} + printf(OUTPUT " %#02.2x,", $temp); } - for(; $j < $coffee_name_length; $j++) { - printf(OUTPUT " 0x00,"); - } - print(OUTPUT "\n\t"); + for(; $j < $coffee_name_length; $j++) {printf(OUTPUT " $null,");} + print(OUTPUT "\n$tab"); #------------------File Data--------------------------- - $coffee_length-=$coffee_header_length; + $coffee_length-=$coffee_header_length; $i = 0; - while(read(FILE, $data, 1)) { - # printf(OUTPUT " %#2.2x,", unpack("C", $data)); - printf(OUTPUT " 0x%2.2x,", unpack("C", $data)); + while(read(FILE, $data, 1)) { + $temp=unpack("C", $data); + if ($complement) {$temp=$temp^0xff;} + printf(OUTPUT " 0x%2.2x,", $temp); $i++;$coffee_length--; if($i == 10) { - print(OUTPUT "\n\t"); + print(OUTPUT "\n$tab"); $i = 0; } } while (--$coffee_length>1) { - print (OUTPUT " 0x00,"); - if($i++ == 9) { - print(OUTPUT "\n\t"); - $i = 0; - } + print (OUTPUT " $null,"); + if($i++ == 9) { + print(OUTPUT "\n$tab"); + $i = 0; + } } - print (OUTPUT " 0x00};\n"); + print (OUTPUT " $null};\n"); close(FILE); push(@fvars, $fvar); push(@pfiles, $file); }} +if ($linkedlist) { +#-------------------httpd_fsdata_file links------------------- +#The non-coffee PROGMEM flash file system for the Raven webserver uses a linked flash list as follows: +print(OUTPUT "\n\n/* Structure of linked list (all offsets relative to start of section):\n"); +print(OUTPUT "struct httpd_fsdata_file {\n"); +print(OUTPUT "$tab const struct httpd_fsdata_file *next; //actual flash address of next link\n"); +print(OUTPUT "$tab const char *name; //offset to coffee file name\n"); +print(OUTPUT "$tab const char *data; //offset to coffee file data\n"); +print(OUTPUT "$tab const int len; //length of file data\n"); +print(OUTPUT "#if HTTPD_FS_STATISTICS == 1 //not enabled since list is in PROGMEM\n"); +print(OUTPUT "$tab u16_t count; //storage for file statistics\n"); +print(OUTPUT "#endif\n"); +print(OUTPUT "}\n*/\n"); + +# Note flash addresses above 0xffff require 32 bit pointers using pgm_read_byte_far, +# and the coffee file system is above that. So the addresses start from 0 which +# allows a 64K file system. The flash starting address is added in the read routine. + +print(OUTPUT "\n#define HTTPD_FS_ROOT file$fvars[$i - 1]\n\n"); for($i = 0; $i < @fvars; $i++) { $file = $pfiles[$i]; $fvar = $fvars[$i]; - if($i == 0) { $prevfile = "NULL"; + $data_offset=0; } else { + $data_offset=$data_offset+$clen[$i-1]; $prevfile = "file" . $fvars[$i - 1]; } -# for AVR, add PROGMEM here - print(OUTPUT "const struct httpd_fsdata_file file".$fvar."[] PROGMEM = {{$prevfile, data$fvar, "); - print(OUTPUT "data$fvar + ". (length($file) + 1) .", "); - print(OUTPUT "sizeof(data$fvar) - ". (length($file) + 1) ."}};\n\n"); -} + $filename_offset=$data_offset+6+2*$coffee_page_t; + $coffee_offset=$data_offset+$coffee_header_length; + if ($coffee_offset>0xffff) {print "Warning : Linked list offset field overflow\n";} -print(OUTPUT "#define HTTPD_FS_ROOT file$fvars[$i - 1]\n\n"); -print(OUTPUT "#define HTTPD_FS_NUMFILES $i\n"); + print(OUTPUT "const struct httpd_fsdata_file"); + for ($t=length($file);$t<16;$t++) {print(OUTPUT " ")}; + # for AVR, add PROGMEM here + print(OUTPUT " file".$fvar."[] PROGMEM={{"); + for ($t=length($prevfile);$t<20;$t++) {print(OUTPUT " ")}; + print(OUTPUT "$prevfile, "); + printf(OUTPUT "(const char *)0x%4.4x, ",$filename_offset); + printf(OUTPUT "(const char *)0x%4.4x, ",$coffee_offset); + printf(OUTPUT "%5u}};\n",$flen[$i]); +} +print(OUTPUT "\n#define HTTPD_FS_NUMFILES $i\n"); +} +print "All done, preallocated coffee files occupy $coffeesize bytes\n";