kenwood_thd75/protocol/
dstar.rs

1//! D-STAR (Digital Smart Technologies for Amateur Radio) commands: DS, CS, GW.
2//!
3//! Provides parsing of responses for the 3 D-STAR-related CAT protocol
4//! commands. Serialization is handled inline by the main dispatcher.
5
6use crate::error::ProtocolError;
7use crate::types::radio_params::{CallsignSlot, DstarSlot, DvGatewayMode};
8
9use super::Response;
10
11/// Parse a `u8` from a string field.
12fn parse_u8_field(s: &str, cmd: &str, field: &str) -> Result<u8, ProtocolError> {
13    s.parse::<u8>().map_err(|_| ProtocolError::FieldParse {
14        command: cmd.to_owned(),
15        field: field.to_owned(),
16        detail: format!("invalid u8: {s:?}"),
17    })
18}
19
20/// Parse a D-STAR command response from mnemonic and payload.
21///
22/// Returns `None` if the mnemonic is not a D-STAR command.
23pub(crate) fn parse_dstar(
24    mnemonic: &str,
25    payload: &str,
26) -> Option<Result<Response, ProtocolError>> {
27    match mnemonic {
28        "DS" => Some(parse_u8_field(payload, "DS", "slot").and_then(|raw| {
29            DstarSlot::try_from(raw)
30                .map(|slot| Response::DstarSlot { slot })
31                .map_err(|e| ProtocolError::FieldParse {
32                    command: "DS".into(),
33                    field: "slot".into(),
34                    detail: e.to_string(),
35                })
36        })),
37        "CS" => Some(parse_u8_field(payload, "CS", "slot").and_then(|raw| {
38            CallsignSlot::try_from(raw)
39                .map(|slot| Response::ActiveCallsignSlot { slot })
40                .map_err(|e| ProtocolError::FieldParse {
41                    command: "CS".into(),
42                    field: "slot".into(),
43                    detail: e.to_string(),
44                })
45        })),
46        "GW" => Some(parse_u8_field(payload, "GW", "value").and_then(|raw| {
47            DvGatewayMode::try_from(raw)
48                .map(|value| Response::Gateway { value })
49                .map_err(|e| ProtocolError::FieldParse {
50                    command: "GW".into(),
51                    field: "value".into(),
52                    detail: e.to_string(),
53                })
54        })),
55        _ => None,
56    }
57}