Skip to content

Commit 6da2c29

Browse files
authored
Merge pull request #11 from adafruit/updates-incompatible-floppyio-floppsy
Add support for floppsy direction pin & circuitpython changes
2 parents 4713293 + 90a33c1 commit 6da2c29

File tree

2 files changed

+113
-64
lines changed

2 files changed

+113
-64
lines changed

adafruit_floppy.py

+68-44
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ def _sleep_ms(interval):
5050
_sleep_deadline_ms(ticks_add(ticks_ms(), interval))
5151

5252

53-
class MFMFloppy: # pylint: disable=too-many-instance-attributes
53+
class Floppy: # pylint: disable=too-many-instance-attributes
5454
"""Interface with floppy disk drive hardware"""
5555

5656
_track: typing.Optional[int]
@@ -71,6 +71,7 @@ def __init__(
7171
readypin: microcontroller.Pin,
7272
wrdatapin: typing.Optional[microcontroller.Pin] = None,
7373
wrgatepin: typing.Optional[microcontroller.Pin] = None,
74+
floppydirectionpin: typing.Optional[microcontroller.Pin] = None,
7475
) -> None:
7576
self._density = DigitalInOut(densitypin)
7677
self._density.pull = Pull.UP
@@ -97,6 +98,10 @@ def __init__(
9798
self._ready = DigitalInOut(readypin)
9899
self._ready.pull = Pull.UP
99100

101+
self._floppydirection = _optionaldigitalinout(floppydirectionpin)
102+
if self._floppydirection:
103+
self._floppydirection.switch_to_output(True)
104+
100105
self._track = None
101106

102107
def _do_step(self, direction, count):
@@ -122,6 +127,7 @@ def find_track0(self):
122127
for _ in range(250):
123128
if not self._track0.value:
124129
self._track = 0
130+
self._check_inpos()
125131
return
126132
self._do_step(_STEP_OUT, 1)
127133
raise RuntimeError("Could not reach track 0")
@@ -131,7 +137,9 @@ def _check_inpos(self) -> None:
131137
drive_says_track0 = not self._track0.value
132138
we_think_track0 = track == 0
133139
if drive_says_track0 != we_think_track0:
134-
raise RuntimeError("Drive lost position")
140+
raise RuntimeError(
141+
f"Drive lost position (target={track}, track0 sensor {drive_says_track0})"
142+
)
135143

136144
@property
137145
def track(self) -> typing.Optional[int]:
@@ -150,7 +158,7 @@ def track(self, track: int) -> None:
150158
delta = track - self.track
151159
if delta < 0:
152160
self._do_step(_STEP_OUT, -delta)
153-
else:
161+
elif delta > 0:
154162
self._do_step(_STEP_IN, delta)
155163

156164
self._track = track
@@ -210,26 +218,8 @@ def flux_readinto(self, buf: "circuitpython_typing.WritableBuffer") -> int:
210218
:return: The actual number of bytes of read"""
211219
return floppyio.flux_readinto(buf, self._rddata, self._index)
212220

213-
def mfm_readinto(self, buf: "circuitpython_typing.WriteableBuffer") -> int:
214-
"""Read mfm blocks into the buffer.
215-
216-
The track is assumed to consist of 512-byte sectors.
217-
218-
The function returns when all sectors have been successfully read, or
219-
a number of index pulses have occurred. Due to technical limitations, this
220-
process may not be interruptible by KeyboardInterrupt.
221-
222-
:param buf: Read data into this buffer. Must be a multiple of 512.
223-
:return: The actual number of sectors read
224-
"""
225-
return floppyio.mfm_readinto(
226-
buf,
227-
self._rddata,
228-
self._index,
229-
)
230221

231-
232-
class FloppyBlockDevice:
222+
class FloppyBlockDevice: # pylint: disable=too-many-instance-attributes
233223
"""Wrap an MFMFloppy object into a block device suitable for `storage.VfsFat`
234224
235225
The default heads/sectors/tracks setting are for 3.5", 1.44MB floppies.
@@ -243,37 +233,53 @@ class FloppyBlockDevice:
243233
import storage
244234
import adafruit_floppy
245235
246-
floppy = adafruit_floppy.MFMFloppy(...)
236+
floppy = adafruit_floppy.Floppy(...)
247237
block_device = adafruit_floppy.FloppyBlockDevice(floppy)
248238
vfs = storage.VfsFat(f)
249239
storage.mount(vfs, '/floppy')
250240
print(os.listdir("/floppy"))
251241
"""
252242

253-
def __init__(self, floppy, heads=2, sectors=18, tracks=80):
243+
def __init__( # pylint: disable=too-many-arguments
244+
self,
245+
floppy,
246+
heads=2,
247+
sectors=18,
248+
tracks=80,
249+
flux_buffer=None,
250+
t1_nom_ns: float = 1000,
251+
):
254252
self.floppy = floppy
255253
self.heads = heads
256254
self.sectors = sectors
257255
self.tracks = tracks
256+
self.flux_buffer = flux_buffer or bytearray(sectors * 12 * 512)
258257
self.track0side0_cache = memoryview(bytearray(sectors * 512))
258+
self.track0side0_validity = bytearray(sectors)
259+
self.track_cache = memoryview(bytearray(sectors * 512))
260+
self.track_validity = bytearray(sectors)
259261

260-
self.floppy.track = 0
261-
self.floppy.head = 0
262-
floppyio.mfm_readinto(self.track0side0_cache, floppy._rddata, floppy._index)
262+
self._t2_5_max = round(2.5 * t1_nom_ns * floppyio.samplerate * 1e-9)
263+
self._t3_5_max = round(3.5 * t1_nom_ns * floppyio.samplerate * 1e-9)
264+
265+
self._track_read(self.track0side0_cache, self.track0side0_validity, 0, 0)
263266

264-
self.track_cache = memoryview(bytearray(sectors * 512))
265267
self.cached_track = -1
266268
self.cached_side = -1
267269

268270
def deinit(self):
269-
"""Deinitialize this object (does nothing)"""
271+
"""Deinitialize this object"""
272+
self.floppy.deinit()
273+
del self.flux_buffer
274+
del self.track0side0_cache
275+
del self.track_validity
270276

271277
def sync(self):
272278
"""Write out any pending data to disk (does nothing)"""
273279

274280
def writeblocks(self, start, buf): # pylint: disable=no-self-use
275281
"""Write to the floppy (always raises an exception)"""
276-
raise IOError("Read-only filesystem")
282+
raise OSError("Read-only filesystem")
277283

278284
def count(self):
279285
"""Return the floppy capacity in 512-byte units"""
@@ -287,27 +293,45 @@ def readblocks(self, start_block, buf):
287293

288294
def _readblock(self, block, buf):
289295
if block > self.count():
290-
raise IOError("Read past end of media")
296+
raise OSError("Read past end of media")
291297
track = block // (self.heads * self.sectors)
292298
block %= self.heads * self.sectors
293299
side = block // (self.sectors)
294300
block %= self.sectors
295-
trackdata = self._get_track_data(track, side)
301+
trackdata, validity = self._get_track_data(track, side)
302+
if not validity[block]:
303+
raise OSError(f"Failed to read sector {track}/{side}/{block}")
296304
buf[:] = trackdata[block * 512 : (block + 1) * 512]
297305

298306
def _get_track_data(self, track, side):
299307
if track == 0 and side == 0:
300-
return self.track0side0_cache
308+
return self.track0side0_cache, self.track0side0_validity
301309
if track != self.cached_track or side != self.cached_side:
302-
self.floppy.selected = True
303-
self.floppy.spin = True
304-
self.floppy.track = track
305-
self.floppy.side = side
306-
self.floppy.mfm_readinto(
307-
self.track_cache,
310+
self._track_read(self.track_cache, self.track_validity, track, side)
311+
return self.track_cache, self.track_validity
312+
313+
def _track_read(self, track_data, validity, track, side):
314+
self.floppy.selected = True
315+
self.floppy.spin = True
316+
self.floppy.track = track
317+
self.floppy.side = side
318+
self._mfm_readinto(track_data, validity)
319+
self.floppy.spin = False
320+
self.floppy.selected = False
321+
self.cached_track = track
322+
self.cached_side = side
323+
324+
def _mfm_readinto(self, track_data, validity):
325+
for i in range(5):
326+
self.floppy.flux_readinto(self.flux_buffer)
327+
print("timing bins", self._t2_5_max, self._t3_5_max)
328+
n = floppyio.mfm_readinto(
329+
track_data,
330+
self.flux_buffer,
331+
self._t2_5_max,
332+
self._t3_5_max,
333+
validity,
334+
i == 0,
308335
)
309-
self.floppy.spin = False
310-
self.floppy.selected = False
311-
self.cached_track = track
312-
self.cached_side = side
313-
return self.track_cache
336+
if n == self.sectors:
337+
break

examples/floppy_vfs.py

+45-20
Original file line numberDiff line numberDiff line change
@@ -3,39 +3,64 @@
33
#
44
# SPDX-License-Identifier: Unlicense
55

6-
# On an Adafruit Feather M4 or Adafruit Feather RP2040 with Floppy Featherwing,
7-
# print the root directory listing of a 1.44MB floppy
6+
# On an Adafruit Floppsy, Adafruit Feather M4 or Adafruit Feather RP2040 with
7+
# Floppy Featherwing, print the root directory listing of a 1.44MB floppy
88

9+
# Leave this line here, this memory must be allocated as early as possible to avoid
10+
# memory fragmentation
11+
flux_buffer = bytearray(110000)
12+
13+
# pylint: disable=wrong-import-position
914
import os
1015
import storage
1116
import board
1217
import adafruit_datetime as datetime
1318
import adafruit_floppy
1419

15-
D24 = getattr(board, "D24") or getattr(board, "A4")
16-
D25 = getattr(board, "D25") or getattr(board, "A5")
17-
1820
epoch = datetime.datetime(1970, 1, 1)
1921

2022
ST_SIZE = 6
2123
ST_TIME = 7
2224
SV_BFREE = 3
2325

24-
floppy = adafruit_floppy.MFMFloppy(
25-
densitypin=board.A1,
26-
indexpin=D25,
27-
selectpin=board.A0,
28-
motorpin=board.A2,
29-
directionpin=board.A3,
30-
steppin=D24,
31-
track0pin=board.D10,
32-
protectpin=board.D11,
33-
rddatapin=board.D9,
34-
sidepin=board.D6,
35-
readypin=board.D5,
36-
)
37-
38-
f = adafruit_floppy.FloppyBlockDevice(floppy, sectors=18)
26+
if hasattr(board, "DENSITY"): # floppsy
27+
floppy = adafruit_floppy.Floppy(
28+
densitypin=board.DENSITY,
29+
indexpin=board.INDEX,
30+
selectpin=board.SELECT,
31+
motorpin=board.MOTOR,
32+
directionpin=board.DIRECTION,
33+
steppin=board.STEP,
34+
track0pin=board.TRACK0,
35+
protectpin=board.WRPROT,
36+
rddatapin=board.RDDATA,
37+
sidepin=board.SIDE,
38+
readypin=board.READY,
39+
floppydirectionpin=board.FLOPPY_DIRECTION,
40+
)
41+
42+
else:
43+
D24 = getattr(board, "D24") or getattr(board, "A4")
44+
D25 = getattr(board, "D25") or getattr(board, "A5")
45+
46+
floppy = adafruit_floppy.Floppy(
47+
densitypin=board.A1,
48+
indexpin=D25,
49+
selectpin=board.A0,
50+
motorpin=board.A2,
51+
directionpin=board.A3,
52+
steppin=D24,
53+
track0pin=board.D10,
54+
protectpin=board.D11,
55+
rddatapin=board.D9,
56+
sidepin=board.D6,
57+
readypin=board.D5,
58+
flux_buffer=flux_buffer,
59+
)
60+
61+
floppy.find_track0()
62+
63+
f = adafruit_floppy.FloppyBlockDevice(floppy, sectors=18, flux_buffer=flux_buffer)
3964

4065
vfs = storage.VfsFat(f)
4166
storage.mount(vfs, "/floppy")

0 commit comments

Comments
 (0)