diff --git a/src/devices/Bmxx80/Bme280.cs b/src/devices/Bmxx80/Bme280.cs
index dfe195e0ee..047112c2e6 100644
--- a/src/devices/Bmxx80/Bme280.cs
+++ b/src/devices/Bmxx80/Bme280.cs
@@ -2,10 +2,9 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System;
using System.Device.I2c;
-using System.Threading.Tasks;
using Iot.Device.Bmxx80.CalibrationData;
-using Iot.Device.Bmxx80.PowerMode;
using Iot.Device.Bmxx80.Register;
namespace Iot.Device.Bmxx80
@@ -13,7 +12,7 @@ namespace Iot.Device.Bmxx80
///
/// Represents a BME280 temperature, barometric pressure and humidity sensor.
///
- public class Bme280 : Bmx280Base
+ public sealed class Bme280 : Bmx280Base
{
///
/// The expected chip ID of the BME280.
@@ -23,7 +22,9 @@ public class Bme280 : Bmx280Base
///
/// Calibration data for the .
///
- private readonly Bme280CalibrationData _bme280Calibration;
+ private Bme280CalibrationData _bme280Calibration;
+
+ private Sampling _humiditySampling;
///
/// Initializes a new instance of the class.
@@ -32,62 +33,79 @@ public class Bme280 : Bmx280Base
public Bme280(I2cDevice i2cDevice)
: base(DeviceId, i2cDevice)
{
- var bme280CalibrationData = new Bme280CalibrationData();
- bme280CalibrationData.ReadFromDevice(this);
- _bme280Calibration = bme280CalibrationData;
- _calibrationData = bme280CalibrationData;
-
+ _bme280Calibration = (Bme280CalibrationData)_calibrationData;
_communicationProtocol = CommunicationProtocol.I2c;
}
///
- /// Get the current sample rate for humidity measurements.
+ /// Gets or sets the humidity sampling.
///
- /// The humidity .
- public Sampling ReadHumiditySampling()
+ /// Thrown when the is set to an undefined mode.
+ public Sampling HumiditySampling
{
- byte status = Read8BitsFromRegister((byte)Bme280Register.CTRL_HUM);
- status = (byte)(status & 0b_0000_0111);
- return ByteToSampling(status);
+ get => _humiditySampling;
+ set
+ {
+ if (!Enum.IsDefined(typeof(Sampling), value))
+ throw new ArgumentOutOfRangeException();
+
+ byte status = Read8BitsFromRegister((byte)Bme280Register.CTRL_HUM);
+ status = (byte)(status & 0b_1111_1000);
+ status = (byte)(status | (byte)value);
+
+ Span command = stackalloc[] {(byte)Bme280Register.CTRL_HUM, status};
+ _i2cDevice.Write(command);
+
+ // Changes to the above register only become effective after a write operation to "CTRL_MEAS".
+ byte measureState = Read8BitsFromRegister((byte)Bmx280Register.CTRL_MEAS);
+
+ command = stackalloc[] {(byte)Bmx280Register.CTRL_MEAS, measureState};
+ _i2cDevice.Write(command);
+ _humiditySampling = value;
+ }
}
///
- /// Sets the humidity sampling to the given value.
+ /// Reads the humidity. A return value indicates whether the reading succeeded.
///
- /// The to set.
- public void SetHumiditySampling(Sampling sampling)
+ ///
+ /// Contains the measured humidity as %rH if the was not set to .
+ /// Contains otherwise.
+ ///
+ /// true
if measurement was not skipped, otherwise false
.
+ public bool TryReadHumidity(out double humidity)
{
- byte status = Read8BitsFromRegister((byte)Bme280Register.CTRL_HUM);
- status = (byte)(status & 0b_1111_1000);
- status = (byte)(status | (byte)sampling);
- _i2cDevice.Write(new[] { (byte)Bme280Register.CTRL_HUM, status });
-
- // Changes to the above register only become effective after a write operation to "CTRL_MEAS".
- byte measureState = Read8BitsFromRegister((byte)Bmx280Register.CTRL_MEAS);
- _i2cDevice.Write(new[] { (byte)Bmx280Register.CTRL_MEAS, measureState });
+ if (HumiditySampling == Sampling.Skipped)
+ {
+ humidity = double.NaN;
+ return false;
+ }
+
+ // Read the temperature first to load the t_fine value for compensation.
+ TryReadTemperature(out _);
+
+ var hum = Read16BitsFromRegister((byte)Bme280Register.HUMIDDATA, Endianness.BigEndian);
+
+ humidity = CompensateHumidity(hum);
+ return true;
}
///
- /// Reads the Humidity from the sensor as %rH.
+ /// Gets the required time in ms to perform a measurement with the current sampling modes.
///
- /// Returns a percentage from 0 to 100.
- public async Task ReadHumidityAsync()
+ /// The time it takes for the chip to read data in milliseconds rounded up.
+ public override int GetMeasurementDuration()
{
- if (ReadPowerMode() == Bmx280PowerMode.Forced)
- {
- await Task.Delay(GetMeasurementTimeForForcedMode(ReadHumiditySampling()));
- }
-
- // Read the temperature first to load the t_fine value for compensation.
- await ReadTemperatureAsync();
-
- byte msb = Read8BitsFromRegister((byte)Bme280Register.HUMIDDATA_MSB);
- byte lsb = Read8BitsFromRegister((byte)Bme280Register.HUMIDDATA_LSB);
-
- // Combine the values into a 32-bit integer.
- int t = (msb << 8) | lsb;
+ return s_osToMeasCycles[(int)PressureSampling] + s_osToMeasCycles[(int)TemperatureSampling] + s_osToMeasCycles[(int)HumiditySampling];
+ }
- return CompensateHumidity(t);
+ ///
+ /// Sets the default configuration for the sensor.
+ ///
+ protected override void SetDefaultConfiguration()
+ {
+ base.SetDefaultConfiguration();
+ HumiditySampling = Sampling.UltraLowPower;
}
///
diff --git a/src/devices/Bmxx80/Bme680.cs b/src/devices/Bmxx80/Bme680.cs
index ce096f5dc5..6b22fda56a 100644
--- a/src/devices/Bmxx80/Bme680.cs
+++ b/src/devices/Bmxx80/Bme680.cs
@@ -3,9 +3,11 @@
// See the LICENSE file in the project root for more information.
using System;
+using System.Collections.Generic;
using System.Device.I2c;
-using System.Threading.Tasks;
+using System.Linq;
using Iot.Device.Bmxx80.CalibrationData;
+using Iot.Device.Bmxx80.FilteringMode;
using Iot.Device.Bmxx80.PowerMode;
using Iot.Device.Bmxx80.Register;
using Iot.Units;
@@ -15,7 +17,7 @@ namespace Iot.Device.Bmxx80
///
/// Represents a BME680 temperature, pressure, relative humidity and VOC gas sensor.
///
- public class Bme680 : Bmxx80Base
+ public sealed class Bme680 : Bmxx80Base
{
///
/// Default I2C bus address.
@@ -35,7 +37,23 @@ public class Bme680 : Bmxx80Base
///
/// Calibration data for the .
///
- private readonly Bme680CalibrationData _bme680Calibration;
+ private Bme680CalibrationData _bme680Calibration;
+
+ ///
+ protected override int _tempCalibrationFactor => 16;
+
+ private readonly List _heaterConfigs = new List();
+ private bool _gasConversionIsEnabled;
+ private bool _heaterIsEnabled;
+
+ private Bme680HeaterProfile _heaterProfile;
+ private Bme680FilteringMode _filterMode;
+ private Sampling _humiditySampling;
+
+ private static readonly byte[] s_osToMeasCycles = { 0, 1, 2, 4, 8, 16 };
+ private static readonly byte[] s_osToSwitchCount = { 0, 1, 1, 1, 1, 1 };
+ private static readonly double[] s_k1Lookup = { 0.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, -0.8, 0.0, 0.0, -0.2, -0.5, 0.0, -1.0, 0.0, 0.0 };
+ private static readonly double[] s_k2Lookup = { 0.0, 0.0, 0.0, 0.0, 0.1, 0.7, 0.0, -0.8, -0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
///
/// Initialize a new instance of the class.
@@ -44,132 +62,372 @@ public class Bme680 : Bmxx80Base
public Bme680(I2cDevice i2cDevice)
: base(DeviceId, i2cDevice)
{
- var bme680CalibrationData = new Bme680CalibrationData();
- bme680CalibrationData.ReadFromDevice(this);
- _bme680Calibration = bme680CalibrationData;
- _calibrationData = bme680CalibrationData;
-
_communicationProtocol = CommunicationProtocol.I2c;
- _controlRegister = (byte)Bme680Register.CTRL_MEAS;
}
///
- /// Set the humidity sampling.
+ /// Gets or sets the humidity sampling.
///
- /// The to set.
- public void SetHumiditySampling(Sampling sampling)
+ /// Thrown when the is set to an undefined mode.
+ public Sampling HumiditySampling
{
- var register = (byte)Bme680Register.CTRL_HUM;
- byte read = Read8BitsFromRegister(register);
+ get => _humiditySampling;
+ set
+ {
+ if (!Enum.IsDefined(typeof(Sampling), value))
+ throw new ArgumentOutOfRangeException();
- // Clear first 3 bits.
- var cleared = (byte)(read & 0b_1111_1000);
+ var status = Read8BitsFromRegister((byte)Bme680Register.CTRL_HUM);
+ status = (byte)((status & (byte)~Bme680Mask.HUMIDITY_SAMPLING) | (byte)value);
- _i2cDevice.Write(new[] { register, (byte)(cleared | (byte)sampling) });
+ Span command = stackalloc[] { (byte)Bme680Register.CTRL_HUM, status };
+ _i2cDevice.Write(command);
+ _humiditySampling = value;
+ }
}
///
- /// Sets the power mode to the given mode
+ /// Gets or sets the heater profile to be used for measurements.
+ /// Current heater profile is only set if the chosen profile is configured.
///
- /// The to set.
- public void SetPowerMode(Bme680PowerMode powerMode)
+ /// Thrown when the is set to an undefined profile.
+ public Bme680HeaterProfile HeaterProfile
+ {
+ get => _heaterProfile;
+ set
+ {
+ if (_heaterConfigs.Exists(config => config.HeaterProfile == value))
+ {
+ if (!Enum.IsDefined(typeof(Bme680HeaterProfile), value))
+ throw new ArgumentOutOfRangeException();
+
+ var heaterProfile = Read8BitsFromRegister((byte)Bme680Register.CTRL_GAS_1);
+ heaterProfile = (byte)((heaterProfile & (byte)~Bme680Mask.NB_CONV) | (byte)value);
+
+ Span command = stackalloc[] { (byte)Bme680Register.CTRL_GAS_1, heaterProfile };
+ _i2cDevice.Write(command);
+ _heaterProfile = value;
+ }
+ }
+ }
+
+ ///
+ /// Gets or sets the filtering mode to be used for measurements.
+ ///
+ /// Thrown when the is set to an undefined mode.
+ public Bme680FilteringMode FilterMode
{
- byte read = Read8BitsFromRegister(_controlRegister);
+ get => _filterMode;
+ set
+ {
+ if (!Enum.IsDefined(typeof(Bme680FilteringMode), value))
+ throw new ArgumentOutOfRangeException();
- // Clear first 2 bits.
- var cleared = (byte)(read & 0b_1111_1100);
+ var filter = Read8BitsFromRegister((byte)Bme680Register.CONFIG);
+ filter = (byte)((filter & (byte)~Bme680Mask.FILTER_COEFFICIENT) | (byte)value << 2);
- _i2cDevice.Write(new[] { _controlRegister, (byte)(cleared | (byte)powerMode) });
+ Span command = stackalloc[] { (byte)Bme680Register.CONFIG, filter };
+ _i2cDevice.Write(command);
+ _filterMode = value;
+ }
}
///
- /// Read a value indicating whether or not new sensor data is available.
+ /// Gets or sets whether the heater is enabled.
///
- /// True if new data is available.
- public bool ReadHasNewData()
+ public bool HeaterIsEnabled
{
- byte read = Read8BitsFromRegister((byte)Bme680Register.STATUS);
+ get => _heaterIsEnabled;
+ set
+ {
+ var heaterStatus = Read8BitsFromRegister((byte)Bme680Register.CTRL_GAS_0);
+ heaterStatus = (byte)((heaterStatus & (byte)~Bme680Mask.HEAT_OFF) | Convert.ToByte(!value) << 3);
+
+ Span command = stackalloc[] { (byte)Bme680Register.CTRL_GAS_0, heaterStatus };
+ _i2cDevice.Write(command);
+ _heaterIsEnabled = value;
+ }
+ }
- // Get only the power mode bit.
- var hasNewData = (byte)(read & 0b_1000_0000);
+ ///
+ /// Gets or sets whether gas conversions are enabled.
+ ///
+ public bool GasConversionIsEnabled
+ {
+ get => _gasConversionIsEnabled;
+ set
+ {
+ var gasConversion = Read8BitsFromRegister((byte)Bme680Register.CTRL_GAS_1);
+ gasConversion = (byte)((gasConversion & (byte)~Bme680Mask.RUN_GAS) | Convert.ToByte(value) << 4);
- return (hasNewData >> 7) == 1;
+ Span command = stackalloc[] { (byte)Bme680Register.CTRL_GAS_1, gasConversion };
+ _i2cDevice.Write(command);
+ _gasConversionIsEnabled = value;
+ }
}
///
- /// Read the humidity.
+ /// Reads whether new data is available.
///
- /// Calculated humidity.
- public async Task ReadHumidityAsync()
+ public bool ReadNewDataIsAvailable()
{
- // Read humidity data.
- byte msb = Read8BitsFromRegister((byte)Bme680Register.HUMIDITYDATA_MSB);
- byte lsb = Read8BitsFromRegister((byte)Bme680Register.HUMIDITYDATA_LSB);
+ var newData = Read8BitsFromRegister((byte)Bme680Register.STATUS);
+ newData = (byte)(newData >> 7);
- // Convert to a 32bit integer.
- var adcHumidity = (msb << 8) + lsb;
+ return Convert.ToBoolean(newData);
+ }
- return CompensateHumidity((await ReadTemperatureAsync()).Celsius, adcHumidity);
+ ///
+ /// Reads whether a gas measurement is in process.
+ ///
+ public bool ReadGasMeasurementInProcess()
+ {
+ var gasMeasInProcess = Read8BitsFromRegister((byte)Bme680Register.STATUS);
+ gasMeasInProcess = (byte)((gasMeasInProcess & (byte)Bme680Mask.GAS_MEASURING) >> 6);
+
+ return Convert.ToBoolean(gasMeasInProcess);
+ }
+
+ ///
+ /// Reads whether a measurement of any kind is in process.
+ ///
+ public bool ReadMeasurementInProcess()
+ {
+ var measInProcess = Read8BitsFromRegister((byte)Bme680Register.STATUS);
+ measInProcess = (byte)((measInProcess & (byte)Bme680Mask.MEASURING) >> 5);
+
+ return Convert.ToBoolean(measInProcess);
+ }
+
+ ///
+ /// Reads whether the target heater temperature is reached.
+ ///
+ public bool ReadHeaterIsStable()
+ {
+ var heaterStable = Read8BitsFromRegister((byte)Bme680Register.GAS_RANGE);
+ heaterStable = (byte)((heaterStable & (byte)Bme680Mask.HEAT_STAB) >> 4);
+
+ return Convert.ToBoolean(heaterStable);
+ }
+
+ ///
+ /// Sets the power mode to the given mode
+ ///
+ /// The to set.
+ /// Thrown when the power mode does not match a defined mode in .
+ public void SetPowerMode(Bme680PowerMode powerMode)
+ {
+ if (!Enum.IsDefined(typeof(Bme680PowerMode), powerMode))
+ throw new ArgumentOutOfRangeException();
+
+ var status = Read8BitsFromRegister((byte)Bme680Register.CTRL_MEAS);
+ status = (byte)((status & (byte)~Bme680Mask.PWR_MODE) | (byte)powerMode);
+
+ Span command = stackalloc[] { (byte)Bme680Register.CTRL_MEAS, status };
+ _i2cDevice.Write(command);
+ }
+
+ ///
+ /// Configures a heater profile, making it ready for use.
+ ///
+ /// The to configure.
+ /// The target temperature in °C. Ranging from 0-400.
+ /// The duration in ms. Ranging from 0-4032.
+ /// The ambient temperature in °C.
+ /// Thrown when the heating profile does not match a defined profile in .
+ ///
+ public void ConfigureHeatingProfile(Bme680HeaterProfile profile, ushort targetTemperature, ushort duration, double ambientTemperature)
+ {
+ if (!Enum.IsDefined(typeof(Bme680HeaterProfile), profile))
+ throw new ArgumentOutOfRangeException();
+
+ // read ambient temperature for resistance calculation
+ var heaterResistance = CalculateHeaterResistance(targetTemperature, (short)ambientTemperature);
+ var heaterDuration = CalculateHeaterDuration(duration);
+
+ Span resistanceCommand = stackalloc[] { (byte)((byte)Bme680Register.RES_HEAT_0 + profile), heaterResistance };
+ Span durationCommand = stackalloc[] { (byte)((byte)Bme680Register.GAS_WAIT_0 + profile), heaterDuration };
+ _i2cDevice.Write(resistanceCommand);
+ _i2cDevice.Write(durationCommand);
+
+ // cache heater configuration
+ if (_heaterConfigs.Exists(config => config.HeaterProfile == profile))
+ _heaterConfigs.Remove(_heaterConfigs.Single(config => config.HeaterProfile == profile));
+ _heaterConfigs.Add(new Bme680HeaterProfileConfig(profile, heaterResistance, duration));
}
///
/// Read the state.
///
/// The current .
- /// Thrown when the power mode does not match a defined mode in .
public Bme680PowerMode ReadPowerMode()
{
- byte read = Read8BitsFromRegister(_controlRegister);
+ var status = Read8BitsFromRegister((byte)Bme680Register.CTRL_MEAS);
- return (Bme680PowerMode)(read & 0b_0000_0011);
+ return (Bme680PowerMode)(status & (byte)Bme680Mask.PWR_MODE);
}
///
- /// Read the pressure.
+ /// Gets the required time in ms to perform a measurement. The duration of the gas
+ /// measurement is not considered if is set to false
+ /// or the chosen is not configured.
+ /// The precision of this duration is within 1ms of the actual measurement time.
///
- /// Calculated pressure in Pa.
- public async Task ReadPressureAsync()
+ /// The used .
+ ///
+ public int GetMeasurementDuration(Bme680HeaterProfile profile)
{
- // Read pressure data.
- byte lsb = Read8BitsFromRegister((byte)Bme680Register.PRESSUREDATA_LSB);
- byte msb = Read8BitsFromRegister((byte)Bme680Register.PRESSUREDATA_MSB);
- byte xlsb = Read8BitsFromRegister((byte)Bme680Register.PRESSUREDATA_XLSB);
+ var measCycles = s_osToMeasCycles[(int)TemperatureSampling];
+ measCycles += s_osToMeasCycles[(int)PressureSampling];
+ measCycles += s_osToMeasCycles[(int)HumiditySampling];
+
+ var switchCount = s_osToSwitchCount[(int)TemperatureSampling];
+ switchCount += s_osToSwitchCount[(int)PressureSampling];
+ switchCount += s_osToSwitchCount[(int)HumiditySampling];
+
+ double measDuration = measCycles * 1963;
+ measDuration += 477 * switchCount; // TPH switching duration
+
+ if (GasConversionIsEnabled)
+ measDuration += 477 * 5; // Gas measurement duration
+ measDuration += 500; // get it to the closest whole number
+ measDuration /= 1000.0; // convert to ms
+ measDuration += 1; // wake up duration of 1ms
+
+ if (GasConversionIsEnabled && _heaterConfigs.Exists(config => config.HeaterProfile == profile))
+ measDuration += _heaterConfigs.Single(config => config.HeaterProfile == profile).HeaterDuration;
+
+ return (int)Math.Ceiling(measDuration);
+ }
+
+ ///
+ /// Reads the humidity. A return value indicates whether the reading succeeded.
+ ///
+ ///
+ /// Contains the measured humidity as %rH if the was not set to .
+ /// Contains otherwise.
+ ///
+ /// true
if measurement was not skipped, otherwise false
.
+ public bool TryReadHumidity(out double humidity)
+ {
+ if (HumiditySampling == Sampling.Skipped)
+ {
+ humidity = double.NaN;
+ return false;
+ }
+
+ // Read humidity data.
+ var hum = Read16BitsFromRegister((byte)Bme680Register.HUMIDITYDATA, Endianness.BigEndian);
+
+ TryReadTemperature(out _);
+ humidity = CompensateHumidity(hum);
+ return true;
+ }
+
+ ///
+ /// Reads the pressure. A return value indicates whether the reading succeeded.
+ ///
+ ///
+ /// Contains the measured pressure in Pa if the was not set to .
+ /// Contains otherwise.
+ ///
+ /// true
if measurement was not skipped, otherwise false
.
+ public override bool TryReadPressure(out double pressure)
+ {
+ if (PressureSampling == Sampling.Skipped)
+ {
+ pressure = double.NaN;
+ return false;
+ }
+
- // Convert to a 32bit integer.
- var adcPressure = (msb << 12) + (lsb << 4) + (xlsb >> 4);
+ // Read pressure data.
+ var press = (int)Read24BitsFromRegister((byte)Bme680Register.PRESSUREDATA, Endianness.BigEndian);
// Read the temperature first to load the t_fine value for compensation.
- await ReadTemperatureAsync();
+ TryReadTemperature(out _);
- return CompensatePressure(adcPressure);
+ pressure = CompensatePressure(press >> 4);
+ return true;
}
///
- /// Read the temperature.
+ /// Reads the temperature. A return value indicates whether the reading succeeded.
///
- /// Calculated temperature.
- public Task ReadTemperatureAsync()
+ ///
+ /// Contains the measured temperature if the was not set to .
+ /// Contains otherwise.
+ ///
+ /// true
if measurement was not skipped, otherwise false
.
+ public override bool TryReadTemperature(out Temperature temperature)
{
- // Read temperature data.
- byte lsb = Read8BitsFromRegister((byte)Bme680Register.TEMPDATA_LSB);
- byte msb = Read8BitsFromRegister((byte)Bme680Register.TEMPDATA_MSB);
- byte xlsb = Read8BitsFromRegister((byte)Bme680Register.TEMPDATA_XLSB);
+ if (TemperatureSampling == Sampling.Skipped)
+ {
+ temperature = Temperature.FromCelsius(double.NaN);
+ return false;
+ }
+
- // Convert to a 32bit integer.
- var adcTemperature = (msb << 12) + (lsb << 4) + (xlsb >> 4);
+ var temp = (int)Read24BitsFromRegister((byte)Bme680Register.TEMPDATA, Endianness.BigEndian);
- return Task.FromResult(CompensateTemperature(adcTemperature));
+ temperature = CompensateTemperature(temp >> 4);
+ return true;
+ }
+
+ ///
+ /// Reads the gas resistance. A return value indicates whether the reading succeeded.
+ ///
+ ///
+ /// Contains the measured gas resistance in Ohm if the heater module reached the target temperature and
+ /// the measurement was valid. Contains otherwise.
+ ///
+ /// true
if measurement was not skipped, otherwise false
.
+ public bool TryReadGasResistance(out double gasResistance)
+ {
+ if (!ReadGasMeasurementIsValid() || !ReadHeaterIsStable())
+ {
+ gasResistance = double.NaN;
+ return false;
+ }
+
+ // Read 10 bit gas resistance value from registers
+ var gasResRaw = Read8BitsFromRegister((byte)Bme680Register.GAS_RES);
+ var gasRange = Read8BitsFromRegister((byte)Bme680Register.GAS_RANGE);
+
+ var gasRes = (ushort)((ushort)(gasResRaw << 2) + (byte)(gasRange >> 6));
+ gasRange &= (byte)Bme680Mask.GAS_RANGE;
+
+ gasResistance = CalculateGasResistance(gasRes, gasRange);
+ return true;
+ }
+
+ ///
+ /// Sets the default configuration for the sensor.
+ ///
+ protected override void SetDefaultConfiguration()
+ {
+ base.SetDefaultConfiguration();
+ HumiditySampling = Sampling.UltraLowPower;
+ FilterMode = Bme680FilteringMode.C0;
+
+ _bme680Calibration = (Bme680CalibrationData)_calibrationData;
+ TryReadTemperature(out var temp);
+ ConfigureHeatingProfile(Bme680HeaterProfile.Profile1, 320, 150, temp.Celsius);
+ HeaterProfile = Bme680HeaterProfile.Profile1;
+
+ HeaterIsEnabled = true;
+ GasConversionIsEnabled = true;
}
///
/// Compensates the humidity.
///
- /// The temperature to use.
/// The humidity value read from the device.
/// The percentage relative humidity.
- private double CompensateHumidity(double temperature, int adcHumidity)
+ private double CompensateHumidity(int adcHumidity)
{
// Calculate the humidity.
+ var temperature = TemperatureFine / 5120.0;
var var1 = adcHumidity - ((_bme680Calibration.DigH1 * 16.0) + ((_bme680Calibration.DigH3 / 2.0) * temperature));
var var2 = var1 * ((_bme680Calibration.DigH2 / 262144.0) * (1.0 + ((_bme680Calibration.DigH4 / 16384.0) * temperature)
+ ((_bme680Calibration.DigH5 / 1048576.0) * temperature * temperature)));
@@ -198,22 +456,22 @@ private double CompensatePressure(int adcPressure)
{
// Calculate the pressure.
var var1 = (TemperatureFine / 2.0) - 64000.0;
- var var2 = var1 * var1 * (_calibrationData.DigP6 / 131072.0);
- var2 += (var1 * _calibrationData.DigP5 * 2.0);
- var2 = (var2 / 4.0) + (_calibrationData.DigP4 * 65536.0);
- var1 = ((_calibrationData.DigP3 * var1 * var1 / 16384.0) + (_calibrationData.DigP2 * var1)) / 524288.0;
- var1 = (1.0 + (var1 / 32768.0)) * _calibrationData.DigP1;
+ var var2 = var1 * var1 * (_bme680Calibration.DigP6 / 131072.0);
+ var2 += (var1 * _bme680Calibration.DigP5 * 2.0);
+ var2 = (var2 / 4.0) + (_bme680Calibration.DigP4 * 65536.0);
+ var1 = ((_bme680Calibration.DigP3 * var1 * var1 / 16384.0) + (_bme680Calibration.DigP2 * var1)) / 524288.0;
+ var1 = (1.0 + (var1 / 32768.0)) * _bme680Calibration.DigP1;
var calculatedPressure = 1048576.0 - adcPressure;
// Avoid exception caused by division by zero.
if (var1 != 0)
{
calculatedPressure = (calculatedPressure - (var2 / 4096.0)) * 6250.0 / var1;
- var1 = _calibrationData.DigP9 * calculatedPressure * calculatedPressure / 2147483648.0;
- var2 = calculatedPressure * (_calibrationData.DigP8 / 32768.0);
+ var1 = _bme680Calibration.DigP9 * calculatedPressure * calculatedPressure / 2147483648.0;
+ var2 = calculatedPressure * (_bme680Calibration.DigP8 / 32768.0);
var var3 = (calculatedPressure / 256.0) * (calculatedPressure / 256.0) * (calculatedPressure / 256.0)
- * (_calibrationData.DigP10 / 131072.0);
- calculatedPressure += (var1 + var2 + var3 + (_calibrationData.DigP7 * 128.0)) / 16.0;
+ * (_bme680Calibration.DigP10 / 131072.0);
+ calculatedPressure += (var1 + var2 + var3 + (_bme680Calibration.DigP7 * 128.0)) / 16.0;
}
else
{
@@ -223,7 +481,64 @@ private double CompensatePressure(int adcPressure)
return calculatedPressure;
}
- ///
- protected override int _tempCalibrationFactor => 16;
+ private bool ReadGasMeasurementIsValid()
+ {
+ var gasMeasValid = Read8BitsFromRegister((byte)Bme680Register.GAS_RANGE);
+ gasMeasValid = (byte)((gasMeasValid & (byte)Bme680Mask.GAS_VALID) >> 5);
+
+ return Convert.ToBoolean(gasMeasValid);
+ }
+
+ private double CalculateGasResistance(ushort adcGasRes, byte gasRange)
+ {
+ var var1 = 1340.0 + 5.0 * _bme680Calibration.RangeSwErr;
+ var var2 = var1 * (1.0 + s_k1Lookup[gasRange] / 100.0);
+ var var3 = 1.0 + s_k2Lookup[gasRange] / 100.0;
+ var gasResistance = 1.0 / (var3 * 0.000000125 * (1 << gasRange) * ((adcGasRes - 512.0) / var2 + 1.0));
+
+ return gasResistance;
+ }
+
+ private byte CalculateHeaterResistance(ushort setTemp, short ambientTemp)
+ {
+ // limit maximum temperature to 400°C
+ if (setTemp > 400)
+ setTemp = 400;
+
+ var var1 = _bme680Calibration.DigGh1 / 16.0 + 49.0;
+ var var2 = _bme680Calibration.DigGh2 / 32768.0 * 0.0005 + 0.00235;
+ var var3 = _bme680Calibration.DigGh3 / 1024.0;
+ var var4 = var1 * (1.0 + var2 * setTemp);
+ var var5 = var4 + var3 * ambientTemp;
+ var heaterResistance = (byte)(3.4 * (var5 * (4.0 / (4.0 + _bme680Calibration.ResHeatRange)) * (1.0 / (1.0 + _bme680Calibration.ResHeatVal * 0.002)) - 25));
+
+ return heaterResistance;
+ }
+
+ // The duration is interpreted as follows:
+ // Byte [7:6]: multiplication factor of 1, 4, 16 or 64
+ // Byte [5:0]: 64 timer values, 1ms step size
+ // Values are rounded down
+ private byte CalculateHeaterDuration(ushort duration)
+ {
+ byte factor = 0;
+ byte durationValue;
+
+ // check if value exceeds maximum duration
+ if (duration > 0xFC0)
+ durationValue = 0xFF;
+ else
+ {
+ while (duration > 0x3F)
+ {
+ duration = (ushort)(duration >> 2);
+ factor += 1;
+ }
+
+ durationValue = (byte)(duration + factor * 64);
+ }
+
+ return durationValue;
+ }
}
}
diff --git a/src/devices/Bmxx80/Bme680HeaterProfile.cs b/src/devices/Bmxx80/Bme680HeaterProfile.cs
new file mode 100644
index 0000000000..14bfd1d277
--- /dev/null
+++ b/src/devices/Bmxx80/Bme680HeaterProfile.cs
@@ -0,0 +1,53 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Iot.Device.Bmxx80
+{
+ ///
+ /// 10 addressable heater profiles stored on the Bme680.
+ ///
+ public enum Bme680HeaterProfile : byte
+ {
+ ///
+ /// Heater Profile 1.
+ ///
+ Profile1 = 0b0000,
+ ///
+ /// Heater Profile 2.
+ ///
+ Profile2 = 0b0001,
+ ///
+ /// Heater Profile 3.
+ ///
+ Profile3 = 0b0010,
+ ///
+ /// Heater Profile 4.
+ ///
+ Profile4 = 0b0011,
+ ///
+ /// Heater Profile 5.
+ ///
+ Profile5 = 0b0100,
+ ///
+ /// Heater Profile 6.
+ ///
+ Profile6 = 0b0101,
+ ///
+ /// Heater Profile 7.
+ ///
+ Profile7 = 0b0110,
+ ///
+ /// Heater Profile 8.
+ ///
+ Profile8 = 0b0111,
+ ///
+ /// Heater Profile 9.
+ ///
+ Profile9 = 0b1000,
+ ///
+ /// Heater Profile 10.
+ ///
+ Profile10 = 0b1001
+ }
+}
diff --git a/src/devices/Bmxx80/Bme680HeaterProfileConfig.cs b/src/devices/Bmxx80/Bme680HeaterProfileConfig.cs
new file mode 100644
index 0000000000..eeaf003b2c
--- /dev/null
+++ b/src/devices/Bmxx80/Bme680HeaterProfileConfig.cs
@@ -0,0 +1,44 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace Iot.Device.Bmxx80
+{
+ ///
+ /// The heater profile configuration saved on the device.
+ ///
+ public class Bme680HeaterProfileConfig
+ {
+ ///
+ /// The chosen heater profile slot, ranging from 0-9.
+ ///
+ public Bme680HeaterProfile HeaterProfile { get; set; }
+ ///
+ /// The heater resistance.
+ ///
+ public ushort HeaterResistance { get; set; }
+ ///
+ /// The heater duration in the internally used format.
+ ///
+ public ushort HeaterDuration { get; set; }
+
+ ///
+ ///
+ ///
+ /// The used heater profile.
+ /// The heater resistance in Ohm.
+ /// The heating duration in ms.
+ ///
+ public Bme680HeaterProfileConfig(Bme680HeaterProfile profile, ushort heaterResistance, ushort heaterDuration)
+ {
+ if (!Enum.IsDefined(typeof(Bme680HeaterProfile), profile))
+ throw new ArgumentOutOfRangeException();
+
+ HeaterProfile = profile;
+ HeaterResistance = heaterResistance;
+ HeaterDuration = heaterDuration;
+ }
+ }
+}
diff --git a/src/devices/Bmxx80/Bme680Mask.cs b/src/devices/Bmxx80/Bme680Mask.cs
new file mode 100644
index 0000000000..e59c3e9677
--- /dev/null
+++ b/src/devices/Bmxx80/Bme680Mask.cs
@@ -0,0 +1,28 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Iot.Device.Bmxx80
+{
+ internal enum Bme680Mask : byte
+ {
+ BIT_H1_DATA_MSK = 0x0F,
+
+ PWR_MODE = 0x03,
+ HEAT_OFF = 0x08,
+ RUN_GAS = 0x10,
+
+ HUMIDITY_SAMPLING = 0x07,
+ FILTER_COEFFICIENT = 0x1C,
+ NB_CONV = 0x0F,
+
+ GAS_RANGE = 0x0F,
+ RH_RANGE = 0x30,
+ RS_ERROR = 0xF0,
+
+ GAS_MEASURING = 0x40,
+ MEASURING = 0x20,
+ GAS_VALID = 0x20,
+ HEAT_STAB = 0x10
+ }
+}
diff --git a/src/devices/Bmxx80/Bmp280.cs b/src/devices/Bmxx80/Bmp280.cs
index 4cbda16ddf..080cc7b3be 100644
--- a/src/devices/Bmxx80/Bmp280.cs
+++ b/src/devices/Bmxx80/Bmp280.cs
@@ -3,14 +3,13 @@
// See the LICENSE file in the project root for more information.
using System.Device.I2c;
-using Iot.Device.Bmxx80.CalibrationData;
namespace Iot.Device.Bmxx80
{
///
/// Represents a BME280 temperature and barometric pressure sensor.
///
- public class Bmp280 : Bmx280Base
+ public sealed class Bmp280 : Bmx280Base
{
///
/// The expected chip ID of the BMP280.
@@ -25,8 +24,6 @@ public Bmp280(I2cDevice i2cDevice)
: base(DeviceId, i2cDevice)
{
_communicationProtocol = CommunicationProtocol.I2c;
- _calibrationData = new Bmp280CalibrationData();
- _calibrationData.ReadFromDevice(this);
}
}
}
diff --git a/src/devices/Bmxx80/Bmx280Base.cs b/src/devices/Bmxx80/Bmx280Base.cs
index a126cdcb0a..e84bdd1473 100644
--- a/src/devices/Bmxx80/Bmx280Base.cs
+++ b/src/devices/Bmxx80/Bmx280Base.cs
@@ -8,9 +8,9 @@
using System;
using System.Device.I2c;
using System.IO;
-using System.Threading.Tasks;
using Iot.Device.Bmxx80.PowerMode;
using Iot.Device.Bmxx80.Register;
+using Iot.Device.Bmxx80.FilteringMode;
using Iot.Units;
namespace Iot.Device.Bmxx80
@@ -30,56 +30,78 @@ public abstract class Bmx280Base : Bmxx80Base
///
public const byte SecondaryI2cAddress = 0x76;
+ ///
+ /// Converts oversampling to needed measurement cycles for that oversampling.
+ ///
+ protected static readonly int[] s_osToMeasCycles = { 0, 7, 9, 14, 23, 44 };
+
+ private Bmx280FilteringMode _filteringMode;
+ private StandbyTime _standbyTime;
+
///
/// Initializes a new instance of the class.
///
/// The ID of the device.
/// The to create with.
protected Bmx280Base(byte deviceId, I2cDevice i2cDevice)
- : base(deviceId, i2cDevice)
+ : base(deviceId, i2cDevice) { }
+
+ ///
+ /// Gets or sets the IIR filter mode.
+ ///
+ /// Thrown when the is set to an undefined mode.
+ public Bmx280FilteringMode FilterMode
{
- _controlRegister = (byte)Bmx280Register.CTRL_MEAS;
+ get => _filteringMode;
+ set
+ {
+ byte current = Read8BitsFromRegister((byte)Bmx280Register.CONFIG);
+ current = (byte)((current & 0b_1110_0011) | (byte)value << 2);
+
+ Span command = stackalloc[] { (byte)Bmx280Register.CONFIG, current };
+ _i2cDevice.Write(command);
+ _filteringMode = value;
+ }
}
///
- /// Reads the current IIR filter mode the device is running in.
+ /// Gets or sets the standby time between two consecutive measurements.
///
- /// The current .
- public FilteringMode ReadFilterMode()
+ /// Thrown when the is set to an undefined mode.
+ public StandbyTime StandbyTime
{
- byte current = Read8BitsFromRegister((byte)Bmx280Register.CONFIG);
- var mode = (byte)((current & 0b_0001_1100) >> 2);
-
- return mode switch
+ get => _standbyTime;
+ set
{
- 0b000 => FilteringMode.Off,
- 0b001 => FilteringMode.X2,
- 0b010 => FilteringMode.X4,
- 0b011 => FilteringMode.X8,
- _ => FilteringMode.X16
- };
+ byte current = Read8BitsFromRegister((byte)Bmx280Register.CONFIG);
+ current = (byte)((current & 0b_0001_1111) | (byte)value << 5);
+
+ Span command = stackalloc[] { (byte)Bmx280Register.CONFIG, current };
+ _i2cDevice.Write(command);
+ _standbyTime = value;
+ }
}
///
- /// Read the temperature.
+ /// Reads the temperature. A return value indicates whether the reading succeeded.
///
- /// Calculated temperature.
- public async Task ReadTemperatureAsync()
+ ///
+ /// Contains the measured temperature if the was not set to .
+ /// Contains otherwise.
+ ///
+ /// true
if measurement was not skipped, otherwise false
.
+ public override bool TryReadTemperature(out Temperature temperature)
{
- if (ReadPowerMode() == Bmx280PowerMode.Forced)
+ if (TemperatureSampling == Sampling.Skipped)
{
- await Task.Delay(GetMeasurementTimeForForcedMode(ReadTemperatureSampling()));
+ temperature = Temperature.FromCelsius(double.NaN);
+ return false;
}
- //Read the MSB, LSB and bits 7:4 (XLSB) of the temperature from the BMP280 registers
- byte msb = Read8BitsFromRegister((byte)Bmx280Register.TEMPDATA_MSB);
- byte lsb = Read8BitsFromRegister((byte)Bmx280Register.TEMPDATA_LSB);
- byte xlsb = Read8BitsFromRegister((byte)Bmx280Register.TEMPDATA_XLSB); // bits 7:4
+ var temp = (int)Read24BitsFromRegister((byte)Bmx280Register.TEMPDATA_MSB, Endianness.BigEndian);
- //Combine the values into a 32-bit integer
- int t = (msb << 12) + (lsb << 4) + (xlsb >> 4);
-
- return CompensateTemperature(t);
+ temperature = CompensateTemperature(temp >> 4);
+ return true;
}
///
@@ -109,49 +131,60 @@ public Bmx280PowerMode ReadPowerMode()
}
///
- /// Reads the pressure from the sensor.
+ /// Reads the pressure. A return value indicates whether the reading succeeded.
///
- /// Atmospheric pressure in Pa.
- public async Task ReadPressureAsync()
+ ///
+ /// Contains the measured pressure in Pa if the was not set to .
+ /// Contains otherwise.
+ ///
+ /// true
if measurement was not skipped, otherwise false
.
+ public override bool TryReadPressure(out double pressure)
{
- if (ReadPowerMode() == Bmx280PowerMode.Forced)
+ if (PressureSampling == Sampling.Skipped)
{
- await Task.Delay(GetMeasurementTimeForForcedMode(ReadPressureSampling()));
- }
-
- // Read the temperature first to load the t_fine value for compensation.
- await ReadTemperatureAsync();
+ pressure = double.NaN;
+ return false;
+ }
- // Read pressure data.
- byte msb = Read8BitsFromRegister((byte)Bmx280Register.PRESSUREDATA_MSB);
- byte lsb = Read8BitsFromRegister((byte)Bmx280Register.PRESSUREDATA_LSB);
- byte xlsb = Read8BitsFromRegister((byte)Bmx280Register.PRESSUREDATA_XLSB); // bits 7:4
+ // Read the temperature first to load the t_fine value for compensation.
+ TryReadTemperature(out _);
- //Combine the values into a 32-bit integer.
- int t = (msb << 12) + (lsb << 4) + (xlsb >> 4);
+ // Read pressure data.
+ var press = (int)Read24BitsFromRegister((byte)Bmx280Register.PRESSUREDATA, Endianness.BigEndian);
//Convert the raw value to the pressure in Pa.
- long pres = CompensatePressure(t);
+ long pressPa = CompensatePressure(press >> 4);
//Return the temperature as a float value.
- return (double)pres / 256;
+ pressure = (double)pressPa / 256;
+ return true;
}
///
/// Calculates the altitude in meters from the specified sea-level pressure(in hPa).
///
/// Sea-level pressure in hPa.
- /// Height in meters from sea-level.
- public async Task ReadAltitudeAsync(double seaLevelPressure)
+ ///
+ /// Contains the calculated metres above sea-level if the was not set to .
+ /// Contains otherwise.
+ ///
+ /// true
if pressure measurement was not skipped, otherwise false
.
+ public bool TryReadAltitude(double seaLevelPressure, out double altitude)
{
// Read the pressure first.
- double pressure = await ReadPressureAsync();
+ var success = TryReadPressure(out var pressure);
+ if (!success)
+ {
+ altitude = double.NaN;
+ return false;
+ }
// Convert the pressure to Hectopascals (hPa).
pressure /= 100;
// Calculate and return the altitude using the international barometric formula.
- return 44330.0 * (1.0 - Math.Pow((pressure / seaLevelPressure), 0.1903));
+ altitude = 44330.0 * (1.0 - Math.Pow(pressure / seaLevelPressure, 0.1903));
+ return true;
}
///
@@ -175,17 +208,6 @@ public DeviceStatus ReadStatus()
};
}
- ///
- /// Sets the IIR filter mode.
- ///
- /// The to set.
- public void SetFilterMode(FilteringMode filteringMode)
- {
- byte current = Read8BitsFromRegister((byte)Bmx280Register.CONFIG);
- current = (byte)((current & 0b_1110_0011) | (byte)filteringMode << 2);
- _i2cDevice.Write(new[] { (byte)Bmx280Register.CONFIG, current });
- }
-
///
/// Sets the power mode to the given mode
///
@@ -197,47 +219,27 @@ public void SetPowerMode(Bmx280PowerMode powerMode)
// Clear last 2 bits.
var cleared = (byte)(read & 0b_1111_1100);
- _i2cDevice.Write(new[] { _controlRegister, (byte)(cleared | (byte)powerMode) });
+ Span command = stackalloc[] { _controlRegister, (byte)(cleared | (byte)powerMode) };
+ _i2cDevice.Write(command);
}
///
- /// Sets the standby time mode the device will used when operating in normal mode.
+ /// Gets the required time in ms to perform a measurement with the current sampling modes.
///
- /// The to set.
- public void SetStandbyTime(StandbyTime standbyTime)
- {
- byte current = Read8BitsFromRegister((byte)Bmx280Register.CONFIG);
- current = (byte)((current & 0b_0001_1111) | (byte)standbyTime << 5);
- _i2cDevice.Write(new[] { (byte)Bmx280Register.CONFIG, current });
- }
-
- ///
- /// Reads the currently configured standby time mode the device will used when operating in normal mode.
- ///
- /// The current .
- public StandbyTime ReadStandbyTime()
+ /// The time it takes for the chip to read data in milliseconds rounded up.
+ public virtual int GetMeasurementDuration()
{
- byte current = Read8BitsFromRegister((byte)Bmx280Register.CONFIG);
-
- return (StandbyTime)((current & 0b_1110_0000) >> 5);
+ return s_osToMeasCycles[(int)PressureSampling] + s_osToMeasCycles[(int)TemperatureSampling];
}
///
- /// Recommended wait timings from the datasheet.
+ /// Sets the default configuration for the sensor.
///
- /// The to get for.
- /// The time it takes for the chip to read data in milliseconds rounded up.
- internal int GetMeasurementTimeForForcedMode(Sampling sampleMode)
+ protected override void SetDefaultConfiguration()
{
- return sampleMode switch
- {
- Sampling.UltraLowPower => 7,
- Sampling.LowPower => 9,
- Sampling.Standard => 14,
- Sampling.HighResolution => 23,
- Sampling.UltraHighResolution => 44,
- _ => 0
- };
+ base.SetDefaultConfiguration();
+ FilterMode = Bmx280FilteringMode.Off;
+ StandbyTime = StandbyTime.Ms125;
}
///
diff --git a/src/devices/Bmxx80/Bmxx80.csproj b/src/devices/Bmxx80/Bmxx80.csproj
index 3b1096e7e2..3a9422993b 100644
--- a/src/devices/Bmxx80/Bmxx80.csproj
+++ b/src/devices/Bmxx80/Bmxx80.csproj
@@ -9,6 +9,9 @@
+
+
+
@@ -17,7 +20,8 @@
-
+
+
diff --git a/src/devices/Bmxx80/Bmxx80Base.cs b/src/devices/Bmxx80/Bmxx80Base.cs
index 4f98b04152..e3d2e47768 100644
--- a/src/devices/Bmxx80/Bmxx80Base.cs
+++ b/src/devices/Bmxx80/Bmxx80Base.cs
@@ -17,29 +17,34 @@ namespace Iot.Device.Bmxx80
///
public abstract class Bmxx80Base : IDisposable
{
+ ///
+ /// Calibration data for the sensor.
+ ///
internal Bmxx80CalibrationData _calibrationData;
///
- /// I2C device used to communicate with the device
+ /// I2C device used to communicate with the device.
///
protected I2cDevice _i2cDevice;
///
- /// Communication protocol
+ /// Chosen communication protocol.
///
protected CommunicationProtocol _communicationProtocol;
///
- /// Control register
+ /// The control register of the sensor.
///
protected byte _controlRegister;
///
- /// Bmxx80 communication protocol
+ /// Bmxx80 communication protocol.
///
public enum CommunicationProtocol
{
- /// Communication protocol
+ ///
+ /// I²C communication protocol.
+ ///
I2c
}
@@ -49,6 +54,14 @@ public enum CommunicationProtocol
///
protected int TemperatureFine;
+ ///
+ /// The temperature calibration factor.
+ ///
+ protected virtual int _tempCalibrationFactor => 1;
+
+ private Sampling _temperatureSampling;
+ private Sampling _pressureSampling;
+
///
/// Initializes a new instance of the class.
///
@@ -64,67 +77,82 @@ protected Bmxx80Base(byte deviceId, I2cDevice i2cDevice)
byte readSignature = _i2cDevice.ReadByte();
if (readSignature != deviceId)
- {
throw new IOException($"Unable to find a chip with id {deviceId}");
- }
+
+ ReadCalibrationData();
+ SetDefaultConfiguration();
}
///
- /// Sets the pressure sampling.
+ /// Gets or sets the pressure sampling.
///
- /// The to set.
- public void SetPressureSampling(Sampling sampling)
+ /// Thrown when the is set to an undefined mode.
+ public Sampling PressureSampling
{
- byte status = Read8BitsFromRegister(_controlRegister);
- status = (byte)(status & 0b1110_0011);
- status = (byte)(status | (byte)sampling << 2);
- _i2cDevice.Write(new[] { _controlRegister, status });
+ get => _pressureSampling;
+ set
+ {
+ byte status = Read8BitsFromRegister(_controlRegister);
+ status = (byte)(status & 0b1110_0011);
+ status = (byte)(status | (byte)value << 2);
+
+ Span command = stackalloc[] { _controlRegister, status };
+ _i2cDevice.Write(command);
+ _pressureSampling = value;
+ }
}
///
- /// Set the temperature oversampling.
+ /// Gets or sets the temperature sampling.
///
- /// The to set.
- public void SetTemperatureSampling(Sampling sampling)
+ /// Thrown when the is set to an undefined mode.
+ public Sampling TemperatureSampling
{
- byte status = Read8BitsFromRegister(_controlRegister);
- status = (byte)(status & 0b0001_1111);
- status = (byte)(status | (byte)sampling << 5);
- _i2cDevice.Write(new[] { _controlRegister, status });
+ get => _temperatureSampling;
+ set
+ {
+ byte status = Read8BitsFromRegister(_controlRegister);
+ status = (byte)(status & 0b0001_1111);
+ status = (byte)(status | (byte)value << 5);
+
+ Span command = stackalloc[] { _controlRegister, status };
+ _i2cDevice.Write(command);
+ _temperatureSampling = value;
+ }
}
///
- /// Get the current sample rate for pressure measurements
+ /// When called, the device is reset using the complete power-on-reset procedure.
+ /// The device will reset to the default configuration.
///
- /// The current pressure rate.
- public Sampling ReadPressureSampling()
+ public void Reset()
{
- byte status = Read8BitsFromRegister(_controlRegister);
- status = (byte)((status & 0b0001_1100) >> 2);
+ const byte resetCommand = 0xB6;
+ Span command = stackalloc[] { (byte)Bmxx80Register.RESET, resetCommand };
+ _i2cDevice.Write(command);
- return ByteToSampling(status);
+ SetDefaultConfiguration();
}
///
- /// Get the sample rate for temperature measurements.
+ /// Reads the temperature. A return value indicates whether the reading succeeded.
///
- /// The current temperature rate.
- public Sampling ReadTemperatureSampling()
- {
- byte status = Read8BitsFromRegister(_controlRegister);
- status = (byte)((status & 0b1110_0000) >> 5);
-
- return ByteToSampling(status);
- }
+ ///
+ /// Contains the measured temperature if the was not set to .
+ /// Contains otherwise.
+ ///
+ /// true
if measurement was not skipped, otherwise false
.
+ public abstract bool TryReadTemperature(out Temperature temperature);
///
- /// When called, the device is reset using the complete power-on-reset procedure.
+ /// Reads the pressure. A return value indicates whether the reading succeeded.
///
- public void Reset()
- {
- const byte resetCommand = 0xB6;
- _i2cDevice.Write(new[] { (byte)Bmxx80Register.RESET, resetCommand });
- }
+ ///
+ /// Contains the measured pressure in Pa if the was not set to .
+ /// Contains otherwise.
+ ///
+ /// true
if measurement was not skipped, otherwise false
.
+ public abstract bool TryReadPressure(out double pressure);
///
/// Compensates the temperature.
@@ -145,11 +173,6 @@ protected Temperature CompensateTemperature(int adcTemperature)
return Temperature.FromCelsius(temp);
}
- ///
- /// Temperature calibration factor
- ///
- protected virtual int _tempCalibrationFactor => 1;
-
///
/// Reads an 8 bit value from a register.
///
@@ -164,71 +187,123 @@ protected internal byte Read8BitsFromRegister(byte register)
return value;
}
else
- {
throw new NotImplementedException();
- }
}
///
/// Reads a 16 bit value over I2C.
///
/// Register to read from.
+ /// Interpretation of the bytes (big or little endian).
/// Value from register.
- protected internal ushort Read16BitsFromRegister(byte register)
+ protected internal ushort Read16BitsFromRegister(byte register, Endianness endianness = Endianness.LittleEndian)
{
- if (_communicationProtocol == CommunicationProtocol.I2c)
+ Span bytes = stackalloc byte[2];
+ switch (_communicationProtocol)
{
- Span bytes = stackalloc byte[2];
-
- _i2cDevice.WriteByte(register);
- _i2cDevice.Read(bytes);
-
- return BinaryPrimitives.ReadUInt16LittleEndian(bytes);
+ case CommunicationProtocol.I2c:
+ _i2cDevice.WriteByte(register);
+ _i2cDevice.Read(bytes);
+ break;
+ default:
+ throw new NotImplementedException();
}
- else
+
+ return endianness switch
{
- throw new NotImplementedException();
- }
+ Endianness.LittleEndian => BinaryPrimitives.ReadUInt16LittleEndian(bytes),
+ Endianness.BigEndian => BinaryPrimitives.ReadUInt16BigEndian(bytes),
+ _ => throw new ArgumentOutOfRangeException(nameof(endianness), endianness, null)
+ };
}
///
/// Reads a 24 bit value over I2C.
///
/// Register to read from.
+ /// Interpretation of the bytes (big or little endian).
/// Value from register.
- protected internal uint Read24BitsFromRegister(byte register)
+ protected internal uint Read24BitsFromRegister(byte register, Endianness endianness = Endianness.LittleEndian)
{
- if (_communicationProtocol == CommunicationProtocol.I2c)
+ Span bytes = stackalloc byte[4];
+ switch (_communicationProtocol)
{
- Span bytes = stackalloc byte[4];
-
- _i2cDevice.WriteByte(register);
- _i2cDevice.Read(bytes.Slice(1));
-
- return BinaryPrimitives.ReadUInt32LittleEndian(bytes);
+ case CommunicationProtocol.I2c:
+ _i2cDevice.WriteByte(register);
+ _i2cDevice.Read(bytes.Slice(1));
+ break;
+ default:
+ throw new NotImplementedException();
}
- else
+
+ return endianness switch
{
- throw new NotImplementedException();
- }
+ Endianness.LittleEndian => BinaryPrimitives.ReadUInt32LittleEndian(bytes),
+ Endianness.BigEndian => BinaryPrimitives.ReadUInt32BigEndian(bytes),
+ _ => throw new ArgumentOutOfRangeException(nameof(endianness), endianness, null)
+ };
}
///
- /// Convert byte to sampling
+ /// Converts byte to .
///
- /// Value to convert
- /// Sampling
+ /// Value to convert.
+ ///
protected Sampling ByteToSampling(byte value)
{
// Values >=5 equals UltraHighResolution.
if (value >= 5)
- {
return Sampling.UltraHighResolution;
- }
return (Sampling)value;
}
+ ///
+ /// Sets the default configuration for the sensor.
+ ///
+ protected virtual void SetDefaultConfiguration()
+ {
+ PressureSampling = Sampling.UltraLowPower;
+ TemperatureSampling = Sampling.UltraLowPower;
+ }
+
+ ///
+ /// Specifies the Endianness of a device.
+ ///
+ protected internal enum Endianness
+ {
+ ///
+ /// Indicates little endian.
+ ///
+ LittleEndian,
+
+ ///
+ /// Indicates big endian.
+ ///
+ BigEndian
+ }
+
+ private void ReadCalibrationData()
+ {
+ switch (this)
+ {
+ case Bme280 _:
+ _calibrationData = new Bme280CalibrationData();
+ _controlRegister = (byte)Bmx280Register.CTRL_MEAS;
+ break;
+ case Bmp280 _:
+ _calibrationData = new Bmp280CalibrationData();
+ _controlRegister = (byte)Bmx280Register.CTRL_MEAS;
+ break;
+ case Bme680 _:
+ _calibrationData = new Bme680CalibrationData();
+ _controlRegister = (byte)Bme680Register.CTRL_MEAS;
+ break;
+ }
+
+ _calibrationData.ReadFromDevice(this);
+ }
+
///
/// Cleanup.
///
diff --git a/src/devices/Bmxx80/CalibrationData/Bme280CalibrationData.cs b/src/devices/Bmxx80/CalibrationData/Bme280CalibrationData.cs
index d3fe69e27d..934e079523 100644
--- a/src/devices/Bmxx80/CalibrationData/Bme280CalibrationData.cs
+++ b/src/devices/Bmxx80/CalibrationData/Bme280CalibrationData.cs
@@ -1,6 +1,7 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
using Iot.Device.Bmxx80.Register;
namespace Iot.Device.Bmxx80.CalibrationData
diff --git a/src/devices/Bmxx80/CalibrationData/Bme680CalibrationData.cs b/src/devices/Bmxx80/CalibrationData/Bme680CalibrationData.cs
index 53964f0df3..ea7ce6d5f7 100644
--- a/src/devices/Bmxx80/CalibrationData/Bme680CalibrationData.cs
+++ b/src/devices/Bmxx80/CalibrationData/Bme680CalibrationData.cs
@@ -11,6 +11,8 @@ namespace Iot.Device.Bmxx80.CalibrationData
///
internal class Bme680CalibrationData : Bmxx80CalibrationData
{
+ public byte DigP10 { get; set; }
+
public ushort DigH1 { get; set; }
public ushort DigH2 { get; set; }
public sbyte DigH3 { get; set; }
@@ -19,6 +21,14 @@ internal class Bme680CalibrationData : Bmxx80CalibrationData
public byte DigH6 { get; set; }
public sbyte DigH7 { get; set; }
+ public sbyte DigGh1 { get; set; }
+ public short DigGh2 { get; set; }
+ public sbyte DigGh3 { get; set; }
+
+ public byte ResHeatRange { get; set; }
+ public sbyte ResHeatVal { get; set; }
+ public sbyte RangeSwErr { get; set; }
+
///
/// Read coefficient data from device.
///
@@ -31,7 +41,7 @@ protected internal override void ReadFromDevice(Bmxx80Base bmxx80Base)
DigT3 = bmxx80Base.Read8BitsFromRegister((byte)Bme680Register.DIG_T3);
// Read humidity calibration data.
- DigH1 = (ushort)((bmxx80Base.Read8BitsFromRegister((byte)Bme680Register.DIG_H1_MSB) << 4) | (bmxx80Base.Read8BitsFromRegister((byte)Bme680Register.DIG_H1_LSB) & 0b0000_1111));
+ DigH1 = (ushort)((bmxx80Base.Read8BitsFromRegister((byte)Bme680Register.DIG_H1_MSB) << 4) | (bmxx80Base.Read8BitsFromRegister((byte)Bme680Register.DIG_H1_LSB) & (byte)Bme680Mask.BIT_H1_DATA_MSK));
DigH2 = (ushort)((bmxx80Base.Read8BitsFromRegister((byte)Bme680Register.DIG_H2_MSB) << 4) | (bmxx80Base.Read8BitsFromRegister((byte)Bme680Register.DIG_H2_LSB) >> 4));
DigH3 = (sbyte)bmxx80Base.Read8BitsFromRegister((byte)Bme680Register.DIG_H3);
DigH4 = (sbyte)bmxx80Base.Read8BitsFromRegister((byte)Bme680Register.DIG_H4);
@@ -50,6 +60,16 @@ protected internal override void ReadFromDevice(Bmxx80Base bmxx80Base)
DigP8 = (short)bmxx80Base.Read16BitsFromRegister((byte)Bme680Register.DIG_P8_LSB);
DigP9 = (short)bmxx80Base.Read16BitsFromRegister((byte)Bme680Register.DIG_P9_LSB);
DigP10 = bmxx80Base.Read8BitsFromRegister((byte)Bme680Register.DIG_P10);
+
+ // read gas calibration data.
+ DigGh1 = (sbyte)bmxx80Base.Read8BitsFromRegister((byte)Bme680Register.DIG_GH1);
+ DigGh2 = (short)bmxx80Base.Read16BitsFromRegister((byte)Bme680Register.DIG_GH2);
+ DigGh3 = (sbyte)bmxx80Base.Read8BitsFromRegister((byte)Bme680Register.DIG_GH3);
+
+ // read heater calibration data
+ ResHeatRange = (byte)((bmxx80Base.Read8BitsFromRegister((byte)Bme680Register.RES_HEAT_RANGE) & (byte)Bme680Mask.RH_RANGE) >> 4);
+ RangeSwErr = (sbyte)((bmxx80Base.Read8BitsFromRegister((byte)Bme680Register.RANGE_SW_ERR) & (byte)Bme680Mask.RS_ERROR) >> 4);
+ ResHeatVal = (sbyte)bmxx80Base.Read8BitsFromRegister((byte)Bme680Register.RES_HEAT_VAL);
}
}
}
diff --git a/src/devices/Bmxx80/CalibrationData/Bmxx80CalibrationData.cs b/src/devices/Bmxx80/CalibrationData/Bmxx80CalibrationData.cs
index 0aa2965389..3907b32bb5 100644
--- a/src/devices/Bmxx80/CalibrationData/Bmxx80CalibrationData.cs
+++ b/src/devices/Bmxx80/CalibrationData/Bmxx80CalibrationData.cs
@@ -22,12 +22,11 @@ internal abstract class Bmxx80CalibrationData
public short DigP7 { get; set; }
public short DigP8 { get; set; }
public short DigP9 { get; set; }
- public byte DigP10 { get; set; }
-
+
///
/// Read coefficient data from device.
///
/// The to read coefficient data from.
- protected internal virtual void ReadFromDevice(Bmxx80Base bmxx80Base) { }
+ protected internal abstract void ReadFromDevice(Bmxx80Base bmxx80Base);
}
}
diff --git a/src/devices/Bmxx80/DeviceStatus.cs b/src/devices/Bmxx80/DeviceStatus.cs
index 13d51c2cea..a284146606 100644
--- a/src/devices/Bmxx80/DeviceStatus.cs
+++ b/src/devices/Bmxx80/DeviceStatus.cs
@@ -1,4 +1,8 @@
-namespace Iot.Device.Bmxx80
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Iot.Device.Bmxx80
{
///
/// Indicates the status of the device.
diff --git a/src/devices/Bmxx80/FilteringMode/Bme680FilteringMode.cs b/src/devices/Bmxx80/FilteringMode/Bme680FilteringMode.cs
new file mode 100644
index 0000000000..8bfd8ea976
--- /dev/null
+++ b/src/devices/Bmxx80/FilteringMode/Bme680FilteringMode.cs
@@ -0,0 +1,46 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Iot.Device.Bmxx80.FilteringMode
+{
+ ///
+ /// IIR filter coefficient. The higher the coefficient, the slower the sensors
+ /// responds to external inputs.
+ ///
+ public enum Bme680FilteringMode
+ {
+ ///
+ /// Filter coefficient of 0.
+ ///
+ C0 = 0b000,
+ ///
+ /// Filter coefficient of 1.
+ ///
+ C1 = 0b001,
+ ///
+ /// Filter coefficient of 3.
+ ///
+ C3 = 0b010,
+ ///
+ /// Filter coefficient of 7.
+ ///
+ C7 = 0b011,
+ ///
+ /// Filter coefficient of 15.
+ ///
+ C15 = 0b100,
+ ///
+ /// Filter coefficient of 31.
+ ///
+ C31 = 0b101,
+ ///
+ /// Filter coefficient of 63.
+ ///
+ C63 = 0b110,
+ ///
+ /// Filter coefficient of 127.
+ ///
+ C127 = 0b111
+ }
+}
diff --git a/src/devices/Bmxx80/FilteringMode.cs b/src/devices/Bmxx80/FilteringMode/Bmx280FilteringMode.cs
similarity index 91%
rename from src/devices/Bmxx80/FilteringMode.cs
rename to src/devices/Bmxx80/FilteringMode/Bmx280FilteringMode.cs
index ee0169964b..5d6edb6c5c 100644
--- a/src/devices/Bmxx80/FilteringMode.cs
+++ b/src/devices/Bmxx80/FilteringMode/Bmx280FilteringMode.cs
@@ -2,7 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-namespace Iot.Device.Bmxx80
+namespace Iot.Device.Bmxx80.FilteringMode
{
///
/// Bmx280 devices feature an internal IIR filter.
@@ -11,11 +11,11 @@ namespace Iot.Device.Bmxx80
/// This filter effectively reduces the bandwidth of the temperature and pressure output signals
/// and increases the resolution of the pressure and temperature output data to 20 bits.
///
- /// The higher the coefficient, the slower the sensors respond to external inputs.
+ /// The higher the coefficient, the slower the sensors responds to external inputs.
///
/// See the data sheet with recommended settings for different scenarios.
///
- public enum FilteringMode : byte
+ public enum Bmx280FilteringMode : byte
{
///
/// Filter off.
diff --git a/src/devices/Bmxx80/README.md b/src/devices/Bmxx80/README.md
index a6c501b30f..9fcf21e4ca 100644
--- a/src/devices/Bmxx80/README.md
+++ b/src/devices/Bmxx80/README.md
@@ -11,13 +11,13 @@ The implementation supports the following devices:
- BMP280 temperature and barometric pressure sensor ([Datasheet](https://cdn-shop.adafruit.com/datasheets/BST-BMP280-DS001-11.pdf))
- BME280 temperature, barometric pressure and humidity sensor ([Datasheet](https://ae-bst.resource.bosch.com/media/_tech/media/datasheets/BST-BME280-DS002.pdf))
-- BME680 Temperature, barometric pressure, Humidity and VOC gas sensor ([Datasheet](https://ae-bst.resource.bosch.com/media/_tech/media/datasheets/BST-BME680-DS001.pdf))
+- BME680 temperature, barometric pressure, humidity and VOC gas sensor ([Datasheet](https://ae-bst.resource.bosch.com/media/_tech/media/datasheets/BST-BME680-DS001.pdf))
## Usage
-2 examples on how to use this device binding are available in the [samples](samples) folder.
+3 examples on how to use this device binding are available in the [samples](samples) folder.
-The following fritzing diagram illustrates one way to wire up the BMP280 with a Raspberry Pi using I2C.
+The following fritzing diagram illustrates one way to wire up the BMP280 with a Raspberry Pi using I2C:
![Raspberry Pi Breadboard diagram](samples/rpi-bmp280_i2c.png)
diff --git a/src/devices/Bmxx80/Register/Bme280Register.cs b/src/devices/Bmxx80/Register/Bme280Register.cs
index f76b5f35a1..943e52b5e5 100644
--- a/src/devices/Bmxx80/Register/Bme280Register.cs
+++ b/src/devices/Bmxx80/Register/Bme280Register.cs
@@ -1,4 +1,8 @@
-namespace Iot.Device.Bmxx80.Register
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Iot.Device.Bmxx80.Register
{
///
/// General control registers for the BME280.
@@ -14,7 +18,6 @@ internal enum Bme280Register : byte
DIG_H5 = 0xE5,
DIG_H6 = 0xE7,
- HUMIDDATA_LSB = 0xFE,
- HUMIDDATA_MSB = 0xFD,
+ HUMIDDATA = 0xFD
}
}
diff --git a/src/devices/Bmxx80/Register/Bme680Register.cs b/src/devices/Bmxx80/Register/Bme680Register.cs
index 799bf8e010..4a0d9f64a9 100644
--- a/src/devices/Bmxx80/Register/Bme680Register.cs
+++ b/src/devices/Bmxx80/Register/Bme680Register.cs
@@ -12,9 +12,6 @@ namespace Iot.Device.Bmxx80.Register
///
internal enum Bme680Register : byte
{
- CTRL_MEAS = 0x74,
- CTRL_HUM = 0x72,
-
DIG_H1_LSB = 0xE2,
DIG_H1_MSB = 0xE3,
DIG_H2_LSB = 0xE2,
@@ -40,17 +37,28 @@ internal enum Bme680Register : byte
DIG_P9_LSB = 0x9E,
DIG_P10 = 0xA0,
- HUMIDITYDATA_LSB = 0x26,
- HUMIDITYDATA_MSB = 0x25,
-
- PRESSUREDATA_MSB = 0x1F,
- PRESSUREDATA_LSB = 0x20,
- PRESSUREDATA_XLSB = 0x21,
+ DIG_GH1 = 0xED,
+ DIG_GH2 = 0xEB,
+ DIG_GH3 = 0xEE,
+ RES_HEAT_VAL = 0x00,
+ RES_HEAT_RANGE = 0x02,
+ RANGE_SW_ERR = 0x04,
STATUS = 0x1D,
- TEMPDATA_MSB = 0x22,
- TEMPDATA_LSB = 0x23,
- TEMPDATA_XLSB = 0x24,
+ PRESSUREDATA = 0x1F,
+ TEMPDATA = 0x22,
+ HUMIDITYDATA = 0x25,
+
+ GAS_RES = 0x2A,
+ GAS_RANGE = 0x2B,
+ RES_HEAT_0 = 0x5A,
+ GAS_WAIT_0 = 0x64,
+
+ CTRL_GAS_0 = 0x70,
+ CTRL_GAS_1 = 0x71,
+ CTRL_HUM = 0x72,
+ CTRL_MEAS = 0x74,
+ CONFIG = 0x75
}
}
diff --git a/src/devices/Bmxx80/Register/Bmx280Register.cs b/src/devices/Bmxx80/Register/Bmx280Register.cs
index ad55261ce0..9d7231c9b4 100644
--- a/src/devices/Bmxx80/Register/Bmx280Register.cs
+++ b/src/devices/Bmxx80/Register/Bmx280Register.cs
@@ -25,20 +25,10 @@ internal enum Bmx280Register : byte
DIG_P8 = 0x9C,
DIG_P9 = 0x9E,
- VERSION = 0xD1,
- SOFTRESET = 0xE0,
-
- CAL26 = 0xE1, // R calibration stored in 0xE1-0xF0
-
STATUS = 0xF3,
CONFIG = 0xF5,
- PRESSUREDATA_MSB = 0xF7,
- PRESSUREDATA_LSB = 0xF8,
- PRESSUREDATA_XLSB = 0xF9, // bits <7:4>
-
- TEMPDATA_MSB = 0xFA,
- TEMPDATA_LSB = 0xFB,
- TEMPDATA_XLSB = 0xFC, // bits <7:4>
+ PRESSUREDATA = 0xF7,
+ TEMPDATA_MSB = 0xFA
}
}
diff --git a/src/devices/Bmxx80/Register/Bmxx80Register.cs b/src/devices/Bmxx80/Register/Bmxx80Register.cs
index f93ba57a4b..be62dbfe62 100644
--- a/src/devices/Bmxx80/Register/Bmxx80Register.cs
+++ b/src/devices/Bmxx80/Register/Bmxx80Register.cs
@@ -10,6 +10,6 @@ namespace Iot.Device.Bmxx80.Register
internal enum Bmxx80Register : byte
{
CHIPID = 0xD0,
- RESET = 0xE0,
+ RESET = 0xE0
}
}
diff --git a/src/devices/Bmxx80/samples/Bme280.sample.cs b/src/devices/Bmxx80/samples/Bme280.sample.cs
index 7b3c3abd7e..615247bd22 100644
--- a/src/devices/Bmxx80/samples/Bme280.sample.cs
+++ b/src/devices/Bmxx80/samples/Bme280.sample.cs
@@ -5,16 +5,15 @@
using System;
using System.Device.I2c;
using System.Threading;
-using System.Threading.Tasks;
using Iot.Device.Bmxx80;
+using Iot.Device.Bmxx80.FilteringMode;
using Iot.Device.Bmxx80.PowerMode;
-using Iot.Units;
namespace Iot.Device.Samples
{
class Program
{
- static async Task Main(string[] args)
+ static void Main(string[] args)
{
Console.WriteLine("Hello Bme280!");
@@ -31,60 +30,52 @@ static async Task Main(string[] args)
{
while (true)
{
+ //set higher sampling
+ i2CBmpe80.TemperatureSampling = Sampling.LowPower;
+ i2CBmpe80.PressureSampling = Sampling.UltraHighResolution;
+ i2CBmpe80.HumiditySampling = Sampling.Standard;
+
//set mode forced so device sleeps after read
i2CBmpe80.SetPowerMode(Bmx280PowerMode.Forced);
- //set samplings
- i2CBmpe80.SetTemperatureSampling(Sampling.UltraLowPower);
- i2CBmpe80.SetPressureSampling(Sampling.UltraLowPower);
- i2CBmpe80.SetHumiditySampling(Sampling.UltraLowPower);
+ // wait for measurement to be performed
+ var measurementTime = i2CBmpe80.GetMeasurementDuration();
+ Thread.Sleep(measurementTime);
//read values
- Temperature tempValue = await i2CBmpe80.ReadTemperatureAsync();
+ i2CBmpe80.TryReadTemperature(out var tempValue);
Console.WriteLine($"Temperature: {tempValue.Celsius} C");
- double preValue = await i2CBmpe80.ReadPressureAsync();
+ i2CBmpe80.TryReadPressure(out var preValue);
Console.WriteLine($"Pressure: {preValue} Pa");
- double altValue = await i2CBmpe80.ReadAltitudeAsync(defaultSeaLevelPressure);
+ i2CBmpe80.TryReadAltitude(defaultSeaLevelPressure, out var altValue);
Console.WriteLine($"Altitude: {altValue} meters");
- double humValue = await i2CBmpe80.ReadHumidityAsync();
+ i2CBmpe80.TryReadHumidity(out var humValue);
Console.WriteLine($"Humidity: {humValue} %");
Thread.Sleep(1000);
- //set higher sampling
- i2CBmpe80.SetTemperatureSampling(Sampling.LowPower);
- Console.WriteLine(i2CBmpe80.ReadTemperatureSampling());
- i2CBmpe80.SetPressureSampling(Sampling.UltraHighResolution);
- Console.WriteLine(i2CBmpe80.ReadPressureSampling());
- i2CBmpe80.SetHumiditySampling(Sampling.Standard);
- Console.WriteLine(i2CBmpe80.ReadHumiditySampling());
-
- i2CBmpe80.SetFilterMode(FilteringMode.Off);
- Console.WriteLine(i2CBmpe80.ReadFilterMode());
+ //change sampling and filter
+ i2CBmpe80.TemperatureSampling = Sampling.UltraHighResolution;
+ i2CBmpe80.PressureSampling = Sampling.UltraLowPower;
+ i2CBmpe80.HumiditySampling = Sampling.UltraLowPower;
+ i2CBmpe80.FilterMode = Bmx280FilteringMode.X2;
//set mode forced and read again
i2CBmpe80.SetPowerMode(Bmx280PowerMode.Forced);
+ // wait for measurement to be performed
+ measurementTime = i2CBmpe80.GetMeasurementDuration();
+ Thread.Sleep(measurementTime);
+
//read values
- tempValue = await i2CBmpe80.ReadTemperatureAsync();
+ i2CBmpe80.TryReadTemperature(out tempValue);
Console.WriteLine($"Temperature: {tempValue.Celsius} C");
- preValue = await i2CBmpe80.ReadPressureAsync();
+ i2CBmpe80.TryReadPressure(out preValue);
Console.WriteLine($"Pressure: {preValue} Pa");
- altValue = await i2CBmpe80.ReadAltitudeAsync(defaultSeaLevelPressure);
+ i2CBmpe80.TryReadAltitude(defaultSeaLevelPressure, out altValue);
Console.WriteLine($"Altitude: {altValue} meters");
- humValue = await i2CBmpe80.ReadHumidityAsync();
+ i2CBmpe80.TryReadHumidity(out humValue);
Console.WriteLine($"Humidity: {humValue} %");
Thread.Sleep(5000);
-
- //set sampling to higher
- i2CBmpe80.SetTemperatureSampling(Sampling.UltraHighResolution);
- Console.WriteLine(i2CBmpe80.ReadTemperatureSampling());
- i2CBmpe80.SetPressureSampling(Sampling.UltraLowPower);
- Console.WriteLine(i2CBmpe80.ReadPressureSampling());
- i2CBmpe80.SetHumiditySampling(Sampling.UltraLowPower);
- Console.WriteLine(i2CBmpe80.ReadHumiditySampling());
-
- i2CBmpe80.SetFilterMode(FilteringMode.X2);
- Console.WriteLine(i2CBmpe80.ReadFilterMode());
}
}
}
diff --git a/src/devices/Bmxx80/samples/Bme680.sample.cs b/src/devices/Bmxx80/samples/Bme680.sample.cs
index efc666baf5..328efa4202 100644
--- a/src/devices/Bmxx80/samples/Bme680.sample.cs
+++ b/src/devices/Bmxx80/samples/Bme680.sample.cs
@@ -1,7 +1,10 @@
-using System;
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
using System.Device.I2c;
-using System.Threading;
-using System.Threading.Tasks;
+using System.Threading;
using Iot.Device.Bmxx80;
using Iot.Device.Bmxx80.PowerMode;
@@ -15,7 +18,7 @@ public static class Program
///
/// Main entry point for the program.
///
- static async Task Main()
+ static void Main()
{
Console.WriteLine("Hello BME680!");
@@ -27,33 +30,63 @@ static async Task Main()
using (var bme680 = new Bme680(unixI2cDevice))
{
- // Prevents reading old data from the sensor's registers.
- bme680.Reset();
-
- bme680.SetHumiditySampling(Sampling.UltraLowPower);
- bme680.SetTemperatureSampling(Sampling.LowPower);
- bme680.SetPressureSampling(Sampling.UltraHighResolution);
-
while (true)
{
- // Once a reading has been taken, the sensor goes back to sleep mode.
- if (bme680.ReadPowerMode() == Bme680PowerMode.Sleep)
+ // get the time a measurement will take with the current settings
+ var measurementDuration = bme680.GetMeasurementDuration(bme680.HeaterProfile);
+
+ // 10 consecutive measurement with default settings
+ for (var i = 0; i < 10; i++)
{
// This instructs the sensor to take a measurement.
bme680.SetPowerMode(Bme680PowerMode.Forced);
+
+ // wait while measurement is being taken
+ Thread.Sleep(measurementDuration);
+
+ // Print out the measured data
+ bme680.TryReadTemperature(out var temperature);
+ bme680.TryReadPressure(out var pressure);
+ bme680.TryReadHumidity(out var humidity);
+ bme680.TryReadGasResistance(out var gasResistance);
+
+ Console.WriteLine($"{temperature.Celsius:N2} °c | {pressure / 100:N2} hPa | {humidity:N2} %rH | {gasResistance:N2} Ohm");
+
+ // when measuring the gas resistance on each cycle it is important to wait a certain interval
+ // because a heating plate is activated which will heat up the sensor without sleep, this can
+ // falsify all readings coming from the sensor
+ Thread.Sleep(1000);
}
- // This prevent us from reading old data from the sensor.
- if (bme680.ReadHasNewData())
+ // change the settings
+ bme680.TemperatureSampling = Sampling.HighResolution;
+ bme680.HumiditySampling = Sampling.UltraHighResolution;
+ bme680.PressureSampling = Sampling.Skipped;
+
+ bme680.ConfigureHeatingProfile(Bme680HeaterProfile.Profile2, 280, 80, 24);
+ bme680.HeaterProfile = Bme680HeaterProfile.Profile2;
+
+ measurementDuration = bme680.GetMeasurementDuration(bme680.HeaterProfile);
+
+ // 10 consecutive measurements with custom settings
+ for (int i = 0; i < 10; i++)
{
- var temperature = Math.Round((await bme680.ReadTemperatureAsync()).Celsius, 2).ToString("N2");
- var pressure = Math.Round(await bme680.ReadPressureAsync() / 100, 2).ToString("N2");
- var humidity = Math.Round(await bme680.ReadHumidityAsync(), 2).ToString("N2");
+ // perform the measurement
+ bme680.SetPowerMode(Bme680PowerMode.Forced);
+ Thread.Sleep(measurementDuration);
- Console.WriteLine($"{temperature} °c | {pressure} hPa | {humidity} %rH");
+ // Print out the measured data
+ bme680.TryReadTemperature(out var temperature);
+ bme680.TryReadPressure(out var pressure);
+ bme680.TryReadHumidity(out var humidity);
+ bme680.TryReadGasResistance(out var gasResistance);
+ Console.WriteLine($"{temperature.Celsius:N2} °c | {pressure / 100:N2} hPa | {humidity:N2} %rH | {gasResistance:N2} Ohm");
Thread.Sleep(1000);
}
+
+ // reset will change settings back to default
+ bme680.Reset();
}
}
}
diff --git a/src/devices/Bmxx80/samples/Bmp280.sample.cs b/src/devices/Bmxx80/samples/Bmp280.sample.cs
index 7b68f25807..99ec367183 100644
--- a/src/devices/Bmxx80/samples/Bmp280.sample.cs
+++ b/src/devices/Bmxx80/samples/Bmp280.sample.cs
@@ -5,16 +5,15 @@
using System;
using System.Device.I2c;
using System.Threading;
-using System.Threading.Tasks;
using Iot.Device.Bmxx80;
+using Iot.Device.Bmxx80.FilteringMode;
using Iot.Device.Bmxx80.PowerMode;
-using Iot.Units;
namespace Iot.Device.Samples
{
class Program
{
- static async Task Main(string[] args)
+ static void Main(string[] args)
{
Console.WriteLine("Hello Bmp280!");
@@ -31,45 +30,46 @@ static async Task Main(string[] args)
{
while (true)
{
+ //set higher sampling
+ i2CBmp280.TemperatureSampling = Sampling.LowPower;
+ i2CBmp280.PressureSampling = Sampling.UltraHighResolution;
+
//set mode forced so device sleeps after read
i2CBmp280.SetPowerMode(Bmx280PowerMode.Forced);
- //set samplings
- i2CBmp280.SetTemperatureSampling(Sampling.UltraLowPower);
- i2CBmp280.SetPressureSampling(Sampling.UltraLowPower);
+ // wait for measurement to be performed
+ var measurementTime = i2CBmp280.GetMeasurementDuration();
+ Thread.Sleep(measurementTime);
//read values
- Temperature tempValue = await i2CBmp280.ReadTemperatureAsync();
+ i2CBmp280.TryReadTemperature(out var tempValue);
Console.WriteLine($"Temperature {tempValue.Celsius}");
- double preValue = await i2CBmp280.ReadPressureAsync();
+ i2CBmp280.TryReadPressure(out var preValue);
Console.WriteLine($"Pressure {preValue}");
- double altValue = await i2CBmp280.ReadAltitudeAsync(defaultSeaLevelPressure);
+ i2CBmp280.TryReadAltitude(defaultSeaLevelPressure, out var altValue);
Console.WriteLine($"Altitude: {altValue}");
Thread.Sleep(1000);
- //set higher sampling
- i2CBmp280.SetTemperatureSampling(Sampling.LowPower);
- Console.WriteLine(i2CBmp280.ReadTemperatureSampling());
- i2CBmp280.SetPressureSampling(Sampling.UltraHighResolution);
- Console.WriteLine(i2CBmp280.ReadPressureSampling());
+ //change sampling rate
+ i2CBmp280.TemperatureSampling = Sampling.UltraHighResolution;
+ i2CBmp280.PressureSampling = Sampling.UltraLowPower;
+ i2CBmp280.FilterMode = Bmx280FilteringMode.X4;
//set mode forced and read again
i2CBmp280.SetPowerMode(Bmx280PowerMode.Forced);
+ // wait for measurement to be performed
+ measurementTime = i2CBmp280.GetMeasurementDuration();
+ Thread.Sleep(measurementTime);
+
//read values
- tempValue = await i2CBmp280.ReadTemperatureAsync();
+ i2CBmp280.TryReadTemperature(out tempValue);
Console.WriteLine($"Temperature {tempValue.Celsius}");
- preValue = await i2CBmp280.ReadPressureAsync();
+ i2CBmp280.TryReadPressure(out preValue);
Console.WriteLine($"Pressure {preValue}");
- altValue = await i2CBmp280.ReadAltitudeAsync(defaultSeaLevelPressure);
+ i2CBmp280.TryReadAltitude(defaultSeaLevelPressure, out altValue);
Console.WriteLine($"Altitude: {altValue}");
Thread.Sleep(5000);
-
- //set sampling to higher
- i2CBmp280.SetTemperatureSampling(Sampling.UltraHighResolution);
- Console.WriteLine(i2CBmp280.ReadTemperatureSampling());
- i2CBmp280.SetPressureSampling(Sampling.UltraLowPower);
- Console.WriteLine(i2CBmp280.ReadPressureSampling());
}
}
}