ymodem.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. #include "ymodem.h"
  2. #include "ring_buf.h"
  3. #include "../swapi/subjects/serial/serial.h"
  4. static unsigned short crc16(const unsigned char *buf, unsigned long count)
  5. {
  6. unsigned short crc = 0;
  7. while(count--) {
  8. crc = crc ^ *buf++ << 8;
  9. for(int i = 0; i < 8; i++) {
  10. if(crc & 0x8000) crc = crc << 1 ^ 0x1021;
  11. else crc = crc << 1;
  12. }
  13. }
  14. return crc;
  15. }
  16. static const char *u32_to_str(unsigned int val)
  17. {
  18. static char num_str[11]; int pos = 10; num_str[10] = 0;
  19. if(val == 0) return "0"; // If already zero then just return zero
  20. while((val != 0) && (pos > 0)) {
  21. num_str[--pos] = (val % 10) + '0';
  22. val /= 10;
  23. }
  24. return &num_str[pos];
  25. }
  26. static unsigned long str_to_u32(char *str)
  27. {
  28. const char *s = str; unsigned long acc; int c;
  29. /* Strip leading spaces if any */
  30. do {
  31. c = *s++;
  32. } while(c == ' ');
  33. for(acc = 0; (c >= '0') && (c <= '9'); c = *s++) {
  34. c -= '0'; acc *= 10; acc += c;
  35. }
  36. return acc;
  37. }
  38. typedef struct
  39. {
  40. void *h; RingBuf rx_buf;
  41. RingBufElement rx_buf_storage[2*(PACKET_1K_SIZE+PACKET_OVERHEAD)]; // 最大缓存2包数据
  42. } SYmodemUart;
  43. static SYmodemUart s_myUart;
  44. static int uart_getchar(int timeout_ms)
  45. {
  46. RingBufElement val; unsigned long stime, now;
  47. if(timeout_ms >= 0) xgettickcount(&stime);
  48. while(1) {
  49. if(RingBuf_get(&s_myUart.rx_buf, &val)) return (int)val;
  50. if(timeout_ms >= 0) {
  51. xgettickcount(&now);
  52. if((now - stime) >= (unsigned long)timeout_ms) return -1; // timeout
  53. }
  54. sw_thrd_delay(THRDWAIT_DELAY);
  55. }
  56. }
  57. static void uart_putchar(int c)
  58. {
  59. unsigned char ch = (unsigned char)c;
  60. serial_send_data(s_myUart.h, &ch, 1);
  61. }
  62. /* Returns 0 on success, 1 on corrupt packet, -1 on error (timeout): */
  63. static int receive_packet(char *data, int *length)
  64. {
  65. int i, c; unsigned int packet_size;
  66. unsigned short received_crc;
  67. *length = 0;
  68. c = uart_getchar(PACKET_TIMEOUT);
  69. if(c < 0) return -1;
  70. switch(c) {
  71. case SOH:
  72. packet_size = PACKET_SIZE;
  73. break;
  74. case STX:
  75. packet_size = PACKET_1K_SIZE;
  76. break;
  77. case EOT:
  78. return 0;
  79. case CAN:
  80. c = uart_getchar(PACKET_TIMEOUT);
  81. if(c == CAN) { *length = -1; return 0; }
  82. default:
  83. *length = -1;
  84. return 0;
  85. }
  86. *data = (char)c;
  87. for(i = 1; i < (packet_size + PACKET_OVERHEAD); ++i) {
  88. c = uart_getchar(PACKET_TIMEOUT);
  89. if(c < 0) return -1;
  90. data[i] = (char)c;
  91. }
  92. if(data[PACKET_SEQNO_INDEX] != ((data[PACKET_SEQNO_COMP_INDEX] ^ 0xff) & 0xff)) return 1;
  93. received_crc = (data[PACKET_HEADER + packet_size] << 8) | data[PACKET_HEADER + packet_size + 1];
  94. if(crc16((unsigned char*)data + PACKET_HEADER, packet_size) != received_crc) return 1;
  95. *length = packet_size;
  96. return 0;
  97. }
  98. static int comio_data_recv_proc(unsigned long wParam/*传递打开的串口句柄*/, unsigned long lParam/*保留暂未使用*/)
  99. {
  100. SYmodemUart *pComIO = &s_myUart; void *pSerial = pComIO->h;
  101. const unsigned char *pRecvBuf = serial_get_recv_buffer(pSerial); int nRecvBytes = serial_get_recv_buffer_bytes(pSerial);
  102. const char *log_prefix = serial_get_log_prefix(pSerial); RingBufElement val = pRecvBuf[nRecvBytes - 1]; // 1字节数据
  103. if(!RingBuf_put(&pComIO->rx_buf, val)) {
  104. uart_putchar(CAN); uart_putchar(CAN);
  105. sw_log_error("%s: sorry,ring buffer full, failed to put!!", log_prefix);
  106. return -1;
  107. }
  108. serial_clear_recv_buffer(pSerial);
  109. return 1;
  110. }
  111. int ymodem_recv_files(const char *dir)
  112. {
  113. unsigned char packet_data[PACKET_1K_SIZE + PACKET_OVERHEAD];
  114. int packet_length, i, file_done, session_done;
  115. unsigned int packets_received, errors, first_try, files_num;
  116. char file_name[FILE_NAME_LENGTH], file_size[FILE_SIZE_LENGTH], *file_ptr;
  117. unsigned char block[PACKET_1K_SIZE]; unsigned int file_size_val = 0; char path[MAX_PATH_CHARS];
  118. RingBuf_ctor(&s_myUart.rx_buf, s_myUart.rx_buf_storage, sizeof(s_myUart.rx_buf_storage) / sizeof(RingBufElement));
  119. s_myUart.h = serial_open(UART_DEVICE_NAME, UART_BAUD_RATE, UART_PARITY_CHECK, \
  120. comio_data_recv_proc, NULL, NULL);
  121. if(!s_myUart.h) return -1;
  122. file_name[0] = '\0'; first_try = 1; files_num = 0;
  123. for(session_done = 0, errors = 0; serial_recvThrd_isAlive(s_myUart.h); )
  124. { // receive files
  125. if(!first_try) uart_putchar(CRC);
  126. first_try = 0;
  127. for(packets_received = 0, file_done = 0; serial_recvThrd_isAlive(s_myUart.h); )
  128. { // receive packets
  129. switch(receive_packet((char *)packet_data, &packet_length))
  130. {
  131. case 0: // receive success
  132. if(errors != 0) errors = 0;
  133. switch(packet_length)
  134. {
  135. case -1: { uart_putchar(ACK); serial_close(s_myUart.h, WAITTHRD_SAFEEXIT_TIMEOUT); return -2; } // abort
  136. case 0: { uart_putchar(ACK); file_done = 1; ++files_num; break; } // end of file
  137. default: // normal data packet
  138. if((packet_data[PACKET_SEQNO_INDEX] & 0xff) != (packets_received & 0xff)) { uart_putchar(NAK); break; } // sequence number error
  139. if(packets_received == 0)
  140. {
  141. if(packet_data[PACKET_HEADER] != 0x00) // filename packet has data
  142. {
  143. for(file_ptr = (char *)packet_data + PACKET_HEADER, i = 0; *file_ptr && i < FILE_NAME_LENGTH; ) file_name[i++] = *file_ptr++;
  144. file_name[i++] = '\0'; // 接收的文件名称
  145. for(++file_ptr, i = 0; *file_ptr != ' ' && i < FILE_SIZE_LENGTH; ) file_size[i++] = *file_ptr++;
  146. file_size[i++] = '\0'; // 接收的文件大小
  147. file_size_val = str_to_u32(file_size);
  148. uart_putchar(ACK); uart_putchar(CRC);
  149. sw_log_debug("[%s] <文件: %s, 大小: %u> 开始接收...", UART_MODULE_NAME, file_name, file_size_val);
  150. snprintf(path, sizeof(path), "%s/%s", dir, file_name);
  151. if(sw_file_exists(path)) sw_file_delete(path);
  152. }
  153. else
  154. { // filename packet is empty(空包文件); end of session
  155. uart_putchar(ACK); file_done = 1; session_done = 1; break;
  156. }
  157. }
  158. else
  159. {
  160. for(i = 0; i < packet_length; i++) { block[i] = packet_data[PACKET_HEADER+i]; }
  161. uart_putchar(ACK);
  162. sw_log_debug("[%s] <文件: %s, 大小: %u> 收到第%u包数据, 数据包大小: %u字节", UART_MODULE_NAME, \
  163. file_name, file_size_val, packets_received, packet_length);
  164. if(!sw_dir_exists(dir)) sw_dir_create(dir);
  165. if(sw_file_update(path, "ab", (char *)block, packet_length) != packet_length) { uart_putchar(CAN); uart_putchar(CAN); serial_close(s_myUart.h, WAITTHRD_SAFEEXIT_TIMEOUT); return -3; }
  166. }
  167. ++packets_received; // 累加已接收包数
  168. }
  169. break;
  170. default: // receive error
  171. if(packets_received != 0) { if(++errors >= MAX_ERRORS/*many errors*/) { uart_putchar(CAN); uart_putchar(CAN); serial_close(s_myUart.h, WAITTHRD_SAFEEXIT_TIMEOUT); return -4; } }
  172. uart_putchar(CRC);
  173. }
  174. if(file_done) { if(!session_done) sw_log_info("[%s] 文件: %s 接收完成, 实际大小: %u字节", UART_MODULE_NAME, file_name, sw_file_getSize(path)); break; } // 文件接收完成
  175. }
  176. if(session_done) break; // 传输会话结束
  177. }
  178. serial_close(s_myUart.h, WAITTHRD_SAFEEXIT_TIMEOUT);
  179. return files_num;
  180. }
  181. static void send_packet(unsigned char *data, int block_no)
  182. {
  183. int count, packet_size; unsigned short crc;
  184. /* We use a short packet for block 0 - all others are 1K */
  185. if(block_no == 0) packet_size = PACKET_SIZE;
  186. else packet_size = PACKET_1K_SIZE;
  187. crc = crc16(data, packet_size);
  188. /* 128 byte packets use SOH, 1K use STX */
  189. uart_putchar((block_no == 0) ? SOH : STX);
  190. uart_putchar(block_no & 0xFF);
  191. uart_putchar(~block_no & 0xFF);
  192. for(count = 0; count < packet_size; count++) uart_putchar(data[count]);
  193. uart_putchar((crc >> 8) & 0xFF);
  194. uart_putchar(crc & 0xFF);
  195. }
  196. /* Send block 0 (the filename block). filename might be truncated to fit. */
  197. static void send_packet0(char *filename, unsigned long size)
  198. {
  199. unsigned long count = 0; unsigned char block[PACKET_SIZE];
  200. const char *num;
  201. if(filename) {
  202. while(*filename && (count < PACKET_SIZE-FILE_SIZE_LENGTH-2)) block[count++] = *filename++;
  203. block[count++] = 0;
  204. num = u32_to_str(size);
  205. while(*num) block[count++] = *num++;
  206. }
  207. while(count < PACKET_SIZE) block[count++] = 0;
  208. send_packet(block, 0);
  209. }
  210. static long send_data_packets(unsigned char *data, unsigned long size)
  211. {
  212. int blockno = 1; unsigned long send_size; int ch, retry = 0;
  213. unsigned long total_sent = 0;
  214. while(size > 0)
  215. {
  216. if(size > PACKET_1K_SIZE) send_size = PACKET_1K_SIZE;
  217. else send_size = size;
  218. send_packet(data, blockno);
  219. ch = uart_getchar(PACKET_TIMEOUT);
  220. if(ch == ACK)
  221. {
  222. blockno++; retry = 0;
  223. data += send_size;
  224. size -= send_size;
  225. total_sent += send_size; // 已发送的字节数
  226. }
  227. else if(ch == NAK || ch == -1)
  228. {
  229. retry++;
  230. if(retry >= MAX_ERRORS) return -1; // give up after MAX_ERRORS retries
  231. }
  232. else if(ch == CAN)
  233. {
  234. uart_putchar(CAN);
  235. uart_putchar(CAN);
  236. return -2;
  237. }
  238. }
  239. retry = 0; do {
  240. uart_putchar(EOT);
  241. ch = uart_getchar(PACKET_TIMEOUT);
  242. } while((ch != ACK) && (ch != -1) && (++retry < MAX_ERRORS));
  243. if(ch != ACK) return -3;
  244. // 最后发送一个空包文件, 结束文件接收
  245. ch = uart_getchar(PACKET_TIMEOUT);
  246. if(ch == CRC)
  247. {
  248. retry = 0; do {
  249. send_packet0(0, 0);
  250. ch = uart_getchar(PACKET_TIMEOUT);
  251. } while((ch != ACK) && (ch != -1) && (++retry < MAX_ERRORS));
  252. if(ch != ACK) return -4;
  253. }
  254. return (long)total_sent;
  255. }
  256. int ymodem_send_file(const char *path)
  257. {
  258. char file_name[FILE_NAME_LENGTH], *file_buf = NULL;
  259. int file_size, ch, crc_nak = 1, retry, ret = 0;
  260. if(!sw_file_exists(path)) return -1;
  261. snprintf(file_name, sizeof(file_name), "%s", xGetPathFileName(path));
  262. file_size = sw_file_getSize(path);
  263. if(file_size <= 0) return -2;
  264. file_buf = (char*)malloc(file_size);
  265. if(!file_buf) return -3;
  266. if(sw_file_load(path, "rb", file_buf, file_size) != file_size) { ret = -4; goto ret_p; }
  267. RingBuf_ctor(&s_myUart.rx_buf, s_myUart.rx_buf_storage, sizeof(s_myUart.rx_buf_storage) / sizeof(RingBufElement));
  268. s_myUart.h = serial_open(UART_DEVICE_NAME, UART_BAUD_RATE, UART_PARITY_CHECK, \
  269. comio_data_recv_proc, NULL, NULL);
  270. if(!s_myUart.h) { ret = -5; goto ret_p; }
  271. retry = 0; do { ch = uart_getchar(PACKET_TIMEOUT); } while(ch != CRC && ++retry < 30);
  272. if(ch != CRC) { uart_putchar(CAN); uart_putchar(CAN); ret = -6; goto ret_p; }
  273. retry = 0; do
  274. {
  275. send_packet0(file_name, (unsigned long)file_size);
  276. ch = uart_getchar(PACKET_TIMEOUT);
  277. if(ch == ACK)
  278. {
  279. ch = uart_getchar(PACKET_TIMEOUT);
  280. if(ch == CRC) { ret = send_data_packets((unsigned char *)file_buf, file_size); if(ret < 0) { ret += -7; } break; }
  281. }
  282. else if((ch == CRC) && (crc_nak)) { crc_nak = 0; continue; } // 接收到CRC, 重发一次0包
  283. else if((ch != NAK) || (crc_nak)) { break; } // 接收到NAK, 需要重发一次0包
  284. } while(++retry < MAX_ERRORS && serial_recvThrd_isAlive(s_myUart.h));
  285. ret_p:
  286. if(file_buf) free(file_buf);
  287. if(s_myUart.h) serial_close(s_myUart.h, WAITTHRD_SAFEEXIT_TIMEOUT); s_myUart.h = NULL;
  288. return ret;
  289. }