Skip to content

Commit f2ed28d

Browse files
asv-soft-u03asv-soft-u05
authored andcommitted
feat: add basic ulog file structure
Need to create all handlers Asana: https://app.asana.com/0/1203851531040615/1208409499620267/f
1 parent f7f6f97 commit f2ed28d

File tree

12 files changed

+313
-0
lines changed

12 files changed

+313
-0
lines changed

src/Asv.ULog/Asv.ULog.csproj.DotSettings

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@
33
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=serializers/@EntryIndexedValue">True</s:Boolean>
44
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=tokens/@EntryIndexedValue">True</s:Boolean>
55
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=tokens_005Cfileheader/@EntryIndexedValue">True</s:Boolean>
6+
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=ulogfile_005Cmodels/@EntryIndexedValue">False</s:Boolean>
7+
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=ulogfile_005Cprocessor/@EntryIndexedValue">False</s:Boolean>
8+
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=ulogfile_005Cprocessors_005Cfileelements/@EntryIndexedValue">True</s:Boolean>
9+
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=ulogfile_005Cprocessors_005Chandlers/@EntryIndexedValue">True</s:Boolean>
10+
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=ulogfile_005Cprocessors_005Cmodels/@EntryIndexedValue">True</s:Boolean>
11+
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=ulogfile_005Cprocessor_005Chandlers/@EntryIndexedValue">True</s:Boolean>
612
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=ulogvalue_005Ccontainer/@EntryIndexedValue">True</s:Boolean>
713
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=ulogvalue_005Csimple/@EntryIndexedValue">True</s:Boolean>
814
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=ulogvalue/@EntryIndexedValue">True</s:Boolean>
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace Asv.ULog.ULogFile.Processors;
2+
3+
public sealed class CompositeKey
4+
{
5+
public required ULogTypeDefinition Type { get; init; }
6+
public required string Name { get; init; }
7+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace Asv.ULog.ULogFile.Processors;
2+
3+
public sealed class SubscriptionMessage
4+
{
5+
public required byte MultiId { get; init; }
6+
public required ushort MessageId { get; init; }
7+
public required string MessageName { get; init; }
8+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
namespace Asv.ULog.ULogFile.Processors;
2+
3+
public class EmptyTokenHandler : ITokenHandler
4+
{
5+
public void Handle(IULogToken token, ProcessorContext context) { }
6+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using System.Diagnostics;
2+
3+
namespace Asv.ULog.ULogFile.Processors;
4+
5+
public class FileHeaderTokenHandler : ITokenHandler
6+
{
7+
public void Handle(IULogToken token, ProcessorContext context)
8+
{
9+
Debug.Assert(context.File.ReadState == TokenPlaceFlags.Header);
10+
var header = token as ULogFileHeaderToken;
11+
12+
context.File.Time = FromTimeStampToDateTime(header!.Timestamp).TimeOfDay;
13+
context.File.Version = header.Version;
14+
}
15+
16+
private static DateTime FromTimeStampToDateTime(ulong timestamp)
17+
{
18+
var dt = new DateTime(); // DateTimeOffset
19+
dt = dt.AddSeconds(timestamp).ToLocalTime();
20+
return dt;
21+
}
22+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using System.Diagnostics;
2+
3+
namespace Asv.ULog.ULogFile.Processors;
4+
5+
public class FlagBitsTokenHandler : ITokenHandler
6+
{
7+
public void Handle(IULogToken token, ProcessorContext context)
8+
{
9+
Debug.Assert(context.File.ReadState == TokenPlaceFlags.Header);
10+
var flagBits = token as ULogFlagBitsMessageToken;
11+
context.File.Definition.FlagBits.CompatFlags = flagBits!.CompatFlags;
12+
context.File.Definition.FlagBits.CompatFlags = flagBits.IncompatFlags;
13+
context.File.Definition.FlagBits.AppendedOffsets = flagBits.AppendedOffsets;
14+
}
15+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
namespace Asv.ULog.ULogFile.Processors;
2+
3+
public interface ITokenHandler
4+
{
5+
public void Handle(IULogToken token, ProcessorContext context);
6+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
namespace Asv.ULog.ULogFile.Processors;
2+
3+
public class ProcessorContext
4+
{
5+
public required ULogFile File { get; init; }
6+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
namespace Asv.ULog.ULogFile.Processors;
2+
3+
public class TokenProcessor
4+
{
5+
private readonly Dictionary<ULogToken, ITokenHandler> _handlers;
6+
private readonly ProcessorContext _context;
7+
8+
public TokenProcessor(Dictionary<ULogToken, ITokenHandler> handlers, ProcessorContext context)
9+
{
10+
_handlers = handlers;
11+
_context = context;
12+
}
13+
14+
public TokenPlaceFlags Process(IULogToken token)
15+
{
16+
if (_handlers.TryGetValue(token.TokenType, out var handler))
17+
{
18+
handler.Handle(token, _context);
19+
return token.TokenSection;
20+
}
21+
else
22+
{
23+
return _context.File.ReadState; // while not all tokens are handled
24+
throw new UnknownTokenException();
25+
}
26+
}
27+
}

src/Asv.ULog/ULogFile/ULogFile.cs

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
using System.Buffers;
2+
using System.Collections.Immutable;
3+
using System.Diagnostics;
4+
using Asv.ULog.ULogFile.Processors;
5+
6+
namespace Asv.ULog.ULogFile;
7+
8+
public class Data
9+
{
10+
public IDictionary<ushort, SubscriptionMessage> SubscriptionMessages { get; } = new Dictionary<ushort, SubscriptionMessage>();
11+
public IDictionary<ushort, ULogArray> LoggedDataMessages { get; } = new Dictionary<ushort, ULogArray>();
12+
public ICollection<ULogObject> LoggedStringMessages { get; } = new List<ULogObject>();
13+
public IDictionary<ushort, ULogObject> TaggedLoggedStringMessages { get; } = new Dictionary<ushort, ULogObject>();
14+
public ICollection<ULogObject> SynchronizationMessages { get; } = new List<ULogObject>();
15+
public ICollection<ushort> DropoutMessages { get; } = new List<ushort>();
16+
17+
public IDictionary<CompositeKey, string> InformationMessages { get; } = new Dictionary<CompositeKey, string>();
18+
public IDictionary<CompositeKey, ICollection<string>> MultiInformationMessages { get; } = new Dictionary<CompositeKey, ICollection<string>>();
19+
public IDictionary<CompositeKey, string> Parameters { get; } = new Dictionary<CompositeKey, string>();
20+
public IDictionary<CompositeKey, string> DefaultParameters { get; } = new Dictionary<CompositeKey, string>();
21+
}
22+
23+
public class Definition
24+
{
25+
public ULogFlagBitsMessageToken FlagBits { get; } = new();
26+
public ICollection<IDictionary<string, ULogValue>> FormatMessages { get; } = new List<IDictionary<string, ULogValue>>();
27+
public IDictionary<CompositeKey, string> InformationMessages { get; } = new Dictionary<CompositeKey, string>();
28+
public IDictionary<CompositeKey, ICollection<string>> MultiInformationMessages { get; } = new Dictionary<CompositeKey, ICollection<string>>();
29+
public IDictionary<CompositeKey, string> Parameters { get; } = new Dictionary<CompositeKey, string>();
30+
public IDictionary<CompositeKey, string> DefaultParameters { get; } = new Dictionary<CompositeKey, string>();
31+
}
32+
33+
public class ULogFile
34+
{
35+
private readonly IULogReader _reader;
36+
private readonly TokenProcessor _processor;
37+
38+
/*
39+
Header
40+
*/
41+
public TimeSpan Time { get; set; }
42+
public byte Version { get; set; }
43+
44+
45+
public readonly Definition Definition = new();
46+
public readonly Data Data = new();
47+
48+
public TokenPlaceFlags ReadState { get; private set; } = TokenPlaceFlags.None;
49+
50+
public ULogFile(IULogReader reader)
51+
{
52+
_reader = reader;
53+
_processor = new TokenProcessor(new Dictionary<ULogToken, ITokenHandler>
54+
{
55+
{ ULogToken.FileHeader, new FileHeaderTokenHandler() },
56+
{ ULogToken.FlagBits, new FlagBitsTokenHandler() },
57+
{ ULogToken.Unsubscription, new EmptyTokenHandler() } // cause unsub is not used currently
58+
}, new ProcessorContext{ File = this });
59+
}
60+
61+
public void Deserialize(ref ReadOnlySequence<byte> data)
62+
{
63+
ReadState = TokenPlaceFlags.Header;
64+
var rdr = new SequenceReader<byte>(data);
65+
while (_reader.TryRead(ref rdr, out var token))
66+
{
67+
Debug.Assert(token is not null);
68+
ReadState = _processor.Process(token);
69+
}
70+
}
71+
72+
public void Serialize(ref Span<byte> buffer)
73+
{
74+
throw new NotImplementedException();
75+
}
76+
77+
public static ULogValue Create(ULogLoggedDataMessageToken data,IReadOnlyDictionary<string, ULogFormatMessageToken> messages,
78+
IReadOnlyDictionary<ushort, ULogSubscriptionMessageToken> subscriptions, out string messageName)
79+
{
80+
var sub = subscriptions[data.MessageId];
81+
var message = messages[sub.MessageName];
82+
messageName = sub.MessageName;
83+
var obj = CreateReference(message.MessageName,messages);
84+
var span = new ReadOnlySpan<byte>(data.Data);
85+
obj.Deserialize(ref span);
86+
return obj;
87+
}
88+
89+
private static ULogObject CreateReference(string name, IReadOnlyDictionary<string, ULogFormatMessageToken> messages)
90+
{
91+
var message = messages[name];
92+
var builder = ImmutableArray.CreateBuilder<ULogProperty>(message.Fields.Count);
93+
foreach (var field in message.Fields)
94+
{
95+
var prop = Create(field.Type, messages);
96+
builder.Add(new ULogProperty(field.Name,prop));
97+
}
98+
if (message.Fields[^1].Name.StartsWith("_padding"))
99+
{
100+
builder.RemoveAt(builder.Count - 1);
101+
}
102+
return new ULogObject(builder.ToImmutable());
103+
}
104+
105+
private static ULogValue Create(ULogTypeDefinition fieldType, IReadOnlyDictionary<string, ULogFormatMessageToken> messages)
106+
{
107+
ULogValue value;
108+
if (fieldType.BaseType == ULogType.ReferenceType)
109+
{
110+
value = CreateReference(fieldType.TypeName, messages);
111+
}
112+
else
113+
{
114+
value = CreateSimple(fieldType);
115+
}
116+
117+
if (!fieldType.IsArray) return value;
118+
119+
var buidler = ImmutableArray.CreateBuilder<ULogValue>(fieldType.ArraySize);
120+
buidler.Add(value);
121+
for (var i = 1; i < fieldType.ArraySize; i++)
122+
{
123+
buidler.Add(value.CloneToken());
124+
}
125+
126+
return new ULogArray(buidler.ToImmutable());
127+
128+
}
129+
130+
private static ULogSimple CreateSimple(ULogTypeDefinition type)
131+
{
132+
switch (type.BaseType)
133+
{
134+
case ULogType.Int8:
135+
return new ULogInt8();
136+
case ULogType.UInt8:
137+
return new ULogUInt8();
138+
case ULogType.Int16:
139+
return new ULogInt16();
140+
case ULogType.UInt16:
141+
return new ULogUInt16();
142+
case ULogType.Int32:
143+
return new ULogInt32();
144+
case ULogType.UInt32:
145+
return new ULogUInt32();
146+
case ULogType.Int64:
147+
return new ULogInt64();
148+
case ULogType.UInt64:
149+
return new ULogUInt64();
150+
case ULogType.Float:
151+
return new ULogFloat();
152+
case ULogType.Double:
153+
return new ULogDouble();
154+
case ULogType.Bool:
155+
return new ULogBool();
156+
case ULogType.Char:
157+
return new ULogChar();
158+
case ULogType.ReferenceType:
159+
default:
160+
throw new ArgumentOutOfRangeException();
161+
}
162+
}
163+
}

0 commit comments

Comments
 (0)