#!/usr/bin/env python
#----------------------------------------------
#               guiphone.py
#----------------------------------------------
#Original code written by Michael Wright, y2kLeader.com
#If you use all or part of this code in your project please 
#   include the line above in the header.
#To run: python3 guiphone.py 

from tkinter import *
import tkinter as tk
from tkinter import ttk
import tkinter.font as font
from PIL import Image, ImageTk
import sys
import os
import time
import datetime
from datetime import datetime
import serial
import io
import mysql.connector
import threading
import textwrap
from tkinter import messagebox
from tkinter import simpledialog
#import RPi.GPIO as gpio

ringtone="incomingcall.wav"
message_alert="messagealert.wav"
disconnect_tone="hangup.wav"
outgoing_ringtone="outgoingcall.wav"
ser=serial.Serial('/dev/ttyUSB3',115200,timeout=.5)
event_port=serial.Serial('/dev/ttyUSB2',115200,timeout=.5)
modem=""
mic=""
speaker=""
device_name=""
#---------------------------------------------------------
def get_audio_device_numbers():
#---------------------------------------------------------
   global modem
   global mic
   global speaker
   #get the audio id number for the Quectel EC25 Modem
   device=os.popen("arecord -l | grep EC25 | awk '{print $2+0}'")
   modem=device.read().replace("\r","").replace("\n","")

   #get the microphone device number
   device=os.popen("arecord -l | grep '"+recdev.get()+"' | awk '{print $2+0}'")
   mic=device.read().replace("\r","").replace("\n","")

   #get the speaker device number
   device=os.popen("aplay -l | grep '"+playdev.get()+"' | awk '{print $2+0}'")
   speaker=device.read().replace("\r","").replace("\n","")

tn=""
exitflag=0
callmode="none"
#listpick=""
messages_listpick=""
contact_recordnum=0
texter_popup=""
storage_device=""
#---------------------------------------------------------
def on_tab_selected(event):
#---------------------------------------------------------
   #This function is fired when a notebook tab is clicked
   selected_tab = event.widget.select()
   tab_text=event.widget.tab(selected_tab,"text")
   if tab_text=="MESSAGES":
      populate_messages_list()
   if tab_text=="GPS":
      refresh_gps_location()
   if tab_text=="CONTACTS":
      populate_contacts_list()

root=Tk()
root.title("GUI Phone")
root.geometry("500x700")
notebook=ttk.Notebook(root)
notebook.pack(pady=15,fill='both',expand=1)
dialer=Frame(notebook,width=500,height=700,bg="darkblue")
contacts=Frame(notebook,width=500,height=700,bg="white")
messages=Frame(notebook,width=500,height=700,bg="white")
gps=Frame(notebook,width=500,height=700,bg="white")
settings=Frame(notebook,width=500,height=700,bg="lightgrey")
notebook.bind("<<NotebookTabChanged>>",on_tab_selected)
notebook.add(dialer,text="DIALER")
notebook.add(contacts,text="CONTACTS")
notebook.add(messages,text="MESSAGES")
notebook.add(gps,text="GPS")
notebook.add(settings,text="SETTINGS")
typed_number=tk.StringVar()
#----------------------------------------
def kill_process(process_name):
#----------------------------------------
   response=os.popen("ps | grep "+process_name+" | awk {'print $1'}").read().strip()
   lines=response.split('\n')
   if(len(response)==0): #return if no processes found
      return
   for line in lines:
      os.system("kill -9 "+line)
      time.sleep(.5)

#----------------------------------------
def send3(command,port,sleeptime):
#----------------------------------------
   command=command+"\r"
   port.write(command.encode())
   time.sleep(sleeptime)  
   data=ser.read(10000)
   data=data.decode("utf-8")
   data=data.replace("\r\n\r\nOK\r\n","").strip()
   return data

#---------------------------------------------------------
def play(soundfile):
#---------------------------------------------------------
   playstring="aplay -q -D plughw:"+speaker+" "+soundfile+" & "
   os.system(playstring)

#---------------------------------------------------------
def check_for_events():
#---------------------------------------------------------
   global callmode
   global caller_name
   global caller_number
   #checks for events every 2 seconds
   threading.Timer(2.0, check_for_events).start()
   if(exitflag==1):
      os.system('clear')
      os._exit(0)
   eventbuf=event_port.read(1000)
   eventbuffer=eventbuf.decode("utf-8").strip()

   #---check for an incoming voice call
   if (eventbuffer.find('+CRING: VOICE') != -1 and callmode=="none" or callmode=="ringing"):
      callerinfo=(eventbuffer.partition('+CLIP: ')[2])
      info=callerinfo.split(",")
      if(len(info)==6):  #has caller info
         caller_number=info[0].replace('"','')
         caller_name=info[4].replace('"','')
        
         if(len(caller_name)!=0):
            infotxt="Call from "+caller_name
            dialer_alert.configure(text="Call from "+caller_name)
         if(len(caller_name)==0):
            infotxt="Call from "+caller_number
            dialer_alert.configure(text="Call from "+caller_number)
         callmode="ringing"
         callbutton.config(image=ringpic)
         play(ringtone)

   #---check to see if the remote phone hung up
   if (eventbuffer.find('NO CARRIER') != -1):
      eventbuffer=""
      dialer_alert.configure(text=" ")
      kill_process("arecord")
      kill_process("aplay") 
      callmode="none"
      callbutton.config(image=callpic)
      play(disconnect_tone)

   #---check to see if there was an incoming text 
   if (eventbuffer.find("+CMTI:") != -1):
      textnum=(eventbuffer.partition('+CMTI: ')[2])
      textnum=(textnum.partition(',')[2])
      send3("AT+CMGF=1",ser,.1)
      response=send3("AT+CMGR="+textnum,ser,.1)
      lines=(response.partition('+CMGR: ')[2]).split("\r\n")
      metadata=lines[0]
      msg=lines[1]
      text_message=textwrap.fill(text=msg, width=40)
      tinfo=metadata.split(",")
      sender=tinfo[1].replace('"','')
      dialer_alert.configure(text="Message from "+sender+"\n"+text_message)
      play(message_alert)
      eventbuffer=""
#---------------------------------------------------------
def initiate_call_audio():
#---------------------------------------------------------
   kill_process("arecord")
   kill_process("aplay")
   get_audio_device_numbers()
   voice_out="arecord -q -f S16_LE -D plughw:"+mic+" | aplay -q -D plughw:"+modem+" -c 1 -f S16_LE -r 44100 &"
   voice_in="arecord -q -D plughw:"+modem+" -c 1 -f S16_LE | aplay -q -f S16_LE -D plughw:"+speaker+" &"
   os.system(voice_out)
   time.sleep(1)
   os.system(voice_in)
   time.sleep(1)

#---------------------------------
def key_pressed(key):
#---------------------------------
   global callmode
   global tn
   if(ord(key)>47 and ord(key)<58 or key=="#" or key=="*"):
      tn=tn+key
      play("keypress.wav")
      send3('AT+VTS="'+key+'"',ser,.1) # send the key tone
      typed_number.set(tn)
      return
   if(key=="<"):
      tn=tn[:-1]
      typed_number.set(tn)
      return
   if(key=="x"):
      exitflag=1
      os._exit(0)
   if(key=="c"):
      if(callmode=="none"):
         make_a_call()
         return
      if(callmode=="ringing"):
         answer_call()
         return
      if(callmode=="incall" or callmode=="ringing"):
         hangup()
         return


#---------------------------------
def make_a_call():
#---------------------------------
   global callmode
   callmode="incall"
   dialer_alert.configure(text="Calling "+typed_number.get())
   callbutton.config(image=incallpic)
   send3('AT+QGPSCFG=\"outport\",\"none\"',ser,.1)
   send3("AT+qcfg=\"USBCFG\",0x2c7c,0x0125,1,1,1,1,1,1,1",ser,.1)
   send3("AT+qpcmv=1,2",ser,.1)
   send3("ATD"+typed_number.get()+";",ser,.1)
   initiate_call_audio()
   #If you are getting 2 outgoing ringtones, delete from this line to the end of the function
   ringcounter=0
   while 1:
      tdata = ser.read()  
      play(outgoing_ringtone)    
      ringcounter=ringcounter+1
      if(ringcounter==8):  #call was not picked up after 8 rings
         break
      time.sleep(1)           
      data_left = ser.inWaiting()
      tdata += ser.read(data_left) 
      d=tdata.decode("utf-8")
      if (d.find('+') != -1):
         callmode="incall"
         initiate_call_audio()
         break



#---------------------------------
def answer_call():
#---------------------------------
   kill_process("arecord")
   kill_process("aplay")
   global callmode
   global caller_name
   global caller_number
   callmode="incall"
   callbutton.config(image=incallpic)
   #stop the ring tone
   os.system("kill $(ps auxww | grep -v grep | grep "+ringtone+" | awk {'print $2'})")
   initiate_call_audio()
   #initiate the modem for a voice call
   send3('AT+QGPSCFG=\"outport\",\"none\"',ser,.1)
   send3("AT+qcfg=\"USBCFG\",0x2c7c,0x0125,1,1,1,1,1,1,1",ser,.1)
   send3("AT+qpcmv=1,2",ser,.1)
   send3("ATA",ser,.1)
   caller=caller_name
   if (caller_name==""):
      caller_name=caller_number
   dialer_alert.configure(text="Connected with "+caller_name)

#---------------------------------
def hangup():
#---------------------------------
   global callmode
   callmode="none"
   dialer_alert.configure(text=" ")
   typed_number.set(tn)
   send3("ATH",ser,.1)
   play(disconnect_tone)
   callbutton.config(image=callpic)
   kill_process("arecord")
   kill_process("aplay")
#---------------------------------
def get_contacts_choice(event):
#---------------------------------
   global listpick
   global listphone
   # Keeps track of which contact was selected
   selection = event.widget.curselection()
   value=""
   for entry in selection:
      try:
         value = event.widget.get(selection[0])
      except:
         print("error")
   print("setting listpic as "+value)
   listpick=value
#---------------------------------
def get_message_choice(event):
#---------------------------------
   global messages_listpick
   # Keeps track of which message was selected
   selection = event.widget.curselection()
   value=""
   for entry in selection:
      try:
         value = event.widget.get(selection[0])
      except:
         messagebox.showinfo("Phonebook entry not found.")
   messages_listpick=value

#---------------------------------
def call_contact(sel):
#---------------------------------
   notebook.select(dialer)
   global callmode
   callmode="incall"
   #search the phonebook for the contact_recordnum
   response=send3('AT+CPBF="'+sel+'"',ser,.1)
   if (response.find('+CPBF: ') != -1):
      line=(response.partition('+CPBF: ')[2]).strip()
      info=line.split(",")
      contact_recordnum=info[0] #for reference only
      contact_number=info[1].replace('"','')
   
   dialer_alert.configure(text="Calling "+contact_number)
   callbutton.config(image=incallpic)
   send3('AT+QGPSCFG=\"outport\",\"none\"',ser,.1)
   send3("AT+qcfg=\"USBCFG\",0x2c7c,0x0125,1,1,1,1,1,1,1",ser,.1)
   send3("AT+qpcmv=1,2",ser,.1)
   send3("ATD"+contact_number+";",ser,.1)
   initiate_call_audio()

#---------------------------------
def text_contact(sel):
#---------------------------------
   response=send3('AT+CPBF="'+sel+'"',ser,.1)
   if (response.find('+CPBF: ') != -1):
      line=(response.partition('+CPBF: ')[2]).replace('OK','').replace('\r\n','').replace('"','')
      info=line.split(",")
      contact_number=info[1]
      contact_name=info[3]
   message=simpledialog.askstring(title="Send a Message",prompt="Text the following to "+contact_name)
   send3("AT+CMGF=1",ser,.1)
   send3('AT+CSCS="GSM"',ser,.1)
   send3('AT+CMGS="'+contact_number+'"',ser,.1)
   send3(message+"\x1a",ser,.1)
#---------------------------------
def edit_contact():
#---------------------------------
   send3('AT+CPBF="'+listpick+'"',ser,.1)
   buf=ser.read(1000)
   buffer=buf.decode("utf-8").strip()
   if (buffer.find('+CPBF: ') != -1):
      line=(buffer.partition('+CPBF: ')[2]).replace('OK','').replace('\r\n','').replace('"','')
      info=line.split(",")
      contact_recordnum=info[0]
      contact_number=info[1]
      contact_type=info[2]
      contact_name=info[3]
      new_name=simpledialog.askstring(title="Change Contact Name",prompt="Change name from "+contact_name+" to:")
      new_number=simpledialog.askstring(title="Change Contact Number",prompt="Change number from "+contact_number+" to:")
      if(new_name!=contact_name):
         name2=new_name
      if(new_name==""):
         name2=contact_name
      if (new_number!=contact_number):
         number2=new_number
      if (new_number==""):
         number2=contact_number
      if(new_name=="" and new_number==""):
         return      
      ct=contact_recordnum+',"'+number2+'",'+contact_type+',"'+name2+'"'
      send3('AT+CPBW='+ct,ser,.1)
      populate_contacts_list()

#---------------------------------
def delete_contact():
#---------------------------------
   send3('AT+CPBF="'+listpick+'"',ser,.1)
   buf=ser.read(1000)
   buffer=buf.decode("utf-8").strip()
   if (buffer.find('+CPBF: ') != -1):
      line=(buffer.partition('+CPBF: ')[2]).replace('OK','').replace('\r\n','').replace('"','')
      info=line.split(",")
      contact_recordnum=info[0]
      send3("AT+CPBW="+contact_recordnum,ser,.1)
      populate_contacts_list()
#---------------------------------
def create_contact():
#---------------------------------
   new_name=simpledialog.askstring(title="Create Contact",prompt="Contact Name:")
   new_number=simpledialog.askstring(title="Create Contact",prompt="Phone Number:")
   if(new_name=="" or new_number==""):
      return
   ct='"'+new_number+'",129,"'+new_name+'"'
   send3('AT+CPBW=,'+ct,ser,.1)
   populate_contacts_list()



#===========Populate dialer Folder=========================
scrnfont = font.Font(family='default', size=28)
keypadfont = font.Font(family='Helvetica', size=36, weight='bold')
alertfont = font.Font(family='Helvetica', size=18)

t1=tk.Entry(dialer,textvariable=typed_number, font=scrnfont).grid(row=1,column=0,columnspan=5,pady=(0,15))
Button(dialer, text="1",font=keypadfont,command=lambda key="1": key_pressed(key)).grid(row=2,column=1,sticky="N,S,E,W") 
Button(dialer, text="2",font=keypadfont,command=lambda key="2": key_pressed(key)).grid(row=2,column=2,sticky="N,S,E,W") 
Button(dialer, text="3",font=keypadfont,command=lambda key="3": key_pressed(key)).grid(row=2,column=3,sticky="N,S,E,W") 
Button(dialer, text="4",font=keypadfont,command=lambda key="4": key_pressed(key)).grid(row=3,column=1,sticky="N,S,E,W") 
Button(dialer, text="5",font=keypadfont,command=lambda key="5": key_pressed(key)).grid(row=3,column=2,sticky="N,S,E,W") 
Button(dialer, text="6",font=keypadfont,command=lambda key="6": key_pressed(key)).grid(row=3,column=3,sticky="N,S,E,W") 
Button(dialer, text="7",font=keypadfont,command=lambda key="7": key_pressed(key)).grid(row=4,column=1,sticky="N,S,E,W") 
Button(dialer, text="8",font=keypadfont,command=lambda key="8": key_pressed(key)).grid(row=4,column=2,sticky="N,S,E,W") 
Button(dialer, text="9",font=keypadfont,command=lambda key="9": key_pressed(key)).grid(row=4,column=3,sticky="N,S,E,W") 
Button(dialer, text="*",font=keypadfont,command=lambda key="*": key_pressed(key)).grid(row=5,column=1,sticky="N,S,E,W") 
Button(dialer, text="0",font=keypadfont,command=lambda key="0": key_pressed(key)).grid(row=5,column=2,sticky="N,S,E,W") 
Button(dialer, text="#",font=keypadfont,command=lambda key="#": key_pressed(key)).grid(row=5,column=3,sticky="N,S,E,W") 
exitpic1=Image.open("exit.png")
resized_exitpic=exitpic1.resize((80,80),Image.ANTIALIAS)
exitpic=ImageTk.PhotoImage(resized_exitpic)
callpic1=Image.open("call_icon.png")
resized_callpic=callpic1.resize((80,80),Image.ANTIALIAS)
callpic=ImageTk.PhotoImage(resized_callpic)
incallpic1=Image.open("incall_icon.png")
resized_incallpic=incallpic1.resize((80,80),Image.ANTIALIAS)
incallpic=ImageTk.PhotoImage(resized_incallpic)
ringpic1=Image.open("phoneringing.gif")
resized_ringpic=ringpic1.resize((80,80),Image.ANTIALIAS)
ringpic=ImageTk.PhotoImage(resized_ringpic)
back1=Image.open("back_icon.png")
resized_back1=back1.resize((60,60),Image.ANTIALIAS)
backpic=ImageTk.PhotoImage(resized_back1)
exitbutton=Button(dialer,image=exitpic,text="x",width=3,font=keypadfont,command=lambda key="x": key_pressed(key)).grid(row=6,column=1,sticky="N,S,E,W")
callbutton=Button(dialer,image=callpic,text="call",width=3,font=keypadfont,command=lambda key="c": key_pressed(key))
callbutton.grid(row=6,column=2,sticky="N,S,E,W")
callbutton.config(image=callpic)
callbutton.config(text="call")
backbutton=Button(dialer,image= backpic,text="x",width=3,font=keypadfont,command=lambda key="<": key_pressed(key)).grid(row=6,column=3,sticky="N,S,E,W")
Label(dialer,text="",fg="white",bg="darkblue").grid(row=7,column=0,columnspan=5,sticky="N,S,E,W") #spacer
dialer_alert=Label(dialer,text="",fg="white",bg="darkblue",font=alertfont)
dialer_alert.grid(row=8,column=0,columnspan=5,sticky="N,S,E,W")

#==========Populate the contacts folder=====================
listfont = font.Font(family='Helvetica', size=24)
conbuttonfont=font.Font(family='Helvetica', size=22)
#---------------------------------
def populate_contacts_list():
#---------------------------------
   send3("AT+CPBR=1,100",ser,.1)
   data=ser.read(10000)
   data=data.decode("utf-8").strip()
   data=data.replace('OK','')
   records=data.split("+CPBR: ")
   lb = Listbox(contacts,font=listfont,width=26, height=13,selectmode=SINGLE)  
   for i in range(1,len(records)):
      contact=records[i].split(",")
      cr=contact[0]
      contact_recordnum=(cr.partition('+CPBR ')[0])
      contact_number=contact[1].replace('"','')
      contact_type=contact[2]
      contact_name=contact[3].replace('"','').replace('\r\n','')
      if (contact_name[0]!="["):
         lb.insert(END,contact_name)   
   lb.grid(row=0,column=1,pady=10)  
   lb.bind('<<ListboxSelect>>',get_contacts_choice)
   my_scrollbar = Scrollbar(contacts,orient=VERTICAL,width=50)
   my_scrollbar.grid(row=0, column=1, sticky="NSE",pady=10)
   lb.config(yscrollcommand=my_scrollbar.set)
   my_scrollbar.config(command=lb.yview)
   #add buttons below listbox with contacts
   contact_call_button=Button(contacts, text="Call",font=conbuttonfont,command=lambda: call_contact(lb.get(ACTIVE))).place(x=5,y=520)
   contact_call_button=Button(contacts, text="Text",font=conbuttonfont,command=lambda: text_contact(lb.get(ACTIVE))).place(x=95,y=520)
   contact_call_button=Button(contacts, text="Edit",font=conbuttonfont,command=lambda: edit_contact()).place(x=190,y=520)
   contact_call_button=Button(contacts, text="Del",font=conbuttonfont,command=lambda: delete_contact()).place(x=280,y=520)
   contact_call_button=Button(contacts, text="New",font=conbuttonfont,command=lambda: create_contact()).place(x=365,y=520)

#==========Populate the messages folder=====================
messagesfont = font.Font(family='Helvetica', size=16)
messageslabelfont = font.Font(family='Helvetica', size=16)
messagesbuttonfont=font.Font(family='Helvetica', size=22)
messages_label=Label(messages,text="Stanby while populating messages...",fg="white",bg="darkblue",font=messageslabelfont,justify=CENTER,width=40)
messages_label.grid(row=0,column=0,sticky="E,W")

#---------------------------------
def view_message():
#---------------------------------
   data=messages_listpick.split("~")
   the_date=data[0]
   phone_number=data[1]
   message_sequence=data[2]
   message=data[3]
   message_recordnum=data[4]
   message_recordnum=message_recordnum.replace("[Message #","")
   message_recordnum=message_recordnum.replace("]","")
   message=textwrap.fill(text=message, width=40)
   #messagebox.showinfo(phone_number,message_sequence+" "+message)
   #messagebox.askokcancel(title=phone_number, message=message+"\r\nClick OK to reply")
   os.system("matchbox-keyboard &")  #start onscreen keybaord
   reply=simpledialog.askstring(title="Reply to Message",prompt=message)
   send3("AT+CMGF=1",ser,.1)
   send3('AT+CSCS="GSM"',ser,.1)
   send3('AT+CMGS="'+phone_number+'"',ser,.1)
   send3(reply+"\x1a",ser,.1)
#---------------------------------
def del_message():
#---------------------------------
   data=messages_listpick.split("~")
   message_recordnum=data[4]
   message_recordnum=message_recordnum.replace("[Message #","")
   message_recordnum=message_recordnum.replace("]","")
   send3("AT+CMGD="+message_recordnum,ser,.1)
   populate_messages_list()
#---------------------------------
def del_all_messages():
#---------------------------------
   send3("AT+CMGD=,4",ser,.1)
   populate_messages_list()
#---------------------------------
def populate_messages_list():
#---------------------------------
   messages_label.configure(text="Stanby while populating messages...")
   messages_listbox = Listbox(messages,font=messagesfont,width=40, height=16)  
   #first read where the messages are stored and space remaining
   send3("AT+CPMS?",ser,.1)
   memdata=ser.read(1000)
   memdata=memdata.decode("utf-8").strip()
   storage_area=(memdata.partition('+CPMS: "')[2])
   storage_area=(storage_area.partition('"')[0])
   if(storage_area=="ME"):
      sto="Modem Chip"
   if(storage_area=="SM"):
      sto="SIM Card"
   memdata=memdata.replace('OK','')
   memdata=memdata.replace('\r\n','')
   mem=memdata.split(",")
   used=mem[1]
   capacity=mem[2]
   available=int(capacity)-int(used)
   space_available=used+" messages stored, "+str(available)+" spaces available"
   messages_label.configure(text="Storage Area = "+sto+"\n"+space_available)
   messages_listbox = Listbox(messages,font=messagesfont,width=24, height=17,selectmode=SINGLE)
   send3("AT+CMGF=1",ser,.1)
   send3('AT+CMGL="ALL"',ser,.1)
   txtdata=ser.read(10000)
   txtdata=txtdata.decode("utf-8").strip()
   if (txtdata.find("+CMGL:") != -1):
      record=txtdata.split("+CMGL:")
      for i in range(1,len(record)):
         #first extract the message number 
         line=record[i].split("\r\n")
         metadata=line[0].split(",")
         message_number=int(metadata[0])
         #query this particular message to get more detailed metadata
         send3("AT+QCMGR="+str(message_number),ser,.1)
         data=ser.read(1000)
         data=data.decode("utf-8").strip()
         str2=data.split("\r\n")
         metadata=str2[0] # metadata line
         metadata_array=metadata.split(",")
         message=str2[1] #message line
         phone_number=metadata_array[1]
         phone_number=phone_number.replace('"','')
         # Extract the date and convert format
         dt=metadata_array[3].replace('"','') #get the date string
         yr=dt[0:2]
         mo=dt[3:5]
         dy=dt[6:8]
         the_date="20"+yr+"-"+mo+"-"+dy 
         sm_date=mo+"/"+dy
         #extract the time
         the_time=metadata_array[4][0:8]
         #extract and convert the time zone
         timezone1=metadata_array[4][8:len(metadata_array[4])-1]
         timezone=int(int(timezone1)/4)
         # Determine if this is a normal or concatenated message
         isconcat=0
         seg=""
         if(len(metadata_array)>5):
            isconcat=1
            concatnum=metadata_array[5]
            concat_seq=metadata_array[6]
            total_in_concat=metadata_array[7]
            seg="("+concat_seq+" of "+total_in_concat+")"
         messages_listbox.insert(END,the_date+"~"+phone_number+"~"+seg+"~"+message+"~[Message #"+str(message_number)+"]")   
   messages_listbox.grid(row=1,column=0,pady=10,sticky="E,W")
   messages_listbox.bind('<<ListboxSelect>>',get_message_choice)
   messages_scrollbar = Scrollbar(messages,orient=VERTICAL,width=50)
   messages_scrollbar.grid(row=1, column=0, sticky="NSE",pady=10)
   messages_listbox.config(yscrollcommand=messages_scrollbar.set)
   messages_scrollbar.config(command=messages_listbox.yview)
   messages_view_button=Button(messages, text="View",font=conbuttonfont,command=lambda: view_message()).place(x=5,y=520)
   messages_del_button=Button(messages, text="Del",font=conbuttonfont,command=lambda: del_message()).place(x=110,y=520)
   messages_del_button=Button(messages, text="Delete All",font=conbuttonfont,command=lambda: del_all_messages()).place(x=200,y=520)
#-------------------------------------------------
def refresh_gps_location():
#-------------------------------------------------
   send3('AT+QGPSCFG="outport","usbnmea"',ser,.1)
   send3("AT+QGPS=1",ser,.1)
   send3("AT+QGPSLOC=2",ser,.1)
   time.sleep(.5)
   data=ser.read(1000)
   time.sleep(.1)
   data=data.decode("utf-8").strip()
   if (data.find('+CME ERROR: 516') != -1):
      #print("Not Fixed Yet")
      time.sleep(2)
      return
   gps=data.split(",")
   latitude=float(gps[1])
   if (latitude < 0):
      latitude_hemisphere="South"
   if (latitude > 0):
      latitude_hemisphere="North"
   longitude=float(gps[2])
   latitude_orig=latitude
   longitude_orig=longitude
   if(longitude < 0):
      longitude_hemisphere="West"
   if(longitude > 0):
      longitude_hemisphere="East"
   latitude=abs(latitude)
   longitude=abs(longitude)
   altitude=gps[4]
   course=gps[6]
   speed=gps[7]
   gpsinfo=str(latitude)+" "+latitude_hemisphere+" Latitude\r\n"
   gpsinfo=gpsinfo+str(longitude)+" "+longitude_hemisphere+" Longitude\r\n"
   gpsinfo=gpsinfo+"Altitude="+altitude+" Meters\r\n"
   gpsinfo=gpsinfo+"Direction traveling="+course+" degrees\r\n"
   #gpsinfo=textwrap.fill(text=gpsinfo, width=40)
   gps_label.configure(text=gpsinfo)

#==========Populate the GPS folder=====================
gpsfont=font.Font(family='Helvetica', size=22)
gps_label=Label(gps,text="Stanby while retreiving GPS Location...",fg="white",bg="darkblue",font=messageslabelfont,justify=CENTER,width=40)
gps_label.pack()

#-------------------------------------------------
def get_current_storage_device():
#-------------------------------------------------
   #get the current storage device and check the correct button
   global storage_device
   send3("AT+CPMS?",ser,.1)
   memdata=ser.read(1000)
   memdata=memdata.decode("utf-8").strip()
   storage_area=(memdata.partition('+CPMS: "')[2])
   storage_area=(storage_area.partition('"')[0])
   if(storage_area=="ME"):
      storage_device="ME"
   if(storage_area=="SM"):
      storage_device="SM"
   stordev.set(storage_device)
#-------------------------------------------------
def select_storage_device():
#-------------------------------------------------
   sd=stordev.get()
   send3('AT+CPMS="'+sd+'","'+sd+'","'+sd+'"',ser,.1)
   send3('AT+CPBS="'+sd+'"',ser,.1)  
#---------------------------
def sound_device_changed(dev):
#---------------------------
   #print("rec dev changed to "+recdev.get())
   #save to text file
   file=open("audio.txt","w")
   file.write(recdev.get()+"\n")
   file.write(playdev.get()+"\n")
   file.close()
   get_audio_device_numbers()
#---------------------------
def sound_settings():
#---------------------------
   global recording_device_name
   global playing_device_name
   device_name=""
   #list the recording sound settings in a drop down list box
   Label(settings,text="Recording ",font=dropdownfont).place(x=5,y=420)
   recording_device=ttk.Combobox(settings,textvariable=recdev,font=dropdownfont)
   recording_devices=os.popen("arecord -l | grep card").read()
   recording_devices=recording_devices.replace("\r\n","").strip()
   data=recording_devices.split("\n")
   #open the audio.txt file (if exists) to get the current sound settings
   try:
      file=open("audio.txt","r")
      recording_device_name=file.readline().strip()
      recording_device.set("test+"+device_name)
      playing_device_name=file.readline().strip()
      file.close()
   except:
      recording_device_name=""
      playing_device_name=""
      recording_device.set("Choose recording device...")
   #now list the recording devices that ALSA can find
   #if it sees the one saved in the text file then select it automatically
   for line in data:
      #counter=counter+1
      d1=line.split(":")
      device_number=d1[0].partition(' ')[2]
      device_string=d1[1]
      start = device_string.find("[") + len("[")
      end = device_string.find("]")
      dev = device_string[start:end]
      if (dev!="EC25-AF"):
         device_name=dev
         recording_device['values']= tuple(list(recording_device['values']) + [device_name])    
      recording_device.place(x=150,y=420)
      recording_device.set(recording_device_name)
      recording_device.bind('<<ComboboxSelected>>', sound_device_changed)
   #Do the same for the playing devices
   Label(settings,text="Playing ",font=dropdownfont).place(x=5,y=460)
   playing_device=ttk.Combobox(settings,textvariable=playdev,font=dropdownfont)
   playing_devices=os.popen("aplay -l | grep card").read()
   playing_devices=playing_devices.replace("\r\n","").strip()
   data=playing_devices.split("\n")
   for line in data:
      d1=line.split(":")
      device_number=d1[0].partition(' ')[2]
      device_string=d1[1]
      start = device_string.find("[") + len("[")
      end = device_string.find("]")
      dev = device_string[start:end]
      if (dev!="EC25-AF"):
         device_name=dev
         playing_device['values']= tuple(list(playing_device['values']) + [device_name])    
      playing_device.place(x=150,y=460)
      playing_device.set(playing_device_name)
      playing_device.bind('<<ComboboxSelected>>', sound_device_changed)
   get_audio_device_numbers()
#---------------------------
def display_settings():
#---------------------------
   #Get Phone number
   response=send3("AT+CNUM",ser,.1)
   line=response.split("+CNUM:")
   line2=line[1].split(",")
   phone_number=line2[1].replace('"','')
   info="Your Number: "+phone_number+"\n"

   #Get signal strength
   response=send3("AT+CSQ",ser,.1) 
   sigline=response.split("+CSQ:")
   sigline2=sigline[1].split(",")
   signal=int(sigline2[0])
   signal=round((signal*100)/31)
   info=info+"Signal Strength: "+str(signal)+" %"+"\n"

   #Get Network Name
   response=send3("AT+COPS?",ser,.1) 
   copsline=response.split("+COPS:")
   copsline2=copsline[1].split(",")
   network=copsline2[2].replace('"','')
   info=info+"Network Provider: "+network+"\n"

   #Get time and date through network   
   response=send3("AT+QLTS",ser,.1) 
   line=response.split("+QLTS:")
   line2=line[1].split(",")
   the_date=line2[0]
   the_date=(the_date.partition('"')[2])
   the_time=line2[1]
   the_time=(the_time.partition('-')[0])
   info=info+"Date/Time: "+the_date+" "+the_time+"\n"

   #Get the IMEI of the phone
   response=send3("AT+GSN",ser,.1) 
   imei=(response.partition('OK')[0])
   info=info+"IMEI: "+imei+"\n"

   #Get the IMSI of the SIM card (serial number)
   response=send3("AT+CIMI",ser,.1)
   imsi=(response.partition('OK')[0])
   info=info+"SIM ser#: "+imsi+"\n"

   #Get the Firmware installed on the modem
   response=send3("AT+GMR",ser,.1)
   info=info+"Firmware: "+response+"\n"
   mystats.configure(text=info)

   #Display the input and output sound devices to choose from
   get_current_storage_device()
   sound_settings()


#==========Populate the Settings folder=====================
stordev=StringVar()
recdev=StringVar()
playdev=StringVar()
recdev=StringVar()
yy=90
settingsfont = font.Font(family='Helvetica', size=18)
dropdownfont=font.Font(family='Helvetica', size=18)
Label(settings,text="Choose a Storage Device:",font=settingsfont,fg="yellow",bg="black").place(x=5,y=5)
Radiobutton(settings, text="Modem Chip",font=settingsfont,variable=stordev,value="ME",command=select_storage_device ).place(x=5,y=45)
Radiobutton(settings, text="SIM Card",font=settingsfont,variable=stordev,value="SM",command=select_storage_device).place(x=240,y=45)
Label(settings,text="Network & Phone Settings",font=settingsfont,fg="yellow",bg="black").place(x=5,y=100)
mystats=Label(settings,text="My stats",font=settingsfont,justify=LEFT,width=35)
mystats.place(x=0,y=135)
Label(settings,text="Sound Settings",font=settingsfont,fg="yellow",bg="black").place(x=5,y=370)

#---------------- start the program --------------------
callmode="none"
caller_name=""
caller_number=""
send3("ATE0",ser,.1) #set no echo IMPORTANT!
send3("AT+CRC=1",ser,.1)  #set extended call format
send3("AT+CLIP=1",ser,.1) #enable caller ID
#Wait the call is answered to give an unsolicited response +COLP: "3174260810",129,,, instead of OK
send3("AT+COLP=1",ser,.1) 
display_settings()
check_for_events() 
root.mainloop()
