Contiki 3.x
shell-netperf.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  * A small pogram to measure the communication performance between two nodes
36  * \author
37  * Adam Dunkels <adam@sics.se>
38  */
39 
40 #include "contiki.h"
41 #include "shell-netperf.h"
42 #include "net/rime/rime.h"
43 #include "contiki-conf.h"
44 
45 #include <stdio.h>
46 #include <string.h>
47 
48 #ifndef HAVE_SNPRINTF
49 int snprintf(char *str, size_t size, const char *format, ...);
50 #endif /* HAVE_SNPRINTF */
51 
52 /*---------------------------------------------------------------------------*/
53 #define DATALEN 90
54 #define MAX_RETRIES 8
55 
56 #define CONTINUE_EVENT 128
57 
58 struct power {
59  unsigned long lpm, cpu, rx, tx;
60 };
61 
62 struct stats {
63  uint16_t sent, received, timedout;
64  unsigned long total_tx_latency;
65  unsigned long total_rx_latency;
66  clock_time_t start, end;
67  struct power power0, power;
68 };
69 
70 
71 enum {
72  DATAPATH_COMMAND_NONE,
73  DATAPATH_COMMAND_ECHO_REQUEST,
74  DATAPATH_COMMAND_STREAM_ECHO_REQUEST,
75  DATAPATH_COMMAND_ECHO_REPLY,
76 } datapath_commands;
77 
78 struct datapath_msg {
79  linkaddr_t receiver;
80  rtimer_clock_t tx, rx;
81  uint8_t datapath_command;
82  uint8_t received;
83 };
84 
85 enum {
86  CTRL_COMMAND_CLEAR,
87  CTRL_COMMAND_STATS,
88  CTRL_COMMAND_STATS_REPLY
89 } ctrlpath_commands;
90 
91 struct ctrl_msg {
92  uint8_t command;
93  struct stats stats;
94 };
95 
96 static struct runicast_conn ctrl;
97 static struct unicast_conn unicast;
98 static struct broadcast_conn broadcast;
99 static struct mesh_conn mesh;
100 static struct rucb_conn rucb;
101 
102 static linkaddr_t receiver;
103 static uint8_t is_sender;
104 static int left_to_send;
105 
106 static struct stats stats;
107 
108 enum {
109  TYPE_NONE = 0,
110  TYPE_BROADCAST = 1,
111  TYPE_UNICAST = 2,
112  TYPE_UNICAST_PINGPONG = 3,
113  TYPE_UNICAST_STREAM = 4,
114 };
115 
116 static uint8_t current_type;
117 
118 /*---------------------------------------------------------------------------*/
119 PROCESS(shell_netperf_process, "netperf");
120 SHELL_COMMAND(netperf_command,
121  "netperf",
122  "netperf: measure single-hop network performance",
123  &shell_netperf_process);
124 /*---------------------------------------------------------------------------*/
125 static void
126 memcpy_misaligned(void *dest, const void *source, int len)
127 {
128  int i;
129  uint8_t *destptr;
130  const uint8_t *sourceptr;
131  if(((int)dest & 1) == 1 ||
132  ((int)source & 1) == 1) {
133  destptr = dest;
134  sourceptr = source;
135  for(i = 0; i < len; ++i) {
136  *destptr++ = *sourceptr++;
137  }
138  } else {
139  memcpy(dest, source, len);
140  }
141 }
142 /*---------------------------------------------------------------------------*/
143 static void
144 print_remote_stats(struct stats *s)
145 {
146  unsigned long total_time;
147 
148  printf("%d 1 %d %d %d %lu %lu %lu %lu %lu %lu %lu # for automatic processing\n",
149  current_type,
150  s->sent, s->received, s->timedout,
151  s->end - s->start,
152  s->total_tx_latency, s->total_rx_latency,
153  s->power.cpu - s->power0.cpu,
154  s->power.lpm - s->power0.lpm,
155  s->power.rx - s->power0.rx,
156  s->power.tx - s->power0.tx);
157 
158  printf("Remote node statistics:\n");
159  total_time = s->power.cpu + s->power.lpm - s->power0.cpu - s->power0.lpm;
160  printf(" Remote radio duty cycle: rx %lu.%02lu%% tx %lu.%02lu%%\n",
161  (100 * (s->power.rx - s->power0.rx))/total_time,
162  ((10000 * (s->power.rx - s->power0.rx))/total_time) % 100,
163  (100 * (s->power.tx - s->power0.tx))/total_time,
164  ((10000 * (s->power.tx - s->power0.tx))/total_time) % 100);
165 
166  printf(" Packets: sent %d received %d\n",
167  s->sent, s->received);
168 }
169 /*---------------------------------------------------------------------------*/
170 static void
171 print_local_stats(struct stats *s)
172 {
173  unsigned long total_time;
174 
175  printf("%d 0 %d %d %d %lu %lu %lu %lu %lu %lu %lu # for automatic processing\n",
176  current_type,
177  s->sent, s->received, s->timedout,
178  s->end - s->start,
179  s->total_tx_latency, s->total_rx_latency,
180  s->power.cpu - s->power0.cpu,
181  s->power.lpm - s->power0.lpm,
182  s->power.rx - s->power0.rx,
183  s->power.tx - s->power0.tx);
184 
185  printf("Local node statistics:\n");
186 
187  printf(" Total transfer time: %lu.%02lu seconds, %lu.%02lu packets/second\n",
188  (s->end - s->start) / CLOCK_SECOND,
189  ((10 * (s->end - s->start)) / CLOCK_SECOND) % 10,
190  ((1UL * CLOCK_SECOND * s->sent) / (s->end - s->start)),
191  (((100UL * CLOCK_SECOND * s->sent) / (s->end - s->start)) % 100));
192 
193  printf(" Average round-trip-time: %lu ms (%lu + %lu)\n",
194  (1000 * (s->total_rx_latency + s->total_tx_latency) / s->received) /
195  RTIMER_ARCH_SECOND,
196  (1000 * (s->total_tx_latency) / s->received) /
197  RTIMER_ARCH_SECOND,
198  (1000 * (s->total_rx_latency) / s->received) /
199  RTIMER_ARCH_SECOND);
200 
201  total_time = s->power.cpu + s->power.lpm - s->power0.cpu - s->power0.lpm;
202  printf(" Radio duty cycle: rx %lu.%02lu%% tx %lu.%02lu%%\n",
203  (100 * (s->power.rx - s->power0.rx))/total_time,
204  ((10000 * (s->power.rx - s->power0.rx))/total_time) % 100,
205  (100 * (s->power.tx - s->power0.tx))/total_time,
206  ((10000 * (s->power.tx - s->power0.tx))/total_time) % 100);
207 
208  printf(" Packets received: %d.%lu%%, %d of %d\n",
209  100 * s->received / s->sent,
210  (10000L * s->received / s->sent) % 10,
211  s->received, s->sent);
212 }
213 /*---------------------------------------------------------------------------*/
214 static void
215 sample_power_profile(struct power *p)
216 {
217  energest_flush();
218  p->lpm = energest_type_time(ENERGEST_TYPE_LPM);
219  p->cpu = energest_type_time(ENERGEST_TYPE_CPU);
220  p->rx = energest_type_time(ENERGEST_TYPE_LISTEN);
221  p->tx = energest_type_time(ENERGEST_TYPE_TRANSMIT);
222 }
223 /*---------------------------------------------------------------------------*/
224 static void
225 clear_stats(void)
226 {
227  memset(&stats, 0, sizeof(stats));
228  stats.start = clock_time();
229  sample_power_profile(&stats.power0);
230 }
231 /*---------------------------------------------------------------------------*/
232 static void
233 setup_sending(linkaddr_t *to, int num)
234 {
235  is_sender = 1;
236  left_to_send = num;
237  linkaddr_copy(&receiver, to);
238  clear_stats();
239 }
240 /*---------------------------------------------------------------------------*/
241 static void
242 finalize_stats(struct stats *s)
243 {
244  stats.end = clock_time();
245  sample_power_profile(&stats.power);
246 }
247 /*---------------------------------------------------------------------------*/
248 static unsigned long filesize, bytecount, packetsize;
249 static int download_complete;
250 static void
251 write_chunk(struct rucb_conn *c, int offset, int flag,
252  char *data, int datalen)
253 {
254  printf("+");
255 }
256 static int
257 read_chunk(struct rucb_conn *c, int offset, char *to, int maxsize)
258 {
259  int size;
260  /* printf("-");*/
261  size = maxsize;
262  if(bytecount + maxsize >= filesize) {
263  size = filesize - bytecount;
264  }
265  if(size > packetsize) {
266  size = packetsize;
267  }
268  bytecount += size;
269  if(bytecount == filesize) {
270  /* end_time_rucb = clock_time();*/
271  download_complete = 1;
272  process_post(&shell_netperf_process, PROCESS_EVENT_CONTINUE, NULL);
273  }
274  return size;
275 }
276 const static struct rucb_callbacks rucb_callbacks =
277  { write_chunk, read_chunk, NULL };
278 /*---------------------------------------------------------------------------*/
279 static int
280 construct_next_packet(void)
281 {
282  struct datapath_msg *msg;
283  packetbuf_clear();
284  if(left_to_send > 0) {
285  packetbuf_set_datalen(DATALEN);
286  msg = packetbuf_dataptr();
287  msg->datapath_command = DATAPATH_COMMAND_NONE;
288  msg->received = 0;
289 #if TIMESYNCH_CONF_ENABLED
290  msg->tx = msg->rx = timesynch_time();
291 #else /* TIMESYNCH_CONF_ENABLED */
292  msg->tx = msg->rx = 0;
293 #endif /* TIMESYNCH_CONF_ENABLED */
294  linkaddr_copy(&msg->receiver, &receiver);
295  left_to_send--;
296  return 1;
297  }
298  return 0;
299 }
300 /*---------------------------------------------------------------------------*/
301 static int
302 construct_next_echo(void)
303 {
304  struct datapath_msg *msg;
305  if(construct_next_packet()) {
306  msg = packetbuf_dataptr();
307  msg->datapath_command = DATAPATH_COMMAND_ECHO_REQUEST;
308  return 1;
309  }
310  return 0;
311 }
312 /*---------------------------------------------------------------------------*/
313 static int
314 construct_next_stream_echo(void)
315 {
316  struct datapath_msg *msg;
317  if(construct_next_packet()) {
318  msg = packetbuf_dataptr();
319  msg->datapath_command = DATAPATH_COMMAND_STREAM_ECHO_REQUEST;
320  packetbuf_set_attr(PACKETBUF_ATTR_PACKET_TYPE,
321  PACKETBUF_ATTR_PACKET_TYPE_STREAM);
322  return 1;
323  }
324  return 0;
325 }
326 /*---------------------------------------------------------------------------*/
327 static void
328 process_incoming_packet(void)
329 {
330  struct datapath_msg *msg = packetbuf_dataptr();
331  rtimer_clock_t now;
332  struct datapath_msg msg_copy;
333 
334 #if TIMESYNCH_CONF_ENABLED
335  now = timesynch_time();
336 #else /* TIMESYNCH_CONF_ENABLED */
337  now = 0;
338 #endif /* TIMESYNCH_CONF_ENABLED */
339 
340  memcpy_misaligned(&msg_copy, (uint8_t *)msg, sizeof(msg_copy));
341  stats.received++;
342  stats.total_tx_latency += msg_copy.rx - msg_copy.tx;
343  stats.total_rx_latency += now - msg_copy.rx;
344 }
345 /*---------------------------------------------------------------------------*/
346 static int
347 construct_reply(const linkaddr_t *from)
348 {
349  struct datapath_msg *msg = packetbuf_dataptr();
350 #if TIMESYNCH_CONF_ENABLED
351  rtimer_clock_t now = timesynch_time();
352 #else /* TIMESYNCH_CONF_ENABLED */
353  rtimer_clock_t now = 0;
354 #endif /* TIMESYNCH_CONF_ENABLED */
355 
356  memcpy_misaligned(&msg->rx, &now, sizeof(rtimer_clock_t));
357 
358  switch(msg->datapath_command) {
359  case DATAPATH_COMMAND_ECHO_REQUEST:
360  msg->datapath_command = DATAPATH_COMMAND_ECHO_REPLY;
361  break;
362  case DATAPATH_COMMAND_STREAM_ECHO_REQUEST:
363  msg->datapath_command = DATAPATH_COMMAND_ECHO_REPLY;
364  packetbuf_set_attr(PACKETBUF_ATTR_PACKET_TYPE,
365  PACKETBUF_ATTR_PACKET_TYPE_STREAM);
366  break;
367  }
368  if(msg->datapath_command == DATAPATH_COMMAND_ECHO_REPLY) {
369  packetbuf_set_datalen(sizeof(struct datapath_msg));
370  msg->received = stats.received;
371  stats.sent++;
372  return 1;
373  }
374  return 0;
375 }
376 /*---------------------------------------------------------------------------*/
377 static void
378 sent_mesh(struct mesh_conn *c)
379 {
380  stats.sent++;
381 }
382 static void
383 timedout_mesh(struct mesh_conn *c)
384 {
385  if(is_sender) {
386  if(construct_next_echo()) {
387  mesh_send(&mesh, &receiver);
388  }
389  }
390  stats.timedout++;
391 }
392 static void
393 recv_mesh(struct mesh_conn *c, const linkaddr_t *from, uint8_t hops)
394 {
395  process_incoming_packet();
396  if(is_sender) {
397  if(construct_next_echo()) {
398  mesh_send(&mesh, &receiver);
399  }
400  } else {
401  if(construct_reply(from)) {
402  mesh_send(&mesh, from);
403  }
404  }
405 }
406 const static struct mesh_callbacks mesh_callbacks =
407  { recv_mesh, sent_mesh, timedout_mesh };
408 /*---------------------------------------------------------------------------*/
409 static void
410 sent_ctrl(struct runicast_conn *c, const linkaddr_t *to, uint8_t rexmits)
411 {
412  process_post(&shell_netperf_process, CONTINUE_EVENT, NULL);
413 }
414 static void
415 timedout_ctrl(struct runicast_conn *c, const linkaddr_t *to, uint8_t rexmits)
416 {
417  shell_output_str(&netperf_command, "netperf control connection failed", "");
418  process_exit(&shell_netperf_process);
419 }
420 static void
421 recv_ctrl(struct runicast_conn *c, const linkaddr_t *from, uint8_t seqno)
422 {
423  static uint8_t last_seqno = -1;
424  struct stats s;
425  struct ctrl_msg *msg = packetbuf_dataptr();
426 
427  if(last_seqno == seqno) {
428  return;
429  }
430  last_seqno = seqno;
431  switch(msg->command) {
432  case CTRL_COMMAND_STATS:
433  msg->command = CTRL_COMMAND_STATS_REPLY;
434  finalize_stats(&stats);
435  memcpy_misaligned(&msg->stats, &stats, sizeof(stats));
436  packetbuf_set_datalen(sizeof(struct ctrl_msg));
437  runicast_send(c, from, MAX_RETRIES);
438  break;
439  case CTRL_COMMAND_STATS_REPLY:
440  memcpy_misaligned(&s, &msg->stats, sizeof(stats));
441  print_remote_stats(&s);
442  process_post(&shell_netperf_process, CONTINUE_EVENT, NULL);
443  break;
444  case CTRL_COMMAND_CLEAR:
445  clear_stats();
446  break;
447  }
448 }
449 const static struct runicast_callbacks runicast_callbacks =
450  { recv_ctrl, sent_ctrl, timedout_ctrl };
451 /*---------------------------------------------------------------------------*/
452 static int
453 send_ctrl_command(const linkaddr_t *to, uint8_t command)
454 {
455  struct ctrl_msg *msg;
456  packetbuf_clear();
457  packetbuf_set_datalen(sizeof(struct ctrl_msg));
458  msg = packetbuf_dataptr();
459  msg->command = command;
460  return runicast_send(&ctrl, to, MAX_RETRIES);
461 }
462 /*---------------------------------------------------------------------------*/
463 static void
464 recv_broadcast(struct broadcast_conn *c, const linkaddr_t *from)
465 {
466  process_incoming_packet();
467  if(is_sender) {
468  } else if(construct_reply(from)) {
469  broadcast_send(&broadcast);
470  }
471 }
472 const static struct broadcast_callbacks broadcast_callbacks =
473  { recv_broadcast };
474 /*---------------------------------------------------------------------------*/
475 static void
476 recv_unicast(struct unicast_conn *c, const linkaddr_t *from)
477 {
478  process_incoming_packet();
479  if(is_sender) {
480  struct datapath_msg *msg = packetbuf_dataptr();
481  if(msg->datapath_command == DATAPATH_COMMAND_ECHO_REPLY) {
482  process_post(&shell_netperf_process, CONTINUE_EVENT, NULL);
483  }
484  } else if(construct_reply(from)) {
485  unicast_send(&unicast, from);
486  }
487 }
488 const static struct unicast_callbacks unicast_callbacks =
489  { recv_unicast };
490 /*---------------------------------------------------------------------------*/
491 static void
492 print_usage(void)
493 {
494  shell_output_str(&netperf_command,
495  "netperf [-b|u|p|s] <receiver> <num packets>: perform network measurements to receiver", "");
496  shell_output_str(&netperf_command,
497  " -b measure broadcast performance", "");
498  shell_output_str(&netperf_command,
499  " -u measure one-way unicast performance", "");
500  shell_output_str(&netperf_command,
501  " -p measure ping-pong unicast performance", "");
502  shell_output_str(&netperf_command,
503  " -s measure ping-pong stream unicast performance", "");
504 }
505 /*---------------------------------------------------------------------------*/
506 void
507 shell_netperf_init(void)
508 {
509  runicast_open(&ctrl, SHELL_RIME_CHANNEL_NETPERF, &runicast_callbacks);
510  broadcast_open(&broadcast, SHELL_RIME_CHANNEL_NETPERF + 1, &broadcast_callbacks);
511  unicast_open(&unicast, SHELL_RIME_CHANNEL_NETPERF + 2, &unicast_callbacks);
512  mesh_open(&mesh, SHELL_RIME_CHANNEL_NETPERF + 3, &mesh_callbacks);
513  rucb_open(&rucb, SHELL_RIME_CHANNEL_NETPERF + 5, &rucb_callbacks);
514  shell_register_command(&netperf_command);
515 }
516 /*---------------------------------------------------------------------------*/
517 PROCESS_THREAD(shell_netperf_process, ev, data)
518 {
519  static struct etimer e;
520  static linkaddr_t receiver;
521  const char *nextptr;
522  const char *args;
523  static char recvstr[40];
524  static int i, num_packets;
525  static uint8_t do_broadcast, do_unicast, do_pingpong, do_stream_pingpong;
526 
527  PROCESS_BEGIN();
528 
529  current_type = TYPE_NONE;
530 
531  do_broadcast = do_unicast = do_pingpong =
532  do_stream_pingpong = 0;
533 
534  args = data;
535 
536  /* Parse the -bups options */
537  while(*args == '-') {
538  ++args;
539  while(*args != ' ' &&
540  *args != 0) {
541  if(*args == 'b') {
542  do_broadcast = 1;
543  }
544  if(*args == 'u') {
545  do_unicast = 1;
546  }
547  if(*args == 'p') {
548  do_pingpong = 1;
549  }
550  if(*args == 's') {
551  do_stream_pingpong = 1;
552  }
553  ++args;
554  }
555  while(*args == ' ') {
556  args++;
557  }
558  }
559 
560  /* Parse the receiver address */
561  receiver.u8[0] = shell_strtolong(args, &nextptr);
562  if(nextptr == data || *nextptr != '.') {
563  print_usage();
564  PROCESS_EXIT();
565  }
566  args = nextptr + 1;
567  receiver.u8[1] = shell_strtolong(args, &nextptr);
568 
569  /* Store the receiver address as a string since we need to print it
570  out later. */
571  snprintf(recvstr, sizeof(recvstr), "%d.%d",
572  receiver.u8[0], receiver.u8[1]);
573 
574  /* Parse the number of packets to send */
575  args = nextptr;
576  while(*args == ' ') {
577  ++args;
578  }
579  num_packets = shell_strtolong(args, &nextptr);
580  if(nextptr == data || num_packets == 0) {
581  print_usage();
582  PROCESS_EXIT();
583  }
584 
585  /* Send broadcast packets, if requested */
586  if(do_broadcast) {
587  current_type = TYPE_BROADCAST;
588  shell_output_str(&netperf_command, "-------- Broadcast --------", "");
589 
590  shell_output_str(&netperf_command, "Contacting ", recvstr);
591  while(!send_ctrl_command(&receiver, CTRL_COMMAND_CLEAR)) {
592  PROCESS_PAUSE();
593  }
594  PROCESS_YIELD_UNTIL(ev == CONTINUE_EVENT);
595 
596  shell_output_str(&netperf_command, "Measuring broadcast performance to ", recvstr);
597 
598  setup_sending(&receiver, num_packets);
599  for(i = 0; i < num_packets; ++i) {
600  if(construct_next_packet()) {
601  broadcast_send(&broadcast);
602  stats.sent++;
603  }
604  PROCESS_PAUSE();
605  }
606 
607  shell_output_str(&netperf_command, "Requesting statistics from ", recvstr);
608  while(!send_ctrl_command(&receiver, CTRL_COMMAND_STATS)) {
609  PROCESS_PAUSE();
610  }
611  PROCESS_YIELD_UNTIL(ev == CONTINUE_EVENT);
612 
613  /* Wait for reply */
614  PROCESS_YIELD_UNTIL(ev == CONTINUE_EVENT);
615 
616  finalize_stats(&stats);
617  print_local_stats(&stats);
618  }
619 
620  if(do_unicast) {
621  current_type = TYPE_UNICAST;
622  shell_output_str(&netperf_command, "-------- Unicast one-way --------", "");
623 
624  shell_output_str(&netperf_command, "Contacting ", recvstr);
625  while(!send_ctrl_command(&receiver, CTRL_COMMAND_CLEAR)) {
626  PROCESS_PAUSE();
627  }
628  PROCESS_YIELD_UNTIL(ev == CONTINUE_EVENT);
629 
630  shell_output_str(&netperf_command, "Measuring unicast performance to ", recvstr);
631 
632  setup_sending(&receiver, num_packets);
633 
634  for(i = 0; i < num_packets; ++i) {
635  if(construct_next_packet()) {
636  unicast_send(&unicast, &receiver);
637  stats.sent++;
638  }
639  PROCESS_PAUSE();
640  }
641 
642  shell_output_str(&netperf_command, "Requesting statistics from ", recvstr);
643  while(!send_ctrl_command(&receiver, CTRL_COMMAND_STATS)) {
644  PROCESS_PAUSE();
645  }
646  PROCESS_YIELD_UNTIL(ev == CONTINUE_EVENT);
647 
648  /* Wait for reply */
649  PROCESS_YIELD_UNTIL(ev == CONTINUE_EVENT);
650 
651  finalize_stats(&stats);
652  print_local_stats(&stats);
653  }
654  if(do_pingpong) {
655  current_type = TYPE_UNICAST_PINGPONG;
656  shell_output_str(&netperf_command, "-------- Unicast ping-pong--------", "");
657 
658  shell_output_str(&netperf_command, "Contacting ", recvstr);
659  while(!send_ctrl_command(&receiver, CTRL_COMMAND_CLEAR)) {
660  PROCESS_PAUSE();
661  }
662  PROCESS_YIELD_UNTIL(ev == CONTINUE_EVENT);
663 
664  shell_output_str(&netperf_command, "Measuring two-way unicast performance to ", recvstr);
665 
666  setup_sending(&receiver, num_packets);
667 
668  for(i = 0; i < num_packets; ++i) {
669  if(construct_next_echo()) {
670 
671  unicast_send(&unicast, &receiver);
672  stats.sent++;
673  }
675  PROCESS_YIELD_UNTIL(ev == CONTINUE_EVENT || etimer_expired(&e));
676  }
677 
678  shell_output_str(&netperf_command, "Requesting statistics from ", recvstr);
679  while(!send_ctrl_command(&receiver, CTRL_COMMAND_STATS)) {
680  PROCESS_PAUSE();
681  }
682  PROCESS_YIELD_UNTIL(ev == CONTINUE_EVENT);
683 
684  /* Wait for reply */
685  PROCESS_YIELD_UNTIL(ev == CONTINUE_EVENT);
686 
687  finalize_stats(&stats);
688  print_local_stats(&stats);
689  }
690  if(do_stream_pingpong) {
691  current_type = TYPE_UNICAST_STREAM;
692  shell_output_str(&netperf_command, "-------- Unicast stream ping-pong--------", "");
693 
694  shell_output_str(&netperf_command, "Contacting ", recvstr);
695  while(!send_ctrl_command(&receiver, CTRL_COMMAND_CLEAR)) {
696  PROCESS_PAUSE();
697  }
698  PROCESS_YIELD_UNTIL(ev == CONTINUE_EVENT);
699 
700  shell_output_str(&netperf_command, "Measuring two-way unicast stream performance to ", recvstr);
701 
702  setup_sending(&receiver, num_packets);
703 
704  for(i = 0; i < num_packets; ++i) {
705  if(construct_next_stream_echo()) {
706  unicast_send(&unicast, &receiver);
707  stats.sent++;
708  }
710  PROCESS_YIELD_UNTIL(ev == CONTINUE_EVENT || etimer_expired(&e));
711  }
712 
713  shell_output_str(&netperf_command, "Requesting statistics from ", recvstr);
714  while(!send_ctrl_command(&receiver, CTRL_COMMAND_STATS)) {
715  PROCESS_PAUSE();
716  }
717  PROCESS_YIELD_UNTIL(ev == CONTINUE_EVENT);
718 
719  /* Wait for reply */
720  PROCESS_YIELD_UNTIL(ev == CONTINUE_EVENT);
721 
722  finalize_stats(&stats);
723  print_local_stats(&stats);
724 
725  }
726 
727  shell_output_str(&netperf_command, "Done", "");
728  PROCESS_END();
729 }
730 /*---------------------------------------------------------------------------*/
int mesh_send(struct mesh_conn *c, const linkaddr_t *to)
Send a mesh packet.
Definition: mesh.c:184
int etimer_expired(struct etimer *et)
Check if an event timer has expired.
Definition: etimer.c:205
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
A brief description of what this file is.
#define NULL
The null pointer.
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
Mesh callbacks.
Definition: mesh.h:73
int process_post(struct process *p, process_event_t ev, process_data_t data)
Post an asynchronous event.
Definition: process.c:322
rtimer_clock_t timesynch_time(void)
Get the current time-synchronized 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
CCIF clock_time_t clock_time(void)
Get the current clock time.
Definition: clock.c:41
unsigned long shell_strtolong(const char *str, const char **retstr)
Convert a string to a number.
Definition: shell.c:521
Callback structure for broadcast.
Definition: broadcast.h:80
void shell_register_command(struct shell_command *c)
Register a command with the shell.
Definition: shell.c:413
#define PROCESS_PAUSE()
Yield the process for a short while.
Definition: process.h:221
#define PROCESS(name, strname)
Declare a process.
Definition: process.h:307
int broadcast_send(struct broadcast_conn *c)
Send an identified best-effort broadcast packet.
Definition: broadcast.c:111
void packetbuf_clear(void)
Clear and reset the packetbuf.
Definition: packetbuf.c:77
void etimer_set(struct etimer *et, clock_time_t interval)
Set an event timer.
Definition: etimer.c:177
void mesh_open(struct mesh_conn *c, uint16_t channels, const struct mesh_callbacks *callbacks)
Open a mesh connection.
Definition: mesh.c:164
void * packetbuf_dataptr(void)
Get a pointer to the data in the packetbuf.
Definition: packetbuf.c:207
void broadcast_open(struct broadcast_conn *c, uint16_t channel, const struct broadcast_callbacks *u)
Set up an identified best-effort broadcast connection.
Definition: broadcast.c:96
#define PROCESS_YIELD_UNTIL(c)
Yield the currently running process until a condition occurs.
Definition: process.h:178
A timer.
Definition: etimer.h:76
void process_exit(struct process *p)
Cause a process to exit.
Definition: process.c:202
#define SHELL_COMMAND(name, command, description, process)
Define a shell command.
Definition: shell.h:219
#define CLOCK_SECOND
A second, measured in system clock time.
Definition: clock.h:82