En el anterior artículo explicaba cómo instalar linux en el marco digital Parrot DF3120. En este explicaré cómo generar el toolchain para poder crear programas que funcionen en el marco digital. De paso crearemos una versión de la imagen más moderna para nuestro marco. El artículo original que lo explicaba es este, pero está desfasado y hay que hacer retoques para que funcione bien.
Lo voy a hacer todo desde mi linux Ubuntu 11.10, por lo que es posible que algunas cosas haya que modificarlas si usáis otra distribución.
Lo primero es instalarse usa serie de paquetes que son necesarios para que todo el proceso sea correcto:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
sudo apt-get install git-core sudo apt-get install tig sudo apt-get install lzop sudo apt-get install uboot-mkimage sudo apt-get install libelf-dev sudo apt-get install libncurses-dev sudo apt-get install gtk-doc-tools sudo apt-get install checkinstall sudo apt-get install e2fsprogs sudo apt-get install libglib2.0-dev sudo apt-get install libxml2-dev sudo apt-get install genext2fs sudo apt-get install lzma sudo apt-get install subversion sudo apt-get install cvs sudo apt-get install gawk sudo apt-get install bison sudo apt-get install flex sudo apt-get install automake sudo apt-get install gcc sudo apt-get install build-essential sudo apt-get install texinfo sudo apt-get install curl |
Después hay que bajarse minifs con el git:
1 |
git clone http://oomz.net/git/minifs.git minifs |
A continuación hay que hacer un par de modificaciones:
- Edita el fichero minifs/conf/board/df3120/config_busybox.conf y reemplaza la línea # CONFIG_CHMOD is not set por CONFIG_CHMOD=y
- Edita el fichero minifs/conf/packages/05crosstools.sh y reemplaza la línea hset libtool url «http://ftp.gnu.org/gnu/libtool/libtool-2.4.2.tar.gz» por hset libtool url «http://ftp.gnu.org/gnu/libtool/libtool-2.4.tar.gz»
- Edita el fichero minifs/conf/packages/11graphical.sh y reemplaza la línea hset libpng url «ftp://ftp.simplesystems.org/pub/libpng/png/src/libpng-1.4.8.tar.bz2» por hset libpng url «ftp://ftp.simplesystems.org/pub/libpng/png/src/libpng-1.4.9.tar.bz2»
Después ya podemos ejecutar el script de la siguiente forma (Puede tardar varios minutos):
1 2 3 |
cd minifs export MINIFS_BOARD=df3120 ./minifs_build.sh |
Ahora vemos que entre otras cosas se han creado dos ficheros en el directorio build-df3120, un .img y un .plt. Pues bien con ellos hay que volver a hacer lo mismo que comentaba en el anterior artículo. Si todo ha ido bien veremos la nueva versión del firmware donde lo más destacado es que aparecen los mensajes de arranque:
Ahora vamos a compilar nuestro primer programa, y cómo no, tenía que ser un Hola Mundo:
1 2 3 4 5 6 |
#include <stdio.h> void main(void) { printf("Hola Mundo.\n"); } |
Copiamos el código que aparece arriba y lo guardamos en un fichero llamado holamundo.c. Después ejecutamos el siguiente comando:
1 |
toolchain/arm-v4t-linux-uclibcgnueabi/bin/arm-v4t-linux-uclibcgnueabi-gcc holamundo.c -o holamundo |
Esto habrá generado un fichero ejecutable llamado holamundo, pero ¿cómo lo subimos al marco para ejecutarlo?. Pues bien entre otros comandos el marco tiene dos, el tftp y wget para descargar ficheros mediante el protocolo tftp y http respectivamente, por tanto hay que instalar un servidor web o tftpd en nuestra máquina linux.
Servidor web apache:
1 |
sudo apt-get install apache2 |
Servidor tftp: Instrucciones
Si hemos optado por el servidor web sólo hay que copiar el fichero holamundo al directorio /var/www. Si la elección ha sido tftpd entonces hay que copiar el fichero holamundo al directorio que se haya configurado.
Ahora tenemos que descargarlo desde el marco digital. Hacemos un telnet como explicaba en el anterior artículo. En el firmware actual todo el disco está montado como sólo lectura, por lo que tendremos que remontarlo como escritura también de la siguiente forma:
1 |
mount / / -o remount,rw |
Ahora nos vamos al directorio /tmp y descargamos el programa.
Para tftp el comando sería:
1 |
tftp -g -r holamundo <IP DEL SERVIDOR TFTP> |
Para wget el comando sería:
1 |
wget http://<IP DEL SERVIDOR WEB>/holamundo |
Ahora que tenemos el fichero, hay que darle permisos de ejecución y finalmente ejecutarlo:
1 2 |
chmod a+x holamundo ./holamundo |
Obtendremos esto:
Ya hemos compilado nuestro primer programa y lo hemos hecho funcionar, pero claro, nos interesa que se pueda dibujar en la pantalla algo para ver cómo se ve en el marco. Lo primero que hay que saber es que la pantalla tiene asignado el dispositivo /dev/fb0 y que lo que tenemos que conseguir es acceder a su memoria para escribir directamente los colores. Esto se consigue de la siguiente forma:
Con la función open abrimos el dispositivo como lectura/escritura:
1 |
int g_fb = open("/dev/fb0", O_RDWR); |
Con la función ioctl recibimos en una estructura información sobre la pantalla:
1 2 |
struct fb_var_screeninfo var_info; ioctl(g_fb, FBIOGET_VSCREENINFO, &var_info); |
Con la función mmap obtenemos el buffer de la memoria de vídeo para leerlo y escribir en el:
1 |
char *buffer = (char *)mmap(0, 153600, PROT_READ|PROT_WRITE, MAP_SHARED, g_fb, 0); |
Ahora sólo queda dibujar los bytes en la memoria para que se vean reflejados como pixeles en la pantalla. Al poder representar la pantalla 64k colores estos se codifican a RGB mediante 16 bit con el formato 5-6-5 (rrrrrggggggbbbbb). Así el rojo es 1111100000000000 (0xF800), el verde es 0000011111100000 (0x07E0) y el azul es 0000000000011111 (0x001F). Por tanto cada pixel en la pantalla ocupa 16 bits.
Para probar todo esto he creado un programa que muestra un cuadro verde rebotando por el marco usando la técnica de doble buffer para evitar parpadeos:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
#include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <linux/fb.h> #include <sys/mman.h> #include <sys/ioctl.h> char *inicializa(int *cuantos) { char* buffer; int g_fb; struct fb_var_screeninfo var_info; g_fb = open("/dev/fb0", O_RDWR); if (g_fb == -1) { printf("No se puede abrir /dev/fb0\n"); _exit(1); } printf("/dev/fb0 abierto con el handle 0x%x\n", (unsigned)g_fb); if (ioctl(g_fb, FBIOGET_VSCREENINFO, &var_info)) { printf("No se puede obtener la información variable de la pantalla\n"); _exit(1); } printf("xres: %d\n", var_info.xres); printf("yres: %d\n", var_info.yres); printf("bpp: %d\n", var_info.bits_per_pixel); *cuantos = var_info.xres * var_info.yres * var_info.bits_per_pixel /8; printf("El tamaño del buffer de pantalla es de %d bytes\n", *cuantos); buffer = (char *)mmap(0, *cuantos, PROT_READ|PROT_WRITE, MAP_SHARED, g_fb, 0); if ((int)buffer == -1) { printf("falló mmap().\n"); exit(1); } printf("Pantalla devuelta\n"); return buffer; } void cuadro(int x, int y, short int *buffer, int color) { int anchura; int altura; short int *puntero; for(altura = 0; altura < 50; altura++) { puntero = buffer + ((y + altura) * 320); for(anchura = 0; anchura < 50; anchura++) { *(puntero + x + anchura) = color; } } } void main(void) { int indice; int cuantos; int x = 0; int y = 0; int suma_x = 1; int suma_y = 1; short int *buffer = (short int *)inicializa(&cuantos); short int *ventana = (short int *)malloc(cuantos); if (ventana == NULL) { printf("No se puede crear el doble buffer\n"); _exit(1); } // fondo negro for(indice = 0; indice < (cuantos / 2); indice++) { buffer[indice] = 0; } for(;;) { usleep(10000); cuadro(x, y, ventana, 0); x += suma_x; y += suma_y; if(x > 269 || x < 0) { suma_x *= -1; x += suma_x; } if(y > 189 || y < 0) { suma_y *= -1; y += suma_y; } cuadro(x, y, ventana, 0x7E0); memcpy(buffer, ventana, cuantos); } } |
Que ejecutándolo quedaría así:
En un próximo artículo explicaré como acceder a la interfaz con SDL, comunicarse con bluetooth mediante RFCOMM y obtener los valores de los botones traseros y del inclinómetro.
Edición 12/02/2012: