      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
     15
     16
     17
     18
     19
     20
     21
     22
     23
     24
     25
     26
     27
     28
     29
     30
     31
     32
     33
     34
     35
     36
     37
     38
     39
     40
     41
     42
     43
     44
     45
     46
     47
     48
     49
     50
     51
     52
     53
     54
     55
     56
     57
     58
     59
     60
     61
     62
     63
     64
     65
     66
     67
     68
     69
     70
     71
     72
     73
     74
     75
     76
     77
     78
     79
     80
     81
     82
     83
     84
     85
     86
     87
     88
     89
     90
     91
     92
     93
     94
     95
     96
     97
     98
     99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127

    /*
     * Licensed to the Apache Software Foundation (ASF) under one
     * or more contributor license agreements.  See the NOTICE file
     * distributed with this work for additional information
     * regarding copyright ownership.  The ASF licenses this file
     * to you under the Apache License, Version 2.0 (the
     * "License"); you may not use this file except in compliance
     * with the License.  You may obtain a copy of the License at
     *
     *  http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing,
     * software distributed under the License is distributed on an
     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
     * KIND, either express or implied.  See the License for the
     * specific language governing permissions and limitations
     * under the License.
     */
    //!  Poll the temperature sensor every 10 seconds. Transmit the sensor data to the CoAP server after polling.
    //!  This is the Rust version of https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/rust-nbiot/apps/my_sensor_app/OLDsrc/sensor.c

    use mynewt::{
        result::*,                              //  Import Mynewt API Result and Error types
        hw::sensor::{
            self,                               //  Import Mynewt Sensor API functions
            sensor_ptr,                         //  Import Mynewt Sensor API types
            sensor_arg, sensor_data_ptr, sensor_listener,
            sensor_temp_raw_data, sensor_type_t,
            SensorValue, SensorValueType,
        },
        sys::console,                           //  Import Mynewt Console API
        fill_zero, Strn,                        //  Import Mynewt macros
    };
    use mynewt_macros::{ init_strn };           //  Import Mynewt procedural macros
    use crate::app_network::send_sensor_data;   //  Import `app_network.rs` for sending sensor data

    ///  Sensor to be polled: `temp_stm32_0` is Blue Pill's internal temperature sensor
    static SENSOR_DEVICE: Strn      = init_strn!("temp_stm32_0");
    ///  Poll sensor every 10,000 milliseconds (10 seconds)
    const SENSOR_POLL_TIME: u32     = (10 * 1000);
    ///  Use key (field name) `t` to transmit raw temperature to CoAP Server
    const TEMP_SENSOR_KEY: &str     = "t";
    ///  Type of sensor: Raw temperature sensor (integer sensor values 0 to 4095)
    const TEMP_SENSOR_TYPE: sensor_type_t = sensor::SENSOR_TYPE_AMBIENT_TEMPERATURE_RAW;

    ///  Ask Mynewt to poll the temperature sensor every 10 seconds and call `handle_sensor_data()`.
    ///  Return `Ok()` if successful, else return `Err()` with `MynewtError` error code inside.
    pub fn start_sensor_listener() -> MynewtResult<()>  {  //  Returns an error code upon error.
        console::print("Rust TMP poll\n");

        //  Set the sensor polling time to 10 seconds.  SENSOR_DEVICE is "temp_stm32_0", SENSOR_POLL_TIME is 10,000.
        sensor::set_poll_rate_ms(&SENSOR_DEVICE, SENSOR_POLL_TIME) ? ;

        //  Fetch the sensor by name, without locking the driver for exclusive access.
        let sensor = sensor::mgr_find_next_bydevname(&SENSOR_DEVICE, core::ptr::null_mut()) ? ;
        assert!(!sensor.is_null(), "no sensor");

        //  Define the listener function to be called after polling the temperature sensor.
        let listener = sensor_listener {
            sl_sensor_type: TEMP_SENSOR_TYPE,       //  Type of sensor: ambient temperature
            sl_func       : sensor::as_untyped(handle_sensor_data),  //  Listener function
            ..fill_zero!(sensor_listener)           //  Set other fields to 0
        };

        //  Register the Listener Function to be called every 10 seconds, with the polled sensor data.
        sensor::register_listener(sensor, listener) ? ;  //  `?` means in case of error, return error now.

        //  Return `Ok()` to indicate success.  This line should not end with a semicolon (;).
        Ok(())
    }

    ///  This listener function is called every 10 seconds by Mynewt to handle the polled sensor data.
    ///  Return 0 if we have handled the sensor data successfully.
    extern fn handle_sensor_data(sensor: sensor_ptr, _arg: sensor_arg,
        sensor_data: sensor_data_ptr, sensor_type: sensor_type_t) -> MynewtError {
        console::print("Rust handle_sensor_data\n");

        //  Check that the temperature data is valid.
        if sensor_data.is_null() { return MynewtError::SYS_EINVAL; }  //  Exit if data is missing
        assert!(!sensor.is_null(), "null sensor");

        //  Get the temperature sensor value. It could be raw or computed.
        let sensor_value = convert_sensor_data(sensor_data, sensor_type);
        if let SensorValueType::None = sensor_value.val { assert!(false, "bad type"); }

        //  Compose a CoAP message with the temperature sensor data and send to the
        //  CoAP server.  The message will be enqueued for transmission by the OIC
        //  background task so this function will return without waiting for the message
        //  to be transmitted.
        let res = send_sensor_data(&sensor_value);

        //  `SYS_EAGAIN` means that the Network Task is still starting up the network.
        //  We drop the sensor data and send at the next poll.
        if let Err(err) = res {  //  `if let` will assign `err` to the error code inside `res`
            if err == MynewtError::SYS_EAGAIN {
                console::print("TMP network not ready\n");
                return MynewtError::SYS_EOK;
            }
        }
        //  Return 0 to Mynewt to indicate no error.  Should not end with a semicolon (;).
        MynewtError::SYS_EOK
    }

    ///  Convert the raw temperature value received from Mynewt into a `SensorValue` for transmission, which includes the sensor data key `t`.
    ///  `sensor_type` indicates the type of data in `sensor_data`.
    #[allow(non_snake_case, unused_variables)]
    fn convert_sensor_data(sensor_data: sensor_data_ptr, sensor_type: sensor_type_t) -> SensorValue {
        console::print("TMP listener got rawtmp\n");
        //  Construct and return a new `SensorValue` (without semicolon)
        SensorValue {
            key: TEMP_SENSOR_KEY,  //  Sensor data key is `t`
            val: match sensor_type {
                SENSOR_TYPE_AMBIENT_TEMPERATURE_RAW => {  //  If this is raw temperature...
                    //  Interpret the sensor data as a `sensor_temp_raw_data` struct that contains raw temp.
                    let mut rawtempdata = fill_zero!(sensor_temp_raw_data);
                    let rc = unsafe { sensor::get_temp_raw_data(sensor_data, &mut rawtempdata) };
                    assert_eq!(rc, 0, "rawtmp fail");
                    //  Check that the raw temperature data is valid.
                    assert_ne!(rawtempdata.strd_temp_raw_is_valid, 0, "bad rawtmp");
                    //  Raw temperature data is valid.  Return it.
                    SensorValueType::Uint(rawtempdata.strd_temp_raw)  //  Raw Temperature in integer (0 to 4095)
                }
                //  Unknown type of sensor value
                //  _ => { assert!(false, "sensor type"); SensorValueType::Uint(0) }
            }
        }
    }

# Help

## Keyboard Shortcuts

`?`
  Show this help dialog
`S`
  Focus the search field
`↑`
  Move up in search results
`↓`
  Move down in search results
`↹`
  Switch tab
`⏎`
  Go to active search result
`+`
  Expand all sections
`-`
  Collapse all sections

## Search Tricks

Prefix searches with a type followed by a colon (e.g., `fn:`) to restrict the search to a given type.

Accepted types are: `fn`, `mod`, `struct`, `enum`, `trait`, `type`, `macro`, and `const`.

Search functions by type signature (e.g., `vec -> usize` or `* -> vec`)

Search multiple things at once by splitting your query with comma (e.g., `str,u8` or `String,struct:Vec,test`)