Une histoire de stdout et de pipe

a marqué ce sujet comme résolu.

Bonjour,

J'essaie en ce moment de réaliser un petit script shell pour faciliter le test d'une carte électronique tournant sous linux. Je suis sous Busybox avec un shell simple (POSIX, il n'y a pas de tableaux par exemple).

Mon script communique avec un périphérique en SPI via un driver, je ne m'occupe pas de la gestion du SPI, j'ai juste à donner le numéro de registre que je veux lire ou écrire avec la data. Ceci se fait via les fichiers d'interfaces dans /proc.

Lorsque je teste à la main l'écriture ou la lecture d'un registre voici l'output que j'ai :

1
2
3
4
root@OpenWrt:/# echo write reg 0x00 0x40 > /proc/bus/spi/cap11xx/cap11xx
write register 0x00 = 0x40
root@OpenWrt:/# echo read reg 0x03 > /proc/bus/spi/cap11xx/cap11xx
read register 0x03 = 0x00

Le but du script que j'écris c'est de récupérer la valeur (après le =) et de la comparer avec une valeur prédéfinie. Pour se faire j'utilise la commande cut pour récupérer juste les 0x00.

Sauf que si je l'applique dans le pipe de la commande, le résultat ne donne… rien :

1
2
root@OpenWrt:/# echo read reg 0x03 > /proc/bus/spi/cap11xx/cap11xx | cut -d "=" -f 2
read register 0x03 = 0x00

Mais si j'applique "à la main" le cut sur le résultat, j'obtiens bien ce que je veux :

1
2
root@OpenWrt:/# echo "read register 0x03 = 0x00" | cut -d "=" -f 2
 0x00

Le problème vient du fait que j'écris dans le fichier cap11xx, et non dans le stdout, donc le "cut" qui est dans le pipe lui s'applique sur stdout… qui doit être vide. Sauf que le driver écrit bien une phrase de résultat…

Dans le script j'ai essayé pas mal de trucs trouvés sur le net mais rien n'y fait, je n'arrive pas à récupérer la phrase renvoyée par le driver.

Je lance donc cette bouteille dans la mer de fruit pour savoir déjà si c'est possible à réaliser.

Merci :)

+0 -0

Je ne suis pas vraiment assez bon pour pouvoir aider sans avoir le loisir d'essayer de mon coté, mais si le problème vient de stdout/fichier, ne serait-il pas possible de le faire en deux lignes, comme

1
2
echo read reg 0x03 > /proc/bus/spi/cap11xx/cap11xx
cat /proc/bus/spi/cap11xx/cap11xx | cut -d "=" -f 2

Malheureusement, non, j'avais déjà essayé le cat sur le fichier d'interface, mais ça renvoie la liste des registres disponibles.

Je n'ai pas la main sur le driver du périphérique, et je n'ai aucune doc dessus (sur le driver, pour le composant j'ai la datasheet, mais le but c'est d'utiliser le driver, pas de tout refaire from scratch).

Je suis en train de jouer avec l'imbrications de commandes mais ça n'a pas l'air de marcher non plus :(

Le problème vient du fait que j'écris dans le fichier cap11xx, et non dans le stdout, donc le "cut" qui est dans le pipe lui s'applique sur stdout… qui doit être vide.

Ce ne serait pas plutôt parce que ta commande est en fait équivalente à :

echo read reg 0x03 | cut -d "=" -f 2 > /proc/bus/spi/cap11xx/cap11xx

En d'autres ternes ce serait la chaîne "read reg 0x03" qui serait passée à cut avant d'être envoyée au fichier. Comme cut ne trouve pas de = il ne change peut-être rien donc la commande fonctionne du point de vue du périphérique, et du coup tu n'appliques rien à la sortie.

Techniquement comme tu fais un echo, je ne suis pas sûr que tu pouisses récupérer quelque chose avec une pipe après. Tu print dans un fichier, pas un exécutable, donc il ne peut pas y avoir de sortie il me semble. LE driver afficherait le résultat par ses propres moyens.

Arrêtez-moi si je viens de dire une grosse connerie !

EDIT: J'ai une idée pour vérifier ce que ja'vance. J'espère que ton shell supporte les variables au moins…

1
$resultat=`echo read reg 0x03  > /proc/bus/spi/cap11xx/cap11xx `

Si $resultat est vide, alors j'ai raison. Sinon, désolé pour le bullshit.

+0 -0

Salut,

Ce ne serait pas plutôt parce que ta commande est en fait équivalente à :

echo read reg 0x03 | cut -d "=" -f 2 > /proc/bus/spi/cap11xx/cap11xx

QuentinC

Non, la redirection s'applique bien à la commande echo uniquement. Si ton raisonnement était juste, la suite echo un >/dev/null | echo deux ne devrait rien afficher.

Sinon, je suis du même avis que QuentinC : les messages affichés doivent sans doute provenir du noyau (comme ceux qui sont affichés sur le tty1, par exemple lors de l'insertion d'un clé USB) ce qui fait qu'il n'est pas possible de les récupérer à l'aide d'un tube. Tu as regardé si ces derniers se retouvaient à la fin de la sortie de la commande dmesg(1) ?

1
$ dmesg | tail
+1 -0

Peut-être que le driver écrit ses messages directement dans /dev/tty ? Si c'est la cas, une solution serait d'utiliser un truc qui roule une commande dans un PTY (comme expect ou empty), mais c'est plutôt lourd à utiliser. L'idée de lire la liste des registres avec leurs valeurs est probablement plus simple.

+0 -0

Salut,

Ce ne serait pas plutôt parce que ta commande est en fait équivalente à :

echo read reg 0x03 | cut -d "=" -f 2 > /proc/bus/spi/cap11xx/cap11xx

QuentinC

Non, la redirection s'applique bien à la commande echo uniquement. Si ton raisonnement était juste, la suite echo un >/dev/null | echo deux ne devrait rien afficher.

Sinon, je suis du même avis que QuentinC : les messages affichés doivent sans doute provenir du noyau (comme ceux qui sont affichés sur le tty1, par exemple lors de l'insertion d'un clé USB) ce qui fait qu'il n'est pas possible de les récupérer à l'aide d'un tube. Tu as regardé si ces derniers se retouvaient à la fin de la sortie de la commande dmesg(1) ?

1
$ dmesg | tail

Taurre

Effectivement les messages apparaissent bien avec dmesg.

Si on ne peut pas les récupérer, vu qu'ils proviennent du noyau, y a un moyen de ne pas les afficher, comme on peut le faire via une redirection vers /dev/null ? Ou alors faut voir avec le driver ?

@QuentinC :
J'ai essayé cette méthode dans mon script au début, et la variable était vide. Justement je ne comprenais pas pourquoi :)

+0 -0

Si on ne peut pas les récupérer, vu qu'ils proviennent du noyau, y a un moyen de ne pas les afficher, comme on peut le faire via une redirection vers /dev/null ? Ou alors faut voir avec le driver ?

zeqL

Apparemment, il est possible de les supprimer à l'aide de la commande dmesg -n 1 (sous GNU/Linux en tous les cas) qui spécifie que seuls les messages d'urgences seront affichés. Si cela fonctionne, tu peux l'ajouter dans le fichier de configuration de ton interpréteur de commande (.bashrc, .kshrc, .shrc, etc).

Édit : je n'ai rien dit, il semble que les privilèges d'administration soient nécessaires pour exécuter cette commande.

+0 -0

Il est possible d'écrire dans une sortie sans que le shell redirige convenablement. Pour cela, il faut directement envoyer au fd du process. Le shell bind la sortie du programme (echo > …) mais pas ça sortie /proc/$$/fd/1.

J'ai vérifié si busybox supporte coproc, mais visiblement non. Par contre, il autorise sh alors busybox sh -c bash -c './fd_redirection |& cut -d "=" -f 2' devrait fonctionner…

fd_redirection:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#!/bin/bash

coproc cat
exec 7>&${COPROC[1]}-
exec 1>&7-

echo read reg 0x03 > /proc/bus/spi/cap11xx/cap11xx

read r <&${COPROC[0]}
echo $r >&2

C'est une solution encore plus sioux xD.

Je ne suis pas au boulot, mais il me semble que j'avais déjà essayé un #!/bin/bash et j'ai reçu une fin de non recevoir, mais il faudrait que je re-teste.

Après tu as peut-être fait une erreur. Il me semble aussi que le busybox que j'ai, toutes les fonctions possibles n'ont pas été implémentées. :s

Mon script communique avec un périphérique en SPI via un driver, je ne m'occupe pas de la gestion du SPI, j'ai juste à donner le numéro de registre que je veux lire ou écrire avec la data. Ceci se fait via les fichiers d'interfaces dans /proc.

Bonjour

rien à voir avec le topic, mais y'a t'il des boitiers justement qui expose ces ports là sous linux, sans partir sur du raspberry ou du openwrt ?

Bah n'importe qu'elle carte ayant un processeur ou microcontrôleur gérant le SPI aura le bus visible sous Linux si tant est que le driver existe.

D'ailleurs je ne comprend pas ta question ou alors il y a une grand confusion de ta part :

  • Linux = OS
  • OpenWRT = OS (qui se fonde sur Linux)
  • Raspberry = Carte de développement

Au niveau des cartes de développement proposant du SPI avec un Linux possible, en général ça tourne avec un microcontrôleur à base d'ARM :

  • Rasbperry Pi
  • BeagleBone Black (BBB)
  • Banana Pi
  • MinnowBoard

Je te conseille d'aller voir la liste des cartes ici : elinux.org
Ce n'est pas exhaustif, mais l'avantage c'est que les cartes présentes içi ne sont normalement d'obscures produits chinois sortis d'on ne sait où. Il y a un minimum de documentation.

Bah y a plein de périphériques SPI ou I2C qui existent… Genre tu prend un module avec thermomètre en I2C et tu lis la datasheet pour connaître les registres.

Ensuite comme tout le temps en informatique, communiquer avec un périphérique consiste simplement à aller lire / écrire des registres.

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte