Just a little bit freak

sábado, 4 de mayo de 2013

El SDK del IGEPv2


Continuando con el articulo que escribí hace ya un tiempo sobre el IGEPv2, voy a explicar los pasos necesarios para crear tu propio SDK para esta plataforma embedded.


El proyecto Yocto

Generar un SDK desde cero no es una tarea sencilla, en absoluto. Para hacer la tarea de forma sencilla, nos vamos a ayudar de la meta-distribución Yocto Poky distribuida por ISEE y personalizada para su plataforma IGEPv2.




Yocto Poky esta basada en la herramienta bitbake, herramienta que hace uso de unos ficheros de recipes (reglas) preparadas para hacer tareas complejas. Entre sus reglas, podemos encontrar una que nos permite generar el SDK para la plataforma IGEPv2. Veremos que el proceso para generar este SDK es muy sencillo (aunque costoso computacionalmente).


Dependencias previas

Vamos a realizar la compilación del SDK para el IGEPv2 usando un PC host con la distribución Ubuntu 12.04 LTS instalada. Es necesario instalar estos paquetes antes de empezar el proceso:

    $ sudo apt-get install diffstat
    $ sudo apt-get install texi2html
    $ sudo apt-get install texinfo
    $ sudo apt-get install gawk
    $ sudo apt-get install chrpath
    $ sudo apt-get install gnupg
    $ sudo apt-get install libcurl3
    $ sudo apt-get install libcurl3-gnutls
    $ sudo apt-get install python-pycurl


Si usáis otra distribución distinta, puede que falten, o puede que sobren paquetes.


Generación del SDK

El primer paso es clonar Poky del repositorio git de ISEE.

    $ git clone -b denzil git://git.isee.biz/pub/scm/poky.git
    Initialized empty Git repository in /mnt/data/gatchets/IGEPv2/poky/.git/
    remote: Counting objects: 62407, done.
    remote: Compressing objects: 100% (19827/19827), done.
    remote: Total 62407 (delta 41254), reused 61256 (delta 40311)
    Receiving objects: 100% (62407/62407), 38.81 MiB | 318 KiB/s, done.
    Resolving deltas: 100% (41254/41254), done.


El paso anterior debe haber generado dentro de tu directorio local un directorio llamado "poky".

Descargar el layer de ISEE del repositorio git:

    $ cd poky
    $ git clone -b denzil git://git.isee.biz/pub/scm/meta-isee.git

A continuación modifica el contenido del fichero build/conf/bblayers.conf. Debería contener esta información (falta añadir el layer meta-isee)

    $ cat build/conf/bblayers.conf

    Code: Select all
    # LAYER_CONF_VERSION is increased each time build/conf/bblayers.conf
    # changes incompatibly
    LCONF_VERSION = "4"

    BBFILES ?= ""
    BBLAYERS ?= " \
      /path/to/poky/meta \
      /path/to/poky/meta-yocto \
      /path/to/poky/meta-isee \
      "

Editar el fichero build/conf/local.conf (que ya debe existir, no deberías crearlo a mano) y cambia la variable MACHINE para que ponga esto:

    MACHINE ??= "igep00x0"

Configura el entorno de bitbake:

    $ source oe-init-build-env

Al hacer un source del fichero anterior, en realidad estas provocando  cambios en la variable de entorno PATH y estableciendo otras variables de entorno que usa la herramienta bitbake para hacer su trabajo.

Ahora ya puedes lanzar el comando que genera el SDK:

    $ bitbake meta-toolchain-sdk

Y tener mucha paciencia [...] Este proceso tarda unas cuantas horas. En mi PC, un Intel Core i3, con 4GB de RAM, han sido casi 16 horas de compilación.

Cuando el proceso termine, el SDK queda listo en este path:

    poky/build/tmp/deploy/sdk/igep-sdk-yocto-toolchain-1.2.1-2.tar.bz2


Instalación del SDK

Una vez generado el SDK, hay que instalarlo en tu sistema host. Para hacerlo, sigue estos pasos:

    $ cd poky/build/tmp/deploy/sdk
    $ sudo -s
    $ tar xvfj igep-sdk-yocto-toolchain-1.2.1-1.tar.bz2 -C /

El comando anterior desplegará todo el SDK del IGEPv2 dentro del directorio:

    /opt/poky/1.2/

No cambies ese directorio, ya que ese path esta hardcoded dentro de los binarios del SDK, y si cambias a un path diferente, no te funcionará correctamente.


Uso del SDK

Para configurar el entorno para compilar binarios para esta plataforma, basta con ejecutar este script:

    $ . /opt/poky/1.2/environment-setup-armv7a-vfp-neon-poky-linux-gnueabi

Fijate en el punto '.' antes del path, es necesario para que los cambios que se hacen en el entorno queden ahi cuando el script termine de ejecutarse.

Ahora ya tienes disponibles en tu path los compiladores cruzados para tu nueva plataforma ARM:

    $ arm-poky-linux-gnueabi-gcc --version
    arm-poky-linux-gnueabi-gcc (GCC) 4.6.4 20120303 (prerelease)
    Copyright (C) 2011 Free Software Foundation, Inc.
    This is free software; see the source for copying conditions.  There is NO
    warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

    $ arm-poky-linux-gnueabi-g++ --version
    arm-poky-linux-gnueabi-g++ (GCC) 4.6.4 20120303 (prerelease)
    Copyright (C) 2011 Free Software Foundation, Inc.
    This is free software; see the source for copying conditions.  There is NO
    warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

A partir de este momento ya puedes usar el SDK del ARM de forma análoga a como usarías el SDK de tu PC host nativo.

Además de usar las herramientas cruzadas (cross-compilador, cross-linker, etc.) has de tener en cuenta que debes cambiar el SDK_PREFIX para que apunte al directorio raíz del SDK recién instalado. ¿Que significa esto? Pues que cuando compilas en tu PC host, el SDK_PREFIX siempre es este:

    SDK_PREFIX="/"

En realidad, ni siquiera se define, ya que tus ficheros de header estan en /usr/include y tus librerías en /usr/lib. Sin embargo, cuando usas un SDK cruzado, el SDK_PREFIX ya no es "/", debe cambiar para apuntar al nuevo directorio, en nuestro caso:

    SDK_PREFIX=/opt/poky/1.2.1/sysroots/armv7a-vfp-neon-poky-linux-gnueabi/

Esto es así porque los headers de compilación para tu plataforma ARM no estan en /usr/include, sino que están en $SDK_PREFIX/usr/include. Y las librerías de linkado para tu plataforma ARM no estan en /usr/lib, sino que están en $SDK_PREFIX/usr/lib.

Teniendo esto en cuenta, compilar un proyecto para ARM es tan simple como hacerlo para la máquina nativa.


Trabajo pendiente

Veremos mas adelante como usar el SDK que acabamos de construir para compilar el binario del x-loader (MLO), la imagen del kernel de Linux (zImage), y un target filesystem con el que vamos a arrancar la placa.

miércoles, 20 de febrero de 2013

Diseño de bases de datos relacionales

Hacía ya tiempo que no publicaba nada en este blog. No es por falta de ganas, queridos lectores, os lo aseguro, ni tampoco por falta de ideas (tengo unos cuantos temas pendientes). Es lo de siempre: la falta de tiempo libre. Quien me mandaría a mi emanciparme... ¡¡Con lo bien que estaba yo en casa de mis padres!! :)

Con la llegada del frio invernal, esta semana pasada me decidí a escribir un pequeño articulo para recordar el proceso de normalización del diseño lógico de una base de datos hasta la tercera forma normal (3FN).

Tras publicar una primera versión (quizá alguno de vosotros ya lo leyó, ansiosos, que soys unos ansiosos!! jejeje), en realidad no me gustó mucho el resultado: contenía demasiada información inconexa, y carente del hilo conductor que a mi me gusta seguir para explicar bien las cosas, para que se entiendan.

Así que me puse a revisarlo hasta redactarlo casi por completo. Hoy lo he vuelto a leer y ahora si que está como a mi me gusta. No obstante, el articulo se extendía bastante y he tenido que esquivar distintos temas que han ido apareciendo a lo largo del documento, que darían para escribir bastantes páginas mas sobre esta materia. Quizás para otra ocasión.

Si alguien tiene interés en profundizar en algún tema que dejo apartado, que se ponga en contacto conmigo y así tendremos motivación adicional para escribir el próximo articulo. Espero que os guste.


¿Que es una base de datos?

Una base de datos (BD en adelante) es un almacén de datos de distintos tipos interrelacionados, ordenados adecuadamente, y que generalmente pertenecen a una empresa u organización. Habitualmente se representa con este símbolo

¿Que es un sistema gestor de base de datos?


Cada persona del mundo se podría inventar su propio método para organizar internamente una BD de creación propia: ficheros organizados por registros, una  hoja de cálculo, hojas de papel indexadas alfabéticamente, cuaderno de notas, ... Pero ninguno es lo suficientemente eficiente como para manejar volúmenes de información grandes.

Cuando se habla de manejar miles de millones de registrosinteresa que el acceso a la información se pueda automatizar desde un sistema informático que permita el acceso a la información se realice de manera rápida y eficiente. Para eso se crearon los SISTEMAS GESTORES DE BASES DE DATOS (SGBD).

El SGBD es la pieza de software a través de la cual se realizan todas las operaciones sobre la BD, actuando como un interfaz entre la BD y nuestra aplicación. Las operaciones permitidas son:

  • Consultas para buscar información
  • Inserciones de nuevos datos
  • Borrado de datos
  • Actualizaciones de los datos existentes.
Internamente, los datos se almacenan en uno o varios  discos, y en uno o varios ficheros. Pero el usuario percibe que todos los datos se encuentran en un mismo lugar, y accede a ellos mediante sentencias específicas que él y el SGBD comprenden.

Los SGBD también se encargan de otras tareas como mantener la seguridad de la información almacenada (tanto por caídas del sistema como por accesos no autorizados), o compartir la información entre varios usuarios,  evitando resultados anómalos debidos a los accesos concurrentes.


¿Que es un sistema de información?

Un sistema de información es un conjunto de elementos hardware, software y humanos, orientados al almacenamiento, tratamiento, y explotación de datos e información, organizados y listos para su uso posterior, generados para cubrir una necesidad u objetivo.

Un sistema de información se compone de varios elementos:
  • Usuarios
  • Telecomunicaciones (redes LAN, WAN)
  • Elementos software (aplicación, BD, SGBD, sistema operativo, ...)
  • Elementos hardware (servidores, routers, terminales, TPV, ...)
Como vemos, la BD y el SGBD son dos de los elementos software que componen un sistema de información.

Para desarrollar un sistema de información completo, se siguen varias fases:
  • Estudio de la viabilidad
  • Recogida y análisis de los requisitos
  • Diseño
  • Creación de prototipos
  • Desarrollo
  • Implantación
  • Validación
  • Prueba
  • Operación
En concreto, la fase de diseño de un sistema de información (la que nos ocupa en este documento), se divide a su vez en:
  • Diseño de la BD
  • Diseño de la aplicación
La BD debe ser independiente de la aplicación que la usa. Por tanto, no se debe diseñar la BD pensando en almacenar los datos en un formato determinado que le venga bien a la aplicación. Este error es bastante típico cuando el diseñador y el programador de la aplicación, son la misma persona, y cuando lo hace, es por comodidad, pero sobre todo por falta de conocimiento.


Diseño de la base de datos

Vamos a profundizar en el diseño de la BD. El diseño de la BD, consta de 3 etapas:
  • Diseño conceptual
  • Diseño lógico
  • Diseño físico
El diseño conceptual de la BD se realiza a partir de los requisitos del cliente, y genera como salida un ESQUEMA CONCEPTUAL, basado en el modelo entidad-relación. Este esquema conceptual es independiente del SGBD seleccionado (por tanto, el mismo para todos ellos). Esta pensado para que sea comprensible para cualquier persona que tenga relación con el proyecto, incluso sin que tenga conocimientos de programación. 

El diseño lógico de la BD se realiza a partir del esquema conceptual, y genera como salida un ESQUEMA LÓGICO. Todos los SGBD de un mismo tipo utilizan el mismo diseño lógico. En este documento vamos a centrarnos en los SGBD relacionales (ver de que se trata esto del modelo relacional, mas adelante). Por tanto, nos sirve para PostgreSQL, MySQL, Oracle, Access, SQLServer, etc.

El diseño físico de la BD se realiza a partir del esquema lógico, y genera como salida un ESQUEMA FISICO. El esquema físico ya es dependiente del SGBD elegido para implementar la DB. Por tanto, un esquema físico de Oracle no es compatible con un esquema físico de PostgreSQL, por poner un ejemplo.

En este documento no hablaremos de diseño conceptual ni tampoco de diseño físico. Ambos escapan del objetivo de este post. Quizás para otra ocasión.


Diseño lógico de la base de datos

Continuamos centrando el objetivo de este documento, entrando en mas detalles del diseño lógico de la BD.

El esquema lógico generado durante la fase de diseño lógico de la BD se representa con un LENGUAJE DE MODELADO. Antes de continuar, vamos a aclarar que es esto de un modelo, y para que sirve.

El mundo real es demasiado complejo, tiene demasiados detalles en los que nos podemos fijar. Para poder representar objetos del mundo real en un modelo, es preciso simplificar la realidad y captar solo aquellos detalles que sean de interés para el modelo en cuestión que deseamos realizar. Es lo que se conoce como modelar la realidad.

Pondremos un símil con el mundo de la especulación inmobiliaria, hoy en día tan de moda y en boca de todos. Un arquitecto hace (en realidad, hacía en la época de bonanza, ya no) varios planos de un edificio antes de que los albañiles empiecen a tirar cemento: plano de las habitaciones de cada vivienda, de los esquemas eléctricos, de los conductos de ventilación, del parking, etc. Cada uno de esos planos es un modelo distinto del edificio construido.

Como diseñadores de la BD, una de las tareas que tendremos que realizar es 
modelar el esquema lógico de la BD. Para hacer esta tarea, existen distintos lenguajes de modelado:
  • Modelo jerárquico: relaciones padre-hijo
  • Modelo en red: los hijos pueden tener varios padres
  • Modelo relacional: utiliza tablas y relaciones entre ellas
  • Modelo orientado a objetos: utiliza objetos y mensajes
  • Modelo semántico: utiliza descripciones semánticas de la información.
  • Modelo deductivo: utiliza axiomas deductivos y reglas de inferencia.
En este documento vamos a hablar exclusivamente del modelo relacional. Como ejemplos de SGBD relacionales tenemos PostgreSQL, Oracle, MySQL, SQLite, SQLServer, Access, etc.

El modelo relacional

El modelo relacional fue definido por un investigador de IBM, el científico informático Ingles, Edgar Frank Codd, en 1970, quien también desarrolló el sistema de normalización que estudiaremos después.



Probablemente, si has leído hasta este punto del documento es porque ya tenías alguna idea sobre el modelo relacional, y te suenan conceptos como relación, tupla, clave o atributo. De todas formas, como el resto del documento esta basado en estos conceptos, los vamos a definir formalmente, para que no quede ninguna duda:

Un modelo de datos relacional esta formada por un conjunto de RELACIONES R1, R2, ..., Rn, que se representan gráficamente como TABLAS.

La relación Ri esta formada por un conjunto de FILAS, TUPLAS o ENTIDADES, que se corresponden con las INSTANCIAS de la relación.

Se define CARDINALIDAD como el numero de instancias (filas) de una relación en un momento dado.

Cada relación R tiene un conjunto de ATRIBUTOS, COLUMNAS o CAMPOS, A1, A2, ..., Am. Se representan como R(A1, A2, ..., Am).

Llamamos NULO al valor de un atributo para el que no tenemos un valor. Indica un valor que no existe, o que es desconocido.

Llamamos GRADO al número de atributos de una relación.

Llamamos DOMINIO de un atributo, al conjunto de valores válidos que puede tomar ese atributo.

Veamos lo anterior con un ejemplo:

    RELACION_ALUMNOS
    Codigo      DNI         Apellido1       Apellido2   Nombre
    21313       26767671X   Martinez        Romero      Ronnie
    3910        26143413V   Lopez           Garcia      Ilsed
    19423       26913493A   Sanchez         Pons        Spyros


La relación alumnos tiene una cardinalidad 3 (3 filas), un grado 5 (5 columnas), y el dominio del atributo Nombre (por poner un ejemplo) son los strings de 32 bytes.


Claves primarias y ajenas

Muchas de las propiedades del modelo relacional se fundamentan en la definición matemática de Conjunto. Un CONJUNTO es una colección desordenada de elementos distintos del mismo tipo. Una relación es por tanto un Conjunto de tuplas. Luego no puede haber dos tuplas iguales, todas las tuplas son por tanto distintas. Además, no se asume ningún orden dentro de un conjunto.

Como las tuplas no están ordenadas, no se puede hacer referencia a una tupla por su posición dentro de la relación. El modo de hacer referencia a las tuplas es a través de las claves primarias. Pero, ¿que es esto de una clave primaria? Veamos algunas definiciones mas:

Llamamos CLAVE de una tupla a aquellos atributos que identifican de forma única a las entidades de una relación. Existen varios tipos de claves:
  • SUPERCLAVE. Cualquier subconjunto de atributos que identifiquen de forma única a las tuplas de una entidad. Por tanto, el conjunto de todos los atributos de una relación es una superclave de esa relación.
  • CLAVE CANDIDATA.Es el menor subconjunto de atributos de una superclave que sigue siendo un identificador único. Si a una clave candidata le quitamos un atributo, deja de ser clave candidata. Notar que en una relación puede haber varias claves candidatas, cada una de ellas con un numero distinto de atributos.
  • CLAVE PRIMARIA (PK). La clave primaria es la clave candidata que el diseñador elige para identificar a las tuplas de una relación.
  • CLAVE AJENA (FK). Es el conjunto de atributos de una relación R2 cuyos valores son completamente NULOS o coinciden completamente con los de la clave primaria de una relación R1. Se dice que la clave ajena de una tupla referencia a la tupla donde se define el valor correspondiente de la clave primaria.
Como las claves son conjuntos de atributos, las vamos a representar con la notación de conjuntos {...}

Diremos que R1 y R2 son dos RELACIONES INTERRELACIONADAS si R1 tiene una clave ajena que apunta a la clave primaria de R2. Por tanto, no confundir el concepto de relación (tabla) con el de interrelación (claves ajena apuntando a clave primaria).


Reglas de integridad

Las claves primarias y ajenas deben cumplir una serie de propiedades que permiten mantener la integridad de la BD, es decir, permiten asegurar que los valores de sus atributos se ajustan a los valores del mundo real modelado.
  • La INTEGRIDAD DE ENTIDAD. Ningún de los atributos que componen una clave primaria puede aceptar valores NULOS, ya que la clave primaria debe identificar a cada tupla de la relación. 
  • La INTEGRIDAD REFERENCIAL. Las claves ajenas no pueden contener valores que no coincidan exactamente con alguna clave primaria, a menos que todos sus atributos sean NULOS.

Los atributos que no pertenecen a las claves, también deben cumplir una serie de propiedades. En este caso, solo deben aceptar valores de su DOMINIO. Esto implica que no todos los posibles valores de un atributo tienen sentido. Por ejemplo, la edad de las personas no puede ser negativa.
 
Las reglas de integridad deben ser propiedad de la BD, no de la aplicación. Por tanto, no se deben controlar estas restricciones desde la propia aplicación. Con esto evitaremos problemas graves con inserciones, actualizaciones o borrados realizados desde fuera de la propia aplicación (inconsistencias, etc.).


Normalización de relaciones

La teoría de normalización, desarrollada por Codd en 1972, se fundamenta en una serie de formas normales (FN)Inicialmente Codd definió 3 formas normales: 1FN, 2FN y 3FN. Aunque mas tarde se han incluido otras (FNBC, 4FN y 5FN). 

Cada una de las distintas FN exige que se cumplan una serie de condiciones distintas sobre todas las relaciones del modelo. Todas las FN se incluyen en una jerarquía, de forma que una relación que esta en iFN, también está en (i-1)FN. Por ejemplo, una relación en 2FN también esta en 1FN. Aunque no se cumple la inversa, por tanto, una relación en 1FN no tiene por que estar en 2FN (aunque podría estarlo).

El proceso de normalización es un proceso mecánico que, siguiendo unas reglas que definiremos a continuación, reemplaza un conjunto inicial de relaciones por otro conjunto final de relaciones, equivalente (mismos atributos, mismas tuplas y mismas dependencias), pero con una estructura mas simple

Como resultado de aplicar el proceso de normalización, se obtiene una BD equivalente y con numerosas ventajas:
  • optimiza el espacio de almacenamiento
  • elimina las redundancias de datos 
  • al eliminar redundancias, se evitan inconsistencias
  • mejora la independencia de los datos
  • elimina problemas en operaciones de inserción, actualización y borrado
La redundancia de datos es mala porque nos hace desperdiciar espacio en disco, lo que influye en un mayor coste (€/byte), y en un incremento del tiempo de acceso (seg/byte). Ademas, la redundancia crea problemas de mantenimiento. La operación de actualización de los datos redundantes se debe hacer de la misma forma exactamente en todas las ubicaciones del dato redundante, o pronto aparecerán las primeras inconsistencias de datos.

Y llegados a este punto,
por fin encontramos el objetivo con el que inicié la escritura de este post: explicar los pasos que debes realizar para normalizar un diseño lógico hasta su tercera forma normal (3FN). Todo lo que hemos explicado hasta este momento era necesario para centrar el objetivo de este post.


La primera forma normal 1FN

Una relación esta en 1FN si y solo si todos sus atributos son atómicos.

Se habla de atomicidad en el sentido de "indivisible". Cada atributo debe contener un único valor de su dominio, en el sentido semántico, de modo que la descomposición de un dato atómico produce una pérdida de significado.

Un ejemplo tipico que incumple la primera forma normal 1FN es cuando en un campo de texto metemos varios valores del mismo dominio, como por ejemplo 3 números de teléfono.

    TABLA CLIENTES
    IDCliente       Nombre      Telefono
    45              Francisco   444444444
    275             Miguel      555555555,666666666,777777777


Una variante del caso anterior, también incorrecta, consiste en separar los campos de la lista de teléfonos en varias columnas. En el ejemplo anterior, sería tener el campo telefono1, telefono2, .... y asi. Este fallo de diseño es incluso peor que el anterior, pues habrá muchos campos nulos y en el caso de necesitar mas, tendríamos que redimensionar la tabla con un nuevo campo (telefono3).

    TABLA_CLIENTES
    IDCliente       Nombre      Telefono1       Telefono2       Telefono3
    45              Francisco   444444444       NULL            NULL
    275             Miguel      555555555       666666666       777777777


¿Como se resuelve? La regla dice lo siguiente:

    R(A,B,C,V) tal que PK(A,B) y el atributo V viola 1FN

Se obtienen dos relaciones:

    R1(A,B,C), PK(A,B)
    R2(A,B,V), PK(A,B), FK(A,B) references R1


Aplicando la regla anterior, se obtienen dos relaciones:

    TABLA_CLIENTES
    IDCliente       Nombre
    45              Francisco
    275             Miguel


    TABLA_TELEFONOS_CLIENTE
    IDCliente       Telefono
    45              444444444
    275             555555555
    275             666666666



Dependencia funcional entre atributos

Antes de continuar con 2FN y 3FN necesitamos introducir el concepto de DEPENDENCIA FUNCIONAL entre los atributos de una relación.

Los atributos de una relación los elegimos nosotros como diseñadores de la BD. Pero las dependencias entre atributos no es sencillo identificarlas, ya que requiere un analisis de las interrelaciones entre atributos, y la intuición a veces no es suficiente para encontrar y clasificar todas las dependencias (en ocasiones la BD modela conocimiento que escapa a nuestra inteligencia, o incluso peor, al sentido común).

Estas dependencias son consecuencia de los objetos del mundo real que describen las relaciones, y no de los valores actualmente almacenados en la relación. Por tanto, si tenemos una relación de vehiculos como la siguiente:

    TABLA_VEHICULOS
    Modelo          Cilindrada   Color
    Seat Leon       1900         Rojo
    Citroen XZ      1900         Rojo
    Suzuki Vitara   1900         Rojo


y en un momento dado, todos los coches de 1900cc son de color rojo, no podemos afirmar que existe una dependencia entre los atributos Color y Cilindrada, ya que se trata de un hecho casual. Por tanto, para buscar dependencias funcionales, no se deben analizar los datos de la relación, sino las entidades abstractas a los que se refieren esos datos.

Las dependencias funcionales se pueden dar entre atributos o entre subconjuntos de atributos. De forma genérica, siendo {X} e {Y} dos subconjuntos de atributos de una relación, diremos que {Y} tiene una dependencia funcional de {X}, o que {X} determina a {Y}, si cada valor de {X} siempre tiene asociado el mismo valor de {Y}.

La dependencia funcional se representa como {X} ---> {Y}

El hecho de que {X} determine a {Y} no quiere decir que conociendo {X} sabemos el valor de {Y}, sino que en la relación indicada, cada vez que {X} tome un valor determinado, {Y} en la misma fila tomara siempre el mismo valor.

Por ejemplo, si tenemos una relación clientes como la siguiente:

    TABLA_CLIENTES
    Dni                 Nombre              Edad
    40145496H           Sergio Garcia       26
    18817495B           Ania Rodriguez      48
    33133473H           Hulk Hogan          48


podemos afirmar que {Dni} determina a {Nombre}, puesto que cada vez que {Dni} tome un valor determinado, el {Nombre} en la misma fila tomara siempre el mismo valor. Sin embargo, no podemos decir que {Edad} determine a {Dni}, puesto que para un mismo valor de {Edad}, (48 años), dos {Dni} diferentes.

Diremos que la dependencia funcional {X} ---> {Y} es completa si {Y} depente de todos los atributos de {X}, no de ningún subconjunto de {X}.

Las dependencias funcionales son restricciones de integridad sobre los datos. Conocer las dependencias funcionales en el momento del diseño de la base de datos permite crear mecanismos para evitar la redundancia (y los potenciales problemas de integridad que eso conlleva) y mejorar la eficiencia.


La segunda forma normal 2FN

Una relación esta en 2FN si esta en 1FN y todos los atributos que no forman parte de la clave candidata dependen completamente de la clave candidata (y no de un subconjunto de esta). Dicho de forma simple, los atributos que no aporten información directa sobre la clave primaria, deben almacenarse en una relación separada. 

Veamos un ejemplo que no está en 2FN:

    TABLA_LINEAS_PEDIDO
    IDCliente   IDProducto      Cantidad        Nombre_producto
    29          42              1               Zapatillas deportivas de tenis
    29          10              2               Zapatillas deportivas de rubgy
    46          9               5               Balón reglamentario de baloncesto
    204         42              1               Zapatillas deportivas de tenis
    144         10              1               Zapatillas deportivas de rugby


En la tabla de lineas de pedido, la única clave candidata es la formada por los atributos [IDCliente,IDProducto].

El campo Cantidad es totalmente dependiente de la clave candidata, puesto que cada cliente compra de un producto una cantidad dada. Por tanto:

    {IDCliente,IDProducto} ---> {Cantidad}

En cambio, el campo Nombre_producto NO es totalmente dependiente de la clave candidata, puesto que el Nombre_producto solo depende del IDProducto, pero no
del IDCliente.

    {IDProducto} ---> {Nombre_producto}

Puesto que NO todos los atributos que no forman parte de la clave candidata dependen completamente de la clave candidata (Nombre_producto solo depende de un subconjunto de la clave candidata), la tabla TABLA_LINEAS_PEDIDO no esta en segunda forma normal 2FN.

Si dejaramos esta tabla tal y como esta, tendriamos una redundancia de datos innecesaria en el atributo Nombre_producto. Y ademas, podríamos crear inconsistencias de datos si cambiamos el campo Nombre_producto de un registro de la tabla. ¿Cual sería el Nombre_producto del IDProducto=42, si ese nombre es distinto en varios registros de la tabla?

¿Como se resuelve? La regla dice lo siguiente:

    R(A,B,C,D) tal que PK(A,B) y {R.A} ---> {R.D}

es decir, un atributo R.D de la tabla R no depende totalmente de la clave primaria PK(A,B), solo de una parte de esa clave primaria.

Se obtienen dos relaciones:

    R1(A,D), PK(A)
    R2(A,B,C), PK(A,B), FK(A) references R1


Aplicando la regla anterior, se obtienen dos relaciones:

    TABLA_PRODUCTOS
    IDProducto  Nombre_producto
    9           Balón reglamentario de baloncesto
    10          Zapatillas deportivas de rugby
    42          Zapatillas deportivas de tenis


    TABLA_LINEAS_PEDIDO
    IDCliente   IDProducto      Cantidad
    29          42              1
    46          9               5
    204         42              1
    144         10              1


Estas dos tablas si estan en 2FN.


La tercera forma normal 3FN.

Una tabla esta en 3FN si esta en 2FN y todos los atributos que no forman parte de la clave candidata dependen únicamente de la clave candidata. Dicho de otro modo mas facil de entender, no existen dependencias funcionales entre los atributos que no forman parte de la clave candidata.

Imagina una tabla que registra ciudades y datos sobre esas ciudades:

    TABLA_CIUDADES
    IDCiudad   Nombre    País      Continente
    1          Paris     Francia   Europa
    2          Lion      Francia   Europa
    3          Berlin    Alemania  Europa
    4          Pekin     China     Asia
    5          Bonn      Alemania  Europa


En el ejemplo anterior, la clave candidata es IDCiudad. Podemos ver que existe una dependencia funcional entre los atributos Pais y Continente, ya que cada Pais pertenece siempre al mismo Continente. Y puesto que ni Pais ni Continente forman parte de la clave candidata (IDCiudad), la tabla no esta en 3FN.

¿Como se resuelve? La regla dice lo siguiente:

    R(A,B,C) tal que PK(A) y {R.B} ---> {R.C}

es decir, un atributo R.C depende funcionalmente de R.B, y ninguno de ellos forma parte de la clave primaria PK(A).

Se obtienen dos relaciones:

    R1(B,C), PK(B)
    R2(A,B), PK(A), FK(B) references R1


Aplicando la regla anterior, se obtienen 2 relaciones:

    TABLA_PAISES
    Pais        Continente
    Francia     Europa
    Alemania    Europa
    China       Asia


    TABLA_CIUDADES
    IDCiudad   Nombre    País
    1          Paris     Francia
    2          Lion      Francia
    3          Berlin    Alemania
    4          Pekin     China
    5          Bonn      Alemania


Si no hubiéramos normalizado, tendríamos que en una fila de la tabla, el Continente de Francia es Europa, pero por error podríamos tener en otra fila de la tabla que el Continente de Francia es Asia (nos cargamos la integridad de los datos). Además, si la tabla mantuviera centenares de miles de registros, tendríamos información duplicada muchisimas veces (redundancia).


El lenguaje estructurado de consultas

El lenguaje que entienden los SGBD relacionales y desde el que se comunica nuestra aplicación con la BD se llama SQL (Structured Query Language). Este lenguaje permite realizar todas las operaciones de consulta, inserción, actualización, borrado y administración de una BD relacional.

Mediante el API adecuado, podremos usar el lenguaje SQL desde nuestra aplicación escrita en C/C++ para acceder a la BD.

No hablaremos mas sobre SQL en este documento. Quizás en otro post me anime a hablar sobre este lenguaje.

domingo, 20 de mayo de 2012

Fabricar una microSD para arrancar el IGEPv2


= Que es el IGEPv2 =

El IGEPv2 board es una placa embebida muy parecida a la conocida Beagle board, pero con 512MB de memoria RAM y 512MB de NAND flash (en lugar de los 256 de la Beagle). Esta placa lleva una CPU muy rápida (un ARM Cortex A8, OMAP 3530 que corre a 720MHz), y una GPU PowerVR SGX530 a 110MHz que permite correr un servidor de X de manera eficiente. Ademas cuenta con puertos de I/O de audio estéreo, salida de video DVI-D usando HDMI (720p HD), ethernet RJ45, microSD, USB host/device y conectividad inalámbrica WiFi y Bluetooth.



Teniendo en cuenta que su tamaño es aproximadamente el mismo que el de una tarjeta de crédito, y que su consumo es de solo 5W, se trata de una placa muy apetecible para montar sistemas embebidos de todo tipo. La limitación aquí ya no viene dada por las capacidades de la placa, sino por la de tu propia imaginación...

Por el reducido consumo, yo lo usaré como servidor en Internet dedicado las 24h. Pero es solo una idea de las muchas que seguro se te ocurren: cámaras de vídeo vigilancia, receptores de GPS, TPV táctiles, lectores de tarjetas, cajeros automáticos, control de domótica, robots inteligentes, señalización de autopistas, videoconsolas, centro de datos multimedia, etc. etc. etc.

Es un hardware diseñado y fabricado íntegramente en Barcelona por la empresa catalana ISEE, que lo vende a un precio de 188€. Tratándose de un producto nacional, de una calidad excelente, y tal como están las cosas en este país con esta maldita crisis, merece la pena destacar a una empresa nacional que continua invirtiendo en I+D, y desarrollando tecnología puntera a nivel internacional.

= Material necesario para trabajar con el IGEPv2 =

Además del IGEPv2, necesitas material adicional para trabajar con la placa: un alimentador de 5V y un cable para el puerto serie de debug con conector plano (que también vende el fabricante). Una tarjeta microSD de al menos 2GB, un lector de tarjetas microSD, y si tu PC no tiene conector de puerto serie DB9 (lo habitual en estos días), un conversor de USB a DB9. También es necesario un conversor NULL MODEM (para cruzar las señales Tx y Rx). Sería ideal que el conversor de USB a DB9 ya fuera NULL MODEM (de esa manera nos evitamos comprar el conversor NULL MODEM), aunque yo no he encontrado ninguno de estos en el mercado.




= El arranque del IGEPv2 =

En general, los procesadores OMAP35xx pueden arrancar desde una microSD.

El IGEPv2 (basado en el OMAP35xx) usa la tarjeta microSD como el dispositivo de arranque de mas alta prioridad, lo que significa que el procesador intenta arrancar desde la microSD antes que intentar arrancar desde cualquier otro dispositivo (desde la NAND flash).

El procesador intenta cargar un archivo llamado MLO, que reside en la primera partición de la tarjeta microSD, y que también se conoce como x-loader. El procesador solamente carga y ejecuta el programa MLO e ignora el resto. El x-loader (MLO) pasa a ejecutarse por el procesador. Ya es responsabilidad del x-loader que el arranque continúe cargando un kernel, un bootloader (u-boot), o cualquier otra cosa.



= Fabricación de la microSD para arrancar el IGEPv2 =

La tarjeta microSD debe reconfigurarse con unas características determinadas para que puedas usarla para arrancar el IGEPv2:
  • Una geometría particular (heads, sectors, cilindros)
  • Dos particiones primarias (una de msdos 'boot' y otra de linux 'rootfs').

= Definir la geometría y las particiones en la microSD =

Mucho cuidado! Usaremos /dev/sde como fichero dispositivo para la microSD, pero ten en cuenta que este nombre de fichero dispositivo lo decide el kernel cuando detecta un nuevo dispositivo conectado al sistema, por lo que asegúrate de confirmar este valor antes de continuar (comando dmesg), o en caso contrario podrías dañar tu equipo completamente. Avisado quedas.

Borra la tabla de particiones:

    $ sudo dd if=/dev/zero of=/dev/sde bs=1024 count=1024

Arranca el fdisk sobre el dispositivo de la microSD con los flag -u=cylinders (para establecer unidades en cilindros) y -c=dos (para establecer el modo de compatibilidad DOS), ya que por defecto es NONDOS y la microSD que genera no funciona correctamente.

    $ sudo fdisk -u=cylinders -c=dos /dev/sde

Borra todas las particiones creadas en esa tarjeta SD:

    Command (m for help): [d]
    Selected partition 1

Printa la geometría actual de la tarjeta microSD:

    Orden (m para obtener ayuda): p
    Disco /dev/sde: 4035 MB, 4035969024 bytes
    125 cabezas, 62 sectores/pista, 1017 cilindros
    Unidades = cilindros de 7750 * 512 = 3968000 bytes
    Tamaño de sector (lógico / físico): 512 bytes / 512 bytes
    Tamaño E/S (mínimo/óptimo): 512 bytes / 512 bytes
    Identificador de disco: 0x000a6737

La geometría de la tarjeta microSD debe ser esta:
  • 255 heads
  • 63 sectors/track
  • CCC cilindros
El numero de cilindros (valor CCC) se calcula de esta manera:

    4035969024 / 255 / 63 / 512 = 490.677734375

En este caso, CCC=490 (es decir, se trunca, no se redondea)

Como vemos en el listado obtenido antes, nuestra tarjeta microSD no tiene estos parámetros de geometría, por lo que tenemos que cambiarlos. Para establecer los valores calculados, entra en el modo extendido:

    Orden (m para obtener ayuda): x
    Orden avanzada (m para obtener ayuda): h
    Número de cabezas (1-256, valor predeterminado 125): 255
 
    Orden avanzada (m para obtener ayuda): s
    Número de sectores (1-63, valor predeterminado 62): 63
    Atención: estableciendo desplazamiento de sector para compatibilidad con DOS

    Orden avanzada (m para obtener ayuda): c
    Número de cilindros (1-1048576, valor predeterminado 1017): 490 (CCC)

Vuelve al modo normal, y printa el trabajo realizado:

    Orden avanzada (m para obtener ayuda): r

    Orden (m para obtener ayuda): p

    Disco /dev/sde: 4035 MB, 4035969024 bytes
    255 cabezas, 63 sectores/pista, 490 cilindros
    Unidades = cilindros de 16065 * 512 = 8225280 bytes
    Tamaño de sector (lógico / físico): 512 bytes / 512 bytes
    Tamaño E/S (mínimo/óptimo): 512 bytes / 512 bytes
    Identificador de disco: 0x000a6737

Crea ahora la partición primaria de 'boot'

    Orden (m para obtener ayuda): n

    Acción de la orden
    e   Partición extendida
       p   Partición primaria (1-4)
    p
    Número de partición (1-4): 1
    Primer cilindro (1-490, valor predeterminado 1):
    Se está utilizando el valor predeterminado 1
    Último cilindro, +cilindros o +tamaño{K,M,G} (1-490, valor predeterminado 490): +8

    Orden (m para obtener ayuda): t
    Se ha seleccionado la partición 1
    Código hexadecimal (escriba L para ver los códigos): c
    Se ha cambiado el tipo de sistema de la partición 1 por c (W95 FAT32 (LBA))

Marca la partición de 'boot' como bootable:

    Orden (m para obtener ayuda): a
    Número de partición (1-4): 1

Ahora crea la partición primaria del 'rootfs':

    Orden (m para obtener ayuda): n
    Acción de la orden
    e   Partición extendida
       p   Partición primaria (1-4)
    p
    Número de partición (1-4): 2
    Primer cilindro (52-490, valor predeterminado 52):
    Se está utilizando el valor predeterminado 52
    Último cilindro, +cilindros o +tamaño{K,M,G} (52-490, valor predeterminado 490):
    Se está utilizando el valor predeterminado 490

El trabajo realizado hasta ahora debe visualizarse de esta manera:

    Orden (m para obtener ayuda): p

    Disco /dev/sde: 4035 MB, 4035969024 bytes
    255 cabezas, 63 sectores/pista, 490 cilindros
    Unidades = cilindros de 16065 * 512 = 8225280 bytes
    Tamaño de sector (lógico / físico): 512 bytes / 512 bytes
    Tamaño E/S (mínimo/óptimo): 512 bytes / 512 bytes
    Identificador de disco: 0x4b4b1fee

    Disposit. Inicio    Comienzo      Fin      Bloques  Id  Sistema
    /dev/sde1   *           1           9       72261    c  W95 FAT32 (LBA)
    /dev/sde2              10         490     3863632+  83  Linux

Por último, graba y sal:

    Orden (m para obtener ayuda): w
    ¡Se ha modificado la tabla de particiones!
    Llamando a ioctl() para volver a leer la tabla de particiones.
    ATENCIÓN: Si ha creado o modificado alguna de las
    particiones DOS 6.x, consulte la página man de fdisk
    para ver información adicional.
    Se están sincronizando los discos.


= Formatear las particiones =

Antes de continuar, asegúrate de desmontar las dos particiones recién creadas, ya que a veces el auto montado las monta automáticamente, y ahora mismo no es lo que deseamos (comando umount). Después haz lo siguiente:

Formatea la partición de boot (label 'boot'):

    $ sudo mkfs.msdos -F 32 /dev/sde1 -n boot
    mkfs.msdos 3.0.7 (24 Dec 2009)

Formatea la partición del rootfs (label 'rootfs'):

    $ sudo mkfs.ext4 -L rootfs /dev/sde2
    mke2fs 1.41.11 (14-Mar-2010)
    Etiqueta del sistema de ficheros=rootfs
    Tipo de SO: Linux
    Tamaño del bloque=4096 (bitácora=2)
    Tamaño del fragmento=4096 (bitácora=2)
    Stride=0 blocks, Stripe width=0 blocks
    241920 nodos-i, 965908 bloques
    48295 bloques (5.00%) reservados para el superusuario
    Primer bloque de datos=0
    Número máximo de bloques del sistema de ficheros=989855744
    30 bloque de grupos
    32768 bloques por grupo, 32768 fragmentos por grupo
    8064 nodos-i por grupo
    Respaldo del superbloque guardado en los bloques:
        32768, 98304, 163840, 229376, 294912, 819200, 884736

    Escribiendo las tablas de nodos-i: hecho
    Creating journal (16384 blocks): hecho
    Escribiendo superbloques y la información contable del sistema de ficheros: hecho

    Este sistema de ficheros se revisará automáticamente cada 37 montajes o
    180 días, lo que suceda primero.  Utilice tune2fs -c o -i para cambiarlo.

Con esto ya tienes lista la tarjeta microSD para arrancar el IGEPv2.


= Trabajo pendiente =

En la partición 'boot' hay que copiar 3 ficheros:
  • MLO: el binario del x-loader
  • igep.ini: un fichero de configuración proporcionado por ISEE
  • zImage: la imagen del kernel que deseamos arrancar.
Y en la particion 'rootfs' hay que meter:
  • El rootfs descomprimido (aplicaciones del userspace).
De momento dejaremos estas tareas pendientes para el próximo articulo del blog. Si te ha gustado lo que has aprendido en este articulo, continua atento en los próximos días!

sábado, 10 de marzo de 2012

Esta vida me matará a disgustos

Esta gente que viven de los impuestos que pagamos todos, se dedican a estropearme las pocas horas libres que tengo a la semana... Otro jaleo legal mas, y ya van demasiados durante este año 2012, creo que ya he perdido la cuenta. No doy abasto, estoy hecho polvo, van a acabar con mi salud. Yo solo quería dedicar mi fin de semana a estudiar y descansar, después de una semana de lo mas movida, y es que no hay manera, todos los fines de semana me tiene que pasar algo.



Resulta que ahora me han enviado una multa grave, ni mas ni menos que de 200€, supuestamente por haber infringido el articulo 12.4 del Reglamento General de Conductores: conducir con el permiso de circulación caducado. Pero es que mi permiso de circulación B esta en regla hasta el año 2014. ¿A caso desde la administración pública no tienen acceso a la base de datos para contrastar ese dato?

Así que me he pasado medio fin de semana preparando el escrito de alegaciones y toda la documentación para poner el recurso, que tendré que entregar por vía Administrativa en una oficina de Correos para que me compulsen toda la documentación, que por supuesto, primero tendré que encargarme de recopilar. Esta claro que mi tiempo libre no vale nada para esta gente. ¡¡Es que no me dejan vivir tranquilo!! Os juro que ¡¡ESTOY HARTO!!


Generalitat de Catalunya
Servei Territorial de Transit de Barcelona
Plaza de España, nº 1
08015, Barcelona


Antecedentes:

El Domingo 18 de Diciembre de 2011 circulaba por Terrassa con mi vehículo matricula XXX. Bajaba por la Avenida de Barcelona, dirección hacia el Parc Valles. Tras ponerse en verde el semáforo que da acceso a la carretera de Montcada, siempre por mi carril de la derecha y a no mas de 20Km/h, cuando iba a girar hacia la derecha para incorporarme a la Avinguda de les Glories Catalanes (justo enfrente del edificio de la policía municipal de Terrassa), escuché un fuerte derrape detrás de mi coche, tras el cual noté un golpe seco en la parte trasera izquierda de mi vehículo que me lanzó varios metros hacia delante.

El conductor del vehículo que golpeó a mi coche, salió de su coche muy agitado, gritándo, y encarándose conmigo, sin dejarme hablar, afirmando que la culpa era mia, cuando yo iba delante por mi carril de la derecha, y él fue quien golpeó a mi coche por detrás, a una velocidad desproporcionada para lo que es ese tramo de carretera (derrapó y por la inercia, me golpeó).

Considerando que era imposible hacer un parte amistoso con este conductor, llamé desde mi teléfono móvil XXXXXXXXX a la policía local de Terrassa, a las 20:40h (adjunto la factura de teléfono con los datos de la llamada), para que vinieran a hacer el atestado del accidente. Los dos agentes de la policía local llegaron en pocos minutos.

Solicité personalmente que practicaran la prueba de alcoholemia a este conductor, puesto que no veía coherente su estado de animo tan alterado. Éste incluso llegó a encararse con los policías locales. Yo también hice la prueba de alcoholemia, con resultado negativo.

Toda la documentación de mi vehículo (ficha técnica, carnet de conducir, permiso de circulación y justificante de pago del seguro en vigor) le fue entregada al policía local cuando me la requirió. Pueden comprobar en la documentación adjunta, que toda la documentación solicitada estaba en regla.


Denuncia reclamada:

En fecha 09/03/2012 he recogido una notificación de Correos procedente de Servei Territorial de Trànsit de Barcelona, por una denuncia “GREU” del día 18 de Diciembre del 2011 a las 21:26h, en la avenida de les Glories Catalanes, en Terrassa (el día del accidente en el lugar de los hechos anteriormente descritos), por un importe de 200€. El hecho denunciado, “CONDUIR EL VEHICLE AMB L'AUTORITZACIÓ ADMINISTRATIVA CADUCADA, SUSCEPTIBLE D'ESSER PRORROGADA”, artículo y norma infringida el Reglamento general de conductores, 12.4.


Alegaciones:

Tal y como pueden comprobar en la documentación adjunta, mi permiso de circulación B esta en vigor hasta el XX.XX.2014, así como el resto de la documentación presentada al policía local cuando me la requirió el día de los antecedentes descritos anteriormente. Por lo que no entiendo los motivos de esta sanción, y seguramente se trate de algún error.

Mi sorpresa al recibir la notificación de esta sanción ha sido mayúscula, puesto que tras hablar durante varios minutos con el policía local mientras le describía personalmente los hechos del accidente y él redactaba el atestado, en ningún momento me dijo nada sobre el hecho denunciado. De haberme avisado en el momento, lo hubiéramos aclarado todo inmediatamente. Ahora, gestionar esta reclamación casi 3 meses después del accidente a mi me ha supuesto, y supongo que a ustedes también, una perdida de tiempo considerable que todos nos hubiéramos ahorrado si se hubiera notificado esta sanción en el momento.


Solicito:

A raíz de los antecedentes descritos, de las alegaciones planteadas, y de las pruebas presentadas, solicito que se admita a trámite este escrito de alegaciones, procedan a retirar esta denuncia, y revisen de nuevo los datos del atestado del accidente para comprobar si se ha cometido algún error administrativo con los datos de la persona denunciada.


Documentación adjunta:

1.- Copia de la denuncia recurrida
2.- Copia del atestado del accidente descrito
3.- Documento nacional de identidad
4.- Permiso de circulación B
5.- Ficha técnica del vehículo
6.- Justificante de pago del seguro obligatorio
7.- El permiso de circulación para el año 2011
8.- Factura de teléfono con los datos de la llamada a la policía local de Terrassa


Terrassa, a 10 de Marzo de 2012

Firmado:
Angel Ivan Castell Rovira.


Actualización del 17 de Abril de 2012. El recurso ha sido aceptado y la multa retirada. Si es que no podía ser de otra manera... ¡menos mal! :-)

miércoles, 25 de enero de 2012

El mecanismo de conexiones, señales y slots en Qt

Este post asume que el lector tiene ciertos conocimientos en programación C++ y en la librería Qt. Si no sabes de que te estoy hablando, es mejor que dediques tu tiempo a leer otro sitio, porque te vas a aburrir de lo lindo. Avisado quedas.



=== La base teórica ===

El mecanismo de señales y slots es una de las características mas importantes de la librería Qt, probablemente la que le diferencia de otros framework para desarrollar interfaces de usuario.

Las señales y los slots se usan para las comunicaciones entre los objetos del interfaz. En general, la señal (signal) parte de un objeto "emisor" y llega a un objeto "receptor". El objeto receptor decide si ejecuta un slot y finaliza el proceso, o emite una nueva señal que propaga el evento hacia otro objeto receptor. El proceso se puede repetir.

Como ejemplo sencillo, imagina un botón de "Apagar". Cuando el usuario lo pulsa, el boton genera la señal clicked(). Y en respuesta a esa señal, el sistema ejecuta un slot que hace un apagado ordenado de todo el sistema.

Para establecer una conexión entre la señal emitida por un objeto "emisor" y un slot que ejecuta el objeto "receptor", se usa el metodo connect() y las macros SIGNAL() y SLOT(). La sintaxis es esta:

    connect(emisor, SIGNAL(signal_emitida()), receptor, SLOT(slot_doaction()));


Cuando el widget "emisor" genera la señal "signal_emitida", el widget "receptor" ejecuta el código del slot "slot_doaction". La llamada connect, y las macros SIGNAL() y SLOT() forman parte de la sintaxis de Qt, y no son parte del estandar C++. Para compilarlas, se usa un meta-object compiler (moc) que traduce estas macros en C++ estándar. Esta parte escapa del propósito de este post , aunque si sientes interés, no dudes en preguntarme.

Algunas consideraciones a tener en cuenta:

* Una misma señal puede conectarse a distintos slots
* Distintas señales pueden conectarse a un mismo slot
* Una señal puede conectarse a otra señal, lo que emite una segunda signal en el widget receptor inmediatamente después de recibir la primera.

La lista de parámetros de la señal signal_emitida(signature) debe coincidir con la lista de parámetros del slot_doaction(signature). Pero el slot slot_doaction(signature) puede tener menos parámetros que los que tiene la señal signal_emitida(signature), en cuyo caso los parámetros adicionales son simplemente ignorados. Aunque parezca un poco extraño, fíjate que tiene sentido, ya que Qt es capaz de ignorar argumentos sobrantes, pero en ningún caso puede inventar argumentos de la nada. Algunos ejemplos para aclarar este punto:

                   Signals      Slots                   ¿isOK?
rangeChanged(int, int) setRange(int, int) OK
valueChanged(int) setValue() OK
clicked() setValue(int) NOK


Todas las clases que heredan de QObject (o alguna de sus subclases como QWidget), pueden contener señales, slots y conexiones. Pero para que sea posible definirlas, es necesario que la clase mencione la macro Q_OBJECT al comienzo de su declaración.


=== Sintaxis en la práctica ===

Veamos un ejemplo de como se realiza una conexión. Para ello, necesitamos dos clases ("Emisor" y "Receptor") que sean agregaciones de una clase contenedora W (dos partes componentes, o si lo prefieres, dos variables de W). Para enviar un mensaje desde "Emisor" hasta "Receptor" haríamos la siguiente conexión en W (pongo pseudocódigo para que te quedes con la idea):

    class W: public QObject
{
Q_OBJECT
...
Emisor e;
Receptor r;
connect(e, SIGNAL(signalChangePos()), r, SLOT(slotChangePosition()));
};

class Emisor: public QObject
{
Q_OBJECT
...
signal signalChangePos();
...
emit signalChangePos();
};

class Receptor: public QObject
{
Q_OBJECT
...
slot slotChangePosition();
};


Veamos ahora la declaración de una clase MiWidget que maneja señales y slots. MiWidget hereda de QWidget, y a su vez QWidget hereda de QObject:

    class MiWidget : public QWidget
{
Q_OBJECT // Macro es necesaria cuando la clase define sus propias señales o slots

public:
MiWidget(QWidget *parent = 0);
void foo(QString &text);

signals: // señales emitidas por esta clase
void findnext(const QString &str);
void findprev(const QString &str);

private slots: // slots de esta clase
void enableFindButton(const QString &text);
};


Supongamos que el metodo foo emite una signal, veamos como se realiza la implementación:

    void MiWidget::foo(QString &text)
{
emit findprev(text); // se emite la señal findprev con el texto "text"
}



=== Un ejemplo práctico ===

Un escenario común ocurre cuando quieres pasar valores constantes en la sentencia connect. Esto ocurre por ejemplo cuando quieres implementar un teclado QWERTY usando QPushButtons como teclas. Podrías pensar que lo lógico es implementar algo como esto:

    connect(key_q, SIGNAL(pressed()), panelTexto, SLOT(keyPressed('q')));
connect(key_w, SIGNAL(pressed()), panelTexto, SLOT(keyPressed('w')));
connect(key_e, SIGNAL(pressed()), panelTexto, SLOT(keyPressed('e')));
connect(key_r, SIGNAL(pressed()), panelTexto, SLOT(keyPressed('r')));
connect(key_t, SIGNAL(pressed()), panelTexto, SLOT(keyPressed('t')));
...


Pero esto no es valido en Qt, y no te funcionaría. Para implementar un teclado, la opción fácil sería usar un montón de QPushButton, y asignar a cada uno un slot diferente. La implementación sería como esto:

    connect(key_q, SIGNAL(pressed()), panelTexto, SLOT(press_q()));
connect(key_w, SIGNAL(pressed()), panelTexto, SLOT(press_w()));
connect(key_e, SIGNAL(pressed()), panelTexto, SLOT(press_e()));
connect(key_r, SIGNAL(pressed()), panelTexto, SLOT(press_r()));
connect(key_t, SIGNAL(pressed()), panelTexto, SLOT(press_t()));
...


Y la lista de slots:

    private slots:
void press_q();
void press_w();
void press_e();
void press_r();
void press_t();
...


Parece una exageración tener 102 slots, todos prácticamente con el mismo código. Pero, ¿a caso se te ocurre alguna alternativa mejor? Para hacer esto de una forma mas eficiente y sencilla de mantener, con un único slot, se usa la clase QSignalMapper. Con su ayuda, podríamos hacer esto:

    signalMapper = new QSignalMapper;

signalMapper->setMapping(key_q, QChar('q'));
signalMapper->setMapping(key_w, QChar('w'));
signalMapper->setMapping(key_e, QChar('e'));
signalMapper->setMapping(key_r, QChar('r'));
signalMapper->setMapping(key_t, QChar('t'));
...

// Conexiones de los button con el signal mapper
connect(key_q, SIGNAL(pressed()), signalMapper, SLOT(map());
connect(key_w, SIGNAL(pressed()), signalMapper, SLOT(map());
connect(key_e, SIGNAL(pressed()), signalMapper, SLOT(map());
connect(key_r, SIGNAL(pressed()), signalMapper, SLOT(map());
connect(key_t, SIGNAL(pressed()), signalMapper, SLOT(map());

// Y conexion del signal mapper con el slot genérico
connect(signalMapper, SIGNAL(mapped(QChar)), panelTexto, SLOT(setText(QChar)));


Y en el slot setText() irias pintando los distintos caracteres en el objeto "panelTexto", según la tecla pulsada por el usuario.

viernes, 25 de marzo de 2011

Mens sana in corpore sano

El deporte ha formado parte de mi vida desde que tengo uso de razón, y probablemente así siga siendo hasta el día que me falle la salud. Empecé a practicarlo con 11 años, y desde entonces hasta hoy, 23 años después, ahí seguimos, a tope. Para mi ya forma parte de una filosofía de vida. Vivir sin el deporte sería como vivir sin dormir, o vivir sin comer.



Nunca destaqué por tener unas cualidades atléticas sobresalientes. No obstante, el esfuerzo y las ganas continuas de mejorar me han llevado a labrar un historial deportivo del que hoy en día me siento, por que no decirlo, orgulloso. Y precisamente se trata de este historial deportivo del que hoy os voy a hablar en este post:



== Futbol ==

[1987-1988]
Escuela infantil de futbol Selma Junior (Castellón)



== Baloncesto ==

Recuerdo mis años como jugador de baloncesto con muchísima nostalgia. Con los años he perdido contacto con demasiada gente, decenas de compañeros de equipo, entrenadores, fisioterapeutas... De todos vosotros guardo muy buenos recuerdos. Me acuerdo de aquella remontada ganando "in extremis" contra el equipo valenciano de "La Salle", uno de los mejores de toda la Comunidad Valenciana, después de perder la primera parte por mas de 25 puntos, y el pabellón de Grapa repleto de gente rugiendo y aplaudiendo... Todavía se me pone la piel de gallina. Me acuerdo muchas veces de todos vosotros.

[1987-1988]
Escuela infantil de baloncesto Taugres Castellón

[1988-1989]
Escuela infantil de baloncesto Taugres Castellón
Seleccionado como cantera del club en la "Operación Altura '89"

[1989-1990]
Temporada completa en el Cadete B club de baloncesto Taugres Castellón

[1990-1991]
Temporada completa en el Cadete A club de baloncesto Taugres Castellón

[1991-1992]
Temporada completa en el Juvenil A club de baloncesto Atletic Basquet Castelló (ABC)
Parte de la temporada doblo entrenamientos con el juvenil B del mismo club

[1992-1993]
Temporada completa en el Juvenil A club de baloncesto Ceramicas Gaya

[1993-1994]
Pretemporada e inicio de temporada con el Junior/Senior club de baloncesto Ceramicas Gaya



== Rutas en bicicleta ==

La fecha indica la primera vez que realicé la ruta, aunque algunas son rutas habituales de entrenamiento. Como por ejemplo la subida al Desert de les Palmes, con un desnivel de mas de 700 metros de altura, la he realizado decenas de veces. Precisamente en el descenso de esa carretera tuve mi primer (y único) accidente con la bicicleta. Me rompí dos dedos de la mano contra un coche en un accidente que me podría haber costado la vida.

[1991]
Castellon - San Juan de Moro - Castellon (36Km)
Castellon - Onda - Castellon (48Km)

[1992]
Castellon - San Juan de Moro - Villafames - Borriol - Castellon (56Km)
Castellon - Borriol - Cabanes - Castellon (56Km)
Castellon - Magdalena - Desert de les Palmes - Castellon (30Km)

[1993]
Castellon - San Juan de Moro - Alcora - Castellon (42Km)
Grao de Castellon - Oropesa - Grao de Castellon (36Km)
Castellon - Borriol - Atzaneta - Benafigos (58km)

[1994]
Grao de Castellon - Magdalena - Desert de les Palmes - Grao de Castellón (25Km)
Grao de Castellon - Pico del Bartolo - Grao de Castellon (29Km)
Castellon - Villafames - Costur - Castellon (60km)
Grao de Castellon - Oropesa (por la costa) - Grao de Castellon (36Km)



== Gimnasios fitness ==

El fitness forma parte del deporte que practico habitualmente 3 o 4 días por semana. Algún día os hablaré sobre mis rutinas de entrenamiento, de las que hay para hablar largo y tendido.

[01/1995 - 01/2004]
Gimnasio en mi casa

[02/2004 - 07/2004]
Gimnasio Amstelpark, Amsterdam (Holanda)

[08/2004 - 11/2004]
Gimnasio en mi casa

[12/2004 - 02/2005]
Gimnasio Club Estudio Praga, Madrid

[02/2005 - 06/2006]
[Gimnasio Muscle Gracia, Bilbao (Vizcaya)

[07/2006 - Actualmente]
Gimnasio Balla Shen Dragon, Terrassa (Barcelona)



== Montañismo ==

Mi pasión por la naturaleza no queda bien reflejada en esta lista de montañas tan corta. Espero y deseo poder ampliar esta lista en los próximos años:

[8/1994]
Pico del Bartolo (724m)
Parque natural del Desert de les Palmes (Castellón)
Ruta en bicicleta partiendo desde Castellón de la Plana.

[5/2009]
Pico de San Jerónimo (1224m)
Parque natural de la muntanya de Montserrat (Barcelona)
http://es.wikiloc.com/wikiloc/view.do?id=1998089

[7/2009]
Pico La Mola (1104m)
Parque Natural Sant Llorenç del Munt (Barcelona)
Ruta de trekking partiendo desde Sant Feliu del Raco.

[4/2011]
Pico del Collbaix (547m)
Parque natural Sant Llorenç del Munt (Manresa, Barcelona)
Ruta de trekking partiendo desde San Joan de Vilatorrada.

[4/2011]
Pico del Penyagolosa (1814m)
Parque natural del Penyagolosa (Castellón)
http://es.wikiloc.com/wikiloc/view.do?id=762341

[07/2011]
Pico del Montcau (1066m)
Parque natural de Sant Llorenç del Munt i l'Obac (Barcelona)
Ruta de trekking partiendo desde el Coll d'Estenalles y pasando por la Mola.

[07/2011]
Pico superior del Pedraforca (2497m)
Parque Natural del Cadí-Moixeró (Barcelona)
Ruta desde el mirador del Gresolet
http://es.wikiloc.com/wikiloc/view.do?id=2001713

[08/2011]
Ruta circular desde Benafigos por el Rio Montlleo
Parque natural del Penyagolosa (Castellón)
http://es.wikiloc.com/wikiloc/view.do?id=995398
Video 1/2 y 2/2 en YouTube.

[08/2011]
Ronda Vallesana Terrassa
Parque natural de Sant Llorenç del Munt i l'Obac
http://es.wikiloc.com/wikiloc/view.do?id=1261016

[03/2012]
Ruta circular por Sant Joan de Penyagolosa el Burguillar
Parque natural del Penyagolosa (Castellón)
http://es.wikiloc.com/wikiloc/view.do?id=113557
Video 1/1 en YouTube

[04/2012]
Magdalena - Pico del Bartolo (724m) - Magdalena
Parque natural del Desert de les Palmes (Castellón)
http://es.wikiloc.com/wikiloc/view.do?id=2181053

[06/2012]
Pico superior del Pedraforca (2497m)
Parque Natural del Cadí-Moixeró (Barcelona)
Ruta desde el pueblo de Gósol
http://es.wikiloc.com/wikiloc/view.do?id=953231
Video 1/2 y 2/2 en YouTube

[07/2012]
Ruta circular desde Navajas, embalse del Regajo y salto de la novia
Parque natural de la Sierra de Espadá (Castellón)
http://es.wikiloc.com/wikiloc/view.do?id=2635251
Video en YouTube asap...

[07/2012]
Ruta circular Terrassa - Casanova de l'Obac - Matadepera - Terrassa
Parque natural de Sant Llorenç del Munt i l'Obac (Barcelona)
http://es.wikiloc.com/wikiloc/view.do?id=2447046

[08/2012]
Pico superior del Pedraforca (2497m)
Parque Natural del Cadí-Moixeró (Barcelona)
Ruta desde el mirador del Gresolet
http://es.wikiloc.com/wikiloc/view.do?id=2001713

[08/2012]
Pica d'Estats (3143m) y Pic Verdaguer (3133m)
Parque Natural del Alto Pirineo
Ruta desde el refugio de Vallferrera
http://es.wikiloc.com/wikiloc/view.do?id=3023152
Video 1/2 y 2/2 en YouTube

[08/2012]
Vuelta al Desert de les Palmes
Parque natural del Desert de les Palmes (Castellón)
Ruta desde el puente de la autopista
http://es.wikiloc.com/wikiloc/view.do?id=353937
Video en Youtube asap...

[08/2012]
Villafranca - La Estrella - Pico del Picayo (1304m) - Villafranca
Ruta desde Villafranca del Cid
http://es.wikiloc.com/wikiloc/view.do?id=1339571
Video 1/1 en Youtube

[09/2012]
Terrassa - Matadepera - La Mola - Montcau - Terrassa
Parque natural de Sant Llorenç del Munt i l'Obac (Barcelona)
Ruta desde Terrassa
http://es.wikiloc.com/wikiloc/view.do?id=2281875

[09/2012]
Benafigos - Mas de la Cormana - Benafigos
Parque natural del Penyagolosa (Castellón)
Ruta desde Benafigos
http://es.wikiloc.com/wikiloc/view.do?id=1933351

[09/2012]
Sant Joan de Penyagolosa - Nacimiento rio Carbo - Pic Penyagolosa (1813m)
Parque natural del Penyagolosa (Castellón)
Ruta desde Ermitorio Sant Joan de Penyagolosa
http://es.wikiloc.com/wikiloc/view.do?id=1537350
Video en YouTube asap...

[03/2012]
GR33 desde el Grao de Castellón hasta Sant Joan de Penyagolosa (65km, D+2640m)
Grao, Castellón, Borriol, Villafames, Les Useres, Xodos y Vistabella (Castellón).
http://es.wikiloc.com/wikiloc/view.do?id=834053
Video en YouTube asap...


== Carreras populares ==

Soy corredor habitual desde que dejé el baloncesto con 18 años. A 15km de entrenamiento semanales, distancia que supero holgadamente todas las semanas, calculo que mis piernas deben haber corrido mas de 10.000km. Desde hace unos 6 años, me aficioné a participar en carreras populares. Estas son algunas de las carreras en las que he participado:



09/2007
I travessa Circutor - Monasterio Montserrat (23km, 1200m D+: 4h 30m)

10/2007
II gran premio 42 y pico Castellón (10km: 49m 47s)

10/2008
Cursa de fons a Sant Muç, Rubi (10Km: 48m 56s)

09/2008
Cursa festa major Matadepera (10km: 51m 49s)

04/2008
Mullat i Corre circuit de Montmelo (10km: 47m 27s)

09/2008
II travessa Circutor - Monasterio Montserrat (23km, 1200m D+: 4h 05m)

01/2009
IX mitja marató de Terrassa (21Km: 2h 0m 45s)

07/2009
XXX Cursa Festa Major Terrassa (8km: 37m 35s)

07/2009
XXVII Cursa atlètica popular Ca n'Anglada (6km: 25m 02s)

09/2009
Cursa festa major Matadepera (10km: 52m 44s)

10/2009
III travessa Circutor - Monasterio Montserrat (23km, 1200m D+: 3h 52m)

07/2010
XXXI Cursa Festa Major Terrassa (8km: 39m 53s)

09/2010
Cursa festa major Matadepera (10km: 49m 44s)

09/2010
Cursa Mercè en Barcelona (10km: 44m 44s)

01/2011
Cursa Santi Centelles de Terrassa (5Km: 22m 35s)

04/2011
IV Carrera a pie costa Azahar (10km: 45m 59s)

05/2011
XI Cursa de Muntanya de Rubí (11km: 1h 10m 16s)

06/2011
XXVII Cursa atlètica popular Pla de Bonaire (7km: 32m 22s)

06/2011
XXIX Cursa atlètica popular Sant Llorenç (5.5km: 22m 30s)

06/2011
I Cursa popular Grao de Castellò (5km: 21m 31s)

07/2011
XXXII Cursa Festa Major Terrassa (7.5km: 37m 59s)

07/2011
XXIX Cursa atlètica popular Ca n'Anglada (6km: 23m 24s)

09/2011
Cursa festa major Matadepera (10km: 46m 39s)

09/2011
Cursa Mercè en Barcelona (10km: 44m 41s)

10/2011
V travessa Circutor - Monasterio Montserrat (23km, 1200m D+: 3h 54m)

01/2012
XIII mitja marató de Terrassa (21km: 1h 56m 17s)

05/2012
I cursa de Vallparadis (7.5km: 33m 21s)

06/2012
XXIV pujada al Desert de les Palmes - Castellò (7.8km, 400m D+: 44m 26s)

06/2012
XXXIII Cursa Festa Major Terrassa (7.5km: 43m 25s) (liebre de otro corredor)

09/2012
III Ruta de les X Ermites, Begues (52km, 2500m D+: 10h 42m 13s)

10/2012
VI travessa Circutor - Monasterio Montserrat (23km, 1200m D+: 3h 43m 00s)

11/2012
XXIX Mitja Marató de Castellò (21km: 1h 44m 14s)



== Entrenamiento running ==

Zonas donde realizo (o he realizado en el pasado) entrenamientos habitualmente. En muchas de ellas me podéis encontrar entrenando hoy en día.

Camino de la Fileta (Castellón)
Camino del rio seco (Castellón)
Avd. Ferrandis Salvador (Castellón)
Camino de la Plana (Castellón)
Camino Serradal (Castellón)
Avd. del Mar (Castellón)
Amstelpark, Amstelveen (Holanda)
Paseo del Museo Guggenheim (Bilbao)
Carretera del Desert de les Palmes (Castellón)
Avenida del Valles, Terrassa (Barcelona)
Parc Vallparadis, Terrassa (Barcelona)



== Planes para el futuro ==

Por supuesto, seguir corriendo todas las carreras populares que me queden cerca. Mi próxima carrera será el día 16 de Abril en mi querida ciudad natal. Participaré en la IV carrera a pié, costa de Azahar.

Aunque desde hace un par de años ronda por mi cabeza la palabra "Triatlon", me atrae mucho la idea de juntar la bicicleta, piscina y running en una sola prueba. Pronto espero poder comprar una buena bicicleta para entrenar la prueba en condiciones. También necesitaré una piscina para entrenar la natación. Aunque mi presupuesto de momento no está para muchas alegrías.

También me gustaría comprar un GPS para aventurarme mas a menudo por la montaña haciendo trekkings de muchos kilómetros y varios días. El Camino de Santiago empezando en los Pirineos encajaría muy bien en este apartado.

Esperemos que las lesiones nos respeten durante muchos años para seguir disfrutar de todos estos proyectos durante mucho tiempo... ¿Alguien se anima con alguno de ellos? :-)

Seguidores