View Single Post
Old Tue, Dec-11-2012, 02:05:07 PM   #418
p0lar
Naturally Agitated
 
p0lar's Avatar
 
Join Date: Sep 2005
Posts: 3,553
In the garage:
Reputation: 0 p0lar will become famous soon enough

United States




Default Re: Comprehensive MSS54/MSS54HP DME Information

Here is a PROPERLY executed .0DA to binary converter written in Perl. It doesn't calculate/correct the checksums, but you can use the script located here for that. This script works on all MSS50, MSS52, MSS54 and MSS54HP .0DA files tested.

Syntax:
0da2bin.pl --input=<version.0da>
Code:
#!/usr/bin/perl -w

#    Copyright (c) 2012, 2013 p0lar @ m3forum.net
#
#    Redistribution and use in source and binary forms, with or without
#    modification, are permitted provided that the following conditions
#    are met:
#    1. Redistributions of source code must retain the above copyright
#       notice, this list of conditions and the following disclaimer.
#    2. Redistributions in binary form must reproduce the above copyright
#       notice, this list of conditions and the following disclaimer in the
#       documentation and/or other materials provided with the distribution.
#    3. All advertising materials mentioning features or use of this software
#       must display the following acknowledgement:
#	This product includes software developed by p0lar @ m3forum.net and its
#       contributors
#    4. Neither the name of p0lar @ m3forum.net nor the names of its
#       contributors may be used to endorse or promote products derived from
#       this software without specific prior written permission.
#
#    THIS SOFTWARE IS PROVIDED BY P0LAR @ M3FORUM.NET AND CONTRIBUTORS ``AS IS''
#    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
#    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
#    ARE DISCLAIMED.  IN NO EVENT SHALL P0LAR @ M3FORUM.NET OR CONTRIBUTORS BE
#    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
#    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
#    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
#    INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
#    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
#    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
#    POSSIBILITY OF SUCH DAMAGE.
#
#    NO WARRANTY
#
#    BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
#    FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
#    OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
#    PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
#    OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
#    MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
#    TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
#    PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
#    REPAIR OR CORRECTION.
#
#    IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
#    WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
#    REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
#    INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
#    OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
#    TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
#    YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
#    PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
#    POSSIBILITY OF SUCH DAMAGES.
#

use strict;
use File::Basename;
use Data::Dumper; $Data::Dumper::Indent = 1; $Data::Dumper::Sortkeys = 1;
use Getopt::Long;

# essential configuration variables
my %config = (
  'version'          => '0.1.9',
  'debug'            => 0,
  'help'             => 0,
  'overwrite'        => 0,
  'silent'           => 0,
  'bin_ext'          => '.bin',
);

# handle command line options
GetOptions(
  'help|?|h'    => \$config{'help'},
  'input|i=s'   => \$config{'file_in'},
  'output|o=s'  => \$config{'file_out'},
  'debug|d'     => \$config{'debug'},
  'writeover|w' => \$config{'overwrite'},
  'silent|s'    => \$config{'silent'}, # reserved for future use
  'version|v'   => \$config{'displayVersion'},
);

# Display version or usage information if requested (or implicitly)
&version if (defined($config{'displayVersion'}));
&usage unless (defined($config{'file_in'}) || $config{'help'});

# Check to see if the binary actually exists, is readable, is binary and is of the proper size
die ("No input file specified.\n")          unless (defined($config{'file_in'}));
die ("Input file does not exist.\n")        unless (-e $config{'file_in'});
die ("Input file is not readable.\n")       unless (-r $config{'file_in'});
die ("Input file is binary.\n")         if (-B $config{'file_in'});

my %data;

# read file into scalar
($data{'file_name'}, $data{'file_dir'}, $data{'file_ext'}) = fileparse($config{'file_in'}, qr/\.[^.]*/);

# Open original .0DA Intel Hex File and read contents into data storage
$data{'raw_bin'} = &readHexFile($config{'file_in'});

# die if there's no data inside the 0DA file
die ("No data found in 0DA in the format of :10..., possibly not DME file?\n") unless (length($data{'raw_bin'}) > 0);

# collect DME type and version information - this MUST exist
($config{'dme_type'}, $config{'dme_version'}) = &getDMEVersion($data{'raw_bin'});

# The MSS54HP has the first and second halves sectioned and ordered differently
if ($config{'dme_type'} eq 'MSS54HP') {
  my @segmentArray = ($data{'raw_bin'} =~ m/(.{16384})/gs);
  $data{'raw_bin'} = $segmentArray[1] . $segmentArray[0] . $segmentArray[3] . $segmentArray[2];
}

# a quick file size check is in order
die ("Improper file size (" . length($data{'raw_bin'}) . " bytes)\n") unless (&filesizeValidate($data{'raw_bin'}, $config{'dme_type'}));

# make output file equivalent to input file unless something else is specified via CLI
$config{'file_out'} = $data{'file_name'} . $config{'bin_ext'} unless defined ($config{'file_out'});
my $i = 1;

my $file_out = $config{'file_out'};

# don't overwrite any files - default behaviour can be adjusted by CLI or config option
while (-e $config{'file_out'} && ! $config{'overwrite'}) {
  print ($config{'file_out'} . " exists, trying ") unless ($config{'silent'});
  $config{'file_out'} = $file_out . "($i)";
  print ($config{'file_out'} . " instead...\n") unless ($config{'silent'});
  $i++;
}
print($config{'file_out'} . " is available to write binary...\n") if (($i > 1) && ! $config{'silent'});
print("Writing " . $config{'dme_type'} . " (" . $config{'dme_version'} . ") binary to " . $config{'file_out'} . "...\n") unless ($config{'silent'});
&writeBinFile($config{'file_out'}, $data{'raw_bin'});

#----------------------------
# SUBROUTINES               |
#----------------------------

# simple usage/syntax
sub usage {
  die ("\nSyntax: " . fileparse($0, qr/\.[%.]*/) . " --debug --help --silent --writeover --input=<filein.0da> --output=<file_out.bin>\nIf an output file is not specified, the input file's base name will be used in conjunction with a .bin extension.\n  --writeover WILL cause <file_out.bin> to be overwritten if <file_out.bin> exists.\n\n");
}

# display version, then exit.
sub version {
  print (fileparse($0, qr/\.[%.]*/) . " v" . $config{'version'} . "\n");
  exit (0);
}

# simple debug function
sub debug ($) {
  print (@_) if $config{'debug'};
}

# Converts a binary string to a hexadecimal string
sub bin2hex($) {
  my $hex_out;
  $hex_out .= sprintf("%02X", ord($_)) foreach (split //, $_[0]);
  $hex_out;
}

# Converts a hexadecimal string to a binary string
sub hex2bin($) {
  ((my $bin_out = $_[0]) =~ s/([a-f0-9][a-f0-9])/chr(hex($1))/egi);
  $bin_out;
}

# extract DME Version and type from binary string
sub getDMEVersion ($) {
  my $raw_bin = $_[0];
  # gather up DME version by locating string within the raw binary
  if ($raw_bin =~ /(2113\d{8}[0-9A-Z]{4}){3}/i) {
    my $dme_version = $1;
    if    ($dme_version =~ /2113180[01](\d){4}[0-9A-Z]{4}/i) { return ('MSS50',   $dme_version) }
    elsif ($dme_version =~ /21132100(\d){4}[0-9A-Z]{4}/i)    { return ('MSS52',   $dme_version) }
    elsif ($dme_version =~ /21132200(\d){4}[0-9A-Z]{4}/i)    { return ('MSS54',   $dme_version) }
    elsif ($dme_version =~ /21132[35]00(\d){4}[0-9A-Z]{4}/i) { return ('MSS54HP', $dme_version) }
    else {
      die ("Uncertain DME type: $dme_version\n");
    }
  } else {
    die ("DME version string not located - wrong or improper file format?\n");
  }
}

# routine to write out binary file
sub writeBinFile ($$) {
  my ($file_out, $file_data) = (@_);
  open (BIN_OUT, ">", $file_out);
  binmode (BIN_OUT);
  print (BIN_OUT $file_data) or die($!);
  close (BIN_OUT);
}

# routine to confirm file size based on dme_type
sub filesizeValidate ($$) {
  my $file_in = shift();
  my $dme_type = shift();
  return (1) if (length($file_in) == 65536 && $dme_type eq 'MSS54HP');
  return (1) if (length($file_in) == 32768);
  return (0);
}

# Binary file read routine
sub readHexFile ($) {
  my $file_in = shift();
  my $raw_bin;
  open (INTEL_HEX_FILE_IN, $file_in) or die ($!);
  while ($data{'data_in'} = <INTEL_HEX_FILE_IN>) {
    chomp ($data{'data_in'});
    $raw_bin .= &hex2bin($4) if ($data{'data_in'} =~ /:(10)([0-9,A-F]{4})([0-9,A-F]{2})([0-9,A-F]{32})([0-9,A-F]{2})/);
  }
  close (INTEL_HEX_FILE_IN);
  return ($raw_bin);
}

Last edited by p0lar; Fri, Mar-22-2013 at 03:00:52 PM.
Jump to top p0lar is offline   Reply With Quote