Contiki 2.5
display.c
1 /*
2  * Copyright (c) 2004 Swedish Institute of Computer Science.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without modification,
6  * are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13  * 3. The name of the author may not be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
19  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
21  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
24  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
25  * OF SUCH DAMAGE.
26  *
27  * $Id: display.c,v 1.10 2010/02/23 18:44:08 adamdunkels Exp $
28  *
29  * Author: Adam Dunkels <adam@sics.se>
30  *
31  */
32 
33 #include "dev/leds.h"
34 #include "display.h"
35 #include "nodes.h"
36 #include "node.h"
37 #include "ether.h"
38 #include "lib/list.h"
39 #include "lib/memb.h"
40 #include "sensor.h"
41 
42 #include <gtk/gtk.h>
43 
44 #include <sys/time.h>
45 #include <stdlib.h>
46 #include <stdio.h>
47 #include <unistd.h>
48 
49 static GdkPixmap *pixmap = NULL;
50 static GtkWidget *drawing_area;
51 static GdkFont *font;
52 
53 #define DISPLAY_WIDTH 400
54 #define DISPLAY_HEIGHT 400
55 
56 #define BASESTATION_SIZE 4
57 
58 #define MAPSCALE 20
59 #define SCALE 2
60 
61 #define MARK_SIZE 8
62 
63 #define RADIO_SIZE 20
64 
65 #define DOT_SIZE ether_strength()
66 #define DOT_INTENSITY 3
67 
68 struct dot {
69  struct dot *next;
70  int x, y;
71  int destx, desty;
72  int size;
73  int intensity;
74 };
75 
76 MEMB(dotsmem, struct dot, 20000);
77 LIST(dots);
78 LIST(tempdots);
79 
80 static int window_is_open;
81 
82 static GdkGC *intensity_gcs[DOT_INTENSITY];
83 
84 static GdkGC *intensity_clusterhead;
85 static GdkGC *intensity_clusterhead_lightgray;
86 static GdkGC *intensity_clusterhead_red;
87 
88 static GdkGC *green, *red, *yellow, *black, *white;
89 
90 static struct nodes_node *marked_node;
91 
92 /*-----------------------------------------------------------------------------------*/
93 void
94 display_redraw(void)
95 {
96  int i;
97  struct nodes_node *n;
98  int x, y;
99  struct dot *d;
100 
101  if(!window_is_open) {
102  return;
103  }
104 
105  gdk_draw_rectangle(pixmap,
106  white,
107  TRUE,
108  0, 0,
109  drawing_area->allocation.width,
110  drawing_area->allocation.height);
111 
112 
113  for(i = 0; i < nodes_num(); ++i) {
114  n = nodes_node(i);
115  x = n->x;
116  y = n->y;
117 
118  /* if(n->type == NODE_TYPE_CLUSTERHEAD) {
119  gdk_draw_arc(pixmap,
120  intensity_clusterhead_lightgray,
121  TRUE,
122  x * SCALE - DOT_SIZE * SCALE,
123  y * SCALE - DOT_SIZE * SCALE,
124  DOT_SIZE * 2 * SCALE, DOT_SIZE * 2 * SCALE,
125  0, 360 * 64);
126  }*/
127 
128  if(n == marked_node) {
129  gdk_draw_arc(pixmap,
130  red,
131  FALSE,
132  x * SCALE - MARK_SIZE * SCALE,
133  y * SCALE - MARK_SIZE * SCALE,
134  MARK_SIZE * 2 * SCALE, MARK_SIZE * 2 * SCALE,
135  0, 360 * 64);
136  }
137 
138  }
139 
140  for(i = 0; i < nodes_num(); ++i) {
141  n = nodes_node(i);
142  x = n->x;
143  y = n->y;
144 
145  /* if(n->type == NODE_TYPE_CLUSTERHEAD) {
146  gdk_draw_rectangle(pixmap,
147  intensity_clusterhead_red,
148  TRUE,
149  x * SCALE,
150  y * SCALE,
151  3, 3);
152  for(j = 0; j < nodes_num(); ++j) {
153  m = nodes_node(j);
154  if(m->type == NODE_TYPE_CLUSTERHEAD &&
155  ((x - m->x) * (x - m->x) +
156  (y - m->y) * (y - m->y) < ether_strength() * ether_strength())) {
157  gdk_draw_line(pixmap,
158  intensity_clusterhead,
159  x * SCALE,
160  y * SCALE,
161  m->x * SCALE,
162  m->y * SCALE);
163 
164 
165  }
166  }
167  } else */ {
168 
169  if(strlen(n->text) > 0) {
170  gdk_draw_string(pixmap,
171  font,
172  black,
173  x * SCALE + 10,
174  y * SCALE + 7,
175  n->text);
176 
177  }
178  gdk_draw_rectangle(pixmap,
179  black,
180  TRUE,
181  x * SCALE,
182  y * SCALE,
183  2, 2);
184  /* gdk_draw_rectangle(pixmap,
185  drawing_area->style->white_gc,
186  TRUE,
187  x * SCALE,
188  y * SCALE,
189  2, 2);*/
190  if(n->leds & LEDS_GREEN) {
191  gdk_draw_rectangle(pixmap,
192  green,
193  TRUE,
194  x * SCALE + 2,
195  y * SCALE,
196  4, 4);
197  }
198  if(n->leds & LEDS_YELLOW) {
199  gdk_draw_rectangle(pixmap,
200  yellow,
201  TRUE,
202  x * SCALE,
203  y * SCALE + 2,
204  4, 4);
205  }
206  if(n->leds & LEDS_RED) {
207  gdk_draw_rectangle(pixmap,
208  red,
209  TRUE,
210  x * SCALE + 2,
211  y * SCALE + 2,
212  4, 4);
213  }
214  if(n->linex != 0 && n->liney != 0) {
215  gdk_draw_line(pixmap,
216  green,
217  x * SCALE,
218  y * SCALE,
219  n->linex * SCALE,
220  n->liney * SCALE);
221  gdk_draw_rectangle(pixmap,
222  green,
223  TRUE,
224  n->linex * SCALE - 2,
225  n->liney * SCALE - 2,
226  4, 4);
227  }
228 
229  if(n->radio_status) {
230  gdk_draw_arc(pixmap,
231  green,
232  FALSE,
233  x * SCALE - RADIO_SIZE * SCALE,
234  y * SCALE - RADIO_SIZE * SCALE,
235  RADIO_SIZE * 2 * SCALE, RADIO_SIZE * 2 * SCALE,
236  0, 360 * 64);
237  }
238 
239 
240  }
241 
242  }
243 
244  for(d = list_head(dots); d != NULL; d = d->next) {
245  gdk_draw_arc(pixmap,
246  intensity_gcs[d->intensity - 1],
247  FALSE,
248  d->x * SCALE - d->size * SCALE,
249  d->y * SCALE - d->size * SCALE,
250  d->size * 2 * SCALE, d->size * 2 * SCALE,
251  0, 360 * 64);
252  }
253 
254 
255  gtk_widget_draw(drawing_area, NULL);
256 
257 }
258 /*-----------------------------------------------------------------------------------*/
259 void
260 display_tick(void)
261 {
262  struct dot *d, *e;
263  struct ether_packet *p;
264 
265  if(!window_is_open) {
266  return;
267  }
268 
269  /* Fade out active dots. The intensity value of each dot is counted
270  downwards, and those dots that still have an intensity are placed
271  in a temporary list. The temporary list is then copied into the
272  list of all dots. */
273 
274  list_init(tempdots);
275 
276  for(d = list_head(dots);
277  d != NULL;
278  d = e) {
279  if(d != NULL) {
280  e = d->next;
281  } else {
282  e = NULL;
283  }
284  if(d->size > 20) {
285  d->size /= 2;
286  } else {
287  d->size -= 4;
288  }
289  /* --(d->intensity);*/
290  if(d->size > 0) {
291  list_push(tempdots, d);
292  } else {
293  memb_free(&dotsmem, (void *)d);
294  }
295  }
296  list_copy(dots, tempdots);
297 
298  /* Check if there are any new dots that should be placed in the list. */
299  for(p = ether_packets(); p != NULL; p = p->next) {
300  d = (struct dot *)memb_alloc(&dotsmem);
301 
302  if(d != NULL) {
303  d->x = p->x;
304  d->y = p->y;
305  d->size = DOT_SIZE;
306  d->intensity = DOT_INTENSITY;
307  list_push(dots, d);
308  }
309  }
310 }
311 /*-----------------------------------------------------------------------------------*/
312 static gint
313 configure_event(GtkWidget *widget, GdkEventConfigure *event)
314 {
315  if(pixmap != NULL) {
316  gdk_pixmap_unref(pixmap);
317  }
318 
319  pixmap = gdk_pixmap_new(widget->window,
320  widget->allocation.width,
321  widget->allocation.height,
322  -1);
323 
324  if(pixmap == NULL) {
325  printf("gdk_pixmap_new == NULL\n");
326  exit(1);
327  }
328  gdk_draw_rectangle(pixmap,
329  widget->style->black_gc,
330  TRUE,
331  0, 0,
332  widget->allocation.width,
333  widget->allocation.height);
334  /* draw_screen();*/
335  return TRUE;
336 }
337 
338 /* Redraw the screen from the backing pixmap */
339 static gint
340 expose_event (GtkWidget * widget, GdkEventExpose * event)
341 {
342  /* draw_screen();*/
343  gdk_draw_pixmap(widget->window,
344  widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
345  pixmap,
346  event->area.x, event->area.y,
347  event->area.x, event->area.y,
348  event->area.width, event->area.height);
349  return FALSE;
350 }
351 
352 static gint
353 key_press_event (GtkWidget * widget, GdkEventKey * event)
354 {
355  /* if(event->keyval == GDK_Shift_L ||
356  event->keyval == GDK_Shift_R) {
357  return TRUE;
358  }
359  keys[lastkey] = event->keyval;
360  ++lastkey;
361  if(lastkey >= NUMKEYS) {
362  lastkey = 0;
363  }*/
364 
365  if(event->keyval == 'q') {
366  gtk_exit(0);
367  /* exit(0);*/
368  }
369  if(event->keyval == 'p') {
370  display_output_fig();
371  }
372  return TRUE;
373 }
374 
375 static gint
376 key_release_event (GtkWidget * widget, GdkEventKey * event)
377 {
378  return TRUE;
379 }
380 
381 static gint
382 button_press_event (GtkWidget * widget, GdkEventKey * event)
383 {
384  struct dot *d;
385  struct sensor_data s;
386  GdkModifierType state;
387  int x, y;
388 
389  gdk_window_get_pointer (event->window, &x, &y, &state);
390 
391  x = ((GdkEventButton*)event)->x / SCALE;
392  y = ((GdkEventButton*)event)->y / SCALE;
393 
394  if(state & GDK_BUTTON1_MASK) {
395  d = (struct dot *)memb_alloc(&dotsmem);
396 
397  if(d != NULL) {
398  d->x = x;
399  d->y = y;
400  d->size = sensor_strength();
401  d->intensity = DOT_INTENSITY - 2;
402  list_push(dots, d);
403  }
404  sensor_data_init(&s);
405  s.pir = 1;
406  s.button = 0;
407  s.vib = 0;
408  ether_send_sensor_data(&s, x, y, sensor_strength());
409  } else if(state & GDK_BUTTON2_MASK) {
410  sensor_data_init(&s);
411  s.pir = 0;
412  s.button = 1;
413  s.vib = 0;
414  if(marked_node != NULL) {
415  ether_send_sensor_data(&s, marked_node->x, marked_node->y, 1);
416  }
417  } else if(state & GDK_BUTTON3_MASK) {
418  sensor_data_init(&s);
419  s.pir = 0;
420  s.button = 0;
421  s.vib = 1;
422  if(marked_node != NULL) {
423  ether_send_sensor_data(&s, marked_node->x, marked_node->y, 1);
424  }
425  }
426 
427  return TRUE;
428 }
429 
430 static gint
431 pointer_motion_event (GtkWidget * widget, GdkEventMotion * event)
432 {
433  struct dot *d;
434  struct sensor_data s;
435  GdkModifierType state;
436 
437  int x, y;
438  struct nodes_node *node, *closest;
439  int nodex, nodey;
440  unsigned long dist;
441  int i;
442 
443  if(event->is_hint) {
444  return TRUE;
445  }
446 
447  gdk_window_get_pointer (event->window, &x, &y, &state);
448  x /= SCALE;
449  y /= SCALE;
450 
451 
452  if(state & GDK_BUTTON1_MASK) {
453  d = (struct dot *)memb_alloc(&dotsmem);
454 
455  if(d != NULL) {
456  d->x = x;
457  d->y = y;
458  d->size = sensor_strength();
459  d->intensity = DOT_INTENSITY - 2;
460  list_push(dots, d);
461  }
462  sensor_data_init(&s);
463  s.pir = 1;
464  ether_send_sensor_data(&s, x, y, sensor_strength());
465  } else {
466 
467 
468  /* Find the closest node and mark it. */
469  closest = NULL;
470  dist = 0;
471  for(i = 0; i < nodes_num(); ++i) {
472  node = nodes_node(i);
473  nodex = node->x;
474  nodey = node->y;
475 
476  if(closest == NULL ||
477  (x - nodex) * (x - nodex) + (y - nodey) * (y - nodey) < dist) {
478  dist = (x - nodex) * (x - nodex) + (y - nodey) * (y - nodey);
479  closest = node;
480  }
481  }
482  marked_node = closest;
483  }
484  return TRUE;
485 }
486 
487 static void
488 quit(void)
489 {
490  gtk_exit(0);
491 }
492 /*-----------------------------------------------------------------------------------*/
493 static void (* idle)(void);
494 static gint
495 idle_callback(gpointer data)
496 {
497  idle();
498  return TRUE;
499 }
500 /*-----------------------------------------------------------------------------------*/
501 static GdkGC *
502 get_color(unsigned short r, unsigned short g, unsigned short b)
503 {
504  GdkGCValues values;
505  GdkColor color;
506 
507  color.pixel = 0;
508  color.red = r;
509  color.green = g;
510  color.blue = b;
511 
512  if(gdk_colormap_alloc_color(gdk_colormap_get_system(),
513  &color, FALSE, TRUE)) {
514  }
515 
516  values.foreground = color;
517 
518  return gdk_gc_new_with_values(drawing_area->window,
519  &values,
520  GDK_GC_FOREGROUND);
521 }
522 /*-----------------------------------------------------------------------------------*/
523 static void
524 stdin_callback(gpointer data, gint source, GdkInputCondition condition)
525 {
526  char buf[1000];
527  int len;
528 
529  len = read(STDIN_FILENO, &buf, sizeof(buf));
530  printf("read len %d\n", len);
531  buf[len] = 0;
532  ether_send_serial(buf);
533 }
534 /*-----------------------------------------------------------------------------------*/
535 void
536 display_init(void (* idlefunc)(void), int time, int with_gui)
537 {
538  int i;
539  GtkWidget *window;
540  GtkWidget *vbox;
541  GdkGCValues values;
542  GdkColor color;
543 
544  memb_init(&dotsmem);
545  list_init(dots);
546  list_init(tempdots);
547 
548  gtk_init(NULL, NULL);
549 
550  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
551  gtk_window_set_title(GTK_WINDOW(window), "Contiki simulation display");
552 
553  vbox = gtk_vbox_new(FALSE, 0);
554  gtk_container_add(GTK_CONTAINER (window), vbox);
555  gtk_widget_show(vbox);
556 
557  gtk_signal_connect(GTK_OBJECT (window), "destroy",
558  GTK_SIGNAL_FUNC (quit), NULL);
559 
560  font = gdk_font_load("-*-courier-medium-r-*-*-12-*-*-*-*-*-iso8859-1");
561 
562  /* Create the drawing area */
563 
564  drawing_area = gtk_drawing_area_new();
565  gtk_drawing_area_size(GTK_DRAWING_AREA (drawing_area),
566  DISPLAY_WIDTH,
567  DISPLAY_HEIGHT);
568  gtk_box_pack_start(GTK_BOX(vbox), drawing_area, TRUE, TRUE, 0);
569 
570  gtk_widget_show(drawing_area);
571 
572  /* Signals used to handle backing pixmap */
573 
574  gtk_signal_connect(GTK_OBJECT (drawing_area), "expose_event",
575  (GtkSignalFunc) expose_event, NULL);
576  gtk_signal_connect(GTK_OBJECT (drawing_area), "configure_event",
577  (GtkSignalFunc) configure_event, NULL);
578 
579  /* Event signals */
580 
581  gtk_signal_connect(GTK_OBJECT (window), "key_press_event",
582  (GtkSignalFunc) key_press_event, NULL);
583  gtk_signal_connect(GTK_OBJECT (window), "key_release_event",
584  (GtkSignalFunc) key_release_event, NULL);
585 
586  gtk_signal_connect(GTK_OBJECT (window), "button_press_event",
587  (GtkSignalFunc) button_press_event, NULL);
588 
589  gtk_signal_connect(GTK_OBJECT (window), "motion_notify_event",
590  (GtkSignalFunc) pointer_motion_event, NULL);
591 
592  gtk_widget_set_events(drawing_area,GDK_KEY_PRESS_MASK
593  | GDK_KEY_RELEASE_MASK | GDK_BUTTON_PRESS_MASK
594  | GDK_POINTER_MOTION_MASK);
595 
596  /* gtk_window_iconify(window);*/
597  if(with_gui) {
598  gtk_widget_show(window);
599  window_is_open = with_gui;
600  }
601 
602 
603  idle = idlefunc;
604  gtk_timeout_add(time, idle_callback, NULL);
605 
606  if(with_gui) {
607 
608  for(i = 0; i < DOT_INTENSITY; ++i) {
609  color.pixel = 0;
610  color.red = 0;
611  color.green = ((DOT_INTENSITY + 1) * 0xffff) / (i + 1);
612  color.blue = ((DOT_INTENSITY + 1) * 0xffff) / (i + 1);
613 
614  if(gdk_colormap_alloc_color(gdk_colormap_get_system(),
615  &color, FALSE, TRUE)) {
616  }
617 
618  values.foreground = color;
619 
620  intensity_gcs[i] = gdk_gc_new_with_values(drawing_area->window, &values,
621  GDK_GC_FOREGROUND);
622  }
623 
624  color.pixel = 0;
625  color.red = 0xbfff;
626  color.green = 0xbfff;
627  color.blue = 0xbfff;
628 
629  if(gdk_colormap_alloc_color(gdk_colormap_get_system(),
630  &color, FALSE, TRUE)) {
631  }
632 
633  values.foreground = color;
634 
635  intensity_clusterhead = gdk_gc_new_with_values(drawing_area->window, &values,
636  GDK_GC_FOREGROUND);
637 
638  color.pixel = 0;
639  color.red = 0xefff;
640  color.green = 0xefff;
641  color.blue = 0xefff;
642 
643  if(gdk_colormap_alloc_color(gdk_colormap_get_system(),
644  &color, FALSE, TRUE)) {
645  }
646 
647  values.foreground = color;
648 
649  intensity_clusterhead_lightgray = gdk_gc_new_with_values(drawing_area->window, &values,
650  GDK_GC_FOREGROUND);
651 
652  color.pixel = 0;
653  color.red = 0xffff;
654  color.green = 0;
655  color.blue = 0;
656 
657  if(gdk_colormap_alloc_color(gdk_colormap_get_system(),
658  &color, FALSE, TRUE)) {
659  }
660 
661  values.foreground = color;
662 
663  intensity_clusterhead_red = gdk_gc_new_with_values(drawing_area->window, &values,
664  GDK_GC_FOREGROUND);
665 
666 
667  red = get_color(0xffff, 0, 0);
668  green = get_color(0, 0xffff, 0);
669  yellow = get_color(0xffff, 0xffff, 0);
670  black = get_color(0, 0, 0);
671  white = get_color(0xffff, 0xffff, 0xffff);
672  }
673 
674  gdk_input_add(STDIN_FILENO, GDK_INPUT_READ, stdin_callback, NULL);
675 }
676 /*-----------------------------------------------------------------------------------*/
677 void
678 display_run(void)
679 {
680  gtk_main();
681 }
682 /*-----------------------------------------------------------------------------------*/
683 void
684 display_output_fig(void)
685 {
686  int i;
687  struct nodes_node *n;
688  int x, y;
689  int dot_radius = 75;
690  int scale = 50;
691  FILE *fp;
692  char name[40];
693  struct timeval tv;
694 
695  gettimeofday(&tv, NULL);
696  snprintf(name, sizeof(name), "network-%lu.fig", tv.tv_sec);
697 
698  fp = fopen(name, "w");
699  fprintf(fp, "#FIG 3.2\n"
700  "Landscape\n"
701  "Center\n"
702  "Inches\n"
703  "Letter\n"
704  "100.00\n"
705  "Single\n"
706  "-2\n"
707  "1200 2\n"
708  );
709 
710  for(i = 0; i < nodes_num(); ++i) {
711  n = nodes_node(i);
712  x = n->x * scale;
713  y = n->y * scale;
714 
715  fprintf(fp, "1 3 1 1 0 7 50 -1 0 4.000 1 0.0000 %d %d %d %d %d %d %d %d\n",
716  x, y,
717  dot_radius, dot_radius,
718  x, y,
719  x + dot_radius, y + dot_radius);
720 
721  if(strlen(n->text) > 0) {
722  fprintf(fp, "4 0 0 50 -1 16 18 0.0000 4 135 720 %d %d %s\\001\n",
723  x + 2 * scale, y, n->text);
724  }
725 
726  if(n->linex != 0 && n->liney != 0) {
727  fprintf(fp, "2 1 1 1 0 7 50 -1 -1 0.000 0 0 -1 0 1 2\n"
728  "1 1 4.00 60.00 120.00\n"
729  "%d %d %d %d\n",
730  x, y,
731  n->linex * scale, n->liney * scale);
732  }
733 
734  }
735 
736  fclose(fp);
737 }
738 /*-----------------------------------------------------------------------------------*/