LwIP——无操作系统启动流程

news2024/9/21 12:33:41

目录

启动流程

虚拟网卡控制块

发送流程

接收流程

 总结


启动流程

通过阅读正点原子的无操作系统移植工程的源码,可以总结出LwIP的无操作系统的启动流程。

前面一些都是基于其他的外设的初始化,我们只关心这里lwip_comm_init(),这个函数的总流程先给出。 

uint8_t lwip_comm_init(void)
{
    uint8_t retry = 0;
    struct netif *netif_init_flag;              /* 调用netif_add()函数时的返回值,用于判断网络初始化是否成功 */
    ip_addr_t ipaddr;                           /* ip地址 */
    ip_addr_t netmask;                          /* 子网掩码 */
    ip_addr_t gw;                               /* 默认网关 */

    if (ethernet_mem_malloc())return 1;         /* 内存申请失败*/

    lwip_comm_default_ip_set(&g_lwipdev);       /* 设置默认IP等信息 */

    while (ethernet_init())                     /* 初始化以太网芯片,如果失败的话就重试5次 */
    {
        retry++;

        if (retry > 5)
        {
            retry = 0;                          /* 以太网芯片初始化失败 */
            return 3;
        }
    }

    lwip_init();                                /* 初始化LWIP内核 */

#if LWIP_DHCP                                   /* 使用动态IP */
    ipaddr.addr = 0;
    netmask.addr = 0;
    gw.addr = 0;
#else   /* 使用静态IP */
    IP4_ADDR(&ipaddr, g_lwipdev.ip[0], g_lwipdev.ip[1], g_lwipdev.ip[2], g_lwipdev.ip[3]);
    IP4_ADDR(&netmask, g_lwipdev.netmask[0], g_lwipdev.netmask[1], g_lwipdev.netmask[2], g_lwipdev.netmask[3]);
    IP4_ADDR(&gw, g_lwipdev.gateway[0], g_lwipdev.gateway[1], g_lwipdev.gateway[2], g_lwipdev.gateway[3]);
    printf("网卡en的MAC地址为:................%d.%d.%d.%d.%d.%d\r\n", g_lwipdev.mac[0], g_lwipdev.mac[1], g_lwipdev.mac[2], g_lwipdev.mac[3], g_lwipdev.mac[4], g_lwipdev.mac[5]);
    printf("静态IP地址........................%d.%d.%d.%d\r\n", g_lwipdev.ip[0], g_lwipdev.ip[1], g_lwipdev.ip[2], g_lwipdev.ip[3]);
    printf("子网掩码..........................%d.%d.%d.%d\r\n", g_lwipdev.netmask[0], g_lwipdev.netmask[1], g_lwipdev.netmask[2], g_lwipdev.netmask[3]);
    printf("默认网关..........................%d.%d.%d.%d\r\n", g_lwipdev.gateway[0], g_lwipdev.gateway[1], g_lwipdev.gateway[2], g_lwipdev.gateway[3]);
#endif  /* 向网卡列表中添加一个网口 */
    netif_init_flag = netif_add(&g_lwip_netif, (const ip_addr_t *)&ipaddr, (const ip_addr_t *)&netmask, (const ip_addr_t *)&gw, NULL, &ethernetif_init, &ethernet_input);


    if (netif_init_flag == NULL)
    {
        return 4;                             /* 网卡添加失败 */
    }
    else                                      /* 网口添加成功后,设置netif为默认值,并且打开netif网口 */
    {
        netif_set_default(&g_lwip_netif);     /* 设置netif为默认网口 */

        if (netif_is_link_up(&g_lwip_netif))
        {
            netif_set_up(&g_lwip_netif);      /* 打开netif网口 */
        }
        else
        {
            netif_set_down(&g_lwip_netif);
        }
    }

#if LWIP_DHCP                               /* 如果使用DHCP的话 */
    g_lwipdev.dhcpstatus = 0;                 /* DHCP标记为0 */
    dhcp_start(&g_lwip_netif);                /* 开启DHCP服务 */
#endif
    return 0;                               /* 操作OK. */
}

ethernet_mem_malloc:为描述符及缓冲区申请内存,除了这种用算法实现的内存申请函数可以申请内存之外,ST官方给出的例程是使用简单的使用数组来实现申请内存。

/**
 * @breif       为ETH底层驱动申请内存
 * @param       无
 * @retval      0,正常
 *              1,失败
 */
uint8_t ethernet_mem_malloc(void)
{
    g_eth_dma_rx_dscr_tab = mymalloc(SRAMIN, ETH_RXBUFNB * sizeof(ETH_DMADescTypeDef)); /* 申请内存 */
    g_eth_dma_tx_dscr_tab = mymalloc(SRAMIN, ETH_TXBUFNB * sizeof(ETH_DMADescTypeDef)); /* 申请内存 */
    g_eth_rx_buf = mymalloc(SRAMIN, ETH_RX_BUF_SIZE * ETH_RXBUFNB); /* 申请内存 */
    g_eth_tx_buf = mymalloc(SRAMIN, ETH_TX_BUF_SIZE * ETH_TXBUFNB); /* 申请内存 */

    if (!(uint32_t)&g_eth_dma_rx_dscr_tab || !(uint32_t)&g_eth_dma_tx_dscr_tab || !(uint32_t)&g_eth_rx_buf || !(uint32_t)&g_eth_tx_buf)
    {
        ethernet_mem_free();
        return 1;   /* 申请失败 */
    }

    return 0;       /* 申请成功 */
}

ethernet_init:配置以太网环境、初始化RMII的IO(通过调用的HAL_ETH_Init函数,它会调用HAL_ETH_MspInit函数初始化相应的接口IO以及复位PHY芯片管脚)、复位PHY芯片(非常重要,不复位以太网通信不能成功)

/**
 * @brief       以太网芯片初始化
 * @param       无
 * @retval      0,成功
 *              1,失败
 */
uint8_t ethernet_init(void)
{
    uint8_t macaddress[6];

    macaddress[0] = g_lwipdev.mac[0];
    macaddress[1] = g_lwipdev.mac[1];
    macaddress[2] = g_lwipdev.mac[2];
    macaddress[3] = g_lwipdev.mac[3];
    macaddress[4] = g_lwipdev.mac[4];
    macaddress[5] = g_lwipdev.mac[5];

    g_eth_handler.Instance = ETH;
    g_eth_handler.Init.AutoNegotiation = ETH_AUTONEGOTIATION_ENABLE;    /* 使能自协商模式 */
    g_eth_handler.Init.Speed = ETH_SPEED_100M;                          /* 速度100M,如果开启了自协商模式,此配置就无效 */
    g_eth_handler.Init.DuplexMode = ETH_MODE_FULLDUPLEX;                /* 全双工模式,如果开启了自协商模式,此配置就无效 */
    g_eth_handler.Init.PhyAddress = ETHERNET_PHY_ADDRESS;               /* 以太网芯片的地址 */
    g_eth_handler.Init.MACAddr = macaddress;                            /* MAC地址 */
    g_eth_handler.Init.RxMode = ETH_RXINTERRUPT_MODE;                   /* 中断接收模式 */
    g_eth_handler.Init.ChecksumMode = ETH_CHECKSUM_BY_HARDWARE;         /* 硬件帧校验 */
    g_eth_handler.Init.MediaInterface = ETH_MEDIA_INTERFACE_RMII;       /* RMII接口 */

    if (HAL_ETH_Init(&g_eth_handler) == HAL_OK)
    {
        return 0;   /* 成功 */
    }
    else
    {
        return 1;  /* 失败 */
    }
}

lwip_init:初始化LwIP内核,它是LwIP内核源码自带的函数,初始化了一系列函数,如sys_init()、mem_init()、pbuf_init()、netif_init()。

添加虚拟网卡

LwIP是软件,如何管理真正的以太网硬件呢,比如网络接口有多种,如WIFI接口、以太网接口,怎么管理这些实际的网络接口,LwIP抽象了一个虚拟网卡来管理这些各种硬件网络接口。

ethernetif_init:网卡初始化,设置虚拟网卡参数,该函数在ethernetif.c文件中已经帮我们实现好了整体框架。它会调用low_level_init函数,该函数初始化发送和接收描述符,并开启ETH中断。

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.
    */
    MIB2_INIT_NETIF(netif, snmp_ifType_ethernet_csmacd, LINK_SPEED_OF_YOUR_NETIF_IN_BPS);

    netif->state = ethernetif;
    netif->name[0] = IFNAME0;
    netif->name[1] = 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...) */
#if LWIP_IPV4
    netif->output = etharp_output;
#endif /* LWIP_IPV4 */
#if LWIP_IPV6
    netif->output_ip6 = ethip6_output;
#endif /* LWIP_IPV6 */
    netif->linkoutput = low_level_output;

    ethernetif->ethaddr = (struct eth_addr *) & (netif->hwaddr[0]);

    /* initialize the hardware */
    low_level_init(netif);

    return ERR_OK;
}

low_level_init:初始化发送和接收描述符,并开启ETH中断。

static void
low_level_init(struct netif *netif)
{
    netif->hwaddr_len = ETHARP_HWADDR_LEN; /* 设置MAC地址长度,为6个字节 */
    /* 初始化MAC地址,设置什么地址由用户自己设置,但是不能与网络中其他设备MAC地址重复 */
    netif->hwaddr[0] = g_lwipdev.mac[0]; 
    netif->hwaddr[1] = g_lwipdev.mac[1]; 
    netif->hwaddr[2] = g_lwipdev.mac[2];
    netif->hwaddr[3] = g_lwipdev.mac[3];   
    netif->hwaddr[4] = g_lwipdev.mac[4];
    netif->hwaddr[5] = g_lwipdev.mac[5];
    
    netif->mtu = 1500; /* 最大允许传输单元,允许该网卡广播和ARP功能 */

    /* 网卡状态信息标志位,是很重要的控制字段,它包括网卡功能使能、广播 */
    /* 使能、 ARP 使能等等重要控制位 */
    netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;   /* 广播 ARP协议 链接检测 */
    
    HAL_ETH_DMATxDescListInit(&g_eth_handler,g_eth_dma_tx_dscr_tab,g_eth_tx_buf,ETH_TXBUFNB); /* 初始化发送描述符 */
    HAL_ETH_DMARxDescListInit(&g_eth_handler,g_eth_dma_rx_dscr_tab,g_eth_rx_buf,ETH_RXBUFNB); /* 初始化接收描述符 */
    HAL_ETH_Start(&g_eth_handler); /* 开启ETH */
}

ethernet_input:以太网数据包输入,这里LwIP默认已经帮我们实现好了框架。

开启虚拟网卡:通过netif_add添加一个网口该函数实现如下:

    netif_init_flag = netif_add(&g_lwip_netif, (const ip_addr_t *)&ipaddr, (const ip_addr_t *)&netmask, (const ip_addr_t *)&gw, NULL, &ethernetif_init, &ethernet_input);

 网口添加成功之后,设置netif为默认值,并且打开netif网口。

else                                      /* 网口添加成功后,设置netif为默认值,并且打开netif网口 */
    {
        netif_set_default(&g_lwip_netif);     /* 设置netif为默认网口 */

        if (netif_is_link_up(&g_lwip_netif))
        {
            netif_set_up(&g_lwip_netif);      /* 打开netif网口 */
        }
        else
        {
            netif_set_down(&g_lwip_netif);
        }
    }

虚拟网卡控制块

发送流程

接收流程

接收有两种方式接收数据包,一种是查询式接收数据包,一种是中断方式接收数据包。

 总结

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/80094.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

eve-ng ubuntu 20.04 设置iptables

eve-ng ubuntu 20.04 设置iptables一、设置方法1、建立iptables规则开机加载脚本2、建立iptables规则关机/重启保存脚本3、添加可执行权限4、保存当前iptables规则到配置文件二、命令解释一、设置方法 1、建立iptables规则开机加载脚本 sudo vi /etc/network/if-pre-up.d/ipt…

(十一)Vue之条件渲染

文章目录v-if与v-else-if、v-else一起使用v-show关于 <template>标签Vue学习目录 上一篇&#xff1a;&#xff08;十&#xff09;Vue之绑定样式 v-if v-if&#xff0c;默认为true&#xff0c;如果为false&#xff0c;底层实现是直接把这个节点删除 适用于&#xff1a;…

MLE,MAP,经验风险最小化,结构风险最小化,邻域风险最小化

文章目录Maximun likelihood extimationMaximum A Posterior EstimationVicinal Risk Minimization, VRMMaximun likelihood extimation 最大似然估计:样本->参数,完全相信观测到的数据,最优可能产生这些看到的数据的模型就是最理想的模型. 频率学派认为,参数是一个常数,不…

fpga实操训练(基础)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 之前我们虽然说过怎么编写verilog代码&#xff0c;怎么用iverilog软件和gtkwave软件进行仿真验证&#xff0c;但是一直没有说明如何在真实的板子上…

web前端期末大作业——基于HTML+CSS+JavaScript仿蘑菇街时尚服装购物商城

常见网页设计作业题材有 个人、 美食、 公司、 学校、 旅游、 电商、 宠物、 电器、 茶叶、 家居、 酒店、 舞蹈、 动漫、 服装、 体育、 化妆品、 物流、 环保、 书籍、 婚纱、 游戏、 节日、 戒烟、 电影、 摄影、 文化、 家乡、 鲜花、 礼品、 汽车、 其他等网页设计题目, A…

28个你应该知道的JavaScript技巧

今天我将分享一些Javascript中的常用技巧&#xff0c;以帮助您解决问题。设置过程中的常见问题更快更容易。 01、Javascript 反向字符串 下面是代码&#xff1a; /*niemvuilaptrinh.com*/const stringReverse str > str.split("").reverse().join("")…

搜索引擎项目测试报告

目录单元测试构建索引模块文档信息对象Document的构建的单元测试**针对每一篇文档进行分析、处理、分词**针对文档内容提取关键字的测试&#xff08;正则表达式&#xff09;测试去掉script测试去掉标签完整测试Document类中的parseContent方法关于ansj分词器的测试关于构建倒排…

CleanMyMac4.12.2最新免费的macOS电脑清理工具

相信不少的小伙伴都在用苹果电脑&#xff0c;不论是 iMac&#xff0c;还是 MacBook&#xff0c;用着用着电脑就变慢了。这通病与苹果电脑的性能无关&#xff0c;主要是硬盘空间不足的问题&#xff01;当然你可以在购买电脑的时候就把硬盘升级&#xff0c;但主要的问题是 – 没有…

python代码圣诞树你还没有嘛?所有画法都在这篇文章里拉~

前言 嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~ 今天&#xff0c;我就来给大家分享一下python制作的几种圣诞树吧~ 一&#xff1a;唯美圣诞 代码展示 导入模块 完整源码点击领取即可 import turtle as t from turtle import * import random as r import time n 100.0spee…

【JavaWeb】Tomcat的入门使用

1Tomcat的相关概念: Tomcat是Apache软件基金会一个核心项目&#xff0c;是一个开源免费的轻量级Web服务器&#xff0c;支持Servlet/JSP少量JavaEE规范。 概念中提到了JavaEE规范&#xff0c;那什么又是JavaEE规范呢? JavaEE: Java Enterprise Edition,Java企业版。指Java企业…

5年Java开发干到月薪38k?当初实习期2.5k的苦我也吃过...

每一个能在所属行业中成为佼佼者的人&#xff0c;一定都会有他自己的独到的见解以及成长方法......这个观点我非常认同&#xff0c;我不自诩自己是个大佬&#xff0c;但现在也算是做出了头&#xff0c;我从刚毕业做 Java 实习生月薪 2.5k&#xff0c;到现在干了 5 年 Java 开发…

仿雷速体育app踢足球tab

MyTabLayout MyTabLayout用法参照BaseLibrary的Demo GitHub仓库地址 效果图 引入 gradle allprojects {repositories {maven { url https://jitpack.io }} }implementation com.github.DL-ZhangTeng:BaseLibrary:2.3.0属性 MyTabLayout属性名描述&#xff1a;可参考原生控…

Chat GPT使用体验,它真的好厉害!!!

最近的chat GTP很火&#xff0c;起因是OpenAI发布了一个全新的聊天机器人模型。就连马斯克也在感叹“很多人疯狂地陷入了 ChatGPT 循环中”&#xff0c;“ChatGPT 好得吓人&#xff0c;我们离强大到危险的人工智能不远了”。 官方的介绍是&#xff0c;这一模型可以与人类进行谈…

人类特有本能:保护族群老弱病残

人有哪些特有的本能&#xff1f; - 知乎 对于动物群体来说&#xff0c;受伤了就不管了&#xff0c;自生自灭。对于人类来说&#xff0c;受伤了尽量照顾恢复。这看起来吃亏&#xff0c;实际上划算。一个成年人&#xff0c;长大需要20年&#xff0c;受伤恢复只要3个月。 远方青木…

全新CorelDRAW2023最新版矢量图软件功能简介

CorelDRAW2023简介 &#xff1a;设计绘画 CorelDraw 是一个绘图与排版的软件&#xff0c;它广泛地应用于商标设计、标志制作、模型绘制、插图描画、排版及分色输出等诸多领域。 作为一个强大的绘图软件&#xff0c;它被喜爱的程度可用下面的事实说明&#xff1a;用作商业设计和…

WPFUI LiveCharts使用记录(一)柱状图

前言&#xff1a;LiveCharts是一个图标控件库集&#xff0c;可以实现柱状图、折线图、饼图、仪表盘等图表控件。而且最新版本支持全平台使用&#xff0c;实现的样例展示可以点击查看作者Alberto Rodrguez的 github仓库 1.背景 1.1 新建项目 这篇文章使用的是.NET framework4.…

Foxmail升级后图片链接乱

升级后默认勾选了总是以纯文本格式阅读邮件。 在设置-高级-中取消勾选

ZooKeeper组件的核心知识总结,吐血总结,一文带你学会

文章目录数据模型数据存储Watch机制会话机制ACL权限序列化方式集群ZAB协议日志清理实现分布式锁实现分布式ID实现负载均衡开源框架使用案例Zookeeper 基本介绍Apache ZooKeeper 是由Apache Hadoop的子项目发展而来&#xff0c;为分布式应用提供高效且可靠的分布式协调服务。 在…

java计算机毕业设计ssm医院管理系统3w16k(附源码、数据库)

java计算机毕业设计ssm医院管理系统3w16k&#xff08;附源码、数据库&#xff09; 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。…

【应用】OPC 通讯协议

OPC 通讯协议OPC 通讯协议基础OPC 简介OPC 与 OPC UAOPC 逻辑对象模型OPC 通信方式Java 实现 OPC 的方式Java 实现 OPC-clientOPC-DAOPC-UA模拟数据进行代码测试OPC-DA 代码验证OPC-UA 代码验证OPC 通讯协议基础 OPC 简介 OPC 全称 OLE For Process Control&#xff0c;即用于…