private void OnAnalogAddedEvent(object sender, EventArgs e) { Console.WriteLine("OnAnalogEventAdded started"); Analog analog = (Analog)e; IORequestBlock iorb = new IORequestBlock() { RequestType = RequestType.SEND, ProcessControllerName = analog.ProcContrName }; DBContext dbContext = new DBContext(); RTU rtu; if ((rtu = dbContext.GetRTUByName(analog.ProcContrName)) != null) { iorb.ReqAddress = (ushort)rtu.GetCommandAddress(analog); bool shouldCommand = false; switch (rtu.Protocol) { case IndustryProtocols.ModbusTCP: ModbusHandler mdbHandler = new ModbusHandler(); mdbHandler.Header = new ModbusApplicationHeader() { TransactionId = 0, Length = 5, ProtocolId = (ushort)IndustryProtocols.ModbusTCP, DeviceAddress = rtu.Address }; mdbHandler.Request = new WriteRequest() { StartAddr = (ushort)rtu.GetCommandAddress(analog) }; if (shouldCommand = AnalogProcessor.InitialWorkPointAnalog(analog)) { mdbHandler.Request.FunCode = FunctionCodes.WriteSingleRegister; AnalogProcessor.EGUToRawValue(analog); ((WriteRequest)mdbHandler.Request).Value = analog.RawCommValue; iorb.SendBuff = mdbHandler.PackData(); iorb.SendMsgLength = iorb.SendBuff.Length; Console.WriteLine(BitConverter.ToString(iorb.SendBuff, 0, 12)); IORequests.EnqueueRequest(iorb); analog.IsInit = true; } break; } } Console.WriteLine("OnAnalogEventAdded finished"); }
// napravila, ali nisam testirala do kraja, to je nekad za buducnost, svakako ne treba sad :) public OMSSCADACommon.Responses.Response WriteSingleAnalog(string id, float value) { Console.WriteLine("WriteSingleAnalog!"); Analog analog = null; OMSSCADACommon.Responses.Response response = new OMSSCADACommon.Responses.Response(); // to do: //while (!Database.IsConfigurationRunning) // getting PV from db ProcessVariable pv; if (dbContext.GetProcessVariableByName(id, out pv)) { analog = (Analog)pv; } // does this ID exist in the database if (analog == null) { response.ResultMessage = ResultMessage.INVALID_ID; return(response); } // to do: // ovde analogProcessor provera opsega, alarma...bla, bla RTU rtu; if ((rtu = dbContext.GetRTUByName(analog.ProcContrName)) != null) { IORequestBlock iorb = new IORequestBlock() { RequestType = RequestType.SEND, ProcessControllerName = analog.ProcContrName }; iorb.ReqAddress = (ushort)rtu.GetCommandAddress(analog); bool shouldCommand = false; switch (rtu.Protocol) { case IndustryProtocols.ModbusTCP: ModbusHandler mdbHandler = new ModbusHandler { Header = new ModbusApplicationHeader() { TransactionId = 0, Length = 5, ProtocolId = (ushort)IndustryProtocols.ModbusTCP, DeviceAddress = rtu.Address }, Request = new WriteRequest() { FunCode = FunctionCodes.WriteSingleCoil, StartAddr = (ushort)rtu.GetCommandAddress(analog) } }; if (shouldCommand = AnalogProcessor.SetNewWorkPoint(analog, value)) { mdbHandler.Request.FunCode = FunctionCodes.WriteSingleRegister; ((WriteRequest)mdbHandler.Request).Value = (ushort)analog.RawCommValue; } iorb.SendBuff = mdbHandler.PackData(); iorb.SendMsgLength = iorb.SendBuff.Length; break; } IORequests.EnqueueRequest(iorb); Console.WriteLine("enqued {0}", BitConverter.ToString(iorb.SendBuff, 0, 12)); response.ResultMessage = ResultMessage.OK; } else { // rtu does not exist } return(response); }
/// <summary> /// Send Commands to simulator, to make its state consistent with RTDB /// </summary> public void InitializeSimulator() { // ovo probati sa taskovima, za svaki od rtu-ova. ipak ne, jer nekim promenljivim komandujes, nekim ne // var rtus = dbContext.GettAllRTUs(); //Parallel.ForEach(rtus, (currentRtu, state) => //{ // Console.WriteLine("InitSim Parallel.foreach RTU name = {0}, Therad id = {1} started", currentRtu.Key, Thread.CurrentThread.ManagedThreadId); // IIndustryProtocolHandler IProtHandler = null; // RTU rtu = dbContext.GetRTUByName(currentRtu.Key); // if (currentRtu.Value != null) // { // IORequestBlock iorb = new IORequestBlock() // { // RequestType = RequestType.SEND, // ProcessControllerName = currentRtu.Key // }; // switch (rtu.Protocol) // { // case IndustryProtocols.ModbusTCP: // IProtHandler = new ModbusHandler() // { // Header = new ModbusApplicationHeader // { // TransactionId = 0, // ProtocolId = (ushort)IndustryProtocols.ModbusTCP, // DeviceAddress = rtu.Address, // Length = 5 // }, // Request = new WriteRequest() // }; // break; // } // //to do. praviti nove iorbove // // za svaku varijablu trebas imati should command ili ne i u zavisnosti od toga puniti data, racunati length zahtvea i ostalo // //-------------analogs--------------- // var analogs = dbContext.GetProcessVariable().Where(pv => pv.Type == VariableTypes.ANALOG && pv.IsInit == false && // pv.ProcContrName.Equals(currentRtu.Key)).OrderBy(pv => pv.RelativeAddress); // int requestCount = analogs.ToList().Count(); // if (requestCount != 0) // { // ProcessVariable firstPV = analogs.FirstOrDefault(); // iorb.ReqAddress = (ushort)rtu.GetAcqAddress(firstPV); // if (IProtHandler != null) // { // switch (rtu.Protocol) // { // case IndustryProtocols.ModbusTCP: // for(int i = 0; i < requestCount; i++) // { // } // ((ReadRequest)((ModbusHandler)IProtHandler).Request).FunCode = FunctionCodes.ReadInputRegisters; // ((ReadRequest)((ModbusHandler)IProtHandler).Request).Quantity = (ushort)requestCount; // ((ReadRequest)((ModbusHandler)IProtHandler).Request).StartAddr = iorb.ReqAddress; // break; // } // iorb.Flags = requestCount; // iorb.SendBuff = IProtHandler.PackData(); // iorb.SendMsgLength = iorb.SendBuff.Length; // IORequests.EnqueueRequest(iorb); // } // } // //-------------digitals---------------(to do: add init flag...) // var digitals = dbContext.GetProcessVariable().Where(pv => pv.Type == VariableTypes.DIGITAL && // pv.ProcContrName.Equals(currentRtu.Key)).OrderBy(pv => pv.RelativeAddress); // requestCount = digitals.ToList().Count(); // if (requestCount != 0) // { // ProcessVariable firstPV = digitals.FirstOrDefault(); // iorb.ReqAddress = (ushort)rtu.GetAcqAddress(firstPV); // if (IProtHandler != null) // { // switch (rtu.Protocol) // { // case IndustryProtocols.ModbusTCP: // ((ReadRequest)((ModbusHandler)IProtHandler).Request).FunCode = FunctionCodes.ReadDiscreteInput; // ((ReadRequest)((ModbusHandler)IProtHandler).Request).Quantity = (ushort)requestCount; // ((ReadRequest)((ModbusHandler)IProtHandler).Request).StartAddr = iorb.ReqAddress; // break; // } // iorb.Flags = requestCount; // iorb.SendBuff = IProtHandler.PackData(); // iorb.SendMsgLength = iorb.SendBuff.Length; // IORequests.EnqueueRequest(iorb); // } // } // } //}); List <ProcessVariable> pvs = dbContext.GetProcessVariable().ToList(); if (pvs.Count != 0) { foreach (ProcessVariable pv in pvs) { IORequestBlock iorb = new IORequestBlock() { RequestType = RequestType.SEND, ProcessControllerName = pv.ProcContrName }; RTU rtu; if ((rtu = dbContext.GetRTUByName(pv.ProcContrName)) != null) { iorb.ReqAddress = (ushort)rtu.GetCommandAddress(pv); bool shouldCommand = false; switch (rtu.Protocol) { case IndustryProtocols.ModbusTCP: ModbusHandler mdbHandler = new ModbusHandler(); mdbHandler.Header = new ModbusApplicationHeader() { TransactionId = 0, Length = 5, ProtocolId = (ushort)IndustryProtocols.ModbusTCP, DeviceAddress = rtu.Address }; mdbHandler.Request = new WriteRequest() { StartAddr = (ushort)rtu.GetCommandAddress(pv) }; switch (pv.Type) { // initialy, on simulator all digitals are set to 0 -> closed state case VariableTypes.DIGITAL: Digital digital = (Digital)pv; CommandTypes comm; if (shouldCommand = CommandValidator.InitialCommandingForDigital(digital, out comm)) { mdbHandler.Request.FunCode = FunctionCodes.WriteSingleCoil; ((WriteRequest)mdbHandler.Request).Value = (ushort)comm; } break; case VariableTypes.ANALOG: Analog analog = (Analog)pv; if (shouldCommand = AnalogProcessor.InitialWorkPointAnalog(analog)) { mdbHandler.Request.FunCode = FunctionCodes.WriteSingleRegister; ((WriteRequest)mdbHandler.Request).Value = (ushort)analog.RawCommValue; } analog.IsInit = true; break; case VariableTypes.COUNTER: Counter counter = (Counter)pv; break; } if (shouldCommand) { iorb.SendBuff = mdbHandler.PackData(); iorb.SendMsgLength = iorb.SendBuff.Length; //if (pv.Name == "MEAS_AN_1") // Console.WriteLine(BitConverter.ToString(iorb.SendBuff, 0, 12)); } break; } if (shouldCommand) { IORequests.EnqueueRequest(iorb); } } else { // izbrisati omdah te procesne varijable sa rtu-om tog imena? Console.WriteLine("Invalid config: ProcContrName = {0} does not exists.", pv.ProcContrName); continue; } } } }
/// <summary> /// Processing answers from Simulator - Process Controller /// </summary> public void ProcessPCAnwers(TimeSpan timeout, CancellationToken token) { while (!token.IsCancellationRequested) { bool isSuccessful; IORequestBlock answer = IORequests.DequeueAnswer(out isSuccessful, timeout); if (isSuccessful) { bool isChange = false; RTU rtu; // sporno //while (!Database.IsConfigurationRunning) if ((rtu = dbContext.GetRTUByName(answer.ProcessControllerName)) != null) { switch (rtu.Protocol) { case IndustryProtocols.ModbusTCP: ModbusHandler mdbHandler = new ModbusHandler(); try { mdbHandler.UnpackData(answer.RcvBuff, answer.RcvMsgLength); switch (mdbHandler.Response.FunCode) { case FunctionCodes.ReadDiscreteInput: { BitReadResponse response = (BitReadResponse)mdbHandler.Response; var responsePVCount = answer.Flags; ushort varAddr = answer.ReqAddress; for (int i = 0; i < responsePVCount; i++, varAddr++) { ProcessVariable pv; if (rtu.GetProcessVariableByAddress(varAddr, out pv)) { Digital target = (Digital)pv; try { bool isOpened = response.BitValues[i]; if (target.State != target.ValidStates[isOpened ? 1 : 0]) { isChange = true; target.State = target.ValidStates[isOpened ? 1 : 0]; Console.WriteLine(" CHANGE! Digital variable {0}, state: {1}", target.Name, target.State); DMSClient dMSClient = new DMSClient(); dMSClient.ChangeOnSCADADigital(target.Name, target.State); } } catch { Console.WriteLine("Digital variable {0}, state: INVALID", target.Name); } } } if (isChange) { ScadaModelParser parser = new ScadaModelParser(); parser.SerializeScadaModel(); } } break; // analog input case FunctionCodes.ReadInputRegisters: { RegisterReadResponse response = (RegisterReadResponse)mdbHandler.Response; var responsePVCount = answer.Flags; ushort varAddr = answer.ReqAddress; for (int i = 0; i < responsePVCount; i++, varAddr++) { ProcessVariable pv; if (rtu.GetProcessVariableByAddress(varAddr, out pv)) { Analog target = (Analog)pv; try { ushort newRawAcqValue = response.RegValues[target.RelativeAddress]; float newAcqValue; AnalogProcessor.RawValueToEGU(target, newRawAcqValue, out newAcqValue); if (target.AcqValue != newAcqValue) { isChange = true; target.RawAcqValue = newRawAcqValue; target.AcqValue = newAcqValue; Console.WriteLine(" CHANGE! Analog variable {0}, AcqValue: {1}", target.Name, target.AcqValue); //to do: propagacija analogih promena(ako se secate Pavlica je prvo rekao da nam to ne treba da samo jednom zakucamo vrednost na pocetku) xD DMSClient dMSClient = new DMSClient(); dMSClient.ChangeOnSCADAAnalog(target.Name, target.AcqValue); } } catch { // Console.WriteLine("Digital variable {0}, state: INVALID", target.Name); } } } if (isChange) { ScadaModelParser parser = new ScadaModelParser(); parser.SerializeScadaModel(); } } break; } } catch (Exception e) { Console.WriteLine(e.Message); } break; } } } } Console.WriteLine("ProcessPCAnswers.shutdown=true"); return; }
public bool DeserializeScadaModel(string deserializationSource = "ScadaModel.xml") { // to do Database.IsConfigurationFinished = false; string message = string.Empty; string configurationName = deserializationSource; string source = Path.Combine(basePath, configurationName); if (Database.Instance.RTUs.Count != 0) { Database.Instance.RTUs.Clear(); } if (Database.Instance.ProcessVariablesName.Count != 0) { Database.Instance.ProcessVariablesName.Clear(); } try { XElement xdocument = XElement.Load(source); // access RTUS, DIGITALS, ANALOGS, COUNTERS from ScadaModel root IEnumerable <XElement> elements = xdocument.Elements(); var rtus = xdocument.Element("RTUS").Elements("RTU").ToList(); var digitals = (from dig in xdocument.Element("Digitals").Elements("Digital") orderby(int) dig.Element("RelativeAddress") select dig).ToList(); var analogs = (from dig in xdocument.Element("Analogs").Elements("Analog") orderby(int) dig.Element("RelativeAddress") select dig).ToList(); var counters = (from dig in xdocument.Element("Counters").Elements("Counter") orderby(int) dig.Element("RelativeAddress") select dig).ToList(); // parsing RTUS if (rtus.Count != 0) { foreach (var rtu in rtus) { RTU newRtu; string uniqueName = (string)rtu.Element("Name"); // if RTU with that name does not already exist? if (!dbContext.Database.RTUs.ContainsKey(uniqueName)) { byte address = (byte)(int)rtu.Element("Address"); bool freeSpaceForDigitals = (bool)rtu.Element("FreeSpaceForDigitals"); bool freeSpaceForAnalogs = (bool)rtu.Element("FreeSpaceForAnalogs"); string stringProtocol = (string)rtu.Element("Protocol"); IndustryProtocols protocol = (IndustryProtocols)Enum.Parse(typeof(IndustryProtocols), stringProtocol); int digOutStartAddr = (int)rtu.Element("DigOutStartAddr"); int digInStartAddr = (int)rtu.Element("DigInStartAddr"); int anaInStartAddr = (int)rtu.Element("AnaInStartAddr"); int anaOutStartAddr = (int)rtu.Element("AnaOutStartAddr"); int counterStartAddr = (int)rtu.Element("CounterStartAddr"); int digOutCount = (int)rtu.Element("NoDigOut"); int digInCount = (int)rtu.Element("NoDigIn"); int anaInCount = (int)rtu.Element("NoAnaIn"); int anaOutCount = (int)rtu.Element("NoAnaOut"); int counterCount = (int)rtu.Element("NoCnt"); ushort anaInRawMin = (ushort)(int)rtu.Element("AnaInRawMin"); ushort anaInRawMax = (ushort)(int)rtu.Element("AnaInRawMax"); ushort anaOutRawMin = (ushort)(int)rtu.Element("AnaOutRawMin"); ushort anaOutRawMax = (ushort)(int)rtu.Element("AnaOutRawMax"); if (digOutCount != digInCount) { message = string.Format("Invalid config: RTU - {0}: Value of DigOutCount must be the same as Value of DigInCount", uniqueName); Console.WriteLine(message); return(false); } newRtu = new RTU() { Name = uniqueName, Address = address, FreeSpaceForDigitals = freeSpaceForDigitals, FreeSpaceForAnalogs = freeSpaceForAnalogs, Protocol = protocol, DigOutStartAddr = digOutStartAddr, DigInStartAddr = digInStartAddr, AnaInStartAddr = anaInStartAddr, AnaOutStartAddr = anaOutStartAddr, CounterStartAddr = counterStartAddr, NoDigOut = digOutCount, NoDigIn = digInCount, NoAnaIn = anaInCount, NoAnaOut = anaOutCount, NoCnt = counterCount, AnaInRawMin = anaInRawMin, AnaInRawMax = anaInRawMax, AnaOutRawMin = anaOutRawMin, AnaOutRawMax = anaOutRawMax }; dbContext.AddRTU(newRtu); } else { // to do: bacati exception mozda message = string.Format("Invalid config: There is multiple RTUs with Name={0}!", uniqueName); Console.WriteLine(message); return(false); } } } else { message = string.Format("Invalid config: file must contain at least 1 RTU!"); Console.WriteLine(message); return(false); } //parsing DIGITALS. ORDER OF RELATIVE ADDRESSES IS IMPORTANT if (digitals.Count != 0) { foreach (var d in digitals) { string procContr = (string)d.Element("ProcContrName"); // does RTU exists? RTU associatedRtu; if ((associatedRtu = dbContext.GetRTUByName(procContr)) != null) { Digital newDigital = new Digital(); // SETTING ProcContrName newDigital.ProcContrName = procContr; string uniqueName = (string)d.Element("Name"); // variable with that name does not exists in db? if (!dbContext.Database.ProcessVariablesName.ContainsKey(uniqueName)) { // SETTING Name newDigital.Name = uniqueName; // SETTING State string stringCurrentState = (string)d.Element("State"); States stateValue = (States)Enum.Parse(typeof(States), stringCurrentState); newDigital.State = stateValue; // SETTING Command parameter - for initializing Simulator with last command string lastCommandString = (string)d.Element("Command"); CommandTypes command = (CommandTypes)Enum.Parse(typeof(CommandTypes), lastCommandString); // SETTING Class string digDevClass = (string)d.Element("Class"); DigitalDeviceClasses devClass = (DigitalDeviceClasses)Enum.Parse(typeof(DigitalDeviceClasses), digDevClass); newDigital.Class = devClass; // SETTING RelativeAddress ushort relativeAddress = (ushort)(int)d.Element("RelativeAddress"); newDigital.RelativeAddress = relativeAddress; var hasCommands = d.Element("ValidCommands"); if (hasCommands.HasElements) { var validCommands = hasCommands.Elements("Command").ToList(); // SETTING ValidCommands foreach (var xElementCommand in validCommands) { string stringCommand = (string)xElementCommand; CommandTypes validCommand = (CommandTypes)Enum.Parse(typeof(CommandTypes), stringCommand); newDigital.ValidCommands.Add(validCommand); } } else { message = string.Format("Invalid config: Variable = {0} does not contain commands.", uniqueName); Console.WriteLine(message); return(false); } var hasStates = d.Element("ValidStates"); if (hasStates.HasElements) { var validStates = hasStates.Elements("State").ToList(); // SETTING ValidStates foreach (var xElementState in validStates) { string stringState = (string)xElementState; States state = (States)Enum.Parse(typeof(States), stringState); newDigital.ValidStates.Add(state); } } else { message = string.Format("Invalid config: Variable = {0} does not contain states.", uniqueName); Console.WriteLine(message); return(false); } ushort calculatedRelativeAddres; if (associatedRtu.TryMap(newDigital, out calculatedRelativeAddres)) { if (relativeAddress == calculatedRelativeAddres) { if (associatedRtu.MapProcessVariable(newDigital)) { dbContext.AddProcessVariable(newDigital); } } else { message = string.Format("Invalid config: Variable = {0} RelativeAddress = {1} is not valid.", uniqueName, relativeAddress); Console.WriteLine(message); return(false); } } } else { message = string.Format("Invalid config: Name = {0} is not unique. Variable already exists", uniqueName); Console.WriteLine(message); return(false); } } else { message = string.Format("Invalid config: Parsing Digitals, ProcContrName = {0} does not exists.", procContr); Console.WriteLine(message); return(false); } } } // parsing ANALOGS. ORDER OF RELATIVE ADDRESSES IS IMPORTANT if (analogs.Count != 0) { foreach (var a in analogs) { string procContr = (string)a.Element("ProcContrName"); // does RTU exists? RTU associatedRtu; if ((associatedRtu = dbContext.GetRTUByName(procContr)) != null) { Analog newAnalog = new Analog(); // SETTING ProcContrName newAnalog.ProcContrName = procContr; string uniqueName = (string)a.Element("Name"); // variable with that name does not exists in db? if (!dbContext.Database.ProcessVariablesName.ContainsKey(uniqueName)) { // SETTING Name newAnalog.Name = uniqueName; // SETTING NumOfRegisters ushort numOfReg = (ushort)(int)a.Element("NumOfRegisters"); newAnalog.NumOfRegisters = numOfReg; // SETTING AcqValue ushort acqValue = (ushort)(float)a.Element("AcqValue"); newAnalog.AcqValue = acqValue; // SETTING CommValue ushort commValue = (ushort)(float)a.Element("CommValue"); newAnalog.CommValue = commValue; // SETTING MinValue float minValue = (float)a.Element("MinValue"); newAnalog.MinValue = minValue; // SETTING MaxValue float maxValue = (float)a.Element("MaxValue"); newAnalog.MaxValue = maxValue; // SETTING UnitSymbol string stringUnitSymbol = (string)a.Element("UnitSymbol"); UnitSymbol unitSymbolValue = (UnitSymbol)Enum.Parse(typeof(UnitSymbol), stringUnitSymbol, true); newAnalog.UnitSymbol = unitSymbolValue; // SETTING RelativeAddress ushort relativeAddress = (ushort)(int)a.Element("RelativeAddress"); newAnalog.RelativeAddress = relativeAddress; // svejedno je uzeli AnaInRawMin ili AnaOutRawMin -> isti su trenutni, // sve dok imamo samo Analog.cs a ne AnaIn.cs + AnaOut.cs (dok je kao za digital) newAnalog.RawBandLow = associatedRtu.AnaInRawMin; newAnalog.RawBandHigh = associatedRtu.AnaInRawMax; // SETTING RawAcqValue and RawCommValue AnalogProcessor.EGUToRawValue(newAnalog); ushort calculatedRelativeAddres; if (associatedRtu.TryMap(newAnalog, out calculatedRelativeAddres)) { if (relativeAddress == calculatedRelativeAddres) { if (associatedRtu.MapProcessVariable(newAnalog)) { dbContext.AddProcessVariable(newAnalog); } } else { message = string.Format("Invalid config: Analog Variable = {0} RelativeAddress = {1} is not valid.", uniqueName, relativeAddress); Console.WriteLine(message); return(false); } } } else { message = string.Format("Invalid config: Name = {0} is not unique. Analog Variable already exists", uniqueName); Console.WriteLine(message); return(false); } } else { message = string.Format("Invalid config: Parsing Analogs, ProcContrName = {0} does not exists.", procContr); Console.WriteLine(message); return(false); } } } // to do: if (counters.Count != 0) { } Console.WriteLine("Configuration passed successfully."); } catch (FileNotFoundException e) { Console.WriteLine(e.Message); return(false); } catch (XmlException e) { Console.WriteLine(e.Message); return(false); } catch (Exception e) { Console.WriteLine(e.Message); Console.WriteLine(e.StackTrace); return(false); } Database.IsConfigurationFinished = true; return(true); }
/// <summary> /// Processing answers from Simulator - Process Controller /// </summary> public void ProcessPCAnwers(TimeSpan timeout, CancellationToken token) { DataLinkHandler dataLinkHandler = new DataLinkHandler(); while (!token.IsCancellationRequested) { bool isSuccessful; IORequestBlock answer = IORequests.DequeueAnswer(out isSuccessful, timeout); if (isSuccessful) { bool isChange = false; RTU rtu; if ((rtu = dbContext.GetRTUByName(answer.ProcessControllerName)) != null) { switch (rtu.Protocol) { case IndustryProtocols.ModbusTCP: ModbusHandler mdbHandler = new ModbusHandler(); try { mdbHandler.UnpackData(answer.RcvBuff, answer.RcvMsgLength); switch (mdbHandler.Response.FunCode) { case FunctionCodes.ReadDiscreteInput: { BitReadResponse response = (BitReadResponse)mdbHandler.Response; var responsePVCount = answer.Flags; ushort varAddr = answer.ReqAddress; for (int i = 0; i < responsePVCount; i++, varAddr++) { ProcessVariable pv; if (rtu.GetProcessVariableByAddress(varAddr, out pv)) { Digital target = (Digital)pv; try { bool isOpened = response.BitValues[i]; if (target.State != target.ValidStates[isOpened ? 1 : 0]) { isChange = true; target.State = target.ValidStates[isOpened ? 1 : 0]; Console.WriteLine(" CHANGE! Digital variable {0}, state: {1}", target.Name, target.State); dMSProxy.ChangeOnSCADADigital(target.Name, target.State); } } catch { Console.WriteLine("Digital variable {0}, state: INVALID", target.Name); } } } if (isChange) { ScadaModelParser parser = new ScadaModelParser(); parser.SerializeScadaModel(); } } break; // analog input case FunctionCodes.ReadInputRegisters: { RegisterReadResponse response = (RegisterReadResponse)mdbHandler.Response; var responsePVCount = answer.Flags; ushort varAddr = answer.ReqAddress; for (int i = 0; i < responsePVCount; i++, varAddr++) { ProcessVariable pv; if (rtu.GetProcessVariableByAddress(varAddr, out pv)) { Analog target = (Analog)pv; try { ushort newRawAcqValue = response.RegValues[target.RelativeAddress]; float newAcqValue; AnalogProcessor.RawValueToEGU(target, newRawAcqValue, out newAcqValue); if (target.AcqValue != newAcqValue) { isChange = true; target.RawAcqValue = newRawAcqValue; target.AcqValue = newAcqValue; Console.WriteLine(" CHANGE! Analog variable {0}, AcqValue: {1}", target.Name, target.AcqValue); //to do: propagacija analogih promena(ako se secate Pavlica je prvo rekao da nam to ne treba da samo jednom zakucamo vrednost na pocetku) xD dMSProxy.ChangeOnSCADAAnalog(target.Name, target.AcqValue); } } catch { // Console.WriteLine("Digital variable {0}, state: INVALID", target.Name); } } } if (isChange) { ScadaModelParser parser = new ScadaModelParser(); parser.SerializeScadaModel(); } } break; } } catch (Exception e) { Console.WriteLine(e.Message); } break; case IndustryProtocols.DNP3TCP: byte len = answer.RcvBuff[2]; byte actualLen = (byte)(2 + 1 + 5 + 2); // start + len + ctrl + dest + source + crc len -= 5; // minus header while (len > 0) { if (len < 16) { // last chunk actualLen += (byte)(len + 2); break; } actualLen += (byte)(16 + 2); len -= 16; } byte[] message = new byte[actualLen]; for (int i = 0; i < actualLen; i++) { message[i] = answer.RcvBuff[i]; } List <UserLevelObject> userLevelObjects = dataLinkHandler.PackUp(message); if (userLevelObjects == null) { continue; } DNP3UserLayerHandler dNP3UserLayerHandler = new DNP3UserLayerHandler(new DNP3Handler(), dbContext); List <Tuple <string, float> > tuples = dNP3UserLayerHandler.ReadAllAnalogInputPointsReadResponse(userLevelObjects, rtu.Name); foreach (Tuple <string, float> tuple in tuples) { try { dMSProxy.ChangeOnSCADAAnalog(tuple.Item1, tuple.Item2); } catch { dMSProxy = new DMSSCADAProxy(); } } break; } } } } Console.WriteLine("ProcessPCAnswers.shutdown=true"); return; }
public bool DeserializeScadaModel(string deserializationSource = "ScadaModel.xml") { // to do Database.IsConfigurationFinished = false; string message = string.Empty; string configurationName = deserializationSource; // string source = Path.Combine(basePath, configurationName); if (Database.Instance.RTUs.Count != 0) { Database.Instance.RTUs.Clear(); } if (Database.Instance.ProcessVariablesName.Count != 0) { Database.Instance.ProcessVariablesName.Clear(); } try { // XElement xdocument = XElement.Load(source); // access RTUS, DIGITALS, ANALOGS, COUNTERS from ScadaModel root // IEnumerable<XElement> elements = xdocument.Elements(); //var rtus = xdocument.Element("RTUS").Elements("RTU").ToList(); //var digitals = (from dig in xdocument.Element("Digitals").Elements("Digital") // orderby (int)dig.Element("RelativeAddress") // select dig).ToList(); //var analogs = (from dig in xdocument.Element("Analogs").Elements("Analog") // orderby (int)dig.Element("RelativeAddress") // select dig).ToList(); //var counters = (from dig in xdocument.Element("Counters").Elements("Counter") // orderby (int)dig.Element("RelativeAddress") // select dig).ToList(); List <ScadaDBClassLib.ModelData.RTU> rtus = new List <ScadaDBClassLib.ModelData.RTU>(); List <ScadaDBClassLib.ModelData.Digital> digitals = new List <ScadaDBClassLib.ModelData.Digital>(); List <ScadaDBClassLib.ModelData.Analog> analogs = new List <ScadaDBClassLib.ModelData.Analog>(); using (ScadaDBClassLib.ScadaCtxcs ctx = new ScadaDBClassLib.ScadaCtxcs()) { rtus = ctx.RTUs.ToList(); digitals = ctx.Digitals.ToList(); analogs = ctx.Analogs.ToList(); } // parsing RTUS if (rtus.Count != 0) { foreach (var rtu in rtus) { RTU newRtu; string uniqueName = (string)rtu.Name; // if RTU with that name does not already exist? if (!dbContext.Database.RTUs.ContainsKey(uniqueName)) { byte address = (byte)(int)rtu.Address; bool freeSpaceForDigitals = (bool)rtu.FreeSpaceForDigitals; bool freeSpaceForAnalogs = (bool)rtu.FreeSpaceForAnalogs; IndustryProtocols protocol = IndustryProtocols.ModbusTCP; int digOutStartAddr = (int)rtu.DigOutStartAddr; int digInStartAddr = (int)rtu.DigInStartAddr; int anaInStartAddr = (int)rtu.AnaInStartAddr; int anaOutStartAddr = (int)rtu.AnaOutStartAddr; int counterStartAddr = (int)rtu.CounterStartAddr; int digOutCount = (int)rtu.NoDigOut; int digInCount = (int)rtu.NoDigIn; int anaInCount = (int)rtu.NoAnaIn; int anaOutCount = (int)rtu.NoAnaOut; int counterCount = (int)rtu.NoCnt; ushort anaInRawMin = (ushort)(int)rtu.AnaInRawMin; ushort anaInRawMax = (ushort)(int)rtu.AnaInRawMax; ushort anaOutRawMin = (ushort)(int)rtu.AnaOutRawMin; ushort anaOutRawMax = (ushort)(int)rtu.AnaOutRawMax; if (digOutCount != digInCount) { message = string.Format("Invalid config: RTU - {0}: Value of DigOutCount must be the same as Value of DigInCount", uniqueName); Console.WriteLine(message); return(false); } newRtu = new RTU() { Name = uniqueName, Address = address, FreeSpaceForDigitals = freeSpaceForDigitals, FreeSpaceForAnalogs = freeSpaceForAnalogs, Protocol = protocol, DigOutStartAddr = digOutStartAddr, DigInStartAddr = digInStartAddr, AnaInStartAddr = anaInStartAddr, AnaOutStartAddr = anaOutStartAddr, CounterStartAddr = counterStartAddr, NoDigOut = digOutCount, NoDigIn = digInCount, NoAnaIn = anaInCount, NoAnaOut = anaOutCount, NoCnt = counterCount, AnaInRawMin = anaInRawMin, AnaInRawMax = anaInRawMax, AnaOutRawMin = anaOutRawMin, AnaOutRawMax = anaOutRawMax }; //using (ScadaContextDB ctx = new ScadaContextDB()) //{ // ctx.RTUs.Add(new ScadaCloud.Model.RTU // { // Name = uniqueName, // Address = address, // FreeSpaceForDigitals = freeSpaceForDigitals, // FreeSpaceForAnalogs = freeSpaceForAnalogs, // Protocol = protocol, // DigOutStartAddr = digOutStartAddr, // DigInStartAddr = digInStartAddr, // AnaInStartAddr = anaInStartAddr, // AnaOutStartAddr = anaOutStartAddr, // CounterStartAddr = counterStartAddr, // NoDigOut = digOutCount, // NoDigIn = digInCount, // NoAnaIn = anaInCount, // NoAnaOut = anaOutCount, // NoCnt = counterCount, // AnaInRawMin = anaInRawMin, // AnaInRawMax = anaInRawMax, // AnaOutRawMin = anaOutRawMin, // AnaOutRawMax = anaOutRawMax // }); // ctx.SaveChanges(); //} dbContext.AddRTU(newRtu); } else { // to do: bacati exception mozda message = string.Format("Invalid config: There is multiple RTUs with Name={0}!", uniqueName); Console.WriteLine(message); return(false); } } } else { message = string.Format("Invalid config: file must contain at least 1 RTU!"); Console.WriteLine(message); return(false); } //parsing DIGITALS. ORDER OF RELATIVE ADDRESSES IS IMPORTANT if (digitals.Count != 0) { foreach (var d in digitals) { string procContr = (string)d.ProcContrName; // does RTU exists? RTU associatedRtu; if ((associatedRtu = dbContext.GetRTUByName(procContr)) != null) { Digital newDigital = new Digital(); // SETTING ProcContrName newDigital.ProcContrName = procContr; string uniqueName = (string)d.Name; // variable with that name does not exists in db? if (!dbContext.Database.ProcessVariablesName.ContainsKey(uniqueName)) { // SETTING Name newDigital.Name = uniqueName; // SETTING State string stringCurrentState = (string)d.State; States stateValue = (States)Enum.Parse(typeof(States), stringCurrentState); newDigital.State = stateValue; // SETTING Command parameter - for initializing Simulator with last command string lastCommandString = (string)d.Command; CommandTypes command = (CommandTypes)Enum.Parse(typeof(CommandTypes), lastCommandString); // SETTING Class DigitalDeviceClasses devClass = DigitalDeviceClasses.SWITCH; newDigital.Class = devClass; // SETTING RelativeAddress ushort relativeAddress = (ushort)(int)d.RelativeAddress; newDigital.RelativeAddress = relativeAddress; // SETTING ValidCommands newDigital.ValidCommands.Add(CommandTypes.OPEN); newDigital.ValidCommands.Add(CommandTypes.CLOSE); newDigital.ValidStates.Add(States.CLOSED); newDigital.ValidStates.Add(States.OPENED); //using (ScadaContextDB ctx = new ScadaContextDB()) //{ // ctx.Digirals.Add(new ScadaCloud.Model.Digital // { // Name = uniqueName, // RelativeAddress = relativeAddress, // ProcContrName = procContr, // State = stringCurrentState, // Command = lastCommandString // }); // ctx.SaveChanges(); //} ushort calculatedRelativeAddres; if (associatedRtu.TryMap(newDigital, out calculatedRelativeAddres)) { if (relativeAddress == calculatedRelativeAddres) { if (associatedRtu.MapProcessVariable(newDigital)) { dbContext.AddProcessVariable(newDigital); } } else { message = string.Format("Invalid config: Variable = {0} RelativeAddress = {1} is not valid.", uniqueName, relativeAddress); Console.WriteLine(message); continue; } } } else { message = string.Format("Invalid config: Name = {0} is not unique. Variable already exists", uniqueName); Console.WriteLine(message); continue; } } else { message = string.Format("Invalid config: Parsing Digitals, ProcContrName = {0} does not exists.", procContr); Console.WriteLine(message); return(false); } } } // parsing ANALOGS. ORDER OF RELATIVE ADDRESSES IS IMPORTANT if (analogs.Count != 0) { foreach (var a in analogs) { string procContr = (string)a.ProcContrName; // does RTU exists? RTU associatedRtu; if ((associatedRtu = dbContext.GetRTUByName(procContr)) != null) { Analog newAnalog = new Analog(); // SETTING ProcContrName newAnalog.ProcContrName = procContr; string uniqueName = (string)a.Name; // variable with that name does not exists in db? if (!dbContext.Database.ProcessVariablesName.ContainsKey(uniqueName)) { // SETTING Name newAnalog.Name = uniqueName; // SETTING NumOfRegisters ushort numOfReg = (ushort)(int)a.NumOfRegisters; newAnalog.NumOfRegisters = numOfReg; // SETTING AcqValue ushort acqValue = (ushort)(float)a.AcqValue; newAnalog.AcqValue = acqValue; // SETTING CommValue ushort commValue = (ushort)(float)a.CommValue; newAnalog.CommValue = commValue; // SETTING MinValue float minValue = (float)a.MinValue; newAnalog.MinValue = minValue; // SETTING MaxValue float maxValue = (float)a.MaxValue; newAnalog.MaxValue = maxValue; // SETTING UnitSymbol string stringUnitSymbol = (string)a.UnitSymbol; UnitSymbol unitSymbolValue = (UnitSymbol)Enum.Parse(typeof(UnitSymbol), stringUnitSymbol, true); newAnalog.UnitSymbol = unitSymbolValue; // SETTING RelativeAddress ushort relativeAddress = (ushort)(int)a.RelativeAddress; newAnalog.RelativeAddress = relativeAddress; // svejedno je uzeli AnaInRawMin ili AnaOutRawMin -> isti su trenutni, // sve dok imamo samo Analog.cs a ne AnaIn.cs + AnaOut.cs (dok je kao za digital) newAnalog.RawBandLow = associatedRtu.AnaInRawMin; newAnalog.RawBandHigh = associatedRtu.AnaInRawMax; //using (ScadaContextDB ctx = new ScadaContextDB()) //{ // ctx.Analogs.Add(new ScadaCloud.Model.Analog // { // Name = uniqueName, // NumOfRegisters = numOfReg, // AcqValue = acqValue, // CommValue = commValue, // MaxValue = maxValue, // MinValue = minValue, // ProcContrName = procContr, // RelativeAddress = relativeAddress, // UnitSymbol = stringUnitSymbol // }); // ctx.SaveChanges(); //} // SETTING RawAcqValue and RawCommValue AnalogProcessor.EGUToRawValue(newAnalog); ushort calculatedRelativeAddres; if (associatedRtu.TryMap(newAnalog, out calculatedRelativeAddres)) { if (relativeAddress == calculatedRelativeAddres) { if (associatedRtu.MapProcessVariable(newAnalog)) { dbContext.AddProcessVariable(newAnalog); } } else { message = string.Format("Invalid config: Analog Variable = {0} RelativeAddress = {1} is not valid.", uniqueName, relativeAddress); Console.WriteLine(message); return(false); } } } else { message = string.Format("Invalid config: Name = {0} is not unique. Analog Variable already exists", uniqueName); Console.WriteLine(message); return(false); } } else { message = string.Format("Invalid config: Parsing Analogs, ProcContrName = {0} does not exists.", procContr); Console.WriteLine(message); return(false); } } } // to do: //if (counters.Count != 0) //{ //} Console.WriteLine("Configuration passed successfully."); } catch (FileNotFoundException e) { Console.WriteLine(e.Message); return(false); } catch (XmlException e) { Console.WriteLine(e.Message); return(false); } catch (Exception e) { Console.WriteLine(e.Message); Console.WriteLine(e.StackTrace); return(false); } Database.IsConfigurationFinished = true; return(true); }