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, AddressTerm, Addressing, EnumEntryDecl, EnumValueSrc, FloatEncoding,
9 FormulaBindings, IndexOffset, NodeDecl, PredicateRefs, Sign, SkippedNode, 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, RegisterNode, SkNode, StringNode,
20};
21use crate::swissknife::{
22 AstNode as SkAst, EvalError as SkEvalError, EvalMode, Value as SkValue, collect_identifiers,
23 evaluate as eval_ast, is_builtin_constant, parse_expression, substitute,
24};
25use crate::{GenApiError, RegisterIo, SkOutput};
26
27#[derive(Debug)]
30pub struct NodeMap {
31 version: String,
32 nodes: HashMap<String, Node>,
33 dependents: HashMap<String, Vec<String>>,
34 skipped: Vec<SkippedNode>,
35 generation: Cell<u64>,
36}
37
38fn register_addressing_dependency(
39 dependents: &mut HashMap<String, Vec<String>>,
40 node_name: &str,
41 addressing: &Addressing,
42) {
43 for provider in addressing.referenced_nodes() {
44 dependents
45 .entry(provider.to_string())
46 .or_default()
47 .push(node_name.to_string());
48 }
49}
50
51fn register_predicate_dependencies(
52 dependents: &mut HashMap<String, Vec<String>>,
53 node_name: &str,
54 predicates: &PredicateRefs,
55) {
56 for provider in predicates.references() {
57 dependents
58 .entry(provider.to_string())
59 .or_default()
60 .push(node_name.to_string());
61 }
62}
63
64fn ensure_readable(access: &AccessMode, name: &str) -> Result<(), GenApiError> {
65 if matches!(access, AccessMode::WO) {
66 return Err(GenApiError::Access(name.to_string()));
67 }
68 Ok(())
69}
70
71fn ensure_device_port(name: &str, port: Option<&str>) -> Result<(), GenApiError> {
89 match port {
90 None => Ok(()),
91 Some(p) if p.eq_ignore_ascii_case("Device") => Ok(()),
92 Some(p) => Err(GenApiError::Unavailable(format!(
93 "register '{name}' is bound to port '{p}'; \
94 non-device ports are not routed yet (GA-12)"
95 ))),
96 }
97}
98
99fn ensure_writable(access: &AccessMode, name: &str) -> Result<(), GenApiError> {
100 if matches!(access, AccessMode::RO) {
101 return Err(GenApiError::Access(name.to_string()));
102 }
103 Ok(())
104}
105
106impl NodeMap {
107 pub fn version(&self) -> &str {
109 &self.version
110 }
111
112 pub fn node(&self, name: &str) -> Option<&Node> {
114 self.nodes.get(name)
115 }
116
117 pub fn node_names(&self) -> impl Iterator<Item = &str> {
119 self.nodes.keys().map(|s| s.as_str())
120 }
121
122 pub fn dependents(&self, name: &str) -> &[String] {
126 self.dependents
127 .get(name)
128 .map(|v| v.as_slice())
129 .unwrap_or(&[])
130 }
131
132 pub fn categories(&self) -> Vec<(&str, &[String])> {
134 self.nodes
135 .values()
136 .filter_map(|node| match node {
137 Node::Category(cat) => Some((cat.name.as_str(), cat.children.as_slice())),
138 _ => None,
139 })
140 .collect()
141 }
142
143 pub fn nodes_at_visibility(&self, level: Visibility) -> Vec<&str> {
148 self.nodes
149 .iter()
150 .filter(|(_, node)| node.visibility() <= level)
151 .map(|(name, _)| name.as_str())
152 .collect()
153 }
154
155 pub fn try_from_xml(model: XmlModel) -> Result<Self, GenApiError> {
163 let mut nodes = HashMap::new();
164 let mut dependents: HashMap<String, Vec<String>> = HashMap::new();
165 let mut skipped = model.skipped;
170 for decl in model.nodes {
171 let tag = decl.kind().to_string();
172 let name = Some(decl.name().to_string());
173 let mut local: HashMap<String, Vec<String>> = HashMap::new();
177 match build_node(decl, &mut local) {
178 Ok((node_name, node)) => {
179 for (provider, mut names) in local {
180 dependents.entry(provider).or_default().append(&mut names);
181 }
182 nodes.insert(node_name, node);
183 }
184 Err(err) => {
185 warn!(
186 tag = %tag,
187 node = name.as_deref().unwrap_or("<unnamed>"),
188 error = %err,
189 "dropping GenApi node"
190 );
191 skipped.push(SkippedNode {
192 tag,
193 name,
194 error: err.to_string(),
195 });
196 }
197 }
198 }
199
200 Ok(NodeMap {
201 version: model.version,
202 nodes,
203 dependents,
204 skipped,
205 generation: Cell::new(0),
206 })
207 }
208
209 pub fn skipped(&self) -> &[SkippedNode] {
216 &self.skipped
217 }
218
219 pub fn get_integer(&self, name: &str, io: &dyn RegisterIo) -> Result<i64, GenApiError> {
221 if let Some(Node::IntConverter(_)) = self.nodes.get(name) {
222 return self.get_int_converter(name, io);
223 }
224 if let Some(output) = self.nodes.get(name).and_then(|node| match node {
225 Node::SwissKnife(sk) => Some(sk.output),
226 _ => None,
227 }) {
228 return match output {
229 SkOutput::Integer => {
230 let node = match self.nodes.get(name) {
231 Some(Node::SwissKnife(node)) => node,
232 _ => unreachable!("node vanished during lookup"),
233 };
234 let mut stack = HashSet::new();
235 let value = self.evaluate_swissknife(node, io, &mut stack)?;
236 sk_to_i64(name, value)
237 }
238 SkOutput::Float => Err(GenApiError::Type(name.to_string())),
239 };
240 }
241 let node = self.get_integer_node(name)?;
242 ensure_readable(&node.access, name)?;
243 self.ensure_selectors(name, &node.selected_if, io)?;
244 if let Some(v) = node.value {
246 return Ok(v);
247 }
248 if let Some(ref pv) = node.pvalue {
250 let pv = pv.clone();
251 return self.get_integer(&pv, io);
252 }
253 let addressing = node
254 .addressing
255 .as_ref()
256 .ok_or_else(|| GenApiError::NodeNotFound(format!("{name}: no addressing or pValue")))?;
257 let (address, len) = self.resolve_address(name, addressing, io)?;
258 if let Some(value) = *node.cache.borrow() {
259 return Ok(value);
260 }
261 let raw = io.read(address, len as usize).map_err(|err| match err {
262 GenApiError::Io(_) => err,
263 other => other,
264 })?;
265 let value = if let Some(bitfield) = node.bitfield {
266 let extracted = extract(&raw, bitfield).map_err(|err| map_bitops_error(name, err))?;
267 interpret_bitfield_value(
268 name,
269 extracted,
270 bitfield.bit_length,
271 integer_sign(node).is_signed(),
272 )?
273 } else {
274 bytes_to_i64(name, &raw, integer_sign(node))?
275 };
276 debug!(node = %name, raw = value, "read integer feature");
277 node.cache.replace(Some(value));
278 node.raw_cache.replace(Some(raw));
279 Ok(value)
280 }
281
282 pub fn set_integer(
284 &mut self,
285 name: &str,
286 value: i64,
287 io: &dyn RegisterIo,
288 ) -> Result<(), GenApiError> {
289 if let Some(Node::IntConverter(_)) = self.nodes.get(name) {
290 return self.set_int_converter(name, value, io);
291 }
292 let node = self.get_integer_node(name)?;
293 self.ensure_writable_now(name, &node.access, io)?;
294 self.ensure_selectors(name, &node.selected_if, io)?;
295 if let Some(ref pv) = node.pvalue {
296 let pv = pv.clone();
297 return self.set_integer(&pv, value, io);
298 }
299 let addressing = node
300 .addressing
301 .as_ref()
302 .ok_or_else(|| GenApiError::NodeNotFound(format!("{name}: no addressing or pValue")))?;
303 let (address, len) = self.resolve_address(name, addressing, io)?;
304 if value < node.min || value > node.max {
305 return Err(GenApiError::Range(name.to_string()));
306 }
307 if let Some(inc) = node.inc
308 && inc != 0
309 && (value - node.min) % inc != 0
310 {
311 return Err(GenApiError::Range(name.to_string()));
312 }
313 if let Some(bitfield) = node.bitfield {
314 let encoded = encode_bitfield_value(name, value, bitfield.bit_length, node.min < 0)?;
315 let mut raw = get_raw_or_read(&node.raw_cache, io, address, len)?;
316 insert(&mut raw, bitfield, encoded).map_err(|err| map_bitops_error(name, err))?;
317 debug!(node = %name, raw = value, "write integer feature");
318 io.write(address, &raw).map_err(|err| match err {
319 GenApiError::Io(_) => err,
320 other => other,
321 })?;
322 node.cache.replace(Some(value));
323 node.raw_cache.replace(Some(raw));
324 } else {
325 let bytes = i64_to_bytes(name, value, len, integer_sign(node))?;
326 debug!(node = %name, raw = value, "write integer feature");
327 io.write(address, &bytes).map_err(|err| match err {
328 GenApiError::Io(_) => err,
329 other => other,
330 })?;
331 node.cache.replace(Some(value));
332 node.raw_cache.replace(Some(bytes));
333 }
334 self.invalidate_dependents(name);
335 Ok(())
336 }
337
338 pub fn get_float(&self, name: &str, io: &dyn RegisterIo) -> Result<f64, GenApiError> {
340 match self.nodes.get(name) {
341 Some(Node::Converter(_)) => return self.get_converter(name, io),
342 Some(Node::IntConverter(_)) => {
343 return self.get_int_converter(name, io).map(|v| v as f64);
344 }
345 _ => {}
346 }
347 if let Some(output) = self.nodes.get(name).and_then(|node| match node {
348 Node::SwissKnife(sk) => Some(sk.output),
349 _ => None,
350 }) {
351 return match output {
352 SkOutput::Float => {
353 let node = match self.nodes.get(name) {
354 Some(Node::SwissKnife(node)) => node,
355 _ => unreachable!("node vanished during lookup"),
356 };
357 let mut stack = HashSet::new();
358 let value = self.evaluate_swissknife(node, io, &mut stack)?;
359 Ok(value.as_f64())
360 }
361 SkOutput::Integer => self.get_integer(name, io).map(|v| v as f64),
362 };
363 }
364 let node = self.get_float_node(name)?;
365 ensure_readable(&node.access, name)?;
366 self.ensure_selectors(name, &node.selected_if, io)?;
367 if let Some(ref pv) = node.pvalue {
368 let pv = pv.clone();
369 return self.get_float(&pv, io);
370 }
371 let addressing = node
372 .addressing
373 .as_ref()
374 .ok_or_else(|| GenApiError::NodeNotFound(format!("{name}: no addressing or pValue")))?;
375 let (address, len) = self.resolve_address(name, addressing, io)?;
376 if let Some(value) = *node.cache.borrow() {
377 return Ok(value);
378 }
379 let raw = io.read(address, len as usize).map_err(|err| match err {
380 GenApiError::Io(_) => err,
381 other => other,
382 })?;
383 let value = match node.encoding {
384 FloatEncoding::Ieee754 => {
385 let v = decode_ieee754(name, &raw, node.byte_order)?;
386 debug!(node = %name, value = v, "read float feature (ieee754)");
387 v
388 }
389 FloatEncoding::ScaledInteger => {
390 let raw_value = bytes_to_i64(name, &raw, Sign::Signed)?;
393 let v = apply_scale(node, raw_value as f64);
394 debug!(node = %name, raw = raw_value, value = v, "read float feature (scaled)");
395 v
396 }
397 };
398 node.cache.replace(Some(value));
399 Ok(value)
400 }
401
402 pub fn set_float(
404 &mut self,
405 name: &str,
406 value: f64,
407 io: &dyn RegisterIo,
408 ) -> Result<(), GenApiError> {
409 match self.nodes.get(name) {
410 Some(Node::Converter(_)) => return self.set_converter(name, value, io),
411 Some(Node::IntConverter(_)) => {
412 return self.set_int_converter(name, round_to_i64(name, value)?, io);
413 }
414 _ => {}
415 }
416 let node = self.get_float_node(name)?;
417 self.ensure_writable_now(name, &node.access, io)?;
418 self.ensure_selectors(name, &node.selected_if, io)?;
419 if let Some(ref pv) = node.pvalue {
420 let pv = pv.clone();
421 return self.set_float(&pv, value, io);
422 }
423 let addressing = node
424 .addressing
425 .as_ref()
426 .ok_or_else(|| GenApiError::NodeNotFound(format!("{name}: no addressing or pValue")))?;
427 let (address, len) = self.resolve_address(name, addressing, io)?;
428 if value < node.min || value > node.max {
429 return Err(GenApiError::Range(name.to_string()));
430 }
431 let bytes = match node.encoding {
432 FloatEncoding::Ieee754 => {
433 let bytes = encode_ieee754(name, value, len, node.byte_order)?;
434 debug!(node = %name, value, "write float feature (ieee754)");
435 bytes
436 }
437 FloatEncoding::ScaledInteger => {
438 let raw = encode_float(node, value)?;
439 let bytes = i64_to_bytes(name, raw, len, Sign::Signed)?;
440 debug!(node = %name, raw, value, "write float feature (scaled)");
441 bytes
442 }
443 };
444 io.write(address, &bytes).map_err(|err| match err {
445 GenApiError::Io(_) => err,
446 other => other,
447 })?;
448 node.cache.replace(Some(value));
449 self.invalidate_dependents(name);
450 Ok(())
451 }
452
453 pub fn get_enum(&self, name: &str, io: &dyn RegisterIo) -> Result<String, GenApiError> {
455 let node = self.get_enum_node(name)?;
456 ensure_readable(&node.access, name)?;
457 self.ensure_selectors(name, &node.selected_if, io)?;
458 if let Some(ref pv) = node.pvalue {
460 let pv = pv.clone();
461 if let Some(value) = node.value_cache.borrow().clone() {
462 return Ok(value);
463 }
464 let raw_value = self.get_integer(&pv, io)?;
465 let entry = self.lookup_enum_entry(node, raw_value, io)?;
466 node.value_cache.replace(Some(entry.clone()));
467 return Ok(entry);
468 }
469 let addressing = node
470 .addressing
471 .as_ref()
472 .ok_or_else(|| GenApiError::NodeNotFound(format!("{name}: no addressing")))?;
473 let (address, len) = self.resolve_address(name, addressing, io)?;
474 if let Some(value) = node.value_cache.borrow().clone() {
475 return Ok(value);
476 }
477 let raw = io.read(address, len as usize).map_err(|err| match err {
478 GenApiError::Io(_) => err,
479 other => other,
480 })?;
481 let raw_value = bytes_to_i64(name, &raw, Sign::Signed)?;
483 let entry = self.lookup_enum_entry(node, raw_value, io)?;
484 debug!(node = %name, raw = raw_value, entry = %entry, "read enum feature");
485 node.value_cache.replace(Some(entry.clone()));
486 Ok(entry)
487 }
488
489 pub fn set_enum(
491 &mut self,
492 name: &str,
493 entry: &str,
494 io: &dyn RegisterIo,
495 ) -> Result<(), GenApiError> {
496 let node = self.get_enum_node(name)?;
497 self.ensure_writable_now(name, &node.access, io)?;
498 self.ensure_selectors(name, &node.selected_if, io)?;
499 if let Some(ref pv) = node.pvalue {
500 let pv = pv.clone();
501 let entry_decl = node
502 .entries
503 .iter()
504 .find(|candidate| candidate.name == entry)
505 .ok_or_else(|| GenApiError::EnumNoSuchEntry {
506 node: name.to_string(),
507 entry: entry.to_string(),
508 })?;
509 let raw_value = self.resolve_enum_entry_value(node, entry_decl, io)?;
510 let entry_str = entry.to_string();
511 self.set_integer(&pv, raw_value, io)?;
513 let node = self.get_enum_node(name)?;
514 node.value_cache.replace(Some(entry_str));
515 node.invalidate();
516 self.invalidate_dependents(name);
517 return Ok(());
518 }
519 let addressing = node
520 .addressing
521 .as_ref()
522 .ok_or_else(|| GenApiError::NodeNotFound(format!("{name}: no addressing")))?;
523 let (address, len) = self.resolve_address(name, addressing, io)?;
524 let entry_decl = node
525 .entries
526 .iter()
527 .find(|candidate| candidate.name == entry)
528 .ok_or_else(|| GenApiError::EnumNoSuchEntry {
529 node: name.to_string(),
530 entry: entry.to_string(),
531 })?;
532 let raw = self.resolve_enum_entry_value(node, entry_decl, io)?;
533 let bytes = i64_to_bytes(name, raw, len, Sign::Signed)?;
534 debug!(node = %name, raw, entry, "write enum feature");
535 io.write(address, &bytes).map_err(|err| match err {
536 GenApiError::Io(_) => err,
537 other => other,
538 })?;
539 node.value_cache.replace(None);
540 self.invalidate_dependents(name);
541 Ok(())
542 }
543
544 pub fn enum_entries(&self, name: &str) -> Result<Vec<String>, GenApiError> {
546 let node = self.get_enum_node(name)?;
547 if let Some(mapping) = node.mapping_cache.borrow().as_ref() {
548 let mut names: Vec<_> = mapping.by_name.keys().cloned().collect();
549 names.sort();
550 names.dedup();
551 return Ok(names);
552 }
553 let mut names: Vec<_> = node
554 .entries
555 .iter()
556 .map(|entry| entry.name.clone())
557 .collect();
558 names.sort();
559 names.dedup();
560 Ok(names)
561 }
562
563 pub fn is_implemented(&self, name: &str, io: &dyn RegisterIo) -> Result<bool, GenApiError> {
571 let prefs = self.predicate_refs(name)?;
572 match &prefs.p_is_implemented {
573 None => Ok(true),
574 Some(provider) => self.eval_predicate_ref(name, provider, io),
575 }
576 }
577
578 pub fn is_available(&self, name: &str, io: &dyn RegisterIo) -> Result<bool, GenApiError> {
586 if !self.is_implemented(name, io)? {
587 return Ok(false);
588 }
589 let prefs = self.predicate_refs(name)?;
590 if let Some(provider) = &prefs.p_is_available
591 && !self.eval_predicate_ref(name, provider, io)?
592 {
593 return Ok(false);
594 }
595 let selected_if = self
596 .nodes
597 .get(name)
598 .and_then(Self::selected_if_slice)
599 .unwrap_or(&[]);
600 self.selectors_allow(selected_if, io)
601 }
602
603 fn ensure_writable_now(
624 &self,
625 name: &str,
626 access: &AccessMode,
627 io: &dyn RegisterIo,
628 ) -> Result<(), GenApiError> {
629 ensure_writable(access, name)?;
630 if !self.is_available(name, io)? {
631 return Err(GenApiError::Unavailable(name.to_string()));
632 }
633 let prefs = self.predicate_refs(name)?;
634 if let Some(provider) = &prefs.p_is_locked
635 && self.eval_predicate_ref(name, provider, io)?
636 {
637 return Err(GenApiError::Locked {
638 name: name.to_string(),
639 locked_by: provider.to_string(),
640 });
641 }
642 Ok(())
643 }
644
645 pub fn effective_access_mode(
656 &self,
657 name: &str,
658 io: &dyn RegisterIo,
659 ) -> Result<AccessMode, GenApiError> {
660 let node = self
661 .nodes
662 .get(name)
663 .ok_or_else(|| GenApiError::NodeNotFound(name.to_string()))?;
664 let base = node.access_mode().unwrap_or(AccessMode::RO);
665 if !self.is_available(name, io)? {
666 return Ok(AccessMode::RO);
667 }
668 let prefs = self.predicate_refs(name)?;
669 if let Some(provider) = &prefs.p_is_locked
670 && self.eval_predicate_ref(name, provider, io)?
671 {
672 return Ok(match base {
673 AccessMode::RW => AccessMode::RO,
674 other => other,
675 });
676 }
677 Ok(base)
678 }
679
680 pub fn available_enum_entries(
689 &self,
690 name: &str,
691 io: &dyn RegisterIo,
692 ) -> Result<Vec<String>, GenApiError> {
693 let node = self.get_enum_node(name)?;
694 let any_entry_predicate = node.entries.iter().any(|e| !e.predicates.is_empty());
695 if !any_entry_predicate {
696 return self.enum_entries(name);
697 }
698 let mut out = Vec::new();
699 for entry in &node.entries {
700 if let Some(provider) = &entry.predicates.p_is_implemented
701 && !self.eval_predicate_ref(name, provider, io)?
702 {
703 continue;
704 }
705 if let Some(provider) = &entry.predicates.p_is_available
706 && !self.eval_predicate_ref(name, provider, io)?
707 {
708 continue;
709 }
710 out.push(entry.name.clone());
711 }
712 out.sort();
713 out.dedup();
714 Ok(out)
715 }
716
717 fn predicate_refs(&self, name: &str) -> Result<&PredicateRefs, GenApiError> {
718 self.nodes
719 .get(name)
720 .map(Node::predicates)
721 .ok_or_else(|| GenApiError::NodeNotFound(name.to_string()))
722 }
723
724 fn eval_predicate_ref(
733 &self,
734 ctx: &str,
735 provider: &str,
736 io: &dyn RegisterIo,
737 ) -> Result<bool, GenApiError> {
738 if provider == ctx {
739 return Err(GenApiError::ExprEval {
740 name: ctx.to_string(),
741 msg: "predicate references the node it gates".into(),
742 });
743 }
744 let mut stack = HashSet::new();
745 stack.insert(ctx.to_string());
746 let value = self.resolve_numeric(provider, io, &mut stack)?;
747 trace!(node = %ctx, provider, value, "predicate eval");
748 Ok(value != 0.0)
749 }
750
751 fn selectors_allow(
755 &self,
756 rules: &[(String, Vec<String>)],
757 io: &dyn RegisterIo,
758 ) -> Result<bool, GenApiError> {
759 for (selector, allowed) in rules {
760 if allowed.is_empty() {
761 continue;
762 }
763 let current = self.get_selector_value(selector, io)?;
764 if !allowed.iter().any(|v| v == ¤t) {
765 return Ok(false);
766 }
767 }
768 Ok(true)
769 }
770
771 fn selected_if_slice(node: &Node) -> Option<&[(String, Vec<String>)]> {
772 match node {
773 Node::Integer(n) => Some(&n.selected_if),
774 Node::Float(n) => Some(&n.selected_if),
775 Node::Enum(n) => Some(&n.selected_if),
776 Node::Boolean(n) => Some(&n.selected_if),
777 _ => None,
778 }
779 }
780
781 pub fn get_bool(&self, name: &str, io: &dyn RegisterIo) -> Result<bool, GenApiError> {
783 let node = self.get_bool_node(name)?;
784 ensure_readable(&node.access, name)?;
785 self.ensure_selectors(name, &node.selected_if, io)?;
786 if let Some(ref pv) = node.pvalue {
787 let pv = pv.clone();
788 let raw = self.get_integer(&pv, io)?;
789 let on = node.on_value.unwrap_or(1);
790 return Ok(raw == on);
791 }
792 let addressing = node
793 .addressing
794 .as_ref()
795 .ok_or_else(|| GenApiError::NodeNotFound(format!("{name}: no addressing or pValue")))?;
796 let bitfield = node
797 .bitfield
798 .ok_or_else(|| GenApiError::Parse(format!("{name}: boolean without bitfield")))?;
799 let (address, len) = self.resolve_address(name, addressing, io)?;
800 if let Some(value) = *node.cache.borrow() {
801 return Ok(value);
802 }
803 let raw = io.read(address, len as usize).map_err(|err| match err {
804 GenApiError::Io(_) => err,
805 other => other,
806 })?;
807 let raw_value = extract(&raw, bitfield).map_err(|err| map_bitops_error(name, err))?;
808 let value = raw_value != 0;
809 debug!(node = %name, raw = raw_value, value, "read boolean feature");
810 node.cache.replace(Some(value));
811 node.raw_cache.replace(Some(raw));
812 Ok(value)
813 }
814
815 pub fn set_bool(
817 &mut self,
818 name: &str,
819 value: bool,
820 io: &dyn RegisterIo,
821 ) -> Result<(), GenApiError> {
822 let node = self.get_bool_node(name)?;
823 self.ensure_writable_now(name, &node.access, io)?;
824 self.ensure_selectors(name, &node.selected_if, io)?;
825 if let Some(ref pv) = node.pvalue {
826 let pv = pv.clone();
827 let on = node.on_value.unwrap_or(1);
828 let off = node.off_value.unwrap_or(0);
829 let raw = if value { on } else { off };
830 return self.set_integer(&pv, raw, io);
831 }
832 let addressing = node
833 .addressing
834 .as_ref()
835 .ok_or_else(|| GenApiError::NodeNotFound(format!("{name}: no addressing or pValue")))?;
836 let bitfield = node
837 .bitfield
838 .ok_or_else(|| GenApiError::Parse(format!("{name}: boolean without bitfield")))?;
839 let (address, len) = self.resolve_address(name, addressing, io)?;
840 let encoded = if value { 1 } else { 0 };
841 let mut raw = get_raw_or_read(&node.raw_cache, io, address, len)?;
842 insert(&mut raw, bitfield, encoded).map_err(|err| map_bitops_error(name, err))?;
843 debug!(node = %name, raw = encoded, value, "write boolean feature");
844 io.write(address, &raw).map_err(|err| match err {
845 GenApiError::Io(_) => err,
846 other => other,
847 })?;
848 node.cache.replace(Some(value));
849 node.raw_cache.replace(Some(raw));
850 self.invalidate_dependents(name);
851 Ok(())
852 }
853
854 pub fn exec_command(&mut self, name: &str, io: &dyn RegisterIo) -> Result<(), GenApiError> {
856 let node = self.get_command_node(name)?;
857 let cmd_value = node.command_value.unwrap_or(1);
859
860 if let Some(ref pv) = node.pvalue {
861 let pv = pv.clone();
863 debug!(node = %name, "execute command via pValue");
864 return self.set_integer(&pv, cmd_value, io);
865 }
866
867 let address = node
868 .address
869 .ok_or_else(|| GenApiError::NodeNotFound(format!("{name}: no address or pValue")))?;
870 if node.len == 0 {
871 return Err(GenApiError::Parse(format!(
872 "command node {name} has zero length"
873 )));
874 }
875 let data = i64_to_bytes(name, cmd_value, node.len, Sign::Signed)?;
876 debug!(node = %name, "execute command");
877 io.write(address, &data).map_err(|err| match err {
878 GenApiError::Io(_) => err,
879 other => other,
880 })?;
881 self.invalidate_dependents(name);
882 Ok(())
883 }
884
885 fn get_integer_node(&self, name: &str) -> Result<&IntegerNode, GenApiError> {
886 match self.nodes.get(name) {
887 Some(Node::Integer(node)) => Ok(node),
888 Some(_) => Err(GenApiError::Type(name.to_string())),
889 None => Err(GenApiError::NodeNotFound(name.to_string())),
890 }
891 }
892
893 fn get_float_node(&self, name: &str) -> Result<&FloatNode, GenApiError> {
894 match self.nodes.get(name) {
895 Some(Node::Float(node)) => Ok(node),
896 Some(_) => Err(GenApiError::Type(name.to_string())),
897 None => Err(GenApiError::NodeNotFound(name.to_string())),
898 }
899 }
900
901 fn get_enum_node(&self, name: &str) -> Result<&EnumNode, GenApiError> {
902 match self.nodes.get(name) {
903 Some(Node::Enum(node)) => Ok(node),
904 Some(_) => Err(GenApiError::Type(name.to_string())),
905 None => Err(GenApiError::NodeNotFound(name.to_string())),
906 }
907 }
908
909 fn get_bool_node(&self, name: &str) -> Result<&BooleanNode, GenApiError> {
910 match self.nodes.get(name) {
911 Some(Node::Boolean(node)) => Ok(node),
912 Some(_) => Err(GenApiError::Type(name.to_string())),
913 None => Err(GenApiError::NodeNotFound(name.to_string())),
914 }
915 }
916
917 fn get_command_node(&self, name: &str) -> Result<&CommandNode, GenApiError> {
918 match self.nodes.get(name) {
919 Some(Node::Command(node)) => Ok(node),
920 Some(_) => Err(GenApiError::Type(name.to_string())),
921 None => Err(GenApiError::NodeNotFound(name.to_string())),
922 }
923 }
924
925 fn ensure_selectors(
926 &self,
927 node_name: &str,
928 rules: &[(String, Vec<String>)],
929 io: &dyn RegisterIo,
930 ) -> Result<(), GenApiError> {
931 for (selector, allowed) in rules {
932 if allowed.is_empty() {
933 continue;
934 }
935 let current = self.get_selector_value(selector, io)?;
936 if !allowed.iter().any(|value| value == ¤t) {
937 return Err(GenApiError::Unavailable(format!(
938 "node '{node_name}' unavailable for selector '{selector}={current}'"
939 )));
940 }
941 }
942 Ok(())
943 }
944
945 fn lookup_enum_entry(
946 &self,
947 node: &EnumNode,
948 raw_value: i64,
949 io: &dyn RegisterIo,
950 ) -> Result<String, GenApiError> {
951 {
952 let mut cache = node.mapping_cache.borrow_mut();
953 if cache.is_none() {
954 *cache = Some(self.build_enum_mapping(node, io)?);
955 }
956 if let Some(mapping) = cache.as_ref()
957 && let Some(entry) = mapping.by_value.get(&raw_value)
958 {
959 return Ok(entry.clone());
960 }
961 *cache = Some(self.build_enum_mapping(node, io)?);
962 if let Some(mapping) = cache.as_ref()
963 && let Some(entry) = mapping.by_value.get(&raw_value)
964 {
965 return Ok(entry.clone());
966 }
967 }
968 Err(GenApiError::EnumValueUnknown {
969 node: node.name.clone(),
970 value: raw_value,
971 })
972 }
973
974 fn build_enum_mapping(
975 &self,
976 node: &EnumNode,
977 io: &dyn RegisterIo,
978 ) -> Result<EnumMapping, GenApiError> {
979 let mut by_value = HashMap::new();
980 let mut by_name = HashMap::new();
981
982 for entry in &node.entries {
983 let value = self.resolve_enum_entry_value(node, entry, io)?;
984 match by_value.entry(value) {
985 HashMapEntry::Vacant(slot) => {
986 slot.insert(entry.name.clone());
987 }
988 HashMapEntry::Occupied(existing) => {
989 warn!(
990 enum_node = %node.name,
991 value,
992 kept = %existing.get(),
993 dropped = %entry.name,
994 "duplicate enum value"
995 );
996 }
997 }
998 by_name.insert(entry.name.clone(), value);
999 }
1000
1001 let mut summary: Vec<_> = by_value
1002 .iter()
1003 .map(|(value, name)| (*value, name.clone()))
1004 .collect();
1005 summary.sort_by_key(|(value, _)| *value);
1006 debug!(node = %node.name, entries = ?summary, "build enum mapping");
1007
1008 Ok(EnumMapping { by_value, by_name })
1009 }
1010
1011 fn resolve_enum_entry_value(
1012 &self,
1013 node: &EnumNode,
1014 entry: &EnumEntryDecl,
1015 io: &dyn RegisterIo,
1016 ) -> Result<i64, GenApiError> {
1017 match &entry.value {
1018 EnumValueSrc::Literal(value) => Ok(*value),
1019 EnumValueSrc::FromNode(provider) => {
1020 let value = self.get_integer(provider, io)?;
1021 trace!(
1022 enum_node = %node.name,
1023 entry = %entry.name,
1024 provider = %provider,
1025 value,
1026 "resolved enum entry from provider"
1027 );
1028 Ok(value)
1029 }
1030 }
1031 }
1032
1033 pub fn register_address(
1047 &self,
1048 name: &str,
1049 io: &dyn RegisterIo,
1050 ) -> Result<(u64, u32), GenApiError> {
1051 let node = self
1052 .node(name)
1053 .ok_or_else(|| GenApiError::NodeNotFound(name.to_string()))?;
1054 let addressing = match node {
1055 Node::Integer(node) => node.addressing.as_ref(),
1056 Node::Float(node) => node.addressing.as_ref(),
1057 Node::Enum(node) => node.addressing.as_ref(),
1058 Node::Boolean(node) => node.addressing.as_ref(),
1059 Node::String(node) => Some(&node.addressing),
1060 Node::Register(node) => Some(&node.addressing),
1061 _ => None,
1062 }
1063 .ok_or_else(|| {
1064 GenApiError::Unavailable(format!("node '{name}' has no register addressing"))
1065 })?;
1066 self.resolve_address(name, addressing, io)
1067 }
1068
1069 fn resolve_address(
1070 &self,
1071 node_name: &str,
1072 addressing: &Addressing,
1073 io: &dyn RegisterIo,
1074 ) -> Result<(u64, u32), GenApiError> {
1075 match addressing {
1076 Addressing::Sum { terms, len } => {
1077 let mut address: u64 = 0;
1078 for term in terms {
1079 address =
1080 address.wrapping_add(self.resolve_address_term(node_name, term, *len, io)?);
1081 }
1082 if terms.len() > 1 {
1083 debug!(
1084 node = %node_name,
1085 terms = terms.len(),
1086 address = format_args!("0x{address:X}"),
1087 len = *len,
1088 "resolve summed address"
1089 );
1090 }
1091 Ok((address, *len))
1092 }
1093 Addressing::BySelector { selector, map } => {
1094 let value = self.get_selector_value(selector, io)?;
1095 if let Some((_, (address, len))) = map.iter().find(|(name, _)| name == &value) {
1096 let addr = *address;
1097 let len = *len;
1098 debug!(
1099 node = %node_name,
1100 selector = %selector,
1101 value = %value,
1102 address = format_args!("0x{addr:X}"),
1103 len,
1104 "resolve address via selector"
1105 );
1106 Ok((addr, len))
1107 } else {
1108 Err(GenApiError::Unavailable(format!(
1109 "node '{node_name}' unavailable for selector '{selector}={value}'"
1110 )))
1111 }
1112 }
1113 }
1114 }
1115
1116 fn resolve_address_term(
1118 &self,
1119 node_name: &str,
1120 term: &AddressTerm,
1121 len: u32,
1122 io: &dyn RegisterIo,
1123 ) -> Result<u64, GenApiError> {
1124 let bad = |addr: i64| GenApiError::BadIndirectAddress {
1125 name: node_name.to_string(),
1126 addr,
1127 };
1128 match term {
1129 AddressTerm::Fixed(offset) => Ok(*offset),
1130 AddressTerm::Node(provider) => {
1131 let value = self.get_integer(provider, io)?;
1132 u64::try_from(value).map_err(|_| bad(value))
1133 }
1134 AddressTerm::Index { node, offset } => {
1135 let index = self.get_integer(node, io)?;
1136 let index = u64::try_from(index).map_err(|_| bad(index))?;
1137 let stride = match offset {
1138 IndexOffset::Fixed(stride) => *stride,
1139 IndexOffset::Node(provider) => {
1140 let value = self.get_integer(provider, io)?;
1141 u64::try_from(value).map_err(|_| bad(value))?
1142 }
1143 IndexOffset::Length => u64::from(len),
1145 };
1146 Ok(index.wrapping_mul(stride))
1147 }
1148 }
1149 }
1150
1151 fn get_selector_value(
1152 &self,
1153 selector: &str,
1154 io: &dyn RegisterIo,
1155 ) -> Result<String, GenApiError> {
1156 match self.nodes.get(selector) {
1157 Some(Node::Enum(_)) => self.get_enum(selector, io),
1158 Some(Node::Boolean(_)) => Ok(self.get_bool(selector, io)?.to_string()),
1159 Some(Node::Integer(_)) => Ok(self.get_integer(selector, io)?.to_string()),
1160 Some(_) => Err(GenApiError::Parse(format!(
1161 "selector {selector} has unsupported type"
1162 ))),
1163 None => Err(GenApiError::NodeNotFound(selector.to_string())),
1164 }
1165 }
1166
1167 #[allow(clippy::too_many_arguments)]
1174 fn eval_formula(
1175 &self,
1176 name: &str,
1177 ast: &SkAst,
1178 vars: &[(String, String)],
1179 overrides: &[(&str, SkValue)],
1180 mode: EvalMode,
1181 io: &dyn RegisterIo,
1182 stack: &mut HashSet<String>,
1183 ) -> Result<SkValue, GenApiError> {
1184 let mut values: HashMap<String, SkValue> = HashMap::new();
1185 for (var, provider) in vars {
1186 if overrides.iter().any(|(ident, _)| ident == var) {
1187 continue;
1188 }
1189 values.insert(var.clone(), self.resolve_value(provider, io, stack)?);
1190 }
1191 for (ident, value) in overrides {
1192 values.insert((*ident).to_string(), *value);
1193 }
1194 let mut resolver = |ident: &str| -> Result<SkValue, SkEvalError> {
1195 values
1196 .get(ident)
1197 .copied()
1198 .ok_or_else(|| SkEvalError::UnknownVariable(ident.to_string()))
1199 };
1200 eval_ast(ast, &mut resolver, mode).map_err(|err| expr_error(name, err))
1201 }
1202
1203 fn evaluate_swissknife(
1204 &self,
1205 node: &SkNode,
1206 io: &dyn RegisterIo,
1207 stack: &mut HashSet<String>,
1208 ) -> Result<SkValue, GenApiError> {
1209 if let Some((value, generation)) = *node.cache.borrow()
1210 && generation == self.generation.get()
1211 {
1212 return Ok(value);
1213 }
1214 if !stack.insert(node.name.clone()) {
1215 stack.remove(&node.name);
1216 return Err(GenApiError::ExprEval {
1217 name: node.name.clone(),
1218 msg: "cyclic dependency".into(),
1219 });
1220 }
1221 let current_gen = self.generation.get();
1222 let result = self.eval_formula(
1223 &node.name,
1224 &node.ast,
1225 &node.vars,
1226 &[],
1227 eval_mode(node.output),
1228 io,
1229 stack,
1230 );
1231 stack.remove(&node.name);
1232 let value = result?;
1233 debug!(node = %node.name, value = %value, "evaluate SwissKnife");
1234 node.cache.replace(Some((value, current_gen)));
1235 Ok(value)
1236 }
1237
1238 fn resolve_value(
1243 &self,
1244 provider: &str,
1245 io: &dyn RegisterIo,
1246 stack: &mut HashSet<String>,
1247 ) -> Result<SkValue, GenApiError> {
1248 match self.nodes.get(provider) {
1249 Some(Node::Integer(_)) => self.get_integer(provider, io).map(SkValue::Int),
1250 Some(Node::Float(_)) => self.get_float(provider, io).map(SkValue::Float),
1251 Some(Node::Boolean(_)) => self
1252 .get_bool(provider, io)
1253 .map(|flag| SkValue::Int(i64::from(flag))),
1254 Some(Node::Enum(_)) => self.get_enum_numeric(provider, io).map(SkValue::Int),
1255 Some(Node::SwissKnife(node)) => self.evaluate_swissknife(node, io, stack),
1256 Some(Node::Converter(node)) => self.evaluate_converter(node, io, stack),
1257 Some(Node::IntConverter(node)) => self
1258 .evaluate_int_converter(node, io, stack)
1259 .map(SkValue::Int),
1260 Some(_) => Err(GenApiError::Type(provider.to_string())),
1261 None => Err(GenApiError::NodeNotFound(provider.to_string())),
1262 }
1263 }
1264
1265 fn resolve_numeric(
1266 &self,
1267 provider: &str,
1268 io: &dyn RegisterIo,
1269 stack: &mut HashSet<String>,
1270 ) -> Result<f64, GenApiError> {
1271 self.resolve_value(provider, io, stack)
1272 .map(|value| value.as_f64())
1273 }
1274
1275 fn get_enum_numeric(&self, name: &str, io: &dyn RegisterIo) -> Result<i64, GenApiError> {
1276 let entry = self.get_enum(name, io)?;
1277 let node = self.get_enum_node(name)?;
1278 {
1279 let mut mapping = node.mapping_cache.borrow_mut();
1280 if mapping.is_none() {
1281 *mapping = Some(self.build_enum_mapping(node, io)?);
1282 }
1283 if let Some(map) = mapping.as_ref()
1284 && let Some(value) = map.by_name.get(&entry)
1285 {
1286 return Ok(*value);
1287 }
1288 }
1289 Err(GenApiError::EnumNoSuchEntry {
1290 node: name.to_string(),
1291 entry,
1292 })
1293 }
1294
1295 fn invalidate_dependents(&self, name: &str) {
1296 self.bump_generation();
1297 if let Some(children) = self.dependents.get(name) {
1298 let mut visited = HashSet::new();
1299 for child in children {
1300 self.invalidate_recursive(child, &mut visited);
1301 }
1302 }
1303 }
1304
1305 fn invalidate_recursive(&self, name: &str, visited: &mut HashSet<String>) {
1306 if !visited.insert(name.to_string()) {
1307 return;
1308 }
1309 if let Some(node) = self.nodes.get(name) {
1310 node.invalidate_cache();
1311 }
1312 if let Some(children) = self.dependents.get(name) {
1313 for child in children {
1314 self.invalidate_recursive(child, visited);
1315 }
1316 }
1317 }
1318
1319 fn bump_generation(&self) {
1320 let current = self.generation.get();
1321 self.generation.set(current.wrapping_add(1));
1322 }
1323
1324 fn get_converter_node(&self, name: &str) -> Result<&ConverterNode, GenApiError> {
1329 match self.nodes.get(name) {
1330 Some(Node::Converter(node)) => Ok(node),
1331 Some(_) => Err(GenApiError::Type(name.to_string())),
1332 None => Err(GenApiError::NodeNotFound(name.to_string())),
1333 }
1334 }
1335
1336 fn get_int_converter_node(&self, name: &str) -> Result<&IntConverterNode, GenApiError> {
1337 match self.nodes.get(name) {
1338 Some(Node::IntConverter(node)) => Ok(node),
1339 Some(_) => Err(GenApiError::Type(name.to_string())),
1340 None => Err(GenApiError::NodeNotFound(name.to_string())),
1341 }
1342 }
1343
1344 fn get_string_node(&self, name: &str) -> Result<&StringNode, GenApiError> {
1345 match self.nodes.get(name) {
1346 Some(Node::String(node)) => Ok(node),
1347 Some(_) => Err(GenApiError::Type(name.to_string())),
1348 None => Err(GenApiError::NodeNotFound(name.to_string())),
1349 }
1350 }
1351
1352 fn get_register_node(&self, name: &str) -> Result<&RegisterNode, GenApiError> {
1353 match self.nodes.get(name) {
1354 Some(Node::Register(node)) => Ok(node),
1355 Some(_) => Err(GenApiError::Type(name.to_string())),
1356 None => Err(GenApiError::NodeNotFound(name.to_string())),
1357 }
1358 }
1359
1360 pub fn get_converter(&self, name: &str, io: &dyn RegisterIo) -> Result<f64, GenApiError> {
1362 let node = self.get_converter_node(name)?;
1363 if let Some((value, generation)) = *node.cache.borrow()
1364 && generation == self.generation.get()
1365 {
1366 return Ok(value.as_f64());
1367 }
1368 let mut stack = HashSet::new();
1369 let value = self.evaluate_converter(node, io, &mut stack)?;
1370 node.cache.replace(Some((value, self.generation.get())));
1371 Ok(value.as_f64())
1372 }
1373
1374 pub fn get_int_converter(&self, name: &str, io: &dyn RegisterIo) -> Result<i64, GenApiError> {
1376 let node = self.get_int_converter_node(name)?;
1377 if let Some((value, generation)) = *node.cache.borrow()
1378 && generation == self.generation.get()
1379 {
1380 return Ok(value);
1381 }
1382 let mut stack = HashSet::new();
1383 let value = self.evaluate_int_converter(node, io, &mut stack)?;
1384 node.cache.replace(Some((value, self.generation.get())));
1385 Ok(value)
1386 }
1387
1388 pub fn set_converter(
1390 &mut self,
1391 name: &str,
1392 value: f64,
1393 io: &dyn RegisterIo,
1394 ) -> Result<(), GenApiError> {
1395 let node = self.get_converter_node(name)?;
1396 let (p_value, raw) = self.converter_raw_write(
1397 &node.name,
1398 &node.ast_to,
1399 &node.vars_to,
1400 &node.p_value,
1401 SkValue::Float(value),
1402 eval_mode(node.output),
1403 io,
1404 )?;
1405 self.write_converter_raw(&p_value, raw, io)?;
1406 self.invalidate_dependents(name);
1407 Ok(())
1408 }
1409
1410 pub fn set_int_converter(
1412 &mut self,
1413 name: &str,
1414 value: i64,
1415 io: &dyn RegisterIo,
1416 ) -> Result<(), GenApiError> {
1417 let node = self.get_int_converter_node(name)?;
1418 let (p_value, raw) = self.converter_raw_write(
1419 &node.name,
1420 &node.ast_to,
1421 &node.vars_to,
1422 &node.p_value,
1423 SkValue::Int(value),
1424 EvalMode::Integer,
1425 io,
1426 )?;
1427 self.write_converter_raw(&p_value, raw, io)?;
1428 self.invalidate_dependents(name);
1429 Ok(())
1430 }
1431
1432 #[allow(clippy::too_many_arguments)]
1439 fn converter_raw_write(
1440 &self,
1441 name: &str,
1442 ast_to: &SkAst,
1443 vars_to: &[(String, String)],
1444 p_value: &str,
1445 value: SkValue,
1446 mode: EvalMode,
1447 io: &dyn RegisterIo,
1448 ) -> Result<(String, SkValue), GenApiError> {
1449 let mut stack = HashSet::new();
1450 let mut overrides = vec![("FROM", value)];
1451 if vars_to.iter().any(|(var, _)| var == "OLD") {
1452 let old = self.resolve_value(p_value, io, &mut stack)?;
1453 overrides.push(("OLD", old));
1454 }
1455 let raw = self.eval_formula(name, ast_to, vars_to, &overrides, mode, io, &mut stack)?;
1456 Ok((p_value.to_string(), raw))
1457 }
1458
1459 fn write_converter_raw(
1460 &mut self,
1461 p_value: &str,
1462 raw: SkValue,
1463 io: &dyn RegisterIo,
1464 ) -> Result<(), GenApiError> {
1465 match self.nodes.get(p_value) {
1466 Some(Node::Float(_)) => self.set_float(p_value, raw.as_f64(), io),
1467 Some(Node::Boolean(_)) => self.set_bool(p_value, raw.is_truthy(), io),
1468 Some(_) => self.set_integer(p_value, sk_to_i64(p_value, raw)?, io),
1469 None => Err(GenApiError::NodeNotFound(p_value.to_string())),
1470 }
1471 }
1472
1473 pub fn get_string(&self, name: &str, io: &dyn RegisterIo) -> Result<String, GenApiError> {
1475 let node = self.get_string_node(name)?;
1476 ensure_readable(&node.access, name)?;
1477 if let Some((ref value, generation)) = *node.cache.borrow()
1478 && generation == self.generation.get()
1479 {
1480 return Ok(value.clone());
1481 }
1482 let (address, len) = self.resolve_address(name, &node.addressing, io)?;
1483 let raw = io.read(address, len as usize)?;
1484 let end = raw.iter().position(|&b| b == 0).unwrap_or(raw.len());
1486 let value = String::from_utf8_lossy(&raw[..end]).to_string();
1487 node.cache
1488 .replace(Some((value.clone(), self.generation.get())));
1489 debug!(node = %name, value = %value, "get_string");
1490 Ok(value)
1491 }
1492
1493 pub fn set_string(
1495 &self,
1496 name: &str,
1497 value: &str,
1498 io: &dyn RegisterIo,
1499 ) -> Result<(), GenApiError> {
1500 let node = self.get_string_node(name)?;
1501 self.ensure_writable_now(name, &node.access, io)?;
1502 let (address, len) = self.resolve_address(name, &node.addressing, io)?;
1503 let mut buf = vec![0u8; len as usize];
1505 let bytes = value.as_bytes();
1506 let copy_len = bytes.len().min(len as usize);
1507 buf[..copy_len].copy_from_slice(&bytes[..copy_len]);
1508 io.write(address, &buf)?;
1509 node.cache
1510 .replace(Some((value.to_string(), self.generation.get())));
1511 self.invalidate_dependents(name);
1512 debug!(node = %name, value = %value, "set_string");
1513 Ok(())
1514 }
1515
1516 pub fn get_register(&self, name: &str, io: &dyn RegisterIo) -> Result<Vec<u8>, GenApiError> {
1523 let node = self.get_register_node(name)?;
1524 ensure_readable(&node.access, name)?;
1525 ensure_device_port(name, node.port.as_deref())?;
1526 if let Some((ref value, generation)) = *node.cache.borrow()
1527 && generation == self.generation.get()
1528 {
1529 return Ok(value.clone());
1530 }
1531 let (address, len) = self.resolve_address(name, &node.addressing, io)?;
1532 let raw = io.read(address, len as usize)?;
1533 node.cache
1534 .replace(Some((raw.clone(), self.generation.get())));
1535 debug!(node = %name, len = raw.len(), "get_register");
1536 Ok(raw)
1537 }
1538
1539 pub fn set_register(
1546 &self,
1547 name: &str,
1548 data: &[u8],
1549 io: &dyn RegisterIo,
1550 ) -> Result<(), GenApiError> {
1551 let node = self.get_register_node(name)?;
1552 self.ensure_writable_now(name, &node.access, io)?;
1553 ensure_device_port(name, node.port.as_deref())?;
1554 let (address, len) = self.resolve_address(name, &node.addressing, io)?;
1555 if data.len() != len as usize {
1556 return Err(GenApiError::Range(format!(
1557 "register '{name}' is {len} bytes; got {}",
1558 data.len()
1559 )));
1560 }
1561 io.write(address, data)?;
1562 node.cache
1563 .replace(Some((data.to_vec(), self.generation.get())));
1564 self.invalidate_dependents(name);
1565 debug!(node = %name, len = data.len(), "set_register");
1566 Ok(())
1567 }
1568
1569 fn evaluate_converter(
1571 &self,
1572 node: &ConverterNode,
1573 io: &dyn RegisterIo,
1574 stack: &mut HashSet<String>,
1575 ) -> Result<SkValue, GenApiError> {
1576 if !stack.insert(node.name.clone()) {
1577 stack.remove(&node.name);
1578 return Err(GenApiError::ExprEval {
1579 name: node.name.clone(),
1580 msg: "cyclic dependency".into(),
1581 });
1582 }
1583 let result = self.eval_formula(
1584 &node.name,
1585 &node.ast_from,
1586 &node.vars_from,
1587 &[],
1588 eval_mode(node.output),
1589 io,
1590 stack,
1591 );
1592 stack.remove(&node.name);
1593 let value = result?;
1594 debug!(node = %node.name, value = %value, "evaluate Converter");
1595 Ok(value)
1596 }
1597
1598 fn evaluate_int_converter(
1600 &self,
1601 node: &IntConverterNode,
1602 io: &dyn RegisterIo,
1603 stack: &mut HashSet<String>,
1604 ) -> Result<i64, GenApiError> {
1605 if !stack.insert(node.name.clone()) {
1606 stack.remove(&node.name);
1607 return Err(GenApiError::ExprEval {
1608 name: node.name.clone(),
1609 msg: "cyclic dependency".into(),
1610 });
1611 }
1612 let result = self.eval_formula(
1613 &node.name,
1614 &node.ast_from,
1615 &node.vars_from,
1616 &[],
1617 EvalMode::Integer,
1618 io,
1619 stack,
1620 );
1621 stack.remove(&node.name);
1622 let int_value = result?.as_i64();
1623 debug!(node = %node.name, int_value, "evaluate IntConverter");
1624 Ok(int_value)
1625 }
1626}
1627
1628fn build_node(
1631 decl: NodeDecl,
1632 dependents: &mut HashMap<String, Vec<String>>,
1633) -> Result<(String, Node), GenApiError> {
1634 match decl {
1635 NodeDecl::Integer {
1636 name,
1637 meta,
1638 addressing,
1639 len,
1640 access,
1641 min,
1642 max,
1643 inc,
1644 unit,
1645 bitfield,
1646 sign,
1647 selectors,
1648 selected_if,
1649 pvalue,
1650 p_max,
1651 p_min,
1652 value,
1653 predicates,
1654 } => {
1655 if let Some(ref addr) = addressing {
1656 register_addressing_dependency(dependents, &name, addr);
1657 }
1658 if let Some(ref pv) = pvalue {
1659 dependents.entry(pv.clone()).or_default().push(name.clone());
1660 }
1661 if let Some(ref pm) = p_max {
1662 dependents.entry(pm.clone()).or_default().push(name.clone());
1663 }
1664 if let Some(ref pm) = p_min {
1665 dependents.entry(pm.clone()).or_default().push(name.clone());
1666 }
1667 for (selector, _) in &selected_if {
1668 dependents
1669 .entry(selector.clone())
1670 .or_default()
1671 .push(name.clone());
1672 }
1673 register_predicate_dependencies(dependents, &name, &predicates);
1674 let node = IntegerNode {
1675 name: name.clone(),
1676 meta,
1677 addressing,
1678 len,
1679 access,
1680 min,
1681 max,
1682 inc,
1683 unit,
1684 bitfield,
1685 sign,
1686 selectors,
1687 selected_if,
1688 pvalue,
1689 p_max,
1690 p_min,
1691 value,
1692 predicates,
1693 cache: std::cell::RefCell::new(None),
1694 raw_cache: std::cell::RefCell::new(None),
1695 };
1696 Ok((name, Node::Integer(node)))
1697 }
1698 NodeDecl::Float {
1699 name,
1700 meta,
1701 addressing,
1702 access,
1703 min,
1704 max,
1705 unit,
1706 scale,
1707 offset,
1708 selectors,
1709 selected_if,
1710 pvalue,
1711 encoding,
1712 byte_order,
1713 predicates,
1714 } => {
1715 if let Some(ref addr) = addressing {
1716 register_addressing_dependency(dependents, &name, addr);
1717 }
1718 if let Some(ref pv) = pvalue {
1719 dependents.entry(pv.clone()).or_default().push(name.clone());
1720 }
1721 for (selector, _) in &selected_if {
1722 dependents
1723 .entry(selector.clone())
1724 .or_default()
1725 .push(name.clone());
1726 }
1727 register_predicate_dependencies(dependents, &name, &predicates);
1728 let node = FloatNode {
1729 name: name.clone(),
1730 meta,
1731 addressing,
1732 access,
1733 min,
1734 max,
1735 unit,
1736 scale,
1737 offset,
1738 selectors,
1739 selected_if,
1740 pvalue,
1741 encoding,
1742 byte_order,
1743 predicates,
1744 cache: std::cell::RefCell::new(None),
1745 };
1746 Ok((name, Node::Float(node)))
1747 }
1748 NodeDecl::Enum {
1749 name,
1750 meta,
1751 addressing,
1752 access,
1753 entries,
1754 default,
1755 selectors,
1756 selected_if,
1757 pvalue,
1758 predicates,
1759 } => {
1760 if let Some(ref addr) = addressing {
1761 register_addressing_dependency(dependents, &name, addr);
1762 }
1763 if let Some(ref pv) = pvalue {
1764 dependents.entry(pv.clone()).or_default().push(name.clone());
1765 }
1766 for (selector, _) in &selected_if {
1767 dependents
1768 .entry(selector.clone())
1769 .or_default()
1770 .push(name.clone());
1771 }
1772 register_predicate_dependencies(dependents, &name, &predicates);
1773 let mut providers = Vec::new();
1774 let mut provider_set = HashSet::new();
1775 for entry in &entries {
1776 if let EnumValueSrc::FromNode(node_name) = &entry.value {
1777 dependents
1778 .entry(node_name.clone())
1779 .or_default()
1780 .push(name.clone());
1781 if provider_set.insert(node_name.clone()) {
1782 providers.push(node_name.clone());
1783 }
1784 }
1785 register_predicate_dependencies(dependents, &name, &entry.predicates);
1786 }
1787 providers.sort();
1788 let node = EnumNode {
1789 name: name.clone(),
1790 meta,
1791 addressing,
1792 access,
1793 pvalue,
1794 entries,
1795 default,
1796 selectors,
1797 selected_if,
1798 providers,
1799 predicates,
1800 value_cache: std::cell::RefCell::new(None),
1801 mapping_cache: std::cell::RefCell::new(None),
1802 };
1803 Ok((name, Node::Enum(node)))
1804 }
1805 NodeDecl::Boolean {
1806 name,
1807 meta,
1808 addressing,
1809 len,
1810 access,
1811 bitfield,
1812 selectors,
1813 selected_if,
1814 pvalue,
1815 on_value,
1816 off_value,
1817 predicates,
1818 } => {
1819 if let Some(ref addr) = addressing {
1820 register_addressing_dependency(dependents, &name, addr);
1821 }
1822 if let Some(ref pv) = pvalue {
1823 dependents.entry(pv.clone()).or_default().push(name.clone());
1824 }
1825 for (selector, _) in &selected_if {
1826 dependents
1827 .entry(selector.clone())
1828 .or_default()
1829 .push(name.clone());
1830 }
1831 register_predicate_dependencies(dependents, &name, &predicates);
1832 let node = BooleanNode {
1833 name: name.clone(),
1834 meta,
1835 addressing,
1836 len,
1837 access,
1838 bitfield,
1839 selectors,
1840 selected_if,
1841 pvalue,
1842 on_value,
1843 off_value,
1844 predicates,
1845 cache: std::cell::RefCell::new(None),
1846 raw_cache: std::cell::RefCell::new(None),
1847 };
1848 Ok((name, Node::Boolean(node)))
1849 }
1850 NodeDecl::Command {
1851 name,
1852 meta,
1853 address,
1854 len,
1855 pvalue,
1856 command_value,
1857 predicates,
1858 } => {
1859 if let Some(ref pv) = pvalue {
1860 dependents.entry(pv.clone()).or_default().push(name.clone());
1861 }
1862 register_predicate_dependencies(dependents, &name, &predicates);
1863 let node = CommandNode {
1864 name: name.clone(),
1865 meta,
1866 address,
1867 len,
1868 pvalue,
1869 command_value,
1870 predicates,
1871 };
1872 Ok((name, Node::Command(node)))
1873 }
1874 NodeDecl::Category {
1875 name,
1876 meta,
1877 children,
1878 predicates,
1879 } => {
1880 register_predicate_dependencies(dependents, &name, &predicates);
1881 let node = CategoryNode {
1882 name: name.clone(),
1883 meta,
1884 children,
1885 predicates,
1886 };
1887 Ok((name, Node::Category(node)))
1888 }
1889 NodeDecl::SwissKnife(decl) => {
1890 let name = decl.name;
1891 let meta = decl.meta;
1892 let expr = decl.expr;
1893 let variables = decl.variables;
1894 let output = decl.output;
1895 let predicates = decl.predicates;
1896 let mut ast = parse_expression(&expr).map_err(|err| GenApiError::ExprParse {
1897 name: name.clone(),
1898 msg: err.to_string(),
1899 })?;
1900 substitute(&mut ast, &formula_bindings(&name, &decl.bindings)?);
1901 let mut used = HashSet::new();
1902 collect_identifiers(&ast, &mut used);
1903 for ident in &used {
1904 if !variables.iter().any(|(var, _)| var == ident) && !is_builtin_constant(ident) {
1907 return Err(GenApiError::UnknownVariable {
1908 name: name.clone(),
1909 var: ident.clone(),
1910 });
1911 }
1912 }
1913 for (_, provider) in &variables {
1914 dependents
1915 .entry(provider.clone())
1916 .or_default()
1917 .push(name.clone());
1918 }
1919 register_predicate_dependencies(dependents, &name, &predicates);
1920 let node = SkNode {
1921 name: name.clone(),
1922 meta,
1923 output,
1924 ast,
1925 vars: variables,
1926 predicates,
1927 cache: std::cell::RefCell::new(None),
1928 };
1929 Ok((name, Node::SwissKnife(node)))
1930 }
1931 NodeDecl::Converter(decl) => {
1932 let name = decl.name;
1933 let bindings = formula_bindings(&name, &decl.bindings)?;
1934 let mut ast_to =
1935 parse_expression(&decl.formula_to).map_err(|err| GenApiError::ExprParse {
1936 name: name.clone(),
1937 msg: format!("FormulaTo: {err}"),
1938 })?;
1939 substitute(&mut ast_to, &bindings);
1940 let mut ast_from =
1941 parse_expression(&decl.formula_from).map_err(|err| GenApiError::ExprParse {
1942 name: name.clone(),
1943 msg: format!("FormulaFrom: {err}"),
1944 })?;
1945 substitute(&mut ast_from, &bindings);
1946 for (_, provider) in &decl.variables_to {
1948 dependents
1949 .entry(provider.clone())
1950 .or_default()
1951 .push(name.clone());
1952 }
1953 for (_, provider) in &decl.variables_from {
1954 if !decl.variables_to.iter().any(|(_, p)| p == provider) {
1955 dependents
1956 .entry(provider.clone())
1957 .or_default()
1958 .push(name.clone());
1959 }
1960 }
1961 dependents
1963 .entry(decl.p_value.clone())
1964 .or_default()
1965 .push(name.clone());
1966 register_predicate_dependencies(dependents, &name, &decl.predicates);
1967 let node = ConverterNode {
1968 name: name.clone(),
1969 meta: decl.meta,
1970 p_value: decl.p_value,
1971 ast_to,
1972 ast_from,
1973 vars_to: decl.variables_to,
1974 vars_from: decl.variables_from,
1975 unit: decl.unit,
1976 output: decl.output,
1977 predicates: decl.predicates,
1978 cache: std::cell::RefCell::new(None),
1979 };
1980 Ok((name, Node::Converter(node)))
1981 }
1982 NodeDecl::IntConverter(decl) => {
1983 let name = decl.name;
1984 let bindings = formula_bindings(&name, &decl.bindings)?;
1985 let mut ast_to =
1986 parse_expression(&decl.formula_to).map_err(|err| GenApiError::ExprParse {
1987 name: name.clone(),
1988 msg: format!("FormulaTo: {err}"),
1989 })?;
1990 substitute(&mut ast_to, &bindings);
1991 let mut ast_from =
1992 parse_expression(&decl.formula_from).map_err(|err| GenApiError::ExprParse {
1993 name: name.clone(),
1994 msg: format!("FormulaFrom: {err}"),
1995 })?;
1996 substitute(&mut ast_from, &bindings);
1997 for (_, provider) in &decl.variables_to {
1998 dependents
1999 .entry(provider.clone())
2000 .or_default()
2001 .push(name.clone());
2002 }
2003 for (_, provider) in &decl.variables_from {
2004 if !decl.variables_to.iter().any(|(_, p)| p == provider) {
2005 dependents
2006 .entry(provider.clone())
2007 .or_default()
2008 .push(name.clone());
2009 }
2010 }
2011 dependents
2012 .entry(decl.p_value.clone())
2013 .or_default()
2014 .push(name.clone());
2015 register_predicate_dependencies(dependents, &name, &decl.predicates);
2016 let node = IntConverterNode {
2017 name: name.clone(),
2018 meta: decl.meta,
2019 p_value: decl.p_value,
2020 ast_to,
2021 ast_from,
2022 vars_to: decl.variables_to,
2023 vars_from: decl.variables_from,
2024 unit: decl.unit,
2025 predicates: decl.predicates,
2026 cache: std::cell::RefCell::new(None),
2027 };
2028 Ok((name, Node::IntConverter(node)))
2029 }
2030 NodeDecl::String(decl) => {
2031 let name = decl.name;
2032 register_addressing_dependency(dependents, &name, &decl.addressing);
2033 register_predicate_dependencies(dependents, &name, &decl.predicates);
2034 let node = StringNode {
2035 name: name.clone(),
2036 meta: decl.meta,
2037 addressing: decl.addressing,
2038 access: decl.access,
2039 predicates: decl.predicates,
2040 cache: std::cell::RefCell::new(None),
2041 };
2042 Ok((name, Node::String(node)))
2043 }
2044 NodeDecl::Register(decl) => {
2045 let name = decl.name;
2046 register_addressing_dependency(dependents, &name, &decl.addressing);
2047 register_predicate_dependencies(dependents, &name, &decl.predicates);
2048 let node = RegisterNode {
2049 name: name.clone(),
2050 meta: decl.meta,
2051 addressing: decl.addressing,
2052 access: decl.access,
2053 port: decl.port,
2054 predicates: decl.predicates,
2055 cache: std::cell::RefCell::new(None),
2056 };
2057 Ok((name, Node::Register(node)))
2058 }
2059 other => Err(GenApiError::Unsupported(format!(
2065 "node '{}' has declaration kind '{}', which this nodemap cannot build; \
2066 viva-genapi-xml understands it but viva-genapi has no arm for it",
2067 other.name(),
2068 other.kind()
2069 ))),
2070 }
2071}
2072
2073fn integer_sign(node: &IntegerNode) -> Sign {
2087 node.sign
2088}
2089
2090fn formula_bindings(
2098 node: &str,
2099 declared: &FormulaBindings,
2100) -> Result<HashMap<String, SkAst>, GenApiError> {
2101 let mut bindings: HashMap<String, SkAst> = HashMap::new();
2102 for (name, literal) in &declared.constants {
2103 let value = parse_expression(literal).map_err(|err| GenApiError::ExprParse {
2104 name: node.to_string(),
2105 msg: format!("Constant {name}: {err}"),
2106 })?;
2107 bindings.insert(name.clone(), value);
2108 }
2109 for (name, formula) in &declared.expressions {
2110 let mut ast = parse_expression(formula).map_err(|err| GenApiError::ExprParse {
2111 name: node.to_string(),
2112 msg: format!("Expression {name}: {err}"),
2113 })?;
2114 substitute(&mut ast, &bindings);
2115 bindings.insert(name.clone(), ast);
2116 }
2117 Ok(bindings)
2118}
2119
2120fn sk_to_i64(name: &str, value: SkValue) -> Result<i64, GenApiError> {
2126 match value {
2127 SkValue::Int(value) => Ok(value),
2128 SkValue::Float(value) => round_to_i64(name, value),
2129 }
2130}
2131
2132fn eval_mode(output: SkOutput) -> EvalMode {
2134 match output {
2135 SkOutput::Integer => EvalMode::Integer,
2136 SkOutput::Float => EvalMode::Float,
2137 }
2138}
2139
2140fn expr_error(name: &str, err: SkEvalError) -> GenApiError {
2142 match err {
2143 SkEvalError::UnknownVariable(var) => GenApiError::UnknownVariable {
2144 name: name.to_string(),
2145 var,
2146 },
2147 SkEvalError::DivisionByZero => GenApiError::ExprEval {
2148 name: name.to_string(),
2149 msg: "division by zero".into(),
2150 },
2151 SkEvalError::UnknownFunction(func) => GenApiError::ExprEval {
2152 name: name.to_string(),
2153 msg: format!("unknown function: {func}"),
2154 },
2155 SkEvalError::ArityMismatch {
2156 name: func,
2157 expected,
2158 got,
2159 } => GenApiError::ExprEval {
2160 name: name.to_string(),
2161 msg: format!("function {func} expects {expected} args, got {got}"),
2162 },
2163 }
2164}
2165
2166impl TryFrom<XmlModel> for NodeMap {
2167 type Error = GenApiError;
2168
2169 fn try_from(model: XmlModel) -> Result<Self, Self::Error> {
2170 NodeMap::try_from_xml(model)
2171 }
2172}