|
@@ -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):
|