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), }
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
119pub 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
140pub 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
161pub 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
183pub 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
201pub 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}