canfestival——从机发送PDO报文

1、PDO基本介绍

PDO(过程数据对象)用来传输实时数据,PDO分两种,一种是TPDO(发送的),一种是RPDO(接收的)。

触发模式:事件和定时器、远程请求、同步触发。

 如下图所示,TPDO1在OD中索引为1800,此处写通讯参数。canfestival——从机发送PDO报文_第1张图片

 canfestival——从机发送PDO报文_第2张图片

 TPDO 的通讯参数存放在 1800h to 19FFh ,映射参数存放在 1A00h to 1BFFh 

 网上下载一本电子书:canopen轻松入门(周立功)

 

2、PDO通讯参数

Transmission_Type:传输类型

Inhibit_Time:抑制时间,由于PDO的优先级较高,必要时需要抑制

Event_Timer:周期时间

SYNC_start_value:同步起始值

要修改的源程序位置如下: 

/* index 0x1800 :   Transmit PDO 1 Parameter. */
                    UNS8 EwtCanAnalysis_highestSubIndex_obj1800 = 6; /* number of subindex - 1*/
                    UNS32 EwtCanAnalysis_obj1800_COB_ID_used_by_PDO = 0x180;	/* 384 */
                    UNS8 EwtCanAnalysis_obj1800_Transmission_Type = 0x0;	/* 0 */
                    UNS16 EwtCanAnalysis_obj1800_Inhibit_Time = 0x0;	/* 0 */
                    UNS8 EwtCanAnalysis_obj1800_Compatibility_Entry = 0x0;	/* 0 */
                    UNS16 EwtCanAnalysis_obj1800_Event_Timer = 0x0;	/* 0 */
                    UNS8 EwtCanAnalysis_obj1800_SYNC_start_value = 0x0;	/* 0 */
                    ODCallback_t EwtCanAnalysis_Index1800_callbacks[] = 
                     {
                       NULL,
                       NULL,
                       NULL,
                       NULL,
                       NULL,
                       NULL,
                       NULL,
                     };
                    subindex EwtCanAnalysis_Index1800[] = 
                     {
                       { RO, uint8, sizeof (UNS8), 
                       (void*)&EwtCanAnalysis_highestSubIndex_obj1800 },
                       { RW, uint32, sizeof (UNS32), 
                       (void*)&EwtCanAnalysis_obj1800_COB_ID_used_by_PDO },
                       { RW, uint8, sizeof (UNS8), 
                       (void*)&EwtCanAnalysis_obj1800_Transmission_Type },
                       { RW, uint16, sizeof (UNS16), 
                       (void*)&EwtCanAnalysis_obj1800_Inhibit_Time },
                       { RW, uint8, sizeof (UNS8), 
                       (void*)&EwtCanAnalysis_obj1800_Compatibility_Entry },
                       { RW, uint16, sizeof (UNS16), 
                       (void*)&EwtCanAnalysis_obj1800_Event_Timer },
                       { RW, uint8, sizeof (UNS8), 
                       (void*)&EwtCanAnalysis_obj1800_SYNC_start_value }
                     };

 

3、PDO映射参数

 映射的数据分解

31-16位:索引

15-8位:子索引

7-0位:长度

例如将其分解:0x20000008

canfestival——从机发送PDO报文_第3张图片

 要修改的源程序位置如下:

/* index 0x1A00 :   Transmit PDO 1 Mapping. */
                    UNS8 EwtCanAnalysis_highestSubIndex_obj1A00 = 8; /* number of subindex - 1*/
                    UNS32 EwtCanAnalysis_obj1A00[] = 
                    {
                      0x0,	/* 0 */
                      0x0,	/* 0 */
                      0x0,	/* 0 */
                      0x0,	/* 0 */
                      0x0,	/* 0 */
                      0x0,	/* 0 */
                      0x0,	/* 0 */
                      0x0	/* 0 */
                    };
                    subindex EwtCanAnalysis_Index1A00[] = 
                     {
                       { RW, uint8, sizeof (UNS8), 
                       (void*)&EwtCanAnalysis_highestSubIndex_obj1A00 },
                       { RW, uint32, sizeof (UNS32), (void*)&EwtCanAnalysis_obj1A00[0] },
                       { RW, uint32, sizeof (UNS32), (void*)&EwtCanAnalysis_obj1A00[1] },
                       { RW, uint32, sizeof (UNS32), (void*)&EwtCanAnalysis_obj1A00[2] },
                       { RW, uint32, sizeof (UNS32), (void*)&EwtCanAnalysis_obj1A00[3] },
                       { RW, uint32, sizeof (UNS32), (void*)&EwtCanAnalysis_obj1A00[4] },
                       { RW, uint32, sizeof (UNS32), (void*)&EwtCanAnalysis_obj1A00[5] },
                       { RW, uint32, sizeof (UNS32), (void*)&EwtCanAnalysis_obj1A00[6] },
                       { RW, uint32, sizeof (UNS32), (void*)&EwtCanAnalysis_obj1A00[7] }
                     };

 

4、从机发送PDO的应用

 _sendPDOevent():启动所有需要触发的PDO事件

  pTransmissionType:触发方式

isSyncEvent:同步触发

state5:发送报文

state11:下一个

 if (offsetObjdict):通讯参数被设置

/*!
**
**
** @param d
** @param isSyncEvent
**
** @return
**/

UNS8
_sendPDOevent (CO_Data * d, UNS8 isSyncEvent)
{
  UNS8 pdoNum = 0x00;           /* number of the actual processed pdo-nr. */
  UNS8 *pTransmissionType = NULL;
  UNS8 status = state3;
  UNS16 offsetObjdict = d->firstIndex->PDO_TRS;
  UNS16 offsetObjdictMap = d->firstIndex->PDO_TRS_MAP;
  UNS16 lastIndex = d->lastIndex->PDO_TRS;

  if (!d->CurrentCommunicationState.csPDO)
    {
      return 0;
    }


  /* study all PDO stored in the objects dictionary */
  if (offsetObjdict)
    {
      Message pdo;/* = Message_Initializer;*/
      memset(&pdo, 0, sizeof(pdo));
      while (offsetObjdict <= lastIndex)
        {
          switch (status)
            {
            case state3:
              if ( /* bSubCount always 5 with objdictedit -> check disabled */
                   /*d->objdict[offsetObjdict].bSubCount < 5 ||*/
                   /* check if TPDO is not valid */
                   *(UNS32 *) d->objdict[offsetObjdict].pSubindex[1].pObject & 0x80000000)
                {
                  MSG_WAR (0x3960, "Not a valid PDO ", 0x1800 + pdoNum);
                  /*Go next TPDO */
                  status = state11;
                  break;
                }
              /* get the PDO transmission type */
              pTransmissionType =
                (UNS8 *) d->objdict[offsetObjdict].pSubindex[2].pObject;
              MSG_WAR (0x3962, "Reading PDO at index : ", 0x1800 + pdoNum);

              /* check if transmission type is SYNCRONOUS */
              /* message transmited every n SYNC with n=TransmissionType */
              if (isSyncEvent &&
                  (*pTransmissionType >= TRANS_SYNC_MIN) &&
                  (*pTransmissionType <= TRANS_SYNC_MAX) &&
                  (++d->PDO_status[pdoNum].transmit_type_parameter ==
                   *pTransmissionType))
                {
                  /*Reset count of SYNC */
                  d->PDO_status[pdoNum].transmit_type_parameter = 0;
                  MSG_WAR (0x3964, "  PDO is on SYNCHRO. Trans type : ",
                           *pTransmissionType);
                  memset(&pdo, 0, sizeof(pdo));
                  /*{
                    Message msg_init = Message_Initializer;
                    pdo = msg_init;
                  }*/
                  if (buildPDO (d, pdoNum, &pdo))
                    {
                      MSG_ERR (0x1906, " Couldn't build TPDO number : ",
                               pdoNum);
                      status = state11;
                      break;
                    }
                  status = state5;
                  /* If transmission RTR, with data sampled on SYNC */
                }
              else if (isSyncEvent && (*pTransmissionType == TRANS_RTR_SYNC))
                {
                  if (buildPDO
                      (d, pdoNum, &d->PDO_status[pdoNum].last_message))
                    {
                      MSG_ERR (0x1966, " Couldn't build TPDO number : ",
                               pdoNum);
                      d->PDO_status[pdoNum].transmit_type_parameter &=
                        ~PDO_RTR_SYNC_READY;
                    }
                  else
                    {
                      d->PDO_status[pdoNum].transmit_type_parameter |=
                        PDO_RTR_SYNC_READY;
                    }
                  status = state11;
                  break;
                  /* If transmission on Event and not inhibited, check for changes */
                }
              else
                if ( (isSyncEvent && (*pTransmissionType == TRANS_SYNC_ACYCLIC))
                     ||
                     (!isSyncEvent && (*pTransmissionType == TRANS_EVENT_PROFILE || *pTransmissionType == TRANS_EVENT_SPECIFIC)
                       && !(d->PDO_status[pdoNum].transmit_type_parameter & PDO_INHIBITED)))
                {
                  sendOnePDOevent(d, pdoNum);
                  status = state11;
                }
              else
                {
                  MSG_WAR (0x306C,
                           "  PDO is not on EVENT or synchro or not at this SYNC. Trans type : ",
                           *pTransmissionType);
                  status = state11;
                }
              break;
            case state5:       /*Send the pdo */
              sendPdo(d, pdoNum, &pdo);
              status = state11;
              break;
            case state11:      /*Go to next TPDO */
              pdoNum++;
              offsetObjdict++;
              offsetObjdictMap++;
              MSG_WAR (0x3970, "next pdo index : ", pdoNum);
              status = state3;
              break;

            default:
              MSG_ERR (0x1972, "Unknown state has been reached :", status);
              return 0xFF;
            }                   /* end switch case */

        }                       /* end while */
    }
  return 0;
}

 buildPDO:构建PDO

pdo->cob_id:ID

pdo->rtr:数据帧

index:索引

subIndex:子索引

getODentry (d, index, subIndex, tmp, &ByteSize, &dataType, 0)

UNS8 buildPDO (CO_Data * d, UNS8 numPdo, Message * pdo)
{
  const indextable *TPDO_com = d->objdict + d->firstIndex->PDO_TRS + numPdo;
  const indextable *TPDO_map = d->objdict + d->firstIndex->PDO_TRS_MAP + numPdo;

  UNS8 prp_j = 0x00;
  UNS32 offset = 0x00000000;
  const UNS8 *pMappingCount = (UNS8 *) TPDO_map->pSubindex[0].pObject;

  pdo->cob_id = (UNS16) UNS16_LE(*(UNS32*)TPDO_com->pSubindex[1].pObject & 0x7FF);
  pdo->rtr = NOT_A_REQUEST;

  MSG_WAR (0x3009, "  PDO CobId is : ",
           *(UNS32 *) TPDO_com->pSubindex[1].pObject);
  MSG_WAR (0x300D, "  Number of objects mapped : ", *pMappingCount);

  do
    {
      UNS8 dataType;            /* Unused */
      UNS8 tmp[] = { 0, 0, 0, 0, 0, 0, 0, 0 };  /* temporary space to hold bits */

      /* pointer fo the var which holds the mapping parameter of an mapping entry  */
      UNS32 *pMappingParameter =
        (UNS32 *) TPDO_map->pSubindex[prp_j + 1].pObject;
      UNS16 index = (UNS16) ((*pMappingParameter) >> 16);
      UNS32 Size = (UNS32) (*pMappingParameter & (UNS32) 0x000000FF);     /* Size in bits */

      /* get variable only if Size != 0 and Size is lower than remaining bits in the PDO */
      if (Size && ((offset + Size) <= 64))
        {
          UNS32 ByteSize = 1 + ((Size - 1) >> 3);        /*1->8 => 1 ; 9->16 => 2, ... */
          UNS8 subIndex =
            (UNS8) (((*pMappingParameter) >> (UNS8) 8) & (UNS32) 0x000000FF);

          MSG_WAR (0x300F, "  got mapping parameter : ", *pMappingParameter);
          MSG_WAR (0x3050, "    at index : ", TPDO_map->index);
          MSG_WAR (0x3051, "    sub-index : ", prp_j + 1);

          if (getODentry (d, index, subIndex, tmp, &ByteSize, &dataType, 0) !=
              OD_SUCCESSFUL)
            {
              MSG_ERR (0x1013,
                       " Couldn't find mapped variable at index-subindex-size : ",
                       (UNS32) (*pMappingParameter));
              return 0xFF;
            }
          /* copy bit per bit in little endian */
          CopyBits ((UNS8) Size, ((UNS8 *) tmp), 0, 0,
                    (UNS8 *) & pdo->data[offset >> 3], (UNS8)(offset % 8), 0);

          offset += Size;
        }
      prp_j++;
    }
  while (prp_j < *pMappingCount);

  pdo->len = (UNS8)(1 + ((offset - 1) >> 3));

  MSG_WAR (0x3015, "  End scan mapped variable", 0);

  return 0;
}

 

UNS32 _getODentry( CO_Data* d,
                   UNS16 wIndex,
                   UNS8 bSubindex,
                   void * pDestData,
                   UNS32 * pExpectedSize,
                   UNS8 * pDataType,
                   UNS8 checkAccess,
                   UNS8 endianize)
{ /* DO NOT USE MSG_ERR because the macro may send a PDO -> infinite
    loop if it fails. */
  UNS32 errorCode;
  UNS32 szData;
  const indextable *ptrTable;
  ODCallback_t *Callback;

  ptrTable = (*d->scanIndexOD)(wIndex, &errorCode, &Callback);

  if (errorCode != OD_SUCCESSFUL)
    return errorCode;
  if( ptrTable->bSubCount <= bSubindex ) {
    /* Subindex not found */
    accessDictionaryError(wIndex, bSubindex, 0, 0, OD_NO_SUCH_SUBINDEX);
    return OD_NO_SUCH_SUBINDEX;
  }

  if (checkAccess && (ptrTable->pSubindex[bSubindex].bAccessType & WO)) {
    MSG_WAR(0x2B30, "Access Type : ", ptrTable->pSubindex[bSubindex].bAccessType);
    accessDictionaryError(wIndex, bSubindex, 0, 0, OD_READ_NOT_ALLOWED);
    return OD_READ_NOT_ALLOWED;
  }

  if (pDestData == 0) {
    return SDOABT_GENERAL_ERROR;
  }

  if (ptrTable->pSubindex[bSubindex].size > *pExpectedSize) {
    /* Requested variable is too large to fit into a transfer line, inform    *
     * the caller about the real size of the requested variable.              */
    *pExpectedSize = ptrTable->pSubindex[bSubindex].size;
    return SDOABT_OUT_OF_MEMORY;
  }

  *pDataType = ptrTable->pSubindex[bSubindex].bDataType;
  szData = ptrTable->pSubindex[bSubindex].size;

#  ifdef CANOPEN_BIG_ENDIAN
  if(endianize && *pDataType > boolean && !(
         *pDataType >= visible_string &&
         *pDataType <= domain)) {
    /* data must be transmited with low byte first */
    UNS8 i, j = 0;
    MSG_WAR(boolean, "data type ", *pDataType);
    MSG_WAR(visible_string, "data type ", *pDataType);
    for ( i = szData ; i > 0 ; i--) {
      MSG_WAR(i," ", j);
      ((UNS8*)pDestData)[j++] =
        ((UNS8*)ptrTable->pSubindex[bSubindex].pObject)[i-1];
    }
    *pExpectedSize = szData;
  }
  else /* no endianisation change */
#  endif

  if(*pDataType != visible_string) {
      memcpy(pDestData, ptrTable->pSubindex[bSubindex].pObject,szData);
      *pExpectedSize = szData;
  }else{
      /* TODO : CONFORM TO DS-301 :
       *  - stop using NULL terminated strings
       *  - store string size in td_subindex
       * */
      /* Copy null terminated string to user, and return discovered size */
      UNS8 *ptr = (UNS8*)ptrTable->pSubindex[bSubindex].pObject;
      UNS8 *ptr_start = ptr;
      /* *pExpectedSize IS < szData . if null, use szData */
      UNS8 *ptr_end = ptr + (*pExpectedSize ? *pExpectedSize : szData) ;
      UNS8 *ptr_dest = (UNS8*)pDestData;
      while( *ptr && ptr < ptr_end){
          *(ptr_dest++) = *(ptr++);
      }

    *pExpectedSize = (UNS32) (ptr - ptr_start);
    /* terminate string if not maximum length */
    if (*pExpectedSize < szData)
            *(ptr) = 0;
  }

  return OD_SUCCESSFUL;
}

从机使用TPDO1发送数值1到主机 

700:上文中的心跳包

 canfestival——从机发送PDO报文_第4张图片

 

你可能感兴趣的:(canopen)