diff --git a/Makefile.ac b/Makefile.ac
index bfabdb8155..73fda7678d 100644
--- a/Makefile.ac
+++ b/Makefile.ac
@@ -45,6 +45,8 @@ SETTINGS_MODULES=$(ACINCLUDE)/settings_modules.xml
SETTINGS_TELEMETRY=$(ACINCLUDE)/settings_telemetry.xml
MAKEFILE_AC=$(ACINCLUDE)/Makefile.ac
MODULES_H=$(AC_GENERATED)/modules.h
+MODULES_DIR=$(PAPARAZZI_HOME)/conf/modules/
+AUTOPILOT_H=$(AC_GENERATED)/autopilot.h
AIRCRAFT_MD5=$(AIRCRAFT_CONF_DIR)/aircraft.md5
# "make Q=''" to get full echo
@@ -70,7 +72,7 @@ print_version:
@echo "-----------------------------------------------------------------------"
-all_ac_h: $(AIRFRAME_H) $(MODULES_H) $(SETTINGS_H) $(MAKEFILE_AC) $(PERIODIC_H)
+all_ac_h: $(AIRFRAME_H) $(MODULES_H) $(SETTINGS_H) $(MAKEFILE_AC) $(PERIODIC_H) $(AUTOPILOT_H)
@echo "TARGET: " $(TARGET)"\n" > $(ACINCLUDE)/$(TARGET)_srcs.list
@echo "CFLAGS: " $($(TARGET).CFLAGS)"\n" >> $(ACINCLUDE)/$(TARGET)_srcs.list
@echo "LDFLAGS: " $($(TARGET).LDFLAGS)"\n" >> $(ACINCLUDE)/$(TARGET)_srcs.list
@@ -130,6 +132,12 @@ $(MODULES_H) : $(CONF)/$(AIRFRAME_XML) $(TOOLS)/gen_modules.out $(CONF)/modules/
$(Q)$(TOOLS)/gen_modules.out $(SETTINGS_MODULES) $< > $@
$(Q)chmod a+r $@
+$(AUTOPILOT_H) : $(CONF)/$(AIRFRAME_XML) $(TOOLS)/gen_autopilot.out $(CONF)/autopilot/*.xml
+ $(Q)test -d $(AC_GENERATED) || mkdir -p $(AC_GENERATED)
+ @echo BUILD $@
+ $(Q)$(TOOLS)/gen_autopilot.out $(CONF)/$(AIRFRAME_XML) $@
+ $(Q)chmod a+r $@
+
$(SETTINGS_MODULES) : $(MODULES_H)
$(SETTINGS_TELEMETRY) : $(PERIODIC_H)
diff --git a/conf/autopilot/autopilot.dtd b/conf/autopilot/autopilot.dtd
new file mode 100644
index 0000000000..c23f404aa6
--- /dev/null
+++ b/conf/autopilot/autopilot.dtd
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/conf/autopilot/booz_autopilot.xml b/conf/autopilot/booz_autopilot.xml
new file mode 100644
index 0000000000..fe8bdbc30b
--- /dev/null
+++ b/conf/autopilot/booz_autopilot.xml
@@ -0,0 +1,88 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/conf/autopilot/fw_autopilot.xml b/conf/autopilot/fw_autopilot.xml
new file mode 100644
index 0000000000..d17362739e
--- /dev/null
+++ b/conf/autopilot/fw_autopilot.xml
@@ -0,0 +1,80 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sw/lib/ocaml/xml2h.ml b/sw/lib/ocaml/xml2h.ml
index 6f02c3853e..a718de7193 100644
--- a/sw/lib/ocaml/xml2h.ml
+++ b/sw/lib/ocaml/xml2h.ml
@@ -47,6 +47,15 @@ let sprint_float_array = fun l ->
| x::xs -> x ^","^ loop xs in
"{" ^ loop l
+let start_and_begin_out = fun xml_file h_name out ->
+ let xml = Xml.parse_file xml_file in
+
+ fprintf out "/* This file has been generated from %s */\n" xml_file;
+ fprintf out "/* Please DO NOT EDIT */\n\n";
+
+ fprintf out "#ifndef %s\n" h_name;
+ fprintf out "#define %s\n\n" h_name;
+ xml
let start_and_begin = fun xml_file h_name ->
let xml = Xml.parse_file xml_file in
diff --git a/sw/lib/ocaml/xml2h.mli b/sw/lib/ocaml/xml2h.mli
index 7431fe3471..1055cde76d 100644
--- a/sw/lib/ocaml/xml2h.mli
+++ b/sw/lib/ocaml/xml2h.mli
@@ -28,6 +28,7 @@ val define : string -> string -> unit
val define_string : string -> string -> unit
val xml_error : string -> 'a
val sprint_float_array : string list -> string
+val start_and_begin_out : string -> string -> out_channel -> Xml.xml
val start_and_begin : string -> string -> Xml.xml
val start_and_begin_c : string -> string -> Xml.xml
val begin_c_out : string -> string -> out_channel -> unit
diff --git a/sw/tools/Makefile b/sw/tools/Makefile
index a417d4b144..8ac851f1e0 100644
--- a/sw/tools/Makefile
+++ b/sw/tools/Makefile
@@ -31,7 +31,7 @@ OCAMLNETINCLUDES=$(shell ocamlfind query -r -i-format netstring) $(shell ocamlfi
OCAMLNETCMA=$(shell ocamlfind query -r -a-format -predicates byte netstring) $(shell ocamlfind query -r -a-format -predicates byte netclient)
LIBPPRZCMA=$(LIBPPRZDIR)/lib-pprz.cma
-all: gen_common.cmo gen_aircraft.out gen_airframe.out gen_messages2.out gen_messages.out gen_ubx.out gen_mtk.out gen_flight_plan.out gen_radio.out gen_periodic.out gen_settings.out gen_xsens.out gen_modules.out gen_abi.out find_free_msg_id.out gen_srtm.out mergelogs
+all: gen_common.cmo gen_aircraft.out gen_airframe.out gen_messages2.out gen_messages.out gen_ubx.out gen_mtk.out gen_flight_plan.out gen_radio.out gen_periodic.out gen_settings.out gen_xsens.out gen_modules.out gen_autopilot.out gen_abi.out find_free_msg_id.out gen_srtm.out mergelogs
FP_CMO = fp_proc.cmo gen_flight_plan.cmo
ABS_FP = $(FP_CMO:%=$$PAPARAZZI_SRC/sw/tools/%)
diff --git a/sw/tools/gen_autopilot.ml b/sw/tools/gen_autopilot.ml
new file mode 100644
index 0000000000..bd4111b6c6
--- /dev/null
+++ b/sw/tools/gen_autopilot.ml
@@ -0,0 +1,342 @@
+(*
+ * $Id: gen_modules.ml 4538 2010-02-04 09:45:08Z gautier $
+ *
+ * XML preprocessing for core autopilot
+ *
+ * Copyright (C) 2010 Gautier Hattenberger
+ *
+ * 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 Xml2h
+
+let (//) = Filename.concat
+
+let paparazzi_conf = Env.paparazzi_home // "conf"
+let autopilot_dir = paparazzi_conf // "autopilot"
+
+(** Formatting with a margin *)
+let margin = ref 0
+let step = 2
+
+let right () = margin := !margin + step
+let left () = margin := !margin - step
+
+let lprintf = fun out f ->
+ fprintf out "%s" (String.make !margin ' ');
+ fprintf out f
+
+let get_ap_modes = fun ap ->
+ List.filter (fun m -> (Xml.tag m) = "mode") (Xml.children ap)
+
+let get_ap_control_block = fun ap ->
+ List.filter (fun m -> (Xml.tag m) = "control_block") (Xml.children ap)
+
+let get_ap_exceptions = fun ap ->
+ try ExtXml.child ap "exceptions"
+ with _ -> Xml.Element ("exceptions", [], [])
+
+let get_mode_exceptions = fun mode ->
+ List.filter (fun m -> (Xml.tag m) = "exception") (Xml.children mode)
+
+let print_mode_name = fun name ->
+ String.concat "" ["AUTOPILOT_MODE_"; (String.uppercase name)]
+
+(** Define modes *)
+let print_modes = fun modes out_h ->
+ let mode_idx = ref 0 in
+ List.iter (fun m ->
+ try
+ let name = Xml.attrib m "name" in
+ lprintf out_h "#define %s %d\n" (print_mode_name name) !mode_idx;
+ mode_idx := !mode_idx + 1;
+ with _ -> ()
+ )
+ modes
+
+(** Init function: set last_mode to initial ap_mode *) (* TODO really needed ? *)
+let print_ap_init = fun modes out_h ->
+
+ let find_default_mode = fun _ ->
+ let default = List.find_all (fun m ->
+ List.exists (fun s -> if Xml.tag s = "select" then Xml.attrib s "cond" = "$DEFAULT_MODE" else false) (Xml.children m)
+ ) modes in
+ match List.length default with
+ 0 -> List.hd modes
+ | 1 -> List.hd default
+ | _ -> failwith "Autopilot Core Error: only one default mode can be set"
+ in
+
+ let default = find_default_mode () in
+ lprintf out_h "\nstatic inline void autopilot_core_init(void) {\n";
+ right ();
+ lprintf out_h "autopilot_mode = %s;\n" (print_mode_name (Xml.attrib default "name"));
+ lprintf out_h "private_autopilot_mode = autopilot_mode;\n";
+ lprintf out_h "last_autopilot_mode = autopilot_mode;\n";
+ left ();
+ lprintf out_h "}\n"
+
+(** Function to test if a mode is selected *)
+let print_test_select = fun modes out_h ->
+ lprintf out_h "\nstatic inline uint8_t autopilot_core_mode_select(void) {\n";
+ right ();
+ List.iter (fun m -> (* Test select for all modes *)
+ let select = List.filter (fun s -> Xml.tag s = "select") (Xml.children m) in
+ List.iter (fun s -> (* In each mode, build condition and exceptions' list *)
+ let cond = Xml.attrib s "cond" in
+ let except = try String.concat " || "
+ (List.map (fun e -> Printf.sprintf "private_autopilot_mode != %s" (print_mode_name e))
+ (Str.split (Str.regexp "|") (Xml.attrib s "exception"))
+ ) with _ -> "" in
+ match (cond, String.length except) with
+ ("$DEFAULT_MODE", _) -> ()
+ | (_, 0) -> lprintf out_h "if (%s) { return %s; }\n" cond (print_mode_name (Xml.attrib m "name"))
+ | (_, _) -> lprintf out_h "if ((%s) && (%s)) { return %s; }\n" cond except (print_mode_name (Xml.attrib m "name"))
+ ) select;
+ ) modes;
+ lprintf out_h "return private_autopilot_mode;\n";
+ left ();
+ lprintf out_h "}\n"
+
+
+(** Function to test exceptions on modes
+ * The generated function returns the new mode if an exception is true
+ *)
+let print_test_exception = fun modes out_h ->
+ (** Test condition and deroute to given mode or last mode *)
+ let print_exception = fun ex ->
+ let name = Xml.attrib ex "deroute"
+ and cond = Xml.attrib ex "cond" in
+ match name with
+ "$LAST_MODE" -> lprintf out_h "if (%s) { return last_autopilot_mode; }\n" cond
+ | _ -> lprintf out_h "if (%s) { return %s; }\n" cond (print_mode_name name)
+ in
+
+ lprintf out_h "\nstatic inline uint8_t autopilot_core_mode_exceptions(uint8_t mode) {\n";
+ right ();
+ lprintf out_h "switch ( mode ) { \n";
+ right ();
+ List.iter (fun m -> (* Test exceptions for all modes *)
+ lprintf out_h "case %s :\n" (print_mode_name (Xml.attrib m "name"));
+ right ();
+ lprintf out_h "{\n";
+ right ();
+ let exceptions = get_mode_exceptions m in
+ List.iter (fun e ->
+ print_exception e
+ ) exceptions;
+ left ();
+ lprintf out_h "}\n";
+ lprintf out_h "break;\n";
+ left ()
+ ) modes;
+ left ();
+ lprintf out_h "}\n";
+ lprintf out_h "return mode;\n";
+ left ();
+ lprintf out_h "}\n"
+
+(** Function to test global exceptions
+ * The generated function returns the mode of the last true exception in the list
+ *)
+let print_global_exceptions = fun exceptions out_h ->
+ lprintf out_h "\nstatic inline uint8_t autopilot_core_global_exceptions(uint8_t mode) {\n";
+ right ();
+ List.iter (fun ex -> lprintf out_h "if (%s) { mode = %s; }\n" (Xml.attrib ex "cond") (print_mode_name (Xml.attrib ex "deroute")))
+ (Xml.children exceptions);
+ lprintf out_h "return mode;\n";
+ left ();
+ lprintf out_h "}\n"
+
+(** Set mode by calling start and stop functions if needed *)
+let print_set_mode = fun modes out_h ->
+
+ let print_case = fun mode f ->
+ lprintf out_h "case %s :\n" (print_mode_name (Xml.attrib mode "name"));
+ right ();
+ List.iter (fun x -> lprintf out_h "%s;\n" x) (Str.split (Str.regexp "|") f);
+ lprintf out_h "break;\n";
+ left ();
+ in
+ let print_switch = fun var modes t ->
+ lprintf out_h "switch ( %s ) { \n" var;
+ right ();
+ List.iter (fun m ->
+ try
+ let stop = Xml.attrib m t in
+ print_case m stop
+ with _ -> ()
+ ) modes;
+ left ();
+ lprintf out_h "}\n"
+ in
+
+ lprintf out_h "\nstatic inline void autopilot_core_set_mode(uint8_t new_mode) {\n\n";
+ right ();
+ lprintf out_h "if (new_mode == private_autopilot_mode) return;\n\n"; (* set mode if different from current mode *)
+ (* Print stop functions for each modes *)
+ print_switch "private_autopilot_mode" modes "stop";
+ lprintf out_h "\n";
+ (* Print start functions for each modes *)
+ print_switch "new_mode" modes "start";
+ lprintf out_h "\n";
+ lprintf out_h "last_autopilot_mode = private_autopilot_mode;\n";
+ lprintf out_h "private_autopilot_mode = new_mode;\n";
+ lprintf out_h "autopilot_mode = new_mode;\n";
+ left ();
+ lprintf out_h "}\n"
+
+
+(** Peridiodic function: calls control loops according to the ap_mode *)
+let print_ap_periodic = fun modes ctrl_block main_freq out_h ->
+
+ (** Print function *)
+ let print_call = fun call ->
+ try
+ let f = Xml.attrib call "fun" in
+ let cond = try String.concat "" ["if ("; (Xml.attrib call "cond"); ") { "; f; "; }\n"]
+ with _ -> String.concat "" [f; ";\n"] in
+ lprintf out_h "%s" cond
+ with _ -> ()
+ in
+ (** Print a control block *)
+ let print_ctrl = fun ctrl ->
+ List.iter (fun c ->
+ match (Xml.tag c) with
+ "call" -> print_call c
+ | "call_block" -> List.iter print_call (Xml.children (List.find (fun n -> (Xml.attrib c "name") = (Xml.attrib n "name")) ctrl_block))
+ | _ -> ()
+ ) (Xml.children ctrl)
+ in
+ (** Equivalent to the RunOnceEvery macro *)
+ let print_prescaler = fun pre ctrl ->
+ lprintf out_h "{ \n";
+ right ();
+ lprintf out_h "static uint16_t prescaler = 0;\n";
+ lprintf out_h "prescaler++;\n";
+ lprintf out_h "if (prescaler >= %d) {\n" pre;
+ right ();
+ lprintf out_h "prescaler = 0;\n";
+ print_ctrl ctrl;
+ left ();
+ lprintf out_h "}\n";
+ left ();
+ lprintf out_h "}\n"
+ in
+ let get_control = fun mode ->
+ List.filter (fun m -> (Xml.tag m) = "control") (Xml.children mode)
+ in
+
+ (** Start printing the main periodic task *)
+ lprintf out_h "\nstatic inline void autopilot_core_periodic_task(void) {\n\n";
+ right ();
+ lprintf out_h "uint8_t mode = autopilot_core_mode_select();\n"; (* get selected mode *)
+ lprintf out_h "mode = autopilot_core_mode_exceptions(mode);\n"; (* change mode according to exceptions *)
+ lprintf out_h "mode = autopilot_core_global_exceptions(mode);\n"; (* change mode according to global exceptions *)
+ lprintf out_h "autopilot_core_set_mode(mode);\n\n"; (* set new mode and call start/stop functions *)
+ lprintf out_h "switch ( private_autopilot_mode ) { \n";
+ right ();
+ List.iter (fun m -> (* Print control loops for each modes *)
+ lprintf out_h "case %s :\n" (print_mode_name (Xml.attrib m "name"));
+ right ();
+ lprintf out_h "{\n";
+ right ();
+ List.iter (fun c -> (* Look for control loops *)
+ let ctrl_freq = try int_of_string (Xml.attrib c "freq") with _ -> main_freq in
+ let prescaler = main_freq / ctrl_freq in
+ match prescaler with
+ 0 -> failwith "Autopilot Core Error: control freq higher than main freq"
+ | 1 -> print_ctrl c (* no prescaler if running at main_freq *)
+ | _ -> print_prescaler prescaler c
+ ) (get_control m);
+ left ();
+ lprintf out_h "}\n";
+ lprintf out_h "break;\n\n";
+ left ();
+ ) modes;
+ left ();
+ lprintf out_h "}\n";
+ left ();
+ lprintf out_h "}\n"
+
+(** Parse config file *)
+let parse_modes ap freq out_h =
+ let modes = get_ap_modes ap in
+ let ctrl_block = get_ap_control_block ap in
+ print_modes modes out_h;
+ fprintf out_h "\nEXTERN_AP uint8_t autopilot_mode;\n";
+ fprintf out_h "\n#ifdef AUTOPILOT_CORE_C\n";
+ fprintf out_h "\n#include \"modules.h\"\n";
+ fprintf out_h "uint8_t private_autopilot_mode;\n";
+ fprintf out_h "uint8_t last_autopilot_mode;\n\n";
+ print_ap_init modes out_h;
+ print_test_select modes out_h;
+ print_test_exception modes out_h;
+ print_global_exceptions (get_ap_exceptions ap) out_h;
+ print_set_mode modes out_h;
+ print_ap_periodic modes ctrl_block freq out_h;
+ fprintf out_h "\n#endif // AUTOPILOT_CORE_C\n"
+
+let h_name = "AUTOPILOT_CORE_H"
+
+(** Main generation function
+ * Usage: main_freq xml_file_input h_file_output
+ *)
+let gen_autopilot main_freq xml_file h_file =
+ let out_h = open_out h_file in
+ try
+ let ap_xml = start_and_begin_out xml_file h_name out_h in
+ let _ = try
+ let ap_name = Xml.attrib ap_xml "name" in
+ fprintf out_h "/*** %s ***/\n\n" ap_name;
+ with _ -> () in
+ fprintf out_h "#ifdef AUTOPILOT_CORE_C\n";
+ fprintf out_h "#define EXTERN_AP\n";
+ fprintf out_h "#else\n";
+ fprintf out_h "#define EXTERN_AP extern\n";
+ fprintf out_h "#endif\n";
+ parse_modes ap_xml main_freq out_h;
+ fprintf out_h "\n#endif // %s\n" h_name;
+ close_out out_h
+ with
+ Xml.Error e -> fprintf stderr "%s: XML error:%s\n" xml_file (Xml.error e); exit 1
+ | Dtd.Prove_error e -> fprintf stderr "%s: DTD error:%s\n%!" xml_file (Dtd.prove_error e); exit 1
+ | Dtd.Check_error e -> fprintf stderr "%s: DTD error:%s\n%!" xml_file (Dtd.check_error e); exit 1
+ | Dtd.Parse_error e -> fprintf stderr "%s: DTD error:%s\n%!" xml_file (Dtd.parse_error e); exit 1
+
+(* Main call *)
+let () =
+ if Array.length Sys.argv <> 3 then
+ failwith (Printf.sprintf "Usage: %s airframe_xml_file out_h_file" Sys.argv.(0));
+ let xml_file = Sys.argv.(1)
+ and h_file = Sys.argv.(2) in
+ try
+ let xml = Xml.parse_file xml_file in
+ let (autopilot, ap_freq) = Gen_common.get_autopilot_of_airframe xml in
+ gen_autopilot ap_freq autopilot h_file;
+ ()
+ with
+ Xml.Error e -> fprintf stderr "%s: XML error:%s\n" xml_file (Xml.error e); exit 1
+ | Dtd.Prove_error e -> fprintf stderr "%s: DTD error:%s\n%!" xml_file (Dtd.prove_error e); exit 1
+ | Dtd.Check_error e -> fprintf stderr "%s: DTD error:%s\n%!" xml_file (Dtd.check_error e); exit 1
+ | Dtd.Parse_error e -> fprintf stderr "%s: DTD error:%s\n%!" xml_file (Dtd.parse_error e); exit 1
+ | Not_found -> let out_h = open_out h_file in close_out out_h; exit 0
+
+
diff --git a/sw/tools/gen_common.ml b/sw/tools/gen_common.ml
index 2b8a6c0dc1..db9afa9ddb 100644
--- a/sw/tools/gen_common.ml
+++ b/sw/tools/gen_common.ml
@@ -30,8 +30,10 @@ let (//) = Filename.concat
let paparazzi_conf = Env.paparazzi_home // "conf"
let modules_dir = paparazzi_conf // "modules"
+let autopilot_dir = paparazzi_conf // "autopilot"
let default_module_targets = "ap|sim"
+let default_freq = 60
(** remove all duplicated elements of a list *)
let singletonize = fun l ->
@@ -65,7 +67,7 @@ let targets_of_field = fun field default ->
(** [get_modules_of_airframe xml]
* Returns a list of module configuration from airframe file *)
-let get_modules_of_airframe = fun xml ->
+let rec get_modules_of_airframe = fun xml ->
(* extract all "modules" sections *)
let section = List.filter (fun s -> compare (Xml.tag s) "modules" = 0) (Xml.children xml) in
(* Raise error if more than one modules section *)
@@ -73,12 +75,20 @@ let get_modules_of_airframe = fun xml ->
[modules] ->
(* if only one section, returns a list of configuration *)
let t_global = targets_of_field modules "" in
- List.map (fun m ->
- if compare (Xml.tag m) "load" <> 0 then Xml2h.xml_error "load";
+ let get_module = fun m t ->
let file = modules_dir // ExtXml.attrib m "name" in
- let targets = singletonize (t_global @ targets_of_field m "") in
+ let targets = singletonize (t @ targets_of_field m "") in
{ xml = ExtXml.parse_file file; file = file; param = Xml.children m; extra_targets = targets }
- ) (Xml.children modules)
+ in
+ List.flatten (List.map (fun m ->
+ if compare (Xml.tag m) "load" <> 0 then Xml2h.xml_error "load";
+ let airframe_module = [get_module m t_global] in
+ let ap_module = try
+ let ap_file = autopilot_dir // ExtXml.attrib m "autopilot" in
+ get_modules_of_airframe (ExtXml.parse_file ap_file)
+ with _ -> [] in
+ List.flatten [airframe_module @ ap_module]
+ ) (Xml.children modules))
| [] -> []
| _ -> failwith "Error: you have more than one 'modules' section in your airframe file"
@@ -126,3 +136,17 @@ let get_modules_dir = fun modules ->
let dir = List.map (fun m -> try Xml.attrib m.xml "dir" with _ -> ExtXml.attrib m.xml "name") modules in
singletonize (List.sort compare dir)
+(** [get_autopilot_of_airframe xml]
+ * Returns (autopilot xml, main freq) from airframe xml file *)
+let get_autopilot_of_airframe = fun xml ->
+ (* extract all "modules" sections *)
+ let section = List.filter (fun s -> compare (Xml.tag s) "modules" = 0) (Xml.children xml) in
+ (* Raise error if more than one modules section *)
+ match section with
+ [modules] ->
+ let main_freq = try int_of_string (Xml.attrib modules "main_freq") with _ -> default_freq in
+ let ap = try Xml.attrib modules "autopilot" with _ -> raise Not_found in
+ (autopilot_dir // ap, main_freq)
+ | [] -> raise Not_found
+ | _ -> failwith "Error: you have more than one 'modules' section in your airframe file"
+
diff --git a/sw/tools/gen_common.mli b/sw/tools/gen_common.mli
index 27734ff6a8..159b2970e1 100644
--- a/sw/tools/gen_common.mli
+++ b/sw/tools/gen_common.mli
@@ -35,6 +35,9 @@ val modules_dir : string
(* Default targets for modules *)
val default_module_targets : string
+(* Default AP freq *)
+val default_freq : int
+
(** remove all duplicated elements of a list *)
val singletonize : 'a list -> 'a list
@@ -63,3 +66,9 @@ val get_modules_name : Xml.xml -> string list
* Returns the list of modules directories *)
val get_modules_dir : module_conf list -> string list
+(** [get_autopilot_of_airframe xml]
+ * Returns (autopilot file, main freq) from airframe xml file
+ * Raise Not_found if no autopilot
+ * Fail if more than one *)
+val get_autopilot_of_airframe : Xml.xml -> (string * int)
+