未验证 提交 35ecfd21 编写于 作者: Z Zdenek Havlin 提交者: GitHub

#1694 Handle `STATUS_REG` error correctly: distinguishing ext. temp and light sensor (#1695)

* #1694 Handle `STATUS_REG` error correctly - distinguishing ext. temp and light sensor

* #1694 Update xml doc
上级 b0fc3c2e
......@@ -19,6 +19,8 @@ namespace Iot.Device.SensorHub
/// </summary>
public const int DefaultI2cAddress = 0x17;
internal const byte NO_ERROR = 0x0;
private readonly I2cDevice _i2cDevice;
/// <summary>
......@@ -43,23 +45,24 @@ namespace Iot.Device.SensorHub
/// </summary>
/// <remarks>Range is -30 to 127 Celsius.</remarks>
/// <param name="temperature">The temperature if successful</param>
/// <returns></returns>
/// <returns><c>True</c> on success, <c>False</c> otherwise</returns>
/// <exception cref="IOException">Thrown when ext. temperature sensor not found.</exception>
public bool TryReadOffBoardTemperature(out Temperature temperature)
{
temperature = Temperature.MaxValue;
var status = ReadRegister(Register.STATUS_REG);
if (status.Equals((byte)RegisterStatusErrors.OFFBOARD_TEMPERATURE_SENSOR_NOT_FOUND))
if (IsStatusRegError(status, StatusFunctionError.TEMP_NOT_FOUND))
{
throw new IOException("No offboard temperature sensor found");
}
if (status.Equals((byte)RegisterStatusErrors.NO_ERROR))
else if (IsStatusRegError(status, StatusFunctionError.TEMP_OVERFLOW))
{
temperature = Temperature.FromDegreesCelsius(ReadRegister(Register.TEMP_REG));
return true;
return false;
}
return false;
temperature = Temperature.FromDegreesCelsius(ReadRegister(Register.TEMP_REG));
return true;
}
/// <summary>
......@@ -67,11 +70,11 @@ namespace Iot.Device.SensorHub
/// </summary>
/// <remarks>Range is -40 to 80 Celsius.</remarks>
/// <param name="temperature">Temperature if successful</param>
/// <returns></returns>
/// <returns><c>True</c> on success, <c>False</c> otherwise</returns>
public bool TryReadBarometerTemperature(out Temperature temperature)
{
temperature = Temperature.MaxValue;
if (ReadRegister(Register.BMP280_STATUS).Equals((byte)RegisterStatusErrors.NO_ERROR))
if (ReadRegister(Register.BMP280_STATUS).Equals(NO_ERROR))
{
temperature = Temperature.FromDegreesCelsius(ReadRegister(Register.BMP280_TEMP_REG));
return true;
......@@ -85,11 +88,11 @@ namespace Iot.Device.SensorHub
/// </summary>
/// <remarks>Range is 300Pa to 1100hPa</remarks>
/// <param name="pressure">Pressure if successful</param>
/// <returns></returns>
/// <returns><c>True</c> on success, <c>False</c> otherwise</returns>
public bool TryReadBarometerPressure(out Pressure pressure)
{
pressure = Pressure.MaxValue;
if (ReadRegister(Register.BMP280_STATUS).Equals((byte)RegisterStatusErrors.NO_ERROR))
if (ReadRegister(Register.BMP280_STATUS).Equals(NO_ERROR))
{
Span<byte> bytes = stackalloc byte[4]
{
......@@ -111,23 +114,26 @@ namespace Iot.Device.SensorHub
/// </summary>
/// <remarks>Range is 0 to 1800 Lux.</remarks>
/// <param name="illuminance">Illuminance if successful</param>
/// <returns></returns>
/// <returns><c>True</c> on success, <c>False</c> otherwise</returns>
public bool TryReadIlluminance(out Illuminance illuminance)
{
illuminance = Illuminance.MaxValue;
if (ReadRegister(Register.STATUS_REG).Equals((byte)RegisterStatusErrors.NO_ERROR))
{
Span<byte> bytes = stackalloc byte[2]
{
ReadRegister(Register.LIGHT_REG_H),
ReadRegister(Register.LIGHT_REG_L)
};
illuminance = new(BinaryPrimitives.ReadInt16BigEndian(bytes), UnitsNet.Units.IlluminanceUnit.Lux);
return true;
var status = ReadRegister(Register.STATUS_REG);
if (IsStatusRegError(status, StatusFunctionError.LIGHT_BRIGHTNESS_NOT_FOUND)
|| IsStatusRegError(status, StatusFunctionError.LIGHT_BRIGHTNESS_OVERFLOW))
{
return false;
}
return false;
Span<byte> bytes = stackalloc byte[2]
{
ReadRegister(Register.LIGHT_REG_H),
ReadRegister(Register.LIGHT_REG_L)
};
illuminance = new(BinaryPrimitives.ReadInt16BigEndian(bytes), UnitsNet.Units.IlluminanceUnit.Lux);
return true;
}
/// <summary>
......@@ -135,11 +141,11 @@ namespace Iot.Device.SensorHub
/// </summary>
/// <remarks>Range is 25 to 95 percent</remarks>
/// <param name="humidity">Relative humidity if successful</param>
/// <returns></returns>
/// <returns><c>True</c> on success, <c>False</c> otherwise</returns>
public bool TryReadRelativeHumidity(out RelativeHumidity humidity)
{
humidity = RelativeHumidity.MaxValue;
if (ReadRegister(Register.ON_BOARD_SENSOR_ERROR).Equals((byte)RegisterStatusErrors.NO_ERROR))
if (ReadRegister(Register.ON_BOARD_SENSOR_ERROR).Equals(NO_ERROR))
{
humidity = RelativeHumidity.FromPercent(ReadRegister(Register.ON_BOARD_HUMIDITY_REG));
return true;
......@@ -153,11 +159,11 @@ namespace Iot.Device.SensorHub
/// </summary>
/// <remakrs>Range is -20 to 60 Celsius</remakrs>
/// <param name="temperature">Temperature if successful</param>
/// <returns></returns>
/// <returns><c>True</c> on success, <c>False</c> otherwise</returns>
public bool TryReadOnBoardTemperature(out Temperature temperature)
{
temperature = Temperature.MaxValue;
if (ReadRegister(Register.ON_BOARD_SENSOR_ERROR).Equals((byte)RegisterStatusErrors.NO_ERROR))
if (ReadRegister(Register.ON_BOARD_SENSOR_ERROR).Equals(NO_ERROR))
{
temperature = Temperature.FromDegreesCelsius(ReadRegister(Register.ON_BOARD_TEMP_REG));
return true;
......@@ -171,6 +177,8 @@ namespace Iot.Device.SensorHub
/// </summary>
public bool IsMotionDetected => ReadRegister(Register.MOTION_DETECTED) == 1;
private static bool IsStatusRegError(byte status, StatusFunctionError error) => (status & (byte)error) != 0;
private byte ReadRegister(Register register)
{
_i2cDevice.WriteByte((byte)register);
......@@ -194,10 +202,12 @@ namespace Iot.Device.SensorHub
MOTION_DETECTED = 0x0D, // 0(No Active Body) - 1(Active Body)
}
internal enum RegisterStatusErrors : byte
internal enum StatusFunctionError : byte
{
NO_ERROR = 0x0, // No error reported
OFFBOARD_TEMPERATURE_SENSOR_NOT_FOUND = 0x02, // Offboard temperature sensor not found
TEMP_OVERFLOW = 0x01, // Ext. Temperature Overflow
TEMP_NOT_FOUND = 0x02, // Ext. Temperature Not Found
LIGHT_BRIGHTNESS_OVERFLOW = 0x04, // Light Brightness Overflow
LIGHT_BRIGHTNESS_NOT_FOUND = 0x08, // Light Brightness Not Found
}
}
}
......@@ -6,6 +6,7 @@ using System.Device.I2c;
using System.IO;
using Moq;
using Xunit;
using static Iot.Device.SensorHub.SensorHub;
namespace Iot.Device.SensorHub.Tests
{
......@@ -20,31 +21,44 @@ namespace Iot.Device.SensorHub.Tests
}
[Fact]
public void Should_Throw_When_No_Offboard_Sensor_Found()
public void Should_Throw_When_NoDevice_Found()
{
Func<SensorHub> sh = () => new(_mockI2cDevice.Object);
_mockI2cDevice.Setup(x => x.ReadByte()).Throws(new IOException("Not Connected"));
var exception = Assert.Throws<IOException>(sh);
Assert.StartsWith("No response from SensorHub", exception.Message);
}
[Fact]
public void Should_Throw_When_No_Offboard_Temperature_Sensor_Found()
{
SensorHub sh = new(_mockI2cDevice.Object);
_mockI2cDevice.SetupSequence(x => x.ReadByte())
.Returns((byte)SensorHub.RegisterStatusErrors.OFFBOARD_TEMPERATURE_SENSOR_NOT_FOUND);
.Returns((byte)SensorHub.StatusFunctionError.TEMP_NOT_FOUND);
var exception = Assert.Throws<IOException>(() => sh.TryReadOffBoardTemperature(out var t));
Assert.Equal("No offboard temperature sensor found", exception.Message);
}
[Fact]
public void Should_Throw_When_NoDevice_Found()
public void Should_Not_Read_Offboard_Temperature_On_Sensor_Overflow()
{
Func<SensorHub> sh = () => new(_mockI2cDevice.Object);
_mockI2cDevice.Setup(x => x.ReadByte()).Throws(new IOException("Not Connected"));
var exception = Assert.Throws<IOException>(sh);
Assert.StartsWith("No response from SensorHub", exception.Message);
SensorHub sh = new(_mockI2cDevice.Object);
_mockI2cDevice.SetupSequence(x => x.ReadByte())
.Returns((byte)StatusFunctionError.TEMP_OVERFLOW);
Assert.False(sh.TryReadOffBoardTemperature(out _));
}
[Fact]
public void Should_Read_Correct_Offboard_Sensor_Temperature()
[Theory]
[InlineData(0x00)] // No Error
[InlineData(0x04)] // Light Brightness Overflow
[InlineData(0x08)] // Light Brightness Not Found
public void Should_Read_Correct_Offboard_Sensor_Temperature(byte statusReg)
{
SensorHub sh = new(_mockI2cDevice.Object);
_mockI2cDevice.SetupSequence(x => x.ReadByte())
.Returns((byte)SensorHub.RegisterStatusErrors.NO_ERROR)
.Returns(statusReg)
.Returns(128);
sh.TryReadOffBoardTemperature(out var t);
......@@ -57,7 +71,7 @@ namespace Iot.Device.SensorHub.Tests
{
SensorHub sh = new(_mockI2cDevice.Object);
_mockI2cDevice.SetupSequence(x => x.ReadByte())
.Returns((byte)SensorHub.RegisterStatusErrors.NO_ERROR)
.Returns(SensorHub.NO_ERROR)
.Returns(50);
sh.TryReadBarometerTemperature(out var t);
......@@ -70,7 +84,7 @@ namespace Iot.Device.SensorHub.Tests
{
SensorHub sh = new(_mockI2cDevice.Object);
_mockI2cDevice.SetupSequence(x => x.ReadByte())
.Returns((byte)SensorHub.RegisterStatusErrors.NO_ERROR)
.Returns(SensorHub.NO_ERROR)
.Returns(0) // H
.Returns(19) // M
.Returns(136); // L
......@@ -80,12 +94,15 @@ namespace Iot.Device.SensorHub.Tests
Assert.Equal(p.Pascals, expected);
}
[Fact]
public void Should_Read_Correct_Illuminance()
[Theory]
[InlineData(0x00)] // No error
[InlineData(0x01)] // Ext. Temperature Overflow
[InlineData(0x02)] // Ext. Temperature Not Found
public void Should_Read_Correct_Illuminance(byte statusReg)
{
SensorHub sh = new(_mockI2cDevice.Object);
_mockI2cDevice.SetupSequence(x => x.ReadByte())
.Returns((byte)SensorHub.RegisterStatusErrors.NO_ERROR)
.Returns(statusReg)
.Returns(3) // H
.Returns(12); // L
......@@ -94,12 +111,24 @@ namespace Iot.Device.SensorHub.Tests
Assert.Equal(l.Lux, expected);
}
[Theory]
[InlineData(0x04)] // Light Brightness Overflow
[InlineData(0x08)] // Light Brightness Not Found
public void Should_Not_Read_Illuminance(byte statusReg)
{
SensorHub sh = new(_mockI2cDevice.Object);
_mockI2cDevice.SetupSequence(x => x.ReadByte())
.Returns(statusReg);
Assert.False(sh.TryReadIlluminance(out _));
}
[Fact]
public void Should_Read_Correct_Humidity()
{
SensorHub sh = new(_mockI2cDevice.Object);
_mockI2cDevice.SetupSequence(x => x.ReadByte())
.Returns((byte)SensorHub.RegisterStatusErrors.NO_ERROR)
.Returns(SensorHub.NO_ERROR)
.Returns(50);
sh.TryReadRelativeHumidity(out var h);
......@@ -112,7 +141,7 @@ namespace Iot.Device.SensorHub.Tests
{
SensorHub sh = new(_mockI2cDevice.Object);
_mockI2cDevice.SetupSequence(x => x.ReadByte())
.Returns((byte)SensorHub.RegisterStatusErrors.NO_ERROR)
.Returns(SensorHub.NO_ERROR)
.Returns(50);
sh.TryReadOnBoardTemperature(out var t);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册