【RL-TCPnet网络教程】第26章 RL-TCPnet之DHCP应用

第26章     RL-TCPnet之DHCP应用

本章节为大家讲解RL-TCPnet的DHCP应用,学习本章节前,务必要优先学习第25章的DHCP基础知识。有了这些基础知识之后,再搞本章节会有事半功倍的效果。

本章教程含STM32F407开发板和STM32F429开发板。

26.1  初学者重要提示

26.2  DHCP函数

26.3  DHCP配置说明(Net_Config.c)

26.4  DHCP调试说明(Net_Debug.c)

26.5  DHCP检测过程

26.6  网络调试助手和板子的操作步骤

26.7  实验例程说明(RTX)

26.8  总结

26.1  初学者重要提示

  1. 学习本章节前,务必保证已经学习了第25章的基础知识。
  2. 本章相对比较简单,配套的例子中实现了一种8秒内无法通过DHCP Client获取动态IP的情况下,使用配置向导文件Net_Config.c中设置的静态IP地址。

26.2  DHCP函数

涉及到DHCP的,仅有如下两个函数:

  • dhcp_disable

此函数比较简单,用于禁止DHCP。

  • dhcp_cbfunc

此函数是DHCP的回调函数,实际测试发现,这个函数没有任何效果,也就是此函数没有被调用到。

关于这2个函数的讲解及其使用方法可以看教程第 3 章 3.4 小节里面说的参考资料 rlarm.chm 文件:

注意,这两个函数都不支持重入,也就是不支持多任务调用。

26.3  DHCP配置说明(Net_Config.c)

(本章节配套例子的配置与本小节的说明相同)

RL-TCPnet的配置工作是通过配置文件Net_Config.c实现。在MDK工程中打开文件Net_Config.c,可以看到下图所示的工程配置向导:

RL-TCPnet要配置的选项非常多,我们这里把几个主要的配置选项简单介绍下。

System Definitions

(1)Local Host Name

局域网域名。

这里起名为armfly,使用局域网域名限制为15个字符。

(2)Memory Pool size

参数范围1536-262144字节。

内存池大小配置,单位字节。另外注意一点,配置向导这里显示的单位是字节,如果看原始定义,MDK会做一个自动的4字节倍数转换,比如我们这里配置的是8192字节,那么原始定义是#define MEM_SIZE  2048,也就是8192/4 = 2048。

(3)Tick Timer interval

可取10,20,25,40,50,100,200,单位ms。

系统滴答时钟间隔,也就是网络协议栈的系统时间基准,默认情况下,取值100ms。

Ethernet Network Interface

以太网接口配置,勾选了此选项就可以配置了,如果没有使能DHCP的话,将使用这里配置的固定IP

(1)MAC Address

局域网内可以随意配置,只要不跟局域网内其它设备的MAC地址冲突即可。

(2)IP Address

IP地址。

(3)Subnet mask

子网掩码。

(4)Default Gateway

默认网关。

Ethernet Network Interface

以太网接口配置,这个配置里面还有如下两项比较重要的配置需要说明。

(1)NetBIOS Name Service

NetBIOS局域网域名服务,这里打上对勾就使能了。这样我们就可以通过前面配置的Local Host Name局域网域名进行访问,而不需要通过IP地址访问了。

(2)Dynaminc Host Configuration

即DHCP,这里打上对勾就使能了。使能了DHCP后,RL-TCPnet就可以从外接的路由器上获得动态IP地址。

(3)Vendor Class Identifier

厂商ID,如果设置了的话,会将其加到DHCP的请求消息中,用于识别网络设备的不同厂商。

(4)Bootfile Name

从DHCP 服务器获取的引导文件名。

(5)NTP Servers

从DCHP服务器获得NTP服务器列表。

UDP Sockets

UDP Sockets配置,打上对勾就使能了此项功能

(1)Number of UDP Sockets

用于配置可创建的UDP Sockets数量,这里配置了5个。

范围1 – 20。

TCP Sockets

TCP Sockets配置,打上对勾就使能了此项功能

(1)Number of TCP Sockets

用于配置可创建的TCP Sockets数量。

(2)Number of Retries

范围0-20。

用于配置重试次数,TCP数据传输时,如果在设置的重试时间内得不到应答,算一次重试失败,这里就是配置的最大重试次数。

(3)Retry Timeout in seconds

范围1-10,单位秒。

重试时间。如果发送的数据在重试时间内得不到应答,将重新发送数据。

(4)Default Connect Timeout in seconds

范围1-600,单位秒。

用于配置默认的保持连接时间,即我们常说的Keep Alive时间,如果时间到了将断开连接。常用于HTTP Server,Telnet Server等。

(5)Maximum Segment Size

范围536-1460,单位字节。

MSS定义了TCP数据包能够传输的最大数据分段。

(6)Receive Window Size

范围536-65535,单位字节。

TCP接收窗口大小。

BSD Socket Interface

BSD Socket配置,打上对勾就使能了此项功能

(1)BSD_NUMSOCKS

用于配置可创建的BSD Socket数量。

范围1-20。

(2)BSD_SRVSOCKS

定义的BSD Socket中可以采用TCP通信协议的服务器个数。

(3)BSD_RCVTOUT

socket接收函数recv工作在阻塞状态时的溢出时间设置,单位秒。

范围0-600秒,配置为0的话,表示无限等待。

(4)BSD_GETHOSTEN

启用或禁用Berkeley风格的主机名解。

26.4 DHCP调试说明(Net_Debug.c)

(重要说明,RL-TCPnet的调试是通过串口打印出来的)

RL-TCPnet的调试功能是通过配置文件Net_Debug.c实现。在MDK工程中打开文件Net_Debug.c,可以看到下图所示的工程配置向导:

Print Time Stamp

勾选了此选项的话,打印消息时,前面会附带时间信息。

其它所有的选项

默认情况下,所有的调试选项都关闭了,每个选项有三个调试级别可选择,这里我们以DHCP Debug为例,点击下拉列表,可以看到里面有Off,Errors only和Full debug三个调试级别可供选择,每个调试选项里面都是这三个级别。

Off:表示关闭此选项的调试功能。

Errors only:表示仅在此选项出错时,将其错误打印出来。

Full debug:表示此选项的全功能调试。

下面是对DHCP Debug配置为Full debug时,打印出来的消息:

26.5 DHCP检测过程

本章节配套的程序中对DHCP检测过程做了一个简单的判断,8秒内不能获得动态IP地址的话,将使用配置向导文件Net_Config.c里面设置的固定IP地址:192.168.1.100。

检测代码如下:

  1 /*
  2 
  3 **********************************************************************************************************
  4 
  5                                                    外部调用
  6 
  7 **********************************************************************************************************
  8 
  9 */
 10 
 11 #define DHCP_TOUT   80                 /* DHCP动态IP获取的溢出时间设置为8秒 */
 12 
 13 #define MY_IP localm[NETIF_ETH].IpAdr
 14 
 15 extern LOCALM localm[];             
 16 
 17  
 18 
 19  
 20 
 21 /*
 22 
 23 **********************************************************************************************************
 24 
 25                                                    变量
 26 
 27 **********************************************************************************************************
 28 
 29 */
 30 
 31 uint32_t dhcp_tout;
 32 
 33 uint8_t DHCP_Status[2][40] = {"IP: 192.168.X.X",              
 34 
 35                               "Waiting for DHCP"};
 36 
 37  
 38 
 39  
 40 
 41 /*
 42 
 43 *********************************************************************************************************
 44 
 45 *    函 数 名: main
 46 
 47 *    功能说明: 标准c程序入口。
 48 
 49 *    形    参: 无
 50 
 51 *    返 回 值: 无
 52 
 53 *********************************************************************************************************
 54 
 55 */
 56 
 57 static void dhcp_check(void)
 58 
 59 {
 60 
 61  
 62 
 63      /* 检测是否通过DHCP自动获得IP */
 64 
 65      if (mem_test (&MY_IP, 0, IP_ADRLEN) == __FALSE && !(dhcp_tout & 0x80000000))
 66 
 67      {
 68 
 69          /* 已经获得IP */
 70 
 71          dhcp_tout = 0;
 72 
 73          sprintf((char *)DHCP_Status[0],"%d.%d.%d.%d", MY_IP[0], MY_IP[1],
 74 
 75                                     MY_IP[2], MY_IP[3]);
 76 
 77          sprintf((char *)DHCP_Status[1],"DHCP Success");
 78 
 79          printf_tcpdbg("%s\r\n", DHCP_Status[0]);
 80 
 81          printf_tcpdbg("%s\r\n", DHCP_Status[1]);
 82 
 83          return;
 84 
 85      }
 86 
 87     
 88 
 89      /* 每100ms进行一次减减操作 */
 90 
 91      if (--dhcp_tout == 0)
 92 
 93      {
 94 
 95          /* 设置的8秒自动获取IP时间已经到了,禁止DHCP,准备使用固定IP */
 96 
 97          dhcp_disable ();
 98 
 99          sprintf((char *)DHCP_Status[1],"DHCP Failed" );
100 
101          /* 更新溢出时间,将固定IP的分配时间也设置为8秒 */
102 
103          dhcp_tout = 80 | 0x80000000;
104 
105          return;
106 
107      }
108 
109     
110 
111      /* 设置固定IP的8秒时间到 */
112 
113      if (dhcp_tout == 0x80000000)
114 
115      {
116 
117          dhcp_tout = 0;
118 
119          sprintf((char *)DHCP_Status[0],"%d.%d.%d.%d", MY_IP[0], MY_IP[1],
120 
121                                     MY_IP[2], MY_IP[3]);
122 
123          sprintf((char *)DHCP_Status[1],"DHCP Failed Use static IP");
124 
125          printf_tcpdbg("%s\r\n", DHCP_Status[0]);
126 
127          printf_tcpdbg("%s\r\n", DHCP_Status[1]);
128 
129      }
130 
131 }
132 
133  
134 
135 /*
136 
137 *********************************************************************************************************
138 
139 *    函 数 名: TCPnetTest
140 
141 *    功能说明: 主要实现动态IP获取和网络协议栈主函数main_TcpNet的调用。
142 
143 *    形    参: 无
144 
145 *    返 回 值: 无
146 
147 *********************************************************************************************************
148 
149 */
150 
151 void TCPnetTest(void)
152 
153 {
154 
155      uint32_t tstart, tend;
156 
157     
158 
159      /* 初始化变量 */
160 
161      dhcp_tout = DHCP_TOUT;
162 
163      tstart = os_time_get();
164 
165     
166 
167      while (1)
168 
169      {
170 
171          /* 每100ms做一次DHCP检测 */
172 
173          if(dhcp_tout != 0)
174 
175          {
176 
177               tend = os_time_get() - tstart;
178 
179               //printf_tcpdbg("%x %d\r\n", dhcp_tout, tend);
180 
181               if(tend >= 100)
182 
183               {
184 
185                    tstart = os_time_get();
186 
187                    dhcp_check();
188 
189               }
190 
191          }
192 
193         
194 
195          os_evt_wait_and(0x0001, 0xFFFF);
196 
197          while (main_TcpNet() == __TRUE);
198 
199      }
200 
201 }

26.6 网络调试助手和板子的操作步骤

因为这个例子是基于前面第19章BSD Socket服务器的例子简单修改而来,所以操作步骤直接看第19章的19.9小节即可。

26.7 实验例程说明(RTX)

26.7.1 STM32F407开发板实验

配套例子:

V5-1033_RL-TCPnet实验_DHCP应用(RTX)

实验目的:

  1. 学习RL-TCPnet的DHCP应用。

实验内容:

  1. DHCP已经使能,如果插上网线8秒内无法从路由器/交换机获得IP地址,将使用固定IP:192.168.1.100。此固定IP是在配置向导文件Net_Config.c里面设置的。
  2. 本例程创建了一个socket服务器,采用TCP通信协议,而且使能了局域网域名NetBIOS,用户只需在电脑端ping armfly就可以获得板子的IP地址,本地端口被设置为1024。
  3. 用户可以在电脑端用网络调试软件创建TCP Client连接此服务器。
  4. 网络调试助手发送命令字符1,板子回复字符1到8以及回车和换行两个字符,共10个。
  5. 网络调试助手发送命令字符2,板子回复1024个字符,前4个字符是abcd,最后4个字符是efgh,中间的1016个全部是字符0。

实验操作:

详见本章节26.6小节。

配置向导文件设置(Net_Config.c):

详见本章节26.3小节。

调试文件设置(Net_Debug.c):

详见本章节26.4小节。

RTX配置:

RTX配置向导详情如下:

Task Configuration

(1)Number of concurrent running tasks

允许创建7个任务,实际创建了如下6个任务:

AppTaskUserIF任务   :按键消息处理。

AppTaskLED任务     :LED闪烁。

AppTaskMsgPro任务 :按键检测。

AppTaskSocket任务  :socket服务器任务。

AppTaskTCPMain任务:RL-TCPnet网络主任务。

AppTaskStart任务  :启动任务,也是最高优先级任务,这里实现RL-TCPnet的时间基准更新。

(2)Number of tasks with user-provided stack

创建的6个任务都是采用自定义堆栈方式。

(3)Run in privileged mode

设置任务运行在非特权级模式。

RTX任务调试信息:

程序设计:

任务栈大小分配:

static uint64_t AppTaskUserIFStk[1024/8];   /* 任务栈 */

static uint64_t AppTaskLEDStk[1024/8];      /* 任务栈 */

static uint64_t AppTaskMsgProStk[1024/8];  /* 任务栈 */

static uint64_t AppTaskSocketStk[2048/8];   /* 任务栈 */

static uint64_t AppTaskTCPMainStk[2048/8]; /* 任务栈 */

static uint64_t AppTaskStartStk[1024/8];     /* 任务栈 */

将任务栈定义成uint64_t类型可以保证任务栈是8字节对齐的,8字节对齐的含义就是数组的首地址对8求余等于0。如果不做8字节对齐的话,部分C语言库函数、浮点运算和uint64_t类型数据运算会出问题。

系统栈大小分配:

RTX初始化:

/*

*********************************************************************************************************

*    函 数 名: main

*    功能说明: 标准c程序入口。

*    形    参: 无

*    返 回 值: 无

*********************************************************************************************************

*/

int main (void)

{   

     /* 初始化外设 */

     bsp_Init();

    

     /* 创建启动任务 */

     os_sys_init_user (AppTaskStart,              /* 任务函数 */

                       6,                         /* 任务优先级 */

                       &AppTaskStartStk,          /* 任务栈 */

                       sizeof(AppTaskStartStk));  /* 任务栈大小,单位字节数 */

     while(1);

}

硬件外设初始化

硬件外设的初始化是在 bsp.c 文件实现:

/*

*********************************************************************************************************

*    函 数 名: bsp_Init

*    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次

*    形    参:无

*    返 回 值: 无

*********************************************************************************************************

*/

void bsp_Init(void)

{

     /*

         由于ST固件库的启动文件已经执行了CPU系统时钟的初始化,所以不必再次重复配置系统时钟。

         启动文件配置了CPU主时钟频率、内部Flash访问速度和可选的外部SRAM FSMC初始化。

 

         系统时钟缺省配置为168MHz,如果需要更改,可以修改 system_stm32f4xx.c 文件

     */

     /* 优先级分组设置为4,可配置0-15级抢占式优先级,0级子优先级,即不存在子优先级。*/

     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);

 

     bsp_InitDWT();     /* 初始化DWT */

     bsp_InitUart();    /* 初始化串口 */

     bsp_InitKey();    /* 初始化按键变量(必须在 bsp_InitTimer() 之前调用) */

     bsp_InitLed();    /* 初始LED指示灯端口 */

}

RTX任务创建:

 1 /*
 2 
 3 *********************************************************************************************************
 4 
 5 *    函 数 名: AppTaskCreate
 6 
 7 *    功能说明: 创建应用任务
 8 
 9 *    形    参: 无
10 
11 *    返 回 值: 无
12 
13 *********************************************************************************************************
14 
15 */
16 
17 static void AppTaskCreate (void)
18 
19 {
20 
21      HandleTaskUserIF = os_tsk_create_user(AppTaskUserIF,             /* 任务函数 */
22 
23                                            1,                         /* 任务优先级 */
24 
25                                            &AppTaskUserIFStk,         /* 任务栈 */
26 
27                                            sizeof(AppTaskUserIFStk)); /* 任务栈大小,单位字节数 */
28 
29     
30 
31      HandleTaskLED = os_tsk_create_user(AppTaskLED,              /* 任务函数 */
32 
33                                         2,                       /* 任务优先级 */
34 
35                                         &AppTaskLEDStk,          /* 任务栈 */
36 
37                                         sizeof(AppTaskLEDStk));  /* 任务栈大小,单位字节数 */
38 
39     
40 
41      HandleTaskMsgPro = os_tsk_create_user(AppTaskMsgPro,             /* 任务函数 */
42 
43                                            3,                         /* 任务优先级 */
44 
45                                            &AppTaskMsgProStk,         /* 任务栈 */
46 
47                                            sizeof(AppTaskMsgProStk)); /* 任务栈大小,单位字节数 */
48 
49     
50 
51      HandleTaskSocket = os_tsk_create_user(AppTaskSocket,             /* 任务函数 */
52 
53                                            4,                         /* 任务优先级 */
54 
55                                            &AppTaskSocketStk,         /* 任务栈 */
56 
57                                            sizeof(AppTaskSocketStk)); /* 任务栈大小,单位字节数 */
58 
59     
60 
61     HandleTaskTCPMain = os_tsk_create_user(AppTaskTCPMain,             /* 任务函数 */
62 
63                                            5,                         /* 任务优先级 */
64 
65                                            &AppTaskTCPMainStk,         /* 任务栈 */
66 
67                                            sizeof(AppTaskTCPMainStk)); /* 任务栈大小,单位字节数 */
68 
69 }

六个RTX任务的实现:

  1 /*
  2 
  3 *********************************************************************************************************
  4 
  5 *    函 数 名: AppTaskUserIF
  6 
  7 *    功能说明: 按键消息处理     
  8 
  9 *    形    参: 无
 10 
 11 *    返 回 值: 无
 12 
 13 *   优 先 级: 1  (数值越小优先级越低,这个跟uCOS相反)
 14 
 15 *********************************************************************************************************
 16 
 17 */
 18 
 19 __task void AppTaskUserIF(void)
 20 
 21 {
 22 
 23      uint8_t ucKeyCode;
 24 
 25  
 26 
 27     while(1)
 28 
 29     {
 30 
 31          ucKeyCode = bsp_GetKey();
 32 
 33         
 34 
 35          if (ucKeyCode != KEY_NONE)
 36 
 37          {
 38 
 39               switch (ucKeyCode)
 40 
 41               {
 42 
 43                    /* K1键按下 */
 44 
 45                    case KEY_DOWN_K1:
 46 
 47                        printf("K1键按下\r\n");        
 48 
 49                        break;  
 50 
 51  
 52 
 53                    /* K2键按下 */
 54 
 55                    case KEY_DOWN_K2:
 56 
 57                        printf("K2键按下\r\n");
 58 
 59                        break;
 60 
 61                   
 62 
 63                    /* K3键按下 */
 64 
 65                    case KEY_DOWN_K3:
 66 
 67                        printf("K3键按下\r\n");
 68 
 69                        break;
 70 
 71  
 72 
 73                    /* 其他的键值不处理 */
 74 
 75                    default:                    
 76 
 77                        break;
 78 
 79               }
 80 
 81          }
 82 
 83         
 84 
 85          os_dly_wait(20);
 86 
 87      }
 88 
 89 }
 90 
 91  
 92 
 93 /*
 94 
 95 *********************************************************************************************************
 96 
 97 *    函 数 名: AppTaskLED
 98 
 99 *    功能说明: LED闪烁。
100 
101 *    形    参: 无
102 
103 *    返 回 值: 无
104 
105 *   优 先 级: 2 
106 
107 *********************************************************************************************************
108 
109 */
110 
111 __task void AppTaskLED(void)
112 
113 {
114 
115      const uint16_t usFrequency = 500; /* 延迟周期 */
116 
117     
118 
119      /* 设置延迟周期 */
120 
121      os_itv_set(usFrequency);
122 
123     
124 
125     while(1)
126 
127     {
128 
129          bsp_LedToggle(2);
130 
131  
132 
133          /* os_itv_wait是绝对延迟,os_dly_wait是相对延迟。*/
134 
135          os_itv_wait();
136 
137     }
138 
139 }
140 
141  
142 
143 /*
144 
145 *********************************************************************************************************
146 
147 *    函 数 名: AppTaskMsgPro
148 
149 *    功能说明: 按键检测
150 
151 *    形    参: 无
152 
153 *    返 回 值: 无
154 
155 *   优 先 级: 3 
156 
157 *********************************************************************************************************
158 
159 */
160 
161 __task void AppTaskMsgPro(void)
162 
163 {
164 
165     while(1)
166 
167     {
168 
169          bsp_KeyScan();
170 
171          os_dly_wait(10);
172 
173     }
174 
175 }
176 
177  
178 
179 /*
180 
181 *********************************************************************************************************
182 
183 *    函 数 名: AppTaskSocket
184 
185 *    功能说明: RL-TCPnet测试任务
186 
187 *    形    参: 无
188 
189 *    返 回 值: 无
190 
191 *   优 先 级: 4 
192 
193 *********************************************************************************************************
194 
195 */
196 
197 __task void AppTaskSocket(void)
198 
199 {
200 
201      while (1)
202 
203      {
204 
205          SocketTest();
206 
207      }
208 
209 }
210 
211  
212 
213 /*
214 
215 *********************************************************************************************************
216 
217 *    函 数 名: AppTaskTCPMain
218 
219 *    功能说明: RL-TCPnet网络主任务
220 
221 *    形    参: 无
222 
223 *    返 回 值: 无
224 
225 *   优 先 级: 5 
226 
227 *********************************************************************************************************
228 
229 */
230 
231 __task void AppTaskTCPMain(void)
232 
233 {
234 
235      while (1)
236 
237      {
238 
239          TCPnetTest();
240 
241      }
242 
243 }
244 
245  
246 
247 /*
248 
249 *********************************************************************************************************
250 
251 *    函 数 名: AppTaskStart
252 
253 *    功能说明: 启动任务,也是最高优先级任务,这里实现RL-TCPnet的时间基准更新。
254 
255 *    形    参: 无
256 
257 *    返 回 值: 无
258 
259 *   优 先 级: 6 
260 
261 *********************************************************************************************************
262 
263 */
264 
265 __task void AppTaskStart(void)
266 
267 {
268 
269      /* 初始化RL-TCPnet */
270 
271      init_TcpNet ();
272 
273     
274 
275      /* 创建任务 */
276 
277      AppTaskCreate();
278 
279     
280 
281      os_itv_set (100);
282 
283     
284 
285     while(1)
286 
287     {
288 
289          os_itv_wait ();
290 
291         
292 
293          /* RL-TCPnet时间基准更新函数 */
294 
295          timer_tick ();
296 
297     }
298 
299 }

RL-TCPnet网络主任务

这里专门创建了一个app_tcpnet_lib.c文件用于RL-TCPnet的网络主任务,实现动态IP获取和网络协议栈主函数main_TcpNet的调用。

  1 #include "includes.h"
  2 
  3  
  4 
  5  
  6 
  7  
  8 
  9  
 10 
 11 /*
 12 
 13 *********************************************************************************************************
 14 
 15 *                                      用于本文件的调试
 16 
 17 *********************************************************************************************************
 18 
 19 */
 20 
 21 #if 1
 22 
 23      #define printf_tcpdbg printf
 24 
 25 #else
 26 
 27      #define printf_tcpdbg(...)
 28 
 29 #endif
 30 
 31  
 32 
 33  
 34 
 35 /*
 36 
 37 **********************************************************************************************************
 38 
 39                                                    外部调用
 40 
 41 **********************************************************************************************************
 42 
 43 */
 44 
 45 #define DHCP_TOUT   80                 /* DHCP动态IP获取的溢出时间设置为8秒 */
 46 
 47 #define MY_IP localm[NETIF_ETH].IpAdr
 48 
 49 extern LOCALM localm[];             
 50 
 51  
 52 
 53  
 54 
 55 /*
 56 
 57 **********************************************************************************************************
 58 
 59                                                    变量
 60 
 61 **********************************************************************************************************
 62 
 63 */
 64 
 65 uint32_t dhcp_tout;
 66 
 67 uint8_t DHCP_Status[2][40] = {"IP: 192.168.X.X",              
 68 
 69                               "Waiting for DHCP"};
 70 
 71  
 72 
 73  
 74 
 75 /*
 76 
 77 *********************************************************************************************************
 78 
 79 *    函 数 名: main
 80 
 81 *    功能说明: 标准c程序入口。
 82 
 83 *    形    参: 无
 84 
 85 *    返 回 值: 无
 86 
 87 *********************************************************************************************************
 88 
 89 */
 90 
 91 static void dhcp_check(void)
 92 
 93 {
 94 
 95  
 96 
 97      /* 检测是否通过DHCP自动获得IP */
 98 
 99      if (mem_test (&MY_IP, 0, IP_ADRLEN) == __FALSE && !(dhcp_tout & 0x80000000))
100 
101      {
102 
103           /* 已经获得IP */
104 
105          dhcp_tout = 0;
106 
107          sprintf((char *)DHCP_Status[0],"%d.%d.%d.%d", MY_IP[0], MY_IP[1],
108 
109                                     MY_IP[2], MY_IP[3]);
110 
111          sprintf((char *)DHCP_Status[1],"DHCP Success");
112 
113          printf_tcpdbg("%s\r\n", DHCP_Status[0]);
114 
115          printf_tcpdbg("%s\r\n", DHCP_Status[1]);
116 
117          return;
118 
119      }
120 
121     
122 
123      /* 每100ms进行一次减减操作 */
124 
125      if (--dhcp_tout == 0)
126 
127      {
128 
129           /* 设置的8秒自动获取IP时间已经到了,禁止DHCP,准备使用固定IP */
130 
131          dhcp_disable ();
132 
133          sprintf((char *)DHCP_Status[1],"DHCP Failed" );
134 
135           /* 更新溢出时间,将固定IP的分配时间也设置为8秒 */
136 
137          dhcp_tout = 80 | 0x80000000;
138 
139          return;
140 
141      }
142 
143     
144 
145      /* 设置固定IP的8秒时间到 */
146 
147      if (dhcp_tout == 0x80000000)
148 
149      {
150 
151          dhcp_tout = 0;
152 
153          sprintf((char *)DHCP_Status[0],"%d.%d.%d.%d", MY_IP[0], MY_IP[1],
154 
155                                     MY_IP[2], MY_IP[3]);
156 
157          sprintf((char *)DHCP_Status[1],"DHCP Failed Use static IP");
158 
159          printf_tcpdbg("%s\r\n", DHCP_Status[0]);
160 
161          printf_tcpdbg("%s\r\n", DHCP_Status[1]);
162 
163      }
164 
165 }
166 
167  
168 
169 /*
170 
171 *********************************************************************************************************
172 
173 *    函 数 名: TCPnetTest
174 
175 *    功能说明: 主要实现动态IP获取和网络协议栈主函数main_TcpNet的调用。
176 
177 *    形    参: 无
178 
179 *    返 回 值: 无
180 
181 *********************************************************************************************************
182 
183 */
184 
185 void TCPnetTest(void)
186 
187 {
188 
189      uint32_t tstart, tend;
190 
191     
192 
193      /* 初始化变量 */
194 
195      dhcp_tout = DHCP_TOUT;
196 
197      tstart = os_time_get();
198 
199     
200 
201      while (1)
202 
203      {
204 
205           /* 每100ms做一次DHCP检测 */
206 
207          if(dhcp_tout != 0)
208 
209          {
210 
211               tend = os_time_get() - tstart;
212 
213               //printf_tcpdbg("%x %d\r\n", dhcp_tout, tend);
214 
215               if(tend >= 100)
216 
217               {
218 
219                    tstart = os_time_get();
220 
221                    dhcp_check();
222 
223               }
224 
225          }
226 
227         
228 
229          os_evt_wait_and(0x0001, 0xFFFF);
230 
231          while (main_TcpNet() == __TRUE);
232 
233      }
234 
235 }

Socket 服务器任务

这里专门创建了一个app_socket_lib.c文件用于socket服务器任务。

  1 #include "includes.h" 
  2 
  3  
  4 
  5  
  6 
  7  
  8 
  9 /*
 10 
 11 *********************************************************************************************************
 12 
 13 *                                      用于本文件的调试
 14 
 15 *********************************************************************************************************
 16 
 17 */
 18 
 19 #if 1
 20 
 21      #define printf_debug printf
 22 
 23 #else
 24 
 25      #define printf_debug(...)
 26 
 27 #endif
 28 
 29  
 30 
 31  
 32 
 33 /*
 34 
 35 *********************************************************************************************************
 36 
 37 *                              宏定义,本地端口
 38 
 39 *********************************************************************************************************
 40 
 41 */
 42 
 43 /* 这个是本地端口 */
 44 
 45 #define LocalPort_NUM    1001
 46 
 47  
 48 
 49  
 50 
 51 /*
 52 
 53 *********************************************************************************************************
 54 
 55 *                                         变量
 56 
 57 *********************************************************************************************************
 58 
 59 */
 60 
 61 /* RL-TCPnet API的返回值 */
 62 
 63 const char * ReVal_Table[]=
 64 
 65 {
 66 
 67      " 0: SCK_SUCCESS       Success                             ",
 68 
 69      "-1: SCK_ERROR         General Error                       ",
 70 
 71      "-2: SCK_EINVALID      Invalid socket descriptor           ",
 72 
 73      "-3: SCK_EINVALIDPARA  Invalid parameter                   ",
 74 
 75      "-4: SCK_EWOULDBLOCK   It would have blocked.              ",
 76 
 77      "-5: SCK_EMEMNOTAVAIL  Not enough memory in memory pool    ",
 78 
 79      "-6: SCK_ECLOSED       Connection is closed or aborted     ",
 80 
 81      "-7: SCK_ELOCKED       Socket is locked in RTX environment ",
 82 
 83      "-8: SCK_ETIMEOUT      Socket, Host Resolver timeout       ",
 84 
 85      "-9: SCK_EINPROGRESS   Host Name resolving in progress     ",
 86 
 87      "-10: SCK_ENONAME      Host Name not existing              ",
 88 
 89 };
 90 
 91  
 92 
 93 uint8_t sendbuf[1024];
 94 
 95  
 96 
 97  
 98 
 99 /*
100 
101 *********************************************************************************************************
102 
103 *    函 数 名: SocketTest
104 
105 *    功能说明: Socket应用
106 
107 *    形    参: 无
108 
109 *    返 回 值: 无
110 
111 *********************************************************************************************************
112 
113 */
114 
115 void SocketTest(void)
116 
117 { 
118 
119      char dbuf[10];
120 
121      int len;
122 
123      int sock, sd, res;
124 
125      SOCKADDR_IN addr;
126 
127      SOCKADDR_IN ReAddr;
128 
129  
130 
131     
132 
133      while (1)
134 
135      {
136 
137          /* 创建一个socket
138 
139             第1个参数AF_INET:当前仅支持这个类型的地址族。
140 
141             第2个参数SOCK_STREAM:表示数据流通信类型,即使用的TCP。
142 
143             第3个参数0 :配置为0的话,自动跟第2个参数进行协议匹配,这里就是TCP协议。
144 
145          */
146 
147          sock = socket (AF_INET, SOCK_STREAM, 0);
148 
149  
150 
151          /* 端口号设置为1001 */
152 
153          addr.sin_port        = htons(LocalPort_NUM);
154 
155         
156 
157          /* 与函数socket中的AF_INET作用一样 */
158 
159          addr.sin_family      = PF_INET;
160 
161           /*
162 
163             INADDR_ANY就是指定地址为0.0.0.0的地址,这个地址事实上表示不确定地址,或所有地址,
164 
165             任意地址。用在这里的话就表示监控端口号为ddr.sin_port的所有IP地址消息。一般主要用
166 
167             于有多个网卡或者IP地址的情况。开发板只用了DM9161的网口,就是监听这个网口的IP地址。
168 
169          */
170 
171          addr.sin_addr.s_addr = INADDR_ANY;
172 
173         
174 
175          /* 给socket绑定IP和端口号 */
176 
177          bind (sock, (SOCKADDR *)&addr, sizeof(addr));
178 
179  
180 
181          /* 设置监听,最大监听1个连接 */
182 
183          listen (sock, 1);
184 
185         
186 
187           /*
188 
189             等待soket连接请求,有的话,自动创建1个新的socket进行连接通信,没有的话,等待连接。
190 
191             注意,能够accept的个数受到listen函数的限制,而listen函数又受到Net_Config.c中宏定义
192 
193             BSD_NUMSOCKS 的限制。
194 
195          */
196 
197          len = sizeof(ReAddr);
198 
199          sd = accept (sock, (SOCKADDR *)&ReAddr, &len);
200 
201          printf_debug ("远程客户端请求连接IP: %d.%d.%d.%d\n", ReAddr.sin_addr.s_b1,
202 
203                                                              ReAddr.sin_addr.s_b2,
204 
205                                                                        ReAddr.sin_addr.s_b3,
206 
207                                                              ReAddr.sin_addr.s_b4);
208 
209          printf_debug ("远程客户端端口号: %d\n", ntohs(ReAddr.sin_port));
210 
211          
212 
213          /* 关闭监听socket,这个监听socket是调用函数socket后自动创建的 */
214 
215          closesocket (sock);
216 
217          sock = sd;
218 
219  
220 
221         
222 
223          while (1)
224 
225          {
226 
227               /*
228 
229                 socket数据接收函数,如果recv工作在阻塞模式,使用这个函数注意以下事项:
230 
231                 1. 此函数的溢出时间受到Net_Config.c中宏定义 BSD_RCVTOUT 的限制。溢出时间到会自动退出。
232 
233                 2. 这个函数接收到一次数据包就会返回,大于或者小于设置的缓冲区大小都没有关系,如果数据量
234 
235                    大于接收缓冲区大小,用户只需多次调用函数recv进行接收即可。
236 
237                 3. 实际接收到数据大小通过判断此函数的返回值即可。
238 
239               */
240 
241               res = recv (sock, dbuf, sizeof(dbuf), 0);
242 
243               if (res <= 0)
244 
245               {
246 
247                    printf_debug("退出接收函数,重新开始监听%s\r\n", ReVal_Table[abs(res)]);
248 
249                    break;
250 
251               }
252 
253               else
254 
255               {
256 
257                    printf_debug("Receive Data Length = %d\r\n", res);
258 
259                    switch(dbuf[0])
260 
261                    {
262 
263                         /* 字符命令 1 */
264 
265                        case '1':
266 
267                             sendbuf[0] = '1';
268 
269                             sendbuf[1] = '2';
270 
271                             sendbuf[2] = '3';
272 
273                             sendbuf[3] = '4';
274 
275                             sendbuf[4] = '5';
276 
277                             sendbuf[5] = '6';
278 
279                             sendbuf[6] = '7';
280 
281                             sendbuf[7] = '8';
282 
283                             sendbuf[8] = '\r';
284 
285                             sendbuf[9] = '\n';                       
286 
287                             res = send (sock, (char *)sendbuf, 10, 0);
288 
289                             if (res < 0)
290 
291                             {
292 
293                                  printf_debug("函数send发送数据失败\r\n");
294 
295                             }
296 
297                             else
298 
299                             {
300 
301                                  printf_debug("函数send发送数据成功\r\n");                                
302 
303                             }
304 
305                             break;
306 
307                       
308 
309                         /* 字符命令 2 */
310 
311                        case '2':
312 
313                             /* 将数据缓冲区清成字符0,方便网络调试助手查看数据 */
314 
315                             len = sizeof(sendbuf);
316 
317                             memset(sendbuf, 48, len);
318 
319                       
320 
321                             /* 这里仅初始化了数据包的前4个字节和最后4个字节 */
322 
323                             sendbuf[0] = 'a';
324 
325                             sendbuf[1] = 'b';
326 
327                             sendbuf[2] = 'c';
328 
329                             sendbuf[3] = 'd';
330 
331                             sendbuf[len - 4] = 'e';
332 
333                             sendbuf[len - 3] = 'f';
334 
335                             sendbuf[len - 2] = 'g';
336 
337                             sendbuf[len - 1] = 'h';                  
338 
339                             res = send (sock, (char *)sendbuf, len, 0);
340 
341                             if (res < 0)
342 
343                             {
344 
345                                  printf_debug("函数send发送数据失败%s\r\n", ReVal_Table[abs(res)]);
346 
347                             }
348 
349                             else
350 
351                             {
352 
353                                  printf_debug("函数send成功发送数据 = %d字节\r\n", res);                                
354 
355                             }
356 
357                             break;
358 
359                   
360 
361                        /* 其它数值不做处理 */
362 
363                        default:                    
364 
365                             break;
366 
367                    }
368 
369               }
370 
371  
372 
373          }
374 
375         
376 
377           /*
378 
379             溢出时间到,远程设备断开连接等,程序都会执行到这里,我们在这里关闭socket,
380 
381             程序返回到第一个大while循环的开头重新创建socket并监听。
382 
383          */
384 
385          closesocket (sock);
386 
387      }
388 
389 }

26.7.2 STM32F429开发板实验

配套例子:

V6-1033_RL-TCPnet实验_DHCP应用(RTX)

实验目的:

  1. 学习RL-TCPnet的DHCP应用。

实验内容:

  1. DHCP已经使能,如果插上网线8秒内无法从路由器/交换机获得IP地址,将使用固定IP:192.168.1.100。此固定IP是在配置向导文件Net_Config.c里面设置的。
  2. 本例程创建了一个socket服务器,采用TCP通信协议,而且使能了局域网域名NetBIOS,用户只需在电脑端ping armfly就可以获得板子的IP地址,本地端口被设置为1024。
  3. 用户可以在电脑端用网络调试软件创建TCP Client连接此服务器。
  4. 网络调试助手发送命令字符1,板子回复字符1到8以及回车和换行两个字符,共10个。
  5. 网络调试助手发送命令字符2,板子回复1024个字符,前4个字符是abcd,最后4个字符是efgh,中间的1016个全部是字符0。

实验操作:

详见本章节26.6小节。

配置向导文件设置(Net_Config.c):

详见本章节26.3小节。

调试文件设置(Net_Debug.c):

详见本章节26.4小节。

RTX配置:

RTX配置向导详情如下:

Task Configuration

(1)Number of concurrent running tasks

允许创建7个任务,实际创建了如下6个任务:

AppTaskUserIF任务   :按键消息处理。

AppTaskLED任务     :LED闪烁。

AppTaskMsgPro任务 :按键检测。

AppTaskSocket任务  :socket服务器任务

AppTaskTCPMain任务:RL-TCPnet网络主任务。

AppTaskStart任务  :启动任务,也是最高优先级任务,这里实现RL-TCPnet的时间基准更新。

(2)Number of tasks with user-provided stack

创建的6个任务都是采用自定义堆栈方式。

(3)Run in privileged mode

设置任务运行在非特权级模式。

RTX任务调试信息:

程序设计:

任务栈大小分配:

static uint64_t AppTaskUserIFStk[1024/8];   /* 任务栈 */

static uint64_t AppTaskLEDStk[1024/8];      /* 任务栈 */

static uint64_t AppTaskMsgProStk[1024/8];  /* 任务栈 */

static uint64_t AppTaskSocketStk[2048/8];   /* 任务栈 */

static uint64_t AppTaskTCPMainStk[2048/8]; /* 任务栈 */

static uint64_t AppTaskStartStk[1024/8];     /* 任务栈 */

将任务栈定义成uint64_t类型可以保证任务栈是8字节对齐的,8字节对齐的含义就是数组的首地址对8求余等于0。如果不做8字节对齐的话,部分C语言库函数、浮点运算和uint64_t类型数据运算会出问题。

系统栈大小分配:

RTX初始化:

/*

*********************************************************************************************************

*    函 数 名: main

*    功能说明: 标准c程序入口。

*    形    参: 无

*    返 回 值: 无

*********************************************************************************************************

*/

int main (void)

{   

     /* 初始化外设 */

     bsp_Init();

    

     /* 创建启动任务 */

     os_sys_init_user (AppTaskStart,              /* 任务函数 */

                       6,                         /* 任务优先级 */

                       &AppTaskStartStk,          /* 任务栈 */

                       sizeof(AppTaskStartStk));  /* 任务栈大小,单位字节数 */

     while(1);

}

硬件外设初始化

硬件外设的初始化是在 bsp.c 文件实现:

 1 /*
 2 
 3 *********************************************************************************************************
 4 
 5 *    函 数 名: bsp_Init
 6 
 7 *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
 8 
 9 *    形    参:无
10 
11 *    返 回 值: 无
12 
13 *********************************************************************************************************
14 
15 */
16 
17 void bsp_Init(void)
18 
19 {
20 
21      /*
22 
23          由于ST固件库的启动文件已经执行了CPU系统时钟的初始化,所以不必再次重复配置系统时钟。
24 
25          启动文件配置了CPU主时钟频率、内部Flash访问速度和可选的外部SRAM FSMC初始化。
26 
27  
28 
29          系统时钟缺省配置为168MHz,如果需要更改,可以修改 system_stm32f4xx.c 文件
30 
31      */
32 
33      /* 优先级分组设置为4,可配置0-15级抢占式优先级,0级子优先级,即不存在子优先级。*/
34 
35      NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
36 
37  
38 
39      SystemCoreClockUpdate();    /* 根据PLL配置更新系统时钟频率变量 SystemCoreClock */
40 
41  
42 
43      bsp_InitDWT();      /* 初始化DWT */
44 
45      bsp_InitUart();     /* 初始化串口 */
46 
47      bsp_InitKey();     /* 初始化按键变量(必须在 bsp_InitTimer() 之前调用) */
48 
49  
50 
51      bsp_InitExtIO();    /* FMC总线上扩展了32位输出IO, 操作LED等外设必须初始化 */
52 
53      bsp_InitLed();      /* 初始LED指示灯端口 */
54 
55 }

RTX任务创建:

 1 /*
 2 
 3 *********************************************************************************************************
 4 
 5 *    函 数 名: AppTaskCreate
 6 
 7 *    功能说明: 创建应用任务
 8 
 9 *    形    参: 无
10 
11 *    返 回 值: 无
12 
13 *********************************************************************************************************
14 
15 */
16 
17 static void AppTaskCreate (void)
18 
19 {
20 
21      HandleTaskUserIF = os_tsk_create_user(AppTaskUserIF,             /* 任务函数 */
22 
23                                            1,                         /* 任务优先级 */
24 
25                                            &AppTaskUserIFStk,         /* 任务栈 */
26 
27                                            sizeof(AppTaskUserIFStk)); /* 任务栈大小,单位字节数 */
28 
29     
30 
31      HandleTaskLED = os_tsk_create_user(AppTaskLED,              /* 任务函数 */
32 
33                                         2,                       /* 任务优先级 */
34 
35                                         &AppTaskLEDStk,          /* 任务栈 */
36 
37                                         sizeof(AppTaskLEDStk));  /* 任务栈大小,单位字节数 */
38 
39     
40 
41      HandleTaskMsgPro = os_tsk_create_user(AppTaskMsgPro,             /* 任务函数 */
42 
43                                            3,                         /* 任务优先级 */
44 
45                                            &AppTaskMsgProStk,         /* 任务栈 */
46 
47                                            sizeof(AppTaskMsgProStk)); /* 任务栈大小,单位字节数 */
48 
49     
50 
51      HandleTaskSocket = os_tsk_create_user(AppTaskSocket,             /* 任务函数 */
52 
53                                            4,                         /* 任务优先级 */
54 
55                                            &AppTaskSocketStk,         /* 任务栈 */
56 
57                                            sizeof(AppTaskSocketStk)); /* 任务栈大小,单位字节数 */
58 
59     
60 
61     HandleTaskTCPMain = os_tsk_create_user(AppTaskTCPMain,             /* 任务函数 */
62 
63                                            5,                         /* 任务优先级 */
64 
65                                            &AppTaskTCPMainStk,         /* 任务栈 */
66 
67                                            sizeof(AppTaskTCPMainStk)); /* 任务栈大小,单位字节数 */
68 
69 }

六个RTX任务的实现:

  1 /*
  2 
  3 *********************************************************************************************************
  4 
  5 *    函 数 名: AppTaskUserIF
  6 
  7 *    功能说明: 按键消息处理     
  8 
  9 *    形    参: 无
 10 
 11 *    返 回 值: 无
 12 
 13 *   优 先 级: 1  (数值越小优先级越低,这个跟uCOS相反)
 14 
 15 *********************************************************************************************************
 16 
 17 */
 18 
 19 __task void AppTaskUserIF(void)
 20 
 21 {
 22 
 23      uint8_t ucKeyCode;
 24 
 25  
 26 
 27     while(1)
 28 
 29     {
 30 
 31          ucKeyCode = bsp_GetKey();
 32 
 33         
 34 
 35          if (ucKeyCode != KEY_NONE)
 36 
 37          {
 38 
 39               switch (ucKeyCode)
 40 
 41               {
 42 
 43                    /* K1键按下 */
 44 
 45                    case KEY_DOWN_K1:
 46 
 47                        printf("K1键按下\r\n");        
 48 
 49                        break;  
 50 
 51  
 52 
 53                    /* K2键按下 */
 54 
 55                    case KEY_DOWN_K2:
 56 
 57                        printf("K2键按下\r\n");
 58 
 59                        break;
 60 
 61                   
 62 
 63                    /* K3键按下 */
 64 
 65                    case KEY_DOWN_K3:
 66 
 67                        printf("K3键按下\r\n");
 68 
 69                        break;
 70 
 71  
 72 
 73                    /* 其他的键值不处理 */
 74 
 75                    default:                    
 76 
 77                        break;
 78 
 79               }
 80 
 81          }
 82 
 83         
 84 
 85          os_dly_wait(20);
 86 
 87      }
 88 
 89 }
 90 
 91  
 92 
 93 /*
 94 
 95 *********************************************************************************************************
 96 
 97 *    函 数 名: AppTaskLED
 98 
 99 *    功能说明: LED闪烁。
100 
101 *    形    参: 无
102 
103 *    返 回 值: 无
104 
105 *   优 先 级: 2 
106 
107 *********************************************************************************************************
108 
109 */
110 
111 __task void AppTaskLED(void)
112 
113 {
114 
115      const uint16_t usFrequency = 500; /* 延迟周期 */
116 
117     
118 
119      /* 设置延迟周期 */
120 
121      os_itv_set(usFrequency);
122 
123     
124 
125     while(1)
126 
127     {
128 
129          bsp_LedToggle(2);
130 
131  
132 
133          /* os_itv_wait是绝对延迟,os_dly_wait是相对延迟。*/
134 
135          os_itv_wait();
136 
137     }
138 
139 }
140 
141  
142 
143 /*
144 
145 *********************************************************************************************************
146 
147 *    函 数 名: AppTaskMsgPro
148 
149 *    功能说明: 按键检测
150 
151 *    形    参: 无
152 
153 *    返 回 值: 无
154 
155 *   优 先 级: 3 
156 
157 *********************************************************************************************************
158 
159 */
160 
161 __task void AppTaskMsgPro(void)
162 
163 {
164 
165     while(1)
166 
167     {
168 
169          bsp_KeyScan();
170 
171          os_dly_wait(10);
172 
173     }
174 
175 }
176 
177  
178 
179 /*
180 
181 *********************************************************************************************************
182 
183 *    函 数 名: AppTaskSocket
184 
185 *    功能说明: RL-TCPnet测试任务
186 
187 *    形    参: 无
188 
189 *    返 回 值: 无
190 
191 *   优 先 级: 4 
192 
193 *********************************************************************************************************
194 
195 */
196 
197 __task void AppTaskSocket(void)
198 
199 {
200 
201      while (1)
202 
203      {
204 
205          SocketTest();
206 
207      }
208 
209 }
210 
211  
212 
213 /*
214 
215 *********************************************************************************************************
216 
217 *    函 数 名: AppTaskTCPMain
218 
219 *    功能说明: RL-TCPnet网络主任务
220 
221 *    形    参: 无
222 
223 *    返 回 值: 无
224 
225 *   优 先 级: 5 
226 
227 *********************************************************************************************************
228 
229 */
230 
231 __task void AppTaskTCPMain(void)
232 
233 {
234 
235      while (1)
236 
237      {
238 
239          TCPnetTest();
240 
241      }
242 
243 }
244 
245  
246 
247 /*
248 
249 *********************************************************************************************************
250 
251 *    函 数 名: AppTaskStart
252 
253 *    功能说明: 启动任务,也是最高优先级任务,这里实现RL-TCPnet的时间基准更新。
254 
255 *    形    参: 无
256 
257 *    返 回 值: 无
258 
259 *   优 先 级: 6 
260 
261 *********************************************************************************************************
262 
263 */
264 
265 __task void AppTaskStart(void)
266 
267 {
268 
269      /* 初始化RL-TCPnet */
270 
271      init_TcpNet ();
272 
273     
274 
275      /* 创建任务 */
276 
277      AppTaskCreate();
278 
279     
280 
281      os_itv_set (100);
282 
283     
284 
285     while(1)
286 
287     {
288 
289          os_itv_wait ();
290 
291         
292 
293          /* RL-TCPnet时间基准更新函数 */
294 
295          timer_tick ();
296 
297     }
298 
299 }

RL-TCPnet网络主任务

这里专门创建了一个app_tcpnet_lib.c文件用于RL-TCPnet的网络主任务,实现动态IP获取和网络协议栈主函数main_TcpNet的调用。

  1 #include "includes.h"
  2 
  3  
  4 
  5  
  6 
  7  
  8 
  9  
 10 
 11 /*
 12 
 13 *********************************************************************************************************
 14 
 15 *                                      用于本文件的调试
 16 
 17 *********************************************************************************************************
 18 
 19 */
 20 
 21 #if 1
 22 
 23      #define printf_tcpdbg printf
 24 
 25 #else
 26 
 27      #define printf_tcpdbg(...)
 28 
 29 #endif
 30 
 31  
 32 
 33  
 34 
 35 /*
 36 
 37 **********************************************************************************************************
 38 
 39                                                    外部调用
 40 
 41 **********************************************************************************************************
 42 
 43 */
 44 
 45 #define DHCP_TOUT   80                 /* DHCP动态IP获取的溢出时间设置为8秒 */
 46 
 47 #define MY_IP localm[NETIF_ETH].IpAdr
 48 
 49 extern LOCALM localm[];             
 50 
 51  
 52 
 53  
 54 
 55 /*
 56 
 57 **********************************************************************************************************
 58 
 59                                                    变量
 60 
 61 **********************************************************************************************************
 62 
 63 */
 64 
 65 uint32_t dhcp_tout;
 66 
 67 uint8_t DHCP_Status[2][40] = {"IP: 192.168.X.X",              
 68 
 69                               "Waiting for DHCP"};
 70 
 71  
 72 
 73  
 74 
 75 /*
 76 
 77 *********************************************************************************************************
 78 
 79 *    函 数 名: main
 80 
 81 *    功能说明: 标准c程序入口。
 82 
 83 *    形    参: 无
 84 
 85 *    返 回 值: 无
 86 
 87 *********************************************************************************************************
 88 
 89 */
 90 
 91 static void dhcp_check(void)
 92 
 93 {
 94 
 95  
 96 
 97      /* 检测是否通过DHCP自动获得IP */
 98 
 99      if (mem_test (&MY_IP, 0, IP_ADRLEN) == __FALSE && !(dhcp_tout & 0x80000000))
100 
101      {
102 
103           /* 已经获得IP */
104 
105          dhcp_tout = 0;
106 
107          sprintf((char *)DHCP_Status[0],"%d.%d.%d.%d", MY_IP[0], MY_IP[1],
108 
109                                     MY_IP[2], MY_IP[3]);
110 
111          sprintf((char *)DHCP_Status[1],"DHCP Success");
112 
113          printf_tcpdbg("%s\r\n", DHCP_Status[0]);
114 
115          printf_tcpdbg("%s\r\n", DHCP_Status[1]);
116 
117          return;
118 
119      }
120 
121     
122 
123      /* 每100ms进行一次减减操作 */
124 
125      if (--dhcp_tout == 0)
126 
127      {
128 
129           /* 设置的8秒自动获取IP时间已经到了,禁止DHCP,准备使用固定IP */
130 
131          dhcp_disable ();
132 
133          sprintf((char *)DHCP_Status[1],"DHCP Failed" );
134 
135           /* 更新溢出时间,将固定IP的分配时间也设置为8秒 */
136 
137          dhcp_tout = 80 | 0x80000000;
138 
139          return;
140 
141      }
142 
143     
144 
145      /* 设置固定IP的8秒时间到 */
146 
147      if (dhcp_tout == 0x80000000)
148 
149      {
150 
151          dhcp_tout = 0;
152 
153          sprintf((char *)DHCP_Status[0],"%d.%d.%d.%d", MY_IP[0], MY_IP[1],
154 
155                                     MY_IP[2], MY_IP[3]);
156 
157          sprintf((char *)DHCP_Status[1],"DHCP Failed Use static IP");
158 
159          printf_tcpdbg("%s\r\n", DHCP_Status[0]);
160 
161          printf_tcpdbg("%s\r\n", DHCP_Status[1]);
162 
163      }
164 
165 }
166 
167  
168 
169 /*
170 
171 *********************************************************************************************************
172 
173 *    函 数 名: TCPnetTest
174 
175 *    功能说明: 主要实现动态IP获取和网络协议栈主函数main_TcpNet的调用。
176 
177 *    形    参: 无
178 
179 *    返 回 值: 无
180 
181 *********************************************************************************************************
182 
183 */
184 
185 void TCPnetTest(void)
186 
187 {
188 
189      uint32_t tstart, tend;
190 
191     
192 
193      /* 初始化变量 */
194 
195      dhcp_tout = DHCP_TOUT;
196 
197      tstart = os_time_get();
198 
199     
200 
201      while (1)
202 
203      {
204 
205           /* 每100ms做一次DHCP检测 */
206 
207          if(dhcp_tout != 0)
208 
209          {
210 
211               tend = os_time_get() - tstart;
212 
213               //printf_tcpdbg("%x %d\r\n", dhcp_tout, tend);
214 
215               if(tend >= 100)
216 
217               {
218 
219                    tstart = os_time_get();
220 
221                    dhcp_check();
222 
223               }
224 
225          }
226 
227         
228 
229          os_evt_wait_and(0x0001, 0xFFFF);
230 
231          while (main_TcpNet() == __TRUE);
232 
233      }
234 
235 }

Socket 服务器任务

这里专门创建了一个app_socket_lib.c文件用于socket服务器任务。

  1 #include "includes.h" 
  2 
  3  
  4 
  5  
  6 
  7  
  8 
  9 /*
 10 
 11 *********************************************************************************************************
 12 
 13 *                                      用于本文件的调试
 14 
 15 *********************************************************************************************************
 16 
 17 */
 18 
 19 #if 1
 20 
 21      #define printf_debug printf
 22 
 23 #else
 24 
 25      #define printf_debug(...)
 26 
 27 #endif
 28 
 29  
 30 
 31  
 32 
 33 /*
 34 
 35 *********************************************************************************************************
 36 
 37 *                              宏定义,本地端口
 38 
 39 *********************************************************************************************************
 40 
 41 */
 42 
 43 /* 这个是本地端口 */
 44 
 45 #define LocalPort_NUM    1001
 46 
 47  
 48 
 49  
 50 
 51 /*
 52 
 53 *********************************************************************************************************
 54 
 55 *                                         变量
 56 
 57 *********************************************************************************************************
 58 
 59 */
 60 
 61 /* RL-TCPnet API的返回值 */
 62 
 63 const char * ReVal_Table[]=
 64 
 65 {
 66 
 67      " 0: SCK_SUCCESS       Success                             ",
 68 
 69      "-1: SCK_ERROR         General Error                       ",
 70 
 71      "-2: SCK_EINVALID      Invalid socket descriptor           ",
 72 
 73      "-3: SCK_EINVALIDPARA  Invalid parameter                   ",
 74 
 75      "-4: SCK_EWOULDBLOCK   It would have blocked.              ",
 76 
 77      "-5: SCK_EMEMNOTAVAIL  Not enough memory in memory pool    ",
 78 
 79      "-6: SCK_ECLOSED       Connection is closed or aborted     ",
 80 
 81      "-7: SCK_ELOCKED       Socket is locked in RTX environment ",
 82 
 83      "-8: SCK_ETIMEOUT      Socket, Host Resolver timeout       ",
 84 
 85      "-9: SCK_EINPROGRESS   Host Name resolving in progress     ",
 86 
 87      "-10: SCK_ENONAME      Host Name not existing              ",
 88 
 89 };
 90 
 91  
 92 
 93 uint8_t sendbuf[1024];
 94 
 95  
 96 
 97  
 98 
 99 /*
100 
101 *********************************************************************************************************
102 
103 *    函 数 名: SocketTest
104 
105 *    功能说明: Socket应用
106 
107 *    形    参: 无
108 
109 *    返 回 值: 无
110 
111 *********************************************************************************************************
112 
113 */
114 
115 void SocketTest(void)
116 
117 { 
118 
119      char dbuf[10];
120 
121      int len;
122 
123      int sock, sd, res;
124 
125      SOCKADDR_IN addr;
126 
127      SOCKADDR_IN ReAddr;
128 
129  
130 
131     
132 
133      while (1)
134 
135      {
136 
137          /* 创建一个socket
138 
139             第1个参数AF_INET:当前仅支持这个类型的地址族。
140 
141             第2个参数SOCK_STREAM:表示数据流通信类型,即使用的TCP。
142 
143             第3个参数0 :配置为0的话,自动跟第2个参数进行协议匹配,这里就是TCP协议。
144 
145          */
146 
147          sock = socket (AF_INET, SOCK_STREAM, 0);
148 
149  
150 
151          /* 端口号设置为1001 */
152 
153          addr.sin_port        = htons(LocalPort_NUM);
154 
155         
156 
157          /* 与函数socket中的AF_INET作用一样 */
158 
159          addr.sin_family      = PF_INET;
160 
161           /*
162 
163             INADDR_ANY就是指定地址为0.0.0.0的地址,这个地址事实上表示不确定地址,或所有地址,
164 
165             任意地址。用在这里的话就表示监控端口号为ddr.sin_port的所有IP地址消息。一般主要用
166 
167             于有多个网卡或者IP地址的情况。开发板只用了DM9161的网口,就是监听这个网口的IP地址。
168 
169          */
170 
171          addr.sin_addr.s_addr = INADDR_ANY;
172 
173         
174 
175          /* 给socket绑定IP和端口号 */
176 
177          bind (sock, (SOCKADDR *)&addr, sizeof(addr));
178 
179  
180 
181          /* 设置监听,最大监听1个连接 */
182 
183          listen (sock, 1);
184 
185         
186 
187           /*
188 
189             等待soket连接请求,有的话,自动创建1个新的socket进行连接通信,没有的话,等待连接。
190 
191             注意,能够accept的个数受到listen函数的限制,而listen函数又受到Net_Config.c中宏定义
192 
193             BSD_NUMSOCKS 的限制。
194 
195          */
196 
197          len = sizeof(ReAddr);
198 
199          sd = accept (sock, (SOCKADDR *)&ReAddr, &len);
200 
201          printf_debug ("远程客户端请求连接IP: %d.%d.%d.%d\n", ReAddr.sin_addr.s_b1,
202 
203                                                              ReAddr.sin_addr.s_b2,
204 
205                                                                        ReAddr.sin_addr.s_b3,
206 
207                                                              ReAddr.sin_addr.s_b4);
208 
209          printf_debug ("远程客户端端口号: %d\n", ntohs(ReAddr.sin_port));
210 
211         
212 
213          /* 关闭监听socket,这个监听socket是调用函数socket后自动创建的 */
214 
215          closesocket (sock);
216 
217          sock = sd;
218 
219  
220 
221         
222 
223          while (1)
224 
225          {
226 
227               /*
228 
229                 socket数据接收函数,如果recv工作在阻塞模式,使用这个函数注意以下事项:
230 
231                 1. 此函数的溢出时间受到Net_Config.c中宏定义 BSD_RCVTOUT 的限制。溢出时间到会自动退出。
232 
233                 2. 这个函数接收到一次数据包就会返回,大于或者小于设置的缓冲区大小都没有关系,如果数据量
234 
235                    大于接收缓冲区大小,用户只需多次调用函数recv进行接收即可。
236 
237                 3. 实际接收到数据大小通过判断此函数的返回值即可。
238 
239               */
240 
241               res = recv (sock, dbuf, sizeof(dbuf), 0);
242 
243               if (res <= 0)
244 
245               {
246 
247                    printf_debug("退出接收函数,重新开始监听%s\r\n", ReVal_Table[abs(res)]);
248 
249                    break;
250 
251               }
252 
253               else
254 
255               {
256 
257                    printf_debug("Receive Data Length = %d\r\n", res);
258 
259                    switch(dbuf[0])
260 
261                    {
262 
263                         /* 字符命令 1 */
264 
265                        case '1':
266 
267                             sendbuf[0] = '1';
268 
269                             sendbuf[1] = '2';
270 
271                             sendbuf[2] = '3';
272 
273                             sendbuf[3] = '4';
274 
275                             sendbuf[4] = '5';
276 
277                             sendbuf[5] = '6';
278 
279                             sendbuf[6] = '7';
280 
281                             sendbuf[7] = '8';
282 
283                             sendbuf[8] = '\r';
284 
285                             sendbuf[9] = '\n';                       
286 
287                             res = send (sock, (char *)sendbuf, 10, 0);
288 
289                             if (res < 0)
290 
291                             {
292 
293                                  printf_debug("函数send发送数据失败\r\n");
294 
295                             }
296 
297                             else
298 
299                             {
300 
301                                  printf_debug("函数send发送数据成功\r\n");                                
302 
303                             }
304 
305                             break;
306 
307                       
308 
309                         /* 字符命令 2 */
310 
311                        case '2':
312 
313                             /* 将数据缓冲区清成字符0,方便网络调试助手查看数据 */
314 
315                             len = sizeof(sendbuf);
316 
317                             memset(sendbuf, 48, len);
318 
319                       
320 
321                             /* 这里仅初始化了数据包的前4个字节和最后4个字节 */
322 
323                             sendbuf[0] = 'a';
324 
325                             sendbuf[1] = 'b';
326 
327                             sendbuf[2] = 'c';
328 
329                             sendbuf[3] = 'd';
330 
331                             sendbuf[len - 4] = 'e';
332 
333                             sendbuf[len - 3] = 'f';
334 
335                             sendbuf[len - 2] = 'g';
336 
337                             sendbuf[len - 1] = 'h';                  
338 
339                             res = send (sock, (char *)sendbuf, len, 0);
340 
341                             if (res < 0)
342 
343                             {
344 
345                                  printf_debug("函数send发送数据失败%s\r\n", ReVal_Table[abs(res)]);
346 
347                             }
348 
349                             else
350 
351                             {
352 
353                                  printf_debug("函数send成功发送数据 = %d字节\r\n", res);                                
354 
355                             }
356 
357                             break;
358 
359                   
360 
361                        /* 其它数值不做处理 */
362 
363                        default:                    
364 
365                             break;
366 
367                    }
368 
369               }
370 
371  
372 
373          }
374 
375         
376 
377           /*
378 
379             溢出时间到,远程设备断开连接等,程序都会执行到这里,我们在这里关闭socket,
380 
381             程序返回到第一个大while循环的开头重新创建socket并监听。
382 
383          */
384 
385          closesocket (sock);
386 
387      }
388 
389 }

26.8 总结

本章节就为大家讲解这么多,内容相对比较简单,希望大家熟练掌握。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏高性能服务器开发

(五)如何编写高性能日志

一、服务器端日志与客户端日志的区别 在正式讲解之前,我们先来看一个日志类的实现方法,这个日志类也是代表着大多数客户端日志的主流写法: /** *@desc:...

4158
来自专栏Android 研究

Android跨进程通信IPC之7——Binder相关结构体简介

binder_node 代表的是Binder实体对象,每一个service组件或者ServiceManager在Binder驱动程序中的描述,Binder驱动通...

1062
来自专栏依乐祝

ASP.NET Core WebApi使用Swagger生成api说明文档看这篇就够了

将 Swagger 生成器添加到 Startup.ConfigureServices 方法中的服务集合中:

2331
来自专栏猿天地

高性能NIO框架Netty入门篇

Netty介绍 Netty是由JBOSS提供的一个java开源框架。Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服...

38510
来自专栏程序员宝库

给你一份详细的 Spring Boot 知识清单

在过去两三年的Spring生态圈,最让人兴奋的莫过于Spring Boot框架。或许从命名上就能看出这个框架的设计初衷:快速的启动Spring应用。因而Spri...

1155
来自专栏Java架构

深入浅出JVM的锁优化案例锁优化

线程阻塞的时候,让等待的线程不放弃cpu执行时间,而是执行一个自旋(一般是空循环),这叫做自旋锁。

1184
来自专栏Ray学习笔记

Ajax与Controller数据交互-实例

3233
来自专栏magicsoar

html5利用websocket完成的推送功能(tomcat)

利用websocket和java完成的消息推送功能,服务器用的是tomcat7.0.42,一些东西是自己琢磨的,也不知道恰不恰当,不恰当处,还请各位见谅,并指出...

5106
来自专栏java一日一条

Spring面试问答Top 25

本人收集了一些在大家在面试时被经常问及的关于Spring的主要问题,这些问题有可能在你下次面试时就会被问到。对于本文中未提及的Spring其他模块,我会单独分享...

772
来自专栏吴伟祥

Settings -> Plugins 原

Free Mybatis Plugins    (*mapper.java-- *mapper.xml)

792

扫码关注云+社区

领取腾讯云代金券