a26d87e09e
insertion of new commands and command pipelining. There are also a bunch of new commands for network access (using Rime): ping, data collection, packet sniffing, sending shell commands across the network, and testing the single-hop throughput to neighboring nodes. Commands are also available for reading from and writing to files, reading the sensors (on the Tmote Sky platform), and accessing the power and energy consumption of the system. Dynamic loading of programs across the network is also possible, although a little untested at the moment.
643 lines
17 KiB
C
643 lines
17 KiB
C
/*
|
|
* 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.
|
|
*
|
|
* $Id: shell-rime.c,v 1.1 2008/02/04 23:42:17 adamdunkels Exp $
|
|
*/
|
|
|
|
/**
|
|
* \file
|
|
* A brief description of what this file is.
|
|
* \author
|
|
* Adam Dunkels <adam@sics.se>
|
|
*/
|
|
|
|
#include "contiki.h"
|
|
#include "contiki-conf.h"
|
|
#include "shell-rime.h"
|
|
|
|
#include "dev/leds.h"
|
|
|
|
#include "lib/random.h"
|
|
|
|
#include "net/rime.h"
|
|
#include "net/rime/neighbor.h"
|
|
#include "net/rime/route.h"
|
|
#include "net/rime/trickle.h"
|
|
|
|
#include "net/rime/timesynch.h"
|
|
|
|
#define WITH_DEBUG_COMMANDS 1
|
|
|
|
#if NETSIM
|
|
#include "ether.h"
|
|
#endif /* NETSIM */
|
|
|
|
#include <stdio.h>
|
|
#ifndef HAVE_SNPRINTF
|
|
int snprintf(char *str, size_t size, const char *format, ...);
|
|
#endif /* HAVE_SNPRINTF */
|
|
#include <string.h>
|
|
|
|
|
|
#define COLLECT_REXMITS 4
|
|
|
|
enum {
|
|
TRICKLE_TYPE_NODES,
|
|
TRICKLE_TYPE_NETCMD,
|
|
};
|
|
|
|
struct trickle_msg {
|
|
uint8_t type;
|
|
char netcmd[1];
|
|
};
|
|
|
|
#define COLLECT_MSG_HDRSIZE 2
|
|
struct collect_msg {
|
|
uint16_t timestamp;
|
|
uint8_t data[1];
|
|
};
|
|
|
|
#if WITH_DEBUG_COMMANDS
|
|
static struct abc_conn abc;
|
|
static struct uc_conn uc;
|
|
#endif /* WITH_DEBUG_COMMANDS */
|
|
|
|
static struct collect_conn collect;
|
|
static struct trickle_conn trickle;
|
|
static struct ctimer ctimer;
|
|
static int waiting_for_nodes = 0;
|
|
static int waiting_for_collect = 0;
|
|
static int messages_received = 0;
|
|
|
|
|
|
static int is_sink = 0;
|
|
|
|
/* XXX ideas not implemented yet:
|
|
|
|
* download: download file from specific node.
|
|
|
|
* traceroute
|
|
|
|
*/
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
PROCESS(shell_nodes_process, "nodes");
|
|
SHELL_COMMAND(nodes_command,
|
|
"nodes",
|
|
"nodes: get a list of nodes in the network",
|
|
&shell_nodes_process);
|
|
PROCESS(shell_netcmd_process, "netcmd");
|
|
PROCESS(shell_netcmd_server_process, "netcmd server");
|
|
SHELL_COMMAND(netcmd_command,
|
|
"netcmd",
|
|
"netcmd <command>: run a command on all nodes in the network",
|
|
&shell_netcmd_process);
|
|
PROCESS(shell_send_process, "send");
|
|
SHELL_COMMAND(send_command,
|
|
"send",
|
|
"send: send data to the collector node",
|
|
&shell_send_process);
|
|
PROCESS(shell_collect_process, "collect");
|
|
SHELL_COMMAND(collect_command,
|
|
"collect",
|
|
"collect: collect data from the network",
|
|
&shell_collect_process);
|
|
#if WITH_TREEDEPTH
|
|
PROCESS(shell_treedepth_process, "treedepth");
|
|
SHELL_COMMAND(treedepth_command,
|
|
"treedepth",
|
|
"treedepth: print the collection tree depth",
|
|
&shell_treedepth_process);
|
|
#endif /* WITH_TREEDEPTH */
|
|
PROCESS(shell_neighbors_process, "neighbors");
|
|
SHELL_COMMAND(neighbors_command,
|
|
"neighbors",
|
|
"neighbors: dump neighbor list in binary format",
|
|
&shell_neighbors_process);
|
|
PROCESS(shell_routes_process, "routes");
|
|
SHELL_COMMAND(routes_command,
|
|
"routes",
|
|
"routes: dump route list in binary format",
|
|
&shell_routes_process);
|
|
PROCESS(shell_packetize_process, "packetize");
|
|
SHELL_COMMAND(packetize_command,
|
|
"packetize",
|
|
"packetize: put data into one packet",
|
|
&shell_packetize_process);
|
|
/*---------------------------------------------------------------------------*/
|
|
#if WITH_DEBUG_COMMANDS
|
|
PROCESS(shell_broadcast_process, "broadcast");
|
|
SHELL_COMMAND(broadcast_command,
|
|
"broadcast",
|
|
"broadcast: broadcast data to all neighbors",
|
|
&shell_broadcast_process);
|
|
PROCESS(shell_unicast_process, "unicast");
|
|
SHELL_COMMAND(unicast_command,
|
|
"unicast",
|
|
"unicast <node addr>: unicast data to specific neighbor",
|
|
&shell_unicast_process);
|
|
#endif /* WITH_DEBUG_COMMANDS */
|
|
/*---------------------------------------------------------------------------*/
|
|
PROCESS_THREAD(shell_packetize_process, ev, data)
|
|
{
|
|
static struct queuebuf *q = NULL;
|
|
static char *ptr;
|
|
static int size;
|
|
int len;
|
|
PROCESS_BEGIN();
|
|
|
|
while(1) {
|
|
struct shell_input *input;
|
|
PROCESS_WAIT_EVENT_UNTIL(ev == shell_event_input);
|
|
|
|
if(q == NULL) {
|
|
rimebuf_clear();
|
|
q = queuebuf_new_from_rimebuf();
|
|
if(q == NULL) {
|
|
shell_output_str(&packetize_command, "packetize: could not allocate packet buffer", "");
|
|
PROCESS_EXIT();
|
|
}
|
|
ptr = queuebuf_dataptr(q);
|
|
size = 0;
|
|
}
|
|
|
|
input = data;
|
|
|
|
len = input->len1 + input->len2;
|
|
|
|
if(len + size >= RIMEBUF_SIZE ||
|
|
len == 0) {
|
|
shell_output(&packetize_command,
|
|
ptr, size,
|
|
"", 0);
|
|
queuebuf_free(q);
|
|
q = NULL;
|
|
PROCESS_EXIT();
|
|
}
|
|
|
|
memcpy(ptr + size, input->data1, input->len1);
|
|
size += input->len1;
|
|
memcpy(ptr + size, input->data2, input->len2);
|
|
size += input->len2;
|
|
|
|
}
|
|
|
|
PROCESS_END();
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
PROCESS_THREAD(shell_routes_process, ev, data)
|
|
{
|
|
struct {
|
|
uint16_t len;
|
|
uint16_t dest;
|
|
uint16_t nexthop;
|
|
uint16_t hop_count;
|
|
uint16_t seqno;
|
|
} msg;
|
|
int i;
|
|
struct route_entry *r;
|
|
|
|
PROCESS_BEGIN();
|
|
|
|
memset(&msg, 0, sizeof(msg));
|
|
msg.len = 4;
|
|
for(i = 0; i < route_num(); ++i) {
|
|
r = route_get(i);
|
|
rimeaddr_copy((rimeaddr_t *)&msg.dest, &r->dest);
|
|
rimeaddr_copy((rimeaddr_t *)&msg.nexthop, &r->nexthop);
|
|
msg.hop_count = r->hop_count;
|
|
msg.seqno = r->seqno;
|
|
shell_output(&routes_command, &msg, sizeof(msg), "", 0);
|
|
}
|
|
|
|
PROCESS_END();
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
PROCESS_THREAD(shell_neighbors_process, ev, data)
|
|
{
|
|
struct {
|
|
uint16_t len;
|
|
uint16_t addr;
|
|
uint16_t rtmetric;
|
|
uint16_t etx;
|
|
} msg;
|
|
int i;
|
|
struct neighbor *n;
|
|
|
|
PROCESS_BEGIN();
|
|
|
|
for(i = 0; i < neighbor_num(); ++i) {
|
|
|
|
n = neighbor_get(i);
|
|
|
|
if(!rimeaddr_cmp(&n->addr, &rimeaddr_null)) {
|
|
memset(&msg, 0, sizeof(msg));
|
|
msg.len = 3;
|
|
rimeaddr_copy((rimeaddr_t *)&msg.addr, &n->addr);
|
|
msg.rtmetric = n->rtmetric;
|
|
msg.etx = neighbor_etx(n);
|
|
shell_output(&neighbors_command, &msg, sizeof(msg), "", 0);
|
|
}
|
|
}
|
|
|
|
PROCESS_END();
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
PROCESS_THREAD(shell_netcmd_server_process, ev, data)
|
|
{
|
|
static struct process *child_command;
|
|
int err;
|
|
PROCESS_BEGIN();
|
|
|
|
/* XXX: direct output to null. */
|
|
printf("netcmd server got command string '%s'\n", (char *)data);
|
|
err = shell_start_command(data, strlen((char * )data), NULL, &child_command);
|
|
if(err == SHELL_FOREGROUND && process_is_running(child_command)) {
|
|
PROCESS_WAIT_EVENT_UNTIL(ev == PROCESS_EVENT_EXIT ||
|
|
(ev == PROCESS_EVENT_EXITED &&
|
|
data == child_command));
|
|
if(ev == PROCESS_EVENT_EXIT) {
|
|
process_exit(child_command);
|
|
}
|
|
}
|
|
|
|
PROCESS_END();
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
PROCESS_THREAD(shell_netcmd_process, ev, data)
|
|
{
|
|
struct trickle_msg *msg;
|
|
int len;
|
|
|
|
PROCESS_BEGIN();
|
|
|
|
len = strlen((char *)data);
|
|
if(len > RIMEBUF_SIZE) {
|
|
char buf[32];
|
|
snprintf(buf, sizeof(buf), "%d", len);
|
|
shell_output_str(&netcmd_command, "command line too large: ", buf);
|
|
} else {
|
|
|
|
rimebuf_clear();
|
|
msg = rimebuf_dataptr();
|
|
rimebuf_set_datalen(1 + len + 1);
|
|
msg->type = TRICKLE_TYPE_NETCMD;
|
|
strcpy(msg->netcmd, data);
|
|
printf("netcmd sending '%s'\n", msg->netcmd);
|
|
trickle_send(&trickle);
|
|
}
|
|
|
|
PROCESS_END();
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
PROCESS_THREAD(shell_nodes_process, ev, data)
|
|
{
|
|
static struct etimer etimer;
|
|
struct trickle_msg *msg;
|
|
char buf[10];
|
|
PROCESS_BEGIN();
|
|
|
|
if(!is_sink) {
|
|
|
|
shell_output_str(&nodes_command,
|
|
"Setting up a collection network...", "");
|
|
#if TIMESYNCH_CONF_ENABLED
|
|
timesynch_set_authority_level(0);
|
|
#endif
|
|
collect_set_sink(&collect, 1);
|
|
|
|
etimer_set(&etimer, CLOCK_SECOND * 2);
|
|
PROCESS_WAIT_UNTIL(etimer_expired(&etimer));
|
|
is_sink = 1;
|
|
}
|
|
|
|
rimebuf_clear();
|
|
msg = rimebuf_dataptr();
|
|
rimebuf_set_datalen(sizeof(struct trickle_msg));
|
|
msg->type = TRICKLE_TYPE_NODES;
|
|
trickle_send(&trickle);
|
|
|
|
etimer_set(&etimer, CLOCK_SECOND * 10);
|
|
waiting_for_nodes = 1;
|
|
shell_output_str(&nodes_command,
|
|
"Request sent, waiting for replies...", "");
|
|
messages_received = 0;
|
|
|
|
PROCESS_WAIT_UNTIL(etimer_expired(&etimer));
|
|
snprintf(buf, sizeof(buf), "%d", messages_received);
|
|
shell_output_str(&nodes_command, buf, " nodes heard");
|
|
|
|
waiting_for_nodes = 0;
|
|
PROCESS_END();
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
#if WITH_TREEDEPTH
|
|
PROCESS_THREAD(shell_treedepth_process, ev, data)
|
|
{
|
|
char buf[20];
|
|
|
|
PROCESS_BEGIN();
|
|
|
|
snprintf(buf, sizeof(buf), "%d", collect_depth(&collect));
|
|
|
|
shell_output_str(&treedepth_command, buf, "");
|
|
|
|
PROCESS_END();
|
|
}
|
|
#endif /* WITH_TREEDEPTH */
|
|
/*---------------------------------------------------------------------------*/
|
|
PROCESS_THREAD(shell_collect_process, ev, data)
|
|
{
|
|
|
|
PROCESS_BEGIN();
|
|
|
|
#if TIMESYNCH_CONF_ENABLED
|
|
timesynch_set_authority_level(0);
|
|
#endif
|
|
collect_set_sink(&collect, 1);
|
|
|
|
is_sink = 1;
|
|
waiting_for_collect = 1;
|
|
|
|
PROCESS_WAIT_EVENT_UNTIL(ev == shell_event_input);
|
|
|
|
waiting_for_collect = 0;
|
|
|
|
PROCESS_END();
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
PROCESS_THREAD(shell_send_process, ev, data)
|
|
{
|
|
struct shell_input *input;
|
|
int len;
|
|
struct collect_msg *msg;
|
|
|
|
PROCESS_BEGIN();
|
|
|
|
while(1) {
|
|
PROCESS_WAIT_EVENT_UNTIL(ev == shell_event_input);
|
|
input = data;
|
|
|
|
len = input->len1 + input->len2;
|
|
|
|
if(len == 0) {
|
|
PROCESS_EXIT();
|
|
}
|
|
|
|
if(len < RIMEBUF_SIZE) {
|
|
rimebuf_clear();
|
|
rimebuf_set_datalen(len + COLLECT_MSG_HDRSIZE);
|
|
msg = rimebuf_dataptr();
|
|
memcpy(msg->data, input->data1, input->len1);
|
|
memcpy(msg->data + input->len1, input->data2, input->len2);
|
|
#if TIMESYNCH_CONF_ENABLED
|
|
msg->timestamp = timesynch_time();
|
|
#else
|
|
msg->timestamp = 0;
|
|
#endif
|
|
/* printf("Sending %d bytes\n", len);*/
|
|
collect_send(&collect, COLLECT_REXMITS);
|
|
}
|
|
}
|
|
PROCESS_END();
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
#if WITH_DEBUG_COMMANDS
|
|
PROCESS_THREAD(shell_broadcast_process, ev, data)
|
|
{
|
|
struct shell_input *input;
|
|
int len;
|
|
struct collect_msg *msg;
|
|
|
|
PROCESS_BEGIN();
|
|
|
|
while(1) {
|
|
PROCESS_WAIT_EVENT_UNTIL(ev == shell_event_input);
|
|
input = data;
|
|
|
|
len = input->len1 + input->len2;
|
|
|
|
if(len == 0) {
|
|
PROCESS_EXIT();
|
|
}
|
|
|
|
if(len < RIMEBUF_SIZE) {
|
|
rimebuf_clear();
|
|
rimebuf_set_datalen(len + COLLECT_MSG_HDRSIZE);
|
|
msg = rimebuf_dataptr();
|
|
memcpy(msg->data, input->data1, input->len1);
|
|
memcpy(msg->data + input->len1, input->data2, input->len2);
|
|
#if TIMESYNCH_CONF_ENABLED
|
|
msg->timestamp = timesynch_time();
|
|
#else
|
|
msg->timestamp = 0;
|
|
#endif
|
|
/* printf("Sending %d bytes\n", len);*/
|
|
abc_send(&abc);
|
|
}
|
|
}
|
|
PROCESS_END();
|
|
}
|
|
static void
|
|
recv_abc(struct abc_conn *c)
|
|
{
|
|
printf("abc message received\n");
|
|
}
|
|
static const struct abc_callbacks abc_callbacks = {recv_abc};
|
|
/*---------------------------------------------------------------------------*/
|
|
PROCESS_THREAD(shell_unicast_process, ev, data)
|
|
{
|
|
struct shell_input *input;
|
|
static rimeaddr_t receiver;
|
|
int len;
|
|
const char *nextptr;
|
|
struct collect_msg *msg;
|
|
char buf[30];
|
|
|
|
PROCESS_BEGIN();
|
|
|
|
receiver.u8[0] = shell_strtolong(data, &nextptr);
|
|
if(nextptr == data || *nextptr != '.') {
|
|
shell_output_str(&unicast_command,
|
|
"unicast <receiver>: recevier must be specified", "");
|
|
PROCESS_EXIT();
|
|
}
|
|
++nextptr;
|
|
receiver.u8[1] = shell_strtolong(nextptr, &nextptr);
|
|
|
|
snprintf(buf, sizeof(buf), "%d.%d", receiver.u8[0], receiver.u8[1]);
|
|
shell_output_str(&unicast_command, "Sending unicast packets to ", buf);
|
|
|
|
while(1) {
|
|
PROCESS_WAIT_EVENT_UNTIL(ev == shell_event_input);
|
|
input = data;
|
|
|
|
len = input->len1 + input->len2;
|
|
|
|
if(len == 0) {
|
|
PROCESS_EXIT();
|
|
}
|
|
|
|
if(len < RIMEBUF_SIZE) {
|
|
rimebuf_clear();
|
|
rimebuf_set_datalen(len + COLLECT_MSG_HDRSIZE);
|
|
msg = rimebuf_dataptr();
|
|
memcpy(msg->data, input->data1, input->len1);
|
|
memcpy(msg->data + input->len1, input->data2, input->len2);
|
|
#if TIMESYNCH_CONF_ENABLED
|
|
msg->timestamp = timesynch_time();
|
|
#else
|
|
msg->timestamp = 0;
|
|
#endif
|
|
/* printf("Sending %d bytes\n", len);*/
|
|
uc_send(&uc, &receiver);
|
|
}
|
|
}
|
|
PROCESS_END();
|
|
}
|
|
static void
|
|
recv_uc(struct uc_conn *c, rimeaddr_t *from)
|
|
{
|
|
printf("uc message received from %d.%d\n", from->u8[0], from->u8[1]);
|
|
}
|
|
static const struct uc_callbacks uc_callbacks = {recv_uc};
|
|
#endif /* WITH_DEBUG_COMMANDS */
|
|
/*---------------------------------------------------------------------------*/
|
|
static void
|
|
recv_collect(rimeaddr_t *originator, u8_t seqno, u8_t hops)
|
|
{
|
|
struct collect_msg *collect_msg;
|
|
rtimer_clock_t latency;
|
|
|
|
collect_msg = rimebuf_dataptr();
|
|
|
|
#if TIMESYNCH_CONF_ENABLED
|
|
latency = timesynch_time() - collect_msg->timestamp;
|
|
#else
|
|
latency = 0;
|
|
#endif
|
|
|
|
if(waiting_for_collect) {
|
|
struct {
|
|
uint16_t len;
|
|
uint16_t originator;
|
|
uint16_t seqno;
|
|
uint16_t hops;
|
|
uint16_t latency;
|
|
} msg;
|
|
|
|
|
|
msg.len = 5 + (rimebuf_datalen() - COLLECT_MSG_HDRSIZE) / 2;
|
|
rimeaddr_copy((rimeaddr_t *)&msg.originator, originator);
|
|
msg.seqno = seqno;
|
|
msg.hops = hops;
|
|
msg.latency = latency;
|
|
/* printf("recv_collect datalen %d\n", rimebuf_datalen());*/
|
|
|
|
shell_output(&collect_command,
|
|
&msg, sizeof(msg),
|
|
collect_msg->data, rimebuf_datalen() - COLLECT_MSG_HDRSIZE);
|
|
} else if(waiting_for_nodes) {
|
|
char buf[40];
|
|
snprintf(buf, sizeof(buf), "%d.%d, %d hops, latency %lu ms",
|
|
originator->u8[0], originator->u8[1],
|
|
hops, (1000L * latency) / RTIMER_ARCH_SECOND);
|
|
shell_output_str(&nodes_command, "Message from node ", buf);
|
|
messages_received++;
|
|
}
|
|
|
|
}
|
|
static const struct collect_callbacks collect_callbacks = { recv_collect };
|
|
/*---------------------------------------------------------------------------*/
|
|
static void
|
|
send_collect(void *dummy)
|
|
{
|
|
struct collect_msg msg;
|
|
#if TIMESYNCH_CONF_ENABLED
|
|
msg.timestamp = timesynch_time();
|
|
#else
|
|
msg.timestamp = 0;
|
|
#endif
|
|
rimebuf_copyfrom(&msg, COLLECT_MSG_HDRSIZE);
|
|
collect_send(&collect, COLLECT_REXMITS);
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
static void
|
|
recv_trickle(struct trickle_conn *c)
|
|
{
|
|
struct trickle_msg *msg;
|
|
|
|
msg = rimebuf_dataptr();
|
|
if(msg->type == TRICKLE_TYPE_NODES) {
|
|
ctimer_set(&ctimer, random_rand() % (CLOCK_SECOND * 2),
|
|
send_collect, NULL);
|
|
} else if(msg->type == TRICKLE_TYPE_NETCMD) {
|
|
/* First ensure that the old process is killed. */
|
|
process_exit(&shell_netcmd_server_process);
|
|
|
|
/* Make sure that the incoming command is null-terminated (which
|
|
is should be already). */
|
|
|
|
msg->netcmd[rimebuf_datalen() - 2] = 0;
|
|
|
|
/* Start the server process with the incoming command. */
|
|
process_start(&shell_netcmd_server_process, msg->netcmd);
|
|
}
|
|
}
|
|
const static struct trickle_callbacks trickle_callbacks = { recv_trickle };
|
|
/*---------------------------------------------------------------------------*/
|
|
void
|
|
shell_rime_init(void)
|
|
{
|
|
trickle_open(&trickle, CLOCK_SECOND * 4, 16, &trickle_callbacks);
|
|
collect_open(&collect, 17, &collect_callbacks);
|
|
|
|
shell_register_command(&collect_command);
|
|
shell_register_command(&neighbors_command);
|
|
shell_register_command(&netcmd_command);
|
|
shell_register_command(&nodes_command);
|
|
shell_register_command(&packetize_command);
|
|
shell_register_command(&routes_command);
|
|
shell_register_command(&send_command);
|
|
|
|
#if WITH_TREEDEPTH
|
|
shell_register_command(&treedepth_command);
|
|
#endif /* WITH_TREEDEPTH */
|
|
|
|
#if WITH_DEBUG_COMMANDS
|
|
uc_open(&uc, 14, &uc_callbacks);
|
|
abc_open(&abc, 15, &abc_callbacks);
|
|
shell_register_command(&broadcast_command);
|
|
shell_register_command(&unicast_command);
|
|
#endif /* WITH_DEBUG_COMMANDS */
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|