123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168 |
- # Copyright (c) 2015, Nordic Semiconductor
- # All rights reserved.
- #
- # Redistribution and use in source and binary forms, with or without
- # modification, are permitted provided that the following conditions are met:
- #
- # * Redistributions of source code must retain the above copyright notice, this
- # list of conditions and the following disclaimer.
- #
- # * 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.
- #
- # * Neither the name of Nordic Semiconductor ASA 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 THE COPYRIGHT HOLDERS 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 THE COPYRIGHT HOLDER 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.
- from nordicsemi.dfu import intelhex
- from struct import unpack
- class nRFHex(intelhex.IntelHex):
- """
- Converts and merges .hex and .bin files into one .bin file.
- """
- info_struct_address_base = 0x00003000
- info_struct_address_offset = 0x1000
- info_struct_magic_number = 0x51B1E5DB
- info_struct_magic_number_offset = 0x004
- s1x0_mbr_end_address = 0x1000
- s132_mbr_end_address = 0x3000
- def __init__(self, source, bootloader=None):
- """
- Constructor that requires a firmware file path.
- Softdevices can take an optional bootloader file path as parameter.
- :param str source: The file path for the firmware
- :param str bootloader: Optional file path to bootloader firmware
- :return: None
- """
- super(nRFHex, self).__init__()
- self.file_format = 'hex'
- if source.endswith('.bin'):
- self.file_format = 'bin'
- self.loadfile(source, self.file_format)
- self._removeuicr()
- self.bootloaderhex = None
- if bootloader is not None:
- self.bootloaderhex = nRFHex(bootloader)
- def _removeuicr(self):
- uicr_start_address = 0x10000000
- maxaddress = self.maxaddr()
- if maxaddress >= uicr_start_address:
- for i in range(uicr_start_address, maxaddress + 1):
- self._buf.pop(i, 0)
- def address_has_magic_number(self, address):
- try:
- potential_magic_number = self.gets(address, 4)
- potential_magic_number = unpack('L', potential_magic_number)[0]
- return nRFHex.info_struct_magic_number == potential_magic_number
- except Exception:
- return False
- def get_softdevice_variant(self):
- potential_magic_number_address = nRFHex.info_struct_address_base + nRFHex.info_struct_magic_number_offset
- if self.address_has_magic_number(potential_magic_number_address):
- return "s1x0"
- for i in xrange(4):
- potential_magic_number_address += nRFHex.info_struct_address_offset
- if self.address_has_magic_number(potential_magic_number_address):
- return "s132"
- return "unknown"
- def get_mbr_end_address(self):
- softdevice_variant = self.get_softdevice_variant()
- if softdevice_variant == "s132":
- return nRFHex.s132_mbr_end_address
- else:
- return nRFHex.s1x0_mbr_end_address
- def minaddr(self):
- min_address = super(nRFHex, self).minaddr()
- # Lower addresses are reserved for master boot record
- if self.file_format != 'bin':
- min_address = max(self.get_mbr_end_address(), min_address)
- return min_address
- def size(self):
- """
- Returns the size of the source.
- :return: int
- """
- min_address = self.minaddr()
- max_address = self.maxaddr()
- size = max_address - min_address + 1
- # Round up to nearest word
- word_size = 4
- number_of_words = (size + (word_size - 1)) / word_size
- size = number_of_words * word_size
- return size
- def bootloadersize(self):
- """
- Returns the size of the bootloader.
- :return: int
- """
- if self.bootloaderhex is None:
- return 0
- return self.bootloaderhex.size()
- def tobinfile(self, fobj, start=None, end=None, pad=None, size=None):
- """
- Writes a binary version of source and bootloader respectivly to fobj which could be a
- file object or a file path.
- :param str fobj: File path or object the function writes to
- :return: None
- """
- # If there is a bootloader this will make the recursion call use the samme file object.
- if getattr(fobj, "write", None) is None:
- fobj = open(fobj, "wb")
- close_fd = True
- else:
- close_fd = False
- start_address = self.minaddr()
- size = self.size()
- super(nRFHex, self).tobinfile(fobj, start=start_address, size=size)
- if self.bootloaderhex is not None:
- self.bootloaderhex.tobinfile(fobj)
- if close_fd:
- fobj.close()
|