//
// srecord - manipulate eprom load files
// Copyright (C) 1998-2003, 2005-2007 Peter Miller
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see
// .
//
#include
#include
srec_input_file_tektronix::srec_input_file_tektronix(const string &a_filename) :
srec_input_file(a_filename),
data_record_count(0),
garbage_warning(false),
seen_some_input(false),
termination_seen(false)
{
}
srec_input_file_tektronix::~srec_input_file_tektronix()
{
// make sure the termination record is done
}
int
srec_input_file_tektronix::get_nibble()
{
int n = srec_input_file::get_nibble();
checksum_add(n);
return n;
}
int
srec_input_file_tektronix::get_byte()
{
// this differs from the srec_input_file method only in that we
// don't add to the checksum.
int c1 = get_nibble();
int c2 = get_nibble();
return ((c1 << 4) | c2);
}
int
srec_input_file_tektronix::read_inner(srec_record &record)
{
for (;;)
{
int c = get_char();
if (c < 0)
return 0;
if (c == '/')
break;
if (c == '\n')
continue;
if (!garbage_warning)
{
warning("ignoring garbage lines");
garbage_warning = true;
}
for (;;)
{
c = get_char();
if (c < 0)
return 0;
if (c == '\n')
break;
}
}
if (peek_char() == '/')
{
//
// lines beginning with ``//'' are end-of-file records
//
seek_to_end();
return 0;
}
unsigned char buffer[255+5];
checksum_reset();
buffer[0] = get_byte();
buffer[1] = get_byte();
buffer[2] = get_byte();
int nibble_checksum = checksum_get();
buffer[3] = get_byte();
if (use_checksums() && nibble_checksum != buffer[3])
{
fatal_error
(
"header checksum mismatch (%02X != %02X)",
nibble_checksum,
buffer[3]
);
}
if (buffer[2])
{
checksum_reset();
for (int j = 0; j < buffer[2]; ++j)
buffer[4 + j] = get_byte();
int data_checksum_calc = checksum_get();
int data_checksum_file = get_byte();
if (use_checksums() && data_checksum_calc != data_checksum_file)
{
fatal_error
(
"data checksum mismatch (%02X != %02X)",
data_checksum_calc,
data_checksum_file
);
}
}
if (get_char() != '\n')
fatal_error("end-of-line expected");
record =
srec_record
(
(
buffer[2] == 0
?
srec_record::type_start_address
:
srec_record::type_data
),
srec_record::decode_big_endian(buffer, 2),
buffer + 4,
buffer[2]
);
return 1;
}
int
srec_input_file_tektronix::read(srec_record &record)
{
for (;;)
{
if (!read_inner(record))
{
if (!seen_some_input && garbage_warning)
fatal_error("file contains no data");
if (data_record_count <= 0)
fatal_error("file contains no data");
if (!termination_seen)
{
warning("no start address record");
termination_seen = true;
}
return 0;
}
seen_some_input = true;
if
(
record.get_type() != srec_record::type_start_address
&&
termination_seen
)
{
warning("termination record should be last");
termination_seen = false;
}
switch (record.get_type())
{
default:
// impossible
continue;
case srec_record::type_data:
++data_record_count;
break;
case srec_record::type_start_address:
if (termination_seen)
warning("redundant termination record");
termination_seen = true;
break;
}
break;
}
return 1;
}
const char *
srec_input_file_tektronix::get_file_format_name()
const
{
return "Tektronix (16-bit)";
}