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));
}
}
}