blob: 8bc3c8dc21a1fb9a69eb4933bf365ca89b9242b9 [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//! # OpenThread API Module #
//!
//! This module contains (mostly) type-safe versions of the OpenThread API,
//! excluding the platform API.
//!
//! ## Type Safety ##
//!
//! Full type safety for an API which wasn't created for type safety is hard. There are some
//! operations which feel like they should be fully safe but are ultimately marked as `unsafe`
//! because it might be possible to abuse in some way that causes undefined behavior.
//!
//! ## Types ##
//!
//! Each enum, struct, or object in the OpenThread C API is associated with a safe Rust
//! equivalent. For example:
//!
//! * [`otInstance`](crate::otsys::otInstance): [`ot::Instance`](Instance).
//! * [`otMessage`](crate::otsys::otMessage): [`ot::Message<'_>`](Message).
//! * [`otError`](crate::otsys::otError): [`ot::Error`](Error) or [`Result`].
//!
//! ## Ownership ##
//!
//! Some OpenThread API objects, like [`otsys::otInstance`](crate::otsys::otInstance) and
//! [`otsys::otMessage`](crate::otsys::otMessage) have hidden implementations and explicit ownership
//! transfer. That means we must have a notation which is capable of both "owned" instances
//! and "borrowed" references.
//!
//! The rust equivalent of passing around a pointer to one of thse
//! objects would be to pass around a reference: `otInstance*` becomes a `&ot::Instance`.
//! Owned instances are "boxed" into a [`ot::Box`](Box), so an owned `otInstance*` would become
//! a `ot::Box<ot::Instance>`, or a [`OtInstanceBox`](crate::OtInstanceBox) for short. When the box
//! goes out of scope, the appropriate OpenThread C finalization API is called.
//!
//! ## Singleton/Multiple OpenThread Instances ##
//!
//! OpenThread can be compiled to either only support a singleton instance or to support
//! multiple independent OpenThread instances.
//!
//! Currently, this crate only supports a singleton OpenThread instance. Attempting to create
//! more than one OpenThread instance at a time will result in a runtime panic.
//!
//! ## Traits ##
//!
//! The OpenThread API is broken down into "modules" of functionality containing types and
//! related methods. Similarly, this Rust interface breaks down functionality into traits.
//! This allows parts of the OpenThread API to be substituted with mocked versions for unit
//! testing.
//!
//! ## Callbacks ##
//!
//! In most cases, you register a callback by passing a closure to the appropriate callback
//! registration API.
//!
//! ## Platform Implementations ##
//!
//! This crate doesn't directly provide the platform implementations for OpenThread—that
//! needs to come from either a separate library or the program which is using this crate.
//!
use openthread_sys::*;
use std::ffi::CStr;
mod cli;
pub use cli::*;
mod error;
pub use error::*;
mod srp;
pub use srp::*;
mod singleton;
pub use singleton::*;
pub(crate) mod tasklets;
pub use tasklets::*;
mod reset;
pub use reset::*;
mod link;
pub use link::*;
pub(crate) mod types;
pub use types::*;
mod dnssd;
pub use dnssd::*;
mod thread;
pub use thread::*;
mod ip6;
pub use ip6::*;
mod state;
pub use state::*;
mod radio;
pub use radio::*;
mod udp;
pub use udp::*;
mod border_agent;
pub use border_agent::*;
mod infra_if;
pub use infra_if::*;
pub mod message;
pub use message::{Message, MessageBuffer};
mod otbox;
pub use otbox::*;
mod dataset;
pub use dataset::*;
mod border_router;
pub use border_router::*;
mod platform;
pub use platform::*;
mod joiner;
pub use joiner::*;
mod trel;
pub use trel::*;
mod net_data;
pub use net_data::*;
/// Trait implemented by all OpenThread instances.
pub trait InstanceInterface:
Ip6
+ Cli
+ Reset
+ Dataset
+ Link
+ Dnssd
+ State
+ Tasklets
+ Thread
+ BorderRouter
+ SrpServer
+ MessageBuffer
+ Radio
+ Joiner
+ Udp
+ Trel
+ BorderAgent
+ NetData
{
}
/// Returns the OpenThread version string. This is the safe equivalent of
/// [`otsys::otGetVersionString()`](crate::otsys::otGetVersionString()).
pub fn get_version_string() -> &'static str {
unsafe {
// SAFETY: `otGetVersionString` guarantees to return a C-String that will not change.
CStr::from_ptr(otGetVersionString())
.to_str()
.expect("OpenThread version string was bad UTF8")
}
}
/// Changes the logging level.
pub fn set_logging_level(level: LogLevel) {
unsafe {
otLoggingSetLevel(level.into());
}
}
/// Converts a byte string into an ASCII [`String`], properly escaped.
pub(crate) fn ascii_dump(data: &[u8]) -> String {
let vec = data.iter().copied().flat_map(std::ascii::escape_default).collect::<Vec<_>>();
std::str::from_utf8(&vec).unwrap().to_string()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_get_version() {
let vstr = get_version_string();
println!("OpenThread Version: {:?}", vstr);
assert!(!vstr.is_empty());
}
}