@@ -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,7 @@ 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 (f "Drive lost position (target= { track } , track0 sensor { drive_says_track0 } ) " )
135
141
136
142
@property
137
143
def track (self ) -> typing .Optional [int ]:
@@ -150,7 +156,7 @@ def track(self, track: int) -> None:
150
156
delta = track - self .track
151
157
if delta < 0 :
152
158
self ._do_step (_STEP_OUT , - delta )
153
- else :
159
+ elif delta > 0 :
154
160
self ._do_step (_STEP_IN , delta )
155
161
156
162
self ._track = track
@@ -210,24 +216,6 @@ def flux_readinto(self, buf: "circuitpython_typing.WritableBuffer") -> int:
210
216
:return: The actual number of bytes of read"""
211
217
return floppyio .flux_readinto (buf , self ._rddata , self ._index )
212
218
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
-
231
219
232
220
class FloppyBlockDevice :
233
221
"""Wrap an MFMFloppy object into a block device suitable for `storage.VfsFat`
@@ -243,37 +231,46 @@ class FloppyBlockDevice:
243
231
import storage
244
232
import adafruit_floppy
245
233
246
- floppy = adafruit_floppy.MFMFloppy (...)
234
+ floppy = adafruit_floppy.Floppy (...)
247
235
block_device = adafruit_floppy.FloppyBlockDevice(floppy)
248
236
vfs = storage.VfsFat(f)
249
237
storage.mount(vfs, '/floppy')
250
238
print(os.listdir("/floppy"))
251
239
"""
252
240
253
- def __init__ (self , floppy , heads = 2 , sectors = 18 , tracks = 80 ):
241
+ def __init__ (self , floppy , heads = 2 , sectors = 18 , tracks = 80 , flux_buffer = None , t1_nom_ns : float = 1000 ):
254
242
self .floppy = floppy
255
243
self .heads = heads
256
244
self .sectors = sectors
257
245
self .tracks = tracks
246
+ self .flux_buffer = flux_buffer or buffer (sectors * 12 * 512 )
258
247
self .track0side0_cache = memoryview (bytearray (sectors * 512 ))
248
+ self .track0side0_validity = bytearray (sectors )
249
+ self .track_cache = memoryview (bytearray (sectors * 512 ))
250
+ self .track_validity = bytearray (sectors )
259
251
260
- self .floppy .track = 0
261
- self .floppy .head = 0
262
- floppyio .mfm_readinto (self .track0side0_cache , floppy ._rddata , floppy ._index )
252
+ self ._t2_5_max = round (2.5 * t1_nom_ns * floppyio .samplerate * 1e-9 )
253
+ self ._t3_5_max = round (3.5 * t1_nom_ns * floppyio .samplerate * 1e-9 )
254
+
255
+ self ._track_read (self .track0side0_cache , self .track0side0_validity , 0 , 0 )
263
256
264
- self .track_cache = memoryview (bytearray (sectors * 512 ))
265
257
self .cached_track = - 1
266
258
self .cached_side = - 1
267
259
260
+
268
261
def deinit (self ):
269
- """Deinitialize this object (does nothing)"""
262
+ """Deinitialize this object"""
263
+ self .floppy .deinit ()
264
+ del self .flux_buffer
265
+ del self .track0side0_cache
266
+ del self .track_validity
270
267
271
268
def sync (self ):
272
269
"""Write out any pending data to disk (does nothing)"""
273
270
274
271
def writeblocks (self , start , buf ): # pylint: disable=no-self-use
275
272
"""Write to the floppy (always raises an exception)"""
276
- raise IOError ("Read-only filesystem" )
273
+ raise OSError ("Read-only filesystem" )
277
274
278
275
def count (self ):
279
276
"""Return the floppy capacity in 512-byte units"""
@@ -287,27 +284,37 @@ def readblocks(self, start_block, buf):
287
284
288
285
def _readblock (self , block , buf ):
289
286
if block > self .count ():
290
- raise IOError ("Read past end of media" )
287
+ raise OSError ("Read past end of media" )
291
288
track = block // (self .heads * self .sectors )
292
289
block %= self .heads * self .sectors
293
290
side = block // (self .sectors )
294
291
block %= self .sectors
295
- trackdata = self ._get_track_data (track , side )
292
+ trackdata , validity = self ._get_track_data (track , side )
293
+ if not validity [block ]:
294
+ raise OSError (f"Failed to read sector { track } /{ side } /{ block } " )
296
295
buf [:] = trackdata [block * 512 : (block + 1 ) * 512 ]
297
296
298
297
def _get_track_data (self , track , side ):
299
298
if track == 0 and side == 0 :
300
- return self .track0side0_cache
299
+ return self .track0side0_cache , self . track0side0_validity
301
300
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 ,
308
- )
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
301
+ self ._track_read (self .track_cache , self .track_validity , track , side )
302
+ return self .track_cache , self .track_validity
303
+
304
+ def _track_read (self , track_data , validity , track , side ):
305
+ self .floppy .selected = True
306
+ self .floppy .spin = True
307
+ self .floppy .track = track
308
+ self .floppy .side = side
309
+ self ._mfm_readinto (track_data , validity )
310
+ self .floppy .spin = False
311
+ self .floppy .selected = False
312
+ self .cached_track = track
313
+ self .cached_side = side
314
+
315
+ def _mfm_readinto (self , track_data , validity ):
316
+ for i in range (5 ):
317
+ self .floppy .flux_readinto (self .flux_buffer )
318
+ print ("timing bins" , self ._t2_5_max , self ._t3_5_max )
319
+ n = floppyio .mfm_readinto (track_data , self .flux_buffer , self ._t2_5_max , self ._t3_5_max , validity , i == 0 )
320
+ if n == self .sectors : break
0 commit comments