@@ -50,7 +50,7 @@ def _sleep_ms(interval):
50
50
_sleep_deadline_ms (ticks_add (ticks_ms (), interval ))
51
51
52
52
53
- class MFMFloppy : # pylint: disable=too-many-instance-attributes
53
+ class Floppy : # pylint: disable=too-many-instance-attributes
54
54
"""Interface with floppy disk drive hardware"""
55
55
56
56
_track : typing .Optional [int ]
@@ -71,6 +71,7 @@ def __init__(
71
71
readypin : microcontroller .Pin ,
72
72
wrdatapin : typing .Optional [microcontroller .Pin ] = None ,
73
73
wrgatepin : typing .Optional [microcontroller .Pin ] = None ,
74
+ floppydirectionpin : typing .Optional [microcontroller .Pin ] = None ,
74
75
) -> None :
75
76
self ._density = DigitalInOut (densitypin )
76
77
self ._density .pull = Pull .UP
@@ -97,6 +98,10 @@ def __init__(
97
98
self ._ready = DigitalInOut (readypin )
98
99
self ._ready .pull = Pull .UP
99
100
101
+ self ._floppydirection = _optionaldigitalinout (floppydirectionpin )
102
+ if self ._floppydirection :
103
+ self ._floppydirection .switch_to_output (True )
104
+
100
105
self ._track = None
101
106
102
107
def _do_step (self , direction , count ):
@@ -122,6 +127,7 @@ def find_track0(self):
122
127
for _ in range (250 ):
123
128
if not self ._track0 .value :
124
129
self ._track = 0
130
+ self ._check_inpos ()
125
131
return
126
132
self ._do_step (_STEP_OUT , 1 )
127
133
raise RuntimeError ("Could not reach track 0" )
@@ -131,7 +137,9 @@ def _check_inpos(self) -> None:
131
137
drive_says_track0 = not self ._track0 .value
132
138
we_think_track0 = track == 0
133
139
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
+ )
135
143
136
144
@property
137
145
def track (self ) -> typing .Optional [int ]:
@@ -150,7 +158,7 @@ def track(self, track: int) -> None:
150
158
delta = track - self .track
151
159
if delta < 0 :
152
160
self ._do_step (_STEP_OUT , - delta )
153
- else :
161
+ elif delta > 0 :
154
162
self ._do_step (_STEP_IN , delta )
155
163
156
164
self ._track = track
@@ -210,26 +218,8 @@ def flux_readinto(self, buf: "circuitpython_typing.WritableBuffer") -> int:
210
218
:return: The actual number of bytes of read"""
211
219
return floppyio .flux_readinto (buf , self ._rddata , self ._index )
212
220
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
- )
230
221
231
-
232
- class FloppyBlockDevice :
222
+ class FloppyBlockDevice : # pylint: disable=too-many-instance-attributes
233
223
"""Wrap an MFMFloppy object into a block device suitable for `storage.VfsFat`
234
224
235
225
The default heads/sectors/tracks setting are for 3.5", 1.44MB floppies.
@@ -243,37 +233,53 @@ class FloppyBlockDevice:
243
233
import storage
244
234
import adafruit_floppy
245
235
246
- floppy = adafruit_floppy.MFMFloppy (...)
236
+ floppy = adafruit_floppy.Floppy (...)
247
237
block_device = adafruit_floppy.FloppyBlockDevice(floppy)
248
238
vfs = storage.VfsFat(f)
249
239
storage.mount(vfs, '/floppy')
250
240
print(os.listdir("/floppy"))
251
241
"""
252
242
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
+ ):
254
252
self .floppy = floppy
255
253
self .heads = heads
256
254
self .sectors = sectors
257
255
self .tracks = tracks
256
+ self .flux_buffer = flux_buffer or bytearray (sectors * 12 * 512 )
258
257
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 )
259
261
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 )
263
266
264
- self .track_cache = memoryview (bytearray (sectors * 512 ))
265
267
self .cached_track = - 1
266
268
self .cached_side = - 1
267
269
268
270
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
270
276
271
277
def sync (self ):
272
278
"""Write out any pending data to disk (does nothing)"""
273
279
274
280
def writeblocks (self , start , buf ): # pylint: disable=no-self-use
275
281
"""Write to the floppy (always raises an exception)"""
276
- raise IOError ("Read-only filesystem" )
282
+ raise OSError ("Read-only filesystem" )
277
283
278
284
def count (self ):
279
285
"""Return the floppy capacity in 512-byte units"""
@@ -287,27 +293,45 @@ def readblocks(self, start_block, buf):
287
293
288
294
def _readblock (self , block , buf ):
289
295
if block > self .count ():
290
- raise IOError ("Read past end of media" )
296
+ raise OSError ("Read past end of media" )
291
297
track = block // (self .heads * self .sectors )
292
298
block %= self .heads * self .sectors
293
299
side = block // (self .sectors )
294
300
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 } " )
296
304
buf [:] = trackdata [block * 512 : (block + 1 ) * 512 ]
297
305
298
306
def _get_track_data (self , track , side ):
299
307
if track == 0 and side == 0 :
300
- return self .track0side0_cache
308
+ return self .track0side0_cache , self . track0side0_validity
301
309
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 ,
308
335
)
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
0 commit comments