mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
Merge pull request #7428 from haukepetersen/add_rdcli
net: add full CoRE Resource Directory endpoint implementation
This commit is contained in:
commit
1095ac2487
15
Makefile.dep
15
Makefile.dep
@ -768,6 +768,21 @@ ifneq (,$(filter rdcli_simple,$(USEMODULE)))
|
|||||||
USEMODULE += fmt
|
USEMODULE += fmt
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifneq (,$(filter rdcli_standalone,$(USEMODULE)))
|
||||||
|
USEMODULE += rdcli
|
||||||
|
USEMODULE += xtimer
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq (,$(filter rdcli,$(USEMODULE)))
|
||||||
|
USEMODULE += rdcli_common
|
||||||
|
USEMODULE += core_thread_flags
|
||||||
|
USEMODULE += gcoap
|
||||||
|
USEMODULE += fmt
|
||||||
|
ifneq (,$(filter shell_commands,$(USEMODULE)))
|
||||||
|
USEMODULE += sock_util
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
ifneq (,$(filter rdcli_common,$(USEMODULE)))
|
ifneq (,$(filter rdcli_common,$(USEMODULE)))
|
||||||
USEMODULE += fmt
|
USEMODULE += fmt
|
||||||
USEMODULE += gcoap
|
USEMODULE += gcoap
|
||||||
|
40
examples/rdcli/Makefile
Normal file
40
examples/rdcli/Makefile
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
# name of your application
|
||||||
|
APPLICATION = rdcli
|
||||||
|
|
||||||
|
# If no BOARD is found in the environment, use this default:
|
||||||
|
BOARD ?= native
|
||||||
|
|
||||||
|
# This has to be the absolute path to the RIOT base directory:
|
||||||
|
RIOTBASE ?= $(CURDIR)/../..
|
||||||
|
|
||||||
|
BOARD_INSUFFICIENT_MEMORY := arduino-duemilanove arduino-mega2560 arduino-uno \
|
||||||
|
chronos hifive1 mega-xplained msb-430 msb-430h \
|
||||||
|
nucleo-f030r8 nucleo-l053r8 nucleo-f031k6 \
|
||||||
|
nucleo-f042k6 nucleo-f303k8 nucleo-f334r8 \
|
||||||
|
nucleo-l031k6 stm32f0discovery telosb waspmote-pro \
|
||||||
|
wsn430-v1_3b wsn430-v1_4 z1
|
||||||
|
|
||||||
|
USEMODULE += gnrc_netdev_default
|
||||||
|
USEMODULE += auto_init_gnrc_netif
|
||||||
|
USEMODULE += gnrc_ipv6_default
|
||||||
|
USEMODULE += gnrc_icmpv6_echo
|
||||||
|
|
||||||
|
USEMODULE += rdcli_standalone
|
||||||
|
|
||||||
|
USEMODULE += shell
|
||||||
|
USEMODULE += shell_commands
|
||||||
|
USEMODULE += ps
|
||||||
|
USEMODULE += fmt
|
||||||
|
|
||||||
|
# Comment this out to disable code in RIOT that does safety checking
|
||||||
|
# which is not needed in a production environment but helps in the
|
||||||
|
# development process:
|
||||||
|
CFLAGS += -DDEVELHELP
|
||||||
|
|
||||||
|
# For debugging and demonstration purposes, we limit the lifetime to 60s
|
||||||
|
CFLAGS += -DRDCLI_LT=60
|
||||||
|
|
||||||
|
# Change this to 0 show compiler invocation lines by default:
|
||||||
|
QUIET ?= 1
|
||||||
|
|
||||||
|
include $(RIOTBASE)/Makefile.include
|
20
examples/rdcli/README.md
Normal file
20
examples/rdcli/README.md
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
CoRE Resource Directory Client Example
|
||||||
|
======================================
|
||||||
|
This example application demonstrates the usage of RIOT's Resource Directory
|
||||||
|
(RD) client module, called `rdcli`. This module supports the registration,
|
||||||
|
update, and removal processes as defined in the
|
||||||
|
[Resource Directory Draft](https://tools.ietf.org/html/draft-ietf-core-resource-directory-14).
|
||||||
|
|
||||||
|
Usage
|
||||||
|
=====
|
||||||
|
The examples includes a shell command that you can use to interact with a given
|
||||||
|
RD server, called `rdcli`. Simply use that shell command without parameters for
|
||||||
|
more information on its usage.
|
||||||
|
|
||||||
|
Some connection parameters are configured statically during compile time,
|
||||||
|
namely the lifetime (`RDCLI_LT`) and the node's endpoint name (`RDCLI_EP`). You
|
||||||
|
can change these values during command line by overriding these values in the
|
||||||
|
application's Makefile, e.g. add
|
||||||
|
```
|
||||||
|
CFLAGS += "-DRDCLI_EP=\"MyNewEpName\""
|
||||||
|
```
|
108
examples/rdcli/main.c
Normal file
108
examples/rdcli/main.c
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017-2018 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 CoRE Resource Directory client (rdcli) example application
|
||||||
|
*
|
||||||
|
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||||
|
*
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "fmt.h"
|
||||||
|
#include "shell.h"
|
||||||
|
#include "net/ipv6/addr.h"
|
||||||
|
#include "net/gcoap.h"
|
||||||
|
#include "net/rdcli_common.h"
|
||||||
|
#include "net/rdcli_standalone.h"
|
||||||
|
|
||||||
|
#define MAIN_QUEUE_SIZE (8)
|
||||||
|
static msg_t _main_msg_queue[MAIN_QUEUE_SIZE];
|
||||||
|
|
||||||
|
/* we will use a custom event handler for dumping rdcli_standalone events */
|
||||||
|
static void _on_rdcli_event(rdcli_standalone_event_t event)
|
||||||
|
{
|
||||||
|
switch (event) {
|
||||||
|
case RDCLI_REGISTERED:
|
||||||
|
puts("rdcli event: now registered with a RD");
|
||||||
|
break;
|
||||||
|
case RDCLI_DEREGISTERED:
|
||||||
|
puts("rdcli event: dropped client registration");
|
||||||
|
break;
|
||||||
|
case RDCLI_UPDATED:
|
||||||
|
puts("rdcli event: successfully updated client registration");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* define some dummy CoAP resources */
|
||||||
|
static ssize_t _handler_dummy(coap_pkt_t *pdu,
|
||||||
|
uint8_t *buf, size_t len, void *ctx)
|
||||||
|
{
|
||||||
|
(void)ctx;
|
||||||
|
|
||||||
|
/* get random data */
|
||||||
|
int16_t val = 23;
|
||||||
|
|
||||||
|
gcoap_resp_init(pdu, buf, len, COAP_CODE_CONTENT);
|
||||||
|
size_t plen = fmt_s16_dec((char *)pdu->payload, val);
|
||||||
|
return gcoap_finish(pdu, plen, COAP_FORMAT_TEXT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t _handler_info(coap_pkt_t *pdu,
|
||||||
|
uint8_t *buf, size_t len, void *ctx)
|
||||||
|
{
|
||||||
|
(void)ctx;
|
||||||
|
|
||||||
|
gcoap_resp_init(pdu, buf, len, COAP_CODE_CONTENT);
|
||||||
|
size_t slen = sizeof("SOME NODE INFOMRATION");
|
||||||
|
memcpy(pdu->payload, "SOME NODE INFOMRATION", slen);
|
||||||
|
return gcoap_finish(pdu, slen, COAP_FORMAT_TEXT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const coap_resource_t _resources[] = {
|
||||||
|
{ "/node/info", COAP_GET, _handler_info, NULL },
|
||||||
|
{ "/sense/hum", COAP_GET, _handler_dummy, NULL },
|
||||||
|
{ "/sense/temp", COAP_GET, _handler_dummy, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
static gcoap_listener_t _listener = {
|
||||||
|
.resources = (coap_resource_t *)&_resources[0],
|
||||||
|
.resources_len = sizeof(_resources) / sizeof(_resources[0]),
|
||||||
|
.next = NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
/* we need a message queue for the thread running the shell in order to
|
||||||
|
* receive potentially fast incoming networking packets */
|
||||||
|
msg_init_queue(_main_msg_queue, MAIN_QUEUE_SIZE);
|
||||||
|
|
||||||
|
puts("CoRE RD client example!\n");
|
||||||
|
|
||||||
|
/* setup CoAP resources */
|
||||||
|
gcoap_register_listener(&_listener);
|
||||||
|
|
||||||
|
/* register event callback with rdcli_standalone */
|
||||||
|
rdcli_standalone_reg_cb(_on_rdcli_event);
|
||||||
|
|
||||||
|
puts("Client information:");
|
||||||
|
printf(" ep: %s\n", rdcli_common_get_ep());
|
||||||
|
printf(" lt: %is\n", (int)RDCLI_LT);
|
||||||
|
|
||||||
|
char line_buf[SHELL_DEFAULT_BUFSIZE];
|
||||||
|
shell_run(NULL, line_buf, SHELL_DEFAULT_BUFSIZE);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -65,6 +65,7 @@ PSEUDOMODULES += pktqueue
|
|||||||
PSEUDOMODULES += printf_float
|
PSEUDOMODULES += printf_float
|
||||||
PSEUDOMODULES += prng
|
PSEUDOMODULES += prng
|
||||||
PSEUDOMODULES += prng_%
|
PSEUDOMODULES += prng_%
|
||||||
|
PSEUDOMODULES += rdcli_standalone
|
||||||
PSEUDOMODULES += rdcli_simple_standalone
|
PSEUDOMODULES += rdcli_simple_standalone
|
||||||
PSEUDOMODULES += saul_adc
|
PSEUDOMODULES += saul_adc
|
||||||
PSEUDOMODULES += saul_default
|
PSEUDOMODULES += saul_default
|
||||||
|
@ -133,6 +133,10 @@ endif
|
|||||||
ifneq (,$(filter rdcli_simple,$(USEMODULE)))
|
ifneq (,$(filter rdcli_simple,$(USEMODULE)))
|
||||||
DIRS += net/application_layer/rdcli_simple
|
DIRS += net/application_layer/rdcli_simple
|
||||||
endif
|
endif
|
||||||
|
ifneq (,$(filter rdcli,$(USEMODULE)))
|
||||||
|
DIRS += net/application_layer/rdcli
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
DIRS += $(dir $(wildcard $(addsuffix /Makefile, $(USEMODULE))))
|
DIRS += $(dir $(wildcard $(addsuffix /Makefile, $(USEMODULE))))
|
||||||
|
|
||||||
|
@ -163,6 +163,11 @@ void auto_init(void)
|
|||||||
extern void rdcli_common_init(void);
|
extern void rdcli_common_init(void);
|
||||||
rdcli_common_init();
|
rdcli_common_init();
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef MODULE_RDCLI_STANDALONE
|
||||||
|
DEBUG("Auto init rdcli_standalone\n");
|
||||||
|
extern void rdcli_standalone_run(void);
|
||||||
|
rdcli_standalone_run();
|
||||||
|
#endif
|
||||||
#ifdef MODULE_RDCLI_SIMPLE_STANDALONE
|
#ifdef MODULE_RDCLI_SIMPLE_STANDALONE
|
||||||
DEBUG("Auto init rdcli_simple module\n");
|
DEBUG("Auto init rdcli_simple module\n");
|
||||||
extern void rdcli_simple_run(void);
|
extern void rdcli_simple_run(void);
|
||||||
|
123
sys/include/net/rdcli.h
Normal file
123
sys/include/net/rdcli.h
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017-2018 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 net_rdcli CoRE RD Endpoint Library
|
||||||
|
* @ingroup net
|
||||||
|
* @brief Library for using RIOT as CoRE Resource Directory endpoint
|
||||||
|
*
|
||||||
|
* This module implements a CoRE Resource Directory endpoint library, that
|
||||||
|
* allows RIOT nodes to register themselves with resource directories.
|
||||||
|
* It implements the standard endpoint functionality as defined in
|
||||||
|
* draft-ietf-core-resource-directory-15.
|
||||||
|
* @see https://tools.ietf.org/html/draft-ietf-core-resource-directory-15
|
||||||
|
*
|
||||||
|
* @note As the name of this library (`rdcli`) can be misleading in
|
||||||
|
* context of the RD draft (endpoint vs client), this library
|
||||||
|
* will most likely undergo a name change in the near future...
|
||||||
|
*
|
||||||
|
* # Design Decisions
|
||||||
|
* - all operations provided by this module are fully synchronous, meaning that
|
||||||
|
* the functions will block until an operation is successful or will time out
|
||||||
|
* - the implementation limits the client to be registered with a single RD at
|
||||||
|
* any point in time
|
||||||
|
*
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
* @brief CoRE Resource Directory endpoint interface
|
||||||
|
*
|
||||||
|
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef NET_RDCLI_H
|
||||||
|
#define NET_RDCLI_H
|
||||||
|
|
||||||
|
#include "net/sock/udp.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return values and error codes used by this module
|
||||||
|
*/
|
||||||
|
enum {
|
||||||
|
RDCLI_OK = 0, /**< everything went as expected */
|
||||||
|
RDCLI_TIMEOUT = -1, /**< no response from the network */
|
||||||
|
RDCLI_ERR = -2, /**< internal error or invalid reply */
|
||||||
|
RDCLI_NORD = -3, /**< not connected to an RD */
|
||||||
|
RDCLI_OVERFLOW = -4, /**< internal buffers can not handle input */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Discover the registration interface resource of a RD
|
||||||
|
*
|
||||||
|
* @param[in] remote remote endpoint of the target RD
|
||||||
|
* @param[out] regif the registration interface is written to this buffer
|
||||||
|
* @param[in] maxlen size of @p regif
|
||||||
|
*
|
||||||
|
* @return RDCLI_OK on success
|
||||||
|
* @return RDCLI_TIMEOUT if the discovery request times out
|
||||||
|
* @return RDCLI_NORD if addressed endpoint is not a RD
|
||||||
|
* @return RDCLI_ERR on any other internal error
|
||||||
|
*/
|
||||||
|
int rdcli_discover_regif(const sock_udp_ep_t *remote,
|
||||||
|
char *regif, size_t maxlen);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initiate the node registration by sending an empty push
|
||||||
|
*
|
||||||
|
* - if registration fails (e.g. timeout), we are not associated with any RD
|
||||||
|
* anymore (even if we have been before we called rdcli_register)
|
||||||
|
*
|
||||||
|
* @note In case a multicast address is given, the @p regif parameter MUST be
|
||||||
|
* NULL. The first RD responding to the request will be chosen and all
|
||||||
|
* replies from other RD servers are ignored.
|
||||||
|
*
|
||||||
|
* @param[in] remote remote endpoint of the target RD
|
||||||
|
* @param[in] regif registration interface resource of the RD, it will be
|
||||||
|
* discovered automatically when set to NULL
|
||||||
|
*
|
||||||
|
* @return RDCLI_OK on success
|
||||||
|
* @return RDCLI_TIMEOUT on registration timeout
|
||||||
|
* @return RDCLI_NORD if addressed endpoint is not a RD
|
||||||
|
* @return RDCLI_OVERFLOW if @p regif does not fit into internal buffer
|
||||||
|
* @return RDCLI_ERR on any other internal error
|
||||||
|
*/
|
||||||
|
int rdcli_register(const sock_udp_ep_t *remote, const char *regif);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Update our current entry at the RD
|
||||||
|
*
|
||||||
|
* @return RDCLI_OK on success
|
||||||
|
* @return RDCLI_TIMEOUT if the update request times out
|
||||||
|
* @return RDCLI_ERR on any other internal error
|
||||||
|
*/
|
||||||
|
int rdcli_update(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Unregister from a given RD server
|
||||||
|
*
|
||||||
|
* @return RDCLI_OK on success
|
||||||
|
* @return RDCLI_TIMEOUT if the remove request times out
|
||||||
|
* @return RDCLI_ERR on any other internal error
|
||||||
|
*/
|
||||||
|
int rdcli_remove(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Dump the current RD connection status to STDIO (for debugging)
|
||||||
|
*/
|
||||||
|
void rdcli_dump_status(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* NET_RDCLI_H */
|
||||||
|
/** @} */
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2017 Freie Universität Berlin
|
* Copyright (C) 2017-2018 Freie Universität Berlin
|
||||||
*
|
*
|
||||||
* This file is subject to the terms and conditions of the GNU Lesser
|
* 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
|
* General Public License v2.1. See the file LICENSE in the top level
|
||||||
@ -13,7 +13,7 @@
|
|||||||
* @{
|
* @{
|
||||||
*
|
*
|
||||||
* @file
|
* @file
|
||||||
* @brief
|
* @brief CoRE RD Client static configuration default values
|
||||||
*
|
*
|
||||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||||
*/
|
*/
|
||||||
@ -42,10 +42,10 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Default client update interval (default is half the lifetime)
|
* @brief Default client update interval (default is 3/4 the lifetime)
|
||||||
*/
|
*/
|
||||||
#ifndef RDCLI_UPDATE_INTERVAL
|
#ifndef RDCLI_UPDATE_INTERVAL
|
||||||
#define RDCLI_UPDATE_INTERVAL (RDCLI_LT / 2)
|
#define RDCLI_UPDATE_INTERVAL ((RDCLI_LT / 4) * 3)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
90
sys/include/net/rdcli_standalone.h
Normal file
90
sys/include/net/rdcli_standalone.h
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017-2018 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 net_rdcli_standalone CoRE RD Standalone Extension
|
||||||
|
* @ingroup net_rdcli
|
||||||
|
* @brief Run CoRE Resource Directory client in standalone configuration
|
||||||
|
*
|
||||||
|
* This sub-module enables the CoRE RD client to manage is registration state
|
||||||
|
* with a server autonomously by periodically running the update procedure. This
|
||||||
|
* is implemented by running a dedicated thread.
|
||||||
|
*
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
* @brief CoRE Resource Directory client standalone extension
|
||||||
|
*
|
||||||
|
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef NET_RDCLI_STANDALONE_H
|
||||||
|
#define NET_RDCLI_STANDALONE_H
|
||||||
|
|
||||||
|
#include "net/sock/udp.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Possible types of events triggered by the standalone rdcli module
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
RDCLI_REGISTERED,
|
||||||
|
RDCLI_DEREGISTERED,
|
||||||
|
RDCLI_UPDATED,
|
||||||
|
} rdcli_standalone_event_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Callback function signature for RD client state synchronization
|
||||||
|
*
|
||||||
|
* The registered callback function is executed in the context of the dedicated
|
||||||
|
* standalone RD client's thread.
|
||||||
|
*
|
||||||
|
* @param[in] t type of event
|
||||||
|
*/
|
||||||
|
typedef void(*rdcli_standalone_cb_t)(rdcli_standalone_event_t event);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Spawn a new thread that takes care of sending periodic updates to an
|
||||||
|
* active RD entry
|
||||||
|
*
|
||||||
|
* @note This function must only be called once (typically during system
|
||||||
|
* initialization)
|
||||||
|
*/
|
||||||
|
void rdcli_standalone_run(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Register a callback to be notified about RD client state changes
|
||||||
|
*
|
||||||
|
* Only a single callback can be active at any point in time, so setting a new
|
||||||
|
* callback will override the existing one.
|
||||||
|
*
|
||||||
|
* @pre @p cb != NULL
|
||||||
|
*
|
||||||
|
* @param[in] cb callback to execute on RD client state changes
|
||||||
|
*/
|
||||||
|
void rdcli_standalone_reg_cb(rdcli_standalone_cb_t cb);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Signal the rdcli thread about connection status change
|
||||||
|
*
|
||||||
|
* @note This function should not be called by a user, but it is called from
|
||||||
|
* withing the rdcli implementation
|
||||||
|
*
|
||||||
|
* @param[in] connected set to true if we are connected to a RD
|
||||||
|
*/
|
||||||
|
void rdcli_standalone_signal(bool connected);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* NET_RDCLI_STANDALONE_H */
|
||||||
|
/** @} */
|
7
sys/net/application_layer/rdcli/Makefile
Normal file
7
sys/net/application_layer/rdcli/Makefile
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
SRC = rdcli.c
|
||||||
|
|
||||||
|
ifneq (,$(filter rdcli_standalone,$(USEMODULE)))
|
||||||
|
SRC += rdcli_standalone.c
|
||||||
|
endif
|
||||||
|
|
||||||
|
include $(RIOTBASE)/Makefile.base
|
363
sys/net/application_layer/rdcli/rdcli.c
Normal file
363
sys/net/application_layer/rdcli/rdcli.c
Normal file
@ -0,0 +1,363 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017-2018 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 net_rdcli
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
* @brief CoRE Resource Directory client implementation
|
||||||
|
*
|
||||||
|
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||||
|
*
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "fmt.h"
|
||||||
|
#include "mutex.h"
|
||||||
|
#include "thread_flags.h"
|
||||||
|
|
||||||
|
#include "net/gcoap.h"
|
||||||
|
#include "net/ipv6/addr.h"
|
||||||
|
#include "net/rdcli.h"
|
||||||
|
#include "net/rdcli_common.h"
|
||||||
|
#include "net/rdcli_config.h"
|
||||||
|
|
||||||
|
#ifdef MODULE_RDCLI_STANDALONE
|
||||||
|
#include "net/rdcli_standalone.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ENABLE_DEBUG (0)
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
#define FLAG_SUCCESS (0x0001)
|
||||||
|
#define FLAG_TIMEOUT (0x0002)
|
||||||
|
#define FLAG_ERR (0x0004)
|
||||||
|
#define FLAG_OVERFLOW (0x0008)
|
||||||
|
#define FLAG_MASK (0x000f)
|
||||||
|
|
||||||
|
#define BUFSIZE (512U)
|
||||||
|
|
||||||
|
static char *_regif_buf;
|
||||||
|
static size_t _regif_buf_len;
|
||||||
|
|
||||||
|
static char _rd_loc[NANOCOAP_URI_MAX];
|
||||||
|
static char _rd_regif[NANOCOAP_URI_MAX];
|
||||||
|
static sock_udp_ep_t _rd_remote;
|
||||||
|
|
||||||
|
static mutex_t _mutex = MUTEX_INIT;
|
||||||
|
static volatile thread_t *_waiter;
|
||||||
|
|
||||||
|
static uint8_t buf[BUFSIZE];
|
||||||
|
|
||||||
|
static void _lock(void)
|
||||||
|
{
|
||||||
|
mutex_lock(&_mutex);
|
||||||
|
_waiter = sched_active_thread;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _sync(void)
|
||||||
|
{
|
||||||
|
thread_flags_t flags = thread_flags_wait_any(FLAG_MASK);
|
||||||
|
|
||||||
|
if (flags & FLAG_ERR) {
|
||||||
|
return RDCLI_ERR;
|
||||||
|
}
|
||||||
|
else if (flags & FLAG_TIMEOUT) {
|
||||||
|
return RDCLI_TIMEOUT;
|
||||||
|
}
|
||||||
|
else if (flags & FLAG_OVERFLOW) {
|
||||||
|
return RDCLI_OVERFLOW;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return RDCLI_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _on_register(unsigned req_state, coap_pkt_t* pdu,
|
||||||
|
sock_udp_ep_t *remote)
|
||||||
|
{
|
||||||
|
thread_flags_t flag = FLAG_ERR;
|
||||||
|
|
||||||
|
if ((req_state == GCOAP_MEMO_RESP) &&
|
||||||
|
(pdu->hdr->code == COAP_CODE_CREATED)) {
|
||||||
|
/* read the location header and save the RD details on success */
|
||||||
|
if (coap_get_location_path(pdu, (uint8_t *)_rd_loc,
|
||||||
|
sizeof(_rd_loc)) > 0) {
|
||||||
|
memcpy(&_rd_remote, remote, sizeof(_rd_remote));
|
||||||
|
flag = FLAG_SUCCESS;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* reset RD entry */
|
||||||
|
flag = FLAG_OVERFLOW;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (req_state == GCOAP_MEMO_TIMEOUT) {
|
||||||
|
flag = FLAG_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
thread_flags_set((thread_t *)_waiter, flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _on_update_remove(unsigned req_state, coap_pkt_t *pdu, uint8_t code)
|
||||||
|
{
|
||||||
|
thread_flags_t flag = FLAG_ERR;
|
||||||
|
|
||||||
|
if ((req_state == GCOAP_MEMO_RESP) && (pdu->hdr->code == code)) {
|
||||||
|
flag = FLAG_SUCCESS;
|
||||||
|
}
|
||||||
|
else if (req_state == GCOAP_MEMO_TIMEOUT) {
|
||||||
|
flag = FLAG_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
thread_flags_set((thread_t *)_waiter, flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _on_update(unsigned req_state, coap_pkt_t *pdu, sock_udp_ep_t *remote)
|
||||||
|
{
|
||||||
|
(void)remote;
|
||||||
|
_on_update_remove(req_state, pdu, COAP_CODE_CHANGED);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _on_remove(unsigned req_state, coap_pkt_t *pdu, sock_udp_ep_t *remote)
|
||||||
|
{
|
||||||
|
(void)remote;
|
||||||
|
_on_update_remove(req_state, pdu, COAP_CODE_DELETED);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _update_remove(unsigned code, gcoap_resp_handler_t handle)
|
||||||
|
{
|
||||||
|
coap_pkt_t pkt;
|
||||||
|
|
||||||
|
if (_rd_loc[0] == 0) {
|
||||||
|
return RDCLI_NORD;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* build CoAP request packet */
|
||||||
|
int res = gcoap_req_init(&pkt, buf, sizeof(buf), code, _rd_loc);
|
||||||
|
if (res < 0) {
|
||||||
|
return RDCLI_ERR;
|
||||||
|
}
|
||||||
|
coap_hdr_set_type(pkt.hdr, COAP_TYPE_CON);
|
||||||
|
ssize_t pkt_len = gcoap_finish(&pkt, 0, COAP_FORMAT_NONE);
|
||||||
|
|
||||||
|
/* send request */
|
||||||
|
gcoap_req_send2(buf, pkt_len, &_rd_remote, handle);
|
||||||
|
|
||||||
|
/* synchronize response */
|
||||||
|
return _sync();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _on_discover(unsigned req_state, coap_pkt_t *pdu,
|
||||||
|
sock_udp_ep_t *remote)
|
||||||
|
{
|
||||||
|
thread_flags_t flag = RDCLI_NORD;
|
||||||
|
(void)remote;
|
||||||
|
|
||||||
|
if (req_state == GCOAP_MEMO_RESP) {
|
||||||
|
unsigned ct = coap_get_content_type(pdu);
|
||||||
|
if (ct != COAP_FORMAT_LINK) {
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
if (pdu->payload_len == 0) {
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
/* do simplified parsing of registration interface location */
|
||||||
|
char *start = (char *)pdu->payload;
|
||||||
|
char *end;
|
||||||
|
char *limit = (char *)(pdu->payload + pdu->payload_len);
|
||||||
|
while ((*start != '<') && (start < limit)) {
|
||||||
|
start++;
|
||||||
|
}
|
||||||
|
if (*start != '<') {
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
end = ++start;
|
||||||
|
while ((*end != '>') && (end < limit)) {
|
||||||
|
end++;
|
||||||
|
}
|
||||||
|
if (*end != '>') {
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
/* TODO: verify size of interface resource identifier */
|
||||||
|
size_t uri_len = (size_t)(end - start);
|
||||||
|
if (uri_len >= _regif_buf_len) {
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
memcpy(_regif_buf, start, uri_len);
|
||||||
|
memset((_regif_buf + uri_len), 0, (_regif_buf_len - uri_len));
|
||||||
|
flag = FLAG_SUCCESS;
|
||||||
|
}
|
||||||
|
else if (req_state == GCOAP_MEMO_TIMEOUT) {
|
||||||
|
flag = FLAG_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
end:
|
||||||
|
thread_flags_set((thread_t *)_waiter, flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _discover_internal(const sock_udp_ep_t *remote,
|
||||||
|
char *regif, size_t maxlen)
|
||||||
|
{
|
||||||
|
coap_pkt_t pkt;
|
||||||
|
|
||||||
|
/* save pointer to result buffer */
|
||||||
|
_regif_buf = regif;
|
||||||
|
_regif_buf_len = maxlen;
|
||||||
|
|
||||||
|
/* do URI discovery for the registration interface */
|
||||||
|
int res = gcoap_req_init(&pkt, buf, sizeof(buf), COAP_METHOD_GET,
|
||||||
|
"/.well-known/core");
|
||||||
|
if (res < 0) {
|
||||||
|
return RDCLI_ERR;
|
||||||
|
}
|
||||||
|
coap_hdr_set_type(pkt.hdr, COAP_TYPE_CON);
|
||||||
|
gcoap_add_qstring(&pkt, "rt", "core.rd");
|
||||||
|
size_t pkt_len = gcoap_finish(&pkt, 0, COAP_FORMAT_NONE);
|
||||||
|
res = gcoap_req_send2(buf, pkt_len, remote, _on_discover);
|
||||||
|
if (res < 0) {
|
||||||
|
return RDCLI_ERR;
|
||||||
|
}
|
||||||
|
return _sync();
|
||||||
|
}
|
||||||
|
|
||||||
|
int rdcli_discover_regif(const sock_udp_ep_t *remote, char *regif, size_t maxlen)
|
||||||
|
{
|
||||||
|
assert(remote && regif);
|
||||||
|
|
||||||
|
_lock();
|
||||||
|
int res = _discover_internal(remote, regif, maxlen);
|
||||||
|
mutex_unlock(&_mutex);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rdcli_register(const sock_udp_ep_t *remote, const char *regif)
|
||||||
|
{
|
||||||
|
assert(remote);
|
||||||
|
|
||||||
|
int res;
|
||||||
|
ssize_t pkt_len;
|
||||||
|
int retval;
|
||||||
|
coap_pkt_t pkt;
|
||||||
|
|
||||||
|
_lock();
|
||||||
|
|
||||||
|
/* if no registration interface is given, we will need to trigger a URI
|
||||||
|
* discovery for it first (see section 5.2) */
|
||||||
|
if (regif == NULL) {
|
||||||
|
retval = _discover_internal(remote, _rd_regif, sizeof(_rd_regif));
|
||||||
|
if (retval != RDCLI_OK) {
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (strlen(_rd_regif) >= sizeof(_rd_regif)) {
|
||||||
|
retval = RDCLI_OVERFLOW;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
strncpy(_rd_regif, regif, sizeof(_rd_regif));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* build and send CoAP POST request to the RD's registration interface */
|
||||||
|
res = gcoap_req_init(&pkt, buf, sizeof(buf), COAP_METHOD_POST, _rd_regif);
|
||||||
|
if (res < 0) {
|
||||||
|
retval = RDCLI_ERR;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
/* set some packet options and write query string */
|
||||||
|
coap_hdr_set_type(pkt.hdr, COAP_TYPE_CON);
|
||||||
|
rdcli_common_add_qstring(&pkt);
|
||||||
|
|
||||||
|
/* add the resource description as payload */
|
||||||
|
res = gcoap_get_resource_list(pkt.payload, pkt.payload_len,
|
||||||
|
COAP_FORMAT_LINK);
|
||||||
|
if (res < 0) {
|
||||||
|
retval = RDCLI_ERR;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* finish up the packet */
|
||||||
|
pkt_len = gcoap_finish(&pkt, res, COAP_FORMAT_LINK);
|
||||||
|
|
||||||
|
/* send out the request */
|
||||||
|
res = gcoap_req_send2(buf, pkt_len, remote, _on_register);
|
||||||
|
if (res < 0) {
|
||||||
|
retval = RDCLI_ERR;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
retval = _sync();
|
||||||
|
|
||||||
|
end:
|
||||||
|
/* if we encountered any error, we mark the client as not connected */
|
||||||
|
if (retval != RDCLI_OK) {
|
||||||
|
_rd_loc[0] = '\0';
|
||||||
|
}
|
||||||
|
#ifdef MODULE_RDCLI_STANDALONE
|
||||||
|
else {
|
||||||
|
rdcli_standalone_signal(true);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
mutex_unlock(&_mutex);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rdcli_update(void)
|
||||||
|
{
|
||||||
|
_lock();
|
||||||
|
int res = _update_remove(COAP_METHOD_POST, _on_update);
|
||||||
|
if (res != RDCLI_OK) {
|
||||||
|
/* in case we are not able to reach the RD, we drop the association */
|
||||||
|
#ifdef MODULE_RDCLI_STANDALONE
|
||||||
|
rdcli_standalone_signal(false);
|
||||||
|
#endif
|
||||||
|
_rd_loc[0] = '\0';
|
||||||
|
}
|
||||||
|
mutex_unlock(&_mutex);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rdcli_remove(void)
|
||||||
|
{
|
||||||
|
_lock();
|
||||||
|
if (_rd_loc[0] == '\0') {
|
||||||
|
mutex_unlock(&_mutex);
|
||||||
|
return RDCLI_NORD;
|
||||||
|
}
|
||||||
|
#ifdef MODULE_RDCLI_STANDALONE
|
||||||
|
rdcli_standalone_signal(false);
|
||||||
|
#endif
|
||||||
|
_update_remove(COAP_METHOD_DELETE, _on_remove);
|
||||||
|
/* we actually do not care about the result, we drop the RD local RD entry
|
||||||
|
* in any case */
|
||||||
|
_rd_loc[0] = '\0';
|
||||||
|
mutex_unlock(&_mutex);
|
||||||
|
return RDCLI_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rdcli_dump_status(void)
|
||||||
|
{
|
||||||
|
puts("CoAP RD connection status:");
|
||||||
|
|
||||||
|
if (_rd_loc[0] == 0) {
|
||||||
|
puts(" --- not registered with any RD ---");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* get address string */
|
||||||
|
char addr[IPV6_ADDR_MAX_STR_LEN];
|
||||||
|
ipv6_addr_to_str(addr, (ipv6_addr_t *)&_rd_remote.addr, sizeof(addr));
|
||||||
|
|
||||||
|
printf("RD address: coap://[%s]:%i\n", addr, (int)_rd_remote.port);
|
||||||
|
printf(" ep name: %s\n", rdcli_common_get_ep());
|
||||||
|
printf(" lifetime: %is\n", (int)RDCLI_LT);
|
||||||
|
printf(" reg if: %s\n", _rd_regif);
|
||||||
|
printf(" location: %s\n", _rd_loc);
|
||||||
|
}
|
||||||
|
}
|
115
sys/net/application_layer/rdcli/rdcli_standalone.c
Normal file
115
sys/net/application_layer/rdcli/rdcli_standalone.c
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017-2018 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 net_rdcli_simple
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
* @brief Standalone extension for the simple RD registration client
|
||||||
|
*
|
||||||
|
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||||
|
*
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
#include "assert.h"
|
||||||
|
#include "thread.h"
|
||||||
|
#include "xtimer.h"
|
||||||
|
#include "net/rdcli.h"
|
||||||
|
#include "net/rdcli_config.h"
|
||||||
|
#include "net/rdcli_standalone.h"
|
||||||
|
|
||||||
|
#define ENABLE_DEBUG (0)
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
/* stack configuration */
|
||||||
|
#define STACKSIZE (THREAD_STACKSIZE_DEFAULT)
|
||||||
|
#define PRIO (THREAD_PRIORITY_MAIN - 1)
|
||||||
|
#define TNAME "rdcli"
|
||||||
|
|
||||||
|
#define UPDATE_TIMEOUT (0xe537)
|
||||||
|
|
||||||
|
#define TIMEOUT_US ((uint64_t)(RDCLI_UPDATE_INTERVAL * US_PER_SEC))
|
||||||
|
|
||||||
|
static char _stack[STACKSIZE];
|
||||||
|
|
||||||
|
static xtimer_t _timer;
|
||||||
|
static kernel_pid_t _runner_pid;
|
||||||
|
static msg_t _msg;
|
||||||
|
|
||||||
|
static rdcli_standalone_cb_t _cb = NULL;
|
||||||
|
|
||||||
|
static void _set_timer(void)
|
||||||
|
{
|
||||||
|
xtimer_set_msg64(&_timer, TIMEOUT_US, &_msg, _runner_pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _notify(rdcli_standalone_event_t event)
|
||||||
|
{
|
||||||
|
if (_cb) {
|
||||||
|
_cb(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *_reg_runner(void *arg)
|
||||||
|
{
|
||||||
|
(void)arg;
|
||||||
|
msg_t in;
|
||||||
|
|
||||||
|
/* prepare context and message */
|
||||||
|
_runner_pid = thread_getpid();
|
||||||
|
_msg.type = UPDATE_TIMEOUT;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
DEBUG("rd stand: waiting for message\n");
|
||||||
|
msg_receive(&in);
|
||||||
|
if (in.type == UPDATE_TIMEOUT) {
|
||||||
|
if (rdcli_update() == RDCLI_OK) {
|
||||||
|
DEBUG("rd stand: update ok\n");
|
||||||
|
_set_timer();
|
||||||
|
_notify(RDCLI_UPDATED);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_notify(RDCLI_DEREGISTERED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL; /* should never be reached */
|
||||||
|
}
|
||||||
|
|
||||||
|
void rdcli_standalone_run(void)
|
||||||
|
{
|
||||||
|
thread_create(_stack, sizeof(_stack), PRIO, 0, _reg_runner, NULL, TNAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rdcli_standalone_signal(bool connected)
|
||||||
|
{
|
||||||
|
/* clear timer in any case */
|
||||||
|
xtimer_remove(&_timer);
|
||||||
|
/* reset the update timer in case a connection was established or updated */
|
||||||
|
if (connected) {
|
||||||
|
_set_timer();
|
||||||
|
_notify(RDCLI_REGISTERED);
|
||||||
|
} else {
|
||||||
|
_notify(RDCLI_DEREGISTERED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void rdcli_standalone_reg_cb(rdcli_standalone_cb_t cb)
|
||||||
|
{
|
||||||
|
/* Note: we do not allow re-setting the callback (via passing cb := NULL),
|
||||||
|
* as this would mean additional complexity for synchronizing the
|
||||||
|
* value of `_cb` to prevent concurrency issues... */
|
||||||
|
assert(cb);
|
||||||
|
_cb = cb;
|
||||||
|
}
|
@ -66,6 +66,9 @@ endif
|
|||||||
ifneq (,$(filter conn_can,$(USEMODULE)))
|
ifneq (,$(filter conn_can,$(USEMODULE)))
|
||||||
SRC += sc_can.c
|
SRC += sc_can.c
|
||||||
endif
|
endif
|
||||||
|
ifneq (,$(filter rdcli,$(USEMODULE)))
|
||||||
|
SRC += sc_rdcli.c
|
||||||
|
endif
|
||||||
|
|
||||||
ifneq (,$(filter periph_rtc,$(FEATURES_PROVIDED)))
|
ifneq (,$(filter periph_rtc,$(FEATURES_PROVIDED)))
|
||||||
SRC += sc_rtc.c
|
SRC += sc_rtc.c
|
||||||
|
130
sys/shell/commands/sc_rdcli.c
Normal file
130
sys/shell/commands/sc_rdcli.c
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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 sys_shell_commands
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
* @brief Shell commands for the rdcli module
|
||||||
|
*
|
||||||
|
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||||
|
*
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "net/rdcli.h"
|
||||||
|
#include "net/nanocoap.h"
|
||||||
|
#include "net/sock/util.h"
|
||||||
|
#include "net/rdcli_config.h"
|
||||||
|
#include "net/rdcli_common.h"
|
||||||
|
|
||||||
|
static int make_sock_ep(sock_udp_ep_t *ep, const char *addr)
|
||||||
|
{
|
||||||
|
ep->port = 0;
|
||||||
|
if (sock_udp_str2ep(ep, addr) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ep->family = AF_INET6;
|
||||||
|
ep->netif = SOCK_ADDR_ANY_NETIF;
|
||||||
|
if (ep->port == 0) {
|
||||||
|
ep->port = RDCLI_SERVER_PORT;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _rdcli_handler(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
if ((argc > 1) && (strcmp(argv[1], "register") == 0)) {
|
||||||
|
char *regif = NULL;
|
||||||
|
if (argc < 3) {
|
||||||
|
printf("usage: %s register <server address> [registration interface]\n",
|
||||||
|
argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
sock_udp_ep_t remote;
|
||||||
|
if (make_sock_ep(&remote, argv[2]) < 0) {
|
||||||
|
printf("error: unable to parse address\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (argc > 3) {
|
||||||
|
regif = argv[3];
|
||||||
|
}
|
||||||
|
puts("Registering with RD now, this may take a short while...");
|
||||||
|
if (rdcli_register(&remote, regif) != RDCLI_OK) {
|
||||||
|
puts("error: registration failed");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
puts("registration successful\n");
|
||||||
|
rdcli_dump_status();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((argc > 1) && (strcmp(argv[1], "discover") == 0)) {
|
||||||
|
if (argc < 3) {
|
||||||
|
printf("usage: %s discover <server address>\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
char regif[NANOCOAP_URI_MAX];
|
||||||
|
sock_udp_ep_t remote;
|
||||||
|
if (make_sock_ep(&remote, argv[2]) < 0) {
|
||||||
|
printf("error: unable to parse address\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (rdcli_discover_regif(&remote, regif, sizeof(regif)) == RDCLI_OK) {
|
||||||
|
printf("the registration interface is '%s'\n", regif);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf("error: unable to discover registration interface\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((argc > 1) && (strcmp(argv[1], "update") == 0)) {
|
||||||
|
res = rdcli_update();
|
||||||
|
if (res == RDCLI_OK) {
|
||||||
|
puts("RD update successful");
|
||||||
|
}
|
||||||
|
else if (res == RDCLI_NORD) {
|
||||||
|
puts("error: not associated with any RD");
|
||||||
|
}
|
||||||
|
else if (res == RDCLI_TIMEOUT) {
|
||||||
|
puts("error: unable to reach RD - dropped association");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
puts("error: RD update failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((argc > 1) && (strcmp(argv[1], "remove") == 0)) {
|
||||||
|
res = rdcli_remove();
|
||||||
|
if (res == RDCLI_OK) {
|
||||||
|
puts("node successfully removed from RD");
|
||||||
|
}
|
||||||
|
else if (res == RDCLI_NORD) {
|
||||||
|
puts("error: not associated with any RD");
|
||||||
|
}
|
||||||
|
else if (res == RDCLI_TIMEOUT) {
|
||||||
|
puts("error: unable to reach RD - remove association only locally");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
puts("error: unable to remove node from RD");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((argc > 1) && (strcmp(argv[1], "info") == 0)) {
|
||||||
|
rdcli_dump_status();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf("usage: %s <register|discover|update|remove|info>\n",
|
||||||
|
argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -142,6 +142,10 @@ extern int _ls_handler(int argc, char **argv);
|
|||||||
extern int _can_handler(int argc, char **argv);
|
extern int _can_handler(int argc, char **argv);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef MODULE_RDCLI
|
||||||
|
extern int _rdcli_handler(int argc, char **argv);
|
||||||
|
#endif
|
||||||
|
|
||||||
const shell_command_t _shell_command_list[] = {
|
const shell_command_t _shell_command_list[] = {
|
||||||
{"reboot", "Reboot the node", _reboot_handler},
|
{"reboot", "Reboot the node", _reboot_handler},
|
||||||
#ifdef MODULE_CONFIG
|
#ifdef MODULE_CONFIG
|
||||||
@ -232,6 +236,9 @@ const shell_command_t _shell_command_list[] = {
|
|||||||
#endif
|
#endif
|
||||||
#ifdef MODULE_CONN_CAN
|
#ifdef MODULE_CONN_CAN
|
||||||
{"can", "CAN commands", _can_handler},
|
{"can", "CAN commands", _can_handler},
|
||||||
|
#endif
|
||||||
|
#ifdef MODULE_RDCLI
|
||||||
|
{"rdcli", "CoAP RD client commands", _rdcli_handler },
|
||||||
#endif
|
#endif
|
||||||
{NULL, NULL, NULL}
|
{NULL, NULL, NULL}
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user