1 /*
2  * Copyright (C) 2015-2019 Alibaba Group Holding Limited
3  */
4 
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <stdarg.h>
9 
10 #include "amp_config.h"
11 #include "amp_utils.h"
12 #include "aos_system.h"
13 #include "amp_defines.h"
14 #include "aos_hal_uart.h"
15 #include "aos_hal_gpio.h"
16 #include "aos/kernel.h"
17 
18 #include "amp_board_config.h"
19 #include "amp_boot_recovery.h"
20 #include "app_mgr.h"
21 
22 #define MOD_STR "AMP_BOOT_RECOVERY"
23 
24 static gpio_dev_t amp_status_led;
25 static gpio_dev_t amp_rec_switch;
26 
27 /* status led mode */
28 static AMP_STATUS amp_status = AMP_STATUS_NORMAL;
29 
30 extern int download_apppack(uint8_t *buf, int32_t buf_len);
31 extern int ymodem_upgrade(void (*func)(unsigned char *, int));
32 extern int write_app_pack(const char *filename, int32_t file_size, int32_t type,
33                           int32_t offset, uint8_t *buf, int32_t buf_len,
34                           int32_t complete);
35 
ymodem_appbin_init(void)36 static void ymodem_appbin_init(void)
37 {
38     apppack_init(write_app_pack);
39 }
40 
amp_status_set(AMP_STATUS mode)41 static void amp_status_set(AMP_STATUS mode)
42 {
43     if (mode >= AMP_STATUS_END) {
44         return;
45     }
46     amp_status = mode;
47 }
48 
ymodem_appbin_finish(void)49 static void ymodem_appbin_finish(void)
50 {
51     apppack_final();
52     amp_status_set(AMP_STATUS_NORMAL);
53     amp_debug(MOD_STR, "ymodem_appbin_finish");
54 }
55 
ymodem_appbin_write(unsigned char * buf,int size)56 static void ymodem_appbin_write(unsigned char *buf, int size)
57 {
58     //hexdump("ymodem data", buf, size);
59     amp_status_set(AMP_STATUS_UPDATING);
60     download_apppack(buf, size);
61 }
62 
_amp_status_led_on(void)63 static void _amp_status_led_on(void)
64 {
65     AMP_STATUS_IO_ON ? aos_hal_gpio_output_high(&amp_status_led) : aos_hal_gpio_output_low(&amp_status_led);
66 }
67 
_amp_status_led_off(void)68 static void _amp_status_led_off(void)
69 {
70     AMP_STATUS_IO_ON ? aos_hal_gpio_output_low(&amp_status_led) : aos_hal_gpio_output_high(&amp_status_led);
71 }
72 
_amp_status_led_task(void * param)73 static void _amp_status_led_task(void *param)
74 {
75 
76     while (1) {
77         // amp_debug(MOD_STR, "status_led_mode set");
78         switch (amp_status) {
79             case AMP_STATUS_NORMAL:
80                 /* normal running */
81                 _amp_status_led_on();
82                 aos_msleep(500);
83                 _amp_status_led_off();
84                 aos_msleep(2500);
85                 break;
86             case AMP_STATUS_SERVICE_AVAILABLE:
87                 /* service available */
88                 _amp_status_led_on();
89                 aos_msleep(2500);
90                 _amp_status_led_off();
91                 aos_msleep(500);
92                 break;
93             case AMP_STATUS_RECOVERY:
94                 /* recovery mode */
95                 _amp_status_led_on();
96                 aos_msleep(100);
97                 _amp_status_led_off();
98                 aos_msleep(100);
99                 _amp_status_led_on();
100                 aos_msleep(100);
101                 _amp_status_led_off();
102                 aos_msleep(850);
103                 break;
104             case AMP_STATUS_UPDATING:
105                 /* upgrading */
106                 _amp_status_led_on();
107                 aos_msleep(50);
108                 _amp_status_led_off();
109                 aos_msleep(50);
110                 _amp_status_led_on();
111                 aos_msleep(50);
112                 _amp_status_led_off();
113                 aos_msleep(50);
114                 break;
115             case AMP_STATUS_JSERROR:
116                 /* JS Error */
117                 _amp_status_led_on();
118                 aos_msleep(1000);
119                 break;
120             case AMP_STATUS_COREDUMP:
121                 /* JS Error */
122                 _amp_status_led_on();
123                 aos_msleep(1000);
124                 break;
125             default:
126                 amp_debug(MOD_STR, "wrong status mode");
127                 break;
128         }
129     }
130     return;
131 }
132 
amp_recovery_init(void)133 int amp_recovery_init(void)
134 {
135     int delay = 0, ret = -1, status_off = 1;
136     uint32_t value = 0;
137     aos_task_t amp_stat_task;
138 
139     amp_debug(MOD_STR, "recovery entry");
140     amp_rec_switch.port   = AMP_REC_IO;
141     amp_rec_switch.config = INPUT_PULL_UP;
142     amp_status_led.port   = AMP_STATUS_IO;
143     amp_status_led.config = OUTPUT_OPEN_DRAIN_PULL_UP;
144 
145     amp_error(MOD_STR, "recovery switch io is %d led port is %d", AMP_REC_IO, AMP_STATUS_IO);
146     /* configure GPIO with the given settings */
147 
148     ret = aos_hal_gpio_init(&amp_rec_switch);
149     if (ret != 0) {
150         amp_error(MOD_STR, "recovery switch gpio init error!");
151         return 0;
152     }
153 
154     // for debounce
155     while (delay++ <= 10) {
156         aos_hal_gpio_input_get(&amp_rec_switch, &value);
157         // recovery switch
158         if (value == !AMP_REC_IO_ON) {
159             status_off = 0;
160         }
161 
162         amp_debug(MOD_STR, "gpio status: %d", value);
163         aos_msleep(10);
164         delay += 1;
165     }
166 
167     if (status_off) {
168         /* enter to recovery mode */
169         amp_debug(MOD_STR, "enter to recovery, not to start JS code");
170         ret = aos_hal_gpio_init(&amp_status_led);
171         if (ret != 0) {
172             amp_error(MOD_STR, "recovery status gpio init error!");
173             return 0;
174         }
175         aos_task_new_ext(&amp_stat_task, "amp status task", _amp_status_led_task, NULL, 1024, ADDON_TSK_PRIORRITY);
176 
177         amp_status_set(AMP_STATUS_RECOVERY);
178         aos_hal_gpio_finalize(&amp_rec_switch);
179         return -1;
180     }
181     aos_hal_gpio_finalize(&amp_rec_switch);
182     return 0;
183 }
184 
amp_recovery_entry(void)185 int amp_recovery_entry(void)
186 {
187     ymodem_appbin_init();
188     ymodem_upgrade(ymodem_appbin_write);
189     ymodem_appbin_finish();
190     amp_debug(MOD_STR, "ymodem_upgrade done");
191     while (1) {
192         aos_msleep(1000);
193     }
194 
195     return 0;
196 }
197 
amp_recovery_appbin(void)198 int amp_recovery_appbin(void)
199 {
200     ymodem_appbin_init();
201     ymodem_upgrade(ymodem_appbin_write);
202     ymodem_appbin_finish();
203     return 0;
204 }
205