# greaseweazle/image/scp.py # # Written & released by Keir Fraser # # This is free and unencumbered software released into the public domain. # See the file COPYING for more details, or visit . import struct, functools from greaseweazle import error from greaseweazle.flux import Flux from .image import Image class SCPOpts: """legacy_ss: Set to True to generate (incorrect) legacy single-sided SCP image. """ def __init__(self): self.legacy_ss = False class SCP(Image): # 40MHz sample_freq = 40000000 def __init__(self): self.opts = SCPOpts() self.nr_revs = None self.to_track = dict() def side_count(self): s = [0,0] # non-empty tracks on each side for tnr in self.to_track: s[tnr&1] += 1 return s @classmethod def from_file(cls, name): with open(name, "rb") as f: dat = f.read() header = struct.unpack("<3s9BI", dat[0:16]) (sig, _, _, nr_revs, _, _, flags, _, single_sided, _, _) = header error.check(sig == b"SCP", "SCP: Bad signature") index_cued = flags & 1 or nr_revs == 1 if not index_cued: nr_revs -= 1 # Some tools generate a short TLUT. We handle this by truncating the # TLUT at the first Track Data Header. trk_offs = struct.unpack("<168I", dat[16:0x2b0]) for i in range(168): try: off = trk_offs[i] except IndexError: break if off == 0 or off >= 0x2b0: continue off = off//4 - 4 error.check(off >= 0, "SCP: Bad Track Table") trk_offs = trk_offs[:off] scp = cls() scp.nr_revs = nr_revs for trknr in range(len(trk_offs)): trk_off = trk_offs[trknr] if trk_off == 0: continue # Parse the SCP track header and extract the flux data. thdr = dat[trk_off:trk_off+4+12*nr_revs] sig, tnr = struct.unpack("<3sB", thdr[:4]) error.check(sig == b"TRK", "SCP: Missing track signature") error.check(tnr == trknr, "SCP: Wrong track number in header") _off = 12 if index_cued else 24 # skip first partial rev s_off, = struct.unpack("= nr_revs: # We're done: We simply discard any surplus flux samples self.to_track[cyl*2+side] = (tdh, dat) return to_index += flux.index_list[rev] # Process the current flux sample into SCP "bitcell" format to_index -= x y = x * factor + rem val = round(y) if (val & 65535) == 0: val += 1 rem = y - val while val >= 65536: dat.append(0) dat.append(0) val -= 65536 dat.append(val>>8) dat.append(val&255) # Header for last track(s) in case we ran out of flux timings. while rev < nr_revs: tdh += struct.pack("