1 //
2 // Copyright (c) 2010-2023 Antmicro
3 //
4 // This file is licensed under the MIT License.
5 // Full license text is available in 'licenses/MIT.txt'.
6 //
7 using System;
8 using System.Collections.Generic;
9 using System.Globalization;
10 
11 namespace Antmicro.Renode.Utilities.RESD
12 {
13     public abstract class RESDSample : IAutoLoadType
14     {
TryReadMetadata(SafeBinaryReader reader)15         public virtual bool TryReadMetadata(SafeBinaryReader reader)
16         {
17             Metadata = MetadataBlock.ReadFromStream(reader);
18             return true;
19         }
20 
Skip(SafeBinaryReader reader, int count)21         public virtual bool Skip(SafeBinaryReader reader, int count)
22         {
23             if(!Width.HasValue)
24             {
25                 throw new RESDException($"This sample type ({this.GetType().Name}) doesn't allow for skipping data.");
26             }
27 
28             if(reader.BaseStream.Position + count * Width.Value > reader.Length)
29             {
30                 return false;
31             }
32 
33             reader.SkipBytes(count * Width.Value);
34             return true;
35         }
36 
37         public abstract int? Width { get; }
TryReadFromStream(SafeBinaryReader reader)38         public abstract bool TryReadFromStream(SafeBinaryReader reader);
39 
40         public IDictionary<string, MetadataValue> Metadata { get; private set; }
41 
42         // Ensure decimal dots are always used regardless of the system locale
43         // for consistent output formatting.
DecimalToString(decimal value)44         protected static string DecimalToString(decimal value)
45         {
46             return value.ToString(CultureInfo.InvariantCulture);
47         }
48     }
49 
50     [SampleType(SampleType.Temperature)]
51     public class TemperatureSample : RESDSample
52     {
53         public override int? Width => 4;
54 
55         public int Temperature { get; private set; }
56 
TryReadFromStream(SafeBinaryReader reader)57         public override bool TryReadFromStream(SafeBinaryReader reader)
58         {
59             Temperature = reader.ReadInt32();
60 
61             return true;
62         }
63 
ToString()64         public override string ToString()
65         {
66             return $"{DecimalToString(Temperature / (decimal)1e3)} °C";
67         }
68     }
69 
70     [SampleType(SampleType.Acceleration)]
71     public class AccelerationSample : RESDSample
72     {
73         public override int? Width => 4 * 3;
74 
75         public int AccelerationX { get; private set; }
76         public int AccelerationY { get; private set; }
77         public int AccelerationZ { get; private set; }
78 
TryReadFromStream(SafeBinaryReader reader)79         public override bool TryReadFromStream(SafeBinaryReader reader)
80         {
81             AccelerationX = reader.ReadInt32();
82             AccelerationY = reader.ReadInt32();
83             AccelerationZ = reader.ReadInt32();
84 
85             return true;
86         }
87 
ToString()88         public override string ToString()
89         {
90             var xStr = DecimalToString(AccelerationX / (decimal)1e6);
91             var yStr = DecimalToString(AccelerationY / (decimal)1e6);
92             var zStr = DecimalToString(AccelerationZ / (decimal)1e6);
93 
94             return $"[{xStr}, {yStr}, {zStr}] g";
95         }
96     }
97 
98     [SampleType(SampleType.AngularRate)]
99     public class AngularRateSample : RESDSample
100     {
101         public override int? Width => 4 * 3;
102 
103         public int AngularRateX { get; private set; }
104         public int AngularRateY { get; private set; }
105         public int AngularRateZ { get; private set; }
106 
TryReadFromStream(SafeBinaryReader reader)107         public override bool TryReadFromStream(SafeBinaryReader reader)
108         {
109             AngularRateX = reader.ReadInt32();
110             AngularRateY = reader.ReadInt32();
111             AngularRateZ = reader.ReadInt32();
112 
113             return true;
114         }
115 
ToString()116         public override string ToString()
117         {
118             var xStr = DecimalToString(AngularRateX / (decimal)1e5);
119             var yStr = DecimalToString(AngularRateY / (decimal)1e5);
120             var zStr = DecimalToString(AngularRateZ / (decimal)1e5);
121 
122             return $"[{xStr}, {yStr}, {zStr}] rad/s";
123         }
124     }
125 
126     [SampleType(SampleType.Voltage)]
127     public class VoltageSample : RESDSample
128     {
129         public override int? Width => 4;
130 
131         public uint Voltage { get; private set; }
132 
TryReadFromStream(SafeBinaryReader reader)133         public override bool TryReadFromStream(SafeBinaryReader reader)
134         {
135             Voltage = reader.ReadUInt32();
136 
137             return true;
138         }
139 
ToString()140         public override string ToString()
141         {
142             return $"{DecimalToString(Voltage / (decimal)1e6)} V";
143         }
144     }
145 
146     [SampleType(SampleType.ECG)]
147     public class ECGSample : RESDSample
148     {
149         public override int? Width => 4;
150 
151         public int ECG { get; private set; }
152 
TryReadFromStream(SafeBinaryReader reader)153         public override bool TryReadFromStream(SafeBinaryReader reader)
154         {
155             ECG = reader.ReadInt32();
156 
157             return true;
158         }
159 
ToString()160         public override string ToString()
161         {
162             return $"{ECG} nV";
163         }
164     }
165 
166     [SampleType(SampleType.Humidity)]
167     public class HumiditySample : RESDSample
168     {
169         public override int? Width => 4;
170 
171         public uint Humidity { get; private set; }
172 
TryReadFromStream(SafeBinaryReader reader)173         public override bool TryReadFromStream(SafeBinaryReader reader)
174         {
175             Humidity = reader.ReadUInt32();
176 
177             return true;
178         }
179 
ToString()180         public override string ToString()
181         {
182             return $"{DecimalToString(Humidity / 1e3m)} %RH";
183         }
184     }
185 
186     [SampleType(SampleType.Pressure)]
187     public class PressureSample : RESDSample
188     {
189         public override int? Width => 8;
190 
191         public ulong Pressure { get; private set; }
192 
TryReadFromStream(SafeBinaryReader reader)193         public override bool TryReadFromStream(SafeBinaryReader reader)
194         {
195             Pressure = reader.ReadUInt64();
196 
197             return true;
198         }
199 
ToString()200         public override string ToString()
201         {
202             return $"{DecimalToString(Pressure / (decimal)1e3)} Pa";
203         }
204     }
205 
206     [SampleType(SampleType.MagneticFluxDensity)]
207     public class MagneticSample : RESDSample
208     {
209         public override int? Width => 4 * 3;
210 
211         public int MagneticFluxDensityX { get; private set; }
212         public int MagneticFluxDensityY { get; private set; }
213         public int MagneticFluxDensityZ { get; private set; }
214 
TryReadFromStream(SafeBinaryReader reader)215         public override bool TryReadFromStream(SafeBinaryReader reader)
216         {
217             MagneticFluxDensityX = reader.ReadInt32();
218             MagneticFluxDensityY = reader.ReadInt32();
219             MagneticFluxDensityZ = reader.ReadInt32();
220 
221             return true;
222         }
223 
ToString()224         public override string ToString()
225         {
226             return $"[{MagneticFluxDensityX}, {MagneticFluxDensityY}, {MagneticFluxDensityZ}] nT";
227         }
228     }
229 
230     public class SampleTypeAttribute : Attribute
231     {
SampleTypeAttribute(SampleType sampleType)232         public SampleTypeAttribute(SampleType sampleType)
233         {
234             this.SampleType = sampleType;
235         }
236 
237         public SampleType SampleType { get; }
238     }
239 
240     public enum SampleType
241     {
242         // General sample types
243         Temperature = 0x0001,
244         Acceleration = 0x002,
245         AngularRate = 0x0003,
246         Voltage = 0x0004,
247         ECG = 0x0005,
248         Humidity = 0x0006,
249         Pressure = 0x0007,
250         MagneticFluxDensity = 0x0008,
251 
252         // Custom sample types
253         Custom = 0xF000,
254     }
255 }
256