// 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 NucuCar.Sensors.Environment.Bmxx80.CalibrationData;
using NucuCar.Sensors.Environment.Bmxx80.Register;
namespace NucuCar.Sensors.Environment.Bmxx80
{
///
/// Represents a BME280 temperature, barometric pressure and humidity sensor.
///
public class Bme280 : Bmx280Base
{
///
/// The expected chip ID of the BME280.
///
private const byte DeviceId = 0x60;
///
/// Calibration data for the .
///
private Bme280CalibrationData _bme280Calibration;
private Sampling _humiditySampling;
///
/// Initializes a new instance of the class.
///
/// The to create with.
public Bme280(I2cDevice i2cDevice)
: base(DeviceId, i2cDevice)
{
_bme280Calibration = (Bme280CalibrationData)_calibrationData;
_communicationProtocol = CommunicationProtocol.I2c;
}
///
/// Gets or sets the humidity sampling.
///
/// Thrown when the is set to an undefined mode.
public Sampling HumiditySampling
{
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;
}
}
///
/// 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 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;
}
///
/// Gets the required time in ms to perform a measurement with the current sampling modes.
///
/// The time it takes for the chip to read data in milliseconds rounded up.
public override int GetMeasurementDuration()
{
return s_osToMeasCycles[(int)PressureSampling] + s_osToMeasCycles[(int)TemperatureSampling] + s_osToMeasCycles[(int)HumiditySampling];
}
///
/// Sets the default configuration for the sensor.
///
protected override void SetDefaultConfiguration()
{
base.SetDefaultConfiguration();
HumiditySampling = Sampling.UltraLowPower;
}
///
/// Compensates the humidity.
///
/// The humidity value read from the device.
/// The percentage relative humidity.
private double CompensateHumidity(int adcHumidity)
{
// The humidity is calculated using the compensation formula in the BME280 datasheet.
double varH = TemperatureFine - 76800.0;
varH = (adcHumidity - (_bme280Calibration.DigH4 * 64.0 + _bme280Calibration.DigH5 / 16384.0 * varH)) *
(_bme280Calibration.DigH2 / 65536.0 * (1.0 + _bme280Calibration.DigH6 / 67108864.0 * varH *
(1.0 + _bme280Calibration.DigH3 / 67108864.0 * varH)));
varH *= 1.0 - _bme280Calibration.DigH1 * varH / 524288.0;
if (varH > 100)
{
varH = 100;
}
else if (varH < 0)
{
varH = 0;
}
return varH;
}
}
}