发现一个很简单的以太网协议实现,网上有人称之为EncEthernet,不知道它的正宗名称是什么,姑且称之为EncEthernet吧。
它只支持ARP、ICMP(ping)、TCP和UDP协议。Keil编译后,ROM占用不到3K,RAM占用不到2K,真是非常mini。
如果单片机资源有限,可以考虑使用EncEthernet。
EncEthernet只有三个文件:
net.h 定义一些常量
ip_arp_udp_tcp.h 协议函数定义头文件
ip_arp_udp_tcp.c 协议函数实现C文件
以下是协议实现的主要函数:
void init_ip_arp_udp_tcp(unsigned char *mymac,unsigned char *myip,unsigned int port); //协议初始化函数
unsigned char eth_type_is_arp_and_my_ip(unsigned char *buf,unsigned int len); //判断是否为arp包
unsigned char eth_type_is_ip_and_my_ip(unsigned char *buf,unsigned int len); //判断是不是ip包
void make_arp_answer_from_request(unsigned char *buf); //arp回复
void make_echo_reply_from_request(unsigned char *buf,unsigned int len); //ping 回复
void make_udp_reply_from_request(unsigned char *buf,char *data,unsigned char datalen,unsigned int port); //udp回复
void make_tcp_synack_from_syn(unsigned char *buf); //tcp握手
unsigned int get_tcp_data_pointer(void); //获得tcp包携带的data位置
void make_tcp_ack_from_any(unsigned char *buf); //应答ack
void make_tcp_ack_with_data(unsigned char *buf,unsigned int dlen);应答ack+data
移植EncEthernet,需要修改ip_arp_udp_tcp.c 文件里的网卡的数据包发送函数。make_arp_answer_from_request、make_echo_reply_from_request、make_udp_reply_from_request、make_tcp_ack_with_data等函数末尾都有引用数据包发送函数。
EncEthernet没有tcp连接管理。如果需要管理tcp连接,tcp连接管理可以参考lwip。
下面是主函数main的编写,我移植的是stm32f103c8t6+enc28j60
#include "ip_arp_udp_tcp.h"
#include "net.h"
#define BUFFER_SIZE 1500
unsigned char buf[BUFFER_SIZE + 1]; //定义收发缓冲区
unsigned char mymac[6] = {0x54, 0x55, 0x58, 0x10, 0x00, 0x24};
unsigned char myip[4] = {192, 168, 10, 25};
unsigned int mytcpport = 2000;
int main(void)
{
unsigned int plen;
unsigned int dat_p;
enc28j60_init(mymac); //enc28j60初始化,里面包含spi的初始化
init_ip_arp_udp_tcp(mymac, myip, mytcpport);
while(1)
{
plen = enc28j60_packet_receive(buf, BUFFER_SIZE);
if(plen == 0) continue;
if(eth_type_is_arp_and_my_ip(buf, plen))
{
make_arp_answer_from_request(buf);
continue;
}
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)
{
make_echo_reply_from_request(buf, plen);
continue;
}
if (buf[IP_PROTO_P] == IP_PROTO_TCP_V && buf[TCP_DST_PORT_H_P] ==(mytcpport>>8) && buf[TCP_DST_PORT_L_P] == (mytcpport&0xff))
{
if (buf[TCP_FLAGS_P] & TCP_FLAGS_SYN_V)
{
make_tcp_synack_from_syn(buf); //握手
continue;
}
if (buf[TCP_FLAGS_P] & TCP_FLAGS_ACK_V)
{
init_len_info(buf);
dat_p = get_tcp_data_pointer();
if (dat_p == 0)
{
if (buf[TCP_FLAGS_P] & TCP_FLAGS_FIN_V) //挥手
make_tcp_ack_from_any(buf);
continue;
}
//处理用户自定义数据处理
plen=0;
if (strncmp("data1", (char *) & (buf[dat_p]), 4) == 0)
{
plen = fill_tcp_data_p(buf, 0, "reply");
goto SENDTCP;
}
SENDTCP:
make_tcp_ack_from_any(buf); // 发送ack
if(plen>0)make_tcp_ack_with_data(buf, plen); // 如果有数据则
continue;
}
}
}
}
参考:《STM32F103RC ENC28J60 SPI EXAMPLE》http://www.codeforge.com/article/236406
总结:EncEthernet实现了最基本的arp、icmp、udp和tcp协议,是一个非常轻量级的以太网协议实现。非常适合使用在资源非常有限的单片机里。