Contiki 3.x
shell-rime.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2008, Swedish Institute of Computer Science.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * This file is part of the Contiki operating system.
30  *
31  */
32 
33 /**
34  * \file
35  * Shell commands for Rime communication primitives
36  * \author
37  * Adam Dunkels <adam@sics.se>
38  */
39 
40 #include "contiki.h"
41 #include "contiki-conf.h"
42 #include "shell-rime.h"
43 
44 #include "dev/leds.h"
45 
46 #include "lib/crc16.h"
47 #include "lib/random.h"
48 
49 #include "net/rime/rime.h"
50 #include "net/netstack.h"
51 #include "net/rime/route.h"
52 
53 #include "net/rime/timesynch.h"
54 
55 #if CONTIKI_TARGET_NETSIM
56 #include "ether.h"
57 #endif /* CONTIKI_TARGET_NETSIM */
58 
59 #include <stdio.h>
60 #ifndef HAVE_SNPRINTF
61 int snprintf(char *str, size_t size, const char *format, ...);
62 #endif /* HAVE_SNPRINTF */
63 #include <string.h>
64 
65 
66 #define DEFAULT_COLLECT_REXMITS 15
67 
68 
69 #define COLLECT_MSG_HDRSIZE 4
70 struct collect_msg {
71  uint16_t timestamp;
72  uint16_t crc;
73  uint8_t data[1];
74 };
75 
76 struct collect_conn shell_collect_conn;
77 static int waiting_for_collect = 0;
78 
79 static int is_sink = 0;
80 
81 /*---------------------------------------------------------------------------*/
82 PROCESS(shell_mac_process, "mac");
83 SHELL_COMMAND(mac_command,
84  "mac",
85  "mac <onoroff>: turn MAC protocol on (1) or off (0)",
86  &shell_mac_process);
87 PROCESS(shell_send_process, "send");
88 SHELL_COMMAND(send_command,
89  "send",
90  "send <rexmits>: send data to the collector node, with rexmits hop-by-hop retransmissions",
91  &shell_send_process);
92 PROCESS(shell_collect_process, "collect");
93 SHELL_COMMAND(collect_command,
94  "collect",
95  "collect: collect data from the network",
96  &shell_collect_process);
97 #if WITH_TREEDEPTH
98 PROCESS(shell_treedepth_process, "treedepth");
99 SHELL_COMMAND(treedepth_command,
100  "treedepth",
101  "treedepth: print the collection tree depth",
102  &shell_treedepth_process);
103 #endif /* WITH_TREEDEPTH */
104 PROCESS(shell_routes_process, "routes");
105 SHELL_COMMAND(routes_command,
106  "routes",
107  "routes: dump route list in binary format",
108  &shell_routes_process);
109 PROCESS(shell_packetize_process, "packetize");
110 SHELL_COMMAND(packetize_command,
111  "packetize",
112  "packetize: put data into one packet",
113  &shell_packetize_process);
114 /*---------------------------------------------------------------------------*/
115 PROCESS_THREAD(shell_mac_process, ev, data)
116 {
117  int onoroff;
118  const char *next;
119 
120  PROCESS_BEGIN();
121  onoroff = shell_strtolong((char *)data, &next);
122  if(next == data) {
123  shell_output_str(&mac_command, "mac: current MAC layer: ", NETSTACK_RDC.name);
124  shell_output_str(&mac_command, "mac usage: ", mac_command.description);
125  } else {
126  if(onoroff) {
127  NETSTACK_RDC.on();
128  shell_output_str(&mac_command, "mac: turned MAC on: ", NETSTACK_RDC.name);
129  } else {
130  NETSTACK_RDC.off(1);
131  shell_output_str(&mac_command, "mac: turned MAC off (keeping radio on): ",
132  NETSTACK_RDC.name);
133  }
134  }
135  PROCESS_END();
136 }
137 /*---------------------------------------------------------------------------*/
138 PROCESS_THREAD(shell_packetize_process, ev, data)
139 {
140  static struct queuebuf *q = NULL;
141  static char *ptr;
142  static int size;
143  int len;
144  PROCESS_BEGIN();
145 
146  while(1) {
147  struct shell_input *input;
149 
150  if(q == NULL) {
151  packetbuf_clear();
152  q = queuebuf_new_from_packetbuf();
153  if(q == NULL) {
154  shell_output_str(&packetize_command, "packetize: could not allocate packet buffer", "");
155  PROCESS_EXIT();
156  }
157  ptr = queuebuf_dataptr(q);
158  size = 0;
159  }
160 
161  input = data;
162 
163  len = input->len1 + input->len2;
164 
165  if(len + size >= PACKETBUF_SIZE ||
166  len == 0) {
167  shell_output(&packetize_command,
168  ptr, size,
169  "", 0);
170  queuebuf_free(q);
171  q = NULL;
172  PROCESS_EXIT();
173  }
174 
175  memcpy(ptr + size, input->data1, input->len1);
176  size += input->len1;
177  memcpy(ptr + size, input->data2, input->len2);
178  size += input->len2;
179 
180  }
181 
182  PROCESS_END();
183 }
184 /*---------------------------------------------------------------------------*/
185 PROCESS_THREAD(shell_routes_process, ev, data)
186 {
187  struct {
188  uint16_t len;
189  uint16_t dest;
190  uint16_t nexthop;
191  uint16_t hop_count;
192  uint16_t seqno;
193  } msg;
194  int i;
195  struct route_entry *r;
196 
197  PROCESS_BEGIN();
198 
199  memset(&msg, 0, sizeof(msg));
200  msg.len = 4;
201  for(i = 0; i < route_num(); ++i) {
202  r = route_get(i);
203  linkaddr_copy((linkaddr_t *)&msg.dest, &r->dest);
204  linkaddr_copy((linkaddr_t *)&msg.nexthop, &r->nexthop);
205  msg.hop_count = r->cost;
206  msg.seqno = r->seqno;
207  shell_output(&routes_command, &msg, sizeof(msg), "", 0);
208  }
209 
210  PROCESS_END();
211 }
212 /*---------------------------------------------------------------------------*/
213 #if WITH_TREEDEPTH
214 PROCESS_THREAD(shell_treedepth_process, ev, data)
215 {
216  char buf[20];
217 
218  PROCESS_BEGIN();
219 
220  snprintf(buf, sizeof(buf), "%d", collect_depth(&collect));
221 
222  shell_output_str(&treedepth_command, buf, "");
223 
224  PROCESS_END();
225 }
226 #endif /* WITH_TREEDEPTH */
227 /*---------------------------------------------------------------------------*/
228 PROCESS_THREAD(shell_collect_process, ev, data)
229 {
230 
231  PROCESS_BEGIN();
232 
233 #if TIMESYNCH_CONF_ENABLED
235 #endif
236  collect_set_sink(&shell_collect_conn, 1);
237 
238  is_sink = 1;
239  waiting_for_collect = 1;
240 
242 
243  waiting_for_collect = 0;
244 
245  PROCESS_END();
246 }
247 /*---------------------------------------------------------------------------*/
248 PROCESS_THREAD(shell_send_process, ev, data)
249 {
250  struct shell_input *input;
251  int len;
252  struct collect_msg *msg;
253  static int num_rexmits;
254  const char *next;
255 
256  PROCESS_BEGIN();
257 
258  num_rexmits = shell_strtolong((char *)data, &next);
259 
260  if(next == data) {
261  /* If no argument was given, we send packets with a default number
262  of retransmissions. */
263  num_rexmits = DEFAULT_COLLECT_REXMITS;
264  }
265 
266  while(1) {
268  input = data;
269 
270  len = input->len1 + input->len2;
271 
272  if(len == 0) {
273  PROCESS_EXIT();
274  }
275 
276  if(len < PACKETBUF_SIZE) {
277  packetbuf_clear();
278  packetbuf_set_datalen(len + COLLECT_MSG_HDRSIZE);
279  msg = packetbuf_dataptr();
280  memcpy(msg->data, input->data1, input->len1);
281  memcpy(msg->data + input->len1, input->data2, input->len2);
282 #if TIMESYNCH_CONF_ENABLED
283  msg->timestamp = timesynch_time();
284 #else
285  msg->timestamp = 0;
286 #endif
287  msg->crc = crc16_data(msg->data, len, 0);
288  collect_send(&shell_collect_conn, num_rexmits);
289  }
290  }
291  PROCESS_END();
292 }
293 /*---------------------------------------------------------------------------*/
294 static void
295 recv_collect(const linkaddr_t *originator, uint8_t seqno, uint8_t hops)
296 {
297  struct collect_msg collect_msg;
298  char *dataptr;
299  rtimer_clock_t latency;
300  int len;
301 
302  /* Copy the collect message header. */
303  memcpy(&collect_msg, packetbuf_dataptr(), sizeof(collect_msg));
304  dataptr = ((struct collect_msg *)packetbuf_dataptr())->data;
305 
306 #if TIMESYNCH_CONF_ENABLED
307  latency = timesynch_time() - collect_msg.timestamp;
308 #else
309  latency = 0;
310 #endif
311 
312  if(waiting_for_collect) {
313  struct {
314  uint16_t len;
315  uint16_t originator;
316  uint16_t seqno;
317  uint16_t hops;
318  uint16_t latency;
319  } msg;
320 
321  if(packetbuf_datalen() >= COLLECT_MSG_HDRSIZE) {
322  len = packetbuf_datalen() - COLLECT_MSG_HDRSIZE;
323 
324  if(collect_msg.crc == crc16_data(dataptr, len, 0)) {
325  msg.len = 5 + (packetbuf_datalen() - COLLECT_MSG_HDRSIZE) / 2;
326  linkaddr_copy((linkaddr_t *)&msg.originator, originator);
327  msg.seqno = seqno;
328  msg.hops = hops;
329  msg.latency = latency;
330 
331  shell_output(&collect_command,
332  &msg, sizeof(msg),
333  dataptr, packetbuf_datalen() - COLLECT_MSG_HDRSIZE);
334  }
335  }
336  }
337 
338 }
339 static const struct collect_callbacks collect_callbacks = { recv_collect };
340 /*---------------------------------------------------------------------------*/
341 void
342 shell_rime_init(void)
343 {
344  collect_open(&shell_collect_conn, SHELL_RIME_CHANNEL_COLLECT,
345  COLLECT_ROUTER, &collect_callbacks);
346  collect_set_keepalive(&shell_collect_conn, 10 * 60 * CLOCK_SECOND);
347 
348  shell_register_command(&collect_command);
349  shell_register_command(&mac_command);
350  shell_register_command(&packetize_command);
351  shell_register_command(&routes_command);
352  shell_register_command(&send_command);
353 
354 #if WITH_TREEDEPTH
355  shell_register_command(&treedepth_command);
356 #endif /* WITH_TREEDEPTH */
357 
358 }
359 /*---------------------------------------------------------------------------*/
void shell_output_str(struct shell_command *c, char *text1, const char *text2)
Output strings from a shell command.
Definition: shell.c:383
#define PROCESS_EXIT()
Exit the currently running process.
Definition: process.h:200
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition: process.h:120
#define NULL
The null pointer.
Header file for a simple time synchronization mechanism
void packetbuf_set_datalen(uint16_t len)
Set the length of the data in the packetbuf.
Definition: packetbuf.c:200
Header file for the Rime stack
rtimer_clock_t timesynch_time(void)
Get the current time-synchronized time.
void shell_output(struct shell_command *c, void *data1, int len1, const void *data2, int len2)
Output data from a shell command.
Definition: shell.c:395
uint16_t packetbuf_datalen(void)
Get the length of the data in the packetbuf.
Definition: packetbuf.c:239
void timesynch_set_authority_level(int level)
Set the authority level of the current time.
void linkaddr_copy(linkaddr_t *dest, const linkaddr_t *src)
Copy a Rime address.
Definition: linkaddr.c:60
#define PROCESS_THREAD(name, ev, data)
Define the body of a process.
Definition: process.h:273
#define PROCESS_END()
Define the end of a process.
Definition: process.h:131
unsigned long shell_strtolong(const char *str, const char **retstr)
Convert a string to a number.
Definition: shell.c:521
Structure for shell input data.
Definition: shell.h:365
void shell_register_command(struct shell_command *c)
Register a command with the shell.
Definition: shell.c:413
#define PROCESS_WAIT_EVENT_UNTIL(c)
Wait for an event to be posted to the process, with an extra condition.
Definition: process.h:157
#define PROCESS(name, strname)
Declare a process.
Definition: process.h:307
int shell_event_input
The event number for shell input data.
Definition: shell.c:70
void packetbuf_clear(void)
Clear and reset the packetbuf.
Definition: packetbuf.c:77
A brief description of what this file is.
#define PACKETBUF_SIZE
The size of the packetbuf, in bytes.
Definition: packetbuf.h:65
void * packetbuf_dataptr(void)
Get a pointer to the data in the packetbuf.
Definition: packetbuf.c:207
Header file for the CRC16 calculcation
unsigned short crc16_data(const unsigned char *data, int len, unsigned short acc)
Calculate the CRC16 over a data area.
Definition: crc16.c:66
#define SHELL_COMMAND(name, command, description, process)
Define a shell command.
Definition: shell.h:219
Include file for the Contiki low-layer network stack (NETSTACK)
Header file for the Rime route table
#define CLOCK_SECOND
A second, measured in system clock time.
Definition: clock.h:82