• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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