欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

canfestival——从机发送PDO报文

程序员文章站 2022-07-14 09:05:38
...

1、PDO基本介绍

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

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

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

 canfestival——从机发送PDO报文

 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报文

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

/* 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报文

 

相关标签: canopen