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
157mod history_tracker;
158pub use history_tracker::*;
159
160/// Trait implemented by all OpenThread instances.
161pub trait InstanceInterface:
162    Ip6
163    + Cli
164    + Reset
165    + Dataset
166    + Link
167    + Dnssd
168    + State
169    + Tasklets
170    + Thread
171    + BackboneRouter
172    + BorderRouter
173    + SrpServer
174    + MessageBuffer
175    + Radio
176    + Joiner
177    + Uptime
178    + Udp
179    + Trel
180    + BorderAgent
181    + NetData
182    + Nat64
183    + DnsUpstream
184    + LinkMetrics
185    + MultiRadioLink
186    + HistoryTracker
187{
188}
189
190/// Returns the OpenThread version string. This is the safe equivalent of
191/// [`otsys::otGetVersionString()`](crate::otsys::otGetVersionString()).
192pub fn get_version_string() -> &'static str {
193    unsafe {
194        // SAFETY: `otGetVersionString` guarantees to return a C-String that will not change.
195        CStr::from_ptr(otGetVersionString())
196            .to_str()
197            .expect("OpenThread version string was bad UTF8")
198    }
199}
200
201/// Changes the logging level.
202pub fn set_logging_level(level: LogLevel) {
203    unsafe {
204        otLoggingSetLevel(level.into());
205    }
206}
207
208/// Get the logging level.
209pub fn get_logging_level() -> LogLevel {
210    unsafe { otLoggingGetLevel().into() }
211}
212
213/// Represents the thread version
214#[derive(
215    Debug,
216    Copy,
217    Clone,
218    Eq,
219    Ord,
220    PartialOrd,
221    PartialEq,
222    num_derive::FromPrimitive,
223    num_derive::ToPrimitive,
224)]
225#[repr(u16)]
226pub enum ThreadVersion {
227    /// Thread specification version 1.1.0.
228    ///
229    /// This is the functional equivalent of `OT_THREAD_VERSION_1_1`, which is not currently
230    /// exported as a part of the OpenThread C API.
231    V1_1 = 2,
232
233    /// Thread specification version 1.2.0.
234    ///
235    /// This is the functional equivalent of `OT_THREAD_VERSION_1_2`, which is not currently
236    /// exported as a part of the OpenThread C API.
237    V1_2 = 3,
238
239    /// Thread specification version 1.3.0.
240    ///
241    /// This is the functional equivalent of `OT_THREAD_VERSION_1_3`, which is not currently
242    /// exported as a part of the OpenThread C API.
243    V1_3 = 4,
244}
245
246/// Returns the version of the Thread specification that OpenThread
247/// is configured to use. This is the safe equivalent of
248/// [`otsys::otThreadGetVersion()`](crate::otsys::otThreadGetVersion()).
249pub fn get_thread_version() -> ThreadVersion {
250    use num::FromPrimitive;
251
252    // SAFETY: otThreadGetVersion() is guaranteed to be safe to call in any context.
253    let ver = unsafe { otThreadGetVersion() };
254
255    ThreadVersion::from_u16(ver).unwrap_or_else(|| panic!("Unknown Thread specification: {ver}"))
256}
257
258/// Returns a `'static`-scoped string slice describing the version of the
259/// Thread specification that is currently in use.
260///
261/// Format is suitable for use with MeshCop.
262pub fn get_thread_version_str() -> &'static str {
263    match get_thread_version() {
264        ThreadVersion::V1_1 => "1.1.0",
265        ThreadVersion::V1_2 => "1.2.0",
266        ThreadVersion::V1_3 => "1.3.0",
267    }
268}
269
270/// Converts a byte string into an ASCII [`String`], properly escaped.
271pub(crate) fn ascii_dump(data: &[u8]) -> String {
272    let vec = data.iter().copied().flat_map(std::ascii::escape_default).collect::<Vec<_>>();
273    std::str::from_utf8(&vec).unwrap().to_string()
274}
275
276#[cfg(test)]
277mod tests {
278    use super::*;
279
280    #[test]
281    fn test_get_version() {
282        let vstr = get_version_string();
283        println!("OpenThread Version: {vstr:?}");
284        assert!(!vstr.is_empty());
285    }
286
287    #[unsafe(no_mangle)]
288    unsafe extern "C" fn otPlatAlarmMilliGetNow() -> u32 {
289        // SAFETY: Must only be called from unit test.
290        0
291    }
292}