
6 changed files with 587 additions and 0 deletions
@ -0,0 +1,38 @@
|
||||
APPLICATION = emb6
|
||||
|
||||
FEATURES_REQUIRED = periph_gpio periph_spi # for at86rf231
|
||||
|
||||
BOARD ?= samr21-xpro
|
||||
|
||||
RIOTBASE ?= $(CURDIR)/../..
|
||||
|
||||
BOARD_INSUFFICIENT_MEMORY := msb-430h stm32f0discovery weio z1
|
||||
|
||||
USEMODULE += emb6_router
|
||||
USEMODULE += emb6_conn_udp
|
||||
USEMODULE += ipv6_addr
|
||||
USEMODULE += shell
|
||||
USEMODULE += shell_commands
|
||||
USEMODULE += ps
|
||||
USEMODULE += od
|
||||
|
||||
# define the driver to be used for selected boards
|
||||
ifneq (,$(filter samr21-xpro,$(BOARD))) |
||||
DRIVER := at86rf233
|
||||
endif |
||||
ifneq (,$(filter iotlab-m3 fox,$(BOARD))) |
||||
DRIVER := at86rf231
|
||||
endif |
||||
ifneq (,$(filter mulle,$(BOARD))) |
||||
DRIVER := at86rf212b
|
||||
endif |
||||
|
||||
# use the at86rf231 as fallback device
|
||||
DRIVER ?= at86rf231
|
||||
|
||||
# include the selected driver
|
||||
USEMODULE += $(DRIVER)
|
||||
|
||||
QUIET ?= 1
|
||||
|
||||
include $(RIOTBASE)/Makefile.include |
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) 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. |
||||
*/ |
||||
|
||||
/**
|
||||
* @{ |
||||
* |
||||
* @file |
||||
* @author Martine Lenders <mlenders@inf.fu-berlin.de> |
||||
*/ |
||||
|
||||
#include <stdbool.h> |
||||
|
||||
#include "common.h" |
||||
|
||||
size_t hex2ints(uint8_t *out, const char *in) |
||||
{ |
||||
bool upper = true; |
||||
size_t out_size = 0; |
||||
|
||||
while (*in != '\0') { |
||||
char c; |
||||
if ((*in >= '0') && (*in <= '9')) { |
||||
c = '0'; |
||||
} |
||||
else if ((*in >= 'a') && (*in <= 'f')) { |
||||
c = 'a' - 10; |
||||
} |
||||
else if ((*in >= 'A') && (*in <= 'F')) { |
||||
c = 'A' - 10; |
||||
} |
||||
else { |
||||
in++; |
||||
continue; |
||||
} |
||||
if (upper) { |
||||
*out = (char)(*in - c) << 4; |
||||
} |
||||
else { |
||||
*out |= (char)(*in - c); |
||||
out++; |
||||
out_size++; |
||||
} |
||||
upper = !upper; |
||||
in++; |
||||
} |
||||
if (!upper) { |
||||
out_size++; |
||||
} |
||||
return out_size; |
||||
} |
||||
|
||||
/** @} */ |
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Martine Lenders <mlenders@inf.fu-berlin.de> |
||||
* |
||||
* 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 tests |
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief Definitions for tests/lwip/ |
||||
* |
||||
* @author Martine Lenders <mlenders@inf.fu-berlin.de> |
||||
*/ |
||||
#ifndef MAIN_H_ |
||||
#define MAIN_H_ |
||||
|
||||
#include <stdint.h> |
||||
#include <sys/types.h> |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief Application configuration |
||||
* @{ |
||||
*/ |
||||
#define CONN_INBUF_SIZE (256) |
||||
#define SERVER_MSG_QUEUE_SIZE (8) |
||||
#define SERVER_BUFFER_SIZE (64) |
||||
/**
|
||||
* @} |
||||
*/ |
||||
|
||||
/**
|
||||
* @brief Converts hex string to byte array. |
||||
* |
||||
* @param[out] out Resulting byte array |
||||
* @param[in] in `\0` terminated string. Non-hex characters (all except 0-9, a-f, A-F) |
||||
* will be ignored. |
||||
* |
||||
* @return Length of @p out. |
||||
*/ |
||||
size_t hex2ints(uint8_t *out, const char *in); |
||||
|
||||
/**
|
||||
* @brief Ping shell command |
||||
* |
||||
* @param[in] argc number of arguments |
||||
* @param[in] argv array of arguments |
||||
* |
||||
* @return 0 on success |
||||
* @return other on error |
||||
*/ |
||||
int ping_cmd(int argc, char **argv); |
||||
|
||||
#ifdef MODULE_CONN_UDP |
||||
/**
|
||||
* @brief UDP IP shell command |
||||
* |
||||
* @param[in] argc number of arguments |
||||
* @param[in] argv array of arguments |
||||
* |
||||
* @return 0 on success |
||||
* @return other on error |
||||
*/ |
||||
int udp_cmd(int argc, char **argv); |
||||
#endif |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif /* MAIN_H_ */ |
||||
/** @} */ |
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Martine Lenders <mlenders@inf.fu-berlin.de> |
||||
* |
||||
* 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 examples |
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief Test for raw IPv6 connections |
||||
* |
||||
* @author Martine Lenders <mlenders@inf.fu-berlin.de> |
||||
* |
||||
* This test application tests the gnrc_conn_ip module. If you select protocol 58 you can also |
||||
* test if gnrc is able to deal with multiple subscribers to ICMPv6 (gnrc_icmpv6 and this |
||||
* application). |
||||
* |
||||
* @} |
||||
*/ |
||||
|
||||
#include <errno.h> |
||||
#include <stdio.h> |
||||
|
||||
#include "at86rf2xx.h" |
||||
#include "at86rf2xx_params.h" |
||||
#include "common.h" |
||||
#include "emb6.h" |
||||
#include "emb6/netdev2.h" |
||||
#include "uip-ds6.h" |
||||
#include "net/ipv6/addr.h" |
||||
#include "shell.h" |
||||
#include "thread.h" |
||||
#include "xtimer.h" |
||||
|
||||
#define EMB6_STACKSIZE (THREAD_STACKSIZE_DEFAULT) |
||||
#define EMB6_PRIO (THREAD_PRIORITY_MAIN - 3) |
||||
#define EMB6_DELAY (500) |
||||
|
||||
static at86rf2xx_t at86rf2xx; |
||||
static s_ns_t emb6 = { |
||||
.hc = &sicslowpan_driver, |
||||
.llsec = &nullsec_driver, |
||||
.hmac = &nullmac_driver, |
||||
.lmac = &sicslowmac_driver, |
||||
.frame = &framer_802154, |
||||
.c_configured = 1, |
||||
}; |
||||
static char emb6_stack[EMB6_STACKSIZE]; |
||||
|
||||
static int ifconfig(int argc, char **argv) |
||||
{ |
||||
(void)argc; |
||||
(void)argv; |
||||
char addrstr[IPV6_ADDR_MAX_STR_LEN]; |
||||
printf("0: "); |
||||
for (int i = 0; i < UIP_DS6_ADDR_NB; i++) { |
||||
if (uip_ds6_if.addr_list[i].isused) { |
||||
printf("inet6 %s\n", |
||||
ipv6_addr_to_str(addrstr, |
||||
(ipv6_addr_t *)&uip_ds6_if.addr_list[i].ipaddr, |
||||
sizeof(addrstr))); |
||||
if (i != 0) { |
||||
printf(" "); |
||||
} |
||||
} |
||||
} |
||||
puts(""); |
||||
return 0; |
||||
} |
||||
|
||||
static void *_emb6_thread(void *args) |
||||
{ |
||||
emb6_process(500); /* never stops */ |
||||
return NULL; |
||||
} |
||||
|
||||
static const shell_command_t shell_commands[] = { |
||||
{ "ping6", "Send pings and receive pongs", ping_cmd }, |
||||
#ifdef MODULE_CONN_UDP |
||||
{ "udp", "Send UDP messages and listen for messages on UDP port", udp_cmd }, |
||||
#endif |
||||
{ "ifconfig", "Shows assigned IPv6 addresses", ifconfig }, |
||||
{ NULL, NULL, NULL } |
||||
}; |
||||
static char line_buf[SHELL_DEFAULT_BUFSIZE]; |
||||
|
||||
char conn_inbuf[CONN_INBUF_SIZE]; |
||||
|
||||
int main(void) |
||||
{ |
||||
netdev2_t *netdev = (netdev2_t *)&at86rf2xx; |
||||
|
||||
puts("RIOT lwip test application"); |
||||
|
||||
at86rf2xx_setup(&at86rf2xx, at86rf2xx_params); |
||||
netdev->driver->init((netdev2_t *)&at86rf2xx); |
||||
emb6_netdev2_setup(netdev); |
||||
emb6_init(&emb6); |
||||
thread_create(emb6_stack, sizeof(emb6_stack), EMB6_PRIO, |
||||
THREAD_CREATE_STACKTEST, _emb6_thread, NULL, "emb6"); |
||||
shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE); |
||||
|
||||
/* should be never reached */ |
||||
return 0; |
||||
} |
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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. |
||||
*/ |
||||
|
||||
/**
|
||||
* @ingroup examples |
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief Demonstrating the sending and receiving of UDP data over POSIX sockets. |
||||
* |
||||
* @author Martine Lenders <mlenders@inf.fu-berlin.de> |
||||
* |
||||
* @} |
||||
*/ |
||||
|
||||
#include <stdbool.h> |
||||
#include <inttypes.h> |
||||
#include <stdio.h> |
||||
|
||||
#include "atomic.h" |
||||
#include "byteorder.h" |
||||
#include "net/icmpv6.h" |
||||
#include "net/ipv6.h" |
||||
#include "xtimer.h" |
||||
|
||||
#include "uip.h" |
||||
#include "uip-icmp6.h" |
||||
|
||||
#include "common.h" |
||||
|
||||
#define ECHO_ID (0xd1e9) |
||||
|
||||
static struct uip_icmp6_echo_reply_notification recv_ntfy = { NULL, NULL }; |
||||
static uint16_t seq = 0; |
||||
static atomic_int_t received, num; |
||||
|
||||
static bool _waiting = true; |
||||
|
||||
static inline icmpv6_echo_t *uip_icmp_buf(void) |
||||
{ |
||||
return ((icmpv6_echo_t *)&uip_buf[uip_l2_l3_hdr_len]); |
||||
} |
||||
|
||||
static inline int max_len(void) |
||||
{ |
||||
return UIP_BUFSIZE - (((uint8_t *)uip_icmp_buf()) - uip_buf) - |
||||
sizeof(icmpv6_echo_t); |
||||
} |
||||
|
||||
static int ping_send(const uip_ipaddr_t *dst, int payload_len) |
||||
{ |
||||
int len = payload_len; |
||||
icmpv6_echo_t *ping = uip_icmp_buf(); |
||||
|
||||
ping->id = byteorder_htons(ECHO_ID); |
||||
|
||||
if (payload_len > max_len()) { |
||||
puts("Payload too long for buffer."); |
||||
return -1; |
||||
} |
||||
|
||||
for (network_uint16_t *payload = (network_uint16_t *)(ping + 1); |
||||
len >= 0; |
||||
payload++, len -= 2) { |
||||
*payload = byteorder_htons(seq); |
||||
} |
||||
|
||||
ping->seq = byteorder_htons(seq++); |
||||
|
||||
uip_icmp6_send((const uip_ipaddr_t *)dst, ICMPV6_ECHO_REQ, 0, |
||||
payload_len + (sizeof(icmpv6_echo_t) - sizeof(icmpv6_hdr_t))); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static void handle_reply(uip_ipaddr_t *source, uint8_t ttl, uint8_t *data, |
||||
uint16_t datalen) |
||||
{ |
||||
char addr_str[IPV6_ADDR_MAX_STR_LEN]; |
||||
icmpv6_echo_t *ping = (icmpv6_echo_t *)data; |
||||
|
||||
_waiting = false; |
||||
|
||||
ipv6_addr_to_str(addr_str, (ipv6_addr_t *)source, sizeof(addr_str)); |
||||
|
||||
atomic_inc(&received); |
||||
printf("%" PRIu16 " bytes from %s: icmp_seq=%" PRIu16 " ttl=%u quota=%i/%i\n", |
||||
datalen, addr_str, byteorder_ntohs(ping->seq), (unsigned)ttl, |
||||
ATOMIC_VALUE(received), ATOMIC_VALUE(num)); |
||||
} |
||||
|
||||
void usage(char *cmd) |
||||
{ |
||||
printf("usage: %s <dst> [<num>] [<payload_len>]\n", cmd); |
||||
} |
||||
|
||||
int ping_cmd(int argc, char **argv) |
||||
{ |
||||
ipv6_addr_t dst; |
||||
int payload_len, _num; |
||||
|
||||
if ((argc < 2) || (ipv6_addr_from_str(&dst, argv[1]) == NULL)) { |
||||
usage(argv[0]); |
||||
return 1; |
||||
} |
||||
if ((argc < 3) || ((_num = atoi(argv[2])) == 0)) { |
||||
_num = 3; |
||||
} |
||||
if ((argc < 4) || ((payload_len = atoi(argv[3])) == 0)) { |
||||
payload_len = 16; |
||||
} |
||||
atomic_set_to_zero(&num); |
||||
atomic_cas(&num, 0, _num); |
||||
atomic_set_to_zero(&received); |
||||
seq = 0; |
||||
if (recv_ntfy.callback == NULL) { |
||||
uip_icmp6_echo_reply_callback_add(&recv_ntfy, handle_reply); |
||||
} |
||||
for (uint16_t i = 0; i < _num; i++) { |
||||
_waiting = true; |
||||
ping_send((uip_ipaddr_t *)&dst, payload_len); |
||||
xtimer_usleep(1000000); |
||||
if (_waiting) { |
||||
puts("Timeout"); |
||||
} |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
/** @} */ |
@ -0,0 +1,168 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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. |
||||
*/ |
||||
|
||||
/**
|
||||
* @ingroup examples |
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief Demonstrating the sending and receiving of UDP data over POSIX sockets. |
||||
* |
||||
* @author Martine Lenders <mlenders@inf.fu-berlin.de> |
||||
* |
||||
* @} |
||||
*/ |
||||
|
||||
#include <stdbool.h> |
||||
#include <stdint.h> |
||||
#include <stdio.h> |
||||
|
||||
#include "common.h" |
||||
#include "od.h" |
||||
#include "net/af.h" |
||||
#include "net/conn/udp.h" |
||||
#include "net/ipv6.h" |
||||
#include "thread.h" |
||||
#include "xtimer.h" |
||||
|
||||
#ifdef MODULE_CONN_UDP |
||||
static char conn_inbuf[CONN_INBUF_SIZE]; |
||||
static bool server_running; |
||||
static conn_udp_t server_conn; |
||||
static char server_stack[THREAD_STACKSIZE_DEFAULT]; |
||||
static msg_t server_msg_queue[SERVER_MSG_QUEUE_SIZE]; |
||||
|
||||
static void *_server_thread(void *args) |
||||
{ |
||||
ipv6_addr_t server_addr = IPV6_ADDR_UNSPECIFIED; |
||||
uint16_t port; |
||||
int res; |
||||
|
||||
msg_init_queue(server_msg_queue, SERVER_MSG_QUEUE_SIZE); |
||||
/* parse port */ |
||||
port = (uint16_t)atoi((char *)args); |
||||
if ((res = conn_udp_create(&server_conn, &server_addr, |
||||
sizeof(server_addr), AF_INET6, port)) < 0) { |
||||
printf("Unable to open UDP server on port %" PRIu16 " (error code %d)\n", |
||||
port, -res); |
||||
return NULL; |
||||
} |
||||
server_running = true; |
||||
printf("Success: started UDP server on port %" PRIu16 "\n", port); |
||||
while (1) { |
||||
int res; |
||||
ipv6_addr_t src; |
||||
size_t src_len = sizeof(ipv6_addr_t); |
||||
uint16_t sport; |
||||
if ((res = conn_udp_recvfrom(&server_conn, conn_inbuf, sizeof(conn_inbuf), &src, |
||||
&src_len, &sport)) < 0) { |
||||
puts("Error on receive"); |
||||
} |
||||
else if (res == 0) { |
||||
puts("No data received"); |
||||
} |
||||
else { |
||||
char addrstr[IPV6_ADDR_MAX_STR_LEN]; |
||||
printf("Received from [%s]:%" PRIu16 ":\n", ipv6_addr_to_str(addrstr, &src, |
||||
sizeof(addrstr)), sport); |
||||
od_hex_dump(conn_inbuf, res, 0); |
||||
} |
||||
} |
||||
return NULL; |
||||
} |
||||
|
||||
static int udp_send(char *addr_str, char *port_str, char *data, unsigned int num, |
||||
unsigned int delay) |
||||
{ |
||||
ipv6_addr_t src = IPV6_ADDR_UNSPECIFIED, dst; |
||||
uint16_t port; |
||||
uint8_t byte_data[strlen(data) / 2]; |
||||
size_t data_len; |
||||
|
||||
/* parse destination address */ |
||||
if (ipv6_addr_from_str(&dst, addr_str) == NULL) { |
||||
puts("Error: unable to parse destination address"); |
||||
return 1; |
||||
} |
||||
/* parse port */ |
||||
port = (uint16_t)atoi(port_str); |
||||
data_len = hex2ints(byte_data, data); |
||||
for (unsigned int i = 0; i < num; i++) { |
||||
if (conn_udp_sendto(byte_data, data_len, &src, sizeof(src), (struct sockaddr *)&dst, |
||||
sizeof(dst), AF_INET6, port, port) < 0) { |
||||
puts("could not send"); |
||||
} |
||||
else { |
||||
printf("Success: send %u byte to [%s]:%" PRIu16 ")\n", |
||||
(unsigned)data_len, addr_str, port); |
||||
} |
||||
xtimer_usleep(delay); |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
static int udp_start_server(char *port_str) |
||||
{ |
||||
if (thread_create(server_stack, sizeof(server_stack), THREAD_PRIORITY_MAIN - 1, |
||||
THREAD_CREATE_STACKTEST, _server_thread, port_str, |
||||
"UDP server") <= KERNEL_PID_UNDEF) { |
||||
return 1; |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
int udp_cmd(int argc, char **argv) |
||||
{ |
||||
if (argc < 2) { |
||||
printf("usage: %s [send|server]\n", argv[0]); |
||||
return 1; |
||||
} |
||||
|
||||
if (strcmp(argv[1], "send") == 0) { |
||||
uint32_t num = 1; |
||||
uint32_t delay = 1000000; |
||||
if (argc < 5) { |
||||
printf("usage: %s send <addr> <port> <hex data> [<num> [<delay in us>]]\n", |
||||
argv[0]); |
||||
return 1; |
||||
} |
||||
if (argc > 5) { |
||||
num = (uint32_t)atoi(argv[5]); |
||||
} |
||||
if (argc > 6) { |
||||
delay = (uint32_t)atoi(argv[6]); |
||||
} |
||||
return udp_send(argv[2], argv[3], argv[4], num, delay); |
||||
} |
||||
else if (strcmp(argv[1], "server") == 0) { |
||||
if (argc < 3) { |
||||
printf("usage: %s server [start|stop]\n", argv[0]); |
||||
return 1; |
||||
} |
||||
if (strcmp(argv[2], "start") == 0) { |
||||
if (argc < 4) { |
||||
printf("usage %s server start <port>\n", argv[0]); |
||||
return 1; |
||||
} |
||||
return udp_start_server(argv[3]); |
||||
} |
||||
else { |
||||
puts("error: invalid command"); |
||||
return 1; |
||||
} |
||||
} |
||||
else { |
||||
puts("error: invalid command"); |
||||
return 1; |
||||
} |
||||
} |
||||
#else |
||||
typedef int dont_be_pedantic; |
||||
#endif |
||||
|
||||
/** @} */ |
Loading…
Reference in new issue