{\scriptsize \begin{lstlisting}
     1	/**
     2	   @file
     3	
     4	   Robot-Side application with GUI (simulator) to control the robot.
     5	*/
     6	
     7	#include <time.h>
     8	#include <math.h>
     9	#include <pthread.h>
    10	#include <stdio.h>
    11	#include <stdlib.h>
    12	#include <gtk/gtk.h>
    13	#include <glib.h>
    14	#include <unistd.h>
    15	#include <signal.h>
    16	#include <gdk/gdk.h>
    17	
    18	#include "../lib/libcomm.h"
    19	#include "guicommon.h"
    20	
    21	// Pointer to the Main-Application-Object. Is necessary if a function
    22	// of the GUI is called from a not-gui-object.
    23	GtkWidget *gr_application;
    24	
    25	// Pointer to the DrawinArea-Object. Is necessary if a function
    26	// of the DrawingArea is called from a not-gui-object.
    27	GtkWidget *da_global;
    28	
    29	// Stores the absolut position of the robot. 
    30	int robot_x = 50, robot_y = 0;
    31	
    32	// Configuration for LineMonitor. Stores the Soft- and Hard-Timeout
    33	// and wait-times.
    34	int soft_msec;
    35	int hard_msec;
    36	int wait_msec;
    37	
    38	// Indicates the the "system" is shutting down. Do not launch further
    39	// command to the GUI
    40	int shut_down;
    41	
    42	// Stores the portnumber on which the server operates. serverport:
    43	// Datalink (local/bind); serverport + 1: Linemonitor (remote/connect).
    44	int serverport;
    45	
    46	
    47	
    48	/**
    49	
    50	    @param widget (GtkWidget *) pointer to affected object (for
    51	    example: window).
    52	
    53	    @param event (GdkEventM *) pointer to structure which
    54	    describes the event.
    55	
    56	    @param data (gpointer) pointer to additional data from gtk.
    57	
    58	
    59	*/
    60	static gbooleandelete_event(GtkWidget *widget,
    61				    GdkEvent  *event,
    62				    gpointer   data) {
    63	  interface_stop(); // ??
    64	  fprintf(stderr, "Shut down...\n");
    65	  gtk_main_quit();
    66	  return FALSE;
    67	}
    68	
    69	
    70	/** This function will be called be gtk when the window gets a closing
    71	    command, it makes sure that the interface is down and the program
    72	    is finished.
    73	
    74	    @param widget (GtkWidget *) pointer to affected object (for
    75	    example: window).
    76	
    77	    @param data (gpointer) pointer to additional data from gtk.
    78	 */
    79	void gr_delete_event(GtkWidget *widget, gpointer data) {
    80	  interface_stop();
    81	  shut_down = 1;
    82	  fprintf(stderr, "Shut down...\n");
    83	  gtk_main_quit();
    84	  gdk_window_process_all_updates();
    85	}
    86	
    87	
    88	/** This function is called if a signal (line C-c, terminate)
    89	    occurs. See in signal() -calls in main() for detals.
    90	
    91	    @param sig (int) number of orrured signal
    92	*/
    93	static void finish(int sig) {
    94	  gr_delete_event(gr_application, NULL);
    95	}
    96	
    97	
    98	/** This function is called by gtk if the drawing area (da) needs to
    99	    be redrawn. For example if it becomes visible.
   100	
   101	    @param widget (GtkWidget *) pointer to affected object (in this
   102	    case the drawing area).
   103	
   104	    @param data (gpointer) pointer to additional data from gtk.
   105	*/
   106	void gr_da_expose_event(GtkWidget *widget, gpointer data) {
   107	  gui_common_drawrobot(widget, &robot_x, &robot_y, -1, -1, 0);
   108	}
   109	
   110	
   111	
   112	/** This function is called if a button is pressed
   113	
   114	    @param widget (GtkWidget *) pointer to affected object (button).
   115	
   116	    @param event (GdkEventMotion *) pointer to structure which
   117	    describes the event.
   118	*/
   119	
   120	void gr_button_press_event(GtkWidget *widget, gpointer data) {
   121	  if(strcmp("Emergency Stop", (char *)data) == 0) {
   122	    gr_delete_event(gr_application, NULL);    
   123	    g_print("Emergency Stop Button pressed\n");
   124	  }
   125	}
   126	
   127	
   128	/**
   129	   Function which is called from block_call() if a
   130	   message/datablock has received. See API of block_call().
   131	*/
   132	gr_block_call_do_test(int fd, int id, unsigned int type, char *buf,
   133	                   unsigned int size, int term) {
   134	  struct ROBOT_POSITION *robot_position;
   135	
   136	  // do nothing, if the system is shutting down
   137	  if (shut_down) {
   138	    return;
   139	  }
   140	
   141	  if ((sizeof(struct ROBOT_POSITION) == size) && (type == 1)) {
   142	    // load new position of the robot from the received package
   143	    robot_position = (struct ROBOT_POSITION *) buf;
   144	    robot_x = robot_position -> x;
   145	    robot_y = robot_position -> y;
   146	    free(robot_position);
   147	
   148	    // drive robot to the new coordinates
   149	    interface_driveto(robot_x, robot_y);
   150	
   151	    // make sure, that thre is no conflict with the
   152	    // gdk-main-loop. This is a locking-mechanism which privents
   153	    // "Xlib: unexpected async reply"s
   154	    gdk_threads_enter();
   155	
   156	    // re-draw the robot with the new coordinates
   157	    gui_common_drawrobot(da_global, &robot_x, &robot_y, -1, -1, 0);
   158	
   159	    // make sure, that all changed item are really plotted n the screen
   160	    gdk_window_process_all_updates();
   161	
   162	    // unlock gdk-main-loop
   163	    gdk_threads_leave();
   164	
   165	    // some of the other tries to force a re-draw of the screen -- all
   166	    // useless!
   167	    /*    while(gtk_events_pending() && !shut_down) {
   168		    gtk_main_iteration();
   169	          } */
   170	    //    gdk_flush();
   171	    //    da_global->queue_draw();
   172	    //    gtk_widget_draw(da_global, da_global);
   173	    /*    gtk_widget_queue_draw(da_global);
   174		  gtk_widget_queue_draw(gr_application);*/
   175	    //    gtk_widget_queue_clear(da_global->window);
   176	    //    da_global -> queue_draw();
   177	    //    gtk_widget_draw(da_global, NULL);
   178	    /*    gtk_signal_emit_by_name(da_global, "expose_event", 
   179		  NULL, 1);*/
   180	    //    gtk_signal_emit_by_name(GTK_OBJECT(da_global), "changed");
   181	    //    gtk_signal_emit_by_name(GTK_OBJECT(da_global), "expose_event");
   182	    //    gtk_widget_show_all(da_global);
   183	    //    gdk_window_hide(da_global->window);
   184	    //    gdk_window_show(da_global->window);
   185	    //    gdk_window_get_update_area(da_global->window);
   186	    //    gtk_widget_queue_draw(da_global);
   187	  } else {
   188	    if (type != 1) {
   189	      fprintf(stderr, "** WARNING: Unknown type of datablock received!\n");
   190	    } else {
   191	      fprintf(stderr, "** WARNING: Datablock with improper size received!\n");
   192	    }
   193	  }
   194	}
   195	
   196	
   197	/** Exception function for the linemonitor(), print exception code and
   198	    its meaning on the screen and take further action if
   199	    necessary. See API of linemonitor(). */
   200	linemonitor_exception(char *server, int port, int type) {
   201	  fprintf(stderr, "linemonitor_exception(%s, %d, %d): ",
   202		  server, port, type);
   203	  switch(type) {
   204	  case 0:
   205	    fprintf(stderr, "Connecion Fault\n");
   206	    gr_delete_event(gr_application, NULL);
   207	    break;
   208	  case 1:
   209	    fprintf(stderr, "Soft Real Time Exception\n");
   210	    break;
   211	  case 2:
   212	    fprintf(stderr, "HARD Real Time Exception\n");
   213	    gr_delete_event(gr_application, NULL);
   214	    break;
   215	  case 3:
   216	    fprintf(stderr, "Transmission Fault\n");
   217	    gr_delete_event(gr_application, NULL);
   218	    break;
   219	  case 4:
   220	    fprintf(stderr, "Emergency Stop\n");
   221	    gr_delete_event(gr_application, NULL);
   222	    break;
   223	  } /* switch() */
   224	}
   225	
   226	
   227	
   228	/**
   229	   Function which ist called from block_call() if a the connection
   230	   terminates: shut down system. See block_call() API.
   231	*/
   232	gr_block_call_term_test(int fd, int id) {
   233	  gr_delete_event(gr_application, NULL);
   234	}
   235	
   236	
   237	
   238	/**
   239	   Function which is called from socket_accept() if someone has
   240	   connected. See socket_accept() API.
   241	*/
   242	gr_socket_accept_do(int fd, int id, char *pip,
   243	                      struct sockaddr_in their_addr, int term) {
   244	
   245	  // starting line-monitor
   246	  char *pard = inet_ntoa(their_addr.sin_addr);
   247	  linemonitor(pard, serverport + 1,
   248		      soft_msec, hard_msec, wait_msec,
   249		      linemonitor_exception);
   250	  
   251	
   252	  // waiting for incomming data in an other thread
   253	  block_call(fd, id, false,
   254	             (void *) gr_block_call_do_test,
   255	             (void *) gr_block_call_term_test);
   256	}
   257	
   258	
   259	
   260	
   261	
   262	
   263	int main(int argc, char *argv[]) {
   264	  // file discriptor for the local bind.
   265	  int sock;
   266	
   267	  // GTK-Objecte. This is necessary to create the buttons on the
   268	  // screen and connect them to some actions
   269	  GtkWidget *button1, *button2, *button3, *button4;
   270	  // Sorting into tables.
   271	  GtkWidget *table, *table2;
   272	
   273	  // system is not shutting down now... (it shutting up ;-)
   274	  shut_down = 0;
   275	
   276	  // Init the gtk (GUI toolkit) and the gdk (threads) system
   277	  g_thread_init(NULL);
   278	  gdk_threads_init();
   279	  gtk_init(&argc, &argv);
   280	
   281	  // Connect the finish() -function to some signals which can cause a
   282	  // system shut down.
   283	  signal(SIGHUP, finish);  // 01  /  hangup     - close Window
   284	  signal(SIGINT, finish);  // 02  /  Interrupt  - ^C - C-c
   285	  signal(SIGQUIT, finish); // 03  /  Quit
   286	  signal(SIGTERM, finish); // 15  /  Terminierung -- kill
   287	  signal(SIGALRM, finish); // 14  /  Alarm
   288	
   289	  // load and examine parameters
   290	  if (argc == 6) {
   291	    serverport = atoi(argv[1]);
   292	    soft_msec = atoi(argv[2]);
   293	    hard_msec = atoi(argv[3]);
   294	    wait_msec = atoi(argv[4]);
   295	    interface_init(2);
   296	  } else {
   297	    if (argc == 5) {
   298	      serverport = atoi(argv[1]);
   299	      soft_msec = atoi(argv[2]);
   300	      hard_msec = atoi(argv[3]);
   301	      wait_msec = atoi(argv[4]);
   302	      interface_init(0);
   303	    } else {
   304	      fprintf(stderr, "%s port-to-bind soft_msec hard_msec wait_msec\n", argv[0]);
   305	      //      exit(0);
   306	    }
   307	  }
   308	
   309	  // bind local port and launch socket_accept() to wait for connection
   310	  if ((sock = socket_bind(serverport, 10)) < 0) {
   311	    error("bind()");
   312	  } else {
   313	    socket_accept(sock, 0, (void *) gr_socket_accept_do);
   314	  }
   315	
   316	  // create button(s)
   317	  button1  = gtk_button_new_with_label("Emergency Stop");
   318	  /*  button2  = gtk_button_new_with_label("Button 2");
   319	  button3  = gtk_button_new_with_label("Button 3");
   320	  button4  = gtk_button_new_with_label("Button 4"); */
   321	
   322	  // connect the buttons to the function gr_button_press_event(). If
   323	  // the botton is pressed, this function will be colled.
   324	  gtk_signal_connect(GTK_OBJECT(button1), "clicked",
   325			     GTK_SIGNAL_FUNC(gr_button_press_event),
   326			     "Emergency Stop" );
   327	  /*  gtk_signal_connect(GTK_OBJECT(button2), "clicked",
   328			     GTK_SIGNAL_FUNC(gr_button_press_event),
   329			     "Button 2");
   330	  gtk_signal_connect(GTK_OBJECT(button3), "clicked",
   331			     GTK_SIGNAL_FUNC(gr_button_press_event),
   332			     "Button 3" );
   333	  gtk_signal_connect(GTK_OBJECT(button4), "clicked",
   334			     GTK_SIGNAL_FUNC(gr_button_press_event),
   335			     "Button 4"); */
   336	
   337	  // create tables to sort buttons and drawindarea in it
   338	  table = gtk_table_new(2,2,FALSE);
   339	  table2 = gtk_table_new(2,2,FALSE);
   340	
   341	  // create new application (wiindow)
   342	  gr_application = gtk_window_new(GTK_WINDOW_TOPLEVEL);
   343	
   344	  // set window title
   345	  gtk_window_set_title(GTK_WINDOW (gr_application), "Robot");
   346	
   347	  // connect the function gr_delete_event() with the event of a
   348	  // window-close.
   349	  g_signal_connect(G_OBJECT (gr_application), "delete_event",
   350			   G_CALLBACK (gr_delete_event), NULL);
   351	
   352	  // display window
   353	  gtk_widget_show(gr_application);
   354	  
   355	  // create drawing area
   356	  da_global = gtk_drawing_area_new();
   357	
   358	  // set which events in the drawing area causing a expose-event
   359	  gtk_widget_set_events(da_global, GDK_EXPOSURE_MASK
   360				 | GDK_LEAVE_NOTIFY_MASK
   361				 | GDK_BUTTON_PRESS_MASK
   362				 | GDK_POINTER_MOTION_MASK
   363				 | GDK_POINTER_MOTION_HINT_MASK);
   364	  
   365	  // set a minimum size of drawing area
   366	  gtk_widget_set_size_request(da_global, 100, 100);
   367	
   368	  // connect the function gr_delete_event() with the event of a
   369	  // window-close.
   370	  gtk_signal_connect(GTK_OBJECT(gr_application), "delete_event",
   371			     GTK_SIGNAL_FUNC(gr_delete_event), NULL);
   372	
   373	  // connect the function gr_da_expose_event() with the expose-event
   374	  // of the drawing area.
   375	  gtk_signal_connect(GTK_OBJECT(da_global), "expose_event",
   376			     GTK_SIGNAL_FUNC(gr_da_expose_event), NULL);
   377	
   378	  // fill the buttons in the table
   379	  gtk_table_attach_defaults(GTK_TABLE(table2), button1, 0,1, 0,1);
   380	  /*  gtk_table_attach_defaults(GTK_TABLE(table2), button2, 0,1, 1,2);
   381	  gtk_table_attach_defaults(GTK_TABLE(table2), button3, 1,2, 0,1);
   382	  gtk_table_attach_defaults(GTK_TABLE(table2), button4, 1,2, 1,2); */
   383	
   384	  // fill the drawing area and the table into another table
   385	  gtk_table_attach_defaults(GTK_TABLE(table), da_global, 0,1, 0,1);
   386	  gtk_table_attach_defaults(GTK_TABLE(table), table2, 0,1, 1,2);
   387	
   388	  // fill this table into the windos
   389	  gtk_container_add(GTK_CONTAINER(gr_application),table);
   390	
   391	  // display it  
   392	  gtk_widget_show_all(gr_application);
   393	
   394	  // call gtk-main-loop
   395	  gtk_main();
   396	
   397	  return 0;
   398	}
   399	
   400	
\end{lstlisting}}
