Skip to main content

sig_net/
coap.rs

1use crate::*;
2
3fn option_nibble(value: u16) -> (u8, u8) {
4    match value {
5        0..=12 => (value as u8, 0),
6        13..=268 => (13, 1),
7        _ => (14, 2),  // >= 269
8    }
9}
10
11fn encode_option_nibble(buffer: &mut PacketBuffer, delta: u16, length: u16) -> Result<()> {
12    let (delta_nib, delta_ext) = option_nibble(delta);
13    let (len_nib, len_ext) = option_nibble(length);
14
15    let nibble = (delta_nib << 4) | len_nib;
16    buffer.write_byte(nibble)?;
17
18    match delta_ext {
19        1 => buffer.write_byte((delta - 13) as u8)?,
20        2 => buffer.write_u16(delta - 269)?,
21        _ => {}
22    }
23
24    match len_ext {
25        1 => buffer.write_byte((length - 13) as u8)?,
26        2 => buffer.write_u16(length - 269)?,
27        _ => {}
28    }
29
30    Ok(())
31}
32
33pub fn encode_coap_option(
34    buffer: &mut PacketBuffer,
35    option_number: u16,
36    prev_option: u16,
37    option_value: &[u8],
38) -> Result<()> {
39    let delta = option_number
40        .checked_sub(prev_option)
41        .ok_or(SigNetError::InvalidArgument)?;
42    encode_option_nibble(buffer, delta, option_value.len() as u16)?;
43    buffer.write_bytes(option_value)
44}
45
46pub fn build_coap_header(buffer: &mut PacketBuffer, message_id: u16) -> Result<()> {
47    let header = CoAPHeader::new(message_id);
48    buffer.write_bytes(&header.to_bytes())
49}
50
51pub fn build_uri_path_options(buffer: &mut PacketBuffer, universe: u16, scope: &str) -> Result<()> {
52    if !(MIN_UNIVERSE..=MAX_UNIVERSE).contains(&universe) {
53        return Err(SigNetError::InvalidArgument);
54    }
55
56    let segments = [
57        SIGNET_URI_PREFIX,
58        SIGNET_URI_VERSION,
59        scope,
60        SIGNET_URI_LEVEL,
61    ];
62
63    let mut prev_option: u16 = 0;
64    for &segment in &segments {
65        encode_coap_option(buffer, COAP_OPTION_URI_PATH, prev_option, segment.as_bytes())?;
66        prev_option = COAP_OPTION_URI_PATH;
67    }
68
69    let universe_str = universe.to_string();
70    encode_coap_option(buffer, COAP_OPTION_URI_PATH, prev_option, universe_str.as_bytes())
71}
72
73pub fn build_uri_string(universe: u16, scope: &str, uri_output: &mut [u8]) -> Result<usize> {
74    if !(MIN_UNIVERSE..=MAX_UNIVERSE).contains(&universe) {
75        return Err(SigNetError::InvalidArgument);
76    }
77    let s = format!(
78        "/{}/{}/{}/{}/{}",
79        SIGNET_URI_PREFIX,
80        SIGNET_URI_VERSION,
81        scope,
82        SIGNET_URI_LEVEL,
83        universe
84    );
85    let bytes = s.as_bytes();
86    if bytes.len() > uri_output.len() {
87        return Err(SigNetError::InvalidArgument);
88    }
89    uri_output[..bytes.len()].copy_from_slice(bytes);
90    Ok(bytes.len())
91}
92
93pub fn build_node_uri_string(
94    tuid: &[u8; TUID_LENGTH],
95    endpoint: u16,
96    scope: &str,
97    uri_output: &mut [u8],
98) -> Result<usize> {
99    let hex = TUID(*tuid).to_hex_upper();
100    let hex_str = core::str::from_utf8(&hex)
101        .map_err(|_| SigNetError::Encode)?;
102    let s = format!(
103        "/{}/{}/{}/{}/{}/{}",
104        SIGNET_URI_PREFIX,
105        SIGNET_URI_VERSION,
106        scope,
107        SIGNET_URI_NODE,
108        hex_str,
109        endpoint
110    );
111    let bytes = s.as_bytes();
112    if bytes.len() > uri_output.len() {
113        return Err(SigNetError::InvalidArgument);
114    }
115    uri_output[..bytes.len()].copy_from_slice(bytes);
116    Ok(bytes.len())
117}
118
119/// /sig-net/v1/<scope>/node_beacon/{TUID_UPPER}/0
120pub fn build_node_beacon_uri_string(
121    tuid: &[u8; TUID_LENGTH],
122    scope: &str,
123    output: &mut [u8],
124) -> Result<usize> {
125    let hex = TUID(*tuid).to_hex_upper();
126    let hex_str = core::str::from_utf8(&hex)
127        .map_err(|_| SigNetError::Encode)?;
128    let s = format!(
129        "/{}/{}/{}/node_beacon/{}/0",
130        SIGNET_URI_PREFIX, SIGNET_URI_VERSION, scope, hex_str
131    );
132    let bytes = s.as_bytes();
133    if bytes.len() > output.len() {
134        return Err(SigNetError::InvalidArgument);
135    }
136    output[..bytes.len()].copy_from_slice(bytes);
137    Ok(bytes.len())
138}
139
140/// /sig-net/v1/<scope>/node_lost/{TUID_UPPER}/0
141pub fn build_node_lost_uri_string(
142    tuid: &[u8; TUID_LENGTH],
143    scope: &str,
144    output: &mut [u8],
145) -> Result<usize> {
146    let hex = TUID(*tuid).to_hex_upper();
147    let hex_str = core::str::from_utf8(&hex)
148        .map_err(|_| SigNetError::Encode)?;
149    let s = format!(
150        "/{}/{}/{}/node_lost/{}/0",
151        SIGNET_URI_PREFIX, SIGNET_URI_VERSION, scope, hex_str
152    );
153    let bytes = s.as_bytes();
154    if bytes.len() > output.len() {
155        return Err(SigNetError::InvalidArgument);
156    }
157    output[..bytes.len()].copy_from_slice(bytes);
158    Ok(bytes.len())
159}
160
161/// /sig-net/v1/<scope>/manager/{TUID_UPPER}/{endpoint}
162pub fn build_manager_uri_string(
163    tuid: &[u8; TUID_LENGTH],
164    endpoint: u16,
165    scope: &str,
166    output: &mut [u8],
167) -> Result<usize> {
168    let hex = TUID(*tuid).to_hex_upper();
169    let hex_str = core::str::from_utf8(&hex)
170        .map_err(|_| SigNetError::Encode)?;
171    let s = format!(
172        "/{}/{}/{}/manager/{}/{}",
173        SIGNET_URI_PREFIX, SIGNET_URI_VERSION, scope, hex_str, endpoint
174    );
175    let bytes = s.as_bytes();
176    if bytes.len() > output.len() {
177        return Err(SigNetError::InvalidArgument);
178    }
179    output[..bytes.len()].copy_from_slice(bytes);
180    Ok(bytes.len())
181}
182
183/// /sig-net/v1/<scope>/timecode/{stream}
184pub fn build_timecode_uri_string(
185    stream: u8,
186    scope: &str,
187    output: &mut [u8],
188) -> Result<usize> {
189    let s = format!(
190        "/{}/{}/{}/timecode/{}",
191        SIGNET_URI_PREFIX, SIGNET_URI_VERSION, scope, stream
192    );
193    let bytes = s.as_bytes();
194    if bytes.len() > output.len() {
195        return Err(SigNetError::InvalidArgument);
196    }
197    output[..bytes.len()].copy_from_slice(bytes);
198    Ok(bytes.len())
199}
200
201/// /sig-net/v1/<scope>/preview/{universe}
202pub fn build_preview_uri_string(
203    universe: u16,
204    scope: &str,
205    output: &mut [u8],
206) -> Result<usize> {
207    if !(MIN_UNIVERSE..=MAX_UNIVERSE).contains(&universe) {
208        return Err(SigNetError::InvalidArgument);
209    }
210    let s = format!(
211        "/{}/{}/{}/preview/{}",
212        SIGNET_URI_PREFIX, SIGNET_URI_VERSION, scope, universe
213    );
214    let bytes = s.as_bytes();
215    if bytes.len() > output.len() {
216        return Err(SigNetError::InvalidArgument);
217    }
218    output[..bytes.len()].copy_from_slice(bytes);
219    Ok(bytes.len())
220}