Bläddra i källkod

python: Put SCP read code into the new module too.

Keir Fraser 5 år sedan
förälder
incheckning
234ae62a66
2 ändrade filer med 112 tillägg och 57 borttagningar
  1. 73 0
      scripts/greaseweazle/scp.py
  2. 39 57
      scripts/gw.py

+ 73 - 0
scripts/greaseweazle/scp.py

@@ -7,6 +7,8 @@
 
 import struct
 
+from greaseweazle.flux import Flux
+
 class SCP:
 
     # 40MHz
@@ -18,6 +20,77 @@ class SCP:
         self.nr_revs = None
         self.track_list = []
 
+
+    @classmethod
+    def from_file(cls, dat):
+
+        header = struct.unpack("<3s9BI", dat[0:16])
+        (sig, _, _, nr_revs, s_trk, e_trk, flags, _, ss, _, _) = header
+        assert sig == b"SCP"
+        nr_sides = 1 if ss else 2
+        
+        trk_offs = struct.unpack("<168I", dat[16:0x2b0])
+
+        scp = cls(s_trk // nr_sides, nr_sides)
+        scp.nr_revs = nr_revs
+
+        for trknr in range(s_trk, e_trk+1):
+            trk_off = trk_offs[trknr]
+            if trk_off == 0:
+                scp.track_list.append((None, None))
+
+            # Parse the SCP track header and extract the flux data.
+            thdr = dat[trk_off:trk_off+4+12*nr_revs]
+            sig, tnr, _, _, s_off = struct.unpack("<3sB3I", thdr[:16])
+            assert sig == b"TRK"
+            assert tnr == trknr
+            _, e_nr, e_off = struct.unpack("<3I", thdr[-12:])
+            tdat = dat[trk_off+s_off:trk_off+e_off+e_nr*2]
+
+            scp.track_list.append((thdr, tdat))
+
+        return scp
+
+
+    def get_track(self, cyl, side, writeout=False):
+        if side >= self.nr_sides:
+            return None
+        if cyl < self.start_cyl:
+            return None
+        off = (cyl - self.start_cyl) * self.nr_sides + side
+        if off >= len(self.track_list):
+            return None
+        tdh, dat = self.track_list[off]
+        if not dat:
+            return None
+        tdh = tdh[4:]
+
+        # Writeout requires only a single revolution
+        if writeout:
+            tdh = tdh[:12]
+            _, nr, _ = struct.unpack("<3I", tdh)
+            dat = dat[:nr*2]
+        
+        index_list = []
+        while tdh:
+            ticks, _, _ = struct.unpack("<3I", tdh[:12])
+            index_list.append(ticks)
+            tdh = tdh[12:]
+        
+        # Decode the SCP flux data into a simple list of flux times.
+        flux_list = []
+        val = 0
+        for i in range(0, len(dat), 2):
+            x = dat[i]*256 + dat[i+1]
+            if x == 0:
+                val += 65536
+                continue
+            flux_list.append(val + x)
+            val = 0
+
+        return Flux(index_list, flux_list, SCP.sample_freq)
+    
+        
     # append_track:
     # Converts a Flux object into a Supercard Pro Track and appends it to
     # the current image-in-progress.

+ 39 - 57
scripts/gw.py

@@ -20,10 +20,9 @@ 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):
-    nr_sides = 1 if args.single_sided else 2
-    scp = SCP(args.scyl, nr_sides)
+    scp = SCP(args.scyl, args.nr_sides)
     for cyl in range(args.scyl, args.ecyl+1):
-        for side in range(0, nr_sides):
+        for side in range(0, args.nr_sides):
             print("\rReading Track %u.%u..." % (cyl, side), end="")
             usb.seek(cyl, side)
             for retry in range(1, 5):
@@ -55,66 +54,48 @@ def write_from_scp(usb, args):
             elif ack != USB.Ack.FluxOverflow or retry >= 5:
                 raise CmdError(ack)
         drive_ticks = (index_list[1] + index_list[2]) / 2
-    else:
-        # Simple ratio between the Greaseweazle and SCP sample frequencies.
-        factor = usb.sample_freq / SCP.sample_freq
 
     # Parse the SCP image header.
     with open(args.file, "rb") as f:
-        dat = f.read()
-    header = struct.unpack("<3s9BI", dat[0:16])
-    assert header[0] == b"SCP"
-    trk_offs = struct.unpack("<168I", dat[16:0x2b0])
-
-    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("\rWriting Track %u.%u..." % (cyl, side), end="")
-        trk_off = trk_offs[track]
-        if trk_off == 0:
-            continue
-        usb.seek(cyl, side)
-
-        # Parse the SCP track header and extract the flux data.
-        thdr = struct.unpack("<3sBIII", dat[trk_off:trk_off+16])
-        sig, _, track_ticks, samples, off = thdr
-        assert sig == b"TRK"
-        tdat = dat[trk_off+off:trk_off+off+samples*2]
-
-        # Decode the SCP flux data into a simple list of flux times.
-        flux = []
-        rem = 0.0
-        if args.adjust_speed:
-            # @factor adjusts flux times for speed variations between the
-            # read-in and write-out drives.
-            factor = drive_ticks / track_ticks
-        for i in range(0, len(tdat), 2):
-            x = tdat[i]*256 + tdat[i+1]
-            if x == 0:
-                rem += 65536.0
+        scp = SCP.from_file(f.read())
+
+    for cyl in range(args.scyl, args.ecyl+1):
+        for side in range(0, args.nr_sides):
+
+            flux = scp.get_track(cyl, side, writeout=True)
+            if not flux:
                 continue
-            y = x * factor + rem
-            val = int(round(y))
-            rem = y - val
-            flux.append(val)
 
-        # Encode the flux times for Greaseweazle, and write them out.
-        enc_flux = usb.encode_flux(flux)
-        for retry in range(1, 5):
-            ack = usb.write_track(enc_flux)
-            if ack == USB.Ack.Okay:
-                break
-            elif ack == USB.Ack.FluxUnderflow and retry < 5:
-                print("Retry #%u..." % (retry))
+            print("\rWriting Track %u.%u..." % (cyl, side), end="")
+            usb.seek(cyl, side)
+
+            if args.adjust_speed:
+                # @factor adjusts flux times for speed variations between the
+                # read-in and write-out drives.
+                factor = drive_ticks / flux.index_list[0]
             else:
-                raise CmdError(ack)
+                # Simple ratio between the GW and SCP sample frequencies.
+                factor = usb.sample_freq / flux.sample_freq
+
+            # Convert the flux samples to Greaseweazle sample frequency.
+            rem = 0.0
+            flux_list = []
+            for x in flux.list:
+                y = x * factor + rem
+                val = int(round(y))
+                rem = y - val
+                flux_list.append(val)
+
+            # Encode the flux times for Greaseweazle, and write them out.
+            enc_flux = usb.encode_flux(flux_list)
+            for retry in range(1, 5):
+                ack = usb.write_track(enc_flux)
+                if ack == USB.Ack.Okay:
+                    break
+                elif ack == USB.Ack.FluxUnderflow and retry < 5:
+                    print("Retry #%u..." % (retry))
+                else:
+                    raise CmdError(ack)
 
     print()
 
@@ -187,6 +168,7 @@ def _main(argv):
     parser.add_argument("file", help="in/out filename")
     parser.add_argument("device", help="serial device")
     args = parser.parse_args(argv[1:])
+    args.nr_sides = 1 if args.single_sided else 2
 
     if not args.action in actions:
         print("** Action \"%s\" is not recognised" % args.action)