diff --git a/.gitignore b/.gitignore
index 0d10b01..51b133b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -112,6 +112,10 @@
# /sw/ground_segment/joystick
/sw/ground_segment/joystick/test_stick
+# /sw/ground_segment/misc
+/sw/ground_segment/misc/davis2ivy
+
+
# /sw/airborne/arch/lpc21/test/bootloader
/sw/airborne/arch/lpc21/test/bootloader/bl.dmp
/sw/airborne/arch/lpc21/test/bootloader/bl.hex
diff --git a/Makefile b/Makefile
index 516f73a..cd40500 100644
--- a/Makefile
+++ b/Makefile
@@ -43,6 +43,7 @@ AIRBORNE=sw/airborne
COCKPIT=sw/ground_segment/cockpit
TMTC=sw/ground_segment/tmtc
MULTIMON=sw/ground_segment/multimon
+MISC=sw/ground_segment/misc
LOGALIZER=sw/logalizer
SIMULATOR=sw/simulator
MAKE=make PAPARAZZI_SRC=$(PAPARAZZI_SRC) PAPARAZZI_HOME=$(PAPARAZZI_HOME)
@@ -69,7 +70,7 @@ OCAMLRUN=$(shell which ocamlrun)
all: commands static conf
-static : lib center tools cockpit multimon tmtc logalizer lpc21iap sim_static static_h usb_lib
+static : lib center tools cockpit multimon tmtc misc logalizer lpc21iap sim_static static_h usb_lib
conf: conf/conf.xml conf/control_panel.xml
@@ -98,6 +99,9 @@ cockpit: lib
tmtc: lib cockpit
cd $(TMTC); $(MAKE) all
+misc:
+ cd $(MISC); $(MAKE) all
+
multimon:
cd $(MULTIMON); $(MAKE)
diff --git a/conf/control_panel.xml.example b/conf/control_panel.xml.example
index e9a2ea9..f84a4b1 100644
--- a/conf/control_panel.xml.example
+++ b/conf/control_panel.xml.example
@@ -63,6 +63,11 @@
+
+
+
+
+
diff --git a/conf/messages.xml b/conf/messages.xml
index 27a0c43..1df1cbb 100644
--- a/conf/messages.xml
+++ b/conf/messages.xml
@@ -451,7 +451,7 @@
-
+
@@ -1332,7 +1332,7 @@
-
+
@@ -1603,7 +1603,12 @@
-
+
+
+
+
+
+
diff --git a/sw/ground_segment/misc/Makefile b/sw/ground_segment/misc/Makefile
new file mode 100644
index 0000000..018ab40
--- /dev/null
+++ b/sw/ground_segment/misc/Makefile
@@ -0,0 +1,7 @@
+all: davis2ivy
+
+davis2ivy: davis2ivy.o
+ g++ -o davis2ivy davis2ivy.o -s -livy
+
+%.o : %.c
+ gcc -c -O2 -Wall $<
diff --git a/sw/ground_segment/misc/davis2ivy.c b/sw/ground_segment/misc/davis2ivy.c
new file mode 100644
index 0000000..f167bb7
--- /dev/null
+++ b/sw/ground_segment/misc/davis2ivy.c
@@ -0,0 +1,269 @@
+/*
+ * Paparazzi $Id$
+ *
+ * Copyright (C) 2011 Andreas Gaeb
+ *
+ * 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.
+ *
+ */
+
+/** \file davis2ivy.c
+ * \brief Connect a Davis VantagePro weather station to the Paparazzi system
+ *
+ * The program communicates with a Davis VantagePro(2) weather station connected
+ * to a serial port. It asks for new data (Davis' LOOP command) in the
+ * specified intervals, extracts the relevant data (ambient pressure and
+ * temperature, wind speed and direction) and broadcasts this via the Ivy bus.
+ *
+ * At the moment, the Ivy messages should be sent with the ID of the actually
+ * flying aircraft, which integrates them into the log file, as long as the
+ * aircraft sends its alive message.
+ *
+ * Useful links:
+ * - Weather Stations
+ * - Communication docs
+ *
+ */
+
+
+ #include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+#include
+#include
+
+
+typedef enum { FALSE = 0, TRUE } BOOL;
+
+#define PACKET_LENGTH 99
+
+
+// global variables
+int fd, ac_id = 1;
+const char *device;
+unsigned char packet[PACKET_LENGTH];
+TimerId tid;
+BOOL want_alive_msg = FALSE;
+
+
+/// Handler for Ctrl-C, exits the main loop
+void sigint_handler(int sig) {
+ IvyStop();
+ TimerRemove(tid);
+ close(fd);
+}
+
+/// open the serial port with the appropiate settings
+void open_port(const char* device) {
+ fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY);
+ if (fd == -1) {
+ fprintf(stderr, "open_port: unable to open device %s - ", device);
+ perror(NULL);
+ exit(EXIT_FAILURE);
+ }
+ // setup connection options
+ struct termios options;
+
+ // get the current options
+ tcgetattr(fd, &options);
+
+ // set local mode, enable receiver, set comm. options:
+ // 8 data bits, 1 stop bit, no parity, 19200 Baud
+ options.c_cflag = CLOCAL | CREAD | CS8 | B19200;
+
+ // write options back to port
+ tcsetattr(fd, TCSANOW, &options);
+
+}
+
+/// disable transactions and empty queue
+void reset_station() {
+ char newline = '\n', bytes = 0;
+ fprintf(stderr, "Resetting communication\n");
+ // send a \n (wakeup and cancel all running transmits)
+ bytes = write(fd, &newline, 1);
+ // read and discard everything that might be left in the queue
+ close(fd);
+ sleep(1);
+ open_port(device);
+}
+
+/// send a wakeup call to the station
+BOOL wakeup(int tries) {
+ int loops = tries, bytes;
+ BOOL woken = FALSE;
+ char buf[] = {0, 0};
+ char newline = '\n';
+ do {
+ // send a \n
+ bytes = write(fd, &newline, 1);
+ // wait until station answers with \n\r
+ usleep(30000);
+ bytes = read(fd, buf, sizeof(buf));
+ woken = (buf[0] == 10) && (buf[1] == 13);
+ } while (!woken && loops-- > 0);
+ if (!woken) {
+ fprintf(stderr, "Could not wake up station: ");
+ if (bytes < 1) fprintf(stderr, "no bytes received\n");
+ else fprintf(stderr, "received %02x:%02x instead of \\n\\r\n", buf[0], buf[1]);
+ reset_station();
+ }
+ return woken;
+}
+
+/// send a LOOP command (read sensor data) to the station and get the packet back
+BOOL send_loop() {
+ char msg[32], ack;
+ // TODO maybe ask for more packets?
+ snprintf(msg, sizeof(msg), "LOOP %i\n", 1);
+ int bytes = write(fd, msg, strlen(msg));
+ usleep(120000);
+ bytes = read(fd, &ack, 1);
+ if (bytes < 1 || ack != 0x06) {
+ fprintf(stderr, "Failed to receive ACK from station\n");
+ reset_station();
+ return FALSE;
+ }
+ bytes = read(fd, packet, PACKET_LENGTH);
+ if (bytes < PACKET_LENGTH) {
+ fprintf(stderr, "Received packet is incomplete, only %i of %i bytes\n",
+ bytes, PACKET_LENGTH);
+ reset_station();
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+}
+
+/// get the relevant data from the packet and sent it as Ivy message
+void decode_and_send_to_ivy() {
+
+ // check packet integrity
+ char expected[] = "LOO";
+ if (strncmp((char *)packet, expected, 3) != 0) {
+ fprintf(stderr, "Received packet from the weather station which does not match the expected format\n");
+ reset_station();
+ return;
+ }
+
+ // TODO CRC checking (is rather involved for the Davis protocol)
+
+ // get relevant data and convert to SI units
+ // see chapter IX.1 of the protocol definition
+ float
+ pstatic_Pa = (packet[7] | packet[8] << 8)*3.386388640341, // original is inches Hg / 1000
+ temp_degC = ((packet[12] | packet[13] << 8)/10.0 - 32.0)*5.0/9.0, // original is deg F / 10
+ windspeed_mps = packet[14]*0.44704, // original is miles per hour
+ winddir_deg = packet[16] | packet[17] << 8;
+
+
+ // TODO get the real MD5 for the aircraft id
+ if (want_alive_msg)
+ IvySendMsg("%d ALIVE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n", ac_id);
+
+ // format has to match declaration in conf/messages.xml
+ IvySendMsg("%d WEATHER %f %f %f %f\n",
+ ac_id, pstatic_Pa, temp_degC, windspeed_mps, winddir_deg);
+}
+
+/// Get data from the station and send it via Ivy
+/** This function is executed by the timer
+ */
+void handle_timer (TimerId id, void *data, unsigned long delta) {
+ if (wakeup(3) && send_loop()) decode_and_send_to_ivy();
+}
+
+void print_usage(int argc, char ** argv) {
+ fprintf(stderr, "Usage: %s [-a] [-b ] [-d ] [-i ] [-s ]\n",
+ argv[0]);
+};
+
+/// Main function
+int main(int argc, char **argv) {
+ // default values for options
+ const char
+ *defaultbus = "127.255.255.255:2010",
+ *bus = defaultbus,
+ *defaultdevice = "/dev/ttyUSB1";
+ device = defaultdevice;
+ long delay = 1000;
+
+ // parse options
+ char c;
+ while ((c = getopt (argc, argv, "hab:d:i:s:")) != EOF) {
+ switch (c) {
+ case 'h':
+ print_usage(argc, argv);
+ exit(EXIT_SUCCESS);
+ break;
+ case 'a':
+ want_alive_msg = TRUE;
+ break;
+ case 'b':
+ bus = optarg;
+ break;
+ case 'd':
+ device = optarg;
+ break;
+ case 'i':
+ ac_id = atoi(optarg);
+ break;
+ case 's':
+ delay = atoi(optarg)*1000;
+ break;
+ case '?':
+ if (optopt == 'a' || optopt == 'b' || optopt == 'd' || optopt == 's')
+ fprintf (stderr, "Option -%c requires an argument.\n", optopt);
+ else if (isprint (optopt))
+ fprintf (stderr, "Unknown option `-%c'.\n", optopt);
+ else
+ fprintf (stderr, "Unknown option character `\\x%x'.\n", optopt);
+ print_usage(argc, argv);
+ exit(EXIT_FAILURE);
+ default:
+ abort ();
+ }
+ }
+
+
+ // make Ctrl-C stop the main loop and clean up properly
+ signal(SIGINT, sigint_handler);
+
+ bzero (packet, PACKET_LENGTH);
+ open_port(device);
+
+ // setup Ivy communication
+ IvyInit("davis2ivy", "READY", 0, 0, 0, 0);
+ IvyStart(bus);
+
+ // create timer
+ tid = TimerRepeatAfter (0, delay, handle_timer, 0);
+
+ IvyMainLoop();
+
+ return 0;
+}
diff --git a/sw/ground_segment/misc/readme.txt b/sw/ground_segment/misc/readme.txt
new file mode 100644
index 0000000..5221c38
--- /dev/null
+++ b/sw/ground_segment/misc/readme.txt
@@ -0,0 +1,3 @@
+davis2ivy:
+ A wrapper to communicate with a Davis VantagePro/VantagePro2 weather
+ station and integrate weather data into the telemetry link.