almindor / max7219

A platform agnostic driver to interface with the MAX7219 (LED display driver)
MIT License
16 stars 7 forks source link

Can't create max7219 driver from using rppal::spi::Spi #3

Closed nilscript closed 4 years ago

nilscript commented 4 years ago

Im trying to write a digital clock using a raspberry pi and found this library. I can't get it to work though as the error types from this library and rppal does not implement the same trait. I am unsure if the scope of this library is to support raspberry pi or rppal directly but it's worth asking.

The compile error:

error[E0277]: the trait bound `max7219::PinError: std::convert::From<rppal::spi::Error>` is not satisfied
 --> src/main.rs:7:5
  |
7 |     MAX7219::from_spi(1, spi).unwrap();
  |     ^^^^^^^^^^^^^^^^^ the trait `std::convert::From<rppal::spi::Error>` is not implemented for `max7219::PinError`
  |
  = help: the following implementations were found:
            <max7219::PinError as std::convert::From<()>>
            <max7219::PinError as std::convert::From<std::convert::Infallible>>
  = note: required by `max7219::MAX7219::<max7219::connectors::SpiConnector<SPI>>::from_spi`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0277`.
error: could not compile `clock`.

To learn more, run the command again with --verbose.

main.rs:

use rppal::spi::{self, Bus, Mode, SlaveSelect, Spi};
use max7219::MAX7219;

fn main() -> Result<(), spi::Error> {

    let spi = Spi::new(Bus::Spi0, SlaveSelect::Ss0, /*10MHz*/ 10_000_000, Mode::Mode0)?;
    MAX7219::from_spi(1, spi).unwrap();

    Ok(())
}

Cargo.toml:

[package]
name = "clock"
version = "0.1.0"
authors = ["Nils Eriksson <nils.edvin.eriksson@gmail.com>"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
max7219 = "0.2.2"

[dependencies.rppal]
version = "0.11.3"
features = ["hal"]

I am unsure of where a potential solution can be implemented as this lib is a no-std lib. Could be that a solution should exist in the rppal library instead.

almindor commented 4 years ago

Interesting, this means that the rppal::spi is fallible on PIN operations.

There's a constraint on the SPI connector that says PinError: core::convert::From<SPI::Error>

A solution would be to implement this conversion problem is that's not possible outside rppal or the max driver itself due to orphan rules. I'll have to think more about how this can get resolved.

almindor commented 4 years ago

Normaly a generic solution would be to do something like

impl<E> From<E> for PinError {
  fn from(_: E) -> PinError {
    PinError
  }
}

However this is already present in core and it conflicts. Which means that for some readon From<rppi::SPI::Error> does not get implemented for PinError using that core conversion

nilscript commented 4 years ago

I also tried the exact same solution but its as you say. Core conflicts.

almindor commented 4 years ago

Could you try latest master now please? I'm a bit busy today to do proper re-testing of everything but I think it should work. Note: the version is bumped to 0.3.0 so you'll need to workspace this.

I've used .map_err(|_| DataError) and expanded the PinError into a DataError enum so while the main error is lost you still know if it was a PIN error or an SPI one now.

If this works for you I'll try and test tomorrow and do a release.

nilscript commented 4 years ago

We were really on the same wave length today. I also though about just mapping the error. It is compiling now. Lets see if the clock can write something.

Also thanks for the quick help :)

nilscript commented 4 years ago

This works for me. Display is working fine. Hope it works for other systems as well.

almindor commented 4 years ago

Released v0.3.0