Initial Commit
This commit is contained in:
commit
b70e14c028
19 changed files with 613 additions and 0 deletions
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
bin/
|
||||
obj/
|
||||
/packages/
|
||||
riderModule.iml
|
||||
/_ReSharper.Caches/
|
||||
notes.md
|
13
.idea/.idea.PMS5003/.idea/.gitignore
vendored
Normal file
13
.idea/.idea.PMS5003/.idea/.gitignore
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Rider ignored files
|
||||
/contentModel.xml
|
||||
/modules.xml
|
||||
/projectSettingsUpdater.xml
|
||||
/.idea.PMS5003.iml
|
||||
# Datasource local storage ignored files
|
||||
/../../../../../../../:\Projects\Rider\PMS5003\.idea\.idea.PMS5003\.idea/dataSources/
|
||||
/dataSources.local.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
4
.idea/.idea.PMS5003/.idea/encodings.xml
Normal file
4
.idea/.idea.PMS5003/.idea/encodings.xml
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
|
||||
</project>
|
8
.idea/.idea.PMS5003/.idea/indexLayout.xml
Normal file
8
.idea/.idea.PMS5003/.idea/indexLayout.xml
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ContentModelUserStore">
|
||||
<attachedFolders />
|
||||
<explicitIncludes />
|
||||
<explicitExcludes />
|
||||
</component>
|
||||
</project>
|
6
.idea/.idea.PMS5003/.idea/vcs.xml
Normal file
6
.idea/.idea.PMS5003/.idea/vcs.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
22
PMS5003.sln
Normal file
22
PMS5003.sln
Normal file
|
@ -0,0 +1,22 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PMS5003", "PMS5003\PMS5003.csproj", "{918D79E6-9AE8-4FA8-8400-BD3A26BB4A60}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PMS5003Tests", "PMS5003Tests\PMS5003Tests.csproj", "{AF7541BD-C0B1-42FE-AEFB-1A1D9CEAC6B9}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{918D79E6-9AE8-4FA8-8400-BD3A26BB4A60}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{918D79E6-9AE8-4FA8-8400-BD3A26BB4A60}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{918D79E6-9AE8-4FA8-8400-BD3A26BB4A60}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{918D79E6-9AE8-4FA8-8400-BD3A26BB4A60}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{AF7541BD-C0B1-42FE-AEFB-1A1D9CEAC6B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{AF7541BD-C0B1-42FE-AEFB-1A1D9CEAC6B9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{AF7541BD-C0B1-42FE-AEFB-1A1D9CEAC6B9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{AF7541BD-C0B1-42FE-AEFB-1A1D9CEAC6B9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
6
PMS5003.sln.DotSettings.user
Normal file
6
PMS5003.sln.DotSettings.user
Normal file
|
@ -0,0 +1,6 @@
|
|||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=3358b775_002D8738_002D4b8b_002D978a_002D13b28217715f/@EntryIndexedValue"><SessionState ContinuousTestingMode="0" IsActive="True" Name="Pms5003DataUnitTest" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session">
|
||||
<TestAncestor>
|
||||
<TestId>xUnit::AF7541BD-C0B1-42FE-AEFB-1A1D9CEAC6B9::.NETCoreApp,Version=v3.1::PMS5003Tests.Pms5003DataUnitTest</TestId>
|
||||
</TestAncestor>
|
||||
</SessionState></s:String></wpf:ResourceDictionary>
|
16
PMS5003/Exceptions/BufferUnderflowExceptions.cs
Normal file
16
PMS5003/Exceptions/BufferUnderflowExceptions.cs
Normal file
|
@ -0,0 +1,16 @@
|
|||
using System;
|
||||
|
||||
namespace PMS5003.Exceptions
|
||||
{
|
||||
/// <summary>
|
||||
/// BufferUnderflowExceptions is thrown when the PMS5003 data buffer is incomplete.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class BufferUnderflowException : Exception
|
||||
{
|
||||
public BufferUnderflowException() : base("The PMS5003 data buffer is underrun, not enough bytes read!")
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
14
PMS5003/Exceptions/ChecksumMismatchException.cs
Normal file
14
PMS5003/Exceptions/ChecksumMismatchException.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
using System;
|
||||
|
||||
namespace PMS5003.Exceptions
|
||||
{
|
||||
/// <summary>
|
||||
/// ChecksumMismatchException when the frame contents of PMS5003 doesn't match the checksum.
|
||||
/// </summary>
|
||||
public class ChecksumMismatchException : Exception
|
||||
{
|
||||
public ChecksumMismatchException() : base("Checksum mismatch.")
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
16
PMS5003/Exceptions/InvalidStartByteException.cs
Normal file
16
PMS5003/Exceptions/InvalidStartByteException.cs
Normal file
|
@ -0,0 +1,16 @@
|
|||
using System;
|
||||
|
||||
namespace PMS5003.Exceptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Exception that is thrown by the PMS5003 sensor when the read contains an invalid start sequence.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class InvalidStartByteException : Exception
|
||||
{
|
||||
public InvalidStartByteException(short firstByte, short secondByte) : base(
|
||||
$"Invalid start characters, expected 0x42 0x4d got [{firstByte:X}, {secondByte:X}]")
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
14
PMS5003/Exceptions/ReadFailedException.cs
Normal file
14
PMS5003/Exceptions/ReadFailedException.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
using System;
|
||||
|
||||
namespace PMS5003.Exceptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Thrown the the read has failed.
|
||||
/// </summary>
|
||||
public class ReadFailedException : Exception
|
||||
{
|
||||
public ReadFailedException() : base("PMS5003 read failed, max retries exceeded")
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
151
PMS5003/PMS5003.cs
Normal file
151
PMS5003/PMS5003.cs
Normal file
|
@ -0,0 +1,151 @@
|
|||
using System;
|
||||
using System.Device.Gpio;
|
||||
using System.IO.Ports;
|
||||
using System.Threading;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using PMS5003.Exceptions;
|
||||
|
||||
namespace PMS5003
|
||||
{
|
||||
/// <summary>
|
||||
/// PMS5003 digital universal particle concentration sensor.
|
||||
/// Datasheet: https://www.aqmd.gov/docs/default-source/aq-spec/resources-page/plantower-pms5003-manual_v2-3.pdf
|
||||
/// </summary>
|
||||
public class Pms5003
|
||||
{
|
||||
public static Logger<Pms5003> Logger;
|
||||
private readonly GpioController _gpioController;
|
||||
private readonly SerialPort _serialPort;
|
||||
private readonly short _pinSet;
|
||||
private readonly short _pinReset;
|
||||
private bool _isSleeping;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the <see cref="Pms5003"/>.
|
||||
/// </summary>
|
||||
/// <param name="portSerialName">The name of the serial port.</param>
|
||||
/// <param name="pinSet">The number of the SET pin.</param>
|
||||
/// <param name="pinReset">The number if the RESET pin.</param>
|
||||
public Pms5003(string portSerialName, short pinSet, short pinReset)
|
||||
{
|
||||
_serialPort = new SerialPort(portSerialName, Pms5003Constants.DefaultBaudRate);
|
||||
_pinReset = pinReset;
|
||||
_pinSet = pinSet;
|
||||
|
||||
_serialPort.Open();
|
||||
if (Environment.OSVersion.Platform == PlatformID.Unix)
|
||||
{
|
||||
_gpioController = new GpioController();
|
||||
if (pinSet >= 0)
|
||||
{
|
||||
_gpioController.OpenPin(_pinSet, PinMode.Output);
|
||||
_gpioController.Write(_pinSet, PinValue.High);
|
||||
}
|
||||
|
||||
if (pinReset >= 0)
|
||||
{
|
||||
_gpioController.OpenPin(_pinReset, PinMode.Output);
|
||||
_gpioController.Write(_pinReset, PinValue.High);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger?.LogWarning("Not running under Unix platform, skipping GPIO configuration.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the <see cref="Pms5003"/> using /dev/ttyAMA0 serial port name.
|
||||
/// </summary>
|
||||
/// <param name="pinSet"></param>
|
||||
/// <param name="pinReset"></param>
|
||||
public Pms5003(short pinSet, short pinReset) : this("/dev/ttyAMA0", pinSet, pinReset)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the <see cref="Pms5003"/> using /dev/ttyAMA0 serial port name
|
||||
/// and no GPIO pins for SET and RESET.
|
||||
/// </summary>
|
||||
public Pms5003() : this("/dev/ttyAMA0", -1, -1)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the data from the sensor.
|
||||
/// </summary>
|
||||
/// <returns cref="Pms5003Data">The data.</returns>
|
||||
/// <exception cref="ReadFailedException">Thrown when the read fails.</exception>
|
||||
public Pms5003Data ReadData()
|
||||
{
|
||||
var currentTry = 0;
|
||||
const int maxRetries = 5;
|
||||
|
||||
while (currentTry < maxRetries)
|
||||
{
|
||||
try
|
||||
{
|
||||
var buffer = new byte[32];
|
||||
_serialPort.Read(buffer, 0, 32);
|
||||
return Pms5003Data.FromBytes(buffer);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger?.LogWarning(e.ToString());
|
||||
}
|
||||
finally
|
||||
{
|
||||
currentTry += 1;
|
||||
}
|
||||
}
|
||||
|
||||
throw new ReadFailedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the PMS5003 Sensor.
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
if (_gpioController == null || _pinReset < 0) return;
|
||||
_gpioController.Write(_pinReset, PinValue.Low);
|
||||
Thread.Sleep(200);
|
||||
_gpioController.Write(_pinReset, PinValue.High);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enables Sleep Mode for the PMS5003 Sensor.
|
||||
/// </summary>
|
||||
public void Sleep()
|
||||
{
|
||||
if (_gpioController == null || _pinSet < 0) return;
|
||||
_isSleeping = true;
|
||||
_gpioController.Write(_pinSet, PinValue.Low);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disables Sleep Mode for the PMS5003 Sensor.
|
||||
/// </summary>
|
||||
public void WakeUp()
|
||||
{
|
||||
if (_gpioController == null || _pinSet < 0) return;
|
||||
_isSleeping = false;
|
||||
_gpioController.Write(_pinSet, PinValue.High);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if Sleep Mode is enabled.
|
||||
/// </summary>
|
||||
/// <returns>True if sensor is in Sleep Mode, false otherwise.</returns>
|
||||
public bool IsSleeping()
|
||||
{
|
||||
return _isSleeping;
|
||||
}
|
||||
|
||||
~Pms5003()
|
||||
{
|
||||
_serialPort.Close();
|
||||
_gpioController?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
13
PMS5003/PMS5003.csproj
Normal file
13
PMS5003/PMS5003.csproj
Normal file
|
@ -0,0 +1,13 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Iot.Device.Bindings" Version="1.4.0" />
|
||||
<PackageReference Include="System.Device.Gpio" Version="1.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
15
PMS5003/Pms5003Constants.cs
Normal file
15
PMS5003/Pms5003Constants.cs
Normal file
|
@ -0,0 +1,15 @@
|
|||
namespace PMS5003
|
||||
{
|
||||
/// <summary>
|
||||
/// The Pms5003Constants defines constants required by the PMS5003 communication protocol.
|
||||
/// </summary>
|
||||
public class Pms5003Constants
|
||||
{
|
||||
public static readonly int DefaultBaudRate = 9600;
|
||||
public static readonly int StartByte1 = 0x42;
|
||||
public static readonly int StartByte2 = 0x4d;
|
||||
public static readonly int CommandReadInPassive = 0xe2;
|
||||
public static readonly int CommandChangeMode = 0xe1;
|
||||
public static readonly int CommandSleep = 0xe4;
|
||||
}
|
||||
}
|
102
PMS5003/Pms5003Data.cs
Normal file
102
PMS5003/Pms5003Data.cs
Normal file
|
@ -0,0 +1,102 @@
|
|||
using System.Text;
|
||||
using PMS5003.Exceptions;
|
||||
|
||||
namespace PMS5003
|
||||
{
|
||||
/// <summary>
|
||||
/// Pms5003Measurement is an abstraction over the PMS5003 data.
|
||||
/// </summary>
|
||||
public class Pms5003Data
|
||||
{
|
||||
private readonly uint[] _data;
|
||||
public uint Pm1Standard => _data[0];
|
||||
public uint Pm2Dot5Standard => _data[1];
|
||||
public uint Pm10Standard => _data[2];
|
||||
public uint Pm1Atmospheric => _data[3];
|
||||
public uint Pm2Dot5Atmospheric => _data[4];
|
||||
public uint Pm10Atmospheric => _data[5];
|
||||
public uint ParticlesDiameterBeyond0Dot3 => _data[6];
|
||||
public uint ParticlesDiameterBeyond0Dot5 => _data[7];
|
||||
public uint ParticlesDiameterBeyond1Dot0 => _data[8];
|
||||
public uint ParticlesDiameterBeyond2Dot5 => _data[9];
|
||||
public uint ParticlesDiameterBeyond5Dot0 => _data[10];
|
||||
public uint ParticlesDiameterBeyond10Dot0 => _data[11];
|
||||
private uint Reserved => _data[12];
|
||||
private uint Checksum => _data[13];
|
||||
|
||||
private Pms5003Data()
|
||||
{
|
||||
_data = new uint[14];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Instantiates a new instance from the given byte buffer.
|
||||
/// </summary>
|
||||
/// <param name="buffer">The data buffer</param>
|
||||
/// <returns>A new instance.</returns>
|
||||
public static Pms5003Data FromBytes(byte[] buffer)
|
||||
{
|
||||
var pms5003Measurement = new Pms5003Data();
|
||||
|
||||
if (buffer.Length < 4)
|
||||
{
|
||||
throw new BufferUnderflowException();
|
||||
}
|
||||
|
||||
if (buffer[0] != Pms5003Constants.StartByte1 || buffer[1] != Pms5003Constants.StartByte2)
|
||||
{
|
||||
throw new InvalidStartByteException(buffer[0], buffer[1]);
|
||||
}
|
||||
|
||||
var frameLength = Utils.CombineBytes(buffer[2], buffer[3]);
|
||||
if (frameLength > 0)
|
||||
{
|
||||
var currentDataPoint = 0;
|
||||
for (var i = 4; i < frameLength + 4; i += 2)
|
||||
{
|
||||
pms5003Measurement._data[currentDataPoint] = Utils.CombineBytes(buffer[i], buffer[i + 1]);
|
||||
currentDataPoint += 1;
|
||||
}
|
||||
}
|
||||
|
||||
var checkSum = 0;
|
||||
for (var i = 0; i < frameLength + 2; i++)
|
||||
{
|
||||
checkSum += buffer[i];
|
||||
}
|
||||
|
||||
if (pms5003Measurement.Checksum != checkSum)
|
||||
{
|
||||
throw new ChecksumMismatchException();
|
||||
}
|
||||
|
||||
return pms5003Measurement;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a string representation of the Pms5003Data.
|
||||
/// </summary>
|
||||
/// <returns>String with all the fields and values.</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
var buffer = new StringBuilder();
|
||||
buffer.AppendLine("Pms5003Data[");
|
||||
buffer.AppendLine($"Pm1Standard={Pm1Standard},");
|
||||
buffer.AppendLine($"Pm2Dot5Standard={Pm2Dot5Standard},");
|
||||
buffer.AppendLine($"Pm10Standard={Pm10Standard},");
|
||||
buffer.AppendLine($"Pm1Atmospheric={Pm1Atmospheric},");
|
||||
buffer.AppendLine($"Pm2Dot5Atmospheric={Pm2Dot5Atmospheric},");
|
||||
buffer.AppendLine($"Pm10Atmospheric={Pm10Atmospheric},");
|
||||
buffer.AppendLine($"ParticlesDiameterBeyond0Dot3={ParticlesDiameterBeyond0Dot3},");
|
||||
buffer.AppendLine($"ParticlesDiameterBeyond0Dot5={ParticlesDiameterBeyond0Dot5},");
|
||||
buffer.AppendLine($"ParticlesDiameterBeyond1Dot0={ParticlesDiameterBeyond1Dot0},");
|
||||
buffer.AppendLine($"ParticlesDiameterBeyond2Dot5={ParticlesDiameterBeyond2Dot5},");
|
||||
buffer.AppendLine($"ParticlesDiameterBeyond5Dot0={ParticlesDiameterBeyond5Dot0},");
|
||||
buffer.AppendLine($"ParticlesDiameterBeyond10Dot0={ParticlesDiameterBeyond10Dot0},");
|
||||
buffer.AppendLine($"Reserved={Reserved},");
|
||||
buffer.AppendLine($"Checksum={Checksum}");
|
||||
buffer.AppendLine("]");
|
||||
return buffer.ToString();
|
||||
}
|
||||
}
|
||||
}
|
16
PMS5003/Utils.cs
Normal file
16
PMS5003/Utils.cs
Normal file
|
@ -0,0 +1,16 @@
|
|||
namespace PMS5003
|
||||
{
|
||||
public class Utils
|
||||
{
|
||||
/// <summary>
|
||||
/// Combines two bytes and returns the results ((High RSHIFT 8) | Low)
|
||||
/// </summary>
|
||||
/// <param name="high">The high byte.</param>
|
||||
/// <param name="low">The low byte.</param>
|
||||
/// <returns></returns>
|
||||
public static uint CombineBytes(byte high, byte low)
|
||||
{
|
||||
return (uint)(low | (high << 8));;
|
||||
}
|
||||
}
|
||||
}
|
36
PMS5003/readme.md
Normal file
36
PMS5003/readme.md
Normal file
|
@ -0,0 +1,36 @@
|
|||
# Introduction
|
||||
|
||||
C# Library for interfacing with the PMS5003 Particulate Matter Sensor.
|
||||
|
||||
For wiring the Sensor consult the [datasheet](https://www.aqmd.gov/docs/default-source/aq-spec/resources-page/plantower-pms5003-manual_v2-3.pdf).
|
||||
|
||||
## Example
|
||||
|
||||
```csharp
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Application
|
||||
{
|
||||
class Example
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
var pms = new Pms5003();
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
var data = pms.ReadData();
|
||||
Console.WriteLine(data);
|
||||
Thread.Sleep(2000);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
20
PMS5003Tests/PMS5003Tests.csproj
Normal file
20
PMS5003Tests/PMS5003Tests.csproj
Normal file
|
@ -0,0 +1,20 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
|
||||
<PackageReference Include="xunit" Version="2.4.0" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
|
||||
<PackageReference Include="coverlet.collector" Version="1.2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\PMS5003\PMS5003.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
135
PMS5003Tests/Pms5003DataUnitTest.cs
Normal file
135
PMS5003Tests/Pms5003DataUnitTest.cs
Normal file
|
@ -0,0 +1,135 @@
|
|||
using System;
|
||||
using PMS5003;
|
||||
using PMS5003.Exceptions;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace PMS5003Tests
|
||||
{
|
||||
public class Pms5003DataUnitTest
|
||||
{
|
||||
private readonly ITestOutputHelper _testOutputHelper;
|
||||
|
||||
public Pms5003DataUnitTest(ITestOutputHelper testOutputHelper)
|
||||
{
|
||||
_testOutputHelper = testOutputHelper;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Test_FromBytes_Ok()
|
||||
{
|
||||
var tests = new byte[][]
|
||||
{
|
||||
new byte[]
|
||||
{
|
||||
66, 77, 0, 28, 0, 8, 0, 13, 0, 15, 0, 8, 0, 13, 0, 15, 7, 17, 1, 249, 0, 82, 0, 6, 0, 2, 0, 2, 151,
|
||||
0, 2, 248
|
||||
},
|
||||
new byte[]
|
||||
{
|
||||
66, 77, 0, 28, 0, 9, 0, 15, 0, 16, 0, 9, 0, 15, 0, 16, 6, 246, 2, 11, 0, 104, 0, 4, 0, 2, 0, 2, 151,
|
||||
0,
|
||||
3, 11
|
||||
},
|
||||
new byte[]
|
||||
{
|
||||
66, 77, 0, 28, 0, 7, 0, 12, 0, 13, 0, 7, 0, 12, 0, 13, 5, 226, 1, 152, 0, 66, 0, 12, 0, 2, 0, 2,
|
||||
151, 0,
|
||||
3, 84
|
||||
}
|
||||
};
|
||||
|
||||
// Assert that no exception is thrown
|
||||
foreach (var subTest in tests)
|
||||
{
|
||||
Pms5003Data.FromBytes(subTest);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Test_FromBytes_ChecksumMismatchException()
|
||||
{
|
||||
var tests = new byte[][]
|
||||
{
|
||||
new byte[]
|
||||
{
|
||||
66, 77, 0, 28, 0, 8, 0, 13, 0, 16, 0, 8, 0, 13, 0, 16, 6, 45, 1, 167, 0, 101, 0, 10, 0, 8, 0, 151,
|
||||
0, 144, 255, 0
|
||||
},
|
||||
new byte[]
|
||||
{
|
||||
66, 77, 0, 28, 0, 7, 0, 11, 0, 13, 0, 7, 0, 11, 0, 13, 5, 193, 1, 155, 8, 1, 6, 0, 2, 0, 2, 151, 0,
|
||||
3, 44, 0
|
||||
},
|
||||
new byte[]
|
||||
{
|
||||
66, 77, 0, 28, 0, 8, 0, 14, 0, 18, 0, 8, 0, 14, 0, 18, 6, 186, 1, 208, 0, 100, 0, 8, 0, 6, 0, 6,
|
||||
151, 3, 155, 0
|
||||
},
|
||||
new byte[]
|
||||
{
|
||||
66, 77, 0, 28, 0, 7, 0, 10, 0, 10, 232, 0, 10, 0, 33, 208, 10, 165, 0, 70, 0, 4, 0, 0, 0, 0, 151, 0,
|
||||
2, 161, 0, 0,
|
||||
}
|
||||
};
|
||||
|
||||
foreach (var subTest in tests)
|
||||
{
|
||||
Assert.Throws<ChecksumMismatchException>(() => Pms5003Data.FromBytes(subTest));
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Test_FromBytes_InvalidStartByteException()
|
||||
{
|
||||
var tests = new byte[][]
|
||||
{
|
||||
new byte[]
|
||||
{
|
||||
66, 00, 0, 28, 0, 8, 0, 13, 0, 16, 0, 8, 0, 13, 0, 16, 6, 45, 1, 167, 0, 101, 0, 10, 0, 8, 0, 151,
|
||||
0, 144, 255, 0
|
||||
},
|
||||
new byte[]
|
||||
{
|
||||
00, 77, 0, 28, 0, 7, 0, 11, 0, 13, 0, 7, 0, 11, 0, 13, 5, 193, 1, 155, 8, 1, 6, 0, 2, 0, 2, 151, 0,
|
||||
3, 44, 0
|
||||
},
|
||||
};
|
||||
|
||||
foreach (var subTest in tests)
|
||||
{
|
||||
Assert.Throws<InvalidStartByteException>(() => Pms5003Data.FromBytes(subTest));
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Test_ToString()
|
||||
{
|
||||
var pmsData = Pms5003Data.FromBytes(new byte[]
|
||||
{
|
||||
66, 77, 0, 28, 0, 7, 0, 12, 0, 13, 0, 7, 0, 12, 0, 13, 5, 226, 1, 152, 0, 66, 0, 12, 0, 2, 0, 2,
|
||||
151, 0,
|
||||
3, 84
|
||||
});
|
||||
|
||||
_testOutputHelper.WriteLine(pmsData.ToString());
|
||||
Assert.Equal(@"Pms5003Data[
|
||||
Pm1Standard=7,
|
||||
Pm2Dot5Standard=12,
|
||||
Pm10Standard=13,
|
||||
Pm1Atmospheric=7,
|
||||
Pm2Dot5Atmospheric=12,
|
||||
Pm10Atmospheric=13,
|
||||
ParticlesDiameterBeyond0Dot3=1506,
|
||||
ParticlesDiameterBeyond0Dot5=408,
|
||||
ParticlesDiameterBeyond1Dot0=66,
|
||||
ParticlesDiameterBeyond2Dot5=12,
|
||||
ParticlesDiameterBeyond5Dot0=2,
|
||||
ParticlesDiameterBeyond10Dot0=2,
|
||||
Reserved=38656,
|
||||
Checksum=852
|
||||
]
|
||||
", pmsData.ToString());
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue