From e39c5d534eaa4d29fea56d7851343612fdab9a23 Mon Sep 17 00:00:00 2001 From: Olivier Matz Date: Sat, 8 Mar 2014 21:16:18 +0100 Subject: [PATCH] rework xbee_user: remove the foreground param --- commands.c | 77 +++++++++++++++++++--- notes.txt | 52 ++++++++++++++- rc_proto.c | 11 +++- xbee_user.c | 185 ++++++++++++++++++++++++++++------------------------ xbee_user.h | 24 +++++-- 5 files changed, 241 insertions(+), 108 deletions(-) diff --git a/commands.c b/commands.c index 3448ded..2c663c1 100644 --- a/commands.c +++ b/commands.c @@ -83,7 +83,8 @@ static void monitor_cb(struct callout_mgr *cm, if (monitor_current == NULL) monitor_current = LIST_FIRST(&xbee_monitor_list); - xbeeapp_send_atcmd(monitor_current->atcmd, NULL, 0, 0, NULL, NULL); + /* no rx_cb given: the user must check the monitored values in logs */ + xbeeapp_send_atcmd(monitor_current->atcmd, NULL, 0, NULL, NULL); monitor_current = LIST_NEXT(monitor_current, next); callout_reschedule(cm, clt, monitor_period_ms / monitor_count); } @@ -125,6 +126,56 @@ static void range_cb(struct callout_mgr *cm, callout_reschedule(cm, clt, range_period_ms); #endif +/* callback invoked when a xbee_send is done */ +static int8_t send_msg_cb(int8_t retcode, void *frame, unsigned len, + void *arg) +{ + struct xbee_recv_hdr *recvframe = frame; + uint8_t *done = arg; + + *done = 1; + if (retcode == XBEE_USER_RETCODE_TIMEOUT) { + printf_P(PSTR("timeout\r\n")); + return retcode; + } + if (retcode == XBEE_USER_RETCODE_BAD_FRAME || + len < sizeof(*recvframe)) { + printf_P(PSTR("invalid frame\r\n")); + return XBEE_USER_RETCODE_BAD_FRAME; + } + + printf_P(PSTR("ok\r\n")); + return XBEE_USER_RETCODE_OK; +} + +/* callback invoked to dump the response to AT command */ +static int8_t dump_xbee_atresp_cb(int8_t retcode, void *frame, unsigned len, + void *arg) +{ + struct xbee_atresp_hdr *recvframe = frame; + char atcmd_str[3]; + char buf[32]; + uint8_t *done = arg; + + *done = 1; + if (retcode == XBEE_USER_RETCODE_TIMEOUT) { + printf_P(PSTR("timeout\r\n")); + return retcode; + } + if (retcode == XBEE_USER_RETCODE_BAD_FRAME || + len < sizeof(*recvframe)) { + printf_P(PSTR("invalid frame\r\n")); + return XBEE_USER_RETCODE_BAD_FRAME; + } + + /* get AT command from frame */ + memcpy(atcmd_str, &recvframe->cmd, 2); + atcmd_str[2] = '\0'; + + len -= sizeof(*recvframe); + atresp_to_str(buf, sizeof(buf), frame); + NOTICE(E_USER_XBEE, "status ok, len=%d, %s", len, buf); + return XBEE_USER_RETCODE_OK; } /* this structure is filled when cmd_help is parsed successfully */ @@ -324,9 +375,6 @@ const parse_inst_t PROGMEM cmd_neigh_list = { }, }; - - - /* ************* */ /* this structure is filled when cmd_read is parsed successfully */ @@ -342,12 +390,14 @@ static void cmd_read_parsed(void *parsed_result, struct cmd_read_result *res = parsed_result; struct xbee_atcmd copy; char cmd[3]; + volatile uint8_t done = 0; (void)data; memcpy_P(©, res->cmd, sizeof(copy)); memcpy_P(&cmd, copy.name, 2); cmd[2] = '\0'; - xbeeapp_send_atcmd(cmd, NULL, 0, 1, NULL, NULL); + xbeeapp_send_atcmd(cmd, NULL, 0, dump_xbee_atresp_cb, (void *)&done); + while (done == 0); } const char PROGMEM str_read_read[] = "read"; @@ -394,6 +444,7 @@ static void cmd_write_parsed(void *parsed_result, void *data) char cmd[3]; int len; void *param; + volatile uint8_t done = 0; (void)data; memcpy_P(©, res->cmd, sizeof(copy)); @@ -422,7 +473,8 @@ static void cmd_write_parsed(void *parsed_result, void *data) } memcpy_P(&cmd, copy.name, 2); cmd[2] = '\0'; - xbeeapp_send_atcmd(cmd, param, len, 1, NULL, NULL); + xbeeapp_send_atcmd(cmd, param, len, dump_xbee_atresp_cb, (void *)&done); + while (done == 0); } const char PROGMEM str_write_none[] = "write"; @@ -534,6 +586,7 @@ static void cmd_sendmsg_parsed(void *parsed_result, void *data) { struct cmd_sendmsg_result *res = parsed_result; struct xbee_msg msg; + volatile uint8_t done = 0; (void)data; @@ -541,7 +594,8 @@ static void cmd_sendmsg_parsed(void *parsed_result, void *data) msg.iov[0].buf = res->data; msg.iov[0].len = strlen(res->data); - xbeeapp_send_msg(res->addr, &msg, 1); + xbeeapp_send_msg(res->addr, &msg, send_msg_cb, (void *)&done); + while (done == 0); } const char PROGMEM str_sendmsg[] = "sendmsg"; @@ -683,6 +737,7 @@ static void cmd_sendmsg_name_parsed(void *parsed_result, void *data) { struct cmd_sendmsg_name_result *res = parsed_result; struct xbee_msg msg; + volatile uint8_t done = 0; (void)data; @@ -690,7 +745,8 @@ static void cmd_sendmsg_name_parsed(void *parsed_result, void *data) msg.iov[0].buf = res->data; msg.iov[0].len = strlen(res->data); - xbeeapp_send_msg(res->neigh->addr, &msg, 1); + xbeeapp_send_msg(res->neigh->addr, &msg, send_msg_cb, (void *)&done); + while (done == 0); } const parse_token_string_t PROGMEM cmd_sendmsg_name_sendmsg_name = @@ -1225,9 +1281,12 @@ struct cmd_ping_result { /* function called when cmd_ping is parsed successfully */ static void cmd_ping_parsed(void *parsed_result, void *data) { + volatile uint8_t done = 0; + (void)parsed_result; (void)data; - xbeeapp_send_atcmd("VL", NULL, 0, 1, NULL, NULL); + xbeeapp_send_atcmd("VL", NULL, 0, dump_xbee_atresp_cb, (void *)&done); + while (done == 0); } const char PROGMEM str_ping[] = "ping"; diff --git a/notes.txt b/notes.txt index 260ad08..33cab7b 100644 --- a/notes.txt +++ b/notes.txt @@ -105,10 +105,13 @@ interrupt, software interrupts and background tasks problem description ------------------- -Today, Both command line code, xbee char reception and callout events +Today, both command line code, xbee char reception and callout events are handled in the main loop, with the lowest priority. Therefore, the command line cannot block, else the timers + xbee rx won't be executed. +A typical example where the command line blocks is the completion with +many choices. + solution -------- @@ -136,7 +139,6 @@ From highest to lowest priority. - Events, called from timer interrupt after a call to sei(): - LED_PRIO: led blink - - TIME_PRIO: monitor time - BEEP_PRIO: process beep requests and modifies the beep_mask - SPI_PRIO: send and receive SPI data to the atmega168p - CS_PRIO: do the control system of the wing, reading infos from a @@ -176,3 +178,49 @@ xbee_buf.[ch]: not used xbee_neighbor.[ch]: helper to add/delete neighbors, use malloc()/free() xbee_rxtx.[ch]: parse rx frames, provides xbee_proto_xmit() xbee_stats.[ch]: helper to maintain stats + +App +--- + +move this in library ? + +xbeeapp_send(addr, data, len, timeout, cb, arg) +XXX to detail + +Timeout for xbee commands +========================= + +- send_atcmd or send_msg (xbee_prio) + + - allocate a channel and a context + - fill the context with info + - send the message + - load a timeout (xbee_prio) + +- on timeout (xbee_prio) + + - log error + - call the cb with retcode == TIMEOUT + - unregister channel + - remove timer + - this could be a critical error + - if it's a comm error, it's ok + - but if the channel is registered again and 1st callback finally occurs... + +- on rx (xbee_prio) + + - if there is a context, it's related to a query: + - remove the timeout + - unregister channel + - do basic checks on the frame + - log (hexdump) + - the frame must be checked in the cb, we can provide helpers + + +Todo +==== + +- move callout in an aversive module +- move xbeeapp in xbee module + + diff --git a/rc_proto.c b/rc_proto.c index 56e8ad6..442eb90 100644 --- a/rc_proto.c +++ b/rc_proto.c @@ -52,12 +52,17 @@ struct rc_proto_power_levels { static struct rc_proto_power_levels power_levels[MAX_POWER_LEVEL]; /* update power level when we receive the answer from DB */ -static int update_power_level(void *frame, unsigned len, void *arg) +static int8_t update_power_level(int8_t retcode, void *frame, unsigned len, + void *arg) { struct xbee_atresp_hdr *atresp = (struct xbee_atresp_hdr *)frame; int level = (intptr_t)arg; uint8_t db; + /* nothing more to do, error is already logged by xbee_user */ + if (retcode < 0) + return retcode; + /* XXX check if this test is correct */ if (len < sizeof(struct xbee_atresp_hdr) + sizeof(uint8_t)) { /* XXX stats */ @@ -74,7 +79,7 @@ static int update_power_level(void *frame, unsigned len, void *arg) void rc_proto_rx_power_probe(int power_level) { (void)power_level; - xbeeapp_send_atcmd("DB", NULL, 0, 0, update_power_level, NULL); + xbeeapp_send_atcmd("DB", NULL, 0, update_power_level, NULL); } /* send a hello message */ @@ -92,7 +97,7 @@ int8_t rc_proto_send_hello(uint64_t addr, void *data, uint8_t data_len) msg.iov[1].buf = data; msg.iov[1].len = data_len; - return xbeeapp_send_msg(addr, &msg, 1); + return xbeeapp_send_msg(addr, &msg, NULL, NULL); } diff --git a/xbee_user.c b/xbee_user.c index 0d264b5..fca39b6 100644 --- a/xbee_user.c +++ b/xbee_user.c @@ -81,7 +81,7 @@ static void __hexdump(const void *buf, unsigned int len) LINE_LEN - out, PSTR("%c"), c); } - DEBUG(E_USER_XBEE, "%s"); + DEBUG(E_USER_XBEE, "%s", line); } } @@ -90,6 +90,7 @@ static void hexdump_msg(const char *title, const struct xbee_msg *msg) unsigned i; DEBUG(E_USER_XBEE, "dump %s", title); + for (i = 0; i < msg->iovlen; i++) { DEBUG(E_USER_XBEE, "iovec %d at %p, len=%d", i, msg->iov[i].buf, msg->iov[i].len); @@ -97,7 +98,7 @@ static void hexdump_msg(const char *title, const struct xbee_msg *msg) } } -static void hexdump(const char *title, const void *buf, unsigned int len) +void hexdump(const char *title, const void *buf, unsigned int len) { DEBUG(E_USER_XBEE, "dump %s at [%p], len=%d", title, buf, len); __hexdump(buf, len); @@ -113,7 +114,7 @@ static int parse_xmit_status(struct xbee_ctx *ctx, return -1; } - /* see if it matches a xmit query (atcmd_query must be NULL) */ + /* see if it matches a xmit query (atcmd_query must be \0) */ if (ctx->atcmd_query[0] != '\0') { ERROR(E_USER_XBEE, "invalid response 2"); return -1; @@ -134,18 +135,56 @@ static int parse_xmit_status(struct xbee_ctx *ctx, return 0; } -static int dump_atcmd(struct xbee_ctx *ctx, struct xbee_atresp_hdr *frame, - unsigned len) +/* Write in a human readable format the content of an atcmd response frame. It + * assumes the frame is valid .*/ +void atresp_to_str(char *buf, unsigned len, const struct xbee_atresp_hdr *frame) { - char atcmd_str[3]; - const struct xbee_atcmd *cmd_pgm; - struct xbee_atcmd cmd; union { uint8_t u8; uint16_t u16; uint32_t u32; int16_t s16; } __attribute__((packed)) *result; + char atcmd_str[3]; + const struct xbee_atcmd *cmd_pgm; + struct xbee_atcmd cmd; + + /* get AT command from frame */ + memcpy(atcmd_str, &frame->cmd, 2); + atcmd_str[2] = '\0'; + + /* see if it exists */ + cmd_pgm = xbee_atcmd_lookup_name(atcmd_str); + if (cmd_pgm == NULL) { + snprintf(buf, len, "<%s> (unknown cmd)", atcmd_str); + return; + } + memcpy_P(&cmd, cmd_pgm, sizeof(cmd)); + + /* dump frame */ + result = (void *)frame->data; + len -= offsetof(struct xbee_atresp_hdr, data); + if (cmd.flags & XBEE_ATCMD_F_PARAM_U8 && len == sizeof(uint8_t)) + snprintf(buf, len, "<%s> is 0x%x (%d)", atcmd_str, + result->u8, result->u8); + else if (cmd.flags & XBEE_ATCMD_F_PARAM_U16 && len == sizeof(uint16_t)) + snprintf(buf, len, "<%s> is 0x%x (%d)", atcmd_str, + ntohs(result->u16), ntohs(result->u16)); + else if (cmd.flags & XBEE_ATCMD_F_PARAM_U32 && len == sizeof(uint32_t)) + snprintf(buf, len, "<%s> is 0x%"PRIx32" (%"PRIu32")", + atcmd_str, ntohl(result->u32), ntohl(result->u32)); + else if (cmd.flags & XBEE_ATCMD_F_PARAM_S16 && len == sizeof(int16_t)) + snprintf(buf, len, "<%s> is %d", + atcmd_str, ntohs(result->s16)); + else if (len == 0) + snprintf(buf, len, "<%s> no data", atcmd_str); +} + +static int parse_atcmd(struct xbee_ctx *ctx, struct xbee_atresp_hdr *frame, + unsigned len) +{ + char atcmd_str[3]; + char buf[32]; if (ctx == NULL) { ERROR(E_USER_XBEE, "no context"); @@ -165,14 +204,6 @@ static int dump_atcmd(struct xbee_ctx *ctx, struct xbee_atresp_hdr *frame, return -1; } - /* see if it exists */ - cmd_pgm = xbee_atcmd_lookup_name(atcmd_str); - if (cmd_pgm == NULL) { - ERROR(E_USER_XBEE, "unknown response"); - return -1; - } - memcpy_P(&cmd, cmd_pgm, sizeof(cmd)); - /* bad status */ if (frame->status == 1) { WARNING(E_USER_XBEE, "Status is error"); @@ -192,28 +223,12 @@ static int dump_atcmd(struct xbee_ctx *ctx, struct xbee_atresp_hdr *frame, return -1; } - /* callback */ - if (ctx->func != NULL) - ctx->func(frame, len, ctx->arg); - - /* dump frame */ - result = (void *)frame->data; len -= offsetof(struct xbee_atresp_hdr, data); - if (cmd.flags & XBEE_ATCMD_F_PARAM_U8 && len == sizeof(uint8_t)) - NOTICE(E_USER_XBEE, "<%s> is 0x%x (%d)", atcmd_str, - result->u8, result->u8); - else if (cmd.flags & XBEE_ATCMD_F_PARAM_U16 && len == sizeof(uint16_t)) - NOTICE(E_USER_XBEE, "<%s> is 0x%x (%d)", atcmd_str, - ntohs(result->u16), ntohs(result->u16)); - else if (cmd.flags & XBEE_ATCMD_F_PARAM_U32 && len == sizeof(uint32_t)) - NOTICE(E_USER_XBEE, "<%s> is 0x%"PRIx32" (%"PRIu32")", - atcmd_str, ntohl(result->u32), ntohs(result->u32)); - else if (cmd.flags & XBEE_ATCMD_F_PARAM_S16 && len == sizeof(int16_t)) - NOTICE(E_USER_XBEE, "<%s> is %d", - atcmd_str, ntohs(result->s16)); - else if (len == 0) - NOTICE(E_USER_XBEE, "no data, status ok"); - else + + atresp_to_str(buf, sizeof(buf), frame); + NOTICE(E_USER_XBEE, "status ok, len=%d, %s", len, buf); + + if (len != 0) hexdump("atcmd answer", frame->data, len); return 0; @@ -246,21 +261,22 @@ int xbee_recv_data(struct xbee_recv_hdr *recvframe, unsigned len) spi_servo_set(0, val); break; } - case RC_PROTO_TYPE_RANGE: { - struct rc_proto_range *rcr = - (struct rc_proto_range *) recvframe->data; +#endif + case RC_PROTO_POWER_PROBE: { + struct rc_proto_power_probe *rcpb = + (struct rc_proto_power_probe *) recvframe->data; - if (datalen != sizeof(struct rc_proto_range)) + if (datalen != sizeof(*rcpb)) return -1; - if (rcr->power_level >= MAX_POWER_LEVEL) + if (rcpb->power_level >= MAX_POWER_LEVEL) return -1; - rc_proto_rx_range(rcr->power_level); + //rc_proto_rx_range(rcpb->power_level); break; } -#endif + case RC_PROTO_HELLO: { struct rc_proto_hello *rch = (struct rc_proto_hello *) recvframe->data; @@ -277,19 +293,18 @@ int xbee_recv_data(struct xbee_recv_hdr *recvframe, unsigned len) return 0; } -/* socat /dev/ttyUSB0,raw,echo=0,b115200 /dev/ttyACM1,raw,echo=0,b115200 */ +/* main rx entry point for application */ int8_t xbeeapp_rx(struct xbee_dev *dev, int channel, int type, void *frame, unsigned len, void *opaque) { struct xbee_ctx *ctx = opaque; - int8_t ret = 0; + int8_t ret = XBEE_USER_RETCODE_OK; NOTICE(E_USER_XBEE, "type=0x%x, channel=%d, ctx=%p", type, channel, ctx); /* if ctx is !NULL, it is an answer to a query */ if (ctx != NULL) { - /* XXX only delete timeout if answer matched */ xbee_unload_timeout(ctx); if (ctx->atcmd_query) NOTICE(E_USER_XBEE, "Received answer to query <%c%c>", @@ -318,32 +333,33 @@ int8_t xbeeapp_rx(struct xbee_dev *dev, int channel, int type, } addr; memcpy(&addr, frame, sizeof(addr)); addr.u64 = ntohll(addr.u64); - NOTICE(E_USER_XBEE, "from remote address %"PRIx32"%"PRIx32"", + NOTICE(E_USER_XBEE, + "from remote address %"PRIx32"%"PRIx32"", addr.u32.high, addr.u32.low); /* this answer contains an atcmd answer at offset 10 */ - if (dump_atcmd(ctx, frame + 10, len - 10) < 0) - ret = -1; + if (parse_atcmd(ctx, frame + 10, len - 10) < 0) + ret = XBEE_USER_RETCODE_BAD_FRAME; break; } case XBEE_TYPE_ATRESP: { - if (dump_atcmd(ctx, frame, len) < 0) - ret = -1; + if (parse_atcmd(ctx, frame, len) < 0) + ret = XBEE_USER_RETCODE_BAD_FRAME; break; } case XBEE_TYPE_XMIT_STATUS: { if (parse_xmit_status(ctx, frame, len) < 0) - ret = -1; + ret = XBEE_USER_RETCODE_BAD_FRAME; break; } case XBEE_TYPE_RECV: { if (xbee_recv_data(frame, len) < 0) - ret = -1; + ret = XBEE_USER_RETCODE_BAD_FRAME; break; } @@ -357,27 +373,27 @@ int8_t xbeeapp_rx(struct xbee_dev *dev, int channel, int type, case XBEE_TYPE_NODE_ID: default: ERROR(E_USER_XBEE, "Invalid frame"); - ret = -1; + ret = XBEE_USER_RETCODE_BAD_FRAME; break; } WARNING(E_USER_XBEE, "undecoded rx frame"); hexdump("undecoded rx frame", frame, len); - /* restart command line if it was a blocking query */ if (ctx != NULL) { + /* callback */ + if (ctx->rx_cb != NULL) + ret = ctx->rx_cb(ret, frame, len, ctx->arg); + + /* free channel now, it implicitely frees the context too */ xbee_unregister_channel(dev, channel); - if (ctx->foreground) { - xbee_stdin_enable(); - rdline_newline(&xbeeboard.rdl, xbeeboard.prompt); - } } return ret; } -static int xbeeapp_send(struct xbee_ctx *ctx, int type, struct xbee_msg *msg, - int foreground) +/* called with callout prio == XBEE_PRIO */ +static int xbeeapp_send(struct xbee_ctx *ctx, int type, struct xbee_msg *msg) { int ret; int channel; @@ -395,8 +411,7 @@ static int xbeeapp_send(struct xbee_ctx *ctx, int type, struct xbee_msg *msg, ctx = &xbee_ctx[channel]; xbee_set_opaque(xbee_dev, channel, ctx); - NOTICE(E_USER_XBEE, "send frame channel=%d type=0x%x", - channel, type); + NOTICE(E_USER_XBEE, "send frame channel=%d type=0x%x", channel, type); hexdump_msg("xmit frame", msg); /* transmit the frame on this channel */ @@ -410,21 +425,13 @@ static int xbeeapp_send(struct xbee_ctx *ctx, int type, struct xbee_msg *msg, ctx->channel = channel; xbee_load_timeout(ctx); /* load a timeout event */ - /* suspend command line until we have answer or timeout */ - if (foreground) { - ctx->foreground = 1; - rdline_stop(&xbeeboard.rdl); /* don't display prompt when return */ - xbee_stdin_disable(); /* unload file descriptor polling */ - } - return 0; } -/* 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(char *atcmd_str, void *param, - unsigned param_len, int foreground, - int (*func)(void *frame, unsigned len, void *arg), void *arg) +/* send an AT command with parameters filled by caller. param is the argument + * of the atcmd (if any). */ +int xbeeapp_send_atcmd(char *atcmd_str, void *param, unsigned param_len, + xbee_user_rx_cb_t *rx_cb, void *arg) { struct xbee_ctx ctx; /* struct xbee_atcmd_hdr atcmd_hdr; -> no needed same than atcmd_str */ @@ -435,7 +442,7 @@ int xbeeapp_send_atcmd(char *atcmd_str, void *param, memset(&ctx, 0, sizeof(ctx)); ctx.atcmd_query[0] = atcmd_str[0]; ctx.atcmd_query[1] = atcmd_str[1]; - ctx.func = func; + ctx.rx_cb = rx_cb; ctx.arg = arg; msg.iovlen = 2; @@ -445,13 +452,16 @@ int xbeeapp_send_atcmd(char *atcmd_str, void *param, msg.iov[1].len = param_len; prio = callout_mgr_set_prio(&xbeeboard.intr_cm, XBEE_PRIO); - ret = xbeeapp_send(&ctx, XBEE_TYPE_ATCMD, &msg, foreground); + if (prio > XBEE_PRIO) + ERROR(E_USER_XBEE, "invalid prio = %d\n", prio); + ret = xbeeapp_send(&ctx, XBEE_TYPE_ATCMD, &msg); callout_mgr_restore_prio(&xbeeboard.intr_cm, prio); return ret; } -int xbeeapp_send_msg(uint64_t addr, struct xbee_msg *msg, int foreground) +int xbeeapp_send_msg(uint64_t addr, struct xbee_msg *msg, + xbee_user_rx_cb_t *rx_cb, void *arg) { struct xbee_ctx ctx; struct xbee_xmit_hdr xmit_hdr; @@ -465,7 +475,6 @@ int xbeeapp_send_msg(uint64_t addr, struct xbee_msg *msg, int foreground) return -1; } - xmit_hdr.dstaddr = htonll(addr); xmit_hdr.reserved = htons(0xFFFE); xmit_hdr.bcast_radius = 0; @@ -478,10 +487,13 @@ int xbeeapp_send_msg(uint64_t addr, struct xbee_msg *msg, int foreground) msg2.iov[i+1] = msg->iov[i]; memset(&ctx, 0, sizeof(ctx)); - ctx.atcmd_query[0] = '\0'; + ctx.rx_cb = rx_cb; + ctx.arg = arg; prio = callout_mgr_set_prio(&xbeeboard.intr_cm, XBEE_PRIO); - ret = xbeeapp_send(&ctx, XBEE_TYPE_XMIT, &msg2, foreground); + if (prio > XBEE_PRIO) + ERROR(E_USER_XBEE, "invalid prio = %d\n", prio); + ret = xbeeapp_send(&ctx, XBEE_TYPE_XMIT, &msg2); callout_mgr_restore_prio(&xbeeboard.intr_cm, prio); return ret; @@ -497,13 +509,12 @@ static void evt_timeout(struct callout_mgr *cm, struct callout *clt, WARNING(E_USER_XBEE, "Timeout"); - /* restart command line */ - xbee_stdin_enable(); - rdline_newline(&xbeeboard.rdl, xbeeboard.prompt); + /* callback */ + if (ctx->rx_cb != NULL) + ctx->rx_cb(XBEE_USER_RETCODE_TIMEOUT, NULL, 0, ctx->arg); - /* free event */ + /* free channel, it implicitely frees the context too */ xbee_unregister_channel(xbee_dev, ctx->channel); - callout_stop(cm, clt); } diff --git a/xbee_user.h b/xbee_user.h index cfb2ea8..e2bc926 100644 --- a/xbee_user.h +++ b/xbee_user.h @@ -31,12 +31,19 @@ #include #include +#define XBEE_USER_RETCODE_OK 0 +#define XBEE_USER_RETCODE_BAD_FRAME 1 +#define XBEE_USER_RETCODE_TIMEOUT 2 + +/* called when we receive an answer to a query */ +typedef int8_t (xbee_user_rx_cb_t)(int8_t code, void *frame, + unsigned len, void *arg); + /* used for timeouts and xbee rx callback */ struct xbee_ctx { - int foreground; int channel; - char atcmd_query[2]; - int (*func)(void *frame, unsigned len, void *arg); + char atcmd_query[2]; /* 00 is it's data */ + xbee_user_rx_cb_t *rx_cb; void *arg; struct callout timeout; }; @@ -54,6 +61,10 @@ struct xbeeapp_pkt { unsigned tailroom; }; +/* Write in a human readable format the content of an atcmd response frame. It + * assumes the frame is valid .*/ +void atresp_to_str(char *buf, unsigned len, const struct xbee_atresp_hdr *frame); + /* 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); @@ -61,12 +72,11 @@ int8_t xbeeapp_rx(struct xbee_dev *dev, int channel, int type, /* 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); + unsigned param_len, xbee_user_rx_cb_t *rx_cb, void *arg); /* send a message to a peer */ -int xbeeapp_send_msg(uint64_t addr, struct xbee_msg *msg, int foreground); +int xbeeapp_send_msg(uint64_t addr, struct xbee_msg *msg, + xbee_user_rx_cb_t *rx_cb, void *arg); void xbee_stdin_enable(void); void xbee_stdin_disable(void); -- 2.20.1