|
@@ -5,31 +5,120 @@
|
|
|
# This is free and unencumbered software released into the public domain.
|
|
|
# See the file COPYING for more details, or visit <http://unlicense.org>.
|
|
|
|
|
|
+import struct
|
|
|
+
|
|
|
+from greaseweazle.flux import Flux
|
|
|
+from greaseweazle.bitcell import Bitcell
|
|
|
+from bitarray import bitarray
|
|
|
+
|
|
|
class HFE:
|
|
|
|
|
|
def __init__(self, start_cyl, nr_sides):
|
|
|
self.start_cyl = start_cyl
|
|
|
self.nr_sides = nr_sides
|
|
|
- self.nr_revs = None
|
|
|
+ self.bitrate = 250 # XXX real bitrate?
|
|
|
+ # Each track is (bitlen, rawbytes).
|
|
|
+ # rawbytes is a bytes() object in little-endian bit order.
|
|
|
self.track_list = []
|
|
|
|
|
|
|
|
|
@classmethod
|
|
|
def from_file(cls, dat):
|
|
|
- hfe = cls(0, 2)
|
|
|
+
|
|
|
+ (sig, f_rev, nr_cyls, nr_sides, t_enc, bitrate,
|
|
|
+ _, _, _, tlut_base) = struct.unpack("<8s4B2H2BH", dat[:20])
|
|
|
+ assert sig != b"HXCHFEV3", "HFEv3 is not supported"
|
|
|
+ assert sig == b"HXCPICFE" and f_rev <= 1, "Not a valid HFE file"
|
|
|
+ assert 0 < nr_cyls
|
|
|
+ assert 0 < nr_sides < 3
|
|
|
+ assert bitrate != 0
|
|
|
+
|
|
|
+ hfe = cls(0, nr_sides)
|
|
|
+ hfe.bitrate = bitrate
|
|
|
+
|
|
|
+ tlut = dat[tlut_base*512:tlut_base*512+nr_cyls*4]
|
|
|
+
|
|
|
+ for cyl in range(nr_cyls):
|
|
|
+ for side in range(nr_sides):
|
|
|
+ offset, length = struct.unpack("<2H", tlut[cyl*4:(cyl+1)*4])
|
|
|
+ todo = length // 2
|
|
|
+ tdat = bytes()
|
|
|
+ while todo:
|
|
|
+ d_off = offset*512 + side*256
|
|
|
+ d_nr = 256 if todo > 256 else todo
|
|
|
+ tdat += dat[d_off:d_off+d_nr]
|
|
|
+ todo -= d_nr
|
|
|
+ offset += 1
|
|
|
+ hfe.track_list.append((len(tdat)*8, tdat))
|
|
|
+
|
|
|
return hfe
|
|
|
|
|
|
|
|
|
def get_track(self, cyl, side, writeout=False):
|
|
|
- return None
|
|
|
-
|
|
|
-
|
|
|
+ if side >= self.nr_sides or cyl < self.start_cyl:
|
|
|
+ return None
|
|
|
+ off = cyl * self.nr_sides + side
|
|
|
+ if off >= len(self.track_list):
|
|
|
+ return None
|
|
|
+ bitlen, rawbytes = self.track_list[off]
|
|
|
+ tdat = bitarray(endian='little')
|
|
|
+ tdat.frombytes(rawbytes)
|
|
|
+ tdat = tdat[:bitlen]
|
|
|
+ return Flux.from_bitarray(tdat, self.bitrate * 2000)
|
|
|
+
|
|
|
+
|
|
|
def append_track(self, flux):
|
|
|
- pass
|
|
|
+ bc = Bitcell()
|
|
|
+ bc.clock = 0.0005 / self.bitrate
|
|
|
+ bc.from_flux(flux)
|
|
|
+ bits = bc.revolution_list[0][0]
|
|
|
+ bits.bytereverse()
|
|
|
+ self.track_list.append((len(bits), bits.tobytes()))
|
|
|
|
|
|
|
|
|
def get_image(self):
|
|
|
- return bytes()
|
|
|
+
|
|
|
+ # Construct the image header.
|
|
|
+ n_cyl = self.start_cyl + len(self.track_list) // self.nr_sides
|
|
|
+ header = struct.pack("<8s4B2H2BH",
|
|
|
+ b"HXCPICFE",
|
|
|
+ 0,
|
|
|
+ n_cyl,
|
|
|
+ self.nr_sides,
|
|
|
+ 0xff, # unknown encoding
|
|
|
+ self.bitrate,
|
|
|
+ 0, # rpm (unused)
|
|
|
+ 0xff, # unknown interface
|
|
|
+ 1, # rsvd
|
|
|
+ 1) # track list offset
|
|
|
+
|
|
|
+ # We dynamically build the Track-LUT and -Data arrays.
|
|
|
+ tlut = bytearray()
|
|
|
+ tdat = bytearray()
|
|
|
+
|
|
|
+ # Dummy data for unused initial cylinders. Assumes 300RPM.
|
|
|
+ for i in range(self.start_cyl):
|
|
|
+ nr_bytes = 100 * self.bitrate
|
|
|
+ tlut += struct.pack("<2H", len(tdat)//512 + 2, nr_bytes)
|
|
|
+ tdat += bytes([0x88] * (nr_bytes+0x1ff & ~0x1ff))
|
|
|
+
|
|
|
+ # Stuff real data into the image.
|
|
|
+ for i in range(0, len(self.track_list), self.nr_sides):
|
|
|
+ bc = [self.track_list[i],
|
|
|
+ self.track_list[i+1] if self.nr_sides > 1 else (0,bytes())]
|
|
|
+ nr_bytes = max(len(t[1]) for t in bc)
|
|
|
+ nr_blocks = (nr_bytes + 0xff) // 0x100
|
|
|
+ tlut += struct.pack("<2H", len(tdat)//512 + 2, 2 * nr_bytes)
|
|
|
+ for b in range(nr_blocks):
|
|
|
+ for t in bc:
|
|
|
+ slice = t[1][b*256:(b+1)*256]
|
|
|
+ tdat += slice + bytes([0x88] * (256 - len(slice)))
|
|
|
+
|
|
|
+ # Pad the header and TLUT to 512-byte blocks.
|
|
|
+ header += bytes([0xff] * (0x200 - len(header)))
|
|
|
+ tlut += bytes([0xff] * (0x200 - len(tlut)))
|
|
|
+
|
|
|
+ return header + tlut + tdat
|
|
|
|
|
|
|
|
|
# Local variables:
|