using System; using System.Collections.Generic; using NModbus; namespace Team.Utility { public class SlaveStorage : ISlaveDataStore { private readonly SparsePointSource<bool> _coilDiscretes; private readonly SparsePointSource<bool> _coilInputs; private readonly SparsePointSource<ushort> _holdingRegisters; private readonly SparsePointSource<ushort> _inputRegisters; public SlaveStorage() { _coilDiscretes = new SparsePointSource<bool>(); _coilInputs = new SparsePointSource<bool>(); _holdingRegisters = new SparsePointSource<ushort>(); _inputRegisters = new SparsePointSource<ushort>(); } public SparsePointSource<bool> CoilDiscretes { get { return _coilDiscretes; } } public SparsePointSource<bool> CoilInputs { get { return _coilInputs; } } public SparsePointSource<ushort> HoldingRegisters { get { return _holdingRegisters; } } public SparsePointSource<ushort> InputRegisters { get { return _inputRegisters; } } IPointSource<bool> ISlaveDataStore.CoilDiscretes { get { return _coilDiscretes; } } IPointSource<bool> ISlaveDataStore.CoilInputs { get { return _coilInputs; } } IPointSource<ushort> ISlaveDataStore.HoldingRegisters { get { return _holdingRegisters; } } IPointSource<ushort> ISlaveDataStore.InputRegisters { get { return _inputRegisters; } } } public class SparsePointSource<TPoint> : IPointSource<TPoint> { private readonly Dictionary<ushort, TPoint> _values = new(); public event EventHandler<StorageEventArgs<TPoint>> StorageOperationOccurred; /// <summary> /// Gets or sets the value of an individual point wih tout /// </summary> /// <param name="registerIndex"></param> /// <returns></returns> public TPoint this[ushort registerIndex] { get => _values.TryGetValue(registerIndex, out var value) ? value : default; set => _values[registerIndex] = value; } public TPoint[] ReadPoints(ushort startAddress, ushort numberOfPoints) { var points = new TPoint[numberOfPoints]; for (ushort index = 0; index < numberOfPoints; index++) { points[index] = this[(ushort)(index + startAddress)]; } StorageOperationOccurred?.Invoke(this, new StorageEventArgs<TPoint>(PointOperation.Read, startAddress, points)); return points; } public void WritePoints(ushort startAddress, TPoint[] points) { for (ushort index = 0; index < points.Length; index++) { this[(ushort)(index + startAddress)] = points[index]; } StorageOperationOccurred?.Invoke(this, new StorageEventArgs<TPoint>(PointOperation.Write, startAddress, points)); } } public class StorageEventArgs<TPoint> : EventArgs { private readonly TPoint[] _points; public StorageEventArgs(PointOperation pointOperation, ushort startingAddress, TPoint[] points) { Operation = pointOperation; StartingAddress = startingAddress; _points = points; } public ushort StartingAddress { get; } public TPoint[] Points => _points; public PointOperation Operation { get; } } public enum PointOperation { Read, Write } }