1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

net: l2_ping uses radio_packet_t instead of packet_info_t

This commit is contained in:
Oleg Hahm 2014-05-22 23:24:28 +02:00
parent c692b3a00a
commit 4a93a261b4
4 changed files with 333 additions and 92 deletions

View File

@ -80,6 +80,10 @@ ifneq (,$(filter at86rf231,$(USEMODULE)))
USEMODULE += ieee802154
endif
ifneq (,$(filter l2_ping,$(USEMODULE)))
USEMODULE += vtimer
endif
ifneq (,$(filter vtimer,$(USEMODULE)))
USEMODULE += timex
endif

143
sys/net/include/l2_ping.h Normal file
View File

@ -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 <oliver.hahm@inria.fr>
*/
#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 */

View File

@ -1,31 +0,0 @@
/**
* @defgroup sys_ping Ping
* @ingroup sys
* @brief Ping
*/
#include "radio/radio.h"
#define RCV_BUFFER_SIZE (64)
#define RADIO_STACK_SIZE (KERNEL_CONF_STACKSIZE_DEFAULT)
#define PING_PAYLOAD (8)
typedef enum {
L2_PING,
L2_PONG
} l2_ping_type_t;
void ping_init(void);
void ping(radio_address_t addr);
typedef struct pong {
int hopcount;
int ttl;
radio_address_t radio_address;
} ping_r;
typedef struct ping_payload {
uint8_t type;
char payload[PING_PAYLOAD];
} ping_payload;

View File

@ -1,80 +1,144 @@
/**
* Ping: low level ping pong
*
/*
* Copyright (C) 2013, Igor Merkulow <igor.merkulow@gmail.com>
* Copyright (C) 2014, Oliver Hahm <oliver.hahm@inria.fr>
*
* This file is subject to the terms and conditions of the GNU Lesser General
* Public License. See the file LICENSE in the top level directory for more
* details.
* Public License v2.1. See the file LICENSE in the top level directory for
* more details.
*/
/**
* @file
* @author Igor Merkulow <igor.merkulow@gmail.com>
* @author Oliver Hahm <oliver.hahm@inria.fr>
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "thread.h"
#include "msg.h"
#include "mutex.h"
#include "transceiver.h"
#include "radio/types.h"
#include "vtimer.h"
#include "timex.h"
#include "ping.h"
#include "l2_ping.h"
static void send_l2_packet(radio_address_t dst, l2_ping_type_t type);
static void pong(radio_address_t src);
static void *pkt_handler(void *unused);
static void ping_handler(packet_info_t *packet_info);
#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);
static void print_success(void);
static void print_failed(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);
char radio_stack_buffer[RADIO_STACK_SIZE];
msg_t msg_q[RCV_BUFFER_SIZE];
/* internal buffers and variables */
static char l2_pkt_handler_stack_buffer[RADIO_STACK_SIZE];
static msg_t msg_q[RCV_BUFFER_SIZE];
ping_payload pipa;
timex_t start;
float rtt = 0;
#ifndef DISABLE_PROB_STATS
static l2_probe_stat_entry_t probe_stats[MAX_PROB_STATS];
#endif
void ping_handler(packet_info_t *packet_info)
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)
{
pong(packet_info->phy_src);
}
void ping_init(void)
{
kernel_pid_t radio_pid = thread_create(radio_stack_buffer,
RADIO_STACK_SIZE, PRIORITY_MAIN - 2,
CREATE_STACKTEST, pkt_handler, NULL,
"l2_ping_handler");
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();
transceiver_register(transceivers, radio_pid);
#endif
transceiver_register(transceivers, l2_pkt_handler_pid);
}
void ping(radio_address_t addr)
void l2_ping(radio_address_t addr, uint16_t count, uint32_t interval,
const char *payload, uint8_t payload_len, uint8_t probe_only)
{
while (1) {
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);
send_l2_packet(addr, L2_PING);
vtimer_usleep(500 * 1000);
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);
}
static void pkt_handler(void)
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));
@ -82,15 +146,38 @@ static void pkt_handler(void)
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) {
puts("Transceiver buffer full");
DEBUGF("ERROR: Transceiver buffer full\n");
}
else {
puts("Unknown packet received");
DEBUGF("ERROR: Unknown messagereceived\n");
}
}
@ -99,40 +186,42 @@ static void pkt_handler(void)
static void calc_rtt(void)
{
timex_t end;
vtimer_now(&end);
timex_t result = timex_sub(end, start);
timex_t rtt = timex_sub(end, start);
rtt_sum = timex_add(rtt_sum, rtt);
rtt = result.seconds + (float)result.microseconds / (1000.0 * 1000.0);
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 void print_success(void)
{
printf("%s%f%s\n", "time=", rtt, "ms");
}
static void print_failed(void)
{
printf("%s\n", "ping failed");
}
static void pong(radio_address_t src)
{
send_l2_packet(src, L2_PONG);
}
static void send_l2_packet(radio_address_t dst, l2_ping_type_t type)
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;
pipa.type = type;
pp.type = type | L2_PAYLOAD_PING;
pp.seq = seq;
p.data = (uint8_t*) &pipa;
p.length = sizeof(pipa);
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;
@ -143,12 +232,48 @@ static void send_l2_packet(radio_address_t dst, l2_ping_type_t type)
int8_t response = mesg.content.value;
if (response <= 0) {
print_failed();
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)
{
calc_rtt();
print_success();
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
}