#!/usr/bin/perl
# convert binary mitsubishi J2S firmware to motorola S-rec format
# check and recalculate the checksum at the end of the file
# (c) 2010, yurtaev@gmail.com

sub s0 {
	my $s = shift;

	print STDERR "writing $s\n";

	$s = sprintf("%s", chr(length($s) + 1)) . $s;
	my $cs = chr(~int(unpack("%8C*", $s)) & 0xff);
	return "S0" . uc(unpack("H*", $s . $cs)) . "\n";
	
}

my $name = $ARGV[0];

open(IN, "<", $name) || die "can't open $ARGV[0]\n";
binmode IN;

undef $/;

my $in = <>;
my $cs = unpack("%16n*", $in);

if($cs != 0x5a5a) {
	printf STDERR "checksum: %04X, fixing...\n", $cs;
	if($in =~ /([^\377]{2})(?=\377+$)/mg) {
		my $pos = pos($in) - 2;
		#$pos = 0x26dac;
		my $old = unpack("n", $1);#
		#$old = unpack("n", substr($in, $pos, 2));
		my $new = ($old - ($cs - 0x5a5a)) & 0xffff;
		substr($in, $pos, 2, pack("n", $new));
		printf STDERR "checksum: old %04x, new %04x at %05x\n", $old, $new, $pos;
	} else {
		printf STDERR "can't find checksum position!";
	}
}

close IN;

open(IN, "<", \$in) || die "can't open string!\n";
binmode IN;

my $a = 0x0000;

print s0($name);

while(!eof(IN)) {
	my $s;
	my $l = read(IN, $s, 16);
#	my $l = "\x0A\x0A\x0D\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
	$s = sprintf("%s%s%s%s%s", chr(length($s) + 5), chr($a>>24), chr($a>>16), chr($a>>8), chr($a)) . $s;
	my $cs = chr(~int(unpack("%8C*", $s)) & 0xff);
	print "S3", uc(unpack("H*", $s . $cs)), "\n";
	$a += $l;
}
