Infer return type in function header

Dear all,

I'm writing some embedded application using the Decawave DW3000 and an STM32l476 Nucleo.

Now I want to wrap the initialization of the DWM3000 in a function, that looks like this:

#![no_std]
#![no_main]

use core::cell::RefCell;
use embassy_embedded_hal::shared_bus::blocking::spi::SpiDevice;
use embassy_executor::Spawner;
use embassy_stm32::exti::ExtiInput;
use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
use embassy_stm32::spi::Spi;
use embassy_sync::blocking_mutex::NoopMutex;
use embassy_time::{Duration, Timer};

use dw3000_ng::{self, block, DW3000};

use {defmt_rtt as _, panic_probe as _};

async fn init_dw3000(p: embassy_stm32::Peripherals) -> _{
    // SPI Device
    let mut dw_spi_config = embassy_stm32::spi::Config::default();
    //dw_spi_config.frequency = Hertz(16_000_000);
    let dw_spi = Spi::new(
        p.SPI1,
        p.PA5,
        p.PA7,
        p.PA6,
        p.DMA1_CH1,
        p.DMA1_CH2,
        dw_spi_config,
    );
    let dw_cs = Output::new(p.PB6, Level::High, Speed::VeryHigh);
    let dw_spi = NoopMutex::new(RefCell::new(dw_spi));
    let dw_spi_device = SpiDevice::new(&dw_spi, dw_cs);

    // Other pins
    let mut dw_rst = Output::new(p.PA8, Level::High, Speed::VeryHigh);
    let dw_int = Input::new(p.PA9, Pull::None);
    let mut dw_int = ExtiInput::new(dw_int, p.EXTI9);


    // Reset DW3000
    dw_rst.set_low();
    Timer::after(Duration::from_millis(10)).await;
    dw_rst.set_high();
    defmt::info!("DW3000 Reset!");

    let dw_config = dw3000_ng::Config::default();

    let mut dw3000 = dw3000_ng::DW3000::new(dw_spi_device)
        .init().unwrap()
        .config(dw_config).unwrap();

    defmt::info!("DW3000 Setup!");

    dw3000
        .gpio_config(dw3000_ng::hl::ConfigGPIOs::enable_led())
        .unwrap();
    dw3000
        .ll()
        .led_ctrl()
        .modify(|_, w| w.blink_tim(0x2))
        .unwrap();

    Timer::after(Duration::from_millis(200)).await;

    // Disable SPIRDY interrupt
    dw3000.disable_interrupts().unwrap();

    dw3000.enable_tx_interrupts().unwrap();
    dw3000.enable_rx_interrupts().unwrap();


    return dw3000;
}

Can someone help me with the return type of the function (the unwraps will be handled later, first I just need the type of the dw3000).

For reference, this is are my dependencies in Cargo.toml:

[dependencies]
defmt = "0.3"
defmt-rtt = "0.4"
panic-probe = { version = "0.3", features = ["print-defmt"] }

embedded-hal = "1.0.0"
embedded-hal-async = "1.0.0"
embedded-io = "0.6.1"
embedded-io-async = "0.6.1"
embedded-storage = "0.3.1"

cortex-m-rt = "0.7.3"

embassy-executor = { version = "0.5.0", features = ["task-arena-size-1024", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers", "executor-interrupt"] }
embassy-sync = { version = "0.5.0" }
embassy-time = { version = "0.3.0", features = ["defmt", "defmt-timestamp-uptime"] }

cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
embassy-stm32 = { version = "0.1.0", features = ["defmt", "stm32l476rg", "unstable-pac", "memory-x", "time-driver-any", "exti" ]  }

embassy-embedded-hal = { version = "0.1", features = ["defmt"] }
dw3000-ng = "0.8.1"

You're calling config followed by unwrap. The config signature is:

pub fn config(self, config: Config) -> Result<DW3000<SPI, Ready>, Error<SPI>>

The unwrap methd returns the type in the Success part of Result<Success, Error>, which is DW3000<SPI, Ready>.

Since you return dw3000 and it is not shadowed after the initial let (there is no other let dw3000 = ...) then the type must be DW3000<SPI, Ready>. The type of a variable cannot be changed by calling its methods.

Other ways to find out are:

  • Your IDE may have a way to show variable types.
  • You can leave off the fn return type (defaulting to '()') and check the error when you compile. The error should tell you the two types (actual and defined) .

While this is true, SPI is not a concrete type but instead a generic argument. Following the call backward you can see it is the type of dw_spi_device, which in turn was created SpiDevice::new, which however takes 3 other generic arguments. You could probably use rust-analyzer or even try compiling this code leaving the _ in the signature and see if the compiler suggest something. If that doesn't work I would use an opaque type, e.g. DW3000<impl embedded_hal::spi::SpiDevice<u8>, Ready>

1 Like

Oh, right. Thanks for the correction.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.