Exemplo n.º 1
0
        private uint DecodeQuality(int code, TsscPointMetadata nextPoint)
        {
            uint quality = code == TsscCodeWords.Quality2 ?
                           nextPoint.PrevQuality2 :
                           Encoding7Bit.ReadUInt32(m_data, ref m_position);

            nextPoint.PrevQuality2 = nextPoint.PrevQuality1;
            nextPoint.PrevQuality1 = quality;

            return(quality);
        }
Exemplo n.º 2
0
        private void WriteQualityChange(uint quality, TsscPointMetadata point)
        {
            if (point.PrevQuality2 == quality)
            {
                m_lastPoint.WriteCode(TsscCodeWords.Quality2);
            }
            else
            {
                m_lastPoint.WriteCode(TsscCodeWords.Quality7Bit32);
                Encoding7Bit.Write(m_data, ref m_position, quality);
            }

            point.PrevQuality2 = point.PrevQuality1;
            point.PrevQuality1 = quality;
        }
Exemplo n.º 3
0
        /// <summary>
        /// Resets the TSSC Decoder to the initial state.
        /// </summary>
        /// <remarks>
        /// TSSC is a stateful encoder that requires a state
        /// of the previous data to be maintained. Therefore, if
        /// the state ever becomes corrupt (out of order, dropped, corrupted, or duplicated)
        /// the state must be reset on both ends.
        /// </remarks>
        public void Reset()
        {
            m_points       = new();
            m_lastPoint    = new(null, ReadBit, ReadBits5);
            m_data         = Array.Empty <byte>();
            m_position     = 0;
            m_lastPosition = 0;
            ClearBitStream();

            m_prevTimeDelta1 = long.MaxValue;
            m_prevTimeDelta2 = long.MaxValue;
            m_prevTimeDelta3 = long.MaxValue;
            m_prevTimeDelta4 = long.MaxValue;
            m_prevTimestamp1 = 0;
            m_prevTimestamp2 = 0;
        }
Exemplo n.º 4
0
        private void DecodePointID(int code, TsscPointMetadata lastPoint)
        {
            switch (code)
            {
            case TsscCodeWords.PointIDXOR4:
                lastPoint.PrevNextPointId1 = ReadBits4() ^ lastPoint.PrevNextPointId1;
                break;

            case TsscCodeWords.PointIDXOR8:
                lastPoint.PrevNextPointId1 = m_data[m_position] ^ lastPoint.PrevNextPointId1;
                m_position += 1;
                break;

            case TsscCodeWords.PointIDXOR12:
                lastPoint.PrevNextPointId1 = ReadBits4() ^ (m_data[m_position] << 4) ^ lastPoint.PrevNextPointId1;
                m_position += 1;
                break;

            case TsscCodeWords.PointIDXOR16:
                lastPoint.PrevNextPointId1 = m_data[m_position] ^ (m_data[m_position + 1] << 8) ^ lastPoint.PrevNextPointId1;
                m_position += 2;
                break;

            case TsscCodeWords.PointIDXOR20:
                lastPoint.PrevNextPointId1 = ReadBits4() ^ (m_data[m_position] << 4) ^ (m_data[m_position + 1] << 12) ^ lastPoint.PrevNextPointId1;
                m_position += 2;
                break;

            case TsscCodeWords.PointIDXOR24:
                lastPoint.PrevNextPointId1 = m_data[m_position] ^ (m_data[m_position + 1] << 8) ^ (m_data[m_position + 2] << 16) ^ lastPoint.PrevNextPointId1;
                m_position += 3;
                break;

            case TsscCodeWords.PointIDXOR32:
                lastPoint.PrevNextPointId1 = m_data[m_position] ^ (m_data[m_position + 1] << 8) ^ (m_data[m_position + 2] << 16) ^ (m_data[m_position + 3] << 24) ^ lastPoint.PrevNextPointId1;
                m_position += 4;
                break;

            default:
                throw new($"Invalid code received {code} at position {m_position} with last position {m_lastPosition}");
            }
        }
Exemplo n.º 5
0
        /// <summary>
        /// Reads the next measurement from the stream. If the end of the stream has been encountered,
        /// return false.
        /// </summary>
        /// <param name="id">the id</param>
        /// <param name="timestamp">the timestamp in ticks</param>
        /// <param name="quality">the quality</param>
        /// <param name="value">the value</param>
        /// <returns>true if successful, false otherwise.</returns>
        public unsafe bool TryGetMeasurement(out int id, out long timestamp, out uint quality, out float value)
        {
            if (m_position == m_lastPosition && BitStreamIsEmpty)
            {
                ClearBitStream();
                id        = 0;
                timestamp = 0;
                quality   = 0;
                value     = 0;

                return(false);
            }

            // Note: since I will not know the incoming pointID. The most recent
            //       measurement received will be the one that contains the
            //       coding algorithm for this measurement. Since for the more part
            //       measurements generally have some sort of sequence to them,
            //       this still ends up being a good enough assumption.

            int code = m_lastPoint.ReadCode();

            switch (code)
            {
            case TsscCodeWords.EndOfStream:
            {
                ClearBitStream();
                id        = 0;
                timestamp = 0;
                quality   = 0;
                value     = 0;

                return(false);
            }

            case <= TsscCodeWords.PointIDXOR32:
            {
                DecodePointID(code, m_lastPoint);
                code = m_lastPoint.ReadCode();

                if (code < TsscCodeWords.TimeDelta1Forward)
                {
                    throw new($"Expecting code >= {TsscCodeWords.TimeDelta1Forward} Received {code} at position {m_position} with last position { m_lastPosition}");
                }
                break;
            }
            }

            id = m_lastPoint.PrevNextPointId1;

            TsscPointMetadata nextPoint = m_points[m_lastPoint.PrevNextPointId1];

            if (nextPoint is null)
            {
                nextPoint    = new(null, ReadBit, ReadBits5);
                m_points[id] = nextPoint;
                nextPoint.PrevNextPointId1 = id + 1;
            }

            if (code <= TsscCodeWords.TimeXOR7Bit)
            {
                timestamp = DecodeTimestamp(code);
                code      = m_lastPoint.ReadCode();

                if (code < TsscCodeWords.Quality2)
                {
                    throw new($"Expecting code >= {TsscCodeWords.Quality2} Received {code} at position {m_position} with last position { m_lastPosition}");
                }
            }
            else
            {
                timestamp = m_prevTimestamp1;
            }

            if (code <= TsscCodeWords.Quality7Bit32)
            {
                quality = DecodeQuality(code, nextPoint);
                code    = m_lastPoint.ReadCode();

                if (code < TsscCodeWords.Value1)
                {
                    throw new($"Expecting code >= {TsscCodeWords.Value1} Received {code} at position {m_position} with last position { m_lastPosition}");
                }
            }
            else
            {
                quality = nextPoint.PrevQuality1;
            }

            // Since value will almost always change,
            // This is not put inside a function call.
            uint valueRaw;

            switch (code)
            {
            case TsscCodeWords.Value1:
                valueRaw = nextPoint.PrevValue1;
                break;

            case TsscCodeWords.Value2:
                valueRaw             = nextPoint.PrevValue2;
                nextPoint.PrevValue2 = nextPoint.PrevValue1;
                nextPoint.PrevValue1 = valueRaw;
                break;

            case TsscCodeWords.Value3:
                valueRaw             = nextPoint.PrevValue3;
                nextPoint.PrevValue3 = nextPoint.PrevValue2;
                nextPoint.PrevValue2 = nextPoint.PrevValue1;
                nextPoint.PrevValue1 = valueRaw;
                break;

            case TsscCodeWords.ValueZero:
                valueRaw             = 0;
                nextPoint.PrevValue3 = nextPoint.PrevValue2;
                nextPoint.PrevValue2 = nextPoint.PrevValue1;
                nextPoint.PrevValue1 = valueRaw;
                break;

            default:
                switch (code)
                {
                case TsscCodeWords.ValueXOR4:
                    valueRaw = (uint)ReadBits4() ^ nextPoint.PrevValue1;
                    break;

                case TsscCodeWords.ValueXOR8:
                    valueRaw    = m_data[m_position] ^ nextPoint.PrevValue1;
                    m_position += 1;
                    break;

                case TsscCodeWords.ValueXOR12:
                    valueRaw    = (uint)ReadBits4() ^ (uint)(m_data[m_position] << 4) ^ nextPoint.PrevValue1;
                    m_position += 1;
                    break;

                case TsscCodeWords.ValueXOR16:
                    valueRaw    = m_data[m_position] ^ (uint)(m_data[m_position + 1] << 8) ^ nextPoint.PrevValue1;
                    m_position += 2;
                    break;

                case TsscCodeWords.ValueXOR20:
                    valueRaw    = (uint)ReadBits4() ^ (uint)(m_data[m_position] << 4) ^ (uint)(m_data[m_position + 1] << 12) ^ nextPoint.PrevValue1;
                    m_position += 2;
                    break;

                case TsscCodeWords.ValueXOR24:
                    valueRaw    = m_data[m_position] ^ (uint)(m_data[m_position + 1] << 8) ^ (uint)(m_data[m_position + 2] << 16) ^ nextPoint.PrevValue1;
                    m_position += 3;
                    break;

                case TsscCodeWords.ValueXOR28:
                    valueRaw    = (uint)ReadBits4() ^ (uint)(m_data[m_position] << 4) ^ (uint)(m_data[m_position + 1] << 12) ^ (uint)(m_data[m_position + 2] << 20) ^ nextPoint.PrevValue1;
                    m_position += 3;
                    break;

                case TsscCodeWords.ValueXOR32:
                    valueRaw    = m_data[m_position] ^ (uint)(m_data[m_position + 1] << 8) ^ (uint)(m_data[m_position + 2] << 16) ^ (uint)(m_data[m_position + 3] << 24) ^ nextPoint.PrevValue1;
                    m_position += 4;
                    break;

                default:
                    throw new($"Invalid code received {code} at position {m_position} with last position { m_lastPosition}");
                }

                nextPoint.PrevValue3 = nextPoint.PrevValue2;
                nextPoint.PrevValue2 = nextPoint.PrevValue1;
                nextPoint.PrevValue1 = valueRaw;
                break;
            }

            value       = *(float *)&valueRaw;
            m_lastPoint = nextPoint;

            return(true);
        }
Exemplo n.º 6
0
        /// <summary>
        /// Adds the supplied measurement to the stream. If the stream is full,
        /// this method returns false.
        /// </summary>
        /// <param name="id">the id</param>
        /// <param name="timestamp">the timestamp in ticks</param>
        /// <param name="quality">the quality</param>
        /// <param name="value">the value</param>
        /// <returns>true if successful, false otherwise.</returns>
        public unsafe bool TryAddMeasurement(int id, long timestamp, uint quality, float value)
        {
            //if there are fewer than 100 bytes available on the buffer
            //assume that we cannot add any more.
            if (m_lastPosition - m_position < 100)
            {
                return(false);
            }

            TsscPointMetadata point = m_points[id];

            if (point is null)
            {
                point        = new(WriteBits, null, null) { PrevNextPointId1 = id + 1 };
                m_points[id] = point;
            }

            //Note: since I will not know the incoming pointID. The most recent
            //      measurement received will be the one that contains the
            //      coding algorithm for this measurement. Since for the more part
            //      measurements generally have some sort of sequence to them,
            //      this still ends up being a good enough assumption.

            if (m_lastPoint.PrevNextPointId1 != id)
            {
                WritePointIdChange(id);
            }

            if (m_prevTimestamp1 != timestamp)
            {
                WriteTimestampChange(timestamp);
            }

            if (point.PrevQuality1 != quality)
            {
                WriteQualityChange(quality, point);
            }

            uint valueRaw = *(uint *)&value;

            if (point.PrevValue1 == valueRaw)
            {
                m_lastPoint.WriteCode(TsscCodeWords.Value1);
            }
            else if (point.PrevValue2 == valueRaw)
            {
                m_lastPoint.WriteCode(TsscCodeWords.Value2);
                point.PrevValue2 = point.PrevValue1;
                point.PrevValue1 = valueRaw;
            }
            else if (point.PrevValue3 == valueRaw)
            {
                m_lastPoint.WriteCode(TsscCodeWords.Value3);
                point.PrevValue3 = point.PrevValue2;
                point.PrevValue2 = point.PrevValue1;
                point.PrevValue1 = valueRaw;
            }
            else if (valueRaw == 0)
            {
                m_lastPoint.WriteCode(TsscCodeWords.ValueZero);
                point.PrevValue3 = point.PrevValue2;
                point.PrevValue2 = point.PrevValue1;
                point.PrevValue1 = 0;
            }
            else
            {
                uint bitsChanged = valueRaw ^ point.PrevValue1;

                switch (bitsChanged)
                {
                case <= Bits4:
                    m_lastPoint.WriteCode(TsscCodeWords.ValueXOR4);
                    WriteBits((byte)bitsChanged & 15, 4);
                    break;

                case <= Bits8:
                    m_lastPoint.WriteCode(TsscCodeWords.ValueXOR8);

                    m_data[m_position] = (byte)bitsChanged;
                    m_position++;
                    break;

                case <= Bits12:
                    m_lastPoint.WriteCode(TsscCodeWords.ValueXOR12);
                    WriteBits((byte)bitsChanged & 15, 4);

                    m_data[m_position] = (byte)(bitsChanged >> 4);
                    m_position++;
                    break;

                case <= Bits16:
                    m_lastPoint.WriteCode(TsscCodeWords.ValueXOR16);
                    m_data[m_position]     = (byte)bitsChanged;
                    m_data[m_position + 1] = (byte)(bitsChanged >> 8);
                    m_position            += 2;
                    break;

                case <= Bits20:
                    m_lastPoint.WriteCode(TsscCodeWords.ValueXOR20);
                    WriteBits((byte)bitsChanged & 15, 4);

                    m_data[m_position]     = (byte)(bitsChanged >> 4);
                    m_data[m_position + 1] = (byte)(bitsChanged >> 12);
                    m_position            += 2;
                    break;

                case <= Bits24:
                    m_lastPoint.WriteCode(TsscCodeWords.ValueXOR24);

                    m_data[m_position]     = (byte)bitsChanged;
                    m_data[m_position + 1] = (byte)(bitsChanged >> 8);
                    m_data[m_position + 2] = (byte)(bitsChanged >> 16);
                    m_position            += 3;
                    break;

                case <= Bits28:
                    m_lastPoint.WriteCode(TsscCodeWords.ValueXOR28);
                    WriteBits((byte)bitsChanged & 15, 4);

                    m_data[m_position]     = (byte)(bitsChanged >> 4);
                    m_data[m_position + 1] = (byte)(bitsChanged >> 12);
                    m_data[m_position + 2] = (byte)(bitsChanged >> 20);
                    m_position            += 3;
                    break;

                default:
                    m_lastPoint.WriteCode(TsscCodeWords.ValueXOR32);

                    m_data[m_position]     = (byte)bitsChanged;
                    m_data[m_position + 1] = (byte)(bitsChanged >> 8);
                    m_data[m_position + 2] = (byte)(bitsChanged >> 16);
                    m_data[m_position + 3] = (byte)(bitsChanged >> 24);
                    m_position            += 4;
                    break;
                }

                point.PrevValue3 = point.PrevValue2;
                point.PrevValue2 = point.PrevValue1;
                point.PrevValue1 = valueRaw;
            }

            m_lastPoint = point;

            return(true);
        }