
#ifndef __MTCOMM_H__
#define __MTCOMM_H__

#include "config.h"
//------------------------------------------------------------------------


/*
	闭环电机的通讯控制接口
// 协议：
	通过485通讯，总线上可以挂在多个闭环步进电机。

	485串行通讯
	波特率： 115200 bps
	数据帧: 1个起始位，8个数据位，1个停止位，没有校验位。
	8个数据位是通讯的有效数据内容（1个字节）。
	多个数据帧构成一个数据包
	按照固定的8个字节组成一个数据包。

	|---------------------------------------------------------------------------------------|
	|	  B0		| 		B1	 	|	  B2	|   B3	|  B4	|  B5	|  B6	|	  B7	|
	|---------------|---------------|-----------|-------------------------------|-----------|
	|	数据包头		|	目标站号		|	命令		|			数据内容				|	校验字	|
	|---------------|---------------|-----------|-------------------------------|-----------|
	|	固定字节		|	目标站号		|	命令		|			数据内容				|	校验字	|
	|				|				|			|-------------------------------|-----------|
	|				|	0 主站		|			|								|  B1--B6的	|
	|	0xEB		|	1--250 从站	|	1--255	|	4个字节，内容根据命令来定义			|  8位CRC校验	|
	|				|	255 广播		|			|								|			|
	|				|	251--254 保留	|			|								| 			|
	|---------------|---------------|-----------|-------------------------------|-----------|
	|				|				|			|								|			|
	|---------------------------------------------------------------------------------------|

	数据包按照从B0--B7的顺序传输，网络上的通讯以数据包为单位。


传输流程
	默认情况下，如果没有通讯发生，主站处于发送状态，从站处于接收状态。

	如果是有回包的通讯，通讯的过程描述如下：

	主站：
		1.设置为发送状态，给某个站点或全部站点发送命令。
		2.发送完成后，设置为接收状态。
		3.等待回包，如果10ms内没有收到回包，则认为通讯超时。
		4.返回步骤1

	从站：
		1.设置为接收状态，等待主站命令。
		2.接收到新命令后，等待1ms。
		3.设置为发送状态，发送回包给主站，。
		4.等待发送完成后，转到步骤1

	如果没有回包，则主站发送，不需要切换为接收状态。
	从站接收到数据后，只执行响应，不再切换为发送状态

*/


//------------------------------------

#define	MT_SYNC_LEN		1		// 数据识别序列长度
#define	MT_ADDR_LEN		1		// 地址长度
#define	MT_CMD_LEN		1		// 命令长度
#define	MT_CONT_LEN		4		// 数据内容长度
#define	MT_CHK_LEN		1		// 校验字长度

#define	MT_CHECK_LEN		(MT_ADDR_LEN+MT_CMD_LEN+MT_CONT_LEN)
#define	LEN_MTCOMM_PKT		(MT_SYNC_LEN+MT_ADDR_LEN+MT_CMD_LEN+MT_CONT_LEN+MT_CHK_LEN)

//------------------------------------

#ifdef _IN_MTCOMM_C

const u8 MTCOMM_SYNC[MT_SYNC_LEN] =
{
	0xEB,
};

#endif


//------------------------------------
// 数据结构

typedef struct
{
	u8 sync[MT_SYNC_LEN];
	//--------
	u8 addr;
	u8 cmd;
	//-----
	u8 content[MT_CONT_LEN];
	//--------
	u8 crc8;
} __attribute__ ((packed)) MtCommPacket;


//------------------------------------

#define MTTS_ADDR_MAIN			0		// 主站地址
#define MTTS_ADDR_BROADCAST		0xFF	// 广播地址

//------------------------------------

// 命令定义

// 主站到从站
#define MTCMD_ADDR_INIT		0x01	// 站号初始化
#define MTCMD_SET_NEW_AD	0x02	// 设置新站号
#define MTCMD_GET_INFO		0x03	// 查询从站信息
#define MTCMD_READ_DATA		0x04	// 读取数据
#define MTCMD_WRITE_DATA	0x05	// 设置数据

// 从站到主站
#define MTCMD_REV_INFO		0x83	// 查询从站信息命令的回包
#define MTCMD_REV_DATA		0x84	// 读取数据命令的回包

//------------------------------------------------------

#define	MTCOMM_NONE		0
#define MTCOMM_MASTER	1	// 主节点
#define MTCOMM_SLAVE	2	// 从节点

// 节点配置
#ifndef	MTCOMM_AS
#define	MTCOMM_AS		MTCOMM_NONE
#endif

#if	(MTCOMM_AS != MTCOMM_NONE && MTCOMM_AS != MTCOMM_MASTER && MTCOMM_AS != MTCOMM_SLAVE)
#undef MTCOMM_AS
#define	MTCOMM_AS		MTCOMM_NONE
#endif


//------------------------------------------------------

// 通讯函数
typedef struct
{
	int (*SendMtCommData)(u8 *, int);	// 发送数据函数
	int (*GetMtCommData)(u8 *, int);	// 接收数据函数
	int (*GetMtRsvLen)(void);			// 得到已接收数据长度函数
	int (*GetTrsFreeLen)(void);			// 得到发送数据缓冲区长度函数
	void (*Set485TxEnOn)(void);			// 发送允许打开函数
	void (*Set485TxEnOff)(void);		// 发送允许关闭函数
}MtCommExFuncs;

//------------------------------------------------------

// 初始化
// 注册收发函数和485开关函数
void InitMtComm(MtCommExFuncs * pExFuncs);

// 异步收发过程,完成数据的收发过程。
// 需要在控制流程中不停调用
void MtCommAsyncTask(void);

// 打包命令
// 添加同步字，生成CRC
int PacketAMtComm(MtCommPacket * pPacket);

// 校验一个数据包
// 验证同步字和CRC
int CheckAMtPacket(MtCommPacket * pPacket);

// 启动一次发送任务
// 返回传输ID
int SendAMtPacket(MtCommPacket * pPacket, int hasback);

// 获取发送状态
int GetSendStatus(int id);
// 获取发送结果
int GetSendResult(int id);

// 读取一个数据包
// 如果接收到, 数据在pPacket中
int GetAMtPacket(MtCommPacket * pPacket);




#endif
