mirror of
https://github.com/keirf/greaseweazle-firmware.git
synced 2025-10-31 11:06:44 -07:00
New --format specifier for IBM tracks ibm.720 and ibm.1440
This commit is contained in:
@@ -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
scripts/greaseweazle/codec/formats.py
Normal file
48
scripts/greaseweazle/codec/formats.py
Normal file
@@ -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
|
||||
@@ -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:
|
||||
|
||||
@@ -156,7 +156,6 @@ class EDSKTrack:
|
||||
class EDSK(Image):
|
||||
|
||||
read_only = True
|
||||
default_format = 'ibm.mfm'
|
||||
|
||||
def __init__(self):
|
||||
self.to_track = dict()
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -9,37 +9,44 @@ from greaseweazle import error
|
||||
from greaseweazle.codec.ibm import mfm
|
||||
from .image import Image
|
||||
|
||||
import greaseweazle.codec.formats
|
||||
|
||||
class IMG(Image):
|
||||
|
||||
default_format = 'ibm.mfm'
|
||||
|
||||
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
|
||||
|
||||
@@ -41,7 +41,7 @@ class KryoFlux(Image):
|
||||
|
||||
|
||||
@classmethod
|
||||
def to_file(cls, name):
|
||||
def to_file(cls, name, fmt=None):
|
||||
return cls(name)
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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__":
|
||||
|
||||
Reference in New Issue
Block a user