signalk/
steering.rs

1use crate::definitions::V2NumberValue;
2use crate::helper_functions::{get_f64_value, get_f64_value_for_path, F64CompatiblePath};
3use crate::{SignalKGetError, V1CommonValueFields};
4use serde::{Deserialize, Serialize};
5
6#[derive(Serialize, Deserialize, PartialEq, Debug, Default, Clone)]
7#[serde(rename_all = "camelCase")]
8pub struct V1Steering {
9    pub rudder_angle: Option<V2NumberValue>,
10    pub rudder_angle_target: Option<V2NumberValue>,
11    pub autopilot: Option<V1SteeringAutopilot>,
12}
13
14impl F64CompatiblePath for V1Steering {
15    fn get_f64_for_path(&self, path: &mut Vec<&str>) -> Result<f64, SignalKGetError> {
16        match path[0] {
17            "rudderAngle" => get_f64_value(&self.rudder_angle),
18            "rudderAngleTarget" => get_f64_value(&self.rudder_angle_target),
19            "autopilot" => get_f64_value_for_path(path, &self.autopilot),
20            &_ => Err(SignalKGetError::NoSuchPath),
21        }
22    }
23}
24
25#[derive(Serialize, Deserialize, PartialEq, Debug, Default, Clone)]
26#[serde(rename_all = "camelCase")]
27pub struct V1SteeringAutopilot {
28    pub state: Option<V1SteeringAutopilotState>,
29    pub mode: Option<V1SteeringAutopilotMode>,
30    pub target: Option<V1SteeringAutopilotTarget>,
31    pub dead_zone: Option<V2NumberValue>,
32    pub backlash: Option<V2NumberValue>,
33    pub gain: Option<V2NumberValue>,
34    pub max_drive_current: Option<V2NumberValue>,
35    pub max_drive_rate: Option<V2NumberValue>,
36    pub port_lock: Option<V2NumberValue>,
37    pub starboard_lock: Option<V2NumberValue>,
38}
39
40impl F64CompatiblePath for V1SteeringAutopilot {
41    fn get_f64_for_path(&self, path: &mut Vec<&str>) -> Result<f64, SignalKGetError> {
42        match path[0] {
43            &_ => Err(SignalKGetError::NoSuchPath),
44        }
45    }
46}
47
48#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
49#[serde(untagged)]
50pub enum V1SteeringAutopilotState {
51    Expanded(V1SteeringAutopilotStateExpandedValue),
52    Value(V1SteeringAutopilotStateValue),
53}
54
55impl Default for V1SteeringAutopilotState {
56    fn default() -> Self {
57        V1SteeringAutopilotState::Value(V1SteeringAutopilotStateValue::default())
58    }
59}
60#[derive(Serialize, Deserialize, PartialEq, Debug, Default, Clone)]
61pub struct V1SteeringAutopilotStateExpandedValue {
62    pub value: Option<V1SteeringAutopilotStateValue>,
63    #[serde(flatten)]
64    pub common_value_fields: Option<V1CommonValueFields>,
65}
66
67#[derive(Serialize, Deserialize, PartialEq, Debug, Default, Clone)]
68#[serde(rename_all = "camelCase")]
69pub enum V1SteeringAutopilotStateValue {
70    #[default]
71    Auto,
72    Standby,
73    Alarm,
74    NoDrift,
75    Wind,
76    DepthContour,
77    Route,
78    DirectControl,
79}
80#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
81#[serde(untagged)]
82pub enum V1SteeringAutopilotMode {
83    Expanded(V1SteeringAutopilotModeExpandedValue),
84    Value(V1SteeringAutopilotModeValue),
85}
86
87impl Default for V1SteeringAutopilotMode {
88    fn default() -> Self {
89        V1SteeringAutopilotMode::Value(V1SteeringAutopilotModeValue::default())
90    }
91}
92#[derive(Serialize, Deserialize, PartialEq, Debug, Default, Clone)]
93pub struct V1SteeringAutopilotModeExpandedValue {
94    pub value: Option<V1SteeringAutopilotModeValue>,
95    #[serde(flatten)]
96    pub common_value_fields: Option<V1CommonValueFields>,
97}
98
99#[derive(Serialize, Deserialize, PartialEq, Debug, Default, Clone)]
100#[serde(rename_all = "camelCase")]
101pub enum V1SteeringAutopilotModeValue {
102    #[default]
103    PowerSave,
104    Normal,
105    Accurate,
106}
107
108#[derive(Serialize, Deserialize, PartialEq, Debug, Default, Clone)]
109#[serde(rename_all = "camelCase")]
110pub struct V1SteeringAutopilotTarget {
111    pub wind_angle_apparent: Option<V2NumberValue>,
112    pub wind_angle_true: Option<V2NumberValue>,
113    pub heading_true: Option<V2NumberValue>,
114    pub heading_magnetic: Option<V2NumberValue>,
115}
116
117impl F64CompatiblePath for V1SteeringAutopilotTarget {
118    fn get_f64_for_path(&self, path: &mut Vec<&str>) -> Result<f64, SignalKGetError> {
119        match path[0] {
120            "windAngleApparent" => get_f64_value(&self.wind_angle_apparent),
121            "windAngleTrue" => get_f64_value(&self.wind_angle_true),
122            "headingTrue" => get_f64_value(&self.heading_true),
123            "headingMagnetic" => get_f64_value(&self.heading_magnetic),
124            &_ => Err(SignalKGetError::NoSuchPath),
125        }
126    }
127}
128
129#[cfg(test)]
130mod tests {
131    use crate::steering::{
132        V1SteeringAutopilotState, V1SteeringAutopilotStateExpandedValue,
133        V1SteeringAutopilotStateValue,
134    };
135
136    #[test]
137    fn steering_autopilot_value() {
138        let j = r#"{
139        "value" : "auto",
140        "$source": "foo.bar",
141        "timestamp": "2014-08-15T19:00:15.402Z"
142      }"#;
143        println!("{:?}", j);
144        let autopilot: V1SteeringAutopilotState = serde_json::from_str(j).unwrap();
145        println!("{:?}", autopilot);
146    }
147    #[test]
148    fn steering_autopilot_expanded_value() {
149        let j = r#"{
150        "value" : "auto",
151        "$source": "foo.bar",
152        "timestamp": "2014-08-15T19:00:15.402Z"
153      }"#;
154        println!("{:?}", j);
155        let autopilot: V1SteeringAutopilotStateExpandedValue = serde_json::from_str(j).unwrap();
156        println!("{:?}", autopilot);
157    }
158    #[test]
159    fn steering_autopilot_state_value() {
160        let j = r#" "auto" "#;
161        println!("{:?}", j);
162        let autopilot: V1SteeringAutopilotStateValue = serde_json::from_str(j).unwrap();
163        println!("{:?}", autopilot);
164    }
165    #[test]
166    fn serialization_of_stearing_value() {
167        let j = V1SteeringAutopilotStateValue::Auto;
168        println!("{:?}", j);
169        let autopilot = serde_json::to_string(&j).unwrap();
170        println!("{:?}", autopilot);
171    }
172}