#!/usr/bin/python3

import os
import sys
import gi
import serial
import pyudev
import threading

gi.require_version('Gtk', '3.0')

from gi.repository import Gtk

class Modem():
    port = None

    def __init__(self):
        self.GetPort()

    def SendATcmd(self, cmd, expect = b"OK", fail=None):
        if not self.port:
            print("serial port not initialized", self.port)

        try:
            with serial.Serial(self.port, 115200, timeout=0.5) as ser:
                ser.write(cmd + b"\r\n")

                for i in range(20):
                    line = ser.readline()
                    if expect in line:
                        return True, line
                    if fail and fail in line:
                        return False, line
                    if b"ERROR" in line:
                        return False, line
        except:
            return False, None

        return False, None

    def GetPort(self):
        context = pyudev.Context()

        for dev in context.list_devices(subsystem='tty', ID_BUS='usb'):
            secondary = dev.get('ID_MM_PORT_TYPE_AT_PPP')
            if secondary and secondary == '1':
                self.port = dev.get('DEVNAME')
                print("trying port", self.port)
                try:
                    resp, val = self.SendATcmd(b"ATE0")
                    resp, val = self.SendATcmd(b"AT+BMSWVER", b"BMSWVER")
                    if val:
                        print("found port", self.port)
                        return
                except:
                    print("Can't write port {}".format(port))
                    self.port = None

    def VoLTEoff(self):
        if not self.SendATcmd(b"AT$QCPDPIMSCFGE=2,0,0,0", b"OK"):
            return False
        return True

    def VoLTEon(self):
        if not self.SendATcmd(b"AT+CGDCONT=2,\"IPV4V6\",\"ims\"", b"OK"):
            return False
        if not self.SendATcmd(b"AT$QCPDPIMSCFGE=2,1,0,0", b"OK"):
            return False
        return True

    def VoLTEcheck(self):
        resp, val = self.SendATcmd(b"AT+BMRAT", b"BMRAT")

        if not resp:
            return "Can't get LTE status"

        return val.decode().replace("+BMRAT: ", "")

    def CBSon(self):
        resp, val = self.SendATcmd(b"AT+CNMI=2,0,2,0,0")

        if not resp:
            return False

        print("AT+CNMI", val)
        resp, val = self.SendATcmd(b"AT+CSCB=0,\"50\",\"1\"")

        print(val)
        return resp

    def CBSoff(self):
        resp, val = self.SendATcmd(b"AT+CNMI=0,0,0,0,0")

        print(val)
        return resp

    def CBScheck(self):
        resp, val = self.SendATcmd(b"AT+CNMI?", b"+CNMI")

        if not resp:
            print("Can't get CBS status", val)
            return False

        print("CBS status", val)

        if "+CNMI: 2,0,2,0,0" in val.decode():
            return True

        return False

    def GetFWversion(self):
        resp, val = self.SendATcmd(b"AT+BMSWVER", b"BMSWVER")
        if resp:
            version = val.decode().replace("+BMSWVER: ", "").replace(",", "\n")
        else:
            version = "Failed to get Modem FW version"

        return version

class Handler():
    def onEnablePressed(self, *args):
        button = builder.get_object("VoLTEenable")
        if button.get_active():
            print("deactivating -",)
            if m.VoLTEoff():
                print("Success")
            else:
                print("Fail")
        else:
            print("activating -",)
            if m.VoLTEon():
                print("Success")
            else:
                print("Fail")

    def onCBSPressed(self, *args):
        button = builder.get_object("CBSenable")
        if button.get_active():
            print("deactivating -",)
            if m.CBSoff():
                print("Success")
            else:
                print("Fail")
        else:
            print("activating -",)
            if m.CBSon():
                print("Success")
            else:
                print("Fail")

    def onCheckPressed(self, *args):
        label = builder.get_object("VoLTEstatus")
        label.set_text(m.VoLTEcheck())

    def onExitPressed(self, *args):
        Gtk.main_quit()

builder = Gtk.Builder()
builder.add_from_file("/usr/share/bm818-tool/bm818-tool.glade")
builder.connect_signals(Handler())

m = Modem()

def GetModemValues():
    window = builder.get_object("ToolWindow")

    label = builder.get_object("FWversion")
    label.set_text(m.GetFWversion())

    label = builder.get_object("VoLTEstatus")
    label.set_text(m.VoLTEcheck())

    button = builder.get_object("CBSenable")
    if m.CBScheck():
        button.set_active(True)
    else:
        button.set_active(False)
#    button.set_visible(True)

    button = builder.get_object("VoLTEenable")
    resp, val = m.SendATcmd(b"AT$QCPDPIMSCFGE?", b"$QCPDPIMSCFGE: 2 , 1 , 0 , 0", b"$QCPDPIMSCFGE: 2 , 0 , 0 , 0")

    if resp:
        #print(val)
        button.set_active(True)
    else:
        #print(val)
        button.set_active(False)
#    button.set_visible(True)


def main():

    window = builder.get_object("ToolWindow")

    label = builder.get_object("FWversion")
    label.set_text("Fetching ...")

    label = builder.get_object("VoLTEstatus")
    label.set_text("Fetching ...")

    button = builder.get_object("CBSenable")
#    button.set_visible(False)

    button = builder.get_object("VoLTEenable")
#    button.set_visible(False)

    window.show_all()

    background = threading.Thread(target=GetModemValues)
    background.start()

    return Gtk.main()


if __name__ == '__main__':
    sys.exit(main())
