Ejemplo n.º 1
0
        public static void Main(string[] args)
        {
            string hostname = "127.0.0.1";

            if (args.Length > 0)
            {
                hostname = args[0];

                Console.WriteLine("Using hostname: " + hostname);
            }


            Console.WriteLine("Using lib60870.NET version " + LibraryCommon.GetLibraryVersionString());

            // Own certificate has to be a pfx file that contains the private key
            X509Certificate2 ownCertificate = new X509Certificate2("client1.pfx");

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

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

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

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

            // Check that the shown server certificate is in the list of allowed certificates
            secInfo.AllowOnlySpecificCertificates = true;

            Connection con = new Connection(hostname);

            // Set security information object, this will force the connection using TLS (using TCP port 19998)
            con.SetTlsSecurity(secInfo);

            con.DebugOutput = true;

            con.SetASDUReceivedHandler(asduReceivedHandler, null);
            con.SetConnectionHandler(ConnectionHandler, null);

            con.Connect();

            Thread.Sleep(5000);

            con.SendTestCommand(1);

            con.SendInterrogationCommand(CauseOfTransmission.ACTIVATION, 1, QualifierOfInterrogation.STATION);

            Thread.Sleep(5000);

            con.SendControlCommand(CauseOfTransmission.ACTIVATION, 1, new SingleCommand(5000, true, false, 0));

            con.SendControlCommand(CauseOfTransmission.ACTIVATION, 1, new DoubleCommand(5001, DoubleCommand.ON, false, 0));

            con.SendControlCommand(CauseOfTransmission.ACTIVATION, 1, new StepCommand(5002, StepCommandValue.HIGHER, false, 0));

            con.SendControlCommand(CauseOfTransmission.ACTIVATION, 1,
                                   new SingleCommandWithCP56Time2a(5000, false, false, 0, new CP56Time2a(DateTime.Now)));

            /* Synchronize clock of the controlled station */
            con.SendClockSyncCommand(1 /* CA */, new CP56Time2a(DateTime.Now));


            Console.WriteLine("CLOSE");

            con.Close();

            Console.WriteLine("RECONNECT");

            con.Connect();

            Thread.Sleep(5000);


            Console.WriteLine("CLOSE 2");

            con.Close();

            Console.WriteLine("Press any key to terminate...");
            Console.ReadKey();
        }
Ejemplo n.º 2
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);
Ejemplo n.º 3
0
        public static void Main(string[] args)
        {
            bool running = true;

            Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e) {
                e.Cancel = true;
                running  = false;
            };

            // Own certificate has to be a pfx file that contains the private key
            X509Certificate2 ownCertificate = new X509Certificate2("server.pfx");

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

            // Add allowed client certificates - not required when AllowOnlySpecificCertificates == false
            secInfo.AddAllowedCertificate(new X509Certificate2("client1.cer"));
            secInfo.AddAllowedCertificate(new X509Certificate2("client2.cer"));

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

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

            // Check that the shown client certificate is in the list of allowed certificates
            secInfo.AllowOnlySpecificCertificates = true;

            // Use constructor with security information object, this will force the connection using TLS (using TCP port 19998)
            Server server = new Server(secInfo);

            server.DebugOutput = true;

            server.MaxQueueSize = 10;

            server.SetInterrogationHandler(interrogationHandler, null);

            server.SetASDUHandler(asduHandler, null);

            server.Start();

            ASDU newAsdu            = new ASDU(server.GetConnectionParameters(), CauseOfTransmission.INITIALIZED, false, false, 0, 1, false);
            EndOfInitialization eoi = new EndOfInitialization(0);

            newAsdu.AddInformationObject(eoi);
            server.EnqueueASDU(newAsdu);

            int waitTime = 1000;

            while (running)
            {
                Thread.Sleep(100);

                if (waitTime > 0)
                {
                    waitTime -= 100;
                }
                else
                {
                    newAsdu = new ASDU(server.GetConnectionParameters(), CauseOfTransmission.PERIODIC, false, false, 2, 1, false);

                    newAsdu.AddInformationObject(new MeasuredValueScaled(110, -1, new QualityDescriptor()));

                    server.EnqueueASDU(newAsdu);

                    waitTime = 1000;
                }
            }

            Console.WriteLine("Stop server");
            server.Stop();;
        }
Ejemplo n.º 4
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;

                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, srv.passphrase, X509KeyStorageFlags.MachineKeySet);

                        // 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));
                        foreach (string peerCertFilePath in srv.peerCertFilesPaths)
                        {
                            secInfo.AddAllowedCertificate(new X509Certificate2(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 certificates.");
                        Log(srv.name + " - " + e.Message);
                        Environment.Exit(1);
                    }
                }

                var server = new Server(apcipars, alpars, secInfo);
                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));
        }