Device-AVR-UPDI
view release on metacpan or search on metacpan
bin/avr-updi view on Meta::CPAN
$RESET_REQUIRED++;
}
# IO formats
package main::Fileformat {
use base 'IO::Handle';
sub open_out {
my $class = shift;
my $fh;
if( $_[0] eq "-" ) {
$fh = IO::Handle->new_from_fd( STDOUT->fileno, "w" );
}
else {
open $fh, ">", $_[0] or die "Cannot write $_[0] - $!\n";
}
return bless $fh, $class;
}
sub open_in {
my $class = shift;
my $fh;
if( $_[0] eq "-" ) {
$fh = IO::Handle->new_from_fd( STDIN->fileno, "r" );
}
else {
open $fh, "<", $_[0] or die "Cannot read $_[0] - $!\n";
}
return bless $fh, $class;
}
}
package main::Fileformat::Binary {
use base 'main::Fileformat';
sub output {
my $self = shift;
my ( $bytes ) = @_;
$self->print( $bytes );
}
sub input {
my $self = shift;
local $/;
return scalar <$self>;
}
sub input_chunks {
my $self = shift;
return [ 0, $self->input ];
}
}
package main::Fileformat::IntelHex {
use base 'main::Fileformat';
# Because this file format was invented for Intel x86 in the 16-bit era,
# we have to account for its crazy 16bit offset + 16bit segment == 20bit
# linear addressing madness.
sub print_record {
my $self = shift;
my ( $addr, $type, $data ) = @_;
my $clen = length $data;
my $cksum = $clen + ( $addr & 0xFF ) + ( $addr >> 8 ) + $type;
my $encdata = "";
( $encdata .= sprintf "%02X", ord $_), ( $cksum += ord $_ )
for split //, $data;
$self->printf( ":%02X%04X%02X%s%02X\n",
$clen, $addr, $type, $encdata, ( -$cksum ) & 0xFF );
}
sub output_chunk {
my $self = shift;
my ( $addr, $bytes ) = @_;
my $segaddr = 0;
foreach my $data ( $bytes =~ m/(.{1,16})/gs ) {
my $hiaddr = $addr & 0xFFFF0000;
if( $segaddr << 4 != $hiaddr ) {
$segaddr = $hiaddr >> 4;
$self->print_record( 0, 0x02, pack "S>", $segaddr );
}
$self->print_record( $addr & 0xFFFF, 0x00, $data );
$addr += length $data;
}
}
sub output {
my $self = shift;
my ( $bytes ) = @_;
my $addr = 0;
my $chunk = "";
foreach my $data ( $bytes =~ m/(.{1,16})/gs ) {
if( $data !~ m/[^\xff]/ ) {
# data contains only 0xFF bytes.
if( length $chunk ) {
# Write the current chunk then reset it
my $chunkaddr = $addr;
$addr += length $chunk;
$chunk =~ s/\xFF+$//;
$self->output_chunk( $chunkaddr, $chunk );
$chunk = "";
}
$addr += length $data;
}
else {
$chunk .= $data;
}
}
if( length $chunk ) {
$self->output_chunk( $addr, $chunk );
}
$self->print_record( 0, 0x01, "" );
}
sub input {
my $self = shift;
my $bytes = "";
foreach my $chunk ( $self->input_chunks ) {
my ( $addr, $chunkbytes ) = @$chunk;
( run in 0.686 second using v1.01-cache-2.11-cpan-6aa56a78535 )