diskstack 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- diskstack/__init__.py +5 -0
- diskstack/_vendor/__init__.py +0 -0
- diskstack/_vendor/greaseweazle/COPYING +24 -0
- diskstack/_vendor/greaseweazle/__init__.py +2 -0
- diskstack/_vendor/greaseweazle/codec/__init__.py +0 -0
- diskstack/_vendor/greaseweazle/codec/amiga/__init__.py +0 -0
- diskstack/_vendor/greaseweazle/codec/amiga/amigados.py +221 -0
- diskstack/_vendor/greaseweazle/codec/apple2/__init__.py +0 -0
- diskstack/_vendor/greaseweazle/codec/apple2/apple2_gcr.py +223 -0
- diskstack/_vendor/greaseweazle/codec/bitcell.py +117 -0
- diskstack/_vendor/greaseweazle/codec/codec.py +362 -0
- diskstack/_vendor/greaseweazle/codec/commodore/__init__.py +0 -0
- diskstack/_vendor/greaseweazle/codec/commodore/c64_gcr.py +229 -0
- diskstack/_vendor/greaseweazle/codec/datageneral/__init__.py +0 -0
- diskstack/_vendor/greaseweazle/codec/datageneral/datageneral.py +211 -0
- diskstack/_vendor/greaseweazle/codec/hp/__init__.py +0 -0
- diskstack/_vendor/greaseweazle/codec/hp/hp_mmfm.py +258 -0
- diskstack/_vendor/greaseweazle/codec/ibm/__init__.py +0 -0
- diskstack/_vendor/greaseweazle/codec/ibm/ibm.py +1005 -0
- diskstack/_vendor/greaseweazle/codec/macintosh/__init__.py +0 -0
- diskstack/_vendor/greaseweazle/codec/macintosh/mac_gcr.py +238 -0
- diskstack/_vendor/greaseweazle/codec/micropolis/__init__.py +0 -0
- diskstack/_vendor/greaseweazle/codec/micropolis/micropolis.py +233 -0
- diskstack/_vendor/greaseweazle/codec/northstar/__init__.py +0 -0
- diskstack/_vendor/greaseweazle/codec/northstar/northstar.py +210 -0
- diskstack/_vendor/greaseweazle/data/__init__.py +0 -0
- diskstack/_vendor/greaseweazle/data/diskdefs.cfg +81 -0
- diskstack/_vendor/greaseweazle/data/diskdefs_acorn.cfg +119 -0
- diskstack/_vendor/greaseweazle/data/diskdefs_akai.cfg +27 -0
- diskstack/_vendor/greaseweazle/data/diskdefs_amiga.cfg +17 -0
- diskstack/_vendor/greaseweazle/data/diskdefs_apple2.cfg +31 -0
- diskstack/_vendor/greaseweazle/data/diskdefs_apricot.cfg +25 -0
- diskstack/_vendor/greaseweazle/data/diskdefs_atari.cfg +33 -0
- diskstack/_vendor/greaseweazle/data/diskdefs_atarist.cfg +76 -0
- diskstack/_vendor/greaseweazle/data/diskdefs_coco.cfg +98 -0
- diskstack/_vendor/greaseweazle/data/diskdefs_commodore.cfg +127 -0
- diskstack/_vendor/greaseweazle/data/diskdefs_datageneral.cfg +8 -0
- diskstack/_vendor/greaseweazle/data/diskdefs_dec.cfg +37 -0
- diskstack/_vendor/greaseweazle/data/diskdefs_dragon.cfg +61 -0
- diskstack/_vendor/greaseweazle/data/diskdefs_eagle.cfg +25 -0
- diskstack/_vendor/greaseweazle/data/diskdefs_ensoniq.cfg +39 -0
- diskstack/_vendor/greaseweazle/data/diskdefs_epson.cfg +95 -0
- diskstack/_vendor/greaseweazle/data/diskdefs_gem.cfg +15 -0
- diskstack/_vendor/greaseweazle/data/diskdefs_hp.cfg +25 -0
- diskstack/_vendor/greaseweazle/data/diskdefs_ibm.cfg +140 -0
- diskstack/_vendor/greaseweazle/data/diskdefs_kaypro.cfg +58 -0
- diskstack/_vendor/greaseweazle/data/diskdefs_luxor.cfg +96 -0
- diskstack/_vendor/greaseweazle/data/diskdefs_mac.cfg +71 -0
- diskstack/_vendor/greaseweazle/data/diskdefs_micropolis.cfg +73 -0
- diskstack/_vendor/greaseweazle/data/diskdefs_mm1.cfg +69 -0
- diskstack/_vendor/greaseweazle/data/diskdefs_msx.cfg +45 -0
- diskstack/_vendor/greaseweazle/data/diskdefs_northstar.cfg +37 -0
- diskstack/_vendor/greaseweazle/data/diskdefs_occ1.cfg +23 -0
- diskstack/_vendor/greaseweazle/data/diskdefs_olivetti.cfg +18 -0
- diskstack/_vendor/greaseweazle/data/diskdefs_pc98.cfg +69 -0
- diskstack/_vendor/greaseweazle/data/diskdefs_raw.cfg +25 -0
- diskstack/_vendor/greaseweazle/data/diskdefs_rm.cfg +98 -0
- diskstack/_vendor/greaseweazle/data/diskdefs_sci.cfg +15 -0
- diskstack/_vendor/greaseweazle/data/diskdefs_sega.cfg +13 -0
- diskstack/_vendor/greaseweazle/data/diskdefs_sharp.cfg +13 -0
- diskstack/_vendor/greaseweazle/data/diskdefs_thomson.cfg +78 -0
- diskstack/_vendor/greaseweazle/data/diskdefs_tsc.cfg +81 -0
- diskstack/_vendor/greaseweazle/data/diskdefs_xerox.cfg +59 -0
- diskstack/_vendor/greaseweazle/data/diskdefs_zx.cfg +245 -0
- diskstack/_vendor/greaseweazle/error.py +19 -0
- diskstack/_vendor/greaseweazle/flux.py +315 -0
- diskstack/_vendor/greaseweazle/image/__init__.py +0 -0
- diskstack/_vendor/greaseweazle/image/a2r.py +133 -0
- diskstack/_vendor/greaseweazle/image/acorn.py +28 -0
- diskstack/_vendor/greaseweazle/image/adf.py +15 -0
- diskstack/_vendor/greaseweazle/image/apple2.py +18 -0
- diskstack/_vendor/greaseweazle/image/apridisk.py +107 -0
- diskstack/_vendor/greaseweazle/image/caps.py +464 -0
- diskstack/_vendor/greaseweazle/image/d64.py +51 -0
- diskstack/_vendor/greaseweazle/image/d81.py +28 -0
- diskstack/_vendor/greaseweazle/image/d88.py +211 -0
- diskstack/_vendor/greaseweazle/image/dcp.py +45 -0
- diskstack/_vendor/greaseweazle/image/dim.py +53 -0
- diskstack/_vendor/greaseweazle/image/dmk.py +166 -0
- diskstack/_vendor/greaseweazle/image/dsk.py +31 -0
- diskstack/_vendor/greaseweazle/image/edsk.py +591 -0
- diskstack/_vendor/greaseweazle/image/fd.py +23 -0
- diskstack/_vendor/greaseweazle/image/fdi.py +41 -0
- diskstack/_vendor/greaseweazle/image/hdm.py +15 -0
- diskstack/_vendor/greaseweazle/image/hfe.py +742 -0
- diskstack/_vendor/greaseweazle/image/image.py +130 -0
- diskstack/_vendor/greaseweazle/image/imd.py +201 -0
- diskstack/_vendor/greaseweazle/image/img.py +111 -0
- diskstack/_vendor/greaseweazle/image/kryoflux.py +304 -0
- diskstack/_vendor/greaseweazle/image/mgt.py +15 -0
- diskstack/_vendor/greaseweazle/image/msa.py +153 -0
- diskstack/_vendor/greaseweazle/image/nfd.py +113 -0
- diskstack/_vendor/greaseweazle/image/nsi.py +47 -0
- diskstack/_vendor/greaseweazle/image/scp.py +471 -0
- diskstack/_vendor/greaseweazle/image/sf7.py +15 -0
- diskstack/_vendor/greaseweazle/image/sharp2d.py +15 -0
- diskstack/_vendor/greaseweazle/image/td0.py +141 -0
- diskstack/_vendor/greaseweazle/image/xdf.py +15 -0
- diskstack/_vendor/greaseweazle/optimised/__init__.py +22 -0
- diskstack/_vendor/greaseweazle/tools/__init__.py +0 -0
- diskstack/_vendor/greaseweazle/tools/util.py +133 -0
- diskstack/_vendor/greaseweazle/track.py +494 -0
- diskstack/cache.py +210 -0
- diskstack/candidates.py +396 -0
- diskstack/cli.py +348 -0
- diskstack/errors.py +5 -0
- diskstack/filler.py +29 -0
- diskstack/formats.py +381 -0
- diskstack/parallel.py +73 -0
- diskstack/report.py +353 -0
- diskstack/stack.py +317 -0
- diskstack-1.0.0.dist-info/METADATA +329 -0
- diskstack-1.0.0.dist-info/RECORD +119 -0
- diskstack-1.0.0.dist-info/WHEEL +5 -0
- diskstack-1.0.0.dist-info/entry_points.txt +2 -0
- diskstack-1.0.0.dist-info/licenses/LICENSE +21 -0
- diskstack-1.0.0.dist-info/licenses/NOTICE +55 -0
- diskstack-1.0.0.dist-info/licenses/diskstack/_vendor/greaseweazle/COPYING +24 -0
- diskstack-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
# prefix: zx.
|
|
2
|
+
|
|
3
|
+
# Betadisk TR-DOS
|
|
4
|
+
disk trdos.ds80
|
|
5
|
+
cyls = 80
|
|
6
|
+
heads = 2
|
|
7
|
+
tracks * ibm.mfm
|
|
8
|
+
secs = 16
|
|
9
|
+
bps = 256
|
|
10
|
+
h = 0
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Quorum (ZX Spectrum clone) running CP/M-80
|
|
15
|
+
disk quorum.ds80
|
|
16
|
+
cyls = 80
|
|
17
|
+
heads = 2
|
|
18
|
+
tracks * ibm.mfm
|
|
19
|
+
secs = 5
|
|
20
|
+
bps = 1024
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Didaktik D80
|
|
25
|
+
disk d80.ds80
|
|
26
|
+
cyls = 80
|
|
27
|
+
heads = 2
|
|
28
|
+
tracks * ibm.mfm
|
|
29
|
+
secs = 9
|
|
30
|
+
bps = 512
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
#Timex FDD 3/3000
|
|
35
|
+
disk fdd3000.ss40
|
|
36
|
+
cyls = 40
|
|
37
|
+
heads = 1
|
|
38
|
+
tracks 0-39 ibm.mfm
|
|
39
|
+
secs = 16
|
|
40
|
+
bps = 256
|
|
41
|
+
id = 0
|
|
42
|
+
rate = 250
|
|
43
|
+
h = 0
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
disk fdd3000.ds80
|
|
48
|
+
cyls = 80
|
|
49
|
+
heads = 2
|
|
50
|
+
tracks 0-79 ibm.mfm
|
|
51
|
+
secs = 16
|
|
52
|
+
bps = 256
|
|
53
|
+
id = 0
|
|
54
|
+
rate = 250
|
|
55
|
+
h = 1
|
|
56
|
+
end
|
|
57
|
+
tracks 0-79 ibm.mfm
|
|
58
|
+
secs = 16
|
|
59
|
+
bps = 256
|
|
60
|
+
id = 0
|
|
61
|
+
rate = 250
|
|
62
|
+
h = 0
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Kempston Disk Interface
|
|
67
|
+
disk kempston.ss40
|
|
68
|
+
cyls = 40
|
|
69
|
+
heads = 1
|
|
70
|
+
tracks * ibm.mfm
|
|
71
|
+
secs = 10
|
|
72
|
+
bps = 512
|
|
73
|
+
rate = 250
|
|
74
|
+
id=0
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
disk kempston.ds80
|
|
79
|
+
cyls = 80
|
|
80
|
+
heads = 2
|
|
81
|
+
tracks * ibm.mfm
|
|
82
|
+
secs = 10
|
|
83
|
+
bps = 512
|
|
84
|
+
rate = 250
|
|
85
|
+
id=0
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# MGT +D
|
|
90
|
+
disk plusd.ds80
|
|
91
|
+
cyls = 80
|
|
92
|
+
heads = 2
|
|
93
|
+
tracks * ibm.mfm
|
|
94
|
+
secs = 10
|
|
95
|
+
bps = 512
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
#ZX Spectrum Opus Discovery
|
|
100
|
+
disk opus.ss40
|
|
101
|
+
cyls = 40
|
|
102
|
+
heads = 1
|
|
103
|
+
tracks * ibm.mfm
|
|
104
|
+
secs = 18
|
|
105
|
+
bps = 256
|
|
106
|
+
id = 0
|
|
107
|
+
rate = 250
|
|
108
|
+
cskew = 13
|
|
109
|
+
interleave=13
|
|
110
|
+
iam = no
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
disk opus.ds80
|
|
115
|
+
cyls = 80
|
|
116
|
+
heads = 2
|
|
117
|
+
tracks * ibm.mfm
|
|
118
|
+
secs = 18
|
|
119
|
+
bps = 256
|
|
120
|
+
id = 0
|
|
121
|
+
rate = 250
|
|
122
|
+
cskew = 13
|
|
123
|
+
interleave=13
|
|
124
|
+
iam = no
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# ZX Spectrum +3DOS
|
|
129
|
+
disk 3dos.ss40
|
|
130
|
+
cyls = 40
|
|
131
|
+
heads = 1
|
|
132
|
+
tracks * ibm.mfm
|
|
133
|
+
secs = 9
|
|
134
|
+
bps = 512
|
|
135
|
+
rate = 250
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
disk 3dos.ds80
|
|
140
|
+
cyls = 80
|
|
141
|
+
heads = 2
|
|
142
|
+
tracks * ibm.mfm
|
|
143
|
+
secs = 9
|
|
144
|
+
bps = 512
|
|
145
|
+
rate = 250
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Rocky Gush
|
|
150
|
+
disk rocky.ss40
|
|
151
|
+
cyls = 40
|
|
152
|
+
heads = 1
|
|
153
|
+
tracks 0-79 ibm.mfm
|
|
154
|
+
secs = 5
|
|
155
|
+
bps = 1024
|
|
156
|
+
id = 0
|
|
157
|
+
rate = 250
|
|
158
|
+
h = 0
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
disk rocky.ds80
|
|
163
|
+
cyls = 80
|
|
164
|
+
heads = 2
|
|
165
|
+
tracks 0-79 ibm.mfm
|
|
166
|
+
secs = 5
|
|
167
|
+
bps = 1024
|
|
168
|
+
id = 0
|
|
169
|
+
rate = 250
|
|
170
|
+
h = 1
|
|
171
|
+
end
|
|
172
|
+
tracks 0-79 ibm.mfm
|
|
173
|
+
secs = 5
|
|
174
|
+
bps = 1024
|
|
175
|
+
id = 0
|
|
176
|
+
rate = 250
|
|
177
|
+
h = 0
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
# Turbodrive
|
|
182
|
+
disk turbodrive.ds40
|
|
183
|
+
cyls = 40
|
|
184
|
+
heads = 2
|
|
185
|
+
tracks 0-39 ibm.mfm
|
|
186
|
+
secs = 10
|
|
187
|
+
bps = 512
|
|
188
|
+
rate = 250
|
|
189
|
+
interleave = 5
|
|
190
|
+
cskew = 5
|
|
191
|
+
h = 1
|
|
192
|
+
end
|
|
193
|
+
tracks 0-39 ibm.mfm
|
|
194
|
+
secs = 10
|
|
195
|
+
bps = 512
|
|
196
|
+
rate = 250
|
|
197
|
+
interleave = 5
|
|
198
|
+
cskew = 5
|
|
199
|
+
h = 0
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
disk turbodrive.ds80
|
|
204
|
+
cyls = 80
|
|
205
|
+
heads = 2
|
|
206
|
+
tracks 0-79 ibm.mfm
|
|
207
|
+
secs = 10
|
|
208
|
+
bps = 512
|
|
209
|
+
rate = 250
|
|
210
|
+
interleave = 5
|
|
211
|
+
cskew = 5
|
|
212
|
+
h = 1
|
|
213
|
+
end
|
|
214
|
+
tracks 0-79 ibm.mfm
|
|
215
|
+
secs = 10
|
|
216
|
+
bps = 512
|
|
217
|
+
rate = 250
|
|
218
|
+
interleave = 5
|
|
219
|
+
cskew = 5
|
|
220
|
+
h = 0
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
# Watford SPDOS
|
|
225
|
+
disk watford.ss40
|
|
226
|
+
cyls = 40
|
|
227
|
+
heads = 1
|
|
228
|
+
tracks * ibm.mfm
|
|
229
|
+
secs = 10
|
|
230
|
+
bps = 512
|
|
231
|
+
rate = 250
|
|
232
|
+
id=0
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
disk watford.ds80
|
|
237
|
+
cyls = 80
|
|
238
|
+
heads = 2
|
|
239
|
+
tracks * ibm.mfm
|
|
240
|
+
secs = 10
|
|
241
|
+
bps = 512
|
|
242
|
+
rate = 250
|
|
243
|
+
id=0
|
|
244
|
+
end
|
|
245
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# greaseweazle/error.py
|
|
2
|
+
#
|
|
3
|
+
# Error management and reporting.
|
|
4
|
+
#
|
|
5
|
+
# Written & released by Keir Fraser <keir.xen@gmail.com>
|
|
6
|
+
#
|
|
7
|
+
# This is free and unencumbered software released into the public domain.
|
|
8
|
+
# See the file COPYING for more details, or visit <http://unlicense.org>.
|
|
9
|
+
|
|
10
|
+
class Fatal(Exception):
|
|
11
|
+
pass
|
|
12
|
+
|
|
13
|
+
def check(pred, desc):
|
|
14
|
+
if not pred:
|
|
15
|
+
raise Fatal(desc)
|
|
16
|
+
|
|
17
|
+
# Local variables:
|
|
18
|
+
# python-indent: 4
|
|
19
|
+
# End:
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
# greaseweazle/flux.py
|
|
2
|
+
#
|
|
3
|
+
# Written & released by Keir Fraser <keir.xen@gmail.com>
|
|
4
|
+
#
|
|
5
|
+
# This is free and unencumbered software released into the public domain.
|
|
6
|
+
# See the file COPYING for more details, or visit <http://unlicense.org>.
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
from typing import List, Optional, Protocol
|
|
10
|
+
|
|
11
|
+
from diskstack._vendor.greaseweazle import error
|
|
12
|
+
|
|
13
|
+
class HasFlux(Protocol):
|
|
14
|
+
def summary_string(self) -> str:
|
|
15
|
+
...
|
|
16
|
+
def flux(self) -> Flux:
|
|
17
|
+
...
|
|
18
|
+
def flux_for_writeout(self, cue_at_index) -> WriteoutFlux:
|
|
19
|
+
...
|
|
20
|
+
|
|
21
|
+
class Flux:
|
|
22
|
+
|
|
23
|
+
_ticks_per_rev: float
|
|
24
|
+
|
|
25
|
+
def __init__(self,
|
|
26
|
+
index_list: List[float],
|
|
27
|
+
flux_list: List[float],
|
|
28
|
+
sample_freq: float,
|
|
29
|
+
index_cued = True) -> None:
|
|
30
|
+
self.index_list = index_list
|
|
31
|
+
self.sector_list: Optional[List[List[float]]] = None
|
|
32
|
+
self.list = flux_list
|
|
33
|
+
self.sample_freq = sample_freq
|
|
34
|
+
self.splice: Optional[float] = None
|
|
35
|
+
self.index_cued = index_cued
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def __str__(self) -> str:
|
|
39
|
+
s = "\nFlux: %.2f MHz" % (self.sample_freq*1e-6)
|
|
40
|
+
if self.index_cued: s += ", Index-Cued"
|
|
41
|
+
s += ("\n Total: %u samples, %.2fms\n"
|
|
42
|
+
% (len(self.list), sum(self.list)*1000/self.sample_freq))
|
|
43
|
+
for rev, t in enumerate(self.index_list):
|
|
44
|
+
s += " Revolution %u: %.2fms\n" % (rev, t*1000/self.sample_freq)
|
|
45
|
+
if self.sector_list:
|
|
46
|
+
for sec, t in enumerate(self.sector_list[rev]):
|
|
47
|
+
s += (" Sector %u: %.2fms\n"
|
|
48
|
+
% (sec, t*1000/self.sample_freq))
|
|
49
|
+
return s[:-1]
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def summary_string(self) -> str:
|
|
53
|
+
return ("Raw Flux (%u flux in %.2fms)"
|
|
54
|
+
% (len(self.list), sum(self.list)*1000/self.sample_freq))
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def identify_hard_sectors(self) -> None:
|
|
58
|
+
if self.sector_list is not None:
|
|
59
|
+
return
|
|
60
|
+
error.check(len(self.index_list) > 3,
|
|
61
|
+
"Not enough index marks for a hard-sectored track")
|
|
62
|
+
self.cue_at_index()
|
|
63
|
+
x = [self.index_list[0], self.index_list[2]]
|
|
64
|
+
x.sort()
|
|
65
|
+
thresh = x[1] * 3 / 4
|
|
66
|
+
ticks_to_index: float = 0
|
|
67
|
+
short_ticks: float = 0
|
|
68
|
+
sectors: List[float] = []
|
|
69
|
+
index_list = self.index_list
|
|
70
|
+
self.index_list = []
|
|
71
|
+
self.sector_list = []
|
|
72
|
+
short_count = 0
|
|
73
|
+
for t in index_list:
|
|
74
|
+
is_short = (t < thresh)
|
|
75
|
+
if is_short:
|
|
76
|
+
short_ticks += t
|
|
77
|
+
short_count += 1
|
|
78
|
+
# Latch an index when we see two short pulses, or a long pulse
|
|
79
|
+
# following at least one short pulse.
|
|
80
|
+
if short_count != 0 and (short_count > 1 or not is_short):
|
|
81
|
+
ticks_to_index += short_ticks
|
|
82
|
+
sectors.append(short_ticks)
|
|
83
|
+
self.index_list.append(ticks_to_index)
|
|
84
|
+
self.sector_list.append(sectors)
|
|
85
|
+
sectors = []
|
|
86
|
+
short_ticks = ticks_to_index = short_count = 0
|
|
87
|
+
if not is_short:
|
|
88
|
+
ticks_to_index += t
|
|
89
|
+
sectors.append(t)
|
|
90
|
+
error.check(len(self.index_list) > 0,
|
|
91
|
+
"No hard-sector index mark found")
|
|
92
|
+
self.index_cued = (
|
|
93
|
+
(len(self.index_list) >= 2) and
|
|
94
|
+
(len(self.sector_list[0]) == len(self.sector_list[1])))
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def append(self, flux: Flux) -> None:
|
|
98
|
+
# Scale the new flux if required, to match existing sample frequency.
|
|
99
|
+
# This will result in floating-point flux values.
|
|
100
|
+
if self.sample_freq == flux.sample_freq:
|
|
101
|
+
f_list, i_list = flux.list, flux.index_list
|
|
102
|
+
else:
|
|
103
|
+
factor = self.sample_freq / flux.sample_freq
|
|
104
|
+
f_list = [x*factor for x in flux.list]
|
|
105
|
+
i_list = [x*factor for x in flux.index_list]
|
|
106
|
+
# Any trailing flux is incorporated into the first revolution of
|
|
107
|
+
# the appended flux.
|
|
108
|
+
rev0 = i_list[0] + sum(self.list) - sum(self.index_list)
|
|
109
|
+
self.index_list += [rev0] + i_list[1:]
|
|
110
|
+
self.list += f_list
|
|
111
|
+
# TODO: Work with hard-sectored disks
|
|
112
|
+
self.sector_list = None
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def cue_at_index(self) -> None:
|
|
116
|
+
|
|
117
|
+
if self.index_cued:
|
|
118
|
+
return
|
|
119
|
+
|
|
120
|
+
error.check(len(self.index_list) >= 2,
|
|
121
|
+
'''\
|
|
122
|
+
Not enough revolutions of flux data to cue at index.
|
|
123
|
+
Try dumping more revolutions (larger --revs value).''')
|
|
124
|
+
|
|
125
|
+
# Clip the initial partial revolution.
|
|
126
|
+
to_index = self.index_list[0]
|
|
127
|
+
for i in range(len(self.list)):
|
|
128
|
+
to_index -= self.list[i]
|
|
129
|
+
if to_index < 0:
|
|
130
|
+
break
|
|
131
|
+
if to_index < 0:
|
|
132
|
+
self.list = [-to_index] + self.list[i+1:]
|
|
133
|
+
else: # we ran out of flux
|
|
134
|
+
self.list = []
|
|
135
|
+
self.index_list = self.index_list[1:]
|
|
136
|
+
self.index_cued = True
|
|
137
|
+
if self.sector_list:
|
|
138
|
+
self.sector_list = self.sector_list[1:]
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def reverse(self) -> None:
|
|
142
|
+
|
|
143
|
+
assert self.sector_list is None
|
|
144
|
+
|
|
145
|
+
was_index_cued = self.index_cued
|
|
146
|
+
flux_sum = sum(self.list)
|
|
147
|
+
|
|
148
|
+
self.index_cued = False
|
|
149
|
+
self.list.reverse()
|
|
150
|
+
self.index_list.reverse()
|
|
151
|
+
|
|
152
|
+
to_index = flux_sum - sum(self.index_list)
|
|
153
|
+
if to_index <= 0:
|
|
154
|
+
if to_index < 0:
|
|
155
|
+
self.list.insert(0, -to_index)
|
|
156
|
+
flux_sum += -to_index
|
|
157
|
+
self.index_list = self.index_list[1:]
|
|
158
|
+
self.index_cued = True
|
|
159
|
+
else:
|
|
160
|
+
self.index_list = [to_index] + self.index_list[:-1]
|
|
161
|
+
|
|
162
|
+
if was_index_cued:
|
|
163
|
+
self.index_list.append(flux_sum - sum(self.index_list))
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def set_nr_revs(self, revs:int) -> None:
|
|
167
|
+
|
|
168
|
+
self.cue_at_index()
|
|
169
|
+
error.check(self.index_list,
|
|
170
|
+
'Need at least one revolution to adjust # revolutions')
|
|
171
|
+
|
|
172
|
+
if len(self.index_list) > revs:
|
|
173
|
+
self.index_list = self.index_list[:revs]
|
|
174
|
+
if self.sector_list:
|
|
175
|
+
self.sector_list = self.sector_list[:revs]
|
|
176
|
+
to_index = sum(self.index_list)
|
|
177
|
+
for i in range(len(self.list)):
|
|
178
|
+
to_index -= self.list[i]
|
|
179
|
+
if to_index < 0:
|
|
180
|
+
self.list = self.list[:i]
|
|
181
|
+
break
|
|
182
|
+
|
|
183
|
+
while len(self.index_list) < revs:
|
|
184
|
+
nr = min(revs - len(self.index_list), len(self.index_list))
|
|
185
|
+
to_index = sum(self.index_list[:nr])
|
|
186
|
+
l = self.list
|
|
187
|
+
for i in range(len(l)):
|
|
188
|
+
to_index -= l[i]
|
|
189
|
+
if to_index < 0:
|
|
190
|
+
to_index += l[i]
|
|
191
|
+
l = l[:i]
|
|
192
|
+
break
|
|
193
|
+
if self.list:
|
|
194
|
+
self.list = l + [to_index + self.list[0]] + self.list[1:]
|
|
195
|
+
self.index_list = self.index_list[:nr] + self.index_list
|
|
196
|
+
if self.sector_list:
|
|
197
|
+
self.sector_list = self.sector_list[:nr] + self.sector_list
|
|
198
|
+
|
|
199
|
+
def flux_for_writeout(self, cue_at_index) -> WriteoutFlux:
|
|
200
|
+
|
|
201
|
+
# Splice at index unless we know better.
|
|
202
|
+
splice = 0 if self.splice is None else self.splice
|
|
203
|
+
|
|
204
|
+
error.check(self.index_cued,
|
|
205
|
+
"Cannot write non-index-cued raw flux")
|
|
206
|
+
error.check(splice == 0 or len(self.index_list) > 1,
|
|
207
|
+
"Cannot write single-revolution unaligned raw flux")
|
|
208
|
+
splice_at_index = (splice == 0)
|
|
209
|
+
|
|
210
|
+
# Copy the required amount of flux to a fresh list.
|
|
211
|
+
flux_list = []
|
|
212
|
+
to_index = self.index_list[0]
|
|
213
|
+
remain = to_index + splice
|
|
214
|
+
for f in self.list:
|
|
215
|
+
if f > remain:
|
|
216
|
+
break
|
|
217
|
+
flux_list.append(f)
|
|
218
|
+
remain -= f
|
|
219
|
+
|
|
220
|
+
if not cue_at_index:
|
|
221
|
+
# We will write more than one revolution and terminate the
|
|
222
|
+
# second revolution at the splice. Extend the start of the write
|
|
223
|
+
# with "safe" 4us sample values, in case the drive motor is a
|
|
224
|
+
# little fast.
|
|
225
|
+
if remain > 0:
|
|
226
|
+
flux_list.append(remain)
|
|
227
|
+
prepend = max(round(to_index/10 - splice), 0)
|
|
228
|
+
if prepend != 0:
|
|
229
|
+
four_us = max(self.sample_freq * 4e-6, 1)
|
|
230
|
+
flux_list = [four_us]*round(prepend/four_us) + flux_list
|
|
231
|
+
splice_at_index = False
|
|
232
|
+
elif splice_at_index:
|
|
233
|
+
# Extend with "safe" 4us sample values, to avoid unformatted area
|
|
234
|
+
# at end of track if drive motor is a little slow.
|
|
235
|
+
four_us = max(self.sample_freq * 4e-6, 1)
|
|
236
|
+
if remain > four_us:
|
|
237
|
+
flux_list.append(remain)
|
|
238
|
+
for i in range(round(to_index/(10*four_us))):
|
|
239
|
+
flux_list.append(four_us)
|
|
240
|
+
elif remain > 0:
|
|
241
|
+
# End the write exactly where specified.
|
|
242
|
+
flux_list.append(remain)
|
|
243
|
+
|
|
244
|
+
return WriteoutFlux(to_index, flux_list, self.sample_freq,
|
|
245
|
+
index_cued = cue_at_index,
|
|
246
|
+
terminate_at_index = splice_at_index)
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
def flux(self) -> Flux:
|
|
251
|
+
return self
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def scale(self, factor) -> None:
|
|
255
|
+
"""Scale up all flux and index timings by specified factor."""
|
|
256
|
+
self.sample_freq /= factor
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
@property
|
|
260
|
+
def ticks_per_rev(self) -> float:
|
|
261
|
+
"""Mean time between index pulses, in sample ticks"""
|
|
262
|
+
try:
|
|
263
|
+
index_list = self.index_list
|
|
264
|
+
if not self.index_cued:
|
|
265
|
+
index_list = index_list[1:]
|
|
266
|
+
ticks_per_rev = sum(index_list) / len(index_list)
|
|
267
|
+
except:
|
|
268
|
+
ticks_per_rev = self._ticks_per_rev
|
|
269
|
+
return ticks_per_rev
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
@property
|
|
273
|
+
def time_per_rev(self) -> float:
|
|
274
|
+
"""Mean time between index pulses, in seconds (float)"""
|
|
275
|
+
return self.ticks_per_rev / self.sample_freq
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
class WriteoutFlux:
|
|
279
|
+
|
|
280
|
+
def __init__(
|
|
281
|
+
self,
|
|
282
|
+
ticks_to_index: float,
|
|
283
|
+
flux_list: List[float],
|
|
284
|
+
sample_freq: float,
|
|
285
|
+
index_cued: bool,
|
|
286
|
+
terminate_at_index: bool
|
|
287
|
+
) -> None:
|
|
288
|
+
self.ticks_to_index = ticks_to_index
|
|
289
|
+
self.list = flux_list
|
|
290
|
+
self.sample_freq = sample_freq
|
|
291
|
+
self.index_cued = index_cued
|
|
292
|
+
self.terminate_at_index = terminate_at_index
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
def __str__(self) -> str:
|
|
296
|
+
s = ("\nWriteoutFlux: %.2f MHz, %.2fms to index, %s\n"
|
|
297
|
+
" Total: %u samples, %.2fms"
|
|
298
|
+
% (self.sample_freq*1e-6,
|
|
299
|
+
self.ticks_to_index*1000/self.sample_freq,
|
|
300
|
+
("Write all", "Terminate at index")[self.terminate_at_index],
|
|
301
|
+
len(self.list), sum(self.list)*1000/self.sample_freq))
|
|
302
|
+
return s
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
def summary_string(self) -> str:
|
|
306
|
+
s = ("Flux: %.1fms period, %.1f ms total, %s"
|
|
307
|
+
% (self.ticks_to_index*1000/self.sample_freq,
|
|
308
|
+
sum(self.list)*1000/self.sample_freq,
|
|
309
|
+
("Write all", "Terminate at index")[self.terminate_at_index]))
|
|
310
|
+
return s
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
# Local variables:
|
|
314
|
+
# python-indent: 4
|
|
315
|
+
# End:
|
|
File without changes
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# greaseweazle/image/a2r.py
|
|
2
|
+
#
|
|
3
|
+
# Applesauce 3.x image format.
|
|
4
|
+
#
|
|
5
|
+
# Written & released by Keir Fraser <keir.xen@gmail.com>
|
|
6
|
+
#
|
|
7
|
+
# This is free and unencumbered software released into the public domain.
|
|
8
|
+
# See the file COPYING for more details, or visit <http://unlicense.org>.
|
|
9
|
+
|
|
10
|
+
from typing import Dict, Tuple, Optional, List
|
|
11
|
+
|
|
12
|
+
import struct
|
|
13
|
+
|
|
14
|
+
from diskstack._vendor.greaseweazle import error
|
|
15
|
+
from diskstack._vendor.greaseweazle.flux import Flux
|
|
16
|
+
from .image import Image
|
|
17
|
+
|
|
18
|
+
class A2RCapType:
|
|
19
|
+
timing = 1
|
|
20
|
+
bits = 2
|
|
21
|
+
xtiming = 3
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class A2RTrack:
|
|
25
|
+
|
|
26
|
+
def __init__(self, cyl: int, head: int, ps_per_tick: int):
|
|
27
|
+
self.cyl, self.head = cyl, head
|
|
28
|
+
self.sample_freq = 1e12 / ps_per_tick
|
|
29
|
+
self.caps: List[bytes] = list()
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def add_cap(self, cap) -> None:
|
|
33
|
+
self.caps.append(cap)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def best_cap(self) -> bytes:
|
|
37
|
+
# Look for a trace with two index pulses. This is correct for the
|
|
38
|
+
# claimed 2.25 revolutions of an index-cued xtiming capture.
|
|
39
|
+
for dat in self.caps:
|
|
40
|
+
if dat[4] == 2:
|
|
41
|
+
return dat
|
|
42
|
+
return self.caps[-1]
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def flux(self) -> Flux:
|
|
46
|
+
dat = self.best_cap()
|
|
47
|
+
|
|
48
|
+
# Decode the index list.
|
|
49
|
+
nidx = dat[4]
|
|
50
|
+
i = 5+nidx*4
|
|
51
|
+
index_list = list(struct.unpack(f'<{nidx}I', dat[5:i]))
|
|
52
|
+
for i in range(len(index_list)-1, 0, -1):
|
|
53
|
+
index_list[i] -= index_list[i-1]
|
|
54
|
+
ncap, = struct.unpack('<I', dat[i:i+4])
|
|
55
|
+
i += 4
|
|
56
|
+
|
|
57
|
+
# Decode the flux list.
|
|
58
|
+
flux_list: List[float] = []
|
|
59
|
+
acc = 0
|
|
60
|
+
for f in dat[i:i+ncap]:
|
|
61
|
+
acc += f
|
|
62
|
+
if f != 255:
|
|
63
|
+
flux_list.append(acc)
|
|
64
|
+
acc = 0
|
|
65
|
+
if acc != 0:
|
|
66
|
+
flux_list.append(acc)
|
|
67
|
+
|
|
68
|
+
flux = Flux(index_list, flux_list, self.sample_freq)
|
|
69
|
+
return flux
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class A2R(Image):
|
|
73
|
+
|
|
74
|
+
read_only = True
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def __init__(self, name: str, _fmt) -> None:
|
|
78
|
+
self.to_track: Dict[Tuple[int,int], A2RTrack] = dict()
|
|
79
|
+
self.filename = name
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def process_rwcp(self, dat: bytes) -> None:
|
|
83
|
+
|
|
84
|
+
ps_per_tick, = struct.unpack('<I', dat[1:5])
|
|
85
|
+
i = 16
|
|
86
|
+
|
|
87
|
+
while dat[i] == ord('C'):
|
|
88
|
+
|
|
89
|
+
start = i
|
|
90
|
+
|
|
91
|
+
# Basic decoding, sufficient to skip unwanted capture types.
|
|
92
|
+
cap, loc, nidx = struct.unpack('<BHB', dat[i+1:i+5])
|
|
93
|
+
cyl, head = loc>>1, loc&1
|
|
94
|
+
i += 5 + nidx*4
|
|
95
|
+
ncap, = struct.unpack('<I', dat[i:i+4])
|
|
96
|
+
i += 4 + ncap
|
|
97
|
+
|
|
98
|
+
# Store away (x)timing captures for future decode.
|
|
99
|
+
if cap != A2RCapType.xtiming and cap != A2RCapType.timing:
|
|
100
|
+
continue
|
|
101
|
+
if not (cyl, head) in self.to_track:
|
|
102
|
+
t = A2RTrack(cyl, head, ps_per_tick)
|
|
103
|
+
self.to_track[cyl, head] = t
|
|
104
|
+
else:
|
|
105
|
+
t = self.to_track[cyl, head]
|
|
106
|
+
t.add_cap(dat[start:i])
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def from_bytes(self, dat: bytes) -> None:
|
|
110
|
+
|
|
111
|
+
error.check(dat[:8] == b'A2R3\xff\x0a\x0d\x0a',
|
|
112
|
+
'A2R: Invalid signature')
|
|
113
|
+
dat = dat[8:]
|
|
114
|
+
|
|
115
|
+
# Extract the RWCP chunk(s).
|
|
116
|
+
while len(dat) > 8:
|
|
117
|
+
id, sz = struct.unpack('<4sI', dat[:8])
|
|
118
|
+
dat = dat[8:]
|
|
119
|
+
if id == b'RWCP':
|
|
120
|
+
self.process_rwcp(dat)
|
|
121
|
+
dat = dat[sz:]
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def get_track(self, cyl: int, side: int) -> Optional[Flux]:
|
|
125
|
+
if not (cyl, side) in self.to_track:
|
|
126
|
+
return None
|
|
127
|
+
track = self.to_track[cyl, side]
|
|
128
|
+
return track.flux()
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
# Local variables:
|
|
132
|
+
# python-indent: 4
|
|
133
|
+
# End:
|