I wanted to have a standard add-on instruction that would take and array (as an in_out parameter). However I wanted it to work with arrays of different sizes, so I could use the same common add-on instruction for processing any number of arrays of potentially different sizes.
After much experimentation I found an ingenious solution that seems to exploit a back door vunerability in the compiler. I thought that I would share it here in case anyone should find it interesting / useful. If any of the RSLogix developers see this then please do not block this method as I am using it!
You define the add-on instruction in_out parameter of array size 1. Actually this can be any size as long as it is not greater then the size of the source array being passed in. But a size of 1 means that it will work with any array size. The call to the add-on instrution has just the array name without a size specified.
Within the add-on instruction, you can now access array indices [2]+ without issue provided that you do not exceed the bounds of the passed-in source array (if you do then expect a major fault). Also, the array index used in the add-on instruction code has to be a variable and not a fixed number (to fool the compiler about the array size). To prevent exceeding the array bounds you have to limit the index to the bounds of the source array. You can use the size instruction (with dim_to_vary = 0) to detect the size of the passed in array and them ensure that your inex variable does not exceed this. The size instruction rather surprisingly gives the size of the passed in array and not the size of the in_out definition. I assume that this works as the add-on instruction has the address of the passed in array as in_out are passed ny refernce not value.
I am surprised that the whole scheme worked though, as I expected that the code would not compile as the index could actually outside of the range specified in the in_out parameter. It certainly will not work if a fixed number is used in place of a variable (e.g. my_arr[2]) as the compiler can check this at compile time. Obviously if a variable is used for the index this cannot be checked at compile time so is slips through the compiler checks.
Here is a worked example:-
Controller / program scope tag:-
BigArr : DINT[100]; // Source array to be accessed
Add-on instruction in_out definition:-
pArr : DINT[1]; // "Pointer" to source array
Add-on instruction local tags:-
ArraySize : DINT; // Sizeof the source array
Index : DINT; // Index into the source array
MyDint : DINT; // Loacl value for test purposes
Add-on instruction code:-
size(pArr,0,ArraySize); // Get actual size of passed in array
for Index := 0 to ArraySize do // For all array elements
MyDint := pArr[Index]; // Extract array element
end_for;
Index := 68;
MyDint := pArr[Index]; // Read specified array element
MyDint := 12345;
Index := 34;
pArr[Index] := MyDint; // Write specified array element
Add-on instruction call:-
MyAOI(AOITag,BigArr); // Call AOI passing in the source array - note no array size specified.
After much experimentation I found an ingenious solution that seems to exploit a back door vunerability in the compiler. I thought that I would share it here in case anyone should find it interesting / useful. If any of the RSLogix developers see this then please do not block this method as I am using it!
You define the add-on instruction in_out parameter of array size 1. Actually this can be any size as long as it is not greater then the size of the source array being passed in. But a size of 1 means that it will work with any array size. The call to the add-on instrution has just the array name without a size specified.
Within the add-on instruction, you can now access array indices [2]+ without issue provided that you do not exceed the bounds of the passed-in source array (if you do then expect a major fault). Also, the array index used in the add-on instruction code has to be a variable and not a fixed number (to fool the compiler about the array size). To prevent exceeding the array bounds you have to limit the index to the bounds of the source array. You can use the size instruction (with dim_to_vary = 0) to detect the size of the passed in array and them ensure that your inex variable does not exceed this. The size instruction rather surprisingly gives the size of the passed in array and not the size of the in_out definition. I assume that this works as the add-on instruction has the address of the passed in array as in_out are passed ny refernce not value.
I am surprised that the whole scheme worked though, as I expected that the code would not compile as the index could actually outside of the range specified in the in_out parameter. It certainly will not work if a fixed number is used in place of a variable (e.g. my_arr[2]) as the compiler can check this at compile time. Obviously if a variable is used for the index this cannot be checked at compile time so is slips through the compiler checks.
Here is a worked example:-
Controller / program scope tag:-
BigArr : DINT[100]; // Source array to be accessed
Add-on instruction in_out definition:-
pArr : DINT[1]; // "Pointer" to source array
Add-on instruction local tags:-
ArraySize : DINT; // Sizeof the source array
Index : DINT; // Index into the source array
MyDint : DINT; // Loacl value for test purposes
Add-on instruction code:-
size(pArr,0,ArraySize); // Get actual size of passed in array
for Index := 0 to ArraySize do // For all array elements
MyDint := pArr[Index]; // Extract array element
end_for;
Index := 68;
MyDint := pArr[Index]; // Read specified array element
MyDint := 12345;
Index := 34;
pArr[Index] := MyDint; // Write specified array element
Add-on instruction call:-
MyAOI(AOITag,BigArr); // Call AOI passing in the source array - note no array size specified.