J'ai un appareil qui envoie des informations via USB à mon ordinateur. Arch Linux configure cet appareil en créant un fichier nommé ttyUSB0
dans /dev/
. J'utilise GTKterm
pour recevoir ces informations entrantes et les afficher dans une fenêtre de terminal émulée.
Ma question est de savoir comment GTKterm
lit/écrit exactement ce ttyUSB0
fichier, et où puis-je commencer à apprendre comment implémenter des fonctionnalités similaires? Autrement dit, dans la forme la plus élémentaire, comment pourrais-je écrire un caractère dans ttyUSB0
, ou, au contraire, recevoir un octet et l'écrire dans un fichier?
Les ATS sont des fichiers que vous pouvez utiliser comme n'importe quel autre. Vous pouvez les ouvrir avec les outils standard d'ouverture de fichier de votre langue et lire ou écrire à partir d'eux. Ils ont un comportement spécial différent des fichiers "ordinaires", mais les bases sont les mêmes. Je couvrirai certains des cas spéciaux à la fin, mais d'abord, une expérience.
Une chose intéressante que vous pouvez faire directement depuis un terminal ordinaire. Exécutez tty
et il affichera une ligne comme:
/dev/pts/2
C'est l'appareil TTY sur lequel votre terminal fonctionne. Vous pouvez écrire quelque chose sur ce terminal:
$ echo Hello > /dev/pts/2
Hello
$
Vous pouvez même en lire:
$ read X < /dev/pts/2
hello
$ echo $X
hello
$
(read X
Est la commande "lire une ligne de l'entrée standard dans la variable X" de sh; la <consiste à utiliser/dev/pts/2 comme entrée standard pour la commande de lecture; le premier "bonjour" que j'ai tapé, et le second a été imprimé).
Si vous ouvrez un autre shell, par exemple en utilisant screen
ou xterm
, vous pouvez exécuter exécuter echo spooky > /dev/pts/2
Dans ce shell pour faire apparaître le texte sur votre terminal d'origine, et le même pour les autres commandes. Tout cela est juste votre Shell ouvrant un fichier sans savoir qu'il s'agit d'un ATS.
Voici un programme C très simple qui fait exactement ce que vous avez demandé, et écrit un seul caractère dans/dev/pts/3, puis en lit un seul octet:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main() {
char byte;
int fd = open("/dev/pts/3", O_RDWR);
write(fd, "X", 1);
ssize_t size = read(fd, &byte, 1);
printf("Read byte %c\n", byte);
return 0;
}
Un véritable appareil TTY attaché à un émulateur Shell ou terminal aura un comportement intéressant, mais vous devriez récupérer quelque chose.
Pour accéder à un terminal, vous devez être autorisé à l'utiliser. Ce ne sont que les autorisations de fichier standard que vous voyez avec ls -l
Et définies avec chmod
: vous avez besoin d'une autorisation de lecture pour ouvrir le fichier et le lire, et une autorisation d'écriture pour y écrire. Les ATS qui soutiennent votre terminal vous appartiendront, mais pas ceux d'un autre utilisateur, et les ATS pour les périphériques USB peuvent ou non l'être, selon votre configuration. Vous pouvez modifier les autorisations de la même manière que toujours.
En ce qui concerne l'écriture d'un programme pour travailler avec lui, vous n'avez pas besoin de faire beaucoup de spécial. Vous pouvez voir dans l'exemple qu'une chose que vous n'avez pas à faire est de fermer le fichier à chaque fois pour que vos données soient lues par l'autre extrémité: les fichiers TTY agissent comme des pipelines, poussant simplement les données dans les deux sens à mesure qu'elles entrent. Ce n'est pas comme écrire dans un fichier normal où les données sont enregistrées sur le disque - elles sont transmises immédiatement de l'autre côté ou stockées en mémoire jusqu'à ce que quelqu'un le lit.
Vous voudrez peut-être utiliser la fonction sélectionner pour pouvoir faire d'autres choses en attendant que l'appareil dise quelque chose, mais si vous êtes content d'attendre que les données passent, vous pouvez simplement utiliser bloquer les lectures et laisser le système d'exploitation faire le levage.
Une chose à garder à l'esprit est qu'il peut y avoir une taille de tampon limitée dans le noyau, et si vous écrivez beaucoup de données à la fois, vous pouvez finir par bloquer sans le vouloir. Si cela est susceptible d'être un problème, utilisez IO non bloquant avec open("/dev/...", O_RDWR | O_NONBLOCK)
. Le principe sera le même dans les deux cas.