summaryrefslogblamecommitdiffstats
path: root/drivers/staging/epl/EplSdoAsySequ.c
blob: 256d70866343ed1b9f1ca5f5361b081cd15df0d5 (plain) (tree)
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500







































































                                                                             


                                                                  
                                                   



















                                                                             
                                                                   
 
                                                                 
 
                                                                                                             

















                                                                                       







                                                                        

                               
                




                                                                                                           

                                                          
 
                       

                             







                                        

                               


                                   

                                                                              






                                                                                       

                     



                                                                 

                                     

                                              
 

                                                     

      
                         




                                                                             
                                                   




                                                                             




                                                                  
 



                                                                            
 


                                                                                
 


                                                           


                                             


                                                                                
 
                                                                                
                                                                 
 



                                                                              
 

                                                                         
 

                                                                          








































                                                                             

                                                             
 
                       
 
                                                                     
 
                   





















                                                                             

                                                                    
 




























                                                                        
                                     









                                                                           

      
                                                           




                                                        


                                                            




                                                         

      

                   



















                                                                             
                                        
 















                                                                            

                                     

                                                                       

      

                                                                              

                                                           

                                      


                                                            

                                       

      
                   




















                                                                                   


                                                                 
 













                                                                      
                                                           



                                                                        
     
                                                        
      

                              
 


                                
                                                            



                                                                         
     
                                                        
      




































                                                                                            
                                                           



                                                                          
      

                                              
 


                                                
                                                            



                                                                           
      



































                                                                                

 





















                                                                                     


                                                                
 





















                                                                             

 

















                                                                             
                                                        
 



















































                                                                         



















                                                                             
                                                              
 















































                                                                               

































                                                                                         




                                                                  
 





                                        

                                     

                                                                      

      

























































                                                                                          

                                                   
                                     


                                                             


























































































                                                                                                                                                                                                                  

                                                     

























































































































































                                                                                                                                                                                                                  

                                                     
















































































































































































































































































































































































                                                                                                                                                                                                                  
                                                           










































                                                                                          

                                                                                      























































































































































                                                                                                                                                                                                      

                                                                                        






















































































































































































































































































                                                                                                                                                                    

                                     

                                                                      
      
                   


























                                                                                         



                                                                            
 
                       
                                       





















































                                                                                                           


















                                                                                 


                                                                                
 
                       
 


                                                                                                                
                                                           

                                                                                                           
     
                                                

      
                                                                                                               
                                                            

                                                                                                           
     
                                                
      


                                           
 
                   




















                                                                             


                                                           
 



                                                       

                                     

                                                                             

      
                                                                               
                                                         






































                                                                          
                                     

                                                                             

      



                                                                                        
 

                   




















                                                                             

                             
 





                                                                          
 
                   

 



















                                                                                     


                                                                                
 










































                                                                                                 

 

















                                                                                     
                                                                                
                                                                
 

                                       

                          










































                                                                                                                    






















                                                                                          



                                                                              
 

                                       
 
                             
 
                                        
 

                                                     
 






                                                                                                              

                                                                                                                                                                                       
 



                                                                        
 

                                                                         
 



                                                                
 
                
                                                                                                                                                                                  
 


                                         
 

                               
 
                   



















                                                                                     

                                                                         
 
                                   
 

                                                                          
 
                             



















                                                                                     

                                                                          
 

                              
 

                                                          
 





                                                                             
 
         
 
                   


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

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

  Project:      openPOWERLINK

  Description:  source file for asychronous SDO Sequence Layer 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: EplSdoAsySequ.c,v $

                $Author: D.Krueger $

                $Revision: 1.10 $  $Date: 2008/11/13 17:13:09 $

                $State: Exp $

                Build Environment:
                    GCC V3.4

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

  Revision History:

  2006/06/26 k.t.:   start of the implementation

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

#include "user/EplSdoAsySequ.h"

#if ((((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDO_UDP)) == 0) &&\
     (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDO_ASND)) == 0)   )

#error 'ERROR: At least UDP or Asnd module needed!'

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

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

#define EPL_SDO_HISTORY_SIZE        5

#ifndef EPL_MAX_SDO_SEQ_CON
#define EPL_MAX_SDO_SEQ_CON         10
#endif

#define EPL_SEQ_DEFAULT_TIMEOUT     5000	// in [ms] => 5 sec

#define EPL_SEQ_RETRY_COUNT         5	// => max. Timeout 30 sec

#define EPL_SEQ_NUM_THRESHOLD       100	// threshold which distinguishes between old and new sequence numbers

// define frame with size of Asnd-Header-, SDO Sequenze Header size, SDO Command header
// and Ethernet-Header size
#define EPL_SEQ_FRAME_SIZE          24
// size of the header of the asynchronus SDO Sequence layer
#define EPL_SEQ_HEADER_SIZE         4

// buffersize for one frame in history
#define EPL_SEQ_HISTROY_FRAME_SIZE  EPL_MAX_SDO_FRAME_SIZE

// mask to get scon and rcon
#define EPL_ASY_SDO_CON_MASK        0x03

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

// events for processfunction
typedef enum {
	kAsySdoSeqEventNoEvent = 0x00,	// no Event
	kAsySdoSeqEventInitCon = 0x01,	// init connection
	kAsySdoSeqEventFrameRec = 0x02,	// frame received
	kAsySdoSeqEventFrameSend = 0x03,	// frame to send
	kAsySdoSeqEventTimeout = 0x04,	// Timeout for connection
	kAsySdoSeqEventCloseCon = 0x05	// higher layer close connection
} tEplAsySdoSeqEvent;

// structure for History-Buffer
typedef struct {
	u8 m_bFreeEntries;
	u8 m_bWrite;		// index of the next free buffer entry
	u8 m_bAck;		// index of the next message which should become acknowledged
	u8 m_bRead;		// index between m_bAck and m_bWrite to the next message for retransmission
	u8 m_aabHistoryFrame[EPL_SDO_HISTORY_SIZE]
	    [EPL_SEQ_HISTROY_FRAME_SIZE];
	unsigned int m_auiFrameSize[EPL_SDO_HISTORY_SIZE];

} tEplAsySdoConHistory;

// state of the statemaschine
typedef enum {
	kEplAsySdoStateIdle = 0x00,
	kEplAsySdoStateInit1 = 0x01,
	kEplAsySdoStateInit2 = 0x02,
	kEplAsySdoStateInit3 = 0x03,
	kEplAsySdoStateConnected = 0x04,
	kEplAsySdoStateWaitAck = 0x05
} tEplAsySdoState;

// connection control structure
typedef struct {
	tEplSdoConHdl m_ConHandle;
	tEplAsySdoState m_SdoState;
	u8 m_bRecSeqNum;	// name from view of the communication partner
	u8 m_bSendSeqNum;	// name from view of the communication partner
	tEplAsySdoConHistory m_SdoConHistory;
	tEplTimerHdl m_EplTimerHdl;
	unsigned int m_uiRetryCount;	// retry counter
	unsigned int m_uiUseCount;	// one sequence layer connection may be used by
	// multiple command layer connections

} tEplAsySdoSeqCon;

// instance structure
typedef struct {
	tEplAsySdoSeqCon m_AsySdoConnection[EPL_MAX_SDO_SEQ_CON];
	tEplSdoComReceiveCb m_fpSdoComReceiveCb;
	tEplSdoComConCb m_fpSdoComConCb;

#if defined(WIN32) || defined(_WIN32)
	LPCRITICAL_SECTION m_pCriticalSection;
	CRITICAL_SECTION m_CriticalSection;

	LPCRITICAL_SECTION m_pCriticalSectionReceive;
	CRITICAL_SECTION m_CriticalSectionReceive;
#endif

} tEplAsySdoSequInstance;

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

static tEplAsySdoSequInstance AsySdoSequInstance_g;

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

static tEplKernel EplSdoAsySeqProcess(unsigned int uiHandle_p,
				      unsigned int uiDataSize_p,
				      tEplFrame * pData_p,
				      tEplAsySdoSeq * pRecFrame_p,
				      tEplAsySdoSeqEvent Event_p);

static tEplKernel EplSdoAsySeqSendIntern(tEplAsySdoSeqCon * pAsySdoSeqCon_p,
					 unsigned int uiDataSize_p,
					 tEplFrame * pData_p,
					 BOOL fFrameInHistory);

static tEplKernel EplSdoAsySeqSendLowerLayer(tEplAsySdoSeqCon * pAsySdoSeqCon_p,
					     unsigned int uiDataSize_p,
					     tEplFrame * pEplFrame_p);

tEplKernel EplSdoAsyReceiveCb(tEplSdoConHdl ConHdl_p,
			      tEplAsySdoSeq *pSdoSeqData_p,
			      unsigned int uiDataSize_p);

static tEplKernel EplSdoAsyInitHistory(void);

static tEplKernel EplSdoAsyAddFrameToHistory(tEplAsySdoSeqCon * pAsySdoSeqCon_p,
					     tEplFrame * pFrame_p,
					     unsigned int uiSize_p);

static tEplKernel EplSdoAsyAckFrameToHistory(tEplAsySdoSeqCon * pAsySdoSeqCon_p,
					     u8 bRecSeqNumber_p);

static tEplKernel EplSdoAsyReadFromHistory(tEplAsySdoSeqCon * pAsySdoSeqCon_p,
					   tEplFrame ** ppFrame_p,
					   unsigned int *puiSize_p,
					   BOOL fInitRead);

static unsigned int EplSdoAsyGetFreeEntriesFromHistory(tEplAsySdoSeqCon *
						       pAsySdoSeqCon_p);

static tEplKernel EplSdoAsySeqSetTimer(tEplAsySdoSeqCon * pAsySdoSeqCon_p,
				       unsigned long ulTimeout);

/***************************************************************************/
/*                                                                         */
/*                                                                         */
/*          C L A S S  <EPL asychronus SDO Sequence layer>                 */
/*                                                                         */
/*                                                                         */
/***************************************************************************/
//
// Description: this module contains the asynchronus SDO Sequence Layer for
//              the EPL SDO service
//
//
/***************************************************************************/

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

//---------------------------------------------------------------------------
//
// Function:    EplSdoAsySeqInit
//
// Description: init first instance
//
//
//
// Parameters:  fpSdoComCb_p    = callback function to inform Command layer
//                                about new frames
//              fpSdoComConCb_p = callback function to inform command layer
//                                about connection state
//
//
// Returns:     tEplKernel = errorcode
//
//
// State:
//
//---------------------------------------------------------------------------
tEplKernel EplSdoAsySeqInit(tEplSdoComReceiveCb fpSdoComCb_p,
			    tEplSdoComConCb fpSdoComConCb_p)
{
	tEplKernel Ret;

	Ret = EplSdoAsySeqAddInstance(fpSdoComCb_p, fpSdoComConCb_p);

	return Ret;

}

//---------------------------------------------------------------------------
//
// Function:    EplSdoAsySeqAddInstance
//
// Description: init following instances
//
//
//
// Parameters:  fpSdoComCb_p    = callback function to inform Command layer
//                                about new frames
//              fpSdoComConCb_p = callback function to inform command layer
//                                about connection state
//
// Returns:     tEplKernel = errorcode
//
//
// State:
//
//---------------------------------------------------------------------------
tEplKernel EplSdoAsySeqAddInstance(tEplSdoComReceiveCb fpSdoComCb_p,
				   tEplSdoComConCb fpSdoComConCb_p)
{
	tEplKernel Ret;

	Ret = kEplSuccessful;

	// check functionpointer
	if (fpSdoComCb_p == NULL) {
		Ret = kEplSdoSeqMissCb;
		goto Exit;
	} else {
		AsySdoSequInstance_g.m_fpSdoComReceiveCb = fpSdoComCb_p;
	}

	// check functionpointer
	if (fpSdoComConCb_p == NULL) {
		Ret = kEplSdoSeqMissCb;
		goto Exit;
	} else {
		AsySdoSequInstance_g.m_fpSdoComConCb = fpSdoComConCb_p;
	}

	// set controllstructure to 0
	EPL_MEMSET(&AsySdoSequInstance_g.m_AsySdoConnection[0], 0x00,
		   sizeof(AsySdoSequInstance_g.m_AsySdoConnection));

	// init History
	Ret = EplSdoAsyInitHistory();
	if (Ret != kEplSuccessful) {
		goto Exit;
	}
#if defined(WIN32) || defined(_WIN32)
	// create critical section for process function
	AsySdoSequInstance_g.m_pCriticalSection =
	    &AsySdoSequInstance_g.m_CriticalSection;
	InitializeCriticalSection(AsySdoSequInstance_g.m_pCriticalSection);

	// init critical section for receive cb function
	AsySdoSequInstance_g.m_pCriticalSectionReceive =
	    &AsySdoSequInstance_g.m_CriticalSectionReceive;
	InitializeCriticalSection(AsySdoSequInstance_g.
				  m_pCriticalSectionReceive);
#endif

#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDO_UDP)) != 0)
	// init lower layer
	Ret = EplSdoUdpuAddInstance(EplSdoAsyReceiveCb);
	if (Ret != kEplSuccessful) {
		goto Exit;
	}
#endif

#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDO_ASND)) != 0)
	// init lower layer
	Ret = EplSdoAsnduAddInstance(EplSdoAsyReceiveCb);
	if (Ret != kEplSuccessful) {
		goto Exit;
	}
#endif

      Exit:
	return Ret;

}

//---------------------------------------------------------------------------
//
// Function:    EplSdoAsySeqDelInstance
//
// Description: delete instances
//
//
//
// Parameters:
//
//
// Returns:     tEplKernel = errorcode
//
//
// State:
//
//---------------------------------------------------------------------------
tEplKernel EplSdoAsySeqDelInstance(void)
{
	tEplKernel Ret;
	unsigned int uiCount;
	tEplAsySdoSeqCon *pAsySdoSeqCon;

	Ret = kEplSuccessful;

	// delete timer of open connections
	uiCount = 0;
	pAsySdoSeqCon = &AsySdoSequInstance_g.m_AsySdoConnection[0];
	while (uiCount < EPL_MAX_SDO_SEQ_CON) {
		if (pAsySdoSeqCon->m_ConHandle != 0) {
			EplTimeruDeleteTimer(&pAsySdoSeqCon->m_EplTimerHdl);
		}
		uiCount++;
		pAsySdoSeqCon++;
	}

#if defined(WIN32) || defined(_WIN32)
	// delete critical section for process function
	DeleteCriticalSection(AsySdoSequInstance_g.m_pCriticalSection);
#endif

	// set instance-table to 0
	EPL_MEMSET(&AsySdoSequInstance_g, 0x00, sizeof(AsySdoSequInstance_g));

#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDO_UDP)) != 0)
	// delete lower layer
	Ret = EplSdoUdpuDelInstance();
#endif

#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDO_ASND)) != 0)
	// delete lower layer
	Ret = EplSdoAsnduDelInstance();
#endif

	return Ret;
}

//---------------------------------------------------------------------------
//
// Function:    EplSdoAsySeqInitCon
//
// Description: start initialization of a sequence layer connection.
//              It tries to reuse an existing connection to the same node.
//
//
// Parameters:  pSdoSeqConHdl_p = pointer to the variable for the connection handle
//              uiNodeId_p      = Node Id of the target
//              SdoType          = Type of the SDO connection
//
//
// Returns:     tEplKernel = errorcode
//
//
// State:
//
//---------------------------------------------------------------------------
tEplKernel EplSdoAsySeqInitCon(tEplSdoSeqConHdl *pSdoSeqConHdl_p,
			       unsigned int uiNodeId_p,
			       tEplSdoType SdoType)
{
	tEplKernel Ret;
	unsigned int uiCount;
	unsigned int uiFreeCon;
	tEplSdoConHdl ConHandle;
	tEplAsySdoSeqCon *pAsySdoSeqCon;
	Ret = kEplSuccessful;

	// check SdoType
	// call init function of the protcol abstraction layer
	// which tries to find an existing connection to the same node
	switch (SdoType) {
		// SDO over UDP
	case kEplSdoTypeUdp:
		{
#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDO_UDP)) != 0)
			Ret = EplSdoUdpuInitCon(&ConHandle, uiNodeId_p);
			if (Ret != kEplSuccessful) {
				goto Exit;
			}
#else
			Ret = kEplSdoSeqUnsupportedProt;
#endif
			break;
		}

		// SDO over Asnd
	case kEplSdoTypeAsnd:
		{
#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDO_ASND)) != 0)
			Ret = EplSdoAsnduInitCon(&ConHandle, uiNodeId_p);
			if (Ret != kEplSuccessful) {
				goto Exit;
			}
#else
			Ret = kEplSdoSeqUnsupportedProt;
#endif
			break;
		}

		// unsupported protocols
		// -> auto should be replaced by command layer
	case kEplSdoTypeAuto:
	case kEplSdoTypePdo:
	default:
		{
			Ret = kEplSdoSeqUnsupportedProt;
			goto Exit;
		}

	}			// end of switch(SdoType)

	// find existing connection to the same node or find empty entry for connection
	uiCount = 0;
	uiFreeCon = EPL_MAX_SDO_SEQ_CON;
	pAsySdoSeqCon = &AsySdoSequInstance_g.m_AsySdoConnection[0];

	while (uiCount < EPL_MAX_SDO_SEQ_CON) {
		if (pAsySdoSeqCon->m_ConHandle == ConHandle) {	// existing connection found
			break;
		}
		if (pAsySdoSeqCon->m_ConHandle == 0) {
			uiFreeCon = uiCount;
		}
		uiCount++;
		pAsySdoSeqCon++;
	}

	if (uiCount == EPL_MAX_SDO_SEQ_CON) {
		if (uiFreeCon == EPL_MAX_SDO_SEQ_CON) {	// no free entry found
			switch (SdoType) {
				// SDO over UDP
			case kEplSdoTypeUdp:
				{
#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDO_UDP)) != 0)
					Ret = EplSdoUdpuDelCon(ConHandle);
					if (Ret != kEplSuccessful) {
						goto Exit;
					}
#endif
					break;
				}

				// SDO over Asnd
			case kEplSdoTypeAsnd:
				{
#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDO_ASND)) != 0)
					Ret = EplSdoAsnduDelCon(ConHandle);
					if (Ret != kEplSuccessful) {
						goto Exit;
					}
#endif
					break;
				}

				// unsupported protocols
				// -> auto should be replaced by command layer
			case kEplSdoTypeAuto:
			case kEplSdoTypePdo:
			default:
				{
					Ret = kEplSdoSeqUnsupportedProt;
					goto Exit;
				}

			}	// end of switch(SdoType)

			Ret = kEplSdoSeqNoFreeHandle;
			goto Exit;
		} else {	// free entry found
			pAsySdoSeqCon =
			    &AsySdoSequInstance_g.m_AsySdoConnection[uiFreeCon];
			pAsySdoSeqCon->m_ConHandle = ConHandle;
			uiCount = uiFreeCon;
		}
	}
	// set handle
	*pSdoSeqConHdl_p = (uiCount | EPL_SDO_ASY_HANDLE);

	// increment use counter
	pAsySdoSeqCon->m_uiUseCount++;

	// call intern process function
	Ret = EplSdoAsySeqProcess(uiCount,
				  0, NULL, NULL, kAsySdoSeqEventInitCon);

      Exit:
	return Ret;
}

//---------------------------------------------------------------------------
//
// Function:    EplSdoAsySeqSendData
//
// Description: send sata unsing a established connection
//
//
//
// Parameters:  pSdoSeqConHdl_p = connection handle
//              uiDataSize_p    = Size of Frame to send
//                                  -> wihtout SDO sequence layer header, Asnd header
//                                     and ethernetnet
//                                  ==> SDO Sequence layer payload
//              SdoType          = Type of the SDO connection
//
//
// Returns:     tEplKernel = errorcode
//
//
// State:
//
//---------------------------------------------------------------------------
tEplKernel EplSdoAsySeqSendData(tEplSdoSeqConHdl SdoSeqConHdl_p,
				unsigned int uiDataSize_p,
				tEplFrame *pabData_p)
{
	tEplKernel Ret;
	unsigned int uiHandle;

	uiHandle = (SdoSeqConHdl_p & ~EPL_SDO_SEQ_HANDLE_MASK);

	// check if connection ready
	if (AsySdoSequInstance_g.m_AsySdoConnection[uiHandle].m_SdoState ==
	    kEplAsySdoStateIdle) {
		// no connection with this handle
		Ret = kEplSdoSeqInvalidHdl;
		goto Exit;
	} else if (AsySdoSequInstance_g.m_AsySdoConnection[uiHandle].
		   m_SdoState != kEplAsySdoStateConnected) {
		Ret = kEplSdoSeqConnectionBusy;
		goto Exit;
	}

	Ret = EplSdoAsySeqProcess(uiHandle,
				  uiDataSize_p,
				  pabData_p, NULL, kAsySdoSeqEventFrameSend);
      Exit:
	return Ret;
}

//---------------------------------------------------------------------------
//
// Function:    EplSdoAsySeqProcessEvent
//
// Description: function processes extern events
//              -> later needed for timeout controll with timer-module
//
//
//
// Parameters:  pEvent_p = pointer to event
//
//
// Returns:     tEplKernel = errorcode
//
//
// State:
//
//---------------------------------------------------------------------------
tEplKernel EplSdoAsySeqProcessEvent(tEplEvent *pEvent_p)
{
	tEplKernel Ret;
	tEplTimerEventArg *pTimerEventArg;
	tEplAsySdoSeqCon *pAsySdoSeqCon;
	tEplTimerHdl EplTimerHdl;
	unsigned int uiCount;

	Ret = kEplSuccessful;
	// check parameter
	if (pEvent_p == NULL) {
		Ret = kEplSdoSeqInvalidEvent;
		goto Exit;
	}

	if (pEvent_p->m_EventType != kEplEventTypeTimer) {
		Ret = kEplSdoSeqInvalidEvent;
		goto Exit;
	}
	// get timerhdl
	pTimerEventArg = (tEplTimerEventArg *) pEvent_p->m_pArg;
	EplTimerHdl = pTimerEventArg->m_TimerHdl;

	// get pointer to intern control structure of connection
	if (pTimerEventArg->m_ulArg == 0) {
		goto Exit;
	}
	pAsySdoSeqCon = (tEplAsySdoSeqCon *) pTimerEventArg->m_ulArg;

	// check if time is current
	if (EplTimerHdl != pAsySdoSeqCon->m_EplTimerHdl) {
		// delete timer
		EplTimeruDeleteTimer(&EplTimerHdl);
		goto Exit;
	}
	// delete timer
	EplTimeruDeleteTimer(&pAsySdoSeqCon->m_EplTimerHdl);

	// get indexnumber of control structure
	uiCount = 0;
	while ((&AsySdoSequInstance_g.m_AsySdoConnection[uiCount]) !=
	       pAsySdoSeqCon) {
		uiCount++;
		if (uiCount > EPL_MAX_SDO_SEQ_CON) {
			goto Exit;
		}
	}

	// process event and call processfunction if needed
	Ret = EplSdoAsySeqProcess(uiCount,
				  0, NULL, NULL, kAsySdoSeqEventTimeout);

      Exit:
	return Ret;

}

//---------------------------------------------------------------------------
//
// Function:    EplSdoAsySeqDelCon
//
// Description: del and close one connection
//
//
//
// Parameters:  SdoSeqConHdl_p = handle of connection
//
//
// Returns:     tEplKernel = errorcode
//
//
// State:
//
//---------------------------------------------------------------------------
tEplKernel EplSdoAsySeqDelCon(tEplSdoSeqConHdl SdoSeqConHdl_p)
{
	tEplKernel Ret = kEplSuccessful;
	unsigned int uiHandle;
	tEplAsySdoSeqCon *pAsySdoSeqCon;

	uiHandle = (SdoSeqConHdl_p & ~EPL_SDO_SEQ_HANDLE_MASK);

	// check if handle invalid
	if (uiHandle >= EPL_MAX_SDO_SEQ_CON) {
		Ret = kEplSdoSeqInvalidHdl;
		goto Exit;
	}
	// get pointer to connection
	pAsySdoSeqCon = &AsySdoSequInstance_g.m_AsySdoConnection[uiHandle];

	// decrement use counter
	pAsySdoSeqCon->m_uiUseCount--;

	if (pAsySdoSeqCon->m_uiUseCount == 0) {
		// process close in processfunction
		Ret = EplSdoAsySeqProcess(uiHandle,
					  0,
					  NULL, NULL, kAsySdoSeqEventCloseCon);

		//check protocol
		if ((pAsySdoSeqCon->m_ConHandle & EPL_SDO_ASY_HANDLE_MASK) ==
		    EPL_SDO_UDP_HANDLE) {
#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDO_UDP)) != 0)
			// call close function of lower layer
			EplSdoUdpuDelCon(pAsySdoSeqCon->m_ConHandle);
#endif // end of #if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDO_UDP)) != 0)
		} else {
#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDO_ASND)) != 0)
			// call close function of lower layer
			EplSdoAsnduDelCon(pAsySdoSeqCon->m_ConHandle);
#endif // end of #if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDO_ASND)) != 0)
		}

		// delete timer
		EplTimeruDeleteTimer(&pAsySdoSeqCon->m_EplTimerHdl);

		// clean controllstructure
		EPL_MEMSET(pAsySdoSeqCon, 0x00, sizeof(tEplAsySdoSeqCon));
		pAsySdoSeqCon->m_SdoConHistory.m_bFreeEntries =
		    EPL_SDO_HISTORY_SIZE;
	}

      Exit:
	return Ret;

}

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

//---------------------------------------------------------------------------
//
// Function:    EplEplSdoAsySeqProcess
//
// Description: intern function to process the asynchronus SDO Sequence Layer
//              state maschine
//
//
//
// Parameters:  uiHandle_p      = index of the control structure of the connection
//              uiDataSize_p    = size of data frame to process (can be 0)
//                                  -> without size of sequence header and Asnd header!!!
//
//              pData_p         = pointer to frame to send (can be NULL)
//              pRecFrame_p     = pointer to received frame (can be NULL)
//              Event_p         = Event to process
//
//
//
// Returns:     tEplKernel = errorcode
//
//
// State:
//
//---------------------------------------------------------------------------
static tEplKernel EplSdoAsySeqProcess(unsigned int uiHandle_p,
				      unsigned int uiDataSize_p,
				      tEplFrame * pData_p,
				      tEplAsySdoSeq * pRecFrame_p,
				      tEplAsySdoSeqEvent Event_p)
{
	tEplKernel Ret;
	unsigned int uiFrameSize;
	tEplFrame *pEplFrame;
	tEplAsySdoSeqCon *pAsySdoSeqCon;
	tEplSdoSeqConHdl SdoSeqConHdl;
	unsigned int uiFreeEntries;

#if defined(WIN32) || defined(_WIN32)
	// enter  critical section for process function
	EnterCriticalSection(AsySdoSequInstance_g.m_pCriticalSection);
#endif

	Ret = kEplSuccessful;

	// get handle for hinger layer
	SdoSeqConHdl = uiHandle_p | EPL_SDO_ASY_HANDLE;

	// check if handle invalid
	if ((SdoSeqConHdl & ~EPL_SDO_SEQ_HANDLE_MASK) ==
	    EPL_SDO_SEQ_INVALID_HDL) {
		Ret = kEplSdoSeqInvalidHdl;
		goto Exit;
	}
	// get pointer to connection
	pAsySdoSeqCon = &AsySdoSequInstance_g.m_AsySdoConnection[uiHandle_p];

	// check size
	if ((pData_p == NULL) && (pRecFrame_p == NULL) && (uiDataSize_p != 0)) {
		Ret = kEplSdoSeqInvalidFrame;
		goto Exit;
	}
	// check state
	switch (pAsySdoSeqCon->m_SdoState) {
		// idle state
	case kEplAsySdoStateIdle:
		{
			// check event
			switch (Event_p) {
				// new connection
				// -> send init frame and change to
				// kEplAsySdoStateInit1
			case kAsySdoSeqEventInitCon:
				{
					// set sending scon to 1
					pAsySdoSeqCon->m_bRecSeqNum = 0x01;
					// set set send rcon to 0
					pAsySdoSeqCon->m_bSendSeqNum = 0x00;
					Ret =
					    EplSdoAsySeqSendIntern
					    (pAsySdoSeqCon, 0, NULL, FALSE);
					if (Ret != kEplSuccessful) {
						goto Exit;
					}
					// change state
					pAsySdoSeqCon->m_SdoState =
					    kEplAsySdoStateInit1;

					// set timer
					Ret =
					    EplSdoAsySeqSetTimer(pAsySdoSeqCon,
								 EPL_SEQ_DEFAULT_TIMEOUT);

					break;
				}

				// init con from extern
				// check rcon and scon
				// -> send answer
			case kAsySdoSeqEventFrameRec:
				{
/*
                    PRINTF3("%s scon=%u rcon=%u\n",
                            __func__,
                            pRecFrame_p->m_le_bSendSeqNumCon,
                            pRecFrame_p->m_le_bRecSeqNumCon);
*/
					// check if scon == 1 and rcon == 0
					if (((pRecFrame_p->
					      m_le_bRecSeqNumCon &
					      EPL_ASY_SDO_CON_MASK) == 0x00)
					    &&
					    ((pRecFrame_p->
					      m_le_bSendSeqNumCon &
					      EPL_ASY_SDO_CON_MASK) == 0x01)) {
						// save sequence numbers
						pAsySdoSeqCon->m_bRecSeqNum =
						    AmiGetByteFromLe
						    (&pRecFrame_p->
						     m_le_bRecSeqNumCon);
						pAsySdoSeqCon->m_bSendSeqNum =
						    AmiGetByteFromLe
						    (&pRecFrame_p->
						     m_le_bSendSeqNumCon);
						// create answer and send answer
						// set rcon to 1 (in send direction own scon)
						pAsySdoSeqCon->m_bRecSeqNum++;
						Ret =
						    EplSdoAsySeqSendIntern
						    (pAsySdoSeqCon, 0, NULL,
						     FALSE);
						if (Ret != kEplSuccessful) {
							goto Exit;
						}
						// change state to kEplAsySdoStateInit2
						pAsySdoSeqCon->m_SdoState =
						    kEplAsySdoStateInit2;

						// set timer
						Ret =
						    EplSdoAsySeqSetTimer
						    (pAsySdoSeqCon,
						     EPL_SEQ_DEFAULT_TIMEOUT);
					} else {	// error -> close
						// delete timer
						EplTimeruDeleteTimer
						    (&pAsySdoSeqCon->
						     m_EplTimerHdl);
						if (((pRecFrame_p->
						      m_le_bRecSeqNumCon &
						      EPL_ASY_SDO_CON_MASK) !=
						     0x00)
						    || ((pRecFrame_p->m_le_bSendSeqNumCon & EPL_ASY_SDO_CON_MASK) != 0x00)) {	// d.k. only answer with close message if the message sent was not a close message
							// save sequence numbers
							pAsySdoSeqCon->
							    m_bRecSeqNum =
							    AmiGetByteFromLe
							    (&pRecFrame_p->
							     m_le_bRecSeqNumCon);
							pAsySdoSeqCon->
							    m_bSendSeqNum =
							    AmiGetByteFromLe
							    (&pRecFrame_p->
							     m_le_bSendSeqNumCon);
							// set rcon and scon to 0
							pAsySdoSeqCon->
							    m_bSendSeqNum &=
							    EPL_SEQ_NUM_MASK;
							pAsySdoSeqCon->
							    m_bRecSeqNum &=
							    EPL_SEQ_NUM_MASK;
							// send frame
							EplSdoAsySeqSendIntern
							    (pAsySdoSeqCon, 0,
							     NULL, FALSE);
						}
						// call Command Layer Cb
						AsySdoSequInstance_g.
						    m_fpSdoComConCb
						    (SdoSeqConHdl,
						     kAsySdoConStateInitError);
					}
					break;
				}

			default:
				// d.k. do nothing
				break;

			}	// end of switch(Event_p)
			break;
		}

		// init connection step 1
		// wait for frame with scon = 1
		// and rcon = 1
	case kEplAsySdoStateInit1:
		{
//            PRINTF0("EplSdoAsySequ: StateInit1\n");

			// check event
			switch (Event_p) {
				// frame received
			case kAsySdoSeqEventFrameRec:
				{
					// check scon == 1 and rcon == 1
					if (((pRecFrame_p->
					      m_le_bRecSeqNumCon &
					      EPL_ASY_SDO_CON_MASK) == 0x01)
					    && ((pRecFrame_p->m_le_bSendSeqNumCon & EPL_ASY_SDO_CON_MASK) == 0x01)) {	// create answer own scon = 2
						// save sequence numbers
						pAsySdoSeqCon->m_bRecSeqNum =
						    AmiGetByteFromLe
						    (&pRecFrame_p->
						     m_le_bRecSeqNumCon);
						pAsySdoSeqCon->m_bSendSeqNum =
						    AmiGetByteFromLe
						    (&pRecFrame_p->
						     m_le_bSendSeqNumCon);

						pAsySdoSeqCon->m_bRecSeqNum++;
						Ret =
						    EplSdoAsySeqSendIntern
						    (pAsySdoSeqCon, 0, NULL,
						     FALSE);
						if (Ret != kEplSuccessful) {
							goto Exit;
						}
						// change state to kEplAsySdoStateInit3
						pAsySdoSeqCon->m_SdoState =
						    kEplAsySdoStateInit3;

						// set timer
						Ret =
						    EplSdoAsySeqSetTimer
						    (pAsySdoSeqCon,
						     EPL_SEQ_DEFAULT_TIMEOUT);

					}
					// check if scon == 1 and rcon == 0, i.e. other side wants me to be server
					else if (((pRecFrame_p->
						   m_le_bRecSeqNumCon &
						   EPL_ASY_SDO_CON_MASK) ==
						  0x00)
						 &&
						 ((pRecFrame_p->
						   m_le_bSendSeqNumCon &
						   EPL_ASY_SDO_CON_MASK) ==
						  0x01)) {
						// save sequence numbers
						pAsySdoSeqCon->m_bRecSeqNum =
						    AmiGetByteFromLe
						    (&pRecFrame_p->
						     m_le_bRecSeqNumCon);
						pAsySdoSeqCon->m_bSendSeqNum =
						    AmiGetByteFromLe
						    (&pRecFrame_p->
						     m_le_bSendSeqNumCon);
						// create answer and send answer
						// set rcon to 1 (in send direction own scon)
						pAsySdoSeqCon->m_bRecSeqNum++;
						Ret =
						    EplSdoAsySeqSendIntern
						    (pAsySdoSeqCon, 0, NULL,
						     FALSE);
						if (Ret != kEplSuccessful) {
							goto Exit;
						}
						// change state to kEplAsySdoStateInit2
						pAsySdoSeqCon->m_SdoState =
						    kEplAsySdoStateInit2;

						// set timer
						Ret =
						    EplSdoAsySeqSetTimer
						    (pAsySdoSeqCon,
						     EPL_SEQ_DEFAULT_TIMEOUT);
					} else {	// error -> Close
						pAsySdoSeqCon->m_SdoState =
						    kEplAsySdoStateIdle;
						// delete timer
						EplTimeruDeleteTimer
						    (&pAsySdoSeqCon->
						     m_EplTimerHdl);
						if (((pRecFrame_p->
						      m_le_bRecSeqNumCon &
						      EPL_ASY_SDO_CON_MASK) !=
						     0x00)
						    || ((pRecFrame_p->m_le_bSendSeqNumCon & EPL_ASY_SDO_CON_MASK) != 0x00)) {	// d.k. only answer with close message if the message sent was not a close message
							// save sequence numbers
							pAsySdoSeqCon->
							    m_bRecSeqNum =
							    AmiGetByteFromLe
							    (&pRecFrame_p->
							     m_le_bRecSeqNumCon);
							pAsySdoSeqCon->
							    m_bSendSeqNum =
							    AmiGetByteFromLe
							    (&pRecFrame_p->
							     m_le_bSendSeqNumCon);

							// set rcon and scon to 0
							pAsySdoSeqCon->
							    m_bSendSeqNum &=
							    EPL_SEQ_NUM_MASK;
							pAsySdoSeqCon->
							    m_bRecSeqNum &=
							    EPL_SEQ_NUM_MASK;
							// send frame
							EplSdoAsySeqSendIntern
							    (pAsySdoSeqCon, 0,
							     NULL, FALSE);
						}
						// call Command Layer Cb
						AsySdoSequInstance_g.
						    m_fpSdoComConCb
						    (SdoSeqConHdl,
						     kAsySdoConStateInitError);
					}
					break;
				}

				// timeout
			case kAsySdoSeqEventTimeout:
				{	// error -> Close
					pAsySdoSeqCon->m_SdoState =
					    kEplAsySdoStateIdle;

					// set rcon and scon to 0
					pAsySdoSeqCon->m_bSendSeqNum &=
					    EPL_SEQ_NUM_MASK;
					pAsySdoSeqCon->m_bRecSeqNum &=
					    EPL_SEQ_NUM_MASK;
					// send frame
					EplSdoAsySeqSendIntern(pAsySdoSeqCon,
							       0, NULL, FALSE);
					// call Command Layer Cb
					AsySdoSequInstance_g.
					    m_fpSdoComConCb(SdoSeqConHdl,
							    kAsySdoConStateInitError);
					break;
				}

			default:
				// d.k. do nothing
				break;

			}	// end of switch(Event_p)
			break;
		}

		// init connection step 2
	case kEplAsySdoStateInit2:
		{
//            PRINTF0("EplSdoAsySequ: StateInit2\n");

			// check event
			switch (Event_p) {
				// frame received
			case kAsySdoSeqEventFrameRec:
				{
					// check scon == 2 and rcon == 1
					if (((pRecFrame_p->
					      m_le_bRecSeqNumCon &
					      EPL_ASY_SDO_CON_MASK) == 0x01)
					    && ((pRecFrame_p->m_le_bSendSeqNumCon & EPL_ASY_SDO_CON_MASK) == 0x02)) {	// create answer own rcon = 2
						// save sequence numbers
						pAsySdoSeqCon->m_bRecSeqNum =
						    AmiGetByteFromLe
						    (&pRecFrame_p->
						     m_le_bRecSeqNumCon);
						pAsySdoSeqCon->m_bSendSeqNum =
						    AmiGetByteFromLe
						    (&pRecFrame_p->
						     m_le_bSendSeqNumCon);

						pAsySdoSeqCon->m_bRecSeqNum++;
						Ret =
						    EplSdoAsySeqSendIntern
						    (pAsySdoSeqCon, 0, NULL,
						     FALSE);
						if (Ret != kEplSuccessful) {
							goto Exit;
						}
						// change state to kEplAsySdoStateConnected
						pAsySdoSeqCon->m_SdoState =
						    kEplAsySdoStateConnected;

						// set timer
						Ret =
						    EplSdoAsySeqSetTimer
						    (pAsySdoSeqCon,
						     EPL_SEQ_DEFAULT_TIMEOUT);

						// call Command Layer Cb
						AsySdoSequInstance_g.
						    m_fpSdoComConCb
						    (SdoSeqConHdl,
						     kAsySdoConStateConnected);

					}
					// check scon == 1 and rcon == 1, i.e. other side wants me to initiate the connection
					else if (((pRecFrame_p->
						   m_le_bRecSeqNumCon &
						   EPL_ASY_SDO_CON_MASK) ==
						  0x01)
						 &&
						 ((pRecFrame_p->
						   m_le_bSendSeqNumCon &
						   EPL_ASY_SDO_CON_MASK) ==
						  0x01)) {
						// save sequence numbers
						pAsySdoSeqCon->m_bRecSeqNum =
						    AmiGetByteFromLe
						    (&pRecFrame_p->
						     m_le_bRecSeqNumCon);
						pAsySdoSeqCon->m_bSendSeqNum =
						    AmiGetByteFromLe
						    (&pRecFrame_p->
						     m_le_bSendSeqNumCon);
						// create answer and send answer
						// set rcon to 1 (in send direction own scon)
						pAsySdoSeqCon->m_bRecSeqNum++;
						Ret =
						    EplSdoAsySeqSendIntern
						    (pAsySdoSeqCon, 0, NULL,
						     FALSE);
						if (Ret != kEplSuccessful) {
							goto Exit;
						}
						// set timer
						Ret =
						    EplSdoAsySeqSetTimer
						    (pAsySdoSeqCon,
						     EPL_SEQ_DEFAULT_TIMEOUT);
						// change state to kEplAsySdoStateInit3
						pAsySdoSeqCon->m_SdoState =
						    kEplAsySdoStateInit3;

					} else {	// error -> Close
						pAsySdoSeqCon->m_SdoState =
						    kEplAsySdoStateIdle;
						// delete timer
						EplTimeruDeleteTimer
						    (&pAsySdoSeqCon->
						     m_EplTimerHdl);
						if (((pRecFrame_p->
						      m_le_bRecSeqNumCon &
						      EPL_ASY_SDO_CON_MASK) !=
						     0x00)
						    || ((pRecFrame_p->m_le_bSendSeqNumCon & EPL_ASY_SDO_CON_MASK) != 0x00)) {	// d.k. only answer with close message if the message sent was not a close message
							// save sequence numbers
							pAsySdoSeqCon->
							    m_bRecSeqNum =
							    AmiGetByteFromLe
							    (&pRecFrame_p->
							     m_le_bRecSeqNumCon);
							pAsySdoSeqCon->
							    m_bSendSeqNum =
							    AmiGetByteFromLe
							    (&pRecFrame_p->
							     m_le_bSendSeqNumCon);
							// set rcon and scon to 0
							pAsySdoSeqCon->
							    m_bSendSeqNum &=
							    EPL_SEQ_NUM_MASK;
							pAsySdoSeqCon->
							    m_bRecSeqNum &=
							    EPL_SEQ_NUM_MASK;
							// send frame
							EplSdoAsySeqSendIntern
							    (pAsySdoSeqCon, 0,
							     NULL, FALSE);
						}
						// call Command Layer Cb
						AsySdoSequInstance_g.
						    m_fpSdoComConCb
						    (SdoSeqConHdl,
						     kAsySdoConStateInitError);
					}
					break;
				}

				// timeout
			case kAsySdoSeqEventTimeout:
				{	// error -> Close
					pAsySdoSeqCon->m_SdoState =
					    kEplAsySdoStateIdle;
					// set rcon and scon to 0
					pAsySdoSeqCon->m_bSendSeqNum &=
					    EPL_SEQ_NUM_MASK;
					pAsySdoSeqCon->m_bRecSeqNum &=
					    EPL_SEQ_NUM_MASK;
					// send frame
					EplSdoAsySeqSendIntern(pAsySdoSeqCon,
							       0, NULL, FALSE);

					// call Command Layer Cb
					AsySdoSequInstance_g.
					    m_fpSdoComConCb(SdoSeqConHdl,
							    kAsySdoConStateInitError);
					break;
				}

			default:
				// d.k. do nothing
				break;

			}	// end of switch(Event_p)
			break;
		}

		// init connection step 3
	case kEplAsySdoStateInit3:
		{
			// check event
			switch (Event_p) {
				// frame received
			case kAsySdoSeqEventFrameRec:
				{
					// check scon == 2 and rcon == 2
					if (((pRecFrame_p->
					      m_le_bRecSeqNumCon &
					      EPL_ASY_SDO_CON_MASK) == 0x02)
					    &&
					    ((pRecFrame_p->
					      m_le_bSendSeqNumCon &
					      EPL_ASY_SDO_CON_MASK) == 0x02)) {
						// save sequence numbers
						pAsySdoSeqCon->m_bRecSeqNum =
						    AmiGetByteFromLe
						    (&pRecFrame_p->
						     m_le_bRecSeqNumCon);
						pAsySdoSeqCon->m_bSendSeqNum =
						    AmiGetByteFromLe
						    (&pRecFrame_p->
						     m_le_bSendSeqNumCon);
						// change state to kEplAsySdoStateConnected
						pAsySdoSeqCon->m_SdoState =
						    kEplAsySdoStateConnected;

						// set timer
						Ret =
						    EplSdoAsySeqSetTimer
						    (pAsySdoSeqCon,
						     EPL_SEQ_DEFAULT_TIMEOUT);
						// call Command Layer Cb
						AsySdoSequInstance_g.
						    m_fpSdoComConCb
						    (SdoSeqConHdl,
						     kAsySdoConStateConnected);

					}
					// check scon == 2 and rcon == 1
					else if (((pRecFrame_p->
						   m_le_bRecSeqNumCon &
						   EPL_ASY_SDO_CON_MASK) ==
						  0x01)
						 && ((pRecFrame_p->m_le_bSendSeqNumCon & EPL_ASY_SDO_CON_MASK) == 0x02)) {	// create answer own rcon = 2
						// save sequence numbers
						pAsySdoSeqCon->m_bRecSeqNum =
						    AmiGetByteFromLe
						    (&pRecFrame_p->
						     m_le_bRecSeqNumCon);
						pAsySdoSeqCon->m_bSendSeqNum =
						    AmiGetByteFromLe
						    (&pRecFrame_p->
						     m_le_bSendSeqNumCon);

						pAsySdoSeqCon->m_bRecSeqNum++;
						Ret =
						    EplSdoAsySeqSendIntern
						    (pAsySdoSeqCon, 0, NULL,
						     FALSE);
						if (Ret != kEplSuccessful) {
							goto Exit;
						}
						// change state to kEplAsySdoStateConnected
						pAsySdoSeqCon->m_SdoState =
						    kEplAsySdoStateConnected;

						// set timer
						Ret =
						    EplSdoAsySeqSetTimer
						    (pAsySdoSeqCon,
						     EPL_SEQ_DEFAULT_TIMEOUT);

						// call Command Layer Cb
						AsySdoSequInstance_g.
						    m_fpSdoComConCb
						    (SdoSeqConHdl,
						     kAsySdoConStateConnected);

					} else {	// error -> Close
						pAsySdoSeqCon->m_SdoState =
						    kEplAsySdoStateIdle;
						// delete timer
						EplTimeruDeleteTimer
						    (&pAsySdoSeqCon->
						     m_EplTimerHdl);
						if (((pRecFrame_p->
						      m_le_bRecSeqNumCon &
						      EPL_ASY_SDO_CON_MASK) !=
						     0x00)
						    || ((pRecFrame_p->m_le_bSendSeqNumCon & EPL_ASY_SDO_CON_MASK) != 0x00)) {	// d.k. only answer with close message if the message sent was not a close message
							// save sequence numbers
							pAsySdoSeqCon->
							    m_bRecSeqNum =
							    AmiGetByteFromLe
							    (&pRecFrame_p->
							     m_le_bRecSeqNumCon);
							pAsySdoSeqCon->
							    m_bSendSeqNum =
							    AmiGetByteFromLe
							    (&pRecFrame_p->
							     m_le_bSendSeqNumCon);
							// set rcon and scon to 0
							pAsySdoSeqCon->
							    m_bSendSeqNum &=
							    EPL_SEQ_NUM_MASK;
							pAsySdoSeqCon->
							    m_bRecSeqNum &=
							    EPL_SEQ_NUM_MASK;
							// send frame
							EplSdoAsySeqSendIntern
							    (pAsySdoSeqCon, 0,
							     NULL, FALSE);
						}
						// call Command Layer Cb
						AsySdoSequInstance_g.
						    m_fpSdoComConCb
						    (SdoSeqConHdl,
						     kAsySdoConStateInitError);
					}
					break;
				}

				// timeout
			case kAsySdoSeqEventTimeout:
				{	// error -> Close
					pAsySdoSeqCon->m_SdoState =
					    kEplAsySdoStateIdle;
					// set rcon and scon to 0
					pAsySdoSeqCon->m_bSendSeqNum &=
					    EPL_SEQ_NUM_MASK;
					pAsySdoSeqCon->m_bRecSeqNum &=
					    EPL_SEQ_NUM_MASK;
					// send frame
					EplSdoAsySeqSendIntern(pAsySdoSeqCon,
							       0, NULL, FALSE);

					// call Command Layer Cb
					AsySdoSequInstance_g.
					    m_fpSdoComConCb(SdoSeqConHdl,
							    kAsySdoConStateInitError);
					break;
				}

			default:
				// d.k. do nothing
				break;

			}	// end of switch(Event_p)
			break;
		}

		// connection established
	case kEplAsySdoStateConnected:
		{
			// check event
			switch (Event_p) {

				// frame to send
			case kAsySdoSeqEventFrameSend:
				{
					// set timer
					Ret =
					    EplSdoAsySeqSetTimer(pAsySdoSeqCon,
								 EPL_SEQ_DEFAULT_TIMEOUT);
					// check if data frame or ack
					if (pData_p == NULL) {	// send ack
						// inc scon
						//pAsySdoSeqCon->m_bRecSeqNum += 4;
						Ret =
						    EplSdoAsySeqSendIntern
						    (pAsySdoSeqCon, 0, NULL,
						     FALSE);
						if (Ret != kEplSuccessful) {
							goto Exit;
						}
					} else {	// send dataframe
						// increment send sequence number
						pAsySdoSeqCon->m_bRecSeqNum +=
						    4;
						Ret =
						    EplSdoAsySeqSendIntern
						    (pAsySdoSeqCon,
						     uiDataSize_p, pData_p,
						     TRUE);
						if (Ret == kEplSdoSeqRequestAckNeeded) {	// request ack
							// change state to wait ack
							pAsySdoSeqCon->
							    m_SdoState =
							    kEplAsySdoStateWaitAck;
							// set Ret to kEplSuccessful, because no error
							// for higher layer
							Ret = kEplSuccessful;

						} else if (Ret !=
							   kEplSuccessful) {
							goto Exit;
						} else {
							// call Command Layer Cb
							AsySdoSequInstance_g.
							    m_fpSdoComConCb
							    (SdoSeqConHdl,
							     kAsySdoConStateFrameSended);
						}
					}
					break;
				}	// end of case kAsySdoSeqEventFrameSend

				// frame received
			case kAsySdoSeqEventFrameRec:
				{
					u8 bSendSeqNumCon =
					    AmiGetByteFromLe(&pRecFrame_p->
							     m_le_bSendSeqNumCon);

					// set timer
					Ret =
					    EplSdoAsySeqSetTimer(pAsySdoSeqCon,
								 EPL_SEQ_DEFAULT_TIMEOUT);
					// check scon
					switch (bSendSeqNumCon &
						EPL_ASY_SDO_CON_MASK) {
						// close from other node
					case 0:
					case 1:
						{
							// return to idle
							pAsySdoSeqCon->
							    m_SdoState =
							    kEplAsySdoStateIdle;
							// delete timer
							EplTimeruDeleteTimer
							    (&pAsySdoSeqCon->
							     m_EplTimerHdl);
							// call Command Layer Cb
							AsySdoSequInstance_g.
							    m_fpSdoComConCb
							    (SdoSeqConHdl,
							     kAsySdoConStateConClosed);

							break;
						}

						// Request Ack or Error Ack
						// possible contain data
					case 3:
						// normal frame
					case 2:
						{
							if ((AmiGetByteFromLe
							     (&pRecFrame_p->
							      m_le_bRecSeqNumCon)
							     &
							     EPL_ASY_SDO_CON_MASK)
							    == 3) {
//                                PRINTF0("EplSdoAsySequ: error response received\n");

								// error response (retransmission request)
								// resend frames from history

								// read frame from history
								Ret =
								    EplSdoAsyReadFromHistory
								    (pAsySdoSeqCon,
								     &pEplFrame,
								     &uiFrameSize,
								     TRUE);
								if (Ret !=
								    kEplSuccessful)
								{
									goto Exit;
								}

								while ((pEplFrame != NULL)
								       &&
								       (uiFrameSize
									!= 0)) {
									// send frame
									Ret =
									    EplSdoAsySeqSendLowerLayer
									    (pAsySdoSeqCon,
									     uiFrameSize,
									     pEplFrame);
									if (Ret
									    !=
									    kEplSuccessful)
									{
										goto Exit;
									}
									// read next frame from history
									Ret =
									    EplSdoAsyReadFromHistory
									    (pAsySdoSeqCon,
									     &pEplFrame,
									     &uiFrameSize,
									     FALSE);
									if (Ret
									    !=
									    kEplSuccessful)
									{
										goto Exit;
									}
								}	// end of while((pabFrame != NULL)
							}	// end of if (error response)

							if (((pAsySdoSeqCon->m_bSendSeqNum + 4) & EPL_SEQ_NUM_MASK) == (bSendSeqNumCon & EPL_SEQ_NUM_MASK)) {	// next frame of sequence received
								// save send sequence number (without ack request)
								pAsySdoSeqCon->
								    m_bSendSeqNum
								    =
								    bSendSeqNumCon
								    & ~0x01;

								// check if ack or data-frame
								//ignore ack -> already processed
								if (uiDataSize_p
								    >
								    EPL_SEQ_HEADER_SIZE)
								{
									AsySdoSequInstance_g.
									    m_fpSdoComReceiveCb
									    (SdoSeqConHdl,
									     ((tEplAsySdoCom *) & pRecFrame_p->m_le_abSdoSeqPayload), (uiDataSize_p - EPL_SEQ_HEADER_SIZE));
									// call Command Layer Cb
									AsySdoSequInstance_g.
									    m_fpSdoComConCb
									    (SdoSeqConHdl,
									     kAsySdoConStateFrameSended);

								} else {
									// call Command Layer Cb
									AsySdoSequInstance_g.
									    m_fpSdoComConCb
									    (SdoSeqConHdl,
									     kAsySdoConStateAckReceived);
								}
							} else if (((bSendSeqNumCon - pAsySdoSeqCon->m_bSendSeqNum - 4) & EPL_SEQ_NUM_MASK) < EPL_SEQ_NUM_THRESHOLD) {	// frame of sequence was lost,
								// because difference of received and old value
								// is less then halve of the values range.

								// send error frame with own rcon = 3
								pAsySdoSeqCon->
								    m_bSendSeqNum
								    |= 0x03;
								Ret =
								    EplSdoAsySeqSendIntern
								    (pAsySdoSeqCon,
								     0, NULL,
								     FALSE);
								// restore send sequence number
								pAsySdoSeqCon->
								    m_bSendSeqNum
								    =
								    (pAsySdoSeqCon->
								     m_bSendSeqNum
								     &
								     EPL_SEQ_NUM_MASK)
								    | 0x02;
								if (Ret !=
								    kEplSuccessful)
								{
									goto Exit;
								}
								// break here, because a requested acknowledge
								// was sent implicitly above
								break;
							}
							// else, ignore repeated frame

							if ((bSendSeqNumCon & EPL_ASY_SDO_CON_MASK) == 3) {	// ack request received

								// create ack with own scon = 2
								Ret =
								    EplSdoAsySeqSendIntern
								    (pAsySdoSeqCon,
								     0, NULL,
								     FALSE);
								if (Ret !=
								    kEplSuccessful)
								{
									goto Exit;
								}
							}

							break;
						}

					}	// switch(pAsySdoSeqCon->m_bSendSeqNum & EPL_ASY_SDO_CON_MASK)
					break;
				}	// end of case kAsySdoSeqEventFrameRec:

				//close event from higher layer
			case kAsySdoSeqEventCloseCon:
				{
					pAsySdoSeqCon->m_SdoState =
					    kEplAsySdoStateIdle;
					// set rcon and scon to 0
					pAsySdoSeqCon->m_bSendSeqNum &=
					    EPL_SEQ_NUM_MASK;
					pAsySdoSeqCon->m_bRecSeqNum &=
					    EPL_SEQ_NUM_MASK;
					// send frame
					EplSdoAsySeqSendIntern(pAsySdoSeqCon,
							       0, NULL, FALSE);

					// delete timer
					EplTimeruDeleteTimer(&pAsySdoSeqCon->
							     m_EplTimerHdl);
					// call Command Layer Cb is not necessary, because the event came from there
//                    AsySdoSequInstance_g.m_fpSdoComConCb(SdoSeqConHdl,
//                                                            kAsySdoConStateInitError);
					break;
				}

				// timeout
			case kAsySdoSeqEventTimeout:
				{

					uiFreeEntries =
					    EplSdoAsyGetFreeEntriesFromHistory
					    (pAsySdoSeqCon);
					if ((uiFreeEntries <
					     EPL_SDO_HISTORY_SIZE)
					    && (pAsySdoSeqCon->m_uiRetryCount < EPL_SEQ_RETRY_COUNT)) {	// unacknowlegded frames in history
						// and retry counter not exceeded

						// resend data with acknowledge request

						// increment retry counter
						pAsySdoSeqCon->m_uiRetryCount++;

						// set timer
						Ret =
						    EplSdoAsySeqSetTimer
						    (pAsySdoSeqCon,
						     EPL_SEQ_DEFAULT_TIMEOUT);

						// read first frame from history
						Ret =
						    EplSdoAsyReadFromHistory
						    (pAsySdoSeqCon, &pEplFrame,
						     &uiFrameSize, TRUE);
						if (Ret != kEplSuccessful) {
							goto Exit;
						}

						if ((pEplFrame != NULL)
						    && (uiFrameSize != 0)) {

							// set ack request in scon
							AmiSetByteToLe
							    (&pEplFrame->m_Data.
							     m_Asnd.m_Payload.
							     m_SdoSequenceFrame.
							     m_le_bSendSeqNumCon,
							     AmiGetByteFromLe
							     (&pEplFrame->
							      m_Data.m_Asnd.
							      m_Payload.
							      m_SdoSequenceFrame.
							      m_le_bSendSeqNumCon)
							     | 0x03);

							// send frame
							Ret =
							    EplSdoAsySeqSendLowerLayer
							    (pAsySdoSeqCon,
							     uiFrameSize,
							     pEplFrame);
							if (Ret !=
							    kEplSuccessful) {
								goto Exit;
							}

						}
					} else {
						// timeout, because of no traffic -> Close
						pAsySdoSeqCon->m_SdoState =
						    kEplAsySdoStateIdle;
						// set rcon and scon to 0
						pAsySdoSeqCon->m_bSendSeqNum &=
						    EPL_SEQ_NUM_MASK;
						pAsySdoSeqCon->m_bRecSeqNum &=
						    EPL_SEQ_NUM_MASK;
						// send frame
						EplSdoAsySeqSendIntern
						    (pAsySdoSeqCon, 0, NULL,
						     FALSE);

						// call Command Layer Cb
						AsySdoSequInstance_g.
						    m_fpSdoComConCb
						    (SdoSeqConHdl,
						     kAsySdoConStateTimeout);
					}

					break;
				}

			default:
				// d.k. do nothing
				break;

			}	// end of switch(Event_p)
			break;
		}

		// wait for Acknowledge (history buffer full)
	case kEplAsySdoStateWaitAck:
		{
			PRINTF0("EplSdoAsySequ: StateWaitAck\n");

			// set timer
			Ret = EplSdoAsySeqSetTimer(pAsySdoSeqCon,
						   EPL_SEQ_DEFAULT_TIMEOUT);

			//TODO: retry of acknowledge
			if (Event_p == kAsySdoSeqEventFrameRec) {
				// check rcon
				switch (pRecFrame_p->
					m_le_bRecSeqNumCon &
					EPL_ASY_SDO_CON_MASK) {
					// close-frome other node
				case 0:
					{
						// return to idle
						pAsySdoSeqCon->m_SdoState =
						    kEplAsySdoStateIdle;
						// delete timer
						EplTimeruDeleteTimer
						    (&pAsySdoSeqCon->
						     m_EplTimerHdl);
						// call Command Layer Cb
						AsySdoSequInstance_g.
						    m_fpSdoComConCb
						    (SdoSeqConHdl,
						     kAsySdoConStateConClosed);

						break;
					}

					// normal frame
				case 2:
					{
						// should be ack
						// -> change to state kEplAsySdoStateConnected
						pAsySdoSeqCon->m_SdoState =
						    kEplAsySdoStateConnected;
						// call Command Layer Cb
						AsySdoSequInstance_g.
						    m_fpSdoComConCb
						    (SdoSeqConHdl,
						     kAsySdoConStateAckReceived);
						// send data to higher layer if needed
						if (uiDataSize_p >
						    EPL_SEQ_HEADER_SIZE) {
							AsySdoSequInstance_g.
							    m_fpSdoComReceiveCb
							    (SdoSeqConHdl,
							     ((tEplAsySdoCom *)
							      & pRecFrame_p->
							      m_le_abSdoSeqPayload),
							     (uiDataSize_p -
							      EPL_SEQ_HEADER_SIZE));
						}
						break;
					}

					// Request Ack or Error Ack
				case 3:
					{
						// -> change to state kEplAsySdoStateConnected
						pAsySdoSeqCon->m_SdoState =
						    kEplAsySdoStateConnected;

						if (pRecFrame_p->m_le_bRecSeqNumCon == pAsySdoSeqCon->m_bRecSeqNum) {	// ack request
							// -> send ack
							// save sequence numbers
							pAsySdoSeqCon->
							    m_bRecSeqNum =
							    AmiGetByteFromLe
							    (&pRecFrame_p->
							     m_le_bRecSeqNumCon);
							pAsySdoSeqCon->
							    m_bSendSeqNum =
							    AmiGetByteFromLe
							    (&pRecFrame_p->
							     m_le_bSendSeqNumCon);

							// create answer own rcon = 2
							pAsySdoSeqCon->
							    m_bRecSeqNum--;

							// check if ack or data-frame
							if (uiDataSize_p >
							    EPL_SEQ_HEADER_SIZE)
							{
								AsySdoSequInstance_g.
								    m_fpSdoComReceiveCb
								    (SdoSeqConHdl,
								     ((tEplAsySdoCom *) & pRecFrame_p->m_le_abSdoSeqPayload), (uiDataSize_p - EPL_SEQ_HEADER_SIZE));
								// call Command Layer Cb
								AsySdoSequInstance_g.
								    m_fpSdoComConCb
								    (SdoSeqConHdl,
								     kAsySdoConStateFrameSended);

							} else {
								Ret =
								    EplSdoAsySeqSendIntern
								    (pAsySdoSeqCon,
								     0, NULL,
								     FALSE);
								if (Ret !=
								    kEplSuccessful)
								{
									goto Exit;
								}
							}

						} else {
							// error ack
							// resend frames from history

							// read frame from history
							Ret =
							    EplSdoAsyReadFromHistory
							    (pAsySdoSeqCon,
							     &pEplFrame,
							     &uiFrameSize,
							     TRUE);
							while ((pEplFrame !=
								NULL)
							       && (uiFrameSize
								   != 0)) {
								// send frame
								Ret =
								    EplSdoAsySeqSendLowerLayer
								    (pAsySdoSeqCon,
								     uiFrameSize,
								     pEplFrame);
								if (Ret !=
								    kEplSuccessful)
								{
									goto Exit;
								}
								// read next frame

								// read frame from history
								Ret =
								    EplSdoAsyReadFromHistory
								    (pAsySdoSeqCon,
								     &pEplFrame,
								     &uiFrameSize,
								     FALSE);
							}	// end of while((pabFrame != NULL)
						}
						break;
					}
				}	// end of switch(pRecFrame_p->m_le_bRecSeqNumCon & EPL_ASY_SDO_CON_MASK)

			} else if (Event_p == kAsySdoSeqEventTimeout) {	// error -> Close
				pAsySdoSeqCon->m_SdoState = kEplAsySdoStateIdle;
				// set rcon and scon to 0
				pAsySdoSeqCon->m_bSendSeqNum &=
				    EPL_SEQ_NUM_MASK;
				pAsySdoSeqCon->m_bRecSeqNum &= EPL_SEQ_NUM_MASK;
				// send frame
				EplSdoAsySeqSendIntern(pAsySdoSeqCon,
						       0, NULL, FALSE);

				// call Command Layer Cb
				AsySdoSequInstance_g.
				    m_fpSdoComConCb(SdoSeqConHdl,
						    kAsySdoConStateTimeout);
			}

			break;
		}

		// unknown state
	default:
		{
			EPL_DBGLVL_SDO_TRACE0
			    ("Error: Unknown State in EplSdoAsySeqProcess\n");

		}
	}			// end of switch(pAsySdoSeqCon->m_SdoState)

      Exit:

#if defined(WIN32) || defined(_WIN32)
	// leave critical section for process function
	LeaveCriticalSection(AsySdoSequInstance_g.m_pCriticalSection);
#endif
	return Ret;

}

//---------------------------------------------------------------------------
//
// Function:    EplSdoAsySeqSendIntern
//
// Description: intern function to create and send a frame
//              -> if uiDataSize_p == 0 create a frame with infos from
//                 pAsySdoSeqCon_p
//
//
//
// Parameters:  pAsySdoSeqCon_p = pointer to control structure of the connection
//              uiDataSize_p    = size of data frame to process (can be 0)
//                                  -> without size of sequence header and Asnd header!!!
//              pData_p         = pointer to frame to process (can be NULL)
//              fFrameInHistory = if TRUE frame is saved to history else not
//
//
//
// Returns:     tEplKernel = errorcode
//
//
// State:
//
//---------------------------------------------------------------------------
static tEplKernel EplSdoAsySeqSendIntern(tEplAsySdoSeqCon * pAsySdoSeqCon_p,
					 unsigned int uiDataSize_p,
					 tEplFrame * pData_p,
					 BOOL fFrameInHistory_p)
{
	tEplKernel Ret;
	u8 abFrame[EPL_SEQ_FRAME_SIZE];
	tEplFrame *pEplFrame;
	unsigned int uiFreeEntries;

	if (pData_p == NULL) {	// set pointer to own frame
		EPL_MEMSET(&abFrame[0], 0x00, sizeof(abFrame));
		pEplFrame = (tEplFrame *) & abFrame[0];
	} else {		// set pointer to frame from calling function
		pEplFrame = pData_p;
	}

	if (fFrameInHistory_p != FALSE) {
		// check if only one free entry in history buffer
		uiFreeEntries =
		    EplSdoAsyGetFreeEntriesFromHistory(pAsySdoSeqCon_p);
		if (uiFreeEntries == 1) {	// request an acknowledge in dataframe
			// own scon = 3
			pAsySdoSeqCon_p->m_bRecSeqNum |= 0x03;
		}
	}
	// fillin header informations
	// set service id sdo
	AmiSetByteToLe(&pEplFrame->m_Data.m_Asnd.m_le_bServiceId, 0x05);
	AmiSetByteToLe(&pEplFrame->m_Data.m_Asnd.m_Payload.m_SdoSequenceFrame.
		       m_le_abReserved, 0x00);
	// set receive sequence number and rcon
	AmiSetByteToLe(&pEplFrame->m_Data.m_Asnd.m_Payload.m_SdoSequenceFrame.
		       m_le_bRecSeqNumCon, pAsySdoSeqCon_p->m_bSendSeqNum);
	// set send sequence number and scon
	AmiSetByteToLe(&pEplFrame->m_Data.m_Asnd.m_Payload.m_SdoSequenceFrame.
		       m_le_bSendSeqNumCon, pAsySdoSeqCon_p->m_bRecSeqNum);

	// add size
	uiDataSize_p += EPL_SEQ_HEADER_SIZE;

	// forward frame to appropriate lower layer
	Ret = EplSdoAsySeqSendLowerLayer(pAsySdoSeqCon_p, uiDataSize_p, pEplFrame);	// pointer to frame

	// check if all allright
	if ((Ret == kEplSuccessful)
	    && (fFrameInHistory_p != FALSE)) {
		// set own scon to 2 if needed
		if ((pAsySdoSeqCon_p->m_bRecSeqNum & 0x03) == 0x03) {
			pAsySdoSeqCon_p->m_bRecSeqNum--;
		}
		// save frame to history
		Ret = EplSdoAsyAddFrameToHistory(pAsySdoSeqCon_p,
						 pEplFrame, uiDataSize_p);
		if (Ret == kEplSdoSeqNoFreeHistory) {	// request Ack needed
			Ret = kEplSdoSeqRequestAckNeeded;
		}

	}

	return Ret;
}

//---------------------------------------------------------------------------
//
// Function:    EplSdoAsySeqSendLowerLayer
//
// Description: intern function to send a previously created frame to lower layer
//
// Parameters:  pAsySdoSeqCon_p = pointer to control structure of the connection
//              uiDataSize_p    = size of data frame to process (can be 0)
//                                  -> without size of Asnd header!!!
//              pData_p         = pointer to frame to process (can be NULL)
//
// Returns:     tEplKernel = errorcode
//
//
// State:
//
//---------------------------------------------------------------------------
static tEplKernel EplSdoAsySeqSendLowerLayer(tEplAsySdoSeqCon * pAsySdoSeqCon_p,
					     unsigned int uiDataSize_p,
					     tEplFrame * pEplFrame_p)
{
	tEplKernel Ret;

	// call send-function
	// check handle for UDP or Asnd
	if ((pAsySdoSeqCon_p->m_ConHandle & EPL_SDO_ASY_HANDLE_MASK) == EPL_SDO_UDP_HANDLE) {	// send over UDP
#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDO_UDP)) != 0)
		Ret = EplSdoUdpuSendData(pAsySdoSeqCon_p->m_ConHandle, pEplFrame_p,	// pointer to frame
					 uiDataSize_p);
#else
		Ret = kEplSdoSeqUnsupportedProt;
#endif

	} else if ((pAsySdoSeqCon_p->m_ConHandle & EPL_SDO_ASY_HANDLE_MASK) == EPL_SDO_ASND_HANDLE) {	// ASND
#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDO_ASND)) != 0)
		Ret = EplSdoAsnduSendData(pAsySdoSeqCon_p->m_ConHandle, pEplFrame_p,	// pointer to frame
					  uiDataSize_p);
#else
		Ret = kEplSdoSeqUnsupportedProt;
#endif
	} else {		// error
		Ret = kEplSdoSeqInvalidHdl;
	}

	return Ret;
}

//---------------------------------------------------------------------------
//
// Function:        EplSdoAsyReceiveCb
//
// Description:     callback-function for received frames from lower layer
//
//
//
// Parameters:      ConHdl_p        = handle of the connection
//                  pSdoSeqData_p   = pointer to frame
//                  uiDataSize_p    = size of frame
//
//
// Returns:         tEplKernel = errorcode
//
//
// State:
//
//---------------------------------------------------------------------------
tEplKernel EplSdoAsyReceiveCb(tEplSdoConHdl ConHdl_p,
			      tEplAsySdoSeq *pSdoSeqData_p,
			      unsigned int uiDataSize_p)
{
	tEplKernel Ret;
	unsigned int uiCount = 0;
	unsigned int uiFreeEntry = EPL_MAX_SDO_SEQ_CON;
	tEplAsySdoSeqCon *pAsySdoSeqCon;

#if defined(WIN32) || defined(_WIN32)
	// enter  critical section
	EnterCriticalSection(AsySdoSequInstance_g.m_pCriticalSectionReceive);
#endif

	EPL_DBGLVL_SDO_TRACE2("Handle: 0x%x , First Databyte 0x%x\n", ConHdl_p,
			      ((u8 *) pSdoSeqData_p)[0]);

	// search controll structure for this connection
	pAsySdoSeqCon = &AsySdoSequInstance_g.m_AsySdoConnection[uiCount];
	while (uiCount < EPL_MAX_SDO_SEQ_CON) {
		if (pAsySdoSeqCon->m_ConHandle == ConHdl_p) {
			break;
		} else if ((pAsySdoSeqCon->m_ConHandle == 0)
			   && (uiFreeEntry == EPL_MAX_SDO_SEQ_CON)) {
			// free entry
			uiFreeEntry = uiCount;
		}
		uiCount++;
		pAsySdoSeqCon++;
	}

	if (uiCount == EPL_MAX_SDO_SEQ_CON) {	// new connection
		if (uiFreeEntry == EPL_MAX_SDO_SEQ_CON) {
			Ret = kEplSdoSeqNoFreeHandle;
			goto Exit;
		} else {
			pAsySdoSeqCon =
			    &AsySdoSequInstance_g.
			    m_AsySdoConnection[uiFreeEntry];
			// save handle from lower layer
			pAsySdoSeqCon->m_ConHandle = ConHdl_p;
			// increment use counter
			pAsySdoSeqCon->m_uiUseCount++;
			uiCount = uiFreeEntry;
		}
	}
	// call history ack function
	Ret = EplSdoAsyAckFrameToHistory(pAsySdoSeqCon,
					 (AmiGetByteFromLe
					  (&pSdoSeqData_p->
					   m_le_bRecSeqNumCon) &
					  EPL_SEQ_NUM_MASK));
	if (Ret != kEplSuccessful) {
		goto Exit;
	}
#if defined(WIN32) || defined(_WIN32)
	// leave critical section
	LeaveCriticalSection(AsySdoSequInstance_g.m_pCriticalSectionReceive);
#endif

	// call process function with pointer of frame and event kAsySdoSeqEventFrameRec
	Ret = EplSdoAsySeqProcess(uiCount,
				  uiDataSize_p,
				  NULL, pSdoSeqData_p, kAsySdoSeqEventFrameRec);

      Exit:
	return Ret;
}

//---------------------------------------------------------------------------
//
// Function:        EplSdoAsyInitHistory
//
// Description:     inti function for history buffer
//
//
//
// Parameters:
//
//
// Returns:         tEplKernel = errorcode
//
//
// State:
//
//---------------------------------------------------------------------------
static tEplKernel EplSdoAsyInitHistory(void)
{
	tEplKernel Ret;
	unsigned int uiCount;

	Ret = kEplSuccessful;
	// init m_bFreeEntries in history-buffer
	for (uiCount = 0; uiCount < EPL_MAX_SDO_SEQ_CON; uiCount++) {
		AsySdoSequInstance_g.m_AsySdoConnection[uiCount].
		    m_SdoConHistory.m_bFreeEntries = EPL_SDO_HISTORY_SIZE;
	}

	return Ret;
}

//---------------------------------------------------------------------------
//
// Function:        EplSdoAsyAddFrameToHistory
//
// Description:     function to add a frame to the history buffer
//
//
//
// Parameters:      pAsySdoSeqCon_p = pointer to control structure of this connection
//                  pFrame_p        = pointer to frame
//                  uiSize_p        = size of the frame
//                                     -> without size of the ethernet header
//                                        and the asnd header
//
// Returns:         tEplKernel = errorcode
//
//
// State:
//
//---------------------------------------------------------------------------
static tEplKernel EplSdoAsyAddFrameToHistory(tEplAsySdoSeqCon * pAsySdoSeqCon_p,
					     tEplFrame * pFrame_p,
					     unsigned int uiSize_p)
{
	tEplKernel Ret;
	tEplAsySdoConHistory *pHistory;

	Ret = kEplSuccessful;

	// add frame to history buffer

	// check size
	// $$$ d.k. EPL_SEQ_HISTORY_FRAME_SIZE includes the header size, but uiSize_p does not!!!
	if (uiSize_p > EPL_SEQ_HISTROY_FRAME_SIZE) {
		Ret = kEplSdoSeqFrameSizeError;
		goto Exit;
	}
	// save pointer to history
	pHistory = &pAsySdoSeqCon_p->m_SdoConHistory;

	// check if a free entry is available
	if (pHistory->m_bFreeEntries > 0) {	// write message in free entry
		EPL_MEMCPY(&
			   ((tEplFrame *) pHistory->
			    m_aabHistoryFrame[pHistory->m_bWrite])->
			   m_le_bMessageType, &pFrame_p->m_le_bMessageType,
			   uiSize_p + EPL_ASND_HEADER_SIZE);
		// store size
		pHistory->m_auiFrameSize[pHistory->m_bWrite] = uiSize_p;

		// decremend number of free bufferentries
		pHistory->m_bFreeEntries--;

		// increment writeindex
		pHistory->m_bWrite++;

		// check if write-index run over array-boarder
		if (pHistory->m_bWrite == EPL_SDO_HISTORY_SIZE) {
			pHistory->m_bWrite = 0;
		}

	} else {		// no free entry
		Ret = kEplSdoSeqNoFreeHistory;
	}

      Exit:
	return Ret;
}

//---------------------------------------------------------------------------
//
// Function:        EplSdoAsyAckFrameToHistory
//
// Description:     function to delete acknowledged frames fron history buffer
//
//
//
// Parameters:      pAsySdoSeqCon_p = pointer to control structure of this connection
//                  bRecSeqNumber_p = receive sequence number of the received frame
//
//
// Returns:         tEplKernel = errorcode
//
//
// State:
//
//---------------------------------------------------------------------------
static tEplKernel EplSdoAsyAckFrameToHistory(tEplAsySdoSeqCon * pAsySdoSeqCon_p,
					     u8 bRecSeqNumber_p)
{
	tEplKernel Ret;
	tEplAsySdoConHistory *pHistory;
	u8 bAckIndex;
	u8 bCurrentSeqNum;

	Ret = kEplSuccessful;

	// get pointer to history buffer
	pHistory = &pAsySdoSeqCon_p->m_SdoConHistory;

	// release all acknowledged frames from history buffer

	// check if there are entries in history
	if (pHistory->m_bFreeEntries < EPL_SDO_HISTORY_SIZE) {
		bAckIndex = pHistory->m_bAck;
		do {
			bCurrentSeqNum =
			    (((tEplFrame *) pHistory->
			      m_aabHistoryFrame[bAckIndex])->m_Data.m_Asnd.
			     m_Payload.m_SdoSequenceFrame.
			     m_le_bSendSeqNumCon & EPL_SEQ_NUM_MASK);
			if (((bRecSeqNumber_p -
			      bCurrentSeqNum) & EPL_SEQ_NUM_MASK)
			    < EPL_SEQ_NUM_THRESHOLD) {
				pHistory->m_auiFrameSize[bAckIndex] = 0;
				bAckIndex++;
				pHistory->m_bFreeEntries++;
				if (bAckIndex == EPL_SDO_HISTORY_SIZE) {	// read index run over array-boarder
					bAckIndex = 0;
				}
			} else {	// nothing to do anymore,
				// because any further frame in history has larger sequence
				// number than the acknowledge
				goto Exit;
			}
		}
		while ((((bRecSeqNumber_p - 1 -
			  bCurrentSeqNum) & EPL_SEQ_NUM_MASK)
			< EPL_SEQ_NUM_THRESHOLD)
		       && (pHistory->m_bWrite != bAckIndex));

		// store local read-index to global var
		pHistory->m_bAck = bAckIndex;
	}

      Exit:
	return Ret;
}

//---------------------------------------------------------------------------
//
// Function:        EplSdoAsyReadFromHistory
//
// Description:     function to one frame from history
//
//
//
// Parameters:      pAsySdoSeqCon_p = pointer to control structure of this connection
//                  ppFrame_p       = pointer to pointer to the buffer of the stored frame
//                  puiSize_p       = OUT: size of the frame
//                  fInitRead       = bool which indicate a start of retransmission
//                                      -> return last not acknowledged message if TRUE
//
//
// Returns:         tEplKernel = errorcode
//
//
// State:
//
//---------------------------------------------------------------------------
static tEplKernel EplSdoAsyReadFromHistory(tEplAsySdoSeqCon * pAsySdoSeqCon_p,
					   tEplFrame ** ppFrame_p,
					   unsigned int *puiSize_p,
					   BOOL fInitRead_p)
{
	tEplKernel Ret;
	tEplAsySdoConHistory *pHistory;

	Ret = kEplSuccessful;

	// read one message from History

	// get pointer to history buffer
	pHistory = &pAsySdoSeqCon_p->m_SdoConHistory;

	// check if init
	if (fInitRead_p != FALSE) {	// initialize read index to the index which shall be acknowledged next
		pHistory->m_bRead = pHistory->m_bAck;
	}
	// check if entries are available for reading
	if ((pHistory->m_bFreeEntries < EPL_SDO_HISTORY_SIZE)
	    && (pHistory->m_bWrite != pHistory->m_bRead)) {
//        PRINTF4("EplSdoAsyReadFromHistory(): init = %d, read = %u, write = %u, ack = %u", (int) fInitRead_p, (u16)pHistory->m_bRead, (u16)pHistory->m_bWrite, (u16)pHistory->m_bAck);
//        PRINTF2(", free entries = %u, next frame size = %u\n", (u16)pHistory->m_bFreeEntries, pHistory->m_auiFrameSize[pHistory->m_bRead]);

		// return pointer to stored frame
		*ppFrame_p =
		    (tEplFrame *) pHistory->m_aabHistoryFrame[pHistory->
							      m_bRead];

		// save size
		*puiSize_p = pHistory->m_auiFrameSize[pHistory->m_bRead];

		pHistory->m_bRead++;
		if (pHistory->m_bRead == EPL_SDO_HISTORY_SIZE) {
			pHistory->m_bRead = 0;
		}

	} else {
//        PRINTF3("EplSdoAsyReadFromHistory(): read = %u, ack = %u, free entries = %u, no frame\n", (u16)pHistory->m_bRead, (u16)pHistory->m_bAck, (u16)pHistory->m_bFreeEntries);

		// no more frames to send
		// return null pointer
		*ppFrame_p = NULL;

		*puiSize_p = 0;
	}

	return Ret;

}

//---------------------------------------------------------------------------
//
// Function:        EplSdoAsyGetFreeEntriesFromHistory
//
// Description:     function returns the number of free histroy entries
//
//
//
// Parameters:      pAsySdoSeqCon_p = pointer to control structure of this connection
//
//
// Returns:         unsigned int    = number of free entries
//
//
// State:
//
//---------------------------------------------------------------------------
static unsigned int EplSdoAsyGetFreeEntriesFromHistory(tEplAsySdoSeqCon *
						       pAsySdoSeqCon_p)
{
	unsigned int uiFreeEntries;

	uiFreeEntries =
	    (unsigned int)pAsySdoSeqCon_p->m_SdoConHistory.m_bFreeEntries;

	return uiFreeEntries;
}

//---------------------------------------------------------------------------
//
// Function:        EplSdoAsySeqSetTimer
//
// Description:     function sets or modify timer in timermosule
//
//
//
// Parameters:      pAsySdoSeqCon_p = pointer to control structure of this connection
//                  ulTimeout       = timeout in ms
//
//
// Returns:         unsigned int    = number of free entries
//
//
// State:
//
//---------------------------------------------------------------------------
static tEplKernel EplSdoAsySeqSetTimer(tEplAsySdoSeqCon * pAsySdoSeqCon_p,
				       unsigned long ulTimeout)
{
	tEplKernel Ret;
	tEplTimerArg TimerArg;

	TimerArg.m_EventSink = kEplEventSinkSdoAsySeq;
	TimerArg.m_ulArg = (unsigned long)pAsySdoSeqCon_p;

	if (pAsySdoSeqCon_p->m_EplTimerHdl == 0) {	// create new timer
		Ret = EplTimeruSetTimerMs(&pAsySdoSeqCon_p->m_EplTimerHdl,
					  ulTimeout, TimerArg);
	} else {		// modify exisiting timer
		Ret = EplTimeruModifyTimerMs(&pAsySdoSeqCon_p->m_EplTimerHdl,
					     ulTimeout, TimerArg);

	}

	return Ret;
}

// EOF