-
-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathOBISId.cs
More file actions
132 lines (121 loc) · 5.05 KB
/
OBISId.cs
File metadata and controls
132 lines (121 loc) · 5.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Text;
namespace DSMRParser.Models;
/// <summary>
/// Represents an OBIS ID.
/// </summary>
[DebuggerDisplay("{ToString()}")]
public record OBISId
{
private static readonly char[] _splitchars = ['-', ':', '.'];
/// <summary>
/// A read-only instance of the <see cref="OBISId"/> structure whose value is all 255's.
/// </summary>
public static readonly OBISId NONE = new();
/// <summary>Part A of the OBIS ID (from the form A-B:C.D.E.F).</summary>
public byte A { get; init; } = 255;
/// <summary>Part B of the OBIS ID (from the form A-B:C.D.E.F).</summary>
public byte B { get; init; } = 255;
/// <summary>Part C of the OBIS ID (from the form A-B:C.D.E.F).</summary>
public byte C { get; init; } = 255;
/// <summary>Part D of the OBIS ID (from the form A-B:C.D.E.F).</summary>
public byte D { get; init; } = 255;
/// <summary>Part E of the OBIS ID (from the form A-B:C.D.E.F).</summary>
public byte E { get; init; } = 255;
/// <summary>Part F of the OBIS ID (from the form A-B:C.D.E.F).</summary>
public byte F { get; init; } = 255;
/// <summary>
/// Initializes a new <see cref="OBISId"/> with the given parts.
/// </summary>
/// <param name="parts">The individual parts of an OBIS ID.</param>
/// <exception cref="InvalidOBISIdException">Thrown when too many parts are specified (>6).</exception>
public OBISId(params byte[] parts)
{
if (parts.Length > 6)
{
throw new InvalidOBISIdException("Too many parts");
}
for (var i = 0; i < parts.Length && i < 6; i++)
{
switch (i)
{
case 0: A = parts[i]; break;
case 1: B = parts[i]; break;
case 2: C = parts[i]; break;
case 3: D = parts[i]; break;
case 4: E = parts[i]; break;
case 5: F = parts[i]; break;
}
}
}
/// <summary>
/// Initializes a new <see cref="OBISId"/> from the given string representation of an OBIS ID.
/// </summary>
/// <param name="id">The OBIS ID in string representation (e.g. "1-2:3.4.5.6")</param>
/// <seealso cref="FromString(string)"/>
/// <exception cref="InvalidOBISIdException">
/// Thrown when <paramref name="id"/> is null or empty or any of the parts contain an invalid value.
/// </exception>
public OBISId(string id)
: this(string.IsNullOrEmpty(id) ? throw new InvalidOBISIdException("Null or empty OBIS ID") : [.. GetParts(id)]) { }
/// <summary>
/// Creates an <see cref="OBISId"/> from a string representation of an OBIS ID.
/// </summary>
/// <param name="id">The OBIS ID in string representation (e.g. "1-2:3.4.5.6")</param>
/// <seealso cref="OBISId(string)"/>
/// <exception cref="InvalidOBISIdException">
/// Thrown when <paramref name="id"/> is null or empty or any of the parts contain an invalid value.
/// </exception>
/// <returns>Returns an <see cref="OBISId"/> when the given string can be parsed as such.</returns>
public static OBISId FromString(string id) => new(id);
/// <summary>
/// Returns the string representation of an <see cref="OBISId"/>.
/// </summary>
/// <returns>The string representation of an <see cref="OBISId"/>.</returns>
public override string ToString()
{
var parts = new byte[] { A, B, C, D, E, F };
var i = 0;
var result = new StringBuilder();
while (i < parts.Length && parts[i] < 255)
{
switch (i)
{
case 0: break;
case 1: result.Append('-'); break;
case 2: result.Append(':'); break;
default: result.Append('.'); break;
}
result.Append(parts[i]);
i++;
}
return result.ToString();
}
/// <summary>
/// Creates an OBISId from a string
/// </summary>
/// <param name="id">The OBIS ID to create from.</param>
public static implicit operator OBISId(string id) => FromString(id);
/// <summary>
/// Splits a given string up into the byte-values of each of the parts.
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
/// <remarks>
/// This methods splits on a few given chars but doesn't care about their order. This means an OBIS ID of
/// "1-2:3.4.5.6" is considered just as valid as an OBIS ID of "1.2-3:4.5-6" or "1-2-3-4-5-6" or "1.2.3:4:5:6".
/// </remarks>
private static IEnumerable<byte> GetParts(string id)
{
// Split on defined separators, return Max+1 parts so we can throw when too many parts are given, convert
// each part to a 0..255 value.
foreach (var v in id.Split(_splitchars, 7))
{
yield return byte.TryParse(v, NumberStyles.None, CultureInfo.InvariantCulture, out var result)
? result
: throw new InvalidOBISIdException($"Invalid value '{v}' in string '{id}'");
}
}
}