moteus_protocol/resolution.rs
1// Copyright 2026 mjbots Robotic Systems, LLC. info@mjbots.com
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Resolution types for register values.
16
17/// The resolution (data type) used when encoding or decoding a register value.
18///
19/// Each resolution type determines:
20/// - The number of bytes used on the wire
21/// - The scaling applied to convert between wire format and physical units
22/// - The range of representable values
23#[non_exhaustive]
24#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
25#[repr(i8)]
26pub enum Resolution {
27 /// 8-bit signed integer (1 byte)
28 Int8 = 0,
29 /// 16-bit signed integer (2 bytes)
30 Int16 = 1,
31 /// 32-bit signed integer (4 bytes)
32 Int32 = 2,
33 /// 32-bit IEEE 754 float (4 bytes)
34 Float = 3,
35 /// This register should be ignored/not transmitted
36 #[default]
37 Ignore = 4,
38}
39
40impl core::fmt::Display for Resolution {
41 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
42 match self {
43 Resolution::Int8 => write!(f, "int8"),
44 Resolution::Int16 => write!(f, "int16"),
45 Resolution::Int32 => write!(f, "int32"),
46 Resolution::Float => write!(f, "float"),
47 Resolution::Ignore => write!(f, "ignore"),
48 }
49 }
50}
51
52impl Resolution {
53 /// Returns the size in bytes for this resolution type.
54 ///
55 /// Returns 0 for `Ignore`.
56 #[inline]
57 pub const fn size(self) -> usize {
58 match self {
59 Resolution::Int8 => 1,
60 Resolution::Int16 => 2,
61 Resolution::Int32 => 4,
62 Resolution::Float => 4,
63 Resolution::Ignore => 0,
64 }
65 }
66
67 /// Returns the multiplex protocol type code for this resolution.
68 ///
69 /// This is used in the wire protocol to identify the data type.
70 #[inline]
71 pub const fn type_code(self) -> u8 {
72 match self {
73 Resolution::Int8 => 0x00,
74 Resolution::Int16 => 0x04,
75 Resolution::Int32 => 0x08,
76 Resolution::Float => 0x0c,
77 Resolution::Ignore => 0x00, // Should not be used
78 }
79 }
80
81 /// Creates a Resolution from a type code.
82 ///
83 /// Returns `None` if the type code is invalid.
84 #[inline]
85 pub const fn from_type_code(code: u8) -> Option<Resolution> {
86 match code & 0x0c {
87 0x00 => Some(Resolution::Int8),
88 0x04 => Some(Resolution::Int16),
89 0x08 => Some(Resolution::Int32),
90 0x0c => Some(Resolution::Float),
91 _ => None,
92 }
93 }
94
95 /// Returns the minimum representable value for integer types.
96 ///
97 /// This value is used to represent NaN in the protocol.
98 #[inline]
99 pub const fn nan_value(self) -> i32 {
100 match self {
101 Resolution::Int8 => -128,
102 Resolution::Int16 => -32768,
103 Resolution::Int32 => i32::MIN,
104 Resolution::Float => 0, // NaN represented differently
105 Resolution::Ignore => 0,
106 }
107 }
108
109 /// Returns the maximum representable value for integer types.
110 #[inline]
111 pub const fn max_value(self) -> i32 {
112 match self {
113 Resolution::Int8 => 127,
114 Resolution::Int16 => 32767,
115 Resolution::Int32 => i32::MAX,
116 Resolution::Float => 0, // Not applicable
117 Resolution::Ignore => 0,
118 }
119 }
120}
121
122#[cfg(test)]
123mod tests {
124 use super::*;
125
126 #[test]
127 fn test_resolution_size() {
128 assert_eq!(Resolution::Int8.size(), 1);
129 assert_eq!(Resolution::Int16.size(), 2);
130 assert_eq!(Resolution::Int32.size(), 4);
131 assert_eq!(Resolution::Float.size(), 4);
132 assert_eq!(Resolution::Ignore.size(), 0);
133 }
134
135 #[test]
136 fn test_type_code_roundtrip() {
137 for res in [
138 Resolution::Int8,
139 Resolution::Int16,
140 Resolution::Int32,
141 Resolution::Float,
142 ] {
143 let code = res.type_code();
144 assert_eq!(Resolution::from_type_code(code), Some(res));
145 }
146 }
147}