Skip to content

Commit

Permalink
implicitly cast to bool in bindings
Browse files Browse the repository at this point in the history
Only the node binding's `StatusFlags` interface must use explicit boolean values.
To implicitly cast that interface's values to boolean would
- incur much more overhead
- lose precise typing information

See napi-rs docs about Env and Context.
  • Loading branch information
2bndy5 committed Oct 30, 2024
1 parent 4b751af commit ed03062
Show file tree
Hide file tree
Showing 10 changed files with 97 additions and 69 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@ This includes but is not limited to Linux on RPi. Other points of interest:

Here is the intended roadmap:

- [x] implement driver for the nRF24L01 (OTA compatible with other RF24 library)
- [x] implement driver for the nRF24L01 (OTA compatible with RF24 library)

This should be HAL-agnostic in terms of MCU. It would also be nice to
reimplement the same API (using [rust's `trait` feature][rust-traits])
for use on nRF5x radios.

- [ ] implement a fake BLE API for the nRF24L01 (see [#4](https://github.com/nRF24/rf24-rs/issues/4))
- [ ] implement network layers (OTA compatible with RF24Network and RF24Mesh libraries)
- [ ] implement ESB support for nRF5x MCUs. This might be guarded under [cargo features][cargo-feat].

Expand Down
43 changes: 24 additions & 19 deletions bindings/node/src/radio.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
#![cfg(target_os = "linux")]

use crate::types::{
AvailablePipe, CrcLength, DataRate, FifoState, HardwareConfig, PaLevel, StatusFlags,
WriteConfig,
coerce_to_bool, AvailablePipe, CrcLength, DataRate, FifoState, HardwareConfig, PaLevel,
StatusFlags, WriteConfig,
};
use linux_embedded_hal::{
gpio_cdev::{chips, LineRequestFlags},
spidev::{SpiModeFlags, SpidevOptions},
CdevPin, Delay, SpidevDevice,
};
use napi::{bindgen_prelude::Buffer, Error, Result, Status};
use napi::{bindgen_prelude::Buffer, Error, JsNumber, Result, Status};

use rf24::radio::prelude::*;

Expand Down Expand Up @@ -168,10 +168,15 @@ impl RF24 {
///
/// @group Basic
#[napi]
pub fn send(&mut self, buf: Buffer, ask_no_ack: Option<bool>) -> Result<bool> {
pub fn send(
&mut self,
buf: Buffer,
#[napi(ts_arg_type = "boolean | number")] ask_no_ack: Option<JsNumber>,
) -> Result<bool> {
let buf = buf.to_vec();
let ask_no_ack = coerce_to_bool(ask_no_ack, false)?;
self.inner
.send(&buf, ask_no_ack.unwrap_or_default())
.send(&buf, ask_no_ack)
.map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}")))
}

Expand Down Expand Up @@ -330,9 +335,9 @@ impl RF24 {
///
/// @group Configuration
#[napi]
pub fn set_lna(&mut self, enable: bool) -> Result<()> {
pub fn set_lna(&mut self,#[napi(ts_arg_type = "boolean | number")] enable: JsNumber) -> Result<()> {
self.inner
.set_lna(enable)
.set_lna(coerce_to_bool(Some(enable), true)?)
.map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}")))
}

Expand All @@ -345,9 +350,9 @@ impl RF24 {
///
/// @group Configuration
#[napi]
pub fn allow_ack_payloads(&mut self, enable: bool) -> Result<()> {
pub fn allow_ack_payloads(&mut self, #[napi(ts_arg_type = "boolean | number")] enable: JsNumber) -> Result<()> {
self.inner
.allow_ack_payloads(enable)
.allow_ack_payloads(coerce_to_bool(Some(enable), false)?)
.map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}")))
}

Expand All @@ -359,19 +364,19 @@ impl RF24 {
///
/// @group Configuration
#[napi]
pub fn set_auto_ack(&mut self, enable: bool) -> Result<()> {
pub fn set_auto_ack(&mut self, #[napi(ts_arg_type = "boolean | number")] enable: JsNumber) -> Result<()> {
self.inner
.set_auto_ack(enable)
.set_auto_ack(coerce_to_bool(Some(enable), false)?)
.map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}")))
}

/// Enable or disable the auto-ack feature for a specified `pipe`.
///
/// @group Configuration
#[napi]
pub fn set_auto_ack_pipe(&mut self, enable: bool, pipe: u8) -> Result<()> {
pub fn set_auto_ack_pipe(&mut self, enable: JsNumber, pipe: u8) -> Result<()> {
self.inner
.set_auto_ack_pipe(enable, pipe)
.set_auto_ack_pipe(coerce_to_bool(Some(enable), false)?, pipe)
.map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}")))
}

Expand All @@ -383,9 +388,9 @@ impl RF24 {
///
/// @group Configuration
#[napi]
pub fn allow_ask_no_ack(&mut self, enable: bool) -> Result<()> {
pub fn allow_ask_no_ack(&mut self, #[napi(ts_arg_type = "boolean | number")] enable: JsNumber) -> Result<()> {
self.inner
.allow_ask_no_ack(enable)
.allow_ask_no_ack(coerce_to_bool(Some(enable), false)?)
.map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}")))
}

Expand Down Expand Up @@ -567,9 +572,9 @@ impl RF24 {
///
/// @group Advanced
#[napi]
pub fn get_fifo_state(&mut self, about_tx: bool) -> Result<FifoState> {
pub fn get_fifo_state(&mut self, #[napi(ts_arg_type = "boolean | number")] about_tx: JsNumber) -> Result<FifoState> {
self.inner
.get_fifo_state(about_tx)
.get_fifo_state(coerce_to_bool(Some(about_tx), false)?)
.map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}")))
.map(|e| FifoState::from_inner(e))
}
Expand Down Expand Up @@ -631,9 +636,9 @@ impl RF24 {
///
/// @group Configuration
#[napi]
pub fn set_dynamic_payloads(&mut self, enable: bool) -> Result<()> {
pub fn set_dynamic_payloads(&mut self, #[napi(ts_arg_type = "boolean | number")] enable: JsNumber) -> Result<()> {
self.inner
.set_dynamic_payloads(enable)
.set_dynamic_payloads(coerce_to_bool(Some(enable), false)?)
.map_err(|e| Error::new(Status::GenericFailure, format!("{e:?}")))
}

Expand Down
12 changes: 12 additions & 0 deletions bindings/node/src/types.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
//! This module defines thin wrappers around rust native types to be exposed in node.js
use napi::{JsNumber, Result};



/// A private helper to implicitly convert JS numbers to boolean values (falling back to a `default` value)
pub fn coerce_to_bool(napi_instance: Option<JsNumber>, default: bool) -> Result<bool> {
if let Some(napi_value) = napi_instance {
return napi_value.coerce_to_bool()?.get_value();
}
return Ok(default);
}

/// Optional configuration parameters to fine tune instantiating the {@link RF24} object.
/// Pass this object as third parameter to {@link RF24} constructor.
#[napi(object)]
Expand Down
48 changes: 24 additions & 24 deletions bindings/python/src/radio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,12 +150,12 @@ impl RF24 {
/// This has no effect if auto-ack is disabled or
/// [RF24.allow_ask_no_ack] is not enabled.
#[pyo3(
signature = (buf, ask_no_ack = false),
text_signature = "(buf: bytes | bytearray, ask_no_ack = False) -> bool",
signature = (buf, ask_no_ack = 0i32),
text_signature = "(buf: bytes | bytearray, ask_no_ack: bool | int = False) -> bool",
)]
pub fn send(&mut self, buf: &[u8], ask_no_ack: bool) -> PyResult<bool> {
pub fn send(&mut self, buf: &[u8], ask_no_ack: i32) -> PyResult<bool> {
self.inner
.send(buf, ask_no_ack)
.send(buf, ask_no_ack != 0)
.map_err(|e| PyRuntimeError::new_err(format!("{e:?}")))
}

Expand All @@ -180,12 +180,12 @@ impl RF24 {
/// Returns:
/// A Boolean that describes if the given `buf` was successfully loaded into the TX FIFO.
#[pyo3(
signature = (buf, ask_no_ack = false, start_tx = true),
text_signature = "(buf: bytes | bytearray, ask_no_ack = False, start_tx = True) -> bool",
signature = (buf, ask_no_ack = 0i32, start_tx = 1i32),
text_signature = "(buf: bytes | bytearray, ask_no_ack: bool | int = False, start_tx: bool | int = True) -> bool",
)]
pub fn write(&mut self, buf: &[u8], ask_no_ack: bool, start_tx: bool) -> PyResult<bool> {
pub fn write(&mut self, buf: &[u8], ask_no_ack: i32, start_tx: i32) -> PyResult<bool> {
self.inner
.write(buf, ask_no_ack, start_tx)
.write(buf, ask_no_ack != 0, start_tx != 0)
.map_err(|e| PyRuntimeError::new_err(format!("{e:?}")))
}

Expand Down Expand Up @@ -299,9 +299,9 @@ impl RF24 {
/// For clone's and module's with a separate PA/LNA circuit (external antenna),
/// this function may not behave exactly as expected. Consult the radio module's
/// manufacturer.
pub fn set_lna(&mut self, enable: bool) -> PyResult<()> {
pub fn set_lna(&mut self, enable: i32) -> PyResult<()> {
self.inner
.set_lna(enable)
.set_lna(enable != 0)
.map_err(|e| PyRuntimeError::new_err(format!("{e:?}")))
}

Expand All @@ -311,9 +311,9 @@ impl RF24 {
/// > This feature requires dynamically sized payloads.
/// > Use [`RF24.set_dynamic_payloads(True)`][rf24_py.RF24.set_dynamic_payloads]
/// > to enable dynamically sized payloads.
pub fn allow_ack_payloads(&mut self, enable: bool) -> PyResult<()> {
pub fn allow_ack_payloads(&mut self, enable: i32) -> PyResult<()> {
self.inner
.allow_ack_payloads(enable)
.allow_ack_payloads(enable != 0)
.map_err(|e| PyRuntimeError::new_err(format!("{e:?}")))
}

Expand All @@ -325,9 +325,9 @@ impl RF24 {
///
/// Parameters:
/// enable: Pass true to enable the auto-ack feature for all pipes.
pub fn set_auto_ack(&mut self, enable: bool) -> PyResult<()> {
pub fn set_auto_ack(&mut self, enable: i32) -> PyResult<()> {
self.inner
.set_auto_ack(enable)
.set_auto_ack(enable != 0)
.map_err(|e| PyRuntimeError::new_err(format!("{e:?}")))
}

Expand All @@ -340,9 +340,9 @@ impl RF24 {
/// Parameters:
/// enable: Pass true to enable the auto-ack feature for the specified `pipe`.
/// pipe: The pipe about which to control the auto-ack feature.
pub fn set_auto_ack_pipe(&mut self, enable: bool, pipe: u8) -> PyResult<()> {
pub fn set_auto_ack_pipe(&mut self, enable: i32, pipe: u8) -> PyResult<()> {
self.inner
.set_auto_ack_pipe(enable, pipe)
.set_auto_ack_pipe(enable != 0, pipe)
.map_err(|e| PyRuntimeError::new_err(format!("{e:?}")))
}

Expand All @@ -352,9 +352,9 @@ impl RF24 {
/// enable: Setting this to `true` will allow the `ask_no_ack` parameter to
/// take effect. See [`RF24.send()`][rf24_py.RF24.send] and
/// [`RF24.write()`][rf24_py.RF24.write] for more detail.
pub fn allow_ask_no_ack(&mut self, enable: bool) -> PyResult<()> {
pub fn allow_ask_no_ack(&mut self, enable: i32) -> PyResult<()> {
self.inner
.allow_ask_no_ack(enable)
.allow_ask_no_ack(enable != 0)
.map_err(|e| PyRuntimeError::new_err(format!("{e:?}")))
}

Expand Down Expand Up @@ -494,9 +494,9 @@ impl RF24 {
/// Parameters:
/// about_tx: True returns data about the TX FIFO.
/// False returns data about the RX FIFO.
pub fn get_fifo_state(&mut self, about_tx: bool) -> PyResult<FifoState> {
pub fn get_fifo_state(&mut self, about_tx: i32) -> PyResult<FifoState> {
self.inner
.get_fifo_state(about_tx)
.get_fifo_state(about_tx != 0)
.map_err(|e| PyRuntimeError::new_err(format!("{e:?}")))
.map(|e| FifoState::from_inner(e))
}
Expand Down Expand Up @@ -544,9 +544,9 @@ impl RF24 {
/// enable: If set to `true`, the statically sized payload length (set via
/// [`RF24.payload_length`][rf24_py.RF24.payload_length]) are not
/// used.
pub fn set_dynamic_payloads(&mut self, enable: bool) -> PyResult<()> {
pub fn set_dynamic_payloads(&mut self, enable: i32) -> PyResult<()> {
self.inner
.set_dynamic_payloads(enable)
.set_dynamic_payloads(enable != 0)
.map_err(|e| PyRuntimeError::new_err(format!("{e:?}")))
}

Expand Down Expand Up @@ -633,8 +633,8 @@ impl RF24 {
/// Setting this attribute to `True` is equivalent to calling
/// [`power_up()`][rf24_py.RF24.power_up] (using default delay).
#[setter]
pub fn set_power(&mut self, enable: bool) -> PyResult<()> {
if enable {
pub fn set_power(&mut self, enable: i32) -> PyResult<()> {
if enable != 0 {
self.power_up(None)
} else {
self.power_down()
Expand Down
13 changes: 8 additions & 5 deletions bindings/python/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,15 @@ pub struct StatusFlags {
#[pymethods]
impl StatusFlags {
#[new]
#[pyo3(signature = (rx_dr = false, tx_ds = false, tx_df = false))]
fn new(rx_dr: bool, tx_ds: bool, tx_df: bool) -> Self {
#[pyo3(
signature = (rx_dr = 0i32, tx_ds = 0i32, tx_df = 0i32),
text_signature = "(rx_dr: bool = False, tx_ds: bool = False, tx_df: bool = False) -> StatusFlags",
)]
fn new(rx_dr: i32, tx_ds: i32, tx_df: i32) -> Self {
Self {
rx_dr,
tx_ds,
tx_df,
rx_dr: rx_dr != 0,
tx_ds: tx_ds != 0,
tx_df: tx_df != 0,
}
}

Expand Down
2 changes: 1 addition & 1 deletion crates/rf24-rs/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# rf24-rs

This is a rust driver library for the nRF24L01 wireless transceivers.
This crate is a rust driver library for the nRF24L01 wireless transceivers.

See the examples in the repository's [examples/rust](https://github.com/nRF24/rf24-rs/blob/main/examples/rust) folder.

Expand Down
7 changes: 4 additions & 3 deletions crates/rf24-rs/src/radio/rf24/details.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use super::{mnemonics, registers};
use crate::{
radio::prelude::{
EsbChannel, EsbCrcLength, EsbDataRate, EsbFifo, EsbPaLevel, EsbPayloadLength, EsbPipe,
EsbStatus,
EsbPower, EsbStatus,
},
StatusFlags,
};
Expand Down Expand Up @@ -126,7 +126,7 @@ where
);
defmt::println!(
"Powered Up________________{=bool}",
self._config_reg & 2 > 0
self.is_powered()
);

// print pipe addresses
Expand Down Expand Up @@ -172,6 +172,7 @@ where
#[cfg(not(target_os = "none"))]
#[cfg(feature = "std")]
fn print_details(&mut self) -> Result<(), Self::DetailsErrorType> {

std::println!("Is a plus variant_________{}", self.is_plus_variant());

let channel = self.get_channel()?;
Expand Down Expand Up @@ -258,7 +259,7 @@ where
"Primary Mode______________{}X",
if self._config_reg & 1 > 0 { "R" } else { "T" }
);
std::println!("Powered Up________________{}", self._config_reg & 2 > 0);
std::println!("Powered Up________________{}", self.is_powered());

// print pipe addresses
self.spi_read(5, registers::TX_ADDR)?;
Expand Down
4 changes: 2 additions & 2 deletions crates/rf24-rs/src/radio/rf24/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ where
/// `spi` bus with the given `ce_pin`.
///
/// The radio's CSN pin (aka Chip Select pin) shall be defined
/// when instantiating the [`SpiDevice`] object (passed to the
/// `spi` parameter).
/// when instantiating the [`SpiDevice`](trait@embedded-hal::spi::SpiDevice)
/// object (passed to the `spi` parameter).
pub fn new(ce_pin: DO, spi: SPI, delay_impl: DELAY) -> RF24<SPI, DO, DELAY> {
RF24 {
_status: 0,
Expand Down
6 changes: 3 additions & 3 deletions crates/rf24-rs/src/radio/rf24/power.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ where
self.spi_write_byte(registers::CONFIG, self._config_reg)?;

// For nRF24L01+ to go from power down mode to TX or RX mode it must first pass through stand-by mode.
// There must be a delay of Tpd2stby (see Table 16.) after the nRF24L01+ leaves power down mode before
// the CEis set high. - Tpd2stby can be up to 5ms per the 1.0 datasheet
// There must be a delay of Tpd2standby (see Table 16.) after the nRF24L01+ leaves power down mode before
// the CE is set high. Tpd2standby can be up to 5ms per the 1.0 datasheet
if delay.is_some_and(|val| val > 0) || delay.is_none() {
self._delay_impl.delay_ns(delay.unwrap_or(5000000));
}
Expand All @@ -47,7 +47,7 @@ where

/// Is the radio powered up?
fn is_powered(&self) -> bool {
(self._config_reg & 2) != 2
(self._config_reg & 2) > 0
}
}

Expand Down
Loading

0 comments on commit ed03062

Please sign in to comment.