openthread/ot/mod.rs
1// Copyright 2022 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! # OpenThread API Module #
6//!
7//! This module contains (mostly) type-safe versions of the OpenThread API,
8//! excluding the platform API.
9//!
10//! ## Type Safety ##
11//!
12//! Full type safety for an API which wasn't created for type safety is hard. There are some
13//! operations which feel like they should be fully safe but are ultimately marked as `unsafe`
14//! because it might be possible to abuse in some way that causes undefined behavior.
15//!
16//! ## Types ##
17//!
18//! Each enum, struct, or object in the OpenThread C API is associated with a safe Rust
19//! equivalent. For example:
20//!
21//! * [`otInstance`](crate::otsys::otInstance): [`ot::Instance`](Instance).
22//! * [`otMessage`](crate::otsys::otMessage): [`ot::Message<'_>`](Message).
23//! * [`otError`](crate::otsys::otError): [`ot::Error`](Error) or [`Result`].
24//!
25//! ## Ownership ##
26//!
27//! Some OpenThread API objects, like [`otsys::otInstance`](crate::otsys::otInstance) and
28//! [`otsys::otMessage`](crate::otsys::otMessage) have hidden implementations and explicit ownership
29//! transfer. That means we must have a notation which is capable of both "owned" instances
30//! and "borrowed" references.
31//!
32//! The rust equivalent of passing around a pointer to one of thse
33//! objects would be to pass around a reference: `otInstance*` becomes a `&ot::Instance`.
34//! Owned instances are "boxed" into a [`ot::Box`](Box), so an owned `otInstance*` would become
35//! a `ot::Box<ot::Instance>`, or a [`OtInstanceBox`](crate::OtInstanceBox) for short. When the box
36//! goes out of scope, the appropriate OpenThread C finalization API is called.
37//!
38//! ## Singleton/Multiple OpenThread Instances ##
39//!
40//! OpenThread can be compiled to either only support a singleton instance or to support
41//! multiple independent OpenThread instances.
42//!
43//! Currently, this crate only supports a singleton OpenThread instance. Attempting to create
44//! more than one OpenThread instance at a time will result in a runtime panic.
45//!
46//! ## Traits ##
47//!
48//! The OpenThread API is broken down into "modules" of functionality containing types and
49//! related methods. Similarly, this Rust interface breaks down functionality into traits.
50//! This allows parts of the OpenThread API to be substituted with mocked versions for unit
51//! testing.
52//!
53//! ## Callbacks ##
54//!
55//! In most cases, you register a callback by passing a closure to the appropriate callback
56//! registration API.
57//!
58//! ## Platform Implementations ##
59//!
60//! This crate doesn't directly provide the platform implementations for OpenThread—that
61//! needs to come from either a separate library or the program which is using this crate.
62//!
63
64use openthread_sys::*;
65use std::ffi::CStr;
66
67mod cli;
68pub use cli::*;
69
70mod error;
71pub use error::*;
72
73mod srp;
74pub use srp::*;
75
76mod singleton;
77pub use singleton::*;
78
79pub(crate) mod tasklets;
80pub use tasklets::*;
81
82mod reset;
83pub use reset::*;
84
85mod link;
86pub use link::*;
87
88mod link_metrics;
89pub use link_metrics::*;
90
91pub(crate) mod types;
92pub use types::*;
93
94mod dnssd;
95pub use dnssd::*;
96
97mod thread;
98pub use thread::*;
99
100mod ip6;
101pub use ip6::*;
102
103mod state;
104pub use state::*;
105
106mod radio;
107pub use radio::*;
108
109mod uptime;
110pub use uptime::*;
111
112mod udp;
113pub use udp::*;
114
115mod border_agent;
116pub use border_agent::*;
117
118mod infra_if;
119pub use infra_if::*;
120
121pub mod message;
122pub use message::{Message, MessageBuffer};
123
124mod otbox;
125pub use otbox::*;
126
127mod dataset;
128pub use dataset::*;
129
130mod backbone_router;
131pub use backbone_router::*;
132
133mod border_router;
134pub use border_router::*;
135
136mod platform;
137pub use platform::*;
138
139mod joiner;
140pub use joiner::*;
141
142mod trel;
143pub use trel::*;
144
145mod net_data;
146pub use net_data::*;
147
148mod nat64;
149pub use nat64::*;
150
151mod dns_upstream;
152pub use dns_upstream::*;
153
154mod multi_radio_neighbor_info;
155pub use multi_radio_neighbor_info::*;
156
157/// Trait implemented by all OpenThread instances.
158pub trait InstanceInterface:
159 Ip6
160 + Cli
161 + Reset
162 + Dataset
163 + Link
164 + Dnssd
165 + State
166 + Tasklets
167 + Thread
168 + BackboneRouter
169 + BorderRouter
170 + SrpServer
171 + MessageBuffer
172 + Radio
173 + Joiner
174 + Uptime
175 + Udp
176 + Trel
177 + BorderAgent
178 + NetData
179 + Nat64
180 + DnsUpstream
181 + LinkMetrics
182 + MultiRadioLink
183{
184}
185
186/// Returns the OpenThread version string. This is the safe equivalent of
187/// [`otsys::otGetVersionString()`](crate::otsys::otGetVersionString()).
188pub fn get_version_string() -> &'static str {
189 unsafe {
190 // SAFETY: `otGetVersionString` guarantees to return a C-String that will not change.
191 CStr::from_ptr(otGetVersionString())
192 .to_str()
193 .expect("OpenThread version string was bad UTF8")
194 }
195}
196
197/// Changes the logging level.
198pub fn set_logging_level(level: LogLevel) {
199 unsafe {
200 otLoggingSetLevel(level.into());
201 }
202}
203
204/// Get the logging level.
205pub fn get_logging_level() -> LogLevel {
206 unsafe { otLoggingGetLevel().into() }
207}
208
209/// Represents the thread version
210#[derive(
211 Debug,
212 Copy,
213 Clone,
214 Eq,
215 Ord,
216 PartialOrd,
217 PartialEq,
218 num_derive::FromPrimitive,
219 num_derive::ToPrimitive,
220)]
221#[repr(u16)]
222pub enum ThreadVersion {
223 /// Thread specification version 1.1.0.
224 ///
225 /// This is the functional equivalent of `OT_THREAD_VERSION_1_1`, which is not currently
226 /// exported as a part of the OpenThread C API.
227 V1_1 = 2,
228
229 /// Thread specification version 1.2.0.
230 ///
231 /// This is the functional equivalent of `OT_THREAD_VERSION_1_2`, which is not currently
232 /// exported as a part of the OpenThread C API.
233 V1_2 = 3,
234
235 /// Thread specification version 1.3.0.
236 ///
237 /// This is the functional equivalent of `OT_THREAD_VERSION_1_3`, which is not currently
238 /// exported as a part of the OpenThread C API.
239 V1_3 = 4,
240}
241
242/// Returns the version of the Thread specification that OpenThread
243/// is configured to use. This is the safe equivalent of
244/// [`otsys::otThreadGetVersion()`](crate::otsys::otThreadGetVersion()).
245pub fn get_thread_version() -> ThreadVersion {
246 use num::FromPrimitive;
247
248 // SAFETY: otThreadGetVersion() is guaranteed to be safe to call in any context.
249 let ver = unsafe { otThreadGetVersion() };
250
251 ThreadVersion::from_u16(ver).unwrap_or_else(|| panic!("Unknown Thread specification: {ver}"))
252}
253
254/// Returns a `'static`-scoped string slice describing the version of the
255/// Thread specification that is currently in use.
256///
257/// Format is suitable for use with MeshCop.
258pub fn get_thread_version_str() -> &'static str {
259 match get_thread_version() {
260 ThreadVersion::V1_1 => "1.1.0",
261 ThreadVersion::V1_2 => "1.2.0",
262 ThreadVersion::V1_3 => "1.3.0",
263 }
264}
265
266/// Converts a byte string into an ASCII [`String`], properly escaped.
267pub(crate) fn ascii_dump(data: &[u8]) -> String {
268 let vec = data.iter().copied().flat_map(std::ascii::escape_default).collect::<Vec<_>>();
269 std::str::from_utf8(&vec).unwrap().to_string()
270}
271
272#[cfg(test)]
273mod tests {
274 use super::*;
275
276 #[test]
277 fn test_get_version() {
278 let vstr = get_version_string();
279 println!("OpenThread Version: {vstr:?}");
280 assert!(!vstr.is_empty());
281 }
282
283 #[unsafe(no_mangle)]
284 unsafe extern "C" fn otPlatAlarmMilliGetNow() -> u32 {
285 // SAFETY: Must only be called from unit test.
286 0
287 }
288}