[chronojump] Added pydownloader (adapted to Chronopic) to record firmware easy



commit 5b1ead44e7d7e8f192371b9d71db2a17cbcbc664
Author: Xavier de Blas <xaviblas master gnome org>
Date:   Wed Jun 2 19:42:53 2010 +0800

    Added pydownloader (adapted to Chronopic) to record firmware easy

 .../chronopic_firmware_10ms_unvalidated.hex        |   28 +
 .../chronopic_firmware_50ms.hex                    |   28 +
 chronopic-firmware/pydownloader-chronopic/ledp.hex |    8 +
 .../pydownloader-chronopic/libIris/IntelHex.py     |  536 ++++++++++++++++++++
 .../pydownloader-chronopic/libIris/IntelHex.pyc    |  Bin 0 -> 11367 bytes
 .../libIris/Pic16_Bootloader.py                    |  446 ++++++++++++++++
 .../libIris/Pic16_Bootloader.pyc                   |  Bin 0 -> 8504 bytes
 .../libIris/Pic16_Bootloader.py~                   |  446 ++++++++++++++++
 .../libIris/Pic16_Firmware.py                      |   70 +++
 .../libIris/Pic16_Firmware.pyc                     |  Bin 0 -> 5167 bytes
 .../pydownloader-chronopic/libIris/__init__.py     |   51 ++
 .../pydownloader-chronopic/libIris/__init__.pyc    |  Bin 0 -> 1132 bytes
 .../pydownloader-chronopic/libIris/__init__.py~    |   51 ++
 .../pydownloader-chronopic/pydownloader-wx.py      |  443 ++++++++++++++++
 14 files changed, 2107 insertions(+), 0 deletions(-)
---
diff --git a/chronopic-firmware/pydownloader-chronopic/chronopic_firmware_10ms_unvalidated.hex b/chronopic-firmware/pydownloader-chronopic/chronopic_firmware_10ms_unvalidated.hex
new file mode 100644
index 0000000..f830719
--- /dev/null
+++ b/chronopic-firmware/pydownloader-chronopic/chronopic_firmware_10ms_unvalidated.hex
@@ -0,0 +1,28 @@
+:02000000662870
+:08000800A000030EA1000B197A
+:100010001A280B181F280C1813280428210E8300F7
+:10002000A00E200E09000C10FF30220203190E282A
+:10003000A20A0E280B11D9308100A3030E28AA08AA
+:1000400003192628A2018F018E01AA012208A4000B
+:100050000F08A5000E08A600A2018F018E01013035
+:10006000A3000130A900D930810006080B108B11C4
+:100070000E2883161930990024309800831290308E
+:10008000980008008C1E42281A0808000C1E4628FA
+:1000900099000800FF30AB00FF30AC006400AC0BEF
+:1000A0004F28AB0B4C280800061A00340134270DEA
+:1000B000023A8600080006080B108B1508008B1109
+:1000C00045304620270846208B150800831611303E
+:1000D00086000730810039200B118312D93081004E
+:1000E000831231309000A2018F018E0183160C140F
+:1000F00083124A205B20A2010130A3000030A90036
+:100100000130AA005420A70057208B160B178B171D
+:1001100064008C1E91284220AD0045302D02031949
+:100120005F200030290203199E280130290203199B
+:100130009F28023029020319BD2888288828A3088F
+:10014000031D882806080B105420A8002808270241
+:100150000319AF282808A7000230A900882826081C
+:100160008E0703188F0A25088F070318A20A240890
+:10017000A2070030A9005B208828583046202708B5
+:100180004620240846202508462026084620003020
+:08019000A90057205B2088281C
+:00000001FF
diff --git a/chronopic-firmware/pydownloader-chronopic/chronopic_firmware_50ms.hex b/chronopic-firmware/pydownloader-chronopic/chronopic_firmware_50ms.hex
new file mode 100644
index 0000000..4fce9bb
--- /dev/null
+++ b/chronopic-firmware/pydownloader-chronopic/chronopic_firmware_50ms.hex
@@ -0,0 +1,28 @@
+:02000000662870
+:08000800A000030EA1000B197A
+:100010001A280B181F280C1813280428210E8300F7
+:10002000A00E200E09000C10FF30220203190E282A
+:10003000A20A0E280B11D9308100A3030E28AA08AA
+:1000400003192628A2018F018E01AA012208A4000B
+:100050000F08A5000E08A600A2018F018E01053031
+:10006000A3000130A900D930810006080B108B11C4
+:100070000E2883161930990024309800831290308E
+:10008000980008008C1E42281A0808000C1E4628FA
+:1000900099000800FF30AB00FF30AC006400AC0BEF
+:1000A0004F28AB0B4C280800061A00340134270DEA
+:1000B000023A8600080006080B108B1508008B1109
+:1000C00045304620270846208B150800831611303E
+:1000D00086000730810039200B118312D93081004E
+:1000E000831231309000A2018F018E0183160C140F
+:1000F00083124A205B20A2010530A3000030A90032
+:100100000130AA005420A70057208B160B178B171D
+:1001100064008C1E91284220AD0045302D02031949
+:100120005F200030290203199E280130290203199B
+:100130009F28023029020319BD2888288828A3088F
+:10014000031D882806080B105420A8002808270241
+:100150000319AF282808A7000230A900882826081C
+:100160008E0703188F0A25088F070318A20A240890
+:10017000A2070030A9005B208828583046202708B5
+:100180004620240846202508462026084620003020
+:08019000A90057205B2088281C
+:00000001FF
diff --git a/chronopic-firmware/pydownloader-chronopic/ledp.hex b/chronopic-firmware/pydownloader-chronopic/ledp.hex
new file mode 100644
index 0000000..98f09d1
--- /dev/null
+++ b/chronopic-firmware/pydownloader-chronopic/ledp.hex
@@ -0,0 +1,8 @@
+:0400000000000428D0
+:080008008A110A120728FD30DD
+:10001000831603138600023083128606FF30FF002A
+:10002000FF3014200B28080083120313A3007F085D
+:10003000A2002208230403192228FF30A207031C70
+:06004000A30319280800CB
+:02400E00FF3F72
+:00000001FF
diff --git a/chronopic-firmware/pydownloader-chronopic/libIris/IntelHex.py b/chronopic-firmware/pydownloader-chronopic/libIris/IntelHex.py
new file mode 100644
index 0000000..6a8111f
--- /dev/null
+++ b/chronopic-firmware/pydownloader-chronopic/libIris/IntelHex.py
@@ -0,0 +1,536 @@
+#!/usr/bin/env python
+# -*- coding: iso-8859-15 -*-
+
+# Description: File downloader library for SkyPIC
+# Copyright (C) 2007 by Rafael Treviño Menéndez
+# Author: Rafael Treviño Menéndez <skasi 7 gmail com>
+#         Juan Gonzalez Gomez <juan iearobotics com>
+
+# 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.
+
+
+
+
+#------------------------------------------------------------------------------
+"""
+ Libreria para el analisis de ficheros .hex que esten en formato Hex de 
+ Intel. Se incluyen ademas funciones para realizar conversiones entre
+ diferentes formas de representacion de los programas en codigo maquina
+ 
+ FORMATOS DE DATOS. En esta libreria se usan tres tipos de formatos 
+  para representar la informacion que hay en un fichero .HEX
+
+ -FORMATO 1: Memoria (mem). Se asocia cada direccion con su palabra.
+    Es una lista de tuplas (direccion,palabra). La palabra se representa
+    a su vez mediante una otra tupla con su byte alto y su byte bajo
+    El formato lo podemos expresar asi: 
+    mem = [tupla1, tupla2....] = [(dir1, pal1), (dir2,pal2), ...] =
+        = [ (dir1, (dato1h,dato1l)), (dir2,(dato2h,dato2l)), ... ]
+    Este es el formato mas generico
+
+ -FORMATO 2: Lista de bloques. Los contenidos que estan en posiciones de
+    memoria consecutivas se agrupan en bloques. La representacion es una
+    lista de bloques:
+    programa = [bloque1, bloque2.....] Cada uno de estos bloques es a su 
+    vez una lista de PALABRAS (no bytes). La primera palabra es la direccion
+   de comienzo del bloque
+    bloque1 = [direccion, palabra1, palabra2,.....]
+
+ -FORMATO 3: Lista de bloques de 16 palabras. Es el mismo que el formato 2
+    pero ahora los bloques son como maximo de 16 palabras
+
+ USO DE LOS FORMATOS
+
+ -FORMATO 1: Es el mas generico. Contiene tuplas con las direcciones y 
+             las palabras almacenadas. 
+ -FORMATO 2: Bloques contiguos de palabras. Su principal utilidad es para
+             almacenar programas que se grabaran en el PIC. Los bloques
+             pueden ser de cualquier tamano
+ -FORMATO 3: Bloques contiguos de como maximo 16 palabras. Es igual que el 
+             formato 2 pero con la limitacion de tamano de bloques. Su 
+             principal utilidad es para la carga de programas con el 
+             Bootloader. Por cada bloque de 16 palabras se envia un 
+             checksum para comprobar que el envio es correcto
+ 
+"""
+#------------------------------------------------------------------------------
+
+
+class ReaderError (Exception):
+#----------------------------------------------------------------------------
+  """
+  Excepciones producidas en el modulo IntelHex
+  """
+#----------------------------------------------------------------------------  
+  pass
+
+
+
+
+class HexReader:
+#----------------------------------------------------------------------------
+  """
+  Clase principal para la lectura de ficheros .HEX y realizar conversiones
+  """
+#----------------------------------------------------------------------------
+
+  
+  def __init__ (self, file):
+  #----------------------------------------------------------------------------
+    """
+    Inicializacion de la clase. Se le pasa el fichero que se quiere parsear
+    Bien se puede pasar el descriptor o el nombre del fichero
+    """
+  #----------------------------------------------------------------------------
+  
+    #-- Comprobar si lo que se pasa es una cadena con el nombre del 
+    #-- fichero. En ese caso se abre el fichero para obtener su descriptor
+    if isinstance (file, str): 
+    
+      #-- Abrir el fichero o devolver una excepcion si hay error
+      try:
+        fd = open (file)
+      except IOError,msg:
+        raise ReaderError, msg
+        
+      #-- Indicar que se especifico el fichero por su nombre  
+      fileName=True;  
+        
+    else:
+      fd = file; #-- El argumento se toma directamente como un descriptor
+      fileName=False;
+      
+    #-- Realizar el parseo y obtener el contenido en formato 2
+    self.__memory = readHex(fd)
+    
+    #-- En el caso de que se haya especificado el fichero mediante un
+    #-- nombre se cierra el fichero. En caso contrario se deja abierto
+    if fileName:
+      fd.close()
+    
+  
+  def memory (self):
+  #-------------------------------------------------------------
+    """
+    Devolver el fichero .HEX en formato 1, como una memoria  
+    """
+  #-------------------------------------------------------------
+    return self.__memory
+
+
+  def dataBlocks(self):
+  #----------------------------------------------------------------------  
+    """
+    Devolver el fichero .HEX como una lista de bloques en formato 2
+    """
+  #----------------------------------------------------------------------
+    return memToBlocks(self.__memory)  
+
+  
+  
+  def dataBlocks16(self): 
+  #----------------------------------------------------------------------
+    """
+    Devolver el fichero .Hex como una lista de bloques en formato 3
+    """
+  #----------------------------------------------------------------------
+    return memToBlocks16(self.__memory) 
+
+  
+  
+  def size(self):
+  #-------------------------------------------------------------------------
+    """
+    Devolver el tamano en palabras. No se distingue entre codigo y datos
+    """
+  #-------------------------------------------------------------------------
+    return len(self.__memory)
+
+  
+  def blocks(self):
+  #------------------------------------------------------------------
+    """
+    Devolver el numero de bloques 
+    """
+  #------------------------------------------------------------------
+    blocks = memToBlocks(self.__memory)
+    return len(blocks)
+    
+  
+  def blocks16(self):
+  #------------------------------------------------------------------
+    """
+    Devolver el numero de bloques con tamano maximo de 16 palabras
+    """
+  #------------------------------------------------------------------
+    blocks = memToBlocks16(self.__memory)
+    return len(blocks)  
+
+  
+  
+  def outputPython(self,name="prog"):
+  #-------------------------------------------------------------------
+    """
+    Devuelve una cadena de Salida en formato python con el codigo
+    maquina del fichero .hex
+    """
+  #-------------------------------------------------------------------
+    
+    #-- Convertir a bloques y luego a cadena python
+    blocks = memToBlocks(self.__memory)
+    return blocksToStrPython(blocks,name)
+    
+  
+  def outputPython16(self,name="prog"):
+  #-------------------------------------------------------------------
+    """
+    Devuelve una cadena de Salida en formato python con el codigo
+    maquina del fichero .hex
+    La lista esta formada por bloques con tamano menor o igual a 16
+    """
+  #-------------------------------------------------------------------
+    
+    #-- Convertir a bloques y luego a cadena python
+    blocks = memToBlocks16(self.__memory)
+    return blocksToStrPython(blocks,name)  
+  
+  
+  def outputTable(self):
+  #------------------------------------------------------------
+    """
+    Salida como una tabla Direccion - Contenido
+    """
+  #------------------------------------------------------------  
+    return memToStrTable(self.__memory)
+   
+  
+  def outputBlocks(self):
+  #----------------------------------------------------------
+    """
+    Salida como bloques en formato 2. Direccion - Bloque
+    """
+  #----------------------------------------------------------
+    blocks = memToBlocks(self.__memory)
+    return blocksToStr(blocks)
+    
+  
+  def outputBlocks16(self):
+  #----------------------------------------------------------
+    """
+    Salida como bloques en formato 3. Direccion - Bloque
+    """
+  #----------------------------------------------------------
+    blocks = memToBlocks16(self.__memory)
+    return blocksToStr(blocks)
+
+
+
+
+#------------------------------------------------------------------------------
+#           FUNCIONES ESTATICAS QUE SE PUEDEN INVOCAR DIRECTAMENTE
+#------------------------------------------------------------------------------
+
+
+
+def readHex (fd):
+#--------------------------------------------------------------
+  """
+  Funciona para analizar ficheros .HEX.
+  ENTRADAS: Descriptor del fichero
+  DEVUELVE: Una lista en el FORMATO 1 (memoria)
+  """
+#--------------------------------------------------------------
+
+  #-- Leer las lineas del fichero .hex
+  lines = fd.readlines ()
+  fd.close ()
+
+  # Inicializar la lista de salida
+  mem = []
+
+  #-- Recorrer todas las lineas del fichero
+  for line in lines:
+  
+    #-- FORMAT .HEX
+    #-- CAMPO 1. (1 byte) Comienzo de linea. Caracter ':'
+    if line [0] != ':':
+      raise ReaderError, 'Error en formato HEX: Comienzo de linea incorrecto'
+
+    #-- CAMPO 2. (2 bytes) Numero de bytes de los datos
+    count = int (line [1:3], 16)
+    
+    #-- CAMPO 3. (2 bytes) Direccion de comienzo de los datos
+    addr = int (line [3:7], 16) / 2
+    
+    #-- CAMPO 4. (1 byte). Tipo de comando (registro)
+    rectype = int (line [7:9], 16)
+
+    #-- El registro de tipo 1 indica que es el final del fichero
+    #-- Si es asi se termina y se devuelve el contenido leido
+    if rectype == 1:
+      return mem
+
+    #-- Si es un registro mayor a 1 se ignora
+    #-- Los registro de tipo 4 no tengo muy claro para que son
+    #-- Creo que indican cual es la direccion de comienzo del
+    #-- programa
+    #-- Los registros normales son los de tipo 0 (datos)
+    if rectype > 1:
+      continue
+
+    #-- Inicializar Checksum
+    chk = count + (addr * 2 & 0xFF) + (addr >> 7) + rectype
+
+    #-- CAMPO 5: Datos. Una cadena de "count" bytes. Se deben interpretar
+    #-- como palabras. El primer byte es el bajo y el segundo el alto
+    for loop in xrange (0, count / 2):
+      #-- Crear la tupla con el (byte alto, byte bajo)
+      data = (int (line [11 + 4 * loop: 13 + 4 * loop], 16),
+              int (line [9 + 4 * loop: 11 + 4 * loop], 16))
+      
+      #-- Actualizar checksum      
+      chk += data [0] + data [1]        
+              
+      #-- En el pic las palabras son de 14 bits por lo que el byte alto
+      #-- NUNCA puede ser mayor de 0x3F        
+      if data [0] > 0x3F:
+        raise ReaderError, 'Error en formato HEX: Palabra incorrecta'
+        
+      #-- Anadir la tupla con la direccion y los datos  
+      mem.append ((addr, data))
+      
+      #-- Incrementar la direccion
+      addr += 1
+      
+    #-- CAMPO 6: Checksum del fichero
+    checksum = int (line [9 + count * 2: 11 + count * 2], 16)
+    chk = (0x100 - chk & 0xFF) & 0xFF  
+
+    #-- Comprobación del checksum. Ver si el checksum del fichero es igual
+    #-- al calculado.
+    if chk != checksum:
+      raise ReaderError, 'Error en formato HEX: Fallo en checksum'
+
+  raise ReaderError, 'Error en formato HEX: Final erroneo'
+  
+
+
+def memToBlocks(mem):
+#---------------------------------------------------------------------- 
+  """
+  Conversion del FORMATO 1 (memoria) al FORMATO 2: lista de bloques
+  contiguos
+  ENTRADA: Lista en formato 1 (memoria)
+  DEVUELVE: Lista en FORMATO 2
+  """
+#----------------------------------------------------------------------
+
+  #-- obtener una copia local de la memoria para no borrar la original
+  data = [] + mem
+
+  #-- Obtener la primera tupla
+  address, (d0, d1) = data [0]
+  del data [0]
+  a = address
+
+  #-- Inicializar programa. Un programa es una lista de bloques contiguos
+  #-- de palabras
+  program = []
+  
+  #-- Comenzar el primer bloque. Situar el primer elemento
+  block = [a, (d0 * 0x100 + d1)]
+
+  #-- Repetir para cada palabra del fichero .hex
+  while len (data):
+  
+    #-- Obtener la siguiente palabra y su direccion
+    address, (d0, d1) = data [0]
+    del data [0]
+    
+    #-- Si la palabra esta a continuacion de la anterior
+    if address== a + 1: 
+      #-- Anadir palabra al bloque
+      block.append (d0 * 0x100 + d1)
+      a = address
+    else:  
+      #-- La palabra NO es contigua
+      #-- Hay dos casos:
+      #-- 1) Que este en el mismo subbloque de 8. En ese caso se considera
+      #-- que forman parte del mismo bloque. Los "gaps" se rellenan con ceros
+      #-- 2) Que esten en diferentes subbloques. Eso significa que 
+      #--    pertenecen a bloques separados.
+      if address/8 == (a+1)/8:  #-- Caso 1. Mismo subbloque
+        block.extend ((address - (a + 1)) * [0])
+        block.append (d0 * 0x100 + d1)
+        a = address
+      else:   #-- Caso 2: Distinto Bloque
+        #-- Anadir el bloque actual al programa
+        #-- Pero SOLO si es un bloque de codigo. Es decir, si su direccion
+        #-- de inicio esta por debajo de 0x2000. A partir de esa direccion
+        #-- lo que se tiene es la configuracion
+        program.append (block)
+        
+        #-- Crear el bloque nuevo. Meter el primer elemento
+        a = address
+        block = [a, (d0 * 0x100 + d1)]
+      
+  #-- Falta por añadir al programa el ultimo bloque leido 
+  program.append (block)
+    
+  return program
+
+
+
+def blocksToBlocks16(prog1):
+#--------------------------------------------------------------------------
+  """
+  CONVERSION DEL FORMATO 2  al FORMATO 3: Lista de bloques de
+  datos de tamano maximo de 16 palabras
+  ENTRADA: Lista en formato 2
+  DEVUELVE: Lista de bloques en FORMATO 3
+  """
+#---------------------------------------------------------------------------
+  #-- Programa de salida: lista de bloques de tamano 16 palabras
+  prog2 = []
+  
+  #---- Recorrer todos los bloques y trocearlos en bloques de 16 palabras
+  for block in prog1:
+
+    #-- Si el bloque tiene un tamano menor o igual a 16 no hace
+    #-- falta trocearlo
+    if len(block)<=16:
+      prog2.append(block)
+    else:
+      #-- Bloque tiene tamano mayor a 16. Hay que trocear.
+      
+      #-- Guardar la direccion de inicio
+      addr = block[0]
+      del block[0]
+      
+      #-- Calcular el numero de subbloques de 16 palabras que hay 
+      nblock = len(block)/16;
+     
+      #-- Obtener los subbloques completos
+      for i in range(nblock):
+        nuevo_bloque = [addr] + block[0:16]
+        
+        #-- Anadir subbloque
+        prog2.append(nuevo_bloque)
+        addr+=16;
+        del block[0:16]
+        
+      
+      #--- El ultimo bloque esta formados por los "restos"
+      if (len(block)!=0):
+        nuevo_bloque = [addr] + block
+        prog2.append(nuevo_bloque)   
+
+  return prog2
+
+
+
+def memToBlocks16(mem): 
+#--------------------------------------------------------------------------
+  """
+  CONVERSION DEL FORMATO 1 (memoria) al FORMATO 3: Lista de bloques de
+  datos de tamano maximo de 16 palabras
+  ENTRADA: Lista en formato 2
+  DEVUELVE: Lista de bloques en FORMATO 3
+  """
+#---------------------------------------------------------------------------
+ 
+  #-- Primero agrupar en bloques contiguos
+  prog1 = memToBlocks(mem)
+  
+  #-- "trocear" en bloques de 16
+  return blocksToBlocks16(prog1)
+
+
+
+
+#------------------------------------------------------------------------------#
+#            FUNCIONES DE CONVERSION A CADENAS DE CARACTERES                   #
+#------------------------------------------------------------------------------#
+
+
+def blocksToStrPython(program,name="prog"):
+#-------------------------------------------------------------------
+  """
+  Convertir a una cadena en formato de lista de Python
+  Se crea una cadena con syntaxis python con el codigo maquina
+  El parametro name es el nombre del programa en el codigo python
+  ENTRADAS:
+     -blocks:  LIsta de bloques en FORMATO 2 o 3
+     -name: Cadena a asignar como nombre a la lista de salida
+  DEVUELVE: Una cadena con la lista, en formato PYTHON
+  """
+#-------------------------------------------------------------------
+
+  #-- Comienzo de la cadena
+  prog_str = "%s=[" % (name)
+  
+  #-- Recorrer todos los bloques y pasarlos a un string
+  for block in program:
+    cad=["0x%04X" % (palabra) for palabra in block]
+    prog_str = prog_str + "[" + ", ".join(cad) + "],"
+    
+  #-- Final de la cadena  
+  prog_str+="]"  
+  
+  #-- Devolver la cadena
+  return prog_str
+  
+  #-- Esta es la version compacta. Hace lo mismo que todo lo anterior
+  #-- return '%s = [%s]' % (name, ', '.join (['[%s]' % (', '.join (["0x%04X" %
+  #            palabra for palabra in block])) for block in self.__program]))
+
+ 
+
+def memToStrTable(mem):
+#--------------------------------------------------------------------------
+  """
+  Convertir una memoria (formato 1) en una cadena en forma de tabla. 
+  Cada una de las filas contiene la direccion y su contenido
+  ENTRADAS: mem: Memoria en FORMATO 1
+  """
+#--------------------------------------------------------------------------
+
+  #-- Volcar la memoria
+  tabla=  "Dir: Contenido\n"
+  tabla+= "---- ---------\n"
+  for addres,palabra in mem:
+    tabla+= "%04X: %04X\n" % (addres, palabra[0]*0x100 + palabra[1])
+  return tabla
+  
+
+
+def blocksToStr(data):
+#----------------------------------------------------------------
+  """
+  Convertir a una lista en formato 2 o 3 en una cadena
+  ENTRADAS: data: datos en FORMATO 2 o 3
+  """
+#----------------------------------------------------------------
+  salida=""
+  for block in data:
+    salida+= "Direccion: %04X\n" % (block[0])
+    cad=["%04X" % (palabra) for palabra in block[1:]]
+    salida= salida + " ".join(cad)
+    salida+="\n\n"
+  return salida
+
+  #-- Esta es la version compacta (sustituye al resto)
+  #-- return ''.join (['Direccion: %04X\n%s\n\n' % (block [0], ' '.join  
+  #(["%04X" % (palabra) for palabra in block[1:]])) for block in self.__program])
diff --git a/chronopic-firmware/pydownloader-chronopic/libIris/IntelHex.pyc b/chronopic-firmware/pydownloader-chronopic/libIris/IntelHex.pyc
new file mode 100644
index 0000000..e534bf2
Binary files /dev/null and b/chronopic-firmware/pydownloader-chronopic/libIris/IntelHex.pyc differ
diff --git a/chronopic-firmware/pydownloader-chronopic/libIris/Pic16_Bootloader.py b/chronopic-firmware/pydownloader-chronopic/libIris/Pic16_Bootloader.py
new file mode 100644
index 0000000..49e7687
--- /dev/null
+++ b/chronopic-firmware/pydownloader-chronopic/libIris/Pic16_Bootloader.py
@@ -0,0 +1,446 @@
+#!/usr/bin/env python
+# -*- coding: iso-8859-15 -*-
+
+# Description: File downloader library for SkyPIC
+# Copyright (C) 2007 by Rafael Treviño Menéndez
+# Author: Rafael Treviño Menéndez <skasi 7 gmail com>
+#         Juan Gonzalez <juan iearobotics com>
+
+# 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.
+
+"""
+  Modulo Cliente para comunicarse con el PIC_BOOTLOADER y descargar       
+  ficheros .hex en la tarejta Skypic
+
+  Ademas se incorporan metodos para que el usuario pueda acceder 
+  a los diferentes servicios del Bootloader por si quiere implementarse
+  su propio programa de descarga o quiere hacer modificaciones a bajo 
+  nivel en el bootloader
+"""
+
+import serial 
+import time
+import IntelHex
+import sys
+
+
+#############
+# CONSTANTS #
+#############
+
+#--------------------------------------
+#- Configuracion del puerto serie 
+#--------------------------------------
+#-- Timeout por defecto para el acceso al puerto serie
+SERIAL_TIMEOUT = 0.2
+
+#--- Velocidad de transmision para la comunicacion con el PIC Bootloader
+BAUDIOS = 19200
+
+#------------------------------------------------------------------
+#-  IDENTIFICACION DE LOS COMANDOS DEL PROTOCOLO DEL BOOTLOADER  
+#------------------------------------------------------------------
+CMD_WRITE    = '\xE3'  #-- Escritura de un bloque
+CMD_DATA_OK  = '\xE7'  #-- Datos enviados correctamente
+CMD_OK       = '\xE4'  #-- Operacion ejecutada
+CMD_IDENT    = '\xEA'  #-- Comando de identificacion del bootloader
+CMD_IDACK    = '\xEB'  #-- Bootloader identificado
+CMD_SEND_DONE= '\xED'  #-- Comando de ejecucion
+
+#------------------------------------------------------------------------
+#-- Constantes usadas con el metodo download para indicar
+#-- lo que va ocurriendo con la descarga 
+#------------------------------------------------------------------------
+WRITING_START=1      #-- Comienzo de la escritura
+WRITING_INC=2        #-- Escritura de una palabra
+WRITING_END=3        #-- Fin de la escritura
+
+IDENT_START=4        #-- Comienzo de la identificacion del bootloader
+IDENT_NACK=5         #-- No se ha recibido respuesta
+
+#-- Timeout por defecto, en segundos, que se espera a detectar el 
+#-- Bootloader
+DEFAULT_TIMEOUT = 10
+
+
+#----------------------------------------
+#- Clase para la gestion de los errores
+#----------------------------------------
+class IrisError (Exception):
+  """
+  Excepciones producidas en el modulo Pic16_Bootloader
+  """
+  pass
+
+
+def default_logCallback(msg):
+  """
+    Funcion de "log" por defecto. 
+    Simplemente se imprimen los mensajes
+  """
+  sys.stdout.write(msg)
+  sys.stdout.flush()
+
+
+#-----------------------------------------------------------------------------
+def default_stateCallback(op,inc,total):
+  """
+  Funcion de estado por defecto
+  Se imprime informacion en la consola
+  La funcion debe devolver TRUE si todo esta OK y se quiere continuar
+  con el proceso. FALSE en caso contrario. La descarga se aborta
+ Los parametros recibidos son:
+   -op: Tipo de operacion. Indica la fase de la descarga que se ha iniciado
+   -inc: 
+      -En el estado IDENT_NACK indica el numero reitentos hasta el momento
+      -En el estado WRITING_INC indica el numero de bloques enviados
+   -total:
+      -En el estado IDENT_NACK indica el tiempo total transcurrido desde
+       el comienzo de la identificacion (en segundos)
+      -En el estado WRITING_INC indica el numero total de bloques del
+       del programa a transmitir
+
+  El usuario puede crear su propia funcion de estado para actualizar el
+  interfaz de su aplicacion como quiera. Esta funcion es un ejemplo para
+  una interfaz de consola
+  """
+
+
+  #--------------------------------------------------
+  #- Comienzo de la identificacion del Bootloader 
+  #--------------------------------------------------
+  if op==IDENT_START:
+    print "Esperando Bootloader"
+    return True
+    
+  #-------------------------------------------------------------------------
+  #-- Timeout en la identificacion. 
+  #-- Cuando el tiempo transcurrido supera el timeout en la identificacion
+  #-- se aborta devolviendose False
+  #-------------------------------------------------------------------------  
+  elif op==IDENT_NACK:
+    sys.stdout.write('.')
+    sys.stdout.flush()
+    if total<=DEFAULT_TIMEOUT:
+      return True
+    else :
+      return False  
+  
+  #-----------------------------------------------------------------------
+  #-- Comienzo de la descarga
+  #-- Se imprime una barra de status en ASCII formada por '.' y se lleva
+  #-- el cursor a la izquierda (imprimiendo el caracter '\b'
+  #----------------------------------------------------------------------
+  elif op==WRITING_START:
+    sys.stdout.write("\nDescargando:\n")
+    cad="".join(["." for i in range(total)])
+    back="".join(["\b" for i in range(total)])
+    
+    #-- Imprimir la "barra de estado" con '.'. Un '.' por cada bloque
+    sys.stdout.write(cad)
+    
+    #-- Llevar el cursos a la izquierda
+    sys.stdout.write(back)
+    sys.stdout.flush()
+    
+    return True
+  
+  #----------------------------------------------------------------------
+  #-- Se ha grabado un bloque. Se actualiza la "barra de estado ascii"  
+  #----------------------------------------------------------------------
+  elif op==WRITING_INC:  
+    sys.stdout.write("*")
+    sys.stdout.flush()
+    return True
+    
+  #----------------------------------------
+  #- Fin de la descarga
+  #----------------------------------------
+  elif op==WRITING_END: 
+    print " OK"
+    return True
+    
+
+#----------------------------------------------------------------------------
+#--                           CLASE  PRINCIPAL    
+#----------------------------------------------------------------------------
+class Iris:
+  """
+  Clase prinipal del modulo Pic16_Bootloader. Se utiliza para comunicarse
+  con el Bootloader y descargar programas en la Skypic
+  """
+
+  #---------------------
+  #- Destructor 
+  #---------------------
+  def __del__(self):
+  
+    #-- Cerrar el pueto serie
+    if self.__serial:
+      #print "Debug: cerrando puerto serie: %s" % (self.__serial.portstr)
+      self.__serial.close()
+
+
+  def __init__ (self, serialName, logCallback = default_logCallback):
+  #-------------------------------------------------------------------------
+    """
+  Constructor
+  ENTRADAS:
+    serialName: Dispositivo serie
+    logCallback: Funcion de retrollamada para el "log"    
+    """
+  #--------------------------------------------------------------------------  
+    
+    self.__serial = None
+    self.__log = logCallback
+    
+    #-- Abrir puerto serie
+    try:
+      self.__serial = serial.Serial(serialName, BAUDIOS)
+    except serial.SerialException:
+      raise IrisError,'Error al abrir puerto serie %s.' % serialName
+
+    if self.__log:
+      self.__log ('Serial port %s opened.\n' % self.__serial.portstr)
+
+    #-- Configurar timeout
+    #-- He detectado que en Linux al configurar el timeout se modifica
+    #-- el estado del DTR. No en todos los casos (depende del driver
+    #-- del conversor USB-serie usado). El problema siempre esta en que
+    #-- los valores del DTR no estan estandarizados y cada driver los 
+    #-- maneja a su propia manera.
+    #-- La solucion que se esta utilizando es la de configurar el 
+    #-- timeout al principio
+    self.__serial.timeout = SERIAL_TIMEOUT
+  
+    #-- Vaciar los buffers del puerto serie
+    self.__serial.flushInput()
+    self.__serial.flushOutput()
+
+  
+  def close(self):
+  #-----------------------------
+    """
+    Cerrar el puerto serie
+    """
+  #-----------------------------
+    if self.__serial!=None:
+      self.__serial.close()
+      
+ 
+  
+  def sendDone (self):
+  #--------------------------------------------------------------------
+    """
+    Enviar comando SENDDONE para que arranque el programa cargado
+    """
+  #--------------------------------------------------------------------  
+  
+    #-- Enviar el comando
+    self.__serial.write (CMD_SEND_DONE)
+    
+    #-- Esperar la respuesta
+    ch = self.__serial.read (1)
+    if ch != CMD_OK:
+      raise IrisError, "Error en Done"
+      
+    if self.__log:
+      self.__log ('Ejecutando programa\n')  
+      
+
+  def skypicReset (self):
+  #----------------------------------------------------------------
+    """
+    Hacer reset de la Skypic. Solo funcionara si el jumper JP4
+    esta colocado en la posicion DTR
+    """
+  #----------------------------------------------------------------
+  
+    #-- Desactivar la senal DTR durante 0.5 segundos
+    self.__serial.setDTR (0)
+    
+    #-- Esto es para depurar
+    #if self.__log:
+    #  self.__log("%s: DTR OFF\n" % self.__serial.portstr)
+    time.sleep (0.5)
+    
+    #-- Volver a activarla. Reset hecho
+    self.__serial.setDTR (1)
+    
+    #-- Esto es para depurar
+    #if self.__log:
+    #  self.__log("%s: DTR ON\n" % self.__serial.portstr)
+    
+    if self.__log:
+      self.__log ('Reset Skypic\n')
+    
+
+  
+  def identBootloader (self, timeoutCallback=default_stateCallback):
+  #-----------------------------------------------------------------------
+    """
+   Identificar el Bootloader
+   Devuelve: 
+      -TRUE si se ha detectado
+      -FALSE si ha transcurrido el timeout y no se ha detectado
+       Esto puede ocurrir bien porque no haya comunicacion con el bootloader
+       o bien porque no se haya pulsado el boton de reset de la skypic
+   ENTRADAS:
+      -timeoutCallback : Funcion de estado. Se invoca al comienzo de la 
+         identificacion y si no se ha podio encontrar el Bootloader
+    """
+  #-----------------------------------------------------------------------
+     
+    #-- Inicializacion de la funcion de callback
+    if timeoutCallback:
+      timeoutCallback(IDENT_START,0,0)    
+
+    # Timeout or bad reply
+    nack=0;
+    while True:
+
+      #-- Enviar comando de identificacion
+      self.__serial.write (CMD_IDENT)
+
+      #-- Esperar la respuesta
+      id = self.__serial.read (1)
+
+      #-- Condicion de deteccion del bootloader
+      if len (id) == 1 and id == CMD_IDACK:
+        if self.__log:
+          self.__log ('Bootloader OK\n')
+        return True
+          
+      nack+=1    
+      #-- Invocar la funcion de callback
+      if timeoutCallback:
+        ret = timeoutCallback(IDENT_NACK,nack,float(nack)*SERIAL_TIMEOUT) 
+        if ret==False:
+          #-- Bootloder NO detectado
+          if self.__log:
+            self.__log ('TIMEOUT\n')
+          
+          raise IrisError,'Bootloader No detectado'
+    
+
+  def writeData(self,block):
+  #--------------------------------------------------
+    """
+    Escribir un bloque a traves del booloader
+    El primer elemento del bloque es la direccion
+    """
+  #--------------------------------------------------
+    
+    #-- Obtener la direccion de comienzo del bloque
+    addr=block[0]
+    
+    #-- Obtener el bloque en bytes
+    #-- Se almacena en data. Primero el byte alto y luego el bajo
+    data=[]
+    for i in block[1:]:
+      data.append(i>>8 & 0xFF)  #-- Andir byte alto
+      data.append(i&0xFF)       #-- Anadir byte bajo
+      
+    #-- Calcular el Checksum  
+    chk = sum(data) & 0xFF
+      
+    #-- Tamano del bloque en bytes
+    tam = len (data)
+
+    #------------------------------------
+    #-- Comenzar la escritura del bloque 
+    #------------------------------------
+    #-- Enviar comando
+    self.__serial.write (CMD_WRITE)
+    
+    #-- Enviar direccion de comienzo del bloque
+    self.__serial.write ('%c%c' % (chr (addr >> 8 & 0xFF),
+                                   chr (addr & 0xFF)))
+                                   
+    #-- Enviar tamano
+    self.__serial.write (chr (tam))
+    
+    #-- Enviar checksum
+    self.__serial.write (chr (chk))
+    
+    #-- Enviar los datos
+    for d in data:
+      self.__serial.write (chr(d))
+    
+    #-----------------------------
+    #-- Comprobar las respuestas 
+    #-----------------------------
+    
+    # --- Datos correctos?
+    ch = self.__serial.read (1)
+    if ch != CMD_DATA_OK:
+      raise IrisError, 'Data error.'
+
+    # --- Escritura ok?
+    ch = self.__serial.read (1)
+    if ch != CMD_OK:
+      raise IrisError, 'Write error.'
+    
+  
+  def download (self, program, stateCallback=default_stateCallback):
+  #---------------------------------------------------------------------------
+    """
+    Descargar un programa a traves del bootloader
+    Para cada fase de la descarga se invoca la funcion de retrollamda
+    stateCallback
+    """
+  #---------------------------------------------------------------------------
+  
+    #-- Hacer un reset
+    self.skypicReset()
+    
+    #-- Identificar el bootloader
+    #-- Se invoca a la funcion de estado
+    self.identBootloader(timeoutCallback=stateCallback)
+    
+    #-- Obtener Tamano del programa en bloques
+    tam = len(program)
+    
+    #-- Invocar la funcion de estado para indicar el comienzo
+    #-- de la descarga
+    if stateCallback:
+      ok=stateCallback(WRITING_START, 0, tam);
+      if not ok:
+        raise IrisError, "Abortado"
+      
+    #-- Escribir los bloques
+    count=1;
+    for block in program:
+      self.writeData(block)
+      
+      #-- Invocar funcion de estado para indicar que se ha descargado
+      #-- un bloque
+      if stateCallback:
+        ok=stateCallback(WRITING_INC,count,tam); 
+        if not ok:
+          raise IrisError, "Abortado"        
+      
+      #-- Incrementar contador de numero de bloques descargados
+      count=count + 1
+      
+    #-- Invocar la funcion de estado para indicar que se ha terminado
+    #-- la descarga, siempre que no haya sido abortada    
+    if stateCallback:
+      ok=stateCallback(WRITING_END,0,tam);  
+      if not ok:
+          raise IrisError, "Abortado" 
+      
+    #-- Ejecutar el programa  
+    self.sendDone ()
diff --git a/chronopic-firmware/pydownloader-chronopic/libIris/Pic16_Bootloader.pyc b/chronopic-firmware/pydownloader-chronopic/libIris/Pic16_Bootloader.pyc
new file mode 100644
index 0000000..36cf0cf
Binary files /dev/null and b/chronopic-firmware/pydownloader-chronopic/libIris/Pic16_Bootloader.pyc differ
diff --git a/chronopic-firmware/pydownloader-chronopic/libIris/Pic16_Bootloader.py~ b/chronopic-firmware/pydownloader-chronopic/libIris/Pic16_Bootloader.py~
new file mode 100644
index 0000000..a7205cd
--- /dev/null
+++ b/chronopic-firmware/pydownloader-chronopic/libIris/Pic16_Bootloader.py~
@@ -0,0 +1,446 @@
+#!/usr/bin/env python
+# -*- coding: iso-8859-15 -*-
+
+# Description: File downloader library for SkyPIC
+# Copyright (C) 2007 by Rafael Treviño Menéndez
+# Author: Rafael Treviño Menéndez <skasi 7 gmail com>
+#         Juan Gonzalez <juan iearobotics com>
+
+# 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.
+
+"""
+  Modulo Cliente para comunicarse con el PIC_BOOTLOADER y descargar       
+  ficheros .hex en la tarejta Skypic
+
+  Ademas se incorporan metodos para que el usuario pueda acceder 
+  a los diferentes servicios del Bootloader por si quiere implementarse
+  su propio programa de descarga o quiere hacer modificaciones a bajo 
+  nivel en el bootloader
+"""
+
+import serial 
+import time
+import IntelHex
+import sys
+
+
+#############
+# CONSTANTS #
+#############
+
+#--------------------------------------
+#- Configuracion del puerto serie 
+#--------------------------------------
+#-- Timeout por defecto para el acceso al puerto serie
+SERIAL_TIMEOUT = 0.2
+
+#--- Velocidad de transmision para la comunicacion con el PIC Bootloader
+BAUDIOS = 38400
+
+#------------------------------------------------------------------
+#-  IDENTIFICACION DE LOS COMANDOS DEL PROTOCOLO DEL BOOTLOADER  
+#------------------------------------------------------------------
+CMD_WRITE    = '\xE3'  #-- Escritura de un bloque
+CMD_DATA_OK  = '\xE7'  #-- Datos enviados correctamente
+CMD_OK       = '\xE4'  #-- Operacion ejecutada
+CMD_IDENT    = '\xEA'  #-- Comando de identificacion del bootloader
+CMD_IDACK    = '\xEB'  #-- Bootloader identificado
+CMD_SEND_DONE= '\xED'  #-- Comando de ejecucion
+
+#------------------------------------------------------------------------
+#-- Constantes usadas con el metodo download para indicar
+#-- lo que va ocurriendo con la descarga 
+#------------------------------------------------------------------------
+WRITING_START=1      #-- Comienzo de la escritura
+WRITING_INC=2        #-- Escritura de una palabra
+WRITING_END=3        #-- Fin de la escritura
+
+IDENT_START=4        #-- Comienzo de la identificacion del bootloader
+IDENT_NACK=5         #-- No se ha recibido respuesta
+
+#-- Timeout por defecto, en segundos, que se espera a detectar el 
+#-- Bootloader
+DEFAULT_TIMEOUT = 10
+
+
+#----------------------------------------
+#- Clase para la gestion de los errores
+#----------------------------------------
+class IrisError (Exception):
+  """
+  Excepciones producidas en el modulo Pic16_Bootloader
+  """
+  pass
+
+
+def default_logCallback(msg):
+  """
+    Funcion de "log" por defecto. 
+    Simplemente se imprimen los mensajes
+  """
+  sys.stdout.write(msg)
+  sys.stdout.flush()
+
+
+#-----------------------------------------------------------------------------
+def default_stateCallback(op,inc,total):
+  """
+  Funcion de estado por defecto
+  Se imprime informacion en la consola
+  La funcion debe devolver TRUE si todo esta OK y se quiere continuar
+  con el proceso. FALSE en caso contrario. La descarga se aborta
+ Los parametros recibidos son:
+   -op: Tipo de operacion. Indica la fase de la descarga que se ha iniciado
+   -inc: 
+      -En el estado IDENT_NACK indica el numero reitentos hasta el momento
+      -En el estado WRITING_INC indica el numero de bloques enviados
+   -total:
+      -En el estado IDENT_NACK indica el tiempo total transcurrido desde
+       el comienzo de la identificacion (en segundos)
+      -En el estado WRITING_INC indica el numero total de bloques del
+       del programa a transmitir
+
+  El usuario puede crear su propia funcion de estado para actualizar el
+  interfaz de su aplicacion como quiera. Esta funcion es un ejemplo para
+  una interfaz de consola
+  """
+
+
+  #--------------------------------------------------
+  #- Comienzo de la identificacion del Bootloader 
+  #--------------------------------------------------
+  if op==IDENT_START:
+    print "Esperando Bootloader"
+    return True
+    
+  #-------------------------------------------------------------------------
+  #-- Timeout en la identificacion. 
+  #-- Cuando el tiempo transcurrido supera el timeout en la identificacion
+  #-- se aborta devolviendose False
+  #-------------------------------------------------------------------------  
+  elif op==IDENT_NACK:
+    sys.stdout.write('.')
+    sys.stdout.flush()
+    if total<=DEFAULT_TIMEOUT:
+      return True
+    else :
+      return False  
+  
+  #-----------------------------------------------------------------------
+  #-- Comienzo de la descarga
+  #-- Se imprime una barra de status en ASCII formada por '.' y se lleva
+  #-- el cursor a la izquierda (imprimiendo el caracter '\b'
+  #----------------------------------------------------------------------
+  elif op==WRITING_START:
+    sys.stdout.write("\nDescargando:\n")
+    cad="".join(["." for i in range(total)])
+    back="".join(["\b" for i in range(total)])
+    
+    #-- Imprimir la "barra de estado" con '.'. Un '.' por cada bloque
+    sys.stdout.write(cad)
+    
+    #-- Llevar el cursos a la izquierda
+    sys.stdout.write(back)
+    sys.stdout.flush()
+    
+    return True
+  
+  #----------------------------------------------------------------------
+  #-- Se ha grabado un bloque. Se actualiza la "barra de estado ascii"  
+  #----------------------------------------------------------------------
+  elif op==WRITING_INC:  
+    sys.stdout.write("*")
+    sys.stdout.flush()
+    return True
+    
+  #----------------------------------------
+  #- Fin de la descarga
+  #----------------------------------------
+  elif op==WRITING_END: 
+    print " OK"
+    return True
+    
+
+#----------------------------------------------------------------------------
+#--                           CLASE  PRINCIPAL    
+#----------------------------------------------------------------------------
+class Iris:
+  """
+  Clase prinipal del modulo Pic16_Bootloader. Se utiliza para comunicarse
+  con el Bootloader y descargar programas en la Skypic
+  """
+
+  #---------------------
+  #- Destructor 
+  #---------------------
+  def __del__(self):
+  
+    #-- Cerrar el pueto serie
+    if self.__serial:
+      #print "Debug: cerrando puerto serie: %s" % (self.__serial.portstr)
+      self.__serial.close()
+
+
+  def __init__ (self, serialName, logCallback = default_logCallback):
+  #-------------------------------------------------------------------------
+    """
+  Constructor
+  ENTRADAS:
+    serialName: Dispositivo serie
+    logCallback: Funcion de retrollamada para el "log"    
+    """
+  #--------------------------------------------------------------------------  
+    
+    self.__serial = None
+    self.__log = logCallback
+    
+    #-- Abrir puerto serie
+    try:
+      self.__serial = serial.Serial(serialName, BAUDIOS)
+    except serial.SerialException:
+      raise IrisError,'Error al abrir puerto serie %s.' % serialName
+
+    if self.__log:
+      self.__log ('Serial port %s opened.\n' % self.__serial.portstr)
+
+    #-- Configurar timeout
+    #-- He detectado que en Linux al configurar el timeout se modifica
+    #-- el estado del DTR. No en todos los casos (depende del driver
+    #-- del conversor USB-serie usado). El problema siempre esta en que
+    #-- los valores del DTR no estan estandarizados y cada driver los 
+    #-- maneja a su propia manera.
+    #-- La solucion que se esta utilizando es la de configurar el 
+    #-- timeout al principio
+    self.__serial.timeout = SERIAL_TIMEOUT
+  
+    #-- Vaciar los buffers del puerto serie
+    self.__serial.flushInput()
+    self.__serial.flushOutput()
+
+  
+  def close(self):
+  #-----------------------------
+    """
+    Cerrar el puerto serie
+    """
+  #-----------------------------
+    if self.__serial!=None:
+      self.__serial.close()
+      
+ 
+  
+  def sendDone (self):
+  #--------------------------------------------------------------------
+    """
+    Enviar comando SENDDONE para que arranque el programa cargado
+    """
+  #--------------------------------------------------------------------  
+  
+    #-- Enviar el comando
+    self.__serial.write (CMD_SEND_DONE)
+    
+    #-- Esperar la respuesta
+    ch = self.__serial.read (1)
+    if ch != CMD_OK:
+      raise IrisError, "Error en Done"
+      
+    if self.__log:
+      self.__log ('Ejecutando programa\n')  
+      
+
+  def skypicReset (self):
+  #----------------------------------------------------------------
+    """
+    Hacer reset de la Skypic. Solo funcionara si el jumper JP4
+    esta colocado en la posicion DTR
+    """
+  #----------------------------------------------------------------
+  
+    #-- Desactivar la senal DTR durante 0.5 segundos
+    self.__serial.setDTR (0)
+    
+    #-- Esto es para depurar
+    #if self.__log:
+    #  self.__log("%s: DTR OFF\n" % self.__serial.portstr)
+    time.sleep (0.5)
+    
+    #-- Volver a activarla. Reset hecho
+    self.__serial.setDTR (1)
+    
+    #-- Esto es para depurar
+    #if self.__log:
+    #  self.__log("%s: DTR ON\n" % self.__serial.portstr)
+    
+    if self.__log:
+      self.__log ('Reset Skypic\n')
+    
+
+  
+  def identBootloader (self, timeoutCallback=default_stateCallback):
+  #-----------------------------------------------------------------------
+    """
+   Identificar el Bootloader
+   Devuelve: 
+      -TRUE si se ha detectado
+      -FALSE si ha transcurrido el timeout y no se ha detectado
+       Esto puede ocurrir bien porque no haya comunicacion con el bootloader
+       o bien porque no se haya pulsado el boton de reset de la skypic
+   ENTRADAS:
+      -timeoutCallback : Funcion de estado. Se invoca al comienzo de la 
+         identificacion y si no se ha podio encontrar el Bootloader
+    """
+  #-----------------------------------------------------------------------
+     
+    #-- Inicializacion de la funcion de callback
+    if timeoutCallback:
+      timeoutCallback(IDENT_START,0,0)    
+
+    # Timeout or bad reply
+    nack=0;
+    while True:
+
+      #-- Enviar comando de identificacion
+      self.__serial.write (CMD_IDENT)
+
+      #-- Esperar la respuesta
+      id = self.__serial.read (1)
+
+      #-- Condicion de deteccion del bootloader
+      if len (id) == 1 and id == CMD_IDACK:
+        if self.__log:
+          self.__log ('Bootloader OK\n')
+        return True
+          
+      nack+=1    
+      #-- Invocar la funcion de callback
+      if timeoutCallback:
+        ret = timeoutCallback(IDENT_NACK,nack,float(nack)*SERIAL_TIMEOUT) 
+        if ret==False:
+          #-- Bootloder NO detectado
+          if self.__log:
+            self.__log ('TIMEOUT\n')
+          
+          raise IrisError,'Bootloader No detectado'
+    
+
+  def writeData(self,block):
+  #--------------------------------------------------
+    """
+    Escribir un bloque a traves del booloader
+    El primer elemento del bloque es la direccion
+    """
+  #--------------------------------------------------
+    
+    #-- Obtener la direccion de comienzo del bloque
+    addr=block[0]
+    
+    #-- Obtener el bloque en bytes
+    #-- Se almacena en data. Primero el byte alto y luego el bajo
+    data=[]
+    for i in block[1:]:
+      data.append(i>>8 & 0xFF)  #-- Andir byte alto
+      data.append(i&0xFF)       #-- Anadir byte bajo
+      
+    #-- Calcular el Checksum  
+    chk = sum(data) & 0xFF
+      
+    #-- Tamano del bloque en bytes
+    tam = len (data)
+
+    #------------------------------------
+    #-- Comenzar la escritura del bloque 
+    #------------------------------------
+    #-- Enviar comando
+    self.__serial.write (CMD_WRITE)
+    
+    #-- Enviar direccion de comienzo del bloque
+    self.__serial.write ('%c%c' % (chr (addr >> 8 & 0xFF),
+                                   chr (addr & 0xFF)))
+                                   
+    #-- Enviar tamano
+    self.__serial.write (chr (tam))
+    
+    #-- Enviar checksum
+    self.__serial.write (chr (chk))
+    
+    #-- Enviar los datos
+    for d in data:
+      self.__serial.write (chr(d))
+    
+    #-----------------------------
+    #-- Comprobar las respuestas 
+    #-----------------------------
+    
+    # --- Datos correctos?
+    ch = self.__serial.read (1)
+    if ch != CMD_DATA_OK:
+      raise IrisError, 'Data error.'
+
+    # --- Escritura ok?
+    ch = self.__serial.read (1)
+    if ch != CMD_OK:
+      raise IrisError, 'Write error.'
+    
+  
+  def download (self, program, stateCallback=default_stateCallback):
+  #---------------------------------------------------------------------------
+    """
+    Descargar un programa a traves del bootloader
+    Para cada fase de la descarga se invoca la funcion de retrollamda
+    stateCallback
+    """
+  #---------------------------------------------------------------------------
+  
+    #-- Hacer un reset
+    self.skypicReset()
+    
+    #-- Identificar el bootloader
+    #-- Se invoca a la funcion de estado
+    self.identBootloader(timeoutCallback=stateCallback)
+    
+    #-- Obtener Tamano del programa en bloques
+    tam = len(program)
+    
+    #-- Invocar la funcion de estado para indicar el comienzo
+    #-- de la descarga
+    if stateCallback:
+      ok=stateCallback(WRITING_START, 0, tam);
+      if not ok:
+        raise IrisError, "Abortado"
+      
+    #-- Escribir los bloques
+    count=1;
+    for block in program:
+      self.writeData(block)
+      
+      #-- Invocar funcion de estado para indicar que se ha descargado
+      #-- un bloque
+      if stateCallback:
+        ok=stateCallback(WRITING_INC,count,tam); 
+        if not ok:
+          raise IrisError, "Abortado"        
+      
+      #-- Incrementar contador de numero de bloques descargados
+      count=count + 1
+      
+    #-- Invocar la funcion de estado para indicar que se ha terminado
+    #-- la descarga, siempre que no haya sido abortada    
+    if stateCallback:
+      ok=stateCallback(WRITING_END,0,tam);  
+      if not ok:
+          raise IrisError, "Abortado" 
+      
+    #-- Ejecutar el programa  
+    self.sendDone ()
diff --git a/chronopic-firmware/pydownloader-chronopic/libIris/Pic16_Firmware.py b/chronopic-firmware/pydownloader-chronopic/libIris/Pic16_Firmware.py
new file mode 100644
index 0000000..5762006
--- /dev/null
+++ b/chronopic-firmware/pydownloader-chronopic/libIris/Pic16_Firmware.py
@@ -0,0 +1,70 @@
+#!/usr/bin/env python
+# -*- coding: iso-8859-15 -*-
+
+# Description: File downloader library for SkyPIC
+# Copyright (C) 2007 by Rafael Treviño Menéndez
+# Author: Rafael Treviño Menéndez <skasi 7 gmail com>
+#         Juan Gonzalez <juan iearobotics com>
+
+# 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.
+
+
+#----------------------------------------------------------------------------
+"""
+ Libreria que contiene FIRMWARE para la Skypic 
+ El firmware ha sido obtenido a partir de los ficheros .hex utilizando 
+ la herramienta hex2python, de la siguiente manera:
+
+  $ ./hex2python.py fichero.hex f3 nombre_lista
+
+ Por ejemplo, el clasico programa del led parpdeante se ha obtenido asi:
+
+ ./hex2python.py ledp1.hex f3 ledp1
+"""
+#----------------------------------------------------------------------------
+
+
+#---------------------------------------------------------------------------
+#- LEDON. Encender el led de la Skypic
+#---------------------------------------------------------------------------
+ledon=[[0x0000, 0x0000, 0x118A, 0x120A, 0x280C, 0x0000, 0x1683, 0x1303, 0x1086, 0x1283, 0x1486, 0x280A, 0x0008, 0x118A, 0x120A, 0x2805],]
+
+#----------------------------------------------------------------------
+#- LEDP1.  Programa del ledp, que hace parpadear el led de la skypic
+#----------------------------------------------------------------------
+ledp1=[[0x0000, 0x0000, 0x118A, 0x120A, 0x2821, 0x0000, 0x30FD, 0x1683, 0x1303, 0x0086, 0x3002, 0x1283, 0x0686, 0x30FF, 0x00FF, 0x30FF, 0x2012],[0x0010, 0x2809, 0x0008, 0x1283, 0x1303, 0x00A3, 0x087F, 0x00A2, 0x0822, 0x0423, 0x1903, 0x2820, 0x30FF, 0x07A2, 0x1C03, 0x03A3, 0x2817],[0x0020, 0x0008, 0x118A, 0x120A, 0x2805],]
+
+#----------------------------------------------------------------------
+#- LEDP2.  Programa del ledp, que hace parpadear el led de la skypic. 
+#- Se diferencia del ledp1 en que el parpadeo es mas rapido
+#----------------------------------------------------------------------
+ledp2=[[0x0000, 0x0000, 0x118A, 0x120A, 0x2821, 0x0000, 0x30FD, 0x1683, 0x1303, 0x0086, 0x3002, 0x1283, 0x0686, 0x3000, 0x00FF, 0x3080, 0x2012],[0x0010, 0x2809, 0x0008, 0x1283, 0x1303, 0x00A3, 0x087F, 0x00A2, 0x0822, 0x0423, 0x1903, 0x2820, 0x30FF, 0x07A2, 0x1C03, 0x03A3, 0x2817],[0x0020, 0x0008, 0x118A, 0x120A, 0x2805],]
+
+#----------------------------------------------------------------------------
+#-          FIRMWARE DEL PROYECTO STARGATE 
+#----------------------------------------------------------------------------
+
+#--- Servidor de Eco. V1. Velocidad 9600 Baudios
+echo=[[0x0000, 0x0183, 0x3000, 0x008A, 0x2804, 0x1683, 0x3081, 0x0099, 0x3024, 0x0098, 0x1283, 0x3090, 0x0098, 0x1683, 0x0186, 0x1283, 0x30FF],[0x0010, 0x0086, 0x2015, 0x2019, 0x0086, 0x2811, 0x1E8C, 0x2815, 0x081A, 0x0008, 0x1E0C, 0x2819, 0x0099, 0x0008],]
+
+#--- Servidor GENERICO. V1. Velocidad 9600 baudios
+generic=[[0x0000, 0x0183, 0x3000, 0x008A, 0x2804, 0x1683, 0x3081, 0x0099, 0x3024, 0x0098, 0x1283, 0x3090, 0x0098, 0x1683, 0x1086, 0x1283, 0x3002],[0x0010, 0x0086, 0x2048, 0x00A0, 0x3050, 0x0220, 0x1903, 0x2824, 0x3049, 0x0220, 0x1903, 0x2827, 0x304C, 0x0220, 0x1903, 0x2830, 0x3053],[0x0020, 0x0220, 0x1903, 0x2838, 0x2811, 0x304F, 0x204C, 0x2811, 0x3049, 0x204C, 0x3020, 0x204C, 0x3030, 0x204C, 0x3010, 0x204C, 0x2811],[0x0030, 0x203E, 0x0800, 0x00A3, 0x304C, 0x204C, 0x0823, 0x204C, 0x2811, 0x203E, 0x2048, 0x0080, 0x3053, 0x204C, 0x2811, 0x2048, 0x0084],[0x0040, 0x2048, 0x00A1, 0x1821, 0x2846, 0x1383, 0x2847, 0x1783, 0x0008, 0x1E8C, 0x2848, 0x081A, 0x0008, 0x1E0C, 0x284C, 0x0099, 0x0008],]
+
+#--- Servidor SERVOS8. V1. Velocidad 9600 baudios
+servos8=[[0x0000, 0x0000, 0x118A, 0x120A, 0x2907, 0x00F2, 0x0E03, 0x0183, 0x1283, 0x1303, 0x00F1, 0x080A, 0x00F0, 0x018A, 0x110B, 0x3000, 0x1283],[0x0010, 0x1303, 0x042B, 0x1D03, 0x2820, 0x0829, 0x052A, 0x1283, 0x1303, 0x0086, 0x30EA, 0x0081, 0x3001, 0x1283, 0x1303, 0x00AB, 0x2862],[0x0020, 0x082B, 0x3A01, 0x1D03, 0x2839, 0x0828, 0x3E20, 0x00AF, 0x3000, 0x1803, 0x3E01, 0x00B0, 0x082F, 0x0084, 0x1383, 0x1830, 0x1783],[0x0030, 0x0800, 0x1283, 0x1303, 0x0081, 0x3002, 0x1283, 0x1303, 0x00AB, 0x2862, 0x082B, 0x3A02, 0x1D03, 0x2861, 0x1283, 0x1303, 0x0186],[0x0040, 0x1283, 0x1303, 0x0828, 0x3E20, 0x00AF, 0x3000, 0x1803, 0x3E01, 0x00B0, 0x082F, 0x0084, 0x1383, 0x1830, 0x1783, 0x0800, 0x3C52],[0x0050, 0x1283, 0x1303, 0x0081, 0x1283, 0x1303, 0x01AB, 0x1003, 0x0DA9, 0x0AA8, 0x3000, 0x0429, 0x1D03, 0x2862, 0x3001, 0x00A9, 0x01A8],[0x0060, 0x2862, 0x01AB, 0x1283, 0x1303, 0x0870, 0x008A, 0x0183, 0x0E71, 0x0083, 0x0EF2, 0x0E72, 0x0009, 0x1683, 0x1303, 0x0186, 0x3002],[0x0070, 0x1283, 0x00
 86, 0x1283, 0x1303, 0x01B4, 0x3008, 0x0234, 0x1803, 0x2889, 0x0834, 0x3E20, 0x00B5, 0x3000, 0x1803, 0x3E01, 0x00B6],[0x0080, 0x0835, 0x0084, 0x1383, 0x1836, 0x1783, 0x30B0, 0x0080, 0x0AB4, 0x2875, 0x01AA, 0x01A8, 0x01AB, 0x3001, 0x00A9, 0x20FD, 0x20DF],[0x0090, 0x20F7, 0x1283, 0x1303, 0x00B4, 0x3A45, 0x1903, 0x28AA, 0x0834, 0x3A49, 0x1903, 0x28A6, 0x0834, 0x3A50, 0x1903, 0x28A4, 0x0834],[0x00A0, 0x3A57, 0x1903, 0x28A8, 0x2890, 0x20DC, 0x2890, 0x20D3, 0x2890, 0x20B2, 0x2890, 0x20AD, 0x2890, 0x0008, 0x20F7, 0x1283, 0x1303],[0x00B0, 0x00AA, 0x0008, 0x20F7, 0x1283, 0x1303, 0x00AC, 0x20F7, 0x1283, 0x1303, 0x00B1, 0x3099, 0x0231, 0x1C03, 0x28C0, 0x3099, 0x00B1],[0x00C0, 0x032C, 0x00B2, 0x3E20, 0x00B2, 0x3000, 0x1803, 0x3E01, 0x00B3, 0x0831, 0x3CFF, 0x00B1, 0x0832, 0x0084, 0x1383, 0x1833, 0x1783],[0x00D0, 0x0831, 0x0080, 0x0008, 0x3049, 0x20E9, 0x3030, 0x20E9, 0x3030, 0x20E9, 0x3011, 0x20E9, 0x0008, 0x304F, 0x20E9, 0x0008, 0x3005],[0x00E0, 0x1683, 0x1303, 0x0081, 0x110B, 0x168B, 0x
 178B, 0x1283, 0x0181, 0x0008, 0x1283, 0x1303, 0x00AE, 0x1283, 0x1303, 0x1E0C, 0x28EC],[0x00F0, 0x1283, 0x1303, 0x082E, 0x1283, 0x1303, 0x0099, 0x0008, 0x1283, 0x1303, 0x1E8C, 0x28F7, 0x081A, 0x0008, 0x3081, 0x1683, 0x1303],[0x0100, 0x0099, 0x3024, 0x0098, 0x3090, 0x1283, 0x0098, 0x0008, 0x118A, 0x120A, 0x286C],]
+
+
+#--- Servidor PICP. V2. Velocidad 9600 baudios
+picp=[[0x0000, 0x0000, 0x118A, 0x120A, 0x2997, 0x0000, 0x218D, 0x3067, 0x1683, 0x0086, 0x1283, 0x0186, 0x2174, 0x2187, 0x1283, 0x1303, 0x00B5],[0x0010, 0x3A41, 0x1903, 0x2842, 0x0835, 0x3A42, 0x1903, 0x2840, 0x0835, 0x3A43, 0x1903, 0x2846, 0x0835, 0x3A44, 0x1903, 0x283E, 0x0835],[0x0020, 0x3A49, 0x1903, 0x283A, 0x0835, 0x3A4A, 0x1903, 0x284A, 0x0835, 0x3A50, 0x1903, 0x2838, 0x0835, 0x3A52, 0x1903, 0x2844, 0x0835],[0x0030, 0x3A54, 0x1903, 0x283C, 0x0835, 0x3A57, 0x1903, 0x2848, 0x280C, 0x20E2, 0x280C, 0x20D9, 0x280C, 0x20CD, 0x280C, 0x20BA, 0x280C],[0x0040, 0x20B5, 0x280C, 0x20B0, 0x280C, 0x20A2, 0x280C, 0x2099, 0x280C, 0x2084, 0x280C, 0x204D, 0x280C, 0x0008, 0x2187, 0x1283, 0x1303],[0x0050, 0x00B2, 0x2187, 0x1283, 0x1303, 0x00B3, 0x3000, 0x0433, 0x1903, 0x285C, 0x3001, 0x00B4, 0x285D, 0x01B4, 0x3000, 0x0434, 0x1903],[0x0060, 0x286F, 0x30FF, 0x00B4, 0x3006, 0x2110, 0x1283, 0x1303, 0x0BB4, 0x2863, 0x3006, 0x2110, 0x1283, 0x1303, 0x03B3, 0x2855, 0x3000],[0x0070, 0x0432, 0x1903,
  0x2876, 0x3001, 0x00B3, 0x2877, 0x01B3, 0x3000, 0x0433, 0x1903, 0x2881, 0x3006, 0x2110, 0x1283, 0x1303, 0x03B2],[0x0080, 0x286F, 0x304A, 0x2179, 0x0008, 0x2187, 0x1283, 0x1303, 0x00B0, 0x2187, 0x1283, 0x1303, 0x00B1, 0x3002, 0x2110, 0x1283, 0x1303],[0x0090, 0x0830, 0x00FF, 0x0831, 0x20FA, 0x3008, 0x2110, 0x3057, 0x2179, 0x0008, 0x3000, 0x2110, 0x3000, 0x00FF, 0x3000, 0x20FA, 0x3043],[0x00A0, 0x2179, 0x0008, 0x3004, 0x2110, 0x20E5, 0x3052, 0x2179, 0x1283, 0x1303, 0x0820, 0x2179, 0x1283, 0x1303, 0x0821, 0x2179, 0x0008],[0x00B0, 0x3006, 0x2110, 0x3041, 0x2179, 0x0008, 0x3008, 0x2110, 0x3042, 0x2179, 0x0008, 0x2187, 0x1283, 0x1303, 0x00AE, 0x2187, 0x1283],[0x00C0, 0x1303, 0x00AF, 0x3002, 0x2110, 0x1283, 0x1303, 0x082E, 0x00FF, 0x082F, 0x20FA, 0x3044, 0x2179, 0x0008, 0x3010, 0x1283, 0x1303],[0x00D0, 0x0086, 0x3002, 0x2161, 0x1283, 0x1303, 0x0186, 0x3054, 0x2179, 0x0008, 0x3049, 0x2179, 0x3040, 0x2179, 0x3030, 0x2179, 0x3012],[0x00E0, 0x2179, 0x0008, 0x304F, 0x2179, 0x0008, 0x168
 3, 0x1303, 0x1786, 0x3001, 0x2127, 0x3008, 0x2127, 0x00A0, 0x3007, 0x2127, 0x00A1],[0x00F0, 0x1003, 0x0C21, 0x00AD, 0x303F, 0x052D, 0x00A1, 0x1683, 0x1303, 0x0186, 0x0008, 0x1283, 0x1303, 0x00AB, 0x087F, 0x00AC, 0x3001],[0x0100, 0x00FF, 0x3000, 0x2144, 0x3008, 0x00FF, 0x1283, 0x1303, 0x082C, 0x2144, 0x3007, 0x00FF, 0x1283, 0x1303, 0x082B, 0x2144, 0x0008],[0x0110, 0x1283, 0x1303, 0x00AA, 0x30F0, 0x1283, 0x1303, 0x0586, 0x3006, 0x00FF, 0x1283, 0x1303, 0x082A, 0x2144, 0x1283, 0x1303, 0x1786],[0x0120, 0x30FF, 0x0085, 0x0185, 0x30FF, 0x0085, 0x0185, 0x0008, 0x1283, 0x1303, 0x00A7, 0x01A8, 0x01A9, 0x0827, 0x0229, 0x1803, 0x2942],[0x0130, 0x1003, 0x0CA8, 0x1283, 0x1303, 0x1586, 0x30F0, 0x0586, 0x1B86, 0x293D, 0x1283, 0x1303, 0x13A8, 0x2940, 0x1283, 0x1303, 0x17A8],[0x0140, 0x0AA9, 0x292C, 0x0828, 0x0008, 0x1283, 0x1303, 0x00A4, 0x087F, 0x00A5, 0x01A6, 0x0825, 0x0226, 0x1803, 0x2960, 0x1824, 0x2954],[0x0150, 0x1283, 0x1303, 0x1386, 0x2957, 0x1283, 0x1303, 0x1786, 0x1586, 0x30F0, 0x0
 586, 0x1003, 0x1283, 0x1303, 0x0CA4, 0x0AA6, 0x294A],[0x0160, 0x0008, 0x1283, 0x1303, 0x00A3, 0x3000, 0x0423, 0x1903, 0x2973, 0x303D, 0x1283, 0x1303, 0x0081, 0x110B, 0x1D0B, 0x296D, 0x1283],[0x0170, 0x1303, 0x03A3, 0x2964, 0x0008, 0x3087, 0x1683, 0x1303, 0x0081, 0x0008, 0x1283, 0x1303, 0x00A2, 0x1283, 0x1303, 0x1E0C, 0x297C],[0x0180, 0x1283, 0x1303, 0x0822, 0x1283, 0x1303, 0x0099, 0x0008, 0x1283, 0x1303, 0x1E8C, 0x2987, 0x081A, 0x0008, 0x3081, 0x1683, 0x1303],[0x0190, 0x0099, 0x3024, 0x0098, 0x3090, 0x1283, 0x0098, 0x0008, 0x118A, 0x120A, 0x2805],]
diff --git a/chronopic-firmware/pydownloader-chronopic/libIris/Pic16_Firmware.pyc b/chronopic-firmware/pydownloader-chronopic/libIris/Pic16_Firmware.pyc
new file mode 100644
index 0000000..97bbf14
Binary files /dev/null and b/chronopic-firmware/pydownloader-chronopic/libIris/Pic16_Firmware.pyc differ
diff --git a/chronopic-firmware/pydownloader-chronopic/libIris/__init__.py b/chronopic-firmware/pydownloader-chronopic/libIris/__init__.py
new file mode 100644
index 0000000..589feb1
--- /dev/null
+++ b/chronopic-firmware/pydownloader-chronopic/libIris/__init__.py
@@ -0,0 +1,51 @@
+#! /usr/bin/python
+# -*- coding: iso-8859-15 -*-
+
+#-- Paqute LibIris
+
+
+# Description: File downloader library for SkyPIC
+# Copyright (C) 2007 by Rafael Treviño Menéndez
+# Author: Rafael Treviño Menéndez <skasi 7 gmail com>
+#         Juan Gonzalez <juan iearobotics com>
+
+# 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.
+
+""" 
+  Paquete LibIris: Descarga de programas en la tarjeta skypic
+
+Este paquete esta formado por tres modulos:
+
+  * IntelHex        : Lectura de ficheros en formato .hex de Intel
+  * Pic16_Bootloader: Descarga de ficheros a traves del bootloader
+  * Pic16_Firmware  : Programas para el PIC16F876A. Incluye los servidores
+                      del proyecto stargate y programas de prubas, como el 
+                      ledp
+                      
+Incluye ademas las siguientes utilidades:
+
+  * hex-view  :  Visualizacion de ficheros .hex
+  * hex2python:  Convertir un fichero .hex a un script en python que contiene
+                 el codigo maquina en una lista
+  * skypic-test: Prueba de descargas en la skypic. Se graba el programama del
+                 ledp. Permite comprobar si la skypic esta funcionando
+                 correctamente
+
+
+"""
+
+#-- Version de la libIris
+VERSION = 1.2
+print "Chronopic version!"
diff --git a/chronopic-firmware/pydownloader-chronopic/libIris/__init__.pyc b/chronopic-firmware/pydownloader-chronopic/libIris/__init__.pyc
new file mode 100644
index 0000000..0732741
Binary files /dev/null and b/chronopic-firmware/pydownloader-chronopic/libIris/__init__.pyc differ
diff --git a/chronopic-firmware/pydownloader-chronopic/libIris/__init__.py~ b/chronopic-firmware/pydownloader-chronopic/libIris/__init__.py~
new file mode 100644
index 0000000..aad0dc3
--- /dev/null
+++ b/chronopic-firmware/pydownloader-chronopic/libIris/__init__.py~
@@ -0,0 +1,51 @@
+#! /usr/bin/python
+# -*- coding: iso-8859-15 -*-
+
+#-- Paqute LibIris
+
+
+# Description: File downloader library for SkyPIC
+# Copyright (C) 2007 by Rafael Treviño Menéndez
+# Author: Rafael Treviño Menéndez <skasi 7 gmail com>
+#         Juan Gonzalez <juan iearobotics com>
+
+# 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.
+
+""" 
+  Paquete LibIris: Descarga de programas en la tarjeta skypic
+
+Este paquete esta formado por tres modulos:
+
+  * IntelHex        : Lectura de ficheros en formato .hex de Intel
+  * Pic16_Bootloader: Descarga de ficheros a traves del bootloader
+  * Pic16_Firmware  : Programas para el PIC16F876A. Incluye los servidores
+                      del proyecto stargate y programas de prubas, como el 
+                      ledp
+                      
+Incluye ademas las siguientes utilidades:
+
+  * hex-view  :  Visualizacion de ficheros .hex
+  * hex2python:  Convertir un fichero .hex a un script en python que contiene
+                 el codigo maquina en una lista
+  * skypic-test: Prueba de descargas en la skypic. Se graba el programama del
+                 ledp. Permite comprobar si la skypic esta funcionando
+                 correctamente
+
+
+"""
+
+#-- Version de la libIris
+VERSION = 1.2
+print "hola!"
diff --git a/chronopic-firmware/pydownloader-chronopic/pydownloader-wx.py b/chronopic-firmware/pydownloader-chronopic/pydownloader-wx.py
new file mode 100755
index 0000000..043607c
--- /dev/null
+++ b/chronopic-firmware/pydownloader-chronopic/pydownloader-wx.py
@@ -0,0 +1,443 @@
+#!/usr/bin/env python
+# -*- 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
+sys.path = ['..'] + sys.path
+
+
+#---------------------------
+#-- 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_4_staticbox = wx.StaticBox(self.panel_1, -1, "Firmware Chronopic")
+        self.frame_1_statusbar = self.CreateStatusBar(1, 0)
+        self.text_ctrl_2 = wx.TextCtrl(self.panel_1, -1, "")
+        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.__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)
+        # 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("PyDownloader")
+        self.frame_1_statusbar.SetStatusWidths([-1])
+        # statusbar fields
+        frame_1_statusbar_fields = ["Change / Cambiar Chronopic firmware"]
+        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((250, 27))
+        self.combo_box_1.SetMinSize((250,30))
+        # 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_4_copy = wx.StaticBoxSizer(self.sizer_4_copy_staticbox, wx.HORIZONTAL)
+        sizer_4 = wx.StaticBoxSizer(self.sizer_4_staticbox, wx.HORIZONTAL)
+        sizer_4.Add(self.text_ctrl_2, 0, wx.TOP|wx.BOTTOM|wx.EXPAND|wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL, 5)
+        sizer_4.Add(self.button_2, 0, wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0)
+        sizer_3.Add(sizer_4, 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, 0)
+        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>
+       
+        #-- Abrir un dialogo de busqueda de ficheros
+        filechooser = wx.FileDialog(self,wildcard = "*.hex;*.HEX")
+        
+        #-- Esperar a que el usuario seleccione el fichero
+        opcion = filechooser.ShowModal()
+        
+        #-- 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..."
+        
+        
+    #-----------------------------------------------------------------
+    #-- 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_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))
+      
+      #-- 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 []
+
+
+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()



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]