#!/usr/bin/env python3

#########################
# Controller for adf435x signal generator
#########################
debug=False

#########################
# Default settings
#########################

def_usbco=16                 # USB connect
def_rfreq=25
def_level=-6
def_pfreq=100
def_pstep=0.01

def_afreq=100.0
def_bfreq=200
def_sstep=0.001
def_tstep=200

swpfreq_corr=1
#########################


import tkinter as tk
from tkinter import *
from tkinter import ttk
from array import array
from threading import Timer
import serial,platform


# 30 ports windows
lincomports=["/dev/ttyS0","/dev/ttyS1","/dev/ttyS2","/dev/ttyS3","/dev/ttyS4","/dev/ttyS5",
             "/dev/ttyS6","/dev/ttyS7","/dev/ttyS8","/dev/ttyS9","/dev/ttyS10","/dev/ttyS11",
             "/dev/ttyS12","/dev/ttyS13","/dev/ttyS14","/dev/ttyS15","/dev/ttyUSB0",
             "/dev/ttyUSB1","/dev/ttyUSB2","/dev/ttyUSB3","/dev/ttyUSB4","/dev/ttyUSB5",
             "/dev/ttyAMA0","/dev/ttyAMA1","/dev/ttyACM0","/dev/ttyACM1",
             "/dev/rfcomm0","/dev/rfcomm1","/dev/ircomm0","/dev/ircomm1"]

# 28 ports windoows
wincomports=["\\\\.\\COM1","\\\\.\\COM1",  "\\\\.\\COM2",  "\\\\.\\COM3",  "\\\\.\\COM4",
                           "\\\\.\\COM5",  "\\\\.\\COM6",  "\\\\.\\COM7",  "\\\\.\\COM8",   
                           "\\\\.\\COM9",  "\\\\.\\COM10", "\\\\.\\COM11", "\\\\.\\COM12",  
                           "\\\\.\\COM13", "\\\\.\\COM14", "\\\\.\\COM15", "\\\\.\\COM16",  
                           "\\\\.\\COM17", "\\\\.\\COM18", "\\\\.\\COM19", "\\\\.\\COM20",  
                           "\\\\.\\COM21", "\\\\.\\COM22", "\\\\.\\COM23", "\\\\.\\COM24",  
                           "\\\\.\\COM25", "\\\\.\\COM26", "\\\\.\\COM27", "\\\\.\\COM28"]  

OS = platform.system()
if OS == 'Linux':
  comports=lincomports
elif OS == 'Windows':
  comports=wincomports
else:
  print("Unknown platform: "+OS)
  quit()

class RepeatedTimer(object):
    def __init__(self, interval, function, *args, **kwargs):
        self._timer     = None
        self.interval   = interval
        self.function   = function
        self.args       = args
        self.kwargs     = kwargs
        self.is_running = False
#        self.start()

    def _run(self):
        self.is_running = False
        self.start()
        self.function(*self.args, **self.kwargs)

    def start(self):
        if not self.is_running:
            self._timer = Timer(self.interval, self._run)
            self._timer.start()
            self.is_running = True

    def stop(self):
        self._timer.cancel()
        self.is_running = False

def d2h3(n):
  b=array('B',[(n>>16)&0xff,(n>>8)&0xff,n&0xff])
  return b

def checksum(a):
  cs=0
  for i in range(len(a)):
    cs=(cs+a[i])&0xff
  return cs


def set_point(f,level,fref):
  cmd=array('B',[0xad,0x02,0x01])
  cmd.append(int(abs(int(level))/3+1))
  cmd=cmd+d2h3(int(float(fref)*10000))
  cmd=cmd+d2h3(int(float(f)*1000))
  cmd.append(checksum(cmd))
  return cmd

def set_sweep(fa,fb,fs,level,fref):
  cmd=array('B',[0xad,0x02,0x02])
  cmd.append(int(abs(int(level))/3+1))
  cmd=cmd+d2h3(int(float(fref)*10000))
  cmd=cmd+d2h3(int(float(fa)*1000*swpfreq_corr))
  cmd=cmd+d2h3(int(float(fb)*1000*swpfreq_corr))
  cmd=cmd+d2h3(int(float(fs)*1000))
  cmd.append(0x02)
  cmd.append(checksum(cmd))
  return cmd

def stop():
  cmd=array('B',[0xad,0xff])
  cmd.append(checksum(cmd))
  return cmd

def set_info(txt):
  info.delete(0,END)
  info.insert(0,txt)

def connect(frame0,Row):
  global info
  def handle_keypress_conn():
    global ser,cp
    try:
      ser = serial.Serial(cp, 115200, timeout=0.5)
      set_info("OK "+cp)
    except:
      set_info("ERROR "+cp)


  def handle_keypress_disconn():
    global ser,info
    if ser!=None:
      ser.close()
      ser=None
    set_info("Disconnected")

  con3=tk.Button(frame0, text="Connect",command=handle_keypress_conn)
  con4=tk.Button(frame0, text="Disconnect",command=handle_keypress_disconn)
  info=tk.Entry(frame0, textvariable="",width=20)

  con3.grid(column=1,row=Row)
  con4.grid(column=2,row=Row)
  info.grid(column=1,row=Row+1,columnspan=2,sticky=tk.NW)

def do_setting():
  global cp
  global refp
  def handle_keypress_usbdev():
    global cp
    cp=comports[int(con1.get())]
    con2.delete(0,END)
    con2.insert(0,cp)


  frame0=tk.Frame();
  varcp=tk.IntVar(value=def_usbco)
  con1=tk.Spinbox(frame0, from_=0, to=32,command=handle_keypress_usbdev,textvariable=varcp,width=4)
  cp=comports[int(con1.get())]
  con2=tk.Entry(frame0,width=12)
  con2.insert(0,cp)

  refp=add_ref(frame0,4)

  con1.grid(column=1,row=1)
  con2.grid(column=2,row=1)
  return frame0

def add_ref(frame,Row):
  varr = tk.DoubleVar(value=def_rfreq)
  butr1=Label(frame, text="Ref. freq.")
  butr2=tk.Spinbox(frame, from_=10.0, to=50.0,increment=0.1,format="%.3f", textvariable=varr,width=8)
  butr3=Label(frame, text="MHz")

  butr1.grid(column=1,row=Row)
  butr2.grid(column=2,row=Row,sticky=tk.NW)
  butr3.grid(column=3,row=Row,sticky=tk.NW)
  Row+=1
  return butr2

def add_level(frame,Row):
  varl = tk.DoubleVar(value=def_level)
  butl1=Label(frame, text="Level.")
  butl2=tk.Spinbox(frame, from_=-9, to=0,increment=3, textvariable=varl,width=8)
  butl3=Label(frame, text="dB")

  butl1.grid(column=1,row=Row)
  butl2.grid(column=2,row=Row,sticky=tk.NW)
  butl3.grid(column=3,row=Row,sticky=tk.NW)
  return butl2

def add_freq(frame,varf,Row,name):
#  varf = tk.DoubleVar(value=freq)
  butf1=Label(frame, text=name)
  butf2=tk.Spinbox(frame, from_=35, to=4000,increment=0.1,format="%.3f", textvariable=varf,width=8)
  butf3=Label(frame, text="MHz")

  butf1.grid(column=1,row=Row)
  butf2.grid(column=2,row=Row,sticky=tk.NW)
  butf3.grid(column=3,row=Row,sticky=tk.NW)
  return butf2

def add_step(frame,step,Row):
  varst = tk.DoubleVar(value=step)
  buts1=Label(frame, text="Step freq..")
  buts2=tk.Spinbox(frame, from_=0.001, to=100,increment=0.01,format="%.3f", textvariable=varst,width=8)
  buts3=Label(frame, text="MHz")

  buts1.grid(column=1,row=Row)
  buts2.grid(column=2,row=Row,sticky=tk.NW)
  buts3.grid(column=3,row=Row,sticky=tk.NW)
  return buts2

def do_point():

  def handle_keypress_start(event):
    if ser==None:
      set_info("First connect!")
    b=set_point(butf2.get(),butl2.get(),refp.get())
    if ser!=None:
      ser.write(b)
    if debug:
      print(b)

  def handle_keypress_stop(event):
    if ser==None:
      set_info("First connect!")
    b=stop()
    if ser!=None:
      ser.write(b)
    if debug:
      print(b)

  def handle_keypress_down(event):
    n=butf2.get()
    n=float(n)-1
    varf.set(n)
    handle_keypress_start(None)

  def handle_keypress_up(event):
    n=butf2.get()
    n=float(n)+1
    varf.set(n)
    handle_keypress_start(None)

  frame1 = tk.Frame()

  Row=1
  butl2=add_level(frame1,Row)

  Row+=1
  varf = tk.DoubleVar(value=def_pfreq)
  butf2=add_freq(frame1,varf,Row,"Freq.")

  Row+=1
  buts2=add_step(frame1,def_pstep,Row)

  Row+=1
  but1=tk.Button(frame1,text="Start")
  but1.bind("<Button-1>",handle_keypress_start)
  but1.grid(column=1,row=Row,sticky=tk.NW)

  but2=tk.Button(frame1,justify=tk.LEFT,text="Stop")
  but2.bind("<Button-1>",handle_keypress_stop)
  but2.grid(column=2,row=Row,sticky=tk.NW)

  Row+=1
  but3=tk.Button(frame1,justify=tk.LEFT,text="Down")
  but3.bind("<Button-1>",handle_keypress_down)
  but3.grid(column=1,row=Row,sticky=tk.NW)

  but4=tk.Button(frame1,text="Up")
  but4.bind("<Button-1>",handle_keypress_up)
  but4.grid(column=2,row=Row,sticky=tk.NW)

  return frame1

def do_sweep():
  def handle_keypress_start(event):
    if ser==None:
      set_info("First connect!")

    b=set_sweep(butf2.get(),bute2.get(),buts2.get(),butl2.get(),refp.get())
    if ser!=None:
      ser.write(b)
    if debug:
      print(b)

  def handle_keypress_stop(event):
    if ser==None:
      set_info("First connect!")

    b=stop()
    if ser!=None:
      ser.write(b)
    if debug:
      print(b)

  frame2 = tk.Frame()

  Row=1
  butl2=add_level(frame2,Row)

  Row+=1
  varf = tk.DoubleVar(value=def_afreq)
  butf2=add_freq(frame2,varf,Row,"Start freq.")

  Row+=1
  vare = tk.DoubleVar(value=def_bfreq)
  bute2=add_freq(frame2,vare,Row,"Stop freq.")

  Row+=1
  buts2=add_step(frame2,def_sstep,Row)

  Row+=1
  but1=tk.Button(frame2,text="Start")
  but1.bind("<Button-1>",handle_keypress_start)
  but1.grid(column=1,row=Row,sticky=tk.NW)

  but2=tk.Button(frame2,justify=tk.LEFT,text="Stop")
  but2.bind("<Button-1>",handle_keypress_stop)
  but2.grid(column=2,row=Row,sticky=tk.NW)

  return frame2


def do_psweep():
  global rt
  def stepping():
    global fspoint
    global step
    fspoint=fspoint+step
    if (fspoint>float(vare.get())):
      fspoint=float(varf.get())
    if (fspoint<float(varf.get())):
      fspoint=float(varf.get())

    varm.set(fspoint)
    varm.set('{:.3f}'.format(fspoint))
    b=set_point(fspoint,butl3.get(),refp.get())
    if ser!=None:
      ser.write(b)
    if debug:
      print(b)


  def handle_keypress_start(event):
    global fspoint
    global rt,step
    fspoint=1
    if ser==None:
      set_info("First connect!")

    rt.interval=float(varsp.get())/1000.
    step=float(buts3.get())
    rt.start()

  def handle_keypress_stop(event):
    global rt
    rt.stop()

    b=stop()
    if ser!=None:
      ser.write(b)
    if debug:
      print(b)

  step=0.01
  rt = RepeatedTimer(1, stepping)

  frame3 = tk.Frame()

  Row=1
  butl3=add_level(frame3,Row)

  Row+=1
  varf = tk.DoubleVar(value=def_afreq)
  butf3=add_freq(frame3,varf,Row,"Start freq.")

  Row+=1
  vare = tk.DoubleVar(value=def_bfreq)
  bute3=add_freq(frame3,vare,Row,"Stop freq.")

  Row+=1
  buts3=add_step(frame3,def_sstep,Row)

  Row+=1
  varsp = tk.DoubleVar(value=def_tstep)
  spd1=Label(frame3, text="Step speed")
  spd2=tk.Spinbox(frame3, from_=10, to=10000,increment=100,format="%.0f", textvariable=varsp,width=8)
  spd3=Label(frame3, text="ms")
  spd1.grid(column=1,row=Row)
  spd2.grid(column=2,row=Row)
  spd3.grid(column=3,row=Row)

  Row+=1
  varm = tk.DoubleVar(value=100)
  mfreq1=Label(frame3, text="Mom. freq..")
  mfreq2=tk.Entry(frame3,textvariable=varm,width=10)
  mfreq3=Label(frame3, text="MHz")
  mfreq1.grid(column=1,row=Row)
  mfreq2.grid(column=2,row=Row)
  mfreq3.grid(column=3,row=Row)

  Row+=1
  but1=tk.Button(frame3,text="Start")
  but1.bind("<Button-1>",handle_keypress_start)
  but1.grid(column=1,row=Row,sticky=tk.NW)

  but2=tk.Button(frame3,justify=tk.LEFT,text="Stop")
  but2.bind("<Button-1>",handle_keypress_stop)
  but2.grid(column=2,row=Row,sticky=tk.NW)

  return frame3

def setup_gui():
  Row=1

  wnd = tk.Tk()
  wnd.title('adf4351 controller')

  frame0=tk.Frame(wnd)

  # create a notebook
  notebook = ttk.Notebook(wnd)
  notebook.pack(pady=10, expand=True)

  frame1 = do_setting()
  frame2 = do_point()
  frame3 = do_sweep()
  frame4 = do_psweep()
  
  frame1.pack(fill='both', expand=True)
  frame2.pack(fill='both', expand=True)
  frame3.pack(fill='both', expand=True)
  frame4.pack(fill='both', expand=True)

  # add frames to notebook
  notebook.add(frame2, text='Point')
  notebook.add(frame3, text='Sweep')
  notebook.add(frame4, text='PSweep')
  notebook.add(frame1, text='Settings')

  connect(frame0,Row)
  notebook.grid(column=1,row=1,sticky=tk.NW)
  frame0.grid(column=1,row=2,sticky=tk.NW)


  wnd.mainloop()

ser=None
setup_gui()
