import re
import os
import struct
import sys


print("Build mode:",sys.argv[1])


srec_p = "srec_cat"



# script required both .bin and .hex file , master_bin.hex as 

total_bin_count = 1
boot_module_lengh = 2
fill_0xff_module_count = boot_module_lengh - total_bin_count
module_boot_strcuture_size = 24
boot_table_size_inbyte = 12 + (boot_module_lengh*module_boot_strcuture_size)

#bin_name_list = "FreeRTOS_final.bin","DYN_ID3_final.bin","DYN_ID3_final.bin"
#bin_name_list = "FreeRTOS_final","OTSU_V1_final","RTL_ID3_final"
#bin_name_list = "FreeRTOS_final","RTL_ID2_final","DYN_ID3_final"
#hex_name_list = "FreeRTOS_final","RTL_ID2_final","DYN_ID3_final"
bin_name_list = "antaris_exo_core_final","OTSU_V1_final","RTL_ID3_final"
#bin_name_list = "test_mod_final","OTSU_V1_final","RTL_ID3_final"

bin_size_read = [1,2,3,4]
cumulative_bin_size = 0

print("Single bin generator")

cntr = 0


aa = 0xAAAAAAAA
bb = 0xBBBBBBBB
cc = 0xCCCCCCCC
dd = 0xDDDDDDDD
ff = 0xff
abcd = 0xaabbccdd

work_complete_flag = 1

mod_count = 0
offset_calc = 0
actual_bin_size = 0
mod_dymmy_cnt = 0




num1 = 0xaabbccd
num2 = 0x12345678

#Flash_address_allocated = 0x8010000
Flash_address_allocated = 0x8110000


# boot table header size 12 byte : 1 byte will be padded in prgram
#bank_selection = 0x8000000      # 4Byte
bank_selection = 0x8100000      # 4Byte

boot_selection = 0x10            # 1Byte
total_module = total_bin_count              # 1Byte
FFS_flag = 0xAA                  # 1Byte
table_verified_sts = 0xAA        # 1Byte
memory_chunk_release = 0x00      # 1Byte
boot_success_state  = 0x00       # 2Byte


firmware_header = 0              # 4Byte
code_loaded_address = 0x12345678 # 4Byte
data_loaded_address = 0x12345678 # 4Byte
code_load_area_memtype = 0x12    # 1Byte
data_load_area_memtype = 0x12    # 1Byte
module_load_status = 0x10        # 1Byte
module_id = 0x00                 # 1Byte
bin_size  = 0x12345678           # 4Byte
packet_count  = 0x12345678       # 4Byte


       




def other_field_update():
    # code load address
    bytes_val = code_loaded_address.to_bytes(4, 'little')                
    fw.write(bytes_val)

    # data load address 
    bytes_val = data_loaded_address.to_bytes(4, 'little')                
    fw.write(bytes_val)

    # code section memory type
    bytes_val = code_load_area_memtype.to_bytes(1, 'little')                
    fw.write(bytes_val)

    # data section memory type
    bytes_val = data_load_area_memtype.to_bytes(1, 'little')                
    fw.write(bytes_val)

    # module reload flag
    bytes_val = module_load_status.to_bytes(1, 'little')                
    fw.write(bytes_val)



with open("boot_table.bin", "wb") as fw:

    # bank slecetion 
    bytes_val = bank_selection.to_bytes(4, 'little')                
    fw.write(bytes_val)


    # boot slecetion 
    bytes_val = boot_selection.to_bytes(1, 'little')                
    fw.write(bytes_val)

    # padding ff
    bytes_val = ff.to_bytes(1, 'little')                
    fw.write(bytes_val)

    # module count
    bytes_val = total_module.to_bytes(1, 'little')                
    fw.write(bytes_val)

    # Full firmware set flasg
    bytes_val = FFS_flag.to_bytes(1, 'little')                
    fw.write(bytes_val)

    # Table verified sts 
    bytes_val = table_verified_sts.to_bytes(1, 'little')                
    fw.write(bytes_val)

    # Memory chunk relase request flasg 
    bytes_val = memory_chunk_release.to_bytes(1, 'little')                
    fw.write(bytes_val)

    # Boot success status 
    bytes_val = boot_success_state.to_bytes(2, 'little')                
    fw.write(bytes_val)


    while (mod_count < total_bin_count):   

        try:
            with open("{}.bin".format(bin_name_list[mod_count]), "rb") as f:

                    byte = f.read(1)
                    dat = bytearray(byte)
                    module_id = int(dat[0])
                    print("\r\nmodule id ",module_id)
                    
                    

                    
                    if module_id == (mod_count+1) :
                                
                        
                        cntr = 0
                        for i in range(11):
                            byte = f.read(1)

                        byte = f.read(4)
                        dat = bytearray(byte)

                        bin_size_read[0] = int(dat[0])
                        bin_size_read[1] = int(dat[1])
                        bin_size_read[2] = int(dat[2])
                        bin_size_read[3] = int(dat[3])
             
                        decimal_num = 0
                        decimal_num = bin_size_read[0] * 1000000
                        decimal_num = decimal_num + bin_size_read[1] * 10000
                        decimal_num = decimal_num + bin_size_read[2] * 100
                        decimal_num = decimal_num + bin_size_read[3]
                        actual_bin_size = decimal_num
                        actual_bin_size = actual_bin_size + 4
                        modulus_num = actual_bin_size % 16
                        if modulus_num > 0 :
                            decimal_num = actual_bin_size + (16-modulus_num)
                        else :
                            decimal_num = actual_bin_size
                        #print("bin size ",decimal_num)
                        print("Bin size in hex ",hex(decimal_num))
                        print("bin place offset : ",hex(offset_calc))
                        print("Bin size in dec ",decimal_num)

#here decimal number is only for arrange all binary in single binary with 16 byte padding to make it it arranfe in oredr

                        firmware_header = Flash_address_allocated + offset_calc
                        print("Firmware header : ",hex(firmware_header))

                        bytes_val = firmware_header.to_bytes(4, 'little')                
                        fw.write(bytes_val)
                        
                        other_field_update()
                        
                        bytes_val = module_id.to_bytes(1, 'little')                
                        fw.write(bytes_val)
                        
                        bytes_val = actual_bin_size.to_bytes(4, 'little')                
                        fw.write(bytes_val)

                        packet_count = (int)(actual_bin_size / 16)
                        modulus_num = actual_bin_size % 16
                        if modulus_num > 0 :
                            packet_count = packet_count + 1

                        packet_count =  packet_count * 16
                        
                        bytes_val = packet_count.to_bytes(4, 'little')                
                        fw.write(bytes_val)
                        
                        f.close()


                        if mod_count > 1 :
                            cmd = str(r"{} temp_{}.hex -Intel {}.hex -Intel -offset {} -o temp_{}.hex -Intel".format(srec_p,mod_count-1,bin_name_list[mod_count],hex(offset_calc),mod_count))
                            returned_value = os.system(cmd)
                            print('Module merging {} with {}'.format(mod_count-1,bin_name_list[mod_count]))

                        elif mod_count > 0 :
                            cmd = str(r"{} {}.hex -Intel {}.hex -Intel -offset {} -o temp_{}.hex -Intel".format(srec_p,bin_name_list[0],bin_name_list[1],hex(offset_calc),mod_count))
                            returned_value = os.system(cmd)
                            print('Module merging 1 with 2')
                        else :
                            print('Module merging skipped since module count is only 1')


                                

                        
                             
                            
                        offset_calc = offset_calc + decimal_num

                    else :
                        work_complete_flag = 0
                        print('Error : Incorrect module order')
                        break

                    
        except IOError:
             work_complete_flag = 0
             print('Error While Opening the file!')


        mod_count = mod_count + 1

    #bytes_val = offset_calc.to_bytes(4, 'little')                
    #fw.write(bytes_val)

    while (mod_dymmy_cnt < fill_0xff_module_count):
        for i in range(module_boot_strcuture_size):
            # padding ff
            bytes_val = ff.to_bytes(1, 'little')                
            fw.write(bytes_val)
        mod_dymmy_cnt = mod_dymmy_cnt + 1


fw.close()
    
if work_complete_flag == 1 :

    if os.path.exists("master_bin.hex"):
      os.remove("master_bin.hex")
    else:
      print("No master_bin.hex already exists")
    
    #os.remove("master_bin.hex")
    if total_bin_count == 1 :
        cmd = str(r"{} {}.hex -Intel -o master_bin.hex -Intel".format(srec_p,bin_name_list[0]))
        returned_value = os.system(cmd)
        print("Single bin for single bin")
    else :
        str1 = str("temp_{}.hex".format(mod_count-1))
        os.rename(str1,"master_bin.hex")


    cmd = str(r"{} master_bin.hex -Intel -o antaris_exo_core_firmware.bin -Binary".format(srec_p))
    returned_value = os.system(cmd)
    
    print('\r\nMaster bin generated')

else :
    print('\r\nError - Master bin not generated ????')
    val = input("Press any key to exit build process") 
    exit(1)



cmd = str(r"{} boot_table.bin -binary -output boot_table.hex -Intel".format(srec_p))
returned_value = os.system(cmd)


cmd = str(r"{} boot_table.hex -Intel -fill 0xFF 0x00000000 {} -STM32 {} -o boot_table_CRC.hex -Intel".format(srec_p,hex(boot_table_size_inbyte),hex(boot_table_size_inbyte)))
returned_value = os.system(cmd)

print('\r\nboot table... ')
cmd = str(r"{} boot_table_CRC.hex -Intel -o antaris_exo_core_boot_table.bin -Binary".format(srec_p))
returned_value = os.system(cmd)

if returned_value != 0 : print(' FAILED !!!')
else : print('generated')

# merging boot table and exo software bin
# bootable flash location = 0x8100000
# exo bin flash location 0x8110000
#srec_cat antaris_exo_core_boot_table.bin -Binary -fill 0xff 0x00000000 0x00010000 antaris_exo_core_firmware.bin -Binary -offset 0x00010000 -o vfb.bin -Binary
print('\r\nmerging boot table and application software... ')
cmd = str(r"{} antaris_exo_core_boot_table.bin -Binary -fill 0xff 0x00000000 0x00010000 antaris_exo_core_firmware.bin -Binary -offset 0x00010000 -o antaris_exo_core_vfb.bin -Binary".format(srec_p))
returned_value = os.system(cmd)
if returned_value != 0 : print(' FAILED !!!')
else : print('generated')

# merging bootloader and application software 
# bootloader flash location = 0x8000000
# bootable flash location = 0x8100000
# exo bin flash location 0x8110000
#srec_cat ../../../../exo_sat_bus_btlr/Debug/exo_sat_bus_btlr.bin -Binary antaris_exo_core_vfb.bin -Binary -offset 0x00100000 -o antaris_btlr_app_merged.bin -Binary
# bootloader and exo sat bus ctrl should be checkeed out in same folder


if sys.argv[1] == "release":
    print('\r\nmerging bootloader and application software... ')
    cmd = str(r"{} ../../../exo_sat_bus_btlr/Debug/exo_sat_bus_btlr.bin -Binary -fill 0xff 0x00000000 0x00100000 antaris_exo_core_vfb.bin -Binary -offset 0x00100000 -o antaris_btlr_and_exo_core_merged_vfb.bin -Binary".format(srec_p))
    returned_value = os.system(cmd)
    if returned_value != 0 : print('FAILED !!!')
    else : print('generated')
    
    exit(0)


