File Coverage

blib/lib/Hex/Parser.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package Hex::Parser;
2 1     1   21490 use strict;
  1         3  
  1         26  
3 1     1   5 use warnings;
  1         2  
  1         30  
4              
5 1     1   755 use parent 'Exporter';
  1         319  
  1         5  
6             our @EXPORT_OK = qw(
7             parse_intel_hex
8             parse_srec_hex);
9              
10             our $VERSION = '0.01';
11              
12 1     1   593 use Hex;
  0            
  0            
13              
14             sub parse_intel_hex {
15             my ( $file ) = @_;
16              
17             open(my $fh, '<', $file) || die "could not open $file: $!";
18              
19             my $hex = Hex->new;
20             my $addr_high_dec = 0;
21              
22             my @hex_parts;
23             while ( my $line = <$fh> ){
24             $line =~ m{
25             : # intel hex start
26             [[:xdigit:]]{2} # bytecount
27             ([[:xdigit:]]{4}) # addr
28             ([[:xdigit:]]{2}) # type
29             ([[:xdigit:]] * ) # databytes
30             [[:xdigit:]]{2} # checksum
31             }ix or next;
32              
33             my $intel_type_dec = $2;
34             my @bytes_hex = unpack( '(A2)*', $3 );
35              
36             # data line?
37             if ( $intel_type_dec == 0 ) {
38             push @hex_parts, [ $addr_high_dec + hex($1), \@bytes_hex ];
39             }
40              
41             # extended linear address type?
42             elsif ( $intel_type_dec == 4 ) {
43             $addr_high_dec = hex( join '', @bytes_hex ) << 16;
44             }
45              
46             # extended segment address type?
47             elsif ( $intel_type_dec == 2 ) {
48             $addr_high_dec = hex( join '', @bytes_hex ) << 4;
49             }
50             }
51              
52              
53             $hex->_set_merged_parts([ sort { $a->[0] <=> $b->[0] } @hex_parts ] );
54             return $hex;
55             }
56              
57             my %_address_length_of_srec_type = (
58             0 => '4',
59             1 => '4',
60             2 => '6',
61             3 => '8',
62             4 => undef,
63             5 => '4',
64             6 => '6',
65             7 => '8',
66             8 => '6',
67             9 => '4',
68             );
69              
70             sub parse_srec_hex {
71             my ( $file ) = @_;
72              
73             open my $fh, '<', $file || die "could not open file: $!";
74              
75             my $hex = Hex->new;
76              
77             my @hex_parts;
78             while ( my $line = <$fh> ){
79             next unless substr( $line, 0, 1 ) =~ m{s}i;
80              
81             my $type = substr $line, 1, 1;
82              
83             my $addr_length = $_address_length_of_srec_type{$type};
84              
85             $line =~ m{
86             s #srec hex start
87             ([[:xdigit:]]{1}) #type
88             [[:xdigit:]]{2} #bytecount
89             ([[:xdigit:]]{$addr_length}) #addr
90             ([[:xdigit:]] * ) #databytes
91             [[:xdigit:]]{2} #checksum
92             }ix or next;
93              
94             #data line?
95             if ( $1 == 0 || $1 == 1 || $1 == 2 || $1 == 3) {
96             push @hex_parts, [ hex $2, [ unpack '(A2)*', $3 ] ];
97             }
98             }
99              
100             $hex->_set_merged_parts( [ sort { $a->[0] <=> $b->[0] } @hex_parts ] );
101              
102             #sort the bytes of the record
103             return $hex;
104             }
105              
106             1;
107              
108              
109             =head1 NAME
110              
111             Hex::Parser - parse intel and srec hex records
112              
113             =head1 SYNOPSIS
114              
115             use Hex::Parser qw(parse_intel_hex parse_srec_hex);
116              
117             # for intel hex record
118             my $hex = parse_intel_hex( 'intel.hex' );n
119              
120             # for srec hex record
121             my $hex = parse_srec_hex( 'srec.hex' );
122              
123             # get 100 bytes ( hex format ) starting at address 0x100
124             # every single byte that is not found is returned as undef
125             my $bytes_ref = $hex->get( 0x100, 10 );
126              
127             # remove 100 bytes strting at address 0x100
128             $hex->remove( 0x100, 10 );
129              
130             # write/overwrite 3 bytes starting at address 0x100
131             $hex->write( 0x100, [ 'AA', 'BB', 'CC' ] );
132              
133             # dump as intel hex ( will use extended linear addresses of 32 bit addresses )
134             # maximum of 10 bytes in data field
135             $hex->as_intel_hex( 10, $file_handle );
136              
137             # dump as srec hex ( always tries to use smallest address )
138             # maximum of 10 bytes in data field
139             $hex->as_screc_hex( 10, $file_handle );
140              
141             =head1 DESCRIPTION
142              
143             Manipulate intel/srec hex files.
144              
145             =head2 Functions
146              
147             =over 12
148              
149             =item C
150              
151             Exported by Hex::Parser
152             Parses intel hex file. Returns Hex object.
153              
154             =item C
155              
156             Exported by Hex::Parser
157             Parses srec hex file. Returns Hex object.
158              
159             =back
160              
161             =head2 Methods of Hex
162              
163             =over 12
164              
165             =item C
166              
167             Returns $count hex bytes in array reference starting at address $from.
168             If byte is not found, undef instead.
169              
170             C<[ 'AA', '00', undef, undef, 'BC', undef ]>
171              
172             =item C
173              
174             Removes $count bytes starting at address $from.
175              
176             =item C
177              
178             (Over)Writes bytes starting at address $from with bytes in $bytes_ref.
179              
180             =item C
181              
182             Writes data as intel hex into file hanlde. Maximum of $hytes_hex_a_line in data field.
183             Extended linear addresses as offset are used if needed.
184             Extended segment addresses are not supported.
185              
186             =item C
187              
188             Writes data as srec into file hanlde. Maximum of $hytes_hex_a_line in data field.
189             Tries to use the smallest address field.
190              
191             =back
192              
193             =head1 LICENSE
194              
195             This is released under the Artistic License.
196              
197             =head1 AUTHOR
198              
199             spebern
200              
201             =cut
202              
203              
204              
205