From cc8226f135f336fd5f17c1457eb1cc1bde4b1029 Mon Sep 17 00:00:00 2001 From: Timothy Nunnink <46979634+tnunnink@users.noreply.github.com> Date: Wed, 26 Jul 2023 09:42:23 -0500 Subject: [PATCH] updated readme --- README.md | 203 +++++--------------- src/.idea/.idea.L5Sharp/.idea/workspace.xml | 9 +- 2 files changed, 51 insertions(+), 161 deletions(-) diff --git a/README.md b/README.md index efceefd1..f50b2382 100644 --- a/README.md +++ b/README.md @@ -1,68 +1,69 @@ - - # L5Sharp -A C# library for interacting with Rockwell's L5X import/export files. -The goal of this project was to provide a simple and reusable library for -querying and manipulating L5X files to aid in the creation of tools that -automate tasks related RSLogix 5000 PLC development. - -## Getting started -This project is still under development and in a preview phase, but you can -start using it by adding the package from Nuget. +A library for intuitively interacting with Rockwell's L5X import/export files. + +## Purpose +The purpose of this library is to offer a reusable, strongly typed, intuitive API +over Rockwell's L5X schema, allowing developers to quickly modify or generate L5X content. +In doing so, this library can aid in creation of tools or scripts that automate the PLC development, maintenance, +or testing processes for automation engineers. + +## Goals +The following are some high level goals this project aimed to accomplish. +1. Provide a simple and intuitive API, making the learning curve as low as possible. +2. Ensure performance as much as possible without sacrificing simplicity. +3. Make it easy and seamless to extend the API to support custom queries or functions. +4. Support strongly typed mutable tag data, so we can reference complex structures statically at compile time. + +## Feedback +If you like or use this project, leave a star. If you have questions or issues, +please post in the [issues](https://github.com/tnunnink/L5Sharp/issues) tab +of the project repository. Any feedback is always appreciated. Enjoy! + +## Quick Start +Install package from Nuget. ```powershell Install-Package L5Sharp ``` -If you would like to contribute, have feedback or questions, please reach out! -If you are using or like the progress being made, please leave a star. Thanks! - - -## Overview -The following is a basic walk through of some of the high level features -ofr the library. I plan to create a more in depth wiki at some point, but for -now please refer to the following information to understand how to use the -library. - -### Entry Point -The main entry point to the L5X is the `LogixContent` class. -Use the factory methods `Load` to load a file or `Parse` to parse a string, -exactly how you would with `XDocument`. +Load an L5X file using the primary entry point `LogixContent` class. ```c# var content = LogixContent.Load("C:\PathToMyFile\FileName.L5X"); ``` - -`LogixContent` has a `L5X` property, which is essentially the root content element -of the document. So if you ever need access the XML directly, use that property. -It also contains the root content attributes, such as target type, target component, -software version, and others. +Get started by querying any type across the L5X using the `Find()` and LINQ extensions. ```csharp -var content = LogixContent.Load(Known.Test); - -content.L5X.Should().NotBeNull(); -content.L5X.SchemaRevision.Should().Be(new Revision()); -content.L5X.SoftwareRevision.Should().Be(new Revision(32, 02)); -content.L5X.TargetName.Should().Be("TestController"); -content.L5X.TargetType.Should().Be("Controller"); -content.L5X.ContainsContext.Should().Be(false); -content.L5X.Owner.Should().Be("tnunnink, EN Engineering"); -content.L5X.ExportDate.Should().NotBeNull(); +var results = content.Find() + .SelectMany(t => t.Members()) + .Where(t => t.DataType == "TIMER") + .Select(t => new { t.TagName, t.Comment, t.Value.As().PRE }) + .ToList(); ``` - -### Querying Content +The above query gets all tags and their nested tag members of type TIMER and returns the TagName, +Comment, and Preset value in a flat list. +>[!NOTE] +>`Find()` returns an `IEnumerable`, allowing for complex queries +using LINQ and the strongly typed objects in the library. +> Since `Find()` queries the entire L5X for the specified type, the above query +> will return all **Tag** components found, including controller and program tags. + +## Usage +The following is some basic examples of how you can use this library +to query and modify the L5X content. + +### Querying Once the LogixContent is created, you can use the container properties to get access to all of the primary L5X components, such as `Tag`, `DataType`, `Module`, `Program`, and more. -The following shows some simple querying via the tags component collection interface. +The following shows some simple querying via the `Tags` component container. ```c# //Get all controller tags. -var controllerTags = content.Tags; +var tags = content.Tags.ToList(); //Get a tag by name. -var myTag = content.Tags.Find("MyTag"); +var tag = content.Tags.Find("MyTag"); //Use LINQ to query further. -var timerTypeTags = content.Tags.Where(t => t.DataType == "TIMER"); +var results = content.Tags.Where(t => t.DataType == "TIMER"); ``` -### Modifying Content +### Modifying Modifying components is simple as well. The same component collection interface offers methods for adding, removing, and replacing components. @@ -82,115 +83,7 @@ var result = content.Tags.Find("MyTag").Replace(tag); content.Save("C:\PathToMyOutputFile\FileName.L5X"); ``` -### More On Querying -Tags are unique components in that they have different scopes. -We have to specify a scope to know where to modify the existing collection. -For example, if you call `Tags().Add(tag)`, where do we add the tag? -This is why you have to specify a scope name for the tags collection when interacting with it. -The same applies to `Routine`. - -But what if I just want to query across the entire file, how do I do that? -The answer is use the `Find()` method and specify the type to query as the -generic argument. -```csharp -var allTagsInFile = content.Find(); -``` -NOTE: `Find()` just returns an `IEnumerable`, so it is essentially read only, -but still allows you to form more complex queries using LINQ and the strongly typed -components in the library. - - -### Tag Data -Tag components also contain simple or complex data structures. -This library includes prebuilt `Atomic` and `Predefined` data structures -that allow in memory creation of tag data. - -When creating a Tag component, initialize the `Value` property to get -a new instance of instantiated tag data for the type. - -The following creates a tag with the predefined `TIMER` tag structure. -```csharp -var tag = new Tag -{ - Name = "TimerTag", - Value = new TIMER() -}; -``` - -You can then get members of the tag using the Member() or Members() methods. -```csharp -//Get the preset member of the timer tag. -var pre = tag.Member("PRE"); - -//Set the value of the DINT preset member. -pre.Value = 5000; - -//Get all tag members. -var members = tag.Members(); -``` -When serialized back to the L5X, this component will include all the -tag data you have set on the component. Nice! - -### Custom Data Types -The goal is to continue adding all predefined data structures, but if -one you require is missing, or if you have a user defined type that -you want to create, you can add them yourself. - -Just inherit from `StructureType` and start creating type members like so. -```csharp -/// -/// A test type used to test nested complex data structure code -/// -public class MyNestedType : StructureType -{ - public MyNestedType() : base(nameof(MyNestedType)) - { - } - - public override DataTypeClass Class => DataTypeClass.User; - - /// - /// A simple boolean member - /// - public BOOL Indy { get; set; } = new(); - - /// - /// A string member - /// - public STRING Str { get; set; } = new(); - - /// - /// A nested timer member - /// - public TIMER Tmr { get; set; } = new(); - - /// - /// A nested user defined type - /// - public MySimpleType Simple { get; set; } = new(); - - /// - /// A nested array of atomic values. - /// Using this Logix.Array will create array filled with instantiated types. - /// This will aviod issues with the structure type members collection containing - /// null data for you members. - /// - public BOOL[] Flags { get; set; } = Logix.Array(10).ToArray(); - - /// - /// A nested array of structure types. - /// - public MESSAGE[] Messages { get; set; } = Logix.Array(10).ToArray(); -} -``` -IMPORTANT: When creating custom types, it is important to make them properties, -and initialize them straight away. Internally, StructureType will generate the -Members collection using reflection and adding all ILogixType members. If not initialized, -Members will contain null instances of the data types, which may cause you some -runtime exceptions when trying to access their members. ## Documentation -For further reading on Rockwell's import/export features, -see the following published document. -[Logix 5000 Controllers Import/Export](https://literature.rockwellautomation.com/idc/groups/literature/documents/rm/1756-rm084_-en-p.pdf) +See my project GitHub Page [here](https://tnunnink.github.io/L5Sharp/index.html) for more in depth articles and API documentation. diff --git a/src/.idea/.idea.L5Sharp/.idea/workspace.xml b/src/.idea/.idea.L5Sharp/.idea/workspace.xml index 84b56413..27116e44 100644 --- a/src/.idea/.idea.L5Sharp/.idea/workspace.xml +++ b/src/.idea/.idea.L5Sharp/.idea/workspace.xml @@ -8,12 +8,8 @@ - + - - - -