etisserant@0: /*
nico@208:   This file is part of CanFestival, a library implementing CanOpen
nico@208:   Stack.
nico@208: 
nico@208:   Copyright (C): Edouard TISSERANT and Francis DUPIN
nico@208: 
nico@208:   See COPYING file for copyrights details.
nico@208: 
nico@208:   This library is free software; you can redistribute it and/or
nico@208:   modify it under the terms of the GNU Lesser General Public
nico@208:   License as published by the Free Software Foundation; either
nico@208:   version 2.1 of the License, or (at your option) any later version.
nico@208: 
nico@208:   This library is distributed in the hope that it will be useful,
nico@208:   but WITHOUT ANY WARRANTY; without even the implied warranty of
nico@208:   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
nico@208:   Lesser General Public License for more details.
nico@208: 
nico@208:   You should have received a copy of the GNU Lesser General Public
nico@208:   License along with this library; if not, write to the Free Software
nico@208:   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
nico@208:   USA
etisserant@0: */
etisserant@0: #include "pdo.h"
etisserant@0: #include "objacces.h"
etisserant@149: #include "canfestival.h"
etisserant@370: #include "sysdep.h"
etisserant@0: 
nico@208: /*!
nico@208: ** @file   pdo.c
nico@208: ** @author Edouard TISSERANT and Francis DUPIN
nico@208: ** @date   Tue Jun  5 09:32:32 2007
nico@208: **
nico@208: ** @brief
nico@208: **
nico@208: **
nico@208: */
etisserant@235: 
etisserant@235: /*!
etisserant@235: **
nico@208: **
nico@208: ** @param d
etisserant@235: ** @param TPDO_com TPDO communication parameters OD entry
etisserant@235: ** @param TPDO_map TPDO mapping parameters OD entry
nico@208: **
nico@208: ** @return
nico@208: **/
etisserant@235: 
etisserant@235: UNS8 buildPDO(CO_Data* d, UNS8 numPdo, Message *pdo)
etisserant@235: {
etisserant@235: 	const indextable* TPDO_com = d->objdict + d->firstIndex->PDO_TRS + numPdo; 
etisserant@235: 	const indextable* TPDO_map = d->objdict + d->firstIndex->PDO_TRS_MAP + numPdo;
etisserant@235: 	
etisserant@235: 	UNS8 prp_j = 0x00;
etisserant@235: 	UNS8 offset = 0x00;
etisserant@235: 	const UNS8* pMappingCount = (UNS8*) TPDO_map->pSubindex[0].pObject;
etisserant@235: 
etisserant@370: 	pdo->cob_id = *(UNS16*)TPDO_com->pSubindex[1].pObject & UNS16_LE(0x7FF);
etisserant@235: 	pdo->rtr = NOT_A_REQUEST;
etisserant@235: 
etisserant@235: 	MSG_WAR(0x3009, "  PDO CobId is : ", *(UNS32*)TPDO_com->pSubindex[1].pObject);
etisserant@235: 	MSG_WAR(0x300D, "  Number of objects mapped : ",*pMappingCount );
etisserant@235: 	
etisserant@235: 	do{
etisserant@235: 		UNS8 dataType; /* Unused */
etisserant@235: 		UNS8 tmp[]= {0,0,0,0,0,0,0,0}; /* temporary space to hold bits */
etisserant@235: 
etisserant@235: 		/* pointer fo the var which holds the mapping parameter of an mapping entry  */
etisserant@235: 		UNS32* pMappingParameter = (UNS32*) TPDO_map->pSubindex[prp_j + 1].pObject;
etisserant@235: 		UNS16 index = (UNS16)((*pMappingParameter) >> 16);
etisserant@235: 		UNS8 Size = (UNS8)(*pMappingParameter); /* Size in bits */
etisserant@235: 		
luis@350: 		/* get variable only if Size != 0 and Size is lower than remaining bits in the PDO */
luis@350: 		if(Size && ((offset + Size) <= 64)) {
luis@350: 			UNS8 ByteSize = 1 + ((Size - 1) >> 3); /*1->8 => 1 ; 9->16 => 2, ... */
luis@350: 			UNS8 subIndex = (UNS8)(( (*pMappingParameter) >> (UNS8)8 ) & (UNS32)0x000000FF);
luis@350: 			
luis@350: 			MSG_WAR(0x300F, "  got mapping parameter : ", *pMappingParameter);
luis@350: 			MSG_WAR(0x3050, "    at index : ", TPDO_map->index);
luis@350: 			MSG_WAR(0x3051, "    sub-index : ", prp_j + 1);
luis@350: 			
luis@350: 			if( getODentry(d, index, subIndex, tmp, &ByteSize, &dataType, 0 ) != OD_SUCCESSFUL ){
luis@350: 				MSG_ERR(0x1013, " Couldn't find mapped variable at index-subindex-size : ", (UNS16)(*pMappingParameter));
luis@350: 				return 0xFF;
luis@350: 			}
luis@350: 			/* copy bit per bit in little endian*/
luis@350: 			CopyBits(Size, ((UNS8*)tmp), 0 , 0, (UNS8*)&pdo->data[offset>>3], offset%8, 0);
luis@350: 
luis@350: 			offset += Size ;
etisserant@235: 		}
etisserant@235: 		prp_j++;
etisserant@235: 	}while( prp_j < *pMappingCount );
etisserant@235: 
etisserant@235: 	pdo->len = 1 + ((offset - 1) >> 3);
etisserant@235: 
etisserant@235: 	MSG_WAR(0x3015, "  End scan mapped variable", 0);
etisserant@235: 
etisserant@235: 	return 0;
etisserant@235: }
nico@208: 
nico@208: /*!
nico@208: **
nico@208: **
nico@208: ** @param d
nico@208: ** @param cobId
nico@208: **
nico@208: ** @return
nico@208: **/
etisserant@236: UNS8 sendPDOrequest( CO_Data* d, UNS16 RPDOIndex )
nico@208: {
etisserant@370:   UNS16 * pwCobId;
etisserant@236:   UNS16 offset = d->firstIndex->PDO_RCV;
etisserant@236:   UNS16 lastIndex = d->lastIndex->PDO_RCV;
etisserant@236: 
nico@215:   /* Sending the request only if the cobid have been found on the PDO
nico@208:      receive */
nico@215:   /* part dictionary */
etisserant@236:   
etisserant@236:   MSG_WAR(0x3930, "sendPDOrequest RPDO Index : ",RPDOIndex);
etisserant@236:   
etisserant@236:   if (offset && RPDOIndex >= 0x1400){
etisserant@236:     offset += RPDOIndex - 0x1400;  
etisserant@236:     if (offset <= lastIndex) {
nico@215:       /* get the CobId*/
etisserant@370:       pwCobId = (UNS16*) d->objdict[offset].pSubindex[1].pObject;
nico@208: 
etisserant@236:       MSG_WAR(0x3930, "sendPDOrequest cobId is : ",*pwCobId);
leonid@252:       {
etisserant@285:           Message pdo;
etisserant@365:           pdo.cob_id = *pwCobId;
etisserant@285:           pdo.rtr = REQUEST;
etisserant@285:           pdo.len = 0;      
etisserant@285:           return canSend(d->canHandle,&pdo);
leonid@252:       }
nico@208:     }
etisserant@236:   }
etisserant@236:   MSG_ERR(0x1931, "sendPDOrequest : RPDO Index not found : ", RPDOIndex);
etisserant@0:   return 0xFF;
etisserant@0: }
etisserant@0: 
etisserant@0: 
nico@208: /*!
nico@208: **
nico@208: **
nico@208: ** @param d
nico@208: ** @param m
nico@208: **
nico@208: ** @return
nico@208: **/
etisserant@0: UNS8 proceedPDO(CO_Data* d, Message *m)
nico@208: {
etisserant@0:   UNS8   numPdo;
nico@215:   UNS8   numMap;  /* Number of the mapped varable */
nico@215:   UNS8 *     pMappingCount = NULL;    /* count of mapped objects... */
nico@215:   /* pointer to the var which is mapped to a pdo... */
nico@215:   /*  void *     pMappedAppObject = NULL;   */
nico@215:   /* pointer fo the var which holds the mapping parameter of an
nico@208:      mapping entry */
nico@208:   UNS32 *    pMappingParameter = NULL;
nico@215:   UNS8  *    pTransmissionType = NULL; /* pointer to the transmission
nico@208:                                          type */
etisserant@370:   UNS16 *    pwCobId = NULL;
etisserant@0:   UNS8       Size;
etisserant@0:   UNS8       offset;
etisserant@0:   UNS8       status;
etisserant@0:   UNS32      objDict;
etisserant@0:   UNS16      offsetObjdict;
etisserant@0:   UNS16      lastIndex;
etisserant@235:   
etisserant@235:   status = state2;
nico@208: 
etisserant@370:   MSG_WAR(0x3935, "proceedPDO, cobID : ", ((*m).cob_id & UNS16_LE(0x7ff)));
etisserant@0:   offset = 0x00;
etisserant@0:   numPdo = 0;
etisserant@0:   numMap = 0;
nico@215:   if((*m).rtr == NOT_A_REQUEST ) { /* The PDO received is not a
nico@208:                                      request. */
etisserant@235: 
etisserant@0:     offsetObjdict = d->firstIndex->PDO_RCV;
etisserant@0:     lastIndex = d->lastIndex->PDO_RCV;
nico@208: 
nico@215:     /* study of all the PDO stored in the dictionary */
etisserant@0:     if(offsetObjdict)
nico@208:       while (offsetObjdict <= lastIndex) {
nico@208: 
nico@208:         switch( status ) {
nico@208: 
nico@208:         case state2:
nico@215:           /* get CobId of the dictionary correspondant to the received
nico@208:              PDO */
etisserant@370:           pwCobId = (UNS16*) d->objdict[offsetObjdict].pSubindex[1].pObject;
nico@215:           /* check the CobId coherance */
nico@215:           /*pwCobId is the cobId read in the dictionary at the state 3
nico@208:             */
etisserant@365:           if ( *pwCobId == (*m).cob_id ){
nico@215:             /* The cobId is recognized */
nico@208:             status = state4;
nico@208:             MSG_WAR(0x3936, "cobId found at index ", 0x1400 + numPdo);
nico@208:             break;
nico@208:           }
nico@208:           else {
nico@215:             /* cobId received does not match with those write in the
nico@208:               dictionnary */
nico@208:             numPdo++;
nico@208:             offsetObjdict++;
nico@208:             status = state2;
nico@208:             break;
nico@208:           }
nico@208: 
nico@215:             case state4:/* Get Mapped Objects Number */
nico@215:                /* The cobId of the message received has been found in the
nico@208:                  dictionnary. */
nico@208:                offsetObjdict = d->firstIndex->PDO_RCV_MAP;
nico@208:              lastIndex = d->lastIndex->PDO_RCV_MAP;
etisserant@217:              pMappingCount = (UNS8*) (d->objdict + offsetObjdict + numPdo)->pSubindex[0].pObject;
nico@208:              numMap = 0;
nico@208:              while (numMap < *pMappingCount) {
nico@208:                UNS8 tmp[]= {0,0,0,0,0,0,0,0};
nico@208:                UNS8 ByteSize;
etisserant@217:                pMappingParameter = (UNS32*) (d->objdict + offsetObjdict + numPdo)->pSubindex[numMap + 1].pObject;
nico@208:                if (pMappingParameter == NULL) {
nico@208:                  MSG_ERR(0x1937, "Couldn't get mapping parameter : ", numMap + 1);
nico@208:                  return 0xFF;
nico@208:                }
nico@215:                /* Get the addresse of the mapped variable. */
nico@215:                /* detail of *pMappingParameter : */
nico@215:                /* The 16 hight bits contains the index, the medium 8 bits
nico@208:                  contains the subindex, */
nico@215:                /* and the lower 8 bits contains the size of the mapped
nico@208:                  variable. */
nico@208: 
nico@208:                Size = (UNS8)(*pMappingParameter);
luis@350: 					
luis@350: 					/* set variable only if Size != 0 and Size is lower than remaining bits in the PDO */
luis@350:                if(Size && ((offset + Size) <= (m->len << 3))) {
luis@350:                  /* copy bit per bit in little endian */
luis@350:                  CopyBits(Size, (UNS8*)&m->data[offset>>3], offset%8, 0, ((UNS8*)tmp), 0, 0);
luis@350: 
luis@350:                  ByteSize = 1 + ((Size - 1) >> 3); /*1->8 => 1 ; 9->16 =>
luis@350:                                                      2, ... */
luis@350: 
luis@350:                  objDict = setODentry(d, (UNS16)((*pMappingParameter) >> 16),
luis@350:                                       (UNS8)(((*pMappingParameter) >> 8 ) & 0xFF),
luis@350:                                    tmp, &ByteSize, 0 );
luis@350: 
luis@350:                  if(objDict != OD_SUCCESSFUL) {
luis@350:                    MSG_ERR(0x1938, "error accessing to the mapped var : ", numMap + 1);
luis@350:                    MSG_WAR(0x2939, "         Mapped at index : ", (*pMappingParameter) >> 16);
luis@350:                    MSG_WAR(0x2940, "                subindex : ", ((*pMappingParameter) >> 8 ) & 0xFF);
luis@350:                    return 0xFF;
luis@350:                  }
luis@350: 
etisserant@365:                  MSG_WAR(0x3942, "Variable updated with value received by PDO cobid : ", m->cob_id);
luis@350:                  MSG_WAR(0x3943, "         Mapped at index : ", (*pMappingParameter) >> 16);
luis@350:                  MSG_WAR(0x3944, "                subindex : ", ((*pMappingParameter) >> 8 ) & 0xFF);
luis@350:                  /* MSG_WAR(0x3945, "                data : ",*((UNS32*)pMappedAppObject)); */
luis@350:                  offset += Size;
luis@350: 					}
nico@208:                numMap++;
nico@215:              } /* end loop while on mapped variables */
nico@208: 
nico@208:              offset=0x00;
nico@208:              numMap = 0;
nico@208:              return 0;
nico@208: 
nico@215:         }/* end switch status*/
nico@215:       }/* end while*/
nico@215:   }/* end if Donnees */
nico@208:   else if ((*m).rtr == REQUEST ){
etisserant@365:     MSG_WAR(0x3946, "Receive a PDO request cobId : ", m->cob_id);
nico@208:     status = state1;
nico@208:     offsetObjdict = d->firstIndex->PDO_TRS;
nico@208:     lastIndex = d->lastIndex->PDO_TRS;
nico@208:     if(offsetObjdict) while( offsetObjdict  <= lastIndex ){
nico@215:       /* study of all PDO stored in the objects dictionary */
nico@208: 
nico@208:       switch( status ){
nico@208: 
nico@215:       case state1:/* check the CobId */
nico@215:         /* get CobId of the dictionary which match to the received PDO
nico@208:          */
etisserant@370:         pwCobId = (UNS16*) (d->objdict + offsetObjdict)->pSubindex[1].pObject;
etisserant@365:         if ( *pwCobId == (*m).cob_id ) {
nico@208:           status = state4;
nico@208:           break;
nico@208:         }
nico@208:         else {
nico@208:           numPdo++;
nico@208:           offsetObjdict++;
nico@208:         }
nico@208:         status = state1;
nico@208:         break;
nico@208: 
nico@208: 
etisserant@236:       case state4:/* check transmission type */
etisserant@217:         pTransmissionType = (UNS8*) d->objdict[offsetObjdict].pSubindex[2].pObject;
etisserant@236:         /* If PDO is to be sampled and send on RTR, do it*/
etisserant@236:         if ( (*pTransmissionType == TRANS_RTR)) {
nico@208:           status = state5;
nico@208:           break;
etisserant@236:         /* RTR_SYNC mean data is prepared at SYNC, and transmitted on RTR */
etisserant@236:         }else if ((*pTransmissionType == TRANS_RTR_SYNC )) {
etisserant@236:     	  if(d->PDO_status[numPdo].transmit_type_parameter & PDO_RTR_SYNC_READY){
etisserant@236:             /*Data ready, just send*/
etisserant@236:     	    canSend(d->canHandle,&d->PDO_status[numPdo].last_message);
etisserant@236:             return 0;
etisserant@236:     	  }else{
etisserant@236:             /* if SYNC did never occur, force emission with current data */
etisserant@236:             /* DS301 do not tell what to do in such a case...*/
etisserant@365:             MSG_ERR(0x1947, "Not ready RTR_SYNC TPDO send current data : ", m->cob_id);
etisserant@236:             status = state5;
etisserant@236:     	  }
etisserant@236:           break;
etisserant@235:         }else if(
etisserant@235:              (*pTransmissionType == TRANS_EVENT_PROFILE) ||
etisserant@235:              (*pTransmissionType == TRANS_EVENT_SPECIFIC) ) {
etisserant@235: 	  /* Zap all timers and inhibit flag */
etisserant@235: 	  d->PDO_status[numPdo].event_timer = DelAlarm(d->PDO_status[numPdo].event_timer);
etisserant@235: 	  d->PDO_status[numPdo].inhibit_timer = DelAlarm(d->PDO_status[numPdo].inhibit_timer);
etisserant@235:   	  d->PDO_status[numPdo].transmit_type_parameter &= ~PDO_INHIBITED;
etisserant@235:   	  /* Call  PDOEventTimerAlarm for this TPDO, this will trigger emission et reset timers */
etisserant@235:           PDOEventTimerAlarm(d, numPdo);
etisserant@235:           return 0;
etisserant@235:         }else {
nico@215:           /* The requested PDO is not to send on request. So, does
nico@208:             nothing. */
etisserant@365:           MSG_WAR(0x2947, "PDO is not to send on request : ", m->cob_id);
nico@208:           return 0xFF;
nico@208:         }
nico@208: 
etisserant@235:       case state5:/* build and send requested PDO */
etisserant@235:       {
etisserant@235:       	Message pdo;
etisserant@235:     	if( buildPDO(d, numPdo, &pdo))
etisserant@235:     	{
etisserant@236:           MSG_ERR(0x1948, " Couldn't build TPDO n°", numPdo);
etisserant@236:           return 0xFF;
etisserant@235:     	}
etisserant@235:     	canSend(d->canHandle,&pdo);
nico@208:         return 0;
etisserant@235:       }
nico@215:       }/* end switch status */
nico@215:     }/* end while */
nico@215:   }/* end if Requete */
nico@208: 
etisserant@0:   return 0;
etisserant@0: }
etisserant@0: 
nico@208: /*!
nico@208: **
nico@208: **
nico@208: ** @param NbBits
nico@208: ** @param SrcByteIndex
nico@208: ** @param SrcBitIndex
nico@208: ** @param SrcBigEndian
nico@208: ** @param DestByteIndex
nico@208: ** @param DestBitIndex
nico@208: ** @param DestBigEndian
nico@208: **/
greg@201: void CopyBits(UNS8 NbBits, UNS8* SrcByteIndex, UNS8 SrcBitIndex, UNS8 SrcBigEndian, UNS8* DestByteIndex, UNS8 DestBitIndex, UNS8 DestBigEndian)
greg@201: {
nico@215:   /* This loop copy as many bits that it can each time, crossing*/
nico@215:   /* successively bytes*/
nico@208:   // boundaries from LSB to MSB.
nico@208:   while(NbBits > 0)
nico@208:     {
nico@215:       /* Bit missalignement between src and dest*/
nico@208:       INTEGER8 Vect = DestBitIndex - SrcBitIndex;
nico@208: 
nico@215:       /* We can now get src and align it to dest*/
nico@208:       UNS8 Aligned = Vect>0 ? *SrcByteIndex << Vect : *SrcByteIndex >> -Vect;
nico@208: 
nico@215:       /* Compute the nb of bit we will be able to copy*/
nico@208:       UNS8 BoudaryLimit = (Vect>0 ? 8 - DestBitIndex :  8 - SrcBitIndex );
nico@208:       UNS8 BitsToCopy = BoudaryLimit > NbBits ? NbBits : BoudaryLimit;
nico@208: 
nico@215:       /* Create a mask that will serve in:*/
nico@208:       UNS8 Mask = ((0xff << (DestBitIndex + BitsToCopy)) | (0xff >> (8 - DestBitIndex)));
nico@208: 
nico@215:       /* - Filtering src*/
nico@208:       UNS8 Filtered = Aligned & ~Mask;
nico@208: 
nico@215:       /* - and erase bits where we write, preserve where we don't*/
nico@208:       *DestByteIndex &= Mask;
nico@208: 
nico@215:       /* Then write.*/
nico@208:       *DestByteIndex |= Filtered ;
nico@208: 
nico@215:       /*Compute next time cursors for src*/
nico@215:       if((SrcBitIndex += BitsToCopy)>7)/* cross boundary ?*/
nico@208:         {
nico@215:           SrcBitIndex = 0;/* First bit*/
nico@215:           SrcByteIndex += (SrcBigEndian ? -1 : 1);/* Next byte*/
nico@215:         }
nico@215: 
nico@215: 
nico@215:       /*Compute next time cursors for dest*/
nico@208:       if((DestBitIndex += BitsToCopy)>7)
nico@208:         {
nico@215:           DestBitIndex = 0;/* First bit*/
nico@215:           DestByteIndex += (DestBigEndian ? -1 : 1);/* Next byte*/
nico@215:         }
nico@215: 
nico@215:       /*And decrement counter.*/
nico@208:       NbBits -= BitsToCopy;
nico@208:     }
greg@201: 
greg@201: }
nico@208: /*!
nico@208: **
nico@208: **
nico@208: ** @param d
nico@208: **
nico@208: ** @return
nico@208: **/
etisserant@235: 
etisserant@235: UNS8 sendPDOevent( CO_Data* d)
etisserant@235: {
etisserant@235:   /* Calls _sendPDOevent specifying it is not a sync event */
etisserant@235:   return _sendPDOevent(d, 0);
etisserant@235: }
etisserant@235: 	
etisserant@235: 
etisserant@235: void PDOEventTimerAlarm(CO_Data* d, UNS32 pdoNum)
etisserant@235: {
etisserant@235: 	/* This is needed to avoid deletion of re-attribuated timer */
etisserant@235: 	d->PDO_status[pdoNum].event_timer = TIMER_NONE;
etisserant@235: 	/* force emission of PDO by artificially changing last emitted*/
etisserant@365: 	d->PDO_status[pdoNum].last_message.cob_id = 0;
etisserant@235: 	_sendPDOevent( d, 0 ); /* not a Sync Event*/	
etisserant@235: }
etisserant@235: 
etisserant@235: void PDOInhibitTimerAlarm(CO_Data* d, UNS32 pdoNum)
etisserant@235: {
etisserant@235: 	/* This is needed to avoid deletion of re-attribuated timer */
etisserant@235: 	d->PDO_status[pdoNum].inhibit_timer = TIMER_NONE;
etisserant@235: 	/* Remove inhibit flag */
etisserant@235: 	d->PDO_status[pdoNum].transmit_type_parameter &= ~PDO_INHIBITED;
etisserant@235: 	_sendPDOevent( d, 0 ); /* not a Sync Event*/
etisserant@235: }
etisserant@235: 
etisserant@235: /*!
etisserant@235: **
etisserant@235: **
etisserant@235: ** @param d
etisserant@235: ** @param isSyncEvent
etisserant@235: **
etisserant@235: ** @return
etisserant@235: **/
etisserant@235: 
etisserant@235: UNS8 _sendPDOevent( CO_Data* d, UNS8 isSyncEvent )
etisserant@235: { 
etisserant@235:   UNS8 	pdoNum = 0x00;       /* number of the actual processed pdo-nr. */
etisserant@235:   UNS8* pTransmissionType = NULL;  
etisserant@235:   UNS8 status = state3;
etisserant@235:   UNS16 offsetObjdict = d->firstIndex->PDO_TRS;
etisserant@235:   UNS16 offsetObjdictMap = d->firstIndex->PDO_TRS_MAP;
etisserant@235:   UNS16 lastIndex = d->lastIndex->PDO_TRS;  
etisserant@235: 
etisserant@235:   /* study all PDO stored in the objects dictionary */	
etisserant@235:   if(offsetObjdict){
etisserant@235:    Message pdo = Message_Initializer;
etisserant@235:    while( offsetObjdict <= lastIndex) {  
etisserant@235:     switch( status ) {
etisserant@236:     case state3:
etisserant@236:       if (/*d->objdict[offsetObjdict].bSubCount < 5 || not necessary with objdictedit (always 5)*/
etisserant@236:           /* check if TPDO is not valid */ 
luis@298:           *(UNS32*)d->objdict[offsetObjdict].pSubindex[1].pObject & 0x80000000) {
etisserant@236: 	  MSG_WAR(0x3960, "Not a valid PDO ", 0x1800 + pdoNum);
etisserant@236: 	  /*Go next TPDO*/
etisserant@236: 	  status = state11;
etisserant@236: 	  break;
etisserant@235: 	}
etisserant@236:       /* get the PDO transmission type */
etisserant@235:       pTransmissionType = (UNS8*) d->objdict[offsetObjdict].pSubindex[2].pObject;    
etisserant@236:       MSG_WAR(0x3962, "Reading PDO at index : ", 0x1800 + pdoNum);
etisserant@236: 
etisserant@236:       /* check if transmission type is SYNCRONOUS */
etisserant@236:       /* The message is transmited every n SYNC with n=TransmissionType */      
etisserant@235:       if( isSyncEvent && 
etisserant@235:       	  (*pTransmissionType >= TRANS_SYNC_MIN) &&
etisserant@235:       	  (*pTransmissionType <= TRANS_SYNC_MAX) &&
etisserant@236:           (++d->PDO_status[pdoNum].transmit_type_parameter == *pTransmissionType) ) {
etisserant@236:         /*Reset count of SYNC*/	
etisserant@235: 	d->PDO_status[pdoNum].transmit_type_parameter = 0;
etisserant@236: 	MSG_WAR(0x3964, "  PDO is on SYNCHRO. Trans type : ", *pTransmissionType);
leonid@252:  {
leonid@252:  Message msg_init = Message_Initializer;
leonid@252:  pdo = msg_init;
leonid@252:  }	
etisserant@235:         if(buildPDO(d, pdoNum, &pdo))
etisserant@235:         {
etisserant@236:             MSG_ERR(0x1906, " Couldn't build TPDO number : ", pdoNum);
etisserant@235: 	    status = state11;
etisserant@235: 	    break;
etisserant@235:         }
etisserant@235: 	status = state5;
etisserant@236:       /* If transmission RTR, with data sampled on SYNC */
etisserant@236:       }else if( isSyncEvent && 
etisserant@236:       	  (*pTransmissionType == TRANS_RTR_SYNC)) {
etisserant@236:           if(buildPDO(d, pdoNum, &d->PDO_status[pdoNum].last_message))
etisserant@236:           {
etisserant@236:              MSG_ERR(0x1966, " Couldn't build TPDO number : ", pdoNum);
etisserant@236:              d->PDO_status[pdoNum].transmit_type_parameter &= ~PDO_RTR_SYNC_READY; 
etisserant@236:           }else{
etisserant@236:              d->PDO_status[pdoNum].transmit_type_parameter |= PDO_RTR_SYNC_READY; 
etisserant@236:           }
etisserant@236: 	  status = state11;
etisserant@236: 	  break;
etisserant@235:       /* If transmission on Event and not inhibited, check for changes */
etisserant@236:       }else if((*pTransmissionType == TRANS_EVENT_PROFILE ||
etisserant@235:                *pTransmissionType == TRANS_EVENT_SPECIFIC )&&
etisserant@235:               !(d->PDO_status[pdoNum].transmit_type_parameter & PDO_INHIBITED)) {
etisserant@236: 	MSG_WAR(0x3968, "  PDO is on EVENT. Trans type : ", *pTransmissionType);
leonid@252:  {
leonid@252:  Message msg_init = Message_Initializer;
leonid@252:  pdo = msg_init;
leonid@252:  }	
etisserant@235:         if(buildPDO(d, pdoNum, &pdo))
etisserant@235:         {
etisserant@236:             MSG_ERR(0x3907, " Couldn't build TPDO number : ", pdoNum);
etisserant@235: 	    status = state11;
etisserant@235: 	    break;
etisserant@235:         }
etisserant@235:         
etisserant@235: 	/*Compare new and old PDO*/
etisserant@365: 	if(d->PDO_status[pdoNum].last_message.cob_id == pdo.cob_id &&
etisserant@235: 	   d->PDO_status[pdoNum].last_message.len == pdo.len &&
etisserant@315: #ifdef UNS64
etisserant@235: 	   *(UNS64*)(&d->PDO_status[pdoNum].last_message.data[0]) == *(UNS64*)(&pdo.data[0])){
etisserant@315: #else /* don't ALLOW_64BIT_OPS*/
etisserant@315:        *(UNS32*)(&d->PDO_status[pdoNum].last_message.data[0]) == *(UNS32*)(&pdo.data[0]) &&
etisserant@315:        *(UNS32*)(&d->PDO_status[pdoNum].last_message.data[4]) == *(UNS32*)(&pdo.data[4])){
etisserant@315: #endif 
etisserant@235: 	   	/* No changes -> go to next pdo*/
etisserant@235: 		status = state11;
etisserant@235: 	}else{
luis@298: 		
luis@298: 		UNS16 EventTimerDuration;
luis@298:         UNS16 InhibitTimerDuration;
luis@298: 		
etisserant@236: 		MSG_WAR(0x306A, "Changes TPDO number : ", pdoNum);
etisserant@235: 		/* Changes detected -> transmit message */
luis@298:         EventTimerDuration = *(UNS16*)d->objdict[offsetObjdict].pSubindex[5].pObject;
luis@298:         InhibitTimerDuration = *(UNS16*)d->objdict[offsetObjdict].pSubindex[3].pObject;
etisserant@297:         
etisserant@235: 		status = state5;
etisserant@235: 		
etisserant@235: 		/* Start both event_timer and inhibit_timer*/
etisserant@297:         if(EventTimerDuration){
etisserant@297:            DelAlarm(d->PDO_status[pdoNum].event_timer);
etisserant@297:            d->PDO_status[pdoNum].event_timer = SetAlarm(d, pdoNum, &PDOEventTimerAlarm, MS_TO_TIMEVAL(EventTimerDuration), 0);
etisserant@297:         }
etisserant@235: 		
etisserant@297:         if(InhibitTimerDuration){
etisserant@297: 		   DelAlarm(d->PDO_status[pdoNum].inhibit_timer);
etisserant@297: 		   d->PDO_status[pdoNum].inhibit_timer = SetAlarm(d, pdoNum, &PDOInhibitTimerAlarm, US_TO_TIMEVAL(InhibitTimerDuration * 100), 0);
etisserant@297:            /* and inhibit TPDO */
etisserant@297:            d->PDO_status[pdoNum].transmit_type_parameter |= PDO_INHIBITED;
etisserant@297:         }
etisserant@235: 		
etisserant@235: 	}
etisserant@235:       }else{
etisserant@236: 	MSG_WAR(0x306C, "  PDO is not on EVENT or synchro or not at this SYNC. Trans type : ", *pTransmissionType);
etisserant@235: 	status = state11;
etisserant@235:       }      
etisserant@235:         break;
etisserant@235:     case state5: /*Send the pdo*/
etisserant@235: 	/*store_as_last_message*/
etisserant@235: 	d->PDO_status[pdoNum].last_message = pdo;	
etisserant@365: 	MSG_WAR(0x396D, "sendPDO cobId :", pdo.cob_id);
etisserant@236: 	MSG_WAR(0x396E,  "     Nb octets  : ",  pdo.len);
etisserant@235:     	
etisserant@235:     	canSend(d->canHandle,&pdo);
etisserant@235: 	status = state11;
etisserant@235: 	break;     
etisserant@235:     case state11: /*Go to next TPDO*/     
etisserant@235: 	pdoNum++;
etisserant@235: 	offsetObjdict++;
etisserant@235: 	offsetObjdictMap++;
etisserant@236: 	MSG_WAR(0x3970, "next pdo index : ", pdoNum);
etisserant@235: 	status = state3;
etisserant@235: 	break;
etisserant@235:       
etisserant@235:     default:
etisserant@236:       MSG_ERR(0x1972,"Unknown state has been reached : %d",status);
etisserant@235:       return 0xFF;
etisserant@235:     }/* end switch case */
etisserant@235:     
etisserant@235:   }/* end while */
etisserant@235:   }
etisserant@235:   return 0;
etisserant@235: }
etisserant@235: 
etisserant@236: /*!
etisserant@236: **
etisserant@236: **
etisserant@236: ** @param d
etisserant@236: ** @param OD_entry
etisserant@236: ** @param bSubindex 
etisserant@236: ** @return always 0
etisserant@236: **/
etisserant@236: 
etisserant@236: UNS32 TPDO_Communication_Parameter_Callback(CO_Data* d, const indextable * OD_entry, UNS8 bSubindex)
etisserant@236: {
etisserant@236:   /* If PDO are actives */
etisserant@236:   if(d->CurrentCommunicationState.csPDO) switch(bSubindex)
etisserant@236:   {
etisserant@236:   	case 2: /* Changed transmition type */
etisserant@236:   	case 3: /* Changed inhibit time */
etisserant@236:   	case 5: /* Changed event time */
etisserant@236:   	{
etisserant@236:           const indextable* TPDO_com = d->objdict + d->firstIndex->PDO_TRS; 
etisserant@236:           UNS8 numPdo = OD_entry - TPDO_com;       /* number of the actual processed pdo-nr. */
etisserant@236:         
etisserant@236:           /* Zap all timers and inhibit flag */
etisserant@236:           d->PDO_status[numPdo].event_timer = DelAlarm(d->PDO_status[numPdo].event_timer);
etisserant@236:           d->PDO_status[numPdo].inhibit_timer = DelAlarm(d->PDO_status[numPdo].inhibit_timer);
etisserant@236:           d->PDO_status[numPdo].transmit_type_parameter = 0;
etisserant@236:           /* Call  PDOEventTimerAlarm for this TPDO, this will trigger emission et reset timers */
etisserant@236:           PDOEventTimerAlarm(d, numPdo);
etisserant@236:           return 0;
etisserant@236:   	}
etisserant@236: 
etisserant@236:   	default: /* other subindex are ignored*/
etisserant@236:   	break;
etisserant@236:   }
etisserant@236:   return 0;
etisserant@236: }
etisserant@236: 
etisserant@235: void PDOInit(CO_Data* d)
etisserant@235: {
etisserant@236:   /* For each TPDO mapping parameters */
etisserant@236:   UNS16	pdoIndex = 0x1800; /* OD index of TDPO */
etisserant@236: 
etisserant@236:   UNS16 offsetObjdict = d->firstIndex->PDO_TRS;
etisserant@236:   UNS16 lastIndex = d->lastIndex->PDO_TRS;
etisserant@236:   if(offsetObjdict) while( offsetObjdict <= lastIndex) {
etisserant@236:     /* Assign callbacks to sensible TPDO mapping subindexes */
etisserant@236:     UNS32 errorCode;
etisserant@236:     ODCallback_t *CallbackList;
etisserant@236:     /* Find callback list */
etisserant@236:     scanIndexOD (d, pdoIndex, &errorCode, &CallbackList);
etisserant@236:     if(errorCode == OD_SUCCESSFUL && CallbackList)
etisserant@236:     {
etisserant@236:       /*Assign callbacks to corresponding subindex*/
etisserant@236:       /* Transmission type */
etisserant@236:       CallbackList[2] = &TPDO_Communication_Parameter_Callback;
etisserant@236:       /* Inhibit time */
etisserant@236:       CallbackList[3] = &TPDO_Communication_Parameter_Callback;
etisserant@236:       /* Event timer */
etisserant@236:       CallbackList[5] = &TPDO_Communication_Parameter_Callback;
etisserant@236:     }
etisserant@236:     pdoIndex++;
etisserant@236:     offsetObjdict++;
etisserant@236:   }  
etisserant@236: 
etisserant@236:   /* Trigger a non-sync event */
etisserant@236:   _sendPDOevent( d, 0 );
etisserant@235: }
etisserant@235: 
etisserant@235: void PDOStop(CO_Data* d)
etisserant@235: {
etisserant@236:   /* For each TPDO mapping parameters */
etisserant@235:   UNS8 	pdoNum = 0x00;       /* number of the actual processed pdo-nr. */
etisserant@235:   UNS16 offsetObjdict = d->firstIndex->PDO_TRS;
etisserant@235:   UNS16 lastIndex = d->lastIndex->PDO_TRS;
etisserant@235:   if(offsetObjdict) while( offsetObjdict <= lastIndex) {
etisserant@236:   	/* Delete TPDO timers */
etisserant@235: 	d->PDO_status[pdoNum].event_timer = DelAlarm(d->PDO_status[pdoNum].event_timer);
etisserant@235: 	d->PDO_status[pdoNum].inhibit_timer = DelAlarm(d->PDO_status[pdoNum].inhibit_timer);
etisserant@236: 	/* Reset transmit type parameter */
etisserant@235: 	d->PDO_status[pdoNum].transmit_type_parameter = 0;
etisserant@365: 	d->PDO_status[pdoNum].last_message.cob_id = 0;
etisserant@235: 	pdoNum++;
etisserant@235: 	offsetObjdict++;
etisserant@235:   }  
etisserant@235: }