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) } } } }