improve file transfer

This commit is contained in:
lixianjing 2019-11-26 11:33:14 +08:00
parent 294cfa3bb7
commit da0e491a3f
13 changed files with 321 additions and 116 deletions

View File

@ -0,0 +1,27 @@
# 文件传输
主要用于在 PC 和开发板之间传输文件,通信方式可用 TCP 或串口。如果内部 flash 不够存放资源数据和程序数据,可用把资源数据做出文件系统镜像(或 zip 文件),下载到外部 flash 中。
File Transfer 提供了文件接收方和文件发送方两部分代码,文件发送方在 PC 端运行,文件接收方在开发板上运行。
* 在 PC 端运行 TCP 文件发送程序:
```
./bin/tcp_file_sender.exe port filename
```
如:
```
./bin/tcp_file_sender.exe 9999 assets.bin
```
* 在 PC 端运行串口文件发送程序:
```
./bin/serial_file_sender.exe port filename
```
如:
```
./bin/serial_file_sender.exe COM3 assets.bin
```

View File

@ -28,16 +28,10 @@
#include "tkc/iostream.h"
#include "file_transfer/file_receiver.h"
file_receiver_t* file_receiver_create(tk_iostream_t* io, tk_ostream_t* target, uint32_t block_size,
const char* productid) {
file_receiver_t* receiver = NULL;
return_value_if_fail(io != NULL && target != NULL, NULL);
receiver = TKMEM_ZALLOC(file_receiver_t);
file_receiver_t* file_receiver_create(uint32_t block_size, const char* productid) {
file_receiver_t* receiver = TKMEM_ZALLOC(file_receiver_t);
return_value_if_fail(receiver != NULL, NULL);
receiver->io = io;
receiver->target = target;
receiver->block_size =
tk_max(tk_min(block_size, FILE_TRANSFER_MAX_BLOCK_SIZE), FILE_TRANSFER_MIN_BLOCK_SIZE);
@ -45,13 +39,11 @@ file_receiver_t* file_receiver_create(tk_iostream_t* io, tk_ostream_t* target, u
tk_strncpy(receiver->productid, productid, TK_NAME_LEN);
}
object_ref(OBJECT(io));
object_ref(OBJECT(target));
return receiver;
}
ret_t file_receiver_run(file_receiver_t* receiver, const char* filename) {
ret_t file_receiver_run(file_receiver_t* receiver, tk_iostream_t* io, tk_ostream_t* target,
const char* filename) {
int32_t ret = 0;
uint32_t crc = 0;
uint32_t offset = 0;
@ -62,18 +54,19 @@ ret_t file_receiver_run(file_receiver_t* receiver, const char* filename) {
file_transfer_req_t req;
file_transfer_ack_t ack;
file_transfer_data_t data;
file_transfer_header_t header;
file_transfer_meta_t meta;
progress_event_t event;
return_value_if_fail(receiver != NULL, RET_BAD_PARAMS);
memset(&req, 0x00, sizeof(req));
memset(&ack, 0x00, sizeof(ack));
memset(&data, 0x00, sizeof(data));
memset(&header, 0x00, sizeof(header));
memset(&meta, 0x00, sizeof(meta));
in = tk_iostream_get_istream(receiver->io);
out = tk_iostream_get_ostream(receiver->io);
in = tk_iostream_get_istream(io);
out = tk_iostream_get_ostream(io);
goto_error_if_fail(in != NULL && out != NULL);
if (filename != NULL) {
tk_strncpy(req.filename, filename, TK_NAME_LEN);
}
@ -87,10 +80,10 @@ ret_t file_receiver_run(file_receiver_t* receiver, const char* filename) {
ret = tk_ostream_write_len(out, (const uint8_t*)&req, sizeof(req), timeout);
goto_error_if_fail(ret == sizeof(req));
ret = tk_istream_read_len(in, (uint8_t*)&header, sizeof(header), timeout * 100);
goto_error_if_fail(ret == sizeof(header));
ret = tk_istream_read_len(in, (uint8_t*)&meta, sizeof(meta), timeout * 100);
goto_error_if_fail(ret == sizeof(meta));
goto_error_if_fail(header.size > 0);
goto_error_if_fail(meta.size > 0);
buff = TKMEM_ALLOC(receiver->block_size + 1);
goto_error_if_fail(buff != NULL);
@ -102,12 +95,12 @@ ret_t file_receiver_run(file_receiver_t* receiver, const char* filename) {
ret = tk_istream_read_len(in, (uint8_t*)buff, data.size, timeout);
goto_error_if_fail(ret == data.size);
ack.size = ret;
ack.offset = data.offset;
crc = tk_crc32(PPPINITFCS32, buff, data.size);
if(crc != data.crc) {
if (crc != data.crc) {
log_debug("crc error\n");
ack.type = FILE_TRANSFER_PACKET_NACK;
ret = tk_ostream_write_len(out, (const uint8_t*)&ack, sizeof(ack), timeout);
@ -118,11 +111,11 @@ ret_t file_receiver_run(file_receiver_t* receiver, const char* filename) {
ret = tk_ostream_write_len(out, (const uint8_t*)&ack, sizeof(ack), timeout);
goto_error_if_fail(ret == sizeof(ack));
ret = tk_ostream_write_len(receiver->target, (const uint8_t*)buff, data.size, timeout);
ret = tk_ostream_write_len(target, (const uint8_t*)buff, data.size, timeout);
offset += data.size;
log_debug("%u/%u\n", offset, header.size);
if (offset == header.size) {
emitter_dispatch(EMITTER(receiver), progress_event_init(&event, (100 * offset / meta.size)));
if (offset == meta.size) {
log_debug("transfer done.\n");
break;
}
@ -131,14 +124,13 @@ ret_t file_receiver_run(file_receiver_t* receiver, const char* filename) {
error:
TKMEM_FREE(buff);
return (offset == header.size && offset > 0) ? RET_OK : RET_FAIL;
return (offset == meta.size && offset > 0) ? RET_OK : RET_FAIL;
}
ret_t file_receiver_destroy(file_receiver_t* receiver) {
return_value_if_fail(receiver != NULL, RET_BAD_PARAMS);
OBJECT_UNREF(receiver->io);
OBJECT_UNREF(receiver->target);
emitter_deinit(&(receiver->emitter));
TKMEM_FREE(receiver);
return RET_OK;

View File

@ -27,21 +27,53 @@
BEGIN_C_DECLS
/**
* @class file_receiver_t
*
*
* > EVT_PROGRESS事件
*/
typedef struct _file_receiver_t {
emitter_t emitter;
uint32_t received_bytes;
uint32_t total_bytes;
tk_iostream_t* io;
tk_ostream_t* target;
uint32_t block_size;
char productid[TK_NAME_LEN + 1];
} file_receiver_t;
file_receiver_t* file_receiver_create(tk_iostream_t* io, tk_ostream_t* target, uint32_t block_size,
const char* productid);
ret_t file_receiver_run(file_receiver_t* receiver, const char* filename);
/**
* @method file_receiver_create
* @annotation ["constructor"]
* receiver对象
*
* @param {uint32_t} block_size
* @param {const char*} productid ()
*
* @return {file_receiver_t*} receiver对象
*/
file_receiver_t* file_receiver_create(uint32_t block_size, const char* productid);
/**
* @method file_receiver_run
*
*
* @param {file_receiver_t*} receiver receiver对象
* @param {tk_iostream_t*} io
* @param {tk_ostream_t*} target
* @param {const char*} filename ()
*
* @return {ret_t} RET_OK表示成功
*/
ret_t file_receiver_run(file_receiver_t* receiver, tk_iostream_t* io, tk_ostream_t* target,
const char* filename);
/**
* @method file_receiver_destroy
* receiver对象
*
* @param {file_receiver_t*} receiver receiver对象
*
* @return {ret_t} RET_OK表示成功
*/
ret_t file_receiver_destroy(file_receiver_t* receiver);
END_C_DECLS

View File

@ -28,21 +28,16 @@
#include "tkc/iostream.h"
#include "file_transfer/file_sender.h"
file_sender_t* file_sender_create(const char* filename, tk_iostream_t* io) {
file_sender_t* sender = NULL;
return_value_if_fail(filename != NULL && io != NULL, NULL);
sender = TKMEM_ZALLOC(file_sender_t);
file_sender_t* file_sender_create(void) {
file_sender_t* sender = TKMEM_ZALLOC(file_sender_t);
return_value_if_fail(sender != NULL, NULL);
sender->io = io;
sender->filename = filename;
emitter_init(&(sender->emitter));
object_ref(OBJECT(io));
return sender;
}
ret_t file_sender_run(file_sender_t* sender) {
ret_t file_sender_run(file_sender_t* sender, tk_iostream_t* io, const char* filename) {
int32_t ret = 0;
uint32_t offset = 0;
int32_t total_size = 0;
@ -54,22 +49,23 @@ ret_t file_sender_run(file_sender_t* sender) {
file_transfer_req_t req;
file_transfer_ack_t ack;
file_transfer_data_t data;
file_transfer_header_t header;
file_transfer_meta_t meta;
progress_event_t event;
return_value_if_fail(sender != NULL, RET_BAD_PARAMS);
memset(&req, 0x00, sizeof(req));
memset(&ack, 0x00, sizeof(ack));
memset(&data, 0x00, sizeof(data));
memset(&header, 0x00, sizeof(header));
memset(&meta, 0x00, sizeof(meta));
total_size = file_get_size(sender->filename);
total_size = file_get_size(filename);
goto_error_if_fail(total_size > 0);
f = fs_open_file(os_fs(), sender->filename, "rb");
f = fs_open_file(os_fs(), filename, "rb");
goto_error_if_fail(f != NULL);
in = tk_iostream_get_istream(sender->io);
out = tk_iostream_get_ostream(sender->io);
in = tk_iostream_get_istream(io);
out = tk_iostream_get_ostream(io);
goto_error_if_fail(in != NULL && out != NULL);
ret = tk_istream_read_len(in, (uint8_t*)&req, sizeof(req), timeout * 10);
@ -80,12 +76,12 @@ ret_t file_sender_run(file_sender_t* sender) {
goto_error_if_fail(buff != NULL);
data.type = FILE_TRANSFER_PACKET_DATA;
header.type = FILE_TRANSFER_PACKET_HEADER;
header.size = total_size;
path_basename(sender->filename, header.name, sizeof(header.name));
meta.type = FILE_TRANSFER_PACKET_META;
meta.size = total_size;
path_basename(filename, meta.name, sizeof(meta.name));
ret = tk_ostream_write_len(out, (const uint8_t*)&header, sizeof(header), timeout);
goto_error_if_fail(ret == sizeof(header));
ret = tk_ostream_write_len(out, (const uint8_t*)&meta, sizeof(meta), timeout);
goto_error_if_fail(ret == sizeof(meta));
do {
ret = fs_file_read(f, buff, req.block_size);
@ -105,8 +101,8 @@ ret_t file_sender_run(file_sender_t* sender) {
goto_error_if_fail(ack.type == FILE_TRANSFER_PACKET_ACK);
offset += data.size;
log_debug("%u/%u\n", offset, total_size);
if(offset == total_size) {
emitter_dispatch(EMITTER(sender), progress_event_init(&event, (100 * offset / total_size)));
if (offset == total_size) {
log_debug("transfer done.\n");
break;
}
@ -124,7 +120,6 @@ error:
ret_t file_sender_destroy(file_sender_t* sender) {
return_value_if_fail(sender != NULL, RET_BAD_PARAMS);
OBJECT_UNREF(sender->io);
emitter_deinit(&(sender->emitter));
TKMEM_FREE(sender);

View File

@ -27,17 +27,45 @@
BEGIN_C_DECLS
/**
* @class file_sender_t
*
*
* > EVT_PROGRESS事件
*/
typedef struct _file_sender_t {
emitter_t emitter;
uint32_t sent_bytes;
uint32_t total_bytes;
tk_iostream_t* io;
const char* filename;
} file_sender_t;
file_sender_t* file_sender_create(const char* filename, tk_iostream_t* io);
ret_t file_sender_run(file_sender_t* sender);
/**
* @method file_sender_create
* @annotation ["constructor"]
* sender对象
*
* @return {file_sender_t*} sender对象
*/
file_sender_t* file_sender_create(void);
/**
* @method file_sender_run
*
*
* @param {file_sender_t*} sender sender对象
* @param {tk_iostream_t*} io
* @param {const char*} filename
*
* @return {ret_t} RET_OK表示成功
*/
ret_t file_sender_run(file_sender_t* sender, tk_iostream_t* io, const char* filename);
/**
* @method file_sender_destroy
* sender对象
*
* @param {file_sender_t*} sender sender对象
*
* @return {ret_t} RET_OK表示成功
*/
ret_t file_sender_destroy(file_sender_t* sender);
END_C_DECLS

View File

@ -26,39 +26,162 @@
BEGIN_C_DECLS
/**
* @enum file_transfer_packet_type_t
*
*/
typedef enum _file_transfer_packet_type_t {
FILE_TRANSFER_PACKET_HEADER = 0xffeedd01,
/**
* @const FILE_TRANSFER_PACKET_META
* (sender->receiver)
*/
FILE_TRANSFER_PACKET_META = 0xffeedd01,
/**
* @const FILE_TRANSFER_PACKET_DATA
* (sender->receiver)
*/
FILE_TRANSFER_PACKET_DATA = 0xffeedd02,
/**
* @const FILE_TRANSFER_PACKET_ACK
* (sender<-receiver)
*/
FILE_TRANSFER_PACKET_ACK = 0xffeedd03,
/**
* @const FILE_TRANSFER_PACKET_NACK
* (sender<-receiver)
*/
FILE_TRANSFER_PACKET_NACK = 0xffeedd04,
/**
* @const FILE_TRANSFER_PACKET_REQ
* (sender<-receiver)
*/
FILE_TRANSFER_PACKET_REQ = 0xffeedd05
} file_transfer_packet_type_t;
typedef struct _file_transfer_header_t {
/**
* @class file_transfer_meta_t
* (sender->receiver)
*/
typedef struct _file_transfer_meta_t {
/**
* @property {uint32_t} type
* @annotation ["readable","writable"]
*
*/
uint32_t type;
/**
* @property {uint32_t} size
* @annotation ["readable","writable"]
*
*/
uint32_t size;
/**
* @property {char*} name
* @annotation ["readable","writable"]
*
*/
char name[TK_NAME_LEN + 1];
} file_transfer_header_t;
typedef struct _file_transfer_req_t {
uint32_t type;
uint32_t block_size;
char filename[TK_NAME_LEN + 1];
char productid[TK_NAME_LEN + 1];
} file_transfer_req_t;
} file_transfer_meta_t;
/**
* @class file_transfer_data_t
* (sender->receiver)
*/
typedef struct _file_transfer_data_t {
/**
* @property {uint32_t} type
* @annotation ["readable","writable"]
*
*/
uint32_t type;
/**
* @property {uint32_t} size
* @annotation ["readable","writable"]
*
*/
uint32_t size;
/**
* @property {uint32_t} offset
* @annotation ["readable","writable"]
*
*/
uint32_t offset;
/**
* @property {uint32_t} crc
* @annotation ["readable","writable"]
* CRC
*/
uint32_t crc;
} file_transfer_data_t;
typedef struct _file_transfer_ack_t {
/**
* @class file_transfer_req_t
* (sender<-receiver)
*/
typedef struct _file_transfer_req_t {
/**
* @property {uint32_t} type
* @annotation ["readable","writable"]
*
*/
uint32_t type;
/**
* @property {uint32_t} block_size
* @annotation ["readable","writable"]
*
*/
uint32_t block_size;
/**
* @property {char*} filename
* @annotation ["readable","writable"]
*
*/
char filename[TK_NAME_LEN + 1];
/**
* @property {char*} productid
* @annotation ["readable","writable"]
* ID()
*/
char productid[TK_NAME_LEN + 1];
} file_transfer_req_t;
/**
* @class file_transfer_ack_t
* (sender<-receiver)
*/
typedef struct _file_transfer_ack_t {
/**
* @property {uint32_t} type
* @annotation ["readable","writable"]
*
*/
uint32_t type;
/**
* @property {uint32_t} size
* @annotation ["readable","writable"]
*
*/
uint32_t size;
/**
* @property {uint32_t} offset
* @annotation ["readable","writable"]
*
*/
uint32_t offset;
uint32_t crc;
} file_transfer_ack_t;
#define FILE_TRANSFER_MIN_BLOCK_SIZE 1024

View File

@ -0,0 +1,19 @@
static ret_t on_progress(void* ctx, event_t* e) {
progress_event_t* evt = (progress_event_t*)e;
log_debug("progress: %u\n", evt->percent);
return RET_OK;
}
ret_t do_receive(tk_iostream_t* io, tk_ostream_t* target, const char* filename) {
file_receiver_t* receiver = file_receiver_create(FILE_TRANSFER_DEFAULT_BLOCK_SIZE, "myboard");
return_value_if_fail(receiver != NULL, RET_FAIL);
emitter_on(EMITTER(receiver), EVT_PROGRESS, on_progress, NULL);
file_receiver_run(receiver, io, target, filename);
file_receiver_destroy(receiver);
return RET_OK;
}

View File

@ -0,0 +1,18 @@
static ret_t on_progress(void* ctx, event_t* e) {
progress_event_t* evt = (progress_event_t*)e;
log_debug("progress: %u\n", evt->percent);
return RET_OK;
}
static ret_t do_send(tk_iostream_t* io, const char* filename) {
file_sender_t* sender = file_sender_create();
return_value_if_fail(sender != NULL, RET_FAIL);
emitter_on(EMITTER(sender), EVT_PROGRESS, on_progress, NULL);
file_sender_run(sender, io, filename);
file_sender_destroy(sender);
return RET_OK;
}

View File

@ -8,15 +8,7 @@
#include "streams/serial/iostream_serial.h"
#include "streams/file/ostream_file.h"
ret_t do_receive(tk_iostream_t* io, tk_ostream_t* target, const char* filename) {
file_receiver_t* receiver = file_receiver_create(io, target, FILE_TRANSFER_DEFAULT_BLOCK_SIZE, "myboard");
return_value_if_fail(receiver != NULL, RET_FAIL);
file_receiver_run(receiver, filename);
file_receiver_destroy(receiver);
return RET_OK;
}
#include "receiver.inc"
int main(int argc, char* argv[]) {
const char* port = NULL;

View File

@ -7,15 +7,7 @@
#include "file_transfer/file_sender.h"
#include "streams/serial/iostream_serial.h"
ret_t do_send(tk_iostream_t* io, const char* filename) {
file_sender_t* sender = file_sender_create(filename, io);
return_value_if_fail(sender != NULL, RET_FAIL);
file_sender_run(sender);
file_sender_destroy(sender);
return RET_OK;
}
#include "sender.inc"
int main(int argc, char* argv[]) {
const char* port = NULL;
@ -31,6 +23,7 @@ int main(int argc, char* argv[]) {
port = argv[1];
filename = argv[2];
return_value_if_fail(file_exist(filename), 0);
do {
tk_iostream_t* io = tk_iostream_serial_create(port);

View File

@ -9,15 +9,7 @@
#include "streams/inet/socket_helper.h"
#include "streams/file/ostream_file.h"
ret_t do_receive(tk_iostream_t* io, tk_ostream_t* out, const char* filename) {
file_receiver_t* receiver = file_receiver_create(io, out, FILE_TRANSFER_DEFAULT_BLOCK_SIZE, "myboard");
return_value_if_fail(receiver != NULL, RET_FAIL);
file_receiver_run(receiver, filename);
file_receiver_destroy(receiver);
return RET_OK;
}
#include "receiver.inc"
int main(int argc, char* argv[]) {
int sock = 0;
@ -40,7 +32,7 @@ int main(int argc, char* argv[]) {
sock = tcp_connect(host, port);
if(sock > 0) {
if (sock > 0) {
log_debug("connected %d \n", sock);
tk_iostream_t* io = tk_iostream_tcp_create(sock);
tk_ostream_t* out = tk_ostream_file_create(filename);

View File

@ -8,15 +8,7 @@
#include "streams/inet/iostream_tcp.h"
#include "streams/inet/socket_helper.h"
ret_t do_send(tk_iostream_t* io, const char* filename) {
file_sender_t* sender = file_sender_create(filename, io);
return_value_if_fail(sender != NULL, RET_FAIL);
file_sender_run(sender);
file_sender_destroy(sender);
return RET_OK;
}
#include "sender.inc"
int main(int argc, char* argv[]) {
int sock = 0;
@ -35,6 +27,8 @@ int main(int argc, char* argv[]) {
port = tk_atoi(argv[1]);
filename = argv[2];
return_value_if_fail(file_exist(filename), 0);
sock = tcp_listen(port);
return_value_if_fail(sock > 0, 0);

View File

@ -91,8 +91,8 @@ static ret_t tk_iostream_serial_exec(object_t* obj, const char* name, const char
} else if (tk_str_eq(name, TK_IOSTREAM_SERIAL_CMD_CONFIG)) {
int ret =
serial_config(s->fd, s->baudrate, s->bytesize, s->stopbits, s->flowcontrol, s->parity);
log_debug("baudrate=%d bytesize=%d stopbits=%d flowcontrol=%d parity=%d\n",
s->baudrate, s->bytesize, s->stopbits, s->flowcontrol, s->parity);
log_debug("baudrate=%d bytesize=%d stopbits=%d flowcontrol=%d parity=%d\n", s->baudrate,
s->bytesize, s->stopbits, s->flowcontrol, s->parity);
serial_oflush(s->fd);
return ret == 0 ? RET_OK : RET_FAIL;