public void ConversionRoundTrip() { VolumeConcentration decimalfraction = VolumeConcentration.FromDecimalFractions(1); AssertEx.EqualTolerance(1, VolumeConcentration.FromCentilitersPerLiter(decimalfraction.CentilitersPerLiter).DecimalFractions, CentilitersPerLiterTolerance); AssertEx.EqualTolerance(1, VolumeConcentration.FromCentilitersPerMililiter(decimalfraction.CentilitersPerMililiter).DecimalFractions, CentilitersPerMililiterTolerance); AssertEx.EqualTolerance(1, VolumeConcentration.FromDecilitersPerLiter(decimalfraction.DecilitersPerLiter).DecimalFractions, DecilitersPerLiterTolerance); AssertEx.EqualTolerance(1, VolumeConcentration.FromDecilitersPerMililiter(decimalfraction.DecilitersPerMililiter).DecimalFractions, DecilitersPerMililiterTolerance); AssertEx.EqualTolerance(1, VolumeConcentration.FromDecimalFractions(decimalfraction.DecimalFractions).DecimalFractions, DecimalFractionsTolerance); AssertEx.EqualTolerance(1, VolumeConcentration.FromLitersPerLiter(decimalfraction.LitersPerLiter).DecimalFractions, LitersPerLiterTolerance); AssertEx.EqualTolerance(1, VolumeConcentration.FromLitersPerMililiter(decimalfraction.LitersPerMililiter).DecimalFractions, LitersPerMililiterTolerance); AssertEx.EqualTolerance(1, VolumeConcentration.FromMicrolitersPerLiter(decimalfraction.MicrolitersPerLiter).DecimalFractions, MicrolitersPerLiterTolerance); AssertEx.EqualTolerance(1, VolumeConcentration.FromMicrolitersPerMililiter(decimalfraction.MicrolitersPerMililiter).DecimalFractions, MicrolitersPerMililiterTolerance); AssertEx.EqualTolerance(1, VolumeConcentration.FromMillilitersPerLiter(decimalfraction.MillilitersPerLiter).DecimalFractions, MillilitersPerLiterTolerance); AssertEx.EqualTolerance(1, VolumeConcentration.FromMillilitersPerMililiter(decimalfraction.MillilitersPerMililiter).DecimalFractions, MillilitersPerMililiterTolerance); AssertEx.EqualTolerance(1, VolumeConcentration.FromNanolitersPerLiter(decimalfraction.NanolitersPerLiter).DecimalFractions, NanolitersPerLiterTolerance); AssertEx.EqualTolerance(1, VolumeConcentration.FromNanolitersPerMililiter(decimalfraction.NanolitersPerMililiter).DecimalFractions, NanolitersPerMililiterTolerance); AssertEx.EqualTolerance(1, VolumeConcentration.FromPartsPerBillion(decimalfraction.PartsPerBillion).DecimalFractions, PartsPerBillionTolerance); AssertEx.EqualTolerance(1, VolumeConcentration.FromPartsPerMillion(decimalfraction.PartsPerMillion).DecimalFractions, PartsPerMillionTolerance); AssertEx.EqualTolerance(1, VolumeConcentration.FromPartsPerThousand(decimalfraction.PartsPerThousand).DecimalFractions, PartsPerThousandTolerance); AssertEx.EqualTolerance(1, VolumeConcentration.FromPartsPerTrillion(decimalfraction.PartsPerTrillion).DecimalFractions, PartsPerTrillionTolerance); AssertEx.EqualTolerance(1, VolumeConcentration.FromPercent(decimalfraction.Percent).DecimalFractions, PercentTolerance); AssertEx.EqualTolerance(1, VolumeConcentration.FromPicolitersPerLiter(decimalfraction.PicolitersPerLiter).DecimalFractions, PicolitersPerLiterTolerance); AssertEx.EqualTolerance(1, VolumeConcentration.FromPicolitersPerMililiter(decimalfraction.PicolitersPerMililiter).DecimalFractions, PicolitersPerMililiterTolerance); }
/// <summary> /// Read the equivalent CO2 in ppm and equivalent Total Volatile Compound in ppb /// </summary> /// <param name="equivalentCO2">The equivalent CO2 (eCO2) output range for CCS811 is from /// 400ppm up to 29206ppm.</param> /// <param name="equivalentTotalVolatileOrganicCompound">The equivalent Total Volatile Organic Compound (eTVOC) /// output range for CCS811 is from 0ppb up to 32768ppb</param> /// <param name="rawCurrentSelected">Raw data containing the value of the /// current through the sensor(0μA to 63μA)</param> /// <param name="rawAdcReading">Raw data containing the /// readings of the voltage across the sensor with the selected /// current(1023 = 1.65V) where 1023 is the maximum value</param> /// <returns>True if success</returns> public bool TryReadGasData(out VolumeConcentration equivalentCO2, out VolumeConcentration equivalentTotalVolatileOrganicCompound, out ElectricCurrent rawCurrentSelected, out int rawAdcReading) { int equivalentCO2InPpm = -1; int equivalentTotalVolatileOrganicCompoundInPpb = -1; int rawCurrent = -1; rawAdcReading = -1; Span <byte> toRead = stackalloc byte[8]; ReadRegister(Register.ALG_RESULT_DATA, toRead); if (toRead[5] != (byte)Error.NoError) { equivalentCO2 = VolumeConcentration.Zero; equivalentTotalVolatileOrganicCompound = VolumeConcentration.Zero; rawCurrentSelected = ElectricCurrent.Zero; return(false); } equivalentCO2InPpm = BinaryPrimitives.ReadInt16BigEndian(toRead.Slice(0, 2)); equivalentTotalVolatileOrganicCompoundInPpb = BinaryPrimitives.ReadInt16BigEndian(toRead.Slice(2, 2)); rawCurrent = toRead[6] >> 2; rawAdcReading = ((toRead[6] & 0b0000_0011) << 2) + toRead[7]; equivalentCO2 = VolumeConcentration.FromPartsPerMillion(equivalentCO2InPpm); equivalentTotalVolatileOrganicCompound = VolumeConcentration.FromPartsPerBillion(equivalentTotalVolatileOrganicCompoundInPpb); rawCurrentSelected = ElectricCurrent.FromMicroamperes(rawCurrent); return((equivalentCO2InPpm >= 400) && (equivalentCO2InPpm <= 29206) && (equivalentTotalVolatileOrganicCompoundInPpb >= 0) && (equivalentTotalVolatileOrganicCompoundInPpb <= 32768)); }
/// <summary> /// Gets the current CO2 concentration from the sensor. /// </summary> /// <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() { // 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[MessageBytes]; 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); } if (bytesRead < MessageBytes) { throw new TimeoutException($"Communication with sensor failed."); } // 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"); } }
private bool IsPpmValidThreshold(VolumeConcentration ppm) { if ((ppm < VolumeConcentration.Zero) || (ppm > VolumeConcentration.FromPartsPerMillion(ushort.MaxValue))) { return(false); } return(true); }
/// <summary> /// Set the threshold for the equivalent CO2. The pinInterrupt should be existing so /// interruptions are activated. If not, then the function will return false /// </summary> /// <param name="lowEquivalentCO2">The low value for the threshold</param> /// <param name="highEquivalentCO2">The high value for the threshold</param> /// <returns>True if success</returns> /// <remarks>Difference between the low and high value should be more than 50. This is called /// the hysteresis value.</remarks> public bool SetThreshold(VolumeConcentration lowEquivalentCO2, VolumeConcentration highEquivalentCO2) { if (_pinInterruption < 0) { return(false); } if (!IsPpmValidThreshold(lowEquivalentCO2)) { throw new ArgumentException($"{lowEquivalentCO2} can only be between 0 and {ushort.MaxValue}"); } if (!IsPpmValidThreshold(highEquivalentCO2)) { throw new ArgumentException($"{highEquivalentCO2} can only be between 0 and {ushort.MaxValue}"); } if (lowEquivalentCO2 > highEquivalentCO2) { var temp = highEquivalentCO2; highEquivalentCO2 = lowEquivalentCO2; lowEquivalentCO2 = temp; } if (highEquivalentCO2 - lowEquivalentCO2 < VolumeConcentration.FromPartsPerMillion(50)) { throw new ArgumentException($"{highEquivalentCO2}-{lowEquivalentCO2} should be more than 50"); } Span <byte> toSend = stackalloc byte[4]; BinaryPrimitives.WriteUInt16BigEndian(toSend.Slice(0, 2), (ushort)lowEquivalentCO2.PartsPerMillion); BinaryPrimitives.WriteUInt16BigEndian(toSend.Slice(2, 2), (ushort)highEquivalentCO2.PartsPerMillion); WriteRegister(Register.THRESHOLDS, toSend); // Activate the interrupt threshold as well byte mode = ReadRegister(Register.MEAS_MODE); mode |= 0b0000_0100; WriteRegister(Register.MEAS_MODE, mode); return(!Status.HasFlag(Status.ERROR)); }
private static void TestThresholdAndInterrupt(Ccs811Sensor ccs811) { if (!ccs811.InterruptEnable) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Error: interrupt needs to be activated to run this test"); Console.ResetColor(); return; } ccs811.MeasurementReady += Ccs811MeasurementReady; // Setting up a range where we will see something in a normal environment VolumeConcentration low = VolumeConcentration.FromPartsPerMillion(400); VolumeConcentration high = VolumeConcentration.FromPartsPerMillion(600); Console.WriteLine($"Setting up {low.PartsPerMillion}-{high.PartsPerMillion} range, in clear environment, that should raise interrupts. Wait 3 minutes and change mode. Blow on the sensor and wait a bit."); Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine("Warning: only the first measurement to cross the threshold is raised."); Console.ResetColor(); ccs811.SetThreshold(low, high); DateTime dt = DateTime.Now.AddMinutes(3); while (dt > DateTime.Now) { Thread.Sleep(10); } low = VolumeConcentration.FromPartsPerMillion(15000); high = VolumeConcentration.FromPartsPerMillion(20000); Console.WriteLine($"Changing threshold for {low.PartsPerMillion}-{high.PartsPerMillion}, a non reachable range in clear environment. No measurement should appear in next 3 minutes"); dt = DateTime.Now.AddMinutes(3); ccs811.SetThreshold(low, high); while (dt > DateTime.Now) { Thread.Sleep(10); } }
public void NumberToPartsPerMillionTest() => Assert.Equal(VolumeConcentration.FromPartsPerMillion(2), 2.PartsPerMillion());
public static VolumeConcentration PartsPerMillion <T>(this T value) => VolumeConcentration.FromPartsPerMillion(Convert.ToDecimal(value));