OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 4735|回复: 3

有移植过canfestival的朋友,进来救个急

[复制链接]

1

主题

2

帖子

0

精华

新手入门

积分
13
金钱
13
注册时间
2019-7-20
在线时间
2 小时
发表于 2019-8-20 17:51:17 | 显示全部楼层 |阅读模式
1金钱
本人最近在研究canfestvial协议,已经移植完成了,但是在做主机NMT心跳功能的时候有几点疑问,利用字典编辑器创建了一个主站,在index引索值为1016h里面编辑了消费者心跳时间(0x3E8=1000MS)和条目数量(默认1,改不了),然后拷贝到程序开始调试,按照我的理解,主机上电后初始化完,会按1016h里面的时间来定时查询,查询的回调是这个函数:void ConsumerHeartbeatAlarm(CO_Data* d, UNS32 id),但是这个回调的第一条语句就是这个 UNS8 nodeId = (UNS8)(((d->ConsumerHeartbeatEntries[id]) & (UNS32)0x00FF0000) >> (UNS8)16); 获取节点ID,而d->ConsumerHeartbeatEntries[id]的值是索引到字典里面的消费者心跳时间,也就是1000,所以这个ConsumerHeartBeat_nodeId的值就一直是0,那问题来了,主机NMT节点维护机制是如何知道自己要查询哪个节点的?也就是说,如果我有个从机节点ID是0x01,有个从机的节点ID是0x02,那主机是如何知道闹钟溢出后 该查哪个节点的状态呢?

if( d->NMTable[nodeId] != Unknown_state ) {
        UNS8 index, ConsumerHeartBeat_nodeId ;
        for( index = (UNS8)0x00; index < *d->ConsumerHeartbeatCount; index++ )
          {
            ConsumerHeartBeat_nodeId = (UNS8)( ((d->ConsumerHeartbeatEntries[index]) & (UNS32)0x00FF0000) >> (UNS8)16 );
            if ( nodeId == ConsumerHeartBeat_nodeId )
              {                                                               
                TIMEVAL time = ( (d->ConsumerHeartbeatEntries[index]) & (UNS32)0x0000FFFF ) ;
                /* Renew alarm for next heartbeat. */
                DelAlarm(d->ConsumerHeartBeatTimers[index]);
                d->ConsumerHeartBeatTimers[index] = SetAlarm(d, index, &ConsumerHeartbeatAlarm, MS_TO_TIMEVAL(time), 0);
              }
          }
      }

这一段代码是主机的这个void proceedNODE_GUARD(CO_Data* d, Message* m )函数里面的,nodeId的值是根据接收到心跳报文的值,我试了一下从机发送心跳报文的时候可以跳到这里来,这个nodeId值倒是对的,但是 ConsumerHeartBeat_nodeId = (UNS8)( ((d->ConsumerHeartbeatEntries[index]) & (UNS32)0x00FF0000) >> (UNS8)16 );这个ConsumerHeartBeat_nodeId一直是0, if ( nodeId == ConsumerHeartBeat_nodeId )这句话一直进不去,也就是更新不了下一次的维护周期了。

void ConsumerHeartbeatAlarm(CO_Data* d, UNS32 id)
{
  UNS8 nodeId = (UNS8)(((d->ConsumerHeartbeatEntries[id]) & (UNS32)0x00FF0000) >> (UNS8)16);
  /*MSG_WAR(0x00, "ConsumerHearbeatAlarm", 0x00);*/

  /* timer have been notified and is now free (non periodic)*/
  /* -> avoid deleting re-assigned timer if message is received too late*/
  d->ConsumerHeartBeatTimers[id]=TIMER_NONE;

  /* set node state */
  d->NMTable[nodeId] = Disconnected;
  /*! call heartbeat error with NodeId */
  (*d->heartbeatError)(d, nodeId);
}

这个是主机心跳计时溢出回调,这个nodeId一直是0,如果发生错误,根本就不知道是哪个节点心跳出错了呀,刚刚接触,有说错的地方,希望包涵,欢迎纠正,需要源码的可以留言,到时候我再上传一下。
还有,下面这段代码是检测到上线报文的处理
  /* Boot-Up frame reception */
      if ( d->NMTable[nodeId] == Initialisation)
      {
          /*
          ** The device send the boot-up message (Initialisation)
          ** to indicate the master that it is entered in
          ** pre_operational mode
          */
          MSG_WAR(0x3100, "The NMT is a bootup from node : ", nodeId);
          /* call post SlaveBootup with NodeId */
                  (*d->post_SlaveBootup)(d, nodeId);
      }

处理函数得自己实现,从机上线的时候会发送上线报文,在这里可以记录一下上线的从机数量和从机节点,问题是每次到到更新下次的检查周期和出错的时候,都会调用这条语句(UNS8)( ((d->ConsumerHeartbeatEntries[index]) & (UNS32)0x00FF0000) >> (UNS8)16 );然后就懵了,难道是主机检测到从机的上线报文后,动态更改对象字典生成的值?那这样这个对象字典毫无意义啊,求大佬指点一下,感激不尽

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

558

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
164897
金钱
164897
注册时间
2010-12-1
在线时间
2100 小时
发表于 2019-8-21 02:29:33 | 显示全部楼层
回复

使用道具 举报

1

主题

2

帖子

0

精华

新手入门

积分
13
金钱
13
注册时间
2019-7-20
在线时间
2 小时
 楼主| 发表于 2019-8-21 09:29:04 | 显示全部楼层
谢谢原子哥,请问你们有canfestival的例程吗?
回复

使用道具 举报

558

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
164897
金钱
164897
注册时间
2010-12-1
在线时间
2100 小时
发表于 2019-8-22 02:49:59 | 显示全部楼层
没有明天 发表于 2019-8-21 09:29
谢谢原子哥,请问你们有canfestival的例程吗?

没有哦
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-6-9 09:30

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表