using System;
using System.Device.Gpio;
using System.IO.Ports;
using System.Threading;
using Microsoft.Extensions.Logging;
using PMS5003.Exceptions;
namespace PMS5003
{
///
/// PMS5003 digital universal particle concentration sensor.
/// Datasheet: https://www.aqmd.gov/docs/default-source/aq-spec/resources-page/plantower-pms5003-manual_v2-3.pdf
///
public class Pms5003
{
public static Logger Logger;
private readonly GpioController _gpioController;
private readonly SerialPort _serialPort;
private readonly short _pinSet;
private readonly short _pinReset;
private bool _isSleeping;
///
/// Initializes the .
///
/// The name of the serial port.
/// The number of the SET pin.
/// The number if the RESET pin.
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.");
}
}
///
/// Initializes the using /dev/ttyAMA0 serial port name.
///
///
///
public Pms5003(short pinSet, short pinReset) : this("/dev/ttyAMA0", pinSet, pinReset)
{
}
///
/// Initializes the using /dev/ttyAMA0 serial port name
/// and no GPIO pins for SET and RESET.
///
public Pms5003() : this("/dev/ttyAMA0", -1, -1)
{
}
///
/// Reads the data from the sensor.
///
/// The data.
/// Thrown when the read fails.
public Pms5003Data ReadData()
{
var currentTry = 0;
const int maxRetries = 50;
var buffer = new byte[32];
while (currentTry < maxRetries)
{
try
{
// Try to find start frame
_serialPort.Read(buffer, 0, 1);
if (buffer[0] != Pms5003Constants.StartByte1)
{
continue;
}
_serialPort.Read(buffer, 1, 1);
if (buffer[1] != Pms5003Constants.StartByte2)
{
continue;
}
// Read rest of data
_serialPort.Read(buffer, 2, 30);
return Pms5003Data.FromBytes(buffer);
}
catch (Exception e)
{
Logger?.LogWarning(e.ToString());
Thread.Sleep(1000);
}
finally
{
currentTry += 1;
}
}
throw new ReadFailedException();
}
///
/// Resets the PMS5003 Sensor.
///
public void Reset()
{
if (_gpioController == null || _pinReset < 0) return;
_gpioController.Write(_pinReset, PinValue.Low);
Thread.Sleep(200);
_gpioController.Write(_pinReset, PinValue.High);
}
///
/// Enables Sleep Mode for the PMS5003 Sensor.
///
public void Sleep()
{
if (_gpioController == null || _pinSet < 0) return;
_isSleeping = true;
_gpioController.Write(_pinSet, PinValue.Low);
}
///
/// Disables Sleep Mode for the PMS5003 Sensor.
///
public void WakeUp()
{
if (_gpioController == null || _pinSet < 0) return;
_isSleeping = false;
_gpioController.Write(_pinSet, PinValue.High);
}
///
/// Checks if Sleep Mode is enabled.
///
/// True if sensor is in Sleep Mode, false otherwise.
public bool IsSleeping()
{
return _isSleeping;
}
~Pms5003()
{
_serialPort.Close();
_gpioController?.Dispose();
}
}
}