Read and Write Flux commands are extended.

1. Read flux can be terminated on a number of ticks as well as number of IDX.
2. Write flux can be started immediately rather than index cued.
This commit is contained in:
Keir Fraser
2020-12-05 17:52:45 +00:00
parent 58f9b92ca6
commit b69b4cdef1
3 changed files with 43 additions and 28 deletions

View File

@@ -14,7 +14,7 @@
* GREASEWEAZLE COMMAND SET
*/
/* CMD_GET_INFO, length=3, 0. Returns 32 bytes after ACK. */
/* CMD_GET_INFO, length=3, idx. Returns 32 bytes after ACK. */
#define CMD_GET_INFO 0
/* [BOOTLOADER] CMD_UPDATE, length=6, <update_len>.
* Host follows with <update_len> bytes.
@@ -33,10 +33,10 @@
#define CMD_GET_PARAMS 5
/* CMD_MOTOR, length=4, drive#, on/off. Turn on/off a drive motor. */
#define CMD_MOTOR 6
/* CMD_READ_FLUX, length=2-3. Optionally include all or part of gw_read_flux.
/* CMD_READ_FLUX, length=2-8. Argument is gw_read_flux.
* Returns flux readings until EOStream. */
#define CMD_READ_FLUX 7
/* CMD_WRITE_FLUX, length=2-3. Optionally include all or part of gw_write_flux.
/* CMD_WRITE_FLUX, length=2-4. Argument is gw_write_flux.
* Host follows with flux readings until EOStream. */
#define CMD_WRITE_FLUX 8
/* CMD_GET_FLUX_STATUS, length=2. Last read/write status returned in ACK. */
@@ -152,17 +152,23 @@ struct packed gw_bw_stats {
/* CMD_READ_FLUX */
struct packed gw_read_flux {
uint16_t nr_idx; /* default: 2 */
/* Maximum ticks to read for (or 0, for no limit). */
uint32_t ticks;
/* Maximum index pulses to read (or 0, for no limit). */
uint16_t max_index;
};
/* CMD_WRITE_FLUX */
struct packed gw_write_flux {
uint8_t terminate_at_index; /* default: 0 */
/* If non-zero, start the write at the index pulse. */
uint8_t cue_at_index;
/* If non-zero, terminate the write at the next index pulse. */
uint8_t terminate_at_index;
};
/* CMD_ERASE_FLUX */
struct packed gw_erase_flux {
uint32_t erase_ticks;
uint32_t ticks;
};
/* CMD_SINK_SOURCE_BYTES */

View File

@@ -355,11 +355,12 @@ class Unit:
## _read_track:
## Private helper which issues command requests to Greaseweazle.
def _read_track(self, nr_revs):
def _read_track(self, revs, ticks):
# Request and read all flux timings for this track.
dat = bytearray()
self._send_cmd(struct.pack("<2BH", Cmd.ReadFlux, 4, nr_revs+1))
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)
@@ -374,12 +375,12 @@ class Unit:
## read_track:
## Read and decode flux and index timings for the current track.
def read_track(self, nr_revs, nr_retries=5):
def read_track(self, revs, ticks=0, nr_retries=5):
retry = 0
while True:
try:
dat = self._read_track(nr_revs)
dat = self._read_track(revs, ticks)
except CmdError as error:
# An error occurred. We may retry on transient overflows.
if error.code == Ack.FluxOverflow and retry < nr_retries:
@@ -412,7 +413,8 @@ class Unit:
## write_track:
## Write the given flux stream to the current track via Greaseweazle.
def write_track(self, flux_list, terminate_at_index, nr_retries=5):
def write_track(self, flux_list, terminate_at_index,
cue_at_index=True, nr_retries=5):
# Create encoded data stream.
dat = self._encode_flux(flux_list)
@@ -421,7 +423,8 @@ class Unit:
while True:
try:
# Write the flux stream to the track via Greaseweazle.
self._send_cmd(struct.pack("3B", Cmd.WriteFlux, 3,
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) # Sync with Greaseweazle

View File

@@ -324,7 +324,9 @@ static void floppy_end_command(void *ack, unsigned int ack_len)
*/
static struct {
unsigned int idx, nr_idx;
unsigned int nr_index;
unsigned int max_index;
time_t deadline;
} read;
static void _write_28bit(uint32_t x)
@@ -342,7 +344,7 @@ static void rdata_encode_flux(void)
timcnt_t prev = dma.prev_sample, curr, next;
uint32_t ticks;
ASSERT(read.idx < read.nr_idx);
ASSERT(read.nr_index < read.max_index);
/* We don't want to race the Index IRQ handler. */
IRQ_global_disable();
@@ -350,10 +352,10 @@ static void rdata_encode_flux(void)
/* Find out where the DMA engine's producer index has got to. */
prod = ARRAY_SIZE(dma.buf) - dma_rdata.ndtr;
if (read.idx != index.count) {
if (read.nr_index != index.count) {
/* We have just passed the index mark: Record information about
* the just-completed revolution. */
read.idx = index.count;
read.nr_index = index.count;
ticks = (timcnt_t)(index.rdata_cnt - prev);
IRQ_global_enable(); /* we're done reading ISR variables */
u_buf[U_MASK(u_prod++)] = 0xff;
@@ -415,9 +417,6 @@ static void rdata_encode_flux(void)
static uint8_t floppy_read_prep(const struct gw_read_flux *rf)
{
if (rf->nr_idx == 0)
return ACK_BAD_COMMAND;
/* Prepare Timer & DMA. */
dma_rdata.mar = (uint32_t)(unsigned long)dma.buf;
dma_rdata.ndtr = ARRAY_SIZE(dma.buf);
@@ -437,7 +436,9 @@ static uint8_t floppy_read_prep(const struct gw_read_flux *rf)
flux_op.start = time_now();
flux_op.status = ACK_OKAY;
memset(&read, 0, sizeof(read));
read.nr_idx = rf->nr_idx;
read.max_index = rf->max_index ?: INT_MAX;
read.deadline = flux_op.start;
read.deadline += rf->ticks ? time_from_samples(rf->ticks) : INT_MAX;
return ACK_OKAY;
}
@@ -476,9 +477,10 @@ static void floppy_read(void)
floppy_state = ST_read_flux_drain;
u_cons = u_prod = avail = 0;
} else if (read.idx >= read.nr_idx) {
} else if ((read.nr_index >= read.max_index)
|| (time_since(read.deadline) >= 0)) {
/* Read all requested revolutions. */
/* Read all requested data. */
floppy_flux_end();
floppy_state = ST_read_flux_drain;
@@ -523,6 +525,7 @@ static void floppy_read(void)
static struct {
bool_t is_finished;
bool_t cue_at_index;
bool_t terminate_at_index;
uint32_t astable_period;
uint32_t ticks;
@@ -745,6 +748,7 @@ static uint8_t floppy_write_prep(const struct gw_write_flux *wf)
flux_op.status = ACK_OKAY;
memset(&write, 0, sizeof(write));
write.flux_mode = FLUXMODE_idle;
write.cue_at_index = wf->cue_at_index;
write.terminate_at_index = wf->terminate_at_index;
return ACK_OKAY;
@@ -792,7 +796,7 @@ static void floppy_write_wait_data(void)
static void floppy_write_wait_index(void)
{
if (index.count == 0) {
if (write.cue_at_index && (index.count == 0)) {
if (time_since(flux_op.start) > time_ms(2000)) {
/* Timeout */
floppy_flux_end();
@@ -900,7 +904,7 @@ static uint8_t floppy_erase_prep(const struct gw_erase_flux *ef)
floppy_state = ST_erase_flux;
flux_op.status = ACK_OKAY;
flux_op.end = time_now() + time_from_samples(ef->erase_ticks);
flux_op.end = time_now() + time_from_samples(ef->ticks);
return ACK_OKAY;
}
@@ -1145,16 +1149,18 @@ static void process_command(void)
goto out;
}
case CMD_READ_FLUX: {
struct gw_read_flux rf = { .nr_idx = 2 };
if ((len < 2) || (len > (2 + sizeof(rf))))
struct gw_read_flux rf;
if (len != (2 + sizeof(rf)))
goto bad_command;
memcpy(&rf, &u_buf[2], len-2);
u_buf[1] = floppy_read_prep(&rf);
goto out;
}
case CMD_WRITE_FLUX: {
struct gw_write_flux wf = { 0 };
if ((len < 2) || (len > (2 + sizeof(wf))))
struct gw_write_flux wf = {
.cue_at_index = 1,
.terminate_at_index = 0 };
if (len != (2 + sizeof(wf)))
goto bad_command;
memcpy(&wf, &u_buf[2], len-2);
u_buf[1] = floppy_write_prep(&wf);