Skip to content

Commit 7d2e46a

Browse files
committed
Update adafruit_floppy
1 parent d1cd3f8 commit 7d2e46a

4 files changed

Lines changed: 95 additions & 31 deletions

File tree

lib/adafruit_floppy

shared-bindings/floppyio/__init__.c

Lines changed: 73 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "shared-bindings/digitalio/DigitalInOut.h"
2929
#include "common-hal/floppyio/__init__.h"
3030

31+
#include <math.h>
3132
#include <stdint.h>
3233

3334
#include "py/binary.h"
@@ -52,62 +53,117 @@
5253
//| ...
5354
//|
5455
STATIC mp_obj_t floppyio_flux_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
55-
enum { ARG_buffer, ARG_data, ARG_index };
56+
enum { ARG_buffer, ARG_data, ARG_index, ARG_index_wait };
5657
static const mp_arg_t allowed_args[] = {
5758
{ MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
5859
{ MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
5960
{ MP_QSTR_index, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
61+
{ MP_QSTR_index_wait, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
6062
};
6163
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
6264
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
6365

6466
mp_buffer_info_t bufinfo;
6567
mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_WRITE);
68+
6669
digitalio_digitalinout_obj_t *data = assert_digitalinout(args[ARG_data].u_obj);
6770
digitalio_digitalinout_obj_t *index = assert_digitalinout(args[ARG_index].u_obj);
6871

69-
return MP_OBJ_NEW_SMALL_INT(common_hal_floppyio_flux_readinto(bufinfo.buf, bufinfo.len, data, index));
72+
mp_int_t index_wait_ms = args[ARG_index_wait].u_obj ?
73+
MICROPY_FLOAT_C_FUN(round)(mp_arg_validate_type_float(args[ARG_index_wait].u_obj, MP_QSTR_index_wait) * 1000) :
74+
MICROPY_FLOAT_CONST(.220);
75+
76+
return MP_OBJ_NEW_SMALL_INT(common_hal_floppyio_flux_readinto(bufinfo.buf, bufinfo.len, data, index, index_wait_ms));
7077
}
7178
MP_DEFINE_CONST_FUN_OBJ_KW(floppyio_flux_readinto_obj, 0, floppyio_flux_readinto);
7279

7380
//| def mfm_readinto(
74-
//| buffer: WriteableBuffer, data: digitalio.DigitalInOut, index: digitalio.DigitalInOut
81+
//| buffer: WriteableBuffer,
82+
//| flux: ReadableBuffer,
83+
//| flux_t1_nominal: int,
84+
//| validity: bytearray | None = None,
85+
//| clear_validity: bool = True,
7586
//| ) -> int:
76-
//| """Read mfm blocks into the buffer.
87+
//| """Decode MFM flux into the buffer
7788
//|
7889
//| The track is assumed to consist of 512-byte sectors.
7990
//|
80-
//| The function returns when all sectors have been successfully read, or
81-
//| a number of index pulses have occurred. Due to technical limitations, this
82-
//| process may not be interruptible by KeyboardInterrupt.
91+
//| The function returns the number of sectors successfully read. In addition,
92+
//| it updates the ``validity`` buffer with information about which sectors
93+
//| were read.
8394
//|
84-
//| :param buffer: Read data into this buffer. Must be a multiple of 512.
85-
//| :param data: Pin on which the mfm data appears
86-
//| :param index: Pin on which the index pulse appears
95+
//| MFM encoding uses pulses of 3 widths, "T2", "T3" and "T4".
96+
//| A 1440KiB disk in standard MFM format has "T2" pulses of 2000ns, "T3" pulses of 3000ns,
97+
//| and "T4" pulses of 4000ns.
98+
//|
99+
//| Parameters ``t2_max`` and ``t3_max`` are used to distinguish these pulses.
100+
//| A pulse with ``p <= t2_max`` is a "T2" pulse,
101+
//| a pulse with ``t2_max < p <= t3_max`` is a "T3" pulse,
102+
//| and a pulse with ``t3_max < p`` is a "T4" pulse.
103+
//|
104+
//| The following code can convert a number in nanoseconds to a number of samples
105+
//| for a given sample rate:
106+
//|
107+
//| . code-block:: py
108+
//|
109+
//| def ns_to_count(ns, samplerate):
110+
//| return round(ns * samplerate * 1e-9)
111+
//|
112+
//| This means the following typical values are a good starting place for a 1.44MB floppy:
113+
//|
114+
//| . code-block:: py
115+
//|
116+
//| t2_max = ns_to_count(2500, samplerate) # Mid way between T2 and T3 length
117+
//| t3_max = ns_to_count(3500, samplerate) # Mid way between T2 and T3 length
118+
//|
119+
//| :param buffer: Read data into this buffer. Byte length must be a multiple of 512.
120+
//| :param flux: Flux data from a previous `flux_readinto` call
121+
//| :param t2_max: Maximum time of a flux cell in counts.
122+
//| :param t3_max: Nominal time of a flux cell in counts.
123+
//| :param validity: Optional bytearray. For each sector successfully read, the corresponding validity entry is set to ``1`` and previously valid sectors are not decoded.
124+
//| :param clear_validity: If `True`, clear the validity information before decoding and attempt to decode all sectors.
87125
//| :return: The actual number of sectors read
88126
//| """
89127
//| ...
90128
//|
91129
STATIC mp_obj_t floppyio_mfm_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
92-
enum { ARG_buffer, ARG_data, ARG_index };
130+
enum { ARG_buffer, ARG_flux, ARG_t2_max, ARG_t3_max, ARG_validity, ARG_clear_validity };
93131
static const mp_arg_t allowed_args[] = {
94132
{ MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
95-
{ MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
96-
{ MP_QSTR_index, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
133+
{ MP_QSTR_flux, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
134+
{ MP_QSTR_flux_t2_max, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
135+
{ MP_QSTR_flux_t3_max, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
136+
{ MP_QSTR_validity, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
137+
{ MP_QSTR_clear_validity, MP_ARG_BOOL, {.u_bool = true } },
97138
};
98139
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
99140
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
100141

101142
mp_buffer_info_t bufinfo;
102143
mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_WRITE);
103-
digitalio_digitalinout_obj_t *data = assert_digitalinout(args[ARG_data].u_obj);
104-
digitalio_digitalinout_obj_t *index = assert_digitalinout(args[ARG_index].u_obj);
105-
106144
if (bufinfo.len % 512 != 0) {
107145
mp_raise_ValueError(MP_ERROR_TEXT("Buffer must be a multiple of 512 bytes"));
108146
}
109147
size_t n_sectors = bufinfo.len / 512;
110-
return MP_OBJ_NEW_SMALL_INT(common_hal_floppyio_mfm_readinto(bufinfo.buf, n_sectors, data, index));
148+
149+
mp_buffer_info_t bufinfo_flux;
150+
mp_get_buffer_raise(args[ARG_flux].u_obj, &bufinfo_flux, MP_BUFFER_READ);
151+
152+
mp_buffer_info_t bufinfo_validity;
153+
uint8_t validity_buf[n_sectors];
154+
if (args[ARG_validity].u_obj) {
155+
mp_get_buffer_raise(args[ARG_validity].u_obj, &bufinfo_validity, MP_BUFFER_READ);
156+
mp_arg_validate_length_min(bufinfo_validity.len, n_sectors, MP_QSTR_validity);
157+
if (args[ARG_clear_validity].u_bool) {
158+
memset(validity_buf, 0, sizeof(validity_buf));
159+
}
160+
} else {
161+
bufinfo_validity.buf = &validity_buf;
162+
bufinfo_validity.len = n_sectors;
163+
memset(validity_buf, 0, sizeof(validity_buf));
164+
}
165+
166+
return MP_OBJ_NEW_SMALL_INT(common_hal_floppyio_mfm_readinto(&bufinfo, &bufinfo_flux, bufinfo_validity.buf, args[ARG_t2_max].u_int, args[ARG_t3_max].u_int));
111167
}
112168
MP_DEFINE_CONST_FUN_OBJ_KW(floppyio_mfm_readinto_obj, 0, floppyio_mfm_readinto);
113169

shared-bindings/floppyio/__init__.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@
2626

2727
#pragma once
2828

29+
#include "py/obj.h"
2930
#include "common-hal/digitalio/DigitalInOut.h"
3031

31-
int common_hal_floppyio_flux_readinto(void *buf, size_t len, digitalio_digitalinout_obj_t *data, digitalio_digitalinout_obj_t *index);
32-
int common_hal_floppyio_mfm_readinto(void *buf, size_t n_sector, digitalio_digitalinout_obj_t *data, digitalio_digitalinout_obj_t *index);
32+
int common_hal_floppyio_flux_readinto(void *buf, size_t len, digitalio_digitalinout_obj_t *data, digitalio_digitalinout_obj_t *index, mp_int_t index_wait_ms);
33+
int common_hal_floppyio_mfm_readinto(const mp_buffer_info_t *buf, const mp_buffer_info_t *flux_buf, uint8_t *validity, size_t t2_max, size_t t3_max);

shared-module/floppyio/__init__.c

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
*/
2626

2727
#include "py/runtime.h"
28+
#include "py/mphal.h"
2829

2930
#include "shared-bindings/time/__init__.h"
3031
#include "shared-bindings/floppyio/__init__.h"
@@ -38,17 +39,18 @@
3839
#define T3_5 (FLOPPYIO_SAMPLERATE * 7 / 2 / 1000000)
3940
#endif
4041

41-
#define MFM_IO_MMIO (1)
4242
#include "lib/adafruit_floppy/src/mfm_impl.h"
4343

44+
MP_WEAK
4445
__attribute__((optimize("O3")))
45-
int common_hal_floppyio_flux_readinto(void *buf, size_t len, digitalio_digitalinout_obj_t *data, digitalio_digitalinout_obj_t *index) {
46+
int common_hal_floppyio_flux_readinto(void *buf, size_t len, digitalio_digitalinout_obj_t *data, digitalio_digitalinout_obj_t *index, mp_int_t index_wait_ms) {
4647
uint32_t index_mask;
4748
volatile uint32_t *index_port = common_hal_digitalio_digitalinout_get_reg(index, DIGITALINOUT_REG_READ, &index_mask);
4849

4950
uint32_t data_mask;
5051
volatile uint32_t *data_port = common_hal_digitalio_digitalinout_get_reg(data, DIGITALINOUT_REG_READ, &data_mask);
5152

53+
uint32_t index_deadline_ms = mp_hal_ticks_ms() + index_wait_ms;
5254
#undef READ_INDEX
5355
#undef READ_DATA
5456
#define READ_INDEX() (!!(*index_port & index_mask))
@@ -62,6 +64,9 @@ int common_hal_floppyio_flux_readinto(void *buf, size_t len, digitalio_digitalin
6264

6365
// wait for index pulse low
6466
while (READ_INDEX()) { /* NOTHING */
67+
if (supervisor_ticks_ms32() > index_deadline_ms) {
68+
return 0;
69+
}
6570
}
6671

6772

@@ -96,15 +101,17 @@ int common_hal_floppyio_flux_readinto(void *buf, size_t len, digitalio_digitalin
96101
return pulses_ptr - pulses;
97102
}
98103

99-
int common_hal_floppyio_mfm_readinto(void *buf, size_t n_sectors, digitalio_digitalinout_obj_t *data, digitalio_digitalinout_obj_t *index) {
100-
mfm_io_t io;
101-
io.index_port = common_hal_digitalio_digitalinout_get_reg(index, DIGITALINOUT_REG_READ, &io.index_mask);
102-
io.data_port = common_hal_digitalio_digitalinout_get_reg(data, DIGITALINOUT_REG_READ, &io.data_mask);
103-
104-
common_hal_mcu_disable_interrupts();
105-
uint8_t validity[n_sectors];
106-
int result = read_track(io, n_sectors, buf, validity);
107-
common_hal_mcu_enable_interrupts();
104+
int common_hal_floppyio_mfm_readinto(const mp_buffer_info_t *buf, const mp_buffer_info_t *flux_buf, uint8_t *validity, size_t t2_max, size_t t3_max) {
105+
mfm_io_t io = {
106+
.T2_max = t2_max,
107+
.T3_max = t3_max,
108+
.pulses = flux_buf->buf,
109+
.n_pulses = flux_buf->len,
110+
.sectors = buf->buf,
111+
.sector_validity = validity,
112+
.n_sectors = buf->len / 512,
113+
};
114+
int result = decode_track_mfm(&io);
108115

109116
return result;
110117
}

0 commit comments

Comments
 (0)