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.

Visitas:

Seguidores