namespace Modbus.Data { using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using Unme.Common; /// /// Object simulation of device memory map. /// The underlying collections are thread safe when using the ModbusMaster API to read/write values. /// You can use the SyncRoot property to synchronize direct access to the DataStore collections. /// public class DataStore { private readonly object _syncRoot = new object(); /// /// Initializes a new instance of the class. /// public DataStore() { CoilDiscretes = new ModbusDataCollection { ModbusDataType = ModbusDataType.Coil }; InputDiscretes = new ModbusDataCollection { ModbusDataType = ModbusDataType.Input }; HoldingRegisters = new ModbusDataCollection { ModbusDataType = ModbusDataType.HoldingRegister }; InputRegisters = new ModbusDataCollection { ModbusDataType = ModbusDataType.InputRegister }; } /// /// Initializes a new instance of the class. /// /// List of discrete coil values. /// List of discrete input values /// List of holding register values. /// List of input register values. internal DataStore( IList coilDiscretes, IList inputDiscretes, IList holdingRegisters, IList inputRegisters) { CoilDiscretes = new ModbusDataCollection(coilDiscretes) { ModbusDataType = ModbusDataType.Coil }; InputDiscretes = new ModbusDataCollection(inputDiscretes) { ModbusDataType = ModbusDataType.Input }; HoldingRegisters = new ModbusDataCollection(holdingRegisters) { ModbusDataType = ModbusDataType.HoldingRegister }; InputRegisters = new ModbusDataCollection(inputRegisters) { ModbusDataType = ModbusDataType.InputRegister }; } /// /// Occurs when the DataStore is written to via a Modbus command. /// public event EventHandler DataStoreWrittenTo; /// /// Occurs when the DataStore is read from via a Modbus command. /// public event EventHandler DataStoreReadFrom; /// /// Gets the discrete coils. /// public ModbusDataCollection CoilDiscretes { get; } /// /// Gets the discrete inputs. /// public ModbusDataCollection InputDiscretes { get; } /// /// Gets the holding registers. /// public ModbusDataCollection HoldingRegisters { get; } /// /// Gets the input registers. /// public ModbusDataCollection InputRegisters { get; } /// /// An object that can be used to synchronize direct access to the DataStore collections. /// public object SyncRoot { get { return _syncRoot; } } /// /// Retrieves subset of data from collection. /// /// The collection type. /// The type of elements in the collection. internal static T ReadData( DataStore dataStore, ModbusDataCollection dataSource, ushort startAddress, ushort count, object syncRoot) where T : Collection, new() { DataStoreEventArgs dataStoreEventArgs; int startIndex = startAddress + 1; if (startIndex < 0 || dataSource.Count < startIndex + count) { throw new InvalidModbusRequestException(Modbus.IllegalDataAddress); } U[] dataToRetrieve; lock (syncRoot) { dataToRetrieve = dataSource.Slice(startIndex, count).ToArray(); } T result = new T(); for (int i = 0; i < count; i++) { result.Add(dataToRetrieve[i]); } dataStoreEventArgs = DataStoreEventArgs.CreateDataStoreEventArgs(startAddress, dataSource.ModbusDataType, result); dataStore.DataStoreReadFrom?.Invoke(dataStore, dataStoreEventArgs); return result; } /// /// Write data to data store. /// /// The type of the data. internal static void WriteData( DataStore dataStore, IEnumerable items, ModbusDataCollection destination, ushort startAddress, object syncRoot) { DataStoreEventArgs dataStoreEventArgs; int startIndex = startAddress + 1; if (startIndex < 0 || destination.Count < startIndex + items.Count()) { throw new InvalidModbusRequestException(Modbus.IllegalDataAddress); } lock (syncRoot) { Update(items, destination, startIndex); } dataStoreEventArgs = DataStoreEventArgs.CreateDataStoreEventArgs( startAddress, destination.ModbusDataType, items); dataStore.DataStoreWrittenTo?.Invoke(dataStore, dataStoreEventArgs); } /// /// Updates subset of values in a collection. /// internal static void Update(IEnumerable items, IList destination, int startIndex) { if (startIndex < 0 || destination.Count < startIndex + items.Count()) { throw new InvalidModbusRequestException(Modbus.IllegalDataAddress); } int index = startIndex; foreach (T item in items) { destination[index] = item; ++index; } } } }