public void Run() { random = new Random(testConfig.seed); IDNP3Manager mgr = DNP3ManagerFactory.CreateManager(1); channel = mgr.AddTCPClient("client", LogLevels.NONE, ChannelRetry.Default, testConfig.host, testConfig.port); channel.AddStateListener(state => { }); ConfigureOutstation(); Console.WriteLine("[{0}] Starting Value change...", testConfig.seed); while (true) { for (int i = 0; i < testConfig.actionsPerCycle; ++i) { ExecuteSignal(); } Thread.Sleep(testConfig.testTime); var eventRecorder = testConfig.eventRecorder; Console.WriteLine(""); Console.WriteLine( " --- Batch executed: PendingS:" + eventRecorder.GetPending() + " ErrorsS:" + eventRecorder.Errors + " OfS:" + eventRecorder.Total); } }
static void Main(string[] args) { IDNP3Manager mgr = DNP3ManagerFactory.CreateManager(); mgr.AddLogHandler(PrintingLogAdapter.Instance); //this is optional var channel = mgr.AddTCPServer("server", LogLevel.INFO, 5000, "127.0.0.1", 20000); //optionally, add a listener for the channel state channel.AddStateListener(state => Console.WriteLine("Server state: " + state)); var config = new SlaveStackConfig(); var outstation = channel.AddOutstation("outstation", LogLevel.INFO, RejectingCommandHandler.Instance, config); //optionally, add a listener for the stack state outstation.AddStateListener(state => Console.WriteLine("Outstation state: " + state)); Console.WriteLine("Press <Enter> to randomly change a value"); var publisher = outstation.GetDataObserver(); Random r = new Random(); while (true) { Console.ReadLine(); int value = r.Next(UInt16.MaxValue); System.Console.WriteLine("Change Analog 0 to: " + value); publisher.Start(); publisher.Update(new Analog(value, 1, DateTime.Now), 0); publisher.End(); } }
static void Main(string[] args) { IDNP3Manager mgr = DNP3ManagerFactory.CreateManager(); mgr.AddLogHandler(PrintingLogAdapter.Instance); //this is optional var channel = mgr.AddTCPClient("client", LogLevel.INFO, 5000, "127.0.0.1", 20000); //optionally, add a listener for the channel state channel.AddStateListener(state => Console.WriteLine("Client state: " + state)); var config = new MasterStackConfig(); config.link.useConfirms = true; //setup your stack configuration here. var master = channel.AddMaster("master", LogLevel.INFO, PrintingDataObserver.Instance, config); //optionally, add a listener for the stack state master.AddStateListener(state => Console.WriteLine("Master state: " + state)); Console.WriteLine("Enter an index to send a command"); while (true) { System.UInt32 index = System.UInt32.Parse(Console.ReadLine()); var future = master.GetCommandProcessor().SelectAndOperate(new ControlRelayOutputBlock(ControlCode.CC_PULSE, 1, 100, 100), index); CommandStatus result = future.Await(); Console.WriteLine("Result: " + result); } }
static int Main(string[] args) { IDNP3Manager mgr = DNP3ManagerFactory.CreateManager(1, new PrintingLogAdapter()); //一個管理者 var channel = mgr.AddTCPServer("server", LogLevels.NORMAL, ServerAcceptMode.CloseExisting, new IPEndpoint("127.0.0.1", 20000), ChannelListener.Print()); //創造一個Channel var config = new OutstationStackConfig(); // configure the various measurements in our database 創造資料量測點 config.databaseTemplate.binary.Add(3, new BinaryConfig()); config.databaseTemplate.binary.Add(7, new BinaryConfig()); config.databaseTemplate.analog.Add(0, new AnalogConfig()); // .... 允許自動送資料 config.outstation.config.allowUnsolicited = true; // Optional: setup your stack configuration here設定本地地址,遠端地址 config.link.localAddr = 10; // outstation ip config.link.remoteAddr = 1; //master addr var outstation = channel.AddOutstation("outstation", RejectingCommandHandler.Instance, DefaultOutstationApplication.Instance, config); //把設定檔丟到Channel物件裡面 outstation.Enable(); // enable communications Console.WriteLine("Press <Enter> to change a value"); //要放進去暫存器的數值 bool binaryValue = false; double analogValue = 0; while (true) { //按下 Enter 會改變二元值 跟增加類比數值 switch (Console.ReadLine()) { case ("x"): return(0); default: { binaryValue = !binaryValue; ++analogValue; // create a changeset and load it var changeset = new ChangeSet(); var binaryFlags = new Flags(); binaryFlags.Set(BinaryQuality.ONLINE); var analogFlags = new Flags(); analogFlags.Set(AnalogQuality.ONLINE); //更新暫存器的數值 changeset.Update(new Binary(binaryValue, binaryFlags, new DNPTime(DateTime.UtcNow)), 3); changeset.Update(new Analog(analogValue, analogFlags, DNPTime.Now), 0); outstation.Load(changeset); } break; } } }
static int Main(string[] args) { IDNP3Manager mgr = DNP3ManagerFactory.CreateManager(1, new PrintingLogAdapter()); var channel = mgr.AddTCPServer("server", LogLevels.NORMAL, ChannelRetry.Default, "0.0.0.0", 20000); // Optional: add a listener for the channel state channel.AddStateListener(state => Console.WriteLine("channel state: " + state)); var config = new OutstationStackConfig(); // configure the various measurements in our database config.databaseTemplate = new DatabaseTemplate(4, 1, 1, 1, 1, 1, 1, 0); config.databaseTemplate.binaries[0].clazz = PointClass.Class2; // .... config.outstation.config.allowUnsolicited = true; // Optional: setup your stack configuration here config.link.localAddr = 10; config.link.remoteAddr = 1; var outstation = channel.AddOutstation("outstation", RejectingCommandHandler.Instance, DefaultOutstationApplication.Instance, config); outstation.Enable(); // enable communications Console.WriteLine("Press <Enter> to change a value"); bool binaryValue = false; double analogValue = 0; while (true) { switch (Console.ReadLine()) { case ("x"): return(0); default: { binaryValue = !binaryValue; ++analogValue; System.Console.WriteLine("Change Binary 0 to: " + binaryValue); System.Console.WriteLine("Change Analog 9 to: " + analogValue); // create a changeset and load it var changeset = new ChangeSet(); changeset.Update(new Binary(binaryValue, 1, DateTime.Now), 0); changeset.Update(new Analog(analogValue, 1, DateTime.Now), 0); outstation.Load(changeset); } break; } } }
public DNP3SimulatorPlugin(ILog log) { this.logHandler = new ForwardingLogHandler(log); this.manager = DNP3ManagerFactory.CreateManager(this.logHandler); imgList.Images.Add(Properties.Resources.satellite_dish); imgList.Images.Add(Properties.Resources.network_monitor); imgList.Images.Add(Properties.Resources.send_container); /* * Load outstation plugins here */ }
public DNP3SimulatorPlugin(ILog log) { this.logHandler = new ForwardingLogHandler(log); this.manager = DNP3ManagerFactory.CreateManager(this.logHandler); imgList.Images.Add(Properties.Resources.satellite_dish); imgList.Images.Add(Properties.Resources.network_monitor); imgList.Images.Add(Properties.Resources.send_container); /* Load outstation plugins here */ }
static void Main(string[] args) { IDNP3Manager mgr = DNP3ManagerFactory.CreateManager(); mgr.AddLogHandler(PrintingLogAdapter.Instance); //this is optional var channel = mgr.AddTCPServer("server", LogLevels.NORMAL, TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(5), "0.0.0.0", 20000); // Optional: add a listener for the channel state channel.AddStateListener(state => Console.WriteLine("channel state: " + state)); var config = new OutstationStackConfig(); // configure the various measurements in our database config.databaseTemplate = new DatabaseTemplate(4, 1, 1, 1, 1, 1, 1); config.databaseTemplate.binaries[0].pointClass = PointClass.Class2; // .... // Optional: overide the default reporting variations config.outstation.eventConfig.binary = EventBinaryResponse.Group2Var2; config.outstation.staticConfig.analog = StaticAnalogResponse.Group30Var5; // Optional: setup your stack configuration here config.link.localAddr = 10; config.link.remoteAddr = 1; var outstation = channel.AddOutstation("outstation", RejectingCommandHandler.Instance, DefaultOutstationApplication.Instance, config); outstation.Enable(); // enable communications Console.WriteLine("Press <Enter> to randomly change a value"); var database = outstation.GetDatabase(); bool value = false; while (true) { Console.ReadLine(); value = !value; System.Console.WriteLine("Change Binary 1 to: " + value); database.Start(); database.Update(new Binary(value, 1, DateTime.Now), 0); database.End(); } }
public static void InitDeviceConnection(CIMData.SCADAInfo scadaDev) { IDNP3Manager mgr = DNP3ManagerFactory.CreateManager(1); //mgr.AddLogHandler(PrintingLogAdapter.Instance); //this is optional UInt16 sport = Convert.ToUInt16(scadaDev.Dnp.Port); scadaDev.Channel = mgr.AddTCPClient(scadaDev.Name, LogLevels.ALL, ChannelRetry.Default, scadaDev.Dnp.IPAddress, sport); //optionally, add a listener for the channel state scadaDev.Channel.AddStateListener(state => Console.WriteLine("channel state: " + state + " for dev: " + scadaDev.Name + " addr: " + scadaDev.Dnp.IPAddress)); var config = new MasterStackConfig(); //setup your stack configuration here. UInt16 laddr = Convert.ToUInt16(scadaDev.Dnp.LocalAddress); UInt16 raddr = Convert.ToUInt16(scadaDev.Dnp.RemoteAddress); config.link.localAddr = laddr; config.link.remoteAddr = raddr; var key = new byte[16]; for (int i = 0; i < key.Length; ++i) { key[i] = 0xFF; } HandleSOEData hse = new HandleSOEData(scadaDev); scadaDev.Master = scadaDev.Channel.AddMaster("master", hse.getInstance(), DefaultMasterApplication.Instance, config); // you a can optionally add various kinds of polls var integrityPoll = scadaDev.Master.AddClassScan(ClassField.AllClasses, TimeSpan.FromMinutes(1), TaskConfig.Default); scadaDev.Master.Enable(); scadaDev.Connected = true; }
// Static Constructor static DNP3InputAdapter() { s_adapters = new List <DNP3InputAdapter>(); s_manager = DNP3ManagerFactory.CreateManager(Environment.ProcessorCount); s_manager.AddLogHandler(new IaonProxyLogHandler()); }
static int Main(string[] args) { IDNP3Manager mgr = DNP3ManagerFactory.CreateManager(1, PrintingLogAdapter.Instance); var channel = mgr.AddTCPClient("client", LogLevels.ALL, ChannelRetry.Default, "127.0.0.1", 20000); //optionally, add a listener for the channel state channel.AddStateListener(state => Console.WriteLine("channel state: " + state)); var config = new MasterStackConfig(); //setup your stack configuration here. config.link.localAddr = 1; config.link.remoteAddr = 10; var key = new byte[16]; for (int i = 0; i < key.Length; ++i) { key[i] = 0xFF; } var master = channel.AddMaster("master", PrintingSOEHandler.Instance, DefaultMasterApplication.Instance, config); // you a can optionally add various kinds of polls var integrityPoll = master.AddClassScan(ClassField.AllClasses, TimeSpan.FromMinutes(1), TaskConfig.Default); var rangePoll = master.AddRangeScan(30, 2, 5, 7, TimeSpan.FromSeconds(20), TaskConfig.Default); var classPoll = master.AddClassScan(ClassField.AllEventClasses, TimeSpan.FromSeconds(5), TaskConfig.Default); /* you can also do very custom scans * var headers = new Header[] { Header.Range8(1, 2, 7, 8), Header.Count8(2, 3, 7) }; * var weirdPoll = master.AddScan(headers, TimeSpan.FromSeconds(20)); */ master.Enable(); // enable communications Console.WriteLine("Enter a command"); while (true) { switch (Console.ReadLine()) { case "a": // perform an ad-hoc scan of all analogs master.ScanAllObjects(30, 0, TaskConfig.Default); break; case "c": var task = master.SelectAndOperate(GetCommandHeaders(), TaskConfig.Default); task.ContinueWith((result) => Console.WriteLine("Result: " + result.Result)); break; case "o": var crob = new ControlRelayOutputBlock(ControlCode.PULSE_ON, 1, 100, 100); var single = master.SelectAndOperate(crob, 1, TaskConfig.Default); single.ContinueWith((result) => Console.WriteLine("Result: " + result.Result)); break; case "l": // add interpretation to the current logging level var filters = channel.GetLogFilters(); channel.SetLogFilters(filters.Add(LogFilters.TRANSPORT_TX | LogFilters.TRANSPORT_RX)); break; case "i": integrityPoll.Demand(); break; case "r": rangePoll.Demand(); break; case "e": classPoll.Demand(); break; case "x": return(0); default: break; } } }
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..."); }
static int Main(string[] args) { var application = new MasterApplicatonSA(); IDNP3Manager mgr = DNP3ManagerFactory.CreateManager(); Console.WriteLine(String.Format("Crypto: {0}", mgr.SSLVersion())); mgr.AddLogHandler(PrintingLogAdapter.Instance); //this is optional var channel = mgr.AddTCPClient("client", LogLevels.NORMAL, ChannelRetry.Default, "127.0.0.1", 20000); //optionally, add a listener for the channel state channel.AddStateListener(state => Console.WriteLine("channel state: " + state)); var config = new MasterStackConfig(); //setup your stack configuration here. config.link.localAddr = 1; config.link.remoteAddr = 10; var master = channel.AddMasterSA("master", PrintingSOEHandler.Instance, application, config); // define users on the master master.AddUser(User.Default, UpdateKey.Demo(0xFF, KeyWrapAlgorithm.AES_128)); // you a can optionally add various kinds of polls var integrityPoll = master.AddClassScan(ClassField.AllClasses, TimeSpan.FromMinutes(1), TaskConfig.Default); var rangePoll = master.AddRangeScan(30, 2, 5, 7, TimeSpan.FromSeconds(20), TaskConfig.Default); var classPoll = master.AddClassScan(ClassField.AllEventClasses, TimeSpan.FromSeconds(5), TaskConfig.Default); /* you can also do very custom scans * var headers = new Header[] { Header.Range8(1, 2, 7, 8), Header.Count8(2, 3, 7) }; * var weirdPoll = master.AddScan(headers, TimeSpan.FromSeconds(20)); */ master.Enable(); // enable communications Console.WriteLine("Enter a command"); while (true) { switch (Console.ReadLine()) { case "a": // perform an ad-hoc scan of all analogs master.ScanAllObjects(30, 0, TaskConfig.Default); break; case "c": var crob = new ControlRelayOutputBlock(ControlCode.PULSE_ON, 1, 100, 100); var commands = CommandHeader.From(IndexedValue.From(crob, 0)); var task = master.SelectAndOperate(commands, TaskConfig.With(User.Default)); task.ContinueWith((result) => Console.WriteLine("Result: " + result.Result)); break; case "l": // add interpretation to the current logging level var filters = channel.GetLogFilters(); channel.SetLogFilters(filters.Add(LogFilters.TRANSPORT_TX | LogFilters.TRANSPORT_RX)); break; case "i": integrityPoll.Demand(); break; case "r": rangePoll.Demand(); break; case "e": classPoll.Demand(); break; case "x": return(0); default: break; } } }
public Manager(IDNP3Manager DNP3Manager) { this.DNP3Manager = DNP3Manager; TulipContext = new TulipEntities(); //this.Channels = new List<ChannelWrapper>(); }
static int Main(string[] args) { IDNP3Manager mgr = DNP3ManagerFactory.CreateManager(); mgr.AddLogHandler(PrintingLogAdapter.Instance); //this is optional var channel = mgr.AddTCPClient("client", LogLevels.NORMAL, TimeSpan.FromSeconds(5), TimeSpan.FromMinutes(2), "127.0.0.1", 20000); //optionally, add a listener for the channel state channel.AddStateListener(state => Console.WriteLine("channel state: " + state)); var config = new MasterStackConfig(); //setup your stack configuration here. config.link.localAddr = 1; config.link.remoteAddr = 10; var master = channel.AddMaster("master", PrintingSOEHandler.Instance, DefaultMasterApplication.Instance, config); // you a can optionally add various kinds of polls var integrityPoll = master.AddClassScan(ClassField.AllClasses, TimeSpan.FromMinutes(1)); var rangePoll = master.AddRangeScan(30, 2, 5, 7, TimeSpan.FromSeconds(20)); var classPoll = master.AddClassScan(ClassField.AllEventClasses, TimeSpan.FromSeconds(5)); // you a can optionally add state callbacks for monitoring these polls integrityPoll.AddScanCallback((PollState state) => Console.WriteLine("integrity poll state change: " + state)); classPoll.AddScanCallback((PollState state) => Console.WriteLine("class poll state change: " + state)); rangePoll.AddScanCallback((PollState state) => Console.WriteLine("range poll state change: " + state)); master.Enable(); // enable communications Console.WriteLine("Enter an index to send a command"); while (true) { switch (Console.ReadLine()) { case "c": var crob = new ControlRelayOutputBlock(ControlCode.PULSE, 1, 100, 100); var future = master.GetCommandProcessor().SelectAndOperate(crob, 0); future.Listen((result) => Console.WriteLine("Result: " + result)); break; case "l": // add interpretation to the current logging level var filters = channel.GetLogFilters(); channel.SetLogFilters(filters.Add(LogFilters.TRANSPORT_TX | LogFilters.TRANSPORT_RX)); break; case "i": integrityPoll.Demand(); break; case "r": rangePoll.Demand(); break; case "e": classPoll.Demand(); break; case "x": return(0); default: break; } } }
public DNP3Connector(ushort concurrency) { manager = DNP3ManagerFactory.CreateManager(concurrency); }