20 de julio de 2008

Panel de Televisiones con PS3 (I)

En las próximas entradas voy a explicar un proyecto que me ha tenido ocupado las últimas semanas. Con motivo de la feria ESOF 2008 el Instituto de Física de Cantabria tenia apalabrado un stand donde enseñaría lo que se hace aquí. Como es una feria de divulgación científica, se decide llevar 9 televisores LCD que formaban un panel de 3x3. Este panel ya lo había preparado Ignacio Coterillo anteriormente con imágenes estáticas. Para la ESOF 2008 se preparo un programa para ir pasando imágenes sucesivamente.
En la entrada de hoy voy a hablar brevemente del hardware utilizado.

Implicados:
  • Ignacio Coterillo
  • Luis José Cabellos
Hardware:
  • 9 televisiones LCD 42'', Hitachi
  • 9 Playstation 3 de 40GB
  • 1 switch ethernet 3COM de 24 bocas
  • cables hdmi, cables ethernet, cables de alimentación...etc
Preparación de las PS3:
  • Instalar Fedora 7
  • Instalar un entorno de ventanas liviano: XFCE
  • Quitar servicios no necesarios: bluetooth, mail, ...etc
  • Se las configura con una red local para verse entre ellas a través del switch y se configura ssh para ir a través de claves RSA.
Próxima entrada, Software desarrollado para mostrar las imágenes.

3 de julio de 2008

Recursividad en un ASSERT

Después de tanto tiempo sin escribir sobre código erróneo, hoy voy a presentar un pequeño trozo de código que puede fallar (y falló). A ver si sois capaces de encontrar el error.

#define M_ASSERT( exp ) AssertScreen( exp, #exp )

Para empezar tenemos esta definición de ASSERT. Simplemente al autor del código no le gusta el ASSERT de la librería estándar de C, así que crea su propia versión. No es nada raro.

void AssertScreen( int expression, const char * msg ){
if( expression != 0 ){
return;
}

void * fontData = LoadFile( "debugfont.fnt" );
LogScreen::Setup( fontData );
LogScreen::PrintString( msg );

do{}while( 1 );
}

Veamos que hace el assert propio. Abre una ventana con el mensaje de error e interrumpe la ejecución(o más bien la para entrando en un bucle infinito).

void * LoadFile( const char * name ){
File file;

if( file.Open( name ) ){
M_ASSERT( false && "File Not Found" );
return 0;
}

void * data = file.Load();

file.Close();

return data;
}

Y esta es la función en la que vemos el problema, la función encargada de abrir y leer un fichero.

El error / Mi solución
Bueno, el error creo que se ve rápido. Y más si se tiene en cuenta la pista del título de la entrada Recursividad en un ASSERT. Pues ese es el error, es posible que falle un ASSERT dentro del propio ASSERT. Es más si falla, empezara a fallar recursivamente hasta agotar los recursos, ya que nunca llega a parar la ejecución (no llega nunca al bucle infinito).

El fallo se produce porque ASSERT usa la función LoadFile para cargar la fuente del mensaje. Y LoadFile llama a ASSERT si no encuentra un fichero.

La mejor manera de solucionarlo, creo yo, es quitar el assert del LoadFile. Más aún cuando LoadFile devuelve 0 en caso de no encontrar el fichero. Es de lo más común que no se encuentre un fichero determinado y no por eso se debe llamar a un ASSERT.

Otra posible solución es usar el ASSERT de la librería estándar. Creed me, el ASSERT no hacia nada del otro mundo. Es más, no hacia nada adicional al ASSERT de la librería estándar, solo poner una fuente de letra diferente. Y a veces esto fallaba.

No llega al nivel de ASSERT propio que vi una vez, que permitía ignorar un error, ignorar todos los errores del mismo ASSERT, o terminar la ejecución del programa. Eso si que era motivo para hacerse una función propia.

La moraleja de hoy, no os compliquéis la vida.