/****************************************************************************

  (c) SYSTEC electronic GmbH, D-07973 Greiz, August-Bebel-Str. 29
      www.systec-electronic.com

  Project:      openPOWERLINK

  Description:  source file for api function of EplOBD-Module

  License:

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions
    are met:

    1. Redistributions of source code must retain the above copyright
       notice, this list of conditions and the following disclaimer.

    2. Redistributions in binary form must reproduce the above copyright
       notice, this list of conditions and the following disclaimer in the
       documentation and/or other materials provided with the distribution.

    3. Neither the name of SYSTEC electronic GmbH nor the names of its
       contributors may be used to endorse or promote products derived
       from this software without prior written permission. For written
       permission, please contact info@systec-electronic.com.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
    FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
    COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
    ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    POSSIBILITY OF SUCH DAMAGE.

    Severability Clause:

        If a provision of this License is or becomes illegal, invalid or
        unenforceable in any jurisdiction, that shall not affect:
        1. the validity or enforceability in that jurisdiction of any other
           provision of this License; or
        2. the validity or enforceability in other jurisdictions of that or
           any other provision of this License.

  -------------------------------------------------------------------------

                $RCSfile: EplObd.c,v $

                $Author: D.Krueger $

                $Revision: 1.12 $  $Date: 2008/10/17 15:32:32 $

                $State: Exp $

                Build Environment:
                Microsoft VC7

  -------------------------------------------------------------------------

  Revision History:

  2006/06/02 k.t.:   start of the implementation, version 1.00
		     ->based on CANopen OBD-Modul

****************************************************************************/

#include "EplInc.h"
#include "kernel/EplObdk.h"	// function prototyps of the EplOBD-Modul

#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_OBDK)) != 0)

/***************************************************************************/
/*                                                                         */
/*                                                                         */
/*          G L O B A L   D E F I N I T I O N S                            */
/*                                                                         */
/*                                                                         */
/***************************************************************************/

//---------------------------------------------------------------------------
// const defines
//---------------------------------------------------------------------------

// float definitions and macros
#define _SHIFTED_EXPONENT_MASK_SP   0xff
#define _BIAS_SP                    126
#define T_SP                        23
#define EXPONENT_DENORM_SP          (-_BIAS_SP)
#define BASE_TO_THE_T_SP            ((float) 8388608.0)
#define GET_EXPONENT_SP(x)          ((((x) >> T_SP) & _SHIFTED_EXPONENT_MASK_SP) - _BIAS_SP)

//---------------------------------------------------------------------------
// local types
//---------------------------------------------------------------------------

// struct for instance table
INSTANCE_TYPE_BEGIN EPL_MCO_DECL_INSTANCE_MEMBER()

STATIC tEplObdInitParam INST_FAR m_ObdInitParam;
STATIC tEplObdStoreLoadObjCallback INST_NEAR m_fpStoreLoadObjCallback;

INSTANCE_TYPE_END
// decomposition of float
typedef union {
	tEplObdReal32 m_flRealPart;
	int m_nIntegerPart;

} tEplObdRealParts;

//---------------------------------------------------------------------------
// modul globale vars
//---------------------------------------------------------------------------

// This macro replace the unspecific pointer to an instance through
// the modul specific type for the local instance table. This macro
// must defined in each modul.
//#define tEplPtrInstance             tEplInstanceInfo MEM*

EPL_MCO_DECL_INSTANCE_VAR()

BYTE MEM abEplObdTrashObject_g[8];

//---------------------------------------------------------------------------
// local function prototypes
//---------------------------------------------------------------------------

EPL_MCO_DEFINE_INSTANCE_FCT()

static tEplKernel EplObdCallObjectCallback(EPL_MCO_DECL_INSTANCE_PTR_
					   tEplObdCallback fpCallback_p,
					   tEplObdCbParam MEM * pCbParam_p);

static tEplObdSize EplObdGetDataSizeIntern(tEplObdSubEntryPtr pSubIndexEntry_p);

static tEplObdSize EplObdGetStrLen(void *pObjData_p,
				   tEplObdSize ObjLen_p, tEplObdType ObjType_p);

#if (EPL_OBD_CHECK_OBJECT_RANGE != FALSE)
static tEplKernel EplObdCheckObjectRange(tEplObdSubEntryPtr pSubindexEntry_p,
					 void *pData_p);
#endif

static tEplKernel EplObdGetVarEntry(tEplObdSubEntryPtr pSubindexEntry_p,
				    tEplObdVarEntry MEM ** ppVarEntry_p);

static tEplKernel EplObdGetEntry(EPL_MCO_DECL_INSTANCE_PTR_
				 unsigned int uiIndex_p,
				 unsigned int uiSubindex_p,
				 tEplObdEntryPtr * ppObdEntry_p,
				 tEplObdSubEntryPtr * ppObdSubEntry_p);

static tEplObdSize EplObdGetObjectSize(tEplObdSubEntryPtr pSubIndexEntry_p);

static tEplKernel EplObdGetIndexIntern(tEplObdInitParam MEM * pInitParam_p,
				       unsigned int uiIndex_p,
				       tEplObdEntryPtr * ppObdEntry_p);

static tEplKernel EplObdGetSubindexIntern(tEplObdEntryPtr pObdEntry_p,
					  unsigned int uiSubIndex_p,
					  tEplObdSubEntryPtr * ppObdSubEntry_p);

static tEplKernel EplObdAccessOdPartIntern(EPL_MCO_DECL_INSTANCE_PTR_
					   tEplObdPart CurrentOdPart_p,
					   tEplObdEntryPtr pObdEnty_p,
					   tEplObdDir Direction_p);

static void *EplObdGetObjectDefaultPtr(tEplObdSubEntryPtr pSubIndexEntry_p);
static void MEM *EplObdGetObjectCurrentPtr(tEplObdSubEntryPtr pSubIndexEntry_p);

#if (EPL_OBD_USE_STORE_RESTORE != FALSE)

static tEplKernel EplObdCallStoreCallback(EPL_MCO_DECL_INSTANCE_PTR_
					  tEplObdCbStoreParam MEM *
					  pCbStoreParam_p);

#endif // (EPL_OBD_USE_STORE_RESTORE != FALSE)

static void EplObdCopyObjectData(void MEM * pDstData_p,
				 void *pSrcData_p,
				 tEplObdSize ObjSize_p, tEplObdType ObjType_p);

void *EplObdGetObjectDataPtrIntern(tEplObdSubEntryPtr pSubindexEntry_p);

static tEplKernel EplObdIsNumericalIntern(tEplObdSubEntryPtr pObdSubEntry_p,
					  BOOL * pfEntryNumerical_p);

static tEplKernel PUBLIC EplObdWriteEntryPre(EPL_MCO_DECL_INSTANCE_PTR_
					     unsigned int uiIndex_p,
					     unsigned int uiSubIndex_p,
					     void *pSrcData_p,
					     void **ppDstData_p,
					     tEplObdSize Size_p,
					     tEplObdEntryPtr * ppObdEntry_p,
					     tEplObdSubEntryPtr * ppSubEntry_p,
					     tEplObdCbParam MEM * pCbParam_p,
					     tEplObdSize * pObdSize_p);

static tEplKernel PUBLIC EplObdWriteEntryPost(EPL_MCO_DECL_INSTANCE_PTR_
					      tEplObdEntryPtr pObdEntry_p,
					      tEplObdSubEntryPtr pSubEntry_p,
					      tEplObdCbParam MEM * pCbParam_p,
					      void *pSrcData_p,
					      void *pDstData_p,
					      tEplObdSize ObdSize_p);

//=========================================================================//
//                                                                         //
//          P U B L I C   F U N C T I O N S                                //
//                                                                         //
//=========================================================================//

//---------------------------------------------------------------------------
//
// Function:    EplObdInit()
//
// Description: initializes the first instance
//
// Parameters:  pInitParam_p    = init parameter
//
// Return:      tEplKernel      =   errorcode
//
// State:
//
//---------------------------------------------------------------------------

EPLDLLEXPORT tEplKernel PUBLIC EplObdInit(EPL_MCO_DECL_PTR_INSTANCE_PTR_
					  tEplObdInitParam MEM * pInitParam_p)
{

	tEplKernel Ret;
	EPL_MCO_DELETE_INSTANCE_TABLE();

	if (pInitParam_p == NULL) {
		Ret = kEplSuccessful;
		goto Exit;
	}

	Ret = EplObdAddInstance(EPL_MCO_PTR_INSTANCE_PTR_ pInitParam_p);

      Exit:
	return Ret;

}

//---------------------------------------------------------------------------
//
// Function:    EplObdAddInstance()
//
// Description: adds a new instance
//
// Parameters:  pInitParam_p
//
// Return:      tEplKernel
//
// State:
//
//---------------------------------------------------------------------------

EPLDLLEXPORT tEplKernel PUBLIC EplObdAddInstance(EPL_MCO_DECL_PTR_INSTANCE_PTR_
						 tEplObdInitParam MEM *
						 pInitParam_p)
{

	EPL_MCO_DECL_INSTANCE_PTR_LOCAL tEplKernel Ret;

	// check if pointer to instance pointer valid
	// get free instance and set the globale instance pointer
	// set also the instance addr to parameterlist
	EPL_MCO_CHECK_PTR_INSTANCE_PTR();
	EPL_MCO_GET_FREE_INSTANCE_PTR();
	EPL_MCO_SET_PTR_INSTANCE_PTR();

	// save init parameters
	EPL_MEMCPY(&EPL_MCO_GLB_VAR(m_ObdInitParam), pInitParam_p,
		   sizeof(tEplObdInitParam));

	// clear callback function for command LOAD and STORE
	EPL_MCO_GLB_VAR(m_fpStoreLoadObjCallback) = NULL;

	// sign instance as used
	EPL_MCO_WRITE_INSTANCE_STATE(kStateUsed);

	// initialize object dictionary
	// so all all VarEntries will be initialized to trash object and default values will be set to current data
	Ret = EplObdAccessOdPart(EPL_MCO_INSTANCE_PTR_
				 kEplObdPartAll, kEplObdDirInit);

	return Ret;

}

//---------------------------------------------------------------------------
//
// Function:    EplObdDeleteInstance()
//
// Description: delete instance
//
// Parameters:  EPL_MCO_DECL_INSTANCE_PTR
//
// Return:      tEplKernel
//
// State:
//
//---------------------------------------------------------------------------
#if (EPL_USE_DELETEINST_FUNC != FALSE)
EPLDLLEXPORT tEplKernel PUBLIC EplObdDeleteInstance(EPL_MCO_DECL_INSTANCE_PTR)
{
	// check for all API function if instance is valid
	EPL_MCO_CHECK_INSTANCE_STATE();

	// sign instance as unused
	EPL_MCO_WRITE_INSTANCE_STATE(kStateUnused);

	return kEplSuccessful;

}
#endif // (EPL_USE_DELETEINST_FUNC != FALSE)

//---------------------------------------------------------------------------
//
// Function:    EplObdWriteEntry()
//
// Description: Function writes data to an OBD entry. Strings
//              are stored with added '\0' character.
//
// Parameters:  EPL_MCO_DECL_INSTANCE_PTR_
//              uiIndex_p       =   Index of the OD entry
//              uiSubIndex_p    =   Subindex of the OD Entry
//              pSrcData_p      =   Pointer to the data to write
//              Size_p          =   Size of the data in Byte
//
// Return:      tEplKernel      =   Errorcode
//
//
// State:
//
//---------------------------------------------------------------------------

EPLDLLEXPORT tEplKernel PUBLIC EplObdWriteEntry(EPL_MCO_DECL_INSTANCE_PTR_
						unsigned int uiIndex_p,
						unsigned int uiSubIndex_p,
						void *pSrcData_p,
						tEplObdSize Size_p)
{

	tEplKernel Ret;
	tEplObdEntryPtr pObdEntry;
	tEplObdSubEntryPtr pSubEntry;
	tEplObdCbParam MEM CbParam;
	void MEM *pDstData;
	tEplObdSize ObdSize;

	Ret = EplObdWriteEntryPre(EPL_MCO_INSTANCE_PTR_
				  uiIndex_p,
				  uiSubIndex_p,
				  pSrcData_p,
				  &pDstData,
				  Size_p,
				  &pObdEntry, &pSubEntry, &CbParam, &ObdSize);
	if (Ret != kEplSuccessful) {
		goto Exit;
	}

	Ret = EplObdWriteEntryPost(EPL_MCO_INSTANCE_PTR_
				   pObdEntry,
				   pSubEntry,
				   &CbParam, pSrcData_p, pDstData, ObdSize);
	if (Ret != kEplSuccessful) {
		goto Exit;
	}

      Exit:

	return Ret;

}

//---------------------------------------------------------------------------
//
// Function:    EplObdReadEntry()
//
// Description: The function reads an object entry. The application
//              can always read the data even if attrib kEplObdAccRead
//              is not set. The attrib is only checked up for SDO transfer.
//
// Parameters:  EPL_MCO_DECL_INSTANCE_PTR_
//              uiIndex_p       = Index oof the OD entry to read
//              uiSubIndex_p    = Subindex to read
//              pDstData_p      = pointer to the buffer for data
//              Offset_p        = offset in data for read access
//              pSize_p         = IN: Size of the buffer
//                                OUT: number of readed Bytes
//
// Return:      tEplKernel
//
// State:
//
//---------------------------------------------------------------------------

EPLDLLEXPORT tEplKernel PUBLIC EplObdReadEntry(EPL_MCO_DECL_INSTANCE_PTR_
					       unsigned int uiIndex_p,
					       unsigned int uiSubIndex_p,
					       void *pDstData_p,
					       tEplObdSize * pSize_p)
{

	tEplKernel Ret;
	tEplObdEntryPtr pObdEntry;
	tEplObdSubEntryPtr pSubEntry;
	tEplObdCbParam MEM CbParam;
	void *pSrcData;
	tEplObdSize ObdSize;

	// check for all API function if instance is valid
	EPL_MCO_CHECK_INSTANCE_STATE();

	ASSERT(pDstData_p != NULL);
	ASSERT(pSize_p != NULL);

	// get address of index and subindex entry
	Ret = EplObdGetEntry(EPL_MCO_INSTANCE_PTR_
			     uiIndex_p, uiSubIndex_p, &pObdEntry, &pSubEntry);
	if (Ret != kEplSuccessful) {
		goto Exit;
	}
	// get pointer to object data
	pSrcData = EplObdGetObjectDataPtrIntern(pSubEntry);

	// check source pointer
	if (pSrcData == NULL) {
		Ret = kEplObdReadViolation;
		goto Exit;
	}
	//------------------------------------------------------------------------
	// address of source data to structure of callback parameters
	// so callback function can change this data before reading
	CbParam.m_uiIndex = uiIndex_p;
	CbParam.m_uiSubIndex = uiSubIndex_p;
	CbParam.m_pArg = pSrcData;
	CbParam.m_ObdEvent = kEplObdEvPreRead;
	Ret = EplObdCallObjectCallback(EPL_MCO_INSTANCE_PTR_
				       pObdEntry->m_fpCallback, &CbParam);
	if (Ret != kEplSuccessful) {
		goto Exit;
	}
	// get size of data and check if application has reserved enough memory
	ObdSize = EplObdGetDataSizeIntern(pSubEntry);
	// check if offset given and calc correct number of bytes to read
	if (*pSize_p < ObdSize) {
		Ret = kEplObdValueLengthError;
		goto Exit;
	}
	// read value from object
	EPL_MEMCPY(pDstData_p, pSrcData, ObdSize);
	*pSize_p = ObdSize;

	// write address of destination data to structure of callback parameters
	// so callback function can change this data after reading
	CbParam.m_pArg = pDstData_p;
	CbParam.m_ObdEvent = kEplObdEvPostRead;
	Ret = EplObdCallObjectCallback(EPL_MCO_INSTANCE_PTR_
				       pObdEntry->m_fpCallback, &CbParam);

      Exit:

	return Ret;

}

//---------------------------------------------------------------------------
//
// Function:    EplObdAccessOdPart()
//
// Description: restores default values of one part of OD
//
// Parameters:  ObdPart_p
//              Direction_p
//
// Return:      tEplKernel
//
// State:
//
//---------------------------------------------------------------------------

EPLDLLEXPORT tEplKernel PUBLIC EplObdAccessOdPart(EPL_MCO_DECL_INSTANCE_PTR_
						  tEplObdPart ObdPart_p,
						  tEplObdDir Direction_p)
{

	tEplKernel Ret = kEplSuccessful;
	BOOL fPartFount;
	tEplObdEntryPtr pObdEntry;

	// check for all API function if instance is valid
	EPL_MCO_CHECK_INSTANCE_STATE();

	//  part always has to be unequal to NULL
	pObdEntry = EPL_MCO_GLB_VAR(m_ObdInitParam.m_pPart);
	ASSERTMSG(pObdEntry != NULL,
		  "EplObdAccessOdPart(): no  OD part is defined!\n");

	// if ObdPart_p is not valid fPartFound keeps FALSE and function returns kEplObdIllegalPart
	fPartFount = FALSE;

	// access to  part
	if ((ObdPart_p & kEplObdPartGen) != 0) {
		fPartFount = TRUE;

		Ret = EplObdAccessOdPartIntern(EPL_MCO_INSTANCE_PTR_
					       kEplObdPartGen, pObdEntry,
					       Direction_p);
		if (Ret != kEplSuccessful) {
			goto Exit;
		}
	}
	// access to manufacturer part
	pObdEntry = EPL_MCO_GLB_VAR(m_ObdInitParam.m_pManufacturerPart);

	if (((ObdPart_p & kEplObdPartMan) != 0) && (pObdEntry != NULL)) {
		fPartFount = TRUE;

		Ret = EplObdAccessOdPartIntern(EPL_MCO_INSTANCE_PTR_
					       kEplObdPartMan, pObdEntry,
					       Direction_p);
		if (Ret != kEplSuccessful) {
			goto Exit;
		}
	}
	// access to device part
	pObdEntry = EPL_MCO_GLB_VAR(m_ObdInitParam.m_pDevicePart);

	if (((ObdPart_p & kEplObdPartDev) != 0) && (pObdEntry != NULL)) {
		fPartFount = TRUE;

		Ret = EplObdAccessOdPartIntern(EPL_MCO_INSTANCE_PTR_
					       kEplObdPartDev, pObdEntry,
					       Direction_p);
		if (Ret != kEplSuccessful) {
			goto Exit;
		}
	}
#if (defined (EPL_OBD_USER_OD) && (EPL_OBD_USER_OD != FALSE))
	{
		// access to user part
		pObdEntry = EPL_MCO_GLB_VAR(m_ObdInitParam.m_pUserPart);

		if (((ObdPart_p & kEplObdPartUsr) != 0) && (pObdEntry != NULL)) {
			fPartFount = TRUE;

			Ret = EplObdAccessOdPartIntern(EPL_MCO_INSTANCE_PTR_
						       kEplObdPartUsr,
						       pObdEntry, Direction_p);
			if (Ret != kEplSuccessful) {
				goto Exit;
			}
		}
	}
#endif

	// no access to an OD part was done? illegal OD part was specified!
	if (fPartFount == FALSE) {
		Ret = kEplObdIllegalPart;
	}

      Exit:

	return Ret;

}

//---------------------------------------------------------------------------
//
// Function:    EplObdDefineVar()
//
// Description: defines a variable in OD
//
// Parameters:  pEplVarParam_p
//
// Return:      tEplKernel
//
// State:
//
//---------------------------------------------------------------------------

EPLDLLEXPORT tEplKernel PUBLIC EplObdDefineVar(EPL_MCO_DECL_INSTANCE_PTR_
					       tEplVarParam MEM * pVarParam_p)
{

	tEplKernel Ret;
	tEplObdVarEntry MEM *pVarEntry;
	tEplVarParamValid VarValid;
	tEplObdSubEntryPtr pSubindexEntry;

	// check for all API function if instance is valid
	EPL_MCO_CHECK_INSTANCE_STATE();

	ASSERT(pVarParam_p != NULL);	// is not allowed to be NULL

	// get address of subindex entry
	Ret = EplObdGetEntry(EPL_MCO_INSTANCE_PTR_
			     pVarParam_p->m_uiIndex,
			     pVarParam_p->m_uiSubindex, NULL, &pSubindexEntry);
	if (Ret != kEplSuccessful) {
		goto Exit;
	}
	// get var entry
	Ret = EplObdGetVarEntry(pSubindexEntry, &pVarEntry);
	if (Ret != kEplSuccessful) {
		goto Exit;
	}

	VarValid = pVarParam_p->m_ValidFlag;

	// copy only this values, which valid flag is set
	if ((VarValid & kVarValidSize) != 0) {
		if (pSubindexEntry->m_Type != kEplObdTypDomain) {
			tEplObdSize DataSize;

			// check passed size parameter
			DataSize = EplObdGetObjectSize(pSubindexEntry);
			if (DataSize != pVarParam_p->m_Size) {	// size of variable does not match
				Ret = kEplObdValueLengthError;
				goto Exit;
			}
		} else {	// size can be set only for objects of type DOMAIN
			pVarEntry->m_Size = pVarParam_p->m_Size;
		}
	}

	if ((VarValid & kVarValidData) != 0) {
		pVarEntry->m_pData = pVarParam_p->m_pData;
	}
/*
    #if (EPL_PDO_USE_STATIC_MAPPING == FALSE)
    {
        if ((VarValid & kVarValidCallback) != 0)
        {
           pVarEntry->m_fpCallback = pVarParam_p->m_fpCallback;
        }

        if ((VarValid & kVarValidArg) != 0)
        {
           pVarEntry->m_pArg = pVarParam_p->m_pArg;
        }
    }
    #endif
*/
	// Ret is already set to kEplSuccessful from ObdGetVarIntern()

      Exit:

	return Ret;

}

//---------------------------------------------------------------------------
//
// Function:    EplObdGetObjectDataPtr()
//
// Description: It returnes the current data pointer. But if object is an
//              constant object it returnes the default pointer.
//
// Parameters:  uiIndex_p    =   Index of the entry
//              uiSubindex_p =   Subindex of the entry
//
// Return:      void *    = pointer to object data
//
// State:
//
//---------------------------------------------------------------------------

EPLDLLEXPORT void *PUBLIC EplObdGetObjectDataPtr(EPL_MCO_DECL_INSTANCE_PTR_
						 unsigned int uiIndex_p,
						 unsigned int uiSubIndex_p)
{
	tEplKernel Ret;
	void *pData;
	tEplObdEntryPtr pObdEntry;
	tEplObdSubEntryPtr pObdSubEntry;

	// get pointer to index structure
	Ret = EplObdGetIndexIntern(&EPL_MCO_GLB_VAR(m_ObdInitParam),
				   uiIndex_p, &pObdEntry);
	if (Ret != kEplSuccessful) {
		pData = NULL;
		goto Exit;
	}
	// get pointer to subindex structure
	Ret = EplObdGetSubindexIntern(pObdEntry, uiSubIndex_p, &pObdSubEntry);
	if (Ret != kEplSuccessful) {
		pData = NULL;
		goto Exit;
	}
	// get Datapointer
	pData = EplObdGetObjectDataPtrIntern(pObdSubEntry);

      Exit:
	return pData;

}

#if (defined (EPL_OBD_USER_OD) && (EPL_OBD_USER_OD != FALSE))

//---------------------------------------------------------------------------
//
// Function:    EplObdRegisterUserOd()
//
// Description: function registers the user OD
//
// Parameters:  pUserOd_p   =pointer to user ODd
//
// Return:     tEplKernel = errorcode
//
// State:
//
//---------------------------------------------------------------------------
EPLDLLEXPORT tEplKernel PUBLIC EplObdRegisterUserOd(EPL_MCO_DECL_INSTANCE_PTR_
						    tEplObdEntryPtr pUserOd_p)
{

	EPL_MCO_CHECK_INSTANCE_STATE();

	EPL_MCO_GLB_VAR(m_ObdInitParam.m_pUserPart) = pUserOd_p;

	return kEplSuccessful;

}

#endif

//---------------------------------------------------------------------------
//
// Function:    EplObdInitVarEntry()
//
// Description: function to initialize VarEntry dependened on object type
//
// Parameters:  pVarEntry_p = pointer to var entry structure
//              Type_p      = object type
//              ObdSize_p   = size of object data
//
// Returns:     none
//
// State:
//
//---------------------------------------------------------------------------

EPLDLLEXPORT void PUBLIC EplObdInitVarEntry(EPL_MCO_DECL_INSTANCE_PTR_
					    tEplObdVarEntry MEM * pVarEntry_p,
					    tEplObdType Type_p,
					    tEplObdSize ObdSize_p)
{
/*
    #if (EPL_PDO_USE_STATIC_MAPPING == FALSE)
    {
        // reset pointer to VAR callback and argument
        pVarEntry_p->m_fpCallback  = NULL;
        pVarEntry_p->m_pArg = NULL;
    }
    #endif
*/

// 10-dec-2004 r.d.: this function will not be used for strings
	if ((Type_p == kEplObdTypDomain))
//         (bType_p == kEplObdTypVString) /* ||
//         (bType_p == kEplObdTypOString) ||
//         (bType_p == kEplObdTypUString)    */ )
	{
		// variables which are defined as DOMAIN or VSTRING should not point to
		// trash object, because this trash object contains only 8 bytes. DOMAINS or
		// STRINGS can be longer.
		pVarEntry_p->m_pData = NULL;
		pVarEntry_p->m_Size = 0;
	} else {
		// set address to variable data to trash object
		// This prevents an access violation if user forgets to call EplObdDefineVar()
		// for this variable but mappes it in a PDO.
		pVarEntry_p->m_pData = &abEplObdTrashObject_g[0];
		pVarEntry_p->m_Size = ObdSize_p;
	}

}

//---------------------------------------------------------------------------
//
// Function:    EplObdGetDataSize()
//
// Description: function to initialize VarEntry dependened on object type
//
//              gets the data size of an object
//              for string objects it returnes the string length
//
// Parameters:  EPL_MCO_DECL_INSTANCE_PTR_ = Instancepointer
//              uiIndex_p   =   Index
//              uiSubIndex_p=   Subindex
//
// Return:      tEplObdSize
//
// State:
//
//---------------------------------------------------------------------------
EPLDLLEXPORT tEplObdSize PUBLIC EplObdGetDataSize(EPL_MCO_DECL_INSTANCE_PTR_
						  unsigned int uiIndex_p,
						  unsigned int uiSubIndex_p)
{
	tEplKernel Ret;
	tEplObdSize ObdSize;
	tEplObdEntryPtr pObdEntry;
	tEplObdSubEntryPtr pObdSubEntry;

	// get pointer to index structure
	Ret = EplObdGetIndexIntern(&EPL_MCO_GLB_VAR(m_ObdInitParam),
				   uiIndex_p, &pObdEntry);
	if (Ret != kEplSuccessful) {
		ObdSize = 0;
		goto Exit;
	}
	// get pointer to subindex structure
	Ret = EplObdGetSubindexIntern(pObdEntry, uiSubIndex_p, &pObdSubEntry);
	if (Ret != kEplSuccessful) {
		ObdSize = 0;
		goto Exit;
	}
	// get size
	ObdSize = EplObdGetDataSizeIntern(pObdSubEntry);
      Exit:
	return ObdSize;
}

//---------------------------------------------------------------------------
//
// Function:    EplObdGetNodeId()
//
// Description: function returns nodeid from entry 0x1F93
//
//
// Parameters:  EPL_MCO_DECL_INSTANCE_PTR = Instancepointer
//
// Return:      unsigned int = Node Id
//
// State:
//
//---------------------------------------------------------------------------
EPLDLLEXPORT unsigned int PUBLIC EplObdGetNodeId(EPL_MCO_DECL_INSTANCE_PTR)
{
	tEplKernel Ret;
	tEplObdSize ObdSize;
	BYTE bNodeId;

	bNodeId = 0;
	ObdSize = sizeof(bNodeId);
	Ret = EplObdReadEntry(EPL_MCO_PTR_INSTANCE_PTR_
			      EPL_OBD_NODE_ID_INDEX,
			      EPL_OBD_NODE_ID_SUBINDEX, &bNodeId, &ObdSize);
	if (Ret != kEplSuccessful) {
		bNodeId = EPL_C_ADR_INVALID;
		goto Exit;
	}

      Exit:
	return (unsigned int)bNodeId;

}

//---------------------------------------------------------------------------
//
// Function:    EplObdSetNodeId()
//
// Description: function sets nodeid in entry 0x1F93
//
//
// Parameters:  EPL_MCO_DECL_INSTANCE_PTR_ = Instancepointer
//              uiNodeId_p  =   Node Id to set
//              NodeIdType_p=   Type on which way the Node Id was set
//
// Return:      tEplKernel = Errorcode
//
// State:
//
//---------------------------------------------------------------------------
EPLDLLEXPORT tEplKernel PUBLIC EplObdSetNodeId(EPL_MCO_DECL_PTR_INSTANCE_PTR_
					       unsigned int uiNodeId_p,
					       tEplObdNodeIdType NodeIdType_p)
{
	tEplKernel Ret;
	tEplObdSize ObdSize;
	BYTE fHwBool;
	BYTE bNodeId;

	// check Node Id
	if (uiNodeId_p == EPL_C_ADR_INVALID) {
		Ret = kEplInvalidNodeId;
		goto Exit;
	}
	bNodeId = (BYTE) uiNodeId_p;
	ObdSize = sizeof(BYTE);
	// write NodeId to OD entry
	Ret = EplObdWriteEntry(EPL_MCO_PTR_INSTANCE_PTR_
			       EPL_OBD_NODE_ID_INDEX,
			       EPL_OBD_NODE_ID_SUBINDEX, &bNodeId, ObdSize);
	if (Ret != kEplSuccessful) {
		goto Exit;
	}
	// set HWBOOL-Flag in Subindex EPL_OBD_NODE_ID_HWBOOL_SUBINDEX
	switch (NodeIdType_p) {
		// type unknown
	case kEplObdNodeIdUnknown:
		{
			fHwBool = OBD_FALSE;
			break;
		}

	case kEplObdNodeIdSoftware:
		{
			fHwBool = OBD_FALSE;
			break;
		}

	case kEplObdNodeIdHardware:
		{
			fHwBool = OBD_TRUE;
			break;
		}

	default:
		{
			fHwBool = OBD_FALSE;
		}

	}			// end of switch (NodeIdType_p)

	// write flag
	ObdSize = sizeof(fHwBool);
	Ret = EplObdWriteEntry(EPL_MCO_PTR_INSTANCE_PTR
			       EPL_OBD_NODE_ID_INDEX,
			       EPL_OBD_NODE_ID_HWBOOL_SUBINDEX,
			       &fHwBool, ObdSize);
	if (Ret != kEplSuccessful) {
		goto Exit;
	}

      Exit:
	return Ret;
}

//---------------------------------------------------------------------------
//
// Function:    EplObdIsNumerical()
//
// Description: function checks if a entry is numerical or not
//
//
// Parameters:  EPL_MCO_DECL_INSTANCE_PTR_ = Instancepointer
//              uiIndex_p           = Index
//              uiSubIndex_p        = Subindex
//              pfEntryNumerical_p  = pointer to BOOL for returnvalue
//                                  -> TRUE if entry a numerical value
//                                  -> FALSE if entry not a numerical value
//
// Return:      tEplKernel = Errorcode
//
// State:
//
//---------------------------------------------------------------------------
EPLDLLEXPORT tEplKernel PUBLIC EplObdIsNumerical(EPL_MCO_DECL_INSTANCE_PTR_
						 unsigned int uiIndex_p,
						 unsigned int uiSubIndex_p,
						 BOOL * pfEntryNumerical_p)
{
	tEplKernel Ret;
	tEplObdEntryPtr pObdEntry;
	tEplObdSubEntryPtr pObdSubEntry;

	// get pointer to index structure
	Ret = EplObdGetIndexIntern(&EPL_MCO_GLB_VAR(m_ObdInitParam),
				   uiIndex_p, &pObdEntry);
	if (Ret != kEplSuccessful) {
		goto Exit;
	}
	// get pointer to subindex structure
	Ret = EplObdGetSubindexIntern(pObdEntry, uiSubIndex_p, &pObdSubEntry);
	if (Ret != kEplSuccessful) {
		goto Exit;
	}

	Ret = EplObdIsNumericalIntern(pObdSubEntry, pfEntryNumerical_p);

      Exit:
	return Ret;

}

//---------------------------------------------------------------------------
//
// Function:    EplObdReadEntryToLe()
//
// Description: The function reads an object entry from the byteoder
//              of the system to the little endian byteorder for numerical values.
//              For other types a normal read will be processed. This is usefull for
//              the PDO and SDO module. The application
//              can always read the data even if attrib kEplObdAccRead
//              is not set. The attrib is only checked up for SDO transfer.
//
// Parameters:  EPL_MCO_DECL_INSTANCE_PTR_
//              uiIndex_p       = Index of the OD entry to read
//              uiSubIndex_p    = Subindex to read
//              pDstData_p      = pointer to the buffer for data
//              Offset_p        = offset in data for read access
//              pSize_p         = IN: Size of the buffer
//                                OUT: number of readed Bytes
//
// Return:      tEplKernel
//
// State:
//
//---------------------------------------------------------------------------
EPLDLLEXPORT tEplKernel PUBLIC EplObdReadEntryToLe(EPL_MCO_DECL_INSTANCE_PTR_
						   unsigned int uiIndex_p,
						   unsigned int uiSubIndex_p,
						   void *pDstData_p,
						   tEplObdSize * pSize_p)
{
	tEplKernel Ret;
	tEplObdEntryPtr pObdEntry;
	tEplObdSubEntryPtr pSubEntry;
	tEplObdCbParam MEM CbParam;
	void *pSrcData;
	tEplObdSize ObdSize;

	// check for all API function if instance is valid
	EPL_MCO_CHECK_INSTANCE_STATE();

	ASSERT(pDstData_p != NULL);
	ASSERT(pSize_p != NULL);

	// get address of index and subindex entry
	Ret = EplObdGetEntry(EPL_MCO_INSTANCE_PTR_
			     uiIndex_p, uiSubIndex_p, &pObdEntry, &pSubEntry);
	if (Ret != kEplSuccessful) {
		goto Exit;
	}
	// get pointer to object data
	pSrcData = EplObdGetObjectDataPtrIntern(pSubEntry);

	// check source pointer
	if (pSrcData == NULL) {
		Ret = kEplObdReadViolation;
		goto Exit;
	}
	//------------------------------------------------------------------------
	// address of source data to structure of callback parameters
	// so callback function can change this data before reading
	CbParam.m_uiIndex = uiIndex_p;
	CbParam.m_uiSubIndex = uiSubIndex_p;
	CbParam.m_pArg = pSrcData;
	CbParam.m_ObdEvent = kEplObdEvPreRead;
	Ret = EplObdCallObjectCallback(EPL_MCO_INSTANCE_PTR_
				       pObdEntry->m_fpCallback, &CbParam);
	if (Ret != kEplSuccessful) {
		goto Exit;
	}
	// get size of data and check if application has reserved enough memory
	ObdSize = EplObdGetDataSizeIntern(pSubEntry);
	// check if offset given and calc correct number of bytes to read
	if (*pSize_p < ObdSize) {
		Ret = kEplObdValueLengthError;
		goto Exit;
	}
	// check if numerical type
	switch (pSubEntry->m_Type) {
		//-----------------------------------------------
		// types without ami
	case kEplObdTypVString:
	case kEplObdTypOString:
	case kEplObdTypDomain:
	default:
		{
			// read value from object
			EPL_MEMCPY(pDstData_p, pSrcData, ObdSize);
			break;
		}

		//-----------------------------------------------
		// numerical type which needs ami-write
		// 8 bit or smaller values
	case kEplObdTypBool:
	case kEplObdTypInt8:
	case kEplObdTypUInt8:
		{
			AmiSetByteToLe(pDstData_p, *((BYTE *) pSrcData));
			break;
		}

		// 16 bit values
	case kEplObdTypInt16:
	case kEplObdTypUInt16:
		{
			AmiSetWordToLe(pDstData_p, *((WORD *) pSrcData));
			break;
		}

		// 24 bit values
	case kEplObdTypInt24:
	case kEplObdTypUInt24:
		{
			AmiSetDword24ToLe(pDstData_p, *((DWORD *) pSrcData));
			break;
		}

		// 32 bit values
	case kEplObdTypInt32:
	case kEplObdTypUInt32:
	case kEplObdTypReal32:
		{
			AmiSetDwordToLe(pDstData_p, *((DWORD *) pSrcData));
			break;
		}

		// 40 bit values
	case kEplObdTypInt40:
	case kEplObdTypUInt40:
		{
			AmiSetQword40ToLe(pDstData_p, *((QWORD *) pSrcData));
			break;
		}

		// 48 bit values
	case kEplObdTypInt48:
	case kEplObdTypUInt48:
		{
			AmiSetQword48ToLe(pDstData_p, *((QWORD *) pSrcData));
			break;
		}

		// 56 bit values
	case kEplObdTypInt56:
	case kEplObdTypUInt56:
		{
			AmiSetQword56ToLe(pDstData_p, *((QWORD *) pSrcData));
			break;
		}

		// 64 bit values
	case kEplObdTypInt64:
	case kEplObdTypUInt64:
	case kEplObdTypReal64:
		{
			AmiSetQword64ToLe(pDstData_p, *((QWORD *) pSrcData));
			break;
		}

		// time of day
	case kEplObdTypTimeOfDay:
	case kEplObdTypTimeDiff:
		{
			AmiSetTimeOfDay(pDstData_p, ((tTimeOfDay *) pSrcData));
			break;
		}

	}			// end of switch(pSubEntry->m_Type)

	*pSize_p = ObdSize;

	// write address of destination data to structure of callback parameters
	// so callback function can change this data after reading
	CbParam.m_pArg = pDstData_p;
	CbParam.m_ObdEvent = kEplObdEvPostRead;
	Ret = EplObdCallObjectCallback(EPL_MCO_INSTANCE_PTR_
				       pObdEntry->m_fpCallback, &CbParam);

      Exit:

	return Ret;

}

//---------------------------------------------------------------------------
//
// Function:    EplObdWriteEntryFromLe()
//
// Description: Function writes data to an OBD entry from a source with
//              little endian byteorder to the od with system specuific
//              byteorder. Not numerical values will only by copied. Strings
//              are stored with added '\0' character.
//
// Parameters:  EPL_MCO_DECL_INSTANCE_PTR_
//              uiIndex_p       =   Index of the OD entry
//              uiSubIndex_p    =   Subindex of the OD Entry
//              pSrcData_p      =   Pointer to the data to write
//              Size_p          =   Size of the data in Byte
//
// Return:      tEplKernel      =   Errorcode
//
//
// State:
//
//---------------------------------------------------------------------------
EPLDLLEXPORT tEplKernel PUBLIC EplObdWriteEntryFromLe(EPL_MCO_DECL_INSTANCE_PTR_
						      unsigned int uiIndex_p,
						      unsigned int uiSubIndex_p,
						      void *pSrcData_p,
						      tEplObdSize Size_p)
{
	tEplKernel Ret;
	tEplObdEntryPtr pObdEntry;
	tEplObdSubEntryPtr pSubEntry;
	tEplObdCbParam MEM CbParam;
	void MEM *pDstData;
	tEplObdSize ObdSize;
	QWORD qwBuffer;
	void *pBuffer = &qwBuffer;

	Ret = EplObdWriteEntryPre(EPL_MCO_INSTANCE_PTR_
				  uiIndex_p,
				  uiSubIndex_p,
				  pSrcData_p,
				  &pDstData,
				  Size_p,
				  &pObdEntry, &pSubEntry, &CbParam, &ObdSize);
	if (Ret != kEplSuccessful) {
		goto Exit;
	}

	// check if numerical type
	switch (pSubEntry->m_Type) {
		//-----------------------------------------------
		// types without ami
	default:
		{		// do nothing, i.e. use the given source pointer
			pBuffer = pSrcData_p;
			break;
		}

		//-----------------------------------------------
		// numerical type which needs ami-write
		// 8 bit or smaller values
	case kEplObdTypBool:
	case kEplObdTypInt8:
	case kEplObdTypUInt8:
		{
			*((BYTE *) pBuffer) = AmiGetByteFromLe(pSrcData_p);
			break;
		}

		// 16 bit values
	case kEplObdTypInt16:
	case kEplObdTypUInt16:
		{
			*((WORD *) pBuffer) = AmiGetWordFromLe(pSrcData_p);
			break;
		}

		// 24 bit values
	case kEplObdTypInt24:
	case kEplObdTypUInt24:
		{
			*((DWORD *) pBuffer) = AmiGetDword24FromLe(pSrcData_p);
			break;
		}

		// 32 bit values
	case kEplObdTypInt32:
	case kEplObdTypUInt32:
	case kEplObdTypReal32:
		{
			*((DWORD *) pBuffer) = AmiGetDwordFromLe(pSrcData_p);
			break;
		}

		// 40 bit values
	case kEplObdTypInt40:
	case kEplObdTypUInt40:
		{
			*((QWORD *) pBuffer) = AmiGetQword40FromLe(pSrcData_p);
			break;
		}

		// 48 bit values
	case kEplObdTypInt48:
	case kEplObdTypUInt48:
		{
			*((QWORD *) pBuffer) = AmiGetQword48FromLe(pSrcData_p);
			break;
		}

		// 56 bit values
	case kEplObdTypInt56:
	case kEplObdTypUInt56:
		{
			*((QWORD *) pBuffer) = AmiGetQword56FromLe(pSrcData_p);
			break;
		}

		// 64 bit values
	case kEplObdTypInt64:
	case kEplObdTypUInt64:
	case kEplObdTypReal64:
		{
			*((QWORD *) pBuffer) = AmiGetQword64FromLe(pSrcData_p);
			break;
		}

		// time of day
	case kEplObdTypTimeOfDay:
	case kEplObdTypTimeDiff:
		{
			AmiGetTimeOfDay(pBuffer, ((tTimeOfDay *) pSrcData_p));
			break;
		}

	}			// end of switch(pSubEntry->m_Type)

	Ret = EplObdWriteEntryPost(EPL_MCO_INSTANCE_PTR_
				   pObdEntry,
				   pSubEntry,
				   &CbParam, pBuffer, pDstData, ObdSize);
	if (Ret != kEplSuccessful) {
		goto Exit;
	}

      Exit:

	return Ret;

}

//---------------------------------------------------------------------------
//
// Function:    EplObdGetAccessType()
//
// Description: Function returns accesstype of the entry
//
// Parameters:  EPL_MCO_DECL_INSTANCE_PTR_
//              uiIndex_p       =   Index of the OD entry
//              uiSubIndex_p    =   Subindex of the OD Entry
//              pAccessTyp_p    =   pointer to buffer to store accesstype
//
// Return:      tEplKernel     =   errorcode
//
//
// State:
//
//---------------------------------------------------------------------------
EPLDLLEXPORT tEplKernel PUBLIC EplObdGetAccessType(EPL_MCO_DECL_INSTANCE_PTR_
						   unsigned int uiIndex_p,
						   unsigned int uiSubIndex_p,
						   tEplObdAccess * pAccessTyp_p)
{
	tEplKernel Ret;
	tEplObdEntryPtr pObdEntry;
	tEplObdSubEntryPtr pObdSubEntry;

	// get pointer to index structure
	Ret = EplObdGetIndexIntern(&EPL_MCO_GLB_VAR(m_ObdInitParam),
				   uiIndex_p, &pObdEntry);
	if (Ret != kEplSuccessful) {
		goto Exit;
	}
	// get pointer to subindex structure
	Ret = EplObdGetSubindexIntern(pObdEntry, uiSubIndex_p, &pObdSubEntry);
	if (Ret != kEplSuccessful) {
		goto Exit;
	}
	// get accessType
	*pAccessTyp_p = pObdSubEntry->m_Access;

      Exit:
	return Ret;
}

//---------------------------------------------------------------------------
//
// Function:    EplObdSearchVarEntry()
//
// Description: gets variable from OD
//
// Parameters:  uiIndex_p       =   index of the var entry to search
//              uiSubindex_p    =   subindex of var entry to search
//              ppVarEntry_p    =   pointer to the pointer to the varentry
//
// Return:      tEplKernel
//
// State:
//
//---------------------------------------------------------------------------

tEplKernel PUBLIC EplObdSearchVarEntry(EPL_MCO_DECL_INSTANCE_PTR_
				       unsigned int uiIndex_p,
				       unsigned int uiSubindex_p,
				       tEplObdVarEntry MEM ** ppVarEntry_p)
{

	tEplKernel Ret;
	tEplObdSubEntryPtr pSubindexEntry;

	// check for all API function if instance is valid
	EPL_MCO_CHECK_INSTANCE_STATE();

	// get address of subindex entry
	Ret = EplObdGetEntry(EPL_MCO_INSTANCE_PTR_
			     uiIndex_p, uiSubindex_p, NULL, &pSubindexEntry);
	if (Ret == kEplSuccessful) {
		// get var entry
		Ret = EplObdGetVarEntry(pSubindexEntry, ppVarEntry_p);
	}

	return Ret;

}

//=========================================================================//
//                                                                         //
//          P R I V A T E   D E F I N I T I O N S                          //
//                                                                         //
//=========================================================================//

EPL_MCO_DECL_INSTANCE_FCT()
//---------------------------------------------------------------------------
//
// Function:    EplObdCallObjectCallback()
//
// Description: calls callback function of an object or of a variable
//
// Parameters:  fpCallback_p
//              pCbParam_p
//
// Return:      tEplKernel
//
// State:
//
//---------------------------------------------------------------------------
static tEplKernel EplObdCallObjectCallback(EPL_MCO_DECL_INSTANCE_PTR_
					   tEplObdCallback fpCallback_p,
					   tEplObdCbParam MEM * pCbParam_p)
{

	tEplKernel Ret;
	tEplObdCallback MEM fpCallback;

	// check for all API function if instance is valid
	EPL_MCO_CHECK_INSTANCE_STATE();

	ASSERT(pCbParam_p != NULL);

	Ret = kEplSuccessful;

	// check address of callback function before calling it
	if (fpCallback_p != NULL) {
		// KEIL C51 V6.01 has a bug.
		// Therefore the parameter fpCallback_p has to be copied in local variable fpCallback.
		fpCallback = fpCallback_p;

		// call callback function for this object
		Ret = fpCallback(EPL_MCO_INSTANCE_PARAM_IDX_()
				 pCbParam_p);
	}

	return Ret;
}

//---------------------------------------------------------------------------
//
// Function:    EplObdGetDataSizeIntern()
//
// Description: gets the data size of an object
//              for string objects it returnes the string length
//
// Parameters:  pSubIndexEntry_p
//
// Return:      tEplObdSize
//
// State:
//
//---------------------------------------------------------------------------

static tEplObdSize EplObdGetDataSizeIntern(tEplObdSubEntryPtr pSubIndexEntry_p)
{

	tEplObdSize DataSize;
	void MEM *pData;

	// If OD entry is defined by macro EPL_OBD_SUBINDEX_ROM_VSTRING
	// then the current pointer is always NULL. The function
	// returns the length of default string.
	DataSize = EplObdGetObjectSize(pSubIndexEntry_p);

	if (pSubIndexEntry_p->m_Type == kEplObdTypVString) {
		// The pointer to current value can be received from EplObdGetObjectCurrentPtr()
		pData =
		    ((void MEM *)EplObdGetObjectCurrentPtr(pSubIndexEntry_p));
		if (pData != NULL) {
			DataSize =
			    EplObdGetStrLen((void *)pData, DataSize,
					    pSubIndexEntry_p->m_Type);
		}

	}

	return DataSize;

}

//---------------------------------------------------------------------------
//
// Function:    EplObdGetStrLen()
//
// Description: The function calculates the length of string. The '\0'
//              character is included!!
//
// Parameters:  pObjData_p          = pointer to string
//              ObjLen_p            = max. length of objectr entry
//              bObjType_p          = object type (VSTRING, ...)
//
// Returns:     string length + 1
//
// State:
//
//---------------------------------------------------------------------------

static tEplObdSize EplObdGetStrLen(void *pObjData_p,
				   tEplObdSize ObjLen_p, tEplObdType ObjType_p)
{

	tEplObdSize StrLen = 0;
	BYTE *pbString;

	if (pObjData_p == NULL) {
		goto Exit;
	}
	//----------------------------------------
	// Visible String: data format byte
	if (ObjType_p == kEplObdTypVString) {
		pbString = pObjData_p;

		for (StrLen = 0; StrLen < ObjLen_p; StrLen++) {
			if (*pbString == '\0') {
				StrLen++;
				break;
			}

			pbString++;
		}
	}
	//----------------------------------------
	// other string types ...

      Exit:
	return (StrLen);

}

#if (EPL_OBD_CHECK_OBJECT_RANGE != FALSE)

//---------------------------------------------------------------------------
//
// Function:    EplObdCheckObjectRange()
//
// Description: function to check value range of object data
//
// NOTICE: The pointer of data (pData_p) must point out to an even address,
//         if ObjType is unequal to kEplObdTypInt8 or kEplObdTypUInt8! But it is
//         always realiced because pointer m_pDefault points always to an
//         array of the SPECIFIED type.
//
// Parameters:  pSubindexEntry_p
//              pData_p
//
// Return:      tEplKernel
//
// State:
//
//---------------------------------------------------------------------------

static tEplKernel EplObdCheckObjectRange(tEplObdSubEntryPtr pSubindexEntry_p,
					 void *pData_p)
{

	tEplKernel Ret;
	void *pRangeData;

	ASSERTMSG(pSubindexEntry_p != NULL,
		  "EplObdCheckObjectRange(): no address to subindex struct!\n");

	Ret = kEplSuccessful;

	// check if data range has to be checked
	if ((pSubindexEntry_p->m_Access & kEplObdAccRange) == 0) {
		goto Exit;
	}
	// get address of default data
	pRangeData = pSubindexEntry_p->m_pDefault;

	// jump to called object type
	switch ((tEplObdType) pSubindexEntry_p->m_Type) {
		// -----------------------------------------------------------------
		// ObdType kEplObdTypBool will not be checked because there are only
		// two possible values 0 or 1.

		// -----------------------------------------------------------------
		// ObdTypes which has to be check up because numerical values
	case kEplObdTypInt8:

		// switch to lower limit
		pRangeData = ((tEplObdInteger8 *) pRangeData) + 1;

		// check if value is to low
		if (*((tEplObdInteger8 *) pData_p) <
		    *((tEplObdInteger8 *) pRangeData)) {
			Ret = kEplObdValueTooLow;
			break;
		}
		// switch to higher limit
		pRangeData = ((tEplObdInteger8 *) pRangeData) + 1;

		// check if value is to high
		if (*((tEplObdInteger8 *) pData_p) >
		    *((tEplObdInteger8 *) pRangeData)) {
			Ret = kEplObdValueTooHigh;
		}

		break;

	case kEplObdTypUInt8:

		// switch to lower limit
		pRangeData = ((tEplObdUnsigned8 *) pRangeData) + 1;

		// check if value is to low
		if (*((tEplObdUnsigned8 *) pData_p) <
		    *((tEplObdUnsigned8 *) pRangeData)) {
			Ret = kEplObdValueTooLow;
			break;
		}
		// switch to higher limit
		pRangeData = ((tEplObdUnsigned8 *) pRangeData) + 1;

		// check if value is to high
		if (*((tEplObdUnsigned8 *) pData_p) >
		    *((tEplObdUnsigned8 *) pRangeData)) {
			Ret = kEplObdValueTooHigh;
		}

		break;

	case kEplObdTypInt16:

		// switch to lower limit
		pRangeData = ((tEplObdInteger16 *) pRangeData) + 1;

		// check if value is to low
		if (*((tEplObdInteger16 *) pData_p) <
		    *((tEplObdInteger16 *) pRangeData)) {
			Ret = kEplObdValueTooLow;
			break;
		}
		// switch to higher limit
		pRangeData = ((tEplObdInteger16 *) pRangeData) + 1;

		// check if value is to high
		if (*((tEplObdInteger16 *) pData_p) >
		    *((tEplObdInteger16 *) pRangeData)) {
			Ret = kEplObdValueTooHigh;
		}

		break;

	case kEplObdTypUInt16:

		// switch to lower limit
		pRangeData = ((tEplObdUnsigned16 *) pRangeData) + 1;

		// check if value is to low
		if (*((tEplObdUnsigned16 *) pData_p) <
		    *((tEplObdUnsigned16 *) pRangeData)) {
			Ret = kEplObdValueTooLow;
			break;
		}
		// switch to higher limit
		pRangeData = ((tEplObdUnsigned16 *) pRangeData) + 1;

		// check if value is to high
		if (*((tEplObdUnsigned16 *) pData_p) >
		    *((tEplObdUnsigned16 *) pRangeData)) {
			Ret = kEplObdValueTooHigh;
		}

		break;

	case kEplObdTypInt32:

		// switch to lower limit
		pRangeData = ((tEplObdInteger32 *) pRangeData) + 1;

		// check if value is to low
		if (*((tEplObdInteger32 *) pData_p) <
		    *((tEplObdInteger32 *) pRangeData)) {
			Ret = kEplObdValueTooLow;
			break;
		}
		// switch to higher limit
		pRangeData = ((tEplObdInteger32 *) pRangeData) + 1;

		// check if value is to high
		if (*((tEplObdInteger32 *) pData_p) >
		    *((tEplObdInteger32 *) pRangeData)) {
			Ret = kEplObdValueTooHigh;
		}

		break;

	case kEplObdTypUInt32:

		// switch to lower limit
		pRangeData = ((tEplObdUnsigned32 *) pRangeData) + 1;

		// check if value is to low
		if (*((tEplObdUnsigned32 *) pData_p) <
		    *((tEplObdUnsigned32 *) pRangeData)) {
			Ret = kEplObdValueTooLow;
			break;
		}
		// switch to higher limit
		pRangeData = ((tEplObdUnsigned32 *) pRangeData) + 1;

		// check if value is to high
		if (*((tEplObdUnsigned32 *) pData_p) >
		    *((tEplObdUnsigned32 *) pRangeData)) {
			Ret = kEplObdValueTooHigh;
		}

		break;

	case kEplObdTypReal32:

		// switch to lower limit
		pRangeData = ((tEplObdReal32 *) pRangeData) + 1;

		// check if value is to low
		if (*((tEplObdReal32 *) pData_p) <
		    *((tEplObdReal32 *) pRangeData)) {
			Ret = kEplObdValueTooLow;
			break;
		}
		// switch to higher limit
		pRangeData = ((tEplObdReal32 *) pRangeData) + 1;

		// check if value is to high
		if (*((tEplObdReal32 *) pData_p) >
		    *((tEplObdReal32 *) pRangeData)) {
			Ret = kEplObdValueTooHigh;
		}

		break;

		// -----------------------------------------------------------------
	case kEplObdTypInt40:
	case kEplObdTypInt48:
	case kEplObdTypInt56:
	case kEplObdTypInt64:

		// switch to lower limit
		pRangeData = ((signed QWORD *)pRangeData) + 1;

		// check if value is to low
		if (*((signed QWORD *)pData_p) < *((signed QWORD *)pRangeData)) {
			Ret = kEplObdValueTooLow;
			break;
		}
		// switch to higher limit
		pRangeData = ((signed QWORD *)pRangeData) + 1;

		// check if value is to high
		if (*((signed QWORD *)pData_p) > *((signed QWORD *)pRangeData)) {
			Ret = kEplObdValueTooHigh;
		}

		break;

		// -----------------------------------------------------------------
	case kEplObdTypUInt40:
	case kEplObdTypUInt48:
	case kEplObdTypUInt56:
	case kEplObdTypUInt64:

		// switch to lower limit
		pRangeData = ((unsigned QWORD *)pRangeData) + 1;

		// check if value is to low
		if (*((unsigned QWORD *)pData_p) <
		    *((unsigned QWORD *)pRangeData)) {
			Ret = kEplObdValueTooLow;
			break;
		}
		// switch to higher limit
		pRangeData = ((unsigned QWORD *)pRangeData) + 1;

		// check if value is to high
		if (*((unsigned QWORD *)pData_p) >
		    *((unsigned QWORD *)pRangeData)) {
			Ret = kEplObdValueTooHigh;
		}

		break;

		// -----------------------------------------------------------------
	case kEplObdTypReal64:

		// switch to lower limit
		pRangeData = ((tEplObdReal64 *) pRangeData) + 1;

		// check if value is to low
		if (*((tEplObdReal64 *) pData_p) <
		    *((tEplObdReal64 *) pRangeData)) {
			Ret = kEplObdValueTooLow;
			break;
		}
		// switch to higher limit
		pRangeData = ((tEplObdReal64 *) pRangeData) + 1;

		// check if value is to high
		if (*((tEplObdReal64 *) pData_p) >
		    *((tEplObdReal64 *) pRangeData)) {
			Ret = kEplObdValueTooHigh;
		}

		break;

		// -----------------------------------------------------------------
	case kEplObdTypTimeOfDay:
	case kEplObdTypTimeDiff:
		break;

		// -----------------------------------------------------------------
		// ObdTypes kEplObdTypXString and kEplObdTypDomain can not be checkt because
		// they have no numerical value.
	default:

		Ret = kEplObdUnknownObjectType;
		break;
	}

      Exit:

	return Ret;

}
#endif // (EPL_OBD_CHECK_OBJECT_RANGE != FALSE)

//---------------------------------------------------------------------------
//
// Function:    EplObdWriteEntryPre()
//
// Description: Function prepares write of data to an OBD entry. Strings
//              are stored with added '\0' character.
//
// Parameters:  EPL_MCO_DECL_INSTANCE_PTR_
//              uiIndex_p       =   Index of the OD entry
//              uiSubIndex_p    =   Subindex of the OD Entry
//              pSrcData_p      =   Pointer to the data to write
//              Size_p          =   Size of the data in Byte
//
// Return:      tEplKernel      =   Errorcode
//
//
// State:
//
//---------------------------------------------------------------------------

static tEplKernel PUBLIC EplObdWriteEntryPre(EPL_MCO_DECL_INSTANCE_PTR_
					     unsigned int uiIndex_p,
					     unsigned int uiSubIndex_p,
					     void *pSrcData_p,
					     void **ppDstData_p,
					     tEplObdSize Size_p,
					     tEplObdEntryPtr * ppObdEntry_p,
					     tEplObdSubEntryPtr * ppSubEntry_p,
					     tEplObdCbParam MEM * pCbParam_p,
					     tEplObdSize * pObdSize_p)
{

	tEplKernel Ret;
	tEplObdEntryPtr pObdEntry;
	tEplObdSubEntryPtr pSubEntry;
	tEplObdAccess Access;
	void MEM *pDstData;
	tEplObdSize ObdSize;
	BOOL fEntryNumerical;

#if (EPL_OBD_USE_STRING_DOMAIN_IN_RAM != FALSE)
	tEplObdVStringDomain MEM MemVStringDomain;
	void MEM *pCurrData;
#endif

	// check for all API function if instance is valid
	EPL_MCO_CHECK_INSTANCE_STATE();

	ASSERT(pSrcData_p != NULL);	// should never be NULL

	//------------------------------------------------------------------------
	// get address of index and subindex entry
	Ret = EplObdGetEntry(EPL_MCO_INSTANCE_PTR_
			     uiIndex_p, uiSubIndex_p, &pObdEntry, &pSubEntry);
	if (Ret != kEplSuccessful) {
		goto Exit;
	}
	// get pointer to object data
	pDstData = (void MEM *)EplObdGetObjectDataPtrIntern(pSubEntry);

	Access = (tEplObdAccess) pSubEntry->m_Access;

	// check access for write
	// access violation if adress to current value is NULL
	if (((Access & kEplObdAccConst) != 0) || (pDstData == NULL)) {
		Ret = kEplObdAccessViolation;
		goto Exit;
	}
	//------------------------------------------------------------------------
	// get size of object
	// -as ObdSize = ObdGetObjectSize (pSubEntry);

	//------------------------------------------------------------------------
	// To use the same callback function for ObdWriteEntry as well as for
	// an SDO download call at first (kEplObdEvPre...) the callback function
	// with the argument pointer to object size.
	pCbParam_p->m_uiIndex = uiIndex_p;
	pCbParam_p->m_uiSubIndex = uiSubIndex_p;

	// Because object size and object pointer are
	// adapted by user callback function, re-read
	// this values.
	ObdSize = EplObdGetObjectSize(pSubEntry);
	pDstData = (void MEM *)EplObdGetObjectDataPtrIntern(pSubEntry);

	// 09-dec-2004 r.d.:
	//      Function EplObdWriteEntry() calls new event kEplObdEvWrStringDomain
	//      for String or Domain which lets called module directly change
	//      the data pointer or size. This prevents a recursive call to
	//      the callback function if it calls EplObdGetEntry().
#if (EPL_OBD_USE_STRING_DOMAIN_IN_RAM != FALSE)
	if ((pSubEntry->m_Type == kEplObdTypVString) ||
	    (pSubEntry->m_Type == kEplObdTypDomain) ||
	    (pSubEntry->m_Type == kEplObdTypOString)) {
		if (pSubEntry->m_Type == kEplObdTypVString) {
			// reserve one byte for 0-termination
			// -as ObdSize -= 1;
			Size_p += 1;
		}
		// fill out new arg-struct
		MemVStringDomain.m_DownloadSize = Size_p;
		MemVStringDomain.m_ObjSize = ObdSize;
		MemVStringDomain.m_pData = pDstData;

		pCbParam_p->m_ObdEvent = kEplObdEvWrStringDomain;
		pCbParam_p->m_pArg = &MemVStringDomain;
		//  call user callback
		Ret = EplObdCallObjectCallback(EPL_MCO_INSTANCE_PTR_
					       pObdEntry->m_fpCallback,
					       pCbParam_p);
		if (Ret != kEplSuccessful) {
			goto Exit;
		}
		// write back new settings
		pCurrData = pSubEntry->m_pCurrent;
		if ((pSubEntry->m_Type == kEplObdTypVString)
		    || (pSubEntry->m_Type == kEplObdTypOString)) {
			((tEplObdVString MEM *) pCurrData)->m_Size =
			    MemVStringDomain.m_ObjSize;
			((tEplObdVString MEM *) pCurrData)->m_pString =
			    MemVStringDomain.m_pData;
		} else		// if (pSdosTableEntry_p->m_bObjType == kEplObdTypDomain)
		{
			((tEplObdVarEntry MEM *) pCurrData)->m_Size =
			    MemVStringDomain.m_ObjSize;
			((tEplObdVarEntry MEM *) pCurrData)->m_pData =
			    (void MEM *)MemVStringDomain.m_pData;
		}

		// Because object size and object pointer are
		// adapted by user callback function, re-read
		// this values.
		ObdSize = MemVStringDomain.m_ObjSize;
		pDstData = (void MEM *)MemVStringDomain.m_pData;
	}
#endif //#if (OBD_USE_STRING_DOMAIN_IN_RAM != FALSE)

	// 07-dec-2004 r.d.: size from application is needed because callback function can change the object size
	// -as 16.11.04 CbParam.m_pArg     = &ObdSize;
	// 09-dec-2004 r.d.: CbParam.m_pArg     = &Size_p;
	pCbParam_p->m_pArg = &ObdSize;
	pCbParam_p->m_ObdEvent = kEplObdEvInitWrite;
	Ret = EplObdCallObjectCallback(EPL_MCO_INSTANCE_PTR_
				       pObdEntry->m_fpCallback, pCbParam_p);
	if (Ret != kEplSuccessful) {
		goto Exit;
	}

	if (Size_p > ObdSize) {
		Ret = kEplObdValueLengthError;
		goto Exit;
	}

	if (pSubEntry->m_Type == kEplObdTypVString) {
		if (((char MEM *)pSrcData_p)[Size_p - 1] == '\0') {	// last byte of source string contains null character

			// reserve one byte in destination for 0-termination
			Size_p -= 1;
		} else if (Size_p >= ObdSize) {	// source string is not 0-terminated
			// and destination buffer is too short
			Ret = kEplObdValueLengthError;
			goto Exit;
		}
	}

	Ret = EplObdIsNumericalIntern(pSubEntry, &fEntryNumerical);
	if (Ret != kEplSuccessful) {
		goto Exit;
	}

	if ((fEntryNumerical != FALSE)
	    && (Size_p != ObdSize)) {
		// type is numerical, therefor size has to fit, but it does not.
		Ret = kEplObdValueLengthError;
		goto Exit;
	}
	// use given size, because non-numerical objects can be written with shorter values
	ObdSize = Size_p;

	// set output parameters
	*pObdSize_p = ObdSize;
	*ppObdEntry_p = pObdEntry;
	*ppSubEntry_p = pSubEntry;
	*ppDstData_p = pDstData;

	// all checks are done
	// the caller may now convert the numerial source value to platform byte order in a temporary buffer

      Exit:

	return Ret;

}

//---------------------------------------------------------------------------
//
// Function:    EplObdWriteEntryPost()
//
// Description: Function finishes write of data to an OBD entry. Strings
//              are stored with added '\0' character.
//
// Parameters:  EPL_MCO_DECL_INSTANCE_PTR_
//              uiIndex_p       =   Index of the OD entry
//              uiSubIndex_p    =   Subindex of the OD Entry
//              pSrcData_p      =   Pointer to the data to write
//              Size_p          =   Size of the data in Byte
//
// Return:      tEplKernel      =   Errorcode
//
//
// State:
//
//---------------------------------------------------------------------------

static tEplKernel PUBLIC EplObdWriteEntryPost(EPL_MCO_DECL_INSTANCE_PTR_
					      tEplObdEntryPtr pObdEntry_p,
					      tEplObdSubEntryPtr pSubEntry_p,
					      tEplObdCbParam MEM * pCbParam_p,
					      void *pSrcData_p,
					      void *pDstData_p,
					      tEplObdSize ObdSize_p)
{

	tEplKernel Ret;

	// caller converted the source value to platform byte order
	// now the range of the value may be checked

#if (EPL_OBD_CHECK_OBJECT_RANGE != FALSE)
	{
		// check data range
		Ret = EplObdCheckObjectRange(pSubEntry_p, pSrcData_p);
		if (Ret != kEplSuccessful) {
			goto Exit;
		}
	}
#endif

	// now call user callback function to check value
	// write address of source data to structure of callback parameters
	// so callback function can check this data
	pCbParam_p->m_pArg = pSrcData_p;
	pCbParam_p->m_ObdEvent = kEplObdEvPreWrite;
	Ret = EplObdCallObjectCallback(EPL_MCO_INSTANCE_PTR_
				       pObdEntry_p->m_fpCallback, pCbParam_p);
	if (Ret != kEplSuccessful) {
		goto Exit;
	}
	// copy object data to OBD
	EPL_MEMCPY(pDstData_p, pSrcData_p, ObdSize_p);

	// terminate string with 0
	if (pSubEntry_p->m_Type == kEplObdTypVString) {
		((char MEM *)pDstData_p)[ObdSize_p] = '\0';
	}
	// write address of destination to structure of callback parameters
	// so callback function can change data subsequently
	pCbParam_p->m_pArg = pDstData_p;
	pCbParam_p->m_ObdEvent = kEplObdEvPostWrite;
	Ret = EplObdCallObjectCallback(EPL_MCO_INSTANCE_PTR_
				       pObdEntry_p->m_fpCallback, pCbParam_p);

      Exit:

	return Ret;

}

//---------------------------------------------------------------------------
//
// Function:    EplObdGetObjectSize()
//
// Description: function to get size of object
//              The function determines if an object type an fixed data type (BYTE, WORD, ...)
//              or non fixed object (string, domain). This information is used to decide
//              if download data are stored temporary or not. For objects with fixed data length
//              and types a value range checking can process.
//              For strings the function returns the whole object size not the
//              length of string.
//
// Parameters:  pSubIndexEntry_p
//
// Return:      tEplObdSize
//
// State:
//
//---------------------------------------------------------------------------

static tEplObdSize EplObdGetObjectSize(tEplObdSubEntryPtr pSubIndexEntry_p)
{

	tEplObdSize DataSize = 0;
	void *pData;

	switch (pSubIndexEntry_p->m_Type) {
		// -----------------------------------------------------------------
	case kEplObdTypBool:

		DataSize = 1;
		break;

		// -----------------------------------------------------------------
		// ObdTypes which has to be check because numerical values
	case kEplObdTypInt8:
		DataSize = sizeof(tEplObdInteger8);
		break;

		// -----------------------------------------------------------------
	case kEplObdTypUInt8:
		DataSize = sizeof(tEplObdUnsigned8);
		break;

		// -----------------------------------------------------------------
	case kEplObdTypInt16:
		DataSize = sizeof(tEplObdInteger16);
		break;

		// -----------------------------------------------------------------
	case kEplObdTypUInt16:
		DataSize = sizeof(tEplObdUnsigned16);
		break;

		// -----------------------------------------------------------------
	case kEplObdTypInt32:
		DataSize = sizeof(tEplObdInteger32);
		break;

		// -----------------------------------------------------------------
	case kEplObdTypUInt32:
		DataSize = sizeof(tEplObdUnsigned32);
		break;

		// -----------------------------------------------------------------
	case kEplObdTypReal32:
		DataSize = sizeof(tEplObdReal32);
		break;

		// -----------------------------------------------------------------
		// ObdTypes which has to be not checked because not NUM values
	case kEplObdTypDomain:

		pData = (void *)pSubIndexEntry_p->m_pCurrent;
		if ((void MEM *)pData != (void MEM *)NULL) {
			DataSize = ((tEplObdVarEntry MEM *) pData)->m_Size;
		}
		break;

		// -----------------------------------------------------------------
	case kEplObdTypVString:
		//case kEplObdTypUString:

		// If OD entry is defined by macro EPL_OBD_SUBINDEX_ROM_VSTRING
		// then the current pointer is always NULL. The function
		// returns the length of default string.
		pData = (void *)pSubIndexEntry_p->m_pCurrent;
		if ((void MEM *)pData != (void MEM *)NULL) {
			// The max. size of strings defined by STRING-Macro is stored in
			// tEplObdVString of current value.
			// (types tEplObdVString, tEplObdOString and tEplObdUString has the same members)
			DataSize = ((tEplObdVString MEM *) pData)->m_Size;
		} else {
			// The current position is not decleared. The string
			// is located in ROM, therefor use default pointer.
			pData = (void *)pSubIndexEntry_p->m_pDefault;
			if ((CONST void ROM *)pData != (CONST void ROM *)NULL) {
				// The max. size of strings defined by STRING-Macro is stored in
				// tEplObdVString of default value.
				DataSize =
				    ((CONST tEplObdVString ROM *) pData)->
				    m_Size;
			}
		}

		break;

		// -----------------------------------------------------------------
	case kEplObdTypOString:

		pData = (void *)pSubIndexEntry_p->m_pCurrent;
		if ((void MEM *)pData != (void MEM *)NULL) {
			// The max. size of strings defined by STRING-Macro is stored in
			// tEplObdVString of current value.
			// (types tEplObdVString, tEplObdOString and tEplObdUString has the same members)
			DataSize = ((tEplObdOString MEM *) pData)->m_Size;
		} else {
			// The current position is not decleared. The string
			// is located in ROM, therefor use default pointer.
			pData = (void *)pSubIndexEntry_p->m_pDefault;
			if ((CONST void ROM *)pData != (CONST void ROM *)NULL) {
				// The max. size of strings defined by STRING-Macro is stored in
				// tEplObdVString of default value.
				DataSize =
				    ((CONST tEplObdOString ROM *) pData)->
				    m_Size;
			}
		}
		break;

		// -----------------------------------------------------------------
	case kEplObdTypInt24:
	case kEplObdTypUInt24:

		DataSize = 3;
		break;

		// -----------------------------------------------------------------
	case kEplObdTypInt40:
	case kEplObdTypUInt40:

		DataSize = 5;
		break;

		// -----------------------------------------------------------------
	case kEplObdTypInt48:
	case kEplObdTypUInt48:

		DataSize = 6;
		break;

		// -----------------------------------------------------------------
	case kEplObdTypInt56:
	case kEplObdTypUInt56:

		DataSize = 7;
		break;

		// -----------------------------------------------------------------
	case kEplObdTypInt64:
	case kEplObdTypUInt64:
	case kEplObdTypReal64:

		DataSize = 8;
		break;

		// -----------------------------------------------------------------
	case kEplObdTypTimeOfDay:
	case kEplObdTypTimeDiff:

		DataSize = 6;
		break;

		// -----------------------------------------------------------------
	default:
		break;
	}

	return DataSize;
}

//---------------------------------------------------------------------------
//
// Function:    EplObdGetObjectDefaultPtr()
//
// Description: function to get the default pointer (type specific)
//
// Parameters:  pSubIndexEntry_p    = pointer to subindex structure
//
// Returns:     (void *)   = pointer to default value
//
// State:
//
//---------------------------------------------------------------------------

static void *EplObdGetObjectDefaultPtr(tEplObdSubEntryPtr pSubIndexEntry_p)
{

	void *pDefault;
	tEplObdType Type;

	ASSERTMSG(pSubIndexEntry_p != NULL,
		  "EplObdGetObjectDefaultPtr(): pointer to SubEntry not valid!\n");

	// get address to default data from default pointer
	pDefault = pSubIndexEntry_p->m_pDefault;
	if (pDefault != NULL) {
		// there are some special types, whose default pointer always is NULL or has to get from other structure
		// get type from subindex structure
		Type = pSubIndexEntry_p->m_Type;

		// check if object type is a string value
		if ((Type == kEplObdTypVString)	/* ||
						   (Type == kEplObdTypUString) */ ) {

			// EPL_OBD_SUBINDEX_RAM_VSTRING
			//    tEplObdSize         m_Size;       --> size of default string
			//    char *    m_pDefString; --> pointer to  default string
			//    char *    m_pString;    --> pointer to string in RAM
			//
			pDefault =
			    (void *)((tEplObdVString *) pDefault)->m_pString;
		} else if (Type == kEplObdTypOString) {
			pDefault =
			    (void *)((tEplObdOString *) pDefault)->m_pString;
		}
	}

	return pDefault;

}

//---------------------------------------------------------------------------
//
// Function:    EplObdGetVarEntry()
//
// Description: gets a variable entry of an object
//
// Parameters:  pSubindexEntry_p
//              ppVarEntry_p
//
// Return:      tCopKernel
//
// State:
//
//---------------------------------------------------------------------------

static tEplKernel EplObdGetVarEntry(tEplObdSubEntryPtr pSubindexEntry_p,
				    tEplObdVarEntry MEM ** ppVarEntry_p)
{

	tEplKernel Ret = kEplObdVarEntryNotExist;

	ASSERT(ppVarEntry_p != NULL);	// is not allowed to be NULL
	ASSERT(pSubindexEntry_p != NULL);

	// check VAR-Flag - only this object points to variables
	if ((pSubindexEntry_p->m_Access & kEplObdAccVar) != 0) {
		// check if object is an array
		if ((pSubindexEntry_p->m_Access & kEplObdAccArray) != 0) {
			*ppVarEntry_p =
			    &((tEplObdVarEntry MEM *) pSubindexEntry_p->
			      m_pCurrent)[pSubindexEntry_p->m_uiSubIndex - 1];
		} else {
			*ppVarEntry_p =
			    (tEplObdVarEntry MEM *) pSubindexEntry_p->
			    m_pCurrent;
		}

		Ret = kEplSuccessful;
	}

	return Ret;

}

//---------------------------------------------------------------------------
//
// Function:    EplObdGetEntry()
//
// Description: gets a index entry from OD
//
// Parameters:  uiIndex_p       =   Index number
//              uiSubindex_p    =   Subindex number
//              ppObdEntry_p    =   pointer to the pointer to the entry
//              ppObdSubEntry_p =   pointer to the pointer to the subentry
//
// Return:      tEplKernel

//
// State:
//
//---------------------------------------------------------------------------

static tEplKernel EplObdGetEntry(EPL_MCO_DECL_INSTANCE_PTR_
				 unsigned int uiIndex_p,
				 unsigned int uiSubindex_p,
				 tEplObdEntryPtr * ppObdEntry_p,
				 tEplObdSubEntryPtr * ppObdSubEntry_p)
{

	tEplObdEntryPtr pObdEntry;
	tEplObdCbParam MEM CbParam;
	tEplKernel Ret;

	// check for all API function if instance is valid
	EPL_MCO_CHECK_INSTANCE_STATE();

	//------------------------------------------------------------------------
	// get address of entry of index
	Ret =
	    EplObdGetIndexIntern(&EPL_MCO_GLB_VAR(m_ObdInitParam), uiIndex_p,
				 &pObdEntry);
	if (Ret != kEplSuccessful) {
		goto Exit;
	}
	//------------------------------------------------------------------------
	// get address of entry of subindex
	Ret = EplObdGetSubindexIntern(pObdEntry, uiSubindex_p, ppObdSubEntry_p);
	if (Ret != kEplSuccessful) {
		goto Exit;
	}
	//------------------------------------------------------------------------
	// call callback function to inform user/stack that an object will be searched
	// if the called module returnes an error then we abort the searching with kEplObdIndexNotExist
	CbParam.m_uiIndex = uiIndex_p;
	CbParam.m_uiSubIndex = uiSubindex_p;
	CbParam.m_pArg = NULL;
	CbParam.m_ObdEvent = kEplObdEvCheckExist;
	Ret = EplObdCallObjectCallback(EPL_MCO_INSTANCE_PTR_
				       pObdEntry->m_fpCallback, &CbParam);
	if (Ret != kEplSuccessful) {
		Ret = kEplObdIndexNotExist;
		goto Exit;
	}
	//------------------------------------------------------------------------
	// it is allowed to set ppObdEntry_p to NULL
	// if so, no address will be written to calling function
	if (ppObdEntry_p != NULL) {
		*ppObdEntry_p = pObdEntry;
	}

      Exit:

	return Ret;

}

//---------------------------------------------------------------------------
//
// Function:    EplObdGetObjectCurrentPtr()
//
// Description: function to get Current pointer (type specific)
//
// Parameters:  pSubIndexEntry_p
//
// Return:      void MEM*
//
// State:
//
//---------------------------------------------------------------------------

static void MEM *EplObdGetObjectCurrentPtr(tEplObdSubEntryPtr pSubIndexEntry_p)
{

	void MEM *pData;
	unsigned int uiArrayIndex;
	tEplObdSize Size;

	pData = pSubIndexEntry_p->m_pCurrent;

	// check if constant object
	if (pData != NULL) {
		// check if object is an array
		if ((pSubIndexEntry_p->m_Access & kEplObdAccArray) != 0) {
			// calculate correct data pointer
			uiArrayIndex = pSubIndexEntry_p->m_uiSubIndex - 1;
			if ((pSubIndexEntry_p->m_Access & kEplObdAccVar) != 0) {
				Size = sizeof(tEplObdVarEntry);
			} else {
				Size = EplObdGetObjectSize(pSubIndexEntry_p);
			}
			pData = ((BYTE MEM *) pData) + (Size * uiArrayIndex);
		}
		// check if VarEntry
		if ((pSubIndexEntry_p->m_Access & kEplObdAccVar) != 0) {
			// The data pointer is stored in VarEntry->pData
			pData = ((tEplObdVarEntry MEM *) pData)->m_pData;
		}
		// the default pointer is stored for strings in tEplObdVString
		else if ((pSubIndexEntry_p->m_Type == kEplObdTypVString)	/* ||
										   (pSubIndexEntry_p->m_Type == kEplObdTypUString)    */
			 ) {
			pData =
			    (void MEM *)((tEplObdVString MEM *) pData)->
			    m_pString;
		} else if (pSubIndexEntry_p->m_Type == kEplObdTypOString) {
			pData =
			    (void MEM *)((tEplObdOString MEM *) pData)->
			    m_pString;
		}
	}

	return pData;

}

//---------------------------------------------------------------------------
//
// Function:    EplObdGetIndexIntern()
//
// Description: gets a index entry from OD
//
// Parameters:  pInitParam_p
//              uiIndex_p
//              ppObdEntry_p
//
// Return:      tEplKernel
//
// State:
//
//---------------------------------------------------------------------------

static tEplKernel EplObdGetIndexIntern(tEplObdInitParam MEM * pInitParam_p,
				       unsigned int uiIndex_p,
				       tEplObdEntryPtr * ppObdEntry_p)
{

	tEplObdEntryPtr pObdEntry;
	tEplKernel Ret;
	unsigned int uiIndex;

#if (defined (EPL_OBD_USER_OD) && (EPL_OBD_USER_OD != FALSE))

	unsigned int nLoop;

	// if user OD is used then objekts also has to be searched in user OD
	// there is less code need if we do this in a loop
	nLoop = 2;

#endif

	ASSERTMSG(ppObdEntry_p != NULL,
		  "EplObdGetIndexIntern(): pointer to index entry is NULL!\n");

	Ret = kEplObdIndexNotExist;

	// get start address of OD part
	// start address depends on object index because
	// object dictionary is divided in 3 parts
	if ((uiIndex_p >= 0x1000) && (uiIndex_p < 0x2000)) {
		pObdEntry = pInitParam_p->m_pPart;
	} else if ((uiIndex_p >= 0x2000) && (uiIndex_p < 0x6000)) {
		pObdEntry = pInitParam_p->m_pManufacturerPart;
	}
	// index range 0xA000 to 0xFFFF is reserved for DSP-405
	// DS-301 defines that range 0x6000 to 0x9FFF (!!!) is stored if "store" was written to 0x1010/3.
	// Therefore default configuration is OBD_INCLUDE_A000_TO_DEVICE_PART = FALSE.
	// But a CANopen Application which does not implement dynamic OD or user-OD but wants to use static objets 0xA000...
	// should set OBD_INCLUDE_A000_TO_DEVICE_PART to TRUE.

#if (EPL_OBD_INCLUDE_A000_TO_DEVICE_PART == FALSE)
	else if ((uiIndex_p >= 0x6000) && (uiIndex_p < 0x9FFF))
#else
	else if ((uiIndex_p >= 0x6000) && (uiIndex_p < 0xFFFF))
#endif
	{
		pObdEntry = pInitParam_p->m_pDevicePart;
	}

#if (defined (EPL_OBD_USER_OD) && (EPL_OBD_USER_OD != FALSE))

	// if index does not match in static OD then index only has to be searched in user OD
	else {
		// begin from first entry of user OD part
		pObdEntry = pInitParam_p->m_pUserPart;

		// no user OD is available
		if (pObdEntry == NULL) {
			goto Exit;
		}
		// loop must only run once
		nLoop = 1;
	}

	do {

#else

	// no user OD is available
	// so other object can be found in OD
	else {
		Ret = kEplObdIllegalPart;
		goto Exit;
	}

#endif

	// note:
	// The end of Index table is marked with m_uiIndex = 0xFFFF.
	// If this function will be called with wIndex_p = 0xFFFF, entry
	// should not be found. Therefor it is important to use
	// while{} instead of do{}while !!!

	// get first index of index table
	uiIndex = pObdEntry->m_uiIndex;

	// search Index in OD part
	while (uiIndex != EPL_OBD_TABLE_INDEX_END) {
		// go to the end of this function if index is found
		if (uiIndex_p == uiIndex) {
			// write address of OD entry to calling function
			*ppObdEntry_p = pObdEntry;
			Ret = kEplSuccessful;
			goto Exit;
		}
		// objects are sorted in OD
		// if the current index in OD is greater than the index which is to search then break loop
		// in this case user OD has to be search too
		if (uiIndex_p < uiIndex) {
			break;
		}
		// next entry in index table
		pObdEntry++;

		// get next index of index table
		uiIndex = pObdEntry->m_uiIndex;
	}

#if (defined (EPL_OBD_USER_OD) && (EPL_OBD_USER_OD != FALSE))

	// begin from first entry of user OD part
	pObdEntry = pInitParam_p->m_pUserPart;

	// no user OD is available
	if (pObdEntry == NULL) {
		goto Exit;
	}
	// switch next loop for user OD
	nLoop--;

}

while (nLoop > 0) ;

#endif

    // in this line Index was not found

Exit:

return Ret;

}

//---------------------------------------------------------------------------
//
// Function:    EplObdGetSubindexIntern()
//
// Description: gets a subindex entry from a index entry
//
// Parameters:  pObdEntry_p
//              bSubIndex_p
//              ppObdSubEntry_p
//
// Return:      tEplKernel
//
// State:
//
//---------------------------------------------------------------------------

static tEplKernel EplObdGetSubindexIntern(tEplObdEntryPtr pObdEntry_p,
					  unsigned int uiSubIndex_p,
					  tEplObdSubEntryPtr * ppObdSubEntry_p)
{

	tEplObdSubEntryPtr pSubEntry;
	unsigned int nSubIndexCount;
	tEplKernel Ret;

	ASSERTMSG(pObdEntry_p != NULL,
		  "EplObdGetSubindexIntern(): pointer to index is NULL!\n");
	ASSERTMSG(ppObdSubEntry_p != NULL,
		  "EplObdGetSubindexIntern(): pointer to subindex is NULL!\n");

	Ret = kEplObdSubindexNotExist;

	// get start address of subindex table and count of subindices
	pSubEntry = pObdEntry_p->m_pSubIndex;
	nSubIndexCount = pObdEntry_p->m_uiCount;
	ASSERTMSG((pSubEntry != NULL) && (nSubIndexCount > 0), "ObdGetSubindexIntern(): invalid subindex table within index table!\n");	// should never be NULL

	// search subindex in subindex table
	while (nSubIndexCount > 0) {
		// check if array is found
		if ((pSubEntry->m_Access & kEplObdAccArray) != 0) {
			// check if subindex is in range
			if (uiSubIndex_p < pObdEntry_p->m_uiCount) {
				// update subindex number (subindex entry of an array is always in RAM !!!)
				pSubEntry->m_uiSubIndex = uiSubIndex_p;
				*ppObdSubEntry_p = pSubEntry;
				Ret = kEplSuccessful;
				goto Exit;
			}
		}
		// go to the end of this function if subindex is found
		else if (uiSubIndex_p == pSubEntry->m_uiSubIndex) {
			*ppObdSubEntry_p = pSubEntry;
			Ret = kEplSuccessful;
			goto Exit;
		}
		// objects are sorted in OD
		// if the current subindex in OD is greater than the subindex which is to search then break loop
		// in this case user OD has to be search too
		if (uiSubIndex_p < pSubEntry->m_uiSubIndex) {
			break;
		}

		pSubEntry++;
		nSubIndexCount--;
	}

	// in this line SubIndex was not fount

      Exit:

	return Ret;

}

//---------------------------------------------------------------------------
//
// Function:    EplObdSetStoreLoadObjCallback()
//
// Description: function set address to callbackfunction for command Store and Load
//
// Parameters:  fpCallback_p
//
// Return:      tEplKernel
//
// State:
//
//---------------------------------------------------------------------------
#if (EPL_OBD_USE_STORE_RESTORE != FALSE)
EPLDLLEXPORT tEplKernel PUBLIC
EplObdSetStoreLoadObjCallback(EPL_MCO_DECL_INSTANCE_PTR_
			      tEplObdStoreLoadObjCallback fpCallback_p)
{

	EPL_MCO_CHECK_INSTANCE_STATE();

	// set new address of callback function
	EPL_MCO_GLB_VAR(m_fpStoreLoadObjCallback) = fpCallback_p;

	return kEplSuccessful;

}
#endif // (EPL_OBD_USE_STORE_RESTORE != FALSE)

//---------------------------------------------------------------------------
//
// Function:    EplObdAccessOdPartIntern()
//
// Description: runs through OD and executes a job
//
// Parameters:  CurrentOdPart_p
//              pObdEnty_p
//              Direction_p     = what is to do (load values from flash or EEPROM, store, ...)
//
// Return:      tEplKernel
//
// State:
//
//---------------------------------------------------------------------------

static tEplKernel EplObdAccessOdPartIntern(EPL_MCO_DECL_INSTANCE_PTR_
					   tEplObdPart CurrentOdPart_p,
					   tEplObdEntryPtr pObdEnty_p,
					   tEplObdDir Direction_p)
{

	tEplObdSubEntryPtr pSubIndex;
	unsigned int nSubIndexCount;
	tEplObdAccess Access;
	void MEM *pDstData;
	void *pDefault;
	tEplObdSize ObjSize;
	tEplKernel Ret;
	tEplObdCbStoreParam MEM CbStore;
	tEplObdVarEntry MEM *pVarEntry;

	ASSERT(pObdEnty_p != NULL);

	Ret = kEplSuccessful;

	// prepare structure for STORE RESTORE callback function
	CbStore.m_bCurrentOdPart = (BYTE) CurrentOdPart_p;
	CbStore.m_pData = NULL;
	CbStore.m_ObjSize = 0;

	// command of first action depends on direction to access
#if (EPL_OBD_USE_STORE_RESTORE != FALSE)
	if (Direction_p == kEplObdDirLoad) {
		CbStore.m_bCommand = (BYTE) kEplObdCommOpenRead;

		// call callback function for previous command
		Ret = EplObdCallStoreCallback(EPL_MCO_INSTANCE_PTR_ & CbStore);
		if (Ret != kEplSuccessful) {
			goto Exit;
		}
		// set command for index and subindex loop
		CbStore.m_bCommand = (BYTE) kEplObdCommReadObj;
	} else if (Direction_p == kEplObdDirStore) {
		CbStore.m_bCommand = (BYTE) kEplObdCommOpenWrite;

		// call callback function for previous command
		Ret = EplObdCallStoreCallback(EPL_MCO_INSTANCE_PTR_ & CbStore);
		if (Ret != kEplSuccessful) {
			goto Exit;
		}
		// set command for index and subindex loop
		CbStore.m_bCommand = (BYTE) kEplObdCommWriteObj;
	}
#endif // (EPL_OBD_USE_STORE_RESTORE != FALSE)

	// we should not restore the OD values here
	// the next NMT command "Reset Node" or "Reset Communication" resets the OD data
	if (Direction_p != kEplObdDirRestore) {
		// walk through OD part till end is found
		while (pObdEnty_p->m_uiIndex != EPL_OBD_TABLE_INDEX_END) {
			// get address to subindex table and count of subindices
			pSubIndex = pObdEnty_p->m_pSubIndex;
			nSubIndexCount = pObdEnty_p->m_uiCount;
			ASSERT((pSubIndex != NULL) && (nSubIndexCount > 0));	// should never be NULL

			// walk through subindex table till all subinices were restored
			while (nSubIndexCount != 0) {
				Access = (tEplObdAccess) pSubIndex->m_Access;

				// get pointer to current and default data
				pDefault = EplObdGetObjectDefaultPtr(pSubIndex);
				pDstData = EplObdGetObjectCurrentPtr(pSubIndex);

				// NOTE (for kEplObdTypVString):
				//      The function returnes the max. number of bytes for a
				//      current string.
				//      r.d.: For stings the default-size will be read in other lines following (kEplObdDirInit).
				ObjSize = EplObdGetObjectSize(pSubIndex);

				// switch direction of OD access
				switch (Direction_p) {
					// --------------------------------------------------------------------------
					// VarEntry structures has to be initialized
				case kEplObdDirInit:

					// If VAR-Flag is set, m_pCurrent means not address of data
					// but address of tEplObdVarEntry. Address of data has to be get from
					// this structure.
					if ((Access & kEplObdAccVar) != 0) {
						EplObdGetVarEntry(pSubIndex,
								  &pVarEntry);
						EplObdInitVarEntry(pVarEntry,
								   pSubIndex->
								   m_Type,
								   ObjSize);
/*
                            if ((Access & kEplObdAccArray) == 0)
                            {
                                EplObdInitVarEntry (pSubIndex->m_pCurrent, pSubIndex->m_Type, ObjSize);
                            }
                            else
                            {
                                EplObdInitVarEntry ((tEplObdVarEntry MEM*) (((BYTE MEM*) pSubIndex->m_pCurrent) + (sizeof (tEplObdVarEntry) * pSubIndex->m_uiSubIndex)),
                                    pSubIndex->m_Type, ObjSize);
                            }
*/
						// at this time no application variable is defined !!!
						// therefore data can not be copied.
						break;
					} else if (pSubIndex->m_Type ==
						   kEplObdTypVString) {
						// If pointer m_pCurrent is not equal to NULL then the
						// string was defined with EPL_OBD_SUBINDEX_RAM_VSTRING. The current
						// pointer points to struct tEplObdVString located in MEM.
						// The element size includes the max. number of
						// bytes. The element m_pString includes the pointer
						// to string in MEM. The memory location of default string
						// must be copied to memory location of current string.

						pDstData =
						    pSubIndex->m_pCurrent;
						if (pDstData != NULL) {
							// 08-dec-2004: code optimization !!!
							//              entries ((tEplObdVStringDef ROM*) pSubIndex->m_pDefault)->m_pString
							//              and ((tEplObdVStringDef ROM*) pSubIndex->m_pDefault)->m_Size were read
							//              twice. thats not necessary!

							// For copying data we have to set the destination pointer to the real RAM string. This
							// pointer to RAM string is located in default string info structure. (translated r.d.)
							pDstData =
							    (void MEM
							     *)((tEplObdVStringDef ROM *) pSubIndex->m_pDefault)->m_pString;
							ObjSize =
							    ((tEplObdVStringDef
							      ROM *) pSubIndex->
							     m_pDefault)->
							    m_Size;

							((tEplObdVString MEM *)
							 pSubIndex->
							 m_pCurrent)->
				     m_pString = pDstData;
							((tEplObdVString MEM *)
							 pSubIndex->
							 m_pCurrent)->m_Size =
				     ObjSize;
						}

					} else if (pSubIndex->m_Type ==
						   kEplObdTypOString) {
						pDstData =
						    pSubIndex->m_pCurrent;
						if (pDstData != NULL) {
							// 08-dec-2004: code optimization !!!
							//              entries ((tEplObdOStringDef ROM*) pSubIndex->m_pDefault)->m_pString
							//              and ((tEplObdOStringDef ROM*) pSubIndex->m_pDefault)->m_Size were read
							//              twice. thats not necessary!

							// For copying data we have to set the destination pointer to the real RAM string. This
							// pointer to RAM string is located in default string info structure. (translated r.d.)
							pDstData =
							    (void MEM
							     *)((tEplObdOStringDef ROM *) pSubIndex->m_pDefault)->m_pString;
							ObjSize =
							    ((tEplObdOStringDef
							      ROM *) pSubIndex->
							     m_pDefault)->
							    m_Size;

							((tEplObdOString MEM *)
							 pSubIndex->
							 m_pCurrent)->
				     m_pString = pDstData;
							((tEplObdOString MEM *)
							 pSubIndex->
							 m_pCurrent)->m_Size =
				     ObjSize;
						}

					}

					// no break !! because copy of data has to done too.

					// --------------------------------------------------------------------------
					// all objects has to be restored with default values
				case kEplObdDirRestore:

					// 09-dec-2004 r.d.: optimization! the same code for kEplObdDirRestore and kEplObdDirLoad
					//                   is replaced to function ObdCopyObjectData() with a new parameter.

					// restore object data for init phase
					EplObdCopyObjectData(pDstData, pDefault,
							     ObjSize,
							     pSubIndex->m_Type);
					break;

					// --------------------------------------------------------------------------
					// objects with attribute kEplObdAccStore has to be load from EEPROM or from a file
				case kEplObdDirLoad:

					// restore object data for init phase
					EplObdCopyObjectData(pDstData, pDefault,
							     ObjSize,
							     pSubIndex->m_Type);

					// no break !! because callback function has to be called too.

					// --------------------------------------------------------------------------
					// objects with attribute kEplObdAccStore has to be stored in EEPROM or in a file
				case kEplObdDirStore:

					// when attribute kEplObdAccStore is set, then call callback function
#if (EPL_OBD_USE_STORE_RESTORE != FALSE)
					if ((Access & kEplObdAccStore) != 0) {
						// fill out data pointer and size of data
						CbStore.m_pData = pDstData;
						CbStore.m_ObjSize = ObjSize;

						// call callback function for read or write object
						Ret =
						    ObdCallStoreCallback
						    (EPL_MCO_INSTANCE_PTR_ &
						     CbStore);
						if (Ret != kEplSuccessful) {
							goto Exit;
						}
					}
#endif // (EPL_OBD_USE_STORE_RESTORE != FALSE)
					break;

					// --------------------------------------------------------------------------
					// if OD Builder key has to be checked no access to subindex and data should be made
				case kEplObdDirOBKCheck:

					// no break !! because we want to break the second loop too.

					// --------------------------------------------------------------------------
					// unknown Direction
				default:

					// so we can break the second loop earler
					nSubIndexCount = 1;
					break;
				}

				nSubIndexCount--;

				// next subindex entry
				if ((Access & kEplObdAccArray) == 0) {
					pSubIndex++;
					if ((nSubIndexCount > 0)
					    &&
					    ((pSubIndex->
					      m_Access & kEplObdAccArray) !=
					     0)) {
						// next subindex points to an array
						// reset subindex number
						pSubIndex->m_uiSubIndex = 1;
					}
				} else {
					if (nSubIndexCount > 0) {
						// next subindex points to an array
						// increment subindex number
						pSubIndex->m_uiSubIndex++;
					}
				}
			}

			// next index entry
			pObdEnty_p++;
		}
	}
	// -----------------------------------------------------------------------------------------
	// command of last action depends on direction to access
	if (Direction_p == kEplObdDirOBKCheck) {

		goto Exit;
	}
#if (EPL_OBD_USE_STORE_RESTORE != FALSE)
	else {
		if (Direction_p == kEplObdDirLoad) {
			CbStore.m_bCommand = (BYTE) kEplObdCommCloseRead;
		} else if (Direction_p == kEplObdDirStore) {
			CbStore.m_bCommand = (BYTE) kEplObdCommCloseWrite;
		} else if (Direction_p == kEplObdDirRestore) {
			CbStore.m_bCommand = (BYTE) kEplObdCommClear;
		} else {
			goto Exit;
		}

		// call callback function for last command
		Ret = EplObdCallStoreCallback(EPL_MCO_INSTANCE_PTR_ & CbStore);
	}
#endif // (EPL_OBD_USE_STORE_RESTORE != FALSE)

//    goto Exit;

      Exit:

	return Ret;

}

// ----------------------------------------------------------------------------
// Function:    EplObdCopyObjectData()
//
// Description: checks pointers to object data and copy them from source to destination
//
// Parameters:  pDstData_p              = destination pointer
//              pSrcData_p              = source pointer
//              ObjSize_p               = size of object
//              ObjType_p               =
//
// Returns:     tEplKernel              = error code
// ----------------------------------------------------------------------------

static void EplObdCopyObjectData(void MEM * pDstData_p,
				 void *pSrcData_p,
				 tEplObdSize ObjSize_p, tEplObdType ObjType_p)
{

	tEplObdSize StrSize = 0;

	// it is allowed to set default and current address to NULL (nothing to copy)
	if (pDstData_p != NULL) {

		if (ObjType_p == kEplObdTypVString) {
			// The function calculates the really number of characters of string. The
			// object entry size can be bigger as string size of default string.
			// The '\0'-termination is included. A string with no characters has a
			// size of 1.
			StrSize =
			    EplObdGetStrLen((void *)pSrcData_p, ObjSize_p,
					    kEplObdTypVString);

			// If the string length is greater than or equal to the entry size in OD then only copy
			// entry size - 1 and always set the '\0'-termination.
			if (StrSize >= ObjSize_p) {
				StrSize = ObjSize_p - 1;
			}
		}

		if (pSrcData_p != NULL) {
			// copy data
			EPL_MEMCPY(pDstData_p, pSrcData_p, ObjSize_p);

			if (ObjType_p == kEplObdTypVString) {
				((char MEM *)pDstData_p)[StrSize] = '\0';
			}
		}
	}

}

//---------------------------------------------------------------------------
//
// Function:    EplObdIsNumericalIntern()
//
// Description: function checks if a entry is numerical or not
//
//
// Parameters:  EPL_MCO_DECL_INSTANCE_PTR_ = Instancepointer
//              uiIndex_p           = Index
//              uiSubIndex_p        = Subindex
//              pfEntryNumerical_p  = pointer to BOOL for returnvalue
//                                  -> TRUE if entry a numerical value
//                                  -> FALSE if entry not a numerical value
//
// Return:      tEplKernel = Errorcode
//
// State:
//
//---------------------------------------------------------------------------
static tEplKernel EplObdIsNumericalIntern(tEplObdSubEntryPtr pObdSubEntry_p,
					  BOOL * pfEntryNumerical_p)
{
	tEplKernel Ret = kEplSuccessful;

	// get Type
	if ((pObdSubEntry_p->m_Type == kEplObdTypVString)
	    || (pObdSubEntry_p->m_Type == kEplObdTypOString)
	    || (pObdSubEntry_p->m_Type == kEplObdTypDomain)) {	// not numerical types
		*pfEntryNumerical_p = FALSE;
	} else {		// numerical types
		*pfEntryNumerical_p = TRUE;
	}

	return Ret;

}

// -------------------------------------------------------------------------
// function to classify object type (fixed/non fixed)
// -------------------------------------------------------------------------

// ----------------------------------------------------------------------------
// Function:    EplObdCallStoreCallback()
//
// Description: checks address to callback function and calles it when unequal
//              to NULL
//
// Parameters:  EPL_MCO_DECL_INSTANCE_PTR_ = (instance pointer)
//              pCbStoreParam_p        = address to callback parameters
//
// Returns:     tEplKernel             = error code
// ----------------------------------------------------------------------------
#if (EPL_OBD_USE_STORE_RESTORE != FALSE)
static tEplKernel EplObdCallStoreCallback(EPL_MCO_DECL_INSTANCE_PTR_
					  tEplObdCbStoreParam MEM *
					  pCbStoreParam_p)
{

	tEplKernel Ret = kEplSuccessful;

	ASSERT(pCbStoreParam_p != NULL);

	// check if function pointer is NULL - if so, no callback should be called
	if (EPL_MCO_GLB_VAR(m_fpStoreLoadObjCallback) != NULL) {
		Ret =
		    EPL_MCO_GLB_VAR(m_fpStoreLoadObjCallback)
		    (EPL_MCO_INSTANCE_PARAM_IDX_()
		     pCbStoreParam_p);
	}

	return Ret;

}
#endif // (EPL_OBD_USE_STORE_RESTORE != FALSE)
//---------------------------------------------------------------------------
//
// Function:    EplObdGetObjectDataPtrIntern()
//
// Description: Function gets the data pointer of an object.
//              It returnes the current data pointer. But if object is an
//              constant object it returnes the default pointer.
//
// Parameters:  pSubindexEntry_p = pointer to subindex entry
//
// Return:      void *    = pointer to object data
//
// State:
//
//---------------------------------------------------------------------------

void *EplObdGetObjectDataPtrIntern(tEplObdSubEntryPtr pSubindexEntry_p)
{

	void *pData;
	tEplObdAccess Access;

	ASSERTMSG(pSubindexEntry_p != NULL,
		  "EplObdGetObjectDataPtrIntern(): pointer to SubEntry not valid!\n");

	// there are are some objects whose data pointer has to get from other structure
	// get access type for this object
	Access = pSubindexEntry_p->m_Access;

	// If object has access type = const,
	// for data only exists default values.
	if ((Access & kEplObdAccConst) != 0) {
		// The pointer to defualt value can be received from ObdGetObjectDefaultPtr()
		pData = ((void *)EplObdGetObjectDefaultPtr(pSubindexEntry_p));
	} else {
		// The pointer to current value can be received from ObdGetObjectCurrentPtr()
		pData = ((void *)EplObdGetObjectCurrentPtr(pSubindexEntry_p));
	}

	return pData;

}
#endif // end of #if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_OBDK)) != 0)
// EOF
