diff --git a/Cargo.toml b/Cargo.toml index d594cd65d..6f911f274 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,8 @@ crate-type = ["cdylib"] cpy-binder = "1.0" libc = "0.2" pyo3 = { version = "0.18", features = ["extension-module", "abi3-py39"], optional = true } -navigator-rs = { version = "0.4.0" } +# navigator-rs = { version = "0.5.0" } +navigator-rs = { git = "https://github.com/patrickelectric/navigator-rs.git", branch = "pi5" } rand = "0.8" lazy_static = "1.4.0" diff --git a/examples/cpp/simple.cpp b/examples/cpp/simple.cpp index c70a5c288..760ca80b5 100644 --- a/examples/cpp/simple.cpp +++ b/examples/cpp/simple.cpp @@ -34,9 +34,10 @@ int main() { printf("Leak sensor: %s\n", read_leak() ? "true" : "false"); - ADCData adc = read_adc_all(); + float adc[4]; + read_adc_all(adc, 4); printf("Reading ADC Channels: 1 = %f, 2 = %f, 3 = %f, 4 = %f\n", - adc.channel[0], adc.channel[1], adc.channel[2], adc.channel[3]); + adc[0], adc[1], adc[2], adc[3]); printf("Data ADC Channels: 1 = %f\n", read_adc(AdcChannel::Ch1)); diff --git a/examples/python/main.py b/examples/python/main.py index 4f30f2469..97b308275 100755 --- a/examples/python/main.py +++ b/examples/python/main.py @@ -2,7 +2,7 @@ import os import bluerobotics_navigator as navigator -from bluerobotics_navigator import AdcChannel, PwmChannel, UserLed +from bluerobotics_navigator import AdcChannel, UserLed def navigator_check(): diff --git a/src/lib.rs b/src/lib.rs index cf31f71c6..75d0d56ad 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -45,7 +45,7 @@ impl NavigatorManager { *NAVIGATOR.lock().unwrap() = Some(NavigatorManager { navigator: navigator_rs::Navigator::create() .with_rgb_led_strip_size(with_navigator_builder!().rgb_led_strip_size) - .build(), + .build_navigator_v1_pi4(), }); } &NAVIGATOR @@ -79,27 +79,6 @@ macro_rules! impl_from_enum { // Help with conversion from navigator enum API to our stable API impl_from_enum!(AdcChannel, navigator_rs::AdcChannel, Ch0, Ch1, Ch2, Ch3); -impl_from_enum!( - PwmChannel, - navigator_rs::PwmChannel, - Ch1, - Ch2, - Ch3, - Ch4, - Ch5, - Ch6, - Ch7, - Ch8, - Ch9, - Ch10, - Ch11, - Ch12, - Ch13, - Ch14, - Ch15, - Ch16, - All -); impl_from_enum!(UserLed, navigator_rs::UserLed, Led1, Led2, Led3); impl From for AxisData { @@ -112,19 +91,6 @@ impl From for AxisData { } } -impl From for ADCData { - fn from(read_adc: navigator_rs::ADCData) -> Self { - Self { - channel: [ - read_adc.channel[0], - read_adc.channel[1], - read_adc.channel[2], - read_adc.channel[3], - ], - } - } -} - #[cpy_enum] #[comment = "Available ADC channels to read from."] enum AdcChannel { @@ -142,28 +108,6 @@ enum UserLed { Led3, } -#[cpy_enum] -#[comment = "Controllable PWM output channels."] -enum PwmChannel { - Ch1, - Ch2, - Ch3, - Ch4, - Ch5, - Ch6, - Ch7, - Ch8, - Ch9, - Ch10, - Ch11, - Ch12, - Ch13, - Ch14, - Ch15, - Ch16, - All, -} - #[cpy_struct] #[comment = "Board-oriented direction axes (x is forwards, y is right, z is down)."] struct AxisData { @@ -172,12 +116,6 @@ struct AxisData { z: f32, } -#[cpy_struct] -#[comment = "An array of readings from the different ADC channels."] -struct ADCData { - channel: [f32; 4], -} - #[cpy_fn] #[comment_c = "Initializes the Navigator module with default settings."] #[comment_py = "Initializes the Navigator module with default settings.\n @@ -185,7 +123,7 @@ struct ADCData { >>> import bluerobotics_navigator as navigator\n >>> navigator.init()"] fn init() { - with_navigator!().init(); + // Keep to avoid API break } #[cpy_fn] @@ -197,7 +135,8 @@ fn init() { >>> import bluerobotics_navigator as navigator\n >>> sensors_ok = navigator.self_test()"] fn self_test() -> bool { - with_navigator!().self_test() + // Keep to avoid API break + true } #[cpy_fn] @@ -251,7 +190,9 @@ fn set_led_toggle(select: UserLed) { >>> import bluerobotics_navigator as navigator\n >>> navigator.set_led_all(True)"] fn set_led_all(state: bool) { - with_navigator!().set_led_all(state) + for led in [UserLed::Led1, UserLed::Led2, UserLed::Led3] { + with_navigator!().set_led(led.into(), state); + } } #[cpy_fn_c] @@ -298,8 +239,7 @@ fn set_neopixel_rgbw_py(rgb_array: Vec<[u8; 4]>) { with_navigator!().set_neopixel_rgbw(&rgb_array) } -#[cpy_fn] -#[comment_c = "Reads the ADC channel values (from the ADS1115 chip)."] +#[cpy_fn_py] #[comment_py = "Reads the ADC channel values (from the ADS1115 chip).\n Same as :py:func:`read_adc`, but it returns an array with all channel readings.\n Returns:\n @@ -307,8 +247,20 @@ fn set_neopixel_rgbw_py(rgb_array: Vec<[u8; 4]>) { Examples:\n >>> import bluerobotics_navigator as navigator\n >>> adc_measurements = navigator.read_adc_all().channel"] -fn read_adc_all() -> ADCData { - with_navigator!().read_adc_all().into() +fn read_adc_all_py() -> Vec { + with_navigator!().read_adc_all() +} + +#[cpy_fn_c] +#[comment_c = "Reads the ADC channel values (from the ADS1115 chip)."] +fn read_adc_all_c(adc_array: *mut f32, length: usize) { + let array = unsafe { + assert!(!adc_array.is_null()); + std::slice::from_raw_parts_mut::(adc_array, length) + }; + + let values = with_navigator!().read_adc_all(); + array[..length].copy_from_slice(&values[..length]); } #[cpy_fn] @@ -414,46 +366,6 @@ fn set_pwm_enable(state: bool) { with_navigator!().set_pwm_enable(state) } -#[cpy_fn] -#[comment_c = "Get the PWM chip (PCA9685)'s OE_pin state"] -#[comment_py = "Get the PWM chip (PCA9685)'s OE_pin state.\n - Returns:\n - bool: `True` -> ON, `False` -> OFF.\n - Examples:\n - Please check :py:func:`set_pwm_channel_value`\n - >>> navigator.get_pwm_enable()"] -fn get_pwm_enable() -> bool { - with_navigator!().get_pwm_enable() -} - -#[cpy_fn] -#[comment_c = "LOW_LEVEL: Sets the PWM frequency of the PCA9685 chip. All channels use the same frequency."] -#[comment_py = "LOW_LEVEL: Sets the PWM frequency of the PCA9685 chip. All channels use the same frequency.\n\n - This directly sets the PRE_SCALE value on the PCA9685 - it is generally easier to use - :py:func:`set_pwm_freq_hz` instead.\n - The desired prescaler value can be calculated for an update rate using the formula:\n - `prescale_value = round(clock_freq / (4096 * desired_freq)) - 1`,\n - where `clock_freq` is 24_576_000 to match the Navigator's 24.5760 MHz clock.\n - Notes:\n - Changing the pre-scaler affects the channel outputs, so they need to be re-configured afterwards - (e.g. using :py:func:`set_pwm_channel_value`).\n - The minimum prescaler value is 3, which corresponds to 1526 Hz.\n - The maximum prescaler value is 255, which corresponds to 24 Hz.\n - Servo motors generally work best with PWM frequencies between 50-200 Hz, - which corresponds to prescalar values of 119-29.\n - Internally, this function stops the oscillator and restarts it (if it was already running) - after setting the prescalar value.\n - Args:\n - value (uint8): The desired prescaler value (3..255).\n - Examples:\n - >>> import bluerobotics_navigator as navigator\n - >>> navigator.set_pwm_freq_prescale(119)\n - >>> navigator.set_pwm_channel_value(PwmChannel.Ch1, 2000)\n - >>> navigator.set_pwm_enable(True)"] -fn set_pwm_freq_prescale(value: u8) { - with_navigator!().set_pwm_freq_prescale(value) -} - #[cpy_fn] #[comment_c = "Sets the PWM frequency of the PCA9685 chip. All channels use the same frequency."] #[comment_py = "Sets the PWM frequency of the PCA9685 chip. All channels use the same frequency.\n @@ -468,10 +380,10 @@ fn set_pwm_freq_prescale(value: u8) { Examples:\n >>> import bluerobotics_navigator as navigator\n >>> navigator.set_pwm_freq_hz(60)\n - >>> navigator.set_pwm_channel_value(PwmChannel.Ch1, 2000)\n + >>> navigator.set_pwm_channel_value(1, 2000)\n >>> navigator.set_pwm_enable(True)"] fn set_pwm_freq_hz(freq: f32) { - with_navigator!().set_pwm_freq_hz(freq) + with_navigator!().set_pwm_frequency(freq) } #[cpy_fn] @@ -498,8 +410,8 @@ fn set_pwm_freq_hz(freq: f32) { >>> navigator.set_pwm_freq_hz(1000)\n >>> navigator.set_pwm_channel_value(PwmChannel.Ch1, 2000)\n >>> navigator.set_pwm_enable(True)"] -fn set_pwm_channel_value(channel: PwmChannel, value: u16) { - with_navigator!().set_pwm_channel_value(channel.into(), value) +fn set_pwm_channel_value(channel: usize, value: f32) { + with_navigator!().set_pwm_duty_cycle(channel, value / 4096.0) } #[cpy_fn] @@ -520,31 +432,31 @@ fn set_pwm_channel_value(channel: PwmChannel, value: u16) { >>> navigator.set_pwm_freq_hz(1000)\n >>> navigator.set_pwm_channel_duty_cycle(PwmChannel.Ch1, 0.5)\n >>> navigator.set_pwm_enable(True)"] -fn set_pwm_channel_duty_cycle(channel: PwmChannel, duty_cycle: f32) { - with_navigator!().set_pwm_channel_duty_cycle(channel.into(), duty_cycle) +fn set_pwm_channel_duty_cycle(channel: usize, duty_cycle: f32) { + with_navigator!().set_pwm_duty_cycle(channel, duty_cycle) } #[cpy_fn_c] -#[comment = "Sets the duty cycle (based on OFF counter from 0 to 4096) for a list of multiple PWM channels."] -fn set_pwm_channels_value_c(channels: *const PwmChannel, value: u16, length: usize) { +#[comment = "Sets the duty cycle (based on OFF counter from 0 to 1) for a list of multiple PWM channels."] +fn set_pwm_channels_value_c(channels: *const usize, value: f32, length: usize) { let array_channels = unsafe { assert!(!channels.is_null()); std::slice::from_raw_parts(channels, length) }; for channel in array_channels.iter().take(length) { - with_navigator!().set_pwm_channel_value(channel.clone().into(), value); + with_navigator!().set_pwm_duty_cycle(*channel, value); } } #[cpy_fn_c] #[comment = "Sets the duty cycle (from 0.0 to 1.0) for a list of multiple PWM channels."] -fn set_pwm_channels_duty_cycle_c(channels: *const PwmChannel, duty_cycle: f32, length: usize) { +fn set_pwm_channels_duty_cycle_c(channels: *const usize, duty_cycle: f32, length: usize) { let array_channels = unsafe { assert!(!channels.is_null()); std::slice::from_raw_parts(channels, length) }; for channel in array_channels.iter().take(length) { - with_navigator!().set_pwm_channel_duty_cycle(channel.clone().into(), duty_cycle); + with_navigator!().set_pwm_duty_cycle(*channel, duty_cycle); } } @@ -556,9 +468,9 @@ fn set_pwm_channels_duty_cycle_c(channels: *const PwmChannel, duty_cycle: f32, l Examples:\n You can use this method like :py:func:`set_pwm_channel_value`.\n >>> navigator.set_pwm_channels_value([PwmChannel.Ch1, PwmChannel.Ch16], 1000)"] -fn set_pwm_channels_value_py(channels: Vec, value: u16) { +fn set_pwm_channels_value_py(channels: Vec, value: u16) { for i in 0..channels.len() { - with_navigator!().set_pwm_channel_value(channels[i].clone().into(), value); + with_navigator!().set_pwm_duty_cycle(channels[i], value as f32 / 4096.0); } } @@ -570,15 +482,15 @@ fn set_pwm_channels_value_py(channels: Vec, value: u16) { Examples:\n You can use this method like :py:func:`set_pwm_channel_duty_cycle`.\n >>> navigator.set_pwm_channels_value([PwmChannel.Ch1, PwmChannel.Ch16], 0.5)"] -fn set_pwm_channels_duty_cycle_py(channels: Vec, duty_cycle: f32) { +fn set_pwm_channels_duty_cycle_py(channels: Vec, duty_cycle: f32) { for channel in channels { - with_navigator!().set_pwm_channel_duty_cycle(channel.into(), duty_cycle); + with_navigator!().set_pwm_duty_cycle(channel.into(), duty_cycle); } } #[cpy_fn_c] #[comment = "Sets the duty cycle (from 0 to 4096) for a list of multiple channels with multiple values."] -fn set_pwm_channels_values_c(channels: *const PwmChannel, values: *const u16, length: usize) { +fn set_pwm_channels_values_c(channels: *const usize, values: *const f32, length: usize) { let array_channels = unsafe { assert!(!channels.is_null()); std::slice::from_raw_parts(channels, length) @@ -588,14 +500,14 @@ fn set_pwm_channels_values_c(channels: *const PwmChannel, values: *const u16, le std::slice::from_raw_parts(values, length) }; for i in 0..length { - with_navigator!().set_pwm_channel_value(array_channels[i].clone().into(), array_values[i]); + with_navigator!().set_pwm_duty_cycle(array_channels[i], array_values[i] / 4096.0); } } #[cpy_fn_c] #[comment = "Sets the duty cycle (from 0.0 to 1.0) for a list of multiple channels with multiple values."] fn set_pwm_channels_duty_cycle_values_c( - channels: *const PwmChannel, + channels: *const usize, duty_cycle: *const f32, length: usize, ) { @@ -608,8 +520,7 @@ fn set_pwm_channels_duty_cycle_values_c( std::slice::from_raw_parts(duty_cycle, length) }; for i in 0..length { - with_navigator!() - .set_pwm_channel_duty_cycle(array_channels[i].clone().into(), array_values[i]); + with_navigator!().set_pwm_duty_cycle(array_channels[i], array_values[i]); } } @@ -622,14 +533,14 @@ fn set_pwm_channels_duty_cycle_values_c( Examples:\n You can use this method like :py:func:`set_pwm_channel_value`.\n >>> navigator.set_pwm_channels_values([PwmChannel.Ch1, PwmChannel.Ch5], [1000, 500])"] -fn set_pwm_channels_values_py(channels: Vec, values: Vec) { +fn set_pwm_channels_values_py(channels: Vec, values: Vec) { if channels.len() != values.len() { println!("The number of values is different from the number of PWM channels."); return; } for i in 0..channels.len() { - with_navigator!().set_pwm_channel_value(channels[i].clone().into(), values[i]); + with_navigator!().set_pwm_duty_cycle(channels[i].clone().into(), values[i] as f32 / 4096.0); } } @@ -642,20 +553,19 @@ fn set_pwm_channels_values_py(channels: Vec, values: Vec) { Examples:\n You can use this method like :py:func:`set_pwm_channel_duty_cycle`.\n >>> navigator.set_pwm_channels_duty_cycle_values([PwmChannel.Ch1, PwmChannel.Ch5], [0.25, 0.75])"] -fn set_pwm_channels_duty_cycle_values_py(channels: Vec, duty_cycle_values: Vec) { +fn set_pwm_channels_duty_cycle_values_py(channels: Vec, duty_cycle_values: Vec) { if channels.len() != duty_cycle_values.len() { println!("The number of values is different from the number of PWM channels."); return; } for i in 0..channels.len() { - with_navigator!() - .set_pwm_channel_duty_cycle(channels[i].clone().into(), duty_cycle_values[i]); + with_navigator!().set_pwm_duty_cycle(channels[i].clone().into(), duty_cycle_values[i]); } } cpy_module!( name = bluerobotics_navigator, - types = [AdcChannel, UserLed, PwmChannel, AxisData, ADCData], + types = [AdcChannel, UserLed, AxisData], functions = [ init, self_test, @@ -674,8 +584,6 @@ cpy_module!( read_accel, read_gyro, set_pwm_enable, - get_pwm_enable, - set_pwm_freq_prescale, set_pwm_freq_hz, set_pwm_channel_value, set_pwm_channel_duty_cycle,