File: TransducerMeasurement.cs
Web Access
Project: ..\..\..\src\Iot.Device.Bindings\Iot.Device.Bindings.csproj (Iot.Device.Bindings)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Iot.Device.Common;
using UnitsNet;
 
namespace Iot.Device.Nmea0183.Sentences
{
    /// <summary>
    /// Reading of a sensor, not covered by other sentences.
    /// This can include environmental values (temperature, pressure), tank levels, etc.
    /// </summary>
    public class TransducerMeasurement : NmeaSentence
    {
        /// <summary>
        /// This sentence's id
        /// </summary>
        public static SentenceId Id => new SentenceId("XDR");
        private static bool Matches(SentenceId sentence) => Id == sentence;
        private static bool Matches(TalkerSentence sentence) => Matches(sentence.Id);
 
        private readonly List<TransducerDataSet> _dataSets;
 
        /// <summary>
        /// Constructs a new basic XDR sentence with a single data set.
        /// </summary>
        public TransducerMeasurement(string dataName, string dataType, double value, string unit)
            : base(OwnTalkerId, Id, DateTimeOffset.UtcNow)
        {
            _dataSets = new List<TransducerDataSet>();
            _dataSets.Add(new TransducerDataSet()
            {
                DataName = dataName ?? throw new ArgumentNullException(nameof(dataName)),
                DataType = dataType ?? throw new ArgumentNullException(nameof(dataType)),
                Value = value,
                Unit = unit ?? throw new ArgumentNullException(nameof(unit))
            });
            Valid = true;
        }
 
        /// <summary>
        /// Constructs a new basic XDR sentence with a list of data sets
        /// </summary>
        public TransducerMeasurement(IEnumerable<TransducerDataSet> dataSets)
            : base(OwnTalkerId, Id, DateTimeOffset.UtcNow)
        {
            if (dataSets == null)
            {
                throw new ArgumentNullException(nameof(dataSets));
            }
 
            _dataSets = new List<TransducerDataSet>(dataSets);
            if (_dataSets.Count >= 1 && _dataSets.Count < 10)
            {
                Valid = true;
            }
            else
            {
                Valid = false;
            }
        }
 
        /// <summary>
        /// Decodes an XDR sentence
        /// </summary>
        public TransducerMeasurement(TalkerSentence sentence, DateTimeOffset time)
            : this(sentence.TalkerId, Matches(sentence) ? sentence.Fields : throw new ArgumentException($"SentenceId does not match expected id '{Id}'"), time)
        {
        }
 
        /// <summary>
        /// Decodes an XDR sentence
        /// </summary>
        internal TransducerMeasurement(TalkerId talkerId, IEnumerable<string> fields, DateTimeOffset time)
            : base(talkerId, Id, time)
        {
            _dataSets = new List<TransducerDataSet>();
            IEnumerator<string> field = fields.GetEnumerator();
            // Rounding is intended. The number of fields must be a multiple of 4, or the remainder is invalid
            int numDataSets = fields.Count() / 4;
 
            for (int i = 0; i < numDataSets; i++)
            {
                string dataType = ReadString(field) ?? string.Empty;
                double value = ReadValue(field) ?? 0.0;
                string unit = ReadString(field) ?? string.Empty;
                string dataName = ReadString(field) ?? "Unknown";
                var ds = new TransducerDataSet(dataType, value, unit, dataName);
                _dataSets.Add(ds);
            }
 
            if (_dataSets.Count >= 1)
            {
                Valid = true;
            }
            else
            {
                Valid = false;
            }
        }
 
        /// <summary>
        /// False, because XDR sentences can contain a variety of elements
        /// </summary>
        public override bool ReplacesOlderInstance => false;
 
        /// <summary>
        /// Return the data sets of this message.
        /// The returned list is a read-only copy of the data sets and cannot be modified.
        /// </summary>
        public IList<TransducerDataSet> DataSets
        {
            get
            {
                return _dataSets.AsReadOnly();
            }
        }
 
        /// <summary>
        /// Creates a sentence from roll and pitch angles
        /// </summary>
        /// <param name="roll">Roll angle (positive right or left wing up)</param>
        /// <param name="pitch">Pitch angle (positive nose up)</param>
        /// <param name="yaw">Yaw angle (heading)</param>
        /// <returns>A measurement sequence ready to send</returns>
        public static IList<TransducerMeasurement> FromRollAndPitch(Angle roll, Angle pitch, Angle yaw)
        {
            TransducerMeasurement[] tm = new TransducerMeasurement[2];
            TransducerDataSet ds1 = new TransducerDataSet("A", roll.Normalize(false).Degrees, "D", "Roll");
            TransducerDataSet ds2 = new TransducerDataSet("A", pitch.Normalize(false).Degrees, "D", "Pitch");
            TransducerDataSet ds3 = new TransducerDataSet("A", yaw.Normalize(false).Degrees, "D", "Yaw");
            tm[0] = new TransducerMeasurement(new[] { ds1, ds2, ds3 });
 
            // Different clients require different spellings
            TransducerDataSet ds4 = new TransducerDataSet("A", roll.Normalize(false).Degrees, "D", "ROLL");
            TransducerDataSet ds5 = new TransducerDataSet("A", pitch.Normalize(false).Degrees, "D", "PITCH");
            TransducerDataSet ds6 = new TransducerDataSet("A", yaw.Normalize(false).Degrees, "D", "YAW");
            tm[1] = new TransducerMeasurement(new[] { ds4, ds5, ds6 });
            return tm;
        }
 
        /// <summary>
        /// Presents this message as output
        /// </summary>
        public override string ToNmeaParameterList()
        {
            if (Valid)
            {
                StringBuilder b = new StringBuilder();
                for (var index = 0; index < _dataSets.Count; index++)
                {
                    TransducerDataSet data = _dataSets[index];
                    b.Append(data.ToString());
                    if (index != _dataSets.Count - 1)
                    {
                        b.Append(",");
                    }
                }
 
                return b.ToString();
            }
 
            return string.Empty;
        }
 
        /// <inheritdoc />
        public override string ToReadableContent()
        {
            if (Valid)
            {
                StringBuilder b = new StringBuilder();
                foreach (var data in _dataSets)
                {
                    b.Append(data.ToReadableContent());
                    b.Append(" ");
                }
 
                return b.ToString();
            }
 
            return "No data";
        }
    }
}