From 2d242f25b723f31a4a188cc60a705a5078e1b81e Mon Sep 17 00:00:00 2001 From: ig Date: Fri, 10 Mar 2023 10:11:59 +0100 Subject: [PATCH 1/5] Make MbWords writable --- .../Protocol/Frames/Accessors/Accessors.cs | 7 ++----- .../Accessors/{MbRegisters.cs => MbWords.cs} | 19 +++++++++++++------ 2 files changed, 15 insertions(+), 11 deletions(-) rename csharp/Lib/Protocols/Modbus/Protocol/Frames/Accessors/{MbRegisters.cs => MbWords.cs} (71%) diff --git a/csharp/Lib/Protocols/Modbus/Protocol/Frames/Accessors/Accessors.cs b/csharp/Lib/Protocols/Modbus/Protocol/Frames/Accessors/Accessors.cs index 92282070e..45f8f8b6a 100644 --- a/csharp/Lib/Protocols/Modbus/Protocol/Frames/Accessors/Accessors.cs +++ b/csharp/Lib/Protocols/Modbus/Protocol/Frames/Accessors/Accessors.cs @@ -8,10 +8,7 @@ public static class Accessors public static MbByte ByteAt (this ArraySegment data, Byte i) => new MbByte(data, i); public static MbWord WordAt (this ArraySegment data, Byte i) => new MbWord(data, i); public static MbAddress AddressAt(this ArraySegment data, Byte i) => new MbAddress(data, i); - - public static MbRegisters RegistersAt(this ArraySegment data, Byte i) => new MbRegisters(data, i); - public static MbBits BitsAt (this ArraySegment data, Byte i) => new MbBits(data, i); - - + public static MbWords WordsAt (this ArraySegment data, Byte i) => new MbWords(data, i); + public static MbBits BitsAt (this ArraySegment data, Byte i) => new MbBits(data, i); public static MbByte ByteAt(this ArraySegment data,Byte i) where T : struct, IConvertible => new MbByte(data, i); } \ No newline at end of file diff --git a/csharp/Lib/Protocols/Modbus/Protocol/Frames/Accessors/MbRegisters.cs b/csharp/Lib/Protocols/Modbus/Protocol/Frames/Accessors/MbWords.cs similarity index 71% rename from csharp/Lib/Protocols/Modbus/Protocol/Frames/Accessors/MbRegisters.cs rename to csharp/Lib/Protocols/Modbus/Protocol/Frames/Accessors/MbWords.cs index a2124a9fa..fdc7be0c2 100644 --- a/csharp/Lib/Protocols/Modbus/Protocol/Frames/Accessors/MbRegisters.cs +++ b/csharp/Lib/Protocols/Modbus/Protocol/Frames/Accessors/MbWords.cs @@ -3,20 +3,18 @@ using InnovEnergy.Lib.Utils; namespace InnovEnergy.Lib.Protocols.Modbus.Protocol.Frames.Accessors; -public readonly struct MbRegisters : IReadOnlyList +public readonly struct MbWords : IReadOnlyList { private readonly ArraySegment _Data; - internal MbRegisters(ArraySegment data, Byte startIndex) : this(data, startIndex, CountWords(data, startIndex)) + internal MbWords(ArraySegment data, Byte startIndex) : this(data, startIndex, CountWords(data, startIndex)) { } - - - internal MbRegisters(ArraySegment data, Byte startIndex, UInt16 wordCount) : this(data.Array!, startIndex, wordCount) + internal MbWords(ArraySegment data, Byte startIndex, UInt16 wordCount) : this(data.Array!, startIndex, wordCount) { } - internal MbRegisters(Byte[] data, Byte startIndex, UInt16 wordCount) + internal MbWords(Byte[] data, Byte startIndex, UInt16 wordCount) { _Data = new ArraySegment(data, startIndex, wordCount * 2); } @@ -62,6 +60,8 @@ public readonly struct MbRegisters : IReadOnlyList public UInt16 this[Int32 index] { + // a single register is always big endian (according to standard) + get { var i = index * 2; @@ -71,5 +71,12 @@ public readonly struct MbRegisters : IReadOnlyList return (UInt16) (hi | lo); } + + set + { + var i = index * 2; + _Data[i + 0] = (Byte)(value >> 8); + _Data[i + 1] = (Byte)(value & 0xFF); + } } } \ No newline at end of file From df087b9d8eb5616338406047169eae7f0a6607d5 Mon Sep 17 00:00:00 2001 From: ig Date: Fri, 10 Mar 2023 13:46:46 +0100 Subject: [PATCH 2/5] remove MbAddress type --- .../Protocol/Frames/Accessors/Accessors.cs | 4 - .../Protocol/Frames/Accessors/MbAddress.cs | 22 ---- .../Protocol/Frames/Accessors/MbRegisters.cs | 105 ++++++++++++++++++ .../Protocol/Frames/Accessors/MbWords.cs | 46 ++++---- .../ReadDiscreteInputsCommandFrame.cs | 4 +- .../ReadHoldingRegistersCommandFrame.cs | 4 +- .../ReadInputRegistersCommandFrame.cs | 4 +- .../ReadWriteRegistersCommandFrame.cs | 6 +- .../Frames/Commands/WriteCoilsCommandFrame.cs | 8 +- .../Commands/WriteRegistersCommandFrame.cs | 8 +- .../Modbus/Protocol/Frames/ModbusFrame.cs | 2 +- .../ReadHoldingRegistersResponseFrame.cs | 2 +- .../ReadInputRegistersResponseFrame.cs | 2 +- .../Replies/ReadWriteRegistersCommandFrame.cs | 2 +- .../Frames/Replies/WriteCoilsResponseFrame.cs | 4 +- .../Replies/WriteRegistersResponseFrame.cs | 4 +- 16 files changed, 153 insertions(+), 74 deletions(-) delete mode 100644 csharp/Lib/Protocols/Modbus/Protocol/Frames/Accessors/MbAddress.cs create mode 100644 csharp/Lib/Protocols/Modbus/Protocol/Frames/Accessors/MbRegisters.cs diff --git a/csharp/Lib/Protocols/Modbus/Protocol/Frames/Accessors/Accessors.cs b/csharp/Lib/Protocols/Modbus/Protocol/Frames/Accessors/Accessors.cs index 45f8f8b6a..2a2e9e2c5 100644 --- a/csharp/Lib/Protocols/Modbus/Protocol/Frames/Accessors/Accessors.cs +++ b/csharp/Lib/Protocols/Modbus/Protocol/Frames/Accessors/Accessors.cs @@ -2,12 +2,8 @@ namespace InnovEnergy.Lib.Protocols.Modbus.Protocol.Frames.Accessors; public static class Accessors { - public static MbByte ByteAt(this Byte[] data, Byte i) => new MbByte(new ArraySegment(data), i); - public static MbWord WordAt(this Byte[] data, Byte i) => new MbWord(new ArraySegment(data), i); - public static MbByte ByteAt (this ArraySegment data, Byte i) => new MbByte(data, i); public static MbWord WordAt (this ArraySegment data, Byte i) => new MbWord(data, i); - public static MbAddress AddressAt(this ArraySegment data, Byte i) => new MbAddress(data, i); public static MbWords WordsAt (this ArraySegment data, Byte i) => new MbWords(data, i); public static MbBits BitsAt (this ArraySegment data, Byte i) => new MbBits(data, i); public static MbByte ByteAt(this ArraySegment data,Byte i) where T : struct, IConvertible => new MbByte(data, i); diff --git a/csharp/Lib/Protocols/Modbus/Protocol/Frames/Accessors/MbAddress.cs b/csharp/Lib/Protocols/Modbus/Protocol/Frames/Accessors/MbAddress.cs deleted file mode 100644 index 56495ee07..000000000 --- a/csharp/Lib/Protocols/Modbus/Protocol/Frames/Accessors/MbAddress.cs +++ /dev/null @@ -1,22 +0,0 @@ -using InnovEnergy.Lib.Utils; - -namespace InnovEnergy.Lib.Protocols.Modbus.Protocol.Frames.Accessors; - -public readonly struct MbAddress -{ - private readonly MbWord _MbWord; - - internal MbAddress(ArraySegment data, Byte index) - { - _MbWord = new MbWord(data, index); - } - - internal UInt16 Get() => (UInt16)(_MbWord.Get() + 1); - - internal UInt16 Set(UInt16 address) => _MbWord.Set(address - 1); - internal UInt16 Set(IConvertible value) => value.ConvertTo().Apply(Set); - - public static implicit operator UInt16(MbAddress w) => w.Get(); - - public override String ToString() => Get().ToString(); -} \ No newline at end of file diff --git a/csharp/Lib/Protocols/Modbus/Protocol/Frames/Accessors/MbRegisters.cs b/csharp/Lib/Protocols/Modbus/Protocol/Frames/Accessors/MbRegisters.cs new file mode 100644 index 000000000..6db8492b9 --- /dev/null +++ b/csharp/Lib/Protocols/Modbus/Protocol/Frames/Accessors/MbRegisters.cs @@ -0,0 +1,105 @@ +using System.Collections; +using InnovEnergy.Lib.Utils; +using static InnovEnergy.Lib.Protocols.Modbus.Protocol.MultiRegisterEndianness; + +namespace InnovEnergy.Lib.Protocols.Modbus.Protocol.Frames.Accessors; + +using Float32 = Single; + +public struct MbRegisters : IReadOnlyList +{ + private MbWords Words { get; } + private UInt16 StartRegister { get; } + private MultiRegisterEndianness Endianness { get; } + + public MbRegisters(MbWords words, + UInt16 startRegister, + MultiRegisterEndianness endianness, + RegisterIndexing registerIndexing) + { + Words = words; + Endianness = endianness; + + var start = startRegister - (Int16) registerIndexing; // TODO: check + + if (start < 0) + throw new ArgumentOutOfRangeException(nameof(startRegister)); + + StartRegister = (UInt16)start; + } + + public IEnumerator GetEnumerator() => Words.GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + + public Int32 Count => Words.Count; + + public UInt16 this[Int32 index] => Words[index]; + + private Byte MapIndex(UInt16 index) + { + var i = index - StartRegister; + if (i is < Byte.MinValue or > Byte.MaxValue) + throw new IndexOutOfRangeException(); + + return (Byte)i; + } + + public UInt16 GetUInt16(UInt16 index) + { + return index + .Apply(MapIndex) + .Apply(Words.GetUInt16); + } + + public void SetUInt16(UInt16 index, UInt16 value) + { + Words.SetUInt16(MapIndex(index), value); + } + + public Int16 GetInt16(UInt16 index) + { + return (Int16) GetUInt16(index); + } + + public void SetUInt16(UInt16 index, Int16 value) + { + SetUInt16(index, (UInt16)value); + } + + public UInt32 GetUInt32(UInt16 index) + { + var i = MapIndex(index); + + var hi = (UInt32) GetUInt16(i); + var lo = (UInt32) GetUInt16(++i); + + if (Endianness == LittleEndian) + (lo, hi) = (hi, lo); + + return hi << 16 | lo; + } + + // TODO + // public void SetUInt32(UInt32 index, UInt32 value) + + public Int32 GetInt32(UInt16 index) => (Int32)GetUInt32(index); + + // TODO + // public void SetInt32(Int32 index, Int32 value) + + + public Float32 GetFloat32(UInt16 index) + { + return index + .Apply(GetInt32) + .Apply(BitConverter.Int32BitsToSingle); + } + + // TODO + // public void SetFloat32(Float32 index, Float32 value) + + + + +} \ No newline at end of file diff --git a/csharp/Lib/Protocols/Modbus/Protocol/Frames/Accessors/MbWords.cs b/csharp/Lib/Protocols/Modbus/Protocol/Frames/Accessors/MbWords.cs index fdc7be0c2..5511c5c63 100644 --- a/csharp/Lib/Protocols/Modbus/Protocol/Frames/Accessors/MbWords.cs +++ b/csharp/Lib/Protocols/Modbus/Protocol/Frames/Accessors/MbWords.cs @@ -5,20 +5,17 @@ namespace InnovEnergy.Lib.Protocols.Modbus.Protocol.Frames.Accessors; public readonly struct MbWords : IReadOnlyList { - private readonly ArraySegment _Data; + internal readonly ArraySegment Data; - internal MbWords(ArraySegment data, Byte startIndex) : this(data, startIndex, CountWords(data, startIndex)) + internal MbWords(ArraySegment data, Byte startIndex = 0) : + this(data, startIndex, CountWords(data, startIndex)) { } - internal MbWords(ArraySegment data, Byte startIndex, UInt16 wordCount) : this(data.Array!, startIndex, wordCount) + internal MbWords(ArraySegment data, Byte startIndex, UInt16 wordCount) { + Data = new ArraySegment(data.Array!, startIndex + data.Offset, wordCount * 2); } - internal MbWords(Byte[] data, Byte startIndex, UInt16 wordCount) - { - _Data = new ArraySegment(data, startIndex, wordCount * 2); - } - private static UInt16 CountWords(ArraySegment data, Byte startIndex) { var wordCount = (data.Count - startIndex) / 2; @@ -27,14 +24,14 @@ public readonly struct MbWords : IReadOnlyList internal IReadOnlyCollection Set(IReadOnlyCollection values) { - if (values.Count != _Data.Count / 2) + if (values.Count != Data.Count / 2) throw new ArgumentException($"Expecting an list of size {values.Count}!", nameof(values)); var i = 0; foreach (var value in values) { - _Data[i++] = (Byte) (value >> 8); - _Data[i++] = (Byte) (value & 0xFF); + Data[i++] = (Byte) (value >> 8); + Data[i++] = (Byte) (value & 0xFF); } return values; @@ -43,12 +40,12 @@ public readonly struct MbWords : IReadOnlyList public IEnumerator GetEnumerator() { - var end = _Data.Count; + var end = Data.Count; for (var i = 0; i < end; ) { - var hi = _Data[i++] << 8; - var lo = _Data[i++]; + var hi = Data[i++] << 8; + var lo = Data[i++]; yield return (UInt16) (hi | lo); } @@ -56,7 +53,7 @@ public readonly struct MbWords : IReadOnlyList IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - public Int32 Count => _Data.Count / 2; + public Int32 Count => Data.Count / 2; public UInt16 this[Int32 index] { @@ -66,17 +63,20 @@ public readonly struct MbWords : IReadOnlyList { var i = index * 2; - var hi = _Data[i] << 8; - var lo = _Data[i+1]; + var hi = Data[i] << 8; + var lo = Data[i+1]; return (UInt16) (hi | lo); } - set - { - var i = index * 2; - _Data[i + 0] = (Byte)(value >> 8); - _Data[i + 1] = (Byte)(value & 0xFF); - } + } + + public UInt16 GetUInt16(Byte index) => this[index]; + + public void SetUInt16(Byte index, UInt16 value) + { + var i = index * 2; + Data[i + 0] = (Byte)(value >> 8); + Data[i + 1] = (Byte)(value & 0xFF); } } \ No newline at end of file diff --git a/csharp/Lib/Protocols/Modbus/Protocol/Frames/Commands/ReadDiscreteInputsCommandFrame.cs b/csharp/Lib/Protocols/Modbus/Protocol/Frames/Commands/ReadDiscreteInputsCommandFrame.cs index 88461e76e..325d88e5c 100644 --- a/csharp/Lib/Protocols/Modbus/Protocol/Frames/Commands/ReadDiscreteInputsCommandFrame.cs +++ b/csharp/Lib/Protocols/Modbus/Protocol/Frames/Commands/ReadDiscreteInputsCommandFrame.cs @@ -13,8 +13,8 @@ internal class ReadDiscreteInputsCommandFrame : ModbusFrame { private const Int32 Size = 6; - private MbAddress ReadAddress => Data.AddressAt(2); - private MbWord QuantityOfInputs => Data.WordAt(4); + private MbWord ReadAddress => Data.WordAt(2); + private MbWord QuantityOfInputs => Data.WordAt(4); public ReadDiscreteInputsCommandFrame(Byte slave, UInt16 readAddress, UInt16 nBits) : base(Size) diff --git a/csharp/Lib/Protocols/Modbus/Protocol/Frames/Commands/ReadHoldingRegistersCommandFrame.cs b/csharp/Lib/Protocols/Modbus/Protocol/Frames/Commands/ReadHoldingRegistersCommandFrame.cs index b03914c0a..9134b0be9 100644 --- a/csharp/Lib/Protocols/Modbus/Protocol/Frames/Commands/ReadHoldingRegistersCommandFrame.cs +++ b/csharp/Lib/Protocols/Modbus/Protocol/Frames/Commands/ReadHoldingRegistersCommandFrame.cs @@ -14,8 +14,8 @@ internal class ReadHoldingRegistersCommandFrame : ModbusFrame internal const Int32 Size = 6; - public MbAddress ReadAddress => Data.AddressAt(2); - public MbWord NbToRead => Data.WordAt(4); + public MbWord ReadAddress => Data.WordAt(2); + public MbWord NbToRead => Data.WordAt(4); public Int32 ExpectedResponseSize => ReadHoldingRegistersResponseFrame.ExpectedSize(NbToRead); diff --git a/csharp/Lib/Protocols/Modbus/Protocol/Frames/Commands/ReadInputRegistersCommandFrame.cs b/csharp/Lib/Protocols/Modbus/Protocol/Frames/Commands/ReadInputRegistersCommandFrame.cs index f06845565..a17fe34f8 100644 --- a/csharp/Lib/Protocols/Modbus/Protocol/Frames/Commands/ReadInputRegistersCommandFrame.cs +++ b/csharp/Lib/Protocols/Modbus/Protocol/Frames/Commands/ReadInputRegistersCommandFrame.cs @@ -11,8 +11,8 @@ internal class ReadInputRegistersCommandFrame : ModbusFrame { internal const Int32 Size = 6; - public MbAddress ReadAddress => Data.AddressAt(2); - public MbWord NbToRead => Data.WordAt(4); + public MbWord ReadAddress => Data.WordAt(2); + public MbWord NbToRead => Data.WordAt(4); public Int32 ExpectedResponseSize => ReadInputRegistersResponseFrame.ExpectedSize(NbToRead); diff --git a/csharp/Lib/Protocols/Modbus/Protocol/Frames/Commands/ReadWriteRegistersCommandFrame.cs b/csharp/Lib/Protocols/Modbus/Protocol/Frames/Commands/ReadWriteRegistersCommandFrame.cs index 57f86d379..e280c071d 100644 --- a/csharp/Lib/Protocols/Modbus/Protocol/Frames/Commands/ReadWriteRegistersCommandFrame.cs +++ b/csharp/Lib/Protocols/Modbus/Protocol/Frames/Commands/ReadWriteRegistersCommandFrame.cs @@ -11,12 +11,12 @@ internal class ReadWriteRegistersCommandFrame : ModbusFrame { internal new const Int32 MinSize = 11; - public MbAddress ReadAddress => Data.AddressAt(2); + public MbWord ReadAddress => Data.WordAt(2); public MbWord NbToRead => Data.WordAt(4); - public MbAddress WriteAddress => Data.AddressAt(6); + public MbWord WriteAddress => Data.WordAt(6); public MbWord NbToWrite => Data.WordAt(8); public MbByte ByteCount => Data.ByteAt(10); - public MbRegisters RegistersToWrite => Data.RegistersAt(11); + public MbWords RegistersToWrite => Data.WordsAt(11); public Int32 ExpectedResponseSize => ReadWriteRegistersResponseFrame.ExpectedSize(NbToRead); diff --git a/csharp/Lib/Protocols/Modbus/Protocol/Frames/Commands/WriteCoilsCommandFrame.cs b/csharp/Lib/Protocols/Modbus/Protocol/Frames/Commands/WriteCoilsCommandFrame.cs index 5865ddd21..e366616cb 100644 --- a/csharp/Lib/Protocols/Modbus/Protocol/Frames/Commands/WriteCoilsCommandFrame.cs +++ b/csharp/Lib/Protocols/Modbus/Protocol/Frames/Commands/WriteCoilsCommandFrame.cs @@ -14,10 +14,10 @@ public class WriteCoilsCommandFrame : ModbusFrame { private new const Int32 MinSize = 7; - private MbAddress WriteAddress => Data.AddressAt(2); - private MbWord NbOfCoils => Data.WordAt(4); - private MbByte ByteCount => Data.ByteAt(6); - public MbBits CoilsToWrite => Data.BitsAt(7); + private MbWord WriteAddress => Data.WordAt(2); + private MbWord NbOfCoils => Data.WordAt(4); + private MbByte ByteCount => Data.ByteAt(6); + public MbBits CoilsToWrite => Data.BitsAt(7); public WriteCoilsCommandFrame(Byte slave, UInt16 writeAddress, Booleans coils) : base(MinSize + NbBytes(coils)) { diff --git a/csharp/Lib/Protocols/Modbus/Protocol/Frames/Commands/WriteRegistersCommandFrame.cs b/csharp/Lib/Protocols/Modbus/Protocol/Frames/Commands/WriteRegistersCommandFrame.cs index 8eb4ca915..b317767c1 100644 --- a/csharp/Lib/Protocols/Modbus/Protocol/Frames/Commands/WriteRegistersCommandFrame.cs +++ b/csharp/Lib/Protocols/Modbus/Protocol/Frames/Commands/WriteRegistersCommandFrame.cs @@ -11,10 +11,10 @@ internal class WriteRegistersCommandFrame : ModbusFrame { internal new const Int32 MinSize = 7; - public MbAddress WriteAddress => Data.AddressAt(2); - public MbWord NbOfRegisters => Data.WordAt(4); - public MbByte ByteCount => Data.ByteAt(6); - public MbRegisters RegistersToWrite => Data.RegistersAt(7); + public MbWord WriteAddress => Data.WordAt(2); + public MbWord NbOfRegisters => Data.WordAt(4); + public MbByte ByteCount => Data.ByteAt(6); + public MbWords RegistersToWrite => Data.WordsAt(7); public Int32 ExpectedResponseSize => WriteRegistersResponseFrame.ExpectedSize(); diff --git a/csharp/Lib/Protocols/Modbus/Protocol/Frames/ModbusFrame.cs b/csharp/Lib/Protocols/Modbus/Protocol/Frames/ModbusFrame.cs index 539551b92..fa1c3b008 100644 --- a/csharp/Lib/Protocols/Modbus/Protocol/Frames/ModbusFrame.cs +++ b/csharp/Lib/Protocols/Modbus/Protocol/Frames/ModbusFrame.cs @@ -17,7 +17,7 @@ public class ModbusFrame internal ModbusFrame(Int32 size) { - Data = new ArraySegment(new Byte[size]); + Data = new Byte[size]; } diff --git a/csharp/Lib/Protocols/Modbus/Protocol/Frames/Replies/ReadHoldingRegistersResponseFrame.cs b/csharp/Lib/Protocols/Modbus/Protocol/Frames/Replies/ReadHoldingRegistersResponseFrame.cs index ba8b3e707..7fcd77983 100644 --- a/csharp/Lib/Protocols/Modbus/Protocol/Frames/Replies/ReadHoldingRegistersResponseFrame.cs +++ b/csharp/Lib/Protocols/Modbus/Protocol/Frames/Replies/ReadHoldingRegistersResponseFrame.cs @@ -11,7 +11,7 @@ internal class ReadHoldingRegistersResponseFrame : ModbusFrame internal new const Int32 MinSize = 3; public MbByte ByteCount => Data.ByteAt(2); - public MbRegisters RegistersRead => Data.RegistersAt(3); + public MbWords RegistersRead => Data.WordsAt(3); public ReadHoldingRegistersResponseFrame(Byte slave, UInt16s registersRead) : base(ExpectedSize(registersRead.Count)) diff --git a/csharp/Lib/Protocols/Modbus/Protocol/Frames/Replies/ReadInputRegistersResponseFrame.cs b/csharp/Lib/Protocols/Modbus/Protocol/Frames/Replies/ReadInputRegistersResponseFrame.cs index bb301e638..29cebda39 100644 --- a/csharp/Lib/Protocols/Modbus/Protocol/Frames/Replies/ReadInputRegistersResponseFrame.cs +++ b/csharp/Lib/Protocols/Modbus/Protocol/Frames/Replies/ReadInputRegistersResponseFrame.cs @@ -12,7 +12,7 @@ internal class ReadInputRegistersResponseFrame : ModbusFrame internal new const Int32 MinSize = 3; public MbByte ByteCount => Data.ByteAt(2); - public MbRegisters RegistersRead => Data.RegistersAt(3); + public MbWords RegistersRead => Data.WordsAt(3); public ReadInputRegistersResponseFrame(Byte slave, UInt16s registersRead) : base(ExpectedSize(registersRead.Count)) { diff --git a/csharp/Lib/Protocols/Modbus/Protocol/Frames/Replies/ReadWriteRegistersCommandFrame.cs b/csharp/Lib/Protocols/Modbus/Protocol/Frames/Replies/ReadWriteRegistersCommandFrame.cs index ce7ecf2da..43eed5e21 100644 --- a/csharp/Lib/Protocols/Modbus/Protocol/Frames/Replies/ReadWriteRegistersCommandFrame.cs +++ b/csharp/Lib/Protocols/Modbus/Protocol/Frames/Replies/ReadWriteRegistersCommandFrame.cs @@ -12,7 +12,7 @@ internal class ReadWriteRegistersResponseFrame : ModbusFrame internal new const Int32 MinSize = 3; public MbByte ByteCount => Data.ByteAt(2); - public MbRegisters RegistersRead => Data.RegistersAt(3); + public MbWords RegistersRead => Data.WordsAt(3); public ReadWriteRegistersResponseFrame(Byte slave, UInt16s registersRead) : base(ExpectedSize(registersRead.Count)) { diff --git a/csharp/Lib/Protocols/Modbus/Protocol/Frames/Replies/WriteCoilsResponseFrame.cs b/csharp/Lib/Protocols/Modbus/Protocol/Frames/Replies/WriteCoilsResponseFrame.cs index 6ec170980..76518a0e5 100644 --- a/csharp/Lib/Protocols/Modbus/Protocol/Frames/Replies/WriteCoilsResponseFrame.cs +++ b/csharp/Lib/Protocols/Modbus/Protocol/Frames/Replies/WriteCoilsResponseFrame.cs @@ -7,8 +7,8 @@ public class WriteCoilsResponseFrame : ModbusFrame { private const Int32 Size = 6; - public MbAddress WriteAddress => Data.AddressAt(2); - public MbWord NbWritten => Data.WordAt(4); + public MbWord WriteAddress => Data.WordAt(2); + public MbWord NbWritten => Data.WordAt(4); internal static Int32 ExpectedSize() => Size; diff --git a/csharp/Lib/Protocols/Modbus/Protocol/Frames/Replies/WriteRegistersResponseFrame.cs b/csharp/Lib/Protocols/Modbus/Protocol/Frames/Replies/WriteRegistersResponseFrame.cs index 2817c3460..76a0a6b7d 100644 --- a/csharp/Lib/Protocols/Modbus/Protocol/Frames/Replies/WriteRegistersResponseFrame.cs +++ b/csharp/Lib/Protocols/Modbus/Protocol/Frames/Replies/WriteRegistersResponseFrame.cs @@ -7,8 +7,8 @@ internal class WriteRegistersResponseFrame : ModbusFrame { private const Int32 Size = 6; - public MbAddress WriteAddress => Data.AddressAt(2); - public MbWord NbWritten => Data.WordAt(4); + public MbWord WriteAddress => Data.WordAt(2); + public MbWord NbWritten => Data.WordAt(4); internal static Int32 ExpectedSize() => Size; From 6db610d30886b5610b98947d14a755e1768f2b1d Mon Sep 17 00:00:00 2001 From: ig Date: Fri, 10 Mar 2023 13:57:39 +0100 Subject: [PATCH 3/5] implement Logic/Wire addressing in ModbusClients --- .../Protocols/Modbus/Clients/Endianness.cs | 10 ---- .../Protocols/Modbus/Clients/ModbusClient.cs | 29 +++++++---- .../Modbus/Clients/ModbusRtuClient.cs | 22 +++++++-- .../Modbus/Clients/ModbusTcpClient.cs | 48 +++++++++++++------ 4 files changed, 71 insertions(+), 38 deletions(-) delete mode 100644 csharp/Lib/Protocols/Modbus/Clients/Endianness.cs diff --git a/csharp/Lib/Protocols/Modbus/Clients/Endianness.cs b/csharp/Lib/Protocols/Modbus/Clients/Endianness.cs deleted file mode 100644 index d53103dec..000000000 --- a/csharp/Lib/Protocols/Modbus/Clients/Endianness.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace InnovEnergy.Lib.Protocols.Modbus.Clients; - -[Flags] -public enum Endianness -{ - LittleEndian32BitIntegers = 0, - LittleEndian32Floats = 0, - BigEndian32BitIntegers = 1, - BigEndian32Floats = 2, -} \ No newline at end of file diff --git a/csharp/Lib/Protocols/Modbus/Clients/ModbusClient.cs b/csharp/Lib/Protocols/Modbus/Clients/ModbusClient.cs index 1bc736622..c992d0874 100644 --- a/csharp/Lib/Protocols/Modbus/Clients/ModbusClient.cs +++ b/csharp/Lib/Protocols/Modbus/Clients/ModbusClient.cs @@ -1,6 +1,8 @@ using InnovEnergy.Lib.Protocols.Modbus.Connections; using InnovEnergy.Lib.Protocols.Modbus.Conversions; -using static InnovEnergy.Lib.Protocols.Modbus.Clients.Endianness; +using InnovEnergy.Lib.Protocols.Modbus.Protocol; +using static InnovEnergy.Lib.Protocols.Modbus.Protocol.MultiRegisterEndianness; +using static InnovEnergy.Lib.Protocols.Modbus.Protocol.RegisterIndexing; namespace InnovEnergy.Lib.Protocols.Modbus.Clients; @@ -11,9 +13,10 @@ using Coils = IReadOnlyList; public abstract class ModbusClient { - protected ModbusConnection Connection { get; } - protected Byte SlaveId { get; } - protected Endianness Endianness { get; } + protected ModbusConnection Connection { get; } + protected Byte SlaveId { get; } + protected RegisterIndexing RegisterIndexing { get; } + protected MultiRegisterEndianness Endianness { get; } // TODO: add additional functions: coils... @@ -41,12 +44,20 @@ public abstract class ModbusClient return WriteRegisters(writeAddress, (IReadOnlyList)values); } - protected ModbusClient(ModbusConnection connection, Byte slaveId, Endianness endianness = LittleEndian32BitIntegers | LittleEndian32Floats) + protected ModbusClient(ModbusConnection connection, + Byte slaveId, + RegisterIndexing registerIndexing = OneBased, + MultiRegisterEndianness endianness = LittleEndian) { - Connection = connection; - SlaveId = slaveId; - Endianness = endianness; + Connection = connection; + SlaveId = slaveId; + RegisterIndexing = registerIndexing; + Endianness = endianness; } public void CloseConnection() => Connection.Close(); -} \ No newline at end of file + + protected UInt16 LogicToWire(UInt16 address) => RegisterIndexing.LogicToSerialized(address); + protected UInt16 SerializedToLogic(UInt16 address) => RegisterIndexing.SerializedToLogic(address); +} + diff --git a/csharp/Lib/Protocols/Modbus/Clients/ModbusRtuClient.cs b/csharp/Lib/Protocols/Modbus/Clients/ModbusRtuClient.cs index b901c3f76..c49456ab0 100644 --- a/csharp/Lib/Protocols/Modbus/Clients/ModbusRtuClient.cs +++ b/csharp/Lib/Protocols/Modbus/Clients/ModbusRtuClient.cs @@ -30,7 +30,9 @@ public class ModbusRtuClient : ModbusClient public override ModbusRegisters ReadInputRegisters(UInt16 readAddress, UInt16 nValues) { - var cmd = new ReadInputRegistersCommandFrame(SlaveId, readAddress, nValues); + var wireReadAddress = LogicToWire(readAddress); + + var cmd = new ReadInputRegistersCommandFrame(SlaveId, wireReadAddress, nValues); var crc = CalcCrc(cmd); // TX @@ -54,7 +56,9 @@ public class ModbusRtuClient : ModbusClient public override ModbusRegisters ReadHoldingRegisters(UInt16 readAddress, UInt16 nValues) { - var cmd = new ReadHoldingRegistersCommandFrame(SlaveId, readAddress, nValues); + var wireReadAddress = LogicToWire(readAddress); + + var cmd = new ReadHoldingRegistersCommandFrame(SlaveId, wireReadAddress, nValues); var crc = CalcCrc(cmd.Data); // TX @@ -82,7 +86,9 @@ public class ModbusRtuClient : ModbusClient public override UInt16 WriteRegisters(UInt16 writeAddress, UInt16s values) { - var cmd = new WriteRegistersCommandFrame(SlaveId, writeAddress, values); + var wireWriteAddress = LogicToWire(writeAddress); + + var cmd = new WriteRegistersCommandFrame(SlaveId, wireWriteAddress, values); var crc = CalcCrc(cmd); var nToRead = cmd.ExpectedResponseSize + CrcSize; @@ -105,10 +111,16 @@ public class ModbusRtuClient : ModbusClient public override ModbusRegisters ReadWriteRegisters(UInt16 readAddress, UInt16 nbToRead, UInt16 writeAddress, UInt16s registersToWrite) { - var cmd = new ReadWriteRegistersCommandFrame(SlaveId, readAddress, nbToRead, writeAddress, registersToWrite); + var wireReadAddress = LogicToWire(readAddress); + var wireWriteAddress = LogicToWire(writeAddress); + + var cmd = new ReadWriteRegistersCommandFrame(SlaveId, + wireReadAddress, + nbToRead, + wireWriteAddress, + registersToWrite); var crc = CalcCrc(cmd); - // TX cmd.Data.Concat(crc).Apply(Connection.Transmit); diff --git a/csharp/Lib/Protocols/Modbus/Clients/ModbusTcpClient.cs b/csharp/Lib/Protocols/Modbus/Clients/ModbusTcpClient.cs index c0506cbf3..2952d4243 100644 --- a/csharp/Lib/Protocols/Modbus/Clients/ModbusTcpClient.cs +++ b/csharp/Lib/Protocols/Modbus/Clients/ModbusTcpClient.cs @@ -1,10 +1,11 @@ using System.Diagnostics; using InnovEnergy.Lib.Protocols.Modbus.Connections; using InnovEnergy.Lib.Protocols.Modbus.Conversions; +using InnovEnergy.Lib.Protocols.Modbus.Protocol; using InnovEnergy.Lib.Protocols.Modbus.Protocol.Frames.Commands; using InnovEnergy.Lib.Protocols.Modbus.Protocol.Frames.Replies; using InnovEnergy.Lib.Protocols.Modbus.Tcp; -using static InnovEnergy.Lib.Protocols.Modbus.Clients.Endianness; +using static InnovEnergy.Lib.Protocols.Modbus.Protocol.MultiRegisterEndianness; namespace InnovEnergy.Lib.Protocols.Modbus.Clients; @@ -20,16 +21,21 @@ public class ModbusTcpClient : ModbusClient private UInt16 NextId() => unchecked(++_Id); - public ModbusTcpClient(ModbusConnection connection, Byte slaveId, Endianness endianness = LittleEndian32BitIntegers | LittleEndian32Floats) : base(connection, slaveId, endianness) + public ModbusTcpClient(ModbusConnection connection, + Byte slaveId, + RegisterIndexing registerIndexing = RegisterIndexing.OneBased, + MultiRegisterEndianness endianness = LittleEndian) : base(connection, slaveId, registerIndexing, endianness) { } public override IReadOnlyList ReadDiscreteInputs(UInt16 readAddress, UInt16 nValues) { + var wireReadAddress = LogicToWire(readAddress); + var id = NextId(); // TODO: check response id - var cmd = new ReadDiscreteInputsCommandFrame(SlaveId, readAddress, nValues); + var cmd = new ReadDiscreteInputsCommandFrame(SlaveId, wireReadAddress, nValues); var hdr = new MbapHeader(id, cmd.Data.Count); var frm = new ModbusTcpFrame(hdr, cmd); @@ -46,9 +52,10 @@ public class ModbusTcpClient : ModbusClient public override ModbusRegisters ReadInputRegisters(UInt16 readAddress, UInt16 nValues) { + var wireReadAddress = LogicToWire(readAddress); var id = NextId(); // TODO: check response id - - var cmd = new ReadInputRegistersCommandFrame(SlaveId, readAddress, nValues); + + var cmd = new ReadInputRegistersCommandFrame(SlaveId, wireReadAddress, nValues); var hdr = new MbapHeader(id, cmd.Data.Count); var frm = new ModbusTcpFrame(hdr, cmd); @@ -65,12 +72,15 @@ public class ModbusTcpClient : ModbusClient return new ModbusRegisters(readAddress, verified.RegistersRead.ToArray()); } + + public override ModbusRegisters ReadHoldingRegisters(UInt16 readAddress, UInt16 nValues) { + var wireReadAddress = LogicToWire(readAddress); + var id = NextId(); // TODO: check response id - - var cmd = new ReadHoldingRegistersCommandFrame(SlaveId, readAddress, nValues); + var cmd = new ReadHoldingRegistersCommandFrame(SlaveId, wireReadAddress, nValues); var hdr = new MbapHeader(id, cmd.Data.Count); var frm = new ModbusTcpFrame(hdr, cmd); @@ -84,14 +94,15 @@ public class ModbusTcpClient : ModbusClient var verified = cmd.VerifyResponse(rxFrm); - return new ModbusRegisters(readAddress, verified.RegistersRead.ToArray()); + return new ModbusRegisters(readAddress, verified.RegistersRead.ToArray()); // TODO } public override UInt16 WriteMultipleCoils(UInt16 writeAddress, Coils coils) { + var wireWriteAddress = LogicToWire(writeAddress); + var id = NextId(); // TODO: check response id - - var cmd = new WriteCoilsCommandFrame(SlaveId, writeAddress, coils); + var cmd = new WriteCoilsCommandFrame(SlaveId, wireWriteAddress, coils); var hdr = new MbapHeader(id, cmd.Data.Count); var frm = new ModbusTcpFrame(hdr, cmd); @@ -109,9 +120,10 @@ public class ModbusTcpClient : ModbusClient public override UInt16 WriteRegisters(UInt16 writeAddress, UInt16s values) { + var wireWriteAddress = LogicToWire(writeAddress); + var id = NextId(); // TODO: check response id - - var cmd = new WriteRegistersCommandFrame(SlaveId, writeAddress, values); + var cmd = new WriteRegistersCommandFrame(SlaveId, wireWriteAddress, values); var hdr = new MbapHeader(id, cmd.Data.Count); var frm = new ModbusTcpFrame(hdr, cmd); @@ -130,9 +142,17 @@ public class ModbusTcpClient : ModbusClient public override ModbusRegisters ReadWriteRegisters(UInt16 readAddress, UInt16 nbToRead, UInt16 writeAddress, UInt16s registersToWrite) { + var wireReadAddress = LogicToWire(readAddress); + var wireWriteAddress = LogicToWire(writeAddress); + var id = NextId(); // TODO: check response id - var cmd = new ReadWriteRegistersCommandFrame(SlaveId, readAddress, nbToRead, writeAddress, registersToWrite); + var cmd = new ReadWriteRegistersCommandFrame(SlaveId, + wireReadAddress, + nbToRead, + wireWriteAddress, + registersToWrite); + var hdr = new MbapHeader(id, cmd.Data.Count); var frm = new ModbusTcpFrame(hdr, cmd); @@ -146,7 +166,7 @@ public class ModbusTcpClient : ModbusClient var verified = cmd.VerifyResponse(rxFrm); - return new ModbusRegisters(readAddress, verified.RegistersRead.ToArray()); + return new ModbusRegisters(readAddress, verified.RegistersRead.ToArray()); // TODO } } \ No newline at end of file From 5a082c22e8d8f8079570a3eb49a1f0223dbd67fd Mon Sep 17 00:00:00 2001 From: ig Date: Mon, 13 Mar 2023 11:36:50 +0100 Subject: [PATCH 4/5] Make DB class static --- csharp/App/Backend/Database/Db.cs | 79 +++++++++--------- csharp/App/Backend/Database/DbConnection.cs | 18 ----- csharp/App/Backend/Database/Fake.cs | 14 ++-- csharp/App/Backend/Database/Folder.cs | 81 ++++++++++++------- csharp/App/Backend/Database/Installation.cs | 38 ++++++--- csharp/App/Backend/Database/User.cs | 72 +++++++++++------ csharp/App/Backend/Database/User2Folder.cs | 8 +- .../App/Backend/Database/User2Installation.cs | 9 +-- 8 files changed, 177 insertions(+), 142 deletions(-) delete mode 100644 csharp/App/Backend/Database/DbConnection.cs diff --git a/csharp/App/Backend/Database/Db.cs b/csharp/App/Backend/Database/Db.cs index 3e673e05c..6da24a5f8 100644 --- a/csharp/App/Backend/Database/Db.cs +++ b/csharp/App/Backend/Database/Db.cs @@ -1,19 +1,18 @@ using System.Diagnostics.CodeAnalysis; using InnovEnergy.App.Backend.Model; using InnovEnergy.App.Backend.Model.Relations; -using InnovEnergy.App.Backend.Utils; using InnovEnergy.Lib.Utils; using SQLite; namespace InnovEnergy.App.Backend.Database; -public partial class Db : IDisposable +public static partial class Db { internal const String DbPath = "./db.sqlite"; - private readonly SQLiteConnection _Db; // internal handle to the connection, disposable + private static readonly SQLiteConnection _Db = new SQLiteConnection(DbPath); - private TableQuery Sessions => _Db.Table(); + private static TableQuery Sessions => _Db.Table(); [SuppressMessage("ReSharper", "AccessToDisposedClosure")] static Db() @@ -33,16 +32,9 @@ public partial class Db : IDisposable }); } - // private, force access through Connect() - private Db() => _Db = new SQLiteConnection(DbPath); - - public static Db Connect() => new Db(); - - public void Dispose() => _Db.Dispose(); - // the C in CRUD - private Int64 Create(TreeNode treeNode) + private static Int64 Create(TreeNode treeNode) { try { @@ -56,7 +48,7 @@ public partial class Db : IDisposable } - private Boolean Create(Session session) + private static Boolean Create(Session session) { try { @@ -70,7 +62,7 @@ public partial class Db : IDisposable } // the U in CRUD - private Boolean Update(TreeNode treeNode) + private static Boolean Update(TreeNode treeNode) { try { @@ -84,7 +76,7 @@ public partial class Db : IDisposable } // the D in CRUD - private Boolean Delete(TreeNode treeNode) + private static Boolean Delete(TreeNode treeNode) { try { @@ -97,49 +89,49 @@ public partial class Db : IDisposable } } - public IEnumerable GetAllAccessibleInstallations(User user) + public static IEnumerable GetAllAccessibleInstallations(User user) { - var direct = GetDirectlyAccessibleInstallations(user); + var direct = GetDirectlyAccessibleInstallations(user); var fromFolders = GetAllAccessibleFolders(user) - .SelectMany(GetChildInstallations); + .SelectMany(GetChildInstallations); return direct - .Concat(fromFolders) - .Distinct(); + .Concat(fromFolders) + .Distinct(); } - public IEnumerable GetAllAccessibleFolders(User user) + public static IEnumerable GetAllAccessibleFolders(User user) { return GetDirectlyAccessibleFolders(user) - .SelectMany(GetDescendantFolders) - .Distinct(); + .SelectMany(GetDescendantFolders) + .Distinct(); // Distinct because the user might have direct access // to a child folder of a folder he has already access to } - public IEnumerable GetDirectlyAccessibleInstallations(User user) + public static IEnumerable GetDirectlyAccessibleInstallations(User user) { return User2Installation - .Where(r => r.UserId == user.Id) - .Select(r => r.InstallationId) - .Select(GetInstallationById) - .NotNull() - .Do(i => i.ParentId = 0); // hide inaccessible parents from calling user + .Where(r => r.UserId == user.Id) + .Select(r => r.InstallationId) + .Select(GetInstallationById) + .NotNull() + .Do(i => i.ParentId = 0); // hide inaccessible parents from calling user } - public IEnumerable GetDirectlyAccessibleFolders(User user) + public static IEnumerable GetDirectlyAccessibleFolders(User user) { return User2Folder - .Where(r => r.UserId == user.Id) - .Select(r => r.FolderId) - .Select(GetFolderById) - .NotNull() - .Do(i => i.ParentId = 0); // hide inaccessible parents from calling user; + .Where(r => r.UserId == user.Id) + .Select(r => r.FolderId) + .Select(GetFolderById) + .NotNull() + .Do(i => i.ParentId = 0); // hide inaccessible parents from calling user; } - public Boolean AddToAccessibleInstallations(Int64 userId, Int64 updatedInstallationId) + public static Boolean AddToAccessibleInstallations(Int64 userId, Int64 updatedInstallationId) { var con = new User2Installation { @@ -158,7 +150,7 @@ public partial class Db : IDisposable } } - public Boolean AddToAccessibleFolders(Int64 userId, Int64 updatedFolderId) + public static Boolean AddToAccessibleFolders(Int64 userId, Int64 updatedFolderId) { var con = new User2Folder { @@ -178,7 +170,7 @@ public partial class Db : IDisposable } - public User? GetUserByToken(String token) + public static User? GetUserByToken(String token) { return Sessions .Where(s => s.Token == token).ToList() @@ -189,9 +181,9 @@ public partial class Db : IDisposable } - public Boolean NewSession(Session ses) => Create(ses); + public static Boolean NewSession(Session ses) => Create(ses); - public Boolean DeleteSession(Int64 id) + public static Boolean DeleteSession(Int64 id) { try { @@ -204,13 +196,14 @@ public partial class Db : IDisposable } } - public Object? GetInstallationS3Key(Int64 installationId) + public static String? GetInstallationS3Key(Int64 installationId) { return Installations - .FirstOrDefault(installation => installation.Id == installationId).S3Key; + .FirstOrDefault(i => i.Id == installationId)? + .S3Key; } - public void DeleteS3KeysDaily() + public static void DeleteAllS3Keys() { foreach (var installation in Installations.ToList()) { diff --git a/csharp/App/Backend/Database/DbConnection.cs b/csharp/App/Backend/Database/DbConnection.cs deleted file mode 100644 index 4676ca498..000000000 --- a/csharp/App/Backend/Database/DbConnection.cs +++ /dev/null @@ -1,18 +0,0 @@ -using InnovEnergy.App.Backend.Model; -using SQLite; - -namespace InnovEnergy.App.Backend.Database; - - -// TODO ? -public struct DbConnection -{ - public DbConnection(SQLiteConnection connection, User caller) - { - Connection = connection; - Caller = caller; - } - - public SQLiteConnection Connection { get;} - public User Caller { get;} -} \ No newline at end of file diff --git a/csharp/App/Backend/Database/Fake.cs b/csharp/App/Backend/Database/Fake.cs index 63fff39ee..6c88cc3be 100644 --- a/csharp/App/Backend/Database/Fake.cs +++ b/csharp/App/Backend/Database/Fake.cs @@ -2,9 +2,9 @@ using InnovEnergy.App.Backend.Model.Relations; namespace InnovEnergy.App.Backend.Database; -public partial class Db +public static partial class Db { - public void CreateFakeRelations() + public static void CreateFakeRelations() { _Db.RunInTransaction(() => { @@ -16,7 +16,7 @@ public partial class Db }); } - private void CreateFakeUserTree() + private static void CreateFakeUserTree() { foreach (var userId in Enumerable.Range(1, NbUsers)) { @@ -32,7 +32,7 @@ public partial class Db } } - private void CreateFakeFolderTree() + private static void CreateFakeFolderTree() { foreach (var folderId in Enumerable.Range(1, NbFolders)) { @@ -48,7 +48,7 @@ public partial class Db } } - private void LinkFakeInstallationsToFolders() + private static void LinkFakeInstallationsToFolders() { var nFolders = NbFolders; @@ -59,7 +59,7 @@ public partial class Db } } - private void GiveFakeUsersAccessToFolders() + private static void GiveFakeUsersAccessToFolders() { foreach (var uf in User2Folder) // remove existing relations _Db.Delete(uf); @@ -79,7 +79,7 @@ public partial class Db } } - private void GiveFakeUsersAccessToInstallations() + private static void GiveFakeUsersAccessToInstallations() { foreach (var ui in User2Installation) // remove existing relations _Db.Delete(ui); diff --git a/csharp/App/Backend/Database/Folder.cs b/csharp/App/Backend/Database/Folder.cs index 1204ed06c..3b08ad654 100644 --- a/csharp/App/Backend/Database/Folder.cs +++ b/csharp/App/Backend/Database/Folder.cs @@ -1,17 +1,16 @@ using InnovEnergy.App.Backend.Model; -using InnovEnergy.App.Backend.Utils; using InnovEnergy.Lib.Utils; using SQLite; namespace InnovEnergy.App.Backend.Database; -public partial class Db +public static partial class Db { - private TableQuery Folders => _Db.Table(); + private static TableQuery Folders => _Db.Table(); - public Int32 NbFolders => Folders.Count(); + public static Int32 NbFolders => Folders.Count(); - public Folder? GetFolderById(Int64 id) + public static Folder? GetFolderById(Int64 id) { return Folders.FirstOrDefault(u => u.Id == id); @@ -21,56 +20,76 @@ public partial class Db //return PopulateDescendants(folder); } - public IEnumerable GetChildFolders(Folder parent) + public static IEnumerable GetChildFolders(Folder parent) { return Folders.Where(f => f.ParentId == parent.Id); } - - public IEnumerable GetDescendantFolders(Folder parent) - { - return parent.Traverse(GetChildFolders); - } - - public IEnumerable GetChildInstallations(Folder parent) + + public static IEnumerable GetChildInstallations(Folder parent) { return Installations.Where(f => f.ParentId == parent.Id); } - public IEnumerable GetChildUsers(User parent) + public static IEnumerable GetDescendantFolders(Folder parent) { - return Users.Where(f => f.ParentId == parent.Id); + return parent.Traverse(GetChildFolders); } - public IEnumerable GetDescendantUsers(User parent) + public static Boolean IsDescendantOf(Folder folder, Int64 ancestorFolderId) { - return parent.Traverse(GetChildUsers); + return Ancestors(folder) + .Any(u => u.Id == ancestorFolderId); } - public Int64 CreateFolder(Folder folder) + public static Boolean IsDescendantOf(Folder folder, Folder ancestor) + { + return IsDescendantOf(folder, ancestor.Id); + } + + private static IEnumerable Ancestors(Folder child) + { + return child.Unfold(GetParent); + } + + public static Folder? GetParent(Folder f) + { + return IsRoot(f) + ? null + : GetFolderById(f.ParentId); + } + + public static Boolean IsRoot(Folder f) + { + return f.ParentId == 0; // root has ParentId 0 by definition + } + + public static Int64 CreateFolder(Folder folder) { return Create(folder); } - public Boolean UpdateFolder(Folder folder) + public static Boolean UpdateFolder(Folder folder) { // TODO: no circles in path return Update(folder); } - public Boolean ChangeParent(Installation child, Int64 parentId) - { - child.ParentId = parentId; - return UpdateInstallation(child); - } - - public Boolean ChangeParent(Folder child, Int64 parentId) - { - child.ParentId = parentId; - return UpdateFolder(child); - } + // These should not be necessary, just Update folder/installation with new parentId - public Boolean DeleteFolder(Folder folder) + // public Boolean ChangeParent(Installation child, Int64 parentId) + // { + // child.ParentId = parentId; + // return UpdateInstallation(child); + // } + // + // public Boolean ChangeParent(Folder child, Int64 parentId) + // { + // child.ParentId = parentId; + // return UpdateFolder(child); + // } + + public static Boolean DeleteFolder(Folder folder) { // Delete direct children User2Folder .Delete(f => f.FolderId == folder.Id); diff --git a/csharp/App/Backend/Database/Installation.cs b/csharp/App/Backend/Database/Installation.cs index de8aae85b..777b19cbc 100644 --- a/csharp/App/Backend/Database/Installation.cs +++ b/csharp/App/Backend/Database/Installation.cs @@ -1,37 +1,55 @@ using InnovEnergy.App.Backend.Model; -using InnovEnergy.App.Backend.Utils; using SQLite; namespace InnovEnergy.App.Backend.Database; -public partial class Db +public static partial class Db { - private TableQuery Installations => _Db.Table(); + private static TableQuery Installations => _Db.Table(); - public Int32 NbInstallations => Installations.Count(); + public static Int32 NbInstallations => Installations.Count(); - public Installation? GetInstallationById(Int64 id) => Installations + public static Installation? GetInstallationById(Int64 id) => Installations .FirstOrDefault(u => u.Id == id); - public Int64 CreateInstallation(Installation installation) + private static IEnumerable Ancestors(Installation installation) + { + var parentFolder = GetParent(installation); + + return parentFolder is null + ? Enumerable.Empty() + : Ancestors(parentFolder); + } + + public static Folder? GetParent(Installation installation) + { + return IsRoot(installation) + ? null + : GetFolderById(installation.ParentId); + } + + public static Boolean IsRoot(Installation i) + { + return i.ParentId == 0; // root has ParentId 0 by definition + } + + public static Int64 CreateInstallation(Installation installation) { return Create(installation); } - public Boolean UpdateInstallation(Installation installation) + public static Boolean UpdateInstallation(Installation installation) { return Update(installation); } - - public Boolean DeleteInstallation(Installation installation) + public static Boolean DeleteInstallation(Installation installation) { User2Installation.Delete(i => i.InstallationId == installation.Id); return Delete(installation); } - } diff --git a/csharp/App/Backend/Database/User.cs b/csharp/App/Backend/Database/User.cs index 980786076..09c52bd85 100644 --- a/csharp/App/Backend/Database/User.cs +++ b/csharp/App/Backend/Database/User.cs @@ -9,34 +9,43 @@ using InnovEnergy.App.Backend.Utils; using InnovEnergy.Lib.Utils; using SQLite; -#pragma warning disable CS0472 -#pragma warning disable CS8602 namespace InnovEnergy.App.Backend.Database; -public partial class Db + +public static partial class Db { - private TableQuery Users => _Db.Table(); + private static TableQuery Users => _Db.Table(); - public Int32 NbUsers => Users.Count(); + public static Int32 NbUsers => Users.Count(); - public User? GetUserById(Int64 id) + public static IEnumerable GetChildUsers(User parent) + { + return Users.Where(f => f.ParentId == parent.Id); + } + + public static IEnumerable GetDescendantUsers(User parent) + { + return parent.Traverse(GetChildUsers); + } + + public static User? GetUserById(Int64 id) { return Users.FirstOrDefault(u => u.Id == id); } - public Boolean IsParentOfChild(Int64 parentId, User child) + public static Boolean IsDescendantOf(User user, User ancestor) { - return Ancestors(child) - .Any(u => u.Id == parentId); + return Ancestors(user) + .Any(u => u.Id == ancestor.Id); } - - private IEnumerable Ancestors(User child) + + private static IEnumerable Ancestors(User child) { return child.Unfold(GetParent); } - public User? GetParent(User u) + public static User? GetParent(User u) { return IsRoot(u) ? null @@ -48,9 +57,28 @@ public partial class Db return u.ParentId == 0; // root has ParentId 0 by definition } - public User? GetUserByEmail(String email) => Users.FirstOrDefault(u => u.Email == email); + public static Boolean HasDirectAccessToFolder(User user, Folder folder) + { + return HasDirectAccessToFolder(user, folder.Id); + } + + public static Boolean HasDirectAccessToFolder(User user, Int64 folderId) + { + return User2Folder.Any(r => r.FolderId == folderId && r.UserId == user.Id); + } + + public static Boolean HasAccessToFolder(User user, Int64 folderId) + { + var folder = GetFolderById(folderId); + if (folder is null) + return false; - public Int64 CreateUser(User user) + return Ancestors(folder).Any(f => HasDirectAccessToFolder(user, f)); + } + + public static User? GetUserByEmail(String email) => Users.FirstOrDefault(u => u.Email == email); + + public static Int64 CreateUser(User user) { if (GetUserByEmail(user.Email) is not null) return -1; // TODO: User with that email already exists @@ -69,13 +97,12 @@ public partial class Db private static Byte[] HmacSha256Digest(String message, String secret) { - var encoding = new UTF8Encoding(); - var keyBytes = encoding.GetBytes(secret); - var messageBytes = encoding.GetBytes(message); + var encoding = new UTF8Encoding(); + var keyBytes = encoding.GetBytes(secret); + var messageBytes = encoding.GetBytes(message); var cryptographer = new HMACSHA256(keyBytes); - var bytes = cryptographer.ComputeHash(messageBytes); - return bytes; + return cryptographer.ComputeHash(messageBytes); } private static String BuildSignature(String method, String path, String data, Int64 time, String secret) @@ -93,7 +120,6 @@ public partial class Db Console.WriteLine("Message to sign:\n" + messageToSign); - var hmac = HmacSha256Digest(messageToSign, secret); return Convert.ToBase64String(hmac); } @@ -149,7 +175,7 @@ public partial class Db // // } - public Object? CreateAndSaveInstallationS3ApiKey(Installation installation) + public static Object CreateAndSaveInstallationS3ApiKey(Installation installation) { //EXOSCALE API URL const String url = "https://api-ch-dk-2.exoscale.com/v2/"; @@ -192,7 +218,7 @@ public partial class Db return newKey; } - public Boolean UpdateUser(User user) + public static Boolean UpdateUser(User user) { var oldUser = GetUserById(user.Id); if (oldUser == null) @@ -208,7 +234,7 @@ public partial class Db return Update(user); } - public Boolean DeleteUser(User user) + public static Boolean DeleteUser(User user) { User2Folder.Delete(u => u.UserId == user.Id); User2Installation.Delete(u => u.UserId == user.Id); diff --git a/csharp/App/Backend/Database/User2Folder.cs b/csharp/App/Backend/Database/User2Folder.cs index 29351f1dd..38316200f 100644 --- a/csharp/App/Backend/Database/User2Folder.cs +++ b/csharp/App/Backend/Database/User2Folder.cs @@ -1,12 +1,12 @@ using InnovEnergy.App.Backend.Model.Relations; using SQLite; -namespace InnovEnergy.App.Backend.Database; +namespace InnovEnergy.App.Backend.Database; -public partial class Db +public static partial class Db { - private TableQuery User2Folder => _Db.Table(); - public Int32 NbUser2Folder => User2Folder.Count(); + private static TableQuery User2Folder => _Db.Table(); + public static Int32 NbUser2Folder => User2Folder.Count(); } diff --git a/csharp/App/Backend/Database/User2Installation.cs b/csharp/App/Backend/Database/User2Installation.cs index 069588d7c..0f8eb36a0 100644 --- a/csharp/App/Backend/Database/User2Installation.cs +++ b/csharp/App/Backend/Database/User2Installation.cs @@ -3,12 +3,9 @@ using SQLite; namespace InnovEnergy.App.Backend.Database; -public partial class Db +public static partial class Db { - private TableQuery User2Installation => _Db.Table(); - public Int32 NbUser2Installation => User2Installation.Count(); - - - + private static TableQuery User2Installation => _Db.Table(); + public static Int32 NbUser2Installation => User2Installation.Count(); } From d974a7f1761f6465436a9d24043576a3f49696ea Mon Sep 17 00:00:00 2001 From: ig Date: Mon, 13 Mar 2023 11:48:04 +0100 Subject: [PATCH 5/5] Move tables to main DB class, convert entity related function to extensions --- csharp/App/Backend/Database/Db.cs | 49 +++++++++++++++---- csharp/App/Backend/Database/Fake.cs | 10 ++-- csharp/App/Backend/Database/Folder.cs | 31 +++--------- csharp/App/Backend/Database/Installation.cs | 20 +++----- csharp/App/Backend/Database/User.cs | 32 +++++------- csharp/App/Backend/Database/User2Folder.cs | 12 ----- .../App/Backend/Database/User2Installation.cs | 11 ----- 7 files changed, 70 insertions(+), 95 deletions(-) delete mode 100644 csharp/App/Backend/Database/User2Folder.cs delete mode 100644 csharp/App/Backend/Database/User2Installation.cs diff --git a/csharp/App/Backend/Database/Db.cs b/csharp/App/Backend/Database/Db.cs index 6da24a5f8..b2e488228 100644 --- a/csharp/App/Backend/Database/Db.cs +++ b/csharp/App/Backend/Database/Db.cs @@ -10,9 +10,40 @@ public static partial class Db { internal const String DbPath = "./db.sqlite"; - private static readonly SQLiteConnection _Db = new SQLiteConnection(DbPath); + public static SQLiteConnection Connection { get; } = new SQLiteConnection(DbPath); + + public static TableQuery Sessions => Connection.Table(); + public static TableQuery Folders => Connection.Table(); + public static TableQuery Installations => Connection.Table(); + public static TableQuery Users => Connection.Table(); + public static TableQuery User2Folder => Connection.Table(); + public static TableQuery User2Installation => Connection.Table(); + + public static Int32 NbUser2Installation => User2Installation.Count(); + public static Int32 NbUser2Folder => User2Folder.Count(); + public static Int32 NbFolders => Folders.Count(); + public static Int32 NbInstallations => Installations.Count(); + public static Int32 NbUsers => Users.Count(); + + + public static Folder? GetFolderById(Int64 id) + { + return Folders + .FirstOrDefault(f => f.Id == id); + } + + public static Installation? GetInstallationById(Int64 id) + { + return Installations + .FirstOrDefault(i => i.Id == id); + } + + public static User? GetUserById(Int64 id) + { + return Users + .FirstOrDefault(u => u.Id == id); + } - private static TableQuery Sessions => _Db.Table(); [SuppressMessage("ReSharper", "AccessToDisposedClosure")] static Db() @@ -38,8 +69,8 @@ public static partial class Db { try { - _Db.Insert(treeNode); - return SQLite3.LastInsertRowid(_Db.Handle); + Connection.Insert(treeNode); + return SQLite3.LastInsertRowid(Connection.Handle); } catch (Exception e) { @@ -52,7 +83,7 @@ public static partial class Db { try { - _Db.Insert(session); + Connection.Insert(session); return true; } catch (Exception e) @@ -66,7 +97,7 @@ public static partial class Db { try { - _Db.InsertOrReplace(treeNode); + Connection.InsertOrReplace(treeNode); return true; } catch (Exception e) @@ -80,7 +111,7 @@ public static partial class Db { try { - _Db.Delete(treeNode); + Connection.Delete(treeNode); return true; } catch (Exception e) @@ -141,7 +172,7 @@ public static partial class Db try { - _Db.Insert(con); + Connection.Insert(con); return true; } catch (Exception e) @@ -160,7 +191,7 @@ public static partial class Db try { - _Db.Insert(con); + Connection.Insert(con); return true; } catch (Exception e) diff --git a/csharp/App/Backend/Database/Fake.cs b/csharp/App/Backend/Database/Fake.cs index 6c88cc3be..7eca66ce8 100644 --- a/csharp/App/Backend/Database/Fake.cs +++ b/csharp/App/Backend/Database/Fake.cs @@ -6,7 +6,7 @@ public static partial class Db { public static void CreateFakeRelations() { - _Db.RunInTransaction(() => + Connection.RunInTransaction(() => { CreateFakeUserTree(); CreateFakeFolderTree(); @@ -62,7 +62,7 @@ public static partial class Db private static void GiveFakeUsersAccessToFolders() { foreach (var uf in User2Folder) // remove existing relations - _Db.Delete(uf); + Connection.Delete(uf); var nFolders = NbFolders; var nUsers = NbUsers; @@ -75,14 +75,14 @@ public static partial class Db UserId = user.Id, FolderId = Random.Shared.Next(nFolders) + 1 }; - _Db.Insert(relation); + Connection.Insert(relation); } } private static void GiveFakeUsersAccessToInstallations() { foreach (var ui in User2Installation) // remove existing relations - _Db.Delete(ui); + Connection.Delete(ui); var nbInstallations = NbInstallations; @@ -94,7 +94,7 @@ public static partial class Db UserId = user.Id, InstallationId = Random.Shared.Next(nbInstallations) + 1 }; - _Db.Insert(relation); + Connection.Insert(relation); } } } \ No newline at end of file diff --git a/csharp/App/Backend/Database/Folder.cs b/csharp/App/Backend/Database/Folder.cs index 3b08ad654..9383354c2 100644 --- a/csharp/App/Backend/Database/Folder.cs +++ b/csharp/App/Backend/Database/Folder.cs @@ -1,64 +1,49 @@ using InnovEnergy.App.Backend.Model; using InnovEnergy.Lib.Utils; -using SQLite; namespace InnovEnergy.App.Backend.Database; public static partial class Db { - private static TableQuery Folders => _Db.Table(); - - public static Int32 NbFolders => Folders.Count(); - - public static Folder? GetFolderById(Int64 id) - { - return Folders.FirstOrDefault(u => u.Id == id); - - // if (folder is null) - // return null; - - //return PopulateDescendants(folder); - } - - public static IEnumerable GetChildFolders(Folder parent) + public static IEnumerable GetChildFolders(this Folder parent) { return Folders.Where(f => f.ParentId == parent.Id); } - public static IEnumerable GetChildInstallations(Folder parent) + public static IEnumerable GetChildInstallations(this Folder parent) { return Installations.Where(f => f.ParentId == parent.Id); } - public static IEnumerable GetDescendantFolders(Folder parent) + public static IEnumerable GetDescendantFolders(this Folder parent) { return parent.Traverse(GetChildFolders); } - public static Boolean IsDescendantOf(Folder folder, Int64 ancestorFolderId) + public static Boolean IsDescendantOf(this Folder folder, Int64 ancestorFolderId) { return Ancestors(folder) .Any(u => u.Id == ancestorFolderId); } - public static Boolean IsDescendantOf(Folder folder, Folder ancestor) + public static Boolean IsDescendantOf(this Folder folder, Folder ancestor) { return IsDescendantOf(folder, ancestor.Id); } - private static IEnumerable Ancestors(Folder child) + private static IEnumerable Ancestors(this Folder child) { return child.Unfold(GetParent); } - public static Folder? GetParent(Folder f) + public static Folder? GetParent(this Folder f) { return IsRoot(f) ? null : GetFolderById(f.ParentId); } - public static Boolean IsRoot(Folder f) + public static Boolean IsRoot(this Folder f) { return f.ParentId == 0; // root has ParentId 0 by definition } diff --git a/csharp/App/Backend/Database/Installation.cs b/csharp/App/Backend/Database/Installation.cs index 777b19cbc..3220637c0 100644 --- a/csharp/App/Backend/Database/Installation.cs +++ b/csharp/App/Backend/Database/Installation.cs @@ -5,15 +5,7 @@ namespace InnovEnergy.App.Backend.Database; public static partial class Db { - - private static TableQuery Installations => _Db.Table(); - - public static Int32 NbInstallations => Installations.Count(); - - public static Installation? GetInstallationById(Int64 id) => Installations - .FirstOrDefault(u => u.Id == id); - - private static IEnumerable Ancestors(Installation installation) + public static IEnumerable Ancestors(this Installation installation) { var parentFolder = GetParent(installation); @@ -22,29 +14,29 @@ public static partial class Db : Ancestors(parentFolder); } - public static Folder? GetParent(Installation installation) + public static Folder? GetParent(this Installation installation) { return IsRoot(installation) ? null : GetFolderById(installation.ParentId); } - public static Boolean IsRoot(Installation i) + public static Boolean IsRoot(this Installation i) { return i.ParentId == 0; // root has ParentId 0 by definition } - public static Int64 CreateInstallation(Installation installation) + public static Int64 CreateInstallation(this Installation installation) { return Create(installation); } - public static Boolean UpdateInstallation(Installation installation) + public static Boolean UpdateInstallation(this Installation installation) { return Update(installation); } - public static Boolean DeleteInstallation(Installation installation) + public static Boolean DeleteInstallation(this Installation installation) { User2Installation.Delete(i => i.InstallationId == installation.Id); diff --git a/csharp/App/Backend/Database/User.cs b/csharp/App/Backend/Database/User.cs index 09c52bd85..5d91f3eee 100644 --- a/csharp/App/Backend/Database/User.cs +++ b/csharp/App/Backend/Database/User.cs @@ -7,67 +7,57 @@ using System.Text.RegularExpressions; using InnovEnergy.App.Backend.Model; using InnovEnergy.App.Backend.Utils; using InnovEnergy.Lib.Utils; -using SQLite; namespace InnovEnergy.App.Backend.Database; - public static partial class Db { - private static TableQuery Users => _Db.Table(); - - public static Int32 NbUsers => Users.Count(); - - public static IEnumerable GetChildUsers(User parent) + public static IEnumerable GetChildUsers(this User parent) { - return Users.Where(f => f.ParentId == parent.Id); + return Users + .Where(f => f.ParentId == parent.Id); } - public static IEnumerable GetDescendantUsers(User parent) + public static IEnumerable GetDescendantUsers(this User parent) { return parent.Traverse(GetChildUsers); } - - public static User? GetUserById(Int64 id) - { - return Users.FirstOrDefault(u => u.Id == id); - } - public static Boolean IsDescendantOf(User user, User ancestor) + public static Boolean IsDescendantOf(this User user, User ancestor) { return Ancestors(user) .Any(u => u.Id == ancestor.Id); } - private static IEnumerable Ancestors(User child) + private static IEnumerable Ancestors(this User child) { return child.Unfold(GetParent); } - public static User? GetParent(User u) + public static User? GetParent(this User u) { return IsRoot(u) ? null : GetUserById(u.ParentId); } - public static Boolean IsRoot(User u) + public static Boolean IsRoot(this User u) { return u.ParentId == 0; // root has ParentId 0 by definition } - public static Boolean HasDirectAccessToFolder(User user, Folder folder) + public static Boolean HasDirectAccessToFolder(this User user, Folder folder) { return HasDirectAccessToFolder(user, folder.Id); } - public static Boolean HasDirectAccessToFolder(User user, Int64 folderId) + public static Boolean HasDirectAccessToFolder(this User user, Int64 folderId) { return User2Folder.Any(r => r.FolderId == folderId && r.UserId == user.Id); } - public static Boolean HasAccessToFolder(User user, Int64 folderId) + public static Boolean HasAccessToFolder(this User user, Int64 folderId) { var folder = GetFolderById(folderId); if (folder is null) diff --git a/csharp/App/Backend/Database/User2Folder.cs b/csharp/App/Backend/Database/User2Folder.cs deleted file mode 100644 index 38316200f..000000000 --- a/csharp/App/Backend/Database/User2Folder.cs +++ /dev/null @@ -1,12 +0,0 @@ -using InnovEnergy.App.Backend.Model.Relations; -using SQLite; - -namespace InnovEnergy.App.Backend.Database; - -public static partial class Db -{ - private static TableQuery User2Folder => _Db.Table(); - public static Int32 NbUser2Folder => User2Folder.Count(); - -} - diff --git a/csharp/App/Backend/Database/User2Installation.cs b/csharp/App/Backend/Database/User2Installation.cs deleted file mode 100644 index 0f8eb36a0..000000000 --- a/csharp/App/Backend/Database/User2Installation.cs +++ /dev/null @@ -1,11 +0,0 @@ -using InnovEnergy.App.Backend.Model.Relations; -using SQLite; - -namespace InnovEnergy.App.Backend.Database; - -public static partial class Db -{ - private static TableQuery User2Installation => _Db.Table(); - public static Int32 NbUser2Installation => User2Installation.Count(); -} -