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

时间:2023-03-09 17:56:01
【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 文件:

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

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

26.3  DHCP配置说明(Net_Config.c)

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

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

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

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

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

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。

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

Ethernet Network Interface

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

(1)MAC Address

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

(2)IP Address

IP地址。

(3)Subnet mask

子网掩码。

(4)Default Gateway

默认网关。

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

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服务器列表。

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

UDP Sockets

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

(1)Number of UDP Sockets

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

范围1 – 20。

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

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接收窗口大小。

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

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,可以看到下图所示的工程配置向导:

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

Print Time Stamp

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

其它所有的选项

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

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

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

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

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

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

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

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配置向导详情如下:

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

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任务调试信息:

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

程序设计:

任务栈大小分配:

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类型数据运算会出问题。

系统栈大小分配:

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

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配置向导详情如下:

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

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任务调试信息:

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

程序设计:

任务栈大小分配:

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类型数据运算会出问题。

系统栈大小分配:

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

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 总结

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