You are on page 1of 3

My investigation into the use of Siemens Step-7 ANY pointers began with the need to convert an array of characters

into a string. The task sounded simple enough. I was to receive a NULL (Hex 00) terminated block of characters through an Ethernet-I/O to DP coupler and I needed to copy these characters into a string and set the string length. I knew that if I passed pointers to the input array of characters and the output string to an STL function, the process should be fairly easy. This led me down an education path that I hadn't planned on. All of the information needed is buried in the Siemens documentation, but it was difficult for me to put it all together. One simple example could have explained the whole story and saved an entire day trial and error until I fully understood how to accomplish the task. First a short review on ANY pointers. ANY pointers are NOT pointers in the sense that they are an address that points to data as is the case in "C" or assembly language. Siemens pointers (both regular pointers and ANY pointers) are actually structures that contain a memory area identifier and an index (address) into that particular memory area. In the case of an ANY pointer, the full description is: Byte 0 1 2-3 4-5 6-9 Description 10H for Step 7 - Block Identifier Data Type Repetition Factor Block Number (in the case of a Data Block) Pointer To The Data. This is actually an index into a particular memory area

For a full description of ANY pointers, refer to the Siemens "Programming With Step-7" manual. Secondly, a short review on parameters when calling a function. When a function is called with an ANY pointer as an input, output, or InOut parameter, the ANY pointer is not actually passed to the function. The address of the ANY pointer structure is passed to the function. In a way, it is a double indirection. The function gets a pointer to the pointer that points to the data. Another way of looking at it is that the function receives a pointer to a structure that contains the ANY pointer data. In order to be able to use the ANY pointer, we must first extract the parts of the any pointer that we are interested in. In the application shown below, it is assumed that both the input and the output data would be contained in Data Blocks. Therefore, the data type is not extracted from the ANY pointer data block. However, the data block number (bytes 4-5) as well as the data index (bytes 6-9) are extracted so that the Data Blocks can be opened and the indexes can be transferred into the address registers (AR1 and AR2). Strings. Strings are arrays of characters (bytes) with the first byte being the maximum length possible for the string (the defined size when the string was declared or created). The second byte indicates the length of the current string contained in the variable. The actual data for the string starts at the third byte. For details on strings, see the "Programming With Step-7" manual. A couple of quick notes about the application below. The application only works if both the input and output data are contained in Data Blocks. If other data areas need to be supported, the application will need to be expanded. FUNCTION "CharsToS" : VOID TITLE = AUTHOR : JDK VERSION : 0.1 VAR_INPUT InChars : ANY ; END_VAR VAR_OUTPUT OutString : ANY ; END_VAR VAR_TEMP

// The Block Number Was Extracted From The Any Pointer By Loading The DB Number Into The Accumulator // And Then Storing It Into A Temporary Variable. NullIndex : BYTE . the function will continue to fill the //output string until the maximum string length is reached. CharsLength : WORD . Extract the Repetition from the ANY pointer (in our case.P#4.0]. // Open The Data Block. // Move The Pointer To The Any Pointer Into AR1 // AR1 (Address Register 1) contains the address of the ANY pointer (AR1 Contains a pointer to the block of data // known as the ANY pointer).CharsBlock : WORD . // Load Data Block Number Contained In The Any Pointer T #StringBlock. // Move The Pointer To The Any Pointer Into AR1 // AR1 Now Contains The Address Of The Any Pointer. I Was Hoping To Just Open The Data Block Using The Number // In The Accumulator And Not Have To Store It In A Temporary Variable. // Save The String Pointer Into A Local Temp DWord L P##OutString. // Load Data Block Number Contained In The Any Pointer T #CharsBlock. // Save Block Number In Temp Word Variable OPN DI [#StringBlock]. // Open The Data Block.P#2. Extract The Block Number And Address // (Offset Pointer Into The Data Block) From The Any Pointer L W [AR1. // Get The Address Of The Any Pointer LAR1 .0].P#4. StringBlock : WORD . // Save Block Number In Temp Word Variable OPN DB [#CharsBlock]. Extract The Block Number And Address // (Offset Pointer Into The Data Block) From The Any Pointer L W [AR1. // Extract The Offset Pointer Into The Data Block By // Loading The Value Into The Accumulator T #CharsPointer. //The function will look for the NULL and set the current string length. StringTotalLength : WORD . number of bytes) L W [AR1. L D [AR1. StringLength : BYTE . CharsPointer : DWORD . // Extract The Offset Pointer Into The Data Block By // Loading The Value Into The Accumulator . // Load Repetition (Num Of Bytes In Our Case) Contained In The Any Pointer T #CharsLength. // Get The Address Of The Any Pointer LAR1 .0]. // L P##InChars. END_VAR BEGIN NETWORK TITLE = //This function will copy characters from a byte array and put them into a string.P#6. If the //input string does NOT contain a NULL. L D [AR1. The Data Block Was Then Opened With The Open Command // With The Temporary Variable As The DB Number.0]. StringPointer : DWORD . But Never Figured Out The Syntax.0]. // Save Number Of Characters In Temp Word Variable // AR1 Now Contains The Address Of The Any Pointer.P#6. //The character array should be a NULL (Hex 00) terminated group of characters.

0. // Compare Character To Null JC Exit.0]. And Try Next Character L #NullIndex.P#0. INC 1.0]. JC Exit. This Ensures ENO Will Be On For Chaining The Function In Ladder BE . // Load 0 For Comparison ==I . T #NullIndex. // Initialize Current String Length To Maximum Length L 0. // Load NullIndex T DIB [AR2. // Save RLO Into BR. // Exit routine END_FUNCTION . Exit: L #StringPointer. T #NullIndex. ==I . // Be Sure RLO Is On Prior To Exit SAVE . // Increment Character Pointer To Next Character +AR2 P#1. // Load pointer to beginning of string LAR2 . T #StringLength. // Increment Address Pointer To First Byte Of String (After Max. String is at maximum length. // Move pointer to address register L #NullIndex. Length and Length) Rep1: L DBB [AR1. No Nulls Found +AR1 P#1. // Load Next Character From Input T DIB [AR2. // Transfer The String Pointer Into Address Register 2 L #CharsPointer. T DIB [AR2.0].0.P#0. // Store NullIndex at current length of string SET .0].P#1. L DIB [AR2.T #StringPointer.P#1. // Initialize NullIndex To 0 +AR2 P#2.0]. LAR1 . Check For End Of String. Exit Routine // We Haven't Found The Null Character Yet. L #StringLength. // Found Null. // Increment String Pointer To Next Location In String JU Rep1. // Store Character In String Output L 0. // Jump if end of string.0.P#0. // Save The String Pointer Into A Local Temp DWord LAR2 . Increment The Index.