linux 內(nèi)核定時(shí)器timer_list用法
作者 codercjg 在 30 十月 2015, 2:27 下午
實(shí)現(xiàn)了一個(gè)秒定時(shí)器涌攻,每秒更新計(jì)數(shù)值。驅(qū)動(dòng)源碼second.c:
include <linux/init.h>#include <linux/module.h>#include <linux/fs.h>#include <linux/miscdevice.h>#include <linux/types.h>#include <linux/timer.h>#include <asm/atomic.h>#include <asm/uaccess.h>struct second_t{ atomic_t counter; struct timer_list timer;};struct second_t second;void second_timer_handler(unsigned long arg){ mod_timer(&second.timer, jiffies+HZ); atomic_inc(&second.counter); printk("second timer: %d\n", atomic_read(&second.counter));}int second_open(struct inode *inode, struct file *filp){ init_timer(&second.timer); second.timer.expires = jiffies + HZ; second.timer.function = second_timer_handler; atomic_set(&second.counter, 0); add_timer(&second.timer); return 0;}int second_release(struct inode *inode, struct file *filp){ del_timer(&second.timer); return 0;}static ssize_t second_read(struct file *filp, char __user *buf, size_t count, loff_t ppos){ int counter = atomic_read(&second.counter); if(put_user(counter, (int)buf)){ return -EFAULT; }else { return sizeof(int); }}static struct file_operations fops = { .owner = THIS_MODULE, .open = second_open, .release = second_release, .read = second_read,};static struct miscdevice misc = { .minor = MISC_DYNAMIC_MINOR, .name = "second", .fops = &fops,};static int __init second_init(void){ misc_register(&misc); return 0;}static void __exit second_exit(void){ misc_deregister(&misc);}MODULE_AUTHOR("codercjg");MODULE_LICENSE("Dual BSD/GPL");module_init(second_init);module_exit(second_exit);
測試源碼secondapp.c:
include <sys/types.h>#include <unistd.h>#include <fcntl.h>#include <stdlib.h>#include <errno.h>#include <stdio.h>int main(int argc, char *argv[]){ int second; int fd = open("/dev/second", O_RDONLY); if(fd<0){ perror("open"); exit(errno); } while(1){ read(fd, &second, 4); printf("%d\n", second); sleep(1); } close(fd); return 0;}
分類: Linux驅(qū)動(dòng) | 評(píng)論
mini2440 led驅(qū)動(dòng)
作者 codercjg 在 28 十月 2015, 8:42 下午
datasheet上外設(shè)寄存器地址都是物理地址铃诬,而cpu訪問的是虛擬地址性含,通過mmu映射到實(shí)際物理地址。
在驅(qū)動(dòng)中要想讀寫外設(shè)寄存器首先要找到物理地址對應(yīng)的虛擬地址捉偏,這通過io內(nèi)存函數(shù)request_mem_region()和ioremap()實(shí)現(xiàn)物理地址到虛擬地址的轉(zhuǎn)換鸳君。
request_mem_region()用于判斷物理地址是否被占用农渊,ioremap()用于創(chuàng)建頁表實(shí)現(xiàn)物理地址到虛擬地址的映射。
led1 led2 led3 led4 分別對應(yīng)io口GPB5 GPB6 GPB7 GPB8或颊,需要設(shè)置寄存器GPBCON設(shè)置它們?yōu)檩敵鲈椅桑O(shè)置GPBUP禁用上拉電阻传于。
GPBDAT寄存器可用于點(diǎn)亮和熄滅led。GPB IO口寄存器物理基地址為0×56000010批糟,共占16字節(jié)格了。
驅(qū)動(dòng)源碼ledstest.c:
/* * for mini2440 board leds, GPB5-led1 GPB6-led2 GPB7-led3 GPB8-led4 */#include <linux/init.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/miscdevice.h>#include <linux/fs.h>#include <linux/ioport.h>#include <asm/io.h>MODULE_AUTHOR("codercjg");MODULE_LICENSE("Dual BSD/GPL");#define GPB_REG_BASE 0x56000010#define GPB_REG_SIZE 16 static void __iomem *gpbbase;static volatile unsigned int *gpbcon, *gpbdata, *gpbup;static struct resource *iomem; int leds_ioctl(struct inode *node, struct file *file, unsigned int cmd, unsigned long arg){ switch (cmd) { case 0: if (arg == 1) { *gpbdata |= (1 << 5); } else if (arg == 2) { *gpbdata |= (1 << 6); } else if (arg == 3) { *gpbdata |= (1 << 7); } else if (arg == 4) { *gpbdata |= (1 << 8); } else { return -EINVAL; } break; case 1: if (arg == 1) { gpbdata &= ~(1 << 5); } else if (arg == 2) { gpbdata &= ~(1 << 6); } else if (arg == 3) { gpbdata &= ~(1 << 7); } else if (arg == 4) { gpbdata &= ~(1 << 8); } else { return -EINVAL; } break; default: return -EINVAL; } return 0;}static struct file_operations fops = { .owner = THIS_MODULE, .ioctl= leds_ioctl,};static struct miscdevice misc = { .minor = MISC_DYNAMIC_MINOR, .name = "ledstest", .fops = &fops,}; static int leds_driver_init(void){ iomem = request_mem_region(GPB_REG_BASE, GPB_REG_SIZE, "leds"); if (iomem) { gpbbase = ioremap(GPB_REG_BASE, GPB_REG_SIZE); gpbcon = (unsigned int)gpbbase; gpbdata = (unsigned int)(gpbbase + 4); gpbup = (unsigned int)(gpbbase + 8); / config GPB5 GPB6 GPB7 GPB8 output */ *gpbcon &= ~(3 << 10) & ~(3 << 12) & ~(3 << 14) & ~(3 << 16); gpbcon |= (1 << 10) | (1 << 12) | (1 << 14) | (1 << 16); / disable pullup */ gpbup |= (1 << 5) | (1 << 6) | (1 << 7) | (1 << 8); / leds off */ *gpbdata |= (1 << 5) | (1 << 6) | (1 << 7) | (1 << 8); misc_register(&misc); printk("leds_driver_init\n"); return 0; } else { return -EBUSY; }}static void leds_driver_exit(void){ if (iomem) { misc_deregister(&misc); iounmap(gpbbase); release_mem_region(GPB_REG_BASE, GPB_REG_SIZE); iomem = NULL; } printk("leds_driver_exit\n");}module_init(leds_driver_init);module_exit(leds_driver_exit);
測試代碼ledsapp.c:
include <stdio.h>
include <sys/types.h>
include <sys/ioctl.h>
include <unistd.h>
include <fcntl.h>
include <stdlib.h>
int main(int argc, char *argv[])
{
int fd;
int cmd;
int no;
if(argc != 3 || sscanf(argv[1], "%d", &cmd) !=1 || sscanf(argv[2], "%d", &no) !=1){
perror("usage: ledsapp x x");
exit(1);
}
fd = open("/dev/ledstest", O_RDWR);
if(fd < 0){
perror("open /dev/ledstest");
exit(1);
}
if(ioctl(fd, cmd, no) < 0){
perror("ioctl");
exit(1);
}
close(fd);
return 0;
}
驅(qū)動(dòng)名為leds時(shí)會(huì)沖突,所以改成ledstest徽鼎。
加載led驅(qū)動(dòng)后盛末,發(fā)現(xiàn)還是流水燈。要想用ledapp控制它否淤,就得先停止控制led的程序悄但。
/etc/rc.d/init.d/leds stop
之后ledsapp 1 1就可以點(diǎn)亮led1, ledsapp 0 1就可以熄滅led1石抡。
分類: Linux驅(qū)動(dòng) | 評(píng)論
gprs使用外置協(xié)議棧lwip
作者 codercjg 在 23 十月 2015, 4:53 下午
MG323 GPRS模塊檐嚣,內(nèi)置協(xié)議棧只支持TCP和UDP等上層協(xié)議,而我需要完成一個(gè)gprs ping 遠(yuǎn)程主機(jī)測延時(shí)的功能啰扛,所以需要一個(gè)外置協(xié)議棧來發(fā)送icmp ping request嚎京。一開始以為只要直接發(fā)送ip數(shù)據(jù)報(bào)就行了,后來發(fā)現(xiàn)還需要實(shí)現(xiàn)ppp隐解。因?yàn)樾枰猵pp,icmp和dns等功能鞍帝,偷懶采用了freertos+lwip1.3.2。
使用過程中走過的坑:
1.gprs的AT命令解析主要用到sscanf()和sprintf()煞茫,當(dāng)任務(wù)棧分配比較小時(shí)帕涌,這兩個(gè)函數(shù)很可能導(dǎo)致棧溢出。
2.lwip中用到動(dòng)態(tài)內(nèi)存分配時(shí)续徽,要注意下pbufalloc()和pbuffree()的使用蚓曼,發(fā)現(xiàn)當(dāng)ppp收到一個(gè)IP包后,會(huì)為它分配內(nèi)存钦扭,當(dāng)是tcp和udp時(shí)處理完成后都會(huì)釋放該內(nèi)存纫版,而當(dāng)識(shí)別出是icmp報(bào)文,做了相關(guān)處理后居然沒有釋放土全,直接導(dǎo)致內(nèi)存泄漏捎琐。解決方法是在raw.c 中rawinput()里加上一句pbuffree()。
/* receive callback function available /if (pcb->recv != NULL) {/ the receive callback function did not eat the packet? /if (pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src)) != 0) {* pbuf_free(p); / add by cjg, to fix ping memory leak bug // receive function ate the packet /p = NULL;eaten = 1;
3.當(dāng)發(fā)生內(nèi)存泄露后裹匙,最終會(huì)導(dǎo)致分配內(nèi)存失敗,此時(shí)調(diào)用memcpy()末秃,傳入空指針概页,直接導(dǎo)致訪存錯(cuò)誤。
4.創(chuàng)建lwip相關(guān)的任務(wù)要調(diào)用systhreadnew()因?yàn)樗鼤?huì)同時(shí)創(chuàng)建一個(gè)定時(shí)器练慕,某些時(shí)刻會(huì)檢查惰匙,要是你不小心用到它而卻用xTaskCreate()創(chuàng)建的任務(wù)技掏,跑著跑著肯定出異常。
最后附一個(gè)流程:
撥號(hào)入網(wǎng):
gprssendcmd(“AT\r”);
gprssendcmd(“ATE0\r”);
gprssendcmd(“ATS0=0\r”);
gprssendcmd(“AT+CGDCONT=1,\”IP\”,\”CMNET\”\r”); /* 加入移動(dòng)網(wǎng)絡(luò)项鬼,移動(dòng)卡聯(lián)通卡都可以加入這個(gè)網(wǎng)絡(luò) /
gprssendcmd(“ATD99#\r”); /* 撥號(hào)上網(wǎng)/
之后不再發(fā)AT指令哑梳,而是用lwip ppp發(fā)數(shù)據(jù)了。
ppp獲取IP:
主要是為pppOpen()實(shí)現(xiàn)一個(gè)回調(diào)函數(shù)linkStatusCB()用于獲取ip和dns server等
pppInit();pppSetAuth(PPPAUTHTYPE_CHAP, NULL, NULL);pppOpen(fd, linkStatusCB, NULL);/send lcp req to peer// ppp callback /void linkStatusCB(void ctx, int errCode, void arg){struct ppp_addrs addrs = arg;if (errCode == PPPERR_NONE) {/ connect ok. /GPRSDEBUG(("connected\n"));GPRSDEBUG(("ipaddr = %s ", inetntoa(addrs->our_ipaddr)));GPRSDEBUG(("netmask = %s ", inet_ntoa(addrs->netmask)));GPRSDEBUG(("dns1 = %s ", inet_ntoa(addrs->dns1)));GPRSDEBUG(("dns2 = %s \n", inet_ntoa(addrs->dns2)));pppaddrs = (struct ppp_addrs)arg;gprsstate = IP_GOT;} else {gprsstate = PPP_ERR;/* connect lost /GPRSDEBUG(("connection lost\n"));}}
dns解析:
主要是為dnsgethostbyname()實(shí)現(xiàn)一個(gè)回調(diào)函數(shù)dnsfound()用于解析成功時(shí)獲取IP地址
dns_init();dns_setserver(0, &pppaddrs.dns1); / 設(shè)置dns 服務(wù)器地址绘盟,由ppp獲得 /dnsresolve(hostname, &targetip); / 解析域名 // dns resolve callback /void dnsfound(const char name, struct ipaddr ipaddr, void callback_arg){if (!ipaddr) { / 解析成功時(shí)該值非空鸠真,解析失敗時(shí)該值為空/GPRSDEBUG(("dns resolve:%s failed\n", name));gprsstate = DNSRESOLVEDERR;} else {GPRSDEBUG(("dns resolve: %s===>%s\n", name, inet_ntoa(ipaddr)));dnsip = ipaddr;gprsstate = DNSRESOLVEDOK;}}/* dns resolve /errt dnsresolve(char hostname, struct ipaddr ip){errt err = dnsgethostbyname(hostname, ip, dns_found, NULL);switch (err) {case ERR_OK:GPRSDEBUG(("dns resolve: %s===>%s\n", hostname, inet_ntoa(ip)));dnsip = ip;gprsstate = DNSRESOLVEDOK;break;case ERR_INPROGRESS:/ need to udp ask, and then return result via callback function /GPRSDEBUG(("dns resolving...\n"));gprsstate = DNS_RESOLVING;break;default:GPRSDEBUG(("dns resolve error\n"));gprsstate = DNSRESOLVED*ERR;break;}return err;}
接下來就是ping、tcp和udp等應(yīng)用了龄毡。
分類: lwip協(xié)議棧 | 2個(gè)評(píng)論
lwip dns
作者 codercjg 在 16 十月 2015, 10:28 上午
lwIP DNS OverviewThe lwIP stack provides a basic DNS client (introduced in 1.3.0) to allow other applications to resolve host names to addresses using the DNS (Domain Name System) protocol. LWIP_DNS must be #defined in lwipopts.h to a nonzero value to enable DNS support in your lwIP platform.
if DHCP is used in conjunction with the lwIP DNS client, DNS will automatically be configured to use the offered DNS server (if the DHCP server offers one).
Application DNS requests with Raw/Native APIRaw API applications can use the dns_gethostbyname() function to request a lookup, and specify a callback function to notify the application when the lookup is complete. As you can see from its header bellow, this function will return immediately. If the requested address is already known, it will be returned via the passed argument pointer. If a request to a DNS server needs to be made, your callback function will be called when it has finshed.
- err_t* dns_gethostbyname(const char hostname, struct ip_addr addr, dns_found_callback found, void callback_arg) Resolve a hostname (string) into an IP address.* NON-BLOCKING callback version for use with raw API!!!** Returns immediately with one of err_t return codes:* – ERR_OK if hostname is a valid IP address string or the host* name is already in the local names table.* – ERR_INPROGRESS enqueue a request to be sent to the DNS server* for resolution if no errors are present.** @param hostname the hostname that is to be queried* @param addr pointer to a struct ip_addr where to store the address if it is already* cached in the dns_table (only valid if ERR_OK is returned!)* @param found a callback function to be called on success, failure or timeout (only if* ERR_INPROGRESS is returned!)* @param callback_arg argument to pass to the callback function* callback function and argument defined as follows:* A function of this type must be implemented by the application using the DNS resolver.* @param name pointer to the name that was looked up.* @param ipaddr pointer to a struct ip_addr containing the IP address of the hostname,* or NULL if the name could not be found (or on any other error).* @param callback_arg a user-specified callback argument passed to dns_gethostbyname:** typedef void (*dns_found_callback)(const char *name, struct ip_addr *ipaddr, void *callback_arg);
A sample call:
struct ip_addr resolved;switch(dns_gethostbyname("www.lwIP.com", &resolved, smtp_serverFound, NULL)){case ERR_OK:// numeric or cached, returned in resolvedsmtp.serverIP.addr = resolved->addr;smtp.state = SMTP_NAME_RESOLVED;break;case ERR_INPROGRESS:// need to ask, will return data via callbacksmtp.state = SMTP_NAME_RESOLVING;break;default:// bad arguments in function callbreak;}A sample DNS callback function:void smtp_serverFound(const char *name, struct ip_addr *ipaddr, void *arg){if ((ipaddr) && (ipaddr->addr)){smtp.serverIP.addr = ipaddr->addr;smtp.state = SMTP_NAME_RESOLVED;if (smtp_connect() == ERR_OK)return;smtp.lastError = SMTP_CONNECT_FAILED;}elsesmtp.lastError = SMTP_UNKNOWN_HOST;smtp.state = SMTP_IDLE;}
Application DNS requests with Netconn APIerr_t netconn_gethostbyname(const char *name, ip_addr_t *addr)
See also netconn_gethostbyname().
Application DNS requests with Sockets APIFor socket based apps, a gethostbyname() wrapper function is provided that blocks during the lookup if necessary. Use the following functions:
gethostbyname() – standard implementation, blocks if necessary until lookup complete or failsgethostbyname_r() – thread-safe version of gethostbyname (separate buffer for each invokation)
http://lwip.wikia.com/wiki/DNS
分類: lwip協(xié)議棧 | 評(píng)論
MINI2440 開發(fā)環(huán)境搭建
作者 codercjg 在 13 十月 2015, 10:19 下午
從搭好交叉編譯環(huán)境到在板子上跑第一個(gè)hello driver吠卷,其中的波折真是一言難盡。
其中要注意的地方有:
1.重新編譯光盤里的linux內(nèi)核源碼生成zImage, 并下載到板子上沦零。否則編譯出的linux 驅(qū)動(dòng)可能會(huì)和板子上跑的內(nèi)核不匹配祭隔,
從而導(dǎo)致insmod時(shí)出現(xiàn)莫名其妙的錯(cuò)誤。
make distcelan
cp config_mini2440_w35 .config
make zImage
2.下載zImage到板子上時(shí)路操,安裝usb驅(qū)動(dòng)折騰了好久疾渴。其實(shí)我的板子從Nor Flash啟動(dòng)時(shí)跑的是superboot, 不是supervivi,只需要
安裝光盤里的MiniTools-USB就可以。
3.然后用minitool下載之前編譯內(nèi)核生成的zImage
4.最后掛載nfs屯仗,我在vmware Ubuntu虛擬機(jī)里開發(fā)搞坝,省得下載編譯后的驅(qū)動(dòng)麻煩
ifconfig eth0 192.168.3.200 broadcast 192.168.3.255 netmask 255.255.255.0
mkdir /mnt/nfs
mount -t nfs -o nolock 192.168.3.102:/home/user/nfs /mnt/nfs
之后就可以直接insmod /mnt/nfs下的hello driver了。
分類: Linux驅(qū)動(dòng) | 評(píng)論
lwip ppp
作者 codercjg 在 13 十月 2015, 11:04 上午
PPP from an application perspectiveThere are two ways to use lwIP with PPP support. Either PPPoE (PPP over Ethernet) or PPP-over-serial. lwIP supports being run in a threaded environment, where ppp is a separate task that runs alongside the main lwIP thread. lwIP also supports being run from a main loop, with lwIP functions being called from the main loop.****
PPP over serialTo setup a PPP connection over a serial link you will need to provide the Serial IO functions.Both the thread environment and a main loop require implemented sio_write() to be implemented./*** Writes to the serial device.** @param fd serial device handle* @param data pointer to data to send* @param len length (in bytes) of data to send* @return number of bytes actually sent** @note This function will block until all data can be sent./u32_t sio_write(sio_fd_t fd, u8_t data, u32_t len);
With Task SupportIn addition to sio_write(), sio_read(), sio_read_abort() and the linkStatusCB are required to be implemented by you. The first 2 functions are statically linked, while the last function is defined through a function pointer (so the name can be different, and could be dynamically created as well).The function sio_read() is called from the pppInputThread, repeatedly. It blocks until it fills the requested buffer size or times-out, reading data from the serial device. It must abort itself if there is a call to sio_read_abort(). The soft link between sio_read and sio_read_abort must be implemented by you, either via a global variable, RTOS event, etc. The timeout should be relatively small, just large enough so that data is actually buffered in more than 1 byte chunks but small enough to make the ppp stack responsive. A timeout of about 2 ms is reasonable./* Reads from the serial device.** @param fd serial device handle* @param data pointer to data buffer for receiving* @param len maximum length (in bytes) of data to receive* @return number of bytes actually received – may be 0 if aborted by sio_read_abort/u32_t sio_read(sio_fd_t fd, u8_t data, u32_t len);The sio_read_abort() function must cause the sio_read command to exit immediately. This command is called by the tcpip_thread, mostly when ending a PPP session (terminated, link down or explicit close)./ Aborts a blocking sio_read() call.** @param fd serial device handle*/void sio_read_abort(sio_fd_t fd);****
**Required callback function *The callbackvoid (linkStatusCB)(void *ctx, int errCode, void arg)is called under the following events:Link Terminated. errCode is nonzero, arg is null.sifup (Interface Up).errCode is PPPERR_NONE, and arg is pointer to ppp_addrs structure, which contains IP address.sifdown (Interace Down). errCode is PPPERR_CONNECT, and arg is null.The errCode can be one of the following#define PPPERR_NONE 0 / No error. /#define PPPERR_PARAM -1 / Invalid parameter. /#define PPPERR_OPEN -2 / Unable to open PPP session. /#define PPPERR_DEVICE -3 / Invalid I/O device for PPP. /#define PPPERR_ALLOC -4 / Unable to allocate resources. /#define PPPERR_USER -5 / User interrupt. /#define PPPERR_CONNECT -6 / Connection lost. /#define PPPERR_AUTHFAIL -7 / Failed authentication challenge. /#define PPPERR_PROTOCOL -8 / Failed to meet protocol. /The ctx pointer is an optional user defined pointer that is defined as an argument in the call to pppOverSerialOpen, which can point to user defined data.
With no Task SupportYou need to receive the serial data in your main thread, then from your main thread callpppos_input(int pd, u_char data, int len);****
Example Task Application codeThis example shows the initialization of the TCP and PPP threads. It assumes that you will do your socket handling in the context of the main() function.
include "ppp/ppp.h"#define PPP_SERIAL_PORT 0static void linkStatusCB(void* ctx, int errCode, void* arg);int main(void) { int connected = 0; int setup = 0; int pd; const char username = "myuser"; const char password = "mypassword"; / initialise lwIP. This creates a new thread, tcpip_thread, that * communicates with the pppInputThread (see below) / tcpip_init(tcpip_init_done, &setup); while (!setup) { sleep(1); } / initialise PPP. This needs to be done only once after boot up, to * initialize global variables, etc. / pppInit(); / set the method of authentication. Use PPPAUTHTYPE_PAP, or * PPPAUTHTYPE_CHAP for more security . * If this is not called, the default is PPPAUTHTYPE_NONE. / pppSetAuth(PPPAUTHTYPE_ANY, username, password); / call the board specific function that will open the specific serial * port hardware, for example, configuring pins, I/Os, UART, USART, * clocks, etc. This function is not part of lwip or ppp. You need to * supply this or find an example for your hardware. / OpenMySerialPortOrUART(PPP_SERIAL_PORT, ...); / call the board specific function that will connect to the modem, * ie dialing phone numbers, sending configuration AT commands, etc. * This function is not part of lwip or ppp. You need to supply this if (DialOutMyModem(PPP_SERIAL_PORT, ...) != 0) { printf("can't dial out"); } else { /* Open a new PPP connection using the given I/O device. * This initializes the PPP control block but does not * attempt to negotiate the LCP session. * Return a new PPP connection descriptor on success or * an error code (negative) on failure. * This call creates one new thread per call, to service the particular * serial port, serviced by the pppInputThread function. / pd = pppOverSerialOpen(PPP_SERIAL_PORT, linkStatusCB, &connected); if (pd >= 0) { // the thread was successfully started. while (!connected && timeout(60 seconds)) { sleep(100 ms); } if (!timeout) { // We are connected on lwIP over PPP! while (working) { / create some socket connections, * do writes and reads on the sockets, close them, etc / } } / calling pppClose will end the pppInputThread associated with pd*/ pppClose(pd); } // shut down the rest of your hardware.}static void tcpip_init_done(void *arg){ if (arg) { *((bool *)arg) = 1; }}static void linkStatusCB(void *ctx, int errCode, void *arg) { //DTRACE("ctx = 0x%04X, errCode = %d arg = 0x%04X", ctx, errCode, arg); int *connected = (int *) ctx; struct ppp_addrs addrs = arg; if (errCode == PPPERR_NONE) { / We are connected */ connected = 1; syslog(LOG_DEBUG, "ip_addr = %s", inet_ntoa(addrs->our_ipaddr)); syslog(LOG_DEBUG, "netmask = %s", inet_ntoa(addrs->netmask)); syslog(LOG_DEBUG, "dns1 = %s", inet_ntoa(addrs->dns1)); syslog(LOG_DEBUG, "dns2 = %s", inet_ntoa(addrs->dns2)); } else { / We have lost connection */ }}
**Debug Support **Add this to lwipopts.h#define PPP_THREAD_NAME “ppp”#define PPP_THREAD_STACKSIZE 200#define PPP_THREAD_PRIO 2#define LWIP_DEBUG 1#define PPP_DEBUG LWIP_DBG_ONPPP packets all start and end with 0x7E. If you don’t see these, something is wrong with your low level driverFurther packet debugging hints are here: http://lists.nongnu.org/archive/html/lwip-users/2011-06/msg00036.htmlIf you have trouble with the RTOS crashing on pppClose, look here :
http://lists.gnu.org/archive/html/lwip-users/2012-02/msg00124.html
quote from: http://lwip.wikia.com/wiki/PPP
分類: lwip協(xié)議棧 | 評(píng)論