/
pc_control_panel.ml
268 lines (239 loc) · 8.78 KB
/
pc_control_panel.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
(*
* $Id$
*
* Paparazzi center processes 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
module Utils = Pc_common
let (//) = Filename.concat
let control_panel_xml_file = Utils.conf_dir // "control_panel.xml"
let control_panel_xml = ExtXml.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 ->
try
let xml = Hashtbl.find programs x in
Env.paparazzi_src // ExtXml.attrib xml "command"
with Not_found ->
failwith (sprintf "Fatal Error: Program '%s' not found in control_panel.xml" x)
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 gui log com_name args ->
Utils.run_and_monitor ?file gui log com_name (program_command com_name) args
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 session_combo ->
(* Ask for a session name *)
let text = Gtk_tools.combo_value session_combo in
let text = if text = "" then "My session" else text in
match GToolbox.input_string ~ok:"Save" ~text ~title:"Session name" "Save custom session ?" with
None -> ""
| 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 ();
name
let double_quote = fun s ->
if String.contains s ' ' then
sprintf "\"%s\"" s
else
s
let supervision = fun ?file gui log (ac_combo : Gtk_tools.combo) ->
let run_gcs = fun () ->
run_and_monitor ?file gui log "GCS" ""
and run_server = fun args ->
run_and_monitor ?file gui log "Server" args
and run_sitl = fun ac_name ->
let args = sprintf "-a %s -boot -norc" ac_name in
run_and_monitor ?file gui log "Simulator" args
in
(* Sessions *)
let session_combo = Gtk_tools.combo [] gui#vbox_session in
let remove_custom_sessions = fun () ->
let (store, _column) = Gtk_tools.combo_model session_combo in
store#clear ()
in
let register_custom_sessions = fun () ->
remove_custom_sessions ();
Gtk_tools.add_to_combo session_combo "Simulation";
Gtk_tools.add_to_combo session_combo "Replay";
Gtk_tools.add_to_combo session_combo Gtk_tools.combo_separator;
Hashtbl.iter
(fun name _session ->
Gtk_tools.add_to_combo session_combo name)
sessions in
register_custom_sessions ();
Gtk_tools.select_in_combo session_combo "Simulation";
let execute_custom = fun session_name ->
let session = try Hashtbl.find sessions session_name with Not_found -> failwith (sprintf "Unknown session: %s" session_name) in
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 ?file gui log name !p)
(Xml.children session)
in
(* Replay session *)
let replay = fun () ->
run_and_monitor ?file gui log "Log File Player" "";
run_server "-n";
run_gcs () in
(* Simulations *)
let simulation = fun () ->
run_gcs ();
run_server "-n";
run_sitl (Gtk_tools.combo_value ac_combo) in
(* Run session *)
let callback = fun () ->
match Gtk_tools.combo_value session_combo with
"Simulation" -> simulation ()
| "Replay" -> replay ()
| custom -> execute_custom custom in
ignore (gui#button_execute#connect#clicked ~callback);
(* Close session *)
let callback = fun () ->
close_programs gui in
ignore (gui#button_remove_all_processes#connect#clicked ~callback);
(* Tools *)
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 compare = fun x y ->
match x, y with
`I (x, _), `I (y, _) -> compare x y
| _ -> compare x y in
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;
(* New session *)
let callback = fun () ->
match GToolbox.input_string ~title:"New session" ~text:"My session" "New session name ?" with
None -> ()
| Some s ->
Gtk_tools.add_to_combo session_combo s in
ignore (gui#menu_item_new_session#connect#activate ~callback);
(* Save new session *)
let callback = fun () ->
match save_session gui session_combo with
"" -> ()
| session_name ->
register_custom_sessions ();
Gtk_tools.select_in_combo session_combo session_name
in
ignore (gui#menu_item_save_session#connect#activate ~callback);
(* Remove current session *)
let callback = fun () ->
let session_name = Gtk_tools.combo_value session_combo in
match GToolbox.question_box ~title:"Delete custom session" ~buttons:["Cancel"; "Delete"] ~default:2 (sprintf "Delete '%s' custom session ? (NO undo)" session_name) with
2 ->
if Hashtbl.mem sessions session_name then begin
Hashtbl.remove sessions session_name;
write_control_panel_xml ();
register_custom_sessions ()
end;
close_programs gui
| _ -> ()
in
ignore (gui#menu_item_delete_session#connect#activate ~callback);
session_combo, execute_custom