Skip to main content

damiao_codec/
types.rs

1//! Damiao motor type and register-ID enums.
2
3use motor_codec::MotorTypeId;
4
5/// Damiao motor SKUs supported by v1 of this codec.
6///
7/// Each variant maps to a unique `u16` discriminant carried by
8/// [`MotorTypeId::Damiao`]. Discriminants are intentionally explicit so they
9/// remain stable across refactors.
10#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
11#[repr(u16)]
12#[non_exhaustive]
13pub enum DamiaoMotorType {
14    /// DM-3507 — small ankle/wrist actuator.
15    DM3507 = 0,
16    /// DM-4310 24V.
17    DM4310 = 1,
18    /// DM-4310 48V.
19    DM4310_48V = 2,
20    /// DM-4340 24V (default workhorse for OpenArm).
21    DM4340 = 3,
22    /// DM-4340 48V.
23    DM4340_48V = 4,
24    /// DM-6006.
25    DM6006 = 5,
26    /// DM-8006.
27    DM8006 = 6,
28    /// DM-8009.
29    DM8009 = 7,
30    /// DM-10010L (low-speed, high-torque hip).
31    DM10010L = 8,
32    /// DM-10010 (high-speed hip).
33    DM10010 = 9,
34    /// DM-H3510 (high-speed micro).
35    DMH3510 = 10,
36    /// DM-H6215.
37    DMH6215 = 11,
38    /// DM-G6220 (gearbox geared).
39    DMG6220 = 12,
40}
41
42impl DamiaoMotorType {
43    /// Inverse of `From<u16>`; returns `None` for unknown discriminants.
44    pub fn from_discriminant(d: u16) -> Option<Self> {
45        Some(match d {
46            0 => Self::DM3507,
47            1 => Self::DM4310,
48            2 => Self::DM4310_48V,
49            3 => Self::DM4340,
50            4 => Self::DM4340_48V,
51            5 => Self::DM6006,
52            6 => Self::DM8006,
53            7 => Self::DM8009,
54            8 => Self::DM10010L,
55            9 => Self::DM10010,
56            10 => Self::DMH3510,
57            11 => Self::DMH6215,
58            12 => Self::DMG6220,
59            _ => return None,
60        })
61    }
62}
63
64impl From<DamiaoMotorType> for MotorTypeId {
65    fn from(t: DamiaoMotorType) -> Self {
66        MotorTypeId::Damiao(t as u16)
67    }
68}
69
70/// Look up a Damiao SKU by string (used by the TOML loader to resolve
71/// `type = "DM4340"` config fields).
72///
73/// Returns `None` for unknown SKU strings.
74pub fn parse_motor_type(s: &str) -> Option<MotorTypeId> {
75    let t = match s {
76        "DM3507" => DamiaoMotorType::DM3507,
77        "DM4310" => DamiaoMotorType::DM4310,
78        "DM4310_48V" => DamiaoMotorType::DM4310_48V,
79        "DM4340" => DamiaoMotorType::DM4340,
80        "DM4340_48V" => DamiaoMotorType::DM4340_48V,
81        "DM6006" => DamiaoMotorType::DM6006,
82        "DM8006" => DamiaoMotorType::DM8006,
83        "DM8009" => DamiaoMotorType::DM8009,
84        "DM10010L" => DamiaoMotorType::DM10010L,
85        "DM10010" => DamiaoMotorType::DM10010,
86        "DMH3510" => DamiaoMotorType::DMH3510,
87        "DMH6215" => DamiaoMotorType::DMH6215,
88        "DMG6220" => DamiaoMotorType::DMG6220,
89        _ => return None,
90    };
91    Some(t.into())
92}
93
94/// Register IDs for the Damiao parameter sub-protocol (CAN ID `0x7FF`).
95///
96/// Byte values match Damiao's protocol manual.
97#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
98#[repr(u8)]
99#[non_exhaustive]
100#[allow(non_camel_case_types, missing_docs)]
101pub enum DamiaoRid {
102    UV_Value = 0,
103    KT_Value = 1,
104    OT_Value = 2,
105    OC_Value = 3,
106    ACC = 4,
107    DEC = 5,
108    MAX_SPD = 6,
109    MST_ID = 7,
110    ESC_ID = 8,
111    TIMEOUT = 9,
112    CTRL_MODE = 10,
113    Damp = 11,
114    Inertia = 12,
115    hw_ver = 13,
116    sw_ver = 14,
117    SN = 15,
118    NPP = 16,
119    Rs = 17,
120    LS = 18,
121    Flux = 19,
122    Gr = 20,
123    PMAX = 21,
124    VMAX = 22,
125    TMAX = 23,
126    I_BW = 24,
127    KP_ASR = 25,
128    KI_ASR = 26,
129    KP_APR = 27,
130    KI_APR = 28,
131    OV_Value = 29,
132    GREF = 30,
133    Deta = 31,
134    V_BW = 32,
135    IQ_c1 = 33,
136    VL_c1 = 34,
137    can_br = 35,
138    sub_ver = 36,
139}
140
141impl From<DamiaoRid> for u8 {
142    fn from(r: DamiaoRid) -> u8 {
143        r as u8
144    }
145}
146
147#[cfg(test)]
148mod tests {
149    use super::*;
150
151    const ALL_SKUS: &[(&str, u16)] = &[
152        ("DM3507", 0),
153        ("DM4310", 1),
154        ("DM4310_48V", 2),
155        ("DM4340", 3),
156        ("DM4340_48V", 4),
157        ("DM6006", 5),
158        ("DM8006", 6),
159        ("DM8009", 7),
160        ("DM10010L", 8),
161        ("DM10010", 9),
162        ("DMH3510", 10),
163        ("DMH6215", 11),
164        ("DMG6220", 12),
165    ];
166
167    #[test]
168    fn all_13_skus_parse() {
169        for (name, disc) in ALL_SKUS {
170            let id = parse_motor_type(name).unwrap_or_else(|| panic!("parse {name}"));
171            assert_eq!(id, MotorTypeId::Damiao(*disc), "SKU {name}");
172        }
173    }
174
175    #[test]
176    fn unknown_string_returns_none() {
177        assert!(parse_motor_type("DM_DOES_NOT_EXIST").is_none());
178    }
179
180    #[test]
181    fn rid_to_u8_known() {
182        assert_eq!(u8::from(DamiaoRid::CTRL_MODE), 10);
183        assert_eq!(u8::from(DamiaoRid::MST_ID), 7);
184        assert_eq!(u8::from(DamiaoRid::PMAX), 21);
185    }
186}