diff --git a/Makefile b/Makefile
index 6444bbab5f..24f6a61a59 100644
--- a/Makefile
+++ b/Makefile
@@ -55,7 +55,7 @@ ARMGCC=/usr/bin/arm-elf-gcc
all: static
-static : lib tools cockpit visu3d multimon tmtc logalizer lpc21iap sim_static static_h usb_lib
+static : lib center tools cockpit visu3d multimon tmtc logalizer lpc21iap sim_static static_h usb_lib
conf: conf/conf.xml conf/control_panel.xml
@@ -66,6 +66,9 @@ conf/%.xml :conf/%.xml.example
lib:
cd $(LIB)/ocaml; $(MAKE)
+center: lib
+ cd sw/supervision; make
+
tools: lib
cd $(TOOLS); make
diff --git a/Makefile.install b/Makefile.install
index c6c3d06864..d096e90f88 100644
--- a/Makefile.install
+++ b/Makefile.install
@@ -20,6 +20,8 @@ install_data:
$(INSTALL) -d $(DESTDIR)/data/pictures
$(INSTALLDATA) var/maps/trtqtttqtsrrt*.jpg $(DESTDIR)/data/maps
$(INSTALLDATA) data/pictures/*.gif data/pictures/*.svg data/pictures/*.jpg data/pictures/*.png $(DESTDIR)/data/pictures
+ $(INSTALL) -d $(PREFIX)/usr/share/pixmaps
+ $(INSTALLDATA) data/pictures/penguin_icon.png $(PREFIX)/usr/share/pixmaps/paparazzi.png
$(INSTALL) -d $(DESTDIR)/data/srtm
$(INSTALLDATA) data/srtm/N43E001.hgt.bz2 $(DESTDIR)/data/srtm
@@ -73,6 +75,8 @@ install_bin:
$(INSTALL) -d $(PREFIX)/usr/bin/
$(INSTALL) -d $(DESTDIR)/sw/supervision
$(INSTALL) sw/supervision/paparazzi.pl $(DESTDIR)/sw/supervision
+ $(INSTALL) sw/supervision/paparazzicenter.glade $(DESTDIR)/sw/supervision
+ $(INSTALL) sw/supervision/*.cmo $(DESTDIR)/sw/supervision
$(INSTALL) paparazzi-make $(PREFIX)/usr/bin/
$(INSTALLDATA) -d $(DESTDIR)/sw/simulator
$(INSTALL) sw/simulator/*.cmo $(DESTDIR)/sw/simulator
@@ -90,6 +94,7 @@ install_bin:
$(INSTALL) sw/logalizer/plot.pl $(DESTDIR)/sw/logalizer
ln -sf ../share/paparazzi/sw/ground_segment/cockpit/gcs $(PREFIX)/usr/bin/paparazzi-gcs
ln -sf ../share/paparazzi/sw/supervision/paparazzi.pl $(PREFIX)/usr/bin/paparazzi
+ ln -sf ../share/paparazzi/sw/supervision/paparazzicenter $(PREFIX)/usr/bin/paparazzicenter
install_libs:
$(INSTALL) -d $(PREFIX)/usr/lib/perl5/Paparazzi
diff --git a/conf/airframes/microjet5.xml b/conf/airframes/microjet5.xml
index d26c4c1c88..44a6955d36 100644
--- a/conf/airframes/microjet5.xml
+++ b/conf/airframes/microjet5.xml
@@ -253,7 +253,7 @@ ap.CFLAGS += -DINFRARED
ap.srcs += infrared.c estimator.c
ap.CFLAGS += -DNAV
-ap.srcs += nav.c fw_h_ctl.c fw_v_ctl.c
+ap.srcs += nav.c fw_h_ctl.c fw_v_ctl.c nav_survey_rectangle.c
ap.CFLAGS += -DGYRO -DADXRS150 -DPID_RATE_LOOP
@@ -267,7 +267,7 @@ ap.srcs += gyro.c
# Config for SITL simulation
include $(PAPARAZZI_SRC)/conf/autopilot/sitl.makefile
sim.CFLAGS += -DCONFIG=\"tiny.h\" -DLOITER_TRIM -DMOBILE_CAM -DCAM
-sim.srcs += nav_line.c traffic_info.c cam.c
+sim.srcs += nav_survey_rectangle.c traffic_info.c cam.c
diff --git a/conf/conf.xml.example b/conf/conf.xml.example
index 1489ae674a..07d8c665a7 100644
--- a/conf/conf.xml.example
+++ b/conf/conf.xml.example
@@ -23,26 +23,6 @@
flight_plan="flight_plans/dummy.xml"
/>
-
-
-
-
-
diff --git a/conf/flight_plans/versatile.xml b/conf/flight_plans/versatile.xml
index ba7f352f7e..7c2be21e18 100644
--- a/conf/flight_plans/versatile.xml
+++ b/conf/flight_plans/versatile.xml
@@ -1,6 +1,9 @@
-
+
+
@@ -134,5 +137,11 @@
+
+
+
+
+
+
diff --git a/debian/control.etch b/debian/control.etch
index 6f4130bdaa..6bec51f300 100644
--- a/debian/control.etch
+++ b/debian/control.etch
@@ -10,7 +10,7 @@ Package: paparazzi-dev
Architecture: any
Suggests: paparazzi-avr, paparazzi-arm7
Recommends: eagle, gs-common, tetex-extra, dia-gnome
-Depends: ivy-c-dev, ivy-c, ivy-perl, ivy-ocaml, xml-light-ocaml, liblablgtk2-ocaml-dev, make, gcc, boa, gnuplot, libgnomecanvas2-dev, libxml-dom-perl, libsubject-perl, libfile-ncopy-perl, libpcre3-dev, bzip2, libexpect-perl, cvs, liblablgl-ocaml-dev, liblablgtk2-gl-ocaml-dev, liblablgtk2-gnome-ocaml-dev, libcamlimages-ocaml-dev, libusb-dev, speech-dispatcher
+Depends: ivy-c-dev, ivy-c, ivy-perl, ivy-ocaml, xml-light-ocaml, liblablgtk2-ocaml-dev, make, gcc, boa, gnuplot, libgnomecanvas2-dev, libxml-dom-perl, libsubject-perl, libfile-ncopy-perl, libpcre3-dev, bzip2, libexpect-perl, cvs, liblablgl-ocaml-dev, liblablgtk2-gl-ocaml-dev, liblablgtk2-gnome-ocaml-dev, libcamlimages-ocaml-dev, libusb-dev, speech-dispatcher, glade, gedit
Description: Paparazzi Meta Package : common support
@@ -28,6 +28,6 @@ Description: Paparazzi Meta Package. Philips ARM7 support
Package: paparazzi-bin
Architecture: i386
-Depends: ivy-c-dev, ivy-c, ivy-perl, ivy-ocaml, xml-light-ocaml, liblablgtk2-ocaml-dev, make, gcc, boa, gnuplot, libxml-dom-perl, libsubject-perl, libfile-ncopy-perl, libpcre3-dev, bzip2, libexpect-perl, liblablgtk2-gnome-ocaml-dev, speech-dispatcher
+Depends: ivy-c-dev, ivy-c, ivy-perl, ivy-ocaml, xml-light-ocaml, liblablgtk2-ocaml-dev, make, gcc, boa, gnuplot, libxml-dom-perl, libsubject-perl, libfile-ncopy-perl, libpcre3-dev, bzip2, libexpect-perl, liblablgtk2-gnome-ocaml-dev, speech-dispatcher, gedit
Description: Paparazzi main package
diff --git a/debian/paparazzi-bin.postinst b/debian/paparazzi-bin.postinst
index ffe6251b16..8d698e0791 100755
--- a/debian/paparazzi-bin.postinst
+++ b/debian/paparazzi-bin.postinst
@@ -24,5 +24,8 @@ ${OCAMLOPT} -I +lablgtk2 -I ${DESTDIR}/sw/lib/ocaml -o plot unix.cmxa str.cmxa x
cd ${DESTDIR}/sw/simulator
${OCAMLC} -custom -I +lablgtk2 -I ${DESTDIR}/sw/lib/ocaml unix.cma str.cma xml-light.cma lablgtk.cma glibivy-ocaml.cma lib-pprz.cma gtkInit.cmo gaia.cmo -o gaia
+cd ${DESTDIR}/sw/supervision
+${OCAMLC} -custom -I +lablgtk2 -I ${DESTDIR}/sw/lib/ocaml unix.cma str.cma xml-light.cma lablgtk.cma glibivy-ocaml.cma lib-pprz.cma lablglade.cma lablgnomeui.cma gtkInit.cmo gtk_pc.cmo gtk_process.cmo pc_common.cmo pc_aircraft.cmo pc_control_panel.cmo paparazzicenter.cmo -o paparazzicenter
+
cd ${DESTDIR}/sw/tools
${OCAMLC} -custom -I +lablgtk2 -I ${DESTDIR}/sw/lib/ocaml unix.cma str.cma xml-light.cma ivy-ocaml.cma lib-pprz.cma fp_syntax.cmo fp_parser.cmo fp_lexer.cmo fp_proc.cmo gen_flight_plan.cmo -o gen_flight_plan.out
diff --git a/debian/rules b/debian/rules
index 4d4ce4c0a8..c3c1f7efa3 100644
--- a/debian/rules
+++ b/debian/rules
@@ -69,7 +69,7 @@ binary-arch: build install
dh_installdocs
dh_installexamples
# dh_install
-# dh_installmenu
+ dh_installmenu
# dh_installdebconf
# dh_installlogrotate
# dh_installemacsen
diff --git a/sw/airborne/Makefile b/sw/airborne/Makefile
index e2c02149c3..f4a0b96c77 100644
--- a/sw/airborne/Makefile
+++ b/sw/airborne/Makefile
@@ -25,7 +25,7 @@ OBJDIR = $(PAPARAZZI_HOME)/var/$(AIRCRAFT)/$(TARGET)
VARINCLUDE=$(PAPARAZZI_HOME)/var/include
ACINCLUDE = $(PAPARAZZI_HOME)/var/$(AIRCRAFT)
-INCLUDES = -I $(PAPARAZZI_SRC)/sw/include -I $(PAPARAZZI_SRC)/sw/airborne -I $(PAPARAZZI_SRC)/conf/autopilot -I $(PAPARAZZI_SRC)/sw/airborne/$($(TARGET).ARCHDIR) -I $(VARINCLUDE) -I $(ACINCLUDE)
+INCLUDES = -I $(PAPARAZZI_SRC)/sw/include -I $(PAPARAZZI_SRC)/var/include -I $(PAPARAZZI_SRC)/sw/airborne -I $(PAPARAZZI_SRC)/conf/autopilot -I $(PAPARAZZI_SRC)/sw/airborne/$($(TARGET).ARCHDIR) -I $(VARINCLUDE) -I $(ACINCLUDE)
SRC_ARCH = $(PAPARAZZI_SRC)/sw/airborne/$(ARCHDIR)
diff --git a/sw/ground_segment/cockpit/gcs.ml b/sw/ground_segment/cockpit/gcs.ml
index 774cd175c6..fcf1205aa6 100644
--- a/sw/ground_segment/cockpit/gcs.ml
+++ b/sw/ground_segment/cockpit/gcs.ml
@@ -340,6 +340,7 @@ and plugin_window = ref ""
and layout_file = ref "horizontal.xml"
and edit = ref false
and display_particules = ref false
+and wid = ref None
let options =
[ "-b", Arg.String (fun x -> ivy_bus := x), "Bus\tDefault is 127.255.255.25:2010";
@@ -364,6 +365,7 @@ let options =
"-google_fill", Arg.Set GM.auto, "Google maps auto fill";
"-speech", Arg.Set Speech.active, "Active vocal messages";
"-particules", Arg.Set display_particules, "Display particules";
+ "-wid", Arg.String (fun s -> wid := Some (Int32.of_string s)), " Id of an existing window to be attached to";
"-m", Arg.String (fun x -> map_files := x :: !map_files), "Map description file"]
@@ -374,7 +376,7 @@ let quit = fun () ->
exit 0
| _ -> ()
-let create_geomap = fun window editor_frame ->
+let create_geomap = fun window switch_fullscreen editor_frame ->
let geomap = new G.widget ~height:500 ~projection:!projection () in
let menu_fact = new GMenu.factory geomap#file_menu in
@@ -385,11 +387,6 @@ let create_geomap = fun window editor_frame ->
ignore (geomap#canvas#event#connect#any (any_event geomap));
ignore (menu_fact#add_item "Redraw" ~key:GdkKeysyms._L ~callback:(fun _ -> geomap#canvas#misc#draw None));
- let switch_fullscreen = fun x ->
- if x then
- window#fullscreen ()
- else
- window#unfullscreen () in
ignore (menu_fact#add_check_item "Fullscreen" ~key:GdkKeysyms._F ~active: !fullscreen ~callback:switch_fullscreen);
ignore (menu_fact#add_item "Quit" ~key:GdkKeysyms._Q ~callback:quit);
@@ -498,18 +495,29 @@ let _main =
and height = ExtXml.int_attrib layout "height" in
(** The whole window map2d **)
- let window = GWindow.window ~title:"Paparazzi GCS" ~border_width:1 ~width ~height ~allow_shrink:true () in
- if !maximize then
- window#maximize ();
- if !fullscreen then
- window#fullscreen ();
-
- ignore (window#connect#destroy ~callback:(fun _ -> exit 0));
+ let window, switch_fullscreen =
+ match !wid with
+ None ->
+ let window = GWindow.window ~title:"Paparazzi GCS" ~border_width:1 ~width ~height ~allow_shrink:true () in
+ if !maximize then
+ window#maximize ();
+ if !fullscreen then
+ window#fullscreen ();
+ ignore (window#connect#destroy ~callback:(fun _ -> exit 0));
+ let switch_fullscreen = fun x ->
+ if x then
+ window#fullscreen ()
+ else
+ window#unfullscreen () in
+ (window:>GWindow.window_skel),switch_fullscreen
+ | Some window ->
+ (GWindow.plug ~window ~width ~height ():>GWindow.window_skel), fun _ -> () in
+
(* Editor frame *)
let editor_frame = GBin.frame () in
- let geomap, menu_fact = create_geomap window editor_frame in
+ let geomap, menu_fact = create_geomap window switch_fullscreen editor_frame in
let map_frame = GPack.vbox () in
(** Put the canvas in a frame *)
diff --git a/sw/ground_segment/tmtc/link.ml b/sw/ground_segment/tmtc/link.ml
index 424798907f..3919897e52 100644
--- a/sw/ground_segment/tmtc/link.ml
+++ b/sw/ground_segment/tmtc/link.ml
@@ -55,7 +55,7 @@ let airborne_device = fun device addr ->
match device with
"WAVECARD" -> WavecardDevice (W.addr_of_string addr)
| "XBEE" -> XBeeDevice
- | "PPRZ" -> Uart
+ | "PPRZ" | "AEROCOMM" -> Uart
| _ -> failwith (sprintf "Link: unknown datalink: %s" device)
let get_define = fun xml name ->
diff --git a/sw/ground_segment/tmtc/messages.ml b/sw/ground_segment/tmtc/messages.ml
index ee1b09f73b..658c33741d 100644
--- a/sw/ground_segment/tmtc/messages.ml
+++ b/sw/ground_segment/tmtc/messages.ml
@@ -31,11 +31,6 @@ let list_sort = fun f l -> List.sort (fun x y -> compare (f x) (f y)) l
let display_delay = 500 (* Time in second between two updates *)
let led_delay = 500 (* Time in milliseconds while the green led is displayed *)
-
-let (//) = Filename.concat
-
-let xml_file = Env.paparazzi_src // "conf" // "messages.xml"
-
let dnd_targets = [ { Gtk.target = "STRING"; flags = []; info = 0} ]
(** Display one page for a message *)
@@ -184,7 +179,7 @@ let _ =
(** Get the XML description of the required classes *)
let xml_classes =
- let xml = Xml.parse_file xml_file in
+ let xml = Pprz.messages_xml () in
let class_of = fun n ->
try
List.find (fun x -> ExtXml.attrib x "name" = n) (Xml.children xml)
diff --git a/sw/lib/ocaml/mapCanvas.ml b/sw/lib/ocaml/mapCanvas.ml
index 1adbbc6fe6..56db148e03 100644
--- a/sw/lib/ocaml/mapCanvas.ml
+++ b/sw/lib/ocaml/mapCanvas.ml
@@ -175,7 +175,7 @@ class basic_widget = fun ?(height=800) ?width ?(projection = Mercator) ?georef (
method top_still = 3.5*.s
val adj = GData.adjustment
- ~value:1. ~lower:0.05 ~upper:10.
+ ~value:1. ~lower:0.005 ~upper:10.
~step_incr:0.25 ~page_incr:1.0 ~page_size:1.0 ()
method info = info
diff --git a/sw/lib/ocaml/serial.ml b/sw/lib/ocaml/serial.ml
index ed90482923..fe06a8a101 100644
--- a/sw/lib/ocaml/serial.ml
+++ b/sw/lib/ocaml/serial.ml
@@ -86,7 +86,7 @@ let opendev device speed =
init_serial device speed
with
Failure x ->
- failwith (Printf.sprintf "%s (%s)" x device)
+ failwith (Printf.sprintf "Error %s (%s)" x device)
let close = Unix.close
diff --git a/sw/lib/perl/Paparazzi/Environment.pm b/sw/lib/perl/Paparazzi/Environment.pm
index 49c1cceb77..05c733ae1a 100644
--- a/sw/lib/perl/Paparazzi/Environment.pm
+++ b/sw/lib/perl/Paparazzi/Environment.pm
@@ -26,7 +26,7 @@ if (defined $ENV{PAPARAZZI_HOME}) {
#else {
# print "system mode\n inst_prefix INST_PREFIX";
#}
-print " paparazzi_home $paparazzi_home\n\n";
+#print " paparazzi_home $paparazzi_home\n\n";
sub set_env {
diff --git a/sw/simulator/Makefile b/sw/simulator/Makefile
index 15e8095ca1..79cf194a29 100644
--- a/sw/simulator/Makefile
+++ b/sw/simulator/Makefile
@@ -40,7 +40,7 @@ AIRBORNE = ../airborne
VARINCLUDE=$(PAPARAZZI_HOME)/var/include
ACINCLUDE = $(PAPARAZZI_HOME)/var/$(AIRCRAFT)
-all : gaia sitl.cma simhitl
+all : gaia sitl.cma simhitl launchsitl
simhitl : fg.o $(SIMHCMO) simhitl.cmo
@echo OL $@
diff --git a/sw/simulator/diffusion.ml b/sw/simulator/diffusion.ml
index a408de8328..5e7b7cb7fa 100644
--- a/sw/simulator/diffusion.ml
+++ b/sw/simulator/diffusion.ml
@@ -9,7 +9,7 @@ type plume = { mutable utm_x : float; mutable utm_y : float; mutable value : int
(* NW of Muret ref *)
let muret = utm_of WGS84 {LL.posn_lat=(Deg>>Rad)43.4624; posn_long=(Deg>>Rad)1.2727}
let royan = utm_of WGS84 {LL.posn_lat=(Deg>>Rad)45.7122; posn_long=(Deg>>Rad)(-1.2037)}
-let source = fun () -> { utm_x = royan.LL.utm_x -. 300.; utm_y = royan.LL.utm_y -. 300.; value = 255; utm_zone = royan.LL.utm_zone}
+let source = fun () -> { utm_x = muret.LL.utm_x -. 300.; utm_y = muret.LL.utm_y -. 300.; value = 255; utm_zone = muret.LL.utm_zone}
let available_ids = ref []
let gen_id =
diff --git a/sw/simulator/simsitl.pl b/sw/simulator/simsitl.pl
index b469cd549b..34ced1bef1 100755
--- a/sw/simulator/simsitl.pl
+++ b/sw/simulator/simsitl.pl
@@ -16,18 +16,16 @@ GetOptions (
"b=s" => \$options->{ivy_bus},
"a=s" => \$options->{aircraft},
"fg=s" => \$options->{fg},
+ "boot" => \$options->{boot},
+ "norc" => \$options->{norc},
+ "launch" => \$options->{launch},
);
my @args = ();
-push @args, "-b", $options->{ivy_bus};
+push @args, "-b", $options->{ivy_bus} if defined $options->{ivy_bus};
push @args, "-fg", $options->{fg} if defined $options->{fg};
+push @args, "-norc" if defined $options->{norc};
+push @args, "-boot" if defined $options->{boot};
+push @args, "-launch" if defined $options->{launch};
my $sim_binary = Paparazzi::Environment::paparazzi_home()."/var/".$options->{aircraft}."/sim/simsitl";
-die "$sim_binary not found. try make AIRCRAFT=$options->{aircraft} sim\n" unless -e $sim_binary;
+die "Error: $sim_binary not found. Build target 'sim' for $options->{aircraft} (make AIRCRAFT=$options->{aircraft} sim)\n" unless -e $sim_binary;
exec ($sim_binary, @args)
-
-
-
-
-
-
-
-
diff --git a/sw/simulator/sitl.ml b/sw/simulator/sitl.ml
index 3db956930b..1cfc7fe23a 100644
--- a/sw/simulator/sitl.ml
+++ b/sw/simulator/sitl.ml
@@ -33,6 +33,8 @@ let fos = float_of_string
let raw_datalink_msg_separator = Str.regexp ";"
+let norc = ref false
+
module Make(A:Data.MISSION) = struct
let servos_period = 1./.40. (* s *)
@@ -125,7 +127,8 @@ module Make(A:Data.MISSION) = struct
let my_id = ref (-1)
let init = fun id vbox ->
- rc ();
+ if not !norc then
+ rc ();
my_id := id;
sim_init ();
@@ -222,4 +225,4 @@ module Make(A:Data.MISSION) = struct
use_gps_pos (cm utm.utm_x) (cm utm.utm_y) utm.utm_zone gps.Gps.course gps.Gps.alt gps.Gps.gspeed gps.Gps.climb gps.Gps.time gps.Gps.availability gps.Gps.wgs84.Latlong.posn_lat gps.Gps.wgs84.Latlong.posn_long
end
-let options = []
+let options = ["-norc", Arg.Set norc, "Hide the simulated RC"]
diff --git a/sw/supervision/Makefile b/sw/supervision/Makefile
index 97de89960f..cff0288acb 100644
--- a/sw/supervision/Makefile
+++ b/sw/supervision/Makefile
@@ -6,25 +6,27 @@ OCAMLOPT = ocamlopt
OCAMLLIB = ../lib/ocaml
INCLUDES= -I $(OCAMLLIB) -I ../multimon -I +lablgtk2 -I +xml-light
LIBPPRZCMA=$(OCAMLLIB)/lib-pprz.cma
-PAPARAZZICENTERCMO = gui.cmo paparazzicenter.cmo
+PAPARAZZICENTERCMO = gtk_pc.cmo gtk_process.cmo pc_common.cmo pc_aircraft.cmo pc_control_panel.cmo paparazzicenter.cmo
all: paparazzicenter
paparazzicenter : $(PAPARAZZICENTERCMO) $(OCAMLLIB)/lib-pprz.cma
@echo OL $@
- $(Q)$(OCAMLC) -custom $(INCLUDES) -o $@ unix.cma str.cma xml-light.cma lablgtk.cma lablglade.cma gtkInit.cmo lib-pprz.cma $^
+ $(Q)$(OCAMLC) -custom $(INCLUDES) -o $@ unix.cma str.cma xml-light.cma lablgtk.cma lablglade.cma gtkInit.cmo lib-pprz.cma lablgnomeui.cma $^
-gui.ml : paparazzicenter.glade
+gtk_pc.ml : paparazzicenter.glade
lablgladecc2 -root window $< > $@
-program.ml : paparazzicenter.glade
- lablgladecc2 -root hbox_program $< > $@
+gtk_process.ml : paparazzicenter.glade
+ lablgladecc2 -root hbox_program $< | grep -B 1000000 " end" > $@
%.cmo : %.ml
@echo OC $<
$(Q)$(OCAMLC) $(INCLUDES) -c $<
-paparazzicenter.cmo : gui.cmo
+paparazzicenter.cmo : gtk_pc.cmo gtk_process.cmo pc_common.cmo pc_control_panel.cmo pc_aircraft.cmo
+
+pc_control_panel.cmo pc_aircraft.cmo : pc_common.cmo
clean:
- \rm *.cm* gui.ml
+ \rm *.cm* gtk_pc.ml gtk_process.ml
diff --git a/sw/supervision/paparazzicenter.glade b/sw/supervision/paparazzicenter.glade
index b203a90d94..c53cac3f2c 100644
--- a/sw/supervision/paparazzicenter.glade
+++ b/sw/supervision/paparazzicenter.glade
@@ -52,7 +52,7 @@
- 240
+ 260
100
True
True
@@ -647,72 +647,6 @@
-
-
- True
- 0
- 0.5
- GTK_SHADOW_NONE
-
-
-
- True
- 0.5
- 0.5
- 1
- 1
- 0
- 0
- 12
- 0
-
-
-
- True
- False
- 0
-
-
-
-
-
-
-
-
-
-
-
- True
- <b>Target</b>
- False
- True
- GTK_JUSTIFY_LEFT
- False
- False
- 0.5
- 0.5
- 0
- 0
- PANGO_ELLIPSIZE_NONE
- -1
- False
- 0
-
-
- label_item
-
-
-
-
- 2
- 3
- 0
- 1
- fill
- fill
-
-
-
True
@@ -876,6 +810,23 @@
False
+
+
+
+ True
+ Save the current configuration. Required for Build and Upload
+ True
+ gtk-save
+ True
+ GTK_RELIEF_NORMAL
+ True
+
+
+ 0
+ False
+ False
+
+
0
@@ -1115,23 +1066,6 @@
False
-
-
-
- True
- Save the current configuration. Required for Build and Upload
- True
- gtk-save
- True
- GTK_RELIEF_NORMAL
- True
-
-
- 0
- False
- False
-
-
0
@@ -1311,6 +1245,7 @@
True
False
+ Upload into the airborne device (which must be plugged !).
True
GTK_RELIEF_NORMAL
True
@@ -1395,6 +1330,164 @@
+
+
+
+ True
+ False
+ 0
+
+
+
+ True
+ 0
+ 0.5
+ GTK_SHADOW_NONE
+
+
+
+ True
+ 0.5
+ 0.5
+ 1
+ 1
+ 0
+ 0
+ 12
+ 0
+
+
+
+ True
+ False
+ 0
+
+
+
+
+
+
+
+
+
+
+
+ True
+ <b>Target</b>
+ False
+ True
+ GTK_JUSTIFY_LEFT
+ False
+ False
+ 0.5
+ 0.5
+ 0
+ 0
+ PANGO_ELLIPSIZE_NONE
+ -1
+ False
+ 0
+
+
+ label_item
+
+
+
+
+ 0
+ True
+ True
+
+
+
+
+
+ True
+ Add a target in the combo list
+ True
+ GTK_RELIEF_NORMAL
+ True
+
+
+
+ True
+ 0.5
+ 0.5
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+
+
+
+ True
+ False
+ 2
+
+
+
+ True
+ gtk-add
+ 4
+ 0.5
+ 0.5
+ 0
+ 0
+
+
+ 0
+ False
+ False
+
+
+
+
+
+ True
+ New Target
+ True
+ False
+ GTK_JUSTIFY_LEFT
+ False
+ False
+ 0.5
+ 0.5
+ 0
+ 0
+ PANGO_ELLIPSIZE_NONE
+ -1
+ False
+ 0
+
+
+ 0
+ False
+ False
+
+
+
+
+
+
+
+
+ 0
+ False
+ False
+
+
+
+
+ 2
+ 3
+ 0
+ 1
+ fill
+
+
+
0
@@ -1462,7 +1555,7 @@
True
- Configuration
+ Conf/Console
False
False
GTK_JUSTIFY_LEFT
@@ -1483,7 +1576,7 @@
-
+
True
False
0
@@ -1503,14 +1596,14 @@
+
+
+ True
+ False
+ 0
+
+
+
+ True
+ Current:
+ False
+ False
+ GTK_JUSTIFY_LEFT
+ False
+ False
+ 0.5
+ 0.5
+ 0
+ 0
+ PANGO_ELLIPSIZE_NONE
+ -1
+ False
+ 0
+
+
+ 0
+ False
+ False
+
+
+
+
+
+ True
+ True
+ True
+ True
+ 0
+
+ True
+ *
+ False
+ 20
+
+
+ 0
+ False
+ True
+
+
+
+
+
+ True
+ True
+ GTK_RELIEF_NORMAL
+ True
+
+
+
+ True
+ 0.5
+ 0.5
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+
+
+
+ True
+ False
+ 2
+
+
+
+ True
+ gtk-clear
+ 4
+ 0.5
+ 0.5
+ 0
+ 0
+
+
+ 0
+ False
+ False
+
+
+
+
+
+ True
+ Remove All Processes
+ True
+ False
+ GTK_JUSTIFY_LEFT
+ False
+ False
+ 0.5
+ 0.5
+ 0
+ 0
+ PANGO_ELLIPSIZE_NONE
+ -1
+ False
+ 0
+
+
+ 0
+ False
+ False
+
+
+
+
+
+
+
+
+ 0
+ False
+ False
+ GTK_PACK_END
+
+
+
+
+
+ True
+ Save current process commands in a user session
+ True
+ gtk-save
+ True
+ GTK_RELIEF_NORMAL
+ True
+
+
+ 0
+ False
+ False
+
+
+
+
+
+ True
+ Delete the current session from the user sessions
+ True
+ gtk-delete
+ True
+ GTK_RELIEF_NORMAL
+ True
+
+
+ 0
+ False
+ False
+
+
+
+
+ 0
+ False
+ False
+
+
+
True
@@ -1618,14 +1882,14 @@
False
- True
+ False
True
- Supervision
+ Control Panel
False
False
GTK_JUSTIFY_LEFT
@@ -1646,30 +1910,17 @@
-
+
True
False
0
-
- True
- False
- 0
-
-
-
-
-
-
- 0
- True
- True
-
+
- False
+ True
True
@@ -1737,12 +1988,38 @@
+ 32
True
False
0
-
+
+ True
+ process name
+ False
+ False
+ GTK_JUSTIFY_LEFT
+ False
+ False
+ 0.5
+ 0.5
+ 0
+ 0
+ PANGO_ELLIPSIZE_NONE
+ 20
+ False
+ 0
+
+
+ 0
+ False
+ False
+
+
+
+
+
True
True
True
@@ -1761,7 +2038,28 @@
-
+
+ True
+ Automatic respawn
+ True
+
+ True
+ GTK_RELIEF_NORMAL
+ True
+ False
+ False
+ True
+
+
+ 0
+ False
+ False
+
+
+
+
+
+ 32
True
True
gtk-stop
@@ -1777,8 +2075,10 @@
-
+
+ 32
True
+ False
True
gtk-remove
True
diff --git a/sw/supervision/paparazzicenter.ml b/sw/supervision/paparazzicenter.ml
index 56eed0c057..adb780c4b9 100644
--- a/sw/supervision/paparazzicenter.ml
+++ b/sw/supervision/paparazzicenter.ml
@@ -1,369 +1,93 @@
+(*
+ * $Id$
+ *
+ * Paparazzi center main module
+ *
+ * Copyright (C) 2007 ENAC, Pascal Brisset, Antoine Drouin
+ *
+ * This file is part of paparazzi.
+ *
+ * paparazzi is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * paparazzi is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with paparazzi; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ *)
+
open Printf
+open Pc_common
+module CP = Pc_control_panel
+module AC = Pc_aircraft
-let (//) = Filename.concat
-let bn = Filename.basename
-let conf_dir = Env.paparazzi_home // "conf"
-
-let gcs = Env.paparazzi_src // "sw/ground_segment/cockpit/gcs"
-
-let string_of_gdkcolor = fun c ->
- sprintf "#%2x%2x%2x" (Gdk.Color.red c) (Gdk.Color.green c) (Gdk.Color.blue c)
-
-let aircraft_sample = fun name ac_id ->
- Xml.Element ("aircraft",
- ["name", name;
- "ac_id", ac_id;
- "airframe", "airframes/microjet5.xml";
- "radio", "radios/cockpitMM.xml";
- "telemetry", "telemetry/default.xml";
- "flight_plan", "flight_plans/versatile.xml";
- "settings", "settings/tuning.xml";
- "gui_color", "blue"],
- [])
-
-
-
-let control_panel_xml = Xml.parse_file (conf_dir // "control_panel.xml")
-let programs =
- let h = Hashtbl.create 7 in
- let s = ExtXml.child ~select:(fun x -> Xml.attrib x "name" = "programs") control_panel_xml "section" in
- List.iter
- (fun p -> Hashtbl.add h (ExtXml.attrib p "name") p)
- (Xml.children s);
- h
-let program_command = fun x ->
- let xml = Hashtbl.find programs x in
- ExtXml.attrib xml "command"
-
-let conf_xml_file = conf_dir // "conf.xml"
-let conf_xml = Xml.parse_file conf_xml_file
-let aircrafts = Hashtbl.create 7
-let _ =
- List.iter (fun aircraft ->
- Hashtbl.add aircrafts (ExtXml.attrib aircraft "name") aircraft)
- (Xml.children conf_xml)
-let airframes_dir = conf_dir // "airframes"
-let flight_plans_dir = conf_dir // "flight_plans"
-
-let write_conf_xml = fun () ->
- Sys.rename conf_xml_file (conf_xml_file^"~");
- let l = Hashtbl.fold (fun _ a r -> a::r) aircrafts [] in
- let c = Xml.Element ("conf", [], l) in
- let f = open_out conf_xml_file in
- output_string f (ExtXml.to_string_fmt ~tab_attribs:true c);
- close_out f
-
-let new_ac_id = fun () ->
- let m = ref 0 in
- Hashtbl.iter
- (fun _ x ->
- m := max !m (int_of_string (ExtXml.attrib x "ac_id")))
- aircrafts ;
- !m + 1
-
-
-type combo = GEdit.combo_box * (GTree.list_store * string GTree.column)
-
-let combo = fun ?(others = []) strings vbox ->
- let strings = others @ strings in
- let (combo, (tree, column)) =
- GEdit.combo_box_text ~packing:vbox#add ~strings () in
- combo#set_active 0;
- (combo, (tree, column))
-
-let parse_conf_xml = fun vbox ->
- let strings = ref [] in
- Hashtbl.iter (fun name _ac -> strings := name :: !strings) aircrafts;
- combo ~others:[""] !strings vbox
-
-
-let combo_connect = fun ((combo: #GEdit.combo_box), (_,column)) cb ->
- ignore (combo#connect#changed
- (fun () ->
- match combo#active_iter with
- | None -> ()
- | Some row ->
- let data = combo#model#get ~row ~column in
- cb data))
-
-let combo_value = fun ((combo: #GEdit.combo_box), (_,column)) ->
- match combo#active_iter with
- | None -> raise Not_found
- | Some row -> combo#model#get ~row ~column
-
-let combo_widget = fst
-let combo_model = snd
-
-
-let is_xml_file = fun s ->
- let n = String.length s in
- n >= 4 && String.sub s (n-4) 4 = ".xml"
-
-let combo_dir = fun ?others directory vbox ->
- let files = Array.to_list (Sys.readdir directory) in
- let xml_files = List.filter is_xml_file files in
- combo ?others xml_files vbox
-
-
-let command = fun log ac_name target ->
- let com = sprintf "cd %s; export PATH=/usr/bin:$PATH; make AIRCRAFT=%s %s" Env.paparazzi_home ac_name target in
- log com;
- let com_stdout, com_stdin, com_stderr = Unix.open_process_full com [||] in
- let channel_out = GMain.Io.channel_of_descr (Unix.descr_of_in_channel com_stdout) in
- let channel_err = GMain.Io.channel_of_descr (Unix.descr_of_in_channel com_stderr) in
- let cb = fun c _ -> log (input_line c); true in
- let io_watch_out = Glib.Io.add_watch [`IN] (cb com_stdout) channel_out in
- let io_watch_err = Glib.Io.add_watch [`IN] (cb com_stderr) channel_err in
- ignore (Glib.Io.add_watch [`HUP] (fun _ -> Glib.Io.remove io_watch_out; Glib.Io.remove io_watch_err; log "\nDONE\n"; false) channel_out)
-
-
-let run = prerr_endline
-
-
-let editor =
- try Sys.getenv "EDITOR" with _ -> "gedit"
-
-let edit = fun file ->
- ignore (Sys.command (sprintf "%s '%s'&" editor file))
-
-
-let gcs_or_edit = fun file ->
- match GToolbox.question_box ~title:"Flight plan editing" ~default:2 ~buttons:["Text editor"; "GCS"] "Which editor do you want to use ?" with
- 1 -> edit file
- | 2 -> ignore (Sys.command (sprintf "%s -edit '%s'&" gcs file))
- | _ -> failwith "Internal error: gcs_or_edit"
-
-let ac_files = fun gui ->
- ["airframe", gui#label_airframe, gui#button_browse_airframe, gui#button_edit_airframe, edit;
- "flight_plan", gui#label_flight_plan, gui#button_browse_flight_plan, gui#button_edit_flight_plan, gcs_or_edit;
-(* "settings", gui#label_settings, gui#button_browse_settings, gui#button_edit_settings, edit; *)
- "radio", gui#label_radio, gui#button_browse_radio, gui#button_edit_radio, edit;
- "telemetry", gui#label_telemetry, gui#button_browse_telemetry, gui#button_edit_telemetry, edit]
-
-
-(* Awful but easier *)
-let current_color = ref "white"
-
-
-(* Link A/C to airframe & flight_plan labels *)
-let ac_combo_handler = fun gui (ac_combo:combo) target_combo ->
- combo_connect ac_combo
- (fun ac_name ->
- try
- let sample = aircraft_sample ac_name "42" in
- let aircraft = Hashtbl.find aircrafts ac_name in
- let value = fun a ->
- try (ExtXml.attrib aircraft a) with _ -> Xml.attrib sample a in
- List.iter
- (fun (a, label, _, _, _) -> label#set_text (value a))
- (ac_files gui);
- gui#entry_settings#set_text
- (value "settings");
- let ac_id = ExtXml.attrib aircraft "ac_id"
- and gui_color = ExtXml.attrib_or_default aircraft "gui_color" "white" in
- gui#button_clean#misc#set_sensitive true;
- gui#button_build#misc#set_sensitive true;
- gui#eventbox_gui_color#misc#modify_bg [`NORMAL, `NAME gui_color];
- current_color := gui_color;
- gui#entry_ac_id#set_text ac_id;
- (combo_widget target_combo)#misc#set_sensitive true;
- with
- Not_found ->
- gui#label_airframe#set_text "";
- gui#label_flight_plan#set_text "";
- gui#button_clean#misc#set_sensitive false;
- gui#button_build#misc#set_sensitive false;
- (combo_widget target_combo)#misc#set_sensitive false
- );
-
- (* New A/C button *)
- let callback = fun _ ->
- match GToolbox.input_string ~title:"New A/C" ~text:"MYAC" "New A/C name ?" with
- None -> ()
- | Some s ->
- let (store, column) = combo_model ac_combo in
- let row = store#append () in
- store#set ~row ~column s;
- let a = aircraft_sample s (string_of_int (new_ac_id ())) in
- Hashtbl.add aircrafts s a;
- (combo_widget ac_combo)#set_active_iter (Some row)
- in
- ignore (gui#button_new_ac#connect#clicked ~callback);
-
- (* Delete A/C *)
- let callback = fun _ ->
- let ac_name = combo_value ac_combo in
- if ac_name <> "" then
- match GToolbox.question_box ~title:"Delete A/C" ~buttons:["Cancel"; "Delete"] ~default:2 (sprintf "Delete %s ? (NO undo)" ac_name) with
- 2 -> begin
- begin try Hashtbl.remove aircrafts ac_name with _ -> () end;
- let combo_box = combo_widget ac_combo in
- match combo_box#active_iter with
- | None -> ()
- | Some row ->
- let (store, column) = combo_model ac_combo in
- ignore (store#remove row);
- combo_box#set_active 1
- end
- | _ -> ()
- in
- ignore (gui#button_delete_ac#connect#clicked ~callback);
-
- (* GUI color *)
- let callback = fun _ ->
- let csd = GWindow.color_selection_dialog ~show:true () in
- let callback = fun _ ->
- let colorname = string_of_gdkcolor csd#colorsel#color in
- gui#eventbox_gui_color#misc#modify_bg [`NORMAL, `NAME colorname];
- current_color := colorname;
- csd#destroy () in
- ignore (csd#ok_button#connect#clicked ~callback);
- ignore (csd#cancel_button#connect#clicked ~callback:csd#destroy) in
- ignore(gui#button_gui_color#connect#clicked ~callback);
-
- (* Save button *)
- let callback = fun _ ->
- match GToolbox.question_box ~title:"Save conf.xml" ~buttons:["Cancel"; "Save"] ~default:2 "Save in conf.xml ? (backup in conf.xml~)" with
- 2 ->
- let ac_name = combo_value ac_combo in
- if ac_name <> "" then begin
- let color = !current_color in
- let aircraft =
- Xml.Element ("aircraft",
- ["name", ac_name;
- "ac_id", gui#entry_ac_id#text;
- "airframe", gui#label_airframe#text;
- "radio", gui#label_radio#text;
- "telemetry", gui#label_telemetry#text;
- "flight_plan", gui#label_flight_plan#text;
- "settings", gui#entry_settings#text;
- "gui_color", color],
- []) in
- begin try Hashtbl.remove aircrafts ac_name with _ -> () end;
- Hashtbl.add aircrafts ac_name aircraft
- end;
- write_conf_xml ()
- | _ -> () in
- ignore(gui#button_save_ac#connect#clicked ~callback)
-
-
-let build_handler = fun gui ac_combo target_combo log ->
- (* Link target to upload button *)
- combo_connect target_combo
- (fun target ->
- gui#button_upload#misc#set_sensitive (target <> "sim"));
-
- (* Clean button *)
- let callback = fun () ->
- command log (combo_value ac_combo) "clean_ac" in
- ignore (gui#button_clean#connect#clicked ~callback);
-
- (* Build button *)
- let callback = fun () ->
- let ac_name = combo_value ac_combo
- and target = combo_value target_combo in
- command log ac_name target in
- ignore (gui#button_build#connect#clicked ~callback);
-
- (* Upload button *)
- let callback = fun () ->
- let ac_name = combo_value ac_combo
- and target = combo_value target_combo in
- command log ac_name (sprintf "%s.upload" target) in
- ignore (gui#button_upload#connect#clicked ~callback)
-
-let choose_xml_file = fun title subdir cb ->
- let dir = conf_dir // subdir in
- let dialog = GWindow.file_chooser_dialog ~action:`OPEN ~title () in
- ignore (dialog#set_current_folder dir);
- dialog#add_filter (GFile.filter ~name:"log" ~patterns:["*.xml"] ());
- dialog#add_button_stock `CANCEL `CANCEL ;
- dialog#add_select_button_stock `OPEN `OPEN ;
- begin match dialog#run (), dialog#filename with
- `OPEN, Some name ->
- dialog#destroy ();
- cb (bn name)
- | _ -> dialog#destroy ()
- end
-
-let first_word = fun s ->
- try
- let n = String.index s ' ' in
- String.sub s 0 n
- with
- Not_found -> s
-
-let conf_handler = fun gui ->
- List.iter (fun (name, label, button_browse, button_edit, editor) ->
- let callback = fun _ ->
- editor (conf_dir // label#text) in
- ignore (button_edit#connect#clicked ~callback);
- let callback = fun _ ->
- let subdir = Filename.dirname label#text in
- let cb = fun name -> label#set_text (subdir // name) in
- choose_xml_file name subdir cb in
- ignore (button_browse#connect#clicked ~callback))
- (ac_files gui);
- (* Special case for settings (not a single file) *)
- let callback = fun _ ->
- edit (conf_dir // (first_word gui#entry_settings#text)) in
- ignore (gui#button_edit_settings#connect#clicked ~callback)
-
-
-let supervision = fun gui ->
- (* Replay menu *)
- ()
-
- (* GCS button
- let callback = fun () ->
- match (combo_value session_combo) with
- "SIM" ->
- let ac_name = combo_value ac_combo in
- let sim_com = program_command "sim"
- and server = program_command "server"
- and gcs_com = program_command "gcs" in
- let sim = sprintf "%s -a %s" sim_com ac_name
- and gcs = sprintf "%s" gcs_com in
-
- run sim;
- run server;
- run gcs
- | x -> fprintf stderr "%s not yet\n" x
- in
- ignore (gui#button_GCS#connect#clicked ~callback);
-*)
-
-
-
-
let () =
let file = Env.paparazzi_src // "sw" // "supervision" // "paparazzicenter.glade" in
- let gui = new Gui.window ~file () in
- ignore (gui#window#connect#destroy ~callback:(fun _ -> exit 0));
+ let gui = new Gtk_pc.window ~file () in
+ ignore (gui#window#connect#destroy ~callback:(fun _ -> CP.close_programs gui; exit 0));
gui#toplevel#show ();
- let ac_combo = parse_conf_xml gui#vbox_ac
+ let ac_combo = AC.parse_conf_xml gui#vbox_ac
and target_combo = combo ["sim";"fbw";"ap"] gui#vbox_target in
(combo_widget target_combo)#misc#set_sensitive false;
gui#button_clean#misc#set_sensitive false;
gui#button_build#misc#set_sensitive false;
- ac_combo_handler gui ac_combo target_combo;
+ AC.ac_combo_handler gui ac_combo target_combo;
- conf_handler gui;
+ AC.conf_handler gui;
+
+ (* Change the buffer of the text view to attach a tag_table *)
+ let background_tags =
+ List.map (fun color ->
+ let tag = GText.tag ~name:color () in
+ tag#set_property (`BACKGROUND color);
+ (color, tag))
+ ["red"; "green"] in
+ let tag_table = GText.tag_table () in
+ List.iter (fun (color, tag) -> tag_table#add tag#as_tag) background_tags;
+ let buffer = GText.buffer ~tag_table () in
+ gui#console#set_buffer buffer;
+
+ let error_regexp = Str.regexp_case_fold ".*\\(error\\)\\|\\(no such file\\)" in
+ let compute_tags = fun s ->
+ if Str.string_match error_regexp s 0 then
+ [List.assoc "red" background_tags]
+ else
+ [] in
let log = fun s ->
- gui#console#buffer#insert s;
- gui#console#buffer#insert "\n";
+ let iter = gui#console#buffer#end_iter in
+ let tags = compute_tags s in
+ gui#console#buffer#insert ~iter ~tags s;
+ let iter = gui#console#buffer#end_iter in
+ gui#console#buffer#insert ~iter "\n";
(* Scroll to the bottom line *)
let end_iter = gui#console#buffer#end_iter in
let end_mark = gui#console#buffer#create_mark end_iter in
gui#console#scroll_mark_onscreen (`MARK end_mark) in
- build_handler gui ac_combo target_combo log;
+ AC.build_handler gui ac_combo target_combo log;
- supervision gui;
+ CP.supervision ~file gui log;
- GMain.Main.main ()
+ (* GCS plugin
+ Cannot reattach a new window: hack by kill and remake the socket *)
+ let rec socket = fun () ->
+ let socket_GCS = GWindow.socket ~packing:gui#vbox_GCS#add () in
+ CP.socket_GCS_id := socket_GCS#xwindow;
+ ignore(socket_GCS#connect#plug_removed
+ (fun () -> gui#vbox_GCS#remove socket_GCS#coerce; socket ())) in
+ socket ();
+
+ GMain.Main.main ();;
diff --git a/sw/supervision/pc_aircraft.ml b/sw/supervision/pc_aircraft.ml
new file mode 100644
index 0000000000..02734db0fe
--- /dev/null
+++ b/sw/supervision/pc_aircraft.ml
@@ -0,0 +1,303 @@
+(*
+ * $Id$
+ *
+ * Paparazzi center aircraft handling
+ *
+ * Copyright (C) 2007 ENAC, Pascal Brisset, Antoine Drouin
+ *
+ * This file is part of paparazzi.
+ *
+ * paparazzi is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * paparazzi is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with paparazzi; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ *)
+
+open Pc_common
+open Printf
+
+let gcs = Env.paparazzi_src // "sw/ground_segment/cockpit/gcs"
+
+let string_of_gdkcolor = fun c ->
+ sprintf "#%2x%2x%2x" (Gdk.Color.red c) (Gdk.Color.green c) (Gdk.Color.blue c)
+
+let aircraft_sample = fun name ac_id ->
+ Xml.Element ("aircraft",
+ ["name", name;
+ "ac_id", ac_id;
+ "airframe", "airframes/microjet5.xml";
+ "radio", "radios/cockpitMM.xml";
+ "telemetry", "telemetry/default.xml";
+ "flight_plan", "flight_plans/versatile.xml";
+ "settings", "settings/basic.xml";
+ "gui_color", "blue"],
+ [])
+
+
+
+let airframes_dir = conf_dir // "airframes"
+let flight_plans_dir = conf_dir // "flight_plans"
+
+let write_conf_xml = fun () ->
+ Sys.rename conf_xml_file (conf_xml_file^"~");
+ let l = Hashtbl.fold (fun _ a r -> a::r) aircrafts [] in
+ let c = Xml.Element ("conf", [], l) in
+ let f = open_out conf_xml_file in
+ output_string f (ExtXml.to_string_fmt ~tab_attribs:true c);
+ close_out f
+
+let new_ac_id = fun () ->
+ let m = ref 0 in
+ Hashtbl.iter
+ (fun _ x ->
+ m := max !m (int_of_string (ExtXml.attrib x "ac_id")))
+ aircrafts ;
+ !m + 1
+
+let parse_conf_xml = fun vbox ->
+ let strings = ref [] in
+ Hashtbl.iter (fun name _ac -> strings := name :: !strings) aircrafts;
+ combo ~others:[""] !strings vbox
+
+
+let combo_connect = fun ((combo: #GEdit.combo_box), (_,column)) cb ->
+ ignore (combo#connect#changed
+ (fun () ->
+ match combo#active_iter with
+ | None -> ()
+ | Some row ->
+ let data = combo#model#get ~row ~column in
+ cb data))
+
+let combo_value = fun ((combo: #GEdit.combo_box), (_,column)) ->
+ match combo#active_iter with
+ | None -> raise Not_found
+ | Some row -> combo#model#get ~row ~column
+
+let is_xml_file = fun s ->
+ let n = String.length s in
+ n >= 4 && String.sub s (n-4) 4 = ".xml"
+
+let combo_dir = fun ?others directory vbox ->
+ let files = Array.to_list (Sys.readdir directory) in
+ let xml_files = List.filter is_xml_file files in
+ combo ?others xml_files vbox
+
+
+
+
+let editor =
+ try Sys.getenv "EDITOR" with _ -> "gedit"
+
+let edit = fun file ->
+ ignore (Sys.command (sprintf "%s '%s'&" editor file))
+
+
+let gcs_or_edit = fun file ->
+ match GToolbox.question_box ~title:"Flight plan editing" ~default:2 ~buttons:["Text editor"; "GCS"] "Which editor do you want to use ?" with
+ 1 -> edit file
+ | 2 -> ignore (Sys.command (sprintf "%s -edit '%s'&" gcs file))
+ | _ -> failwith "Internal error: gcs_or_edit"
+
+let ac_files = fun gui ->
+ ["airframe", gui#label_airframe, gui#button_browse_airframe, gui#button_edit_airframe, edit;
+ "flight_plan", gui#label_flight_plan, gui#button_browse_flight_plan, gui#button_edit_flight_plan, gcs_or_edit;
+(* "settings", gui#label_settings, gui#button_browse_settings, gui#button_edit_settings, edit; *)
+ "radio", gui#label_radio, gui#button_browse_radio, gui#button_edit_radio, edit;
+ "telemetry", gui#label_telemetry, gui#button_browse_telemetry, gui#button_edit_telemetry, edit]
+
+
+(* Awful but easier *)
+let current_color = ref "white"
+
+
+(* Link A/C to airframe & flight_plan labels *)
+let ac_combo_handler = fun gui (ac_combo:combo) target_combo ->
+ combo_connect ac_combo
+ (fun ac_name ->
+ try
+ let sample = aircraft_sample ac_name "42" in
+ let aircraft = Hashtbl.find aircrafts ac_name in
+ let value = fun a ->
+ try (ExtXml.attrib aircraft a) with _ -> Xml.attrib sample a in
+ List.iter
+ (fun (a, label, _, _, _) -> label#set_text (value a))
+ (ac_files gui);
+ gui#entry_settings#set_text
+ (value "settings");
+ let ac_id = ExtXml.attrib aircraft "ac_id"
+ and gui_color = ExtXml.attrib_or_default aircraft "gui_color" "white" in
+ gui#button_clean#misc#set_sensitive true;
+ gui#button_build#misc#set_sensitive true;
+ gui#eventbox_gui_color#misc#modify_bg [`NORMAL, `NAME gui_color];
+ current_color := gui_color;
+ gui#entry_ac_id#set_text ac_id;
+ (combo_widget target_combo)#misc#set_sensitive true;
+ with
+ Not_found ->
+ gui#label_airframe#set_text "";
+ gui#label_flight_plan#set_text "";
+ gui#button_clean#misc#set_sensitive false;
+ gui#button_build#misc#set_sensitive false;
+ (combo_widget target_combo)#misc#set_sensitive false
+ );
+
+ (* New A/C button *)
+ let callback = fun _ ->
+ match GToolbox.input_string ~title:"New A/C" ~text:"MYAC" "New A/C name ?" with
+ None -> ()
+ | Some s ->
+ let (store, column) = combo_model ac_combo in
+ let row = store#append () in
+ store#set ~row ~column s;
+ let a = aircraft_sample s (string_of_int (new_ac_id ())) in
+ Hashtbl.add aircrafts s a;
+ aircrafts_table_has_changed := true;
+ (combo_widget ac_combo)#set_active_iter (Some row)
+ in
+ ignore (gui#button_new_ac#connect#clicked ~callback);
+
+ (* Delete A/C *)
+ let callback = fun _ ->
+ let ac_name = combo_value ac_combo in
+ if ac_name <> "" then
+ match GToolbox.question_box ~title:"Delete A/C" ~buttons:["Cancel"; "Delete"] ~default:2 (sprintf "Delete %s ? (NO undo)" ac_name) with
+ 2 -> begin
+ begin try Hashtbl.remove aircrafts ac_name with _ -> () end;
+ aircrafts_table_has_changed := true;
+ let combo_box = combo_widget ac_combo in
+ match combo_box#active_iter with
+ | None -> ()
+ | Some row ->
+ let (store, column) = combo_model ac_combo in
+ ignore (store#remove row);
+ combo_box#set_active 1
+ end
+ | _ -> ()
+ in
+ ignore (gui#button_delete_ac#connect#clicked ~callback);
+
+ (* GUI color *)
+ let callback = fun _ ->
+ let csd = GWindow.color_selection_dialog ~show:true () in
+ let callback = fun _ ->
+ let colorname = string_of_gdkcolor csd#colorsel#color in
+ gui#eventbox_gui_color#misc#modify_bg [`NORMAL, `NAME colorname];
+ current_color := colorname;
+ csd#destroy () in
+ ignore (csd#ok_button#connect#clicked ~callback);
+ ignore (csd#cancel_button#connect#clicked ~callback:csd#destroy) in
+ ignore(gui#button_gui_color#connect#clicked ~callback);
+
+ (* Save button *)
+ let callback = fun _ ->
+ match GToolbox.question_box ~title:"Save conf.xml" ~buttons:["Cancel"; "Save"] ~default:2 "Save in conf.xml ? (backup in conf.xml~)" with
+ 2 ->
+ let ac_name = combo_value ac_combo in
+ if ac_name <> "" then begin
+ let color = !current_color in
+ let aircraft =
+ Xml.Element ("aircraft",
+ ["name", ac_name;
+ "ac_id", gui#entry_ac_id#text;
+ "airframe", gui#label_airframe#text;
+ "radio", gui#label_radio#text;
+ "telemetry", gui#label_telemetry#text;
+ "flight_plan", gui#label_flight_plan#text;
+ "settings", gui#entry_settings#text;
+ "gui_color", color],
+ []) in
+ begin try Hashtbl.remove aircrafts ac_name with _ -> () end;
+ Hashtbl.add aircrafts ac_name aircraft
+ end;
+ write_conf_xml ()
+ | _ -> () in
+ ignore(gui#button_save_ac#connect#clicked ~callback)
+
+
+let build_handler = fun gui ac_combo (target_combo:combo) (log:string->unit) ->
+ (* Link target to upload button *)
+ combo_connect target_combo
+ (fun target ->
+ gui#button_upload#misc#set_sensitive (target <> "sim"));
+
+ (* New Target button *)
+ let callback = fun _ ->
+ match GToolbox.input_string ~title:"New Target" ~text:"tunnel" "New build target ?" with
+ None -> ()
+ | Some s ->
+ let (store, column) = combo_model target_combo in
+ let row = store#append () in
+ store#set ~row ~column s;
+ (combo_widget target_combo)#set_active_iter (Some row)
+ in
+ ignore (gui#button_new_target#connect#clicked ~callback);
+
+
+ (* Clean button *)
+ let callback = fun () ->
+ command log (combo_value ac_combo) "clean_ac" in
+ ignore (gui#button_clean#connect#clicked ~callback);
+
+ (* Build button *)
+ let callback = fun () ->
+ let ac_name = combo_value ac_combo
+ and target = combo_value target_combo in
+ let target = if target="sim" then target else sprintf "%s.compile" target in
+ command log ac_name target in
+ ignore (gui#button_build#connect#clicked ~callback);
+
+ (* Upload button *)
+ let callback = fun () ->
+ let ac_name = combo_value ac_combo
+ and target = combo_value target_combo in
+ command log ac_name (sprintf "%s.upload" target) in
+ ignore (gui#button_upload#connect#clicked ~callback)
+
+let choose_xml_file = fun title subdir cb ->
+ let dir = conf_dir // subdir in
+ let dialog = GWindow.file_chooser_dialog ~action:`OPEN ~title () in
+ ignore (dialog#set_current_folder dir);
+ dialog#add_filter (GFile.filter ~name:"log" ~patterns:["*.xml"] ());
+ dialog#add_button_stock `CANCEL `CANCEL ;
+ dialog#add_select_button_stock `OPEN `OPEN ;
+ begin match dialog#run (), dialog#filename with
+ `OPEN, Some name ->
+ dialog#destroy ();
+ cb (Filename.basename name)
+ | _ -> dialog#destroy ()
+ end
+
+let first_word = fun s ->
+ try
+ let n = String.index s ' ' in
+ String.sub s 0 n
+ with
+ Not_found -> s
+
+let conf_handler = fun gui ->
+ List.iter (fun (name, label, button_browse, button_edit, editor) ->
+ let callback = fun _ ->
+ editor (conf_dir // label#text) in
+ ignore (button_edit#connect#clicked ~callback);
+ let callback = fun _ ->
+ let subdir = Filename.dirname label#text in
+ let cb = fun name -> label#set_text (subdir // name) in
+ choose_xml_file name subdir cb in
+ ignore (button_browse#connect#clicked ~callback))
+ (ac_files gui);
+ (* Special case for settings (not a single file) *)
+ let callback = fun _ ->
+ edit (conf_dir // (first_word gui#entry_settings#text)) in
+ ignore (gui#button_edit_settings#connect#clicked ~callback)
diff --git a/sw/supervision/pc_common.ml b/sw/supervision/pc_common.ml
new file mode 100644
index 0000000000..4366904de1
--- /dev/null
+++ b/sw/supervision/pc_common.ml
@@ -0,0 +1,118 @@
+(*
+ * $Id$
+ *
+ * Paparazzi center utilities
+ *
+ * Copyright (C) 2007 ENAC, Pascal Brisset, Antoine Drouin
+ *
+ * This file is part of paparazzi.
+ *
+ * paparazzi is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * paparazzi is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with paparazzi; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ *)
+
+open Printf
+
+let (//) = Filename.concat
+let conf_dir = Env.paparazzi_home // "conf"
+
+(** From OCaml otherlibs/unix/unix.ml *)
+let my_open_process_in = fun cmd ->
+ let (in_read, in_write) = Unix.pipe () in
+ let inchan = Unix.in_channel_of_descr in_read in
+ let pid = Unix.create_process "/bin/sh" [|"/bin/sh"; "-c"; cmd|] Unix.stdin in_write Unix.stderr in
+ Unix.close in_write;
+ pid, inchan
+
+
+let run_and_log = fun log com ->
+ let com = com ^ " 2>&1" in
+ let pid, com_stdout = my_open_process_in com in
+ let channel_out = GMain.Io.channel_of_descr (Unix.descr_of_in_channel com_stdout) in
+ let cb = fun ev -> if List.mem `IN ev then begin log (input_line com_stdout); true end else begin log (sprintf "\nDONE (%s)\n" com); false end in
+ let _io_watch_out = Glib.Io.add_watch [`IN; `HUP] cb channel_out in
+ pid, channel_out
+
+let command = fun (log:string->unit) ac_name target ->
+ let com = sprintf "export PATH=/usr/bin:$PATH; make -C %s -f Makefile.ac AIRCRAFT=%s %s" Env.paparazzi_src ac_name target in
+ log com;
+ ignore (run_and_log log com)
+
+type combo = GEdit.combo_box * (GTree.list_store * string GTree.column)
+let combo_widget = fst
+let combo_model = snd
+
+
+let combo = fun ?(others = []) strings vbox ->
+ let strings = others @ strings in
+ let (combo, (tree, column)) =
+ GEdit.combo_box_text ~packing:vbox#add ~strings () in
+ combo#set_active 0;
+ (combo, (tree, column))
+
+
+let conf_is_set = fun home ->
+ Sys.file_exists home &&
+ Sys.file_exists (home // "conf") &&
+ Sys.file_exists (home // "data")
+
+let druid = fun home ->
+ let w = GWindow.window ~title:"Configuring Paparazzi" () in
+
+ let d = GnoDruid.druid ~packing:w#add () in
+
+ ignore (d#connect#cancel (fun () -> exit 1));
+
+ begin
+ let fp = GnoDruid.druid_page_edge ~position:`START ~aa:true ~title:"Configure Paparazzi !!" () in
+ fp#set_text (sprintf "Configuration files need to be installed in your Paparazzi home (%s). To use another directory, please exit this utility, set the PAPARAZZI_HOME variable to the desired folder and restart." home);
+ d#append_page fp;
+ ignore (fp#connect#next
+ (fun _ ->
+ command prerr_endline "" "init";
+ false
+ ))
+
+ end;
+
+ begin
+ let ep = GnoDruid.druid_page_edge ~position:`FINISH ~aa:true ~title:"The end" () in
+ ep#set_text "You are ready. Congratulations!" ;
+ d#append_page ep ;
+
+ ignore (ep#connect#finish
+ (fun _ ->
+ w#destroy ();
+ GMain.quit ()
+ ))
+ end;
+ w#show ();
+ GMain.main ()
+
+let _ =
+ let home = Env.paparazzi_home in
+ if not (conf_is_set home) then
+ druid home
+
+let conf_xml_file = conf_dir // "conf.xml"
+let conf_xml = Xml.parse_file conf_xml_file
+let aircrafts = Hashtbl.create 7
+let aircrafts_table_has_changed = ref false
+let _ =
+ List.iter (fun aircraft ->
+ Hashtbl.add aircrafts (ExtXml.attrib aircraft "name") aircraft)
+ (Xml.children conf_xml);
+ aircrafts_table_has_changed := true
diff --git a/sw/supervision/pc_control_panel.ml b/sw/supervision/pc_control_panel.ml
new file mode 100644
index 0000000000..3f96609c28
--- /dev/null
+++ b/sw/supervision/pc_control_panel.ml
@@ -0,0 +1,314 @@
+(*
+ * $Id$
+ *
+ * Paparazzi center process handling
+ *
+ * Copyright (C) 2007 ENAC, Pascal Brisset, Antoine Drouin
+ *
+ * This file is part of paparazzi.
+ *
+ * paparazzi is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * paparazzi is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with paparazzi; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ *)
+
+open Printf
+open Pc_common
+
+let socket_GCS_id = ref (Int32.of_int 0)
+
+let control_panel_xml_file = conf_dir // "control_panel.xml"
+let control_panel_xml = Xml.parse_file control_panel_xml_file
+let programs =
+ let h = Hashtbl.create 7 in
+ let s = ExtXml.child ~select:(fun x -> Xml.attrib x "name" = "programs") control_panel_xml "section" in
+ List.iter
+ (fun p -> Hashtbl.add h (ExtXml.attrib p "name") p)
+ (Xml.children s);
+ h
+let program_command = fun x ->
+ let xml = Hashtbl.find programs x in
+ Env.paparazzi_src // ExtXml.attrib xml "command"
+
+let sessions =
+ let h = Hashtbl.create 7 in
+ let s = ExtXml.child ~select:(fun x -> Xml.attrib x "name" = "sessions") control_panel_xml "section" in
+ List.iter
+ (fun p -> Hashtbl.add h (ExtXml.attrib p "name") p)
+ (Xml.children s);
+ h
+
+
+
+let not_sessions_section = fun x -> ExtXml.attrib x "name" <> "sessions"
+
+let write_control_panel_xml = fun () ->
+ Sys.rename control_panel_xml_file (control_panel_xml_file^"~");
+ let l = Hashtbl.fold (fun _ a r -> a::r) sessions [] in
+ let s = Xml.Element ("section", ["name","sessions"], l) in
+ let children = List.filter not_sessions_section (Xml.children control_panel_xml) @ [s] in
+ let c = Xml.Element ("control_panel", Xml.attribs control_panel_xml, children) in
+ let f = open_out control_panel_xml_file in
+ output_string f (ExtXml.to_string_fmt ~tab_attribs:false c);
+ close_out f
+
+let run_and_monitor = fun ?file ?(plugged=false) gui log com_name args ->
+ let com = program_command com_name in
+ let c = sprintf "%s %s" com args in
+ let p = new Gtk_process.hbox_program ?file () in
+ (gui#vbox_programs:GPack.box)#pack p#toplevel#coerce;
+ p#label_com_name#set_text com_name;
+ p#entry_program#set_text c;
+ let pid = ref (-1) in
+ let run = fun callback ->
+ let c = p#entry_program#text in
+ let c = if plugged then sprintf "%s -wid 0x%lx" c !socket_GCS_id else c in
+ if plugged then
+ gui#notebook#goto_page 2; (* FIXME *)
+ log (sprintf "Run '%s'" c);
+ let (pi, out) = run_and_log log ("exec "^c) in
+ pid := pi;
+ ignore (Glib.Io.add_watch [`HUP] (fun _ -> callback true; false) out) in
+ let rec callback = fun stop ->
+ match p#button_stop#label, stop with
+ "gtk-stop", _ ->
+ ignore (Unix.kill !pid Sys.sigkill);
+ p#button_stop#set_label "gtk-redo";
+ p#button_remove#misc#set_sensitive true;
+ if stop && p#checkbutton_autolaunch#active then
+ callback false
+ | "gtk-redo", false ->
+ p#button_stop#set_label "gtk-stop";
+ run callback;
+ p#button_remove#misc#set_sensitive false
+ | _ -> ()
+ in
+ ignore (p#button_stop#connect#clicked ~callback:(fun () -> callback false));
+ run callback;
+
+ (* Stop the program if the box is removed *)
+ let callback = fun w ->
+ callback true in
+ ignore(p#toplevel#connect#destroy ~callback);
+
+ (* Remove button *)
+ let callback = fun () ->
+ gui#vbox_programs#remove p#toplevel#coerce in
+ ignore (p#button_remove#connect#clicked ~callback)
+
+
+let close_programs = fun gui ->
+ List.iter (fun w ->
+ gui#vbox_programs#remove w;
+ w#destroy ())
+ gui#vbox_programs#children
+
+let parse_process_args = fun (name, args) ->
+ (* How to do it with a simple regexp split ??? *)
+ (* Mark spaces into args *)
+ let marked_space = Char.chr 0 in
+ let in_quotes = ref false in
+ for i = 0 to String.length args - 1 do
+ match args.[i] with
+ ' ' when !in_quotes -> args.[i] <- marked_space
+ | '"' -> in_quotes := not !in_quotes
+ | _ -> ()
+ done;
+ (* Split *)
+ let args = Str.split (Str.regexp "[ ]+") args in
+ (* Restore spaces and remove quotes *)
+ let restore_spaces = fun s ->
+ let n = String.length s in
+ for i = 0 to n - 1 do
+ if s.[i] = marked_space then s.[i] <- ' '
+ done;
+ if n >= 2 && s.[0] = '"' then
+ String.sub s 1 (n-2)
+ else
+ s in
+ let args = List.map restore_spaces args in
+ (* Remove the first "arg" which is the command *)
+ let args = List.tl args in
+ (* Build the XML arg list *)
+ let is_option = fun s -> String.length s > 0 && s.[0] = '-' in
+ let rec xml_args = function
+ [] -> []
+ | option::value::l when not (is_option value) ->
+ Xml.Element("arg", ["flag",option; "constant", value],[])::xml_args l
+ | option::l ->
+ Xml.Element("arg", ["flag",option],[])::xml_args l in
+ Xml.Element("program", ["name", name], xml_args args)
+
+let save_session = fun gui ->
+ (* Ask for a session name *)
+ let text = gui#entry_session_name#text in
+ let text = if text = "" then "My session" else text in
+ match GToolbox.input_string ~ok:"Save" ~text ~title:"Session name" "Save user session ?" with
+ None -> false
+ | Some name ->
+ let current_processes =
+ List.map (fun hbox ->
+ let hbox = new GPack.box (Gobject.unsafe_cast hbox#as_widget) in
+ match hbox#children with
+ label::entry::_ ->
+ let label = new GMisc.label (Gobject.unsafe_cast label#as_widget)
+ and entry = new GEdit.entry (Gobject.unsafe_cast entry#as_widget) in
+ (label#text, entry#text)
+ | _ -> failwith "Internal error: save session")
+ gui#vbox_programs#children in
+ let current_programs = List.map parse_process_args current_processes in
+ let session = Xml.Element("session", ["name", name], current_programs) in
+ begin try Hashtbl.remove sessions name with _ -> () end;
+ Hashtbl.add sessions name session;
+ write_control_panel_xml ();
+ true
+
+let double_quote = fun s ->
+ if String.contains s ' ' then
+ sprintf "\"%s\"" s
+ else
+ s
+
+
+let supervision = fun ?file gui log ->
+ let supervision_page = 1 in (* FIXME *)
+
+ let run_gcs = fun () ->
+ run_and_monitor ?file ~plugged:true gui log "gcs" ""
+ and run_server = fun () ->
+ run_and_monitor ?file gui log "server" ""
+ and run_link = fun args ->
+ run_and_monitor ?file gui log "link" args
+ and run_sitl = fun ac_name ->
+ let args = sprintf "-a %s -boot -norc" ac_name in
+ run_and_monitor ?file gui log "sim" args
+ in
+
+ (* Replay menu *)
+ let callback = fun () ->
+ gui#entry_session_name#set_text "Replay";
+ run_and_monitor ?file gui log "play" "";
+ run_server ();
+ run_gcs ()
+ in
+ ignore (gui#replay_menu_item#connect#activate ~callback);
+
+ (* Close session *)
+ let callback = fun () ->
+ close_programs gui in
+ ignore (gui#button_remove_all_processes#connect#clicked ~callback);
+
+ (* Programs *)
+ let entries = ref [] in
+ Hashtbl.iter
+ (fun name prog ->
+ let cb = fun () ->
+ run_and_monitor ?file gui log name "" in
+ entries := `I (name, cb) :: !entries)
+ programs;
+ let menu = GMenu.menu ()
+ and sorted_entries = List.sort compare !entries in
+ GToolbox.build_menu menu sorted_entries;
+ gui#programs_menu_item#set_submenu menu;
+
+ (* Simulations *)
+ let insert_sims_in_menu = fun num_page ->
+ if num_page = supervision_page && !aircrafts_table_has_changed then
+ let entries = ref [] in
+ Hashtbl.iter
+ (fun ac_name ac ->
+ let cb = fun () ->
+ gui#entry_session_name#set_text (sprintf "Sim %s" ac_name);
+ run_gcs ();
+ run_server ();
+ run_sitl ac_name
+ in
+ entries := `I (ac_name, cb) :: !entries)
+ aircrafts;
+ let menu = GMenu.menu ()
+ and sorted_entries = List.sort compare !entries in
+ GToolbox.build_menu menu sorted_entries;
+ gui#sim_menu_item#set_submenu menu;
+ aircrafts_table_has_changed := false in
+
+ ignore (gui#notebook#connect#switch_page ~callback:insert_sims_in_menu);
+
+ (* Sessions *)
+ let insert_sessions_in_menu = fun () ->
+ let entries = ref [] in
+ let cb = fun name session () ->
+ gui#entry_session_name#set_text name;
+ List.iter
+ (fun program ->
+ let name = ExtXml.attrib program "name" in
+ let p = ref "" in
+ List.iter
+ (fun arg ->
+ let constant =
+ try double_quote (Xml.attrib arg "constant") with _ -> "" in
+ p := sprintf "%s %s %s" !p (ExtXml.attrib arg "flag") constant)
+ (Xml.children program);
+ run_and_monitor ~plugged:(name="gcs") ?file gui log name !p)
+ (Xml.children session)
+ in
+ Hashtbl.iter
+ (fun name session ->
+ entries := `I (name, cb name session) :: !entries)
+ sessions;
+ let menu = GMenu.menu ()
+ and sorted_entries = List.sort compare !entries in
+ GToolbox.build_menu menu sorted_entries;
+ gui#session_menu_item#set_submenu menu in
+
+ insert_sessions_in_menu ();
+
+ (* Add new session *)
+ let callback = fun () ->
+ if save_session gui then
+ insert_sessions_in_menu () in
+ ignore (gui#button_save_session#connect#clicked ~callback);
+
+ (* Remove current session *)
+ let callback = fun () ->
+ let session_name = gui#entry_session_name#text in
+ match GToolbox.question_box ~title:"Delete user session" ~buttons:["Cancel"; "Delete"] ~default:2 (sprintf "Delete '%s' user session ? (NO undo)" session_name) with
+ 2 ->
+ if Hashtbl.mem sessions session_name then begin
+ Hashtbl.remove sessions session_name;
+ write_control_panel_xml ();
+ insert_sessions_in_menu ()
+ end;
+ close_programs gui;
+ gui#entry_session_name#set_text ""
+ | _ -> ()
+ in
+ ignore (gui#button_delete_session#connect#clicked ~callback);
+
+ (* Flights *)
+ let cb = fun name args () ->
+ gui#entry_session_name#set_text (sprintf "Fly with %s" name);
+ run_gcs ();
+ run_server ();
+ run_link args
+ in
+ let entries =
+ [`I ("XBee", cb "XBee" "-transport xbee -uplink");
+ `I ("Aerocomm", cb "Aerocomm" "-s 57600 -aerocomm -uplink");
+ `I ("Serial", cb "Serial" "-uplink")] in
+ let menu = GMenu.menu ()
+ and sorted_entries = List.sort compare entries in
+ GToolbox.build_menu menu sorted_entries;
+ gui#fly_menu_item#set_submenu menu
+
diff --git a/sw/tools/gen_flight_plan.ml b/sw/tools/gen_flight_plan.ml
index 4cb8a895a5..cb9159ffe2 100644
--- a/sw/tools/gen_flight_plan.ml
+++ b/sw/tools/gen_flight_plan.ml
@@ -564,7 +564,7 @@ let check_geo_ref = fun xml ->
let utm0 = utm_of WGS84 { posn_lat=(Deg>>Rad)lat0_deg;
posn_long=(Deg>>Rad)lon0_deg } in
- let max_d = get_float "max_dist_from_home" in
+ let max_d = min 1000. (get_float "max_dist_from_home") in
let check_zone = fun u ->
if (utm_of WGS84 (of_utm WGS84 u)).utm_zone <> utm0.utm_zone then
failwith "Fatal error: You are too close (less than twice the max distance) to an UTM zone border !" in