Hi All
Hoping somebody can point me in the right direction.
I am trying to set up a ModbusTCP Device (Slave) on a SC20100S Dev Rev C board with a EthClick Module in position 1 on the board.
I have had similar running on a G120 DEV with NetMF4.3 / Visual Basic without a problem and I’m now trying to move to TinyCLR. I apologize if my code formatting is not 100% as I’m not an experienced C# programmer. You could say I don’t have my C legs yet
I have distilled the code down to the bare minimum - setting up the network and setting up the Modbus device to allow reading of holding registers only.
The test setup is a laptop (10.1.1.101) running a Modbus test tool (Radzio! Modbus Master Simulator) directly connected to the SC20100 board (10.1.1.1).
I can ping the board no problem.
(Note I “borrowed” a MAC address from my iPad as I thought this may have been a problem initially).
When I get the test tool to request 10 holding registers it initially gets a valid response and correctly reads the values I have set in the holding registers (2). Subsequent request result in a Modbus timeout.
If I “disconnect” the modbus test tool and then reconnect I again get one successful read and then timeouts.
I have captured the network activity using Wireshark - network comms is not my strong suit so I am not sure why the subsequent requests fail. Any thoughts would be appreciated.
namespace TinyCLR_V1
{ class E_network
{
public static void Ethernet_Processing()
{
try
{
bool link_required = true;
var networkController = GHIElectronics.TinyCLR.Devices.Network.NetworkController.FromName("GHIElectronics.TinyCLR.NativeApis.ENC28J60.NetworkController");
var networkInterfaceSetting = new GHIElectronics.TinyCLR.Devices.Network.EthernetNetworkInterfaceSettings();
var networkCommunicationInterfaceSettings = new GHIElectronics.TinyCLR.Devices.Network.SpiNetworkCommunicationInterfaceSettings();
var cs = GHIElectronics.TinyCLR.Devices.Gpio.GpioController.GetDefault().OpenPin(GHIElectronics.TinyCLR.Pins.SC20100.GpioPin.PD3);
var settings = new GHIElectronics.TinyCLR.Devices.Spi.SpiConnectionSettings()
{
ChipSelectLine = cs,
ClockFrequency = 4000000,
Mode = GHIElectronics.TinyCLR.Devices.Spi.SpiMode.Mode0,
ChipSelectType = GHIElectronics.TinyCLR.Devices.Spi.SpiChipSelectType.Gpio,
ChipSelectHoldTime = TimeSpan.FromTicks(10),
ChipSelectSetupTime = TimeSpan.FromTicks(10)
};
networkCommunicationInterfaceSettings.SpiApiName = GHIElectronics.TinyCLR.Pins.SC20100.SpiBus.Spi3;
networkCommunicationInterfaceSettings.GpioApiName = GHIElectronics.TinyCLR.Pins.SC20100.GpioPin.Id;
networkCommunicationInterfaceSettings.SpiSettings = settings;
networkCommunicationInterfaceSettings.InterruptPin = GHIElectronics.TinyCLR.Devices.Gpio.GpioController.GetDefault().OpenPin
(GHIElectronics.TinyCLR.Pins.SC20100.GpioPin.PC5);
networkCommunicationInterfaceSettings.InterruptEdge = GpioPinEdge.FallingEdge;
networkCommunicationInterfaceSettings.InterruptDriveMode = GpioPinDriveMode.InputPullUp;
networkCommunicationInterfaceSettings.ResetPin = GHIElectronics.TinyCLR.Devices.Gpio.GpioController.GetDefault().OpenPin
(GHIElectronics.TinyCLR.Pins.SC20100.GpioPin.PD4);
networkCommunicationInterfaceSettings.ResetActiveState = GpioPinValue.Low;
networkInterfaceSetting.Address = new System.Net.IPAddress(new byte[] { 10, 1, 1, 1 });
networkInterfaceSetting.SubnetMask = new System.Net.IPAddress(new byte[] { 255, 255, 255, 0 });
// networkInterfaceSetting.GatewayAddress = new System.Net.IPAddress(new byte[] { 10, 1, 1, 1 });
// networkInterfaceSetting.DnsAddresses = new System.Net.IPAddress[] { new System.Net.IPAddress(new byte[]
// { 75, 75, 75, 75 }), new System.Net.IPAddress(new byte[] { 75, 75, 75, 76 }) };
networkInterfaceSetting.MacAddress = new byte[] { 0xEC, 0xAD, 0xB8, 0x74, 0xF1, 0x7C };
networkInterfaceSetting.IsDhcpEnabled = false;
networkInterfaceSetting.IsDynamicDnsEnabled = false;
networkInterfaceSetting.TlsEntropy = new byte[] { 0, 1, 2, 3 };
networkController.SetInterfaceSettings(networkInterfaceSetting);
networkController.SetCommunicationInterfaceSettings(networkCommunicationInterfaceSettings);
networkController.SetAsDefaultController();
networkController.NetworkAddressChanged += NetworkController_NetworkAddressChanged;
networkController.NetworkLinkConnectedChanged += NetworkController_NetworkLinkConnectedChanged;
networkController.Enable();
System.Diagnostics.Debug.WriteLine("Network is ready to use: ");
Thread.Sleep(100);
//Modbus Device Configuration
GHIElectronics.TinyCLR.Devices.Modbus.ModbusDevice ModbusTCP_Device;
ModbusTCP_Device = new MyModbusDevice(248);
GHIElectronics.TinyCLR.Devices.Modbus.Interface.ModbusTcpListener mbListner;
mbListner = new GHIElectronics.TinyCLR.Devices.Modbus.Interface.ModbusTcpListener(ModbusTCP_Device, 502, 5, 1000);
Thread.Sleep(100);
ModbusTCP_Device.Start();
while (link_required == true)
{
if (ModbusTCP_Device.IsRunning == true)
{
// System.Diagnostics.Debug.WriteLine("Running ");
}
else
{
System.Diagnostics.Debug.WriteLine("Modbus Devic is Stopped ");
}
Thread.Sleep(1000);
}
}
catch
{
Debug.WriteLine("Error in E_Network");
}
}
private static void NetworkController_NetworkLinkConnectedChanged(NetworkController sender, NetworkLinkConnectedChangedEventArgs e)
{
Debug.WriteLine("connection changed");
// Raise event connect/disconnect
}
private static void NetworkController_NetworkAddressChanged(NetworkController sender, NetworkAddressChangedEventArgs e)
{
var ipProperties = sender.GetIPProperties();
var address = ipProperties.Address.GetAddressBytes();
// linkReady = address[0] != 0;
}
}
// implement slave device
public class MyModbusDevice : ModbusDevice
{
public MyModbusDevice(byte deviceAddress, object syncObject = null)
: base(deviceAddress, syncObject)
{ }
public MyModbusDevice(IModbusInterface intf, byte deviceAddress, object syncObject = null)
: base(intf, deviceAddress, syncObject)
{ }
protected override string OnGetDeviceIdentification(ModbusObjectId objectId)
{
switch (objectId)
{
case ModbusObjectId.VendorName:
return "Vendor Name";
case ModbusObjectId.ProductCode:
return "101";
case ModbusObjectId.MajorMinorRevision:
return "1.0";
case ModbusObjectId.VendorUrl:
return "www.test.com.au";
case ModbusObjectId.ProductName:
return "Test Modbus";
case ModbusObjectId.ModelName:
return "1";
case ModbusObjectId.UserApplicationName:
return "SC100";
}
return null;
}
protected override ModbusConformityLevel GetConformityLevel()
{
return ModbusConformityLevel.Regular;
}
protected override ModbusErrorCode OnReadHoldingRegisters(bool isBroadcast, ushort startAddress, ushort[] registers)
{
try
{
for (int n = 0; n < registers.Length; ++n)
{
// just set a number in each register to test
registers[n] = 2;
}
System.Diagnostics.Debug.WriteLine("Read Response Fired");
return ModbusErrorCode.NoError;
}
catch
{
Debug.WriteLine("error in on read holding registers");
return base.OnReadHoldingRegisters(isBroadcast, startAddress, registers);
}
}
// override any On<ModusFunction> methods here
}