# gqrx-hamlib - a gqrx to Hamlib interface to keep frequency
# between gqrx and a radio in sync when using gqrx as a panadaptor
# using Hamlib to control the radio
#
# The Hamlib daemon (rigctld) must be running, gqrx started with
# the 'Remote Control via TCP' button clicked and
# comms to the radio working otherwise an error will occur when
# starting this program. Ports used are the defaults for gqrx and Hamlib.
#
#
# Copyright 2017, 2018 Simon Kennedy, G0FCU, g0fcu at g0fcu.com
# 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 3 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, see <http://www.gnu.org/licenses/>.

import sys
import socket
import time
from os.path import expanduser
from PyQt5 import QtGui, QtCore, QtWidgets
from PyQt5.QtCore import QThread
from gqrxHamlib import gqrxHamlibGUI
#import xmlrpc.client

class startControl(QThread):
    reportErr = QtCore.pyqtSignal(str, str)
    
    def __init__(self, control, oneoff, gqrxIPv, gqrxPortv, hamlibIPv, hamlibPortv,  modev, ifModev, ifFreqv):
        QThread.__init__(self)
        self.control = control
        self.oneoff = oneoff
        self.gqrxIPv = gqrxIPv
        self.gqrxPortv = gqrxPortv
        self.hamlibIPv = hamlibIPv
        self.hamlibPortv = hamlibPortv
        self.modev = modev
        TCP_IP = '127.0.0.1'
        
        self.ifFreqv = ifFreqv
        self.ifModev = ifModev
        

        
                  
    def __del__(self):
        self.wait()
      
    def run(self):    
        HAMLIB_PORT = 4532
        GQRX_PORT = 7356
        sockGqrx = 0
        sockHamlib = 0
        #self.setupUi(self)
        endpoint = 'hamlib'
        RIG_PORT = HAMLIB_PORT
        TCP_IP = self.hamlibIPv
        #TCP_IP = '127.0.0.1'
        #HAMLIB_PORT = 4532
        #self.gqrxIPv = '127.0.0.1'
        #GQRX_PORT = 7356
        #TCP_IP = "'127.0.0.1'"
        #HAMLIB_PORT = "'9537'"
        #self.gqrxIPv = "'127.0.0.1'"
        #GQRX_PORT = "'9536'"
        print (TCP_IP, HAMLIB_PORT, self.gqrxIPv, GQRX_PORT)
        sockHamlib = socket.create_connection((TCP_IP, HAMLIB_PORT))
            #sockHamlib = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
            # Bind the socket to the port
            #server_address1 = (TCP_IP, HAMLIB_PORT)
            #sockHamlib.connect(server_address)
            #sockHamlib.bind(server_address1)
        #sockGqrx = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
        # Bind the socket to the port
        #server_address2 = (self.gqrxIPv, GQRX_PORT)
        #sockGqrx.bind(server_address2)
        #sockGqrx.connect(server_address)
        sockGqrx = socket.create_connection((self.gqrxIPv, GQRX_PORT))
        rig_freq = 0
        gqrx_freq = 0
        old_rig_freq = 0
        old_gqrx_freq = 0
        rig_mode = ''
        gqrx_mode = ''
        set_mode = ''
        old_rig_mode = ''
        old_gqrx_mode = ''
        data = 0
                
        gqrx_freq = self.getfreq(self.gqrxIPv, GQRX_PORT, 'gqrx', sockGqrx)
        print (gqrx_freq)
        if gqrx_freq.find('\n') != -1:
            gqrx_freq = gqrx_freq[0:gqrx_freq.find('\n')]
        else:
            print('ERROR')
        old_gqrx_freq = 0 #gqrx_freq
                 
        while self.control > 0:       
            time.sleep(0.2)
            if self.control == 1 or self.control == 3:
                #rig_freq = str(self.getfreq(TCP_IP, RIG_PORT, endpoint))
                rig_freq = self.getfreq(TCP_IP, RIG_PORT, endpoint, sockHamlib)
                #print (rig_freq)
                if rig_freq[:4] != 'RPRT':
                    if endpoint == 'hamlib':
                        if rig_freq.find('\n') != -1:
                            rig_freq = rig_freq[0:rig_freq.find('\n')]
                    else:
                        rig_freqStr = repr(rig_freq)
                        if rig_freqStr.find('.') != -1:
                            rig_freqStr = rig_freqStr[0:rig_freqStr.find('.')]
                            rig_freq = int(rig_freqStr)
                    if rig_freq != old_rig_freq:
                        # set gqrx to Hamlib/flrig frequency
                        print ('call set gqrx freq', self.gqrxIPv, GQRX_PORT, 'gqrx', '@', rig_freq, '@', sockGqrx)
                        self.setfreq(self.gqrxIPv, GQRX_PORT, 'gqrx', int(rig_freq), sockGqrx)
                        #print('SetFreq Return Code from GQRX: {0}'.format(rc))
                        old_rig_freq = rig_freq
                        old_gqrx_freq = gqrx_freq
                    if self.modev == 'Y':
                        rig_mode = self.getmode(TCP_IP, RIG_PORT, endpoint, sockHamlib)[:3]
                        if rig_mode != old_rig_mode:
                            set_mode = rig_mode
                            # set gqrx to Hamlib frequency
                            self.setmode(self.gqrxIPv, GQRX_PORT, 'gqrx', set_mode, sockGqrx)
                            old_rig_mode = rig_mode
                            old_gqrx_mode = rig_mode
            
       
            if self.control == 1 or self.control == 2:
                gqrx_freq = self.getfreq(self.gqrxIPv, GQRX_PORT, 'gqrx', sockGqrx)
                #print (gqrx_freq)
                if gqrx_freq[:4] != 'RPRT':
                    if gqrx_freq.find('\n') != -1:
                        gqrx_freq = gqrx_freq[0:gqrx_freq.find('\n')]
                    if self.control == 2 and self.ifModev == 'Y':
                        if gqrx_freq != old_gqrx_freq:
                            if gqrx_freq > self.ifFreqv:
                                ifDiff = int(gqrx_freq) - int(self.ifFreqv)
                            else:
                                ifDiff = 0 - (int(self.ifFreqv) - int(gqrx_freq))
                            #print 'ifDiff', ifDiff,'ifFreqv',int(self.ifFreqv),'gqrx_freq',int(gqrx_freq)
                            rig_freq = str(self.getfreq(TCP_IP, RIG_PORT, endpoint, sockHamlib))
                            if endpoint == 'hamlib':
                                 if rig_freq.find('\n') != -1:
                                    rig_freq = rig_freq[0:rig_freq.find('\n')]
                            else:
                                if rig_freq.find('.') != -1:
                                    rig_freq = rig_freq[0:rig_freq.find('.')]
                            
                            self.setfreq(TCP_IP, RIG_PORT, endpoint, float(int(rig_freq) + int(ifDiff)), sockHamlib)
                            #print 'calc', float(int(rig_freq) - int(ifDiff))
                            #old_gqrx_freq = self.ifFreqv
                            gqrx_freq = self.ifFreqv
                            self.setfreq(self.gqrxIPv, GQRX_PORT, 'gqrx', float(gqrx_freq), sockGqrx)
                                
                        if self.modev == 'Y':        
                            gqrx_mode = self.getmode(self.gqrxIPv, GQRX_PORT, 'gqrx', sockGqrx)[:3]
                            if gqrx_mode != old_gqrx_mode:
                                # set Hamlib to gqrx frequency
                                self.setmode(TCP_IP, RIG_PORT, endpoint, gqrx_mode, sockGqrx)
                                #print('SetMode Return Code from Hamlib: {0}'.format(rc))
                                old_gqrx_mode = gqrx_mode
                                old_rig_mode = gqrx_mode  
                    else:
                        #print (gqrx_freq)
                        if gqrx_freq[:4] != 'RPRT':
                            if gqrx_freq != old_gqrx_freq:
                                # set Hamlib to gqrx frequency
                                self.setfreq(TCP_IP, RIG_PORT, endpoint, float(gqrx_freq), sockHamlib)
                                old_gqrx_freq = gqrx_freq
                                old_rig_freq = gqrx_freq
                            if self.modev == 'Y':        
                                gqrx_mode = self.getmode(self.gqrxIPv, GQRX_PORT, 'gqrx', sockGqrx)[:3]
        
                                if gqrx_mode != old_gqrx_mode:
                                    # set Hamlib to gqrx frequency
                                    self.setmode(TCP_IP, RIG_PORT, endpoint, gqrx_mode, sockHamlib)
                                    #print('SetMode Return Code from Hamlib: {0}'.format(rc))
                                    old_gqrx_mode = gqrx_mode
                                    old_rig_mode = gqrx_mode 
                            
            if self.oneoff == True:
                return
    
      
    def getfreq(self, IP, PORT, endpoint, sock):
        if endpoint == 'hamlib' or endpoint == 'gqrx':
            #sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
            # Bind the socket to the port
            #server_address = (IP, PORT)
            #sock.connect(server_address)
            sock.sendall(b'f\n')
            data = sock.recv(16)
            #print ('get', endpoint, ' ',IP ,' ',data)
            if data[:4] == 'RPRT':
                if data[:6] != 'RPRT 0':
                    self.reportErr.emit(endpoint, str(data))
                    return data
            #sock.close()
            data = data.decode("utf-8")
        else:
            data = 0
            data = self.server.main.get_frequency()
        return data
    
    def setfreq(self, IP, PORT, endpoint, freq, sock):
        if endpoint == 'hamlib' or endpoint == 'gqrx':
            #sock = socket.socket(socket.AF_INET, 
            #             socket.SOCK_STREAM) 
            # Bind the socket to the port
            #server_address = (IP, PORT)
            #sock.connect(server_address)
            build_msg = 'F ' + str(freq) + '\n'
            MESSAGE = bytes(build_msg, 'utf-8')
            #print(sock)
            sock.sendall(MESSAGE)
            print ('set', endpoint, ' ',IP ,' ',build_msg,MESSAGE)
            data = sock.recv(16)
            print ('set', endpoint, ' ',IP ,' ',data)
            if data[:4] == 'RPRT':
                 if data[:6] != 'RPRT 0':
                     self.reportErr.emit(endpoint, str(data))
                     return data
                    ##sock.close()
        else:
            data = self.server.main.set_frequency(float(freq))
        return data
    
    def getmode(self, IP, PORT, endpoint, sock):
        if endpoint == 'hamlib' or endpoint == 'gqrx':
            #sock = socket.socket(socket.AF_INET, 
            #                 socket.SOCK_STREAM) 
            # Bind the socket to the port
            #server_address = (IP, PORT)
            #sock.connect(server_address)
            sock.sendall(b'm\n')
            data = sock.recv(16)
            if data[:4] == 'RPRT':
                if data[:6] != 'RPRT 0':
                    self.reportErr.emit(endpoint, str(data))
                    return data
            #sock.close()
            data = data.decode("utf-8")
        else:
            data = self.server.rig.get_mode(str())  
        return data
    
    def setmode(self, IP, PORT, endpoint, mode, sock):
        if endpoint == 'hamlib' or endpoint == 'gqrx':
            #sock = socket.socket(socket.AF_INET, 
            #                 socket.SOCK_STREAM) 
            # Bind the socket to the port
            #server_address = (IP, PORT)
            #sock.connect(server_address)
            build_msg = 'M ' + str(mode) + ' 0' + '\n'
            MESSAGE = bytes(build_msg, "utf-8")
            sock.sendall(MESSAGE)
            data = ''
            data = sock.recv(7)
            if data[:4] == 'RPRT':
                if data[:6] != 'RPRT 0':
                    self.reportErr.emit(endpoint, str(data))
                    return data
            #sock.close()
        else:
            data = self.server.rig.set_mode(str(mode))
        return data
       
class gqrxHamlib(QtWidgets.QMainWindow, gqrxHamlibGUI.Ui_MainWindow):
    def __init__(self):
        super(self.__class__, self).__init__()
        self.setupUi(self)
        self.readConfig()
        self.control = 0
        oneoff = False
        global rc 
        rc = ''
        
        self.controlThread = startControl(self.control, oneoff, self.gqrxIPv, self.gqrxPortv, self.hamlibIPv, self.hamlibPortv, self.modev, self.ifModev, self.ifFreqv)
        self.controlThread.reportErr.connect(self.reportErrMsg)
        # At this point we want to allow user to stop/terminate the thread
        # so we enable that button
        self.btn_stop.setEnabled(True)
        self.controlThread.setTerminationEnabled(True)
        # And we connect the click of that button to the built in
        # terminate method that all QThread instances have
        self.btn_stop.clicked.connect(self.stopThread)
        self.actionSetup.triggered.connect(self.readConfig)
        self.buttonBox.accepted.connect(self.updateConfig)
        if self.ifModev != 'Y':
            self.pushButton.clicked.connect(self.gqrxhamlibSync)
            self.pushButton_3.clicked.connect(self.hamlibControl)
            self.pushButton_4.clicked.connect(self.hamlibControlOneoff)
            self.pushButton_8.clicked.connect(self.hamlibControlOneoff)
             
        self.pushButton_2.clicked.connect(self.gqrxControl)
        self.pushButton_6.clicked.connect(self.gqrxControlOneoff)
        
    def reportErrMsg(self, source, rc):
        self.errorMsg.setText('Error, return code ' + rc + ' reported by ' + source) 
                    
    def stopThread(self):
        self.btn_stop.setStyleSheet("background-color: red")
        if self.ifModev != 'Y':
            self.pushButton.setStyleSheet("background-color: green")
            self.pushButton_3.setStyleSheet("background-color: green")
            self.pushButton_4.setStyleSheet("background-color: green")
        self.pushButton_2.setStyleSheet("background-color: green")
        self.pushButton_6.setStyleSheet("background-color: green")
        self.control = 0
        self.controlThread.terminate()
        
    def gqrxhamlibSync(self):
        self.btn_stop.setStyleSheet("background-color: green")
        if self.ifModev != 'Y':
            self.pushButton.setStyleSheet("background-color: red")
            self.pushButton_3.setStyleSheet("background-color: green")
            self.pushButton_4.setStyleSheet("background-color: green")
        self.pushButton_2.setStyleSheet("background-color: green")
        self.pushButton_6.setStyleSheet("background-color: green")
        self.control = 1
        oneoff = False
        self.controlThread.terminate()
        self.errorMsg.setText('')
        self.controlThread = startControl(self.control, oneoff, self.gqrxIPv, self.gqrxPortv, self.hamlibIPv, self.hamlibPortv, self.modev, self.ifModev, self.ifFreqv)
        self.controlThread.reportErr.connect(self.reportErrMsg)
        self.controlThread.start()
        
    def gqrxControl(self):
        self.btn_stop.setStyleSheet("background-color: green")
        if self.ifModev != 'Y':
            self.pushButton.setStyleSheet("background-color: green")
            self.pushButton_3.setStyleSheet("background-color: green")
            self.pushButton_4.setStyleSheet("background-color: green")
        self.pushButton_2.setStyleSheet("background-color: red")
        self.pushButton_6.setStyleSheet("background-color: green")
        self.control = 2
        oneoff = False
        self.controlThread.terminate()
        self.errorMsg.setText('')
        self.controlThread = startControl(self.control, oneoff, self.gqrxIPv, self.gqrxPortv, self.hamlibIPv, self.hamlibPortv, self.modev, self.ifModev, self.ifFreqv)
        self.controlThread.reportErr.connect(self.reportErrMsg)
        self.controlThread.start()
    
    def hamlibControl(self):
        self.btn_stop.setStyleSheet("background-color: green")
        if self.ifModev != 'Y':
            self.pushButton.setStyleSheet("background-color: green")
            self.pushButton_3.setStyleSheet("background-color: red")
            self.pushButton_4.setStyleSheet("background-color: green")
        self.pushButton_2.setStyleSheet("background-color: green")
        self.pushButton_6.setStyleSheet("background-color: green")
        self.control = 3
        oneoff = False
        self.controlThread.terminate()
        self.errorMsg.setText('')
        self.controlThread = startControl(self.control, oneoff, self.gqrxIPv, self.gqrxPortv, self.hamlibIPv, self.hamlibPortv, self.modev, self.ifModev, self.ifFreqv)
        self.controlThread.reportErr.connect(self.reportErrMsg)
        self.controlThread.start()
              
    def gqrxControlOneoff(self):
        self.btn_stop.setStyleSheet("background-color: green")
        if self.ifModev != 'Y':
            self.pushButton.setStyleSheet("background-color: green")
            self.pushButton_3.setStyleSheet("background-color: green")
            self.pushButton_4.setStyleSheet("background-color: green")
        self.pushButton_2.setStyleSheet("background-color: green")
        self.pushButton_6.setStyleSheet("background-color: red")
        self.control = 2
        oneoff = True
        self.controlThread.terminate()
        self.errorMsg.setText('')
        self.controlThread = startControl(self.control, oneoff, self.gqrxIPv, self.gqrxPortv, self.hamlibIPv, self.hamlibPortv, self.modev, self.ifModev, self.ifFreqv)
        self.controlThread.reportErr.connect(self.reportErrMsg)
        self.controlThread.start()
        self.pushButton_6.setStyleSheet("background-color: green")
        self.control = 0
        
    def hamlibControlOneoff(self):
        self.btn_stop.setStyleSheet("background-color: green")
        if self.ifModev != 'Y':
            self.pushButton.setStyleSheet("background-color: green")
            self.pushButton_3.setStyleSheet("background-color: green")
            self.pushButton_4.setStyleSheet("background-color: red")
            self.pushButton_8.setStyleSheet("background-color: red")
        self.pushButton_2.setStyleSheet("background-color: green")
        self.pushButton_6.setStyleSheet("background-color: green")
        self.control = 3
        oneoff = True
        self.controlThread.terminate()
        self.errorMsg.setText('')
        self.controlThread = startControl(self.control, oneoff, self.gqrxIPv, self.gqrxPortv, self.hamlibIPv, self.hamlibPortv, self.modev, self.ifModev, self.ifFreqv)
        self.controlThread.reportErr.connect(self.reportErrMsg)
        self.controlThread.start()
        self.pushButton_4.setStyleSheet("background-color: green")
        self.pushButton_8.setStyleSheet("background-color: green")
        self.control = 0
        
    def readConfig(self):
        homedir = expanduser("~")
        try:
            cf = open(homedir + '/.config/.gqrxHamlib.config', 'r')
        except IOError:
            cf = open(homedir + '/.config/.gqrxHamlib.config', 'w+')
            configLine = '127.0.0.1,7356,127.0.0.1,4532,Y,N,0'
            cf.write(configLine)
            cf.close()
            cf = open(homedir + '/.config/.gqrxHamlib.config', 'r')
        configLine = cf.read()
        # handle upgrade from 2.5 to 2.6 where there are two additional parameters for IF panaadaptor functionality
        countitems = len(configLine.split(','))
        if countitems == 8:
            self.gqrxIPv, self.gqrxPortv, self.hamlibIPv, self.hamlibPortv, self.modev = configLine.split(',')
            self.ifModev = 'N'
            self.ifFreqv = str(0)
            cf.close()
            cf = open(homedir + '/.config/.gqrxHamlib.config', 'w')
            configLine = self.gqrxIPv+','+self.gqrxPortv+','+self.hamlibIPv+','+self.hamlibPortv+','+self.modev+','+self.ifModev+','+self.ifFreqv
            cf.write(configLine)
            cf.close()
        else:
            self.gqrxIPv, self.gqrxPortv, self.hamlibIPv, self.hamlibPortv, self.modev, self.ifModev, self.ifFreqv = configLine.split(',')
        self.gqrxIP.setText(self.gqrxIPv)
        self.gqrxPort.setText(self.gqrxPortv)
        self.hamlibIP.setText(self.hamlibIPv)
        self.hamlibPort.setText(self.hamlibPortv)
        self.if_freq.setText(self.ifFreqv)
        if self.modev == 'Y':
            self.mode.setChecked(True)
        else:
            self.mode.setChecked(False)
        if self.ifModev == 'Y':
            self.panadaptor.setChecked(True)
            self.pushButton.setStyleSheet("background-color: grey")
            self.pushButton_2.setStyleSheet("background-color: green")
            self.pushButton_3.setStyleSheet("background-color: grey")
            self.pushButton_4.setStyleSheet("background-color: grey")
            self.pushButton_8.setStyleSheet("background-color: grey")
            self.pushButton_6.setStyleSheet("background-color: green")
        else:
            self.panadaptor.setChecked(False)
            self.pushButton.setStyleSheet("background-color: green")
            self.pushButton_2.setStyleSheet("background-color: green")
            self.pushButton_3.setStyleSheet("background-color: green")
            self.pushButton_4.setStyleSheet("background-color: green")
            self.pushButton_8.setStyleSheet("background-color: green")
            self.pushButton_6.setStyleSheet("background-color: green")
        cf.close()
            
    def updateConfig(self):
        homedir = expanduser("~")
        cf = open(homedir + '/.config/.gqrxHamlib.config', 'w')
        self.gqrxIPv = self.gqrxIP.text()
        self.gqrxPortv = self.gqrxPort.text()
        self.hamlibIPv = self.hamlibIP.text()
        self.hamlibPortv = self.hamlibPort.text()
        if self.mode.isChecked():
            self.modev = 'Y'
        else:
            self.modev = 'N'
        if self.panadaptor.isChecked():
            self.ifModev = 'Y'
            self.pushButton.setStyleSheet("background-color: grey")
            self.pushButton_2.setStyleSheet("background-color: green")
            self.pushButton_3.setStyleSheet("background-color: grey")
            self.pushButton_4.setStyleSheet("background-color: grey")
            self.pushButton_8.setStyleSheet("background-color: grey")
            self.pushButton_6.setStyleSheet("background-color: green")
        else:
            self.ifModev = 'N'
            self.pushButton.setStyleSheet("background-color: green")
            self.pushButton_2.setStyleSheet("background-color: green")
            self.pushButton_3.setStyleSheet("background-color: green")
            self.pushButton_4.setStyleSheet("background-color: green")
            self.pushButton_8.setStyleSheet("background-color: green")
            self.pushButton_6.setStyleSheet("background-color: green")
        configLine = self.gqrxIPv+','+self.gqrxPortv+','+self.hamlibIPv+','+self.hamlibPortv+','+self.modev+','+self.ifModev+','+self.ifFreqv
        cf.write(configLine)
        cf.close()
        # revert to previous sync method
        if self.control == 1:
            self.gqrxhamlibSync()
        elif self.control == 2:
            self.gqrxControl()
        elif self.control == 3:
            self.hamlibControl()
        else:
            self.stopThread()

def main():
    app = QtWidgets.QApplication(sys.argv)
    form = gqrxHamlib()
    form.show()
    app.exec_()
            
if __name__ == '__main__':
    main()

