Skip to main content

Frame enumeration

The following C# code snippets demonstrate how to enumerate vehicle data frames from a received data batch:

internal readonly struct PubSubFrame
{
public int Version { get; init; }

public string VehicleId { get; init; }

public int Length { get; init; }

public ReadOnlyMemory<byte> Data { get; init; }
}

internal readonly struct PubSubBatch(ReadOnlyMemory<byte> data) : IEnumerable<PubSubFrame>
{
public ReadOnlyMemory<byte> Data { get; } = data;

public IEnumerator<PubSubFrame> GetEnumerator()
{
const int VEHICLE_ID_LENGTH = 16;
const char HEADER_CHAR = 'F';
const int VERSION_V1 = 0x01;

for (int idx = 0; idx < Data.Length;)
{
byte header = Data.Span[idx++];
if (header != HEADER_CHAR)
{
throw new Exception("Invalid frame header");
}

byte version = Data.Span[idx++];
if (version != VERSION_V1)
{
throw new Exception("Unsupported version");
}

ReadOnlyMemory<byte> vId = Data.Slice(idx, VEHICLE_ID_LENGTH);
Guid vGuid = new(vId.ToArray());
string vehicleId = vGuid.ToString();
idx += VEHICLE_ID_LENGTH;

int length = BinaryPrimitives.ReadInt32LittleEndian(Data.Span[idx..]);
idx += sizeof(int);

ReadOnlyMemory<byte> data = Data.Slice(idx, length);
idx += length;

yield return new PubSubFrame()
{
Version = version,
VehicleId = vehicleId,
Length = length,
Data = data
};
}
}

IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}

Usage Example

The following example shows how to process incoming messages and iterate through the vehicle data frames contained in each batch:

Task startTask = subscriber.StartAsync((PubsubMessage message, CancellationToken cancel) =>
{
Console.WriteLine($"Received message - length: {message.Data.Length}");

try
{
// Process received message here
foreach (PubSubFrame frame in new PubSubBatch(message.Data.Memory))
{
// Processing vehicle data frames
}
}
catch (Exception e)
{
Console.WriteLine($"ERROR: {e.Message}");
}

return Task.FromResult(SubscriberClient.Reply.Ack);
});