lora_e5/
credentials.rs

1use std::{fmt, str::FromStr};
2
3#[derive(Debug, Clone)]
4pub struct Credentials {
5    pub app_eui: AppEui,
6    pub app_key: AppKey,
7    pub dev_eui: DevEui,
8}
9
10impl Credentials {
11    pub fn new(dev_eui: DevEui, app_eui: AppEui, app_key: AppKey) -> Self {
12        Self {
13            dev_eui,
14            app_eui,
15            app_key,
16        }
17    }
18}
19
20macro_rules! derive_from_str {
21    ($name:ident, $size:expr) => {
22        #[derive(Debug, Clone, PartialEq, Eq)]
23        pub struct $name([u8; $size]);
24
25        impl FromStr for $name {
26            type Err = ParseError;
27
28            fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
29                let mut s = s.to_string();
30                s.retain(|c| c != ':');
31                let byte_vec = hex::decode(&s)?;
32                let len = byte_vec.len();
33                let byte_arr: [u8; $size] = byte_vec
34                    .try_into()
35                    .map_err(|_| ParseError::VecWrongSize(len))?;
36                Ok(Self(byte_arr))
37            }
38        }
39
40        impl fmt::Display for $name {
41            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
42                let str = hex::encode(&self.0).to_uppercase();
43                write!(f, "{str}")
44            }
45        }
46
47        impl From<[u8; $size]> for $name {
48            fn from(arr: [u8; $size]) -> Self {
49                Self(arr)
50            }
51        }
52    };
53}
54
55derive_from_str!(AppEui, 8);
56derive_from_str!(DevEui, 8);
57derive_from_str!(AppKey, 16);
58
59use super::*;
60
61impl<const N: usize> LoraE5<N> {
62    pub fn get_dev_eui(&mut self) -> Result<DevEui> {
63        const EXPECTED_PRELUDE: &str = "+ID: DevEui, ";
64        self.write_command("AT+ID=DevEui")?;
65        let n = self.read_until_break(DEFAULT_TIMEOUT)?;
66        let response = self.framed_response(n, EXPECTED_PRELUDE)?;
67        Ok(DevEui::from_str(response.trim_end())?)
68    }
69
70    pub fn get_app_eui(&mut self) -> Result<AppEui> {
71        const EXPECTED_PRELUDE: &str = "+ID: AppEui, ";
72        self.write_command("AT+ID=AppEui")?;
73        let n = self.read_until_break(DEFAULT_TIMEOUT)?;
74        let response = self.framed_response(n, EXPECTED_PRELUDE)?;
75        Ok(AppEui::from_str(response.trim_end())?)
76    }
77
78    pub fn set_app_eui(&mut self, app_eui: &AppEui) -> Result {
79        const EXPECTED_PRELUDE: &str = "+ID: AppEui, ";
80        let cmd = format!("AT+ID=AppEui, {app_eui}");
81        self.write_command(&cmd)?;
82        let n = self.read_until_break(DEFAULT_TIMEOUT)?;
83        let response = self.framed_response(n, EXPECTED_PRELUDE)?;
84        let app_eui_response = AppEui::from_str(response.trim_end())?;
85        if &app_eui_response == app_eui {
86            Ok(())
87        } else {
88            Err(Error::UnexpectedResponse(app_eui_response.to_string()))
89        }
90    }
91
92    pub fn set_dev_eui(&mut self, dev_eui: &DevEui) -> Result {
93        const EXPECTED_PRELUDE: &str = "+ID: DevEui, ";
94        let cmd = format!("AT+ID=DevEui, {dev_eui}");
95        self.write_command(&cmd)?;
96        let n = self.read_until_break(DEFAULT_TIMEOUT)?;
97        let response = self.framed_response(n, EXPECTED_PRELUDE)?;
98        let dev_eui_response = DevEui::from_str(response.trim_end())?;
99        if &dev_eui_response == dev_eui {
100            Ok(())
101        } else {
102            Err(Error::UnexpectedResponse(dev_eui_response.to_string()))
103        }
104    }
105
106    pub fn set_app_key(&mut self, app_key: &AppKey) -> Result {
107        const EXPECTED_PRELUDE: &str = "+KEY: APPKEY ";
108        let cmd = format!("AT+KEY=APPKEY, {app_key}");
109        self.write_command(&cmd)?;
110        let n = self.read_until_break(DEFAULT_TIMEOUT)?;
111        let response = self.framed_response(n, EXPECTED_PRELUDE)?;
112        let app_key_response = AppKey::from_str(response.trim_end())?;
113        if &app_key_response == app_key {
114            Ok(())
115        } else {
116            Err(Error::UnexpectedResponse(response.to_string()))
117        }
118    }
119
120    pub fn set_credentials(&mut self, credentials: &Credentials) -> Result {
121        self.set_dev_eui(&credentials.dev_eui)?;
122        self.set_app_eui(&credentials.app_eui)?;
123        self.set_app_key(&credentials.app_key)
124    }
125}
126
127use thiserror::Error;
128
129#[derive(Error, Debug)]
130pub enum ParseError {
131    #[error("hex error: {0}")]
132    FromHex(#[from] hex::FromHexError),
133    #[error("Vec is unexpected of len {0}")]
134    VecWrongSize(usize),
135}