ymodem.h 4.5 KB
Newer Older
G
Grissiom 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
#ifndef __YMODEM_H__
#define __YMODEM_H__
/*
 * File      : ymodem.h
 * COPYRIGHT (C) 2012, Shanghai Real-Thread Technology Co., Ltd
 *
 * Change Logs:
 * Date           Author       Notes
 * 2013-04-14     Grissiom     initial implementation
 */

#include "rtthread.h"

/* The word "RYM" is stand for "Real-YModem". */

enum rym_code {
    RYM_CODE_NONE = 0x00,
    RYM_CODE_SOH  = 0x01,
    RYM_CODE_STX  = 0x02,
    RYM_CODE_EOT  = 0x04,
    RYM_CODE_ACK  = 0x06,
    RYM_CODE_NAK  = 0x15,
    RYM_CODE_CAN  = 0x18,
    RYM_CODE_C    = 0x43,
};

/* RYM error code
 *
 * We use the rt_err_t to return error values. We take use of current error
 * codes available in RTT and append ourselves.
 */
/* timeout on handshake */
#define RYM_ERR_TMO  0x70
/* wrong code, wrong SOH, STX etc. */
#define RYM_ERR_CODE 0x71
/* wrong sequence number */
#define RYM_ERR_SEQ  0x72
/* wrong CRC checksum */
#define RYM_ERR_CRC  0x73
/* not enough data received */
#define RYM_ERR_DSZ  0x74
/* the transmission is aborted by user */
#define RYM_ERR_CAN  0x75

/* how many ticks wait for chars between packet. */
#ifndef RYM_WAIT_CHR_TICK
#define RYM_WAIT_CHR_TICK (RT_TICK_PER_SECOND * 3)
#endif
/* how many ticks wait for between packet. */
#ifndef RYM_WAIT_PKG_TICK
#define RYM_WAIT_PKG_TICK (RT_TICK_PER_SECOND * 3)
#endif
/* how many ticks between two handshake code. */
#ifndef RYM_CHD_INTV_TICK
B
bernard 已提交
55 56 57 58 59 60
#define RYM_CHD_INTV_TICK (RT_TICK_PER_SECOND * 3)
#endif

/* how many CAN be sent when user active end the session. */
#ifndef RYM_END_SESSION_SEND_CAN_NUM
#define RYM_END_SESSION_SEND_CAN_NUM  0x07
G
Grissiom 已提交
61 62 63 64 65 66 67 68
#endif

enum rym_stage {
    RYM_STAGE_NONE,
    /* set when C is send */
    RYM_STAGE_ESTABLISHING,
    /* set when we've got the packet 0 and sent ACK and second C */
    RYM_STAGE_ESTABLISHED,
B
bernard 已提交
69 70
    /* set when the sender respond to our second C and recviever got a real
     * data packet. */
G
Grissiom 已提交
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
    RYM_STAGE_TRANSMITTING,
    /* set when the sender send a EOT */
    RYM_STAGE_FINISHING,
    /* set when transmission is really finished, i.e., after the NAK, C, final
     * NULL packet stuff. */
    RYM_STAGE_FINISHED,
};

struct rym_ctx;
/* when receiving files, the buf will be the data received from ymodem protocol
 * and the len is the data size.
 *
 * TODO:
 * When sending files, the len is the buf size in RYM. The callback need to
 * fill the buf with data to send. Returning RYM_CODE_EOT will terminate the
 * transfer and the buf will be discarded. Any other return values will cause
 * the transfer continue.
 */
typedef enum rym_code (*rym_callback)(struct rym_ctx *ctx, rt_uint8_t *buf, rt_size_t len);

/* Currently RYM only support one transfer session(ctx) for simplicity.
 *
 * In case we could support multiple sessions in The future, the first argument
 * of APIs are (struct rym_ctx*).
 */
struct rym_ctx
{
    rym_callback on_data;
    rym_callback on_begin;
    rym_callback on_end;
    /* When error happened, user need to check this to get when the error has
     * happened. */
    enum rym_stage stage;
    /* user could get the error content through this */
    rt_uint8_t *buf;

    struct rt_semaphore sem;

    rt_device_t dev;
};

/** recv a file on device dev with ymodem session ctx.
 *
 * If an error happens, you can get where it is failed from ctx->stage.
 *
 * @param on_begin The callback will be invoked when the first packet arrived.
 * This packet often contain file names and the size of the file, if the sender
 * support it. So if you want to save the data to a file, you may need to
 * create the file on need. It is the on_begin's responsibility to parse the
 * data content. The on_begin can be NULL, in which case the transmission will
 * continue without any side-effects.
 *
 * @param on_data The callback will be invoked on the packets received.  The
 * callback should save the data to the destination. The return value will be
 * sent to the sender and in turn, only RYM_{ACK,CAN} is valid. When on_data is
 * NULL, RYM will barely send ACK on every packet and have no side-effects.
 *
 * @param on_end The callback will be invoked when one transmission is
 * finished. The data should be 128 bytes of NULL. You can do some cleaning job
 * in this callback such as closing the file. The return value of this callback
 * is ignored. As above, this parameter can be NULL if you don't need such
 * function.
 *
 * @param handshake_timeout the timeout when hand shaking. The unit is in
 * second.
 */
rt_err_t rym_recv_on_device(struct rym_ctx *ctx, rt_device_t dev,
        rym_callback on_begin, rym_callback on_data, rym_callback on_end,
        int handshake_timeout);

#endif