Esempio n. 1
0
        /// <summary>
        /// Compiles the stated zenon Logic project.
        /// </summary>
        /// <param name="zenonLogicProject"></param>
        /// <param name="compilerOutputText">
        /// Contains the output messages of the compilation process. Null if the if retrieving the compiler output failed.
        /// </param>
        internal void CompileZenonLogicProject(LogicProject zenonLogicProject, out IEnumerable <string> compilerOutputText)
        {
            ProcessStartInfo startInfo = new ProcessStartInfo(K5BexeFilePath, $"BUILD {this.ZenonLogicProjectDirectory}")
            {
                CreateNoWindow = false,
                WindowStyle    = ProcessWindowStyle.Hidden
            };

            using (Process stratonCompileProcess = new Process {
                StartInfo = startInfo
            })
            {
                try
                {
                    stratonCompileProcess.Start();
                    stratonCompileProcess.WaitForExit();

                    compilerOutputText = ReadCompileLogFileOfZenonLogicProject(zenonLogicProject);
                }
                catch (Exception e)
                {
                    throw new InvalidOperationException(string.Format(Strings.K5BCompileFailedException, zenonLogicProject.Path), e);
                }
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Writes the appli.xml content directly into the file.
        /// </summary>
        /// <remarks>
        /// This is done because import via k5b.exe omitts the folder structures in the application tree.
        /// </remarks>
        /// <param name="zenonLogicProject"></param>
        private void WriteAppliXmlFile(LogicProject zenonLogicProject)
        {
            string appliXmlFilePathToImport = TemporaryFileCreator.GetRandomTemporaryFilePathWithExtension("xml");

            zenonLogicProject.ApplicationTree.ExportAsFile(appliXmlFilePathToImport, LogicXmlEncoding);

            var appliFilePath = Path.Combine(this.ZenonLogicProjectDirectory, "appli.xml");

            try
            {
                if (File.Exists(appliFilePath))
                {
                    File.Delete(appliFilePath);
                }

                File.Copy(appliXmlFilePathToImport, appliFilePath);
            }
            catch (IOException e)
            {
                throw new InvalidOperationException(string.Format(Strings.AppliFileWriteIOException, appliFilePath), e);
            }
            catch (Exception e)
            {
                throw new InvalidOperationException(String.Format(Strings.AppliFileWriteException, appliFilePath), e);
            }
        }
Esempio n. 3
0
        private string SerializeZenonLogicProjectToXmlFile(LogicProject zenonLogicProject)
        {
            string xmlFilePathToImport = TemporaryFileCreator.GetRandomTemporaryFilePathWithExtension("xml");

            zenonLogicProject.ExportAsFile(xmlFilePathToImport, LogicXmlEncoding);
            return(xmlFilePathToImport);
        }
Esempio n. 4
0
        internal bool TryApplyCompilerSettings(LogicProject zenonLogicProject, ImportOptions options = ImportOptions.Default)
        {
            if (zenonLogicProject?.Settings == null)
            {
                return(false);
            }

            var  settings     = zenonLogicProject.Settings.CompilerSettings.CompilerOptions.OptionTuples ?? Enumerable.Empty <LogicOptionTuple>();
            bool allSucceeded = TryApplyCompilerSettings(settings);

            // According to CD-FR the following three setting sections shall never be set manually.
            //allSucceeded
            //  = TryApplySettings(zenonLogicProject.Settings.CompilerSettings.SimulationCodeOptions.OptionTuples ?? Enumerable.Empty<LogicOptionTuple>())
            //  && allSucceeded;
            //allSucceeded
            //  = TryApplySettings(zenonLogicProject.Settings.CompilerSettings.TargetCodeOptions.OptionTuples ?? Enumerable.Empty<LogicOptionTuple>())
            //  && allSucceeded;

            uint cycleTime = zenonLogicProject.Settings.TriggerTime.CycleTime;

            if (cycleTime == 0)
            {
                cycleTime = 10000; // 10 seconds as the default for invalid values
            }

            allSucceeded = SetOption("CycleTime", cycleTime.ToString()) && allSucceeded;

            if (!options.HasFlag(ImportOptions.ApplyOnlineSettings))
            {
                return(allSucceeded);
            }

            return(allSucceeded);
        }
Esempio n. 5
0
        /// <summary>
        /// Compiles the stated zenon Logic project.
        /// </summary>
        /// <param name="zenonLogicProjectToCompile"></param>
        /// <param name="compilerOutputText">
        /// Contains the output messages of the compilation process. Null if the if retrieving the compiler output failed.
        /// </param>
        public void CompileZenonLogicProject(LogicProject zenonLogicProjectToCompile, out IEnumerable <string> compilerOutputText)
        {
            if (!Directory.Exists(zenonLogicProjectToCompile.Path))
            {
                throw new DirectoryNotFoundException
                          ($"{Strings.ZenonLogicProjectDirectoryNotFound} {Strings.ZenonLogicHintForMissingDirectory}");
            }

            K5ToolSet k5ToolSet = new K5ToolSet(zenonLogicProjectToCompile.Path);

            k5ToolSet.CompileZenonLogicProject(zenonLogicProjectToCompile, out compilerOutputText);
        }
Esempio n. 6
0
        /// <summary>
        /// Imports the stated <see cref="LogicProject"/> into zenon Logic.
        /// </summary>
        /// <param name="zenonLogicProject">The project to import into zenon.</param>
        /// <param name="options">Specifies options on how to import the <paramref name="zenonLogicProject"/> into zenon.</param>
        internal bool ImportZenonLogicProject(LogicProject zenonLogicProject, ImportOptions options)
        {
            string xmlFilePathToImport = SerializeZenonLogicProjectToXmlFile(zenonLogicProject);
            string option = "XMLMERGE";

            if (options.HasFlag(ImportOptions.ReCreateVariables))
            {
                option += "-RV";
            }

            if (options.HasFlag(ImportOptions.DoNotMerge))
            {
                option += "-NM";
            }

            string arguments = $"{option} {this.ZenonLogicProjectDirectory} {xmlFilePathToImport}";

            // Import via K5B.exe
            ProcessStartInfo startInfo = new ProcessStartInfo(K5BexeFilePath, arguments)
            {
                CreateNoWindow = false,
                WindowStyle    = ProcessWindowStyle.Hidden
            };

            using (Process stratonXmlImportProcess = new Process {
                StartInfo = startInfo
            })
            {
                try
                {
                    stratonXmlImportProcess.Start();
                    stratonXmlImportProcess.WaitForExit();
                }
                catch (Exception e)
                {
                    throw new InvalidOperationException(Strings.K5BXmlImportFailedException, e);
                }
            }

            // needed for import using K5B.exe as these parts get not imported
            WriteAppliXmlFile(zenonLogicProject);
            WriteGlobalDefinesFile(zenonLogicProject);

            return(true);
        }
Esempio n. 7
0
        /// <summary>
        /// Reads the __build.log file of the stated zenon Logic project.
        /// The file contains the output messages of the last compilation process.
        /// </summary>
        /// <param name="zenonLogicProject"></param>
        /// <returns>Returns null if __build.log does not exist. Happens if the projects was never compiled.</returns>
        private IEnumerable <string> ReadCompileLogFileOfZenonLogicProject(LogicProject zenonLogicProject)
        {
            string compilerOutputFilePath = Path.Combine(ZenonLogicProjectDirectory, ZenonLogicCompileLogFileName);

            if (!File.Exists(compilerOutputFilePath))
            {
                return(null);
            }

            try
            {
                return(File.ReadAllLines(compilerOutputFilePath));
            }
            catch (Exception e)
            {
                throw new FileLoadException(string.Format(Strings.ZenonLogicCompileLogFileReadException, zenonLogicProject.Path), e);
            }
        }
Esempio n. 8
0
        /// <summary>
        /// Writes the appli.EQV content directly into the file.
        /// </summary>
        /// <remarks>
        /// This is done because the import via k5b.exe omitts global definitions.
        /// </remarks>
        /// <param name="zenonLogicProject"></param>
        private void WriteGlobalDefinesFile(LogicProject zenonLogicProject)
        {
            string      globalDefinesFilePath = TemporaryFileCreator.GetRandomTemporaryFilePathWithExtension("EQV");
            LogicDefine globalDefine          = zenonLogicProject.LogicDefinitions.Defines
                                                .FirstOrDefault(define => define.Name.Equals(Strings.GlobalDefineName));

            if (globalDefine == null || string.IsNullOrWhiteSpace(globalDefine.DefineContent))
            {
                return;
            }

            File.WriteAllText(globalDefinesFilePath, globalDefine.DefineContent);

            var appliEqvFilePath = Path.Combine(this.ZenonLogicProjectDirectory, "appli.EQV");

            if (File.Exists(appliEqvFilePath))
            {
                File.Delete(appliEqvFilePath);
            }

            File.Copy(globalDefinesFilePath, appliEqvFilePath);
        }
Esempio n. 9
0
        private static void Main(string[] args)
        {
            // NOTE: No error handling etc. is included here, this sample is just intended to give you a starting point on
            // handling zenon Logic projects via code,
            // IMPORTANT: To avoid side effects, you should make sure that the Logic workbench is not running,
            // which is not shown here.

            // This sample accesses zenon via COM, therefore we need to connect first.
            var zenonEditor = Marshal.GetActiveObject(ZenonRuntimeComObjectName) as zenOn.ApplicationED;

            if (zenonEditor == null)
            {
                Console.WriteLine("Cannot connect to an instance of zenon Editor.");
                return;
            }

            // The active zenon editor project is used for our sample.
            var zenonProject = zenonEditor.MyWorkspace.ActiveDocument;

            if (zenonProject == null)
            {
                Console.WriteLine("No active instance of a zenon Editor project can be received.");
                return;
            }

            // NOTE: For this example, you need a reference to zenon.Interop.dll in your .csproj.
            // We added it from version 7.60 to a binaries folder.
            //
            // You can use alternative approaches to the one which is shown here, i.e.:
            // - modifying the project as pure XML
            //   Required:      References to zenonApi.Core and zenonApi.Logic.
            //   Advantage:     No dependency on Windows or zenon.
            //   Disadvantage:  If you want to import the object model to Logic, you need to do this on your own.
            // - modifying the project via a COM reference to zenon, as done in this example
            //   Required:      Reference to zenon.Interop.dll, references to zenonApi.Core, zenonApi.Logic and zenonApi.Zenon
            //   Advantage:     Easy to import and modify Logic projects from within a zenon context.
            //   Disadvantage:  Can only be done with a running zenon Editor instance on Windows
            // - modifying the project not via the Add-In framework
            //   Required:      Reference to Scada.AddIn.Contracts, zenonApi.Core, zenonApi.Logic, zenonApi.Zenon
            //   Advantage:     Same as for COM
            //   Disadvantage:  Same as for COM
            // - Just create projects and do basic modifications without any of our APIs
            //   Required:      -
            //   Advantage:     No dependencies, except K5B.exe and/or K5Prp.dll
            //   Disadvantage:  Just XML, no typed object model, hard to modify/maintain, etc.
            // What you choose simply depends on what you are developing and using.
            // The easiest way might be to work with the provided APIs we use here for COM and Add-In.

            // If you use the Add-In Framework, use "new zenonApi.Zenon.Zenon(zenonProject)
            var wrapper = new zenonApi.Zenon.ZenonCom(zenonProject);

            // We want to modify or create a Logic project named "Sample":
            var lazyLogicProjects       = wrapper.LazyLogicProjects;
            var sampleProjectToBeEdited = lazyLogicProjects.FirstOrDefault(x => x.ProjectName == "Sample")?.Value;

            if (sampleProjectToBeEdited == null)
            {
                // "Sample" does not exist, we need to create it with the following.
                // All changes you make in the API will only take affect, after you call ImportLogicProjectsIntoZenon
                // (see the end of this file)
                sampleProjectToBeEdited = new LogicProject("Sample");
                lazyLogicProjects.Add(new LazyLogicProject(sampleProjectToBeEdited));
            }

            // Access the logic options etc. via a object model. The following shows some examples.
            sampleProjectToBeEdited.Settings.TriggerTime.CycleTime = 10000;
            sampleProjectToBeEdited.Settings.CompilerSettings.CompilerOptions["warniserr"] = "OFF";

            // Get the first global variable group ("(GLOBAL)" and "(RETAIN)" always exist).
            var variableGroup = sampleProjectToBeEdited.GlobalVariables.VariableGroups.FirstOrDefault();

            // The appropriate group can also be accessed directly like this:
            variableGroup = sampleProjectToBeEdited.GlobalVariables[LogicVariableKind.Global];

            // Sample for creating some string variables in our "Sample" project:
            for (int i = 0; i < 10; i++)
            {
                var variableSample = new LogicVariable()
                {
                    InitialValue    = "5",
                    MaxStringLength = "255",
                    Type            = "STRING",
                    Name            = "MyVariable" + i,
                };
                variableSample.VariableInfos.Add(new LogicVariableInfo()
                {
                    // Set to be visible in zenon (SYB Flag)
                    Data = "<syb>",
                    Type = LogicVariableInformationTypeKind.Embed
                });

                variableSample.VariableInfos.Add(new LogicVariableInfo()
                {
                    Data = "STRATON",
                    Type = LogicVariableInformationTypeKind.Profile
                });

                variableGroup.Variables.Add(variableSample);
            }

            // Get the first folder of your application tree in Logic and rename it
            LogicFolder folder = sampleProjectToBeEdited.ApplicationTree.Folders.FirstOrDefault();

            if (folder == null)
            {
                // Does not exist, create it instead.
                folder = new LogicFolder("RenamedTestFolder");
                sampleProjectToBeEdited.ApplicationTree.Folders.Add(folder);
            }

            // Renaming is possible.
            folder.Name = "RenamedTestFolder";

            // Same for the first program:
            LogicProgram program = folder.Programs.FirstOrDefault();

            if (program == null)
            {
                program = new LogicProgram("RenamedTestProgram");
                folder.Programs.Add(program);
            }
            program.Name = "RenamedMyProgram";
            // Modify the source code of a program:
            program.SourceCode += "\n// Some Comment";

            // Navigate back to the application tree when only having the program (useful when working with multiple logic
            // projects at once):
            var folderAgain = program.Parent;

            // Change the cycle timing and other project settings
            sampleProjectToBeEdited.Settings.TriggerTime.CycleTime = 12345;
            sampleProjectToBeEdited.Settings.CompilerSettings.CompilerOptions["warniserr"] = "OFF";

            // Modify variables (if it exists)
            var variable = program.VariableGroups.FirstOrDefault()?.Variables.FirstOrDefault();

            if (variable != null)
            {
                variable.Name           = "RenamedVariable";
                variable.Attributes.In  = true;
                variable.Attributes.Out = true;
                variable.VariableInfos.Add(new LogicVariableInfo()
                {
                    Type = LogicVariableInformationTypeKind.Embed, Data = "<syb>"
                });
            }

            // Remove a folder if it exists
            sampleProjectToBeEdited.ApplicationTree.Folders.FirstOrDefault(x => x.Name == "Signals")?.Remove();

            // Sample for exporting a project object model to a file:
            string sampleFile = $@"C:\Users\{Environment.UserName}\Desktop\DemoProjectModified.xml";

            sampleProjectToBeEdited.ExportAsFile(sampleFile, Encoding.GetEncoding("iso-8859-1"));

            // Sample for reading a project object model from a file:
            var projectFromXmlFile = LogicProject.Import(XElement.Load(sampleFile));

            // Sample for convert the project object model to XElements and save it manually to the same file
            XElement modifiedProject = sampleProjectToBeEdited.ExportAsXElement();

            XDocument document = new XDocument
            {
                Declaration = new XDeclaration("1.0", "iso-8859-1", "yes")
            };

            document.Add(modifiedProject);
            using (XmlTextWriter writer = new XmlTextWriter(
                       $@"C:\Users\{Environment.UserName}\Desktop\DemoProjectModified.xml",
                       Encoding.GetEncoding("iso-8859-1")))
            {
                writer.Indentation = 3;
                writer.Formatting  = Formatting.Indented;
                document.Save(writer);
            }

            // Import and commit logic projects with the changes we made:
            wrapper.ImportLogicProjectsIntoZenon();

            // For zenon version 10 or higher, additional import options are available, e.g.:
            // wrapper.ImportLogicProjectsIntoZenon(true, ImportOptions.ReCreateVariables | ImportOptions.ApplyOnlineSettings);

            wrapper.Dispose();
        }
Esempio n. 10
0
        internal void TryApplyOnlineChangeSettings(LogicProject zenonLogicProject, ImportOptions options = ImportOptions.Default)
        {
            if (!options.HasFlag(ImportOptions.ApplyOnlineSettings))
            {
                return;
            }

            var optionTuples = zenonLogicProject.Settings.OnlineChangeSettings.OptionTuples ?? Enumerable.Empty <LogicOptionTuple>();

            const uint callback            = 0x400;
            IntPtr     hwnd                = Process.GetCurrentProcess().MainWindowHandle;
            string     clientName          = System.Reflection.Assembly.GetEntryAssembly().GetName().Name;
            string     hotSizeBuffer       = string.Empty;
            bool       enableHot           = false;
            bool       hasHotOptionDefined = false;

            using (K5SrvWrapper srv = K5SrvWrapper.TryConnect(hwnd, callback, zenonLogicProject.Path, clientName, K5SrvConstants.K5DbSelfNotif))
            {
                while (!srv.IsReady)
                {
                    Thread.Sleep(100);
                }

                foreach (var optionTuple in optionTuples)
                {
                    if (!string.IsNullOrWhiteSpace(optionTuple.Name) && !string.IsNullOrWhiteSpace(optionTuple.Value))
                    {
                        if (optionTuple.Name.StartsWith("size_"))
                        {
                            hotSizeBuffer = hotSizeBuffer + optionTuple.Name.Replace("size_", "") + "=" + optionTuple.Value + ",";
                        }

                        else if (optionTuple.Name.Equals("enable"))
                        {
                            hasHotOptionDefined = true;
                            if (int.TryParse(optionTuple.Value, out var i))
                            {
                                enableHot = i > 0;
                            }
                            else if (bool.TryParse(optionTuple.Value, out var b))
                            {
                                enableHot = b;
                            }
                            else if (optionTuple.Value.Equals("ON", StringComparison.OrdinalIgnoreCase))
                            {
                                enableHot = true;
                            }
                            else if (optionTuple.Value.Equals("OFF", StringComparison.OrdinalIgnoreCase))
                            {
                                enableHot = false;
                            }
                        }
                    }
                }

                if (hasHotOptionDefined)
                {
                    srv.SetHot(enableHot);
                }

                if (hotSizeBuffer.Length > 0)
                {
                    srv.SetHotSizing(hotSizeBuffer);
                }
            }
        }