1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
//! # PX4 bindings for Rust
//!
//! This crate provides the framework to make dynamically loadable PX4 modules
//! in Rust. Right now, it provides bindings for the two most important APIs:
//! Logging and uORB. It also provides the entry point for your module, and
//! handles panics on the main thread of the module.
//!
//! See the
//! [`example` directory](https://github.com/dronesforwork/px4-rust/tree/master/example)
//! for an example module.
//!
//! ## Compiling and running
//!
//! To build a PX4 module in Rust, create a crate as you would for any other
//! application binary, and then add the following to your Cargo.toml:
//!
//! ```text
//! [lib]
//! crate-type = ["cdylib"]
//! path = "src/module.rs"
//! ```
//!
//! This will turn your program into a loadable module instead of a standalone
//! application. The resulting file will be called `lib<name>.so`, which you
//! can manually rename to `<name>.px4mod` if you want.
//!
//! To run your module, use the
//! [`dyn`](https://dev.px4.io/en/middleware/modules_command.html#dyn)
//! PX4 command. Give it the full path name, followed by any arguments to your
//! module. Note that `dyn` will *not* reload your file if you run it again.
//! If you want to run a changed version of your module, you'll either need to
//! restart PX4, or move/rename the file.
//!
//! ## Entry point
//!
//! Mark your entry function with `#[px4_module_main]`. The boilerplate code
//! needed to set up the environment and export the function under the right
//! name is then inserted automatically.
//!
//! Your main function should take a `&[&str]` as argument. It *may* return a
//! `i32` status code, either directly, or as the error type of a `Result`. A
//! panic from your main thread is caught and results in a status code of −1.
//!
//! ### Example
//!
//! ```
//! use px4::px4_module_main;
//!
//! #[px4_module_main]
//! fn my_module(args: &[&str]) -> i32 {
//! 0
//! }
//! ```
//!
//! ## Logging
//!
//! As soon as your main function is entered, logging is already set up using
//! the standard [`log` crate](https://docs.rs/log/). You can use the standard
//! logging macros such as `info!`, `warn!`, and `error!` to log messages,
//! equivalent to `PX4_INFO` (etc.) in C and C++.
//!
//! Use the `info_raw!` macro to send raw output, equivalent to the
//! `PX4_INFO_RAW` macro in C and C++.
//! Do not use standard output or standard error for this, as the standard
//! streams of the PX4 process are often not the ones connected to the terminal
//! the user is looking at.
//!
//! ### Example
//!
//! ```
//! use log::{info, warn};
//! use px4::px4_module_main;
//!
//! #[px4_module_main]
//! fn my_module(args: &[&str]) {
//! info!("Hello World!");
//! warn!("A warning!");
//! panic!("Bye!");
//! }
//! ```
//!
//! ## uORB
//!
//! Message definitions can be imported from `.msg` files, and then subscribed
//! to or published. See the [`uorb` module](uorb/index.html) for documentation
//! on how to use the uORB bindings.
//!
//! ### Example
//!
//! ```
//! use log::info;
//! use px4::{px4_module_main, px4_message};
//! use px4::uorb::{Publish, Subscribe};
//!
//! #[px4_message("../example/msg/debug_value.msg")]
//! pub struct debug_value;
//!
//! #[px4_module_main]
//! fn my_module(args: &[&str]) {
//!
//! let mut publ = debug_value::advertise();
//! publ.publish(&debug_value { timestamp: 0, value: 1.0, ind: 3 }).unwrap();
//!
//! let sub = debug_value::subscribe().unwrap();
//! info!("Latest debug message: {:?}", sub.get().unwrap());
//! }
//! ```
use std::ffi::CStr;
use std::os::raw::c_char;
pub mod uorb;
mod logging;
pub use crate::logging::{log_raw, LogLevel};
pub use px4_macros::{px4_message, px4_module_main};
#[doc(hidden)]
pub unsafe fn _run<F, R>(modulename: &'static [u8], argc: u32, argv: *mut *mut u8, f: F) -> i32
where
F: Fn(&[&str]) -> R + std::panic::UnwindSafe,
R: MainStatusCode,
{
logging::init(modulename);
std::panic::catch_unwind(move || {
let mut args = Vec::with_capacity(argc as usize);
for i in 0..argc {
args.push(
CStr::from_ptr(*argv.offset(i as isize) as *const c_char)
.to_str()
.unwrap_or_else(|_| panic!("Invalid UTF-8 in arguments.")),
);
}
f(&args).to_status_code()
}).unwrap_or(R::panic_status_code())
}
/// The return type of your `#[px4_module_main]` function.
pub trait MainStatusCode {
/// The status code to return.
fn to_status_code(self) -> i32;
/// The status code to return in case of a panic.
///
/// −1 by default.
fn panic_status_code() -> i32 {
-1
}
}
/// Returns 0.
impl MainStatusCode for () {
fn to_status_code(self) -> i32 {
0
}
}
/// Returns the `i32` itself.
impl MainStatusCode for i32 {
fn to_status_code(self) -> i32 {
self
}
}
/// Returns 0 for `Ok`, and 1 for `Err`.
impl MainStatusCode for Result<(), ()> {
fn to_status_code(self) -> i32 {
match self {
Ok(()) => 0,
Err(()) => 1,
}
}
}
/// Returns 0 for `Ok`, and the `i32` itself for `Err`.
impl MainStatusCode for Result<(), i32> {
fn to_status_code(self) -> i32 {
match self {
Ok(()) => 0,
Err(s) => s,
}
}
}