Context
There is a VARIANT parameter in the given function block written in Siemens SCL (TIA Portal v17). This parameter addresses the pointer to a memory area. The task is to add an offset to this pointer using the integer value defined in runtime. Unfortunately, the POKE_ functions cannot be used as the offset is need to be added to the area shared via the VARIANT pointer and then pass it further.
Solution
Siemens SCL is quite static, so adding offsets to the memory area addressed via VARIANT or POINTER type is possible usually over the global unoptimized data blocks and their elements, where PEEK_ functions become available. But actually, the functionality that PEEK/POKE functions implement for the data blocks duplicates functionality of the ANY pointer type from STL. Fortunately, if one declares a variable typed as ANY, and makes an assign to it, the PLC runtime will assign to this ANY pointer the exact memory address of the right operand. Then, adding an offset to the ANY pointer could be done.
1. Declare the pointer overlaid by structures containing the offset area
t_p_RawOffsetPtr : Any;
t_st_OffsetPointer AT t_p_RawOffsetPtr : Struct
Byte1 : Byte; // Header constant
Byte2 : Byte; // Data type
Word2 : Word; // Length
Word3 : Word; // Data block key
Dword : DWord; // Offset key
END_STRUCT;
t_d_OffsetWord : DWord; // Offset key
t_st_OffsetWord AT t_d_OffsetWord : Struct
Byte1 : Byte; // Area key to preserve
Byte2 : Byte;
Byte3 : Byte;
Byte4 : Byte;
END_STRUCT;
t_b_OffsetArea : Byte;
2. Render the offset into the pointer
#t_p_RawOffsetPtr := #io_p_InputPointer; // Assign the temporary pointer: ANY or VARIANT
// Byte2 field contains the unit length code and could be used to control reading
#t_st_OffsetPointer.Word2 := #l_w_LENGTH; // Defined using units from Byte2 field
#t_d_OffsetWord := #t_st_OffsetPointer.Dword; // Retrieving offset encoding area
#t_b_OffsetArea := #t_st_OffsetWord.Byte1; // Preserving memory area code
#t_d_OffsetWord := #t_d_OffsetWord AND 16#00FFFFFF; // Setting elder byte to 0
#t_d_OffsetWord := SHR_DWORD(IN := #t_d_OffsetWord, N := 3); // Bitwise address section removal
#t_d_OffsetWord += #l_w_OFFSET; // Adding offset
// Recovery
#t_d_OffsetWord := SHL_DWORD(IN := #t_d_OffsetWord, N := 3);
#t_st_OffsetWord.Byte1 := #t_b_OffsetArea;
#t_st_OffsetPointer.Dword := #t_d_OffsetWord;
After this reassembling, the ANY pointer may be used as a value for being passed over VARIANT parameter to the function that requires pointing to memory area with runtime-defined length.