diff --git a/Makefile.dep b/Makefile.dep index 62f4eb5f4..85076fee2 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -90,6 +90,10 @@ ifneq (,$(filter at86rf231,$(USEMODULE))) USEMODULE += ieee802154 endif +ifneq (,$(filter l2_ping,$(USEMODULE))) + USEMODULE += vtimer +endif + ifneq (,$(filter vtimer,$(USEMODULE))) USEMODULE += timex endif diff --git a/sys/Makefile b/sys/Makefile index 6e12c3770..246190413 100644 --- a/sys/Makefile +++ b/sys/Makefile @@ -13,6 +13,9 @@ endif ifneq (,$(filter net_if,$(USEMODULE))) DIRS += net/link_layer/net_if endif +ifneq (,$(filter l2_ping,$(USEMODULE))) + DIRS += net/link_layer/ping +endif ifneq (,$(filter transport_layer,$(USEMODULE))) USEMODULE += udp USEMODULE += tcp diff --git a/sys/Makefile.include b/sys/Makefile.include index f8e258699..e974bb582 100644 --- a/sys/Makefile.include +++ b/sys/Makefile.include @@ -41,6 +41,9 @@ endif ifneq (,$(filter ieee802154,$(USEMODULE))) USEMODULE_INCLUDES += $(RIOTBASE)/sys/net/include endif +ifneq (,$(filter l2_ping,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/sys/net/include +endif ifneq (,$(filter ccn_lite,$(USEMODULE))) USEMODULE_INCLUDES += $(RIOTBASE)/sys/net/include USEMODULE_INCLUDES += $(RIOTBASE)/sys/net/ccn_lite diff --git a/sys/auto_init/auto_init.c b/sys/auto_init/auto_init.c index 3c1943d9c..9d2d7bfbb 100644 --- a/sys/auto_init/auto_init.c +++ b/sys/auto_init/auto_init.c @@ -78,6 +78,10 @@ #include "periph/cpuid.h" #endif +#ifdef MODULE_L2_PING +#include "l2_ping.h" +#endif + #define ENABLE_DEBUG (0) #if ENABLE_DEBUG #define DEBUG_ENABLED @@ -237,6 +241,10 @@ void auto_init(void) DEBUG("Auto init mci module.\n"); MCI_initialize(); #endif +#ifdef MODULE_L2_PING + DEBUG("Auto init net_if module.\n"); + l2_ping_init(); +#endif #ifdef MODULE_NET_IF DEBUG("Auto init net_if module.\n"); auto_init_net_if(); diff --git a/sys/include/ping.h b/sys/include/ping.h deleted file mode 100644 index a6ec62319..000000000 --- a/sys/include/ping.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2010 Freie Universität Berlin - * - * This file is subject to the terms and conditions of the GNU Lesser - * General Public License v2.1. See the file LICENSE in the top level - * directory for more details. - */ - - -/** - * @defgroup sys_ping Ping - * @ingroup sys - * @brief Ping - */ - -#include "radio/radio.h" - -#ifdef __cplusplus -extern "C" { -#endif - -void init_payload(void); -void ping_init(protocol_t protocol, uint8_t channr, radio_address_t addr); -void ping(radio_address_t addr, uint8_t channr); -void calc_rtt(void); -void print_success(void); -void print_failed(void); -void gpio_n_timer_init(void); -void adjust_timer(void); -static void ping_handler(void *payload, int payload_size, - packet_info_t *packet_info); -static void pong_handler(void *payload, int payload_size, - packet_info_t *packet_info); -void pong(uint16_t src); - -typedef struct pong { - int hopcount; - int ttl; - radio_address_t radio_address; -} ping_r; - -typedef struct ping_payload { - char *payload; -} ping_payload; - -#ifdef __cplusplus -} -#endif diff --git a/sys/net/include/l2_ping.h b/sys/net/include/l2_ping.h new file mode 100644 index 000000000..89f080736 --- /dev/null +++ b/sys/net/include/l2_ping.h @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2014, INRIA + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License v2.1. See the file LICENSE in the top level directory for + * more details. + */ + +#ifndef L2_PING_H +#define L2_PING_H + +/** + * @defgroup net_l2_ping Link Layer Ping + * @ingroup net + * @brief Link Layer Ping + * + * @{ + * @file + * @brief Link Layer Ping public interface, data structs, and defines + * + * @author Oliver Hahm + */ + +#include "radio/radio.h" + +#ifdef __cplusplus + extern "C" { +#endif + +/** + * @brief the bitmask of the first link layer payload byte defining the type + */ +#define L2_PAYLOAD_TYPE (0xF0) + +/** + * @brief link layer payload type + * + * @note assure not to interfere with valid network layer values like the + * 6LoWPAN dispatch field + */ +#define L2_PAYLOAD_PING (0x10) + +/** + * @brief the bitmask for the payload identifier, defining the actual l2 ping type + * + * @see l2_ping_type_t + */ +#define L2_PING_TYPE (0x0F) + +/** + * @brief the default interval between two ping packets are sent in microseconds + */ +#define L2_PING_DEFAULT_INTERVAL (50 * 1000u) + +/** + * @brief maximum number of bytes for payload within a l2 ping packet + */ +#define L2_PING_PAYLOAD_SIZE (8) + +/** + * @brief data type for the l2 ping type + */ +typedef enum { + L2_PING = 0x01, /**< ping request packet */ + L2_PONG = 0x02, /**< pong response packet */ + L2_PROBE = 0x04 /**< probe packet */ +} l2_ping_type_t; + +/** + * @brief l2 ping statistics data structure + */ +typedef struct { + radio_address_t dst; /**< the destination address for the last ping request sent */ + uint16_t ping_count; /**< the amount of ping requests sent to this destination */ + uint16_t pong_count; /**< the amount of pong respnses received from this node */ + timex_t last_rtt; /**< the round trip time for the last received pong response */ + timex_t avg_rtt; /**< the average round trip time to this node */ + timex_t max_rtt; /**< the maximum round trip time to this node */ + timex_t min_rtt; /**< the minimum round trip time to this node */ +} l2_ping_stats_t; + +/** + * @brief l2 probe statistics entry + */ +typedef struct { + radio_address_t src; /**< link layer address of the probe's origin */ + uint16_t count; /**< number of received probes from this node */ +} l2_probe_stat_entry_t; + +/** + * @brief payload data structure for l2 ping packets + */ +typedef struct ping_payload { + uint8_t type; /**< the data type */ + uint16_t seq; /**< sequence number */ + /* cppcheck-suppress unusedStructMember */ + char payload[L2_PING_PAYLOAD_SIZE]; /**< the actual payload */ + uint8_t payload_len; /**< number of payload bytes */ +} l2_ping_payload_t; + +/** + * @brief the current l2 ping statistics about the current communication + * partner + */ +extern l2_ping_stats_t l2_ping_stats; + +/** + * @brief initializes the l2 ping module + * + * @note this function gets usually called by auto_init + */ +void l2_ping_init(void); + +/** + * @brief send a ping request + * + * @param[in] addr the destination address + * @param[in] count the number of requests to send, 0 means infinite + * @param[in] interval the interval between sending ping requests, + * if 0 the default interval (#L2_PING_DEFAULT_INTERVAL) + * @param[in] payload optional payload data, may be NULL + * @param[in] payload_len the length of the payload data, must be smaller than + * #L2_PING_PAYLOAD_SIZE + * @param[in] probe_only do not request a pong response + */ +void l2_ping(radio_address_t addr, uint16_t count, uint32_t interval, + const char *payload, uint8_t payload_len, uint8_t probe_only); + +/** + * @brief get l2 probe statistics to check how many probes have been received + * + * @param[out] l2_probe_stats pointer to an array of ::l2_probe_stat_entry_t + * @param[out] count pointer to the number of entries in l2_probe_stats + */ +void l2_probe_stats(l2_probe_stat_entry_t *l2_probe_stats[], uint16_t *count); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* L2_PING_H */ diff --git a/sys/ping/Makefile b/sys/net/link_layer/ping/Makefile similarity index 64% rename from sys/ping/Makefile rename to sys/net/link_layer/ping/Makefile index 48422e909..9e5ec0eac 100644 --- a/sys/ping/Makefile +++ b/sys/net/link_layer/ping/Makefile @@ -1 +1,3 @@ +MODULE := l2_ping + include $(RIOTBASE)/Makefile.base diff --git a/sys/net/link_layer/ping/ping.c b/sys/net/link_layer/ping/ping.c new file mode 100644 index 000000000..06989764a --- /dev/null +++ b/sys/net/link_layer/ping/ping.c @@ -0,0 +1,279 @@ +/* + * Copyright (C) 2013, Igor Merkulow + * Copyright (C) 2014, Oliver Hahm + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License v2.1. See the file LICENSE in the top level directory for + * more details. + */ + +/** + * @file + * @author Igor Merkulow + * @author Oliver Hahm + * + */ + +#include +#include +#include + +#include "thread.h" +#include "msg.h" +#include "mutex.h" + +#include "transceiver.h" +#include "radio/types.h" +#include "vtimer.h" +#include "timex.h" +#include "l2_ping.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +/*--------------------------------------------------------------------------------------*/ +/* interal defines */ +#define RCV_BUFFER_SIZE (64) +#define RADIO_STACK_SIZE (KERNEL_CONF_STACKSIZE_DEFAULT) +#define MAX_PROB_STATS (64) + +/* internal prototypes */ +/* link layer send function for l2_pings */ +static int8_t send_l2_packet(radio_address_t dst, l2_ping_type_t type, uint16_t seq, const char *payload, uint8_t payload_len); +/* handler for incoming packets from transceiver */ +static void *l2_pkt_handler(void *unused); +/* handles l2 ping requests */ +static void ping_handler(radio_address_t addr, uint16_t seq); +/* handles l2 pong responses */ +static void pong_handler(void); +/* handle l2 probes */ +static void probe_handler(radio_address_t src); +/* calculates the round trip time for a ping-pong exchange */ +static void calc_rtt(void); + +/* internal buffers and variables */ +static char l2_pkt_handler_stack_buffer[RADIO_STACK_SIZE]; +static msg_t msg_q[RCV_BUFFER_SIZE]; + +#ifndef DISABLE_PROB_STATS +static l2_probe_stat_entry_t probe_stats[MAX_PROB_STATS]; +#endif + +static timex_t start, end, rtt_sum; +static uint8_t ping_sent; +static struct mutex_t ping_sender_mutex; +l2_ping_stats_t l2_ping_stats; + +/*--------------------------------------------------------------------------------------*/ +/* public interface functions */ +void l2_ping_init(void) +{ + mutex_init(&ping_sender_mutex); + kernel_pid_t l2_pkt_handler_pid = thread_create(l2_pkt_handler_stack_buffer, + RADIO_STACK_SIZE, + PRIORITY_MAIN - 2, + CREATE_STACKTEST, + l2_pkt_handler, NULL, + "l2_pkt_handler"); + uint16_t transceivers = TRANSCEIVER_DEFAULT; + +#ifndef MODULE_NET_IF + transceiver_init(transceivers); + (void) transceiver_start(); +#endif + transceiver_register(transceivers, l2_pkt_handler_pid); +} + +void l2_ping(radio_address_t addr, uint16_t count, uint32_t interval, + const char *payload, uint8_t payload_len, uint8_t probe_only) +{ + l2_ping_type_t pt; + + probe_only ? (pt = L2_PROBE) : (pt = L2_PING); + + if (!interval) { + interval = L2_PING_DEFAULT_INTERVAL; + } + + mutex_lock(&ping_sender_mutex); + l2_ping_stats.dst = addr; + l2_ping_stats.ping_count = 0; + l2_ping_stats.pong_count = 0; + l2_ping_stats.last_rtt = timex_set(0, 0); + l2_ping_stats.avg_rtt = timex_set(0, 0); + l2_ping_stats.max_rtt = timex_set(0, 0); + l2_ping_stats.min_rtt = timex_set(UINT32_MAX, UINT32_MAX); + + for (unsigned i = 1; (count == 0) || (i <= count); i++) { + vtimer_now(&start); + + if (send_l2_packet(addr, pt, i, payload, payload_len)) { + ping_sent = 1; + l2_ping_stats.ping_count++; + } + if ((!count) || (i <= count)) { + vtimer_usleep(interval); + } + } + mutex_unlock(&ping_sender_mutex); +} + +void l2_probe_stats(l2_probe_stat_entry_t *l2_probe_stats[], uint16_t *count) +{ + unsigned i; + *l2_probe_stats = probe_stats; + for (i = 0; i < MAX_PROB_STATS; i++) { + if (!(probe_stats[i]).src) { + break; + } + } + *count = i; +} + +/*--------------------------------------------------------------------------------------*/ +/* internal functions */ +static void *l2_pkt_handler(void *unused) +{ + (void) unused; + + msg_t m; + radio_packet_t *p; + l2_ping_payload_t *pp; + + msg_init_queue(msg_q, sizeof(msg_q)); + + while (1) { + msg_receive(&m); + + if (m.type == PKT_PENDING) { + vtimer_now(&end); + p = (radio_packet_t *) m.content.ptr; + pp = (l2_ping_payload_t *) p->data; + + if ((pp->type & L2_PAYLOAD_TYPE) == L2_PAYLOAD_PING) { + DEBUGF("INFO: received l2_ping_packet number %d from %d with payload(%d) %.*s.\n", + pp->seq, p->src, pp->payload_len, pp->payload_len, pp->payload); + switch (pp->type & L2_PING_TYPE) { + case L2_PING: + ping_handler(p->src, pp->seq); + break; + case L2_PONG: + pong_handler(); + break; + case L2_PROBE: + probe_handler(p->src); + break; + default: + DEBUGF("ERROR: Unknown L2 PING type\n"); + } + } + else { + DEBUGF("WARN: no L2 ping packet, type is %02X\n", pp->type); + } + + p->processing--; + } + else if (m.type == ENOBUFFER) { + DEBUGF("ERROR: Transceiver buffer full\n"); + } + else { + DEBUGF("ERROR: Unknown messagereceived\n"); + } + } + + return NULL; +} + +static void calc_rtt(void) +{ + timex_t rtt = timex_sub(end, start); + rtt_sum = timex_add(rtt_sum, rtt); + + l2_ping_stats.last_rtt = rtt; + l2_ping_stats.avg_rtt = timex_from_uint64(timex_uint64(rtt_sum) / l2_ping_stats.pong_count); + if (timex_cmp(rtt, l2_ping_stats.max_rtt) > 0) { + l2_ping_stats.max_rtt = rtt; + } + if (timex_cmp(rtt, l2_ping_stats.min_rtt) < 0) { + l2_ping_stats.min_rtt = rtt; + } +} + +static int8_t send_l2_packet(radio_address_t dst, l2_ping_type_t type, uint16_t seq, const char *payload, uint8_t payload_len) +{ + radio_packet_t p; + l2_ping_payload_t pp; + + if (payload_len > L2_PING_PAYLOAD_SIZE) { + DEBUGF("ERROR: payload too big for l2 ping packet of type %u\n", type); + return -1; + } + + transceiver_command_t tcmd; + tcmd.transceivers = TRANSCEIVER_DEFAULT; + tcmd.data = &p; + + pp.type = type | L2_PAYLOAD_PING; + pp.seq = seq; + + memset(pp.payload, 0, L2_PING_PAYLOAD_SIZE); + memcpy(pp.payload, payload, payload_len); + pp.payload_len = payload_len; + + p.data = (uint8_t*) &pp; + p.length = sizeof(pp); + p.dst = dst; + + msg_t mesg; + mesg.type = SND_PKT; + mesg.content.ptr = (char *) &tcmd; + + msg_send_receive(&mesg, &mesg, transceiver_pid); + int8_t response = mesg.content.value; + + if (response <= 0) { + DEBUGF("ERROR: sending L2 packet of type %x failed.\n", type); + } + + return response; +} + +static void ping_handler(radio_address_t addr, uint16_t seq) +{ + send_l2_packet(addr, L2_PONG, seq, NULL, 0); +} + +static void pong_handler(void) +{ + if (ping_sent) { + ping_sent = 0; + l2_ping_stats.pong_count++; + calc_rtt(); + } + else { + DEBUGF("ERROR: received pong without a sent ping\n"); + } +} + +static void probe_handler(radio_address_t src) +{ +#ifdef DISABLE_PROB_STATS + DEBUGF("WARN: L2 probe statistics are disabled, not handling probe packet.\n"); +#else + unsigned i; + for (i = 0; i < MAX_PROB_STATS; i++) { + /* found entry for this source address */ + if (probe_stats[i].src == src) { + probe_stats[i].count++; + return; + } + /* found empty entry */ + else if (!(probe_stats[i].src)) { + probe_stats[i].src = src; + probe_stats[i].count++; + return; + } + } + DEBUGF("ERROR: L2 probe statistics full! Probe data from %u not stored.\n", src); +#endif +} diff --git a/sys/ping/ping.c b/sys/ping/ping.c deleted file mode 100644 index 8c486a0c7..000000000 --- a/sys/ping/ping.c +++ /dev/null @@ -1,111 +0,0 @@ -/** - * Ping: low level ping pong - * - * Copyright (C) 2013, Igor Merkulow - * - * This file is subject to the terms and conditions of the GNU Lesser - * General Public License v2.1. See the file LICENSE in the top level - * directory for more details. - */ - -/** - * @file - * @author Igor Merkulow - * - */ - -#include -#include -#include "thread.h" -#include "msg.h" - -#include "cc110x_legacy_csma/cc1100.h" -#include "lpc2387.h" - -#include "vtimer.h" -#include "timex.h" -#include "gpioint.h" -#include "ping.h" - -ping_payload *pipa; -protocol_t protocol_id = 0; -radio_address_t r_address = 0; -timex_t start = 0; -float rtt = 0; - -void ping_handler(void *payload, int payload_size, - packet_info_t *packet_info) -{ - pong(packet_info->phy_src); -} - -void pong_handler(void *payload, int payload_size, - packet_info_t *packet_info) -{ - calc_rtt(); - print_success(); -} - -void pong(uint16_t src) -{ - int trans_ok = cc1100_send_csmaca(src, protocol_id, 2, pipa->payload, - sizeof(pipa->payload)); - - if (trans_ok < 0) { - print_failed(); - } -} - -void ping_init(protocol_t protocol, uint8_t channr, radio_address_t addr) -{ - protocol_id = protocol; - r_address = addr; - cc1100_set_packet_handler(protocol, ping_handler); - cc1100_set_channel(channr); - cc1100_set_address(r_address); - init_payload(); -} - -void ping(radio_address_t addr, uint8_t channr) -{ - cc1100_set_packet_handler(protocol_id, pong_handler); - cc1100_set_channel(channr); - cc1100_set_address(r_address); - - while (1) { - vtimer_now(&start); - int trans_ok = cc1100_send_csmaca(addr, - protocol_id, 2, pipa->payload, sizeof(pipa->payload)); - - if (trans_ok < 0) { - print_failed(); - } - - hwtimer_wait(HWTIMER_TICKS(500 * 1000)); - } -} - -void calc_rtt(void) -{ - timex_t end; - vtimer_now(&end); - timex_t result = timex_sub(end, start); - - rtt = result.seconds + (float)result.microseconds / (1000.0 * 1000.0); -} - -void print_success(void) -{ - printf("%s%f%s\n", "time=", rtt, "ms"); -} - -void print_failed(void) -{ - printf("%s\n", "ping failed"); -} - -void init_payload(void) -{ - pipa = malloc(sizeof(*pipa)); - pipa->payload = NULL; -} diff --git a/sys/shell/commands/Makefile b/sys/shell/commands/Makefile index 49dd87cc8..798ac5257 100644 --- a/sys/shell/commands/Makefile +++ b/sys/shell/commands/Makefile @@ -13,6 +13,9 @@ ifneq (,$(filter cc110x_legacy_csma,$(USEMODULE))) SRC += sc_cc110x_legacy_csma.c endif endif +ifneq (,$(filter l2_ping,$(USEMODULE))) + SRC += sc_l2_ping.c +endif ifneq (,$(filter net_if,$(USEMODULE))) SRC += sc_net_if.c endif diff --git a/sys/shell/commands/sc_l2_ping.c b/sys/shell/commands/sc_l2_ping.c new file mode 100644 index 000000000..4d0120308 --- /dev/null +++ b/sys/shell/commands/sc_l2_ping.c @@ -0,0 +1,144 @@ +/* + * Shell commands for l2_ping module + * + * Copyright (C) 2014, INRIA + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License v2.1. See the file LICENSE in the top level directory for + * more details. + * + * @ingroup shell_commands + * @{ + * @file + * @brief provides shell commands use link layer ping functionality + * @author Oliver Hahm + * @} + */ + +#include +#include +#include + +#include "l2_ping.h" +#include "transceiver.h" +#include "timex.h" +#include "vtimer.h" + +void _l2_ping_req_handler(int argc, char **argv) +{ + size_t payload_strlen; + uint16_t count = 5; + timex_t start, end, period; + + if (transceiver_pid == KERNEL_PID_UNDEF) { + puts("Transceiver not initialized"); + return; + } + if (argc < 2) { + printf("Usage:\t%s [COUNT] [MSG]\n", argv[0]); + return; + } + + char l2_payload[L2_PING_PAYLOAD_SIZE]; + if (argc > 3) { + payload_strlen = strlen(argv[3]); + if (payload_strlen > L2_PING_PAYLOAD_SIZE) { + printf("[l2_ping] Your input is too long and will be truncated to \"%.*s\".\n", L2_PING_PAYLOAD_SIZE, argv[3]); + payload_strlen = L2_PING_PAYLOAD_SIZE; + } + memset(l2_payload, 0, L2_PING_PAYLOAD_SIZE); + strncpy(l2_payload, argv[3], payload_strlen); + } + else { + payload_strlen = 0; + } + + if (argc > 2) { + count = atoi(argv[2]); + } + + printf("[l2_ping] Send %" PRIu8 " ping requests to %" PRIu16 " with interval %" PRIu32 ".%" PRIu32 "s and payload %s\n", + count, atoi(argv[1]), + timex_from_uint64(L2_PING_DEFAULT_INTERVAL).seconds, + timex_from_uint64(L2_PING_DEFAULT_INTERVAL).microseconds, + (argc > 3) ? l2_payload : "NULL"); + vtimer_now(&start); + l2_ping((radio_address_t) atoi(argv[1]), count, L2_PING_DEFAULT_INTERVAL, + l2_payload, payload_strlen, 0); + vtimer_now(&end); + period = timex_sub(end, start); + + printf(" --- ping statistics for host %" PRIu16 " ---\n", l2_ping_stats.dst); + printf(" %" PRIu16 " packets transmitted, %" PRIu16 " received, %" PRIu16 "%% packet loss, time %" PRIu32 ".%06" PRIu32 "s\n", + l2_ping_stats.ping_count, + l2_ping_stats.pong_count, + 100 - ((l2_ping_stats.pong_count * 100) / l2_ping_stats.ping_count), + period.seconds, + period.microseconds); + printf(" rtt min/avg/max = %" PRIu32 ".%06" PRIu32 "/%" PRIu32 ".%06" PRIu32 "/%" PRIu32 ".%06" PRIu32 " s\n", + l2_ping_stats.min_rtt.seconds, l2_ping_stats.min_rtt.microseconds, + l2_ping_stats.avg_rtt.seconds, l2_ping_stats.avg_rtt.microseconds, + l2_ping_stats.max_rtt.seconds, l2_ping_stats.max_rtt.microseconds); +} + +void _l2_ping_probe_handler(int argc, char **argv) +{ + size_t payload_strlen; + uint16_t count = 5; + timex_t start, end, period; + + if (transceiver_pid == KERNEL_PID_UNDEF) { + puts("Transceiver not initialized"); + return; + } + if (argc < 2) { + printf("Usage:\t%s [COUNT] [MSG]\n", argv[0]); + return; + } + + char l2_payload[L2_PING_PAYLOAD_SIZE]; + if (argc > 3) { + payload_strlen = strlen(argv[3]); + if (payload_strlen > L2_PING_PAYLOAD_SIZE) { + printf("[l2_ping] Your input is too long and will be truncated to \"%.*s\".\n", L2_PING_PAYLOAD_SIZE, argv[3]); + payload_strlen = L2_PING_PAYLOAD_SIZE; + } + memset(l2_payload, 0, L2_PING_PAYLOAD_SIZE); + strncpy(l2_payload, argv[3], payload_strlen); + } + else { + payload_strlen = 0; + } + + if (argc > 2) { + count = atoi(argv[2]); + } + + printf("[l2_ping] Send %" PRIu16 " probes to %" PRIu16 " with interval %u and payload %s\n", + count, atoi(argv[1]), L2_PING_DEFAULT_INTERVAL, (argc > 3) ? l2_payload : "NULL"); + vtimer_now(&start); + l2_ping((radio_address_t) atoi(argv[1]), count, L2_PING_DEFAULT_INTERVAL, + l2_payload, payload_strlen, 1); + vtimer_now(&end); + period = timex_sub(end, start); + + printf(" --- ping statistics for host %" PRIu16 " ---\n", l2_ping_stats.dst); + printf(" %" PRIu16 " packets transmitted in %" PRIu32 ".%06" PRIu32 "s\n", l2_ping_stats.ping_count, + period.seconds, period.microseconds); +} + +void _l2_ping_get_probe_handler(int argc, char **argv) +{ + (void) argc; + (void) argv; + + l2_probe_stat_entry_t *stats; + uint16_t count; + + l2_probe_stats(&stats, &count); + + printf("[l2_ping] Getting link layer probe statistics:\n"); + for (uint16_t i = 0; i < count; i++) { + printf("...received %" PRIu16 " probes from node %" PRIu16 ".\n", stats[i].count, stats[i].src); + } +} diff --git a/sys/shell/commands/shell_commands.c b/sys/shell/commands/shell_commands.c index 695529564..90f381aa8 100644 --- a/sys/shell/commands/shell_commands.c +++ b/sys/shell/commands/shell_commands.c @@ -124,6 +124,12 @@ extern void _transceiver_set_ignore_handler(int argc, char **argv); #endif #endif +#ifdef MODULE_L2_PING +extern void _l2_ping_req_handler(int argc, char **argv); +extern void _l2_ping_probe_handler(int argc, char **argv); +extern void _l2_ping_get_probe_handler(int argc, char **argv); +#endif + #ifdef MODULE_NET_IF extern void _net_if_ifconfig(int argc, char **argv); #endif @@ -213,6 +219,11 @@ const shell_command_t _shell_command_list[] = { {"chan", "Gets or sets the channel for the CC1100 transceiver", _cc110x_get_set_channel_handler}, #endif #endif +#ifdef MODULE_L2_PING + {"l2_ping", "Sends link layer ping requests", _l2_ping_req_handler}, + {"l2_probe", "Sends link layer probes", _l2_ping_probe_handler}, + {"l2_probe_stats", "Get statistics about received probes", _l2_ping_get_probe_handler}, +#endif #ifdef MODULE_NET_IF {"ifconfig", "Configures a network interface", _net_if_ifconfig}, #endif