diff --git a/README.md b/README.md index 7258520..dd8be58 100644 --- a/README.md +++ b/README.md @@ -18,8 +18,8 @@ Refer to [Azure IoT Edge](https://github.com/Azure/azure-iot-edge) ## HowTo Run ## This section will help you download the prebuilt module image from docker hub, and run it with IoT Edge directly. - 1. Setup [Azure IoT Edge](https://github.com/Azure/azure-iot-edge) with compatible version on your machine. - 2. Follow [this](https://docs.microsoft.com/en-us/azure/iot-edge/quickstart) to deploy a custom IoT Edge module. + 1. Setup Azure IoT Edge [Windows](https://docs.microsoft.com/en-us/azure/iot-edge/quickstart) or [Linux](https://docs.microsoft.com/en-us/azure/iot-edge/quickstart-linux) with compatible version on your machine. + 2. Follow [this](https://docs.microsoft.com/en-us/azure/iot-edge/tutorial-deploy-modbus-tcp) to deploy a custom IoT Edge module. 3. In the Image field, enter **microsoft/azureiotedge-modbus-tcp:1.0-preview**. 4. You may also want to provide configuration to the module when it starts, paste the configuration in the desired property field. For more about configuration, see [here](https://github.com/Azure/iot-edge-modbus#configuration). @@ -27,11 +27,13 @@ This section will help you download the prebuilt module image from docker hub, a If you prefer to build your own module, use the following script. Dockerfiles are located under [Docker](https://github.com/Azure/iot-edge-modbus/tree/master/Docker) folder, you should be able to find one for your platform. There are two Dockerfiles in each platform, the multi-stage "Dockerfile-auto" will automatically build source code and Docker image. The other "Dockerfile" requires you to build source code first and then copy binary to the image. **Note**: Arm32 multi-stage build doesn't work at this moment, please build it manually. **Note**: Please replace **PlatForm** in below scripts with the actual platform path you are trying to build. + ### Multi-stage build ### ```cmd >cd iot-edge-modbus/ >docker build -t modbusModule -f Docker//Dockerfile-auto . ``` + ### Manually build ### The application requires the [.NET Core SDK 2.0](https://www.microsoft.com/net/download/windows). ```cmd @@ -106,18 +108,21 @@ For more about Modbus, please refer to the [Wiki](https://en.wikipedia.org/wiki/ ## Module Endpoints and Routing ## All telemetry are sent out from modbusOutput endpoint by default. Routing is enabled by specifying rules like below. + ### Route to IoT Hub ### ```json { "modbusToIoTHub":"FROM /messages/modules/modbus/outputs/modbusOutput INTO $upstream" } ``` + ### Route to other (filter) modules ### ```json { "modbusToFilter":"FROM /messages/modules/modbus/outputs/modbusOutput INTO BrokeredEndpoint(\"/modules/filtermodule/inputs/input1\")" } ``` + ### Write to Modbus ### Modbus module also has an input enpoint to receive message/commands. Currently it supports writing back to a single register/cell in a Modbus slave. The content of command must be the following format. ```json @@ -136,5 +141,5 @@ The command should have a property "command-type" with value "ModbusWrite". Also ``` ## Debug ## -There is a flag **IOT_EDGE** at the first line in Program.cs, which can be turn off to debug the Modbus module in console mode. Running console mode requires IoT device connection string being inserted as a environment variable named **EdgeHubConnectionString**, and a local configuration file "iot-edge-modbus.json" since module twin is not available. +There is a flag **IOT_EDGE** at the first line in Program.cs, which can be turn off to debug the Modbus module in console mode. Running console mode requires IoT device connection string being inserted as a environment variable named **EdgeHubConnectionString**, and a local configuration file "iot-edge-modbus.json" since module twin is not available. You can copy "iot-edge-modbus.json" template from project root directory. **Note**: running in console mode means none of the IoT Edge features is available. This mode is only to debug non edge-related functions. \ No newline at end of file diff --git a/src/ModbusSlave.cs b/src/ModbusSlave.cs index 68dc7d2..46b1721 100644 --- a/src/ModbusSlave.cs +++ b/src/ModbusSlave.cs @@ -55,6 +55,14 @@ namespace Modbus.Slaves { return ModbusSessionList.Find(x => x.config.HwId.ToUpper() == hwid.ToUpper()); } + public void Release() + { + foreach (var session in ModbusSessionList) + { + session.ReleaseSession(); + } + ModbusSessionList.Clear(); + } } /// /// Base class of Modbus session. @@ -65,6 +73,7 @@ namespace Modbus.Slaves public abstract Task> ProcessOperations(); public abstract Task WriteCB(string uid, string address, string value); public abstract Task InitSession(); + public abstract void ReleaseSession(); } /* ----------------------- -------- @@ -92,12 +101,7 @@ namespace Modbus.Slaves config = conf; } #endregion - #region Destructors - ~ModbusTCPSlaveSession() - { - m_socket.Dispose(); - } - #endregion + #region Private Properties private const int m_reqSize = 12; private const int m_bufSize = 512; @@ -165,6 +169,16 @@ namespace Modbus.Slaves EncodeRead(x); } } + + public override void ReleaseSession() + { + if (m_socket != null) + { + m_socket.Disconnect(false); + m_socket.Dispose(); + m_socket = null; + } + } #endregion #region Private Methods private async Task ConnectSlave() diff --git a/src/Program.cs b/src/Program.cs index db439ef..8aee2a0 100644 --- a/src/Program.cs +++ b/src/Program.cs @@ -181,8 +181,8 @@ namespace Modbus.Containers try { - // stop all activities while updating configuration #if IOT_EDGE + // stop all activities while updating configuration await ioTHubModuleClient.SetInputMessageHandlerAsync( "input1", DummyCallBack, @@ -229,7 +229,7 @@ namespace Modbus.Containers { ModuleConfig config; Slaves.ModuleHandle moduleHandle; - string jsonStr; + string jsonStr = null; string serializedStr; serializedStr = JsonConvert.SerializeObject(desiredProperties); @@ -243,8 +243,19 @@ namespace Modbus.Containers } else { - // get config from local file - jsonStr = File.ReadAllText(@"..\iot-edge-modbus.json"); + Console.WriteLine("No configuration found in desired properties."); + if (File.Exists(@"iot-edge-modbus.json")) + { + try + { + // get config from local file + jsonStr = File.ReadAllText(@"iot-edge-modbus.json"); + } + catch (Exception ex) + { + Console.WriteLine("Unable to read configuration from file. Error: " + ex.Message); + } + } } if (!string.IsNullOrEmpty(jsonStr)) @@ -263,11 +274,11 @@ namespace Modbus.Containers { var userContext = new Tuple(ioTHubModuleClient, moduleHandle); #if IOT_EDGE - // Register callback to be called when a message is received by the module - await ioTHubModuleClient.SetInputMessageHandlerAsync( - "input1", - PipeMessage, - userContext); + // Register callback to be called when a message is received by the module + await ioTHubModuleClient.SetInputMessageHandlerAsync( + "input1", + PipeMessage, + userContext); #else m_task_list.Add(Receive(userContext)); #endif @@ -301,11 +312,6 @@ namespace Modbus.Containers var msgs = await s.ProcessOperations(); result.AddRange(msgs); } - if (!m_run) - { - break; - } - await Task.Delay(m_interval.Interval); if (result.Count > 0) { Message message = new Message(Encoding.ASCII.GetBytes(JsonConvert.SerializeObject(result))); @@ -316,7 +322,13 @@ namespace Modbus.Containers await ioTHubModuleClient.SendEventAsync(message); #endif } + if (!m_run) + { + break; + } + await Task.Delay(m_interval.Interval); } + moduleHandle.Release(); } ///