Sfoglia il codice sorgente

python: 4-space indentation

Keir Fraser 5 anni fa
parent
commit
4f22b8099d
3 ha cambiato i file con 536 aggiunte e 525 eliminazioni
  1. 267 264
      scripts/greaseweazle/USB.py
  2. 263 259
      scripts/gw.py
  3. 6 2
      scripts/mk_update.py

+ 267 - 264
scripts/greaseweazle/USB.py

@@ -10,285 +10,288 @@ from . import version
 
 ## Control-Path command set
 class ControlCmd:
-  ClearComms      = 10000
-  Normal          =  9600
+    ClearComms      = 10000
+    Normal          =  9600
+
 
-  
 ## Command set
 class Cmd:
-  GetInfo         =  0
-  Seek            =  1
-  Side            =  2
-  SetParams       =  3
-  GetParams       =  4
-  Motor           =  5
-  ReadFlux        =  6
-  WriteFlux       =  7
-  GetFluxStatus   =  8
-  GetIndexTimes   =  9
-  Select          = 10
-  # Bootloader specific:
-  Update          =  1
-
-  
+    GetInfo         =  0
+    Seek            =  1
+    Side            =  2
+    SetParams       =  3
+    GetParams       =  4
+    Motor           =  5
+    ReadFlux        =  6
+    WriteFlux       =  7
+    GetFluxStatus   =  8
+    GetIndexTimes   =  9
+    Select          = 10
+    # Bootloader specific:
+    Update          =  1
+
+
 ## Command responses/acknowledgements
 class Ack:
-  Okay            = 0
-  BadCommand      = 1
-  NoIndex         = 2
-  NoTrk0          = 3
-  FluxOverflow    = 4
-  FluxUnderflow   = 5
-  Wrprot          = 6
-  Max             = 6
-
-  
+    Okay            = 0
+    BadCommand      = 1
+    NoIndex         = 2
+    NoTrk0          = 3
+    FluxOverflow    = 4
+    FluxUnderflow   = 5
+    Wrprot          = 6
+    Max             = 6
+
+
 ## Cmd.{Get,Set}Params indexes
 class Params:
-  Delays          = 0
+    Delays          = 0
 
 
 ## CmdError: Encapsulates a command acknowledgement.
 class CmdError(Exception):
 
-  str = [ "Okay", "Bad Command", "No Index (No disk?)", "Track 0 not found",
-          "Flux Overflow", "Flux Underflow", "Disk is Write Protected" ]
+    str = [ "Okay", "Bad Command", "No Index (No disk?)", "Track 0 not found",
+            "Flux Overflow", "Flux Underflow", "Disk is Write Protected" ]
 
-  def __init__(self, cmd, code):
-    self.cmd = cmd
-    self.code = code
+    def __init__(self, cmd, code):
+        self.cmd = cmd
+        self.code = code
 
-  def __str__(self):
-    if self.code <= Ack.Max:
-      return self.str[self.code]
-    return "Unknown Error (%u)" % self.code
+    def __str__(self):
+        if self.code <= Ack.Max:
+            return self.str[self.code]
+        return "Unknown Error (%u)" % self.code
 
 
 class Unit:
 
-  ## Unit information, instance variables:
-  ##  major, minor: Greaseweazle firmware version number
-  ##  max_index:    Maximum index timings for Cmd.ReadFlux
-  ##  max_cmd:      Maximum Cmd number accepted by this unit
-  ##  sample_freq:  Resolution of all time values passed to/from this unit
-
-  ## Unit(ser):
-  ## Accepts a Pyserial instance for Greaseweazle communications.
-  def __init__(self, ser):
-    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))
-    x = struct.unpack("<4BI24x", self.ser.read(32))
-    (self.major, self.minor, self.max_index,
-     self.max_cmd, self.sample_freq) = x
-    # Check whether firmware is in update mode: limited command set if so.
-    self.update_mode = (self.max_index == 0)
-    if self.update_mode:
-      self.update_jumpered = (self.sample_freq & 1)
-      del self.max_index
-      del self.sample_freq
-      return
-    # We are running main firmware: Check whether an update is needed.
-    # We can use only the GetInfo command if the firmware is out of date.
-    self.update_needed = (version.major != self.major
-                          or version.minor != self.minor)
-    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._select_delay, self._step_delay,
-    self._seek_settle_delay, self._motor_delay,
-       self._auto_off_delay) = struct.unpack("<5H", self.ser.read(10))
-    
-
-  ## reset:
-  ## Resets communications with Greaseweazle.
-  def reset(self):
-    self.ser.reset_output_buffer()
-    self.ser.baudrate = ControlCmd.ClearComms
-    self.ser.baudrate = ControlCmd.Normal
-    self.ser.reset_input_buffer()
-
-
-  ## send_cmd:
-  ## Send given command byte sequence to Greaseweazle.
-  ## Raise a CmdError if command fails.
-  def send_cmd(self, cmd):
-    self.ser.write(cmd)
-    (c,r) = struct.unpack("2B", self.ser.read(2))
-    assert c == cmd[0]
-    if r != 0:
-      raise CmdError(c,r)
-
-
-  ## seek:
-  ## Seek currently-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))
-
-
-  ## drive_select:
-  ## Select/deselect the drive.
-  def drive_select(self, 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)))
-
-
-  ## 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))
-    x = struct.unpack("<%dI" % nr, self.ser.read(4*nr))
-    return x
-
-
-  ## 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.ser.write(dat)
-    (ack,) = struct.unpack("B", self.ser.read(1))
-    return ack
-
-  
-  ## decode_flux:
-  ## Decode the Greaseweazle data stream into a list of flux samples.
-  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)
-    assert flux[-1] == 0
-    return flux[:-1]
-
-
-  ## encode_flux:
-  ## Convert the given flux timings into an encoded data stream.
-  def encode_flux(self, flux):
-    dat = bytearray()
-    for val in flux:
-      if val == 0:
-        pass
-      elif val < 250:
-        dat.append(val)
-      else:
-        high = val // 250
-        if high <= 5:
-          dat.append(249+high)
-          dat.append(1 + val%250)
-        else:
-          dat.append(255)
-          dat.append(1 | (val<<1) & 255)
-          dat.append(1 | (val>>6) & 255)
-          dat.append(1 | (val>>13) & 255)
-          dat.append(1 | (val>>20) & 255)
-    dat.append(0) # End of Stream
-    return dat
-
-  
-  ## 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))
-    while True:
-      dat += self.ser.read(1)
-      dat += self.ser.read(self.ser.in_waiting)
-      if dat[-1] == 0:
-        break
-    try:
-      self.send_cmd(struct.pack("2B", Cmd.GetFluxStatus, 2))
-    except CmdError as error:
-      del dat
-      return (error.code, None)
-    return (Ack.Okay, dat)
-    
-
-  ## 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.ser.write(dat)
-    self.ser.read(1) # Sync with Greaseweazle
-    try:
-      self.send_cmd(struct.pack("2B", Cmd.GetFluxStatus, 2))
-    except CmdError as error:
-      return error.code
-    return Ack.Okay
-
-  
-  ##
-  ## Delay-property public getters and setters:
-  ##  select_delay:      Delay (usec) after asserting drive select
-  ##  step_delay:        Delay (usec) after issuing a head-step command
-  ##  seek_settle_delay: Delay (msec) after completing a head-seek operation
-  ##  motor_delay:       Delay (msec) after turning on drive spindle motor
-  ##  auto_off_delay:    Timeout (msec) since last command upon which all
-  ##                     drives are deselected and spindle motors turned off
-  ##
-
-  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))
-
-  @property
-  def select_delay(self):
-    return self._select_delay
-  @select_delay.setter
-  def select_delay(self, select_delay):
-    self._select_delay = select_delay
-    self._set_delays()
-    
-  @property
-  def step_delay(self):
-    return self._step_delay
-  @step_delay.setter
-  def step_delay(self, step_delay):
-    self._step_delay = step_delay
-    self._set_delays()
-    
-  @property
-  def seek_settle_delay(self):
-    return self._seek_settle_delay
-  @seek_settle_delay.setter
-  def seek_settle_delay(self, seek_settle_delay):
-    self._seek_settle_delay = seek_settle_delay
-    self._set_delays()
-    
-  @property
-  def motor_delay(self):
-    return self._motor_delay
-  @motor_delay.setter
-  def motor_delay(self, motor_delay):
-    self._motor_delay = motor_delay
-    self._set_delays()
-    
-  @property
-  def auto_off_delay(self):
-    return self._auto_off_delay
-  @auto_off_delay.setter
-  def auto_off_delay(self, auto_off_delay):
-    self._auto_off_delay = auto_off_delay
-    self._set_delays()
-    
+    ## Unit information, instance variables:
+    ##  major, minor: Greaseweazle firmware version number
+    ##  max_index:    Maximum index timings for Cmd.ReadFlux
+    ##  max_cmd:      Maximum Cmd number accepted by this unit
+    ##  sample_freq:  Resolution of all time values passed to/from this unit
+
+    ## Unit(ser):
+    ## Accepts a Pyserial instance for Greaseweazle communications.
+    def __init__(self, ser):
+        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))
+        x = struct.unpack("<4BI24x", self.ser.read(32))
+        (self.major, self.minor, self.max_index,
+         self.max_cmd, self.sample_freq) = x
+        # Check whether firmware is in update mode: limited command set if so.
+        self.update_mode = (self.max_index == 0)
+        if self.update_mode:
+            self.update_jumpered = (self.sample_freq & 1)
+            del self.max_index
+            del self.sample_freq
+            return
+        # We are running main firmware: Check whether an update is needed.
+        # We can use only the GetInfo command if the firmware is out of date.
+        self.update_needed = (version.major != self.major
+                              or version.minor != self.minor)
+        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._select_delay, self._step_delay,
+        self._seek_settle_delay, self._motor_delay,
+           self._auto_off_delay) = struct.unpack("<5H", self.ser.read(10))
+
+
+    ## reset:
+    ## Resets communications with Greaseweazle.
+    def reset(self):
+        self.ser.reset_output_buffer()
+        self.ser.baudrate = ControlCmd.ClearComms
+        self.ser.baudrate = ControlCmd.Normal
+        self.ser.reset_input_buffer()
+
+
+    ## send_cmd:
+    ## Send given command byte sequence to Greaseweazle.
+    ## Raise a CmdError if command fails.
+    def send_cmd(self, cmd):
+        self.ser.write(cmd)
+        (c,r) = struct.unpack("2B", self.ser.read(2))
+        assert c == cmd[0]
+        if r != 0:
+            raise CmdError(c,r)
+
+
+    ## 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))
+
+
+    ## drive_select:
+    ## Select/deselect the drive.
+    def drive_select(self, 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)))
+
+
+    ## 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))
+        x = struct.unpack("<%dI" % nr, self.ser.read(4*nr))
+        return x
+
+
+    ## 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.ser.write(dat)
+        (ack,) = struct.unpack("B", self.ser.read(1))
+        return ack
+
+
+    ## decode_flux:
+    ## Decode the Greaseweazle data stream into a list of flux samples.
+    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)
+        assert flux[-1] == 0
+        return flux[:-1]
+
+
+    ## encode_flux:
+    ## Convert the given flux timings into an encoded data stream.
+    def encode_flux(self, flux):
+        dat = bytearray()
+        for val in flux:
+            if val == 0:
+                pass
+            elif val < 250:
+                dat.append(val)
+            else:
+                high = val // 250
+                if high <= 5:
+                    dat.append(249+high)
+                    dat.append(1 + val%250)
+                else:
+                    dat.append(255)
+                    dat.append(1 | (val<<1) & 255)
+                    dat.append(1 | (val>>6) & 255)
+                    dat.append(1 | (val>>13) & 255)
+                    dat.append(1 | (val>>20) & 255)
+        dat.append(0) # End of Stream
+        return dat
+
+
+    ## 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))
+        while True:
+            dat += self.ser.read(1)
+            dat += self.ser.read(self.ser.in_waiting)
+            if dat[-1] == 0:
+                break
+        try:
+            self.send_cmd(struct.pack("2B", Cmd.GetFluxStatus, 2))
+        except CmdError as error:
+            del dat
+            return (error.code, None)
+        return (Ack.Okay, dat)
+
+
+    ## 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.ser.write(dat)
+        self.ser.read(1) # Sync with Greaseweazle
+        try:
+            self.send_cmd(struct.pack("2B", Cmd.GetFluxStatus, 2))
+        except CmdError as error:
+            return error.code
+        return Ack.Okay
+
+
+    ##
+    ## Delay-property public getters and setters:
+    ##  select_delay:      Delay (usec) after asserting drive select
+    ##  step_delay:        Delay (usec) after issuing a head-step command
+    ##  seek_settle_delay: Delay (msec) after completing a head-seek operation
+    ##  motor_delay:       Delay (msec) after turning on drive spindle motor
+    ##  auto_off_delay:    Timeout (msec) since last command upon which all
+    ##                     drives are deselected and spindle motors turned off
+    ##
+
+    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))
+
+    @property
+    def select_delay(self):
+        return self._select_delay
+    @select_delay.setter
+    def select_delay(self, select_delay):
+        self._select_delay = select_delay
+        self._set_delays()
+
+    @property
+    def step_delay(self):
+        return self._step_delay
+    @step_delay.setter
+    def step_delay(self, step_delay):
+        self._step_delay = step_delay
+        self._set_delays()
+
+    @property
+    def seek_settle_delay(self):
+        return self._seek_settle_delay
+    @seek_settle_delay.setter
+    def seek_settle_delay(self, seek_settle_delay):
+        self._seek_settle_delay = seek_settle_delay
+        self._set_delays()
+
+    @property
+    def motor_delay(self):
+        return self._motor_delay
+    @motor_delay.setter
+    def motor_delay(self, motor_delay):
+        self._motor_delay = motor_delay
+        self._set_delays()
+
+    @property
+    def auto_off_delay(self):
+        return self._auto_off_delay
+    @auto_off_delay.setter
+    def auto_off_delay(self, auto_off_delay):
+        self._auto_off_delay = auto_off_delay
+        self._set_delays()
+
+# Local variables:
+# python-indent: 4
+# End:

+ 263 - 259
scripts/gw.py

@@ -21,294 +21,298 @@ scp_freq = 40000000
 # Returns the Track Data Header (TDH) and the SCP "bitcell" array.
 def flux_to_scp(flux, track, nr_revs):
 
-  factor = scp_freq / usb.sample_freq
+    factor = scp_freq / usb.sample_freq
 
-  index_times = usb.get_index_times(nr_revs+1)
-  tdh = struct.pack("<3sB", b"TRK", track)
-  dat = bytearray()
+    index_times = usb.get_index_times(nr_revs+1)
+    tdh = struct.pack("<3sB", b"TRK", track)
+    dat = bytearray()
 
-  len_at_index = rev = 0
-  to_index = index_times[0]
-  rem = 0.0
-
-  for x in flux:
+    len_at_index = rev = 0
+    to_index = index_times[0]
+    rem = 0.0
 
-    # Are we processing initial samples before the first revolution?
-    if rev == 0:
-      if to_index >= x:
-        # Discard initial samples
+    for x in flux:
+
+        # 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 += index_times[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(index_times[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 += index_times[rev]
+
+        # Process the current flux sample into SCP "bitcell" format
         to_index -= x
-        continue
-      # Now starting the first full revolution
-      rev = 1
-      to_index += index_times[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(index_times[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 += index_times[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(index_times[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)
+        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(index_times[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)
 
 
 # read_to_scp:
 # Reads a floppy disk and dumps it into a new Supercard Pro image file.
 def read_to_scp(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, 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 = usb.decode_flux(enc_flux)
-    (tdh, dat) = flux_to_scp(flux, track, args.revs)
-    trk_dat += tdh
-    trk_dat += dat
-  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)
+    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, 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 = usb.decode_flux(enc_flux)
+        (tdh, dat) = flux_to_scp(flux, track, args.revs)
+        trk_dat += tdh
+        trk_dat += dat
+    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)
 
 
 # write_from_scp:
 # Writes the specified Supercard Pro image file to floppy disk.
 def write_from_scp(args):
-  factor = usb.sample_freq / scp_freq
-  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 i in track_range:
-    cyl = i >> (nr_sides - 1)
-    side = i & (nr_sides - 1)
-    print("\rWriting Track %u.%u..." % (cyl, side), end="")
-    if trk_offs[i] == 0:
-      continue
-    usb.seek(cyl, side)
-    thdr = struct.unpack("<3sBIII", dat[trk_offs[i]:trk_offs[i]+16])
-    (sig,_,_,samples,off) = thdr
-    assert sig == b"TRK"
-    tdat = dat[trk_offs[i]+off:trk_offs[i]+off+samples*2]
-    flux = []
-    rem = 0.0
-    for i in range(0,len(tdat),2):
-      x = tdat[i]*256 + tdat[i+1]
-      if x == 0:
-        rem += 65536.0
-        continue
-      y = x * factor + rem
-      val = int(round(y))
-      rem = y - val
-      flux.append(val)
-    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))
-      else:
-        raise CmdError(ack)
-  print()
+    factor = usb.sample_freq / scp_freq
+    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 i in track_range:
+        cyl = i >> (nr_sides - 1)
+        side = i & (nr_sides - 1)
+        print("\rWriting Track %u.%u..." % (cyl, side), end="")
+        if trk_offs[i] == 0:
+            continue
+        usb.seek(cyl, side)
+        thdr = struct.unpack("<3sBIII", dat[trk_offs[i]:trk_offs[i]+16])
+        (sig,_,_,samples,off) = thdr
+        assert sig == b"TRK"
+        tdat = dat[trk_offs[i]+off:trk_offs[i]+off+samples*2]
+        flux = []
+        rem = 0.0
+        for i in range(0,len(tdat),2):
+            x = tdat[i]*256 + tdat[i+1]
+            if x == 0:
+                rem += 65536.0
+                continue
+            y = x * factor + rem
+            val = int(round(y))
+            rem = y - val
+            flux.append(val)
+        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))
+            else:
+                raise CmdError(ack)
+    print()
 
 
 # update_firmware:
 # Updates the Greaseweazle firmware using the specified Update File.
 def update_firmware(args):
 
-  # Check that an update operation was actually requested.
-  if args.action != "update":
-    print("Greaseweazle is in Firmware Update Mode:")
-    print(" The only available action is \"update <update_file>\"")
-    if usb.update_jumpered:
-      print(" Remove the Update Jumper for normal operation")
-    else:
-      print(" Main firmware is erased: You *must* perform an update!")
-    return
-
-  # Check that the firmware is actually in update mode.
-  if not usb.update_mode:
-    print("Greaseweazle is in Normal Mode:")
-    print(" To \"update\" you must install the Update Jumper")
-    return
-
-  # Read and check the update file.
-  with open(args.file, "rb") as f:
-    dat = f.read()
-  (sig, maj, min, pad1, pad2, crc) = struct.unpack(">2s4BH", dat[-8:])
-  if len(dat) & 3 != 0 or sig != b'GW' or pad1 != 0 or pad2 != 0:
-    print("%s: Bad update file" % (args.file))
-    return
-  crc16 = crcmod.predefined.Crc('crc-ccitt-false')
-  crc16.update(dat)
-  if crc16.crcValue != 0:
-    print("%s: Bad CRC" % (args.file))
-
-  # Perform the update.
-  print("Updating to v%u.%u..." % (maj, min))
-  ack = usb.update_firmware(dat)
-  if ack != 0:
-    print("** UPDATE FAILED: Please retry!")
-    return
-  print("Done.")
-  print("** Disconnect Greaseweazle and remove the Programming Jumper.")
+    # Check that an update operation was actually requested.
+    if args.action != "update":
+        print("Greaseweazle is in Firmware Update Mode:")
+        print(" The only available action is \"update <update_file>\"")
+        if usb.update_jumpered:
+            print(" Remove the Update Jumper for normal operation")
+        else:
+            print(" Main firmware is erased: You *must* perform an update!")
+        return
+
+    # Check that the firmware is actually in update mode.
+    if not usb.update_mode:
+        print("Greaseweazle is in Normal Mode:")
+        print(" To \"update\" you must install the Update Jumper")
+        return
+
+    # Read and check the update file.
+    with open(args.file, "rb") as f:
+        dat = f.read()
+    (sig, maj, min, pad1, pad2, crc) = struct.unpack(">2s4BH", dat[-8:])
+    if len(dat) & 3 != 0 or sig != b'GW' or pad1 != 0 or pad2 != 0:
+        print("%s: Bad update file" % (args.file))
+        return
+    crc16 = crcmod.predefined.Crc('crc-ccitt-false')
+    crc16.update(dat)
+    if crc16.crcValue != 0:
+        print("%s: Bad CRC" % (args.file))
+
+    # Perform the update.
+    print("Updating to v%u.%u..." % (maj, min))
+    ack = usb.update_firmware(dat)
+    if ack != 0:
+        print("** UPDATE FAILED: Please retry!")
+        return
+    print("Done.")
+    print("** Disconnect Greaseweazle and remove the Programming Jumper.")
 
 
 # _main:
 # Argument processing and dispatch.
 def _main(argv):
 
-  actions = {
-    "read" : read_to_scp,
-    "write" : write_from_scp,
-    "update" : update_firmware
-  }
-  
-  parser = argparse.ArgumentParser(
-    formatter_class=argparse.ArgumentDefaultsHelpFormatter)
-  parser.add_argument("action")
-  parser.add_argument("--revs", type=int, default=3,
-                      help="number of revolutions to read per track")
-  parser.add_argument("--scyl", type=int, default=0,
-                      help="first cylinder to read/write")
-  parser.add_argument("--ecyl", type=int, default=81,
-                      help="last cylinder to read/write")
-  parser.add_argument("--single-sided", action="store_true")
-  parser.add_argument("file", help="in/out filename")
-  parser.add_argument("device", help="serial device")
-  args = parser.parse_args(argv[1:])
-
-  if not args.action in actions:
-    print("** Action \"%s\" is not recognised" % args.action)
-    print("Valid actions: ", end="")
-    print(", ".join(str(key) for key in actions.keys()))
-    return
-  
-  global usb
-  usb = USB.Unit(serial.Serial(args.device))
-
-  print("** %s v%u.%u, Host Tools v%u.%u"
-        % (("Greaseweazle","Bootloader")[usb.update_mode],
-           usb.major, usb.minor,
-           version.major, version.minor))
-
-  if args.action == "update" or usb.update_mode:
-    return actions[args.action](args)
-  
-  elif usb.update_needed:
-    print("Firmware is out of date: Require v%u.%u"
-          % (version.major, version.minor))
-    print("Install the Update Jumper and \"update <update_file>\"")
-    return
-  
-  #usb.step_delay = 5000
-  #print("Select Delay: %uus" % usb.select_delay)
-  #print("Step Delay: %uus" % usb.step_delay)
-  #print("Settle Time: %ums" % usb.seek_settle_delay)
-  #print("Motor Delay: %ums" % usb.motor_delay)
-  #print("Auto Off: %ums" % usb.auto_off_delay)
-
-  try:
-    usb.drive_select(True)
-    usb.drive_motor(True)
-    actions[args.action](args)
-  except KeyboardInterrupt:
-    print()
-    usb.reset()
-    usb.ser.close()
-    usb.ser.open()
-  finally:
-    usb.drive_motor(False)
-    usb.drive_select(False)
+    actions = {
+      "read" : read_to_scp,
+      "write" : write_from_scp,
+      "update" : update_firmware
+    }
+
+    parser = argparse.ArgumentParser(
+      formatter_class=argparse.ArgumentDefaultsHelpFormatter)
+    parser.add_argument("action")
+    parser.add_argument("--revs", type=int, default=3,
+                        help="number of revolutions to read per track")
+    parser.add_argument("--scyl", type=int, default=0,
+                        help="first cylinder to read/write")
+    parser.add_argument("--ecyl", type=int, default=81,
+                        help="last cylinder to read/write")
+    parser.add_argument("--single-sided", action="store_true")
+    parser.add_argument("file", help="in/out filename")
+    parser.add_argument("device", help="serial device")
+    args = parser.parse_args(argv[1:])
+
+    if not args.action in actions:
+        print("** Action \"%s\" is not recognised" % args.action)
+        print("Valid actions: ", end="")
+        print(", ".join(str(key) for key in actions.keys()))
+        return
+
+    global usb
+    usb = USB.Unit(serial.Serial(args.device))
+
+    print("** %s v%u.%u, Host Tools v%u.%u"
+          % (("Greaseweazle","Bootloader")[usb.update_mode],
+             usb.major, usb.minor,
+             version.major, version.minor))
+
+    if args.action == "update" or usb.update_mode:
+        return actions[args.action](args)
+
+    elif usb.update_needed:
+        print("Firmware is out of date: Require v%u.%u"
+              % (version.major, version.minor))
+        print("Install the Update Jumper and \"update <update_file>\"")
+        return
+
+    #usb.step_delay = 5000
+    #print("Select Delay: %uus" % usb.select_delay)
+    #print("Step Delay: %uus" % usb.step_delay)
+    #print("Settle Time: %ums" % usb.seek_settle_delay)
+    #print("Motor Delay: %ums" % usb.motor_delay)
+    #print("Auto Off: %ums" % usb.auto_off_delay)
+
+    try:
+        usb.drive_select(True)
+        usb.drive_motor(True)
+        actions[args.action](args)
+    except KeyboardInterrupt:
+        print()
+        usb.reset()
+        usb.ser.close()
+        usb.ser.open()
+    finally:
+        usb.drive_motor(False)
+        usb.drive_select(False)
 
 
 def main(argv):
-  try:
-    _main(argv)
-  except USB.CmdError as error:
-    print("Command Failed: %s" % error)
+    try:
+        _main(argv)
+    except USB.CmdError as error:
+        print("Command Failed: %s" % error)
 
 
 if __name__ == "__main__":
-  main(sys.argv)
+    main(sys.argv)
+
+# Local variables:
+# python-indent: 4
+# End:

+ 6 - 2
scripts/mk_update.py

@@ -6,9 +6,9 @@
 #  2 bytes: major, minor
 #  2 bytes: 0, 0
 #  2 bytes: CRC16-CCITT, seed 0xFFFF, stored big endian
-# 
+#
 # 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>.
 
@@ -34,3 +34,7 @@ def main(argv):
 
 if __name__ == "__main__":
     main(sys.argv)
+
+# Local variables:
+# python-indent: 4
+# End: