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