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

CAN example #312

Open
hanusek opened this issue Sep 30, 2023 · 6 comments
Open

CAN example #312

hanusek opened this issue Sep 30, 2023 · 6 comments

Comments

@hanusek
Copy link

hanusek commented Sep 30, 2023

Hello.
Based on example I tried to compile it:

use esp_idf_sys as _;
use log::*;

use embedded_can::nb::*;
use embedded_can::Frame;
use esp_idf_hal::prelude::*;
use esp_idf_hal::can;

fn main() {
    esp_idf_sys::link_patches();
    // Bind the log crate to the ESP Logging facilities
    esp_idf_svc::log::EspLogger::initialize_default();

    info!("Hello, world!");

    let peripherals = Peripherals::take().unwrap();
    let pins = peripherals.pins;

    let filter = can::config::Filter::standard_allow_all();

    let timing = can::config::Timing::B1M;
    let config = can::config::Config::new().filter(filter).timing(timing);

    let mut can = can::CanDriver::new(peripherals.can, pins.gpio27, pins.gpio26, &config).unwrap();
    
    let timeout = 1000;
    if let Ok(rx_frame) = nb::block!(can.receive(timeout)) {
        info!("rx {:}:", rx_frame);
    }
}

Error:

33 |     if let Ok(rx_frame) = nb::block!(can.receive(timeout)) {
   |                           ^^^^^^^^^^^--------------------^
   |                           |          |
   |                           |          this expression has type `Result<esp_idf_hal::can::Frame, EspError>`
   |                           expected `EspError`, found `Error<_>`
   |
   = note: expected struct `EspError`
                found enum `nb::Error<_>`
   = note: this error originates in the macro `nb::block` (in Nightly builds, run with -Z macro-backtrace for more info)

When I change calling receive method:

    if let Ok(rx_frame) = nb::block!(can.receive()) {
        info!("rx {:}:", rx_frame);
    }

Error:

567 |     pub fn receive(&mut self, timeout: TickType_t) -> Result<Frame, EspError> {
    |            ^^^^^^^
help: provide the argument
    |
28  |     if let Ok(rx_frame) = nb::block!(can.receive(/* u32 */)) {
    |                                                 ~~~~~~~~~~~

error[E0308]: mismatched types
  --> src/main.rs:28:27
   |
28 |     if let Ok(rx_frame) = nb::block!(can.receive()) {
   |                           ^^^^^^^^^^^-------------^
   |                           |          |
   |                           |          this expression has type `Result<esp_idf_hal::can::Frame, EspError>`
   |                           expected `EspError`, found `Error<_>`
   |
   = note: expected struct `EspError`
                found enum `nb::Error<_>`
   = note: this error originates in the macro `nb::block` (in Nightly builds, run with -Z macro-backtrace for more info)

@ivmarkov
Copy link
Collaborator

ivmarkov commented Oct 1, 2023

TL;DR: Remove the nb_block! macros from the code.

Long story: you are mis-interpreting the example. The example calls transmit/receive via the e-hal traits, and there you need nb_block!. You are however calling the transmit/receive esp-idf-hal-specific API, which does not need nb_block! (and takes a timeout parameter).

@ivmarkov ivmarkov closed this as completed Oct 1, 2023
@hanusek
Copy link
Author

hanusek commented Oct 2, 2023

Thanks for your reply. It worked on Friday - code below.

fn main() {
    // It is necessary to call this function once. Otherwise some patches to the runtime
    // implemented by esp-idf-sys might not link properly. See https://github.com/esp-rs/esp-idf-template/issues/71
    esp_idf_sys::link_patches();
    esp_idf_svc::log::EspLogger::initialize_default();

    info!("Hello, world!");

    let peripherals = Peripherals::take().unwrap();
    let pins = peripherals.pins;

    let filter = can::config::Filter::standard_allow_all();

    let timing = can::config::Timing::B1M;
    let config = can::config::Config::new().filter(filter).timing(timing);

    let mut can = can::CanDriver::new(peripherals.can, pins.gpio27, pins.gpio26, &config).unwrap();
   
    loop {
        if let Ok(rx_frame) =  can.receive(1000) {
            info!("rx {:}:", rx_frame);
        }
    }
}

@jobafr
Copy link

jobafr commented Nov 6, 2023

I ran into this as well and figured it out by explicitly specifying I want the trait method, thus opting into the nonblocking API.

    nb::block!(embedded_can::nb::Can::transmit(&mut can, &tx_frame)).unwrap();

    if let Ok(rx_frame) = nb::block!(embedded_can::nb::Can::receive(&mut can)) {
        log::info!("rx {:}:", rx_frame);
    }

As it stands, the documented "hello world" example for this crate seems to be broken :/

@ivmarkov
Copy link
Collaborator

ivmarkov commented Nov 6, 2023

I ran into this as well and figured it out by explicitly specifying I want the trait method, thus opting into the nonblocking API.

    nb::block!(embedded_can::nb::Can::transmit(&mut can, &tx_frame)).unwrap();

    if let Ok(rx_frame) = nb::block!(embedded_can::nb::Can::receive(&mut can)) {
        log::info!("rx {:}:", rx_frame);
    }

As it stands, the documented "hello world" example for this crate seems to be broken :/

Would you clarify what exactly is broken w.r.t. the documented "hello world" example?

@jobafr
Copy link

jobafr commented Nov 23, 2023

I copied the example from the crate documentation and added fn main so it looks like this:

use embedded_can::nb::Can;
use embedded_can::Frame;
use embedded_can::StandardId;
use esp_idf_hal::can;
use esp_idf_hal::prelude::*;

fn main() {
    let peripherals = Peripherals::take().unwrap();
    let pins = peripherals.pins;

    // filter to accept only CAN ID 881
    let filter = can::config::Filter::Standard {
        filter: 881,
        mask: 0x7FF,
    };
    // filter that accepts all CAN IDs
    // let filter = can::config::Filter::standard_allow_all();

    let timing = can::config::Timing::B500K;
    let config = can::config::Config::new().filter(filter).timing(timing);
    let mut can = can::CanDriver::new(peripherals.can, pins.gpio5, pins.gpio4, &config).unwrap();

    let tx_frame =
        can::Frame::new(StandardId::new(0x042).unwrap(), &[0, 1, 2, 3, 4, 5, 6, 7]).unwrap();
    nb::block!(can.transmit(&tx_frame)).unwrap();

    if let Ok(rx_frame) = nb::block!(can.receive()) {
        info!("rx {:}:", rx_frame);
    }
}

Then I ran cargo check and got:

   Compiling my-project v0.1.0 (/home/me/my-project)
error: cannot find macro `info` in this scope
  --> src/main.rs:28:9
   |
28 |         info!("rx {:}:", rx_frame);
   |         ^^^^
   |
help: consider importing this macro
   |
1  + use log::info;
   |

error[E0061]: this function takes 3 arguments but 2 arguments were supplied
   --> src/main.rs:24:9
    |
24  |         can::Frame::new(StandardId::new(0x042).unwrap(), &[0, 1, 2, 3, 4, 5, 6, 7]).unwrap();
    |         ^^^^^^^^^^^^^^^ -------------------------------  ------------------------- an argument of type `bool` is missing
    |                         |
    |                         expected `u32`, found `StandardId`
    |
note: associated function defined here
   --> /home/me/.cargo/registry/src/index.crates.io-6f17d22bba15001f/esp-idf-hal-0.42.4/src/can.rs:727:12
    |
727 |     pub fn new(id: u32, extended: bool, data: &[u8]) -> Option<Self> {
    |            ^^^
help: provide the argument
    |
24  |         can::Frame::new(/* u32 */, /* bool */, &[0, 1, 2, 3, 4, 5, 6, 7]).unwrap();
    |                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

error[E0061]: this method takes 2 arguments but 1 argument was supplied
   --> src/main.rs:25:20
    |
25  |     nb::block!(can.transmit(&tx_frame)).unwrap();
    |                    ^^^^^^^^----------- an argument of type `u32` is missing
    |
note: method defined here
   --> /home/me/.cargo/registry/src/index.crates.io-6f17d22bba15001f/esp-idf-hal-0.42.4/src/can.rs:444:12
    |
444 |     pub fn transmit(&self, frame: &Frame, timeout: TickType_t) -> Result<(), EspError> {
    |            ^^^^^^^^
help: provide the argument
    |
25  |     nb::block!(can.transmit(&tx_frame, /* u32 */)).unwrap();
    |                            ~~~~~~~~~~~~~~~~~~~~~~

error[E0308]: mismatched types
  --> src/main.rs:25:5
   |
25 |     nb::block!(can.transmit(&tx_frame)).unwrap();
   |     ^^^^^^^^^^^-----------------------^
   |     |          |
   |     |          this expression has type `Result<(), EspError>`
   |     expected `EspError`, found `Error<_>`
   |
   = note: expected struct `EspError`
                found enum `nb::Error<_>`
   = note: this error originates in the macro `nb::block` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0061]: this method takes 1 argument but 0 arguments were supplied
   --> src/main.rs:27:42
    |
27  |     if let Ok(rx_frame) = nb::block!(can.receive()) {
    |                                          ^^^^^^^-- an argument of type `u32` is missing
    |
note: method defined here
   --> /home/me/.cargo/registry/src/index.crates.io-6f17d22bba15001f/esp-idf-hal-0.42.4/src/can.rs:448:12
    |
448 |     pub fn receive(&self, timeout: TickType_t) -> Result<Frame, EspError> {
    |            ^^^^^^^
help: provide the argument
    |
27  |     if let Ok(rx_frame) = nb::block!(can.receive(/* u32 */)) {
    |                                                 ~~~~~~~~~~~

error[E0308]: mismatched types
  --> src/main.rs:27:27
   |
27 |     if let Ok(rx_frame) = nb::block!(can.receive()) {
   |                           ^^^^^^^^^^^-------------^
   |                           |          |
   |                           |          this expression has type `Result<esp_idf_hal::can::Frame, EspError>`
   |                           expected `EspError`, found `Error<_>`
   |
   = note: expected struct `EspError`
                found enum `nb::Error<_>`
   = note: this error originates in the macro `nb::block` (in Nightly builds, run with -Z macro-backtrace for more info)

warning: unused import: `embedded_can::Frame`
 --> src/main.rs:2:5
  |
2 | use embedded_can::Frame;
  |     ^^^^^^^^^^^^^^^^^^^
  |
  = note: `#[warn(unused_imports)]` on by default

warning: unused import: `embedded_can::nb::Can`
 --> src/main.rs:1:5
  |
1 | use embedded_can::nb::Can;
  |     ^^^^^^^^^^^^^^^^^^^^^

Some errors have detailed explanations: E0061, E0308.
For more information about an error, try `rustc --explain E0061`.
warning: `my-project` (bin "my-project") generated 2 warnings
error: could not compile `my-project` (bin "my-project") due to 8 previous errors; 2 warnings emitted

Dependencies:

[dependencies]
log = { version = "0.4", default-features = false }
esp-idf-svc = { version = "0.47.1", default-features = false }
embedded-can = "0.4.1"
esp-idf-hal = "0.42.4"
nb = "1.1.0"

@ivmarkov ivmarkov reopened this Nov 23, 2023
@ivmarkov
Copy link
Collaborator

I think what you are saying is that this doc example does not compile out of the box, as it went out of date. Because we don't run cargo test in CI.

Fair enough..

I've reopened the issue. Feel free to contribute a PR that fixes the example.

... and I hope you are not blocked by this. The example only needs a few minimal changes to compile.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Archived in project
Development

No branches or pull requests

3 participants