1 /*
2 * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "at_lowpower.h"
17
18 #ifndef CONFIG_FACTORY_TEST_MODE
19 #include "lwip/ip_addr.h"
20 #endif
21 #include "hi_at.h"
22 #include "hi_gpio.h"
23 #include "hi_io.h"
24 #include "hi_lowpower.h"
25 #include "hi_stdlib.h"
26 #include "hi_time.h"
27 #include "hi_types_base.h"
28 #include "hi_watchdog.h"
29 #include "hi_wifi_api.h"
30
31 #include "at.h"
32 #include "at_io.h"
33
34 #define MILLISECOND_PER_TICK 10
35 #define GPIO3_WAKE_UP_SOURCE 3
36 #define GPIO5_WAKE_UP_SOURCE 5
37 #define GPIO7_WAKE_UP_SOURCE 7
38 #define GPIO14_WAKE_UP_SOURCE 14
39 #define ALL_GPIO_WAKE_UP_SOURCE 0
40
41 #define IO0_GPIO_MODE 0
42 #define IO1_GPIO_MODE 0
43 #define IO2_GPIO_MODE 0
44 #define IO3_GPIO_MODE 0
45 #define IO4_GPIO_MODE 0
46 #define IO5_GPIO_MODE 0
47 #define IO6_GPIO_MODE 0
48 #define IO7_GPIO_MODE 0
49 #define IO8_GPIO_MODE 0
50 #define IO9_GPIO_MODE 0
51 #define IO10_GPIO_MODE 0
52 #define IO11_GPIO_MODE 0
53 #define IO12_GPIO_MODE 0
54 #define IO13_GPIO_MODE 4
55 #define IO14_GPIO_MODE 4
56
57 hi_u8 g_io_gpio_mode[] = {
58 IO0_GPIO_MODE,
59 IO1_GPIO_MODE,
60 IO2_GPIO_MODE,
61 IO3_GPIO_MODE,
62 IO4_GPIO_MODE,
63 IO5_GPIO_MODE,
64 IO6_GPIO_MODE,
65 IO7_GPIO_MODE,
66 IO8_GPIO_MODE,
67 IO9_GPIO_MODE,
68 IO10_GPIO_MODE,
69 IO11_GPIO_MODE,
70 IO12_GPIO_MODE,
71 IO13_GPIO_MODE,
72 IO14_GPIO_MODE,
73 };
74
ms_to_systick(hi_u32 ms,hi_bool include0)75 hi_u32 ms_to_systick(hi_u32 ms, hi_bool include0)
76 {
77 hi_u32 tick;
78
79 /* >10ms Align Down */
80 if (ms > MILLISECOND_PER_TICK) {
81 tick = ms / MILLISECOND_PER_TICK; /* convert from ms to ticks */
82 } else {
83 if ((include0 == HI_TRUE) && (ms == 0)) {
84 tick = 0;
85 } else {
86 tick = 1;
87 }
88 }
89
90 return tick;
91 }
92 #ifndef CONFIG_FACTORY_TEST_MODE
at_setup_sleep(hi_s32 argc,hi_char * argv[])93 hi_u32 at_setup_sleep(hi_s32 argc, hi_char *argv[])
94 {
95 hi_u8 sleep_mode;
96
97 if (argc != 1 || argv == HI_NULL) { /* just support sleep mode param */
98 return HI_ERR_FAILURE;
99 }
100
101 if ((at_param_null_check(argc, (const hi_char **)argv) != HI_ERR_SUCCESS) ||
102 (integer_check(argv[0]) != HI_ERR_SUCCESS)) {
103 return HI_ERR_FAILURE;
104 }
105
106 sleep_mode = (hi_u8)atoi(argv[0]);
107 if (sleep_mode > 2) { /* 0:wake up; 1:light sleep; 2:deep sleep */
108 return HI_ERR_FAILURE;
109 }
110
111 hi_lpc_set_type((hi_lpc_type)sleep_mode);
112
113 hi_at_printf("OK\r\n");
114 return HI_ERR_SUCCESS;
115 }
116
wake_gpio_callback(hi_void * arg)117 hi_void wake_gpio_callback(hi_void *arg)
118 {
119 /* Add processing code based on service scenarios. */
120 hi_unref_param(arg);
121 /* To prevent the watchdog from being triggered by frequent reporting of GPIO interrupts
122 in some abnormal scenarios,the watchdog is reset. */
123 hi_watchdog_feed();
124 hi_at_printf("+WKGPIO: GPIO INT TRIGGER!\r\n");
125 }
126
check_io_status(hi_gpio_idx io_num)127 hi_u32 check_io_status(hi_gpio_idx io_num)
128 {
129 hi_u8 io_current_func = 0;
130 hi_gpio_dir gpio_dir = HI_GPIO_DIR_IN;
131
132 hi_io_get_func((hi_io_name)io_num, &io_current_func);
133 if (io_num < HI_GPIO_IDX_13) {
134 if (io_current_func != 0) {
135 return HI_ERR_FAILURE;
136 }
137 } else {
138 if ((io_current_func != 0) && (io_current_func != IO13_GPIO_MODE)) {
139 return HI_ERR_FAILURE;
140 }
141 }
142
143 gpio_get_dir(io_num, &gpio_dir);
144 if (gpio_dir == HI_GPIO_DIR_OUT) {
145 return HI_ERR_FAILURE;
146 }
147
148 return HI_ERR_SUCCESS;
149 }
150
wake_gpio_init(hi_gpio_idx io_num)151 hi_u32 wake_gpio_init(hi_gpio_idx io_num)
152 {
153 hi_u32 ret;
154 ret = hi_io_set_func((hi_io_name)io_num, g_io_gpio_mode[io_num]);
155 if (ret != HI_ERR_SUCCESS) {
156 return ret;
157 }
158
159 ret = hi_gpio_init();
160 if ((ret != HI_ERR_SUCCESS) && (ret != HI_ERR_GPIO_REPEAT_INIT)) {
161 return ret;
162 }
163
164 ret = hi_gpio_set_dir(io_num, HI_GPIO_DIR_IN);
165 if (ret != HI_ERR_SUCCESS) {
166 hi_gpio_deinit();
167 return ret;
168 }
169
170 return HI_ERR_SUCCESS;
171 }
172
at_setup_wake_gpio(hi_s32 argc,hi_char * argv[])173 hi_u32 at_setup_wake_gpio(hi_s32 argc, hi_char *argv[])
174 {
175 hi_u32 ret;
176 hi_s32 i;
177 hi_gpio_idx io_num;
178 hi_gpio_int_type int_type;
179 hi_gpio_int_polarity int_level;
180
181 if (argc != 3 || argv == HI_NULL) { /* 3 param: io_num, int_type, int_level */
182 return HI_ERR_FAILURE;
183 }
184
185 ret = at_param_null_check(argc, (const hi_char **)argv);
186 if (ret != HI_ERR_SUCCESS) {
187 return ret;
188 }
189
190 for (i = 0; i < argc; i++) {
191 if (integer_check(argv[i]) != HI_ERR_SUCCESS) {
192 return HI_ERR_FAILURE;
193 }
194 }
195
196 io_num = (hi_gpio_idx)atoi(argv[0]);
197 if (io_num > HI_GPIO_IDX_14) {
198 return HI_ERR_FAILURE;
199 }
200
201 int_type = (hi_gpio_int_type)atoi(argv[1]);
202 if (int_type > HI_INT_TYPE_EDGE) {
203 return HI_ERR_FAILURE;
204 }
205
206 int_level = (hi_gpio_int_polarity)atoi(argv[2]); /* 2: int_level */
207 if (int_level > HI_GPIO_EDGE_RISE_LEVEL_HIGH) {
208 return HI_ERR_FAILURE;
209 }
210
211 ret = check_io_status(io_num);
212 if (ret != HI_ERR_SUCCESS) {
213 return ret;
214 }
215
216 ret = wake_gpio_init(io_num);
217 if (ret != HI_ERR_SUCCESS) {
218 return ret;
219 }
220
221 ret = hi_gpio_register_isr_function(io_num, int_type, int_level, wake_gpio_callback, HI_NULL);
222 if (ret != HI_ERR_SUCCESS) {
223 return ret;
224 }
225
226 ret = hi_lpc_config_dsleep_wakeup_io(io_num, HI_TRUE);
227 if (ret != HI_ERR_SUCCESS) {
228 return ret;
229 }
230
231 hi_at_printf("OK\r\n");
232 return HI_ERR_SUCCESS;
233 }
234
at_setup_ultra_dsleep(hi_s32 argc,hi_char * argv[])235 hi_u32 at_setup_ultra_dsleep(hi_s32 argc, hi_char *argv[])
236 {
237 hi_udsleep_src wake_gpio;
238 hi_s32 i;
239 hi_u32 ret;
240 hi_u8 wake_param;
241
242 if (argc != 1 || argv[0] == HI_NULL) {
243 return HI_ERR_FAILURE;
244 }
245
246 ret = at_param_null_check(argc, (const hi_char **)argv);
247 if (ret != HI_ERR_SUCCESS) {
248 return ret;
249 }
250
251 for (i = 0; i < argc; i++) {
252 if (integer_check(argv[i]) != HI_ERR_SUCCESS) {
253 return HI_ERR_FAILURE;
254 }
255 }
256
257 wake_param = (hi_u8)atoi(argv[0]);
258 switch (wake_param) {
259 case ALL_GPIO_WAKE_UP_SOURCE:
260 wake_gpio = HI_UDS_GPIO3 | HI_UDS_GPIO5
261 | HI_UDS_GPIO7 | HI_UDS_GPIO14;
262 break;
263 case GPIO3_WAKE_UP_SOURCE:
264 wake_gpio = HI_UDS_GPIO3;
265 break;
266 case GPIO5_WAKE_UP_SOURCE:
267 wake_gpio = HI_UDS_GPIO5;
268 break;
269 case GPIO7_WAKE_UP_SOURCE:
270 wake_gpio = HI_UDS_GPIO7;
271 break;
272 case GPIO14_WAKE_UP_SOURCE:
273 wake_gpio = HI_UDS_GPIO14;
274 break;
275 default:
276 return HI_ERR_FAILURE;
277 }
278
279 hi_at_printf("OK\r\n");
280 hi_udelay(3000); /* 3000:delay 3ms */
281 hi_lpc_enable_udsleep(wake_gpio);
282
283 return HI_ERR_SUCCESS;
284 }
285
arp_offload_parse_ipv4_check(char * ip_str,unsigned int * ip_result)286 hi_u32 arp_offload_parse_ipv4_check(char *ip_str, unsigned int *ip_result)
287 {
288 char *ip_str_cpy = ip_str;
289 const char delim = '.';
290 unsigned char count = 0;
291 char *str_value = NULL;
292 hi_u32 value;
293 char *pos = NULL;
294
295 if (strlen(ip_str) > 15) { /* 15 */
296 return HI_ERR_FAILURE;
297 }
298
299 pos = strchr(ip_str_cpy, delim);
300 while (pos != NULL && pos < (ip_str + 15)) { /* 15 */
301 *pos = '\0';
302 str_value = ip_str_cpy;
303 ip_str_cpy = pos + 1;
304 if ((strlen(str_value) < 1 || strlen(str_value) > 3) || /* 3 */
305 (integer_check(str_value) != HI_ERR_SUCCESS)) {
306 return HI_ERR_FAILURE;
307 }
308 value = (hi_u32)atoi(str_value);
309 value <<= count * 8; /* 8 */
310 count++;
311 *ip_result += value;
312 pos = strchr(ip_str_cpy, delim);
313 }
314 if (count != 3) { /* 3 */
315 return HI_ERR_FAILURE;
316 }
317
318 if ((strlen(ip_str_cpy) < 1 || strlen(ip_str_cpy) > 3) || /* 3 */
319 (integer_check(ip_str_cpy) != HI_ERR_SUCCESS)) {
320 return HI_ERR_FAILURE;
321 }
322 value = (hi_u32)atoi(ip_str_cpy);
323 value <<= 3 * 8; /* 3*8 */
324 *ip_result += value;
325
326 return HI_ERR_SUCCESS;
327 }
328
329
at_set_arpoffload(hi_s32 argc,const hi_char ** argv)330 hi_u32 at_set_arpoffload(hi_s32 argc, const hi_char **argv)
331 {
332 const char *ifname = "wlan0";
333 unsigned char enable;
334 unsigned int ip_addr = 0;
335
336 if ((argc < 1) || (argc > 2) || (argv == NULL)) { /* 1/2 */
337 return HI_ERR_FAILURE;
338 }
339
340 if ((at_param_null_check(argc, argv) == HI_ERR_FAILURE) || (integer_check(argv[0]) != HI_ERR_SUCCESS)) {
341 return HI_ERR_FAILURE;
342 }
343
344 enable = (unsigned char)atoi(argv[0]);
345 if (argc == 1) {
346 if (enable != 0) {
347 return HI_ERR_FAILURE;
348 }
349 } else {
350 if (enable != 1) {
351 return HI_ERR_FAILURE;
352 }
353
354 if (arp_offload_parse_ipv4_check((char *)argv[1], &ip_addr) != HI_ERR_SUCCESS) {
355 return HI_ERR_FAILURE;
356 }
357 }
358
359 if (hi_wifi_arp_offload_setting(ifname, enable, ip_addr) != HI_ERR_SUCCESS) {
360 return HI_ERR_FAILURE;
361 }
362
363 hi_at_printf("OK\r\n");
364 return HI_ERR_SUCCESS;
365 }
366
at_set_powersave(hi_s32 argc,const hi_char ** argv)367 hi_u32 at_set_powersave(hi_s32 argc, const hi_char **argv)
368 {
369 unsigned char ps_switch;
370 int ret;
371 unsigned int wifi_sleep_time = 0;
372
373 if ((argc < 1) || (argc > 2) || (argv == NULL)) { /* 1/2 */
374 return HI_ERR_FAILURE;
375 }
376
377 if ((at_param_null_check(argc, (const hi_char **)argv) != HI_ERR_SUCCESS) ||
378 (integer_check(argv[0]) != HI_ERR_SUCCESS)) {
379 return HI_ERR_FAILURE;
380 }
381
382 ps_switch = (unsigned char)atoi(argv[0]);
383 if (argc == 1) {
384 if ((ps_switch != 0) && (ps_switch != 1)) {
385 return HI_ERR_FAILURE;
386 }
387 } else { /* 2 parameters */
388 if (ps_switch != 1) {
389 return HI_ERR_FAILURE;
390 }
391
392 if (integer_check(argv[1]) != HI_ERR_SUCCESS) {
393 return HI_ERR_FAILURE;
394 }
395 wifi_sleep_time = (unsigned int)atoi(argv[1]);
396 if ((wifi_sleep_time < 33) || (wifi_sleep_time > 4000)) { /* 33/4000 */
397 return HI_ERR_FAILURE;
398 }
399 }
400
401 ret = (hi_u32)hi_wifi_set_pm_switch(ps_switch, wifi_sleep_time);
402 if (ret != HI_ERR_SUCCESS) {
403 return HI_ERR_FAILURE;
404 }
405
406 hi_at_printf("OK\r\n");
407 return HI_ERR_SUCCESS;
408 }
409
at_set_ndoffload(hi_s32 argc,const hi_char ** argv)410 hi_u32 at_set_ndoffload(hi_s32 argc, const hi_char **argv)
411 {
412 const char *ifname = "wlan0";
413 unsigned char enable;
414 ip6_addr_t ip6_addr = { 0 };
415
416 if ((argc < 1) || (argc > 2) || (argv == NULL)) { /* 1/2 */
417 return HI_ERR_FAILURE;
418 }
419
420 if ((at_param_null_check(argc, argv) == HI_ERR_FAILURE) || (integer_check(argv[0]) != HI_ERR_SUCCESS)) {
421 return HI_ERR_FAILURE;
422 }
423
424 enable = (unsigned char)atoi(argv[0]);
425 if (argc == 1) {
426 if (enable != 0) {
427 return HI_ERR_FAILURE;
428 }
429 } else {
430 if (enable != 1) {
431 return HI_ERR_FAILURE;
432 }
433
434 if (ip6addr_aton((char *)argv[1], &ip6_addr) != 1) {
435 return HI_ERR_FAILURE;
436 }
437 }
438
439 if (hi_wifi_nd_offload_setting(ifname, enable, (unsigned char *)&ip6_addr) != HI_ERR_SUCCESS) {
440 return HI_ERR_FAILURE;
441 }
442
443 hi_at_printf("OK\r\n");
444 return HI_ERR_SUCCESS;
445 }
446 #endif
447
448 const at_cmd_func g_at_lowpower_func_tbl[] = {
449 #ifndef CONFIG_FACTORY_TEST_MODE
450 {"+SLP", 4, HI_NULL, HI_NULL, (at_call_back_func)at_setup_sleep, HI_NULL},
451 {"+WKGPIO", 7, HI_NULL, HI_NULL, (at_call_back_func)at_setup_wake_gpio, HI_NULL},
452 {"+USLP", 5, HI_NULL, HI_NULL, (at_call_back_func)at_setup_ultra_dsleep, HI_NULL},
453 {"+ARP", 4, HI_NULL, HI_NULL, (at_call_back_func)at_set_arpoffload, HI_NULL},
454 {"+PS", 3, HI_NULL, HI_NULL, (at_call_back_func)at_set_powersave, HI_NULL},
455 {"+ND", 3, HI_NULL, HI_NULL, (at_call_back_func)at_set_ndoffload, HI_NULL},
456 #endif
457 };
458
459 #define AT_LOWPOWER_FUNC_NUM (sizeof(g_at_lowpower_func_tbl) / sizeof(g_at_lowpower_func_tbl[0]))
460
hi_at_lowpower_cmd_register(hi_void)461 hi_void hi_at_lowpower_cmd_register(hi_void)
462 {
463 hi_at_register_cmd(g_at_lowpower_func_tbl, AT_LOWPOWER_FUNC_NUM);
464 }
465
466