xmodem.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  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 "crc16.h"
  34. #include <sys.h>
  35. #include <uart.h>
  36. #define SOH 0x01
  37. #define STX 0x02
  38. #define EOT 0x04
  39. #define ACK 0x06
  40. #define NAK 0x15
  41. #define CAN 0x18
  42. #define CTRLZ 0x1A
  43. #define DLY_1S 1000
  44. #define MAXRETRANS 1000
  45. static int check(int crc, const unsigned char *buf, int sz)
  46. {
  47. if (crc) {
  48. unsigned short crc = crc16_ccitt(buf, sz);
  49. unsigned short tcrc = (buf[sz]<<8)+buf[sz+1];
  50. if (crc == tcrc)
  51. return 1;
  52. }
  53. else {
  54. int i;
  55. unsigned char cks = 0;
  56. for (i = 0; i < sz; ++i) {
  57. cks += buf[i];
  58. }
  59. if (cks == buf[sz])
  60. return 1;
  61. }
  62. return 0;
  63. }
  64. static void flushinput(void)
  65. {
  66. while (_inbyte(((DLY_1S)*3)>>1) >= 0)
  67. ;
  68. }
  69. int xmodemReceive(unsigned char *dest, int destsz)
  70. {
  71. unsigned char xbuff[1030]; /* 1024 for XModem 1k + 3 head chars + 2 crc + nul */
  72. unsigned char *p;
  73. int bufsz, crc = 0;
  74. unsigned char trychar = 'C';
  75. unsigned char packetno = 1;
  76. int i, c, len = 0;
  77. int retry, retrans = MAXRETRANS;
  78. for(;;) {
  79. for( retry = 0; retry < MAXRETRANS; ++retry) {
  80. if (trychar) _outbyte(trychar);
  81. if ((c = _inbyte((DLY_1S))) >= 0) {
  82. switch (c) {
  83. case SOH:
  84. bufsz = 128;
  85. goto start_recv;
  86. case STX:
  87. bufsz = 1024;
  88. goto start_recv;
  89. case EOT:
  90. flushinput();
  91. _outbyte(ACK);
  92. return len; /* normal end */
  93. case CAN:
  94. if ((c = _inbyte(DLY_1S)) == CAN) {
  95. flushinput();
  96. _outbyte(ACK);
  97. return -1; /* canceled by remote */
  98. }
  99. break;
  100. default:
  101. break;
  102. }
  103. }
  104. }
  105. if (trychar == 'C') { trychar = NAK; continue; }
  106. flushinput();
  107. _outbyte(CAN);
  108. _outbyte(CAN);
  109. _outbyte(CAN);
  110. return -2; /* sync error */
  111. start_recv:
  112. if (trychar == 'C') crc = 1;
  113. trychar = 0;
  114. p = xbuff;
  115. *p++ = c;
  116. for (i = 0; i < (bufsz+(crc?1:0)+3); ++i) {
  117. if ((c = _inbyte(DLY_1S)) < 0) goto reject;
  118. *p++ = c;
  119. }
  120. if (xbuff[1] == (unsigned char)(~xbuff[2]) &&
  121. (xbuff[1] == packetno || xbuff[1] == (unsigned char)packetno-1) &&
  122. check(crc, &xbuff[3], bufsz)) {
  123. if (xbuff[1] == packetno) {
  124. // register int count = destsz - len;
  125. // if (count > bufsz) count = bufsz;
  126. if (bufsz > 0) {
  127. sys_memcpy (&dest[len], &xbuff[3], bufsz);
  128. len += bufsz;
  129. }
  130. ++packetno;
  131. retrans = MAXRETRANS+1;
  132. }
  133. if (--retrans <= 0) {
  134. flushinput();
  135. _outbyte(CAN);
  136. _outbyte(CAN);
  137. _outbyte(CAN);
  138. return -3; /* too many retry error */
  139. }
  140. _outbyte(ACK);
  141. continue;
  142. }
  143. reject:
  144. flushinput();
  145. _outbyte(NAK);
  146. }
  147. }