#!/usr/bin/env python # k 3 # # k3 can be run with command line arguments or interactively. For the most # part, the program simply takes input and calls an appropriate method in # k3lib. # # Mike Markowski, mike.ab3ap@gmail.com # Jan 1, 2018 import libK3 import readline import serial import subprocess import sys def usage(progName): print('%s for interactive mode. Commands:\n' % progName) print(' a display VFO A frequency.') print(' a f_kHz set VFO A to f_kHz.') print(' a f_kHz s_kHz set VFO A to f_kHz,') print(' set VFO B to f_kHz + s_kHz,') print(' enter SPLIT mode.') print(' (Exit SPLIT when s_kHz = 0.)') print(' b [...] as above for command \'a\'but for VFO B.') print(' c text send cw text.') print(' d display serial device.') print(' h or ? this message.') print(' f flip VFO A/B settings.') print(' k display keyer speed.') print(' k wpm set keyer speed to wpm.') print(' m [mode] change mode based on freq.') print(' n use normal bandwidth for mode.') print(' p [pwr] get/set transmitter power in Watts.') print(' q immediately kill \'c\' cw generation.') print(' s [s_kHz] split from current frequency by s_kHz.') print(' S display rig serial number.') print(' t toggle test mode on/off.') def main(argv): myname = argv[0] argv = argv[1:] dev = "/dev/ttyUSB0" baud = 38400 myCall = 'ab3ap' # See usage() for details on arguments and values. k3 = libK3.LibK3() interactive = False # Interactive (no cmd line args) or non-default serial device. if (len(argv) == 0 or (len(argv) == 2 and argv[0] == '-d')): interactive = True n = len(argv) i = 0 while i < n: opt = argv[i] if opt == '-d': # Non-default serial device. dev = argv[i+1] break i += 1 while True: try: k3.connect(dev, baud) break except serial.serialutil.SerialException: print('Can\'t open %s.' % dev) dev = input('Serial device: ') if interactive: while True: try: line = input('k3$ ') cmd = line.split() lenc = len(cmd) except EOFError: print('') break if lenc == 0: continue elif cmd[0] == '9': k3.sendCw('r 5nn tu') elif cmd[0] == 'a' or cmd[0] == 'b': if lenc == 1: print(numFmt(k3.getFreq_Hz(cmd[0]) / 1e3, ' ')) elif lenc == 2: k3.cancelSplit() try: f_Hz = 1e3 * float(cmd[1]) k3.setFreq_Hz(cmd[0], f_Hz) mode = k3.findMode(f_Hz) k3.setMode(mode) except ValueError: print('Non-float frequency: %s' % cmd[1]) elif lenc == 3: # Split requested. try: f_Hz = 1e3 * float(cmd[1]) # Primary VFO freuqncy. up_Hz = float(cmd[2]) * 1e3 # Secondary VFO offset. k3.setSplit_Hz(cmd[0], f_Hz, up_Hz) # Set mode (CW, SSB, etc.). mode = k3.findMode(f_Hz) k3.setMode(mode) except ValueError: print('Non-float split: %s %s' % (cmd[1], cmd[2])) elif cmd[0] == 'c': if lenc == 1: k3.sendCw(myCall) # Put out call for dx hunting. k3.sendCw(line.strip()[1:]) elif cmd[0] == 'd': # Display serial device. print('Serial device: %s' % dev) elif cmd[0] == 'f': # Flip VFOs. k3.abSwap() elif cmd[0] == 'h' or cmd[0] == '?': usage(myname) elif cmd[0] == 'k': if lenc == 1: print('%d wpm' % k3.getKeyerSpeed_wpm()) else: try: k3.setKeyerSpeed_wpm(int(cmd[1])) except ValueError: print('Non-integer keyer speed: %s' % cmd[1]) elif cmd[0] == 'm': if lenc == 1: f_Hz = k3.getFreq_Hz('a') mode = k3.findMode(f_Hz) # Find mode from frequency. k3.setMode(mode) elif lenc == 2: k3.setMode(cmd[1]) elif cmd[0] == 'n': k3.setNormal() elif cmd[0] == 'p': if lenc == 1: print('%d W' % k3.getPower_W()) else: try: k3.setPower_W(float(cmd[1])) except ValueError: print('Non-float power: %s' % cmd[1]) elif cmd[0] == 'q': k3.quitCw() elif cmd[0] == 's': if lenc == 1: k3.cancelSplit() else: try: up_Hz = float(cmd[1]) * 1e3 # Secondary VFO offset. except ValueError: print('Non-float split offset: %s' % cmd[1]) break f_Hz = k3.getFreq_Hz('a') k3.setSplit_Hz('a', f_Hz, up_Hz) mode = k3.findMode(f_Hz) # Find mode from frequency. k3.setMode(mode) elif cmd[0] == 'S': print('SN %d' % k3.getSerialNumber()) elif cmd[0] == 't': k3.setTest() else: try: subprocess.run(cmd) # Try a shell command. except FileNotFoundError: print('Unrecognized shell command: %s' % line) sys.exit(0) # Finished interactive commands. n = len(argv) i = 0 while i < n: opt = argv[i] if opt == '-A': print(numFmt(k3.getFreq_Hz('a') / 1e3, ' ')) elif opt == '-a': f_Hz = 1e3 * float(argv[i+1]) k3.setFreq_Hz('a', f_Hz) mode = k3.findMode(f_Hz) k3.setMode(mode) i += 1 elif opt == '-B': print(numFmt(k3.getFreq_Hz('b') / 1e3, ' ')) elif opt == '-b': f_Hz = 1e3 * float(argv[i+1]) k3.setFreq_Hz('b', f_Hz) mode = k3.findMode(f_Hz) k3.setMode(mode) i += 1 elif opt == '-c': k3.sendCw(argv[i+1]) i += 1 elif opt == '-d': i += 1 # Ignore for now. elif opt == '-f': k3.abSwap() elif opt in ('-h', '--help'): usage(myname) elif opt == '-k': k3.setKeyerSpeed_wpm(int(argv[i+1])) i += 1 elif opt == '-K': print(k3.getKeyerSpeed_wpm()) elif opt == '-p': k3.setPower_W(float(argv[i+1])) i += 1 elif opt == '-P': print(k3.getPower_W()) elif opt == '-q': k3.quitCw() elif opt == '-s': f_Hz = 1e3 * float(argv[i+1]) u_Hz = 1e3 * float(argv[i+2]) k3.setSplit_Hz(f_Hz, u_Hz) i += 2 elif opt == '-S': print(k3.getSerialNumber()) elif opt == '-t': k3.setTest() else: print('Bleh. Don\'t know what %s is.' % opt) sys.exit(1) i += 1 k3.disconnect() def numFmt(n, sep=','): """Print a number and insert a separator every 3 numerals. The separator is a comma by default. Examples: numFmt(1234) = 1,234 numFmt(-23456.789) = -23,456.789 numFmt(-23456,789, ".") = -23.456,789 (European) Inputs: n (float): number to be formatted sep (string): optional separator to use. Comma is default. Output: (string): formatted version of number """ # Convert to string, making number non-negative. neg = False if n < 0: neg = True n = -n s = str(n) # Save fraction. dot = max(s.find('.'), s.find(',')) tail = '' if dot != -1: tail = s[dot : len(s)] s = s[0:dot] # Right to left, insert separator every 3 numerals. while len(s) > 3: tail = sep + s[len(s)-3:len(s)] + tail s = s[:len(s)-3] tail = s + tail if neg: tail = '-' + tail return tail if __name__ == '__main__': main(sys.argv)