Эх сурвалжийг харах

python: Clean up usb module some more. Move more stuff into usb.read_track()
Mark some methods private with an underscore.

Keir Fraser 5 жил өмнө
parent
commit
613c125351
2 өөрчлөгдсөн 76 нэмэгдсэн , 61 устгасан
  1. 71 43
      scripts/greaseweazle/usb.py
  2. 5 18
      scripts/gw.py

+ 71 - 43
scripts/greaseweazle/usb.py

@@ -5,8 +5,9 @@
 # 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, collections
+import struct
 from greaseweazle import version
+from greaseweazle.flux import Flux
 
 ## Control-Path command set
 class ControlCmd:
@@ -78,7 +79,7 @@ class Unit:
         self.ser = ser
         self.reset()
         # Copy firmware info to instance variables (see above for definitions).
-        self.send_cmd(struct.pack("3B", Cmd.GetInfo, 3, 0))
+        self._send_cmd(struct.pack("3B", Cmd.GetInfo, 3, 0))
         x = struct.unpack("<4BI24x", self.ser.read(32))
         (self.major, self.minor, self.max_index,
          self.max_cmd, self.sample_freq) = x
@@ -96,7 +97,7 @@ class Unit:
         if self.update_needed:
             return
         # Initialise the delay properties with current firmware values.
-        self.send_cmd(struct.pack("4B", Cmd.GetParams, 4, Params.Delays, 10))
+        self._send_cmd(struct.pack("4B", Cmd.GetParams, 4, Params.Delays, 10))
         (self._select_delay, self._step_delay,
          self._seek_settle_delay, self._motor_delay,
          self._auto_off_delay) = struct.unpack("<5H", self.ser.read(10))
@@ -111,10 +112,10 @@ class Unit:
         self.ser.reset_input_buffer()
 
 
-    ## send_cmd:
+    ## _send_cmd:
     ## Send given command byte sequence to Greaseweazle.
     ## Raise a CmdError if command fails.
-    def send_cmd(self, cmd):
+    def _send_cmd(self, cmd):
         self.ser.write(cmd)
         (c,r) = struct.unpack("2B", self.ser.read(2))
         assert c == cmd[0]
@@ -125,26 +126,26 @@ class Unit:
     ## seek:
     ## Seek the selected drive's heads to the specified track (cyl, side).
     def seek(self, cyl, side):
-        self.send_cmd(struct.pack("3B", Cmd.Seek, 3, cyl))
-        self.send_cmd(struct.pack("3B", Cmd.Side, 3, side))
+        self._send_cmd(struct.pack("3B", Cmd.Seek, 3, cyl))
+        self._send_cmd(struct.pack("3B", Cmd.Side, 3, side))
 
 
     ## drive_select:
     ## Select/deselect the drive.
     def drive_select(self, state):
-        self.send_cmd(struct.pack("3B", Cmd.Select, 3, int(state)))
+        self._send_cmd(struct.pack("3B", Cmd.Select, 3, int(state)))
 
 
     ## drive_motor:
     ## Turn the selected drive's motor on/off.
     def drive_motor(self, state):
-        self.send_cmd(struct.pack("3B", Cmd.Motor, 3, int(state)))
+        self._send_cmd(struct.pack("3B", Cmd.Motor, 3, int(state)))
 
 
-    ## get_index_times:
+    ## _get_index_times:
     ## Get index timing values for the last .read_track() command.
-    def get_index_times(self, nr):
-        self.send_cmd(struct.pack("4B", Cmd.GetIndexTimes, 4, 0, nr))
+    def _get_index_times(self, nr):
+        self._send_cmd(struct.pack("4B", Cmd.GetIndexTimes, 4, 0, nr))
         x = struct.unpack("<%dI" % nr, self.ser.read(4*nr))
         return x
 
@@ -152,30 +153,34 @@ class Unit:
     ## update_firmware:
     ## Update Greaseweazle to the given new firmware.
     def update_firmware(self, dat):
-        self.send_cmd(struct.pack("<2BI", Cmd.Update, 6, len(dat)))
+        self._send_cmd(struct.pack("<2BI", Cmd.Update, 6, len(dat)))
         self.ser.write(dat)
         (ack,) = struct.unpack("B", self.ser.read(1))
         return ack
 
 
-    ## decode_flux:
+    ## _decode_flux:
     ## Decode the Greaseweazle data stream into a list of flux samples.
-    def decode_flux(self, dat):
+    def _decode_flux(self, dat):
         flux = []
-        while dat:
-            i = dat.popleft()
-            if i < 250:
-                flux.append(i)
-            elif i == 255:
-                val =  (dat.popleft() & 254) >>  1
-                val += (dat.popleft() & 254) <<  6
-                val += (dat.popleft() & 254) << 13
-                val += (dat.popleft() & 254) << 20
-                flux.append(val)
-            else:
-                val = (i - 249) * 250
-                val += dat.popleft() - 1
-                flux.append(val)
+        dat_i = iter(dat)
+        try:
+            while True:
+                i = next(dat_i)
+                if i < 250:
+                    flux.append(i)
+                elif i == 255:
+                    val =  (next(dat_i) & 254) >>  1
+                    val += (next(dat_i) & 254) <<  6
+                    val += (next(dat_i) & 254) << 13
+                    val += (next(dat_i) & 254) << 20
+                    flux.append(val)
+                else:
+                    val = (i - 249) * 250
+                    val += next(dat_i) - 1
+                    flux.append(val)
+        except StopIteration:
+            pass
         assert flux[-1] == 0
         return flux[:-1]
 
@@ -205,31 +210,54 @@ class Unit:
 
 
     ## read_track:
-    ## Read flux timings as encoded data stream for the current track.
-    def read_track(self, nr_idx):
-        dat = collections.deque()
-        self.send_cmd(struct.pack("3B", Cmd.ReadFlux, 3, nr_idx))
+    ## Read and decode flux and index timings for the current track.
+    def read_track(self, nr_revs):
+
+        # Request and read all flux timings for this track.
+        dat = bytearray()
+        self._send_cmd(struct.pack("3B", Cmd.ReadFlux, 3, nr_revs+1))
         while True:
             dat += self.ser.read(1)
             dat += self.ser.read(self.ser.in_waiting)
             if dat[-1] == 0:
                 break
+
+        # Check flux status. We bail if there was an error.
         try:
-            self.send_cmd(struct.pack("2B", Cmd.GetFluxStatus, 2))
+            self._send_cmd(struct.pack("2B", Cmd.GetFluxStatus, 2))
         except CmdError as error:
             del dat
-            return error.code, None, None
-        return Ack.Okay, self.get_index_times(nr_idx), dat
+            return error.code, None
+
+        # Decode the flux list and read the index-times list.
+        flux_list = self._decode_flux(dat)
+        index_list = self._get_index_times(nr_revs+1)
+
+        # Clip the initial partial revolution.
+        to_index = index_list[0]
+        for i in range(len(flux_list)):
+            to_index -= flux_list[i]
+            if to_index < 0:
+                flux_list[i] = -to_index
+                flux_list = flux_list[i:]
+                break
+        if to_index >= 0:
+            # We ran out of flux.
+            flux_list = []
+        index_list = index_list[1:]
+
+        # Success: Return the requested full index-to-index revolutions.
+        return Ack.Okay, Flux(index_list, flux_list, self.sample_freq)
 
 
     ## write_track:
     ## Write the given data stream to the current track via Greaseweazle.
     def write_track(self, dat):
-        self.send_cmd(struct.pack("<2BIB", Cmd.WriteFlux, 7, 0, 1))
+        self._send_cmd(struct.pack("<2BIB", Cmd.WriteFlux, 7, 0, 1))
         self.ser.write(dat)
         self.ser.read(1) # Sync with Greaseweazle
         try:
-            self.send_cmd(struct.pack("2B", Cmd.GetFluxStatus, 2))
+            self._send_cmd(struct.pack("2B", Cmd.GetFluxStatus, 2))
         except CmdError as error:
             return error.code
         return Ack.Okay
@@ -246,11 +274,11 @@ class Unit:
     ##
 
     def _set_delays(self):
-        self.send_cmd(struct.pack("<3B5H", Cmd.SetParams,
-                                  3+5*2, Params.Delays,
-                                  self._select_delay, self._step_delay,
-                                  self._seek_settle_delay,
-                                  self._motor_delay, self._auto_off_delay))
+        self._send_cmd(struct.pack("<3B5H", Cmd.SetParams,
+                                   3+5*2, Params.Delays,
+                                   self._select_delay, self._step_delay,
+                                   self._seek_settle_delay,
+                                   self._motor_delay, self._auto_off_delay))
 
     @property
     def select_delay(self):

+ 5 - 18
scripts/gw.py

@@ -13,8 +13,6 @@ import crcmod.predefined
 
 from greaseweazle import version
 from greaseweazle import usb as USB
-from greaseweazle.bitcell import Bitcell
-from greaseweazle.flux import Flux
 from greaseweazle.scp import SCP
 from greaseweazle.hfe import HFE
 
@@ -43,28 +41,16 @@ def read_to_image(usb, args):
 
             # Physically read the track.
             for retry in range(1, 5):
-                ack, index_list, enc_flux = usb.read_track(args.revs+1)
+                ack, flux = usb.read_track(args.revs)
                 if ack == USB.Ack.Okay:
                     break
                 elif ack == USB.Ack.FluxOverflow and retry < 5:
                     print("Retry #%u..." % (retry))
                 else:
                     raise CmdError(ack)
-
-            # Decode the flux and clip the initial partial revolution.
-            flux_list = usb.decode_flux(enc_flux)
-            del enc_flux
-            to_index = index_list[0]
-            for i in range(len(flux_list)):
-                to_index -= flux_list[i]
-                if to_index < 0:
-                    flux_list[i] = -to_index
-                    flux_list = flux_list[i:]
-                    index_list = index_list[1:]
-                    break
                 
             # Stash the data for later writeout to the image file.
-            image.append_track(Flux(index_list, flux_list, usb.sample_freq))
+            image.append_track(flux)
 
     print()
 
@@ -81,12 +67,13 @@ def write_from_image(usb, args):
         # @drive_ticks is the time in Gresaeweazle ticks between index pulses.
         # We will adjust the flux intervals per track to allow for this.
         for retry in range(1, 5):
-            ack, index_list, _ = usb.read_track(3)
+            ack, flux = usb.read_track(2)
             if ack == USB.Ack.Okay:
                 break
             elif ack != USB.Ack.FluxOverflow or retry >= 5:
                 raise CmdError(ack)
-        drive_ticks = (index_list[1] + index_list[2]) / 2
+        drive_ticks = (flux.index_list[0] + flux.index_list[1]) / 2
+        del flux
 
     # Read and parse the image file.
     image_class = get_image_class(args.file)