@@ -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
0 commit comments