123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182 |
- #!/usr/bin/perl
- use strict;
- use integer;
- use PerlIO::gzip;
- use File::Temp;
- use File::Spec;
- my $esptool = ($^O eq 'MSWin32') ? 'esptool.exe' : 'esptool.py';
- $esptool = $ENV{'ESPTOOL'} || $esptool;
- my $FW_MAGIC = 0x7a07fbd6;
- my %datatypes = (
- 'end' => 0, # End of data
- 'data' => 1, # FPGA flash data
- 'target' => 2, # Firmware target string
- 'note' => 3, # Informative string
- 'espota' => 4, # ESP32 OTA image
- 'fpgainit' => 5, # FPGA bypass (transient) image during update
- 'esppart' => 6, # ESP32 partition table
- 'espsys' => 7, # ESP32 boot loader, OTA control partition...
- 'esptool' => 8 # esptool.py options for flashing
- );
- my @type;
- foreach my $t (keys(%datatypes)) {
- $type[$datatypes{$t}] = $t;
- }
- my $FDF_OPTIONAL = 0x0001;
- my $STRING_MAX_LEN = 4095;
- sub getint($) {
- my($s) = @_;
- return undef
- unless ($s =~ /^(([1-9][0-9]+)|(0(x[0-9a-f]+|[0-7]*)))([kmgtpe]?)$/i);
- my $o = oct($3) + $2;
- my $p = lc($5);
- if ($p eq 'k') {
- $o <<= 10;
- } elsif ($p eq 'm') {
- $o <<= 20;
- } elsif ($p eq 'g') {
- $o <<= 30;
- } elsif ($p eq 't') {
- $o <<= 40;
- } elsif ($p eq 'p') {
- $o <<= 50;
- } elsif ($p eq 'e') {
- $o <<= 60;
- }
- return $o;
- }
- sub filelen($) {
- my($f) = @_;
- my @s = stat($f);
- return $s[7];
- }
- sub unquote_cmd($) {
- my($s) = @_;
- my @a;
- $s =~ s/[\r\n]+/ /g;
- while ($s =~ /^\s*(?:\"((?:[^\"]+|\"\")*)\"|(\S+))(\s.*)?$/) {
- push(@a, $1.$2);
- $s = $3;
- }
- return @a;
- }
- my @args = @ARGV;
- my $file = shift(@args);
- if (!defined($file)) {
- die "Usage: $0 fwfile [esptool options...]\n";
- }
- open(my $fw, '<:gzip', $file)
- or die "$0: $file: $!\n";
- my @chunks = ();
- my $err = 0;
- my $hdr;
- while (read($fw, $hdr, 16) == 16) {
- # magic type flags data_len addr
- my @h = unpack('VvvVV', $hdr);
- my $c = { 'hdr' => $hdr, 'magic' => $h[0], 'type' => $h[1],
- 'flags' => $h[2], 'len' => $h[3], 'addr' => $h[4] };
- if ($c->{'magic'} != $FW_MAGIC) {
- print STDERR "$0: $file: bad chunk magic\n";
- $err = 1;
- last;
- }
- my $t = $type[$c->{'type'}];
- last if ($t eq 'end'); # End of stream
- my $d;
- if (read($fw, $d, $c->{'len'}) != $c->{'len'}) {
- print STDERR "$0: $file: short chunk read\n";
- $err = 1;
- last;
- }
- $c->{'data'} = $d;
- push(@chunks, $c);
- }
- close($fw);
- exit $err if ($err);
- my $td = File::Temp->newdir(CLEANUP => 1);
- my @espfiles = ();
- my %espopt = ('before' => 'default_reset', 'after' => 'hard_reset',
- 'baud' => 115200, 'port' => undef, 'chip' => undef,
- 'flash_mode' => undef, 'flash_freq' => undef,
- 'flash_size' => undef);
- my $nc = 0;
- foreach my $c ( @chunks ) {
- my $t = $type[$c->{'type'}];
- if ($t eq 'esptool') {
- my $s = $c->{'data'};
- $s =~ s/[\r\n]+/ /g;
- while ($s =~ /^\s*(\S+)\s+(\S+)(.*)/) {
- $espopt{$1} = $2;
- $s = $3;
- }
- } elsif ($t =~ /^esp/ && $c->{'addr'}) {
- my $addr = sprintf('%x', $c->{'addr'});
- my $tff = File::Spec->catfile($td, $t.$nc.'_'.$addr.'.bin');
- open(my $tf, '>', $tff) or die "$0: $tff: $!\n";
- print $tf $c->{'data'};
- close($tf);
- push(@espfiles, '0x'.$addr, $tff);
- }
- $nc++;
- }
- foreach my $e (keys %espopt) {
- my $ev = $ENV{"ESP\U$e"};
- if (defined($ev)) {
- $espopt{$e} = $ev;
- }
- }
- my @espcmd = unquote_cmd($esptool);
- foreach my $o (sort grep (!/^flash_/, keys %espopt)) {
- if (defined($espopt{$o})) {
- push(@espcmd, "--$o", $espopt{$o});
- }
- }
- push(@espcmd, @args);
- push(@espcmd, 'write_flash', '-z');
- foreach my $o (sort grep (/^flash_/, keys %espopt)) {
- if (defined($espopt{$o})) {
- push(@espcmd, "--$o", $espopt{$o});
- }
- }
- push(@espcmd, @espfiles);
- if (defined($ENV{'VERBOSE'})) {
- print STDERR join(' ', @espcmd), "\n";
- }
- $err = system(@espcmd);
- if ($err == -1) {
- print STDERR "$0: $espcmd[0]: $!\n";
- }
- exit !!$err;
|