summaryrefslogtreecommitdiffstats
path: root/oncology/dpfhack_display/fw
diff options
context:
space:
mode:
Diffstat (limited to 'oncology/dpfhack_display/fw')
l---------oncology/dpfhack_display/fw/Debug1
-rw-r--r--oncology/dpfhack_display/fw/README115
-rwxr-xr-xoncology/dpfhack_display/fw/chartbl.py96
-rwxr-xr-xoncology/dpfhack_display/fw/detect.py94
-rw-r--r--oncology/dpfhack_display/fw/font4x8.binbin0 -> 65536 bytes
-rwxr-xr-xoncology/dpfhack_display/fw/fulldump.py29
-rwxr-xr-xoncology/dpfhack_display/fw/hackit.py167
-rw-r--r--oncology/dpfhack_display/fw/hexfiles/cmdhandler_14e5.ihx64
-rw-r--r--oncology/dpfhack_display/fw/hexfiles/cmdhandler_14f4.ihx64
-rw-r--r--oncology/dpfhack_display/fw/hexfiles/cmdhandler_14fb.ihx63
-rw-r--r--oncology/dpfhack_display/fw/hexfiles/cmdhandler_big_14fb.ihx64
-rw-r--r--oncology/dpfhack_display/fw/hexfiles/fw_blue.ihx660
-rw-r--r--oncology/dpfhack_display/fw/hexfiles/fw_focal.ihx678
-rw-r--r--oncology/dpfhack_display/fw/hexfiles/fw_focal_landscape.ihx679
-rw-r--r--oncology/dpfhack_display/fw/hexfiles/fw_pearl.ihx686
-rw-r--r--oncology/dpfhack_display/fw/hexfiles/fw_pearl_landscape.ihx686
-rw-r--r--oncology/dpfhack_display/fw/hexfiles/fw_pink.ihx657
-rw-r--r--oncology/dpfhack_display/fw/hexfiles/fw_white.ihx657
-rw-r--r--oncology/dpfhack_display/fw/hexfiles/jmptbl0.ihx3
-rw-r--r--oncology/dpfhack_display/fw/hexfiles/jmptbl1.ihx3
-rw-r--r--oncology/dpfhack_display/fw/hexfiles/jmptbl2.ihx3
-rw-r--r--oncology/dpfhack_display/fw/hexfiles/jmptbl3.ihx3
-rw-r--r--oncology/dpfhack_display/fw/hexfiles/jmptbl_black.ihxbin0 -> 12288 bytes
-rw-r--r--oncology/dpfhack_display/fw/hexfiles/jmptbl_blue.ihx2
-rw-r--r--oncology/dpfhack_display/fw/hexfiles/jmptbl_pearl.ihx2
-rw-r--r--oncology/dpfhack_display/fw/hexfiles/jmptbl_pink.ihx2
-rw-r--r--oncology/dpfhack_display/fw/hexfiles/jmptbl_white.ihx2
-rw-r--r--oncology/dpfhack_display/fw/hexfiles/p_start.ihx5
-rw-r--r--oncology/dpfhack_display/fw/hexfiles/p_start0.ihx5
-rw-r--r--oncology/dpfhack_display/fw/hexfiles/p_start1.ihx5
-rw-r--r--oncology/dpfhack_display/fw/hexfiles/p_start2.ihx5
-rw-r--r--oncology/dpfhack_display/fw/hexfiles/p_start3.ihx6
-rw-r--r--oncology/dpfhack_display/fw/hexfiles/p_start_black.ihx5
-rw-r--r--oncology/dpfhack_display/fw/hexfiles/p_start_blue.ihx6
-rw-r--r--oncology/dpfhack_display/fw/hexfiles/p_start_pearl.ihx5
-rw-r--r--oncology/dpfhack_display/fw/hexfiles/p_start_pink.ihx5
-rw-r--r--oncology/dpfhack_display/fw/hexfiles/p_start_white.ihx5
-rw-r--r--oncology/dpfhack_display/fw/hexfiles/p_usbdesc.ihx16
-rwxr-xr-xoncology/dpfhack_display/fw/profiles.py142
-rw-r--r--oncology/dpfhack_display/fw/struct16846
-rw-r--r--oncology/dpfhack_display/fw/sys38759
-rwxr-xr-xoncology/dpfhack_display/fw/update.py15
42 files changed, 61310 insertions, 0 deletions
diff --git a/oncology/dpfhack_display/fw/Debug b/oncology/dpfhack_display/fw/Debug
new file mode 120000
index 00000000..89798698
--- /dev/null
+++ b/oncology/dpfhack_display/fw/Debug
@@ -0,0 +1 @@
+../Debug \ No newline at end of file
diff --git a/oncology/dpfhack_display/fw/README b/oncology/dpfhack_display/fw/README
new file mode 100644
index 00000000..46ffa999
--- /dev/null
+++ b/oncology/dpfhack_display/fw/README
@@ -0,0 +1,115 @@
+This is rudimentary code to inject your own source into the AX206 based DPFs.
+Since this chip is very much undocumented and no information about the internal
+firmware is available, the following strategy was chosen:
+
+- Leave original firmware as intact as possible (NEVER touch sector 0)
+- Allow to manually put unit into "Developer Mode"
+- Allow to return to default state using the RESET button
+
+Note that the Developer Mode uses two sectors at the end of the internal
+flash. Therefore, DO NOT fill up the frame with images to the maximum,
+or weird things may happen.
+
+When the DPF is hacked using the scripts described below, the Developer Mode
+is simply entered by connecting the DPF to a PC via the USB cable and holding
+the MENU button for approx. 2 seconds.
+
+See more about the Developer Mode below.
+
+----------------------------------------------------------------------------
+
+The tar file contents are merely:
+
+- simple (yet unfinished and quirky) library to access the DPF flash and
+ the extended functionality when in "Developer Mode".
+- Python wrapper around the above library
+- Python scripts to patch various DPFs (listed in profiles.py) and other
+ auxiliaries
+
+Description of a few tools
+---------------------------
+
+app_detect.s, detect.py: Simple rudimentary detection for Sitronix/NXP
+ compatible LCD controllers and SPI flash chip.
+fulldump.py: Performs a dump of the flash according to detected
+ flash size (often specified wrong by vendor)
+
+Developer Mode
+---------------
+
+When the unit is in Developer Mode, it registers itself as USB device with
+the same VID:PID, but not as USB storage. This allows much faster access using
+libusb and as non-root. However, the unit will still use USB storage SCSI
+commands, see dpflib for the wrapping over libusb.
+
+Specific commands are implemented using the handler for the SCSI command
+0xcd, mode 6. These commands are handled on the DPF by cmdhandler.s
+(up to v0.1alpha) and by dpflib/dpflib.c on the target.
+
+Note that the protocol may change in future, once the internal firmware
+is fully replaced by something more structured. Thus, you should implement
+extras on the dpflib level only, never access USB directly.
+
+Prerequisites
+--------------
+
+You need:
+
+- A proper Linux system with GCC, python-dev (libraries and headers to
+ compilee your own modules)
+Optionally:
+- Possibly some knowledge of the 8051, if you want to mess around
+- A working sdcc distribution including asx8051, aslink, etc.
+
+Usage
+------
+
+1. run 'make' to build the tools and patches
+2. Initiate USB connection from the DPF via the menu
+3. Wait a while and check dmesg for the /dev/sgX assignment
+4. Run 'python hackit.py /dev/sgX' as root (CAREFUL!!!) to probe for
+ known DPFs and confirm that you wish to patch the DPF according to the
+ instructions.
+
+The hackit.py script checks for a valid DPF, so you can not accidentally
+damage your hard disk. Also, it runs a crc32 check on critical modules
+for more safety. DO NOT CHANGE the existing checksums. Only *add* new
+profiles in profiles.py, don't EVER change existing ones.
+
+Before messing around, you might want to dump the entire flash using the
+fulldump.py script.
+
+For those desiring to try adding hacks for other frame models, there is
+now a short howto in the reverse/ folder.
+
+----------------------------------------------------------------------------
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+WARNING: Do not modify the script unless you REALLY know what you are doing.
+
+DISCLAIMER: There is no guarantee that you will not brick your DPF.
+The Author(s) of this code take no responsibilities. You are completely on
+your own there!
+If you bricked your DPF, check the URL below for information how to restore
+the flash image.
+
+LICENSE:
+You are allowed to modify and distribute the code, as long as you keep it
+OpenSource. We just trust you that you have a notion of fair usage :-)
+
+TODO:
+1. Windows support, fully featured lcd4linux support via generic DPF library
+ (I leave this to others. I hate Windows.)
+2. Replace flash firmware with improved opensource environment
+
+----------------------------------------------------------------------------
+
+Find updates and documentation here:
+
+http://picframe.spritesserver.nl/wiki/index.php/DPF_with_AppoTech_AX206
+
+or here:
+
+http://tech.section5.ch/news/?p=68
+
+----------------------------------------------------------------------------
diff --git a/oncology/dpfhack_display/fw/chartbl.py b/oncology/dpfhack_display/fw/chartbl.py
new file mode 100755
index 00000000..a3015c6a
--- /dev/null
+++ b/oncology/dpfhack_display/fw/chartbl.py
@@ -0,0 +1,96 @@
+import struct
+import sys
+
+rgbformat = "BBB"
+CHAR_WIDTH = 4
+CHAR_HEIGHT = 8
+
+context = {
+ 'nrows' : 0,
+ 'ncols' : 0,
+ 'width' : 0,
+ 'height' : 0,
+}
+
+
+def rgbto565(r, g, b):
+ return (( (r & 0xf8) ) | ((g & 0xe0) >> 5),
+ ( (g & 0x1c) << 3 ) | ((b & 0xf8) >> 3))
+
+
+def gentbl():
+ c = 0
+ a = ""
+ for i in range(32, 127):
+ a += "%c" % chr(i)
+ c += 1
+ if c == 16:
+ c = 0
+ a = ""
+
+
+def output_chr(context, out, data, offset):
+ width = context['width']
+ for i in range(CHAR_HEIGHT):
+ off = offset + i * width
+ for j in range(CHAR_WIDTH):
+ o = 3 * (off + j)
+ r, g, b = struct.unpack(rgbformat, data[o:o + 3])
+ rgb565 = rgbto565(r, g, b)
+ out += chr(rgb565[0])
+ out += chr(rgb565[1])
+ return out
+
+def convert2table(context, data):
+ out = ""
+ width = context['width']
+ for i in xrange(context['nrows']):
+ off = i * CHAR_HEIGHT * width
+ for j in xrange(context['ncols']):
+ o = off + j * CHAR_WIDTH
+ out = output_chr(context, out, data, o)
+ return out
+
+def readpnm(context, prefix):
+ pnm = open(prefix + ".pnm", "r")
+
+ d = pnm.readline()
+ d = pnm.readline()
+ l = pnm.readline()
+ a, b = l.split()
+ x, y = int(a), int(b)
+ a = pnm.readline()
+
+ l = x * y
+ context['width'] = x
+ context['height'] = y
+ context['ncols'] = x / CHAR_WIDTH
+ context['nrows'] = y / CHAR_HEIGHT
+
+ data = pnm.read()
+ pnm.close()
+
+ return data
+
+def convert2raw(context, data):
+
+ out = ""
+
+ for i in xrange(l):
+ off = 3 * i
+ r, g, b = struct.unpack(rgbformat, data[off:off + 3])
+ rgb565 = rgbto565(r, g, b)
+ out += chr(rgb565[0])
+ out += chr(rgb565[1])
+
+ return out
+
+# gentbl()
+c = {}
+
+out = readpnm(c, sys.argv[1])
+out = convert2table(c, out)
+
+f = open(sys.argv[1] + ".bin", "w")
+f.write(out)
+f.close()
diff --git a/oncology/dpfhack_display/fw/detect.py b/oncology/dpfhack_display/fw/detect.py
new file mode 100755
index 00000000..e667ae5f
--- /dev/null
+++ b/oncology/dpfhack_display/fw/detect.py
@@ -0,0 +1,94 @@
+# Simple detection module for AX206 based DPF hardware
+# (c) 2011 <hackfin@section5.ch>
+#
+# Run with argument:
+#
+# - generic scsi device, e.g. /dev/sg1
+# or:
+# - "usb0" for hacked device
+#
+# NOTE: The LCD detection will only work on a hacked device
+
+import struct
+import sys
+sys.path.append("./Debug")
+import dpf
+
+g_spansion_types = {
+ 0x13: ("s25fl008", 16, 0x10000)
+}
+
+g_stm_types = {
+ 0x14: ("m25p80", 16, 0x10000),
+ 0x15: ("m25p16", 32, 0x10000),
+ 0x16: ("m25p32", 64, 0x10000)
+}
+
+g_amic_types = {
+ 0x13: ("a25l080", 16, 0x10000),
+}
+
+g_vendors = {
+ 0x00: ("ST legacy", g_stm_types),
+ 0x01: ("Spansion", g_spansion_types),
+ 0x20: ("ST/Numonyx", g_stm_types),
+ 0x1c: ("EON", g_stm_types),
+ 0x37: ("AMIC", g_amic_types),
+ 0xc2: ("Macronix", g_stm_types),
+ 0xc8: ("Apple", g_stm_types),
+ 0xef: ("Winbond", g_stm_types)
+}
+
+g_lcdmanu = {
+ 0x45: "Philips/NXP",
+ 0x5c: "Sitronix",
+ 0x54: "Ilitek"
+}
+
+g_lcdctrl = {
+ 0x66: "ILI9163B",
+ 0xf0: "ST7735R"
+}
+
+
+def detect_lcd(d):
+ d.writeMemory("app_detect.ihx")
+ d.run(0x18a0)
+ buf = d.readMemory(0x1900, 4)
+
+ v = struct.unpack("BBBB", buf)
+
+ if v[1] != 0xff:
+ try:
+ manu = g_lcdmanu[v[1]]
+ print "Manufacturer:", manu
+ print "Module/driver version:", hex(v[2])
+ print "Identified module:", g_lcdctrl[v[3]]
+ except KeyError:
+ print "Unknown module id", hex(v[1]), hex(v[2]), hex(v[3])
+ else:
+ print "Does not support RDID"
+
+def detect_flash(d):
+ manu, dev0, dev1 = d.probeFlash()
+ try:
+ print "Manufacturer: %s" % g_vendors[manu][0]
+ f = g_vendors[manu][1][dev1]
+ except KeyError:
+ print "Unknown Manufacturer"
+ print "Got id[3]: %x, %x, %x" % (manu, dev0, dev1)
+ try:
+ f = g_stm_types[1][dev1]
+ print "Compatible : %s" % f[0]
+ except KeyError:
+ print "Unable to detect flash, just assuming 2MB size"
+ f = ("m25p16", 32, 0x10000)
+ bytes = f[1] * f[2]
+ print "Size : %d MB" % (bytes / (1024 * 1024))
+ return bytes
+
+if __name__ == "__main__":
+ d = dpf.open(sys.argv[1])
+ detect_flash(d)
+ detect_lcd(d)
+ d.close()
diff --git a/oncology/dpfhack_display/fw/font4x8.bin b/oncology/dpfhack_display/fw/font4x8.bin
new file mode 100644
index 00000000..cd158c61
--- /dev/null
+++ b/oncology/dpfhack_display/fw/font4x8.bin
Binary files differ
diff --git a/oncology/dpfhack_display/fw/fulldump.py b/oncology/dpfhack_display/fw/fulldump.py
new file mode 100755
index 00000000..28c0ad2c
--- /dev/null
+++ b/oncology/dpfhack_display/fw/fulldump.py
@@ -0,0 +1,29 @@
+# Script to extract flash
+#
+# <hackfin@section5.ch>
+#
+# Argument is either:
+#
+# /dev/sgX : scsi device (unhacked mode)
+# usb0 : developer mode (already hacked)
+
+import sys
+sys.path.append("./Debug")
+import dpf
+
+import detect
+
+d = dpf.open(sys.argv[1])
+
+size = detect.detect_flash(d)
+
+# Offset, size
+print "Reading %x bytes..." % size
+buf = d.readFlash(0x00, size)
+
+f = open("full.bin", "wb")
+f.write(buf)
+f.close()
+
+d.close()
+
diff --git a/oncology/dpfhack_display/fw/hackit.py b/oncology/dpfhack_display/fw/hackit.py
new file mode 100755
index 00000000..5c7a5ae9
--- /dev/null
+++ b/oncology/dpfhack_display/fw/hackit.py
@@ -0,0 +1,167 @@
+#!/usr/bin/python
+import struct
+import sys
+sys.path.append("./Debug")
+import dpf
+import time
+import binascii
+
+# DPF profiles
+import profiles
+
+# If you are an expert, set this to 0 to avoid the warnings
+paranoia_mode = 1
+
+JUMPTABLE_OFFSET = 0x80
+HEXDIR = "hexfiles/"
+
+instructions = [
+ """Press and hold MENU while USB is plugged in.
+If successful, you will get the 'USB connect' message and the device
+will appear as non-USB storage device"""
+]
+
+ins_common = """To put the device back into (almost) original state working
+as USB storage, press the RESET button."""
+
+############################################################################
+
+bswap = lambda x: ( (x >> 8) & 0xff ) | ((x << 8) & 0xff00)
+
+def dump_flash(d, fname, offset, size):
+ data = d.readFlash(offset, size)
+ f = open(fname, "wb")
+ f.write(data)
+ f.close()
+
+def find_dpf(version):
+ for i in profiles.KNOWN_DPFS:
+ v = i[0]
+ if v[0] == str(version[0]) and v[1] == str(version[1]) and v[2] == str(version[2]):
+ print "Found matching version info"
+ return i
+ return None
+
+def get_module(buf, n):
+ n *= 8
+ start, end, flashaddr = struct.unpack("<HHI", buf[n:n+8])
+
+ start = bswap(start)
+ end = bswap(end)
+
+ return start, end, flashaddr
+
+def patch_module(d, record, buf):
+ n = record[0]
+ if n == profiles.BINARY: # Write full binary into sector
+ start, flashaddr = record[1]
+ f = open(record[2])
+ d.eraseFlash(flashaddr)
+ buf = f.read()
+ f.close()
+ d.writeFlash(flashaddr, buf)
+ elif n == profiles.PATCH: # We make a copy of a full sector
+ start, flashaddr = record[1]
+ print "Patching sector addr %06x with %s" % (flashaddr, record[2])
+ d.patchSector(start, flashaddr, HEXDIR + record[2])
+ elif n == profiles.COPY: # We make a copy of a full sector
+ src, dest = record[1]
+ print "Copying sector from 0x%06x to 0x%06x..." %(src, dest)
+ data = d.readFlash(src, 0x10000)
+ d.eraseFlash(dest)
+ d.writeFlash(dest, data)
+ else:
+ print "Analyzing module %d..." % n
+ start, end, flashaddr = get_module(buf, n)
+ l = end - start
+ start += 0x800
+ data = d.readFlash(flashaddr, l)
+ c = binascii.crc32(data) & 0xffffffff
+ checksums = record[1]
+ i = 0
+ try:
+ i = checksums.index(c)
+ except ValueError:
+ print "CRC32 does not match: 0x%08lx" % c
+ return False
+
+ n = len(checksums) - 1
+
+ if i == n:
+ print "Seems up to date. Do you still wish to patch?"
+ a = raw_input("Type 'yes' to continue > ")
+ if a != "yes":
+ return True
+ print "Updating module.."
+ else:
+ print "Patching from version %d to %d" % (i, n)
+
+ d.patchSector(start, flashaddr, HEXDIR + record[2])
+
+ return True
+
+def recognize(d):
+ print "Reading flash..."
+ buf = d.readFlash(0x0, 0x280)
+
+ print "done"
+ b = buf[:7]
+ xmem, code, dummy, offset = struct.unpack(">HHBH", b)
+ version = (buf[0x50:0x58], buf[0x60: 0x70], buf[0x80:0x88])
+
+ dpf = find_dpf(version)
+ if not dpf:
+ print "No DPF found. Create a record or look for one"
+ print version
+ else:
+ print "Identifier:", dpf[1]
+ di = dpf[3]
+ di['offset'] = offset
+
+ return dpf
+
+def patch(d, dpf):
+ if (paranoia_mode):
+ print """Now patching. There is no 100% guarantee that your device will
+ work after doing this. You must never unplug the device from USB while
+ it is being updated.
+ Are you sure you take all risks and that you want to continue?"""
+ a = raw_input("Type 'yes' to continue > ")
+ if a != "yes":
+ print "Aborting."
+ return False
+
+ p = dpf[4]
+
+ buf = d.readFlash(JUMPTABLE_OFFSET, dpf[3]['offset'])
+ for i in p[2]:
+ if not patch_module(d, i, buf):
+ return False
+
+ return True
+#
+#
+# MAIN
+
+if len(sys.argv) != 2:
+ print "Usage: %s [<generic scsi device> | usb0]" % sys.argv[0]
+ print "You may have to run this as root when accessing generic scsi devices"
+ sys.exit(-1)
+
+d = dpf.open(sys.argv[1])
+
+dpf = recognize(d)
+if dpf:
+ r = dpf[4]
+ ret = patch(d, dpf)
+ if ret:
+ print
+ print "Now disconnect the DPF from USB."
+ print "To activate the 'developer mode':"
+ print
+ print instructions[r[0]]
+ print
+ print ins_common
+ else:
+ print "DPF might not be completely patched."
+d.close()
diff --git a/oncology/dpfhack_display/fw/hexfiles/cmdhandler_14e5.ihx b/oncology/dpfhack_display/fw/hexfiles/cmdhandler_14e5.ihx
new file mode 100644
index 00000000..3841cc6a
--- /dev/null
+++ b/oncology/dpfhack_display/fw/hexfiles/cmdhandler_14e5.ihx
@@ -0,0 +1,64 @@
+:0913300043C80530CEFDE5C922D9
+:0713390075CA143004012203
+:0E13400043C80530CEFDC2CEE5C930E0EF2235
+:07134E0075CA1130040122F1
+:0E13550043C80530CEFDC2CEE5C920E0EF2230
+:0A13630053C8FB43C80130CEFD2241
+:0D136D0075CA0E75C901716375CA1475C982
+:03137A000080E60A
+:0D137D0075CA0E75C901716375CA1175C975
+:03138A000180D609
+:04138D00F5C980D24C
+:09139100E6F5C9716308D9F822E0
+:09139A00E493F5C97163D9F8224E
+:0E13A3004386108C828D83EA2CC5F0EB3DA8AA
+:0213B100F0F951
+:0713B30071397C4075CA216D
+:0B13BA007130F0E8B58207E9B583034D
+:0313C500716D2225
+:0613C800DCF0716D80E510
+:0B13CE00714E75CA218C828D83EAF9F4
+:0413D900719A717D17
+:0313DD00714E222C
+:0C13E0008C828D837CF87D001215427415
+:0913EC00F5C0E07413C0E0E473E5
+:0113F50022D5
+:0C13F600438610E4F550F551F552F55314
+:0B140200714E75CA217455718D745332
+:08140D00718D7442718D74535E
+:0C141500718D788479047191789F7904BE
+:0614210071917400718D51
+:08142700717D714E7904789F7C
+:03142F00913222D5
+:01143200E4D5
+:05143300F608D9FC22BF
+:0E14E5007895E6C5F008E6FC08E6FD08E6FA94
+:0C14F30008E6FBC5F0B4010471A38025DD
+:0714FF00B4020471E0801E3D
+:07150600B4040471CE80174C
+:07150D00B41004B1298010A5
+:07151400B41104B15D800970
+:07151B00B41204B16180026B
+:02152200B142D4
+:0515240071F602181829
+:0C152900E4F577F578F579F57A757B7FAD
+:08153500757C00757D7F757E59
+:05153D000012128022E3
+:05154200B129E4F8F9F5
+:0E154700EC120F25ED120F25D3E438F8E4392D
+:08155500F9B800EEB940EB22E9
+:04155D00B129A17D92
+:0E1561008C778D788A798B7A789AE6F57B08FC
+:0E156F00E6F57C08E6F57D08E6F57E121280B2
+:0A157D007888E6FB08E6FC08E6FDAE
+:0E158700EBF5F033CC33CD33FBEC33CD33CB6F
+:0815950033FCE5F003541FFDD7
+:0B159D00EB4C601C71397F2075CA21E7
+:0C15A8007130120F257130120F25DFF496
+:0715B400716D1BBBFF011C60
+:0215BB0080E0CE
+:0815BD00ED6013713975CA21BC
+:0C15C5007130120F257130120F25DDF47B
+:0215D100716D3A
+:0115D30022F5
+:00000001FF
diff --git a/oncology/dpfhack_display/fw/hexfiles/cmdhandler_14f4.ihx b/oncology/dpfhack_display/fw/hexfiles/cmdhandler_14f4.ihx
new file mode 100644
index 00000000..c71b29fa
--- /dev/null
+++ b/oncology/dpfhack_display/fw/hexfiles/cmdhandler_14f4.ihx
@@ -0,0 +1,64 @@
+:0913300043C80530CEFDE5C922D9
+:0713390075CA143004012203
+:0E13400043C80530CEFDC2CEE5C930E0EF2235
+:07134E0075CA1130040122F1
+:0E13550043C80530CEFDC2CEE5C920E0EF2230
+:0A13630053C8FB43C80130CEFD2241
+:0D136D0075CA0E75C901716375CA1475C982
+:03137A000080E60A
+:0D137D0075CA0E75C901716375CA1175C975
+:03138A000180D609
+:04138D00F5C980D24C
+:09139100E6F5C9716308D9F822E0
+:09139A00E493F5C97163D9F8224E
+:0E13A3004386108C828D83EA2CC5F0EB3DA8AA
+:0213B100F0F951
+:0713B30071397C4075CA216D
+:0B13BA007130F0E8B58207E9B583034D
+:0313C500716D2225
+:0613C800DCF0716D80E510
+:0B13CE00714E75CA218C828D83EAF9F4
+:0413D900719A717D17
+:0313DD00714E222C
+:0C13E0008C828D837CF87D001215517406
+:0913EC00F5C0E07413C0E0E473E5
+:0113F50022D5
+:0C13F600438610E4F550F551F552F55314
+:0B140200714E75CA217455718D745332
+:08140D00718D7442718D74535E
+:0C141500718D788479047191789F7904BE
+:0614210071917400718D51
+:08142700717D714E7904789F7C
+:03142F00913222D5
+:01143200E4D5
+:05143300F608D9FC22BF
+:0E14F4007895E6C5F008E6FC08E6FD08E6FA85
+:0C15020008E6FBC5F0B4010471A38025CD
+:07150E00B4020471E0801E2D
+:07151500B4040471CE80173D
+:07151C00B41004B138801087
+:07152300B41104B16C800952
+:07152A00B41204B17080024D
+:02153100B151B6
+:0515330071F60218181A
+:0C153800E4F577F578F579F57A757B7F9E
+:08154400757C00757D7F757E4A
+:05154C000012128022D4
+:05155100B138E4F8F9D7
+:0E155600EC120F25ED120F25D3E438F8E4391E
+:08156400F9B800EEB940EB22DA
+:04156C00B138A18C65
+:0E1570008C778D788A798B7A789AE6F57B08ED
+:0E157E00E6F57C08E6F57D08E6F57E121280A3
+:0A158C007888E6FB08E6FC08E6FD9F
+:0E159600EBF5F033CC33CD33FBEC33CD33CB60
+:0815A40033FCE5F003541FFDC8
+:0B15AC00EB4C601C71397F2075CA21D8
+:0C15B7007130120F257130120F25DFF487
+:0715C300716D1BBBFF011C51
+:0215CA0080E0BF
+:0815CC00ED6013713975CA21AD
+:0C15D4007130120F257130120F25DDF46C
+:0215E000716D2B
+:0115E20022E6
+:00000001FF
diff --git a/oncology/dpfhack_display/fw/hexfiles/cmdhandler_14fb.ihx b/oncology/dpfhack_display/fw/hexfiles/cmdhandler_14fb.ihx
new file mode 100644
index 00000000..2e6cf3a4
--- /dev/null
+++ b/oncology/dpfhack_display/fw/hexfiles/cmdhandler_14fb.ihx
@@ -0,0 +1,63 @@
+:0913300043C80530CEFDE5C922D9
+:0713390075CA143004012203
+:0E13400043C80530CEFDC2CEE5C930E0EF2235
+:07134E0075CA1130040122F1
+:0E13550043C80530CEFDC2CEE5C920E0EF2230
+:0A13630053C8FB43C80130CEFD2241
+:0D136D0075CA0E75C901716375CA1475C982
+:03137A000080E60A
+:0D137D0075CA0E75C901716375CA1175C975
+:03138A000180D609
+:04138D00F5C980D24C
+:09139100E6F5C9716308D9F822E0
+:09139A00E493F5C97163D9F8224E
+:0E13A3004386108C828D83EA2CC5F0EB3DA8AA
+:0213B100F0F951
+:0713B30071397C4075CA216D
+:0B13BA007130F0E8B58207E9B583034D
+:0313C500716D2225
+:0613C800DCF0716D80E510
+:0B13CE00714E75CA218C828D83EAF9F4
+:0413D900719A717D17
+:0313DD00714E222C
+:0C13E0008C828D837CF87D0012155874FF
+:0913EC00F5C0E07413C0E0E473E5
+:0113F50022D5
+:0C13F600438610E4F550F551F552F55314
+:0B140200714E75CA217455718D745332
+:08140D00718D7442718D74535E
+:0C141500718D788479047191789F7904BE
+:0614210071917400718D51
+:08142700717D714E7904789F7C
+:03142F00913222D5
+:01143200E4D5
+:05143300F608D9FC22BF
+:0E14FB007895E6C5F008E6FC08E6FD08E6FA7E
+:0C15090008E6FBC5F0B4010471A38025C6
+:07151500B4020471E0801E26
+:07151C00B4040471CE801736
+:07152300B41004B13F801079
+:07152A00B41104B173800944
+:07153100B41204B17780023F
+:02153800B158A8
+:05153A0071F602181813
+:0E153F00E4F577F578F579F57A757B7F757CA4
+:0B154D0000757D7F757E001212802269
+:05155800B13FE4F8F9C9
+:0E155D00EC120F25ED120F25D3E438F8E43917
+:08156B00F9B800EEB940EB22D3
+:04157300B13FA19350
+:0E1577008C778D788A798B7A789AE6F57B08E6
+:0E158500E6F57C08E6F57D08E6F57E1212809C
+:0A1593007888E6FB08E6FC08E6FD98
+:0E159D00EBF5F033CC33CD33FBEC33CD33CB59
+:0815AB0033FCE5F003541FFDC1
+:0B15B300EB4C601C71397F2075CA21D1
+:0C15BE007130120F257130120F25DFF480
+:0715CA00716D1BBBFF011C4A
+:0215D10080E0B8
+:0815D300ED6013713975CA21A6