From 608c07083a1bf61df3ef38415242dbf0f333b806 Mon Sep 17 00:00:00 2001 From: Olivier Matz Date: Wed, 26 Feb 2014 20:16:56 +0100 Subject: [PATCH] avoid copy by using iovecs --- commands.c | 16 +++++++- rc_proto.c | 23 ++++++------ xbee_user.c | 104 ++++++++++++++++++++++++++++++---------------------- xbee_user.h | 29 +++++++++++---- 4 files changed, 107 insertions(+), 65 deletions(-) diff --git a/commands.c b/commands.c index 446d92d..ffcd918 100644 --- a/commands.c +++ b/commands.c @@ -533,9 +533,15 @@ struct cmd_sendmsg_result { static void cmd_sendmsg_parsed(void *parsed_result, void *data) { struct cmd_sendmsg_result *res = parsed_result; + struct xbee_msg msg; (void)data; - xbeeapp_send_msg(res->addr, res->data, strlen(res->data), 1); + + msg.iovlen = 1; + msg.iov[0].buf = res->data; + msg.iov[0].len = strlen(res->data); + + xbeeapp_send_msg(res->addr, &msg, 1); } const char PROGMEM str_sendmsg[] = "sendmsg"; @@ -676,9 +682,15 @@ struct cmd_sendmsg_name_result { static void cmd_sendmsg_name_parsed(void *parsed_result, void *data) { struct cmd_sendmsg_name_result *res = parsed_result; + struct xbee_msg msg; (void)data; - xbeeapp_send_msg(res->neigh->addr, res->data, strlen(res->data), 1); + + msg.iovlen = 1; + msg.iov[0].buf = res->data; + msg.iov[0].len = strlen(res->data); + + xbeeapp_send_msg(res->neigh->addr, &msg, 1); } const parse_token_string_t PROGMEM cmd_sendmsg_name_sendmsg_name = diff --git a/rc_proto.c b/rc_proto.c index 22b6f28..56e8ad6 100644 --- a/rc_proto.c +++ b/rc_proto.c @@ -78,22 +78,21 @@ void rc_proto_rx_power_probe(int power_level) } /* send a hello message */ -// XXX iovec for xbee ? int8_t rc_proto_send_hello(uint64_t addr, void *data, uint8_t data_len) { - struct { - struct rc_proto_echo_req hdr; - char buf[XBEE_MAX_FRAME_LEN - sizeof(struct rc_proto_echo_req)]; - } frame; + struct rc_proto_echo_req hdr; + struct xbee_msg msg; - if (data_len > sizeof(frame.buf)) - return -1; + hdr.type = RC_PROTO_HELLO; + hdr.datalen = data_len; + + msg.iovlen = 2; + msg.iov[0].buf = &hdr; + msg.iov[0].len = sizeof(hdr); + msg.iov[1].buf = data; + msg.iov[1].len = data_len; - frame.hdr.type = RC_PROTO_HELLO; - frame.hdr.datalen = data_len; - memcpy(frame.buf, data, data_len); - return xbeeapp_send_msg(addr, &frame, - data_len + sizeof(struct rc_proto_echo_req), 1); + return xbeeapp_send_msg(addr, &msg, 1); } diff --git a/xbee_user.c b/xbee_user.c index 81f2fb6..4717313 100644 --- a/xbee_user.c +++ b/xbee_user.c @@ -38,6 +38,7 @@ #include #include +#include #include "rc_proto.h" #include "xbee_user.h" @@ -54,14 +55,13 @@ int xbee_raw = 0; int xbee_hexdump = 0; int xbee_debug = 0; -static void hexdump(const char *title, const void *buf, unsigned int len) +static void __hexdump(const void *buf, unsigned int len) { unsigned int i, out, ofs; const unsigned char *data = buf; #define LINE_LEN 80 char line[LINE_LEN]; /* space needed 8+16*3+3+16 == 75 */ - printf_P(PSTR("%s at [%p], len=%d\r\n"), title, data, len); ofs = 0; while (ofs < len) { /* format 1 line in the buffer, then use printk to print them */ @@ -84,8 +84,26 @@ static void hexdump(const char *title, const void *buf, unsigned int len) } } +static void hexdump_msg(const char *title, const struct xbee_msg *msg) +{ + unsigned i; + + printf_P(PSTR("dump %s\r\n"), title); + for (i = 0; i < msg->iovlen; i++) { + printf_P(PSTR("iovec %d at %p, len=%d\r\n"), i, + msg->iov[i].buf, msg->iov[i].len); + __hexdump(msg->iov[i].buf, msg->iov[i].len); + } +} + +static void hexdump(const char *title, const void *buf, unsigned int len) +{ + printf_P(PSTR("dump %s at [%p], len=%d\r\n"), title, buf, len); + __hexdump(buf, len); +} + static int parse_xmit_status(struct xbee_ctx *ctx, - struct xbee_xmit_status_hdr *frame, unsigned len) + struct xbee_xmit_status_hdr *frame, unsigned len) { (void)len; @@ -116,7 +134,7 @@ static int parse_xmit_status(struct xbee_ctx *ctx, } static int dump_atcmd(struct xbee_ctx *ctx, struct xbee_atresp_hdr *frame, - unsigned len) + unsigned len) { char atcmd_str[3]; const struct xbee_atcmd *cmd_pgm; @@ -362,17 +380,12 @@ int8_t xbeeapp_rx(struct xbee_dev *dev, int channel, int type, return ret; } -static int xbeeapp_send(struct xbee_ctx *ctx, int type, void *buf, unsigned len, - int foreground) +static int xbeeapp_send(struct xbee_ctx *ctx, int type, struct xbee_msg *msg, + int foreground) { int ret; int channel; - if (len > XBEE_MAX_FRAME_LEN) { - printf_P(PSTR("frame too large\r\n")); - return -1; - } - /* register a channel */ channel = xbee_register_channel(xbee_dev, XBEE_CHANNEL_ANY, xbeeapp_rx, NULL); @@ -387,13 +400,13 @@ static int xbeeapp_send(struct xbee_ctx *ctx, int type, void *buf, unsigned len, xbee_set_opaque(xbee_dev, channel, ctx); if (xbee_debug) - printf_P(PSTR("send frame channel=%d type=0x%x len=%d\r\n"), - channel, type, len); + printf_P(PSTR("send frame channel=%d type=0x%x\r\n"), + channel, type); if (xbee_hexdump) - hexdump("xmit frame", buf, len); + hexdump_msg("xmit frame", msg); /* transmit the frame on this channel */ - ret = xbee_tx(xbee_dev, channel, type, buf, len); + ret = xbee_tx_iovec(xbee_dev, channel, type, msg); if (ret < 0) { printf_P(PSTR("cannot send\r\n")); xbee_unregister_channel(xbee_dev, channel); @@ -415,15 +428,13 @@ static int xbeeapp_send(struct xbee_ctx *ctx, int type, void *buf, unsigned len, /* send an AT command with parameters filled by caller. Disable * command line until we get the answer or until a timeout occurs */ -int xbeeapp_send_atcmd(const char *atcmd_str, - void *param, unsigned param_len, int foreground, - int (*func)(void *frame, unsigned len, void *arg), void *arg) +int xbeeapp_send_atcmd(char *atcmd_str, void *param, + unsigned param_len, int foreground, + int (*func)(void *frame, unsigned len, void *arg), void *arg) { struct xbee_ctx ctx; - struct { - struct xbee_atcmd_hdr atcmd; - char buf[XBEE_MAX_FRAME_LEN]; - } __attribute__((packed)) frame; + /* struct xbee_atcmd_hdr atcmd_hdr; -> no needed same than atcmd_str */ + struct xbee_msg msg; memset(&ctx, 0, sizeof(ctx)); ctx.atcmd_query[0] = atcmd_str[0]; @@ -431,41 +442,46 @@ int xbeeapp_send_atcmd(const char *atcmd_str, ctx.func = func; ctx.arg = arg; - memcpy(&frame.atcmd.cmd, atcmd_str, 2); - memcpy(&frame.buf, param, param_len); + msg.iovlen = 2; + msg.iov[0].buf = atcmd_str; + msg.iov[0].len = 2; + msg.iov[1].buf = param; + msg.iov[1].len = param_len; - if (xbeeapp_send(&ctx, XBEE_TYPE_ATCMD, &frame, - sizeof(struct xbee_atcmd_hdr) + - param_len, foreground) < 0) { + if (xbeeapp_send(&ctx, XBEE_TYPE_ATCMD, &msg, foreground) < 0) return -1; - } return 0; } -int xbeeapp_send_msg(uint64_t addr, void *data, - unsigned data_len, int foreground) +int xbeeapp_send_msg(uint64_t addr, struct xbee_msg *msg, int foreground) { struct xbee_ctx ctx; - struct { - struct xbee_xmit_hdr xmit; - char buf[XBEE_MAX_FRAME_LEN]; - } __attribute__((packed)) frame; + struct xbee_xmit_hdr xmit_hdr; + struct xbee_msg msg2; + unsigned i; + + if (msg->iovlen + 2 > XBEE_MSG_MAXIOV) { + printf_P(PSTR("too many iovecs\r\n")); + return -1; + } + + xmit_hdr.dstaddr = htonll(addr); + xmit_hdr.reserved = htons(0xFFFE); + xmit_hdr.bcast_radius = 0; + xmit_hdr.opts = 0; + + msg2.iovlen = msg->iovlen + 1; + msg2.iov[0].buf = &xmit_hdr; + msg2.iov[0].len = sizeof(xmit_hdr); + for (i = 0; i < msg->iovlen; i++) + msg2.iov[i+1] = msg->iov[i]; memset(&ctx, 0, sizeof(ctx)); ctx.atcmd_query[0] = '\0'; - frame.xmit.dstaddr = htonll(addr); - frame.xmit.reserved = htons(0xFFFE); - frame.xmit.bcast_radius = 0; - frame.xmit.opts = 0; - memcpy(&frame.buf, data, data_len); - - if (xbeeapp_send(&ctx, XBEE_TYPE_XMIT, &frame, - sizeof(struct xbee_xmit_hdr) + - data_len, foreground) < 0) { + if (xbeeapp_send(&ctx, XBEE_TYPE_XMIT, &msg2, foreground) < 0) return -1; - } return 0; } diff --git a/xbee_user.h b/xbee_user.h index ced5363..daedeee 100644 --- a/xbee_user.h +++ b/xbee_user.h @@ -29,6 +29,7 @@ #define _XBEE_USER_H_ #include +#include /* used for timeouts and xbee rx callback */ struct xbee_ctx { @@ -46,14 +47,28 @@ extern int xbee_raw; extern int xbee_hexdump; extern int xbee_debug; +/* we use a specific structure to send packets. It allows to prepend some + * data in the frame without doing a copy. */ +struct xbeeapp_pkt { + char *buf; + unsigned len; + unsigned headroom; + unsigned tailroom; +}; + +/* callback registered to xbee module, called when a xbee frame is received */ int8_t xbeeapp_rx(struct xbee_dev *dev, int channel, int type, - void *frame, unsigned len, void *opaque); -int xbeeapp_send_atcmd(const char *atcmd_str, - void *param, unsigned param_len, int foreground, - int (*func)(void *frame, unsigned len, void *arg), - void *arg); -int xbeeapp_send_msg(uint64_t addr, void *data, - unsigned data_len, int foreground); + void *frame, unsigned len, void *opaque); + +/* Send an AT command to the xbee device. The callback function for the answer + * is given as a parameter */ +int xbeeapp_send_atcmd(char *atcmd_str, void *param, + unsigned param_len, int foreground, + int (*func)(void *frame, unsigned len, void *arg), + void *arg); + +/* send a message to a peer */ +int xbeeapp_send_msg(uint64_t addr, struct xbee_msg *msg, int foreground); void xbee_stdin_enable(void); void xbee_stdin_disable(void); -- 2.20.1