using System;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using log4net;
using Modbus.Data;
using Modbus.IO;
using Modbus.Message;
using Modbus.Utility;
namespace Modbus.Device
{
///
/// Modbus slave device.
///
public abstract class ModbusSlave : ModbusDevice
{
///
/// Occurs when a modbus slave receives a request.
///
public event EventHandler ModbusSlaveRequestReceived;
private static readonly ILog _logger = LogManager.GetLogger(typeof(ModbusSlave));
internal ModbusSlave(byte unitId, ModbusTransport transport)
: base(transport)
{
DataStore = DataStoreFactory.CreateDefaultDataStore();
UnitId = unitId;
}
///
/// Gets or sets the data store.
///
public DataStore DataStore { get; set; }
///
/// Gets or sets the unit ID.
///
public byte UnitId { get; set; }
///
/// Start slave listening for requests.
///
public abstract void Listen();
internal static ReadCoilsInputsResponse ReadDiscretes(ReadCoilsInputsRequest request, DataStore dataStore, ModbusDataCollection dataSource)
{
DiscreteCollection data = DataStore.ReadData(dataStore, dataSource, request.StartAddress, request.NumberOfPoints, dataStore.SyncRoot);
ReadCoilsInputsResponse response = new ReadCoilsInputsResponse(request.FunctionCode, request.SlaveAddress, data.ByteCount, data);
return response;
}
internal static ReadHoldingInputRegistersResponse ReadRegisters(ReadHoldingInputRegistersRequest request, DataStore dataStore, ModbusDataCollection dataSource)
{
RegisterCollection data = DataStore.ReadData(dataStore, dataSource, request.StartAddress, request.NumberOfPoints, dataStore.SyncRoot);
ReadHoldingInputRegistersResponse response = new ReadHoldingInputRegistersResponse(request.FunctionCode, request.SlaveAddress, data);
return response;
}
internal static WriteSingleCoilRequestResponse WriteSingleCoil(WriteSingleCoilRequestResponse request, DataStore dataStore, ModbusDataCollection dataSource)
{
DataStore.WriteData(dataStore, new DiscreteCollection(request.Data[0] == Modbus.CoilOn), dataSource, request.StartAddress, dataStore.SyncRoot);
return request;
}
internal static WriteMultipleCoilsResponse WriteMultipleCoils(WriteMultipleCoilsRequest request, DataStore dataStore, ModbusDataCollection dataSource)
{
DataStore.WriteData(dataStore, CollectionUtility.Slice(request.Data, 0, request.NumberOfPoints), dataSource, request.StartAddress, dataStore.SyncRoot);
WriteMultipleCoilsResponse response = new WriteMultipleCoilsResponse(request.SlaveAddress, request.StartAddress, request.NumberOfPoints);
return response;
}
internal static WriteSingleRegisterRequestResponse WriteSingleRegister(WriteSingleRegisterRequestResponse request, DataStore dataStore, ModbusDataCollection dataSource)
{
DataStore.WriteData(dataStore, request.Data, dataSource, request.StartAddress, dataStore.SyncRoot);
return request;
}
internal static WriteMultipleRegistersResponse WriteMultipleRegisters(WriteMultipleRegistersRequest request, DataStore dataStore, ModbusDataCollection dataSource)
{
DataStore.WriteData(dataStore, request.Data, dataSource, request.StartAddress, dataStore.SyncRoot);
WriteMultipleRegistersResponse response = new WriteMultipleRegistersResponse(request.SlaveAddress, request.StartAddress, request.NumberOfPoints);
return response;
}
[SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily", Justification = "Cast is not unneccessary.")]
internal IModbusMessage ApplyRequest(IModbusMessage request)
{
_logger.Info(request.ToString());
EventHandler handler = ModbusSlaveRequestReceived;
if (handler != null)
handler(this, new ModbusSlaveRequestEventArgs(request));
IModbusMessage response;
switch (request.FunctionCode)
{
case Modbus.ReadCoils:
response = ReadDiscretes((ReadCoilsInputsRequest) request, DataStore, DataStore.CoilDiscretes);
break;
case Modbus.ReadInputs:
response = ReadDiscretes((ReadCoilsInputsRequest) request, DataStore, DataStore.InputDiscretes);
break;
case Modbus.ReadHoldingRegisters:
response = ReadRegisters((ReadHoldingInputRegistersRequest) request, DataStore, DataStore.HoldingRegisters);
break;
case Modbus.ReadInputRegisters:
response = ReadRegisters((ReadHoldingInputRegistersRequest) request, DataStore, DataStore.InputRegisters);
break;
case Modbus.Diagnostics:
response = request;
break;
case Modbus.WriteSingleCoil:
response = WriteSingleCoil((WriteSingleCoilRequestResponse) request, DataStore, DataStore.CoilDiscretes);
break;
case Modbus.WriteSingleRegister:
response = WriteSingleRegister((WriteSingleRegisterRequestResponse) request, DataStore, DataStore.HoldingRegisters);
break;
case Modbus.WriteMultipleCoils:
response = WriteMultipleCoils((WriteMultipleCoilsRequest) request, DataStore, DataStore.CoilDiscretes);
break;
case Modbus.WriteMultipleRegisters:
response = WriteMultipleRegisters((WriteMultipleRegistersRequest) request, DataStore, DataStore.HoldingRegisters);
break;
case Modbus.ReadWriteMultipleRegisters:
ReadWriteMultipleRegistersRequest readWriteRequest = (ReadWriteMultipleRegistersRequest) request;
response = ReadRegisters(readWriteRequest.ReadRequest, DataStore, DataStore.HoldingRegisters);
WriteMultipleRegisters(readWriteRequest.WriteRequest, DataStore, DataStore.HoldingRegisters);
break;
default:
string errorMessage = String.Format(CultureInfo.InvariantCulture, "Unsupported function code {0}", request.FunctionCode);
_logger.Error(errorMessage);
throw new ArgumentException(errorMessage, "request");
}
return response;
}
}
}