1use crate::error::ProtocolError;
8use crate::types::Band;
9use crate::types::channel::FineStep;
10use crate::types::mode::Mode;
11use crate::types::radio_params::{
12 AfGainLevel, FilterMode, FilterWidthIndex, SMeterReading, SquelchLevel,
13};
14
15use super::Response;
16
17pub(crate) fn parse_vfo(mnemonic: &str, payload: &str) -> Option<Result<Response, ProtocolError>> {
21 match mnemonic {
22 "AG" => Some(parse_ag(payload)),
23 "SQ" => Some(parse_sq(payload)),
24 "SM" => Some(parse_sm(payload)),
25 "MD" => Some(parse_md(payload)),
26 "FS" => Some(parse_fs(payload)),
27 "FT" => Some(parse_ft(payload)),
28 "SH" => Some(parse_sh(payload)),
29 "UP" => Some(Ok(Response::Ok)),
30 "RA" => Some(parse_ra(payload)),
31 _ => None,
32 }
33}
34
35fn parse_u8_field(s: &str, cmd: &str, field: &str) -> Result<u8, ProtocolError> {
41 s.parse::<u8>().map_err(|_| ProtocolError::FieldParse {
42 command: cmd.to_owned(),
43 field: field.to_owned(),
44 detail: format!("invalid u8: {s:?}"),
45 })
46}
47
48fn split_band_value<'a>(payload: &'a str, cmd: &str) -> Result<(Band, &'a str), ProtocolError> {
50 let parts: Vec<&str> = payload.splitn(2, ',').collect();
51 if parts.len() != 2 {
52 return Err(ProtocolError::FieldParse {
53 command: cmd.to_owned(),
54 field: "all".to_owned(),
55 detail: format!("expected band,value, got {payload:?}"),
56 });
57 }
58 let band_val = parse_u8_field(parts[0], cmd, "band")?;
59 let band = Band::try_from(band_val).map_err(|e| ProtocolError::FieldParse {
60 command: cmd.to_owned(),
61 field: "band".to_owned(),
62 detail: e.to_string(),
63 })?;
64 Ok((band, parts[1]))
65}
66
67fn parse_ag(payload: &str) -> Result<Response, ProtocolError> {
76 let raw = parse_u8_field(payload.trim(), "AG", "level")?;
77 let level = AfGainLevel::from(raw);
78 Ok(Response::AfGain { level })
79}
80
81fn parse_sq(payload: &str) -> Result<Response, ProtocolError> {
83 let (band, val_str) = split_band_value(payload, "SQ")?;
84 let raw = parse_u8_field(val_str, "SQ", "level")?;
85 let level = SquelchLevel::try_from(raw).map_err(|e| ProtocolError::FieldParse {
86 command: "SQ".to_owned(),
87 field: "level".to_owned(),
88 detail: e.to_string(),
89 })?;
90 Ok(Response::Squelch { band, level })
91}
92
93fn parse_sm(payload: &str) -> Result<Response, ProtocolError> {
95 let (band, val_str) = split_band_value(payload, "SM")?;
96 let raw = parse_u8_field(val_str, "SM", "level")?;
97 let level = SMeterReading::try_from(raw).map_err(|e| ProtocolError::FieldParse {
98 command: "SM".to_owned(),
99 field: "level".to_owned(),
100 detail: e.to_string(),
101 })?;
102 Ok(Response::Smeter { band, level })
103}
104
105fn parse_md(payload: &str) -> Result<Response, ProtocolError> {
107 let (band, val_str) = split_band_value(payload, "MD")?;
108 let mode_val = parse_u8_field(val_str, "MD", "mode")?;
109 let mode = Mode::try_from(mode_val).map_err(|e| ProtocolError::FieldParse {
110 command: "MD".to_owned(),
111 field: "mode".to_owned(),
112 detail: e.to_string(),
113 })?;
114 Ok(Response::Mode { band, mode })
115}
116
117fn parse_fs(payload: &str) -> Result<Response, ProtocolError> {
122 let step_val = parse_u8_field(payload.trim(), "FS", "step")?;
123 let step = FineStep::try_from(step_val).map_err(|e| ProtocolError::FieldParse {
124 command: "FS".to_owned(),
125 field: "step".to_owned(),
126 detail: e.to_string(),
127 })?;
128 Ok(Response::FineStep { step })
129}
130
131fn parse_ft(payload: &str) -> Result<Response, ProtocolError> {
136 let data_str = if let Some((_prefix, val)) = payload.split_once(',') {
138 val
139 } else {
140 payload
141 };
142 let value = parse_u8_field(data_str, "FT", "value")?;
143 Ok(Response::FunctionType {
144 enabled: value != 0,
145 })
146}
147
148fn parse_sh(payload: &str) -> Result<Response, ProtocolError> {
152 let parts: Vec<&str> = payload.splitn(2, ',').collect();
153 if parts.len() == 2 {
154 let mode_raw = parse_u8_field(parts[0], "SH", "mode")?;
155 let mode = FilterMode::try_from(mode_raw).map_err(|e| ProtocolError::FieldParse {
156 command: "SH".to_owned(),
157 field: "mode".to_owned(),
158 detail: e.to_string(),
159 })?;
160 let width_raw = parse_u8_field(parts[1], "SH", "width")?;
161 let width =
162 FilterWidthIndex::from_raw(width_raw).map_err(|e| ProtocolError::FieldParse {
163 command: "SH".into(),
164 field: "width".into(),
165 detail: e.to_string(),
166 })?;
167 Ok(Response::FilterWidth { mode, width })
168 } else {
169 let width_raw = parse_u8_field(payload, "SH", "width")?;
171 let width =
172 FilterWidthIndex::from_raw(width_raw).map_err(|e| ProtocolError::FieldParse {
173 command: "SH".into(),
174 field: "width".into(),
175 detail: e.to_string(),
176 })?;
177 Ok(Response::FilterWidth {
178 mode: FilterMode::Ssb,
179 width,
180 })
181 }
182}
183
184fn parse_ra(payload: &str) -> Result<Response, ProtocolError> {
186 let (band, val_str) = split_band_value(payload, "RA")?;
187 let val = parse_u8_field(val_str, "RA", "enabled")?;
188 Ok(Response::Attenuator {
189 band,
190 enabled: val != 0,
191 })
192}