https://github.com/tudelft/paparazzi
Tip revision: 7f672efb6e93f46ccd140faaaaf2d7692e0b4f92 authored by alessandro-mancinelli on 03 May 2023, 09:13:48 UTC
port checked, working, missing PWM drivers
port checked, working, missing PWM drivers
Tip revision: 7f672ef
pc_common.ml
(*
* 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_env "/bin/sh" [|"/bin/sh"; "-c"; cmd|] (Array.append (Unix.environment ()) [|"GTK_SETLOCALE=0";"LANG=C"|]) in_read in_write Unix.stderr in
Unix.close in_write;
pid, inchan
let buf_size = 512
let run_and_log = fun log exit_cb com ->
let com = com ^ " 2>&1" in
let pid, com_stdout = my_open_process_in com in
let channel_out_fd = Unix.descr_of_in_channel com_stdout in
let channel_out = GMain.Io.channel_of_descr channel_out_fd in
let cb = fun _ ->
let buf = Bytes.create buf_size in
(* loop until input returns zero *)
let rec log_input = fun out ->
let n = input out buf 0 buf_size in
(* split on beginning of new line *)
let s = Str.split (Str.regexp "^") (Bytes.to_string (Bytes.sub buf 0 n)) in
List.iter (fun l -> log l) s;
if n = buf_size then (log_input out) + n else n
in
let count = log_input com_stdout in
if count = 0 then exit_cb true;
true
in
let io_watch_out = Glib.Io.add_watch ~cond:[`IN] ~callback:cb channel_out in
pid, channel_out, com_stdout, io_watch_out
let strip_prefix = fun dir file subdir ->
let n = String.length dir in
if not (String.length file > n && String.sub file 0 n = dir) then begin
let home = Env.paparazzi_home in
let nn = String.length home in
if (String.length file > nn && String.sub file 0 nn = home) then begin
".." // String.sub file (nn+1) (String.length file - nn -1)
end else
let msg = sprintf "Selected file '%s' should be in '%s'" file dir in
GToolbox.message_box ~title:"Error" msg;
raise Exit
end else
subdir // String.sub file (n+1) (String.length file - n - 1)
let choose_xml_file = fun ?(multiple = false) 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:"xml" ~patterns:["*.xml"] ());
dialog#add_button_stock `CANCEL `CANCEL ;
dialog#add_select_button_stock `OPEN `OPEN ;
dialog#set_select_multiple multiple;
begin match dialog#run (), dialog#filename with
| `OPEN, _ when multiple ->
let names = dialog#get_filenames in
dialog#destroy ();
cb (List.map (fun f -> strip_prefix dir f subdir) names)
| `OPEN, Some name ->
dialog#destroy ();
cb [strip_prefix dir name subdir]
| _ -> dialog#destroy ()
end
let run_and_monitor = fun ?(once = false) ?file ?(finished_callback = fun () -> ()) gui log com_name com args ->
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)
and outchan = ref stdin
and watches = ref [] in
let run = fun callback ->
let c = p#entry_program#text in
log (sprintf "RUN '%s'\n" c);
let (pi, out, unixfd, io_watch) = run_and_log log callback ("exec "^c) in
pid := pi;
outchan := unixfd;
(* watch for hangup/end on the out io, after small delay call callback to stop/remove prog *)
let io_watch' = Glib.Io.add_watch ~cond:[`HUP] ~callback:
(fun _ ->
(* call with a delay of 200ms, not strictly needed anymore, but seems more pleasing to the eye *)
ignore (Glib.Timeout.add ~ms:200 ~callback:(fun () -> callback true; false));
(* return true to not automatically remove event source,
otherwise will try to remove non existent source in callback, resulting in:
GLib-CRITICAL **: Source ID xxx was not found when attempting to remove it *)
true) out in
watches := [ io_watch; io_watch' ] in
let remove_callback = fun () ->
gui#vbox_programs#remove p#toplevel#coerce in
let rec callback = fun stop ->
match p#button_stop#label, stop with
"gtk-stop", _ ->
List.iter Glib.Io.remove !watches;
close_in !outchan;
ignore (Unix.kill !pid Sys.sigkill);
begin match Unix.waitpid [] !pid with
| (x, Unix.WEXITED 0) ->
log (sprintf "\nDONE '%s'\n\n" com);
| (x, Unix.WEXITED i) ->
log (sprintf "\nFAILED '%s' with code %i\n\n" com i);
| (x, _) ->
log (sprintf "\nSTOPPED '%s'\n\n" com);
end;
finished_callback ();
p#button_stop#set_label "gtk-redo";
p#button_remove#misc#set_sensitive true;
if once then
remove_callback ()
else 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));
ignore (p#entry_program#connect#activate ~callback:(fun () -> callback false));
run callback;
(* Stop the program if the box is closed *)
let callback = fun () ->
callback true in
ignore(p#toplevel#connect#destroy ~callback);
(* Remove button *)
ignore (p#button_remove#connect#clicked ~callback:remove_callback)
let basic_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 (fun _ -> ()) com)
let command = fun ?file ?finished_callback gui (log:string->unit) ac_name target ->
let com = sprintf "make -C %s -f Makefile.ac AIRCRAFT=%s %s" Env.paparazzi_src ac_name target in
run_and_monitor ~once:true ?file ?finished_callback gui log "make" com ""
let conf_is_set = fun home ->
Sys.file_exists home &&
Sys.file_exists (home // "conf") &&
Sys.file_exists (home // "data")
(* This was the place where GnoDruid used to create a wizard configuring your
* paparazzi installation. This could be replaced with an implementation using
* GtkAssistant instead. The issue tracking this can be found at:
* https://github.com/paparazzi/paparazzi/issues/923
*)
let _ =
let home = Env.paparazzi_home in
if not (conf_is_set home) then
printf "ERROR: Configuration files need to be installed in your \
Paparazzi home (%s). Run `make init` in the toplevel paparazzi \
directory to do that in your Paparazzi home (%s) directory. To \
use another directory, set the PAPARAZZI_HOME variable to the \
desired folder.\n" home home
let conf_xml_file = conf_dir // "conf.xml"
let backup_xml_file = conf_xml_file ^ "~"
let aircrafts = Hashtbl.create 7
let build_aircrafts = fun () ->
let conf_xml = ExtXml.parse_file conf_xml_file in
List.iter (fun aircraft ->
Hashtbl.add aircrafts (ExtXml.attrib aircraft "name") aircraft)
(Xml.children conf_xml)