|  | @@ -5,7 +5,7 @@
 | 
	
		
			
				|  |  |  # This is free and unencumbered software released into the public domain.
 | 
	
		
			
				|  |  |  # See the file COPYING for more details, or visit <http://unlicense.org>.
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -import heapq, struct
 | 
	
		
			
				|  |  | +import copy, heapq, struct
 | 
	
		
			
				|  |  |  import itertools as it
 | 
	
		
			
				|  |  |  from bitarray import bitarray
 | 
	
		
			
				|  |  |  import crcmod.predefined
 | 
	
	
		
			
				|  | @@ -54,6 +54,9 @@ class IDAM(TrackArea):
 | 
	
		
			
				|  |  |          return (super().__eq__(x)
 | 
	
		
			
				|  |  |                  and self.c == x.c and self.h == x.h
 | 
	
		
			
				|  |  |                  and self.r == x.r and self.n == x.n)
 | 
	
		
			
				|  |  | +    def __copy__(self):
 | 
	
		
			
				|  |  | +        return IDAM(self.start, self.end, self.crc,
 | 
	
		
			
				|  |  | +                    self.c, self.h, self.r, self.n)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  class DAM(TrackArea):
 | 
	
		
			
				|  |  |      def __init__(self, start, end, crc, mark, data=None):
 | 
	
	
		
			
				|  | @@ -66,6 +69,8 @@ class DAM(TrackArea):
 | 
	
		
			
				|  |  |          return (super().__eq__(x)
 | 
	
		
			
				|  |  |                  and self.mark == x.mark
 | 
	
		
			
				|  |  |                  and self.data == x.data)
 | 
	
		
			
				|  |  | +    def __copy__(self):
 | 
	
		
			
				|  |  | +        return DAM(self.start, self.end, self.crc, self.mark, self.data)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  class Sector(TrackArea):
 | 
	
		
			
				|  |  |      def __init__(self, idam, dam):
 | 
	
	
		
			
				|  | @@ -89,6 +94,8 @@ class Sector(TrackArea):
 | 
	
		
			
				|  |  |  class IAM(TrackArea):
 | 
	
		
			
				|  |  |      def __str__(self):
 | 
	
		
			
				|  |  |          return "IAM: %6d-%6d" % (self.start, self.end)
 | 
	
		
			
				|  |  | +    def __copy__(self):
 | 
	
		
			
				|  |  | +        return IAM(self.start, self.end)
 | 
	
		
			
				|  |  |      
 | 
	
		
			
				|  |  |  class IBM_MFM:
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -98,10 +105,12 @@ class IBM_MFM:
 | 
	
		
			
				|  |  |      DDAM = 0xf8
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      gap_presync = 12
 | 
	
		
			
				|  |  | -    filler = 0x4e
 | 
	
		
			
				|  |  |      
 | 
	
		
			
				|  |  |      def __init__(self, cyl, head):
 | 
	
		
			
				|  |  |          self.cyl, self.head = cyl, head
 | 
	
		
			
				|  |  | +        self.filler = 0x4e
 | 
	
		
			
				|  |  | +        self.time_per_rev = 0.2
 | 
	
		
			
				|  |  | +        self.clock = 1e-6
 | 
	
		
			
				|  |  |          self.sectors = []
 | 
	
		
			
				|  |  |          self.iams = []
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -127,7 +136,7 @@ class IBM_MFM:
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      def decode_raw(self, track):
 | 
	
		
			
				|  |  |          track.cue_at_index()
 | 
	
		
			
				|  |  | -        raw = RawTrack(clock = 1e-6, data = track)
 | 
	
		
			
				|  |  | +        raw = RawTrack(clock = self.clock, data = track)
 | 
	
		
			
				|  |  |          bits, _ = raw.get_all_data()
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          areas = []
 | 
	
	
		
			
				|  | @@ -232,25 +241,18 @@ class IBM_MFM:
 | 
	
		
			
				|  |  |                  t += encode(dam[3:])
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          # Add the pre-index gap.
 | 
	
		
			
				|  |  | -        tlen = 200000//16
 | 
	
		
			
				|  |  | +        tlen = int((self.time_per_rev / self.clock) // 16)
 | 
	
		
			
				|  |  |          gap = max(tlen - len(t)//2, 0)
 | 
	
		
			
				|  |  |          t += encode(bytes([self.filler] * gap))
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          track = MasterTrack(
 | 
	
		
			
				|  |  |              bits = mfm_encode(t),
 | 
	
		
			
				|  |  | -            time_per_rev = 0.2)
 | 
	
		
			
				|  |  | +            time_per_rev = self.time_per_rev)
 | 
	
		
			
				|  |  |          track.verify = self
 | 
	
		
			
				|  |  |          track.verify_revs = default_revs
 | 
	
		
			
				|  |  |          return track
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    def verify_track(self, flux):
 | 
	
		
			
				|  |  | -        readback_track = decode_track(self.cyl, self.head, flux)
 | 
	
		
			
				|  |  | -        if readback_track.nr_missing() != 0:
 | 
	
		
			
				|  |  | -            return False
 | 
	
		
			
				|  |  | -        return self.sectors == readback_track.sectors
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  class IBM_MFM_Formatted(IBM_MFM):
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      gap_4a = 80 # Post-Index
 | 
	
	
		
			
				|  | @@ -262,22 +264,6 @@ class IBM_MFM_Formatted(IBM_MFM):
 | 
	
		
			
				|  |  |          super().__init__(cyl, head)
 | 
	
		
			
				|  |  |          self.raw_iams, self.raw_sectors = [], []
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        pos = self.gap_4a
 | 
	
		
			
				|  |  | -        if self.gap_1 is not None:
 | 
	
		
			
				|  |  | -            self.iams = [IAM(pos*16,(pos+4)*16)]
 | 
	
		
			
				|  |  | -            pos += self.gap_1
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        for i in range(self.nsec):
 | 
	
		
			
				|  |  | -            pos += self.gap_presync
 | 
	
		
			
				|  |  | -            idam = IDAM(pos*16, (pos+10)*16, 0xffff,
 | 
	
		
			
				|  |  | -                        c=cyl, h=head, r=self.id0+i, n = self.sz)
 | 
	
		
			
				|  |  | -            pos += 10 + self.gap_2 + self.gap_presync
 | 
	
		
			
				|  |  | -            size = 128 << self.sz
 | 
	
		
			
				|  |  | -            dam = DAM(pos*16, (pos+4+size+2)*16, 0xffff,
 | 
	
		
			
				|  |  | -                      mark=self.DAM, data=bytes(size))
 | 
	
		
			
				|  |  | -            self.sectors.append(Sector(idam, dam))
 | 
	
		
			
				|  |  | -            pos += 4 + size + 2 + self.gap_3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |      def decode_raw(self, track):
 | 
	
		
			
				|  |  |          iams, sectors = self.iams, self.sectors
 | 
	
		
			
				|  |  |          self.iams, self.sectors = self.raw_iams, self.raw_sectors
 | 
	
	
		
			
				|  | @@ -314,8 +300,46 @@ class IBM_MFM_Formatted(IBM_MFM):
 | 
	
		
			
				|  |  |              tdat += s.dam.data
 | 
	
		
			
				|  |  |          return tdat
 | 
	
		
			
				|  |  |          
 | 
	
		
			
				|  |  | -    
 | 
	
		
			
				|  |  | -class IBM_MFM_1M44(IBM_MFM_Formatted):
 | 
	
		
			
				|  |  | +    def verify_track(self, flux):
 | 
	
		
			
				|  |  | +        readback_track = IBM_MFM_Formatted(self.cyl, self.head)
 | 
	
		
			
				|  |  | +        readback_track.clock = self.clock
 | 
	
		
			
				|  |  | +        readback_track.time_per_rev = self.time_per_rev
 | 
	
		
			
				|  |  | +        for x in self.iams:
 | 
	
		
			
				|  |  | +            readback_track.iams.append(copy.copy(x))
 | 
	
		
			
				|  |  | +        for x in self.sectors:
 | 
	
		
			
				|  |  | +            idam, dam = copy.copy(x.idam), copy.copy(x.dam)
 | 
	
		
			
				|  |  | +            idam.crc, dam.crc = 0xffff, 0xffff
 | 
	
		
			
				|  |  | +            readback_track.sectors.append(Sector(idam, dam))
 | 
	
		
			
				|  |  | +        readback_track.decode_raw(flux)
 | 
	
		
			
				|  |  | +        if readback_track.nr_missing() != 0:
 | 
	
		
			
				|  |  | +            return False
 | 
	
		
			
				|  |  | +        return self.sectors == readback_track.sectors
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +class IBM_MFM_Predefined(IBM_MFM_Formatted):
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    def __init__(self, cyl, head):
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        super().__init__(cyl, head)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        pos = self.gap_4a
 | 
	
		
			
				|  |  | +        if self.gap_1 is not None:
 | 
	
		
			
				|  |  | +            self.iams = [IAM(pos*16,(pos+4)*16)]
 | 
	
		
			
				|  |  | +            pos += 4 + self.gap_1
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        for i in range(self.nsec):
 | 
	
		
			
				|  |  | +            pos += self.gap_presync
 | 
	
		
			
				|  |  | +            idam = IDAM(pos*16, (pos+10)*16, 0xffff,
 | 
	
		
			
				|  |  | +                        c=cyl, h=head, r=self.id0+i, n = self.sz)
 | 
	
		
			
				|  |  | +            pos += 10 + self.gap_2 + self.gap_presync
 | 
	
		
			
				|  |  | +            size = 128 << self.sz
 | 
	
		
			
				|  |  | +            dam = DAM(pos*16, (pos+4+size+2)*16, 0xffff,
 | 
	
		
			
				|  |  | +                      mark=self.DAM, data=bytes(size))
 | 
	
		
			
				|  |  | +            self.sectors.append(Sector(idam, dam))
 | 
	
		
			
				|  |  | +            pos += 4 + size + 2 + self.gap_3
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +class IBM_MFM_1M44(IBM_MFM_Predefined):
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      gap_3  = 84 # Post-DAM
 | 
	
		
			
				|  |  |      nsec   = 18
 |