⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 simple_server.c

📁 基于lpc2103和ENC28J60的网卡驱动
💻 C
字号:
/*********************************************
 * vim:sw=8:ts=8:si:et
 * To use the above modeline in vim you must have "set modeline" in your .vimrc
 * Author: Guido Socher
 * Copyright: GPL V2
 * See http://www.gnu.org/licenses/gpl.html
 *
 * Ethernet remote device and sensor
 * UDP and HTTP interface 
        url looks like this http://baseurl/password/command
        or http://baseurl/password/
 *
 * Title: Microchip ENC28J60 Ethernet Interface Driver
 * Chip type           : ATMEGA88 with ENC28J60
 * Note: there is a version number in the text. Search for tuxgraphics
 *********************************************/

/*****************************************************/
/* EasyLPC2103 Study Broad + ENC28J60 Module						*/
/* http://www.OurEDA.cn														*/
/*****************************************************/
/*							Modified By OurEDA.CN								*/
/*****************************************************/


#include "ip_arp_udp_tcp.h"
#include "enc28j60.h"
#include "net.h"
#include "stdio.h"
#include <LPC2103.H>

#include <string.h>

#define PSTR(s)					s

#define	LED_R					(1<<19)					/* P0.19连接红色LED */
#define LED_R_ON				IOCLR |= LED_R		/* 红色LED点亮			*/
#define LED_R_OFF			IOSET |= LED_R			/* 红色LED熄灭			*/
#define CMD_LED_R_ON		1								/* cmd:红色LED点亮	*/
#define CMD_LED_R_OFF	2								/* cmd:红色LED熄灭	*/

#define	LED_G					(1<<20)					/* P0.20连接绿色LED */
#define LED_G_ON				IOCLR |= LED_G		/* 绿色LED点亮			*/
#define LED_G_OFF			IOSET |= LED_G		/* 绿色LED熄灭			*/
#define CMD_LED_G_ON	3								/* cmd:绿色LED点亮	*/
#define CMD_LED_G_OFF	4								/* cmd:绿色LED熄灭	*/

extern void delay_ms(unsigned char ms);

// please modify the following two lines. mac and ip have to be unique
// in your local area network. You can not have the same numbers in
// two devices:
/* 下面这部分内容是ENC28J60模块的硬件地址MAC */
static uint8_t mymac[6] = {0xA1,0xA5,0x58,0x10,0x00,0x24};
/* 下面这部分内容是ENC28J60模块的以太网地址IP */
static uint8_t myip[4] = {192,168,10,29};

// base url (you can put a DNS name instead of an IP addr. if you have
// a DNS server (baseurl must end in "/"):
/* 下面这部分内容是浏览器地址, 必须与IP相同*/
static char baseurl[]="http://192.168.10.29/";
/* 下面这部分内容是监听的端口, 默认80端口即可*/

// listen port for tcp/www (max range 1-254) or on a different port:
//static char baseurl[]="http://10.0.0.24:88/";
static uint16_t mywwwport =80;

// listen port for udp
// how did I get the mac addr? Translate the first 3 numbers into ascii is: TUX
/* 下面这部分内容是UDP端口, 不需要修改 */
static uint16_t myudpport =1200;

#define BUFFER_SIZE 1500
static uint8_t buf[BUFFER_SIZE+1];

// the password string (only the first 5 char checked), (only a-z,0-9,_ characters):
/* 密码(在HttpServer中称为"路径"或许更恰当)*/
static char password[]="hello"; // must not be longer than 9 char

/*****************************************************/
/* 简单的说, 可以按照如下的形式访问这个HttpServer			*/
/* http://baseurl/password/cmd												*/
/* 例如 htt://192.168.10.29/hello/2											*/
/* 特别需要注意的是: cmd命令只有一位,只能是数字				*/
/*****************************************************/

uint8_t verify_password(char *str) {
	// the first characters of the received string are
	// a simple password/cookie:
	if (strncmp(password,str,5)==0){
		return(1);
	}
	return(0);
}

// takes a string of the form password/commandNumber and analyse it
// return values: -1 invalid password, otherwise command number
//						-2 no command given but password valid
int8_t analyse_get_url(char *str) {
	uint8_t i=0;
	if (verify_password(str)==0){
		return(-1);
	}
	// find first "/"
	// passw not longer than 9 char:
	while(*str && i<10 && *str >',' && *str<'{'){
		if (*str=='/'){
			str++;
			break;
		}
		i++;
		str++;
	}
	if (*str < 0x3a && *str > 0x2f){
		// is a ASCII number, return it
		return(*str-0x30);
	}
	return(-2);
}

// prepare the webpage by writing the data to the tcp send buffer
/* 这是向用户的浏览器推送的Web页面的内容 */
uint16_t print_webpage(uint8_t *buf,uint8_t cmd) {
	uint16_t plen;
	
	plen=fill_tcp_data_p(buf,0,PSTR("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\nPragma: no-cache\r\n\r\n"));
	plen=fill_tcp_data_p(buf,plen,PSTR("<center><p><b>EasyLPC2103 + ENC28J60 Control and Communication Demo</b></p>\n"));

	/* 输出网页上的LED图标: IF嵌套形式 */
	/* 红色LED指令*/
	if (cmd==CMD_LED_R_ON) {
		/* 输出红色LED状态 */
		plen=fill_tcp_data_p(buf,plen,PSTR("<p><font color=\"#FF0000\" size=\"7\"><b>●</b></font>"));
		/* 输出绿色LED状态 */
		if(IOPIN & LED_G) plen=fill_tcp_data_p(buf,plen,PSTR("<font color=\"#000000\" size=\"7\"><b>●</b></font></p>\n"));
		else plen=fill_tcp_data_p(buf,plen,PSTR("<font color=\"#00FF00\" size=\"7\"><b>●</b></font></p>\n"));
	}
	if(cmd==CMD_LED_R_OFF){
		/* 输出红色LED状态 */
		plen=fill_tcp_data_p(buf,plen,PSTR("<p><font color=\"#000000\" size=\"7\"><b>●</b></font>"));
		/* 输出绿色LED状态 */
		if(IOPIN & LED_G) plen=fill_tcp_data_p(buf,plen,PSTR("<font color=\"#000000\" size=\"7\"><b>●</b></font></p>\n"));
		else plen=fill_tcp_data_p(buf,plen,PSTR("<font color=\"#00FF00\" size=\"7\"><b>●</b></font></p>\n"));
	}
	/* 绿色LED指令*/
	if (cmd==CMD_LED_G_ON) {
		/* 输出红色LED状态 */
		if(IOPIN & LED_R) plen=fill_tcp_data_p(buf,plen,PSTR("<font color=\"#000000\" size=\"7\"><b>●</b></font>"));
		else plen=fill_tcp_data_p(buf,plen,PSTR("<font color=\"#FF0000\" size=\"7\"><b>●</b></font>"));
		/* 输出绿色LED状态 */
		plen=fill_tcp_data_p(buf,plen,PSTR("<font color=\"#00FF00\" size=\"7\"><b>●</b></font></p>\n"));
	}
	if(cmd==CMD_LED_G_OFF){
		/* 输出红色LED状态 */
		if(IOPIN & LED_R) plen=fill_tcp_data_p(buf,plen,PSTR("<font color=\"#000000\" size=\"7\"><b>●</b></font>"));
		else plen=fill_tcp_data_p(buf,plen,PSTR("<font color=\"#FF0000\" size=\"7\"><b>●</b></font>"));
		/* 输出绿色LED状态 */
		plen=fill_tcp_data_p(buf,plen,PSTR("<font color=\"#000000\" size=\"7\"><b>●</b></font></p>\n"));
	}

	/* 刷新 */
	plen=fill_tcp_data_p(buf,plen,PSTR("<small><a href=\""));
	plen=fill_tcp_data(buf,plen,baseurl);
	plen=fill_tcp_data(buf,plen,password);
	plen=fill_tcp_data_p(buf,plen,PSTR("\">[刷新]</a></small></p>\n"));

	/* 输出网页上的红色LED控制链接: SWITCH-CASE */
	/* 这部分代码中部分内容没有使用宏定义*/
	plen=fill_tcp_data_p(buf,plen,PSTR("<p><a href=\""));
	plen=fill_tcp_data(buf,plen,baseurl);
	plen=fill_tcp_data(buf,plen,password);
	switch(cmd) {
		case CMD_LED_R_ON:
			plen=fill_tcp_data_p(buf,plen,PSTR("/2\">熄灭红色LED</a>"));
			if(IOPIN & LED_G) {
				plen=fill_tcp_data_p(buf,plen,PSTR("<a href=\""));plen=fill_tcp_data(buf,plen,baseurl);plen=fill_tcp_data(buf,plen,password);
				plen=fill_tcp_data_p(buf,plen,PSTR("/3\">点亮绿色LED</a></p>\n"));
			} else {
				plen=fill_tcp_data_p(buf,plen,PSTR("<a href=\""));plen=fill_tcp_data(buf,plen,baseurl);plen=fill_tcp_data(buf,plen,password);
				plen=fill_tcp_data_p(buf,plen,PSTR("/4\">熄灭绿色LED</a></p>\n"));
			}
			break;
		case CMD_LED_R_OFF:
			plen=fill_tcp_data_p(buf,plen,PSTR("/1\">点亮红色LED</a>"));
			if(IOPIN & LED_G) {
				plen=fill_tcp_data_p(buf,plen,PSTR("<a href=\""));plen=fill_tcp_data(buf,plen,baseurl);plen=fill_tcp_data(buf,plen,password);
				plen=fill_tcp_data_p(buf,plen,PSTR("/3\">点亮绿色LED</a></p>\n"));
			} else {
				plen=fill_tcp_data_p(buf,plen,PSTR("<a href=\""));plen=fill_tcp_data(buf,plen,baseurl);plen=fill_tcp_data(buf,plen,password);
				plen=fill_tcp_data_p(buf,plen,PSTR("/4\">熄灭绿色LED</a></p>\n"));
			}
			break;
		case CMD_LED_G_ON:
			if(IOPIN & LED_R) plen=fill_tcp_data_p(buf,plen,PSTR("/1\">点亮红色LED</a>"));
			else plen=fill_tcp_data_p(buf,plen,PSTR("/2\">熄灭红色LED</a>"));
			plen=fill_tcp_data_p(buf,plen,PSTR("<a href=\""));plen=fill_tcp_data(buf,plen,baseurl);plen=fill_tcp_data(buf,plen,password);
			plen=fill_tcp_data_p(buf,plen,PSTR("/4\">熄灭绿色LED</a></p>\n"));
			break;
		case CMD_LED_G_OFF:
			if(IOPIN & LED_R) plen=fill_tcp_data_p(buf,plen,PSTR("/1\">点亮红色LED</a>"));
			else plen=fill_tcp_data_p(buf,plen,PSTR("/2\">熄灭红色LED</a>"));
			plen=fill_tcp_data_p(buf,plen,PSTR("<a href=\""));plen=fill_tcp_data(buf,plen,baseurl);plen=fill_tcp_data(buf,plen,password);
			plen=fill_tcp_data_p(buf,plen,PSTR("/3\">点亮绿色LED</a></p>\n"));
		default:
			break;
	}

	plen=fill_tcp_data_p(buf,plen,PSTR("<p>======================</p>\n"));
	plen=fill_tcp_data_p(buf,plen,PSTR("<p><a href=\"http://www.oureda.cn\"><b>www.OurEDA.cn</b></a></p>\n"));
	return(plen);
}

int simple_server(void) {
	uint16_t plen,dat_p;
	uint8_t cmd_pos=0;
	int8_t cmd, i;
	uint8_t payloadlen=0;
	char str[30];
	char cmdval;

	delay_ms(200);

	/* 初始化点亮红色LED */
	LED_R_ON;
	i = CMD_LED_R_ON;

	/*initialize enc28j60*/
	enc28j60Init(mymac);
	// change clkout from 6.25MHz to 12.5MHz
	enc28j60clkout(2);
	delay_ms(20);

	/* Magjack leds configuration, see enc28j60 datasheet, page 11 */
	// LEDB=yellow LEDA=green
	// 0x476 is PHLCON LEDA=links status, LEDB=receive/transmit
	// enc28j60PhyWrite(PHLCON,0b0000 0100 0111 01 10);
	enc28j60PhyWrite(PHLCON,0xd76);	//0x476	  
	delay_ms(20);

	//init the ethernet/ip layer:
	init_ip_arp_udp_tcp(mymac,myip,mywwwport);
	printf("Chip var:0x%x \n",enc28j60getrev());

	while(1) {
		// get the next new packet:
		plen = enc28j60PacketReceive(BUFFER_SIZE, buf);

		/*plen will ne unequal to zero if there is a valid packet (without crc error) */
		if(plen==0) {
			continue;
		}

		// arp is broadcast if unknown but a host may also
		// verify the mac address by sending it to a unicast address.
		if(eth_type_is_arp_and_my_ip(buf,plen)) {
			make_arp_answer_from_request(buf);
			printf("make_arp_answer_from_request\n");
			continue;
		}
		
		// check if ip packets are for us:
		if(eth_type_is_ip_and_my_ip(buf,plen)==0) {
			continue;
		}
		
		if(buf[IP_PROTO_P]==IP_PROTO_ICMP_V && buf[ICMP_TYPE_P]==ICMP_TYPE_ECHOREQUEST_V) {
			// a ping packet, let's send pong
			make_echo_reply_from_request(buf, plen);
			printf("make_echo_reply_from_request\n");
			continue;
		}

		/*******************************************/
		/* tcp port www start, compare only the lower byte */
		/*******************************************/
		if (buf[IP_PROTO_P]==IP_PROTO_TCP_V&&buf[TCP_DST_PORT_H_P]==0&&buf[TCP_DST_PORT_L_P]==mywwwport) {
			if (buf[TCP_FLAGS_P] & TCP_FLAGS_SYN_V) {
				make_tcp_synack_from_syn(buf);
				// make_tcp_synack_from_syn does already send the syn,ack
				continue;
			}
			if (buf[TCP_FLAGS_P] & TCP_FLAGS_ACK_V){
				init_len_info(buf); // init some data structures
				// we can possibly have no data, just ack:
				dat_p=get_tcp_data_pointer();
				if (dat_p==0) {
					if (buf[TCP_FLAGS_P] & TCP_FLAGS_FIN_V) {
						// finack, answer with ack
						make_tcp_ack_from_any(buf);
					}
					// just an ack with no data, wait for next packet
					continue;
				}
				if (strncmp("GET ",(char *)&(buf[dat_p]),4)!=0) {
					// head, post and other methods:
					// for possible status codes see: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
					plen=fill_tcp_data_p(buf,0,PSTR("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n<h1>200 OK</h1>"));
					goto SENDTCP;
				}
				if (strncmp("/ ",(char *)&(buf[dat_p+4]),2)==0){
					plen=fill_tcp_data_p(buf,0,PSTR("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n"));
					plen=fill_tcp_data_p(buf,plen,PSTR("<p>Usage: "));
					plen=fill_tcp_data(buf,plen,baseurl);
					plen=fill_tcp_data_p(buf,plen,PSTR("password</p>"));
					goto SENDTCP;
				}
				cmd=analyse_get_url((char *)&(buf[dat_p+5]));
				// for possible status codes see: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
				if (cmd==-1){
					plen=fill_tcp_data_p(buf,0,PSTR("HTTP/1.0 401 Unauthorized\r\nContent-Type: text/html\r\n\r\n<h1>401 Unauthorized</h1>"));
					goto SENDTCP;
				}
				if (cmd==CMD_LED_R_ON){
					LED_R_ON;
					i=CMD_LED_R_ON;
				}
				if (cmd==CMD_LED_R_OFF){
					LED_R_OFF;
					i=CMD_LED_R_OFF;
				}
				if (cmd==CMD_LED_G_ON){
					LED_G_ON;
					i=CMD_LED_G_ON;
				}
				if (cmd==CMD_LED_G_OFF){
					LED_G_OFF;
					i=CMD_LED_G_OFF;
				}
				// if (cmd==-2) or any other value
				// just display the status:
				plen=print_webpage(buf,(i));

SENDTCP:
				make_tcp_ack_from_any(buf); // send ack for http get
				make_tcp_ack_with_data(buf,plen); // send data
				continue;
			}
		}
		
		/****************************************/
		/* udp start, we listen on udp port 1200=0x4B0 */
		/****************************************/
		if (buf[IP_PROTO_P]==IP_PROTO_UDP_V&&buf[UDP_DST_PORT_H_P]==4&&buf[UDP_DST_PORT_L_P]==0xb0) {
			payloadlen=buf[UDP_LEN_L_P]-UDP_HEADER_LEN;
			// you must sent a string starting with v. e.g udpcom version 10.0.0.24
			if (verify_password((char *)&(buf[UDP_DATA_P]))) {
				// find the first comma which indicates the start of a command:
				cmd_pos=0;
				while(cmd_pos<payloadlen) {
					cmd_pos++;
					if (buf[UDP_DATA_P+cmd_pos]==',') {
						cmd_pos++; // put on start of cmd
						break;
					}
				}
				// a command is one char and a value. At least 3 characters long. It has an '=' on position 2:
				if (cmd_pos<2 || cmd_pos>payloadlen-3 || buf[UDP_DATA_P+cmd_pos+1]!='=') {
					strcpy(str,"e=no_cmd");
					goto ANSWER;
				}
				// supported commands are t=0 t=1 t=?
				/* 下面的内容是UDP的, 与WEB页面无关 */
				if (buf[UDP_DATA_P+cmd_pos]=='t'){
					cmdval=buf[UDP_DATA_P+cmd_pos+2];
					if(cmdval=='1'){
						/* 加入动作 */
						IOCLR |= (1<<26);
						strcpy(str,"t=1");
						goto ANSWER;
					} else if(cmdval=='0') {
						/* 加入动作 */
						IOSET |= (1<<26);
						strcpy(str,"t=0");
						goto ANSWER;
					} else if(cmdval=='?') {
						if (IOPIN & (1<<19)){
							strcpy(str,"t=1");
							goto ANSWER;
						}
						strcpy(str,"t=0");
						goto ANSWER;
					}
				}
				strcpy(str,"e=no_such_cmd");
				goto ANSWER;
			}
			strcpy(str,"e=invalid_pw");

ANSWER:
			make_udp_reply_from_request(buf,str,strlen(str),myudpport);
		}
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -