Example #1
0
        static void Main(string[] args)
        {
            Log("{json:scada} IEC60870-5-104 Driver - Copyright 2020 RLO");
            Log("Driver version " + DriverVersion);
            Log("Using lib60870.NET version " +
                LibraryCommon.GetLibraryVersionString());

            if (args.Length > 0) // first argument in number of the driver instance
            {
                int  num;
                bool res = int.TryParse(args[0], out num);
                if (res)
                {
                    ProtocolDriverInstanceNumber = num;
                }
            }
            if (args.Length > 1) // second argument is logLevel
            {
                int  num;
                bool res = int.TryParse(args[1], out num);
                if (res)
                {
                    LogLevel = num;
                }
            }

            string fname = JsonConfigFilePath;

            if (!File.Exists(fname))
            {
                fname = JsonConfigFilePathAlt;
            }
            if (!File.Exists(fname))
            {
                Log("Missing config file " + JsonConfigFilePath);
                Environment.Exit(-1);
            }

            Log("Reading config file " + fname);
            string json = File.ReadAllText(fname);

            JSConfig = JsonSerializer.Deserialize <JSONSCADAConfig>(json);
            if (
                JSConfig.mongoConnectionString == "" ||
                JSConfig.mongoConnectionString == null
                )
            {
                Log("Missing MongoDB connection string in JSON config file " +
                    fname);
                Environment.Exit(-1);
            }
            // Log("MongoDB connection string: " + JSConfig.mongoConnectionString);
            if (
                JSConfig.mongoDatabaseName == "" ||
                JSConfig.mongoDatabaseName == null
                )
            {
                Log("Missing MongoDB database name in JSON config file " +
                    fname);
                Environment.Exit(-1);
            }
            Log("MongoDB database name: " + JSConfig.mongoDatabaseName);
            if (JSConfig.nodeName == "" || JSConfig.nodeName == null)
            {
                Log("Missing nodeName parameter in JSON config file " +
                    fname);
                Environment.Exit(-1);
            }
            Log("Node name: " + JSConfig.nodeName);

            var Client = ConnectMongoClient(JSConfig);
            var DB     = Client.GetDatabase(JSConfig.mongoDatabaseName);

            // read and process instances configuration
            var collinsts =
                DB
                .GetCollection
                <protocolDriverInstancesClass
                >(ProtocolDriverInstancesCollectionName);
            var instances =
                collinsts
                .Find(inst =>
                      inst.protocolDriver == ProtocolDriverName &&
                      inst.protocolDriverInstanceNumber ==
                      ProtocolDriverInstanceNumber &&
                      inst.enabled == true)
                .ToList();
            var foundInstance = false;

            foreach (protocolDriverInstancesClass inst in instances)
            {
                if (
                    ProtocolDriverName == inst.protocolDriver &&
                    ProtocolDriverInstanceNumber ==
                    inst.protocolDriverInstanceNumber
                    )
                {
                    foundInstance = true;
                    if (!inst.enabled)
                    {
                        Log("Driver instance [" +
                            ProtocolDriverInstanceNumber.ToString() +
                            "] disabled!");
                        Environment.Exit(-1);
                    }
                    Log("Instance: " +
                        inst.protocolDriverInstanceNumber.ToString());
                    var nodefound = false;
                    foreach (var name in inst.nodeNames)
                    {
                        if (JSConfig.nodeName == name)
                        {
                            nodefound = true;
                        }
                    }
                    if (!nodefound)
                    {
                        Log("Node '" +
                            JSConfig.nodeName +
                            "' not found in instances configuration!");
                        Environment.Exit(-1);
                    }
                    DriverInstance = inst;
                    break;
                }
                break; // process just first result
            }
            if (!foundInstance)
            {
                Log("Driver instance [" +
                    ProtocolDriverInstanceNumber +
                    "] not found in configuration!");
                Environment.Exit(-1);
            }

            // read and process connections configuration for this driver instance
            var collconns =
                DB
                .GetCollection
                <IEC10X_connection>(ProtocolConnectionsCollectionName);
            var conns =
                collconns
                .Find(conn =>
                      conn.protocolDriver == ProtocolDriverName &&
                      conn.protocolDriverInstanceNumber ==
                      ProtocolDriverInstanceNumber &&
                      conn.enabled == true)
                .ToList();

            foreach (IEC10X_connection isrv in conns)
            {
                if (isrv.ipAddresses.Length < 1)
                {
                    Log("Missing ipAddresses list!");
                    Environment.Exit(-1);
                }
                IEC10Xconns.Add(isrv);
                Log(isrv.name.ToString() + " - New Connection");
            }
            if (IEC10Xconns.Count == 0)
            {
                Log("No connections found!");
                Environment.Exit(-1);
            }

            // start thread to process redundancy control
            Thread thrMongoRedundacy =
                new Thread(() =>
                           ProcessRedundancyMongo(JSConfig));

            thrMongoRedundacy.Start();

            // start thread to update acquired data to database
            Thread thrMongo =
                new Thread(() =>
                           ProcessMongo(JSConfig));

            thrMongo.Start();

            // start thread to watch for commands in the database using a change stream
            Thread thrMongoCmd =
                new Thread(() =>
                           ProcessMongoCmd(JSConfig));

            thrMongoCmd.Start();

            Log("Setting up IEC Connections & ASDU handlers...");
            int cntIecSrv = 0;

            foreach (IEC10X_connection srv in IEC10Xconns)
            {
                var apcipars = new APCIParameters();
                apcipars.K  = srv.k;
                apcipars.W  = srv.w;
                apcipars.T0 = srv.t0;
                apcipars.T1 = srv.t1;
                apcipars.T2 = srv.t2;
                apcipars.T3 = srv.t3;
                var alpars = new ApplicationLayerParameters();
                alpars.SizeOfCOT = srv.sizeOfCOT;
                alpars.SizeOfCA  = srv.sizeOfCA;
                alpars.SizeOfIOA = srv.sizeOfIOA;
                alpars.OA        = srv.localLinkAddress;
                var      tcpPort    = 2404;
                string[] ipAddrPort = srv.ipAddresses[0].Split(':');
                if (ipAddrPort.Length > 1)
                {
                    if (int.TryParse(ipAddrPort[1], out _))
                    {
                        tcpPort = System.Convert.ToInt32(ipAddrPort[1]);
                    }
                }
                var con =
                    new Connection(ipAddrPort[0],
                                   tcpPort,
                                   apcipars,
                                   alpars);
                con.Parameters.OA     = srv.localLinkAddress;
                srv.connection        = con;
                srv.CntGI             = srv.giInterval - 3;
                srv.CntTestCommand    = srv.testCommandInterval - 1;
                srv.CntTimeSync       = 0;
                srv.CntTestCommandSeq = 0;
                if (LogLevel >= LogLevelDebug)
                {
                    con.DebugOutput = true;
                }
                con.SetASDUReceivedHandler(AsduReceivedHandler, cntIecSrv);
                con.SetConnectionHandler(ConnectionHandler, cntIecSrv);

                // create timer to increment counters each second
                srv.TimerCnt          = new System.Timers.Timer();
                srv.TimerCnt.Interval = 1000;
                srv.TimerCnt.Elapsed += (sender, e) => MyElapsedMethod(sender, e, srv);
Example #2
0
        static void Main(string[] args)
        {
            Log("{json:scada} IEC60870-5-101 Server Driver - Copyright 2020 RLO");
            Log("Driver version " + DriverVersion);
            Log("Using lib60870.NET version " +
                LibraryCommon.GetLibraryVersionString());

            if (
                args.Length > 0 // first argument in number of the driver instance
                )
            {
                int  num;
                bool res = int.TryParse(args[0], out num);
                if (res)
                {
                    ProtocolDriverInstanceNumber = num;
                }
            }
            if (
                args.Length > 1 // second argument is logLevel
                )
            {
                int  num;
                bool res = int.TryParse(args[1], out num);
                if (res)
                {
                    LogLevel = num;
                }
            }

            string fname = JsonConfigFilePath;

            if (args.Length > 2) // third argument is config file name
            {
                if (File.Exists(args[2]))
                {
                    fname = args[2];
                }
            }
            if (!File.Exists(fname))
            {
                fname = JsonConfigFilePathAlt;
            }
            if (!File.Exists(fname))
            {
                Log("Missing config file " + JsonConfigFilePath);
                Environment.Exit(-1);
            }

            Log("Reading config file " + fname);
            string json = File.ReadAllText(fname);

            JSConfig = JsonSerializer.Deserialize <JSONSCADAConfig>(json);
            if (
                JSConfig.mongoConnectionString == "" ||
                JSConfig.mongoConnectionString == null
                )
            {
                Log("Missing MongoDB connection string in JSON config file " +
                    fname);
                Environment.Exit(-1);
            }
            // Log("MongoDB connection string: " + JSConfig.mongoConnectionString);
            if (
                JSConfig.mongoDatabaseName == "" ||
                JSConfig.mongoDatabaseName == null
                )
            {
                Log("Missing MongoDB database name in JSON config file " +
                    fname);
                Environment.Exit(-1);
            }
            Log("MongoDB database name: " + JSConfig.mongoDatabaseName);
            if (JSConfig.nodeName == "" || JSConfig.nodeName == null)
            {
                Log("Missing nodeName parameter in JSON config file " +
                    fname);
                Environment.Exit(-1);
            }
            Log("Node name: " + JSConfig.nodeName);

            // connect to MongoDB Database server
            Client = ConnectMongoClient(JSConfig);
            var DB = Client.GetDatabase(JSConfig.mongoDatabaseName);

            // read and process instances configuration
            var collinsts =
                DB
                .GetCollection
                <protocolDriverInstancesClass
                >(ProtocolDriverInstancesCollectionName);
            var instances =
                collinsts
                .Find(inst =>
                      inst.protocolDriver == ProtocolDriverName &&
                      inst.protocolDriverInstanceNumber ==
                      ProtocolDriverInstanceNumber &&
                      inst.enabled == true)
                .ToList();
            var foundInstance = false;

            foreach (protocolDriverInstancesClass inst in instances)
            {
                if (
                    ProtocolDriverName == inst.protocolDriver &&
                    ProtocolDriverInstanceNumber ==
                    inst.protocolDriverInstanceNumber
                    )
                {
                    foundInstance = true;
                    if (!inst.enabled)
                    {
                        Log("Driver instance [" +
                            ProtocolDriverInstanceNumber.ToString() +
                            "] disabled!");
                        Environment.Exit(-1);
                    }
                    Log("Instance: " +
                        inst.protocolDriverInstanceNumber.ToString());
                    var nodefound = false;
                    foreach (var name in inst.nodeNames)
                    {
                        if (JSConfig.nodeName == name)
                        {
                            nodefound = true;
                        }
                    }
                    if (!nodefound)
                    {
                        Log("Node '" +
                            JSConfig.nodeName +
                            "' not found in instances configuration!");
                        Environment.Exit(-1);
                    }
                    DriverInstance = inst;
                    break;
                }
                break; // process just first result
            }
            if (!foundInstance)
            {
                Log("Driver instance [" +
                    ProtocolDriverInstanceNumber +
                    "] not found in configuration!");
                Environment.Exit(-1);
            }

            // read and process connections configuration for this driver instance
            var collconns =
                DB
                .GetCollection
                <IEC10X_connection>(ProtocolConnectionsCollectionName);
            var conns =
                collconns
                .Find(conn =>
                      conn.protocolDriver == ProtocolDriverName &&
                      conn.protocolDriverInstanceNumber ==
                      ProtocolDriverInstanceNumber &&
                      conn.enabled == true)
                .ToList();

            foreach (IEC10X_connection isrv in conns)
            {
                IEC10Xconns.Add(isrv);
                Log(isrv.name.ToString());
            }
            if (IEC10Xconns.Count == 0)
            {
                Log("No connections found!");
                Environment.Exit(-1);
            }

            // start thread to dequeue iec data and send to connections
            Thread thrDeqIecInfo =
                new Thread(() =>
                           DequeueIecInfo());

            thrDeqIecInfo.Start();

            // start thread to watch for commands in the database using a change stream
            Thread thrMongoCS =
                new Thread(() =>
                           ProcessMongoCS(JSConfig));

            thrMongoCS.Start();

            Log("Setting up IEC Connections & ASDU handlers...");
            int cntIecSrv = 0;

            foreach (IEC10X_connection srv in IEC10Xconns)
            {
                TcpClientVirtualSerialPort virtualPort = null;
                SerialPort port = null;
                if (srv.portName.Contains(":"))
                {
                    var hostport = srv.portName.Split(":");
                    virtualPort = new TcpClientVirtualSerialPort(hostport[0], System.Convert.ToInt32(hostport[1]));
                    if (LogLevel >= LogLevelDebug)
                    {
                        virtualPort.DebugOutput = true;
                    }
                    virtualPort.Start();
                }
                else
                {
                    port          = new SerialPort();
                    port.PortName = srv.portName;
                    port.BaudRate = srv.baudRate;
                    switch (srv.parity.ToLower())
                    {
                    default:     // Even is the starndard parity for 101
                    case "even":
                        port.Parity = Parity.Even;
                        break;

                    case "none":
                        port.Parity = Parity.None;
                        break;

                    case "odd":
                        port.Parity = Parity.Odd;
                        break;

                    case "mark":
                        port.Parity = Parity.Mark;
                        break;

                    case "space":
                        port.Parity = Parity.Space;
                        break;
                    }
                    switch (srv.stopBits.ToLower())
                    {
                    default:
                    case "one":
                        port.StopBits = StopBits.One;
                        break;

                    case "one5":
                    case "onepointfive":
                        port.StopBits = StopBits.OnePointFive;
                        break;

                    case "two":
                        port.StopBits = StopBits.Two;
                        break;
                    }
                    switch (srv.handshake.ToLower())
                    {
                    default:
                    case "none":
                        port.Handshake = Handshake.None;
                        break;

                    case "xon":
                    case "xonxoff":
                        port.Handshake = Handshake.XOnXOff;
                        break;

                    case "rts":
                    case "requesttosend":
                        port.Handshake = Handshake.RequestToSend;
                        break;

                    case "rtsxon":
                    case "requesttosendxonxoff":
                        port.Handshake = Handshake.RequestToSendXOnXOff;
                        break;
                    }
                    port.Open();
                    port.DiscardInBuffer();
                }

                LinkLayerParameters llParameters = new LinkLayerParameters();
                llParameters.AddressLength    = srv.sizeOfLinkAddress;
                llParameters.TimeoutForACK    = srv.timeoutForACK;
                llParameters.TimeoutRepeat    = srv.timeoutRepeat;
                llParameters.UseSingleCharACK = srv.useSingleCharACK;

                CS101Slave slave;
                if (port != null)
                {
                    slave = new CS101Slave(port, llParameters);
                }
                else
                {
                    slave = new CS101Slave(virtualPort, llParameters);
                }
                slave.Parameters.SizeOfCOT = srv.sizeOfCOT;
                slave.Parameters.SizeOfCA  = srv.sizeOfCA;
                slave.Parameters.SizeOfIOA = srv.sizeOfIOA;
                slave.Parameters.OA        = srv.localLinkAddress;
                if (LogLevel >= LogLevelDebug)
                {
                    slave.DebugOutput = true;
                }
                slave.LinkLayerAddress = srv.localLinkAddress;
                slave.LinkLayerMode    = lib60870.linklayer.LinkLayerMode.UNBALANCED;
                slave.SetInterrogationHandler(InterrogationHandler, cntIecSrv);
                slave.SetUserDataQueueSizes(srv.maxQueueSize, srv.maxQueueSize);
                srv.server = slave;
                slave.SetASDUHandler(AsduReceivedHandler, cntIecSrv);
                // slave.Start();

                Log(srv.name + " - New server listening on " + srv.portName);
                cntIecSrv++;
            }
            Thread.Sleep(1000);
            bool running = true;

            Console.CancelKeyPress +=
                delegate(object sender, ConsoleCancelEventArgs e)
            {
                e.Cancel = true;
                running  = false;
            };
            Log("Press [CTRL]+[C] to terminate...");

            int cnt = 1;

            do
            {
                try
                {
                    foreach (IEC10X_connection srv in IEC10Xconns)
                    {
                        srv.server.Run();
                    }

                    if (Client == null)
                    {
                        // retry connection
                        IsMongoLive = false;
                        Client      = new MongoClient(JSConfig.mongoConnectionString);
                        DB          = Client.GetDatabase(JSConfig.mongoDatabaseName);
                        IsMongoLive = true;
                    }

                    if ((cnt % 20) == 0) // each 1 second test mongo connection
                    {
                        IsMongoLive =
                            DB
                            .RunCommandAsync((Command <BsonDocument>)
                                             "{ping:1}")
                            .Wait(1000);
                        if (!IsMongoLive)
                        {
                            throw new Exception("Error on MongoDB connection ");
                        }
                    }
                }
                catch (Exception e)
                { // Disconnects to retry after some time
                    IsMongoLive = false;
                    Client      = null;
                    Log("Exception");
                    Log(e);
                    Log(e
                        .ToString()
                        .Substring(0,
                                   e.ToString().IndexOf(Environment.NewLine)));
                    System.Threading.Thread.Sleep(100);
                }

                Thread.Sleep(50);
                cnt++;
            }while (running);
            Log("Exiting application!");
            Environment.Exit(0);
        }
Example #3
0
        static void Main(string[] args)
        {
            Log("{json:scada} IEC60870-5-104 Server Driver - Copyright 2020 RLO");
            Log("Driver version " + DriverVersion);
            Log("Using lib60870.NET version " +
                LibraryCommon.GetLibraryVersionString());

            if (
                args.Length > 0 // first argument in number of the driver instance
                )
            {
                int  num;
                bool res = int.TryParse(args[0], out num);
                if (res)
                {
                    ProtocolDriverInstanceNumber = num;
                }
            }
            if (
                args.Length > 1 // second argument is logLevel
                )
            {
                int  num;
                bool res = int.TryParse(args[1], out num);
                if (res)
                {
                    LogLevel = num;
                }
            }

            string fname = JsonConfigFilePath;

            if (args.Length > 2) // third argument is config file name
            {
                if (File.Exists(args[2]))
                {
                    fname = args[2];
                }
            }
            if (!File.Exists(fname))
            {
                fname = JsonConfigFilePathAlt;
            }
            if (!File.Exists(fname))
            {
                Log("Missing config file " + JsonConfigFilePath);
                Environment.Exit(-1);
            }

            Log("Reading config file " + fname);
            string json = File.ReadAllText(fname);

            JSConfig = JsonSerializer.Deserialize <JSONSCADAConfig>(json);
            if (
                JSConfig.mongoConnectionString == "" ||
                JSConfig.mongoConnectionString == null
                )
            {
                Log("Missing MongoDB connection string in JSON config file " +
                    fname);
                Environment.Exit(-1);
            }
            // Log("MongoDB connection string: " + JSConfig.mongoConnectionString);
            if (
                JSConfig.mongoDatabaseName == "" ||
                JSConfig.mongoDatabaseName == null
                )
            {
                Log("Missing MongoDB database name in JSON config file " +
                    fname);
                Environment.Exit(-1);
            }
            Log("MongoDB database name: " + JSConfig.mongoDatabaseName);
            if (JSConfig.nodeName == "" || JSConfig.nodeName == null)
            {
                Log("Missing nodeName parameter in JSON config file " +
                    fname);
                Environment.Exit(-1);
            }
            Log("Node name: " + JSConfig.nodeName);

            // connect to MongoDB Database server
            Client = ConnectMongoClient(JSConfig);
            var DB = Client.GetDatabase(JSConfig.mongoDatabaseName);

            // read and process instances configuration
            var collinsts =
                DB
                .GetCollection
                <protocolDriverInstancesClass
                >(ProtocolDriverInstancesCollectionName);
            var instances =
                collinsts
                .Find(inst =>
                      inst.protocolDriver == ProtocolDriverName &&
                      inst.protocolDriverInstanceNumber ==
                      ProtocolDriverInstanceNumber &&
                      inst.enabled == true)
                .ToList();
            var foundInstance = false;

            foreach (protocolDriverInstancesClass inst in instances)
            {
                if (
                    ProtocolDriverName == inst.protocolDriver &&
                    ProtocolDriverInstanceNumber ==
                    inst.protocolDriverInstanceNumber
                    )
                {
                    foundInstance = true;
                    if (!inst.enabled)
                    {
                        Log("Driver instance [" +
                            ProtocolDriverInstanceNumber.ToString() +
                            "] disabled!");
                        Environment.Exit(-1);
                    }
                    Log("Instance: " +
                        inst.protocolDriverInstanceNumber.ToString());
                    var nodefound = false;
                    foreach (var name in inst.nodeNames)
                    {
                        if (JSConfig.nodeName == name)
                        {
                            nodefound = true;
                        }
                    }
                    if (!nodefound)
                    {
                        Log("Node '" +
                            JSConfig.nodeName +
                            "' not found in instances configuration!");
                        Environment.Exit(-1);
                    }
                    DriverInstance = inst;
                    break;
                }
                break; // process just first result
            }
            if (!foundInstance)
            {
                Log("Driver instance [" +
                    ProtocolDriverInstanceNumber +
                    "] not found in configuration!");
                Environment.Exit(-1);
            }

            // read and process connections configuration for this driver instance
            var collconns =
                DB
                .GetCollection
                <IEC10X_connection>(ProtocolConnectionsCollectionName);
            var conns =
                collconns
                .Find(conn =>
                      conn.protocolDriver == ProtocolDriverName &&
                      conn.protocolDriverInstanceNumber ==
                      ProtocolDriverInstanceNumber &&
                      conn.enabled == true)
                .ToList();

            foreach (IEC10X_connection isrv in conns)
            {
                IEC10Xconns.Add(isrv);
                Log(isrv.name.ToString());
            }
            if (IEC10Xconns.Count == 0)
            {
                Log("No connections found!");
                Environment.Exit(-1);
            }

            // start thread to dequeue iec data and send to connections
            Thread thrDeqIecInfo =
                new Thread(() =>
                           DequeueIecInfo());

            thrDeqIecInfo.Start();

            // start thread to watch for commands in the database using a change stream
            Thread thrMongoCS =
                new Thread(() =>
                           ProcessMongoCS(JSConfig));

            thrMongoCS.Start();

            Log("Setting up IEC Connections & ASDU handlers...");
            int cntIecSrv = 0;

            foreach (IEC10X_connection srv in IEC10Xconns)
            {
                var apcipars = new APCIParameters();
                apcipars.K  = srv.k;
                apcipars.W  = srv.w;
                apcipars.T0 = srv.t0;
                apcipars.T1 = srv.t1;
                apcipars.T2 = srv.t2;
                apcipars.T3 = srv.t3;
                var alpars = new ApplicationLayerParameters();
                alpars.SizeOfCOT = srv.sizeOfCOT;
                alpars.SizeOfCA  = srv.sizeOfCA;
                alpars.SizeOfIOA = srv.sizeOfIOA;
                alpars.OA        = srv.localLinkAddress;

                var server = new Server(apcipars, alpars);
                srv.server = server;
                if (srv.serverModeMultiActive)
                {
                    server.ServerMode = ServerMode.CONNECTION_IS_REDUNDANCY_GROUP;
                }
                else
                {
                    server.ServerMode = ServerMode.SINGLE_REDUNDANCY_GROUP;
                }
                var      localBindIpAddress = "0.0.0.0";
                var      tcpPort            = 2404;
                string[] ipAddrPort         = srv.ipAddressLocalBind.Split(':');
                if (ipAddrPort.Length > 0)
                {
                    if (ipAddrPort[0] != "")
                    {
                        localBindIpAddress = ipAddrPort[0];
                    }
                }
                if (ipAddrPort.Length > 1)
                {
                    if (int.TryParse(ipAddrPort[1], out _))
                    {
                        tcpPort = System.Convert.ToInt32(ipAddrPort[1]);
                    }
                }
                server.SetLocalAddress(localBindIpAddress);
                server.SetLocalPort(tcpPort);
                //RedundancyGroup redGroup = new RedundancyGroup("catch all");
                //server.AddRedundancyGroup(redGroup);
                if (LogLevel >= LogLevelDebug)
                {
                    server.DebugOutput = true;
                }
                server.MaxQueueSize       = srv.maxQueueSize;
                server.MaxOpenConnections = srv.maxClientConnections;
                Log(srv.name + " - Max Queue Size: " + server.MaxQueueSize);
                Log(srv.name + " - Max Client Connections: " + server.MaxOpenConnections);
                server.SetConnectionRequestHandler(
                    ConnectionRequestHandler,
                    cntIecSrv
                    );
                server.SetConnectionEventHandler(
                    ConnectionEventHandler,
                    cntIecSrv
                    );
                server.SetInterrogationHandler(
                    InterrogationHandler,
                    cntIecSrv
                    );
                server.SetASDUHandler(AsduReceivedHandler, cntIecSrv);
                server.Start();

                Log(srv.name + " - New server listening on " + localBindIpAddress + ":" + tcpPort);
                cntIecSrv++;
            }
            Thread.Sleep(1000);
            bool running = true;

            Console.CancelKeyPress +=
                delegate(object sender, ConsoleCancelEventArgs e)
            {
                e.Cancel = true;
                running  = false;
            };
            Log("Press [CTRL]+[C] to terminate...");

            do
            {
                try
                {
                    if (Client == null)
                    {
                        // retry connection
                        Client = new MongoClient(JSConfig.mongoConnectionString);
                        DB     = Client.GetDatabase(JSConfig.mongoDatabaseName);
                    }
                    IsMongoLive =
                        DB
                        .RunCommandAsync((Command <BsonDocument>)
                                         "{ping:1}")
                        .Wait(10000);
                    if (!IsMongoLive)
                    {
                        throw new Exception("Error on MongoDB connection ");
                    }
                    //foreach (IEC104_connection srv in IEC10Xconns)
                    //{
                    //}
                }
                catch (Exception e)
                { // Disconnects to retry after some time
                    Client = null;
                    Log("Exception Mongo");
                    Log(e);
                    Log(e
                        .ToString()
                        .Substring(0,
                                   e.ToString().IndexOf(Environment.NewLine)));
                    System.Threading.Thread.Sleep(3000);
                }

                Thread.Sleep(1000);
            }while (running);
            Log("Exiting application!");
            Environment.Exit(0);

            /* Synchronize clock of the controlled station */
            //con.SendClockSyncCommand(1 /* CA */, new CP56Time2a(DateTime.Now));
        }
Example #4
0
        public static void Main(string[] args)
        {
            /*
             *
             * //Instantiate the tag with the proper mapper and datatype
             * var myTag = new Tag<RealPlcMapper, float>()
             * {
             *  Name = "PLC1FLOAT0",
             *  Gateway = "127.0.0.1",
             *  Path = "1,0",
             *  PlcType = PlcType.ControlLogix,
             *  Protocol = Protocol.ab_eip,
             *  UseConnectedMessaging = true,
             *  Timeout = TimeSpan.FromSeconds(5)
             * };
             *
             * //Initialize the tag to set up structures and prepare for read/write
             * //This is optional as an optimization before using the tag
             * //If omitted, the tag will initialize on the first Read() or Write()
             * myTag.Initialize();
             *
             * //The value is held locally and only synchronized on Read() or Write()
             * myTag.Value = (float)3337.431;
             *
             * //Transfer Value to PLC
             * myTag.Write();
             *
             * var myTag2 = new Tag<DintPlcMapper, int>()
             * {
             *  Name = "PLC1ANA1",
             *  Gateway = "127.0.0.1",
             *  Path = "1,0",
             *  PlcType = PlcType.ControlLogix,
             *  UseConnectedMessaging = true,
             *  Protocol = Protocol.ab_eip,
             *  Timeout = TimeSpan.FromSeconds(5)
             * };
             *
             * //Initialize the tag to set up structures and prepare for read/write
             * //This is optional as an optimization before using the tag
             * //If omitted, the tag will initialize on the first Read() or Write()
             * myTag2.Initialize();
             *
             * //The value is held locally and only synchronized on Read() or Write()
             * myTag2.Value = 2233;
             *
             * //Transfer Value to PLC
             * myTag2.Write();
             *
             * var myTag3 = new Tag<RealPlcMapper, float[]>()
             * {
             *  Name = "SCADA",
             *  Gateway = "127.0.0.1",
             *  Path = "1,0",
             *  PlcType = PlcType.ControlLogix,
             *  UseConnectedMessaging = true,
             *  Protocol = Protocol.ab_eip,
             *  ArrayDimensions = new int[] { 10, 10 },
             *  Timeout = TimeSpan.FromSeconds(5)
             * };
             *
             * //Initialize the tag to set up structures and prepare for read/write
             * //This is optional as an optimization before using the tag
             * //If omitted, the tag will initialize on the first Read() or Write()
             * myTag3.Initialize();
             *
             * //The value is held locally and only synchronized on Read() or Write()
             * myTag3.Value = new float[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
             *
             * //Transfer Value to PLC
             * myTag3.Write();
             *
             * myTag.Dispose();
             * myTag2.Dispose();
             * myTag3.Dispose();
             */

            Log("{json:scada} PLC TAG Driver - Copyright 2020 RLO");
            Log("Driver version " + DriverVersion);
            Log("Using libplctag version " + LibPlcTag.VersionMajor + "." + LibPlcTag.VersionMinor + "." + LibPlcTag.VersionPatch);

            if (args.Length > 0) // first argument in number of the driver instance
            {
                int  num;
                bool res = int.TryParse(args[0], out num);
                if (res)
                {
                    ProtocolDriverInstanceNumber = num;
                }
            }
            if (args.Length > 1) // second argument is logLevel
            {
                int  num;
                bool res = int.TryParse(args[1], out num);
                if (res)
                {
                    LogLevel = num;
                }
            }
            string fname = JsonConfigFilePath;

            if (args.Length > 2) // third argument is config file name
            {
                if (File.Exists(args[2]))
                {
                    fname = args[2];
                }
            }
            if (!File.Exists(fname))
            {
                fname = JsonConfigFilePathAlt;
            }
            if (!File.Exists(fname))
            {
                Log("Missing config file " + JsonConfigFilePath);
                Environment.Exit(-1);
            }

            Log("Reading config file " + fname);
            string json = File.ReadAllText(fname);

            JSConfig = JsonSerializer.Deserialize <JSONSCADAConfig>(json);
            if (
                JSConfig.mongoConnectionString == "" ||
                JSConfig.mongoConnectionString == null
                )
            {
                Log("Missing MongoDB connection string in JSON config file " +
                    fname);
                Environment.Exit(-1);
            }
            // Log("MongoDB connection string: " + JSConfig.mongoConnectionString);
            if (
                JSConfig.mongoDatabaseName == "" ||
                JSConfig.mongoDatabaseName == null
                )
            {
                Log("Missing MongoDB database name in JSON config file " +
                    fname);
                Environment.Exit(-1);
            }
            Log("MongoDB database name: " + JSConfig.mongoDatabaseName);
            if (JSConfig.nodeName == "" || JSConfig.nodeName == null)
            {
                Log("Missing nodeName parameter in JSON config file " +
                    fname);
                Environment.Exit(-1);
            }
            Log("Node name: " + JSConfig.nodeName);

            var Client = ConnectMongoClient(JSConfig);
            var DB     = Client.GetDatabase(JSConfig.mongoDatabaseName);

            // read and process instances configuration
            var collinsts =
                DB
                .GetCollection
                <protocolDriverInstancesClass
                >(ProtocolDriverInstancesCollectionName);
            var instances =
                collinsts
                .Find(inst =>
                      inst.protocolDriver == ProtocolDriverName &&
                      inst.protocolDriverInstanceNumber ==
                      ProtocolDriverInstanceNumber &&
                      inst.enabled == true)
                .ToList();
            var foundInstance = false;

            foreach (protocolDriverInstancesClass inst in instances)
            {
                if (
                    ProtocolDriverName == inst.protocolDriver &&
                    ProtocolDriverInstanceNumber ==
                    inst.protocolDriverInstanceNumber
                    )
                {
                    foundInstance = true;
                    if (!inst.enabled)
                    {
                        Log("Driver instance [" +
                            ProtocolDriverInstanceNumber.ToString() +
                            "] disabled!");
                        Environment.Exit(-1);
                    }
                    Log("Instance: " +
                        inst.protocolDriverInstanceNumber.ToString());
                    var nodefound = false;
                    foreach (var name in inst.nodeNames)
                    {
                        if (JSConfig.nodeName == name)
                        {
                            nodefound = true;
                        }
                    }
                    if (!nodefound)
                    {
                        Log("Node '" +
                            JSConfig.nodeName +
                            "' not found in instances configuration!");
                        Environment.Exit(-1);
                    }
                    DriverInstance = inst;
                    break;
                }
                break; // process just first result
            }
            if (!foundInstance)
            {
                Log("Driver instance [" +
                    ProtocolDriverInstanceNumber +
                    "] not found in configuration!");
                Environment.Exit(-1);
            }

            // read and process connections configuration for this driver instance
            var collconns =
                DB
                .GetCollection
                <PLC_connection>(ProtocolConnectionsCollectionName);
            var conns =
                collconns
                .Find(conn =>
                      conn.protocolDriver == ProtocolDriverName &&
                      conn.protocolDriverInstanceNumber ==
                      ProtocolDriverInstanceNumber &&
                      conn.enabled == true)
                .ToList();

            foreach (PLC_connection isrv in conns)
            {
                if (isrv.ipAddresses.Length < 1)
                {
                    Log("Missing ipAddresses list!");
                    Environment.Exit(-1);
                }
                PLCconns.Add(isrv);
                Log(isrv.name.ToString() + " - New Connection");
            }
            if (PLCconns.Count == 0)
            {
                Log("No connections found!");
                Environment.Exit(-1);
            }

            switch (LogLevel)
            {
            case LogLevelNoLog:
                LibPlcTag.DebugLevel = DebugLevel.Detail;
                break;

            default:
            case LogLevelBasic:
                LibPlcTag.DebugLevel = DebugLevel.Warn;
                break;

            case LogLevelDetailed:
                LibPlcTag.DebugLevel = DebugLevel.Info;
                break;

            case LogLevelDebug:
                LibPlcTag.DebugLevel = DebugLevel.Detail;
                break;
            }

            // start thread to process redundancy control
            Thread thrMongoRedundacy =
                new Thread(() =>
                           ProcessRedundancyMongo(JSConfig));

            thrMongoRedundacy.Start();

            // start thread to update acquired data to database
            Thread thrMongo =
                new Thread(() =>
                           ProcessMongo(JSConfig));

            thrMongo.Start();

            Log("Setting up IEC Connections & ASDU handlers...");
            foreach (PLC_connection srv in PLCconns)
            {
                var collection = DB.GetCollection <rtData>(RealtimeDataCollectionName);
                var filter     = Builders <rtData> .Filter.Eq("protocolSourceConnectionNumber", srv.protocolConnectionNumber);

                var documents  = collection.Find(filter).ToList();
                var enumerator = documents.GetEnumerator();

                var tags = Enumerable.Range(0, documents.Count)
                           .Select(i => {
                    enumerator.MoveNext();
                    var plctp = PlcType.ControlLogix;
                    switch (srv.plc.ToLower())
                    {
                    default:
                    case "lgx":
                    case "compactlogix":
                    case "contrologix":
                    case "controllogix":
                        plctp = PlcType.ControlLogix;
                        break;

                    case "pccc":
                    case "lgxpccc":
                    case "logixpccc":
                        plctp = PlcType.LogixPccc;
                        break;

                    case "omron":
                    case "omronnjnx":
                    case "omron-njnx":
                    case "micro800":
                    case "micrologix800":
                    case "mlgx800":
                        plctp = PlcType.Micro800;
                        break;

                    case "mlgx":
                    case "micrologix":
                        plctp = PlcType.MicroLogix;
                        break;

                    case "plc5":
                        plctp = PlcType.Plc5;
                        break;

                    case "slc500":
                        plctp = PlcType.Slc500;
                        break;
                    }
                    if (enumerator.Current.protocolSourceASDU.ToString().Contains("[") && enumerator.Current.protocolSourceASDU.ToString().Contains("]"))
                    {
                        var p1       = enumerator.Current.protocolSourceASDU.ToString().IndexOf("[");
                        var p2       = enumerator.Current.protocolSourceASDU.ToString().IndexOf("]");
                        var p3       = enumerator.Current.protocolSourceObjectAddress.ToString().IndexOf("[");
                        var datatype = enumerator.Current.protocolSourceASDU.ToString().Substring(0, p1).ToLower();
                        var arrlens  = enumerator.Current.protocolSourceASDU.ToString().Substring(p1 + 1, p2 - p1 - 1);
                        var arrlen   = System.Convert.ToInt32(arrlens);
                        switch (datatype)
                        {
                        case "bool":
                        case "boolean":
                            {
                                var tag = new Tag <BoolPlcMapper, bool[]>()
                                {
                                    Name     = enumerator.Current.protocolSourceObjectAddress.ToString().Substring(0, p3),
                                    Gateway  = srv.ipAddresses[0],
                                    Path     = enumerator.Current.protocolSourceCommonAddress.ToString(),
                                    PlcType  = plctp,
                                    Protocol = (srv.protocol.ToLower() == "modbus") ? Protocol.modbus_tcp : Protocol.ab_eip,
                                    UseConnectedMessaging = srv.useConnectedMsg,
                                    Timeout         = TimeSpan.FromMilliseconds(1000),
                                    ArrayDimensions = new int[] { arrlen, 1 },
                                    ReadCacheMillisecondDuration = srv.readCacheMs
                                };

                                var tagFound = false;     // avoid tag re-insertion
                                foreach (var tg in srv.listBoolArrayTags)
                                {
                                    if (tg.Name == tag.Name)
                                    {
                                        tagFound = true;
                                    }
                                }
                                if (!tagFound)
                                {
                                    tag.Initialize();
                                    srv.listBoolArrayTags.Add(tag);
                                }
                            }
                            break;

                        case "byte":
                        case "sint":
                        case "int8":
                            {
                                var tag = new Tag <SintPlcMapper, sbyte[]>()
                                {
                                    Name     = enumerator.Current.protocolSourceObjectAddress.ToString().Substring(0, p3),
                                    Gateway  = srv.ipAddresses[0],
                                    Path     = enumerator.Current.protocolSourceCommonAddress.ToString(),
                                    PlcType  = plctp,
                                    Protocol = (srv.protocol.ToLower() == "modbus") ? Protocol.modbus_tcp : Protocol.ab_eip,
                                    UseConnectedMessaging = srv.useConnectedMsg,
                                    Timeout         = TimeSpan.FromMilliseconds(1000),
                                    ArrayDimensions = new int[] { arrlen, 1 },
                                    ReadCacheMillisecondDuration = srv.readCacheMs
                                };
                                var tagFound = false;     // avoid tag re-insertion
                                foreach (var tg in srv.listSintArrayTags)
                                {
                                    if (tg.Name == tag.Name)
                                    {
                                        tagFound = true;
                                    }
                                }
                                if (!tagFound)
                                {
                                    tag.Initialize();
                                    srv.listSintArrayTags.Add(tag);
                                }
                            }
                            break;

                        default:
                        case "int":
                        case "int16":
                            {
                                var tag = new Tag <IntPlcMapper, short[]>()
                                {
                                    Name     = enumerator.Current.protocolSourceObjectAddress.ToString().Substring(0, p3),
                                    Gateway  = srv.ipAddresses[0],
                                    Path     = enumerator.Current.protocolSourceCommonAddress.ToString(),
                                    PlcType  = plctp,
                                    Protocol = (srv.protocol.ToLower() == "modbus") ? Protocol.modbus_tcp : Protocol.ab_eip,
                                    UseConnectedMessaging = srv.useConnectedMsg,
                                    Timeout         = TimeSpan.FromMilliseconds(1000),
                                    ArrayDimensions = new int[] { arrlen, 1 },
                                    ReadCacheMillisecondDuration = srv.readCacheMs
                                };
                                var tagFound = false;     // avoid tag re-insertion
                                foreach (var tg in srv.listIntArrayTags)
                                {
                                    if (tg.Name == tag.Name)
                                    {
                                        tagFound = true;
                                    }
                                }
                                if (!tagFound)
                                {
                                    tag.Initialize();
                                    srv.listIntArrayTags.Add(tag);
                                }
                            }
                            break;

                        case "dint":
                        case "int32":
                            {
                                var tag = new Tag <DintPlcMapper, int[]>()
                                {
                                    Name     = enumerator.Current.protocolSourceObjectAddress.ToString().Substring(0, p3),
                                    Gateway  = srv.ipAddresses[0],
                                    Path     = enumerator.Current.protocolSourceCommonAddress.ToString(),
                                    PlcType  = plctp,
                                    Protocol = (srv.protocol.ToLower() == "modbus") ? Protocol.modbus_tcp : Protocol.ab_eip,
                                    UseConnectedMessaging = srv.useConnectedMsg,
                                    Timeout         = TimeSpan.FromMilliseconds(1000),
                                    ArrayDimensions = new int[] { arrlen, 1 },
                                    ReadCacheMillisecondDuration = srv.readCacheMs
                                };
                                tag.Initialize();
                                srv.listDintArrayTags.Add(tag);
                                var tagFound = false;     // avoid tag re-insertion
                                foreach (var tg in srv.listDintArrayTags)
                                {
                                    if (tg.Name == tag.Name)
                                    {
                                        tagFound = true;
                                    }
                                }
                                if (!tagFound)
                                {
                                    tag.Initialize();
                                    srv.listDintArrayTags.Add(tag);
                                }
                            }
                            break;

                        case "lint":
                        case "int64":
                            {
                                var tag = new Tag <LintPlcMapper, long[]>()
                                {
                                    Name     = enumerator.Current.protocolSourceObjectAddress.ToString().Substring(0, p3),
                                    Gateway  = srv.ipAddresses[0],
                                    Path     = enumerator.Current.protocolSourceCommonAddress.ToString(),
                                    PlcType  = plctp,
                                    Protocol = (srv.protocol.ToLower() == "modbus") ? Protocol.modbus_tcp : Protocol.ab_eip,
                                    UseConnectedMessaging = srv.useConnectedMsg,
                                    Timeout         = TimeSpan.FromMilliseconds(1000),
                                    ArrayDimensions = new int[] { arrlen, 1 },
                                    ReadCacheMillisecondDuration = srv.readCacheMs
                                };
                                tag.Initialize();
                                srv.listLintArrayTags.Add(tag);
                                var tagFound = false;     // avoid tag re-insertion
                                foreach (var tg in srv.listLintArrayTags)
                                {
                                    if (tg.Name == tag.Name)
                                    {
                                        tagFound = true;
                                    }
                                }
                                if (!tagFound)
                                {
                                    tag.Initialize();
                                    srv.listLintArrayTags.Add(tag);
                                }
                            }
                            break;

                        case "real":
                        case "float32":
                            {
                                var tag = new Tag <RealPlcMapper, float[]>()
                                {
                                    Name     = enumerator.Current.protocolSourceObjectAddress.ToString().Substring(0, p3),
                                    Gateway  = srv.ipAddresses[0],
                                    Path     = enumerator.Current.protocolSourceCommonAddress.ToString(),
                                    PlcType  = plctp,
                                    Protocol = (srv.protocol.ToLower() == "modbus") ? Protocol.modbus_tcp : Protocol.ab_eip,
                                    UseConnectedMessaging = srv.useConnectedMsg,
                                    Timeout         = TimeSpan.FromMilliseconds(1000),
                                    ArrayDimensions = new int[] { arrlen, 1 },
                                };
                                var tagFound = false;     // avoid tag re-insertion
                                foreach (var tg in srv.listRealArrayTags)
                                {
                                    if (tg.Name == tag.Name)
                                    {
                                        tagFound = true;
                                    }
                                }
                                if (!tagFound)
                                {
                                    tag.Initialize();
                                    srv.listRealArrayTags.Add(tag);
                                }
                            }
                            break;

                        case "lreal":
                        case "float64":
                            {
                                var tag = new Tag <LrealPlcMapper, double[]>()
                                {
                                    Name     = enumerator.Current.protocolSourceObjectAddress.ToString().Substring(0, p1 + 1),
                                    Gateway  = srv.ipAddresses[0],
                                    Path     = enumerator.Current.protocolSourceCommonAddress.ToString(),
                                    PlcType  = plctp,
                                    Protocol = (srv.protocol.ToLower() == "modbus") ? Protocol.modbus_tcp : Protocol.ab_eip,
                                    UseConnectedMessaging = srv.useConnectedMsg,
                                    Timeout         = TimeSpan.FromMilliseconds(1000),
                                    ArrayDimensions = new int[] { arrlen, 1 },
                                    ReadCacheMillisecondDuration = srv.readCacheMs
                                };
                                var tagFound = false;     // avoid tag re-insertion
                                foreach (var tg in srv.listLrealArrayTags)
                                {
                                    if (tg.Name == tag.Name)
                                    {
                                        tagFound = true;
                                    }
                                }
                                if (!tagFound)
                                {
                                    tag.Initialize();
                                    srv.listLrealArrayTags.Add(tag);
                                }
                            }
                            break;
                        }
                    }
                    else
                    {
                        switch (enumerator.Current.protocolSourceASDU.ToString().ToLower())
                        {
                        case "bool":
                        case "boolean":
                            {
                                var tag = new Tag <BoolPlcMapper, bool>()
                                {
                                    Name     = enumerator.Current.protocolSourceObjectAddress.ToString(),
                                    Gateway  = srv.ipAddresses[0],
                                    Path     = enumerator.Current.protocolSourceCommonAddress.ToString(),
                                    PlcType  = plctp,
                                    Protocol = (srv.protocol.ToLower() == "modbus") ? Protocol.modbus_tcp : Protocol.ab_eip,
                                    UseConnectedMessaging = srv.useConnectedMsg,
                                    Timeout = TimeSpan.FromMilliseconds(1000),
                                    ReadCacheMillisecondDuration = srv.readCacheMs
                                };
                                tag.Initialize();
                                srv.listBoolTags.Add(tag);
                            }
                            break;

                        case "byte":
                        case "sint":
                        case "int8":
                            {
                                var tag = new Tag <SintPlcMapper, sbyte>()
                                {
                                    Name     = enumerator.Current.protocolSourceObjectAddress.ToString(),
                                    Gateway  = srv.ipAddresses[0],
                                    Path     = enumerator.Current.protocolSourceCommonAddress.ToString(),
                                    PlcType  = plctp,
                                    Protocol = (srv.protocol.ToLower() == "modbus") ? Protocol.modbus_tcp : Protocol.ab_eip,
                                    UseConnectedMessaging = srv.useConnectedMsg,
                                    Timeout = TimeSpan.FromMilliseconds(1000),
                                    ReadCacheMillisecondDuration = srv.readCacheMs
                                };
                                tag.Initialize();
                                srv.listSintTags.Add(tag);
                            }
                            break;

                        default:
                        case "int":
                        case "int16":
                            {
                                var tag = new Tag <IntPlcMapper, short>()
                                {
                                    Name     = enumerator.Current.protocolSourceObjectAddress.ToString(),
                                    Gateway  = srv.ipAddresses[0],
                                    Path     = enumerator.Current.protocolSourceCommonAddress.ToString(),
                                    PlcType  = plctp,
                                    Protocol = (srv.protocol.ToLower() == "modbus") ? Protocol.modbus_tcp : Protocol.ab_eip,
                                    UseConnectedMessaging = srv.useConnectedMsg,
                                    Timeout = TimeSpan.FromMilliseconds(1000),
                                    ReadCacheMillisecondDuration = srv.readCacheMs
                                };
                                tag.Initialize();
                                srv.listIntTags.Add(tag);
                            }
                            break;

                        case "dint":
                        case "int32":
                            {
                                var tag = new Tag <DintPlcMapper, int>()
                                {
                                    Name     = enumerator.Current.protocolSourceObjectAddress.ToString(),
                                    Gateway  = srv.ipAddresses[0],
                                    Path     = enumerator.Current.protocolSourceCommonAddress.ToString(),
                                    PlcType  = plctp,
                                    Protocol = (srv.protocol.ToLower() == "modbus") ? Protocol.modbus_tcp : Protocol.ab_eip,
                                    UseConnectedMessaging = srv.useConnectedMsg,
                                    Timeout = TimeSpan.FromMilliseconds(1000),
                                    ReadCacheMillisecondDuration = srv.readCacheMs
                                };
                                tag.Initialize();
                                srv.listDintTags.Add(tag);
                            }
                            break;

                        case "lint":
                        case "int64":
                            {
                                var tag = new Tag <LintPlcMapper, long>()
                                {
                                    Name     = enumerator.Current.protocolSourceObjectAddress.ToString(),
                                    Gateway  = srv.ipAddresses[0],
                                    Path     = enumerator.Current.protocolSourceCommonAddress.ToString(),
                                    PlcType  = plctp,
                                    Protocol = (srv.protocol.ToLower() == "modbus") ? Protocol.modbus_tcp : Protocol.ab_eip,
                                    UseConnectedMessaging = srv.useConnectedMsg,
                                    Timeout = TimeSpan.FromMilliseconds(1000),
                                    ReadCacheMillisecondDuration = srv.readCacheMs
                                };
                                tag.Initialize();
                                srv.listLintTags.Add(tag);
                            }
                            break;

                        case "real":
                        case "float32":
                            {
                                var tag = new Tag <RealPlcMapper, float>()
                                {
                                    Name     = enumerator.Current.protocolSourceObjectAddress.ToString(),
                                    Gateway  = srv.ipAddresses[0],
                                    Path     = enumerator.Current.protocolSourceCommonAddress.ToString(),
                                    PlcType  = plctp,
                                    Protocol = (srv.protocol.ToLower() == "modbus") ? Protocol.modbus_tcp : Protocol.ab_eip,
                                    UseConnectedMessaging = srv.useConnectedMsg,
                                    Timeout = TimeSpan.FromMilliseconds(1000),
                                    ReadCacheMillisecondDuration = srv.readCacheMs
                                };
                                tag.Initialize();
                                srv.listRealTags.Add(tag);
                            }
                            break;

                        case "lreal":
                        case "float64":
                            {
                                var tag = new Tag <LrealPlcMapper, double>()
                                {
                                    Name     = enumerator.Current.protocolSourceObjectAddress.ToString(),
                                    Gateway  = srv.ipAddresses[0],
                                    Path     = enumerator.Current.protocolSourceCommonAddress.ToString(),
                                    PlcType  = plctp,
                                    Protocol = (srv.protocol.ToLower() == "modbus") ? Protocol.modbus_tcp : Protocol.ab_eip,
                                    UseConnectedMessaging = srv.useConnectedMsg,
                                    Timeout = TimeSpan.FromMilliseconds(1000),
                                    ReadCacheMillisecondDuration = srv.readCacheMs
                                };
                                tag.Initialize();
                                srv.listLrealTags.Add(tag);
                            }
                            break;
                        }
                    }

                    return(0);
                })
                           .ToList();

                // A thread for scanning each connection
                Thread thrPlcScan =
                    new Thread(() =>
                               ProcessPLCScan(srv));
                thrPlcScan.Start();
            }

            // start thread to watch for commands in the database using a change stream
            Thread thrMongoCmd =
                new Thread(() =>
                           ProcessMongoCmd(JSConfig));

            thrMongoCmd.Start();


            do
            {
                Thread.Sleep(500);

                if (!Console.IsInputRedirected)
                {
                    if (Console.KeyAvailable)
                    {
                        if (Console.ReadKey().Key == ConsoleKey.Escape)
                        {
                            Log("Exiting application!");
                            Environment.Exit(0);
                        }
                        else
                        {
                            Log("Press 'Esc' key to terminate...");
                        }
                    }
                }
            } while (true);
        }
Example #5
0
        static int Main(string[] args)
        {
            Log(DriverMessage);
            Log("Driver version " + DriverVersion);
            Log("Using opendnp3 version 3.1.1");

            if (args.Length > 0) // first argument in number of the driver instance
            {
                int  num;
                bool res = int.TryParse(args[0], out num);
                if (res)
                {
                    ProtocolDriverInstanceNumber = num;
                }
            }
            if (args.Length > 1) // second argument is logLevel
            {
                int  num;
                bool res = int.TryParse(args[1], out num);
                if (res)
                {
                    LogLevel = num;
                }
            }
            string fname = JsonConfigFilePath;

            if (args.Length > 2) // third argument is config file name
            {
                if (File.Exists(args[2]))
                {
                    fname = args[2];
                }
            }
            if (!File.Exists(fname))
            {
                fname = JsonConfigFilePathAlt;
            }
            if (!File.Exists(fname))
            {
                Log("Missing config file " + JsonConfigFilePath);
                Environment.Exit(-1);
            }

            Log("Reading config file " + fname);
            string json = File.ReadAllText(fname);

            JSConfig = JsonSerializer.Deserialize <JSONSCADAConfig>(json);
            if (
                JSConfig.mongoConnectionString == "" ||
                JSConfig.mongoConnectionString == null
                )
            {
                Log("Missing MongoDB connection string in JSON config file " +
                    fname);
                Environment.Exit(-1);
            }
            if (
                JSConfig.mongoDatabaseName == "" ||
                JSConfig.mongoDatabaseName == null
                )
            {
                Log("Missing MongoDB database name in JSON config file " +
                    fname);
                Environment.Exit(-1);
            }
            Log("MongoDB database name: " + JSConfig.mongoDatabaseName);
            if (JSConfig.nodeName == "" || JSConfig.nodeName == null)
            {
                Log("Missing nodeName parameter in JSON config file " +
                    fname);
                Environment.Exit(-1);
            }
            Log("Node name: " + JSConfig.nodeName);

            var Client = ConnectMongoClient(JSConfig);
            var DB     = Client.GetDatabase(JSConfig.mongoDatabaseName);

            // read and process instances configuration
            var collinsts =
                DB
                .GetCollection
                <protocolDriverInstancesClass
                >(ProtocolDriverInstancesCollectionName);
            var instances =
                collinsts
                .Find(inst =>
                      inst.protocolDriver == ProtocolDriverName &&
                      inst.protocolDriverInstanceNumber ==
                      ProtocolDriverInstanceNumber &&
                      inst.enabled == true)
                .ToList();
            var foundInstance = false;

            foreach (protocolDriverInstancesClass inst in instances)
            {
                if (
                    ProtocolDriverName == inst.protocolDriver &&
                    ProtocolDriverInstanceNumber ==
                    inst.protocolDriverInstanceNumber
                    )
                {
                    foundInstance = true;
                    if (!inst.enabled)
                    {
                        Log("Driver instance [" +
                            ProtocolDriverInstanceNumber.ToString() +
                            "] disabled!");
                        Environment.Exit(-1);
                    }
                    Log("Instance: " +
                        inst.protocolDriverInstanceNumber.ToString());
                    var nodefound = false;
                    foreach (var name in inst.nodeNames)
                    {
                        if (JSConfig.nodeName == name)
                        {
                            nodefound = true;
                        }
                    }
                    if (!nodefound)
                    {
                        Log("Node '" +
                            JSConfig.nodeName +
                            "' not found in instances configuration!");
                        Environment.Exit(-1);
                    }
                    DriverInstance = inst;
                    break;
                }
                break; // process just first result
            }
            if (!foundInstance)
            {
                Log("Driver instance [" +
                    ProtocolDriverInstanceNumber +
                    "] not found in configuration!");
                Environment.Exit(-1);
            }

            // read and process connections configuration for this driver instance
            var collconns =
                DB
                .GetCollection
                <DNP3_connection>(ProtocolConnectionsCollectionName);
            var conns =
                collconns
                .Find(conn =>
                      conn.protocolDriver == ProtocolDriverName &&
                      conn.protocolDriverInstanceNumber ==
                      ProtocolDriverInstanceNumber &&
                      conn.enabled == true)
                .ToList();

            foreach (DNP3_connection isrv in conns)
            {
                if (isrv.ipAddresses.Length < 1 && isrv.portName.Trim() == "")
                {
                    Log("No ipAddresses or port name defined on conenction! " + isrv.name);
                    Environment.Exit(-1);
                }
                DNP3conns.Add(isrv);
                Log(isrv.name.ToString() + " - New Connection");
            }
            if (DNP3conns.Count == 0)
            {
                Log("No connections found!");
                Environment.Exit(-1);
            }

            // start thread to process redundancy control
            Thread thrMongoRedundacy =
                new Thread(() =>
                           ProcessRedundancyMongo(JSConfig));

            thrMongoRedundacy.Start();

            // start thread to update acquired data to database
            Thread thrMongo =
                new Thread(() =>
                           ProcessMongo(JSConfig));

            thrMongo.Start();

            // start thread to watch for commands in the database using a change stream
            Thread thrMongoCmd =
                new Thread(() =>
                           ProcessMongoCmd(JSConfig));

            thrMongoCmd.Start();

            Log("Setting up connections & ASDU handlers...");
            mgr = DNP3ManagerFactory.CreateManager(2 * Environment.ProcessorCount, new PrintingLogAdapter());
            foreach (DNP3_connection srv in DNP3conns)
            {
                uint logLevel = LogLevels.NONE;
                if (LogLevel >= LogLevelBasic)
                {
                    logLevel = LogLevels.NORMAL;
                }
                if (LogLevel >= LogLevelDetailed)
                {
                    logLevel = LogLevels.NORMAL | LogLevels.APP_COMMS;
                }
                if (LogLevel >= LogLevelDebug)
                {
                    logLevel = LogLevels.ALL;
                }

                MyChannelListener chlistener = new MyChannelListener();
                chlistener.dnp3conn = srv;

                IChannel channel = null;        // can be tcp, udp, tls, or serial
                if (srv.ipAddresses.Length > 0) // TCP, TLS or UDP
                {
                    if (srv.ipAddressLocalBind.Trim() != "")
                    { // UDP
                        // look for the same channel config already created (multi-drop case)
                        // if found, just reuse
                        foreach (DNP3_connection conn in DNP3conns)
                        {
                            if (!(conn.channel is null))
                            {
                                if (conn.ipAddressLocalBind.Trim() != "" &&
                                    srv.ipAddressLocalBind.Trim() == conn.ipAddressLocalBind.Trim() &&
                                    srv.ipAddresses[0] == conn.ipAddresses[0])
                                {
                                    channel = conn.channel;
                                    break;
                                }
                            }
                        }
                        if (!(channel is null))
                        {
                            Log(srv.name + " - Reusing channel...");
                        }
                        else
                        {
                            Log(srv.name + " - Creating UDP channel...");
                            ushort   localUdpPort    = 20000;
                            string[] localIpAddrPort = srv.ipAddressLocalBind.Split(':');
                            if (localIpAddrPort.Length > 1)
                            {
                                if (int.TryParse(localIpAddrPort[1], out _))
                                {
                                    localUdpPort = System.Convert.ToUInt16(localIpAddrPort[1]);
                                }
                            }
                            ushort   remoteUdpPort    = 20000;
                            string[] remoteIpAddrPort = srv.ipAddresses[0].Split(':');
                            if (remoteIpAddrPort.Length > 1)
                            {
                                if (int.TryParse(remoteIpAddrPort[1], out _))
                                {
                                    remoteUdpPort = System.Convert.ToUInt16(remoteIpAddrPort[1]);
                                }
                            }
                            channel = mgr.AddUDPChannel(
                                "UDP:" + srv.name,
                                logLevel,
                                new ChannelRetry(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(5)),
                                new IPEndpoint(localIpAddrPort[0], localUdpPort),
                                new IPEndpoint(remoteIpAddrPort[0], remoteUdpPort),
                                chlistener
                                );
                        }
                    }
                    else
                    { // TCP or TLS
                        ushort   tcpPort    = 20000;
                        string[] ipAddrPort = srv.ipAddresses[0].Split(':');
                        if (ipAddrPort.Length > 1)
                        {
                            if (int.TryParse(ipAddrPort[1], out _))
                            {
                                tcpPort = System.Convert.ToUInt16(ipAddrPort[1]);
                            }
                        }

                        // look for the same channel config already created (multi-drop case)
                        // if found, just reuse
                        foreach (DNP3_connection conn in DNP3conns)
                        {
                            if (!(conn.channel is null))
                            {
                                if (srv.ipAddresses.SequenceEqual(conn.ipAddresses))
                                {
                                    channel = conn.channel;
                                    break;
                                }
                            }
                        }
                        if (!(channel is null))
                        {
                            Log(srv.name + " - Reusing channel...");
                        }
Example #6
0
        public static Int32 BulkWriteLimit  = 1000;  // limit of each bulk write to mongodb
        //public static int OPCDefaultPublishingInterval = 2500;
        //public static int OPCDefaultSamplingInterval = 1000;
        //public static uint OPCDefaultQueueSize = 10;

        public static int Main(string[] args)
        {
            Log("{json:scada} OPC-UA Client Driver - Copyright 2021 RLO");
            Log("Driver version " + DriverVersion);
            Log("Using UA-.NETStandard library from the OPC Foundation.");

            if (args.Length > 0) // first argument in number of the driver instance
            {
                int  num;
                bool res = int.TryParse(args[0], out num);
                if (res)
                {
                    ProtocolDriverInstanceNumber = num;
                }
            }
            if (args.Length > 1) // second argument is logLevel
            {
                int  num;
                bool res = int.TryParse(args[1], out num);
                if (res)
                {
                    LogLevel = num;
                }
            }

            string fname = JsonConfigFilePath;

            if (args.Length > 2) // third argument is config file name
            {
                if (File.Exists(args[2]))
                {
                    fname = args[2];
                }
            }
            if (!File.Exists(fname))
            {
                fname = JsonConfigFilePathAlt;
            }
            if (!File.Exists(fname))
            {
                Log("Missing config file " + JsonConfigFilePath);
                Environment.Exit(-1);
            }

            Log("Reading config file " + fname);
            string json = File.ReadAllText(fname);

            JSConfig = JsonSerializer.Deserialize <JSONSCADAConfig>(json);
            if (
                JSConfig.mongoConnectionString == "" ||
                JSConfig.mongoConnectionString == null
                )
            {
                Log("Missing MongoDB connection string in JSON config file " +
                    fname);
                Environment.Exit(-1);
            }
            // Log("MongoDB connection string: " + JSConfig.mongoConnectionString);
            if (
                JSConfig.mongoDatabaseName == "" ||
                JSConfig.mongoDatabaseName == null
                )
            {
                Log("Missing MongoDB database name in JSON config file " +
                    fname);
                Environment.Exit(-1);
            }
            Log("MongoDB database name: " + JSConfig.mongoDatabaseName);
            if (JSConfig.nodeName == "" || JSConfig.nodeName == null)
            {
                Log("Missing nodeName parameter in JSON config file " +
                    fname);
                Environment.Exit(-1);
            }
            Log("Node name: " + JSConfig.nodeName);

            var Client = ConnectMongoClient(JSConfig);
            var DB     = Client.GetDatabase(JSConfig.mongoDatabaseName);

            // read and process instances configuration
            var collinsts =
                DB
                .GetCollection
                <protocolDriverInstancesClass
                >(ProtocolDriverInstancesCollectionName);
            var instances =
                collinsts
                .Find(inst =>
                      inst.protocolDriver == ProtocolDriverName &&
                      inst.protocolDriverInstanceNumber ==
                      ProtocolDriverInstanceNumber &&
                      inst.enabled == true)
                .ToList();
            var foundInstance = false;

            foreach (protocolDriverInstancesClass inst in instances)
            {
                if (
                    ProtocolDriverName == inst.protocolDriver &&
                    ProtocolDriverInstanceNumber ==
                    inst.protocolDriverInstanceNumber
                    )
                {
                    foundInstance = true;
                    if (!inst.enabled)
                    {
                        Log("Driver instance [" +
                            ProtocolDriverInstanceNumber.ToString() +
                            "] disabled!");
                        Environment.Exit(-1);
                    }
                    Log("Instance: " +
                        inst.protocolDriverInstanceNumber.ToString());
                    var nodefound = false;
                    foreach (var name in inst.nodeNames)
                    {
                        if (JSConfig.nodeName == name)
                        {
                            nodefound = true;
                        }
                    }
                    if (!nodefound)
                    {
                        Log("Node '" +
                            JSConfig.nodeName +
                            "' not found in instances configuration!");
                        Environment.Exit(-1);
                    }
                    DriverInstance = inst;
                    break;
                }
                break; // process just first result
            }
            if (!foundInstance)
            {
                Log("Driver instance [" +
                    ProtocolDriverInstanceNumber +
                    "] not found in configuration!");
                Environment.Exit(-1);
            }

            // read and process connections configuration for this driver instance
            var collconns =
                DB
                .GetCollection
                <OPCUA_connection>(ProtocolConnectionsCollectionName);
            var conns =
                collconns
                .Find(conn =>
                      conn.protocolDriver == ProtocolDriverName &&
                      conn.protocolDriverInstanceNumber ==
                      ProtocolDriverInstanceNumber &&
                      conn.enabled == true)
                .ToList();

            foreach (OPCUA_connection isrv in conns)
            {
                if (isrv.endpointURLs.Length < 1)
                {
                    Log("Missing remote endpoint URLs list!");
                    Environment.Exit(-1);
                }
                OPCUAconns.Add(isrv);
                Log(isrv.name.ToString() + " - New Connection");
            }
            if (OPCUAconns.Count == 0)
            {
                Log("No connections found!");
                Environment.Exit(-1);
            }

            // start thread to process redundancy control
            var thrMongoRedundacy =
                new Thread(() =>
                           ProcessRedundancyMongo(JSConfig));

            thrMongoRedundacy.Start();

            // start thread to update acquired data to database
            var thrMongo =
                new Thread(() =>
                           ProcessMongo(JSConfig));

            thrMongo.Start();

            // thrMongo.Priority = ThreadPriority.AboveNormal;

            // start thread to watch for commands in the database using a change stream
            //var thrMongoCmd =
            //    new Thread(() =>
            //            ProcessMongoCmd(JSConfig));
            //thrMongoCmd.Start();

            Log("Setting up OPC-UA Connections & ASDU handlers...");
            var thrSrvs = new List <Thread>();

            foreach (OPCUA_connection srv in OPCUAconns)
            {
                srv.connection = new OPCUAClient(srv);
                // srv.connection.Run();
                srv.thrOPCStack = new Thread(() => srv.connection.Run());
                srv.thrOPCStack.Start();
            }

            Thread.Sleep(1000);

            do
            {
                foreach (OPCUA_connection srv in OPCUAconns)
                {
                }

                Thread.Sleep(1000);

                if (!Console.IsInputRedirected)
                {
                    if (Console.KeyAvailable)
                    {
                        if (Console.ReadKey().Key == ConsoleKey.Escape)
                        {
                            Log("Exiting application!");
                            Environment.Exit(0);
                        }
                        else
                        {
                            Log("Press 'Esc' key to terminate...");
                        }
                    }
                }
            } while (true);

            // return (int)OPCUAClient.ExitCode;
        }
Example #7
0
        static void Main(string[] args)
        {
            Log("{json:scada} IEC60870-5-104 Driver - Copyright 2020 RLO");
            Log("Driver version " + DriverVersion);
            Log("Using lib60870.NET version " +
                LibraryCommon.GetLibraryVersionString());

            if (args.Length > 0) // first argument in number of the driver instance
            {
                int  num;
                bool res = int.TryParse(args[0], out num);
                if (res)
                {
                    ProtocolDriverInstanceNumber = num;
                }
            }
            if (args.Length > 1) // second argument is logLevel
            {
                int  num;
                bool res = int.TryParse(args[1], out num);
                if (res)
                {
                    LogLevel = num;
                }
            }

            string fname = JsonConfigFilePath;

            if (args.Length > 2) // third argument is config file name
            {
                if (File.Exists(args[2]))
                {
                    fname = args[2];
                }
            }
            if (!File.Exists(fname))
            {
                fname = JsonConfigFilePathAlt;
            }
            if (!File.Exists(fname))
            {
                Log("Missing config file " + JsonConfigFilePath);
                Environment.Exit(-1);
            }

            Log("Reading config file " + fname);
            string json = File.ReadAllText(fname);

            JSConfig = JsonSerializer.Deserialize <JSONSCADAConfig>(json);
            if (
                JSConfig.mongoConnectionString == "" ||
                JSConfig.mongoConnectionString == null
                )
            {
                Log("Missing MongoDB connection string in JSON config file " +
                    fname);
                Environment.Exit(-1);
            }
            // Log("MongoDB connection string: " + JSConfig.mongoConnectionString);
            if (
                JSConfig.mongoDatabaseName == "" ||
                JSConfig.mongoDatabaseName == null
                )
            {
                Log("Missing MongoDB database name in JSON config file " +
                    fname);
                Environment.Exit(-1);
            }
            Log("MongoDB database name: " + JSConfig.mongoDatabaseName);
            if (JSConfig.nodeName == "" || JSConfig.nodeName == null)
            {
                Log("Missing nodeName parameter in JSON config file " +
                    fname);
                Environment.Exit(-1);
            }
            Log("Node name: " + JSConfig.nodeName);

            var Client = ConnectMongoClient(JSConfig);
            var DB     = Client.GetDatabase(JSConfig.mongoDatabaseName);

            // read and process instances configuration
            var collinsts =
                DB
                .GetCollection
                <protocolDriverInstancesClass
                >(ProtocolDriverInstancesCollectionName);
            var instances =
                collinsts
                .Find(inst =>
                      inst.protocolDriver == ProtocolDriverName &&
                      inst.protocolDriverInstanceNumber ==
                      ProtocolDriverInstanceNumber &&
                      inst.enabled == true)
                .ToList();
            var foundInstance = false;

            foreach (protocolDriverInstancesClass inst in instances)
            {
                if (
                    ProtocolDriverName == inst.protocolDriver &&
                    ProtocolDriverInstanceNumber ==
                    inst.protocolDriverInstanceNumber
                    )
                {
                    foundInstance = true;
                    if (!inst.enabled)
                    {
                        Log("Driver instance [" +
                            ProtocolDriverInstanceNumber.ToString() +
                            "] disabled!");
                        Environment.Exit(-1);
                    }
                    Log("Instance: " +
                        inst.protocolDriverInstanceNumber.ToString());
                    var nodefound = false;
                    foreach (var name in inst.nodeNames)
                    {
                        if (JSConfig.nodeName == name)
                        {
                            nodefound = true;
                        }
                    }
                    if (!nodefound)
                    {
                        Log("Node '" +
                            JSConfig.nodeName +
                            "' not found in instances configuration!");
                        Environment.Exit(-1);
                    }
                    DriverInstance = inst;
                    break;
                }
                break; // process just first result
            }
            if (!foundInstance)
            {
                Log("Driver instance [" +
                    ProtocolDriverInstanceNumber +
                    "] not found in configuration!");
                Environment.Exit(-1);
            }

            // read and process connections configuration for this driver instance
            var collconns =
                DB
                .GetCollection
                <IEC10X_connection>(ProtocolConnectionsCollectionName);
            var conns =
                collconns
                .Find(conn =>
                      conn.protocolDriver == ProtocolDriverName &&
                      conn.protocolDriverInstanceNumber ==
                      ProtocolDriverInstanceNumber &&
                      conn.enabled == true)
                .ToList();

            foreach (IEC10X_connection isrv in conns)
            {
                if (isrv.ipAddresses.Length < 1)
                {
                    Log("Missing ipAddresses list!");
                    Environment.Exit(-1);
                }
                IEC10Xconns.Add(isrv);
                Log(isrv.name.ToString() + " - New Connection");
            }
            if (IEC10Xconns.Count == 0)
            {
                Log("No connections found!");
                Environment.Exit(-1);
            }

            // start thread to process redundancy control
            Thread thrMongoRedundacy =
                new Thread(() =>
                           ProcessRedundancyMongo(JSConfig));

            thrMongoRedundacy.Start();

            // start thread to update acquired data to database
            Thread thrMongo =
                new Thread(() =>
                           ProcessMongo(JSConfig));

            thrMongo.Start();

            // start thread to watch for commands in the database using a change stream
            Thread thrMongoCmd =
                new Thread(() =>
                           ProcessMongoCmd(JSConfig));

            thrMongoCmd.Start();

            Log("Setting up IEC Connections & ASDU handlers...");
            int cntIecSrv = 0;

            foreach (IEC10X_connection srv in IEC10Xconns)
            {
                var apcipars = new APCIParameters();
                apcipars.K  = srv.k;
                apcipars.W  = srv.w;
                apcipars.T0 = srv.t0;
                apcipars.T1 = srv.t1;
                apcipars.T2 = srv.t2;
                apcipars.T3 = srv.t3;
                var alpars = new ApplicationLayerParameters();
                alpars.SizeOfCOT = srv.sizeOfCOT;
                alpars.SizeOfCA  = srv.sizeOfCA;
                alpars.SizeOfIOA = srv.sizeOfIOA;
                alpars.OA        = srv.localLinkAddress;

                TlsSecurityInformation secInfo = null;
                if (srv.localCertFilePath != "")
                {
                    try
                    {
                        // Own certificate has to be a pfx file that contains the private key
                        X509Certificate2 ownCertificate = new X509Certificate2(srv.localCertFilePath);

                        // Create a new security information object to configure TLS
                        secInfo = new TlsSecurityInformation(null, ownCertificate);

                        // Add allowed server certificates - not required when AllowOnlySpecificCertificates == false
                        secInfo.AddAllowedCertificate(new X509Certificate2(srv.peerCertFilePath));

                        // Add a CA certificate to check the certificate provided by the server - not required when ChainValidation == false
                        secInfo.AddCA(new X509Certificate2(srv.rootCertFilePath));

                        // Check if the certificate is signed by a provided CA
                        secInfo.ChainValidation = srv.chainValidation;

                        // Check that the shown server certificate is in the list of allowed certificates
                        secInfo.AllowOnlySpecificCertificates = srv.allowOnlySpecificCertificates;
                    }
                    catch (Exception e)
                    {
                        Log(srv.name + " - Error configuring TLS certficates.");
                        Log(srv.name + " - " + e.Message);
                        Environment.Exit(1);
                    }
                }

                var      tcpPort    = 2404;
                string[] ipAddrPort = srv.ipAddresses[0].Split(':');
                if (ipAddrPort.Length > 1)
                {
                    if (int.TryParse(ipAddrPort[1], out _))
                    {
                        tcpPort = System.Convert.ToInt32(ipAddrPort[1]);
                    }
                }
                var con =
                    new Connection(ipAddrPort[0],
                                   tcpPort,
                                   apcipars,
                                   alpars);
                con.Parameters.OA     = srv.localLinkAddress;
                srv.conn1             = con;
                srv.conn2             = con;
                srv.connection        = con;
                srv.CntGI             = srv.giInterval - 3;
                srv.CntTestCommand    = srv.testCommandInterval - 1;
                srv.CntTimeSync       = 0;
                srv.CntTestCommandSeq = 0;
                if (LogLevel >= LogLevelDebug)
                {
                    con.DebugOutput = true;
                }
                con.SetASDUReceivedHandler(AsduReceivedHandler, cntIecSrv);
                con.SetConnectionHandler(ConnectionHandler, cntIecSrv);

                if (srv.ipAddresses.Length > 1) // is there a secondary server ?
                {
                    string[] ipAddrPort2 = srv.ipAddresses[1].Split(':');
                    if (ipAddrPort2.Length > 1)
                    {
                        if (int.TryParse(ipAddrPort2[1], out _))
                        {
                            tcpPort = System.Convert.ToInt32(ipAddrPort2[1]);
                        }
                    }
                    var c2 =
                        new Connection(ipAddrPort2[0],
                                       tcpPort,
                                       apcipars,
                                       alpars);
                    con.Parameters.OA = srv.localLinkAddress;
                    srv.conn2         = c2;
                    srv.connection    = c2; // force initial swap to primary server
                    if (LogLevel >= LogLevelDebug)
                    {
                        c2.DebugOutput = true;
                    }
                    c2.SetASDUReceivedHandler(AsduReceivedHandler, cntIecSrv);
                    c2.SetConnectionHandler(ConnectionHandler, cntIecSrv);
                }

                if (srv.localCertFilePath != "" && secInfo != null)
                {
                    srv.conn1.SetTlsSecurity(secInfo);
                    srv.conn2.SetTlsSecurity(secInfo);
                }

                // create timer to increment counters each second
                srv.TimerCnt          = new System.Timers.Timer();
                srv.TimerCnt.Interval = 1000;
                srv.TimerCnt.Elapsed += (sender, e) => MyElapsedMethod(sender, e, srv);
Example #8
0
        public static void Main(string[] args)
        {
            Log("{json:scada} IEC60870-5-101 Driver - Copyright 2020 RLO");
            Log("Driver version " + DriverVersion);
            Log("Using lib60870.NET version " +
                LibraryCommon.GetLibraryVersionString());

            if (args.Length > 0) // first argument in number of the driver instance
            {
                int  num;
                bool res = int.TryParse(args[0], out num);
                if (res)
                {
                    ProtocolDriverInstanceNumber = num;
                }
            }
            if (args.Length > 1) // second argument is logLevel
            {
                int  num;
                bool res = int.TryParse(args[1], out num);
                if (res)
                {
                    LogLevel = num;
                }
            }

            string fname = JsonConfigFilePath;

            if (args.Length > 2) // third argument is config file name
            {
                if (File.Exists(args[2]))
                {
                    fname = args[2];
                }
            }
            if (!File.Exists(fname))
            {
                fname = JsonConfigFilePathAlt;
            }
            if (!File.Exists(fname))
            {
                Log("Missing config file " + JsonConfigFilePath);
                Environment.Exit(-1);
            }

            Log("Reading config file " + fname);
            string json = File.ReadAllText(fname);

            JSConfig = JsonSerializer.Deserialize <JSONSCADAConfig>(json);
            if (
                JSConfig.mongoConnectionString == "" ||
                JSConfig.mongoConnectionString == null
                )
            {
                Log("Missing MongoDB connection string in JSON config file " +
                    fname);
                Environment.Exit(-1);
            }
            // Log("MongoDB connection string: " + JSConfig.mongoConnectionString);
            if (
                JSConfig.mongoDatabaseName == "" ||
                JSConfig.mongoDatabaseName == null
                )
            {
                Log("Missing MongoDB database name in JSON config file " +
                    fname);
                Environment.Exit(-1);
            }
            Log("MongoDB database name: " + JSConfig.mongoDatabaseName);
            if (JSConfig.nodeName == "" || JSConfig.nodeName == null)
            {
                Log("Missing nodeName parameter in JSON config file " +
                    fname);
                Environment.Exit(-1);
            }
            Log("Node name: " + JSConfig.nodeName);

            // connect to MongoDB Database server
            var Client = ConnectMongoClient(JSConfig);
            var DB     = Client.GetDatabase(JSConfig.mongoDatabaseName);

            // read and process instances configuration
            var collinsts =
                DB
                .GetCollection
                <protocolDriverInstancesClass
                >(ProtocolDriverInstancesCollectionName);
            var instances =
                collinsts
                .Find(inst =>
                      inst.protocolDriver == ProtocolDriverName &&
                      inst.protocolDriverInstanceNumber ==
                      ProtocolDriverInstanceNumber &&
                      inst.enabled == true)
                .ToList();
            var foundInstance = false;

            foreach (protocolDriverInstancesClass inst in instances)
            {
                if (
                    ProtocolDriverName == inst.protocolDriver &&
                    ProtocolDriverInstanceNumber ==
                    inst.protocolDriverInstanceNumber
                    )
                {
                    foundInstance = true;
                    if (!inst.enabled)
                    {
                        Log("Driver instance [" +
                            ProtocolDriverInstanceNumber.ToString() +
                            "] disabled!");
                        Environment.Exit(-1);
                    }
                    Log("Instance: " +
                        inst.protocolDriverInstanceNumber.ToString());
                    var nodefound = false;
                    foreach (var name in inst.nodeNames)
                    {
                        if (JSConfig.nodeName == name)
                        {
                            nodefound = true;
                        }
                    }
                    if (!nodefound)
                    {
                        Log("Node '" +
                            JSConfig.nodeName +
                            "' not found in instances configuration!");
                        Environment.Exit(-1);
                    }
                    DriverInstance = inst;
                    break;
                }
                break; // process just first result
            }
            if (!foundInstance)
            {
                Log("Driver instance [" +
                    ProtocolDriverInstanceNumber +
                    "] not found in configuration!");
                Environment.Exit(-1);
            }

            // read and process connections configuration for this driver instance
            var collconns =
                DB
                .GetCollection
                <IEC10X_connection>(ProtocolConnectionsCollectionName);
            var conns =
                collconns
                .Find(conn =>
                      conn.protocolDriver == ProtocolDriverName &&
                      conn.protocolDriverInstanceNumber ==
                      ProtocolDriverInstanceNumber &&
                      conn.enabled == true)
                .ToList();

            foreach (IEC10X_connection isrv in conns)
            {
                IEC10Xconns.Add(isrv);
                Log(isrv.name.ToString() + " - New Connection");
            }
            if (IEC10Xconns.Count == 0)
            {
                Log("No connections found!");
                Environment.Exit(-1);
            }

            // start thread to process redundancy control
            Thread thrMongoRedundacy =
                new Thread(() =>
                           ProcessRedundancyMongo(JSConfig));

            thrMongoRedundacy.Start();

            // start thread to update acquired data to database
            Thread thrMongo =
                new Thread(() =>
                           ProcessMongo(JSConfig));

            thrMongo.Start();

            // start thread to watch for commands in the database using a change stream
            Thread thrMongoCmd =
                new Thread(() =>
                           ProcessMongoCmd(JSConfig));

            thrMongoCmd.Start();

            Log("Setting up IEC Connections & ASDU handlers...");
            int cntIecSrv = 0;

            foreach (IEC10X_connection srv in IEC10Xconns)
            {
                TcpClientVirtualSerialPort virtualPort = null;
                SerialPort port = null;
                if (srv.portName.Contains(":"))
                {
                    var hostport = srv.portName.Split(":");
                    virtualPort = new TcpClientVirtualSerialPort(hostport[0], System.Convert.ToInt32(hostport[1]));
                    if (LogLevel >= LogLevelDebug)
                    {
                        virtualPort.DebugOutput = true;
                    }
                    virtualPort.Start();
                }
                else
                {
                    port          = new SerialPort();
                    port.PortName = srv.portName;
                    port.BaudRate = srv.baudRate;
                    switch (srv.parity.ToLower())
                    {
                    default:     // Even is the starndard parity for 101
                    case "even":
                        port.Parity = Parity.Even;
                        break;

                    case "none":
                        port.Parity = Parity.None;
                        break;

                    case "odd":
                        port.Parity = Parity.Odd;
                        break;

                    case "mark":
                        port.Parity = Parity.Mark;
                        break;

                    case "space":
                        port.Parity = Parity.Space;
                        break;
                    }
                    switch (srv.stopBits.ToLower())
                    {
                    default:
                    case "one":
                        port.StopBits = StopBits.One;
                        break;

                    case "one5":
                    case "onepointfive":
                        port.StopBits = StopBits.OnePointFive;
                        break;

                    case "two":
                        port.StopBits = StopBits.Two;
                        break;
                    }
                    switch (srv.handshake.ToLower())
                    {
                    default:
                    case "none":
                        port.Handshake = Handshake.None;
                        break;

                    case "xon":
                    case "xonxoff":
                        port.Handshake = Handshake.XOnXOff;
                        break;

                    case "rts":
                    case "requesttosend":
                        port.Handshake = Handshake.RequestToSend;
                        break;

                    case "rtsxon":
                    case "requesttosendxonxoff":
                        port.Handshake = Handshake.RequestToSendXOnXOff;
                        break;
                    }
                    port.Open();
                    port.DiscardInBuffer();
                }

                LinkLayerParameters llParameters = new LinkLayerParameters();
                llParameters.AddressLength    = srv.sizeOfLinkAddress;
                llParameters.TimeoutForACK    = srv.timeoutForACK;
                llParameters.TimeoutRepeat    = srv.timeoutRepeat;
                llParameters.UseSingleCharACK = srv.useSingleCharACK;

                ApplicationLayerParameters alpars = new ApplicationLayerParameters();
                alpars.SizeOfCOT = srv.sizeOfCOT;
                alpars.SizeOfCA  = srv.sizeOfCA;
                alpars.SizeOfIOA = srv.sizeOfIOA;
                alpars.OA        = srv.localLinkAddress;

                CS101Master master;
                if (port != null)
                {
                    Log("Serial Port: " + srv.portName);
                    master =
                        new CS101Master(port,
                                        LinkLayerMode.UNBALANCED,
                                        llParameters,
                                        alpars);
                }
                else
                {
                    Log("Virtual Serial Port: " + srv.portName);
                    master =
                        new CS101Master(virtualPort,
                                        LinkLayerMode.UNBALANCED,
                                        llParameters,
                                        alpars);
                }
                // master.OwnAddress = srv.localLinkAddress;
                master.SetTimeouts(srv.timeoutMessage, srv.timeoutCharacter);
                master.AddSlave(srv.remoteLinkAddress);
                master.SlaveAddress = srv.remoteLinkAddress;

                srv.master         = master;
                srv.CntGI          = srv.giInterval - 5;
                srv.CntTestCommand = srv.testCommandInterval - 2;
                srv.CntTimeSync    = srv.timeSyncInterval;
                if (LogLevel >= LogLevelDebug)
                {
                    master.DebugOutput = true;
                }
                master.SetASDUReceivedHandler(AsduReceivedHandlerPre, cntIecSrv);
                master.SetLinkLayerStateChangedHandler(linkLayerStateChanged, cntIecSrv);
                master.SetReceivedRawMessageHandler(rcvdRawMessageHandler, cntIecSrv);
                master.Start();

                // create timer to increment counters each second
                srv.TimerCnt          = new System.Timers.Timer();
                srv.TimerCnt.Interval = 1000;
                srv.TimerCnt.Elapsed += (sender, e) => MyElapsedMethod(sender, e, srv);