提交 0ba0b87d 编写于 作者: M Marcus Fehde

Review remarks. Timeout handling for Mhz19b changed.

上级 a1a24c16
......@@ -14,29 +14,15 @@ namespace Iot.Device.Ahtxx
/// Note: has been tested with AHT20 only, but should work with AHT10 and AHT15 as well.
/// Up to now all functions are contained in the base class, though there might be differences between the sensors types.
/// </summary>
public class AhtBase : IDisposable
public abstract class AhtBase : IDisposable
{
/// <summary>
/// Address of AHTxx device (0x38). This address is fix and cannot be changed.
/// This implies that only one device can be attached to a single I2C bus at a time.
/// </summary>
public const int DeviceAddress = 0x38;
public const int DefaultI2cAddress = 0x38;
// datasheet version 1.1, table 10
private enum StatusBit : byte
{
Calibrated = 0x08,
Busy = 0x80
}
private enum Command : byte
{
Calibrate = 0xbe,
SoftRest = 0xba,
Measure = 0xac
}
private I2cDevice _i2cDevice = null;
private I2cDevice _i2cDevice;
private double _temperature;
private double _humidity;
......@@ -93,6 +79,7 @@ namespace Iot.Device.Ahtxx
0x33,
0x00
};
_i2cDevice.Write(buffer);
// According to the datasheet the measurement takes 80 ms and completion is indicated by the status bit.
......@@ -122,7 +109,7 @@ namespace Iot.Device.Ahtxx
/// </summary>
private void SoftReset()
{
_i2cDevice.WriteByte((byte)Command.SoftRest);
_i2cDevice.WriteByte((byte)Command.SoftReset);
// reset requires 20ms at most, c.f. datasheet version 1.1, ch. 5.5
Thread.Sleep(20);
}
......@@ -138,6 +125,7 @@ namespace Iot.Device.Ahtxx
0x08, // command parameters c.f. datasheet, version 1.1, ch. 5.4
0x00
};
_i2cDevice.Write(buffer);
// wait 10ms c.f. datasheet, version 1.1, ch. 5.4
Thread.Sleep(10);
......@@ -171,5 +159,19 @@ namespace Iot.Device.Ahtxx
_i2cDevice?.Dispose();
_i2cDevice = null;
}
// datasheet version 1.1, table 10
private enum StatusBit : byte
{
Calibrated = 0x08,
Busy = 0x80
}
private enum Command : byte
{
Calibrate = 0xbe,
SoftReset = 0xba,
Measure = 0xac
}
}
}
......@@ -19,7 +19,7 @@ namespace Iot.Device.Ahtxx.Samples
public static void Main(string[] args)
{
const int I2cBus = 1;
I2cConnectionSettings i2cSettings = new I2cConnectionSettings(I2cBus, Aht20.DeviceAddress);
I2cConnectionSettings i2cSettings = new I2cConnectionSettings(I2cBus, Aht20.DefaultI2cAddress);
I2cDevice i2cDevice = I2cDevice.Create(i2cSettings);
Aht20 aht20Sensor = new Aht20(i2cDevice);
......
......@@ -16,28 +16,7 @@ namespace Iot.Device.Mhz19b
/// </summary>
public sealed class Mhz19b : IDisposable
{
private enum Command : byte
{
ReadCo2Concentration = 0x86,
CalibrateZeroPoint = 0x87,
CalibrateSpanPoint = 0x88,
AutoCalibrationSwitch = 0x79,
DetectionRangeSetting = 0x99
}
private enum MessageFormat
{
Start = 0x00,
SensorNum = 0x01,
Command = 0x02,
DataHighRequest = 0x03,
DataLowRequest = 0x04,
DataHighResponse = 0x02,
DataLowResponse = 0x03,
Checksum = 0x08
}
private const int MessageSize = 9;
private const int MessageBytes = 9;
private bool _shouldDispose = false;
private SerialPort _serialPort = null;
private Stream _serialPortStream = null;
......@@ -72,6 +51,7 @@ namespace Iot.Device.Mhz19b
ReadTimeout = 1000,
WriteTimeout = 1000
};
_serialPort.Open();
_serialPortStream = _serialPort.BaseStream;
_shouldDispose = true;
......@@ -79,63 +59,52 @@ namespace Iot.Device.Mhz19b
/// <summary>
/// Gets the current CO2 concentration from the sensor.
/// The validity is true if the current concentration was successfully read.
/// If the serial communication timed out or the checksum was invalid the validity is false.
/// If the validity is false the ratio is set to 0.
/// </summary>
/// <returns>CO2 concentration in ppm and validity</returns>
/// <exception cref="System.IO.IOException">Communication with sensor failed</exception>
/// <returns>CO2 volume concentration</returns>
/// <exception cref="IOException">Communication with sensor failed</exception>
/// <exception cref="TimeoutException">A timeout occurred while communicating with the sensor</exception>
public VolumeConcentration GetCo2Reading()
{
try
{
// send read command request
var request = CreateRequest(Command.ReadCo2Concentration);
request[(int)MessageFormat.Checksum] = Checksum(request);
_serialPortStream.Write(request, 0, request.Length);
// send read command request
var request = CreateRequest(Command.ReadCo2Concentration);
request[(int)MessageFormat.Checksum] = Checksum(request);
_serialPortStream.Write(request, 0, request.Length);
// read complete response (9 bytes expected)
byte[] response = new byte[MessageSize];
int timeout = 100;
int bytesRead = 0;
while (timeout > 0 && bytesRead < MessageSize)
{
bytesRead += _serialPortStream.Read(response, bytesRead, response.Length - bytesRead);
Thread.Sleep(1);
timeout--;
}
// read complete response (9 bytes expected)
byte[] response = new byte[MessageBytes];
if (timeout == 0)
{
throw new IOException("Timeout");
}
long endTicks = DateTime.Now.AddMilliseconds(250).Ticks;
int bytesRead = 0;
while (DateTime.Now.Ticks < endTicks && bytesRead < MessageBytes)
{
bytesRead += _serialPortStream.Read(response, bytesRead, response.Length - bytesRead);
Thread.Sleep(1);
}
// check response and return calculated concentration if valid
if (response[(int)MessageFormat.Checksum] == Checksum(response))
{
return VolumeConcentration.FromPartsPerMillion((int)response[(int)MessageFormat.DataHighResponse] * 256 + (int)response[(int)MessageFormat.DataLowResponse]);
}
else
{
throw new IOException("Invalid response message received from sensor");
}
if (bytesRead < MessageBytes)
{
throw new TimeoutException($"Communication with sensor failed.");
}
catch (Exception e)
// check response and return calculated concentration if valid
if (response[(int)MessageFormat.Checksum] == Checksum(response))
{
throw new IOException("Sensor communication failed", e);
return VolumeConcentration.FromPartsPerMillion((int)response[(int)MessageFormat.DataHighResponse] * 256 + (int)response[(int)MessageFormat.DataLowResponse]);
}
else
{
throw new IOException("Invalid response message received from sensor");
}
}
/// <summary>
/// Initiates a zero point calibration.
/// The sensor doesn't respond anything, so this is fire and forget.
/// </summary>
/// <exception cref="System.IO.IOException">Communication with sensor failed</exception>
public void PerformZeroPointCalibration() => SendRequest(CreateRequest(Command.CalibrateZeroPoint));
/// <summary>
/// Initiate a span point calibration.
/// The sensor doesn't respond anything, so this is fire and forget.
/// </summary>
/// <param name="span">span value, between 1000[ppm] and 5000[ppm]. The typical value is 2000[ppm].</param>
/// <exception cref="System.ArgumentException">Thrown when span value is out of range</exception>
......@@ -157,7 +126,6 @@ namespace Iot.Device.Mhz19b
/// <summary>
/// Switches the autmatic baseline correction on and off.
/// The sensor doesn't respond anything, so this is fire and forget.
/// </summary>
/// <param name="state">State of automatic correction</param>
/// <exception cref="System.IO.IOException">Communication with sensor failed</exception>
......@@ -172,7 +140,6 @@ namespace Iot.Device.Mhz19b
/// <summary>
/// Set the sensor detection range.
/// The sensor doesn't respond anything, so this is fire and forget
/// </summary>
/// <param name="detectionRange">Detection range of the sensor</param>
/// <exception cref="System.IO.IOException">Communication with sensor failed</exception>
......@@ -252,5 +219,26 @@ namespace Iot.Device.Mhz19b
_serialPort = null;
}
}
private enum Command : byte
{
ReadCo2Concentration = 0x86,
CalibrateZeroPoint = 0x87,
CalibrateSpanPoint = 0x88,
AutoCalibrationSwitch = 0x79,
DetectionRangeSetting = 0x99
}
private enum MessageFormat
{
Start = 0x00,
SensorNum = 0x01,
Command = 0x02,
DataHighRequest = 0x03,
DataLowRequest = 0x04,
DataHighResponse = 0x02,
DataLowResponse = 0x03,
Checksum = 0x08
}
}
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册