Compilando Qt e aplicações gráficas em Linux embarcado
- por Sergio Prado
Cada vez mais temos equipamentos embarcados com interfaces de vídeo disponíveis. Hoje é comum displays LCD embutidos no equipamento, alguns deles com interface touch screen. Em alguns casos temos disponível um controlador de vídeo, que pode ser VGA, DVI ou HDMI, e um conector para ligar um display externo.
E trabalhar com displays gráficos em Linux não é algo de outro mundo. Exige que você conheça alguns conceitos, sabia preparar seu kernel corretamente, escolher e cross-compilar uma biblioteca de interface gráfica (você não vai querer reinventar a roda, certo?), e aprender a usá-la.
Mas antes de colocar a mão na massa, vamos estudar alguns conceitos.
A ARQUITETURA
Se cada interface ou placa de vídeo tivesse seu driver e sua específica API, imagina o trabalho que seria para as aplicações ou bibliotecas que precisam acessar diretamente o vídeo, como media players ou bibliotecas de interface gráfica como Qt ou GTK. Elas precisariam implementar a API de acesso a cada placa de vídeo. Você poderia ver notícias do tipo: “Nova versão do MPlayer agora suporta NVidia GeForce 9800 GT!”.
Ainda bem que as coisas não são bem assim, porque existe em Linux o conceito de frame buffer, que é uma camada de abstração entre os drivers da placa de vídeo e as aplicações e bibliotecas que precisam acessá-la.
Se existe então um driver de frame buffer disponível para a sua placa de vídeo, é garantido que aplicações e bibliotecas compatíveis com frame buffer irão funcionar.
VÍDEO EM LINUX DESKTOP
Sistemas desktop possuem uma arquitetura mais complexa. Normalmente trabalham com o Servidor X (também chamado de X11 ou X Window System), que é uma camada de software para trabalhar com interfaces gráficas. O Servidor X pode acessar as placas de vídeo de 2 formas: através de frame buffers, ou acessando diretamente o driver da placa de vídeo. Em cima do Servidor X roda normalmente um gerenciador de janelas como o Gnome e o KDE.
Então a arquitetura fica mais ou menos assim: o gerenciador de janelas (Ex: Gnome ou KDE) acessa as bibliotecas disponibilizadas pelo Servidor X, que então acessa a interface de vídeo através de um frame buffer ou conversando diretamente com o driver da placa de vídeo.
Esta não é normalmente a arquitetura que temos em um equipamento com Linux embarcado, principalmente pelos recursos de memória e processamento que serão necessários para incluir todas as bibliotecas necessárias (pode chegar a consumir 100Mb de flash e 20Mb de RAM apenas para ter um Gnome embarcado no seu equipamento!).
Precisamos então de uma solução mais leve para equipamentos embarcados.
VÍDEO EM LINUX EMBARCADO
Todas as soluções para Linux embarcado são baseadas na arquitetura do frame buffer. Algumas bibliotecas fornecem funções de acesso direto ao frame buffer como a SDL e a OpenGL ES. Já outras bibliotecas, além do acesso ao frame buffer, possuem um sistema de janelas completo para o desenvolvimento de interface gráficas, como é o caso do GtkFB e do Qt.
O Qt, que será nosso foco a partir de agora, é um framework multiplataforma para o desenvolvimento de interfaces gráficas. Desenvolvido em C++, é a biblioteca usada pelo gerenciador de janelas KDE.
A plataforma Qt foi criada pela Trolltech em 1995. No ano de 2000, a Trolltech liberou uma versão do Qt para sistemas embarcados, chamada de Qtopia ou Qt/Embedded, que ajudou a disseminar seu uso em dispositivos móveis. Em 2008, a Trolltech foi adquirida pela Nokia, que criou a divisão Qt Development Frameworks para cuidar do desenvolvimento desta plataforma.
Ainda em 2008, o Qtopia virou Qt Extended, com um modelo voltado para PDAs e celulares, mas não durou muito. Em 2009, a Nokia descontinuou o Qt Extended, unificando suas principais funcionalidades dentro da biblioteca do Qt. Mas como o Qtopia era liberado sob a licença GPL, o comunidade Openmoko criou um fork do projeto, e chamou de Qt Extended Improved.
Que tal agora um pouco de ação? Utilizaremos aqui a última versão do Qt para Linux embarcado liberado pela Nokia. Vamos cross-compilar o Qt V4.7.1 e uma aplicação de exemplo para rodar no kit FriendlyARM mini2440.
CROSS-COMPILANDO O QT
Sua primeira tarefa é seguir os passos deste artigo aqui. Só que, antes de compilar, habilite também as opções abaixo:
Toolchain ---> [*] Build/install c++ compiler and libstdc++? Package Selection for the target ---> Graphic libraries and applications (graphic/text) ---> [*] Qt ---> [*] Compile and install demos and examples (with code) Mouse drivers ---> [*] tslib |
Depois de compilado, grave o kernel na flash seguindo os procedimentos deste artigo aqui, e monte um sistema de NFS conforme explique neste outro artigo aqui.
Para verificar se o Qt compilou corretamente, na console da mini2440 execute a aplicação abaixo:
$ /usr/share/qt/examples/qws/framebuffer/framebuffer |
Você deverá ver 3 retângulos na tela (vermelho, verde e azul), conforme imagem abaixo. Se der algum problema, verifique se todos os procedimentos foram executados corretamente.
CONFIGURANDO E TESTANDO O TOUCH SCREEN
Antes de desenvolver sua primeira aplicação em Qt, vamos configurar e testar a interface touch screen.
Primeiro, altere o arquivo “/etc/ts.conf” e tire o comentário da linha “module_raw input“. Depois, coloque em um script de inicialização os comandos abaixo:
export TSLIB_TSEVENTTYPE=INPUT export TSLIB_CONSOLEDEVICE=none export TSLIB_FBDEVICE=/dev/fb0 export TSLIB_TSDEVICE=/dev/input/event1 export TSLIB_CALIBFILE=/etc/pointercal export QWS_MOUSE_PROTO=tslib:/dev/input/event1 |
Agora, vamos calibrar o display. Execute o comando abaixo:
$ ts_calibrate |
Você precisará tocar no cursor exibido na tela algumas vezes para calibrar corretamente o touch screen. Depois você pode testá-lo com o comando abaixo:
$ ts_test |
Pronto, agora só falta sua aplicação!
CROSS-COMPILANDO UMA APLICAÇÃO
Nossa aplicação será um simples botão a ser exibido com a mensagem “Hello Embedded World!“. Salve o código abaixo em um arquivo chamado “hello.cpp“.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#include "QtGui" int main(int argc, char *argv[]) { QApplication app(argc, argv); QPushButton hello("Hello Embedded World!"); hello.resize(200, 60); hello.show(); return app.exec(); } |
Para compilar, vamos criar um shell script:
#!/bin/bash QT_DIR=/opt/buildroot/buildroot-2010.11/output/build/qt-everywhere-opensource-src-4.7.1 QMAKE=$QT_DIR/bin/qmake SPECS=$QT_DIR/mkspecs/qws/linux-arm-g++ $QMAKE -project -o hello.pro $QMAKE -spec $SPECS -o Makefile hello.pro make |
Altere a variável QT_DIR para o diretório do seu ambiente do Buildroot. Execute o script, e você terá a aplicação “hello” em Qt pronta para ser executada na mini2440.
Copie a aplicação para o rootfs da mini2440, mas antes de executá-la, você precisa entender um conceito importante do Qt para Linux embarcado. Ele trabalha numa arquitetura cliente-servidor. É o servidor que trata os eventos e notifica as aplicações-cliente. Uma explicação mais completa sobre a arquitetura do Qt pode ser encontrada aqui.
Apenas um servidor pode estar rodando ao mesmo tempo, e qualquer aplicação pode ser o servidor. Para iniciar uma aplicação como servidor, basta passar o parâmetro “-qws“. Como nossa aplicação é a única aplicação Qt rodando, é o que faremos:
$ /usr/bin/hello -qws |
Pronto! Eis sua primeira aplicação Qt rodando na mini2440:
Agora é só aprender sobre a rica e extensão API do Qt e usar sua imaginação!
Enquanto escrevia este artigo, o Thiago Costa, leitor do blog, me enviou um documento bem completo sobre a configuração do Qt na mini2440, só que com uma abordagem diferente da minha. Ele documentou o procedimento completo para pegar o kit com o Qtopia instalado e reconfigurá-lo para usar o Qt. Vale a pena dar uma olhada, o documento esta disponível aqui.
Um abraço e boa diversão!
Sergio Prado