/*******************************************************************************
* 版权所有：	
版本号：    1.00 
文件名：    Down.h
生成日期： 2010-04-25
作者：      
功能说明：下载及超级终端调试
	
修改日志：  
日志1：           
修改者：    
修改日期：
修改内容：
修改原因：
****************************************************************************/
#include "head.h"
#ifdef CAN_SLAVE_BOARD

#define RECV_TIMEOUT	(USTIMER_SEC*5)

enum 
{
	SEND=1,
	RECV
};



struct program_comm g_program;

/**************************************************************************
函数名称：init_file_program
函数版本：1.00 
作者：   
创建日期：2013.05.16     
函数功能说明：程序文件解析
输入参数：
输出参数：
返回值：

更新信息：
更新日志1：
日期：	  
修改者：	  
修改内容：  
修改原因：
***************************************************************************/
int init_file_program(u8 slot, s32 index)
{
	u32 len,i;
	u16 crc;
	u8 *buf;
	char file_name[64];

	int pfile;
	loff_t pos;

	sprintf(file_name,"%s%s",g_file_item[index].file_dir,g_file_item[index].file_name);

	// 打开文件
	pfile = rt_file_open(file_name,O_RDONLY ,0);

	//pfile = rt_file_open("/app/data/DTU-DIDO.elf.bin",O_RDONLY ,0);
	if(IS_ERR(pfile))
	{
		return -1;
	}

	// 得到文件长度
	len = rt_file_getfile_size(pfile);
	
	// 分配内存
	buf = rt_malloc(len);
	if((buf) == NULL)
	{
		rt_file_close(pfile,0);
		return -2; 	
	}

	// 读出内容
	pos = 0;
	if(rt_file_read(pfile,buf,len,&pos) != len)
	{
		rt_file_close(pfile,0);
		rt_free(buf);
		return -3;
	}
	// 关闭文件
	rt_file_close(pfile,0);

	// 检查CRC
	crc = CrcStr(buf+64,len-2-64);

	#ifdef MODE_LITTLE_ENDIAN
	swap16(&crc);
	#endif
	
	if(crc != *(u16*)(buf+len-2))
	{
		rt_printf("init_down_program:CRC=%x, %x", crc,  *(u16*)(buf+len-2));
		rt_free(buf);
		return -4;
	}
	memset(&g_program, 0, sizeof(g_program));
	g_program.slot = slot;
	g_program.file_name = g_file_item[index].file_name;
	g_program.num = len;
	if (len % (CAN_FRAME_LEN_MAX-8) == 0)
	{
		g_program.framenum = len/(CAN_FRAME_LEN_MAX-8);
	}
	else
	{
		g_program.framenum = len/(CAN_FRAME_LEN_MAX-8)+1;
	}
	g_program.frameno = 0;
	g_program.probuf = buf;
	g_program.crc16 = crc;
	g_program.status = StartDOWN;
	g_program.comm = SEND;

	// 
	g_program.bit_prog = 0;
	g_program.bit_echo = 0;
	if(slot == 0x0f)
	{
		for(i=0; i<g_equ_config->equ_slot_num; i++)
		{
			if(equ_get_di_num(i) || equ_get_do_num(i))
			{
				//if (equ_slot_check(i) == 0)
				{
					g_program.bit_prog |= 1<<i;
				}
			}
		}
	}
	else
	{
		g_program.bit_prog |= 1<<slot;
	}
	
	g_prog_up.framesum = g_program.framenum;
	g_prog_up.frameno = g_program.frameno;
	g_prog_up.bit_prog = g_program.bit_prog;
	g_prog_up.bit_echo = g_program.bit_echo;
	
	return 0;
}

int down_exit(void)
{
	rt_free(g_program.probuf);
	return 0;
}

/**************************************************************************
函数名称：slot_program_update_send
函数版本：1.00 
作者：   
创建日期：2013.05.16     
函数功能说明：子板程序更新
输入参数：
输出参数：
返回值：

更新信息：
更新日志1：
日期：	  
修改者：	  
修改内容：  
修改原因：
***************************************************************************/
int slot_program_update_send(u8 slot, u8 cmd, u16 frameno, u8 lenth, u8 *buffer)
{
	int num;
	u8 *buf;

	// 检查合法性
	num = lenth;
	if(num > (CAN_FRAME_LEN_MAX -6))
	{
		return -1;
	}

	// 帧头
	buf = can_request_tx_buf(CAN_FRAME_TYPE_PROGRAM_UPDATE);
	buf[0] = CAN_FRAME_TYPE_PROGRAM_UPDATE;
	buf[1] = slot;
	buf[2] = 0;
	buf[3] = num+4;
	buf[4] = cmd;
	buf[5] = 0;
	buf[6] = frameno>>8;
	buf[7] = frameno;

	if (lenth > 0)
	{
		memcpy(buf+8,buffer,lenth);
	} 

	// 校验和
	buf[5] = can_app_checksum(buf,num+8);
	buf[5] = ~buf[5] +1;
	
	// 发送
	can_send(0,buf);
	can_send(1,buf);

	//print_mem("TTTT:",g_frame_downbuf,num+8);

	clk_time_get(&g_program.update_time);

	return 0;
}


/**************************************************************************
函数名称：IsDownFrame
函数版本：1.00 
作者：   
创建日期：2008.8.20    
函数功能说明：判断是否是下载命令码
输入参数：
输出参数：无
返回值： 成功时返回1，否则，0
函数扇入清单：
***************************************************************************/
static bool IsDownFrame(BYTE cmd)
{
	if(cmd==WrtDt)return true;
	if(cmd==ErsFSH)return true;
	if(cmd==RdDt)return true;
	if(cmd==NAKCODE)return true;
	if(cmd==RunPrg)return true;
	if(cmd==ReadInf)return true;
	if(cmd==StartDOWN)return true;
	if(cmd==WAVEINF)return true;

	if(cmd==VIRLCD_E0)return true;
	if(cmd==VIRLCD_E1)return true;
	if(cmd==VIRLCD_E2)return true;

	return false;
}

int prog_recv_timeout(void)
{
	// 超时处理
	if(ustimer_get_duration(g_program.us_recv) > RECV_TIMEOUT && g_program.comm == RECV)
	{
		rt_printf("program_check_period timeout:bit_prog=0x%08x,bit_echo=0x%08x.\r\n",g_program.bit_prog,g_program.bit_echo);
		if(g_program.bit_echo == 0)
		{
			// TODO:
			rt_printf("下载终止!\r\n");
			g_program.bit_prog = 0;
			g_program.bit_echo = 0;
			
			g_program.comm = 0;
			g_prog_up.bit_echo = g_program.bit_echo;
			rt_file_del("/tmp/DTU-DIDO.elf.bin");
			down_exit();
			return -1;
		}

		g_program.bit_prog = g_program.bit_echo;
		g_program.bit_echo = 0;
		g_program.comm = SEND;

	}

	return 0;
}

int prog_recv(u8 *buf)
{
	struct can_frame_head 	*cfh;
	int recvok;

	cfh = (struct can_frame_head *)buf;

	g_program.us_recv = ustimer_get_origin();
	g_program.head[cfh->src].can_bus = 0;	
	
	recvok = false;
	if(IsDownFrame(buf[4]))
	{
		u8 *p=&buf[4];
		if(p[0] == g_program.status && p[2] == OK)
		{
			recvok = true;	
		}
	}
 	
	if (g_program.comm == RECV && recvok)
	{	
		g_program.bit_echo |= 1<<cfh->src;
		if((g_program.bit_echo&g_program.bit_prog) != g_program.bit_prog)
		{
			return 0;
		}
		
		// 接收完成，进行状态转换
		switch (g_program.status)
		{
			case StartDOWN://启动下载
				g_program.status = ErsFSH;
				break;
				
			case ErsFSH: //擦除flash
				g_program.status = WrtDt;
				break;

			case WrtDt:
				if(g_program.frameno == g_program.framenum)
				{
					g_program.status = RunPrg;
				}
				g_prog_up.frameno = g_program.frameno;
				g_prog_up.bit_echo = g_program.bit_echo;
				break;
				
			case RunPrg:	//启动程序
				break;

			case ReadInf: //读设备信息
			//	g_program.status = ErsFSH;
				break;
			default:
				break;
 		}

 		

		// 重新进入发送状态
		g_program.bit_echo = 0;
		g_program.comm = SEND;
		
//		rt_printf("OK\r\n");
 	}
	
	return 0;
}



/**************************************************************************
函数名称：prog_send
函数版本：1.00 
作者：   
创建日期：2013.05.18    
函数功能说明：程序上传、下载
输入参数：
输出参数：无
返回值： 成功时返回1，否则，0
函数扇入清单：
***************************************************************************/
int prog_send (void)
{
	if (g_program.comm == SEND)
	{		
		g_program.comm = RECV;
		g_program.us_recv = ustimer_get_origin();
		switch (g_program.status)
		{
			case StartDOWN://启动下载
			case ReadInf://启动上传
			case RunPrg:	//启动程序
			{
				u8 buf[20];
				memcpy(buf,g_program.file_name,16);
				memcpy(buf+16,&g_program.bit_prog,4);
				Swap_32(buf+16);
				slot_program_update_send(g_program.slot, g_program.status, 0, 20, buf);
				if (g_program.status == RunPrg)
				{	
					g_program.status = 0;
					g_program.comm = 0;
					down_exit();
				}
				break;
			}

			case ErsFSH: //擦除flash
			{
				u8 len[8];
				u8 i;
				
				for (i=0; i<4; i++)
				{
					len[3-i] =g_program.num>>(i*8);					
				}

				
				slot_program_update_send(g_program.slot, g_program.status, 0, 4, len);			
				break;
			}

			case WrtDt:
			{
				u8 buf[CAN_FRAME_LEN_MAX];
				u8 lenth;
				
				// rt_printf("frameno = %d,framenum = %d\r\n", g_program.frameno,g_program.framenum);
				if(g_program.frameno == g_program.framenum)
				{
					g_program.status = RunPrg;
					break;
				}
				else if (g_program.frameno < (g_program.framenum-1))
				{
					lenth = CAN_FRAME_LEN_MAX-8;
				}
				else
				{
					lenth = g_program.num - g_program.frameno*(CAN_FRAME_LEN_MAX-8);
				}
				memcpy(&buf[0], g_program.probuf+g_program.frameno*(CAN_FRAME_LEN_MAX-8), lenth);
				slot_program_update_send(g_program.slot, g_program.status, g_program.frameno, lenth, buf);
				
				g_program.frameno++;
				
				break;
			}

			case RdDt://读数据
			{
				break;
			}
		}
		
	}
	
	return 0;
}

#ifdef METERING_ENERGY
u8 is_prog_down(void)
{
	return g_program.comm;
}
#endif
#endif