Bladeren bron

python: Put SCP write code into new module

Keir Fraser 5 jaren geleden
bovenliggende
commit
f8b1707286
2 gewijzigde bestanden met toevoegingen van 148 en 124 verwijderingen
  1. 129 0
      scripts/greaseweazle/scp.py
  2. 19 124
      scripts/gw.py

+ 129 - 0
scripts/greaseweazle/scp.py

@@ -0,0 +1,129 @@
+# greaseweazle/scp.py
+#
+# Written & released by Keir Fraser <keir.xen@gmail.com>
+#
+# 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
+
+class SCP:
+
+    # 40MHz
+    sample_freq = 40000000
+
+    def __init__(self, start_cyl, nr_sides):
+        self.start_cyl = start_cyl
+        self.nr_sides = nr_sides
+        self.nr_revs = None
+        self.track_list = []
+
+    # append_track:
+    # Converts a Flux object into a Supercard Pro Track and appends it to
+    # the current image-in-progress.
+    def append_track(self, flux):
+
+        nr_revs = len(flux.index_list) - 1
+        if not self.nr_revs:
+            self.nr_revs = nr_revs
+        else:
+            assert self.nr_revs == nr_revs
+        
+        factor = SCP.sample_freq / flux.sample_freq
+
+        trknr = self.start_cyl * self.nr_sides + len(self.track_list)
+        tdh = struct.pack("<3sB", b"TRK", trknr)
+        dat = bytearray()
+
+        len_at_index = rev = 0
+        to_index = flux.index_list[0]
+        rem = 0.0
+
+        for x in flux.list:
+
+            # Are we processing initial samples before the first revolution?
+            if rev == 0:
+                if to_index >= x:
+                    # Discard initial samples
+                    to_index -= x
+                    continue
+                # Now starting the first full revolution
+                rev = 1
+                to_index += flux.index_list[rev]
+
+            # Does the next flux interval cross the index mark?
+            while to_index < x:
+                # Append to the TDH for the previous full revolution
+                tdh += struct.pack("<III",
+                                   int(round(flux.index_list[rev]*factor)),
+                                   (len(dat) - len_at_index) // 2,
+                                   4 + nr_revs*12 + len_at_index)
+                # Set up for the next revolution
+                len_at_index = len(dat)
+                rev += 1
+                if rev > nr_revs:
+                    # We're done: We simply discard any surplus flux samples
+                    self.track_list.append((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 = int(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("<III",
+                               int(round(flux.index_list[rev]*factor)),
+                               (len(dat) - len_at_index) // 2,
+                               4 + nr_revs*12 + len_at_index)
+            len_at_index = len(dat)
+            rev += 1
+
+        self.track_list.append((tdh, dat))
+
+
+    def get_image(self):
+        s_trk = self.start_cyl * self.nr_sides
+        e_trk = s_trk + len(self.track_list) - 1
+        # Generate the TLUT and concatenate all the tracks together.
+        trk_offs = bytearray(s_trk * 4)
+        trk_dat = bytearray()
+        for tdh, dat in self.track_list:
+            trk_offs += struct.pack("<I", 0x2b0 + len(trk_dat))
+            trk_dat += tdh + dat
+        trk_offs += bytes(0x2a0 - len(trk_offs))
+        # Calculate checksum over all data (except 16-byte image header).
+        csum = 0
+        for x in trk_offs:
+            csum += x
+        for x in trk_dat:
+            csum += x
+        # Generate the image header.
+        header = struct.pack("<3s9BI",
+                             b"SCP",    # Signature
+                             0,         # Version
+                             0x80,      # DiskType = Other
+                             self.nr_revs, s_trk, e_trk,
+                             0x01,      # Flags = Index
+                             0,         # 16-bit cell width
+                             1 if self.nr_sides == 1 else 0,
+                             0,         # 25ns capture
+                             csum & 0xffffffff)
+        # Concatenate it all together and send it back.
+        return header + trk_offs + trk_dat
+
+
+# Local variables:
+# python-indent: 4
+# End:

+ 19 - 124
scripts/gw.py

@@ -15,135 +15,30 @@ from greaseweazle import version
 from greaseweazle import USB
 from greaseweazle.bitcell import Bitcell
 from greaseweazle.flux import Flux
-
-# 40MHz
-scp_freq = 40000000
-
-# flux_to_scp:
-# Converts Greaseweazle flux samples into a Supercard Pro Track.
-# Returns the Track Data Header (TDH) and the SCP "bitcell" array.
-def flux_to_scp(flux, track, nr_revs):
-
-    factor = scp_freq / flux.sample_freq
-
-    tdh = struct.pack("<3sB", b"TRK", track)
-    dat = bytearray()
-
-    len_at_index = rev = 0
-    to_index = flux.index_list[0]
-    rem = 0.0
-
-    for x in flux.list:
-
-        # Are we processing initial samples before the first revolution?
-        if rev == 0:
-            if to_index >= x:
-                # Discard initial samples
-                to_index -= x
-                continue
-            # Now starting the first full revolution
-            rev = 1
-            to_index += flux.index_list[rev]
-
-        # Does the next flux interval cross the index mark?
-        while to_index < x:
-            # Append to the Track Data Header for the previous full revolution
-            tdh += struct.pack("<III",
-                               int(round(flux.index_list[rev]*factor)),
-                               (len(dat) - len_at_index) // 2,
-                               4 + nr_revs*12 + len_at_index)
-            # Set up for the next revolution
-            len_at_index = len(dat)
-            rev += 1
-            if rev > nr_revs:
-                # We're done: We simply discard any surplus flux samples
-                return tdh, dat
-            to_index += flux.index_list[rev]
-
-        # Process the current flux sample into SCP "bitcell" format
-        to_index -= x
-        y = x * factor + rem
-        val = int(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("<III",
-                           int(round(flux.index_list[rev]*factor)),
-                           (len(dat) - len_at_index) // 2,
-                           4 + nr_revs*12 + len_at_index)
-        len_at_index = len(dat)
-        rev += 1
-
-    return tdh, dat
-
+from greaseweazle.scp import SCP
 
 # read_to_scp:
 # Reads a floppy disk and dumps it into a new Supercard Pro image file.
 def read_to_scp(usb, args):
-    trk_dat = bytearray()
-    trk_offs = []
-    if args.single_sided:
-        track_range = range(args.scyl, args.ecyl+1)
-        nr_sides = 1
-    else:
-        track_range = range(args.scyl*2, (args.ecyl+1)*2)
-        nr_sides = 2
-    for track in track_range:
-        cyl = track >> (nr_sides - 1)
-        side = track & (nr_sides - 1)
-        print("\rReading Track %u.%u..." % (cyl, side), end="")
-        trk_offs.append(len(trk_dat))
-        usb.seek(cyl, side)
-        for retry in range(1, 5):
-            ack, index_list, enc_flux = usb.read_track(args.revs+1)
-            if ack == USB.Ack.Okay:
-                break
-            elif ack == USB.Ack.FluxOverflow and retry < 5:
-                print("Retry #%u..." % (retry))
-            else:
-                raise CmdError(ack)
-        flux = Flux(index_list, usb.decode_flux(enc_flux), usb.sample_freq)
-        tdh, dat = flux_to_scp(flux, track, args.revs)
-        trk_dat += tdh
-        trk_dat += dat
+    nr_sides = 1 if args.single_sided else 2
+    scp = SCP(args.scyl, nr_sides)
+    for cyl in range(args.scyl, args.ecyl+1):
+        for side in range(0, nr_sides):
+            print("\rReading Track %u.%u..." % (cyl, side), end="")
+            usb.seek(cyl, side)
+            for retry in range(1, 5):
+                ack, index_list, enc_flux = usb.read_track(args.revs+1)
+                if ack == USB.Ack.Okay:
+                    break
+                elif ack == USB.Ack.FluxOverflow and retry < 5:
+                    print("Retry #%u..." % (retry))
+                else:
+                    raise CmdError(ack)
+            flux = Flux(index_list, usb.decode_flux(enc_flux), usb.sample_freq)
+            scp.append_track(flux)
     print()
-    csum = 0
-    for x in trk_dat:
-        csum += x
-    trk_offs_dat = bytearray()
-    for x in trk_offs:
-        trk_offs_dat += struct.pack("<I", 0x2b0 + x)
-    trk_offs_dat += bytes(0x2a0 - len(trk_offs_dat))
-    for x in trk_offs_dat:
-        csum += x
-    ds_flag = 0
-    if args.single_sided:
-        ds_flag = 1
-    header_dat = struct.pack("<3s9BI",
-                             b"SCP",    # Signature
-                             0,         # Version
-                             0x80,      # DiskType = Other
-                             args.revs, # Nr Revolutions
-                             track_range.start, # Start track
-                             track_range.stop-1, # End track
-                             0x01,      # Flags = Index
-                             0,         # 16-bit cell width
-                             ds_flag,   # Double Sided
-                             0,         # 25ns capture
-                             csum & 0xffffffff)
     with open(args.file, "wb") as f:
-        f.write(header_dat)
-        f.write(trk_offs_dat)
-        f.write(trk_dat)
+        f.write(scp.get_image())
 
 
 # write_from_scp:
@@ -162,7 +57,7 @@ def write_from_scp(usb, args):
         drive_ticks = (index_list[1] + index_list[2]) / 2
     else:
         # Simple ratio between the Greaseweazle and SCP sample frequencies.
-        factor = usb.sample_freq / scp_freq
+        factor = usb.sample_freq / SCP.sample_freq
 
     # Parse the SCP image header.
     with open(args.file, "rb") as f: