Giter Club home page Giter Club logo

l5sharp's People

Contributors

tnunnink avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

l5sharp's Issues

Creating Safety Programs

Hi,

Is there a way to add the class attribute to a program and/or tag to specify it as a safety program/tag?

E.g.
<Program Use="Target"
Name="_00s_InMap_CLP330"
TestEdits="false"
MainRoutineName="Main"
Disabled="false"
Class="Safety"
UseAsFolder="false">

Subtag Descriptions In UDTs only returning base tag.

When Looping through each members in a tag, the descriptions of those sub-tags only returns the description of the highest level tag when using the .Description function

foreach (var subtag in tag.Members()) {
    Console.Writeline(subtag.Description);
}

Will always return the same description

No LogixContext class.

With regard to the usage/example:

var context = new LogixContext("FileName.L5X");

Should be?

var context = new L5XContext("FileName.L5X");

Or, should there be a LogixContext class (that has be omitted)?
Could you extend the example?

Controller Module

Another nice improvement might be the auto-generation of the controller's Module element when creating a new L5X instance.

Right now, if I use L5X.New(name, processor), it will create the Controller element in the L5X file, but nothing for the module. Is there enough information to be able to create the Module for the controller (i.e. Local)? I don't know if you have enough built-in data to know how to build the module. I'm trying to reference the Module instance in my program, so if Studio automatically creates it, that's not going to help my use case.

Parsing to a DataType

Related to my other feat7ure request, is there a function available to parse a string of a DataType to a DataType instance?

Something like this, but then output to the actual DataType ( or rather, LogixType) to use in making Tags?

private object GetMemberDataType(Parameter parameter)
{
    object output;
    switch(parameter.DataType)
    {
        case "BOOL":
            output = new BOOL();
            break;
        case "DINT":
            output = new DINT();
            break;
        case "INT":
            output = new INT();
            break;
        case "LINT":
            output = new LINT();
            break;
        case "LREAL":
            output = new LREAL();
            break;
        case "REAL":
            output = new REAL();
            break;
        case "SINT":
            output = new SINT();
            break;
        case "UDINT":
            output = new UDINT();
            break;
        case "UINT":
            output = new UINT();
            break;
        case "ULINT":
            output = new ULINT();
            break;
        case "USINT":
            output = new USINT();
            break;
        case "MESSAGE":
            output = new MESSAGE();
            break;
        case "STRING":
            output = new STRING();
            break;
        case "TIMER":
            output = new TIMER();
            break;
        default:
            output = new BOOL();
            break;
    }

    return output;
}

Working with SafetyInfo

I am trying to get a SafetyInfo element added to an L5X, and then add a list of SafetyTagMaps. I think I am able to get the SafetyInfo created with an xElement representing the tag maps, but I'm having difficulty figuring out how to incorporate that SafetyInfo into the L5X.

What is the correct way to incorporate the SafetyInfo object?

Creating AOIs Efficiently

I'm attempting to create an AOI,. I'm importing an L5X of the AOI, and I want to create the AOI tag and the required Input/Output/InOut tags. Currently, the AddOnInstruction class is very nice, but I can't figure out a way to, neatly, create the necessary tags for the AOI.

When I try to create the AOI tag (i.e. the tag that the AOI is tied to), I can't figure out a nice way to add in the proper tag Members using the AOI class Parameter property.

devenv_WZdVRGeFFz

Feature Request: AOI Rung Instruction

I was thinking it might not be that difficult to generate the rung instruction neutral text for an AOI. I was playing around with it, and it seems like it follows the same pattern:
<AOI Name>(<AOI Tag>, <InOut Tags>, <Input Tags>, <Output Tags>);

Maybe it's that easy?

Problem Creating Array Tags

I'm running into an issue with generating an array tag. For this example, I'm making a BOOL[100] tag.

For the Tag creation, I am setting the Value to the following:
Value = ArrayType.New<BOOL>(100)

It could be that there is a better way to do this, but it seems to work except for one thing. The resulting L5X tag that's exported shows its DataType as:
... DataType="BOOL[100]" Radix="Decimal" Dimensions="100">

This does not import into Studio 5000, but works just fine if the DataType is "BOOL" with the Dimensions set at "100".

RLL Routine Rung Comment Generation

I have run into an issue when creating a new RLL Routine and adding a commented Rung.

In L5X output, the Comment element is added after the Text element. When importing into Studio 5000 (v33.11), it gives the following error:

Element <Comment> is in the wrong order.

If I manually swap the order in the L5X, everything imports correctly. Is there something I can do to re-order the way the rung tags are generated?

Proposal to Extend L5Sharp Support to .NET Standard 2.0

First, I'd like to express my gratitude for L5Sharp—it's been an invaluable discovery for me.

I believe we can broaden the appeal of L5Sharp by extending support to include the .NET Framework by targeting .Net Standard 2.0 as well. This change would significantly benefit users with legacy applications, like myself, who are currently limited to forking the project for compatibility.

I've successfully adapted the code for .NET Framework 4.8 in my testing and am willing to prepare and submit a pull request. I think this enhancement could make the project more accessible to a wider audience.

Looking forward to hearing your thoughts on this suggestion.

Thank you for considering my proposal.

Can't Derive from Sealed Type

Did you end up sealing the base classes in v2.2.0? This worked before, but now it's saying it's sealed. Is it possible to keep them unsealed?
devenv_yiDzORCrWp

Issue with DateTime Format in AOIs

Hi,

When I try to write an AOI with L5Sharp then import it, I get an error in Studio stating:

Error: Line 1250: Failed to set the 'CreatedDate' property (The parameter is incorrect.).
	RSLogix5000Content/Controller/AddOnInstructionDefinitions/AddOnInstructionDefinition[@Name="AOI_OB16_Mapping"]

The raw L5X file shows the following:

<AddOnInstructionDefinition Name="AOI_OB16_Mapping" Revision="1.1" ExecutePreScan="false" ExecutePostScan="false" ExecuteEnableInFalse="false" CreatedDate="Thu Apr 18 11:12:14 2024" CreatedBy="ProgramGenerator" EditedDate="Thu Apr 18 11:12:14 2024" EditedBy="ProgramGenerator" IsEncrypted="false" SoftwareRevision="33.0">

When I look at an L5X file that was generated with Studio, itself, the AOI header is: (notice the datetime format)

<AddOnInstructionDefinition Name="AOI_OB16_Mapping" Revision="1.1" ExecutePrescan="false" ExecutePostscan="false" ExecuteEnableInFalse="false" CreatedDate="2019-09-09T18:20:54.492Z" CreatedBy="joe.a.kelly" EditedDate="2024-03-01T18:33:47.092Z" EditedBy="joe.a.kelly" SoftwareRevision="v33.00">

Looking at the AddOnInstruction class, it looks like it's setting the DateTime string using the SetDateTime method where the format is hard-coded:

protected void SetDateTime(DateTime? value, string? format = null, [CallerMemberName] string? name = null)
{
    if (string.IsNullOrEmpty(name))
    {
        throw new ArgumentException("Name can not be null or empty", "name");
    }

    if (!value.HasValue)
    {
        Element.Attribute(name)?.Remove();
        return;
    }

    if (format == null)
    {
        format = "ddd MMM d HH:mm:ss yyyy";
    }

    string value2 = value.Value.ToString(format);
    Element.SetAttributeValue(name, value2);
}

When I correct the DateTime format, the error goes away. Maybe this is a change from different versions of studio? I'm using v33.

Adding rung to routine with no rungs

I'm trying to retrieve the collection of Rungs for a Routine that currently has no Rungs defined (it works as I expect for a routine with rungs). My L5X content was created by importing an L5X document exported from Studio 5000.

When I call routine.Content() on a routine with no rungs, it throws the following exception:

System.InvalidOperationException: 'The required attribute or child element 'RLLContent' does not exist for Routine.'

Stepping through the code and inspecting the offending routine shows that its Type is set to RLL just prior to making the call that causes the exception. If I explicitly set the Type to RLL, then the call works as I expect (which I expect is a bug). See the following:

public static LogixContainer<Rung> Rungs(this Routine routine) 
{
    LogixContainer<Rung> rungs = null;
    try
    {
        var type = routine.Type;          // This is already set to "RLL"
        rungs = routine.Content<Rung>();  // This throws an exception
    }
    catch (InvalidOperationException) 
    {
        routine.Type = RoutineType.RLL;   // explicitly re-set the type to "RLL"
        rungs = routine.Content<Rung>();  // this works as I'd expect.
        rungs.Add(new Rung("Test Rung")); // as does this
    }
    return rungs;
}

I'm guessing explicitly setting the type to RLL causes the underlying RLLContent element to be created for the Routine?
The above seems to be a work around, but is there a preferred way to initialize a collection of Rungs for a Routine?

Consumed Tag Attributes

Hey,

Thanks for providing this great project!! Even as a complete novice at C# I've been able to test some powerful concepts with it.

One thing I'm still trying to figure out, is there a way to Get/Set the Producer and RemoteTag attributes of a Consumed tag as detailed by 1756-RM014B pages 105 and 110?

Question/Issue using custom data types with existing tags.

First off, great work on the project. I was dabbling with parsing the l5x using the Rockwell provided XML schema, and I found this repo and realized you were lightyears ahead of me.

I have a project with a lot of UDTs that are often nested within each other. I'm attempting to use L5Sharp to import tags/datatypes from another project (the Studio5000 built-in tools are very clunky), and I'm encountering an issue with creating a Tag object that uses a custom data type class that I've defined. Below is what I've attempted so far.


        var content = LogixContent.Load("Aspiration_Module.L5X");

        var structTest = content.Tags().Find("Members").Member("Configuration.Development.StructTest");

        var testTag = new Tag
        {
            Name = structTest.TagName,
            Data = structTest.Data.As<StructTestUDT>()
        };

Ideally I would like to be able to lookup a tag defined in the L5X and cast it directly to my custom defined object which matches the tag data type.

I wrote a simple method to generate C# classes from existing datatypes in the L5X project.

using L5Sharp.Enums;
using L5Sharp.Types.Atomics;
using L5Sharp.Types.Predefined;
using L5Sharp.Types;
using L5Sharp;
namespace XML_Infer
{
	/// <summary>
	/// 
	///</summary>
	public class StructTestUDT : StructureType
	{
		public StructTestUDT() : base(nameof(StructTestUDT))
		{
		}
		public override DataTypeClass Class => DataTypeClass.User;
		public BOOL Bool1 { get; set; } = new();
		/// <summary>
		/// 
		///</summary>
		public BOOL Bool2 { get; set; } = new();
		/// <summary>
		/// 
		///</summary>
		public DINT RegularInt { get; set; } = new();
		/// <summary>
		/// 
		///</summary>
		public BOOL Bool2_1 { get; set; } = new();
		/// <summary>
		/// 
		///</summary>
		public BOOL Bool2_2 { get; set; } = new();
		/// <summary>
		/// 
		///</summary>
		public BOOL Bool2_3 { get; set; } = new();
		/// <summary>
		/// 
		///</summary>
	}
}

For reference, here is the xml for the datatype I generated the StrucTestUDT class from.

<DataType Name="StructTestUDT" Family="NoFamily" Class="User">
<Members>
<Member Name="ZZZZZZZZZZStructTest0" DataType="SINT" Dimension="0" Radix="Decimal" Hidden="true" ExternalAccess="Read/Write"/>
<Member Name="Bool1" DataType="BIT" Dimension="0" Radix="Decimal" Hidden="false" Target="ZZZZZZZZZZStructTest0" BitNumber="0" ExternalAccess="Read/Write"/>
<Member Name="Bool2" DataType="BIT" Dimension="0" Radix="Decimal" Hidden="false" Target="ZZZZZZZZZZStructTest0" BitNumber="1" ExternalAccess="Read/Write"/>
<Member Name="RegularInt" DataType="DINT" Dimension="0" Radix="Decimal" Hidden="false" ExternalAccess="Read/Write"/>
<Member Name="ZZZZZZZZZZStructTest4" DataType="SINT" Dimension="0" Radix="Decimal" Hidden="true" ExternalAccess="Read/Write"/>
<Member Name="Bool2_1" DataType="BIT" Dimension="0" Radix="Decimal" Hidden="false" Target="ZZZZZZZZZZStructTest4" BitNumber="0" ExternalAccess="Read/Write"/>
<Member Name="Bool2_2" DataType="BIT" Dimension="0" Radix="Decimal" Hidden="false" Target="ZZZZZZZZZZStructTest4" BitNumber="1" ExternalAccess="Read/Write"/>
<Member Name="Bool2_3" DataType="BIT" Dimension="0" Radix="Decimal" Hidden="false" Target="ZZZZZZZZZZStructTest4" BitNumber="2" ExternalAccess="Read/Write"/>
</Members>
</DataType>

I've reviewed the source pretty extensively hoping for an example, but haven't had any luck. If what I'm attempting is supported/implemented, I'd appreciate any guidance you can provide. If not, I'm happy to contribute to the project in order to help add that functionality.

Tag Data Type Modification

Hey, I just started checking out your project and it looks really great! I'm trying to use it for some simple things, and I've run into something that I can't quite figure out.

I am opening an existing L5X that has AOIs defined already. What I would like to do is simply create a tag, and set it's data type to that AOI. From what I can see, the DataType is just read-only for the tag. Looking into your code, it seems like I might have to replicate the AOI in C# class form to be able to get it to work is that right?

Is there a way to simply create a new tag and have it's DataType set to a string value?

AOI Rung Numbers

I tried importing an AOI (generated by L5Sharp), and Studio is complaining that the Number attribute in the Rung element can't be zero. I looked at the L5X and, sure enough, the Number attribute doesn't get populated. This is different behavior than a normal Routine in a Program. Studio doesn't complain about those not having Rung Numbers, but for some reason, when it comes to AOIs, it cares. This is running v33.

Updating rungs for routines

I am trying to modify the rungs in the test routine of my main program. I was able to access the "MainProgram" and the "Test" routine using the Find extension. Is there a way to modify the rungs of a routine without using the Content method to access the rungs (I cannot write the modified rungs back to the routine)?

Here is what I have currently implemented:

Program main = content.Programs.Find("MainProgram");
Routine inputs = main.Routines.Find("Test");
LogixContainer<Rung> rungs = inputs.Content<Rung>();

Please let me know if you need any more information.

Bit Descriptions

I have a tag that's an INT and I wanted to know if there was already an implementation where I can add descriptions to the individual bits (in the Comment element)

<Tag Name="DO_03" TagType="Base" DataType="INT" Radix="Decimal" Constant="false" ExternalAccess="Read/Write">
<Comments>
    <Comment Operand=".0"><![CDATA[SAFETY RESET PB ENABLE]]></Comment>
    <Comment Operand=".1"><![CDATA[FRONT GATE LATCH ENABLE]]></Comment>
    <Comment Operand=".2"><![CDATA[LEFT GATE LATCH ENABLE]]></Comment>
    <Comment Operand=".3"><![CDATA[RIGHT GATE LATCH ENABLE]]></Comment>
    <Comment Operand=".4"><![CDATA[OPERATOR WORKLIGHT ENABLE]]></Comment>
    <Comment Operand=".5"><![CDATA[SPARE]]></Comment>
    <Comment Operand=".6"><![CDATA[BOWL FEEDER 1 ENABLE(SMALL RIVETS)]]></Comment>
    <Comment Operand=".7"><![CDATA[BOWL FEEDER 2 ENABLE(LARGE RIVETS)]]></Comment>
    <Comment Operand=".8"><![CDATA[LIGHT CURTAIN ZONE INDICATOR LIGHT GREEN]]></Comment>
    <Comment Operand=".9"><![CDATA[LIGHT CURTAIN ZONE INDICATOR LIGHT RED]]></Comment>
    <Comment Operand=".10"><![CDATA[SPARE]]></Comment>
    <Comment Operand=".11"><![CDATA[SPARE]]></Comment>
    <Comment Operand=".12"><![CDATA[SPARE]]></Comment>
    <Comment Operand=".13"><![CDATA[SPARE]]></Comment>
    <Comment Operand=".14"><![CDATA[SPARE]]></Comment>
    <Comment Operand=".15"><![CDATA[SPARE]]></Comment>
</Comments>
<Data Format="L5K"><![CDATA[0]]></Data>
  <Data Format="Decorated">
    <DataValue DataType="INT" Radix="Decimal" Value="0"/>
  </Data>
</Tag>

New FBD Routine Example

I've been using the library quite a bit recently and really appreciate the work you've put into it.

One thing that I've found difficult to figure out is creating a new FBD routine and adding a sheet to it. I am able to open existing sheets and manipulate them, but I haven't quite figured out how to start one from scratch. Any advice?

Inconsistent use of bool and BOOL data type

Hi Tnunnink,

First of all... Awesome project, lots of great stuff here!

I'm having some trouble loading some L5X files that have been generated by Rockwell's Application Code Manager. I'm sure you're aware that ACM creates L5X files which are a bit inconsistent in the use of "0"/"1" or "false"/"true". Logix Designer is similarly inconsistent when importing these L5X files.

Here's an example of a controller element in an L5X file:

<Controller ... ShareUnusedTimeSlice="0" ... ReportMinorOverflow="false">

This will happily import into Logix Designer but will throw an error when loaded as a L5X object as it expects the ShareUnusedTimeSlice property to be a bool.

When changed to this:

<Controller ... ShareUnusedTimeSlice="true" ... ReportMinorOverflow="false">

The opposite is true - failing to import into Logix Designer but happily loaded as an L5X object.

I've had this problem with Controller's ShareUnusedTimeSlice property and Program's Disabled property so far.

I see the BOOL.cs class that is being used as a solution to this in a variety of places. Would be happy to make a PR where I fix some problematic properties but thought I'd first pop by to see if you had any insight to offer as to why it's not more widely used and/or if there's a better approach.

Cheers!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.