LWIP一句话记住就行:
一项工程,两份配置,三种内存分配,四套操作API,五步初始化,六个"数据流",七个数据结构
-------------------------------------------
前面在第一节乃至后面每一篇我都在强调五步初始化,第三节也实操了一下.
今天呢就详细的再来讲一下这五步初始化的具体操作.
1.xxx_init(网络驱动,一般由具体厂商弄,比如BCM,RTL,AW...)
2.tcpip_init(lwip的初始化流程了)
3.lwip_init(就是一些通用协议,内存,网卡的初始化调用)
4.netif_init(网卡的初始化,同上步还有很多同级的初始化操作)
5.ethernetif_init(底层硬件初始化,上面的netif可以理解为抽象的网卡)
这里我们还是借鉴博通的ap6203来看:
static int bcm_cmd_wifi_init(rt_uint32_t argc, char** argv)
{
rt_kprintf("argc=%d\n", argc);
if (argc > 1)
{
++argv;
--argc;
}
tcpip_init(NULL, NULL);
#ifdef USE_POLLING_MODE
mhd_config_polling(1);
mhd_config_polling_interval(50);
#endif
bcm_wifi_start();
return 0;
}
MSH_CMD_EXPORT_ALIAS(bcm_cmd_wifi_init, bcm_init, Broadcom WiFi Init commands);
这里我们可以主要分两个部分:
1.tcpip_inti()进行协议栈的初始化,也就是后面会提到的lwip_init().
2.mhd_xxx()以及bcm_xxx()这些都是博通网卡的初始化,你可以理解为硬件操作,当然啦这都是不开源的,所以我也没办法帮大家分析了.
但你们知道的我总会给大家带来点特别的东西.于是翻山越岭,终于在<嵌入式网络那些事LWIP协议>一书中找到了一个RTL8019的网卡初始化:
/************************************
**函数名:board_init
**输入参数:无
**输出参数:无
**功能描述:网卡复位与初始化函数
**************************************/
void board_int(void)
{
NE_RESET = 0x11;
Delay(500);
NE_CR = ENCR_PAGE0 + ENCR_NODMA;
NE_DCR = NEDCRVAL;
NE_TPSR = TX_START_PG;
NE_PSTART = RX_START_PG;
NE_STOP = RX_STOP_PG;
NE_BNRY = RX_START_PG;
...
本来想着把代码全部粘贴上来,仔细一看就不要占用我的版面了.因为看不懂,所以我就简单的告诉大家,这就是厂商自己整出来操作一下寄存器.如果你恰好在博通,联发科,正基...这些公司,那就更不需要我说了,但是如果不是,哈哈就直接忽略吧.记住有这么一个过程就好.
值得一提的是:
MSH_CMD_EXPORT_ALIAS(bcm_cmd_wifi_init, bcm_init, Broadcom WiFi Init commands);
可以看到集成了一条命令,bcm_init.那么我们可以猜想一下,肯定还有联网,断开,扫描...命令,类似wifimanager.
好了我们接着来看重点:lwip/src/api/tcpip.c
/**
* @ingroup lwip_os
* Initialize this module:
* - initialize all sub modules
* - start the tcpip_thread
*
* @param initfunc a function to call when tcpip_thread is running and finished initializing
* @param arg argument to pass to initfunc
*/
void
tcpip_init(tcpip_init_done_fn initfunc, void *arg)
{
lwip_init();
tcpip_init_done = initfunc;
tcpip_init_done_arg = arg;
if (sys_mbox_new(&tcpip_mbox, TCPIP_MBOX_SIZE) != ERR_OK) {
LWIP_ASSERT("failed to create tcpip_thread mbox", 0);
}
#if LWIP_TCPIP_CORE_LOCKING
if (sys_mutex_new(&lock_tcpip_core) != ERR_OK) {
LWIP_ASSERT("failed to create lock_tcpip_core", 0);
}
#endif /* LWIP_TCPIP_CORE_LOCKING */
sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, RT_THREAD_PRIORITY_MAX-1);
}
1.调用lwip_init()初始化sub modules.
2.利用sys_mbox_new()创建一个邮箱.
3.利用sys_mutex_new()创建一个锁.
4.利用sys_thread_new()创建一个tcpip_thread线程.
/**
* The main lwIP thread. This thread has exclusive access to lwIP core functions
* (unless access to them is not locked). Other threads communicate with this
* thread using message boxes.
*
* It also starts all the timers to make sure they are running in the right
* thread context.
*
* @param arg unused argument
*/
static void
tcpip_thread(void *arg)
{
struct tcpip_msg *msg;
LWIP_UNUSED_ARG(arg);
LWIP_MARK_TCPIP_THREAD();
LOCK_TCPIP_CORE();
if (tcpip_init_done != NULL) {
tcpip_init_done(tcpip_init_done_arg);
}
while (1) { /* MAIN Loop */
LWIP_TCPIP_THREAD_ALIVE();
/* wait for a message, timeouts are processed while waiting */
TCPIP_MBOX_FETCH(&tcpip_mbox, (void **)&msg);
if (msg == NULL) {
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: NULL\n"));
LWIP_ASSERT("tcpip_thread: invalid message", 0);
continue;
}
tcpip_thread_handle_msg(msg);
}
}
这里我也只把代码先贴出来,后面也会单独来分析.总之tcpip_init()大家先记住上面这四步就行了,重要的两步后面会详细分析.
一些子系统的初始化操作,包括sys,mem,memp,pbuf,tcp,udp,arp…
如果详细的展开讲,那么篇幅就很长很长了,不过呢我之前在百度脑图整了个流程分析.
这里贴上连接,方便大家去跟一下.
https://naotu.baidu.com/file/9a8cb83b68a7ac578aa833079e2f3b83
这里需要重点提出来的就是netif_init(),紧接着下一节我就会单独来分析.
其实这也只是lwip_init()中调用的而已,只是个人觉得很重要就拿出来了.等下一节具体分析吧.
其实这篇博文呢也只是给初始化开个头,因为接下来都会一直停留在初始化阶段,会结合代码详细的分析.大家拭目以待吧.
-------------------------------------------
这期就到这里了,LWIP想怎么玩就怎么玩,我们下期再见.