Skip to content

Commit 35ed38b

Browse files
committed
16 - Updated telegrams
Updated existing telegrams and added new ones
1 parent 713a1b8 commit 35ed38b

14 files changed

Lines changed: 709 additions & 210 deletions

RS485 Monitor/src/TelegramParser.cs

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ public void ParseChunk(byte[] rawData)
132132
/// <summary>
133133
/// Parse the given file
134134
/// </summary>
135-
/// <param name="filePath"></param>
135+
/// <param name="filePath"></param>
136136
public void ParseFile(string filePath)
137137
{
138138
FileInfo info = new(filePath);
@@ -199,28 +199,23 @@ private void FinishBlock()
199199
return null;
200200
}
201201

202-
// Check if we can convert
203-
if ( tg.Type == BaseTelegram.TelegramType.READ_RESPONSE)
202+
// Define known telegrams
203+
Dictionary<UInt16, Type> knownTelegrams = new()
204204
{
205-
if (tg.Source == 0xAA && tg.Destination == 0x5A && tg.PDU.Length == 10)
206-
{
207-
tg = new BatteryStatus(tg);
208-
}
209-
else if (tg.Source == 0xAA && tg.Destination == 0xDA && tg.PDU.Length == 10)
210-
{
211-
tg = new ECUStatus(tg);
212-
}
213-
}
214-
215-
else if (tg.Type == BaseTelegram.TelegramType.READ_REQUEST)
205+
{ControllerRequest.TELEGRAM_ID, typeof(ControllerRequest) },
206+
{ControllerResponse.TELEGRAM_ID, typeof(ControllerResponse) },
207+
{BatteryRequest.TELEGRAM_ID, typeof(BatteryRequest) },
208+
{BatteryResponse.TELEGRAM_ID, typeof(BatteryResponse) },
209+
{SpeedometerRequest.TELEGRAM_ID, typeof(SpeedometerRequest) },
210+
{SpeedometerResponse.TELEGRAM_ID, typeof(SpeedometerResponse) },
211+
};
212+
213+
// try to fetch the special telegram type
214+
if (knownTelegrams.TryGetValue(tg.Id, out Type? specialType))
216215
{
217-
if (tg.Source == 0xBA && tg.Destination == 0xAA && tg.PDU.Length == GSMStatus.RAW_DATA_LEN)
218-
{
219-
tg = new GSMStatus(tg);
220-
}
216+
tg = (BaseTelegram?)Activator.CreateInstance(specialType, [tg]);
221217
}
222218

223219
return tg;
224220
}
225-
226-
}
221+
}
Lines changed: 123 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
using NLog;
22

33
/// <summary>
4-
/// This class defines a basic telegram with data. No special parsing of the
4+
/// This class defines a basic telegram with data. No special parsing of the
55
/// content is done here. Check the specialized classes for more detail
66
/// </summary>
77
public class BaseTelegram : IEquatable<BaseTelegram>
@@ -11,86 +11,141 @@ public class BaseTelegram : IEquatable<BaseTelegram>
1111
/// </summary>
1212
static readonly Logger log = LogManager.GetCurrentClassLogger();
1313

14-
#region Properties
14+
15+
#region Constants
1516
/// <summary>
16-
/// Start Sequence of the telegram
17+
/// Maximum supported data length
1718
/// </summary>
18-
public UInt16 Start { get => (UInt16)((Raw[0] << 8) + Raw[1]); }
19+
private const byte MAX_DATA_LEN = 32;
1920

2021
/// <summary>
21-
/// Source of the telegram
22+
/// Minimum length of a telegram. This contains the following data:
23+
/// - Type (2 bytes)
24+
/// - Destination (1 byte)
25+
/// - Source (1 byte)
26+
/// - Data length (1 byte)
27+
/// - Checksum (1 byte)
28+
/// - End byte (1 byte)
2229
/// </summary>
23-
public byte Source { get => Raw[POS_SRC]; }
30+
private const byte MIN_DATA_LEN = 7;
2431

2532
/// <summary>
26-
/// Destination of the telegram
33+
/// End byte of the telegram
2734
/// </summary>
28-
public byte Destination { get => Raw[POS_DES]; }
35+
private const byte END_TELEGRAM = 0x0D;
2936

3037
/// <summary>
31-
/// User Data
38+
/// Offset of the high Byte of the the telegram type
3239
/// </summary>
33-
public byte[] PDU { get; }
40+
private const byte POS_TYPE_H = 0;
41+
/// <summary>
42+
/// Offset of the low Byte of the the telegram type
43+
/// </summary>
44+
private const byte POS_TYPE_L = 1;
45+
/// <summary>
46+
/// Position of the destination id in the raw data
47+
/// </summary>
48+
private const byte POS_DES = 2;
49+
/// <summary>
50+
/// Position of the source id in the raw data
51+
/// </summary>
52+
private const byte POS_SRC = 3;
53+
/// <summary>
54+
/// Position of the data length in the raw data
55+
/// </summary>
56+
private const byte POS_LEN = 4;
57+
#endregion
3458

59+
#region Properties
3560
/// <summary>
36-
/// Received checksum
61+
/// Type of the telegram as raw value
3762
/// </summary>
38-
public byte Checksum { get => Raw[POS_LEN + PDU.Length + 1]; }
63+
public UInt16 RawType
64+
{
65+
get => (UInt16)((Raw[POS_TYPE_H] << 8) + Raw[POS_TYPE_L]);
66+
}
3967

4068
/// <summary>
41-
/// Copy of the received raw data of the telegram
69+
/// Destination / recipient of the telegram
4270
/// </summary>
43-
public byte[] Raw { get; }
71+
public byte Destination { get => Raw[POS_DES]; }
4472

4573
/// <summary>
46-
/// Are the raw data valid against the Checksum
74+
/// Source / sender of the telegram
4775
/// </summary>
48-
public bool Valid { get; }
76+
public byte Source { get => Raw[POS_SRC]; }
4977

50-
public enum TelegramType
78+
/// <summary>
79+
/// Identifier for the telegram type. Is is a mixture of the telegram type,
80+
/// the destination and the source.
81+
/// </summary>
82+
public UInt16 Id
5183
{
52-
READ_REQUEST = 0xC55C,
53-
READ_RESPONSE = 0xB66B
84+
get => (UInt16)(Destination << 8 | Source);
5485
}
86+
5587
/// <summary>
56-
/// Type of the telegram
88+
/// User Data / specific to the telegram
5789
/// </summary>
58-
public TelegramType Type { get => (TelegramType)Start; }
59-
60-
#endregion
90+
public byte[] PDU { get; }
6191

62-
#region Constants
6392
/// <summary>
64-
/// Maximum supported data length
93+
/// Received checksum
6594
/// </summary>
66-
private const byte MAX_DATA_LEN = 32;
95+
public byte Checksum { get => Raw[POS_LEN + PDU.Length + 1]; }
6796

6897
/// <summary>
69-
/// End byte of the telegram
98+
/// Complete telegram as raw data
7099
/// </summary>
71-
private const byte END_TELEGRAM = 0x0D;
100+
public byte[] Raw { get; }
72101

73102
/// <summary>
74-
/// Position of the source id in the raw data
103+
/// The raw PDU is valid against the received checksum
75104
/// </summary>
76-
private const byte POS_SRC = 2;
105+
public bool Valid
106+
{
107+
get
108+
{
109+
byte calcCheck = Raw[POS_LEN];
110+
foreach (byte b in PDU)
111+
{
112+
calcCheck ^= b;
113+
}
114+
115+
log.Trace($"Checksum: read={Checksum.ToString("X2")}, calc={calcCheck.ToString("X2")}");
116+
return calcCheck == Checksum;
117+
}
118+
}
119+
77120
/// <summary>
78-
/// Position of the destination id in the raw data
121+
/// Possible types of the telegram
79122
/// </summary>
80-
private const byte POS_DES = 3;
123+
public enum TelegramType
124+
{
125+
/// <summary>
126+
/// Request telegram triggered by bus master to the unit
127+
/// </summary>
128+
REQUEST = 0xC55C,
129+
/// <summary>
130+
/// Telegram sent as a response to a request from the unit to the bus master
131+
/// </summary>
132+
RESPONSE = 0xB66B
133+
}
134+
81135
/// <summary>
82-
/// Position of the data length in the raw data
136+
/// Type of the telegram
83137
/// </summary>
84-
private const byte POS_LEN = 4;
138+
public TelegramType Type { get => (TelegramType)RawType; }
139+
85140
#endregion
86141

87142
/// <summary>
88-
/// Internal constructor for specialized classes
143+
/// Internal constructor for specialized classes. Create empty arrays
89144
/// </summary>
90145
protected BaseTelegram()
91146
{
92-
PDU = new byte[1];
93-
Raw = new byte[1];
147+
PDU = Array.Empty<byte>();
148+
Raw = Array.Empty<byte>();
94149
}
95150

96151
/// <summary>
@@ -104,56 +159,52 @@ protected BaseTelegram(BaseTelegram c)
104159

105160
this.PDU = new byte[c.PDU.Length];
106161
Array.Copy(c.PDU, this.PDU, this.PDU.Length);
107-
108-
this.Valid = c.Valid;
109162
}
110163

111164
/// <summary>
112165
/// Create a new base telegram based on the given raw data
113166
/// </summary>
114167
/// <param name="rawData">raw data of one telegram</param>
115-
/// <exception cref="ArgumentException">Given data length in the raw data is invalid.</exception>
168+
/// <exception cref="ArgumentNullException">Raw data is null.</exception>
169+
/// <exception cref="ArgumentException">Raw data is too short.</exception>
170+
/// <exception cref="ArgumentException">Invalid data length in the raw data.</exception>
171+
/// <exception cref="ArgumentException">Raw data does not contain End tag.</exception>
116172
public BaseTelegram(byte[] rawData)
117173
{
174+
// Basic validation
175+
ArgumentNullException.ThrowIfNull(rawData);
176+
if (rawData.Length < MIN_DATA_LEN)
177+
{
178+
throw new ArgumentException("Raw data is too short");
179+
}
180+
118181
// Copy raw data
119182
Raw = new byte[rawData.Length];
120183
Array.Copy(rawData, Raw, Raw.Length);
121184

122185
// fetch user data
123-
byte dataLen = rawData[POS_LEN];
124-
if (dataLen > MAX_DATA_LEN)
186+
byte pduLen = rawData[POS_LEN];
187+
if (pduLen > MAX_DATA_LEN)
125188
{
126-
throw new ArgumentException($"Invalid data len {dataLen}. Max supported: {MAX_DATA_LEN}");
189+
throw new ArgumentException($"Invalid data len {pduLen}. Max supported: {MAX_DATA_LEN}");
127190
}
128-
PDU = new byte[dataLen];
191+
192+
// copy user data to PDU array
193+
PDU = new byte[pduLen];
129194
Array.Copy(rawData, POS_LEN + 1, PDU, 0, PDU.Length);
130195

131-
/* Verify checksum
132-
* Checksum is calculated as XOR of the user data, including the length byte
133-
*/
134-
byte calcCheck = dataLen;
135-
foreach (byte b in PDU)
136-
{
137-
calcCheck ^= b;
138-
}
139-
log.Trace($"Checksum: read={Checksum.ToString("X2")}, calc={calcCheck.ToString("X2")}");
140-
Valid = (calcCheck == Checksum);
196+
// Verify checksum
141197
if (Valid == false)
142198
{
143-
log.Warn($"Telegram has an invalid checksum read:{Checksum.ToString("X2")}, calc:{calcCheck.ToString("X2")}");
199+
log.Warn("Telegram has an invalid checksum");
144200
}
145201

146-
// Check end telegram
147-
try
148-
{
149-
if (rawData.Length < (5 + 1 + dataLen) || rawData[5 + 1 + dataLen] != END_TELEGRAM)
150-
{
151-
log.Warn("RawData does not hold Endtag");
152-
}
153-
}
154-
catch (IndexOutOfRangeException)
202+
// Check end telegram value
203+
int pos_end_tag = MIN_DATA_LEN - 1 + pduLen;
204+
if (rawData.Length < pos_end_tag || rawData[pos_end_tag] != END_TELEGRAM)
155205
{
156-
log.Warn("Rawdata does not contain End tag");
206+
log.Error("RawData does not hold Endtag");
207+
throw new ArgumentException("Raw data does not contain End tag");
157208
}
158209
}
159210

@@ -192,8 +243,14 @@ public virtual string ToStringDetailed()
192243
return ToString();
193244
}
194245

246+
/// <summary>
247+
/// Compare two telegrams based on the raw data
248+
/// </summary>
249+
/// <param name="other">Second object to compare</param>
250+
/// <returns></returns>
195251
public bool Equals(BaseTelegram? other)
196252
{
197253
return Array.Equals(this.Raw, other?.Raw);
198254
}
199-
}
255+
256+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
using NLog;
2+
3+
/// <summary>
4+
/// Specialization of the BaseTelegram class that extracts the information
5+
/// of BatteryStatus
6+
/// </summary>
7+
public class BatteryRequest : BaseTelegram
8+
{
9+
/// <summary>
10+
/// Internal logging object
11+
/// </summary>
12+
private static readonly Logger log = LogManager.GetCurrentClassLogger();
13+
14+
#region Constants
15+
/// <summary>
16+
/// Required size of PDU data
17+
/// </summary>
18+
private const byte PDU_LENGTH = 1;
19+
20+
21+
private const byte SOURCE = (byte)Units.ECU;
22+
private const byte DESTINATION = (byte)Units.BATTERY;
23+
public const UInt16 TELEGRAM_ID = DESTINATION << 8 | SOURCE;
24+
#endregion
25+
26+
/// <summary>
27+
/// Create a new Battery Status object based on a received telegram
28+
/// </summary>
29+
/// <param name="t">Raw telegram</param>
30+
/// <exception cref="ArgumentException">Raw data has an unexpected length</exception>
31+
public BatteryRequest(BaseTelegram t)
32+
: base(t)
33+
{
34+
if (t.PDU.Length != PDU_LENGTH)
35+
{
36+
throw new ArgumentException($"Unexpected size of {t.PDU.Length}");
37+
}
38+
if (t.Source != SOURCE || t.Destination != DESTINATION)
39+
{
40+
throw new ArgumentException("Not a BatteryResponse telegram");
41+
}
42+
}
43+
44+
/// <summary>
45+
/// Get a string representation of the telegram
46+
/// </summary>
47+
/// <returns>String representation</returns>
48+
public override string ToString()
49+
{
50+
log.Trace(base.ToString());
51+
return "Battery Request";
52+
}
53+
}

0 commit comments

Comments
 (0)