1 /*
2 * Copyright (C) 2015-2017 Alibaba Group Holding Limited
3 */
4
5 #include "amp_boot.h"
6
7 #define MOD_STR "AMP_YMODEM"
8 #define YMODEM_OK 0
9 #define YMODEM_ERR (-1)
10 #define YMODEM_FILE_TOOBIG (-2)
11
12 #define YMODEM_SOH 0x01
13 #define YMODEM_STX 0x02
14 #define YMODEM_EOT 0x04
15 #define YMODEM_ACK 0x06
16 #define YMODEM_NAK 0x15
17 #define YMODEM_CAN 0x18
18 #define YMODEM_CCHAR 'C'
19 #define SOH_DATA_LEN 128
20 #define STX_DATA_LEN 1024
21
22 #define UART_RECV_TIMEOUT 4000000
23
24 #define YMODEM_STATE_INIT 0
25 #define YMODEM_STATE_WAIT_HEAD 1
26 #define YMODEM_STATE_WAIT_DATA 2
27 #define YMODEM_STATE_WAIT_END 3
28 #define YMODEM_STATE_WAIT_NEXT 4
29
30 #define YMODEM_MAX_CHAR_NUM 64
31 #define YMODEM_ERR_NAK_NUM 5
32
33 static unsigned int ymodem_flash_addr = 0;
34 static unsigned int ymodem_flash_size = 0;
35 static unsigned int ymodem_max_write_size = 40 * 1024 * 1024;
36
37 #define uart_send_byte amp_boot_uart_send_byte
38 #define uart_recv_byte amp_boot_uart_recv_byte
39
40 typedef void (*ymodem_write_t)(unsigned char *, int);
41
42 static ymodem_write_t ymodem_write = NULL;
43
44 extern void aos_boot_delay(uint32_t ms);
45
46 typedef struct {
47 uint16_t crc;
48 } CRC16_Context;
49
UpdateCRC16(uint16_t crcIn,uint8_t byte)50 static uint16_t UpdateCRC16(uint16_t crcIn, uint8_t byte)
51 {
52 uint32_t crc = crcIn;
53 uint32_t in = byte | 0x100;
54
55 do {
56 crc <<= 1;
57 in <<= 1;
58 if (in & 0x100) {
59 ++crc;
60 }
61 if (crc & 0x10000) {
62 crc ^= 0x1021;
63 }
64 } while (!(in & 0x10000));
65 return crc & 0xffffu;
66 }
67
CRC16_Init(CRC16_Context * inContext)68 static void CRC16_Init( CRC16_Context *inContext )
69 {
70 inContext->crc = 0;
71 }
72
CRC16_Update(CRC16_Context * inContext,const void * inSrc,size_t inLen)73 static void CRC16_Update( CRC16_Context *inContext, const void *inSrc, size_t inLen )
74 {
75 const uint8_t *src = (const uint8_t *) inSrc;
76 const uint8_t *srcEnd = src + inLen;
77 while ( src < srcEnd ) {
78 inContext->crc = UpdateCRC16(inContext->crc, *src++);
79 }
80 }
81
CRC16_Final(CRC16_Context * inContext,uint16_t * outResult)82 static void CRC16_Final( CRC16_Context *inContext, uint16_t *outResult )
83 {
84 inContext->crc = UpdateCRC16(inContext->crc, 0);
85 inContext->crc = UpdateCRC16(inContext->crc, 0);
86 *outResult = inContext->crc & 0xffffu;
87 }
88
crc16_computer(void * addr,size_t len)89 static unsigned short crc16_computer(void *addr, size_t len)
90 {
91 unsigned short crc = 0;
92 CRC16_Context crc_context;
93 CRC16_Init(&crc_context);
94 CRC16_Update(&crc_context, addr, len);
95 CRC16_Final(&crc_context, &crc);
96 return crc;
97 }
98
ymodem_str2int(char * buf,unsigned int buf_len)99 unsigned int ymodem_str2int(char *buf, unsigned int buf_len)
100 {
101 int type = 10;
102 int value = 0;
103 int i = 0;
104
105 if((buf[0] == '0') && (buf[1] == 'x' || buf[1] == 'X')) {
106 type = 16;
107 buf += 2;
108 }
109 for (i = 0; i < buf_len; buf++, i++) {
110 if(*buf == 0) {
111 return value;
112 }
113 if (*buf >= '0' && *buf <= '9') {
114 value = value * type + *buf - '0';
115 } else {
116 if(10 == type) {
117 return value;
118 }
119 if (*buf >= 'A' && *buf <= 'F') {
120 value = value * 16 + *buf - 'A' + 10;
121 }
122 else if (*buf >= 'a' && *buf <= 'f') {
123 value = value * 16 + *buf - 'a' + 10;
124 } else {
125 return value;
126 }
127 }
128 }
129 return value;
130 }
131
ymodem_recv_bytes(unsigned char * buffer,unsigned int nbytes,unsigned int timeout)132 unsigned int ymodem_recv_bytes(unsigned char *buffer, unsigned int nbytes, unsigned int timeout)
133 {
134 int ret = 0;
135 unsigned char c = 0;
136 unsigned int i = 0;
137 unsigned int t = 0;
138
139 while ((i < nbytes) && (t < timeout)) {
140 ret = uart_recv_byte(&c);
141 if (1 == ret) {
142 buffer[i] = c;
143 i++;
144 }
145 t++;
146 }
147 return i;
148 }
149
ymodem_data_head_parse(unsigned char data_type)150 int ymodem_data_head_parse(unsigned char data_type)
151 {
152 int i = 0;
153 int ret = YMODEM_ERR;
154 int lp = 0;
155 unsigned int buf_len = 0;
156 unsigned char *buffer = NULL;
157 unsigned short crc = 0;
158 unsigned int value = 0;
159
160 amp_debug(MOD_STR, "ymodem_data_head_parse\n");
161 buf_len = ((YMODEM_SOH == data_type) ? SOH_DATA_LEN : STX_DATA_LEN) + 4;
162 buffer = amp_malloc(buf_len);
163 memset(buffer, 0, buf_len);
164 /* SOH HEAD */
165 value = ymodem_recv_bytes(buffer, buf_len, UART_RECV_TIMEOUT);
166 if( (buf_len != value) || (0 != buffer[0]) || (0xFF != buffer[1]) ) {
167 amp_debug(MOD_STR, "header error: %d %02x %02x\n", buf_len, buffer[0], buffer[1]);
168 goto err_exit;
169 }
170
171 amp_debug(MOD_STR, "ymodem_recv_bytes head done, buf_len:%d\n", buf_len);
172 /* check CRC */
173 crc = crc16_computer(&buffer[2], buf_len-4);
174 if (((crc >> 8) != buffer[buf_len - 2]) || ((crc & 0xFF) != buffer[buf_len - 1])) {
175 amp_debug(MOD_STR, "header crc error\n");
176 goto err_exit;
177 }
178 /* parse file name && file length */
179 for(i = 2; i < buf_len - 2; i++) {
180 if((0 == buffer[i]) && (0 == lp)) {
181 lp = i + 1;
182 continue;
183 }
184
185 if((0 == buffer[i]) && (0 != lp)) {
186 /* from buffer[lp] to buffer[i] is file length ascii */
187 value = ymodem_str2int((char *)&buffer[lp], i - lp);
188 if (0 == value) {
189 goto err_exit;
190 }
191 ymodem_flash_size = value;
192 if(value > ymodem_max_write_size) {
193 ret = YMODEM_FILE_TOOBIG;
194 goto err_exit;
195 }
196 break;
197 }
198 }
199
200 for (i = 2; i < buf_len - 4; i ++) {
201 if (buffer[i] != 0) {
202 ret = YMODEM_OK;
203 }
204 }
205 amp_debug(MOD_STR, "get file size:%d\n", ymodem_flash_size);
206
207 err_exit:
208 amp_free(buffer);
209 return ret;
210 }
211
ymodem_data_parse(unsigned char data_type)212 int ymodem_data_parse(unsigned char data_type)
213 {
214 int ret = YMODEM_ERR;
215 unsigned int buf_len = 0;
216 unsigned short crc = 0;
217 unsigned int value = 0;
218 unsigned char *buffer = NULL;
219
220 buf_len = ((YMODEM_SOH == data_type) ? SOH_DATA_LEN : STX_DATA_LEN) + 4;
221 buffer = amp_malloc(buf_len);
222 memset(buffer, 0, buf_len);
223
224 amp_debug(MOD_STR, "ymodem_data_parse\n");
225 /* SOH HEAD */
226 value = ymodem_recv_bytes(buffer, buf_len, UART_RECV_TIMEOUT);
227 if ((buf_len != value) || (0xFF != buffer[0] + buffer[1])) {
228 amp_error(MOD_STR, "ymodem_data_parse crc error:%02x %02x\n", buffer[buf_len - 2], buffer[buf_len - 1] );
229 goto err_exit;
230 }
231
232 /* check CRC */
233 crc = crc16_computer(&buffer[2], buf_len - 4);
234 if (((crc >> 8) != buffer[buf_len - 2]) || ((crc & 0xFF) != buffer[buf_len - 1])) {
235 goto err_exit;
236 }
237
238 /* write data fo flash */
239 amp_debug(MOD_STR, "write data, buf_len:%d\n", buf_len - 4);
240 if (ymodem_write != NULL) {
241 ymodem_write(&buffer[2], buf_len - 4);
242 }
243 // ymodem_write_data_to_flash(&buffer[2], *addr, buf_len - 4);
244 // *addr += buf_len - 4;
245 ret = YMODEM_OK;
246
247 err_exit :
248 amp_free(buffer);
249 return ret;
250 }
251
ymodem_recv_file(void)252 int ymodem_recv_file(void)
253 {
254 int i = 0;
255 int ret = YMODEM_OK;
256 int state = 0;
257 int end_flag = 0;
258 unsigned char c = 0;
259 unsigned int bytes = 0;
260
261 /* send C */
262 while (1) {
263 aos_boot_delay(1);
264 if(state != YMODEM_STATE_INIT) {
265 bytes = ymodem_recv_bytes(&c, 1, 50000);
266 }
267 //aos_printf("ymodem_recv_file bytes = %d, i = %d, state = %d\n", bytes, i, state);
268 //amp_debug_send_str("ymodem_recv_file \n");
269 switch (state)
270 {
271 case YMODEM_STATE_INIT: /* send 'C' */
272 if(i % 20 == 0) {
273 uart_send_byte(YMODEM_CCHAR);
274 }
275 state = YMODEM_STATE_WAIT_HEAD;
276 break;
277
278 case YMODEM_STATE_WAIT_HEAD: /* wait SOH */
279 if(1 != bytes) {
280 i ++;
281 state = YMODEM_STATE_INIT;
282 break;
283 }
284 if(( YMODEM_SOH == c ) || ( YMODEM_STX == c )) {
285 ret = ymodem_data_head_parse(c);
286 if (ret == YMODEM_OK) {
287 uart_send_byte(YMODEM_ACK);
288 aos_boot_delay(100);
289 uart_send_byte(YMODEM_CCHAR);
290 state = YMODEM_STATE_WAIT_DATA;
291 break;
292 } else {
293 /* end */
294 uart_send_byte(YMODEM_ACK);
295 aos_boot_delay(200);
296 if(end_flag == 1) {
297 ret = YMODEM_OK;
298 } else {
299 for(i = 0; i < YMODEM_ERR_NAK_NUM; i++) {
300 uart_send_byte(YMODEM_NAK);
301 }
302 }
303 return ret;
304 }
305 } else if (3 == c) { /* ctrl+c abort ymodem */
306 amp_debug(MOD_STR, "Abort\n");
307 return YMODEM_ERR;
308 }
309 break;
310
311 case YMODEM_STATE_WAIT_DATA: /* receive data */
312 if(1 == bytes) {
313 if( (YMODEM_SOH == c) || (YMODEM_STX == c) ) {
314 ret = ymodem_data_parse(c);
315 if (ret == YMODEM_OK) {
316 uart_send_byte(YMODEM_ACK);
317 }
318 } else if( YMODEM_EOT == c ) {
319 uart_send_byte(YMODEM_NAK);
320 state = YMODEM_STATE_WAIT_END;
321 }
322 }
323 break;
324
325 case YMODEM_STATE_WAIT_END: /* receive end eot */
326 if ((1 == bytes) && (YMODEM_EOT == c)) {
327 uart_send_byte(YMODEM_ACK);
328 i = 0;
329 state = YMODEM_STATE_INIT;
330 end_flag = 1;
331 }
332 break;
333
334 default:
335 state = YMODEM_STATE_INIT;
336 break;
337 }
338 }
339
340 return YMODEM_OK;
341 }
342
ymodem_upgrade(void (* func)(unsigned char *,int))343 int ymodem_upgrade(void (*func)(unsigned char *, int))
344 {
345 int i = 0;
346 int ret = 0;
347 unsigned char c = 0;
348
349 ymodem_write = func;
350
351 amp_debug(MOD_STR, "Please start ymodem ... (press ctrl+c to cancel)\n");
352
353 ret = ymodem_recv_file();
354 if (ret != YMODEM_OK) {
355 for(i = 0; i < 5000; i++ ) {
356 if(uart_recv_byte(&c)) {
357 break;
358 }
359 }
360 }
361
362 if(ret == YMODEM_OK) {
363 amp_debug(MOD_STR, "Recv App Bin OK\n");
364 } else if(ret == YMODEM_FILE_TOOBIG) {
365 amp_debug(MOD_STR, "file too big len:0x%08x !!!\n", ymodem_flash_size);
366 } else {
367 amp_debug(MOD_STR, "Ymodem recv file Err:%d !!!\n", ret);
368 }
369 return ret;
370 }
371