//This file was generated by the LASAL2 CodeGenerator  -- 
//Please, do not edit this file (it might be overwritten by the next generator run)
//{{LSL_DECLARATION
#include <.\lsl_st_mt.h>

(*!
<Class
	Name               = "MerkerEx"
	Revision           = "1.22"
	GUID               = "{BDB200DC-DF69-42A8-8520-CB45026F10E9}"
	RealtimeTask       = "false"
	CyclicTask         = "false"
	BackgroundTask     = "false"
	Sigmatek           = "true"
	OSInterface        = "false"
	HighPriority       = "false"
	Automatic          = "false"
	UpdateMode         = "Prescan"
	IconPath           = ".\Class\MerkerEx\aMerkerEX.ICO"
	SharedCommandTable = "true"
	Objectsize         = "(284,120)"
	Comment            = "storage of data with arbitrary length">
	<Channels>
		<Server
			Name           = "m_udLength"
			GUID           = "{A501DB60-4755-4B0D-804B-5150CD0ECAC5}"
			Visualized     = "true"
			Initialize     = "true"
			WriteProtected = "false"
			Retentive      = "false"
			Comment        = "length of the data buffer">
			<NewInst>
				<Function Name="GET_DATA_PTR">
				</Function>
				<Function Name="EXCHANGE_DATA_PTR">
				</Function>
				<Function Name="SAVE_DATA_TO_RAMEXFILE">
				</Function>
			</NewInst>
		</Server>
		<Client Name="ThreadSafe" Required="false" Internal="false" DefValue="0" Comment="client is used to ensure threadsafe accsess to data&#13;&#10;set client to 1 to get threadsafe data&#13;&#10;on the other hand (default = 0) there will be no treadsafety at dataaccess&#13;&#10;note: do not connect client !"/>
	</Channels>
	<Dependencies>
		<Files>
			<File Path=".\lsl_st_mt.h" Include="true"/>
		</Files>
	</Dependencies>
	<RevDoku>
		<Owner Company="sigmatek" Author="fimluc"/>
		<Dokumentation Revision="1.22" Date="2018-04-24" Author="kolott" Company="sigmatek" Description="DEVSW-462: Problem with CIL-Interface fixed when using option &quot;ThreadSafe&quot;"/>
		<Dokumentation Revision="1.21" Date="2015-12-03" Author="fimluc" Company="sigmatek" Description="MerkerEx CalcCrc changed to ordinary counter because of performance issues"/>
		<Dokumentation Revision="1.20" Date="2015-09-25" Author="fimluc" Company="sigmatek" Description="All global functions are virtual now."/>
		<Dokumentation Revision="1.18" Date="2014-04-24" Author="kolott" Company="sigmatek" Description="ThreadSafeViolation Message disabled"/>
		<Dokumentation Revision="1.17" Date="2014-04-16" Author="kolott" Company="sigmatek" Description="Set Required Flag of Client ThreadSafe to false"/>
		<Dokumentation Revision="1.16" Date="2014-03-14" Author="kolott" Company="sigmatek" Description="Client ThreadSafe added"/>
		<Dokumentation Revision="1.15" Date="2014-02-13" Author="spimar" Company="sigmatek" Description="size is also set if no mem available"/>
		<Dokumentation Revision="1.14" Date="2013-10-01" Author="spimar&#13;&#10;kolott" Company="sigmatek" Description="Initialize memory with initvalue is possible again"/>
		<Dokumentation Revision="1.13" Date="2013-09-04" Author="kolott" Company="sigmatek" Description="Bugfix RuntimeWatchdog II"/>
		<Dokumentation Revision="1.12" Date="2013-08-23" Author="kolott" Company="sigmatek" Description="Bugfix RuntimeWatchdog"/>
		<Dokumentation Revision="1.11" Date="2013-04-08" Author="kolott" Company="sigmatek" Description="ARM-Ready"/>
		<Dokumentation Revision="1.10" Date="2012-12-17" Author="feshar" Company="Sigmatek" Description="New NewInst for RamImage tool if RamEx objects are using file storage."/>
		<Dokumentation Revision="1.2" Date="2012-05-03" Author="feshar" Company="Sigmatek" Description="Changes for RamEx file storage."/>
		<Dokumentation Revision="1.1" Date="2011-09-28" Author="Spimar" Company="Sigmatek" Description="The input and output parameters of the server write methods  are now fitted to the datatype of the server;"/>
	</RevDoku>
</Class>
*)
MerkerEx : CLASS
	TYPE
	  Cmdm_udLength :  //! <Type Public="true" Name="Cmdm_udLength"/>
	  (
	    GET_DATA_PTR,
	    EXCHANGE_DATA_PTR,
	    SAVE_DATA_TO_RAMEXFILE
	  )$UINT;
	END_TYPE
  //Servers:
	m_udLength 	: SvrChCmd_UDINT;
  //Clients:
	ThreadSafe 	: CltCh_DINT;
  //Variables:
		m_pData 	: ^USINT;			//! <Variable Comment="pointer to data of variable length" Name="m_pData"/>
		m_udGrowBy 	: UDINT;			//! <Variable Comment="alloc memory in pieces of n bytes" Name="m_udGrowBy"/>
		m_udAllocated 	: UDINT;			//! <Variable Comment="size of allocated block of memory" Name="m_udAllocated"/>
		m_udCrc 	: UDINT;
		m_MuxHdl 	: ^void;
		m_MuxIfc 	: ^LSL_MT_TYPE;
  //Functions:
				//! <Function Comment=" 22.06.2004 in New_inst auch EXCHANGE_DATA_PTR dazugebaut weil Billion nicht &#13;&#10; ramex sondern Merkerex für die IPRs benutzt!! &#13;&#10; the constructor allocates memory, if the m_udLength&#13;&#10; data element is set, otherwise it just returns OK&#13;&#10;Wenn das Datenelement m_udLength initialisiert worden ist,&#13;&#10;dann wird Speicher angefordert, sonst einfach C_OK zurück-&#13;&#10;geliefert.&#13;&#10;" Name="MerkerEx"/>
	FUNCTION MerkerEx
		VAR_OUTPUT
			ret_code 	: ConfStates;			//! <Variable Comment="Zeiger auf den internen Datenpuffer" Name="MerkerEx.ret_code"/>
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL Init;
				//! <Function Comment="Use this function to change the size of the data buffer&#13;&#10;Diese Funktion kann die Größe des Datenpuffers ändern.&#13;&#10;" Name="SetSize"/>
	FUNCTION VIRTUAL GLOBAL SetSize
		VAR_INPUT
			udSize 	: UDINT;			//! <Variable Comment="needing this size of memory" Name="SetSize.udSize"/>
		END_VAR
		VAR_OUTPUT
			ret_code 	: ConfStates;
		END_VAR;
				//! <Function Comment=" Use this function to change a part of the data buffer.&#13;&#10; Call SetSize before, to make sure, the internal data buffer is&#13;&#10; sufficiently big.&#13;&#10;Mit dieser Funktion kann ein Teil des internen Datenpuffers&#13;&#10;beschrieben werden. Um sicherzustellen, daß ausreichend Speicher&#13;&#10;zur Verfügung steht, muß vorher ggf. SetSize() aufgerufen werden.&#13;&#10;" Name="SetDataAt"/>
	FUNCTION VIRTUAL GLOBAL SetDataAt
		VAR_INPUT
			pData 	: ^USINT;			//! <Variable Comment="pointer to a new block of memory" Name="SetDataAt.pData"/>
			udSize 	: UDINT;			//! <Variable Comment=" Anzahl der zu kopierenden Bytes" Name="SetDataAt.udSize"/>
			udAt 	: UDINT;			//! <Variable Comment=" start copy at this offset in the internal buffer" Name="SetDataAt.udAt"/>
		END_VAR
		VAR_OUTPUT
			ret_code 	: ConfStates;
		END_VAR;
				//! <Function Comment=" Call this function, to get back a certain part from&#13;&#10; the stored data&#13;&#10; Mit dieser Funktion kann ein bestimmter Teil des internen Daten-&#13;&#10;puffers zurückgelesen werden.&#13;&#10;" Name="GetDataAt"/>
	FUNCTION VIRTUAL GLOBAL GetDataAt
		VAR_INPUT
			pData 	: ^USINT;			//! <Variable Comment=" Zeiger auf einen ausreichend großen Ziel-Datenpuffer" Name="GetDataAt.pData"/>
			udSize 	: UDINT;
			udAt 	: UDINT;			//! <Variable Comment=" Start-Offset für den Kopiervorgang" Name="GetDataAt.udAt"/>
		END_VAR
		VAR_OUTPUT
			ret_code 	: ConfStates;
		END_VAR;
				//! <Function Comment=" This function can be called to initialize the&#13;&#10; data buffer with 0&#13;&#10;  Mit dieser Funktion wird der Datenpuffer ab einem bestimmten&#13;&#10; Offset mit 0 initialisiert.&#13;&#10; [&lt;udStartOff] Initialisierung ab diesem Offset&#13;&#10;" Name="ZeroMemory"/>
	FUNCTION ZeroMemory
		VAR_INPUT
			udStartOff 	: UDINT;			//! <Variable Comment=" start to init at this offset" Name="ZeroMemory.udStartOff"/>
		END_VAR;
				//! <Function Comment=" Mit dieser Funktion kann der gesamte interne Datenpuffer des&#13;&#10; Objekts gesetzt werden. Die Funktion erwartet sich einen Zeiger auf&#13;&#10; einen Datenpuffer mit der Größe des internen Puffers. Exakt diese&#13;&#10; Datenmenge wird dann nämlich auf den internen Puffer umkopiert.&#13;&#10; this is the function that enables the user to&#13;&#10; set all the data of the data buffer. The function expects a&#13;&#10; pointer to a data buffer with at least the size&#13;&#10; of the internal data buffer, exactly the size of the internal&#13;&#10; buffer is copied from the source&#13;&#10;" Name="SetData"/>
	FUNCTION VIRTUAL GLOBAL SetData
		VAR_INPUT
			pData 	: ^USINT;
		END_VAR;
				//! <Function Comment="returns the size of the internal data buffer in bytes&#13;&#10;Liefert die Größe des internen Datenpuffers.&#13;&#10;" Name="GetSize"/>
	FUNCTION VIRTUAL GLOBAL GetSize
		VAR_OUTPUT
			udSize 	: UDINT;
		END_VAR;
				//! <Function Comment=" Call this function to get all the data back from&#13;&#10; the internal buffer.&#13;&#10;  Diese Funktion kopiert den Inhalt des internen Datenpuffers auf&#13;&#10; den bereitgestellten Puffer um.&#13;&#10;" Name="GetData"/>
	FUNCTION VIRTUAL GLOBAL GetData
		VAR_INPUT
			pData 	: ^USINT;
		END_VAR;
				//! <Function Comment="The function returns the pointer to the internal data buffer of the MerkerEx object. The&#13;&#10;results of this function may vary between different calls to this function due to calls&#13;&#10;to the SetSize function inbetween.&#13;&#10;Therefore it&apos;s not recommanded to access the internal data buffer by means of this&#13;&#10;function!&#13;&#10;Die Funktion liefert einen Zeiger auf den internen Datenpuffer des MerkerEx-&#13;&#10;Objekts zurück. Wenn zwischen einzelnen Aufrufen dieser Funktion die&#13;&#10;Funktion SetSize aufgerufen wird, dann kann sich dieser Zeiger verändern.&#13;&#10;Daher wird der Zugriff auf diesen Puffer nicht empfohlen!&#13;&#10;" Name="GetDataPtr"/>
	FUNCTION VIRTUAL GLOBAL GetDataPtr
		VAR_OUTPUT
			pData 	: ^USINT;			//! <Variable Comment="pointer to internal data buffer" Name="GetDataPtr.pData"/>
		END_VAR;
				//! <Function Comment="Use this function to assign a new block of memory to the&#13;&#10;MerkerEx - object. m_udLength has to be changed simultaniously.&#13;&#10;" Name="SetDataPtr"/>
	FUNCTION VIRTUAL GLOBAL SetDataPtr
		VAR_INPUT
			pData 	: ^void;
		END_VAR;
				//! <Function Comment="[#ENGLISH]&#13;&#10;To make memory allocation more efficient, one can set the value&#13;&#10;udGrowBy. Memory will the be allocated in pieces of udGrowBy-bytes,&#13;&#10;instead of allocating only the exactly needed number of bytes.&#13;&#10;In this way calls to the OS-memalloc function can be saved.&#13;&#10;" Name="SetGrowBy"/>
	FUNCTION VIRTUAL GLOBAL SetGrowBy
		VAR_INPUT
			udGrowBy 	: UDINT;			//! <Variable Comment="grow mem block in pieces of n bytes" Name="SetGrowBy.udGrowBy"/>
		END_VAR;
				//! <Function Comment="[#ENGLISH]&#13;&#10;function does the memory allocation&#13;&#10;" Name="Alloc"/>
	FUNCTION VIRTUAL GLOBAL Alloc
		VAR_INPUT
			udSize 	: UDINT;
		END_VAR
		VAR_OUTPUT
			pCode 	: ^void;			//! <Variable Comment="pointer to allocated block" Name="Alloc.pCode"/>
		END_VAR;
				//! <Function Comment="[#ENGLISH]&#13;&#10;checks for udGrowBy and calculates the size of memory&#13;&#10;which is actually to allocate&#13;&#10;" Name="GetNewBlockSize"/>
	FUNCTION AWL GetNewBlockSize
		VAR_INPUT
			udSize 	: UDINT;
		END_VAR
		VAR_OUTPUT
			bAlloc 	: BOOL;			//! <Variable Comment="is it necessary to alloc a new block?" Name="GetNewBlockSize.bAlloc"/>
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL UpdateToFile;
	
	FUNCTION GetAllocSize
		VAR_INPUT
			size 	: UDINT;
			block 	: UDINT;
		END_VAR
		VAR_OUTPUT
			retcode 	: UDINT;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL LockOn;
	
	FUNCTION VIRTUAL GLOBAL LockOff;
	
	FUNCTION SetSizeCTor
		VAR_INPUT
			udSize 	: UDINT;
		END_VAR
		VAR_OUTPUT
			retcode 	: ConfStates;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL ObjectTraceMessage
		VAR_INPUT
			txt 	: ^CHAR;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL GetCRC
		VAR_OUTPUT
			udCRC 	: UDINT;
		END_VAR;
	
	FUNCTION HexChar
		VAR_INPUT
			hxindex 	: USINT;
		END_VAR
		VAR_OUTPUT
			retcode 	: USINT;
		END_VAR;
	
	FUNCTION CalcCRC;
				//! <Function Comment="[#ENGLISH]&#13;&#10;" Name="m_udLength.NewInst"/>
	FUNCTION VIRTUAL GLOBAL m_udLength::NewInst
		VAR_INPUT
			pPara 	: ^CmdStruct;
			pResult 	: ^results;
		END_VAR
		VAR_OUTPUT
			ret_code 	: iprStates;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL m_udLength::Read
		VAR_OUTPUT
			output (EAX) 	: UDINT;
		END_VAR;
  //Tables:
	FUNCTION @STD
		VAR_OUTPUT
			ret_code	: CONFSTATES;
		END_VAR;
	FUNCTION GLOBAL TAB @CT_;
END_CLASS;

//}}LSL_DECLARATION


FUNCTION GLOBAL TAB MerkerEx::@CT_
0$UINT,
2#0100000000000000$UINT, //TY_MERKEREX
1$UINT, 22$UINT, (SIZEOF(::MerkerEx))$UINT, 
1$UINT, 1$UINT, 0$UINT, 
TO_UDINT(2225119864), "MerkerEx", //Class
TO_UDINT(0), 0, 0$UINT, 0$UINT, //Baseclass
//Servers:
(::MerkerEx.m_udLength.pMeth)$UINT, _CH_CMD$UINT, 2#0000000000000000$UINT, TO_UDINT(3370139294), "m_udLength", 
//Clients:
(::MerkerEx.ThreadSafe.pCh)$UINT, _CH_CLT_DATA$UINT, 2#0000000000000000$UINT, TO_UDINT(1443724377), "ThreadSafe", 
END_FUNCTION


#define USER_CNT_MerkerEx 15

TYPE
	_LSL_STD_VMETH	: STRUCT
			CmdTable	: CMDMETH;
			UserFcts	: ARRAY[0..USER_CNT_MerkerEx] OF ^Void;
	END_STRUCT;
END_TYPE

FUNCTION MerkerEx::@STD
	VAR_OUTPUT
		ret_code	: CONFSTATES;
	END_VAR
	VAR
		vmt	: _LSL_STD_VMETH;
	END_VAR

	//Command Methods
	InitCmdTable (nCmd := nSTDCMD + USER_CNT_MerkerEx, pCmd := #vmt.CmdTable);
	vmt.CmdTable.NewInstr		:= #NewInst();
	vmt.CmdTable.Read		:= #Read();
	vmt.CmdTable.Write		:= #M_WR_DIRECT();
	vmt.CmdTable.Init		:= #Init();
#pragma warning (disable : 74)
	vmt.UserFcts[0]		:= #SetSize();

#pragma warning (default : 74)
#pragma warning (disable : 74)
	vmt.UserFcts[1]		:= #SetDataAt();

#pragma warning (default : 74)
#pragma warning (disable : 74)
	vmt.UserFcts[2]		:= #GetDataAt();

#pragma warning (default : 74)
#pragma warning (disable : 74)
	vmt.UserFcts[3]		:= #SetData();

#pragma warning (default : 74)
#pragma warning (disable : 74)
	vmt.UserFcts[4]		:= #GetSize();

#pragma warning (default : 74)
#pragma warning (disable : 74)
	vmt.UserFcts[5]		:= #GetData();

#pragma warning (default : 74)
#pragma warning (disable : 74)
	vmt.UserFcts[6]		:= #GetDataPtr();

#pragma warning (default : 74)
#pragma warning (disable : 74)
	vmt.UserFcts[7]		:= #SetDataPtr();

#pragma warning (default : 74)
#pragma warning (disable : 74)
	vmt.UserFcts[8]		:= #SetGrowBy();

#pragma warning (default : 74)
#pragma warning (disable : 74)
	vmt.UserFcts[9]		:= #Alloc();

#pragma warning (default : 74)
#pragma warning (disable : 74)
	vmt.UserFcts[10]		:= #UpdateToFile();

#pragma warning (default : 74)
#pragma warning (disable : 74)
	vmt.UserFcts[11]		:= #LockOn();

#pragma warning (default : 74)
#pragma warning (disable : 74)
	vmt.UserFcts[12]		:= #LockOff();

#pragma warning (default : 74)
#pragma warning (disable : 74)
	vmt.UserFcts[13]		:= #ObjectTraceMessage();

#pragma warning (default : 74)
#pragma warning (disable : 74)
	vmt.UserFcts[14]		:= #GetCRC();

#pragma warning (default : 74)
	m_udLength.pMeth		:= StoreCmd (pCmd := #vmt.CmdTable, SHARED);

	IF m_udLength.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	ret_code	:= MerkerEx();

END_FUNCTION

//{{LSL_IMPLEMENTATION

#include <RTOS_MemIntern.h>
//#include <lsl_st_mt.h>
#include <rtos_privheader.h>

//VAR_PRIVATE
//  merker_muxifc : ^LSL_MT_TYPE;
//END_VAR

FUNCTION MerkerEx::MerkerEx
  VAR_OUTPUT
    ret_code		: CONFSTATES;
  END_VAR

  m_MuxIfc := NIL;
  m_MuxHdl := NIL;
//  LockCnt       := 0;
  m_udCrc  := 0;

//  if(IsClientConnected(#ThreadSafe)) then
//    ObjectTraceMessage("do not connect client 'ThreadSafe'");
//    ret_code := C_SYNTAX_ERROR;
//    return;
//  end_if;
  
	SetGrowBy(m_udGrowBy);
	ret_code := SetSizeCTor(m_udLength);
  
  CalcCRC();

END_FUNCTION

FUNCTION VIRTUAL GLOBAL MerkerEx::ObjectTraceMessage
	VAR_INPUT
		txt 	: ^CHAR;
	END_VAR
  var
    msg : array[0..255] of char;
    pObj : ^OBJ;
  end_var

  pObj := LSL_GetHdr(this);
  _strcpy(#msg[0], txt);
  _strcat(#msg[0], " at object ");
 
 #pragma warning (disable:137)
  _strcat(#msg[0], #pObj^.pObjDsc^.SymName.Text[0]);
 #pragma warning (default:137)
  TRACE(#msg[0]);
  LSLCLI_LoaderTracePrint(#msg[0], 15);

END_FUNCTION

(*
FUNCTION GLOBAL MerkerEx::HasToBeThreadSafe

  ObjectTraceMessage("ThreadSafeViolation");

END_FUNCTION
*)
FUNCTION VIRTUAL GLOBAL MerkerEx::LockOn
  
  if(m_MuxHdl <> NIL) then
    m_MuxIfc^.MT_Wait$P_MT_Wait(m_MuxHdl);
//  else
//    if(LockCnt <> 0) then
//      HasToBeThreadSafe();
//    end_if;
//    LockCnt += 1;
  end_if;
  
END_FUNCTION

FUNCTION VIRTUAL GLOBAL MerkerEx::LockOff
  
  if(m_MuxHdl <> NIL) then
    m_MuxIfc^.MT_Signal$P_MT_Signal(m_MuxHdl);
//  else
//    LockCnt -= 1;
//    if(LockCnt <> 0) then
//      HasToBeThreadSafe();
//    end_if;
  end_if;
  
END_FUNCTION

FUNCTION MerkerEx::HexChar
  VAR_INPUT
    hxindex : USINT;
  END_VAR
  VAR_OUTPUT
    retcode : USINT;
  END_VAR
  VAR
  	ph : ^USINT;
  END_VAR
  
  ph      := "0123456789ABCDEF";
  ph      += hxindex and 16#0F;
  retcode := ph^;

END_FUNCTION

FUNCTION VIRTUAL GLOBAL MerkerEx::Init
  VAR
  	label : array[0..16] of usint;
    tmp : udint;
  END_VAR

  if(ThreadSafe <> 0) then

    if(m_MuxIfc = nil) then
      OS_CILGet("LSL_MULTITASK", #m_MuxIfc$void);
    end_if;

    if(m_MuxIfc <> NIL) then
      if(m_MuxHdl = NIL) then
        tmp$^MerkerEx := this;
        label[0]$udint := 16#5F78754D; // Mux_
        label[4]       := HexChar(to_usint(tmp shr 28));
        label[5]       := HexChar(to_usint(tmp shr 24));
        label[6]       := HexChar(to_usint(tmp shr 20));
        label[7]       := HexChar(to_usint(tmp shr 16));
        label[8]       := HexChar(to_usint(tmp shr 12));
        label[9]       := HexChar(to_usint(tmp shr  8));
        label[10]      := HexChar(to_usint(tmp shr  4));
        label[11]      := HexChar(to_usint(tmp       ));
        label[12]      := 0;
    
        m_MuxHdl := m_MuxIfc^.MT_CreateSemaphore$P_MT_CreateSemaphore(MTSEMATYPE_MUTEX, 1, 0, #label[0]);
      end_if;
    end_if;
  end_if;

END_FUNCTION

FUNCTION VIRTUAL GLOBAL MerkerEx::SetGrowBy
	VAR_INPUT
		udGrowBy 	: UDINT;
	END_VAR

  if(udGrowBy <= 1) then
    m_udGrowBy := 1;
  elsif(udGrowBy > 100000) then // just an arbitrary limitation
    m_udGrowBy := 100000;
  else
    m_udGrowBy := udGrowBy;
  end_if;

END_FUNCTION

FUNCTION MerkerEx::GetAllocSize
  VAR_INPUT
    size : UDINT;
    block : UDINT;
  END_VAR
  VAR_OUTPUT
    retcode : UDINT;
  END_VAR

  retcode := size;
  if(block > 1) then
    retcode := size + block - 1;
    retcode := retcode / block;
    retcode := retcode * block;
  end_if;

END_FUNCTION

FUNCTION MerkerEx::SetSizeCTor
VAR_INPUT
	udSize		: UDINT;
END_VAR
VAR_OUTPUT
	retcode		: ConfStates;
END_VAR
VAR
	pData			: ^USINT;
	udOldLen		: UDINT;
END_VAR

  retcode := C_OK;
  if(m_pData = nil) then
    m_udLength := 0;
  end_if;

  if GetNewBlockSize(udSize) then // ok if length didn't change
    udOldLen := m_udLength;
    pData    := Alloc(m_udAllocated)$^USINT;
    if(udSize & pData = nil) then
      retcode := C_OUTOF_NEAR;
      return;
    end_if;
    
    _memset(pData, 0, udSize);
    m_pData    := pData;
    m_udLength := udSize;
  end_if;

END_FUNCTION

FUNCTION VIRTUAL GLOBAL MerkerEx::SetSize
  VAR_INPUT
    udSize		: UDINT;
  END_VAR
  VAR_OUTPUT
    ret_code		: ConfStates;
  END_VAR
  VAR
    ptr, freeptr : ^void;
    len, blk, siz : udint;
  END_VAR

  ret_code := C_OK;
  freeptr  := nil;

  LockOn(); // *****************************************
  ptr := m_pData;
  len := m_udLength;
  blk := m_udGrowBy;
  
  udSize := GetAllocSize(udSize, blk);
  
  if(ptr = nil) then
    len := 0; // force length to 0
  end_if;
  
  if(udSize <> len) then
      // do not force any call of function free --> runtime watchdog will occur because free can take a while
      // note: realloc is using function free as well
      freeptr := ptr;
      ptr     := nil;
      if(udSize <> 0) then
        ptr := _alloc_resize(udSize); // alloc new block
        if(ptr = nil) then
          ret_code := C_OUTOF_NEAR; // error: too less memory
          ptr      := freeptr;
          freeptr  := nil;
        else 
          if(freeptr <> nil) then // copy data ?
            siz := len;
            if(siz > udSize) then
              siz := udSize;
            end_if;
            _memcpy(ptr, freeptr, siz); // copy data
          end_if;
          if(len < udSize) then
            _memset(ptr+len, 0, udSize-len); // initialize new part
          end_if;
        end_if;
      end_if;
  end_if;

  if (ret_code = C_OK) then
    m_pData    := ptr$^usint;
    m_udLength := udSize;
    CalcCRC();
  end_if;

  LockOff(); // ********************************************
  
  if(freeptr <> nil) then
    _free(freeptr); // free memory without lock
  end_if;
  
END_FUNCTION

FUNCTION VIRTUAL GLOBAL MerkerEx::GetSize
	VAR_OUTPUT
		udSize 	: UDINT;
	END_VAR

	udSize := m_udLength;

END_FUNCTION

FUNCTION VIRTUAL GLOBAL MerkerEx::GetData
	VAR_INPUT
		pData 	: ^USINT;
	END_VAR

  GetDataAt(pData, m_udLength, 0);

END_FUNCTION

FUNCTION VIRTUAL GLOBAL MerkerEx::GetDataAt
  VAR_INPUT
    pData		: ^USINT;
    udSize	: UDINT;
    udAt		: UDINT;
  END_VAR
  VAR_OUTPUT
    ret_code	: ConfStates;
  END_VAR

  LockOn(); // *****************************************
	if(m_pData <> nil) & (m_udLength >= udAt+udSize) then
    _memcpy(pData, m_pData+udAt, udSize);
    ret_code := C_OK;
  else
    ret_code := C_OUTOF_NEAR;
  end_if;
  LockOff(); // ********************************************

END_FUNCTION

FUNCTION VIRTUAL GLOBAL MerkerEx::SetDataAt
  VAR_INPUT
    pData		: ^USINT;
    udSize		: UDINT;
    udAt		: UDINT;
  END_VAR
  VAR_OUTPUT
    ret_code		: ConfStates;
  END_VAR

	ret_code := C_OK;
  
  LockOn(); // *****************************************
  if(udSize+udAt > m_udLength) then	
    ret_code := C_OUTOF_NEAR;
  else
    _memcpy(m_pData+udAt, pData, udSize);
    CalcCRC();
	end_if;
  LockOff(); // ********************************************

END_FUNCTION

FUNCTION VIRTUAL GLOBAL MerkerEx::SetData
	VAR_INPUT
		pData 	: ^USINT;
	END_VAR
  
	SetDataAt(pData, m_udLength, 0);

END_FUNCTION

FUNCTION VIRTUAL GLOBAL MerkerEx::SetDataPtr
	VAR_INPUT
		pData 	: ^void;
	END_VAR

 m_pData := pData$^usint;
 CalcCRC();
 
END_FUNCTION

FUNCTION VIRTUAL GLOBAL MerkerEx::GetDataPtr
	VAR_OUTPUT
		pData 	: ^USINT;
	END_VAR

  pData := m_pData;

END_FUNCTION

FUNCTION VIRTUAL GLOBAL MerkerEx::m_udLength::Read
	VAR_OUTPUT
		output (EAX) 	: UDINT;
	END_VAR

  output := m_udLength;

END_FUNCTION

FUNCTION VIRTUAL GLOBAL MerkerEx::m_udLength::NewInst
  VAR_INPUT
    pPara		: ^CmdStruct;
    pResult		: ^results;
  END_VAR
  VAR_OUTPUT
    ret_code		: iprStates;
  END_VAR
  VAR
    pMem : ^void;
    pEx : ^MerkerEx;
    tmp : MerkerEx;
  END_VAR

  case pPara^.uiCmd of 
    // assign a pointer to retentive data to the object
    LSL_MSG_RETENTIVE:
      if(this <> pPara^.aPara[2]$^MerkerEx)then
        ret_code := ERROR;
        return;
      end_if;
      
      LockOn(); // **************************************
      // if this block of memory was already allocated
      // by the current object, then leave it as it is!
      pMem := pPara^.aPara[0]$^void;
      if(pMem = m_pData) then
        // the new data has got this length
        m_udLength := pPara^.aPara[1]$UDINT;
      else
        if m_pData then
          SetSize(0);  // free old data
        end_if;
        m_pData    := pMem$^usint;
        m_udLength := pPara^.aPara[1]$UDINT;
      end_if;
      LockOff(); // *****************************************
    
      // Daten von 2 ramexobjekten vertauschen (füer IPR genützt !!)
      // War falscher weise In der RAMEX
	
    EXCHANGE_DATA_PTR $ UDINT:
      // 22.06.2004 in New_inst auch EXCHANGE_DATA_PTR dazugebaut weil Billion nicht 
      // ramex sondern Merkerex für die IPRs benutzt!! 
   
      LockOn(); // **************************************
     #pragma warning (disable : 137)

      pEX := pPara^.aPara[0]$^MerkerEx;

      // unsere daten ins Temporare
      tmp.m_udLength      := m_udLength;		
      tmp.m_pData         := m_pData;
      tmp.m_udAllocated   := m_udAllocated;

      // unsere vom fremden laden
      m_udLength          := pEX^.m_udLength;		
      m_pData             := pEX^.m_pData;
      m_udAllocated       := pEX^.m_udAllocated;

      // Fremdes Aus dem Zwischenspeicher (das ist unser altes) laden
      pEX^.m_udLength     := tmp.m_udLength;		
      pEX^.m_pData        := tmp.m_pData;
      pEX^.m_udAllocated  := tmp.m_udAllocated;

     #pragma warning (default : 137)
     
      CalcCRC();

      LockOff(); // *****************************************
	  
    GET_DATA_PTR $ UDINT:
      LockOn(); // **************************************
      pResult^.uiLng          := sizeof(pVoid);
      pResult^.aData[0]$^void	:= GetDataPtr();
      LockOff(); // *****************************************
      
    // Rest Ist in die RAMEX gewandert !!! MELKUS

  end_case;

  ret_code := READY;

END_FUNCTION

FUNCTION  MerkerEx::GetNewBlockSize
VAR_INPUT
	udSize		: UDINT;
END_VAR
VAR_OUTPUT 
	bAlloc		: BOOL;
END_VAR

  bAlloc := false;
  if(udSize <> m_udLength) then
    if(udSize <> 0) then
      if(m_udGrowBy = 1) then
        m_udAllocated := udSize;
        bAlloc := true;
        return;
      end_if;
    end_if;
    
    udSize := udSize + m_udGrowBy - 1;
    udSize := udSize / m_udGrowBy;
    udSize := udSize * m_udGrowBy;
    
    if(udSize <> m_udLength) then
      m_udAllocated := udSize;
      bAlloc := true;
      return;
    end_if;
  end_if;
  
END_FUNCTION

FUNCTION VIRTUAL GLOBAL MerkerEx::Alloc
  VAR_INPUT
    udSize  : UDINT;
  END_VAR
  VAR_OUTPUT
    pCode  : ^void;
  END_VAR
  VAR
  	ptr : ^usint;
  END_VAR

  ptr   := m_pData;
  pCode := nil;

  if(ptr <> nil) then
    if(udSize = 0) then
      _free(ptr);
    else
      pCode := _realloc(ptr, udSize);
    end_if;
  else
    pCode := _alloc_resize(udSize);
  end_if;

END_FUNCTION

FUNCTION MerkerEx::ZeroMemory
  VAR_INPUT
    udStartOff		: UDINT;
  END_VAR
  VAR
    ptr : ^usint;
    len : udint;
  END_VAR

  LockOn(); // *****************************************
  ptr := m_pData;
  len := m_udLength;
  LockOff(); // ********************************************
  
  if(ptr <> nil) & (udStartOff < len) then
    _memset(ptr+udStartOff, 0, len-udStartOff);
  end_if;

END_FUNCTION

FUNCTION VIRTUAL GLOBAL MerkerEx::UpdateToFile

  // method is not used in here, just to keep compatibility to RamEx, String, StringInternal

END_FUNCTION


FUNCTION VIRTUAL GLOBAL MerkerEx::GetCRC
	VAR_OUTPUT
		udCRC 	: UDINT;
	END_VAR

  udCRC := m_udCrc;

END_FUNCTION

FUNCTION  MerkerEx::CalcCRC

	m_udCRC += 1;

END_FUNCTION // StringInternal::CalcCRC
