Ejemplo n.º 1
0
    def from_file(cls, dat):

        (sig, f_rev, nr_cyls, nr_sides, t_enc, bitrate, _, _, _,
         tlut_base) = struct.unpack("<8s4B2H2BH", dat[:20])
        error.check(sig != b"HXCHFEV3", "HFEv3 is not supported")
        error.check(sig == b"HXCPICFE" and f_rev <= 1, "Not a valid HFE file")
        error.check(0 < nr_cyls, "HFE: Invalid #cyls")
        error.check(0 < nr_sides < 3, "HFE: Invalid #sides")
        error.check(bitrate != 0, "HFE: Invalid bitrate")

        hfe = cls(0, nr_sides)
        hfe.bitrate = bitrate

        tlut = dat[tlut_base * 512:tlut_base * 512 + nr_cyls * 4]

        for cyl in range(nr_cyls):
            for side in range(nr_sides):
                offset, length = struct.unpack("<2H",
                                               tlut[cyl * 4:(cyl + 1) * 4])
                todo = length // 2
                tdat = bytes()
                while todo:
                    d_off = offset * 512 + side * 256
                    d_nr = 256 if todo > 256 else todo
                    tdat += dat[d_off:d_off + d_nr]
                    todo -= d_nr
                    offset += 1
                hfe.track_list.append((len(tdat) * 8, tdat))

        return hfe
Ejemplo n.º 2
0
    def from_file(cls, name):

        with open(name, "rb") as f:
            dat = f.read()

        (sig, f_rev, n_cyl, n_side, t_enc, bitrate, _, _, _,
         tlut_base) = struct.unpack("<8s4B2H2BH", dat[:20])
        error.check(sig != b"HXCHFEV3", "HFEv3 is not supported")
        error.check(sig == b"HXCPICFE" and f_rev <= 1, "Not a valid HFE file")
        error.check(0 < n_cyl, "HFE: Invalid #cyls")
        error.check(0 < n_side < 3, "HFE: Invalid #sides")
        error.check(bitrate != 0, "HFE: Invalid bitrate")

        hfe = cls()
        hfe.bitrate = bitrate

        tlut = dat[tlut_base * 512:tlut_base * 512 + n_cyl * 4]

        for cyl in range(n_cyl):
            for side in range(n_side):
                offset, length = struct.unpack("<2H",
                                               tlut[cyl * 4:(cyl + 1) * 4])
                todo = length // 2
                tdat = bytes()
                while todo:
                    d_off = offset * 512 + side * 256
                    d_nr = 256 if todo > 256 else todo
                    tdat += dat[d_off:d_off + d_nr]
                    todo -= d_nr
                    offset += 1
                hfe.to_track[cyl, side] = (len(tdat) * 8, tdat)

        return hfe
Ejemplo n.º 3
0
 def _send_cmd(self, cmd):
     self.ser.write(cmd)
     (c,r) = struct.unpack("2B", self.ser.read(2))
     error.check(c == cmd[0], "Command returned garbage (%02x != %02x)"
                 % (c, cmd[0]))
     if r != 0:
         raise CmdError(c, r)
Ejemplo n.º 4
0
    def flux_for_writeout(self):

        error.check(self.splice == 0 or len(self.index_list) > 1,
                    "Cannot write single-revolution unaligned raw flux")
        splice_at_index = (self.splice == 0)

        # Copy the required amount of flux to a fresh list.
        flux_list = []
        to_index = self.index_list[0]
        remain = to_index + self.splice
        for f in self.list:
            if f > remain:
                break
            flux_list.append(f)
            remain -= f

        if splice_at_index:
            # Extend with "safe" 4us sample values, to avoid unformatted area
            # at end of track if drive motor is a little slow.
            four_us = max(self.sample_freq * 4e-6, 1)
            if remain > four_us:
                flux_list.append(remain)
            for i in range(round(to_index / (10 * four_us))):
                flux_list.append(four_us)
        elif remain > 0:
            # End the write exactly where specified.
            flux_list.append(remain)

        return WriteoutFlux(to_index,
                            flux_list,
                            self.sample_freq,
                            index_cued=True,
                            terminate_at_index=(self.splice == 0))
Ejemplo n.º 5
0
    def get_track(self, cyl, head, writeout=False):
        pi = self.pi
        if head < pi.minhead or head > pi.maxhead:
            return None
        if cyl < pi.mincylinder or cyl > pi.maxcylinder:
            return None

        ti = CapsTrackInfoT2(2)
        res = self.lib.CAPSLockTrack(ct.byref(ti), self.iid, cyl, head,
                                     DI_LOCK.def_flags)
        error.check(res == 0, "Could not lock IPF track %d.%d" % (cyl, head))

        if not ti.trackbuf:
            return None  # unformatted/empty
        carray_type = ct.c_ubyte * ((ti.tracklen + 7) // 8)
        carray = carray_type.from_address(ct.addressof(ti.trackbuf.contents))
        trackbuf = bitarray(endian='big')
        trackbuf.frombytes(bytes(carray))
        trackbuf = trackbuf[:ti.tracklen]

        #for i in range(ti.sectorcnt):
        #    si = CapsSectorInfo()
        #    res = self.lib.CAPSGetInfo(ct.byref(si), self.iid,
        #                               cyl, head, 1, i)
        #    error.check(res == 0, "Couldn't get sector info")
        #    range.append((si.datastart, si.datasize))

        weak = []
        for i in range(ti.weakcnt):
            wi = CapsDataInfo()
            res = self.lib.CAPSGetInfo(ct.byref(wi), self.iid, cyl, head, 2, i)
            error.check(res == 0, "Couldn't get weak data info")
            weak.append((wi.start, wi.size))

        timebuf = None
        if ti.timebuf:
            carray_type = ct.c_uint * ti.timelen
            carray = carray_type.from_address(ct.addressof(
                ti.timebuf.contents))
            # Unpack the per-byte timing info into per-bitcell
            timebuf = []
            for i in carray:
                for j in range(8):
                    timebuf.append(i)
            # Pad the timing info with normal cell lengths as necessary
            for j in range(len(carray) * 8, ti.tracklen):
                timebuf.append(1000)
            # Clip the timing info, if necessary.
            timebuf = timebuf[:ti.tracklen]

        # We don't really have access to the bitrate. It depends on RPM.
        # So we assume a rotation rate of 300 RPM (5 rev/sec).
        rpm = 300

        track = MasterTrack(bits=trackbuf,
                            time_per_rev=60 / rpm,
                            bit_ticks=timebuf,
                            splice=ti.overlap,
                            weak=weak)
        return track
Ejemplo n.º 6
0
 def __init__(self, name):
     m = re.search("\d{2}.[01].raw$", name, flags=re.IGNORECASE)
     error.check(
         m is not None, '''\
         Bad Kryoflux image name pattern '%s'
         Name pattern must be path/to/nameNN.N.raw (N is a digit)''' % name)
     self.basename = name[:m.start()]
Ejemplo n.º 7
0
    def from_file(cls, name, fmt):

        if fmt is not None and fmt.img_compatible:  # Acorn ADF
            return IMG.from_file(name, fmt)

        with open(name, "rb") as f:
            dat = f.read()

        adf = cls(name, fmt)

        while True:
            nsec = fmt.fmt.nsec
            error.check((len(dat) % (2 * nsec * 512)) == 0,
                        "Bad ADF image length")
            ncyl = len(dat) // (2 * nsec * 512)
            if ncyl < 90:
                break
            error.check(nsec == 11, "Bad ADF image length")
            fmt = adf.fmt = formats.Format_Amiga_AmigaDOS_HD()

        pos = 0
        for t in fmt.max_tracks:
            tnr = t.cyl * 2 + t.head
            ados = fmt.fmt(t.cyl, t.head)
            pos += ados.set_adf_track(dat[pos:])
            adf.to_track[tnr] = ados

        return adf
Ejemplo n.º 8
0
def open_image(args):
    image_class = util.get_image_class(args.file)
    error.check(hasattr(image_class, 'to_file'),
                "%s: Cannot create %s image files"
                % (args.file, image_class.__name__))
    image = image_class.to_file(args.scyl, args.nr_sides)
    return image
Ejemplo n.º 9
0
    def get_image(self):

        # Work out the single-sided byte code
        s = self.side_count()
        if s[0] and s[1]:
            single_sided = 0
        elif s[0]:
            single_sided = 1
        else:
            single_sided = 2

        to_track = self.to_track
        if single_sided and self.opts.legacy_ss:
            print('SCP: Generated legacy single-sided image')
            to_track = dict()
            for tnr in self.to_track:
                to_track[tnr//2] = self.to_track[tnr]

        ntracks = max(to_track, default=0) + 1

        # Generate the TLUT and concatenate all the tracks together.
        trk_offs = bytearray()
        trk_dat = bytearray()
        for tnr in range(ntracks):
            if tnr in to_track:
                track = to_track[tnr]
                trk_offs += struct.pack("<I", 0x2b0 + len(trk_dat))
                trk_dat += struct.pack("<3sB", b"TRK", tnr)
                trk_dat += track.tdh + track.dat
            else:
                trk_offs += struct.pack("<I", 0)
        error.check(len(trk_offs) <= 0x2a0, "SCP: Too many tracks")
        trk_offs += bytes(0x2a0 - len(trk_offs))

        # Calculate checksum over all data (except 16-byte image header).
        csum = 0
        for x in trk_offs:
            csum += x
        for x in trk_dat:
            csum += x

        # Generate the image header.
        flags = 2 # 96TPI
        if self.index_cued:
            flags |= 1 # Index-Cued
        nr_revs = self.nr_revs if self.nr_revs is not None else 0
        header = struct.pack("<3s9BI",
                             b"SCP",    # Signature
                             0,         # Version
                             self.opts.disktype,
                             nr_revs, 0, ntracks-1,
                             flags,
                             0,         # 16-bit cell width
                             single_sided,
                             0,         # 25ns capture
                             csum & 0xffffffff)

        # Concatenate it all together and send it back.
        return header + trk_offs + trk_dat
Ejemplo n.º 10
0
 def to_file(cls, name, fmt, noclobber):
     error.check(not cls.read_only,
                 "%s: Cannot create %s image files" % (name, cls.__name__))
     obj = cls()
     obj.filename = name
     obj.fmt = fmt
     obj.noclobber = noclobber
     return obj
Ejemplo n.º 11
0
def open_output_image(args, image_class):
    image = image_class.to_file(args.out_file, args.fmt_cls, args.no_clobber)
    for opt, val in args.out_file_opts.items():
        error.check(
            hasattr(image, 'opts') and hasattr(image.opts, opt),
            "%s: Invalid file option: %s" % (args.out_file, opt))
        setattr(image.opts, opt, val)
    return image
Ejemplo n.º 12
0
 def append(self, flux):
     error.check(self.sample_freq == flux.sample_freq,
                 "Cannot append flux with different sample frequency")
     # Any trailing flux is incorporated into the first revolution of
     # the appended flux.
     rev0 = flux.index_list[0] + sum(self.list) - sum(self.index_list)
     self.index_list += [rev0] + flux.index_list[1:]
     self.list += flux.list
Ejemplo n.º 13
0
def usb_open(devicename, is_update=False, mode_check=True):
    def print_update_instructions(usb):
        print("To perform an Update:")
        if not usb.jumperless_update:
            print(" - Disconnect from USB")
            print(" - Install the Update Jumper at pins %s" %
                  ("RXI-TXO" if usb.hw_model != 1 else "DCLK-GND"))
            print(" - Reconnect to USB")
        print(" - Run \"gw update\" to install firmware v%u.%u" %
              (version.major, version.minor))

    if devicename is None:
        devicename = find_port()

    usb = USB.Unit(serial.Serial(devicename))
    usb.port_info = port_info(devicename)
    is_win7 = (platform.system() == 'Windows' and platform.release() == '7')
    usb.jumperless_update = ((usb.hw_model, usb.hw_submodel) != (1, 0)
                             and not is_win7)

    if not mode_check:
        return usb

    if usb.update_mode and not is_update:
        if usb.jumperless_update and not usb.update_jumpered:
            usb = usb_reopen(usb, is_update)
            if not usb.update_mode:
                return usb
        print("ERROR: Greaseweazle is in Firmware Update Mode")
        print(" - The only available action is \"gw update\"")
        if usb.update_jumpered:
            print(" - For normal operation disconnect from USB and remove "
                  "the Update Jumper at pins %s" %
                  ("RXI-TXO" if usb.hw_model != 1 else "DCLK-GND"))
        else:
            print(" - Main firmware is erased: You *must* perform an update!")
        sys.exit(1)

    if is_update and not usb.update_mode:
        if usb.jumperless_update:
            usb = usb_reopen(usb, is_update)
            error.check(
                usb.update_mode, """\
Greaseweazle F7 did not change to Firmware Update Mode as requested.
If the problem persists, install the Update Jumper at pins RXI-TXO.""")
            return usb
        print("ERROR: Greaseweazle is not in Firmware Update Mode")
        print_update_instructions(usb)
        sys.exit(1)

    if not usb.update_mode and usb.update_needed:
        print("ERROR: Greaseweazle firmware v%u.%u is unsupported" %
              (usb.major, usb.minor))
        print_update_instructions(usb)
        sys.exit(1)

    return usb
Ejemplo n.º 14
0
    def __init__(self, name, fmt):
        self.to_track = dict()
        error.check(
            fmt is not None and fmt.img_compatible, """\
Sector image requires compatible format conversion
Compatible formats:\n%s""" %
            formats.print_formats(lambda k, v: v.img_compatible))
        self.filename = name
        self.fmt = fmt
Ejemplo n.º 15
0
def open_image(args, image_class):
    image = image_class.to_file(args.file)
    if args.rate is not None:
        image.bitrate = args.rate
    for opt, val in args.file_opts.items():
        error.check(
            hasattr(image, 'opts') and hasattr(image.opts, opt),
            "%s: Invalid file option: %s" % (args.file, opt))
        setattr(image.opts, opt, val)
    return image
Ejemplo n.º 16
0
def main(argv):

    parser = util.ArgumentParser(allow_abbrev=False,
                                 usage='%(prog)s [options] [file]')
    parser.add_argument("file", nargs="?", help="update filename")
    parser.add_argument("--device", help="device name (COM/serial port)")
    parser.add_argument("--force",
                        action="store_true",
                        help="force update even if firmware is older")
    parser.add_argument("--bootloader",
                        action="store_true",
                        help="update the bootloader (use with caution!)")
    parser.description = description
    parser.prog += ' ' + argv[1]
    args = parser.parse_args(argv[2:])

    if args.file is None:
        args.file, dat = download_latest()
    else:
        with open(args.file, "rb") as f:
            dat = f.read()

    try:
        usb = util.usb_open(args.device, mode_check=False)
        dat_version, dat = extract_update(usb, dat, args)
        print("Updating %s to v%u.%u..." %
              ("Bootloader" if args.bootloader else "Main Firmware",
               *dat_version))
        if not args.force and (usb.can_mode_switch
                               or args.bootloader == usb.update_mode):
            if args.bootloader != usb.update_mode:
                usb = util.usb_reopen(usb, is_update=args.bootloader)
                error.check(args.bootloader == usb.update_mode,
                            'Device did not mode switch as requested')
            if usb.version >= dat_version:
                if usb.update_mode and usb.can_mode_switch:
                    usb = util.usb_reopen(usb, is_update=False)
                raise error.Fatal('Device is running v%d.%d (>= v%d.%d). '
                                  'Use --force to update anyway.' %
                                  (usb.version + dat_version))
        usb = util.usb_mode_check(usb, is_update=not args.bootloader)
        update_firmware(usb, dat, args)
        if usb.update_mode and usb.can_mode_switch:
            util.usb_reopen(usb, is_update=False)
    except USB.CmdError as err:
        if err.code == USB.Ack.OutOfSRAM and args.bootloader:
            # Special warning for Low-Density F1 devices. The new bootloader
            # cannot be fully buffered in the limited RAM available.
            print("ERROR: Bootloader update unsupported on this device "
                  "(insufficient SRAM)")
        elif err.code == USB.Ack.OutOfFlash and not args.bootloader:
            print("ERROR: New firmware is too large for this device "
                  "(insufficient Flash memory)")
        else:
            print("Command Failed: %s" % err)
Ejemplo n.º 17
0
def get_image_class(name):
    _, ext = os.path.splitext(name)
    error.check(
        ext.lower() in image_types, """\
                %s: Unrecognised file suffix '%s'
                Known suffixes: %s""" % (name, ext, ', '.join(image_types)))
    typespec = image_types[ext.lower()]
    if isinstance(typespec, tuple):
        typename, classname = typespec
    else:
        typename, classname = typespec, typespec.lower()
    mod = importlib.import_module('greaseweazle.image.' + classname)
    return mod.__dict__[typename]
Ejemplo n.º 18
0
def open_image(args, image_class):
    error.check(
        hasattr(image_class, 'to_file'),
        "%s: Cannot create %s image files" % (args.file, image_class.__name__))
    image = image_class.to_file(args.scyl, args.nr_sides)
    if args.rate is not None:
        image.bitrate = args.rate
    for opt, val in args.file_opts.items():
        error.check(
            hasattr(image, 'opts') and hasattr(image.opts, opt),
            "%s: Invalid file option: %s" % (args.file, opt))
        setattr(image.opts, opt, val)
    return image
Ejemplo n.º 19
0
def usb_open(devicename, is_update=False, mode_check=True):

    if devicename is None:
        devicename = find_port()

    usb = USB.Unit(serial.Serial(devicename))
    usb.port_info = port_info(devicename)

    if not mode_check:
        return usb

    print("** %s v%u.%u [F%u], Host Tools v%u.%u" %
          (("Greaseweazle", "Bootloader")[usb.update_mode], usb.major,
           usb.minor, usb.hw_model, version.major, version.minor))

    if usb.update_mode and not is_update:
        if usb.hw_model == 7 and not usb.update_jumpered:
            usb = usb_reopen(usb, is_update)
            if not usb.update_mode:
                return usb
        print("Greaseweazle is in Firmware Update Mode:")
        print(" The only available action is \"update\" of main firmware")
        if usb.update_jumpered:
            print(" Remove the Update Jumper for normal operation")
        else:
            print(" Main firmware is erased: You *must* perform an update!")
        sys.exit(1)

    if is_update and not usb.update_mode:
        if usb.hw_model == 7:
            usb = usb_reopen(usb, is_update)
            error.check(
                usb.update_mode, """\
Greaseweazle F7 did not change to Firmware Update Mode as requested.
If the problem persists, install the Update Jumper (across RX/TX).""")
            return usb
        print("Greaseweazle is in Normal Mode:")
        print(" To \"update\" you must install the Update Jumper")
        sys.exit(1)

    if not usb.update_mode and usb.update_needed:
        print("Firmware is out of date: Require v%u.%u" %
              (version.major, version.minor))
        if usb.hw_model == 7:
            print("Run \"update <update_file>\"")
        else:
            print("Install the Update Jumper and \"update <update_file>\"")
        sys.exit(1)

    return usb
Ejemplo n.º 20
0
 def emit_track(self, cyl, side, track):
     if self.opts.bitrate is None:
         t = track.raw_track() if hasattr(track, 'raw_track') else track
         b = getattr(t, 'bitrate', None)
         error.check(
             hasattr(t, 'bitrate'), 'HFE: Requires bitrate to be specified'
             ' (eg. filename.hfe::bitrate=500)')
         self.opts.bitrate = round(t.bitrate / 2e3)
         print('HFE: Data bitrate detected: %d kbit/s' % self.opts.bitrate)
     flux = track.flux()
     flux.cue_at_index()
     raw = RawTrack(clock=5e-4 / self.opts.bitrate, data=flux)
     bits, _ = raw.get_revolution(0)
     bits.bytereverse()
     self.to_track[cyl, side] = (len(bits), bits.tobytes())
Ejemplo n.º 21
0
def get_image_class(name):
    image_types = {
        '.adf': 'ADF',
        '.scp': 'SCP',
        '.hfe': 'HFE',
        '.ipf': 'IPF',
        '.raw': 'KryoFlux'
    }
    if os.path.isdir(name):
        typename = 'KryoFlux'
    else:
        _, ext = os.path.splitext(name)
        error.check(ext.lower() in image_types,
                    "%s: Unrecognised file suffix '%s'" % (name, ext))
        typename = image_types[ext.lower()]
    mod = importlib.import_module('greaseweazle.image.' + typename.lower())
    return mod.__dict__[typename]
Ejemplo n.º 22
0
    def flux_for_writeout(self, cue_at_index=True):

        error.check(self.index_cued,
                    "Cannot write non-index-cued raw flux")
        error.check(self.splice == 0 or len(self.index_list) > 1,
                    "Cannot write single-revolution unaligned raw flux")
        splice_at_index = (self.splice == 0)

        # Copy the required amount of flux to a fresh list.
        flux_list = []
        to_index = self.index_list[0]
        remain = to_index + self.splice
        for f in self.list:
            if f > remain:
                break
            flux_list.append(f)
            remain -= f

        if not cue_at_index:
            # We will write more than one revolutionm and terminate the
            # second revolution at the splice. Extend the start of the write
            # with "safe" 4us sample values, in case the drive motor is a
            # little fast.
            if remain > 0:
                flux_list.append(remain)
            prepend = max(round(to_index/10 - self.splice), 0)
            if prepend != 0:
                four_us = max(self.sample_freq * 4e-6, 1)
                flux_list = [four_us]*round(prepend/four_us) + flux_list
            splice_at_index = False
        elif splice_at_index:
            # Extend with "safe" 4us sample values, to avoid unformatted area
            # at end of track if drive motor is a little slow.
            four_us = max(self.sample_freq * 4e-6, 1)
            if remain > four_us:
                flux_list.append(remain)
            for i in range(round(to_index/(10*four_us))):
                flux_list.append(four_us)
        elif remain > 0:
            # End the write exactly where specified.
            flux_list.append(remain)

        return WriteoutFlux(to_index, flux_list, self.sample_freq,
                            index_cued = cue_at_index,
                            terminate_at_index = splice_at_index)
Ejemplo n.º 23
0
def open_libcaps():

    # Get the OS-dependent list of valid CAPS library names.
    _names = []
    if platform.system() == "Linux":
        _names = [
            "libcapsimage.so.5", "libcapsimage.so.5.1", "libcapsimage.so.4",
            "libcapsimage.so.4.2", "libcapsimage.so"
        ]
    elif platform.system() == "Darwin":
        _names = ["CAPSImage.framework/CAPSImage"]
    elif platform.system() == "Windows":
        _names = ["CAPSImg_x64.dll", "CAPSImg.dll"]

    # Get the absolute path to the root Greaseweazle folder.
    path = os.path.dirname(os.path.abspath(__file__))
    for _ in range(3):
        path = os.path.join(path, os.pardir)
    path = os.path.normpath(path)

    # Create a search list of both relative and absolute library names.
    names = []
    for name in _names:
        names.append(name)
        names.append(os.path.join(path, name))

    # Walk the search list, trying to open the CAPS library.
    for name in names:
        try:
            lib = ct.cdll.LoadLibrary(name)
            break
        except:
            pass

    error.check(
        "lib" in locals(), """\
Could not find SPS/CAPS IPF decode library
For installation instructions please read the wiki:
<https://github.com/keirf/Greaseweazle/wiki/IPF-Images>""")

    # We have opened the library. Now initialise it.
    res = lib.CAPSInit()
    error.check(res == 0, "Failure initialising IPF library '%s'" % name)

    return lib
Ejemplo n.º 24
0
    def from_file(cls, dat):

        adf = cls(0, 2)

        nsec = adf.sec_per_track
        error.check((len(dat) % (2*nsec*512)) == 0, "Bad ADF image")
        ncyl = len(dat) // (2*nsec*512)
        if ncyl > 90:
            ncyl //= 2
            nsec *= 2
            adf.bitrate *= 2
            adf.sec_per_track = nsec

        for i in range(ncyl*2):
            ados = amigados.AmigaDOS(tracknr=i, nsec=nsec)
            ados.set_adf_track(dat[i*nsec*512:(i+1)*nsec*512])
            adf.track_list.append(ados)

        return adf
Ejemplo n.º 25
0
def extract_update(usb, dat, args):

    req_type = b'BL' if args.bootloader else b'GW'

    filename = args.file

    # Verify the update catalogue.
    error.check(
        struct.unpack('4s', dat[:4])[0] == b'GWUP',
        '%s: Not a valid UPD file' % (filename))
    crc32 = crcmod.predefined.Crc('crc-32-mpeg')
    crc32.update(dat)
    error.check(crc32.crcValue == 0, '%s: UPD file is corrupt' % (filename))
    dat = dat[4:-4]

    # Search the catalogue for a match on our Weazle's hardware type.
    while dat:
        upd_len, hw_model = struct.unpack("<2H", dat[:4])
        upd_type, major, minor = struct.unpack("2s2B",
                                               dat[upd_len - 4:upd_len])
        if ((hw_model, upd_type) == (usb.hw_model, req_type)):
            # Match: Pull out the embedded update file.
            dat = dat[4:upd_len + 4]
            break
        # Skip to the next catalogue entry.
        dat = dat[upd_len + 4:]

    error.check(
        dat, '%s: F%u %s update not found' %
        (filename, usb.hw_model,
         'bootloader' if args.bootloader else 'firmware'))

    # Check the matching update file's footer.
    sig, major, minor, hw_model = struct.unpack("<2s2BH", dat[-8:-2])
    error.check(
        len(dat) & 3 == 0 and sig == req_type and hw_model == usb.hw_model,
        '%s: Bad update file' % (filename))
    crc16 = crcmod.predefined.Crc('crc-ccitt-false')
    crc16.update(dat)
    error.check(crc16.crcValue == 0, '%s: Bad CRC' % (filename))

    return (major, minor), dat
Ejemplo n.º 26
0
 def flux_for_writeout(self):
     error.check(self.splice == 0,
                 "Cannot write non-index-aligned raw flux")
     # Copy the first revolution only to a fresh flux list.
     flux_list = []
     to_index = remain = self.index_list[0]
     for f in self.list:
         if f > remain:
             break
         flux_list.append(f)
         remain -= f
     # Extend with "safe" 4us sample values, to avoid unformatted area
     # at end of track if drive motor is a little slow.
     four_us = max(self.sample_freq * 4e-6, 1)
     if remain > four_us:
         flux_list.append(remain)
     for i in range(round(to_index/(10*four_us))):
         flux_list.append(four_us)
     return WriteoutFlux(to_index, flux_list, self.sample_freq,
                         terminate_at_index = True)
Ejemplo n.º 27
0
    def from_file(cls, name):

        with open(name, "rb") as f:
            dat = f.read()

        adf = cls()

        nsec = adf.sec_per_track
        error.check((len(dat) % (2 * nsec * 512)) == 0, "Bad ADF image")
        ncyl = len(dat) // (2 * nsec * 512)
        if ncyl > 90:
            ncyl //= 2
            nsec *= 2
            adf.sec_per_track = nsec

        for tnr in range(ncyl * 2):
            ados = amigados.AmigaDOS(tracknr=tnr, nsec=nsec)
            ados.set_adf_track(dat[tnr * nsec * 512:(tnr + 1) * nsec * 512])
            adf.to_track[tnr] = ados

        return adf
Ejemplo n.º 28
0
    def from_file(cls, dat):

        header = struct.unpack("<3s9BI", dat[0:16])
        (sig, _, _, nr_revs, s_trk, e_trk, flags, _, ss, _, _) = header
        error.check(sig == b"SCP", "SCP: Bad signature")
        nr_sides = 1 if ss else 2

        trk_offs = struct.unpack("<168I", dat[16:0x2b0])

        scp = cls(s_trk // nr_sides, nr_sides)
        scp.nr_revs = nr_revs

        for trknr in range(s_trk, e_trk + 1):
            trk_off = trk_offs[trknr]
            if trk_off == 0:
                scp.track_list.append((None, None))

            # Parse the SCP track header and extract the flux data.
            thdr = dat[trk_off:trk_off + 4 + 12 * nr_revs]
            sig, tnr, _, _, s_off = struct.unpack("<3sB3I", thdr[:16])
            error.check(sig == b"TRK", "SCP: Missing track signature")
            error.check(tnr == trknr, "SCP: Wrong track number in header")
            _, e_nr, e_off = struct.unpack("<3I", thdr[-12:])
            tdat = dat[trk_off + s_off:trk_off + e_off + e_nr * 2]

            scp.track_list.append((thdr, tdat))

        return scp
Ejemplo n.º 29
0
 def _decode_flux(self, dat):
     flux = []
     dat_i = iter(dat)
     try:
         while True:
             i = next(dat_i)
             if i < 250:
                 flux.append(i)
             elif i == 255:
                 val =  (next(dat_i) & 254) >>  1
                 val += (next(dat_i) & 254) <<  6
                 val += (next(dat_i) & 254) << 13
                 val += (next(dat_i) & 254) << 20
                 flux.append(val)
             else:
                 val = (i - 249) * 250
                 val += next(dat_i) - 1
                 flux.append(val)
     except StopIteration:
         pass
     error.check(flux[-1] == 0, "Missing terminator on flux read stream")
     return flux[:-1]
Ejemplo n.º 30
0
 def seek(self, cyl, head):
     self._send_cmd(struct.pack("2Bb", Cmd.Seek, 3, cyl))
     trk0 = not self.get_pin(26)
     if cyl == 0 and not trk0:
         # This can happen with Kryoflux flippy-modded Panasonic drives
         # which may not assert the /TRK0 signal when stepping *inward*
         # from cylinder -1. We can check this by attempting a fake outward
         # step, which is exactly NoClickStep's purpose.
         try:
             info = self.get_current_drive_info()
             if info.is_flippy:
                 self._send_cmd(struct.pack("2B", Cmd.NoClickStep, 2))
         except CmdError:
             # GetInfo.CurrentDrive is unsupported by older firmwares.
             # NoClickStep is "best effort". We're on a likely error
             # path anyway, so let them fail silently.
             pass
         trk0 = not self.get_pin(26)  # now re-sample /TRK0
     error.check(
         cyl < 0 or (cyl == 0) == trk0,
         "Track0 signal %s after seek to cylinder %d" %
         (('absent', 'asserted')[trk0], cyl))
     self._send_cmd(struct.pack("3B", Cmd.Head, 3, head))