using System; using System.Collections.Generic; using System.Collections.ObjectModel; using Modbus.Utility; namespace Modbus.Data { /// /// 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 { /// /// Occurs when the DataStore is read from via a Modbus command. /// public event EventHandler DataStoreReadFrom; /// /// Occurs when the DataStore is written to via a Modbus command. /// public event EventHandler DataStoreWrittenTo; 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 }; } /// /// Gets the coil discretes. /// public ModbusDataCollection CoilDiscretes { get; private set; } /// /// Gets the input discretes. /// public ModbusDataCollection InputDiscretes { get; private set; } /// /// Gets the holding registers. /// public ModbusDataCollection HoldingRegisters { get; private set; } /// /// Gets the input registers. /// public ModbusDataCollection InputRegisters { get; private set; } /// /// 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() { int startIndex = startAddress + 1; if (startIndex < 0 || startIndex >= dataSource.Count) throw new ArgumentOutOfRangeException("Start address was out of range. Must be non-negative and <= the size of the collection."); if (dataSource.Count < startIndex + count) throw new ArgumentOutOfRangeException("Read is outside valid range."); U[] dataToRetrieve; lock(syncRoot) dataToRetrieve = CollectionUtility.Slice(dataSource, startIndex, count); T result = new T(); for (int i = 0; i < count; i++) result.Add(dataToRetrieve[i]); EventHandler handler = dataStore.DataStoreReadFrom; if (handler != null) handler(dataStore, DataStoreEventArgs.CreateDataStoreEventArgs(startAddress, dataSource.ModbusDataType, result)); return result; } /// /// Write data to data store. /// /// The type of the data. internal static void WriteData(DataStore dataStore, IList items, ModbusDataCollection destination, ushort startAddress, object syncRoot) { int startIndex = startAddress + 1; if (startIndex < 0 || startIndex >= destination.Count) throw new ArgumentOutOfRangeException("Start address was out of range. Must be non-negative and <= the size of the collection."); if (destination.Count < startIndex + items.Count) throw new ArgumentOutOfRangeException("Items collection is too large to write at specified start index."); lock (syncRoot) CollectionUtility.Update(items, destination, startIndex); EventHandler handler = dataStore.DataStoreWrittenTo; if (handler != null) handler(dataStore, DataStoreEventArgs.CreateDataStoreEventArgs(startAddress, destination.ModbusDataType, items)); } } }