# Please do not change this widgets module for Quisk.  Instead copy
# it to your own quisk_widgets.py and make changes there.
#
# This module is used to add extra widgets to the QUISK screen.

from __future__ import print_function
from __future__ import absolute_import
from __future__ import division

import math, wx, time
import _quisk as QS
from configure import ComboCtrl


class BottomWidgets:	# Add extra widgets to the bottom of the screen
  REG_ANTENNA_TUNER = 7
  def __init__(self, app, hardware, conf, frame, gbs, vertBox):
    self.config = conf
    self.hardware = hardware
    self.application = app
    self.start_row = app.widget_row			# The first available row
    self.start_col = app.button_start_col	# The start of the button columns
    self.tuner_time = 0
    self.Widgets_0x06(app, hardware, conf, frame, gbs, vertBox)
  def Widgets_0x06(self, app, hardware, conf, frame, gbs, vertBox):
    self.num_rows_added = 1
    start_row = self.start_row
    self.btnPS = app.QuiskCheckbutton(frame, self.OnBtnPS, text='PS')
    self.btnPS.Enable(False)
    gbs.Add(self.btnPS, (start_row, self.start_col), flag=wx.EXPAND)
    self.btnPsCal = app.QuiskPushbutton(frame, self.OnBtnPsCal, 'PS Cal')
    self.btnPsCal.active = False
    gbs.Add(self.btnPsCal, (start_row, self.start_col + 1), flag=wx.EXPAND)
    self.atu_ctrl = ComboCtrl(frame, "ATU", ["Tune", "Bypass"], True)
    gbs.Add(self.atu_ctrl, (start_row, self.start_col + 2), (1, 2), flag=wx.EXPAND)
    bw, bh = self.atu_ctrl.GetMinSize()
    frame.Bind(wx.EVT_COMBOBOX_CLOSEUP, self.OnAtu)
    init = app.hermes_LNA_dB
    self.sliderLNA = app.SliderBoxHH(frame, 'RfLna %d dB', init, -12, 48, self.OnLNA, True)
    self.sliderLNA.idName = "RfLna"
    app.midiControls["RfLna"]	= (self.sliderLNA,	self.OnLNA)
    hardware.ChangeLNA(init)
    gbs.Add(self.sliderLNA, (start_row, self.start_col + 4), (1, 6), flag=wx.EXPAND)
    if conf.button_layout == "Small screen":
      # Display four data items in a single window
      self.text_temperature = app.QuiskText1(frame, '', bh)
      self.text_pa_current = app.QuiskText1(frame, '', bh)
      self.text_fwd_power = app.QuiskText1(frame, '', bh)
      self.text_swr = app.QuiskText1(frame, '', bh)
      self.text_data = self.text_temperature
      self.text_pa_current.Hide()
      self.text_fwd_power.Hide()
      self.text_swr.Hide()
      b = app.QuiskPushbutton(frame, self.OnTextDataMenu, '..')
      szr = self.data_sizer = wx.BoxSizer(wx.HORIZONTAL)
      szr.Add(self.text_data, 1, flag=wx.ALIGN_CENTER_VERTICAL)
      szr.Add(b, 0, flag=wx.ALIGN_CENTER_VERTICAL)
      gbs.Add(szr, (start_row, self.start_col + 10), (1, 2), flag=wx.EXPAND)
      # Make a popup menu for the data window
      self.text_data_menu = wx.Menu()
      item = self.text_data_menu.Append(-1, 'Temperature')
      app.Bind(wx.EVT_MENU, self.OnDataTemperature, item)
      item = self.text_data_menu.Append(-1, 'PA Current')
      app.Bind(wx.EVT_MENU, self.OnDataPaCurrent, item)
      item = self.text_data_menu.Append(-1, 'Fwd Power')
      app.Bind(wx.EVT_MENU, self.OnDataFwdPower, item)
      item = self.text_data_menu.Append(-1, 'SWR')
      app.Bind(wx.EVT_MENU, self.OnDataSwr, item)
    else:
      szr = wx.BoxSizer(wx.HORIZONTAL)
      gbs.Add(szr, (start_row, self.start_col + 10), (1, 18), flag=wx.EXPAND)
      text_temperature = wx.StaticText(frame, -1, ' Temp 100DC XX', style=wx.ST_NO_AUTORESIZE)
      size = text_temperature.GetBestSize()
      text_temperature.Destroy()
      self.text_temperature = wx.StaticText(frame, -1, '', size=size, style=wx.ST_NO_AUTORESIZE)
      self.text_pa_current = wx.StaticText(frame, -1, '', size=size, style=wx.ST_NO_AUTORESIZE)
      self.text_fwd_power = wx.StaticText(frame, -1, '', size=size, style=wx.ST_NO_AUTORESIZE)
      self.text_swr = wx.StaticText(frame, -1, '', size=size, style=wx.ST_NO_AUTORESIZE)
      flag=wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL
      szr.Add(self.text_temperature, 0, flag=flag)
      szr.Add(self.text_pa_current, 0, flag=flag)
      szr.Add(self.text_fwd_power, 0, flag=flag)
      szr.Add(self.text_swr, 0, flag=flag)
  def OnAtu(self, event):
    if not self.hardware.io_board.have_IO_Board:
      self.atu_ctrl.SetText("No ATU")
      self.tuner_time = 0
    elif self.atu_ctrl.GetValue() == "Tune":
      self.atu_ctrl.SetText("Tuning")
      self.tuner_time = time.time()
      self.hardware.WriteI2C(0x7d, 0x1D, self.REG_ANTENNA_TUNER, 1)
    else:
      self.atu_ctrl.SetText("Bypass")
      self.tuner_time = 0
      self.hardware.WriteI2C(0x7d, 0x1D, self.REG_ANTENNA_TUNER, 2)
      if self.application.spotButton.GetValue():
        self.application.spotButton.SetValue(False, True)
    self.sliderLNA.SetFocus()
  def OnLNA(self, event=None):
    value = self.sliderLNA.GetValue()
    self.hardware.ChangeLNA(value)
    self.application.hermes_LNA_dB = value
  def OnBtnPS(self, event):
    if self.btnPS.GetValue():
      QS.set_tx_audio(PsEnable=1)
      self.btnPsCal.Enable(False)
    else:
      QS.set_tx_audio(PsEnable=0)
      self.btnPsCal.Enable(True)
  def OnBtnPsCal(self, event):
    if len(self.application.multi_rx_screen.receiver_list) == 0:
      self.application.multi_rx_screen.OnAddReceiver(event=None, hide_it=True)
    self.btnPS.Enable(False)
    self.btnPsCal.active = True
    self.btnPsCal.SetColor(self.config.color_check_btn)
    QS.set_tx_audio(PsCal=1)
  def Code2Temp(self):		# Convert the HermesLite temperature code to the temperature
    temp = self.hardware.hermes_temperature
    # For best accuracy, 3.26 should be a user's measured 3.3V supply voltage.
    temp = (3.26 * (temp/4096.0) - 0.5)/0.01
    return temp
  def Code2Current(self):	# Convert the HermesLite PA current code to amps
    current = self.hardware.hermes_pa_current
    # 3.26 Ref voltage
    # 4096 steps in ADC
    # Gain of x50 for sense amp
    # Sense resistor is 0.04 Ohms
    current = ((3.26 * (current/4096.0))/50.0)/0.04
    # Scale by resistor voltage divider 1000/(1000+270) at input of slow ADC
    current = current / (1000.0/1270.0)
    return current
  def Code2FwdRevWatts(self, fwd, rev):	# Convert the HermesLite fwd/rev power code to watts forward and reverse
    #print (self.hardware.hermes_rev_power, self.hardware.hermes_fwd_power)
    fwd = self.hardware.InterpolatePower(fwd)
    rev = self.hardware.InterpolatePower(rev)
    # Which voltage is forward and reverse depends on the polarity of the current sense transformer
    if fwd >= rev:
      return fwd, rev
    else:
      return rev, fwd
  def UpdateText(self):		# Called at intervals
    # Button state
    if self.btnPsCal.active:
      if not QS.get_tx_audio("PsCal"):
        self.btnPsCal.active = False
        self.btnPsCal.SetColorNormal()
        self.btnPS.Enable(True)
    # Temperature
    temp = self.Code2Temp()
    temp = (" Temp %3.0f" % temp) + u'\u2103'
    self.text_temperature.SetLabel(temp)
    # power amp current
    current = self.Code2Current()
    current = " PA %4.0f ma" % (1000*current)
    self.text_pa_current.SetLabel(current)
    # forward and reverse peak power
    if not self.hardware.power_interpolator:	# For no interpolator, show ADC
      fwd = self.hardware.hermes_fwd_power
      rev = self.hardware.hermes_rev_power
      self.text_fwd_power.SetLabel("Fwd ADC %4d" % fwd)
      self.text_swr.SetLabel("Rev ADC %4d" % rev)
      return
    fwd, rev = self.Code2FwdRevWatts(self.hardware.hermes_fwd_peak, self.hardware.hermes_rev_peak)
    # forward less reverse power
    power = fwd - rev
    if power < 0.0:
      power = 0.0
    text = " PEP %3.1f watts" % power
    self.text_fwd_power.SetLabel(text)
    # SWR based on average power
    fwd, rev = self.Code2FwdRevWatts(self.hardware.hermes_fwd_power, self.hardware.hermes_rev_power)
    if fwd >= 0.05:
      gamma = math.sqrt(rev / fwd)
      if gamma < 0.98:
        swr = (1.0 + gamma) / (1.0 - gamma)
      else:
        swr = 99.0
      if swr < 9.95:
        text = " SWR %4.2f" % swr
      else:
        text = " SWR %4.0f" % swr
    else:
      text = " SWR  ---"
    self.text_swr.SetLabel(text)
    if self.tuner_time > 0:
      ret = self.hardware.io_board.Receive(self.REG_ANTENNA_TUNER)
      if ret:
        code = ret[0]
        if code == 0:
          t = "ATU OK"
          self.tuner_time = 0
        elif code == 0xEE:
          t = "ATU RF"
        elif code >= 0xF0:
          t = "Err 0x%X" % code
          self.tuner_time = 0
        else:
          t = "ATU 0x%X" % code
        self.atu_ctrl.SetText(t)
        if code == 0xEE:
          if not self.application.spotButton.GetValue():
            self.application.spotButton.SetValue(True, True)
        elif self.application.spotButton.GetValue():
          self.application.spotButton.SetValue(False, True)
      else:
        code = -1
      if code != 0 and self.tuner_time > 0 and time.time() - self.tuner_time > 20:
        self.tuner_time = 0
        self.atu_ctrl.SetText("ATU Err")
  def OnTextDataMenu(self, event):
    btn = event.GetEventObject()
    btn.PopupMenu(self.text_data_menu, (0,0))
  def OnDataTemperature(self, event):
    self.data_sizer.Replace(self.text_data, self.text_temperature)
    self.text_data.Hide()
    self.text_data = self.text_temperature
    self.text_data.Show()
    self.data_sizer.Layout()
  def OnDataPaCurrent(self, event):
    self.data_sizer.Replace(self.text_data, self.text_pa_current)
    self.text_data.Hide()
    self.text_data = self.text_pa_current
    self.text_data.Show()
    self.data_sizer.Layout()
  def OnDataFwdPower(self, event):
    self.data_sizer.Replace(self.text_data, self.text_fwd_power)
    self.text_data.Hide()
    self.text_data = self.text_fwd_power
    self.text_data.Show()
    self.data_sizer.Layout()
  def OnDataSwr(self, event):
    self.data_sizer.Replace(self.text_data, self.text_swr)
    self.text_data.Hide()
    self.text_data = self.text_swr
    self.text_data.Show()
    self.data_sizer.Layout()
