aboutsummaryrefslogtreecommitdiff
path: root/circuitpython/lib/nrfutil/nordicsemi/dfu/nrfhex.py
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--circuitpython/lib/nrfutil/nordicsemi/dfu/nrfhex.py168
1 files changed, 168 insertions, 0 deletions
diff --git a/circuitpython/lib/nrfutil/nordicsemi/dfu/nrfhex.py b/circuitpython/lib/nrfutil/nordicsemi/dfu/nrfhex.py
new file mode 100644
index 0000000..67a5d5c
--- /dev/null
+++ b/circuitpython/lib/nrfutil/nordicsemi/dfu/nrfhex.py
@@ -0,0 +1,168 @@
+# 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('I', 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()