
#ifndef __MODBUS_DEF_H__
#define	__MODBUS_DEF_H__

#include "config.h"
#include "serial.h"

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

// modbus 协议定义
/*

*/

//------------------------------------------------------------------
/*modbus地址规则,支持的寻址空间为256个
 * ----------------------------------
 * |	0	|	1-247  |	248-255	|
 * |---------------------------------
 * |广播地址|子节点地址|	保留		|
 * |---------------------------------
 */
#ifndef MODBUS_IDXMAX
#define	MODBUS_IDXMAX		247	// 支持的最大站号数
#endif

#define	MODBUS_LENMAX		50	// 数据包中数据最大值(单位: 字)

#define	MDBSRXLEN_A			(MODBUS_LENMAX*4 + 21)		// ASCII 方式
#define	MDBSRXLEN_R			(MODBUS_LENMAX*2 + 10)		// RTU 方式

#define	MDBSRXLEN_MAX		MDBSRXLEN_A		// 单位字节


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


//------------------------------------------------------------------
// 支持的命令
#define	READ_COIL_STATUS			0x01	// 读取线圈状态(位操作)
#define	READ_INPUT_STATUS			0x02	// 读取输入状态(位操作)
#define	READ_HOLDING_REGISTER		0x03	// 读取保持寄存器
#define	READ_INPUT_REGISTER			0x04	// 读取输入寄存器
#define	WRITE_SINGLE_COIL			0x05	// 写单个线圈(位操作)
#define	WRITE_SINGLE_REGISTER		0x06	// 写单个保持寄存器
#define	WRITE_MULTIPLE_COIL			0x0F	// 写多个线圈(位操作)
#define	WRITE_MULTIPLE_REGISTER		0x10	// 写多个保持寄存器

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

#define	MODBUS_RD				READ_HOLDING_REGISTER	// 读命令
#define	MODBUS_WR				WRITE_SINGLE_REGISTER	// 写命令
#define	MODBUS_WR_MULTI			WRITE_MULTIPLE_REGISTER	// 写多字命令

//------------------------------------------------------------------
#ifndef MODBUS_MAX_WR
#define	MODBUS_MAX_WR			10
#endif

#ifndef MODBUS_MAX_RD
#define	MODBUS_MAX_RD			10
#endif

typedef struct
{
	// 命令数据
	u8 midx;					// 主站序号
	u8 index;					// 站号，1~247(十进制)
	u8 cmd;						// 命令码
	u16 addr;					// 数据地址
	u16 wrdat[MODBUS_MAX_WR];	// 写数据
	u16 wlen;					// 写数据长度
	u16 rddat[MODBUS_MAX_RD];	// 读到的数据
	u16 rlen;					// 读取数据长度
}Rs485Cmd;

#ifndef MAX_485CMD
#define	MAX_485CMD		20
#endif

typedef void (*Resv485ExProc)(Rs485Cmd * pcmd);			// 收到数据处理函数

typedef struct
{
	int init;		// 1:初始化完成
	u8 idxNum;
	u8 idxList[MODBUS_IDXMAX];		// 站号列表,用于模拟多个从站的动作，1~247(十进制)

	Rs485Cmd cmdbuf[MAX_485CMD];
	// 收发控制
	int working;	// 正在读写中; = 1, 工作中，不能收发新命令

	int bufCmdNum;		// 命令个数; != 0, 有新命令
	int bufHead;
	int bufTail;

	int steps;
	u32 stepTime;

	Resv485ExProc resv485exproc;		// 收到数据处理函数

	int modrsvTimout;		// 读取超时时间

}Rs485Ctrl;


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

typedef void (*OnOffFunc)(void);

// 控制数据结构
typedef struct
{
	int modBusMode;		// 通讯模式, = 0, RTU模式; = 1, ASCII模式
	int filterChk;		// 过滤数据校验位标志, = 0, 不过滤; = 1, 过滤

	u32 modBusWait;		// 通讯延时, 单位us,发送一个字节所需时间

	// 通讯函数指针
	UsartSendData ModBusCommSend;			// 发送数据
	UsartGetData ModBusCommReceive;			// 接收数据
	UsartCleanRsBuf	ModBusCommCleanRsBuf;	// 清空接收缓冲区
	IsUsartSendOver IsModBusCommSendOver;	// 判断发送缓冲区是否为空

	OnOffFunc CommOutEn;	// 数据发送允许
	OnOffFunc CommOutDis;	// 数据发送禁止

}ModbusCtrl;

// 注册modbus通讯函数
void RegisterModbusCommFunc(ModbusCtrl* pCtrl, UsartSendData send, UsartGetData get, UsartCleanRsBuf clean, IsUsartSendOver sdover, OnOffFunc outen, OnOffFunc outdis);

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

// 默认函数
int DefSendData(u8 * pDatBuf, int len);
int DefGetData(u8 * pDat, int expectLen);
int DefCleanRsBuf(void);
int DefIsSendOver(void);
void DefOutEn(void);
void DefOutDis(void);
u16 ModbusCrc16(u8 * puchMsg, u16 usDataLen);
u8 AsciiToRtu(u8 ascii);
u8 RtuToAscii(u8 rtu);

#endif
