Installer un afficheur LCD 44780 avec lcd4linux sur un NAS ReadyNAS de Netgear

J'aime cette petite machine qu'est le ReadyNAS. Bien sur, c'est avant tout un serveur de fichiers, en raid et qui en met plein les mains pour pas cher : 350 euros pour 2x1To. Mais il peut aussi servir à bien d'autres choses... Serveur média, serveur iTunes, serveur de sauvegarde, serveur Time Machine, serveur domotique, mini serveur web... Et à ce prix là, c'est vraiment imbattable. Mais cette petite boite ne dispose d'aucun affichage. Alors pourquoi pas essayer de lui en greffer un sur la base d'un afficheur LCD 2 lignes de 16 caractères (voir plus...) raccordé en USB... D'autant que bien qu'il soit facile d'en réaliser un, on peut également en trouver pour une poignée de $$ qui soit supporté par de nombreux logiciels (ex: cwlinux usb = 37$)... Ceci nous permettra d'un seul coup d'oeuil de surveiller les paramètres vitaux de la machine, sans connecter d'interface web. Malheureusement, il n'existe pas de paquet permettant une installation directe sur le readynas. Nous allons voir ici comment compiler les sources du logiciel et faire fonctionner le tout...

irlcd.jpg

Pré requis matériel:

Dans un précédent billet, j'avais montré comment réaliser un afficheur LCD connecté en USB sur la base d'un afficheur à bas coût et d'une poignée de composants. C'est ce même afficheur que je vais utiliser ici bien que vous puissiez installer pratiquement n'importe quel autre afficheur avec connectivité USB.

Je vais également utiliser le logiciel LCD4Linux ( http://ssl.bulix.org/projects/lcd4linux ). Ce logiciel support une liste impressionnante d'afficheurs LCD que vous trouverez sur la page Supported DIsplays du Wiki du site officiel. L'utilisation de la librairie serdispllib (option) permet encore d'en ajouter une bonne couche.

Vous pouvez sélectionner un afficheur de votre choix, mais pensez toutefois à en prendre un se connectant en USB, le port parallèle n'étant pas de mise sur le ReadyNAS. Potentiellement, un afficheur série pourrait marcher, bien que je ne l'ai pas testé. Il faudrait dans ce cas munir le ReadyNAS d'un câble convertisseur USB / série, et bien vérifier avant d'acheter l'afficheur que les pilotes pour le composant convertisseur soient intégrés au noyau linux du ReadyNAS (dmesg est ton ami..).

Pré requis logiciel:

Dans la mesure ou nous allons compiler sur le ReadyNAS directement, il va nous falloir répondre à un certain nombre de pré requis. En effet, je n'ai pas jugé utile pour compiler un seul logiciel de mettre en place un environnement de compilation croisée pour compiler sur PC ou Mac des paquets pour le ReadyNAS. Le compilateur sera donc installé sur le ReadyNASs lui même.

Tout d'abord, le NAS doit être préparé pour :

  • Permettre un accès SSH en root
  • Permettre l'installation de packages debian

Pour ce faire, il nous faut installer les deux extensions suivantes (avec l'interface web de gestion...):

Rebooter ensuite le NAS puis se connecter en SSH. Le mot de passe root pas défaut est le mot de passe du compte admin.

Il va ensuite nous falloir installer diverses choses. Pour se faire, se connecter sous shell, en root et exécuter le script suivant :

# Installation des librairies libc, compilateur et entête kernel
apt-get install libc6-dev linux-kernel-headers gcc-3.4-base 
# Installation de la librairie usb, qui permet de dialoguer avec l'afficheur
apt-get install libusb-dev

Et éventuellement installer la librairie ncurses. Cela peut s'avérer pratique pour pouvoir tester lcd4linux en mode console texte (c'est à dire sans afficheur...).

apt-get install ncurses-dev

Et quelques utilitaires, qui serviront pour la suite de ce tutorial :

# nécessaire pour décompresser le package lcd4linux
apt-get install bzip2
# pour disposer de la commande lsusb, qui nous permettra de détecter que notre afficheur usb est bien reconnu :
apt-get install usbutils

Et enfin la librairie gd2 nous sera utile si l'afficheur LCD est graphique :

# Librairie GD
apt-get install libgd2 libgd2-dev

Compilation de la librairie serdispllib

Cette étape est optionnelle, mais permettra d'ajouter un support sur d'autres périphériques LCD qui seront pris en charge directement par la librairie (voir la liste sur http://serdisplib.sourceforge.net/#displays ).

  • Se placer dans /usr/src
cd /usr/src
  • Récupérer la librairie en source (tar.gr) à partir de la page sourceforce du projet : http://sourceforge.net/projects/serdisplib/
  • Décompresser la librairie récupérée
tar xvfz serdisplib-1.97.9.tar.gz
  • Configurer le makefile. Noter le switch pour forcer la plateforme sparc, l'auto-configuration étant incapable de le détecter.
cd serdisplib-1.97.9
./configure --enable-libusb --build=sparc-linux
  • Compiler et installer la librairie
make
make install
  • Créer le fichier /etc/ld.so.conf et ajouter la ligne
/usr/local/lib
  • Mettre à jour les chemins des bibliothèques
ldconfig

Ces deux dernières étapes ont pour objectif d'indiquer au système le chemin d'accès au bibliothèques complilées dans /usr/local/lib, sinon ... erreur au chargement de lcd4linux:

Starting lcd4linux: /usr/local/bin/lcd4linux: error while loading shared libraries: libserdisp.so.1: cannot open shared object file: No such file or directory

Récupération du package lcd4linux et compilation

Il va nous falloir récupérer le package lcd4linux sur le site officiel :

cd /usr/src
wget http://ssl.bulix.org/projects/lcd4linux/attachment/wiki/Download/lcd4linux-0.11.0-SVN.tar.bz2

Nous allons ensuite le décompresser.

tar xvjf lcd4linux-0.11.0-SVN.tar.bz2
cd lcd4linux-0.11.0-SVN/

Vient ensuite l'étape de la configuration. Il est impératif de préciser à l'aide du switch '--build' la plateforme de destination, car le package n'est pas capable de l'auto-détecter.

Autre point que le configure n'est pas capable d'auto-détecter : l'absence de port parallèle. La compilation échoue sur celle-ci. Il va donc nous falloir désactiver tous les divers qui l'utilisent afin d'éviter les plantages de compilation. Le flag '--with-drivers' est là pour cela. Bien penser à encadrer les paramètres avec des simples quotes, sinon cela ne marche pas. Il est possible en préfixant le nom du driver par un point d'exclamation, de préciser de l'exclure de la compilation.

La page Driver Overview du wiki nous permet d'identifier les drivers conçus pour le port parallèle. A noter que le driver 'Sample', n'est pas mentionné dans cette liste, et que lui aussi utilises le port parallèle...

Pour réaliser une compilation avec tous les drivers supportés sauf ceux nécessitant le port parallèle, voici la commande :

./configure --with-drivers='all,!HD44780,!LPH7508,!M50530,!Noritake,!T6963,!Sample' --build=sparc-linux

Il est également possible de n'inclure que le driver dont vous avez besoin, ici, la même configuration, mais seulement avec IRLCD, le driver que j'ai écrit pour l'interface LCD que j'ai réalisée et qui a été intégrée par le développeur de lcd4linux dans la dernière version. Ne mettre que le driver nécessaire à clairement un impact sur le poids de l'exécutable. Ainsi, en intégrant tous les drivers et le support ncurses, il pèse 1.3Mo. Après compilation à l'aide de la ligne suivante, il ne pèse plus que 790Ko.

./configure --with-drivers='IRLCD' --build=sparc-linux

Puis vient ensuite la compilation et l'installation...

make

Et si tout s'est bien passé ...

make install

Paramétrage et test

Il va tout d'abord nous falloir générer un fichier de configuration. Pour ce faire nous allons copier celui livré dans /etc :

cp lcd4linux.conf.sample /etc/lcd4linux.conf

Ensuite, nous allons procéder à une petite adaptation pour que la configuration reflète l'afficheur que nous avons choisi. Ici, je vais configurer pour IRLCD. Editer /etc/lcd4linux.conf et commenter

# Display 'picoLCD'

Et dé-commenter le driver de l'afficheur sélectionné, pour moi IRLCD :

Display 'IRLCD'

Ensuite, paramétrer l'aspect (Layout) en commentant celui par défaut :

# Layout 'L20x2'

Et en dé-commentant celui requis, pour moi 16 caractères par 2 lignes

Layout 'L16x2'

Brancher l'afficheur LCD USB, et vérifier qu'il est bien détecté :

 readynas:~# lsusb
 __Bus 003 Device 003: ID 03eb:0002 Atmel Corp.__  ''<< mon afficheur lcd'' 
 Bus 003 Device 001: ID 0000:0000  
 Bus 002 Device 003: ID 051d:0002 American Power Conversion Back-UPS Pro 500/1000/1500
 Bus 002 Device 001: ID 0000:0000  
 Bus 001 Device 001: ID 0000:0000  

Vous pouvez ensuite lancer lcd4linux, qui devrait afficher sur votre afficheur. Il vous restera à configurer l'affichage pour afficher les informations de votre choix, mais là, je vous laisse lire la doc sur le site officiel....

Finalisation de l'installation

Il est ensuite possible de démarrer automatiquement lcd4linux avec le readnas comme c'est expliqué à la fin des howtos.

Je conseille toutefois de 'nicer' lcd4linux à une priorité la plus faible possible. De la doc de la commande nice : `nice' signifie `gentil', la valeur de priorité considérée est une valeur de gentillesse. Plus celle-ci est élévée, plus le processus est gentil vis à vis des autres, leur laissant un accès plus fréquent à l'ordonnanceur. En effet, le programme a tendance à manger un peu de CPU. J'ai donc a cet effet, j'ai légèrement modifié le script de démarrage proposé:

 #!/bin/sh -e
 ### BEGIN INIT INFO
 # Provides:          lcd4linux
 # Required-Start:    
 # Required-Stop:    
 # Default-Start:     2 3 4 5
 # Default-Stop:      1
 ### END INIT INFO
 #
 # lcd4linux               This init.d script is used to start lcd4linux.
 #
 PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin
 DAEMON=/usr/local/bin/lcd4linux
 NAME=lcd4linux
 DESC=lcd4linux
 test -f $DAEMON || exit 0
 set -e
 case "$1" in
  start)
        echo -n "Starting $DESC: "
        start-stop-daemon __\--nicelevel +19__ \--start \--quiet \--pidfile /var/run/$NAME.pid \--exec $DAEMON
        echo "$NAME."
        ;;
  stop)
        echo -n "Stopping $DESC: "
        start-stop-daemon \--oknodo \--stop \--quiet \--pidfile /var/run/$NAME.pid \--exec $DAEMON
        echo "$NAME."
        ;;
  reload)
        start-stop-daemon __\--nicelevel +19__ \--stop \--signal 1 \--quiet \--pidfile /var/run/$NAME.pid \--exec $DAEMON
        ;;
  restart|force-reload)
        echo -n "Restarting $DESC: "
        start-stop-daemon \--stop \--quiet \--pidfile /var/run/$NAME.pid \--exec $DAEMON
        sleep 1
        start-stop-daemon __\--nicelevel +19__ \--start \--quiet \--pidfile /var/run/$NAME.pid \--exec $DAEMON
        echo "$NAME."
        ;;
  *)
        N=/etc/init.d/$NAME
        echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2
        exit 1
        ;;
 esac
 exit 0

Il faut ensuite activer ce script à l'aide des commandes suivantes :

 ln -s /etc/init.d/lcd4linux /etc/rc1.d/K01zlcd4linux
 ln -s /etc/init.d/lcd4linux /etc/rc2.d/S99zlcd4linux
 ln -s /etc/init.d/lcd4linux /etc/rc3.d/S99zlcd4linux
 ln -s /etc/init.d/lcd4linux /etc/rc4.d/S99zlcd4linux
 ln -s /etc/init.d/lcd4linux /etc/rc5.d/S99zlcd4linux

Annexe: Tester sa configuration lcd4linux sur Mac

Sur mac, paradoxalement c'est assez complexe. En effet, la compilation de la librairie libusb échoue en 64 bits sur Snow Leopard. Il aurait été possible de la prélever à partir de macports, mais J'ai plutôt fait le choix (quick & dirty hack...) d'installer libusb et le SDK à partir des packages disponibles pour l'installation de l'interface scanner Twain : http://www.ellert.se/twain-sane/.

Une fois ceci réalisé, il faut télécharger et décompresser lcd4linux, ce qui est déjà indiqué plus haut.

La configuration s'effectue cette fois par la commande :

./configure --with-drivers="IRLCD" --with-plugins='all,!netinfo,!i2c_sensors'

La compilation et l'installation s'effectue ensuite comme d'habitude :

make
make install

L'étape configuration est également à reprendre de la partie précédente du billet.

Notez que ceci ne permettra pas de tester tous les plugins. Certains en effet ne fonctionneront pas, OSX ne gérant pas certaines ressources de la même façon qu'un unix standard. C'est le cas par exemple de l'utilisation du processeur. L'afficheur toutefois devrait se réveiller et se peupler des informations voulues...

Bonne bidouille, JPC

Edit : ajout d'autres techniques de gestion du LCD.

J'ai soumis cette modification sur le forum Netgear, et cela a alimenté quelques discussions (http://www.readynas.com/forum/viewtopic.php?f=34&t=47372&p=271847 ) Une idée intéressante est d'installer l'afficheur LCD qui est intégré sur les plus gros modèles. En effet, le connecteur permettant la connexion d'un LCD serait présent sur la carte mère du Readynas Duo.

L'intérêt de cette technique est de restaurer une fonctionnalité qui est supportée par un driver intégré au noyau du nas. Du coup, l'afficheur se peuplera automatiquement des informations affichées par le firmware, sans effort. Un post en allemand (http://www.readynas.com/forum/viewtopic.php?f=29&t=40117 ) explique comment faire. En synthèse, il faut créer une carte embarquant un W83601G (i2c -> entrées sorties TTL) raccordé à l'afficheur LCD 44780. Je n'ai pas creusé plus avant.

D'autres réactions m'ont donnée des pistes d'investigation. En effet, le firmware du readynas duo, intègre tout le logiciel pour piloter le LCD. Soit. Mais est il possible de modifier les appels au driver ou le driver lui même pour afficher sur autre chose que le lcd interne?

Tout d'abord, il faut voir comment est piloté le lcd interne. Apparemment un périphérique /dev/lcd permet l'écriture du texte, tandis que /proc/sys/dev/lcd/cmd permet d'envoyer des commandes (numéro de ligne, soit 2 pour la ligne 1, soit 192 pour la ligne 2), et /proc/sys/dev/lcd/backlight permet d'allumer et éteindre le backlight (en écrivant 0 ou 1 dessus). C'est simple, et efficace. D'après le code, les écritures sont formatées à 2 lignes de 16 caractères.

Malheureusement, le driver lcd (padre_lcd.ko) n'est pas livré en source dans la partie GPL du readynas. Il est donc difficile de l'adapter pour piloter un autre lcd.

J'ai donc regardé si il était possible de remplacer les appels à /dev/lcd par autre chose. Plusieurs programmes font un appel à ce driver :

  • /frontview/bin/functions : Script shell. fonctions d'affichage utilisées par Frontview
  • /frontview/lib/LCD.pl : Script perl. Je n'ai pas trouvé ou cette librairie était appelée... Un reste d'un ancien développement?
  • /frontview/bin/monitor_enclosure : binaire, aparemment contient des appels à /dev/lcd. Les sources ne sont pas livrés.
  • /frontview/bin/monitor_lcd : companion script.

Afin d'interfacer l'afficheur USB précédemment décrit, j'ai écrit un programme C qui permet en ligne de commande de piloter le LCD. En voici le fonctionnement :

 readylcd [-v] [-h] [-u] [-c] [-x=nn] [-y=nn] ['text to display']
 -v : verbose
 -h : this help screen
 -u : check for lcd presence on usb bus
 -c : clear screen
 -x=nn : go to column x before print (from 0 to 15, default 0)
 -y=nn : go to line y before print (from 0 to 1, default to 0)
 'text to display' (with quotes..)

Et le source (compilé sur le readynas lui même...). Il doit être linké avec la librairie libusb, qui doit préalablement être installée sur le readynas:

/*
* readylcd : Interface program for Frontview / ReadyNAS
* Needs libusb 0.1 and minor modifications to LCD.pl * * Copyright (C) 2010 Jean-Philippe CIVADE <jp@civade.com> * * This software is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include <stdio.h> #include <sys/types.h> #include <string.h> #include <strings.h> #include <usb.h> /* Verbose mode? */ int verbose = 0; /* vid/pid of IRLCD */ #define LCD_USB_VENDOR 0x03EB /* for Atmel device */ #define LCD_USB_DEVICE 0x0002 /* LCD Caracteristics */ #define LCD_NBLINES 2 #define LCD_NBCOLS 16 /* Protocole IR/LCD */ #define LCD_INSTR 20 #define LCD_DATA 21 static char *device_id = NULL, *bus_id = NULL; static usb_dev_handle *lcd; int irlcd_open() { struct usb_bus *busses, *bus; struct usb_device *dev; lcd = NULL; if (verbose==1) printf("Scanning USB for IRLCD interface ...\n"); usb_set_debug(0); usb_init(); usb_find_busses(); usb_find_devices(); busses = usb_get_busses(); for (bus = busses; bus; bus = bus->next) { /* search this bus if no bus id was given or if this is the given bus id */ if (!bus_id || (bus_id && !strcasecmp(bus->dirname, bus_id))) { for (dev = bus->devices; dev; dev = dev->next) { /* search this device if no device id was given or if this is the given device id */ if (!device_id || (device_id && !strcasecmp(dev->filename, device_id))) { if ((dev->descriptor.idVendor == LCD_USB_VENDOR) && (dev->descriptor.idProduct == LCD_USB_DEVICE)) { if (verbose==1) printf("Found IRLCD interface on bus %s device %s\n", bus->dirname, dev->filename); lcd = usb_open(dev); if (usb_claim_interface(lcd, 0) < 0) { if (verbose==1) printf("--> ERROR : usb_claim_interface() failed on readylcd! Device already used ?\n"); return -1; } return 0; } } } } } return -1; } void irlcd_close() { usb_release_interface(lcd, 0); usb_close(lcd); return ; } /* Send a buffer to lcd via a control message */ static int drv_IRLCD_send(int request, unsigned char *buffer, int size) { if (usb_control_msg(lcd, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT, /* bRequestType */ request, /* bRequest (LCD_INSTR / LCD_DATA) */ 0, /* wValue (0) */ 0, /* wIndex (0) */ (char *) buffer, /* pointer to destination buffer */ size, /* wLength */ 1000) < 0) { /* Timeout in millisectonds */ if (verbose==1) printf("IRLCD: USB request failed! Trying to reconnect device."); usb_release_interface(lcd, 0); usb_close(lcd); /* try to close and reopen connection */ if (irlcd_open() < 0) { if (verbose==1) printf("IRLCD: could not re-detect IRLCD USB LCD"); return -1; } /* and try to re-send command */ if (usb_control_msg(lcd, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT, /* bRequestType */ request, /* bRequest (LCD_INSTR / LCD_DATA) */ 0, /* wValue (0) */ 0, /* wIndex (0) */ (char *) buffer, /* pointer to destination buffer */ size, /* wLength */ 1000) < 0) { /* Timeout in millisectonds */ if (verbose==1) printf("IRLCD: retried USB request failed, aborting!"); return -1; } if (verbose==1) printf ("IRLCD: Device successfully reconnected."); } return 0; } /* text mode displays only */ static void drv_IRLCD_clear(void) { unsigned char cmd[1]; cmd[0] = 0x01; /* clear */ drv_IRLCD_send(LCD_INSTR, cmd, 1); cmd[0] = 0x03; /* home */ drv_IRLCD_send(LCD_INSTR, cmd, 1); } /* Write a string of n chars to row, line. Line and row numbering starting at 0 */ static void drv_IRLCD_write(const int row, const int col, const char *data, int len) { unsigned char cmd[1]; static int pos; /* for 2 or 4 lines display */ pos = (row % 2) * 64 + (row / 2) * 20 + col; /* do the cursor positioning here */ cmd[0] = 0x80 | pos; /* do positionning */ drv_IRLCD_send(LCD_INSTR, cmd, 1); /* send string to the display */ drv_IRLCD_send(LCD_DATA, (unsigned char *) data, len); } /* Define spectial char. Matrix is an arrayt of 8 bytes (lines) each byte only used for the 5 less significant bits */ /* this allows defin of 1 char of 5x8 dots */ static void drv_IRLCD_defchar(const int ascii, const unsigned char *matrix) { unsigned char cmd[10]; int i; /* Write to CGRAM */ cmd[0] = 0x40 | 8 * ascii; drv_IRLCD_send(LCD_INSTR, cmd, 1); /* send bitmap to the display */ for (i = 0; i < 8; i++) { cmd[i] = matrix[i] & 0x1f; } drv_IRLCD_send(LCD_DATA, cmd, 8); } int main(int argc, char *argv[]) { int chr; int x=0; int y=0; char buffer[40]; while ( --argc > 0 && (*++argv)[0] == '-' ) while ( chr = *++argv[0] ) switch (chr) { case 'v': verbose = 1; if (verbose==1) printf ("IRLCD Verbose activated\n"); break; case 'h' : printf ("readylcd [-v] [-h] [-u] [-c] [-x=nn] [-y=nn] [-t='text to display']\n"); printf (" -v : verbose\n"); printf (" -h : this help screen\n"); printf (" -u : check for lcd presence on usb bus\n"); printf (" -c : clear screen\n"); printf (" -x=nn : go to column x before print (from 0 to 15, default 0)\n"); printf (" -y=nn : go to line y before print (from 0 to 1, default to 0)\n"); printf (" 'text to display' (with quotes..)\n"); break; case 'u' : if (irlcd_open() != -1) { if (verbose==1) printf ("IRLCD Successfully detected\n"); return 0; } // no lcd detected else return (-1); case 'c' : if (irlcd_open() != -1) { if (verbose==1) printf ("IRLCD Successfully detected\n"); drv_IRLCD_clear(); if (verbose==1) printf ("IRLCD Successfully cleared\n"); return 0; } // no lcd detected : can't clear... else return (-1); case 'x' : // read x value sscanf(argv[0],"x=%d",&x); if (verbose==1) printf ("IRLCD: requested X=%d\n",x); break; case 'y' : // read y value sscanf(argv[0],"y=%d",&y); if (verbose==1) printf ("IRLCD: requested Y=%d\n",y); break; } // read text if (argc) { strcpy (buffer,argv[0]); if (verbose==1) printf ("IRLCD: writing text '%s' on line=%d col=%d\n",buffer,y,x); // sanitize args if (x>=LCD_NBCOLS ) x=LCD_NBCOLS -1; if (y>=LCD_NBLINES) y=LCD_NBLINES-1; buffer[LCD_NBCOLS]='\0'; // 16 chars max... irlcd_open(); drv_IRLCD_write(y,x, buffer, strlen(buffer)); } else printf ("Nothing done. Please consult help with 'readylcd -h'\n"); return 0; }

Ensuite, j'ai modifié les programmes appelant le LCD interne pour qu'ils utilisent la commande précédemment écrite et fassent vivre le LCD USB.

Dans /frontview/bin/functions , réécriture de la fonction "print_lcd_line:

function print_lcd_line()
{
line=$1
line=$(( line - 1 ))
cmd=$(printf "/usr/local/bin/readylcd -y=%d '%-16s'" $line "$2")
eval "$cmd"
}

Dans /frontview/lib/LCD.pl, remplacement du script complet par :

#!/usr/bin/perl
#-------------------------------------------------------------------------
#  Copyright 2007, NETGEAR
#  All rights reserved.
#-------------------------------------------------------------------------

sub lcd_is_supported
{
  # try to initialize
  my $ret = ( system("/usr/local/bin/readylcd -u")==0  ? 1  : 0);
  # if ok, clear screen
  if ($ret)
   {
     system("/usr/local/bin/readylcd -c");
   }
  return $ret;
}

sub print_lcd_line
{
  my $line      = shift;
  my $lcd_mesg  = substr(shift,0,16);
  my $cmd;
  $cmd=sprintf("/usr/local/bin/readylcd -x=%d '%-16s'", $line-1, $lcd_mesg);
  system($cmd);
}

sub hotplug_lcd
{
  my $mesg = shift;
  my $mon_pid;
  # Try to locate monitor_enclosure PID via .pid file
  if( open(PID, "/var/run/monitor_enclosure.pid") )
  {
    $mon_pid = ()[0];
    close PID;
  }
  print_lcd_line("2", $mesg);
  kill(USR1, $mon_pid) if($mon_pid);
}

sub turnon_lcd
{
  $LCD_ON = 1;
}

sub turnoff_lcd
{
  return if( pgrep("LCD_ALWAYS_ON=1", "/etc/default/services") );
  $LCD_ON = 0;
}

sub pgrep
{
  my $string = shift;
  my $infile = shift;
  my $result;

  open(INFILE, "$infile");
  while(  )
  {
    if( /$string/ )
    {
      chomp;
      $result = $_;
      last;
    }
  }
  close(INFILE);

  return $result;
}


1;

Et enfin, le script /frontview/bin/monitor_lcd (annule et remplace) dans lequel au passage j'ai corrigé un bug sur la détection d'adresse ip (voir if addr):

#!/usr/bin/perl

my $ret = ( system("/usr/local/bin/readylcd -u")==0  ? 1  : 0);
if ($ret) {
   $| = 1;# set autoflush
} else {
   exit;
}
sub LCD_MOVE {
  my $x=$_[0];
  my $y=$_[1];
  return 128+($y&1)*64+$x;
}


system("/usr/local/bin/readylcd -c");

#Display IP address
$ip=0;
ioctl FH, $IOCTL_LCD_CMD, pack("L", $LCD_HOME);
open IF, "/sbin/ifconfig |";
while () {
      chomp;
# was inet\addr. On readynas is inet\adr (one d..)
      if (/ \s+ inet\sadr:(\S+) /x) {
        if ($1) {
           $ip = $1;
        } else {
           $ip = "Check Network...";
        }
        last;
      }
}
close IF;
if ($ip == 0) {
  $ip = "No Network link";
}
$cmd=sprintf("/usr/local/bin/readylcd -x=0 -y=0 '%-16s'", $ip);
system ($cmd);
#Display Hostname on second line
open(HN, "/proc/sys/kernel/hostname");
chomp( $hostname = ()[0] );
close(HN);
$cmd=sprintf("/usr/local/bin/readylcd -x=0 -y=1 '%-16s'", $hostname);
system ($cmd);

#Wait for 150 sec to get updated enclosure.log
sleep 150;
#get failure info from enclosure.log
$enclosure_file = "/var/log/frontview/enclosure.log";
$fail_descr = " "x16;
$alert = 0;
open (IN, $enclosure_file) or die "Couldn't open $enclosure_file: $!";
while () {
    if(/=fail/) {
       ($tmp, $descr) = split /descr=/, $_;
       $fail_descr .= $descr;
       $fail_descr .= " ";
       $fail_descr .= " "x8;
       $alert = 1;
    }
}
close ( IN );
$fail_descr .= " "x16;

if ($alert == 1) {
  $i=0;
  while (1) {
    $lcd_msg = substr($fail_descr, $i, 16);
    $cmd=sprintf("/usr/local/bin/readylcd -x=0 -y=1 '%-16s'", $lcd_mesg);
    system ($cmd);
    $tick=0.5;
    if ($i++==(length($fail_descr) -16)) {$i=0;}
    sleepx("$tick");
  }
} else {
  # no backlight support
  $i=0;
  $i=0;
}

# Internal functions
sub sleepx {
  my $dur = shift;
  select(undef, undef, undef, $dur);
}

sub echo {
  my $content = shift;
  my $output = shift || ">/dev/null";
  open(ECHO, "$output");
  print ECHO "$content\n";
  close(ECHO);
}

Ca fait le boulot, mais l'affichage est pauvre. Pas d'usage disque, etc.. car cela est géré par monitor_enclosure, binaire dont les sources ne sont pas livrés... De plus, cela ne résistera pas à une mise à jour du firmware du readynas: il faudra tout repatcher...

Suite à cette remarque, chirpa m'a fait remarquer qu'un autre membre du forum avait créé un script pour afficher sur le lcd interne plus d'informations sur le système (post d'origine : http://www.readynas.com/forum/viewtopic.php?p=166817#p166817 ). Je l'ai donc adapté pour qu'il utilise ma commande pour écrire sur le LCD USB.

Le script "readysysinfo" :

#!/bin/bash
#
# System Info Script for ReadyNAS NV+ 16x2 LCD display.
# Cycles a selection of system information over LCD.
# 0.2a by rxbyte@gmail.com

# ---- Global Variables ----
# No need to alter unless debugging on non-ReadyNAS platform
ROTATION_DELAY=3
NET_INT=eth0
HDD_DEV=/dev/hdc1
RAID_DEV=/dev/c/c
# LCD Flags
LCD_SHOW_MEM=1
LCD_SHOW_CPU=1
LCD_SHOW_SYS=1
LCD_SHOW_NET=1
LCD_SHOW_IP=1
LCD_SHOW_TIME=1
LCD_SHOW_HDD=1

# ---- LCD Management Functions ----
# Change state of LCD backlight
function set_backlight
    {
i=0
    # none supported

    }
# Write string to LCD device
function print_lcd
    {
        line=$1
        line=$(( line - 1 ))
        cmd=$(printf "/usr/local/bin/readylcd -y=%d '%-16s'" $line "$2")
        eval "$cmd"
    }
function reset_lcd
    {
        cmd=$(printf "/usr/local/bin/readylcd -c")
        eval "$cmd"
    }
# ---- Statistics Generation Functions ----
# Each function below produces a string of information for display on one line of the LCD.
# Generate memory usage info
function get_meminfo
    {
           local s=""
           sMemUsed=$(free -m | awk 'NR == 2 {print $3;}')
           sMemTotal=$(free -m | awk 'NR == 2 {print $2;}')
           s="RAM:"$sMemUsed"MB/"$sMemTotal"MB"
           echo $s
    }
# Generate swap usage info
function get_swapinfo
    {
           local s=""
           sSwapUsed=$(free -m | awk 'NR == 4 {print $3;}')
           sSwapTotal=$(free -m | awk 'NR == 4 {print $2;}')
           s="Swap:"$sSwapUsed"MB/"$sSwapTotal"MB"
           echo $s
    }
# Generate system availability info
function get_uptimeinfo
    {
           local s=""
           sUp=$(cat /proc/uptime | awk '{print $1;}' | cut -f1 -d.)
           let "sUp /= 3600"
           # sUnit=$(uptime | awk '{print $4;}' | cut -b1)
           sUsers=$(uptime | awk '{print $4;}')
           s="Up:"$sUp"h/Users:"$sUsers
           echo $s
    }
# Generate domain name info
function get_hostnameinfo
    {
           local s=""
           sHostname=$(hostname -f)
           s=$sHostname
           echo $s
    }
# Generate CPU load average info
function get_loadinfo
    {
           local s=""
           sOneLoad=$(uptime | awk '{print $8;}' | cut -d, -f1)
           sFifteenLoad=$(uptime | awk '{print $10;}' | cut -d, -f1)
           s="Load:"$sOneLoad"/"$sFifteenLoad
           echo $s
    }
# Generate CPU processes info
function get_procinfo
    {
           local s=""
           sProcs=$(ps ax | wc -l | awk '{print $1}')
           s="Processes:"$sProcs
           echo $s
    }
# Generate network interface received data info
function get_ethrxinfo
    {
           local s=""
           sRX=$(ifconfig $NET_INT | grep "RX bytes:" | awk '{print $2}' | cut -b7-64)
           let "sRX /= 1048576"
           s="Rcvd:"$sRX"MB"
           echo $s
    }
# Generate network interface sent data info
function get_ethtxinfo
    {
           local s=""
           sTX=$(ifconfig $NET_INT | grep "RX bytes:" | awk '{print $6}' | cut -b7-64)
           let "sTX /= 1048576"
           s="Sent:"$sTX"MB"
           echo $s
    }
# Generate network interface IP address info
function get_ipinfo
    {
           local s=""
           sIPV4=$(ifconfig $NET_INT | awk 'NR == 2 {print $2;}' | cut -b6-20)
           s="IP:"$sIPV4
           echo $s
    }
# Generate network interface MTU info
function get_mtuinfo
    {
           local s=""
           sMTU=$(ifconfig -s $NET_INT | awk 'NR == 2 {print $2}')
           s="MTU:"$sMTU
           echo $s
    }
# Generate system date info
function get_dateinfo
    {
           local s=""
           sDate=$(date +%a-%d/%m/%Y)
           s=$sDate
           echo $s
    }
# Generate system time info
function get_timeinfo
    {
           local s=""
           sTime=$(date +%H:%M)
           s=$sTime
           echo $s
    }
# Generate free disc info for system partition
function get_syshdinfo
    {
           local s=""
           sUsedSys=$(df -h $HDD_DEV | awk 'NR == 2 {print $3}')
           sTotalSys=$(df -h $HDD_DEV | awk 'NR == 2 {print $2}')
           s="Sys:"$sUsedSys"/"$sTotalSys
           echo $s
    }
# Generate free disc info for raid array partition
function get_raidhdinfo
    {
           local s=""
           sUsedRaid=$(df -h $RAID_DEV | awk 'NR == 2 {print $3}')
           sTotalRaid=$(df -h $RAID_DEV | awk 'NR == 2 {print $2}')
           s="RAID:"$sUsedRaid"/"$sTotalRaid
           echo $s
    }

# ---- Main Function ----
# Display a series of statistics on the LCD
reset_lcd
set_backlight 1
while [ "1" -eq "1" ]; do
# Display Memory Information
    if [ $LCD_SHOW_MEM = 1 ]; then
           print_lcd 0 `get_meminfo`
           print_lcd 1 `get_swapinfo`
           sleep $ROTATION_DELAY
    fi
# Display Disk Space Information
    if [ $LCD_SHOW_HDD = 1 ]; then
           print_lcd 0 `get_syshdinfo`
           print_lcd 1 `get_raidhdinfo`
           sleep $ROTATION_DELAY
    fi

# Display CPU Information
    if [ $LCD_SHOW_CPU = 1 ]; then
           print_lcd 0 `get_procinfo`
           print_lcd 1 `get_loadinfo`
           sleep $ROTATION_DELAY
    fi

# Display System Information
    if [ $LCD_SHOW_SYS = 1 ]; then
           print_lcd 0 `get_hostnameinfo`
           print_lcd 1 `get_uptimeinfo`
           sleep $ROTATION_DELAY
    fi

# Display Network Transport Information
    if [ $LCD_SHOW_NET = 1 ]; then
           print_lcd 0 `get_ethtxinfo`
           print_lcd 1 `get_ethrxinfo`
           sleep $ROTATION_DELAY
    fi

# Display Network IP Information
    if [ $LCD_SHOW_IP = 1 ]; then
           print_lcd 0 `get_ipinfo`
           print_lcd 1 `get_mtuinfo`
           sleep $ROTATION_DELAY
    fi

# Display Date and Time Information
    if [ $LCD_SHOW_TIME = 1 ]; then
           print_lcd 0 `get_dateinfo`
           print_lcd 1 `get_timeinfo`
           sleep $ROTATION_DELAY
    fi
done
reset_lcd
exit 0

La, c'est beaucoup mieux: affichage cyclique des informations essentielles du readynas.