Visor com FreeBSD

Autor: Emilio Florido
Data: 2/05/2003


A idéia inicial

Em meu trabalho mantemos uma sede Web (alojada numa máquina FreeBSD) na que se mostram entre outros, avisos e notícias próprias de nossa atividade (armazenados numa base de dados postgres). Se me ocorreu que poderia ser interessante, mostrar parte dessa informação num monitor exposto ao público. Algo bem como um painel dos que há nos aeroportos com informação dos vôos, mas no que "rotaran" os textos e com letras bastante maiores. Ao final do artigo podes ver algumas fotos do "visor" (que assim é como o chamarei doravante) já funcionando.

Afinando o projeto

Num princípio não tinha demasiado claro como montar o visor. Mesmo assim, algumas coisas pareciam indiscutíveis. Por uma parte, a máquina que o suportasse deveria estar conectada a nossa rede interna de forma que pudesse aceder à base de dados com a informação. Por outra parte, não deveria ter nem teclado nem rato, pois o único que se pretende dela é que mostre a informação "que se lhe diga" e não que seja "operada" por nenhum dos usuários da rede (ainda que mais adiante, e como ampliação, se que os usuários também podem manipular alguma que outra coisa, mas disto se fala bastante mais adiante).

Também tinha outra coisa clara... unicamente estava disponível um 486DX66, com 12 MBytes de RAM e 420 MBytes de disco duro para o visor, assim que as possibilidades já estavam bastante mais acotadas.

Com isto em mente, rapidamente se podem descartar sistemas operativos tipo Windows, pois ou bem carecen praticamente de gestão remota, ou bem se dispõem dela é praticamente impossível fazer que funcionem numa máquina com as características da já mencionada.

Também não Linux é demasiado apropriado. Se que a mais de um lhe doerá isto, mas o certo é que conquanto é possível instalar Linux neste tipo de máquinas (aliás, em meu trabalho uso uma máquina como a anterior -mas com bastante mais memória e disco- que faz de proxy para outras 4), fazer que ademais funcione o meio gráfico (X-Windows como eu queria) é muito difícil, pois a "voracidade" de cor de Linux o impede. Suponho que terá alguma forma de fazer que Linux não comece a " paginar" ao disco de forma crítica ao arrancar o meio gráfico e ao procesador não lhe fique tempo para nada mais, mas eu desde logo não o consegui. De todas formas, sempre estou aberto a qualquer comentário ou sugestão ao respecto, já que também não sou nenhum "gurú" de Linux nem o objeto deste artigo é uma "luta" entre Linux e FreeBSD.

O caso é que por tanto, meu melhor candidato era (e é) FreeBSD. Dito de outra forma, com FreeBSD me foi possível, num 486DX66 com 12 MBytes de RAM e 420 MBytes de disco duro, instalar todo um sistema operativo multitarea/multiusuario, gestionable remotamente sem problemas, e ademais ter funcionando X-Windows como meio gráfico (olho, refiro-me só a X-Windows e não a ter ademais um gestor de janelas como possa ser KDE ou Gnome, que aliás, não são necessários para nada neste projeto).

A instalação

A não ser que alguém tenha um interesse especial em " sofrer" e passar várias horas brigando-se com um 486 para instalá-lo desde zero com FreeBSD, eu aconselharia (ou ao menos é o que eu fiz) desmontarle o disco duro ao 486 , levá-lo a um computador "decente", e realizar a instalação nele  (eu também estava condicionado porque o 486 em questão não dispõe sequer de leitor de CD's).

Durante a instalação do visor não crio que tenha muito que destacar. Unicamente selecionei "O sistema mínimo", o "Suporte para X-Windows" e os pacotes "wget" e "unclutter" (depois verás para que fazem falta). Também não crio que seja necessário incluir nada mais para este projeto (me refiro a coisas como a documentação, os ports, o suporte criptográfico, etc.) e assim fica espaço mais do que de sobra no disco. De todas formas, e por se a alguém lhe interessa, aí vai o reparto que fiz de particiones e a ocupação que atualmente tem o disco tal qual as mostra df -h

Filesystem    Size   Used  Avail Capacity  Mounted on
/dev/ad0s1a  47M        31M    13M    71%    /
/dev/ad0s1f    63M   6.0K    58M     0%    /tmp
/dev/ad0s1g   244M   182M    43M    81%    /usr
/dev/ad0s1e    63M   1.2M    57M     2%    /var
procfs        4.0K   4.0K     0B   100%    /proc

Por certo, usei FreeBSD 4.5, mas não por nada em especial, mais bem porque eram os CD's que tinha mais a mão; imagino que qualquer outra versão servirá exatamente igual de bem que esta concreta.

Após instalado FreeBSD, chega o momento de voltar a desmontar o disco duro do computador "decente" e levá-lo de novo ao 486

. Configuração

De volta ao 486 , FreeBSD deveria arrancar sem problemas e seria o momento de configurar-lhe o suporte de rede e o meio gráfico.

Respecto ao suporte de rede, não crio que tenha nada que comentar; bastará com dar-lhe um nome apropriado (que tal visor?), sua direção IP e pouco mais.

Quanto ao meio gráfico a coisa muda. Se como neste caso se trata de um 486 "entradito em anos", o habitual é que seu cartão gráfico esteja em consonância (me refiro a que seguro que NÃO será uma com 256MBytes de RAM e um procesador gráfico de 700 MHz). Eu recorri a uma resolução de 640x480 e com só 16 cores, e aliás, ao final só usei três cores... é dizer, que não há muito que afinar e que deveria ser relativamente singela a configuração.

Por outra parte, algo que não está demais é passar-se pelo apartado dos serviços que estão funcionando continuamente na máquina e tratar de deshabilitar todos os que não vão servir (por exemplo, sendmail) ou deixar unicamente um par de consolas em lugar de tantas como há por defeito. Quiçá se poderia pensar em recompilar o núcleo e afiná-lo para a máquina em questão ainda que neste caso, desde logo recomendaria encarecidamente fazê-lo sobre outro computador e não sobre o próprio 486...

Também seria um bom momento para criar um usuário para que logo seja o que execute os processos que mostrarão as mensagens pelo visor. Tudo bom chamá-lo também visor?

Problemas a resolver

Supondo que o visor já está instalado e configurado (meio gráfico incluído) terá que resolver algum que outro problema relativo a este projeto concreto:

Vejamos como resolver estes problemas.

Arranque desatendido e contentando a X-Windows

Ainda que habitualmente é mais singelo ir resolvendo os problemas de um num, neste caso resolvê-los juntos é mais fácil. Dá primeiro um vistazo ao seguinte script situado em usr //local/etc/rc.d que chamei X.sh e logo vemos os detalhes:

#!/bin/sh
# Emilio (24-3-03)
case $1 in
      start)
            seu visor -c "/usr/X11R6/bin/Xwrapper -allowMouseOpenFail" &
            sua visor -c "/usr/X11R6/bin/unclutter -display 127.0.0.1:0" &
            seu visor -c /home/visor/controle  
            ;;
      stop)
            # nada por  agora
            ;;
      *)
            echo "Uso: $0 {start | stop}"
            ;;
esac

Um primeiro detalhe a ter em conta é que o nome do script pode ser o que queiras, mas deve terminar em . sh , pois por segurança, o sistema NÃO o executará estando situado em usr //local/etc/rc.d a não ser que se cumpra esta condição (o que tenha permissões de execução -ainda para todos os usuários- não é suficiente).

Por outra parte, outros detalhes poderiam ser:

Xterm a medida

Logicamente, os "fontes" das letras que se costumam mostrar num xterm "normal" não são como para vê-las desde longe. Já que aqui o que se pretende é que se possa ler facilmente uma frase desde uma distância mais do que razoável do monitor (entre 3 e 7 metros) terá do que atuar sobre o tamanho das "fontes". Não todas as "fontes" disponíveis admitem aumentar seu tamanho "indiscriminadamente" e algumas que se o permitem, logo ou bem estão demasiado "pixeladas" ou bem apresentam demasiada separação entre cada uma das letras.

Ainda que "a mão" se pode ir provando até dar com alguma apropriada, eu recomendo usar um programa como xfontsel e assim ver que se pode esperar de cada "fonte". Para usar este programa, basta com invocá-lo e "jogar" com suas diferentes opções até dar com a "fonte" apropriada.

Por certo, se não vês muitas "fontes" onde eleger, talvez queiras echar mão outra vez dos CD's de FreeBSD e incluir alguma mais, ainda que eu também não me aquentei demasiado a cabeça e com um par delas me tenho apañado. Concretamente, usei uma para a cabeceira e o pé, e outra para o centro... claro que para ver de que vai isto de cabeceira, pé e centro, lê o seguinte apartado.

Disposição da tela

Ainda que se poderiam idear centos de formas de distribuir a tela que mostrará no visor, eu pensei no seguinte. Queria ter 3 linhas de texto ao todo. Uma primeira, com capacidade para umas 10 letras que chamarei "cabeceira". Uma intermédia, com capacidade para 15 letras que chamarei "centro" e uma terceira com capacidade para outras 10 letras que chamarei "pé".

Pela quantidade de letras que cabem em cada uma das linhas te poderás fazer uma idéia do tamanho das mesmas, sobretudo se consideras que normalmente num xterm cabem 80 carateres por linha e que costuma ter lugar para umas 24 linhas. De todas formas, se não te fica claro, aí vai um esquema de como dividi a tela do monitor do visor:

linha de cabeceira (10 letras)
 

linha de centro (15 letras)

 

linha de pé (10 letras)

Como vês, em meu desenho, tanto a linha da "cabeceira" como a do "pé" são bastante menores que a do "centro".

A ver se me explico melhor, o que pretendo fazer é pôr em marcha simultaneamente 3 xterm no meio X-Windows com umas dimensões e situação apropriadas como para que entre os 3 cubram o área total da tela Cada xterm irá apresentando a informação que se lhe indique e esta irá movendo-se de forma que as letras que formem a frase em questão irão desaparecendo pela esquerda e aparecendo pela direita, a modo de " fita sem fim" ou bem irão alternando-se uns texto por outros (como por exemplo a data e a hora).

O script de controle

Faz um par de apartados falava do script  /home/visor/controle que se põe em marcha justo após arrancar o meio gráfico. Agora é o momento de ver para que serve. Mas antes, aí vai:

#!/bin/sh
# Emilio (24-3-03)
#Cabeceira
/usr/X11R6/bin/xterm -display 127.0.0.1:0
       -geometry 11x1+0+0 -bg black -fg green -cr '#000011'
       -fn '-b&h-lucidux serif-medium-r-*-*-85-*-72-100-*-*-iso8859-1'
       -e /home/visor/cabeceira &
#Centro
/usr/X11R6/bin/xterm -display 127.0.0.1:0
       -geometry 16x1+0+105 -bg black -fg white -cr '#000011'
       -fn '-*-lucidatypewriter-*-r-*-*-225-*-*-*-*-400-iso8859-1'
       -e /home/visor/centro  &
#Pé
/usr/X11R6/bin/xterm -display 127.0.0.1:0
       -geometry 11x1+0+367 -bg black -fg rede -cr '#000011'
       -fn '-b&h-lucidux serif-medium-r-*-*-88-*-72-100-*-*-iso8859-1'
       -e /home/visor/pé &

Em realidade não são mais do que três linhas, a razão de uma por cada um dos xterm que se arrancarão. TENHO-AS identado de forma que destaque que para cada um deles ajustei:

Começando com o pé

Já que em meu caso concreto o script que controla a informação que se mostra na linha do pé é o mais singelo, começarei por ele. Como sempre, primeiro o código:

#!/bin/sh
# Emilio (24-3-03)
while %[ t ]
do

#  n=1
#  while %[ $n -lt 8 ]
#  do 
#    clear
#    echo -n " "`date "+%H:%M:%S"`
#    n=`expr $n + 1`
#    sleep 1
#  done 

  clear
  echo -n "   "`date "+%H:%M"`
  sleep 3

  clear
  echo -n "   I.E.S."
  sleep 2 

  clear
  echo -n "O Majuelo"
  sleep 4

  clear
  echo -n `date "+%d/%m/%E"`
  sleep 5
done

Como vês, este script faz unicamente três ou quatro coisas e as repete em tanto a máquina esteja em funcionamento. Por uma parte, mostra a hora durante 3 segundos, logo mostra um texto durante dois segundos, outro texto durante 4 segundos e logo a data durante cinco segundos.

Uma observação sobre o mesmo poderia ser que como vês o texto completo a mostrar no pé ("I.E.S. O Majuelo" neste caso) o tenho desglosado em duas partes. O motivo é singelo, na linha do pé cabem unicamente 10 letras e como o texto mede mais, não se veria inteiro.

Por outra parte, se te fixaste há várias linhas comentadas. O motivo é bastante mais rebuscado. Quando criei o script pensei em mostrar a hora com seus minutos e segundos durante algum tempo, é dizer, pretendia que na linha do pé se vissem decorrer os segundos durante um certo tempo após ter visto os textos e a data. Lamentavelmente, na máquina real (um  486DX66) e com todo os processos executando-se não tem potência suficiente como para atualizar a razão de um segundo, pelo que os segundos iam a saltos (em lugar de ir de um num iam de três em três ou a vezes inclusive pior). Por isso ao final optasse por apresentar unicamente a hora e os minutos... ainda que deixei as linhas comentadas por se tens uma máquina mais potente e queres criar esse efeito.

Projetando a cabeceira e o centro

Se te fixaste, para trabalhar com o pé não foi necessário mais do que um processo e do que não requer nenhuma informação adicional. No entanto, para a cabeceira e o centro tinha outras idéias. Na linha de cabeceira pretendia que se apresentasse uma linha a modo de resumo do que se veria na linha de centro. Por exemplo, se na cabeceira pusesse "Plano de reuniões", na linha de centro poderia pôr "As próximas reuniões do ETCP se celebrarão o mês de maio . Como tanto a linha de cabeceira como a de centro têm mais letras das que realmente cabem no visor, estas frases deverão ir "girando" pela tela a uma velocidade razoável como para poder lê-las. Ademais, como terá variadas destas frases, pensei em que cada uma delas se mostrasse um par de vezes antes de que outra a substituísse.

Por outra parte, o conteúdo das frases (tanto da cabeceira como do centro) deveria "sair" da base de dados postgres em onde armazenamos todo este tipo de informação. Desta forma o visor não precisa uma manutenção adicional por parte de nenhum usuário, e inclusive melhor, nem do administrador :-)

Em lugar de complicar os script tanto da cabeceira como do pé com as consultas à base de dados, preferi dar por sentado que num diretório do visor estariam já os textos a mostrar e logo já veria como encheria esse diretório com a informação proveniente da base de dados.

Desta forma, o único que me ficava por resolver era como organizar a informação nesse diretório. Decidi que teria um fichero por cada um das mensagens a mostrar e que esse fichero teria uma primeira linha que seria o texto que se mostraria na linha de cabeceira e um resto de linhas que seria o texto que se mostraria na linha de centro.

Se te perguntas que porquê precisamente assim, pois porque num fichero com esta distribuição basta com usar comandos tão "simplones" como head ou tail para poder extrair por separado a cabeceira (é dizer, o resumo) e o centro (é dizer, o detalhe) de cada um  das mensagens.

Ademais, decidi que cada um destes ficheros se chamasse visorXX.txt sendo XX um número de ordem, já que desta forma é fácil processá-los juntos (fazendo uso de comodines) ou separados (fazendo uso do número de ordem). Por certo, se te perguntas que número de ordem?, pois algo tão singelo como o mesmo número que a base de dados postgres lhe vai dando ao ir inserindo os registos nela.... de todas formas, disto já falarei mais adiante. Por agora, basta com saber que num diretório determinado do visor estarão os ficheros preparados da forma que comentei e prontos para apresentar-se pela tela do visor.

Alguns pequenos detalhes

Já comentei várias vezes que pretendo apresentar tanto a linha de cabeceira como a do centro "girando" no monitor do visor. Claro que para isto vão ser necessárias um par de funções em C às que chamar desde os scripts da cabeceira e o centro. A primeira delas a chamei longitude.c  e é esta:

//Emilio (24-3-03)
#include <stdio.h>
int  main (int argc, char **argv)
{
  if (argc != 2)
   {
      fprintf(stderr, "\n\tuso: %s corrente\n", *argv);
      return (-1);
   }
  else
   { 
      fprintf(stdout,"%d", strlen(argv%[1]));
      return (0);
 }
}

Como vês, nem por sua longitude nem por sua complexidade deveria ter o mais mínimo problema para compilá-la e conseguir do que funcione; prova a teclear:

gcc longitude.c -ou longitude

e verás que é verdade. Se queres provar o que faz, passa-lhe como parâmetro uma corrente e observa que devolve o número de carateres que a formam.

A segunda é algo mais complexa e a chamei desloca.c  . Aí vai a listagem e logo a comento:

// Emilio (24-3-03)
#include <stdio.h>
int main(int argc, char *argv[]%)
{
   int janela, posicion, longitude, i, posCar;
   char *corrente;
   if (argc != 4)
     {
        fprintf(stderr, "\n\tuso: %s janela posição corrente\n", *argv);
        return (-1);
     }
   janela=atoi(argv%[1]);
   posicion=atoi(argv%[2]);
   corrente=argv%[3];
   longitude=strlen(corrente);
   if (longitude<janela)
      {
        corrente=(char *) malloc(janela+1);
        strcpy(corrente,argv%[3]);
        for (i=longitude; i<janela; i++)
           corrente%[i]=' ';
        corrente%[i]='\0';
        longitude=janela;
      } 
   for (i=0; i<janela; i++)
         printf("%c",corrente%[(posicion+i)%longitude]);

   return 0;
} 

Compilá-la deveria ser tão fácil como a anterior. Teclea:

gcc desloca.c -ou desloca

Respecto a seu funcionamento há que ter em conta que neste caso se exigem três parâmetros de entrada, a saber: por uma parte o número de carateres que devem mostrar-se em tela, a posição a partir da qual se começarão a mostrar carateres e por último a corrente sobre a que se trabalhará.

A ver se com um par de exemplos consigo explicar o que faz esta função. Imaginemos que a corrente de entrada seja "As próximas reuniões do ETCP se celebrarão o mês de maio." e que está armazenada numa variável chamada $texto . Desta forma:

/home/visor/desloca 15 4 "$texto"

daria como resultado "próximas reunio". Façamos outra prova:

/home/visor/desloca 15 51 "$texto"

que dá como resultado "s de maio.As p"

Imagino que se entende a idéia. A função desloca.c  devolve a sua saída uma parte da corrente que se lhe dá a sua entrada deslocada um número de carateres determinado contados desde o começo da mesma. Ademais, em lugar da corrente inteira mostra unicamente o número de carateres que se lhe indiquem. Em caso que a corrente de entrada "se lhe acabe" ao ir mostrando carateres, os que lhe faltam os tomada de novo do princípio da corrente

Também está previsto o caso de que a corrente de entrada seja mais corta do que a longitude que se pretende mostrar. Isto é imprescindível, pois por exemplo, há casos nos que a linha de cabeceira é uma só palavra e mede menos do número de carateres que se pretende mostrar. Por exemplo, se a frase de entrada fosse "Reunião" e se executa:

/home/visor/desloca 11 3 "Reunião"

devolverá "nión     Reu"

Tratando a linha da cabeceira

Já é o momento de ver como com ajuda das duas funções anteriores criei o script que controla o funcionamento da linha da cabeceira Aí vai o script:

#!/bin/sh  
# Emilio (24-3-03)

textoanterior="xxxxx"
l=0

while %[ t ]
do
  texto=`/usr/bin/head -n 1 /home/visor/visor/mostrar.txt`
  if %[ "$texto" != "$textoanterior" ]; then
    clear 
    longitude=`/home/visor/longitude "$texto"`
    textoanterior=$texto
    l=0
  fi
  echo -n "`/home/visor/desloca 11 $l "$texto"`"
  l=`expr $l + 1`
  l=`expr $l % $longitude`
  sleep 1
done 

como vês, em tanto esteja a máquina funcionando este script estará funcionando. Isso se, há mais de um detalhe a ter em conta.

Por uma parte, mais arriba comentei a estrutura que teriam os ficheros com as frases a mostrar nos que a primeira linha dos mesmos seria o texto para a cabeceira. De aí o comando head -n 1  , mas o que também disse é que os ficheros se chamariam visorXX.txt e agora resulta que no script se faz referência a um fichero chamado mostrar.txt . Explicarei isto no apartado seguinte junto com o sentido da variável $textoanterior

Pelo demais, quiçá o mais interessante resulta do que não se vê. A linha:

echo -n "`/home/visor/desloca 11 $l "$texto"`"

leva justo entre as primeiras comillas dobres e a primeira comilla singela um caráter de " Escape" mais um caráter 0x0D, é dizer, um retorno de carro que lamentavelmente não se vê neste texto (se usas vi como editor, consegue-se pulsando CNTRL+X, 1B, CNTRL+X, 0D ) . Para que serve?. Pois verás, como a posição na que se mostra a frase vai mudando por cada volta que dá o bucle, se se faz um clear para "limpar" uma posição concreta de uma frase antes de apresentar a nova posição, o parpadeo que resulta em tela é inaceitável. Tem em conta que os carateres são muito grandes e que qualquer processo lento (e clear o é) leva um tempo que um 486 não se pode permitir... por tanto, recorri a " sobreescribir" uma posição concreta de uma frase em cima da anterior com tão só incluir o caráter 0x0D justo ao princípio de cada impressão. Se te fixas verás que só se faz clear quando se produz a mudança de uma frase por outra, é dizer, quando se cumpre que "$texto" != "$textoanterior". De todas formas, como antes dizia, no apartado seguinte comentarei este detalhe.

O resto do código não tem maior complexidade, vai-se incrementando uma variável (chamada $l) à que se lhe calcula o módulo (é dizer, o resto de sua divisão inteira) com sua longitude de forma que ao ir variando a posição de começo da frase a mostrar faça que pareça que "gira" indefinidamente. A ver, mais claro, se a longitude do texto a apresentar fosse cinco, a variável $l iria tomando os valores 0,1,2,3,4,0,1,2,3,4,0...

Problemas de sincronismo

Esta claro que FreeBSD é multitarea. Por tanto, se se lançam três processos xterm como neste caso, cada um deles com um scritp associado, não há nenhuma garantia de que o que ocorra num deles sucederá antes ou após o que suceda em outro. Para o processo do pé não há problemas, pois a informação que nele se mostra não guarda relação mais do que com a data e a hora e não com o que ocorra nos outros processos xterm.

Desafortunadamente, não se pode dizer o mesmo dos processos que controlam a cabeceira e o centro. Como na cabeceira pretendo que tenha um "resumo" do que há no centro, logicamente, se muda a informação que se mostra no centro, deverá mudar a informação da cabeceira.

Ainda que imagino que se poderia recorrer às ordens trap e kill da shell para enviar sinais de um processo a outro e sincronizá-los (prova a teclear help trap e help kill), preferi que seja o processo do centro o que determine que frase se tem de mostrar e que o processo da cabeceira ao "notar" que o centro decidiu mostrar outra frase, o também obre em conseqüência. e mostre outra linha na cabeceira.

Para isto, o processo do centro o que fará, justo ao começar, será criar uma cópia de um dos ficheros com as frases a mostrar -os que se chamam visorXX.txt- sobre um fichero chamado mostrar.txt e a partir de aí, sempre trabalhará com ele. O processo da cabeceira por sua parte trabalhará sempre com o fichero mostrar.txt claro que umas vezes terá um conteúdo e outras vezes outro (este era o fim da variáveis $texto e $textoanterior que comentava no apartado anterior). O momento da mudança o determinará o processo do centro quando copie um novo fichero visorXX.txt sobre o mesmo fichero mostrar.txt

Isto fará que se alguém está muito pendente da cabeceira, notará que ao mesmo instante em que muda a linha do centro não mudou a linha da cabeceira se não que a mudança ocorrerá um instante depois... de todas formas, não crio que ninguém até agora se tenha dado conta deste detalhe no visor real, mas em fim...

Tratando a linha do centro

Agora que já comentei o fato de que ainda tendo muitos ficheros do tipo visorXX.txt o processo do centro copia um deles sobre o fichero mostrar.txt e trabalha unicamente com ele, não crio que a seguinte listagem tenha demasiados mistérios:

#!/bin/sh
# Emilio (24-3-03)

# número de  vezes que se mostra a mesma mensagem
vezes=2

while %[ t ]
do
  clear
  echo -n "IES O Majuelo"
  /home/visor/obtienedatos
  for i in `ls /home/visor/visor/visor*.txt`
  do
    clear
    cp -f $i /home/visor/visor/mostrar.txt
    
    texto=`/usr/bin/tail -n +3 /home/visor/visor/mostrar.txt`
    longitude=`/home/visor/longitude "$texto"`
    l=0
    v=0
    vt=`expr $longitude '*' $vezes`
   
    while %[ $v -lt $vt ]
    do
      echo -n "`/home/visor/desloca 15 $l "$texto"`"
      l=`expr $l + 1`
      l=`expr $l % $longitude`
      v=`expr $v + 1`

#  sleep 1 

#  espera=0 
#  while %[ $espera -lt 300 ]
#  do
#   espera=`expr $espera + 1` 
#  done

    done
  done
done 

A única variável ajustable deste processo é $vezes que permite fazer que cada frase que mostra na linha do centro passe "girando" pelo visor o número de vezes que se deseje antes de que seja substituída por outra. Na prática, duas é um número muito razoável para ela.

Por outra parte, chama-se a um processo chamado obtienedatos, mas dele falarei no apartado seguinte.

Seguidamente, com ajuda do comando tail se extraem do fichero com a frase a mostrar todas suas linhas exceto a primeira e a segunda. A primeira está claro que não deve usar-se pois é a cabeceira, mas e a segunda? porquê não a usar?... O motivo é mais bem de comodidade... quando explique o apartado seguinte, verás que parte da culpa a tem a base de dados postgres. Baste por agora com saber que a linha segunda está em alvo

O resto do código é praticamente o mesmo que o da cabeceira (inclusive com a mesma escusa dos carateres "Escape" e 0x0D que não se vêem no comando echo)

O que falta por comentar são precisamente as linhas que aparecem comentadas. O caso é que quanto mais rápido se execute o processo este do centro, mais rápido será o "giro" das frases na linha do centro. Se se trata de um 486 como em meu caso, com não adicionar nenhum retardo dá tempo suficiente para ir lendo as frases... mas se em lugar de um 486 tens outra máquina mais potente, terá que "frenarla" um pouco (ou aprender a ler muito depressa). Para isso podes ou bem usar o  sleep 1 (ainda que pessoalmente me parecia muito lento) ou bem um bucle de retardo ajustado "a olho" como o que tens também comentado no próprio script.

Como obter os dados

Bueno, pois com todo o anterior construído e supondo que existam os ficheros visorXX.txt com o formato já indicado e a informação apropriada no diretório oportuno (em meu caso  /home/visor/visor/ )  todo deveria a funcionar nada mais arrancar a máquina... mas, como se criam os ficheros visorXX.txt ?

Já comentei que meu objetivo era criar o visor de forma que ninguém tivesse que "mantê-lo" (a ser possível, nem sequer o administrador). Por tanto, a informação a deve obter da base de dados postgres em onde normalmente reside e os usuários já se dedicam a manter como parte de sua atividade diária.

Com objeto de simplificar ao máximo, dado que a informação que se mostra no visor também não é necessário que esteja atualizada ao segundo, e tendo em conta que o pobre visor não é mais do que um 486, recorri a um pequeno "truque".

Tenho "convencido" à máquina em onde reside a base de dados para que cada certo tempo (cada hora para ser exatos) extraia ela mesma os dados que o visor deverá apresentar e os "formate" com a estrutura que espera o visor encontrárselos. Desta forma, ao visor lhe basta com fazer um singelo ftp e recuperar os dados prontos para mostrá-los.

Por tanto, além do processo /home/visor/obtienedatos que comentava no apartado anterior e que agora exporei, será necessário ter outro processo correndo cada certo tempo na máquina que mantém a base de dados com a informação (deste outro processo falaremos mais adiante). Vejamos o script para obter os dados:

#!/bin/sh 
# Emilio (28-4-03)
#
rm /home/visor/diretor/visor/visor*.txt 2> /dev/null
cd /home/visor
/usr/local/bin/wget -q -t 1 -T 120 -r -nH --cut-dirs=1 -l 2
           ftp://diretor:password@servo//home/diretor/visor
if %[ -d /home/visor/diretor/visor ]; then 
  rm -r /home/visor/visor
  mv /home/visor/diretor/visor /home/visor/visor
fi

O "gordo" do processo o faz wget acedendo mediante ftp a um diretório da máquina que contém a base de dados e em onde espera encontrar os ficheros visorXX.txt com os dados que apresentará já convenientemente preparados.

Mesmo assim, há alguns detalhes que indicar. Por um lado, a quantidade imensa de parâmetros para wget fazem que se a conexão não pode realizar-se, não se fique todo detento, se não que passado um tempo prudencial o processo continue (ainda sem dados... logo comento isto). Também fazem que não se crê no visor toda uma estrutura de diretórios similar à da máquina remota, pois wget tem esta "mania" por defeito.... em fim, que com um simples man wget te podes inteirar de para que é cada parâmetro.

O resto de código serve para evitar que o visor se fique sem dados se tivesse algum problema ao aceder à máquina que deve dar-se. É dizer, o visor trata de procurar os dados para apresentar, se os consegue da máquina remota, esquece os que estava apresentando e os substitui pelos novos. Se não os consegue, segue apresentando os mesmos que já tivesse. Pensa que ao estar o visor exposto ao público, é preferible que mostre os mesmos dados variadas vezes (em tanto consegue realizar com sucesso a transferência) que deixar sua tela em alvo. Normalmente não tem por que fallar a transferência... e menos na rede interna, mas não está demais "curar-se em saúde".

Por outro lado, se te fixaste, verás que os dados se estão recuperando do diretório pessoal de um usuário chamado diretor mas, que pinta o diretor em todo isto?.

Usuários que podem mostrar mensagens

Já insisti várias vezes em que os dados se extraem de uma base de dados postgres e que o visor não precisa atendimento por parte de nenhum usuário... no entanto, em nosso caso, cada máquina da rede interna, usando samba dispõe (entre outras) de uma carpeta pessoal que as máquinas Windows vêem como uma carpeta que pendura de um de nossos servos. Nessa carpeta pessoal cada usuário pode armazenar dados próprios que permanecem "a salvo ainda que à máquina Windows lhe ocorra algo (já que realmente os dados se armazenam no servo e não na máquina Windows).

Desta forma, ao diretor lhe pareceu boa idéia que, além das mensagens que se encontram na base de dados postgres, ele pudesse adicionar os que estimasse conveniente. A ver se o explico melhor, o visor mostra tanto as mensagens que obtém de postgres como as mensagens que o diretor teclea desde sua máquina Windows.

Desde o ponto de vista do diretor o processo é tão simples como abrir "WordPad", teclear um fichero no que a primeira linha deve ser um resumo do que pretende contar, a segunda linha a deixa em alvo, e na terceira e seguintes pode escrever o que queira. Logo o armazena em seu carpeta pessoal (que está num de nossos  servos) e pronto... ao momento já se vê pelo visor (em realidade lhe fiz um acesso direto em seu escritorio Windows para que ainda lhe resulte mais singelo o acesso a seu carpeta pessoal).

O diretor pode criar tantos ficheros como queira com as únicas condições de respeitar o formato indicado, armazená-los como texto simples (de aí o uso de " WordPad" ou bem "Word" mas usando "Guardar como..." e elegendo como tipo "Texto sem formato") e que termine o nome do fichero em . txt (em realidade esta última condição não é indispensável, mas evita que se guarda alguma outra coisa nessa mesma carpeta por erro, ao menos não saia pelo visor...).

E como se consegue isto? Pois em realidade não é complexo. O que fiz é que seja o próprio usuário do diretor o que mediante crontab recupere os dados de postgres , a isto lhes adicione os seus convenientemente "retocados" e os deixe preparados para que visor os recupere cada vez que os precise.

Logicamente este processo se poderia estender para dar a possibilidade a outros usuários a mostrar mensagens no visor. Para conseguí-lo seria necessário ou bem ter uma carpeta comum a vários usuários e que tivessem todos eles permissões de escritura nela, ou bem fazer que o processo de obtenção de dados realizasse conexões ftp a todas as carpetas pessoais dos usuários que sejam necessário. Também se poderia prescindir completamente da complexidade que adiciona o permitir a determinados usuários inserir mensagens no visor, para o que bastará com que te esqueças deste último adicionado e passes ao ponto seguinte.

O script que crontab executa periodicamente na carpeta pessoal do usuário do diretor (e que chamei .obtém) é o seguinte:

#!/bin/sh
# Emilio (29-4-03)
#
# Obtém dados de  postgres e
# os do diretor
#
# Se situa no diretório em  questão
cd /home/diretor
#
# Obtém os dados de  postgres
/home/diretor/.obtienedatosvisor
# Obtém os dados do diretor
/home/diretor/.obtienefrasesvisor

Como vês, o único que faz este script é chamar a outros dois de forma que cada um de encarrega de uma só das tarefas (algo bem como "divide e vencerás"). Se me gostaria chamar o atendimento sobre os nomes dos processos chamados (.obtienedatosvisor e .obtienefrasesvisor) e do que os chama (.obtém) que como vês, deveriam ficar ocultos a uma listagem desde a máquina Windows graças ao ponto inicial.

Quanto ao código destes dois últimos scripts, aí vão; primeiro o de . obtienedatosvisor

#!/bin/sh
# Emilio (28-4-03)
#
# Recupera os dados postgres do visor 
#
# Elimina os dados antigos
rm -r /home/diretor/.visor
#
# Cria de  novo o diretório
mkdir /home/diretor/.visor
#
# Se situa no diretório em  questão
cd /home/diretor/.visor
#
# Realiza a transferência
#
/usr/bin/wget -nH --cut-dirs=1
         ftp://usuário:password@iesmajuelo.com//tmp/visor/*.txt

e a continuação o de . obtienefrasesvisor

#!/bin/sh
# Emilio (29-4-03)
#
# Adiciona as frases do diretor ao visor
#
# Se situa no diretório em  questão
cd /home/diretor/frases
#
# Renombra de  forma adequada (visorPxx.txt)
# todos os ficheros com extensão txt 
# e os cópia ao diretório em  que 
# procurará o visor
#
ordem=1
for i in `ls /home/diretor/frases/*.txt`
do
  /home/diretor/.filtro13 < $i > /home/diretor/.visor/visorP$ordem.txt
  ordem=`expr $ordem + 1`
done

O primeiro deles pouco tem que contar (já que está dando por sentado que os dados de postgres os encontrará perfeitamente preparados pela máquina que tem a base de dados).

Do segundo talvez tenha algo mais do que contar. A idéia é que independentemente do nome que o diretor use para criar seus ficheros, estes sempre serão renombrados como  visorPXX.txt de forma que logo o script que controla a linha do centro do visor o veja como uma mensagem mais.

Se és muito meticuloso, te terás dado conta de que os ficheros que provem de postgres  se nomeiam visorXX.txt enquanto os que provem do diretor se nomeiam visorPXX.txt (têm uma P demais). O motivo não é outro que permitir ao administrador distinguir com muita facilidade os uns de outros, por se talvez algum dia há que intervir "a mão".

Por outra parte, verás que também há uma chamada ao processo  /home/diretor/.filtro13 . O motivo não é outro que ter em conta que a máquina do diretor é uma máquina Windows e que por tanto os retornos de linha e os retornos de carro não os trata igual que as máquinas UNIX. Num princípio pensei em usar o comando  recode /cl  ou bem tr -d '\r' para realizar a conversão oportuna, mas dado a simplicidade do problema (e a que me " echaron uma mão") optei pelo seguinte código em C:

#include <stdio.h>
//Emilio, Francisco (25-4-03)
int main (int argc, char *argv[]%)
{
  char c;
  
  while ((c=getchar())!=EOF)
     if (c!=13) putchar(c);

}

Compilar isto é tão singelo como teclear:

gcc .filtro13.c -ou .filtro13.

e não deve ter o mais mínimo problema.

Recuperar os dados de postgres

Bueno, pois é o momento de ver como extrair e "formatar" os dados de postgres que logo se mostrassem no visor. Como outras tantas vezes, primeiro o código e logo o comento:

#!/bin/sh
# Emilio (30-03-03)

# Elimina ficheros antigos
rm visor*.txt

# cria um fichero de  texto por  cada registo
# de  postgres com o resumo e o texto
for i in `psql -d basedatos -t -q -c "select ide from tabela;"`
do
  psql -d basedatos -t -q -c
        "select resumo from tabela where ide=$i;" -ou visor$i.txt
  psql -d basedatos -t -q -c
        "select texto from tabela where ide=$i;" >> visor$i.txt 
done

Como vês, além de eliminar possíveis dados antigos, faz-se uma primeira consulta à base de dados para saber quantos ficheros visorXX.txt vão criar (e com que número de ordem, é dizer, com que valor para as XX) e logo se vão realizando sucessivas consultas, a razão de duas por cada fichero, para criá-los. A primeira consulta à base de dados cria o fichero com a linha de resumo, e a segunda consulta lhe adiciona as linhas de texto que sejam necessárias.

Adicionalmente, cria-se um "oco" entre a primeira linha e o resto (imagino que pela redirección), de aí o formato que levo comentando todo este tempo de uma primeira linha de resumo, uma linha em alvo e por último, tantas linhas como se desejem de texto.

Cuidado com "queimar" o monitor

Se lembras os três processos que continuamente correm no visor, te terás fixado, que tanto a cabeceira, como o centro como o pé nunca estão parados. Quero dizer que sempre há algum texto em movimento e nunca um caráter determinado na mesma posição do monitor do visor. Isto é algo básico se se pretende como em meu caso que o visor esteja acendido muitas horas ao dia (umas 12 horas em meu caso concreto).

Imagino que alguma que outra vez terás visto algum desses cajeros automáticos antigos nos que a imagem de " Insira seu cartão" se ficou para sempre impressa no pequeno monitor que tinham. Isto mais do que problema do monitor é problema do desenho do programa que mostra o texto, pois com tão só movê-lo um pouco se evita este defeito. De todas formas, atualmente se tende a usar telas TFT ou similares que não apresentam este problema, mas claro, falando de um 486 como em meu caso dificilmente terá uma tela TFT, verdade?

Por tanto a fábula seria que nunca os textos se fiquem fixos em nenhuma posição concreta do monitor do visor, e neste projeto isto se cumpre plenamente.... exceto quando pela noite se lhe diz à máquina que se pare e ficam em tela as mensagens de fechamento do sistema operativo (imagino que não fará defeituosa lembrar que NÃO todos os 486 dispõem de fontes ATX que permitem apagar completamente a máquina).

Para este problema não encontrei mais solução do que adicionar um temporizador destes que se vendem nas grandes superfícies ou nas lojas de eletrônica que permitem fixar a hora de acendido e apagado. O que faço é dizer ao visor (usando crontab) que às 21:00 se apague e ao temporizador o programei para cortar a corrente às 21:05. Ademais, já aproveitei para dizer-lhe que volte restaurar a alimentação às 9:00 e assim o visor arranca novamente ao dia seguinte.

Cuidado com o "apagado automático" do monitor

Vimos no ponto anterior que ter o monitor acendido muito tempo pode ter problemas. Como a gente que desenvolve X-Windows também o sabe, por defeito faz que se não usamos o teclado ou o rato, o monitor passe a um modo de " espera" (ou stand-by como dizem os ingleses) que o deixa sem imagem.

Isto é estupendo quando nos levantámos do teclado e se nos esquece apagar o monitor, já que ele se apaga (ou se "escurece") automaticamente quando detecta que não tecleamos nada nem movemos o rato.

Claro que se falamos de uma máquina sem teclado e sem rato, passado um certo tempo, como X-Windows não detectará atividade alguma, se "apagará" o monitor (isso se, com a melhor intenção do mundo) mas deixando "cego" ao pobre visor.

Por tanto, terá que retocar na configuração de X-Windows para que isto não ocorra. Para isto, procura no fichero XF86Config a seção referente à tela (Section "Screen" ) e adiciona as seguintes linhas:

BlankTime 0
StandbyTime 0
SuspendTime 0
OffTime 0.

Rearranca X-Windows e verás como a partir de agora o visor nunca escurece sua tela.

Problemas de horário

Está claro que além das mensagens das linhas de cabeceira e centro, a informação da data e a hora é também útil no visor. Concretamente tal e como eu o apresento, a data e hora se mostram na linha do pé do visor.

Recuperar a data e hora do sistema operativo e formatá-la de forma apropriada não foi nenhum problema e já detalhei como o fazia no script correspondente (dá um vistazo a "Começando com o pé" se não o lembras)

O problema é que mais de um 486 dos que ainda ficam por aí (incluído o do que eu usei como visor) faz já muito tempo que perderam a data e a hora devido ao agotamiento de sua baterista. Logicamente se poderia pretender substituir sua baterista por outra nova, mas quando fisicamente se tenta não sempre é possível (e se o é, a vezes custa a mesma vida retirar a antiga com o consiguiente "perigo" de retirar algo mais do que só a baterista).

O caso é que em lugar de " brigar-me" com a baterista, recorri a ativar o suporte para ntp de forma que o visor possa conferir a um de nossos servos  e "perguntar-lhe" que hora é cada certo tempo. Isto é perfeito para quando o desfase entre o visor e o servo de referência não é muito acusado, mas como a vezes o visor arranca e crê que é o um de janeiro de 1980, o desfase é "desproporcionado" e ntp se nega a realizar nenhum ajuste.

Após pesquisar um pouco, encontrei uma solução a este problema. Incluí também como script de arranque o seguinte processo chamado Hora.sh e com o seguinte conteúdo:

#!/bin/sh
# Emilio (25-4-03)
case $1 in
      start)
            ntpdate -b dirIPservidorNTP
            ;;
      stop)
            # nada por  agora
            ;;
      *)
            echo "Uso: $0 {start | stop}"
            ;;
esac

Desta forma, justo ao arrancar se produz o ajuste da hora do visor à mesma hora que tenha o servo de referência (independentemente do grande que seja o desfase) e logo será já ntp o que se encarregue dos pequenos ajustes necessários para que o visor sempre esteja em hora.

O visor funcionando

Aqui tens algumas fotos do visor em plena ação... logicamente não se vêem girar os textos :-) mas te garanto que o fazem... Não pude evitar os "reflexos" do monitor ao fazer as fotos e apenas se vê a linha do pé devido a que é de cor vermelha, mas para fazer-te uma idéia de como resulta crio que é suficiente.

 

Agradecimientos

Se chegaste lendo até aqui sem dormir-te quase que será um milagre e mereces meu mais sincero agradecimiento.

Logicamente, este projeto é algo muito concreto de nosso trabalho, mas talvez possa servir a alguém mais, ou ao menos possas aproveitar algum de seus scripts para outra idéia.

Inclusive seria possível prová-lo sem necessidade de expo-lo "ao público" para ver que tal funciona em teu próprio FreeBSD... bastará com que te cries por tua conta três ou quatro ficheros do estilo visorXX.txt e vejas que tal se movem as linhas de cabeceira, centro e pé por teu próprio monitor...

Me gostaria também agradecer a Francisco Criado ([email protected]) o ter retocado o código de giro das frases e o "apaño" para usar os textos de Windows sem recorrer a comandos como recode ou tr.

Por último, como outras vezes, não estará demais desde aqui mostrar minha agradecimiento a toda a gente que faz possível que FreeBSD seja um sistema operativo tão flexível como para abarcar os projetos mais díspares.

 


Emilio Florido ([email protected])
Hosted by www.Geocities.ws

1