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...):
- (http://www.readynas.com/download/addons/4.00/EnableRootSSH_1.0.bin)
- (http://www.readynas.com/download/addons/4.00/APT_1.0.bin)
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.