website/content/blog/minitel/index.eo.md

8 KiB
Raw Blame History

+++ title = "Minitel kiel terminalo GNU/Linux" date = 2022-05-15 description = "Ankoraŭ provo uzi Minitel kiel terminalo." draft=true [taxonomies] tags = ["Minitel", "retro", "Arduino"] +++

Celo: uzi unu Minitel kiel terminalo de sistemo GNU/Linux.

{{ float_img(alt="Minitel elmontranta la logotipon de Rust.", src="minitel_rust.jpg", style="max-height:100vh;max-width:min(800px,100%)") }}

Ĉi tio artikolo publikiĝis en la franclingva revuo Programmez! #256, kio enhavas multajn artikolojn pri la Minitel kaj sia interfacaĵo.

😎 La erao de la ĉirkaŭ-komputiko

La Minitel enhavas ĉirkaŭ-komputikan kontaktilon (france "prise péri-informatique"), kiu estas eneligo. Por komuniki kun ĝi, sufiĉas seria interfaco. Do mi uzis Arduinon kiel ponto inter Minitel kaj komputilo. Zorgu tamen, necesas Arduino kun multaj seriaj interfacoj (ekzemple la Mega). Ĉi tio evitas al ni programi serian pelilon. La normo ĉirkaŭ-komputiko uzas preskaŭ ASCII 7-bitoj en bitokoj. La fortpeza bito estas la kontrolsumo.

🔌 Elektroniko

{{ float_img(alt="Konektoskemo", src="minitel_wiring.svg", style="width:300px;background-color:#fff") }}

  • Konektu la GND de la Minitel (stifto 2, en la medio) al GND de la Arduino;
  • Konektu la RX de la Minitel (stifto 1, en la tute maldekstro de GND) al TX1 de la Arduino;
  • Konektu la RX1 de la Arduino al TX de la Minitel (stifto 3, en la tute dekstro de GND) tra 220Ω rezistilo, kaj al +5V tra pull-up 2200Ω rezistilo (ĉiu valoro inter 1kΩ kaj 20kΩ devus funkcii). La rezistilo necesas ĉar la eligo de la Minitel estas +8,5V.

💻 Programaro

Unue mi programis kontrolilon en Python. Ĝi simulas terminalon, kun USB kiel eneligo. Ĝi legas komandan linion, kaj ĝin efektivigas kiam la klavo "Sendo" frapiĝas.

{{ float_img(alt="Minitel ekmontranta la logotipon de Rust.", src="minitel_fortune.jpg", style="max-height:100vh;max-width:min(800px,100%)") }}

Tio sola malfaciligis:

  • Ne estas klavo "Novan Linion". Nur klavo "Ĉaretrevenigo". Sed feliĉe estas la bitoko "Novan Linion", ni do povas uzi CRLF.
  • Il n'y a pas de touche Nouvelle Ligne. Seulement une touche Retour Chariot. Mais par miracle le caractère Nouvelle Ligne existe, on peut donc utiliser du CRLF. Ça veut dire qu'il faut interpréter la touche Envoi (qui a un code sur deux octets) comme LF, et transformer les LF venant de Linux en CRLF.
  • Les accents ne sont pas standard. Une lettre accentuée fait trois octets : un qui indique un caractère spécial, un qui spécifie l'accent, et la lettre. Et attention! On a droit aux majuscules accentuées (coucou Windows, le Minitel fait une chose mieux que toi), mais seulement les accents franchouillards. La piñata et le glacier würmien n'ont pas la nationalité.
  • Le clavier est en majuscule, et les minuscules demandent l'appui de Maj. Si on veut inverser ce comportement, on doit pour chaque lettre arrivant au contrôleur, renvoyer un retour arrière puis la lettre en casse inversée. On voit le clignotement à l'écran et ça oblige à taper assez lentement pour que la réécriture ait le temps de s'opérer.
  • Le port péri-informatique supporte 1200 bit/s, soit un rafraîchissement complet de l'écran en plus de 6 secondes. Certains modèles sont plus rapides, jusqu'à 9600 bit/s. Cette lenteur oblige à optimiser l'affichage pour plus d'immédiateté. On ne peut pas rafraîchir tout l'écran en permanence, il faut envoyer uniquement les caractères qui changent. Donc s'il y a un bug (un imprévu dans le programme, un problème de signal, un utilisateur qui tape trop vite), l'écran ne sera pas dans l'état attendu, et le programme, qui n'a aucun moyen de le savoir, continuera même s'il écrit n'importe quoi.
  • En mode semi-graphique, les caractères sont remplacés par une grille de 2×3 pixels. On peut alors dessiner, en convertissant les images correctement. On a même quelques nuances de gris! (pas 50 mais c'est déjà bien) L'inconvénient, c'est que le changement de couleur agit sur le caractère entier, soit 6 pixels, et non sur chaque pixel individuellement. La gestion de la couleur est donc un peu délicate.
  • Si l'affichage est modifié en permanence, par exemple dans un jeu de Snake pour déplacer le serpent, l'appui de n'importe quelle touche peut interférer avec un caractère spécial de plusieurs octets envoyé par le contrôleur. Il en résulte un comportement imprévisible, et souvent un caractère aléatoire qui s'affiche. C'est pourquoi dans le Snake et dans le Tetris que j'ai faits, l'écran se retrouve vite constellé de caractères. J'ai essayé de nettoyer des petites parties différentes de l'écran en permanence, par exemple ligne par ligne, mais cela prend trop de temps, réduit la réactivité du jeu et n'est pas très efficace.
  • L'écran est très petit, 40×24 caractères seulement. Aussi, il ne défile pas mais reboucle en haut quand le curseur arrive en bas. Il n'est donc pas vraiment adapté à un terminal de type Unix. Il faut soit créer un système de pagination, qui nettoie l'écran à chaque page, soit accepter de reboucler et nettoyer la fin de la ligne.
  • Certains caractères manquent, comme la barre verticale |. Cette dernière étant indispensable dans un terminal, j'ai décidé de la substituer aux accents circonflexes ^ qui sont bizarrement affichés sur le Minitel.
  • Côté Linux ce n'est pas facile non plus... Il faut pouvoir indiquer aux programmes la taille du terminal, qu'ils comprennent qu'ils sont dans un terminal et non dans un script, pour que par exemple bash écrive son invite de commande (prompt), gérer le retour arrière (qui n'est pas géré directement par bash), etc.

Toutes ces contraintes rendent la conception d'un terminal générique compliquée. Il faut que chaque programme adapte sa gestion du clavier et de l'affichage, car les besoins sont différents pour un utilitaire en ligne de commande, un éditeur de texte, une messagerie instantanée ou un jeu en temps réel.

On m'a donc donné l'idée d'une approche différente : plutôt que d'envoyer la sortie des programmes au Minitel, on garde un tampon de l'écran du Minitel en mémoire. C'est un tableau de l'état de chaque caractère, dont le mode texte ou semi-graphique, la couleur, le clignotement, le code du caractère, etc. Les programmes écrivent dedans, puis demandent au contrôleur de l'envoyer. Au prix de calculs plus lents (ce qui reste négligeable), l'algorithme cherche alors à envoyer le moins de données possibles. Les caractères inchangés ne sont pas renvoyés, on profite de l'instruction plaçant le curseur à la position donnée et de celle permettant de répéter les N derniers caractères.

J'ai implémenté ce nouveau contrôleur en Rust (un langage bas-niveau offrant des abstractions haut-niveau sans coût et la sécurité de la mémoire), ce qui permet un code plus propre, sûr et rapide qu'en Python. C'est une bibliothèque réutilisable (publiée sous licence libre GNU AGPL), que j'ai pu utiliser pour faire un terminal, un Tetris et un Snake.

Au prix de quelques nanosieverts et d'un ultrason désagréable, cette petite aventure rétro m'a plongé dans une époque que je n'ai pas connue, quoique j'y vis peut-être encore.

Ressources utiles :