Initial commit
This commit is contained in:
commit
2d6428446e
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
samples/
|
44
README.md
Normal file
44
README.md
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
# Intro
|
||||||
|
|
||||||
|
Mobitec flip-disc displays use MC27C1001 EPROM-s to store the
|
||||||
|
firmware (?) and fonts.
|
||||||
|
In the `firmware/` directory you can find two ROM dumps.
|
||||||
|
|
||||||
|
# Useful commands
|
||||||
|
|
||||||
|
To extract font sections:
|
||||||
|
|
||||||
|
```
|
||||||
|
dd if=mobitec-1682-r7-bib-01979-r3.bin of=mobitec-1682-r7-bib-01979-r3-fonts.bin skip=64 bs=1024
|
||||||
|
dd if=mobitec-01682-r7-bib-01369-r9.bin of=mobitec-01682-r7-bib-01369-r9-fonts.bin skip=64 bs=1024
|
||||||
|
```
|
||||||
|
|
||||||
|
For diffing font sections:
|
||||||
|
|
||||||
|
```
|
||||||
|
dhex mobitec-1682-r7-bib-01979-r3-fonts.bin mobitec-01682-r7-bib-01369-r9-fonts.bin
|
||||||
|
```
|
||||||
|
|
||||||
|
# Dump structure
|
||||||
|
|
||||||
|
The firmware seems to be located in the first 7KiB and the font data
|
||||||
|
starts at 0x10000 offset.
|
||||||
|
|
||||||
|
The font beginning marker seem to consist of a character from `a` to `z`
|
||||||
|
followed by at least 60 null characters.
|
||||||
|
They don't seem aligned or indexed in any way so easiest is just to scan
|
||||||
|
for known markers.
|
||||||
|
|
||||||
|
After the beginning marker you can find the lookup table which maps
|
||||||
|
printable ASCII characters to a glyph address.
|
||||||
|
The lookup table is 190 bytes (95x 16-bit addresses) which correspond
|
||||||
|
to ASCII characters 32 up to 126.
|
||||||
|
Not all fonts include all characters, missing glyphs are represented by address 0.
|
||||||
|
Note that the glyph address is relative to the beginning of font structure,
|
||||||
|
beginning marker inclusive.
|
||||||
|
|
||||||
|
At the glyph address first width and height of the glyph are found represented
|
||||||
|
by two 8-bit integers. The actual bitmap data follows in 8x8 pixel tiles
|
||||||
|
packed together as 8 bytes.
|
||||||
|
|
||||||
|
|
122
extract-fonts.py
Normal file
122
extract-fonts.py
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
import json
|
||||||
|
import cv2
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
"""
|
||||||
|
dd if=mobitec-1682-r7-bib-01979-r3.bin of=mobitec-1682-r7-bib-01979-r3-fonts.bin skip=64 bs=1024
|
||||||
|
dd if=mobitec-01682-r7-bib-01369-r9.bin of=mobitec-01682-r7-bib-01369-r9-fonts.bin skip=64 bs=1024
|
||||||
|
dhex mobitec-1682-r7-bib-01979-r3-fonts.bin mobitec-01682-r7-bib-01369-r9-fonts.bin
|
||||||
|
"""
|
||||||
|
|
||||||
|
src = "mobitec-1682-r7-bib-01979-r3"
|
||||||
|
src = "mobitec-01682-r7-bib-01369-r9"
|
||||||
|
|
||||||
|
with open("firmware/%s.bin" % src, "rb") as fh:
|
||||||
|
buf = fh.read()[65536:]
|
||||||
|
|
||||||
|
|
||||||
|
def scan_fonts(buf):
|
||||||
|
"""
|
||||||
|
Font start markers seem to be ascii character a..z followed by at least 60 nulls
|
||||||
|
"""
|
||||||
|
font_index = buf[0]
|
||||||
|
assert font_index == 0x61
|
||||||
|
prev = 0
|
||||||
|
done = False
|
||||||
|
while not done:
|
||||||
|
needle = b"%c" % (font_index + 1)
|
||||||
|
needle += 50 * b"\x00"
|
||||||
|
try:
|
||||||
|
font_offset = buf.index(needle)
|
||||||
|
except ValueError:
|
||||||
|
break
|
||||||
|
font_body = buf[prev:]
|
||||||
|
done = True
|
||||||
|
else:
|
||||||
|
font_body = buf[prev:font_offset]
|
||||||
|
if done:
|
||||||
|
break
|
||||||
|
font_marker_length = len(needle)
|
||||||
|
font_body = font_body[font_marker_length:]
|
||||||
|
while font_body.startswith(b"\x00"):
|
||||||
|
font_body = font_body[1:]
|
||||||
|
font_marker_length += 1
|
||||||
|
yield font_index, font_body, font_marker_length
|
||||||
|
prev = font_offset
|
||||||
|
font_index += 1
|
||||||
|
|
||||||
|
|
||||||
|
meta = []
|
||||||
|
for font_index, font_body, font_marker_length in scan_fonts(buf):
|
||||||
|
print()
|
||||||
|
print("Parsing font %02x" % font_index)
|
||||||
|
|
||||||
|
# Looks like yet another marker
|
||||||
|
assert font_body[0] == 3
|
||||||
|
assert font_body[1] == 1
|
||||||
|
|
||||||
|
# Look up table consists of 95 16-bit integers
|
||||||
|
glyph_offsets = np.frombuffer(font_body[2:192], dtype=np.uint16)
|
||||||
|
prev = 0
|
||||||
|
slices = []
|
||||||
|
errors = set()
|
||||||
|
|
||||||
|
for index, glyph_offset in enumerate(glyph_offsets):
|
||||||
|
if glyph_offset != 0:
|
||||||
|
glyph_offset -= font_marker_length
|
||||||
|
print("Found %d undecoded bytes between lookup table and first glyph" % len(font_body[192:192 + glyph_offset]))
|
||||||
|
break
|
||||||
|
|
||||||
|
characters_present = ""
|
||||||
|
|
||||||
|
for index, glyph_offset in enumerate(glyph_offsets):
|
||||||
|
if glyph_offset == 0:
|
||||||
|
characters_present += "_"
|
||||||
|
# No glyph
|
||||||
|
meta.append(None)
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
# The index goes from space (32) up to ~ (126)
|
||||||
|
character = chr(index + 32)
|
||||||
|
characters_present += "+"
|
||||||
|
|
||||||
|
# Glyphs are relative to the font marker start
|
||||||
|
glyph_offset -= font_marker_length
|
||||||
|
|
||||||
|
try:
|
||||||
|
height, width = font_body[glyph_offset], font_body[glyph_offset + 1]
|
||||||
|
except IndexError:
|
||||||
|
print("Failed to look up glyph for %s", repr(character))
|
||||||
|
else:
|
||||||
|
jah = np.frombuffer((font_body[glyph_offset + 2:])[::-1], dtype=np.uint8)[::-1]
|
||||||
|
a = np.unpackbits(jah, axis=0)
|
||||||
|
try:
|
||||||
|
img = a[:width * 16].reshape((width, 16, 1))
|
||||||
|
img = np.hstack([img[:, 8:, :], img[:, :8, :]])
|
||||||
|
meta.append({
|
||||||
|
"width": width,
|
||||||
|
"height": height,
|
||||||
|
"bitmap": img.tolist()
|
||||||
|
})
|
||||||
|
img = 255 * img
|
||||||
|
|
||||||
|
slices.append(img)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
blank_image = np.zeros((1, 16, 1), np.uint8)
|
||||||
|
blank_image[::] = 0
|
||||||
|
slices.append(blank_image)
|
||||||
|
|
||||||
|
if glyph_offset <= prev:
|
||||||
|
print("Glyph offsets not ordered")
|
||||||
|
prev = glyph_offset
|
||||||
|
print("Glyphs present:", characters_present)
|
||||||
|
img = np.vstack(slices)
|
||||||
|
|
||||||
|
img = np.flip(np.swapaxes(img, 1, 0), 0)
|
||||||
|
s = img.shape * np.array(5)
|
||||||
|
img = cv2.resize(img, dsize=(s[1], s[0]), interpolation=cv2.INTER_NEAREST)
|
||||||
|
cv2.imwrite("samples/%s-%02x.png" % (src, font_index), img)
|
||||||
|
with open("samples/%s-%02x.json" % (src, font_index), "w") as fh:
|
||||||
|
fh.write(json.dumps({"glyphs": meta}))
|
BIN
firmware/mobitec-01682-r7-bib-01369-r9.bin
Normal file
BIN
firmware/mobitec-01682-r7-bib-01369-r9.bin
Normal file
Binary file not shown.
BIN
firmware/mobitec-1682-r7-bib-01979-r3.bin
Normal file
BIN
firmware/mobitec-1682-r7-bib-01979-r3.bin
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user