From www.AA6E.net
Jump to: navigation, search
#!/usr/bin/python
#
# Orion PSK31 controls .. opsk.py
# Copyright (c) 2004-2006 Martin S. Ewing, AA6E
# Requires pyserial package (pyserial.sourceforge.net)
# Developed under Python 2.2-2.4 and Fedora Linux FC1-FC4
#
# Version 0.20 - Autotune button implemented (tested on 1.372)
#
import serial,sys,time
from Tkinter import *
#
# Serial port for Orion
#
DEVICE="/dev/ham.orion"
#
IDENT="OPSK 0.20 www.aa6e.net/aa6e 2/2006"
#
IDENT_SHORT="OPSK 0.20 AA6E 2006"
#
PERIOD = 800		# msec reschedule interval
WIDTH = 300		# Window width
HEIGHT= 60		# Window height
FMIN = 150		# Default low freq. cutoff
FMAX = 3000		# Default hi  freq. cutoff = range
BWMIN = 100		# Min Bandwidth
BWDEF = 600		# Default bandwidth
#
# Global variables
#
ser = 0		# serial port object
root = 0	# Root Tk object
myCanvas = 0	# main myCanvas
vfoItem = 0	# VFO text
tuningLeft = 50; tuningRight = WIDTH-50
tBar = 0
tBbottom = 44
tBtop = 34
#bwScale = 0
pbtScale = 0
pbtVar = 0
cbw = -1	# current values of bw, fmin, fmax of DSP
cpbt= -1
radioVar = 0	# radio button variable (band index + 1)
myFreq = 0	# frequency (band) currently in use
bwVar = 0	# radio button variable
#
bandList = [ ('80 M', 1), ('40 M', 2), ('30 M', 3), ('20 M', 4), \
  ('17 M', 5), ('15 M', 6), ('12 M', 7), ('10 M', 8) ]
bandFreqs = [ 3.580, 7.070, 10.142, 14.070, 18.100, 21.070, \
  24.920, 28.120 ]
#
bwList = [ ('100 Hz',1), ('200 Hz',2), ('400 Hz',3), ('1 kHz',4), \
  ('2 kHz',5), ('3 kHz',6) ]
bwFreqs = [ 100, 200, 400, 1000, 2000, 3000 ]
#
# Orion basic I/O
#
def rd():
  global ser
  MAX=50; c=''; ans=''; i=0
  while c <> '\r':
    c = ser.read(1)
    # Timeout happens when Orion gets funky.  Next time should be ok.
    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(s):
    global ser
    if ser.inWaiting(): ser.flushInput() # Orion i/o has slipped
    ser.write(s+'\r')
    return None
#
def oget(ss):   		# Get data from Orion
   MAX=5; t = ''; i=0;
   for i in range(MAX):
     wrt(ss)
     t = rd()
     if len(t)<len(ss) : continue       # read string too short
     if t[1:len(ss)] == ss[1:] : break  # resp. looks good
   return t[len(ss):]                   # return data part only
#
def oput(ss):			# Send a command to Orion
   wrt(ss)
#   t = rd()			# Do we get a response?
#   if len(t) > 0: print "resp=",t
   return None
#
def Tune() :		# Start an auto-tune operation
			# Thanks to N4PY for clues how to do this!
   a1 = oget("?KA")
   if not (a1[0] in ['M','B']):
      print "Not using Ant 1 - Tune command ignored."
      return		# Not using Ant 1, so can't tune.
   wrt("*TT1")		# Ensure tuner enabled
			# assume current mode = USB
   wrt("*RMM3")		# CW mode
			# assume current power = 100 W
   wrt("*TP20")		# Power 20 watts
   wrt("*TK")		# Key on
   time.sleep(0.1)
   oput("*TTT")		# Cycle tuner
   time.sleep(3.5)	# Conservative delay?
   wrt("*TU")		# Key off
   wrt("*TP100")
   wrt("*RMM0")		# USB
   return None
#
def getvfoa():			# Get current VFO A setting
   global ser
   vfoa = oget("?AF")
   text = "-- -- --"
   if len(vfoa)==8 :
     mhz = (vfoa[0:2].lstrip('0')).rjust(2)  # strip leading 0's
     text = mhz+'.'+vfoa[2:5]+'.'+vfoa[5:]
   return text
#
def AdjustBar():		# Adjust tuning bar
   global tBar, cbw, cpbt
   global tuningLeft, tuningRight, tBbottom, tBtop
   left = int( (float(cpbt)/FMAX) * (tuningRight-tuningLeft) ) + \
     tuningLeft
   right =int( (float(cpbt+cbw)/FMAX) * (tuningRight-tuningLeft) ) + \
     tuningLeft
   myCanvas.coords(tBar, left, tBbottom, right, tBtop)
   return None
#
def SetRange(v):		# PBT scale's callback
    global cpbt
    cpbt = int(v)
    oput("*RMP"+str(cpbt))
    AdjustBar()
    return None
#
def SetBW():			# Set BW from button
   global bwVar,bwFreqs,cbw
   ix = bwVar.get()
   cbw = int( bwFreqs[ix-1] )
   oput("*RMF"+str(cbw))
   AdjustBar()
   return None 
#
def SetFreq():			# Set operating VFO Freq
   global myFreq,bandFreqs,radioVar
   myFreq = bandFreqs[radioVar.get() - 1]
   oput("*AF" + str(myFreq) )
   return None
#
def GoWide():			# pbt=0, bw=3000
   global cbw,  bwVar, pbtVar, pbtScale
   pbtVar.set(0)
   pbtScale.set(0)
   SetRange(0)
   cbw=3000
   bwVar.set(6)
   SetBW()
   return None
#
# Update the screen (VFO) and set the Orion filter controls
#
def Update() :
   global myCanvas, vfoItem
   # Update VFO frequency display
   if vfoItem == 0:
      vfoItem = myCanvas.create_text(WIDTH/2,20,text=getvfoa(), fill='blue', \
      anchor=CENTER,font=('Arial','14') )
   else :
      myCanvas.itemconfigure(vfoItem, text=getvfoa()) 
   myCanvas.update_idletasks()
   myCanvas.pack()
   myCanvas.after(PERIOD, Update)
   return None
#  Main Entry
#
print IDENT
#
# Open the Orion's channel
#
ser = serial.Serial(DEVICE,baudrate=57600,rtscts=1,timeout=0.2)
ser.flushInput()
ser.flushOutput()
#
# Wake up the Orion
#
wrt("XX")               # Orion ID = syncs the serial port
msg1=rd()
wrt("?V")               # Firmware version number
msg2=rd()
print "Initialization:",msg1,msg2
# Set USB mode
oput("*RMM0")
#
# Initialize window
#
root = Tk()
root.title('Orion PSK')
myCanvas = Canvas(root,width=WIDTH,height=HEIGHT)
gray = "#808080"
myCanvas.create_text(WIDTH/2,5,text=IDENT_SHORT,fill=gray, \
  font=('Verdana','8'), anchor=CENTER)
myCanvas.create_rectangle(tuningLeft,40,tuningRight,38, fill='blue')
tuningCenter = (tuningLeft + tuningRight) / 2
tBar = myCanvas.create_rectangle(tuningCenter-10,tBbottom,tuningCenter+10, \
  tBtop, fill='red')
#
pbtVar = IntVar()
pbtVar.set(0)		#Initialize to zero Hz
pbtScale = Scale(root,  orient=HORIZONTAL, \
  troughcolor="#C0C0C0",fg="Blue",bg="#B0B0B0", length=WIDTH, \
  variable=pbtVar,label="PBT = Lower edge",resolution=50, \
  to = FMAX, tickinterval = 500, command=SetRange)
myCanvas.pack(side=TOP)
#
radioFrame = Frame(root)
Label(radioFrame,text="Select Band",fg="red").pack(side=TOP)
radioVar = IntVar()
for text, value in bandList :
  x= Radiobutton(radioFrame, indicator=0, text=text, value=value, \
     command=SetFreq,variable=radioVar)
  x.pack(side=LEFT)
radioVar.set(4)		# Request 20 mtrs to start
SetFreq()
radioFrame.pack()
bwFrame = Frame(root)
Label(bwFrame,text='Select BW',fg="red").pack(side=TOP)
bwVar = IntVar()
for text, value in bwList :
  x = Radiobutton(bwFrame, indicator=0, text=text, value=value, \
      command=SetBW, variable=bwVar)
  x.pack(side=LEFT)
bwVar.set(6)		# fullwidth to start
SetBW()
bwFrame.pack()
#
pbtScale.pack()
Button(root, text="Go Wide", command=GoWide).pack(side=LEFT)
Button(root, text="Tune", command=Tune).pack(side=LEFT)
Button(root, text="Quit", command=root.quit).pack(side=RIGHT)
myCanvas.after(1,Update)	# Quickly do the first update
root.mainloop()		# Where it all happens
ser.flushInput()
ser.close()