libplctag / libplctag.NET

A .NET wrapper for libplctag.
https://libplctag.github.io/
Mozilla Public License 2.0
221 stars 56 forks source link

Handling libplctag exceptions when using alternative to mappers #425

Open MountainKing91 opened 1 day ago

MountainKing91 commented 1 day ago

Hi,

I am giving a try to the approach recently added to the examples as an alternative to the mappers system. I am using version 1.5.2.

I instantiated a few tags using the "TagDint" class defined in Definitions.cs:

public class Tags
{

    public string Gateway { get; private set; }
    public TagDint PartsCount { get; private set; }
    public TagDint PartsPreset { get; private set; }

    private const string PATH = "1,0";
    private const PlcType PLC_TYPE = PlcType.Omron;
    private const Protocol PROTOCOL = Protocol.ab_eip;

    public Tags(string gateway)
    {
        this.Gateway = gateway;

        PartsCount = new TagDint()
        {
            Name = "PartsCount",
            Gateway = this.Gateway,
            Path = PATH,
            PlcType = PLC_TYPE,
            Protocol = PROTOCOL,
            AutoSyncReadInterval = TimeSpan.FromMilliseconds(500),
            Timeout = TimeSpan.FromMilliseconds(5000),
            DebugLevel = DebugLevel.Error
        };

        PartsPreset = new TagDint()
        {
            Name = "PartsPreset",
            Gateway = this.Gateway,
            Path = PATH,
            PlcType = PLC_TYPE,
            Protocol = PROTOCOL,
            AutoSyncReadInterval = TimeSpan.FromMilliseconds(500),
            Timeout = TimeSpan.FromMilliseconds(5000),
            DebugLevel = DebugLevel.Error
        };
    }
}

At this time the PLC is not connected and whenever I instantiate my Tags class, I get an ErrorNotFound exception from the Decode method of the TagDint class. While it is expected that the tag isn't to be found, I am not sure how I am supposed to handle this situation, since when using the mappers with version 1.4.0 that exception was not thrown. For reference, this is what I used with mappers:

private Tag<M, T> RegisterTag<M, T>(string name, int arrayLength, List<ITag> list) where M : IPlcMapper<T>, new()
{

var tag = new Tag<M, T>()
{
    Name = name,
    Gateway = ServiceParameters.IpAddress,
    Path = PATH,
    PlcType = PLC_TYPE,
    Protocol = PROTOCOL,
    ArrayDimensions = arrayLength > 0 ? new int[] { arrayLength } : null,
    Timeout = TimeSpan.FromMilliseconds(5000),
    AutoSyncReadInterval = TimeSpan.FromMilliseconds(100)
};

tag.ReadCompleted += Tag_ReadCompleted;
list.Add(tag);

return tag;
}

Can anybody give some insights? Thank you

timyhac commented 1 day ago

@MountainKing91 - I can't see any reason that Decode would be called from that code alone. Are you able to follow the stack trace to see what is calling it?

All the usual stuff will help, particularly logs and a repro.

MountainKing91 commented 1 day ago

And you're right, I was looking in the wrong direction - that code is not calling Decode, this one is (in another part of my app):

PartsCount = plcService.Tags.PartsCount.Value;
PartsPreset = plcService.Tags.PartsPreset.Value;

Commenting out the above code the exception is not thrown. I guess before I try to access the tag value I must make sure it is correctly initialized and its status is not < 0 ?

That is also what I actually did with mappers: looping over my tag list, I used a try-catch to initialize each tag and kept trying until GetStatus() returned 0.

timyhac commented 2 hours ago

Yes you do need to initialize a tag before using it. The only methods on Tag that trigger initialization are Initialize, Read, and their async equivalents - since you're using the inheritance example, you could add different behaviour if you want to.