commit-gnuradio
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Commit-gnuradio] r3256 - in gnuradio/branches/developers/jcorgan/ezdop:


From: jcorgan
Subject: [Commit-gnuradio] r3256 - in gnuradio/branches/developers/jcorgan/ezdop: . config ezdop/src/host ezdop/src/host/hunter ezdop/src/host/hunter/config ezdop/src/host/hunter/src
Date: Sat, 12 Aug 2006 12:20:45 -0600 (MDT)

Author: jcorgan
Date: 2006-08-12 12:20:45 -0600 (Sat, 12 Aug 2006)
New Revision: 3256

Added:
   gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/AUTHORS
   gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/ChangeLog
   gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/bootstrap
   gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/config/
   
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/config/hunter_ftdi.m4
   
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/config/hunter_wx.m4
   gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/configure.ac
   gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/
   
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/Makefile.am
   
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/calibrate.cc
   
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/calibrate.h
   
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/doppler.cc
   
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/doppler.h
   gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/gps.cc
   gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/gps.h
   
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/histogram.cc
   
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/histogram.h
   
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/hunter.bmp
   
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/hunter.cc
   gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/hunter.h
   
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/hunter.xpm
   
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/hunter.xrc
   
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/hunterapp.cc
   
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/hunterapp.h
   gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/known.cc
   gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/known.h
   
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/sample.cc
   gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/sample.h
   
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/samplelog.cc
   
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/samplelog.h
   
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/search.cc
   gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/search.h
   
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/serial.cc
   gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/serial.h
   
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/settings.cpp
   
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/settings.h
   
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/spherical.cc
   
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/spherical.h
   
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/tactical.cc
   
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/tactical.h
   gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/util.h
Removed:
   gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/Makefile.am
   
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/calibrate.cpp
   gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/calibrate.h
   gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/doppler.cpp
   gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/doppler.h
   gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/gps.cpp
   gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/gps.h
   gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/header
   
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/histogram.cpp
   gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/histogram.h
   gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/hunter.bmp
   gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/hunter.cpp
   gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/hunter.h
   gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/hunter.xpm
   gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/hunter.xrc
   
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/hunterapp.cpp
   gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/hunterapp.h
   gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/known.cpp
   gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/known.h
   gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/sample.cpp
   gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/sample.h
   
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/samplelog.cpp
   gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/samplelog.h
   gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/search.cpp
   gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/search.h
   gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/serial.cpp
   gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/serial.h
   gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/settings.cpp
   gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/settings.h
   
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/spherical.cpp
   gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/spherical.h
   gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/tactical.cpp
   gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/tactical.h
   gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/util.h
Modified:
   gnuradio/branches/developers/jcorgan/ezdop/config/grc_ezdop.m4
   gnuradio/branches/developers/jcorgan/ezdop/configure.ac
   gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/Makefile.am
   gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/
Log:
Go back to individual configure.ac for hunter application and reorganize 
directories.


Modified: gnuradio/branches/developers/jcorgan/ezdop/config/grc_ezdop.m4
===================================================================
--- gnuradio/branches/developers/jcorgan/ezdop/config/grc_ezdop.m4      
2006-08-12 15:32:25 UTC (rev 3255)
+++ gnuradio/branches/developers/jcorgan/ezdop/config/grc_ezdop.m4      
2006-08-12 18:20:45 UTC (rev 3256)
@@ -31,11 +31,6 @@
        ezdop/src/host/tests/Makefile \
     ])
 
-    # FIXME: Test for wxWidgets
-    AC_CONFIG_FILES([ \
-       ezdop/src/host/hunter/Makefile \
-    ])    
-
     succeeded=yes
 
     AC_PATH_PROG(AVRGCC, [avr-gcc -v], no)

Modified: gnuradio/branches/developers/jcorgan/ezdop/configure.ac
===================================================================
--- gnuradio/branches/developers/jcorgan/ezdop/configure.ac     2006-08-12 
15:32:25 UTC (rev 3255)
+++ gnuradio/branches/developers/jcorgan/ezdop/configure.ac     2006-08-12 
18:20:45 UTC (rev 3256)
@@ -150,25 +150,25 @@
 dnl The order of the GR_ macros determines the order of compilation
 subdirs="config"
 GRC_GNURADIO_CORE
-GRC_GNURADIO_EXAMPLES
-GRC_USRP
-GRC_GR_USRP                    dnl this must come after GRC_USRP
-GRC_GR_AUDIO_ALSA
-GRC_GR_AUDIO_JACK
-GRC_GR_AUDIO_OSS
-GRC_GR_AUDIO_OSX               dnl ***NOT TESTED***
-GRC_GR_AUDIO_PORTAUDIO         dnl ***NOT TESTED***
-GRC_GR_AUDIO_WINDOWS           dnl ***NOT TESTED***
-GRC_GR_ATSC
-GRC_GR_COMEDI
+#GRC_GNURADIO_EXAMPLES
+#GRC_USRP
+#GRC_GR_USRP                   dnl this must come after GRC_USRP
+#GRC_GR_AUDIO_ALSA
+#GRC_GR_AUDIO_JACK
+#GRC_GR_AUDIO_OSS
+#GRC_GR_AUDIO_OSX              dnl ***NOT TESTED***
+#GRC_GR_AUDIO_PORTAUDIO                dnl ***NOT TESTED***
+#GRC_GR_AUDIO_WINDOWS          dnl ***NOT TESTED***
+#GRC_GR_ATSC
+#GRC_GR_COMEDI
 #GRC_GR_ERROR_CORRECTING_CODES  dnl disabled until fix for ticket:25
-GRC_GR_GSM_FR_VOCODER
-GRC_GR_RADAR
-GRC_GR_RADIO_ASTRONOMY
-GRC_GR_VIDEO_SDL
-GRC_GR_WXGUI
-GRC_PMT
-GRC_GR_TRELLIS
+#GRC_GR_GSM_FR_VOCODER
+#GRC_GR_RADAR
+#GRC_GR_RADIO_ASTRONOMY
+#GRC_GR_VIDEO_SDL
+#GRC_GR_WXGUI
+#GRC_PMT
+#GRC_GR_TRELLIS
 GRC_EZDOP
 GRC_GR_EZDOP                   dnl this must come after GRC_EZDOP
 

Modified: gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/Makefile.am
===================================================================
--- gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/Makefile.am       
2006-08-12 15:32:25 UTC (rev 3255)
+++ gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/Makefile.am       
2006-08-12 18:20:45 UTC (rev 3256)
@@ -19,4 +19,4 @@
 
 include $(top_srcdir)/Makefile.common
 
-SUBDIRS = avrdude ezdop tests
\ No newline at end of file
+SUBDIRS = avrdude ezdop tests


Property changes on: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter
___________________________________________________________________
Name: svn:ignore
   - Makefile.in

   + Makefile.in
configure
depcomp
config.guess
ltmain.sh
config.sub
config.h.in
autom4te.cache
INSTALL
COPYING
missing
NEWS
aclocal.m4
install-sh
build


Added: gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/AUTHORS
===================================================================
--- gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/AUTHORS    
                        (rev 0)
+++ gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/AUTHORS    
2006-08-12 18:20:45 UTC (rev 3256)
@@ -0,0 +1 @@
+Johnathan Corgan <address@hidden>

Added: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/ChangeLog
===================================================================

Deleted: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/Makefile.am

Added: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/bootstrap
===================================================================
--- gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/bootstrap  
                        (rev 0)
+++ gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/bootstrap  
2006-08-12 18:20:45 UTC (rev 3256)
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+# Copyright 2001,2005 Free Software Foundation, Inc.
+# 
+# This file is part of GNU Radio
+# 
+# GNU Radio 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.
+# 
+# GNU Radio 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 GNU Radio; see the file COPYING.  If not, write to
+# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+
+rm -fr config.cache autom4te*.cache
+
+aclocal -I config
+autoconf
+autoheader
+automake --add-missing


Property changes on: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/bootstrap
___________________________________________________________________
Name: svn:executable
   + *

Deleted: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/calibrate.cpp

Deleted: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/calibrate.h

Added: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/config/hunter_ftdi.m4
===================================================================
--- 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/config/hunter_ftdi.m4
                              (rev 0)
+++ 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/config/hunter_ftdi.m4
      2006-08-12 18:20:45 UTC (rev 3256)
@@ -0,0 +1,18 @@
+AC_DEFUN([HUNTER_FTDI],[
+    AC_LANG_PUSH(C)
+    
+    AC_CHECK_HEADER([ftdi.h],[],[
+       AC_MSG_ERROR("Hunter requires ftdi.h, not found, stop.")]
+    )
+    
+    save_LIBS="$LIBS"
+    AC_SEARCH_LIBS(ftdi_init, [ftdi], [FTDI_LIBS=$LIBS],[
+       AC_MSG_ERROR("Hunter requires libftdi, not found, stop.")]
+    )
+
+    LIBS="$save_LIBS"
+    AC_LANG_POP(C)
+
+    AC_SUBST(FTDI_LIBS)
+    AC_DEFINE([HAVE_LIBFTDI],[1],[Define to 1 if your system has libftdi.])
+])


Property changes on: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/config/hunter_ftdi.m4
___________________________________________________________________
Name: svn:eol-style
   + native

Added: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/config/hunter_wx.m4
===================================================================
--- 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/config/hunter_wx.m4
                                (rev 0)
+++ 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/config/hunter_wx.m4
        2006-08-12 18:20:45 UTC (rev 3256)
@@ -0,0 +1,11 @@
+AC_DEFUN([HUNTER_WX], [
+       AC_PATH_PROG([WXCONFIG],[wx-config],[no])
+       if test $WXCONFIG = no; then
+               AC_MSG_ERROR("wxWidgets is required, not found, stop.")
+       fi
+
+       WX_FLAGS=`$WXCONFIG --cflags`
+       WX_LIBS=`$WXCONFIG --libs`
+       AC_SUBST(WX_FLAGS)
+       AC_SUBST(WX_LIBS)
+])


Property changes on: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/config/hunter_wx.m4
___________________________________________________________________
Name: svn:eol-style
   + native

Added: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/configure.ac
===================================================================
--- 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/configure.ac   
                            (rev 0)
+++ 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/configure.ac   
    2006-08-12 18:20:45 UTC (rev 3256)
@@ -0,0 +1,42 @@
+#                                               -*- Autoconf -*-
+# Process this file with autoconf to produce a configure script.
+
+AC_PREREQ(2.59)
+AC_INIT(hunter, 0.1svn, address@hidden)
+AM_INIT_AUTOMAKE
+
+AC_CONFIG_SRCDIR([src/hunter.cc])
+AC_CONFIG_HEADER([config.h])
+
+# Checks for programs.
+AC_PROG_CXX
+AC_PROG_CC
+
+# Checks for libraries.
+
+# Checks for header files.
+AC_CHECK_HEADERS([fcntl.h sys/ioctl.h termios.h unistd.h])
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_HEADER_STDBOOL
+AC_C_CONST
+AC_C_INLINE
+AC_TYPE_SIZE_T
+AC_STRUCT_TM
+
+# Checks for library functions.
+AC_PROG_GCC_TRADITIONAL
+AC_HEADER_STDC
+AC_FUNC_MKTIME
+AC_CHECK_FUNCS([modf sqrt])
+
+# Application specific checks
+HUNTER_WX
+HUNTER_FTDI
+
+AC_CONFIG_FILES([ \
+    Makefile
+    src/Makefile
+])
+
+AC_OUTPUT


Property changes on: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/configure.ac
___________________________________________________________________
Name: svn:eol-style
   + native

Deleted: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/doppler.cpp

Deleted: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/doppler.h

Deleted: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/gps.cpp

Deleted: gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/gps.h

Deleted: gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/header

Deleted: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/histogram.cpp

Deleted: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/histogram.h

Deleted: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/hunter.bmp

Deleted: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/hunter.cpp

Deleted: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/hunter.h

Deleted: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/hunter.xpm

Deleted: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/hunter.xrc

Deleted: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/hunterapp.cpp

Deleted: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/hunterapp.h

Deleted: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/known.cpp

Deleted: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/known.h

Deleted: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/sample.cpp

Deleted: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/sample.h

Deleted: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/samplelog.cpp

Deleted: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/samplelog.h

Deleted: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/search.cpp

Deleted: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/search.h

Deleted: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/serial.cpp

Deleted: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/serial.h

Deleted: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/settings.cpp

Deleted: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/settings.h

Deleted: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/spherical.cpp

Deleted: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/spherical.h


Property changes on: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src
___________________________________________________________________
Name: svn:ignore
   + Makefile.in
Makefile
resource.cc


Copied: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/Makefile.am
 (from rev 3254, 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/Makefile.am)
===================================================================
--- 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/Makefile.am
                            (rev 0)
+++ 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/Makefile.am
    2006-08-12 18:20:45 UTC (rev 3256)
@@ -0,0 +1,42 @@
+# Copyright 2006 Johnathan Corgan.
+# 
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2
+# as published by the Free Software Foundation.
+# 
+# This software 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 GNU Radio; see the file COPYING.  If not, write to
+# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+bin_PROGRAMS = hunter
+hunter_SOURCES = \
+                 calibrate.cc \
+                 doppler.cc   \
+                 gps.cc       \
+                 histogram.cc \
+                 hunter.cc    \
+                 hunterapp.cc \
+                 hunter.xrc    \
+                 known.cc     \
+                 resource.cc  \
+                 sample.cc    \
+                 samplelog.cc \
+                 search.cc    \
+                 serial.cc    \
+                 settings.cpp \
+                 spherical.cc \
+                 tactical.cc
+
+hunter_CXXFLAGS = $(WX_FLAGS)
+hunter_LDADD = \
+    $(FTDI_LIBS) \
+    $(WX_LIBS)
+    
+resource.cc: hunter.xrc
+       wxrc -c -o resource.cc hunter.xrc

Copied: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/calibrate.cc
 (from rev 3254, 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/calibrate.cpp)
===================================================================
--- 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/calibrate.cc
                           (rev 0)
+++ 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/calibrate.cc
   2006-08-12 18:20:45 UTC (rev 3256)
@@ -0,0 +1,82 @@
+/*
+ Copyright 2006 Johnathan Corgan.
+ 
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+ 
+ This software 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 GNU Radio; see the file COPYING.  If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+// Application level includes
+#include "calibrate.h"
+#include "hunter.h"
+
+// wxWidgets includes
+#include <wx/xrc/xmlres.h>
+#include <wx/button.h>
+#include <wx/gauge.h>
+#include <wx/stattext.h>
+#include <wx/log.h>
+
+// Event table for CalibrationDialog
+BEGIN_EVENT_TABLE(CalibrationDialog, wxDialog)
+    EVT_BUTTON(XRCID("calibration_start_button"), CalibrationDialog::OnStart)
+    EVT_BUTTON(XRCID("calibration_cancel_button"), 
CalibrationDialog::OnCancelOrZero)
+END_EVENT_TABLE()
+
+CalibrationDialog::CalibrationDialog(HunterFrame *parent)
+{
+    m_hunter_frame = parent;
+    wxXmlResource::Get()->LoadDialog(this, parent, _T("calibration_dialog"));
+    m_start_button = XRCCTRL(*this, "calibration_start_button", wxButton);
+    m_cancel_button = XRCCTRL(*this, "calibration_cancel_button", wxButton);
+    m_progress_gauge = XRCCTRL(*this, "calibration_progress_gauge", wxGauge);
+    m_instructions_text = XRCCTRL(*this, "calibration_instructions_text", 
wxStaticText);
+    m_progress_text = XRCCTRL(*this, "calibration_progress_text", 
wxStaticText);
+    m_cancelled = false;
+}
+
+void CalibrationDialog::OnStart(wxCommandEvent &event)
+{
+    wxLogDebug(_T("CalibrationDialog::OnStart()"));
+    wxString msg;
+    
+    m_start_button->Disable();
+    m_equalized = false;
+    for (int i = 0; i < 6; i++) {
+        msg.Printf(_T("Peforming calibration step #%i"), i+1);
+        m_progress_text->SetLabel(msg);
+        if (m_cancelled)
+             break;
+        wxYield();
+        m_hunter_frame->DoCalibrationStep(i);
+        if (m_cancelled)
+             break;
+        m_progress_gauge->SetValue(i+1);        
+    }
+    m_equalized = true;
+    m_instructions_text->SetLabel(_T("After pressing OK, you will need to\n" \
+                                  "set the signal source to straight ahead\n" \
+                                  "and press the Doppler 'Zero' button."));
+    m_progress_text->SetLabel(_T("Calibration completed."));
+    m_cancel_button->SetLabel(_T("OK"));
+}
+
+void CalibrationDialog::OnCancelOrZero(wxCommandEvent &event)
+{
+    wxLogDebug(_T("CalibrationDialog::OnCancel()"));
+    if (!m_equalized) {
+        m_cancelled = true;
+    }
+
+    EndModal(0);
+}

Copied: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/calibrate.h
 (from rev 3254, 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/calibrate.h)
===================================================================
--- 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/calibrate.h
                            (rev 0)
+++ 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/calibrate.h
    2006-08-12 18:20:45 UTC (rev 3256)
@@ -0,0 +1,53 @@
+/*
+ Copyright 2006 Johnathan Corgan.
+ 
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+ 
+ This software 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 GNU Radio; see the file COPYING.  If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef __CALIBRATE_H__
+#define __CALIBRATE_H__
+
+// wxWidgets includes
+#include <wx/event.h>
+#include <wx/dialog.h>
+#include <wx/gauge.h>  // Can't forward declare because wxGauge is a macro
+
+// Forward declarations
+class wxStaticText;
+class HunterFrame;
+class wxButton;
+
+class CalibrationDialog : public wxDialog
+{
+public:
+    CalibrationDialog(HunterFrame *parent);
+    
+private:
+    void OnStart(wxCommandEvent &event);
+    void OnCancelOrZero(wxCommandEvent &event);
+
+    HunterFrame *m_hunter_frame;
+    wxGauge *m_progress_gauge;
+    wxStaticText *m_progress_text;
+    wxStaticText *m_instructions_text;
+    wxButton *m_start_button;
+    wxButton *m_cancel_button;
+    bool m_cancelled;
+    bool m_equalized;
+            
+    DECLARE_EVENT_TABLE();
+};
+
+#endif // __CALIBRATE_H__

Copied: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/doppler.cc 
(from rev 3254, 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/doppler.cpp)
===================================================================
--- 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/doppler.cc 
                            (rev 0)
+++ 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/doppler.cc 
    2006-08-12 18:20:45 UTC (rev 3256)
@@ -0,0 +1,517 @@
+/*
+ Copyright 2006 Johnathan Corgan.
+ 
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+ 
+ This software 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 GNU Radio; see the file COPYING.  If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+// Application level includes
+#include "doppler.h"
+#include "util.h"
+#include <dopctrl.h>
+
+// wxWidgets includes
+#include <wx/log.h>
+#include <wx/frame.h>
+
+// System level includes
+#include <cmath>
+
+#define SAMPLERATE      8000
+#define QUANTUM         0.2        // Sample period in seconds
+#define MAXSAMPLE       0x3FF      // 12 bit ADC
+
+#define DEFAULT_SELECTED_ROTATION_RATE 2     // 500 Hz until told otherwise
+#define DEFAULT_FILTER_LEVEL 20
+
+#define NORMALIZEPHASE(x) \
+        if ((x) > M_PI) \
+            (x) -= 2*M_PI; \
+        if ((x) < -M_PI) \
+            (x) += 2*M_PI;
+
+unsigned char rotation_rates[] = {
+    8,      // 250 Hz
+    5,      // 400 Hz
+    4,      // 500 Hz
+    3,      // 666 Hz
+    2,      // 1000 Hz
+    1       // 2000 Hz
+};
+
+const wxEventType wxEVT_DOPPLER_UPDATE = wxNewEventType();
+
+EZDopplerUpdate::EZDopplerUpdate(const wxEventType &event, float &in_phase, 
+                                 float &quadrature, float &volume) :
+wxNotifyEvent(event)
+{
+    m_in_phase = in_phase;
+    m_quadrature = quadrature;
+    m_volume = volume;
+}
+
+DopplerBackground::DopplerBackground(wxWindow *window, EZDoppler *doppler)
+{
+    wxASSERT(window);
+    wxASSERT(doppler);
+    
+    m_running = false;
+    m_dest = window;
+    m_doppler = doppler;
+       Create();
+}
+
+// It's in thread.h but somehow gets undef'd
+typedef void *ExitCode;
+ExitCode DopplerBackground::Entry()
+{
+    float in_phase, quadrature, phase, magnitude, volume, rflevel;
+
+    m_running = true;
+       while (!TestDestroy()) {
+           if (m_doppler->Sample((int)(QUANTUM*SAMPLERATE), in_phase, 
quadrature, volume)) {
+           EZDopplerUpdate update(wxEVT_DOPPLER_UPDATE, in_phase, quadrature, 
volume);
+               wxPostEvent(m_dest, update);
+        }
+       }
+       m_running = false;
+}
+
+EZDoppler::EZDoppler(wxWindow *gui)
+{
+    wxASSERT(gui);
+
+    m_thread = NULL;
+    m_online = false;
+    m_selected_rate = DEFAULT_SELECTED_ROTATION_RATE;
+    m_gui = gui;
+    m_in_phase = 0.0;
+    m_quadrature = 0.0;
+    m_alpha = 1.0/(DEFAULT_FILTER_LEVEL*200);
+    m_beta = 1.0-m_alpha;
+    m_phase = 0.0;
+    m_offset = 0.0;
+        
+    for(int i = 0; i < NUM_RATES; i++) 
+        m_calibration[i] = 0.0;
+    
+#if HAVE_LIBFTDI
+       m_device = new struct ftdi_context;
+       wxASSERT(m_device);
+       if (ftdi_init(m_device)) {
+           wxLogWarning(_T("ftdi_init: %s"), m_device->error_str);
+           return;
+    }
+#endif
+
+}
+
+EZDoppler::~EZDoppler()
+{
+    if (m_online) {
+        wxLogMessage(_T("EZDoppler::~EZDoppler(): doppler still online in 
destructor, finalizing"));
+        Finalize();
+    }
+#if HAVE_LIBFTDI
+    wxASSERT(m_device);
+       ftdi_deinit(m_device);
+       delete m_device;
+#endif
+}
+
+bool EZDoppler::Initialize()
+{
+    m_online = false;
+    
+#if HAVE_LIBFTDI
+       if (ftdi_usb_open(m_device, EZDOP_VENDORID, EZDOP_PRODUCTID)) {
+               wxLogDebug(_T("ftdi_usb_open: %s"), m_device->error_str);
+               return false;
+       }
+#elif HAVE_LIBFTD2XX
+    if ((m_status = FT_Open(0, &m_handle)) != FT_OK) {
+               wxLogError(_T("FT_Open failed: %i"), m_status);
+               return false;
+       }
+#endif
+
+    m_online = true;
+    if (m_online)
+        Reset();
+
+    return m_online;
+ }
+
+bool EZDoppler::Finalize()
+{
+    if (!m_online)
+        return true;
+
+    if (m_thread && m_thread->IsRunning()) {
+        wxLogDebug(_T("EZDoppler::Finalize: finalizing a running doppler"));
+        Stop();
+    }
+
+#if HAVE_LIBFTDI
+       if (ftdi_usb_close(m_device)) {
+           wxLogWarning(_T("ftdi_usb_close: %s"), m_device->error_str);
+           return false;
+       }
+#elif HAVE_LIBFTD2XX
+    if ((m_status = FT_Close(m_handle)) != FT_OK) {
+               wxLogWarning(_T("FT_Close failed: %i"), m_status);
+               return false;
+       }
+#endif
+
+    m_online = false;
+    return true;
+}
+
+bool EZDoppler::IsOnline()
+{
+    return m_online;
+}
+
+bool EZDoppler::send_byte(unsigned char data)
+{
+    wxASSERT(m_online);
+#if HAVE_LIBFTDI       
+    if (ftdi_write_data(m_device, &data, 1) != 1) {
+        wxLogWarning(_T("ftdi_write_data: %s"), m_device->error_str);
+        return false;
+    }
+#elif HAVE_LIBFTD2XX
+    DWORD written;
+    if ((m_status = FT_Write(m_handle, &data, 1, &written)) != FT_OK || 
written != 1) {
+        wxLogError(_T("FT_Write failed: %i"), m_status);
+               return false;
+       }
+#endif
+       return true;    
+}
+
+bool EZDoppler::Reset()
+{
+    wxASSERT(m_online);
+
+    if (m_thread && m_thread->IsRunning()) {
+        wxLogDebug(_T("EZDoppler::Reset: resetting running doppler"));
+        Stop();
+    }
+
+
+    // Reset FTDI chipset
+#if HAVE_LIBFTDI
+       if (ftdi_usb_reset(m_device)) {
+           wxLogWarning(_T("ftdi_usb_reset: %s"), m_device->error_str);
+           return false;
+    }
+#elif HAVE_LIBFTD2XX
+       if ((m_status = FT_ResetDevice(m_handle) != FT_OK)) {
+               wxLogError(_T("FT_ResetDevice failed: %i"), m_status);
+               return false;
+       }
+#endif
+
+    // Set FTDI chipset baudrate for bitbang
+#if HAVE_LIBFTDI
+       if (ftdi_set_baudrate(m_device, EZDOP_BAUDRATE)) {
+           wxLogWarning(_T("ftdi_set_baudrate: %s"), m_device->error_str);
+           return false;
+    }
+#elif HAVE_LIBFTD2XX
+       if ((m_status = FT_SetBaudRate(m_handle, EZDOP_BAUDRATE)) != FT_OK) {
+               wxLogError(_T("FT_SetBaudRate failed: %i"), m_status);
+               return false;
+       }
+#endif
+
+    // Toggle DTR (-->AVR RESET)
+#if HAVE_LIBFTDI
+    // Enable bitbang
+       if (ftdi_enable_bitbang(m_device, EZDOP_BBDIR)) {
+           wxLogWarning(_T("ftdi_enable_bitbang: %s"), m_device->error_str);
+               return false;
+       }
+
+       // Lower DTR by writing 0 to bitbang output
+       if (!send_byte(0x00)) // HMMM: this actually lowers all outputs, of 
course
+           return false;
+#elif HAVE_LIBFTD2XX
+       // Set DTR line (goes low) to reset AVR and delay
+       if ((m_status = FT_SetDtr(m_handle)) != FT_OK) {
+               wxLogError(_T("FT_SetDtr failed: %i"), m_status);
+               return false;
+       }
+#endif
+
+    // 10 ms sleep with RESET low
+    wxMilliSleep(10); 
+
+#if HAVE_LIBFTDI
+       // Now raise DTR by writing 1 to bitbang output
+       if (!send_byte(0xFF))
+           return false;
+
+       if (ftdi_disable_bitbang(m_device)) {
+           wxLogWarning(_T("ftdi_disable_bitbang: %s"), m_device->error_str);
+               return false;
+       }
+       
+       // Minimum chunk size for reads to reduce latency
+       if (ftdi_read_data_set_chunksize(m_device, 256)) {
+           wxLogWarning(_T("ftdi_read_data_set_chunksize: %s"), 
m_device->error_str);
+               return false;
+       }
+#elif HAVE_LIBFTD2XX
+    if ((m_status = FT_ClrDtr(m_handle)) != FT_OK) {
+               wxLogError(_T("FT_ClrDtr failed: %i"), m_status);
+               return false;
+       }
+#endif
+
+    // 100 ms after RESET cleared to let things warm up
+    wxMilliSleep(100);
+
+    m_selected_rate = DEFAULT_SELECTED_ROTATION_RATE;
+
+    return true;
+}
+
+bool EZDoppler::Start()
+{
+    wxASSERT(m_online);
+    // TODO: flush stream data
+
+    if (!send_byte(EZDOP_CMD_ROTATE) || !send_byte(EZDOP_CMD_STREAM))
+        return false;
+        
+    m_thread = new DopplerBackground(m_gui, this);
+    m_thread->Run();    
+}
+
+bool EZDoppler::Stop()
+{
+    wxASSERT(m_online);
+    // TODO: flush stream data
+
+    if (m_thread && m_thread->IsRunning()) {
+        m_thread->Delete();
+        while (m_thread->IsRunning()) {
+            wxYield();
+        }
+    }
+    
+    m_thread = NULL;
+    return (send_byte(EZDOP_CMD_STROFF) && send_byte(EZDOP_CMD_STOP));
+}
+
+bool EZDoppler::SelectRotationRate(int n)
+{
+    wxASSERT(m_online);
+    wxASSERT(n >= 0 && n < 6);
+
+    unsigned char rate = rotation_rates[n];
+    if (send_byte(EZDOP_CMD_RATE) && send_byte(rate)) {
+        m_selected_rate = n;
+        m_in_phase = 0.0;
+        m_quadrature = 0.0;
+        return true;
+    }
+    
+    return false;
+}
+
+int EZDoppler::GetSelectedRotationRate()
+{
+    return m_selected_rate;
+}
+
+bool EZDoppler::Zero()
+{
+    return true;
+}
+
+bool EZDoppler::SetFilter(int n)
+{
+    wxASSERT(n > 0);
+    m_alpha = 1.0/(n*200); // Time constant is filter value divided by 5 
(empirically determined)
+    m_beta = 1.0-m_alpha;
+    return true;
+}
+
+bool EZDoppler::Sample(int nsamples, float &in_phase, float &quadrature, float 
&volume)
+{
+    unsigned short *audio = new unsigned short[nsamples*2];
+    unsigned char *antenna = new unsigned char[nsamples];
+    
+    unsigned int rd;
+    unsigned int count = 0;
+    
+    // Read samples from USB port, 2 bytes per sample
+    while (count < nsamples*2) {
+        unsigned int amt = nsamples*2-count;
+        unsigned char *ptr = (unsigned char *)&audio[count/2]; // if count is 
odd, causes frame slip?
+        if ((count/2)*2 != count)
+            wxLogDebug(_T("EZDoppler::Sample: count is odd (%i)"), count);
+#if HAVE_LIBFTDI
+        rd = ftdi_read_data(m_device, ptr, amt);
+        if (rd < 0) {
+            wxLogWarning(_T("ftdi_read_data: %s"), m_device->error_str);
+            return false; // FIXME: memory leak for antenna and audio!
+        }
+        count += rd;
+#elif HAVE_LIBFTD2XX
+        DWORD num;
+        FT_STATUS status = FT_Read(m_handle, ptr, amt, &num);
+        if (status != FT_OK) {
+            wxLogWarning(_T("FT_Read: %i"), status);
+            return false; // FIXME: memory leak for antenna and audio!
+        }
+        count += num;
+#endif        
+    }    
+    
+    // Extract antenna array position from samples, flag unsynced if not a 
valid antenna value
+    bool sync = true;
+    for (int i = 0; i < nsamples; i++) {
+        unsigned char ant = (audio[i] & 0xF000) >> 12;
+        if (ant != 8 && ant != 4 && ant != 2 && ant != 1)
+            sync = false;
+        antenna[i] = ant;
+        audio[i] &= 0x03FF;
+    }
+            
+    // If not synced, throw away a byte in receive stream to resync
+    unsigned char dummy;
+    if (!sync) {
+        wxLogDebug(_T("EZDoppler::Sample: sync failure detected"));
+#if HAVE_LIBFTDI
+        ftdi_read_data(m_device, &dummy, 1);
+#elif HAVE_LIBFTD2XX
+        DWORD rd;
+        FT_Read(m_handle, &dummy, 1, &rd);
+#endif            
+        return false; // FIXME: memory leak for antenna and audio!
+    }
+
+    // Calculate DC offset and max and min values
+    float sum = 0.0;
+    float mean = 0.0;
+    for (int i = 0; i < nsamples; i++)
+        sum += audio[i];
+    mean = sum/nsamples;
+
+    // Calculate doppler response
+    unsigned char ant;
+    float sample;
+    volume = 0.0;
+    for (int i = 0; i < nsamples; i++) {
+        ant = antenna[i];
+
+        // Subtract DC offset and scale to -1 to 1
+        sample = 2*(((float)audio[i])-mean)/MAXSAMPLE;
+
+        // Calculate peak volume
+        if (fabs(sample) > volume)
+            volume = fabs(sample);
+
+        // Integrate and lowpass filter sample into I/Q based on which antenna 
is selected
+        // Order here creates a clockwise rotating I/Q phasor
+        switch(ant) {
+            case 8:
+                m_in_phase = m_in_phase*m_beta + sample*m_alpha;
+                break;
+            case 4:
+                m_quadrature = m_quadrature*m_beta - sample*m_alpha;
+                break;
+            case 2:
+                m_in_phase = m_in_phase*m_beta - sample*m_alpha;
+                break;
+            case 1:
+                m_quadrature = m_quadrature*m_beta + sample*m_alpha;
+                break;
+            default:
+                wxLogError(_T("EZDoppler::Sample: Unknown antenna value %i"), 
ant);
+                break;
+        }
+    }
+
+    // m_phase is the actual instrument reading regardless of calibration
+    m_phase = atan2(m_quadrature, m_in_phase);
+
+    // Calibration angle is sum of equalized offset and global offset
+    float cal = m_calibration[m_selected_rate] + m_offset;
+
+    // Rotate I, Q by calibration angle
+    float i_cal = cos(cal);
+    float q_cal = sin(cal);
+    in_phase = m_in_phase*i_cal - m_quadrature*q_cal;
+    quadrature = m_quadrature*i_cal + m_in_phase*q_cal;
+
+    delete antenna;
+    delete audio;
+    return true;
+}
+
+bool EZDoppler::Calibrate(float phase)
+{
+    float offset = phase - m_phase;
+    NORMALIZEPHASE(offset);
+    m_calibration[m_selected_rate] = offset;
+    return true;
+}
+
+bool EZDoppler::SetCalibration(int rate, float offset)
+{
+    wxASSERT(rate >= 0 && rate < 7);
+    if (rate < 6)
+        m_calibration[rate] = offset;
+    else
+        m_offset = offset;
+}
+
+float EZDoppler::GetCalibration(int rate)
+{
+    wxASSERT(rate >= 0 && rate < 7);
+    if (rate < 6)
+        return m_calibration[rate];
+    else
+        return m_offset;        
+}
+
+bool EZDoppler::SetOffset(float offset)
+{
+    m_offset = offset-m_phase-m_calibration[m_selected_rate];
+    NORMALIZEPHASE(m_offset);
+    NORMALIZEPHASE(m_offset);
+    NORMALIZEPHASE(m_offset);
+}
+
+bool EZDoppler::Nudge(float amount)
+{
+    float cal = m_calibration[m_selected_rate];
+    cal += amount;
+    NORMALIZEPHASE(cal);
+    m_calibration[m_selected_rate] = cal;
+    return true;
+}
+
+bool EZDoppler::NudgeAll(float amount)
+{
+    m_offset += amount;
+    NORMALIZEPHASE(m_offset);
+    return true;
+}

Copied: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/doppler.h 
(from rev 3254, 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/doppler.h)
===================================================================
--- 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/doppler.h  
                            (rev 0)
+++ 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/doppler.h  
    2006-08-12 18:20:45 UTC (rev 3256)
@@ -0,0 +1,130 @@
+/*
+ Copyright 2006 Johnathan Corgan.
+ 
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+ 
+ This software 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 GNU Radio; see the file COPYING.  If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef __DOPPLER_H__
+#define __DOPPLER_H__
+
+// Autoconf generated configure options
+#if HAVE_CONFIG_H
+    #include "config.h"
+#endif
+
+// USB access library
+#if HAVE_LIBFTDI
+    #include <ftdi.h>
+#elif HAVE_LIBFTD2XX
+    #if __WIN32__
+        #include <windows.h>
+    #endif
+    #include <FTD2XX.H>
+#endif
+
+#include <wx/event.h>
+
+#define NUM_RATES   6
+
+class EZDoppler;
+
+class DopplerBackground : public wxThread
+{
+public:
+        DopplerBackground(wxWindow *window, EZDoppler *doppler);
+        virtual ExitCode Entry();
+        bool IsRunning() { return m_running; }
+
+private:
+        bool m_running;
+        wxWindow *m_dest;
+        EZDoppler *m_doppler;
+};
+
+class EZDopplerUpdate : public wxNotifyEvent
+{
+public:
+    EZDopplerUpdate(const wxEventType &event, float &in_phase, float 
&quadrature,
+                    float &volume); 
+    virtual wxEvent *Clone() const { return new EZDopplerUpdate(*this); }
+
+    float m_in_phase;
+    float m_quadrature;
+    float m_volume;
+};
+
+extern const wxEventType wxEVT_DOPPLER_UPDATE;
+
+typedef void(wxEvtHandler::*EZDopplerUpdateFunction)(EZDopplerUpdate&);
+
+#define EVT_DOPPLER_UPDATE(fn) \
+        DECLARE_EVENT_TABLE_ENTRY( \
+            wxEVT_DOPPLER_UPDATE, -1, -1, \
+            
(wxObjectEventFunction)(wxEventFunction)(EZDopplerUpdateFunction)&fn, \
+            (wxObject *)NULL \
+        ),
+
+class EZDoppler
+{
+public:
+    EZDoppler(wxWindow *gui);
+    ~EZDoppler();
+
+    // Control commands
+    bool Initialize();
+    bool Finalize();
+    bool IsOnline();
+    bool Start();
+    bool Stop();
+    bool Zero();
+    bool SetFilter(int n);
+    bool SelectRotationRate(int n);
+    int  GetSelectedRotationRate();
+    bool Reset();
+    bool Sample(int nsamples, float &in_phase, float &quadrature, float 
&volume);
+    bool Calibrate(float phase);
+    bool SetCalibration(int rate, float offset);
+    float GetCalibration(int rate);
+    bool SetOffset(float offset = 0.0);
+    bool Nudge(float amount);
+    bool NudgeAll(float amount);
+            
+private:
+    // USB interaction
+#if HAVE_LIBFTDI
+    struct ftdi_context *m_device;          // libftdi device instance data
+#elif HAVE_LIBFTD2XX
+    FT_HANDLE m_handle;                     // FTD2XX device instance data
+    FT_STATUS m_status;                     // FTD2XX device function call 
results
+#endif
+    bool send_byte(unsigned char data);
+
+    // Doppler control
+    bool m_online;
+    int  m_selected_rate;
+    wxWindow *m_gui;
+    DopplerBackground *m_thread;
+
+    // DSP state
+    float m_in_phase;           // Filtered I value
+    float m_quadrature;         // Filtered Q value
+    float m_alpha;              // Exponential lowpass constant
+    float m_beta;               // Exponential lowpass constant = 1-alpha
+    float m_phase;              // Actual phase of doppler before calibration
+    float m_offset;             // Global calibration angle
+    float m_calibration[NUM_RATES]; // Individual rotation rate offset
+};    
+
+#endif // __DOPPLER_H__

Copied: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/gps.cc 
(from rev 3254, 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/gps.cpp)
===================================================================
--- gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/gps.cc 
                        (rev 0)
+++ gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/gps.cc 
2006-08-12 18:20:45 UTC (rev 3256)
@@ -0,0 +1,247 @@
+/*
+ Copyright 2006 Johnathan Corgan.
+ 
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+ 
+ This software 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 GNU Radio; see the file COPYING.  If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+// Application level includes
+#include "gps.h"
+#include "serial.h"
+
+// wxWidgets includes
+#include <wx/log.h>
+
+#define NMEA_BAUD       4800
+#define NMEA_BUFSIZE    82      // Maximum NMEA sentence length
+
+const wxEventType wxEVT_GPS_UPDATE = wxNewEventType();
+
+GPSUpdate::GPSUpdate(const wxEventType &event, GPRMC *gprmc) :
+wxNotifyEvent(event)
+{
+    m_gprmc = gprmc;
+}
+
+GPSBackground::GPSBackground(GPS *gps)
+{
+    wxLogDebug(_T("GPSBackground::GPSBackground()"));
+    wxASSERT(gps);
+    
+    m_running = false;
+    m_gps = gps;
+    m_port = gps->GetPort();
+       Create();
+}
+
+// It's in thread.h but somehow gets undef'd
+typedef void *ExitCode;
+ExitCode GPSBackground::Entry()
+{
+    wxLogDebug(_T("GPSBackground::GPSBackground: entry"));
+
+    m_running = true;
+       while (!TestDestroy()) 
+        PerLoop();
+       m_running = false;
+
+    wxLogDebug(_T("GPSBackground::GPSBackground: exit"));
+}
+
+void GPSBackground::PerLoop()
+{
+    static char buffer[NMEA_BUFSIZE];
+    static int offset = 0;
+
+    while(m_port->RxReady() > 0) {
+        while (offset < NMEA_BUFSIZE) {
+            // Read a byte into the buffer from the GPS data
+            if (m_port->Read(&buffer[offset], 1) != 1)
+                return;  // No more to read or read error/timeout, bail
+
+            // Test for end of NMEA message
+            if (buffer[offset] == '\r' || buffer[offset] == '\n') {
+                buffer[offset] = '\0'; // Append end of string null
+                if (strlen(buffer))
+                    m_gps->RxData(buffer);
+                offset = 0;
+            }
+            else
+                offset++;
+        }
+        
+        wxLogDebug(_T("GPSBackground: discarding too long input"));
+        offset = 0;
+    }        
+
+    wxMilliSleep(500);
+}
+
+GPS::GPS(wxEvtHandler *dest)
+{
+    wxLogDebug(_T("GPS::GPS()"));
+    m_thread = NULL;
+    m_dest = dest;
+}
+
+GPS::~GPS()
+{
+    wxLogDebug(_T("GPS::~GPS()"));
+}
+
+bool GPS::Start(wxString &port)
+{
+    wxLogDebug(_T("GPS::Start(): %s"), port.c_str());
+    m_port = new SerialPort(port);
+
+    if (m_port->Open(NMEA_BAUD) == false) {
+        delete m_port;
+        return false;
+    }   
+
+    m_thread = new GPSBackground(this);
+    m_thread->Run();    
+    return true;
+}
+
+bool GPS::Stop()
+{
+    wxLogDebug(_T("GPS::Stop()"));
+
+    if (m_thread && m_thread->IsRunning()) {
+        m_thread->Delete();
+        while (m_thread->IsRunning()) {
+            wxYieldIfNeeded();
+        }
+    }
+    
+    m_thread = NULL;
+
+    m_port->Close();
+    if (m_port)
+        delete m_port;
+
+    return true;
+}
+
+bool NMEA::Checksum(char *sentence)
+{
+    unsigned char checksum = '\0';
+    char ch, *pos = sentence, ctxt[3];
+    
+    while ((ch = *pos++) != '*' && ch != '\0')
+        checksum ^= ch;
+        
+    sprintf(ctxt, "%02X", checksum);
+    if (strncmp(ctxt, pos, 2))
+        return false;
+    else
+        return true;
+}
+
+char *NMEA::Field(char *sentence, int num)
+{
+    static char result[NMEA_BUFSIZE];
+    char ch, *pos = sentence;
+            
+    while (num-- > 0)
+        while ((ch = *pos++) != ',' && ch != '\0')
+            continue;
+
+    strncpy(result, pos, NMEA_BUFSIZE-1);
+    int i = 0;
+    pos = result;
+    while (*pos && *pos != ',' && *pos != '*' && *pos != '\r' && ++i < 
NMEA_BUFSIZE)
+        pos++;
+    
+    *pos = 0;
+    return result;
+}
+
+double NMEA::Coord(char *sentence, int num)
+{
+    double coord, degrees, minutes;
+
+    sscanf(Field(sentence, num), "%lf", &coord);
+    minutes = 100.0*modf(coord/100.0, &degrees);
+    coord = degrees+minutes/60.0;
+
+    char *ptr = Field(sentence, num+1);
+    if (*ptr == 'S' || *ptr == 'W')
+        coord = -coord;
+
+    return coord;
+}
+
+void GPS::RxData(char *buffer)
+{
+    wxASSERT(buffer);
+    
+    if (NMEA::Checksum(buffer+1)) {
+        if (strncmp("$GPRMC", buffer, 6) == 0) {
+            GPRMC *fix = new GPRMC(buffer);
+                   GPSUpdate update(wxEVT_GPS_UPDATE, fix);
+               wxPostEvent(m_dest, update);
+        }
+    }
+    else
+        wxLogDebug(_T("GPS::RxData: NMEA checksum failed for input"));
+}
+
+GPRMC::GPRMC(char *sentence)
+{
+    wxASSERT(sentence);
+
+    struct tm stamp;
+    char digits[2];
+
+    char *p = Field(sentence, 1);
+    wxASSERT(p);
+    strncpy(digits, p, 2);
+    stamp.tm_hour = atoi(digits);
+    strncpy(digits, p+2, 2);
+    stamp.tm_min = atoi(digits);
+    strncpy(digits, p+4, 2);
+    stamp.tm_sec = atoi(digits);
+
+    p = Field(sentence, 9);
+    wxASSERT(p);
+    strncpy(digits, p, 2);
+    stamp.tm_mday = atoi(digits);
+    strncpy(digits, p+2, 2);
+    stamp.tm_mon = atoi(digits)-1;
+    strncpy(digits, p+4, 2);
+    stamp.tm_year = atoi(digits)+100;
+
+    m_stamp = mktime(&stamp);
+    m_valid = !strcmp(Field(sentence, 2), "A");
+    m_fix.SetLatitude(Coord(sentence, 3));
+    m_fix.SetLongitude(Coord(sentence, 5));
+    sscanf(Field(sentence, 7), "%f", &m_speed);
+    sscanf(Field(sentence, 8), "%f", &m_heading);
+    sscanf(Field(sentence, 10), "%f", &m_magnetic);
+    if (!strcmp(Field(sentence, 11), "W"))
+        m_magnetic = -m_magnetic;
+    m_mode = *Field(sentence, 12);
+}
+
+void GPRMC::AsString(char *buf)
+{
+    sprintf(buf, "%s %lf %lf %f %f %f, %s",
+            ctime(&m_stamp),
+            m_fix.Latitude(),
+            m_fix.Longitude(),
+            m_speed, m_heading, m_magnetic,
+            m_valid ? "valid" : "invalid");
+}

Copied: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/gps.h 
(from rev 3254, 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/gps.h)
===================================================================
--- gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/gps.h  
                        (rev 0)
+++ gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/gps.h  
2006-08-12 18:20:45 UTC (rev 3256)
@@ -0,0 +1,119 @@
+/*
+ Copyright 2006 Johnathan Corgan.
+ 
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+ 
+ This software 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 GNU Radio; see the file COPYING.  If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef __GPS_H__
+#define __GPS_H__
+
+// Autoconf generated configure options
+#if HAVE_CONFIG_H
+    #include "config.h"
+#endif
+
+// Application level includes
+#include "spherical.h"
+
+// wxWidgets includes
+#include <wx/event.h>
+
+// System level includes
+#include <math.h>  // For some reason, <cmath> doesn't include modf needed in 
gps.cpp
+
+class GPRMC;
+
+class GPSUpdate : public wxNotifyEvent
+{
+public:
+    GPSUpdate(const wxEventType &event, GPRMC *gprmc);
+    virtual wxEvent *Clone() const { return new GPSUpdate(*this); }
+    GPRMC *m_gprmc;
+};
+
+extern const wxEventType wxEVT_GPS_UPDATE;
+
+typedef void(wxEvtHandler::*GPSUpdateFunction)(GPSUpdate&);
+
+#define EVT_GPS_UPDATE(fn) \
+        DECLARE_EVENT_TABLE_ENTRY( \
+            wxEVT_GPS_UPDATE, -1, -1, \
+            (wxObjectEventFunction)(wxEventFunction)(GPSUpdateFunction)&fn, \
+            (wxObject *)NULL \
+        ),
+
+class NMEA
+{
+public:
+    static bool Checksum(char *sentence);
+    static char *Field(char *sentence, int num);
+    static double Coord(char *sentence, int num);
+};
+
+class GPRMC : public NMEA
+{
+public:
+    GPRMC(char *sentence);
+    void AsString(char *buf);
+        
+    time_t m_stamp;
+    bool   m_valid;
+    Spherical m_fix;
+    float m_speed;
+    float m_heading;
+    float m_magnetic;
+    unsigned char m_mode;
+};
+
+class GPS;
+class SerialPort;
+
+class GPSBackground : public wxThread
+{
+public:
+    GPSBackground(GPS *gps);
+    virtual ExitCode Entry();
+    bool IsRunning() { return m_running; }
+
+private:
+    void PerLoop();
+
+    bool m_running;
+    GPS *m_gps;
+    SerialPort *m_port;
+};
+
+class wxString;
+
+class GPS
+{
+public:
+    GPS(wxEvtHandler *dest);
+    ~GPS();
+    
+    bool Start(wxString &port);
+    bool Stop();
+    SerialPort *GetPort() { return m_port; }
+    void RxData(char *buffer);
+    
+private:
+    void RxGPRMC(char *buffer);
+
+    GPSBackground *m_thread;
+    wxEvtHandler *m_dest;
+    SerialPort *m_port;
+};
+
+#endif // __GPS_H__

Copied: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/histogram.cc
 (from rev 3254, 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/histogram.cpp)
===================================================================
--- 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/histogram.cc
                           (rev 0)
+++ 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/histogram.cc
   2006-08-12 18:20:45 UTC (rev 3256)
@@ -0,0 +1,170 @@
+/*
+ Copyright 2006 Johnathan Corgan.
+ 
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+ 
+ This software 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 GNU Radio; see the file COPYING.  If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+// Application level includes
+#include "histogram.h"
+
+// wxWidgets includes
+#include <wx/log.h>
+#include <wx/dc.h>
+#include <wx/dcclient.h>
+
+using namespace std;
+
+ErrorHistogram::ErrorHistogram()
+{
+    Reset();
+}
+
+void ErrorHistogram::Reset()
+{
+    m_bins = vector<float>(360);
+    m_mode = 0;
+    m_modal_frequency = 0.0;
+    m_isum = 0.0;
+    m_qsum = 0.0;
+    m_msum = 0.0;
+    m_conc = 0.0;
+    m_mean = 0.0;
+    m_count = 0;
+}
+
+void ErrorHistogram::Calc(const vector<Sample> &samples, const Spherical 
&location)
+{
+    Reset();    
+    for (int i = 0; i < samples.size(); i++) {
+        const Sample &sample = samples[i];
+        float angle, ierror, qerror;
+        sample.CalcError(location, angle, ierror, qerror); 
+        Add(angle, sample.Strength(), ierror, qerror);
+    }
+    Normalize();
+}
+
+void ErrorHistogram::Add(float angle, float magnitude, float ierror, float 
qerror)
+{
+    int index = (int)(angle+180.0);
+    while (index > 359)
+        index -= 360;
+    while (index < 0)
+        index += 360;
+    wxASSERT(index >= 0 && index < 360);
+    
+    float freq = m_bins[index] += magnitude;
+    if (freq > m_modal_frequency) {
+        m_modal_frequency = freq;
+        m_mode = index-180;
+    }
+    
+    m_isum += ierror;
+    m_qsum += qerror;
+    m_msum += magnitude;
+    m_count++;
+}
+
+// This turns the histogram into an actual PDF
+void ErrorHistogram::Normalize()
+{
+    if (m_msum == 0.0)
+        return;
+        
+    for (int i = 0; i < 360; i++)
+        m_bins[i] = m_bins[i]/(m_msum);
+
+    m_modal_frequency /= m_msum;
+    m_conc = (m_isum*m_isum+m_qsum*m_qsum)/(m_msum*m_msum);
+    if (m_conc > 0.0)
+        m_mean = atan2(m_qsum, m_isum)*180.0/M_PI;
+}
+
+// Event table for HistogramPanel
+BEGIN_EVENT_TABLE(HistogramPanel, wxPanel)
+    EVT_PAINT(HistogramPanel::OnPaint)
+    EVT_SIZE(HistogramPanel::OnSize)
+END_EVENT_TABLE()
+
+HistogramPanel::HistogramPanel(wxWindow *parent) :
+wxPanel(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize)
+{
+       SetBackgroundColour(*wxBLACK);
+    m_mode = Rectangular;
+}
+
+void HistogramPanel::SetData(const ErrorHistogram &histogram)
+{
+    m_histogram = histogram; // Copy constructor invoked
+    Refresh();
+}
+
+void HistogramPanel::OnPaint(wxPaintEvent &event)
+{
+    wxPaintDC dc(this);
+       draw_panel(dc);
+}
+
+void HistogramPanel::draw_panel(wxDC &dc)
+{
+    const vector<float> &data = m_histogram.Data();            
+    if (m_histogram.Count() == 0)
+        return;
+    
+    if (m_mode == Polar) {
+        // Draw histogram bars
+       dc.SetPen(wxPen(*wxRED, 1, wxSOLID));
+        for (int i = 0; i < 360; i++) {
+            float len = 
data[i]*(m_extent*0.75-10)/m_histogram.ModalFrequency();
+               float radians = i*M_PI/180.0;
+            wxPoint tip = wxPoint((int)(m_center.x-sin(radians)*len),
+                             (int)(m_center.y+cos(radians)*len));
+    
+            dc.DrawLine(m_center, tip);
+        }
+    }
+    else if (m_mode == Rectangular) {
+        // Draw zero tick
+        dc.SetPen(wxPen(*wxWHITE, 1, wxSOLID));
+        dc.DrawLine(m_center.x, 0, m_center.x, 10);
+
+        // Draw mode tick
+        dc.SetPen(wxPen(*wxGREEN, 1, wxSOLID));
+        int mode = (int)((m_histogram.Mode()+180)/360.0*m_width);
+        dc.DrawLine(mode, 0, mode, 9);
+
+        // Draw histogram bars
+        dc.SetPen(wxPen(*wxRED, 1, wxSOLID));
+        float freq = m_histogram.ModalFrequency();
+        for (int i = 0; i < 360; i++) {
+            int len = (int)(data[i]/freq*(m_height-10));
+            int pos = (int)(i/360.0*m_width);
+            dc.DrawLine(pos, m_height, pos, m_height-len);
+        }
+    }
+}
+
+void HistogramPanel::OnSize(wxSizeEvent &event)
+{
+    GetClientSize(&m_width, &m_height);
+    m_center = wxPoint(m_width/2, (int)(m_height*0.75));
+
+    if (m_width > m_height)
+        m_extent = m_height;
+    else
+        m_extent = m_width;
+        
+    Refresh();
+}

Copied: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/histogram.h
 (from rev 3254, 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/histogram.h)
===================================================================
--- 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/histogram.h
                            (rev 0)
+++ 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/histogram.h
    2006-08-12 18:20:45 UTC (rev 3256)
@@ -0,0 +1,89 @@
+/*
+ Copyright 2006 Johnathan Corgan.
+ 
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+ 
+ This software 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 GNU Radio; see the file COPYING.  If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef __HISTOGRAM_H__
+#define __HISTOGRAM_H__
+
+// Application level includes
+#include "sample.h"
+
+// wxWidgets includes
+#include <wx/panel.h>
+
+// System level includes
+#include <vector>
+
+class ErrorHistogram
+{
+public:
+    ErrorHistogram();
+
+    void Reset();
+    void Calc(const std::vector<Sample> &samples, const Spherical &location);
+    void Add(float angle, float magnitude, float ierror, float qerror); // 
analytic errors are -pi to pi
+    void Normalize();
+
+    int   Count()                    const { return m_count; }    
+    int   Mode()                     const { return m_mode; }
+    float ModalFrequency()           const { return m_modal_frequency; }
+    float Mean()                     const { return m_mean; }
+    float Concentration()            const { return m_conc; }
+    const std::vector<float> &Data() const { return m_bins; }
+        
+private:
+    int   m_mode;
+    float m_modal_frequency;
+    float m_isum;
+    float m_qsum;
+    float m_msum;
+    float m_conc;
+    float m_mean;
+    int   m_count;
+    std::vector<float> m_bins;
+};
+
+class HistogramPanel : public wxPanel
+{
+public:
+    enum Mode { Rectangular, Polar };
+
+    HistogramPanel(wxWindow *parent);
+    void SetData(const ErrorHistogram &histogram);
+    void SetMode(Mode mode) { m_mode = mode; Refresh(); }
+        
+    // Event handlers
+    void OnPaint(wxPaintEvent &event);
+    void OnSize(wxSizeEvent &event);
+                
+private:
+    void draw_panel(wxDC &dc);
+    ErrorHistogram m_histogram;
+
+    // State
+    Mode m_mode;
+
+    // Window size derived parameters
+    wxPoint m_center;
+    int m_width;
+    int m_height;
+    int m_extent;
+    
+    DECLARE_EVENT_TABLE();
+};
+
+#endif

Copied: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/hunter.bmp 
(from rev 3254, 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/hunter.bmp)
===================================================================
(Binary files differ)

Copied: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/hunter.cc 
(from rev 3254, 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/hunter.cpp)
===================================================================
--- 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/hunter.cc  
                            (rev 0)
+++ 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/hunter.cc  
    2006-08-12 18:20:45 UTC (rev 3256)
@@ -0,0 +1,1269 @@
+/*
+ Copyright 2006 Johnathan Corgan.
+ 
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+ 
+ This software 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 GNU Radio; see the file COPYING.  If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+// Application includes
+#include "hunter.h"
+#include "hunter.xpm"
+#include "doppler.h"
+#include "tactical.h"
+#include "calibrate.h"
+#include "settings.h"
+#include "gps.h"
+#include "serial.h"
+#include "search.h"
+#include "util.h"
+#include "spherical.h"
+#include "sample.h"
+#include "samplelog.h"
+#include "known.h"
+#include "histogram.h"
+
+// wxWidgets includes
+#include <wx/xrc/xmlres.h>
+#include <wx/wx.h>          // Too many to do individually
+#include <wx/file.h>        // hmmm, fails compile on mingw32 without it
+
+// Event table for HunterFrame
+BEGIN_EVENT_TABLE(HunterFrame, wxFrame)
+    // Application level events
+       EVT_CLOSE(HunterFrame::OnClose)
+    
+    // File menu events
+    EVT_MENU(XRCID("file_new_menuitem"), HunterFrame::OnFileNew)
+    EVT_MENU(XRCID("file_open_menuitem"), HunterFrame::OnFileOpen)
+    EVT_MENU(XRCID("file_close_menuitem"), HunterFrame::OnFileClose)
+    EVT_MENU(XRCID("file_save_menuitem"), HunterFrame::OnFileSave)
+       EVT_MENU(XRCID("file_exit_menuitem"), HunterFrame::OnExit)
+
+    // Doppler menu events
+    EVT_MENU(XRCID("doppler_toggle_menuitem"), HunterFrame::OnDopplerToggle)
+    EVT_MENU(XRCID("doppler_autostart_menuitem"), 
HunterFrame::OnDopplerAutostart)
+    EVT_MENU(XRCID("doppler_reset_menuitem"), HunterFrame::OnDopplerReset)
+
+    // Calibration menu events
+    EVT_MENU(XRCID("calibration_savetofile_menuitem"), 
HunterFrame::OnCalibrationSaveToFile)
+    EVT_MENU(XRCID("calibration_loadfromfile_menuitem"), 
HunterFrame::OnCalibrationLoadFromFile)
+    EVT_MENU(XRCID("calibration_loadtransmitter_menuitem"), 
HunterFrame::OnCalibrationLoadTransmitter)
+    EVT_MENU(XRCID("calibration_savetransmitter_menuitem"), 
HunterFrame::OnCalibrationSaveTransmitter)
+
+    // About menu events
+       EVT_MENU(XRCID("about_menuitem"), HunterFrame::OnAbout)
+
+    // Status panel events
+    EVT_RADIOBOX(XRCID("statistics_source_radiobox"), 
HunterFrame::OnHistogramSourceChg)
+    EVT_RADIOBOX(XRCID("statistics_coords_radiobox"), 
HunterFrame::OnHistogramCoordsChg)
+
+    // Doppler tab events
+       EVT_BUTTON(XRCID("doppler_toggle_button"), HunterFrame::OnDopplerToggle)
+       EVT_CHECKBOX(XRCID("doppler_autostart_checkbox"), 
HunterFrame::OnDopplerAutostart)
+       EVT_BUTTON(XRCID("doppler_reset_button"), HunterFrame::OnDopplerReset)
+       EVT_COMMAND_SCROLL(XRCID("doppler_filter_slider"), 
HunterFrame::OnDopplerFilterChg)
+       EVT_RADIOBOX(XRCID("doppler_rotation_radiobox"), 
HunterFrame::OnDopplerRotationChg)
+       EVT_DOPPLER_UPDATE(HunterFrame::OnDopplerUpdate)
+
+    // GPS tab events
+    EVT_BUTTON(XRCID("gps_toggle_button"), HunterFrame::OnGPSToggle)
+       EVT_CHECKBOX(XRCID("gps_autostart_checkbox"), 
HunterFrame::OnGPSAutostart)
+    EVT_COMBOBOX(XRCID("gps_device_combobox"), HunterFrame::OnGPSDeviceSelect)
+    EVT_TEXT_ENTER(XRCID("gps_device_combobox"), 
HunterFrame::OnGPSDeviceSelect)
+       EVT_GPS_UPDATE(HunterFrame::OnGPSUpdate)
+
+    // Calibration tab events
+       EVT_BUTTON(XRCID("calibration_equalize_button"), 
HunterFrame::OnCalibrationEqualize)
+    EVT_BUTTON(XRCID("calibration_zero_button"), 
HunterFrame::OnCalibrationZero)
+    EVT_SPIN_UP(XRCID("calibration_adjust_spinner"), 
HunterFrame::OnCalibrationAdjustRight)
+    EVT_SPIN_DOWN(XRCID("calibration_adjust_spinner"), 
HunterFrame::OnCalibrationAdjustLeft)
+       EVT_CHECKBOX(XRCID("calibration_all_checkbox"), 
HunterFrame::OnCalibrationAffectAllRates)
+    EVT_BUTTON(XRCID("known_transmitter_update_button"), 
HunterFrame::OnKnownTransmitterUpdate)
+    EVT_CHECKBOX(XRCID("known_transmitter_checkbox"), 
HunterFrame::OnUseKnownTransmitter)
+
+    // Search tab events
+    EVT_BUTTON(XRCID("search_newsave_button"), HunterFrame::OnSearchNewSave)
+    EVT_BUTTON(XRCID("search_openclose_button"), 
HunterFrame::OnSearchOpenClose)
+    EVT_BUTTON(XRCID("search_toggle_button"), HunterFrame::OnSearchToggle)
+    EVT_BUTTON(XRCID("search_once_button"), HunterFrame::OnSearchOnce)
+    EVT_SEARCH_UPDATE(HunterFrame::OnSearchUpdate)
+    
+    // Display tab events
+       EVT_RADIOBOX(XRCID("display_orientation_radiobox"), 
HunterFrame::OnDisplayOrientation)
+    EVT_CHECKBOX(XRCID("display_doppler_checkbox"), 
HunterFrame::OnDisplayDoppler)
+    EVT_CHECKBOX(XRCID("display_known_checkbox"), HunterFrame::OnDisplayKnown)
+    EVT_CHECKBOX(XRCID("display_estimated_checkbox"), 
HunterFrame::OnDisplayEstimated)
+
+END_EVENT_TABLE()
+
+HunterFrame::HunterFrame() :
+wxFrame(),
+m_search(this)
+{
+    m_settings = NULL;
+    m_doppler = NULL;
+    m_gps = NULL;
+    m_log = NULL;
+    m_tactical_panel = NULL;
+    m_error_histogram_panel = NULL;
+        
+    m_doppler_started = false;
+    m_gps_started = false;
+    m_capture = false;
+    m_one_shot = false;
+    m_histogram_source = 0;
+            
+    InitializeSettings();
+       InitializeWindows();
+       InitializeDoppler();
+    InitializeGPS();
+    InitializeCalibration();
+    InitializeSearch();
+    InitializeDisplay();
+}
+       
+void HunterFrame::InitializeSettings()
+{
+    m_settings = new HunterSettings();
+    wxSetWorkingDirectory(m_settings->GetWorkingDirectory());
+}
+
+void HunterFrame::InitializeWindows()
+{
+       // Build main window controls
+       bool loaded = wxXmlResource::Get()->LoadFrame(this, NULL, 
wxT("main_frame"));
+       wxASSERT(loaded);
+
+       // Hack until XRC understands <gravity> for wxSplitterWindow!!
+       XRCCTRL(*this, "horiz_splitter", wxSplitterWindow)->SetSashGravity(1.0);
+
+    // Increase font size for better visibility in certain text displays
+    wxFont font = XRCCTRL(*this, "doppler_relative_bearing_text", 
wxStaticText)->GetFont();
+    float points = font.GetPointSize()*2.0;
+    font.SetPointSize((int)points);
+    XRCCTRL(*this, "doppler_relative_bearing_text", 
wxStaticText)->SetFont(font);
+    XRCCTRL(*this, "doppler_absolute_bearing_text", 
wxStaticText)->SetFont(font);
+    XRCCTRL(*this, "transmitter_estimated_bearing_text", 
wxStaticText)->SetFont(font);
+    XRCCTRL(*this, "transmitter_estimated_range_text", 
wxStaticText)->SetFont(font);
+    XRCCTRL(*this, "transmitter_actual_bearing_text", 
wxStaticText)->SetFont(font);
+    XRCCTRL(*this, "transmitter_actual_range_text", 
wxStaticText)->SetFont(font);
+    points *= 0.75;
+    font.SetPointSize((int)points);
+    XRCCTRL(*this, "gps_latitude_text", wxStaticText)->SetFont(font);
+    XRCCTRL(*this, "gps_longitude_text", wxStaticText)->SetFont(font);
+    XRCCTRL(*this, "gps_heading_text", wxStaticText)->SetFont(font);
+    XRCCTRL(*this, "gps_speed_text", wxStaticText)->SetFont(font);
+    XRCCTRL(*this, "search_latitude_text", wxStaticText)->SetFont(font);
+    XRCCTRL(*this, "search_longitude_text", wxStaticText)->SetFont(font);
+    XRCCTRL(*this, "search_count_text", wxStaticText)->SetFont(font);
+    XRCCTRL(*this, "search_status_text", wxStaticText)->SetFont(font);
+    XRCCTRL(*this, "search_mode_text", wxStaticText)->SetFont(font);
+    XRCCTRL(*this, "search_mean_text", wxStaticText)->SetFont(font);
+    XRCCTRL(*this, "search_score_text", wxStaticText)->SetFont(font);
+    XRCCTRL(*this, "search_disterror_text", wxStaticText)->SetFont(font);
+    XRCCTRL(*this, "error_count_text", wxStaticText)->SetFont(font);
+    XRCCTRL(*this, "error_mode_text", wxStaticText)->SetFont(font);
+    XRCCTRL(*this, "error_mean_text", wxStaticText)->SetFont(font);
+    XRCCTRL(*this, "error_conc_text", wxStaticText)->SetFont(font);
+
+    // Create the menu 
+       SetMenuBar(wxXmlResource::Get()->LoadMenuBar(wxT("main_menu")));
+       CreateStatusBar(1);
+       SetIcon(wxIcon(hunter_xpm));
+
+    // Restore saved window size and position
+    int x = m_settings->GetWindowXPos();
+    int y = m_settings->GetWindowYPos();
+    wxSize size = m_settings->GetWindowSize();
+    int hsplitpos = size.GetHeight()-170;   // HACK!
+    SetSize(x, y, size.GetWidth(), size.GetHeight());
+       XRCCTRL(*this, "horiz_splitter", 
wxSplitterWindow)->SetSashPosition(hsplitpos);
+
+    // Error histogram is a custom control outside XRC system
+    m_error_histogram_panel = new HistogramPanel(this);
+       
wxXmlResource::Get()->AttachUnknownControl(wxT("error_histogram_panel"), 
+                                                      m_error_histogram_panel, 
this);
+}
+
+void HunterFrame::InitializeDoppler()
+{
+       m_doppler = new EZDoppler(this);
+       m_doppler->Initialize();
+       m_doppler_started = false;
+    SetDopplerParams();
+}
+
+void HunterFrame::InitializeGPS()
+{
+    m_gps = new GPS(this);
+       m_gps_started = false;
+
+    // Populate device selection combobox
+    XRCCTRL(*this, "gps_device_combobox", wxComboBox)->Clear();
+       wxArrayString ports = EnumerateSerialPorts();
+    for (int i = 0; i < ports.GetCount(); i++)
+        XRCCTRL(*this, "gps_device_combobox", wxComboBox)->Append(ports[i]);
+    XRCCTRL(*this, "gps_device_combobox", 
wxComboBox)->SetValue(m_settings->GetGPSDeviceName());
+    
+    // GPS autostart
+    if (m_settings->GetGPSAutostart()) {
+       XRCCTRL(*this, "gps_autostart_checkbox", wxCheckBox)->SetValue(true);
+       StartGPS();            
+    }
+}
+
+void HunterFrame::InitializeCalibration()
+{
+    XRCCTRL(*this, "calibration_all_checkbox", 
wxCheckBox)->SetValue(m_settings->GetCalibrationAffectAllRates());
+
+    if (m_settings->GetUseKnownTransmitter()) {
+        m_known.Location(Spherical(m_settings->GetKnownTransmitterLatitude(),
+                                   
m_settings->GetKnownTransmitterLongitude()));
+        XRCCTRL(*this, "known_transmitter_checkbox", 
wxCheckBox)->SetValue(true);
+    }
+
+    UpdateKnownLocation();
+}
+
+void HunterFrame::InitializeDisplay()
+{
+    // Tactical display is a custom control outside XRC system
+       m_tactical_panel = new TacticalPanel(this);
+       wxXmlResource::Get()->AttachUnknownControl(wxT("tactical_panel"), 
+                                                      m_tactical_panel, this);
+
+    if (m_settings->GetDisplayOrientation()) {
+        XRCCTRL(*this, "display_orientation_radiobox", 
wxRadioBox)->SetSelection(1);
+        m_tactical_panel->SetOrientation(NorthUp);
+    }
+
+    if (m_settings->GetDisplayDoppler()) {
+        XRCCTRL(*this, "display_doppler_checkbox", wxCheckBox)->SetValue(true);
+        m_tactical_panel->SetDisplayDoppler(true);
+    }
+
+    if (m_settings->GetDisplayKnown()) {
+        XRCCTRL(*this, "display_known_checkbox", wxCheckBox)->SetValue(true);
+        m_tactical_panel->SetDisplayKnown(true);
+    }
+
+    if (m_settings->GetDisplayEstimated()) {
+        XRCCTRL(*this, "display_estimated_checkbox", 
wxCheckBox)->SetValue(true);
+        m_tactical_panel->SetDisplayEstimated(true);
+    }
+}
+
+void HunterFrame::InitializeSearch()
+{
+    EnableSearchItems(false);
+}
+
+void HunterFrame::SetDopplerParams()
+{
+    // NOTE: This is not in InitializeDoppler() as it needs to be called 
+    // separately when resetting Doppler
+
+       // Adjust windows based on device status
+       if (!m_doppler->IsOnline()) { 
+           // Disable all GUI elements associated with Doppler
+        
+        // Doppler control tab
+           XRCCTRL(*this, "doppler_control_panel", wxPanel)->Disable();
+
+        // Doppler menu items
+        
this->GetMenuBar()->FindItem(XRCID("doppler_toggle_menuitem"))->Enable(false);
+        
this->GetMenuBar()->FindItem(XRCID("doppler_autostart_menuitem"))->Enable(false);
+        
this->GetMenuBar()->FindItem(XRCID("doppler_reset_menuitem"))->Enable(false);
+
+        // Calibration control tab
+        XRCCTRL(*this, "calibration_equalize_button", wxButton)->Enable(false);
+        XRCCTRL(*this, "calibration_zero_button", wxButton)->Enable(false);
+        XRCCTRL(*this, "calibration_adjust_spinner", 
wxSpinButton)->Enable(false);
+
+        return;
+       }
+
+    // Doppler filter level
+    int filter = m_settings->GetDopplerFilter();
+    XRCCTRL(*this, "doppler_filter_slider", wxSlider)->SetValue(filter);
+    wxScrollEvent dummy;
+    OnDopplerFilterChg(dummy);
+
+    // Doppler rotation rate
+    int rate = m_settings->GetDopplerRotation();
+    XRCCTRL(*this, "doppler_rotation_radiobox", 
wxRadioBox)->SetSelection(rate);
+    wxCommandEvent dummy2;
+    OnDopplerRotationChg(dummy2);
+
+    // Doppler calibration values
+    for (int i=0; i < 7; i++) {  // i==6 gets zero offset
+        float offset = m_settings->GetDopplerCalibration(i);
+        m_doppler->SetCalibration(i, offset);
+    }
+
+    // Doppler autostart
+    if (m_settings->GetDopplerAutostart()) {
+        
this->GetMenuBar()->FindItem(XRCID("doppler_autostart_menuitem"))->Check(true);
+        XRCCTRL(*this, "doppler_autostart_checkbox", 
wxCheckBox)->SetValue(true);
+        StartDoppler();            
+    }
+}
+
+void HunterFrame::StartDoppler()
+{
+       m_doppler->Start();
+       m_doppler_started = true;
+       XRCCTRL(*this, "doppler_toggle_button", wxButton)->SetLabel(_T("Stop"));
+    XRCCTRL(*this, "calibration_equalize_button", wxButton)->Enable();
+    XRCCTRL(*this, "calibration_zero_button", wxButton)->Enable();
+    XRCCTRL(*this, "calibration_adjust_spinner", wxSpinButton)->Enable();
+    
this->GetMenuBar()->FindItem(XRCID("doppler_toggle_menuitem"))->SetText(_T("&Stop"));
+    
this->GetMenuBar()->FindItem(XRCID("doppler_reset_menuitem"))->Enable(true);
+}
+
+void HunterFrame::StopDoppler()
+{
+       m_doppler->Stop();
+       m_doppler_started = false;
+    UpdateDopplerStatus(false);
+       XRCCTRL(*this, "doppler_toggle_button", 
wxButton)->SetLabel(_T("Start"));
+    
this->GetMenuBar()->FindItem(XRCID("doppler_toggle_menuitem"))->SetText(_("&Start"));
+    
this->GetMenuBar()->FindItem(XRCID("doppler_reset_menuitem"))->Enable(false);
+    XRCCTRL(*this, "calibration_equalize_button", wxButton)->Disable();
+    XRCCTRL(*this, "calibration_zero_button", wxButton)->Disable();
+    XRCCTRL(*this, "calibration_adjust_spinner", wxSpinButton)->Disable();
+}
+
+void HunterFrame::StartGPS()
+{
+    wxString port = XRCCTRL(*this, "gps_device_combobox", 
wxComboBox)->GetValue();
+    if (!m_gps->Start(port)) {
+        wxMessageDialog(this, wxT("Failed to start GPS!"), wxT("GPS Error"),
+                        wxOK|wxICON_ERROR).ShowModal();
+        return;
+    }    
+    
+    m_gps_started = true;
+    XRCCTRL(*this, "gps_toggle_button", wxButton)->SetLabel(_T("Stop"));
+    XRCCTRL(*this, "gps_device_combobox", wxComboBox)->Disable();
+    XRCCTRL(*this, "display_orientation_radiobox", wxRadioBox)->Enable();
+    if (XRCCTRL(*this, "display_orientation_radiobox", 
wxRadioBox)->GetSelection() == 1) {
+        m_tactical_panel->SetOrientation(NorthUp);
+    }
+
+    if (m_search.HasSolution())
+        UpdateSearchDirection(true);
+
+    UpdateKnownDirection();
+    UpdateKnownStatistics();
+}
+
+void HunterFrame::StopGPS()
+{
+    m_gps->Stop();
+    m_gps_started = false;
+    m_tactical_panel->SetOrientation(TrackUp);
+    m_tactical_panel->SetActualBearing(-1.0);
+    m_tactical_panel->SetEstimatedBearing(-1.0);
+       XRCCTRL(*this, "gps_toggle_button", wxButton)->SetLabel(_T("Start"));
+    XRCCTRL(*this, "gps_device_combobox", wxComboBox)->Enable();
+    XRCCTRL(*this, "display_orientation_radiobox", wxRadioBox)->Disable();
+
+    UpdateGPSStatus(false);
+    UpdateSearchDirection(false);
+    UpdateKnownDirection();
+    UpdateKnownStatistics();
+        
+    // Note: can't replace with call to UpdateDopplerStatus as we only want to 
clear one field
+    XRCCTRL(*this, "doppler_absolute_bearing_text", 
wxStaticText)->SetLabel(_T(""));
+}
+
+void HunterFrame::EnableSearchItems(bool enable)
+{
+       XRCCTRL(*this, "search_toggle_button", wxButton)->Enable(enable);
+       XRCCTRL(*this, "search_once_button", wxButton)->Enable(enable);
+
+    // These fields will get populated when samples come in
+    UpdateSearchStatus(false);
+    UpdateSearchLocation(false);
+    UpdateSearchDirection(false);    
+
+    this->GetMenuBar()->FindItem(XRCID("file_save_menuitem"))->Enable(enable);
+    this->GetMenuBar()->FindItem(XRCID("file_close_menuitem"))->Enable(enable);
+
+    if (!enable) {
+        XRCCTRL(*this, "search_toggle_button", wxButton)->SetLabel(_T("Stop"));
+        XRCCTRL(*this, "search_toggle_button", 
wxButton)->SetLabel(_T("Automatic"));
+    }
+}
+
+void HunterFrame::OnClose(wxCloseEvent &event)
+{
+    wxCommandEvent dummy;
+        
+    // Cleanup for this scope should be done here
+    // TODO: factor out into methods corresponding to start up initialization
+
+    // Save window size and position
+    int x, y;
+    GetPosition(&x, &y);
+    m_settings->SetWindowXPos(x);
+    m_settings->SetWindowYPos(y);
+    m_settings->SetWindowSize(GetSize());
+
+    wxASSERT(m_doppler != NULL);
+    if (m_doppler_started)
+        StopDoppler();
+    m_doppler->Finalize();
+    if (m_gps_started)
+        StopGPS();
+
+    if (m_log)
+        OnFileClose(dummy);
+
+        
+    m_settings->SetWorkingDirectory(wxGetCwd());
+
+    delete m_doppler;
+    delete m_gps;
+    delete m_settings;
+    if (m_log)
+        delete m_log;        
+
+    // Last thing to do
+       Destroy();
+}
+
+void HunterFrame::OnExit(wxCommandEvent &event)
+{
+       // Cleanup for this scope should be done in ::OnClose, not here.  This
+       // method is not called when exiting from the system menu, but rather it
+       // goes straight to ::OnClose
+
+       // Sends close event
+       this->Close();
+}
+
+void HunterFrame::OnAbout(wxCommandEvent &event)
+{
+       wxMessageBox(wxT("Copyright(C) 2005 Johnathan Corgan"), 
+                    wxT("About AE6HO Radio Location System"), 
+                    wxOK | wxICON_INFORMATION, this);
+}
+
+void HunterFrame::OnDopplerToggle(wxCommandEvent &event)
+{
+       if (m_doppler_started)
+           StopDoppler();
+       else
+           StartDoppler();
+}
+
+void HunterFrame::OnDopplerAutostart(wxCommandEvent &event)
+{
+    bool autostart = event.IsChecked();
+    
this->GetMenuBar()->FindItem(XRCID("doppler_autostart_menuitem"))->Check(autostart);
+    XRCCTRL(*this, "doppler_autostart_checkbox", 
wxCheckBox)->SetValue(autostart);
+    m_settings->SetDopplerAutostart(autostart);
+}
+
+void HunterFrame::OnDopplerReset(wxCommandEvent &event)
+{
+       StopDoppler();
+       m_doppler->Reset();
+    SetDopplerParams();  // restarts Doppler if autostart is configured
+}
+
+void HunterFrame::OnDopplerFilterChg(wxScrollEvent &event)
+{
+       int n = XRCCTRL(*this, "doppler_filter_slider", wxSlider)->GetValue();
+       m_doppler->SetFilter(n);
+    m_settings->SetDopplerFilter(n);
+}
+
+void HunterFrame::OnDopplerRotationChg(wxCommandEvent &event)
+{
+       int n = XRCCTRL(*this, "doppler_rotation_radiobox", 
wxRadioBox)->GetSelection();
+       m_doppler->SelectRotationRate(n);
+    m_settings->SetDopplerRotation(n);
+}
+
+void HunterFrame::OnDopplerUpdate(EZDopplerUpdate &event)
+{
+    if (!m_doppler_started) // Spurious event after doppler stopped
+        return;
+        
+    // Update current state variables
+    m_sample.Volume(event.m_volume);
+    m_sample.InPhase(event.m_in_phase);
+    m_sample.Quadrature(event.m_quadrature);
+    m_sample.Strength(sqrt(event.m_in_phase*event.m_in_phase + 
+                           event.m_quadrature*event.m_quadrature));
+    m_sample.Phase(atan2(event.m_quadrature, event.m_in_phase));
+
+    UpdateDopplerStatus(true);
+
+    if (m_log && m_gps_started && m_capture &&
+        m_sample.Speed() >= 5.0 && m_sample.Valid()) {
+        m_log->Add(m_sample);
+        if (m_one_shot == true) {
+            StopCapture();
+            CalcSolution();
+            if (m_search.HasSolution()) {
+                UpdateSearchStatus(true);
+                UpdateSearchDirection(true);
+            }
+        }
+    }
+}
+
+void HunterFrame::UpdateDopplerStatus(bool display)
+{
+    wxString str;
+    if (!display) {
+        m_tactical_panel->SetDopplerBearing(-1.0);
+        XRCCTRL(*this, "doppler_level_gauge", wxGauge)->SetValue(0);
+        XRCCTRL(*this, "doppler_audio_gauge", wxGauge)->SetValue(0);
+        XRCCTRL(*this, "doppler_relative_bearing_text", 
wxStaticText)->SetLabel(_T(""));
+        XRCCTRL(*this, "doppler_absolute_bearing_text", 
wxStaticText)->SetLabel(_T(""));
+        return;
+    }
+
+    float display_relative_bearing = 
degree_normalize(to_degrees(m_sample.Phase()));
+    if (m_tactical_panel)
+        m_tactical_panel->SetDopplerBearing(display_relative_bearing);
+
+    int display_magnitude = (int)limit((m_sample.Strength()*200.0), 0.0, 
100.0);
+    XRCCTRL(*this, "doppler_level_gauge", 
wxGauge)->SetValue(display_magnitude);
+
+    int display_amplitude = (int)limit((m_sample.Volume()*100.0), 0.0, 100.0);
+    XRCCTRL(*this, "doppler_audio_gauge", 
wxGauge)->SetValue(display_amplitude);
+
+    str.Printf(_T("%03i"), 
degree_normalize((int)(display_relative_bearing+0.5))); // So zero is from -0.5 
to 0.5
+    XRCCTRL(*this, "doppler_relative_bearing_text", 
wxStaticText)->SetLabel(str);
+
+    if (m_gps_started) {
+        str.Printf(_T("%03i"), 
degree_normalize((int)(m_sample.Heading()+display_relative_bearing))); 
+        XRCCTRL(*this, "doppler_absolute_bearing_text", 
wxStaticText)->SetLabel(str);
+    }
+}
+
+void HunterFrame::CalcKnownStatistics()
+{
+    if (m_log)
+        m_known.Calc(m_log->Samples());
+
+    UpdateKnownStatistics();
+}   
+
+void HunterFrame::UpdateKnownStatistics()
+{
+    if (m_error_histogram_panel && m_histogram_source == 1)
+        m_error_histogram_panel->SetData(m_known.Histogram());
+    
+    if (!m_known.HasStats()) {
+        XRCCTRL(*this, "error_count_text", wxStaticText)->SetLabel(_T(""));
+        XRCCTRL(*this, "error_mode_text", wxStaticText)->SetLabel(_T(""));
+        XRCCTRL(*this, "error_mean_text", wxStaticText)->SetLabel(_T(""));
+        XRCCTRL(*this, "error_conc_text", wxStaticText)->SetLabel(_T(""));
+        return;
+    }
+    
+    wxString str;
+
+    str.Printf(_T("%i"), m_known.Count());
+    XRCCTRL(*this, "error_count_text", wxStaticText)->SetLabel(str);
+
+    str.Printf(_T("%i"), m_known.Mode());
+    XRCCTRL(*this, "error_mode_text", wxStaticText)->SetLabel(str);
+
+    str.Printf(_T("%5.1f"), m_known.Mean());
+    XRCCTRL(*this, "error_mean_text", wxStaticText)->SetLabel(str);
+
+    str.Printf(_T("%1.3f"), m_known.Concentration());
+    XRCCTRL(*this, "error_conc_text", wxStaticText)->SetLabel(str);
+}
+
+void HunterFrame::OnCalibrationEqualize(wxCommandEvent &event)
+{
+    CalibrationDialog *dlg = new CalibrationDialog(this);
+    dlg->ShowModal();
+}
+
+void HunterFrame::DoCalibrationStep(int which)
+{
+    static int delay;
+    
+    if (which == 0) {       // Set up doppler 
+        delay = XRCCTRL(*this, "doppler_filter_slider", 
wxSlider)->GetValue()/3; // Empirically determined
+        if (delay == 0)
+            delay = 1;
+    }
+
+    // Set rotation rate for this step
+    wxCommandEvent dummy;
+    XRCCTRL(*this, "doppler_rotation_radiobox", 
wxRadioBox)->SetSelection(which);
+    OnDopplerRotationChg(dummy);
+
+    // Wait until stable value
+    wxStartTimer();
+    while(wxGetElapsedTime(false) < 1000*delay)
+        wxYield(); // eeewwww!
+    
+    // Now stable reading can be calibrated
+    m_doppler->Calibrate(-M_PI);      // Sets to zero
+
+    float offset=m_doppler->GetCalibration(which);
+    m_settings->SetDopplerCalibration(which, offset);
+}
+
+void HunterFrame::OnCalibrationZero(wxCommandEvent &event)
+{
+    m_doppler->SetOffset();
+    float offset=m_doppler->GetCalibration(6);
+    m_settings->SetDopplerCalibration(6, offset);
+}
+
+void HunterFrame::OnCalibrationAdjustLeft(wxSpinEvent &event)
+{
+    if (m_settings->GetCalibrationAffectAllRates())
+        m_doppler->NudgeAll(to_radians(-0.5));
+    else
+        m_doppler->Nudge(to_radians(-0.5));
+
+    float offset=m_doppler->GetCalibration(6);
+    m_settings->SetDopplerCalibration(6, offset);
+}
+
+void HunterFrame::OnCalibrationAdjustRight(wxSpinEvent &event)
+{
+    if (m_settings->GetCalibrationAffectAllRates())
+        m_doppler->NudgeAll(to_radians(0.5));
+    else
+        m_doppler->Nudge(to_radians(0.5));
+
+    float offset=m_doppler->GetCalibration(6);
+    m_settings->SetDopplerCalibration(6, offset);
+}
+
+void HunterFrame::OnCalibrationAffectAllRates(wxCommandEvent &event)
+{
+    bool affect = event.IsChecked();
+    XRCCTRL(*this, "calibration_all_checkbox", wxCheckBox)->SetValue(affect);
+    m_settings->SetCalibrationAffectAllRates(affect);
+}
+
+void HunterFrame::OnGPSToggle(wxCommandEvent &event)
+{
+       if (m_gps_started)
+           StopGPS();
+       else
+           StartGPS();
+}
+
+void HunterFrame::OnGPSAutostart(wxCommandEvent &event)
+{
+    bool start = XRCCTRL(*this, "gps_autostart_checkbox", 
wxCheckBox)->GetValue();
+    m_settings->SetGPSAutostart(start);
+}
+
+void HunterFrame::OnGPSDeviceSelect(wxCommandEvent &event)
+{
+       wxString device = XRCCTRL(*this, "gps_device_combobox", 
wxComboBox)->GetValue();
+    m_settings->SetGPSDeviceName(device);
+}
+
+void HunterFrame::OnGPSUpdate(GPSUpdate &update)
+{
+    // Update state variables
+    GPRMC *gprmc = update.m_gprmc;
+    m_sample.Valid(update.m_gprmc->m_valid);
+    m_sample.Time(update.m_gprmc->m_stamp);
+    m_sample.Location(update.m_gprmc->m_fix);
+    m_sample.Heading(update.m_gprmc->m_heading);
+    m_sample.Speed(update.m_gprmc->m_speed*1.15077945); // Conversion from 
knots to mph
+    m_sample.Rate(XRCCTRL(*this, "doppler_rotation_radiobox", 
wxRadioBox)->GetSelection());
+    m_sample.Filtering(XRCCTRL(*this, "doppler_filter_slider", 
wxSlider)->GetValue());
+    
+    UpdateGPSValidity(update.m_gprmc->m_valid);                 // Colors red 
for invalid, black for valid
+    UpdateGPSStatus(true);                                      // gps lat, 
lon, heading, speed
+    UpdateKnownDirection();                                     // actual 
bearing and range
+
+    CalcKnownStatistics();
+    if (m_capture)
+        CalcSolution();
+    if (m_search.HasSolution())
+        UpdateSearchDirection(true);
+        
+    delete update.m_gprmc;
+}
+
+void HunterFrame::CalcSolution()
+{
+    GetStatusBar()->SetStatusText(wxT("Searching..."));    
+    m_search.Solve(m_log);
+}
+
+void HunterFrame::OnSearchUpdate(SearchUpdate &update)
+{
+    if (update.m_done)
+        GetStatusBar()->SetStatusText(wxT(""));    
+
+    if (m_search.HasSolution()) {
+        UpdateSearchStatus(true);
+        UpdateSearchLocation(true);
+        if (m_gps_started)
+           UpdateSearchDirection(true);
+    }
+}
+
+void HunterFrame::UpdateSearchStatus(bool display)
+{
+    wxString str;
+
+    if (m_error_histogram_panel && m_histogram_source == 0)
+        m_error_histogram_panel->SetData(m_search.Histogram());
+        
+    if (!display) {
+        XRCCTRL(*this, "search_count_text", wxStaticText)->SetLabel(_T(""));   
 
+        XRCCTRL(*this, "search_status_text", wxStaticText)->SetLabel(_T(""));  
  
+        XRCCTRL(*this, "search_mode_text", wxStaticText)->SetLabel(_T(""));    
+        XRCCTRL(*this, "search_mean_text", wxStaticText)->SetLabel(_T(""));    
+        XRCCTRL(*this, "search_score_text", wxStaticText)->SetLabel(_T(""));   
 
+        return;
+    }
+
+    str.Printf(_T("%i"), m_log->Count());
+    XRCCTRL(*this, "search_count_text", wxStaticText)->SetLabel(str);
+
+    str.Printf(_T("%s"), m_search.Busy() ? "BUSY" : "");
+    XRCCTRL(*this, "search_status_text", wxStaticText)->SetLabel(str);
+
+    str.Printf(_T("%i"), m_search.Mode());
+    XRCCTRL(*this, "search_mode_text", wxStaticText)->SetLabel(str);
+
+    str.Printf(_T("%6.1f"), m_search.Mean());
+    XRCCTRL(*this, "search_mean_text", wxStaticText)->SetLabel(str);
+
+    str.Printf(_T("%i"), (int)(m_search.Concentration()*100.0));
+    XRCCTRL(*this, "search_score_text", wxStaticText)->SetLabel(str);
+}
+
+void HunterFrame::UpdateGPSStatus(bool display)
+{            
+    wxString str;
+
+    if (!display) {
+        XRCCTRL(*this, "gps_latitude_text", wxStaticText)->SetLabel(_T(""));   
 
+        XRCCTRL(*this, "gps_longitude_text", wxStaticText)->SetLabel(_T(""));  
  
+        XRCCTRL(*this, "gps_heading_text", wxStaticText)->SetLabel(_T(""));    
+        XRCCTRL(*this, "gps_speed_text", wxStaticText)->SetLabel(_T(""));    
+        return;
+    }
+
+    // Calculate latitude to display
+    str.Printf(_T("%1.5lf"), fabs(m_sample.Latitude()));
+    str.Append(m_sample.Latitude() < 0.0 ? _T("S") : _T("N"));
+    XRCCTRL(*this, "gps_latitude_text", wxStaticText)->SetLabel(str);    
+
+    // Calculate longitude to display
+    str.Printf(_T("%1.5lf"), fabs(m_sample.Longitude()));
+    str.Append(m_sample.Longitude() < 0.0 ? _T("W") : _T("E"));
+    XRCCTRL(*this, "gps_longitude_text", wxStaticText)->SetLabel(str);    
+
+    // Calculate heading to display
+    m_tactical_panel->SetHeading(m_sample.Heading());
+    str.Printf(_T("%03i"), (unsigned int)(m_sample.Heading()));
+    XRCCTRL(*this, "gps_heading_text", wxStaticText)->SetLabel(str);    
+
+    // Calculate speed to display
+    str.Printf(_T("%i"), (unsigned int)(m_sample.Speed()));
+    XRCCTRL(*this, "gps_speed_text", wxStaticText)->SetLabel(str);    
+}    
+
+void HunterFrame::UpdateSearchDirection(bool display)
+{
+    wxString str;
+
+    if (!display) {
+        XRCCTRL(*this, "transmitter_estimated_bearing_text", 
wxStaticText)->SetLabel(_T(""));
+        XRCCTRL(*this, "transmitter_estimated_range_text", 
wxStaticText)->SetLabel(_T(""));
+        if (m_tactical_panel)
+            m_tactical_panel->SetEstimatedBearing(-1.0);
+        return;
+    }
+
+    float estimated_bearing = 
+        bearing(m_sample.Location(), m_search.GetEstimatedLocation());
+                
+    float estimated_range = 
+        range(m_sample.Location(), m_search.GetEstimatedLocation());
+    
+    m_tactical_panel->SetEstimatedBearing(estimated_bearing);
+    str.Printf(_T("%03i"), degree_normalize((int)estimated_bearing));
+    XRCCTRL(*this, "transmitter_estimated_bearing_text", 
wxStaticText)->SetLabel(str);
+    if (estimated_range > 99.9)
+        str.Printf(_T("%1.0f"), estimated_range);
+    else if (estimated_range > 9.99)
+        str.Printf(_T("%1.1f"), estimated_range);
+    else
+        str.Printf(_T("%1.2f"), estimated_range);
+    XRCCTRL(*this, "transmitter_estimated_range_text", 
wxStaticText)->SetLabel(str);
+}
+
+void HunterFrame::UpdateSearchLocation(bool display)
+{
+    wxString str;
+    
+    if (!display) {
+        XRCCTRL(*this, "search_latitude_text", 
wxStaticText)->SetLabel(_T(""));    
+        XRCCTRL(*this, "search_longitude_text", 
wxStaticText)->SetLabel(_T(""));    
+        XRCCTRL(*this, "search_disterror_text", 
wxStaticText)->SetLabel(_T(""));    
+        return;
+    }
+
+    Spherical estimated_location = m_search.GetEstimatedLocation();
+
+    // Calculate latitude to display
+    str.Printf(_T("%1.5f"), fabs(estimated_location.Latitude()));
+    str.Append(estimated_location.Latitude() < 0.0 ? _T("S") : _T("N"));
+    XRCCTRL(*this, "search_latitude_text", wxStaticText)->SetLabel(str);    
+
+    // Calculate longitude to display
+    str.Printf(_T("%1.5f"), fabs(estimated_location.Longitude()));
+    str.Append(estimated_location.Longitude() < 0.0 ? _T("W") : _T("E"));
+    XRCCTRL(*this, "search_longitude_text", wxStaticText)->SetLabel(str);    
+
+    if (m_known.IsSet()) {
+        float distance_error = range(m_search.GetEstimatedLocation(), 
m_known.Location());
+        if (distance_error > 99.9)
+            str.Printf(_T("%1.0f"), distance_error);
+        else if (distance_error > 9.99)
+            str.Printf(_T("%1.1f"), distance_error);
+        else
+            str.Printf(_T("%1.2f"), distance_error);
+        XRCCTRL(*this, "search_disterror_text", wxStaticText)->SetLabel(str);
+    }
+}
+
+void HunterFrame::UpdateKnownDirection()
+{
+    wxString str;
+
+    if (!m_known.IsSet() || !m_gps_started) {
+        XRCCTRL(*this, "transmitter_actual_bearing_text", 
wxStaticText)->SetLabel(_T(""));
+        XRCCTRL(*this, "transmitter_actual_range_text", 
wxStaticText)->SetLabel(_T(""));
+        if (m_tactical_panel)
+            m_tactical_panel->SetActualBearing(-1.0);
+        return;
+    }    
+
+    float actual_bearing = bearing(m_sample.Location(), m_known.Location());
+    float actual_range   = range(m_sample.Location(), m_known.Location());
+                                       
+    m_tactical_panel->SetActualBearing(actual_bearing);
+
+    str.Printf(_T("%03i"), degree_normalize((int)actual_bearing));
+    XRCCTRL(*this, "transmitter_actual_bearing_text", 
wxStaticText)->SetLabel(str);
+    if (actual_range > 99.9)
+        str.Printf(_T("%1.0f"), actual_range);
+    else if (actual_range > 9.99)
+        str.Printf(_T("%1.1f"), actual_range);
+    else
+        str.Printf(_T("%1.2f"), actual_range);
+    XRCCTRL(*this, "transmitter_actual_range_text", 
wxStaticText)->SetLabel(str);
+}
+
+void HunterFrame::UpdateKnownLocation()
+{
+    wxString str;
+    
+    if (!m_known.IsSet()) {
+        XRCCTRL(*this, "known_transmitter_latitude_edit", 
wxTextCtrl)->SetValue(_T(""));
+        XRCCTRL(*this, "known_transmitter_longitude_edit", 
wxTextCtrl)->SetValue(_T(""));
+        XRCCTRL(*this, "search_disterror_text", 
wxStaticText)->SetLabel(_T(""));
+        return;
+    }    
+
+    str.Printf(_T("%1.5f"), m_known.Latitude());        
+    XRCCTRL(*this, "known_transmitter_latitude_edit", 
wxTextCtrl)->SetValue(str);
+    str.Printf(_T("%1.5f"), m_known.Longitude());
+    XRCCTRL(*this, "known_transmitter_longitude_edit", 
wxTextCtrl)->SetValue(str);
+    UpdateSearchLocation(true); // to update the known error
+}
+
+void HunterFrame::OnKnownTransmitterUpdate(wxCommandEvent &event)
+{
+    // Note: this is an event handler for a calibration tab button
+    wxString lat_text = XRCCTRL(*this, "known_transmitter_latitude_edit", 
wxTextCtrl)->GetValue();
+    wxString lon_text = XRCCTRL(*this, "known_transmitter_longitude_edit", 
wxTextCtrl)->GetValue();
+
+    double lat = 0.0, lon = 0.0;
+
+    // TODO: use Spherical constructor/exceptions
+    if (!lat_text.ToDouble(&lat) || lat > 90.0 || lat < -90.0) {
+        wxMessageDialog(this, wxT("Invalid latitude entered."), wxT("Data 
Error"),
+                        wxOK|wxICON_ERROR).ShowModal();
+        return;
+    }        
+
+    if (!lon_text.ToDouble(&lon) || lon >180.0 || lon < -180.0) {
+        wxMessageDialog(this, wxT("Invalid longitude entered."), wxT("Data 
Error"),
+                        wxOK|wxICON_ERROR).ShowModal();
+        return;
+    }        
+
+    m_known.Location(Spherical(lat, lon));
+    CalcKnownStatistics();
+    
+    m_settings->SetKnownTransmitterLongitude(lon);
+    m_settings->SetKnownTransmitterLatitude(lat);
+
+    UpdateKnownLocation();
+    if (m_gps_started)
+        UpdateKnownDirection();
+}
+
+void HunterFrame::OnUseKnownTransmitter(wxCommandEvent &event)
+{
+    if (event.IsChecked())
+        m_known.Location(Spherical(m_settings->GetKnownTransmitterLatitude(),
+                                   
m_settings->GetKnownTransmitterLongitude()));
+    else
+        m_known.Clear();
+
+    m_settings->SetUseKnownTransmitter(m_known.IsSet());
+    CalcKnownStatistics();
+    UpdateKnownLocation();
+    if (m_gps_started)
+        UpdateKnownDirection();    
+}
+
+void HunterFrame::UpdateGPSValidity(bool valid)
+{
+    m_sample.Valid(valid);
+
+    wxColour color = *wxBLACK;
+    if (!valid)
+        color = *wxRED;
+
+    XRCCTRL(*this, "doppler_absolute_bearing_text", 
wxStaticText)->SetForegroundColour(color);
+    XRCCTRL(*this, "transmitter_actual_bearing_text", 
wxStaticText)->SetForegroundColour(color);
+    XRCCTRL(*this, "transmitter_actual_range_text", 
wxStaticText)->SetForegroundColour(color);
+    XRCCTRL(*this, "gps_latitude_text", 
wxStaticText)->SetForegroundColour(color);
+    XRCCTRL(*this, "gps_longitude_text", 
wxStaticText)->SetForegroundColour(color);
+    XRCCTRL(*this, "gps_heading_text", 
wxStaticText)->SetForegroundColour(color);
+    XRCCTRL(*this, "gps_speed_text", wxStaticText)->SetForegroundColour(color);
+}
+
+void HunterFrame::OnFileNew(wxCommandEvent &event)
+{
+    if (m_log) {
+        wxLogDebug(_T("Not Implemented: current log is discarded without 
saving..."));
+        StopCapture();
+        delete m_log;
+        m_search.Reset();
+        m_log = NULL;
+    }
+
+    MakeNewLogAndSearch();
+    this->SetTitle(wxT("AE6HO Radio Location System - Unsaved Search")); // 
refactor into EnableSearchItems()
+    XRCCTRL(*this, "search_newsave_button", wxButton)->SetLabel(_T("Save"));
+    XRCCTRL(*this, "search_openclose_button", wxButton)->SetLabel(_T("Close"));
+    this->GetMenuBar()->FindItem(XRCID("file_new_menuitem"))->Enable(false);
+    this->GetMenuBar()->FindItem(XRCID("file_open_menuitem"))->Enable(false);
+    EnableSearchItems(true);
+}
+
+void HunterFrame::MakeNewLogAndSearch()
+{
+    m_log = new SampleLog();
+    m_search.Reset();
+}
+
+void HunterFrame::OnFileOpen(wxCommandEvent &event)
+{
+    wxString filename;
+
+    if (m_log)
+        OnFileClose(event);
+
+    wxFileDialog dlg(this, wxT("Open Log File"), _T("."), _T(""), _T("*.dat"),
+                     wxOPEN|wxFILE_MUST_EXIST|wxCHANGE_DIR);
+    if (dlg.ShowModal() == wxID_OK) {
+        
this->GetMenuBar()->FindItem(XRCID("file_new_menuitem"))->Enable(false);
+        
this->GetMenuBar()->FindItem(XRCID("file_open_menuitem"))->Enable(false);
+        filename = dlg.GetPath();
+        MakeNewLogAndSearch();
+        m_log->Load(filename);        
+        this->SetTitle(wxT("AE6HO Radio Location System - ")+filename);
+        XRCCTRL(*this, "search_newsave_button", 
wxButton)->SetLabel(_T("Save"));
+        XRCCTRL(*this, "search_openclose_button", 
wxButton)->SetLabel(_T("Close"));
+        EnableSearchItems(true);
+        CalcKnownStatistics();
+        CalcSolution();
+    }
+}
+
+void HunterFrame::OnFileSave(wxCommandEvent &event)
+{
+    wxASSERT(m_log);
+    
+    wxString filename;
+    if (!m_log->HasFile()) {
+        wxFileDialog dlg(this, wxT("Save Search Data"), _T("."), _T(""), 
_T("*.dat"), 
+                         wxSAVE|wxOVERWRITE_PROMPT|wxCHANGE_DIR);
+        if (dlg.ShowModal() == wxID_OK) {
+            filename = dlg.GetPath();
+            m_log->Save(filename);
+            this->SetTitle(wxT("AE6HO Radio Location System - ")+filename);
+        }
+    }
+    else
+        m_log->Save();  // Adds additional samples since last save
+}
+
+void HunterFrame::OnFileClose(wxCommandEvent &event)
+{
+    // FIXME: ask user if they want to save changed data instead of going 
straight to save dialog
+    if (m_log->IsDirty())
+        OnFileSave(event);
+
+    StopCapture();
+    delete m_log;
+    m_search.Reset();
+    m_log = NULL;
+    
+    this->SetTitle(wxT("AE6HO Radio Location System")); // refactor into 
EnableSearchItems()
+    XRCCTRL(*this, "search_newsave_button", wxButton)->SetLabel(_T("New"));
+    XRCCTRL(*this, "search_openclose_button", wxButton)->SetLabel(_T("Open"));
+    this->GetMenuBar()->FindItem(XRCID("file_new_menuitem"))->Enable(true);
+    this->GetMenuBar()->FindItem(XRCID("file_open_menuitem"))->Enable(true);
+    EnableSearchItems(false);
+    m_known.ClearStats();
+    UpdateKnownStatistics();
+}
+
+void HunterFrame::OnCalibrationSaveToFile(wxCommandEvent &event)
+{
+    wxString filename;
+    wxFileDialog dlg(this, wxT("Save Calibration Data"), _T("."), _T(""), 
_T("*.cal"), 
+                     wxSAVE|wxOVERWRITE_PROMPT|wxCHANGE_DIR);
+    if (dlg.ShowModal() == wxID_OK) {
+        filename = dlg.GetPath();
+        wxFile file(filename.c_str(), wxFile::write);
+        for (int i = 0; i < 7; i++) {
+            wxString str;
+            float offset = m_settings->GetDopplerCalibration(i);
+            str.Printf(_T("%f\n"), offset);
+            file.Write(str.c_str(), str.length());
+        }
+    }
+}
+
+void HunterFrame::OnCalibrationLoadFromFile(wxCommandEvent &event)
+{
+    wxString filename;
+    wxFileDialog dlg(this, wxT("Load Calibration Data"), _T("."), _T(""), 
_T("*.cal"),
+                     wxOPEN|wxFILE_MUST_EXIST|wxCHANGE_DIR);
+    if (dlg.ShowModal() == wxID_OK) {
+        filename = dlg.GetPath();
+        wxFile file(filename.c_str(), wxFile::read);
+        for (int i = 0; i < 7; i++) {
+            char ch;
+            size_t count;
+            wxString line;
+            count = file.Read(&ch, 1);
+            while (count == 1 && ch != '\n') {
+                line.Append(ch);
+                count = file.Read(&ch, 1);
+            }
+            float offset = atof((char *)line.c_str());
+            m_settings->SetDopplerCalibration(i, offset);
+            m_doppler->SetCalibration(i, offset);
+        }
+    }
+}
+
+void HunterFrame::OnCalibrationSaveTransmitter(wxCommandEvent &event)
+{
+    wxString filename;
+    if (!m_known.IsSet())
+        return; // FIXME: disable menu item when no known transmitter so we 
can't get here
+
+    wxFileDialog dlg(this, wxT("Save Transmitter Coordinates"), _T("."), 
_T(""), _T("*.loc"), 
+                     wxSAVE|wxOVERWRITE_PROMPT|wxCHANGE_DIR);
+    if (dlg.ShowModal() == wxID_OK) {
+        filename = dlg.GetPath();
+        wxFile file(filename.c_str(), wxFile::write);
+        wxString str;
+        // TODO: use Spherical method to output strings
+        str.Printf(_T("%f\n%f\n"), m_known.Latitude(),
+                               m_known.Longitude());
+        file.Write(str.c_str(), str.length());
+    }
+}
+
+void HunterFrame::OnCalibrationLoadTransmitter(wxCommandEvent &event)
+{
+    wxString filename;
+    wxFileDialog dlg(this, wxT("Load Transmitter Location"), _T("."), _T(""), 
_T("*.loc"),
+                     wxOPEN|wxFILE_MUST_EXIST|wxCHANGE_DIR);
+    if (dlg.ShowModal() == wxID_OK) {
+        filename = dlg.GetPath();
+        wxFile file(filename.c_str(), wxFile::read);
+        wxString latitude, longitude;
+
+        for (int i = 0; i < 2; i++) {
+            char ch;
+            size_t count;
+            wxString line;
+
+            count = file.Read(&ch, 1);
+            while (count == 1 && ch != '\n') {
+                line.Append(ch);
+                count = file.Read(&ch, 1);
+            }
+            if (i == 0) {
+                latitude = line;
+            }
+            else if (i == 1) {
+                longitude = line;
+            }
+        }
+
+        m_known.Location(Spherical(latitude, longitude));
+        CalcKnownStatistics();
+
+        XRCCTRL(*this, "known_transmitter_checkbox", 
wxCheckBox)->SetValue(true);
+        m_settings->SetUseKnownTransmitter(true);
+        m_settings->SetKnownTransmitterLatitude(m_known.Latitude());
+        m_settings->SetKnownTransmitterLongitude(m_known.Longitude());
+
+        UpdateKnownLocation();
+        if (m_gps_started)
+            UpdateKnownDirection();
+    }
+}
+
+void HunterFrame::OnSearchNewSave(wxCommandEvent &event)
+{
+    if (!m_log)
+        OnFileNew(event);
+    else
+        OnFileSave(event);
+}
+
+void HunterFrame::OnSearchOpenClose(wxCommandEvent &event)
+{
+    if (!m_log)
+        OnFileOpen(event);
+    else
+        OnFileClose(event);
+}
+
+void HunterFrame::OnSearchToggle(wxCommandEvent &event)
+{
+       if (!m_capture)
+        StartCaptureAutomatic();
+       else
+        StopCapture();
+}
+
+void HunterFrame::StartCaptureAutomatic()
+{
+    m_capture = true;
+    m_one_shot = false;
+    XRCCTRL(*this, "search_toggle_button", wxButton)->SetLabel(_T("Stop"));
+    XRCCTRL(*this, "search_once_button", wxButton)->Enable(false);
+}
+
+void HunterFrame::StartCaptureOnce()
+{
+    m_capture = true;
+    m_one_shot = true;
+    XRCCTRL(*this, "search_once_button", wxButton)->SetLabel(_T("Cancel"));
+    XRCCTRL(*this, "search_toggle_button", wxButton)->Enable(false);
+}
+
+void HunterFrame::StopCapture()
+{
+    m_capture = false;
+    m_one_shot = false;
+    XRCCTRL(*this, "search_toggle_button", wxButton)->Enable(true);
+    XRCCTRL(*this, "search_once_button", wxButton)->Enable(true);
+    XRCCTRL(*this, "search_toggle_button", 
wxButton)->SetLabel(_T("Automatic"));
+    XRCCTRL(*this, "search_once_button", wxButton)->SetLabel(_T("One Shot"));
+}
+
+void HunterFrame::OnSearchOnce(wxCommandEvent &event)
+{
+    if (!m_capture)
+        StartCaptureOnce();
+    else
+        StopCapture();
+}
+
+void HunterFrame::OnDisplayOrientation(wxCommandEvent &event)
+{
+    int selection = XRCCTRL(*this, "display_orientation_radiobox", 
wxRadioBox)->GetSelection();
+    if (selection == 0)
+        m_tactical_panel->SetOrientation(TrackUp);
+    else
+        m_tactical_panel->SetOrientation(NorthUp);
+
+    m_settings->SetDisplayOrientation(selection);
+}
+
+void HunterFrame::OnDisplayDoppler(wxCommandEvent &event)
+{
+    bool checked = event.IsChecked();
+    m_tactical_panel->SetDisplayDoppler(checked);
+    m_settings->SetDisplayDoppler(checked);
+}
+
+void HunterFrame::OnDisplayKnown(wxCommandEvent &event)
+{
+    bool checked = event.IsChecked();
+    m_tactical_panel->SetDisplayKnown(checked);
+    m_settings->SetDisplayKnown(checked);
+}
+
+void HunterFrame::OnDisplayEstimated(wxCommandEvent &event)
+{
+    bool checked = event.IsChecked();
+    m_tactical_panel->SetDisplayEstimated(checked);
+    m_settings->SetDisplayEstimated(checked);
+}
+
+void HunterFrame::OnHistogramSourceChg(wxCommandEvent &event)
+{
+       m_histogram_source = XRCCTRL(*this, "statistics_source_radiobox", 
wxRadioBox)->GetSelection();
+    if (m_histogram_source == 0)
+        m_error_histogram_panel->SetData(m_search.Histogram());
+    else if (m_histogram_source == 1)
+        m_error_histogram_panel->SetData(m_known.Histogram());
+    // TODO: remember this in m_settings
+    Refresh(); // Needed?
+}
+
+void HunterFrame::OnHistogramCoordsChg(wxCommandEvent &event)
+{
+       int n = XRCCTRL(*this, "statistics_coords_radiobox", 
wxRadioBox)->GetSelection();
+    if (n == 0)
+        m_error_histogram_panel->SetMode(HistogramPanel::Rectangular);
+    else if (n == 1)
+        m_error_histogram_panel->SetMode(HistogramPanel::Polar);
+    // TODO: remember this in m_settings
+}

Copied: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/hunter.h 
(from rev 3254, 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/hunter.h)
===================================================================
--- 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/hunter.h   
                            (rev 0)
+++ 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/hunter.h   
    2006-08-12 18:20:45 UTC (rev 3256)
@@ -0,0 +1,156 @@
+/*
+ Copyright 2006 Johnathan Corgan.
+ 
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+ 
+ This software 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 GNU Radio; see the file COPYING.  If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+// Application level includes
+#include "sample.h"
+#include "known.h"
+#include "search.h"
+
+// wxWidgets includes
+#include <wx/frame.h>
+#include <wx/spinbutt.h>  // Unknown why these two aren't in wx.h
+#include <wx/splitter.h>
+
+// Forward declarations
+class EZDoppler;
+class EZDopplerUpdate;
+class GPS;
+class GPSUpdate;
+class HunterSettings;
+class TacticalPanel;
+class HistogramPanel;
+class Spherical;
+class SampleLog;
+class KnownTransmitter;
+
+class HunterFrame : public wxFrame
+{
+public:
+       // Constructor
+       HunterFrame();
+    void DoCalibrationStep(int which);
+    
+private:
+       // Initialization routines
+    void InitializeSettings();    
+       void InitializeWindows();
+       void InitializeDoppler();
+    void InitializeGPS();
+    void InitializeCalibration();
+    void InitializeSearch();
+    void InitializeDisplay();
+
+    // System related functions
+       void OnClose(wxCloseEvent &event);
+    
+    // Status related functions
+    void OnHistogramSourceChg(wxCommandEvent &event);
+    void OnHistogramCoordsChg(wxCommandEvent &event);
+
+    // Search related functions
+    void EnableSearchItems(bool enable);
+    void MakeNewLogAndSearch();
+    void CalcSolution();
+    void StartCaptureAutomatic();
+    void StartCaptureOnce();
+    void StopCapture();
+    void UpdateSearchStatus(bool display);
+    void UpdateSearchLocation(bool display);
+    void UpdateSearchDirection(bool display);
+    void OnSearchNewSave(wxCommandEvent &event);
+    void OnSearchOpenClose(wxCommandEvent &event);
+    void OnSearchToggle(wxCommandEvent &event);
+    void OnSearchOnce(wxCommandEvent &event);
+    void OnSearchUpdate(SearchUpdate &event);                
+    
+    // Doppler related functions
+    void SetDopplerParams();
+    void StartDoppler();
+    void StopDoppler();
+    void UpdateDopplerStatus(bool display);
+       void OnDopplerToggle(wxCommandEvent &event);
+       void OnDopplerAutostart(wxCommandEvent &event);
+       void OnDopplerReset(wxCommandEvent &event);
+       void OnDopplerFilterChg(wxScrollEvent &event);
+       void OnDopplerRotationChg(wxCommandEvent &event);
+    void OnDopplerUpdate(EZDopplerUpdate &event);                
+
+    // GPS related functions
+    void StartGPS();
+    void StopGPS();
+    void UpdateGPSStatus(bool dipslay);
+    void UpdateGPSValidity(bool valid);
+    void OnGPSToggle(wxCommandEvent &event);
+    void OnGPSAutostart(wxCommandEvent &event);
+    void OnGPSDeviceSelect(wxCommandEvent &event);
+    void OnGPSUpdate(GPSUpdate &event);                
+               
+    // Calibration related functions
+    void CalcKnownStatistics();
+    void UpdateKnownLocation();
+    void UpdateKnownDirection();
+    void UpdateKnownStatistics();
+    void OnCalibrationEqualize(wxCommandEvent &event);
+    void OnCalibrationZero(wxCommandEvent &event);
+    void OnCalibrationAdjustLeft(wxSpinEvent &event);
+    void OnCalibrationAdjustRight(wxSpinEvent &event);
+    void OnCalibrationAffectAllRates(wxCommandEvent &event);
+    void OnKnownTransmitterUpdate(wxCommandEvent &event);
+    void OnUseKnownTransmitter(wxCommandEvent &event);
+        
+    // Tactical display related functions
+    void OnDisplayOrientation(wxCommandEvent &event);
+    void OnDisplayDoppler(wxCommandEvent &event);
+    void OnDisplayKnown(wxCommandEvent &event);
+    void OnDisplayEstimated(wxCommandEvent &event);
+    
+       // Menu event handlers
+       void OnExit(wxCommandEvent &event);
+       void OnAbout(wxCommandEvent &event);
+    void OnFileNew(wxCommandEvent &event);
+    void OnFileOpen(wxCommandEvent &event);
+    void OnFileClose(wxCommandEvent &event);
+    void OnFileSave(wxCommandEvent &event);
+    void OnCalibrationSaveToFile(wxCommandEvent &event);
+    void OnCalibrationLoadFromFile(wxCommandEvent &event);
+    void OnCalibrationLoadTransmitter(wxCommandEvent &event);
+    void OnCalibrationSaveTransmitter(wxCommandEvent &event);
+            
+       // Member data
+    HunterSettings *m_settings;         // Configuration file
+       EZDoppler *m_doppler;               // Attached Doppler device
+    GPS *m_gps;                         // Attached GPS device
+    SampleLog *m_log;                   // Accumulated sample points
+    KnownTransmitter m_known;           // Identified known transmitter 
location for calibration
+    TransmitterSearch m_search;         // Search being conducted
+    
+       bool m_doppler_started;             // Tracks start/stop of doppler 
device
+    bool m_gps_started;                 // Tracks start/stop of GPS device
+    bool m_capture;                     // Tracks start/stop of bearing capture
+    bool m_one_shot;                    // Tracks whether capture is one 
bearing only
+    int  m_histogram_source;            // Tracks histogram data source 
(0=estimated, 1=actual);
+    
+    Sample m_sample;                    // Current sample being updated by 
doppler and GPS
+                    
+    // Child windows that need remembering
+    TacticalPanel *m_tactical_panel;
+    HistogramPanel *m_error_histogram_panel;
+    
+       // This class handles events
+       DECLARE_EVENT_TABLE();
+};

Copied: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/hunter.xpm 
(from rev 3254, 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/hunter.xpm)
===================================================================
--- 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/hunter.xpm 
                            (rev 0)
+++ 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/hunter.xpm 
    2006-08-12 18:20:45 UTC (rev 3256)
@@ -0,0 +1,39 @@
+/* XPM */
+static char * hunter_xpm[] = {
+"32 32 4 1",
+"      c #000000",
+".     c #FF0000",
+"+     c #00FF80",
+"@     c #00FF00",
+"             .....              ",
+"         .............          ",
+"        .....     ......        ",
+"      ....     +      ...       ",
+"     ...      @+@      ...      ",
+"    ...       @+@       ...     ",
+"   ...        @+@        ...    ",
+"   ..         @+@         ..    ",
+"  ..          @+@          ..   ",
+" ...          @+@          ...  ",
+" ..           @+@           ..  ",
+" ..           @+@           ..  ",
+" ..           @+@           ..  ",
+"..            @+@            .. ",
+"..            @@@            .. ",
+"..            @@@            .. ",
+"..            @@@            .. ",
+"..                           .. ",
+" ..                         ..  ",
+" ..                         ..  ",
+" ..                         ..  ",
+" ...                       ...  ",
+"  ..                       ..   ",
+"   ..                     ..    ",
+"   ...                   ...    ",
+"    ...                 ...     ",
+"     ...               ...      ",
+"      ....           ....       ",
+"        .....     .....         ",
+"         .............          ",
+"             .....              ",
+"                                "};

Copied: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/hunter.xrc 
(from rev 3254, 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/hunter.xrc)
===================================================================
--- 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/hunter.xrc 
                            (rev 0)
+++ 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/hunter.xrc 
    2006-08-12 18:20:45 UTC (rev 3256)
@@ -0,0 +1,1020 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<resource xmlns="http://www.wxwidgets.org/wxxrc"; version="2.3.0.1">
+
+<object class="wxMenuBar" name="main_menu">
+    <object class="wxMenu" name="file_menu">
+        <label>_File</label>
+        <object class="wxMenuItem" name="file_new_menuitem">
+            <label>_New Search\tCtrl-N</label>
+            <help>Create a new transmitter search.</help>
+        </object>
+        <object class="wxMenuItem" name="file_open_menuitem">
+            <label>_Open Search\tCtrl-O</label>
+            <help>Open an existing search</help>
+        </object>
+        <object class="wxMenuItem" name="file_close_menuitem">
+            <label>_Close Search\tCtrl-W</label>
+            <help>Close current search.</help>
+        </object>
+        <object class="separator"/>
+        <object class="wxMenuItem" name="file_save_menuitem">
+            <label>_Save Search\tCtrl-S</label>
+            <help>Save current search to a file.</help>
+        </object>
+        <object class="separator"/>
+        <object class="wxMenuItem" name="file_exit_menuitem">
+            <label>E_xit\tAlt-X</label>
+            <help>Exit this application</help>
+        </object>
+    </object>
+
+    <object class="wxMenu" name="doppler_menu">
+        <label>_Doppler</label>
+        <object class="wxMenuItem" name="doppler_toggle_menuitem">
+            <label>_Start</label>
+            <help>Start Doppler Rotation</help>
+        </object>
+        <object class="wxMenuItem" name="doppler_autostart_menuitem">
+            <label>_Autostart</label>
+            <checkable>1</checkable>
+            <help>Automatically start Doppler when application loads</help>
+        </object>
+        <object class="wxMenuItem" name="doppler_reset_menuitem">
+            <label>_Reset</label>
+            <help>Reset Doppler</help>
+        </object>
+    </object>
+
+    <object class="wxMenu" name="calibration_menu">
+        <label>_Calibration</label>
+        <object class="wxMenuItem" name="calibration_loadfromfile_menuitem">
+            <label>_Load Calibration File</label>
+            <help>Load system calibration values from filesystem</help>
+        </object>
+        <object class="wxMenuItem" name="calibration_savetofile_menuitem">
+            <label>_Save Calibration File</label>
+            <help>Save system calibration values to filesystem</help>
+        </object>
+        <object class="separator"/>
+        <object class="wxMenuItem" name="calibration_loadtransmitter_menuitem">
+            <label>L_oad Transmitter</label>
+            <help>Load transmitter coordinates from file</help>
+        </object>
+        <object class="wxMenuItem" name="calibration_savetransmitter_menuitem">
+            <label>S_ave Transmitter</label>
+            <help>Save transmitter coordinates to file</help>
+        </object>
+    </object>
+
+    <object class="wxMenu" name="help_menu">
+        <label>_Help</label>
+        <object class="wxMenuItem" name="about_menuitem">
+            <label>_About...</label>
+            <help>About this application</help>
+        </object>
+    </object>
+</object>
+
+<object class="wxFrame" name="main_frame">                        <!-- Main 
window, bottom left and right panes -->
+       <title>AE6HO Radio Location System</title>
+       <object class="wxSplitterWindow" name="horiz_splitter">           <!-- 
Divides main window into top and bottom -->
+               <style>wxSP_3D|wxSP_LIVE_UPDATE</style>
+               <orientation>horizontal</orientation>
+               <minsize>170</minsize>
+
+               <object class="wxSplitterWindow" name="vert_splitter">    <!-- 
Divides top half into left and right -->
+                       <style>wxSP_3D|wxSP_LIVE_UPDATE</style>
+                       <orientation>vertical</orientation>
+                       <minsize>240</minsize>
+                       <sashpos>240</sashpos>
+                       <object_ref ref="status_panel"/>                        
      <!-- Defined below -->
+                       <object class="unknown" name="tactical_panel"/>         
        
+               </object>
+
+               <object_ref ref="control_panel"/>                         <!-- 
Defined below -->
+
+       </object>       
+
+</object>
+
+<object class="wxPanel" name="status_panel">                           <!-- 
Read only display variables -->
+    <object class="wxBoxSizer">   <!-- Each item is a major status disply, 
doppler, GPS, etc. -->
+        <orient>wxVERTICAL</orient>
+        <object class="sizeritem">
+            <flag>wxGROW|wxALL</flag>
+            <border>5</border>
+               <object class="wxStaticBoxSizer"> <!-- Each item is a Doppler 
status control -->
+                   <label>Doppler</label>
+                       <orient>wxVERTICAL</orient>
+                       <object class="sizeritem">
+                               <flag>wxGROW|wxLEFT|wxRIGHT|wxBOTTOM</flag>
+                               <border>5</border>
+                               <object class="wxStaticBoxSizer"> <!-- Single 
item, doppler strength -->
+                                       <orient>wxVERTICAL</orient>
+                                       <label>Strength</label>
+                                       <object class="sizeritem">
+                                               <flag>wxGROW</flag>
+                                               <object class="wxGauge" 
name="doppler_level_gauge">
+                                               </object>
+                                       </object>
+                               </object>
+                       </object>
+                       <object class="sizeritem">
+                               <flag>wxGROW|wxLEFT|wxRIGHT|wxBOTTOM</flag>
+                               <border>5</border>
+                               <object class="wxStaticBoxSizer"> <!-- Single 
item, doppler audio level -->
+                                       <orient>wxVERTICAL</orient>
+                                       <label>Audio Level</label>
+                                       <object class="sizeritem">
+                                               <flag>wxGROW</flag>
+                                               <object class="wxGauge" 
name="doppler_audio_gauge">
+                                               </object>
+                                       </object>
+                               </object>
+                       </object>
+                <object class="sizeritem">
+                    <flag>wxGROW</flag>
+                    <border>5</border>
+                    <object class="wxBoxSizer">
+                        <orient>wxHORIZONTAL</orient>
+                               <object class="sizeritem">
+                                       
<flag>wxGROW|wxLEFT|wxRIGHT|wxBOTTOM</flag>
+                                       <border>5</border>
+                                       <option>1</option>
+                                       <object class="wxStaticBoxSizer"> <!-- 
Single item, absolute bearing -->
+                                               <orient>wxVERTICAL</orient>
+                                               <label>Abs. Bearing</label>
+                                               <object class="sizeritem">
+                                                       <flag>wxGROW</flag>
+                                                       <object 
class="wxStaticText" name="doppler_absolute_bearing_text">
+                                                          
<style>wxALIGN_RIGHT</style>
+                                                       </object>
+                                               </object>
+                                       </object>
+                               </object>
+                               <object class="sizeritem">
+                                       
<flag>wxGROW|wxLEFT|wxRIGHT|wxBOTTOM</flag>
+                                       <border>5</border>
+                                       <option>1</option>
+                                       <object class="wxStaticBoxSizer"> <!-- 
Single item, relative bearing -->
+                                               <orient>wxVERTICAL</orient>
+                                               <label>Rel. Bearing</label>
+                                               <object class="sizeritem">
+                                                       <flag>wxGROW</flag>
+                                                       <object 
class="wxStaticText" name="doppler_relative_bearing_text">
+                                                          
<style>wxALIGN_RIGHT</style>
+                                                       </object>
+                                               </object>
+                                       </object>
+                               </object>
+                    </object>
+                </object>
+               </object>
+        </object>
+
+        <object class="sizeritem">
+            <flag>wxGROW|wxALL</flag>
+            <border>5</border>
+               <object class="wxStaticBoxSizer"> <!-- Each item is a 
Transmitter status control -->
+                   <label>Transmitter</label>
+                       <orient>wxVERTICAL</orient>
+                       <object class="sizeritem">
+                               <flag>wxGROW|wxLEFT|wxRIGHT|wxBOTTOM</flag>
+                               <border>5</border>
+                               <option>1</option>
+                    <object class="wxBoxSizer">
+                        <orient>wxHORIZONTAL</orient>
+                               <object class="sizeritem">
+                                       <flag>wxGROW|wxRIGHT</flag>
+                                       <border>5</border>
+                                       <option>1</option>
+                                       <object class="wxStaticBoxSizer"> <!-- 
Single item, estimated transmitter bearing -->
+                                               <orient>wxVERTICAL</orient>
+                                               <label>Est. Bearing</label>
+                                               <object class="sizeritem">
+                                                       <flag>wxGROW</flag>
+                                                       <object 
class="wxStaticText" name="transmitter_estimated_bearing_text">
+                                                          
<style>wxALIGN_RIGHT</style>
+                                                       </object>
+                                               </object>
+                                       </object>
+                               </object>
+                               <object class="sizeritem">
+                                       <flag>wxGROW|wxLEFT</flag>
+                                       <border>5</border>
+                                       <option>1</option>
+                                       <object class="wxStaticBoxSizer"> <!-- 
Single item, estimated transmitter range -->
+                                               <orient>wxVERTICAL</orient>
+                                               <label>Est. Range</label>
+                                               <object class="sizeritem">
+                                                       <flag>wxGROW</flag>
+                                                       <object 
class="wxStaticText" name="transmitter_estimated_range_text">
+                                                          
<style>wxALIGN_RIGHT</style>
+                                                       </object>
+                                               </object>
+                                       </object>
+                               </object>
+                    </object>
+                </object>
+                       <object class="sizeritem">
+                               <flag>wxGROW|wxLEFT|wxRIGHT|wxBOTTOM</flag>
+                               <border>5</border>
+                               <option>1</option>
+                    <object class="wxBoxSizer">
+                        <orient>wxHORIZONTAL</orient>
+                               <object class="sizeritem">
+                                       <flag>wxGROW|wxRIGHT</flag>
+                                       <border>5</border>
+                                       <option>1</option>
+                                       <object class="wxStaticBoxSizer"> <!-- 
Single item, actual transmitter bearing -->
+                                               <orient>wxVERTICAL</orient>
+                                               <label>Act. Bearing</label>
+                                               <object class="sizeritem">
+                                                       <flag>wxGROW</flag>
+                                                       <object 
class="wxStaticText" name="transmitter_actual_bearing_text">
+                                                          
<style>wxALIGN_RIGHT</style>
+                                                       </object>
+                                               </object>
+                                       </object>
+                               </object>
+                               <object class="sizeritem">
+                                       <flag>wxGROW|wxLEFT</flag>
+                                       <border>5</border>
+                                       <option>1</option>
+                                       <object class="wxStaticBoxSizer"> <!-- 
Single item, actual transmitter range -->
+                                               <orient>wxVERTICAL</orient>
+                                               <label>Act. Range</label>
+                                               <object class="sizeritem">
+                                                       <flag>wxGROW</flag>
+                                                       <object 
class="wxStaticText" name="transmitter_actual_range_text">
+                                                          
<style>wxALIGN_RIGHT</style>
+                                                       </object>
+                                               </object>
+                                       </object>
+                               </object>
+                    </object>
+                </object>
+            </object>
+        </object>
+
+        <object class="sizeritem">
+            <flag>wxGROW|wxALL</flag>
+            <border>5</border>
+            <object class="wxStaticBoxSizer">
+                <label>Error Histogram</label>
+                <orient>wxVERTICAL</orient>
+                <object class="sizeritem">
+                    <object class="unknown" name="error_histogram_panel">
+                        <bg>#000000</bg>
+                        <size>220,220</size>
+                    </object>
+                </object>
+                <object class="sizeritem">
+                    <object class="wxBoxSizer">
+                        <style>wxHORIZONTAL</style>
+                        <object class="sizeritem">
+                            <flag>wxALL</flag>
+                            <border>5</border>
+                            <object class="wxRadioBox" 
name="statistics_source_radiobox">
+                                               <label>Source</label>
+                                               <style>wxRA_SPECIFY_COLS</style>
+                                               <dimension>1</dimension>
+                                               <selection>0</selection>
+                                               <item>Estimated</item>
+                                               <item>Actual</item>
+                            </object>
+                        </object>
+                        <object class="sizeritem">
+                            <flag>wxALL</flag>
+                            <border>5</border>
+                            <object class="wxRadioBox" 
name="statistics_coords_radiobox">
+                                               <label>Coordinates</label>
+                                               <style>wxRA_SPECIFY_COLS</style>
+                                               <dimension>1</dimension>
+                                               <selection>0</selection>
+                                               <item>Rectangular</item>
+                                               <item>Polar</item>
+                            </object>
+                        </object>
+                    </object>
+                </object>
+            </object>
+        </object>
+    </object>
+</object>
+
+<object class="wxNotebook" name="control_panel">                       <!-- 
all user interaction goes here -->
+       <style>wxNB_FIXEDWIDTH|wxNB_TOP</style>
+       <object class="notebookpage">
+               <label>Doppler</label>
+               <object_ref ref="doppler_control_panel"/>               <!-- 
Attached EZ Doppler device configuration and control -->
+       </object>
+       <object class="notebookpage">
+               <label>GPS</label>
+               <object_ref ref="gps_control_panel"/>                   <!-- 
Attached GPS device configuration and control -->
+       </object>
+       <object class="notebookpage">
+               <label>Calibration</label>
+               <object_ref ref="calibration_control_panel"/>   <!-- System 
calibration control -->
+       </object>
+       <object class="notebookpage">
+               <label>Capture</label>
+               <object_ref ref="capture_control_panel"/>           <!-- 
Bearing capture control -->
+       </object>
+       <object class="notebookpage">
+               <label>Search</label>
+               <object_ref ref="search_control_panel"/>                <!-- 
Search control -->
+       </object>
+       <object class="notebookpage">
+               <label>Statistics</label>
+               <object_ref ref="statistics_control_panel"/>    <!-- Statistics 
control -->
+       </object>
+       <object class="notebookpage">
+               <label>Display</label>
+               <object_ref ref="display_control_panel"/>               <!-- 
Tactical display control -->
+       </object>
+</object>
+
+<object class="wxPanel" name="doppler_control_panel">                  <!-- 
Attached EZ Doppler device configuration and control -->
+       <style>wxTAB_TRAVERSAL</style>
+
+       <object class="wxBoxSizer">                                     <!-- 
Left to right controls -->
+               <orient>wxHORIZONTAL</orient>
+               <object class="sizeritem">
+                       <flag>wxTOP</flag>
+                       <border>5</border>
+                       <object class="wxBoxSizer">
+                               <orient>wxVERTICAL</orient>
+                               <object class="sizeritem">              <!-- 
Start or stop doppler operation -->
+                                       <flag>wxLEFT|wxTOP|wxRIGHT</flag>
+                                       <border>5</border>
+                                       <object class="wxButton" 
name="doppler_toggle_button">
+                                               <label>Start</label>
+                                       </object>
+                               </object>
+                               <object class="sizeritem">              <!-- 
Reset doppler -->
+                                       <flag>wxLEFT|wxTOP|wxRIGHT</flag>
+                                       <border>5</border>
+                                       <object class="wxButton" 
name="doppler_reset_button">
+                                               <label>Reset</label>
+                                       </object>
+                               </object>
+                               <object class="sizeritem">              <!-- 
Check for autostart of doppler -->
+                                       <flag>wxLEFT|wxTOP|wxRIGHT</flag>
+                                       <border>5</border>
+                                       <object class="wxCheckBox" 
name="doppler_autostart_checkbox">
+                                               <label>Autostart</label>
+                                       </object>
+                               </object>
+                       </object>
+               </object>
+               <object class="sizeritem">
+                       <flag>wxTOP|wxRIGHT</flag>
+                       <border>5</border>
+                       <object class="wxStaticBoxSizer">
+                               <label>Set Filtering</label>
+                               <orient>wxVERTICAL</orient>
+                               <object class="sizeritem">              <!-- 
Set doppler filter time constant -->
+                                       <flag>wxALL|wxGROW</flag>
+                    <border>5</border>
+                                       <object class="wxSlider" 
name="doppler_filter_slider">
+                                               
<style>wxSL_HORIZONTAL|wxSL_LABELS</style>
+                                               <size>250,45</size>
+                                               <min>1</min>
+                                               <value>20</value>
+                                               <max>100</max>
+                                       </object>
+                               </object>
+                       </object>
+               </object>
+               <object class="sizeritem">              <!-- Set doppler 
rotation -->
+            <flag>wxTOP</flag>
+            <border>5</border>
+            <object class="wxRadioBox" name="doppler_rotation_radiobox">
+                               <label>Set Rotation Rate (Hz)</label>
+                               <style>wxRA_SPECIFY_ROWS</style>
+                               <dimension>2</dimension>
+                               <selection>5</selection>
+                               <item>250</item>
+                               <item>400</item>
+                               <item>500</item>
+                               <item>666</item>
+                               <item>1000</item>
+                               <item>2000</item>
+                       </object>
+               </object>
+       </object>
+</object>
+
+<object class="wxPanel" name="gps_control_panel">
+       <style>wxTAB_TRAVERSAL</style>
+       <object class="wxBoxSizer">                                     <!-- 
Left to right controls -->
+               <orient>wxHORIZONTAL</orient>
+               <object class="sizeritem">
+                       <flag>wxTOP</flag>
+                       <border>5</border>
+                       <object class="wxBoxSizer">
+                               <orient>wxVERTICAL</orient>
+                               <object class="sizeritem">              <!-- 
Start or stop GPS operation -->
+                                       <flag>wxALL</flag>
+                                       <border>5</border>
+                                       <object class="wxButton" 
name="gps_toggle_button">
+                                               <label>Start</label>
+                                       </object>
+                               </object>
+                               <object class="sizeritem">              <!-- 
Check for autostart of GPS -->
+                                       <flag>wxALL</flag>
+                                       <border>5</border>
+                                       <object class="wxCheckBox" 
name="gps_autostart_checkbox">
+                                               <label>Autostart GPS</label>
+                                       </object>
+                               </object>
+                       </object>
+               </object>
+               <object class="sizeritem">
+                       <flag>wxTOP|wxRIGHT</flag>
+                       <border>5</border>
+                       <object class="wxStaticBoxSizer">
+                               <label>Select Port</label>
+                               <orient>wxVERTICAL</orient>
+                               <object class="sizeritem">
+                                       <flag>wxALL|wxGROW</flag>
+                    <border>5</border>
+                                       <object class="wxComboBox" 
name="gps_device_combobox">
+                        <size>150,30</size>
+                                       </object>
+                               </object>
+                       </object>
+               </object>
+        <object class="sizeritem">
+            <flag>wxTOP|wxRIGHT</flag>
+            <border>5</border>
+            <object class="wxStaticBoxSizer">
+                <orient>wxVERTICAL</orient>
+                <label>Location</label>
+                       <object class="sizeritem">
+                               <object class="wxStaticBoxSizer"> <!-- Single 
item, current latitude -->
+                                       <orient>wxVERTICAL</orient>
+                                       <label>Latitude</label>
+                                       <object class="sizeritem">
+                                               <object class="wxStaticText" 
name="gps_latitude_text">
+                                <size>140,22</size>
+                                <style>wxALIGN_RIGHT</style>
+                                               </object>
+                                       </object>
+                               </object>
+                       </object>
+                       <object class="sizeritem">
+                               <object class="wxStaticBoxSizer"> <!-- Single 
item, current latitude-->
+                                       <orient>wxVERTICAL</orient>
+                                       <label>Longitude</label>
+                                       <object class="sizeritem">
+                                               <object class="wxStaticText" 
name="gps_longitude_text">
+                                <size>140,22</size>
+                                <style>wxALIGN_RIGHT</style>
+                                               </object>
+                                       </object>
+                               </object>
+                       </object>
+            </object>
+        </object>
+        <object class="sizeritem">
+            <flag>wxTOP|wxRIGHT</flag>
+            <border>5</border>
+            <object class="wxStaticBoxSizer">
+                <orient>wxVERTICAL</orient>
+                <label>Course</label>
+                       <object class="sizeritem">
+                               <object class="wxStaticBoxSizer"> <!-- Single 
item, gps heading -->
+                                       <orient>wxVERTICAL</orient>
+                                       <label>Heading</label>
+                                       <object class="sizeritem">
+                                               <object class="wxStaticText" 
name="gps_heading_text">
+                                <size>55,22</size>
+                                <style>wxALIGN_RIGHT</style>
+                                               </object>
+                                       </object>
+                               </object>
+                       </object>
+                       <object class="sizeritem">
+                               <object class="wxStaticBoxSizer"> <!-- Single 
item, gps speed -->
+                                       <orient>wxVERTICAL</orient>
+                                       <label>Speed</label>
+                                       <object class="sizeritem">
+                                               <object class="wxStaticText" 
name="gps_speed_text">
+                                <size>55,22</size>
+                                <style>wxALIGN_RIGHT</style>
+                                               </object>
+                                       </object>
+                               </object>
+                       </object>
+            </object>
+        </object>
+       </object>
+</object>
+
+<object class="wxPanel" name="calibration_control_panel">
+       <style>wxTAB_TRAVERSAL</style>
+       <object class="wxBoxSizer">                                     <!-- 
Left to right controls -->
+               <orient>wxHORIZONTAL</orient>
+        <object class="sizeritem">
+            <flag>wxTOP|wxRIGHT</flag>
+            <border>5</border>
+            <object class="wxStaticBoxSizer" name="doppler_calibration_box">
+                <orient>wxVERTICAL</orient>
+                <label>Doppler</label>
+                <object class="sizeritem">
+                    <object class="wxBoxSizer">
+                        <orient>wxHORIZONTAL</orient>
+                                       <object class="sizeritem">              
<!-- Perform doppler calibration -->
+                                               <flag>wxALL</flag>
+                                               <border>5</border>
+                                               <object class="wxButton" 
name="calibration_equalize_button">
+                                                       <label>Equalize</label>
+                                <default>0</default>
+                                               </object>
+                                       </object>
+                                       <object class="sizeritem">              
<!-- Set calibration offset to make zero -->
+                                               <flag>wxALL</flag>
+                                               <border>5</border>
+                                               <object class="wxButton" 
name="calibration_zero_button">
+                                                       <label>Zero</label>
+                                <default>0</default>
+                                               </object>
+                                       </object>
+                    </object>
+                </object>
+
+                <object class="sizeritem">
+                    <object class="wxBoxSizer">
+                        <orient>wxHORIZONTAL</orient>
+                                       <object class="sizeritem">      
+                                               <flag>wxALL</flag>
+                                               <border>5</border>
+                                               <object class="wxStaticText">
+                                                       <label>Adjust 
Offset:</label>
+                                               </object>
+                                       </object>
+                                       <object class="sizeritem">              
<!-- Set calibration offset to make zero -->
+                                               <flag>wxALL</flag>
+                                               <border>5</border>
+                            <object class="wxSpinButton" 
name="calibration_adjust_spinner">
+                                <style>wxSP_HORIZONTAL</style>
+                                <value>500</value>
+                                <min>0</min>
+                                <max>1000</max>
+                            </object>
+                                       </object>
+                    </object>
+                </object>
+
+                <object class="sizeritem">
+                    <flag>wxALL</flag>
+                    <border>5</border>
+                    <object class="wxCheckBox" name="calibration_all_checkbox">
+                        <label>Affect All Rates</label>
+                    </object>
+                </object>
+
+            </object>                                           
+        </object>
+
+        <object class="sizeritem">
+            <flag>wxTOP|wxRIGHT</flag>
+            <border>5</border>
+            <object class="wxStaticBoxSizer" name="known_transmitter_box">
+                <orient>wxHORIZONTAL</orient>
+                <label>Known Transmitter</label>
+                <object class="sizeritem">
+                    <object class="wxBoxSizer">
+                        <orient>wxVERTICAL</orient>
+                        <object class="sizeritem">
+                            <flag>wxRIGHT</flag>
+                            <border>5</border>
+                            <object class="wxStaticBoxSizer">
+                                <orient>wxVERTICAL</orient>
+                                <label>Latitude</label>
+                                <object class="sizeritem">
+                                           <object class="wxTextCtrl" 
name="known_transmitter_latitude_edit">
+                                        <style>wxTE_LEFT</style>
+                                               </object>
+                                       </object>
+                               </object>
+                        </object>
+                        <object class="sizeritem">
+                            <flag>wxTOP||wxBOTTOM|wxALIGN_CENTRE</flag>
+                            <border>5</border>
+                            <object class="wxButton" 
name="known_transmitter_update_button">
+                                <label>Update</label>
+                            </object>
+                        </object>
+                    </object>
+                </object>
+                <object class="sizeritem">
+                    <object class="wxBoxSizer">
+                        <orient>wxVERTICAL</orient>
+                        <object class="sizeritem">
+                            <object class="wxStaticBoxSizer">
+                                <orient>wxVERTICAL</orient>
+                                <label>Longitude</label>
+                                               <object class="sizeritem">
+                                               <object class="wxTextCtrl" 
name="known_transmitter_longitude_edit">
+                                        <style>wxTE_LEFT</style>
+                                               </object>
+                                       </object>
+                                   </object>
+                        </object>
+                        <object class="sizeritem">
+                            <flag>wxTOP|wxALIGN_CENTRE</flag>
+                            <border>10</border>
+                            <object class="wxCheckBox" 
name="known_transmitter_checkbox">
+                                <label>Use</label>
+                                <default>0</default>
+                            </object>
+                        </object>
+                    </object>
+                </object>
+            </object>                                           
+        </object>
+               <object class="sizeritem">
+                   <flag>wxTOP|wxRIGHT</flag>
+                   <border>5</border>
+            <object class="wxStaticBoxSizer">
+                   <label>Bearing Error Statistics</label>
+                       <orient>wxHORIZONTAL</orient>
+                <object class="sizeritem">
+                    <object class="wxBoxSizer">
+                        <orient>wxVERTICAL</orient>
+                        <object class="sizeritem">
+                            <flag>wxRIGHT</flag>
+                            <border>5</border>
+                            <object class="wxStaticBoxSizer">
+                                <label>Count</label>
+                                <object class="sizeritem">
+                                    <object class="wxStaticText" 
name="error_count_text">
+                                        <size>75,22</size>
+                                        <style>wxALIGN_RIGHT</style>
+                                    </object>
+                                </object>
+                            </object>
+                        </object>
+                        <object class="sizeritem">
+                            <flag>wxRIGHT</flag>
+                            <border>5</border>
+                            <object class="wxStaticBoxSizer">
+                                <label>Mode</label>
+                                <object class="sizeritem">
+                                    <object class="wxStaticText" 
name="error_mode_text">
+                                        <size>75,22</size>
+                                        <style>wxALIGN_RIGHT</style>
+                                    </object>
+                                </object>
+                            </object>
+                        </object>
+                    </object>
+                </object>
+                <object class="sizeritem">
+                    <object class="wxBoxSizer">
+                        <orient>wxVERTICAL</orient>
+                        <object class="sizeritem">
+                            <object class="wxStaticBoxSizer">
+                                <label>Mean</label>
+                                <object class="sizeritem">
+                                    <object class="wxStaticText" 
name="error_mean_text">
+                                        <size>75,22</size>
+                                        <style>wxALIGN_RIGHT</style>
+                                    </object>
+                                </object>
+                            </object>
+                        </object>
+                        <object class="sizeritem">
+                            <object class="wxStaticBoxSizer">
+                                <label>Concen.</label>
+                                <object class="sizeritem">
+                                    <object class="wxStaticText" 
name="error_conc_text">
+                                        <size>75,22</size>
+                                        <style>wxALIGN_RIGHT</style>
+                                    </object>
+                                </object>
+                            </object>
+                        </object>
+                    </object>
+                </object>
+            </object>
+               </object>
+       </object>
+</object>
+
+<object class="wxPanel" name="capture_control_panel">
+       <style>wxTAB_TRAVERSAL</style>
+       <object class="wxBoxSizer">                                     <!-- 
Left to right controls -->
+               <orient>wxHORIZONTAL</orient>
+               <object class="sizeritem">
+            <object class="wxPanel">
+            </object>
+               </object>
+       </object>
+</object>
+
+<object class="wxPanel" name="statistics_control_panel">
+       <style>wxTAB_TRAVERSAL</style>
+       <object class="wxBoxSizer">                                     <!-- 
Left to right controls -->
+               <orient>wxHORIZONTAL</orient>
+               <object class="sizeritem">
+            <object class="wxPanel">
+            </object>
+               </object>
+       </object>
+</object>
+
+
+
+<object class="wxDialog" name="calibration_dialog">
+    <title>Equalize Doppler Rotation Rates</title>
+    <object class="wxBoxSizer">
+        <orient>wxVERTICAL</orient>
+        <object class="sizeritem">
+            <flag>wxALL</flag>
+            <border>10</border>
+            <object class="wxStaticText" name="calibration_instructions_text">
+                <label>Please ensure the signal source remains fixed for\nthe 
duration of the test.  The source does not have\nto be at a zero 
bearing.</label>
+            </object>
+        </object>
+        <object class="sizeritem">
+            <flag>wxGROW|wxALL</flag>
+            <border>5</border>
+            <object class="wxStaticBoxSizer">
+                <orient>wxHORIZONTAL</orient>
+                <label>Calibration Progress...</label>
+                <object class="sizeritem">
+                    <style>wxGROW</style>
+                    <option>1</option>
+                    <object class="wxGauge" name="calibration_progress_gauge">
+                        <range>6</range>
+                    </object>
+                </object>
+            </object>
+        </object>
+        <object class="sizeritem">
+            <flag>wxALL</flag>
+            <border>10</border>
+            <object class="wxStaticText" name="calibration_progress_text">
+                <label>Press Start to begin, Cancel to exit...</label>
+            </object>
+        </object>
+        <object class="sizeritem">
+            <flag>wxGROW|wxALL</flag>
+            <border>5</border>
+            <object class="wxBoxSizer">
+                <orient>wxHORIZONTAL</orient>
+                <object class="sizeritem">
+                    <flag>wxALIGN_LEFT</flag>
+                    <object class="wxButton" name="calibration_start_button">
+                        <label>Start</label>
+                    </object>
+                </object>
+                <object class="spacer">
+                    <size>5</size>
+                    <option>1</option>
+                </object>
+                <object class="sizeritem">
+                    <flag>wxALIGN_RIGHT</flag>
+                    <object class="wxButton" name="calibration_cancel_button">
+                        <label>Cancel</label>
+                    </object>
+                </object>
+            </object>
+        </object>
+    </object>
+</object>
+
+<object class="wxPanel" name="display_control_panel">                  <!-- 
Tactical display options -->
+       <style>wxTAB_TRAVERSAL</style>
+
+       <object class="wxBoxSizer">                                     <!-- 
Left to right controls -->
+               <orient>wxHORIZONTAL</orient>
+               <object class="sizeritem">
+                       <flag>wxTOP|wxRIGHT</flag>
+                       <border>5</border>
+            <object class="wxRadioBox" name="display_orientation_radiobox">
+                               <label>Orientation</label>
+                               <style>wxRA_SPECIFY_COLS</style>
+                               <dimension>1</dimension>
+                               <selection>0</selection>
+                               <item>Track Up</item>
+                               <item>North Up</item>
+                       </object>
+               </object>
+               <object class="sizeritem">
+                       <flag>wxTOP|wxRIGHT</flag>
+                       <border>5</border>
+
+            <object class="wxStaticBoxSizer">
+                <orient>wxVERTICAL</orient>
+                <label>Display Pointers</label>
+                <object class="sizeritem">
+                    <object class="wxCheckBox" name="display_doppler_checkbox">
+                        <label>Current Doppler Bearing</label>
+                    </object>
+                </object>
+                <object class="sizeritem">
+                    <object class="wxCheckBox" name="display_known_checkbox">
+                        <label>Known Transmitter Bearing</label>
+                    </object>
+                </object>
+                <object class="sizeritem">
+                    <object class="wxCheckBox" 
name="display_estimated_checkbox">
+                        <label>Estimated Bearing</label>
+                    </object>
+                </object>
+            </object>
+
+               </object>
+       </object>
+</object>
+
+<object class="wxPanel" name="search_control_panel">                   <!-- 
Search control options -->
+       <style>wxTAB_TRAVERSAL</style>
+
+       <object class="wxBoxSizer">                                     <!-- 
Left to right controls -->
+               <orient>wxHORIZONTAL</orient>
+               <object class="sizeritem">
+                       <flag>wxTOP|wxRIGHT</flag>
+                       <border>5</border>
+            <object class="wxStaticBoxSizer">
+                   <label>Search Log</label>
+                       <orient>wxVERTICAL</orient>
+                <object class="sizeritem">
+                    <flag>wxLEFT|wxTOP|wxRIGHT</flag>
+                    <border>5</border>
+                    <object class="wxButton" name="search_newsave_button">
+                        <label>New</label>
+                    </object>
+                </object>
+                <object class="sizeritem">
+                    <flag>wxALL</flag>
+                    <border>5</border>
+                    <object class="wxButton" name="search_openclose_button">
+                        <label>Open</label>
+                    </object>
+                </object>
+                       </object>
+               </object>
+
+               <object class="sizeritem">
+                   <flag>wxTOP|wxRIGHT</flag>
+                   <border>5</border>
+            <object class="wxStaticBoxSizer">
+                   <label>Capture</label>
+                       <orient>wxVERTICAL</orient>
+                <object class="sizeritem">
+                    <flag>wxTOP|wxLEFT|wxRIGHT</flag>
+                    <border>5</border>
+                    <object class="wxButton" name="search_toggle_button">
+                        <label>Auto</label>
+                    </object>
+                </object>
+                <object class="sizeritem">
+                    <flag>wxALL</flag>
+                    <border>5</border>
+                    <object class="wxButton" name="search_once_button">
+                        <label>One Shot</label>
+                    </object>
+                </object>
+            </object>
+               </object>
+
+               <object class="sizeritem">
+                   <flag>wxTOP|wxRIGHT</flag>
+                   <border>5</border>
+            <object class="wxStaticBoxSizer">
+                   <label>Estimated Location</label>
+                       <orient>wxVERTICAL</orient>
+                <object class="sizeritem">
+                    <object class="wxStaticBoxSizer">
+                        <label>Longitude</label>
+                        <object class="sizeritem">
+                            <object class="wxStaticText" 
name="search_longitude_text">
+                                <size>150,22</size>
+                                <style>wxALIGN_RIGHT</style>
+                            </object>
+                        </object>
+                    </object>
+                </object>
+                <object class="sizeritem">
+                    <object class="wxStaticBoxSizer">
+                        <label>Latitude</label>
+                        <object class="sizeritem">
+                            <object class="wxStaticText" 
name="search_latitude_text">
+                                <size>150,22</size>
+                                <style>wxALIGN_RIGHT</style>
+                            </object>
+                        </object>
+                    </object>
+                </object>
+            </object>
+               </object>
+
+               <object class="sizeritem">
+                   <flag>wxTOP|wxRIGHT</flag>
+                   <border>5</border>
+            <object class="wxStaticBoxSizer">
+                   <label>Search Status</label>
+                       <orient>wxHORIZONTAL</orient>
+                <object class="sizeritem">
+                    <object class="wxBoxSizer">
+                        <orient>wxVERTICAL</orient>
+                        <object class="sizeritem">
+                            <flag>wxRIGHT</flag>
+                            <border>5</border>
+                            <object class="wxStaticBoxSizer">
+                                <label>Bearings</label>
+                                <object class="sizeritem">
+                                    <object class="wxStaticText" 
name="search_count_text">
+                                        <size>100,22</size>
+                                        <style>wxALIGN_RIGHT</style>
+                                    </object>
+                                </object>
+                            </object>
+                        </object>
+                        <object class="sizeritem">
+                            <flag>wxRIGHT</flag>
+                            <border>5</border>
+                            <object class="wxStaticBoxSizer">
+                                <label>Status</label>
+                                <object class="sizeritem">
+                                    <object class="wxStaticText" 
name="search_status_text">
+                                        <size>100,22</size>
+                                        <style>wxALIGN_RIGHT</style>
+                                    </object>
+                                </object>
+                            </object>
+                        </object>
+                    </object>
+                </object>
+
+                <object class="sizeritem">
+                    <object class="wxBoxSizer">
+                        <orient>wxVERTICAL</orient>
+                        <object class="sizeritem">
+                            <flag>wxRIGHT</flag>
+                            <border>5</border>
+                            <object class="wxStaticBoxSizer">
+                                <label>Mode</label>
+                                <object class="sizeritem">
+                                    <object class="wxStaticText" 
name="search_mode_text">
+                                        <size>100,22</size>
+                                        <style>wxALIGN_RIGHT</style>
+                                    </object>
+                                </object>
+                            </object>
+                        </object>
+                        <object class="sizeritem">
+                            <flag>wxRIGHT</flag>
+                            <border>5</border>
+                            <object class="wxStaticBoxSizer">
+                                <label>Mean</label>
+                                <object class="sizeritem">
+                                    <object class="wxStaticText" 
name="search_mean_text">
+                                        <size>100,22</size>
+                                        <style>wxALIGN_RIGHT</style>
+                                    </object>
+                                </object>
+                            </object>
+                        </object>
+                    </object>
+                </object>
+
+                <object class="sizeritem">
+                    <object class="wxBoxSizer">
+                        <orient>wxVERTICAL</orient>
+                        <object class="sizeritem">
+                            <object class="wxStaticBoxSizer">
+                                <label>Score</label>
+                                <object class="sizeritem">
+                                    <object class="wxStaticText" 
name="search_score_text">
+                                        <size>100,22</size>
+                                        <style>wxALIGN_RIGHT</style>
+                                    </object>
+                                </object>
+                            </object>
+                        </object>
+                        <object class="sizeritem">
+                            <object class="wxStaticBoxSizer">
+                                <label>Distance Error</label>
+                                <object class="sizeritem">
+                                    <object class="wxStaticText" 
name="search_disterror_text">
+                                        <size>100,22</size>
+                                        <style>wxALIGN_RIGHT</style>
+                                    </object>
+                                </object>
+                            </object>
+                        </object>
+                    </object>
+                </object>
+            </object>
+               </object>
+       </object>
+</object>
+
+</resource>

Copied: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/hunterapp.cc
 (from rev 3254, 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/hunterapp.cpp)
===================================================================
--- 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/hunterapp.cc
                           (rev 0)
+++ 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/hunterapp.cc
   2006-08-12 18:20:45 UTC (rev 3256)
@@ -0,0 +1,52 @@
+/*
+ Copyright 2006 Johnathan Corgan.
+ 
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+ 
+ This software 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 GNU Radio; see the file COPYING.  If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+// Application level includes
+#include "hunterapp.h"
+#include "hunter.h"
+
+// wxWidgets includes
+#include <wx/xrc/xmlres.h>
+#include <wx/log.h>
+
+// Provided in resource.cpp created from hunter.xrc by make system
+extern void InitXmlResource();
+
+bool Hunter::OnInit()
+{
+       m_logger = new wxLogStream();
+       wxLog::SetActiveTarget(m_logger);
+
+    // Get XML resources linked in via resource.cpp
+       wxXmlResource::Get()->InitAllHandlers();
+    InitXmlResource();
+
+       HunterFrame *top = new HunterFrame();
+       top->Show(true);
+
+    // Everything Zen
+       return true;
+}
+
+int Hunter::OnExit()
+{
+       return 0;
+}
+
+// Creates main() and WinMain() entry points
+IMPLEMENT_APP(Hunter)

Copied: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/hunterapp.h
 (from rev 3254, 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/hunterapp.h)
===================================================================
--- 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/hunterapp.h
                            (rev 0)
+++ 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/hunterapp.h
    2006-08-12 18:20:45 UTC (rev 3256)
@@ -0,0 +1,43 @@
+/*
+ Copyright 2006 Johnathan Corgan.
+ 
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+ 
+ This software 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 GNU Radio; see the file COPYING.  If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef __HUNTER_APP__
+#define __HUNTER_APP__
+
+// wxWidgets includes
+#include <wx/app.h>
+
+// Forward declarations
+class wxLog;
+
+class Hunter : public wxApp
+{
+public:
+       // Called on application startup
+       virtual bool OnInit();
+
+       // Called by system when application is closing but
+       // before wxWidgets is finished
+       virtual int OnExit();
+       
+private:
+       // Active log target
+       wxLog *m_logger;
+};
+
+#endif

Copied: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/known.cc 
(from rev 3254, 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/known.cpp)
===================================================================
--- 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/known.cc   
                            (rev 0)
+++ 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/known.cc   
    2006-08-12 18:20:45 UTC (rev 3256)
@@ -0,0 +1,55 @@
+/*
+ Copyright 2006 Johnathan Corgan.
+ 
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+ 
+ This software 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 GNU Radio; see the file COPYING.  If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+// Application level includes
+#include "known.h"
+#include "util.h"
+
+// wxWidget includes
+#include <wx/log.h>
+
+using namespace std;
+
+KnownTransmitter::KnownTransmitter()
+{
+    m_valid = false;
+    ClearStats();
+}
+
+void KnownTransmitter::Location(const Spherical &location)
+{
+    m_location = location;
+    m_valid = true;
+    ClearStats();
+}
+
+void KnownTransmitter::Clear()
+{
+    m_valid = false;
+    ClearStats();
+}
+
+void KnownTransmitter::ClearStats()
+{
+    m_histogram.Reset();
+}
+
+void KnownTransmitter::Calc(const std::vector<Sample> &samples)
+{
+    m_histogram.Calc(samples, m_location);
+}

Copied: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/known.h 
(from rev 3254, 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/known.h)
===================================================================
--- 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/known.h    
                            (rev 0)
+++ 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/known.h    
    2006-08-12 18:20:45 UTC (rev 3256)
@@ -0,0 +1,59 @@
+/*
+ Copyright 2006 Johnathan Corgan.
+ 
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+ 
+ This software 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 GNU Radio; see the file COPYING.  If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef __KNOWN_H__
+#define __KNOWN_H__
+
+// Application level includes
+#include "spherical.h"
+#include "sample.h"
+#include "histogram.h"
+
+// System level includes
+#include <vector>
+
+class KnownTransmitter
+{
+public:
+    KnownTransmitter();
+
+    void Location(const Spherical &location);
+    Spherical Location() const { return m_location; }
+
+    void Clear();
+    void ClearStats();
+    void Calc(const std::vector<Sample> &samples);
+
+    int Count() const { return m_histogram.Count(); }
+    int Mode() const { return m_histogram.Mode(); }
+    float Mean() const { return m_histogram.Mean(); }
+    float Concentration() const { return m_histogram.Concentration(); }
+
+    bool   IsSet() const { return m_valid; }
+    bool   HasStats() const { return m_histogram.Count() > 0; }
+    double Latitude() const { return m_location.Latitude(); }
+    double Longitude() const { return m_location.Longitude(); }
+    const ErrorHistogram &Histogram() { return m_histogram; }
+        
+private:
+    bool m_valid;
+    Spherical m_location;
+    ErrorHistogram m_histogram;
+};
+
+#endif

Copied: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/sample.cc 
(from rev 3254, 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/sample.cpp)
===================================================================
--- 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/sample.cc  
                            (rev 0)
+++ 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/sample.cc  
    2006-08-12 18:20:45 UTC (rev 3256)
@@ -0,0 +1,139 @@
+/*
+ Copyright 2006 Johnathan Corgan.
+ 
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+ 
+ This software 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 GNU Radio; see the file COPYING.  If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+// Application level includes
+#include "sample.h"
+#include "util.h"
+
+// wxWidgets includes
+#include <wx/log.h>
+
+Sample::Sample()
+{
+    m_time = 0;
+    m_valid = false;
+    m_location = Spherical(0.0, 0.0);
+    m_heading = 0.0;
+    m_speed = 0.0;
+    m_in_phase = 0.0;
+    m_quadrature = 0.0;
+    m_phase = 0.0;
+    m_strength = 0.0;
+    m_volume = 0.0;
+    m_rate = 0;
+    m_filtering = 1;
+    m_error = 0.0;
+    m_ierror = 0.0;
+    m_qerror = 0.0;
+}
+
+Sample::Sample(const Sample &sample)
+{
+    m_time = sample.m_time;
+    m_valid = sample.m_valid;
+    m_location = sample.m_location;
+    m_heading = sample.m_heading;
+    m_speed = sample.m_speed;
+    m_in_phase = sample.m_in_phase;
+    m_quadrature = sample.m_quadrature;
+    m_phase = sample.m_phase;
+    m_strength = sample.m_strength;
+    m_volume = sample.m_volume;
+    m_rate = sample.m_rate;
+    m_filtering = sample.m_filtering;
+    m_error = sample.m_error;
+    m_ierror = sample.m_ierror;
+    m_qerror = sample.m_qerror;
+}
+
+Sample::Sample(wxString &line)
+{
+    char valid;
+    double lat, lon;
+
+    sscanf((char *)line.c_str(), "%c %i %lf %lf %f %f %f %f %f %f %f %f %f %f 
%i %i",
+        &valid,
+        &m_time,
+        &lat,
+        &lon,
+        &m_heading,
+        &m_speed,
+        &m_volume,
+        &m_strength,
+        &m_in_phase,
+        &m_quadrature,
+        &m_phase,
+        &m_error,
+        &m_ierror,
+        &m_qerror,
+        &m_rate,
+        &m_filtering);    
+
+    if (valid == 'V') 
+        m_valid = true;
+    else
+        m_valid = false;
+
+    m_location = Spherical(lat, lon);
+}
+
+void Sample::Dump(char *str, int len)
+{
+    //                 vld tim  lat     lon     hdg   speed vol   stren inphs 
quad  phase error ierr  qerr  rt flt
+    snprintf(str, len, "%s %10i %10.5lf %10.5lf %5.1f %6.2f %7.5f %7.5f %9.6f 
%9.6f %9.6f %7.2f %9.6f %9.6f %i %i",
+                    m_valid ? "V":"I",
+                    m_time,
+                    m_location.Latitude(),
+                    m_location.Longitude(),
+                    m_heading,
+                    m_speed,
+                    m_volume,
+                    m_strength,
+                    m_in_phase,
+                    m_quadrature,
+                    m_phase,
+                    m_error,
+                    m_ierror,
+                    m_qerror,
+                    m_rate,
+                    m_filtering);    
+}
+
+void Sample::CalcError(const Spherical &location, float &angle, float &ierror, 
float &qerror) const
+{
+    float actual_bearing = bearing(m_location, location);
+    float sample_relative_bearing = degree_normalize(to_degrees(m_phase));
+    float sample_absolute_bearing = 
degree_normalize(sample_relative_bearing+m_heading);
+    angle = sample_absolute_bearing-actual_bearing;
+    
+    if (angle < -180.0)
+        angle += 360;
+    if (angle > 180.0)
+        angle -= 360;
+
+    ierror = 0.0;
+    qerror = 0.0;
+
+    // Rotate I, Q by actual bearing
+    float i_act = cos(to_radians(-actual_bearing));
+    float q_act = sin(to_radians(-actual_bearing));
+    ierror = m_in_phase*i_act - m_quadrature*q_act;
+    qerror = m_quadrature*i_act + m_in_phase*q_act;
+
+
+}

Copied: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/sample.h 
(from rev 3254, 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/sample.h)
===================================================================
--- 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/sample.h   
                            (rev 0)
+++ 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/sample.h   
    2006-08-12 18:20:45 UTC (rev 3256)
@@ -0,0 +1,97 @@
+/*
+ Copyright 2006 Johnathan Corgan.
+ 
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+ 
+ This software 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 GNU Radio; see the file COPYING.  If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef __SAMPLE_H__
+#define __SAMPLE_H__
+
+// Application level includes
+#include "spherical.h"
+
+// wxWidgets includes
+#include <wx/string.h>
+
+// System level includes
+#include <ctime>
+
+class Sample
+{
+public:
+    Sample();
+    Sample(const Sample &sample);
+    Sample(wxString &line);
+
+    void Time(time_t time)             { m_time = time; }
+    void Valid(bool valid)             { m_valid = valid; }
+    void Location(Spherical &location) { m_location = location; }
+    void Heading(float heading)        { m_heading = heading; }
+    void Speed(float speed)            { m_speed = speed; }
+    void InPhase(float in_phase)       { m_in_phase = in_phase; }
+    void Quadrature(float quadrature)  { m_quadrature = quadrature; }
+    void Phase(float phase)            { m_phase = phase; }
+    void Strength(float strength)      { m_strength = strength; }
+    void Volume(float volume)          { m_volume = volume; }
+    void Rate(int rate)                { m_rate = rate; }
+    void Filtering(int filtering)      { m_filtering = filtering; }
+    void Error(float error)            { m_error = error; }
+    void IError(float error)           { m_ierror = error; }
+    void QError(float error)           { m_qerror = error; }
+                
+    const Spherical &Location() const { return m_location; }
+    float Latitude() const { return m_location.Latitude(); }
+    float Longitude() const { return m_location.Longitude(); }
+    float Heading() const { return m_heading; } 
+    float Speed() const { return m_speed; }
+    float InPhase() const { return m_in_phase; }
+    float Quadrature() const { return m_quadrature; }
+    float Phase() const { return m_phase; }
+    float Strength() const { return m_strength; }
+    float Volume() const { return m_volume; }
+    int   Filtering() const { return m_filtering; }
+    float Error() const { return m_error; }
+    float IError() const { return m_ierror; }
+    float QError() const { return m_qerror; }
+    bool  Valid() const { return m_valid; }
+    
+    void CalcError(const Spherical &location, float &error, float &ierror, 
float &qerror) const;
+    
+    void Dump(char *str, int len); // TEMPORARY
+    
+    operator const std::string();    // Conversion operator to std::string
+            
+private:
+    // Data supplied by measuring system
+    time_t    m_time;           // Unix time of observation
+    bool      m_valid;          // GPS validity indication (NMEA "I" or "V")
+    Spherical m_location;       // GPS latitude and longitude
+    float     m_heading;        // GPS heading in degrees 0.0 - 360.0
+    float     m_speed;          // GPS speed in mph
+    float     m_in_phase;       // Doppler I channel -1.0 to 1.0
+    float     m_quadrature;     // Doppler Q channel -1.0 to 1.0
+    float     m_phase;          // Doppler phase -M_PI to M_PI (derived)
+    float     m_strength;       // Doppler strength 0.0 - 1.0 (derived)
+    float     m_volume;         // Doppler volume 0.0 - 1.0
+    int       m_rate;           // Doppler rotation rate 0 - 5
+    int       m_filtering;      // Doppler filtering 1 - 100
+
+    // Container configured
+    float     m_error;          // Known transmitter bearing error
+    float     m_ierror;         // Known transmitter in phase error
+    float     m_qerror;         // Known transmitter quadrature error
+};
+
+#endif

Copied: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/samplelog.cc
 (from rev 3254, 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/samplelog.cpp)
===================================================================
--- 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/samplelog.cc
                           (rev 0)
+++ 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/samplelog.cc
   2006-08-12 18:20:45 UTC (rev 3256)
@@ -0,0 +1,107 @@
+/*
+ Copyright 2006 Johnathan Corgan.
+ 
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+ 
+ This software 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 GNU Radio; see the file COPYING.  If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+// Application level includes
+#include "samplelog.h"
+
+// wxWidgets includes
+#include <wx/file.h>
+#include <wx/log.h>
+
+// System level includes
+#include <cmath>
+
+SampleLog::SampleLog()
+{
+    m_file = NULL;
+    m_save = -1;
+}
+
+void SampleLog::Load(wxString filename)
+{
+    m_file = new wxFile(filename.c_str(), wxFile::read_write);
+    wxString line;
+            
+    if (m_file && m_file->IsOpened()) {
+        while (readline(line)) {
+            Sample sample(line); // can't use inline temporary in next line
+            Add(sample);      // Locking is handled in Add
+        }
+        
+        m_save = -1;
+    }
+}
+
+bool SampleLog::readline(wxString &line)
+{
+    char ch;
+    size_t count;
+
+    line.Empty();
+    count = m_file->Read(&ch, 1);
+    while (count == 1 && ch != '\n') {
+        line.Append(ch);
+        count = m_file->Read(&ch, 1);
+    }
+
+    return !line.IsEmpty();
+}
+
+void SampleLog::Add(Sample &sample)
+{
+    wxMutexLocker locker(m_mutex);
+    
+    if (m_save < 0)
+        m_save = m_samples.size();
+
+    m_samples.push_back(sample);
+    return;
+}
+
+bool SampleLog::Save(wxString &filename)
+{
+    wxASSERT(!m_file);  // Save called with filename when it already exists is 
an error
+    wxLogError(_T("SampleLog::Save: called with %s when file already exists"), 
filename.c_str());
+    
+    m_filename = filename;
+    m_file = new wxFile(m_filename.c_str(), wxFile::write);
+
+    return Save();
+}
+
+bool SampleLog::Save()
+{
+    wxASSERT(m_file);
+    if (m_save < 0)
+        return false;
+
+    wxMutexLocker locker(m_mutex);
+    
+    char str[256];
+    if (m_file && m_file->IsOpened()) {
+        for (int i = m_save; i < m_samples.size(); i++) {
+            m_samples[i].Dump(str, 255);
+            m_file->Write(str, strlen(str));
+            m_file->Write("\n", strlen("\n"));
+        }
+        m_save = -1;
+        return true;
+    }
+
+    return false;
+}

Copied: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/samplelog.h
 (from rev 3254, 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/samplelog.h)
===================================================================
--- 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/samplelog.h
                            (rev 0)
+++ 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/samplelog.h
    2006-08-12 18:20:45 UTC (rev 3256)
@@ -0,0 +1,63 @@
+/*
+ Copyright 2006 Johnathan Corgan.
+ 
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+ 
+ This software 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 GNU Radio; see the file COPYING.  If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef __SAMPLELOG_H__
+#define __SAMPLELOG_H__
+
+// Application level includes
+#include "sample.h"
+
+// wxWidgets includes
+#include <wx/string.h>
+#include <wx/event.h>
+
+// System level includes
+#include <vector>
+
+// Forward declarations
+class wxFile;
+
+class SampleLog
+{
+public:
+    SampleLog();
+    
+    // Sample access
+    void Add(Sample &sample);
+    int  Count() const { return m_samples.size(); }
+    wxMutex &Mutex() { return m_mutex; }
+    std::vector<Sample>& Samples() { return m_samples; }
+
+    // File operations
+    void Load(wxString filename);
+    bool Save();
+    bool Save(wxString &filename);
+    bool HasFile() const { return (m_file != NULL); }
+    bool IsDirty() const { return m_save >= 0; }
+
+private:
+    bool readline(wxString &line);
+
+    std::vector<Sample> m_samples;
+    wxMutex m_mutex;
+    int m_save;
+    wxString m_filename;
+    wxFile *m_file;
+};
+
+#endif

Copied: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/search.cc 
(from rev 3254, 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/search.cpp)
===================================================================
--- 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/search.cc  
                            (rev 0)
+++ 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/search.cc  
    2006-08-12 18:20:45 UTC (rev 3256)
@@ -0,0 +1,211 @@
+/*
+ Copyright 2006 Johnathan Corgan.
+ 
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+ 
+ This software 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 GNU Radio; see the file COPYING.  If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+// Application level includes
+#include "search.h"
+#include "sample.h"
+#include "util.h"
+
+// wxWidgets includes
+#include <wx/log.h>
+#include <wx/utils.h>
+
+// System level includes
+#include <vector>
+
+using namespace std;
+
+const wxEventType wxEVT_SEARCH_UPDATE = wxNewEventType();
+
+SearchUpdate::SearchUpdate(const wxEventType &event, bool done) :
+wxNotifyEvent(event)
+{
+    m_done = done;
+}
+
+TransmitterSearch::TransmitterSearch(wxEvtHandler *dest) :
+m_condition(m_mutex)
+{
+    Reset();
+    m_resolution = 0.0005;  // 182 foot granularity
+    m_dest = dest;
+    m_log = NULL;
+    m_scale = 0.85;    // Estimated from Mt. Umunhum data
+    m_busy = false;
+    Create();  // wxThreadHelper
+    GetThread()->Run();
+}
+
+TransmitterSearch::~TransmitterSearch()
+{
+    GetThread()->Delete();
+}
+
+void TransmitterSearch::Reset()
+{
+    m_iterations = 0;
+    m_initialized = false;
+    m_solution = Spherical(0.0, 0.0);
+    m_log = NULL;
+    ClearStats();
+}
+
+void TransmitterSearch::ClearStats()
+{
+    m_histogram.Reset();
+}
+
+void *TransmitterSearch::Entry()
+{
+    wxLogDebug(_T("TransmitterSearch::Entry(): entered"));
+    m_mutex.Lock();
+
+       while (!GetThread()->TestDestroy())
+        if (m_condition.WaitTimeout(1000) == wxCOND_NO_ERROR)
+            background_solve();
+
+    m_mutex.Unlock();
+    wxLogDebug(_T("TransmitterSearch::Entry(): exited"));
+}
+
+void TransmitterSearch::background_solve()
+{
+    if (!m_log)
+        return;
+
+    m_iterations = 0;
+    int count = m_log->Count();
+    ClearStats();
+
+    m_busy = true;
+    if (count == 0)  // No data to solve from
+        return post_update(true);
+    
+    if (!m_initialized) { // Get initial solution from first sample, but only 
once
+        m_solution = m_log->Samples().begin()->Location();
+        m_initialized = true;
+    }
+
+    if (count == 1)
+        return post_update(true);
+
+    while(1) {
+        m_iterations = 0;
+        while (++m_iterations <= MaxIterations) {
+            wxMutexLocker locker(m_log->Mutex());
+            if (hillclimb(m_log->Samples())) {     // true return indicates 
solution of some sort achieved
+                m_histogram.Calc(m_log->Samples(), m_solution);
+                return post_update(true);
+            }
+        }
+        
+        // Max iterations reached, send interim solution
+        m_histogram.Calc(m_log->Samples(), m_solution);
+        post_update(false);
+    }    
+}
+
+void TransmitterSearch::post_update(bool done)
+{
+    SearchUpdate update(wxEVT_SEARCH_UPDATE, done);
+    wxPostEvent(m_dest, update);
+    m_busy = !done;
+}
+
+void TransmitterSearch::Solve(SampleLog *log)
+{
+    // FIXME: what if we get here while background thread is still busy?
+    if (m_log && (m_log != log))
+        wxLogError(_T("TransmitterSearch::Solve: supplied log different from 
current one."));
+        
+    m_log = log;
+    m_condition.Signal();
+}
+
+// Return value indicates solution of some sort achieved
+bool TransmitterSearch::hillclimb(vector<Sample> &samples)
+{
+    int nx, ny;
+    int min_x = 0, min_y = 0;
+    int num;
+    
+    Spherical trial;
+
+    float min_error;
+    float trial_error;
+            
+    // Initialize search with current solution
+    if (calc_trial_error(samples, m_solution, min_error) == 0.0) {
+        wxLogDebug(_T("TransmitterSearch::hillclimb: no enabled samples, 
returning"));
+        return true; // No enabled data points, we're done
+    }
+            
+    // Check if moving 'resolution' distance in one of four directions 
decreases error
+    for (nx = -1; nx < 2; nx++) {
+        trial.SetLongitude(m_solution.Longitude() + nx*m_resolution);
+        for (ny = -1; ny < 2; ny++) {
+            // Skip non-compass directions
+            if (nx == ny)
+                continue;
+            trial.SetLatitude(m_solution.Latitude() + ny*m_resolution);
+            calc_trial_error(samples, trial, trial_error);
+            if (trial_error < min_error) {
+                min_error = trial_error;
+                min_x = nx; min_y = ny;
+            }
+        }
+    }
+
+    // Indicate if solution achieved
+    if (min_x == 0 && min_y == 0)
+        return true;
+    else {
+        m_solution.SetLatitude(m_solution.Latitude()+min_y*m_resolution);
+        m_solution.SetLongitude(m_solution.Longitude()+min_x*m_resolution);
+        return false; // Make outer loop call us again
+    }
+}
+
+// Return value is number of enabled samples in vector
+float TransmitterSearch::calc_trial_error(const vector<Sample>&samples, 
+                                          const Spherical &trial, 
+                                          float &trial_error)
+{
+    float wsum = 0.0;
+    trial_error = 0.0;
+    float strength = 1.0;
+            
+    for (int i = 0; i < samples.size(); i++) {
+        const Sample &sample = samples[i];
+        
+        float angle, ierror, qerror;
+        sample.CalcError(trial, angle, ierror, qerror);
+
+        // Wrapped cauchy distribution
+        float p = m_scale;
+        float likelihood = (1-p*p)/(1+p*p-2*p*cos(angle*M_PI/180.0));
+
+        trial_error += -log(likelihood)*sample.Strength();
+        wsum += sample.Strength();
+    }    
+
+    if (wsum > 0.0)
+        trial_error = trial_error/wsum;
+
+    return wsum;
+}

Copied: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/search.h 
(from rev 3254, 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/search.h)
===================================================================
--- 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/search.h   
                            (rev 0)
+++ 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/search.h   
    2006-08-12 18:20:45 UTC (rev 3256)
@@ -0,0 +1,107 @@
+/*
+ Copyright 2006 Johnathan Corgan.
+ 
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+ 
+ This software 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 GNU Radio; see the file COPYING.  If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef __SEARCH_H__
+#define __SEARCH_H__
+
+// Application level includes
+#include "spherical.h"
+#include "samplelog.h"
+#include "histogram.h"
+
+// wxWidgets includes
+#include <wx/event.h>
+
+// System level includes
+#include <ctime>
+
+// Forward declarations
+class wxFile;
+class Sample;
+class TransmitterSearch;
+
+class SearchUpdate : public wxNotifyEvent
+{
+public:
+    SearchUpdate(const wxEventType &event, bool done);
+    virtual wxEvent *Clone() const { return new SearchUpdate(*this); }
+    bool m_done;
+};
+
+extern const wxEventType wxEVT_SEARCH_UPDATE;
+
+typedef void(wxEvtHandler::*SearchUpdateFunction)(SearchUpdate&);
+
+#define EVT_SEARCH_UPDATE(fn) \
+        DECLARE_EVENT_TABLE_ENTRY( \
+            wxEVT_SEARCH_UPDATE, -1, -1, \
+            (wxObjectEventFunction)(wxEventFunction)(SearchUpdateFunction)&fn, 
\
+            (wxObject *)NULL \
+        ),
+
+class TransmitterSearch : public wxThreadHelper
+{
+public:
+    TransmitterSearch(wxEvtHandler *dest);
+    ~TransmitterSearch();
+
+    void Solve(SampleLog *log);
+    bool HasSolution() { return m_log ? m_log->Count() > 1 : false; }
+    void Reset();
+    void ClearStats();
+    bool Busy() const { return m_busy; }
+    int Mode() const { return m_histogram.Mode(); }
+    float Mean() const { return m_histogram.Mean(); }
+    float Concentration() { return m_histogram.Concentration(); }
+
+    const ErrorHistogram &Histogram() { return m_histogram; }
+    Spherical GetEstimatedLocation() { return m_solution; }
+
+    virtual void *Entry();
+                                    
+private:
+    static const int MaxIterations = 20; // TODO: make configurable
+
+    bool hillclimb(std::vector<Sample> &samples);
+    float calc_trial_error(const std::vector<Sample> &samples, const Spherical 
&trial, 
+                           float &solution_error);
+
+    void background_solve();
+    void post_update(bool done);
+    
+    // Background processing
+    wxEvtHandler *m_dest;
+    wxMutex m_mutex;
+    wxCondition m_condition;
+    
+    // Solution state
+    SampleLog *m_log;
+    Spherical m_solution;
+    int m_iterations;
+    bool m_initialized;
+    bool m_busy;
+        
+    // Solution options
+    float m_scale;
+    float m_resolution;
+
+    // Estimated solution histogram
+    ErrorHistogram m_histogram;
+};
+
+#endif

Copied: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/serial.cc 
(from rev 3254, 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/serial.cpp)
===================================================================
--- 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/serial.cc  
                            (rev 0)
+++ 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/serial.cc  
    2006-08-12 18:20:45 UTC (rev 3256)
@@ -0,0 +1,216 @@
+/*
+ Copyright 2006 Johnathan Corgan.
+ 
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+ 
+ This software 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 GNU Radio; see the file COPYING.  If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#include "serial.h"
+
+#include <wx/log.h>
+
+#ifdef __WIN32__
+// I hate Windows.
+#else
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#endif
+
+wxArrayString EnumerateSerialPorts()
+{
+    wxArrayString result;
+    
+#ifdef __WIN32__
+    wxString port;
+    for (int i = 1; i <= 8; i++) {
+        port.Printf("COM%i", i);
+        result.Add(port);
+    }
+#else
+    result.Add(_T("/dev/ttyS0"));
+    result.Add(_T("/dev/ttyS1"));
+    result.Add(_T("/dev/ttyS2"));
+    result.Add(_T("/dev/ttyS3"));
+    result.Add(_T("/dev/ttyUSB0"));
+    result.Add(_T("/dev/ttyUSB1"));
+#endif
+
+    return result;
+}
+
+SerialPort::SerialPort(wxString &port)
+{
+    wxLogDebug(_T("SerialPort::SerialPort(): %s"), port.c_str());
+    m_port = port;
+    m_opened = false;
+#ifdef __WIN32__
+    m_handle = INVALID_HANDLE_VALUE;
+#else
+    m_fd = -1;
+#endif
+}
+
+bool SerialPort::Open(int speed)
+{
+    wxLogDebug(_T("SerialPort::Open: %i baud"), speed);
+    if (m_opened) {
+        wxLogWarning(_T("SerialPort::Open: called on already opened object."));
+        return false;
+    }
+
+#ifdef __WIN32__
+    m_handle = CreateFile(m_port.c_str(), 
+                          GENERIC_READ | GENERIC_WRITE,
+                          0, 
+                          NULL, 
+                          OPEN_EXISTING, 
+                          0, 
+                          NULL);
+    if (m_handle == INVALID_HANDLE_VALUE) {
+        wxLogError("SerialPort::Open: CreateFile() failed");
+        return false;
+    }
+
+    DCB dcb;
+    if (!GetCommState(m_handle, &dcb)) {
+        wxLogError("SerialPort::Open: GetCommState failed.");
+        CloseHandle(m_handle);
+        return false;
+    }
+
+    dcb.BaudRate = speed;
+    dcb.ByteSize = 8;
+    dcb.StopBits = ONESTOPBIT;
+    dcb.Parity = NOPARITY;
+    dcb.fBinary = TRUE;
+    dcb.fParity = FALSE;
+
+    if (!SetCommState(m_handle, &dcb)) {
+        wxLogError("SerialPort::Open: SetCommState failed.");
+        CloseHandle(m_handle);
+        return false;
+    }
+    
+    COMMTIMEOUTS timeouts;
+    if (!GetCommTimeouts(m_handle, &timeouts)) {
+        wxLogError("SerialPort::Open: GetCommTimeouts failed.");
+        CloseHandle(m_handle);
+        return false;
+    }
+
+    timeouts.ReadIntervalTimeout = MAXDWORD;
+    timeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
+    timeouts.ReadTotalTimeoutConstant = 100;
+
+    if (!SetCommTimeouts(m_handle, &timeouts)) {
+        wxLogError("SerialPort::Open: SetCommTimeouts failed.");
+        CloseHandle(m_handle);
+        return false;
+    }
+
+    m_opened = true;
+#else
+    m_fd = open((char *)m_port.c_str(), O_RDWR|O_NONBLOCK);
+    if (m_fd < 0) {
+        wxLogError(_T("SerialPort::Open: open() returned %i"), m_fd);
+        return false;
+    }
+
+    if (!isatty(m_fd)) {
+        wxLogError(_T("SerialPort::Open: device %s is not a tty"), 
m_port.c_str());
+        close(m_fd);
+        return false;
+    }
+
+    if (tcgetattr(m_fd, &m_ttyset_old) != 0) {
+        wxLogError(_T("SerialPort::Open: failed to get port attributes"));
+        close(m_fd);
+        return false;
+    }
+
+    memcpy(&m_ttyset_new, &m_ttyset_old, sizeof(m_ttyset_new));
+       cfsetispeed(&m_ttyset_new, (speed_t)speed);
+       cfsetospeed(&m_ttyset_new, (speed_t)speed);
+       m_ttyset_new.c_cflag &= ~(PARENB|CRTSCTS); // Disable parity and 
flowcontrol
+       m_ttyset_new.c_cflag |= CS8|CREAD|CLOCAL;  // 8 bits, read, no modem 
status lines
+       m_ttyset_new.c_iflag = 0;
+       m_ttyset_new.c_oflag = ONLCR;              // Convert LF to CRLF on 
receive
+       m_ttyset_new.c_lflag = 0;
+
+       if (tcsetattr(m_fd, TCSANOW, &m_ttyset_new) != 0) {
+        wxLogError(_T("SerialPort::Open: failed to set port attributes"));
+        close(m_fd);
+           return false;
+    }
+
+    m_opened = true;
+#endif
+    return m_opened;
+}
+
+void SerialPort::Close()
+{
+    wxLogDebug(_T("SerialPort::Close()"));
+#ifdef __WIN32__
+    CloseHandle(m_handle);
+#else
+    if (m_opened >= 0) {
+        m_ttyset_old.c_cflag |= HUPCL;
+        tcsetattr(m_fd, TCSANOW, &m_ttyset_old);
+        close(m_fd);
+    }
+#endif
+
+    m_opened = false;
+}
+
+SerialPort::~SerialPort()
+{
+    wxLogDebug(_T("SerialPort::~SerialPort()"));
+
+    if (m_opened)
+        Close();
+}
+
+int SerialPort::RxReady()
+{
+    int count = 0;
+#ifdef __WIN32__
+    return 1; // No equivalent Win32 call, use read timeouts instead
+#else
+    if (m_fd < 0 || ioctl(m_fd, FIONREAD, &count) < 0)
+        return -1;
+#endif
+    return count;
+}
+
+int SerialPort::Read(char *buffer, int len)
+{
+    wxASSERT(buffer);
+    wxASSERT(len);
+
+    if (!m_opened)
+        return -1;
+        
+#ifdef __WIN32__
+    DWORD num;
+    if (ReadFile(m_handle, buffer, (DWORD)len, &num, NULL))
+        return num;
+    else
+        return -1;
+#else
+    return read(m_fd, buffer, len);
+#endif
+}

Copied: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/serial.h 
(from rev 3254, 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/serial.h)
===================================================================
--- 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/serial.h   
                            (rev 0)
+++ 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/serial.h   
    2006-08-12 18:20:45 UTC (rev 3256)
@@ -0,0 +1,56 @@
+/*
+ Copyright 2006 Johnathan Corgan.
+ 
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+ 
+ This software 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 GNU Radio; see the file COPYING.  If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef __SERIAL_H__
+#define __SERIAL_H__
+
+#include <wx/arrstr.h>
+
+#ifdef __WIN32__
+#include <windows.h>
+#else
+#include <termios.h>
+#endif
+
+wxArrayString EnumerateSerialPorts();
+
+class SerialPort
+{
+public:
+    SerialPort(wxString &port);
+    ~SerialPort();
+
+    bool Open(int speed);
+    bool IsOpened() { return m_opened; }
+    void Close();
+    int  RxReady();
+    int  Read(char *buffer, int len);
+            
+private:
+#ifdef __WIN32__
+    HANDLE m_handle;
+#else
+    int m_fd;
+    struct termios m_ttyset_old;
+    struct termios m_ttyset_new;
+#endif
+    wxString m_port;
+    bool m_opened;
+};
+
+#endif // __SERIAL_H__

Copied: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/settings.cpp
 (from rev 3254, 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/settings.cpp)
===================================================================
--- 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/settings.cpp
                           (rev 0)
+++ 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/settings.cpp
   2006-08-12 18:20:45 UTC (rev 3256)
@@ -0,0 +1,310 @@
+/*
+ Copyright 2006 Johnathan Corgan.
+ 
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+ 
+ This software 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 GNU Radio; see the file COPYING.  If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+// Application level includes
+#include "settings.h"
+
+HunterSettings::HunterSettings()
+{
+       cfg = new wxConfig(_T("TransmitterHunter"));
+}
+
+HunterSettings::~HunterSettings()
+{
+       if (cfg) {
+               cfg->Flush();
+               delete cfg;
+       }
+}
+
+wxSize HunterSettings::GetWindowSize()
+{
+    long width, height;
+    if (cfg) {
+        cfg->Read(wxT("Application/Width"), &width, 1024);
+        cfg->Read(wxT("Application/Height"), &height, 768);
+    }
+    
+    return wxSize((int)width, (int)height);
+}
+
+void HunterSettings::SetWindowSize(wxSize size)
+{
+    if (cfg) {
+        cfg->Write(wxT("Application/Width"), size.GetWidth());
+        cfg->Write(wxT("Application/Height"), size.GetHeight());
+    }
+}
+
+int HunterSettings::GetWindowXPos()
+{
+       long x;
+       if (cfg)
+               cfg->Read(wxT("Application/XPos"), &x, 0);
+
+       return (int)x;
+}
+
+void HunterSettings::SetWindowXPos(int x)
+{
+    if (cfg)
+        cfg->Write(wxT("Application/XPos"), (long)x);
+}
+
+int HunterSettings::GetWindowYPos()
+{
+       long y;
+       if (cfg)
+               cfg->Read(wxT("Application/YPos"), &y, 0);
+
+       return (int)y;
+}
+
+void HunterSettings::SetWindowYPos(int y)
+{
+    if (cfg)
+        cfg->Write(wxT("Application/YPos"), (long)y);
+}
+
+bool HunterSettings::GetDopplerAutostart()
+{
+       bool start = false;
+       if (cfg)
+               cfg->Read(wxT("Doppler/Autostart"), &start, false);
+
+       return start;
+}
+
+void HunterSettings::SetDopplerAutostart(bool start)
+{
+       if (cfg)
+               cfg->Write(wxT("Doppler/Autostart"), start);
+}
+
+int HunterSettings::GetDopplerFilter()
+{
+       long filtering;
+       if (cfg)
+               cfg->Read(wxT("Doppler/FilterLevel"), &filtering, 20);
+
+       return (int)filtering;
+}
+
+void HunterSettings::SetDopplerFilter(int level)
+{
+    if (cfg)
+        cfg->Write(wxT("Doppler/FilterLevel"), (long)level);
+}
+
+int HunterSettings::GetDopplerRotation()
+{
+       long rate;
+       if (cfg)
+               cfg->Read(wxT("Doppler/Rotation"), &rate, 4);
+
+       return (int)rate;
+}
+
+void HunterSettings::SetDopplerRotation(int rate)
+{
+    if (cfg)
+        cfg->Write(wxT("Doppler/Rotation"), (long)rate);
+}
+
+float HunterSettings::GetDopplerCalibration(int rate)
+{
+       double calibration;
+       wxString key;
+
+       key.Printf(_T("Doppler/Rate%iCalibration"), rate);
+       if (cfg)
+               cfg->Read(key, &calibration, 0.0);
+       return (float)calibration;
+}
+
+void HunterSettings::SetDopplerCalibration(int rate, float offset)
+{
+       wxString key;
+       key.Printf(_T("Doppler/Rate%iCalibration"), rate);
+       if (cfg)
+               cfg->Write(key, offset);
+}
+
+bool HunterSettings::GetGPSAutostart()
+{
+       bool start = false;
+       if (cfg)
+               cfg->Read(wxT("GPS/Autostart"), &start, false);
+
+       return start;
+}
+
+void HunterSettings::SetGPSAutostart(bool start)
+{
+       if (cfg)
+               cfg->Write(wxT("GPS/Autostart"), start);
+}
+
+wxString HunterSettings::GetGPSDeviceName()
+{
+    wxString name;
+    if (cfg)
+        cfg->Read(wxT("GPS/DeviceName"), &name);
+        
+    return name; 
+}
+
+void HunterSettings::SetGPSDeviceName(wxString &name)
+{
+    if (cfg)
+        cfg->Write(wxT("GPS/DeviceName"), name);
+}
+
+bool HunterSettings::GetCalibrationAffectAllRates()
+{
+       bool val = false;
+       if (cfg)
+               cfg->Read(wxT("Calibration/AffectAllRates"), &val, false);
+
+       return val;
+}
+
+void HunterSettings::SetCalibrationAffectAllRates(bool val)
+{
+       if (cfg)
+               cfg->Write(wxT("Calibration/AffectAllRates"), val);
+}
+
+double HunterSettings::GetKnownTransmitterLongitude()
+{
+    double lon;
+    if (cfg)
+        cfg->Read(wxT("KnownTransmitter/Longitude"), &lon);
+        
+    return lon;
+}
+
+void HunterSettings::SetKnownTransmitterLongitude(double lon)
+{
+    if (cfg)
+        cfg->Write(wxT("KnownTransmitter/Longitude"), lon);
+}
+
+double HunterSettings::GetKnownTransmitterLatitude()
+{
+    double lat;
+    if (cfg)
+        cfg->Read(wxT("KnownTransmitter/Latitude"), &lat);
+        
+    return lat;
+}
+
+void HunterSettings::SetKnownTransmitterLatitude(double lat)
+{
+    if (cfg)
+        cfg->Write(wxT("KnownTransmitter/Latitude"), lat);
+}
+
+bool HunterSettings::GetUseKnownTransmitter()
+{
+       bool use = false;
+       if (cfg)
+               cfg->Read(wxT("KnownTransmitter/Use"), &use, false);
+
+       return use;
+}
+
+void HunterSettings::SetUseKnownTransmitter(bool use)
+{
+    if (cfg)
+        cfg->Write(wxT("KnownTransmitter/Use"), use);
+}
+
+int HunterSettings::GetDisplayOrientation()
+{
+       long x;
+       if (cfg)
+               cfg->Read(wxT("Display/Orientation"), &x, 0);
+
+       return (int)x;
+}
+
+void HunterSettings::SetDisplayOrientation(int orientation)
+{
+    if (cfg)
+        cfg->Write(wxT("Display/Orientation"), (long)orientation);
+}
+
+bool HunterSettings::GetDisplayDoppler()
+{
+       bool val = false;
+       if (cfg)
+               cfg->Read(wxT("Display/DopplerPointer"), &val, false);
+
+       return val;
+}
+
+void HunterSettings::SetDisplayDoppler(bool val)
+{
+    if (cfg)
+        cfg->Write(wxT("Display/DopplerPointer"), val);
+}
+
+bool HunterSettings::GetDisplayKnown()
+{
+       bool val = false;
+       if (cfg)
+               cfg->Read(wxT("Display/KnownPointer"), &val, false);
+
+       return val;
+}
+
+void HunterSettings::SetDisplayKnown(bool val)
+{
+    if (cfg)
+        cfg->Write(wxT("Display/KnownPointer"), val);
+}
+
+bool HunterSettings::GetDisplayEstimated()
+{
+       bool val = false;
+       if (cfg)
+               cfg->Read(wxT("Display/EstimatedPointer"), &val, false);
+
+       return val;
+}
+
+void HunterSettings::SetDisplayEstimated(bool val)
+{
+    if (cfg)
+        cfg->Write(wxT("Display/EstimatedPointer"), val);
+}
+
+wxString HunterSettings::GetWorkingDirectory()
+{
+    wxString str(_T("."));
+    if (cfg)
+        return cfg->Read(wxT("Application/WorkingDirectory"), str);
+    return str;
+}
+
+void HunterSettings::SetWorkingDirectory(const wxString &dir)
+{
+    if (cfg)
+        cfg->Write(wxT("Application/WorkingDirectory"), dir);
+}

Copied: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/settings.h 
(from rev 3254, 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/settings.h)
===================================================================
--- 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/settings.h 
                            (rev 0)
+++ 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/settings.h 
    2006-08-12 18:20:45 UTC (rev 3256)
@@ -0,0 +1,101 @@
+/*
+ Copyright 2006 Johnathan Corgan.
+ 
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+ 
+ This software 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 GNU Radio; see the file COPYING.  If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef __SETTINGS_H__
+#define __SETTINGS_H__
+
+// wxWidgets includes
+#include <wx/config.h>
+#include <wx/gdicmn.h>
+
+class HunterSettings
+{
+public:
+    HunterSettings();
+    ~HunterSettings();
+    
+    // Main window size
+    wxSize GetWindowSize();
+    void SetWindowSize(wxSize size);
+
+    // Main window position
+    int GetWindowXPos();
+    void SetWindowXPos(int x);
+    int GetWindowYPos();
+    void SetWindowYPos(int y);
+
+    // Autostart doppler on application bringup
+    bool GetDopplerAutostart();
+    void SetDopplerAutostart(bool val);
+
+    // Doppler filter value
+    int GetDopplerFilter();
+    void SetDopplerFilter(int level);
+
+    // Doppler filter value
+    int GetDopplerRotation();
+    void SetDopplerRotation(int rate);
+
+    // Doppler calibration values
+    float GetDopplerCalibration(int rate);
+    void SetDopplerCalibration(int rate, float offset);
+        
+    // Autostart GPS on application bringup
+    bool GetGPSAutostart();
+    void SetGPSAutostart(bool val);
+
+    // GPS interface device
+    wxString GetGPSDeviceName();
+    void SetGPSDeviceName(wxString &name);
+
+    // Calibration adjust affects all rates
+    bool GetCalibrationAffectAllRates();
+    void SetCalibrationAffectAllRates(bool val);
+
+    // Known transmitter location
+    double GetKnownTransmitterLongitude();
+    void SetKnownTransmitterLongitude(double lon);
+    double GetKnownTransmitterLatitude();
+    void SetKnownTransmitterLatitude(double lat);
+    bool GetUseKnownTransmitter();
+    void SetUseKnownTransmitter(bool use);
+
+    // Display Orientation
+    int GetDisplayOrientation();
+    void SetDisplayOrientation(int orientation);
+
+    // Display Doppler Bearing
+    bool GetDisplayDoppler();
+    void SetDisplayDoppler(bool val);
+
+    // Display Known Bearing
+    bool GetDisplayKnown();
+    void SetDisplayKnown(bool val);
+
+    // Display Estimated Bearing
+    bool GetDisplayEstimated();
+    void SetDisplayEstimated(bool val);
+
+    wxString GetWorkingDirectory();
+    void SetWorkingDirectory(const wxString &dir);
+
+private:
+    wxConfig *cfg;
+};
+
+#endif // __SETTINGS_H__

Copied: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/spherical.cc
 (from rev 3254, 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/spherical.cpp)
===================================================================
--- 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/spherical.cc
                           (rev 0)
+++ 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/spherical.cc
   2006-08-12 18:20:45 UTC (rev 3256)
@@ -0,0 +1,76 @@
+/*
+ Copyright 2006 Johnathan Corgan.
+ 
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+ 
+ This software 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 GNU Radio; see the file COPYING.  If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+// Application level includes
+#include "spherical.h"
+#include "util.h"
+
+Spherical::Spherical()
+{
+    m_latitude = 0.0;
+    m_longitude = 0.0;
+}
+
+Spherical::Spherical(double latitude, double longitude)
+{
+    m_latitude = latitude;
+    m_longitude = longitude;
+}
+
+Spherical::Spherical(wxString latitude, wxString longitude)
+{
+    latitude.ToDouble(&m_latitude);
+    longitude.ToDouble(&m_longitude);
+}
+
+void Spherical::SetLatitude(double latitude)
+{
+    m_latitude = latitude;  // TODO: error handle
+}
+
+void Spherical::SetLongitude(double longitude)
+{
+    m_longitude = longitude;
+}
+
+double range(const Spherical &from, const Spherical &to)
+{
+    double lat1 = to_radians(from.m_latitude);
+    double lon1 = to_radians(from.m_longitude);
+
+    double lat2 = to_radians(to.m_latitude);
+    double lon2 = to_radians(to.m_longitude);
+    
+    double n1 = sin((lat1-lat2)/2);
+    double n2 = sin((lon1-lon2)/2);   
+    double distance = 2*asin(sqrt(n1*n1 + cos(lat1)*cos(lat2)*n2*n2));
+
+    return to_degrees(distance)*60.0*1.15077945; // Conversion to statute miles
+
+}
+
+double bearing(const Spherical &from, const Spherical &to)
+{
+    double lat1 = to_radians(from.m_latitude);
+    double lon1 = to_radians(from.m_longitude);
+    double lat2 = to_radians(to.m_latitude);
+    double lon2 = to_radians(to.m_longitude);
+
+    double bearing = atan2(-sin(lon1-lon2)*cos(lat2), 
cos(lat1)*sin(lat2)-sin(lat1)*cos(lat2)*cos(lon1-lon2));
+    return degree_normalize(to_degrees(bearing));
+}

Copied: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/spherical.h
 (from rev 3254, 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/spherical.h)
===================================================================
--- 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/spherical.h
                            (rev 0)
+++ 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/spherical.h
    2006-08-12 18:20:45 UTC (rev 3256)
@@ -0,0 +1,45 @@
+/*
+ Copyright 2006 Johnathan Corgan.
+ 
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+ 
+ This software 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 GNU Radio; see the file COPYING.  If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef __SPHERICAL_H__
+#define __SPHERICAL_H__
+
+// wxWidgets includes
+#include <wx/string.h>
+
+class Spherical
+{
+public:
+    Spherical();
+    Spherical(double latitude, double longitude);
+    Spherical(wxString latitude, wxString longitude);
+    
+    double Latitude() const { return m_latitude; }
+    double Longitude() const { return m_longitude; }
+    void SetLatitude(double latitude);
+    void SetLongitude(double longitude);    
+    
+private:
+    double m_latitude;
+    double m_longitude;
+
+    friend double range(const Spherical &from, const Spherical &to);
+    friend double bearing(const Spherical &from, const Spherical &to);
+};
+
+#endif // __SPHERICAL_H__

Copied: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/tactical.cc
 (from rev 3254, 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/tactical.cpp)
===================================================================
--- 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/tactical.cc
                            (rev 0)
+++ 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/tactical.cc
    2006-08-12 18:20:45 UTC (rev 3256)
@@ -0,0 +1,142 @@
+/*
+ Copyright 2006 Johnathan Corgan.
+ 
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+ 
+ This software 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 GNU Radio; see the file COPYING.  If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+// Application level includes
+#include "tactical.h"
+
+// wxWidgets includes
+#include <wx/dc.h>
+#include <wx/dcclient.h>
+#include <wx/log.h>
+
+// System level includes
+#include <cmath>
+
+// Event table for TacticalPanel
+BEGIN_EVENT_TABLE(TacticalPanel, wxPanel)
+    EVT_PAINT(TacticalPanel::OnPaint)
+    EVT_SIZE(TacticalPanel::OnSize)
+END_EVENT_TABLE()
+
+TacticalPanel::TacticalPanel(wxWindow *parent) :
+wxPanel(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize)
+{
+    m_orientation = TrackUp;
+    m_display_doppler = false;
+    m_display_known = false;
+    m_display_estimated = false;
+    
+       m_heading = 0.0;
+       m_doppler_bearing = -1.0;
+    m_estimated_bearing = -1.0;
+    m_actual_bearing = -1.0;
+    
+       SetBackgroundColour(*wxBLACK);
+}
+
+void TacticalPanel::OnPaint(wxPaintEvent &event)
+{
+    wxPaintDC dc(this);
+       drawPanel(dc);
+}
+
+void TacticalPanel::drawPanel(wxDC &dc)
+{
+    float radians;
+    float brg = 0;
+    
+    // Draw circle
+       dc.SetPen(wxPen(*wxRED, 2, wxSOLID));
+       dc.SetBrush(wxBrush(*wxBLACK, wxTRANSPARENT));
+    dc.DrawCircle(m_center, m_radius);
+
+    // Calculate end of doppler bearing line
+    // Doppler bearings are relative and must be adjusted for north up display
+    wxPoint doppler_tip = m_center;
+    if (m_doppler_bearing >= 0.0) {
+        brg = m_doppler_bearing;
+        if (m_orientation == NorthUp) {
+            brg += m_heading;
+            if (brg >= 360.0)
+                brg -= 360.0;
+        }
+       radians = brg*M_PI/180.0;
+        doppler_tip = wxPoint((int)(m_center.x+sin(radians)*m_radius*0.95),
+                     (int)(m_height-(m_center.y+cos(radians)*m_radius*0.95)));
+    }
+        
+    // Calculate end of actual bearing line
+    // Actual bearings are absolute and must be adjusted for track up display
+    wxPoint actual_tip = m_center;
+    if (m_actual_bearing >= 0.0) {
+        brg = m_actual_bearing;
+        if (m_orientation == TrackUp) {
+            brg -= m_heading;
+            if (brg < 0.0)
+                brg += 360.0;
+        }
+        radians = brg*M_PI/180.0;
+        actual_tip = wxPoint((int)(m_center.x+sin(radians)*m_radius*0.95),
+                    (int)(m_height-(m_center.y+cos(radians)*m_radius*0.95)));
+    }
+
+    // Calculate end of estimated bearing line
+    // Estimated bearings are absolute and must be adjusted for track up 
display
+    wxPoint estimated_tip = m_center;
+    if (m_estimated_bearing >= 0.0) {
+        brg = m_estimated_bearing;
+        if (m_orientation == TrackUp) {
+            brg -= m_heading;
+            if (brg < 0.0)
+                brg += 360.0;
+        }
+        radians = brg*M_PI/180.0;
+        estimated_tip = wxPoint((int)(m_center.x+sin(radians)*m_radius*0.95),
+                    (int)(m_height-(m_center.y+cos(radians)*m_radius*0.95)));
+    }
+
+    if (m_display_known) {
+       dc.SetPen(wxPen(*wxBLUE, 10, wxSOLID));
+       dc.DrawLine(m_center, actual_tip);
+    }
+    
+    if (m_display_estimated) {
+       dc.SetPen(wxPen(*wxWHITE, 10, wxSOLID));
+        dc.DrawLine(m_center, estimated_tip);
+       }
+
+    if (m_display_doppler) {
+       dc.SetPen(wxPen(*wxGREEN, 10, wxSOLID));
+       dc.DrawLine(m_center, doppler_tip);
+    }
+}
+
+void TacticalPanel::OnSize(wxSizeEvent &event)
+{
+    GetClientSize(&m_width, &m_height);
+    m_center = wxPoint(m_width/2, m_height/2);
+
+       // Circle at 95% of window size
+    if (m_width > m_height)
+        m_radius = m_height/2;
+    else
+        m_radius = m_width/2;
+    m_radius = (int)(m_radius*0.95);
+        
+    Refresh();
+}

Copied: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/tactical.h 
(from rev 3254, 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/tactical.h)
===================================================================
--- 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/tactical.h 
                            (rev 0)
+++ 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/tactical.h 
    2006-08-12 18:20:45 UTC (rev 3256)
@@ -0,0 +1,73 @@
+/*
+ Copyright 2006 Johnathan Corgan.
+ 
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+ 
+ This software 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 GNU Radio; see the file COPYING.  If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef __TACTICAL_H__
+#define __TACTICAL_H__
+
+// wxWidgets includes
+#include <wx/panel.h>
+
+enum Orientation {
+    TrackUp,
+    NorthUp
+};
+
+class TacticalPanel : public wxPanel
+{
+public:
+    TacticalPanel(wxWindow *parent);
+
+    // Event handlers
+    void OnPaint(wxPaintEvent &event);
+    void OnSize(wxSizeEvent &event);
+
+    // Configuration
+    void SetOrientation(Orientation orientation) { m_orientation = 
orientation; Refresh(); }
+    void SetDisplayDoppler(bool display) { m_display_doppler = display; 
Refresh(); }
+    void SetDisplayKnown(bool display) { m_display_known = display; Refresh(); 
}
+    void SetDisplayEstimated(bool display) { m_display_estimated = display; 
Refresh(); }
+    
+    // State updates
+    void SetHeading(float heading) { m_heading = heading; Refresh(); }
+    void SetDopplerBearing(float bearing) { m_doppler_bearing = bearing; 
Refresh(); }
+    void SetEstimatedBearing(float bearing) { m_estimated_bearing = bearing; 
Refresh(); }
+    void SetActualBearing(float bearing) { m_actual_bearing = bearing; 
Refresh(); }
+    
+private:
+    Orientation m_orientation;
+    bool  m_display_doppler;
+    bool  m_display_known;
+    bool  m_display_estimated;
+    
+    float m_heading;
+    float m_doppler_bearing;
+    float m_estimated_bearing;
+    float m_actual_bearing;
+    
+    void drawPanel(wxDC &dc);
+
+    // Window size derived parameters
+    wxPoint m_center;
+    int m_width;
+    int m_height;
+    int m_radius;
+    
+    DECLARE_EVENT_TABLE();
+};
+
+#endif // __TACTICAL_H__

Copied: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/util.h 
(from rev 3254, 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/util.h)
===================================================================
--- gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/util.h 
                        (rev 0)
+++ gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/src/util.h 
2006-08-12 18:20:45 UTC (rev 3256)
@@ -0,0 +1,79 @@
+/*
+ Copyright 2006 Johnathan Corgan.
+ 
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+ 
+ This software 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 GNU Radio; see the file COPYING.  If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef __UTIL_H__
+#define __UTIL_H__
+
+// System level includes
+#include <cmath>
+
+inline double limit(double x, double lower, double upper)
+{
+    if (x < lower)
+        return lower;
+    else if (x > upper)
+        return upper;
+    else
+        return x;
+}
+
+inline int limit(int x, int lower, int upper)
+{
+    if (x < lower)
+        return lower;
+    else if (x > upper)
+        return upper;
+    else
+        return x;
+}
+
+inline double degree_normalize(double degrees)
+{
+    if (degrees >= 360.0)
+        return degrees - 360.0;
+    else if (degrees < 0.0)
+        return degrees + 360.0;
+    else
+        return degrees;
+}
+
+inline int degree_normalize(int degrees)
+{
+    if (degrees >= 360)
+        return degrees - 360;
+    else if (degrees < 0)
+        return degrees + 360;
+    else
+        return degrees;
+}
+
+inline double to_radians(double degrees)
+{
+    return degrees/180.0*M_PI;
+}
+
+inline double to_degrees(double radians)
+{
+    return radians/M_PI*180.0;
+}
+
+#define LOGFUNCTION wxLogDebug("%s", __PRETTY_FUNCTION__)
+#define LOGFUNCTIONENTRY wxLogDebug("%s: entered", __PRETTY_FUNCTION__)
+#define LOGFUNCTIONEXIT wxLogDebug("%s: exited", __PRETTY_FUNCTION__)
+
+#endif // __UTIL_H__

Deleted: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/tactical.cpp

Deleted: 
gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/tactical.h

Deleted: gnuradio/branches/developers/jcorgan/ezdop/ezdop/src/host/hunter/util.h





reply via email to

[Prev in Thread] Current Thread [Next in Thread]