|  | @@ -147,18 +147,31 @@ def read_to_scp(args):
 | 
	
		
			
				|  |  |  # write_from_scp:
 | 
	
		
			
				|  |  |  # Writes the specified Supercard Pro image file to floppy disk.
 | 
	
		
			
				|  |  |  def write_from_scp(args):
 | 
	
		
			
				|  |  | -    factor = usb.sample_freq / scp_freq
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if args.adjust_speed:
 | 
	
		
			
				|  |  | +        # @drive_ticks is the time in Gresaeweazle ticks between index pulses.
 | 
	
		
			
				|  |  | +        # We will adjust the flux intervals per track to allow for this.
 | 
	
		
			
				|  |  | +        usb.read_track(3)
 | 
	
		
			
				|  |  | +        index_times = usb.get_index_times(3)
 | 
	
		
			
				|  |  | +        drive_ticks = (index_times[1] + index_times[2]) / 2
 | 
	
		
			
				|  |  | +    else:
 | 
	
		
			
				|  |  | +        # Simple ratio between the Greaseweazle and SCP sample frequencies.
 | 
	
		
			
				|  |  | +        factor = usb.sample_freq / scp_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 i in track_range:
 | 
	
		
			
				|  |  |          cyl = i >> (nr_sides - 1)
 | 
	
		
			
				|  |  |          side = i & (nr_sides - 1)
 | 
	
	
		
			
				|  | @@ -166,12 +179,20 @@ def write_from_scp(args):
 | 
	
		
			
				|  |  |          if trk_offs[i] == 0:
 | 
	
		
			
				|  |  |              continue
 | 
	
		
			
				|  |  |          usb.seek(cyl, side)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        # Parse the SCP track header and extract the flux data.
 | 
	
		
			
				|  |  |          thdr = struct.unpack("<3sBIII", dat[trk_offs[i]:trk_offs[i]+16])
 | 
	
		
			
				|  |  | -        (sig,_,_,samples,off) = thdr
 | 
	
		
			
				|  |  | +        (sig,_,track_ticks,samples,off) = thdr
 | 
	
		
			
				|  |  |          assert sig == b"TRK"
 | 
	
		
			
				|  |  |          tdat = dat[trk_offs[i]+off:trk_offs[i]+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:
 | 
	
	
		
			
				|  | @@ -181,15 +202,18 @@ def write_from_scp(args):
 | 
	
		
			
				|  |  |              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:
 | 
	
		
			
				|  |  | +            elif ack == usb.Ack.FLUX_UNDERFLOW and retry < 5:
 | 
	
		
			
				|  |  |                  print("Retry #%u..." % (retry))
 | 
	
		
			
				|  |  |              else:
 | 
	
		
			
				|  |  |                  raise CmdError(ack)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      print()
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -254,7 +278,10 @@ def _main(argv):
 | 
	
		
			
				|  |  |                          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("--single-sided", action="store_true",
 | 
	
		
			
				|  |  | +                        help="read/write a single-sided image")
 | 
	
		
			
				|  |  | +    parser.add_argument("--adjust-speed", action="store_true",
 | 
	
		
			
				|  |  | +                        help="adjust write-flux times for drive speed")
 | 
	
		
			
				|  |  |      parser.add_argument("file", help="in/out filename")
 | 
	
		
			
				|  |  |      parser.add_argument("device", help="serial device")
 | 
	
		
			
				|  |  |      args = parser.parse_args(argv[1:])
 |