diff --git a/apps/shell/serial-shell.c b/apps/shell/serial-shell.c new file mode 100644 index 000000000..c2f389515 --- /dev/null +++ b/apps/shell/serial-shell.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2008, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * A shell back-end for the serial port + * \author + * Adam Dunkels + * Simon Duquennoy + */ + +/** + * \addtogroup shell + * @{ + */ + +#include "contiki.h" +#include "dev/serial-line.h" +#include "sys/log.h" +#include "shell.h" +#include "serial-shell.h" + +/*---------------------------------------------------------------------------*/ +PROCESS(serial_shell_process, "Contiki serial shell"); + +/*---------------------------------------------------------------------------*/ +static void +serial_shell_output(const char *str) { + printf("%s", str); +} +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(serial_shell_process, ev, data) +{ + PROCESS_BEGIN(); + + shell_init(); + + while(1) { + static struct pt shell_input_pt; + PROCESS_WAIT_EVENT_UNTIL(ev == serial_line_event_message && data != NULL); + PROCESS_PT_SPAWN(&shell_input_pt, shell_input(&shell_input_pt, serial_shell_output, data)); + } + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ +void +serial_shell_init(void) +{ + process_start(&serial_shell_process, NULL); +} +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/apps/shell/serial-shell.h b/apps/shell/serial-shell.h new file mode 100644 index 000000000..2c364922c --- /dev/null +++ b/apps/shell/serial-shell.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2008, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + */ + +/** + * \file + * A shell back-end for the serial port + * \author + * Adam Dunkels + * Simon Duquennoy + */ + +#ifndef SERIAL_SHELL_H_ +#define SERIAL_SHELL_H_ + +/** + * Initializes Serial Shell module + */ +void serial_shell_init(void); + +#endif /* SERIAL_SHELL_H_ */ diff --git a/apps/shell/shell-commands.c b/apps/shell/shell-commands.c new file mode 100644 index 000000000..89e4bf79f --- /dev/null +++ b/apps/shell/shell-commands.c @@ -0,0 +1,626 @@ +/* + * Copyright (c) 2017, Inria. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + */ + +/** + * \file + * The Contiki shell commands + * \author + * Simon Duquennoy + */ + +/** + * \addtogroup shell + * @{ + */ + +#include "contiki.h" +#include "shell.h" +#include "shell-commands.h" +#include "sys/log.h" +#include "net/ip/uip.h" +#include "net/ip/uiplib.h" +#include "net/ipv6/uip-icmp6.h" +#include "net/ipv6/uip-ds6.h" +#include "net/mac/tsch/tsch.h" +#include "net/mac/tsch/tsch-adaptive-timesync.h" +#include "net/mac/tsch/tsch-queue.h" +#include "net/mac/tsch/tsch-log.h" +#include "net/mac/tsch/tsch-private.h" +#if UIP_CONF_IPV6_RPL_LITE == 1 +#include "net/rpl-lite/rpl.h" +#else /* UIP_CONF_IPV6_RPL_LITE == 1 */ +#include "net/rpl/rpl.h" +#include "net/rpl/rpl-private.h" +#endif /* UIP_CONF_IPV6_RPL_LITE == 1 */ + +#include + +#define PING_TIMEOUT (5 * CLOCK_SECOND) + +static struct uip_icmp6_echo_reply_notification echo_reply_notification; +static shell_output_func *curr_ping_output_func = NULL; +static struct process *curr_ping_process; +static uint8_t curr_ping_ttl; +static uint16_t curr_ping_datalen; + +/*---------------------------------------------------------------------------*/ +static const char * +ds6_nbr_state_to_str(uint8_t state) +{ + switch(state) { + case NBR_INCOMPLETE: + return "Incomplete"; + case NBR_REACHABLE: + return "Reachable"; + case NBR_STALE: + return "Stale"; + case NBR_DELAY: + return "Delay"; + case NBR_PROBE: + return "Probe"; + default: + return "Unknown"; + } +} +/*---------------------------------------------------------------------------*/ +static const char * +rpl_state_to_str(enum rpl_dag_state state) +{ + switch(state) { + case DAG_INITIALIZED: + return "Initialized"; + case DAG_JOINED: + return "Joined"; + case DAG_REACHABLE: + return "Reachable"; + case DAG_POISONING: + return "Poisoning"; + default: + return "Unknown"; + } +} +/*---------------------------------------------------------------------------*/ +static const char * +rpl_mop_to_str(int mop) +{ + switch(mop) { + case RPL_MOP_NO_DOWNWARD_ROUTES: + return "No downward routes"; + case RPL_MOP_NON_STORING: + return "Non-storing"; + case RPL_MOP_STORING_NO_MULTICAST: + return "Storing"; + case RPL_MOP_STORING_MULTICAST: + return "Storing+multicast"; + default: + return "Unknown"; + } +} +/*---------------------------------------------------------------------------*/ +static const char * +rpl_ocp_to_str(int ocp) +{ + switch(ocp) { + case RPL_OCP_OF0: + return "OF0"; + case RPL_OCP_MRHOF: + return "MRHOF"; + default: + return "Unknown"; + } +} +/*---------------------------------------------------------------------------*/ +static void +echo_reply_handler(uip_ipaddr_t *source, uint8_t ttl, uint8_t *data, uint16_t datalen) +{ + if(curr_ping_output_func != NULL) { + curr_ping_output_func = NULL; + curr_ping_ttl = ttl; + curr_ping_datalen = datalen; + process_poll(curr_ping_process); + } +} +/*---------------------------------------------------------------------------*/ +static +PT_THREAD(cmd_ping(struct pt *pt, shell_output_func output, char *args)) +{ + static uip_ipaddr_t remote_addr; + static struct etimer timeout_timer; + char *next_args; + + PT_BEGIN(pt); + + SHELL_ARGS_INIT(args, next_args); + + /* Get argument (remote IPv6) */ + SHELL_ARGS_NEXT(args, next_args); + if(uiplib_ipaddrconv(args, &remote_addr) == 0) { + SHELL_OUTPUT(output, "Invalid IPv6: %s\n", args); + PT_EXIT(pt); + } + + SHELL_OUTPUT(output, "Pinging "); + shell_output_6addr(output, &remote_addr); + SHELL_OUTPUT(output, "\n"); + + /* Send ping request */ + curr_ping_process = PROCESS_CURRENT(); + curr_ping_output_func = output; + etimer_set(&timeout_timer, PING_TIMEOUT); + uip_icmp6_send(&remote_addr, ICMP6_ECHO_REQUEST, 0, 4); + PT_WAIT_UNTIL(pt, curr_ping_output_func == NULL || etimer_expired(&timeout_timer)); + + if(curr_ping_output_func != NULL) { + SHELL_OUTPUT(output, "Timeout\n"); + curr_ping_output_func = NULL; + } else { + SHELL_OUTPUT(output, "Received ping reply from "); + shell_output_6addr(output, &remote_addr); + SHELL_OUTPUT(output, ", len %u, ttl %u, delay %lu ms\n", + curr_ping_datalen, curr_ping_ttl, (1000*(clock_time() - timeout_timer.timer.start))/CLOCK_SECOND); + } + + PT_END(pt); +} +/*---------------------------------------------------------------------------*/ +static +PT_THREAD(cmd_rpl_set_root(struct pt *pt, shell_output_func output, char *args)) +{ + static int is_on; + static uip_ipaddr_t prefix; + char *next_args; + + PT_BEGIN(pt); + + SHELL_ARGS_INIT(args, next_args); + + /* Get first arg (0/1) */ + SHELL_ARGS_NEXT(args, next_args); + + if(!strcmp(args, "1")) { + is_on = 1; + } else if(!strcmp(args, "0")) { + is_on = 0; + } else { + SHELL_OUTPUT(output, "Invalid argument: %s\n", args); + PT_EXIT(pt); + } + + /* Get first second arg (prefix) */ + SHELL_ARGS_NEXT(args, next_args); + if(args != NULL) { + if(uiplib_ipaddrconv(args, &prefix) == 0) { + SHELL_OUTPUT(output, "Invalid Prefix: %s\n", args); + PT_EXIT(pt); + } + } else { + uip_ip6addr(&prefix, UIP_DS6_DEFAULT_PREFIX, 0, 0, 0, 0, 0, 0, 0); + } + + if(is_on) { + if(!rpl_dag_root_is_root()) { + SHELL_OUTPUT(output, "Setting as DAG root with prefix "); + shell_output_6addr(output, &prefix); + SHELL_OUTPUT(output, "\n"); + rpl_dag_root_init(&prefix, NULL); + rpl_dag_root_init_dag_immediately(); + } else { + SHELL_OUTPUT(output, "Node is already a DAG root\n"); + } + } else { + if(rpl_dag_root_is_root()) { + SHELL_OUTPUT(output, "Setting as non-root node: leaving DAG\n"); + rpl_dag_poison_and_leave(); + } else { + SHELL_OUTPUT(output, "Node is not a DAG root\n"); + } + } + + PT_END(pt); +} +/*---------------------------------------------------------------------------*/ +static void +shell_output_log_levels(shell_output_func output) +{ + int i = 0; + SHELL_OUTPUT(output, "Log levels:\n"); + while(all_modules[i].name != NULL) { + SHELL_OUTPUT(output, "-- %-10s: %s\n", + all_modules[i].name, + log_level_to_str(*all_modules[i].curr_log_level)); + i++; + } +} +/*---------------------------------------------------------------------------*/ +static +PT_THREAD(cmd_log(struct pt *pt, shell_output_func output, char *args)) +{ + static int prev_level; + static int level; + char *next_args; + char *ptr; + char *module; + + PT_BEGIN(pt); + + SHELL_ARGS_INIT(args, next_args); + + /* Get and parse argument: module name */ + SHELL_ARGS_NEXT(args, next_args); + module = args; + prev_level = log_get_level(module); + if(module == NULL || (strcmp("all", module) && prev_level == -1)) { + SHELL_OUTPUT(output, "Invalid first argument: %s\n", module) + shell_output_log_levels(output); + PT_EXIT(pt); + } + + /* Get and parse argument: log level */ + SHELL_ARGS_NEXT(args, next_args); + if(args == NULL) { + level = -1; + } else { + level = (int)strtol(args, &ptr, 10); + } + if((level == 0 && args == ptr) + || level < LOG_LEVEL_NONE || level > LOG_LEVEL_DBG) { + SHELL_OUTPUT(output, "Invalid second argument: %s\n", args); + PT_EXIT(pt); + } + + /* Set log level */ + if(level != prev_level) { + log_set_level(module, level); + if(!strcmp(module, "mac") || !strcmp(module, "all")) { + if(level >= LOG_LEVEL_DBG) { + tsch_log_init(); + SHELL_OUTPUT(output, "TSCH logging started\n"); + } else { + tsch_log_stop(); + SHELL_OUTPUT(output, "TSCH logging stopped\n"); + } + } + } + + shell_output_log_levels(output); + + PT_END(pt); +} +/*---------------------------------------------------------------------------*/ +static +PT_THREAD(cmd_help(struct pt *pt, shell_output_func output, char *args)) +{ + struct shell_command_t *cmd_ptr; + + PT_BEGIN(pt); + + SHELL_OUTPUT(output, "Available commands:\n"); + cmd_ptr = shell_commands; + while(cmd_ptr->name != NULL) { + SHELL_OUTPUT(output, "%s\n", cmd_ptr->help); + cmd_ptr++; + } + + PT_END(pt); +} +/*---------------------------------------------------------------------------*/ +static +PT_THREAD(cmd_rpl_global_repair(struct pt *pt, shell_output_func output, char *args)) +{ + PT_BEGIN(pt); + + SHELL_OUTPUT(output, "Triggering RPL global repair\n") + rpl_global_repair(); + + PT_END(pt); +} +/*---------------------------------------------------------------------------*/ +static +PT_THREAD(cmd_rpl_local_repair(struct pt *pt, shell_output_func output, char *args)) +{ + PT_BEGIN(pt); + + SHELL_OUTPUT(output, "Triggering RPL local repair\n"); + rpl_local_repair("Shell"); + + PT_END(pt); +} +/*---------------------------------------------------------------------------*/ +static +PT_THREAD(cmd_ipaddr(struct pt *pt, shell_output_func output, char *args)) +{ + int i; + uint8_t state; + + PT_BEGIN(pt); + + SHELL_OUTPUT(output, "Node IPv6 addresses:\n"); + for(i = 0; i < UIP_DS6_ADDR_NB; i++) { + state = uip_ds6_if.addr_list[i].state; + if(uip_ds6_if.addr_list[i].isused && + (state == ADDR_TENTATIVE || state == ADDR_PREFERRED)) { + SHELL_OUTPUT(output, "-- "); + shell_output_6addr(output, &uip_ds6_if.addr_list[i].ipaddr); + SHELL_OUTPUT(output, "\n"); + } + } + + PT_END(pt); + +} +/*---------------------------------------------------------------------------*/ +static +PT_THREAD(cmd_ip_neighbors(struct pt *pt, shell_output_func output, char *args)) +{ + uip_ds6_nbr_t *nbr; + + PT_BEGIN(pt); + + nbr = uip_ds6_nbr_head(); + if(nbr == NULL) { + SHELL_OUTPUT(output, "Node IPv6 neighbors: none\n"); + PT_EXIT(pt); + } + + SHELL_OUTPUT(output, "Node IPv6 neighbors:\n"); + while(nbr != NULL) { + SHELL_OUTPUT(output, "-- "); + shell_output_6addr(output, uip_ds6_nbr_get_ipaddr(nbr)); + SHELL_OUTPUT(output, " <-> "); + shell_output_lladdr(output, (linkaddr_t *)uip_ds6_nbr_get_ll(nbr)); + SHELL_OUTPUT(output, ", router %u, state %s ", + nbr->isrouter, ds6_nbr_state_to_str(nbr->state)); + SHELL_OUTPUT(output, "\n"); + nbr = uip_ds6_nbr_next(nbr); + } + + PT_END(pt); + +} +/*---------------------------------------------------------------------------*/ +static +PT_THREAD(cmd_tsch_status(struct pt *pt, shell_output_func output, char *args)) +{ + PT_BEGIN(pt); + + SHELL_OUTPUT(output, "TSCH status:\n"); + + SHELL_OUTPUT(output, "-- Is coordinator: %u\n", tsch_is_coordinator); + SHELL_OUTPUT(output, "-- Is associated: %u\n", tsch_is_associated); + if(tsch_is_associated) { + struct tsch_neighbor *n = tsch_queue_get_time_source(); + SHELL_OUTPUT(output, "-- PAN ID: 0x%x\n", frame802154_get_pan_id()); + SHELL_OUTPUT(output, "-- Is PAN secured: %u\n", tsch_is_pan_secured); + SHELL_OUTPUT(output, "-- Join priority: %u\n", tsch_join_priority); + SHELL_OUTPUT(output, "-- Time source: "); + if(n != NULL) { + shell_output_lladdr(output, &n->addr); + SHELL_OUTPUT(output, "\n"); + } else { + SHELL_OUTPUT(output, "none\n"); + } + SHELL_OUTPUT(output, "-- Last synchronized: %lu seconds ago\n", (clock_time() - last_sync_time) / CLOCK_SECOND); + SHELL_OUTPUT(output, "-- Drift w.r.t. coordinator: %ld ppm\n", tsch_adaptive_timesync_get_drift_ppm()); + } + + PT_END(pt); +} +/*---------------------------------------------------------------------------*/ +static +PT_THREAD(cmd_rpl_status(struct pt *pt, shell_output_func output, char *args)) +{ + PT_BEGIN(pt); + + SHELL_OUTPUT(output, "RPL status:\n"); + if(!curr_instance.used) { + SHELL_OUTPUT(output, "-- Instance: None\n"); + } else { + SHELL_OUTPUT(output, "-- Instance: %u\n", curr_instance.instance_id); + if(rpl_dag_root_is_root()) { + SHELL_OUTPUT(output, "-- DAG root\n"); + } else { + SHELL_OUTPUT(output, "-- DAG node\n"); + } + SHELL_OUTPUT(output, "-- DAG: "); + shell_output_6addr(output, &curr_instance.dag.dag_id); + SHELL_OUTPUT(output, ", version %u\n", curr_instance.dag.version); + SHELL_OUTPUT(output, "-- Prefix: "); + shell_output_6addr(output, &curr_instance.dag.prefix_info.prefix); + SHELL_OUTPUT(output, "/%u\n", curr_instance.dag.prefix_info.length); + SHELL_OUTPUT(output, "-- MOP: %s\n", rpl_mop_to_str(curr_instance.mop)); + SHELL_OUTPUT(output, "-- OF: %s\n", rpl_ocp_to_str(curr_instance.of->ocp)); + SHELL_OUTPUT(output, "-- Hop rank increment: %u\n", curr_instance.min_hoprankinc); + SHELL_OUTPUT(output, "-- Default lifetime: %lu seconds\n", RPL_LIFETIME(curr_instance.default_lifetime)); + + SHELL_OUTPUT(output, "-- State: %s\n", rpl_state_to_str(curr_instance.dag.state)); + SHELL_OUTPUT(output, "-- Preferred parent: "); + shell_output_6addr(output, rpl_neighbor_get_ipaddr(curr_instance.dag.preferred_parent)); + SHELL_OUTPUT(output, "\n"); + SHELL_OUTPUT(output, "-- Rank: %u\n", curr_instance.dag.rank); + SHELL_OUTPUT(output, "-- Lowest rank: %u (%u)\n", curr_instance.dag.lowest_rank, curr_instance.max_rankinc); + SHELL_OUTPUT(output, "-- DTSN out: %u\n", curr_instance.dtsn_out); + SHELL_OUTPUT(output, "-- DAO sequence: last sent %u, last acked %u\n", + curr_instance.dag.dao_last_seqno, curr_instance.dag.dao_last_acked_seqno); + SHELL_OUTPUT(output, "-- Trickle timer: current %u, min %u, max %u, redundancy %u\n", + curr_instance.dag.dio_intcurrent, curr_instance.dio_intmin, + curr_instance.dio_intmin + curr_instance.dio_intdoubl, curr_instance.dio_redundancy); + + } + + PT_END(pt); +} +/*---------------------------------------------------------------------------*/ +static +PT_THREAD(cmd_routes(struct pt *pt, shell_output_func output, char *args)) +{ + uip_ds6_defrt_t *default_route; +#if RPL_WITH_NON_STORING + rpl_ns_node_t *link; +#endif /* RPL_WITH_NON_STORING */ +#if RPL_WITH_STORING + uip_ds6_route_t *route; +#endif /* RPL_WITH_STORING */ + + PT_BEGIN(pt); + + /* Our default route */ + SHELL_OUTPUT(output, "Default route:\n"); + default_route = uip_ds6_defrt_lookup(uip_ds6_defrt_choose()); + if(default_route != NULL) { + SHELL_OUTPUT(output, "-- "); + shell_output_6addr(output, &default_route->ipaddr); + if(default_route->lifetime.interval != 0) { + SHELL_OUTPUT(output, " (lifetime: %lu seconds)\n", (unsigned long)default_route->lifetime.interval); + } else { + SHELL_OUTPUT(output, " (lifetime: infinite)\n"); + } + } else { + SHELL_OUTPUT(output, "-- None\n"); + } + +#if RPL_WITH_NON_STORING + if(rpl_ns_num_nodes() > 0) { + /* Our routing links */ + SHELL_OUTPUT(output, "Routing links (%u in total):\n", rpl_ns_num_nodes()); + link = rpl_ns_node_head(); + while(link != NULL) { + uip_ipaddr_t child_ipaddr; + uip_ipaddr_t parent_ipaddr; + rpl_ns_get_node_global_addr(&child_ipaddr, link); + rpl_ns_get_node_global_addr(&parent_ipaddr, link->parent); + SHELL_OUTPUT(output, "-- "); + shell_output_6addr(output, &child_ipaddr); + if(link->parent == NULL) { + memset(&parent_ipaddr, 0, sizeof(parent_ipaddr)); + SHELL_OUTPUT(output, " (DODAG root)"); + } else { + SHELL_OUTPUT(output, " to "); + shell_output_6addr(output, &parent_ipaddr); + } + if(link->lifetime != RPL_ROUTE_INFINITE_LIFETIME) { + SHELL_OUTPUT(output, " (lifetime: %lu seconds)\n", (unsigned long)link->lifetime); + } else { + SHELL_OUTPUT(output, " (lifetime: infinite)\n"); + } + link = rpl_ns_node_next(link); + } + } else { + SHELL_OUTPUT(output, "No routing links\n"); + } +#endif /* RPL_WITH_NON_STORING */ + +#if RPL_WITH_STORING + if(uip_ds6_route_num_routes() > 0) { + /* Our routing entries */ + SHELL_OUTPUT(output, "Routing entries (%u in total):\n", uip_ds6_route_num_routes()); + route = uip_ds6_route_head(); + while(route != NULL) { + SHELL_OUTPUT(output, "-- "); + shell_output_6addr(output, &route->ipaddr); + SHELL_OUTPUT(output, " via "); + shell_output_6addr(output, uip_ds6_route_nexthop(route)); + if((unsigned long)route->state.lifetime != RPL_ROUTE_INFINITE_LIFETIME) { + SHELL_OUTPUT(output, " (lifetime: %lu seconds)\n", (unsigned long)route->state.lifetime); + } else { + SHELL_OUTPUT(output, " (lifetime: infinite)\n"); + } + route = uip_ds6_route_next(route); + } + } else { + SHELL_OUTPUT(output, "No routing entries\n"); + } +#endif /* RPL_WITH_STORING */ + + PT_END(pt); +} +/*---------------------------------------------------------------------------*/ +static +PT_THREAD(cmd_tsch_schedule(struct pt *pt, shell_output_func output, char *args)) +{ + struct tsch_slotframe *sf; + + PT_BEGIN(pt); + + if(tsch_is_locked()) { + PT_EXIT(pt); + } + + sf = tsch_schedule_slotframe_head(); + + if(sf == NULL) { + SHELL_OUTPUT(output, "TSCH schedule: no slotframe\n"); + } else { + SHELL_OUTPUT(output, "TSCH schedule:\n"); + while(sf != NULL) { + struct tsch_link *l = list_head(sf->links_list); + + SHELL_OUTPUT(output, "-- Slotframe: handle %u, size %u, links:\n", sf->handle, sf->size.val); + + while(l != NULL) { + SHELL_OUTPUT(output, "---- Options %02x, type %u, timeslot %u, channel offset %u, address ", + l->link_options, l->link_type, l->timeslot, l->channel_offset); + shell_output_lladdr(output, &l->addr); + SHELL_OUTPUT(output, "\n"); + l = list_item_next(l); + } + + sf = tsch_schedule_slotframe_next(sf); + } + } + PT_END(pt); +} +/*---------------------------------------------------------------------------*/ +void +shell_commands_init(void) +{ + /* Set up Ping Reply callback */ + uip_icmp6_echo_reply_callback_add(&echo_reply_notification, + echo_reply_handler); +} +/*---------------------------------------------------------------------------*/ +struct shell_command_t shell_commands[] = { + { "help", cmd_help, "'> help': Shows this help" }, + { "ip-addr", cmd_ipaddr, "'> ip-addr': Shows all IPv6 addresses" }, + { "ip-nbr", cmd_ip_neighbors, "'> ip-nbr': Shows all IPv6 neighbors" }, + { "log", cmd_log, "'> log module level': Sets log level (0--4) for a given module (or \"all\"). For module \"mac\", level 4 also enables per-slot logging." }, + { "ping", cmd_ping, "'> ping addr': Pings the IPv6 address 'addr'" }, + { "rpl-set-root", cmd_rpl_set_root, "'> rpl-set-root 0/1 [prefix]': Sets node as root (on) or not (off). A /64 prefix can be optionally specified." }, + { "rpl-status", cmd_rpl_status, "'> rpl-status': Shows a summary of the current RPL state" }, + { "rpl-global-repair", cmd_rpl_global_repair, "'> rpl-global-repair': Triggers a RPL global repair" }, + { "rpl-local-repair", cmd_rpl_local_repair, "'> rpl-local-repair': Triggers a RPL local repair" }, + { "routes", cmd_routes, "'> routes': Shows the route entries" }, + { "tsch-schedule", cmd_tsch_schedule, "'> tsch-schedule': Shows the current TSCH schedule" }, + { "tsch-status", cmd_tsch_status, "'> tsch-status': Shows a summary of the current TSCH state" }, + { NULL, NULL, NULL }, +}; + +/** @} */ diff --git a/apps/shell/shell-commands.h b/apps/shell/shell-commands.h new file mode 100644 index 000000000..4e6aa0f40 --- /dev/null +++ b/apps/shell/shell-commands.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2017, Inria. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + */ + +/** + * \file + * Main header file for the Contiki shell + * \author + * Simon Duquennoy + */ + +/** \addtogroup apps + * @{ */ + +#ifndef _SHELL_COMMANDS_H_ +#define _SHELL_COMMANDS_H_ + +/* Command handling function type */ +typedef char (shell_commands_func)(struct pt *pt, shell_output_func output, char *args); + +/* Command structure */ +struct shell_command_t { + const char *name; + shell_commands_func *func; + const char *help; +}; + +/* The set of supported commands */ +extern struct shell_command_t shell_commands[]; + +/** + * Initializes Shell-commands module + */ +void shell_commands_init(void); + +#endif /* _SHELL_COMMANDS_H_ */ + +/** @} */ diff --git a/apps/shell/shell.c b/apps/shell/shell.c new file mode 100644 index 000000000..d6ef20ccb --- /dev/null +++ b/apps/shell/shell.c @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2018, Inria. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + */ + +/** + * \file + * The shell application + * \author + * Simon Duquennoy + */ + +/** + * \addtogroup shell + * @{ + */ + +#include "contiki.h" +#include "shell.h" +#include "shell-commands.h" +#include "net/ip/uip.h" +#include "net/ip/ip64-addr.h" + +/*---------------------------------------------------------------------------*/ +void +shell_output_6addr(shell_output_func output, const uip_ipaddr_t *ipaddr) +{ + uint16_t a; + unsigned int i; + int f; + + if(ipaddr == NULL) { + SHELL_OUTPUT(output, "(NULL IP addr)"); + return; + } + + if(ip64_addr_is_ipv4_mapped_addr(ipaddr)) { + /* Printing IPv4-mapped addresses is done according to RFC 4291 */ + SHELL_OUTPUT(output, "::FFFF:%u.%u.%u.%u", ipaddr->u8[12], ipaddr->u8[13], ipaddr->u8[14], ipaddr->u8[15]); + } else { + for(i = 0, f = 0; i < sizeof(uip_ipaddr_t); i += 2) { + a = (ipaddr->u8[i] << 8) + ipaddr->u8[i + 1]; + if(a == 0 && f >= 0) { + if(f++ == 0) { + SHELL_OUTPUT(output, "::"); + } + } else { + if(f > 0) { + f = -1; + } else if(i > 0) { + SHELL_OUTPUT(output, ":"); + } + SHELL_OUTPUT(output, "%x", a); + } + } + } +} +/*---------------------------------------------------------------------------*/ +void +shell_output_lladdr(shell_output_func output, const linkaddr_t *lladdr) +{ + if(lladdr == NULL) { + SHELL_OUTPUT(output, "(NULL LL addr)"); + return; + } else { + unsigned int i; + for(i = 0; i < LINKADDR_SIZE; i++) { + if(i > 0 && i % 2 == 0) { + SHELL_OUTPUT(output, "."); + } + SHELL_OUTPUT(output, "%02x", lladdr->u8[i]); + } + } +} +/*---------------------------------------------------------------------------*/ +static void +output_prompt(shell_output_func output) +{ + shell_output_lladdr(output, &linkaddr_node_addr); + SHELL_OUTPUT(output, "> "); +} +/*---------------------------------------------------------------------------*/ +PT_THREAD(shell_input(struct pt *pt, shell_output_func output, const char *cmd)) +{ + static char *args; + static struct shell_command_t *cmd_ptr; + + PT_BEGIN(pt); + + /* Shave off any leading spaces. */ + while(*cmd == ' ') { + cmd++; + } + + /* Look for arguments */ + args = strchr(cmd, ' '); + if(args != NULL) { + *args = '\0'; + args++; + } + + /* Lookup for command */ + cmd_ptr = shell_commands; + while(cmd_ptr->name != NULL) { + if(strcmp(cmd, cmd_ptr->name) == 0) { + static struct pt cmd_pt; + PT_SPAWN(pt, &cmd_pt, cmd_ptr->func(&cmd_pt, output, args)); + goto done; + } + cmd_ptr++; + } + + SHELL_OUTPUT(output, "Command not found. Type 'help' for a list of commands\n"); + +done: + output_prompt(output); + PT_END(pt); +} +/*---------------------------------------------------------------------------*/ +void +shell_init(void) +{ + shell_commands_init(); +} +/** @} */ diff --git a/apps/shell/shell.h b/apps/shell/shell.h new file mode 100644 index 000000000..938cb6998 --- /dev/null +++ b/apps/shell/shell.h @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2017, Inria. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + */ + +/** + * \file + * Main header file for the Contiki shell + * \author + * Simon Duquennoy + */ + +/** \addtogroup apps + * @{ */ + +#ifndef SHELL_H_ +#define SHELL_H_ + +#include "net/ip/uip.h" +#include "net/linkaddr.h" +#include "sys/process.h" +#include + +/* Helper macros to parse arguments */ +#define SHELL_ARGS_INIT(args, next_args) (next_args) = (args); + +#define SHELL_ARGS_NEXT(args, next_args) do { \ + (args) = (next_args); \ + if((args) != NULL) { \ + if(*(args) == '\0') { \ + (args) = NULL; \ + } else { \ + (next_args) = strchr((args), ' '); \ + if((next_args) != NULL) { \ + *(next_args) = '\0'; \ + (next_args)++; \ + } \ + } \ + } else { \ + (next_args) = NULL; \ + } \ + } while(0) + +/* Printf-formatted output via a given output function */ +#define SHELL_OUTPUT(output_func, format, ...) do { \ + char buffer[128]; \ + snprintf(buffer, sizeof(buffer), format, ##__VA_ARGS__); \ + (output_func)(buffer); \ + } while(0); + +typedef void (shell_output_func)(const char *str); + +/** + * Initializes Shell module + */ +void shell_init(void); + +/** + * \brief A protothread that is spawned by a Shell driver when receiving a new line. + */ + PT_THREAD(shell_input(struct pt *pt, shell_output_func output, const char *cmd)); + +/** + * Prints an IPv6 address + * + * \param output The output function + * \param ipaddr The IPv6 to printed + */ +void shell_output_6addr(shell_output_func output, const uip_ipaddr_t *ipaddr); + +/** + * Prints a link-layer address + * + * \param output The output function + * \param lladdr The link-layer to be printed + */ +void shell_output_lladdr(shell_output_func output, const linkaddr_t *lladdr); + +#endif /* SHELL_H_ */ + +/** @} */ diff --git a/arch/platform/cc2538dk/contiki-conf.h b/arch/platform/cc2538dk/contiki-conf.h index 23e9dc60d..307b015fe 100644 --- a/arch/platform/cc2538dk/contiki-conf.h +++ b/arch/platform/cc2538dk/contiki-conf.h @@ -45,6 +45,11 @@ typedef uint32_t rtimer_clock_t; /* 192us as in datasheet but ACKs are not always received, so adjusted to 250us */ #define RADIO_DELAY_BEFORE_RX ((unsigned)US_TO_RTIMERTICKS(250)) #define RADIO_DELAY_BEFORE_DETECT 0 +#ifndef TSCH_CONF_BASE_DRIFT_PPM +/* The drift compared to "true" 10ms slots. + * Enable adaptive sync to enable compensation for this. */ +#define TSCH_CONF_BASE_DRIFT_PPM -977 +#endif /*---------------------------------------------------------------------------*/ /** * \name Serial Boot Loader Backdoor configuration diff --git a/arch/platform/jn516x/lib/sprintf.c b/arch/platform/jn516x/lib/sprintf.c index 500951e92..ed93f9885 100644 --- a/arch/platform/jn516x/lib/sprintf.c +++ b/arch/platform/jn516x/lib/sprintf.c @@ -92,10 +92,12 @@ vsnprintf(char *str, size_t n, const char *fmt, __VALIST va) ch = *(fmt++); lz = 1; } - if(ch >= '0' && ch <= '9') { + if(ch == '-' || (ch >= '0' && ch <= '9')) { w = 0; - while(ch >= '0' && ch <= '9') { - w = (((w << 2) + w) << 1) + ch - '0'; + while(ch == '-' || (ch >= '0' && ch <= '9')) { + if(ch != '-') { + w = (((w << 2) + w) << 1) + ch - '0'; + } ch = *fmt++; } } diff --git a/arch/platform/openmote-cc2538/contiki-conf.h b/arch/platform/openmote-cc2538/contiki-conf.h index 83c975b7e..d28a85ba3 100644 --- a/arch/platform/openmote-cc2538/contiki-conf.h +++ b/arch/platform/openmote-cc2538/contiki-conf.h @@ -84,6 +84,11 @@ typedef uint32_t rtimer_clock_t; /* 192us as in datasheet but ACKs are not always received, so adjusted to 250us */ #define RADIO_DELAY_BEFORE_RX ((unsigned)US_TO_RTIMERTICKS(250)) #define RADIO_DELAY_BEFORE_DETECT 0 +#ifndef TSCH_CONF_BASE_DRIFT_PPM +/* The drift compared to "true" 10ms slots. + * Enable adaptive sync to enable compensation for this. */ +#define TSCH_CONF_BASE_DRIFT_PPM -977 +#endif /*---------------------------------------------------------------------------*/ /** * \name Serial Boot Loader Backdoor configuration diff --git a/arch/platform/zoul/contiki-conf.h b/arch/platform/zoul/contiki-conf.h index 59ab8a665..38b34e5ad 100644 --- a/arch/platform/zoul/contiki-conf.h +++ b/arch/platform/zoul/contiki-conf.h @@ -82,6 +82,11 @@ typedef uint32_t rtimer_clock_t; /* 192us as in datasheet but ACKs are not always received, so adjusted to 250us */ #define RADIO_DELAY_BEFORE_RX ((unsigned)US_TO_RTIMERTICKS(250)) #define RADIO_DELAY_BEFORE_DETECT 0 +#ifndef TSCH_CONF_BASE_DRIFT_PPM +/* The drift compared to "true" 10ms slots. + * Enable adaptive sync to enable compensation for this. */ +#define TSCH_CONF_BASE_DRIFT_PPM -977 +#endif /*---------------------------------------------------------------------------*/ /** * \name Serial Boot Loader Backdoor configuration diff --git a/core/net/ip/tcpip.c b/core/net/ip/tcpip.c index bf6d328e4..79ae9702f 100644 --- a/core/net/ip/tcpip.c +++ b/core/net/ip/tcpip.c @@ -58,7 +58,7 @@ /* Log configuration */ #include "sys/log.h" #define LOG_MODULE "TCP/IP" -#define LOG_LEVEL TCPIP_LOG_LEVEL +#define LOG_LEVEL LOG_LEVEL_TCPIP #define UIP_ICMP_BUF ((struct uip_icmp_hdr *)&uip_buf[UIP_LLIPH_LEN + uip_ext_len]) #define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN]) @@ -672,6 +672,15 @@ tcpip_ipv6_output(void) goto send_packet; } + /* We first check if the destination address is one of ours. There is no + * loopback interface -- instead, process this directly as incoming. */ + if(uip_ds6_is_my_addr(&UIP_IP_BUF->destipaddr)) { + LOG_INFO("output: sending to ourself\n"); + packet_input(); + return; + } + + /* Look for a next hop */ if((nexthop = get_nexthop(&ipaddr)) == NULL) { goto exit; } diff --git a/core/net/ipv6/sicslowpan.c b/core/net/ipv6/sicslowpan.c index 95064e8ea..22569aebe 100644 --- a/core/net/ipv6/sicslowpan.c +++ b/core/net/ipv6/sicslowpan.c @@ -81,7 +81,7 @@ /* Log configuration */ #include "sys/log.h" #define LOG_MODULE "6LoWPAN" -#define LOG_LEVEL SICSLOWPAN_LOG_LEVEL +#define LOG_LEVEL LOG_LEVEL_6LOWPAN #ifdef SICSLOWPAN_CONF_COMPRESSION #define SICSLOWPAN_COMPRESSION SICSLOWPAN_CONF_COMPRESSION @@ -1726,6 +1726,11 @@ input(void) /* The MAC puts the 15.4 payload inside the packetbuf data buffer */ packetbuf_ptr = packetbuf_dataptr(); + if(packetbuf_datalen() == 0) { + LOG_WARN("empty packet\n"); + return; + } + /* This is default uip_buf since we assume that this is not fragmented */ buffer = (uint8_t *)UIP_IP_BUF; diff --git a/core/net/ipv6/uip-ds6-nbr.c b/core/net/ipv6/uip-ds6-nbr.c index 90ff7e27e..790adbeba 100644 --- a/core/net/ipv6/uip-ds6-nbr.c +++ b/core/net/ipv6/uip-ds6-nbr.c @@ -55,7 +55,7 @@ /* Log configuration */ #include "sys/log.h" #define LOG_MODULE "IPv6 Nbr" -#define LOG_LEVEL IPV6_LOG_LEVEL +#define LOG_LEVEL LOG_LEVEL_IPV6 #ifdef UIP_CONF_DS6_NEIGHBOR_STATE_CHANGED #define NEIGHBOR_STATE_CHANGED(n) UIP_CONF_DS6_NEIGHBOR_STATE_CHANGED(n) @@ -161,6 +161,18 @@ uip_ds6_nbr_num(void) } /*---------------------------------------------------------------------------*/ uip_ds6_nbr_t * +uip_ds6_nbr_head(void) +{ + return nbr_table_head(ds6_neighbors); +} +/*---------------------------------------------------------------------------*/ +uip_ds6_nbr_t * +uip_ds6_nbr_next(uip_ds6_nbr_t *nbr) +{ + return nbr_table_next(ds6_neighbors, nbr); +} +/*---------------------------------------------------------------------------*/ +uip_ds6_nbr_t * uip_ds6_nbr_lookup(const uip_ipaddr_t *ipaddr) { uip_ds6_nbr_t *nbr = nbr_table_head(ds6_neighbors); diff --git a/core/net/ipv6/uip-ds6-nbr.h b/core/net/ipv6/uip-ds6-nbr.h index e4a2fee42..6e199a11f 100644 --- a/core/net/ipv6/uip-ds6-nbr.h +++ b/core/net/ipv6/uip-ds6-nbr.h @@ -97,6 +97,8 @@ const uip_lladdr_t *uip_ds6_nbr_lladdr_from_ipaddr(const uip_ipaddr_t *ipaddr); void uip_ds6_link_callback(int status, int numtx); void uip_ds6_neighbor_periodic(void); int uip_ds6_nbr_num(void); +uip_ds6_nbr_t *uip_ds6_nbr_head(void); +uip_ds6_nbr_t *uip_ds6_nbr_next(uip_ds6_nbr_t *nbr); #if UIP_ND6_SEND_NS /** diff --git a/core/net/ipv6/uip-ds6-route.c b/core/net/ipv6/uip-ds6-route.c index eb2479290..ab727e36f 100644 --- a/core/net/ipv6/uip-ds6-route.c +++ b/core/net/ipv6/uip-ds6-route.c @@ -49,7 +49,7 @@ /* Log configuration */ #include "sys/log.h" #define LOG_MODULE "IPv6 Route" -#define LOG_LEVEL IPV6_LOG_LEVEL +#define LOG_LEVEL LOG_LEVEL_IPV6 /* A configurable function called after adding a new neighbor as next hop */ #ifdef NETSTACK_CONF_ROUTING_NEIGHBOR_ADDED_CALLBACK diff --git a/core/net/ipv6/uip-ds6.c b/core/net/ipv6/uip-ds6.c index 6e7be7b66..11a67e172 100644 --- a/core/net/ipv6/uip-ds6.c +++ b/core/net/ipv6/uip-ds6.c @@ -54,7 +54,7 @@ /* Log configuration */ #include "sys/log.h" #define LOG_MODULE "IPv6 DS" -#define LOG_LEVEL IPV6_LOG_LEVEL +#define LOG_LEVEL LOG_LEVEL_IPV6 struct etimer uip_ds6_timer_periodic; /**< Timer for maintenance of data structures */ diff --git a/core/net/ipv6/uip-icmp6.c b/core/net/ipv6/uip-icmp6.c index 9e28abc92..c2dbe0f85 100644 --- a/core/net/ipv6/uip-icmp6.c +++ b/core/net/ipv6/uip-icmp6.c @@ -50,7 +50,7 @@ /* Log configuration */ #include "sys/log.h" #define LOG_MODULE "ICMPv6" -#define LOG_LEVEL IPV6_LOG_LEVEL +#define LOG_LEVEL LOG_LEVEL_IPV6 #define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN]) #define UIP_ICMP_BUF ((struct uip_icmp_hdr *)&uip_buf[uip_l2_l3_hdr_len]) @@ -268,6 +268,9 @@ uip_icmp6_error_output(uint8_t type, uint8_t code, uint32_t param) { void uip_icmp6_send(const uip_ipaddr_t *dest, int type, int code, int payload_len) { + LOG_INFO("Sending ICMPv6 packet to "); + LOG_INFO_6ADDR(&UIP_IP_BUF->destipaddr); + LOG_INFO_(", type %u, code %u, len %u\n", type, code, payload_len); UIP_IP_BUF->vtc = 0x60; UIP_IP_BUF->tcflow = 0; diff --git a/core/net/ipv6/uip-nd6.c b/core/net/ipv6/uip-nd6.c index cba9c320c..a432b934e 100644 --- a/core/net/ipv6/uip-nd6.c +++ b/core/net/ipv6/uip-nd6.c @@ -78,7 +78,7 @@ /* Log configuration */ #include "sys/log.h" #define LOG_MODULE "IPv6 NDP" -#define LOG_LEVEL IPV6_LOG_LEVEL +#define LOG_LEVEL LOG_LEVEL_IPV6 /*------------------------------------------------------------------*/ /** @{ */ diff --git a/core/net/ipv6/uip6.c b/core/net/ipv6/uip6.c index 8398a4f95..0df737f43 100644 --- a/core/net/ipv6/uip6.c +++ b/core/net/ipv6/uip6.c @@ -96,7 +96,7 @@ /* Log configuration */ #include "sys/log.h" #define LOG_MODULE "IPv6" -#define LOG_LEVEL IPV6_LOG_LEVEL +#define LOG_LEVEL LOG_LEVEL_IPV6 /*---------------------------------------------------------------------------*/ /** diff --git a/core/net/ipv6/websocket-http-client.c b/core/net/ipv6/websocket-http-client.c index b712a42f2..4c407c75e 100644 --- a/core/net/ipv6/websocket-http-client.c +++ b/core/net/ipv6/websocket-http-client.c @@ -41,7 +41,7 @@ /* Log configuration */ #include "sys/log.h" #define LOG_MODULE "Websocket" -#define LOG_LEVEL IPV6_LOG_LEVEL +#define LOG_LEVEL LOG_LEVEL_IPV6 enum { STATE_WAITING_FOR_HEADER, diff --git a/core/net/ipv6/websocket.c b/core/net/ipv6/websocket.c index 9f1fe7a9d..04c6ba506 100644 --- a/core/net/ipv6/websocket.c +++ b/core/net/ipv6/websocket.c @@ -40,7 +40,7 @@ /* Log configuration */ #include "sys/log.h" #define LOG_MODULE "Websocket" -#define LOG_LEVEL IPV6_LOG_LEVEL +#define LOG_LEVEL LOG_LEVEL_IPV6 PROCESS(websocket_process, "Websockets process"); diff --git a/core/net/mac/csma/csma-output.c b/core/net/mac/csma/csma-output.c index 8f0bab4e2..ff63914d3 100644 --- a/core/net/mac/csma/csma-output.c +++ b/core/net/mac/csma/csma-output.c @@ -58,7 +58,7 @@ /* Log configuration */ #include "sys/log.h" #define LOG_MODULE "CSMA" -#define LOG_LEVEL MAC_LOG_LEVEL +#define LOG_LEVEL LOG_LEVEL_MAC /* Constants of the IEEE 802.15.4 standard */ diff --git a/core/net/mac/csma/csma.c b/core/net/mac/csma/csma.c index bdcb50c95..aa7a98a3d 100644 --- a/core/net/mac/csma/csma.c +++ b/core/net/mac/csma/csma.c @@ -47,7 +47,7 @@ /* Log configuration */ #include "sys/log.h" #define LOG_MODULE "CSMA" -#define LOG_LEVEL MAC_LOG_LEVEL +#define LOG_LEVEL LOG_LEVEL_MAC /*---------------------------------------------------------------------------*/ static void diff --git a/core/net/mac/framer/frame802154e-ie.c b/core/net/mac/framer/frame802154e-ie.c index 20eb98d8b..3ca529360 100644 --- a/core/net/mac/framer/frame802154e-ie.c +++ b/core/net/mac/framer/frame802154e-ie.c @@ -43,7 +43,7 @@ /* Log configuration */ #include "sys/log.h" #define LOG_MODULE "Frame 15.4" -#define LOG_LEVEL FRAMER_LOG_LEVEL +#define LOG_LEVEL LOG_LEVEL_FRAMER /* c.f. IEEE 802.15.4e Table 4b */ enum ieee802154e_header_ie_id { diff --git a/core/net/mac/framer/framer-802154.c b/core/net/mac/framer/framer-802154.c index dab21bda8..52445c0e7 100644 --- a/core/net/mac/framer/framer-802154.c +++ b/core/net/mac/framer/framer-802154.c @@ -46,7 +46,7 @@ /* Log configuration */ #include "sys/log.h" #define LOG_MODULE "Frame 15.4" -#define LOG_LEVEL FRAMER_LOG_LEVEL +#define LOG_LEVEL LOG_LEVEL_FRAMER /** \brief The sequence number (0x00 - 0xff) added to the transmitted * data or MAC command frame. The default is a random value within diff --git a/core/net/mac/mac.c b/core/net/mac/mac.c index 3a6ffff97..c8f8eb87b 100644 --- a/core/net/mac/mac.c +++ b/core/net/mac/mac.c @@ -35,7 +35,7 @@ /* Log configuration */ #include "sys/log.h" #define LOG_MODULE "MAC" -#define LOG_LEVEL MAC_LOG_LEVEL +#define LOG_LEVEL LOG_LEVEL_MAC /*---------------------------------------------------------------------------*/ void diff --git a/core/net/mac/tsch/tsch-adaptive-timesync.c b/core/net/mac/tsch/tsch-adaptive-timesync.c index 9c23e8f19..430db841d 100644 --- a/core/net/mac/tsch/tsch-adaptive-timesync.c +++ b/core/net/mac/tsch/tsch-adaptive-timesync.c @@ -59,6 +59,12 @@ static uint32_t asn_since_last_learning; /* Units in which drift is stored: ppm * 256 */ #define TSCH_DRIFT_UNIT (1000L * 1000 * 256) +/*---------------------------------------------------------------------------*/ +long int +tsch_adaptive_timesync_get_drift_ppm(void) +{ + return (long int)drift_ppm / 256; +} /*---------------------------------------------------------------------------*/ /* Add a value to a moving average estimator */ static int32_t @@ -101,7 +107,7 @@ timesync_learn_drift_ticks(uint32_t time_delta_asn, int32_t drift_ticks) TSCH_LOG_ADD(tsch_log_message, snprintf(log->message, sizeof(log->message), - "drift %ld", (long int)drift_ppm / 256)); + "drift %ld", tsch_adaptive_timesync_get_drift_ppm())); } /*---------------------------------------------------------------------------*/ /* Either reset or update the neighbor's drift */ diff --git a/core/net/mac/tsch/tsch-adaptive-timesync.h b/core/net/mac/tsch/tsch-adaptive-timesync.h index d043ca021..f928856a7 100644 --- a/core/net/mac/tsch/tsch-adaptive-timesync.h +++ b/core/net/mac/tsch/tsch-adaptive-timesync.h @@ -86,4 +86,6 @@ void tsch_timesync_update(struct tsch_neighbor *n, uint16_t time_delta_asn, int3 int32_t tsch_timesync_adaptive_compensate(rtimer_clock_t delta_ticks); +long int tsch_adaptive_timesync_get_drift_ppm(void); + #endif /* __TSCH_ADAPTIVE_TIMESYNC_H__ */ diff --git a/core/net/mac/tsch/tsch-log.c b/core/net/mac/tsch/tsch-log.c index f4089add7..e92311217 100644 --- a/core/net/mac/tsch/tsch-log.c +++ b/core/net/mac/tsch/tsch-log.c @@ -63,6 +63,7 @@ PROCESS_NAME(tsch_pending_events_process); static struct ringbufindex log_ringbuf; static struct tsch_log_t log_array[TSCH_LOG_QUEUE_LEN]; static int log_dropped = 0; +static int log_active = 0; /*---------------------------------------------------------------------------*/ /* Process pending log messages */ @@ -73,16 +74,16 @@ tsch_log_process_pending(void) int16_t log_index; /* Loop on accessing (without removing) a pending input packet */ if(log_dropped != last_log_dropped) { - printf("TSCH:! logs dropped %u\n", log_dropped); + printf("[WARN: TSCH-LOG ] logs dropped %u\n", log_dropped); last_log_dropped = log_dropped; } while((log_index = ringbufindex_peek_get(&log_ringbuf)) != -1) { struct tsch_log_t *log = &log_array[log_index]; if(log->link == NULL) { - printf("TSCH: {asn-%x.%lx link-NULL} ", log->asn.ms1b, log->asn.ls4b); + printf("[INFO: TSCH-LOG ] {asn-%x.%lx link-NULL} ", log->asn.ms1b, log->asn.ls4b); } else { struct tsch_slotframe *sf = tsch_schedule_get_slotframe_by_handle(log->link->slotframe_handle); - printf("TSCH: {asn-%x.%lx link-%u-%u-%u-%u ch-%u} ", + printf("[INFO: TSCH-LOG ] {asn-%x.%lx link-%u-%u-%u-%u ch-%u} ", log->asn.ms1b, log->asn.ls4b, log->link->slotframe_handle, sf ? sf->size.val : 0, log->link->timeslot, log->link->channel_offset, tsch_calculate_channel(&log->asn, log->link->channel_offset)); @@ -144,15 +145,30 @@ tsch_log_prepare_add(void) void tsch_log_commit(void) { - ringbufindex_put(&log_ringbuf); - process_poll(&tsch_pending_events_process); + if(log_active == 1) { + ringbufindex_put(&log_ringbuf); + process_poll(&tsch_pending_events_process); + } } /*---------------------------------------------------------------------------*/ /* Initialize log module */ void tsch_log_init(void) { - ringbufindex_init(&log_ringbuf, TSCH_LOG_QUEUE_LEN); + if(log_active == 0) { + ringbufindex_init(&log_ringbuf, TSCH_LOG_QUEUE_LEN); + log_active = 1; + } +} +/*---------------------------------------------------------------------------*/ +/* Stop log module */ +void +tsch_log_stop(void) +{ + if(log_active == 1) { + tsch_log_process_pending(); + log_active = 0; + } } #endif /* TSCH_LOG_PER_SLOT */ diff --git a/core/net/mac/tsch/tsch-log.h b/core/net/mac/tsch/tsch-log.h index d86a4c137..7c4acd7b4 100644 --- a/core/net/mac/tsch/tsch-log.h +++ b/core/net/mac/tsch/tsch-log.h @@ -46,7 +46,7 @@ #define TSCH_LOG_PER_SLOT TSCH_LOG_CONF_PER_SLOT #else /* TSCH_LOG_CONF_PER_SLOT */ #include "sys/log.h" -#define TSCH_LOG_PER_SLOT (MAC_LOG_LEVEL >= LOG_LEVEL_DBG) +#define TSCH_LOG_PER_SLOT (LOG_LEVEL_MAC >= LOG_LEVEL_DBG) #endif /* TSCH_LOG_CONF_PER_SLOT */ /* The length of the log queue, i.e. maximum number postponed log messages */ @@ -112,6 +112,8 @@ void tsch_log_commit(void); void tsch_log_init(void); /* Process pending log messages */ void tsch_log_process_pending(void); +/* Stop logging module */ +void tsch_log_stop(void); /************ Macros **********/ diff --git a/core/net/mac/tsch/tsch-packet.c b/core/net/mac/tsch/tsch-packet.c index b1fbd23cc..e39766af9 100644 --- a/core/net/mac/tsch/tsch-packet.c +++ b/core/net/mac/tsch/tsch-packet.c @@ -54,7 +54,7 @@ /* Log configuration */ #include "sys/log.h" #define LOG_MODULE "TSCH Pkt" -#define LOG_LEVEL MAC_LOG_LEVEL +#define LOG_LEVEL LOG_LEVEL_MAC /*---------------------------------------------------------------------------*/ /* Construct enhanced ACK packet and return ACK length */ diff --git a/core/net/mac/tsch/tsch-queue.c b/core/net/mac/tsch/tsch-queue.c index b101f8407..3e940a823 100644 --- a/core/net/mac/tsch/tsch-queue.c +++ b/core/net/mac/tsch/tsch-queue.c @@ -58,7 +58,7 @@ /* Log configuration */ #include "sys/log.h" #define LOG_MODULE "TSCH Queue" -#define LOG_LEVEL MAC_LOG_LEVEL +#define LOG_LEVEL LOG_LEVEL_MAC /* Check if TSCH_QUEUE_NUM_PER_NEIGHBOR is power of two */ #if (TSCH_QUEUE_NUM_PER_NEIGHBOR & (TSCH_QUEUE_NUM_PER_NEIGHBOR - 1)) != 0 diff --git a/core/net/mac/tsch/tsch-rpl.c b/core/net/mac/tsch/tsch-rpl.c index 5689922fc..a609d614a 100644 --- a/core/net/mac/tsch/tsch-rpl.c +++ b/core/net/mac/tsch/tsch-rpl.c @@ -54,7 +54,7 @@ /* Log configuration */ #include "sys/log.h" #define LOG_MODULE "TSCH RPL" -#define LOG_LEVEL MAC_LOG_LEVEL +#define LOG_LEVEL LOG_LEVEL_MAC /*---------------------------------------------------------------------------*/ /* To use, set #define TSCH_CALLBACK_KA_SENT tsch_rpl_callback_ka_sent */ diff --git a/core/net/mac/tsch/tsch-schedule.c b/core/net/mac/tsch/tsch-schedule.c index 378a34ff8..e22b0b498 100644 --- a/core/net/mac/tsch/tsch-schedule.c +++ b/core/net/mac/tsch/tsch-schedule.c @@ -58,7 +58,7 @@ /* Log configuration */ #include "sys/log.h" #define LOG_MODULE "TSCH Sched" -#define LOG_LEVEL MAC_LOG_LEVEL +#define LOG_LEVEL LOG_LEVEL_MAC /* Pre-allocated space for links */ MEMB(link_memb, struct tsch_link, TSCH_SCHEDULE_MAX_LINKS); @@ -418,6 +418,18 @@ tsch_schedule_create_minimal(void) 0, 0); } /*---------------------------------------------------------------------------*/ +struct tsch_slotframe * +tsch_schedule_slotframe_head(void) +{ + return list_head(slotframe_list); +} +/*---------------------------------------------------------------------------*/ +struct tsch_slotframe * +tsch_schedule_slotframe_next(struct tsch_slotframe *sf) +{ + return list_item_next(sf); +} +/*---------------------------------------------------------------------------*/ /* Prints out the current schedule (all slotframes and links) */ void tsch_schedule_print(void) diff --git a/core/net/mac/tsch/tsch-schedule.h b/core/net/mac/tsch/tsch-schedule.h index 75f757e66..1099664a9 100644 --- a/core/net/mac/tsch/tsch-schedule.h +++ b/core/net/mac/tsch/tsch-schedule.h @@ -160,5 +160,8 @@ int tsch_schedule_remove_link_by_timeslot(struct tsch_slotframe *slotframe, uint /* Returns the next active link after a given ASN, and a backup link (for the same ASN, with Rx flag) */ struct tsch_link * tsch_schedule_get_next_active_link(struct tsch_asn_t *asn, uint16_t *time_offset, struct tsch_link **backup_link); +/* Access to slotframe list */ +struct tsch_slotframe *tsch_schedule_slotframe_head(void); +struct tsch_slotframe *tsch_schedule_slotframe_next(struct tsch_slotframe *sf); #endif /* __TSCH_SCHEDULE_H__ */ diff --git a/core/net/mac/tsch/tsch-slot-operation.c b/core/net/mac/tsch/tsch-slot-operation.c index 4b2b9faf2..d84a1998d 100644 --- a/core/net/mac/tsch/tsch-slot-operation.c +++ b/core/net/mac/tsch/tsch-slot-operation.c @@ -134,6 +134,7 @@ struct input_packet input_array[TSCH_MAX_INCOMING_PACKETS]; /* Last time we received Sync-IE (ACK or data packet from a time source) */ static struct tsch_asn_t last_sync_asn; +clock_time_t last_sync_time; /* Same info, in clock_time_t units */ /* A global lock for manipulating data structures safely from outside of interrupt */ static volatile int tsch_locked = 0; @@ -614,6 +615,7 @@ PT_THREAD(tsch_tx_slot(struct pt *pt, struct rtimer *t)) tsch_timesync_update(current_neighbor, since_last_timesync, drift_correction); /* Keep track of sync time */ last_sync_asn = tsch_current_asn; + last_sync_time = clock_time(); tsch_schedule_keepalive(); } mac_tx_status = MAC_TX_OK; @@ -851,6 +853,7 @@ PT_THREAD(tsch_rx_slot(struct pt *pt, struct rtimer *t)) int32_t since_last_timesync = TSCH_ASN_DIFF(tsch_current_asn, last_sync_asn); /* Keep track of last sync time */ last_sync_asn = tsch_current_asn; + last_sync_time = clock_time(); /* Save estimated drift */ drift_correction = -estimated_drift; is_drift_correction_used = 1; @@ -1053,6 +1056,7 @@ tsch_slot_operation_sync(rtimer_clock_t next_slot_start, current_slot_start = next_slot_start; tsch_current_asn = *next_slot_asn; last_sync_asn = tsch_current_asn; + last_sync_time = clock_time(); current_link = NULL; } /*---------------------------------------------------------------------------*/ diff --git a/core/net/mac/tsch/tsch-slot-operation.h b/core/net/mac/tsch/tsch-slot-operation.h index c6af61ce2..74e054b55 100644 --- a/core/net/mac/tsch/tsch-slot-operation.h +++ b/core/net/mac/tsch/tsch-slot-operation.h @@ -103,6 +103,8 @@ extern struct tsch_packet *dequeued_array[TSCH_DEQUEUED_ARRAY_SIZE]; * Will be processed layer by tsch_rx_process_pending */ extern struct ringbufindex input_ringbuf; extern struct input_packet input_array[TSCH_MAX_INCOMING_PACKETS]; +/* Last clock_time_t where synchronization happened */ +extern clock_time_t last_sync_time; /********** Functions *********/ diff --git a/core/net/mac/tsch/tsch.c b/core/net/mac/tsch/tsch.c index 567c88af4..a20971ea8 100644 --- a/core/net/mac/tsch/tsch.c +++ b/core/net/mac/tsch/tsch.c @@ -69,7 +69,7 @@ /* Log configuration */ #include "sys/log.h" #define LOG_MODULE "TSCH" -#define LOG_LEVEL MAC_LOG_LEVEL +#define LOG_LEVEL LOG_LEVEL_MAC /* Use to collect link statistics even on Keep-Alive, even though they were * not sent from an upper layer and don't have a valid packet_sent callback */ diff --git a/core/net/mac/tsch/tsch.h b/core/net/mac/tsch/tsch.h index b56ffaf3a..d436b69af 100644 --- a/core/net/mac/tsch/tsch.h +++ b/core/net/mac/tsch/tsch.h @@ -107,7 +107,7 @@ #ifdef TSCH_CONF_JOIN_MY_PANID_ONLY #define TSCH_JOIN_MY_PANID_ONLY TSCH_CONF_JOIN_MY_PANID_ONLY #else -#define TSCH_JOIN_MY_PANID_ONLY 0 +#define TSCH_JOIN_MY_PANID_ONLY 1 #endif /* The radio polling frequency (in Hz) during association process */ diff --git a/core/net/rpl-lite/rpl-dag-root.c b/core/net/rpl-lite/rpl-dag-root.c index afb1b6c67..58af56e28 100644 --- a/core/net/rpl-lite/rpl-dag-root.c +++ b/core/net/rpl-lite/rpl-dag-root.c @@ -38,7 +38,7 @@ /* Log configuration */ #include "sys/log.h" #define LOG_MODULE "RPL" -#define LOG_LEVEL RPL_LOG_LEVEL +#define LOG_LEVEL LOG_LEVEL_RPL #define RPL_DAG_GRACE_PERIOD (CLOCK_SECOND * 20 * 1) diff --git a/core/net/rpl-lite/rpl-dag.c b/core/net/rpl-lite/rpl-dag.c index 4b39f40d8..99b721b74 100644 --- a/core/net/rpl-lite/rpl-dag.c +++ b/core/net/rpl-lite/rpl-dag.c @@ -51,7 +51,7 @@ /* Log configuration */ #include "sys/log.h" #define LOG_MODULE "RPL" -#define LOG_LEVEL RPL_LOG_LEVEL +#define LOG_LEVEL LOG_LEVEL_RPL /*---------------------------------------------------------------------------*/ extern rpl_of_t rpl_of0, rpl_mrhof; @@ -88,14 +88,17 @@ rpl_dag_leave(void) LOG_INFO_(", instance %u\n", curr_instance.instance_id); /* Issue a no-path DAO */ - RPL_LOLLIPOP_INCREMENT(curr_instance.dag.dao_curr_seqno); - rpl_icmp6_dao_output(0); + if(!rpl_dag_root_is_root()) { + RPL_LOLLIPOP_INCREMENT(curr_instance.dag.dao_curr_seqno); + rpl_icmp6_dao_output(0); + } /* Forget past link statistics */ link_stats_reset(); - /* Remove all neighbors */ + /* Remove all neighbors and lnks */ rpl_neighbor_remove_all(); + rpl_ns_free_all(); /* Stop all timers */ rpl_timers_stop_dag_timers(); @@ -110,6 +113,13 @@ rpl_dag_leave(void) } /*---------------------------------------------------------------------------*/ void +rpl_dag_poison_and_leave(void) +{ + curr_instance.dag.state = DAG_POISONING; + rpl_timers_schedule_state_update(); +} +/*---------------------------------------------------------------------------*/ +void rpl_dag_periodic(unsigned seconds) { if(curr_instance.used) { @@ -197,8 +207,10 @@ rpl_local_repair(const char *str) { if(curr_instance.used) { /* Check needed because this is a public function */ LOG_WARN("local repair (%s)\n", str); + if(!rpl_dag_root_is_root()) { + curr_instance.dag.state = DAG_INITIALIZED; /* Reset DAG state */ + } curr_instance.of->reset(); /* Reset OF */ - curr_instance.dag.state = DAG_INITIALIZED; /* Reset DAG state */ link_stats_reset(); /* Forget past link statistics */ rpl_neighbor_remove_all(); /* Remove all neighbors */ rpl_timers_dio_reset("Local repair"); /* Reset Trickle timer */ @@ -220,97 +232,98 @@ rpl_dag_ready_to_advertise(void) void rpl_dag_update_state(void) { - if(curr_instance.used) { - if(!rpl_dag_root_is_root()) { - rpl_nbr_t *old_parent = curr_instance.dag.preferred_parent; - rpl_rank_t old_rank = curr_instance.dag.rank; + rpl_rank_t old_rank; - /* Any scheduled state update is no longer needed */ - rpl_timers_unschedule_state_update(); + if(!curr_instance.used) { + return; + } - if(curr_instance.dag.state == DAG_POISONING) { - rpl_neighbor_set_preferred_parent(NULL); - curr_instance.dag.rank = RPL_INFINITE_RANK; - if(old_rank != RPL_INFINITE_RANK) { - /* Advertise that we are leaving, and leave after a delay */ - LOG_WARN("poisoning and leaving after a delay\n"); - rpl_timers_dio_reset("Poison routes"); - rpl_timers_schedule_leaving(); + old_rank = curr_instance.dag.rank; + /* Any scheduled state update is no longer needed */ + rpl_timers_unschedule_state_update(); + + if(curr_instance.dag.state == DAG_POISONING) { + rpl_neighbor_set_preferred_parent(NULL); + curr_instance.dag.rank = RPL_INFINITE_RANK; + if(old_rank != RPL_INFINITE_RANK) { + /* Advertise that we are leaving, and leave after a delay */ + LOG_WARN("poisoning and leaving after a delay\n"); + rpl_timers_dio_reset("Poison routes"); + rpl_timers_schedule_leaving(); + } + } else if(!rpl_dag_root_is_root()) { + rpl_nbr_t *old_parent = curr_instance.dag.preferred_parent; + rpl_nbr_t *nbr; + + /* Select and set preferred parent */ + rpl_neighbor_set_preferred_parent(rpl_neighbor_select_best()); + /* Update rank */ + curr_instance.dag.rank = rpl_neighbor_rank_via_nbr(curr_instance.dag.preferred_parent); + + /* Update better_parent_since flag for each neighbor */ + nbr = nbr_table_head(rpl_neighbors); + while(nbr != NULL) { + if(rpl_neighbor_rank_via_nbr(nbr) < curr_instance.dag.rank) { + /* This neighbor would be a better parent than our current. + Set 'better_parent_since' if not already set. */ + if(nbr->better_parent_since == 0) { + nbr->better_parent_since = clock_time(); /* Initialize */ } } else { - rpl_nbr_t *nbr; - - /* Select and set preferred parent */ - rpl_neighbor_set_preferred_parent(rpl_neighbor_select_best()); - /* Update rank */ - curr_instance.dag.rank = rpl_neighbor_rank_via_nbr(curr_instance.dag.preferred_parent); - - /* Update better_parent_since flag for each neighbor */ - nbr = nbr_table_head(rpl_neighbors); - while(nbr != NULL) { - if(rpl_neighbor_rank_via_nbr(nbr) < curr_instance.dag.rank) { - /* This neighbor would be a better parent than our current. - Set 'better_parent_since' if not already set. */ - if(nbr->better_parent_since == 0) { - nbr->better_parent_since = clock_time(); /* Initialize */ - } - } else { - nbr->better_parent_since = 0; /* Not a better parent */ - } - nbr = nbr_table_next(rpl_neighbors, nbr); - } - - if(old_parent == NULL || curr_instance.dag.rank < curr_instance.dag.lowest_rank) { - /* This is a slight departure from RFC6550: if we had no preferred parent before, - * reset lowest_rank. This helps recovering from temporary bad link conditions. */ - curr_instance.dag.lowest_rank = curr_instance.dag.rank; - } - - /* Reset DIO timer in case of significant rank update */ - if(curr_instance.dag.last_advertised_rank != RPL_INFINITE_RANK - && curr_instance.dag.rank != RPL_INFINITE_RANK - && ABS((int32_t)curr_instance.dag.rank - curr_instance.dag.last_advertised_rank) > RPL_SIGNIFICANT_CHANGE_THRESHOLD) { - LOG_WARN("significant rank update %u->%u\n", - curr_instance.dag.last_advertised_rank, curr_instance.dag.rank); - /* Update already here to avoid multiple resets in a row */ - curr_instance.dag.last_advertised_rank = curr_instance.dag.rank; - rpl_timers_dio_reset("Significant rank update"); - } - - /* Parent switch */ - if(curr_instance.dag.preferred_parent != old_parent) { - /* We just got a parent (was NULL), reset trickle timer to advertise this */ - if(old_parent == NULL) { - curr_instance.dag.state = DAG_JOINED; - rpl_timers_dio_reset("Got parent"); - LOG_WARN("found parent: "); - LOG_WARN_6ADDR(rpl_neighbor_get_ipaddr(curr_instance.dag.preferred_parent)); - LOG_WARN_(", staying in DAG\n"); - rpl_timers_unschedule_leaving(); - } - - /* Schedule a DAO */ - if(curr_instance.dag.preferred_parent != NULL) { - rpl_timers_schedule_dao(); - } else { - /* We have no more parent, schedule DIS to get a chance to hear updated state */ - curr_instance.dag.state = DAG_INITIALIZED; - LOG_WARN("no parent, scheduling periodic DIS, will leave if no parent is found\n"); - rpl_timers_dio_reset("Poison routes"); - rpl_timers_schedule_periodic_dis(); - rpl_timers_schedule_leaving(); - } - - #if LOG_INFO_ENABLED - rpl_neighbor_print_list("Parent switch"); - #endif /* LOG_INFO_ENABLED */ - } + nbr->better_parent_since = 0; /* Not a better parent */ } + nbr = nbr_table_next(rpl_neighbors, nbr); } - /* Finally, update metric container */ - curr_instance.of->update_metric_container(); + if(old_parent == NULL || curr_instance.dag.rank < curr_instance.dag.lowest_rank) { + /* This is a slight departure from RFC6550: if we had no preferred parent before, + * reset lowest_rank. This helps recovering from temporary bad link conditions. */ + curr_instance.dag.lowest_rank = curr_instance.dag.rank; + } + + /* Reset DIO timer in case of significant rank update */ + if(curr_instance.dag.last_advertised_rank != RPL_INFINITE_RANK + && curr_instance.dag.rank != RPL_INFINITE_RANK + && ABS((int32_t)curr_instance.dag.rank - curr_instance.dag.last_advertised_rank) > RPL_SIGNIFICANT_CHANGE_THRESHOLD) { + LOG_WARN("significant rank update %u->%u\n", + curr_instance.dag.last_advertised_rank, curr_instance.dag.rank); + /* Update already here to avoid multiple resets in a row */ + curr_instance.dag.last_advertised_rank = curr_instance.dag.rank; + rpl_timers_dio_reset("Significant rank update"); + } + + /* Parent switch */ + if(curr_instance.dag.preferred_parent != old_parent) { + /* We just got a parent (was NULL), reset trickle timer to advertise this */ + if(old_parent == NULL) { + curr_instance.dag.state = DAG_JOINED; + rpl_timers_dio_reset("Got parent"); + LOG_WARN("found parent: "); + LOG_WARN_6ADDR(rpl_neighbor_get_ipaddr(curr_instance.dag.preferred_parent)); + LOG_WARN_(", staying in DAG\n"); + rpl_timers_unschedule_leaving(); + } + + /* Schedule a DAO */ + if(curr_instance.dag.preferred_parent != NULL) { + rpl_timers_schedule_dao(); + } else { + /* We have no more parent, schedule DIS to get a chance to hear updated state */ + curr_instance.dag.state = DAG_INITIALIZED; + LOG_WARN("no parent, scheduling periodic DIS, will leave if no parent is found\n"); + rpl_timers_dio_reset("Poison routes"); + rpl_timers_schedule_periodic_dis(); + rpl_timers_schedule_leaving(); + } + +#if LOG_INFO_ENABLED + rpl_neighbor_print_list("Parent switch"); +#endif /* LOG_INFO_ENABLED */ + } } + + /* Finally, update metric container */ + curr_instance.of->update_metric_container(); } /*---------------------------------------------------------------------------*/ static rpl_nbr_t * @@ -516,8 +529,6 @@ process_dio_init_dag(uip_ipaddr_t *from, rpl_dio_t *dio) #endif /* RPL_WITH_PROBING */ /* Leave the network after RPL_DELAY_BEFORE_LEAVING in case we do not find a parent */ - rpl_timers_schedule_leaving(); - LOG_INFO("initialized DAG with instance ID %u, DAG ID ", curr_instance.instance_id); LOG_INFO_6ADDR(&curr_instance.dag.dag_id); @@ -525,6 +536,9 @@ process_dio_init_dag(uip_ipaddr_t *from, rpl_dio_t *dio) LOG_ANNOTATE("#A init=%u\n", curr_instance.dag.dag_id.u8[sizeof(curr_instance.dag.dag_id) - 1]); + LOG_WARN_("just joined, no parent yet, setting timer for leaving\n"); + rpl_timers_schedule_leaving(); + return 1; } /*---------------------------------------------------------------------------*/ diff --git a/core/net/rpl-lite/rpl-dag.h b/core/net/rpl-lite/rpl-dag.h index e7cd0332f..07ef3ca66 100644 --- a/core/net/rpl-lite/rpl-dag.h +++ b/core/net/rpl-lite/rpl-dag.h @@ -57,6 +57,11 @@ * \return The description string */ const char *rpl_dag_state_to_str(enum rpl_dag_state state); +/** + * Start poisoning and leave the DAG after a delay + * +*/ +void rpl_dag_poison_and_leave(void); /** * Leaves the current DAG * diff --git a/core/net/rpl-lite/rpl-ext-header.c b/core/net/rpl-lite/rpl-ext-header.c index d16de80b3..512761689 100644 --- a/core/net/rpl-lite/rpl-ext-header.c +++ b/core/net/rpl-lite/rpl-ext-header.c @@ -51,7 +51,7 @@ /* Log configuration */ #include "sys/log.h" #define LOG_MODULE "RPL" -#define LOG_LEVEL RPL_LOG_LEVEL +#define LOG_LEVEL LOG_LEVEL_RPL /*---------------------------------------------------------------------------*/ #define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN]) @@ -365,14 +365,14 @@ rpl_ext_header_hbh_update(int uip_ext_opt_offset) uint16_t sender_rank; uint8_t sender_closer; rpl_nbr_t *sender; + uint8_t opt_type = UIP_EXT_HDR_OPT_RPL_BUF->opt_type; + uint8_t opt_len = UIP_EXT_HDR_OPT_RPL_BUF->opt_len; if(UIP_HBHO_BUF->len != ((RPL_HOP_BY_HOP_LEN - 8) / 8) - || UIP_EXT_HDR_OPT_RPL_BUF->opt_type != UIP_EXT_HDR_OPT_RPL - || UIP_EXT_HDR_OPT_RPL_BUF->opt_len != RPL_HDR_OPT_LEN) { - + || opt_type != UIP_EXT_HDR_OPT_RPL + || opt_len != RPL_HDR_OPT_LEN) { LOG_ERR("hop-by-hop extension header has wrong size or type (%u %u %u)\n", - UIP_HBHO_BUF->len, UIP_EXT_HDR_OPT_RPL_BUF->opt_type, - UIP_EXT_HDR_OPT_RPL_BUF->opt_len); + UIP_HBHO_BUF->len, opt_type, opt_len); return 0; /* Drop */ } diff --git a/core/net/rpl-lite/rpl-icmp6.c b/core/net/rpl-lite/rpl-icmp6.c index 1e54c2237..a150afced 100644 --- a/core/net/rpl-lite/rpl-icmp6.c +++ b/core/net/rpl-lite/rpl-icmp6.c @@ -56,7 +56,7 @@ /* Log configuration */ #include "sys/log.h" #define LOG_MODULE "RPL" -#define LOG_LEVEL RPL_LOG_LEVEL +#define LOG_LEVEL LOG_LEVEL_RPL /*---------------------------------------------------------------------------*/ #define RPL_DIO_GROUNDED 0x80 @@ -557,10 +557,19 @@ rpl_icmp6_dao_output(uint8_t lifetime) /* Make sure we're up-to-date before sending data out */ rpl_dag_update_state(); - if(!curr_instance.used || curr_instance.dag.preferred_parent == NULL - || prefix == NULL || parent_ipaddr == NULL || curr_instance.mop == RPL_MOP_NO_DOWNWARD_ROUTES) { - LOG_WARN("rpl_icmp6_dao_output: node not ready to send a DAO (used %u, pref parent %u, prefix %u, mop %u)\n", - curr_instance.used, curr_instance.dag.preferred_parent != NULL && parent_ipaddr != NULL, prefix != NULL, curr_instance.mop); + if(!curr_instance.used) { + LOG_WARN("rpl_icmp6_dao_output: not in an instance, skip sending DAO\n"); + return; + } + + if(curr_instance.dag.preferred_parent == NULL) { + LOG_WARN("rpl_icmp6_dao_output: no preferred parent, skip sending DAO\n"); + return; + } + + if(prefix == NULL || parent_ipaddr == NULL || curr_instance.mop == RPL_MOP_NO_DOWNWARD_ROUTES) { + LOG_WARN("rpl_icmp6_dao_output: node not ready to send a DAO (prefix %p, parent addr %p, mop %u)\n", + prefix, parent_ipaddr, curr_instance.mop); return; } diff --git a/core/net/rpl-lite/rpl-mrhof.c b/core/net/rpl-lite/rpl-mrhof.c index 3784a94f8..faab5ce51 100644 --- a/core/net/rpl-lite/rpl-mrhof.c +++ b/core/net/rpl-lite/rpl-mrhof.c @@ -54,7 +54,7 @@ /* Log configuration */ #include "sys/log.h" #define LOG_MODULE "RPL" -#define LOG_LEVEL RPL_LOG_LEVEL +#define LOG_LEVEL LOG_LEVEL_RPL /* RFC6551 and RFC6719 do not mandate the use of a specific formula to * compute the ETX value. This MRHOF implementation relies on the value diff --git a/core/net/rpl-lite/rpl-nbr-policy.c b/core/net/rpl-lite/rpl-nbr-policy.c index db49613b2..b25c92d22 100644 --- a/core/net/rpl-lite/rpl-nbr-policy.c +++ b/core/net/rpl-lite/rpl-nbr-policy.c @@ -50,7 +50,7 @@ /* Log configuration */ #include "sys/log.h" #define LOG_MODULE "RPL" -#define LOG_LEVEL RPL_LOG_LEVEL +#define LOG_LEVEL LOG_LEVEL_RPL /* * Policy for neighbor addition diff --git a/core/net/rpl-lite/rpl-neighbor.c b/core/net/rpl-lite/rpl-neighbor.c index e748e2928..ad128d163 100644 --- a/core/net/rpl-lite/rpl-neighbor.c +++ b/core/net/rpl-lite/rpl-neighbor.c @@ -51,7 +51,7 @@ /* Log configuration */ #include "sys/log.h" #define LOG_MODULE "RPL" -#define LOG_LEVEL RPL_LOG_LEVEL +#define LOG_LEVEL LOG_LEVEL_RPL /* A configurable function called after every RPL parent switch */ #ifdef RPL_CALLBACK_PARENT_SWITCH diff --git a/core/net/rpl-lite/rpl-ns.c b/core/net/rpl-lite/rpl-ns.c index 650f4fb98..c6f4dfe5d 100644 --- a/core/net/rpl-lite/rpl-ns.c +++ b/core/net/rpl-lite/rpl-ns.c @@ -44,7 +44,7 @@ /* Log configuration */ #include "sys/log.h" #define LOG_MODULE "RPL" -#define LOG_LEVEL RPL_LOG_LEVEL +#define LOG_LEVEL LOG_LEVEL_RPL /* Total number of nodes */ static int num_nodes; @@ -203,6 +203,7 @@ void rpl_ns_periodic(unsigned seconds) { rpl_ns_node_t *l; + rpl_ns_node_t *next; /* First pass, decrement lifetime for all nodes with non-infinite lifetime */ for(l = list_head(nodelist); l != NULL; l = list_item_next(l)) { /* Don't touch infinite lifetime nodes */ @@ -211,7 +212,8 @@ rpl_ns_periodic(unsigned seconds) } } /* Second pass, for all expired nodes, deallocate them iff no child points to them */ - for(l = list_head(nodelist); l != NULL; l = list_item_next(l)) { + for(l = list_head(nodelist); l != NULL; l = next) { + next = list_item_next(l); if(l->lifetime == 0) { rpl_ns_node_t *l2; for(l2 = list_head(nodelist); l2 != NULL; l2 = list_item_next(l2)) { @@ -233,3 +235,16 @@ rpl_ns_periodic(unsigned seconds) } } } +/*---------------------------------------------------------------------------*/ +void +rpl_ns_free_all(void) +{ + rpl_ns_node_t *l; + rpl_ns_node_t *next; + for(l = list_head(nodelist); l != NULL; l = next) { + next = list_item_next(l); + list_remove(nodelist, l); + memb_free(&nodememb, l); + num_nodes--; + } +} diff --git a/core/net/rpl-lite/rpl-ns.h b/core/net/rpl-lite/rpl-ns.h index c09d0f6ad..8077cdf57 100644 --- a/core/net/rpl-lite/rpl-ns.h +++ b/core/net/rpl-lite/rpl-ns.h @@ -144,6 +144,11 @@ void rpl_ns_periodic(unsigned seconds); */ void rpl_ns_init(void); +/** + * Deallocate all neighbors +*/ +void rpl_ns_free_all(void); + /** @} */ #endif /* RPL_NS_H */ diff --git a/core/net/rpl-lite/rpl-of0.c b/core/net/rpl-lite/rpl-of0.c index 72c01217c..f35cc53cb 100644 --- a/core/net/rpl-lite/rpl-of0.c +++ b/core/net/rpl-lite/rpl-of0.c @@ -50,7 +50,7 @@ /* Log configuration */ #include "sys/log.h" #define LOG_MODULE "RPL" -#define LOG_LEVEL RPL_LOG_LEVEL +#define LOG_LEVEL LOG_LEVEL_RPL /* Constants from RFC6552. We use the default values. */ #define RANK_STRETCH 0 /* Must be in the range [0;5] */ diff --git a/core/net/rpl-lite/rpl-timers.c b/core/net/rpl-lite/rpl-timers.c index 36a5b6267..b8794e26d 100644 --- a/core/net/rpl-lite/rpl-timers.c +++ b/core/net/rpl-lite/rpl-timers.c @@ -51,7 +51,7 @@ /* Log configuration */ #include "sys/log.h" #define LOG_MODULE "RPL" -#define LOG_LEVEL RPL_LOG_LEVEL +#define LOG_LEVEL LOG_LEVEL_RPL /* A configurable function called after update of the RPL DIO interval */ #ifdef RPL_CALLBACK_NEW_DIO_INTERVAL @@ -483,7 +483,7 @@ rpl_timers_schedule_leaving(void) { if(curr_instance.used) { if(ctimer_expired(&curr_instance.dag.leave)) { - ctimer_set(&curr_instance.dag.leave, PERIODIC_DELAY, handle_leaving_timer, NULL); + ctimer_set(&curr_instance.dag.leave, RPL_DELAY_BEFORE_LEAVING, handle_leaving_timer, NULL); } } } diff --git a/core/net/rpl-lite/rpl.c b/core/net/rpl-lite/rpl.c index 003f6dcca..aefa8bc0c 100644 --- a/core/net/rpl-lite/rpl.c +++ b/core/net/rpl-lite/rpl.c @@ -48,7 +48,7 @@ /* Log configuration */ #include "sys/log.h" #define LOG_MODULE "RPL" -#define LOG_LEVEL RPL_LOG_LEVEL +#define LOG_LEVEL LOG_LEVEL_RPL uip_ipaddr_t rpl_multicast_addr; diff --git a/core/sys/log-conf.h b/core/sys/log-conf.h index 6eb526d6f..131bf0861 100644 --- a/core/sys/log-conf.h +++ b/core/sys/log-conf.h @@ -78,29 +78,29 @@ /********************* A list of currently supported modules ******************/ /******************************************************************************/ -#ifndef RPL_LOG_LEVEL -#define RPL_LOG_LEVEL LOG_LEVEL_NONE /* Only for rpl-lite */ -#endif /* RPL_LOG_LEVEL */ +#ifndef LOG_CONF_LEVEL_RPL +#define LOG_CONF_LEVEL_RPL LOG_LEVEL_NONE /* Only for rpl-lite */ +#endif /* LOG_CONF_LEVEL_RPL */ -#ifndef TCPIP_LOG_LEVEL -#define TCPIP_LOG_LEVEL LOG_LEVEL_NONE -#endif /* TCPIP_LOG_LEVEL */ +#ifndef LOG_CONF_LEVEL_TCPIP +#define LOG_CONF_LEVEL_TCPIP LOG_LEVEL_NONE +#endif /* LOG_CONF_LEVEL_TCPIP */ -#ifndef IPV6_LOG_LEVEL -#define IPV6_LOG_LEVEL LOG_LEVEL_NONE -#endif /* IPV6_LOG_LEVEL */ +#ifndef LOG_CONF_LEVEL_IPV6 +#define LOG_CONF_LEVEL_IPV6 LOG_LEVEL_NONE +#endif /* LOG_CONF_LEVEL_IPV6 */ -#ifndef SICSLOWPAN_LOG_LEVEL -#define SICSLOWPAN_LOG_LEVEL LOG_LEVEL_NONE -#endif /* SICSLOWPAN_LOG_LEVEL */ +#ifndef LOG_CONF_LEVEL_6LOWPAN +#define LOG_CONF_LEVEL_6LOWPAN LOG_LEVEL_NONE +#endif /* LOG_CONF_LEVEL_6LOWPAN */ -#ifndef MAC_LOG_LEVEL -#define MAC_LOG_LEVEL LOG_LEVEL_NONE -#endif /* MAC_LOG_LEVELL */ +#ifndef LOG_CONF_LEVEL_MAC +#define LOG_CONF_LEVEL_MAC LOG_LEVEL_NONE +#endif /* LOG_CONF_LEVEL_MAC */ -#ifndef FRAMER_LOG_LEVEL -#define FRAMER_LOG_LEVEL LOG_LEVEL_NONE -#endif /* FRAMER_LOG_LEVEL */ +#ifndef LOG_CONF_LEVEL_FRAMER +#define LOG_CONF_LEVEL_FRAMER LOG_LEVEL_NONE +#endif /* LOG_CONF_LEVEL_FRAMER */ #endif /* __LOG_CONF_H__ */ diff --git a/core/sys/log.c b/core/sys/log.c index abfb16d15..8f798ef74 100644 --- a/core/sys/log.c +++ b/core/sys/log.c @@ -53,6 +53,24 @@ #include "sys/log.h" #include "net/ip/ip64-addr.h" + +int curr_log_level_rpl = LOG_CONF_LEVEL_RPL; +int curr_log_level_tcpip = LOG_CONF_LEVEL_TCPIP; +int curr_log_level_ipv6 = LOG_CONF_LEVEL_IPV6; +int curr_log_level_6lowpan = LOG_CONF_LEVEL_6LOWPAN; +int curr_log_level_mac = LOG_CONF_LEVEL_MAC; +int curr_log_level_framer = LOG_CONF_LEVEL_FRAMER; + +struct log_module all_modules[] = { + {"rpl", &curr_log_level_rpl, LOG_CONF_LEVEL_RPL}, + {"tcpip", &curr_log_level_tcpip, LOG_CONF_LEVEL_TCPIP}, + {"ipv6", &curr_log_level_ipv6, LOG_CONF_LEVEL_IPV6}, + {"6lowpan", &curr_log_level_6lowpan, LOG_CONF_LEVEL_6LOWPAN}, + {"mac", &curr_log_level_mac, LOG_CONF_LEVEL_MAC}, + {"framer", &curr_log_level_framer, LOG_CONF_LEVEL_FRAMER}, + {NULL, NULL, 0}, +}; + /*---------------------------------------------------------------------------*/ void log_6addr(const uip_ipaddr_t *ipaddr) @@ -131,6 +149,52 @@ log_lladdr_compact(const linkaddr_t *lladdr) LOG_OUTPUT("LL-%04x", UIP_HTONS(lladdr->u16[LINKADDR_SIZE/2-1])); } } - +/*---------------------------------------------------------------------------*/ +void +log_set_level(const char *module, int level) +{ + if(level >= LOG_LEVEL_NONE && level <= LOG_LEVEL_DBG) { + int i = 0; + int module_all = !strcmp("all", module); + while(all_modules[i].name != NULL) { + if(module_all || !strcmp(module, all_modules[i].name)) { + *all_modules[i].curr_log_level = MIN(level, all_modules[i].max_log_level); + } + i++; + } + } +} +/*---------------------------------------------------------------------------*/ +int +log_get_level(const char *module) +{ + int i = 0; + while(all_modules[i].name != NULL) { + if(!strcmp(module, all_modules[i].name)) { + return *all_modules[i].curr_log_level; + } + i++; + } + return -1; +} +/*---------------------------------------------------------------------------*/ +const char * +log_level_to_str(int level) +{ + switch(level) { + case LOG_LEVEL_NONE: + return "None"; + case LOG_LEVEL_ERR: + return "Errors"; + case LOG_LEVEL_WARN: + return "Warnings"; + case LOG_LEVEL_INFO: + return "Info"; + case LOG_LEVEL_DBG: + return "Debug"; + default: + return "N/A"; + } +} /** @} */ /** @} */ diff --git a/core/sys/log.h b/core/sys/log.h index 567cb2cdb..6d0d1ff0f 100644 --- a/core/sys/log.h +++ b/core/sys/log.h @@ -65,10 +65,34 @@ #define LOG_LEVEL_INFO 3 /* Basic info */ #define LOG_LEVEL_DBG 4 /* Detailled debug */ +/* Per-module log level */ + +struct log_module { + const char *name; + int *curr_log_level; + int max_log_level; +}; + +extern int curr_log_level_rpl; +extern int curr_log_level_tcpip; +extern int curr_log_level_ipv6; +extern int curr_log_level_6lowpan; +extern int curr_log_level_mac; +extern int curr_log_level_framer; + +extern struct log_module all_modules[]; + +#define LOG_LEVEL_RPL MIN((LOG_CONF_LEVEL_RPL), curr_log_level_rpl) +#define LOG_LEVEL_TCPIP MIN((LOG_CONF_LEVEL_TCPIP), curr_log_level_tcpip) +#define LOG_LEVEL_IPV6 MIN((LOG_CONF_LEVEL_IPV6), curr_log_level_ipv6) +#define LOG_LEVEL_6LOWPAN MIN((LOG_CONF_LEVEL_6LOWPAN), curr_log_level_6lowpan) +#define LOG_LEVEL_MAC MIN((LOG_CONF_LEVEL_MAC), curr_log_level_mac) +#define LOG_LEVEL_FRAMER MIN((LOG_CONF_LEVEL_FRAMER), curr_log_level_framer) + /* Main log function */ #define LOG(newline, level, levelstr, ...) do { \ - if(level <= LOG_LEVEL) { \ + if(level <= (LOG_LEVEL)) { \ if(newline) { \ LOG_OUTPUT("[%-4s: %-10s] ", levelstr, LOG_MODULE); \ if(LOG_WITH_LOC) { \ @@ -88,7 +112,7 @@ /* Link-layer address */ #define LOG_LLADDR(level, lladdr) do { \ - if(level <= LOG_LEVEL) { \ + if(level <= (LOG_LEVEL)) { \ if(LOG_WITH_COMPACT_ADDR) { \ log_lladdr_compact(lladdr); \ } else { \ @@ -99,7 +123,7 @@ /* IPv6 address */ #define LOG_6ADDR(level, ipaddr) do { \ - if(level <= LOG_LEVEL) { \ + if(level <= (LOG_LEVEL)) { \ if(LOG_WITH_COMPACT_ADDR) { \ log_6addr_compact(ipaddr); \ } else { \ @@ -130,11 +154,10 @@ #define LOG_DBG_6ADDR(...) LOG_6ADDR(LOG_LEVEL_DBG, __VA_ARGS__) /* For testing log level */ -#define LOG_ERR_ENABLED (LOG_LEVEL >= LOG_LEVEL_ERR) -#define LOG_WARN_ENABLED (LOG_LEVEL >= LOG_LEVEL_WARN) -#define LOG_INFO_ENABLED (LOG_LEVEL >= LOG_LEVEL_INFO) -#define LOG_DBG_ENABLED (LOG_LEVEL >= LOG_LEVEL_DBG) -#define LOG_ANNOTATE_ENABLED (LOG_LEVEL >= LOG_LEVEL_ANNOTATE) +#define LOG_ERR_ENABLED (MIN(LOG_LEVEL, curr_log_level) >= LOG_LEVEL_ERR) +#define LOG_WARN_ENABLED (MIN(LOG_LEVEL, curr_log_level) >= LOG_LEVEL_WARN) +#define LOG_INFO_ENABLED (MIN(LOG_LEVEL, curr_log_level) >= LOG_LEVEL_INFO) +#define LOG_DBG_ENABLED (MIN(LOG_LEVEL, curr_log_level) >= LOG_LEVEL_DBG) #if NETSTACK_CONF_WITH_IPV6 @@ -164,6 +187,29 @@ void log_lladdr(const linkaddr_t *lladdr); */ void log_lladdr_compact(const linkaddr_t *lladdr); +/** + * Sets a log level at run-time. Logs are included in the firmware via + * the compile-time flags in log-conf.h, but this allows to force lower log + * levels, system-wide. + * \param module The target module string descriptor + * \param level The log level +*/ +void log_set_level(const char *module, int level); + +/** + * Returns the current log level. + * \param module The target module string descriptor + * \return The current log level +*/ +int log_get_level(const char *module); + +/** + * Returns a textual description of a log level + * \param level log level + * \return The textual description +*/ +const char *log_level_to_str(int level); + #endif /* __LOG_H__ */ /** @} */ diff --git a/examples/ipv6/rpl-tsch/Makefile b/examples/ipv6/rpl-tsch/Makefile index 734c1499e..03173e2a1 100644 --- a/examples/ipv6/rpl-tsch/Makefile +++ b/examples/ipv6/rpl-tsch/Makefile @@ -7,8 +7,9 @@ CFLAGS += -DPROJECT_CONF_H=\"project-conf.h\" CONTIKI_WITH_IPV6 = 1 MAKE_WITH_ORCHESTRA ?= 0 # force Orchestra from command line MAKE_WITH_SECURITY ?= 0 # force Security from command line +MAKE_WITH_PERIODIC_ROUTES_PRINT ?= 0 # print #routes periodically, used for regression tests -APPS += orchestra +APPS += orchestra shell MODULES += core/net/mac/tsch ifeq ($(MAKE_WITH_ORCHESTRA),1) @@ -19,4 +20,8 @@ ifeq ($(MAKE_WITH_SECURITY),1) CFLAGS += -DWITH_SECURITY=1 endif +ifeq ($(MAKE_WITH_PERIODIC_ROUTES_PRINT),1) +CFLAGS += -DWITH_PERIODIC_ROUTES_PRINT=1 +endif + include $(CONTIKI)/Makefile.include diff --git a/examples/ipv6/rpl-tsch/node.c b/examples/ipv6/rpl-tsch/node.c index b1ad2e567..36e67dc6d 100644 --- a/examples/ipv6/rpl-tsch/node.c +++ b/examples/ipv6/rpl-tsch/node.c @@ -40,205 +40,73 @@ #include "node-id.h" #include "rpl.h" #include "rpl-dag-root.h" +#include "sys/log.h" #include "net/ipv6/uip-ds6-route.h" #include "net/mac/tsch/tsch.h" +#include "net/mac/tsch/tsch-log.h" #if UIP_CONF_IPV6_RPL_LITE == 0 #include "rpl-private.h" #endif /* UIP_CONF_IPV6_RPL_LITE == 0 */ #if WITH_ORCHESTRA #include "orchestra.h" #endif /* WITH_ORCHESTRA */ +#if WITH_SHELL +#include "serial-shell.h" +#endif /* WITH_SHELL */ #define DEBUG DEBUG_PRINT #include "net/ip/uip-debug.h" -#define CONFIG_VIA_BUTTON PLATFORM_HAS_BUTTON -#if CONFIG_VIA_BUTTON -#include "button-sensor.h" -#endif /* CONFIG_VIA_BUTTON */ - /*---------------------------------------------------------------------------*/ PROCESS(node_process, "RPL Node"); -#if CONFIG_VIA_BUTTON -AUTOSTART_PROCESSES(&node_process, &sensors_process); -#else /* CONFIG_VIA_BUTTON */ AUTOSTART_PROCESSES(&node_process); -#endif /* CONFIG_VIA_BUTTON */ -/*---------------------------------------------------------------------------*/ -static void -print_network_status(void) -{ - int i; - uint8_t state; - uip_ds6_defrt_t *default_route; -#if RPL_WITH_STORING - uip_ds6_route_t *route; -#endif /* RPL_WITH_STORING */ -#if RPL_WITH_NON_STORING - rpl_ns_node_t *link; -#endif /* RPL_WITH_NON_STORING */ - - PRINTF("--- Network status ---\n"); - - /* Our IPv6 addresses */ - PRINTF("- Server IPv6 addresses:\n"); - for(i = 0; i < UIP_DS6_ADDR_NB; i++) { - state = uip_ds6_if.addr_list[i].state; - if(uip_ds6_if.addr_list[i].isused && - (state == ADDR_TENTATIVE || state == ADDR_PREFERRED)) { - PRINTF("-- "); - PRINT6ADDR(&uip_ds6_if.addr_list[i].ipaddr); - PRINTF("\n"); - } - } - - /* Our default route */ - PRINTF("- Default route:\n"); - default_route = uip_ds6_defrt_lookup(uip_ds6_defrt_choose()); - if(default_route != NULL) { - PRINTF("-- "); - PRINT6ADDR(&default_route->ipaddr); - PRINTF(" (lifetime: %lu seconds)\n", (unsigned long)default_route->lifetime.interval); - } else { - PRINTF("-- None\n"); - } - -#if RPL_WITH_STORING - /* Our routing entries */ - PRINTF("- Routing entries (%u in total):\n", uip_ds6_route_num_routes()); - route = uip_ds6_route_head(); - while(route != NULL) { - PRINTF("-- "); - PRINT6ADDR(&route->ipaddr); - PRINTF(" via "); - PRINT6ADDR(uip_ds6_route_nexthop(route)); - PRINTF(" (lifetime: %lu seconds)\n", (unsigned long)route->state.lifetime); - route = uip_ds6_route_next(route); - } -#endif - -#if RPL_WITH_NON_STORING - /* Our routing links */ - PRINTF("- Routing links (%u in total):\n", rpl_ns_num_nodes()); - link = rpl_ns_node_head(); - while(link != NULL) { - uip_ipaddr_t child_ipaddr; - uip_ipaddr_t parent_ipaddr; - rpl_ns_get_node_global_addr(&child_ipaddr, link); - rpl_ns_get_node_global_addr(&parent_ipaddr, link->parent); - PRINTF("-- "); - PRINT6ADDR(&child_ipaddr); - if(link->parent == NULL) { - memset(&parent_ipaddr, 0, sizeof(parent_ipaddr)); - PRINTF(" --- DODAG root "); - } else { - PRINTF(" to "); - PRINT6ADDR(&parent_ipaddr); - } - PRINTF(" (lifetime: %lu seconds)\n", (unsigned long)link->lifetime); - link = rpl_ns_node_next(link); - } -#endif - - PRINTF("----------------------\n"); -} -/*---------------------------------------------------------------------------*/ -static void -net_init(uip_ipaddr_t *br_prefix) -{ - if(br_prefix) { /* We are RPL root. Will be set automatically - as TSCH pan coordinator via the tsch-rpl module */ - rpl_dag_root_init(br_prefix, NULL); - rpl_dag_root_init_dag_immediately(); - } else { - rpl_dag_root_init(NULL, NULL); - } - - NETSTACK_MAC.on(); -} /*---------------------------------------------------------------------------*/ PROCESS_THREAD(node_process, ev, data) { - static struct etimer et; + int is_coordinator; + PROCESS_BEGIN(); - /* 3 possible roles: - * - role_6ln: simple node, will join any network, secured or not - * - role_6dr: DAG root, will advertise (unsecured) beacons - * - role_6dr_sec: DAG root, will advertise secured beacons - * */ - static int is_coordinator = 0; - static enum { role_6ln, role_6dr, role_6dr_sec } node_role; - node_role = role_6ln; + is_coordinator = 0; - int coordinator_candidate = 0; +#if WITH_SHELL + serial_shell_init(); + log_set_level("all", LOG_LEVEL_WARN); + tsch_log_stop(); +#endif /* WITH_SHELL */ #if CONTIKI_TARGET_COOJA - coordinator_candidate = (node_id == 1); + is_coordinator = (node_id == 1); #endif - if(coordinator_candidate) { - if(LLSEC802154_ENABLED) { - node_role = role_6dr_sec; - } else { - node_role = role_6dr; - } - } else { - node_role = role_6ln; - } - -#if CONFIG_VIA_BUTTON - { -#define CONFIG_WAIT_TIME 5 - - SENSORS_ACTIVATE(button_sensor); - etimer_set(&et, CLOCK_SECOND * CONFIG_WAIT_TIME); - - while(!etimer_expired(&et)) { - printf("Init: current role: %s. Will start in %u seconds. Press user button to toggle mode.\n", - node_role == role_6ln ? "6ln" : (node_role == role_6dr) ? "6dr" : "6dr-sec", - CONFIG_WAIT_TIME); - PROCESS_WAIT_EVENT_UNTIL(((ev == sensors_event) && - (data == &button_sensor) && button_sensor.value(0) > 0) - || etimer_expired(&et)); - if(ev == sensors_event && data == &button_sensor && button_sensor.value(0) > 0) { - node_role = (node_role + 1) % 3; - if(LLSEC802154_ENABLED == 0 && node_role == role_6dr_sec) { - node_role = (node_role + 1) % 3; - } - etimer_restart(&et); - } - } - } - -#endif /* CONFIG_VIA_BUTTON */ - - printf("Init: node starting with role %s\n", - node_role == role_6ln ? "6ln" : (node_role == role_6dr) ? "6dr" : "6dr-sec"); - - tsch_set_pan_secured(LLSEC802154_ENABLED && (node_role == role_6dr_sec)); - is_coordinator = node_role > role_6ln; - if(is_coordinator) { - uip_ipaddr_t prefix; - uip_ip6addr(&prefix, UIP_DS6_DEFAULT_PREFIX, 0, 0, 0, 0, 0, 0, 0); - net_init(&prefix); - } else { - net_init(NULL); + rpl_dag_root_init_dag_immediately(); } + NETSTACK_MAC.on(); #if WITH_ORCHESTRA orchestra_init(); #endif /* WITH_ORCHESTRA */ - /* Print out routing tables every minute */ - etimer_set(&et, CLOCK_SECOND * 60); - while(1) { - print_network_status(); - PROCESS_YIELD_UNTIL(etimer_expired(&et)); - etimer_reset(&et); +#if WITH_PERIODIC_ROUTES_PRINT + { + static struct etimer et; + /* Print out routing tables every minute */ + etimer_set(&et, CLOCK_SECOND * 60); + while(1) { + /* Used for non-regression testing */ + #if RPL_WITH_STORING + PRINTF("Routing entries: %u\n", uip_ds6_route_num_routes()); + #endif + #if RPL_WITH_NON_STORING + PRINTF("Routing links: %u\n", rpl_ns_num_nodes()); + #endif + PROCESS_YIELD_UNTIL(etimer_expired(&et)); + etimer_reset(&et); + } } +#endif /* WITH_PERIODIC_ROUTES_PRINT */ PROCESS_END(); } diff --git a/examples/ipv6/rpl-tsch/project-conf.h b/examples/ipv6/rpl-tsch/project-conf.h index 16b05fffa..e1b99f576 100644 --- a/examples/ipv6/rpl-tsch/project-conf.h +++ b/examples/ipv6/rpl-tsch/project-conf.h @@ -35,6 +35,9 @@ #ifndef __PROJECT_CONF_H__ #define __PROJECT_CONF_H__ +/* Set to use the Contiki shell */ +#define WITH_SHELL 1 + /* Set to run orchestra */ #ifndef WITH_ORCHESTRA #define WITH_ORCHESTRA 0 @@ -75,6 +78,18 @@ #undef SYS_CTRL_CONF_OSC32K_USE_XTAL #define SYS_CTRL_CONF_OSC32K_USE_XTAL 1 +#if WITH_SHELL +/* Needed for CC2538 platforms, for serial */ +#define USB_SERIAL_CONF_ENABLE 1 + +/* USB serial takes space, free more space elsewhere */ +#undef SICSLOWPAN_CONF_FRAG +#define SICSLOWPAN_CONF_FRAG 0 +#undef UIP_CONF_BUFFER_SIZE +#define UIP_CONF_BUFFER_SIZE 160 + +#endif /* WITH_SHELL */ + /* Needed for cc2420 platforms only */ /* Disable DCO calibration (uses timerB) */ #undef DCOSYNCH_CONF_ENABLED @@ -87,13 +102,9 @@ /******************* Configure TSCH ********************/ /*******************************************************/ -/* TSCH per-slot logging */ -#undef TSCH_LOG_CONF_PER_SLOT -#define TSCH_LOG_CONF_PER_SLOT 1 - /* IEEE802.15.4 PANID */ #undef IEEE802154_CONF_PANID -#define IEEE802154_CONF_PANID 0xabcd +#define IEEE802154_CONF_PANID 0x81a5 /* Do not start TSCH at init, wait for NETSTACK_MAC.on() */ #undef TSCH_CONF_AUTOSTART @@ -145,4 +156,13 @@ #define TSCH_CONF_MAX_EB_PERIOD (4 * CLOCK_SECOND) #endif /* CONTIKI_TARGET_COOJA */ +/* Logging */ +#define LOG_CONF_LEVEL_RPL LOG_LEVEL_INFO +#define LOG_CONF_LEVEL_TCPIP LOG_LEVEL_WARN +#define LOG_CONF_LEVEL_IPV6 LOG_LEVEL_WARN +#define LOG_CONF_LEVEL_6LOWPAN LOG_LEVEL_WARN +#define LOG_CONF_LEVEL_MAC LOG_LEVEL_INFO +#define LOG_CONF_LEVEL_FRAMER LOG_LEVEL_DBG +#define TSCH_LOG_CONF_PER_SLOT 1 + #endif /* __PROJECT_CONF_H__ */ diff --git a/examples/logging/project-conf.h b/examples/logging/project-conf.h index 39003b9c4..c35835afb 100644 --- a/examples/logging/project-conf.h +++ b/examples/logging/project-conf.h @@ -39,11 +39,12 @@ * LOG_LEVEL_INFO Basic info * LOG_LEVEL_DBG Detailled debug */ -#define IPV6_LOG_LEVEL LOG_LEVEL_DBG -#define SICSLOWPAN_LOG_LEVEL LOG_LEVEL_DBG -#define TCPIP_LOG_LEVEL LOG_LEVEL_DBG -#define MAC_LOG_LEVEL LOG_LEVEL_DBG -#define FRAMER_LOG_LEVEL LOG_LEVEL_DBG +#define LOG_CONF_LEVEL_IPV6 LOG_LEVEL_DBG +#define LOG_CONF_LEVEL_RPL LOG_LEVEL_DBG +#define LOG_CONF_LEVEL_6LOWPAN LOG_LEVEL_DBG +#define LOG_CONF_LEVEL_TCPIP LOG_LEVEL_DBG +#define LOG_CONF_LEVEL_MAC LOG_LEVEL_DBG +#define LOG_CONF_LEVEL_FRAMER LOG_LEVEL_DBG /* Enable cooja annotations */ #define LOG_CONF_WITH_ANNOTATE 1 diff --git a/regression-tests/08-ipv6/19-cooja-rpl-tsch.csc b/regression-tests/08-ipv6/19-cooja-rpl-tsch.csc index 112172828..97f4dd798 100644 --- a/regression-tests/08-ipv6/19-cooja-rpl-tsch.csc +++ b/regression-tests/08-ipv6/19-cooja-rpl-tsch.csc @@ -26,7 +26,7 @@ Cooja Mote Type #mtype1 [CONTIKI_DIR]/examples/ipv6/rpl-tsch/node.c make TARGET=cooja clean -make node.cooja TARGET=cooja MAKE_WITH_ORCHESTRA=0 MAKE_WITH_SECURITY=0 +make node.cooja TARGET=cooja MAKE_WITH_ORCHESTRA=0 MAKE_WITH_SECURITY=0 MAKE_WITH_PERIODIC_ROUTES_PRINT=1 org.contikios.cooja.interfaces.Position org.contikios.cooja.interfaces.Battery org.contikios.cooja.contikimote.interfaces.ContikiVib @@ -278,7 +278,7 @@ log.log("Waiting for routing links to fill\n"); while(true) {; WAIT_UNTIL(id == 1 && msg.contains("Routing links")); log.log(msg + "\n"); - if(msg.contains("Routing links (9 in total):")) { + if(msg.contains("Routing links: 9")) { log.testOK(); /* Report test success and quit */ } YIELD(); diff --git a/regression-tests/08-ipv6/20-cooja-rpl-tsch-orchestra.csc b/regression-tests/08-ipv6/20-cooja-rpl-tsch-orchestra.csc index 192617b23..676d86366 100644 --- a/regression-tests/08-ipv6/20-cooja-rpl-tsch-orchestra.csc +++ b/regression-tests/08-ipv6/20-cooja-rpl-tsch-orchestra.csc @@ -26,7 +26,7 @@ Cooja Mote Type #mtype11 [CONTIKI_DIR]/examples/ipv6/rpl-tsch/node.c make TARGET=cooja clean -make node.cooja TARGET=cooja MAKE_WITH_ORCHESTRA=1 MAKE_WITH_SECURITY=0 +make node.cooja TARGET=cooja MAKE_WITH_ORCHESTRA=1 MAKE_WITH_SECURITY=0 MAKE_WITH_PERIODIC_ROUTES_PRINT=1 [CONTIKI_DIR]/examples/ipv6/rpl-tsch/node.mtype1 org.contikios.cooja.interfaces.Position @@ -280,7 +280,7 @@ log.log("Waiting for routing links to fill\n"); while(true) {; WAIT_UNTIL(id == 1 && msg.contains("Routing links")); log.log(msg + "\n"); - if(msg.contains("Routing links (9 in total):")) { + if(msg.contains("Routing links: 9")) { log.testOK(); /* Report test success and quit */ } YIELD(); diff --git a/regression-tests/08-ipv6/21-cooja-rpl-tsch-security.csc b/regression-tests/08-ipv6/21-cooja-rpl-tsch-security.csc index e3e192297..ffa370b01 100644 --- a/regression-tests/08-ipv6/21-cooja-rpl-tsch-security.csc +++ b/regression-tests/08-ipv6/21-cooja-rpl-tsch-security.csc @@ -26,7 +26,7 @@ Cooja Mote Type #mtype11 [CONTIKI_DIR]/examples/ipv6/rpl-tsch/node.c make TARGET=cooja clean -make node.cooja TARGET=cooja MAKE_WITH_ORCHESTRA=0 MAKE_WITH_SECURITY=1 +make node.cooja TARGET=cooja MAKE_WITH_ORCHESTRA=0 MAKE_WITH_SECURITY=1 MAKE_WITH_PERIODIC_ROUTES_PRINT=1 org.contikios.cooja.interfaces.Position org.contikios.cooja.interfaces.Battery org.contikios.cooja.contikimote.interfaces.ContikiVib @@ -278,7 +278,7 @@ log.log("Waiting for routing links to fill\n"); while(true) {; WAIT_UNTIL(id == 1 && msg.contains("Routing links")); log.log(msg + "\n"); - if(msg.contains("Routing links (9 in total):")) { + if(msg.contains("Routing links: 9")) { log.testOK(); /* Report test success and quit */ } YIELD(); diff --git a/tools/jn516x/serialdump-linux b/tools/jn516x/serialdump-linux new file mode 100644 index 000000000..69fd8cfdb Binary files /dev/null and b/tools/jn516x/serialdump-linux differ diff --git a/tools/sky/serialdump-linux b/tools/sky/serialdump-linux index 8c7af779d..4d3e616a9 100755 Binary files a/tools/sky/serialdump-linux and b/tools/sky/serialdump-linux differ