
#define	_IN_ETHERNET_C
#include "ethernet.h"
#include "inout.h"
#include "delay.h"
#include "tcpserver.h"
#include "tcpclient.h"
#include "udptrans.h"
#include "trigger.h"
#include "cpuid.h"
#include "crc16.h"

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




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


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

void W5500IntConfig(void);
void RegNetCallBack(void);
void LoadDefNetParas(void);
int ChipParaConfig(void);
void NetworkParaConfig(void);

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


void InitEthernet(void)
{
	W5500IntConfig();		// 中断配置

	InitWNetSpi();			// 初始化Spi通讯

	RegNetCallBack();		// 设置回调函数

	LoadDefNetParas();		// 默认参数

	InitNetConfig();		// 重启芯片并重新配置
}


void InitNetConfig(void)
{
	ChipParaConfig();		// 芯片配置

#if (SERVER_NUM > 0)
	InitTcpServer();
	SetTcpKeepAlive();
#endif

#if (CLIENT_NUM > 0)
	InitTcpClient();
#endif

	NetworkParaConfig();	// 网络参数配置
}


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

// W5500 中断配置
void W5500IntConfig(void)
{

}

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

// 进入临界区
#define SPI_CrisEnter	EnterCritical

// 退出临界区
#define SPI_CrisExit	ExitCritical

// 片选信号输出低电平
#define SPI_CS_Select	WNetNceOn

// 片选信号输出高电平
#define SPI_CS_Deselect	WNetNceOff

#define SPI_ReadByte	WNetSpiReadByte

#define SPI_WriteByte	WNetSpiWriteByte


void RegNetCallBack(void)
{
	// 注册临界区函数
//	reg_wizchip_cris_cbfunc(SPI_CrisEnter, SPI_CrisExit);

	// 注册SPI片选信号函数
	reg_wizchip_cs_cbfunc(SPI_CS_Select, SPI_CS_Deselect);

	// 注册读写函数
	reg_wizchip_spi_cbfunc(SPI_ReadByte, SPI_WriteByte);

	// 注册块读写函数
//	reg_wizchip_spiburst_cbfunc(,);
}

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

void SetNetAddr(u32 ip, u32 mask, u32 gateway, u32 dns)
{
	// 源IP地址（本地IP）
	g_netInfo.ip[0] = GETIP1(ip);
	g_netInfo.ip[1] = GETIP2(ip);
	g_netInfo.ip[2] = GETIP3(ip);
	g_netInfo.ip[3] = GETIP4(ip);

	// 子网掩码
	g_netInfo.sn[0] = GETIP1(mask);
	g_netInfo.sn[1] = GETIP2(mask);
	g_netInfo.sn[2] = GETIP3(mask);
	g_netInfo.sn[3] = GETIP4(mask);

	// 网关IP
	g_netInfo.gw[0] = GETIP1(gateway);	
	g_netInfo.gw[1] = GETIP2(gateway);
	g_netInfo.gw[2] = GETIP3(gateway);
	g_netInfo.gw[3] = GETIP4(gateway);

	// DNS服务器IP
	g_netInfo.dns[0] = GETIP1(dns);
	g_netInfo.dns[1] = GETIP2(dns);
	g_netInfo.dns[2] = GETIP3(dns);
	g_netInfo.dns[3] = GETIP4(dns);
}

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

// 通过CPUID生成网卡物理地址
void MakeMacAddr(u8 * mac)
{
	CpuId cpuid;
	u16 crc;
	u8 chrcksum;

	GetCpuID(&cpuid);

	crc = CalcCrc16(cpuid.buff, CPUID_LEN);

	chrcksum = CalcCheckSum(cpuid.buff, CPUID_LEN);

	if (mac != NULL)
	{
		mac[0] = 0x52;
		mac[1] = 0x50;	// 自定义厂商名 "RP"
		mac[2] = 0x4E;	// 产品标识‘N’
		mac[3] = HIBYTE(crc);
		mac[4] = LOBYTE(crc);
		mac[5] = chrcksum;
	}
}

// 设置默认网络参数
void LoadDefNetParas(void)
{
// 物理层参数
	g_phyConfig.by = PHY_CONFBY_SW;						// 通过软件配置
	g_phyConfig.mode = PHY_MODE_MANUAL;					// 手动配置
	g_phyConfig.speed = PHY_SPEED_100;					// 100
	g_phyConfig.duplex = PHY_DUPLEX_FULL;				// 全双工

// 网络参数
	// 源物理地址
	MakeMacAddr(g_netInfo.mac);

	g_localIP = LOCAL_IP;
	g_netMask = NET_MASK;
	g_gateWay = GATE_WAY;
	g_dnsIP = DNS_IP;

	SetNetAddr(g_localIP, g_netMask, g_gateWay, g_dnsIP);

	// DHCP模式
	g_netInfo.dhcp = NETINFO_STATIC;

// 时间参数
	// ARPTO = time_100us x 0.1ms x (retry_cnt+1)

	g_netTimeout.retry_cnt = 3;
	g_netTimeout.time_100us = 2000;

	// TCPTO = 	(2000) x 0.1ms																// retry_cnt == 0
	//			(2000 + 4000) x 0.1ms														// retry_cnt == 1
	//			(2000 + 4000 + 8000) x 0.1ms												// retry_cnt == 2
	//			(2000 + 4000 + 8000 + 16000) x 0.1ms										// retry_cnt == 3
	//			(2000 + 4000 + 8000 + 16000 + 32000 + ((retry_cnt - 4) x 64000)) x 0.1ms	// retry_cnt >= 4
}

void GetChipConfig(void)
{
	ctlwizchip(CW_GET_PHYCONF, (void*)(&g_phyConfig));

	printf("after set config, phy config is:\r\n");
	if (g_phyConfig.by == PHY_CONFBY_SW)
	{
		printf("config by software:\r\n");
	}
	else if(g_phyConfig.by == PHY_CONFBY_HW)
	{
		printf("config by hardware:\r\n");
	}
	else
	{
		printf("config by %d:\r\n", g_phyConfig.by);
	}

	if (g_phyConfig.mode == PHY_MODE_AUTONEGO)
	{
		printf("mode is PHY_MODE_AUTONEGO:\r\n");
	}
	else if (g_phyConfig.mode == PHY_MODE_MANUAL)
	{
		printf("mode is PHY_MODE_MANUAL:\r\n");
	}
	else
	{
		printf("mode is %d:\r\n", g_phyConfig.mode);
	}

	if (g_phyConfig.speed == PHY_SPEED_100)
	{
		printf("speed is PHY_SPEED_100:\r\n");
	}
	else if (g_phyConfig.speed == PHY_SPEED_10)
	{
		printf("speed is PHY_SPEED_10:\r\n");
	}
	else
	{
		printf("speed is %d:\r\n", g_phyConfig.speed);
	}

	if (g_phyConfig.duplex == PHY_DUPLEX_FULL)
	{
		printf("duplex is PHY_DUPLEX_FULL:\r\n");
	}
	else if (g_phyConfig.duplex == PHY_DUPLEX_HALF)
	{
		printf("duplex is PHY_DUPLEX_HALF:\r\n");
	}
	else
	{
		printf("duplex is %d:\r\n", g_phyConfig.duplex);
	}
}


// 初始化芯片参数
int ChipParaConfig(void)
{
	int rslt;
	u8 tmp8;
	u16 tmp16;
	u8 chipId[6];

	u8 memsize[2][8] = {
							{2,2,2,2,2,2,2,2},
							{2,2,2,2,2,2,2,2},
						};

	// 复位芯片
	ctlwizchip(CW_RESET_WIZCHIP, 0);

	DelayMs(10);

	// 复位物理层
	ctlwizchip(CW_RESET_PHY, 0);

	DelayMs(10);

	// 配置物理层
	ctlwizchip(CW_SET_PHYCONF, (void*)(&g_phyConfig));

	DelayMs(10);

	// 复位物理层
	ctlwizchip(CW_RESET_PHY, 0);

	DelayMs(10);

#if (1)
	// 读取配置
	GetChipConfig();
#endif

	// WIZCHIP SOCKET 缓存区初始化
	rslt = ctlwizchip(CW_INIT_WIZCHIP, (void*)(memsize));
	if(rslt == -1)
	{
		printf("WIZCHIP Initialized fail.\r\n");
		return -1;
	}

	// 读取电源模式
	ctlwizchip(CW_GET_PHYPOWMODE, (void*)(&tmp8));

	printf("powermode is %d:\r\n", tmp8);

	// 中断屏蔽位配置
	tmp16 = 0
			| IK_IP_CONFLICT 		// IP冲突
			| IK_DEST_UNREACH 		// 目标不可达
			| IK_PPPOE_TERMINATED	// PPPOE连接关闭
			| IK_WOL				// 网络唤醒
//			| IK_SOCK_ALL			// 所有的SOCKET中断
			| 0;

	ctlwizchip(CW_SET_INTRMASK, (void*)(&tmp16));
	ctlwizchip(CW_GET_INTRMASK, (void*)(&tmp16));

	// 清除中断标志
	ctlwizchip(CW_GET_INTERRUPT, (void*)(&tmp16));
	tmp16 = 0
			| IK_IP_CONFLICT 		// IP冲突
			| IK_DEST_UNREACH 		// 目标不可达
			| IK_PPPOE_TERMINATED	// PPPOE连接关闭
			| IK_WOL				// 网络唤醒
			| IK_SOCK_ALL;			// 所有的SOCKET中断
	ctlwizchip(CW_CLR_INTERRUPT, (void*)(&tmp16));

	// 设置中断间隔时间
	tmp16 = 25;
	ctlwizchip(CW_SET_INTRTIME, (void*)(&tmp16));
	ctlwizchip(CW_GET_INTRTIME, (void*)(&tmp16));

	printf("intrtime is %d:\r\n", tmp16);

	// 读取芯片ID
	ctlwizchip(CW_GET_ID, (void*)(&chipId));
	printf("chip ID is %x %x %x %x %x %x\r\n", chipId[0],chipId[1],chipId[2],chipId[3],chipId[4],chipId[5]);

	// PHY物理层连接状态检查
	rslt = ctlwizchip(CW_GET_PHYLINK, (void*)(&tmp8));
	if(rslt == -1)
	{
		printf("Unknown PHY Link stauts.\r\n");
	}
	else
	{
		if (tmp8 == PHY_LINK_ON)
		{
			printf("PHY Link ON.\r\n");
		}
		else if (tmp8 == PHY_LINK_OFF)
		{
			printf("PHY Link OFF.\r\n");
		}
	}
	return rslt;
}

// 网络参数配置
void NetworkParaConfig(void)
{
	u8 tmp8;
	u8 tmpstr[6];

// 网络模式
	tmp8 =	  0
//			| NM_FORCEARP	// 强制ARP
//			| NM_WAKEONLAN	// 网络唤醒
//			| NM_PINGBLOCK	// ping 阻塞
//			| NM_PPPOE		// PPPoE 模式
			| 0;
	ctlnetwork(CN_SET_NETMODE, (void*)(&tmp8));

// 网络参数 包括MAC地址，IP地址，子网掩码，DNS，DHCP等
	ctlnetwork(CN_SET_NETINFO, (void*)(&g_netInfo));
	DelayMs(10);
	ctlnetwork(CN_GET_NETINFO, (void*)(&g_netInfo));

	ctlwizchip(CW_GET_ID, (void*)(tmpstr));

	// 显示网络参数
#if (1)
	printf("\r\n=== %s NET CONF ===\r\n",(char*)(tmpstr));
	printf("MAC: %X:%X:%X:%X:%X:%X\r\n",g_netInfo.mac[0],g_netInfo.mac[1],g_netInfo.mac[2],
			g_netInfo.mac[3],g_netInfo.mac[4],g_netInfo.mac[5]);
	printf("SIP: %d.%d.%d.%d\r\n", g_netInfo.ip[0],g_netInfo.ip[1],g_netInfo.ip[2],g_netInfo.ip[3]);
	printf("GAW: %d.%d.%d.%d\r\n", g_netInfo.gw[0],g_netInfo.gw[1],g_netInfo.gw[2],g_netInfo.gw[3]);
	printf("SUB: %d.%d.%d.%d\r\n", g_netInfo.sn[0],g_netInfo.sn[1],g_netInfo.sn[2],g_netInfo.sn[3]);
	printf("DNS: %d.%d.%d.%d\r\n", g_netInfo.dns[0],g_netInfo.dns[1],g_netInfo.dns[2],g_netInfo.dns[3]);
	if (g_netInfo.dhcp == 1)
	{
		printf("alloc ip static\r\n");
	}
	else if (g_netInfo.dhcp == 2)
	{
		printf("alloc ip by dhcp\r\n");
	}
	printf("======================\r\n");
#endif

	// 设置时间参数
	ctlnetwork(CN_SET_TIMEOUT, (void*)(&g_netTimeout));
}


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

// 中断处理
void EthernetIntProc(void)
{
	u16 intr;

	// 控制器中断
	ctlwizchip(CW_GET_INTERRUPT, &intr);		// 读取中断
	ctlwizchip(CW_CLR_INTERRUPT, &intr);		// 清除中断标志

#if (1)
	// 处理中断
	if ((intr & IK_WOL) != 0)					// 网络唤醒
	{
		printf("Wake on LAN\r\n");
	}

	if ((intr & IK_PPPOE_TERMINATED) != 0)		// PPPOE连接关闭
	{
		printf("PPPOE terminated\r\n");
	}

	if ((intr & IK_DEST_UNREACH) != 0) 			// 目标不可达
	{
		printf("Destination Unreachable\r\n");
	}

	if ((intr & IK_IP_CONFLICT) != 0) 			// IP冲突
	{
		printf("IP conflict\r\n");
	}
#endif

}

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

int IsSocketErr(int err)
{
	int rslt;
	rslt = 0;

	switch(err)
	{
		case SOCK_OK:
			printf("Result is OK about socket process.\r\n");
			break;
		case SOCK_BUSY:
			printf("Socket is busy on processing the operation. Valid only Non-block IO Mode.\r\n");
			break;
		case SOCK_FATAL:
            printf("Result is fatal error about socket process.\r\n");
			break;
		case SOCKERR_SOCKNUM:
			printf("Invalid socket number\r\n");
			rslt = -1;
			break;
		case SOCKERR_SOCKOPT:
			printf("Invalid socket option\r\n");
			rslt = -1;
			break;
		case SOCKERR_SOCKINIT:
			printf("Socket is not initialized or SIPR is Zero IP address when Sn_MR_TCP\r\n");
			rslt = -1;
			break;
		case SOCKERR_SOCKCLOSED:
			printf("Socket unexpectedly closed.\r\n");
			rslt = -1;
			break;
		case SOCKERR_SOCKMODE:
			printf("Invalid socket mode for socket operation.\r\n");
			rslt = -1;
			break;
		case SOCKERR_SOCKFLAG:
			printf("Invalid socket flag\r\n");
			rslt = -1;
			break;
		case SOCKERR_SOCKSTATUS:
			printf("Invalid socket status for socket operation.\r\n");
			rslt = -1;
			break;
		case SOCKERR_ARG:
			printf("Invalid argument.\r\n");
			rslt = -1;
			break;
		case SOCKERR_PORTZERO:
			printf("Port number is zero\r\n");
			rslt = -1;
			break;
		case SOCKERR_IPINVALID:
			printf("Invalid IP address\r\n");
			rslt = -1;
			break;
		case SOCKERR_TIMEOUT:
			printf("Timeout occurred\r\n");
			rslt = -1;
			break;
		case SOCKERR_DATALEN:
			printf("Data length is zero or greater than buffer max size.\r\n");
			rslt = -1;
			break;
		case SOCKERR_BUFFER:
			printf("Socket buffer is not enough for data communication.\r\n");
			rslt = -1;
			break;
		case SOCKFATAL_PACKLEN:
			printf("Invalid packet length. Fatal Error.\r\n");
			rslt = -1;
			break;
		default:
			rslt = err;
			break;
	}

	EthernetServiceRun();

	return rslt;
}

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

// Ethernet 发送数据
// 功能：发送数据，将数据添加到发送队列中并发送
// 参数： pDatBuf，发送数据缓冲区
// 		  len, 发送数据长度
// 返回： >= 0, 实际发送数据
// 返回： -1, 输入参数错误
//		  -2, 控制结构没有初始化
//		  -3, 接收缓冲区控制错误

int EthernetSendData(SocketCtrl * pCtrl, u8 * pDatBuf, int len)
{
	int rslt, err;
	rslt = 0;

	if (pCtrl->type == TCP_SERVER || pCtrl->type == TCP_CLIENT)
	{
		if (pCtrl->status == STA_CONNECT)		// 已连接
		{
			err = send(pCtrl->socket, pDatBuf, len);

			rslt = IsSocketErr(err);
		}
		else
		{
			printf("socket not connect\r\n");
		}
	}
#if (UDP_NUM > 0)
	else if (pCtrl->type == UDP_COMM)
	{
		err = UdpTransData(pDatBuf, len);	// sendto
		rslt = IsSocketErr(err);
	}
#endif
	else
	{

	}

	return rslt;
}

// 功能：接收数据，将数据从接收缓冲区中取出
// 参数： pDat，存放缓冲区
//		  expectLen，希望得到数据的大小
// 返回： >= 0，实际得到数据的大小
//		  -1, 输入参数错误
//		  -2, 控制器没有初始化
//		  -3, 接收缓冲区控制错误

int EthernetGetData(SocketCtrl * pCtrl, u8 * pDat, int expectLen)
{
	int rslt, err;
	rslt = 0;
	if (pCtrl->type == TCP_SERVER || pCtrl->type == TCP_CLIENT)
	{
		if (pCtrl->status == STA_CONNECT)		// 已连接
		{
			err = recv(pCtrl->socket, pDat, expectLen);
			rslt = IsSocketErr(err);
		}
		else
		{
			printf("socket not connect\r\n");
		}
	}
#if (UDP_NUM > 0)
	else if (pCtrl->type == UDP_COMM)
	{
		err = UdpRecvData(pDat, expectLen);	// recvfrom
		rslt = IsSocketErr(err);
	}
#endif
	else
	{

	}
	return rslt;
}

// Ethernet 已接收数据长度
int EthernetGetRsLen(SocketCtrl * pCtrl)
{
	if (pCtrl->status == STA_CONNECT ||
#if (UDP_NUM > 0)
			pCtrl->type == UDP_COMM ||
#endif
			0	)		// 已连接
	{
		return getSn_RX_RSR(pCtrl->socket);
	}
	else
	{
//		printf("socket not connect\r\n");
		return -1;
	}
}

// 得到发送缓冲区空闲长度
int EthernetGetSdFreeLen(SocketCtrl * pCtrl)
{
	if (pCtrl->status == STA_CONNECT ||
#if (UDP_NUM > 0)
			pCtrl->type == UDP_COMM	||
#endif
			0	)		// 已连接
	{
		return getSn_TX_FSR(pCtrl->socket);
	}
	else
	{
//		printf("socket not connect\r\n");
		return -1;
	}
}

SocketCtrl * GetCtrlFromSocketIdx(int sIdx)
{
	if (sIdx < UDP_SN_BEG+UDP_NUM)
	{
		return GetUdpCtrlFromSocketId(sIdx-UDP_SN_BEG);
	}
#if (SERVER_NUM > 0)
	else if (sIdx < TCP_SERVER_SN_BEG+SERVER_NUM)
	{
		return GetTcpServerCtrlFromSocketId(sIdx-TCP_SERVER_SN_BEG);
	}
#endif
#if (CLIENT_NUM > 0)
	else if (sIdx < TCP_CLIENT_SN_BEG+CLIENT_NUM)
	{
		return GetTcpClientCtrlFromSocketId(sIdx-TCP_CLIENT_SN_BEG);
	}
#endif
	else
	{
		return NULL;
	}
}

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

// 服务运行
void EthernetServiceRun()
{
#if (SERVER_NUM > 0)
	TcpServerRun();
#endif

#if (CLIENT_NUM > 0)
	TcpClientRun();
#endif

#if (UDP_NUM > 0)
//	UdpTransRun();
#endif
}


