All omni commands implemented as enums.

Structs added for all omni commands.
Additional value types added.
This commit is contained in:
Stoyan Zlatev
2023-10-18 15:31:14 +02:00
parent fe1f529b5e
commit 1b59ac55ce
83 changed files with 1234 additions and 275 deletions
@@ -6,10 +6,13 @@ namespace OmniPlus.Connection
{
protected readonly byte[] bytes;
protected readonly byte[] payload;
protected readonly bool isResponse;
protected SerialPortMessage(byte[] bytes, bool full)
protected SerialPortMessage(byte[] bytes, bool response)
{
if (full)
this.isResponse = response;
if (this.isResponse)
{
this.bytes = bytes;
this.payload = this.ParseMessage(bytes);
@@ -21,7 +24,7 @@ namespace OmniPlus.Connection
}
}
public int Length => this.bytes?.Length ?? 0;
public int Length => this.bytes.Length;
public byte[] Payload => this.payload;
@@ -49,6 +49,8 @@
this.SerialPortConnection_Read();
#endregion
Thread.Sleep(1);
while (!received && timeout >= 0)
{
timeout -= delay;
@@ -9,7 +9,7 @@ namespace OmniPlus.Connections.Messages
public const int MIN_LENGTH = 5;
public const int CRC_LENGTH = 2;
public IrdaMessage(byte[] bytes, bool full = false) : base(bytes, full)
public IrdaMessage(byte[] bytes, bool response = false) : base(bytes, response)
{
}
@@ -1,4 +1,6 @@
using OmniPlus.Connection;
using OmniPlus.Features.Enums;
using OmniPlus.Features.Types;
using System;
@@ -6,40 +8,54 @@ namespace OmniPlus.Connections.Messages
{
public class UI1236Message : SerialPortMessage
{
public const int MIN_LENGTH = 5;
public const byte START_BYTE = 0x0D;
public const byte MIN_LENGTH = 0x05;
public UI1236Message(byte[] bytes, bool full = false) : base(bytes, full)
public UI1236Message(byte[] bytes, bool response = false) : base(bytes, response)
{
}
public byte Start => this.bytes[0];
public byte DataLength => this.bytes[1];
public Control Control => this.bytes[2];
public Status Status
=> this.isResponse
? (Status)this.bytes[3]
: Status.Completed;
protected override byte[] CreateMessage(byte[] payload)
{
var length = payload.Length + MIN_LENGTH;
var evenOffset = length % 2;
length += evenOffset;
var messageLength = payload.Length + MIN_LENGTH;
var even = messageLength % 2;
messageLength += even;
var message = new byte[messageLength];
var index = 0;
var message = new byte[length];
message[index++] = START_BYTE;
message[index++] = (byte)(length - 3);
message[index++] = 0x08; // TODO: control byte
message[index++] = (byte)payload.Length;
Control control = 0;
control.ReturnResponse = true;
message[index++] = control;
payload.CopyTo(message, index);
var checksum = message.CalculateCheckSum16(length);
message[length - evenOffset - 2] = checksum[1];
message[length - evenOffset - 1] = checksum[0];
var checksum = message.CalculateCheckSum16(messageLength);
message[messageLength - even - 2] = checksum[1];
message[messageLength - even - 1] = checksum[0];
return message;
}
protected override byte[] ParseMessage(byte[] message)
{
var payloadLength = message[1] - (message.Length - message[1]);
var payload = new byte[payloadLength];
var payload = new byte[message.Length - MIN_LENGTH];
Array.Copy(message, 3, payload, 0, payloadLength);
Array.Copy(message, 3, payload, 0, payload.Length);
return payload;
}
@@ -0,0 +1,8 @@
namespace OmniPlus.Features.DeviceSpecific
{
public struct BatteryVoltage
{
public const byte BASE = 0xFD;
public const byte GET = 0xA9;
}
}
@@ -0,0 +1,9 @@
namespace OmniPlus.Features.DeviceSpecific
{
public struct BatteryVoltageMeasurementCalibrationFactors
{
public const byte BASE = 0xFD;
public const byte GET = 0xAA;
public const byte SET = 0xAB;
}
}
@@ -0,0 +1,8 @@
namespace OmniPlus.Features.DeviceSpecific
{
public struct DataLogData
{
public const byte BASE = 0xFD;
public const byte GET = 0x80;
}
}
@@ -0,0 +1,9 @@
namespace OmniPlus.Features.DeviceSpecific
{
public struct DataLogInterval
{
public const byte BASE = 0xFD;
public const byte SET = 0x7D;
public const byte GET = 0x7E;
}
}
@@ -0,0 +1,9 @@
namespace OmniPlus.Features.DeviceSpecific
{
public struct DisplayMode
{
public const byte BASE = 0xFD;
public const byte GET = 0x14;
public const byte SET = 0x15;
}
}
@@ -0,0 +1,9 @@
namespace OmniPlus.Features.DeviceSpecific
{
public struct EnabledLCDViews
{
public const byte BASE = 0xFD;
public const byte GET = 0x7B;
public const byte SET = 0x7C;
}
}
@@ -0,0 +1,9 @@
namespace OmniPlus.Features.DeviceSpecific
{
public struct EnabledPredefinedAlarms
{
public const byte BASE = 0xFD;
public const byte GET = 0x12;
public const byte SET = 0x13;
}
}
@@ -0,0 +1,9 @@
namespace OmniPlus.Features.DeviceSpecific
{
public struct ExtendedResolutionSetting
{
public const byte BASE = 0xFD;
public const byte GET = 0x28;
public const byte SET = 0x29;
}
}
@@ -0,0 +1,9 @@
namespace OmniPlus.Features.DeviceSpecific
{
public struct FactoryCalibration
{
public const byte BASE = 0xFD;
public const byte GET = 0x08;
public const byte SET = 0x09;
}
}
@@ -0,0 +1,8 @@
namespace OmniPlus.Features.DeviceSpecific
{
public struct FactoryMeterChamberCalibrationTest
{
public const byte BASE = 0xFD;
public const byte SET = 0x67;
}
}
@@ -0,0 +1,8 @@
namespace OmniPlus.Features.DeviceSpecific
{
public struct FactoryPulseTestMode
{
public const byte BASE = 0xFD;
public const byte SET = 0x1B;
}
}
@@ -0,0 +1,9 @@
namespace OmniPlus.Features.DeviceSpecific
{
public struct FactorySeal
{
public const byte BASE = 0xFD;
public const byte GET = 0x63;
public const byte SET = 0x64;
}
}
@@ -0,0 +1,9 @@
namespace OmniPlus.Features.DeviceSpecific
{
public struct FieldCalibration
{
public const byte BASE = 0xFD;
public const byte GET = 0x0A;
public const byte SET = 0x0B;
}
}
@@ -0,0 +1,67 @@
using OmniPlus.Features.Enums;
using OmniPlus.Features.Types;
using System;
namespace OmniPlus.Features.DeviceSpecific
{
public struct InputVolume
{
public const byte BASE = 0xFD;
public const byte GET = 0x02;
public const byte SET = 0x03;
private InputVolume(byte[] bytes) : this()
{
this.Status = Status.UnknownCommand;
this.MilliliterPerPulse = default(ushort);
this.FractionalPart = default(ushort);
this.MeterSize = default(byte);
this.MeterRange = default(byte);
if (bytes?.Length == 6)
{
this.Status = (Status)bytes[0];
this.MilliliterPerPulse = BitConverter.ToUInt16(bytes, 1);
this.MilliliterPerPulse = BitConverter.ToUInt16(bytes, 3);
this.MeterSize = bytes[5];
this.MeterRange = bytes[6];
}
}
public Status Status { get; }
public ushort MilliliterPerPulse { get; set; }
public ushort FractionalPart { get; set; }
public MeterSize MeterSize { get; set; }
public MeterRange MeterRange { get; set; }
public static byte[] GetCommand
=> new byte[] { BASE, GET };
public static implicit operator InputVolume(byte[] bytes)
=> new InputVolume(bytes);
public static implicit operator byte[] (InputVolume inputVolume)
{
var bytes = new byte[8];
bytes[0] = BASE;
bytes[1] = SET;
BitConverter.GetBytes(inputVolume.MilliliterPerPulse).CopyTo(bytes, 2);
BitConverter.GetBytes(inputVolume.FractionalPart).CopyTo(bytes, 4);
bytes[6] = inputVolume.MeterSize;
bytes[7] = inputVolume.MeterRange;
return bytes;
}
}
}
@@ -0,0 +1,8 @@
namespace OmniPlus.Features.DeviceSpecific
{
public struct LCDSegmentTest
{
public const byte BASE = 0xFD;
public const byte SET = 0x62;
}
}
@@ -0,0 +1,9 @@
namespace OmniPlus.Features.DeviceSpecific
{
public struct LCDTimeout
{
public const byte BASE = 0xFD;
public const byte GET = 0x8B;
public const byte SET = 0x8C;
}
}
@@ -0,0 +1,8 @@
namespace OmniPlus.Features.DeviceSpecific
{
public struct LidState
{
public const byte BASE = 0xFD;
public const byte GET = 0xAC;
}
}
@@ -0,0 +1,9 @@
namespace OmniPlus.Features.DeviceSpecific
{
public struct LifeTimeMaxSensorPulsesperSecond
{
public const byte BASE = 0xFD;
public const byte GET = 0x22;
public const byte SET = 0x23;
}
}
@@ -0,0 +1,8 @@
namespace OmniPlus.Features.DeviceSpecific
{
public struct ManufacturingTestCommand
{
public const byte BASE = 0xFD;
public const byte SET = 0x65;
}
}
@@ -0,0 +1,9 @@
namespace OmniPlus.Features.DeviceSpecific
{
public struct ManufacturingTime
{
public const byte BASE = 0xFD;
public const byte GET = 0x39;
public const byte SET = 0x3A;
}
}
@@ -0,0 +1,9 @@
namespace OmniPlus.Features.DeviceSpecific
{
public struct OmniSize
{
public const byte BASE = 0xFD;
public const byte GET = 0xB7;
public const byte SET = 0xB8;
}
}
@@ -0,0 +1,9 @@
namespace OmniPlus.Features.DeviceSpecific
{
public struct OutputPulseSettings
{
public const byte BASE = 0xFD;
public const byte GET = 0x0E;
public const byte SET = 0x0F;
}
}
@@ -0,0 +1,8 @@
namespace OmniPlus.Features.DeviceSpecific
{
public struct PeriodicAlarmLogEntries
{
public const byte BASE = 0xFD;
public const byte GET = 0xC2;
}
}
@@ -0,0 +1,9 @@
namespace OmniPlus.Features.DeviceSpecific
{
public struct RebootCount
{
public const byte BASE = 0xFD;
public const byte GET = 0x55;
public const byte SET = 0x56;
}
}
@@ -0,0 +1,9 @@
namespace OmniPlus.Features.DeviceSpecific
{
public struct RegisterDeviceIDString
{
public const byte BASE = 0xFD;
public const byte GET = 0x26;
public const byte SET = 0x27;
}
}
@@ -0,0 +1,9 @@
namespace OmniPlus.Features.DeviceSpecific
{
public struct RegisterSetting
{
public const byte BASE = 0xFD;
public const byte GET = 0x24;
public const byte SET = 0x25;
}
}
@@ -0,0 +1,8 @@
namespace OmniPlus.Features.DeviceSpecific
{
public struct SecondsActive
{
public const byte BASE = 0xFD;
public const byte GET = 0x3D;
}
}
@@ -0,0 +1,8 @@
namespace OmniPlus.Features.DeviceSpecific
{
public struct SendFlexNetSerialCommands
{
public const byte BASE = 0xFD;
public const byte SET = 0x98;
}
}
@@ -0,0 +1,8 @@
namespace OmniPlus.Features.DeviceSpecific
{
public struct SendMultipleFlexNetSerialCommands
{
public const byte BASE = 0xFD;
public const byte SET = 0xA2;
}
}
@@ -0,0 +1,63 @@
using OmniPlus.Features.Enums;
using OmniPlus.Features.Types;
using System;
namespace OmniPlus.Features.DeviceSpecific
{
public struct SystemParameters
{
public const byte BASE = 0xFD;
public const byte GET = 0xC6;
private SystemParameters(byte[] bytes)
{
this.Status = Status.UnknownCommand;
this.BuildInfo = default(byte[]);
this.ManifacturingTime = default(uint);
this.SystemTime = default(uint);
this.RebootCount = default(byte);
this.VersionAndType = default(byte[]);
this.BytteryV = default(double);
this.BytteryADC = default(uint);
this.Sealed = default(bool);
if (bytes?.Length >= 60)
{
this.Status = (Status)bytes[0];
this.BuildInfo = bytes.Subarray(1, 16);
this.ManifacturingTime = BitConverter.ToUInt32(bytes, 17);
this.SystemTime = BitConverter.ToUInt32(bytes, 21);
this.RebootCount = bytes[25];
this.VersionAndType = bytes.Subarray(26, 27);
this.BytteryV = BitConverter.ToUInt16(bytes, 53) / 1000.0;
this.BytteryADC = BitConverter.ToUInt32(bytes, 55);
this.Sealed = bytes[59] == 1;
}
}
public Status Status { get; }
public ASCIIString BuildInfo { get; }
public TimeSinse20000101 ManifacturingTime { get; }
public TimeSinse20000101 SystemTime { get; }
public byte RebootCount { get; }
public ASCIIString VersionAndType { get; }
public double BytteryV { get; }
public uint BytteryADC { get; }
public bool Sealed { get; }
public static byte[] GetCommand
=> new byte[] { BASE, GET };
public static implicit operator SystemParameters(byte[] bytes)
=> new SystemParameters(bytes);
}
}
@@ -0,0 +1,9 @@
namespace OmniPlus.Features.DeviceSpecific
{
public struct SystemTime
{
public const byte BASE = 0xFD;
public const byte GET = 0x10;
public const byte SET = 0x11;
}
}
@@ -0,0 +1,8 @@
namespace OmniPlus.Features.DeviceSpecific
{
public struct TestPulse
{
public const byte BASE = 0xFD;
public const byte SET = 0x66;
}
}
@@ -0,0 +1,9 @@
namespace OmniPlus.Features.DeviceSpecific
{
public struct TestTotalizerValue
{
public const byte BASE = 0xFD;
public const byte GET = 0x06;
public const byte SET = 0x07;
}
}
@@ -0,0 +1,8 @@
namespace OmniPlus.Features.DeviceSpecific
{
public struct TimeofFactorySeal
{
public const byte BASE = 0xFD;
public const byte GET = 0x05;
}
}
@@ -0,0 +1,9 @@
namespace OmniPlus.Features.DeviceSpecific
{
public struct TimeofInstallation
{
public const byte BASE = 0xFD;
public const byte GET = 0xBC;
public const byte SET = 0xBD;
}
}
@@ -0,0 +1,8 @@
namespace OmniPlus.Features.DeviceSpecific
{
public struct TriggerWatchdogReset
{
public const byte BASE = 0xFD;
public const byte SET = 0x8D;
}
}
@@ -0,0 +1,234 @@
namespace OmniPlus.Features.Enums
{
public enum DeviceCommands : byte
{
/// <summary>
/// Device specific
/// </summary>
Specific = 0xFD,
/// <summary>
///Available after seal: Yes
/// </summary>
GetInputVolumeValue = 0x02,
/// <summary>
///Available after seal: No
/// </summary>
SetInputVolumeValue = 0x03,
/// <summary>
///Available after seal: Yes
/// </summary>
GetTimeofFactorySeal = 0x05,
/// <summary>
///Available after seal: Yes
/// </summary>
GetTestTotalizerValue = 0x06,
/// <summary>
///Available after seal: Yes
/// </summary>
SetTestTotalizerValue = 0x07,
/// <summary>
///Available after seal: Yes
/// </summary>
GetFactoryCalibration = 0x08,
/// <summary>
///Available after seal: No
/// </summary>
SetFactoryCalibration = 0x09,
/// <summary>
///Available after seal: Yes
/// </summary>
GetFieldCalibration = 0x0A,
/// <summary>
///Available after seal: Yes
/// </summary>
SetFieldCalibration = 0x0B,
/// <summary>
///Available after seal: Yes
/// </summary>
GetOutputPulseSettings = 0x0E,
/// <summary>
///Available after seal: Yes
/// </summary>
SetOutputPulseSettings = 0x0F,
/// <summary>
///Available after seal: Yes
/// </summary>
GetSystemTime = 0x10,
/// <summary>
///Available after seal: Yes
/// </summary>
SetSystemTime = 0x11,
/// <summary>
///Available after seal: Yes
/// </summary>
GetEnabledPredefinedAlarms = 0x12,
/// <summary>
///Available after seal: Yes
/// </summary>
SetEnabledPredefinedAlarms = 0x13,
/// <summary>
///Available after seal: Yes
/// </summary>
GetDisplayMode = 0x14,
/// <summary>
///Available after seal: Yes
/// </summary>
SetDisplayMode = 0x15,
/// <summary>
///Available after seal: No
/// </summary>
SetFactoryPulseTestMode = 0x1B,
/// <summary>
///Available after seal: Yes
/// </summary>
GetLifeTimeMaxSensorPulsesperSecond = 0x22,
/// <summary>
///Available after seal: No
/// </summary>
SetLifeTimeMaxSensorPulsesperSecond = 0x23,
/// <summary>
///Available after seal: Yes
/// </summary>
GetRegisterSetting = 0x24,
/// <summary>
///Available after seal: No
/// </summary>
SetRegisterSetting = 0x25,
/// <summary>
///Available after seal: Yes
/// </summary>
GetRegisterDeviceIDString = 0x26,
/// <summary>
///Available after seal: No
/// </summary>
SetRegisterDeviceIDString = 0x27,
/// <summary>
///Available after seal: Yes
/// </summary>
GetExtendedResolutionSetting = 0x28,
/// <summary>
///Available after seal: Yes
/// </summary>
SetExtendedResolutionSetting = 0x29,
/// <summary>
///Available after seal: Yes
/// </summary>
GetManufacturingTime = 0x39,
/// <summary>
///Available after seal: No
/// </summary>
SetManufacturingTime = 0x3A,
/// <summary>
///Available after seal: Yes
/// </summary>
GetSecondsActive = 0x3D,
/// <summary>
///Available after seal: Yes
/// </summary>
Getrebootcount = 0x55,
/// <summary>
///Available after seal: No
/// </summary>
Setrebootcount = 0x56,
/// <summary>
///Available after seal: No
/// </summary>
SetLCDSegmentTest = 0x62,
/// <summary>
///Available after seal: Yes
/// </summary>
GetFactorySeal = 0x63,
/// <summary>
///Available after seal: No
/// </summary>
SetFactorySeal = 0x64,
/// <summary>
///Available after seal: Conditional
/// </summary>
ManufacturingTestCommand = 0x65,
/// <summary>
///Available after seal: Yes
/// </summary>
SetTestPulse = 0x66,
/// <summary>
///Available after seal: No
/// </summary>
FactoryMeterChamberCalibrationTest = 0x67,
/// <summary>
///Available after seal: Yes
/// </summary>
GetEnabledLCDViews = 0x7B,
/// <summary>
///Available after seal: Yes
/// </summary>
SetEnabledLCDViews = 0x7C,
/// <summary>
///Available after seal: Yes
/// </summary>
SetDataLogInterval = 0x7D,
/// <summary>
///Available after seal: Yes
/// </summary>
GetDataLogInterval = 0x7E,
/// <summary>
///Available after seal: Yes
/// </summary>
GetDataLogData = 0x80,
/// <summary>
///Available after seal: Yes
/// </summary>
GetLCDTimeout = 0x8B,
/// <summary>
///Available after seal: Yes
/// </summary>
SetLCDTimeout = 0x8C,
/// <summary>
///Available after seal: Yes
/// </summary>
TriggerWatchdogReset = 0x8D,
/// <summary>
///Available after seal: Yes
/// </summary>
SendFlexNetSerialCommands = 0x98,
/// <summary>
///Available after seal: Yes
/// </summary>
SendMultipleFlexNetSerialCommands = 0xA2,
/// <summary>
///Available after seal: Yes
/// </summary>
GetBatteryVoltage = 0xA9,
/// <summary>
///Available after seal: Yes
/// </summary>
GetBatteryVoltageMeasurementCalibrationFactors = 0xAA,
/// <summary>
///Available after seal: No
/// </summary>
SetBatteryVoltageMeasurementCalibrationFactors = 0xAB,
/// <summary>
///Available after seal: Yes
/// </summary>
GetLidState = 0xAC,
/// <summary>
///Available after seal: Yes
/// </summary>
GetMeterSize = 0xB7,
/// <summary>
///Available after seal: Yes
/// </summary>
SetMeterSize = 0xB8,
/// <summary>
///Available after seal: Yes
/// </summary>
GetTimeofInstallation = 0xBC,
/// <summary>
///Available after seal: No
/// </summary>
SetTimeofInstallation = 0xBD,
/// <summary>
///Available after seal: Yes
/// </summary>
GetPeriodicAlarmLogEntries = 0xC2
}
}
@@ -0,0 +1,11 @@
namespace OmniPlus.Features.Enums
{
public enum MeterRanges : byte
{
From1To2 = 0x00,
From3To4 = 0x01,
SixInch = 0x02,
EightInch = 0x03,
TenInch = 0x04,
}
}
@@ -0,0 +1,14 @@
namespace OmniPlus.Features.Enums
{
public enum MeterSizes : byte
{
Unknown = 0x00,
OneHalfIn = 0x05,
TwoIn = 0x06,
ThreeIn = 0x07,
FourIn = 0x08,
SixIn = 0x09,
EightIn = 0x0A,
TenIn = 0x0B,
}
}
+47
View File
@@ -0,0 +1,47 @@
namespace OmniPlus.Features.Enums
{
public enum Status : byte
{
/// <summary>
/// Used by communication devices to indicate communication failure/timeout. Should not be used by a slave device implementing UI-1236.
/// </summary>
FailureOrTimeout = 0x00,
/// <summary>
/// Command complete, no errors
/// </summary>
Completed = 0x01,
/// <summary>
/// Error, unable to execute command
/// </summary>
UnableToExecute = 0x02,
/// <summary>
/// Error, unknown command
/// </summary>
UnknownCommand = 0x03,
/// <summary>
/// Error, unsupported control bit pattern
/// </summary>
UnsupportedControl = 0x04,
/// <summary>
/// Error, command blocked by factory seal. Added in version B1.23
/// </summary>
BlockedBySeal = 0x05,
/// <summary>
/// Frame received, no error
/// </summary>
FrameReceived = 0xFC,
/// <summary>
/// Message corrupt
/// </summary>
MessageCorrupt = 0xFD,
/// <summary>
/// Wait status
/// </summary>
Waiting = 0xFE,
/// <summary>
/// Used by communication devices to indicate unrecognized communication device command.
/// </summary>
UnrecognizedDevice = 0xFF
}
}
@@ -1,9 +0,0 @@
namespace OmniPlus.Features.Enums
{
public enum StatusCodes : byte
{
CommandCompleted = 0x01,
UnableToExecute = 0x02,
Sealed = 0x05
}
}
@@ -0,0 +1,26 @@
namespace OmniPlus.Features.Enums
{
public enum UI1203Units : byte
{
/// <summary>
/// Cubic meters
/// </summary>
M3 = 0x00,
/// <summary>
/// Cubic feets
/// </summary>
CF = 0x01,
/// <summary>
/// US gallons
/// </summary>
GAL = 0x04,
/// <summary>
/// Imperial gallons
/// </summary>
IGAL = 0x05,
/// <summary>
/// Acre feets
/// </summary>
AF = 0x06,
}
}
@@ -21,7 +21,7 @@
/// <summary>
/// Available after seal: Yes
/// </summary>
GetVersionandType = 0x05,
GetVersionAndType = 0x05,
/// <summary>
/// Available after seal: Yes
/// </summary>
@@ -33,11 +33,11 @@
/// <summary>
/// Available after seal: Yes
/// </summary>
GetNumberofReadingDigits = 0x09,
GetNumberOfReadingDigits = 0x09,
/// <summary>
/// Available after seal: Yes
/// </summary>
SetNumberofReadingDigits = 0x0A,
SetNumberOfReadingDigits = 0x0A,
/// <summary>
/// Available after seal: Yes
/// </summary>
@@ -93,11 +93,15 @@
/// <summary>
/// Available after seal: Yes
/// </summary>
SetMetrologyAlarmSettings = 0x20,
SetMetrologyAlarmSettings1F = 0x20,
/// <summary>
/// Available after seal: Yes
/// </summary>
GetMetrologyAlarmSettings21 = 0x21,
/// <summary>
/// Available after seal: Yes
/// </summary>
SetMetrologyAlarmSettings21 = 0x20,
/// <summary>
/// Available after seal: Yes
/// </summary>
@@ -0,0 +1,22 @@
namespace OmniPlus.Features.Types
{
using System;
using System.Text;
public struct ASCIIString
{
private readonly string value;
private ASCIIString(byte[] data)
=> this.value = Encoding.ASCII.GetString(data);
public override string ToString()
=> this.value;
public static implicit operator ASCIIString(byte[] data)
=> new ASCIIString(data ?? Array.Empty<byte>());
public static implicit operator byte[](ASCIIString asciiString)
=> Encoding.ASCII.GetBytes(asciiString.value ?? string.Empty);
}
}
+66
View File
@@ -0,0 +1,66 @@
namespace OmniPlus.Features.Types
{
public class Control
{
private readonly byte[] bits;
private Control(byte[] bits)
=> this.bits = bits;
public bool E0Encryption => this.bits[0] == 1;
public bool E1Encryption => this.bits[1] == 1;
public bool E2Encryption => this.bits[2] == 1;
public bool ReturnResponse
{
get => this.bits[3] == 1;
set => this.bits[3] = (byte)(value ? 1 : 0);
}
public bool NFNetwork => this.bits[4] == 1;
public bool MultipleCommands
{
get => this.bits[5] == 1;
set => this.bits[5] = (byte)(value ? 1 : 0);
}
public bool LongControl
{
get => this.bits[6] == 1;
set => this.bits[6] = (byte)(value ? 1 : 0);
}
public bool MultipleFrames
{
get => this.bits[7] == 1;
set => this.bits[7] = (byte)(value ? 1 : 0);
}
public static implicit operator Control(byte controlByte)
{
var bits = new byte[8];
for (int i = 0; i < 8; i++)
{
bits[i] = (byte)((controlByte >> i) & 1);
}
return new Control(bits);
}
public static implicit operator byte (Control control)
{
var @byte = default(byte);
for (int i = 0; i < 8; i++)
{
@byte ^= (byte)(control.bits[i] << i);
}
return @byte;
}
}
}
@@ -0,0 +1,24 @@
using OmniPlus.Features.Enums;
namespace OmniPlus.Features.Types
{
public struct MeterRange
{
private MeterRanges rangeId;
public MeterRange(MeterRanges rangeId)
=> this.rangeId = rangeId;
public static implicit operator MeterRange(byte rangeId)
=> new MeterRange((MeterRanges)rangeId);
public static implicit operator MeterRange(MeterRanges rangeId)
=> new MeterRange(rangeId);
public static implicit operator byte(MeterRange range)
=> (byte)range.rangeId;
public static implicit operator MeterRanges(MeterRange range)
=> range.rangeId;
}
}
@@ -0,0 +1,24 @@
using OmniPlus.Features.Enums;
namespace OmniPlus.Features.Types
{
public struct MeterSize
{
private MeterSizes sizeId;
public MeterSize(MeterSizes sizeId)
=> this.sizeId = sizeId;
public static implicit operator MeterSize(byte sizeId)
=> new MeterSize((MeterSizes)sizeId);
public static implicit operator MeterSize(MeterSizes sizeId)
=> new MeterSize(sizeId);
public static implicit operator byte(MeterSize size)
=> (byte)size.sizeId;
public static implicit operator MeterSizes(MeterSize size)
=> size.sizeId;
}
}
@@ -0,0 +1,28 @@
using System;
namespace OmniPlus.Features.Types
{
public struct TimeSinse20000101
{
private readonly uint seconds;
public TimeSinse20000101(uint seconds)
=> this.seconds = seconds;
public override string ToString()
{
DateTime dateTime = this;
return dateTime.ToString("yyyy-MM-dd HH:mm:ss");
}
public static implicit operator TimeSinse20000101(uint seconds)
=> new TimeSinse20000101(seconds);
public static implicit operator uint(TimeSinse20000101 time)
=> time.seconds;
public static implicit operator DateTime(TimeSinse20000101 time)
=> new DateTime(2000, 01, 01, 00, 00, 00, DateTimeKind.Utc).AddSeconds(time);
}
}
@@ -0,0 +1,30 @@
using System;
namespace OmniPlus.Features.Types
{
public static class TypesExtensions
{
public static byte[] Subarray(this byte[] sourceArray, int start, int length)
{
if (sourceArray is null)
{
throw new ArgumentNullException(nameof(sourceArray));
}
if (length <= 0)
{
throw new ArgumentException($"Invalid subarray length.");
}
var subarray = new byte[length];
var sourceL = sourceArray.Length;
if (sourceL >= length + start)
{
Array.Copy(sourceArray, start, subarray, 0, length);
}
return subarray;
}
}
}
@@ -0,0 +1,8 @@
namespace OmniPlus.Features.UI1236
{
public struct AlarmPersistencePeriod
{
public const byte GET = 0x25;
public const byte SET = 0x26;
}
}
@@ -0,0 +1,8 @@
namespace OmniPlus.Features.UI1236
{
public struct BuildInformation
{
public const byte GET = 0x17;
public const byte SET = 0x18;
}
}
@@ -0,0 +1,7 @@
namespace OmniPlus.Features.UI1236
{
public struct ClearMetrologyAlarms
{
public const byte SET = 0x22;
}
}
@@ -0,0 +1,8 @@
namespace OmniPlus.Features.UI1236
{
public struct CustomerText
{
public const byte GET = 0x07;
public const byte SET = 0x08;
}
}
@@ -0,0 +1,8 @@
namespace OmniPlus.Features.UI1236
{
public struct FactoryID
{
public const byte GET = 0x01;
public const byte SET = 0x02;
}
}
@@ -0,0 +1,8 @@
namespace OmniPlus.Features.UI1236
{
public struct MetrologyAlarmSettings1F
{
public const byte SET = 0x20;
public const byte GET = 0x1F;
}
}
@@ -0,0 +1,8 @@
namespace OmniPlus.Features.UI1236
{
public struct MetrologyAlarmSettings21
{
public const byte SET = 0x20;
public const byte GET = 0x21;
}
}
@@ -0,0 +1,8 @@
namespace OmniPlus.Features.UI1236
{
public struct NumberOfReadingDigits
{
public const byte GET = 0x09;
public const byte SET = 0x0A;
}
}
@@ -0,0 +1,8 @@
namespace OmniPlus.Features.UI1236
{
public struct OptionalUniDirectionalFields
{
public const byte GET = 0x27;
public const byte SET = 0x28;
}
}
@@ -0,0 +1,8 @@
namespace OmniPlus.Features.UI1236
{
public struct ProgrammableID
{
public const byte GET = 0x03;
public const byte SET = 0x04;
}
}
@@ -0,0 +1,7 @@
namespace OmniPlus.Features.UI1236
{
public struct RateResolution
{
public const byte GET = 0x11;
}
}
@@ -0,0 +1,8 @@
namespace OmniPlus.Features.UI1236
{
public struct RateUnits
{
public const byte GET = 0x0D;
public const byte SET = 0x0E;
}
}
@@ -0,0 +1,7 @@
namespace OmniPlus.Features.UI1236
{
public struct Reading
{
public const byte GET = 0x13;
}
}
@@ -0,0 +1,8 @@
namespace OmniPlus.Features.UI1236
{
public struct ReadingMode
{
public const byte GET = 0x15;
public const byte SET = 0x16;
}
}
@@ -0,0 +1,7 @@
namespace OmniPlus.Features.UI1236
{
public struct ReadingPreset
{
public const byte SET = 0x14;
}
}
@@ -0,0 +1,7 @@
namespace OmniPlus.Features.UI1236
{
public struct ReadingResolution
{
public const byte GET = 0x0F;
}
}
@@ -0,0 +1,8 @@
namespace OmniPlus.Features.UI1236
{
public struct ReadingUnits
{
public const byte GET = 0x0B;
public const byte SET = 0x0C;
}
}
@@ -0,0 +1,7 @@
namespace OmniPlus.Features.UI1236
{
public struct UniDirectionalString
{
public const byte GET = 0x29;
}
}
@@ -0,0 +1,7 @@
namespace OmniPlus.Features.UI1236
{
public struct VersionAndType
{
public const byte GET = 0x05;
}
}
-29
View File
@@ -1,29 +0,0 @@
namespace OmniPlus.Messages
{
public class FixedMessages
{
/// <summary>
/// Each bytes array describes following state:
/// 0: pulse, 1: direction, 2-3: fractional portion ml/Pulse, 4: meter size, 5 meter range
/// </summary>
private static readonly byte[][] flowCalibrationSetup = new byte[][]
{
new byte[] { 0x00, 0x00, 0xE1, 0x84, 0x05, 0x00 }, // 0: Meters of size 1 1/2"
new byte[] { 0x00, 0x00, 0xE1, 0x84, 0x05, 0x00 }, // 1: Meters of size 1 1/2"
new byte[] { 0x00, 0x00, 0xE1, 0x84, 0x05, 0x00 }, // 2: Meters of size 1 1/2"
new byte[] { 0x00, 0x00, 0xE1, 0x84, 0x05, 0x00 }, // 3: Meters of size 1 1/2"
new byte[] { 0x00, 0x00, 0xE1, 0x84, 0x05, 0x00 }, // 4: Meters of size 1 1/2"
new byte[] { 0x00, 0x00, 0xE1, 0x84, 0x05, 0x00 }, // 5: Meters of size 1 1/2"
new byte[] { 0x00, 0x00, 0xE1, 0x84, 0x06, 0x00 }, // 6: Meters of size 2"
new byte[] { 0x01, 0x00, 0x8B, 0xC6, 0x07, 0x01 }, // 7: Meters of size 3"
new byte[] { 0x01, 0x00, 0x8B, 0xC6, 0x08, 0x01 }, // 8: Meters of size 4"
new byte[] { 0x06, 0x00, 0x72, 0x41, 0x09, 0x02 }, // 9: Meters of size 6"
new byte[] { 0x01, 0x80, 0xCE, 0x8F, 0x0A, 0x03 }, // 10: Meters of size 8"
new byte[] { 0x02, 0x80, 0xA3, 0x54, 0x0B, 0x04 }, // 11: Meters of size 10"
};
public static byte[] FlowCalibrationSetup(byte meterSize)
=> flowCalibrationSetup[meterSize % flowCalibrationSetup.Length - 1];
}
}
@@ -1,36 +0,0 @@
using OmniPlus.Types;
namespace OmniPlus.Messages
{
public class SetInputVolume : Bytes
{
/// <summary>
/// 0: pulse, 1: direction, 2-3: fractional portion ml/Pulse, 4: meter size, 5 meter range
/// </summary>
private static readonly byte[][] defaults = new byte[][]
{
new byte[] { 0x00, 0x00, 0xE1, 0x84, 0x05, 0x00 }, // 0: Meters of size 1 1/2"
new byte[] { 0x00, 0x00, 0xE1, 0x84, 0x05, 0x00 }, // 1: Meters of size 1 1/2"
new byte[] { 0x00, 0x00, 0xE1, 0x84, 0x05, 0x00 }, // 2: Meters of size 1 1/2"
new byte[] { 0x00, 0x00, 0xE1, 0x84, 0x05, 0x00 }, // 3: Meters of size 1 1/2"
new byte[] { 0x00, 0x00, 0xE1, 0x84, 0x05, 0x00 }, // 4: Meters of size 1 1/2"
new byte[] { 0x00, 0x00, 0xE1, 0x84, 0x05, 0x00 }, // 5: Meters of size 1 1/2"
new byte[] { 0x00, 0x00, 0xE1, 0x84, 0x06, 0x00 }, // 6: Meters of size 2"
new byte[] { 0x01, 0x00, 0x8B, 0xC6, 0x07, 0x01 }, // 7: Meters of size 3"
new byte[] { 0x01, 0x00, 0x8B, 0xC6, 0x08, 0x01 }, // 8: Meters of size 4"
new byte[] { 0x06, 0x00, 0x72, 0x41, 0x09, 0x02 }, // 9: Meters of size 6"
new byte[] { 0x01, 0x80, 0xCE, 0x8F, 0x0A, 0x03 }, // 10: Meters of size 8"
new byte[] { 0x02, 0x80, 0xA3, 0x54, 0x0B, 0x04 }, // 11: Meters of size 10"
};
public SetInputVolume(byte[] data) : base(data)
{
}
public static implicit operator SetInputVolume(byte size)
=> defaults[size % (defaults.Length - 1)];
public static implicit operator SetInputVolume(byte[] bytes)
=> new SetInputVolume(bytes);
}
}
@@ -1,70 +0,0 @@
namespace OmniPlus.Commands
{
using OmniPlus.Types;
using System;
public class SystemParameters
{
private readonly ASCIIString factoryBuild;
private readonly Seconds manifacturingTime;
private readonly Seconds systemTime;
private readonly ASCIIString firmware;
private readonly Battery battery;
private readonly byte rebootCount;
private readonly byte sealStatus;
private SystemParameters(byte[] data)
{
this.rebootCount = default(byte);
this.sealStatus = default(byte);
this.factoryBuild = new byte[16];
this.manifacturingTime = new byte[4];
this.systemTime = new byte[4];
this.firmware = new byte[27];
this.battery = new byte[6];
if (data?.Length > 0)
{
var exactData = new byte[59];
data.CopyTo(exactData, 0);
this.rebootCount = data[24];
this.sealStatus = data[58];
Array.Copy(exactData, 0, this.factoryBuild, 0, 16);
Array.Copy(exactData, 16, this.manifacturingTime, 0, 4);
Array.Copy(exactData, 20, this.systemTime, 0, 4);
Array.Copy(exactData, 25, this.firmware, 0, 27);
Array.Copy(exactData, 52, this.battery, 0, 6);
}
}
public bool VerifyBatteryVoltage(double minV = 3.19, double maxV = 3.75)
=> minV <= this.battery.Volts && this.battery.Volts <= maxV;
public bool VerifySystemTimeDrift(uint max = 700)
{
var baseTimeUTC = new DateTime(2000, 1, 1, 0, 0, 0, DateTimeKind.Utc);
var presentUTC = DateTime.UtcNow - baseTimeUTC;
var totalSeconds = Math.Abs(presentUTC.TotalSeconds - this.systemTime);
return 0 <= totalSeconds && totalSeconds <= max;
}
public bool VerifyRegisterAge(uint max = 365)
{
var manifacturingTimeUTC = new DateTime(this.manifacturingTime.Ticks, DateTimeKind.Utc);
var totalManifacturingDays = new TimeSpan(manifacturingTimeUTC.Ticks).TotalDays;
return 0 <= totalManifacturingDays && totalManifacturingDays <= max;
}
public static implicit operator SystemParameters(byte[] data)
=> new SystemParameters(data);
public static implicit operator byte[] (SystemParameters _)
=> new byte[] { 0xFD, 0xC6 };
}
}
+66 -9
View File
@@ -54,12 +54,71 @@
<Compile Include="Connection\SerialPortMessage.cs" />
<Compile Include="Connection\SerialPortOptions.cs" />
<Compile Include="Connection\Enums\DataBits.cs" />
<Compile Include="Features\Enums\StatusCodes.cs" />
<Compile Include="Features\DeviceSpecific\BatteryVoltage.cs" />
<Compile Include="Features\DeviceSpecific\BatteryVoltageMeasurementCalibrationFactors.cs" />
<Compile Include="Features\DeviceSpecific\DataLogData.cs" />
<Compile Include="Features\DeviceSpecific\DataLogInterval.cs" />
<Compile Include="Features\DeviceSpecific\DisplayMode.cs" />
<Compile Include="Features\DeviceSpecific\EnabledLCDViews.cs" />
<Compile Include="Features\DeviceSpecific\EnabledPredefinedAlarms.cs" />
<Compile Include="Features\DeviceSpecific\ExtendedResolutionSetting.cs" />
<Compile Include="Features\DeviceSpecific\FactoryCalibration.cs" />
<Compile Include="Features\DeviceSpecific\FactoryMeterChamberCalibrationTest.cs" />
<Compile Include="Features\DeviceSpecific\FactoryPulseTestMode.cs" />
<Compile Include="Features\DeviceSpecific\FactorySeal.cs" />
<Compile Include="Features\DeviceSpecific\FieldCalibration.cs" />
<Compile Include="Features\DeviceSpecific\InputVolume.cs" />
<Compile Include="Features\DeviceSpecific\LCDSegmentTest.cs" />
<Compile Include="Features\DeviceSpecific\LCDTimeout.cs" />
<Compile Include="Features\DeviceSpecific\LidState.cs" />
<Compile Include="Features\DeviceSpecific\LifeTimeMaxSensorPulsesperSecond.cs" />
<Compile Include="Features\DeviceSpecific\ManufacturingTestCommand.cs" />
<Compile Include="Features\DeviceSpecific\ManufacturingTime.cs" />
<Compile Include="Features\DeviceSpecific\OmniSize.cs" />
<Compile Include="Features\DeviceSpecific\OutputPulseSettings.cs" />
<Compile Include="Features\DeviceSpecific\PeriodicAlarmLogEntries.cs" />
<Compile Include="Features\DeviceSpecific\RebootCount.cs" />
<Compile Include="Features\DeviceSpecific\RegisterDeviceIDString.cs" />
<Compile Include="Features\DeviceSpecific\RegisterSetting.cs" />
<Compile Include="Features\DeviceSpecific\SecondsActive.cs" />
<Compile Include="Features\DeviceSpecific\SendFlexNetSerialCommands.cs" />
<Compile Include="Features\DeviceSpecific\SendMultipleFlexNetSerialCommands.cs" />
<Compile Include="Features\DeviceSpecific\SystemParameters.cs" />
<Compile Include="Features\DeviceSpecific\SystemTime.cs" />
<Compile Include="Features\DeviceSpecific\TestPulse.cs" />
<Compile Include="Features\DeviceSpecific\TestTotalizerValue.cs" />
<Compile Include="Features\DeviceSpecific\TimeofFactorySeal.cs" />
<Compile Include="Features\DeviceSpecific\TimeofInstallation.cs" />
<Compile Include="Features\DeviceSpecific\TriggerWatchdogReset.cs" />
<Compile Include="Features\Enums\DeviceCommands.cs" />
<Compile Include="Features\Enums\MeterRanges.cs" />
<Compile Include="Features\Enums\MeterSizes.cs" />
<Compile Include="Features\Enums\Status.cs" />
<Compile Include="Features\Enums\PredefinedAlarms.cs" />
<Compile Include="Features\Enums\UI1203Units.cs" />
<Compile Include="Features\Enums\UI1236Commands.cs" />
<Compile Include="Messages\SystemParameters.cs" />
<Compile Include="Messages\FixedMessages.cs" />
<Compile Include="Messages\SetInputVolume.cs" />
<Compile Include="Features\Types\Control.cs" />
<Compile Include="Features\Types\MeterRange.cs" />
<Compile Include="Features\Types\MeterSize.cs" />
<Compile Include="Features\UI1236\AlarmPersistencePeriod.cs" />
<Compile Include="Features\UI1236\BuildInformation.cs" />
<Compile Include="Features\UI1236\ClearMetrologyAlarms.cs" />
<Compile Include="Features\UI1236\CustomerText.cs" />
<Compile Include="Features\UI1236\FactoryID.cs" />
<Compile Include="Features\UI1236\MetrologyAlarmSettings1F.cs" />
<Compile Include="Features\UI1236\MetrologyAlarmSettings21.cs" />
<Compile Include="Features\UI1236\NumberOfReadingDigits.cs" />
<Compile Include="Features\UI1236\OptionalUniDirectionalFields.cs" />
<Compile Include="Features\UI1236\ProgrammableID.cs" />
<Compile Include="Features\UI1236\RateResolution.cs" />
<Compile Include="Features\UI1236\RateUnits.cs" />
<Compile Include="Features\UI1236\Reading.cs" />
<Compile Include="Features\UI1236\ReadingMode.cs" />
<Compile Include="Features\UI1236\ReadingPreset.cs" />
<Compile Include="Features\UI1236\ReadingResolution.cs" />
<Compile Include="Features\UI1236\ReadingUnits.cs" />
<Compile Include="Features\UI1236\UniDirectionalString.cs" />
<Compile Include="Features\UI1236\VersionAndType.cs" />
<Compile Include="Connections\Messages\UI1236Message.cs" />
<Compile Include="Connections\IrdaConnection.cs" />
<Compile Include="Connections\Messages\IrdaMessage.cs" />
@@ -67,11 +126,9 @@
<Compile Include="OmniRegister.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Types\ASCIIString.cs" />
<Compile Include="Types\Battery.cs" />
<Compile Include="Types\Bytes.cs" />
<Compile Include="Types\Seconds.cs" />
<Compile Include="Types\TypesExtensions.cs" />
<Compile Include="Features\Types\ASCIIString.cs" />
<Compile Include="Features\Types\TimeSinse20000101.cs" />
<Compile Include="Features\Types\TypesExtensions.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
+13 -4
View File
@@ -1,6 +1,7 @@
using OmniPlus.Commands;
using OmniPlus.Connections;
using OmniPlus.Connections;
using OmniPlus.Connections.Messages;
using OmniPlus.Features.DeviceSpecific;
using OmniPlus.Features.Enums;
namespace OmniPlus
{
@@ -25,7 +26,7 @@ namespace OmniPlus
this.irdaConnection?.Open();
this.messageHandler = this.irdaConnection.Write;
var bytes = this.messageHandler?.Invoke(new byte[] { 0xFD, 0xC6 }, 3000, 300);
var bytes = this.GetSystemParameters();
}
public void ActivateUniPro()
@@ -36,6 +37,14 @@ namespace OmniPlus
}
internal SystemParameters GetSystemParameters()
=> this.messageHandler?.Invoke(new byte[] { 0xFD, 0xC6 }, 3000, 300);
=> this.messageHandler?.Invoke(SystemParameters.GetCommand, 3000, 300);
internal bool SetInputVolume(InputVolume inputVolume)
{
inputVolume = this.messageHandler?.Invoke(inputVolume, 3000, 300);
return inputVolume.Status == Status.Completed;
}
}
}
+14 -1
View File
@@ -1,4 +1,10 @@
namespace OmniPlus
using OmniPlus.Features.DeviceSpecific;
using OmniPlus.Features.Enums;
using OmniPlus.Features.Types;
using System;
namespace OmniPlus
{
class Program
{
@@ -6,6 +12,13 @@
{
var omniRegister = new OmniRegister("COM1");
omniRegister.ActivateIrda();
var x = omniRegister.SetInputVolume(new InputVolume
{
MilliliterPerPulse = 1500,
FractionalPart = 500,
MeterSize = MeterSizes.OneHalfIn,
MeterRange = MeterRanges.From1To2,
});
}
}
}
-19
View File
@@ -1,19 +0,0 @@
namespace OmniPlus.Types
{
using System;
using System.Text;
public class ASCIIString : Bytes
{
private readonly string value;
public ASCIIString(byte[] data) : base(data)
=> this.value = Encoding.ASCII.GetString(this.data);
public override string ToString()
=> this.value;
public static implicit operator ASCIIString(byte[] data)
=> new ASCIIString(data ?? Array.Empty<byte>());
}
}
-24
View File
@@ -1,24 +0,0 @@
namespace OmniPlus.Types
{
using System;
public class Battery : Bytes
{
private readonly ushort volts;
private readonly uint rawADC;
public Battery(byte[] data) : base(data)
{
this.volts = BitConverter.ToUInt16(this.data, 0);
this.rawADC = BitConverter.ToUInt32(this.data, 2);
}
public double Volts => this.volts / 1000.0;
public override string ToString()
=> $"{this.volts}mV, {this.rawADC} ADC";
public static implicit operator Battery(byte[] data)
=> new Battery(data ?? Array.Empty<byte>());
}
}
-21
View File
@@ -1,21 +0,0 @@
namespace OmniPlus.Types
{
using System;
public class Bytes
{
protected readonly byte[] data;
public Bytes(byte[] data)
=> this.data = data;
public string ToHexString()
=> BitConverter.ToString(this.data);
public static implicit operator byte[] (Bytes bytes)
=> bytes.data ?? Array.Empty<byte>();
public static implicit operator Bytes (byte[] bytes)
=> new Bytes(bytes ?? Array.Empty<byte>());
}
}
-23
View File
@@ -1,23 +0,0 @@
namespace OmniPlus.Types
{
using System;
public class Seconds : Bytes
{
private readonly uint seconds;
public Seconds(byte[] data) : base(data)
=> this.seconds = BitConverter.ToUInt32(data, 0);
public long Ticks => this.seconds * 10_000_000;
public override string ToString()
=> this.seconds.ToString();
public static implicit operator Seconds(byte[] data)
=> new Seconds(data ?? Array.Empty<byte>());
public static implicit operator uint(Seconds seconds)
=> seconds?.seconds ?? default(uint);
}
}
-7
View File
@@ -1,7 +0,0 @@
namespace OmniPlus.Types
{
public static class TypesExtensions
{
}
}