SCL array element copy

JOLTRON

Lifetime Supporting Member
Join Date
Aug 2006
Location
MI
Posts
692
Hello all,

I apologize for the lack of code here. This is more of a basic idea I would like to try. This is my first time dealing with SCL and just looking for a good starting point.

I could do this with STL but I hear that Array's and Indirect Addressing are much easier in SCL.

So basicly I want to create a function that I send a pointer to a DB containing an Array of 100 udt's.

And specify a Src and Dst element and copy the Src to the Dst.
The idea seems so simple yet I come up with nothing for SCL.
Do I have to create an Any pointer or can I just open a DB and access the elements directly???

Thanks for any advice,
-Joel


Code:
FUNCTION ElementCopy : VOID
TITLE = 'Copying a array element'
//This block will copy a Src element of an Array to the Dst elemtn
VAR_INPUT
  ArrayDB  : BLOCK_DB;
  Src      : Int;
  Dst      : Int;
END_VAR
BEGIN
OpenDb ArrayDB
ArrayElement[Dst] = ArrayElement[Src]
 
END_FUNCTION
 
Do you want to copy only one element of array? do you want to be able to copy any type, UDT, INT, DINT, BYTE etc?

There is no open DB in SCL.

You need to use AT command to find DB num, element lenght and address at ANY.

Then you can use WORD_TO_BLOCK_DB(DBnum).DB syntax to access elements. You need to always use byte addresses or have case statement for different lenghts. Maybe even look at using Block move sfc for moving the data, depending on lenght.

I think i do this as practice tonight, if i have time.
 
Last edited:
Do you want to copy only one element of array? do you want to be able to copy any type, UDT, INT, DINT, BYTE etc?

Correct, An array of 100 elements for operations in a machine. If a part moves from Op 5 to Op 15 . Then in the this block I would have 5 - Src and 15 - Dst.

I would like the FC to be re-usable in the long run to be able to copy UDT, or bytes, bools, anything that is feed to it.

I was thinking of using SFC20 but don't know how to format an ANY pointer in SCL.

I will look into this and also the AT command.

I downloaded some examples from the Berger book and the OSCAT examples also, but I'm affraid it looks to be over my head at the moment.

I can read and program some STL and I'm getting pretty good at VB so figured SCL would be a cake walk.
Boy was I wrong :eek:
 
This is how I could acomplish the same thing in STL.
This may be a bit overkill tho.
It's based on earlier STL code that L D[AR2,P#0.0] helped me with.

Sorry for lack of comments, was in a hurry at work. May have time tomorrow to comment it properly.

Code:
FUNCTION "ArrayElmnt2ElmntCopy" : VOID
TITLE =
VERSION : 0.1
 
VAR_INPUT
  BaseAddress : ANY ; 
  FirstElement : ANY ; 
  SrcElement : INT ; 
  DstElement : INT ; 
END_VAR
VAR_TEMP
  iSizeOfArrayElementBytes : INT ; 
  iSFC20Return : INT ; 
  iDBNumber : INT ; 
  diOverallSizeinBytes : DINT ; 
  dwBaseAddressinPtrFmt : DWORD ; 
  diUDTSizeinBytes : DINT ; 
  iNumberOfArrayElements : INT ; 
  pDst : ANY ; 
  pSrc : ANY ; 
END_VAR
BEGIN
NETWORK
TITLE =find data for overall array
      L     P##BaseAddress; 
      LAR1  ; 
      L     W [AR1,P#2.0]; 
      T     #diOverallSizeinBytes; 
      L     W [AR1,P#4.0]; 
      T     #iDBNumber; 
      L     D [AR1,P#6.0]; 
      T     #dwBaseAddressinPtrFmt; 
NETWORK
TITLE =find data for first element of array then size of the udt/array
      L     P##FirstElement; 
      LAR1  ; 
      L     W [AR1,P#2.0]; 
      T     #diUDTSizeinBytes; 
      L     #diOverallSizeinBytes; 
      TAK   ; 
      /D    ; 
      T     #iNumberOfArrayElements; 
NETWORK
TITLE =calc offset based on index
//Construct an ANY pointer for the SrcElement and DstElement
//To copy data from one element to another
      L     #SrcElement; 
      L     1; 
      -I    ; 
      L     #diUDTSizeinBytes; 
      *D    ; 
      SLD   3; 
      L     #dwBaseAddressinPtrFmt; 
      +D    ; 
      LAR1  P##pSrc; 
      T     D [AR1,P#6.0]; 
      L     #iDBNumber; 
      T     W [AR1,P#4.0]; 
      L     #diUDTSizeinBytes; 
      T     W [AR1,P#2.0]; 
      L     W#16#1002; 
      T     W [AR1,P#0.0]; 
 
      L     #DstElement; 
      L     1; 
      -I    ; 
      L     #diUDTSizeinBytes; 
      *D    ; 
      SLD   3; 
      L     #dwBaseAddressinPtrFmt; 
      +D    ; 
      LAR1  P##pDst; 
      T     D [AR1,P#6.0]; 
      L     #iDBNumber; 
      T     W [AR1,P#4.0]; 
      L     #diUDTSizeinBytes; 
      T     W [AR1,P#2.0]; 
      L     W#16#1002; 
      T     W [AR1,P#0.0]; 
 
NETWORK
TITLE =copy data
//SFC20
//pDestination is configured above
//The source block is currently hard coded(info to be stored from previous 
//station)
      CALL "BLKMOV" (
           SRCBLK                   := #pSrc,
           RET_VAL                  := #iSFC20Return,
           DSTBLK                   := #pDst);
 
END_FUNCTION
 
Last edited:
I wrote something like that in SCL, but I have never had the need for it.
It turns out that by programming 100% symbolically, you will never get in the situation that you have to decode the source ot target addresses absolutely.
It allways end up with something like
TargetDB.SomeStruct := SourceDB.SomeStruct ;

The SCL compiler will take of generating the SFC20 call(s) for you.

I'll try to locate the SCL code, but I am afraid that I have reinstalled the PC at least once since I wrote it.
 
I think the need depends on programming method. Maybe one likes to program in LAD/FBD but needs some functionality of higher level language, maybe the one is not competent with higher level languages. Then it might be justified to do one general block that can be used without need to understand inner functionality.

Also if you think about maintenace, maybe that one looking at program needs to only check when data's are moved, not how.

In the end, by learning to do the hard way, you learn lot on the way to destination.
 
It turns out that by programming 100% symbolically, you will never get in the situation that you have to decode the source ot target addresses absolutely.
It allways end up with something like
TargetDB.SomeStruct := SourceDB.SomeStruct ;

Seems like you will always end up creating new code everytime you want to work with a different size array or UDT, I may just not fully understand it at the moment. I'm looking to create so "Canned" FC's and FB's to use as a plant standard. So when we have a machine builder programming machines for us there will be some similarities. At the moment we have a builder building 4 lines for us and I'm amazed at how different they are comeing from one builder.

The SCL compiler will take of generating the SFC20 call(s) for you.
Good to konw I will have to play with that,


I think the need depends on programming method. Maybe one likes to program in LAD/FBD but needs some functionality of higher level language, maybe the one is not competent with higher level languages. Then it might be justified to do one general block that can be used without need to understand inner functionality.
As a plant standard everything is to be done in LAD unless it is absolutley neccessary or incredibly simplified in STL.

Also if you think about maintenace, maybe that one looking at program needs to only check when data's are moved, not how.
Very true also, we have PC's at the end of each line where maintenance will be able to view the logic and they will have a hard enought time with ladder logic, so don't need to have them trying to figure out STL or SCL yet :)

In the end, by learning to do the hard way, you learn lot on the way to destination.
Very true. Another reason I'm looking to do this is just to learn another language. Hopeing to figure out something that will make my life easier in the long run. I'm always looking to learn something new!
 
This might help

http://www.deltamotion.com/peter/S7/S7ug.zip

it is a library of FCs that do indirect addressing. They are meant for use by my customers that don't understand STL or SCL and just want to program in LAD. They get one item at a time. They are much simpler and leaner than setting up all the code for SFC20 but they only do one item at a time. You need to make a loop in LAD to copy many items.
 
I must be missing something here, if it's SCL then you would code it "inline"

Code:
TYPE UDT99
    STRUCT
    idata:INT;
    rdata:REAL;
    wData:ARRAY[1..32] OF WORD;
    bdata:ARRAY[1..32] OF BOOL;
    END_STRUCT
END_TYPE

DATA_BLOCK DB99
    STRUCT
    MyArrayOfUdt:ARRAY[1..10] OF udt99;
    END_STRUCT
BEGIN
END_DATA_BLOCK

FUNCTION FC99 : VOID
VAR_TEMP
    i:INT;
    j:INT;
END_VAR
    i:=1;
    j:=3;
    DB99.MyArrayOfUDT[j]:=DB99.MyArrayOfudt[i];
END_FUNCTION
 
Here's the SCL code implementation for "ArrayElmnt2ElmntCopy" previously posted in STL in post#4

Code:
FUNCTION FC99 : VOID
VAR_INPUT
  BaseAddress : ANY ; 
  FirstElement : ANY ; 
  SrcElement : INT ; 
  DstElement : INT ; 
END_VAR
VAR_TEMP
    iSFC20Return : INT ; 
    pSrc:ANY;
    pDst:ANY;
ViewSrc AT pSrc:STRUCT
    ID:BYTE;
    TYP:BYTE;
    NUM:INT;
    DBN:INT;
    PTR:DINT;
    END_STRUCT;    
ViewDst AT pDst:STRUCT
    ID:BYTE;
    TYP:BYTE;
    NUM:INT;
    DBN:INT;
    PTR:DINT;
    END_STRUCT;    
END_VAR
    pDst:=FirstElement;
    pSrc:=BaseAddress;
    Viewdst.PTR:=ViewSrc.PTR + ViewDst.NUM * 8 * (DstElement - 1);
    ViewSrc.PTR:= ViewSrc.PTR + ViewDst.NUM * 8 * (SrcElement - 1);
    ViewSrc.NUM:= ViewDst.NUM;
    iSFC20Return:=BLKMOV(SRCBLK := pSrc, DSTBLK :=  pDst);
END_FUNCTION
 
In LD's code, I think there should be added some checks, for example that the FirstElement can fit into DstElement as a multiple.
I am sure I had that coded once, but I am afraid that it is lost now.

This is the best that I can find.
The UDT is a way to dissect the elements of the ANY pointer.
Important is the type and the repeat factor.
In almost any case, the type is BYTE, but not always. If you are coding for reusable code to be used by others you should check if the type is BYTE.
The FC is just a sample of how to use the UDT.
Code:
TYPE UDT_ANYptr
    STRUCT
        byId         : BYTE ;    // always 10 Hex  
        byType       : BYTE ;    (* data type codes :
                                    00 NIL
                                    01 BOOL
                                    02 BYTE .. most, but not all ANY type accesses are type BYTE
                                    03 CHAR
                                    04 WORD
                                    05 INT
                                    06 DWORD   
                                    07 DINT     
                                    08 REAL
                                    09 DATE    
                                    0A TOD      
                                    0B TIME
                                    0C S5TIME  
                                    0E DT       
                                    13 STRING *)
        iRepeat      : INT ;     // Repetition factor
        wDBno        : WORD ;    // DB-Number
        dwPtr        :  STRUCT   // Pointer for byte and bit address
                            byte0 : BYTE ;   
                                   (* the 1st byte of dwPtr specifies the memory area:
                                    81 Inputs        
                                    82 Outputs    
                                    83 Merkers/Flags
                                    84 DB
                                    85 IDB   
                                    86 Local data (L-Stack)
                                    87 Previous local data 
                                    *)
                             byte1 : BYTE ;
                             byte2 : BYTE ;
                             byte3 : BYTE ;
                        END_STRUCT ;
    END_STRUCT ;
END_TYPE
 

FUNCTION get_ANY_info : VOID
VAR_INPUT
    anyIn : ANY ;
END_VAR
VAR_OUTPUT
    iNoOfBytes : INT ;
    strType : STRING[8] ;
    strMemArea : STRING[8] ;
    iMemArea : INT ;
END_VAR
VAR_TEMP
    tempAny : ANY ;
    anyTest AT tempAny : UDT_ANYptr ;  
    tempType : INT ;
    tempMemArea : INT ; 
    tempRepeat : INT ;
END_VAR
tempAny := anyIn ;
tempType := BYTE_TO_INT(anyTest.byType);
tempMemArea := BYTE_TO_INT(anyTest.dwPtr.byte0) ;
iMemArea := tempMemArea ; 
tempRepeat := anyTest.iRepeat ;
    CASE tempType OF
        0 : strType := 'NIL' ;
            iNoOfBytes := 0 ;
        1 : strType := 'BOOL' ;
            iNoOfBytes := (tempRepeat / 8) + 1 ; // not sure if this is correct
        2 : strType := 'BYTE' ;
            iNoOfBytes := tempRepeat ; 
        3 : strType := 'CHAR' ;
            iNoOfBytes := tempRepeat ; 
        5 : strType := 'WORD' ;
            iNoOfBytes := tempRepeat * 2 ; 
        6 : strType := 'INT' ;
            iNoOfBytes := tempRepeat * 2 ; 
        7 : strType := 'DWORD' ;
            iNoOfBytes := tempRepeat * 2 ; 
        8 : strType := 'REAL' ;
            iNoOfBytes := tempRepeat * 4 ; 
        9 : strType := 'DATE' ;
            iNoOfBytes := tempRepeat * 2 ; 
        10 : strType := 'TOD' ;
            iNoOfBytes := tempRepeat * 4 ; 
        11 : strType := 'TIME' ;
            iNoOfBytes := tempRepeat * 4 ; 
        12 : strType := 'S5TIME' ;
            iNoOfBytes := tempRepeat * 2 ; 
        13 : strType := 'DT' ;
            iNoOfBytes := tempRepeat * 8 ; 
        19 : strType := 'STRING' ;
            iNoOfBytes := tempRepeat ;  // not sure if the repeat factor is always the same as the string size.
                                        // dont know how to to test it, as transfer of a defined struct always becomes a repeat of bytes.
    ELSE:
        strType := 'undef' ;
        iNoOfBytes := 0 ; 
    END_CASE ;
    CASE tempMemArea OF
        129 : strMemArea := 'I' ;
        130 : strMemArea := 'Q' ;
        131 : strMemArea := 'M' ;
        132 : strMemArea := 'DB' ;
        133 : strMemArea := 'IDB' ;
        134 : strMemArea := 'L' ;
        135 : strMemArea := 'Prev L' ;
    ELSE:
        strMemArea := 'undef' ;
    END_CASE ;
    
END_FUNCTION
 
Maybe I'm overcomplicating it. This is a block that is in the machine that they did not provide us so I'm trying to re-create it.
Inputs:
MWA_STA_SRC = Source element of array
MWA_STA_DST = Desteination element of Array
MWA_DATA = The array


I'll do some more playing around with the code that you all have posted. Thanks for all your help so far!!!

FC801.jpg
 
It also might be that they have over simplified it, that block might be easy to use incorrectly. Also it might be that it is case depended. Atleast that block cant move udt if size of that udt aint hardcoded inside the block.

So you dont have that SCL source? In that case, if you can, maybe post stl source of that block.
 
Last edited:
Since the input is an ARRAY, and not an ANY pointer, it becomes very simple.

In SCL you can write

MWA_DATA[MWA_STA_DST] := MWA_DATA[MWA_STA_SRC] ;

NB. I sure dont like such longs symbols, and then in capitals only !
 
Yes, but then the array must be of fixed lenght. So it is very much case dependent code, and does not achieve the point of standardised general usage block. I myself think its better to have one general usage block witch function is rigorously tested with many thinkable different data combinations than to always write new blocks.
 

Similar Topics

Hello I wanna know if are some function to check what is the max value from an array or if I have to loop the array to compare all numbers to get...
Replies
4
Views
1,906
Hello, When you want compare values of an array to a range of numbers is it a right way to do that? FUNCTION ADD VAR_IN_OUT A:ARRAY[1..50]...
Replies
5
Views
2,090
Hi guys. I have a challenge that I'm struggling with and I can't help thinking there's a really easy solution. I want to move a series of...
Replies
18
Views
5,866
Hi, I just can't wrap my head around this one so all ideas and comments are more than welcome. My SCL programming skills are beginner level. What...
Replies
3
Views
1,952
Hello I am writing a small code, I have two problems populating the arrays? I am getting an error Non-existing identifier. I also need help to...
Replies
12
Views
5,947
Back
Top Bottom