Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix restart_nonblocking error, add integer address mode #4

Merged
merged 3 commits into from Sep 2, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Expand Up @@ -67,11 +67,11 @@ on channel 0.
```rust
extern crate linux_embedded_hal as hal;
extern crate pwm_pca9685 as pca9685;
use pca9685::{ Channel, Pca9685, SlaveAddr };
use pca9685::{ Channel, Pca9685, Address };

fn main() {
let dev = hal::I2cdev::new("/dev/i2c-1").unwrap();
let address = SlaveAddr::default();
let address = Address::default();
let mut pwm = Pca9685::new(dev, address);
// This corresponds to a frequency of 60 Hz.
pwm.set_prescale(100).unwrap();
Expand Down
6 changes: 3 additions & 3 deletions examples/linux.rs
Expand Up @@ -3,12 +3,12 @@ extern crate linux_embedded_hal;
extern crate pwm_pca9685 as pca9685;

use linux_embedded_hal::I2cdev;
use pca9685::{Channel, Pca9685, SlaveAddr};
use pca9685::{Channel, Pca9685, Address};

fn main() {
let dev = I2cdev::new("/dev/i2c-1").unwrap();
let address = SlaveAddr::default();
let mut pwm = Pca9685::new(dev, address);
let address = Address::default();
let mut pwm = Pca9685::new(dev, address).unwrap();

// This corresponds to a frequency of 60 Hz.
pwm.set_prescale(100).unwrap();
Expand Down
41 changes: 25 additions & 16 deletions src/device_impl.rs
Expand Up @@ -2,7 +2,7 @@ use crate::{
config::{BitFlagMode1, BitFlagMode2, Config},
hal::{blocking::delay::DelayUs, blocking::i2c},
DisabledOutputValue, Error, OutputDriver, OutputLogicState, OutputStateChange, Pca9685,
ProgrammableAddress, Register, SlaveAddr,
ProgrammableAddress, Register, Address,
};
use nb;

Expand All @@ -11,12 +11,16 @@ where
I2C: i2c::Write<Error = E> + i2c::WriteRead<Error = E>,
{
/// Create a new instance of the device.
pub fn new(i2c: I2C, address: SlaveAddr) -> Self {
Pca9685 {
pub fn new<A: Into<Address>>(i2c: I2C, address: A) -> Result<Self, Error<E>> {
let a = address.into();

Self::check_address(a.0)?;

Ok(Pca9685 {
i2c,
address: address.address(),
address: a.0,
config: Config::default(),
}
})
}

/// Destroy driver instance, return I²C bus instance.
Expand Down Expand Up @@ -72,17 +76,17 @@ where
/// least 500us after the receiving the first `WouldBlock` error before
/// calling again to continue.
pub fn restart_nonblocking(&mut self) -> nb::Result<(), Error<E>> {
let mode1 = self.read_register(Register::MODE1)?;
let mode1 = self.read_register(Register::MODE1).map_err(nb::Error::Other)?;
eldruin marked this conversation as resolved.
Show resolved Hide resolved
let restart_high = (mode1 & BitFlagMode1::Restart as u8) != 0;
let sleep_high = (mode1 & BitFlagMode1::Sleep as u8) != 0;
if restart_high {
if sleep_high {
self.enable()?;
self.enable().map_err(nb::Error::Other)?;
return Err(nb::Error::WouldBlock);
} else {
let previous = self.config;
let config = previous.with_high(BitFlagMode1::Restart);
self.write_mode1(config)?;
self.write_mode1(config).map_err(nb::Error::Other)?;
self.config = previous;
}
}
Expand All @@ -94,20 +98,22 @@ where
/// Initially these are not enabled. Once you set this, you can call
/// `enable_programmable_address()` and then use `set_address()` to configure
/// the driver to use the new address.
pub fn set_programmable_address(
pub fn set_programmable_address<A: Into<Address>>(
&mut self,
address_type: ProgrammableAddress,
address: u8,
address: A,
) -> Result<(), Error<E>> {
self.check_address(address)?;
let a = address.into();

Self::check_address(a.0)?;
let reg = match address_type {
ProgrammableAddress::Subaddress1 => Register::SUBADDR1,
ProgrammableAddress::Subaddress2 => Register::SUBADDR2,
ProgrammableAddress::Subaddress3 => Register::SUBADDR3,
ProgrammableAddress::AllCall => Register::ALL_CALL_ADDR,
};
self.i2c
.write(self.address, &[reg, address])
.write(self.address, &[reg, a.0])
.map_err(Error::I2C)
}

Expand Down Expand Up @@ -145,13 +151,16 @@ where
/// This does not have any effect on the hardware and is useful when
/// switching between programmable addresses and the fixed hardware address
/// for communication.
pub fn set_address(&mut self, address: u8) -> Result<(), Error<E>> {
self.check_address(address)?;
self.address = address;
pub fn set_address<A: Into<Address>>(&mut self, address: A) -> Result<(), Error<E>> {
let a = address.into();

Self::check_address(a.0)?;
self.address = a.0;

Ok(())
}

fn check_address(&self, address: u8) -> Result<(), Error<E>> {
fn check_address(address: u8) -> Result<(), Error<E>> {
const LED_ALL_CALL: u8 = 0b111_0000;
// const SW_RESET: u8 = 0b000_0011; this gets absorbed by the high speed mode test
const HIGH_SPEED_MODE: u8 = 0b000_111;
Expand Down
50 changes: 25 additions & 25 deletions src/lib.rs
Expand Up @@ -76,12 +76,12 @@
//! ```no_run
//! extern crate linux_embedded_hal as hal;
//! extern crate pwm_pca9685 as pca9685;
//! use pca9685::{ Pca9685, SlaveAddr };
//! use pca9685::{ Pca9685, Address };
//!
//! # fn main() {
//! let dev = hal::I2cdev::new("/dev/i2c-1").unwrap();
//! let address = SlaveAddr::default();
//! let pwm = Pca9685::new(dev, address);
//! let address = Address::default();
//! let pwm = Pca9685::new(dev, address).unwrap();
//! // do something...
//!
//! // get the I2C device back
Expand All @@ -94,13 +94,13 @@
//! ```no_run
//! extern crate linux_embedded_hal as hal;
//! extern crate pwm_pca9685 as pca9685;
//! use pca9685::{ Pca9685, SlaveAddr };
//! use pca9685::{ Pca9685, Address };
//!
//! # fn main() {
//! let dev = hal::I2cdev::new("/dev/i2c-1").unwrap();
//! let (a5, a4, a3, a2, a1, a0) = (false, true, false, true, true, false);
//! let address = SlaveAddr::Alternative(a5, a4, a3, a2, a1, a0);
//! let pwm = Pca9685::new(dev, address);
//! let address = (a5, a4, a3, a2, a1, a0);
//! let pwm = Pca9685::new(dev, address).unwrap();
//! # }
//! ```
//!
Expand All @@ -115,12 +115,12 @@
//! ```no_run
//! extern crate linux_embedded_hal as hal;
//! extern crate pwm_pca9685 as pca9685;
//! use pca9685::{ Channel, Pca9685, SlaveAddr };
//! use pca9685::{ Channel, Pca9685, Address };
//!
//! # fn main() {
//! let dev = hal::I2cdev::new("/dev/i2c-1").unwrap();
//! let address = SlaveAddr::default();
//! let mut pwm = Pca9685::new(dev, address);
//! let address = Address::default();
//! let mut pwm = Pca9685::new(dev, address).unwrap();
//! pwm.set_prescale(100).unwrap();
//!
//! // Turn on channel 0 at 0 and off at 2047, which is 50% in the range `[0..4095]`.
Expand All @@ -144,12 +144,12 @@
//! ```no_run
//! extern crate linux_embedded_hal as hal;
//! extern crate pwm_pca9685 as pca9685;
//! use pca9685::{ Channel, Pca9685, SlaveAddr };
//! use pca9685::{ Channel, Pca9685, Address };
//!
//! # fn main() {
//! let dev = hal::I2cdev::new("/dev/i2c-1").unwrap();
//! let address = SlaveAddr::default();
//! let mut pwm = Pca9685::new(dev, address);
//! let address = Address::default();
//! let mut pwm = Pca9685::new(dev, address).unwrap();
//! pwm.set_prescale(100).unwrap();
//!
//! // Turn on channel 0 at 0
Expand All @@ -173,12 +173,12 @@
//! ```no_run
//! extern crate linux_embedded_hal as hal;
//! extern crate pwm_pca9685 as pca9685;
//! use pca9685::{ Channel, Pca9685, SlaveAddr };
//! use pca9685::{ Channel, Pca9685, Address };
//!
//! # fn main() {
//! let dev = hal::I2cdev::new("/dev/i2c-1").unwrap();
//! let address = SlaveAddr::default();
//! let mut pwm = Pca9685::new(dev, address);
//! let address = Address::default();
//! let mut pwm = Pca9685::new(dev, address).unwrap();
//!
//! // Turn channel 0 full on at 1024
//! pwm.set_channel_full_on(Channel::C0, 1024).unwrap();
Expand All @@ -203,12 +203,12 @@
//! ```no_run
//! extern crate linux_embedded_hal as hal;
//! extern crate pwm_pca9685 as pca9685;
//! use pca9685::{ Channel, Pca9685, SlaveAddr };
//! use pca9685::{ Channel, Pca9685, Address };
//!
//! # fn main() {
//! let dev = hal::I2cdev::new("/dev/i2c-1").unwrap();
//! let address = SlaveAddr::default();
//! let mut pwm = Pca9685::new(dev, address);
//! let address = Address::default();
//! let mut pwm = Pca9685::new(dev, address).unwrap();
//!
//! let mut on = [0; 16];
//! let mut off = [2047; 16];
Expand All @@ -227,12 +227,12 @@
//! ```no_run
//! extern crate linux_embedded_hal as hal;
//! extern crate pwm_pca9685 as pca9685;
//! use pca9685::{Channel, Pca9685, SlaveAddr, ProgrammableAddress};
//! use pca9685::{Channel, Pca9685, Address, ProgrammableAddress};
//!
//! # fn main() {
//! let dev = hal::I2cdev::new("/dev/i2c-1").unwrap();
//! let hardware_address = SlaveAddr::default();
//! let mut pwm = Pca9685::new(dev, hardware_address);
//! let hardware_address = Address::default();
//! let mut pwm = Pca9685::new(dev, hardware_address).unwrap();
//!
//! let subaddr1 = 0x71;
//! pwm.set_programmable_address(ProgrammableAddress::Subaddress1, subaddr1).unwrap();
Expand All @@ -243,7 +243,7 @@
//! pwm.set_channel_on_off(Channel::C0, 0, 2047).unwrap();
//!
//! // The device will also respond to the hardware address:
//! pwm.set_address(hardware_address.address()).unwrap();
//! pwm.set_address(hardware_address).unwrap();
//! pwm.set_channel_on_off(Channel::C0, 2047, 4095).unwrap();
//!
//! // when done you can also disable responding to the additional address:
Expand All @@ -256,11 +256,11 @@
//! ```no_run
//! extern crate linux_embedded_hal as hal;
//! extern crate pwm_pca9685 as pca9685;
//! use pca9685::{Channel, Pca9685, SlaveAddr};
//! use pca9685::{Channel, Pca9685, Address};
//!
//! # fn main() {
//! let dev = hal::I2cdev::new("/dev/i2c-1").unwrap();
//! let mut pwm = Pca9685::new(dev, SlaveAddr::default());
//! let mut pwm = Pca9685::new(dev, Address::default()).unwrap();
//!
//! pwm.set_channel_on_off(Channel::C0, 0, 2047).unwrap();
//! // Prepare for restart and put the device to sleep
Expand All @@ -285,5 +285,5 @@ mod device_impl;
mod types;
pub use crate::types::{
Channel, DisabledOutputValue, Error, OutputDriver, OutputLogicState, OutputStateChange,
Pca9685, ProgrammableAddress, SlaveAddr,
Pca9685, ProgrammableAddress, Address,
};
59 changes: 28 additions & 31 deletions src/types.rs
Expand Up @@ -176,43 +176,40 @@ pub enum ProgrammableAddress {
AllCall,
}

/// Possible slave addresses
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum SlaveAddr {
/// Default slave address
Default,
/// Alternative slave address providing bit values for A5, A4, A3, A2, A1 and A0
Alternative(bool, bool, bool, bool, bool, bool),
}
/// I2C device address
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Address(pub(crate) u8);

impl Default for SlaveAddr {
/// Default slave address
/// Default device address
impl Default for Address {
fn default() -> Self {
SlaveAddr::Default
Address(DEVICE_BASE_ADDRESS)
}
}

impl SlaveAddr {
/// Get the I2C slave address
///
/// This is useful when switching between programmable addresses and the
/// fixed hardware slave address.
pub fn address(self) -> u8 {
match self {
SlaveAddr::Default => DEVICE_BASE_ADDRESS,
SlaveAddr::Alternative(a5, a4, a3, a2, a1, a0) => {
DEVICE_BASE_ADDRESS
| ((a5 as u8) << 5)
| ((a4 as u8) << 4)
| ((a3 as u8) << 3)
| ((a2 as u8) << 2)
| ((a1 as u8) << 1)
| a0 as u8
}
}
/// Support custom (integer) addresses
impl From<u8> for Address {
fn from(a: u8) -> Self {
Address(a)
}
}

/// Compute device address from address bits
impl From<(bool, bool, bool, bool, bool, bool)> for Address {
fn from(a: (bool, bool, bool, bool, bool, bool)) -> Self {
Address(
DEVICE_BASE_ADDRESS
| ((a.0 as u8) << 5)
| ((a.1 as u8) << 4)
| ((a.2 as u8) << 3)
| ((a.3 as u8) << 2)
| ((a.4 as u8) << 1)
| a.5 as u8
)
}
}


#[cfg(test)]
mod tests {
use super::*;
Expand All @@ -233,7 +230,7 @@ mod tests {

#[test]
fn can_get_default_address() {
let addr = SlaveAddr::default();
assert_eq!(DEVICE_BASE_ADDRESS, addr.address());
let addr = Address::default();
assert_eq!(DEVICE_BASE_ADDRESS, addr.0);
}
}