export CVS

This commit is contained in:
Pascal Brisset
2008-12-05 16:18:31 +00:00
parent 0df141b619
commit 1650b8fd79
4 changed files with 472 additions and 16 deletions
+32 -6
View File
@@ -25,7 +25,7 @@ Q=@
OCAMLC = ocamlc
OCAMLOPT = ocamlopt
INCLUDES= -I +xml-light
INCLUDES= -I +xml-light -I +lablgtk2 -I ../lib/ocaml
all: play plotter plot
@@ -33,13 +33,28 @@ play : log_file.ml play.ml
@echo OL $@
$(Q)$(OCAMLC) $(INCLUDES) -custom -o $@ unix.cma str.cma xml-light.cma glibivy-ocaml.cma -I +lablgtk2 -I ../lib/ocaml lablgtk.cma lib-pprz.cma gtkInit.cmo $^
plotter : plotter.ml
plotter : plotter.cmo
@echo OL $@
$(Q)$(OCAMLC) $(INCLUDES) -custom -o $@ unix.cma str.cma xml-light.cma glibivy-ocaml.cma -I +lablgtk2 -I ../lib/ocaml lablgtk.cma lib-pprz.cma gtkInit.cmo $^
$(Q)$(OCAMLC) $(INCLUDES) -custom -o $@ unix.cma str.cma xml-light.cma glibivy-ocaml.cma lablgtk.cma lib-pprz.cma gtkInit.cmo $^
plot : log_file.ml plot.ml
plot : log_file.cmx gtk_export.cmx export.cmx plot.cmx
@echo OL $@
$(Q)$(OCAMLOPT) $(INCLUDES) -o $@ unix.cmxa str.cmxa xml-light.cmxa glibivy-ocaml.cmxa -I +lablgtk2 -I ../lib/ocaml lablgtk.cmxa lib-pprz.cmxa gtkInit.cmx $^
$(Q)$(OCAMLOPT) $(INCLUDES) -o $@ unix.cmxa str.cmxa xml-light.cmxa glibivy-ocaml.cmxa lablgtk.cmxa lib-pprz.cmxa lablglade.cmxa gtkInit.cmx $^
%.cmo: %.ml
@echo OC $<
$(Q)$(OCAMLC) $(OCAMLCFLAGS) $(INCLUDES) -c $<
%.cmi: %.mli
@echo OCI $<
$(Q)$(OCAMLC) $(OCAMLCFLAGS) $(INCLUDES) -c $<
%.cmx: %.ml
@echo OOC $<
$(Q)$(OCAMLOPT) $(OCAMLCFLAGS) $(INCLUDES) -c $<
gtk_export.ml : export.glade
lablgladecc2 -root export -hide-default $< | grep -B 1000000 " end" > $@
@@ -121,6 +136,17 @@ tmclient: tmclient.c
ffjoystick: ffjoystick.c
gcc -g -O2 -Wall `pkg-config glib-2.0 --cflags` -o $@ $^ `pkg-config glib-2.0 --libs` `pcre-config --libs` -lglibivy -lm
ctrlstick: ctrlstick.c
gcc -g -O2 -Wall `pkg-config glib-2.0 --cflags` -o $@ $^ `pkg-config glib-2.0 --libs` `pcre-config --libs` -lglibivy
#
# Dependencies
#
.depend: Makefile
ocamldep -I ../lib/ocaml *.ml* > .depend
ifneq ($(MAKECMDGOALS),clean)
-include .depend
endif
+225
View File
@@ -0,0 +1,225 @@
<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
<glade-interface>
<widget class="GtkWindow" id="export">
<property name="visible">True</property>
<property name="title" translatable="yes">Save CSV</property>
<property name="type">GTK_WINDOW_TOPLEVEL</property>
<property name="window_position">GTK_WIN_POS_NONE</property>
<property name="modal">True</property>
<property name="resizable">True</property>
<property name="destroy_with_parent">False</property>
<property name="decorated">True</property>
<property name="skip_taskbar_hint">False</property>
<property name="skip_pager_hint">False</property>
<property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
<property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
<property name="focus_on_map">True</property>
<property name="urgency_hint">False</property>
<child>
<widget class="GtkVBox" id="vbox4">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">0</property>
<child>
<widget class="GtkScrolledWindow" id="scrolledwindow1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
<property name="vscrollbar_policy">GTK_POLICY_ALWAYS</property>
<property name="shadow_type">GTK_SHADOW_IN</property>
<property name="window_placement">GTK_CORNER_TOP_LEFT</property>
<child>
<widget class="GtkTreeView" id="treeview_messages">
<property name="height_request">191</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="headers_visible">True</property>
<property name="rules_hint">False</property>
<property name="reorderable">False</property>
<property name="enable_search">True</property>
<property name="fixed_height_mode">False</property>
<property name="hover_selection">False</property>
<property name="hover_expand">False</property>
</widget>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
<child>
<widget class="GtkHBox" id="hbox8">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">0</property>
<child>
<widget class="GtkLabel" id="label38">
<property name="visible">True</property>
<property name="label" translatable="yes">Timestamp:</property>
<property name="use_underline">False</property>
<property name="use_markup">False</property>
<property name="justify">GTK_JUSTIFY_LEFT</property>
<property name="wrap">False</property>
<property name="selectable">False</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
<property name="width_chars">-1</property>
<property name="single_line_mode">False</property>
<property name="angle">0</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkEventBox" id="box_choose_period">
<property name="visible">True</property>
<property name="visible_window">True</property>
<property name="above_child">False</property>
<child>
<placeholder/>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="entry_period">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="editable">True</property>
<property name="visibility">True</property>
<property name="max_length">0</property>
<property name="text" translatable="yes">0.25</property>
<property name="has_frame">True</property>
<property name="invisible_char">●</property>
<property name="activates_default">False</property>
<property name="width_chars">4</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label37">
<property name="visible">True</property>
<property name="label" translatable="yes">s</property>
<property name="use_underline">False</property>
<property name="use_markup">False</property>
<property name="justify">GTK_JUSTIFY_LEFT</property>
<property name="wrap">False</property>
<property name="selectable">False</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
<property name="width_chars">-1</property>
<property name="single_line_mode">False</property>
<property name="angle">0</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkEventBox" id="box_choose_interpol">
<property name="visible">True</property>
<property name="visible_window">True</property>
<property name="above_child">False</property>
<child>
<placeholder/>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
<child>
<widget class="GtkHBox" id="hbox6">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">0</property>
<child>
<widget class="GtkButton" id="button_cancel">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label">gtk-cancel</property>
<property name="use_stock">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkButton" id="button_save">
<property name="visible">True</property>
<property name="tooltip" translatable="yes">Save the checked aircraft values in the airframe file</property>
<property name="can_focus">True</property>
<property name="label">gtk-save-as</property>
<property name="use_stock">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">False</property>
</packing>
</child>
</widget>
<packing>
<property name="padding">2</property>
<property name="expand">False</property>
<property name="fill">True</property>
</packing>
</child>
</widget>
</child>
</widget>
</glade-interface>
+198
View File
@@ -0,0 +1,198 @@
(*
* $Id$
*
* GUI to export some values of a log
*
* Copyright (C) 2008, Cyril Allignol, Pascal Brisset
*
* 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 class_name="telemetry"
let cols = new GTree.column_list
let col_message = cols#add Gobject.Data.string
let col_field = cols#add Gobject.Data.string
let col_to_export = cols#add Gobject.Data.boolean
let col_visible = cols#add Gobject.Data.boolean
(** Toggling a tree element *)
let item_toggled ~(model : GTree.tree_store) ~column path =
let row = model#get_iter path in
let b = model#get ~row ~column in
model#set ~row ~column (not b)
let display_columns = fun treeview model ->
let renderer = GTree.cell_renderer_text [`XALIGN 0.] in
let vc = GTree.view_column ~title:"Message" ~renderer:(renderer, ["text", col_message]) () in
ignore (treeview#append_column vc);
let renderer = GTree.cell_renderer_text [`XALIGN 0.] in
let vc = GTree.view_column ~title:"Field" ~renderer:(renderer, ["text", col_field]) () in
ignore (treeview#append_column vc);
let renderer = GTree.cell_renderer_toggle [`XALIGN 0.] in
let vc = GTree.view_column ~title:"To export" ~renderer:(renderer, ["active", col_to_export; "visible", col_visible]) () in
vc#set_clickable true;
ignore (renderer#connect#toggled ~callback:(item_toggled ~model ~column:col_to_export));
ignore (treeview#append_column vc)
let fill_data = fun (model:GTree.tree_store) messages_xml ->
List.iter (fun msg ->
let row = model#append () in
model#set ~row ~column:col_message (ExtXml.attrib msg "name");
List.iter (fun field ->
let row = model#append ~parent:row () in
model#set ~row ~column:col_visible true;
model#set ~row ~column:col_field (ExtXml.attrib field "name"))
(Xml.children msg))
(Xml.children messages_xml)
type timestamp =
Msg of string
| Period of float (* in s *)
let export_values = fun (model:GTree.tree_store) data timestamp filename ->
let fields_to_export = ref [] in
model#foreach (fun _path row ->
if model#get ~row ~column:col_to_export then begin
let field = model#get ~row ~column:col_field
and parent = match model#iter_parent row with Some p -> p | None -> failwith "export_value: no parent ???" in
let msg = model#get ~row:parent ~column:col_message in
fields_to_export := (msg, field) :: !fields_to_export
end;
false);
let f = open_out filename in
(* Print the header *)
fprintf f "Time";
List.iter (fun (m,field) -> fprintf f ";%s:%s" m field) !fields_to_export;
fprintf f "\n%!";
let last_values = Hashtbl.create 97
and time = ref (match data with (t, _, _)::_ -> t | _ -> 0.) in
let print_last_values = fun t ->
fprintf f "%.3f" t;
List.iter
(fun (m,field) ->
let v = try Pprz.string_of_value (Hashtbl.find last_values (m,field)) with Not_found -> "" in
fprintf f ";%s" v)
!fields_to_export;
fprintf f "\n%!" in
List.iter (fun (t, msg, fields) ->
begin
match timestamp with
| Period p ->
if t >= !time then begin
print_last_values !time;
time := !time +. p
end
| _ -> ()
end;
List.iter (fun (f, v) ->
Hashtbl.replace last_values (msg, f) v)
fields;
match timestamp with
Msg m when m = msg ->
print_last_values t
| _ -> ())
data;
close_out f;;
(** The save file dialog box *)
let save_values = fun w log_filename save ->
let filename = Env.paparazzi_home // "var" // "logs" // log_filename ^ ".csv" in
match GToolbox.select_file ~title:"Save Values" ~filename () with
None -> ()
| Some file ->
save file;
w#export#destroy ()
(** The popup window displaying values to export *)
let popup = fun log_filename data ->
(* Build the list window *)
let file = Env.paparazzi_src // "sw" // "logalizer" // "export.glade" in
let w = new Gtk_export.export ~file () in
let icon = GdkPixbuf.from_file Env.icon_file in
w#export#set_icon (Some icon);
(* Build the tree model *)
let model = GTree.tree_store cols in
(** Attach the model to the view *)
w#treeview_messages#set_model (Some model#coerce);
(** Render the columns *)
display_columns w#treeview_messages model;
(** Fill the colums *)
let xml = Pprz.messages_xml () in
let xml_class = ExtXml.child ~select:(fun c -> ExtXml.attrib c "name" = class_name) xml "class" in
fill_data model xml_class;
(* The combo box for the timestamp choice *)
let strings = "Periodic" :: List.map (fun msg -> Xml.attrib msg "name") (Xml.children xml_class) in
let (combo, (tree, column)) = GEdit.combo_box_text ~packing:w#box_choose_period#add ~strings () in
tree#foreach (fun _path row -> combo#set_active_iter (Some row); true); (* Select the first *)
let get_timestamp = fun () ->
match combo#active_iter with
| None -> failwith "get_timestamp"
| Some row ->
combo#model#get ~row ~column in
(* Connect the timestamp chooser to the period entry *)
ignore (combo#connect#changed
(fun () ->
let data = get_timestamp () in
w#entry_period#misc#set_sensitive (data = "Periodic")));
(* The combo box for the extrapolation *)
let strings = ["Last Value"; "Linear Extrapol"] in
let (combo, (tree, column)) = GEdit.combo_box_text ~packing:w#box_choose_interpol#add ~strings () in
tree#foreach (fun _path row -> combo#set_active_iter (Some row); true); (* Select the first *)
ignore (w#button_cancel#connect#clicked (fun () -> w#export#destroy ()));
(** Connect the Save button to the write action *)
let callback = fun () ->
let timestamp =
let combo_value = get_timestamp () in
if combo_value = "Periodic" then
Period (float_of_string w#entry_period#text)
else
Msg combo_value in
save_values w log_filename (export_values model data timestamp) in
ignore (w#button_save#connect#clicked callback)
+17 -10
View File
@@ -326,7 +326,7 @@ let write_kml = fun plot log_name values ->
let add_ac_submenu = fun ?(factor=object method text="1" end) plot menubar (curves_menu_fact: GMenu.menu GMenu.factory) ac menu_name l ->
let add_ac_submenu = fun ?(factor=object method text="1" end) plot menubar (curves_menu_fact: GMenu.menu GMenu.factory) ac menu_name l raw_msgs ->
let menu = GMenu.menu () in
let menuitem = GMenu.menu_item ~label:menu_name () in
menuitem#set_submenu menu;
@@ -364,7 +364,10 @@ let add_ac_submenu = fun ?(factor=object method text="1" end) plot menubar (curv
let callback = fun () ->
let gps_values = List.assoc "GPS" l in
write_kml plot menu_name gps_values in
ignore (menu_fact#add_item ~callback "Export KML path")
ignore (menu_fact#add_item ~callback "Export KML path");
let callback = fun () ->
Export.popup menu_name raw_msgs in
ignore (menu_fact#add_item ~callback "Export CSV")
@@ -412,8 +415,8 @@ let load_log = fun ?factor (plot:plot) (menubar:GMenu.menu_shell GMenu.factory)
Scanf.sscanf l "%f %s %[^\n]"
(fun t ac m ->
if not (Hashtbl.mem acs ac) then
Hashtbl.add acs ac (Hashtbl.create 97);
let msgs = Hashtbl.find acs ac in
Hashtbl.add acs ac (Hashtbl.create 97, ref []);
let msgs, raw_msgs = Hashtbl.find acs ac in
(*Elements of [acs] are assoc lists of [fields] indexed by msg id*)
let msg_id, vs = P.values_of_string m in
@@ -422,7 +425,10 @@ let load_log = fun ?factor (plot:plot) (menubar:GMenu.menu_shell GMenu.factory)
let fields = Hashtbl.find msgs msg_id in
(* Elements of [fields] are values indexed by field name *)
List.iter (fun (f, v) -> Hashtbl.add fields f (t, v)) vs
List.iter (fun (f, v) -> Hashtbl.add fields f (t, v)) vs;
let msg_name = (P.message_of_id msg_id).Pprz.name in
raw_msgs := (t, msg_name, vs) :: !raw_msgs
)
with
exc -> prerr_endline (Printexc.to_string exc)
@@ -432,7 +438,8 @@ let load_log = fun ?factor (plot:plot) (menubar:GMenu.menu_shell GMenu.factory)
close_in f;
(* Compile the data to ease the menu building *)
Hashtbl.iter (* For all A/Cs *)
(fun ac msgs ->
(fun ac (msgs, raw_msgs) ->
let raw_msgs = List.rev !raw_msgs in
let menu_name = sprintf "%s:%s" (Filename.chop_extension (Filename.basename xml_file)) ac in
(* First sort by message id *)
@@ -457,9 +464,9 @@ let load_log = fun ?factor (plot:plot) (menubar:GMenu.menu_shell GMenu.factory)
msgs in
(* Store data for other windows *)
logs_menus := (ac, menu_name, msgs) :: !logs_menus;
logs_menus := (ac, menu_name, (msgs, raw_msgs)) :: !logs_menus;
add_ac_submenu ?factor plot menubar curves_fact ac menu_name msgs;
add_ac_submenu ?factor plot menubar curves_fact ac menu_name msgs raw_msgs;
)
acs
@@ -582,8 +589,8 @@ let rec plot_window = fun init ->
tooltips#set_tip factor#coerce ~text:"Scale next curve (e.g. 0.0174 to convert deg in rad, 57.3 to convert rad in deg, 1.8+32 to convert Celsius into Fahrenheit)";
List.iter
(fun (ac, menu_name, msgs) ->
add_ac_submenu ~factor:(factor:>text_value) plot factory curves_menu_fact ac menu_name msgs)
(fun (ac, menu_name, (msgs, raw_msgs)) ->
add_ac_submenu ~factor:(factor:>text_value) plot factory curves_menu_fact ac menu_name msgs raw_msgs)
!logs_menus;
ignore(open_log_item#connect#activate ~callback:(fun () -> let factor = (factor:>text_value) in open_log ~factor plot factory curves_menu_fact ()));