3

I am working with the DHT11 library where the argument gpio, based on the esp32 implementation, for new must implement InputPin and OutputPin. So I created a function that returns a traitobject of a supertrait of those two traits. But when I want to dereference it to actually call new, I get the error doesn't have a size known at compile-time.

This is the supertrait I made from the above mentioned traits:

trait InputOutputPin: InputPin<Error = EspError> + OutputPin<Error = EspError> {}
impl<T: InputPin<Error = EspError> + OutputPin<Error = EspError>> InputOutputPin for T {}

This is the function that creates an gpio based on which pin number is given:

    fn get_gpio(pin: &u8) -> Result<&dyn InputOutputPin, &'static str>{
        match pin {
            33 => Ok(&Peripherals::take().unwrap().pins.gpio33.into_input_output().unwrap()),
            32 => Ok(&Peripherals::take().unwrap().pins.gpio32.into_input_output().unwrap()),
            27 => Ok(&Peripherals::take().unwrap().pins.gpio27.into_input_output().unwrap()),
            26 => Ok(&Peripherals::take().unwrap().pins.gpio26.into_input_output().unwrap()),
            25 => Ok(&Peripherals::take().unwrap().pins.gpio25.into_input_output().unwrap()),
            _ => Err("Pin not configurable for dht")
        }
    }

And this is how I assign the result from the function:

let gpio = Self::get_gpio(pin).unwrap();
let dht = Dht11::new(*gpio);

All I want to do is create a DHT11 object based on what pin number was chosen, but the esp32 library implements every gpio as its own struct by using a makro. What am I missing or is there a obvious, much better way of doing it.

elhe
  • 122
  • 10
  • As this seems to go stale, I`ll add my workaround for now. I combined the creation of the dht11 object with the pin selection in one function. This is not clean and creates redundancy, but this eliminated the need for the supertrait. I am open to better suggestions: For reference: [This commit](https://github.com/elheck/plantrs/commit/8b73c116350e42ed20b111dffd1a30d15844fece) – elhe Oct 12 '22 at 14:46

2 Answers2

1

Use Box for this. Example:

impl InputOutputPin for Box<dyn InputOutputPin> {}

and change the function from

 fn get_gpio(pin: &u8) -> Result<&dyn InputOutputPin, &'static str> {..}

to

fn get_gpio(pin: &u8) -> Result<Box<dyn InputOutputPin>, &'static str> {...}

Then this will work without problems:

let gpio = Self::get_gpio(pin).unwrap();
let dht = Dht11::new(*gpio);
Danila
  • 53
  • 6
  • The ESP32 is a microcontroller, and there's a good chance the OP (or future askers of questions like this) is working in a no_std environment without an allocator. Is there an alternative solution that doesn't involve a Box? – effect Oct 14 '22 at 16:18
  • @effect, you can do it like this ```impl InputOutputPin for &dyn InputOutputPin {} ``` or ```impl InputOutputPin for &mut dyn InputOutputPin {} ``` – Danila Oct 14 '22 at 16:30
  • Won't they still have the issue of not being able to return an `&dyn InputOutputPin` because the size isn't known at compile time? I don't see how those impl changes removes the need for a Box. – effect Oct 14 '22 at 16:34
  • 1
    @effect, the problem with the size occurs only when dereferencing ```let dht = Dht11::new(*gpio);``` and this implementation allows you not to dereference, but to pass the link directly ```let dht = Dht11::new(gpio);``` where ```gpio``` has type ```&dyn InputOutputPin``` – Danila Oct 14 '22 at 16:44
1

The ESP32 HAL has a degrade method for GPIO pins which erases the pin-specific typing so you don't need to use your dyn supertrait.

The modified code would like more like this:

fn get_gpio(pin: &u8) -> Result<GpioPin<InputOutput>, &'static str>{
        match pin {
            33 => Ok(&Peripherals::take().unwrap().pins.gpio33.into_input_output().unwrap().degrade()),
            32 => Ok(&Peripherals::take().unwrap().pins.gpio32.into_input_output().unwrap().degrade()),
            27 => Ok(&Peripherals::take().unwrap().pins.gpio27.into_input_output().unwrap().degrade()),
            26 => Ok(&Peripherals::take().unwrap().pins.gpio26.into_input_output().unwrap().degrade()),
            25 => Ok(&Peripherals::take().unwrap().pins.gpio25.into_input_output().unwrap().degrade()),
            _ => Err("Pin not configurable for dht")
        }
    }
effect
  • 1,279
  • 6
  • 13
  • @Danila's answer is correct for the general case of working with supertraits, however I think this answer is better suited for the OP's specific situation. – effect Oct 14 '22 at 16:29
  • Ok I hadn't seen the degrade method. This solves my problem most adequately. Thanks – elhe Oct 15 '22 at 19:42