ivmarkov / rust-esp32-std-demo

Rust on ESP32 STD demo app. A demo STD binary crate for the ESP32[XX] and ESP-IDF, which connects to WiFi, Ethernet, drives a small HTTP server and draws on a LED screen.
Apache License 2.0
784 stars 105 forks source link

Question on periodic timer event_loop message #96

Closed enelson1001 closed 2 years ago

enelson1001 commented 2 years ago

I am new to rust. I am trying to retrieve the event_loop_message data outside the subscribe closure. Is there a way to do this? I can't use view_manager inside the closure as it take ownership and I need to use view_manger later.

This is what I have so far in main.rs. The "????" is how do I get the Bme280ReadMessage data outside the bme280_read_event_loop.subscribe closure.


info!("About to start a bme280 read event loop");
    let mut bme280_read_event_loop = EspBackgroundEventLoop::new(&Default::default()).unwrap();

    info!("About to subscribe to the background event loop");
    let bme280_read_subscription =
        bme280_read_event_loop.subscribe(move |message: &Bme280ReadMessage| {
            info!("Got bme280 read message");
        });

    let bme280_read_subscription = match bme280_read_subscription {
        Ok(EspSubscription) => {
            let bme280_values = ??????????????????????????????????????????????????????????????
            view_manager
                .set_temperature_text((bme280_values.0 * 1.8) as i16 + 32)
                .unwrap();
            view_manager.set_humidity_text(bme280_values.1 as u8).unwrap();
            view_manager
                .set_pressure_text(bme280_values.2 * 0.00029529983071445)
                .unwrap();
        }
        Err(e) => panic!("Error {}", e),
    };

    info!("About to schedule a bme280 read periodic timer every one seconds");
    let mut bme280_read_periodic_timer = EspTimerService::new()
        .unwrap()
        .timer(move || {
            info!("Tick from periodic timer");
            let measurements = i2c_bme280.measure(&mut delay).unwrap();
            bme280_read_event_loop
                .post(
                    &Bme280ReadMessage::new(
                        measurements.temperature,
                        measurements.humidity,
                        measurements.pressure,
                    ),
                    None,
                )
                .unwrap();
        })
        .unwrap();

    bme280_read_periodic_timer
        .every(Duration::from_secs(5))
        .unwrap();

#[derive(Copy, Clone, Debug)]
pub struct Bme280ReadMessage(pub f32, pub f32, pub f32);

impl Bme280ReadMessage {
    pub fn new(temperature: f32, humidity: f32, pressure: f32) -> Self {
        Self(temperature, humidity, pressure)
    }
}

impl EspTypedEventSource for Bme280ReadMessage {
    fn source() -> *const c_types::c_char {
        b"BME280 READ TIMER SERVICE\0".as_ptr() as *const _
    }
}

impl EspTypedEventSerializer<Bme280ReadMessage> for Bme280ReadMessage {
    fn serialize<R>(
        event: &Bme280ReadMessage,
        f: impl for<'a> FnOnce(&'a EspEventPostData) -> R,
    ) -> R {
        f(&unsafe { EspEventPostData::new(Self::source(), Self::event_id(), event) })
    }
}

impl EspTypedEventDeserializer<Bme280ReadMessage> for Bme280ReadMessage {
    fn deserialize<R>(
        data: &EspEventFetchData,
        f: &mut impl for<'a> FnMut(&'a Bme280ReadMessage) -> R,
    ) -> R {
        f(unsafe { data.as_payload() })
    }
}
ivmarkov commented 2 years ago

You have to wrap your view manager in a STD Arc<Mutex<ViewManager>>. Once you do this, you can clone it and then send the clones to other threads, where you can safely lock the manager due to the mutex and then call methods on the manager. Alternatively, you should make the view manager itself Sync Send and Clone but thats more complex for a beginner. Regardless, it would be beneficial for you if you read about Send and Sync in Rust, as these concepts are key for the language.

If it is not clear, both the timer closure and the event loop closure are executed in separate threads.

Other points:

These questions btw beling to the Matrix channel. Youll get faster reaction there from many contributors. :)