OMNI+ project created

This commit is contained in:
Stoyan Zlatev
2023-10-11 17:10:02 +02:00
parent 6a30253fcb
commit e4816bc529
29 changed files with 994 additions and 0 deletions
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8.1" />
</startup>
</configuration>
+20
View File
@@ -0,0 +1,20 @@
namespace OmniPlus.Connection
{
public enum BaudRate : int
{
Bps110 = 110,
Bps300 = 300,
Bps600 = 600,
Bps1200 = 1200,
Bps2400 = 2400,
Bps4800 = 4800,
Bps9600 = 9600,
Bps14400 = 14400,
Bps19200 = 19200,
Bps38400 = 38400,
Bps57600 = 57600,
Bps115200 = 115200,
Bps128000 = 128000,
Bps256000 = 256000
}
}
@@ -0,0 +1,14 @@
using System;
namespace OmniPlus.Connection.Contracts
{
internal interface IConnection : IDisposable
{
event ReadEventHandler DataReceived;
event StateEventHandler StateChanged;
void OpenConnection();
void Write(byte[] data);
}
}
@@ -0,0 +1,7 @@
namespace OmniPlus.Connection.Contracts
{
internal interface IData
{
byte[] Data { get; }
}
}
@@ -0,0 +1,9 @@
namespace OmniPlus.Connection.Contracts
{
internal interface IDataSettings : IData
{
bool ReadByte(byte data);
void StartReading();
}
}
@@ -0,0 +1,19 @@
using System.IO.Ports;
namespace OmniPlus.Connection.Contracts
{
internal interface IPortSettings
{
BaudRate BaudRate { get; }
Parity Parity { get; }
DataBits DataBits { get; }
StopBits StopBits { get; }
bool RtsEnbaled { get; }
bool DtrEnabled { get; }
}
}
+10
View File
@@ -0,0 +1,10 @@
namespace OmniPlus.Connection
{
public enum DataBits : int
{
B8 = 8,
B7 = 7,
B6 = 6,
B5 = 5
}
}
@@ -0,0 +1,6 @@
using OmniPlus.Connection.Contracts;
namespace OmniPlus.Connection
{
internal delegate void ReadEventHandler(IData data);
}
+182
View File
@@ -0,0 +1,182 @@
using OmniPlus.Connection.Contracts;
using System;
using System.Collections.Concurrent;
using System.IO.Ports;
namespace OmniPlus.Connection
{
internal class SPConnection : IConnection
{
private readonly string portName;
private readonly IPortSettings portSettings;
private readonly IDataSettings dataSettings;
private event Action bytesReceived;
private ConcurrentQueue<byte> data;
private SerialPort serialPort;
private bool parsingData;
public SPConnection(string portName, IPortSettings portSettings, IDataSettings dataSettings)
{
this.portName = portName;
this.portSettings = portSettings;
this.dataSettings = dataSettings;
this.bytesReceived += SPConnection_BytesReceived;
}
public event ReadEventHandler DataReceived;
public event StateEventHandler StateChanged;
public virtual void Dispose()
{
if (this.DataReceived != null)
{
foreach (var callback in this.DataReceived.GetInvocationList())
{
if (callback is ReadEventHandler responseReceivedCallback)
{
this.DataReceived -= responseReceivedCallback;
}
}
}
this.CloseConnection();
}
public void Write(byte[] data)
{
if (data?.Length > 0 && this.serialPort.IsOpen)
{
lock (this.serialPort)
{
this.serialPort.Write(data, 0, data.Length);
}
}
}
public void OpenConnection()
{
this.CloseConnection();
try
{
this.serialPort = new SerialPort
{
PortName = this.portName,
BaudRate = (int)this.portSettings.BaudRate,
Parity = this.portSettings.Parity,
DataBits = (int)this.portSettings.DataBits,
StopBits = this.portSettings.StopBits,
RtsEnable = this.portSettings.RtsEnbaled,
DtrEnable = this.portSettings.DtrEnabled
};
this.serialPort.DataReceived += this.SerialPort_DataReceived;
this.serialPort.Disposed += this.SerialPort_Disposed;
this.serialPort.ErrorReceived += this.SerialPort_ErrorReceived;
this.serialPort.PinChanged += this.SerialPort_PinChanged;
this.serialPort.Open();
}
catch (Exception exception)
{
this.StateChanged?.Invoke(SPState.Error, exception.ToString());
this.CloseConnection();
}
if (this.serialPort?.IsOpen == true)
{
this.data = new ConcurrentQueue<byte>();
this.StateChanged?.Invoke(SPState.Opened, "Connected - "
+ $", {this.serialPort.PortName}"
+ $", {this.serialPort.BaudRate}"
+ $", {this.serialPort.Parity}"
+ $", {this.serialPort.DataBits}"
+ $", {this.serialPort.StopBits}"
+ $", RTS: {this.serialPort.RtsEnable}"
+ $", DTR: {this.serialPort.DtrEnable}");
}
}
private void CloseConnection()
{
if (this.serialPort != null)
{
this.serialPort.DataReceived -= this.SerialPort_DataReceived;
this.serialPort.Disposed -= this.SerialPort_Disposed;
this.serialPort.ErrorReceived -= this.SerialPort_ErrorReceived;
this.serialPort.PinChanged -= this.SerialPort_PinChanged;
this.serialPort.Dispose();
this.serialPort = null;
this.data = null;
this.StateChanged?.Invoke(SPState.Closed, "Connection was closed.");
}
}
private void SPConnection_BytesReceived()
{
this.parsingData = true;
this.dataSettings.StartReading();
while (this.parsingData)
{
this.parsingData = this.data.TryDequeue(out byte current) && this.dataSettings.ReadByte(current);
}
this.DataReceived?.Invoke(this.dataSettings);
}
private void SerialPort_DataReceived(Object sender, SerialDataReceivedEventArgs args)
{
if (sender is SerialPort serialPort && serialPort.BytesToRead > 0)
{
var bytes = new byte[serialPort.BytesToRead];
lock (serialPort)
{
serialPort.Read(bytes, 0, bytes.Length);
}
foreach (var x in bytes)
{
this.data.Enqueue(x);
}
if (!this.parsingData)
{
this.bytesReceived?.Invoke();
}
}
}
private void SerialPort_Disposed(Object sender, EventArgs args)
{
this.Dispose();
this.StateChanged?.Invoke(SPState.Disposed, $"Connection was disposed!");
}
private void SerialPort_ErrorReceived(Object sender, SerialErrorReceivedEventArgs args)
{
this.Dispose();
this.StateChanged?.Invoke(SPState.Error, $"Error received - {nameof(args.EventType)}: {args.EventType}");
}
private void SerialPort_PinChanged(Object sender, SerialPinChangedEventArgs args)
{
this.Dispose();
this.StateChanged?.Invoke(SPState.PinChanged, $"Pin changed - {nameof(args.EventType)}: {args.EventType}");
}
~SPConnection() => this.Dispose();
}
}
+11
View File
@@ -0,0 +1,11 @@
namespace OmniPlus.Connection
{
internal enum SPState
{
Closed,
Disposed,
Error,
PinChanged,
Opened
}
}
@@ -0,0 +1,4 @@
namespace OmniPlus.Connection
{
internal delegate void StateEventHandler(SPState state, string message);
}
@@ -0,0 +1,17 @@
using OmniPlus.Connection;
using System;
namespace OmniPlus.Contracts
{
internal interface IOmniConnection : IDisposable
{
event StateEventHandler StateChanged;
void CloseConnection();
void OpenConnection();
byte[] Send(byte[] request);
}
}
@@ -0,0 +1,70 @@
namespace OmniPlus.Commands
{
using OmniPlus.Types;
using System;
public class AggregateSystemParameters
{
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 AggregateSystemParameters(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 AggregateSystemParameters(byte[] data)
=> new AggregateSystemParameters(data);
public static implicit operator byte[] (AggregateSystemParameters _)
=> new byte[] { 0xFD, 0xC6 };
}
}
+29
View File
@@ -0,0 +1,29 @@
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];
}
}
@@ -0,0 +1,36 @@
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);
}
}
+81
View File
@@ -0,0 +1,81 @@
using OmniPlus.Connection;
using OmniPlus.Connection.Contracts;
using OmniPlus.Contracts;
using System;
using System.Threading;
namespace OmniPlus
{
internal class OmniConnection : IOmniConnection
{
private readonly IConnection connection;
private readonly int timeoutSeconds;
private readonly int sleeMilliseconds;
private byte[] data;
private bool waiting;
public OmniConnection(string portName, int timeoutSeconds = 3000, int sleeMilliseconds = 300)
{
this.connection = new SPConnection(
portName: portName,
portSettings: new OmniPortSettings(),
dataSettings: new OmniDataSettings(new byte[][]
{
// length, length index
new byte[] { 1, 0 }, // Start byte
new byte[] { 3, 0 }, // Control bytes
new byte[] { 1, 0 }, // Data length byte
new byte[] { 0, 4 }, // Data bytes
new byte[] { 1, 0 }, // Alignment byte
new byte[] { 2, 0 } // CRC 16 bytes
}));
this.timeoutSeconds = timeoutSeconds;
this.sleeMilliseconds = sleeMilliseconds;
}
public event StateEventHandler StateChanged
{
add => this.connection.StateChanged += value;
remove => this.connection.StateChanged -= value;
}
public void CloseConnection()
=> this.connection.Dispose();
public void Dispose()
=> this.connection.Dispose();
public void OpenConnection()
=> this.connection.OpenConnection();
public byte[] Send(byte[] request)
{
this.waiting = true;
this.connection.DataReceived += this.Connection_DataReceived;
this.connection.Write(request);
var timeoutSeconds = this.timeoutSeconds;
while (this.waiting && timeoutSeconds > 0)
{
timeoutSeconds -= this.sleeMilliseconds;
Thread.Sleep(this.sleeMilliseconds);
}
this.connection.DataReceived -= this.Connection_DataReceived;
return this.data ?? Array.Empty<byte>();
}
private void Connection_DataReceived(IData data)
{
this.waiting = false;
this.data = data.Data;
}
}
}
+91
View File
@@ -0,0 +1,91 @@
using OmniPlus.Connection.Contracts;
namespace OmniPlus
{
class OmniDataSettings : IDataSettings
{
private readonly byte[][] template;
private byte[][] messageTemplate;
private byte[] messageContent;
private int rowLength;
private int row;
private int col;
private bool ok;
private bool reading;
public OmniDataSettings(byte[][] template)
=> this.template = template;
public byte[] Data => this.messageContent;
public bool ReadByte(byte data)
{
if (!this.reading)
{
this.reading = this.template[0][1] == data;
}
else
{
this.ok = this.PrepareReading();
if (this.ok)
{
this.messageContent[this.col] = data;
}
}
return this.ok;
}
public void StartReading()
{
this.template.CopyTo(this.messageTemplate, 0);
this.messageContent = new byte[8];
this.row = 0;
this.rowLength = this.messageTemplate[this.row][0];
this.col = -1;
this.reading = false;
this.ok = this.rowLength > 0 && this.col < this.messageContent.Length;
}
private bool PrepareReading()
{
this.col++;
if (this.rowLength - this.col > 0)
{
return true;
}
this.row++;
if (this.row >= this.messageTemplate.Length)
{
return false;
}
var nextLength = this.messageTemplate[this.row][0];
if (nextLength == 0)
{
nextLength = this.messageTemplate[this.row][1];
for (int i = this.row + 1; i < this.messageTemplate.Length; i++)
{
this.messageTemplate[i][1] += nextLength;
}
var messageContent = new byte[this.messageContent.Length + nextLength];
this.messageContent.CopyTo(messageContent, 0);
this.messageContent = messageContent;
}
this.rowLength += nextLength;
return this.row < this.messageTemplate.Length && this.col < this.messageContent.Length;
}
}
}
+76
View File
@@ -0,0 +1,76 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{920435CC-ABDF-497A-9C34-1A8511F0CB56}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>OmniPlus</RootNamespace>
<AssemblyName>OmniPlus</AssemblyName>
<TargetFrameworkVersion>v4.8.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Connection\Contracts\IConnection.cs" />
<Compile Include="Connection\Contracts\IData.cs" />
<Compile Include="Connection\Contracts\IDataSettings.cs" />
<Compile Include="Connection\Contracts\IPortSettings.cs" />
<Compile Include="Connection\ReadEventHandler.cs" />
<Compile Include="Connection\SPConnection.cs" />
<Compile Include="Connection\BaudRate.cs" />
<Compile Include="Contracts\IOmniConnection.cs" />
<Compile Include="Connection\DataBits.cs" />
<Compile Include="Connection\StateEventHandler.cs" />
<Compile Include="OmniDataSettings.cs" />
<Compile Include="Messages\AggregateSystemParameters.cs" />
<Compile Include="Messages\FixedMessages.cs" />
<Compile Include="Messages\SetInputVolume.cs" />
<Compile Include="OmniConnection.cs" />
<Compile Include="OmniPortSettings.cs" />
<Compile Include="OmniRegister.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Connection\SPState.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" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
+22
View File
@@ -0,0 +1,22 @@
using OmniPlus.Connection;
using OmniPlus.Connection.Contracts;
using System.IO.Ports;
namespace OmniPlus
{
public class OmniPortSettings : IPortSettings
{
public BaudRate BaudRate => BaudRate.Bps4800;
public Parity Parity => Parity.None;
public DataBits DataBits => DataBits.B8;
public StopBits StopBits => StopBits.One;
public System.Boolean RtsEnbaled => true;
public System.Boolean DtrEnabled => false;
}
}
+40
View File
@@ -0,0 +1,40 @@
using OmniPlus.Connection;
using OmniPlus.Contracts;
using System;
namespace OmniPlus
{
public class OmniRegister
{
private readonly IOmniConnection omniConnection;
private bool connectionAvailable;
public OmniRegister(string portName)
{
this.omniConnection = new OmniConnection(portName);
this.omniConnection.StateChanged += OmniConnection_StateChanged;
this.omniConnection.OpenConnection();
}
public bool EnsureRegisterInitialized()
{
return true;
}
public bool EnsureRegisterSealed()
{
return true;
}
private void OmniConnection_StateChanged(SPState state, string message)
{
// TODO: handle, log - changes
Console.WriteLine($"[{state}] {message}");
this.connectionAvailable = state == SPState.Opened;
}
}
}
+36
View File
@@ -0,0 +1,36 @@
using OmniPlus.Connection;
using System;
using System.Collections.Concurrent;
using System.Text;
namespace OmniPlus
{
class Program
{
static void Main(string[] args)
{
//var queue = new ConcurrentQueue<byte>();
//var dataSettings = new OmniIrdaSettings();
//var parsingData = true;
//dataSettings.StartReading();
//for (byte i = (byte)'a'; i < (byte)'a' + 26; i++)
//{
// queue.Enqueue(i);
//}
//while (parsingData)
//{
// parsingData = queue.TryDequeue(out byte current) && dataSettings.ReadByte(current);
//}
//parsingData = false;
//Console.WriteLine(Encoding.ASCII.GetString(dataSettings.Data));
//var test = new SPConnection(null, null, null);
}
}
}
@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("OmniPlus")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("OmniPlus")]
[assembly: AssemblyCopyright("Copyright © 2023")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("920435cc-abdf-497a-9c34-1a8511f0cb56")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
+19
View File
@@ -0,0 +1,19 @@
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
@@ -0,0 +1,24 @@
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
@@ -0,0 +1,21 @@
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
@@ -0,0 +1,23 @@
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
@@ -0,0 +1,7 @@
namespace OmniPlus.Types
{
public static class TypesExtensions
{
}
}