Serveur Minitel moderne - Connectez votre Minitel historique à l'Internet moderne via Raspberry Pi
Minitel-Serveur est une plateforme Java innovante qui transforme un terminal Minitel en navigateur web moderne grâce au format VTML (Videotex Markup Language). Le projet crée un pont technologique entre le protocole Videotex historique et les services web contemporains.
- Fonctionnalités
- Architecture
- Prérequis
- Installation et Configuration
- Démarrage Rapide
- Format VTML
- Modules Dynamiques (MModules)
- Composants Graphiques
- Navigation et Événements
- Développement et Debug
- Ressources Techniques
- Contribution
- 🌐 Serveur HTTP avec support du format VTML
- 📱 Client Minitel avec communication série optimisée
- 🔧 Modules dynamiques (MModules) extensibles
- 🎨 Composants graphiques (texte, images bitmap, menus)
- ⚡ Communication haute vitesse (9600 bauds sur Minitel 2)
- 🔗 Navigation interactive avec liens et menus
┌─────────────────┐ GPIO/Série ┌──────────────────┐
│ Minitel │ ◄────────────────► │ Raspberry Pi │
│ (Terminal) │ 7E1 Protocol │ │
└─────────────────┘ │ ┌─────────────┐ │ Ethernet
│ │ Java Server │ │ ◄──────────► Internet
│ │ + Client │ │
│ └─────────────┘ │
└──────────────────┘
StaticFileServer: Serveur HTTP servant les pages VTMLMinitelClient: Interface avec le terminal Minitel physiqueMinitelConnection: Gestion communication série (1200/4800/9600 bauds)Teletel: API haut niveau pour contrôle d'affichage VideotexMModulesManager: Système de plugins dynamiques
- Raspberry Pi (2, 3, 4 ou Zero)
- Terminal Minitel (Minitel 1 ou 2)
- Câble série DIN → GPIO ou USB-Série
- Connexion Ethernet/WiFi
- Java 17+ (OpenJDK 17 recommandé)
- Raspberry Pi OS ou distribution Linux
- Accès GPIO (
/dev/serial0configuré)
# Mise à jour du système
sudo apt update && sudo apt upgrade -y
# Installation d'OpenJDK 17
sudo apt install openjdk-17-jdk -y
# Vérification de l'installation
java -versionNote : Sur Raspberry Pi OS Lite, vous pouvez aussi utiliser
openjdk-17-jresi vous n'avez pas besoin de compiler.
Un script est fourni pour télécharger automatiquement toutes les dépendances Java depuis Maven Central :
cd lib
./download_libs.shLibrairies téléchargées :
- ZXing 3.5.1 - Génération de QR Codes
- Jackson 2.17.2 - Parsing JSON
- Jsoup 1.18.1 - Parsing HTML/XML (VTML)
- JSSC 2.8.0 - Communication série
- Rhino 1.7.14 - Moteur JavaScript
GPIO Raspberry Pi :
Pin 6 (GND) ──► Minitel GND
Pin 8 (TX) ──► Minitel RX
Pin 10 (RX) ──► Minitel TX
Pin 2 (5V) ──► Minitel 5V (si nécessaire)
Connexion avec le Minitel :
Le Minitel fonctionne en logique 5V tandis que le Raspberry Pi utilise du 3.3V. Un level shifter bidirectionnel est nécessaire pour la conversion des niveaux logiques. Un pull-up de 2.2kΩ sur la ligne RX (côté 3.3V) améliore la stabilité de réception clavier.
RASPBERRY PI LEVEL SHIFTER MINITEL
(3.3V Logic) (Bidirectionnel) (5V Logic)
┌─────────────┐ ┌─────────────────────┐ ┌─────────────┐
│ │ │ │ │ │
3.3V (Pin 1) ┼──────┬──────┼──────────────────┤ LV HV ├──────────────────┼── 5V │
│ │ │ │ │ │ │
GND (Pin 6) ─┼──────┼──────┼──────────────────┤ GND GND ├──────────────────┼── GND │
│ │ │ │ │ │ (DIN 2) │
│ │ │ │ │ │ │
Pin 8 (TX) ──┼──────┼──────┼──────────────────┤ LV1 HV1 ├──────────────────┼──► RX │
GPIO14 │ │ │ │ │ │ (DIN 1) │
│ │ │ │ │ │ │
│ 2.2kΩ │ │ │ │ │
│ └┬┐ │ │ │ │ │
│ ││ │ │ │ │ │
│ ┌┴┘ │ │ │ │ │
│ │ │ │ │ │ │
Pin 10 (RX) ◄┼──────┴──────┼──────────────────┤ LV2 HV2 ├──────────────────┼─── TX │
GPIO15 │ │ │ │ │ (DIN 3) │
│ │ │ │ │ │
└─────────────┘ └─────────────────────┘ └─────────────┘
Pull-up 2.2kΩ vers 3.3V
sur ligne RX uniquement
DÉTAIL CONNECTEUR DIN 5 BROCHES (vue face soudure)
┌───────────┐
/ 1 2 \
│ ● │
\ 3 4 /
└────5─────┘
Pin │ Signal │ Connexion
────┼─────────────┼────────────────
1 │ RX (entrée) │ ← HV1 (depuis RPi TX)
2 │ GND │ → GND commun
3 │ TX (sortie) │ → HV2 (vers RPi RX)
4 │ Device RDY │ NON CONNECTÉ
5 │ 8-12V │ ⚠️ NON CONNECTÉ
| Raspberry Pi | Level Shifter LV | Level Shifter HV | Minitel DIN |
|---|---|---|---|
| 3.3V (Pin 1) | LV | HV | - |
| GND (Pin 6) | GND | GND | Pin 2 |
| TX (Pin 8) | LV1 | HV1 | Pin 1 (RX) |
| RX (Pin 10) + pull-up 2.2kΩ → 3.3V | LV2 | HV2 | Pin 3 (TX) |
Info : Exemple de level shifter compatible : Gebildet 3.3V-5V 8 Channels Bi-Directional
Activez l'UART et désactivez la console série :
# Dans /boot/config.txt
enable_uart=1
dtoverlay=disable-bt
# Désactiver getty
sudo systemctl disable serial-getty@ttyAMA0.serviceImportant : Le Minitel démarre toujours en 1200 bauds à sa mise sous tension.
Le client intègre un système d'auto-négociation automatique de la vitesse série :
- Si le client est configuré en 9600 bauds (ou 4800) dans
config.jsonmais que le Minitel est en 1200 bauds, le client détecte la désynchronisation (réception de séries de0x00) - Le client bascule temporairement en 1200 bauds
- Il envoie la séquence PRO2 pour forcer le Minitel à la vitesse cible
- Il reconfigure le port série à la vitesse cible
- La communication reprend normalement
Séquences de changement de vitesse (PRO2) :
| Vitesse | Séquence HEX |
|---|---|
| 1200 bauds | 1B 3A 64 7F |
| 4800 bauds | 1B 3A 6A 7F |
| 9600 bauds | 1B 3A 6B 7F |
Note : Le script
switchTo9600b.shpermet de forcer manuellement le passage en 9600 bauds si nécessaire :chmod +x switchTo9600b.sh ./switchTo9600b.sh
Afin de réaliser le bon fonctionnement du client VTML, il est important de désactiver le mode ECHO du Minitel. Pour cela, réaliser la combinaison de touches suivante :
[Fnct] + [T] puis [E]
Si lorsque vous tapé des touches au clavier et que ces dernières apparaissent, alors le mode ECHO (OFF) n'est pas activé. Recommencez la combinaison de touches ci-dessus.
Note : Cette manipulation doit être effectuée après chaque mise sous tension du Minitel.
Le fichier config.json contient toute la configuration du serveur et du client :
{
"server": {
"port": 8080,
"defaultCharset": "utf-8"
},
"path": {
"root_path": "./root/",
"plugins_path": "./plugins/",
"mmodules_config_path": "./mmodules_config/"
},
"client": {
"serial_port": "/dev/serial0",
"serial_baud": 9600,
"serial_databits": "cs7",
"serial_parity": "parenb",
"serial_parity_odd": "-parodd",
"serial_stopbits": "-cstopb",
"serial_flow_hw": "-crtscts",
"serial_flow_sw": "-ixon -ixoff",
"serial_echo": "-echo",
"serial_icanon": "-icanon",
"serial_opost": "-opost",
"serial_chunk_size": 128,
"serial_chunk_delay_ms": 15,
"joystick_device_0": "/dev/input/js0",
"joystick_device_1": "/dev/input/js1",
"joystick_enabled": true,
"joystick_mapping_0": {
"buttons": { "0": "ACTION1", "1": "ACTION2" },
"axes": { "0+": "RIGHT", "0-": "LEFT", "1+": "DOWN", "1-": "UP" },
"axis_threshold": 16000
},
"joystick_mapping_1": {
"buttons": { "0": "ACTION1", "1": "ACTION2" },
"axes": { "0+": "RIGHT", "0-": "LEFT", "1+": "DOWN", "1-": "UP" },
"axis_threshold": 16000
}
}
}| Section | Clé | Description |
|---|---|---|
server.port |
int | Port HTTP du serveur (défaut: 8080) |
server.defaultCharset |
string | Encodage des pages (défaut: utf-8) |
path.root_path |
string | Répertoire des pages VTML |
path.plugins_path |
string | Répertoire des MModules |
path.mmodules_config_path |
string | Répertoire des configurations MModules |
client.serial_port |
string | Port série du Minitel |
client.serial_baud |
int | Vitesse: 1200, 4800 ou 9600 |
client.serial_databits |
string | Bits de données: cs5, cs6, cs7, cs8 (défaut: cs7) |
client.serial_parity |
string | Parité: parenb (activée) ou -parenb (désactivée) |
client.serial_parity_odd |
string | Parité impaire: parodd ou -parodd (défaut: -parodd = paire) |
client.serial_stopbits |
string | Stop bits: cstopb (2) ou -cstopb (1, défaut) |
client.serial_flow_hw |
string | Flow control matériel: crtscts ou -crtscts (défaut) |
client.serial_flow_sw |
string | Flow control logiciel: "ixon ixoff" ou "-ixon -ixoff" (défaut) |
client.serial_echo |
string | Echo local: echo ou -echo (défaut) |
client.serial_icanon |
string | Mode canonique: icanon ou -icanon (défaut) |
client.serial_opost |
string | Post-processing sortie: opost ou -opost (défaut) |
client.serial_chunk_size |
int | Taille des blocs d'envoi en bytes (défaut: 128) |
client.serial_chunk_delay_ms |
int | Délai entre blocs en ms (défaut: 15, utile pour Minitel Philips) |
client.joystick_enabled |
bool | Activer le support joystick USB |
client.joystick_device_0 |
string | Périphérique joystick joueur 0 |
client.joystick_device_1 |
string | Périphérique joystick joueur 1 |
client.joystick_mapping_0 |
object | Mapping boutons/axes joueur 0 |
client.joystick_mapping_1 |
object | Mapping boutons/axes joueur 1 |
La configuration par défaut est 7E1 (7 bits, parité paire, 1 stop bit), compatible avec tous les Minitel :
| Paramètre | Valeur | Description |
|---|---|---|
serial_databits |
cs7 |
7 bits de données (protocole Videotex) |
serial_parity |
parenb |
Parité activée |
serial_parity_odd |
-parodd |
Parité paire (Even) |
serial_stopbits |
-cstopb |
1 stop bit |
Les Minitel 2 Philips sont plus sensibles au débit que les Alcatel. Si vous rencontrez des problèmes d'affichage (caractères manquants, corruption), ajustez le throttling :
"serial_chunk_size": 64,
"serial_chunk_delay_ms": 20Un script de déploiement est fourni pour copier les fichiers nécessaires vers un dossier cible (ex: Raspberry Pi) :
./deploy.shLe script copie :
- Le JAR compilé (
dist/) - Les pages VTML (
root/) - Les librairies (
lib/) - Les plugins (
plugins/) - Les scripts de démarrage (
*.sh) - Le fichier de configuration (
config.json)
# Compiler le projet
javac -cp "lib/*:src" -d build src/org/somanybits/minitel/**/*.java
# Créer le JAR
jar cfm Minitel.jar manifest.mf -C build .# Démarrer le serveur (utilise config.json)
java -cp Minitel.jar org.somanybits.minitel.server.StaticFileServer
# Ou utiliser le script fourni
./startserver.sh# Connecter le client au serveur
java -jar Minitel.jar localhost 8080
# Ou utiliser le script fourni
./startclient.shUn utilitaire de diagnostic permet de tester les joysticks et d'identifier les numéros de boutons/axes :
# Lancer l'utilitaire de test
./test_joystick.shL'utilitaire propose de tester :
- 0 : Joystick 0 uniquement (
/dev/input/js0) - 1 : Joystick 1 uniquement (
/dev/input/js1) - 2 : Les deux joysticks simultanément
Exemple de sortie :
[J0] 🔘 BOUTON 0 PRESSÉ
[J0] → Config: "0": "ACTION1" ou "ACTION2"
[J0] 🕹️ AXE 0 = 32767 (+) →
[J0] → Config: "0+": "RIGHT"
Utilisez ces informations pour configurer le mapping dans config.json.
Des scripts sont fournis pour installer M-Kiwi en tant que services systemd sur Raspberry Pi :
# Installation
sudo ./install_services.sh
# Désinstallation
sudo ./uninstall_services.shUne fois installés, les services peuvent être gérés avec systemctl :
sudo systemctl start mkiwi-server # Démarrer le serveur
sudo systemctl start mkiwi-client # Démarrer le client
sudo systemctl status mkiwi-server # Voir le status
sudo journalctl -u mkiwi-client -f # Voir les logs
⚠️ Non testé : Ces scripts sont en cours de développement. Voir docs/SERVICES.md pour plus de détails.
VTML est un langage de markup spécialement conçu pour les contraintes du Minitel (40×25 caractères).
📖 Documentation complète : docs/VTML.md
Fichier : root/index.vtml
<minitel title="Accueil">
<!-- Zone de texte positionnée -->
<div class="frame" left="6" top="2" width="30" height="10">
<row> __ __ _ _ _ _ </row>
<row>| \/ (_)_ __ (_) |_ ___| |</row>
<row>| |\/| | | '_ \| | __/ _ \ |</row>
<row>| | | | | | | | | || __/ |</row>
<row>|_| |_|_|_| |_|_|\__\___|_|</row>
<br>
<row> LE LIEU TRANQUILLE </row>
</div>
<!-- Menu interactif -->
<menu name="main" left="4" top="10" width="30" height="10" keytype="number">
<item link="actualites.vtml">1. Actualités</item>
<item link="bar/">2. Bar</item>
<item link="concerts/">3. Concerts</item>
<item link="ServerStatus.mod?val1=69&val2=hello">4. Info Serveur</item>
<item link="wifi/">5. WiFi</item>
</menu>
</minitel>| Tag | Description | Attributs |
|---|---|---|
<minitel> |
Conteneur principal | title |
<div> |
Zone de texte positionnée | left, top, width, height, class |
<row> |
Ligne de texte dans une div | - |
<menu> |
Menu interactif | name, left, top, width, height, keytype |
<item> |
Élément de menu | link |
<br> |
Saut de ligne | - |
┌─────────────────────────────────────────┐ ← 40 caractères
│ (0,0) (39,0) │
│ │
│ │ ← 25 lignes
│ │
│ (0,24) (39,24) │
└─────────────────────────────────────────┘
Les MModules sont des plugins Java qui étendent les fonctionnalités du serveur, similaires aux CGI ou modules PHP.
- Chargement automatique : Tous les fichiers
.jardansplugins/mmodules/sont chargés au démarrage - Activation via URL :
http://localhost:8080/NomModule.mod - Paramètres GET : Support des variables via query string
- Réponse VTML : Les modules génèrent du contenu VTML dynamique
package org.somanybits.minitel.server.mmodules;
import com.sun.net.httpserver.HttpExchange;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;
import org.somanybits.minitel.server.ModelMModule;
import org.somanybits.minitel.server.StaticFileServer;
public class ServerStatus extends ModelMModule {
public ServerStatus(HashMap params, HttpExchange ex, Path docRoot) {
super(params, ex, docRoot);
}
@Override
public String getResponse() {
String resp = "<minitel><div>\n";
resp += "<row>Module: " + this.getClass().getSimpleName() + "</row>\n";
resp += "<row>Version: " + getVersion() + "</row>\n";
resp += "<row>Serveur: " + StaticFileServer.VERSION + "</row>\n";
resp += "<row>Adresse: " + ex.getLocalAddress() + "</row>\n";
// Affichage des paramètres GET
if (params != null) {
resp += "<row>Paramètres:</row>\n";
for (Map.Entry<String, String> entry : params.entrySet()) {
resp += "<row> " + entry.getKey() + " = " + entry.getValue() + "</row>\n";
}
}
resp += "</div></minitel>\n";
return resp;
}
@Override
public String getVersion() {
return "1.0";
}
@Override
public String getContentType() {
return "text/plain; charset=UTF-8";
}
}URL avec paramètres :
http://localhost:8080/ServerStatus.mod?utilisateur=eddy&niveau=admin
Récupération dans le module :
String utilisateur = params.get("utilisateur"); // "eddy"
String niveau = params.get("niveau"); // "admin"Chaque MModule peut avoir son propre fichier de configuration JSON. Le fichier doit être placé dans le répertoire mmodules_config/ (défini par mmodules_config_path dans config.json) et nommé NomDuModule.json.
Exemple de fichier de configuration (mmodules_config/MonModule.json) :
{
"apiKey": "ma-cle-secrete",
"maxResults": 50,
"dataPath": "/chemin/vers/donnees/"
}Utilisation dans le module :
public class MonModule extends ModelMModule {
public MonModule(HashMap params, HttpExchange ex, Path docRoot) {
super(params, ex, docRoot);
}
@Override
public String getResponse() {
// Charger la configuration
JsonNode config = readConfig();
if (config != null) {
// Lire les valeurs
String apiKey = config.get("apiKey").asText();
int maxResults = config.get("maxResults").asInt();
String dataPath = config.get("dataPath").asText();
// Utiliser les valeurs...
}
return "<minitel>...</minitel>";
}
}Méthodes disponibles :
| Méthode | Description |
|---|---|
readConfig() |
Charge et retourne le fichier JSON de configuration (JsonNode), ou null si absent |
getConfigPath() |
Retourne le chemin du fichier de configuration (après appel à readConfig()) |
ServerStatus.mod: Informations systèmeQRCodeDemo.mod: Générateur de QR codes interactifWiFiQRDemo.mod: Génération de QR Codes WiFi pour connexion automatiqueMeteo.mod: Données météorologiques via APINews.mod: Flux RSS adapté pour MinitelChat.mod: Système de messagerie simpleIoT.mod: Monitoring capteurs domestiques
ServerScore est un module natif de M-Kiwi permettant de gérer des tableaux de scores pour les jeux. Il offre une API HTTP simple pour créer, enregistrer et consulter les meilleurs scores.
http://localhost:8080/ServerScore.mod?mode=read&gameid={GameId}&fields=score,name
Modes disponibles :
create: Créer un nouveau tableau de scoreswrite: Enregistrer un scoreread: Lire tous les scorestop1: Meilleur scoretop10: 10ème meilleur score
📖 Documentation complète : docs/ServerScore.md
Le système GraphTel permet d'afficher des images bitmap et de générer des QR codes sur Minitel :
// Conversion d'image en bitmap 1bpp
ImageTo1bpp img = new ImageTo1bpp("images_src/photo.jpg", 80, 69);
// Création du composant graphique
GraphTel gfx = new GraphTel(img.getWidth(), img.getHeight());
gfx.writeBitmap(img.getBitmap());
gfx.inverseBitmap(); // Inversion noir/blanc si nécessaire
gfx.drawToPage(teletel, 0, 1); // Affichage à la position (0,1)// Génération de QR Code centré avec échelle 2
graphtel.generateCenteredQRCode("https://example.com", 2);
// QR Code SCANNABLE avec ZXing (iPhone/Android compatible)
graphtel.generateCenteredScannableQR("https://eddy-briere.com", 2);
// QR Code WiFi pour connexion automatique
graphtel.generateWiFiWPA("MonWiFi", "motdepasse123", 2);
graphtel.generateWiFiOpen("WiFi_Gratuit", 2);
// QR Code de test avec motif de vérification
graphtel.generateTestQRCode(10, 10, 3);
// Motif visuel décoratif
graphtel.generateCenteredVisualQR("MINITEL 2024", 3);Caractéristiques QR Code :
- Résolution : 80×75 pixels en semi-graphique
- Versions supportées : QR Code Version 1 (21×21 modules)
- Facteurs d'échelle : 1x à 4x (recommandé : 2x ou 3x)
- Encodage : Texte simple, URLs, données courtes
Le client gère automatiquement :
- Touches numériques : Navigation dans les menus
- Touches directionnelles : Déplacement curseur (mode 80 colonnes)
- Touches fonction : SOMMAIRE, RETOUR, SUITE, ENVOI, etc.
- Touches spéciales : CORRECTION, RÉPÉTITION, GUIDE
<!-- Lien vers page statique -->
<item link="actualites.vtml">Actualités</item>
<!-- Lien vers dossier (cherche index.vtml) -->
<item link="services/">Services</item>
<!-- Lien vers module avec paramètres -->
<item link="meteo.mod?ville=paris&format=simple">Météo Paris</item>Le système de logs intégré permet le suivi :
LogManager logmgr = Kernel.getInstance().getLogManager();
logmgr.addLog("Message d'information", LogManager.MSG_TYPE_INFO);
logmgr.addLog("Erreur détectée", LogManager.MSG_TYPE_ERROR);Pour développer sans Minitel physique :
- Utilisez un émulateur Minitel (MiniTel, WinTel)
- Connexion TCP au lieu de série pour tests
- Mode debug avec affichage console des séquences
- Format série : 7E1 (7 bits, parité paire, 1 stop bit)
- Vitesses : 1200 bauds (standard), 4800/9600 bauds (Minitel 2)
- Séquences d'échappement : Compatible norme française
La ligne 0 du Minitel est la ligne de status système. Y écrire peut causer des problèmes d'affichage. Par défaut, l'écriture sur la ligne 0 est interdite et le curseur est automatiquement déplacé en ligne 1.
En JavaScript :
// Autoriser l'écriture sur la ligne 0
enableLineZero(true);
// Vérifier si la ligne 0 est accessible
if (isLineZeroEnabled()) {
// ...
}
// Réactiver la protection
enableLineZero(false);En Java :
GetTeletelCode.enableLineZero(true); // Autoriser
GetTeletelCode.enableLineZero(false); // Protéger (défaut)Ce projet est ouvert aux contributions ! N'hésitez pas à :
- Signaler des bugs
- Proposer des améliorations
- Créer de nouveaux MModules
- Améliorer la documentation
Auteur : Eddy BRIERE (peassembler@yahoo.fr)
Version : Client 0.7.2, Serveur 0.4
Licence : Open Source