文档库 最新最全的文档下载
当前位置:文档库 › LWIP移植说明文档

LWIP移植说明文档

LWIP移植说明文档
LWIP移植说明文档

LwIP移植说明文档

该译文以LwIP-1.4.0的移植文档为蓝本

本文档翻译了LwIP-1.4.0的移植说明文档,包括原始API及SYS_ARCH接口的说明文档。由于译者水平所限,译文存在很多不确切或错误的翻译,还请网友多指正。需要特别提出的是,LwIP的SYS_ARCH 接口部分参考了焦海波“uC/OS-II 平台下的 LwIP 移植笔记”一文。在此,将译文放在网络上共享,愿与网友共同学习、共同进步。

INTRODUCTION

lwIP is a small independent implementation of the TCP/IP protocol suite that has been developed by Adam Dunkels at the Computer and Networks Architectures (CNA) lab at the Swedish Institute of Computer Science (SICS).

LwIP是一个TCP/IP协议簇的小型独立实现,该协议簇由瑞士SICS计算机网络实验室的Adam开发。

The focus of the lwIP TCP/IP implementation is to reduce the RAM usage while still having a full scale TCP. This making lwIP suitable for use in embedded systems with tens of kilobytes of free RAM and room for around 40 kilobytes of code ROM.

LwIP TCP/IP实现关注的是减小RAM的使用,同时拥有完整尺度的TCP协议。这使得LwIP适合于在只拥有数十k字节RAM和40k左右ROM的嵌入式系统中使用。

FEATURES

特性

* IP (Internet Protocol) including packet forwarding over multiple network interfaces Internet协议:包括通过多接口发送报文

* ICMP (Internet Control Message Protocol) for network maintenance and debugging Internet控制报文协议:用于网络维护和调试

* IGMP (Internet Group Management Protocol) for multicast traffic management Internet组管理协议:用于多播通信管理

* UDP (User Datagram Protocol) including experimental UDP-lite extensions 用户数据报协议:包括实验性UDP扩展

* TCP (Transmission Control Protocol) with congestion control, RTT estimation and fast recovery/fast retransmit

传输控制协议:拥有阻塞控制、RTT估计和快速恢复、快速传输等功能。

* Specialized raw/native API for enhanced performance

专门的原始API用于提高性能。

* Optional Berkeley-like socket API

可选的伯克利形式SOCKET的API

* DNS (Domain names resolver)

域名解析(域名系统)

* SNMP (Simple Network Management Protocol)

简单网络管理协议

* DHCP (Dynamic Host Configuration Protocol)

动态主机配置协议

* AUTOIP (for IPv4, conform with RFC 3927)

自动IP

* PPP (Point-to-Point Protocol)

点对点传输协议

* ARP (Address Resolution Protocol) for Ethernet

英特网地址解析协议

Raw TCP/IP interface for lwIP

LwIP原始TCP/IP接口

Authors: Adam Dunkels, Leon Woestenberg, Christiaan Simons

作者:Adam Dunkels, Leon Woestenberg, Christiaan Simons

翻译:Lizhiming

lwIP provides three Application Program's Interfaces (APIs) for programs to use for communication with the TCP/IP code:

* low-level "core" / "callback" or "raw" API.

* higher-level "sequential" API.

* BSD-style socket API.

LwIP为程序(上层应用程序)提供了三种应用程序接口,用于和TCP/IP的代码通信,三种接口如下:

* 底层的“内核”/“回调函数”或“原始”API

* 较高层次的有序API

* BSD样式的套接 API

The sequential API provides a way for ordinary, sequential, programs to use the lwIP stack. It is quite similar to the BSD socket API. The model of execution is based on the blocking open-read-write-close paradigm. Since the TCP/IP stack is event based by nature, the TCP/IP code and the application program must reside in different execution contexts (threads). 有序API提供一种常规、有序的编程方法来使用LwIP堆栈。其非常相似于BSD套接API。其执行模型是基于阻塞的打开-读-写-关闭的范式。由于TCP/IP本质上是事件驱动的,TCP/IP代码和应用程序必须驻留在不同的线程中。

The socket API is a compatibility API for existing applications, currently it is built on top of the sequential API. It is meant to provide all functions needed to run socket API applications running on other platforms (e.g. unix / windows etc.). However, due to limitations in the specification of this API, there might be incompatibilities that require small modifications of existing programs.

套接API是一个与现有应用程序兼容的API,当前,它是建立在有序API的基础之上。它为需要在其他平台(如Unix 和Windows等)运行的套接API的应用程序提供完整的功能。但由于API在规格方面的限制,现有程序可能存在与之不兼容的地方,进而需要微小的调整。

** Threading

线程

lwIP started targeting single-threaded environments. When adding multi-threading support, instead of making the core thread-safe, another approach was chosen: there is one main thread running the lwIP core (also known as the "tcpip_thread"). The raw API may only be used from this thread! Application threads using the sequential- or socket API communicate with this main thread through message passing.

LwIP最初以单线程环境为目标。当加入多线程支持时,鉴于内核线程安全的考量,采取了另一种方法:一个主线程运行LwIP内核(也被称作“tcpip_thread”)。原始API可能只在该线程中使用。应用程序线程采用有序API或套接API 通过消息投递与主线程通信。

As such, the list of functions that may be called from other threads or an ISR is very limited! Only functions from these API header files are thread-safe:

- api.h

- netbuf.h

- netifapi.h

- sockets.h

- sys.h

同样地,被其他线程或中断服务程序调用的函数是非常地有限。只有如下API头文件中的函数是线程安全的:

- api.h

- netbuf.h

- netdb.h

- netifapi.h

- sockets.h

- sys.h

Additionaly, memory (de-)allocation functions may be called from multiple threads (not ISR!) with NO_SYS=0 since they are protected by SYS_LIGHTWEIGHT_PROT and/or semaphores. 此外,当NO_SYS=0时,内存的分配和释放函数可能被多个线程(不是中断服务程序)调用,因此它们(需)通过SYS_LIGHTWEIGHT_PROT宏定义和(或)信号量来保护。

Only since 1.3.0, if SYS_LIGHTWEIGHT_PROT is set to 1 and

LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT is set to 1, pbuf_free() may also be called from another thread or an ISR (since only then, mem_free - for PBUF_RAM - may be called from an ISR: otherwise, the HEAP is only protected by semaphores).

仅从1.3.0版本开始,如果SYS_LIGHTWEIGHT_PROT置1,pbuf_free()可由其他线程或中断服务程序调用(仅从那时开始,对PBUF_MEM的mem_free函数可能被其他中断服务程序调用:否则,HEAP仅能通过信号量保护)。

** The remainder of this document discusses the "raw" API. **

该文档的以下内容讨论原始API

The raw TCP/IP interface allows the application program to integrate better with the TCP/IP code. Program execution is event based by having callback functions being called from within the TCP/IP code. The TCP/IP code and the application program both run in the same thread. The sequential API has a much higher overhead and is not very well suited for small systems since it forces a multithreaded paradigm on the application.

原始TCP/IP接口允许应用程序与TCP/IP代码更好的集成。应用程序的执行是通过调用TCP/IP代码中的回调函数来实现事件驱动的。TCP/IP代码和应用程序运行在同一个进程里。有序API模式需要较高的开销,其不适合于小型的系统,因此,迫使应用程序使用多线程范式。

The raw TCP/IP interface is not only faster in terms of code execution time but is also less memory intensive. The drawback is that program development is somewhat harder and application programs written for the raw TCP/IP interface are more difficult to understand. Still, this is the preferred way of writing applications that should be small in code size and memory usage.

原始API不仅在代码执行方面更快,其对存储器密度要求也较低。缺点是程序开发较为困难,为原始API写的应用程序较难于理解。然而,对于要求具有较小的代码尺寸和内存使用的场合,其不失为一种受欢迎的方式。

Both APIs can be used simultaneously by different application programs. In fact, the sequential API is implemented as an application program using the raw TCP/IP interface.

各种API可以同时被不同的应用程序调用(使用)。事实上,有序API是采用原始API接口实现的一个应用程序。

--- 回调函数

Program execution is driven by callbacks. Each callback is an ordinary C function that is called from within the TCP/IP code. Every callback function is passed the current TCP or UDP connection state as an argument. Also, in order to be able to keep program specific state, the callback functions are called with a program specified argument that is independent of the TCP/IP state.

程序的执行有回调函数驱动。每个回调函数都是一个普通的C函数,这些C函数由TCP/IP代码调用。每一个回调函数作为参数传递当前的TCP或UDP连接状态。同时,为了能够保持程序的特定状态,回调函数被指定参数的程序调用,回调函数与TCP/IP状态无关。

The function for setting the application connection state is:

用于设置应用程序的连接状态的函数是:

- void tcp_arg(struct tcp_pcb *pcb, void *arg)

Specifies the program specific state that should be passed to all other callback functions. The "pcb" argument is the current TCP connection control block, and the "arg" argument is the argument that will be passed to the callbacks.

指定程序的特定状态,该程序的返回句柄应传递给所有其他的回调函数。“pcb”参数是当前TCP连接控制块;“arg”参数是回调函数返回时的状态参数。(该函数有两个参数,pcb是用户分配的TCP连接控制块;arg是回调函数返回时,存放回调函数某些参数或状态的指针;该函数返回的句柄应作为参数传递给其他回调函数)

--- TCP connection setup

--- TCP连接建立

The functions used for setting up connections is similar to that of the sequential API and of the BSD socket API. A new TCP connection identifier (i.e., a protocol control block - PCB) is created with the tcp_new() function. This PCB can then be either set to listen for new incoming connections or be explicitly connected to another host.

用于建立连接的函数类似于有序API和BSD套接API。一个新的TCP连接标识(如,协议控制块PCB)通过tcp_new()函数创建。创建完毕,该PCB即可用于监听新到来的连接,也可明确地连接到其他主机。

- struct tcp_pcb *tcp_new(void)

Creates a new connection identifier (PCB). If memory is not available for creating the new pcb, NULL is returned.

创建一个新的连接标识。如果内存不足,返回NULL.

- err_t tcp_bind(struct tcp_pcb *pcb, struct ip_addr *ipaddr,

u16_t port)

Binds the pcb to a local IP address and port number. The IP address can be specified as IP_ADDR_ANY in order to bind the connection to all local IP addresses.

If another connection is bound to the same port, the function will return ERR_USE, otherwise

将pcb绑定到本地IP地址和端口号。为了绑定连接至所有本地IP地址,IP地址可指定为IP_ADDR_ANY。

如果另一个连接已绑定到相同的端口,该函数将返回ERR_USE,否则返回ERR_OK。

- struct tcp_pcb *tcp_listen(struct tcp_pcb *pcb)

Commands a pcb to start listening for incoming connections. When an incoming connection is accepted, the function specified with the tcp_accept() function will be called. The pcb will have to be bound to a local port with the tcp_bind() function.

The tcp_listen() function returns a new connection identifier, and the one passed as an argument to the function will be deallocated. The reason for this behavior is that less memory is needed for a connection that is listening, so tcp_listen() will reclaim the memory needed for the original connection and allocate a new smaller memory block for the listening connection.

tcp_listen() may return NULL if no memory was available for the listening connection. If so, the memory associated with the pcb passed as an argument to tcp_listen() will not be deallocated.

命令一个PCB开始监听即将到来的连接。当新到来的连接被接受,指定tcp_accept()函数将被调用。PCB必须通过tcp_bind()绑定到本地的一个端口。

tcp_listen()返回一个新的连接标识。同时,作为参数传递给该函数的PCB将被释放。原因是处于监听状态的连接仅需少量的内存,因此tcp_listen()将回收初始连接的内存,并为监听连接分配一个新的较小的内存块。

当用于监听连接的内存不足时(不可获得时),tcp_listen()将返回NULL。在这种情况下,作为参数传递给tcp_listen()的内存块将不会被释放。

- struct tcp_pcb *tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog)

Same as tcp_listen, but limits the number of outstanding connections in the listen queue to the value specified by the backlog argument. To use it, your need to set TCP_LISTEN_BACKLOG=1 in your lwipopts.h.

与tcp_listen相同,但限制了在监听队列中未完成(等待)连接的数量,其值由backlog参数指定。使用该函数需在lwipopts.h文件中将TCP_LISTEN_BACKLOG置1。

- void tcp_accepted(struct tcp_pcb *pcb)

Inform lwIP that an incoming connection has been accepted. This would usually be called from the accept callback. This allows lwIP to perform housekeeping tasks, such as allowing further incoming connections to be queued in the listen backlog.

通知LwIP一个新的连接已经被接受。该函数通常被“接受回调函数”调用。这允许LwIP执行内务操作任务,比如允许后续即将到来的连接进入监听后备队列。

- void tcp_accept(struct tcp_pcb *pcb,

err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err))

listening connection.

指定应调用的回调函数,当在一个监听连接上到来一个新的连接时。

- err_t tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr,

u16_t port, err_t (* connected)(void *arg,

struct tcp_pcb *tpcb,

err_t err));

Sets up the pcb to connect to the remote host and sends the initial SYN segment which opens the connection.

The tcp_connect() function returns immediately; it does not wait for the connection to be properly setup. Instead, it will call the function specified as the fourth argument (the "connected" argument) when the connection is established. If the connection could not be properly established, either because the other host refused the connection or because the other host didn't answer, the "err" callback function of this pcb (registered with tcp_err, see below) will be called.

The tcp_connect() function can return ERR_MEM if no memory is available for enqueueing the SYN segment. If the SYN indeed was enqueued successfully, the tcp_connect() function returns ERR_OK.

设置PCB以连接至远程主机,并发送用于打开连接的初始SYN参数。

tcp_connect()函数立即返回;它并不等待连接的正确建立,而是在连接建立时调用第四个参数指定的回调函数。如果连接不能正常建立,或因其他主机拒绝建立连接,或其他主机没有应答,该pcb(以pcb_err注册,见下文)的“err”回调函数将被调用。

如果对入队的SYN参数没有可获得的内存,tcp_connect()将返回ERR_MEM。如果SYN参数成功入队,tcp_connect()将返回ERR_OK。

--- Sending TCP data

--- 发送TCP数据

TCP data is sent by enqueueing the data with a call to tcp_write(). When the data is successfully transmitted to the remote host, the application will be notified with a call to a specified callback function.

TCP数据的发送是通过入队数据并调用tcp_write()来实现的。当数据成功传输至远程主机时,远程主机调用指定的回调函数通知应用程序。

- err_t tcp_write(struct tcp_pcb * pcb, void *dataptr, u16_t len,u8_t copy)

Enqueues the data pointed to by the argument dataptr. The length of the data is passed as the len parameter. The copy argument is either 0 or 1 and indicates whether the new memory should be allocated for the data to be copied into. If the argument is 0, no new memory should be allocated and the data should only be referenced by pointer.

将数据入队写至由参数dataptr指定的内存区域。数据的长度作为len参数传递。拷贝参数为0或1,用于指示是否为将要拷贝来的数据分配新的内存。如果该参数为0,将不分配新的内存,并且数据仅能通过指针来引用。

The tcp_write() function will fail and return ERR_MEM if the length of the data exceeds the current send buffer size or if the length of the queue of outgoing segment is larger than the upper limit defined in lwipopts.h.The number of bytes available in the output queue can be retrieved with the tcp_sndbuf() function.

如果数据的最大长度超过了当前发送数据缓冲区的大小,或输出片段队列的长度超过了lwipopts.h文件中定义的上限,tcp_write()将失败并返回EER_MEM,在输出队列中可获得的字节数可通过tcp_sndbuf()函数检索。

The proper way to use this function is to call the function with at most tcp_sndbuf() bytes of data. If the function returns ERR_MEM, the application should wait until some of the currently enqueued data has been successfully received by the other host and try again.

使用该函数的正确方式是调用该函数,并将参数指定为tcp_sndbuf()获得的最大字节数。如果函数返回ERR_MEM,应用程序应等待直到当前入队数据正确地被其他主机接受并重试。

- void tcp_sent(struct tcp_pcb *pcb,

err_t (* sent)(void *arg, struct tcp_pcb *tpcb,u16_t len))

Specifies the callback function that should be called when data has successfully been received (i.e., acknowledged) by the remote host. The len argument passed to the callback function gives the amount bytes that was acknowledged by the last acknowledgment.

指定当数据被远程主机成功接收时应调用的回调函数。传递给回调函数的len参数给出了在最后一次确认中确认的字节数。

--- Receiving TCP data

--- 接收TCP数据

TCP data reception is callback based - an application specified callback function is called when new data arrives. When the application has taken the data, it has to call the tcp_recved() function to indicate that TCP can advertise increase the receive window.

TCP数据接收是基于回调函数的——当新的数据到达时,应用程序指定的回调函数被调用。当应用程序接收数据完毕,必须调用tcp_recved()函数用于指示TCP通告可以增加新的接收窗口。

- void tcp_recv(struct tcp_pcb *pcb,

err_t (* recv)(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err))

Sets the callback function that will be called when new data arrives. The callback function will be passed a NULL pbuf to indicate that the remote host has closed the connection. If there are no errors and the callback function is to return ERR_OK, then it must free the pbuf. Otherwise, it must not free the pbuf so that lwIP core code can store it.

当新的数据到达时,设置被调用的回调函数。如果远程主机已关闭了连接,该函数的pbuf参数将返回一个NULL空指针。如没有错误,并且回调函数的该参数返回值为ERR_OK,那么该函数必须释放pbuf。否则,禁止释放pbuf,以确保LwIP 内核代码可以存储其值。

Must be called when the application has received the data. The len argument indicates the length of the received data.

当应用程序已接收数据,必须调用此函数。Len参数指示接收数据的长度。

--- Application polling

--- 应用程序轮询

When a connection is idle (i.e., no data is either transmitted or received), lwIP will repeatedly poll the application by calling a specified callback function. This can be used either as a watchdog timer for killing connections that have stayed idle for too long, or as a method of waiting for memory to become available. For instance, if a call to tcp_write() has failed because memory wasn't available, the application may use the polling functionality to call tcp_write() again when the connection has been idle for a while.

当连接处于空闲状态(比如没有数据收发),LwIP将通过特定的回调函数重复地询问应用程序。在这种情况下,可以用看门狗定时器来切断长时间处于空闲状态的连接,也可以用这种方法等待获取内存的分配。例如,由于内存暂时不可获得,调用tcp_write()将失败,应用程序可在连接处于空闲状态时用轮询功能来再次调用tcp_write()。

- void tcp_poll(struct tcp_pcb *pcb, u8_t interval,

err_t (* poll)(void *arg, struct tcp_pcb *tpcb))

Specifies the polling interval and the callback function that should be called to poll the application. The interval is specified in number of TCP coarse grained timer shots, which typically occurs twice a second. An interval of 10 means that the application would be polled every 5 seconds.

指定轮询间隔,并调用该回调函数轮询应用程序。时间间隔由粗略的定时器中断时间来指定,通常1秒钟发生2次。值为10的间隔表示应用程序每隔5秒查询一次。

--- Closing and aborting connections

--- 关闭并中止连接

- err_t tcp_close(struct tcp_pcb *pcb)

Closes the connection. The function may return ERR_MEM if no memory was available for closing the connection. If so, the application should wait and try again either by using the acknowledgment callback or the polling functionality. If the close succeeds, the function returns ERR_OK.

The pcb is deallocated by the TCP code after a call to tcp_close().

关闭连接。如果关闭连接的内存不可获得,该函数将返回ERR_MEM。在这种情况下,应用程序应通过确认回调函数或轮询功能来等待并重试。如果关闭成功,该函数返回ERR_OK。

在tcp_close()调用后,pcb由TCP代码释放其内存。

- void tcp_abort(struct tcp_pcb *pcb)

Aborts the connection by sending a RST (reset) segment to the remote host. The pcb is

ATTENTION: When calling this from one of the TCP callbacks, make sure you always return ERR_ABRT (and never return ERR_ABRT otherwise or you will risk accessing deallocated memory or memory leaks!

If a connection is aborted because of an error, the application is alerted of this event by the err callback. Errors that might abort a connection are when there is a shortage of memory. The callback function to be called is set using the tcp_err() function.

通过向远程主机发送一个复位语句以中止连接。同时,pcb释放。该函数不会失败。

注意:当从TCP的任何一个回调函数中调用该函数时,需确保返回值为ERR_ABRT(从不返回ERR_ABRT,否则将冒险存取已释放的内存,或内存泄露)。

如果由于发生错误连接中止,应用程序应通过err回调函数对该事件保持警觉。造成中止连接的错误可能是内存不足。可调用的回调函数是使用tcp_err()。

- void tcp_err(struct tcp_pcb *pcb, void (* err)(void *arg,

err_t err))

The error callback function does not get the pcb passed to it as a parameter since the pcb may already have been deallocated.

由于pcb可能已经被释放,该回调函数不能获得作为参数传递给其自身的pcb。

--- Lower layer TCP interface

--- 底层TCP接口

TCP provides a simple interface to the lower layers of the system. During system initialization, the function tcp_init() has to be called before any other TCP function is called. When the system is running, the two timer functions tcp_fasttmr() and tcp_slowtmr()must be called with regular intervals. The tcp_fasttmr() should be called every TCP_FAST_INTERVAL milliseconds (defined in tcp.h) and tcp_slowtmr() should be called every TCP_SLOW_INTERVAL milliseconds. TCP为系统的底层提供了一个较为简单的接口。在系统初始化期间,函数tcp_init()应先于其他TCP函数被调用。在系统运行时,两个定时器函数tcp_fasttmr()和tcp_slowtmr()必须以特定的时间间隔调用。tcp_fasttmr()应该每TCP_FAST_INTERVAL毫秒调用一次(定义在tcp.h文件中),tcp_slowtmr()应每隔TCP_SLOW_INTERVAL毫秒

调用一次。

--- UDP interface

--- UDP接口

The UDP interface is similar to that of TCP, but due to the lower level of complexity of UDP, the interface is significantly simpler.

UDP接口与TCP类似,但由于UDP底层的复杂性,但其接口却更为简单。

- struct udp_pcb *udp_new(void)

it has either been bound to a local address or connected to a remote address.

创建一个用于UDP通信的pcb。除非pcb被绑定到一个本地地址或连接到远程地址,否则该pcb处于非活动状态。

- void udp_remove(struct udp_pcb *pcb)

Removes and deallocates the pcb.

删除并释放pcb。

- err_t udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)

Binds the pcb to a local address. The IP-address argument "ipaddr" can be IP_ADDR_ANY to indicate that it should listen to any local IP address. The function currently always return ERR_OK.

将pcb绑定到一个本地地址。IP地址参数可以指定为IP_ADDR_ANY,用以表明其监听本地所有IP地址。该函数总是返回ERR_OK

- err_t udp_connect(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)

Sets the remote end of the pcb. This function does not generate any network traffic, but only set the remote address of the pcb.

设置pcb的远程端。该函数不产生任何网络流量,仅仅设置pcb的远程终端地址。

- err_t udp_disconnect(struct udp_pcb *pcb)

Remove the remote end of the pcb. This function does not generate any network traffic, but only removes the remote address of the pcb.

删除pcb的远程端。该函数不产生任何网络流量,仅仅删除pcb的远程终端地址。

- err_t udp_send(struct udp_pcb *pcb, struct pbuf *p)

Sends the pbuf p. The pbuf is not deallocated.

发送参数p指向的内容。Pbuf不被释放。

- void udp_recv(struct udp_pcb *pcb,

void (* recv)(void *arg, struct udp_pcb *upcb,

struct pbuf *p,

struct ip_addr *addr,

u16_t port),

void *recv_arg)

Specifies a callback function that should be called when a UDP datagram is received.

指定当接收到UDP报文时应调用的回调函数。

--- System initalization

--- 系统初始化

it depends on the build configuration (lwipopts.h)and additional initializations for your runtime environment (e.g. timers).

取决于编译配置(lwipopts.h)及运行环境(如定时器)的附加初始化,我们不能给出一个真实、完整、通用的初始化LwIP堆栈的顺序。

We can give you some idea on how to proceed when using the raw API. We assume a configuration using a single Ethernet netif and the UDP and TCP transport layers, IPv4 and the DHCP client. 我们仅能给出一些使用原始API的处理方法。假定我们使用单网络netif、UDP和TCP、IPv4和DHCP客户端的配置。Call these functions in the order of appearance:

以出现顺序调用如下函数:

- stats_init()

Clears the structure where runtime statistics are gathered.

清除收集运行统计信息的结构。

- sys_init()

Not of much use since we set the NO_SYS 1 option in lwipopts.h, to be called for easy configuration changes.

由于我们在lwipopts.h文件中将NO_SYS置1,所以该函数没太大的用处。对于简单配置的改变应调用此函数。

- mem_init()

Initializes the dynamic memory heap defined by MEM_SIZE.

初始化由MEM_SIZE定义的内存堆。

- memp_init()

Initializes the memory pools defined by MEMP_NUM_x.

初始化由MEMP_NUM_x定义的内存池。

- pbuf_init()

Initializes the pbuf memory pool defined by PBUF_POOL_SIZE.

初始化由PBUF_POOL_SIZE定义的pbuf内存池。

- etharp_init()

Initializes the ARP table and queue.

Note: you must call etharp_tmr at a ARP_TMR_INTERVAL (5 seconds) regular interval after this initialization.

初始化ARP表和队列。注释:此初始化完毕,必须以ARP_TMR_INTERVAL(5秒)间隔调用etharp_tmr函数。

- ip_init()

Doesn't do much, it should be called to handle future changes.

应调用处理后续的改变,此处没处理特别的事务。

Clears the UDP PCB list.

清除UDP的PCB列表。

- tcp_init()

Clears the TCP PCB list and clears some internal TCP timers.

Note: you must call tcp_fasttmr() and tcp_slowtmr() at the predefined regular intervals after this initialization.

清除TCP的PCB列表,并且清除某些内部的TCP定时器。注释:此初始化完毕,必须以实现定义的时间间隔调用tcp_fasttmr()和tcp_slowtmr()。

- netif_add(struct netif *netif, struct ip_addr *ipaddr,

struct ip_addr *netmask, struct ip_addr *gw,

void *state, err_t (* init)(struct netif *netif),

err_t (* input)(struct pbuf *p, struct netif *netif))

Adds your network interface to the netif_list. Allocate a struct netif and pass a pointer to this structure as the first argument. Give pointers to cleared ip_addr structures when using DHCP, or fill them with sane numbers otherwise. The state pointer may be NULL.

The init function pointer must point to a initialization function for your ethernet netif interface. The following code illustrates it's use.

在netif_list中添加网络接口,分配netif结构并向这个结构的第一个参数传递一个指针。当使用DHCP时,给出指向已清空的ip_addr结构的指针,否则,应正确地赋值。State参数可能是空指针NULL。

初始化函数指针必须指向用户的网络netif接口初始化函数。以下代码阐述了它的用法。

err_t netif_if_init(struct netif *netif)

{

u8_t i;

for(i = 0; i < ETHARP_HWADDR_LEN; i++) netif->hwaddr[i] = some_eth_addr[i];

init_my_eth_device();

return ERR_OK;

}

For ethernet drivers, the input function pointer must point to the lwip function ethernet_input() declared in "netif/etharp.h". Other drivers must use ip_input() declared in "lwip/ip.h".

对于网络驱动,输入函数指针必须指向在"netif/etharp.h"声明的LwIP函数ethernet_input()。其他驱动必须使用在"lwip/ip.h"声明的ip_input()函数。

- netif_set_default(struct netif *netif)

注册默认的网络接口。

- netif_set_up(struct netif *netif)

When the netif is fully configured this function must be called.

当netif配置完整,必须调用该函数。

- dhcp_start(struct netif *netif)

Creates a new DHCP client for this interface on the first call. Note: you must call dhcp_fine_tmr() and dhcp_coarse_tmr() at the predefined regular intervals after starting the client.

为该接口的第一次调用创建一个新的DHCP客户端。注释:在启动这个客户端后,必须以实现定义的时间间隔调用dhcp_fine_tmr()和dhcp_coarse_tmr()函数。

You can peek in the netif->dhcp struct for the actual DHCP status.

用户可以通过netif结构中的netif->dhcp成员来查看实际的DHCP状态。

--- Optimalization hints

--- 优化提示

The first thing you want to optimize is the lwip_standard_checksum() routine from src/core/inet.c. You can override this standard function with the #define LWIP_CHKSUM .

优化工作的第一件事情就是src/core/inet.c中的lwip_standard_checksum()程序。用户可以通过#define LWIP_CHKSUM 宏定义,使用用户的函数来取代标准函数。

There are C examples given in inet.c or you might want to craft an assembly function for this. RFC1071 is a good introduction to this subject.

在inet.c文件中有C程序的例子。你可能想要为之编制一个汇编程序。RFC1071对该主题做了详细的介绍。

Other significant improvements can be made by supplying assembly or inline replacements for htons() and htonl() if you're using a little-endian architecture.

#define LWIP_PLATFORM_BYTESWAP 1

#define LWIP_PLATFORM_HTONS(x)

#define LWIP_PLATFORM_HTONL(x)

如果你采用小端结构,可通过采用汇编或内联汇编嵌入来实现htons()和htonl()以获得重要的性能提升。

#define LWIP_PLATFORM_BYTESWAP 1

#define LWIP_PLATFORM_HTONS(x)

#define LWIP_PLATFORM_HTONL(x)

Check your network interface driver if it reads at a higher speed than the maximum wire-speed. If the hardware isn't serviced frequently and fast enough buffer overflows are likely to occur. 检测你的网络接口驱动是否读取的速度高于最大的线速。如果硬件不能足够快速、频繁地服务,那么缓存溢出就可能会发

生。

E.g. when using the cs8900 driver, call cs8900if_service(ethif) as frequently as possible. When using an RTOS let the cs8900 interrupt wake a high priority task that services your driver using a binary semaphore or event flag. Some drivers might allow additional tuning to match your application and network.

例如,在使用CS8900驱动时,尽可能频繁地调用cs8900if_service(ethif)。当运行实时操作系统时,让CS8900中断唤醒较高优先级的任务,而该任务采用信号量或事件标志来为你的驱动提供服务。一些驱动可能允许采取其他的调整来匹配你的应用程序和网络。

For a production release it is recommended to set LWIP_STATS to 0. Note that speed performance isn't influenced much by simply setting high values to the memory options.

对于正式发行的产品,推荐将LWIP_STATS置0。注释:简单地将内存选项置高对速度性能并没有太大影响。

For more optimization hints take a look at the lwIP wiki.

想要获得更多的优化提示,请查看LwIP维基。

--- Zero-copy MACs

--- 零拷贝MACs

To achieve zero-copy on transmit, the data passed to the raw API must remain unchanged until sent. Because the send- (or write-)functions return when the packets have been enqueued for sending, data must be kept stable after that, too.

为了实现传输的0拷贝,传递到原始API的数据必须保持不被更改直到被发送。因为当入队待发的数据包在入队后发送(或写)函数将返回,入队后的数据也必须保持不变。

This implies that PBUF_RAM/PBUF_POOL pbufs passed to raw-API send functions must *not* be reused by the application unless their ref-count is 1.

这意味着传递给原始API发送函数的pbufs不能被应用程序重复使用,除非他们的ref-count为1。

For no-copy pbufs (PBUF_ROM/PBUF_REF), data must be kept unchanged, too, but the stack/driver will/must copy PBUF_REF'ed data when enqueueing, while PBUF_ROM-pbufs are just enqueued (as ROM-data is expected to never change).

对于非拷贝型pbufs,数据也必须保持不变,但当入队时,堆栈/驱动将/必须拷贝PBUF_REF'ed数据,PBUF_ROM-pbufs 仅是被入队(因为ROM-data不会被改变)。

Also, data passed to tcp_write without the copy-flag must not be changed!

此外,没有拷贝标志copy-flag传递到tcp_write函数的数据禁止改变。

Therefore, be careful which type of PBUF you use and if you copy TCP data or not!

因此,要留意你所使用的PBUF的类型,以及是否拷贝TCP数据。

sys_arch interface for lwIP 0.6++

LwIP0.6+的SYS_ARCH接口

Author: Adam Dunkels

作者:Adam Dunkels

翻译:lizhiming 译文参考了焦海波大侠的“uC/OS-II 平台下的 LwIP 移植笔记”译文

The operating system emulation layer provides a common interface between the lwIP code and the underlying operating system kernel. The general idea is that porting lwIP to new architectures requires only small changes to a few header files and a new sys_arch implementation. It is also possible to do a sys_arch implementation that does not rely on any underlying operating system.

操作系统模拟层为LwIP和下层操作系统内核提供了一个通用的接口。一般思想是:移植LwIP到新的架构体系仅需对少数头文件的改动和一个新的sys_arch实现。也可以不依赖任何操作系统来实现sys_arch接口。

The sys_arch provides semaphores and mailboxes to lwIP. For the full lwIP functionality, multiple threads support can be implemented in the sys_arch, but this is not required for the basic lwIP functionality. Previous versions of lwIP required the sys_arch to implement timer scheduling as well but as of lwIP 0.5 this is implemented in a higher layer.

Sys_arch需要为LwIP提供信号量和邮箱两种进程间的服务(通信方式)。如果想获得完整的LwIP功能,需要在sys_arch中实现多线程的支持,但对于基本的LwIP功能,sys_arch并不需要这些支持。LwIP的早期版本也要求sys_arch实现时间调度,但对于LwIP0.5及以后的版本,这一功能是在更高一层实现的。

In addition to the source file providing the functionality of sys_arch, the OS emulation layer must provide several header files defining macros used throughout lwip. The files required and the macros they must define are listed below the sys_arch description.

除提供实现sys_arch功能的源文件外,操作系统模拟层必须提供在LwIP中所使用全部宏定义的少数头文件。所需的文件及必须定义的宏定义列在对sys_arch的描述之后。

Semaphores can be either counting or binary - lwIP works with both kinds. Mailboxes are used for message passing and can be implemented either as a queue which allows multiple messages to be posted to a mailbox, or as a rendez-vous point where only one message can be posted at a time. lwIP works with both kinds, but the former type will be more efficient. A message in a mailbox is just a pointer, nothing more.

信号量可是计数信号量或二进制信号量——LwIP都可正常工作。邮箱用于消息投递,邮箱可采用允许多条消息投递到邮箱的队列实现,邮箱也可以是一个汇合点,在任一时刻,该汇合点仅有一条信息可以被投递。这两种LwIP都可以正常工作,但前者更加有效,投递到邮箱中的消息仅仅是一个指针。

Semaphores are represented by the type "sys_sem_t" which is typedef'd in the sys_arch.h file. Mailboxes are equivalently represented by the type "sys_mbox_t". lwIP does not place any restrictions on how sys_sem_t or sys_mbox_t are represented internally.

信号量用"sys_sem_t"类型来表示,该类型在sys_arch.h文件中定义。相应地,邮箱用"sys_mbox_t"类型来表示。对于sys_sem_t和sys_mbox_t内在如何表示这两种不同类型,LwIP没有任何限制。

The following functions must be implemented by the sys_arch:

以下函数必须由sys_arch实现:

- void sys_init(void)

Is called to initialize the sys_arch layer.

用以初始化系统接口模拟层。

- sys_sem_t sys_sem_new(u8_t count)

Creates and returns a new semaphore. The "count" argument specifies the initial state of the semaphore.

创建并返回一个信号量,参数count返回信号量的初始状态。

- void sys_sem_free(sys_sem_t sem)

Deallocates a semaphore.

释放一个信号量。

- void sys_sem_signal(sys_sem_t sem)

Signals a semaphore.

向信号量发送一个信号。

- u32_t sys_arch_sem_wait(sys_sem_t sem, u32_t timeout)

Blocks the thread while waiting for the semaphore to be signaled. If the "timeout" argument is non-zero, the thread should only be blocked for the specified time (measured in milliseconds). If the "timeout" argument is zero, the thread should be blocked until the semaphore is signalled.

If the timeout argument is non-zero, the return value is the number of milliseconds spent waiting for the semaphore to be signaled. If the semaphore wasn't signaled within the specified time, the return value is SYS_ARCH_TIMEOUT. If the thread didn't have to wait for the semaphore (i.e., it was already signaled), the function may return zero.

Notice that lwIP implements a function with a similar name, sys_sem_wait(), that uses the sys_arch_sem_wait() function.

等待指定的信号并阻塞线程。timeout参数为0,线程会一直被阻塞至收到指定的信号;非0,则线程仅被阻塞至指定的timeout时间(单位为毫秒)。

在timeout参数值非0的情况下,返回值为等待指定的信号所消耗的毫秒数。如果在指定的时间内并没有收到信号,返

回值为 SYS_ARCH_TIMEOUT。如果线程不必再等待这个信号(也就是说,已经收到信号),返回值也可以为0。

注意,LwIP实现了一个名称与之相似的函数来调用这个函数,sys_sem_wait(),在sys_arch中使用sys_arch_sem_wait()函数,注意区别。

- sys_mbox_t sys_mbox_new(int size)

Creates an empty mailbox for maximum "size" elements. Elements stored in mailboxes are pointers. You have to define macros "_MBOX_SIZE" in your lwipopts.h, or ignore this parameter in your implementation and use a default size.

创建一个最大元素为size的空邮箱。存储在邮箱中的元素为指针。用户必须在lwipopts.h文件中定义"_MBOX_SIZE"宏定义,或者在实现时忽略该参数并使用默认值。

- void sys_mbox_free(sys_mbox_t mbox)

Deallocates a mailbox. If there are messages still present in the mailbox when the mailbox is deallocated, it is an indication of a programming error in lwIP and the developer should be notified.

释放一个邮箱,如果在释放时邮箱中仍有消息存在,它表明LwIP中存在一个编程错误,应该通知开发者。

- void sys_mbox_post(sys_mbox_t mbox, void *msg)

Posts the "msg" to the mailbox. This function have to block until the "msg" is really posted. 投递消息"msg"到邮箱。该函数必须阻塞直到"msg"真正被投递。

- err_t sys_mbox_trypost(sys_mbox_t mbox, void *msg)

Try to post the "msg" to the mailbox. Returns ERR_MEM if this one is full, else, ERR_OK if the "msg" is posted.

试图投递消息"msg"到邮箱,如果邮箱已满则返回ERR_MEM,否则返回ERR_OK,消息"msg"被投递。

- u32_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout)

Blocks the thread until a message arrives in the mailbox, but does not block the thread longer than "timeout" milliseconds (similar to the sys_arch_sem_wait() function). If "timeout" is 0, the thread should be blocked until a message arrives. The "msg" argument is a result parameter that is set by the function (i.e., by doing "*msg = ptr"). The "msg" parameter maybe NULL to indicate that the message should be dropped.

The return values are the same as for the sys_arch_sem_wait() function: Number of milliseconds spent waiting or SYS_ARCH_TIMEOUT if there was a timeout.

Note that a function with a similar name, sys_mbox_fetch(), is implemented by lwIP.

阻塞线程直到消息到达邮箱,但阻塞线程的时间不能长于timeout指定的毫秒数(与sys_arch_sem_wait()函数类似)。如果timeout为0,线程需阻塞到消息到达。"msg"是一个该函数设置的返回参数(比如,通过"*msg = ptr"赋值)。"msg"参数可能为NULL,以表明消息应丢弃。

返回值与sys_arch_sem_wait()函数类似:如果存在等待时限,返回值为实际等待的毫秒数或SYS_ARCH_TIMEOUT。

需要注意的是,LwIP实现了一个名称相似的函数sys_mbox_fetch()。

- u32_t sys_arch_mbox_tryfetch(sys_mbox_t mbox, void **msg)

This is similar to sys_arch_mbox_fetch, however if a message is not present in the mailbox, it immediately returns with the code SYS_MBOX_EMPTY. On success 0 is returned.

To allow for efficient implementations, this can be defined as a function-like macro in sys_arch.h instead of a normal function. For example, a naive implementation could be:

#define sys_arch_mbox_tryfetch(mbox,msg) sys_arch_mbox_fetch(mbox,msg,1)

although this would introduce unnecessary delays.

该函数与sys_arch_mbox_fetch函数相似,但如果消息中没有可获得的消息,其将立即返回,返回值为SYS_MBOX_EMPTY,成功时返回0。

为了允许更加有效地实现,该函数可以在sys_arch.h中定义为类似函数的宏定义,取代其常规的函数实现。例如,一

个简单的实现可以是:

#define sys_arch_mbox_tryfetch(mbox,msg) sys_arch_mbox_fetch(mbox,msg,1)

尽管这样会引入不必要的延迟。

- struct sys_timeouts *sys_arch_timeouts(void)

Returns a pointer to the per-thread sys_timeouts structure. In lwIP, each thread has a list of timeouts which is repressented as a linked list of sys_timeout structures. The sys_timeouts structure holds a pointer to a linked list of timeouts. This function is called by the lwIP timeout scheduler and must not return a NULL value.

In a single thread sys_arch implementation, this function will simply return a pointer to a global sys_timeouts variable stored in the sys_arch module.

If threads are supported by the underlying operating system and if such functionality is needed in lwIP, the following function will have to be implemented as well:

返回一个指向当前线程使用的sys_timeouts结构的指针。LwIP中,每一个线程都有一个timeouts链表,这个链表

由sys_timeout结构组成,sys_timeouts结构则保存了指向这个链表的指针。这个函数由LwIP的超时调度程序调用,并且不能返回一个空指针(NULL)。

单线程sys_arch实现中,这个函数只需简单返回一个指针即可。这个指针指向保存在sys_arch模块中的sys_timeouts全局变量。

如果底层操作系统支持多线程并且LwIP中需要这样的功能,那么,以下函数也必须实现:

- sys_thread_t sys_thread_new(char *name, void (* thread)(void *arg), void *arg, int stacksize, int prio)

Starts a new thread named "name" with priority "prio" that will begin its execution in the function "thread()". The "arg" argument will be passed as an argument to the thread() function. The stack size to used for this thread is the "stacksize" parameter. The id of the new thread is returned. Both the id and the priority are system dependent.

启动一个由函数指针thread指定的命名为"name"的新线程,arg将作为参数传递给thread()函数,prio指定这个

新线程的优先级,"stacksize"参数为该线程所需堆栈的大小。返回值为这个新线程的ID,ID和优先级由底层操作系

统决定。

- sys_prot_t sys_arch_protect(void)

This optional function does a "fast" critical region protection and returns the previous protection level. This function is only called during very short critical regions. An embedded system which supports ISR-based drivers might want to implement this function by disabling interrupts. Task-based systems might want to implement this by using a mutex or disabling tasking. This function should support recursive calls from the same task or interrupt. In other words, sys_arch_protect() could be called while already protected. In that case the return value indicates that it is already protected.

sys_arch_protect() is only required if your port is supporting an operating system.

这是一个可选函数,它负责快速完成临界区域保护并返回先前的保护状态。该函数只有在小的临界区域需要保护时才会被调用。支持基于ISR驱动的嵌入式系统可以通过禁止中断来实现这个函数。基于任务的系统可以通过互斥量或禁止任务来实现这个函数。该函数应该支持来自于同一个任务或中断的递归调用。换句话说,当该区域已经被保护,sys_arch_protect()函数依然能被调用。这时,函数的返回值会通知调用者该区域已经被保护。

如果你的移植支持操作系统,sys_arch_protect()函数仅仅是一个需要。

- void sys_arch_unprotect(sys_prot_t pval)

This optional function does a "fast" set of critical region protection to the value specified by pval. See the documentation for sys_arch_protect() for more information. This function is only required if your port is supporting an operating system.

Note:

Be carefull with using mem_malloc() in sys_arch. When malloc() refers to mem_malloc() you can run into a circular function call problem. In mem.c mem_init() tries to allcate a semaphore using mem_malloc, which of course can't be performed when sys_arch uses mem_malloc.

该函数同样是一个可选函数。它的功能就是快速恢复受保护区域至由pval指定的状态。更多信息请参考函数sys_arch_protect()。如果你的移植支持操作系统,该函数仅仅是一个需要。

注释:

在sys_arch中使用mem_malloc()时须小心。当malloc()引用mem_malloc()时,你可能面对的是一个循环调用的问题。在mem.c文件中,mem_init()试图使用mem_malloc函数分配一个信号量,理所当然,当sys_arch使用mem_malloc函数时并不能执行。

----------------------------------------------------------------------------

Additional files required for the "OS support" emulation layer:

“操作系统”模拟层所需的附加文件

----------------------------------------------------------------------------

cc.h - Architecture environment, some compiler specific, some

以太网及TCPIP通俗理解

1 以太网------EtherNet: ---------------------------参考图解 以太网最早由Xerox(施乐)公司创建,于1980年DEC、lntel和Xerox三家公司联合开发成为一个标准。以太网是应用最为广泛的局域网,包括标准的以太网(10Mbit/s)、快速以太网(100Mbit/s)和10G(10Gbit/s)以太网,采用的是CSMA/CD访问控制法,它们都符合IEEE802.3。 IEEE 802.3标准 IEEE802.3规定了包括物理层的连线、电信号和介质访问层协议的内容。以太网是当前应用最普遍的局域网技术,它很大程度上取代了其他局域网标准。如令牌环、FDDI和ARCNET。历经100M以太网在上世纪末的飞速发展后,目前千兆以太网甚至10G以太网正在国际组织和领导企业的推动下不断拓展应用范围。 常见的802.3应用为: 10M: 10base-T (铜线UTP模式) 100M: 100base-TX (铜线UTP模式) 100base-FX(光纤线) 1000M: 1000base-T(铜线UTP模式) 2 UIP协议: uIP由瑞典计算机科学学院(网络嵌入式系统小组)的Adam Dunkels 开发。其源代码由C 语言编写,并完全公开,uIP 的最新版本是1.0 版本,本指南移植和使用的版本正是此版本。uIP协议栈去掉了完整的TCP/IP中不常用的功能,简化了通讯流程,但保留了网络通信 必须使用的协议,设计重点放在了IP/TCP/ICMP/UDP/ARP这些网络层和传输层协议上,保证了其代码的通用性和结构的稳定性。 由于uIP协议栈专门为嵌入式系统而设计,因此还具有如下优越功能: 1)代码非常少,其协议栈代码不到6K,很方便阅读和移植。 2)占用的内存数非常少,RAM 占用仅几百字节。 3)其硬件处理层、协议栈层和应用层共用一个全局缓存区,不存在数据的拷贝,且发送和接收都是依靠这个缓存区,极大的节省空间和时间。 4)支持多个主动连接和被动连接并发。 5)其源代码中提供一套实例程序:web 服务器,web 客户端,电子邮件发送程序(SMTP 客户端),Telnet服务器,DNS主机名解析程序等。通用性强,移植起来基本不用修改就可以通过。 6)对数据的处理采用轮循机制,不需要操作系统的支持。 由于uIP对资源的需求少和移植容易,大部分的8位微控制器都使用过uIP 协议栈,而且很多的著名的嵌入式产品和项目(如卫星,Cisco 路由器,无线传感器网络)中都在使用uIP 协议栈。 3 TCP/IP协议: TCP/IP是(Transmission Control Protocol/Internet Protocol)的简写,中译名为传输控制协

2012.11.6战略智慧笔记 陈果

N 《战略智慧》 --陈果 如何建立战略思维? 你现在最需要解决的是什么问题? 1、未来老百姓的健康生活方式? 2、房产中介的人力资源 3、企业做到一定程度,如何把规模缩小? 4、如何使用90后? 5、外贸出口利润越来越低,公司成本越来越大,如何突破?需要经营的: 1、原始积累(财富) 2、内部团队(精神共同体) 团队是利润,是巨大财富 3、忠实客户(了解客户需求) 企业一定要战略升级,为谁请命? 老板需要经营“空手套白狼”的本领。 企业做大的因素: 1、政府的力量 2、资金对你的加持 3、消费者对你的关注 4、优秀的人才向你靠齐

利润 (如:外婆家) 如:宋城集团,通过做“宋城千古情”项目,获得政府的支持 大老板:看似很傻,实际很厉害,用一年的时间赚10年的钱 如:王志纲老师用三十年的时间做中国最好的“战略思想智库”,一转身获得无数的财富 经营企业就是经营人,经营企业就是经营价值。 企业、产品都是媒介,关键是你想到哪里去。 战略思维思考的问题是:我要到哪里去? 老板必须为战略负责! 战略是唯一不能让职业经理人去做的事情。 没有战略就没有人追随,如果成功也是偶然的。 如:王建林(万达集团),当初做商业地产,所有人都反对如:吴亚军,(南湖地产,温州人)当初做战略十几人的核心团队全部走掉,但今天成为中国女首富。 老板不是所有事情都需要你来做,而是那些事情是你必须要做的。

如:华为,力排众议做最适合当下的战略 这是一场越来越激烈的商战,不要妄想今天的困难明天就过去了,要有打战的思维 如:微软 在战争当中总结经验,这是老板需要修炼的 战略智慧金三角: 找定位 定打法 开模具 战略之道的根本是定位。 打法和模具的关系: 模具是企业超级杀伤力的武器 如:工作室:帮企业找魂,帮企业开模具书院班:帮企业开模具,寻找战略突破打法:合适的发射装置 打法与模具的关系是炮弹和炮筒的关系 孵化人的板块: 从老板到老师的智慧

uip移植笔记

本笔记适用于uIP1.0。 移植平台介绍:MSP430F149+cs8900a+IAR 1、阅读The uIP Embedded TCP/IP Stack The uIP 1.0 Reference Manual. 2、建立一个文件夹,起名myport,将uip-1.0下的uIP和lib两个文件夹拷贝过去,然后再在myport下建立app文件夹。 3、将unix子文件夹下的clock-arch.c、clock-arch.h拷贝到myport下,这个文件实现协议栈所用的时钟,由430的定时器完成,有三个函数: clock_time_t clock_time(void) { return ticks; } void clock_init(void) { 定时器的初始化工作 } __interrupt void timer_interrupt(void)/*定时器中断函数*/ { ++ticks; }。 4、将unix子文件夹下的uip-conf.h拷贝到myport下,这个文件实现协议栈所用的配置,按照需要修改之。 5、写cs8900a的驱动函数,这里采用8位、查询模式,替换tapdev.c 或slipdev.c。 6、将unix子文件夹下的main.c函数拷贝到myport下,这个是主调度流程,按照需要修改。 7、建立自己的工程,将以上文件包含。 8、调试,改错。 其中,uip的缓冲区是以字节数组的形式产生,为了保证它的起始地址是偶数,必须指定地址。 UDP的初始化如下 void myudp_init(void) { uip_ipaddr_t ipaddr;//定义IP类型变量 uip_ipaddr(ipaddr, 210,29,104,88); //远程IP为210.29.104.88 if(myudp_conn != NULL) { uip_udp_remove(myudp_conn);//如果连接已经建立,则删除之 } myudp_conn = uip_udp_new(&ipaddr, HTONS(1000));//建立到远程ipaddr,端口为1000的连接 if(myudp_conn != NULL) {

ucos操作系统在ARM上的移植

UC/OS-II 嵌入式系统在ARM 上的移植 UC/OS-II 操作系统是一款完全公开的源代码,它非常精简,整个操作系统的代码只有几千行,是专门针对于嵌入式开发而产生的一款代码。它有几个特点,分别是可移植性(Portable )、可固化(ROMable )、可裁剪(Scalable )、多任务、可确定性、任务栈、系统服务、中断管理、稳定性可靠性。 UC/OS-II 主要就是一个内核,由ANSIC 语言编写而成。负责任务管理和任务调度,没有文件系统和界面系统。它的代码是公开的,系统的实时性强、移植性好、可多任务。 UC/OS-II 作为基于优先级的抢占式多任务的实时操作系统,包含了实时内核、任务管理、时间管理、任务间通信同步和内存管理的功能。它使得任务的独立性,不相互干涉,非常的准时和高效,且易于设计和扩展。 UO/OS-II 共有16个内核文件,11个与CPU 类型无关,就是说可以直接使用不需要修改。还有3个内核文件与CPU 有关系,要根据需要作出相应的改动。剩下的两个内核文件和具体的应用有关。如图所示UC/OS-II 的16个内核文件的层次。 μC/OS -II 内核文件 软件 硬件

多任务操作的核心是系统调度器,利用TCB来管理任务调度功能。它的主要功能是保存任务的当前态、优先级、等待事件、代码起始地址、初始堆栈指针等。程序的设计关键就是确定划分多任务的问题,以及任务优先级和任务通信。 优先级的意思是每个任务都是无限循环的,有运行态度、就绪态、休眠态、挂起态和中断五种状态。当有高一级优先级的任务就绪后,低优先级立即停止运行,转为挂起态或就绪态。这就是可剥夺型的内核。当中断一个高优先级任务,中断时 挂起,中断结束后任务继续运行,并立即剥夺低优先级的任务。 对于这种可剥夺型内核,CPU的使用时可以确定的,可优化任务级响应。在很多单片机或ARM板上很容易就可以移植UC/OS-II。当然本次设计使用的TQ2440,也可以完美的移植它。移植程序在网上都可以找得到,所以设计中就不做解释了。 本次设计实现的是串口协议和网口协议组合成的一个数据网关。其主要的流程图如下所示:

uip学习笔记

uip_buf:定义如下u8_t uip_buf[UIP_BUFSIZE + 2];所有的数据处理都是通过处理它来完成的。比如接受的数据存储在这里,要发送的数据有会放在这里。 uip_len:uip_buf有用数据的字节 uip_appdata:uip_buf第一个可用字节的指针 uip_conn:总是指向当前连接的指针,定义:struct uip_conn *uip_conn; 下面是TCP连接的结构,用来区别不同的TCP连接,uip_tcp_appstate_t appstate是可以读写的且在实践应用中需要重定义,其他项read-only。 struct uip_conn { uip_ipaddr_t ripaddr; /**< The IP address of the remote host. 远程主机IP地址*/ u16_t lport; /**< The local TCP port, in network byte order. 本地TCP端口号,网络字节顺序*/ u16_t rport; /**< The local remote TCP port, in network byte order.本地远程连接主机TCP端口号*/ u8_t rcv_nxt[4]; /**< The sequence number that we expect to receive next. */ u8_t snd_nxt[4]; /**< The sequence number that was last sent by us. */ u16_t len; /**< Length of the data that was previously sent. */ u16_t mss; /**< Current maximum segment size for the connection. */ u16_t initialmss; /**< Initial maximum segment size for the connection. */ u8_t sa; /**< Retransmission time-out calculation state variable. */ u8_t sv; /**< Retransmission time-out calculation state variable. */ u8_t rto; /**< Retransmission time-out. */ u8_t tcpstateflags; /**< TCP state and flags. */ u8_t timer; /**< The retransmission timer. */ u8_t nrtx; /**< The number of retransmissions for the last segment sent. */ /** The application state. */ uip_tcp_appstate_t appstate; }; uip的应用事件: 1.接收数据:uip_newdata()为真,即远程连接的主机有发送新数据。uip_appdata指针指向实际数据。数据的大小通过uIP函数uip_datalen()获得。在数据不是被缓冲后,应用程序必须立刻启动。 2.发送数据:应用程序通过使用uIP函数uip_send()发送数据。uip_send()函数采用两个参数;一个指针指向发送数据和数据的长度。如果应用程序为了产生要发送的实际数据需要RAM 空间,包缓存(通过uip_appdata指针指向)可以用于这方面。在一个时间里应用程序只能在连接中发送一块数据。因此不可以在每个应用程序启用中调用uip_send()超过一次;只有上

uip协议栈

uIP协议栈分析 uIP特性 uIP协议栈往掉了完整的TCP/IP中不常用的功能,简化了通讯流程,但保存了网络通讯必须使用的协议,设计重点放在了IP/TCP/ICMP/UDP/ARP这些网络层和传输层协议上,保证了其代码的通用性和结构的稳定性。 由于uIP协议栈专门为嵌进式系统而设计,因此还具有如下优越功能: (1)代码非常少,其协议栈代码不到6K,很方便阅读和移植。 (2)占用的内存数非常少,RAM占用仅几百字节。 (3)其硬件处理层、协议栈层和应用层共用一个全局缓存区,不存在数据的拷贝,且发送和接收都是依靠这个缓存区,极大的节省空间和时间。 (4)支持多个主动连接和被动连接并发。 (5)其源代码中提供一套实例程序:web服务器,web客户端,电子邮件发送程序(SMTP 客户端),Telnet服务器,DNS主机名解析程序等。通用性强,移植起来基本不用修改就可以通过。 (6)对数据的处理采用轮循机制,不需要操纵系统的支持。 由于uIP对资源的需求少和移植轻易,大部分的8位微控制器都使用过uIP协议栈, 而且很多的著名的嵌进式产品和项目(如卫星,Cisco路由器,无线传感器网络)中都在使用uIP协议栈。 uIP架构 uIP相当于一个代码库,通过一系列的函数实现与底层硬件和高层应用程序的通讯,对于整个系统来说它内部的协议组是透明的,从而增加了协议的通用性。uIP协议栈与系统底层和高层应用之间的关系如图2-1所示。 从上图可以看出,uIP协议栈主要提供了三个函数供系统底层调用。即uip_init(), uip_input() 和uip_periodic()。其与应用程序的主要接口是UIP_APPCALL( )。 uip_init()是系统初始化时调用的,主要初始化协议栈的侦听端口和默认所有连接是封闭的。当网卡驱动收到一个输进包时,将放进全局缓冲区uip_buf中,包的大小由全局变量uip_len

如何学习TCPIP(基于51单片机)

如何学习TCPIP(基于51单片机) 总体说来,TCPIP并不是一件十分神秘的事情,尤其是基于MCU的应用,不要求进行特别复杂的处理,很多情况下只需要实现最最基本的功能就行了。在实现MCU的TCPIP移植之前,必须对TCPIP有一定程度的了解,可以找一本合适的书籍来翻阅一下,《TCP/IP详解,卷1:协议》https://www.wendangku.net/doc/b34400824.html,/display.aspx?did=510是一本完整而详细的TCP/IP协议指南。描述了属于每一层的各个协议以及它们如何在不同操作系统中运行。 对于TCPIP在MCU上的应用并不要求对协议的所有部分都了解的那么清楚,重点需要了解TCPIP的各个层次的关系,链路层,有时也称作数据链路层或网络接口层,通常包括操作系统中的设备驱动程序和计算机中对应的网络接口卡。它们一起处理与电缆(或其他任何传输媒介)的物理接口细节。网络层,有时也称作互联网层,处理分组在网络中的活动,例如分组的选路。在T C P / I P协议族中,网络层协议包括I P协议(网际协议),I C M P协议(I n t e r n e t互联网控制报文协议),以及I G M P协议(I n t e r n e t组管理协议)。运输层主要为两台主机上的应用程序提供端到端的通信。在T C P / I P协议族中,有两个互不相同的传输协议:T C P(传输控制协议)和U D P(用户数据报协议)。T C P为两台主机提供高可靠性的数据通信。它所做的工作包括把应用程序交给它的数据分成合适的小块交给下面的网络层,确认接收到的分组,设置发送最后确认分组的超时时钟等。由于运输层提供了高可靠性的端到端的通信,因此应用层可以忽略所有这些细节。而另一方面,U D P则为应用层提供一种非常简单的服务。它只是把称作数据报的分组从一台主机发送到另一台主机,但并不保证该数据报能到达另一端。任何必需的可靠性必须由应用层来提供。这两种运输层协议分别在不同的应用程序中有不同的用途。应用层负责处理特定的应用程序细节。几乎各种不同的T C P / I P实现都会提供Telnet,FTP,SMTP 简单邮件传送协议,SNMP简单网络管理协议这些通用的应用程序。 各种类型的数据报格式也是需要了解的重点,使用Sniffer软件可以十分方便的在电脑上查看各种数据报的收发状态.同时Sniffer也是以后调试TCPIP协议寨的一个很有用的工具,Sniffer的使用方式可以在https://www.wendangku.net/doc/b34400824.html,上很方便的搜索到. TCP/IP的分层,以太网封装,IP首部,子网寻址和子网掩码,ARP地址解析协议,ICMP控制报文协议中的ECHO(Ping程序),UDP用户数据报协议,TFTP简单文件传送协议,特别是TCP传输控制协议是TCPIP在MCU上应用所必需掌握的关键知识. 在对TCPIP有了一定程度的了解之后,如何具体的实现就成了问题的关键,我在学习TCPIP 的过程中前后一共使用或阅读了下面的3中TCPIP协议寨,这里有对3个协议寨的比较和下载地址. uIP,适合8bit单片机上使用,但是结构比较复杂,不适宜进行移植,也不是一份很适合阅读的代码.下载地址http://www.sics.se/~adam/uip/ Lwip,适合16/32bit单片机上使用,是嵌入式系统开发人员最好的学习TCPIP的代码,下载地址http://www.sics.se/~adam/lwip/ zLip,南开大学电子应用实验室编写的一个协议寨,有uip和lwip的优点,推荐初学者学习https://www.wendangku.net/doc/b34400824.html,/display.aspx?did=859 在了解了具体实现之后,就有需要在MCU上具体的运行一下了,这里提供一个我做的硬件电路,但是其中我使用了GAL16V8芯片进行地址分配,所以需要有一个支持16V8的烧写器了,同时,如果将at89c55芯片换成sst89c58,并从https://www.wendangku.net/doc/b34400824.html,公司网站上下载一个monitor 51的仿真监控程序,使用烧写器写入sst89c58中,就可以通过串口和Keil软件配合进行硬件仿真了.(市场上的那些100多元的51仿真器就是这个样子的). Gal的代码如下(abel hdl语言编写),使用猜测的方式都应该明白什么意思了把?!

基于FPGA的IP核8051上实现TCPIP的设计

基于FPGA的IP核8051上实现TCP/IP的设计引言 随着芯片规模的越来越大、资源的越来越丰富, 芯片的设计复杂度也大大增加。事实上, 在芯片设计完成后, 有时还需要根据情况改变一些控制, 这在使用过程中会经常遇到。这时候如果再对芯片设计进行改变将是很不可取的, 因为需要设计人员参与这种改变, 这无论是对设计者还是用户都是不能接受的。于是就有必要让这种可以改变的简单控制在芯片设计时就存在, 而且同时还应该使这种改变相对容易, 比较通用, 并且与芯片的其它设计部分尽量不相关。为了满足上述的要求, 在FPGA中嵌入一个比较理想的选择, 而这个即通用又控制简单的IP核最好选择8051微处理器。 在FPGA中植入8051后, 还可在上面实现简单的TCP/IP协议, 以支持远程访问或进行远程调试, 这只是在嵌入FPGA的8051上的一个应用。为了保证用户能够对8051实现不同的控制操作,设计时也可以采用一个外部flash对8051进行加载, 这样, 用户只需要将编译好的汇编语言代码加到flash就可以控制8051的工作, 而此时用户完全不需要对FPGA进行操作就能实现简单的控制,而这需要的仅仅只是keil的编译环境。 1 IP核8051的FPGA实现 现在有许多免费的8051核可以利用, 这些核都可通过硬件描述语言来实现, 并且基本上都可综合, 也就是直接拿来就能用, 需要的只是根据自身的具体需求做一些简单修改即可。总的说来, IP核8051的移植是比较简单的。 本系统的设计与实现可以采用oregano system的mc8051内核, 并且加入定时计数的和串口模块, 8051单片机的设计结构框图如图1所示。

OLC学习笔记及近期遇到OLC相关的故障和问题分析

OLC学习笔记及近期遇到OLC相关的故障和问题分析 1.OLC简介: OLC是OCS对外接机口,主要用作协议的转换和分发。消息的收发短信和语音协议的转换。--中转机器,进行协议解析、OCS处理分发 2.OLC配置简介: OLC包括的几个关键配置文件: 平台的配置文件imp.ini,配置OLC日志大小、最大个数,OLC接口参数等。 配置通讯节点的配置文件itcom.ini,包括本机OLC相关配置、OLC当客户端,连接OCS 的相关配置等。 具体业务进行配置的配置文件servicexxx.ini 下面是整理的配置过程中的一些注意事项: 3.OLC配置注意事项 itcom.ini配置注意事项: [general] module = 151 ; 节点号 postoffice = 176 ; 局号 areacode = 30 ; 区号 myipaddress = 10.40.51.27 ; 本机IP地址 alarmmodule = 133 ; 告警节点号 servercnt = 1 ; 服务器端配置数 clientcnt = 1 ; 客户端配置数 noLimitPort = 1 b、module和postoffice配置,此配置为其他主机连接的主要参数。提供给web\UIP及其其 他外部系统访问时用到的关键参数。 疑问: 320:58001|320:58009,58011,58023,58025,58027|220:65003,65005,65007,65009,65015,65017|3

20:58007|320:58019|320:58015|106:58003 前台配置的pno:220,从OLC上的配置怎么找,该Pno处理什么业务? c、noLimitPort配置由OCS主机/etc目录下的win_mgt.scr的[general]中的listenport值决定 的,如果为5000,需配置为0,其他配置为1。 如:OCS配置为listenport =5001,5010,OLC需要将noLimitPort = 1。 d、Module配置不可重复。如果部署多个OLC,每个OLC的Module不能重复。 如印尼项目生产环境: 雅加达配置: [general] module = 180 postoffice = 176 泗水配置: [general] module = 179 postoffice = 177 ----------------------------------------------------------------- [clientX]下的配置: [client1] mainpno = 380 myipaddress = 10.17.88.35 peeripaddress = 10.17.88.13 port = 5000 peermodule = 132 peerpost = 172 socketnum = 1 longconn = 1 commpno = 105 OLC为客户端、OCS或者其他为服务端。 关注peermodule,peerpost两个参数如何配置? Peermodule 表示对端模块号,常指OCS模块号 Peerpost 表示对端局号,常指OCS局号 可在OCS主机的/etc目录下,通过zxtool2 –v win_mgt.src的[general]查到对应的值。 如印尼项目现场: 雅加达OCS: [general] module=132 postoffice=172

奋斗STM32开发板uIP1.0 以太网例程讲解

奋斗版 STM32 开发板例程文档———uIP1.0 ENC28J60 以太网例程
https://www.wendangku.net/doc/b34400824.html,
uIP1.0 ENC28J60 以太网例程
实验平台:奋斗版STM32开发板V2、V2.1、V3 实验内容:本例程演示了在奋斗STM32开发板上完成ARP,ICMP,TCP服务器、WEB 服务器以及UDP服务器,该实验学习了基于uIP1.0网络协议栈的程序编制。
预先需要掌握的知识
1.ENC28J60
ENC28J60是MICROCHIP公司的带SPI 接口的独立以太网控制器, 以太网控制器特性 ? IEEE 802.3 兼容的以太网控制器 ? 集成MAC 和10 BASE-T PHY ? 接收器和冲突抑制电路 ? 支持一个带自动极性检测和校正的10BASE-T 端口 ? 支持全双工和半双工模式 ? 可编程在发生冲突时自动重发 ? 可编程填充和CRC 生成 ? 可编程自动拒绝错误数据包 ? 最高速度可达10 Mb/s 的SPI 接口 缓冲器 ? 8 KB 发送/ 接收数据包双端口SRAM ? 可配置发送/ 接收缓冲器大小 ? 硬件管理的循环接收FIFO ? 字节宽度的随机访问和顺序访问(地址自动递增) ? 用于快速数据传送的内部DMA ? 硬件支持的IP 校验和计算 介质访问控制器(MAC)特性 ? 支持单播、组播和广播数据包 ? 可编程数据包过滤,并在以下事件的逻辑“与” 和“或”结果为真时唤醒主机: - 单播目标地址 - 组播地址 广播地址 - Magic Packet - 由64 位哈希表定义的组目标地址 - 多达64 字节的可编程模式匹配(偏移量可由用户定义)
淘宝店铺:https://www.wendangku.net/doc/b34400824.html,
1

DS12887时钟芯片_中文资料_

DS12887时钟芯片(中文资料一) 特点 ·可作为IBM AT 计算机的时钟和日历 ·与MC14681B 和DS1287的管脚兼容 ·在没有外部电源的情况下可工作10年 ·自带晶体振荡器及电池 ·可计算到2100年前的秒、分、小时、星期、日期、 月、年七种日历信息并带闰年补偿 ·用二进制码或BCD 码代表日历和闹钟信息 ·有12和24小时两种制式,12小时制时有AM 和PM 提示 ·可选用夏令时模式 ·可以应用于MOTOROLA 和INTEL 两种总线 ·数据/地址总线复用 ·内建128字节RAM 14字节时钟控制寄存器 114字节通用RAM ·可编程方波输出 ·总线兼容中断(/IRQ ) ·三种可编程中断 时间性中断可产生每秒一次直到每天一次中断 周期性中断122ms 到500ms 时钟更新结束中断 管脚名称 AD0-AD7-地址/数据复用总线 NC -空脚 MOT -总线类型选择(MOTOROLA/INTEL ) CS -片选 AS -ALE R/W -在INTEL 总线下作为/WR DS -在INTEL 总线下作为/RD RESET -复位信号 IRQ -中断请求输出 SQW -方波输出 VCC -+5电源 GND -电源地 上电/掉电 当VCC 高于4.25V200ms 后,芯片可以被外部程序操作;当VCC 低于4.25V 时,芯片处于写保护状态(所有的输入均无效),同时所有输出呈高阻状态;当VCC 低于3V 时,芯片将自动把供电方式切换为由内部电池供电。 管脚功能 MOT (总线模式选择) 当此脚接到VCC 时,选用的是MOTOROLA 总线时序;当它接到地或不接时,选用的是INTEL 总线时序。

基于STM32F103的网络温度报警器 物联网

基于STM32F103的网络温度报警器设计 作品名:基于STM32F103的网络温度报警器设计 作者:陈华健贾从含 时间:2015年6月17日

目录: 1.引言 (1) 2.利用普通二极管PN 结测试环境温度原理 (2) 3.器件的选择和芯片的介绍 (4) 4.UC/OS系统移植 (6) 5.文件系统的移植与文件系统基本函数的功能 (16) 6.Uip及socket实现方法 (27)

1.引言 近年来随着科技的飞速发展,嵌入式的应用正在不断深入,同时带动传统控制检测技术日益更新。在实时检测和自动控制的嵌入式应用系统中,嵌入式往往作为一个核心部件来使用,仅嵌入式方面知识是不够的,还应根据具体硬件结构软硬件结合,加以完善。 本系统使用STM32F103实现了接收由上位机通过TCP 协议发出的温度报警阈值信号,并存于SD片卡中。单片机利用普通二极管的PN 结测试环境温度,每30s 采集一次,将采集到的温度信息补充上时间(时、分、秒、毫秒)标注存储在存储芯片中。并将报警时的温度值与当前时间的温度进行比较,当前温度大于阀值温度时,通过发光二极管或蜂鸣器报警。上位机通过TCP,向单片机发送“Read_Info”命令后,单片机能将SD 卡中存储的所有数据发到PC 机的串口助手中;数据格式美观、易懂。 本系统采用普通二极管PN节的温度特性来测量环境温度不失为一种低成本而又容易实现的环境温度测量方式。使用STM32自带的ADC模块进一步降低了成本和设计难度。采用大容量存储芯片可以长时采集环境数据,并且在采集到的温度补充上时间信息使数据更加可信,同时移植了文件系统方便文件在WINDOWS下的读取和处理。 本系统采用了无线传输的方式配合可靠的电源设备或太阳能设备可以在室外持续的传输回温度信息或其他的气象数据(需配合适当的传感器),减少了人工成本,并且更加适应于野外大规模投放接点。

一步一步教你移植uIP

一步一步教你移植uIP0.9到8051+RTL8019AS 追风发表于2010-11-11 22:21|只看该作者|倒序浏览|打印 1. google一下uip,点击进入主页http://www.sics.se/~adam/uip/index.php/Main_Page 当前最新的uIP版本是 1.0,这个版本比较复杂,所以还是移植历史版本吧. 打开http://www.sics.se/~adam/old-uip/下载0.9版: http://www.sics.se/~adam/download/?f=uip-0.9.tar.gz 2. 打开Keil新建项目uIP0.9.uv2, 设置项目属性. 2 L( E/ A* h( C# e0 @6 m memory_model 设置为large 模式,这样默认的存储方式是xdata6 |0 v5 H. { m0 Q5 V+ s: O 因为uIP0.9编译后占用20K rom, 所以必须选一个32K(>20K)的rom的单片机,+ u* m8 p& T/ Z( o: f 比如Device可设置为SST89x58或者SST89x516xx, 解压缩官方下载的uIP0.9压缩包,添加文件至项目, ) |4 M1 V0 C5 a' w; b ! F3 ?- @, v' N% j5 u 需添加至项目的文件有:uip\uip.c, uip.c\uip.h, uip.c\uip_arch.h, ) y! x2 Q: E. A- a% p! l5 ` uip.c\uip_arp.c,uip.c\uip_arp.h , I; I- G7 d: t0 ]& A8 d unix\main.c, unix\uip_arch.c, unix\uipopt.h, 4 `: P* G, w$ m; S/ D, j* y apps\httpd\所有文件# j! B+ \7 |1 q1 c$ \5 ? 3. 因为data是系统关键字, 所以标识符data => dat 6 ~' C6 J& |4 ]4 M; Y2 i) } 以下文件需要改动: fs.h, fsdata.h,httpd.c 4. 为RTL8019AS 编写驱动程序(具体如何操作寄存器老古的网站有详细的教程), 2 r- F 3 k5 S, d- U. V e# M 内容在压缩包中的RTL8019AS.c, RTL8019AS.h 需要更改main.h中的如下地方: include "tapdev.h" => #include "rtl8019as.h" 7 `- j$ i: d Y8 {: A/ ~ tapdev_init() -> rtl8019as_init() 0 Q4 p9 l$ a2 H8 X w tapdev_send() -> rtl8019as_send()

SCD21-SDD21

摘要:本应用笔记介绍了一种新的测试方法,用来预测不平衡(不对称)双绞线在串行电缆上造成的抖动。文中阐述了对于作为质量评估的线对内偏差的一些误解和线对内偏差与抖动之间关系的错误理解。本文澄清了一个关键问题,即:电缆不平衡造成的差模电压与共模电压之间的相互转换,不同模式的电压具有不同的传输速率和损耗特性。本文介绍了一种廉价电缆传输数据时,不同模式电压的转换,合格/失效的判断准则与数据抖动有关。 类似文章还发表在Maxim工程期刊,第64期(PDF,2.5MB)。 概述 1Gbps以上的串行数字视频信号传输(如DVI?、HDMI?和DisplayPort?视频接口标准要求)大大提高了对连接PC和HDTV显示器电缆的性能要求。所以,传统的模拟音频/视频电缆供应商现在也必须与电信串行数字差分电缆制造商一样,了解关于2.5Gbps InfiniBand?和PCI Express?、3.125Gbps CX4以及4.25Gbps Fibre Channel的知识。 本文着重介绍由于视频信号的差模和共模分量的变换所引起的数据抖动现象。本文还揭示了线对间信号偏移的神秘面纱,并建议通过测试电缆来预测抖动。本文证明实际应用中并不一定要求使用昂贵的具有良好性能的差分电缆,只需实现良好的平衡性即可。 DVI/HDMI系统在0.25Gbps至3.40Gbps范围内所要求的常见数字视频传输差分电缆为100Ω屏蔽双绞线(STP),也可以使用100Ω的同轴电缆(twinax),这也是数据通信中比较常见的电缆。 保持平衡 DVI、HDMI和DisplayPort系统都包括四对差分互连线路,以便进行数字视频传输。如能满足两个前提,则利用廉价的接收器件即可恢复信号:1) 差分通路保持传输信号为差分模式,仅引入极少甚至根本不引入共模信号;2) 差分通路保持平衡,这意味着两根线对信号须保持对称。 电缆将信号能量保持在差分模式时,在整个频谱范围内会产生可预测的相位延迟及趋肤效应损耗。这两种效应很容易补偿。否则,信号将无法由常规的接收器恢复。当然,差分耦合电缆(STP或twinax)上差模与共模之间的转换会造成较大误差,无法预测相位延迟和信号损耗。 不一致造成的。例如,假设一对同轴电缆的长度不同(图1)。输入为差模信号,不存在共模电压。而输出信号将出现对应于传输延迟的线对偏差,除线对偏差外,还会产生共模能量,造成差模能量降低。 图1. 简单线对偏移将部分差模信号转换为共模(CM)能量 本例采用的激励为正弦波,而非数字不归零(NRZ)波形。图1所示同轴电缆的偏移延迟在整个频率范围内为常数。然而,STP或twinax电缆内数字NRZ波形的每个正弦(傅里叶)分量都会产生不同的偏移。 关于线对内偏差的误解 差模和共模之间的能量转换是一种常见的测量考虑因素,电缆制造商经常把线对内延迟偏差作为电缆质量保证(QA)的测试项目。然而,传统的测量线对内偏差的方法可能会得出一个错误结论,认为抖动是不可预测的。 误解1:线对内传输偏移相对于频率为固定值。 这种说法对于非差分耦合线对是正确的,例如同轴电缆,但是对于差分耦合电缆并非如此,例如STP和twinax。图2给出了28AWG twinax双绞线电缆的测试结果。线对内偏移实际上在不同频率下会发生极性变化。

一、定义及发展历史

经支气管冷冻活检(cryobiopsy,CB)技术是近十年发展起来的新技术,近年来相关文献报道很多并逐年增加,但该技术仍没有标准化操作流程,且其在间质性肺疾病诊断分类中的地位及安全性仍有待进一步研究。同时由于冷冻活检的快速发展,在不同医疗机构及操作者之间的技术存在很大差异。因此,制订经支气管冷冻活检技术临床应用专家共识对于规范该技术、合理选择适应证、提高诊断效率及安全性很有必要。 为此,中华医学会呼吸病学分会介入呼吸病学学组和中国医师协会呼吸医师分会介入呼吸病学工作委员会经多次讨论后制订了本共识,该专家共识的建立是基于既往研究文献的系统回顾和有实际操作经验专家的建议…,文献包括公开发表的文章和会议论文集。结合我国实际情况,考虑到现有的证据水平较低,达成一致意见但没有对证据水平和推荐力度进行正式的评级。 一、定义及发展历史 冷冻活检是经支气管镜将冷冻探头尖端送至支气管或肺内病变区域,通过制冷剂的快速释放吸收周围环境热量,从而使冷冻探头迅速降温,将探头周围的组织冷冻凝固,通过冷冻的黏附力,将探头和探头周围冻结的组织整体拔出,从而获取靶组织。与活检钳活检相比,由于获取标本组织较大且结构相对完整,有利于病理分析与诊断,因而成为许多呼吸系统疾病的新型活检方式。经支气管冷冻活检分为支气管腔内冷冻活检(endobronchial cryobiopsy,EBCB)和经支气管冷冻肺活检(transbronchial cryobiopsy,TBCB),前者针对支气管镜下可见的病变,主要位于气管和支气管腔内;而后者则针对支气管镜下不可见的外周肺病变。 2008年冷冻技术首次应用于支气管腔内病变取样引,2009年进一步拓展至间质性肺疾病(interstitial lung disease,ILD)的诊断并取得了较高的诊断阳性率和较好的安全性。近十年来,国外应用经支气管冷冻技术对支气管腔内病变、ILD、肺外周病灶、肺移植术后的监测等方面进行了系统的应用和研究,报道文献数量近几年增加迅速,2017年发表了近70篇,2018年初发表了“经支气管冷冻肺活检用于诊断弥漫性实质性肺疾病的专家共识”,2018年9月美国胸科学会(American thorax society,ATS)等多学会联合发布的特发性肺纤维化(idiopathic pulmonary fibrosis,IPF)诊断指南也特别关注了TBCB。我国2010年开展EBCB 技术,2016年进行了TBCB,近2年来冷冻活检技术逐渐引起了介入呼吸病学领域的关注,发展迅速,已开展了TBCB对间质性肺疾病诊断价值的前瞻性研究、气源压力变化对冷冻效能的影响、冷冻肺活检对ILD诊断有效性和安全性前瞻性多中心真实世界研究,这些工作显示了我国在冷冻活检工作方面的特色。 二、适应证及禁忌证 (一)适应证 1.EBCB:支气管腔内病变最常用的取样技术是活检钳活检(forceps biopsy,FB),但由于活检组织量小,导致诊断敏感度和确诊率偏低。一项采用EBCB对腔内可视病灶的多中心对照研究结果显示,EBCB诊断阳性率为95%,而常规FB的诊断阳性率为85.1%。EBCB 获得的标本较FB获得的标本大,而且诊断阳性率较FB明显增高,尽管轻中度出血的发生率较高,但严重出血的发生率并没有显著增加;同时由于EBCB的标本量明显多于FB,有利于后续的分子病理学检测。

uip协议栈下载

竭诚为您提供优质文档/双击可除 uip协议栈下载 篇一:uip之udp应用笔记 千兆网项目中,移植了uip到mcu中,采用udp通信方式,主要用来做一些控制协议的处理。刚开始接手的时候,并没有做过网络方面的应用,而且对tcp/ip及udp通信又不太熟悉。好在网上有一些文档,加上仔细阅读uip_process 代码,一边用抓包软件一边调试,总算把uip很好的应用了起来,而且还针对项目某些应用的特殊性,对uip源码进行了一些修改。本文前半部分对uip源码的一些重要函数进行介绍,后半部分将对修改的部分做个记录,以备往后查阅。 本次使用的是uip-1.0,抓包软件用的wireshark1.6.7,这个软件真的很不错,居然支持gigevision,这点真的很意外。 一、一个完整的udp数据报文格式 其实uip就是将你要发送到网络上的数据加上报头,好让它被成功发送到目的主机。所以我们要先搞清楚一个完整的数据报文,才能搞清楚uip到底在做些什么。 ethernetheader:由目标mac和本机mac及type组成,

共14byte,当目标mac全为ff时,表示是udp广播。 type=0x0800表示是ip。在uip中,ethernetheader结构体定义如下: ipheader:0x45表示version=4,headerlength=20byte;0028表示ipheader+udpheader+userdata长度为40byte; 6c14为包的id,每发一个包,这个id会自加1。80的意义是timetolive,表示这个包的存活时间,路由每转发一次,就会对它自减1。17表示通信协议类型为udp,4a0a为ipheader的校验码。再后面就是源ip和目的ip地址了。 udpheader:0aaa表示srcport为2730;0f74表示dstprot为3956;14表示udpheader+userdata长度为20byte,c477表示udpheader的校验码,在一般的情况下,这个可以为0。 在uip中,ipheader和udpheader结构体定义如下: userdata:再后面就是用户的数据了。 二、aRp数据报文格式 网络中是使用ip来标识主机的,而数据链路层的第一 道关卡是mac地址。因此ip和mac有一张动态映射表,而 这张表就是由aRp协议来建立并维护的。下面是一个aRp数据报文。 同样的,前面14byte是ethheader。hardwaretype对 于以太网来说为0001;0800表示是ipV4;06表示mac地址

uip之udp程序参考

一、UDP的移植 a> uipopt.h 中修改 #define UIP_UDP 1 #define UIP_UDP_CONNS 10(同时可建立udp的连接数) #define UIP_UDP_APPCALL udp_appcall (UDP的用户接口函数) 添加#include b> 新建udp.c 和udp.h 两个文件 udp.c中定义两个函数 udpinit(void) { uip_ipaddr(ipaddr, RIPADDR0, RIPADDR1, RIPADDR2, RIPADDR3); uip_udp_new(ipaddr, UDP_LPORT, UDP_RPORT); //建立一个udp,指定udp端口。 //注意:我对uip_udp_new()函数做了修改,原来本地端口是随机的,我改为了可以配置的。 } //当UDP数据被tapdev_read ()收到,uip_process()函数对UDP进行解析,如果正确,则调用udp_appcall()来交给用户处理。此时,用户可以用uip_newdata()检测是否有新数据,新数据放在uip_appdata指针中,长度为uip_len。 //当定时轮询到达,后也会调用udp_appcall(),可以用uip_poll()检查。此时,用户可以主动发送数据。只须将数据放入指针uip_appdata后的空间中,并将数据长度传给 uip_slen便可。 下面给出了函数的模型(仅供参考): void udp_appcall(void) { if(uip_udp_conn->rport == HTONS(UDP_RPORT)) { if(uip_poll()) { /* for(u16_t i=0; i<1000; i++) {

相关文档
相关文档 最新文档