#!/usr/bin/python2
# -*- coding: UTF-8 -*-

# Description: Example of use of libIris
# Copyright (C) 2007 by Rafael Treviño Menéndez
# Author: Rafael Treviño Menéndez <skasi.7@gmail.com>
#         Juan Gonzalez <juan@iearobotics.com>
#	  Xavier de Blas <xaviblas@gmail.com> (2010 adapted to Chronopic)

# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU Library General Public
# License as published by the Free Software Foundation; either
# version 2 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
# Library General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.


import wx
import sys
import os
import platform
import tempfile

sys.stdout = open(os.path.join(tempfile.gettempdir(), 'chronopic-firmwarecord-stdout.log'),"w")
sys.stderr = open(os.path.join(tempfile.gettempdir(), 'chronopic-firmwarecord-stderr.log'),"w")

if platform.system() == 'Windows':
    LIBDIR = os.path.abspath(os.path.join('..', 'lib'))
    DATADIR = os.path.abspath(os.path.join('../..', 'share'))
    sys.path = ['..'] + sys.path
else:
    LIBDIR = '/usr/lib64'
    DATADIR = '/usr/share'
    root = os.path.join(LIBDIR, 'chronojump', 'python')
    sys.path.insert(0, root)


#---------------------------
#-- Modulos de LibIris
#---------------------------

import libIris.Pic16_Bootloader
import libIris.IntelHex
import libIris.Pic16_Firmware

#-- Timeout para la deteccion del bootloader (en segundos)
#-- Si el programa previamente grabado utiliza el puerto serie
#-- (por ejemplo el servidor de eco esta cargado) este tiempo ya
#-- no es en segundos. 

#-- con este timeout esta unos 25 segundos esperando cuando el servidor
#-- de eco esta cargado (400 si no se usa el puerto serie)
TIMEOUT = 800

#----------------------------------------------
#- Clase para realizar el Drag and Drop
#----------------------------------------------
class myDragDrog(wx.FileDropTarget):

  #-- En el constructor se le pasa el frame principal
  #-- Se usa para invocar el metodo download
  def __init__(self,obj):
    wx.FileDropTarget.__init__(self)
    self.frame = obj

  #-- Se invoca cada vez que se recibe la lista de ficheros arrastrados
  #-- Solo se descarga el primer fichero de la lista recibida
  def OnDropFiles(self,x,y, filenames):
  
    #-- Obtener el nombre del fichero (el primero de la lista)
    #file = filenames[0]
   
    #-- Meter el fichero en el entry "fichero .hex"
    #self.frame.text_ctrl_2.SetValue(file)
    
    #-- Activar la grabacion....
    #self.frame.update()
    #self.frame.download()
    
    return True

#-------------------------------------------------------------------
#--                  CLASE PRINCIPAL
#-------------------------------------------------------------------
class MyFrame(wx.Frame):
    def __init__(self, app, *args, **kwds):
    
    
        #----------------------------------------------------------------
        #--- Esta parte del codigo se ha generado automaticamente con la
        #-- herramienta wxglade. NO modificar.
        #---------------------------------------------------------------
        # begin wxGlade: MyFrame.__init__
        kwds["style"] = wx.DEFAULT_FRAME_STYLE
        wx.Frame.__init__(self, *args, **kwds)
        self.panel_1 = wx.Panel(self, -1)
        self.sizer_4_copy_staticbox = wx.StaticBox(self.panel_1, -1, "Port / Puerto")
        self.sizer_2_staticbox = wx.StaticBox(self.panel_1, -1, "Process / Proceso")
        #self.sizer_firmware_staticbox = wx.StaticBox(self.panel_1, -1, "Select / Seleccionar Firmware")
        self.frame_1_statusbar = self.CreateStatusBar(1, 0)
        #self.text_ctrl_2 = wx.TextCtrl(self.panel_1, -1, "")
        #self.button_firmware_auto = wx.Button(self.panel_1, -1, "Multitest", style=wx.BU_EXACTFIT)
        #self.button_firmware_jumps = wx.Button(self.panel_1, -1, "Jumps / Saltos", style=wx.BU_EXACTFIT)
        #self.button_firmware_runs = wx.Button(self.panel_1, -1, "Runs / Carreras", style=wx.BU_EXACTFIT)
        #self.button_firmware_led = wx.Button(self.panel_1, -1, "Led (test)", style=wx.BU_EXACTFIT)
        #self.button_2 = wx.Button(self.panel_1, -1, "Search / Buscar", style=wx.BU_EXACTFIT)
        self.button_7 = wx.Button(self.panel_1, -1, "Record / Grabar", style=wx.BU_EXACTFIT)
        self.combo_box_1 = wx.ComboBox(self.panel_1, -1, choices=[], style=wx.CB_DROPDOWN)
        self.gauge_1 = wx.Gauge(self.panel_1, -1, 100)
        self.button_6 = wx.Button(self.panel_1, -1, "Cancel / Cancelar")
        self.button_8 = wx.Button(self.panel_1, -1, "Help / Ayuda")

        self.__set_properties()
        self.__do_layout()

        #self.Bind(wx.EVT_BUTTON, self.boton_abrir, self.button_2)
        self.Bind(wx.EVT_BUTTON, self.boton_grabar, self.button_7)
        self.Bind(wx.EVT_BUTTON, self.boton_cancelar, self.button_6)
        self.Bind(wx.EVT_BUTTON, self.boton_ayuda, self.button_8)
        
        #self.Bind(wx.EVT_BUTTON, self.button_open_auto, self.button_firmware_auto)
        #self.Bind(wx.EVT_BUTTON, self.button_open_jumps, self.button_firmware_jumps)
        #self.Bind(wx.EVT_BUTTON, self.button_open_runs, self.button_firmware_runs)
        #self.Bind(wx.EVT_BUTTON, self.button_open_led, self.button_firmware_led)
        # end wxGlade
        #--------------------------------------------
        # Fin del codigo generado automaticamente
        #--------------------------------------------
        
        
        #-- Guardar la aplicacion
        self.app=app;
        
        #-- Para configurar para el drag-and-drop
        #test = myDragDrog(self)
        #self.SetDropTarget(test)
        #self.text_ctrl_2.SetDropTarget(myDragDrog(self))
        #self.combo_box_1.SetDropTarget(myDragDrog(self))
        
        #-- Establecer la habilitacion de los widgets
        #-- Todos menos el boton de cancelar estan activos inicialmente
        self.button_6.Disable()
        
    #----------------------------------------------------------------
    #--- Esta parte del codigo se ha generado automaticamente con la
    #-- herramienta wxglade. NO modificar.
    #---------------------------------------------------------------

    def __set_properties(self):
        # begin wxGlade: MyFrame.__set_properties
        self.SetTitle("Chronopic Firmware Updater")
        self.frame_1_statusbar.SetStatusWidths([-1])
        # statusbar fields
        #frame_1_statusbar_fields = ["Change / Cambiar Chronopic firmware"]
        #frame_1_statusbar_fields = ["Firmwares in Chronojump\\share\\Chronojump\\firmware"]
        frame_1_statusbar_fields = [""]
        for i in range(len(frame_1_statusbar_fields)):
            self.frame_1_statusbar.SetStatusText(frame_1_statusbar_fields[i], i)
        #self.text_ctrl_2.SetMinSize((450, 27))
        self.combo_box_1.SetMinSize((250,30))
        self.frame_1_statusbar.SetStatusText("Record Multitest Firmware / Grabar Firmware Multitest", 0)
        # end wxGlade

    def __do_layout(self):
        # begin wxGlade: MyFrame.__do_layout
        sizer_1 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_3 = wx.BoxSizer(wx.VERTICAL)
        sizer_2 = wx.StaticBoxSizer(self.sizer_2_staticbox, wx.VERTICAL)
        sizer_3.Add(self.button_8, 0, wx.ALIGN_RIGHT|wx.ALL, 5)
        sizer_4_copy = wx.StaticBoxSizer(self.sizer_4_copy_staticbox, wx.HORIZONTAL)
        
        #sizer_firmware = wx.StaticBoxSizer(self.sizer_firmware_staticbox, wx.VERTICAL)
        #sizer_firmware_row_1 = wx.BoxSizer(wx.HORIZONTAL)
        #sizer_firmware_row_1_1 = wx.BoxSizer(wx.HORIZONTAL)
        #sizer_firmware_row_1_2 = wx.BoxSizer(wx.HORIZONTAL)
        #sizer_firmware_row_2 = wx.BoxSizer(wx.HORIZONTAL)
        
        #sizer_firmware_row_1_1.Add(self.button_firmware_auto, 0, wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5)
        #sizer_firmware_row_1_1.Add(self.button_firmware_jumps, 0, wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5)
        #sizer_firmware_row_1_1.Add(self.button_firmware_runs, 0, wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE|wx.LEFT, 5)
        #sizer_firmware_row_1.Add(sizer_firmware_row_1_1, 1, wx.ALIGN_LEFT|wx.LEFT|wx.TOP, 5) #proportion 1 to fill space
        
        #sizer_firmware_row_1_2.Add(self.button_firmware_led, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT, 5)
        #sizer_firmware_row_1.Add(sizer_firmware_row_1_2, 0, wx.ALIGN_RIGHT|wx.RIGHT|wx.TOP, 5) #proportion 0 to be at right
        
        #sizer_firmware_row_2.Add(self.text_ctrl_2, 0, wx.TOP|wx.BOTTOM|wx.EXPAND|wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL, 5)
        #sizer_firmware_row_2.Add(self.button_2, 0, wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0)
        #sizer_firmware.Add(sizer_firmware_row_1, 0, wx.EXPAND, 5)
        #sizer_firmware.Add(sizer_firmware_row_2, 0, wx.ALL|wx.EXPAND, 5)
        #sizer_3.Add(sizer_firmware, 0, wx.LEFT|wx.RIGHT|wx.TOP|wx.EXPAND|wx.ALIGN_CENTER_HORIZONTAL, 5)
        
        sizer_4_copy.Add(self.combo_box_1, 0, wx.TOP|wx.BOTTOM|wx.EXPAND|wx.ALIGN_CENTER_VERTICAL, 5)
        sizer_4_copy.Add(self.button_7, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 5)
        sizer_3.Add(sizer_4_copy, 0, wx.LEFT|wx.RIGHT|wx.TOP|wx.EXPAND|wx.ALIGN_CENTER_HORIZONTAL, 5)
        sizer_2.Add(self.gauge_1, 0, wx.LEFT|wx.RIGHT|wx.TOP|wx.EXPAND|wx.ADJUST_MINSIZE, 4)
        sizer_2.Add((20, 10), 0, wx.ADJUST_MINSIZE, 0)
        sizer_2.Add(self.button_6, 0, wx.EXPAND|wx.ADJUST_MINSIZE, 0)
        sizer_3.Add(sizer_2, 1, wx.ALL|wx.EXPAND, 5)
        self.panel_1.SetAutoLayout(True)
        self.panel_1.SetSizer(sizer_3)
        sizer_3.Fit(self.panel_1)
        sizer_3.SetSizeHints(self.panel_1)
        sizer_1.Add(self.panel_1, 1, wx.EXPAND, 0)
        self.SetAutoLayout(True)
        self.SetSizer(sizer_1)
        sizer_1.Fit(self)
        sizer_1.SetSizeHints(self)
        self.Layout()
        # end wxGlade
        #--------------------------------------------
        # Fin del codigo generado automaticamente
        #--------------------------------------------
        

    #------------------------------------------------------------------
    #-- Funcion de retrollamada del boton de exploracion de ficheros  
    #------------------------------------------------------------------
    def boton_abrir(self, event): # wxGlade: MyFrame.<event_handler>
        print "boton_abrir"
        print DATADIR 
        #-- Abrir un dialogo de busqueda de ficheros
        filechooser = wx.FileDialog(self, "Load Firmware Hex",
                                    os.path.join(DATADIR, 'chronojump', 'firmware'), wildcard = "*.hex;*.HEX")

        print "A" 
        #-- Esperar a que el usuario seleccione el fichero
        opcion = filechooser.ShowModal()
        
        print "B" 
        #-- Segun la opcion...
        if opcion == wx.ID_OK:
        
          #-- Se ha pulsado ok. Obtener el nombre del fichero
          fichero = filechooser.GetPath()
         
          #-- Meter el fichero en el entry "fichero .hex"
          #self.text_ctrl_2.SetValue(fichero)
          
        else: #-- No se ha seleccionado ninguno
          print "Cancel..."
          
        print "C" 
        
    #def button_open_auto(self, event): # wxGlade: MyFrame.<event_handler>
    #    print "button_open_auto"
    #    print DATADIR 
    #    self.text_ctrl_2.SetValue(os.path.join(DATADIR, 'chronojump', 'firmware', 'chronopic-firmware-multitest.hex'))
        
    #def button_open_jumps(self, event): # wxGlade: MyFrame.<event_handler>
    #    print "button_open_jumps"
    #    print DATADIR 
    #    self.text_ctrl_2.SetValue(os.path.join(DATADIR, 'chronojump', 'firmware', 'chronopic_firmware_50ms.hex'))
        
    #def button_open_runs(self, event): # wxGlade: MyFrame.<event_handler>
    #    print "button_open_runs"
    #    print DATADIR 
    #    self.text_ctrl_2.SetValue(os.path.join(DATADIR, 'chronojump', 'firmware', 'chronopic_firmware_10ms.hex'))
        
    #def button_open_led(self, event): # wxGlade: MyFrame.<event_handler>
    #    print "button_open_led"
    #    print DATADIR 
    #    self.text_ctrl_2.SetValue(os.path.join(DATADIR, 'chronojump', 'firmware', 'ledp.hex'))
        
        
    #-----------------------------------------------------------------
    #-- Funciones de retrollamada de los diferentes botones 
    #-----------------------------------------------------------------
    def boton_grabar(self, event): # wxGlade: MyFrame.<event_handler>
        self.download()
        
        
    def boton_cancelar(self, event): # wxGlade: MyFrame.<event_handler>
        self.cancelar = True  
       
    def boton_ayuda(self, event): # wxGlade: MyFrame.<event_handler>
        #dlg = wx.MessageDialog(self, "ENGLISH\n\nWith this tool you can change Chronopic Firmware whenever you want. It's recommended 50ms for jumps and 10ms for runs.\nTesting: 'ledp.hex' can be recorded and then green led will blink.\nFirmwares are in Chronojump installation folder, \\share\\Chronojump\\firmware\nYou can open Chronojump software to see what is the port, but don't press 'Connect' button there, because port cannot be opened by two applications.\nIf you need more help please check forum:\nhttp://forum.chronojump.org\n\n\nESPAÑOL\n\nCon esta herramienta puede cambiar el Firmware de Chronopic tantas veces como quiera. Se recomienda 50ms para saltos, 10 ms para carreras.\nSi desea testear la herramienta, puede grabar el archivo 'ledp.hex' y verá como la luz verde parpadea.\nLos firmwares estan en la carpeta de instalacion de Chronojump, \\share\\Chronojump\\firmware\nPuede abrir Chronojump para ver qué en qué puerto aparece Chronopic, pero no pulse el botón 'Conectar' en Chronojump porque un puerto no puede ser abierto por dos aplicaciones.\nSi necesita más ayuda, por favor use el foro:\nhttp://foro.chronojump.org\n\nChronopic-Firmwarecord is based on PyDownloader.", "PyDownloader Help", wx.OK)
        dlg = wx.MessageDialog(self, "ENGLISH\n\nWith this tool you can change your old Chronopic firmware to the new Multitest firmware. This new firmware allows to change the configuration automatically if user is performing jumps or runs.\nThis firmware does not work for encoder.\nYou can open Chronojump software to see what is the port, but don't press 'Connect' button there, because port cannot be opened by two applications.\nIf you need more help please check forum:\nhttp://forum.chronojump.org\n\n\nESPAÑOL\n\nEsta herramienta sirve para cambiar el antiguo firmware del Chronopic por el nuevo firmware Multitest. Este nuevo firmware se configura automáticamente para saltos o carreras según sea necesario.\nEste firmware no sirve para el encoder.\nPuede abrir Chronojump para ver en qué puerto aparece Chronopic, pero no pulse el botón 'Conectar' en Chronojump porque un puerto no puede ser abierto por dos aplicaciones.\nSi necesita más ayuda, por favor use el foro:\nhttp://foro.chronojump.org\n\nChronopic-Firmwarecord is based on PyDownloader.", "PyDownloader Help", wx.OK)
	dlg.ShowModal()

    def boton_eco(self, event): # wxGlade: MyFrame.<event_handler>
        self.download_program(libIris.Pic16_Firmware.echo)
       
        
    
    #-------------------------------------
    #-- Actualizar el interfaz
    #-------------------------------------    
    def update(self):
      while (self.app.Pending()):
          self.app.Dispatch();  
    
    #------------------------------------------------------------
    #-- Activar todos los botones relacionados con la descarga
    #-- El boton de cancel se desactiva
    #------------------------------------------------------------    
    def botones_modo_descarga(self):
      #-- Cancelar: Deshabilitado
      self.button_6.Disable()
      #-- Resto: Habilitados
      self.button_7.Enable()
          
    #-----------------------------------------------------------------------
    #-- Desactivar todos los botones de descarga. El de cancelar se activa  
    #-----------------------------------------------------------------------
    def botones_modo_cancelar(self):
      #-- Cancelar Activado, resto desactivados
      self.button_6.Enable()
      self.button_7.Disable()

    #---------------------------------------------------------
    #-- Metodo para descargar un fichero .hex en la skypic
    #-- Se lee el nombre del fichero de la interfaz grafica
    #---------------------------------------------------------
    def download(self):
      
      #----------------------------------------
      #-- Abrir y parsear el fichero .hex
      #----------------------------------------
      #-- Obtener el nombre
      #file = str(self.text_ctrl_2.GetLineText(0))
      file = os.path.join(DATADIR, 'chronojump', 'firmware', 'chronopic-firmware-multitest-1.2.hex')

      #-- Si no hay ningun fichero especificado: Error
      if file=="":
        self.frame_1_statusbar.SetStatusText("Fichero .hex no especificado", 0)
        return
      
      #-- Realizar el parseo
      try:
        hr = libIris.IntelHex.HexReader (file)
      except libIris.IntelHex.ReaderError,msg:
        #-- Convertir el mensaje a una cadena
        msg = "%s" % msg
        self.frame_1_statusbar.SetStatusText(msg, 0)
        return      
      
      #----------------------------------
      #-- Realizar la descarga!!
      #----------------------------------
      
      #-- Obtener el programa en el formato correcto
      program = hr.dataBlocks16()
      
      self.download_program(program)

    #------------------------------------------------------------------------
    #-- Funcion de retrollamada de libIris. Segun el estado de la descarga
    #-- Se hace una cosa u otra
    #------------------------------------------------------------------------
    def state(self,op,inc,total):
      #-----------------------------
      #-- Comienzo de descarga
      #-----------------------------
      if op==libIris.Pic16_Bootloader.WRITING_START:
  
        #-- Barra de progreso a cero
        self.gauge_1.SetValue(0)
       
        #-- Actualizar barra de status
        self.frame_1_statusbar.SetStatusText("Recording / Grabando", 0)
        self.update()
        
        return True
        
      
      #------------------------------
      #-- Incremento en la descarga  
      #------------------------------    
      elif op==libIris.Pic16_Bootloader.WRITING_INC:
        self.gauge_1.SetValue(100*inc/total)
        self.update()
        
        #-- Comprobar si se ha apretado boton de Cancelar
        if self.cancelar:
          return False
          
        return True  
      
      #-------------------------------
      #-- Fin de la descarga
      #-------------------------------
      elif op==libIris.Pic16_Bootloader.WRITING_END: 
        self.gauge_1.SetValue(100)
        self.frame_1_statusbar.SetStatusText("Complete / Completado", 0)
        self.update()
        return True
     
      #---------------------------------------------------
      #-- Comienzo de la identificacion del bootloader    
      #---------------------------------------------------    
      elif op==libIris.Pic16_Bootloader.IDENT_START:
        #-- Hay que esperar a que detecte el Bootloader
        self.frame_1_statusbar.SetStatusText("Press Reset on Chronopic / Pulse Reset en el Chronopic", 0)
        self.update()
        return True
        
        
      #-----------------------------------------------------------------
      #-- Respuesta no recibida del bootloader tras un mini-timeout    
      #-----------------------------------------------------------------
      elif op==libIris.Pic16_Bootloader.IDENT_NACK:
      
        #-- Mientras que el tiempo total acumulado sea menor que el 
        #-- TIMEOUT indicado, continuar esperando
        self.update()
        
        #-- Si apretado boton de cancelar abortar...
        if self.cancelar:
          return False
        
        if total<=TIMEOUT:
         return True
        else :
          return False    


    #----------------------------------------
    #- Descargar un programa 
    #----------------------------------------
    def download_program(self,prog):
    
      #-- Poner la barra de progreso a 0
      self.gauge_1.SetValue(0)
      self.update()
    
      #-- Desactivar flag de cancelacion
      self.cancelar=False
      
      #-- Si ya se habia abierto un puerto serie, cerrarlo
      #-- Esto ha sido necesario ponerlo para que funcione
      #-- bien en WINDOWS
      if self.app.iris!=None:
        self.app.iris.close()
      
      #------------------------------------
      #-- Abrir puerto serie
      #------------------------------------
      #-- Primero obtener el nombre del dispositivo serie
      serialName=self.combo_box_1.GetValue()
      
      try:
        self.app.iris = libIris.Pic16_Bootloader.Iris(serialName,
                                                      logCallback=None)
      except libIris.Pic16_Bootloader.IrisError,msg:
      
        #-- Si hay error indicarlo en la barra de estado y abortar
        msg = "%s" % msg
        self.frame_1_statusbar.SetStatusText(msg, 0)
        return
      
      #-- Actualizar la sensibilidad de los botones
      self.botones_modo_cancelar()
      self.update()
      
      try:
        self.app.iris.download(prog,stateCallback=self.state)
      except libIris.Pic16_Bootloader.IrisError,msg:
        msg= "%s" % msg
        self.frame_1_statusbar.SetStatusText(msg, 0)
        
        #-- Poner botones en su estado inicial:
        self.botones_modo_descarga()
        return
        
      #-- Poner botones en su estado inicial:
      self.botones_modo_descarga()

# end of class MyFrame


#---------------------------------------------------------
#-- Funcion para obtener  la lista de puerto serie
#-- Esto depende de la plataforma en la que se ejecute
#---------------------------------------------------------
#def getSerialPorts():
#
#  #-- Windows
#  if os.name == 'nt':
#    
#    #-- Se usan los nueve primeros puertos serie
#    return ["COM1","COM2","COM3","COM4","COM5","COM6","COM7","COM8","COM9"]
#    
#  #-- Linux  
#  elif os.name == 'posix':
#    return ["/dev/ttyUSB0","/dev/ttyUSB1"]
#
#  else:
#    return []

#Adapted from: http://stackoverflow.com/a/11398450
def getSerialPorts():
    import glob

    system_name = platform.system()
    if system_name == "Windows":
        print "get serial ports"
        import serial
        # Scan for available ports.
        available = []
        for i in range(12):
            print i
            try:
                print " ok? "
                s = serial.Serial(i)
                available.append("COM" + str(i+1))
                s.close()
                print " yes "
            except serial.SerialException:
                pass
        return available
    elif system_name == "Darwin":
        # Mac
        return glob.glob('/dev/tty.usbserial*')
    else:
        # Assume Linux or something else
        return glob.glob('/dev/ttyUSB*')


class MyApp(wx.App):
      
    def OnInit(self):
        self.iris=None
        frame = MyFrame(self,None, -1, "")
        frame.Show(True)
        self.SetTopWindow(frame)
        
        #-- Anadir los nombres de los puertos serie al combobox
        serialports = getSerialPorts()
        for disp in serialports:
          frame.combo_box_1.Append(disp) 
            
        return True


def main():
    app = MyApp(0)
    app.MainLoop()


if __name__ == "__main__":
    main()
