From www.AA6E.net
Jump to: navigation, search
#!/bin/env python

# File: oFilter.py
# Version: 0.10
#
# Ten-Tec Orion bandpass/offset control
# Copyright (c) 2006-2007 Martin Ewing
#
# This program 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
# of the License, or (at your option) any later version.
#
# This program 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 this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  
# 02110-1301, USA.
#
# Contact ewing @@ alum.mit.edu or c/o San Pasqual Consulting, 28
# Wood Road, Branford CT 06405, USA.

# Requires wxPython and pySerial packages
# This program displays a GUI panel that allows the user to control
# the Orion's bandpass and offset frequencies, for example to optimize
# settings while watching a waterfall display for HF digital communication.

# oFilter.py initializes to BW = 3000 Hz and shift (offset) = 0 Hz.
# The Rst button allows you to return to this condition at any time.
# The Rpt button resends the most recent settings (in case of Orion I/O
# problems).
# An array of radio buttons allows you to select bandwidth from a fixed
# list of options (100, 200, 500, 1000, 2000, and 3000 Hz).
# An additional set of buttons lets you shift the bandpass in increments
# of +/- 50, 200, or 1000 Hz.

IDENT = 'oFilter.py v 0.1'
#DEVICE = '/dev/ttyS0'
DEVICE = '/dev/ham.orion'
BACKGROUND_COLOR = '#ffffee'
FOREGROUND_COLOR = '#000066'
FOREGROUND_COLOR_FAINT = '#aaaadd'

import wx, sys, serial

app = wx.App()

class OffsetPanel(wx.Panel):
    def __init__(self, parent, id):
        wx.Panel.__init__(self, parent, id, style=wx.NO_BORDER)
        self.SetBackgroundColour(BACKGROUND_COLOR)
        self.SetForegroundColour(FOREGROUND_COLOR)

        self.valuePanelP = parent.GetParent().valuePanel

        b1 = wx.Button(self, -1, ' -50', (10, 10), (60,25))
        b2 = wx.Button(self, -1, ' +50', (70, 10), (60,25))
        b3 = wx.Button(self, -1, '-200', (10, 35), (60,25))
        b4 = wx.Button(self, -1, '+200', (70, 35), (60,25))
        b5 = wx.Button(self, -1, '-1000', (10, 60), (60,25))
        b6 = wx.Button(self, -1, '+1000', (70, 60), (60,25))

        for button in [b1, b2, b3, b4, b5, b6]:
            self.Bind(wx.EVT_BUTTON, self.doOffset, button)

    def doOffset(self, event):
        req_offset = int(event.GetEventObject().GetLabel())
        self.valuePanelP.add_offset(req_offset)
        
class BWPanel(wx.Panel):
    def __init__(self, parent, id):
        wx.Panel.__init__(self, parent, id, style=wx.NO_BORDER)
        self.SetBackgroundColour(BACKGROUND_COLOR)
        self.SetForegroundColour(FOREGROUND_COLOR)

        self.valuePanelP = parent.GetParent().valuePanel

        self.r1 = wx.RadioButton(self, -1, ' 100', (10,10), (60,30))
        self.r2 = wx.RadioButton(self, -1, ' 200', (70,10), (60,30))
        self.r3 = wx.RadioButton(self, -1, ' 500', (10,30), (60,30))
        self.r4 = wx.RadioButton(self, -1, '1000', (70,30), (60,30))
        self.r5 = wx.RadioButton(self, -1, '2000', (10,50), (60,30))
        self.r6 = wx.RadioButton(self, -1, '3000', (70,50), (60,30))
        
        for radio in [self.r1, self.r2, self.r3, self.r4, self.r5, self.r6]:
            self.Bind(wx.EVT_RADIOBUTTON, self.doBW, radio)
 
    def doBW(self, event):
        req_bw = int(event.GetEventObject().GetLabel())
        self.valuePanelP.set_bw(req_bw)
        
    def reset(self):                    # Reset to 3000, wide open
        for r in [self.r1, self.r2, self.r3, self.r4, self.r5]:
            r.SetValue(False)
        self.r6.SetValue(True)

class ValuePanel(wx.Panel):
    def __init__(self, parent, id):
        wx.Panel.__init__(self, parent, id, size=(100,100), style=wx.NO_BORDER)
        self.SetBackgroundColour(BACKGROUND_COLOR)
        self.SetForegroundColour(FOREGROUND_COLOR)
        self.talker = None      # will be set a little later
        self.bwpanel = None     # will be set a little later
        self.bandwidth = 3000
        self.offset = 0
        self.bw_text = wx.StaticText(self, -1, 'BW:    %4s' % self.bandwidth, (10,10), style=wx.NO_BORDER)
        self.offset_text = wx.StaticText(self, -1, 'Shift: %4s' % self.offset, (10,30), style=wx.NO_BORDER)
        b0 = wx.Button(self, -1, "Rst", (10, 60), (42,30))
        self.Bind(wx.EVT_BUTTON, self.doReset, b0)
        brpt = wx.Button(self, -1, "Rpt", (57, 60), (42,30))
        self.Bind(wx.EVT_BUTTON, self.doResend, brpt)

    def doResend(self, event):
        self.talker.resend()
        
    def doReset(self, event):
        self.set_bw(3000)
        self.bwpanel.reset()
        self.add_offset(-self.offset)
        
    def set_bw(self, x):
        self.bw = x
        self.bw_text.SetLabel('BW:    %s' % self.bw)
        self.talker.send_bw(self.bw)
        
    def add_offset(self, x):
        self.offset += x
        self.offset_text.SetLabel('Shift: %s' % self.offset)
        self.talker.send_offset(self.offset)
        
class StatusPanel(wx.Panel):
    def __init__(self, parent, id):
        wx.Panel.__init__(self, parent, id, style=wx.NO_BORDER)
        self.SetBackgroundColour(BACKGROUND_COLOR)
        self.SetForegroundColour(FOREGROUND_COLOR)
        bx = wx.Button(self, -1, "Quit", (280, 0))
        self.Bind(wx.EVT_BUTTON, self.doExit, bx)
        self.talker = None      # to be set later
        
    def setIdent(self):
        tt = wx.StaticText(self, -1, IDENT, (10,2))
        tt.SetForegroundColour(FOREGROUND_COLOR_FAINT)
        tt2= wx.StaticText(self, -1, 'Orion firmware '+self.talker.msg2, (10,19))
        tt2.SetForegroundColour(FOREGROUND_COLOR_FAINT)
        
    def doExit(self, event):
        sys.exit()

class Talk(object):
    def __init__(self,myDevice):
        self.ser = serial.Serial(DEVICE,baudrate=57600,rtscts=1,timeout=0.2)
        self.ser.flushInput()
        self.ser.flushOutput()
        
        self.wrt("XX")               # Orion ID = syncs the serial port
        msg1=self.rd()
        self.wrt("?V")               # Firmware version number
        self.msg2=self.rd()
        print "Initialization:",msg1,self.msg2
        self.bw_local = 3000
        self.offset_local = 0
        
    def rd(self):
        MAX=50; c=''; ans=''; i=0
        while c <> '\r':
            c = self.ser.read(1)
            if c == '': break           #timeout? try again?
            ans += c
            i += 1
            if i > MAX : raise MyExcept, "serial read too long"
        return ans[:-1]       # trim off final \r

    def wrt(self,s):
        if self.ser.inWaiting(): self.ser.flushInput() # Orion i/o has slipped
        self.ser.write(s+'\r')
        return None
    
    def oput(self,ss):			# Send a command to Orion
        self.wrt(ss)
        t = self.rd()			# Do we get a response?
        if len(t) > 0: print "resp=",t
        return None
        
    def send_bw(self,bw):
        print "send bw parm = ",bw
        cmd = '*RMF%d' % bw
        self.oput(cmd)
        self.bw_local = bw
    
    def send_offset(self,offset):
        print 'send offset parm = ',offset
        cmd = '*RMP%d' % offset
        self.oput(cmd)
        self.offset_local = offset

    def resend(self):               # In case of Orion hiccup, repeat xmsn
        self.send_bw(self.bw_local)
        self.send_offset(self.offset_local)

class Communicate(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title, size=(380, 160))
        self.SetMinSize((380,160))
        self.SetMaxSize((380,160))
        talker = Talk(DEVICE)
        
        panel = wx.Panel(self, -1)
        panel.SetBackgroundColour(BACKGROUND_COLOR)
        panel.SetForegroundColour(FOREGROUND_COLOR_FAINT)
        
        statusPanel = StatusPanel(panel, -1)
        statusPanel.talker = talker
        statusPanel.setIdent()
        
        self.valuePanel = ValuePanel(panel, -1)
        bwPanel = BWPanel(panel, -1)
        offsetPanel = OffsetPanel(panel, -1)
        self.valuePanel.bwpanel = bwPanel   # avoiding circular reference
        self.valuePanel.talker = talker     # ditto
        self.valuePanel.doReset(None)

        box = wx.StaticBox(panel, -1, "from AA6E.NET")
        vbox = wx.StaticBoxSizer(box, wx.VERTICAL)
        
        box2 = wx.StaticBox(panel, -1, style=wx.NO_BORDER)
        hbox = wx.StaticBoxSizer(box2,wx.HORIZONTAL)
        
        hbox.Add(self.valuePanel, 0,  wx.ALL)
        hbox.Add(bwPanel, 0, wx.ALL)
        hbox.Add(offsetPanel, 0, wx.ALL)
        
        vbox.Add(hbox, 0, wx. ALL)
        vbox.Add(statusPanel, 0, wx.ALIGN_RIGHT)

        panel.SetSizer(vbox) 
        self.Show(True)

print IDENT
app = wx.App()
Communicate(None, -1, 'Orion Bandpass Control')

app.MainLoop()