usb: Place index timings in-band within the flux read stream.

This removes the low limit on max index timings per read request.
This commit is contained in:
Keir Fraser
2020-10-21 10:29:51 +01:00
parent 81150b5117
commit 9b4b69da85
4 changed files with 59 additions and 47 deletions

View File

@@ -41,9 +41,6 @@
#define CMD_WRITE_FLUX 8
/* CMD_GET_FLUX_STATUS, length=2. Last read/write status returned in ACK. */
#define CMD_GET_FLUX_STATUS 9
/* CMD_GET_INDEX_TIMES, length=4, first, nr.
* Returns nr*4 bytes after ACK. */
#define CMD_GET_INDEX_TIMES 10
/* CMD_SWITCH_FW_MODE, length=3, <mode> */
#define CMD_SWITCH_FW_MODE 11
/* CMD_SELECT, length=3, drive#. Select drive# as current unit. */
@@ -98,6 +95,13 @@
#define BAUD_CLEAR_COMMS 10000
/*
* Flux stream opcodes. Preceded by 0xFF byte.
*/
#define FLUXOP_LONGFLUX 1
#define FLUXOP_INDEX 2
/*
* COMMAND PACKETS
*/
@@ -107,7 +111,7 @@
struct packed gw_info {
uint8_t fw_major;
uint8_t fw_minor;
uint8_t max_index;
uint8_t is_main_firmware; /* == 0 -> update bootloader */
uint8_t max_cmd;
uint32_t sample_freq;
uint8_t hw_model, hw_submodel;
@@ -126,7 +130,7 @@ struct packed gw_bw_stats {
/* CMD_READ_FLUX */
struct packed gw_read_flux {
uint8_t nr_idx; /* default: 2 */
uint16_t nr_idx; /* default: 2 */
};
/* CMD_WRITE_FLUX */

View File

@@ -109,6 +109,12 @@ class BusType:
Shugart = 2
## Flux read stream opcodes, preceded by 0xFF byte
class FluxOp:
LongFlux = 1
Index = 2
## CmdError: Encapsulates a command acknowledgement.
class CmdError(Exception):
@@ -126,9 +132,9 @@ 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
## update_mode: True iff the Greaseweazle unit is in update mode
## Unit(ser):
## Accepts a Pyserial instance for Greaseweazle communications.
@@ -138,17 +144,16 @@ class Unit:
# Copy firmware info to instance variables (see above for definitions).
self._send_cmd(struct.pack("3B", Cmd.GetInfo, 3, GetInfo.Firmware))
x = struct.unpack("<4BI3B21x", self.ser.read(32))
(self.major, self.minor, self.max_index,
(self.major, self.minor, is_main_firmware,
self.max_cmd, self.sample_freq, self.hw_model,
self.hw_submodel, self.usb_speed) = x
# Old firmware doesn't report HW type but runs on STM32F1 only.
if self.hw_model == 0:
self.hw_model = 1
# Check whether firmware is in update mode: limited command set if so.
self.update_mode = (self.max_index == 0)
self.update_mode = (is_main_firmware == 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.
@@ -228,14 +233,6 @@ class Unit:
self._send_cmd(struct.pack("4B", Cmd.Motor, 4, unit, 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
## switch_fw_mode:
## Switch between update bootloader and main firmware.
def switch_fw_mode(self, mode):
@@ -264,27 +261,44 @@ class Unit:
## _decode_flux:
## Decode the Greaseweazle data stream into a list of flux samples.
def _decode_flux(self, dat):
flux = []
flux, index = [], []
dat_i = iter(dat)
ticks_since_index = 0
try:
while True:
i = next(dat_i)
if i < 250:
flux.append(i)
ticks_since_index += 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)
opcode = next(dat_i)
if opcode == FluxOp.LongFlux:
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)
ticks_since_index += val
elif opcode == FluxOp.Index:
val = (next(dat_i) & 254) >> 1
val += (next(dat_i) & 254) << 6
val += (next(dat_i) & 254) << 13
val += (next(dat_i) & 254) << 20
index.append(ticks_since_index + val)
ticks_since_index = -val
pass
else:
raise error.Fatal("Bad opcode in flux stream (%d)"
% opcode)
else:
val = (i - 249) * 250
val += next(dat_i) - 1
flux.append(val)
ticks_since_index += val
except StopIteration:
pass
error.check(flux[-1] == 0, "Missing terminator on flux read stream")
return flux[:-1]
return flux[:-1], index
## _encode_flux:
@@ -317,7 +331,7 @@ class Unit:
# Request and read all flux timings for this track.
dat = bytearray()
self._send_cmd(struct.pack("3B", Cmd.ReadFlux, 3, nr_revs+1))
self._send_cmd(struct.pack("<2BH", Cmd.ReadFlux, 4, nr_revs+1))
while True:
dat += self.ser.read(1)
dat += self.ser.read(self.ser.in_waiting)
@@ -349,8 +363,7 @@ class Unit:
break
# 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)
flux_list, index_list = self._decode_flux(dat)
# Clip the initial partial revolution.
to_index = index_list[0]

View File

@@ -254,7 +254,8 @@ void floppy_init(void)
}
struct gw_info gw_info = {
.max_index = 15, .max_cmd = CMD_MAX,
.is_main_firmware = 1,
.max_cmd = CMD_MAX,
.sample_freq = 72000000u,
.hw_model = STM32F
};
@@ -294,9 +295,7 @@ static struct {
bool_t terminate_at_index;
bool_t no_flux_area;
unsigned int packet_len;
int ticks_since_index;
uint32_t ticks_since_flux;
uint32_t index_ticks[15];
uint8_t packet[USB_HS_MPS];
} rw;
@@ -306,7 +305,6 @@ static void rdata_encode_flux(void)
uint16_t cons = dma.cons, prod;
timcnt_t prev = dma.prev_sample, curr, next;
uint32_t ticks = rw.ticks_since_flux;
int ticks_since_index = rw.ticks_since_index;
ASSERT(rw.idx < rw.nr_idx);
@@ -320,8 +318,14 @@ static void rdata_encode_flux(void)
/* We have just passed the index mark: Record information about
* the just-completed revolution. */
int partial_flux = ticks + (timcnt_t)(index.rdata_cnt - prev);
rw.index_ticks[rw.idx++] = ticks_since_index + partial_flux;
ticks_since_index = -partial_flux;
ASSERT(partial_flux >= 0);
u_buf[U_MASK(u_prod++)] = 0xff;
u_buf[U_MASK(u_prod++)] = FLUXOP_INDEX;
u_buf[U_MASK(u_prod++)] = 1 | (partial_flux << 1);
u_buf[U_MASK(u_prod++)] = 1 | (partial_flux >> 6);
u_buf[U_MASK(u_prod++)] = 1 | (partial_flux >> 13);
u_buf[U_MASK(u_prod++)] = 1 | (partial_flux >> 20);
rw.idx = index.count;
}
IRQ_global_enable();
@@ -346,8 +350,9 @@ static void rdata_encode_flux(void)
u_buf[U_MASK(u_prod++)] = 249 + high;
u_buf[U_MASK(u_prod++)] = 1 + (ticks % 250);
} else {
/* 1500-(2^28-1): Five bytes */
/* 1500-(2^28-1): Six bytes */
u_buf[U_MASK(u_prod++)] = 0xff;
u_buf[U_MASK(u_prod++)] = FLUXOP_LONGFLUX;
u_buf[U_MASK(u_prod++)] = 1 | (ticks << 1);
u_buf[U_MASK(u_prod++)] = 1 | (ticks >> 6);
u_buf[U_MASK(u_prod++)] = 1 | (ticks >> 13);
@@ -355,7 +360,6 @@ static void rdata_encode_flux(void)
}
}
ticks_since_index += ticks;
ticks = 0;
}
@@ -376,12 +380,11 @@ static void rdata_encode_flux(void)
dma.cons = cons;
dma.prev_sample = prev;
rw.ticks_since_flux = ticks;
rw.ticks_since_index = ticks_since_index;
}
static uint8_t floppy_read_prep(const struct gw_read_flux *rf)
{
if ((rf->nr_idx == 0) || (rf->nr_idx > gw_info.max_index))
if (rf->nr_idx == 0)
return ACK_BAD_COMMAND;
/* Prepare Timer & DMA. */
@@ -1035,14 +1038,6 @@ static void process_command(void)
u_buf[1] = rw.status;
goto out;
}
case CMD_GET_INDEX_TIMES: {
uint8_t f = u_buf[2], n = u_buf[3];
if ((len != 4) || (n > 15) || ((f+n) > gw_info.max_index))
goto bad_command;
memcpy(&u_buf[2], rw.index_ticks+f, n*4);
resp_sz += n*4;
break;
}
case CMD_SELECT: {
uint8_t unit = u_buf[2];
if (len != 3)

View File

@@ -38,8 +38,8 @@ static uint32_t u_prod;
static bool_t upd_strapped;
struct gw_info gw_info = {
/* Max Index == 0 signals that this is the Bootloader. */
.max_index = 0, .max_cmd = CMD_MAX,
.is_main_firmware = 0,
.max_cmd = CMD_MAX,
.hw_model = STM32F
};