Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expanded to all SRecord types, heavy refactoring and adding setup.py #1

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 26 additions & 46 deletions srec2bin.py → bin/srec2bin.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,24 @@
#
#-----------------------------------------------------------------------------

import argparse
import logging
import os
import sys
import argparse
from srecord import *

from srec2bin import *

#-- definitions --------------------------------------------------------------

SCRIPT_VERSION = '0.90'
DEFAULT_OUT_FILE_EXT = '.bin'
DEFAULT_OUT_FILE_NAME = 'out' + DEFAULT_OUT_FILE_EXT

#-----------------------------------------------------------------------------


log = logging.getLogger(__name__)


def _mkofn(out_fn, in_fn):
""" if output file name is not specified, derive from input file name """

Expand All @@ -39,13 +44,15 @@ def _mkofn(out_fn, in_fn):

#-----------------------------------------------------------------------------


def _auto_int(x):
return int(x, 0)

#-----------------------------------------------------------------------------
# main program
#-----------------------------------------------------------------------------


if __name__ == "__main__":

parser = argparse.ArgumentParser(
Expand Down Expand Up @@ -81,55 +88,28 @@ def _auto_int(x):
args = parser.parse_args()

fill_byte = (args.fill_byte % 0x100).to_bytes(1, 'big')
target_memory = bytearray(0x10000 * fill_byte)
target_memmap = bytearray(0x10000 * b'\xff')

if args.verbose:
print("Start address: 0x{0:04x}".format(args.start_addr))
print("End address: 0x{0:04x}".format(args.end_addr))
print("Filling with: 0x{0:02x}".format(fill_byte[0]))

srecs = []
line_no = 1
byte_cnt = 0
for srec_line in args.srec_file:
srec = SRecord()
if not srec.process(srec_line):
if srec.type == "S1":
srecs.append(srec)
else:
if args.verbose:
print("Skipping", srec.type if srec.type!="" else "empty", "line")
else:
print("Error in", args.srec_file.name, "Line", str(line_no) + ":")
# to display the offending line we better use bytes type here in case
# the input is (mistakenly) binary stuff instead of a text file
print(srec_line.rstrip().encode('ASCII', 'ignore'))
print(srec.error)
print('Program terminated.')
sys.exit(1)
line_no += 1
log.setLevel(logging.DEBUG)

if args.verbose:
print("S-Record lines processed: {0:d}".format(line_no - 1))

for srec in srecs:
addr = srec.addr
for b in srec.data:
if target_memmap[addr] != 0:
target_memmap[addr] = 0
target_memory[addr] = b
byte_cnt += 1
else:
print("Error: duplicate access to addr", "0x%04x" % addr)
addr += 1
log.debug("Start address: 0x{0:04x}".format(args.start_addr) +
"End address: 0x{0:04x}".format(args.end_addr) +
"Filling with: 0x{0:02x}".format(fill_byte[0]))

if args.verbose:
print("Total bytes processed: {0:d}".format(byte_cnt))
try:
srecords = load(args.srec_file)
except ParseException as e:
log.error("Error in {}:".format(args.srec_file.name))
log.error(e)
log.error('Program terminated.')
sys.exit(1)

target_memory, byte_cnt = to_binary(srecords, fill_byte)
log.debug("Total bytes processed: {0:d}".format(byte_cnt))

out_file_name = _mkofn(args.out_file, args.srec_file.name)
if args.verbose:
print("Writing to output file", out_file_name)
log.debug("Writing to output file", out_file_name)

with open(out_file_name, 'wb') as outfile:
outfile.write(target_memory[args.start_addr:args.end_addr])

Expand Down
77 changes: 77 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import codecs
import os
import re

from setuptools import find_packages, setup

NAME = 'srec2bin'
PACKAGES = find_packages(where='.')
META_PATH = os.path.join('srec2bin', '__init__.py')
KEYWORDS = ['motorola', 'srecord', 'S3']
CLASSIFIERS = [
'Development Status :: 4 - Beta',
'Environment :: Other Environment',
'Natural Language :: English',
'Intended Audience :: Developers',
'License :: OSI Approved :: MIT License',
'Operating System :: MacOS :: MacOS X',
'Operating System :: POSIX',
'Operating System :: Win32',
'Programming Language :: Python :: 3.5',
'Topic :: Software Development :: Libraries :: Python Modules',
]
INSTALL_REQUIRES = [
]

HERE = os.path.abspath(os.path.dirname(__file__))


def read(*parts):
"""
Build an absolute path from *parts* and and return the contents of the
resulting file. Assume UTF-8 encoding.
"""
with codecs.open(os.path.join(HERE, *parts), 'rb', 'utf-8') as f:
return f.read()


META_FILE = read(META_PATH)


def find_meta(meta):
"""
Extract __*meta*__ from META_FILE.
"""
meta_match = re.search(
r"^__{meta}__ = ['\"]([^'\"]*)['\"]".format(meta=meta),
META_FILE, re.M
)
if meta_match:
return meta_match.group(1)
raise RuntimeError("Unable to find __{meta}__ string.".format(meta=meta))


if __name__ == '__main__':
setup(
name=NAME,
description=find_meta('description'),
license=find_meta('license'),
url=find_meta('uri'),
version=find_meta('version'),
author=find_meta('author'),
author_email=find_meta('email'),
maintainer=find_meta('author'),
maintainer_email=find_meta('email'),
keywords=KEYWORDS,
long_description=read('README.md'),
packages=PACKAGES,
# package_dir={'srec2bin': 'srec2bin'},
# package_data={'srec2bin': ['*.rst']},
scripts=['bin/srec2bin.py'],
classifiers=CLASSIFIERS,
install_requires=INSTALL_REQUIRES,
python_requires='>=3.5',
)
11 changes: 11 additions & 0 deletions srec2bin/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
__version__ = '1.0'
__title__ = 'srec2bin'
__description__ = 'This utility converts binary data from Motorola S-Record file format [1] to raw binary.'
__author__ = 'Oliver Thamm'
__email__ = '[email protected]'
__uri__ = 'https://github.com/mrbell321/srec2bin_py'
__doc__ = __description__ + ' <' + __uri__ + '>'
__license__ = 'MIT'

from .srecord import SRecord, Purpose, Type
from .srec import to_image, to_pages, load
79 changes: 79 additions & 0 deletions srec2bin/srec.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import logging
from typing import Generator, Iterable, Tuple, Optional

from .srecord import SRecord, Purpose

log = logging.getLogger(__name__)
log.setLevel(logging.INFO)

MAX_PAGE_SIZE = 0x100000


def load(filename: str):
if isinstance(filename, str):
with open(filename, 'r') as f:
srecords = (SRecord(line) for line in f.readlines())
else:
srecords = (SRecord(line) for line in filename)

return srecords


def to_image(srecords: Iterable[SRecord], fill_byte: bytes = b'\xff', offset: int = 0) -> Tuple[bytearray, int]:
log.debug("Converting SRecords to binary, fill: 0x{}, offset: 0x{:x}".format(fill_byte.hex(), offset))

target_memory = bytearray(fill_byte * 0x100000)
target_memmap = bytearray(0x100000 * b'\xff')
byte_cnt = 0
high_address = 0
for srecord in srecords:
if srecord.purpose == Purpose.Data:
addr = srecord.address - offset
log.debug("Processing SRecord: {} @ 0x{:08x}".format(srecord, addr))
for b in srecord.data:
if target_memmap[addr] == 0:
log.debug("Non critical error: duplicate access to address: 0x{:04X}; {}".format(addr, srecord))
else:
byte_cnt += 1
target_memmap[addr] = 0
target_memory[addr] = b
addr += 1
if addr > high_address:
high_address = addr
else:
log.debug("Skipping non-data line")

return target_memory[:high_address], byte_cnt


def to_pages(srecords: Iterable[SRecord], page_size: Optional[int] = None) -> Generator[
Tuple[int, bytearray], None, None]:
page_size = page_size or MAX_PAGE_SIZE
log.debug("Converting SRecords to binary, page_size: 0x{:x}".format(page_size))

page = bytearray()

page_address = -1
for srecord in srecords:
if srecord.purpose == Purpose.Data:
log.debug("Processing SRecord: {}".format(srecord))
if page_address < 0:
page_address = srecord.address

elif srecord.address < page_address or srecord.address >= (page_address + page_size):
log.debug("Switching from page at 0x{:08X} to 0x{:08X}".format(page_address, srecord.address))
yield page_address, page
page = bytearray()
page_address = srecord.address

if len(page) + len(srecord.data) >= page_size:
remaining = page_size - len(page)
page[len(page):] = srecord.data[:remaining]
yield page_address, page
page = bytearray(srecord.data[remaining:])
page_address = srecord.address + remaining
else:
page[len(page):] = srecord.data[:]

if page:
yield page_address, page
Loading