Kaynağa Gözat

New --format specifier for IBM tracks ibm.720 and ibm.1440

Keir Fraser 3 yıl önce
ebeveyn
işleme
7b8bf48702

+ 0 - 1
scripts/greaseweazle/codec/amiga/amigados.py

@@ -11,7 +11,6 @@ from bitarray import bitarray
 
 from greaseweazle.track import MasterTrack, RawTrack
 
-default_trackset = 'c=0-79:h=0-1'
 default_revs = 1.1
 
 sync_bytes = b'\x44\x89\x44\x89'

+ 48 - 0
scripts/greaseweazle/codec/formats.py

@@ -0,0 +1,48 @@
+
+from greaseweazle.tools import util
+
+class Format:
+    img_compatible = False
+    default_trackset = 'c=0-79:h=0-1'
+    def __init__(self):
+        self.tracks = util.TrackSet(self.default_trackset)
+
+class Format_Amiga_AmigaDOS(Format):
+    def __init__(self):
+        import greaseweazle.codec.amiga.amigados as m
+        self.fmt = m.AmigaDOS
+        self.default_revs = m.default_revs
+        self.decode_track = m.decode_track
+        super().__init__()
+    
+class Format_IBM_720(Format):
+    img_compatible = True
+    def __init__(self):
+        import greaseweazle.codec.ibm.mfm as m
+        self.fmt = m.IBM_MFM_720
+        self.default_revs = m.default_revs
+        self.decode_track = self.fmt.decode_track
+        super().__init__()
+    
+class Format_IBM_1440(Format):
+    img_compatible = True
+    def __init__(self):
+        import greaseweazle.codec.ibm.mfm as m
+        self.fmt = m.IBM_MFM_1M44
+        self.default_revs = m.default_revs
+        self.decode_track = self.fmt.decode_track
+        super().__init__()
+
+    
+formats = {
+    'amiga.amigados': Format_Amiga_AmigaDOS,
+    'ibm.720': Format_IBM_720,
+    'ibm.1440': Format_IBM_1440
+}
+
+def print_formats(f = None):
+    s = ''
+    for k, v in sorted(formats.items()):
+        if not f or f(k, v):
+            s += k if not s else ', ' + k
+    return s

+ 27 - 11
scripts/greaseweazle/codec/ibm/mfm.py

@@ -5,14 +5,13 @@
 # This is free and unencumbered software released into the public domain.
 # See the file COPYING for more details, or visit <http://unlicense.org>.
 
-import copy, heapq, struct
+import copy, heapq, struct, functools
 import itertools as it
 from bitarray import bitarray
 import crcmod.predefined
 
 from greaseweazle.track import MasterTrack, RawTrack
 
-default_trackset = 'c=0-79:h=0-1'
 default_revs = 2
 
 iam_sync_bytes = b'\x52\x24' * 3
@@ -113,8 +112,6 @@ class IBM_MFM:
 
     def __init__(self, cyl, head):
         self.cyl, self.head = cyl, head
-        self.time_per_rev = 0.2
-        self.clock = 1e-6
         self.sectors = []
         self.iams = []
 
@@ -177,7 +174,7 @@ class IBM_MFM:
                     areas.append(Sector(idam, dam))
                 idam = None
             else:
-                print("Unknown mark %02x" % mark)
+                pass #print("Unknown mark %02x" % mark)
 
         if idam is not None:
             areas.append(idam)
@@ -289,12 +286,17 @@ class IBM_MFM_Formatted(IBM_MFM):
     def set_img_track(self, tdat):
         pos = 0
         self.sectors.sort(key = lambda x: x.idam.r)
+        totsize = functools.reduce(lambda x, y: x + (128<<y.idam.n),
+                                   self.sectors, 0)
+        if len(tdat) < totsize:
+            tdat += bytes(totsize - len(tdat))
         for s in self.sectors:
             s.crc = s.idam.crc = s.dam.crc = 0
             size = 128 << s.idam.n
             s.dam.data = tdat[pos:pos+size]
             pos += size
         self.sectors.sort(key = lambda x: x.start)
+        return totsize
 
     def get_img_track(self):
         tdat = bytearray()
@@ -342,15 +344,35 @@ class IBM_MFM_Predefined(IBM_MFM_Formatted):
             self.sectors.append(Sector(idam, dam))
             pos += 4 + size + 2 + self.gap_3
 
+    @classmethod
+    def decode_track(cls, cyl, head, track):
+        mfm = cls(cyl, head)
+        mfm.decode_raw(track)
+        return mfm
+
 
 class IBM_MFM_1M44(IBM_MFM_Predefined):
 
+    time_per_rev = 0.2
+    clock = 1e-6
+    
     gap_3  = 84 # Post-DAM
     nsec   = 18
     id0    = 1
     sz     = 2
 
 
+class IBM_MFM_720(IBM_MFM_Predefined):
+
+    time_per_rev = 0.2
+    clock = 2e-6
+    
+    gap_3  = 84 # Post-DAM
+    nsec   = 9
+    id0    = 1
+    sz     = 2
+
+
 def mfm_encode(dat):
     y = 0
     out = bytearray()
@@ -391,12 +413,6 @@ def decode(dat):
     return bytes(out)
 
 
-def decode_track(cyl, head, track):
-    mfm = IBM_MFM_1M44(cyl, head)
-    mfm.decode_raw(track)
-    return mfm
-
-
 # Local variables:
 # python-indent: 4
 # End:

+ 0 - 1
scripts/greaseweazle/image/edsk.py

@@ -156,7 +156,6 @@ class EDSKTrack:
 class EDSK(Image):
 
     read_only = True
-    default_format = 'ibm.mfm'
 
     def __init__(self):
         self.to_track = dict()

+ 2 - 1
scripts/greaseweazle/image/image.py

@@ -33,11 +33,12 @@ class Image:
 
     ## Default .to_file() constructor
     @classmethod
-    def to_file(cls, name):
+    def to_file(cls, name, fmt=None):
         error.check(not cls.read_only,
                     "%s: Cannot create %s image files" % (name, cls.__name__))
         obj = cls()
         obj.filename = name
+        obj.fmt = fmt
         return obj
 
     ## Above methods and class variables can be overridden by subclasses.

+ 22 - 15
scripts/greaseweazle/image/img.py

@@ -9,37 +9,44 @@ from greaseweazle import error
 from greaseweazle.codec.ibm import mfm
 from .image import Image
 
-class IMG(Image):
+import greaseweazle.codec.formats
 
-    default_format = 'ibm.mfm'
+class IMG(Image):
 
-    def __init__(self):
+    def __init__(self, name, fmt):
         self.to_track = dict()
+        error.check(fmt is not None and fmt.img_compatible, """\
+IMG requires compatible format specifier, eg: --format=ibm.1440
+Compatible formats: %s"""
+                    % greaseweazle.codec.formats.print_formats(
+                        lambda k, v: v.img_compatible))
+        self.filename = name
+        self.fmt = fmt
 
 
     @classmethod
-    def from_file(cls, name):
+    def from_file(cls, name, fmt):
 
         with open(name, "rb") as f:
             dat = f.read()
 
-        img = cls()
-
-        nsec = 18
-        tsz = nsec * 512
-        ncyl = len(dat) // (tsz*2)
+        img = cls(name, fmt)
 
         pos = 0
-        for cyl in range(ncyl):
-            for head in range(2):
-                track = mfm.IBM_MFM_1M44(cyl, head)
-                track.set_img_track(dat[pos:pos+tsz])
-                pos += tsz
-                img.to_track[cyl,head] = track
+        for t in fmt.tracks:
+            cyl, head = t.cyl, t.head
+            track = fmt.fmt(cyl, head)
+            pos += track.set_img_track(dat[pos:])
+            img.to_track[cyl,head] = track
 
         return img
 
 
+    @classmethod
+    def to_file(cls, name, fmt=None):
+        return cls(name, fmt)
+
+
     def get_track(self, cyl, side):
         if (cyl,side) not in self.to_track:
             return None

+ 1 - 1
scripts/greaseweazle/image/kryoflux.py

@@ -41,7 +41,7 @@ class KryoFlux(Image):
 
 
     @classmethod
-    def to_file(cls, name):
+    def to_file(cls, name, fmt=None):
         return cls(name)
 
     @classmethod

+ 12 - 9
scripts/greaseweazle/tools/read.py

@@ -16,10 +16,11 @@ from greaseweazle.tools import util
 from greaseweazle import error
 from greaseweazle import usb as USB
 from greaseweazle.flux import Flux
+from greaseweazle.codec import formats
 
 
 def open_image(args, image_class):
-    image = image_class.to_file(args.file)
+    image = image_class.to_file(args.file, args.fmt_cls)
     if args.rate is not None:
         image.bitrate = args.rate
     for opt, val in args.file_opts.items():
@@ -137,16 +138,18 @@ def main(argv):
         image_class = util.get_image_class(args.file)
         if not args.format and hasattr(image_class, 'default_format'):
             args.format = image_class.default_format
-        decoder, def_tracks = None, None
+        decoder, def_tracks, args.fmt_cls = None, None, None
         if args.format:
             try:
-                mod = importlib.import_module('greaseweazle.codec.'
-                                              + args.format)
-                decoder = mod.decode_track
-            except (ModuleNotFoundError, AttributeError) as ex:
-                raise error.Fatal("Unknown format '%s'" % args.format) from ex
-            def_tracks = util.TrackSet(mod.default_trackset)
-            if args.revs is None: args.revs = mod.default_revs
+                args.fmt_cls = formats.formats[args.format]()
+            except KeyError as ex:
+                raise error.Fatal("""\
+Unknown format '%s'
+Known formats: %s"""
+                                  % (args.format, formats.print_formats()))
+            decoder = args.fmt_cls.decode_track
+            def_tracks = util.TrackSet(args.fmt_cls.default_trackset)
+            if args.revs is None: args.revs = args.fmt_cls.default_revs
         if def_tracks is None:
             def_tracks = util.TrackSet('c=0-81:h=0-1')
         if args.revs is None: args.revs = 3

+ 24 - 7
scripts/greaseweazle/tools/write.py

@@ -14,11 +14,16 @@ import sys
 from greaseweazle.tools import util
 from greaseweazle import error, track
 from greaseweazle import usb as USB
+from greaseweazle.codec import formats
 
 # Read and parse the image file.
 def open_image(args):
     cls = util.get_image_class(args.file)
-    return cls.from_file(args.file)
+    try:
+        image = cls.from_file(args.file)
+    except TypeError:
+        image = cls.from_file(args.file, args.fmt_cls)
+    return image
 
 # write_from_image:
 # Writes the specified image file to floppy disk.
@@ -147,6 +152,7 @@ def main(argv):
     parser.add_argument("--device", help="greaseweazle device name")
     parser.add_argument("--drive", type=util.drive_letter, default='A',
                         help="drive to write (A,B,0,1,2)")
+    parser.add_argument("--format", help="disk format")
     parser.add_argument("--tracks", type=util.TrackSet,
                         help="which tracks to write")
     parser.add_argument("--erase-empty", action="store_true",
@@ -163,19 +169,30 @@ def main(argv):
     args = parser.parse_args(argv[2:])
 
     try:
+        def_tracks, args.fmt_cls = None, None
+        if args.format:
+            try:
+                args.fmt_cls = formats.formats[args.format]()
+            except KeyError as ex:
+                raise error.Fatal("""\
+Unknown format '%s'
+Known formats: %s"""
+                                  % (args.format, formats.print_formats()))
+            def_tracks = util.TrackSet(args.fmt_cls.default_trackset)
+        if def_tracks is None:
+            def_tracks = util.TrackSet('c=0-81:h=0-1')
+        if args.tracks is not None:
+            def_tracks.update_from_trackspec(args.tracks.trackspec)
+        args.tracks = def_tracks
         usb = util.usb_open(args.device)
         image = open_image(args)
-        tracks = util.TrackSet('c=0-81:h=0-1')
-        if args.tracks is not None:
-            tracks.update_from_trackspec(args.tracks.trackspec)
-        args.tracks = tracks
         s = str(args.tracks)
         if args.precomp is not None:
             s += "; %s" % args.precomp
         print("Writing %s" % s)
         util.with_drive_selected(write_from_image, usb, args, image)
-    except USB.CmdError as error:
-        print("Command Failed: %s" % error)
+    except USB.CmdError as err:
+        print("Command Failed: %s" % err)
 
 
 if __name__ == "__main__":