diff --git a/examples/riot/README.md b/examples/riot/README.md new file mode 100644 index 00000000..a81fb92a --- /dev/null +++ b/examples/riot/README.md @@ -0,0 +1,96 @@ +# RIOT Examples + +This doc explains how to compile and run the various RIOT OS examples. + +## Setup RIOT Environment + +Make sure that the environment variable `RIOTBASE` points to a `RIOT` codebase. + +## Build and Run + +### Blinky + +```shell +cd blinky +make BOARD=native all term +``` + +### Hello + +```shell +cd hello +make BOARD=native all term +``` + +### CoAP Federated + +The federated example using CoAP channels needs to be run using 2 terminals. +Make sure to set the `PORT` environment variable to the correct `tap` interface such as `tap0` or `tap1` as can be seen in the code below. + +#### Preparation + +First you need to create the `tap` interfaces so that the `sender` and `receiver` application can communicate through the (linux) host. + +```shell +sudo $RIOTBASE/dist/tools/tapsetup/tapsetup +``` + +#### Get IPv6 address of receiver + +Enter the directory of the `sender` application: + +```shell +cd coap_federated/sender +``` + +Get the IP address of the `receiver` by specifying the `PORT=tap1` and `ONLY_PRINT_IP=1` environment variables: + +*If the program returns more than one IP-Address then select the one that starts with `fe80`*. + +```shell +make ONLY_PRINT_IP=1 BOARD=native PORT=tap1 all term +``` + +The resulting program will print out the IPv6 address of `tap1` and terminate. +This address must be used when starting the sender below. + + +#### Get IPv6 address of sender + +Enter the directory of the `receiver` application: + +```shell +cd coap_federated/receiver +``` + +Get the IP address of the `sender` by specifying the `PORT=tap0` and `ONLY_PRINT_IP=1` environment variables: + +*If the program returns more than one IP-Address then select the one that starts with `fe80`*. + +```shell +make ONLY_PRINT_IP=1 BOARD=native PORT=tap0 all term +``` + +The resulting program will print out the IPv6 address of `tap0` and terminate. +This address must be used when starting the receiver below. + +#### Start the applications + +##### Sender +Start the sender with `PORT=tap0`, make sure to replace `REMOTE_ADDRESS` with +the address of `tap1` that you found above. + +```shell +cd sender +make REMOTE_ADDRESS=fe80::8cc3:33ff:febb:1b3 BOARD=native PORT=tap0 all term +``` + +##### Receiver + +Start the receiver with `PORT=tap1`, make sure to replace `REMOTE_ADDRESS` with +the address of `tap0` that you found above. + +```shell +cd receiver +make REMOTE_ADDRESS=fe80::44e5:1bff:fee4:dac8 BOARD=native PORT=tap1 all term +``` diff --git a/examples/riot/coap_federated/receiver/Makefile b/examples/riot/coap_federated/receiver/Makefile new file mode 100755 index 00000000..7a6d22cb --- /dev/null +++ b/examples/riot/coap_federated/receiver/Makefile @@ -0,0 +1,45 @@ +# name of your application +APPLICATION = lf-coap-federated-receiver + +# This has to be the absolute path to the RIOT base directory: +RIOTBASE ?= $(CURDIR)/../../../../../RIOT + +# If no BOARD is found in the environment, use this default: +BOARD ?= native + +# 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: +DEVELHELP ?= 1 + +# Change this to 0 show compiler invocation lines by default: +QUIET ?= 1 + +# Enable reactor-uc features +CFLAGS += -DNETWORK_CHANNEL_COAP_RIOT +REACTION_QUEUE_SIZE = 32 +EVENT_QUEUE_SIZE = 32 + +CFLAGS += -DTHREAD_STACKSIZE_DEFAULT=10000 +CFLAGS += -DTHREAD_STACKSIZE_MAIN=10000 +CFLAGS += -DISR_STACKSIZE=10000 + +# Configure CoAP retransmission timeout +CFLAGS += -DCONFIG_GCOAP_NO_RETRANS_BACKOFF=1 +CFLAGS += -DCONFIG_COAP_ACK_TIMEOUT_MS=400 +CFLAGS += -DCONFIG_COAP_MAX_RETRANSMIT=4 + +# Check if ONLY_PRINT_IP is defined +# If ONLY_PRINT_IP is defined the REMOTE_ADDRESS is not needed +ifdef ONLY_PRINT_IP + # ONLY_PRINT_IP is defined => Set CFLAGS for it + CFLAGS += -DONLY_PRINT_IP=$(ONLY_PRINT_IP) +else ifdef REMOTE_ADDRESS + # REMOTE_ADDRESS is defined => Set CFLAGS for it + CFLAGS += -DREMOTE_ADDRESS=\"$(REMOTE_ADDRESS)\" +else + # Neither is defined + $(error Either define REMOTE_ADDRESS or set ONLY_PRINT_IP=1 to print the IP-Address of this device.) +endif + +include $(CURDIR)/../../../../make/riot/riot.mk diff --git a/examples/riot/coap_federated/receiver/main.c b/examples/riot/coap_federated/receiver/main.c new file mode 100755 index 00000000..9c50219c --- /dev/null +++ b/examples/riot/coap_federated/receiver/main.c @@ -0,0 +1,117 @@ +#include "reactor-uc/platform/riot/coap_udp_ip_channel.h" +#include "reactor-uc/reactor-uc.h" + +#ifndef REMOTE_ADDRESS +#define REMOTE_ADDRESS "fe80::44e5:1bff:fee4:dac8" +#endif + +#define REMOTE_PROTOCOL_FAMILY AF_INET6 + +typedef struct { + int size; + char msg[512]; +} lf_msg_t; + +lf_ret_t deserialize_msg_t(void *user_struct, const unsigned char *msg_buf, size_t msg_size) { + (void)msg_size; + + lf_msg_t *msg = user_struct; + memcpy(&msg->size, msg_buf, sizeof(msg->size)); + memcpy(msg->msg, msg_buf + sizeof(msg->size), msg->size); + + return LF_OK; +} + +LF_DEFINE_REACTION_STRUCT(Receiver, r, 0) +LF_DEFINE_REACTION_CTOR(Receiver, r, 0) +LF_DEFINE_INPUT_STRUCT(Receiver, in, 1, 0, lf_msg_t, 0) +LF_DEFINE_INPUT_CTOR(Receiver, in, 1, 0, lf_msg_t, 0) + +typedef struct { + Reactor super; + LF_REACTION_INSTANCE(Receiver, r); + LF_PORT_INSTANCE(Receiver, in, 1); + int cnt; + LF_REACTOR_BOOKKEEPING_INSTANCES(1, 1, 0); +} Receiver; + +LF_DEFINE_REACTION_BODY(Receiver, r) { + LF_SCOPE_SELF(Receiver); + LF_SCOPE_ENV(); + LF_SCOPE_PORT(Receiver, in); + printf("Input triggered @ %" PRId64 " with %s size %d\n", env->get_elapsed_logical_time(env), in->value.msg, + in->value.size); +} + +LF_REACTOR_CTOR_SIGNATURE_WITH_PARAMETERS(Receiver, InputExternalCtorArgs *in_external) { + LF_REACTOR_CTOR_PREAMBLE(); + LF_REACTOR_CTOR(Receiver); + LF_INITIALIZE_REACTION(Receiver, r); + LF_INITIALIZE_INPUT(Receiver, in, 1, in_external); + + // Register reaction as an effect of in + LF_PORT_REGISTER_EFFECT(self->in, self->r, 1); +} + +LF_DEFINE_FEDERATED_INPUT_CONNECTION(Receiver, in, lf_msg_t, 5, MSEC(100), false) + +typedef struct { + FederatedConnectionBundle super; + CoapUdpIpChannel channel; + LF_FEDERATED_INPUT_CONNECTION_INSTANCE(Receiver, in); + LF_FEDERATED_CONNECTION_BUNDLE_BOOKKEEPING_INSTANCES(1, 0) +} LF_FEDERATED_CONNECTION_BUNDLE_NAME(Receiver, Sender); + +LF_FEDERATED_CONNECTION_BUNDLE_CTOR_SIGNATURE(Receiver, Sender) { + LF_FEDERATED_CONNECTION_BUNDLE_CTOR_PREAMBLE(); + CoapUdpIpChannel_ctor(&self->channel, parent->env, REMOTE_ADDRESS, REMOTE_PROTOCOL_FAMILY); + LF_FEDERATED_CONNECTION_BUNDLE_CALL_CTOR(); + LF_INITIALIZE_FEDERATED_INPUT_CONNECTION(Receiver, in, deserialize_msg_t); +} + +typedef struct { + Reactor super; + LF_CHILD_REACTOR_INSTANCE(Receiver, receiver, 1); + LF_FEDERATED_CONNECTION_BUNDLE_INSTANCE(Receiver, Sender); + LF_FEDERATE_BOOKKEEPING_INSTANCES(1); + LF_CHILD_INPUT_SOURCES(receiver, in, 1, 1, 0); +} MainRecv; + +LF_REACTOR_CTOR_SIGNATURE(MainRecv) { + LF_REACTOR_CTOR(MainRecv); + LF_FEDERATE_CTOR_PREAMBLE(); + LF_DEFINE_CHILD_INPUT_ARGS(receiver, in, 1, 1); + LF_INITIALIZE_CHILD_REACTOR_WITH_PARAMETERS(Receiver, receiver, 1, _receiver_in_args[i]); + LF_INITIALIZE_FEDERATED_CONNECTION_BUNDLE(Receiver, Sender); + LF_BUNDLE_REGISTER_DOWNSTREAM(Receiver, Sender, receiver, in); +} + +LF_ENTRY_POINT_FEDERATED(MainRecv, SEC(1), true, true, 1, false) + +void print_ip_addresses(void) { + gnrc_netif_t *netif = gnrc_netif_iter(NULL); + char addr_str[IPV6_ADDR_MAX_STR_LEN]; + + while (netif) { + size_t max_addr_count = 4; + ipv6_addr_t addrs[max_addr_count]; + gnrc_netif_ipv6_addrs_get(netif, addrs, max_addr_count * sizeof(ipv6_addr_t)); + + for (size_t i = 0; i < 2; i++) { + if (ipv6_addr_to_str(addr_str, &addrs[i], sizeof(addr_str))) { + LF_INFO(NET, "IPv6 address: %s", addr_str); + } + } + + netif = gnrc_netif_iter(netif); + } +} + +int main() { +#ifdef ONLY_PRINT_IP + print_ip_addresses(); +#else + lf_start(); +#endif + return 0; +} diff --git a/examples/riot/coap_federated/sender/Makefile b/examples/riot/coap_federated/sender/Makefile new file mode 100755 index 00000000..ad03fccd --- /dev/null +++ b/examples/riot/coap_federated/sender/Makefile @@ -0,0 +1,45 @@ +# name of your application +APPLICATION = lf-coap-federated-sender + +# This has to be the absolute path to the RIOT base directory: +RIOTBASE ?= $(CURDIR)/../../../../../RIOT + +# If no BOARD is found in the environment, use this default: +BOARD ?= native + +# 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: +DEVELHELP ?= 1 + +# Change this to 0 show compiler invocation lines by default: +QUIET ?= 1 + +# Enable reactor-uc features +CFLAGS += -DNETWORK_CHANNEL_COAP_RIOT +REACTION_QUEUE_SIZE = 32 +EVENT_QUEUE_SIZE = 32 + +CFLAGS += -DTHREAD_STACKSIZE_DEFAULT=10000 +CFLAGS += -DTHREAD_STACKSIZE_MAIN=10000 +CFLAGS += -DISR_STACKSIZE=10000 + +# Configure CoAP retransmission timeout +CFLAGS += -DCONFIG_GCOAP_NO_RETRANS_BACKOFF=1 +CFLAGS += -DCONFIG_COAP_ACK_TIMEOUT_MS=400 +CFLAGS += -DCONFIG_COAP_MAX_RETRANSMIT=4 + +# Check if ONLY_PRINT_IP is defined +# If ONLY_PRINT_IP is defined the REMOTE_ADDRESS is not needed +ifdef ONLY_PRINT_IP + # ONLY_PRINT_IP is defined => Set CFLAGS for it + CFLAGS += -DONLY_PRINT_IP=$(ONLY_PRINT_IP) +else ifdef REMOTE_ADDRESS + # REMOTE_ADDRESS is defined => Set CFLAGS for it + CFLAGS += -DREMOTE_ADDRESS=\"$(REMOTE_ADDRESS)\" +else + # Neither is defined + $(error Either define REMOTE_ADDRESS or set ONLY_PRINT_IP=1 to print the IP-Address of this device) +endif + +include $(CURDIR)/../../../../make/riot/riot.mk diff --git a/examples/riot/coap_federated/sender/main.c b/examples/riot/coap_federated/sender/main.c new file mode 100755 index 00000000..9a0e47b3 --- /dev/null +++ b/examples/riot/coap_federated/sender/main.c @@ -0,0 +1,127 @@ +#include "reactor-uc/reactor-uc.h" +#include "reactor-uc/platform/riot/coap_udp_ip_channel.h" + +#ifndef REMOTE_ADDRESS +#define REMOTE_ADDRESS "fe80::8cc3:33ff:febb:1b3" +#endif + +#define REMOTE_PROTOCOL_FAMILY AF_INET6 + +typedef struct { + int size; + char msg[512]; +} lf_msg_t; + +size_t serialize_msg_t(const void *user_struct, size_t user_struct_size, unsigned char *msg_buf) { + (void)user_struct_size; + const lf_msg_t *msg = user_struct; + + memcpy(msg_buf, &msg->size, sizeof(msg->size)); + memcpy(msg_buf + sizeof(msg->size), msg->msg, msg->size); + + return sizeof(msg->size) + msg->size; +} + +LF_DEFINE_TIMER_STRUCT(Sender, t, 1, 0) +LF_DEFINE_TIMER_CTOR(Sender, t, 1, 0) +LF_DEFINE_REACTION_STRUCT(Sender, r, 1) +LF_DEFINE_REACTION_CTOR(Sender, r, 0) +LF_DEFINE_OUTPUT_STRUCT(Sender, out, 1, lf_msg_t) +LF_DEFINE_OUTPUT_CTOR(Sender, out, 1) + +typedef struct { + Reactor super; + LF_TIMER_INSTANCE(Sender, t); + LF_REACTION_INSTANCE(Sender, r); + LF_PORT_INSTANCE(Sender, out, 1); + LF_REACTOR_BOOKKEEPING_INSTANCES(1, 2, 0); +} Sender; + +LF_DEFINE_REACTION_BODY(Sender, r) { + LF_SCOPE_SELF(Sender); + LF_SCOPE_ENV(); + LF_SCOPE_PORT(Sender, out); + + printf("Timer triggered @ %" PRId64 "\n", env->get_elapsed_logical_time(env)); + lf_msg_t val; + strcpy(val.msg, "Hello From Sender"); + val.size = sizeof("Hello From Sender"); + lf_set(out, val); +} + +LF_REACTOR_CTOR_SIGNATURE_WITH_PARAMETERS(Sender, OutputExternalCtorArgs *out_external) { + LF_REACTOR_CTOR_PREAMBLE(); + LF_REACTOR_CTOR(Sender); + LF_INITIALIZE_REACTION(Sender, r); + LF_INITIALIZE_TIMER(Sender, t, MSEC(0), SEC(1)); + LF_INITIALIZE_OUTPUT(Sender, out, 1, out_external); + + LF_TIMER_REGISTER_EFFECT(self->t, self->r); + LF_PORT_REGISTER_SOURCE(self->out, self->r, 1); +} + +LF_DEFINE_FEDERATED_OUTPUT_CONNECTION(Sender, out, lf_msg_t, 1) + +typedef struct { + FederatedConnectionBundle super; + CoapUdpIpChannel channel; + LF_FEDERATED_OUTPUT_CONNECTION_INSTANCE(Sender, out); + LF_FEDERATED_CONNECTION_BUNDLE_BOOKKEEPING_INSTANCES(0, 1); +} LF_FEDERATED_CONNECTION_BUNDLE_NAME(Sender, Receiver); + +LF_FEDERATED_CONNECTION_BUNDLE_CTOR_SIGNATURE(Sender, Receiver) { + LF_FEDERATED_CONNECTION_BUNDLE_CTOR_PREAMBLE(); + CoapUdpIpChannel_ctor(&self->channel, parent->env, REMOTE_ADDRESS, REMOTE_PROTOCOL_FAMILY); + LF_FEDERATED_CONNECTION_BUNDLE_CALL_CTOR(); + LF_INITIALIZE_FEDERATED_OUTPUT_CONNECTION(Sender, out, serialize_msg_t); +} + +// Reactor main +typedef struct { + Reactor super; + LF_CHILD_REACTOR_INSTANCE(Sender, sender, 1); + LF_FEDERATED_CONNECTION_BUNDLE_INSTANCE(Sender, Receiver); + LF_FEDERATE_BOOKKEEPING_INSTANCES(1); + LF_CHILD_OUTPUT_CONNECTIONS(sender, out, 1, 1, 1); + LF_CHILD_OUTPUT_EFFECTS(sender, out, 1, 1, 0); + LF_CHILD_OUTPUT_OBSERVERS(sender, out, 1, 1, 0); +} MainSender; + +LF_REACTOR_CTOR_SIGNATURE(MainSender) { + LF_REACTOR_CTOR(MainSender); + LF_FEDERATE_CTOR_PREAMBLE(); + LF_DEFINE_CHILD_OUTPUT_ARGS(sender, out, 1, 1); + LF_INITIALIZE_CHILD_REACTOR_WITH_PARAMETERS(Sender, sender, 1, _sender_out_args[i]); + LF_INITIALIZE_FEDERATED_CONNECTION_BUNDLE(Sender, Receiver); + LF_BUNDLE_REGISTER_UPSTREAM(Sender, Receiver, sender, out); +} + +LF_ENTRY_POINT_FEDERATED(MainSender, SEC(1), true, false, 1, true) + +void print_ip_addresses(void) { + gnrc_netif_t *netif = gnrc_netif_iter(NULL); + char addr_str[IPV6_ADDR_MAX_STR_LEN]; + + while (netif) { + size_t max_addr_count = 4; + ipv6_addr_t addrs[max_addr_count]; + gnrc_netif_ipv6_addrs_get(netif, addrs, max_addr_count * sizeof(ipv6_addr_t)); + + for (size_t i = 0; i < 2; i++) { + if (ipv6_addr_to_str(addr_str, &addrs[i], sizeof(addr_str))) { + LF_INFO(NET, "IPv6 address: %s", addr_str); + } + } + + netif = gnrc_netif_iter(netif); + } +} + +int main() { +#ifdef ONLY_PRINT_IP + print_ip_addresses(); +#else + lf_start(); +#endif + return 0; +} diff --git a/include/reactor-uc/macros.h b/include/reactor-uc/macros.h index 8f5801c0..08b26e02 100644 --- a/include/reactor-uc/macros.h +++ b/include/reactor-uc/macros.h @@ -672,12 +672,10 @@ typedef struct FederatedInputConnection FederatedInputConnection; env.scheduler->leader = IsLeader; \ env.has_async_events = HasInputs; \ \ - env.enter_critical_section(&env); \ FederateName##_ctor(&main_reactor, NULL, &env); \ env.net_bundles_size = NumBundles; \ env.net_bundles = (FederatedConnectionBundle **)&main_reactor._bundles; \ env.assemble(&env); \ - env.leave_critical_section(&env); \ env.start(&env); \ lf_exit(); \ } diff --git a/src/platform/riot/coap_udp_ip_channel.c b/src/platform/riot/coap_udp_ip_channel.c index 89a5a2e7..07e11fb6 100644 --- a/src/platform/riot/coap_udp_ip_channel.c +++ b/src/platform/riot/coap_udp_ip_channel.c @@ -5,6 +5,7 @@ #include "net/gcoap.h" #include "net/sock/util.h" +#include "thread.h" #include #define COAP_UDP_IP_CHANNEL_ERR(fmt, ...) LF_ERR(NET, "CoapUdpIpChannel: " fmt, ##__VA_ARGS__) @@ -12,12 +13,11 @@ #define COAP_UDP_IP_CHANNEL_INFO(fmt, ...) LF_INFO(NET, "CoapUdpIpChannel: " fmt, ##__VA_ARGS__) #define COAP_UDP_IP_CHANNEL_DEBUG(fmt, ...) LF_DEBUG(NET, "CoapUdpIpChannel: " fmt, ##__VA_ARGS__) +char _connection_thread_stack[THREAD_STACKSIZE_MAIN]; +int _connection_thread_pid = 0; static bool _is_globals_initialized = false; static Environment *_env; -// Forward declarations -static lf_ret_t _CoapUdpIpChannel_client_send_connect_message(CoapUdpIpChannel *self); - static void _CoapUdpIpChannel_update_state(CoapUdpIpChannel *self, NetworkChannelState new_state) { COAP_UDP_IP_CHANNEL_DEBUG("Update state: %s => %s\n", NetworkChannel_state_to_string(self->state), NetworkChannel_state_to_string(new_state)); @@ -26,13 +26,22 @@ static void _CoapUdpIpChannel_update_state(CoapUdpIpChannel *self, NetworkChanne NetworkChannelState old_state = self->state; // Update the state of the channel to its new state + mutex_lock(&self->state_mutex); self->state = new_state; + mutex_unlock(&self->state_mutex); // Inform runtime about new state if it changed from or to NETWORK_CHANNEL_STATE_CONNECTED if ((old_state == NETWORK_CHANNEL_STATE_CONNECTED && new_state != NETWORK_CHANNEL_STATE_CONNECTED) || (old_state != NETWORK_CHANNEL_STATE_CONNECTED && new_state == NETWORK_CHANNEL_STATE_CONNECTED)) { _env->platform->new_async_event(_env->platform); } + + // Let connection thread evaluate new state of this channel + msg_t msg = { + .type = 0, + .content.ptr = self, + }; + msg_try_send(&msg, _connection_thread_pid); } static void _CoapUdpIpChannel_update_state_if_not(CoapUdpIpChannel *self, NetworkChannelState new_state, @@ -40,7 +49,8 @@ static void _CoapUdpIpChannel_update_state_if_not(CoapUdpIpChannel *self, Networ // Update the state of the channel itself mutex_lock(&self->state_mutex); if (self->state != if_not) { - COAP_UDP_IP_CHANNEL_DEBUG("Update state: %d => %d\n", self->state, new_state); + COAP_UDP_IP_CHANNEL_DEBUG("Update state: %s => %s\n", NetworkChannel_state_to_string(self->state), + NetworkChannel_state_to_string(new_state)); self->state = new_state; } mutex_unlock(&self->state_mutex); @@ -71,8 +81,10 @@ static CoapUdpIpChannel *_CoapUdpIpChannel_get_coap_channel_by_remote(const sock } } - COAP_UDP_IP_CHANNEL_ERR("Channel not found by socket"); + char remote_addr_str[IPV6_ADDR_MAX_STR_LEN]; + sock_udp_ep_fmt(remote, remote_addr_str, NULL); + COAP_UDP_IP_CHANNEL_ERR("Channel not found by socket (addr=%s)", remote_addr_str); return NULL; } @@ -84,12 +96,13 @@ static bool _CoapUdpIpChannel_send_coap_message(sock_udp_ep_t *remote, char *pat coap_hdr_set_type(pdu.hdr, COAP_TYPE_CON); ssize_t bytes_sent = gcoap_req_send(buf, len, remote, NULL, resp_handler, NULL, GCOAP_SOCKET_TYPE_UDP); - COAP_UDP_IP_CHANNEL_DEBUG("Sending %d bytes", bytes_sent); if (bytes_sent > 0) { - COAP_UDP_IP_CHANNEL_DEBUG("Message sent"); + COAP_UDP_IP_CHANNEL_DEBUG("Sending %d bytes", bytes_sent); + COAP_UDP_IP_CHANNEL_DEBUG("CoAP Message sent"); return true; } + COAP_UDP_IP_CHANNEL_ERR("Failed to send CoAP message"); return false; } @@ -123,10 +136,11 @@ static bool _CoapUdpIpChannel_send_coap_message_with_payload(CoapUdpIpChannel *s ssize_t bytes_sent = gcoap_req_send(self->write_buffer, len, remote, NULL, resp_handler, NULL, GCOAP_SOCKET_TYPE_UDP); COAP_UDP_IP_CHANNEL_DEBUG("Sending %d bytes", bytes_sent); if (bytes_sent > 0) { - COAP_UDP_IP_CHANNEL_DEBUG("Message sent"); + COAP_UDP_IP_CHANNEL_DEBUG("CoAP Message sent"); return true; } + COAP_UDP_IP_CHANNEL_ERR("Failed to send CoAP message"); return false; } @@ -217,11 +231,11 @@ static void _CoapUdpIpChannel_client_open_connection_callback(const gcoap_reques if (memo->state == GCOAP_MEMO_TIMEOUT) { // Failure COAP_UDP_IP_CHANNEL_ERR("TIMEOUT => Try to connect again"); - _CoapUdpIpChannel_client_send_connect_message(self); // Try to connect again + _CoapUdpIpChannel_update_state(self, NETWORK_CHANNEL_STATE_CONNECTION_FAILED); } else if (coap_get_code_class(pdu) != COAP_CLASS_SUCCESS) { // Failure COAP_UDP_IP_CHANNEL_ERR("CONNECTION REJECTED => Try to connect again"); - _CoapUdpIpChannel_client_send_connect_message(self); // Try to connect again + _CoapUdpIpChannel_update_state(self, NETWORK_CHANNEL_STATE_CONNECTION_FAILED); } else { // Success _CoapUdpIpChannel_update_state(self, NETWORK_CHANNEL_STATE_CONNECTED); @@ -254,7 +268,8 @@ static lf_ret_t CoapUdpIpChannel_open_connection(NetworkChannel *untyped_self) { // the connection to us as established. /* Client */ - return _CoapUdpIpChannel_client_send_connect_message(self); + _CoapUdpIpChannel_update_state(self, NETWORK_CHANNEL_STATE_OPEN); + return LF_OK; } static void _CoapUdpIpChannel_client_close_connection_callback(const gcoap_request_memo_t *memo, coap_pkt_t *pdu, @@ -312,9 +327,6 @@ static lf_ret_t CoapUdpIpChannel_send_blocking(NetworkChannel *untyped_self, con if (_CoapUdpIpChannel_get_state(self) == NETWORK_CHANNEL_STATE_CONNECTED) { return LF_OK; - } else { - // Try to connect again - _CoapUdpIpChannel_client_send_connect_message(self); } } @@ -345,6 +357,44 @@ static bool CoapUdpIpChannel_is_connected(NetworkChannel *untyped_self) { return _CoapUdpIpChannel_get_state(self) == NETWORK_CHANNEL_STATE_CONNECTED; } +void *_CoapUdpIpChannel_connection_thread(void *arg) { + COAP_UDP_IP_CHANNEL_DEBUG("Start connection thread"); + (void)arg; + msg_t m; + + while (true) { + msg_receive(&m); + + CoapUdpIpChannel *self = m.content.ptr; + + switch (self->state) { + case NETWORK_CHANNEL_STATE_OPEN: { + /* try to connect */ + _CoapUdpIpChannel_client_send_connect_message(self); + } break; + + case NETWORK_CHANNEL_STATE_CONNECTION_IN_PROGRESS: + /* nothing to do */ + break; + + case NETWORK_CHANNEL_STATE_LOST_CONNECTION: + case NETWORK_CHANNEL_STATE_CONNECTION_FAILED: { + /* try to reconnect */ + _CoapUdpIpChannel_client_send_connect_message(self); + } break; + + case NETWORK_CHANNEL_STATE_CONNECTED: + break; + + case NETWORK_CHANNEL_STATE_UNINITIALIZED: + case NETWORK_CHANNEL_STATE_CLOSED: + break; + } + } + + return NULL; +} + void CoapUdpIpChannel_ctor(CoapUdpIpChannel *self, Environment *env, const char *remote_address, int remote_protocol_family) { assert(self != NULL); @@ -360,6 +410,11 @@ void CoapUdpIpChannel_ctor(CoapUdpIpChannel *self, Environment *env, const char // Initialize coap server gcoap_register_listener(&_listener); + + // Create connection thread + _connection_thread_pid = + thread_create(_connection_thread_stack, sizeof(_connection_thread_stack), THREAD_PRIORITY_MAIN - 1, 0, + _CoapUdpIpChannel_connection_thread, NULL, "coap_connection_thread"); } // Super fields diff --git a/src/platform/riot/riot.c b/src/platform/riot/riot.c index 8b31c71a..ca7d6956 100644 --- a/src/platform/riot/riot.c +++ b/src/platform/riot/riot.c @@ -64,12 +64,12 @@ lf_ret_t PlatformRiot_wait_for(Platform *self, interval_t duration) { void PlatformRiot_leave_critical_section(Platform *self) { PlatformRiot *p = (PlatformRiot *)self; - p->irq_mask = irq_disable(); + irq_restore(p->irq_mask); } void PlatformRiot_enter_critical_section(Platform *self) { PlatformRiot *p = (PlatformRiot *)self; - irq_restore(p->irq_mask); + p->irq_mask = irq_disable(); } void PlatformRiot_new_async_event(Platform *self) { mutex_unlock(&((PlatformRiot *)self)->lock); }