Home

hermsen
There is a newer version of this page. You can find it here.


Project Members:



cođź”—e: Linked List

This Page
Introduction | Usage | Download | Requirements | Acknowledgements

Introduction

Linked lists are suitable as a flexible and modular way to implement simple and powerful code with ease.
This library will allow you to leverage the simplicity, power and flexibility of linked lists.

A linked list is a data structure that represents a sequence of nodes (Elements). This library implements a so called "double linked list", which simply means that the list gives each Element pointers to both the next Element and the previous Element. Unlike an array, a linked list does not provide constant time access to a particular “index” within the list. This means that if you’d like to find the K-th element in the list, you will need to iterate through K elements. The benefit of a linked list is that you can add and remove Elements from the list during runtime so this means you can very easily extend your code with new FB's without extra coding since itteration with Elements is always done in FOR and/or WHILE loops. This means that, by design your code doesn't need to be rewritten, as demonstrated in the example below 👇

Usage

  • Insert the Library Reference in your program's library manager.
  • Declare a new FB named FB_ExtendedElement
  • We need to either to
    • A) extend ~FB_Element~ since it has been decorated as ~~~ ABSTRACT ~~~ or
    • B) implement interface ~~~ LinkedList.IElement ~~~

Tip
Any FB that will be a part of the List should preferably use method B) implement interface.
This way FB_ExtendElement will act as a baseclass for your Element without being itself of type "FB_ELEMENT". EXTENDS means "IS OF CLASS .. ", while IMPLEMENTS means "MAKES USE OF INTERFACE .. ".
If you use encapsulation and composition for the appropriate interface,you gain more freedom and more flexibility as the FB is not a CLASS of. However, the penalty taken is that this will demand more programming effort since the Interface(s) need to be implemented.

INTERFACE IElement2 EXTENDS LinkedList.IElement
METHOD ReturnInstance : POINTER TO FB_MyElement;
METHOD Count : UINT;
PROPERTY GetCount : UINT
// Get only


FUNCTION_BLOCK FB_MyElement IMPLEMENTS IElement2
VAR
    _itfPrev : IElement;
    _itfNext : IElement;
    _itfList : IList;
    _uiCount : UINT := 0;
END_VAR

// Body


METHOD IsListMemberOf : BOOL
VAR_INPUT
    itfList : IList;
END_VAR

// Body
IsListMemberOf := (itfList = THIS^._itfList);


METHOD RemoveElem : IElement

// Body
IF _itfList = 0 THEN
    // This element is not a member of a list
    RemoveElem := 0;
    RETURN;
END_IF
RemoveElem := _itfList.RemoveElem(THIS^);


PROPERTY IsLinkedElem : BOOL

// Get 
GetIsLinkedElem := (_itfList <> 0); // 0 = interface is not initialised (pointing to something)

// Set not implemented 


PROPERTY List : IList

// Get
List := _itfList;

// Set
_itfList := List;


PROPERTY NextElem : IElement

// Get
List := _itfList;

// Set
_itfList := List;


PROPERTY PrevElem : IElement

// Get
PrevElem := _itfPrev;

// Set
_itfPrev := PrevElem;


METHOD ReturnInstance : POINTER TO FB_MyElement

// Body
ReturnInstance := THIS;


METHOD Count : UINT;

// Body
_uiCount := uiCount + 1;

PROPERTY GetCount : UINT

// Get
GetCount := _uiCount;
  • Declare an instance of LIST
  • Declare an instance of FB_MyElement;
// Program
PROGRAM Main
VAR
    i : __UXINT;
    BuildList : BOOL := TRUE;
    RemoveElem: BOOL;
    List : LinkedList.List;
    El1: FB_MyElement;
    El2: FB_MyElement;
    El3: FB_MyElement;
    El4: FB_MyElement;     
    ListSize : UDINT := 0;
    itfElement : LinkedList.IElement;
    itfCurElement : IElement2;
    CurCount : UINT;
END_VAR


// Body
i := i + 1;

IF BuildList THEN // Add all elements
   List.AppendElem( El1 );
   List.AppendElem( El2 );
   List.AppendElem( El3 );
   List.AppendElem( El4 );
   BuildList := FALSE;       
END_IF

IF RemoveElem THEN // Removes the latest valid accessed element
    IF itfCurElement <> 0 THEN
        //__QUERYINTERFACE(<ITF_Source>,<ITF_Dest>);
        IF __QUERYINTERFACE( itfElement, itfCurElement ) THEN 
            List.RemoveElem( itfElement );
        END_IF;
    END_IF
    RemoveElem := FALSE;
END_IF;

ListSize := List.ListSize;
IF ListSize <> 0 THEN // not empty
    itfElement := List.HeadElem;
    IF __QUERYINTERFACE( itfElement, itfCurElement ) THEN 
        WHILE itfCurElement <> 0 DO
            FOR i := 1 TO 10 DO
            // Count gets tallied up
                itfCurElement.Count();
            END_FOR;
            CurCount := itfCurElement.GetCount;
            // Get the next element by using the pointer stored in the element itself (we can also use PrevElem to get the previous element)
            itfElement := itfCurElement.NextElem;
            __QUERYINTERFACE( itfElement, itfCurElement );
        END_WHILE
    END_IF;
END_IF

TIPS
Always obtain access to elements via the functionblock instance of List.
Element require some burnerplate-code when compared to array's but they also more flexible due to their dynamic nature.
You could opt to implement dynamic Elements 'on the fly' through use of a pre-claimed dynamic memory pool factory class. This factory reserves a pre-defined number of elements for you which you can claim or release during runtime. Just check if a new element can be claimed (is there a free lement available from the pool?), claim it, add to the list with AddElement( .. ), done.
Advantage of this type of pool is that the compiler still needs reserve the pool memory during compile phase and thus the controller does not assign dynamic memory during runtime.

Download

By downloading and using our software you abide by the MIT License

Download cođź”—e - Linked List v1.0.0.0 library

Requirements

System requirements and restrictions Info
Programming System CODESYS Development System Version >= 3.5.9.0
Runtime System CODESYS Control Version >= 3.5.9.0
Licensing open source
Required Accessories -


https://www.linkedin.com/in/hahermsen

Project Members: