canfestival_中的协议栈的状态机

这里,单片机侧实现的是主站,主节点的状体如下面代码中的几种:

/* The nodes states 
 * -----------------
 * values are choosen so, that they can be sent directly
 * for heartbeat messages...
 * Must be coded on 7 bits only
 * */
/* Should not be modified */
enum enum_nodeState {
  Initialisation  = 0x00, 
  Disconnected    = 0x01,
  Connecting      = 0x02,
  Preparing       = 0x02,
  Stopped         = 0x04,
  Operational     = 0x05,
  Pre_operational = 0x7F,
  Unknown_state   = 0x0F
};

typedef enum enum_nodeState e_nodeState;
  • Initialisation
  • Disconnected
  • Connecting
  • Preparing
  • Stopped
  • Operational
  • Pre_operational
  • Unknow_state

主机的初始状态是Unknow_state,我们需要在初始化节点时进行设置节点的状态为initialisation,

这时候主站的会自动切换到预操作状态,这个时候主站的各个通信服务的功能才打开。

下面时通信状态的代码,

typedef struct
{
    INTEGER8 csBoot_Up;//current state
    INTEGER8 csSDO;
    INTEGER8 csEmergency;
    INTEGER8 csSYNC;
    INTEGER8 csHeartbeat;
    INTEGER8 csPDO;
    INTEGER8 csLSS;
} s_state_communication;
 

下面时显示调用主站设备为初始化的代码如下:

/***************************  INIT  *****************************************/
void InitNodes(CO_Data* d, UNS32 id)
{
	/****************************** INITIALISATION MASTER *******************************/
	if(strcmp(MasterBoard.baudrate, "none"))
	{
		/* init */
		setState(&TestMaster_Data, Initialisation);
	}
}

这里把主站节点的状态设置为初始化状态,然后自动切换到预操作状态;

在预操作状态下,打开了多种的通信功能,代码如下:

UNS8 setState(CO_Data* d, e_nodeState newState)
{
	if(newState != d->nodeState){
		switch( newState ){
			case Initialisation:
			{
				s_state_communication newCommunicationState = {1, 0, 0, 0, 0, 0, 0};
				d->nodeState = Initialisation;
				switchCommunicationState(d, &newCommunicationState);
				/* call user app init callback now. */
				/* d->initialisation MUST NOT CALL SetState */
				(*d->initialisation)(d);	// 2023-01-06 调用主站节点的初始化的回调函数				
			}

			/* Automatic transition - No break statement ! */
			/* Transition from Initialisation to Pre_operational */
			/* is automatic as defined in DS301. */
            // 这里没有break,会自动执行下面的代码,说明状态自行切换到预操作状态
								
			case Pre_operational:
			{
				s_state_communication newCommunicationState = {0, 1, 1, 1, 1, 0, 1};
				d->nodeState = Pre_operational;
				switchCommunicationState(d, &newCommunicationState);
				if (!(*(d->iam_a_slave)))
				{
					masterSendNMTstateChange (d, 0, NMT_Reset_Node);
				}
        		(*d->preOperational)(d);
			}
			break;
								
			case Operational:
			if(d->nodeState == Initialisation) return 0xFF;
			{
				s_state_communication newCommunicationState = {0, 1, 1, 1, 1, 1, 0};
				d->nodeState = Operational;
				newState = Operational;
				switchCommunicationState(d, &newCommunicationState);
				(*d->operational)(d);
			}
			break;
						
			case Stopped:
			if(d->nodeState == Initialisation) return 0xFF;
			{
				s_state_communication newCommunicationState = {0, 0, 0, 0, 1, 0, 1};
				d->nodeState = Stopped;
				newState = Stopped;
				switchCommunicationState(d, &newCommunicationState);
				(*d->stopped)(d);
			}
			break;
			default:
				return 0xFF;

		}/* end switch case */
	
	}
	/* d->nodeState contains the final state */
	/* may not be the requested state */
    return d->nodeState;  
}

 下面是主站设备进行通信状态切换实现的代码:

#define StartOrStop(CommType, FuncStart, FuncStop) \
	if(newCommunicationState->CommType && d->CurrentCommunicationState.CommType == 0){\
		MSG_WAR(0x9999,#FuncStart, 9999);\
		d->CurrentCommunicationState.CommType = 1;\
		FuncStart;\
	}else if(!newCommunicationState->CommType && d->CurrentCommunicationState.CommType == 1){\
		MSG_WAR(0x9999,#FuncStop, 9999);\
		d->CurrentCommunicationState.CommType = 0;\
		FuncStop;\
	}
#define None

/*!                                                                                                
**                                                                                                 
**                                                                                                 
** @param d                                                                                        
** @param newCommunicationState                                                                    
**/  	
void switchCommunicationState(CO_Data* d, s_state_communication *newCommunicationState)
{
#ifdef CO_ENABLE_LSS
	StartOrStop(csLSS,	startLSS(d),	stopLSS(d))
#endif
	StartOrStop(csSDO,	None,		resetSDO(d))
	StartOrStop(csSYNC,	startSYNC(d),		stopSYNC(d))
	StartOrStop(csHeartbeat,	heartbeatInit(d),	heartbeatStop(d))
	StartOrStop(csEmergency,	emergencyInit(d),	emergencyStop(d)) 
	StartOrStop(csPDO,	PDOInit(d),	PDOStop(d))
	StartOrStop(csBoot_Up,	None,	slaveSendBootUp(d))
}
// 状态有变化才执行相对应的函数;
// 0变1,执行开始函数
// 1变0,执行停止函数

在设置主设备为初始化状态的时候的函数调用:

StartOrStop(csBoot_Up, None, slaveSendBootUp(d))

中的Start,即None,说明没有函数被执行;

然后进入预操作状态,执行的函数顺序为:

startSYNC()

heartbeatInit()

emergencyInit()

slaveSendBootUp()

协议栈运行到这里,除了PDO不能正常外,其他的都可以正常工作了;

下图是打印的log:

需要等到主站配置完成从站设备节点后,需要显示调用函数来切换主站到操作状态,这时候就可以进行PDO的数据通信了。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值