mirror of
https://github.com/keirf/greaseweazle-firmware.git
synced 2025-10-31 11:06:44 -07:00
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:
@@ -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 */
|
||||
|
||||
@@ -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]
|
||||
|
||||
31
src/floppy.c
31
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)
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user