| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182 | #!/usr/bin/perluse 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;
 |