ymodem.h 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. /*
  2. * COPYRIGHT (C) 2011-2022, Real-Thread Information Technology Ltd
  3. * All rights reserved
  4. *
  5. * SPDX-License-Identifier: Apache-2.0
  6. *
  7. * Change Logs:
  8. * Date Author Notes
  9. * 2013-04-14 Grissiom initial implementation
  10. * 2019-12-09 Steven Liu add YMODEM send protocol
  11. * 2022-08-04 Meco Man move error codes to rym_code to silence warnings
  12. * 2026-02-01 wdfk-prog update ymodem callbacks and error handling
  13. */
  14. #ifndef __YMODEM_H__
  15. #define __YMODEM_H__
  16. #include "rtthread.h"
  17. #include <string.h>
  18. /* The word "RYM" is stand for "Real-YModem". */
  19. enum rym_code
  20. {
  21. RYM_CODE_NONE = 0x00,
  22. RYM_CODE_SOH = 0x01,
  23. RYM_CODE_STX = 0x02,
  24. RYM_CODE_EOT = 0x04,
  25. RYM_CODE_ACK = 0x06,
  26. RYM_CODE_NAK = 0x15,
  27. RYM_CODE_CAN = 0x18,
  28. RYM_CODE_C = 0x43,
  29. /* RYM error code */
  30. RYM_ERR_TMO = 0x70, /* timeout on handshake */
  31. RYM_ERR_CODE = 0x71, /* wrong code, wrong SOH, STX etc */
  32. RYM_ERR_SEQ = 0x72, /* wrong sequence number */
  33. RYM_ERR_CRC = 0x73, /* wrong CRC checksum */
  34. RYM_ERR_DSZ = 0x74, /* not enough data received */
  35. RYM_ERR_CAN = 0x75, /* the transmission is aborted by user */
  36. RYM_ERR_ACK = 0x76, /* wrong answer, wrong ACK or C */
  37. RYM_ERR_FILE = 0x77, /* transmit file invalid */
  38. };
  39. /* how many ticks wait for chars between packet. */
  40. #ifndef RYM_WAIT_CHR_TICK
  41. #define RYM_WAIT_CHR_TICK (RT_TICK_PER_SECOND * 3)
  42. #endif
  43. /* how many ticks wait for between packet. */
  44. #ifndef RYM_WAIT_PKG_TICK
  45. #define RYM_WAIT_PKG_TICK (RT_TICK_PER_SECOND * 3)
  46. #endif
  47. /* how many ticks between two handshake code. */
  48. #ifndef RYM_CHD_INTV_TICK
  49. #define RYM_CHD_INTV_TICK (RT_TICK_PER_SECOND * 3)
  50. #endif
  51. /* how many CAN be sent when user active end the session. */
  52. #ifndef RYM_END_SESSION_SEND_CAN_NUM
  53. #define RYM_END_SESSION_SEND_CAN_NUM 0x07
  54. #endif
  55. /* how many retries were made when the error occurred */
  56. #ifndef RYM_MAX_ERRORS
  57. #define RYM_MAX_ERRORS ((rt_size_t)5)
  58. #endif
  59. enum rym_stage
  60. {
  61. RYM_STAGE_NONE = 0,
  62. /* set when C is send */
  63. RYM_STAGE_ESTABLISHING,
  64. /* set when we've got the packet 0 and sent ACK and second C */
  65. RYM_STAGE_ESTABLISHED,
  66. /* set when the sender respond to our second C and recviever got a real
  67. * data packet. */
  68. RYM_STAGE_TRANSMITTING,
  69. /* set when the sender send a EOT */
  70. RYM_STAGE_FINISHING,
  71. /* set when transmission is really finished, i.e., after the NAK, C, final
  72. * NULL packet stuff. */
  73. RYM_STAGE_FINISHED,
  74. };
  75. struct rym_ctx;
  76. /**
  77. * @brief YMODEM callback signature.
  78. *
  79. * @param ctx The context of the current session.
  80. *
  81. * @note When receiving files, the buf will be the data received from ymodem protocol
  82. * and the len is the data size.
  83. *
  84. * When sending files, the len is the buf size in RYM. The callback need to
  85. * fill the buf with data to send. Returning RYM_CODE_EOT will terminate the
  86. * transfer and the buf will be discarded. Any other return values will cause
  87. * the transfer continue.
  88. *
  89. * @note Keep this typedef unchanged for compatibility with external packages.
  90. * To allow error-aware handling without breaking ABI, add state fields
  91. * (e.g. ctx->last_err) in rym_ctx for callbacks to inspect.
  92. */
  93. typedef enum rym_code(*rym_callback)(struct rym_ctx *ctx, rt_uint8_t *buf, rt_size_t len);
  94. /* Currently RYM only support one transfer session(ctx) for simplicity.
  95. *
  96. * In case we could support multiple sessions in The future, the first argument
  97. * of APIs are (struct rym_ctx*).
  98. */
  99. struct rym_ctx
  100. {
  101. /**
  102. * @brief Data callback for each received/sent block.
  103. */
  104. rym_callback on_data;
  105. /**
  106. * @brief Begin callback for the initial header block.
  107. */
  108. rym_callback on_begin;
  109. /**
  110. * @brief End callback for session finalization.
  111. * Callers should check ctx->last_err to distinguish success vs failure.
  112. */
  113. rym_callback on_end;
  114. /* When error happened, user need to check this to get when the error has
  115. * happened. */
  116. enum rym_stage stage;
  117. /* user could get the error content through this */
  118. rt_uint8_t *buf;
  119. /**
  120. * @brief Callback lifecycle state: set when on_begin succeeds.
  121. */
  122. rt_uint8_t begin_called;
  123. /**
  124. * @brief Callback lifecycle state: set when on_end is invoked.
  125. */
  126. rt_uint8_t end_called;
  127. /**
  128. * @brief Last transfer error seen by the core state machine.
  129. * on_end can inspect this to distinguish success vs failure.
  130. */
  131. rt_err_t last_err;
  132. struct rt_semaphore sem;
  133. rt_device_t dev;
  134. };
  135. /* recv a file on device dev with ymodem session ctx.
  136. *
  137. * If an error happens, you can get where it is failed from ctx->stage.
  138. *
  139. * @param on_begin The callback will be invoked when the first packet arrived.
  140. * This packet often contain file names and the size of the file, if the sender
  141. * support it. So if you want to save the data to a file, you may need to
  142. * create the file on need. It is the on_begin's responsibility to parse the
  143. * data content. The on_begin can be NULL, in which case the transmission will
  144. * continue without any side-effects.
  145. *
  146. * @param on_data The callback will be invoked on the packets received. The
  147. * callback should save the data to the destination. The return value will be
  148. * sent to the sender and in turn, only RYM_{ACK,CAN} is valid. When on_data is
  149. * NULL, RYM will barely send ACK on every packet and have no side-effects.
  150. *
  151. * @param on_end The callback will be invoked when one transmission is
  152. * finished. The data should be 128 bytes of NULL. You can do some cleaning job
  153. * in this callback such as closing the file. The return value of this callback
  154. * is ignored. As above, this parameter can be NULL if you don't need such
  155. * function.
  156. *
  157. * @param handshake_timeout the timeout when hand shaking. The unit is in
  158. * second.
  159. */
  160. rt_err_t rym_recv_on_device(struct rym_ctx *ctx, rt_device_t dev, rt_uint16_t oflag,
  161. rym_callback on_begin, rym_callback on_data, rym_callback on_end,
  162. int handshake_timeout);
  163. /* send a file on device dev with ymodem session ctx.
  164. *
  165. * If an error happens, you can get where it is failed from ctx->stage.
  166. *
  167. * @param on_begin The callback will be invoked when the first packet is sent.
  168. * This packet often contain file names and the size of the file. It is the
  169. * on_begin's responsibility to parse the basic information of the file. The
  170. * on_begin can not be NULL.
  171. *
  172. * @param on_data The callback will be invoked when the data packets is sent.
  173. * The callback should read file system and prepare the data packets. The
  174. * on_data can not be NULL.
  175. *
  176. * @param on_end The callback will be invoked when one transmission is
  177. * finished. The data should be 128 bytes of NULL. The on_end can not be NULL.
  178. *
  179. * @param handshake_timeout the timeout when hand shaking. The unit is in
  180. * second.
  181. */
  182. rt_err_t rym_send_on_device(struct rym_ctx *ctx, rt_device_t dev, rt_uint16_t oflag,
  183. rym_callback on_begin, rym_callback on_data, rym_callback on_end,
  184. int handshake_timeout);
  185. #endif