108 changed files with 9 additions and 17045 deletions
File diff suppressed because it is too large
Load Diff
@ -1,158 +0,0 @@
@@ -1,158 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public class BacnetAsyncResult : IAsyncResult, IDisposable |
||||
{ |
||||
private BacnetClient _comm; |
||||
private readonly byte _waitInvokeId; |
||||
private Exception _error; |
||||
private readonly byte[] _transmitBuffer; |
||||
private readonly int _transmitLength; |
||||
private readonly bool _waitForTransmit; |
||||
private readonly int _transmitTimeout; |
||||
private ManualResetEvent _waitHandle; |
||||
private readonly BacnetAddress _address; |
||||
|
||||
public bool Segmented { get; private set; } |
||||
public byte[] Result { get; private set; } |
||||
public object AsyncState { get; set; } |
||||
public bool CompletedSynchronously { get; private set; } |
||||
public WaitHandle AsyncWaitHandle => _waitHandle; |
||||
public bool IsCompleted => _waitHandle.WaitOne(0); |
||||
public BacnetAddress Address => _address; |
||||
|
||||
public Exception Error |
||||
{ |
||||
get => _error; |
||||
set |
||||
{ |
||||
_error = value; |
||||
CompletedSynchronously = true; |
||||
_waitHandle.Set(); |
||||
} |
||||
} |
||||
|
||||
public BacnetAsyncResult(BacnetClient comm, BacnetAddress adr, byte invokeId, byte[] transmitBuffer, int transmitLength, bool waitForTransmit, int transmitTimeout) |
||||
{ |
||||
_transmitTimeout = transmitTimeout; |
||||
_address = adr; |
||||
_waitForTransmit = waitForTransmit; |
||||
_transmitBuffer = transmitBuffer; |
||||
_transmitLength = transmitLength; |
||||
_comm = comm; |
||||
_waitInvokeId = invokeId; |
||||
_comm.OnComplexAck += OnComplexAck; |
||||
_comm.OnError += OnError; |
||||
_comm.OnAbort += OnAbort; |
||||
_comm.OnReject += OnReject; |
||||
_comm.OnSimpleAck += OnSimpleAck; |
||||
_comm.OnSegment += OnSegment; |
||||
_waitHandle = new ManualResetEvent(false); |
||||
} |
||||
|
||||
public void Resend() |
||||
{ |
||||
try |
||||
{ |
||||
if (_comm.Transport.Send(_transmitBuffer, _comm.Transport.HeaderLength, _transmitLength, _address, _waitForTransmit, _transmitTimeout) < 0) |
||||
{ |
||||
Error = new IOException("Write Timeout"); |
||||
} |
||||
} |
||||
catch (Exception ex) |
||||
{ |
||||
Error = new Exception($"Write Exception: {ex.Message}"); |
||||
} |
||||
} |
||||
|
||||
private void OnSegment(BacnetClient sender, BacnetAddress adr, BacnetPduTypes type, BacnetConfirmedServices service, byte invokeId, BacnetMaxSegments maxSegments, BacnetMaxAdpu maxAdpu, byte sequenceNumber, byte[] buffer, int offset, int length) |
||||
{ |
||||
if (invokeId != _waitInvokeId || !adr.Equals(_address)) |
||||
return; |
||||
|
||||
Segmented = true; |
||||
_waitHandle.Set(); |
||||
} |
||||
|
||||
private void OnSimpleAck(BacnetClient sender, BacnetAddress adr, BacnetPduTypes type, BacnetConfirmedServices service, byte invokeId, byte[] data, int dataOffset, int dataLength) |
||||
{ |
||||
if (invokeId != _waitInvokeId || !adr.Equals(_address)) |
||||
return; |
||||
|
||||
_waitHandle.Set(); |
||||
} |
||||
|
||||
private void OnAbort(BacnetClient sender, BacnetAddress adr, BacnetPduTypes type, byte invokeId, BacnetAbortReason reason, byte[] buffer, int offset, int length) |
||||
{ |
||||
if (invokeId != _waitInvokeId || !adr.Equals(_address)) |
||||
return; |
||||
|
||||
Error = new Exception($"Abort from device, reason: {reason}"); |
||||
} |
||||
|
||||
private void OnReject(BacnetClient sender, BacnetAddress adr, BacnetPduTypes type, byte invokeId, BacnetRejectReason reason, byte[] buffer, int offset, int length) |
||||
{ |
||||
if (invokeId != _waitInvokeId || !adr.Equals(_address)) |
||||
return; |
||||
|
||||
Error = new Exception($"Reject from device, reason: {reason}"); |
||||
} |
||||
|
||||
private void OnError(BacnetClient sender, BacnetAddress adr, BacnetPduTypes type, BacnetConfirmedServices service, byte invokeId, BacnetErrorClasses errorClass, BacnetErrorCodes errorCode, byte[] buffer, int offset, int length) |
||||
{ |
||||
if (invokeId != _waitInvokeId || !adr.Equals(_address)) |
||||
return; |
||||
|
||||
Error = new Exception($"Error from device: {errorClass} - {errorCode}"); |
||||
} |
||||
|
||||
private void OnComplexAck(BacnetClient sender, BacnetAddress adr, BacnetPduTypes type, BacnetConfirmedServices service, byte invokeId, byte[] buffer, int offset, int length) |
||||
{ |
||||
if (invokeId != _waitInvokeId || !adr.Equals(_address)) |
||||
return; |
||||
|
||||
Segmented = false; |
||||
Result = new byte[length]; |
||||
|
||||
if (length > 0) |
||||
Array.Copy(buffer, offset, Result, 0, length); |
||||
|
||||
//notify waiter even if segmented |
||||
_waitHandle.Set(); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Will continue waiting until all segments are recieved |
||||
/// </summary> |
||||
public bool WaitForDone(int timeout) |
||||
{ |
||||
while (true) |
||||
{ |
||||
if (!AsyncWaitHandle.WaitOne(timeout)) |
||||
return false; |
||||
if (Segmented) |
||||
_waitHandle.Reset(); |
||||
else |
||||
return true; |
||||
} |
||||
} |
||||
|
||||
public void Dispose() |
||||
{ |
||||
if (_comm != null) |
||||
{ |
||||
_comm.OnComplexAck -= OnComplexAck; |
||||
_comm.OnError -= OnError; |
||||
_comm.OnAbort -= OnAbort; |
||||
_comm.OnReject -= OnReject; |
||||
_comm.OnSimpleAck -= OnSimpleAck; |
||||
_comm.OnSegment -= OnSegment; |
||||
_comm = null; |
||||
} |
||||
|
||||
if (_waitHandle != null) |
||||
{ |
||||
_waitHandle.Dispose(); |
||||
_waitHandle = null; |
||||
} |
||||
} |
||||
} |
@ -1,69 +0,0 @@
@@ -1,69 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public struct BACnetCalendarEntry : ASN1.IEncode, ASN1.IDecode |
||||
{ |
||||
public List<object> Entries; // BacnetDate or BacnetDateRange or BacnetweekNDay |
||||
|
||||
public void Encode(EncodeBuffer buffer) |
||||
{ |
||||
if (Entries == null) |
||||
return; |
||||
|
||||
foreach (ASN1.IEncode entry in Entries) |
||||
{ |
||||
if (entry is BacnetDate) |
||||
{ |
||||
ASN1.encode_tag(buffer, 0, true, 4); |
||||
entry.Encode(buffer); |
||||
} |
||||
|
||||
if (entry is BacnetDateRange) |
||||
{ |
||||
ASN1.encode_opening_tag(buffer, 1); |
||||
entry.Encode(buffer); |
||||
ASN1.encode_closing_tag(buffer, 1); |
||||
} |
||||
|
||||
if (entry is BacnetweekNDay) |
||||
{ |
||||
ASN1.encode_tag(buffer, 2, true, 3); |
||||
entry.Encode(buffer); |
||||
} |
||||
} |
||||
} |
||||
|
||||
public int Decode(byte[] buffer, int offset, uint count) |
||||
{ |
||||
var len = 0; |
||||
|
||||
Entries = new List<object>(); |
||||
|
||||
while (true) |
||||
{ |
||||
len += ASN1.decode_tag_number(buffer, offset + len, out byte tagNumber); |
||||
|
||||
switch (tagNumber) |
||||
{ |
||||
case 0: |
||||
var bdt = new BacnetDate(); |
||||
len += bdt.Decode(buffer, offset + len, count); |
||||
Entries.Add(bdt); |
||||
break; |
||||
case 1: |
||||
var bdr = new BacnetDateRange(); |
||||
len += bdr.Decode(buffer, offset + len, count); |
||||
Entries.Add(bdr); |
||||
len++; // closing tag |
||||
break; |
||||
case 2: |
||||
var bwd = new BacnetweekNDay(); |
||||
len += bwd.Decode(buffer, offset + len, count); |
||||
Entries.Add(bwd); |
||||
break; |
||||
default: |
||||
return len - 1; // closing Tag |
||||
} |
||||
} |
||||
|
||||
} |
||||
} |
@ -1,84 +0,0 @@
@@ -1,84 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
/// <summary> |
||||
/// Reason the transaction with the indicated invoke ID is being aborted. |
||||
/// </summary> |
||||
/// <remarks> |
||||
/// Enumerated values 0-63 are reserved for definition by ASHRAE. |
||||
/// Enumerated values 64-255 may be used by others. |
||||
/// </remarks> |
||||
public enum BacnetAbortReason |
||||
{ |
||||
/// <summary> |
||||
/// This abort reason is returned for a reason other than any of those previously enumerated. |
||||
/// </summary> |
||||
OTHER = 0, |
||||
|
||||
/// <summary> |
||||
/// A buffer capacity has been exceeded. |
||||
/// </summary> |
||||
BUFFER_OVERFLOW = 1, |
||||
|
||||
/// <summary> |
||||
/// Generated in response to an APDU that is not expected in the present |
||||
/// state of the Transaction State Machine. |
||||
/// </summary> |
||||
INVALID_APDU_IN_THIS_STATE = 2, |
||||
|
||||
/// <summary> |
||||
/// The transaction shall be aborted to permit higher priority processing. |
||||
/// </summary> |
||||
PREEMPTED_BY_HIGHER_PRIORITY_TASK = 3, |
||||
|
||||
/// <summary> |
||||
/// Generated in response to an APDU that has its segmentation bit set to TRUE |
||||
/// when the receiving device does not support segmentation. It is also generated |
||||
/// when a BACnet-ComplexACKPDU is large enough to require segmentation but it |
||||
/// cannot be transmitted because either the transmitting device or the receiving |
||||
/// device does not support segmentation. |
||||
/// </summary> |
||||
SEGMENTATION_NOT_SUPPORTED = 4, |
||||
|
||||
/// <summary> |
||||
/// The Transaction is aborted due to receipt of a security error. |
||||
/// </summary> |
||||
SECURITY_ERROR = 5, |
||||
|
||||
/// <summary> |
||||
/// The transaction is aborted due to receipt of a PDU secured differently |
||||
/// than the original PDU of the transaction. |
||||
/// </summary> |
||||
INSUFFICIENT_SECURITY = 6, |
||||
|
||||
/// <summary> |
||||
/// A device receives a request that is segmented, or receives any segment of |
||||
/// a segmented request, where the Proposed Window Size field of the PDU header |
||||
/// is either zero or greater than 127. |
||||
/// </summary> |
||||
WINDOW_SIZE_OUT_OF_RANGE = 7, |
||||
|
||||
/// <summary> |
||||
/// A device receives a confirmed request but its application layer has |
||||
/// not responded within the published APDU Timeout period. |
||||
/// </summary> |
||||
APPLICATION_EXCEEDED_REPLY_TIME = 8, |
||||
|
||||
/// <summary> |
||||
/// A device receives a request but cannot start processing because it has run |
||||
/// out of some internal resource. |
||||
/// </summary> |
||||
OUT_OF_RESOURCES = 9, |
||||
|
||||
/// <summary> |
||||
/// A transaction state machine timer exceeded the timeout applicable for the |
||||
/// current state, causing the transaction machine to abort the transaction. |
||||
/// </summary> |
||||
TSM_TIMEOUT = 10, |
||||
|
||||
/// <summary> |
||||
/// An APDU was received from the local application program whose overall |
||||
/// size exceeds the maximum transmittable length or exceeds the maximum |
||||
/// number of segments accepted by the server. |
||||
/// </summary> |
||||
APDU_TOO_LONG = 11 |
||||
} |
@ -1,196 +0,0 @@
@@ -1,196 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public class BacnetAddress : ASN1.IEncode |
||||
{ |
||||
public ushort net; |
||||
public byte[] adr; |
||||
public byte[] VMac = new byte[3]; // for IP V6, could be integrated also as 3 additional bytes in adr |
||||
public BacnetAddressTypes type; |
||||
|
||||
// Modif FC |
||||
public BacnetAddress RoutedSource = null; |
||||
|
||||
// DAL |
||||
public BacnetAddress RoutedDestination = null; |
||||
|
||||
public BacnetAddress(BacnetAddressTypes addressType, ushort network = 0, byte[] address = null) |
||||
{ |
||||
type = addressType; |
||||
net = network; |
||||
adr = address; |
||||
} |
||||
|
||||
public BacnetAddress(BacnetAddressTypes addressType, string address = null, ushort network = 0) |
||||
: this(addressType, network) |
||||
{ |
||||
if (address == null) |
||||
return; |
||||
|
||||
switch (type) |
||||
{ |
||||
case BacnetAddressTypes.IP: |
||||
adr = new byte[6]; |
||||
var addressParts = address.Split(':'); |
||||
var addressBytes = IPAddress.Parse(addressParts[0]).GetAddressBytes(); |
||||
Array.Copy(addressBytes, adr, addressBytes.Length); |
||||
|
||||
var portBytes = BitConverter.GetBytes(addressParts.Length > 1 |
||||
? ushort.Parse(addressParts[1]) |
||||
: (ushort)0xBAC0); |
||||
|
||||
if (BitConverter.IsLittleEndian) |
||||
portBytes = portBytes.Reverse().ToArray(); |
||||
|
||||
Array.Copy(portBytes, 0, adr, addressBytes.Length, portBytes.Length); |
||||
break; |
||||
|
||||
case BacnetAddressTypes.Ethernet: |
||||
adr = PhysicalAddress.Parse(address).GetAddressBytes(); |
||||
break; |
||||
|
||||
default: |
||||
throw new NotSupportedException("String format is not supported for address type " + type); |
||||
} |
||||
} |
||||
|
||||
public override int GetHashCode() |
||||
{ |
||||
// DAL this was originally broken... |
||||
var str = Convert.ToBase64String(adr); |
||||
return str.GetHashCode(); |
||||
} |
||||
|
||||
public override string ToString() |
||||
{ |
||||
return ToString(type); |
||||
} |
||||
|
||||
public string ToString(BacnetAddressTypes addressType) |
||||
{ |
||||
while (true) |
||||
{ |
||||
switch (addressType) |
||||
{ |
||||
case BacnetAddressTypes.IP: |
||||
return adr != null && adr.Length >= 6 |
||||
? $"{adr[0]}.{adr[1]}.{adr[2]}.{adr[3]}:{(adr[4] << 8) | adr[5]}" |
||||
: "0.0.0.0"; |
||||
|
||||
case BacnetAddressTypes.MSTP: |
||||
return adr != null && adr.Length >= 1 |
||||
? $"{adr[0]}" |
||||
: "-1"; |
||||
|
||||
case BacnetAddressTypes.PTP: |
||||
return "x"; |
||||
|
||||
case BacnetAddressTypes.Ethernet: |
||||
return $"{new PhysicalAddress(adr)}"; |
||||
|
||||
case BacnetAddressTypes.IPV6: |
||||
return adr != null && adr.Length == 18 |
||||
? $"{new IPAddress(adr.Take(16).ToArray())}:{(adr[16] << 8) | adr[17]}" |
||||
: "[::]"; |
||||
|
||||
default: // Routed @ are always like this, NPDU do not contains the MAC type, only the lenght |
||||
if (adr == null || adr.Length == 0) |
||||
return "?"; |
||||
|
||||
switch (adr.Length) |
||||
{ |
||||
case 6: // certainly IP, but not sure (Newron System send it for internal usage with 4*0 bytes) |
||||
addressType = BacnetAddressTypes.IP; |
||||
continue; |
||||
|
||||
case 18: // Not sure it could appears, since NPDU may contains Vmac ? |
||||
addressType = BacnetAddressTypes.IPV6; |
||||
continue; |
||||
|
||||
case 3: |
||||
return $"IPv6 VMac : {adr[0] << 16 | (adr[1] << 8) | adr[2]}"; |
||||
|
||||
default: |
||||
return string.Join(" ", adr); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
public string ToString(bool sourceOnly) |
||||
{ |
||||
if (RoutedSource == null) |
||||
return ToString(); |
||||
|
||||
return sourceOnly |
||||
? RoutedSource.ToString() |
||||
: $"{RoutedSource} via {ToString()}"; |
||||
} |
||||
|
||||
public bool HasAddress(IPAddress ipAddress) |
||||
{ |
||||
if (type != BacnetAddressTypes.IP || adr == null || ipAddress == null) |
||||
return false; |
||||
|
||||
return adr.Take(4).SequenceEqual(ipAddress.GetAddressBytes()); |
||||
} |
||||
|
||||
public override bool Equals(object obj) |
||||
{ |
||||
if (obj is not BacnetAddress) return false; |
||||
var d = (BacnetAddress)obj; |
||||
if (adr == null && d.adr == null) return true; |
||||
if (adr == null || d.adr == null) return false; |
||||
if (adr.Length != d.adr.Length) return false; |
||||
if (adr.Where((t, i) => t != d.adr[i]).Any()) |
||||
return false; |
||||
|
||||
// Modif FC |
||||
if (RoutedSource == null && d.RoutedSource != null) |
||||
return false; |
||||
|
||||
// DAL |
||||
if (RoutedDestination == null && d.RoutedDestination != null) |
||||
return false; |
||||
|
||||
if (d.RoutedSource == null && RoutedSource == null && |
||||
d.RoutedDestination == null && RoutedDestination == null) |
||||
return true; |
||||
|
||||
bool rv = RoutedSource?.Equals(d.RoutedSource) ?? false; |
||||
rv |= RoutedDestination?.Equals(d.RoutedDestination) ?? false; |
||||
return rv; |
||||
} |
||||
|
||||
// checked if device is routed by curent equipement |
||||
public bool IsMyRouter(BacnetAddress device) |
||||
{ |
||||
if (device.RoutedSource == null || RoutedSource != null) |
||||
return false; |
||||
|
||||
if (adr.Length != device.adr.Length) |
||||
return false; |
||||
|
||||
return !adr.Where((t, i) => t != device.adr[i]).Any(); |
||||
} |
||||
|
||||
public void Encode(EncodeBuffer buffer) |
||||
{ |
||||
ASN1.encode_opening_tag(buffer, 1); |
||||
ASN1.encode_application_unsigned(buffer, net); |
||||
ASN1.encode_application_octet_string(buffer, adr, 0, adr.Length); |
||||
ASN1.encode_closing_tag(buffer, 1); |
||||
} |
||||
|
||||
public string FullHashString() |
||||
{ |
||||
var hash = $"{(uint)type}.{net}.{string.Concat(adr.Select(a => a.ToString("X2")))}"; |
||||
|
||||
if (RoutedSource != null) |
||||
hash += $":{RoutedSource.FullHashString()}"; |
||||
|
||||
if (RoutedDestination != null) |
||||
hash += $":{RoutedDestination.FullHashString()}"; |
||||
|
||||
return hash; |
||||
} |
||||
} |
@ -1,13 +0,0 @@
@@ -1,13 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public enum BacnetAddressTypes |
||||
{ |
||||
None, |
||||
IP, |
||||
MSTP, |
||||
Ethernet, |
||||
ArcNet, |
||||
LonTalk, |
||||
PTP, |
||||
IPV6 |
||||
} |
@ -1,65 +0,0 @@
@@ -1,65 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public enum BacnetApplicationTags |
||||
{ |
||||
BACNET_APPLICATION_TAG_NULL = 0, |
||||
BACNET_APPLICATION_TAG_BOOLEAN = 1, |
||||
BACNET_APPLICATION_TAG_UNSIGNED_INT = 2, |
||||
BACNET_APPLICATION_TAG_SIGNED_INT = 3, |
||||
BACNET_APPLICATION_TAG_REAL = 4, |
||||
BACNET_APPLICATION_TAG_DOUBLE = 5, |
||||
BACNET_APPLICATION_TAG_OCTET_STRING = 6, |
||||
BACNET_APPLICATION_TAG_CHARACTER_STRING = 7, |
||||
BACNET_APPLICATION_TAG_BIT_STRING = 8, |
||||
BACNET_APPLICATION_TAG_ENUMERATED = 9, |
||||
BACNET_APPLICATION_TAG_DATE = 10, |
||||
BACNET_APPLICATION_TAG_TIME = 11, |
||||
BACNET_APPLICATION_TAG_OBJECT_ID = 12, |
||||
BACNET_APPLICATION_TAG_RESERVE1 = 13, |
||||
BACNET_APPLICATION_TAG_RESERVE2 = 14, |
||||
BACNET_APPLICATION_TAG_RESERVE3 = 15, |
||||
MAX_BACNET_APPLICATION_TAG = 16, |
||||
|
||||
/* Extra stuff - complex tagged data - not specifically enumerated */ |
||||
|
||||
/* Means : "nothing", an empty list, not even a null character */ |
||||
BACNET_APPLICATION_TAG_EMPTYLIST, |
||||
/* BACnetWeeknday */ |
||||
BACNET_APPLICATION_TAG_WEEKNDAY, |
||||
/* BACnetDateRange */ |
||||
BACNET_APPLICATION_TAG_DATERANGE, |
||||
/* BACnetDateTime */ |
||||
BACNET_APPLICATION_TAG_DATETIME, |
||||
/* BACnetTimeStamp */ |
||||
BACNET_APPLICATION_TAG_TIMESTAMP, |
||||
/* Error Class, Error Code */ |
||||
BACNET_APPLICATION_TAG_ERROR, |
||||
/* BACnetDeviceObjectPropertyReference */ |
||||
BACNET_APPLICATION_TAG_DEVICE_OBJECT_PROPERTY_REFERENCE, |
||||
/* BACnetDeviceObjectReference */ |
||||
BACNET_APPLICATION_TAG_DEVICE_OBJECT_REFERENCE, |
||||
/* BACnetObjectPropertyReference */ |
||||
BACNET_APPLICATION_TAG_OBJECT_PROPERTY_REFERENCE, |
||||
/* BACnetDestination (Recipient_List) */ |
||||
BACNET_APPLICATION_TAG_DESTINATION, |
||||
/* BACnetRecipient */ |
||||
BACNET_APPLICATION_TAG_RECIPIENT, |
||||
/* BACnetCOVSubscription */ |
||||
BACNET_APPLICATION_TAG_COV_SUBSCRIPTION, |
||||
/* BACnetCalendarEntry */ |
||||
BACNET_APPLICATION_TAG_CALENDAR_ENTRY, |
||||
/* BACnetWeeklySchedule */ |
||||
BACNET_APPLICATION_TAG_WEEKLY_SCHEDULE, |
||||
/* BACnetSpecialEvent */ |
||||
BACNET_APPLICATION_TAG_SPECIAL_EVENT, |
||||
/* BACnetReadAccessSpecification */ |
||||
BACNET_APPLICATION_TAG_READ_ACCESS_SPECIFICATION, |
||||
/* BACnetReadAccessResult */ |
||||
BACNET_APPLICATION_TAG_READ_ACCESS_RESULT, |
||||
/* BACnetLightingCommand */ |
||||
BACNET_APPLICATION_TAG_LIGHTING_COMMAND, |
||||
BACNET_APPLICATION_TAG_CONTEXT_SPECIFIC_DECODED, |
||||
BACNET_APPLICATION_TAG_CONTEXT_SPECIFIC_ENCODED, |
||||
/* BACnetLogRecord */ |
||||
BACNET_APPLICATION_TAG_LOG_RECORD |
||||
} |
@ -1,10 +0,0 @@
@@ -1,10 +0,0 @@
|
||||
namespace System.IO.BACnet.Base; |
||||
|
||||
public enum BacnetBinaryPv : byte |
||||
{ |
||||
MIN_BINARY_PV = 0, /* for validating incoming values */ |
||||
BINARY_INACTIVE = 0, |
||||
BINARY_ACTIVE = 1, |
||||
MAX_BINARY_PV = 1, /* for validating incoming values */ |
||||
BINARY_NULL = 255 /* our homemade way of storing this info */ |
||||
} |
@ -1,91 +0,0 @@
@@ -1,91 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public struct BacnetBitString |
||||
{ |
||||
public byte bits_used; |
||||
public byte[] value; |
||||
|
||||
public byte Length => bits_used; |
||||
public bool this[byte bitNumber] => GetBit(bitNumber); |
||||
|
||||
public override string ToString() |
||||
{ |
||||
var ret = ""; |
||||
for (var i = 0; i < bits_used; i++) |
||||
{ |
||||
ret += ((value[i / 8] & (1 << (i % 8))) > 0 ? "1" : "0"); |
||||
} |
||||
return ret; |
||||
} |
||||
|
||||
public void SetBit(byte bitNumber, bool v) |
||||
{ |
||||
var byteNumber = (byte)(bitNumber / 8); |
||||
byte bitMask = 1; |
||||
|
||||
if (value == null) |
||||
value = new byte[ASN1.MAX_BITSTRING_BYTES]; |
||||
|
||||
if (byteNumber < ASN1.MAX_BITSTRING_BYTES) |
||||
{ |
||||
/* set max bits used */ |
||||
if (bits_used < bitNumber + 1) |
||||
bits_used = (byte)(bitNumber + 1); |
||||
bitMask = (byte)(bitMask << (bitNumber - byteNumber * 8)); |
||||
if (v) |
||||
value[byteNumber] |= bitMask; |
||||
else |
||||
value[byteNumber] &= (byte)~bitMask; |
||||
} |
||||
} |
||||
|
||||
public bool GetBit(byte bitNumber) |
||||
{ |
||||
var byteNumber = (byte)(bitNumber / 8); |
||||
|
||||
if (byteNumber >= ASN1.MAX_BITSTRING_BYTES || bitNumber >= bits_used) |
||||
throw new ArgumentOutOfRangeException(nameof(bitNumber)); |
||||
|
||||
if (value == null) |
||||
return false; |
||||
|
||||
var bitMask = (byte)(1 << (bitNumber - byteNumber * 8)); |
||||
return (value[byteNumber] & bitMask) > 0; |
||||
} |
||||
|
||||
public static BacnetBitString Parse(string str) |
||||
{ |
||||
var ret = new BacnetBitString |
||||
{ |
||||
value = new byte[ASN1.MAX_BITSTRING_BYTES] |
||||
}; |
||||
|
||||
if (string.IsNullOrEmpty(str)) |
||||
return ret; |
||||
|
||||
ret.bits_used = (byte)str.Length; |
||||
for (var i = 0; i < ret.bits_used; i++) |
||||
{ |
||||
var isSet = str[i] == '1'; |
||||
if (isSet) ret.value[i / 8] |= (byte)(1 << (i % 8)); |
||||
} |
||||
|
||||
return ret; |
||||
} |
||||
|
||||
public uint ConvertToInt() |
||||
{ |
||||
return value != null |
||||
? BitConverter.ToUInt32(value, 0) |
||||
: 0; |
||||
} |
||||
|
||||
public static BacnetBitString ConvertFromInt(uint value) |
||||
{ |
||||
return new BacnetBitString |
||||
{ |
||||
value = BitConverter.GetBytes(value), |
||||
bits_used = (byte)Math.Ceiling(Math.Log(value, 2)) |
||||
}; |
||||
} |
||||
}; |
@ -1,18 +0,0 @@
@@ -1,18 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public enum BacnetBvlcFunctions : byte |
||||
{ |
||||
BVLC_RESULT = 0, |
||||
BVLC_WRITE_BROADCAST_DISTRIBUTION_TABLE = 1, |
||||
BVLC_READ_BROADCAST_DIST_TABLE = 2, |
||||
BVLC_READ_BROADCAST_DIST_TABLE_ACK = 3, |
||||
BVLC_FORWARDED_NPDU = 4, |
||||
BVLC_REGISTER_FOREIGN_DEVICE = 5, |
||||
BVLC_READ_FOREIGN_DEVICE_TABLE = 6, |
||||
BVLC_READ_FOREIGN_DEVICE_TABLE_ACK = 7, |
||||
BVLC_DELETE_FOREIGN_DEVICE_TABLE_ENTRY = 8, |
||||
BVLC_DISTRIBUTE_BROADCAST_TO_NETWORK = 9, |
||||
BVLC_ORIGINAL_UNICAST_NPDU = 10, |
||||
BVLC_ORIGINAL_BROADCAST_NPDU = 11, |
||||
MAX_BVLC_FUNCTION = 12 |
||||
} |
@ -1,12 +0,0 @@
@@ -1,12 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public enum BacnetBvlcResults : ushort |
||||
{ |
||||
BVLC_RESULT_SUCCESSFUL_COMPLETION = 0x0000, |
||||
BVLC_RESULT_WRITE_BROADCAST_DISTRIBUTION_TABLE_NAK = 0x0010, |
||||
BVLC_RESULT_READ_BROADCAST_DISTRIBUTION_TABLE_NAK = 0x0020, |
||||
BVLC_RESULT_REGISTER_FOREIGN_DEVICE_NAK = 0X0030, |
||||
BVLC_RESULT_READ_FOREIGN_DEVICE_TABLE_NAK = 0x0040, |
||||
BVLC_RESULT_DELETE_FOREIGN_DEVICE_TABLE_ENTRY_NAK = 0x0050, |
||||
BVLC_RESULT_DISTRIBUTE_BROADCAST_TO_NETWORK_NAK = 0x0060 |
||||
} |
@ -1,18 +0,0 @@
@@ -1,18 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public enum BacnetBvlcV6Functions : byte |
||||
{ |
||||
BVLC_RESULT = 0, |
||||
BVLC_ORIGINAL_UNICAST_NPDU = 1, |
||||
BVLC_ORIGINAL_BROADCAST_NPDU = 2, |
||||
BVLC_ADDRESS_RESOLUTION = 3, |
||||
BVLC_FORWARDED_ADDRESS_RESOLUTION = 4, |
||||
BVLC_ADDRESS_RESOLUTION_ACK = 5, |
||||
BVLC_VIRTUAL_ADDRESS_RESOLUTION = 6, |
||||
BVLC_VIRTUAL_ADDRESS_RESOLUTION_ACK = 7, |
||||
BVLC_FORWARDED_NPDU = 8, |
||||
BVLC_REGISTER_FOREIGN_DEVICE = 9, |
||||
BVLC_DELETE_FOREIGN_DEVICE_TABLE_ENTRY = 0xA, |
||||
BVLC_SECURE_BVLC = 0xB, |
||||
BVLC_DISTRIBUTE_BROADCAST_TO_NETWORK = 0xC |
||||
} |
@ -1,10 +0,0 @@
@@ -1,10 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public enum BacnetBvlcV6Results : ushort |
||||
{ |
||||
SUCCESSFUL_COMPLETION = 0x0000, |
||||
ADDRESS_RESOLUTION_NAK = 0x0030, |
||||
VIRTUAL_ADDRESS_RESOLUTION_NAK = 0x0060, |
||||
REGISTER_FOREIGN_DEVICE_NAK = 0X0090, |
||||
DISTRIBUTE_BROADCAST_TO_NETWORK_NAK = 0x00B0 |
||||
} |
@ -1,15 +0,0 @@
@@ -1,15 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public struct BacnetCOVSubscription |
||||
{ |
||||
/* BACnetRecipientProcess */ |
||||
public BacnetAddress Recipient; |
||||
public uint subscriptionProcessIdentifier; |
||||
/* BACnetObjectPropertyReference */ |
||||
public BacnetObjectId monitoredObjectIdentifier; |
||||
public BacnetPropertyReference monitoredProperty; |
||||
/* BACnetCOVSubscription */ |
||||
public bool IssueConfirmedNotifications; |
||||
public uint TimeRemaining; |
||||
public float COVIncrement; |
||||
} |
@ -1,13 +0,0 @@
@@ -1,13 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public enum BacnetCharacterStringEncodings |
||||
{ |
||||
CHARACTER_ANSI_X34 = 0, /* deprecated : Addendum 135-2008k */ |
||||
CHARACTER_UTF8 = 0, |
||||
CHARACTER_MS_DBCS = 1, |
||||
CHARACTER_JISC_6226 = 2, /* deprecated : Addendum 135-2008k */ |
||||
CHARACTER_JISX_0208 = 2, |
||||
CHARACTER_UCS4 = 3, |
||||
CHARACTER_UCS2 = 4, |
||||
CHARACTER_ISO8859 = 5 |
||||
} |
@ -1,47 +0,0 @@
@@ -1,47 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public enum BacnetConfirmedServices : byte |
||||
{ |
||||
/* Alarm and Event Services */ |
||||
SERVICE_CONFIRMED_ACKNOWLEDGE_ALARM = 0, |
||||
SERVICE_CONFIRMED_COV_NOTIFICATION = 1, |
||||
SERVICE_CONFIRMED_EVENT_NOTIFICATION = 2, |
||||
SERVICE_CONFIRMED_GET_ALARM_SUMMARY = 3, |
||||
SERVICE_CONFIRMED_GET_ENROLLMENT_SUMMARY = 4, |
||||
SERVICE_CONFIRMED_GET_EVENT_INFORMATION = 29, |
||||
SERVICE_CONFIRMED_SUBSCRIBE_COV = 5, |
||||
SERVICE_CONFIRMED_SUBSCRIBE_COV_PROPERTY = 28, |
||||
SERVICE_CONFIRMED_LIFE_SAFETY_OPERATION = 27, |
||||
/* File Access Services */ |
||||
SERVICE_CONFIRMED_ATOMIC_READ_FILE = 6, |
||||
SERVICE_CONFIRMED_ATOMIC_WRITE_FILE = 7, |
||||
/* Object Access Services */ |
||||
SERVICE_CONFIRMED_ADD_LIST_ELEMENT = 8, |
||||
SERVICE_CONFIRMED_REMOVE_LIST_ELEMENT = 9, |
||||
SERVICE_CONFIRMED_CREATE_OBJECT = 10, |
||||
SERVICE_CONFIRMED_DELETE_OBJECT = 11, |
||||
SERVICE_CONFIRMED_READ_PROPERTY = 12, |
||||
SERVICE_CONFIRMED_READ_PROP_CONDITIONAL = 13, |
||||
SERVICE_CONFIRMED_READ_PROP_MULTIPLE = 14, |
||||
SERVICE_CONFIRMED_READ_RANGE = 26, |
||||
SERVICE_CONFIRMED_WRITE_PROPERTY = 15, |
||||
SERVICE_CONFIRMED_WRITE_PROP_MULTIPLE = 16, |
||||
/* Remote Device Management Services */ |
||||
SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL = 17, |
||||
SERVICE_CONFIRMED_PRIVATE_TRANSFER = 18, |
||||
SERVICE_CONFIRMED_TEXT_MESSAGE = 19, |
||||
SERVICE_CONFIRMED_REINITIALIZE_DEVICE = 20, |
||||
/* Virtual Terminal Services */ |
||||
SERVICE_CONFIRMED_VT_OPEN = 21, |
||||
SERVICE_CONFIRMED_VT_CLOSE = 22, |
||||
SERVICE_CONFIRMED_VT_DATA = 23, |
||||
/* Security Services */ |
||||
SERVICE_CONFIRMED_AUTHENTICATE = 24, |
||||
SERVICE_CONFIRMED_REQUEST_KEY = 25, |
||||
/* Services added after 1995 */ |
||||
/* readRange (26) see Object Access Services */ |
||||
/* lifeSafetyOperation (27) see Alarm and Event Services */ |
||||
/* subscribeCOVProperty (28) see Alarm and Event Services */ |
||||
/* getEventInformation (29) see Alarm and Event Services */ |
||||
MAX_BACNET_CONFIRMED_SERVICE = 30 |
||||
} |
@ -1,125 +0,0 @@
@@ -1,125 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public struct BacnetDate : ASN1.IEncode, ASN1.IDecode |
||||
{ |
||||
public byte year; /* 255 any */ |
||||
public byte month; /* 1=Jan; 255 any, 13 Odd, 14 Even */ |
||||
public byte day; /* 1..31; 32 last day of the month; 255 any */ |
||||
public byte wday; /* 1=Monday-7=Sunday, 255 any */ |
||||
|
||||
public BacnetDate(byte year, byte month, byte day, byte wday = 255) |
||||
{ |
||||
this.year = year; |
||||
this.month = month; |
||||
this.day = day; |
||||
this.wday = wday; |
||||
} |
||||
|
||||
public void Encode(EncodeBuffer buffer) |
||||
{ |
||||
buffer.Add(year); |
||||
buffer.Add(month); |
||||
buffer.Add(day); |
||||
buffer.Add(wday); |
||||
} |
||||
|
||||
public int Decode(byte[] buffer, int offset, uint count) |
||||
{ |
||||
year = buffer[offset]; |
||||
month = buffer[offset + 1]; |
||||
day = buffer[offset + 2]; |
||||
wday = buffer[offset + 3]; |
||||
return 4; |
||||
} |
||||
|
||||
public bool IsPeriodic => year == 255 || month > 12 || day == 255; |
||||
|
||||
public bool IsAFittingDate(DateTime date) |
||||
{ |
||||
if (date.Year != year + 1900 && year != 255) |
||||
return false; |
||||
|
||||
if (date.Month != month && month != 255 && month != 13 && month != 14) |
||||
return false; |
||||
if (month == 13 && (date.Month & 1) != 1) |
||||
return false; |
||||
if (month == 14 && (date.Month & 1) == 1) |
||||
return false; |
||||
|
||||
if (date.Day != day && day != 255) |
||||
return false; |
||||
// day 32 todo |
||||
|
||||
if (wday == 255) |
||||
return true; |
||||
|
||||
if (wday == 7 && date.DayOfWeek == 0) // Sunday 7 for Bacnet, 0 for .NET |
||||
return true; |
||||
|
||||
if (wday == (int)date.DayOfWeek) |
||||
return true; |
||||
|
||||
return false; |
||||
} |
||||
|
||||
public DateTime toDateTime() // Not every time possible, too much complex (any month, any year ...) |
||||
{ |
||||
try |
||||
{ |
||||
return IsPeriodic |
||||
? new DateTime(1, 1, 1) |
||||
: new DateTime(year + 1900, month, day); |
||||
} |
||||
catch |
||||
{ |
||||
return DateTime.Now; // or anything else why not ! |
||||
} |
||||
} |
||||
|
||||
private static string GetDayName(int day) |
||||
{ |
||||
if (day == 7) |
||||
day = 0; |
||||
|
||||
return CultureInfo.CurrentCulture.DateTimeFormat.DayNames[day]; |
||||
} |
||||
|
||||
public override string ToString() |
||||
{ |
||||
string ret; |
||||
|
||||
if (wday != 255) |
||||
ret = GetDayName(wday) + " "; |
||||
else |
||||
ret = ""; |
||||
|
||||
if (day != 255) |
||||
ret = ret + day + "/"; |
||||
else |
||||
ret += "**/"; |
||||
|
||||
switch (month) |
||||
{ |
||||
case 13: |
||||
ret += "odd/"; |
||||
break; |
||||
case 14: |
||||
ret += "even/"; |
||||
break; |
||||
case 255: |
||||
ret += "**/"; |
||||
break; |
||||
default: |
||||
ret = ret + month + "/"; |
||||
break; |
||||
} |
||||
|
||||
|
||||
if (year != 255) |
||||
ret += year + 1900; |
||||
else |
||||
ret += "****"; |
||||
|
||||
return ret; |
||||
} |
||||
} |
@ -1,53 +0,0 @@
@@ -1,53 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public struct BacnetDateRange : ASN1.IEncode, ASN1.IDecode |
||||
{ |
||||
public BacnetDate startDate; |
||||
public BacnetDate endDate; |
||||
|
||||
public BacnetDateRange(BacnetDate start, BacnetDate end) |
||||
{ |
||||
startDate = start; |
||||
endDate = end; |
||||
} |
||||
|
||||
public void Encode(EncodeBuffer buffer) |
||||
{ |
||||
ASN1.encode_tag(buffer, (byte)BacnetApplicationTags.BACNET_APPLICATION_TAG_DATE, false, 4); |
||||
startDate.Encode(buffer); |
||||
ASN1.encode_tag(buffer, (byte)BacnetApplicationTags.BACNET_APPLICATION_TAG_DATE, false, 4); |
||||
endDate.Encode(buffer); |
||||
} |
||||
|
||||
public int Decode(byte[] buffer, int offset, uint count) |
||||
{ |
||||
var len = 1; // opening tag |
||||
len += startDate.Decode(buffer, offset + len, count); |
||||
len++; |
||||
len += endDate.Decode(buffer, offset + len, count); |
||||
return len; |
||||
} |
||||
|
||||
public bool IsAFittingDate(DateTime date) |
||||
{ |
||||
date = new DateTime(date.Year, date.Month, date.Day); |
||||
return date >= startDate.toDateTime() && date <= endDate.toDateTime(); |
||||
} |
||||
|
||||
public override string ToString() |
||||
{ |
||||
string ret; |
||||
|
||||
if (startDate.day != 255) |
||||
ret = "From " + startDate; |
||||
else |
||||
ret = "From **/**/**"; |
||||
|
||||
if (endDate.day != 255) |
||||
ret = ret + " to " + endDate; |
||||
else |
||||
ret += " to **/**/**"; |
||||
|
||||
return ret; |
||||
} |
||||
}; |
@ -1,104 +0,0 @@
@@ -1,104 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public struct BacnetDeviceObjectPropertyReference : ASN1.IEncode |
||||
{ |
||||
public BacnetObjectId objectIdentifier; |
||||
public BacnetPropertyIds propertyIdentifier; |
||||
public uint arrayIndex; |
||||
public BacnetObjectId deviceIndentifier; |
||||
|
||||
public BacnetDeviceObjectPropertyReference(BacnetObjectId objectIdentifier, BacnetPropertyIds propertyIdentifier, BacnetObjectId? deviceIndentifier = null, uint arrayIndex = ASN1.BACNET_ARRAY_ALL) |
||||
{ |
||||
this.objectIdentifier = objectIdentifier; |
||||
this.propertyIdentifier = propertyIdentifier; |
||||
this.arrayIndex = arrayIndex; |
||||
this.deviceIndentifier = deviceIndentifier ?? new BacnetObjectId(BacnetObjectTypes.MAX_BACNET_OBJECT_TYPE, 0); |
||||
} |
||||
|
||||
public void Encode(EncodeBuffer buffer) |
||||
{ |
||||
ASN1.bacapp_encode_device_obj_property_ref(buffer, this); |
||||
} |
||||
|
||||
public BacnetObjectId ObjectId |
||||
{ |
||||
get => objectIdentifier; |
||||
set => objectIdentifier = value; |
||||
} |
||||
|
||||
public int ArrayIndex // shows -1 when it's ASN1.BACNET_ARRAY_ALL |
||||
{ |
||||
get => arrayIndex != ASN1.BACNET_ARRAY_ALL |
||||
? (int)arrayIndex |
||||
: -1; |
||||
set => arrayIndex = value < 0 |
||||
? ASN1.BACNET_ARRAY_ALL |
||||
: (uint)value; |
||||
} |
||||
|
||||
public BacnetObjectId? DeviceId // shows null when it's not OBJECT_DEVICE |
||||
{ |
||||
get |
||||
{ |
||||
return deviceIndentifier.type == BacnetObjectTypes.OBJECT_DEVICE |
||||
? (BacnetObjectId?)deviceIndentifier |
||||
: null; |
||||
} |
||||
set |
||||
{ |
||||
deviceIndentifier = value ?? new BacnetObjectId(); |
||||
} |
||||
} |
||||
|
||||
public BacnetPropertyIds PropertyId |
||||
{ |
||||
get => propertyIdentifier; |
||||
set => propertyIdentifier = value; |
||||
} |
||||
|
||||
public static object Parse(string value) |
||||
{ |
||||
var parts = value.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries); |
||||
|
||||
BacnetObjectId? deviceId = null; |
||||
BacnetObjectId objectId; |
||||
|
||||
switch (parts.Length) |
||||
{ |
||||
case 2: |
||||
objectId = BacnetObjectId.Parse(parts[0]); |
||||
break; |
||||
|
||||
case 3: |
||||
deviceId = BacnetObjectId.Parse(parts[0]); |
||||
objectId = BacnetObjectId.Parse(parts[1]); |
||||
break; |
||||
|
||||
default: |
||||
throw new ArgumentException("Invalid format", nameof(value)); |
||||
} |
||||
|
||||
if (!Enum.TryParse(parts.Last(), out BacnetPropertyIds propertyId)) |
||||
{ |
||||
if (!uint.TryParse(parts.Last(), out var vendorSpecificPropertyId)) |
||||
throw new ArgumentException("Invalid format of property id", nameof(value)); |
||||
|
||||
propertyId = (BacnetPropertyIds)vendorSpecificPropertyId; |
||||
} |
||||
|
||||
return new BacnetDeviceObjectPropertyReference |
||||
{ |
||||
DeviceId = deviceId, |
||||
ObjectId = objectId, |
||||
PropertyId = propertyId, |
||||
ArrayIndex = -1 |
||||
}; |
||||
} |
||||
|
||||
public override string ToString() |
||||
{ |
||||
return DeviceId != null |
||||
? $"{DeviceId}.{ObjectId}.{PropertyId}" |
||||
: $"{ObjectId}.{PropertyId}"; |
||||
} |
||||
} |
@ -1,11 +0,0 @@
@@ -1,11 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public enum BacnetDeviceStatus : byte |
||||
{ |
||||
OPERATIONAL = 0, |
||||
OPERATIONAL_READONLY = 1, |
||||
DOWNLOAD_REQUIRED = 2, |
||||
DOWNLOAD_IN_PROGRESS = 3, |
||||
NON_OPERATIONAL = 4, |
||||
BACKUP_IN_PROGRESS = 5 |
||||
} |
@ -1,22 +0,0 @@
@@ -1,22 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public struct BacnetError |
||||
{ |
||||
public BacnetErrorClasses error_class; |
||||
public BacnetErrorCodes error_code; |
||||
|
||||
public BacnetError(BacnetErrorClasses errorClass, BacnetErrorCodes errorCode) |
||||
{ |
||||
error_class = errorClass; |
||||
error_code = errorCode; |
||||
} |
||||
public BacnetError(uint errorClass, uint errorCode) |
||||
{ |
||||
error_class = (BacnetErrorClasses)errorClass; |
||||
error_code = (BacnetErrorCodes)errorCode; |
||||
} |
||||
public override string ToString() |
||||
{ |
||||
return $"{error_class}: {error_code}"; |
||||
} |
||||
} |
@ -1,21 +0,0 @@
@@ -1,21 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public enum BacnetErrorClasses |
||||
{ |
||||
ERROR_CLASS_DEVICE = 0, |
||||
ERROR_CLASS_OBJECT = 1, |
||||
ERROR_CLASS_PROPERTY = 2, |
||||
ERROR_CLASS_RESOURCES = 3, |
||||
ERROR_CLASS_SECURITY = 4, |
||||
ERROR_CLASS_SERVICES = 5, |
||||
ERROR_CLASS_VT = 6, |
||||
ERROR_CLASS_COMMUNICATION = 7, |
||||
/* Enumerated values 0-63 are reserved for definition by ASHRAE. */ |
||||
/* Enumerated values 64-65535 may be used by others subject to */ |
||||
/* the procedures and constraints described in Clause 23. */ |
||||
MAX_BACNET_ERROR_CLASS = 8, |
||||
/* do the MAX here instead of outside of enum so that |
||||
compilers will allocate adequate sized datatype for enum */ |
||||
ERROR_CLASS_PROPRIETARY_FIRST = 64, |
||||
ERROR_CLASS_PROPRIETARY_LAST = 65535 |
||||
} |
@ -1,246 +0,0 @@
@@ -1,246 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
// These are sorted in the order given in Clause 18. |
||||
// ERROR, REJECT AND ABORT CODES The Class and Code pairings |
||||
// are required to be used in accordance with Clause 18. |
||||
public enum BacnetErrorCodes |
||||
{ |
||||
/* valid for all classes */ |
||||
ERROR_CODE_OTHER = 0, |
||||
|
||||
/* Error Class - Device */ |
||||
ERROR_CODE_DEVICE_BUSY = 3, |
||||
ERROR_CODE_CONFIGURATION_IN_PROGRESS = 2, |
||||
ERROR_CODE_OPERATIONAL_PROBLEM = 25, |
||||
|
||||
/* Error Class - Object */ |
||||
ERROR_CODE_DYNAMIC_CREATION_NOT_SUPPORTED = 4, |
||||
ERROR_CODE_NO_OBJECTS_OF_SPECIFIED_TYPE = 17, |
||||
ERROR_CODE_OBJECT_DELETION_NOT_PERMITTED = 23, |
||||
ERROR_CODE_OBJECT_IDENTIFIER_ALREADY_EXISTS = 24, |
||||
ERROR_CODE_READ_ACCESS_DENIED = 27, |
||||
ERROR_CODE_UNKNOWN_OBJECT = 31, |
||||
ERROR_CODE_UNSUPPORTED_OBJECT_TYPE = 36, |
||||
|
||||
/* Error Class - Property */ |
||||
ERROR_CODE_CHARACTER_SET_NOT_SUPPORTED = 41, |
||||
ERROR_CODE_DATATYPE_NOT_SUPPORTED = 47, |
||||
ERROR_CODE_INCONSISTENT_SELECTION_CRITERION = 8, |
||||
ERROR_CODE_INVALID_ARRAY_INDEX = 42, |
||||
ERROR_CODE_INVALID_DATA_TYPE = 9, |
||||
ERROR_CODE_NOT_COV_PROPERTY = 44, |
||||
ERROR_CODE_OPTIONAL_FUNCTIONALITY_NOT_SUPPORTED = 45, |
||||
ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY = 50, |
||||
/* ERROR_CODE_READ_ACCESS_DENIED = 27, */ |
||||
ERROR_CODE_UNKNOWN_PROPERTY = 32, |
||||
ERROR_CODE_VALUE_OUT_OF_RANGE = 37, |
||||
ERROR_CODE_WRITE_ACCESS_DENIED = 40, |
||||
|
||||
/* Error Class - Resources */ |
||||
ERROR_CODE_NO_SPACE_FOR_OBJECT = 18, |
||||
ERROR_CODE_NO_SPACE_TO_ADD_LIST_ELEMENT = 19, |
||||
ERROR_CODE_NO_SPACE_TO_WRITE_PROPERTY = 20, |
||||
|
||||
/* Error Class - Security */ |
||||
ERROR_CODE_AUTHENTICATION_FAILED = 1, |
||||
/* ERROR_CODE_CHARACTER_SET_NOT_SUPPORTED = 41, */ |
||||
ERROR_CODE_INCOMPATIBLE_SECURITY_LEVELS = 6, |
||||
ERROR_CODE_INVALID_OPERATOR_NAME = 12, |
||||
ERROR_CODE_KEY_GENERATION_ERROR = 15, |
||||
ERROR_CODE_PASSWORD_FAILURE = 26, |
||||
ERROR_CODE_SECURITY_NOT_SUPPORTED = 28, |
||||
ERROR_CODE_TIMEOUT = 30, |
||||
|
||||
/* Error Class - Services */ |
||||
/* ERROR_CODE_CHARACTER_SET_NOT_SUPPORTED = 41, */ |
||||
ERROR_CODE_COV_SUBSCRIPTION_FAILED = 43, |
||||
ERROR_CODE_DUPLICATE_NAME = 48, |
||||
ERROR_CODE_DUPLICATE_OBJECT_ID = 49, |
||||
ERROR_CODE_FILE_ACCESS_DENIED = 5, |
||||
ERROR_CODE_INCONSISTENT_PARAMETERS = 7, |
||||
ERROR_CODE_INVALID_CONFIGURATION_DATA = 46, |
||||
ERROR_CODE_INVALID_FILE_ACCESS_METHOD = 10, |
||||
ERROR_CODE_INVALID_FILE_START_POSITION = 11, |
||||
ERROR_CODE_INVALID_PARAMETER_DATA_TYPE = 13, |
||||
ERROR_CODE_INVALID_TIME_STAMP = 14, |
||||
ERROR_CODE_MISSING_REQUIRED_PARAMETER = 16, |
||||
/* ERROR_CODE_OPTIONAL_FUNCTIONALITY_NOT_SUPPORTED = 45, */ |
||||
ERROR_CODE_PROPERTY_IS_NOT_A_LIST = 22, |
||||
ERROR_CODE_SERVICE_REQUEST_DENIED = 29, |
||||
|
||||
/* Error Class - VT */ |
||||
ERROR_CODE_UNKNOWN_VT_CLASS = 34, |
||||
ERROR_CODE_UNKNOWN_VT_SESSION = 35, |
||||
ERROR_CODE_NO_VT_SESSIONS_AVAILABLE = 21, |
||||
ERROR_CODE_VT_SESSION_ALREADY_CLOSED = 38, |
||||
ERROR_CODE_VT_SESSION_TERMINATION_FAILURE = 39, |
||||
|
||||
/* unused */ |
||||
ERROR_CODE_RESERVED1 = 33, |
||||
/* new error codes from new addenda */ |
||||
ERROR_CODE_ABORT_BUFFER_OVERFLOW = 51, |
||||
ERROR_CODE_ABORT_INVALID_APDU_IN_THIS_STATE = 52, |
||||
ERROR_CODE_ABORT_PREEMPTED_BY_HIGHER_PRIORITY_TASK = 53, |
||||
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED = 54, |
||||
ERROR_CODE_ABORT_PROPRIETARY = 55, |
||||
ERROR_CODE_ABORT_OTHER = 56, |
||||
ERROR_CODE_INVALID_TAG = 57, |
||||
ERROR_CODE_NETWORK_DOWN = 58, |
||||
ERROR_CODE_REJECT_BUFFER_OVERFLOW = 59, |
||||
ERROR_CODE_REJECT_INCONSISTENT_PARAMETERS = 60, |
||||
ERROR_CODE_REJECT_INVALID_PARAMETER_DATA_TYPE = 61, |
||||
ERROR_CODE_REJECT_INVALID_TAG = 62, |
||||
ERROR_CODE_REJECT_MISSING_REQUIRED_PARAMETER = 63, |
||||
ERROR_CODE_REJECT_PARAMETER_OUT_OF_RANGE = 64, |
||||
ERROR_CODE_REJECT_TOO_MANY_ARGUMENTS = 65, |
||||
ERROR_CODE_REJECT_UNDEFINED_ENUMERATION = 66, |
||||
ERROR_CODE_REJECT_UNRECOGNIZED_SERVICE = 67, |
||||
ERROR_CODE_REJECT_PROPRIETARY = 68, |
||||
ERROR_CODE_REJECT_OTHER = 69, |
||||
ERROR_CODE_UNKNOWN_DEVICE = 70, |
||||
ERROR_CODE_UNKNOWN_ROUTE = 71, |
||||
ERROR_CODE_VALUE_NOT_INITIALIZED = 72, |
||||
ERROR_CODE_INVALID_EVENT_STATE = 73, |
||||
ERROR_CODE_NO_ALARM_CONFIGURED = 74, |
||||
ERROR_CODE_LOG_BUFFER_FULL = 75, |
||||
ERROR_CODE_LOGGED_VALUE_PURGED = 76, |
||||
ERROR_CODE_NO_PROPERTY_SPECIFIED = 77, |
||||
ERROR_CODE_NOT_CONFIGURED_FOR_TRIGGERED_LOGGING = 78, |
||||
ERROR_CODE_UNKNOWN_SUBSCRIPTION = 79, |
||||
ERROR_CODE_PARAMETER_OUT_OF_RANGE = 80, |
||||
ERROR_CODE_LIST_ELEMENT_NOT_FOUND = 81, |
||||
ERROR_CODE_BUSY = 82, |
||||
ERROR_CODE_COMMUNICATION_DISABLED = 83, |
||||
ERROR_CODE_SUCCESS = 84, |
||||
ERROR_CODE_ACCESS_DENIED = 85, |
||||
ERROR_CODE_BAD_DESTINATION_ADDRESS = 86, |
||||
ERROR_CODE_BAD_DESTINATION_DEVICE_ID = 87, |
||||
ERROR_CODE_BAD_SIGNATURE = 88, |
||||
ERROR_CODE_BAD_SOURCE_ADDRESS = 89, |
||||
ERROR_CODE_BAD_TIMESTAMP = 90, |
||||
ERROR_CODE_CANNOT_USE_KEY = 91, |
||||
ERROR_CODE_CANNOT_VERIFY_MESSAGE_ID = 92, |
||||
ERROR_CODE_CORRECT_KEY_REVISION = 93, |
||||
ERROR_CODE_DESTINATION_DEVICE_ID_REQUIRED = 94, |
||||
ERROR_CODE_DUPLICATE_MESSAGE = 95, |
||||
ERROR_CODE_ENCRYPTION_NOT_CONFIGURED = 96, |
||||
ERROR_CODE_ENCRYPTION_REQUIRED = 97, |
||||
ERROR_CODE_INCORRECT_KEY = 98, |
||||
ERROR_CODE_INVALID_KEY_DATA = 99, |
||||
ERROR_CODE_KEY_UPDATE_IN_PROGRESS = 100, |
||||
ERROR_CODE_MALFORMED_MESSAGE = 101, |
||||
ERROR_CODE_NOT_KEY_SERVER = 102, |
||||
ERROR_CODE_SECURITY_NOT_CONFIGURED = 103, |
||||
ERROR_CODE_SOURCE_SECURITY_REQUIRED = 104, |
||||
ERROR_CODE_TOO_MANY_KEYS = 105, |
||||
ERROR_CODE_UNKNOWN_AUTHENTICATION_TYPE = 106, |
||||
ERROR_CODE_UNKNOWN_KEY = 107, |
||||
ERROR_CODE_UNKNOWN_KEY_REVISION = 108, |
||||
ERROR_CODE_UNKNOWN_SOURCE_MESSAGE = 109, |
||||
ERROR_CODE_NOT_ROUTER_TO_DNET = 110, |
||||
ERROR_CODE_ROUTER_BUSY = 111, |
||||
ERROR_CODE_UNKNOWN_NETWORK_MESSAGE = 112, |
||||
ERROR_CODE_MESSAGE_TOO_LONG = 113, |
||||
ERROR_CODE_SECURITY_ERROR = 114, |
||||
ERROR_CODE_ADDRESSING_ERROR = 115, |
||||
ERROR_CODE_WRITE_BDT_FAILED = 116, |
||||
ERROR_CODE_READ_BDT_FAILED = 117, |
||||
ERROR_CODE_REGISTER_FOREIGN_DEVICE_FAILED = 118, |
||||
ERROR_CODE_READ_FDT_FAILED = 119, |
||||
ERROR_CODE_DELETE_FDT_ENTRY_FAILED = 120, |
||||
ERROR_CODE_DISTRIBUTE_BROADCAST_FAILED = 121, |
||||
ERROR_CODE_UNKNOWN_FILE_SIZE = 122, |
||||
ERROR_CODE_ABORT_APDU_TOO_LONG = 123, |
||||
ERROR_CODE_ABORT_APPLICATION_EXCEEDED_REPLY_TIME = 124, |
||||
ERROR_CODE_ABORT_OUT_OF_RESOURCES = 125, |
||||
ERROR_CODE_ABORT_TSM_TIMEOUT = 126, |
||||
ERROR_CODE_ABORT_WINDOW_SIZE_OUT_OF_RANGE = 127, |
||||
ERROR_CODE_FILE_FULL = 128, |
||||
ERROR_CODE_INCONSISTENT_CONFIGURATION = 129, |
||||
ERROR_CODE_INCONSISTENT_OBJECT_TYPE = 130, |
||||
ERROR_CODE_INTERNAL_ERROR = 131, |
||||
ERROR_CODE_NOT_CONFIGURED = 132, |
||||
ERROR_CODE_OUT_OF_MEMORY = 133, |
||||
ERROR_CODE_VALUE_TOO_LONG = 134, |
||||
ERROR_CODE_ABORT_INSUFFICIENT_SECURITY = 135, |
||||
ERROR_CODE_ABORT_SECURITY_ERROR = 136, |
||||
ERROR_CODE_DUPLICATE_ENTRY = 137, |
||||
ERROR_CODE_INVALID_VALUE_IN_THIS_STATE = 138, |
||||
ERROR_CODE_INVALID_OPERATION_IN_THIS_STATE = 139, |
||||
ERROR_CODE_LIST_ITEM_NOT_NUMBERED = 140, |
||||
ERROR_CODE_LIST_ITEM_NOT_TIMESTAMPED = 141, |
||||
ERROR_CODE_INVALID_DATA_ENCODING = 142, |
||||
ERROR_CODE_BVLC_FUNCTION_UNKNOWN = 143, |
||||
ERROR_CODE_BVLC_PROPRIETARY_FUNCTION_UNKNOWN = 144, |
||||
ERROR_CODE_HEADER_ENCODING_ERROR = 145, |
||||
ERROR_CODE_HEADER_NOT_UNDERSTOOD = 146, |
||||
ERROR_CODE_MESSAGE_INCOMPLETE = 147, |
||||
ERROR_CODE_NOT_A_BACNET_SC_HUB = 148, |
||||
ERROR_CODE_PAYLOAD_EXPECTED = 149, |
||||
ERROR_CODE_UNEXPECTED_DATA = 150, |
||||
ERROR_CODE_NODE_DUPLICATE_VMAC = 151, |
||||
ERROR_CODE_HTTP_UNEXPECTED_RESPONSE_CODE = 152, |
||||
ERROR_CODE_HTTP_NO_UPGRADE = 153, |
||||
ERROR_CODE_HTTP_RESOURCE_NOT_LOCAL = 154, |
||||
ERROR_CODE_HTTP_PROXY_AUTHENTICATION_FAILED = 155, |
||||
ERROR_CODE_HTTP_RESPONSE_TIMEOUT = 156, |
||||
ERROR_CODE_HTTP_RESPONSE_SYNTAX_ERROR = 157, |
||||
ERROR_CODE_HTTP_RESPONSE_VALUE_ERROR = 158, |
||||
ERROR_CODE_HTTP_RESPONSE_MISSING_HEADER = 159, |
||||
ERROR_CODE_HTTP_WEBSOCKET_HEADER_ERROR = 160, |
||||
ERROR_CODE_HTTP_UPGRADE_REQUIRED = 161, |
||||
ERROR_CODE_HTTP_UPGRADE_ERROR = 162, |
||||
ERROR_CODE_HTTP_TEMPORARY_UNAVAILABLE = 163, |
||||
ERROR_CODE_HTTP_NOT_A_SERVER = 164, |
||||
ERROR_CODE_HTTP_ERROR = 165, |
||||
ERROR_CODE_WEBSOCKET_SCHEME_NOT_SUPPORTED = 166, |
||||
ERROR_CODE_WEBSOCKET_UNKNOWN_CONTROL_MESSAGE = 167, |
||||
ERROR_CODE_WEBSOCKET_CLOSE_ERROR = 168, |
||||
ERROR_CODE_WEBSOCKET_CLOSED_BY_PEER = 169, |
||||
ERROR_CODE_WEBSOCKET_ENDPOINT_LEAVES = 170, |
||||
ERROR_CODE_WEBSOCKET_PROTOCOL_ERROR = 171, |
||||
ERROR_CODE_WEBSOCKET_DATA_NOT_ACCEPTED = 172, |
||||
ERROR_CODE_WEBSOCKET_CLOSED_ABNORMALLY = 173, |
||||
ERROR_CODE_WEBSOCKET_DATA_INCONSISTENT = 174, |
||||
ERROR_CODE_WEBSOCKET_DATA_AGAINST_POLICY = 175, |
||||
ERROR_CODE_WEBSOCKET_FRAME_TOO_LONG = 176, |
||||
ERROR_CODE_WEBSOCKET_EXTENSION_MISSING = 177, |
||||
ERROR_CODE_WEBSOCKET_REQUEST_UNAVAILABLE = 178, |
||||
ERROR_CODE_WEBSOCKET_ERROR = 179, |
||||
ERROR_CODE_TLS_CLIENT_CERTIFICATE_ERROR = 180, |
||||
ERROR_CODE_TLS_SERVER_CERTIFICATE_ERROR = 181, |
||||
ERROR_CODE_TLS_CLIENT_AUTHENTICATION_FAILED = 182, |
||||
ERROR_CODE_TLS_SERVER_AUTHENTICATION_FAILED = 183, |
||||
ERROR_CODE_TLS_CLIENT_CERTIFICATE_EXPIRED = 184, |
||||
ERROR_CODE_TLS_SERVER_CERTIFICATE_EXPIRED = 185, |
||||
ERROR_CODE_TLS_CLIENT_CERTIFICATE_REVOKED = 186, |
||||
ERROR_CODE_TLS_SERVER_CERTIFICATE_REVOKED = 187, |
||||
ERROR_CODE_TLS_ERROR = 188, |
||||
ERROR_CODE_DNS_UNAVAILABLE = 189, |
||||
ERROR_CODE_DNS_NAME_RESOLUTION_FAILED = 190, |
||||
ERROR_CODE_DNS_RESOLVER_FAILURE = 191, |
||||
ERROR_CODE_DNS_ERROR = 192, |
||||
ERROR_CODE_TCP_CONNECT_TIMEOUT = 193, |
||||
ERROR_CODE_TCP_CONNECTION_REFUSED = 194, |
||||
ERROR_CODE_TCP_CLOSED_BY_LOCAL = 195, |
||||
ERROR_CODE_TCP_CLOSED_OTHER = 196, |
||||
ERROR_CODE_TCP_ERROR = 197, |
||||
ERROR_CODE_IP_ADDRESS_NOT_REACHABLE = 198, |
||||
ERROR_CODE_IP_ERROR = 199, |
||||
ERROR_CODE_CERTIFICATE_EXPIRED = 200, |
||||
ERROR_CODE_CERTIFICATE_INVALID = 201, |
||||
ERROR_CODE_CERTIFICATE_MALFORMED = 202, |
||||
ERROR_CODE_CERTIFICATE_REVOKED = 203, |
||||
ERROR_CODE_UNKNOWN_SECURITY_KEY = 204, |
||||
ERROR_CODE_REFERENCED_PORT_IN_ERROR = 205, |
||||
MAX_BACNET_ERROR_CODE = 206, |
||||
ERROR_CODE_RESERVED_MAX = 255, |
||||
/* Enumerated values 0-255 are reserved for definition by ASHRAE. */ |
||||
/* Enumerated values 256-65535 may be used by others subject to */ |
||||
/* the procedures and constraints described in Clause 23. */ |
||||
/* do the max range inside of enum so that |
||||
compilers will allocate adequate sized datatype for enum |
||||
which is used to store decoding */ |
||||
ERROR_CODE_PROPRIETARY_FIRST = 256, |
||||
ERROR_CODE_PROPRIETARY_LAST = 65535 |
||||
} |
@ -1,140 +0,0 @@
@@ -1,140 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public struct BacnetEventNotificationData |
||||
{ |
||||
public uint processIdentifier; |
||||
public BacnetObjectId initiatingObjectIdentifier; |
||||
public BacnetObjectId eventObjectIdentifier; |
||||
public BacnetGenericTime timeStamp; |
||||
public uint notificationClass; |
||||
public byte priority; |
||||
public BacnetEventTypes eventType; |
||||
public string messageText; /* OPTIONAL - Set to NULL if not being used */ |
||||
public BacnetNotifyTypes notifyType; |
||||
public bool ackRequired; |
||||
public BacnetEventStates fromState; |
||||
public BacnetEventStates toState; |
||||
|
||||
/* |
||||
** Each of these structures in the union maps to a particular eventtype |
||||
** Based on BACnetNotificationParameters |
||||
*/ |
||||
|
||||
/* |
||||
** EVENT_CHANGE_OF_BITSTRING |
||||
*/ |
||||
public BacnetBitString changeOfBitstring_referencedBitString; |
||||
public BacnetBitString changeOfBitstring_statusFlags; |
||||
/* |
||||
** EVENT_CHANGE_OF_STATE |
||||
*/ |
||||
public BacnetPropertyState changeOfState_newState; |
||||
public BacnetBitString changeOfState_statusFlags; |
||||
/* |
||||
** EVENT_CHANGE_OF_VALUE |
||||
*/ |
||||
public BacnetBitString changeOfValue_changedBits; |
||||
public float changeOfValue_changeValue; |
||||
public BacnetCOVTypes? changeOfValue_tag; |
||||
public BacnetBitString changeOfValue_statusFlags; |
||||
/* |
||||
** EVENT_COMMAND_FAILURE |
||||
*/ |
||||
public uint commandFailure_commandValue; |
||||
public BacnetBitString commandFailure_statusFlags; |
||||
public uint commandFailure_feedbackValue; |
||||
/* |
||||
** EVENT_FLOATING_LIMIT |
||||
*/ |
||||
public float floatingLimit_referenceValue; |
||||
public BacnetBitString floatingLimit_statusFlags; |
||||
public float floatingLimit_setPointValue; |
||||
public float floatingLimit_errorLimit; |
||||
/* |
||||
** EVENT_OUT_OF_RANGE |
||||
*/ |
||||
public float outOfRange_exceedingValue; |
||||
public BacnetBitString outOfRange_statusFlags; |
||||
public float outOfRange_deadband; |
||||
public float outOfRange_exceededLimit; |
||||
/* |
||||
** EVENT_CHANGE_OF_LIFE_SAFETY |
||||
*/ |
||||
public BacnetLifeSafetyStates? changeOfLifeSafety_newState; |
||||
public BacnetLifeSafetyModes? changeOfLifeSafety_newMode; |
||||
public BacnetBitString changeOfLifeSafety_statusFlags; |
||||
public BacnetLifeSafetyOperations? changeOfLifeSafety_operationExpected; |
||||
/* |
||||
** EVENT_EXTENDED |
||||
** |
||||
** Not Supported! |
||||
*/ |
||||
/* |
||||
** EVENT_BUFFER_READY |
||||
*/ |
||||
public BacnetDeviceObjectPropertyReference bufferReady_bufferProperty; |
||||
public uint bufferReady_previousNotification; |
||||
public uint bufferReady_currentNotification; |
||||
/* |
||||
** EVENT_UNSIGNED_RANGE |
||||
*/ |
||||
public uint unsignedRange_exceedingValue; |
||||
public BacnetBitString unsignedRange_statusFlags; |
||||
public uint unsignedRange_exceededLimit; |
||||
/* |
||||
** EVENT_EXTENDED |
||||
*/ |
||||
public uint extended_vendorId; |
||||
public uint extended_eventType; |
||||
public object[] extended_parameters; |
||||
|
||||
public override string ToString() |
||||
{ |
||||
return $"initiatingObject: {initiatingObjectIdentifier}, eventObject: {eventObjectIdentifier}, " |
||||
+ $"eventType: {eventType}, notifyType: {notifyType}, timeStamp: {timeStamp}, " |
||||
+ $"fromState: {fromState}, toState: {toState}, {GetEventDetails() ?? "no details"}"; |
||||
} |
||||
|
||||
private string GetEventDetails() |
||||
{ |
||||
switch (eventType) |
||||
{ |
||||
case BacnetEventTypes.EVENT_CHANGE_OF_BITSTRING: |
||||
return $"referencedBitString: {changeOfBitstring_referencedBitString}, statusFlags: {changeOfBitstring_statusFlags}"; |
||||
|
||||
case BacnetEventTypes.EVENT_CHANGE_OF_STATE: |
||||
return $"newState: {changeOfState_newState}, statusFlags: {changeOfState_statusFlags}"; |
||||
|
||||
case BacnetEventTypes.EVENT_CHANGE_OF_VALUE: |
||||
return $"changedBits: {changeOfValue_changedBits}, changeValue: {changeOfValue_changeValue}, " |
||||
+ $"tag: {changeOfValue_tag}, statusFlags: {changeOfValue_statusFlags}"; |
||||
|
||||
case BacnetEventTypes.EVENT_FLOATING_LIMIT: |
||||
return $"referenceValue: {floatingLimit_referenceValue}, statusFlags: {floatingLimit_statusFlags}, " |
||||
+ $"setPointValue: {floatingLimit_setPointValue}, errorLimit: {floatingLimit_errorLimit}"; |
||||
|
||||
case BacnetEventTypes.EVENT_OUT_OF_RANGE: |
||||
return $"exceedingValue: {outOfRange_exceedingValue}, statusFlags: {outOfRange_statusFlags}, " |
||||
+ $"deadband: {outOfRange_deadband}, exceededLimit: {outOfRange_exceededLimit}"; |
||||
|
||||
case BacnetEventTypes.EVENT_CHANGE_OF_LIFE_SAFETY: |
||||
return $"newState: {changeOfLifeSafety_newState}, newMode: {changeOfLifeSafety_newMode}, " |
||||
+ |
||||
$"statusFlags: {changeOfLifeSafety_statusFlags}, operationExpected: {changeOfLifeSafety_operationExpected}"; |
||||
|
||||
case BacnetEventTypes.EVENT_BUFFER_READY: |
||||
return $"bufferProperty: {bufferReady_bufferProperty}, previousNotification: {bufferReady_previousNotification}, " |
||||
+ $"currentNotification: {bufferReady_currentNotification}"; |
||||
|
||||
case BacnetEventTypes.EVENT_UNSIGNED_RANGE: |
||||
return $"exceedingValue: {unsignedRange_exceedingValue}, statusFlags: {unsignedRange_statusFlags}, " |
||||
+ $"exceededLimit: {unsignedRange_exceededLimit}"; |
||||
|
||||
case BacnetEventTypes.EVENT_EXTENDED: |
||||
return $"vendorId: {extended_vendorId}, extendedEventType: {extended_eventType}, parameters: [{extended_parameters?.Length ?? 0}]"; |
||||
|
||||
default: |
||||
return null; |
||||
} |
||||
} |
||||
}; |
@ -1,20 +0,0 @@
@@ -1,20 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public struct BacnetGenericTime |
||||
{ |
||||
public BacnetTimestampTags Tag; |
||||
public DateTime Time; |
||||
public ushort Sequence; |
||||
|
||||
public BacnetGenericTime(DateTime time, BacnetTimestampTags tag, ushort sequence = 0) |
||||
{ |
||||
Time = time; |
||||
Tag = tag; |
||||
Sequence = sequence; |
||||
} |
||||
|
||||
public override string ToString() |
||||
{ |
||||
return $"{Time}"; |
||||
} |
||||
} |
@ -1,12 +0,0 @@
@@ -1,12 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public struct BacnetGetEventInformationData |
||||
{ |
||||
public BacnetObjectId objectIdentifier; |
||||
public BacnetEventStates eventState; |
||||
public BacnetBitString acknowledgedTransitions; |
||||
public BacnetGenericTime[] eventTimeStamps; //3 |
||||
public BacnetNotifyTypes notifyType; |
||||
public BacnetBitString eventEnable; |
||||
public uint[] eventPriorities; //3 |
||||
} |
@ -1,143 +0,0 @@
@@ -1,143 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public struct BacnetLogRecord |
||||
{ |
||||
public DateTime timestamp; |
||||
|
||||
/* logDatum: CHOICE { */ |
||||
public BacnetTrendLogValueType type; |
||||
//private BacnetBitString log_status; |
||||
//private bool boolean_value; |
||||
//private float real_value; |
||||
//private uint enum_value; |
||||
//private uint unsigned_value; |
||||
//private int signed_value; |
||||
//private BacnetBitString bitstring_value; |
||||
//private bool null_value; |
||||
//private BacnetError failure; |
||||
//private float time_change; |
||||
private object any_value; |
||||
/* } */ |
||||
|
||||
public BacnetBitString statusFlags; |
||||
|
||||
public BacnetLogRecord(BacnetTrendLogValueType type, object value, DateTime stamp, uint status) |
||||
{ |
||||
this.type = type; |
||||
timestamp = stamp; |
||||
statusFlags = BacnetBitString.ConvertFromInt(status); |
||||
any_value = null; |
||||
Value = value; |
||||
} |
||||
|
||||
public object Value |
||||
{ |
||||
get |
||||
{ |
||||
switch (type) |
||||
{ |
||||
case BacnetTrendLogValueType.TL_TYPE_ANY: |
||||
return any_value; |
||||
case BacnetTrendLogValueType.TL_TYPE_BITS: |
||||
return (BacnetBitString)Convert.ChangeType(any_value, typeof(BacnetBitString)); |
||||
case BacnetTrendLogValueType.TL_TYPE_BOOL: |
||||
return (bool)Convert.ChangeType(any_value, typeof(bool)); |
||||
case BacnetTrendLogValueType.TL_TYPE_DELTA: |
||||
return (float)Convert.ChangeType(any_value, typeof(float)); |
||||
case BacnetTrendLogValueType.TL_TYPE_ENUM: |
||||
return (uint)Convert.ChangeType(any_value, typeof(uint)); |
||||
case BacnetTrendLogValueType.TL_TYPE_ERROR: |
||||
if (any_value != null) |
||||
return (BacnetError)Convert.ChangeType(any_value, typeof(BacnetError)); |
||||
else |
||||
return new BacnetError(BacnetErrorClasses.ERROR_CLASS_DEVICE, BacnetErrorCodes.ERROR_CODE_ABORT_OTHER); |
||||
case BacnetTrendLogValueType.TL_TYPE_NULL: |
||||
return null; |
||||
case BacnetTrendLogValueType.TL_TYPE_REAL: |
||||
return (float)Convert.ChangeType(any_value, typeof(float)); |
||||
case BacnetTrendLogValueType.TL_TYPE_SIGN: |
||||
return (int)Convert.ChangeType(any_value, typeof(int)); |
||||
case BacnetTrendLogValueType.TL_TYPE_STATUS: |
||||
return (BacnetBitString)Convert.ChangeType(any_value, typeof(BacnetBitString)); |
||||
case BacnetTrendLogValueType.TL_TYPE_UNSIGN: |
||||
return (uint)Convert.ChangeType(any_value, typeof(uint)); |
||||
default: |
||||
throw new NotSupportedException(); |
||||
} |
||||
} |
||||
set |
||||
{ |
||||
switch (type) |
||||
{ |
||||
case BacnetTrendLogValueType.TL_TYPE_ANY: |
||||
any_value = value; |
||||
break; |
||||
case BacnetTrendLogValueType.TL_TYPE_BITS: |
||||
if (value == null) value = new BacnetBitString(); |
||||
if (value.GetType() != typeof(BacnetBitString)) |
||||
value = BacnetBitString.ConvertFromInt((uint)Convert.ChangeType(value, typeof(uint))); |
||||
any_value = (BacnetBitString)value; |
||||
break; |
||||
case BacnetTrendLogValueType.TL_TYPE_BOOL: |
||||
if (value == null) value = false; |
||||
if (value.GetType() != typeof(bool)) |
||||
value = (bool)Convert.ChangeType(value, typeof(bool)); |
||||
any_value = (bool)value; |
||||
break; |
||||
case BacnetTrendLogValueType.TL_TYPE_DELTA: |
||||
if (value == null) value = (float)0; |
||||
if (value.GetType() != typeof(float)) |
||||
value = (float)Convert.ChangeType(value, typeof(float)); |
||||
any_value = (float)value; |
||||
break; |
||||
case BacnetTrendLogValueType.TL_TYPE_ENUM: |
||||
if (value == null) value = (uint)0; |
||||
if (value.GetType() != typeof(uint)) |
||||
value = (uint)Convert.ChangeType(value, typeof(uint)); |
||||
any_value = (uint)value; |
||||
break; |
||||
case BacnetTrendLogValueType.TL_TYPE_ERROR: |
||||
if (value == null) value = new BacnetError(); |
||||
if (value.GetType() != typeof(BacnetError)) |
||||
throw new ArgumentException(); |
||||
any_value = (BacnetError)value; |
||||
break; |
||||
case BacnetTrendLogValueType.TL_TYPE_NULL: |
||||
if (value != null) throw new ArgumentException(); |
||||
any_value = value; |
||||
break; |
||||
case BacnetTrendLogValueType.TL_TYPE_REAL: |
||||
if (value == null) value = (float)0; |
||||
if (value.GetType() != typeof(float)) |
||||
value = (float)Convert.ChangeType(value, typeof(float)); |
||||
any_value = (float)value; |
||||
break; |
||||
case BacnetTrendLogValueType.TL_TYPE_SIGN: |
||||
if (value == null) value = 0; |
||||
if (value.GetType() != typeof(int)) |
||||
value = (int)Convert.ChangeType(value, typeof(int)); |
||||
any_value = (int)value; |
||||
break; |
||||
case BacnetTrendLogValueType.TL_TYPE_STATUS: |
||||
if (value == null) value = new BacnetBitString(); |
||||
if (value.GetType() != typeof(BacnetBitString)) |
||||
value = BacnetBitString.ConvertFromInt((uint)Convert.ChangeType(value, typeof(uint))); |
||||
any_value = (BacnetBitString)value; |
||||
break; |
||||
case BacnetTrendLogValueType.TL_TYPE_UNSIGN: |
||||
if (value == null) value = (uint)0; |
||||
if (value.GetType() != typeof(uint)) |
||||
value = (uint)Convert.ChangeType(value, typeof(uint)); |
||||
any_value = (uint)value; |
||||
break; |
||||
default: |
||||
throw new NotSupportedException(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
public T GetValue<T>() |
||||
{ |
||||
return (T)Convert.ChangeType(Value, typeof(T)); |
||||
} |
||||
} |
@ -1,11 +0,0 @@
@@ -1,11 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public enum BacnetMaxAdpu : byte |
||||
{ |
||||
MAX_APDU50 = 0, |
||||
MAX_APDU128 = 1, |
||||
MAX_APDU206 = 2, |
||||
MAX_APDU480 = 3, |
||||
MAX_APDU1024 = 4, |
||||
MAX_APDU1476 = 5 |
||||
} |
@ -1,13 +0,0 @@
@@ -1,13 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public enum BacnetMaxSegments : byte |
||||
{ |
||||
MAX_SEG0 = 0, |
||||
MAX_SEG2 = 0x10, |
||||
MAX_SEG4 = 0x20, |
||||
MAX_SEG8 = 0x30, |
||||
MAX_SEG16 = 0x40, |
||||
MAX_SEG32 = 0x50, |
||||
MAX_SEG64 = 0x60, |
||||
MAX_SEG65 = 0x70 |
||||
} |
@ -1,23 +0,0 @@
@@ -1,23 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
/* MS/TP Frame Type */ |
||||
public enum BacnetMstpFrameTypes : byte |
||||
{ |
||||
/* Frame Types 8 through 127 are reserved by ASHRAE. */ |
||||
FRAME_TYPE_TOKEN = 0, |
||||
FRAME_TYPE_POLL_FOR_MASTER = 1, |
||||
FRAME_TYPE_REPLY_TO_POLL_FOR_MASTER = 2, |
||||
FRAME_TYPE_TEST_REQUEST = 3, |
||||
FRAME_TYPE_TEST_RESPONSE = 4, |
||||
FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY = 5, |
||||
FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY = 6, |
||||
FRAME_TYPE_REPLY_POSTPONED = 7, |
||||
/* Frame Types 128 through 255: Proprietary Frames */ |
||||
/* These frames are available to vendors as proprietary (non-BACnet) frames. */ |
||||
/* The first two octets of the Data field shall specify the unique vendor */ |
||||
/* identification code, most significant octet first, for the type of */ |
||||
/* vendor-proprietary frame to be conveyed. The length of the data portion */ |
||||
/* of a Proprietary frame shall be in the range of 2 to 501 octets. */ |
||||
FRAME_TYPE_PROPRIETARY_MIN = 128, |
||||
FRAME_TYPE_PROPRIETARY_MAX = 255 |
||||
} |
@ -1,31 +0,0 @@
@@ -1,31 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
/*Network Layer Message Type */ |
||||
/*If Bit 7 of the control octet described in 6.2.2 is 1, */ |
||||
/* a message type octet shall be present as shown in Figure 6-1. */ |
||||
/* The following message types are indicated: */ |
||||
public enum BacnetNetworkMessageTypes : byte |
||||
{ |
||||
NETWORK_MESSAGE_WHO_IS_ROUTER_TO_NETWORK = 0, |
||||
NETWORK_MESSAGE_I_AM_ROUTER_TO_NETWORK = 1, |
||||
NETWORK_MESSAGE_I_COULD_BE_ROUTER_TO_NETWORK = 2, |
||||
NETWORK_MESSAGE_REJECT_MESSAGE_TO_NETWORK = 3, |
||||
NETWORK_MESSAGE_ROUTER_BUSY_TO_NETWORK = 4, |
||||
NETWORK_MESSAGE_ROUTER_AVAILABLE_TO_NETWORK = 5, |
||||
NETWORK_MESSAGE_INIT_RT_TABLE = 6, |
||||
NETWORK_MESSAGE_INIT_RT_TABLE_ACK = 7, |
||||
NETWORK_MESSAGE_ESTABLISH_CONNECTION_TO_NETWORK = 8, |
||||
NETWORK_MESSAGE_DISCONNECT_CONNECTION_TO_NETWORK = 9, |
||||
NETWORK_MESSAGE_CHALLENGE_REQUEST = 10, |
||||
NETWORK_MESSAGE_SECURITY_PAYLOAD = 11, |
||||
NETWORK_MESSAGE_SECURITY_RESPONSE = 12, |
||||
NETWORK_MESSAGE_REQUEST_KEY_UPDATE = 13, |
||||
NETWORK_MESSAGE_UPDATE_KEY_SET = 14, |
||||
NETWORK_MESSAGE_UPDATE_DISTRIBUTION_KEY = 15, |
||||
NETWORK_MESSAGE_REQUEST_MASTER_KEY = 16, |
||||
NETWORK_MESSAGE_SET_MASTER_KEY = 17, |
||||
NETWORK_MESSAGE_WHAT_IS_NETWORK_NUMBER = 18, |
||||
NETWORK_MESSAGE_NETWORK_NUMBER_IS = 19 |
||||
/* X'0A' to X'7F': Reserved for use by ASHRAE, */ |
||||
/* X'80' to X'FF': Available for vendor proprietary messages */ |
||||
} |
@ -1,17 +0,0 @@
@@ -1,17 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public enum BacnetNodeTypes |
||||
{ |
||||
NT_UNKNOWN, |
||||
NT_SYSTEM, |
||||
NT_NETWORK, |
||||
NT_DEVICE, |
||||
NT_ORGANIZATIONAL, |
||||
NT_AREA, |
||||
NT_EQUIPMENT, |
||||
NT_POINT, |
||||
NT_COLLECTION, |
||||
NT_PROPERTY, |
||||
NT_FUNCTIONAL, |
||||
NT_OTHER, |
||||
} |
@ -1,14 +0,0 @@
@@ -1,14 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
[Flags] |
||||
public enum BacnetNpduControls : byte |
||||
{ |
||||
PriorityNormalMessage = 0, |
||||
PriorityUrgentMessage = 1, |
||||
PriorityCriticalMessage = 2, |
||||
PriorityLifeSafetyMessage = 3, |
||||
ExpectingReply = 4, |
||||
SourceSpecified = 8, |
||||
DestinationSpecified = 32, |
||||
NetworkLayerMessage = 128 |
||||
} |
@ -1,7 +0,0 @@
@@ -1,7 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public struct BacnetObjectDescription |
||||
{ |
||||
public BacnetObjectTypes typeId; |
||||
public List<BacnetPropertyIds> propsId; |
||||
} |
@ -1,82 +0,0 @@
@@ -1,82 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
[Serializable] |
||||
public struct BacnetObjectId : IComparable<BacnetObjectId> |
||||
{ |
||||
public BacnetObjectTypes type; |
||||
public uint instance; |
||||
|
||||
public BacnetObjectTypes Type |
||||
{ |
||||
get => type; |
||||
set => type = value; |
||||
} |
||||
|
||||
public uint Instance |
||||
{ |
||||
get => instance; |
||||
set => instance = value; |
||||
} |
||||
|
||||
public BacnetObjectId(BacnetObjectTypes type, uint instance) |
||||
{ |
||||
this.type = type; |
||||
this.instance = instance; |
||||
} |
||||
|
||||
public override string ToString() |
||||
{ |
||||
return $"{Type}:{Instance}"; |
||||
} |
||||
|
||||
public override int GetHashCode() |
||||
{ |
||||
return ToString().GetHashCode(); |
||||
} |
||||
|
||||
public override bool Equals(object obj) |
||||
{ |
||||
return obj != null && obj.ToString().Equals(ToString()); |
||||
} |
||||
|
||||
public int CompareTo(BacnetObjectId other) |
||||
{ |
||||
if (Type == other.Type) |
||||
return Instance.CompareTo(other.Instance); |
||||
|
||||
if (Type == BacnetObjectTypes.OBJECT_DEVICE) |
||||
return -1; |
||||
|
||||
if (other.Type == BacnetObjectTypes.OBJECT_DEVICE) |
||||
return 1; |
||||
|
||||
// cast to int for comparison otherwise unpredictable behaviour with outbound enum (proprietary type) |
||||
return ((int)Type).CompareTo((int)other.Type); |
||||
} |
||||
|
||||
public static bool operator ==(BacnetObjectId a, BacnetObjectId b) |
||||
{ |
||||
return a.Equals(b); |
||||
} |
||||
|
||||
public static bool operator !=(BacnetObjectId a, BacnetObjectId b) |
||||
{ |
||||
return !(a == b); |
||||
} |
||||
|
||||
public static BacnetObjectId Parse(string value) |
||||
{ |
||||
var pattern = new Regex($"(?<{nameof(Type)}>.+):(?<{nameof(Instance)}>.+)"); |
||||
|
||||
if (string.IsNullOrEmpty(value) || !pattern.IsMatch(value)) |
||||
return new BacnetObjectId(); |
||||
|
||||
var objectType = (BacnetObjectTypes)Enum.Parse(typeof(BacnetObjectTypes), |
||||
pattern.Match(value).Groups[nameof(Type)].Value); |
||||
|
||||
var objectInstance = uint.Parse(pattern.Match(value).Groups[nameof(Instance)].Value); |
||||
|
||||
return new BacnetObjectId(objectType, objectInstance); |
||||
} |
||||
|
||||
}; |
@ -1,82 +0,0 @@
@@ -1,82 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public enum BacnetObjectTypes : uint |
||||
{ |
||||
OBJECT_ANALOG_INPUT = 0, |
||||
OBJECT_ANALOG_OUTPUT = 1, |
||||
OBJECT_ANALOG_VALUE = 2, |
||||
OBJECT_BINARY_INPUT = 3, |
||||
OBJECT_BINARY_OUTPUT = 4, |
||||
OBJECT_BINARY_VALUE = 5, |
||||
OBJECT_CALENDAR = 6, |
||||
OBJECT_COMMAND = 7, |
||||
OBJECT_DEVICE = 8, |
||||
OBJECT_EVENT_ENROLLMENT = 9, |
||||
OBJECT_FILE = 10, |
||||
OBJECT_GROUP = 11, |
||||
OBJECT_LOOP = 12, |
||||
OBJECT_MULTI_STATE_INPUT = 13, |
||||
OBJECT_MULTI_STATE_OUTPUT = 14, |
||||
OBJECT_NOTIFICATION_CLASS = 15, |
||||
OBJECT_PROGRAM = 16, |
||||
OBJECT_SCHEDULE = 17, |
||||
OBJECT_AVERAGING = 18, |
||||
OBJECT_MULTI_STATE_VALUE = 19, |
||||
OBJECT_TRENDLOG = 20, |
||||
OBJECT_LIFE_SAFETY_POINT = 21, |
||||
OBJECT_LIFE_SAFETY_ZONE = 22, |
||||
OBJECT_ACCUMULATOR = 23, |
||||
OBJECT_PULSE_CONVERTER = 24, |
||||
OBJECT_EVENT_LOG = 25, |
||||
OBJECT_GLOBAL_GROUP = 26, |
||||
OBJECT_TREND_LOG_MULTIPLE = 27, |
||||
OBJECT_LOAD_CONTROL = 28, |
||||
OBJECT_STRUCTURED_VIEW = 29, |
||||
OBJECT_ACCESS_DOOR = 30, |
||||
OBJECT_TIMER = 31, /* Addendum 135-2012ay */ |
||||
OBJECT_ACCESS_CREDENTIAL = 32, /* Addendum 2008-j */ |
||||
OBJECT_ACCESS_POINT = 33, |
||||
OBJECT_ACCESS_RIGHTS = 34, |
||||
OBJECT_ACCESS_USER = 35, |
||||
OBJECT_ACCESS_ZONE = 36, |
||||
OBJECT_CREDENTIAL_DATA_INPUT = 37, /* authentication-factor-input */ |
||||
OBJECT_NETWORK_SECURITY = 38, /* Addendum 2008-g */ |
||||
OBJECT_BITSTRING_VALUE = 39, /* Addendum 2008-w */ |
||||
OBJECT_CHARACTERSTRING_VALUE = 40, /* Addendum 2008-w */ |
||||
OBJECT_DATE_PATTERN_VALUE = 41, /* Addendum 2008-w */ |
||||
OBJECT_DATE_VALUE = 42, /* Addendum 2008-w */ |
||||
OBJECT_DATETIME_PATTERN_VALUE = 43, /* Addendum 2008-w */ |
||||
OBJECT_DATETIME_VALUE = 44, /* Addendum 2008-w */ |
||||
OBJECT_INTEGER_VALUE = 45, /* Addendum 2008-w */ |
||||
OBJECT_LARGE_ANALOG_VALUE = 46, /* Addendum 2008-w */ |
||||
OBJECT_OCTETSTRING_VALUE = 47, /* Addendum 2008-w */ |
||||
OBJECT_POSITIVE_INTEGER_VALUE = 48, /* Addendum 2008-w */ |
||||
OBJECT_TIME_PATTERN_VALUE = 49, /* Addendum 2008-w */ |
||||
OBJECT_TIME_VALUE = 50, /* Addendum 2008-w */ |
||||
OBJECT_NOTIFICATION_FORWARDER = 51, /* Addendum 2010-af */ |
||||
OBJECT_ALERT_ENROLLMENT = 52, /* Addendum 2010-af */ |
||||
OBJECT_CHANNEL = 53, /* Addendum 2010-aa */ |
||||
OBJECT_LIGHTING_OUTPUT = 54, /* Addendum 2010-i */ |
||||
OBJECT_BINARY_LIGHTING_OUTPUT = 55, /* Addendum 135-2012az */ |
||||
OBJECT_NETWORK_PORT = 56, /* Addendum 135-2012az */ |
||||
OBJECT_ELEVATOR_GROUP = 57, /* Addendum 135-2012aq */ |
||||
OBJECT_ESCALATOR = 58, /* Addendum 135-2012aq */ |
||||
OBJECT_LIFT = 59, /* Addendum 135-2012aq */ |
||||
OBJECT_STAGING = 60, /* Addendum 135-2016bd */ |
||||
OBJECT_AUDIT_LOG = 61, /* Addendum 135-2016bi */ |
||||
OBJECT_AUDIT_REPORTER = 62, /* Addendum 135-2016bi */ |
||||
OBJECT_COLOR = 63, /* Addendum 135-2020ca */ |
||||
OBJECT_COLOR_TEMPERATURE = 64, /* Addendum 135-2020ca */ |
||||
|
||||
/* Enumerated values 0-127 are reserved for definition by ASHRAE. */ |
||||
/* Enumerated values 128-1023 may be used by others subject to */ |
||||
/* the procedures and constraints described in Clause 23. */ |
||||
/* do the max range inside of enum so that |
||||
compilers will allocate adequate sized datatype for enum |
||||
which is used to store decoding */ |
||||
|
||||
OBJECT_PROPRIETARY_MIN = 128, |
||||
OBJECT_PROPRIETARY_MAX = 1023, |
||||
MAX_BACNET_OBJECT_TYPE = 1024, |
||||
MAX_ASHRAE_OBJECT_TYPE = 65 |
||||
} |
@ -1,22 +0,0 @@
@@ -1,22 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
[Flags] |
||||
/* note: these are not the real values, */ |
||||
/* but are shifted left for easy encoding */ |
||||
public enum BacnetPduTypes : byte |
||||
{ |
||||
PDU_TYPE_CONFIRMED_SERVICE_REQUEST = 0, |
||||
SERVER = 1, |
||||
NEGATIVE_ACK = 2, |
||||
SEGMENTED_RESPONSE_ACCEPTED = 2, |
||||
MORE_FOLLOWS = 4, |
||||
SEGMENTED_MESSAGE = 8, |
||||
PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST = 0x10, |
||||
PDU_TYPE_SIMPLE_ACK = 0x20, |
||||
PDU_TYPE_COMPLEX_ACK = 0x30, |
||||
PDU_TYPE_SEGMENT_ACK = 0x40, |
||||
PDU_TYPE_ERROR = 0x50, |
||||
PDU_TYPE_REJECT = 0x60, |
||||
PDU_TYPE_ABORT = 0x70, |
||||
PDU_TYPE_MASK = 0xF0, |
||||
} |
@ -1,7 +0,0 @@
@@ -1,7 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public enum BacnetPolarity : byte |
||||
{ |
||||
POLARITY_NORMAL = 0, |
||||
POLARITY_REVERSE = 1 |
||||
} |
@ -1,18 +0,0 @@
@@ -1,18 +0,0 @@
|
||||
namespace System.IO.BACnet.Base; |
||||
|
||||
public enum BacnetProgramError : ushort |
||||
{ |
||||
PROGRAM_ERROR_NORMAL = 0, |
||||
PROGRAM_ERROR_LOAD_FAILED = 1, |
||||
PROGRAM_ERROR_INTERNAL = 2, |
||||
PROGRAM_ERROR_PROGRAM = 3, |
||||
PROGRAM_ERROR_OTHER = 4, |
||||
/* Enumerated values 0-63 are reserved for definition by ASHRAE. */ |
||||
/* Enumerated values 64-65535 may be used by others subject to */ |
||||
/* the procedures and constraints described in Clause 23. */ |
||||
/* do the max range inside of enum so that |
||||
compilers will allocate adequate sized datatype for enum |
||||
which is used to store decoding */ |
||||
PROGRAM_ERROR_PROPRIETARY_MIN = 64, |
||||
PROGRAM_ERROR_PROPRIETARY_MAX = 65535 |
||||
} |
@ -1,11 +0,0 @@
@@ -1,11 +0,0 @@
|
||||
namespace System.IO.BACnet.Base; |
||||
|
||||
public enum BacnetProgramRequest |
||||
{ |
||||
PROGRAM_REQUEST_READY = 0, |
||||
PROGRAM_REQUEST_LOAD = 1, |
||||
PROGRAM_REQUEST_RUN = 2, |
||||
PROGRAM_REQUEST_HALT = 3, |
||||
PROGRAM_REQUEST_RESTART = 4, |
||||
PROGRAM_REQUEST_UNLOAD = 5 |
||||
} |
@ -1,11 +0,0 @@
@@ -1,11 +0,0 @@
|
||||
namespace System.IO.BACnet.Base; |
||||
|
||||
public enum BacnetProgramState |
||||
{ |
||||
PROGRAM_STATE_IDLE = 0, |
||||
PROGRAM_STATE_LOADING = 1, |
||||
PROGRAM_STATE_RUNNING = 2, |
||||
PROGRAM_STATE_WAITING = 3, |
||||
PROGRAM_STATE_HALTED = 4, |
||||
PROGRAM_STATE_UNLOADING = 5 |
||||
} |
@ -1,577 +0,0 @@
@@ -1,577 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public enum BacnetPropertyIds |
||||
{ |
||||
PROP_ACKED_TRANSITIONS = 0, |
||||
PROP_ACK_REQUIRED = 1, |
||||
PROP_ACTION = 2, |
||||
PROP_ACTION_TEXT = 3, |
||||
PROP_ACTIVE_TEXT = 4, |
||||
PROP_ACTIVE_VT_SESSIONS = 5, |
||||
PROP_ALARM_VALUE = 6, |
||||
PROP_ALARM_VALUES = 7, |
||||
PROP_ALL = 8, |
||||
PROP_ALL_WRITES_SUCCESSFUL = 9, |
||||
PROP_APDU_SEGMENT_TIMEOUT = 10, |
||||
PROP_APDU_TIMEOUT = 11, |
||||
PROP_APPLICATION_SOFTWARE_VERSION = 12, |
||||
PROP_ARCHIVE = 13, |
||||
PROP_BIAS = 14, |
||||
PROP_CHANGE_OF_STATE_COUNT = 15, |
||||
PROP_CHANGE_OF_STATE_TIME = 16, |
||||
PROP_NOTIFICATION_CLASS = 17, |
||||
PROP_BLANK_1 = 18, |
||||
PROP_CONTROLLED_VARIABLE_REFERENCE = 19, |
||||
PROP_CONTROLLED_VARIABLE_UNITS = 20, |
||||
PROP_CONTROLLED_VARIABLE_VALUE = 21, |
||||
PROP_COV_INCREMENT = 22, |
||||
PROP_DATE_LIST = 23, |
||||
PROP_DAYLIGHT_SAVINGS_STATUS = 24, |
||||
PROP_DEADBAND = 25, |
||||
PROP_DERIVATIVE_CONSTANT = 26, |
||||
PROP_DERIVATIVE_CONSTANT_UNITS = 27, |
||||
PROP_DESCRIPTION = 28, |
||||
PROP_DESCRIPTION_OF_HALT = 29, |
||||
PROP_DEVICE_ADDRESS_BINDING = 30, |
||||
PROP_DEVICE_TYPE = 31, |
||||
PROP_EFFECTIVE_PERIOD = 32, |
||||
PROP_ELAPSED_ACTIVE_TIME = 33, |
||||
PROP_ERROR_LIMIT = 34, |
||||
PROP_EVENT_ENABLE = 35, |
||||
PROP_EVENT_STATE = 36, |
||||
PROP_EVENT_TYPE = 37, |
||||
PROP_EXCEPTION_SCHEDULE = 38, |
||||
PROP_FAULT_VALUES = 39, |
||||
PROP_FEEDBACK_VALUE = 40, |
||||
PROP_FILE_ACCESS_METHOD = 41, |
||||
PROP_FILE_SIZE = 42, |
||||
PROP_FILE_TYPE = 43, |
||||
PROP_FIRMWARE_REVISION = 44, |
||||
PROP_HIGH_LIMIT = 45, |
||||
PROP_INACTIVE_TEXT = 46, |
||||
PROP_IN_PROCESS = 47, |
||||
PROP_INSTANCE_OF = 48, |
||||
PROP_INTEGRAL_CONSTANT = 49, |
||||
PROP_INTEGRAL_CONSTANT_UNITS = 50, |
||||
PROP_ISSUE_CONFIRMED_NOTIFICATIONS = 51, |
||||
PROP_LIMIT_ENABLE = 52, |
||||
PROP_LIST_OF_GROUP_MEMBERS = 53, |
||||
PROP_LIST_OF_OBJECT_PROPERTY_REFERENCES = 54, |
||||
PROP_LIST_OF_SESSION_KEYS = 55, |
||||
PROP_LOCAL_DATE = 56, |
||||
PROP_LOCAL_TIME = 57, |
||||
PROP_LOCATION = 58, |
||||
PROP_LOW_LIMIT = 59, |
||||
PROP_MANIPULATED_VARIABLE_REFERENCE = 60, |
||||
PROP_MAXIMUM_OUTPUT = 61, |
||||
PROP_MAX_APDU_LENGTH_ACCEPTED = 62, |
||||
PROP_MAX_INFO_FRAMES = 63, |
||||
PROP_MAX_MASTER = 64, |
||||
PROP_MAX_PRES_VALUE = 65, |
||||
PROP_MINIMUM_OFF_TIME = 66, |
||||
PROP_MINIMUM_ON_TIME = 67, |
||||
PROP_MINIMUM_OUTPUT = 68, |
||||
PROP_MIN_PRES_VALUE = 69, |
||||
PROP_MODEL_NAME = 70, |
||||
PROP_MODIFICATION_DATE = 71, |
||||
PROP_NOTIFY_TYPE = 72, |
||||
PROP_NUMBER_OF_APDU_RETRIES = 73, |
||||
PROP_NUMBER_OF_STATES = 74, |
||||
PROP_OBJECT_IDENTIFIER = 75, |
||||
PROP_OBJECT_LIST = 76, |
||||
PROP_OBJECT_NAME = 77, |
||||
PROP_OBJECT_PROPERTY_REFERENCE = 78, |
||||
PROP_OBJECT_TYPE = 79, |
||||
PROP_OPTIONAL = 80, |
||||
PROP_OUT_OF_SERVICE = 81, |
||||
PROP_OUTPUT_UNITS = 82, |
||||
PROP_EVENT_PARAMETERS = 83, |
||||
PROP_POLARITY = 84, |
||||
PROP_PRESENT_VALUE = 85, |
||||
PROP_PRIORITY = 86, |
||||
PROP_PRIORITY_ARRAY = 87, |
||||
PROP_PRIORITY_FOR_WRITING = 88, |
||||
PROP_PROCESS_IDENTIFIER = 89, |
||||
PROP_PROGRAM_CHANGE = 90, |
||||
PROP_PROGRAM_LOCATION = 91, |
||||
PROP_PROGRAM_STATE = 92, |
||||
PROP_PROPORTIONAL_CONSTANT = 93, |
||||
PROP_PROPORTIONAL_CONSTANT_UNITS = 94, |
||||
PROP_PROTOCOL_CONFORMANCE_CLASS = 95, /* deleted in version 1 revision 2 */ |
||||
PROP_PROTOCOL_OBJECT_TYPES_SUPPORTED = 96, |
||||
PROP_PROTOCOL_SERVICES_SUPPORTED = 97, |
||||
PROP_PROTOCOL_VERSION = 98, |
||||
PROP_READ_ONLY = 99, |
||||
PROP_REASON_FOR_HALT = 100, |
||||
PROP_RECIPIENT = 101, |
||||
PROP_RECIPIENT_LIST = 102, |
||||
PROP_RELIABILITY = 103, |
||||
PROP_RELINQUISH_DEFAULT = 104, |
||||
PROP_REQUIRED = 105, |
||||
PROP_RESOLUTION = 106, |
||||
PROP_SEGMENTATION_SUPPORTED = 107, |
||||
PROP_SETPOINT = 108, |
||||
PROP_SETPOINT_REFERENCE = 109, |
||||
PROP_STATE_TEXT = 110, |
||||
PROP_STATUS_FLAGS = 111, |
||||
PROP_SYSTEM_STATUS = 112, |
||||
PROP_TIME_DELAY = 113, |
||||
PROP_TIME_OF_ACTIVE_TIME_RESET = 114, |
||||
PROP_TIME_OF_STATE_COUNT_RESET = 115, |
||||
PROP_TIME_SYNCHRONIZATION_RECIPIENTS = 116, |
||||
PROP_UNITS = 117, |
||||
PROP_UPDATE_INTERVAL = 118, |
||||
PROP_UTC_OFFSET = 119, |
||||
PROP_VENDOR_IDENTIFIER = 120, |
||||
PROP_VENDOR_NAME = 121, |
||||
PROP_VT_CLASSES_SUPPORTED = 122, |
||||
PROP_WEEKLY_SCHEDULE = 123, |
||||
PROP_ATTEMPTED_SAMPLES = 124, |
||||
PROP_AVERAGE_VALUE = 125, |
||||
PROP_BUFFER_SIZE = 126, |
||||
PROP_CLIENT_COV_INCREMENT = 127, |
||||
PROP_COV_RESUBSCRIPTION_INTERVAL = 128, |
||||
PROP_CURRENT_NOTIFY_TIME = 129, |
||||
PROP_EVENT_TIME_STAMPS = 130, |
||||
PROP_LOG_BUFFER = 131, |
||||
PROP_LOG_DEVICE_OBJECT_PROPERTY = 132, |
||||
/* The enable property is renamed from log-enable in |
||||
Addendum b to ANSI/ASHRAE 135-2004(135b-2) */ |
||||
PROP_ENABLE = 133, |
||||
PROP_LOG_INTERVAL = 134, |
||||
PROP_MAXIMUM_VALUE = 135, |
||||
PROP_MINIMUM_VALUE = 136, |
||||
PROP_NOTIFICATION_THRESHOLD = 137, |
||||
PROP_PREVIOUS_NOTIFY_TIME = 138, |
||||
PROP_PROTOCOL_REVISION = 139, |
||||
PROP_RECORDS_SINCE_NOTIFICATION = 140, |
||||
PROP_RECORD_COUNT = 141, |
||||
PROP_START_TIME = 142, |
||||
PROP_STOP_TIME = 143, |
||||
PROP_STOP_WHEN_FULL = 144, |
||||
PROP_TOTAL_RECORD_COUNT = 145, |
||||
PROP_VALID_SAMPLES = 146, |
||||
PROP_WINDOW_INTERVAL = 147, |
||||
PROP_WINDOW_SAMPLES = 148, |
||||
PROP_MAXIMUM_VALUE_TIMESTAMP = 149, |
||||
PROP_MINIMUM_VALUE_TIMESTAMP = 150, |
||||
PROP_VARIANCE_VALUE = 151, |
||||
PROP_ACTIVE_COV_SUBSCRIPTIONS = 152, |
||||
PROP_BACKUP_FAILURE_TIMEOUT = 153, |
||||
PROP_CONFIGURATION_FILES = 154, |
||||
PROP_DATABASE_REVISION = 155, |
||||
PROP_DIRECT_READING = 156, |
||||
PROP_LAST_RESTORE_TIME = 157, |
||||
PROP_MAINTENANCE_REQUIRED = 158, |
||||
PROP_MEMBER_OF = 159, |
||||
PROP_MODE = 160, |
||||
PROP_OPERATION_EXPECTED = 161, |
||||
PROP_SETTING = 162, |
||||
PROP_SILENCED = 163, |
||||
PROP_TRACKING_VALUE = 164, |
||||
PROP_ZONE_MEMBERS = 165, |
||||
PROP_LIFE_SAFETY_ALARM_VALUES = 166, |
||||
PROP_MAX_SEGMENTS_ACCEPTED = 167, |
||||
PROP_PROFILE_NAME = 168, |
||||
PROP_AUTO_SLAVE_DISCOVERY = 169, |
||||
PROP_MANUAL_SLAVE_ADDRESS_BINDING = 170, |
||||
PROP_SLAVE_ADDRESS_BINDING = 171, |
||||
PROP_SLAVE_PROXY_ENABLE = 172, |
||||
PROP_LAST_NOTIFY_RECORD = 173, |
||||
PROP_SCHEDULE_DEFAULT = 174, |
||||
PROP_ACCEPTED_MODES = 175, |
||||
PROP_ADJUST_VALUE = 176, |
||||
PROP_COUNT = 177, |
||||
PROP_COUNT_BEFORE_CHANGE = 178, |
||||
PROP_COUNT_CHANGE_TIME = 179, |
||||
PROP_COV_PERIOD = 180, |
||||
PROP_INPUT_REFERENCE = 181, |
||||
PROP_LIMIT_MONITORING_INTERVAL = 182, |
||||
PROP_LOGGING_OBJECT = 183, |
||||
PROP_LOGGING_RECORD = 184, |
||||
PROP_PRESCALE = 185, |
||||
PROP_PULSE_RATE = 186, |
||||
PROP_SCALE = 187, |
||||
PROP_SCALE_FACTOR = 188, |
||||
PROP_UPDATE_TIME = 189, |
||||
PROP_VALUE_BEFORE_CHANGE = 190, |
||||
PROP_VALUE_SET = 191, |
||||
PROP_VALUE_CHANGE_TIME = 192, |
||||
/* enumerations 193-206 are new */ |
||||
PROP_ALIGN_INTERVALS = 193, |
||||
/* enumeration 194 is unassigned */ |
||||
PROP_INTERVAL_OFFSET = 195, |
||||
PROP_LAST_RESTART_REASON = 196, |
||||
PROP_LOGGING_TYPE = 197, |
||||
/* enumeration 198-201 is unassigned */ |
||||
PROP_RESTART_NOTIFICATION_RECIPIENTS = 202, |
||||
PROP_TIME_OF_DEVICE_RESTART = 203, |
||||
PROP_TIME_SYNCHRONIZATION_INTERVAL = 204, |
||||
PROP_TRIGGER = 205, |
||||
PROP_UTC_TIME_SYNCHRONIZATION_RECIPIENTS = 206, |
||||
/* enumerations 207-211 are used in Addendum d to ANSI/ASHRAE 135-2004 */ |
||||
PROP_NODE_SUBTYPE = 207, |
||||
PROP_NODE_TYPE = 208, |
||||
PROP_STRUCTURED_OBJECT_LIST = 209, |
||||
PROP_SUBORDINATE_ANNOTATIONS = 210, |
||||
PROP_SUBORDINATE_LIST = 211, |
||||
/* enumerations 212-225 are used in Addendum e to ANSI/ASHRAE 135-2004 */ |
||||
PROP_ACTUAL_SHED_LEVEL = 212, |
||||
PROP_DUTY_WINDOW = 213, |
||||
PROP_EXPECTED_SHED_LEVEL = 214, |
||||
PROP_FULL_DUTY_BASELINE = 215, |
||||
/* enumerations 216-217 are unassigned */ |
||||
/* enumerations 212-225 are used in Addendum e to ANSI/ASHRAE 135-2004 */ |
||||
PROP_REQUESTED_SHED_LEVEL = 218, |
||||
PROP_SHED_DURATION = 219, |
||||
PROP_SHED_LEVEL_DESCRIPTIONS = 220, |
||||
PROP_SHED_LEVELS = 221, |
||||
PROP_STATE_DESCRIPTION = 222, |
||||
/* enumerations 223-225 are unassigned */ |
||||
/* enumerations 226-235 are used in Addendum f to ANSI/ASHRAE 135-2004 */ |
||||
PROP_DOOR_ALARM_STATE = 226, |
||||
PROP_DOOR_EXTENDED_PULSE_TIME = 227, |
||||
PROP_DOOR_MEMBERS = 228, |
||||
PROP_DOOR_OPEN_TOO_LONG_TIME = 229, |
||||
PROP_DOOR_PULSE_TIME = 230, |
||||
PROP_DOOR_STATUS = 231, |
||||
PROP_DOOR_UNLOCK_DELAY_TIME = 232, |
||||
PROP_LOCK_STATUS = 233, |
||||
PROP_MASKED_ALARM_VALUES = 234, |
||||
PROP_SECURED_STATUS = 235, |
||||
/* enumerations 236-243 are unassigned */ |
||||
/* enumerations 244-311 are used in Addendum j to ANSI/ASHRAE 135-2004 */ |
||||
PROP_ABSENTEE_LIMIT = 244, |
||||
PROP_ACCESS_ALARM_EVENTS = 245, |
||||
PROP_ACCESS_DOORS = 246, |
||||
PROP_ACCESS_EVENT = 247, |
||||
PROP_ACCESS_EVENT_AUTHENTICATION_FACTOR = 248, |
||||
PROP_ACCESS_EVENT_CREDENTIAL = 249, |
||||
PROP_ACCESS_EVENT_TIME = 250, |
||||
PROP_ACCESS_TRANSACTION_EVENTS = 251, |
||||
PROP_ACCOMPANIMENT = 252, |
||||
PROP_ACCOMPANIMENT_TIME = 253, |
||||
PROP_ACTIVATION_TIME = 254, |
||||
PROP_ACTIVE_AUTHENTICATION_POLICY = 255, |
||||
PROP_ASSIGNED_ACCESS_RIGHTS = 256, |
||||
PROP_AUTHENTICATION_FACTORS = 257, |
||||
PROP_AUTHENTICATION_POLICY_LIST = 258, |
||||
PROP_AUTHENTICATION_POLICY_NAMES = 259, |
||||
PROP_AUTHENTICATION_STATUS = 260, |
||||
PROP_AUTHORIZATION_MODE = 261, |
||||
PROP_BELONGS_TO = 262, |
||||
PROP_CREDENTIAL_DISABLE = 263, |
||||
PROP_CREDENTIAL_STATUS = 264, |
||||
PROP_CREDENTIALS = 265, |
||||
PROP_CREDENTIALS_IN_ZONE = 266, |
||||
PROP_DAYS_REMAINING = 267, |
||||
PROP_ENTRY_POINTS = 268, |
||||
PROP_EXIT_POINTS = 269, |
||||
PROP_EXPIRY_TIME = 270, |
||||
PROP_EXTENDED_TIME_ENABLE = 271, |
||||
PROP_FAILED_ATTEMPT_EVENTS = 272, |
||||
PROP_FAILED_ATTEMPTS = 273, |
||||
PROP_FAILED_ATTEMPTS_TIME = 274, |
||||
PROP_LAST_ACCESS_EVENT = 275, |
||||
PROP_LAST_ACCESS_POINT = 276, |
||||
PROP_LAST_CREDENTIAL_ADDED = 277, |
||||
PROP_LAST_CREDENTIAL_ADDED_TIME = 278, |
||||
PROP_LAST_CREDENTIAL_REMOVED = 279, |
||||
PROP_LAST_CREDENTIAL_REMOVED_TIME = 280, |
||||
PROP_LAST_USE_TIME = 281, |
||||
PROP_LOCKOUT = 282, |
||||
PROP_LOCKOUT_RELINQUISH_TIME = 283, |
||||
PROP_MASTER_EXEMPTION = 284, |
||||
PROP_MAX_FAILED_ATTEMPTS = 285, |
||||
PROP_MEMBERS = 286, |
||||
PROP_MUSTER_POINT = 287, |
||||
PROP_NEGATIVE_ACCESS_RULES = 288, |
||||
PROP_NUMBER_OF_AUTHENTICATION_POLICIES = 289, |
||||
PROP_OCCUPANCY_COUNT = 290, |
||||
PROP_OCCUPANCY_COUNT_ADJUST = 291, |
||||
PROP_OCCUPANCY_COUNT_ENABLE = 292, |
||||
PROP_OCCUPANCY_EXEMPTION = 293, |
||||
PROP_OCCUPANCY_LOWER_LIMIT = 294, |
||||
PROP_OCCUPANCY_LOWER_LIMIT_ENFORCED = 295, |
||||
PROP_OCCUPANCY_STATE = 296, |
||||
PROP_OCCUPANCY_UPPER_LIMIT = 297, |
||||
PROP_OCCUPANCY_UPPER_LIMIT_ENFORCED = 298, |
||||
PROP_PASSBACK_EXEMPTION = 299, |
||||
PROP_PASSBACK_MODE = 300, |
||||
PROP_PASSBACK_TIMEOUT = 301, |
||||
PROP_POSITIVE_ACCESS_RULES = 302, |
||||
PROP_REASON_FOR_DISABLE = 303, |
||||
PROP_SUPPORTED_FORMATS = 304, |
||||
PROP_SUPPORTED_FORMAT_CLASSES = 305, |
||||
PROP_THREAT_AUTHORITY = 306, |
||||
PROP_THREAT_LEVEL = 307, |
||||
PROP_TRACE_FLAG = 308, |
||||
PROP_TRANSACTION_NOTIFICATION_CLASS = 309, |
||||
PROP_USER_EXTERNAL_IDENTIFIER = 310, |
||||
PROP_USER_INFORMATION_REFERENCE = 311, |
||||
/* enumerations 312-316 are unassigned */ |
||||
PROP_USER_NAME = 317, |
||||
PROP_USER_TYPE = 318, |
||||
PROP_USES_REMAINING = 319, |
||||
PROP_ZONE_FROM = 320, |
||||
PROP_ZONE_TO = 321, |
||||
PROP_ACCESS_EVENT_TAG = 322, |
||||
PROP_GLOBAL_IDENTIFIER = 323, |
||||
/* enumerations 324-325 are unassigned */ |
||||
PROP_VERIFICATION_TIME = 326, |
||||
PROP_BASE_DEVICE_SECURITY_POLICY = 327, |
||||
PROP_DISTRIBUTION_KEY_REVISION = 328, |
||||
PROP_DO_NOT_HIDE = 329, |
||||
PROP_KEY_SETS = 330, |
||||
PROP_LAST_KEY_SERVER = 331, |
||||
PROP_NETWORK_ACCESS_SECURITY_POLICIES = 332, |
||||
PROP_PACKET_REORDER_TIME = 333, |
||||
PROP_SECURITY_PDU_TIMEOUT = 334, |
||||
PROP_SECURITY_TIME_WINDOW = 335, |
||||
PROP_SUPPORTED_SECURITY_ALGORITHM = 336, |
||||
PROP_UPDATE_KEY_SET_TIMEOUT = 337, |
||||
PROP_BACKUP_AND_RESTORE_STATE = 338, |
||||
PROP_BACKUP_PREPARATION_TIME = 339, |
||||
PROP_RESTORE_COMPLETION_TIME = 340, |
||||
PROP_RESTORE_PREPARATION_TIME = 341, |
||||
/* enumerations 342-344 are defined in Addendum 2008-w */ |
||||
PROP_BIT_MASK = 342, |
||||
PROP_BIT_TEXT = 343, |
||||
PROP_IS_UTC = 344, |
||||
PROP_GROUP_MEMBERS = 345, |
||||
PROP_GROUP_MEMBER_NAMES = 346, |
||||
PROP_MEMBER_STATUS_FLAGS = 347, |
||||
PROP_REQUESTED_UPDATE_INTERVAL = 348, |
||||
PROP_COVU_PERIOD = 349, |
||||
PROP_COVU_RECIPIENTS = 350, |
||||
PROP_EVENT_MESSAGE_TEXTS = 351, |
||||
/* enumerations 352-363 are defined in Addendum 2010-af */ |
||||
PROP_EVENT_MESSAGE_TEXTS_CONFIG = 352, |
||||
PROP_EVENT_DETECTION_ENABLE = 353, |
||||
PROP_EVENT_ALGORITHM_INHIBIT = 354, |
||||
PROP_EVENT_ALGORITHM_INHIBIT_REF = 355, |
||||
PROP_TIME_DELAY_NORMAL = 356, |
||||
PROP_RELIABILITY_EVALUATION_INHIBIT = 357, |
||||
PROP_FAULT_PARAMETERS = 358, |
||||
PROP_FAULT_TYPE = 359, |
||||
PROP_LOCAL_FORWARDING_ONLY = 360, |
||||
PROP_PROCESS_IDENTIFIER_FILTER = 361, |
||||
PROP_SUBSCRIBED_RECIPIENTS = 362, |
||||
PROP_PORT_FILTER = 363, |
||||
/* enumeration 364 is defined in Addendum 2010-ae */ |
||||
PROP_AUTHORIZATION_EXEMPTIONS = 364, |
||||
/* enumerations 365-370 are defined in Addendum 2010-aa */ |
||||
PROP_ALLOW_GROUP_DELAY_INHIBIT = 365, |
||||
PROP_CHANNEL_NUMBER = 366, |
||||
PROP_CONTROL_GROUPS = 367, |
||||
PROP_EXECUTION_DELAY = 368, |
||||
PROP_LAST_PRIORITY = 369, |
||||
PROP_WRITE_STATUS = 370, |
||||
/* enumeration 371 is defined in Addendum 2010-ao */ |
||||
PROP_PROPERTY_LIST = 371, |
||||
/* enumeration 372 is defined in Addendum 2010-ak */ |
||||
PROP_SERIAL_NUMBER = 372, |
||||
/* enumerations 373-386 are defined in Addendum 2010-i */ |
||||
PROP_BLINK_WARN_ENABLE = 373, |
||||
PROP_DEFAULT_FADE_TIME = 374, |
||||
PROP_DEFAULT_RAMP_RATE = 375, |
||||
PROP_DEFAULT_STEP_INCREMENT = 376, |
||||
PROP_EGRESS_TIME = 377, |
||||
PROP_IN_PROGRESS = 378, |
||||
PROP_INSTANTANEOUS_POWER = 379, |
||||
PROP_LIGHTING_COMMAND = 380, |
||||
PROP_LIGHTING_COMMAND_DEFAULT_PRIORITY = 381, |
||||
PROP_MAX_ACTUAL_VALUE = 382, |
||||
PROP_MIN_ACTUAL_VALUE = 383, |
||||
PROP_POWER = 384, |
||||
PROP_TRANSITION = 385, |
||||
PROP_EGRESS_ACTIVE = 386, |
||||
PROP_INTERFACE_VALUE = 387, |
||||
PROP_FAULT_HIGH_LIMIT = 388, |
||||
PROP_FAULT_LOW_LIMIT = 389, |
||||
PROP_LOW_DIFF_LIMIT = 390, |
||||
/* enumerations 391-392 are defined in Addendum 135-2012az */ |
||||
PROP_STRIKE_COUNT = 391, |
||||
PROP_TIME_OF_STRIKE_COUNT_RESET = 392, |
||||
/* enumerations 393-398 are defined in Addendum 135-2012ay */ |
||||
PROP_DEFAULT_TIMEOUT = 393, |
||||
PROP_INITIAL_TIMEOUT = 394, |
||||
PROP_LAST_STATE_CHANGE = 395, |
||||
PROP_STATE_CHANGE_VALUES = 396, |
||||
PROP_TIMER_RUNNING = 397, |
||||
PROP_TIMER_STATE = 398, |
||||
/* enumerations 399-427 are defined in Addendum 2012-ai */ |
||||
PROP_APDU_LENGTH = 399, |
||||
PROP_IP_ADDRESS = 400, |
||||
PROP_IP_DEFAULT_GATEWAY = 401, |
||||
PROP_IP_DHCP_ENABLE = 402, |
||||
PROP_IP_DHCP_LEASE_TIME = 403, |
||||
PROP_IP_DHCP_LEASE_TIME_REMAINING = 404, |
||||
PROP_IP_DHCP_SERVER = 405, |
||||
PROP_IP_DNS_SERVER = 406, |
||||
PROP_BACNET_IP_GLOBAL_ADDRESS = 407, |
||||
PROP_BACNET_IP_MODE = 408, |
||||
PROP_BACNET_IP_MULTICAST_ADDRESS = 409, |
||||
PROP_BACNET_IP_NAT_TRAVERSAL = 410, |
||||
PROP_IP_SUBNET_MASK = 411, |
||||
PROP_BACNET_IP_UDP_PORT = 412, |
||||
PROP_BBMD_ACCEPT_FD_REGISTRATIONS = 413, |
||||
PROP_BBMD_BROADCAST_DISTRIBUTION_TABLE = 414, |
||||
PROP_BBMD_FOREIGN_DEVICE_TABLE = 415, |
||||
PROP_CHANGES_PENDING = 416, |
||||
PROP_COMMAND = 417, |
||||
PROP_FD_BBMD_ADDRESS = 418, |
||||
PROP_FD_SUBSCRIPTION_LIFETIME = 419, |
||||
PROP_LINK_SPEED = 420, |
||||
PROP_LINK_SPEEDS = 421, |
||||
PROP_LINK_SPEED_AUTONEGOTIATE = 422, |
||||
PROP_MAC_ADDRESS = 423, |
||||
PROP_NETWORK_INTERFACE_NAME = 424, |
||||
PROP_NETWORK_NUMBER = 425, |
||||
PROP_NETWORK_NUMBER_QUALITY = 426, |
||||
PROP_NETWORK_TYPE = 427, |
||||
PROP_ROUTING_TABLE = 428, |
||||
PROP_VIRTUAL_MAC_ADDRESS_TABLE = 429, |
||||
|
||||
// Addendum-135-2012as |
||||
PROP_COMMAND_TIME_ARRAY = 430, |
||||
PROP_CURRENT_COMMAND_PRIORITY = 431, |
||||
PROP_LAST_COMMAND_TIME = 432, |
||||
PROP_VALUE_SOURCE = 433, |
||||
PROP_VALUE_SOURCE_ARRAY = 434, |
||||
PROP_BACNET_IPV6_MODE = 435, |
||||
PROP_IPV6_ADDRESS = 436, |
||||
PROP_IPV6_PREFIX_LENGTH = 437, |
||||
PROP_BACNET_IPV6_UDP_PORT = 438, |
||||
PROP_IPV6_DEFAULT_GATEWAY = 439, |
||||
PROP_BACNET_IPV6_MULTICAST_ADDRESS = 440, |
||||
PROP_IPV6_DNS_SERVER = 441, |
||||
PROP_IPV6_AUTO_ADDRESSING_ENABLE = 442, |
||||
PROP_IPV6_DHCP_LEASE_TIME = 443, |
||||
PROP_IPV6_DHCP_LEASE_TIME_REMAINING = 444, |
||||
PROP_IPV6_DHCP_SERVER = 445, |
||||
PROP_IPV6_ZONE_INDEX = 446, |
||||
PROP_ASSIGNED_LANDING_CALLS = 447, |
||||
PROP_CAR_ASSIGNED_DIRECTION = 448, |
||||
PROP_CAR_DOOR_COMMAND = 449, |
||||
PROP_CAR_DOOR_STATUS = 450, |
||||
PROP_CAR_DOOR_TEXT = 451, |
||||
PROP_CAR_DOOR_ZONE = 452, |
||||
PROP_CAR_DRIVE_STATUS = 453, |
||||
PROP_CAR_LOAD = 454, |
||||
PROP_CAR_LOAD_UNITS = 455, |
||||
PROP_CAR_MODE = 456, |
||||
PROP_CAR_MOVING_DIRECTION = 457, |
||||
PROP_CAR_POSITION = 458, |
||||
PROP_ELEVATOR_GROUP = 459, |
||||
PROP_ENERGY_METER = 460, |
||||
PROP_ENERGY_METER_REF = 461, |
||||
PROP_ESCALATOR_MODE = 462, |
||||
PROP_FAULT_SIGNALS = 463, |
||||
PROP_FLOOR_TEXT = 464, |
||||
PROP_GROUP_ID = 465, |
||||
/* value 466 is unassigned */ |
||||
PROP_GROUP_MODE = 467, |
||||
PROP_HIGHER_DECK = 468, |
||||
PROP_INSTALLATION_ID = 469, |
||||
PROP_LANDING_CALLS = 470, |
||||
PROP_LANDING_CALL_CONTROL = 471, |
||||
PROP_LANDING_DOOR_STATUS = 472, |
||||
PROP_LOWER_DECK = 473, |
||||
PROP_MACHINE_ROOM_ID = 474, |
||||
PROP_MAKING_CAR_CALL = 475, |
||||
PROP_NEXT_STOPPING_FLOOR = 476, |
||||
PROP_OPERATION_DIRECTION = 477, |
||||
PROP_PASSENGER_ALARM = 478, |
||||
PROP_POWER_MODE = 479, |
||||
PROP_REGISTERED_CAR_CALL = 480, |
||||
PROP_ACTIVE_COV_MULTIPLE_SUBSCRIPTIONS = 481, |
||||
PROP_PROTOCOL_LEVEL = 482, |
||||
PROP_REFERENCE_PORT = 483, |
||||
PROP_DEPLOYED_PROFILE_LOCATION = 484, |
||||
PROP_PROFILE_LOCATION = 485, |
||||
PROP_TAGS = 486, |
||||
PROP_SUBORDINATE_NODE_TYPES = 487, |
||||
PROP_SUBORDINATE_TAGS = 488, |
||||
PROP_SUBORDINATE_RELATIONSHIPS = 489, |
||||
PROP_DEFAULT_SUBORDINATE_RELATIONSHIP = 490, |
||||
PROP_REPRESENTS = 491, |
||||
PROP_DEFAULT_PRESENT_VALUE = 492, |
||||
PROP_PRESENT_STAGE = 493, |
||||
PROP_STAGES = 494, |
||||
PROP_STAGE_NAMES = 495, |
||||
PROP_TARGET_REFERENCES = 496, |
||||
PROP_AUDIT_SOURCE_LEVEL = 497, |
||||
PROP_AUDIT_LEVEL = 498, |
||||
PROP_AUDIT_NOTIFICATION_RECIPIENT = 499, |
||||
PROP_AUDIT_PRIORITY_FILTER = 500, |
||||
PROP_AUDITABLE_OPERATIONS = 501, |
||||
PROP_DELETE_ON_FORWARD = 502, |
||||
PROP_MAXIMUM_SEND_DELAY = 503, |
||||
PROP_MONITORED_OBJECTS = 504, |
||||
PROP_SEND_NOW = 505, |
||||
PROP_FLOOR_NUMBER = 506, |
||||
PROP_DEVICE_UUID = 507, |
||||
/* enumerations 508-511 are defined in Addendum 2020cc */ |
||||
PROP_ADDITIONAL_REFERENCE_PORTS = 508, |
||||
PROP_CERTIFICATE_SIGNING_REQUEST_FILE = 509, |
||||
PROP_COMMAND_VALIDATION_RESULT = 510, |
||||
PROP_ISSUER_CERTIFICATE_FILES = 511, |
||||
/* The special property identifiers all, optional, and required */ |
||||
/* are reserved for use in the ReadPropertyConditional and */ |
||||
/* ReadPropertyMultiple services or services not defined in this standard. |
||||
*/ |
||||
/* Enumerated values 0-511 are reserved for definition by ASHRAE. */ |
||||
/* Enumerated values 512-4194303 may be used by others subject to the */ |
||||
/* procedures and constraints described in Clause 23. */ |
||||
PROP_PROPRIETARY_RANGE_MIN = 512, |
||||
PROP_PROPRIETARY_RANGE_MAX = 4194303, |
||||
/* enumerations 4194304-4194327 are defined in Addendum 2020cc */ |
||||
PROP_MAX_BVLC_LENGTH_ACCEPTED = 4194304, |
||||
PROP_MAX_NPDU_LENGTH_ACCEPTED = 4194305, |
||||
PROP_OPERATIONAL_CERTIFICATE_FILE = 4194305, |
||||
PROP_CURRENT_HEALTH = 4194307, |
||||
PROP_SC_CONNECT_WAIT_TIMEOUT = 4194308, |
||||
PROP_SC_DIRECT_CONNECT_ACCEPT_ENABLE = 4194309, |
||||
PROP_SC_DIRECT_CONNECT_ACCEPT_URIS = 4194310, |
||||
PROP_SC_DIRECT_CONNECT_BINDING = 4194311, |
||||
PROP_SC_DIRECT_CONNECT_CONNECTION_STATUS = 4194312, |
||||
PROP_SC_DIRECT_CONNECT_INITIATE_ENABLE = 4194313, |
||||
PROP_SC_DISCONNECT_WAIT_TIMEOUT = 4194314, |
||||
PROP_SC_FAILED_CONNECTION_REQUESTS = 4194315, |
||||
PROP_SC_FAILOVER_HUB_CONNECTION_STATUS = 4194316, |
||||
PROP_SC_FAILOVER_HUB_URI = 4194317, |
||||
PROP_SC_HUB_CONNECTOR_STATE = 4194318, |
||||
PROP_SC_HUB_FUNCTION_ACCEPT_URIS = 4194319, |
||||
PROP_SC_HUB_FUNCTION_BINDING = 4194320, |
||||
PROP_SC_HUB_FUNCTION_CONNECTION_STATUS = 4194321, |
||||
PROP_SC_HUB_FUNCTION_ENABLE = 4194322, |
||||
PROP_SC_HEARTBEAT_TIMEOUT = 4194323, |
||||
PROP_SC_PRIMARY_HUB_CONNECTION_STATUS = 4194324, |
||||
PROP_SC_PRIMARY_HUB_URI = 4194325, |
||||
PROP_SC_MAXIMUM_RECONNECT_TIME = 4194326, |
||||
PROP_SC_MINIMUM_RECONNECT_TIME = 4194327, |
||||
/* enumerations 4194328-4194332 are defined in Addendum 2020ca */ |
||||
PROP_COLOR_OVERRIDE = 4194328, |
||||
PROP_COLOR_REFERENCE = 4194329, |
||||
PROP_DEFAULT_COLOR = 4194330, |
||||
PROP_DEFAULT_COLOR_TEMPERATURE = 4194331, |
||||
PROP_OVERRIDE_COLOR_REFERENCE = 4194332, |
||||
PROP_COLOR_COMMAND = 4194334, |
||||
PROP_HIGH_END_TRIM = 4194335, |
||||
PROP_LOW_END_TRIM = 4194336, |
||||
PROP_TRIM_FADE_TIME = 4194337, |
||||
|
||||
/* The special property identifiers all, optional, and required */ |
||||
/* are reserved for use in the ReadPropertyConditional and */ |
||||
/* ReadPropertyMultiple services or services not defined in this standard. */ |
||||
/* Enumerated values 0-511 are reserved for definition by ASHRAE. */ |
||||
/* Enumerated values 512-4194303 may be used by others subject to the */ |
||||
/* procedures and constraints described in Clause 23. */ |
||||
/* Enumerated values 4194303-16777215 are reserved |
||||
for definition by ASHRAE. */ |
||||
/* do the max range inside of enum so that |
||||
compilers will allocate adequate sized datatype for enum |
||||
which is used to store decoding */ |
||||
MAX_BACNET_PROPERTY_ID = 16777215 |
||||
} |
@ -1,23 +0,0 @@
@@ -1,23 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public struct BacnetPropertyReference |
||||
{ |
||||
public uint propertyIdentifier; |
||||
public uint propertyArrayIndex; /* optional */ |
||||
|
||||
public BacnetPropertyReference(uint id, uint arrayIndex) |
||||
{ |
||||
propertyIdentifier = id; |
||||
propertyArrayIndex = arrayIndex; |
||||
} |
||||
|
||||
public BacnetPropertyIds GetPropertyId() |
||||
{ |
||||
return (BacnetPropertyIds)propertyIdentifier; |
||||
} |
||||
|
||||
public override string ToString() |
||||
{ |
||||
return $"{GetPropertyId()}"; |
||||
} |
||||
} |
@ -1,48 +0,0 @@
@@ -1,48 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public struct BacnetPropertyState |
||||
{ |
||||
public enum BacnetPropertyStateTypes |
||||
{ |
||||
BOOLEAN_VALUE, |
||||
BINARY_VALUE, |
||||
EVENT_TYPE, |
||||
POLARITY, |
||||
PROGRAM_CHANGE, |
||||
PROGRAM_STATE, |
||||
REASON_FOR_HALT, |
||||
RELIABILITY, |
||||
STATE, |
||||
SYSTEM_STATUS, |
||||
UNITS, |
||||
UNSIGNED_VALUE, |
||||
LIFE_SAFETY_MODE, |
||||
LIFE_SAFETY_STATE |
||||
} |
||||
|
||||
public struct State |
||||
{ |
||||
public bool boolean_value; |
||||
public BacnetBinaryPv binaryValue; |
||||
public BacnetEventTypes eventType; |
||||
public BacnetPolarity polarity; |
||||
public BacnetProgramRequest programChange; |
||||
public BacnetProgramState programState; |
||||
public BacnetProgramError programError; |
||||
public BacnetReliability reliability; |
||||
public BacnetEventStates state; |
||||
public BacnetDeviceStatus systemStatus; |
||||
public BacnetUnitsId units; |
||||
public uint unsignedValue; |
||||
public BacnetLifeSafetyModes lifeSafetyMode; |
||||
public BacnetLifeSafetyStates lifeSafetyState; |
||||
} |
||||
|
||||
public BacnetPropertyStateTypes tag; |
||||
public State state; |
||||
|
||||
public override string ToString() |
||||
{ |
||||
return $"{tag}:{state}"; |
||||
} |
||||
} |
@ -1,13 +0,0 @@
@@ -1,13 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public struct BacnetPropertyValue |
||||
{ |
||||
public BacnetPropertyReference property; |
||||
public IList<BacnetValue> value; |
||||
public byte priority; |
||||
|
||||
public override string ToString() |
||||
{ |
||||
return property.ToString(); |
||||
} |
||||
} |
@ -1,9 +0,0 @@
@@ -1,9 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public enum BacnetPtpDisconnectReasons : byte |
||||
{ |
||||
PTP_DISCONNECT_NO_MORE_DATA = 0, |
||||
PTP_DISCONNECT_PREEMPTED = 1, |
||||
PTP_DISCONNECT_INVALID_PASSWORD = 2, |
||||
PTP_DISCONNECT_OTHER = 3, |
||||
} |
@ -1,24 +0,0 @@
@@ -1,24 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public enum BacnetPtpFrameTypes : byte |
||||
{ |
||||
FRAME_TYPE_HEARTBEAT_XOFF = 0, |
||||
FRAME_TYPE_HEARTBEAT_XON = 1, |
||||
FRAME_TYPE_DATA0 = 2, |
||||
FRAME_TYPE_DATA1 = 3, |
||||
FRAME_TYPE_DATA_ACK0_XOFF = 4, |
||||
FRAME_TYPE_DATA_ACK1_XOFF = 5, |
||||
FRAME_TYPE_DATA_ACK0_XON = 6, |
||||
FRAME_TYPE_DATA_ACK1_XON = 7, |
||||
FRAME_TYPE_DATA_NAK0_XOFF = 8, |
||||
FRAME_TYPE_DATA_NAK1_XOFF = 9, |
||||
FRAME_TYPE_DATA_NAK0_XON = 0x0A, |
||||
FRAME_TYPE_DATA_NAK1_XON = 0x0B, |
||||
FRAME_TYPE_CONNECT_REQUEST = 0x0C, |
||||
FRAME_TYPE_CONNECT_RESPONSE = 0x0D, |
||||
FRAME_TYPE_DISCONNECT_REQUEST = 0x0E, |
||||
FRAME_TYPE_DISCONNECT_RESPONSE = 0x0F, |
||||
FRAME_TYPE_TEST_REQUEST = 0x14, |
||||
FRAME_TYPE_TEST_RESPONSE = 0x15, |
||||
FRAME_TYPE_GREETING = 0xFF //special invention |
||||
} |
@ -1,13 +0,0 @@
@@ -1,13 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public struct BacnetReadAccessResult |
||||
{ |
||||
public BacnetObjectId objectIdentifier; |
||||
public IList<BacnetPropertyValue> values; |
||||
|
||||
public BacnetReadAccessResult(BacnetObjectId objectIdentifier, IList<BacnetPropertyValue> values) |
||||
{ |
||||
this.objectIdentifier = objectIdentifier; |
||||
this.values = values; |
||||
} |
||||
} |
@ -1,40 +0,0 @@
@@ -1,40 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public struct BacnetReadAccessSpecification |
||||
{ |
||||
public BacnetObjectId objectIdentifier; |
||||
public IList<BacnetPropertyReference> propertyReferences; |
||||
|
||||
public BacnetReadAccessSpecification(BacnetObjectId objectIdentifier, IList<BacnetPropertyReference> propertyReferences) |
||||
{ |
||||
this.objectIdentifier = objectIdentifier; |
||||
this.propertyReferences = propertyReferences; |
||||
} |
||||
|
||||
public static object Parse(string value) |
||||
{ |
||||
var ret = new BacnetReadAccessSpecification(); |
||||
if (string.IsNullOrEmpty(value)) return ret; |
||||
var tmp = value.Split(':'); |
||||
if (tmp.Length < 2) return ret; |
||||
ret.objectIdentifier.type = (BacnetObjectTypes)Enum.Parse(typeof(BacnetObjectTypes), tmp[0]); |
||||
ret.objectIdentifier.instance = uint.Parse(tmp[1]); |
||||
var refs = new List<BacnetPropertyReference>(); |
||||
for (var i = 2; i < tmp.Length; i++) |
||||
{ |
||||
refs.Add(new BacnetPropertyReference |
||||
{ |
||||
propertyArrayIndex = ASN1.BACNET_ARRAY_ALL, |
||||
propertyIdentifier = (uint)(BacnetPropertyIds)Enum.Parse(typeof(BacnetPropertyIds), tmp[i]) |
||||
}); |
||||
} |
||||
ret.propertyReferences = refs; |
||||
return ret; |
||||
} |
||||
|
||||
public override string ToString() |
||||
{ |
||||
return propertyReferences.Aggregate(objectIdentifier.ToString(), (current, r) => |
||||
$"{current}:{(BacnetPropertyIds)r.propertyIdentifier}"); |
||||
} |
||||
} |
@ -1,9 +0,0 @@
@@ -1,9 +0,0 @@
|
||||
namespace System.IO.BACnet.Serialize; |
||||
|
||||
public enum BacnetReadRangeRequestTypes |
||||
{ |
||||
RR_BY_POSITION = 1, |
||||
RR_BY_SEQUENCE = 2, |
||||
RR_BY_TIME = 4, |
||||
RR_READ_ALL = 8 |
||||
} |
@ -1,14 +0,0 @@
@@ -1,14 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public enum BacnetReinitializedStates |
||||
{ |
||||
BACNET_REINIT_COLDSTART = 0, |
||||
BACNET_REINIT_WARMSTART = 1, |
||||
BACNET_REINIT_STARTBACKUP = 2, |
||||
BACNET_REINIT_ENDBACKUP = 3, |
||||
BACNET_REINIT_STARTRESTORE = 4, |
||||
BACNET_REINIT_ENDRESTORE = 5, |
||||
BACNET_REINIT_ABORTRESTORE = 6, |
||||
BACNET_REINIT_ACTIVATE_CHANGES = 7, |
||||
BACNET_REINIT_IDLE = 255 |
||||
} |
@ -1,84 +0,0 @@
@@ -1,84 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
/// <summary> |
||||
/// Possible reason for rejecting the PDU. |
||||
/// </summary> |
||||
/// <remarks> |
||||
/// Enumerated values 0-63 are reserved for definition by ASHRAE. |
||||
/// Enumerated values 64-255 may be used by others. |
||||
/// </remarks> |
||||
public enum BacnetRejectReason : byte |
||||
{ |
||||
/// <summary> |
||||
/// Generated in response to a confirmed request APDU that contains a syntax error |
||||
/// for which an error code has not been explicitly defined. |
||||
/// </summary> |
||||
OTHER = 0, |
||||
|
||||
/// <summary> |
||||
/// A buffer capacity has been exceeded. |
||||
/// </summary> |
||||
BUFFER_OVERFLOW = 1, |
||||
|
||||
/// <summary> |
||||
/// Generated in response to a confirmed request APDU that omits a conditional |
||||
/// service argument that should be present or contains a conditional service |
||||
/// argument that should not be present. This condition could also elicit |
||||
/// a Reject PDU with a Reject Reason of <see cref="INVALID_TAG"/>. |
||||
/// </summary> |
||||
INCONSISTENT_PARAMETERS = 2, |
||||
|
||||
/// <summary> |
||||
/// Generated in response to a confirmed request APDU in which the encoding |
||||
/// of one or more of the service parameters does not follow the correct |
||||
/// type specification. This condition could also elicit a Reject PDU |
||||
/// with a Reject Reason of <see cref="INVALID_TAG"/>. |
||||
/// </summary> |
||||
INVALID_PARAMETER_DATA_TYPE = 3, |
||||
|
||||
/// <summary> |
||||
/// While parsing a message, an invalid tag was encountered. Since an invalid tag |
||||
/// could confuse the parsing logic, any of the following Reject Reasons may also |
||||
/// be generated in response to a confirmed request containing an invalid tag: |
||||
/// <list type="bullet"> |
||||
/// <item><description><see cref="INCONSISTENT_PARAMETERS"/></description></item> |
||||
/// <item><description><see cref="INVALID_PARAMETER_DATA_TYPE"/></description></item> |
||||
/// <item><description><see cref="MISSING_REQUIRED_PARAMETER"/></description></item> |
||||
/// <item><description><see cref="TOO_MANY_ARGUMENTS"/></description></item> |
||||
/// </list> |
||||
/// </summary> |
||||
INVALID_TAG = 4, |
||||
|
||||
/// <summary> |
||||
/// Generated in response to a confirmed request APDU that is missing at least one |
||||
/// mandatory service argument. This condition could also elicit a Reject PDU with |
||||
/// a Reject Reason of <see cref="INVALID_TAG"/>. |
||||
/// </summary> |
||||
MISSING_REQUIRED_PARAMETER = 5, |
||||
|
||||
/// <summary> |
||||
/// Generated in response to a confirmed request APDU that conveys a parameter |
||||
/// whose value is outside the range defined for this service. |
||||
/// </summary> |
||||
PARAMETER_OUT_OF_RANGE = 6, |
||||
|
||||
/// <summary> |
||||
/// Generated in response to a confirmed request APDU in which the total number |
||||
/// of service arguments is greater than specified for the service. This condition |
||||
/// could also elicit a Reject PDU with a Reject Reason of <see cref="INVALID_TAG"/>. |
||||
/// </summary> |
||||
TOO_MANY_ARGUMENTS = 7, |
||||
|
||||
/// <summary> |
||||
/// Generated in response to a confirmed request APDU in which one or more of |
||||
/// the service parameters is decoded as an enumeration that is not defined by |
||||
/// the type specification of this parameter. |
||||
/// </summary> |
||||
UNDEFINED_ENUMERATION = 8, |
||||
|
||||
/// <summary> |
||||
/// Generated in response to a confirmed request APDU in which the Service Choice |
||||
/// field specifies an unknown or unsupported service |
||||
/// </summary> |
||||
RECOGNIZED_SERVICE = 9 |
||||
} |
@ -1,27 +0,0 @@
@@ -1,27 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public enum BacnetReliability : uint |
||||
{ |
||||
RELIABILITY_NO_FAULT_DETECTED = 0, |
||||
RELIABILITY_NO_SENSOR = 1, |
||||
RELIABILITY_OVER_RANGE = 2, |
||||
RELIABILITY_UNDER_RANGE = 3, |
||||
RELIABILITY_OPEN_LOOP = 4, |
||||
RELIABILITY_SHORTED_LOOP = 5, |
||||
RELIABILITY_NO_OUTPUT = 6, |
||||
RELIABILITY_UNRELIABLE_OTHER = 7, |
||||
RELIABILITY_PROCESS_ERROR = 8, |
||||
RELIABILITY_MULTI_STATE_FAULT = 9, |
||||
RELIABILITY_CONFIGURATION_ERROR = 10, |
||||
RELIABILITY_MEMBER_FAULT = 11, |
||||
RELIABILITY_COMMUNICATION_FAILURE = 12, |
||||
RELIABILITY_TRIPPED = 13, |
||||
/* Enumerated values 0-63 are reserved for definition by ASHRAE. */ |
||||
/* Enumerated values 64-65535 may be used by others subject to */ |
||||
/* the procedures and constraints described in Clause 23. */ |
||||
/* do the max range inside of enum so that |
||||
compilers will allocate adequate sized datatype for enum |
||||
which is used to store decoding */ |
||||
RELIABILITY_PROPRIETARY_MIN = 64, |
||||
RELIABILITY_PROPRIETARY_MAX = 65535 |
||||
} |
@ -1,14 +0,0 @@
@@ -1,14 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
// From Loren Van Spronsen csharp-bacnet |
||||
public enum BacnetRestartReason |
||||
{ |
||||
UNKNOWN = 0, |
||||
COLD_START = 1, |
||||
WARM_START = 2, |
||||
DETECTED_POWER_LOST = 3, |
||||
DETECTED_POWER_OFF = 4, |
||||
HARDWARE_WATCHDOG = 5, |
||||
SOFTWARE_WATCHDOG = 6, |
||||
SUSPENDED = 7 |
||||
} |
@ -1,10 +0,0 @@
@@ -1,10 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
[Flags] |
||||
public enum BacnetResultFlags |
||||
{ |
||||
NONE = 0, |
||||
FIRST_ITEM = 1, |
||||
LAST_ITEM = 2, |
||||
MORE_ITEMS = 4, |
||||
} |
@ -1,9 +0,0 @@
@@ -1,9 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public enum BacnetSegmentations |
||||
{ |
||||
SEGMENTATION_BOTH = 0, |
||||
SEGMENTATION_TRANSMIT = 1, |
||||
SEGMENTATION_RECEIVE = 2, |
||||
SEGMENTATION_NONE = 3, |
||||
} |
@ -1,62 +0,0 @@
@@ -1,62 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public enum BacnetServicesSupported |
||||
{ |
||||
/* Alarm and Event Services */ |
||||
SERVICE_SUPPORTED_ACKNOWLEDGE_ALARM = 0, |
||||
SERVICE_SUPPORTED_CONFIRMED_COV_NOTIFICATION = 1, |
||||
SERVICE_SUPPORTED_CONFIRMED_EVENT_NOTIFICATION = 2, |
||||
SERVICE_SUPPORTED_GET_ALARM_SUMMARY = 3, |
||||
SERVICE_SUPPORTED_GET_ENROLLMENT_SUMMARY = 4, |
||||
SERVICE_SUPPORTED_GET_EVENT_INFORMATION = 39, |
||||
SERVICE_SUPPORTED_SUBSCRIBE_COV = 5, |
||||
SERVICE_SUPPORTED_SUBSCRIBE_COV_PROPERTY = 38, |
||||
SERVICE_SUPPORTED_LIFE_SAFETY_OPERATION = 37, |
||||
SERVICE_SUPPORTED_CONFIRMED_AUDIT_NOTIFICATION = 44, |
||||
SERVICE_SUPPORTED_AUDIT_LOG_QUERY = 45, |
||||
/* File Access Services */ |
||||
SERVICE_SUPPORTED_ATOMIC_READ_FILE = 6, |
||||
SERVICE_SUPPORTED_ATOMIC_WRITE_FILE = 7, |
||||
/* Object Access Services */ |
||||
SERVICE_SUPPORTED_ADD_LIST_ELEMENT = 8, |
||||
SERVICE_SUPPORTED_REMOVE_LIST_ELEMENT = 9, |
||||
SERVICE_SUPPORTED_CREATE_OBJECT = 10, |
||||
SERVICE_SUPPORTED_DELETE_OBJECT = 11, |
||||
SERVICE_SUPPORTED_READ_PROPERTY = 12, |
||||
SERVICE_SUPPORTED_READ_PROP_CONDITIONAL = 13, |
||||
SERVICE_SUPPORTED_READ_PROP_MULTIPLE = 14, |
||||
SERVICE_SUPPORTED_READ_RANGE = 35, |
||||
SERVICE_SUPPORTED_WRITE_PROPERTY = 15, |
||||
SERVICE_SUPPORTED_WRITE_PROP_MULTIPLE = 16, |
||||
SERVICE_SUPPORTED_WRITE_GROUP = 40, |
||||
/* Remote Device Management Services */ |
||||
SERVICE_SUPPORTED_DEVICE_COMMUNICATION_CONTROL = 17, |
||||
SERVICE_SUPPORTED_PRIVATE_TRANSFER = 18, |
||||
SERVICE_SUPPORTED_TEXT_MESSAGE = 19, |
||||
SERVICE_SUPPORTED_REINITIALIZE_DEVICE = 20, |
||||
SERVICE_SUPPORTED_WHO_AM_I = 47, |
||||
SERVICE_SUPPORTED_YOU_ARE = 48, |
||||
/* Virtual Terminal Services */ |
||||
SERVICE_SUPPORTED_VT_OPEN = 21, |
||||
SERVICE_SUPPORTED_VT_CLOSE = 22, |
||||
SERVICE_SUPPORTED_VT_DATA = 23, |
||||
/* Security Services */ |
||||
SERVICE_SUPPORTED_AUTHENTICATE = 24, |
||||
SERVICE_SUPPORTED_REQUEST_KEY = 25, |
||||
/* Unconfirmed Services */ |
||||
SERVICE_SUPPORTED_I_AM = 26, |
||||
SERVICE_SUPPORTED_I_HAVE = 27, |
||||
SERVICE_SUPPORTED_UNCONFIRMED_COV_NOTIFICATION = 28, |
||||
SERVICE_SUPPORTED_UNCONFIRMED_EVENT_NOTIFICATION = 29, |
||||
SERVICE_SUPPORTED_UNCONFIRMED_PRIVATE_TRANSFER = 30, |
||||
SERVICE_SUPPORTED_UNCONFIRMED_TEXT_MESSAGE = 31, |
||||
SERVICE_SUPPORTED_TIME_SYNCHRONIZATION = 32, |
||||
SERVICE_SUPPORTED_UTC_TIME_SYNCHRONIZATION = 36, |
||||
SERVICE_SUPPORTED_WHO_HAS = 33, |
||||
SERVICE_SUPPORTED_WHO_IS = 34, |
||||
SERVICE_SUPPORTED_UNCONFIRMED_AUDIT_NOTIFICATION = 46, |
||||
/* Other services to be added as they are defined. */ |
||||
/* All values in this production are reserved */ |
||||
/* for definition by ASHRAE. */ |
||||
MAX_BACNET_SERVICES_SUPPORTED = 47 |
||||
} |
@ -1,10 +0,0 @@
@@ -1,10 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
[Flags] |
||||
public enum BacnetStatusFlags |
||||
{ |
||||
STATUS_FLAG_IN_ALARM = 1, |
||||
STATUS_FLAG_FAULT = 2, |
||||
STATUS_FLAG_OVERRIDDEN = 4, |
||||
STATUS_FLAG_OUT_OF_SERVICE = 8 |
||||
} |
@ -1,9 +0,0 @@
@@ -1,9 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public enum BacnetTimestampTags |
||||
{ |
||||
TIME_STAMP_NONE = -1, |
||||
TIME_STAMP_TIME = 0, |
||||
TIME_STAMP_SEQUENCE = 1, |
||||
TIME_STAMP_DATETIME = 2 |
||||
} |
@ -1,18 +0,0 @@
@@ -1,18 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public enum BacnetTrendLogValueType : byte |
||||
{ |
||||
// Copyright (C) 2009 Peter Mc Shane in Steve Karg Stack, trendlog.h |
||||
// Thank's to it's encoding sample, very usefull for this decoding work |
||||
TL_TYPE_STATUS = 0, |
||||
TL_TYPE_BOOL = 1, |
||||
TL_TYPE_REAL = 2, |
||||
TL_TYPE_ENUM = 3, |
||||
TL_TYPE_UNSIGN = 4, |
||||
TL_TYPE_SIGN = 5, |
||||
TL_TYPE_BITS = 6, |
||||
TL_TYPE_NULL = 7, |
||||
TL_TYPE_ERROR = 8, |
||||
TL_TYPE_DELTA = 9, |
||||
TL_TYPE_ANY = 10 |
||||
} |
@ -1,30 +0,0 @@
@@ -1,30 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public enum BacnetUnconfirmedServices : byte |
||||
{ |
||||
SERVICE_UNCONFIRMED_I_AM = 0, |
||||
SERVICE_UNCONFIRMED_I_HAVE = 1, |
||||
SERVICE_UNCONFIRMED_COV_NOTIFICATION = 2, |
||||
SERVICE_UNCONFIRMED_EVENT_NOTIFICATION = 3, |
||||
SERVICE_UNCONFIRMED_PRIVATE_TRANSFER = 4, |
||||
SERVICE_UNCONFIRMED_TEXT_MESSAGE = 5, |
||||
SERVICE_UNCONFIRMED_TIME_SYNCHRONIZATION = 6, |
||||
SERVICE_UNCONFIRMED_WHO_HAS = 7, |
||||
SERVICE_UNCONFIRMED_WHO_IS = 8, |
||||
SERVICE_UNCONFIRMED_UTC_TIME_SYNCHRONIZATION = 9, |
||||
/* addendum 2010-aa */ |
||||
SERVICE_UNCONFIRMED_WRITE_GROUP = 10, |
||||
/* addendum 2012-aq */ |
||||
SERVICE_UNCONFIRMED_COV_NOTIFICATION_MULTIPLE = 11, |
||||
/* addendum 2016-bi */ |
||||
SERVICE_UNCONFIRMED_AUDIT_NOTIFICATION = 12, |
||||
/* addendum 2016-bz */ |
||||
SERVICE_UNCONFIRMED_WHO_AM_I = 13, |
||||
SERVICE_UNCONFIRMED_YOU_ARE = 14, |
||||
/* Other services to be added as they are defined. */ |
||||
/* All choice values in this production are reserved */ |
||||
/* for definition by ASHRAE. */ |
||||
/* Proprietary extensions are made by using the */ |
||||
/* UnconfirmedPrivateTransfer service. See Clause 23. */ |
||||
MAX_BACNET_UNCONFIRMED_SERVICE = 15 |
||||
}; |
@ -1,311 +0,0 @@
@@ -1,311 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
// Add FC : from Karg's Stack |
||||
public enum BacnetUnitsId |
||||
{ |
||||
UNITS_METERS_PER_SECOND_PER_SECOND = 166, |
||||
/* Area */ |
||||
UNITS_SQUARE_METERS = 0, |
||||
UNITS_SQUARE_CENTIMETERS = 116, |
||||
UNITS_SQUARE_FEET = 1, |
||||
UNITS_SQUARE_INCHES = 115, |
||||
/* Currency */ |
||||
UNITS_CURRENCY1 = 105, |
||||
UNITS_CURRENCY2 = 106, |
||||
UNITS_CURRENCY3 = 107, |
||||
UNITS_CURRENCY4 = 108, |
||||
UNITS_CURRENCY5 = 109, |
||||
UNITS_CURRENCY6 = 110, |
||||
UNITS_CURRENCY7 = 111, |
||||
UNITS_CURRENCY8 = 112, |
||||
UNITS_CURRENCY9 = 113, |
||||
UNITS_CURRENCY10 = 114, |
||||
/* Electrical */ |
||||
UNITS_MILLIAMPERES = 2, |
||||
UNITS_AMPERES = 3, |
||||
UNITS_AMPERES_PER_METER = 167, |
||||
UNITS_AMPERES_PER_SQUARE_METER = 168, |
||||
UNITS_AMPERE_SQUARE_METERS = 169, |
||||
UNITS_DECIBELS = 199, |
||||
UNITS_DECIBELS_MILLIVOLT = 200, |
||||
UNITS_DECIBELS_VOLT = 201, |
||||
UNITS_FARADS = 170, |
||||
UNITS_HENRYS = 171, |
||||
UNITS_OHMS = 4, |
||||
UNITS_OHM_METERS = 172, |
||||
UNITS_MILLIOHMS = 145, |
||||
UNITS_KILOHMS = 122, |
||||
UNITS_MEGOHMS = 123, |
||||
UNITS_MICROSIEMENS = 190, |
||||
UNITS_MILLISIEMENS = 202, |
||||
UNITS_SIEMENS = 173, /* 1 mho equals 1 siemens */ |
||||
UNITS_SIEMENS_PER_METER = 174, |
||||
UNITS_TESLAS = 175, |
||||
UNITS_VOLTS = 5, |
||||
UNITS_MILLIVOLTS = 124, |
||||
UNITS_KILOVOLTS = 6, |
||||
UNITS_MEGAVOLTS = 7, |
||||
UNITS_VOLT_AMPERES = 8, |
||||
UNITS_KILOVOLT_AMPERES = 9, |
||||
UNITS_MEGAVOLT_AMPERES = 10, |
||||
UNITS_VOLT_AMPERES_REACTIVE = 11, |
||||
UNITS_KILOVOLT_AMPERES_REACTIVE = 12, |
||||
UNITS_MEGAVOLT_AMPERES_REACTIVE = 13, |
||||
UNITS_VOLTS_PER_DEGREE_KELVIN = 176, |
||||
UNITS_VOLTS_PER_METER = 177, |
||||
UNITS_DEGREES_PHASE = 14, |
||||
UNITS_POWER_FACTOR = 15, |
||||
UNITS_WEBERS = 178, |
||||
/* Energy */ |
||||
UNITS_JOULES = 16, |
||||
UNITS_KILOJOULES = 17, |
||||
UNITS_KILOJOULES_PER_KILOGRAM = 125, |
||||
UNITS_MEGAJOULES = 126, |
||||
UNITS_WATT_HOURS = 18, |
||||
UNITS_KILOWATT_HOURS = 19, |
||||
UNITS_MEGAWATT_HOURS = 146, |
||||
UNITS_WATT_HOURS_REACTIVE = 203, |
||||
UNITS_KILOWATT_HOURS_REACTIVE = 204, |
||||
UNITS_MEGAWATT_HOURS_REACTIVE = 205, |
||||
UNITS_BTUS = 20, |
||||
UNITS_KILO_BTUS = 147, |
||||
UNITS_MEGA_BTUS = 148, |
||||
UNITS_THERMS = 21, |
||||
UNITS_TON_HOURS = 22, |
||||
/* Enthalpy */ |
||||
UNITS_JOULES_PER_KILOGRAM_DRY_AIR = 23, |
||||
UNITS_KILOJOULES_PER_KILOGRAM_DRY_AIR = 149, |
||||
UNITS_MEGAJOULES_PER_KILOGRAM_DRY_AIR = 150, |
||||
UNITS_BTUS_PER_POUND_DRY_AIR = 24, |
||||
UNITS_BTUS_PER_POUND = 117, |
||||
/* Entropy */ |
||||
UNITS_JOULES_PER_DEGREE_KELVIN = 127, |
||||
UNITS_KILOJOULES_PER_DEGREE_KELVIN = 151, |
||||
UNITS_MEGAJOULES_PER_DEGREE_KELVIN = 152, |
||||
UNITS_JOULES_PER_KILOGRAM_DEGREE_KELVIN = 128, |
||||
/* Force */ |
||||
UNITS_NEWTON = 153, |
||||
/* Frequency */ |
||||
UNITS_CYCLES_PER_HOUR = 25, |
||||
UNITS_CYCLES_PER_MINUTE = 26, |
||||
UNITS_HERTZ = 27, |
||||
UNITS_KILOHERTZ = 129, |
||||
UNITS_MEGAHERTZ = 130, |
||||
UNITS_PER_HOUR = 131, |
||||
/* Humidity */ |
||||
UNITS_GRAMS_OF_WATER_PER_KILOGRAM_DRY_AIR = 28, |
||||
UNITS_PERCENT_RELATIVE_HUMIDITY = 29, |
||||
/* Length */ |
||||
UNITS_MICROMETERS = 194, |
||||
UNITS_MILLIMETERS = 30, |
||||
UNITS_CENTIMETERS = 118, |
||||
UNITS_KILOMETERS = 193, |
||||
UNITS_METERS = 31, |
||||
UNITS_INCHES = 32, |
||||
UNITS_FEET = 33, |
||||
/* Light */ |
||||
UNITS_CANDELAS = 179, |
||||
UNITS_CANDELAS_PER_SQUARE_METER = 180, |
||||
UNITS_WATTS_PER_SQUARE_FOOT = 34, |
||||
UNITS_WATTS_PER_SQUARE_METER = 35, |
||||
UNITS_LUMENS = 36, |
||||
UNITS_LUXES = 37, |
||||
UNITS_FOOT_CANDLES = 38, |
||||
/* Mass */ |
||||
UNITS_MILLIGRAMS = 196, |
||||
UNITS_GRAMS = 195, |
||||
UNITS_KILOGRAMS = 39, |
||||
UNITS_POUNDS_MASS = 40, |
||||
UNITS_TONS = 41, |
||||
/* Mass Flow */ |
||||
UNITS_GRAMS_PER_SECOND = 154, |
||||
UNITS_GRAMS_PER_MINUTE = 155, |
||||
UNITS_KILOGRAMS_PER_SECOND = 42, |
||||
UNITS_KILOGRAMS_PER_MINUTE = 43, |
||||
UNITS_KILOGRAMS_PER_HOUR = 44, |
||||
UNITS_POUNDS_MASS_PER_SECOND = 119, |
||||
UNITS_POUNDS_MASS_PER_MINUTE = 45, |
||||
UNITS_POUNDS_MASS_PER_HOUR = 46, |
||||
UNITS_TONS_PER_HOUR = 156, |
||||
/* Power */ |
||||
UNITS_MILLIWATTS = 132, |
||||
UNITS_WATTS = 47, |
||||
UNITS_KILOWATTS = 48, |
||||
UNITS_MEGAWATTS = 49, |
||||
UNITS_BTUS_PER_HOUR = 50, |
||||
UNITS_KILO_BTUS_PER_HOUR = 157, |
||||
UNITS_HORSEPOWER = 51, |
||||
UNITS_TONS_REFRIGERATION = 52, |
||||
/* Pressure */ |
||||
UNITS_PASCALS = 53, |
||||
UNITS_HECTOPASCALS = 133, |
||||
UNITS_KILOPASCALS = 54, |
||||
UNITS_MILLIBARS = 134, |
||||
UNITS_BARS = 55, |
||||
UNITS_POUNDS_FORCE_PER_SQUARE_INCH = 56, |
||||
UNITS_MILLIMETERS_OF_WATER = 206, |
||||
UNITS_CENTIMETERS_OF_WATER = 57, |
||||
UNITS_INCHES_OF_WATER = 58, |
||||
UNITS_MILLIMETERS_OF_MERCURY = 59, |
||||
UNITS_CENTIMETERS_OF_MERCURY = 60, |
||||
UNITS_INCHES_OF_MERCURY = 61, |
||||
/* Temperature */ |
||||
UNITS_DEGREES_CELSIUS = 62, |
||||
UNITS_DEGREES_KELVIN = 63, |
||||
UNITS_DEGREES_KELVIN_PER_HOUR = 181, |
||||
UNITS_DEGREES_KELVIN_PER_MINUTE = 182, |
||||
UNITS_DEGREES_FAHRENHEIT = 64, |
||||
UNITS_DEGREE_DAYS_CELSIUS = 65, |
||||
UNITS_DEGREE_DAYS_FAHRENHEIT = 66, |
||||
UNITS_DELTA_DEGREES_FAHRENHEIT = 120, |
||||
UNITS_DELTA_DEGREES_KELVIN = 121, |
||||
/* Time */ |
||||
UNITS_YEARS = 67, |
||||
UNITS_MONTHS = 68, |
||||
UNITS_WEEKS = 69, |
||||
UNITS_DAYS = 70, |
||||
UNITS_HOURS = 71, |
||||
UNITS_MINUTES = 72, |
||||
UNITS_SECONDS = 73, |
||||
UNITS_HUNDREDTHS_SECONDS = 158, |
||||
UNITS_MILLISECONDS = 159, |
||||
/* Torque */ |
||||
UNITS_NEWTON_METERS = 160, |
||||
/* Velocity */ |
||||
UNITS_MILLIMETERS_PER_SECOND = 161, |
||||
UNITS_MILLIMETERS_PER_MINUTE = 162, |
||||
UNITS_METERS_PER_SECOND = 74, |
||||
UNITS_METERS_PER_MINUTE = 163, |
||||
UNITS_METERS_PER_HOUR = 164, |
||||
UNITS_KILOMETERS_PER_HOUR = 75, |
||||
UNITS_FEET_PER_SECOND = 76, |
||||
UNITS_FEET_PER_MINUTE = 77, |
||||
UNITS_MILES_PER_HOUR = 78, |
||||
/* Volume */ |
||||
UNITS_CUBIC_FEET = 79, |
||||
UNITS_CUBIC_METERS = 80, |
||||
UNITS_IMPERIAL_GALLONS = 81, |
||||
UNITS_MILLILITERS = 197, |
||||
UNITS_LITERS = 82, |
||||
UNITS_US_GALLONS = 83, |
||||
/* Volumetric Flow */ |
||||
UNITS_CUBIC_FEET_PER_SECOND = 142, |
||||
UNITS_CUBIC_FEET_PER_MINUTE = 84, |
||||
// One unit in Addendum 135-2012bg |
||||
UNITS_MILLION_CUBIC_FEET_PER_MINUTE = 254, |
||||
UNITS_CUBIC_FEET_PER_HOUR = 191, |
||||
// five units in Addendum 135-2012bg |
||||
UNITS_STANDARD_CUBIC_FEET_PER_DAY = 47808, |
||||
UNITS_MILLION_STANDARD_CUBIC_FEET_PER_DAY = 47809, |
||||
UNITS_THOUSAND_CUBIC_FEET_PER_DAY = 47810, |
||||
UNITS_THOUSAND_STANDARD_CUBIC_FEET_PER_DAY = 47811, |
||||
UINITS_POUNDS_MASS_PER_DAY = 47812, |
||||
UNITS_CUBIC_METERS_PER_SECOND = 85, |
||||
UNITS_CUBIC_METERS_PER_MINUTE = 165, |
||||
UNITS_CUBIC_METERS_PER_HOUR = 135, |
||||
UNITS_IMPERIAL_GALLONS_PER_MINUTE = 86, |
||||
UNITS_MILLILITERS_PER_SECOND = 198, |
||||
UNITS_LITERS_PER_SECOND = 87, |
||||
UNITS_LITERS_PER_MINUTE = 88, |
||||
UNITS_LITERS_PER_HOUR = 136, |
||||
UNITS_US_GALLONS_PER_MINUTE = 89, |
||||
UNITS_US_GALLONS_PER_HOUR = 192, |
||||
/* Other */ |
||||
UNITS_DEGREES_ANGULAR = 90, |
||||
UNITS_DEGREES_CELSIUS_PER_HOUR = 91, |
||||
UNITS_DEGREES_CELSIUS_PER_MINUTE = 92, |
||||
UNITS_DEGREES_FAHRENHEIT_PER_HOUR = 93, |
||||
UNITS_DEGREES_FAHRENHEIT_PER_MINUTE = 94, |
||||
UNITS_JOULE_SECONDS = 183, |
||||
UNITS_KILOGRAMS_PER_CUBIC_METER = 186, |
||||
UNITS_KW_HOURS_PER_SQUARE_METER = 137, |
||||
UNITS_KW_HOURS_PER_SQUARE_FOOT = 138, |
||||
UNITS_MEGAJOULES_PER_SQUARE_METER = 139, |
||||
UNITS_MEGAJOULES_PER_SQUARE_FOOT = 140, |
||||
UNITS_NO_UNITS = 95, |
||||
UNITS_NEWTON_SECONDS = 187, |
||||
UNITS_NEWTONS_PER_METER = 188, |
||||
UNITS_PARTS_PER_MILLION = 96, |
||||
UNITS_PARTS_PER_BILLION = 97, |
||||
UNITS_PERCENT = 98, |
||||
UNITS_PERCENT_OBSCURATION_PER_FOOT = 143, |
||||
UNITS_PERCENT_OBSCURATION_PER_METER = 144, |
||||
UNITS_PERCENT_PER_SECOND = 99, |
||||
UNITS_PER_MINUTE = 100, |
||||
UNITS_PER_SECOND = 101, |
||||
UNITS_PSI_PER_DEGREE_FAHRENHEIT = 102, |
||||
UNITS_RADIANS = 103, |
||||
UNITS_RADIANS_PER_SECOND = 184, |
||||
UNITS_REVOLUTIONS_PER_MINUTE = 104, |
||||
UNITS_SQUARE_METERS_PER_NEWTON = 185, |
||||
UNITS_WATTS_PER_METER_PER_DEGREE_KELVIN = 189, |
||||
UNITS_WATTS_PER_SQUARE_METER_DEGREE_KELVIN = 141, |
||||
UNITS_PER_MILLE = 207, |
||||
UNITS_GRAMS_PER_GRAM = 208, |
||||
UNITS_KILOGRAMS_PER_KILOGRAM = 209, |
||||
UNITS_GRAMS_PER_KILOGRAM = 210, |
||||
UNITS_MILLIGRAMS_PER_GRAM = 211, |
||||
UNITS_MILLIGRAMS_PER_KILOGRAM = 212, |
||||
UNITS_GRAMS_PER_MILLILITER = 213, |
||||
UNITS_GRAMS_PER_LITER = 214, |
||||
UNITS_MILLIGRAMS_PER_LITER = 215, |
||||
UNITS_MICROGRAMS_PER_LITER = 216, |
||||
UNITS_GRAMS_PER_CUBIC_METER = 217, |
||||
UNITS_MILLIGRAMS_PER_CUBIC_METER = 218, |
||||
UNITS_MICROGRAMS_PER_CUBIC_METER = 219, |
||||
UNITS_NANOGRAMS_PER_CUBIC_METER = 220, |
||||
UNITS_GRAMS_PER_CUBIC_CENTIMETER = 221, |
||||
UNITS_BECQUERELS = 222, |
||||
UNITS_KILOBECQUERELS = 223, |
||||
UNITS_MEGABECQUERELS = 224, |
||||
UNITS_GRAY = 225, |
||||
UNITS_MILLIGRAY = 226, |
||||
UNITS_MICROGRAY = 227, |
||||
UNITS_SIEVERTS = 228, |
||||
UNITS_MILLISIEVERTS = 229, |
||||
UNITS_MICROSIEVERTS = 230, |
||||
UNITS_MICROSIEVERTS_PER_HOUR = 231, |
||||
UNITS_DECIBELS_A = 232, |
||||
UNITS_NEPHELOMETRIC_TURBIDITY_UNIT = 233, |
||||
UNITS_PH = 234, |
||||
UNITS_GRAMS_PER_SQUARE_METER = 235, |
||||
// Since Addendum 135-2012ar |
||||
UNITS_MINUTES_PER_DEGREE_KELVIN = 236, |
||||
UNITS_METER_SQUARED_PER_METER = 237, |
||||
UNITS_AMPERE_SECONDS = 238, |
||||
UNITS_VOLT_AMPERE_HOURS = 239, |
||||
UNITS_KILOVOLT_AMPERE_HOURS = 240, |
||||
UNITS_MEGAVOLT_AMPERE_HOURS = 241, |
||||
UNITS_VOLT_AMPERE_HOURS_REACTIVE = 242, |
||||
UNITS_KILOVOLT_AMPERE_HOURS_REACTIVE = 243, |
||||
UNITS_MEGAVOLT_AMPERE_HOURS_REACTIVE = 244, |
||||
UNITS_VOLT_SQUARE_HOURS = 245, |
||||
UNITS_AMPERE_SQUARE_HOURS = 246, |
||||
UNITS_JOULE_PER_HOURS = 247, |
||||
UNITS_CUBIC_FEET_PER_DAY = 248, |
||||
UNITS_CUBIC_METERS_PER_DAY = 249, |
||||
UNITS_WATT_HOURS_PER_CUBIC_METER = 250, |
||||
UNITS_JOULES_PER_CUBIC_METER = 251, |
||||
UNITS_MOLE_PERCENT = 252, |
||||
UNITS_PASCAL_SECONDS = 253, |
||||
UNITS_MILLION_STANDARD_CUBIC_FEET_PER_MINUTE = 254, |
||||
UNITS_RESERVED_RANGE_MAX = 255, |
||||
/* Enumerated values 256-47807 may be used by others |
||||
subject to the procedures and constraints described in Clause 23. */ |
||||
UNITS_PROPRIETARY_RANGE_MIN = 256, |
||||
UNITS_PROPRIETARY_RANGE_MAX = 47807, |
||||
/* Enumerated values 47808-49999 are reserved for definition by ASHRAE. */ |
||||
UNITS_RESERVED_RANGE_MIN2 = 47808, |
||||
UNITS_POUNDS_MASS_PER_DAY = 47812, |
||||
/* 47813 - NOT USED */ |
||||
UNITS_MILLIREMS = 47814, |
||||
UNITS_MILLIREMS_PER_HOUR = 47815, |
||||
UNITS_RESERVED_RANGE_MAX2 = 49999, |
||||
UNITS_PROPRIETARY_RANGE_MIN2 = 50000, |
||||
/* Enumerated values 50000-65535 may be used by others |
||||
subject to the procedures and constraints described in Clause 23. */ |
||||
/* do the proprietary range inside of enum so that |
||||
compilers will allocate adequate sized datatype for enum |
||||
which is used to store decoding */ |
||||
UNITS_PROPRIETARY_RANGE_MAX2 = 65535 |
||||
} |
@ -1,89 +0,0 @@
@@ -1,89 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public struct BacnetValue |
||||
{ |
||||
public BacnetApplicationTags Tag; |
||||
public object Value; |
||||
|
||||
public BacnetValue(BacnetApplicationTags tag, object value) |
||||
{ |
||||
Tag = tag; |
||||
Value = value; |
||||
} |
||||
|
||||
public BacnetValue(object value) |
||||
{ |
||||
Value = value; |
||||
Tag = BacnetApplicationTags.BACNET_APPLICATION_TAG_NULL; |
||||
|
||||
//guess at the tag |
||||
if (value != null) |
||||
Tag = TagFromType(value.GetType()); |
||||
} |
||||
|
||||
public BacnetApplicationTags TagFromType(Type t) |
||||
{ |
||||
if (t == typeof(string)) |
||||
return BacnetApplicationTags.BACNET_APPLICATION_TAG_CHARACTER_STRING; |
||||
if (t == typeof(int) || t == typeof(short) || t == typeof(sbyte)) |
||||
return BacnetApplicationTags.BACNET_APPLICATION_TAG_SIGNED_INT; |
||||
if (t == typeof(uint) || t == typeof(ushort) || t == typeof(byte)) |
||||
return BacnetApplicationTags.BACNET_APPLICATION_TAG_UNSIGNED_INT; |
||||
if (t == typeof(bool)) |
||||
return BacnetApplicationTags.BACNET_APPLICATION_TAG_BOOLEAN; |
||||
if (t == typeof(float)) |
||||
return BacnetApplicationTags.BACNET_APPLICATION_TAG_REAL; |
||||
if (t == typeof(double)) |
||||
return BacnetApplicationTags.BACNET_APPLICATION_TAG_DOUBLE; |
||||
if (t == typeof(BacnetBitString)) |
||||
return BacnetApplicationTags.BACNET_APPLICATION_TAG_BIT_STRING; |
||||
if (t == typeof(BacnetObjectId)) |
||||
return BacnetApplicationTags.BACNET_APPLICATION_TAG_OBJECT_ID; |
||||
if (t == typeof(BacnetError)) |
||||
return BacnetApplicationTags.BACNET_APPLICATION_TAG_ERROR; |
||||
if (t == typeof(BacnetDeviceObjectPropertyReference)) |
||||
return BacnetApplicationTags.BACNET_APPLICATION_TAG_OBJECT_PROPERTY_REFERENCE; |
||||
if (t.IsEnum) |
||||
return BacnetApplicationTags.BACNET_APPLICATION_TAG_ENUMERATED; |
||||
|
||||
return BacnetApplicationTags.BACNET_APPLICATION_TAG_CONTEXT_SPECIFIC_ENCODED; |
||||
} |
||||
|
||||
public T As<T>() |
||||
{ |
||||
if (typeof(T) == typeof(DateTime)) |
||||
{ |
||||
switch (Tag) |
||||
{ |
||||
case BacnetApplicationTags.BACNET_APPLICATION_TAG_DATE: |
||||
case BacnetApplicationTags.BACNET_APPLICATION_TAG_DATETIME: |
||||
case BacnetApplicationTags.BACNET_APPLICATION_TAG_TIME: |
||||
case BacnetApplicationTags.BACNET_APPLICATION_TAG_TIMESTAMP: |
||||
return (T)Value; |
||||
} |
||||
} |
||||
|
||||
if (typeof(T) == typeof(TimeSpan) && Tag == BacnetApplicationTags.BACNET_APPLICATION_TAG_TIME) |
||||
return (T)(dynamic)((DateTime)Value).TimeOfDay; |
||||
|
||||
if (typeof(T) != typeof(object) && TagFromType(typeof(T)) != Tag) |
||||
throw new ArgumentException($"Value with tag {Tag} can't be converted to {typeof(T).Name}"); |
||||
|
||||
// ReSharper disable once RedundantCast |
||||
// This is needed for casting to enums |
||||
return (T)(dynamic)Value; |
||||
} |
||||
|
||||
public override string ToString() |
||||
{ |
||||
if (Value == null) |
||||
return string.Empty; |
||||
|
||||
if (Value.GetType() != typeof(byte[])) |
||||
return Value.ToString(); |
||||
|
||||
var tmp = (byte[])Value; |
||||
return tmp.Aggregate(string.Empty, (current, b) => |
||||
current + b.ToString("X2")); |
||||
} |
||||
} |
@ -1,22 +0,0 @@
@@ -1,22 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public enum BacnetWritePriority |
||||
{ |
||||
NO_PRIORITY = 0, |
||||
MANUAL_LIFE_SAFETY = 1, |
||||
AUTOMATIC_LIFE_SAFETY = 2, |
||||
UNSPECIFIED_LEVEL_3 = 3, |
||||
UNSPECIFIED_LEVEL_4 = 4, |
||||
CRITICAL_EQUIPMENT_CONTROL = 5, |
||||
MINIMUM_ON_OFF = 6, |
||||
UNSPECIFIED_LEVEL_7 = 7, |
||||
MANUAL_OPERATOR = 8, |
||||
UNSPECIFIED_LEVEL_9 = 9, |
||||
UNSPECIFIED_LEVEL_10 = 10, |
||||
UNSPECIFIED_LEVEL_11 = 11, |
||||
UNSPECIFIED_LEVEL_12 = 12, |
||||
UNSPECIFIED_LEVEL_13 = 13, |
||||
UNSPECIFIED_LEVEL_14 = 14, |
||||
UNSPECIFIED_LEVEL_15 = 15, |
||||
LOWEST_AND_DEFAULT = 16 |
||||
} |
@ -1,71 +0,0 @@
@@ -1,71 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public struct BacnetweekNDay : ASN1.IEncode, ASN1.IDecode |
||||
{ |
||||
public byte month; /* 1 January, 13 Odd, 14 Even, 255 Any */ |
||||
public byte week; /* Don't realy understand ??? 1 for day 1 to 7, 2 for ... what's the objective ? boycott it*/ |
||||
public byte wday; /* 1=Monday-7=Sunday, 255 any */ |
||||
|
||||
public BacnetweekNDay(byte day, byte month, byte week = 255) |
||||
{ |
||||
wday = day; |
||||
this.month = month; |
||||
this.week = week; |
||||
} |
||||
|
||||
public void Encode(EncodeBuffer buffer) |
||||
{ |
||||
buffer.Add(month); |
||||
buffer.Add(week); |
||||
buffer.Add(wday); |
||||
} |
||||
|
||||
public int Decode(byte[] buffer, int offset, uint count) |
||||
{ |
||||
month = buffer[offset++]; |
||||
week = buffer[offset++]; |
||||
wday = buffer[offset]; |
||||
return 3; |
||||
} |
||||
|
||||
private static string GetDayName(int day) |
||||
{ |
||||
if (day == 7) |
||||
day = 0; |
||||
|
||||
return CultureInfo.CurrentCulture.DateTimeFormat.DayNames[day]; |
||||
} |
||||
|
||||
public override string ToString() |
||||
{ |
||||
string ret = wday != 255 ? GetDayName(wday) : "Every days"; |
||||
|
||||
if (month != 255) |
||||
ret += " on " + CultureInfo.CurrentCulture.DateTimeFormat.MonthNames[month - 1]; |
||||
else |
||||
ret += " on every month"; |
||||
|
||||
return ret; |
||||
} |
||||
|
||||
public bool IsAFittingDate(DateTime date) |
||||
{ |
||||
if (date.Month != month && month != 255 && month != 13 && month != 14) |
||||
return false; |
||||
if (month == 13 && (date.Month & 1) != 1) |
||||
return false; |
||||
if (month == 14 && (date.Month & 1) == 1) |
||||
return false; |
||||
|
||||
// What about week, too much stupid : boycott it ! |
||||
|
||||
if (wday == 255) |
||||
return true; |
||||
if (wday == 7 && date.DayOfWeek == 0) // Sunday 7 for Bacnet, 0 for .NET |
||||
return true; |
||||
if (wday == (int)date.DayOfWeek) |
||||
return true; |
||||
|
||||
return false; |
||||
} |
||||
} |
@ -1,84 +0,0 @@
@@ -1,84 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public struct DeviceReportingRecipient : ASN1.IEncode |
||||
{ |
||||
public BacnetBitString WeekofDay; |
||||
public DateTime toTime, fromTime; |
||||
|
||||
public BacnetObjectId Id; |
||||
public BacnetAddress adr; |
||||
|
||||
public uint processIdentifier; |
||||
public bool Ack_Required; |
||||
public BacnetBitString evenType; |
||||
|
||||
public DeviceReportingRecipient(BacnetValue v0, BacnetValue v1, BacnetValue v2, BacnetValue v3, BacnetValue v4, BacnetValue v5, BacnetValue v6) |
||||
{ |
||||
Id = new BacnetObjectId(); |
||||
adr = null; |
||||
|
||||
WeekofDay = (BacnetBitString)v0.Value; |
||||
fromTime = (DateTime)v1.Value; |
||||
toTime = (DateTime)v2.Value; |
||||
if (v3.Value is BacnetObjectId id) |
||||
{ |
||||
Id = id; |
||||
} |
||||
else |
||||
{ |
||||
var netdescr = (BacnetValue[])v3.Value; |
||||
var s = (ushort)(uint)netdescr[0].Value; |
||||
var b = (byte[])netdescr[1].Value; |
||||
adr = new BacnetAddress(BacnetAddressTypes.IP, s, b); |
||||
} |
||||
processIdentifier = (uint)v4.Value; |
||||
Ack_Required = (bool)v5.Value; |
||||
evenType = (BacnetBitString)v6.Value; |
||||
} |
||||
|
||||
public DeviceReportingRecipient(BacnetBitString weekofDay, DateTime fromTime, DateTime toTime, BacnetObjectId id, uint processIdentifier, bool ackRequired, BacnetBitString evenType) |
||||
{ |
||||
adr = null; |
||||
|
||||
WeekofDay = weekofDay; |
||||
this.toTime = toTime; |
||||
this.fromTime = fromTime; |
||||
Id = id; |
||||
this.processIdentifier = processIdentifier; |
||||
Ack_Required = ackRequired; |
||||
this.evenType = evenType; |
||||
} |
||||
|
||||
public DeviceReportingRecipient(BacnetBitString weekofDay, DateTime fromTime, DateTime toTime, BacnetAddress adr, uint processIdentifier, bool ackRequired, BacnetBitString evenType) |
||||
{ |
||||
Id = new BacnetObjectId(); |
||||
WeekofDay = weekofDay; |
||||
this.toTime = toTime; |
||||
this.fromTime = fromTime; |
||||
this.adr = adr; |
||||
this.processIdentifier = processIdentifier; |
||||
Ack_Required = ackRequired; |
||||
this.evenType = evenType; |
||||
} |
||||
|
||||
public void Encode(EncodeBuffer buffer) |
||||
{ |
||||
ASN1.bacapp_encode_application_data(buffer, new BacnetValue(WeekofDay)); |
||||
ASN1.bacapp_encode_application_data(buffer, new BacnetValue(BacnetApplicationTags.BACNET_APPLICATION_TAG_TIME, fromTime)); |
||||
ASN1.bacapp_encode_application_data(buffer, new BacnetValue(BacnetApplicationTags.BACNET_APPLICATION_TAG_TIME, toTime)); |
||||
|
||||
if (adr != null) |
||||
{ |
||||
adr.Encode(buffer); |
||||
} |
||||
else |
||||
{ |
||||
// BacnetObjectId is context specific encoded |
||||
ASN1.encode_context_object_id(buffer, 0, Id.type, Id.instance); |
||||
} |
||||
|
||||
ASN1.bacapp_encode_application_data(buffer, new BacnetValue(processIdentifier)); |
||||
ASN1.bacapp_encode_application_data(buffer, new BacnetValue(Ack_Required)); |
||||
ASN1.bacapp_encode_application_data(buffer, new BacnetValue(evenType)); |
||||
} |
||||
} |
@ -1,10 +0,0 @@
@@ -1,10 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public enum BacnetBackupState |
||||
{ |
||||
IDLE = 0, |
||||
PREPARING_FOR_BACKUP = 1, |
||||
PREPARING_FOR_RESTORE = 2, |
||||
PERFORMING_A_BACKUP = 3, |
||||
PERFORMING_A_RESTORE = 4 |
||||
} |
@ -1,7 +0,0 @@
@@ -1,7 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public enum BacnetCOVTypes |
||||
{ |
||||
CHANGE_OF_VALUE_BITS, |
||||
CHANGE_OF_VALUE_REAL |
||||
} |
@ -1,8 +0,0 @@
@@ -1,8 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public enum BacnetEventEnable |
||||
{ |
||||
EVENT_ENABLE_TO_OFFNORMAL = 1, |
||||
EVENT_ENABLE_TO_FAULT = 2, |
||||
EVENT_ENABLE_TO_NORMAL = 4 |
||||
} |
@ -1,11 +0,0 @@
@@ -1,11 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public enum BacnetEventStates |
||||
{ |
||||
EVENT_STATE_NORMAL = 0, |
||||
EVENT_STATE_FAULT = 1, |
||||
EVENT_STATE_OFFNORMAL = 2, |
||||
EVENT_STATE_HIGH_LIMIT = 3, |
||||
EVENT_STATE_LOW_LIMIT = 4, |
||||
EVENT_STATE_LIFE_SAFETY_ALARM = 5 |
||||
} |
@ -1,40 +0,0 @@
@@ -1,40 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public enum BacnetEventTypes |
||||
{ |
||||
EVENT_CHANGE_OF_BITSTRING = 0, |
||||
EVENT_CHANGE_OF_STATE = 1, |
||||
EVENT_CHANGE_OF_VALUE = 2, |
||||
EVENT_COMMAND_FAILURE = 3, |
||||
EVENT_FLOATING_LIMIT = 4, |
||||
EVENT_OUT_OF_RANGE = 5, |
||||
/* complex-event-type (6), -- see comment below */ |
||||
/* event-buffer-ready (7), -- context tag 7 is deprecated */ |
||||
EVENT_CHANGE_OF_LIFE_SAFETY = 8, |
||||
EVENT_EXTENDED = 9, |
||||
EVENT_BUFFER_READY = 10, |
||||
EVENT_UNSIGNED_RANGE = 11, |
||||
/* -- enumeration value 12 is reserved for future addenda */ |
||||
EVENT_ACCESS_EVENT = 13, |
||||
EVENT_DOUBLE_OUT_OF_RANGE = 14, |
||||
EVENT_SIGNED_OUT_OF_RANGE = 15, |
||||
EVENT_UNSIGNED_OUT_OF_RANGE = 16, |
||||
EVENT_CHANGE_OF_CHARACTERSTRING = 17, |
||||
EVENT_CHANGE_OF_STATUS_FLAGS = 18, |
||||
EVENT_CHANGE_OF_RELIABILITY = 19, |
||||
EVENT_NONE = 20, |
||||
EVENT_CHANGE_OF_DISCRETE_VALUE = 21, |
||||
EVENT_CHANGE_OF_TIMER = 22, |
||||
/* Enumerated values 0-63 are reserved for definition by ASHRAE. */ |
||||
/* Enumerated values 64-65535 may be used by others subject to */ |
||||
/* the procedures and constraints described in Clause 23. */ |
||||
/* It is expected that these enumerated values will correspond to */ |
||||
/* the use of the complex-event-type CHOICE [6] of the */ |
||||
/* BACnetNotificationParameters production. */ |
||||
/* The last enumeration used in this version is 11. */ |
||||
/* do the max range inside of enum so that |
||||
compilers will allocate adequate sized datatype for enum |
||||
which is used to store decoding */ |
||||
EVENT_PROPRIETARY_MIN = 64, |
||||
EVENT_PROPRIETARY_MAX = 65535 |
||||
} |
@ -1,7 +0,0 @@
@@ -1,7 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public enum BacnetFileAccessMethod |
||||
{ |
||||
RECORD_ACCESS = 0, |
||||
STREAM_ACCESS = 1 |
||||
} |
@ -1,30 +0,0 @@
@@ -1,30 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public enum BacnetLifeSafetyModes |
||||
{ |
||||
MIN_LIFE_SAFETY_MODE = 0, |
||||
LIFE_SAFETY_MODE_OFF = 0, |
||||
LIFE_SAFETY_MODE_ON = 1, |
||||
LIFE_SAFETY_MODE_TEST = 2, |
||||
LIFE_SAFETY_MODE_MANNED = 3, |
||||
LIFE_SAFETY_MODE_UNMANNED = 4, |
||||
LIFE_SAFETY_MODE_ARMED = 5, |
||||
LIFE_SAFETY_MODE_DISARMED = 6, |
||||
LIFE_SAFETY_MODE_PREARMED = 7, |
||||
LIFE_SAFETY_MODE_SLOW = 8, |
||||
LIFE_SAFETY_MODE_FAST = 9, |
||||
LIFE_SAFETY_MODE_DISCONNECTED = 10, |
||||
LIFE_SAFETY_MODE_ENABLED = 11, |
||||
LIFE_SAFETY_MODE_DISABLED = 12, |
||||
LIFE_SAFETY_MODE_AUTOMATIC_RELEASE_DISABLED = 13, |
||||
LIFE_SAFETY_MODE_DEFAULT = 14, |
||||
MAX_LIFE_SAFETY_MODE = 15, |
||||
/* Enumerated values 0-255 are reserved for definition by ASHRAE. */ |
||||
/* Enumerated values 256-65535 may be used by others subject to */ |
||||
/* procedures and constraints described in Clause 23. */ |
||||
/* do the max range inside of enum so that |
||||
compilers will allocate adequate sized datatype for enum |
||||
which is used to store decoding */ |
||||
LIFE_SAFETY_MODE_PROPRIETARY_MIN = 256, |
||||
LIFE_SAFETY_MODE_PROPRIETARY_MAX = 65535 |
||||
} |
@ -1,23 +0,0 @@
@@ -1,23 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public enum BacnetLifeSafetyOperations |
||||
{ |
||||
LIFE_SAFETY_OP_NONE = 0, |
||||
LIFE_SAFETY_OP_SILENCE = 1, |
||||
LIFE_SAFETY_OP_SILENCE_AUDIBLE = 2, |
||||
LIFE_SAFETY_OP_SILENCE_VISUAL = 3, |
||||
LIFE_SAFETY_OP_RESET = 4, |
||||
LIFE_SAFETY_OP_RESET_ALARM = 5, |
||||
LIFE_SAFETY_OP_RESET_FAULT = 6, |
||||
LIFE_SAFETY_OP_UNSILENCE = 7, |
||||
LIFE_SAFETY_OP_UNSILENCE_AUDIBLE = 8, |
||||
LIFE_SAFETY_OP_UNSILENCE_VISUAL = 9, |
||||
/* Enumerated values 0-63 are reserved for definition by ASHRAE. */ |
||||
/* Enumerated values 64-65535 may be used by others subject to */ |
||||
/* procedures and constraints described in Clause 23. */ |
||||
/* do the max range inside of enum so that |
||||
compilers will allocate adequate sized datatype for enum |
||||
which is used to store decoding */ |
||||
LIFE_SAFETY_OP_PROPRIETARY_MIN = 64, |
||||
LIFE_SAFETY_OP_PROPRIETARY_MAX = 65535 |
||||
} |
@ -1,39 +0,0 @@
@@ -1,39 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public enum BacnetLifeSafetyStates |
||||
{ |
||||
MIN_LIFE_SAFETY_STATE = 0, |
||||
LIFE_SAFETY_STATE_QUIET = 0, |
||||
LIFE_SAFETY_STATE_PRE_ALARM = 1, |
||||
LIFE_SAFETY_STATE_ALARM = 2, |
||||
LIFE_SAFETY_STATE_FAULT = 3, |
||||
LIFE_SAFETY_STATE_FAULT_PRE_ALARM = 4, |
||||
LIFE_SAFETY_STATE_FAULT_ALARM = 5, |
||||
LIFE_SAFETY_STATE_NOT_READY = 6, |
||||
LIFE_SAFETY_STATE_ACTIVE = 7, |
||||
LIFE_SAFETY_STATE_TAMPER = 8, |
||||
LIFE_SAFETY_STATE_TEST_ALARM = 9, |
||||
LIFE_SAFETY_STATE_TEST_ACTIVE = 10, |
||||
LIFE_SAFETY_STATE_TEST_FAULT = 11, |
||||
LIFE_SAFETY_STATE_TEST_FAULT_ALARM = 12, |
||||
LIFE_SAFETY_STATE_HOLDUP = 13, |
||||
LIFE_SAFETY_STATE_DURESS = 14, |
||||
LIFE_SAFETY_STATE_TAMPER_ALARM = 15, |
||||
LIFE_SAFETY_STATE_ABNORMAL = 16, |
||||
LIFE_SAFETY_STATE_EMERGENCY_POWER = 17, |
||||
LIFE_SAFETY_STATE_DELAYED = 18, |
||||
LIFE_SAFETY_STATE_BLOCKED = 19, |
||||
LIFE_SAFETY_STATE_LOCAL_ALARM = 20, |
||||
LIFE_SAFETY_STATE_GENERAL_ALARM = 21, |
||||
LIFE_SAFETY_STATE_SUPERVISORY = 22, |
||||
LIFE_SAFETY_STATE_TEST_SUPERVISORY = 23, |
||||
MAX_LIFE_SAFETY_STATE = 24, |
||||
/* Enumerated values 0-255 are reserved for definition by ASHRAE. */ |
||||
/* Enumerated values 256-65535 may be used by others subject to */ |
||||
/* procedures and constraints described in Clause 23. */ |
||||
/* do the max range inside of enum so that |
||||
compilers will allocate adequate sized datatype for enum |
||||
which is used to store decoding */ |
||||
LIFE_SAFETY_STATE_PROPRIETARY_MIN = 256, |
||||
LIFE_SAFETY_STATE_PROPRIETARY_MAX = 65535 |
||||
} |
@ -1,7 +0,0 @@
@@ -1,7 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public enum BacnetLimitEnable |
||||
{ |
||||
EVENT_LOW_LIMIT_ENABLE = 1, |
||||
EVENT_HIGH_LIMIT_ENABLE = 2 |
||||
} |
@ -1,8 +0,0 @@
@@ -1,8 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public enum BacnetNotifyTypes |
||||
{ |
||||
NOTIFY_ALARM = 0, |
||||
NOTIFY_EVENT = 1, |
||||
NOTIFY_ACK_NOTIFICATION = 2 |
||||
} |
@ -1,21 +0,0 @@
@@ -1,21 +0,0 @@
|
||||
global using Common.Logging; |
||||
global using PacketDotNet; |
||||
global using SharpPcap; |
||||
global using SharpPcap.LibPcap; |
||||
global using System.Collections.Generic; |
||||
global using System.Globalization; |
||||
global using System.IO.BACnet.Base; |
||||
global using System.IO.BACnet.Serialize; |
||||
global using System.IO.Pipes; |
||||
global using System.IO.Ports; |
||||
global using System.Linq; |
||||
global using System.Net; |
||||
global using System.Net.NetworkInformation; |
||||
global using System.Net.Sockets; |
||||
global using System.Reflection; |
||||
global using System.Runtime.InteropServices; |
||||
global using System.Text; |
||||
global using System.Text.RegularExpressions; |
||||
global using System.Threading; |
||||
global using System.Threading.Tasks; |
||||
global using System.Xml.Serialization; |
@ -1,64 +0,0 @@
@@ -1,64 +0,0 @@
|
||||
namespace System.IO.BACnet.Helpers; |
||||
|
||||
public static class BacnetValuesExtensions |
||||
{ |
||||
public static bool Has(this IList<BacnetPropertyValue> propertyValues, BacnetPropertyIds propertyId) |
||||
{ |
||||
if (propertyValues.All(v => v.property.GetPropertyId() != propertyId)) |
||||
return false; |
||||
|
||||
return propertyValues |
||||
.Where(v => v.property.GetPropertyId() == propertyId) |
||||
.Any(v => !v.value.HasError()); |
||||
} |
||||
|
||||
public static bool HasError(this IList<BacnetPropertyValue> propertyValues, BacnetErrorCodes error) |
||||
{ |
||||
return propertyValues |
||||
.SelectMany(p => p.value) |
||||
.Where(v => v.Tag == BacnetApplicationTags.BACNET_APPLICATION_TAG_ERROR) |
||||
.Any(v => v.As<BacnetError>().error_code == error); |
||||
} |
||||
|
||||
public static bool HasError(this IList<BacnetPropertyValue> propertyValues) |
||||
{ |
||||
return propertyValues.Any(p => p.value.HasError()); |
||||
} |
||||
|
||||
public static bool HasError(this IList<BacnetValue> values) |
||||
{ |
||||
return values.Any(v => v.Tag == BacnetApplicationTags.BACNET_APPLICATION_TAG_ERROR); |
||||
} |
||||
|
||||
public static object Get(this IList<BacnetPropertyValue> propertyValues, BacnetPropertyIds propertyId) |
||||
{ |
||||
return Get<object>(propertyValues, propertyId); |
||||
} |
||||
|
||||
public static T Get<T>(this IList<BacnetPropertyValue> propertyValues, BacnetPropertyIds propertyId) |
||||
{ |
||||
return GetMany<T>(propertyValues, propertyId).FirstOrDefault(); |
||||
} |
||||
|
||||
public static T[] GetMany<T>(this IList<BacnetPropertyValue> propertyValues, BacnetPropertyIds propertyId) |
||||
{ |
||||
if (!propertyValues.Has(propertyId)) |
||||
return new T[0]; |
||||
|
||||
var property = propertyValues.First(v => v.property.GetPropertyId() == propertyId); |
||||
|
||||
return property.property.propertyArrayIndex == ASN1.BACNET_ARRAY_ALL |
||||
? property.value.GetMany<T>() |
||||
: new[] { property.value[(int)property.property.propertyArrayIndex].As<T>() }; |
||||
} |
||||
|
||||
public static T[] GetMany<T>(this IList<BacnetValue> values) |
||||
{ |
||||
return values.Select(v => v.As<T>()).ToArray(); |
||||
} |
||||
|
||||
public static T Get<T>(this IList<BacnetValue> values) |
||||
{ |
||||
return GetMany<T>(values).FirstOrDefault(); |
||||
} |
||||
} |
@ -1,217 +0,0 @@
@@ -1,217 +0,0 @@
|
||||
namespace System.IO.BACnet.Serialize; |
||||
|
||||
public class APDU |
||||
{ |
||||
public static BacnetPduTypes GetDecodedType(byte[] buffer, int offset) |
||||
{ |
||||
return (BacnetPduTypes)buffer[offset]; |
||||
} |
||||
|
||||
public static void SetDecodedType(byte[] buffer, int offset, BacnetPduTypes type) |
||||
{ |
||||
buffer[offset] = (byte)type; |
||||
} |
||||
|
||||
public static int GetDecodedInvokeId(byte[] buffer, int offset) |
||||
{ |
||||
var type = GetDecodedType(buffer, offset); |
||||
switch (type & BacnetPduTypes.PDU_TYPE_MASK) |
||||
{ |
||||
case BacnetPduTypes.PDU_TYPE_SIMPLE_ACK: |
||||
case BacnetPduTypes.PDU_TYPE_COMPLEX_ACK: |
||||
case BacnetPduTypes.PDU_TYPE_ERROR: |
||||
case BacnetPduTypes.PDU_TYPE_REJECT: |
||||
case BacnetPduTypes.PDU_TYPE_ABORT: |
||||
return buffer[offset + 1]; |
||||
case BacnetPduTypes.PDU_TYPE_CONFIRMED_SERVICE_REQUEST: |
||||
return buffer[offset + 2]; |
||||
default: |
||||
return -1; |
||||
} |
||||
} |
||||
|
||||
public static void EncodeConfirmedServiceRequest(EncodeBuffer buffer, BacnetPduTypes type, BacnetConfirmedServices service, BacnetMaxSegments maxSegments, |
||||
BacnetMaxAdpu maxAdpu, byte invokeId, byte sequenceNumber = 0, byte proposedWindowSize = 0) |
||||
{ |
||||
buffer.buffer[buffer.offset++] = (byte)type; |
||||
buffer.buffer[buffer.offset++] = (byte)((byte)maxSegments | (byte)maxAdpu); |
||||
buffer.buffer[buffer.offset++] = invokeId; |
||||
|
||||
if ((type & BacnetPduTypes.SEGMENTED_MESSAGE) > 0) |
||||
{ |
||||
buffer.buffer[buffer.offset++] = sequenceNumber; |
||||
buffer.buffer[buffer.offset++] = proposedWindowSize; |
||||
} |
||||
buffer.buffer[buffer.offset++] = (byte)service; |
||||
} |
||||
|
||||
public static int DecodeConfirmedServiceRequest(byte[] buffer, int offset, out BacnetPduTypes type, out BacnetConfirmedServices service, |
||||
out BacnetMaxSegments maxSegments, out BacnetMaxAdpu maxAdpu, out byte invokeId, out byte sequenceNumber, out byte proposedWindowNumber) |
||||
{ |
||||
var orgOffset = offset; |
||||
|
||||
type = (BacnetPduTypes)buffer[offset++]; |
||||
maxSegments = (BacnetMaxSegments)(buffer[offset] & 0xF0); |
||||
maxAdpu = (BacnetMaxAdpu)(buffer[offset++] & 0x0F); |
||||
invokeId = buffer[offset++]; |
||||
|
||||
sequenceNumber = 0; |
||||
proposedWindowNumber = 0; |
||||
if ((type & BacnetPduTypes.SEGMENTED_MESSAGE) > 0) |
||||
{ |
||||
sequenceNumber = buffer[offset++]; |
||||
proposedWindowNumber = buffer[offset++]; |
||||
} |
||||
service = (BacnetConfirmedServices)buffer[offset++]; |
||||
|
||||
return offset - orgOffset; |
||||
} |
||||
|
||||
public static void EncodeUnconfirmedServiceRequest(EncodeBuffer buffer, BacnetPduTypes type, BacnetUnconfirmedServices service) |
||||
{ |
||||
buffer.buffer[buffer.offset++] = (byte)type; |
||||
buffer.buffer[buffer.offset++] = (byte)service; |
||||
} |
||||
|
||||
public static int DecodeUnconfirmedServiceRequest(byte[] buffer, int offset, out BacnetPduTypes type, out BacnetUnconfirmedServices service) |
||||
{ |
||||
var orgOffset = offset; |
||||
|
||||
type = (BacnetPduTypes)buffer[offset++]; |
||||
service = (BacnetUnconfirmedServices)buffer[offset++]; |
||||
|
||||
return offset - orgOffset; |
||||
} |
||||
|
||||
public static void EncodeSimpleAck(EncodeBuffer buffer, BacnetPduTypes type, BacnetConfirmedServices service, byte invokeId) |
||||
{ |
||||
buffer.buffer[buffer.offset++] = (byte)type; |
||||
buffer.buffer[buffer.offset++] = invokeId; |
||||
buffer.buffer[buffer.offset++] = (byte)service; |
||||
} |
||||
|
||||
public static int DecodeSimpleAck(byte[] buffer, int offset, out BacnetPduTypes type, out BacnetConfirmedServices service, out byte invokeId) |
||||
{ |
||||
var orgOffset = offset; |
||||
|
||||
type = (BacnetPduTypes)buffer[offset++]; |
||||
invokeId = buffer[offset++]; |
||||
service = (BacnetConfirmedServices)buffer[offset++]; |
||||
|
||||
return offset - orgOffset; |
||||
} |
||||
|
||||
public static int EncodeComplexAck(EncodeBuffer buffer, BacnetPduTypes type, BacnetConfirmedServices service, byte invokeId, byte sequenceNumber = 0, byte proposedWindowNumber = 0) |
||||
{ |
||||
var len = 3; |
||||
buffer.buffer[buffer.offset++] = (byte)type; |
||||
buffer.buffer[buffer.offset++] = invokeId; |
||||
if ((type & BacnetPduTypes.SEGMENTED_MESSAGE) > 0) |
||||
{ |
||||
buffer.buffer[buffer.offset++] = sequenceNumber; |
||||
buffer.buffer[buffer.offset++] = proposedWindowNumber; |
||||
len += 2; |
||||
} |
||||
buffer.buffer[buffer.offset++] = (byte)service; |
||||
return len; |
||||
} |
||||
|
||||
public static int DecodeComplexAck(byte[] buffer, int offset, out BacnetPduTypes type, out BacnetConfirmedServices service, out byte invokeId, |
||||
out byte sequenceNumber, out byte proposedWindowNumber) |
||||
{ |
||||
var orgOffset = offset; |
||||
|
||||
type = (BacnetPduTypes)buffer[offset++]; |
||||
invokeId = buffer[offset++]; |
||||
|
||||
sequenceNumber = 0; |
||||
proposedWindowNumber = 0; |
||||
if ((type & BacnetPduTypes.SEGMENTED_MESSAGE) > 0) |
||||
{ |
||||
sequenceNumber = buffer[offset++]; |
||||
proposedWindowNumber = buffer[offset++]; |
||||
} |
||||
service = (BacnetConfirmedServices)buffer[offset++]; |
||||
|
||||
return offset - orgOffset; |
||||
} |
||||
|
||||
public static void EncodeSegmentAck(EncodeBuffer buffer, BacnetPduTypes type, byte originalInvokeId, byte sequenceNumber, byte actualWindowSize) |
||||
{ |
||||
buffer.buffer[buffer.offset++] = (byte)type; |
||||
buffer.buffer[buffer.offset++] = originalInvokeId; |
||||
buffer.buffer[buffer.offset++] = sequenceNumber; |
||||
buffer.buffer[buffer.offset++] = actualWindowSize; |
||||
} |
||||
|
||||
public static int DecodeSegmentAck(byte[] buffer, int offset, out BacnetPduTypes type, out byte originalInvokeId, out byte sequenceNumber, out byte actualWindowSize) |
||||
{ |
||||
var orgOffset = offset; |
||||
|
||||
type = (BacnetPduTypes)buffer[offset++]; |
||||
originalInvokeId = buffer[offset++]; |
||||
sequenceNumber = buffer[offset++]; |
||||
actualWindowSize = buffer[offset++]; |
||||
|
||||
return offset - orgOffset; |
||||
} |
||||
|
||||
public static void EncodeError(EncodeBuffer buffer, BacnetPduTypes type, BacnetConfirmedServices service, byte invokeId) |
||||
{ |
||||
buffer.buffer[buffer.offset++] = (byte)type; |
||||
buffer.buffer[buffer.offset++] = invokeId; |
||||
buffer.buffer[buffer.offset++] = (byte)service; |
||||
} |
||||
|
||||
public static int DecodeError(byte[] buffer, int offset, out BacnetPduTypes type, out BacnetConfirmedServices service, out byte invokeId) |
||||
{ |
||||
var orgOffset = offset; |
||||
|
||||
type = (BacnetPduTypes)buffer[offset++]; |
||||
invokeId = buffer[offset++]; |
||||
service = (BacnetConfirmedServices)buffer[offset++]; |
||||
|
||||
return offset - orgOffset; |
||||
} |
||||
|
||||
public static void EncodeAbort(EncodeBuffer buffer, BacnetPduTypes type, byte invokeId, BacnetAbortReason reason) |
||||
{ |
||||
EncodeAbortOrReject(buffer, type, invokeId, reason); |
||||
} |
||||
|
||||
public static void EncodeReject(EncodeBuffer buffer, BacnetPduTypes type, byte invokeId, BacnetRejectReason reason) |
||||
{ |
||||
EncodeAbortOrReject(buffer, type, invokeId, reason); |
||||
} |
||||
|
||||
private static void EncodeAbortOrReject(EncodeBuffer buffer, BacnetPduTypes type, byte invokeId, dynamic reason) |
||||
{ |
||||
buffer.buffer[buffer.offset++] = (byte)type; |
||||
buffer.buffer[buffer.offset++] = invokeId; |
||||
buffer.buffer[buffer.offset++] = (byte)reason; |
||||
} |
||||
|
||||
public static int DecodeAbort(byte[] buffer, int offset, out BacnetPduTypes type, |
||||
out byte invokeId, out BacnetAbortReason reason) |
||||
{ |
||||
return DecodeAbortOrReject(buffer, offset, out type, out invokeId, out reason); |
||||
} |
||||
|
||||
public static int DecodeReject(byte[] buffer, int offset, out BacnetPduTypes type, |
||||
out byte invokeId, out BacnetRejectReason reason) |
||||
{ |
||||
return DecodeAbortOrReject(buffer, offset, out type, out invokeId, out reason); |
||||
} |
||||
|
||||
private static int DecodeAbortOrReject<TReason>(byte[] buffer, int offset, |
||||
out BacnetPduTypes type, out byte invokeId, out TReason reason) |
||||
{ |
||||
var orgOffset = offset; |
||||
|
||||
type = (BacnetPduTypes)buffer[offset++]; |
||||
invokeId = buffer[offset++]; |
||||
reason = (TReason)(dynamic)buffer[offset++]; |
||||
|
||||
return offset - orgOffset; |
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -1,416 +0,0 @@
@@ -1,416 +0,0 @@
|
||||
namespace System.IO.BACnet.Serialize; |
||||
|
||||
// Special thanks to VTS tool (BBMD services not activated but programmed !) and Steve Karg stack |
||||
public class BVLC |
||||
{ |
||||
public delegate void BVLCMessageReceiveHandler(IPEndPoint sender, BacnetBvlcFunctions function, BacnetBvlcResults result, object data); |
||||
public event BVLCMessageReceiveHandler MessageReceived; |
||||
|
||||
private readonly BacnetIpUdpProtocolTransport _myBbmdTransport; |
||||
readonly string _broadcastAdd; |
||||
private bool _bbmdFdServiceActivated; |
||||
|
||||
public const byte BVLL_TYPE_BACNET_IP = 0x81; |
||||
public const byte BVLC_HEADER_LENGTH = 4; |
||||
public const BacnetMaxAdpu BVLC_MAX_APDU = BacnetMaxAdpu.MAX_APDU1476; |
||||
|
||||
// Two lists for optional BBMD activity |
||||
readonly List<KeyValuePair<IPEndPoint, DateTime>> _foreignDevices = new(); |
||||
private readonly List<KeyValuePair<IPEndPoint, IPAddress>> _bbmds = new(); |
||||
|
||||
// Contains the rules to accept FRD based on the IP adress |
||||
// If empty it's equal to *.*.*.*, everyone allows |
||||
private readonly List<Regex> _autorizedFdr = new(); |
||||
|
||||
public ILog Log { get; set; } = LogManager.GetLogger<BVLC>(); |
||||
|
||||
public BVLC(BacnetIpUdpProtocolTransport transport) |
||||
{ |
||||
_myBbmdTransport = transport; |
||||
_broadcastAdd = _myBbmdTransport.GetBroadcastAddress().ToString().Split(':')[0]; |
||||
} |
||||
|
||||
public string FDList() |
||||
{ |
||||
var sb = new StringBuilder(); |
||||
lock (_foreignDevices) |
||||
{ |
||||
// remove oldest Device entries (Time expiration > TTL + 30s delay) |
||||
_foreignDevices.Remove(_foreignDevices.Find(item => DateTime.Now > item.Value)); |
||||
|
||||
foreach (var client in _foreignDevices) |
||||
sb.Append($"{client.Key.Address}:{client.Key.Port};"); |
||||
} |
||||
return sb.ToString(); |
||||
} |
||||
|
||||
public void AddFDRAutorisationRule(Regex ipRule) |
||||
{ |
||||
_autorizedFdr.Add(ipRule); |
||||
} |
||||
|
||||
// Used to initiate the BBMD & FD behaviour, if BBMD is null it start the FD activity only |
||||
public void AddBBMDPeer(IPEndPoint bbmd, IPAddress mask) |
||||
{ |
||||
_bbmdFdServiceActivated = true; |
||||
|
||||
if (bbmd == null) |
||||
return; |
||||
|
||||
lock (_bbmds) |
||||
_bbmds.Add(new KeyValuePair<IPEndPoint, IPAddress>(bbmd, mask)); |
||||
} |
||||
|
||||
// Add a FD to the table or renew it |
||||
private void RegisterForeignDevice(IPEndPoint sender, int ttl) |
||||
{ |
||||
lock (_foreignDevices) |
||||
{ |
||||
// remove it, if any |
||||
_foreignDevices.Remove(_foreignDevices.Find(item => item.Key.Equals(sender))); |
||||
// TTL + 30s grace period |
||||
var expiration = DateTime.Now.AddSeconds(ttl + 30); |
||||
// add it |
||||
if (_autorizedFdr.Count == 0) // No rules, accept all |
||||
{ |
||||
_foreignDevices.Add(new KeyValuePair<IPEndPoint, DateTime>(sender, expiration)); |
||||
return; |
||||
} |
||||
foreach (var r in _autorizedFdr) |
||||
{ |
||||
if (r.Match(sender.Address.ToString()).Success) |
||||
{ |
||||
_foreignDevices.Add(new KeyValuePair<IPEndPoint, DateTime>(sender, expiration)); |
||||
return; |
||||
} |
||||
} |
||||
Log.Info($"Rejected FDR registration, IP : {sender.Address}"); |
||||
} |
||||
} |
||||
|
||||
// Send a Frame to each registered foreign devices, except the original sender |
||||
private void SendToFDs(byte[] buffer, int msgLength, IPEndPoint ePsender = null) |
||||
{ |
||||
lock (_foreignDevices) |
||||
{ |
||||
// remove oldest Device entries (Time expiration > TTL + 30s delay) |
||||
_foreignDevices.Remove(_foreignDevices.Find(item => DateTime.Now > item.Value)); |
||||
// Send to all others, except the original sender |
||||
foreach (var client in _foreignDevices) |
||||
{ |
||||
if (!client.Key.Equals(ePsender)) |
||||
_myBbmdTransport.Send(buffer, msgLength, client.Key); |
||||
} |
||||
} |
||||
} |
||||
|
||||
private static IPEndPoint BBMDSentAdd(IPEndPoint bbmd, IPAddress mask) |
||||
{ |
||||
var bm = mask.GetAddressBytes(); |
||||
var bip = bbmd.Address.GetAddressBytes(); |
||||
|
||||
/* annotation in Steve Karg bacnet stack : |
||||
|
||||
The B/IP address to which the Forwarded-NPDU message is |
||||
sent is formed by inverting the broadcast distribution |
||||
mask in the BDT entry and logically ORing it with the |
||||
BBMD address of the same entry. This process |
||||
produces either the directed broadcast address of the remote |
||||
subnet or the unicast address of the BBMD on that subnet |
||||
depending on the contents of the broadcast distribution |
||||
mask. |
||||
|
||||
remark from me : |
||||
for instance remote BBMD 192.168.0.1 - mask 255.255.255.255 |
||||
messages are forward directly to 192.168.0.1 |
||||
remote BBMD 192.168.0.1 - mask 255.255.255.0 |
||||
messages are forward to 192.168.0.255, ie certainly the local broadcast |
||||
address, but these datagrams are generaly destroy by the final IP router |
||||
*/ |
||||
|
||||
for (var i = 0; i < bm.Length; i++) |
||||
bip[i] = (byte)(bip[i] | ~bm[i]); |
||||
|
||||
return new IPEndPoint(new IPAddress(bip), bbmd.Port); |
||||
} |
||||
|
||||
// Send a Frame to each registered BBMD except the original sender |
||||
private void SendToBbmDs(byte[] buffer, int msgLength) |
||||
{ |
||||
lock (_bbmds) |
||||
{ |
||||
foreach (var e in _bbmds) |
||||
{ |
||||
var endpoint = BBMDSentAdd(e.Key, e.Value); |
||||
_myBbmdTransport.Send(buffer, msgLength, endpoint); |
||||
} |
||||
} |
||||
} |
||||
|
||||
private static void First4BytesHeaderEncode(IList<byte> b, BacnetBvlcFunctions function, int msgLength) |
||||
{ |
||||
b[0] = BVLL_TYPE_BACNET_IP; |
||||
b[1] = (byte)function; |
||||
b[2] = (byte)((msgLength & 0xFF00) >> 8); |
||||
b[3] = (byte)((msgLength & 0x00FF) >> 0); |
||||
} |
||||
|
||||
private void Forward_NPDU(byte[] buffer, int msgLength, bool toGlobalBroadcast, IPEndPoint ePsender) |
||||
{ |
||||
// Forms the forwarded NPDU from the original one, and send it to all |
||||
// orignal - 4 bytes BVLC - NPDU - APDU |
||||
// change to - 10 bytes BVLC - NPDU - APDU |
||||
|
||||
// copy, 6 bytes shifted |
||||
var b = new byte[msgLength + 6]; // normaly only 'small' frames are present here, so no need to check if it's to big for Udp |
||||
Array.Copy(buffer, 0, b, 6, msgLength); |
||||
|
||||
// 10 bytes for the BVLC Header, with the embedded 6 bytes IP:Port of the original sender |
||||
First4BytesHeaderEncode(b, BacnetBvlcFunctions.BVLC_FORWARDED_NPDU, msgLength + 6); |
||||
BacnetIpUdpProtocolTransport.Convert(ePsender, out var bacSender); // to embbed in the forward BVLC header |
||||
for (var i = 0; i < bacSender.adr.Length; i++) |
||||
b[4 + i] = bacSender.adr[i]; |
||||
|
||||
// To BBMD |
||||
SendToBbmDs(b, msgLength + 6); |
||||
// To FD, except the sender |
||||
SendToFDs(b, msgLength + 6, ePsender); |
||||
// Broadcast if required |
||||
if (toGlobalBroadcast) |
||||
_myBbmdTransport.Send(b, msgLength + 6, new IPEndPoint(IPAddress.Parse(_broadcastAdd), _myBbmdTransport.SharedPort)); |
||||
} |
||||
|
||||
// Send ack or nack |
||||
private void SendResult(IPEndPoint sender, BacnetBvlcResults resultCode) |
||||
{ |
||||
var b = new byte[6]; |
||||
First4BytesHeaderEncode(b, BacnetBvlcFunctions.BVLC_RESULT, 6); |
||||
b[4] = (byte)(((ushort)resultCode & 0xFF00) >> 8); |
||||
b[5] = (byte)((ushort)resultCode & 0xFF); |
||||
|
||||
_myBbmdTransport.Send(b, 6, sender); |
||||
} |
||||
|
||||
public void SendRegisterAsForeignDevice(IPEndPoint bbmd, short ttl) |
||||
{ |
||||
var b = new byte[6]; |
||||
First4BytesHeaderEncode(b, BacnetBvlcFunctions.BVLC_REGISTER_FOREIGN_DEVICE, 6); |
||||
b[4] = (byte)((ttl & 0xFF00) >> 8); |
||||
b[5] = (byte)(ttl & 0xFF); |
||||
_myBbmdTransport.Send(b, 6, bbmd); |
||||
} |
||||
|
||||
public void SendReadBroadCastTable(IPEndPoint bbmd) |
||||
{ |
||||
var b = new byte[4]; |
||||
First4BytesHeaderEncode(b, BacnetBvlcFunctions.BVLC_READ_BROADCAST_DIST_TABLE, 4); |
||||
_myBbmdTransport.Send(b, 4, bbmd); |
||||
} |
||||
|
||||
public void SendReadFDRTable(IPEndPoint bbmd) |
||||
{ |
||||
var b = new byte[4]; |
||||
First4BytesHeaderEncode(b, BacnetBvlcFunctions.BVLC_READ_FOREIGN_DEVICE_TABLE, 4); |
||||
_myBbmdTransport.Send(b, 4, bbmd); |
||||
} |
||||
|
||||
public void SendWriteBroadCastTable(IPEndPoint bbmd, List<Tuple<IPEndPoint, IPAddress>> entries) |
||||
{ |
||||
var b = new byte[4 + 10 * entries.Count]; |
||||
First4BytesHeaderEncode(b, BacnetBvlcFunctions.BVLC_WRITE_BROADCAST_DISTRIBUTION_TABLE, 4 + 10 * entries.Count); |
||||
|
||||
for (var i = 0; i < entries.Count; i++) |
||||
{ |
||||
Array.Copy(entries[i].Item1.Address.GetAddressBytes(), 0, b, 4 + i * 10, 4); |
||||
b[8 + i * 10] = (byte)(entries[i].Item1.Port >> 8); |
||||
b[9 + i * 10] = (byte)(entries[i].Item1.Port & 0xFF); |
||||
Array.Copy(entries[i].Item2.GetAddressBytes(), 0, b, 10 + i * 10, 4); |
||||
} |
||||
|
||||
_myBbmdTransport.Send(b, 4 + 10 * entries.Count, bbmd); |
||||
} |
||||
|
||||
public void SendDeleteForeignDeviceEntry(IPEndPoint bbmd, IPEndPoint foreignDevice) |
||||
{ |
||||
var b = new byte[4 + 6]; |
||||
First4BytesHeaderEncode(b, BacnetBvlcFunctions.BVLC_READ_FOREIGN_DEVICE_TABLE, 4 + 6); |
||||
Array.Copy(foreignDevice.Address.GetAddressBytes(), 0, b, 4, 4); |
||||
b[8] = (byte)(foreignDevice.Port >> 8); |
||||
b[9] = (byte)(foreignDevice.Port & 0xFF); |
||||
_myBbmdTransport.Send(b, 4 + 6, bbmd); |
||||
} |
||||
|
||||
public void SendRemoteWhois(byte[] buffer, IPEndPoint bbmd, int msgLength) |
||||
{ |
||||
Encode(buffer, 0, BacnetBvlcFunctions.BVLC_DISTRIBUTE_BROADCAST_TO_NETWORK, msgLength); |
||||
_myBbmdTransport.Send(buffer, msgLength, bbmd); |
||||
|
||||
} |
||||
|
||||
// Encode is called by internal services if the BBMD is also an active device |
||||
public int Encode(byte[] buffer, int offset, BacnetBvlcFunctions function, int msgLength) |
||||
{ |
||||
// offset always 0, we are the first after udp |
||||
|
||||
// do the job |
||||
First4BytesHeaderEncode(buffer, function, msgLength); |
||||
|
||||
// optional BBMD service |
||||
if (_bbmdFdServiceActivated && function == BacnetBvlcFunctions.BVLC_ORIGINAL_BROADCAST_NPDU) |
||||
{ |
||||
var me = _myBbmdTransport.LocalEndPoint; |
||||
// just sometime working, enable to get the local ep, always 0.0.0.0 if the socket is open with |
||||
// System.Net.IPAddress.Any |
||||
// So in this case don't send a bad message |
||||
if (me.Address.ToString() != "0.0.0.0") |
||||
Forward_NPDU(buffer, msgLength, false, me); // send to all BBMDs and FDs |
||||
} |
||||
return 4; // ready to send |
||||
} |
||||
|
||||
// Decode is called each time an Udp Frame is received |
||||
public int Decode(byte[] buffer, int offset, out BacnetBvlcFunctions function, out int msgLength, IPEndPoint sender) |
||||
{ |
||||
// offset always 0, we are the first after udp |
||||
// and a previous test by the caller guaranteed at least 4 bytes into the buffer |
||||
|
||||
function = (BacnetBvlcFunctions)buffer[1]; |
||||
msgLength = (buffer[2] << 8) | (buffer[3] << 0); |
||||
if (buffer[0] != BVLL_TYPE_BACNET_IP || buffer.Length != msgLength) return -1; |
||||
|
||||
switch (function) |
||||
{ |
||||
case BacnetBvlcFunctions.BVLC_RESULT: |
||||
var resultCode = (buffer[4] << 8) + buffer[5]; |
||||
MessageReceived?.Invoke(sender, function, (BacnetBvlcResults)resultCode, null); |
||||
return 0; // not for the upper layers |
||||
|
||||
case BacnetBvlcFunctions.BVLC_ORIGINAL_UNICAST_NPDU: |
||||
return 4; // only for the upper layers |
||||
|
||||
case BacnetBvlcFunctions.BVLC_ORIGINAL_BROADCAST_NPDU: // Normaly received in an IP local or global broadcast packet |
||||
// Send to FDs & BBMDs, not broadcast or it will be made twice ! |
||||
if (_bbmdFdServiceActivated) |
||||
Forward_NPDU(buffer, msgLength, false, sender); |
||||
return 4; // also for the upper layers |
||||
|
||||
case BacnetBvlcFunctions.BVLC_FORWARDED_NPDU: // Sent only by a BBMD, broadcast on it network, or broadcast demand by one of it's FDs |
||||
if (_bbmdFdServiceActivated && msgLength >= 10) |
||||
{ |
||||
bool ret; |
||||
lock (_bbmds) |
||||
ret = _bbmds.Exists(items => items.Key.Address.Equals(sender.Address)); // verify sender (@ not Port!) presence in the table |
||||
|
||||
if (ret) // message from a know BBMD address, sent to all FDs and broadcast |
||||
{ |
||||
SendToFDs(buffer, msgLength); // send without modification |
||||
|
||||
// Assume all BVLC_FORWARDED_NPDU are directly sent to me in the |
||||
// unicast mode and not by the way of the local broadcast address |
||||
// ie my mask must be 255.255.255.255 in the others BBMD tables |
||||
// If not, it's not really a big problem, devices on the local net will |
||||
// receive two times the message (after all it's just WhoIs, Iam, ...) |
||||
_myBbmdTransport.Send(buffer, msgLength, new IPEndPoint(IPAddress.Parse(_broadcastAdd), _myBbmdTransport.SharedPort)); |
||||
} |
||||
} |
||||
|
||||
return 10; // also for the upper layers |
||||
|
||||
case BacnetBvlcFunctions.BVLC_DISTRIBUTE_BROADCAST_TO_NETWORK: // Sent by a Foreign Device, not a BBMD |
||||
if (_bbmdFdServiceActivated) |
||||
{ |
||||
// Send to FDs except the sender, BBMDs and broadcast |
||||
lock (_foreignDevices) |
||||
{ |
||||
if (_foreignDevices.Exists(item => item.Key.Equals(sender))) // verify previous registration |
||||
Forward_NPDU(buffer, msgLength, true, sender); |
||||
else |
||||
SendResult(sender, BacnetBvlcResults.BVLC_RESULT_DISTRIBUTE_BROADCAST_TO_NETWORK_NAK); |
||||
} |
||||
} |
||||
return 0; // not for the upper layers |
||||
|
||||
case BacnetBvlcFunctions.BVLC_REGISTER_FOREIGN_DEVICE: |
||||
if (_bbmdFdServiceActivated && msgLength == 6) |
||||
{ |
||||
var ttl = (buffer[4] << 8) + buffer[5]; // unit is second |
||||
RegisterForeignDevice(sender, ttl); |
||||
SendResult(sender, BacnetBvlcResults.BVLC_RESULT_SUCCESSFUL_COMPLETION); // ack |
||||
} |
||||
return 0; // not for the upper layers |
||||
|
||||
// We don't care about Read/Write operation in the BBMD/FDR tables (who realy use it ?) |
||||
case BacnetBvlcFunctions.BVLC_READ_FOREIGN_DEVICE_TABLE: |
||||
SendResult(sender, BacnetBvlcResults.BVLC_RESULT_READ_FOREIGN_DEVICE_TABLE_NAK); |
||||
return 0; |
||||
|
||||
case BacnetBvlcFunctions.BVLC_DELETE_FOREIGN_DEVICE_TABLE_ENTRY: |
||||
SendResult(sender, BacnetBvlcResults.BVLC_RESULT_DELETE_FOREIGN_DEVICE_TABLE_ENTRY_NAK); |
||||
return 0; |
||||
|
||||
case BacnetBvlcFunctions.BVLC_READ_BROADCAST_DIST_TABLE: |
||||
SendResult(sender, BacnetBvlcResults.BVLC_RESULT_READ_BROADCAST_DISTRIBUTION_TABLE_NAK); |
||||
return 0; |
||||
|
||||
case BacnetBvlcFunctions.BVLC_WRITE_BROADCAST_DISTRIBUTION_TABLE: |
||||
case BacnetBvlcFunctions.BVLC_READ_BROADCAST_DIST_TABLE_ACK: |
||||
{ |
||||
var nbEntries = (msgLength - 4) / 10; |
||||
var entries = new List<Tuple<IPEndPoint, IPAddress>>(); |
||||
|
||||
for (var i = 0; i < nbEntries; i++) |
||||
{ |
||||
long add = BitConverter.ToInt32(buffer, 4 + i * 10); |
||||
|
||||
Array.Reverse(buffer, 8 + i * 10, 2); |
||||
var port = BitConverter.ToUInt16(buffer, 8 + i * 10); |
||||
|
||||
// new IPAddress(long) with 255.255.255.255 (ie -1) not OK |
||||
var mask = new byte[4]; |
||||
Array.Copy(buffer, 10 + i * 10, mask, 0, 4); |
||||
|
||||
var entry = Tuple.Create(new IPEndPoint(new IPAddress(add), port), new IPAddress(mask)); |
||||
entries.Add(entry); |
||||
} |
||||
|
||||
if (MessageReceived != null && function == BacnetBvlcFunctions.BVLC_READ_BROADCAST_DIST_TABLE_ACK) |
||||
MessageReceived(sender, function, BacnetBvlcResults.BVLC_RESULT_SUCCESSFUL_COMPLETION, entries); |
||||
|
||||
// Today we don't accept it |
||||
if (function == BacnetBvlcFunctions.BVLC_WRITE_BROADCAST_DISTRIBUTION_TABLE) |
||||
SendResult(sender, BacnetBvlcResults.BVLC_RESULT_WRITE_BROADCAST_DISTRIBUTION_TABLE_NAK); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
case BacnetBvlcFunctions.BVLC_READ_FOREIGN_DEVICE_TABLE_ACK: |
||||
{ |
||||
var nbEntries = (msgLength - 4) / 10; |
||||
var entries = new List<Tuple<IPEndPoint, ushort, ushort>>(); |
||||
|
||||
for (var i = 0; i < nbEntries; i++) |
||||
{ |
||||
long add = BitConverter.ToInt32(buffer, 4 + i * 10); |
||||
|
||||
Array.Reverse(buffer, 8 + i * 10, 2); |
||||
var port = BitConverter.ToUInt16(buffer, 8 + i * 10); |
||||
|
||||
Array.Reverse(buffer, 10 + i * 10, 2); |
||||
var ttl = BitConverter.ToUInt16(buffer, 10 + i * 10); |
||||
Array.Reverse(buffer, 12 + i * 10, 2); |
||||
var remainTtl = BitConverter.ToUInt16(buffer, 12 + i * 10); |
||||
|
||||
var entry = Tuple.Create(new IPEndPoint(new IPAddress(add), port), ttl, remainTtl); |
||||
entries.Add(entry); |
||||
} |
||||
|
||||
MessageReceived?.Invoke(sender, function, BacnetBvlcResults.BVLC_RESULT_SUCCESSFUL_COMPLETION, entries); |
||||
return 0; |
||||
} |
||||
|
||||
// error encoding function or experimental one |
||||
default: |
||||
return -1; |
||||
} |
||||
} |
||||
} |
@ -1,117 +0,0 @@
@@ -1,117 +0,0 @@
|
||||
namespace System.IO.BACnet.Serialize; |
||||
|
||||
public class EncodeBuffer |
||||
{ |
||||
public byte[] buffer; //buffer to serialize into |
||||
public int offset; //offset in buffer ... will go beyond max_offset (so that you may count what's needed) |
||||
public int max_offset; //don't write beyond this offset |
||||
public int serialize_counter; //used with 'min_limit' |
||||
public int min_limit; //don't write before this limit (used for segmentation) |
||||
public EncodeResult result; |
||||
public bool expandable; |
||||
|
||||
public EncodeBuffer() |
||||
{ |
||||
expandable = true; |
||||
buffer = new byte[128]; |
||||
max_offset = buffer.Length - 1; |
||||
} |
||||
|
||||
public EncodeBuffer(byte[] buffer, int offset) |
||||
{ |
||||
if (buffer == null) buffer = new byte[0]; |
||||
expandable = false; |
||||
this.buffer = buffer; |
||||
this.offset = offset; |
||||
max_offset = buffer.Length; |
||||
} |
||||
|
||||
public void Increment() |
||||
{ |
||||
if (offset < max_offset) |
||||
{ |
||||
if (serialize_counter >= min_limit) |
||||
offset++; |
||||
serialize_counter++; |
||||
} |
||||
else |
||||
{ |
||||
if (serialize_counter >= min_limit) |
||||
offset++; |
||||
} |
||||
} |
||||
|
||||
public void Add(byte b) |
||||
{ |
||||
if (offset < max_offset) |
||||
{ |
||||
if (serialize_counter >= min_limit) |
||||
buffer[offset] = b; |
||||
} |
||||
else |
||||
{ |
||||
if (expandable) |
||||
{ |
||||
Array.Resize(ref buffer, buffer.Length * 2); |
||||
max_offset = buffer.Length - 1; |
||||
if (serialize_counter >= min_limit) |
||||
buffer[offset] = b; |
||||
} |
||||
else |
||||
result |= EncodeResult.NotEnoughBuffer; |
||||
} |
||||
|
||||
Increment(); |
||||
} |
||||
|
||||
public void Add(byte[] buffer, int count) |
||||
{ |
||||
for (var i = 0; i < count; i++) |
||||
Add(buffer[i]); |
||||
} |
||||
|
||||
public int GetDiff(EncodeBuffer buffer) |
||||
{ |
||||
var diff = Math.Abs(buffer.offset - offset); |
||||
diff = Math.Max(Math.Abs(buffer.serialize_counter - serialize_counter), diff); |
||||
return diff; |
||||
} |
||||
|
||||
public EncodeBuffer Copy() |
||||
{ |
||||
return new EncodeBuffer |
||||
{ |
||||
buffer = buffer, |
||||
max_offset = max_offset, |
||||
min_limit = min_limit, |
||||
offset = offset, |
||||
result = result, |
||||
serialize_counter = serialize_counter, |
||||
expandable = expandable |
||||
}; |
||||
} |
||||
|
||||
public byte[] ToArray() |
||||
{ |
||||
var ret = new byte[offset]; |
||||
Array.Copy(buffer, 0, ret, 0, ret.Length); |
||||
return ret; |
||||
} |
||||
|
||||
public void Reset(int newOffset) |
||||
{ |
||||
offset = newOffset; |
||||
serialize_counter = 0; |
||||
result = EncodeResult.Good; |
||||
} |
||||
|
||||
public override string ToString() |
||||
{ |
||||
return offset + " - " + serialize_counter; |
||||
} |
||||
|
||||
public int GetLength() |
||||
{ |
||||
return Math.Min(offset, max_offset); |
||||
} |
||||
} |
@ -1,8 +0,0 @@
@@ -1,8 +0,0 @@
|
||||
namespace System.IO.BACnet.Serialize; |
||||
|
||||
[Flags] |
||||
public enum EncodeResult |
||||
{ |
||||
Good = 0, |
||||
NotEnoughBuffer = 1 |
||||
} |
@ -1,107 +0,0 @@
@@ -1,107 +0,0 @@
|
||||
namespace System.IO.BACnet.Serialize; |
||||
|
||||
public class MSTP |
||||
{ |
||||
public const byte MSTP_PREAMBLE1 = 0x55; |
||||
public const byte MSTP_PREAMBLE2 = 0xFF; |
||||
public const BacnetMaxAdpu MSTP_MAX_APDU = BacnetMaxAdpu.MAX_APDU480; |
||||
public const byte MSTP_HEADER_LENGTH = 8; |
||||
|
||||
public static byte CRC_Calc_Header(byte dataValue, byte crcValue) |
||||
{ |
||||
var crc = (ushort)(crcValue ^ dataValue); |
||||
|
||||
/* Exclusive OR the terms in the table (top down) */ |
||||
crc = (ushort)(crc ^ (crc << 1) ^ (crc << 2) ^ (crc << 3) ^ (crc << 4) ^ (crc << 5) ^ (crc << 6) ^ (crc << 7)); |
||||
|
||||
/* Combine bits shifted out left hand end */ |
||||
return (byte)((crc & 0xfe) ^ ((crc >> 8) & 1)); |
||||
} |
||||
|
||||
public static byte CRC_Calc_Header(byte[] buffer, int offset, int length) |
||||
{ |
||||
byte crc = 0xff; |
||||
for (var i = offset; i < offset + length; i++) |
||||
crc = CRC_Calc_Header(buffer[i], crc); |
||||
return (byte)~crc; |
||||
} |
||||
|
||||
public static ushort CRC_Calc_Data(byte dataValue, ushort crcValue) |
||||
{ |
||||
var crcLow = (ushort)((crcValue & 0xff) ^ dataValue); |
||||
|
||||
/* Exclusive OR the terms in the table (top down) */ |
||||
return (ushort)((crcValue >> 8) ^ (crcLow << 8) ^ (crcLow << 3) |
||||
^ (crcLow << 12) ^ (crcLow >> 4) |
||||
^ (crcLow & 0x0f) ^ ((crcLow & 0x0f) << 7)); |
||||
} |
||||
|
||||
public static ushort CRC_Calc_Data(byte[] buffer, int offset, int length) |
||||
{ |
||||
ushort crc = 0xffff; |
||||
for (var i = offset; i < offset + length; i++) |
||||
crc = CRC_Calc_Data(buffer[i], crc); |
||||
return (ushort)~crc; |
||||
} |
||||
|
||||
public static int Encode(byte[] buffer, int offset, BacnetMstpFrameTypes frameType, byte destinationAddress, byte sourceAddress, int msgLength) |
||||
{ |
||||
buffer[offset + 0] = MSTP_PREAMBLE1; |
||||
buffer[offset + 1] = MSTP_PREAMBLE2; |
||||
buffer[offset + 2] = (byte)frameType; |
||||
buffer[offset + 3] = destinationAddress; |
||||
buffer[offset + 4] = sourceAddress; |
||||
buffer[offset + 5] = (byte)((msgLength & 0xFF00) >> 8); |
||||
buffer[offset + 6] = (byte)((msgLength & 0x00FF) >> 0); |
||||
buffer[offset + 7] = CRC_Calc_Header(buffer, offset + 2, 5); |
||||
if (msgLength > 0) |
||||
{ |
||||
//calculate data crc |
||||
var dataCrc = CRC_Calc_Data(buffer, offset + 8, msgLength); |
||||
buffer[offset + 8 + msgLength + 0] = (byte)(dataCrc & 0xFF); //LSB first! |
||||
buffer[offset + 8 + msgLength + 1] = (byte)(dataCrc >> 8); |
||||
} |
||||
//optional pad (0xFF) |
||||
return MSTP_HEADER_LENGTH + msgLength + (msgLength > 0 ? 2 : 0); |
||||
} |
||||
|
||||
public static int Decode(byte[] buffer, int offset, int maxLength, out BacnetMstpFrameTypes frameType, out byte destinationAddress, out byte sourceAddress, out int msgLength) |
||||
{ |
||||
if (maxLength < MSTP_HEADER_LENGTH) //not enough data |
||||
{ |
||||
frameType = BacnetMstpFrameTypes.FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY; // don't care |
||||
destinationAddress = sourceAddress = 0; // don't care |
||||
msgLength = 0; |
||||
return -1; |
||||
} |
||||
|
||||
frameType = (BacnetMstpFrameTypes)buffer[offset + 2]; |
||||
destinationAddress = buffer[offset + 3]; |
||||
sourceAddress = buffer[offset + 4]; |
||||
msgLength = (buffer[offset + 5] << 8) | (buffer[offset + 6] << 0); |
||||
var crcHeader = buffer[offset + 7]; |
||||
ushort crcData = 0; |
||||
|
||||
if (msgLength > 0) |
||||
{ |
||||
if (offset + 8 + msgLength + 1 >= buffer.Length) |
||||
return -1; |
||||
|
||||
crcData = (ushort)((buffer[offset + 8 + msgLength + 1] << 8) | (buffer[offset + 8 + msgLength + 0] << 0)); |
||||
} |
||||
|
||||
if (buffer[offset + 0] != MSTP_PREAMBLE1) |
||||
return -1; |
||||
|
||||
if (buffer[offset + 1] != MSTP_PREAMBLE2) |
||||
return -1; |
||||
|
||||
if (CRC_Calc_Header(buffer, offset + 2, 5) != crcHeader) |
||||
return -1; |
||||
|
||||
if (msgLength > 0 && maxLength >= MSTP_HEADER_LENGTH + msgLength + 2 && CRC_Calc_Data(buffer, offset + 8, msgLength) != crcData) |
||||
return -1; |
||||
|
||||
return 8 + msgLength + (msgLength > 0 ? 2 : 0); |
||||
} |
||||
} |
@ -1,134 +0,0 @@
@@ -1,134 +0,0 @@
|
||||
namespace System.IO.BACnet.Serialize; |
||||
|
||||
public class NPDU |
||||
{ |
||||
public const byte BACNET_PROTOCOL_VERSION = 1; |
||||
|
||||
public static BacnetNpduControls DecodeFunction(byte[] buffer, int offset) |
||||
{ |
||||
if (buffer[offset + 0] != BACNET_PROTOCOL_VERSION) return 0; |
||||
return (BacnetNpduControls)buffer[offset + 1]; |
||||
} |
||||
|
||||
public static int Decode(byte[] buffer, int offset, out BacnetNpduControls function, out BacnetAddress destination, |
||||
out BacnetAddress source, out byte hopCount, out BacnetNetworkMessageTypes networkMsgType, out ushort vendorId) |
||||
{ |
||||
var orgOffset = offset; |
||||
|
||||
offset++; |
||||
function = (BacnetNpduControls)buffer[offset++]; |
||||
|
||||
destination = null; |
||||
if ((function & BacnetNpduControls.DestinationSpecified) == BacnetNpduControls.DestinationSpecified) |
||||
{ |
||||
destination = new BacnetAddress(BacnetAddressTypes.None, (ushort)((buffer[offset++] << 8) | (buffer[offset++] << 0)), null); |
||||
int adrLen = buffer[offset++]; |
||||
if (adrLen > 0) |
||||
{ |
||||
destination.adr = new byte[adrLen]; |
||||
for (var i = 0; i < destination.adr.Length; i++) |
||||
destination.adr[i] = buffer[offset++]; |
||||
} |
||||
} |
||||
|
||||
source = null; |
||||
if ((function & BacnetNpduControls.SourceSpecified) == BacnetNpduControls.SourceSpecified) |
||||
{ |
||||
source = new BacnetAddress(BacnetAddressTypes.None, (ushort)((buffer[offset++] << 8) | (buffer[offset++] << 0)), null); |
||||
int adrLen = buffer[offset++]; |
||||
if (adrLen > 0) |
||||
{ |
||||
source.adr = new byte[adrLen]; |
||||
for (var i = 0; i < source.adr.Length; i++) |
||||
source.adr[i] = buffer[offset++]; |
||||
} |
||||
} |
||||
|
||||
hopCount = 0; |
||||
if ((function & BacnetNpduControls.DestinationSpecified) == BacnetNpduControls.DestinationSpecified) |
||||
{ |
||||
hopCount = buffer[offset++]; |
||||
} |
||||
|
||||
networkMsgType = BacnetNetworkMessageTypes.NETWORK_MESSAGE_WHO_IS_ROUTER_TO_NETWORK; |
||||
vendorId = 0; |
||||
if (function.HasFlag(BacnetNpduControls.NetworkLayerMessage)) |
||||
{ |
||||
networkMsgType = (BacnetNetworkMessageTypes)buffer[offset++]; |
||||
if ((byte)networkMsgType >= 0x80) |
||||
{ |
||||
vendorId = (ushort)((buffer[offset++] << 8) | (buffer[offset++] << 0)); |
||||
} |
||||
//DAL - this originally made no sense as the higher level code would just ignore network messages |
||||
// else if (networkMsgType == BacnetNetworkMessageTypes.NETWORK_MESSAGE_WHO_IS_ROUTER_TO_NETWORK) |
||||
// offset += 2; // Don't care about destination network adress |
||||
} |
||||
|
||||
if (buffer[orgOffset + 0] != BACNET_PROTOCOL_VERSION) |
||||
return -1; |
||||
|
||||
return offset - orgOffset; |
||||
} |
||||
|
||||
public static void Encode(EncodeBuffer buffer, BacnetNpduControls function, BacnetAddress destination, |
||||
BacnetAddress source, byte hopCount, BacnetNetworkMessageTypes networkMsgType, ushort vendorId) |
||||
{ |
||||
Encode(buffer, function, destination, source, hopCount); |
||||
|
||||
if (function.HasFlag(BacnetNpduControls.NetworkLayerMessage)) // sure it is, otherwise the other Encode is used |
||||
{ |
||||
buffer.buffer[buffer.offset++] = (byte)networkMsgType; |
||||
if ((byte)networkMsgType >= 0x80) // who used this ??? sure nobody ! |
||||
{ |
||||
buffer.buffer[buffer.offset++] = (byte)((vendorId & 0xFF00) >> 8); |
||||
buffer.buffer[buffer.offset++] = (byte)((vendorId & 0x00FF) >> 0); |
||||
} |
||||
} |
||||
} |
||||
|
||||
public static void Encode(EncodeBuffer buffer, BacnetNpduControls function, BacnetAddress destination, |
||||
BacnetAddress source = null, byte hopCount = 0xFF) |
||||
{ |
||||
// Modif FC |
||||
var hasDestination = destination != null && destination.net > 0; // && destination.net != 0xFFFF; |
||||
var hasSource = source != null && source.net > 0 && source.net != 0xFFFF; |
||||
|
||||
buffer.buffer[buffer.offset++] = BACNET_PROTOCOL_VERSION; |
||||
buffer.buffer[buffer.offset++] = (byte)(function | (hasDestination ? BacnetNpduControls.DestinationSpecified : 0) | (hasSource ? BacnetNpduControls.SourceSpecified : 0)); |
||||
|
||||
if (hasDestination) |
||||
{ |
||||
buffer.buffer[buffer.offset++] = (byte)((destination.net & 0xFF00) >> 8); |
||||
buffer.buffer[buffer.offset++] = (byte)((destination.net & 0x00FF) >> 0); |
||||
|
||||
if (destination.net == 0xFFFF) //patch by F. Chaxel |
||||
buffer.buffer[buffer.offset++] = 0; |
||||
else |
||||
{ |
||||
buffer.buffer[buffer.offset++] = (byte)destination.adr.Length; |
||||
if (destination.adr.Length > 0) |
||||
{ |
||||
foreach (var t in destination.adr) |
||||
buffer.buffer[buffer.offset++] = t; |
||||
} |
||||
} |
||||
} |
||||
|
||||
if (hasSource) |
||||
{ |
||||
buffer.buffer[buffer.offset++] = (byte)((source.net & 0xFF00) >> 8); |
||||
buffer.buffer[buffer.offset++] = (byte)((source.net & 0x00FF) >> 0); |
||||
buffer.buffer[buffer.offset++] = (byte)source.adr.Length; |
||||
if (source.adr.Length > 0) |
||||
{ |
||||
foreach (var t in source.adr) |
||||
buffer.buffer[buffer.offset++] = t; |
||||
} |
||||
} |
||||
|
||||
if (hasDestination) |
||||
{ |
||||
buffer.buffer[buffer.offset++] = hopCount; |
||||
} |
||||
} |
||||
} |
@ -1,67 +0,0 @@
@@ -1,67 +0,0 @@
|
||||
namespace System.IO.BACnet.Serialize; |
||||
|
||||
public class PTP |
||||
{ |
||||
public const byte PTP_PREAMBLE1 = 0x55; |
||||
public const byte PTP_PREAMBLE2 = 0xFF; |
||||
public const byte PTP_GREETING_PREAMBLE1 = 0x42; |
||||
public const byte PTP_GREETING_PREAMBLE2 = 0x41; |
||||
public const BacnetMaxAdpu PTP_MAX_APDU = BacnetMaxAdpu.MAX_APDU480; |
||||
public const byte PTP_HEADER_LENGTH = 6; |
||||
|
||||
public static int Encode(byte[] buffer, int offset, BacnetPtpFrameTypes frameType, int msgLength) |
||||
{ |
||||
buffer[offset + 0] = PTP_PREAMBLE1; |
||||
buffer[offset + 1] = PTP_PREAMBLE2; |
||||
buffer[offset + 2] = (byte)frameType; |
||||
buffer[offset + 3] = (byte)((msgLength & 0xFF00) >> 8); |
||||
buffer[offset + 4] = (byte)((msgLength & 0x00FF) >> 0); |
||||
buffer[offset + 5] = MSTP.CRC_Calc_Header(buffer, offset + 2, 3); |
||||
if (msgLength > 0) |
||||
{ |
||||
//calculate data crc |
||||
var dataCrc = MSTP.CRC_Calc_Data(buffer, offset + 6, msgLength); |
||||
buffer[offset + 6 + msgLength + 0] = (byte)(dataCrc & 0xFF); //LSB first! |
||||
buffer[offset + 6 + msgLength + 1] = (byte)(dataCrc >> 8); |
||||
} |
||||
return PTP_HEADER_LENGTH + msgLength + (msgLength > 0 ? 2 : 0); |
||||
} |
||||
|
||||
public static int Decode(byte[] buffer, int offset, int maxLength, out BacnetPtpFrameTypes frameType, out int msgLength) |
||||
{ |
||||
if (maxLength < PTP_HEADER_LENGTH) // not enough data |
||||
{ |
||||
frameType = BacnetPtpFrameTypes.FRAME_TYPE_CONNECT_REQUEST; // don't care |
||||
msgLength = 0; |
||||
return -1; //not enough data |
||||
} |
||||
|
||||
frameType = (BacnetPtpFrameTypes)buffer[offset + 2]; |
||||
msgLength = (buffer[offset + 3] << 8) | (buffer[offset + 4] << 0); |
||||
var crcHeader = buffer[offset + 5]; |
||||
ushort crcData = 0; |
||||
|
||||
if (msgLength > 0) |
||||
{ |
||||
if (offset + 6 + msgLength + 1 >= buffer.Length) |
||||
return -1; |
||||
|
||||
crcData = (ushort)((buffer[offset + 6 + msgLength + 1] << 8) | (buffer[offset + 6 + msgLength + 0] << 0)); |
||||
} |
||||
|
||||
if (buffer[offset + 0] != PTP_PREAMBLE1) |
||||
return -1; |
||||
|
||||
if (buffer[offset + 1] != PTP_PREAMBLE2) |
||||
return -1; |
||||
|
||||
if (MSTP.CRC_Calc_Header(buffer, offset + 2, 3) != crcHeader) |
||||
return -1; |
||||
|
||||
if (msgLength > 0 && maxLength >= PTP_HEADER_LENGTH + msgLength + 2 && MSTP.CRC_Calc_Data(buffer, offset + 6, msgLength) != crcData) |
||||
return -1; |
||||
|
||||
return 8 + msgLength + (msgLength > 0 ? 2 : 0); |
||||
} |
||||
|
||||
} |
File diff suppressed because it is too large
Load Diff
@ -1,459 +0,0 @@
@@ -1,459 +0,0 @@
|
||||
/************************************************************************** |
||||
* MIT License |
||||
* |
||||
* Copyright (C) 2014 Morten Kvistgaard <mk@pch-engineering.dk> |
||||
* |
||||
* Permission is hereby granted, free of charge, to any person obtaining |
||||
* a copy of this software and associated documentation files (the |
||||
* "Software"), to deal in the Software without restriction, including |
||||
* without limitation the rights to use, copy, modify, merge, publish, |
||||
* distribute, sublicense, and/or sell copies of the Software, and to |
||||
* permit persons to whom the Software is furnished to do so, subject to |
||||
* the following conditions: |
||||
* |
||||
* The above copyright notice and this permission notice shall be included |
||||
* in all copies or substantial portions of the Software. |
||||
* |
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY |
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
* |
||||
*********************************************************************/ |
||||
|
||||
namespace System.IO.BACnet.Storage; |
||||
|
||||
/// <summary> |
||||
/// This is a basic example of a BACNet storage. This one is XML based. It has no fancy optimizing or anything. |
||||
/// </summary> |
||||
[Serializable] |
||||
public class DeviceStorage |
||||
{ |
||||
[XmlIgnore] |
||||
public uint DeviceId { get; set; } |
||||
|
||||
public delegate void ChangeOfValueHandler(DeviceStorage sender, BacnetObjectId objectId, BacnetPropertyIds propertyId, uint arrayIndex, IList<BacnetValue> value); |
||||
public event ChangeOfValueHandler ChangeOfValue; |
||||
public delegate void ReadOverrideHandler(BacnetObjectId objectId, BacnetPropertyIds propertyId, uint arrayIndex, out IList<BacnetValue> value, out ErrorCodes status, out bool handled); |
||||
public event ReadOverrideHandler ReadOverride; |
||||
public delegate void WriteOverrideHandler(BacnetObjectId objectId, BacnetPropertyIds propertyId, uint arrayIndex, IList<BacnetValue> value, out ErrorCodes status, out bool handled); |
||||
public event WriteOverrideHandler WriteOverride; |
||||
|
||||
public Object[] Objects { get; set; } |
||||
|
||||
public DeviceStorage() |
||||
{ |
||||
DeviceId = (uint)new Random().Next(); |
||||
Objects = new Object[0]; |
||||
} |
||||
|
||||
public Property FindProperty(BacnetObjectId objectId, BacnetPropertyIds propertyId) |
||||
{ |
||||
//liniear search |
||||
var obj = FindObject(objectId); |
||||
return FindProperty(obj, propertyId); |
||||
} |
||||
|
||||
private static Property FindProperty(Object obj, BacnetPropertyIds propertyId) |
||||
{ |
||||
//liniear search |
||||
return obj?.Properties.FirstOrDefault(p => p.Id == propertyId); |
||||
} |
||||
|
||||
private Object FindObject(BacnetObjectTypes objectType) |
||||
{ |
||||
//liniear search |
||||
return Objects.FirstOrDefault(obj => obj.Type == objectType); |
||||
} |
||||
|
||||
public Object FindObject(BacnetObjectId objectId) |
||||
{ |
||||
//liniear search |
||||
return Objects.FirstOrDefault(obj => obj.Type == objectId.type && obj.Instance == objectId.instance); |
||||
} |
||||
|
||||
public enum ErrorCodes |
||||
{ |
||||
Good = 0, |
||||
GenericError = -1, |
||||
NotExist = -2, |
||||
NotForMe = -3, |
||||
WriteAccessDenied = -4, |
||||
UnknownObject = -5, |
||||
UnknownProperty = -6 |
||||
} |
||||
|
||||
public int ReadPropertyValue(BacnetObjectId objectId, BacnetPropertyIds propertyId) |
||||
{ |
||||
if (ReadProperty(objectId, propertyId, Serialize.ASN1.BACNET_ARRAY_ALL, out IList<BacnetValue> value) != ErrorCodes.Good) |
||||
return 0; |
||||
|
||||
if (value == null || value.Count < 1) |
||||
return 0; |
||||
|
||||
return (int)Convert.ChangeType(value[0].Value, typeof(int)); |
||||
} |
||||
|
||||
public ErrorCodes ReadProperty(BacnetObjectId objectId, BacnetPropertyIds propertyId, uint arrayIndex, out IList<BacnetValue> value) |
||||
{ |
||||
value = new BacnetValue[0]; |
||||
|
||||
//wildcard device_id |
||||
if (objectId.type == BacnetObjectTypes.OBJECT_DEVICE && objectId.instance >= Serialize.ASN1.BACNET_MAX_INSTANCE) |
||||
objectId.instance = DeviceId; |
||||
|
||||
//overrides |
||||
if (ReadOverride != null) |
||||
{ |
||||
ReadOverride(objectId, propertyId, arrayIndex, out value, out ErrorCodes status, out bool handled); |
||||
if (handled) |
||||
return status; |
||||
} |
||||
|
||||
//find in storage |
||||
var obj = FindObject(objectId); |
||||
if (obj == null) |
||||
return ErrorCodes.UnknownObject; |
||||
|
||||
//object found now find property |
||||
Godot.GD.Print("object "+objectId+"|property "+propertyId); |
||||
var p = FindProperty(objectId, propertyId); |
||||
if (p == null) |
||||
return ErrorCodes.NotExist; |
||||
|
||||
//get value ... check for array index |
||||
if (arrayIndex == 0) |
||||
{ |
||||
value = new[] { new BacnetValue(BacnetApplicationTags.BACNET_APPLICATION_TAG_UNSIGNED_INT, (uint)p.BacnetValue.Count) }; |
||||
} |
||||
else if (arrayIndex != Serialize.ASN1.BACNET_ARRAY_ALL) |
||||
{ |
||||
value = new[] { p.BacnetValue[(int)arrayIndex - 1] }; |
||||
} |
||||
else |
||||
{ |
||||
value = p.BacnetValue; |
||||
} |
||||
Godot.GD.Print("p "+p.BacnetValue.Count()); |
||||
|
||||
return ErrorCodes.Good; |
||||
} |
||||
|
||||
public void ReadPropertyMultiple(BacnetObjectId objectId, ICollection<BacnetPropertyReference> properties, out IList<BacnetPropertyValue> values) |
||||
{ |
||||
var valuesRet = new List<BacnetPropertyValue>(); |
||||
|
||||
foreach (var entry in properties) |
||||
{ |
||||
var newEntry = new BacnetPropertyValue { property = entry }; |
||||
|
||||
switch (ReadProperty(objectId, (BacnetPropertyIds)entry.propertyIdentifier, entry.propertyArrayIndex, out newEntry.value)) |
||||
{ |
||||
case ErrorCodes.UnknownObject: |
||||
newEntry.value = new[] |
||||
{ |
||||
new BacnetValue(BacnetApplicationTags.BACNET_APPLICATION_TAG_ERROR, |
||||
new BacnetError(BacnetErrorClasses.ERROR_CLASS_OBJECT, BacnetErrorCodes.ERROR_CODE_UNKNOWN_OBJECT)) |
||||
}; |
||||
break; |
||||
case ErrorCodes.NotExist: |
||||
newEntry.value = new[] |
||||
{ |
||||
new BacnetValue(BacnetApplicationTags.BACNET_APPLICATION_TAG_ERROR, |
||||
new BacnetError(BacnetErrorClasses.ERROR_CLASS_PROPERTY, BacnetErrorCodes.ERROR_CODE_UNKNOWN_PROPERTY)) |
||||
}; |
||||
break; |
||||
} |
||||
|
||||
valuesRet.Add(newEntry); |
||||
} |
||||
|
||||
values = valuesRet; |
||||
} |
||||
|
||||
public bool ReadPropertyAll(BacnetObjectId objectId, out IList<BacnetPropertyValue> values) |
||||
{ |
||||
//find |
||||
var obj = FindObject(objectId); |
||||
if (obj == null) |
||||
{ |
||||
values = null; |
||||
return false; |
||||
} |
||||
|
||||
//build |
||||
var propertyValues = new BacnetPropertyValue[obj.Properties.Length]; |
||||
for (var i = 0; i < obj.Properties.Length; i++) |
||||
{ |
||||
var newEntry = new BacnetPropertyValue |
||||
{ |
||||
property = new BacnetPropertyReference((uint)obj.Properties[i].Id, Serialize.ASN1.BACNET_ARRAY_ALL) |
||||
}; |
||||
|
||||
if (ReadProperty(objectId, obj.Properties[i].Id, Serialize.ASN1.BACNET_ARRAY_ALL, out newEntry.value) != ErrorCodes.Good) |
||||
{ |
||||
var bacnetError = new BacnetError(BacnetErrorClasses.ERROR_CLASS_OBJECT, BacnetErrorCodes.ERROR_CODE_UNKNOWN_PROPERTY); |
||||
newEntry.value = new[] { new BacnetValue(BacnetApplicationTags.BACNET_APPLICATION_TAG_ERROR, bacnetError) }; |
||||
} |
||||
|
||||
propertyValues[i] = newEntry; |
||||
} |
||||
|
||||
values = propertyValues; |
||||
return true; |
||||
} |
||||
|
||||
public void WritePropertyValue(BacnetObjectId objectId, BacnetPropertyIds propertyId, int value) |
||||
{ |
||||
//get existing type |
||||
if (ReadProperty(objectId, propertyId, Serialize.ASN1.BACNET_ARRAY_ALL, out IList<BacnetValue> readValues) != ErrorCodes.Good) |
||||
return; |
||||
|
||||
if (readValues == null || readValues.Count == 0) |
||||
return; |
||||
|
||||
//write |
||||
WriteProperty(objectId, propertyId, Serialize.ASN1.BACNET_ARRAY_ALL, new[] |
||||
{ |
||||
new BacnetValue(readValues[0].Tag, Convert.ChangeType(value, readValues[0].Value.GetType())) |
||||
}); |
||||
} |
||||
|
||||
|
||||
public void WriteProperty(BacnetObjectId objectId, BacnetPropertyIds propertyId, BacnetValue value) |
||||
{ |
||||
WriteProperty(objectId, propertyId, Serialize.ASN1.BACNET_ARRAY_ALL, new[] { value }); |
||||
} |
||||
|
||||
public ErrorCodes WriteProperty(BacnetObjectId objectId, BacnetPropertyIds propertyId, uint arrayIndex, IList<BacnetValue> value, bool addIfNotExits = false) |
||||
{ |
||||
//wildcard device_id |
||||
if (objectId.type == BacnetObjectTypes.OBJECT_DEVICE && objectId.instance >= Serialize.ASN1.BACNET_MAX_INSTANCE) |
||||
objectId.instance = DeviceId; |
||||
|
||||
//overrides |
||||
if (WriteOverride != null) |
||||
{ |
||||
WriteOverride(objectId, propertyId, arrayIndex, value, out ErrorCodes status, out bool handled); |
||||
if (handled) |
||||
return status; |
||||
} |
||||
|
||||
//find |
||||
var p = FindProperty(objectId, propertyId); |
||||
if (p == null) |
||||
{ |
||||
if (!addIfNotExits) return ErrorCodes.NotExist; |
||||
|
||||
//add obj |
||||
var obj = FindObject(objectId); |
||||
if (obj == null) |
||||
{ |
||||
obj = new Object |
||||
{ |
||||
Type = objectId.type, |
||||
Instance = objectId.instance |
||||
}; |
||||
var arr = Objects; |
||||
Array.Resize(ref arr, arr.Length + 1); |
||||
arr[arr.Length - 1] = obj; |
||||
Objects = arr; |
||||
} |
||||
|
||||
//add property |
||||
p = new Property { Id = propertyId }; |
||||
var props = obj.Properties; |
||||
Array.Resize(ref props, props.Length + 1); |
||||
props[props.Length - 1] = p; |
||||
obj.Properties = props; |
||||
} |
||||
|
||||
//set type if needed |
||||
if (p.Tag == BacnetApplicationTags.BACNET_APPLICATION_TAG_NULL && value != null) |
||||
{ |
||||
foreach (var v in value) |
||||
{ |
||||
if (v.Tag == BacnetApplicationTags.BACNET_APPLICATION_TAG_NULL) |
||||
continue; |
||||
|
||||
p.Tag = v.Tag; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
//write |
||||
p.BacnetValue = value; |
||||
|
||||
//send event ... for subscriptions |
||||
ChangeOfValue?.Invoke(this, objectId, propertyId, arrayIndex, value); |
||||
|
||||
return ErrorCodes.Good; |
||||
} |
||||
|
||||
// Write PROP_PRESENT_VALUE or PROP_RELINQUISH_DEFAULT in an object with a 16 level PROP_PRIORITY_ARRAY (BACNET_APPLICATION_TAG_NULL) |
||||
public ErrorCodes WriteCommandableProperty(BacnetObjectId objectId, BacnetPropertyIds propertyId, BacnetValue value, uint priority) |
||||
{ |
||||
|
||||
if (propertyId != BacnetPropertyIds.PROP_PRESENT_VALUE) |
||||
return ErrorCodes.NotForMe; |
||||
|
||||
var presentvalue = FindProperty(objectId, BacnetPropertyIds.PROP_PRESENT_VALUE); |
||||
if (presentvalue == null) |
||||
return ErrorCodes.NotForMe; |
||||
|
||||
var relinquish = FindProperty(objectId, BacnetPropertyIds.PROP_RELINQUISH_DEFAULT); |
||||
if (relinquish == null) |
||||
return ErrorCodes.NotForMe; |
||||
|
||||
var outOfService = FindProperty(objectId, BacnetPropertyIds.PROP_OUT_OF_SERVICE); |
||||
if (outOfService == null) |
||||
return ErrorCodes.NotForMe; |
||||
|
||||
var array = FindProperty(objectId, BacnetPropertyIds.PROP_PRIORITY_ARRAY); |
||||
if (array == null) |
||||
return ErrorCodes.NotForMe; |
||||
|
||||
var errorcode = ErrorCodes.GenericError; |
||||
|
||||
try |
||||
{ |
||||
// If PROP_OUT_OF_SERVICE=True, value is accepted as is : http://www.bacnetwiki.com/wiki/index.php?title=Priority_Array |
||||
if ((bool)outOfService.BacnetValue[0].Value && propertyId == BacnetPropertyIds.PROP_PRESENT_VALUE) |
||||
{ |
||||
WriteProperty(objectId, BacnetPropertyIds.PROP_PRESENT_VALUE, value); |
||||
return ErrorCodes.Good; |
||||
} |
||||
|
||||
IList<BacnetValue> valueArray = null; |
||||
|
||||
// Thank's to Steve Karg |
||||
// The 135-2016 text: |
||||
// 19.2.2 Application Priority Assignments |
||||
// All commandable objects within a device shall be configurable to accept writes to all priorities except priority 6 |
||||
if (priority == 6) |
||||
return ErrorCodes.WriteAccessDenied; |
||||
|
||||
// http://www.chipkin.com/changing-the-bacnet-present-value-or-why-the-present-value-doesn%E2%80%99t-change/ |
||||
// Write Property PROP_PRESENT_VALUE : A value is placed in the PROP_PRIORITY_ARRAY |
||||
if (propertyId == BacnetPropertyIds.PROP_PRESENT_VALUE) |
||||
{ |
||||
errorcode = ErrorCodes.Good; |
||||
|
||||
valueArray = array.BacnetValue; |
||||
if (value.Value == null) |
||||
valueArray[(int)priority - 1] = new BacnetValue(null); |
||||
else |
||||
valueArray[(int)priority - 1] = value; |
||||
array.BacnetValue = valueArray; |
||||
} |
||||
|
||||
// Look on the priority Array to find the first value to be set in PROP_PRESENT_VALUE |
||||
if (errorcode == ErrorCodes.Good) |
||||
{ |
||||
|
||||
var done = false; |
||||
for (var i = 0; i < 16; i++) |
||||
{ |
||||
if (valueArray[i].Value == null) |
||||
continue; |
||||
|
||||
WriteProperty(objectId, BacnetPropertyIds.PROP_PRESENT_VALUE, valueArray[i]); |
||||
done = true; |
||||
break; |
||||
} |
||||
|
||||
if (done == false) // Nothing in the array : PROP_PRESENT_VALUE = PROP_RELINQUISH_DEFAULT |
||||
{ |
||||
var defaultValue = relinquish.BacnetValue; |
||||
WriteProperty(objectId, BacnetPropertyIds.PROP_PRESENT_VALUE, defaultValue[0]); |
||||
} |
||||
} |
||||
} |
||||
catch |
||||
{ |
||||
errorcode = ErrorCodes.GenericError; |
||||
} |
||||
|
||||
return errorcode; |
||||
} |
||||
|
||||
public ErrorCodes[] WritePropertyMultiple(BacnetObjectId objectId, ICollection<BacnetPropertyValue> values) |
||||
{ |
||||
return values |
||||
.Select(v => WriteProperty(objectId, (BacnetPropertyIds)v.property.propertyIdentifier, v.property.propertyArrayIndex, v.value)) |
||||
.ToArray(); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Store the class, as XML file |
||||
/// </summary> |
||||
/// <param name="path"></param> |
||||
public void Save(string path) |
||||
{ |
||||
var s = new XmlSerializer(typeof(DeviceStorage)); |
||||
using var fs = new FileStream(path, FileMode.Create, FileAccess.Write); |
||||
s.Serialize(fs, this); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Load XML values into class |
||||
/// </summary> |
||||
/// <param name="path">Embedded or external file</param> |
||||
/// <param name="deviceId">Optional deviceId other than the one in the Xml file</param> |
||||
/// <returns></returns> |
||||
public static DeviceStorage Load(string path, uint? deviceId = null) |
||||
{ |
||||
StreamReader textStreamReader; |
||||
|
||||
var assembly = Assembly.GetCallingAssembly(); |
||||
|
||||
try |
||||
{ |
||||
// check if the xml file is an embedded resource |
||||
textStreamReader = new StreamReader(assembly.GetManifestResourceStream(path)); |
||||
} |
||||
catch |
||||
{ |
||||
// if not check the external file |
||||
if (!File.Exists(path)) |
||||
throw new Exception("No AppSettings found"); |
||||
|
||||
textStreamReader = new StreamReader(path); |
||||
} |
||||
|
||||
var s = new XmlSerializer(typeof(DeviceStorage)); |
||||
|
||||
using (textStreamReader) |
||||
{ |
||||
var ret = (DeviceStorage)s.Deserialize(textStreamReader); |
||||
|
||||
//set device_id |
||||
var obj = ret.FindObject(BacnetObjectTypes.OBJECT_DEVICE); |
||||
if (obj != null) |
||||
ret.DeviceId = obj.Instance; |
||||
|
||||
// use the deviceId in the Xml file or another one |
||||
if (!deviceId.HasValue) |
||||
return ret; |
||||
|
||||
ret.DeviceId = deviceId.Value; |
||||
if (obj == null) |
||||
return ret; |
||||
|
||||
// change the value |
||||
obj.Instance = deviceId.Value; |
||||
IList<BacnetValue> val = new[] |
||||
{ |
||||
new BacnetValue(BacnetApplicationTags.BACNET_APPLICATION_TAG_OBJECT_ID, $"OBJECT_DEVICE:{deviceId.Value}") |
||||
}; |
||||
|
||||
ret.WriteProperty(new BacnetObjectId(BacnetObjectTypes.OBJECT_DEVICE, |
||||
Serialize.ASN1.BACNET_MAX_INSTANCE), BacnetPropertyIds.PROP_OBJECT_IDENTIFIER, 1, val, true); |
||||
|
||||
return ret; |
||||
} |
||||
} |
||||
} |
@ -1,18 +0,0 @@
@@ -1,18 +0,0 @@
|
||||
namespace System.IO.BACnet.Storage; |
||||
|
||||
[Serializable] |
||||
public class Object |
||||
{ |
||||
[XmlAttribute] |
||||
public BacnetObjectTypes Type { get; set; } |
||||
|
||||
[XmlAttribute] |
||||
public uint Instance { get; set; } |
||||
|
||||
public Property[] Properties { get; set; } |
||||
|
||||
public Object() |
||||
{ |
||||
Properties = new Property[0]; |
||||
} |
||||
} |
@ -1,127 +0,0 @@
@@ -1,127 +0,0 @@
|
||||
namespace System.IO.BACnet.Storage; |
||||
|
||||
[Serializable] |
||||
public class Property |
||||
{ |
||||
[XmlIgnore] |
||||
public BacnetPropertyIds Id { get; set; } |
||||
|
||||
[XmlAttribute("Id")] |
||||
public string IdText |
||||
{ |
||||
get |
||||
{ |
||||
return Id.ToString(); |
||||
} |
||||
set |
||||
{ |
||||
Id = (BacnetPropertyIds)Enum.Parse(typeof(BacnetPropertyIds), value); |
||||
} |
||||
} |
||||
|
||||
[XmlAttribute] |
||||
public BacnetApplicationTags Tag { get; set; } |
||||
|
||||
[XmlElement] |
||||
public string[] Value { get; set; } |
||||
|
||||
public static BacnetValue DeserializeValue(string value, BacnetApplicationTags type) |
||||
{ |
||||
switch (type) |
||||
{ |
||||
case BacnetApplicationTags.BACNET_APPLICATION_TAG_NULL: |
||||
return value == "" |
||||
? new BacnetValue(type, null) |
||||
: new BacnetValue(value); |
||||
case BacnetApplicationTags.BACNET_APPLICATION_TAG_BOOLEAN: |
||||
return new BacnetValue(type, bool.Parse(value)); |
||||
case BacnetApplicationTags.BACNET_APPLICATION_TAG_UNSIGNED_INT: |
||||
return new BacnetValue(type, uint.Parse(value)); |
||||
case BacnetApplicationTags.BACNET_APPLICATION_TAG_SIGNED_INT: |
||||
return new BacnetValue(type, int.Parse(value)); |
||||
case BacnetApplicationTags.BACNET_APPLICATION_TAG_REAL: |
||||
return new BacnetValue(type, float.Parse(value, CultureInfo.InvariantCulture)); |
||||
case BacnetApplicationTags.BACNET_APPLICATION_TAG_DOUBLE: |
||||
return new BacnetValue(type, double.Parse(value, CultureInfo.InvariantCulture)); |
||||
case BacnetApplicationTags.BACNET_APPLICATION_TAG_OCTET_STRING: |
||||
try |
||||
{ |
||||
return new BacnetValue(type, Convert.FromBase64String(value)); |
||||
} |
||||
catch |
||||
{ |
||||
return new BacnetValue(type, value); |
||||
} |
||||
case BacnetApplicationTags.BACNET_APPLICATION_TAG_CONTEXT_SPECIFIC_DECODED: |
||||
try |
||||
{ |
||||
return new BacnetValue(type, Convert.FromBase64String(value)); |
||||
} |
||||
catch |
||||
{ |
||||
return new BacnetValue(type, value); |
||||
} |
||||
case BacnetApplicationTags.BACNET_APPLICATION_TAG_CHARACTER_STRING: |
||||
return new BacnetValue(type, value); |
||||
case BacnetApplicationTags.BACNET_APPLICATION_TAG_BIT_STRING: |
||||
return new BacnetValue(type, BacnetBitString.Parse(value)); |
||||
case BacnetApplicationTags.BACNET_APPLICATION_TAG_ENUMERATED: |
||||
return new BacnetValue(type, uint.Parse(value)); |
||||
case BacnetApplicationTags.BACNET_APPLICATION_TAG_DATE: |
||||
return new BacnetValue(type, DateTime.Parse(value)); |
||||
case BacnetApplicationTags.BACNET_APPLICATION_TAG_TIME: |
||||
return new BacnetValue(type, DateTime.Parse(value)); |
||||
case BacnetApplicationTags.BACNET_APPLICATION_TAG_OBJECT_ID: |
||||
return new BacnetValue(type, BacnetObjectId.Parse(value)); |
||||
case BacnetApplicationTags.BACNET_APPLICATION_TAG_READ_ACCESS_SPECIFICATION: |
||||
return new BacnetValue(type, BacnetReadAccessSpecification.Parse(value)); |
||||
case BacnetApplicationTags.BACNET_APPLICATION_TAG_OBJECT_PROPERTY_REFERENCE: |
||||
return new BacnetValue(type, BacnetDeviceObjectPropertyReference.Parse(value)); |
||||
default: |
||||
return new BacnetValue(type, null); |
||||
} |
||||
} |
||||
|
||||
public static string SerializeValue(BacnetValue value, BacnetApplicationTags type) |
||||
{ |
||||
switch (type) |
||||
{ |
||||
case BacnetApplicationTags.BACNET_APPLICATION_TAG_NULL: |
||||
return value.ToString(); // Modif FC |
||||
case BacnetApplicationTags.BACNET_APPLICATION_TAG_REAL: |
||||
return ((float)value.Value).ToString(CultureInfo.InvariantCulture); |
||||
case BacnetApplicationTags.BACNET_APPLICATION_TAG_DOUBLE: |
||||
return ((double)value.Value).ToString(CultureInfo.InvariantCulture); |
||||
case BacnetApplicationTags.BACNET_APPLICATION_TAG_OCTET_STRING: |
||||
return Convert.ToBase64String((byte[])value.Value); |
||||
case BacnetApplicationTags.BACNET_APPLICATION_TAG_CONTEXT_SPECIFIC_DECODED: |
||||
{ |
||||
return value.Value is byte[]? Convert.ToBase64String((byte[])value.Value) |
||||
: string.Join(";", ((BacnetValue[])value.Value) |
||||
.Select(v => SerializeValue(v, v.Tag))); |
||||
} |
||||
default: |
||||
return value.Value.ToString(); |
||||
} |
||||
} |
||||
|
||||
[XmlIgnore] |
||||
public IList<BacnetValue> BacnetValue |
||||
{ |
||||
get |
||||
{ |
||||
if (Value == null) |
||||
return new BacnetValue[0]; |
||||
|
||||
var ret = new BacnetValue[Value.Length]; |
||||
for (var i = 0; i < ret.Length; i++) |
||||
ret[i] = DeserializeValue(Value[i], Tag); |
||||
|
||||
return ret; |
||||
} |
||||
set |
||||
{ |
||||
Value = value.Select(v => SerializeValue(v, Tag)).ToArray(); |
||||
} |
||||
} |
||||
} |
@ -1,351 +0,0 @@
@@ -1,351 +0,0 @@
|
||||
namespace System.IO.BACnet; |
||||
|
||||
// Only some elements here are really tested |
||||
// all FDR, BBMD activities is just a copy/adaptation of my IPv4 code |
||||
// Code for V4 working fine, for V6 sure not before a series of tests |
||||
public class BVLCV6 |
||||
{ |
||||
public const byte BVLL_TYPE_BACNET_IPV6 = 0x82; |
||||
public const byte BVLC_HEADER_LENGTH = 10; // Not all the time, could be 7 for bacnet broadcast |
||||
public const BacnetMaxAdpu BVLC_MAX_APDU = BacnetMaxAdpu.MAX_APDU1476; |
||||
// Contains the rules to accept FRD based on the IP adress |
||||
// If empty it's equal to * , everyone allows |
||||
private readonly List<Regex> _autorizedFDR = new(); |
||||
|
||||
private bool _bbmdFdServiceActivated; |
||||
private readonly List<IPEndPoint> _bbmds = new(); |
||||
private readonly BacnetAddress _broadcastAdd; |
||||
// Two lists for optional BBMD activity |
||||
private readonly List<KeyValuePair<IPEndPoint, DateTime>> _foreignDevices = new(); |
||||
private readonly BacnetIpV6UdpProtocolTransport _myTransport; |
||||
public bool RandomVmac; |
||||
|
||||
public byte[] VMAC = new byte[3]; |
||||
public ILog Log { get; set; } = LogManager.GetLogger<BVLCV6>(); |
||||
|
||||
public BVLCV6(BacnetIpV6UdpProtocolTransport transport, int vMac) |
||||
{ |
||||
_myTransport = transport; |
||||
_broadcastAdd = _myTransport.GetBroadcastAddress(); |
||||
|
||||
if (vMac == -1) |
||||
{ |
||||
RandomVmac = true; |
||||
new Random().NextBytes(VMAC); |
||||
VMAC[0] = (byte)((VMAC[0] & 0x7F) | 0x40); // ensure 01xxxxxx on the High byte |
||||
|
||||
// Open with default interface specified, cannot send it or |
||||
// it will generate an uncheckable continuous local loopback |
||||
if (!_myTransport.LocalEndPoint.ToString().Contains("[::]")) |
||||
SendAddressResolutionRequest(VMAC); |
||||
else |
||||
RandomVmac = false; // back to false avoiding loop back |
||||
} |
||||
else // Device Id is the Vmac Id |
||||
{ |
||||
VMAC[0] = (byte)((vMac >> 16) & 0x3F); // ensure the 2 high bits are 0 on the High byte |
||||
VMAC[1] = (byte)((vMac >> 8) & 0xFF); |
||||
VMAC[2] = (byte)(vMac & 0xFF); |
||||
// unicity is guaranteed by the end user ! |
||||
} |
||||
} |
||||
|
||||
public void AddFDRAutorisationRule(Regex ipRule) |
||||
{ |
||||
_autorizedFDR.Add(ipRule); |
||||
} |
||||
|
||||
// Used to initiate the BBMD & FD behaviour, if BBMD is null it start the FD activity only |
||||
public void AddBBMDPeer(IPEndPoint bbmd) |
||||
{ |
||||
_bbmdFdServiceActivated = true; |
||||
|
||||
if (bbmd == null) |
||||
return; |
||||
|
||||
lock (_bbmds) |
||||
_bbmds.Add(bbmd); |
||||
} |
||||
|
||||
// Add a FD to the table or renew it |
||||
private void RegisterForeignDevice(IPEndPoint sender, int ttl) |
||||
{ |
||||
lock (_foreignDevices) |
||||
{ |
||||
// remove it, if any |
||||
_foreignDevices.Remove(_foreignDevices.Find(item => item.Key.Equals(sender))); |
||||
// TTL + 30s grace period |
||||
var Expiration = DateTime.Now.AddSeconds(ttl + 30); |
||||
// add it |
||||
if (_autorizedFDR.Count == 0) // No rules, accept all |
||||
{ |
||||
_foreignDevices.Add(new KeyValuePair<IPEndPoint, DateTime>(sender, Expiration)); |
||||
return; |
||||
} |
||||
|
||||
if (_autorizedFDR.Any(r => r.Match(sender.Address.ToString()).Success)) |
||||
{ |
||||
_foreignDevices.Add(new KeyValuePair<IPEndPoint, DateTime>(sender, Expiration)); |
||||
return; |
||||
} |
||||
|
||||
Log.Info($"Rejected FDR registration, IP : {sender.Address}"); |
||||
} |
||||
} |
||||
|
||||
// Send a Frame to each registered foreign devices, except the original sender |
||||
private void SendToFDs(byte[] buffer, int msgLength, IPEndPoint epSender = null) |
||||
{ |
||||
lock (_foreignDevices) |
||||
{ |
||||
// remove oldest Device entries (Time expiration > TTL + 30s delay) |
||||
_foreignDevices.Remove(_foreignDevices.Find(item => DateTime.Now > item.Value)); |
||||
// Send to all others, except the original sender |
||||
foreach (var client in _foreignDevices) |
||||
{ |
||||
if (!client.Key.Equals(epSender)) |
||||
_myTransport.Send(buffer, msgLength, client.Key); |
||||
} |
||||
} |
||||
} |
||||
|
||||
// Send a Frame to each registered BBMD |
||||
private void SendToBBMDs(byte[] buffer, int msgLength) |
||||
{ |
||||
lock (_bbmds) |
||||
{ |
||||
foreach (var ep in _bbmds) |
||||
{ |
||||
_myTransport.Send(buffer, msgLength, ep); |
||||
} |
||||
} |
||||
} |
||||
|
||||
// Never tested |
||||
private void Forward_NPDU(byte[] buffer, int msgLength, bool toGlobalBroadcast, IPEndPoint epSender, BacnetAddress bacSender) |
||||
{ |
||||
// Forms the forwarded NPDU from the original (broadcast npdu), and send it to all |
||||
|
||||
// copy, 18 bytes shifted (orignal bvlc header : 7 bytes, new one : 25 bytes) |
||||
var b = new byte[msgLength + 18]; |
||||
// normaly only 'small' frames are present here, so no need to check if it's to big for Udp |
||||
Array.Copy(buffer, 0, b, 18, msgLength); |
||||
|
||||
// 7 bytes for the BVLC Header, with the embedded 6 bytes IP:Port of the original sender |
||||
First7BytesHeaderEncode(b, BacnetBvlcV6Functions.BVLC_FORWARDED_NPDU, msgLength + 18); |
||||
// replace my Vmac by the orignal source vMac |
||||
Array.Copy(bacSender.VMac, 0, b, 4, 3); |
||||
// Add IpV6 endpoint |
||||
Array.Copy(bacSender.adr, 0, b, 7, 18); |
||||
// Send To BBMD |
||||
SendToBBMDs(b, msgLength + 18); |
||||
// Send To FD, except the sender |
||||
SendToFDs(b, msgLength + 18, epSender); |
||||
// Broadcast if required |
||||
if (toGlobalBroadcast) |
||||
{ |
||||
BacnetIpV6UdpProtocolTransport.Convert(_broadcastAdd, out IPEndPoint ep); |
||||
_myTransport.Send(b, msgLength + 18, ep); |
||||
} |
||||
} |
||||
|
||||
private void First7BytesHeaderEncode(byte[] b, BacnetBvlcV6Functions function, int msgLength) |
||||
{ |
||||
b[0] = BVLL_TYPE_BACNET_IPV6; |
||||
b[1] = (byte)function; |
||||
b[2] = (byte)((msgLength & 0xFF00) >> 8); |
||||
b[3] = (byte)((msgLength & 0x00FF) >> 0); |
||||
Array.Copy(VMAC, 0, b, 4, 3); |
||||
} |
||||
|
||||
// Send ack or nack |
||||
private void SendResult(IPEndPoint sender, BacnetBvlcV6Results resultCode) |
||||
{ |
||||
var b = new byte[9]; |
||||
First7BytesHeaderEncode(b, BacnetBvlcV6Functions.BVLC_RESULT, 9); |
||||
b[7] = (byte)(((ushort)resultCode & 0xFF00) >> 8); |
||||
b[8] = (byte)((ushort)resultCode & 0xFF); |
||||
_myTransport.Send(b, 9, sender); |
||||
} |
||||
|
||||
public void SendRegisterAsForeignDevice(IPEndPoint bbmd, short ttl) |
||||
{ |
||||
var b = new byte[9]; |
||||
First7BytesHeaderEncode(b, BacnetBvlcV6Functions.BVLC_REGISTER_FOREIGN_DEVICE, 9); |
||||
b[7] = (byte)((ttl & 0xFF00) >> 8); |
||||
b[8] = (byte)(ttl & 0xFF); |
||||
_myTransport.Send(b, 9, bbmd); |
||||
} |
||||
|
||||
public void SendRemoteWhois(byte[] buffer, IPEndPoint bbmd, int msgLength) |
||||
{ |
||||
// 7 bytes for the BVLC Header |
||||
First7BytesHeaderEncode(buffer, BacnetBvlcV6Functions.BVLC_DISTRIBUTE_BROADCAST_TO_NETWORK, msgLength); |
||||
_myTransport.Send(buffer, msgLength, bbmd); |
||||
} |
||||
|
||||
// Send ack |
||||
private void SendAddressResolutionAck(IPEndPoint sender, byte[] vMacDest, BacnetBvlcV6Functions function) |
||||
{ |
||||
var b = new byte[10]; |
||||
First7BytesHeaderEncode(b, function, 10); |
||||
Array.Copy(vMacDest, 0, b, 7, 3); |
||||
_myTransport.Send(b, 10, sender); |
||||
} |
||||
|
||||
// quite the same frame as the previous one |
||||
private void SendAddressResolutionRequest(byte[] vMacDest) |
||||
{ |
||||
BacnetIpV6UdpProtocolTransport.Convert(_broadcastAdd, out IPEndPoint ep); |
||||
|
||||
var b = new byte[10]; |
||||
First7BytesHeaderEncode(b, BacnetBvlcV6Functions.BVLC_ADDRESS_RESOLUTION, 10); |
||||
Array.Copy(vMacDest, 0, b, 7, 3); |
||||
_myTransport.Send(b, 10, ep); |
||||
} |
||||
|
||||
// Encode is called by internal services if the BBMD is also an active device |
||||
public int Encode(byte[] buffer, int offset, BacnetBvlcV6Functions function, int msgLength, BacnetAddress address) |
||||
{ |
||||
// offset always 0, we are the first after udp |
||||
First7BytesHeaderEncode(buffer, function, msgLength); |
||||
|
||||
// BBMD service |
||||
if (function == BacnetBvlcV6Functions.BVLC_ORIGINAL_BROADCAST_NPDU && _bbmdFdServiceActivated) |
||||
{ |
||||
var me = _myTransport.LocalEndPoint; |
||||
BacnetIpV6UdpProtocolTransport.Convert(me, out var bacme); |
||||
Array.Copy(VMAC, bacme.VMac, 3); |
||||
|
||||
Forward_NPDU(buffer, msgLength, false, me, bacme); // send to all BBMDs and FDs |
||||
|
||||
return 7; // ready to send |
||||
} |
||||
|
||||
if (function != BacnetBvlcV6Functions.BVLC_ORIGINAL_UNICAST_NPDU) |
||||
return 0; // ? |
||||
|
||||
buffer[7] = address.VMac[0]; |
||||
buffer[8] = address.VMac[1]; |
||||
buffer[9] = address.VMac[2]; |
||||
return 10; // ready to send |
||||
} |
||||
|
||||
// Decode is called each time an Udp Frame is received |
||||
public int Decode(byte[] buffer, int offset, out BacnetBvlcV6Functions function, out int msgLength, |
||||
IPEndPoint sender, BacnetAddress remoteAddress) |
||||
{ |
||||
// offset always 0, we are the first after udp |
||||
// and a previous test by the caller guaranteed at least 4 bytes into the buffer |
||||
|
||||
function = (BacnetBvlcV6Functions)buffer[1]; |
||||
msgLength = (buffer[2] << 8) | (buffer[3] << 0); |
||||
if (buffer[0] != BVLL_TYPE_BACNET_IPV6 || buffer.Length != msgLength) return -1; |
||||
|
||||
Array.Copy(buffer, 4, remoteAddress.VMac, 0, 3); |
||||
|
||||
switch (function) |
||||
{ |
||||
case BacnetBvlcV6Functions.BVLC_RESULT: |
||||
return 9; // only for the upper layers |
||||
|
||||
case BacnetBvlcV6Functions.BVLC_ORIGINAL_UNICAST_NPDU: |
||||
return 10; // only for the upper layers |
||||
|
||||
case BacnetBvlcV6Functions.BVLC_ORIGINAL_BROADCAST_NPDU: |
||||
// Send to FDs & BBMDs, not broadcast or it will be made twice ! |
||||
if (_bbmdFdServiceActivated) |
||||
Forward_NPDU(buffer, msgLength, false, sender, remoteAddress); |
||||
return 7; // also for the upper layers |
||||
|
||||
case BacnetBvlcV6Functions.BVLC_ADDRESS_RESOLUTION: |
||||
// need to verify that the VMAC is mine |
||||
if (VMAC[0] == buffer[7] && VMAC[1] == buffer[8] && VMAC[2] == buffer[9]) |
||||
// coming from myself ? avoid loopback |
||||
if (!_myTransport.LocalEndPoint.Equals(sender)) |
||||
SendAddressResolutionAck(sender, remoteAddress.VMac, |
||||
BacnetBvlcV6Functions.BVLC_ADDRESS_RESOLUTION_ACK); |
||||
return 0; // not for the upper layers |
||||
|
||||
case BacnetBvlcV6Functions.BVLC_FORWARDED_ADDRESS_RESOLUTION: |
||||
// no need to verify the target VMAC, should be OK |
||||
SendAddressResolutionAck(sender, remoteAddress.VMac, |
||||
BacnetBvlcV6Functions.BVLC_ADDRESS_RESOLUTION_ACK); |
||||
return 0; // not for the upper layers |
||||
|
||||
case BacnetBvlcV6Functions.BVLC_ADDRESS_RESOLUTION_ACK: // adresse conflict |
||||
if (VMAC[0] == buffer[4] && VMAC[1] == buffer[5] && VMAC[2] == buffer[6] && RandomVmac) |
||||
{ |
||||
new Random().NextBytes(VMAC); |
||||
VMAC[0] = (byte)((VMAC[0] & 0x7F) | 0x40); |
||||
SendAddressResolutionRequest(VMAC); |
||||
} |
||||
return 0; // not for the upper layers |
||||
|
||||
case BacnetBvlcV6Functions.BVLC_VIRTUAL_ADDRESS_RESOLUTION: |
||||
SendAddressResolutionAck(sender, remoteAddress.VMac, |
||||
BacnetBvlcV6Functions.BVLC_VIRTUAL_ADDRESS_RESOLUTION_ACK); |
||||
return 0; // not for the upper layers |
||||
|
||||
case BacnetBvlcV6Functions.BVLC_VIRTUAL_ADDRESS_RESOLUTION_ACK: |
||||
return 0; // not for the upper layers |
||||
|
||||
case BacnetBvlcV6Functions.BVLC_FORWARDED_NPDU: |
||||
if (_myTransport.LocalEndPoint.Equals(sender)) return 0; |
||||
|
||||
// certainly TODO the same code I've put in the IPV4 implementation |
||||
if (_bbmdFdServiceActivated && msgLength >= 25) |
||||
{ |
||||
bool ret; |
||||
lock (_bbmds) |
||||
ret = _bbmds.Exists(items => items.Equals(sender)); // verify sender presence in the table |
||||
// avoid also loopback |
||||
|
||||
if (ret) // message from a know BBMD address, sent to all FDs and broadcast |
||||
{ |
||||
SendToFDs(buffer, msgLength); // send without modification |
||||
// Assume all BVLC_FORWARDED_NPDU are directly sent to me in the |
||||
// unicast mode and not by the way of the multicast address |
||||
// If not, it's not really a big problem, devices on the local net will |
||||
// receive two times the message (after all it's just WhoIs, Iam, ...) |
||||
BacnetIpV6UdpProtocolTransport.Convert(_broadcastAdd, out IPEndPoint ep); |
||||
_myTransport.Send(buffer, msgLength, ep); |
||||
} |
||||
} |
||||
return 25; // for the upper layers |
||||
|
||||
case BacnetBvlcV6Functions.BVLC_REGISTER_FOREIGN_DEVICE: |
||||
if (_bbmdFdServiceActivated && msgLength == 9) |
||||
{ |
||||
var TTL = (buffer[7] << 8) + buffer[8]; // unit is second |
||||
RegisterForeignDevice(sender, TTL); |
||||
SendResult(sender, BacnetBvlcV6Results.SUCCESSFUL_COMPLETION); // ack |
||||
} |
||||
return 0; // not for the upper layers |
||||
|
||||
case BacnetBvlcV6Functions.BVLC_DELETE_FOREIGN_DEVICE_TABLE_ENTRY: |
||||
return 0; // not for the upper layers |
||||
|
||||
case BacnetBvlcV6Functions.BVLC_SECURE_BVLC: |
||||
return 0; // not for the upper layers |
||||
|
||||
case BacnetBvlcV6Functions.BVLC_DISTRIBUTE_BROADCAST_TO_NETWORK: // Sent by a Foreign Device, not a BBMD |
||||
if (_bbmdFdServiceActivated) |
||||
{ |
||||
// Send to FDs except the sender, BBMDs and broadcast |
||||
lock (_foreignDevices) |
||||
{ |
||||
if (_foreignDevices.Exists(item => item.Key.Equals(sender))) // verify previous registration |
||||
Forward_NPDU(buffer, msgLength, true, sender, remoteAddress); |
||||
else |
||||
SendResult(sender, BacnetBvlcV6Results.DISTRIBUTE_BROADCAST_TO_NETWORK_NAK); |
||||
} |
||||
} |
||||
return 0; // not for the upper layers |
||||
|
||||
// error encoding function or experimental one |
||||
default: |
||||
return -1; |
||||
} |
||||
} |
||||
} |
@ -1,465 +0,0 @@
@@ -1,465 +0,0 @@
|
||||
/************************************************************************** |
||||
* MIT License |
||||
* |
||||
* Copyright (C) 2014 Morten Kvistgaard <mk@pch-engineering.dk> |
||||
* |
||||
* Permission is hereby granted, free of charge, to any person obtaining |
||||
* a copy of this software and associated documentation files (the |
||||
* "Software"), to deal in the Software without restriction, including |
||||
* without limitation the rights to use, copy, modify, merge, publish, |
||||
* distribute, sublicense, and/or sell copies of the Software, and to |
||||
* permit persons to whom the Software is furnished to do so, subject to |
||||
* the following conditions: |
||||
* |
||||
* The above copyright notice and this permission notice shall be included |
||||
* in all copies or substantial portions of the Software. |
||||
* |
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY |
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
* |
||||
*********************************************************************/ |
||||
|
||||
namespace System.IO.BACnet; |
||||
|
||||
/// <summary> |
||||
/// This is the standard BACNet udp transport |
||||
/// </summary> |
||||
public class BacnetIpUdpProtocolTransport : BacnetTransportBase |
||||
{ |
||||
private UdpClient _sharedConn; |
||||
private UdpClient _exclusiveConn; |
||||
private readonly bool _exclusivePort; |
||||
private readonly bool _dontFragment; |
||||
private readonly string _localEndpoint; |
||||
private BacnetAddress _broadcastAddress; |
||||
private bool _disposing; |
||||
|
||||
public BVLC Bvlc { get; private set; } |
||||
public int SharedPort { get; } |
||||
public int ExclusivePort { get; } |
||||
|
||||
// Give 0.0.0.0:xxxx if the socket is open with System.Net.IPAddress.Any |
||||
// Today only used by _GetBroadcastAddress method & the bvlc layer class in BBMD mode |
||||
// Some more complex solutions could avoid this, that's why this property is virtual |
||||
public virtual IPEndPoint LocalEndPoint => (IPEndPoint)_exclusiveConn.Client.LocalEndPoint; |
||||
|
||||
public BacnetIpUdpProtocolTransport(int port, bool useExclusivePort = false, bool dontFragment = false, |
||||
int maxPayload = 1472, string localEndpointIp = "") |
||||
{ |
||||
SharedPort = port; |
||||
MaxBufferLength = maxPayload; |
||||
Type = BacnetAddressTypes.IP; |
||||
HeaderLength = BVLC.BVLC_HEADER_LENGTH; |
||||
MaxAdpuLength = BVLC.BVLC_MAX_APDU; |
||||
|
||||
_exclusivePort = useExclusivePort; |
||||
_dontFragment = dontFragment; |
||||
_localEndpoint = localEndpointIp; |
||||
} |
||||
|
||||
public BacnetIpUdpProtocolTransport(int sharedPort, int exclusivePort, bool dontFragment = false, |
||||
int maxPayload = 1472, string localEndpointIp = "") |
||||
: this(sharedPort, false, dontFragment, maxPayload, localEndpointIp) |
||||
{ |
||||
ExclusivePort = exclusivePort; |
||||
} |
||||
|
||||
public override bool Equals(object obj) |
||||
{ |
||||
var a = obj as BacnetIpUdpProtocolTransport; |
||||
return a?.SharedPort == SharedPort; |
||||
} |
||||
|
||||
public override int GetHashCode() |
||||
{ |
||||
return SharedPort.GetHashCode(); |
||||
} |
||||
|
||||
public override string ToString() |
||||
{ |
||||
return $"Udp:{SharedPort}"; |
||||
} |
||||
|
||||
private void Open() |
||||
{ |
||||
if (!_exclusivePort) |
||||
{ |
||||
/* We need a shared broadcast "listen" port. This is the 0xBAC0 port */ |
||||
/* This will enable us to have more than 1 client, on the same machine. Perhaps it's not that important though. */ |
||||
/* We (might) only recieve the broadcasts on this. Any unicasts to this might be eaten by another local client */ |
||||
if (_sharedConn == null) |
||||
{ |
||||
_sharedConn = new UdpClient { ExclusiveAddressUse = false }; |
||||
_sharedConn.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); |
||||
var ep = new IPEndPoint(IPAddress.Any, SharedPort); |
||||
if (!string.IsNullOrEmpty(_localEndpoint)) ep = new IPEndPoint(IPAddress.Parse(_localEndpoint), SharedPort); |
||||
DisableConnReset(_sharedConn); |
||||
_sharedConn.Client.Bind(ep); |
||||
SetDontFragment(_sharedConn, _dontFragment); |
||||
Log.Info($"Binded shared {ep} using UDP"); |
||||
} |
||||
/* This is our own exclusive port. We'll recieve everything sent to this. */ |
||||
/* So this is how we'll present our selves to the world */ |
||||
if (_exclusiveConn == null) |
||||
{ |
||||
var ep = new IPEndPoint(IPAddress.Any, ExclusivePort); |
||||
if (!string.IsNullOrEmpty(_localEndpoint)) ep = new IPEndPoint(IPAddress.Parse(_localEndpoint), ExclusivePort); |
||||
_exclusiveConn = new UdpClient(ep); |
||||
|
||||
// Gets the Endpoint : the assigned Udp port number in fact |
||||
ep = (IPEndPoint)_exclusiveConn.Client.LocalEndPoint; |
||||
// closes the socket |
||||
_exclusiveConn.Close(); |
||||
// Re-opens it with the freeed port number, to be sure it's a real active/server socket |
||||
// which cannot be disarmed for listen by .NET for incoming call after a few inactivity |
||||
// minutes ... yes it's like this at least on several systems |
||||
_exclusiveConn = new UdpClient(ep) |
||||
{ |
||||
EnableBroadcast = true |
||||
}; |
||||
SetDontFragment(_exclusiveConn, _dontFragment); |
||||
DisableConnReset(_exclusiveConn); |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
var ep = new IPEndPoint(IPAddress.Any, SharedPort); |
||||
if (!string.IsNullOrEmpty(_localEndpoint)) ep = new IPEndPoint(IPAddress.Parse(_localEndpoint), SharedPort); |
||||
_exclusiveConn = new UdpClient { ExclusiveAddressUse = true }; |
||||
DisableConnReset(_exclusiveConn); |
||||
_exclusiveConn.Client.Bind(ep); |
||||
SetDontFragment(_exclusiveConn, _dontFragment); |
||||
_exclusiveConn.EnableBroadcast = true; |
||||
Log.Info($"Binded exclusively to {ep} using UDP"); |
||||
} |
||||
|
||||
Bvlc = new BVLC(this); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Prevent exception on setting Don't Fragment on OSX |
||||
/// </summary> |
||||
/// <remarks> |
||||
/// https://github.com/dotnet/runtime/issues/27653 |
||||
/// </remarks> |
||||
/// <param name="client"></param> |
||||
/// <param name="dontFragment"></param> |
||||
private void SetDontFragment(UdpClient client, bool dontFragment) |
||||
{ |
||||
if (Environment.OSVersion.Platform != PlatformID.MacOSX) |
||||
{ |
||||
try |
||||
{ |
||||
client.DontFragment = dontFragment; |
||||
} |
||||
catch (SocketException e) |
||||
{ |
||||
Log.WarnFormat("Unable to set DontFragment", e); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Done to prevent exceptions in Socket.BeginReceive() |
||||
/// </summary> |
||||
/// <remarks> |
||||
/// http://microsoft.public.win32.programmer.networks.narkive.com/RlxW2V6m/udp-comms-and-connection-reset-problem |
||||
/// </remarks> |
||||
private static void DisableConnReset(UdpClient client) |
||||
{ |
||||
if (Environment.OSVersion.Platform == PlatformID.Win32NT) |
||||
{ |
||||
const uint IOC_IN = 0x80000000; |
||||
const uint IOC_VENDOR = 0x18000000; |
||||
const uint SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12; |
||||
|
||||
client?.Client.IOControl(unchecked((int)SIO_UDP_CONNRESET), |
||||
new[] { System.Convert.ToByte(false) }, null); |
||||
} |
||||
} |
||||
|
||||
protected void Close() |
||||
{ |
||||
_exclusiveConn.Close(); |
||||
} |
||||
|
||||
public override void Start() |
||||
{ |
||||
_disposing = false; |
||||
|
||||
Open(); |
||||
|
||||
_sharedConn?.BeginReceive(OnReceiveData, _sharedConn); |
||||
_exclusiveConn?.BeginReceive(OnReceiveData, _exclusiveConn); |
||||
} |
||||
|
||||
private void OnReceiveData(IAsyncResult asyncResult) |
||||
{ |
||||
var connection = (UdpClient)asyncResult.AsyncState; |
||||
|
||||
try |
||||
{ |
||||
IPEndPoint ep = null; |
||||
byte[] receiveBuffer; |
||||
|
||||
try |
||||
{ |
||||
receiveBuffer = connection.EndReceive(asyncResult, ref ep); |
||||
} |
||||
finally |
||||
{ |
||||
if (connection.Client != null && !_disposing) |
||||
{ |
||||
try |
||||
{ |
||||
// BeginReceive ASAP to enable parallel processing (e.g. query additional data while processing a notification) |
||||
connection.BeginReceive(OnReceiveData, connection); |
||||
} |
||||
catch (Exception ex) |
||||
{ |
||||
Log.Error($"Failed to restart data receive. {ex}"); |
||||
} |
||||
} |
||||
} |
||||
|
||||
var receiveBufferHex = ConvertToHex(receiveBuffer); |
||||
var receivedLength = receiveBuffer.Length; |
||||
|
||||
if (receivedLength == 0) // Empty frame : port scanner maybe |
||||
return; |
||||
|
||||
//verify message |
||||
Convert(ep, out var remoteAddress); |
||||
|
||||
if (receivedLength < BVLC.BVLC_HEADER_LENGTH) |
||||
{ |
||||
Log.Warn($"Some garbage data got in: {receiveBufferHex}"); |
||||
return; |
||||
} |
||||
|
||||
// Basic Header lenght |
||||
var headerLength = Bvlc.Decode(receiveBuffer, 0, out var function, out var _, ep); |
||||
|
||||
if (headerLength == -1) |
||||
{ |
||||
Log.Warn($"Unknow BVLC Header in: {receiveBufferHex}"); |
||||
return; |
||||
} |
||||
|
||||
switch (function) |
||||
{ |
||||
case BacnetBvlcFunctions.BVLC_RESULT: |
||||
// response to BVLC_REGISTER_FOREIGN_DEVICE, could be BVLC_DISTRIBUTE_BROADCAST_TO_NETWORK |
||||
// but we are not a BBMD, we don't care |
||||
Log.Debug("Receive Register as Foreign Device Response"); |
||||
break; |
||||
|
||||
case BacnetBvlcFunctions.BVLC_FORWARDED_NPDU: |
||||
// BVLC_FORWARDED_NPDU frame by a BBMD, change the remote_address to the original one |
||||
// stored in the BVLC header, we don't care about the BBMD address |
||||
var ip = ((long)receiveBuffer[7] << 24) + ((long)receiveBuffer[6] << 16) + |
||||
((long)receiveBuffer[5] << 8) + receiveBuffer[4]; |
||||
|
||||
var port = (receiveBuffer[8] << 8) + receiveBuffer[9]; // 0xbac0 maybe |
||||
Convert(new IPEndPoint(ip, port), out remoteAddress); |
||||
break; |
||||
} |
||||
|
||||
if (function != BacnetBvlcFunctions.BVLC_ORIGINAL_UNICAST_NPDU && |
||||
function != BacnetBvlcFunctions.BVLC_ORIGINAL_BROADCAST_NPDU && |
||||
function != BacnetBvlcFunctions.BVLC_FORWARDED_NPDU) |
||||
{ |
||||
Log.Debug($"{function} - ignoring"); |
||||
return; |
||||
} |
||||
|
||||
if (receivedLength <= headerLength) |
||||
{ |
||||
Log.Warn($"Missing data, only header received: {receiveBufferHex}"); |
||||
return; |
||||
} |
||||
|
||||
InvokeMessageRecieved(receiveBuffer, headerLength, receivedLength - headerLength, remoteAddress); |
||||
} |
||||
catch (ObjectDisposedException) |
||||
{ |
||||
Log.Debug("Connection has been disposed"); |
||||
} |
||||
catch (Exception e) |
||||
{ |
||||
if (connection.Client == null || _disposing) |
||||
return; |
||||
|
||||
Log.Error("Exception in OnRecieveData", e); |
||||
} |
||||
} |
||||
|
||||
public bool SendRegisterAsForeignDevice(IPEndPoint bbmd, short ttl) |
||||
{ |
||||
if (bbmd.AddressFamily != AddressFamily.InterNetwork) |
||||
return false; |
||||
|
||||
Bvlc.SendRegisterAsForeignDevice(bbmd, ttl); |
||||
return true; |
||||
} |
||||
public bool SendRemoteWhois(byte[] buffer, IPEndPoint bbmd, int msgLength) |
||||
{ |
||||
if (bbmd.AddressFamily != AddressFamily.InterNetwork) |
||||
return false; |
||||
|
||||
Bvlc.SendRemoteWhois(buffer, bbmd, msgLength); |
||||
return true; |
||||
} |
||||
|
||||
public static string ConvertToHex(byte[] buffer) |
||||
{ |
||||
return BitConverter.ToString(buffer).Replace("-", ""); |
||||
} |
||||
|
||||
public int Send(byte[] buffer, int dataLength, IPEndPoint ep) |
||||
{ |
||||
// return _exclusiveConn.Send(buffer, data_length, ep); |
||||
ThreadPool.QueueUserWorkItem(o => |
||||
{ |
||||
try |
||||
{ |
||||
_exclusiveConn.Send(buffer, dataLength, ep); |
||||
} |
||||
catch |
||||
{ |
||||
// not much you can do about at this point |
||||
} |
||||
}, null); |
||||
|
||||
return dataLength; |
||||
} |
||||
|
||||
public override int Send(byte[] buffer, int offset, int dataLength, BacnetAddress address, bool waitForTransmission, int timeout) |
||||
{ |
||||
if (_exclusiveConn == null) return 0; |
||||
|
||||
//add header |
||||
var fullLength = dataLength + HeaderLength; |
||||
Bvlc.Encode(buffer, offset - BVLC.BVLC_HEADER_LENGTH, address.net == 0xFFFF |
||||
? BacnetBvlcFunctions.BVLC_ORIGINAL_BROADCAST_NPDU |
||||
: BacnetBvlcFunctions.BVLC_ORIGINAL_UNICAST_NPDU, fullLength); |
||||
|
||||
//create end point |
||||
Convert(address, out var ep); |
||||
|
||||
try |
||||
{ |
||||
// broadcasts are transported from our local unicast socket also |
||||
return _exclusiveConn.Send(buffer, fullLength, ep); |
||||
} |
||||
catch |
||||
{ |
||||
return 0; |
||||
} |
||||
} |
||||
|
||||
public static void Convert(IPEndPoint ep, out BacnetAddress address) |
||||
{ |
||||
var tmp1 = ep.Address.GetAddressBytes(); |
||||
var tmp2 = BitConverter.GetBytes((ushort)ep.Port); |
||||
Array.Reverse(tmp2); |
||||
Array.Resize(ref tmp1, tmp1.Length + tmp2.Length); |
||||
Array.Copy(tmp2, 0, tmp1, tmp1.Length - tmp2.Length, tmp2.Length); |
||||
address = new BacnetAddress(BacnetAddressTypes.IP, 0, tmp1); |
||||
} |
||||
|
||||
public static void Convert(BacnetAddress address, out IPEndPoint ep) |
||||
{ |
||||
long ipAddress = BitConverter.ToUInt32(address.adr, 0); |
||||
var port = (ushort)((address.adr[4] << 8) | (address.adr[5] << 0)); |
||||
ep = new IPEndPoint(ipAddress, port); |
||||
} |
||||
|
||||
// Get the IPAddress only if one is present |
||||
// this could be usefull to find the broadcast address even if the socket is open on the default interface |
||||
// removes somes virtual interfaces (certainly not all) |
||||
private static UnicastIPAddressInformation GetAddressDefaultInterface() |
||||
{ |
||||
var unicastAddresses = NetworkInterface.GetAllNetworkInterfaces() |
||||
.Where(i => i.OperationalStatus == OperationalStatus.Up) |
||||
.Where(i => i.NetworkInterfaceType != NetworkInterfaceType.Loopback) |
||||
.Where(i => !(i.Name.Contains("VirtualBox") || i.Name.Contains("VMware"))) |
||||
.SelectMany(i => i.GetIPProperties().UnicastAddresses) |
||||
.Where(a => a.Address.AddressFamily == AddressFamily.InterNetwork) |
||||
.ToArray(); |
||||
|
||||
return unicastAddresses.Length == 1 |
||||
? unicastAddresses.Single() |
||||
: null; |
||||
} |
||||
|
||||
// A lot of problems on Mono (Raspberry) to get the correct broadcast @ |
||||
// so this method is overridable (this allows the implementation of operating system specific code) |
||||
// Marc solution http://stackoverflow.com/questions/8119414/how-to-query-the-subnet-masks-using-mono-on-linux for instance |
||||
protected virtual BacnetAddress _GetBroadcastAddress() |
||||
{ |
||||
// general broadcast by default if nothing better is found |
||||
var ep = new IPEndPoint(IPAddress.Parse("255.255.255.255"), SharedPort); |
||||
|
||||
UnicastIPAddressInformation ipAddr = null; |
||||
|
||||
if (LocalEndPoint.Address.ToString() == "0.0.0.0") |
||||
{ |
||||
ipAddr = GetAddressDefaultInterface(); |
||||
} |
||||
else |
||||
{ |
||||
// restricted local broadcast (directed ... routable) |
||||
foreach (var adapter in NetworkInterface.GetAllNetworkInterfaces()) |
||||
foreach (var ip in adapter.GetIPProperties().UnicastAddresses) |
||||
if (LocalEndPoint.Address.Equals(ip.Address)) |
||||
{ |
||||
ipAddr = ip; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if (ipAddr != null) |
||||
{ |
||||
try |
||||
{ |
||||
var strCurrentIP = ipAddr.Address.ToString().Split('.'); |
||||
var strIPNetMask = ipAddr.IPv4Mask.ToString().Split('.'); |
||||
var broadcastStr = new StringBuilder(); |
||||
for (var i = 0; i < 4; i++) |
||||
{ |
||||
broadcastStr.Append(((byte)(int.Parse(strCurrentIP[i]) | ~int.Parse(strIPNetMask[i]))).ToString()); |
||||
if (i != 3) broadcastStr.Append('.'); |
||||
} |
||||
ep = new IPEndPoint(IPAddress.Parse(broadcastStr.ToString()), SharedPort); |
||||
} |
||||
catch |
||||
{ |
||||
// on mono IPv4Mask feature not implemented |
||||
} |
||||
} |
||||
|
||||
Convert(ep, out var broadcast); |
||||
broadcast.net = 0xFFFF; |
||||
return broadcast; |
||||
} |
||||
|
||||
public override BacnetAddress GetBroadcastAddress() |
||||
{ |
||||
return _broadcastAddress ??= _GetBroadcastAddress(); |
||||
} |
||||
|
||||
public override void Dispose() |
||||
{ |
||||
_disposing = true; |
||||
_exclusiveConn?.Close(); |
||||
_exclusiveConn = null; |
||||
_sharedConn?.Close(); |
||||
_sharedConn = null; |
||||
} |
||||
} |
@ -1,362 +0,0 @@
@@ -1,362 +0,0 @@
|
||||
/************************************************************************** |
||||
* MIT License |
||||
* |
||||
* Copyright (C) 2015 Frederic Chaxel <fchaxel@free.fr> |
||||
* Morten Kvistgaard <mk@pch-engineering.dk> |
||||
* Permission is hereby granted, free of charge, to any person obtaining |
||||
* a copy of this software and associated documentation files (the |
||||
* "Software"), to deal in the Software without restriction, including |
||||
* without limitation the rights to use, copy, modify, merge, publish, |
||||
* distribute, sublicense, and/or sell copies of the Software, and to |
||||
* permit persons to whom the Software is furnished to do so, subject to |
||||
* the following conditions: |
||||
* |
||||
* The above copyright notice and this permission notice shall be included |
||||
* in all copies or substantial portions of the Software. |
||||
* |
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY |
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
* |
||||
*********************************************************************/ |
||||
|
||||
// based on Addendum 135-2012aj-4 |
||||
|
||||
namespace System.IO.BACnet; |
||||
|
||||
public class BacnetIpV6UdpProtocolTransport : BacnetTransportBase |
||||
{ |
||||
private readonly bool _exclusivePort; |
||||
private readonly string _localEndpoint; |
||||
private readonly int _vMac; |
||||
private bool _dontFragment; |
||||
private UdpClient _exclusiveConn; |
||||
private UdpClient _sharedConn; |
||||
|
||||
public BVLCV6 Bvlc { get; private set; } |
||||
public int SharedPort { get; } |
||||
|
||||
// Give [::]:xxxx if the socket is open with System.Net.IPAddress.IPv6Any |
||||
// Used the bvlc layer class in BBMD mode |
||||
// Some more complex solutions could avoid this, that's why this property is virtual |
||||
public virtual IPEndPoint LocalEndPoint => (IPEndPoint)_exclusiveConn.Client.LocalEndPoint; |
||||
|
||||
public BacnetIpV6UdpProtocolTransport(int port, int vMac = -1, bool useExclusivePort = false, |
||||
bool dontFragment = false, int maxPayload = 1472, string localEndpointIp = "") |
||||
{ |
||||
SharedPort = port; |
||||
MaxBufferLength = maxPayload; |
||||
Type = BacnetAddressTypes.IPV6; |
||||
MaxAdpuLength = BVLCV6.BVLC_MAX_APDU; |
||||
|
||||
// Two frames type, unicast with 10 bytes or broadcast with 7 bytes |
||||
// Here it's the biggest header, resize will be done after, if needed |
||||
HeaderLength = BVLCV6.BVLC_HEADER_LENGTH; |
||||
|
||||
_exclusivePort = useExclusivePort; |
||||
_dontFragment = dontFragment; |
||||
_localEndpoint = localEndpointIp; |
||||
_vMac = vMac; |
||||
} |
||||
|
||||
public override void Start() |
||||
{ |
||||
Open(); |
||||
|
||||
_sharedConn?.BeginReceive(OnReceiveData, _sharedConn); |
||||
_exclusiveConn?.BeginReceive(OnReceiveData, _exclusiveConn); |
||||
} |
||||
|
||||
public override int Send(byte[] buffer, int offset, int dataLength, BacnetAddress address, |
||||
bool waitForTransmission, int timeout) |
||||
{ |
||||
if (_exclusiveConn == null) return 0; |
||||
|
||||
//add header |
||||
var fullLength = dataLength + HeaderLength; |
||||
|
||||
if (address.net == 0xFFFF) |
||||
{ |
||||
var newBuffer = new byte[fullLength - 3]; |
||||
Array.Copy(buffer, 3, newBuffer, 0, fullLength - 3); |
||||
fullLength -= 3; |
||||
buffer = newBuffer; |
||||
Bvlc.Encode(buffer, offset - BVLCV6.BVLC_HEADER_LENGTH, |
||||
BacnetBvlcV6Functions.BVLC_ORIGINAL_BROADCAST_NPDU, fullLength, address); |
||||
} |
||||
else |
||||
{ |
||||
Bvlc.Encode(buffer, offset - BVLCV6.BVLC_HEADER_LENGTH, BacnetBvlcV6Functions.BVLC_ORIGINAL_UNICAST_NPDU, |
||||
fullLength, address); |
||||
} |
||||
|
||||
// create end point |
||||
Convert(address, out var ep); |
||||
|
||||
try |
||||
{ |
||||
// send |
||||
// multicast are transported from our local unicast socket also |
||||
return _exclusiveConn.Send(buffer, fullLength, ep); |
||||
} |
||||
catch |
||||
{ |
||||
return 0; |
||||
} |
||||
} |
||||
|
||||
public override BacnetAddress GetBroadcastAddress() |
||||
{ |
||||
// could be FF08, FF05, FF04, FF02 |
||||
var ep = new IPEndPoint(IPAddress.Parse("[FF0E::BAC0]"), SharedPort); |
||||
Convert(ep, out var ret); |
||||
ret.net = 0xFFFF; |
||||
return ret; |
||||
} |
||||
|
||||
public override void Dispose() |
||||
{ |
||||
_exclusiveConn?.Close(); |
||||
_exclusiveConn = null; |
||||
_sharedConn?.Close(); |
||||
_sharedConn = null; |
||||
} |
||||
|
||||
public override bool Equals(object obj) |
||||
{ |
||||
var a = obj as BacnetIpV6UdpProtocolTransport; |
||||
return a?.SharedPort == SharedPort; |
||||
} |
||||
|
||||
public override int GetHashCode() |
||||
{ |
||||
return SharedPort.GetHashCode(); |
||||
} |
||||
|
||||
public override string ToString() |
||||
{ |
||||
return "Udp IPv6:" + SharedPort; |
||||
} |
||||
|
||||
private void Open() |
||||
{ |
||||
UdpClient multicastListener = null; |
||||
|
||||
if (!_exclusivePort) |
||||
{ |
||||
/* We need a shared multicast "listen" port. This is the 0xBAC0 port */ |
||||
/* This will enable us to have more than 1 client, on the same machine. Perhaps it's not that important though. */ |
||||
/* We (might) only receive the multicast on this. Any unicasts to this might be eaten by another local client */ |
||||
if (_sharedConn == null) |
||||
{ |
||||
_sharedConn = new UdpClient(AddressFamily.InterNetworkV6) { ExclusiveAddressUse = false }; |
||||
_sharedConn.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); |
||||
EndPoint ep = new IPEndPoint(IPAddress.IPv6Any, SharedPort); |
||||
if (!string.IsNullOrEmpty(_localEndpoint)) |
||||
ep = new IPEndPoint(IPAddress.Parse(_localEndpoint), SharedPort); |
||||
_sharedConn.Client.Bind(ep); |
||||
multicastListener = _sharedConn; |
||||
} |
||||
/* This is our own exclusive port. We'll recieve everything sent to this. */ |
||||
/* So this is how we'll present our selves to the world */ |
||||
if (_exclusiveConn == null) |
||||
{ |
||||
EndPoint ep = new IPEndPoint(IPAddress.IPv6Any, 0); |
||||
if (!string.IsNullOrEmpty(_localEndpoint)) ep = new IPEndPoint(IPAddress.Parse(_localEndpoint), 0); |
||||
_exclusiveConn = new UdpClient((IPEndPoint)ep); |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
EndPoint ep = new IPEndPoint(IPAddress.IPv6Any, SharedPort); |
||||
if (!string.IsNullOrEmpty(_localEndpoint)) |
||||
ep = new IPEndPoint(IPAddress.Parse(_localEndpoint), SharedPort); |
||||
_exclusiveConn = new UdpClient(AddressFamily.InterNetworkV6) |
||||
{ |
||||
ExclusiveAddressUse = true |
||||
}; |
||||
_exclusiveConn.Client.Bind((IPEndPoint)ep); |
||||
multicastListener = _exclusiveConn; |
||||
} |
||||
|
||||
multicastListener.JoinMulticastGroup(IPAddress.Parse("[FF02::BAC0]")); |
||||
multicastListener.JoinMulticastGroup(IPAddress.Parse("[FF04::BAC0]")); |
||||
multicastListener.JoinMulticastGroup(IPAddress.Parse("[FF05::BAC0]")); |
||||
multicastListener.JoinMulticastGroup(IPAddress.Parse("[FF08::BAC0]")); |
||||
multicastListener.JoinMulticastGroup(IPAddress.Parse("[FF0E::BAC0]")); |
||||
|
||||
// If this option is enabled Yabe cannot see itself ! |
||||
// multicastListener.MulticastLoopback = false; |
||||
|
||||
Bvlc = new BVLCV6(this, _vMac); |
||||
} |
||||
|
||||
protected void Close() |
||||
{ |
||||
_sharedConn?.BeginReceive(OnReceiveData, _sharedConn); |
||||
_exclusiveConn?.BeginReceive(OnReceiveData, _exclusiveConn); |
||||
} |
||||
|
||||
private void OnReceiveData(IAsyncResult asyncResult) |
||||
{ |
||||
var conn = (UdpClient)asyncResult.AsyncState; |
||||
try |
||||
{ |
||||
var ep = new IPEndPoint(IPAddress.Any, 0); |
||||
byte[] localBuffer; |
||||
int rx; |
||||
|
||||
try |
||||
{ |
||||
localBuffer = conn.EndReceive(asyncResult, ref ep); |
||||
rx = localBuffer.Length; |
||||
} |
||||
catch (Exception) // ICMP port unreachable |
||||
{ |
||||
//restart data receive |
||||
conn.BeginReceive(OnReceiveData, conn); |
||||
return; |
||||
} |
||||
|
||||
if (rx == 0) // Empty frame : port scanner maybe |
||||
{ |
||||
//restart data receive |
||||
conn.BeginReceive(OnReceiveData, conn); |
||||
return; |
||||
} |
||||
|
||||
try |
||||
{ |
||||
//verify message |
||||
Convert(ep, out var remoteAddress); |
||||
if (rx < BVLCV6.BVLC_HEADER_LENGTH - 3) |
||||
{ |
||||
Log.Warn("Some garbage data got in"); |
||||
} |
||||
else |
||||
{ |
||||
// Basic Header lenght |
||||
var headerLength = Bvlc.Decode(localBuffer, 0, out var function, out _, ep, remoteAddress); |
||||
|
||||
switch (headerLength) |
||||
{ |
||||
case 0: |
||||
return; |
||||
case -1: |
||||
Log.Debug("Unknow BVLC Header"); |
||||
return; |
||||
} |
||||
|
||||
// response to BVLC_REGISTER_FOREIGN_DEVICE (could be BVLC_DISTRIBUTE_BROADCAST_TO_NETWORK ... but we are not a BBMD, don't care) |
||||
if (function == BacnetBvlcV6Functions.BVLC_RESULT) |
||||
{ |
||||
Log.Debug("Receive Register as Foreign Device Response"); |
||||
} |
||||
|
||||
// a BVLC_FORWARDED_NPDU frame by a BBMD, change the remote_address to the original one (stored in the BVLC header) |
||||
// we don't care about the BBMD address |
||||
if (function == BacnetBvlcV6Functions.BVLC_FORWARDED_NPDU) |
||||
{ |
||||
Array.Copy(localBuffer, 7, remoteAddress.adr, 0, 18); |
||||
} |
||||
|
||||
if (function != BacnetBvlcV6Functions.BVLC_ORIGINAL_UNICAST_NPDU && |
||||
function != BacnetBvlcV6Functions.BVLC_ORIGINAL_BROADCAST_NPDU && |
||||
function != BacnetBvlcV6Functions.BVLC_FORWARDED_NPDU) |
||||
return; |
||||
|
||||
if (rx > headerLength) |
||||
InvokeMessageRecieved(localBuffer, headerLength, rx - headerLength, remoteAddress); |
||||
} |
||||
} |
||||
catch (Exception ex) |
||||
{ |
||||
Log.Error("Exception in udp recieve", ex); |
||||
} |
||||
finally |
||||
{ |
||||
//restart data receive |
||||
conn.BeginReceive(OnReceiveData, conn); |
||||
} |
||||
} |
||||
catch (Exception ex) |
||||
{ |
||||
//restart data receive |
||||
if (conn.Client != null) |
||||
{ |
||||
Log.Error("Exception in Ip OnRecieveData", ex); |
||||
conn.BeginReceive(OnReceiveData, conn); |
||||
} |
||||
} |
||||
} |
||||
|
||||
public static string ConvertToHex(byte[] buffer, int length) |
||||
{ |
||||
var ret = ""; |
||||
|
||||
for (var i = 0; i < length; i++) |
||||
ret += buffer[i].ToString("X2"); |
||||
|
||||
return ret; |
||||
} |
||||
|
||||
// Modif FC : used for BBMD communication |
||||
public int Send(byte[] buffer, int dataLength, IPEndPoint ep) |
||||
{ |
||||
try |
||||
{ |
||||
// return _exclusiveConn.Send(buffer, data_length, ep); |
||||
ThreadPool.QueueUserWorkItem(o => _exclusiveConn.Send(buffer, dataLength, ep), null); |
||||
return dataLength; |
||||
} |
||||
catch |
||||
{ |
||||
return 0; |
||||
} |
||||
} |
||||
|
||||
public bool SendRegisterAsForeignDevice(IPEndPoint bbmd, short ttl) |
||||
{ |
||||
if (bbmd.AddressFamily != AddressFamily.InterNetworkV6) |
||||
return false; |
||||
|
||||
Bvlc.SendRegisterAsForeignDevice(bbmd, ttl); |
||||
return true; |
||||
} |
||||
|
||||
public bool SendRemoteWhois(byte[] buffer, IPEndPoint bbmd, int msgLength) |
||||
{ |
||||
if (bbmd.AddressFamily != AddressFamily.InterNetworkV6) |
||||
return false; |
||||
|
||||
// This message was build using the default (10) header lenght, but it's smaller (7) |
||||
var newBuffer = new byte[msgLength - 3]; |
||||
Array.Copy(buffer, 3, newBuffer, 0, msgLength - 3); |
||||
msgLength -= 3; |
||||
|
||||
Bvlc.SendRemoteWhois(newBuffer, bbmd, msgLength); |
||||
return true; |
||||
} |
||||
|
||||
public static void Convert(IPEndPoint ep, out BacnetAddress address) |
||||
{ |
||||
var tmp1 = ep.Address.GetAddressBytes(); |
||||
var tmp2 = BitConverter.GetBytes((ushort)ep.Port); |
||||
Array.Reverse(tmp2); |
||||
Array.Resize(ref tmp1, tmp1.Length + tmp2.Length); |
||||
Array.Copy(tmp2, 0, tmp1, tmp1.Length - tmp2.Length, tmp2.Length); |
||||
address = new BacnetAddress(BacnetAddressTypes.IPV6, 0, tmp1); |
||||
} |
||||
|
||||
public static void Convert(BacnetAddress address, out IPEndPoint ep) |
||||
{ |
||||
var port = (ushort)((address.adr[16] << 8) | (address.adr[17] << 0)); |
||||
var ipv6 = new byte[16]; |
||||
Array.Copy(address.adr, ipv6, 16); |
||||
ep = new IPEndPoint(new IPAddress(ipv6), port); |
||||
} |
||||
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue