From 36c175fb855d11d09d5418afa83dcc7a6924efac Mon Sep 17 00:00:00 2001
From: jcorgan <jcorgan@221aa14e-8319-0410-a670-987f0aec2ac5>
Date: Sun, 3 Sep 2006 23:46:01 +0000
Subject: Merged branch jcorgan/wip into trunk.

git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@3471 221aa14e-8319-0410-a670-987f0aec2ac5
---
 ezdop/src/host/ezdop/ezdop.cc             |  21 +-
 ezdop/src/host/ezdop/ezdop.h              |   2 +-
 ezdop/src/host/hunter/config/hunter_wx.m4 |   4 +-
 ezdop/src/host/hunter/configure.ac        |   2 +-
 ezdop/src/host/hunter/src/Makefile.am     |  16 +-
 ezdop/src/host/hunter/src/doppler.cc      | 358 ++++++------------------------
 ezdop/src/host/hunter/src/doppler.h       |  51 ++---
 ezdop/src/host/hunter/src/hunter.cc       |  31 ++-
 ezdop/src/host/hunter/src/search.cc       |   8 +-
 ezdop/src/host/hunter/src/serial.cc       |   6 +-
 ezdop/src/host/tests/dopper.cc            |   4 +-
 11 files changed, 138 insertions(+), 365 deletions(-)

(limited to 'ezdop/src')

diff --git a/ezdop/src/host/ezdop/ezdop.cc b/ezdop/src/host/ezdop/ezdop.cc
index 43a70dacb5..99997fedf9 100644
--- a/ezdop/src/host/ezdop/ezdop.cc
+++ b/ezdop/src/host/ezdop/ezdop.cc
@@ -22,6 +22,9 @@
 // Application specific includes
 #include "ezdop.h"
 
+// Boost includes
+#include <boost/scoped_array.hpp>
+
 // System includes (FIXME: autoconf these)
 #include <cassert>
 #include <cstdio>
@@ -219,26 +222,27 @@ int ezdop::read_raw(unsigned char *buffer, unsigned int length)
     return rd;
 }
 
-int ezdop::read_iq(complex<float> *buffer, unsigned int samples)
+typedef boost::scoped_array<unsigned char> unsigned_char_scoped_array;
+
+int ezdop::read_iq(complex<float> *buffer, unsigned int samples, float &volume)
 {
     assert(d_online);
     assert(d_device);
     assert(buffer);
 
     // 4 phases, d_rate samples per phase, 2 bytes per sample
-    int bufsize = 8*d_rate*samples;
-    unsigned char *raw = new unsigned char[bufsize];
+    int raw_size = 8*d_rate*samples;
+    unsigned_char_scoped_array raw(new unsigned char[raw_size]);
 
     // Read until required bytes are read. Will block until bytes arrive.
     int rd = 0;
-    while (rd < bufsize)
-        rd += read_raw(&raw[rd], bufsize-rd);
+    while (rd < raw_size)
+        rd += read_raw(&raw[rd], raw_size-rd);
 
     // Iterate through read bytes and invoke state machine
     int i = 0, j = 0;   // i index inputs, j indexes outputs
-    unsigned char ant;
 
-    while (i < bufsize) {
+    while (i < raw_size) {
         unsigned char ch = raw[i++];
         if (d_state == ST_LO) {
             d_val = ch;                     // Save lo byte
@@ -272,6 +276,7 @@ int ezdop::read_iq(complex<float> *buffer, unsigned int samples)
             d_in_phase -= d_val;
         else if (d_ant == 1)            // -Q
             d_quadrature -= d_val;
+
         d_val = 0;
     
         // Update expected antenna and sequence
@@ -292,6 +297,6 @@ int ezdop::read_iq(complex<float> *buffer, unsigned int samples)
         d_state = ST_LO;  // Switch states
     };
 
-    delete raw;
+    volume = 0.0;
     return j;
 }
diff --git a/ezdop/src/host/ezdop/ezdop.h b/ezdop/src/host/ezdop/ezdop.h
index b4ce1a454b..c40178c0bc 100644
--- a/ezdop/src/host/ezdop/ezdop.h
+++ b/ezdop/src/host/ezdop/ezdop.h
@@ -57,7 +57,7 @@ public:
     int read_raw(unsigned char *buffer, unsigned int length);
 
     // Read synced, downconverted I and Q samples, one per rotation
-    int read_iq(complex<float> *buffer, unsigned int samples);
+    int read_iq(complex<float> *buffer, unsigned int samples, float &volume);
 
     // Status
     bool is_online() const { return d_online; }
diff --git a/ezdop/src/host/hunter/config/hunter_wx.m4 b/ezdop/src/host/hunter/config/hunter_wx.m4
index 5d6dd08e75..ffee16a59f 100644
--- a/ezdop/src/host/hunter/config/hunter_wx.m4
+++ b/ezdop/src/host/hunter/config/hunter_wx.m4
@@ -4,8 +4,8 @@ AC_DEFUN([HUNTER_WX], [
 		AC_MSG_ERROR(["wxWidgets is required, not found, stop."])
 	fi
 
-	WX_FLAGS=`$WXCONFIG --cflags`
-	WX_LIBS=`$WXCONFIG --libs`
+	WX_FLAGS=`$WXCONFIG --debug --cflags`
+	WX_LIBS=`$WXCONFIG --debug --libs`
 	AC_SUBST(WX_FLAGS)
 	AC_SUBST(WX_LIBS)
 ])
diff --git a/ezdop/src/host/hunter/configure.ac b/ezdop/src/host/hunter/configure.ac
index b6bd4cf7ee..b0af6cba05 100644
--- a/ezdop/src/host/hunter/configure.ac
+++ b/ezdop/src/host/hunter/configure.ac
@@ -32,7 +32,7 @@ AC_CHECK_FUNCS([modf sqrt])
 
 # Application specific checks
 HUNTER_WX
-HUNTER_FTDI
+#HUNTER_FTDI
 
 AC_CONFIG_FILES([ \
     Makefile
diff --git a/ezdop/src/host/hunter/src/Makefile.am b/ezdop/src/host/hunter/src/Makefile.am
index d1fe5eec23..392b79eff4 100644
--- a/ezdop/src/host/hunter/src/Makefile.am
+++ b/ezdop/src/host/hunter/src/Makefile.am
@@ -33,10 +33,18 @@ hunter_SOURCES = \
                  spherical.cc \
                  tactical.cc
 
+# FIXME: put in config macro
+EZDOP_LIBS = -L/usr/local/lib -lezdop
+
 hunter_CXXFLAGS = $(WX_FLAGS)
 hunter_LDADD = \
-    $(FTDI_LIBS) \
-    $(WX_LIBS)
+    $(WX_LIBS) \
+    $(EZDOP_LIBS)
+
+BUILT_SOURCES = \
+    $(top_builddir)/src/resource.cc
     
-resource.cc: hunter.xrc
-	wxrc -c -o resource.cc hunter.xrc
+$(top_builddir)/src/resource.cc: hunter.xrc
+	wxrc -c -o $(top_builddir)/src/resource.cc $(top_srcdir)/src/hunter.xrc
+
+MOSTLYCLEANFILES = $(BUILT_SOURCES)
\ No newline at end of file
diff --git a/ezdop/src/host/hunter/src/doppler.cc b/ezdop/src/host/hunter/src/doppler.cc
index 1e7b3cf49a..99b5aa6164 100644
--- a/ezdop/src/host/hunter/src/doppler.cc
+++ b/ezdop/src/host/hunter/src/doppler.cc
@@ -25,14 +25,18 @@
 #include <wx/log.h>
 #include <wx/frame.h>
 
+// Boost includes
+#include <boost/scoped_array.hpp>
+
 // System level includes
 #include <cmath>
 
+// TODO: read from ezdop.h
 #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 QUANTUM         0.2        // Sample period in seconds
 #define DEFAULT_FILTER_LEVEL 20
 
 #define NORMALIZEPHASE(x) \
@@ -80,7 +84,7 @@ ExitCode DopplerBackground::Entry()
 
     m_running = true;
 	while (!TestDestroy()) {
-	    if (m_doppler->Sample((int)(QUANTUM*SAMPLERATE), in_phase, quadrature, volume)) {
+	    if (m_doppler->Sample(in_phase, quadrature, volume)) {
     	    EZDopplerUpdate update(wxEVT_DOPPLER_UPDATE, in_phase, quadrature, volume);
 	        wxPostEvent(m_dest, update);
         }
@@ -93,209 +97,66 @@ 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_phase = complex<float>(0.0, 0.0);
+    m_output = complex<float>(0.0, 0.0);
+    m_alpha = complex<float>(0.0, 0.0);
+    m_beta = complex<float>(0.0, 0.0);
+
     m_offset = 0.0;
+    m_angle = 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
-
+    m_ezdop = ezdop_sptr(new ezdop());
+    m_selected_rate = DEFAULT_SELECTED_ROTATION_RATE;
 }
 
 EZDoppler::~EZDoppler()
 {
-    if (m_online) {
+    if (m_ezdop->is_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)
+    m_ezdop->init();
+    if (m_ezdop->is_online())
         Reset();
 
-    return m_online;
- }
+    return m_ezdop->is_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;	
+    return m_ezdop->is_online();
 }
 
 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;
+    return m_ezdop->reset();
 }
 
 bool EZDoppler::Start()
 {
-    wxASSERT(m_online);
-    // TODO: flush stream data
-
-    if (!send_byte(EZDOP_CMD_ROTATE) || !send_byte(EZDOP_CMD_STREAM))
+    if (!(m_ezdop->rotate() && m_ezdop->stream()))
         return false;
         
     m_thread = new DopplerBackground(m_gui, this);
@@ -304,9 +165,6 @@ bool EZDoppler::Start()
 
 bool EZDoppler::Stop()
 {
-    wxASSERT(m_online);
-    // TODO: flush stream data
-
     if (m_thread && m_thread->IsRunning()) {
         m_thread->Delete();
         while (m_thread->IsRunning()) {
@@ -315,172 +173,85 @@ bool EZDoppler::Stop()
     }
     
     m_thread = NULL;
-    return (send_byte(EZDOP_CMD_STROFF) && send_byte(EZDOP_CMD_STOP));
+    return (m_ezdop->stop_streaming() && m_ezdop->stop_rotating());
 }
 
 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;
+    wxLogDebug(_T("EZDoppler::SelectRotationRate: %i %i"), n, (int)(2000/rotation_rates[n]));
+    m_selected_rate = n;
+    return m_ezdop->set_rate(2000/rotation_rates[n]);
 }
 
-int EZDoppler::GetSelectedRotationRate()
+int EZDoppler::GetRotationRate()
 {
     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;
+    float beta = 30.0/(n*m_ezdop->rate()); // Empirically determined
+
+    m_alpha = complex<float>(1.0-beta, 0.0);
+    m_beta = complex<float>(beta, 0.0);
+
     return true;
 }
 
-bool EZDoppler::Sample(int nsamples, float &in_phase, float &quadrature, float &volume)
+typedef boost::scoped_array<complex<float> > complexf_scoped_array;
+
+// IQ is 2 complex floats, maximum rate is 2000, QUANTUM is period in seconds
+complex<float> buffer[(int)(2*QUANTUM*2000)];
+
+bool EZDoppler::Sample(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!
-    }
+    int nsamples = (int)(m_ezdop->rate()*QUANTUM);
 
-    // 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;
-        }
-    }
+    if (!m_ezdop->read_iq(buffer, nsamples, volume))
+        return false;
+
+    for (int i=0; i < nsamples; i++)
+        m_phase = m_alpha*m_phase + m_beta*buffer[i];
 
-    // m_phase is the actual instrument reading regardless of calibration
-    m_phase = atan2(m_quadrature, m_in_phase);
+    // m_angle is the actual instrument reading regardless of calibration
+    m_angle = atan2(m_phase.imag(), m_phase.real());
 
     // Calibration angle is sum of equalized offset and global offset
-    float cal = m_calibration[m_selected_rate] + m_offset;
+    float cal_angle = 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;
+    complex<float> cal = complex<float>(cos(cal_angle), sin(cal_angle));
+    m_output = m_phase*cal;
 
-    delete antenna;
-    delete audio;
+    in_phase = m_output.real()*nsamples/512.0;
+    quadrature = m_output.imag()*nsamples/512.0;
+    // adjust volume
+    
+//  wxLogDebug(_T("%f %f %f"), in_phase, quadrature, volume);
     return true;
 }
 
 bool EZDoppler::Calibrate(float phase)
 {
-    float offset = phase - m_phase;
+
+    float offset = phase - m_angle;
     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;
+
+    return true;
 }
 
 float EZDoppler::GetCalibration(int rate)
@@ -490,11 +261,13 @@ float EZDoppler::GetCalibration(int rate)
         return m_calibration[rate];
     else
         return m_offset;        
+
+    return 0.0;
 }
 
 bool EZDoppler::SetOffset(float offset)
 {
-    m_offset = offset-m_phase-m_calibration[m_selected_rate];
+    m_offset = offset-m_angle-m_calibration[m_selected_rate];
     NORMALIZEPHASE(m_offset);
     NORMALIZEPHASE(m_offset);
     NORMALIZEPHASE(m_offset);
@@ -506,6 +279,7 @@ bool EZDoppler::Nudge(float amount)
     cal += amount;
     NORMALIZEPHASE(cal);
     m_calibration[m_selected_rate] = cal;
+
     return true;
 }
 
diff --git a/ezdop/src/host/hunter/src/doppler.h b/ezdop/src/host/hunter/src/doppler.h
index 1471de6a49..cf3d96da39 100644
--- a/ezdop/src/host/hunter/src/doppler.h
+++ b/ezdop/src/host/hunter/src/doppler.h
@@ -24,19 +24,13 @@
     #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
-
+// Application level includes
+#include <ezdop.h>
+#include <boost/shared_ptr.hpp>
 #include <wx/event.h>
 
-#define NUM_RATES   6
+// TODO: Read this from ezdop.h
+#define NUM_RATES   6   
 
 class EZDoppler;
 
@@ -76,6 +70,8 @@ typedef void(wxEvtHandler::*EZDopplerUpdateFunction)(EZDopplerUpdate&);
             (wxObject *)NULL \
         ),
 
+typedef boost::shared_ptr<ezdop> ezdop_sptr;
+
 class EZDoppler
 {
 public:
@@ -88,12 +84,11 @@ public:
     bool IsOnline();
     bool Start();
     bool Stop();
-    bool Zero();
     bool SetFilter(int n);
     bool SelectRotationRate(int n);
-    int  GetSelectedRotationRate();
+    int  GetRotationRate();
     bool Reset();
-    bool Sample(int nsamples, float &in_phase, float &quadrature, float &volume);
+    bool Sample(float &in_phase, float &quadrature, float &volume);
     bool Calibrate(float phase);
     bool SetCalibration(int rate, float offset);
     float GetCalibration(int rate);
@@ -102,28 +97,18 @@ public:
     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;
+    ezdop_sptr m_ezdop;
+    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
+    complex<float> m_phase;         // Actual phase of doppler before calibration
+    complex<float> m_output;        // Calibrated output phase
+    complex<float> m_alpha;         // Exponential average constant
+    complex<float> m_beta;          // Exponential average constant
+    
+    float m_angle;                  // Actual angle of doppler before calibration
+    float m_offset;                 // Global calibration angle
     float m_calibration[NUM_RATES]; // Individual rotation rate offset
 };    
 
diff --git a/ezdop/src/host/hunter/src/hunter.cc b/ezdop/src/host/hunter/src/hunter.cc
index 39b8325c88..0aabfe29ed 100644
--- a/ezdop/src/host/hunter/src/hunter.cc
+++ b/ezdop/src/host/hunter/src/hunter.cc
@@ -513,19 +513,6 @@ void HunterFrame::OnDopplerUpdate(EZDopplerUpdate &event)
     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)
@@ -606,7 +593,7 @@ 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
+        delay = XRCCTRL(*this, "doppler_filter_slider", wxSlider)->GetValue(); // Empirically determined
         if (delay == 0)
             delay = 1;
     }
@@ -699,12 +686,20 @@ void HunterFrame::OnGPSUpdate(GPSUpdate &update)
     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)
+
+    if (m_log && m_capture && m_doppler_started &&
+        m_sample.Speed() >= 5.0 && m_sample.Valid()) {
+        m_log->Add(m_sample);
         CalcSolution();
-    if (m_search.HasSolution())
+        if (m_one_shot == true)
+            StopCapture();
+    }
+
+    if (m_search.HasSolution()) {
+        UpdateSearchStatus(true);
         UpdateSearchDirection(true);
+    }
         
     delete update.m_gprmc;
 }
@@ -747,7 +742,7 @@ void HunterFrame::UpdateSearchStatus(bool display)
     str.Printf(_T("%i"), m_log->Count());
     XRCCTRL(*this, "search_count_text", wxStaticText)->SetLabel(str);
 
-    str.Printf(_T("%s"), m_search.Busy() ? "BUSY" : "");
+    str.Printf(_T("%s"), m_search.Busy() ? _T("BUSY") : _T(""));
     XRCCTRL(*this, "search_status_text", wxStaticText)->SetLabel(str);
 
     str.Printf(_T("%i"), m_search.Mode());
diff --git a/ezdop/src/host/hunter/src/search.cc b/ezdop/src/host/hunter/src/search.cc
index 9992cb8964..d15a406b65 100644
--- a/ezdop/src/host/hunter/src/search.cc
+++ b/ezdop/src/host/hunter/src/search.cc
@@ -197,10 +197,12 @@ float TransmitterSearch::calc_trial_error(const vector<Sample>&samples,
         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));
+        //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();
 
-        trial_error += -log(likelihood)*sample.Strength();
+	// Adjusted exponential distribution
+	trial_error += sqrt(1+angle*angle)*sample.Strength();
         wsum += sample.Strength();
     }    
 
diff --git a/ezdop/src/host/hunter/src/serial.cc b/ezdop/src/host/hunter/src/serial.cc
index 5ace5aac13..67325d3b4d 100644
--- a/ezdop/src/host/hunter/src/serial.cc
+++ b/ezdop/src/host/hunter/src/serial.cc
@@ -19,6 +19,7 @@
 #include "serial.h"
 
 #include <wx/log.h>
+#include <errno.h>
 
 #ifdef __WIN32__
 // I hate Windows.
@@ -122,9 +123,10 @@ bool SerialPort::Open(int speed)
 
     m_opened = true;
 #else
-    m_fd = open((char *)m_port.c_str(), O_RDWR|O_NONBLOCK);
+    // Fixed at first USB port until string bug fixed
+    m_fd = open("/dev/ttyUSB0", O_RDWR|O_NONBLOCK);
     if (m_fd < 0) {
-        wxLogError(_T("SerialPort::Open: open() returned %i"), m_fd);
+        wxLogError(_T("SerialPort::Open: open(): %i"), errno);
         return false;
     }
 
diff --git a/ezdop/src/host/tests/dopper.cc b/ezdop/src/host/tests/dopper.cc
index a7e79c53d4..74faba2685 100644
--- a/ezdop/src/host/tests/dopper.cc
+++ b/ezdop/src/host/tests/dopper.cc
@@ -57,9 +57,11 @@ int main(int argc, char *argv)
     else
 	printf("failed.\n");
 
+    float volume;
+
     for (int i = 0; i < chunks; i++) {
         printf("Asking EZDOP for %i samples...", samples);
-        int rd = dop->read_iq(buffer, samples);
+        int rd = dop->read_iq(buffer, samples, volume);
 	printf("got %i --- ", rd);
 	if (rd != samples)
 	    printf("*****\n");
-- 
cgit v1.2.3