Skip to content

Commit

Permalink
Fixed bug with Rung comment/text element order. Couple other small cl…
Browse files Browse the repository at this point in the history
…ean up items. Adding CodeKey.cs as a potential idea to add to LogixCode at some point (maybe).
  • Loading branch information
tnunnink committed Mar 22, 2024
1 parent 3c16bf1 commit d9c2282
Show file tree
Hide file tree
Showing 15 changed files with 235 additions and 36 deletions.
44 changes: 20 additions & 24 deletions src/.idea/.idea.L5Sharp/.idea/workspace.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

77 changes: 77 additions & 0 deletions src/L5Sharp.Core/Common/CodeKey.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
using System;

namespace L5Sharp.Core;

public readonly struct CodeKey : IEquatable<CodeKey>
{
/// <summary>
///
/// </summary>
/// <param name="container"></param>
/// <param name="routine"></param>
/// <param name="number"></param>
public CodeKey(string? container, string? routine, uint number)
{
Container = container ?? string.Empty;
Routine = routine ?? string.Empty;
Number = number;
}

/// <summary>
/// The containing program or instruction for the line of code within the project.
/// </summary>
/// <value>
/// A <see cref="string"/> representing the name of the containing program or instruction if attached.
/// If not attached to an L5X file, this will be an empty string.
/// </value>
public string Container { get; }

/// <summary>
/// The name of the routine containing the line of code within the project.
/// </summary>
/// <value>
/// A <see cref="string"/> representing the name of the containing routine if attached.
/// If not attached to an L5X file, this will be an empty string.
/// </value>
public string Routine { get; }

/// <summary>
/// The number representing the rung, line, or sheet within the routine where the code exists.
/// </summary>
public uint Number { get; }


/// <inheritdoc />
public bool Equals(CodeKey other) =>
Container.IsEquivalent(other.Container) &&
Routine.IsEquivalent(other.Routine) &&
Number == other.Number;

/// <inheritdoc />
public override bool Equals(object? obj) => obj is CodeKey other && Equals(other);

/// <inheritdoc />
public override int GetHashCode() =>
StringComparer.OrdinalIgnoreCase.GetHashCode(Container) ^
StringComparer.OrdinalIgnoreCase.GetHashCode(Routine) ^
Number.GetHashCode();

/// <summary>
/// Determines if two objects are equal.
/// </summary>
/// <param name="left">The first object to compare.</param>
/// <param name="right">The second object to compare.</param>
/// <returns><c>true</c> if the objects have the same type and name property; Otherwise, <c>false</c>.</returns>
public static bool operator ==(CodeKey left, CodeKey right) => Equals(left, right);

/// <summary>
/// Determines if two objects are not equal.
/// </summary>
/// <param name="left">The first object to compare.</param>
/// <param name="right">The second object to compare.</param>
/// <returns><c>true</c> if the objects have the same type and name property; Otherwise, <c>false</c>.</returns>
public static bool operator !=(CodeKey left, CodeKey right) => !Equals(left, right);

/// <inheritdoc />
public override string ToString() => $"{Container}/{Routine}/{Number}";
}
2 changes: 1 addition & 1 deletion src/L5Sharp.Core/Elements/Rung.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public NeutralText Text
public string? Comment
{
get => GetProperty<string>();
set => SetProperty(value);
set => SetFirstProperty(value);
}

/// <summary>
Expand Down
8 changes: 4 additions & 4 deletions src/L5Sharp.Core/L5Sharp.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@
<GenerateAssemblyInfo>true</GenerateAssemblyInfo>
<Title>L5Sharp</Title>
<Authors>Timothy Nunnink</Authors>
<Version>0.19.5</Version>
<AssemblyVersion>0.19.5</AssemblyVersion>
<FileVersion>0.19.5.0</FileVersion>
<Version>0.19.6</Version>
<AssemblyVersion>0.19.6</AssemblyVersion>
<FileVersion>0.19.6.0</FileVersion>
<Description>A library for intuitively interacting with Rockwell's L5X import/export files.</Description>
<RepositoryUrl>https://github.com/tnunnink/L5Sharp</RepositoryUrl>
<PackageTags>csharp allen-bradely l5x logix plc-programming rockwell-automation logix5000</PackageTags>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<!--<PackageIcon>icon.png</PackageIcon>-->
<RepositoryType>git</RepositoryType>
<PackageReleaseNotes>Added ComponentClass enum to component classes.</PackageReleaseNotes>
<PackageReleaseNotes>Fixed bug with Rung comment/text element order.</PackageReleaseNotes>
<Copyright>Copyright (c) Timothy Nunnink 2022</Copyright>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageId>L5Sharp</PackageId>
Expand Down
3 changes: 1 addition & 2 deletions src/L5Sharp.Core/LogixComponent.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;

Expand Down
44 changes: 44 additions & 0 deletions src/L5Sharp.Core/LogixElement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -703,6 +703,50 @@ protected void SetProperty<T>(T value, [CallerMemberName] string? name = null)

element.ReplaceWith(new XElement(name, new XCData(property)));
}

/// <summary>
/// Adds, updates, or removes the first child element with the provided value type object.
/// </summary>
/// <param name="name">The name of the property element to add, update, or remove.</param>
/// <param name="value">The value to assign to the child element. The child element is removed if the value is null.
/// Otherwise, the value is converted to its string representation, wrapped in a <see cref="XCData"/> object,
/// and assigned to the Value property of the child element.</param>
/// <typeparam name="T">The value type.</typeparam>
/// <remarks>
/// <para>
/// This method will always set the first child element directly under the element for which it is called. This is
/// important for various element types as they need to ensure the the order of child elements or properties to
/// be correctly imported.
/// </para>
/// <para>
/// This method it only available to make getting/setting data on <see cref="Element"/> as concise
/// as possible from derived classes. This method uses the <see cref="CallerMemberNameAttribute"/> so the deriving
/// classes don't have to specify the property name (assuming its the name matches the underlying element property).
/// </para>
/// </remarks>
protected void SetFirstProperty<T>(T value, [CallerMemberName] string? name = null)
{
if (string.IsNullOrEmpty(name))
throw new ArgumentException("Name can not be null or empty", nameof(name));

var property = value?.ToString();
var element = Element.Element(name);

if (property is null)
{
element?.Remove();
return;
}

if (element is null)
{
Element.AddFirst(new XElement(name, new XCData(property)));
return;
}

element.ReplaceWith(new XElement(name, new XCData(property)));
}


/// <summary>
/// Sets the complex type object of a child element, adds a child element, or removes a child element.
Expand Down
2 changes: 1 addition & 1 deletion src/L5Sharp.Core/LogixType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ public static ArrayType<TLogixType> ToArrayType<TLogixType>(this IEnumerable<TLo
if (array is null) throw new ArgumentNullException(nameof(array));
var arrayType = typeof(ArrayType<>).MakeGenericType(typeof(TLogixType));
var parameterType = typeof(TLogixType[]);
var constructor = arrayType.GetConstructor(new[] { parameterType })!;
var constructor = arrayType.GetConstructor([parameterType])!;
var parameter = Expression.Parameter(parameterType, "array");
var creator = Expression.New(constructor, parameter);
var lambda = Expression.Lambda<Func<TLogixType[], ArrayType<TLogixType>>>(creator, parameter);
Expand Down
21 changes: 17 additions & 4 deletions tests/L5Sharp.Tests/Components/TagTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,19 @@ public void Parent_FromNestedDescendantMember_ShouldBeExpected()
parent?.TagName.Should().Be("Test.Simple");
}

[Test]
public void New_NamedComplexType_ShouldHaveExpectedDataTypeAndMembers()
{
var tag = new Tag { Name = "Test", Value = new ComplexType("MyCustomType") };

tag.Add("Member01", new DINT(100));
tag.Add("Member02", new TIMER { PRE = 3000 });
tag.Add("Member03", new ComplexType("SubType"));

tag.DataType.Should().Be("MyCustomType");
tag.Members().Where(m => m.TagName.Depth == 1).Should().HaveCount(3);
}

#endregion

#region DeserializeTests
Expand Down Expand Up @@ -868,7 +881,7 @@ public Task ProduceInfo_SetNewValue_ShouldBeVerified()

return VerifyXml(xml);
}

[Test]
public Task ConsumeInfo_SetNewValue_ShouldBeVerified()
{
Expand All @@ -889,14 +902,14 @@ public Task ConsumeInfo_SetNewValue_ShouldBeVerified()
}

#endregion

[Test]
public Task Class_SetValidValue_ShouldBeVerified()
{
var tag = new Tag { Name = "Test", Class = ComponentClass.Safety, Value = 100};
var tag = new Tag { Name = "Test", Class = ComponentClass.Safety, Value = 100 };

var xml = tag.Serialize().ToString();

return VerifyXml(xml);
return VerifyXml(xml);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<Rung Type="N">
<Text></Text>
</Rung>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<Rung Type="N">
<Text>XIC(MyTag)[OTE(SomeOutput)TMR(TimerTag,?,?)];</Text>
</Rung>
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<Rung Type="N">
<Comment>This is a test comment</Comment>
<Text>AFI;</Text>
</Rung>
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<Rung Type="N">
<Comment>This is a test comment</Comment>
<Text></Text>
</Rung>
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<Rung Type="N">
<Comment>This is a test comment</Comment>
<Text>AFI;</Text>
</Rung>
Loading

0 comments on commit d9c2282

Please sign in to comment.