init
This commit is contained in:
166
DataPRO/SLICECommands/RealtimeCommands/RealtimeStreamDecoder.cs
Normal file
166
DataPRO/SLICECommands/RealtimeCommands/RealtimeStreamDecoder.cs
Normal file
@@ -0,0 +1,166 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user