mirror of
https://github.com/paparazzi/paparazzi.git
synced 2026-06-05 23:49:00 +08:00
833 lines
28 KiB
OCaml
833 lines
28 KiB
OCaml
(*
|
|
* Flight plan preprocessing (from XML to C)
|
|
*
|
|
* Copyright (C) 2004-2008 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 Latlong
|
|
|
|
module G2D = Geometry_2d
|
|
|
|
(* From mapFP.ml to avoid complex linking *)
|
|
let georef_of_xml = fun xml ->
|
|
let lat0 = Latlong.deg_of_string (ExtXml.attrib xml "lat0")
|
|
and lon0 = Latlong.deg_of_string (ExtXml.attrib xml "lon0") in
|
|
{ posn_lat = (Deg>>Rad)lat0; posn_long = (Deg>>Rad)lon0 }
|
|
|
|
let sof = string_of_float
|
|
let soi = string_of_int
|
|
|
|
let check_expressions = ref false
|
|
|
|
let cm = fun x -> 100. *. x
|
|
|
|
let parse = fun s ->
|
|
let e = Fp_proc.parse_expression s in
|
|
if !check_expressions then begin
|
|
let unexpected = fun kind x ->
|
|
fprintf stderr "Parsing error in '%s': unexpected %s: '%s' \n" s kind x;
|
|
exit 1 in
|
|
begin
|
|
try
|
|
Expr_syntax.check_expression e
|
|
with
|
|
Expr_syntax.Unknown_operator x -> unexpected "operator" x
|
|
| Expr_syntax.Unknown_ident x -> unexpected "ident" x
|
|
| Expr_syntax.Unknown_function x -> unexpected "function" x
|
|
end
|
|
end;
|
|
Expr_syntax.sprint e
|
|
|
|
let parsed_attrib = fun xml a ->
|
|
parse (ExtXml.attrib xml a)
|
|
|
|
let gen_label =
|
|
let x = ref 0 in
|
|
fun p -> incr x; sprintf "%s_%d" p !x
|
|
|
|
(** Formatting with a margin *)
|
|
let margin = ref 0
|
|
let step = 2
|
|
|
|
let right () = margin := !margin + step
|
|
let left () = margin := !margin - step
|
|
|
|
let lprintf = fun f ->
|
|
printf "%s" (String.make !margin ' ');
|
|
printf f
|
|
|
|
|
|
let float_attrib = fun xml a ->
|
|
try
|
|
float_of_string (Xml.attrib xml a)
|
|
with
|
|
Failure "float_of_string" ->
|
|
failwith (sprintf "Float expected in attribute '%s' from %s" a (Xml.to_string_fmt xml))
|
|
let name_of = fun wp -> ExtXml.attrib wp "name"
|
|
|
|
|
|
let ground_alt = ref 0.
|
|
let security_height = ref 0.
|
|
|
|
let check_altitude = fun a x ->
|
|
if a < !ground_alt +. !security_height then begin
|
|
fprintf stderr "\nWarning: low altitude (%.0f<%.0f+%.0f) in %s\n\n" a !ground_alt !security_height (Xml.to_string x)
|
|
end
|
|
|
|
|
|
(** Computes "x" and "y" attributes if "lat" and "lon" are available *)
|
|
let localize_waypoint = fun rel_utm_of_wgs84 waypoint ->
|
|
try
|
|
let (x, y) =
|
|
rel_utm_of_wgs84
|
|
(Latlong.make_geo_deg
|
|
(Latlong.deg_of_string (Xml.attrib waypoint "lat"))
|
|
(Latlong.deg_of_string (Xml.attrib waypoint "lon"))) in
|
|
let x = sprintf "%.2f" x and y = sprintf "%.2f" y in
|
|
ExtXml.subst_attrib "y" y (ExtXml.subst_attrib "x" x waypoint)
|
|
with
|
|
Xml.No_attribute "lat" | Xml.No_attribute "lon" ->
|
|
waypoint
|
|
|
|
|
|
let print_waypoint = fun default_alt waypoint ->
|
|
let (x, y) = (float_attrib waypoint "x", float_attrib waypoint "y")
|
|
and alt = try sof (float_attrib waypoint "height" +. !ground_alt) with _ -> default_alt in
|
|
let alt = try Xml.attrib waypoint "alt" with _ -> alt in
|
|
check_altitude (float_of_string alt) waypoint;
|
|
printf " {%.1f, %.1f, %s},\\\n" x y alt
|
|
|
|
let convert_angle = fun rad -> truncate (1e7 *. (Rad>>Deg)rad)
|
|
|
|
let print_waypoint_lla = fun utm0 default_alt waypoint ->
|
|
let x = float_attrib waypoint "x"
|
|
and y = float_attrib waypoint "y"
|
|
and alt = try Xml.attrib waypoint "alt" with _ -> default_alt in
|
|
let wgs84 = Latlong.of_utm Latlong.WGS84 (Latlong.utm_add utm0 (x, y)) in
|
|
printf " {%d, %d, %.0f}, /* 1e7deg, 1e7deg, cm (hmsl=%.2fm) */ \\\n" (convert_angle wgs84.posn_lat) (convert_angle wgs84.posn_long) (100. *. float_of_string alt) (Egm96.of_wgs84 wgs84)
|
|
|
|
|
|
let index_of_blocks = ref []
|
|
|
|
let get_index_block = fun x ->
|
|
try
|
|
List.assoc x !index_of_blocks
|
|
with
|
|
Not_found -> failwith (sprintf "Unknown block: '%s'" x)
|
|
|
|
let print_exception = fun x ->
|
|
let i = get_index_block (ExtXml.attrib x "deroute") in
|
|
let c = parsed_attrib x "cond" in
|
|
lprintf "if ((nav_block != %d) && %s) { GotoBlock(%d); return; }\n" i c i
|
|
|
|
let element = fun a b c -> Xml.Element (a, b, c)
|
|
let goto l = element "goto" ["name",l] []
|
|
let exit_block = element "exit_block" [] []
|
|
let home_block = Xml.parse_string "<block name=\"HOME\"><home/></block>"
|
|
|
|
let stage = ref 0
|
|
|
|
let output_label l = lprintf "Label(%s)\n" l
|
|
|
|
let get_index_waypoint = fun x l ->
|
|
try
|
|
string_of_int (List.assoc x l)
|
|
with
|
|
Not_found -> failwith (sprintf "Unknown waypoint: %s" x)
|
|
|
|
let pprz_throttle = fun s ->
|
|
begin
|
|
try
|
|
let g = float_of_string s in
|
|
if g < 0. || g > 1. then
|
|
failwith "throttle must be > 0 and < 1"
|
|
with
|
|
Failure "float_of_string" -> () (* No possible check on expression *)
|
|
end;
|
|
sprintf "9600*(%s)" s
|
|
|
|
|
|
(********************* Vertical control ********************************************)
|
|
let output_vmode = fun stage_xml wp last_wp ->
|
|
let pitch = try Xml.attrib stage_xml "pitch" with _ -> "0.0" in
|
|
if pitch = "auto"
|
|
then begin
|
|
lprintf "NavVerticalAutoPitchMode(%s);\n" (pprz_throttle (parsed_attrib stage_xml "throttle"))
|
|
end else begin
|
|
lprintf "NavVerticalAutoThrottleMode(RadOfDeg(%s));\n" (parse pitch);
|
|
end;
|
|
let vmode = try ExtXml.attrib stage_xml "vmode" with _ -> "alt" in
|
|
begin
|
|
match vmode with
|
|
"climb" ->
|
|
lprintf "NavVerticalClimbMode(%s);\n" (parsed_attrib stage_xml "climb")
|
|
| "alt" ->
|
|
let alt =
|
|
try
|
|
let a = parsed_attrib stage_xml "alt" in
|
|
begin
|
|
try
|
|
check_altitude (float_of_string a) stage_xml
|
|
with
|
|
(* Impossible to check the altitude on an expression: *)
|
|
Failure "float_of_string" -> ()
|
|
end;
|
|
a
|
|
with _ ->
|
|
try
|
|
let h = parsed_attrib stage_xml "height" in
|
|
begin
|
|
try
|
|
check_altitude ((float_of_string h) +. !ground_alt) stage_xml
|
|
with
|
|
(* Impossible to check the altitude on an expression: *)
|
|
Failure "float_of_string" -> ()
|
|
end;
|
|
sprintf "Height(%s)" h
|
|
with _ ->
|
|
if wp = ""
|
|
then failwith "alt or waypoint required in alt vmode"
|
|
else sprintf "WaypointAlt(%s)" wp in
|
|
lprintf "NavVerticalAltitudeMode(%s, 0.);\n" alt;
|
|
| "xyz" -> () (** Handled in Goto3D() *)
|
|
| "glide" ->
|
|
lprintf "NavGlide(%s, %s);\n" last_wp wp
|
|
| "throttle" ->
|
|
if (pitch = "auto") then
|
|
failwith "auto pich mode not compatible with vmode=throttle";
|
|
lprintf "NavVerticalThrottleMode(%s);\n" (pprz_throttle (parsed_attrib stage_xml "throttle"))
|
|
| x -> failwith (sprintf "Unknown vmode '%s'" x)
|
|
end;
|
|
vmode
|
|
|
|
(****************** Horizontal control *********************************************)
|
|
let output_hmode x wp last_wp =
|
|
try
|
|
let hmode = ExtXml.attrib x "hmode" in
|
|
begin
|
|
match hmode with
|
|
"route" ->
|
|
if last_wp = "last_wp" then
|
|
fprintf stderr "Warning: Deprecated use of 'route' using last waypoint in %s\n"(Xml.to_string x);
|
|
lprintf "NavSegment(%s, %s);\n" last_wp wp
|
|
| "direct" -> lprintf "NavGotoWaypoint(%s);\n" wp
|
|
| x -> failwith (sprintf "Unknown hmode '%s'" x)
|
|
end;
|
|
hmode
|
|
with
|
|
ExtXml.Error _ -> lprintf "NavGotoWaypoint(%s);\n" wp; "direct" (* Default behaviour *)
|
|
|
|
|
|
|
|
|
|
let rec index_stage = fun x ->
|
|
begin
|
|
match Xml.tag x with
|
|
"for" ->
|
|
incr stage; (* Init of i *)
|
|
incr stage;
|
|
let n = !stage in
|
|
let l = List.map index_stage (Xml.children x) in
|
|
incr stage; (* To count the loop stage *)
|
|
Xml.Element (Xml.tag x, Xml.attribs x@["no", soi n], l)
|
|
| "while" ->
|
|
incr stage;
|
|
let n = !stage in
|
|
let l = List.map index_stage (Xml.children x) in
|
|
incr stage; (* To count the loop stage *)
|
|
Xml.Element (Xml.tag x, Xml.attribs x@["no", soi n], l)
|
|
| "return" | "goto" | "deroute" | "exit_block" | "follow" | "call" | "home"
|
|
| "heading" | "attitude" | "go" | "stay" | "xyz" | "set" | "circle" ->
|
|
incr stage;
|
|
Xml.Element (Xml.tag x, Xml.attribs x@["no", soi !stage], Xml.children x)
|
|
| "survey_rectangle" | "eight" | "oval"->
|
|
incr stage; incr stage;
|
|
Xml.Element (Xml.tag x, Xml.attribs x@["no", soi !stage], Xml.children x)
|
|
| "exception" ->
|
|
x
|
|
| s -> failwith (sprintf "Unknown stage: %s\n" s)
|
|
end
|
|
|
|
|
|
let inside_function = fun name -> "Inside" ^ String.capitalize name
|
|
|
|
let rec print_stage = fun index_of_waypoints x ->
|
|
let stage () = incr stage;lprintf "Stage(%d)\n" !stage; right () in
|
|
begin
|
|
match String.lowercase (Xml.tag x) with
|
|
"return" ->
|
|
stage ();
|
|
lprintf "Return()\n";
|
|
lprintf "break\n";
|
|
| "goto" ->
|
|
stage ();
|
|
lprintf "Goto(%s)\n" (name_of x)
|
|
| "deroute" ->
|
|
stage ();
|
|
lprintf "GotoBlock(%d);\n" (get_index_block (ExtXml.attrib x "block"));
|
|
lprintf "break;\n"
|
|
| "exit_block" ->
|
|
lprintf "default:\n";
|
|
stage ();
|
|
lprintf "NextBlock();\n";
|
|
lprintf "break;\n"
|
|
| "while" ->
|
|
let w = gen_label "while" in
|
|
let e = gen_label "endwhile" in
|
|
output_label w;
|
|
stage ();
|
|
let c = try parsed_attrib x "cond" with _ -> "TRUE" in
|
|
lprintf "if (! (%s)) Goto(%s) else NextStageAndBreak();\n" c e;
|
|
List.iter (print_stage index_of_waypoints) (Xml.children x);
|
|
print_stage index_of_waypoints (goto w);
|
|
output_label e
|
|
| "for" ->
|
|
let f = gen_label "for" in
|
|
let e = gen_label "endfor" in
|
|
let v = Expr_syntax.c_var_of_ident (ExtXml.attrib x "var")
|
|
and from_ = parsed_attrib x "from"
|
|
and to_expr = parsed_attrib x "to" in
|
|
let to_var = v ^ "_to" in
|
|
lprintf "static int8_t %s;\n" v;
|
|
lprintf "static int8_t %s;\n" to_var;
|
|
|
|
(* init *)
|
|
stage ();
|
|
lprintf "%s = %s - 1;\n" v from_;
|
|
lprintf "%s = %s;\n" to_var to_expr;
|
|
left ();
|
|
|
|
output_label f;
|
|
stage ();
|
|
lprintf "if (++%s > %s) Goto(%s) else NextStageAndBreak();\n" v to_var e;
|
|
List.iter (print_stage index_of_waypoints) (Xml.children x);
|
|
print_stage index_of_waypoints (goto f);
|
|
output_label e
|
|
| "heading" ->
|
|
stage ();
|
|
let until = parsed_attrib x "until" in
|
|
lprintf "if (%s) NextStageAndBreak() else {\n" until;
|
|
right ();
|
|
lprintf "NavHeading(RadOfDeg(%s));\n" (parsed_attrib x "course");
|
|
ignore (output_vmode x "" "");
|
|
left (); lprintf "}\n";
|
|
lprintf "break;\n"
|
|
| "follow" ->
|
|
stage ();
|
|
let id = ExtXml.attrib x "ac_id"
|
|
and d = ExtXml.attrib x "distance"
|
|
and h = ExtXml.attrib x "height" in
|
|
lprintf "NavFollow(%s, %s, %s);\n" id d h;
|
|
lprintf "break;\n"
|
|
| "attitude" ->
|
|
stage ();
|
|
begin
|
|
try
|
|
let until = parsed_attrib x "until" in
|
|
lprintf "if (%s) NextStageAndBreak() else {\n" until;
|
|
with ExtXml.Error _ ->
|
|
lprintf "{\n"
|
|
end;
|
|
right ();
|
|
lprintf "NavAttitude(RadOfDeg(%s));\n" (parsed_attrib x "roll");
|
|
ignore (output_vmode x "" "");
|
|
left (); lprintf "}\n";
|
|
lprintf "break;\n"
|
|
| "go" ->
|
|
stage ();
|
|
let wp =
|
|
try
|
|
get_index_waypoint (ExtXml.attrib x "wp") index_of_waypoints
|
|
with
|
|
ExtXml.Error _ ->
|
|
lprintf "waypoints[0].x = %s;\n" (parsed_attrib x "x");
|
|
lprintf "waypoints[0].y = %s;\n" (parsed_attrib x "y");
|
|
"0"
|
|
in
|
|
let at = try ExtXml.attrib x "approaching_time" with _ -> "CARROT" in
|
|
let last_wp =
|
|
try
|
|
get_index_waypoint (ExtXml.attrib x "from") index_of_waypoints
|
|
with ExtXml.Error _ -> "last_wp" in
|
|
if last_wp = "last_wp" then
|
|
lprintf "if (NavApproaching(%s,%s)) NextStageAndBreakFrom(%s) else {\n" wp at wp
|
|
else
|
|
lprintf "if (NavApproachingFrom(%s,%s,%s)) NextStageAndBreakFrom(%s) else {\n" wp last_wp at wp;
|
|
right ();
|
|
let hmode = output_hmode x wp last_wp in
|
|
let vmode = output_vmode x wp last_wp in
|
|
if vmode = "glide" && hmode <> "route" then
|
|
failwith "glide vmode requires route hmode";
|
|
left (); lprintf "}\n";
|
|
begin
|
|
try
|
|
let c = parsed_attrib x "until" in
|
|
lprintf "if (%s) NextStageAndBreak();\n" c
|
|
with
|
|
ExtXml.Error _ -> ()
|
|
end;
|
|
lprintf "break;\n"
|
|
| "stay" ->
|
|
stage ();
|
|
begin
|
|
try
|
|
let wp = get_index_waypoint (ExtXml.attrib x "wp") index_of_waypoints in
|
|
ignore (output_hmode x wp "");
|
|
ignore (output_vmode x wp "");
|
|
with
|
|
Xml2h.Error _ ->
|
|
lprintf "NavGotoXY(last_x, last_y);\n";
|
|
ignore(output_vmode x "" "")
|
|
end;
|
|
begin
|
|
try
|
|
let c = parsed_attrib x "until" in
|
|
lprintf "if (%s) NextStageAndBreak();\n" c
|
|
with
|
|
ExtXml.Error _ -> ()
|
|
end;
|
|
lprintf "break;\n"
|
|
| "xyz" ->
|
|
stage ();
|
|
let r = try parsed_attrib x "radius" with _ -> "100" in
|
|
lprintf "Goto3D(%s)\n" r;
|
|
let x = ExtXml.subst_attrib "vmode" "xyz" x in
|
|
ignore (output_vmode x "" ""); (** To handle "pitch" *)
|
|
lprintf "break;\n"
|
|
| "home" ->
|
|
stage ();
|
|
lprintf "nav_home();\n";
|
|
lprintf "break;\n"
|
|
| "circle" ->
|
|
stage ();
|
|
let wp = get_index_waypoint (ExtXml.attrib x "wp") index_of_waypoints in
|
|
let r = parsed_attrib x "radius" in
|
|
let _vmode = output_vmode x wp "" in
|
|
lprintf "NavCircleWaypoint(%s, %s);\n" wp r;
|
|
begin
|
|
try
|
|
let c = parsed_attrib x "until" in
|
|
lprintf "if (%s) NextStageAndBreak();\n" c
|
|
with
|
|
ExtXml.Error _ -> ()
|
|
end;
|
|
lprintf "break;\n"
|
|
| "eight" ->
|
|
stage ();
|
|
lprintf "nav_eight_init();\n";
|
|
lprintf "NextStageAndBreak();\n";
|
|
left ();
|
|
stage ();
|
|
let center = get_index_waypoint (ExtXml.attrib x "center") index_of_waypoints
|
|
and turn_about = get_index_waypoint (ExtXml.attrib x "turn_around") index_of_waypoints in
|
|
let r = parsed_attrib x "radius" in
|
|
let _vmode = output_vmode x center "" in
|
|
lprintf "Eight(%s, %s, %s);\n" center turn_about r;
|
|
begin
|
|
try
|
|
let c = parsed_attrib x "until" in
|
|
lprintf "if (%s) NextStageAndBreak();\n" c
|
|
with
|
|
ExtXml.Error _ -> ()
|
|
end;
|
|
lprintf "break;\n"
|
|
| "oval" ->
|
|
stage ();
|
|
lprintf "nav_oval_init();\n";
|
|
lprintf "NextStageAndBreak();\n";
|
|
left ();
|
|
stage ();
|
|
let p1 = get_index_waypoint (ExtXml.attrib x "p1") index_of_waypoints
|
|
and p2 = get_index_waypoint (ExtXml.attrib x "p2") index_of_waypoints in
|
|
let r = parsed_attrib x "radius" in
|
|
let _vmode = output_vmode x p1 "" in
|
|
lprintf "Oval(%s, %s, %s);\n" p1 p2 r;
|
|
begin
|
|
try
|
|
let c = parsed_attrib x "until" in
|
|
lprintf "if (%s) NextStageAndBreak();\n" c
|
|
with
|
|
ExtXml.Error _ -> ()
|
|
end;
|
|
lprintf "break;\n"
|
|
| "set" ->
|
|
stage ();
|
|
let var = ExtXml.attrib x "var"
|
|
and value = parsed_attrib x "value" in
|
|
lprintf "%s = %s;\n" var value;
|
|
lprintf "NextStageAndBreak();\n";
|
|
lprintf "break;\n"
|
|
| "call" ->
|
|
stage ();
|
|
let statement = ExtXml.attrib x "fun" in
|
|
lprintf "if (! (%s))\n" statement;
|
|
lprintf " NextStageAndBreak();\n";
|
|
lprintf "break;\n"
|
|
| "survey_rectangle" ->
|
|
let grid = parsed_attrib x "grid"
|
|
and wp1 = get_index_waypoint (ExtXml.attrib x "wp1") index_of_waypoints
|
|
and wp2 = get_index_waypoint (ExtXml.attrib x "wp2") index_of_waypoints
|
|
and orientation = ExtXml.attrib_or_default x "orientation" "NS" in
|
|
stage ();
|
|
if orientation <> "NS" && orientation <> "WE" then
|
|
failwith (sprintf "Unknown survey orientation (NS or WE): %s" orientation);
|
|
lprintf "NavSurveyRectangleInit(%s, %s, %s, %s);\n" wp1 wp2 grid orientation;
|
|
lprintf "NextStageAndBreak();\n";
|
|
left ();
|
|
stage ();
|
|
lprintf "NavSurveyRectangle(%s, %s);\n" wp1 wp2;
|
|
lprintf "break;\n"
|
|
| _s -> failwith "Unreachable"
|
|
end;
|
|
left ()
|
|
|
|
|
|
let indexed_stages = fun blocks ->
|
|
let lstages = ref [] in
|
|
List.iter
|
|
(fun b ->
|
|
let block_name = name_of b
|
|
and block_no = ExtXml.attrib b "no" in
|
|
let rec f = fun stage ->
|
|
try
|
|
let stage_no = Xml.attrib stage "no" in
|
|
lstages :=
|
|
Xml.Element ("stage", [ "block", block_no;
|
|
"block_name", block_name;
|
|
"stage", stage_no], [stage]):: !lstages;
|
|
if (ExtXml.tag_is stage "for" || ExtXml.tag_is stage "while") then
|
|
List.iter f (Xml.children stage)
|
|
with Xml.No_attribute "no" ->
|
|
assert (ExtXml.tag_is stage "exception")
|
|
in
|
|
List.iter f (Xml.children b))
|
|
blocks;
|
|
!lstages
|
|
|
|
|
|
|
|
|
|
let index_blocks = fun xml ->
|
|
let block = ref (-1) in
|
|
let indexed_blocks =
|
|
List.map
|
|
(fun b ->
|
|
incr block;
|
|
let name = name_of b in
|
|
if List.mem_assoc name !index_of_blocks then
|
|
failwith (Printf.sprintf "Error in flight plan: Block '%s' defined twice" name);
|
|
index_of_blocks := (name, !block) :: !index_of_blocks;
|
|
stage := -1;
|
|
let indexed_stages = List.map index_stage (Xml.children b) in
|
|
Xml.Element (Xml.tag b, Xml.attribs b@["no", soi !block], indexed_stages))
|
|
(Xml.children xml) in
|
|
Xml.Element (Xml.tag xml, Xml.attribs xml, indexed_blocks)
|
|
|
|
|
|
|
|
let print_block = fun index_of_waypoints (b:Xml.xml) block_num ->
|
|
let n = name_of b in
|
|
(* Block entry *)
|
|
lprintf "Block(%d) // %s\n" block_num n;
|
|
lprintf "%s; // pre_call\n" (ExtXml.attrib_or_default b "pre_call" "");
|
|
|
|
let excpts, stages =
|
|
List.partition (fun x -> Xml.tag x = "exception") (Xml.children b) in
|
|
|
|
List.iter print_exception excpts;
|
|
|
|
lprintf "switch(nav_stage) {\n";
|
|
right ();
|
|
stage := (-1);
|
|
List.iter (print_stage index_of_waypoints) stages;
|
|
|
|
print_stage index_of_waypoints exit_block;
|
|
|
|
left ();
|
|
lprintf "}\n";
|
|
|
|
(* Block exit *)
|
|
lprintf "%s; // post_call\n" (ExtXml.attrib_or_default b "post_call" "");
|
|
lprintf "break;\n\n"
|
|
|
|
|
|
|
|
let print_blocks = fun index_of_waypoints bs ->
|
|
let block = ref (-1) in
|
|
List.iter (fun b -> incr block; print_block index_of_waypoints b !block) bs
|
|
|
|
let c_suffix =
|
|
let r = Str.regexp "^[a-zA-Z0-9_]*$" in
|
|
fun s -> Str.string_match r s 0
|
|
|
|
let define_waypoints_indices = fun wpts ->
|
|
let i = ref 0 in
|
|
List.iter (fun w ->
|
|
let n = name_of w in
|
|
if c_suffix n then
|
|
Xml2h.define (sprintf "WP_%s" n) (string_of_int !i);
|
|
incr i)
|
|
wpts
|
|
|
|
let home = fun waypoints ->
|
|
let rec loop i = function
|
|
[] -> failwith "Waypoint 'HOME' required"
|
|
| w::ws ->
|
|
if name_of w = "HOME" then
|
|
(float_attrib w "x", float_attrib w "y")
|
|
else
|
|
loop (i+1) ws in
|
|
loop 0 waypoints
|
|
|
|
|
|
let check_distance = fun (hx, hy) max_d wp ->
|
|
let x = float_attrib wp "x"
|
|
and y = float_attrib wp "y" in
|
|
let d = sqrt ((x-.hx)**2. +. (y-.hy)**2.) in
|
|
if d > max_d then
|
|
fprintf stderr "\nWarning: Waypoint '%s' too far from HOME (%.0f>%.0f)\n\n" (name_of wp) d max_d
|
|
|
|
|
|
(* Check coherence between global ref and waypoints ref *)
|
|
(* Returns a patched xml with utm_x0 and utm_y0 set *)
|
|
let check_geo_ref = fun wgs84 xml ->
|
|
let get_float = fun x -> float_attrib xml x in
|
|
let utm0 = utm_of WGS84 wgs84 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
|
|
prerr_endline "Warning: You are close (less than twice the max distance) to an UTM zone border ! The navigation will not work unless the GPS_USE_LATLONG flag is set and the GPS receiver configured to send the POSLLH message." in
|
|
check_zone { utm0 with utm_x = utm0.utm_x +. 2.*.max_d };
|
|
check_zone { utm0 with utm_x = utm0.utm_x -. 2.*.max_d };
|
|
|
|
let wpts = ExtXml.child xml "waypoints" in
|
|
let wpts = ExtXml.subst_attrib "utm_x0" (sof utm0.utm_x) wpts in
|
|
let wpts = ExtXml.subst_attrib "utm_y0" (sof utm0.utm_y) wpts in
|
|
let x = ExtXml.subst_child "waypoints" wpts xml in
|
|
x
|
|
|
|
let dummy_waypoint =
|
|
Xml.Element ("waypoint",
|
|
["name", "dummy";
|
|
"x", "42.";
|
|
"y", "42." ],
|
|
[])
|
|
|
|
|
|
|
|
let print_inside_polygon = fun pts ->
|
|
let layers = Geometry_2d.slice_polygon (Array.of_list pts) in
|
|
let rec f = fun i j ->
|
|
if i = j then
|
|
let {G2D.top=yl; left_side=(xg, ag); right_side=(xd, ad)} = layers.(i) in
|
|
if xg > xd then begin
|
|
lprintf "return FALSE;\n"
|
|
end else begin
|
|
if ad <> 0. || ag <> 0. then
|
|
lprintf "float dy = _y - %.1f;\n" yl;
|
|
let dy_times = fun f -> if f = 0. then "" else sprintf "+dy*%f" f in
|
|
lprintf "return (%.1f%s<= _x && _x <= %.1f%s);\n" xg (dy_times ag) xd (dy_times ad)
|
|
end
|
|
else
|
|
let ij2 = (i+j) / 2 in
|
|
let yl = layers.(ij2).G2D.top in
|
|
lprintf "if (_y <= %.1f) {\n" yl;
|
|
right (); f i ij2; left ();
|
|
lprintf "} else {\n";
|
|
right (); f (ij2+1) j; left ();
|
|
lprintf "}\n"
|
|
in
|
|
f 0 (Array.length layers - 1);;
|
|
|
|
|
|
|
|
let print_inside_sector = fun (s, pts) ->
|
|
lprintf "static inline bool_t %s(float _x, float _y) { \\\n" (inside_function s);
|
|
right ();
|
|
print_inside_polygon pts;
|
|
left ();
|
|
lprintf "}\n"
|
|
|
|
|
|
let parse_wpt_sector = fun waypoints xml ->
|
|
let sector_name = ExtXml.attrib xml "name" in
|
|
let p2D_of = fun x ->
|
|
let name = name_of x in
|
|
try
|
|
let wp = List.find (fun wp -> name_of wp = name) waypoints in
|
|
let x = float_attrib wp "x"
|
|
and y = float_attrib wp "y" in
|
|
{G2D.x2D = x; G2D.y2D = y }
|
|
with
|
|
Not_found -> failwith (sprintf "Error: corner '%s' of sector '%s' not found" name sector_name)
|
|
in
|
|
(sector_name, List.map p2D_of (Xml.children xml))
|
|
|
|
|
|
(************************** MAIN ******************************************)
|
|
let () =
|
|
let xml_file = ref "fligh_plan.xml"
|
|
and dump = ref false in
|
|
Arg.parse [ ("-check", Arg.Set check_expressions, "Enable expression checking");
|
|
("-dump", Arg.Set dump, "Dump compile result") ]
|
|
(fun f -> xml_file := f)
|
|
"Usage:";
|
|
if !xml_file = "" then
|
|
failwith (sprintf "Usage: %s <xml-flight-plan-file>" Sys.argv.(0));
|
|
try
|
|
let xml = ExtXml.parse_file !xml_file in
|
|
|
|
let wgs84 = georef_of_xml xml in
|
|
let xml = check_geo_ref wgs84 xml in
|
|
|
|
let dir = Filename.dirname !xml_file in
|
|
let xml = Fp_proc.process_includes dir xml in
|
|
let xml = Fp_proc.process_paths xml in
|
|
let xml = Fp_proc.process_relative_waypoints xml in
|
|
|
|
(* Add a safety last HOME block *)
|
|
let blocks = Xml.children (ExtXml.child xml "blocks") @ [home_block] in
|
|
|
|
let xml = ExtXml.subst_child "blocks" (index_blocks (element "blocks" [] blocks)) xml in
|
|
let waypoints = Xml.children (ExtXml.child xml "waypoints")
|
|
and blocks = Xml.children (ExtXml.child xml "blocks")
|
|
and global_exceptions = try Xml.children (ExtXml.child xml "exceptions") with _ -> [] in
|
|
|
|
let utm0 = utm_of WGS84 wgs84 in
|
|
let rel_utm_of_wgs84 = fun wgs84 ->
|
|
let utm = utm_of WGS84 wgs84 in
|
|
(utm.utm_x -. utm0.utm_x, utm.utm_y -. utm0.utm_y) in
|
|
let waypoints =
|
|
List.map (localize_waypoint rel_utm_of_wgs84) waypoints in
|
|
|
|
let xml = ExtXml.subst_child "waypoints" (element "waypoints" [] waypoints) xml in
|
|
|
|
if !dump then
|
|
let xml_stages = Xml.Element ("stages", [], indexed_stages blocks) in
|
|
let dump_xml = Xml.Element ("dump", [], [xml; xml_stages]) in
|
|
printf "%s\n" (ExtXml.to_string_fmt dump_xml)
|
|
else begin
|
|
let h_name = "FLIGHT_PLAN_H" in
|
|
printf "/* This file has been generated from %s */\n" !xml_file;
|
|
printf "/* Please DO NOT EDIT */\n\n";
|
|
|
|
printf "#ifndef %s\n" h_name;
|
|
Xml2h.define h_name "";
|
|
printf "\n";
|
|
|
|
printf "#include \"std.h\"\n";
|
|
printf "#include \"generated/modules.h\"\n";
|
|
|
|
begin
|
|
try
|
|
let header = ExtXml.child (ExtXml.child xml "header") "0" in
|
|
printf "%s\n" (Xml.pcdata header)
|
|
with _ -> ()
|
|
end;
|
|
|
|
let name = ExtXml.attrib xml "name" in
|
|
Xml2h.warning ("FLIGHT PLAN: "^name);
|
|
Xml2h.define_string "FLIGHT_PLAN_NAME" name;
|
|
|
|
let get_float = fun x -> float_attrib xml x in
|
|
let qfu = try get_float "qfu" with Xml.No_attribute "qfu" -> 0.
|
|
and mdfh = get_float "max_dist_from_home"
|
|
and alt = ExtXml.attrib xml "alt" in
|
|
security_height := get_float "security_height";
|
|
ground_alt := get_float "ground_alt";
|
|
let home_mode_height = try
|
|
max (get_float "home_mode_height") !security_height
|
|
with _ -> !security_height in
|
|
|
|
check_altitude (float_of_string alt) xml;
|
|
|
|
Xml2h.define "NAV_UTM_EAST0" (sprintf "%.0f" utm0.utm_x);
|
|
Xml2h.define "NAV_UTM_NORTH0" (sprintf "%.0f" utm0.utm_y);
|
|
Xml2h.define "NAV_UTM_ZONE0" (sprintf "%d" utm0.utm_zone);
|
|
Xml2h.define "NAV_LAT0" (sprintf "%d /* 1e7deg */" (convert_angle wgs84.posn_lat));
|
|
Xml2h.define "NAV_LON0" (sprintf "%d /* 1e7deg */" (convert_angle wgs84.posn_long));
|
|
Xml2h.define "NAV_ALT0" (sprintf "%.0f /* mm above msl */" (1000. *. !ground_alt));
|
|
Xml2h.define "NAV_MSL0" (sprintf "%.0f /* mm, EGM96 geoid-height (msl) over ellipsoid */" (1000. *. Egm96.of_wgs84 wgs84));
|
|
|
|
Xml2h.define "QFU" (sprintf "%.1f" qfu);
|
|
|
|
let waypoints = dummy_waypoint :: waypoints in
|
|
|
|
let (hx, hy) = home waypoints in
|
|
List.iter (check_distance (hx, hy) mdfh) waypoints;
|
|
define_waypoints_indices waypoints;
|
|
|
|
Xml2h.define "WAYPOINTS" "{ \\";
|
|
List.iter (print_waypoint alt) waypoints;
|
|
lprintf "};\n";
|
|
Xml2h.define "WAYPOINTS_LLA" "{ \\";
|
|
List.iter (print_waypoint_lla utm0 alt) waypoints;
|
|
lprintf "};\n";
|
|
Xml2h.define "NB_WAYPOINT" (string_of_int (List.length waypoints));
|
|
|
|
Xml2h.define "NB_BLOCK" (string_of_int (List.length blocks));
|
|
|
|
Xml2h.define "GROUND_ALT" (sof !ground_alt);
|
|
Xml2h.define "GROUND_ALT_CM" (sprintf "%.0f" (100.*. !ground_alt));
|
|
Xml2h.define "SECURITY_HEIGHT" (sof !security_height);
|
|
Xml2h.define "SECURITY_ALT" (sof (!security_height +. !ground_alt));
|
|
Xml2h.define "HOME_MODE_HEIGHT" (sof home_mode_height);
|
|
Xml2h.define "MAX_DIST_FROM_HOME" (sof mdfh);
|
|
|
|
let index_of_waypoints =
|
|
let i = ref (-1) in
|
|
List.map (fun w -> incr i; (name_of w, !i)) waypoints in
|
|
|
|
let sectors_element = try ExtXml.child xml "sectors" with Not_found -> Xml.Element ("", [], []) in
|
|
let sectors = List.filter (fun x -> String.lowercase (Xml.tag x) = "sector") (Xml.children sectors_element) in
|
|
let sectors = List.map (parse_wpt_sector waypoints) sectors in
|
|
List.iter print_inside_sector sectors;
|
|
|
|
lprintf "#ifdef NAV_C\n";
|
|
lprintf "\nstatic inline void auto_nav(void) {\n";
|
|
right ();
|
|
List.iter print_exception global_exceptions;
|
|
lprintf "switch (nav_block) {\n";
|
|
right ();
|
|
print_blocks index_of_waypoints blocks;
|
|
lprintf "default: break;\n";
|
|
left ();
|
|
lprintf "}\n";
|
|
left ();
|
|
lprintf "}\n";
|
|
lprintf "#endif // NAV_C\n";
|
|
|
|
begin
|
|
try
|
|
let airspace = Xml.attrib xml "airspace" in
|
|
lprintf "#define InAirspace(_x, _y) %s(_x, _y)\n" (inside_function airspace)
|
|
with
|
|
_ -> ()
|
|
end;
|
|
|
|
Xml2h.finish h_name
|
|
end
|
|
with
|
|
Failure x ->
|
|
fprintf stderr "%s: %s\n" !xml_file x; exit 1
|