From 9b4b69da859d99a40924a2827a87143f1cb02d23 Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Wed, 21 Oct 2020 10:29:51 +0100 Subject: [PATCH] usb: Place index timings in-band within the flux read stream. This removes the low limit on max index timings per read request. --- inc/cdc_acm_protocol.h | 14 +++++---- scripts/greaseweazle/usb.py | 57 +++++++++++++++++++++++-------------- src/floppy.c | 31 +++++++++----------- src/fw_update.c | 4 +-- 4 files changed, 59 insertions(+), 47 deletions(-) diff --git a/inc/cdc_acm_protocol.h b/inc/cdc_acm_protocol.h index 0cc3366..7702005 100644 --- a/inc/cdc_acm_protocol.h +++ b/inc/cdc_acm_protocol.h @@ -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, */ #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 */ diff --git a/scripts/greaseweazle/usb.py b/scripts/greaseweazle/usb.py index 484eb8e..d05fb19 100644 --- a/scripts/greaseweazle/usb.py +++ b/scripts/greaseweazle/usb.py @@ -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] diff --git a/src/floppy.c b/src/floppy.c index 55f33b0..e1e97c5 100644 --- a/src/floppy.c +++ b/src/floppy.c @@ -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) diff --git a/src/fw_update.c b/src/fw_update.c index ae075a2..2827c53 100644 --- a/src/fw_update.c +++ b/src/fw_update.c @@ -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 };