167 lines
6.5 KiB
C#
167 lines
6.5 KiB
C#
|
|
using System;
|
|||
|
|
using System.Collections;
|
|||
|
|
using System.Collections.Generic;
|
|||
|
|
|
|||
|
|
namespace DTS.DASLib.Command.SLICE.RealtimeCommands
|
|||
|
|
{
|
|||
|
|
/// <summary>
|
|||
|
|
/// this class handles decoding a SPS realtime stream packet.
|
|||
|
|
/// </summary>
|
|||
|
|
public class RealtimeStreamDecoder
|
|||
|
|
{
|
|||
|
|
/* per lp,
|
|||
|
|
* Byte index:
|
|||
|
|
0 Sync = CMD_SYNC_BYTE = 0xFA
|
|||
|
|
1 type = CMD_TYPE_REALTIME = 0x08
|
|||
|
|
2 command = CMDRT_REALTIME_STREAM_SAMPLE_PUSH = 0x08
|
|||
|
|
3 status = STATUS_ERROR_NONE = 0x00
|
|||
|
|
4 group = 0x00;
|
|||
|
|
5 id = 0x00;
|
|||
|
|
6-7 datalength
|
|||
|
|
8-9 sequence number
|
|||
|
|
10-11 headerCRC16
|
|||
|
|
12-13 dataCRC16 (currently not used)
|
|||
|
|
… payload
|
|||
|
|
8-byte uint64_t Timestamp (for first sample in payload.)
|
|||
|
|
4-byte uint32_t Channel list (bit set = channel present. Bit clear = channel not present.
|
|||
|
|
8-byte uint64_t Sample Number (starting with first ADC scan in payload)
|
|||
|
|
Number of ADC-Scan sample = (datalength – 20) / (channellist*2)
|
|||
|
|
*/
|
|||
|
|
/// <summary>
|
|||
|
|
/// this is the order of information in the packet
|
|||
|
|
/// the enum value is the offset in bytes from the start of the packet
|
|||
|
|
/// </summary>
|
|||
|
|
public enum ByteIndex
|
|||
|
|
{
|
|||
|
|
Sync = 0,
|
|||
|
|
Type = 1,
|
|||
|
|
Command = 2,
|
|||
|
|
Status = 3,
|
|||
|
|
Group = 4,
|
|||
|
|
Id = 5,
|
|||
|
|
DataLength = 6,
|
|||
|
|
SequenceNumber = 8,
|
|||
|
|
HeaderCRC = 10,
|
|||
|
|
DataCRC = 12,
|
|||
|
|
TimeStamp = 14,
|
|||
|
|
ChannelList = 22,
|
|||
|
|
SampleNumber = 26,
|
|||
|
|
DataStart = 34
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public ushort SequenceNumber { get; }
|
|||
|
|
public ulong TimeStamp { get; }
|
|||
|
|
public ulong SampleNumber { get; }
|
|||
|
|
public int[] Channels { get; }
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// this is all data, not transformed into (short) yet, which requires 2's compliment
|
|||
|
|
/// it is also for all channels in the realtime stream
|
|||
|
|
/// </summary>
|
|||
|
|
public ushort[] RtData { get; }
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// constructors and decodes byte stream
|
|||
|
|
///
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="bytes"></param>
|
|||
|
|
public RealtimeStreamDecoder(IReadOnlyList<byte> bytes)
|
|||
|
|
{
|
|||
|
|
if (bytes.Count > (int)ByteIndex.DataStart)
|
|||
|
|
{
|
|||
|
|
TimeStamp = GetULong(bytes, (int)ByteIndex.TimeStamp);
|
|||
|
|
SequenceNumber = GetUShort(bytes, (int)ByteIndex.SequenceNumber);
|
|||
|
|
SampleNumber = GetULong(bytes, (int)ByteIndex.SampleNumber);
|
|||
|
|
RtData = new ushort[(bytes.Count - (int)ByteIndex.DataStart) / 2];
|
|||
|
|
var uintChannelList = GetUINT(bytes, (int)ByteIndex.ChannelList);
|
|||
|
|
var channels = new List<int>();
|
|||
|
|
var ba = new BitArray(BitConverter.GetBytes(uintChannelList));
|
|||
|
|
for (var i = 0; i < ba.Length; i++)
|
|||
|
|
{
|
|||
|
|
if (ba.Get(i))
|
|||
|
|
{
|
|||
|
|
channels.Add(i);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Channels = channels.ToArray();
|
|||
|
|
for (var idx = 0; idx < RtData.Length; idx++)
|
|||
|
|
{
|
|||
|
|
//all the data is stored as uint16 with channel order so
|
|||
|
|
// AABBCCDDEEFF, so split out the ushorts
|
|||
|
|
RtData[idx] = GetRTUShort(bytes, (int)(ByteIndex.DataStart + idx * 2));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
RtData = new ushort[0];
|
|||
|
|
SampleNumber = 0;
|
|||
|
|
Channels = new int[0];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// returns a ulong given a sequence of bytes and a starting offset in bytes
|
|||
|
|
/// that the ulong starts at
|
|||
|
|
/// SLICE header bytes are sent in reverse order so we have to fix them first
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="bytes"></param>
|
|||
|
|
/// <param name="offset"></param>
|
|||
|
|
/// <returns></returns>
|
|||
|
|
private static ulong GetULong(IReadOnlyList<byte> bytes, int offset)
|
|||
|
|
{
|
|||
|
|
return (ulong)bytes[offset + 7] << 0 |
|
|||
|
|
(ulong)bytes[offset + 6] << 8 |
|
|||
|
|
(ulong)bytes[offset + 5] << 16 |
|
|||
|
|
(ulong)bytes[offset + 4] << 24 |
|
|||
|
|
(ulong)bytes[offset + 3] << 32 |
|
|||
|
|
(ulong)bytes[offset + 2] << 40 |
|
|||
|
|
(ulong)bytes[offset + 1] << 48 |
|
|||
|
|
(ulong)bytes[offset + 0] << 56;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// gets a ushort from the response parameters
|
|||
|
|
/// SLICE header bytes are sent in reverse order, so we have to fix
|
|||
|
|
/// them first
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="bytes"></param>
|
|||
|
|
/// <param name="offset"></param>
|
|||
|
|
/// <returns></returns>
|
|||
|
|
private static uint GetUINT(IReadOnlyList<byte> bytes, int offset)
|
|||
|
|
{
|
|||
|
|
return (uint)bytes[offset + 3] << 0 |
|
|||
|
|
(uint)bytes[offset + 2] << 8 |
|
|||
|
|
(uint)bytes[offset + 1] << 16 |
|
|||
|
|
(uint)bytes[offset + 0] << 32;
|
|||
|
|
}
|
|||
|
|
/// <summary>
|
|||
|
|
/// returns a ushort given a sequence of bytes and a starting offset in bytes
|
|||
|
|
/// SLICE header bytes are sent in reverse order, so we have to fix the byte
|
|||
|
|
/// order first
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="bytes"></param>
|
|||
|
|
/// <param name="offset"></param>
|
|||
|
|
/// <returns></returns>
|
|||
|
|
private static ushort GetUShort(IReadOnlyList<byte> bytes, int offset)
|
|||
|
|
{
|
|||
|
|
return (ushort)(bytes[offset + 1] |
|
|||
|
|
bytes[offset + 0] << 8);
|
|||
|
|
}
|
|||
|
|
/// <summary>
|
|||
|
|
/// returns a ushort given a sequence of bytes and a starting offset in bytes
|
|||
|
|
/// note that DATA is not in reverse order unlike the header, so we
|
|||
|
|
/// DON'T need to fix the order
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="bytes"></param>
|
|||
|
|
/// <param name="offset"></param>
|
|||
|
|
/// <returns></returns>
|
|||
|
|
private static ushort GetRTUShort(IReadOnlyList<byte> bytes, int offset)
|
|||
|
|
{
|
|||
|
|
return (ushort)(bytes[offset + 0] |
|
|||
|
|
bytes[offset + 1] << 8);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|