stm32使用LWIP实现DHCP客户端
LWIP是一款开源的嵌入式网络协议栈,支持的功能很多,而且能在多任务环境下和单任务裸机环境下跑,今天说说他的移植过程,芯片为STM32,网卡为ENC28J60,无操作系统
首先下载LWIP的源代码,我下载的是1.4.1的源码,下载后解压,文件结构如图
将这四个目录中的文件全部拷贝到工程中,API是一些socket通讯的接口,需要在多任务的环境下实现,core里面存放的内核源码,我们主要使用IPV4,include目录下是需要包含的目录,lwip只要求我们包含include目录,里面的内层目录会自动找到,最后建立的工程目录如下
好了,此时源码已经做好,还有需要做的,在include目录下新建一个文件夹,必须叫arch,里面存放这几个文件,自己新建
文件的具体内容如下
cc.h
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __CC_H__
#define __CC_H__ #include "cpu.h" //编译器无关的数据类型定义
typedef unsigned char u8_t;
typedef signed char s8_t;
typedef unsigned short u16_t;
typedef signed short s16_t;
typedef unsigned long u32_t;
typedef signed long s32_t;
typedef u32_t mem_ptr_t;
typedef int sys_prot_t; //lwip调试的时候数据类型定义
#define U16_F "hu"
#define S16_F "d"
#define X16_F "hx"
#define U32_F "u"
#define S32_F "d"
#define X32_F "x"
#define SZT_F "uz" //根据不同的编译器的符号定义
#if defined (__ICCARM__) #define PACK_STRUCT_BEGIN
#define PACK_STRUCT_STRUCT
#define PACK_STRUCT_END
#define PACK_STRUCT_FIELD(x) x
#define PACK_STRUCT_USE_INCLUDES #elif defined (__CC_ARM) #define PACK_STRUCT_BEGIN __packed
#define PACK_STRUCT_STRUCT
#define PACK_STRUCT_END
#define PACK_STRUCT_FIELD(x) x #elif defined (__GNUC__) #define PACK_STRUCT_BEGIN
#define PACK_STRUCT_STRUCT __attribute__ ((__packed__))
#define PACK_STRUCT_END
#define PACK_STRUCT_FIELD(x) x #elif defined (__TASKING__) #define PACK_STRUCT_BEGIN
#define PACK_STRUCT_STRUCT
#define PACK_STRUCT_END
#define PACK_STRUCT_FIELD(x) x #endif #define LWIP_PLATFORM_ASSERT(x) //do { if(!(x)) while(1); } while(0) #endif /* __CC_H__ */
cpu.h
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __CPU_H__
#define __CPU_H__ //定义cpu的数据模式,大端小端
#define BYTE_ORDER LITTLE_ENDIAN #endif /* __CPU_H__ */
perf.h
#ifndef __PERF_H__
#define __PERF_H__ //用于lwip内置的统计功能
//不使能定义为空就可以了
#define PERF_START /* null definition */
#define PERF_STOP(x) /* null definition */ #endif /* __PERF_H__ */
sys_arch.h
#ifndef __SYS_RTXC_H__
#define __SYS_RTXC_H__ void init_lwip_timer(void); //初始化LWIP定时器 u8_t timer_expired(u32_t *last_time,u32_t tmr_interval); //定时器超时判断 #endif /* __SYS_RTXC_H__ */
sya_arch.c--注意该文件要加入源文件列表中,这是c文件哦
#include "lwip/debug.h"
#include "lwip/def.h"
#include "lwip/sys.h"
#include "lwip/mem.h"
#include "timerx.h" //初始化LWIP定时器
void init_lwip_timer(void)
{
TIM6_Int_Init(,);//100Khz计数频率,计数到100为10ms
} //为LWIP提供计时
extern u32_t lwip_timer;//lwip 计时器,每10ms增加1. u32_t sys_now(void)
{
return lwip_timer;
} //定时器超时判断
//last_time:最近时间
//tmr_interval:定时器溢出周期
u8_t timer_expired(u32_t *last_time,u32_t tmr_interval)
{
u32_t time;
time = *last_time;
if((lwip_timer-time)>=tmr_interval){
*last_time = lwip_timer;
return ;
}
return ;
}
可以看到我们定义了定时器,那么就要修改相关的定时器文件,文件如下
timerx.c
#include "timerx.h" u32 lwip_timer=;//lwip 计时器,每10ms增加1. //定时器6中断服务程序
void TIM6_IRQHandler(void)
{ if (TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源
{
TIM_ClearITPendingBit(TIM6, TIM_IT_Update ); //清除TIMx的中断待处理位:TIM 中断源
lwip_timer++;//lwip计时器增加1
} } //基本定时器6中断初始化
//这里时钟选择为APB1的2倍,而APB1为36M
//arr:自动重装值。
//psc:时钟预分频数
//这里使用的是定时器3!
void TIM6_Int_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE); //时钟使能 TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值 计数到5000为500ms
TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 10Khz的计数频率
TIM_TimeBaseStructure.TIM_ClockDivision = ; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位 TIM_ITConfig( TIM6,TIM_IT_Update|TIM_IT_Trigger,ENABLE);//使能定时器6更新触发中断 TIM_Cmd(TIM6, ENABLE); //使能TIMx外设 NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn; //TIM3中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = ; //先占优先级0级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = ; //从优先级3级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
}
timerx.h
#ifndef __TIMER_H_
#define __TIMER_H_ #include "sys.h" void TIM6_Int_Init(u16 arr,u16 psc); #endif
好了,这个时候移植就基本完成了,但是编译是过不了的,因为我们缺少一个配置文件.h,这个文件放哪都可以,只要工程包含这个文件的目录,另外,该文件名称不能改动
lwipopts.h
#ifndef __LWIPOPTS_H__
#define __LWIPOPTS_H__ //回环模式
//#define LWIP_HAVE_LOOPIF 1 /* Prevent having to link sys_arch.c (we don't test the API layers in unit tests) */
#define NO_SYS 1 //是否使用操作系统
#define LWIP_NETCONN 0
#define LWIP_SOCKET 0 #define LWIP_DHCP 1 //使能DHCP模块
#define MEM_ALIGNMENT 4 //必须4字节对齐 曾出现在memset的时候hardfault
#define LWIP_DNS 1 #define MEM_SIZE 16000 //使用多大一块内存做lwip内存
#define TCP_SND_QUEUELEN 40 //tcp发送序列长度
#define MEMP_NUM_TCP_SEG TCP_SND_QUEUELEN #define TCP_MSS 1460
#define TCP_WND (4 * TCP_MSS)
#define TCP_SND_BUF (8 * TCP_MSS) #define ETHARP_SUPPORT_STATIC_ENTRIES 1 #endif /* __LWIPOPTS_H__ */
可以看到,我们没有使用操作系统并且使能了dhcp功能
这时候就可以编译通过了,但是还有一个必须做的工作,移植网卡的驱动到lwip中,
也就是netif文件夹中的ethernetif.c文件,该文件修改为如下内容
//网卡驱动层文件 #if 1 /* don't build, this is only a skeleton, see previous comment */ #include "lwip/def.h"
#include "lwip/mem.h"
#include "lwip/pbuf.h"
#include <lwip/stats.h>
#include <lwip/snmp.h>
#include "netif/etharp.h"
#include "netif/ppp_oe.h"
#include "enc28j60.h"
#include "netif/ethernetif.h"
#include "string.h"
#include "delay.h" /* Define those to better describe your network interface. */
#define IFNAME0 'e'
#define IFNAME1 'n' //MAC地址
const u8 mymac[]={0x99,0x02,0x35,0x04,0x45,0x61}; //MAC地址
//定义发送接受缓冲区
u8 lwip_buf[*]; //返回网卡地址
struct ethernetif
{
struct eth_addr *ethaddr;
/* Add whatever per-interface state that is needed here. */
}; //网卡的初始化
static err_t low_level_init(struct netif *netif)
{
//mac地址
netif->hwaddr_len = ETHARP_HWADDR_LEN;
/* set MAC hardware address */
netif->hwaddr[] = mymac[];
netif->hwaddr[] = mymac[];
netif->hwaddr[] = mymac[];
netif->hwaddr[] = mymac[];
netif->hwaddr[] = mymac[];
netif->hwaddr[] = mymac[]; //最大传输单元
netif->mtu = MAX_FRAMELEN;
if(ENC28J60_Init((u8*)mymac)) //初始化ENC28J60
{
return ERR_IF; //底层网络接口错误
}
//指示灯状态:0x476 is PHLCON LEDA(绿)=links status, LEDB(红)=receive/transmit
//PHLCON:PHY 模块LED 控制寄存器
ENC28J60_PHY_Write(PHLCON,0x0476); netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP; return ERR_OK;
} //从指定网卡输出一部分数据
static err_t low_level_output(struct netif *netif, struct pbuf *p)
{
struct pbuf *q;
int send_len=; #if ETH_PAD_SIZE
pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
#endif for(q = p; q != NULL; q = q->next) {
/* Send the data from the pbuf to the interface, one pbuf at a
time. The size of the data in each pbuf is kept in the ->len
variable. */
//send data from(q->payload, q->len);
memcpy((u8_t*)&lwip_buf[send_len], (u8_t*)q->payload, q->len);
send_len +=q->len;
}
// signal that packet should be sent();
ENC28J60_Packet_Send(send_len,lwip_buf); #if ETH_PAD_SIZE
pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
#endif LINK_STATS_INC(link.xmit); return ERR_OK;
} //从指定网卡读取一帧数据回来
static struct pbuf *low_level_input(struct netif *netif)
{
// struct ethernetif *ethernetif = netif->state;
struct pbuf *p, *q;
u16_t len;
int rev_len=; /* Obtain the size of the packet and put it into the "len"
variable. */
len = ENC28J60_Packet_Receive(MAX_FRAMELEN,lwip_buf); #if ETH_PAD_SIZE
len += ETH_PAD_SIZE; /* allow room for Ethernet padding */
#endif /* We allocate a pbuf chain of pbufs from the pool. */
p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL); if (p != NULL) { #if ETH_PAD_SIZE
pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
#endif /* We iterate over the pbuf chain until we have read the entire
* packet into the pbuf. */
for(q = p; q != NULL; q = q->next) {
/* Read enough bytes to fill this pbuf in the chain. The
* available data in the pbuf is given by the q->len
* variable.
* This does not necessarily have to be a memcpy, you can also preallocate
* pbufs for a DMA-enabled MAC and after receiving truncate it to the
* actually received size. In this case, ensure the tot_len member of the
* pbuf is the sum of the chained pbuf len members.
*/
//read data into(q->payload, q->len);
memcpy((u8_t*)q->payload, (u8_t*)&lwip_buf[rev_len],q->len);
rev_len +=q->len; }
// acknowledge that packet has been read(); #if ETH_PAD_SIZE
pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
#endif LINK_STATS_INC(link.recv);
} else {
//drop packet();
LINK_STATS_INC(link.memerr);
LINK_STATS_INC(link.drop);
} return p;
} /**
* This function should be called when a packet is ready to be read
* from the interface. It uses the function low_level_input() that
* should handle the actual reception of bytes from the network
* interface. Then the type of the received packet is determined and
* the appropriate input function is called.
*
* @param netif the lwip network interface structure for this ethernetif
*/
void ethernetif_input(struct netif *netif)
{
// struct ethernetif *ethernetif;
struct eth_hdr *ethhdr;
struct pbuf *p; // ethernetif = netif->state; /* move received packet into a new pbuf */
p = low_level_input(netif);
/* no packet could be read, silently ignore this */
if (p == NULL) return;
/* points to packet payload, which starts with an Ethernet header */
ethhdr = p->payload; switch (htons(ethhdr->type)) {
/* IP or ARP packet? */
case ETHTYPE_IP:
case ETHTYPE_ARP:
#if PPPOE_SUPPORT
/* PPPoE packet? */
case ETHTYPE_PPPOEDISC:
case ETHTYPE_PPPOE:
#endif /* PPPOE_SUPPORT */
/* full packet send to tcpip_thread to process */
if (netif->input(p, netif)!=ERR_OK)
{ LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));
pbuf_free(p);
p = NULL;
}
break; default:
pbuf_free(p);
p = NULL;
break;
}
} /**
* Should be called at the beginning of the program to set up the
* network interface. It calls the function low_level_init() to do the
* actual setup of the hardware.
*
* This function should be passed as a parameter to netif_add().
*
* @param netif the lwip network interface structure for this ethernetif
* @return ERR_OK if the loopif is initialized
* ERR_MEM if private data couldn't be allocated
* any other err_t on error
*/
err_t ethernetif_init(struct netif *netif)
{
struct ethernetif *ethernetif; LWIP_ASSERT("netif != NULL", (netif != NULL)); ethernetif = mem_malloc(sizeof(struct ethernetif));
if (ethernetif == NULL) {
LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_init: out of memory\n"));
return ERR_MEM;
} #if LWIP_NETIF_HOSTNAME
/* Initialize interface hostname */
netif->hostname = "lwip";
#endif /* LWIP_NETIF_HOSTNAME */ /*
* Initialize the snmp variables and counters inside the struct netif.
* The last argument should be replaced with your link speed, in units
* of bits per second.
*/
NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, LINK_SPEED_OF_YOUR_NETIF_IN_BPS); netif->state = ethernetif;
netif->name[] = IFNAME0;
netif->name[] = IFNAME1;
/* We directly use etharp_output() here to save a function call.
* You can instead declare your own function an call etharp_output()
* from it if you have to do some checks before sending (e.g. if link
* is available...) */
netif->output = etharp_output;
netif->linkoutput = low_level_output; ethernetif->ethaddr = (struct eth_addr *)&(netif->hwaddr[]); /* initialize the hardware */
return low_level_init(netif); } #endif
主要是三个功能,网卡数据输入,网卡数据输入,网卡初始化,而且我们可以看到,lwip的配置是可以支持多个网卡滴
要是没有网卡驱动的可以看我之前的例程,里面有
这时候我们算是完整完成了lwip的移植,现在到了使用阶段了
这是我们的main函数
int main(void)
{
NVIC_Group_Init();//系统默认中断分组
Debug_Serial_Init();
Delay_Init();
Led_Init();
Key_Exti_Init();
LCD_Init();
LCD_Clear(LCD_BLACK); ipaddr.addr = ;
netmask.addr = ;
gw.addr = ;
init_lwip_timer(); //初始化LWIP定时器
//初始化LWIP协议栈,执行检查用户所有可配置的值,初始化所有的模块
lwip_init(); //添加网络接口
while((netif_add(&enc28j60_netif, &ipaddr, &netmask, &gw, NULL, ðernetif_init, ðernet_input)==NULL))
{
LCD_ShowString(,,,,(u8*)"ENC28J60 Init Failed ",LCD_BLACK);
Delay_Ms();
LCD_ShowString(,,,,(u8*)" ",LCD_BLACK);
Delay_Ms();
}
LCD_ShowString(,,,,(u8*)"ENC28J60 Init OK ",LCD_BLACK);
//注册默认的网络接口
netif_set_default(&enc28j60_netif);
//建立网络接口用于处理通信
netif_set_up(&enc28j60_netif); dhcp_start(&enc28j60_netif); //为网卡创建一个新的DHCP客户端 while()
{
LWIP_Polling();
Led_Set(,);
Delay_Ms();
Led_Set(,);
Delay_Ms();
}
}
初始化定时器,初始化协议栈,添加网络接口(该函数同时完成网卡的初始化,mac地址在之前的文件中),注册网络接口,建立网络通讯接口,因为是dhcp,所以完全不用管网络的地址是多少,直接给0,后面他会自己获得到的
接下来启动dhcp服务,因为是裸机程序,没有多任务再跑,所以我们必须轮询系统事件并处理,也就是LWIP_Polling(),该函数如下
#define CLOCKTICKS_PER_MS 10 //定义时钟节拍 static ip_addr_t ipaddr, netmask, gw; //定义IP地址
struct netif enc28j60_netif; //定义网络接口
u32_t input_time;
u32_t last_arp_time;
u32_t last_tcp_time;
u32_t last_ipreass_time; u32_t last_dhcp_fine_time;
u32_t last_dhcp_coarse_time;
u32 dhcp_ip=; //LWIP查询
void LWIP_Polling(void)
{
if(timer_expired(&input_time,)) //接收包,周期处理函数
{
ethernetif_input(&enc28j60_netif);
}
if(timer_expired(&last_tcp_time,TCP_TMR_INTERVAL/CLOCKTICKS_PER_MS))//TCP处理定时器处理函数
{
tcp_tmr();
}
if(timer_expired(&last_arp_time,ARP_TMR_INTERVAL/CLOCKTICKS_PER_MS))//ARP处理定时器
{
etharp_tmr();
}
if(timer_expired(&last_ipreass_time,IP_TMR_INTERVAL/CLOCKTICKS_PER_MS))//IP重新组装定时器
{
ip_reass_tmr();
}
if(timer_expired(&last_dhcp_fine_time,DHCP_FINE_TIMER_MSECS/CLOCKTICKS_PER_MS))//dhcp服务
{
dhcp_fine_tmr();
}
if(timer_expired(&last_dhcp_coarse_time,DHCP_COARSE_TIMER_MSECS/CLOCKTICKS_PER_MS))//dhcp服务
{
dhcp_coarse_tmr();
}
}
在循环中处理好相应的事件,因为我们没建立tcp链接所以tcp其实可以不要,另外dhcp服务使用的是udp,端口使用的是udp的57,58
到这里编译连接,系统启动就能查看到路由器自动分配的IP了
具体工程在下面下载
http://download.csdn.net/detail/dengrengong/8548851
stm32使用LWIP实现DHCP客户端的更多相关文章
- 电脑无法上网,DHCP客户端不能正确获取IP地址
问题特征:DHCP服务器更新[保留]配置信息后,给一客户端绑定了新的IP地址;但客户端IP地址并未正确更新; 处理: 一.检查DHCP服务器配置; 1.MAC地址.IP地址均正确;并已“添加到筛选器” ...
- (五)Cisco dhcp snooping实例3-多交换机环境(DHCP服务器和DHCP客户端位于同VLAN)
试验拓扑 环境:dhcp server和dhcp客户端属于同vlan,但是客户端属于不同的交换机,在L2和L3交换机开启dhcp snooping后得出如下结论 L3交换机的配置 ip dhcp po ...
- (四)Cisco dhcp snooping实例2-多交换机环境(DHCP服务器和DHCP客户端位于不同VLAN)
试验拓扑 环境:dhcp server和客户端处于不同网段的情况 dhcp server的配置 no ip routing ip dhcp pool vlan27 network 172.28.27. ...
- (三)Cisco dhcp snooping实例1-单交换机(DHCP服务器和DHCP客户端位于同一VLAN)
环境:cisco dhcp server和客户端都属于vlan27,dhcp server 接在交换机G0/1,客户端接在交换机的G0/2 cisco dhcp server相关配置 ip dhcp ...
- lwip TCP client 客户端 & FreeRTOS
static void tcpecho_thread(void *arg) { ip_addr_t serverIpAddr; struct netbuf *buf; void *data; u16_ ...
- 抓DHCP客户端ip脚本
cat testnew.sh #!/bin/bash catch_ip (){Ip=`sudo nmap -sP 192.168.1.0/24 |grep -i -B2 $mac|grep Nmap ...
- LWIP在STM32上的移植
本文做记录摘抄,加上自己的体会: 文章标题:STM32使用LWIP实现DHCP客户端 http://www.cnblogs.com/dengxiaojun/p/4379545.html 该文章介绍了几 ...
- stm32 学习参考(转)
源:stm32 学习参考 单片机裸机下写一个自己的shell调试器 LWIP_STM32_ENC28J60_NETCONN_TCP_SERVICER(5) LWIP_STM32_ENC ...
- stm32+lwip(一):使用STM32CubeMX生成项目
我是卓波,很高兴你来看我的博客. 系列文章: stm32+lwip(一):使用STM32CubeMX生成项目 stm32+lwip(二):UDP测试 stm32+lwip(三):TCP测试 stm32 ...
随机推荐
- Photos FrameWork 续
1. Model PHAsset .PHAssetCollection.PHCollectionList 是Photos框架中的模型类,PHAsset类模型是图片或者视频文件数据:PHAssetCol ...
- php截取中文字符串,英文字符串,中英文字符串长度的方法
今天学习了php函数截取中文字符串,英文字符串,中英文字符串的函数使用方法.对中英文截取方法不理解,此处先做记录. PHP自带的函数如strlen().mb_strlen()都是通过计算字符串所占字节 ...
- 激活OFFICE2010时,提示choice.exe不是有效的win32程序
我在安装office2010破解版时,提示choice.exe不是有效的win32应用程序 删除choice.exe再激活,按提示找到目录删掉这个文件,需要设置显示隐藏文件夹
- 最小生成树Prim
首先解释什么是最小生成树,最小生成树是指在一张图中找出一棵树,任意两点的距离已经是最短的了. 算法要点: 1.用book数组存放访问过的节点. 2.用dis数组保存对应下标的点到树的最近距离,这里要注 ...
- Android Studio的使用(五)--导入第三方Jar包
本篇博文将介绍一下如何导入第三方Jar包. 1.首先将下载的Jar包直接Copy到libs目录下面,然后右击Jar文件,点击Add As Library后,在出现的弹出框点击确定即可. 2.打开bui ...
- Centos下安装jdk详解
环境: 系统: [root@Wulaoer ~]# cat /proc/version Linux version 2.6.32-431.el6.x86_64 (mockbuild@c6b8.bsys ...
- 解决:无法将“Add-Migration”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确,然后再试一次
1.输入的中划线“-”格式不对,检查是否为全角状态下输入,误输入了下划线“_",或是前后有空格: 2.没有引用EntityFramework命令,请执行如下名称(Import-Module ...
- jstat undocumented
jstat -J-Djstat.showUnsupported=true -name btrace.com.sun.btrace.samples.ThreadCounter.count 11674 h ...
- jpda
http://www.ibm.com/developerworks/cn/java/j-lo-jpda1/ 远程调试用rmi通信,被调试端需要启动一个调试服务器,用命令jsadebugd. java/ ...
- javascript 之Function对象的apply(),call(),bind(),方法和arguments,caller,length属性
注:这篇文章原文:http://www.jb51.net/article/30883.htm 自己作为学习,重新写写. 一.写在前面的话 前端javascript编程还只是略懂皮毛,DOM知道一点,j ...