# Creates a firmware package for the Beyond Utility
# takes an application binary as the input, as well
# as the start address and the version number string
# Outputs a "latest.beyondfw" file that contains
# a header region containing useful info, and a
# CRC at the end to verify the file integrity

import hashlib
import os
import argparse
import struct
import ihex_loader



# Output file format:
#
# Initial - length of software version string
# followed by the string itself
# next 4 bytes: start address of binary file (ordered little-endian,
# least significant byte first)
# next 4 bytes: length of binary data (again, little endian)
# then the binary blob itself
# finally, SHA512 hash of the entire file to the end of the binary blob (64 bytes)

def main():
    parser = argparse.ArgumentParser('Creates Utility firmware file')
    parser.add_argument('-v', '--version', help='Version string')
    parser.add_argument('-s', '--start', help='Firmware start address (default = 0x00404000)')
    parser.add_argument('file_name',help='Input file name (bin)')
    parser.add_argument('outfile_name',help='Output file name (beyondfw)')

    args = parser.parse_args()

    (inhead,intail) = os.path.split(args.file_name)
    if(intail.split('.')[-1] != 'bin' and intail.split('.')[-1] != 'hex'):
        print('Error: only binary or Intel hex files accepted (*.bin, *.hex)')
        quit()
    (outhead,outtail) = os.path.split(args.outfile_name)
    if(outtail.split('.')[-1] != 'beyondfw'):
        outtail = outtail.split('.')[0] + '.beyondfw'

    vlen = len(args.version)
    if(args.start):
        start_addr = args.start
        if(start_addr.startswith('0x')):
            int_start_addr = int(start_addr, 16)
        else:
            int_start_addr = int(start_addr)
    else:
        int_start_addr = 0x00404000

    if(intail.split('.')[-1] == 'hex'):
        (listfiledata, startaddr) = ihex_loader.load_ihex(args.file_name)
        int_start_addr = startaddr
        fildata = bytes(listfiledata)
    else:    
        with open(args.file_name,'rb') as infil:
            fildata = infil.read()

    outfiledata = bytearray()
    #print(len(fildata))
    outfiledata.append(vlen)
    outfiledata.extend(args.version.encode('ascii'))
    outfiledata.extend(struct.pack('<II',int_start_addr, len(fildata)))
    outfiledata.extend(fildata)

    h = hashlib.sha512(outfiledata)

    outfiledata.extend(h.digest())

    with open(os.path.join(outhead,outtail),'wb') as outfil:
        outfil.write(outfiledata)


if __name__ == '__main__':
    main()