BattleCity

 Juego Battle City  

= Integrantes =

= Descripción = Battle city (condocido también como Tank o Tank1990)es un popular videojuego publicado por Namco en 1985. En este proyecto se implementa una versión de este juego utilizando la tarjeta Condorboard Condorboard y un display de 128x64 pixeles. El proyecto se desarrolló sobre la plataforma CONDORBOARD, sobre la cual se ha montado previamente la distribución de Linux embebido Angstrom Para conocer más acerca de la instalación de la imagen del kernel y el sistema de archivos por favor diríjase a: Condor:Uboot, Condor:Kernel,Condor:rootfs. En este proyecto muestra como usar la librería POSIX(Portable Operating System Interface) para el manejo de hilos a nivel de usuario, y porta la librería del display de 128x64 pixeles con controlador KS0108 para la Condorboard(con controlador AT91SAM9XE128) también a nivel de usuario.

Vídeos y fotos de demostración
D5Vseok5jDQ

En el video se muestra el movimiento de los tanques de los dos jugadores (limitados por la pared del escenario), así como los disparos realizados por ambos jugadores que destruyen parte de la pared y restan vida al oponente cuando son alcanzados por las balas. Al mismo tiempo en la consola del sistema se muestra la información del juego. Al final el jugador 1 es el ganador pues la vida de su oponente llega a cero. = Herramientas para el desarrollo del proyecto =

Preliminares
El proyecto se desarrolla en base a la distribución Angstrom de Linux embebido, la cual está montada de antemano sobre la plataforma Condorboard. Para conocer más acerca del proceso de arranque, montaje de la imagen del kernel y del sistema de archivos por favor rediríjase a los siguientes links: Condor:Boot Process Condor:Uboot Condor:Kernel Condor:rootfs

Una vez montada la distribución, este proyecto se enfoca principalmente en el uso de las librerías POSIX para acceder a los periféricos a nivel de usuario (Específicamente se accede a la PIO para el manejo del display de 128x64), y para manejar multi hilos dentro del proceso del programa.

Compilación de programas para la distribución Angstrom
Para correr un programa a nivel de usuario sobre la distribución de Angstrom este debe compilarse utilizando el compilador cruzado de la distribución:arm-angstrom-linux-gnueabi-gcc. Un claro ejemplo con una descripción más detallada la puede encontrar aquí. Para este proyecto, para poder utilizar las funciones de la librería pthread.h, sobre la que hablaremos en breve, debe incluirse el flag -lpthread en la compilación del programa. El siguiente makefile hecho para este proyecto ilustra la utilización del compilador cruzado, como incluir nuevas librerías para el programa, e incluye el uso del flag -lpthread necesario para este caso: CC		=	arm-angstrom-linux-gnueabi-gcc HW=hardware GLCD_DIR = ks108 MODULOS_SOURCE= \ $(HW)/condor_base.c \ $(GLCD_DIR)/include/KS0108.c \ $(GLCD_DIR)/include/graphic.c \ $(GLCD_DIR)/include/KS0108-AT91.c \ #$(GLCD_DIR)/imagenes/imagenes.c \ MODULOS = $(MODULOS_SOURCE:.c=.o) INCLUDE= \ -I. \		-I$(HW) \ -I$(GLCD_DIR)/include \ #-I$(GLCD_DIR)/imagenes FILEIN	=	main.c $(MODULOS_SOURCE) FILEOUT	=	main_battle
 * 1) Compilador
 * 1) Modulos

all: $(FILEOUT) $(FILEOUT): $(MODULOS) rm -f $(FILEOUT) $(CC) -lpthread $(INCLUDE) $(FILEIN) -o $(FILEOUT).bin $(MODULOS) : %.o : %.c	$(CC) -c $(INCLUDE) $< -o $@ clean: rm -f *.bin rm -f *.o			rm -f $(GLCD_DIR)/include/*.o			rm -f $(GLCD_DIR)/imagenes/*.o			rm -f $(HW)/*.o

Manejo del display
Para el manejo del display se portó una librería ya existente de la que puede encontrar información detallada [Control_de_Display_128x64|aquí]. Dado que estamos trabajando a nivel de usuario, para poder acceder a los periféricos del microcontrolador se utilizó la función mmap de POSIX de la siguiente forma:

//copiar código de init_pio

Esta función mapea archivos o dispositivos (en este caso el periférico PIO) en memoria y proporciona una dirección base virtual u offset, esta dirección es usada cada vez que se quiera acceder al periférico, así que para portar la librería del display esta dirección es pasada como parámetro a todas las funciones del display. Entonces, las definiciones de los registros para la librería quedan finalmente así:

//copiar los ks108_control_etc...

Donde at_addbase es el offset proporcionado por mmap. Una vez hechas estas modificaciones, todas las funciones de la librería están listas para usar en el programa principal.

Creación de threads
En este proyecto el manejo de hilos de ejecución o threads es la base para controlar las diferentes actividades en paralelo del juego. Una descripción más detallada de la definición de estos hilos dentro del programa se muestra más adelante. En esta sección se ilustra cómo utilizar la librería ' de POSIX para crear threads y manejarlos. Las funciones básicas para la cración y manejo de threads son: pthread_create que crea un nuevo hilo con la función y el identificador pasados como parámetro, pthread_join que espera la terminación del thread con el ID pasado como parámetro y recibe el retorno del thread de existir, entre otras. En este ejemplo se muestra un uso sencillo de estas funciones.
 * 1) include 
 * 2) include 
 * 3) include 
 * 4) include 
 * 5) define MAX_THREADS 8

typedef struct {//Se define la estructura para pasar como parámetro a los threads int id,valor; } parameters;

parameters parametros[MAX_THREADS]; pthread_t tabla_hilos[MAX_THREADS];

void *funcion_thread(parameters *p) { printf("Ejecutando la funciÃ³n en el thread con id %d al que se le ha pasado el valor %d\n", p->id,p->valor); pthread_exit(p->valor); }

int main(void){ int i, *res;

//creamos tantos threads como MAX_THREADS printf("\nCreando threads...\n\n"); for (i=0; i<MAX_THREADS; i++) { parametros[i].id = i;	parametros[i].valor=rand%100;

pthread_create(&tabla_hilos[i], NULL, (void *)&funcion_thread,(void *)&parametros[i]); }

// esperamos que terminen todos los threads printf("\nThreads creados. Esperando que terminen...\n\n"); for (i=0; i<MAX_THREADS; i++) { int *aux; pthread_join(tabla_hilos[i],&aux); printf("El thread %d devolvio el valor %d\n", i,aux); }

return 0; }

Note que al ejecutar el programa el orden de ejecución de cada hilo no está previamente determinado, por lo que en cada ejecución los resultados obtenidos en consola pueden variar. Dado que en este ejemplo no se usan periféricos del microcontrolador, puede probarse en diferentes plataformas simplemente cambiando el compilador. Por ejemplo para la distribución Angstrom sobre la que estamos trabajando en la plataforma Condorboard la compilación de este programa sería con el compilador cruzado de Angstrom:

% arm-angstrom-linux-gnueabi-gcc -o thread-create thread-create.c -lpthread

Mientras que para un computador esta compilación sería: //Para el caso de windows % cc -o thread-create thread-create.c -lpthread

//Para el caso de Linux % gcc -o thread-create thread-create.c -lpthread

= Diseño de la solución =

Diseño de la arquitectura software
Para la implementación del juego se definieron diferentes hilos de ejecución para las diferentes actividades que se deben llevar en paralelo, el siguiente diagrama ilustra la dinámica del programa. En este se ilustra cómo cada thread, que corresponde a una función, es lanzado por otra función que a su vez es un thread:



Descripción de threads
En este thread se actualiza en una variable la acción realizada por el usuario al pulsar los controles de entrada, que para esta implementación se utilizó la terminal, pero que puede ser escalable para usar pulsadores u algún otro periférico. Es el thread encargado de repintar el escenario y los tanques de los jugadores. Para llevar a cabo esta actualización se utilizaron diferentes métodos y se enriqueció la librería del display para trabajar directamente sobre las imágenes utilizadas, y no sobre la lectura del display. Dichas modificaciones están claramente documentadas en los archivos fuente del proyecto. Dentro de este hilo se maneja la actividad de cada jugador. Evalúa el comando de entrada actualizado por el thread de actualizarControles y toma la acción correspondiente a este que incluye moverse en las 4 direcciones, y disparar. Para el caso de disparar se lanza un thread_bala por cada bala lanzada. Cada bala lanzada corresponde a este thread. Dentro de éste se actualiza la imagen del escenario para que sea actualizada en la pantalla, cada vez corriendo la bala, y se evalúa si esta ha chocado con una pared o con un jugador, casos en los que modifica el escenario al destruir la pared o resta la vida del jugador disparado respectivamente.
 * Thread *actualizarControles
 * Thread *actualizarPantalla
 * Thread *jugar
 * Thread *thread_bala

Descripción de variables globales
A diferencia de los procesos, los threads corren en un mismo espacio de memoria, por lo tanto aunque es posible no es necesario utilizar protocolos de comunicación entre threads cuando corresponda. En su lugar es suficiente con definir las variables globales necesarias dentro del juego, ya que cada thread podrá leer dichas variables sin importar si es modificada por otro thread o función. Para este proyecto las diferentes variables globales se definieron para dar un informe del estado actual del juego, y poder controlar sus diferentes variables sin causar conflictos entre los threads.


 * "keyboard": Es la variable en la que se almacena el último caracter leído del teclado, es modificada por *actualizarControles, y es leída dentro del hilo de cada jugador (*jugar) para conocer la acción a seguir, ya sea de movimiento o de disparo.
 * "vidaJ1, vidaJ2": Para el manejo del nivel de vida de los jugadores se definieron las varialbes vidaJ1 y vidaJ2, que son modificadas por los hilos de las balas en caso de alcanzar la posición de un tanque, y son evaluadas constantemente por el hilo de actualizarPantalla.
 * "busyShotJ1, busyShotJ2": Estas variables son utilizadas dentro de los hilos de cada jugador (*jugar) para evaluar si les es permitido disparar en caso de recibir el comando correspondiente. Con estas variables se asegura un retardo entre una bala y otra del mismo tanque para un mejor control del juego.

= Materiales =

Dispositivos Hardware

 * Tarjeta de desarrollo uniandes CondorBoard
 * Hoja de datos del AT91SAM9XE128 Descargar...
 * Display 128x64 con controlador KS0108
 * Información técnica del display Descargar...
 * Hoja de datos del controlador Descargar...

Herramientas Software

 * Distribución de Linux embebido - Angstrom
 * Compilador cruzado para la distribución angstrom: arm-angstrom-linux-gnueabi-gcc
 * Sam-ba: Herramienta para montar Uboot en el microcontroladoR
 * Herramienta LCDAssistant (Bitmap converter) Descargar

= Código fuente =


 * Archivo ejecutable (Descargar)
 * Archivos Fuente - Proyecto completo. Incluye el archivo principal (main.c), la librería modificada en ks108/, y el Makefile para su compilación en la plataforma Condorboard con la distribución Angstrom (Descargar)

= Resultados =

Análisis de resultados
= Bibliografía =

Posix library Uboot - redirigir a condor Uimage - redirigir a condor

Threads - Capítulo 4: