diff --git a/Software/EPROM_NG_v2.0rc1.py b/Software/EPROM_NG_v2.0rc1.py deleted file mode 100644 index 2f9a5e5..0000000 --- a/Software/EPROM_NG_v2.0rc1.py +++ /dev/null @@ -1,494 +0,0 @@ -# kris@mygeekyhobby.com -# -# ver 1.0 - may 2020 - initial release -# ver 1.2 - june 2020 - added save to SPI EEPROM functionality -# - fixed the args parsing -# - added auto load wait option -# - added save SPI option -# ver 1.3 - july 2020 - removed some of the debug stuff -# - removed address scrolling when loading -# ver 1.6g - Aug 2020 - Lunches GUI when no parameters specified (code contributed by John Gerrard)... requires PySimpleGUI module "pip install PySimpleGUI" -# - small fixes to the output -# ver 1.6e - fixed bug with SPI==y -# -# ver 2.0rc1 - Oct 2020 - save parameters in GUI -# - .bin and .hex file support -# - binary mode upload with packets of 128-512 bytes at a time -# - Save to SPI works with any type of data range (any source file less than 128 bytes gets "padded" with 0xFF) - -version = "2.0rc1" - -import argparse -import serial,os -import time -import PySimpleGUI as sg -import sys - -# All routines here - -# Print int list in Hex format (for debugging only) -def PrintHex(intList): - row = 0 - for val in intList: - print("%0.2X"%val, end=' ', flush=True) - row += 1 - if row == 64: - print("") - row=0 -# ----------------------------------------------------------------------- -def chunkData(bfr): - """ - Analyze the 64k buffer, find all 128Byte chunks that are in use (have data != to -1) - Will return a list of 512 entries with "1" meaning block of 128Bytes had data chaned and "0" no data changed - """ - mapped=[] - - for i in range(0,len(bfr),128): - chunk = bfr[i:i+128] # split buffer into 128 Bytes chunks - - used = False - - for cell in chunk: # if any byte changed, mark chunk for upload - if cell > 0: - used = True - - if used: - mapped.append(1) - else: - mapped.append(0) - - return mapped -# ----------------------------------------------------------------------- -def plotData(mapped): - """ - Display map of data usage in the buffer, "*" data used and "_" not used - """ - col=0 - for idx in range(len(mapped)): - if idx == 0: # first address special case - print("0x%0.4X"%idx, end=' ', flush=True) - - if mapped[idx] == 1: - print("*", end=' ', flush=True) - else: - print("_", end=' ', flush=True) - col+=1 - if col == 32: - if (idx*128+128) < 65535: - print("") - print("0x%0.4X"%int(idx*128+128),end=' ', flush=True) - col=0 - return -# ----------------------------------------------------------------------- -def packetData(mapped): - data=[] - """ - create a list of tuples [(start_address,size),(start_address,size),...,(start_address,size)] ... size can be 128,256,384,512 - in other words find continues ranges of 128Byte data that has changed, group into packets of 128-512 bytes, create a list for later processing - """ - n=0 - col=0 - start=-2 - for idx in range(len(mapped)): - if mapped[idx] == 1: - if n == 0: - start = idx*128 - n+=1 - if n == 4: - data.append((start,512)) - n=0 - else: - if n > 0: - start = (idx-n)*128 - data.append((start,n*128)) - n=0 - start = -2 - return data -# ----------------------------------------------------------------------- -def Decode(len, sum, addr, data): - - """ - Borrowed this from www.sbprojects.net, credits to San Bergmans - - Decode an Intel string. - - Returns a list of N bytes. - Returns an empty list if an error has occurred. - """ - - global Errors - - checksum = len + (addr & 0xFF) + (addr >> 8) - index = 0 - bytes = [] - - if len <= 0 or len > 32: - # Illegal length - Eprint("Illegal line length found.") - Errors += 1 - return bytes - - while len > 0: - # Iterate over all data bytes - decimal = int(data[index:index+2], 16) - bytes.append(decimal) - checksum = checksum + decimal - index += 2 - len -= 1 - - checksum = (checksum + int(sum, 16)) & 0xFF - - if checksum != 0: - # Checksum didn't add up - Eprint("Checksum error.") - bytes = [] - Errors += 1 - return bytes - - return bytes -# ----------------------------------------------------------------------- -def ParseIntelLine(line): - - """ - Borrowed this from www.sbprojects.net, credits to San Bergmans - - Parse an IntelHex line. - Record types 02, 03, 04 and 05 are ignored. - Maximum payload length is 32 bytes. - Everything after the checksum is ignored. - - Returns True if EOF record found, or when an error is found. - """ - - global Errors - - # Remove EOL character and leading and trailing white space - line = line.strip() - - if len(line) == 0: - # Ignore empty lines - return False - - # Pad the line with plenty of spaces to make parsing easier - # We don't have to worry about the line being too short - line = line + ' '*74 - - if line[0] in ('#', ';'): - # Ignore lines starting with a comment symbol - return False - - if line[0] != ":": - # Line must begin with a colon - Eprint("Illegal start of formatted line.") - Errors += 1 - return True - - if line[7:9] in ('02', '03', '04', '05'): - # These record types are simply ignored - return False - - if line[0:11] == ":00000001FF": - # End of file marker found - return True - - datalength = int(line[1:3], 16) - checksum_index = (datalength + 4) * 2 + 1 - checksum = line[checksum_index:checksum_index + 2] - address = int(line[3:7], 16) - data = line[9:checksum_index] - - # Decode the dataline - bytes = Decode(datalength, checksum, address, data) - if len(bytes) == 0: - # Decoding the line resulted in an error - return True - - #print(address, bytes) - for x in range (0,len(bytes)): - buff64k[x+address] = bytes[x] -# ----------------------------------------------------------------------- - -sg.theme('DarkAmber') # Add a touch of color - -#if not sg.user_settings_get_entry('startaddress',''): # this is a hack for default settings not working for some reason in sg.user_settings module -# sg.user_settings_set_entry('startaddress', "0x0000") - -form = sg.FlexForm('Eprom emulator Uploader 2.0') -from serial.tools.list_ports import comports -com = [p.device for p in comports()] - -layout = [ [sg.Text('Eprom Type'), sg.InputCombo(('2716', '2732','2764', '27128','27256', '27512'),sg.user_settings_get_entry('mem',''), key='mem', size=(10, 6))], - [sg.Text('COM port '), sg.InputCombo(com,sg.user_settings_get_entry('port',''),key='port',size=(10, 1))], - [sg.Checkbox('Save to SPI',sg.user_settings_get_entry('spi',False),key='spi'),sg.Checkbox('Show Data Map',sg.user_settings_get_entry('map',True),key='map')], - [sg.Checkbox('Auto Start',sg.user_settings_get_entry('auto',False),key='auto')], - [sg.Text('Start Address (for *.bin files)'),sg.Input(sg.user_settings_get_entry('startaddress',"0x0000"), key='startaddress', size=(10,1))], # 4 - [sg.Text('Choose A File', size=(35, 1))], - [sg.In(sg.user_settings_get_entry('filename', ''),key='filename'),sg.FileBrowse(file_types=(("iHex files", "*.hex"),("Binary","*.bin")))], # 6 - [sg.Submit(), sg.Cancel()], - ] - - -if len(sys.argv) >= 2: - parser = argparse.ArgumentParser(description='This script sends data to EPROM Emulator over serial port, requires python 3.8, pyserial and pysimplegui (use "pip3 install"') - parser.add_argument('file_arg', metavar='', type=str, help='Data file in 8 bit iHEX (*.hex) or binary format (*.bin)') - parser.add_argument('port_arg', metavar='', type=str, help='Serial port to use, eg COM1 in Windows or "/dev/ttyUSB0" in Linux') - parser.add_argument('-mem', metavar='', type=str, choices=['2716', '2732','2764', '27128', '27256', '27512'], default='27512', help='Emulated EPROM memory type, eg.: 2716..27512. Defaults to 27512') - parser.add_argument('-spi', metavar='y/n', choices=['y','n'], default=False, help='Enable/Disable emulator saves data to SPI EEPROM') - parser.add_argument('-auto', metavar='y/n', choices=['y','n'], default=False, help='Enable/Disable emulator automatically load last saved image and EPROM configuraiton on start.') - parser.add_argument('-start', metavar='', type=str, default="0x0000", help='start address for loading binary files, defaults to 0x0000 if none provided') - parser.add_argument('-map', metavar='y/n', choices=['y','n'], default=True, help='Show a map of memory usage after loading files') - args = parser.parse_args() - mem = args.mem - port = args.port_arg - spi = args.spi - auto = args.auto - startaddrstr = args.start - mapmem = args.map - file = args.file_arg - gui = False -else: - window = sg.Window('EPROM EMU NG GUI Uploader '+version, layout) - gui = True -# Create the Window -# Event Loop to process "events" and get the "values" of the inputs - while True: - event, values = window.read() - mem = values['mem'] - port = values['port'] - spi = values['spi'] - auto = values['auto'] - startaddrstr = values['startaddress'] - mapmem = values['map'] - - if values['spi']: spi="y" - else: spi= "n" - - if values['auto']: auto="y" - else: auto = "n" - - if values['map']: mapmem="y" - else: mapmem = "n" - - file = values['filename'] - if event == sg.WIN_CLOSED or event == 'Cancel': # if user closes window or clicks cancel - exit() - break - if event == 'Submit': # if user closes window or clicks cancel - sg.user_settings_set_entry('filename', values['filename']) - sg.user_settings_set_entry('startaddress', values['startaddress']) - sg.user_settings_set_entry('mem', values['mem']) - sg.user_settings_set_entry('spi', values['spi']) - sg.user_settings_set_entry('auto', values['auto']) - sg.user_settings_set_entry('port', values['port']) - sg.user_settings_set_entry('map', values['map']) - break - - window.close() - -mem_type = "" -if mem == "2716": - mem_type = ':ini16' - max_size = 2048 -elif mem == "2732": - mem_type = ':ini32' - max_size = 4096 -elif mem == "2764": - mem_type = ':ini64' - max_size = 8192 -elif mem == "27128": - mem_type = ':ini128' - max_size = 16384 -elif mem == "27256": - mem_type = ':ini256' - max_size = 32768 -elif mem == "27512": - mem_type = ':ini512' - max_size = 65536 - -try: - ser = serial.Serial(port=port,baudrate=115200,timeout=0.5,writeTimeout=0) -except: - print("Failed to open port, verify port name") - exit() - -# ------------------------------------------------------------------------ -buff64k = [-1]*65536 -# ------------------------------------------------------------------------- -print ("\nRunning EPROM EMU NG python script version",version) -print("") -print("File used: {}\n".format(os.path.basename(file))) - -filename, file_extension = os.path.splitext(file) - -if file_extension.lower() == ".bin": - isbin = True -else: - isbin = False - - -if isbin: # process bin - - startaddr = int(startaddrstr, 16) - binfile = open(file,"rb").read() - file_size = len(binfile) - - # load the binary file into the buffer at start location - for x in range (0,file_size): - buff64k[x+startaddr] = binfile[x] - print("Done processing bin\n") - -else: # process hex file - Bytes_Written = 0 - Errors = 0 - - with open(file) as fp: - while True: - line = fp.readline() - if len(line) > 0: - if ParseIntelLine(line): - break - else: - break - if Errors == 0: - print("Done processing hex\n") - fp.close() - -# generate data map (list of 128Byte chunks that has data) -datamap = chunkData(buff64k) -# display map of data in buffer -if mapmem == "y": - print('Each symbol represents 128Bytes "*" with data, "-" with no data\n') - plotData(datamap) -else: - print("Memory map disabled") -# process data map into a list of 128Byte chunks that can be sent in 1,2,3 or 4 chunks of 128Bytes to the emulator -data = packetData(datamap) - -# ---------------------------------------------------------------------------------- - -print("\n\nUsing serial port {}, emulating: {} EPROM".format(port,mem)) - -time.sleep(2) # on nano, opening the port will trigger reset of the arduino, so need to wait - -try: - for x in range(4): - data_tx = ("\r\n").encode() - ser.write(data_tx) - - ser.flushInput() # ignore anything waiting in the input buffer. - - print("\n-- attempting to get sync --\n") - - data_tx = (":dml\r\n").encode() - ser.write(data_tx) - - response = ser.readline() - - if "HW: " in response.decode(): # Emulator will respond with version number like "HW: v1.0" - print(response.decode()) - elif "...." in response.decode(): - print("Waiting for autoupload to finish... Note: you can disable autoupload by long pressing pushbutton") - while "..." in ser.readline().decode(): - print(".", end=' ', flush=True) - - print("") - time.sleep(2) - ser.flushInput() # ignore anything waiting in the input buffer. - - data_tx = (":dml\r\n").encode() - ser.write(data_tx) - response = ser.readline() - if "HW: " in response.decode(): - print(response.decode()) - else: - print("Failed to connect after autoload - exiting") - exit() - else: - print("Failed to connect - exiting") - exit() - - # - - if spi == "y": - print('-- Setting "Save to SPI EEPROM" option to enable --') - data_tx = (":iniSPI1\r\n").encode() - ser.write(data_tx) - response = ser.readline() - print(response.decode()) - if spi == "n": - print('-- Setting "Save to SPI EEPROM" option to disable --') - data_tx = (":iniSPI0\r\n").encode() - ser.write(data_tx) - response = ser.readline() - print(response.decode()) - - # - # Set the Auto load from SPI EEPROM option - # - if auto == "y": - print('-- Setting "Auto load from SPI EEPROM" option to enable --') - data_tx = (":iniAuto1\r\n").encode() - ser.write(data_tx) - response = ser.readline() - print(response.decode()) - if auto == "n": - print('-- Setting "Auto load from SPI EEPROM" option to disable --') - data_tx = (":iniAuto0\r\n").encode() - ser.write(data_tx) - response = ser.readline() - print(response.decode()) - - print("-- prcessing file --\n") - start = time.time() - - for StartAddr,FrameSize in data: - - # request byte frame processing - data_tx = (":SBN\r\n").encode() - ser.write(data_tx) - # Wait for ACK - response = ser.readline() # this is a form of sync before the array gets sent - # Send address and no of bytes incomming - ser.write((str(StartAddr)+"\n").encode()) - ser.write((str(FrameSize)+"\n").encode()) - # set un-used bytes "-1" to "0xffh" - for x in range (StartAddr,StartAddr+FrameSize): - if buff64k[x] < 0: - buff64k[x] = 0xff - - #print("\nBuffer: ", len(buff64k[StartAddr:StartAddr+FrameSize])," Start Address:",str(hex(StartAddr))) - #PrintHex(buff64k[StartAddr:StartAddr+FrameSize]) - - # send to emulator - ser.write(buff64k[StartAddr:StartAddr+FrameSize]) - # Wait for ACK - - response = ser.readline() - - print("0x%0.4X"%StartAddr,response.decode().strip(), end='\r', flush=True) - - taken = time.time() - start - print("\n\nTime taken to transfer: {}s \n".format(str(round(taken,2)))) - print("-- Setting EPROM Type --") - - data_tx = (mem_type + "\r\n").encode() - ser.write(data_tx) - response = ser.readline() - print(response.decode()) - - print("-- Finished -- ") - - # enable emulation - data_tx = (":EMUON\r\n").encode() - ser.write(data_tx) - - response = ser.readline() - print(response.decode()) - -except Exception as e: - print("Failed to send",e) - -ser.close() -if gui: - input("Press Enter to continue...") -sys.exit(0) \ No newline at end of file