
#ifndef __XMODEM_H__
#define __XMODEM_H__

#include "config.h"

/*
	Xmodem 协议是一种串口通信中广泛用到的异步文件传输协议。
	分为标准Xmodem和1k-Xmodem两种，前者以128字节块的形式传输数据，后者字节块为1k即1024字节，并且每个块都使用一个校验和过程来进行错误检测。
	在校验过程中如果接收方关于一个块的校验和与它在发送方的校验和相同时，接收方就向发送方发送一个确认字节(ACK)。
	由于Xmodem需要对每个块都进行认可，这将导致性能有所下降，特别是延时比较长的场合，这种协议显得效率更低。
	除了Xmodem，还有Ymodem，Zmodem协议。他们的协议内容和Xmodem类似，不同的是Ymodem允许批处理文件传输，效率更高，Zmodem则是改进的了Xmodem，它只需要对损坏的块进行重发，其它正确的块不需要发送确认字节，减少了通信量。


	标准Xmodem协议（每个数据包含有128字节数据）帧格式如下

		________________________________________________________________
		|     |				|                	|       	|         	|
		| SOH | 信息包序号	| 信息包序号的补码	| 数据区段	|   校验和  	|
		|_____|_____________|___________________|___________|___________|
		|     |				|                	|       	|         	|
		|  1B |		1B		|         1B       	|   128B   	|     1B   	|
		|_____|_____________|___________________|___________|___________|


		SOH（0x01）是启动传输的字符

		包序号从1--255，如果大于255，则从头再开始

		数据段在标准Xmodem协议中是128字节，如果传送的文件不是128的整数倍，那么最后一个数据包的有效内容肯定小于帧长，不足的部分需要用CTRL-Z(0x1A)来填充。

		校验和是数据区段的累加和校验


	XModem 扩展协议（每个数据包含有128字节数据）帧格式如下

		________________________________________________________________
		|     |				|                	|       	|         	|
		| SOH | 信息包序号	| 信息包序号的补码	| 数据区段	|   CRC校验	|
		|_____|_____________|___________________|___________|___________|
		|     |				|                	|       	|         	|
		|  1B |		1B		|         1B       	|   128B   	|     2B   	|
		|_____|_____________|___________________|___________|___________|

		CRC校验是数据区段的16位CRC校验（MSB存放）

			X16+X12+X5+X0

	1K-Xmodem（每个数据包含有1024字节数据）帧格式如下
		________________________________________________________________
		|     |				|                	|       	|         	|
		| STX | 信息包序号	| 信息包序号的补码	| 数据区段	|   CRC校验	|
		|_____|_____________|___________________|___________|___________|
		|     |				|                	|       	|         	|
		|  1B |		1B		|         1B       	|   1024B   |     2B   	|
		|_____|_____________|___________________|___________|___________|


	传输协议：

	1. 启动传输

		传输由接收方启动，方法是向发送方发送"C"或者NAK (注意哦，这里提到的NAK是用来启动传输的。以下我们会看到NAK还可以用来对数据产生重传的机制)。
		接收方发送NAK信号表示接收方打算用累加和校验；发送字符"C"则表示接收方想打算使用CRC校验。

	2. 传输过程

		当接收方发送的第一个"C"或者NAK到达发送方，发送方认为可以发送第一个数据包，传输已经启动。
		发送方接着应该将数据以每次128字节的数据加上包头，包号，包号补码，末尾加上校验和或CRC校验，打包成帧格式传送。
		发送方发了第一包后就等待接收方的确认字节ACK，收到接收方传来的ACK确认，就认为数据包被接收方正确接收，并且接收方要求发送方继续发送下一个包；
		如果发送方收到接收方传来的NAK(这里，NAK用来告诉发送方重传，不是用来启动传输)字节，则表示接收方请求重发刚才的数据包。
		如果发送方收到接收方传来的CAN字节，则表示接收方请求无条件停止传输。

	3. 结束传输

		如果发送方正常传输完全部数据，需要结束传输，正常结束需要发送方发送 EOT 字节通知接收方，接收方回以ACK进行确认。
		当然接收方也可强制停止传输，当接收方发送 CAN 字节给发送方，表示接收方想无条件停止传输，发送方收到CAN后，不需要再发送 EOT确认。

	4. 特殊处理

		虽然数据包是以 SOH 来标志一个信息包的起始的，但在 SOH 位置上如果出现EOT则表示数据传输结束，再也没有数据传过来。
		接收方首先应确认数据包序号的完整性，通过对数据包序号取补，然后和数据包序号的补码异或，结果为0表示正确，结果不为0则发送NAK请求重传。
		接收方确认数据包序号正确后，然后检查是否期望的序号。如果不是期望得到的数据包序号，说明发生严重错误，应该发送一个 CAN 来中止传输。
		如果接收到的数据包的包序号和前一包相同，那么接收方会忽略这个重复包，向发送方发出 ACK ，准备接收下一个包。
		接收方确认了信息包序号的完整性和是正确期望的后，只对 128 字节的数据区段进行算术和校验，结果与帧中最后一个字节的校验和或2字节的CRC比较，相同发送 ACK，不同发送 NAK。

	5．校验的说明

		Xmodem协议支持2种校验和，它们是累加和与CRC校验。
		当接收方一开始启动传输时发送的是NAK，表示它希望以累加和方式校验。
		当接收方一开始启动传输时发送的是字符“C”，表示它希望以CRC方式校验。
		Xmodem要求发送方支持CRC的就必须同时支持累加和。
		如果发送方只支持累加和，而接收方用字符“C”来启动，那么发送方只要不管它，当接收方继续发送“C”，三次后都没收到应答，就自动会改为发送NAK（发送方可能不支持CRC校验，需要改为累加和校验方式）。
		发送方收到NAK就赶紧发送数据包响应

*/

#define	XMODEM_SOH			0x01		// Xmodem数据包头
#define	XMODEM_STX			0x02		// 1K-Xmodem数据包头
#define	XMODEM_EOT			0x04		// 传输结束
#define	XMODEM_ACK			0x06		// 认可响应，如：数据包正确接收
#define	XMODEM_NAK			0x15		// 不认可响应
#define	XMODEM_CAN			0x18		// 取消传输
#define	XMODEM_CTRLZ		0x1A		// 填充数据


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

#define	XMODEM_F_SIZE		128
#define	XMODEM1K_F_SIZE		1024

#define	XMODEM_HEAD_SIZE	3

#define	XMODEM_CHECK_SIZE	1
#define	XMODEM_CRC_SIZE		2


#define	XMODEM_FRAME		(XMODEM_F_SIZE+XMODEM_HEAD_SIZE+XMODEM_CHECK_SIZE)
#define	XMODEM1K_FRAME		(XMODEM1K_F_SIZE+XMODEM_HEAD_SIZE+XMODEM_CHECK_SIZE)

#define	XMODEM_FRAME_C		(XMODEM_F_SIZE+XMODEM_HEAD_SIZE+XMODEM_CRC_SIZE)
#define	XMODEM1K_FRAME_C	(XMODEM1K_F_SIZE+XMODEM_HEAD_SIZE+XMODEM_CRC_SIZE)

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




typedef struct
{
	void (*InitSave)(void);
	int (*SaveData)(int, u8 *, int, u32);
	int (*XmodemOutBuff)(u8 *, int);
	int (*XmodemInBuff)(u8 *, int);
	int (*XmodemGetInBuffLen)(void);
	int (*XmodemCleanBuff)(void);

	int savedsize;
	int xpktlen;
}XmodemCtrl;

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


int XmodemReceive(XmodemCtrl * pCtrl);


void OutDebugBufInfo(void);

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





#endif

