Skip to content

Event Handling C#

Hello,

How can I use events with C# code? Can events and eventhandlers be used normally in C# code? Is there another way?

For example I want Output1 to become true when I press Input1 once.

I also noticed that I can assign a task type of "User Event Task" to Tasks and Events in PLCnext Engineer. How can that be used exactly?

Thank you in advance, this forum has been of HUGE help to me!

Comments

  • Yes, you should be able to use C# events in the normal way to handle and raise events. But I am not sure this will help with the requirement you mentioned.

    I want Output1 to become true when I press Input1 once.

    In C# code, you will need to check the value of the input every time the POU is called, and then set the output value based on the value of the input (and any other conditions).

    People occassionally ask us if there is something like a "hardware interrupt", i.e. a system-generated interrupt that they could use to automatically execute a method when the value of a physical input changes. The answer to that question is "no" - at the lowest level of the user program, physical inputs must be "polled" and events generated from there if necessary.

    I also noticed that I can assign a task type of "User Event Task" to Tasks and Events in PLCnext Engineer. How can that be used exactly?

    A user event task is just another type of task that will execute program instance(s) every time it runs, just like a cyclic task. Unlike a cyclic task, the user event task only runs when a "User Event" triggers it. Unfortunately there is (still) currently no easy way to trigger a user event. This was discussed in this earlier thread, which includes examples of C++ code that can be used to trigger user events:

    We are still waiting for a PLCnext Engineer function block that can trigger user events.

  • Let's say I have a program "Program" that contains a class "Modules" in which a bool variable is contained that is called "inputSwitch_1". Is there a way to connect the actual external digital Input_1 with the variable "inputSwitch_1"? Because in order to show a variable as "IN" port under GDS PORT LIST it has to be declared as [Input] at my "Program".

    I am trying to find a way to use object oriented programming but also handle events such as "inputSwitch_1" -> True/False.

  • Can you give a code snippet or a UML class diagram showing the relevant interface on the "Modules" class and how you would like an instance of the "Modules" class to be created and used by "Program", using this digital input as an example?

  • I mean something like this. I want to match PLC's digital IOs with variables inside a class. I have created the Modules class as a Function Block, I do not know if that is correct.

    I am trying to understand how I can match external PLC IOs to variables inside classes (not inside the main Program) and then raise an event every time my variables change.

    Could you maybe provide me with a simple C# example?

  • I want to match PLC's digital IOs with variables inside a class.

    You mean variables inside an object, not a class, right? Or do you want all instances of that class to use the same digital I/O?

    Where are instances of that class created? In the C# program, or in an IEC 61131 program?

  • edited May 2023

    Yes I am sorry for the confusion. I mean variables inside an object.

    And the instances of that class are created in the C# program which I attach to the Main Task in the PLCnext engineer.

    I want for example object1 to be connected to input1 and output1, object2 to be connected to input2 and output2 etc..

  • One possibility is for the Module class to include a "Process" method, which includes a list of all the I/O values as parameters. The "Process" method for each instance of "Module" would be called in the __Process method of "Program", and that's where the mapping would happen.

    Another possibility is for "Program" to pass a pointer to instance-specific I/O variable(s) as part of the "Module" constructor. The Module class would still need to have a "Process" method, but that method would use the pointer that was passed in the constructor to read/write the values of the I/O variables.

    There are probably other solutions too.

  • Could you please provide me with a C# example using the pointer method you mentioned?

  • I am not sure that this is good C# code but it compiles, runs and seems to work as expected (i.e. each Module sets the value of the Output based on the value of the Input).

    using Iec61131.Engineering.Prototypes.Common;
    using Iec61131.Engineering.Prototypes.Methods;
    using Iec61131.Engineering.Prototypes.Ports;
    using Iec61131.Engineering.Prototypes.Types;
    using Iec61131.Engineering.Prototypes.Variables;
    using System;
    using System.Iec61131Lib;
    using System.Runtime.InteropServices;
    
    
    namespace PLCnextFirmwareLibrary1
    {
        class Module
        {
            private unsafe bool* inputPointer;
            private unsafe bool* outputPointer;
    
    
            public unsafe Module (bool* inputSwitch, bool* outputSwitch)
            {
                inputPointer = inputSwitch;
                outputPointer = outputSwitch;
            }
    
    
            public void Process()
            {
                unsafe { *outputPointer = *inputPointer; }
            }
        }
    
    
        [Program]
        public class Program1
        {
            // Use the attributes [Global] and either [InputPort] or [OutputPort] to mark fields, 
            // that should exchange data with other IEC- or C#-Programs
            [Global, InputPort]
            public bool Input1 = false;
    
    
            [Global, InputPort]
            public bool Input2 = false;
    
    
            [Global, OutputPort]
            public bool Output1 = false;
    
    
            [Global, OutputPort]
            public bool Output2 = false;
    
    
            private Module Module1;
            private Module Module2;
    
    
            [Initialization]
            public void __Init()
            {
                unsafe
                {
                    fixed (bool* Input1Pointer = &Input1,
                                 Output1Pointer = &Output1,
                                 Input2Pointer = &Input2,
                                 Output2Pointer = &Output2)
                    {
                        Module1 = new Module(Input1Pointer, Output1Pointer);
                        Module2 = new Module(Input2Pointer, Output2Pointer);
                    }
                }
            }
    
    
            [Execution]
            public void __Process()
            {
                Module1.Process();
                Module2.Process();
            }
        }
    }
    
    
    

    This code is provided without warranty or including any warranty of fitness for a particular purpose.

  • This is very much to the point, thank you. Also, how could we use this code to handle event triggers when for example Input1 or Input2 changes? Could you maybe add that on the previous code as an example?

  • how could we use this code to handle event triggers when for example Input1 or Input2 changes?

    That doesn't require anything specific to PLCnext Technology. You should be able to use C# events in the normal way to handle and raise events. For example, the Program could compare the latest value of each input with the previous value, and raise an event whenever an input changes state. The "Modules" could register delegates that cause event handlers to be called for any event(s) that they are interested in. I'm not sure exactly what that would look like, but it would all be standard C#.

Sign In or Register to comment.