1use crate::img;
19use crate::DYNERR;
20use crate::STDRESULT;
21use std::fmt;
22use std::str::FromStr;
23use std::collections::HashMap;
24use math_parse::MathParse;
25use bit_vec::BitVec;
26
27pub mod gcr;
28mod formats;
29mod parse_user_fmt;
30
31fn eval_u8(expr: &str,ctx: &std::collections::HashMap<String,String>) -> Result<u8,DYNERR> {
32 match MathParse::parse(expr) {
33 Ok(parsed) => match parsed.solve_int(Some(ctx)) {
34 Ok(ans) => match u8::try_from(ans) {
35 Ok(ans) => Ok(ans),
36 Err(_) => {
37 log::error!("{} evaluated to {} which is not a u8",expr,ans);
38 Err(Box::new(img::Error::MetadataMismatch))
39 }
40 }
41 Err(e) => {
42 log::error!("problem solving {}: {}",expr,e);
43 if expr.contains("/") && !expr.contains("//") {
44 log::warn!("floating point division detected in user expression, use `//` for integer division")
45 }
46 log::debug!("variables: {:?}",ctx);
47 Err(Box::new(img::Error::MetadataMismatch))
48 }
49 },
50 Err(e) => {
51 log::error!("problem parsing {}: {}",expr,e);
52 Err(Box::new(img::Error::MetadataMismatch))
53 }
54 }
55}
56
57fn estimate_bit_cell_duration(flux_timings: &[u8]) -> Option<usize> {
62 let min_frac = [1,5];
65 let mut histogram: Vec<usize> = vec![0;64];
66 let mut last = 0;
67 let mut total_counts = 0;
68 for dt in flux_timings {
69 if *dt < 64 && last != 255 {
70 histogram[*dt as usize] += 1;
71 total_counts += 1;
72 }
73 last = *dt;
74 }
75 let mut running_counts = 0;
76 for i in 0..64 {
77 running_counts += histogram[i];
78 if running_counts*min_frac[1] > total_counts*min_frac[0] {
79 return Some(i);
80 }
81 }
82 return None;
83}
84
85#[derive(Clone,PartialEq)]
86pub enum Method {
87 Auto,
89 Fast,
91 Analyze,
93 Emulate,
95}
96
97impl FromStr for Method {
98 type Err = super::Error;
99 fn from_str(s: &str) -> Result<Self,Self::Err> {
100 match s {
101 "auto" => Ok(Method::Auto),
102 "analyze" => Ok(Method::Analyze),
103 "fast" => Ok(Method::Fast),
104 "emulate" => Ok(Method::Emulate),
105 _ => Err(super::Error::MetadataMismatch)
106 }
107 }
108}
109
110impl fmt::Display for Method {
111 fn fmt(&self,f: &mut fmt::Formatter<'_>) -> fmt::Result {
112 match self {
113 Self::Auto => write!(f,"auto"),
114 Self::Analyze => write!(f,"analyze"),
115 Self::Emulate => write!(f,"emulate"),
116 Self::Fast => write!(f,"fast"),
117 }
118 }
119}
120
121pub struct FluxCells {
128 stream: BitVec,
130 ptr: usize,
132 time: u64,
134 revolution: usize,
136 tick_ps: usize,
138 fshift: usize,
140 fmask: usize,
142 bshift: usize,
144 bmask: usize,
146 recal: [usize;2]
148}
149
150impl FluxCells {
151 fn new_woz_bits(ptr: usize,stream: BitVec,time: u64,double_speed: bool) -> Self {
153 let shft = double_speed as usize;
154 let revolution = stream.len() << 5;
155 Self {
156 stream,
157 ptr,
158 time,
159 revolution,
160 tick_ps: 125000 >> shft,
161 fshift: 5,
162 fmask: (1 << 5) - 1,
163 bshift: 5,
164 bmask: (1 << 5) - 1,
165 recal: [1,1]
166 }
167 }
168 fn new_woz_flux(ptr: usize,stream: BitVec,time: u64,double_speed: bool,recal: [usize;2]) -> Self {
170 let shft = double_speed as usize;
171 let revolution = stream.len() << 2;
172 Self {
173 stream,
174 ptr,
175 time,
176 revolution,
177 tick_ps: 125000 >> shft,
178 fshift: 2,
179 fmask: (1 << 2) - 1,
180 bshift: 5,
181 bmask: (1 << 5) - 1,
182 recal
183 }
184 }
185 pub fn from_woz_bits(bit_count: usize,buf: &[u8],time: u64,double_speed: bool) -> Self {
187 let mut stream = BitVec::from_bytes(buf);
188 stream.truncate(bit_count);
189 Self::new_woz_bits(0,stream,time,double_speed)
190 }
191 pub fn from_woz_flux(byte_count: usize,buf: &[u8],time: u64,double_speed: bool) -> Self {
194 let mut recal = [1,1];
195 if let Some(median) = estimate_bit_cell_duration(&buf[0..byte_count]) {
196 log::trace!("bit cell is {}",median);
197 recal[0] = match double_speed { true => 0x10, false => 0x20};
198 recal[1] = median;
199 }
200 let ticks_per_cell = 4 >> double_speed as usize;
203 let mut stream = BitVec::new();
204 let mut write = |carryover0: &mut usize, carryover1: &mut usize| {
205 let ticks = *carryover0 + *carryover1;
206 let cells = ticks / ticks_per_cell;
207 for j in 0..cells {
208 stream.push(j==0 && *carryover1 > 0 || j==cells-1);
209 }
210 *carryover0 = (cells>0) as usize * (ticks % ticks_per_cell);
211 *carryover1 = (cells==0) as usize * (ticks % ticks_per_cell);
212 };
213 let mut carryover0 = 0;
214 let mut carryover1 = 0;
215 for segment in &buf[0..byte_count] {
216 carryover0 += *segment as usize * recal[0] / recal[1];
217 if *segment!=255 {
218 write(&mut carryover0,&mut carryover1);
219 }
220 }
221 write(&mut carryover0,&mut carryover1);
222 Self::new_woz_flux(0,stream,time,double_speed,recal)
223 }
224 pub fn change_resolution(&mut self,flux_shift: usize) {
227 if flux_shift == self.fshift {
228 return;
229 } else if flux_shift < self.fshift {
230 let factor = 1 << self.fshift >> flux_shift;
232 let mut new_stream = BitVec::new();
233 for bit in &self.stream {
234 new_stream.push(bit);
235 new_stream.append(&mut BitVec::from_elem(factor-1,false));
236 }
237 self.fshift = flux_shift;
238 self.fmask = (1 << flux_shift) - 1;
239 self.stream = new_stream;
240 } else {
241 let factor = 1 << flux_shift >> self.fshift;
243 let new_len = self.stream.len() << self.fshift >> flux_shift;
244 let mut new_stream = BitVec::new();
245 for i in 0..new_len {
246 let mut val = false;
247 for j in 0..factor {
248 val |= self.stream[i*factor+j];
249 }
250 new_stream.push(val);
251 }
252 self.fshift = flux_shift;
253 self.fmask = (1 << flux_shift) - 1;
254 self.stream = new_stream;
255 }
256 }
257 pub fn to_woz_buf(&self,padded_len: Option<usize>,padded_val: u8) -> (Vec<u8>,usize) {
264 let (mut buf,count) = if self.fshift==self.bshift {
265 (self.stream.to_bytes(),self.stream.len())
266 } else {
267 let mut zeroes = 0;
268 let ticks_per_cell = ((1 << self.fshift) * self.tick_ps / 125000) as u8;
269 let mut end = usize::MAX;
270 let mut buf = Vec::new();
271 for (i,cell) in self.stream.iter().rev().enumerate() {
274 if cell {
275 end = self.stream.len() - i;
276 break;
277 }
278 }
279 if end==usize::MAX {
280 log::info!("no flux transitions on track");
281 end = 1;
282 }
283 let mut iter_clos = |cell| {
284 if cell {
285 buf.push(zeroes + ticks_per_cell);
288 zeroes = 0;
289 } else {
290 zeroes += ticks_per_cell;
291 }
292 if zeroes >= 0xff {
293 buf.push(0xff);
294 zeroes = zeroes % 0xff;
295 }
296 };
297 for i in end..self.stream.len() {
298 iter_clos(self.stream[i]);
299 }
300 for i in 0..end {
301 iter_clos(self.stream[i]);
302 }
303 let count = buf.len();
304 (buf,count)
305 };
306 let padding = match (buf.len(),padded_len) {
307 (l,Some(tot)) if l<=tot => tot-l,
308 (l,Some(tot)) => panic!("buffer too small {}/{}",l,tot),
309 (l,_) if l==0 => 512,
310 (l,_) => ((l-1)/512)*512 + 512 - l
311 };
312 buf.append(&mut vec![padded_val;padding]);
313 (buf,count)
314 }
315 pub fn sync_to_other_track(&mut self,other: &FluxCells) {
318 self.ptr = (other.ptr * self.revolution / other.revolution) >> self.fshift << self.fshift;
319 }
320 pub fn count(&self) -> usize {
322 self.stream.len()
323 }
324 pub fn set_ptr(&mut self,ticks: usize) {
325 self.ptr = ticks;
326 }
327 pub fn fwd(&mut self,ticks: usize) {
329 self.ptr = (self.ptr + ticks) % self.revolution;
330 self.time += ticks as u64;
331 }
332 pub fn rev(&mut self,ticks: usize) {
335 self.ptr = (self.ptr + self.revolution - ticks) % self.revolution;
336 self.time -= match ticks as u64 > self.time {
337 true => self.time,
338 false => ticks as u64
339 };
340 }
341 pub fn ticks_since(&self,ref_tick: u64) -> u64 {
343 match ref_tick > self.time {
344 true => 0,
345 false => self.time - ref_tick
346 }
347 }
348 pub fn ps_since(&self,ref_tick: u64) -> u64 {
350 match ref_tick > self.time {
351 true => 0,
352 false => self.tick_ps as u64 * (self.time - ref_tick)
353 }
354
355 }
356 pub fn density(&self) -> Option<f64> {
359 if self.recal[1] > 0 && self.bshift != self.fshift {
360 Some(self.recal[0] as f64 / self.recal[1] as f64)
361 } else {
362 None
363 }
364 }
365 pub fn read_bit(&mut self) -> bool {
367 let cells_per_bit = 1 << self.bshift >> self.fshift;
368 let mut ans = false;
369 for _ in 0..cells_per_bit {
370 ans |= self.stream[self.ptr >> self.fshift];
371 self.fwd(1 << self.fshift);
372 }
373 ans
374 }
375 pub fn write_bit(&mut self,pulse: bool) {
377 let cells_per_bit = 1 << self.bshift >> self.fshift;
378 for _ in 0..cells_per_bit {
379 self.stream.set(self.ptr >> self.fshift,pulse && (self.ptr & self.bmask==0));
380 self.fwd(1 << self.fshift);
381 }
382 }
383}
384
385#[derive(Clone)]
388struct SectorMarker {
389 key: Vec<u8>,
390 mask: Vec<u8>,
391}
392
393#[derive(Clone)]
395pub struct ZoneFormat {
396 flux_code: img::FluxCode,
397 addr_nibs: img::FieldCode,
398 data_nibs: img::FieldCode,
399 speed_kbps: usize,
400 motor_start: usize,
401 motor_end: usize,
402 motor_step: usize,
403 heads: Vec<usize>,
404 addr_fmt_expr: Vec<String>,
408 addr_seek_expr: Vec<String>,
413 data_expr: Vec<String>,
417 markers: [SectorMarker; 4],
419 gaps: [BitVec; 3],
421 swap_nibs: Vec<[u8;2]>,
423 capacity: Vec<usize>
425}
426
427#[derive(Clone)]
429pub struct DiskFormat {
430 zones: Vec<ZoneFormat>
431}
432
433impl fmt::Display for img::Track {
434 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
435 match self {
436 Self::CH((c, h)) => write!(f, "cyl {} head {}", c, h),
437 Self::Motor((m, h)) => write!(f, "motor-pos {} head {}", m, h),
438 Self::Num(t) => write!(f, "track {}", t),
439 }
440 }
441}
442
443impl PartialOrd for img::Track {
444 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
445 match (self,other) {
446 (Self::CH(x),Self::CH(y)) => x.partial_cmp(y),
447 (Self::Motor(x),Self::Motor(y)) => x.partial_cmp(y),
448 (Self::Num(x),Self::Num(y)) => x.partial_cmp(y),
449 _ => None
450 }
451 }
452}
453
454impl img::Track {
455 pub fn jump(&mut self, cyls: isize, new_head: Option<usize>, steps_per_cyl: usize) -> STDRESULT {
457 match self {
458 Self::CH((c,h)) => {
459 *c = usize::try_from(*c as isize + cyls)?;
460 if let Some(head) = new_head {
461 *h = head;
462 }
463 Ok(())
464 },
465 Self::Motor((m,h)) => {
466 *m = usize::try_from(*m as isize + cyls * steps_per_cyl as isize)?;
467 if let Some(head) = new_head {
468 *h = head;
469 }
470 Ok(())
471 },
472 _ => Err(Box::new(crate::commands::CommandError::InvalidCommand))
473 }
474 }
475}
476
477impl img::Sector {
478 pub fn to_explicit(&mut self,hex_str: &str) -> STDRESULT {
480 let idx = match self {
481 Self::Num(n) => n,
482 Self::Addr((n,_)) => n
483 };
484 if hex_str.len() < 6 {
485 log::error!("sector address is too short");
486 return Err(Box::new(img::Error::SectorAccess));
487 }
488 *self = Self::Addr((*idx,hex::decode(hex_str)?));
489 Ok(())
490 }
491}
492
493impl fmt::Display for img::Sector {
494 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
495 match self {
496 Self::Num(n) => write!(f, "{}",n),
497 Self::Addr((n,a)) => write!(f, "{}:{:?}",n,a)
498 }
499 }
500}
501
502impl fmt::Display for img::SectorHood {
503 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
504 write!(f, "{},{},{},{}",self.vol,self.cyl,self.head,self.aux)
505 }
506}
507
508impl img::SectorHood {
509 fn get_fmt_vars(&self,sec: u8) -> Result<HashMap<String,String>,DYNERR> {
510 let mut ctx = HashMap::new();
511 ctx.insert("vol".to_string(),u8::to_string(&self.vol));
512 ctx.insert("cyl".to_string(),u8::to_string(&self.cyl));
513 ctx.insert("head".to_string(),u8::to_string(&self.head));
514 ctx.insert("sec".to_string(),u8::to_string(&sec));
515 ctx.insert("aux".to_string(),u8::to_string(&self.aux));
516 Ok(ctx)
517 }
518 fn get_seek_vars(&self,sec: u8,actual: &[u8]) -> Result<HashMap<String,String>,DYNERR> {
519 let mut ctx = HashMap::new();
520 ctx.insert("vol".to_string(),u8::to_string(&self.vol));
521 ctx.insert("cyl".to_string(),u8::to_string(&self.cyl));
522 ctx.insert("head".to_string(),u8::to_string(&self.head));
523 ctx.insert("sec".to_string(),u8::to_string(&sec));
524 ctx.insert("aux".to_string(),u8::to_string(&self.aux));
525 for i in 0..actual.len() {
526 ctx.insert(["a",&usize::to_string(&i)].concat(),u8::to_string(&actual[i]));
527 }
528 Ok(ctx)
529 }
530 pub fn head(&self) -> u8 {
531 self.head
532 }
533 pub fn a2_525(vol: u8,trk: u8) -> Self {
534 Self {
535 vol,
536 cyl: trk,
537 head: 0,
538 aux: 0
539 }
540 }
541 pub fn a2_35(cyl: u8,head: u8) -> Self {
542 Self {
543 vol: 0,
544 cyl,
545 head,
546 aux: 0
547 }
548 }
549 pub fn c64(cyl: u8,aux: u8) -> Self {
550 Self {
551 vol: 0,
552 cyl,
553 head: 0,
554 aux
555 }
556 }
557 pub fn ibm(cyl: u8,head: u8,aux: u8) -> Self {
558 Self {
559 vol: 0,
560 cyl,
561 head,
562 aux
563 }
564 }
565}
566
567impl ZoneFormat {
568 pub fn check_flux_code(&self,flux_code: img::FluxCode) -> STDRESULT {
569 if flux_code == self.flux_code {
570 Ok(())
571 } else {
572 Err(Box::new(super::Error::ImageTypeMismatch))
573 }
574 }
575 fn get_marker(&self, which: usize) -> (&[u8],&[u8]) {
577 (
578 &self.markers[which].key,
579 &self.markers[which].mask
580 )
581 }
582 fn get_gap_bits(&self, which: usize) -> &BitVec {
583 &self.gaps[which]
584 }
585 fn get_addr_for_formatting(&self,hood: &img::SectorHood,sec: &img::Sector) -> Result<Vec<u8>,DYNERR> {
590 match sec {
591 img::Sector::Addr((_,addr)) => {
592 let mut ans = addr.clone();
593 match (addr.len(),self.addr_nibs) {
594 (3,img::FieldCode::WOZ((4,4))) => ans.push(addr[0] ^ addr[1] ^ addr[2]),
595 (4,img::FieldCode::WOZ((6,2))) => ans.push((addr[0] ^ addr[1] ^ addr[2] ^ addr[3]) & 63),
596 _ => {}
597 }
598 Ok(ans)
599 },
600 img::Sector::Num(sec) => {
601 let mut ans = Vec::new();
602 let ctx = hood.get_fmt_vars((*sec).try_into()?)?;
603 for expr in &self.addr_fmt_expr {
604 ans.push(eval_u8(expr,&ctx)?);
605 }
606 Ok(ans)
607 }
608 }
609 }
610 fn get_addr_for_seeking(&self,hood: &img::SectorHood,sec: &img::Sector,actual: &[u8]) -> Result<Vec<u8>,DYNERR> {
615 match sec {
616 img::Sector::Addr((_,addr)) => {
617 let mut ans = addr.clone();
618 match (addr.len(),self.addr_nibs) {
619 (3,img::FieldCode::WOZ((4,4))) => ans.push(addr[0] ^ addr[1] ^ addr[2]),
620 (4,img::FieldCode::WOZ((6,2))) => ans.push((addr[0] ^ addr[1] ^ addr[2] ^ addr[3]) & 63),
621 _ => {}
622 }
623 Ok(ans)
624 },
625 img::Sector::Num(sec) => {
626 let mut ans = Vec::new();
627 let ctx = hood.get_seek_vars((*sec).try_into()?,actual)?;
628 for expr in &self.addr_seek_expr {
629 ans.push(eval_u8(expr,&ctx)?);
630 }
631 Ok(ans)
632 }
633 }
634 }
635 fn diff_addr(&self, hood: &img::SectorHood, sec: &img::Sector, actual: &[u8]) -> Result<Vec<u8>,DYNERR> {
638 let mut ans = Vec::new();
639 let pattern = self.get_addr_for_seeking(hood,sec,actual)?;
640 if pattern.len() != actual.len() {
641 log::error!("lengths did not match during address comparison");
642 return Err(Box::new(super::Error::SectorAccess));
643 }
644 for i in 0..pattern.len() {
645 ans.push(actual[i] ^ pattern[i]);
646 }
647 Ok(ans)
648 }
649 fn get_data_header(&self,hood: &img::SectorHood,sec: &img::Sector) -> Result<Vec<u8>,DYNERR> {
651 let idx = match sec {
652 img::Sector::Addr((n,_)) => *n,
653 img::Sector::Num(n) => *n
654 };
655 let mut ans = Vec::new();
656 let ctx = hood.get_fmt_vars((idx).try_into()?)?;
657 for expr in &self.data_expr {
659 if expr == "dat" {
660 return Ok(ans);
661 } else {
662 ans.push(eval_u8(expr,&ctx)?);
663 }
664 }
665 Ok(ans)
666 }
667 pub fn addr_nibs(&self) -> img::FieldCode {
668 self.addr_nibs
669 }
670 fn data_nibs(&self) -> img::FieldCode {
671 self.data_nibs
672 }
673 fn capacity(&self,sec: &img::Sector) -> usize {
677 let idx = match sec {
678 img::Sector::Addr((n,_)) => *n,
679 img::Sector::Num(n) => *n
680 };
681 self.capacity[idx % self.capacity.len()]
682 }
683 pub fn sector_count(&self) -> usize {
684 self.capacity.len()
685 }
686 pub fn track_solution(&self,addr_map: Vec<[u8;6]>,size_map: Vec<usize>,addr_type: &str,addr_mask: [u8;6],density: Option<f64>) -> img::TrackSolution {
687 img::TrackSolution::Solved(img::SolvedTrack {
688 speed_kbps: self.speed_kbps,
689 density,
690 flux_code: self.flux_code,
691 addr_code: self.addr_nibs,
692 data_code: self.data_nibs,
693 addr_type: addr_type.to_string(),
694 addr_mask,
695 addr_map,
696 size_map
697 })
698 }
699 fn chk_marker(&self, i: usize, win: &[u8;5], which: usize, mnemonic: &[char], fallback: char, last_marker: &mut usize, last_marker_end: &mut usize) -> char {
702 let count = usize::min(3,self.markers[which].key.len());
703 for stage in 0..count {
704 let mut matching = true;
705 for i in 0..count {
706 let y = self.markers[which].key[i];
707 let mask = self.markers[which].mask[i];
708 matching &= win[2-stage+i] & mask == y & mask;
709 }
710 if matching {
711 if stage+1==count {
712 *last_marker += 1;
713 *last_marker_end = i + 1;
714 if *last_marker > 3 {
715 *last_marker = 0;
716 }
717 }
718 return mnemonic[stage%mnemonic.len()];
719 }
720 }
721 fallback
722 }
723 pub fn woz_mnemonic(&self,buf: &[u8],i: usize,last_marker: &mut usize,last_marker_end: &mut usize) -> char {
727 let hexdigit = |x| match x {
728 x if x < 10 => char::from_u32(x as u32 + 48).unwrap_or('^'),
729 x if x < 16 => char::from_u32(x as u32 + 87).unwrap_or('^'),
730 _ => '^'
731 };
732 let addr_nib_count = match self.addr_nibs() {
733 img::FieldCode::WOZ((4,4)) => 2*self.addr_fmt_expr.len(),
734 _ => self.addr_fmt_expr.len()
735 };
736 let data_nib_count = match (self.capacity(&img::Sector::Num(0)),self.data_nibs()) {
737 (256,img::FieldCode::WOZ((4,4))) => 512,
738 (256,img::FieldCode::WOZ((5,3))) => 411,
739 (256,img::FieldCode::WOZ((6,2))) => 343,
740 (524,img::FieldCode::WOZ((6,2))) => 703,
741 _ => 343
742 };
743 let mut win = [0;5];
744 for rel in 0..5 {
745 let abs = i as isize - 2 + rel;
746 if abs >= 0 && abs < buf.len() as isize {
747 win[rel as usize] = buf[abs as usize];
748 }
749 }
750 let invalid = gcr::decode(buf[i] as usize + 0xaa00, &self.data_nibs).is_err();
751 let mut fallback = match (invalid,buf[i]) {
752 (true,0xd5) => 'R',
753 (true,0xaa) => 'R',
754 (true,_) => '?',
755 _ => '.'
756 };
757 if *last_marker == 2 && i > *last_marker_end + 40 {
759 *last_marker = 0;
760 }
761 if *last_marker == 0 {
762 if win[2] == 0xff {
764 fallback = '>';
765 }
766 self.chk_marker(i,&win,0,&['(','A',':'],fallback,last_marker,last_marker_end)
767 } else if *last_marker==1 && i < *last_marker_end + addr_nib_count {
768 match self.addr_nibs() {
770 img::FieldCode::WOZ((4,4)) => {
771 if (i-*last_marker_end)%2 == 0 {
772 let val = buf[i] as usize * 256 + win[3] as usize;
773 hexdigit(gcr::decode(val,&self.addr_nibs).unwrap_or(0) >> 4)
774 } else {
775 let val = win[1] as usize * 256 + buf[i] as usize;
776 hexdigit(gcr::decode(val,&self.addr_nibs).unwrap_or(0) & 0x0f)
777 }
778 },
779 _ => hexdigit(gcr::decode(buf[i] as usize,&self.addr_nibs).unwrap_or(0))
780 }
781 } else if *last_marker==1 {
782 self.chk_marker(i,&win,1,&[':','A',')'],fallback,last_marker,last_marker_end)
784 } else if *last_marker==2 {
785 if win[2] == 0xff {
787 fallback = '>';
788 }
789 self.chk_marker(i,&win,2,&['(','D',':'],fallback,last_marker,last_marker_end)
790 } else if *last_marker==3 && i < *last_marker_end + data_nib_count {
791 fallback
793 } else if *last_marker==3 {
794 self.chk_marker(i,&win,3,&[':','D',')'],fallback,last_marker,last_marker_end)
796 } else {
797 fallback
798 }
799 }
800}
801
802pub fn get_zone_fmt<'a>(motor: usize,head: usize,fmt: &'a Option<DiskFormat>) -> Result<&'a ZoneFormat,DYNERR> {
804 match fmt {
805 Some(f) => Ok(f.get_zone_fmt(motor,head)?),
806 None => Err(Box::new(img::Error::UnknownFormat))
807 }
808}
809
810impl<'a> DiskFormat {
811 pub fn get_zone_fmt(&'a self,motor: usize,head: usize) -> Result<&'a ZoneFormat,DYNERR> {
812 for zone in &self.zones {
813 if motor >= zone.motor_start && motor < zone.motor_end && zone.heads.contains(&head) {
814 return Ok(zone)
815 }
816 }
817 log::info!("zone at motor pos {} not found",motor);
818 return Err(Box::new(super::Error::UnexpectedZone))
819 }
820 pub fn get_motor_and_head(&self) -> Vec<(usize,usize)> {
822 let mut ans = Vec::new();
823 for zone in &self.zones {
824 for m in (zone.motor_start..zone.motor_end).step_by(zone.motor_step) {
825 for h in &zone.heads {
826 ans.push((m,*h));
827 }
828 }
829 }
830 ans
831 }
832}