123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541 |
- import struct
- import itertools as it
- from greaseweazle import version
- from greaseweazle import error
- from greaseweazle.flux import Flux
- from greaseweazle import optimised
- EARLIEST_SUPPORTED_FIRMWARE = (0, 25)
- class ControlCmd:
- ClearComms = 10000
- Normal = 9600
- class Cmd:
- GetInfo = 0
- Update = 1
- Seek = 2
- Head = 3
- SetParams = 4
- GetParams = 5
- Motor = 6
- ReadFlux = 7
- WriteFlux = 8
- GetFluxStatus = 9
- GetIndexTimes = 10
- SwitchFwMode = 11
- Select = 12
- Deselect = 13
- SetBusType = 14
- SetPin = 15
- Reset = 16
- EraseFlux = 17
- SourceBytes = 18
- SinkBytes = 19
- str = {
- GetInfo: "GetInfo",
- Update: "Update",
- Seek: "Seek",
- Head: "Head",
- SetParams: "SetParams",
- GetParams: "GetParams",
- Motor: "Motor",
- ReadFlux: "ReadFlux",
- WriteFlux: "WriteFlux",
- GetFluxStatus: "GetFluxStatus",
- GetIndexTimes: "GetIndexTimes",
- SwitchFwMode: "SwitchFwMode",
- Select: "Select",
- Deselect: "Deselect",
- SetBusType: "SetBusType",
- SetPin: "SetPin",
- Reset: "Reset",
- EraseFlux: "EraseFlux",
- SourceBytes: "SourceBytes",
- SinkBytes: "SinkBytes"
- }
- class Ack:
- Okay = 0
- BadCommand = 1
- NoIndex = 2
- NoTrk0 = 3
- FluxOverflow = 4
- FluxUnderflow = 5
- Wrprot = 6
- NoUnit = 7
- NoBus = 8
- BadUnit = 9
- BadPin = 10
- BadCylinder = 11
- str = {
- Okay: "Okay",
- BadCommand: "Bad Command",
- NoIndex: "No Index",
- NoTrk0: "Track 0 not found",
- FluxOverflow: "Flux Overflow",
- FluxUnderflow: "Flux Underflow",
- Wrprot: "Disk is Write Protected",
- NoUnit: "No drive unit selected",
- NoBus: "No bus type (eg. Shugart, IBM/PC) specified",
- BadUnit: "Invalid unit number",
- BadPin: "Not a modifiable pin",
- BadCylinder: "Invalid cylinder"
- }
- class GetInfo:
- Firmware = 0
- BandwidthStats = 1
- class Params:
- Delays = 0
- class BusType:
- Invalid = 0
- IBMPC = 1
- Shugart = 2
- class FluxOp:
- Index = 1
- Space = 2
- Astable = 3
- class CmdError(Exception):
- def __init__(self, cmd, code):
- self.cmd = cmd
- self.code = code
- def cmd_str(self):
- return Cmd.str.get(self.cmd[0], "UnknownCmd")
-
- def errcode_str(self):
- if self.code == Ack.BadCylinder:
- s = Ack.str[Ack.BadCylinder]
- return s + " %d" % struct.unpack('2Bb', self.cmd)[2]
- return Ack.str.get(self.code, "Unknown Error (%u)" % self.code)
- def __str__(self):
- return "%s: %s" % (self.cmd_str(), self.errcode_str())
- class Unit:
-
-
-
-
-
-
-
- def __init__(self, ser):
- self.ser = ser
- self.reset()
-
- self._send_cmd(struct.pack("3B", Cmd.GetInfo, 3, GetInfo.Firmware))
- x = struct.unpack("<4BI3B21x", self.ser.read(32))
- (self.major, self.minor, is_main_firmware,
- self.max_cmd, self.sample_freq, self.hw_model,
- self.hw_submodel, self.usb_speed) = x
- self.version = (self.major, self.minor)
-
- if self.hw_model == 0:
- self.hw_model = 1
-
- self.update_mode = (is_main_firmware == 0)
- if self.update_mode:
- self.update_jumpered = (self.sample_freq & 1)
- del self.sample_freq
- return
-
-
- self.update_needed = (self.version < EARLIEST_SUPPORTED_FIRMWARE or
- self.version > (version.major, version.minor))
- if self.update_needed:
- return
-
- 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._watchdog_delay) = struct.unpack("<5H", self.ser.read(10))
-
-
- def reset(self):
- self.ser.reset_output_buffer()
- self.ser.baudrate = ControlCmd.ClearComms
- self.ser.baudrate = ControlCmd.Normal
- self.ser.reset_input_buffer()
- self.ser.close()
- self.ser.open()
-
-
-
- def _send_cmd(self, cmd):
- self.ser.write(cmd)
- (c,r) = struct.unpack("2B", self.ser.read(2))
- error.check(c == cmd[0], "Command returned garbage (%02x != %02x)"
- % (c, cmd[0]))
- if r != 0:
- raise CmdError(cmd, r)
-
-
- def seek(self, cyl, head):
- self._send_cmd(struct.pack("2Bb", Cmd.Seek, 3, cyl))
- self._send_cmd(struct.pack("3B", Cmd.Head, 3, head))
-
-
- def set_bus_type(self, type):
- self._send_cmd(struct.pack("3B", Cmd.SetBusType, 3, type))
-
-
- def set_pin(self, pin, level):
- self._send_cmd(struct.pack("4B", Cmd.SetPin, 4, pin, int(level)))
-
-
- def power_on_reset(self):
- self._send_cmd(struct.pack("2B", Cmd.Reset, 2))
-
-
- def drive_select(self, unit):
- self._send_cmd(struct.pack("3B", Cmd.Select, 3, unit))
-
-
- def drive_deselect(self):
- self._send_cmd(struct.pack("2B", Cmd.Deselect, 2))
-
-
- def drive_motor(self, unit, state):
- self._send_cmd(struct.pack("4B", Cmd.Motor, 4, unit, int(state)))
-
-
- def switch_fw_mode(self, mode):
- self._send_cmd(struct.pack("3B", Cmd.SwitchFwMode, 3, int(mode)))
-
-
- 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
-
-
- def update_bootloader(self, dat):
- self._send_cmd(struct.pack("<2B2I", Cmd.Update, 10,
- len(dat), 0xdeafbee3))
- self.ser.write(dat)
- (ack,) = struct.unpack("B", self.ser.read(1))
- return ack
-
-
- def _decode_flux(self, dat):
- flux, index = [], []
- assert dat[-1] == 0
- dat_i = it.islice(dat, 0, len(dat)-1)
- ticks, ticks_since_index = 0, 0
- def _read_28bit():
- val = (next(dat_i) & 254) >> 1
- val += (next(dat_i) & 254) << 6
- val += (next(dat_i) & 254) << 13
- val += (next(dat_i) & 254) << 20
- return val
- try:
- while True:
- i = next(dat_i)
- if i == 255:
- opcode = next(dat_i)
- if opcode == FluxOp.Index:
- val = _read_28bit()
- index.append(ticks_since_index + ticks + val)
- ticks_since_index = -(ticks + val)
- elif opcode == FluxOp.Space:
- ticks += _read_28bit()
- else:
- raise error.Fatal("Bad opcode in flux stream (%d)"
- % opcode)
- else:
- if i < 250:
- val = i
- else:
- val = 250 + (i - 250) * 255
- val += next(dat_i) - 1
- ticks += val
- flux.append(ticks)
- ticks_since_index += ticks
- ticks = 0
- except StopIteration:
- pass
- return flux, index
-
-
- def _encode_flux(self, flux):
- nfa_thresh = round(150e-6 * self.sample_freq)
- nfa_period = round(1.25e-6 * self.sample_freq)
- dat = bytearray()
- def _write_28bit(x):
- dat.append(1 | (x<<1) & 255)
- dat.append(1 | (x>>6) & 255)
- dat.append(1 | (x>>13) & 255)
- dat.append(1 | (x>>20) & 255)
-
-
-
-
- dummy_flux = round(100e-6 * self.sample_freq)
- for val in it.chain(flux, [dummy_flux]):
- if val == 0:
- pass
- elif val < 250:
- dat.append(val)
- elif val > nfa_thresh:
- dat.append(255)
- dat.append(FluxOp.Space)
- _write_28bit(val)
- dat.append(255)
- dat.append(FluxOp.Astable)
- _write_28bit(nfa_period)
- else:
- high = (val-250) // 255
- if high < 5:
- dat.append(250 + high)
- dat.append(1 + (val-250) % 255)
- else:
- dat.append(255)
- dat.append(FluxOp.Space)
- _write_28bit(val - 249)
- dat.append(249)
- dat.append(0)
- return dat
-
-
- def _read_track(self, revs, ticks):
-
- dat = bytearray()
- self._send_cmd(struct.pack("<2BIH", Cmd.ReadFlux, 8,
- ticks, revs+1))
- while True:
- dat += self.ser.read(1)
- dat += self.ser.read(self.ser.in_waiting)
- if dat[-1] == 0:
- break
-
- self._send_cmd(struct.pack("2B", Cmd.GetFluxStatus, 2))
- return dat
-
-
- def read_track(self, revs, ticks=0, nr_retries=5):
- retry = 0
- while True:
- try:
- dat = self._read_track(revs, ticks)
- except CmdError as error:
-
- if error.code == Ack.FluxOverflow and retry < nr_retries:
- retry += 1
- else:
- raise error
- else:
-
- break
- try:
-
- flux_list, index_list = optimised.decode_flux(dat)
- except AttributeError:
- flux_list, index_list = self._decode_flux(dat)
-
- return Flux(index_list, flux_list, self.sample_freq, index_cued=False)
-
-
- def write_track(self, flux_list, terminate_at_index,
- cue_at_index=True, nr_retries=5):
-
- dat = self._encode_flux(flux_list)
-
- retry = 0
- while True:
- try:
-
- self._send_cmd(struct.pack("4B", Cmd.WriteFlux, 4,
- int(cue_at_index),
- int(terminate_at_index)))
- self.ser.write(dat)
- self.ser.read(1)
- self._send_cmd(struct.pack("2B", Cmd.GetFluxStatus, 2))
- except CmdError as error:
-
- if error.code == Ack.FluxUnderflow and retry < nr_retries:
- retry += 1
- else:
- raise error
- else:
-
- break
-
-
- def erase_track(self, ticks):
- self._send_cmd(struct.pack("<2BI", Cmd.EraseFlux, 6, int(ticks)))
- self.ser.read(1)
- self._send_cmd(struct.pack("2B", Cmd.GetFluxStatus, 2))
-
-
- def source_bytes(self, nr):
- self._send_cmd(struct.pack("<2BI", Cmd.SourceBytes, 6, nr))
- while nr > 0:
- self.ser.read(1)
- waiting = self.ser.in_waiting
- self.ser.read(waiting)
- nr -= 1 + waiting
-
-
- def sink_bytes(self, nr):
- self._send_cmd(struct.pack("<2BI", Cmd.SinkBytes, 6, nr))
- dat = bytes(1024*1024)
- while nr > len(dat):
- self.ser.write(dat)
- nr -= len(dat)
- self.ser.write(dat[:nr])
- self.ser.read(1)
-
-
- def bw_stats(self):
- self._send_cmd(struct.pack("3B", Cmd.GetInfo, 3,
- GetInfo.BandwidthStats))
- min_bytes, min_usecs, max_bytes, max_usecs = struct.unpack(
- "<4I16x", self.ser.read(32))
- min_bw = (8 * min_bytes) / min_usecs
- max_bw = (8 * max_bytes) / max_usecs
- return min_bw, max_bw
-
-
-
-
-
-
-
-
-
-
- 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._watchdog_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 watchdog_delay(self):
- return self._watchdog_delay
- @watchdog_delay.setter
- def watchdog_delay(self, watchdog_delay):
- self._watchdog_delay = watchdog_delay
- self._set_delays()
|