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
11pub struct PinGroup {
14 scanner: Rc<RefCell<PinScanner>>,
15 pins: Vec<PinGroupItem>,
16 mask: AccessMask,
17}
18
19#[derive(Debug)]
21pub struct PinGroupItem {
22 name: String,
23 pin_id: PinId,
24 writable: bool,
25}
26
27impl PinGroupItem {
28 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 pub fn name(&self) -> &str {
41 &self.name
42 }
43 pub fn pin_id(&self) -> &PinId {
45 &self.pin_id
46 }
47 pub fn writable(&self) -> bool {
49 self.writable
50 }
51
52 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 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 pub fn pin_ids(&self) -> impl Iterator<Item = &PinGroupItem> {
92 self.pins.iter()
93 }
94
95 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 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 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 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 pub fn update(&mut self) -> Result<(), Error> {
129 let mut scanner = self.scanner.try_borrow_mut()?;
130 scanner.update()
131 }
132
133 pub fn write_update(&mut self) -> Result<(), Error> {
135 let mut scanner = self.scanner.try_borrow_mut()?;
136 scanner.write_update()
137 }
138
139 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}