From f4ef4d36022b83f8ccb33cb69efc00290e612edf Mon Sep 17 00:00:00 2001 From: Adrian Stevens Date: Wed, 8 Dec 2021 22:09:49 -0800 Subject: [PATCH] Bme680 refactoring --- .../Bme680.Configuration.cs | 12 + .../Bme680.HumidityCompensation.cs | 2 +- .../Bme680.PressureCompensation.cs | 2 +- .../Bme680.PressureUnit.cs | 18 -- .../Bme680.RegisterAddresses.cs | 2 +- .../Bme680.SensorSettings.cs | 30 -- .../Bme680.TemperatureCompensation.cs | 3 +- .../Bme680.TemperatureUnit.cs | 17 -- .../Sensors.Atmospheric.Bme680/Bme680.cs | 286 +++++++++++++++--- .../Sensors.Atmospheric.Bme680/Bme680Comms.cs | 12 + .../Sensors.Atmospheric.Bme680/Bme680I2C.cs | 27 ++ .../Sensors.Atmospheric.Bme680/Bme680SPI.cs | 33 ++ .../Sensors.Atmospheric.Bme680/Helpers.cs | 42 --- .../Samples/Bme680_Sample/MeadowApp.cs | 77 ++++- 14 files changed, 401 insertions(+), 162 deletions(-) create mode 100644 Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Bme680.Configuration.cs delete mode 100644 Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Bme680.PressureUnit.cs delete mode 100644 Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Bme680.SensorSettings.cs delete mode 100644 Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Bme680.TemperatureUnit.cs create mode 100644 Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Bme680Comms.cs create mode 100644 Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Bme680I2C.cs create mode 100644 Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Bme680SPI.cs delete mode 100644 Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Helpers.cs diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Bme680.Configuration.cs b/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Bme680.Configuration.cs new file mode 100644 index 0000000000..04a0bb90f4 --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Bme680.Configuration.cs @@ -0,0 +1,12 @@ +namespace Meadow.Foundation.Sensors.Atmospheric +{ + public partial class Bme680 + { + public class Configuration + { + public Oversample TemperatureOversample { get; set; } = Oversample.OversampleX16; + public Oversample PressureOversample { get; set; } = Oversample.OversampleX16; + public Oversample HumidityOversample { get; set; } = Oversample.OversampleX16; + } + } +} \ No newline at end of file diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Bme680.HumidityCompensation.cs b/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Bme680.HumidityCompensation.cs index da1044d494..daa1d313d2 100644 --- a/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Bme680.HumidityCompensation.cs +++ b/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Bme680.HumidityCompensation.cs @@ -4,7 +4,7 @@ namespace Meadow.Foundation.Sensors.Atmospheric { public partial class Bme680 { - internal class HumidityCompensation + protected class HumidityCompensation { public HumidityCompensation(byte[] rawCompData1) { diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Bme680.PressureCompensation.cs b/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Bme680.PressureCompensation.cs index 82aff25278..d7c6f4a0fe 100644 --- a/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Bme680.PressureCompensation.cs +++ b/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Bme680.PressureCompensation.cs @@ -5,7 +5,7 @@ namespace Meadow.Foundation.Sensors.Atmospheric { public partial class Bme680 { - public class PressureCompensation + protected class PressureCompensation { public PressureCompensation(IReadOnlyList rawCompensationData) { diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Bme680.PressureUnit.cs b/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Bme680.PressureUnit.cs deleted file mode 100644 index 865c182fef..0000000000 --- a/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Bme680.PressureUnit.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Meadow.Foundation.Sensors.Atmospheric -{ - public partial class Bme680 - { - public enum PressureUnit - { - Pa, - Psia, - Atm - } - } -} \ No newline at end of file diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Bme680.RegisterAddresses.cs b/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Bme680.RegisterAddresses.cs index 3b6e3a241e..f988410ab8 100644 --- a/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Bme680.RegisterAddresses.cs +++ b/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Bme680.RegisterAddresses.cs @@ -12,7 +12,7 @@ public enum Addresses : byte Default = Address0 } - class RegisterAddresses + internal class RegisterAddresses { public static readonly Register Status = new Register(0x73, 1); public const byte Reset = 0xE0; diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Bme680.SensorSettings.cs b/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Bme680.SensorSettings.cs deleted file mode 100644 index c55d86b030..0000000000 --- a/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Bme680.SensorSettings.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Meadow.Foundation.Sensors.Atmospheric -{ - public partial class Bme680 - { - public class SensorSettings - { - public Oversample TemperatureOversample { get; set; } = Oversample.OversampleX16; - public Oversample PressureOversample { get; set; } = Oversample.OversampleX16; - public Oversample HumidityOversample { get; set; } = Oversample.OversampleX16; - public TemperatureUnit TemperatureUnit { get; set; } = TemperatureUnit.C; - public PressureUnit PressureUnit { get; set; } = PressureUnit.Pa; - - /// - /// Get the measurements in the standard metric system - /// - public static SensorSettings SI => new SensorSettings(); - - /// - /// Get the measurements in the United States Customary Units - /// - public static SensorSettings USCU => new SensorSettings() { PressureUnit = PressureUnit.Psia, TemperatureUnit = TemperatureUnit.F }; - } - } -} diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Bme680.TemperatureCompensation.cs b/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Bme680.TemperatureCompensation.cs index 21105e12d1..6d77accbe5 100644 --- a/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Bme680.TemperatureCompensation.cs +++ b/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Bme680.TemperatureCompensation.cs @@ -1,12 +1,11 @@ using System; using System.Collections.Generic; -using Meadow.Hardware; namespace Meadow.Foundation.Sensors.Atmospheric { public partial class Bme680 { - public class TemperatureCompensation + protected class TemperatureCompensation { public TemperatureCompensation(IReadOnlyList rawCompData) { diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Bme680.TemperatureUnit.cs b/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Bme680.TemperatureUnit.cs deleted file mode 100644 index 6b68725ab3..0000000000 --- a/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Bme680.TemperatureUnit.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Meadow.Foundation.Sensors.Atmospheric -{ - public partial class Bme680 - { - public enum TemperatureUnit - { - C, - F - } - } -} \ No newline at end of file diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Bme680.cs b/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Bme680.cs index ed1010187b..db51c1c6a6 100644 --- a/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Bme680.cs +++ b/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Bme680.cs @@ -1,83 +1,273 @@ using System; +using System.Threading.Tasks; using Meadow.Hardware; +using Meadow.Peripherals.Sensors; +using Meadow.Units; +using PU = Meadow.Units.Pressure.UnitType; +using TU = Meadow.Units.Temperature.UnitType; +using HU = Meadow.Units.RelativeHumidity.UnitType; +using Meadow.Devices; +using System.Buffers; +using Meadow.Utilities; namespace Meadow.Foundation.Sensors.Atmospheric { - public partial class Bme680 : I2cPeripheral + /// + /// BME680 Temperature, Pressure and Humidity Sensor. + /// + /// + /// This class implements the functionality necessary to read the temperature, pressure and humidity + /// from the Bosch BME680 sensor. + /// + public partial class Bme680: + SamplingSensorBase<(Units.Temperature? Temperature, RelativeHumidity? Humidity, Pressure? Pressure)>, + ITemperatureSensor, IHumiditySensor, IBarometricPressureSensor { - private SensorSettings _settings; - private readonly object _lock; - private bool _initialized; - public bool IsSampling { get; private set; } + //==== events + /// + /// + public event EventHandler> TemperatureUpdated = delegate { }; + public event EventHandler> PressureUpdated = delegate { }; + public event EventHandler> HumidityUpdated = delegate { }; - protected Memory readBuffer = new byte[25]; + //==== internals + protected Memory readBuffer = new byte[32]; + protected Memory writeBuffer = new byte[32]; - public Bme680(II2cBus bus, byte address = (byte)Addresses.Default, SensorSettings sensorSettings = null) : base(bus, address) + //==== properties + public Oversample TemperatureSampleCount { get; set; } = Oversample.OversampleX8; + public Oversample PressureSampleCount { get; set; } = Oversample.OversampleX8; + public Oversample HumiditySampleCount { get; set; } = Oversample.OversampleX8; + private Configuration configuration; + + /// + /// Communication bus used to read and write to the BME280 sensor. + /// + /// + /// The BME has both I2C and SPI interfaces. The ICommunicationBus allows the + /// selection to be made in the constructor. + /// + private readonly Bme680Comms bme680Comms; + + /// + /// Compensation data from the sensor. + /// + protected TemperatureCompensation temperatureCompensation; + protected PressureCompensation pressureCompensation; + protected HumidityCompensation humidityCompensation; + + + /// + /// The temperature, in degrees celsius (°C), from the last reading. + /// + public Units.Temperature? Temperature => Conditions.Temperature; + + /// + /// The pressure, in hectopascals (hPa), from the last reading. 1 hPa + /// is equal to one millibar, or 1/10th of a kilopascal (kPa)/centibar. + /// + public Pressure? Pressure => Conditions.Pressure; + + /// + /// The humidity, in percent relative humidity, from the last reading.. + /// + public RelativeHumidity? Humidity => Conditions.Humidity; + + /// + /// Initializes a new instance of the class. + /// + /// I2C Bus to use for communicating with the sensor + /// I2C address of the sensor. + public Bme680(II2cBus i2cBus, byte address = (byte)Addresses.Default) { - if (sensorSettings == null) - sensorSettings = new SensorSettings(); - _settings = sensorSettings; - _lock = new object(); - _initialized = false; + bme680Comms = new Bme680I2C(i2cBus, address); + configuration = new Configuration(); // here to avoid the warning + Initialize(); } - private void Initialize() + public Bme680(IMeadowDevice device, ISpiBus spiBus, IPin chipSelectPin) : + this(spiBus, device.CreateDigitalOutputPort(chipSelectPin)) { - lock (_lock) - { - if (_initialized) - return; - Console.WriteLine("Initializing Temperature and Pressure"); - // Init the temp and pressure registers - // Clear the registers so they're in a known state. - var status = (byte)((((byte)_settings.TemperatureOversample << 5) & 0xe0) | - (((byte)_settings.PressureOversample << 2) & 0x1c)); - WriteRegister(RegisterAddresses.ControlTemperatureAndPressure, status); - - // Init the humidity registers - Console.WriteLine("Initializing Humidity"); - status = (byte)((byte)_settings.HumidityOversample & 0x07); - WriteRegister(RegisterAddresses.ControlHumidity, status); - - Console.WriteLine("Finished initializing."); - _initialized = true; - } } - public void UpdateSensorSettings(SensorSettings sensorSettings) + public Bme680(ISpiBus spiBus, IDigitalOutputPort chipSelectPort, Configuration sensorSettings = null) { - _settings = sensorSettings; + bme680Comms = new Bme680SPI(spiBus, chipSelectPort); + configuration = new Configuration(); // here to avoid the warning Initialize(); } - public SensorReading? Read() + /// + /// + /// + protected void Initialize() { - Initialize(); - try + // Init the temp and pressure registers + // Clear the registers so they're in a known state. + var status = (byte)((((byte)configuration.TemperatureOversample << 5) & 0xe0) | + (((byte)configuration.PressureOversample << 2) & 0x1c)); + + bme680Comms.WriteRegister(RegisterAddresses.ControlTemperatureAndPressure.Address, status); + + // Init the humidity registers + status = (byte)((byte)configuration.HumidityOversample & 0x07); + bme680Comms.WriteRegister(RegisterAddresses.ControlHumidity.Address, status); + } + + protected override void RaiseEventsAndNotify(IChangeResult<(Units.Temperature? Temperature, RelativeHumidity? Humidity, Pressure? Pressure)> changeResult) + { + if (changeResult.New.Temperature is { } temp) { + TemperatureUpdated?.Invoke(this, new ChangeResult(temp, changeResult.Old?.Temperature)); + } + if (changeResult.New.Humidity is { } humidity) { + HumidityUpdated?.Invoke(this, new ChangeResult(humidity, changeResult.Old?.Humidity)); + } + if (changeResult.New.Pressure is { } pressure) { + PressureUpdated?.Invoke(this, new ChangeResult(pressure, changeResult.Old?.Pressure)); + } + base.RaiseEventsAndNotify(changeResult); + } + + protected override async Task<(Units.Temperature? Temperature, RelativeHumidity? Humidity, Pressure? Pressure)> ReadSensor() + { + Console.WriteLine("F"); + + configuration.TemperatureOversample = TemperatureSampleCount; + configuration.PressureOversample = PressureSampleCount; + configuration.HumidityOversample = HumiditySampleCount; + + return await Task.Run(() => + { + (Units.Temperature Temperature, RelativeHumidity Humidity, Pressure Pressure) conditions; + + // Read the current control register + var status = bme680Comms.ReadRegister(RegisterAddresses.ControlTemperatureAndPressure.Address); + + // Force a sample + status = BitHelpers.SetBit(status, 0x00, true); + + Console.WriteLine("GGG"); + + bme680Comms.WriteRegister(RegisterAddresses.ControlTemperatureAndPressure.Address, status); + // Wait for the sample to be taken. + do + { + status = bme680Comms.ReadRegister(RegisterAddresses.ControlTemperatureAndPressure.Address); + } while (BitHelpers.GetBitValue(status, 0x00)); + + Console.WriteLine("H"); + + var sensorData = readBuffer.Span[0..RegisterAddresses.AllSensors.Length]; + bme680Comms.ReadRegisters(RegisterAddresses.AllSensors.Address, sensorData); + + Console.WriteLine("I"); + + var rawPressure = GetRawValue(sensorData.Slice(0, 3)); + var rawTemperature = GetRawValue(sensorData.Slice(3, 3)); + var rawHumidity = GetRawValue(sensorData.Slice(6, 2)); + //var rawVoc = GetRawValue(sensorData.Slice(8, 2)); + + Console.WriteLine("J"); + + bme680Comms.ReadRegisters(RegisterAddresses.CompensationData1.Address, readBuffer.Span[0..RegisterAddresses.CompensationData1.Length]); + var compensationData1 = readBuffer.Span[0..RegisterAddresses.CompensationData1.Length].ToArray(); + + bme680Comms.ReadRegisters(RegisterAddresses.CompensationData2.Address, readBuffer.Span[0..RegisterAddresses.CompensationData2.Length]); + var compensationData2 = readBuffer.Span[0..RegisterAddresses.CompensationData2.Length].ToArray(); + + Console.WriteLine("K"); + + var compensationData = ArrayPool.Shared.Rent(64); + try + { + Array.Copy(compensationData1, 0, compensationData, 0, compensationData1.Length); + Array.Copy(compensationData2, 0, compensationData, 25, compensationData2.Length); + + var temp = RawToTemp(rawTemperature, + new TemperatureCompensation(compensationData)); + + var pressure = RawToPressure(temp, rawPressure, + new PressureCompensation(compensationData)); + var humidity = RawToHumidity(temp, rawHumidity, + new HumidityCompensation(compensationData)); + + conditions.Temperature = new Units.Temperature(temp, TU.Celsius); + conditions.Pressure = new Pressure(pressure, PU.Pascal); + conditions.Humidity = new RelativeHumidity(humidity, HU.Percent); + } + finally + { + ArrayPool.Shared.Return(compensationData, true); + } + + Console.WriteLine("Return conditions"); + return conditions; + }); + } + + private static int GetRawValue(Span data) + { + if (data.Length == 3) { - return SensorReading.CreateFromDevice(this, _settings); + return (data[0] << 12) | (data[1] << 4) | ((data[2] >> 4) & 0x0f); } - catch (Exception ex) + if (data.Length == 2) { - Console.WriteLine(ex); + return (data[0] << 8) | data[1]; } - return null; + return 0; + } + + private static double RawToTemp(int adcTemperature, TemperatureCompensation temperatureCompensation) + { + var var1 = ((adcTemperature / 16384.0M) - (temperatureCompensation.T1 / 1024.0M)) * + temperatureCompensation.T2; + var var2 = ((adcTemperature / 131072M) - (temperatureCompensation.T1 / 8192.0M)); + var var3 = var2 * ((adcTemperature / 131072.0M) - (temperatureCompensation.T1 / 8192.0M)); + var var4 = var3 * (temperatureCompensation.T3 * 16.0M); + var tFine = var1 + var4; + return Convert.ToDouble(tFine / 5120.0M); + } + + private static double RawToPressure(double temp, int adcPressure, PressureCompensation pressureCompensation) + { + var tFine = temp * 5120; + var var1 = (tFine / 2.0) - 64000.0; + var var2 = var1 * var1 * (pressureCompensation.P6 / 131072.0); + var2 += (var1 * pressureCompensation.P5 * 2.0); + var2 = (var2 / 4.0) + (pressureCompensation.P4 * 65536.0); + var1 = (((pressureCompensation.P3 * var1 * var1) / 16384.0) + + (pressureCompensation.P2 * var1)) / 524288.0; + var1 = (1.0 + (var1 / 32768.0)) * pressureCompensation.P1; + var calcPress = 1048576.0 - adcPressure; + calcPress = ((calcPress - (var2 / 4096.0)) * 6250.0) / var1; + var1 = (pressureCompensation.P9 * calcPress * calcPress) / 2147483648.0; + var2 = calcPress * (pressureCompensation.P8 / 32768.0); + var var3 = (calcPress / 256.0) * (calcPress / 256.0) * (calcPress / 256.0) * + (pressureCompensation.P10 / 131072.0); + calcPress += (var1 + var2 + var3 + (pressureCompensation.P7 * 128.0)) / 16.0; + return calcPress; + } + + private static double RawToHumidity(double temp, int adcHumidity, HumidityCompensation humidityCompensation) + { + var var1 = adcHumidity - ((humidityCompensation.H1 * 16.0) + ((humidityCompensation.H3 / 2.0) * temp)); + var var2 = var1 * ((humidityCompensation.H2 / 262144.0) * (1.0 + ((humidityCompensation.H4 / 16384.0) * temp) + ((humidityCompensation.H5 / 1048576.0) * temp * temp))); + var var3 = humidityCompensation.H6 / 16384.0; + var var4 = humidityCompensation.H7 / 2097152.0; + return var2 + ((var3 + (var4 * temp)) * var2 * var2); } private byte ReadRegister(Register register) { - return ReadRegister(register.Address); + return bme680Comms.ReadRegister(register.Address); } private Span ReadRegisters(Register register) - { - ReadRegister(register.Address, readBuffer.Span[0..register.Length]); + { + bme680Comms.ReadRegisters(register.Address, readBuffer.Span[0..register.Length]); return readBuffer.Slice(0, register.Length).Span; } - private void WriteRegister(Register register, byte data) - { - WriteRegister(register.Address, data); - } } } diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Bme680Comms.cs b/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Bme680Comms.cs new file mode 100644 index 0000000000..ef39b78163 --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Bme680Comms.cs @@ -0,0 +1,12 @@ +using System; + +namespace Meadow.Foundation.Sensors.Atmospheric +{ + internal abstract class Bme680Comms + { + public abstract void WriteRegister(byte register, byte value); + public abstract void ReadRegisters(byte address, Span readBuffer); + + public abstract byte ReadRegister(byte address); + } +} \ No newline at end of file diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Bme680I2C.cs b/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Bme680I2C.cs new file mode 100644 index 0000000000..36cc8af4be --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Bme680I2C.cs @@ -0,0 +1,27 @@ +using System; +using Meadow.Hardware; + +namespace Meadow.Foundation.Sensors.Atmospheric +{ + internal class Bme680I2C : Bme680Comms + { + protected I2cPeripheral i2CPeripheral; + + internal Bme680I2C(II2cBus i2c, byte busAddress) + { + i2CPeripheral = new I2cPeripheral(i2c, busAddress); + } + + public override byte ReadRegister(byte register) => i2CPeripheral.ReadRegister(register); + + public override void ReadRegisters(byte register, Span readBuffer) + { + i2CPeripheral.ReadRegister(register, readBuffer); + } + + public override void WriteRegister(byte register, byte value) + { + i2CPeripheral.WriteRegister(register, value); + } + } +} \ No newline at end of file diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Bme680SPI.cs b/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Bme680SPI.cs new file mode 100644 index 0000000000..3ca3337823 --- /dev/null +++ b/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Bme680SPI.cs @@ -0,0 +1,33 @@ +using System; +using Meadow.Hardware; + +namespace Meadow.Foundation.Sensors.Atmospheric +{ + internal class Bme680SPI : Bme680Comms + { + ISpiPeripheral spiPeripheral; + + public override byte ReadRegister(byte register) => spiPeripheral.ReadRegister(register); + + internal Bme680SPI(ISpiBus spi, IDigitalOutputPort? chipSelect = null) + { + spiPeripheral = new SpiPeripheral(spi, chipSelect); + } + + public override void ReadRegisters(byte startRegister, Span readBuffer) + { + spiPeripheral.ReadRegister(startRegister, readBuffer); + + // skip past the byte where we clocked out the register address + for (int i = 1; i < readBuffer.Length; i++) + { + readBuffer[i - 1] = readBuffer[i]; + } + } + + public override void WriteRegister(byte register, byte value) + { + spiPeripheral.WriteRegister(register, value); + } + } +} \ No newline at end of file diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Helpers.cs b/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Helpers.cs deleted file mode 100644 index 584301a76b..0000000000 --- a/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Driver/Sensors.Atmospheric.Bme680/Helpers.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.Collections; -using System.Linq; -using System.Text; - -namespace Meadow.Foundation.Sensors.Atmospheric -{ - public static class Helpers - { - public static string ToBitString(this byte @byte) - { - return Convert.ToString(@byte, 2); - } - - public static string ToBitString(this byte[] bytes) - { - return string.Join(" ", bytes.Select(x => Convert.ToString(x,2))); - } - - public static string ToBitString(this Span bytes) - { - var sb = new StringBuilder(); - foreach (var b in bytes) - { - sb.Append($"{Convert.ToString(b,2)} "); - } - - return sb.ToString(); - } - - public static int ToInt(byte lsb, byte msb) - { - var bytes = new byte[] {0x00, 0x00, msb, lsb}; - if (BitConverter.IsLittleEndian) - { - Array.Reverse(bytes); - } - - return BitConverter.ToInt32(bytes); - } - } -} diff --git a/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Samples/Bme680_Sample/MeadowApp.cs b/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Samples/Bme680_Sample/MeadowApp.cs index 3f0326661c..fe8780ef37 100644 --- a/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Samples/Bme680_Sample/MeadowApp.cs +++ b/Source/Meadow.Foundation.Peripherals/Sensors.Atmospheric.Bme680/Samples/Bme680_Sample/MeadowApp.cs @@ -2,18 +2,91 @@ using Meadow.Devices; using Meadow.Foundation.Sensors.Atmospheric; using System; +using System.Threading.Tasks; namespace Sensors.Atmospheric.BME680_Sample { public class MeadowApp : App { - Bme680 bme680; + // + + Bme680 sensor; public MeadowApp() { Console.WriteLine("Initializing..."); - bme680 = new Bme680(Device.CreateI2cBus()); + CreateSpiSensor(); + //CreateI2CSensor(); + + Console.WriteLine("A"); + + var consumer = Bme680.CreateObserver( + handler: result => + { + Console.WriteLine($"Observer: Temp changed by threshold; new temp: {result.New.Temperature?.Celsius:N2}C, old: {result.Old?.Temperature?.Celsius:N2}C"); + }, + filter: result => + { + //c# 8 pattern match syntax. checks for !null and assigns var. + if (result.Old is { } old) + { + return ( + (result.New.Temperature.Value - old.Temperature.Value).Abs().Celsius > 0.5 + && + (result.New.Humidity.Value - old.Humidity.Value).Percent > 0.05 + ); + } + return false; + } + ); + sensor.Subscribe(consumer); + + Console.WriteLine("B"); + + sensor.Updated += (sender, result) => { + Console.WriteLine($" Temperature: {result.New.Temperature?.Celsius:N2}C"); + Console.WriteLine($" Relative Humidity: {result.New.Humidity:N2}%"); + Console.WriteLine($" Pressure: {result.New.Pressure?.Millibar:N2}mbar ({result.New.Pressure?.Pascal:N2}Pa)"); + }; + + Console.WriteLine("D"); + + sensor.StartUpdating(TimeSpan.FromSeconds(1)); + + Console.WriteLine("C"); + + ReadConditions().Wait(); + + Console.WriteLine("E"); } + + void CreateSpiSensor() + { + Console.WriteLine("Create BME680 sensor with SPI..."); + + var spiBus = Device.CreateSpiBus(); + sensor = new Bme680(spiBus, Device.CreateDigitalOutputPort(Device.Pins.D14)); + } + + void CreateI2CSensor() + { + Console.WriteLine("Create BME680 sensor with I2C..."); + + var i2c = Device.CreateI2cBus(); + sensor = new Bme680(i2c, (byte)Bme680.Addresses.Default); // SDA pulled up + + } + + async Task ReadConditions() + { + var conditions = await sensor.Read(); + Console.WriteLine("Initial Readings:"); + Console.WriteLine($" Temperature: {conditions.Temperature?.Celsius:N2}C"); + Console.WriteLine($" Pressure: {conditions.Pressure?.Bar:N2}hPa"); + Console.WriteLine($" Relative Humidity: {conditions.Humidity?.Percent:N2}%"); + } + + // } } \ No newline at end of file