Skip to content

Commit

Permalink
WRITE_FLUX: Hard-sector index detection
Browse files Browse the repository at this point in the history
Expected sector timing is specified to the WRITE_FLUX command. This
allows detection of short sector times, which indicate the true
track start ("track index"). This allows write cueing as for
soft-sectored disks.
  • Loading branch information
keirf committed Sep 27, 2024
1 parent 5b08577 commit 8b8d4a6
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 5 deletions.
6 changes: 5 additions & 1 deletion inc/cdc_acm_protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
/* CMD_READ_FLUX, length=8-12. Argument is gw_read_flux; optional fields
* may be omitted. Returns flux readings terminating with EOStream (NUL). */
#define CMD_READ_FLUX 7
/* CMD_WRITE_FLUX, length=4. Argument is gw_write_flux.
/* CMD_WRITE_FLUX, length=4-8. Argument is gw_write_flux.
* Host follows the ACK with flux values terminating with EOStream (NUL).
* Device finally returns a status byte, 0 on success.
* No further commands should be issued until the status byte is received. */
Expand Down Expand Up @@ -205,6 +205,10 @@ struct packed gw_write_flux {
uint8_t cue_at_index;
/* If non-zero, terminate the write at the next index pulse. */
uint8_t terminate_at_index;
/** OPTIONAL FIELDS: **/
/* Hard sector time, in ticks. Used to find first sector and to trigger
* cue_at_index and terminate_at_index, if they are enabled. */
uint32_t hard_sector_ticks; /* default: 0 (disabled) */
};

/* CMD_ERASE_FLUX */
Expand Down
46 changes: 42 additions & 4 deletions src/floppy.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ static struct index {
volatile unsigned int count;
/* For synchronising index pulse reporting to the RDATA flux stream. */
volatile unsigned int rdata_cnt;
/* Threshold and trigger for detecting a hard-sector index hole. */
uint32_t hard_sector_thresh; /* hole-to-hole threshold to detect index */
uint32_t hard_sector_trigger; /* != 0 -> trigger is primed */
/* Last time at which index was triggered. */
time_t trigger_time;
/* Timer structure for index_timer() calls. */
Expand Down Expand Up @@ -517,6 +520,16 @@ static uint8_t floppy_noclick_step(void)
return ACK_OKAY;
}

static void index_set_hard_sector_detection(uint32_t hard_sector_ticks)
{
uint32_t hard_sector_time = time_from_samples(hard_sector_ticks);

IRQ_global_disable();
index.hard_sector_thresh = hard_sector_time * 3 / 4;
index.hard_sector_trigger = 0;
IRQ_global_enable();
}

static void floppy_flux_end(void)
{
/* Turn off write pins. */
Expand All @@ -540,6 +553,9 @@ static void floppy_flux_end(void)
dma_wdata.cr &= ~DMA_CR_EN;
while ((dma_rdata.cr & DMA_CR_EN) || (dma_wdata.cr & DMA_CR_EN))
continue;

/* Disable hard-sector index detection. */
index_set_hard_sector_detection(0);
}

static void quiesce_drives(void)
Expand Down Expand Up @@ -1129,6 +1145,8 @@ static uint8_t floppy_write_prep(const struct gw_write_flux *wf)
write.cue_at_index = wf->cue_at_index;
write.terminate_at_index = wf->terminate_at_index;

index_set_hard_sector_detection(wf->hard_sector_ticks);

return ACK_OKAY;
}

Expand Down Expand Up @@ -1605,8 +1623,9 @@ static void process_command(void)
goto out;
}
case CMD_WRITE_FLUX: {
struct gw_write_flux wf;
if (len != (2 + sizeof(wf)))
struct gw_write_flux wf = {};
if ((len < (2 + offsetof(struct gw_write_flux, hard_sector_ticks)))
|| (len > (2 + sizeof(wf))))
goto bad_command;
memcpy(&wf, &u_buf[2], len-2);
u_buf[1] = floppy_write_prep(&wf);
Expand Down Expand Up @@ -1827,14 +1846,33 @@ static void IRQ_INDEX_changed(void)
{
unsigned int cnt = tim_rdata->cnt;
time_t now = time_now();
int32_t delta;

/* Clear INDEX-changed flag. */
exti->pr = m(pin_index);

if (time_diff(index.trigger_time, now) < time_us(delay_params.index_mask))
delta = time_diff(index.trigger_time, now);
if (delta < time_us(delay_params.index_mask))
return;

index.trigger_time = now;

if (unlikely(index.hard_sector_thresh != 0)) {
if (delta > index.hard_sector_thresh) {
/* Long pulse indicates a subsequent sector hole. Filter it out
* and unprime the index trigger. */
index.hard_sector_trigger = 0;
return;
}
/* First short pulse indicates the extra (index) hole. Second
* consecutive short pulse is the first sector hole: That's the only
* one we count. */
index.hard_sector_trigger ^= 1;
if (index.hard_sector_trigger) {
/* Filter out the "rising edge" of the trigger. */
return;
}
}

index.count++;
index.rdata_cnt = cnt;
}
Expand Down

0 comments on commit 8b8d4a6

Please sign in to comment.