Skip to main content

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}