1use std::cell::Cell;
4use std::collections::{HashMap, HashSet, hash_map::Entry as HashMapEntry};
5
6use tracing::{debug, trace, warn};
7use viva_genapi_xml::{
8 AccessMode, Addressing, EnumEntryDecl, EnumValueSrc, FloatEncoding, NodeDecl, PredicateRefs,
9 Visibility, XmlModel,
10};
11
12use crate::bitops::{extract, insert};
13use crate::conversions::{
14 apply_scale, bytes_to_i64, decode_ieee754, encode_bitfield_value, encode_float, encode_ieee754,
15 get_raw_or_read, i64_to_bytes, interpret_bitfield_value, map_bitops_error, round_to_i64,
16};
17use crate::nodes::{
18 BooleanNode, CategoryNode, CommandNode, ConverterNode, EnumMapping, EnumNode, FloatNode,
19 IntConverterNode, IntegerNode, Node, SkNode, StringNode,
20};
21use crate::swissknife::{
22 EvalError as SkEvalError, collect_identifiers, evaluate as eval_ast, parse_expression,
23};
24use crate::{GenApiError, RegisterIo, SkOutput};
25
26#[derive(Debug)]
29pub struct NodeMap {
30 version: String,
31 nodes: HashMap<String, Node>,
32 dependents: HashMap<String, Vec<String>>,
33 generation: Cell<u64>,
34}
35
36fn register_addressing_dependency(
37 dependents: &mut HashMap<String, Vec<String>>,
38 node_name: &str,
39 addressing: &Addressing,
40) {
41 match addressing {
42 Addressing::Fixed { .. } => {}
43 Addressing::BySelector { selector, .. } => {
44 dependents
45 .entry(selector.clone())
46 .or_default()
47 .push(node_name.to_string());
48 }
49 Addressing::Indirect { p_address_node, .. } => {
50 dependents
51 .entry(p_address_node.clone())
52 .or_default()
53 .push(node_name.to_string());
54 }
55 }
56}
57
58fn register_predicate_dependencies(
59 dependents: &mut HashMap<String, Vec<String>>,
60 node_name: &str,
61 predicates: &PredicateRefs,
62) {
63 for provider in predicates.references() {
64 dependents
65 .entry(provider.to_string())
66 .or_default()
67 .push(node_name.to_string());
68 }
69}
70
71fn ensure_readable(access: &AccessMode, name: &str) -> Result<(), GenApiError> {
72 if matches!(access, AccessMode::WO) {
73 return Err(GenApiError::Access(name.to_string()));
74 }
75 Ok(())
76}
77
78fn ensure_writable(access: &AccessMode, name: &str) -> Result<(), GenApiError> {
79 if matches!(access, AccessMode::RO) {
80 return Err(GenApiError::Access(name.to_string()));
81 }
82 Ok(())
83}
84
85impl NodeMap {
86 pub fn version(&self) -> &str {
88 &self.version
89 }
90
91 pub fn node(&self, name: &str) -> Option<&Node> {
93 self.nodes.get(name)
94 }
95
96 pub fn node_names(&self) -> impl Iterator<Item = &str> {
98 self.nodes.keys().map(|s| s.as_str())
99 }
100
101 pub fn dependents(&self, name: &str) -> &[String] {
105 self.dependents
106 .get(name)
107 .map(|v| v.as_slice())
108 .unwrap_or(&[])
109 }
110
111 pub fn categories(&self) -> Vec<(&str, &[String])> {
113 self.nodes
114 .values()
115 .filter_map(|node| match node {
116 Node::Category(cat) => Some((cat.name.as_str(), cat.children.as_slice())),
117 _ => None,
118 })
119 .collect()
120 }
121
122 pub fn nodes_at_visibility(&self, level: Visibility) -> Vec<&str> {
127 self.nodes
128 .iter()
129 .filter(|(_, node)| node.visibility() <= level)
130 .map(|(name, _)| name.as_str())
131 .collect()
132 }
133
134 pub fn try_from_xml(model: XmlModel) -> Result<Self, GenApiError> {
136 let mut nodes = HashMap::new();
137 let mut dependents: HashMap<String, Vec<String>> = HashMap::new();
138 for decl in model.nodes {
139 match decl {
140 NodeDecl::Integer {
141 name,
142 meta,
143 addressing,
144 len,
145 access,
146 min,
147 max,
148 inc,
149 unit,
150 bitfield,
151 selectors,
152 selected_if,
153 pvalue,
154 p_max,
155 p_min,
156 value,
157 predicates,
158 } => {
159 if let Some(ref addr) = addressing {
160 register_addressing_dependency(&mut dependents, &name, addr);
161 }
162 if let Some(ref pv) = pvalue {
163 dependents.entry(pv.clone()).or_default().push(name.clone());
164 }
165 if let Some(ref pm) = p_max {
166 dependents.entry(pm.clone()).or_default().push(name.clone());
167 }
168 if let Some(ref pm) = p_min {
169 dependents.entry(pm.clone()).or_default().push(name.clone());
170 }
171 for (selector, _) in &selected_if {
172 dependents
173 .entry(selector.clone())
174 .or_default()
175 .push(name.clone());
176 }
177 register_predicate_dependencies(&mut dependents, &name, &predicates);
178 let node = IntegerNode {
179 name: name.clone(),
180 meta,
181 addressing,
182 len,
183 access,
184 min,
185 max,
186 inc,
187 unit,
188 bitfield,
189 selectors,
190 selected_if,
191 pvalue,
192 p_max,
193 p_min,
194 value,
195 predicates,
196 cache: std::cell::RefCell::new(None),
197 raw_cache: std::cell::RefCell::new(None),
198 };
199 nodes.insert(name, Node::Integer(node));
200 }
201 NodeDecl::Float {
202 name,
203 meta,
204 addressing,
205 access,
206 min,
207 max,
208 unit,
209 scale,
210 offset,
211 selectors,
212 selected_if,
213 pvalue,
214 encoding,
215 byte_order,
216 predicates,
217 } => {
218 if let Some(ref addr) = addressing {
219 register_addressing_dependency(&mut dependents, &name, addr);
220 }
221 if let Some(ref pv) = pvalue {
222 dependents.entry(pv.clone()).or_default().push(name.clone());
223 }
224 for (selector, _) in &selected_if {
225 dependents
226 .entry(selector.clone())
227 .or_default()
228 .push(name.clone());
229 }
230 register_predicate_dependencies(&mut dependents, &name, &predicates);
231 let node = FloatNode {
232 name: name.clone(),
233 meta,
234 addressing,
235 access,
236 min,
237 max,
238 unit,
239 scale,
240 offset,
241 selectors,
242 selected_if,
243 pvalue,
244 encoding,
245 byte_order,
246 predicates,
247 cache: std::cell::RefCell::new(None),
248 };
249 nodes.insert(name, Node::Float(node));
250 }
251 NodeDecl::Enum {
252 name,
253 meta,
254 addressing,
255 access,
256 entries,
257 default,
258 selectors,
259 selected_if,
260 pvalue,
261 predicates,
262 } => {
263 if let Some(ref addr) = addressing {
264 register_addressing_dependency(&mut dependents, &name, addr);
265 }
266 if let Some(ref pv) = pvalue {
267 dependents.entry(pv.clone()).or_default().push(name.clone());
268 }
269 for (selector, _) in &selected_if {
270 dependents
271 .entry(selector.clone())
272 .or_default()
273 .push(name.clone());
274 }
275 register_predicate_dependencies(&mut dependents, &name, &predicates);
276 let mut providers = Vec::new();
277 let mut provider_set = HashSet::new();
278 for entry in &entries {
279 if let EnumValueSrc::FromNode(node_name) = &entry.value {
280 dependents
281 .entry(node_name.clone())
282 .or_default()
283 .push(name.clone());
284 if provider_set.insert(node_name.clone()) {
285 providers.push(node_name.clone());
286 }
287 }
288 register_predicate_dependencies(&mut dependents, &name, &entry.predicates);
289 }
290 providers.sort();
291 let node = EnumNode {
292 name: name.clone(),
293 meta,
294 addressing,
295 access,
296 pvalue,
297 entries,
298 default,
299 selectors,
300 selected_if,
301 providers,
302 predicates,
303 value_cache: std::cell::RefCell::new(None),
304 mapping_cache: std::cell::RefCell::new(None),
305 };
306 nodes.insert(name, Node::Enum(node));
307 }
308 NodeDecl::Boolean {
309 name,
310 meta,
311 addressing,
312 len,
313 access,
314 bitfield,
315 selectors,
316 selected_if,
317 pvalue,
318 on_value,
319 off_value,
320 predicates,
321 } => {
322 if let Some(ref addr) = addressing {
323 register_addressing_dependency(&mut dependents, &name, addr);
324 }
325 if let Some(ref pv) = pvalue {
326 dependents.entry(pv.clone()).or_default().push(name.clone());
327 }
328 for (selector, _) in &selected_if {
329 dependents
330 .entry(selector.clone())
331 .or_default()
332 .push(name.clone());
333 }
334 register_predicate_dependencies(&mut dependents, &name, &predicates);
335 let node = BooleanNode {
336 name: name.clone(),
337 meta,
338 addressing,
339 len,
340 access,
341 bitfield,
342 selectors,
343 selected_if,
344 pvalue,
345 on_value,
346 off_value,
347 predicates,
348 cache: std::cell::RefCell::new(None),
349 raw_cache: std::cell::RefCell::new(None),
350 };
351 nodes.insert(name, Node::Boolean(node));
352 }
353 NodeDecl::Command {
354 name,
355 meta,
356 address,
357 len,
358 pvalue,
359 command_value,
360 predicates,
361 } => {
362 if let Some(ref pv) = pvalue {
363 dependents.entry(pv.clone()).or_default().push(name.clone());
364 }
365 register_predicate_dependencies(&mut dependents, &name, &predicates);
366 let node = CommandNode {
367 name: name.clone(),
368 meta,
369 address,
370 len,
371 pvalue,
372 command_value,
373 predicates,
374 };
375 nodes.insert(name, Node::Command(node));
376 }
377 NodeDecl::Category {
378 name,
379 meta,
380 children,
381 predicates,
382 } => {
383 register_predicate_dependencies(&mut dependents, &name, &predicates);
384 let node = CategoryNode {
385 name: name.clone(),
386 meta,
387 children,
388 predicates,
389 };
390 nodes.insert(name, Node::Category(node));
391 }
392 NodeDecl::SwissKnife(decl) => {
393 let name = decl.name;
394 let meta = decl.meta;
395 let expr = decl.expr;
396 let variables = decl.variables;
397 let output = decl.output;
398 let predicates = decl.predicates;
399 let ast = parse_expression(&expr).map_err(|err| GenApiError::ExprParse {
400 name: name.clone(),
401 msg: err.to_string(),
402 })?;
403 let mut used = HashSet::new();
404 collect_identifiers(&ast, &mut used);
405 for ident in &used {
406 if !variables.iter().any(|(var, _)| var == ident) {
407 return Err(GenApiError::UnknownVariable {
408 name: name.clone(),
409 var: ident.clone(),
410 });
411 }
412 }
413 for (_, provider) in &variables {
414 dependents
415 .entry(provider.clone())
416 .or_default()
417 .push(name.clone());
418 }
419 register_predicate_dependencies(&mut dependents, &name, &predicates);
420 let node = SkNode {
421 name: name.clone(),
422 meta,
423 output,
424 ast,
425 vars: variables,
426 predicates,
427 cache: std::cell::RefCell::new(None),
428 };
429 nodes.insert(name, Node::SwissKnife(node));
430 }
431 NodeDecl::Converter(decl) => {
432 let name = decl.name;
433 let ast_to = parse_expression(&decl.formula_to).map_err(|err| {
434 GenApiError::ExprParse {
435 name: name.clone(),
436 msg: format!("FormulaTo: {err}"),
437 }
438 })?;
439 let ast_from = parse_expression(&decl.formula_from).map_err(|err| {
440 GenApiError::ExprParse {
441 name: name.clone(),
442 msg: format!("FormulaFrom: {err}"),
443 }
444 })?;
445 for (_, provider) in &decl.variables_to {
447 dependents
448 .entry(provider.clone())
449 .or_default()
450 .push(name.clone());
451 }
452 for (_, provider) in &decl.variables_from {
453 if !decl.variables_to.iter().any(|(_, p)| p == provider) {
454 dependents
455 .entry(provider.clone())
456 .or_default()
457 .push(name.clone());
458 }
459 }
460 dependents
462 .entry(decl.p_value.clone())
463 .or_default()
464 .push(name.clone());
465 register_predicate_dependencies(&mut dependents, &name, &decl.predicates);
466 let node = ConverterNode {
467 name: name.clone(),
468 meta: decl.meta,
469 p_value: decl.p_value,
470 ast_to,
471 ast_from,
472 vars_to: decl.variables_to,
473 vars_from: decl.variables_from,
474 unit: decl.unit,
475 output: decl.output,
476 predicates: decl.predicates,
477 cache: std::cell::RefCell::new(None),
478 };
479 nodes.insert(name, Node::Converter(node));
480 }
481 NodeDecl::IntConverter(decl) => {
482 let name = decl.name;
483 let ast_to = parse_expression(&decl.formula_to).map_err(|err| {
484 GenApiError::ExprParse {
485 name: name.clone(),
486 msg: format!("FormulaTo: {err}"),
487 }
488 })?;
489 let ast_from = parse_expression(&decl.formula_from).map_err(|err| {
490 GenApiError::ExprParse {
491 name: name.clone(),
492 msg: format!("FormulaFrom: {err}"),
493 }
494 })?;
495 for (_, provider) in &decl.variables_to {
496 dependents
497 .entry(provider.clone())
498 .or_default()
499 .push(name.clone());
500 }
501 for (_, provider) in &decl.variables_from {
502 if !decl.variables_to.iter().any(|(_, p)| p == provider) {
503 dependents
504 .entry(provider.clone())
505 .or_default()
506 .push(name.clone());
507 }
508 }
509 dependents
510 .entry(decl.p_value.clone())
511 .or_default()
512 .push(name.clone());
513 register_predicate_dependencies(&mut dependents, &name, &decl.predicates);
514 let node = IntConverterNode {
515 name: name.clone(),
516 meta: decl.meta,
517 p_value: decl.p_value,
518 ast_to,
519 ast_from,
520 vars_to: decl.variables_to,
521 vars_from: decl.variables_from,
522 unit: decl.unit,
523 predicates: decl.predicates,
524 cache: std::cell::RefCell::new(None),
525 };
526 nodes.insert(name, Node::IntConverter(node));
527 }
528 NodeDecl::String(decl) => {
529 let name = decl.name;
530 register_addressing_dependency(&mut dependents, &name, &decl.addressing);
531 register_predicate_dependencies(&mut dependents, &name, &decl.predicates);
532 let node = StringNode {
533 name: name.clone(),
534 meta: decl.meta,
535 addressing: decl.addressing,
536 access: decl.access,
537 predicates: decl.predicates,
538 cache: std::cell::RefCell::new(None),
539 };
540 nodes.insert(name, Node::String(node));
541 }
542 }
543 }
544
545 Ok(NodeMap {
546 version: model.version,
547 nodes,
548 dependents,
549 generation: Cell::new(0),
550 })
551 }
552
553 pub fn get_integer(&self, name: &str, io: &dyn RegisterIo) -> Result<i64, GenApiError> {
555 if let Some(output) = self.nodes.get(name).and_then(|node| match node {
556 Node::SwissKnife(sk) => Some(sk.output),
557 _ => None,
558 }) {
559 return match output {
560 SkOutput::Integer => {
561 let node = match self.nodes.get(name) {
562 Some(Node::SwissKnife(node)) => node,
563 _ => unreachable!("node vanished during lookup"),
564 };
565 let mut stack = HashSet::new();
566 let value = self.evaluate_swissknife(node, io, &mut stack)?;
567 round_to_i64(name, value)
568 }
569 SkOutput::Float => Err(GenApiError::Type(name.to_string())),
570 };
571 }
572 let node = self.get_integer_node(name)?;
573 ensure_readable(&node.access, name)?;
574 self.ensure_selectors(name, &node.selected_if, io)?;
575 if let Some(v) = node.value {
577 return Ok(v);
578 }
579 if let Some(ref pv) = node.pvalue {
581 let pv = pv.clone();
582 return self.get_integer(&pv, io);
583 }
584 let addressing = node
585 .addressing
586 .as_ref()
587 .ok_or_else(|| GenApiError::NodeNotFound(format!("{name}: no addressing or pValue")))?;
588 let (address, len) = self.resolve_address(name, addressing, io)?;
589 if let Some(value) = *node.cache.borrow() {
590 return Ok(value);
591 }
592 let raw = io.read(address, len as usize).map_err(|err| match err {
593 GenApiError::Io(_) => err,
594 other => other,
595 })?;
596 let value = if let Some(bitfield) = node.bitfield {
597 let extracted = extract(&raw, bitfield).map_err(|err| map_bitops_error(name, err))?;
598 interpret_bitfield_value(name, extracted, bitfield.bit_length, node.min < 0)?
599 } else {
600 bytes_to_i64(name, &raw)?
601 };
602 debug!(node = %name, raw = value, "read integer feature");
603 node.cache.replace(Some(value));
604 node.raw_cache.replace(Some(raw));
605 Ok(value)
606 }
607
608 pub fn set_integer(
610 &mut self,
611 name: &str,
612 value: i64,
613 io: &dyn RegisterIo,
614 ) -> Result<(), GenApiError> {
615 let node = self.get_integer_node(name)?;
616 ensure_writable(&node.access, name)?;
617 self.ensure_selectors(name, &node.selected_if, io)?;
618 if let Some(ref pv) = node.pvalue {
619 let pv = pv.clone();
620 return self.set_integer(&pv, value, io);
621 }
622 let addressing = node
623 .addressing
624 .as_ref()
625 .ok_or_else(|| GenApiError::NodeNotFound(format!("{name}: no addressing or pValue")))?;
626 let (address, len) = self.resolve_address(name, addressing, io)?;
627 if value < node.min || value > node.max {
628 return Err(GenApiError::Range(name.to_string()));
629 }
630 if let Some(inc) = node.inc
631 && inc != 0
632 && (value - node.min) % inc != 0
633 {
634 return Err(GenApiError::Range(name.to_string()));
635 }
636 if let Some(bitfield) = node.bitfield {
637 let encoded = encode_bitfield_value(name, value, bitfield.bit_length, node.min < 0)?;
638 let mut raw = get_raw_or_read(&node.raw_cache, io, address, len)?;
639 insert(&mut raw, bitfield, encoded).map_err(|err| map_bitops_error(name, err))?;
640 debug!(node = %name, raw = value, "write integer feature");
641 io.write(address, &raw).map_err(|err| match err {
642 GenApiError::Io(_) => err,
643 other => other,
644 })?;
645 node.cache.replace(Some(value));
646 node.raw_cache.replace(Some(raw));
647 } else {
648 let bytes = i64_to_bytes(name, value, len)?;
649 debug!(node = %name, raw = value, "write integer feature");
650 io.write(address, &bytes).map_err(|err| match err {
651 GenApiError::Io(_) => err,
652 other => other,
653 })?;
654 node.cache.replace(Some(value));
655 node.raw_cache.replace(Some(bytes));
656 }
657 self.invalidate_dependents(name);
658 Ok(())
659 }
660
661 pub fn get_float(&self, name: &str, io: &dyn RegisterIo) -> Result<f64, GenApiError> {
663 if let Some(output) = self.nodes.get(name).and_then(|node| match node {
664 Node::SwissKnife(sk) => Some(sk.output),
665 _ => None,
666 }) {
667 return match output {
668 SkOutput::Float => {
669 let node = match self.nodes.get(name) {
670 Some(Node::SwissKnife(node)) => node,
671 _ => unreachable!("node vanished during lookup"),
672 };
673 let mut stack = HashSet::new();
674 let value = self.evaluate_swissknife(node, io, &mut stack)?;
675 Ok(value)
676 }
677 SkOutput::Integer => self.get_integer(name, io).map(|v| v as f64),
678 };
679 }
680 let node = self.get_float_node(name)?;
681 ensure_readable(&node.access, name)?;
682 self.ensure_selectors(name, &node.selected_if, io)?;
683 if let Some(ref pv) = node.pvalue {
684 let pv = pv.clone();
685 return self.get_float(&pv, io);
686 }
687 let addressing = node
688 .addressing
689 .as_ref()
690 .ok_or_else(|| GenApiError::NodeNotFound(format!("{name}: no addressing or pValue")))?;
691 let (address, len) = self.resolve_address(name, addressing, io)?;
692 if let Some(value) = *node.cache.borrow() {
693 return Ok(value);
694 }
695 let raw = io.read(address, len as usize).map_err(|err| match err {
696 GenApiError::Io(_) => err,
697 other => other,
698 })?;
699 let value = match node.encoding {
700 FloatEncoding::Ieee754 => {
701 let v = decode_ieee754(name, &raw, node.byte_order)?;
702 debug!(node = %name, value = v, "read float feature (ieee754)");
703 v
704 }
705 FloatEncoding::ScaledInteger => {
706 let raw_value = bytes_to_i64(name, &raw)?;
707 let v = apply_scale(node, raw_value as f64);
708 debug!(node = %name, raw = raw_value, value = v, "read float feature (scaled)");
709 v
710 }
711 };
712 node.cache.replace(Some(value));
713 Ok(value)
714 }
715
716 pub fn set_float(
718 &mut self,
719 name: &str,
720 value: f64,
721 io: &dyn RegisterIo,
722 ) -> Result<(), GenApiError> {
723 let node = self.get_float_node(name)?;
724 ensure_writable(&node.access, name)?;
725 self.ensure_selectors(name, &node.selected_if, io)?;
726 if let Some(ref pv) = node.pvalue {
727 let pv = pv.clone();
728 return self.set_float(&pv, value, io);
729 }
730 let addressing = node
731 .addressing
732 .as_ref()
733 .ok_or_else(|| GenApiError::NodeNotFound(format!("{name}: no addressing or pValue")))?;
734 let (address, len) = self.resolve_address(name, addressing, io)?;
735 if value < node.min || value > node.max {
736 return Err(GenApiError::Range(name.to_string()));
737 }
738 let bytes = match node.encoding {
739 FloatEncoding::Ieee754 => {
740 let bytes = encode_ieee754(name, value, len, node.byte_order)?;
741 debug!(node = %name, value, "write float feature (ieee754)");
742 bytes
743 }
744 FloatEncoding::ScaledInteger => {
745 let raw = encode_float(node, value)?;
746 let bytes = i64_to_bytes(name, raw, len)?;
747 debug!(node = %name, raw, value, "write float feature (scaled)");
748 bytes
749 }
750 };
751 io.write(address, &bytes).map_err(|err| match err {
752 GenApiError::Io(_) => err,
753 other => other,
754 })?;
755 node.cache.replace(Some(value));
756 self.invalidate_dependents(name);
757 Ok(())
758 }
759
760 pub fn get_enum(&self, name: &str, io: &dyn RegisterIo) -> Result<String, GenApiError> {
762 let node = self.get_enum_node(name)?;
763 ensure_readable(&node.access, name)?;
764 self.ensure_selectors(name, &node.selected_if, io)?;
765 if let Some(ref pv) = node.pvalue {
767 let pv = pv.clone();
768 if let Some(value) = node.value_cache.borrow().clone() {
769 return Ok(value);
770 }
771 let raw_value = self.get_integer(&pv, io)?;
772 let entry = self.lookup_enum_entry(node, raw_value, io)?;
773 node.value_cache.replace(Some(entry.clone()));
774 return Ok(entry);
775 }
776 let addressing = node
777 .addressing
778 .as_ref()
779 .ok_or_else(|| GenApiError::NodeNotFound(format!("{name}: no addressing")))?;
780 let (address, len) = self.resolve_address(name, addressing, io)?;
781 if let Some(value) = node.value_cache.borrow().clone() {
782 return Ok(value);
783 }
784 let raw = io.read(address, len as usize).map_err(|err| match err {
785 GenApiError::Io(_) => err,
786 other => other,
787 })?;
788 let raw_value = bytes_to_i64(name, &raw)?;
789 let entry = self.lookup_enum_entry(node, raw_value, io)?;
790 debug!(node = %name, raw = raw_value, entry = %entry, "read enum feature");
791 node.value_cache.replace(Some(entry.clone()));
792 Ok(entry)
793 }
794
795 pub fn set_enum(
797 &mut self,
798 name: &str,
799 entry: &str,
800 io: &dyn RegisterIo,
801 ) -> Result<(), GenApiError> {
802 let node = self.get_enum_node(name)?;
803 ensure_writable(&node.access, name)?;
804 self.ensure_selectors(name, &node.selected_if, io)?;
805 if let Some(ref pv) = node.pvalue {
806 let pv = pv.clone();
807 let entry_decl = node
808 .entries
809 .iter()
810 .find(|candidate| candidate.name == entry)
811 .ok_or_else(|| GenApiError::EnumNoSuchEntry {
812 node: name.to_string(),
813 entry: entry.to_string(),
814 })?;
815 let raw_value = self.resolve_enum_entry_value(node, entry_decl, io)?;
816 let entry_str = entry.to_string();
817 self.set_integer(&pv, raw_value, io)?;
819 let node = self.get_enum_node(name)?;
820 node.value_cache.replace(Some(entry_str));
821 node.invalidate();
822 self.invalidate_dependents(name);
823 return Ok(());
824 }
825 let addressing = node
826 .addressing
827 .as_ref()
828 .ok_or_else(|| GenApiError::NodeNotFound(format!("{name}: no addressing")))?;
829 let (address, len) = self.resolve_address(name, addressing, io)?;
830 let entry_decl = node
831 .entries
832 .iter()
833 .find(|candidate| candidate.name == entry)
834 .ok_or_else(|| GenApiError::EnumNoSuchEntry {
835 node: name.to_string(),
836 entry: entry.to_string(),
837 })?;
838 let raw = self.resolve_enum_entry_value(node, entry_decl, io)?;
839 let bytes = i64_to_bytes(name, raw, len)?;
840 debug!(node = %name, raw, entry, "write enum feature");
841 io.write(address, &bytes).map_err(|err| match err {
842 GenApiError::Io(_) => err,
843 other => other,
844 })?;
845 node.value_cache.replace(None);
846 self.invalidate_dependents(name);
847 Ok(())
848 }
849
850 pub fn enum_entries(&self, name: &str) -> Result<Vec<String>, GenApiError> {
852 let node = self.get_enum_node(name)?;
853 if let Some(mapping) = node.mapping_cache.borrow().as_ref() {
854 let mut names: Vec<_> = mapping.by_name.keys().cloned().collect();
855 names.sort();
856 names.dedup();
857 return Ok(names);
858 }
859 let mut names: Vec<_> = node
860 .entries
861 .iter()
862 .map(|entry| entry.name.clone())
863 .collect();
864 names.sort();
865 names.dedup();
866 Ok(names)
867 }
868
869 pub fn is_implemented(&self, name: &str, io: &dyn RegisterIo) -> Result<bool, GenApiError> {
877 let prefs = self.predicate_refs(name)?;
878 match &prefs.p_is_implemented {
879 None => Ok(true),
880 Some(provider) => self.eval_predicate_ref(name, provider, io),
881 }
882 }
883
884 pub fn is_available(&self, name: &str, io: &dyn RegisterIo) -> Result<bool, GenApiError> {
892 if !self.is_implemented(name, io)? {
893 return Ok(false);
894 }
895 let prefs = self.predicate_refs(name)?;
896 if let Some(provider) = &prefs.p_is_available
897 && !self.eval_predicate_ref(name, provider, io)?
898 {
899 return Ok(false);
900 }
901 let selected_if = self
902 .nodes
903 .get(name)
904 .and_then(Self::selected_if_slice)
905 .unwrap_or(&[]);
906 self.selectors_allow(selected_if, io)
907 }
908
909 pub fn effective_access_mode(
920 &self,
921 name: &str,
922 io: &dyn RegisterIo,
923 ) -> Result<AccessMode, GenApiError> {
924 let node = self
925 .nodes
926 .get(name)
927 .ok_or_else(|| GenApiError::NodeNotFound(name.to_string()))?;
928 let base = node.access_mode().unwrap_or(AccessMode::RO);
929 if !self.is_available(name, io)? {
930 return Ok(AccessMode::RO);
931 }
932 let prefs = self.predicate_refs(name)?;
933 if let Some(provider) = &prefs.p_is_locked
934 && self.eval_predicate_ref(name, provider, io)?
935 {
936 return Ok(match base {
937 AccessMode::RW => AccessMode::RO,
938 other => other,
939 });
940 }
941 Ok(base)
942 }
943
944 pub fn available_enum_entries(
953 &self,
954 name: &str,
955 io: &dyn RegisterIo,
956 ) -> Result<Vec<String>, GenApiError> {
957 let node = self.get_enum_node(name)?;
958 let any_entry_predicate = node.entries.iter().any(|e| !e.predicates.is_empty());
959 if !any_entry_predicate {
960 return self.enum_entries(name);
961 }
962 let mut out = Vec::new();
963 for entry in &node.entries {
964 if let Some(provider) = &entry.predicates.p_is_implemented
965 && !self.eval_predicate_ref(name, provider, io)?
966 {
967 continue;
968 }
969 if let Some(provider) = &entry.predicates.p_is_available
970 && !self.eval_predicate_ref(name, provider, io)?
971 {
972 continue;
973 }
974 out.push(entry.name.clone());
975 }
976 out.sort();
977 out.dedup();
978 Ok(out)
979 }
980
981 fn predicate_refs(&self, name: &str) -> Result<&PredicateRefs, GenApiError> {
982 self.nodes
983 .get(name)
984 .map(Node::predicates)
985 .ok_or_else(|| GenApiError::NodeNotFound(name.to_string()))
986 }
987
988 fn eval_predicate_ref(
997 &self,
998 ctx: &str,
999 provider: &str,
1000 io: &dyn RegisterIo,
1001 ) -> Result<bool, GenApiError> {
1002 if provider == ctx {
1003 return Err(GenApiError::ExprEval {
1004 name: ctx.to_string(),
1005 msg: "predicate references the node it gates".into(),
1006 });
1007 }
1008 let mut stack = HashSet::new();
1009 stack.insert(ctx.to_string());
1010 let value = self.resolve_numeric(provider, io, &mut stack)?;
1011 trace!(node = %ctx, provider, value, "predicate eval");
1012 Ok(value != 0.0)
1013 }
1014
1015 fn selectors_allow(
1019 &self,
1020 rules: &[(String, Vec<String>)],
1021 io: &dyn RegisterIo,
1022 ) -> Result<bool, GenApiError> {
1023 for (selector, allowed) in rules {
1024 if allowed.is_empty() {
1025 continue;
1026 }
1027 let current = self.get_selector_value(selector, io)?;
1028 if !allowed.iter().any(|v| v == ¤t) {
1029 return Ok(false);
1030 }
1031 }
1032 Ok(true)
1033 }
1034
1035 fn selected_if_slice(node: &Node) -> Option<&[(String, Vec<String>)]> {
1036 match node {
1037 Node::Integer(n) => Some(&n.selected_if),
1038 Node::Float(n) => Some(&n.selected_if),
1039 Node::Enum(n) => Some(&n.selected_if),
1040 Node::Boolean(n) => Some(&n.selected_if),
1041 _ => None,
1042 }
1043 }
1044
1045 pub fn get_bool(&self, name: &str, io: &dyn RegisterIo) -> Result<bool, GenApiError> {
1047 let node = self.get_bool_node(name)?;
1048 ensure_readable(&node.access, name)?;
1049 self.ensure_selectors(name, &node.selected_if, io)?;
1050 if let Some(ref pv) = node.pvalue {
1051 let pv = pv.clone();
1052 let raw = self.get_integer(&pv, io)?;
1053 let on = node.on_value.unwrap_or(1);
1054 return Ok(raw == on);
1055 }
1056 let addressing = node
1057 .addressing
1058 .as_ref()
1059 .ok_or_else(|| GenApiError::NodeNotFound(format!("{name}: no addressing or pValue")))?;
1060 let bitfield = node
1061 .bitfield
1062 .ok_or_else(|| GenApiError::Parse(format!("{name}: boolean without bitfield")))?;
1063 let (address, len) = self.resolve_address(name, addressing, io)?;
1064 if let Some(value) = *node.cache.borrow() {
1065 return Ok(value);
1066 }
1067 let raw = io.read(address, len as usize).map_err(|err| match err {
1068 GenApiError::Io(_) => err,
1069 other => other,
1070 })?;
1071 let raw_value = extract(&raw, bitfield).map_err(|err| map_bitops_error(name, err))?;
1072 let value = raw_value != 0;
1073 debug!(node = %name, raw = raw_value, value, "read boolean feature");
1074 node.cache.replace(Some(value));
1075 node.raw_cache.replace(Some(raw));
1076 Ok(value)
1077 }
1078
1079 pub fn set_bool(
1081 &mut self,
1082 name: &str,
1083 value: bool,
1084 io: &dyn RegisterIo,
1085 ) -> Result<(), GenApiError> {
1086 let node = self.get_bool_node(name)?;
1087 ensure_writable(&node.access, name)?;
1088 self.ensure_selectors(name, &node.selected_if, io)?;
1089 if let Some(ref pv) = node.pvalue {
1090 let pv = pv.clone();
1091 let on = node.on_value.unwrap_or(1);
1092 let off = node.off_value.unwrap_or(0);
1093 let raw = if value { on } else { off };
1094 return self.set_integer(&pv, raw, io);
1095 }
1096 let addressing = node
1097 .addressing
1098 .as_ref()
1099 .ok_or_else(|| GenApiError::NodeNotFound(format!("{name}: no addressing or pValue")))?;
1100 let bitfield = node
1101 .bitfield
1102 .ok_or_else(|| GenApiError::Parse(format!("{name}: boolean without bitfield")))?;
1103 let (address, len) = self.resolve_address(name, addressing, io)?;
1104 let encoded = if value { 1 } else { 0 };
1105 let mut raw = get_raw_or_read(&node.raw_cache, io, address, len)?;
1106 insert(&mut raw, bitfield, encoded).map_err(|err| map_bitops_error(name, err))?;
1107 debug!(node = %name, raw = encoded, value, "write boolean feature");
1108 io.write(address, &raw).map_err(|err| match err {
1109 GenApiError::Io(_) => err,
1110 other => other,
1111 })?;
1112 node.cache.replace(Some(value));
1113 node.raw_cache.replace(Some(raw));
1114 self.invalidate_dependents(name);
1115 Ok(())
1116 }
1117
1118 pub fn exec_command(&mut self, name: &str, io: &dyn RegisterIo) -> Result<(), GenApiError> {
1120 let node = self.get_command_node(name)?;
1121 let cmd_value = node.command_value.unwrap_or(1);
1123
1124 if let Some(ref pv) = node.pvalue {
1125 let pv = pv.clone();
1127 debug!(node = %name, "execute command via pValue");
1128 return self.set_integer(&pv, cmd_value, io);
1129 }
1130
1131 let address = node
1132 .address
1133 .ok_or_else(|| GenApiError::NodeNotFound(format!("{name}: no address or pValue")))?;
1134 if node.len == 0 {
1135 return Err(GenApiError::Parse(format!(
1136 "command node {name} has zero length"
1137 )));
1138 }
1139 let data = i64_to_bytes(name, cmd_value, node.len)?;
1140 debug!(node = %name, "execute command");
1141 io.write(address, &data).map_err(|err| match err {
1142 GenApiError::Io(_) => err,
1143 other => other,
1144 })?;
1145 self.invalidate_dependents(name);
1146 Ok(())
1147 }
1148
1149 fn get_integer_node(&self, name: &str) -> Result<&IntegerNode, GenApiError> {
1150 match self.nodes.get(name) {
1151 Some(Node::Integer(node)) => Ok(node),
1152 Some(_) => Err(GenApiError::Type(name.to_string())),
1153 None => Err(GenApiError::NodeNotFound(name.to_string())),
1154 }
1155 }
1156
1157 fn get_float_node(&self, name: &str) -> Result<&FloatNode, GenApiError> {
1158 match self.nodes.get(name) {
1159 Some(Node::Float(node)) => Ok(node),
1160 Some(_) => Err(GenApiError::Type(name.to_string())),
1161 None => Err(GenApiError::NodeNotFound(name.to_string())),
1162 }
1163 }
1164
1165 fn get_enum_node(&self, name: &str) -> Result<&EnumNode, GenApiError> {
1166 match self.nodes.get(name) {
1167 Some(Node::Enum(node)) => Ok(node),
1168 Some(_) => Err(GenApiError::Type(name.to_string())),
1169 None => Err(GenApiError::NodeNotFound(name.to_string())),
1170 }
1171 }
1172
1173 fn get_bool_node(&self, name: &str) -> Result<&BooleanNode, GenApiError> {
1174 match self.nodes.get(name) {
1175 Some(Node::Boolean(node)) => Ok(node),
1176 Some(_) => Err(GenApiError::Type(name.to_string())),
1177 None => Err(GenApiError::NodeNotFound(name.to_string())),
1178 }
1179 }
1180
1181 fn get_command_node(&self, name: &str) -> Result<&CommandNode, GenApiError> {
1182 match self.nodes.get(name) {
1183 Some(Node::Command(node)) => Ok(node),
1184 Some(_) => Err(GenApiError::Type(name.to_string())),
1185 None => Err(GenApiError::NodeNotFound(name.to_string())),
1186 }
1187 }
1188
1189 fn ensure_selectors(
1190 &self,
1191 node_name: &str,
1192 rules: &[(String, Vec<String>)],
1193 io: &dyn RegisterIo,
1194 ) -> Result<(), GenApiError> {
1195 for (selector, allowed) in rules {
1196 if allowed.is_empty() {
1197 continue;
1198 }
1199 let current = self.get_selector_value(selector, io)?;
1200 if !allowed.iter().any(|value| value == ¤t) {
1201 return Err(GenApiError::Unavailable(format!(
1202 "node '{node_name}' unavailable for selector '{selector}={current}'"
1203 )));
1204 }
1205 }
1206 Ok(())
1207 }
1208
1209 fn lookup_enum_entry(
1210 &self,
1211 node: &EnumNode,
1212 raw_value: i64,
1213 io: &dyn RegisterIo,
1214 ) -> Result<String, GenApiError> {
1215 {
1216 let mut cache = node.mapping_cache.borrow_mut();
1217 if cache.is_none() {
1218 *cache = Some(self.build_enum_mapping(node, io)?);
1219 }
1220 if let Some(mapping) = cache.as_ref()
1221 && let Some(entry) = mapping.by_value.get(&raw_value)
1222 {
1223 return Ok(entry.clone());
1224 }
1225 *cache = Some(self.build_enum_mapping(node, io)?);
1226 if let Some(mapping) = cache.as_ref()
1227 && let Some(entry) = mapping.by_value.get(&raw_value)
1228 {
1229 return Ok(entry.clone());
1230 }
1231 }
1232 Err(GenApiError::EnumValueUnknown {
1233 node: node.name.clone(),
1234 value: raw_value,
1235 })
1236 }
1237
1238 fn build_enum_mapping(
1239 &self,
1240 node: &EnumNode,
1241 io: &dyn RegisterIo,
1242 ) -> Result<EnumMapping, GenApiError> {
1243 let mut by_value = HashMap::new();
1244 let mut by_name = HashMap::new();
1245
1246 for entry in &node.entries {
1247 let value = self.resolve_enum_entry_value(node, entry, io)?;
1248 match by_value.entry(value) {
1249 HashMapEntry::Vacant(slot) => {
1250 slot.insert(entry.name.clone());
1251 }
1252 HashMapEntry::Occupied(existing) => {
1253 warn!(
1254 enum_node = %node.name,
1255 value,
1256 kept = %existing.get(),
1257 dropped = %entry.name,
1258 "duplicate enum value"
1259 );
1260 }
1261 }
1262 by_name.insert(entry.name.clone(), value);
1263 }
1264
1265 let mut summary: Vec<_> = by_value
1266 .iter()
1267 .map(|(value, name)| (*value, name.clone()))
1268 .collect();
1269 summary.sort_by_key(|(value, _)| *value);
1270 debug!(node = %node.name, entries = ?summary, "build enum mapping");
1271
1272 Ok(EnumMapping { by_value, by_name })
1273 }
1274
1275 fn resolve_enum_entry_value(
1276 &self,
1277 node: &EnumNode,
1278 entry: &EnumEntryDecl,
1279 io: &dyn RegisterIo,
1280 ) -> Result<i64, GenApiError> {
1281 match &entry.value {
1282 EnumValueSrc::Literal(value) => Ok(*value),
1283 EnumValueSrc::FromNode(provider) => {
1284 let value = self.get_integer(provider, io)?;
1285 trace!(
1286 enum_node = %node.name,
1287 entry = %entry.name,
1288 provider = %provider,
1289 value,
1290 "resolved enum entry from provider"
1291 );
1292 Ok(value)
1293 }
1294 }
1295 }
1296
1297 fn resolve_address(
1298 &self,
1299 node_name: &str,
1300 addressing: &Addressing,
1301 io: &dyn RegisterIo,
1302 ) -> Result<(u64, u32), GenApiError> {
1303 match addressing {
1304 Addressing::Fixed { address, len } => Ok((*address, *len)),
1305 Addressing::BySelector { selector, map } => {
1306 let value = self.get_selector_value(selector, io)?;
1307 if let Some((_, (address, len))) = map.iter().find(|(name, _)| name == &value) {
1308 let addr = *address;
1309 let len = *len;
1310 debug!(
1311 node = %node_name,
1312 selector = %selector,
1313 value = %value,
1314 address = format_args!("0x{addr:X}"),
1315 len,
1316 "resolve address via selector"
1317 );
1318 Ok((addr, len))
1319 } else {
1320 Err(GenApiError::Unavailable(format!(
1321 "node '{node_name}' unavailable for selector '{selector}={value}'"
1322 )))
1323 }
1324 }
1325 Addressing::Indirect {
1326 p_address_node,
1327 len,
1328 } => {
1329 let addr_value = self.get_integer(p_address_node, io)?;
1330 if addr_value <= 0 {
1331 return Err(GenApiError::BadIndirectAddress {
1332 name: node_name.to_string(),
1333 addr: addr_value,
1334 });
1335 }
1336 let addr =
1337 u64::try_from(addr_value).map_err(|_| GenApiError::BadIndirectAddress {
1338 name: node_name.to_string(),
1339 addr: addr_value,
1340 })?;
1341 if addr == 0 {
1342 return Err(GenApiError::BadIndirectAddress {
1343 name: node_name.to_string(),
1344 addr: addr_value,
1345 });
1346 }
1347 debug!(
1348 node = %node_name,
1349 source = %p_address_node,
1350 address = format_args!("0x{addr:X}"),
1351 len = *len,
1352 "resolve address via pAddress"
1353 );
1354 Ok((addr, *len))
1355 }
1356 }
1357 }
1358
1359 fn get_selector_value(
1360 &self,
1361 selector: &str,
1362 io: &dyn RegisterIo,
1363 ) -> Result<String, GenApiError> {
1364 match self.nodes.get(selector) {
1365 Some(Node::Enum(_)) => self.get_enum(selector, io),
1366 Some(Node::Boolean(_)) => Ok(self.get_bool(selector, io)?.to_string()),
1367 Some(Node::Integer(_)) => Ok(self.get_integer(selector, io)?.to_string()),
1368 Some(_) => Err(GenApiError::Parse(format!(
1369 "selector {selector} has unsupported type"
1370 ))),
1371 None => Err(GenApiError::NodeNotFound(selector.to_string())),
1372 }
1373 }
1374
1375 fn evaluate_swissknife(
1376 &self,
1377 node: &SkNode,
1378 io: &dyn RegisterIo,
1379 stack: &mut HashSet<String>,
1380 ) -> Result<f64, GenApiError> {
1381 if let Some((value, generation)) = *node.cache.borrow()
1382 && generation == self.generation.get()
1383 {
1384 return Ok(value);
1385 }
1386 if !stack.insert(node.name.clone()) {
1387 stack.remove(&node.name);
1388 return Err(GenApiError::ExprEval {
1389 name: node.name.clone(),
1390 msg: "cyclic dependency".into(),
1391 });
1392 }
1393 let current_gen = self.generation.get();
1394 let result = (|| {
1395 let mut values: HashMap<String, f64> = HashMap::new();
1396 let mut inputs = Vec::new();
1397 for (var, provider) in &node.vars {
1398 let value = self.resolve_numeric(provider, io, stack)?;
1399 values.insert(var.clone(), value);
1400 inputs.push((var.clone(), value));
1401 }
1402 let mut resolver = |ident: &str| -> Result<f64, SkEvalError> {
1403 values
1404 .get(ident)
1405 .copied()
1406 .ok_or_else(|| SkEvalError::UnknownVariable(ident.to_string()))
1407 };
1408 let value = match eval_ast(&node.ast, &mut resolver) {
1409 Ok(value) => value,
1410 Err(SkEvalError::UnknownVariable(var)) => {
1411 return Err(GenApiError::UnknownVariable {
1412 name: node.name.clone(),
1413 var,
1414 });
1415 }
1416 Err(SkEvalError::DivisionByZero) => {
1417 return Err(GenApiError::ExprEval {
1418 name: node.name.clone(),
1419 msg: "division by zero".into(),
1420 });
1421 }
1422 Err(SkEvalError::UnknownFunction(func)) => {
1423 return Err(GenApiError::ExprEval {
1424 name: node.name.clone(),
1425 msg: format!("unknown function: {func}"),
1426 });
1427 }
1428 Err(SkEvalError::ArityMismatch {
1429 name: func,
1430 expected,
1431 got,
1432 }) => {
1433 return Err(GenApiError::ExprEval {
1434 name: node.name.clone(),
1435 msg: format!("function {func} expects {expected} args, got {got}"),
1436 });
1437 }
1438 };
1439 debug!(node = %node.name, inputs = ?inputs, output = value, "evaluate SwissKnife");
1440 Ok(value)
1441 })();
1442 stack.remove(&node.name);
1443 match result {
1444 Ok(value) => {
1445 node.cache.replace(Some((value, current_gen)));
1446 Ok(value)
1447 }
1448 Err(err) => Err(err),
1449 }
1450 }
1451
1452 fn resolve_numeric(
1453 &self,
1454 provider: &str,
1455 io: &dyn RegisterIo,
1456 stack: &mut HashSet<String>,
1457 ) -> Result<f64, GenApiError> {
1458 match self.nodes.get(provider) {
1459 Some(Node::Integer(_)) => self.get_integer(provider, io).map(|v| v as f64),
1460 Some(Node::Float(_)) => self.get_float(provider, io),
1461 Some(Node::Boolean(_)) => Ok(if self.get_bool(provider, io)? {
1462 1.0
1463 } else {
1464 0.0
1465 }),
1466 Some(Node::Enum(_)) => self.get_enum_numeric(provider, io).map(|v| v as f64),
1467 Some(Node::SwissKnife(node)) => self.evaluate_swissknife(node, io, stack),
1468 Some(Node::Converter(node)) => self.evaluate_converter(node, io, stack),
1469 Some(Node::IntConverter(node)) => self
1470 .evaluate_int_converter(node, io, stack)
1471 .map(|v| v as f64),
1472 Some(_) => Err(GenApiError::Type(provider.to_string())),
1473 None => Err(GenApiError::NodeNotFound(provider.to_string())),
1474 }
1475 }
1476
1477 fn get_enum_numeric(&self, name: &str, io: &dyn RegisterIo) -> Result<i64, GenApiError> {
1478 let entry = self.get_enum(name, io)?;
1479 let node = self.get_enum_node(name)?;
1480 {
1481 let mut mapping = node.mapping_cache.borrow_mut();
1482 if mapping.is_none() {
1483 *mapping = Some(self.build_enum_mapping(node, io)?);
1484 }
1485 if let Some(map) = mapping.as_ref()
1486 && let Some(value) = map.by_name.get(&entry)
1487 {
1488 return Ok(*value);
1489 }
1490 }
1491 Err(GenApiError::EnumNoSuchEntry {
1492 node: name.to_string(),
1493 entry,
1494 })
1495 }
1496
1497 fn invalidate_dependents(&self, name: &str) {
1498 self.bump_generation();
1499 if let Some(children) = self.dependents.get(name) {
1500 let mut visited = HashSet::new();
1501 for child in children {
1502 self.invalidate_recursive(child, &mut visited);
1503 }
1504 }
1505 }
1506
1507 fn invalidate_recursive(&self, name: &str, visited: &mut HashSet<String>) {
1508 if !visited.insert(name.to_string()) {
1509 return;
1510 }
1511 if let Some(node) = self.nodes.get(name) {
1512 node.invalidate_cache();
1513 }
1514 if let Some(children) = self.dependents.get(name) {
1515 for child in children {
1516 self.invalidate_recursive(child, visited);
1517 }
1518 }
1519 }
1520
1521 fn bump_generation(&self) {
1522 let current = self.generation.get();
1523 self.generation.set(current.wrapping_add(1));
1524 }
1525
1526 fn get_converter_node(&self, name: &str) -> Result<&ConverterNode, GenApiError> {
1531 match self.nodes.get(name) {
1532 Some(Node::Converter(node)) => Ok(node),
1533 Some(_) => Err(GenApiError::Type(name.to_string())),
1534 None => Err(GenApiError::NodeNotFound(name.to_string())),
1535 }
1536 }
1537
1538 fn get_int_converter_node(&self, name: &str) -> Result<&IntConverterNode, GenApiError> {
1539 match self.nodes.get(name) {
1540 Some(Node::IntConverter(node)) => Ok(node),
1541 Some(_) => Err(GenApiError::Type(name.to_string())),
1542 None => Err(GenApiError::NodeNotFound(name.to_string())),
1543 }
1544 }
1545
1546 fn get_string_node(&self, name: &str) -> Result<&StringNode, GenApiError> {
1547 match self.nodes.get(name) {
1548 Some(Node::String(node)) => Ok(node),
1549 Some(_) => Err(GenApiError::Type(name.to_string())),
1550 None => Err(GenApiError::NodeNotFound(name.to_string())),
1551 }
1552 }
1553
1554 pub fn get_converter(&self, name: &str, io: &dyn RegisterIo) -> Result<f64, GenApiError> {
1556 let node = self.get_converter_node(name)?;
1557 if let Some((value, generation)) = *node.cache.borrow()
1558 && generation == self.generation.get()
1559 {
1560 return Ok(value);
1561 }
1562 let mut stack = HashSet::new();
1563 let value = self.evaluate_converter(node, io, &mut stack)?;
1564 node.cache.replace(Some((value, self.generation.get())));
1565 Ok(value)
1566 }
1567
1568 pub fn get_int_converter(&self, name: &str, io: &dyn RegisterIo) -> Result<i64, GenApiError> {
1570 let node = self.get_int_converter_node(name)?;
1571 if let Some((value, generation)) = *node.cache.borrow()
1572 && generation == self.generation.get()
1573 {
1574 return Ok(value);
1575 }
1576 let mut stack = HashSet::new();
1577 let value = self.evaluate_int_converter(node, io, &mut stack)?;
1578 node.cache.replace(Some((value, self.generation.get())));
1579 Ok(value)
1580 }
1581
1582 pub fn get_string(&self, name: &str, io: &dyn RegisterIo) -> Result<String, GenApiError> {
1584 let node = self.get_string_node(name)?;
1585 ensure_readable(&node.access, name)?;
1586 if let Some((ref value, generation)) = *node.cache.borrow()
1587 && generation == self.generation.get()
1588 {
1589 return Ok(value.clone());
1590 }
1591 let (address, len) = self.resolve_address(name, &node.addressing, io)?;
1592 let raw = io.read(address, len as usize)?;
1593 let end = raw.iter().position(|&b| b == 0).unwrap_or(raw.len());
1595 let value = String::from_utf8_lossy(&raw[..end]).to_string();
1596 node.cache
1597 .replace(Some((value.clone(), self.generation.get())));
1598 debug!(node = %name, value = %value, "get_string");
1599 Ok(value)
1600 }
1601
1602 pub fn set_string(
1604 &self,
1605 name: &str,
1606 value: &str,
1607 io: &dyn RegisterIo,
1608 ) -> Result<(), GenApiError> {
1609 let node = self.get_string_node(name)?;
1610 ensure_writable(&node.access, name)?;
1611 let (address, len) = self.resolve_address(name, &node.addressing, io)?;
1612 let mut buf = vec![0u8; len as usize];
1614 let bytes = value.as_bytes();
1615 let copy_len = bytes.len().min(len as usize);
1616 buf[..copy_len].copy_from_slice(&bytes[..copy_len]);
1617 io.write(address, &buf)?;
1618 node.cache
1619 .replace(Some((value.to_string(), self.generation.get())));
1620 self.invalidate_dependents(name);
1621 debug!(node = %name, value = %value, "set_string");
1622 Ok(())
1623 }
1624
1625 fn evaluate_converter(
1626 &self,
1627 node: &ConverterNode,
1628 io: &dyn RegisterIo,
1629 stack: &mut HashSet<String>,
1630 ) -> Result<f64, GenApiError> {
1631 if !stack.insert(node.name.clone()) {
1632 stack.remove(&node.name);
1633 return Err(GenApiError::ExprEval {
1634 name: node.name.clone(),
1635 msg: "cyclic dependency".into(),
1636 });
1637 }
1638
1639 let result = (|| {
1640 let mut values: HashMap<String, f64> = HashMap::new();
1642 for (var, provider) in &node.vars_to {
1643 let value = self.resolve_numeric(provider, io, stack)?;
1644 values.insert(var.clone(), value);
1645 }
1646 let mut resolver = |ident: &str| -> Result<f64, SkEvalError> {
1648 values
1649 .get(ident)
1650 .copied()
1651 .ok_or_else(|| SkEvalError::UnknownVariable(ident.to_string()))
1652 };
1653 match eval_ast(&node.ast_to, &mut resolver) {
1654 Ok(value) => {
1655 debug!(node = %node.name, value, "evaluate Converter");
1656 Ok(value)
1657 }
1658 Err(SkEvalError::UnknownVariable(var)) => Err(GenApiError::UnknownVariable {
1659 name: node.name.clone(),
1660 var,
1661 }),
1662 Err(SkEvalError::DivisionByZero) => Err(GenApiError::ExprEval {
1663 name: node.name.clone(),
1664 msg: "division by zero".into(),
1665 }),
1666 Err(SkEvalError::UnknownFunction(func)) => Err(GenApiError::ExprEval {
1667 name: node.name.clone(),
1668 msg: format!("unknown function: {func}"),
1669 }),
1670 Err(SkEvalError::ArityMismatch {
1671 name: func,
1672 expected,
1673 got,
1674 }) => Err(GenApiError::ExprEval {
1675 name: node.name.clone(),
1676 msg: format!("function {func} expects {expected} args, got {got}"),
1677 }),
1678 }
1679 })();
1680
1681 stack.remove(&node.name);
1682 result
1683 }
1684
1685 fn evaluate_int_converter(
1686 &self,
1687 node: &IntConverterNode,
1688 io: &dyn RegisterIo,
1689 stack: &mut HashSet<String>,
1690 ) -> Result<i64, GenApiError> {
1691 if !stack.insert(node.name.clone()) {
1692 stack.remove(&node.name);
1693 return Err(GenApiError::ExprEval {
1694 name: node.name.clone(),
1695 msg: "cyclic dependency".into(),
1696 });
1697 }
1698
1699 let result = (|| {
1700 let mut values: HashMap<String, f64> = HashMap::new();
1701 for (var, provider) in &node.vars_to {
1702 let value = self.resolve_numeric(provider, io, stack)?;
1703 values.insert(var.clone(), value);
1704 }
1705 let mut resolver = |ident: &str| -> Result<f64, SkEvalError> {
1706 values
1707 .get(ident)
1708 .copied()
1709 .ok_or_else(|| SkEvalError::UnknownVariable(ident.to_string()))
1710 };
1711 match eval_ast(&node.ast_to, &mut resolver) {
1712 Ok(value) => {
1713 let int_value = round_to_i64(&node.name, value)?;
1714 debug!(node = %node.name, int_value, "evaluate IntConverter");
1715 Ok(int_value)
1716 }
1717 Err(SkEvalError::UnknownVariable(var)) => Err(GenApiError::UnknownVariable {
1718 name: node.name.clone(),
1719 var,
1720 }),
1721 Err(SkEvalError::DivisionByZero) => Err(GenApiError::ExprEval {
1722 name: node.name.clone(),
1723 msg: "division by zero".into(),
1724 }),
1725 Err(SkEvalError::UnknownFunction(func)) => Err(GenApiError::ExprEval {
1726 name: node.name.clone(),
1727 msg: format!("unknown function: {func}"),
1728 }),
1729 Err(SkEvalError::ArityMismatch {
1730 name: func,
1731 expected,
1732 got,
1733 }) => Err(GenApiError::ExprEval {
1734 name: node.name.clone(),
1735 msg: format!("function {func} expects {expected} args, got {got}"),
1736 }),
1737 }
1738 })();
1739
1740 stack.remove(&node.name);
1741 result
1742 }
1743}
1744
1745impl From<XmlModel> for NodeMap {
1746 fn from(model: XmlModel) -> Self {
1747 NodeMap::try_from_xml(model).expect("invalid GenApi model")
1748 }
1749}