Skip to main content

jtag_scanner/
group.rs

1use std::{cell::RefCell, rc::Rc};
2
3use bitvec::{order::Lsb0, vec::BitVec};
4
5use crate::{
6    BsrEdit, BsrView, ChainView, Error,
7    ErrorKind::{self, PinGroupLimit},
8    PinId, PinScanner, PinState, TapCmd, TapInfo,
9};
10
11/// Groups pins and assign given names to each pin, restricting the
12/// usage of [PinScanner] within the group. Implements [PinGroup].
13pub struct PinGroup {
14    scanner: Rc<RefCell<PinScanner>>,
15    pins: Vec<PinGroupItem>,
16    mask: AccessMask,
17}
18
19/// Items required during construction of [PinGroup].
20#[derive(Debug)]
21pub struct PinGroupItem {
22    name: String,
23    pin_id: PinId,
24    writable: bool,
25}
26
27impl PinGroupItem {
28    /// Creates an item.
29    /// - `name`: the given name for the pin, like `MISO`, `SCK`, or `D0`.
30    /// - `writable`: whether write access is allowed for this pin.
31    pub fn new(name: &str, pin_id: PinId, writable: bool) -> Self {
32        Self {
33            name: name.to_string().trim().to_uppercase(),
34            pin_id,
35            writable,
36        }
37    }
38
39    /// The given name.
40    pub fn name(&self) -> &str {
41        &self.name
42    }
43    /// The ID for the actual pin in the current chain.
44    pub fn pin_id(&self) -> &PinId {
45        &self.pin_id
46    }
47    /// True if write access should be enabled in the group.
48    pub fn writable(&self) -> bool {
49        self.writable
50    }
51
52    /// Returns true if `self` and `other` cannot exist in the same group.
53    pub fn conflicts_with(&self, other: &PinGroupItem) -> bool {
54        self.name == other.name || self.pin_id == other.pin_id
55    }
56}
57
58impl PinGroup {
59    /// Creates the [PinGroup] with the scanner managed by `Rc` of `RefCell`.
60    /// Multi-thread operation is unsupported.
61    ///
62    /// **WARNING**: This does not automatically check the added writable pins
63    /// against any existing pin group that has the same pin for write access.
64    /// This is intended for flexibility; check it manually if needed.
65    pub fn new(
66        scanner: &Rc<RefCell<PinScanner>>,
67        pins: impl IntoIterator<Item = PinGroupItem>,
68    ) -> Result<Self, Error> {
69        let sc = scanner.borrow();
70        let mut vec_pins = Vec::new();
71        let mut mask = AccessMask::new(sc.tap_infos());
72        for item in pins.into_iter() {
73            sc.verify_pin_id(&item.pin_id, item.writable)?;
74            if vec_pins
75                .iter()
76                .any(|existing| item.conflicts_with(existing))
77            {
78                return Err("duplicated pins in the supposed group".into());
79            }
80            mask.add_pin(&item.pin_id, item.writable);
81            vec_pins.push(item);
82        }
83        Ok(Self {
84            scanner: scanner.clone(),
85            pins: vec_pins,
86            mask,
87        })
88    }
89
90    /// Iterates through all [PinGroupItem]s in the group, with their given names.
91    pub fn pin_ids(&self) -> impl Iterator<Item = &PinGroupItem> {
92        self.pins.iter()
93    }
94
95    /// Checks if the pin is writable in this group.
96    pub fn pin_writable(&self, pin_id: &PinId) -> Result<bool, Error> {
97        self.pin_ids()
98            .find_map(|item| (&item.pin_id == pin_id).then_some(item.writable))
99            .ok_or(Error::new(PinGroupLimit, "this pin is not in the group"))
100    }
101
102    /// Gets a pin identifier by its name given in the group.
103    pub fn get_pin_id(&self, pin_name: &str) -> Result<PinId, Error> {
104        let pin_name = pin_name.trim().to_uppercase();
105        self.pin_ids()
106            .find(|item| item.name == pin_name)
107            .ok_or_else(|| "given name '{pin_name}' not found in group".into())
108            .map(|item| item.pin_id().clone())
109    }
110
111    /// Similar to [PinScanner::get_pin_state], disabling access to pins
112    /// outside the group.
113    pub fn get_pin_state(&self, pin_id: &PinId) -> Result<PinState, Error> {
114        let scanner = self.scanner.try_borrow()?;
115        let bsr_view = BsrView::new(&scanner, Some(&self.mask));
116        bsr_view.get(pin_id)
117    }
118
119    /// Similar to [PinScanner::set_pin_state], disabling access to pins
120    /// outside the group, or pins without write access.
121    pub fn set_pin_state(&mut self, pin_id: &PinId, new_state: Option<bool>) -> Result<(), Error> {
122        let mut scanner = self.scanner.try_borrow_mut()?;
123        let mut bsr_edit = BsrEdit::new(&mut scanner, Some(&self.mask));
124        bsr_edit.set(pin_id, new_state)
125    }
126
127    /// See [PinScanner::update].
128    pub fn update(&mut self) -> Result<(), Error> {
129        let mut scanner = self.scanner.try_borrow_mut()?;
130        scanner.update()
131    }
132
133    /// See [PinScanner::write_update]. Makes no sense without previous writes.
134    pub fn write_update(&mut self) -> Result<(), Error> {
135        let mut scanner = self.scanner.try_borrow_mut()?;
136        scanner.write_update()
137    }
138
139    /// Similar to [PinScanner::batch], disabling access to pins outside
140    /// the group; disables writes to pins without write access.
141    pub fn batch(
142        &mut self,
143        count: usize,
144        mut writer: impl FnMut(usize, &mut BsrEdit) -> Result<(), Error>,
145        mut reader: impl FnMut(usize, &BsrView) -> Result<(), Error>,
146    ) -> Result<(), Error> {
147        let mut scanner = self.scanner.try_borrow_mut()?;
148        scanner.batch_with_mask(
149            count,
150            |i, edit| writer(i, edit),
151            |i, view| reader(i, view),
152            Some(&self.mask),
153        )
154    }
155}
156
157pub(crate) struct AccessMask(Vec<BitVec<u8, Lsb0>>);
158
159impl AccessMask {
160    fn new(tap_infos: &[TapInfo]) -> Self {
161        let mut perm_mask = vec![BitVec::new(); tap_infos.len()];
162        for (i_tap, mask) in perm_mask.iter_mut().enumerate() {
163            mask.resize(tap_infos[i_tap].dr_len(TapCmd::Extest), false);
164        }
165        Self(perm_mask)
166    }
167
168    fn add_pin(&mut self, pin_id: &PinId, writable: bool) {
169        let mask = &mut self.0[pin_id.tap_index()];
170        if let Some(cell_i) = pin_id.cell_i() {
171            *mask.get_mut(cell_i).unwrap() = true;
172        }
173        if writable {
174            if let Some(cell_o) = pin_id.cell_o() {
175                *mask.get_mut(cell_o).unwrap() = true;
176            }
177        }
178    }
179
180    pub fn check_access(&self, pin_id: &PinId, for_write: bool) -> Result<(), Error> {
181        let mask = &self.0[pin_id.tap_index()];
182        let valid = if !for_write {
183            pin_id.cell_i().is_some_and(|i| mask[i])
184        } else {
185            pin_id.cell_o().is_some_and(|o| mask[o])
186        };
187        if valid {
188            Ok(())
189        } else {
190            Error::result(
191                ErrorKind::PinGroupLimit,
192                "operation not permitted by the pin group",
193            )
194        }
195    }
196}