0

I have an array of a structure: myStructure[0..100]

I would like to index that structure by name.

It works by giving each index a name:

P101_AI := 9
P102_AI := 10
P103_AI := 11
P104_AI := 12

So indexing a member in the structure: myStructure[P103_AI].value (i.e. indexing myStructure[11].value)

However, is it possible to index this indirectly?

i.e. if delcaring TempString : STRING[30];

altering TempString at runtime to index the array.

Here is some pseudocade to describe what I would like to do:

FOR i:=101 TO 104 DO
   TempString := CONCAT('P',i);
   TempString := CONCAT(TempString,'_AI');
   MyStructure[ indirect(TempString)].value := 'some value';
END_FOR;
tomatoeshift
  • 465
  • 7
  • 23
  • What IDE are you using? – Sergey Romanov Feb 05 '20 at 05:21
  • @SergeyRomanov I use [B&R's Automation Studio](https://www.br-automation.com/en/products/software/automation-studio/) – tomatoeshift Feb 05 '20 at 05:25
  • Use enums as suggested or define global constants. But in your pseudocode example it is not clear why you want to do that. Why do not you use `i` directly as an index? Can you explain the task? Are you try to access a BIT only? – Sergey Romanov Feb 05 '20 at 09:00
  • I actually already used enums before I asked this question. The purpose of my question: I have sensors named from `100-199` , `200-299` etc. The sensors have the same names, but the initial number increases for each set. For iterative tasks I would loop throug all sensors in each set. I know that I could use a two-dimensional array to solve this, but then it would be semi confusing in the cod then defining `[P101][set2]`, i.e. sensor P201. – tomatoeshift Feb 05 '20 at 15:23

3 Answers3

1

What about creating an enum?

{attribute 'qualified_only'}
TYPE E_AnalogInput :
(
    P101_AI := 9,
    P102_AI,
    P103_AI,
    P104_AI
);
END_TYPE

Then you can declare:

analogInputs : ARRAY[E_AnalogInput.P101_AI..E_AnalogInput.P104_AI] OF INT;

Running a for loop:

FOR inputCount:=E_AnalogInput.P101_AI TO E_AnalogInput.P104_AI BY 1 DO
    //Do something
END_FOR

Hope this helps

Arndt
  • 98
  • 5
  • I actually already have the sensor names defined as enums. However, when I tried `ARRAY[E_AnalogInput.P101_AI..E_AnalogInput.P104_AI]`, my compiler did not accept this. It seems like it is not possible to specify a single enumn with `E_AnalogInput.P101_AI`. However, when using only `P101_AI`, the compiler reconizes the enumn. – tomatoeshift Feb 05 '20 at 15:28
  • Strange, using TwinCAT and MachineExpert (both Codesys based it works pretty good. - maybe you can try to add the attribute for qualified access? {attribute 'qualified_only'} - I added this in the answer – Arndt Feb 06 '20 at 07:37
0

I would use pointers and mapping. First, change your structure to the pointer.

TYPE MyType: STRUCT
        input: POINTER TO INT;
        value: INT;
        // other properties
    END_STRUCT
END_TYPE

Then, create a global array.

VAR_GLOBAL
    MyStructure: ARRAY[1..100] OR MyType;
END_VAR

Now in a program create one time running code.

PROGRAM PLC_PRG:
    VAR
        xInit:= FALSE;
    END_VAR

    IF NOT xInit THEN
        xInit := TRUE;
        mMap();
    END_IF
END_PROGRAM

Now in a method or action mMap do this for every array element.

MyStructure[1].input:= ADR(AI_Name);
MyStructure[2].input:= ADR(P102_AI);
MyStructure[3].input:= ADR(%ID0.1);

I used 3 different ways to bind pointer. The order is not important I think. Then in a program, you can do this.

FOR i := 1 TO 100 DO
   MyStructure[i].value := 'MyStructure[i].input^;
END_FOR;
Sergey Romanov
  • 2,949
  • 4
  • 23
  • 38
0

This is how i solved it.

TYPE infoType: STRUCT
    name: STRING[20];
    END_STRUCT
END_TYPE
TYPE sensorType: STRUCT
    value: INT;
    info:  infoType;
    END_STRUCT
END_TYPE
TYPE IO_Type: STRUCT
    AI: ARRAY[1..100] OF sensorType;
    END_STRUCT
END_TYPE
TYPE E_AnalogInput :
(
    P101_AI := 9,
    P102_AI,
    P103_AI,
    P104_AI
);
END_TYPE
PROGRAM PLC_PRG:
    VAR
        IOs: IO_Type;
    END_VAR

    IOs.AI[P101_AI].info.name := 'P101_AI';

    FOR i:=101 TO 104 DO
        TempString := CONCAT('P',i);
        TempString := CONCAT(TempString,'_AI');
        FOR i:=0 TO SIZE_OF(ADR(IOs.AI)) / SIZE_OF(ADR(IOs.AI[0]))  DO
            IF TempString = IOs.AI[i].info.name THEN
                IOs.AI[i].value := 123; // Some value
                EXIT;
            END_IF;
        END_FOR;
    END_FOR;

END_PROGRAM
tomatoeshift
  • 465
  • 7
  • 23