vos/ambiq-hal-sys/ambiq-sparkfun-sdk/tools/bootloader_scripts/generate_ota_descriptor.py
2022-10-23 23:45:43 -07:00

162 lines
5.7 KiB
Python

#!/usr/bin/env python3
#******************************************************************************
#
# This scripts creates a single Blob, which can be programmed at OTA_POINTER
# The first 4 bytes contain address to OTA Descriptor, which immediately follows
#
#******************************************************************************
import argparse
import sys
magicnum = 0xDEADCAFE
#******************************************************************************
#
# Main function
#
#******************************************************************************
def main():
# Read the binary file from the command line.
with open(args.binfile, mode='rb') as binfile:
application = binfile.read()
if len(args.trailerfile) > 0:
with open(args.trailerfile, mode='rb') as binfile:
trailer= binfile.read()
else:
trailer = []
applen = len(application)
crc = crc32(application)
ota_desc = []
# OTA Descriptor immediately follows the OTA_POINTER
ota_desc.extend(int_to_bytes(magicnum))
ota_desc.extend(int_to_bytes(int(args.linkaddr, 0)))
ota_desc.extend(int_to_bytes(applen))
ota_desc.extend(int_to_bytes(crc))
trailerlen = len(trailer)
ota_desc.extend(int_to_bytes(trailerlen))
ota_desc.extend(int_to_bytes(int(args.options, 0)))
ota_desc.extend(int_to_bytes(int(args.flashaddr , 0)+ 40)) # pui32SecInfoPtr
if (args.otaimageaddr != 0):
# Image has been flashed seprately. Just code the address in descriptor
ota_desc.extend(int_to_bytes(int(args.otaimageaddr, 0))) # pui32ImageAddr
else:
# Image is written immediately following the OTA descriptor
# Need to determine if there is a padding needed in between to ensure proper alignment
image_addr = int(args.flashaddr , 0) + 40 + trailerlen
if (image_addr % int(args.alignment) != 0):
pad_size = int(args.alignment) - (image_addr % int(args.alignment))
else:
pad_size = 0
image_addr = image_addr + pad_size
ota_desc.extend(int_to_bytes(image_addr)) # pui32ImageAddr
ota_desc_crc = crc32(ota_desc)
# OTA_POINTER contents
new_image = []
new_image.extend(int_to_bytes(int(args.flashaddr , 0)+ 4)) # OTA Descriptor address
new_image.extend(ota_desc) # OTA Descriptor
new_image.extend(int_to_bytes(ota_desc_crc))
if trailerlen > 0:
print('Adding Security Trailer')
new_image.extend(trailer)
if (pad_size != 0):
print('Adding padding of {} bytes...'.format(pad_size), flush=True)
pad_binarray = bytearray([0]*pad_size);
new_image.extend(pad_binarray)
if (args.otaimageaddr == 0):
# Image
new_image.extend(application)
print('Saving OTA descriptor image {} bytes to {}...'.format(len(new_image), args.outfile), flush=True)
with open(args.outfile, mode='wb') as imagefile:
imagebytearray = bytearray(new_image)
imagefile.write(imagebytearray)
print('Done.')
#******************************************************************************
#
# Turn a 32-bit number into a series of bytes for transmission.
#
# This command will split a 32-bit integer into an array of bytes, ordered
# LSB-first for transmission over the UART.
#
#******************************************************************************
def int_to_bytes(n):
A = [n & 0xFF,
(n >> 8) & 0xFF,
(n >> 16) & 0xFF,
(n >> 24) & 0xFF]
return A
#******************************************************************************
#
# Extract a word from a byte array
#
#******************************************************************************
def word_from_bytes(B, n):
return (B[n] + (B[n + 1] << 8) + (B[n + 2] << 16) + (B[n + 3] << 24))
#******************************************************************************
#
# CRC function that matches the CRC used by the Apollo bootloader.
#
#******************************************************************************
poly32 = 0x1EDC6F41
def crc32(L):
rem = 0
for b in L:
rem = rem ^ (b << 24)
for i in range(8):
if rem & 0x80000000:
rem = ((rem << 1) ^ poly32)
else:
rem = (rem << 1)
rem = rem & 0xFFFFFFFF
return rem
#******************************************************************************
#
# Main program flow
#
#******************************************************************************
if __name__ == '__main__':
parser = argparse.ArgumentParser(description =
'Utility to generate OTA blob for multi boot test app')
parser.add_argument('binfile',
help = 'Binary file to program into the target device')
parser.add_argument('flashaddr', help = 'Flash address (hex) where blob will be flashed to')
parser.add_argument('linkaddr', help = 'Link address (hex) of the program file')
parser.add_argument('-a', dest = 'alignment', default=4,
help = 'Desired alignment for application in image')
parser.add_argument('options',
help = 'OTA options parameter')
parser.add_argument('-s', dest = 'trailerfile', default='',
help = 'Binary file for (optional) security trailer')
parser.add_argument('-i', dest='otaimageaddr', default=0,
help = '(optional) Flash address (hex) where the OTA image is flashed to - if not specified, the image is included in outfile immediately following the descriptor')
parser.add_argument('-o', dest = 'outfile',
help = 'output filename for the ota descriptor')
args = parser.parse_args()
main()