Skip to content

Commit

Permalink
Bmxx80 API modification (dotnet#797)
Browse files Browse the repository at this point in the history
* Add ReadResult class

* Add Read/ReadAsync methods for ease of use

* Use nullable Properties, update samples

* Fix UnitsNet related exceptions, remove redundancies
  • Loading branch information
RobinTTY authored and Oliver Christen committed Dec 14, 2020
1 parent 73d02e3 commit a8d3140
Show file tree
Hide file tree
Showing 11 changed files with 450 additions and 222 deletions.
75 changes: 61 additions & 14 deletions src/devices/Bmxx80/Bme280.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@

using System;
using System.Device.I2c;
using System.Threading;
using System.Threading.Tasks;
using Iot.Device.Bmxx80.CalibrationData;
using Iot.Device.Bmxx80.PowerMode;
using Iot.Device.Bmxx80.ReadResult;
using Iot.Device.Bmxx80.Register;
using UnitsNet;

Expand Down Expand Up @@ -81,30 +85,53 @@ public Sampling HumiditySampling
/// Contains an undefined value if the return value is false.
/// </param>
/// <returns><code>true</code> if measurement was not skipped, otherwise <code>false</code>.</returns>
public bool TryReadHumidity(out Ratio humidity)
public bool TryReadHumidity(out Ratio humidity) => TryReadHumidityCore(out humidity);

/// <summary>
/// Gets the required time in ms to perform a measurement with the current sampling modes.
/// </summary>
/// <returns>The time it takes for the chip to read data in milliseconds rounded up.</returns>
public override int GetMeasurementDuration()
{
if (HumiditySampling == Sampling.Skipped)
return s_osToMeasCycles[(int)PressureSampling] + s_osToMeasCycles[(int)TemperatureSampling] + s_osToMeasCycles[(int)HumiditySampling];
}

/// <summary>
/// Performs a synchronous reading.
/// </summary>
/// <returns><see cref="Bme280ReadResult"/></returns>
public Bme280ReadResult Read()
{
if (ReadPowerMode() != Bmx280PowerMode.Normal)
{
humidity = default;
return false;
SetPowerMode(Bmx280PowerMode.Forced);
Thread.Sleep(GetMeasurementDuration());
}

// Read the temperature first to load the t_fine value for compensation.
TryReadTemperature(out _);

var hum = Read16BitsFromRegister((byte)Bme280Register.HUMIDDATA, Endianness.BigEndian);
var tempSuccess = TryReadTemperatureCore(out var temperature);
var pressSuccess = TryReadPressureCore(out var pressure, skipTempFineRead: true);
var humiditySuccess = TryReadHumidityCore(out var humidity, skipTempFineRead: true);

humidity = CompensateHumidity(hum);
return true;
return new Bme280ReadResult(tempSuccess ? temperature : null, pressSuccess ? pressure : null, humiditySuccess ? humidity : null);
}

/// <summary>
/// Gets the required time in ms to perform a measurement with the current sampling modes.
/// Performs an asynchronous reading.
/// </summary>
/// <returns>The time it takes for the chip to read data in milliseconds rounded up.</returns>
public override int GetMeasurementDuration()
/// <returns><see cref="Bme280ReadResult"/></returns>
public async Task<Bme280ReadResult> ReadAsync()
{
return s_osToMeasCycles[(int)PressureSampling] + s_osToMeasCycles[(int)TemperatureSampling] + s_osToMeasCycles[(int)HumiditySampling];
if (ReadPowerMode() != Bmx280PowerMode.Normal)
{
SetPowerMode(Bmx280PowerMode.Forced);
await Task.Delay(GetMeasurementDuration());
}

var tempSuccess = TryReadTemperatureCore(out var temperature);
var pressSuccess = TryReadPressureCore(out var pressure, skipTempFineRead: true);
var humiditySuccess = TryReadHumidityCore(out var humidity, skipTempFineRead: true);

return new Bme280ReadResult(tempSuccess ? temperature : null, pressSuccess ? pressure : null, humiditySuccess ? humidity : null);
}

/// <summary>
Expand Down Expand Up @@ -141,5 +168,25 @@ private Ratio CompensateHumidity(int adcHumidity)

return Ratio.FromPercent(varH);
}

private bool TryReadHumidityCore(out Ratio humidity, bool skipTempFineRead = false)
{
if (HumiditySampling == Sampling.Skipped)
{
humidity = default;
return false;
}

if (!skipTempFineRead)
{
TryReadTemperature(out _);
}

// Read the temperature first to load the t_fine value for compensation.
var hum = Read16BitsFromRegister((byte)Bme280Register.HUMIDDATA, Endianness.BigEndian);

humidity = CompensateHumidity(hum);
return true;
}
}
}
178 changes: 115 additions & 63 deletions src/devices/Bmxx80/Bme680.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@
using System.Collections.Generic;
using System.Device.I2c;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Iot.Device.Bmxx80.CalibrationData;
using Iot.Device.Bmxx80.FilteringMode;
using Iot.Device.Bmxx80.PowerMode;
using Iot.Device.Bmxx80.ReadResult;
using Iot.Device.Bmxx80.Register;
using UnitsNet;

Expand Down Expand Up @@ -355,6 +358,40 @@ public Duration GetMeasurementDuration(Bme680HeaterProfile profile)
return Duration.FromMilliseconds(Math.Ceiling(measDuration));
}

/// <summary>
/// Performs a synchronous reading.
/// </summary>
/// <returns><see cref="Bme680ReadResult"/></returns>
public Bme680ReadResult Read()
{
SetPowerMode(Bme680PowerMode.Forced);
Thread.Sleep((int)GetMeasurementDuration(HeaterProfile).Milliseconds);

var tempSuccess = TryReadTemperatureCore(out var temperature);
var pressSuccess = TryReadPressureCore(out var pressure, skipTempFineRead: true);
var humiditySuccess = TryReadHumidityCore(out var humidity, skipTempFineRead: true);
var gasSuccess = TryReadGasResistanceCore(out var gasResistance);

return new Bme680ReadResult(tempSuccess ? temperature : null, pressSuccess ? pressure : null, humiditySuccess ? humidity : null, gasSuccess ? gasResistance : null);
}

/// <summary>
/// Performs an asynchronous reading.
/// </summary>
/// <returns><see cref="Bme680ReadResult"/></returns>
public async Task<Bme680ReadResult> ReadAsync()
{
SetPowerMode(Bme680PowerMode.Forced);
await Task.Delay((int)GetMeasurementDuration(HeaterProfile).Milliseconds);

var tempSuccess = TryReadTemperatureCore(out var temperature);
var pressSuccess = TryReadPressureCore(out var pressure, skipTempFineRead: true);
var humiditySuccess = TryReadHumidityCore(out var humidity, skipTempFineRead: true);
var gasSuccess = TryReadGasResistanceCore(out var gasResistance);

return new Bme680ReadResult(tempSuccess ? temperature : null, pressSuccess ? pressure : null, humiditySuccess ? humidity : null, gasSuccess ? gasResistance : null);
}

/// <summary>
/// Reads the humidity. A return value indicates whether the reading succeeded.
/// </summary>
Expand All @@ -363,21 +400,7 @@ public Duration GetMeasurementDuration(Bme680HeaterProfile profile)
/// Contains <see cref="double.NaN"/> otherwise.
/// </param>
/// <returns><code>true</code> if measurement was not skipped, otherwise <code>false</code>.</returns>
public bool TryReadHumidity(out Ratio humidity)
{
if (HumiditySampling == Sampling.Skipped)
{
humidity = default;
return false;
}

// Read humidity data.
var hum = Read16BitsFromRegister((byte)Bme680Register.HUMIDITYDATA, Endianness.BigEndian);

TryReadTemperature(out _);
humidity = CompensateHumidity(hum);
return true;
}
public bool TryReadHumidity(out Ratio humidity) => TryReadHumidityCore(out humidity);

/// <summary>
/// Reads the pressure. A return value indicates whether the reading succeeded.
Expand All @@ -387,23 +410,7 @@ public bool TryReadHumidity(out Ratio humidity)
/// Contains <see cref="double.NaN"/> otherwise.
/// </param>
/// <returns><code>true</code> if measurement was not skipped, otherwise <code>false</code>.</returns>
public override bool TryReadPressure(out Pressure pressure)
{
if (PressureSampling == Sampling.Skipped)
{
pressure = Pressure.FromPascals(double.NaN);
return false;
}

// Read pressure data.
var press = (int)Read24BitsFromRegister((byte)Bme680Register.PRESSUREDATA, Endianness.BigEndian);

// Read the temperature first to load the t_fine value for compensation.
TryReadTemperature(out _);

pressure = CompensatePressure(press >> 4);
return true;
}
public override bool TryReadPressure(out Pressure pressure) => TryReadPressureCore(out pressure);

/// <summary>
/// Reads the temperature. A return value indicates whether the reading succeeded.
Expand All @@ -413,19 +420,7 @@ public override bool TryReadPressure(out Pressure pressure)
/// Contains <see cref="double.NaN"/> otherwise.
/// </param>
/// <returns><code>true</code> if measurement was not skipped, otherwise <code>false</code>.</returns>
public override bool TryReadTemperature(out Temperature temperature)
{
if (TemperatureSampling == Sampling.Skipped)
{
temperature = Temperature.FromDegreesCelsius(double.NaN);
return false;
}

var temp = (int)Read24BitsFromRegister((byte)Bme680Register.TEMPDATA, Endianness.BigEndian);

temperature = CompensateTemperature(temp >> 4);
return true;
}
public override bool TryReadTemperature(out Temperature temperature) => TryReadTemperatureCore(out temperature);

/// <summary>
/// Reads the gas resistance. A return value indicates whether the reading succeeded.
Expand All @@ -435,24 +430,7 @@ public override bool TryReadTemperature(out Temperature temperature)
/// the measurement was valid. Undefined otherwise.
/// </param>
/// <returns><code>true</code> if measurement was not skipped, otherwise <code>false</code>.</returns>
public bool TryReadGasResistance(out ElectricResistance gasResistance)
{
if (!ReadGasMeasurementIsValid() || !ReadHeaterIsStable())
{
gasResistance = default;
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;
}
public bool TryReadGasResistance(out ElectricResistance gasResistance) => TryReadGasResistanceCore(out gasResistance);

/// <summary>
/// Sets the default configuration for the sensor.
Expand Down Expand Up @@ -623,5 +601,79 @@ private byte CalculateHeaterDuration(Duration duration)

return durationValue;
}

private bool TryReadTemperatureCore(out Temperature temperature)
{
if (TemperatureSampling == Sampling.Skipped)
{
temperature = default;
return false;
}

var temp = (int)Read24BitsFromRegister((byte)Bme680Register.TEMPDATA, Endianness.BigEndian);

temperature = CompensateTemperature(temp >> 4);
return true;
}

private bool TryReadHumidityCore(out Ratio humidity, bool skipTempFineRead = false)
{
if (HumiditySampling == Sampling.Skipped)
{
humidity = default;
return false;
}

// Read humidity data.
var hum = Read16BitsFromRegister((byte)Bme680Register.HUMIDITYDATA, Endianness.BigEndian);

if (!skipTempFineRead)
{
TryReadTemperatureCore(out _);
}

humidity = CompensateHumidity(hum);
return true;
}

private bool TryReadPressureCore(out Pressure pressure, bool skipTempFineRead = false)
{
if (PressureSampling == Sampling.Skipped)
{
pressure = default;
return false;
}

// Read pressure data.
var press = (int)Read24BitsFromRegister((byte)Bme680Register.PRESSUREDATA, Endianness.BigEndian);

// Read the temperature first to load the t_fine value for compensation.
if (!skipTempFineRead)
{
TryReadTemperatureCore(out _);
}

pressure = CompensatePressure(press >> 4);
return true;
}

private bool TryReadGasResistanceCore(out ElectricResistance gasResistance)
{
if (!ReadGasMeasurementIsValid() || !ReadHeaterIsStable())
{
gasResistance = default;
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;
}
}
}
43 changes: 41 additions & 2 deletions src/devices/Bmxx80/Bmp280.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Device.I2c;
using Iot.Device.Bmxx80.Register;
using System.Threading;
using System.Threading.Tasks;
using Iot.Device.Bmxx80.PowerMode;
using Iot.Device.Bmxx80.ReadResult;
using UnitsNet;

namespace Iot.Device.Bmxx80
{
Expand All @@ -26,5 +29,41 @@ public Bmp280(I2cDevice i2cDevice)
{
_communicationProtocol = CommunicationProtocol.I2c;
}

/// <summary>
/// Performs a synchronous reading.
/// </summary>
/// <returns><see cref="Bmp280ReadResult"/></returns>
public Bmp280ReadResult Read()
{
if (ReadPowerMode() != Bmx280PowerMode.Normal)
{
SetPowerMode(Bmx280PowerMode.Forced);
Thread.Sleep(GetMeasurementDuration());
}

var tempSuccess = TryReadTemperatureCore(out var temperature);
var pressSuccess = TryReadPressureCore(out var pressure, skipTempFineRead: true);

return new Bmp280ReadResult(tempSuccess ? temperature : null, pressSuccess ? pressure : null);
}

/// <summary>
/// Performs an asynchronous reading.
/// </summary>
/// <returns><see cref="Bmp280ReadResult"/></returns>
public async Task<Bmp280ReadResult> ReadAsync()
{
if (ReadPowerMode() != Bmx280PowerMode.Normal)
{
SetPowerMode(Bmx280PowerMode.Forced);
await Task.Delay(GetMeasurementDuration());
}

var tempSuccess = TryReadTemperatureCore(out var temperature);
var pressSuccess = TryReadPressureCore(out var pressure, skipTempFineRead: true);

return new Bmp280ReadResult(tempSuccess ? temperature : null, pressSuccess ? pressure : null);
}
}
}
Loading

0 comments on commit a8d3140

Please sign in to comment.