xmodem.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. /*
  2. * Copyright 2001-2019 Georges Menie (www.menie.org)
  3. * All rights reserved.
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions are met:
  6. *
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name of the University of California, Berkeley nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
  17. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
  20. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. /* this code needs standard functions memcpy() and memset()
  28. and input/output functions _inbyte() and _outbyte().
  29. the prototypes of the input/output functions are:
  30. int _inbyte(unsigned short timeout); // msec timeout
  31. void _outbyte(int c);
  32. */
  33. #include "util.h"
  34. #include "crc16.h"
  35. #define SOH 0x01
  36. #define STX 0x02
  37. #define EOT 0x04
  38. #define ACK 0x06
  39. #define NAK 0x15
  40. #define CAN 0x18
  41. #define CTRLZ 0x1A
  42. #define DLY_1S 1000
  43. #define MAXRETRANS 25
  44. static int check(int crc, const unsigned char *buf, int sz)
  45. {
  46. if (crc) {
  47. unsigned short crc = crc16_ccitt(buf, sz);
  48. unsigned short tcrc = (buf[sz]<<8)+buf[sz+1];
  49. if (crc == tcrc)
  50. return 1;
  51. }
  52. else {
  53. int i;
  54. unsigned char cks = 0;
  55. for (i = 0; i < sz; ++i) {
  56. cks += buf[i];
  57. }
  58. if (cks == buf[sz])
  59. return 1;
  60. }
  61. return 0;
  62. }
  63. static void flushinput(void)
  64. {
  65. while (_inbyte(((DLY_1S)*3)>>1) >= 0)
  66. ;
  67. }
  68. int xmodemReceive(unsigned char *dest, int destsz)
  69. {
  70. unsigned char xbuff[1030]; /* 1024 for XModem 1k + 3 head chars + 2 crc + nul */
  71. unsigned char *p;
  72. int bufsz, crc = 0;
  73. unsigned char trychar = 'C';
  74. unsigned char packetno = 1;
  75. int i, c, len = 0;
  76. int retry, retrans = MAXRETRANS;
  77. for(;;) {
  78. for( retry = 0; retry < 16; ++retry) {
  79. if (trychar) _outbyte(trychar);
  80. if ((c = _inbyte((DLY_1S)<<1)) >= 0) {
  81. switch (c) {
  82. case SOH:
  83. bufsz = 128;
  84. goto start_recv;
  85. case STX:
  86. bufsz = 1024;
  87. goto start_recv;
  88. case EOT:
  89. flushinput();
  90. _outbyte(ACK);
  91. return len; /* normal end */
  92. case CAN:
  93. if ((c = _inbyte(DLY_1S)) == CAN) {
  94. flushinput();
  95. _outbyte(ACK);
  96. return -1; /* canceled by remote */
  97. }
  98. break;
  99. default:
  100. break;
  101. }
  102. }
  103. }
  104. if (trychar == 'C') { trychar = NAK; continue; }
  105. flushinput();
  106. _outbyte(CAN);
  107. _outbyte(CAN);
  108. _outbyte(CAN);
  109. return -2; /* sync error */
  110. start_recv:
  111. if (trychar == 'C') crc = 1;
  112. trychar = 0;
  113. p = xbuff;
  114. *p++ = c;
  115. for (i = 0; i < (bufsz+(crc?1:0)+3); ++i) {
  116. if ((c = _inbyte(DLY_1S)) < 0) goto reject;
  117. *p++ = c;
  118. }
  119. if (xbuff[1] == (unsigned char)(~xbuff[2]) &&
  120. (xbuff[1] == packetno || xbuff[1] == (unsigned char)packetno-1) &&
  121. check(crc, &xbuff[3], bufsz)) {
  122. if (xbuff[1] == packetno) {
  123. // register int count = destsz - len;
  124. // if (count > bufsz) count = bufsz;
  125. if (bufsz > 0) {
  126. sys_memcpy (&dest[len], &xbuff[3], bufsz);
  127. len += bufsz;
  128. }
  129. ++packetno;
  130. retrans = MAXRETRANS+1;
  131. }
  132. if (--retrans <= 0) {
  133. flushinput();
  134. _outbyte(CAN);
  135. _outbyte(CAN);
  136. _outbyte(CAN);
  137. return -3; /* too many retry error */
  138. }
  139. _outbyte(ACK);
  140. continue;
  141. }
  142. reject:
  143. flushinput();
  144. _outbyte(NAK);
  145. }
  146. }
  147. int xmodemTransmit(unsigned char *src, int srcsz)
  148. {
  149. unsigned char xbuff[1030]; /* 1024 for XModem 1k + 3 head chars + 2 crc + nul */
  150. int bufsz, crc = -1;
  151. unsigned char packetno = 1;
  152. int i, c, len = 0;
  153. int retry;
  154. for(;;) {
  155. for( retry = 0; retry < 16; ++retry) {
  156. if ((c = _inbyte((DLY_1S)<<1)) >= 0) {
  157. switch (c) {
  158. case 'C':
  159. crc = 1;
  160. goto start_trans;
  161. case NAK:
  162. crc = 0;
  163. goto start_trans;
  164. case CAN:
  165. if ((c = _inbyte(DLY_1S)) == CAN) {
  166. _outbyte(ACK);
  167. flushinput();
  168. return -1; /* canceled by remote */
  169. }
  170. break;
  171. default:
  172. break;
  173. }
  174. }
  175. }
  176. _outbyte(CAN);
  177. _outbyte(CAN);
  178. _outbyte(CAN);
  179. flushinput();
  180. return -2; /* no sync */
  181. for(;;) {
  182. start_trans:
  183. xbuff[0] = SOH; bufsz = 128;
  184. xbuff[1] = packetno;
  185. xbuff[2] = ~packetno;
  186. c = srcsz - len;
  187. if (c > bufsz) c = bufsz;
  188. if (c >= 0) {
  189. sys_memset (&xbuff[3], 0, bufsz);
  190. if (c == 0) {
  191. xbuff[3] = CTRLZ;
  192. }
  193. else {
  194. sys_memcpy (&xbuff[3], &src[len], c);
  195. if (c < bufsz) xbuff[3+c] = CTRLZ;
  196. }
  197. if (crc) {
  198. unsigned short ccrc = crc16_ccitt(&xbuff[3], bufsz);
  199. xbuff[bufsz+3] = (ccrc>>8) & 0xFF;
  200. xbuff[bufsz+4] = ccrc & 0xFF;
  201. }
  202. else {
  203. unsigned char ccks = 0;
  204. for (i = 3; i < bufsz+3; ++i) {
  205. ccks += xbuff[i];
  206. }
  207. xbuff[bufsz+3] = ccks;
  208. }
  209. for (retry = 0; retry < MAXRETRANS; ++retry) {
  210. for (i = 0; i < bufsz+4+(crc?1:0); ++i) {
  211. _outbyte(xbuff[i]);
  212. }
  213. if ((c = _inbyte(DLY_1S)) >= 0 ) {
  214. switch (c) {
  215. case ACK:
  216. ++packetno;
  217. len += bufsz;
  218. goto start_trans;
  219. case CAN:
  220. if ((c = _inbyte(DLY_1S)) == CAN) {
  221. _outbyte(ACK);
  222. flushinput();
  223. return -1; /* canceled by remote */
  224. }
  225. break;
  226. case NAK:
  227. default:
  228. break;
  229. }
  230. }
  231. }
  232. _outbyte(CAN);
  233. _outbyte(CAN);
  234. _outbyte(CAN);
  235. flushinput();
  236. return -4; /* xmit error */
  237. }
  238. else {
  239. for (retry = 0; retry < 10; ++retry) {
  240. _outbyte(EOT);
  241. if ((c = _inbyte((DLY_1S)<<1)) == ACK) break;
  242. }
  243. flushinput();
  244. return (c == ACK)?len:-5;
  245. }
  246. }
  247. }
  248. }
  249. #ifdef TEST_XMODEM_RECEIVE
  250. int main(void)
  251. {
  252. int st;
  253. printf ("Send data using the xmodem protocol from your terminal emulator now...\n");
  254. /* the following should be changed for your environment:
  255. 0x30000 is the download address,
  256. 65536 is the maximum size to be written at this address
  257. */
  258. st = xmodemReceive((char *)0x30000, 65536);
  259. if (st < 0) {
  260. printf ("Xmodem receive error: status: %d\n", st);
  261. }
  262. else {
  263. printf ("Xmodem successfully received %d bytes\n", st);
  264. }
  265. return 0;
  266. }
  267. #endif
  268. #ifdef TEST_XMODEM_SEND
  269. int main(void)
  270. {
  271. int st;
  272. printf ("Prepare your terminal emulator to receive data now...\n");
  273. /* the following should be changed for your environment:
  274. 0x30000 is the download address,
  275. 12000 is the maximum size to be send from this address
  276. */
  277. st = xmodemTransmit((char *)0x30000, 12000);
  278. if (st < 0) {
  279. printf ("Xmodem transmit error: status: %d\n", st);
  280. }
  281. else {
  282. printf ("Xmodem successfully transmitted %d bytes\n", st);
  283. }
  284. return 0;
  285. }
  286. #endif