Suivez-nous sur X

|
|
|
0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z,
ALL
|
|
0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z
|
|
0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z
|
|
A propos d'Obligement
|
|
David Brunet
|
|
|
|
Programmation : AMOS - AMOStel, un émulateur Minitel en AMOS (1re partie : les jeux de caractères)
(Article écrit par François Lionet et extrait d'Amiga News Tech - mars 1992)
|
|
Chose promise, chose due : Daisy et moi nous sommes réconciliés ! Main dans la patte, nous allons vous proposer
dans cette rubrique, de réaliser un émulateur Minitel complet en AMOS.
Il s'agit d'un travail de longue haleine, dont la publication sera étalée sur plusieurs articles. Nous
n'allons pas trop nous étendre sur l'émulation elle-même, ce qui prendrait tout le magazine
pendant plusieurs mois, mais plutôt sur l'implémentation en AMOS. Ainsi aujourd'hui, vous trouverez
un truc permettant de changer le jeu de caractères dans toute fenêtre ouverte.
À propos de la documentation :
le Minitel est un domaine assez professionnel, à cheval sur les réseaux de communication et la
telématique. Les documentations que l'on trouve sont en général assez ardues. Nous avons cependant
trouvé quelques livres assez abordables, comme Guide Pratique Du Vidéotex aux éditions Eyrolles.
Les jeux de caractères
Première chose à faire pour émuler le Minitel, reproduire ses jeux de caractères. Le Minitel
ne contient pas moins de quatre jeux de cent vingt-huit caractères différents chacun.
- Jeu G0 : les caractères ASCII presque standard. Les lettres de l'alphabet,
les chiffres et ponctuations. Neuf caractères sont spécifiques, de $5b à $5e, et de $7b à $7f.
- Jeu G1 : les mosaïques contiguës. C'est grâce à ces caractères semi-graphiques que
les serveurs peuvent afficher des images. Chaque caractère est divisé en six (deux par trois), et
toutes les combinaisons sont explorées.
- Jeu G2 : les mosaïques séparées, semblables aux précédentes avec un trait noir entre
chaque pavé. Ces mosaïques sont souvent utilisées par les serveurs. L'annuaire électronique affiche
le cadran de téléphone en haut à gauche de l'image avec les caractères du jeu G2.
- Jeu G3 : les caractères spéciaux, à savoir les accents et trémas.
Comment implémenter
ceci en AMOS ? Il est en effet impossible (théoriquement) de changer le jeu de caractères courant d'un
écran. Impossible, jusqu'à maintenant ! La fonction "=SCREEN BASE" retourne l'adresse de base de la
structure interne de définition d'un écran AMOS. En position 170 de cette structure, se trouve l'adresse
de la structure de la fenêtre courante, dans laquelle l'adresse du jeu de caractères se trouve en position 8.
La petite procédure suivante fait pointer le jeu de caractères courant sur une adresse quelconque.
Procedure _SET WINDOW_FONT[A]
AFONT=Leek(Screen Base+170)+8
Loke AFONT,A
End Proc
|
Pour aller plus rapidement lors de l'affichage, les caractères sont codés très simplement : l'un après
l'autre, se trouvent les huit octets de définition de chaque caractère. Le jeu de caractères comprend
les trente-deux premiers caractères, même si ceux-ci ne sont pas accessibles.
Quelques applications :
- Notre programme d'émulation, bien sûr. Nous allons fabriquer une banque mémoire contenant les
quatre jeux à la suite.
- Définir de nouveaux symboles graphiques.
- Coder un listing, en faisant pointer les caractères sur n'importe quoi. Il n'y a aucun risque.
Le nec plus ultra étant de faire pointer sur des données modifiées, par exemple "_SET_WINDOW_FONT[Log Base(0)]".
Le programme ouvre un écran deux couleurs dans lequel il travaille. Il crée les quatre jeux à la
suite l'un de l'autre. La plupart des caractères sont définis dans le jeu par défaut de l'AMOS.
Il suffit de les afficher avec un "PRINT" normal, ce que fait la procédure "_CPRINT[]".
On imprime d'abord les caractères ASCII normaux, puis les caractères spécifiques, en les prenant
dans les codes supérieurs à 128.
La procédure "_GET_FONT[]" se charge de transférer la police
de l'écran dans la banque. Les jeux graphiques sont quant à eux fabriqués à partir des données (datas),
en explorant toutes les différentes possibilités.
L'émulateur
Vous devez vous procurer un câble Minitel-Amiga et relier les deux machines. Pour le moment,
toutes les manipulations doivent se faire sur le Minitel.
L'interface série fonctionne correctement à partir d'AMOS 1.3. Attention cependant, il se peut
que le programme ne fonctionne qu'une fois, puis bloque la deuxième fois. Ce problème ne vient pas
de l'AMOS, mais de Commodore : une version du serial.device contient un bogue.
Solution : copier le fichier Devs/serial.device de votre disquette Workbench originale sur votre
disquette AMOS.
Le programme est composé de deux procédures principales :
- "_DISPLAY_INIT" : initialise l'écran et lit toutes les données des codes de contrôle.
- "_DISPLAY[A]" : réceptionne un caractère, et émule l'écran du Minitel. Le caractère peut
provenir de l'interface série, ou d'une banque mémoire dans laquelle vous aurez enregistré des
données.
Ces deux procédures peuvent facilement être récupérées dans d'autres programmes. Vous devez pour cela :
- Copier les deux procédures et la définition des variables globales.
- Ouvrir un écran 16 couleurs basse résolution, d'au minimum 320x200 pixels.
- Appeler la procédure "_DISPLAY_INIT".
Ce qui est émulé
Bien que l'Amiga soit infiniment supérieur au niveau graphique au Minitel, l'émulation
de l'affichage est assez complexe à réaliser, du fait de la présence de codes de contrôles de
couleur, appelés attributs graphiques.
Qu'est-ce donc qu'un attribut graphique ? Il s'agit d'un caractère affiché par le Minitel comme un
espace, et définissant les caractéristiques de ce qui vient à sa droite sur l'écran.
Peuvent ainsi être définies la couleur de fond et le soulignement.
Lorsque l'on affiche un caractère à l'écran, il faut donc pour connaître sa couleur de fond, explorer la
ligne de la gauche vers la droite. Une émulation parfaite n'est donc possible qu'en langage machine.
En AMOS, il faut ruser. Nous gardons en mémoire (dans la banque 11) une grille représentant l'écran.
Cette grille contiendra les attributs graphiques. Nous avons aussi volontairement simplifié l'émulation.
Tout fonctionne, sauf le soulignement, utilisé extrêmement finement par les serveurs, et par
conséquent très difficile à reproduire, et le défilement. Pour les initiés, le niveau de l'émulation
se situe entre Amigatel et Flammitel.
Fonctionnement du programme
AMOS permet d'adresser des labels contenus dans des chaînes de caractères. C'est extrêmement pratique
et surtout, rapide. Notre émulateur doit en effet fonctionner assez rapidement et ne pas aller moins
vite que le débit de la prise série !
Nous usons (et abusons) de cette facilité dans le programme :
- "CMODE$" contient la fonction actuelle. La première instruction de la procédure "_DISPLAY"
branche directement à la routine, sans perdre de temps en tests. Les routines de traitements spécifiques
peuvent, par une simple égalité, modifier le branchement lors du prochain appel de la procédure.
- Les labels des routines de gestion des codes de contrôle se trouvent dans les tableaux "CMODE$()"
et "ESC$()". Le numéro du code pointe directement dans le tableau. En un coup de cuillère à pot,
on connaît la routine à appeler. Nous utilisons une méthode toute simple pour afficher les caractères
en double largeur (ou hauteur) : on affiche le caractère en taille normale, puis on le zoome à même l'écran.
'*****************************
' Émulateur Minitel en AMOS
' Par Daisy & François Lionet
' Partie 1 : l'affichage
'*****************************
'
' Tableaux des codes de controle
Dim CMODE$(32),ESC$(128)
'
' Variables globales
Global CMODE$,CMODE$(),ESC$(),OCMODE$
Global GMODE,FLSH,G2$,GOPAP,CPAP,CPEN,CINV,PRNT$,ALAST
Global XCU,YCU,OXCU,OYCU
Global PAR1,PAR2,PAR3
Global AATR
'
' Faire fonctionner Minitel_Fonte.AMOS
' puis ce programme. Vous pouvez ensuite
' enlever la ligne suivante...
'Load "ram:minitel_fonte.abk",15
'
' Ouverture de l'écran d'exemple
Screen Open 0,320,200,16,0 : Flash Off : Cls 0
_DISPLAY_INIT
'
' Ouvre l'interface série
Serial Open 0,1
'
' Boucle d'exemple
Repeat
'
_SERIAL_GET
A=Param : If A>=0 : _DISPLAY[A,1] : End If
'
Until A<0
'
' Fermeture de la série
Serial Close
'
Procedure _DISPLAY_INIT
'
' Préparation de l'ecran
Paper 0 : Cls
Wind Open 1,0,8,40,24
'
' La palette du minitel ne comprend que des couleurs
' extrèmement vives!
Palette 0,$F00,$F0,$FF0,$F,$F0F,$FF,$FFF
' Fait clignoter les couleurs 8-15
For C=0 To 7
V=Colour(C)
Flash C+8,"("+Mid$(Hex$(V,3),2)+",20)(000,20)"
Next
'
' Initilisalisation des fenetres
Window 1 : Paper 0 : Pen 7 : Clw
Scroll Off : Curs Off
'
Window 0 : Paper 0 : Pen 7 : Clw
Scroll Off : Curs On : _SET_FONT[0]
'
' Initialisation des attributs
CMODE$="_G0"
GMODE=0 : FLSH=0 : PRNT$="_NNPRINT"
GOPAP=-1 : CPAP=0 : CPEN=7 : CINV=0
'
' Lis les codes de controle
For C=0 To 31 : Read CMODE$(C) : Next
'
' Lis les code d'échappement
Repeat : Read C : Read ESC$(C) : Until ESC$(C)=""
'
' Chaine de définition des caracteres spéciaux
G2$=Chr$($41)+"eèaàuù"+Chr$($42)
G2$=G2$+"eé"+Chr$($43)+"eêaâiîuûoô"
G2$=G2$+Chr$($48)+"eëiïaä"
G2$=G2$+Chr$($4B)+"cç"
'
' Initialise la carte de couleurs
Erase 11 : Reserve As Work 11,40*26 : AATR=Start(11)
Fill AATR To AATR+25*40,0
'
' Jeu de commandes du mode C0
Data "_Nul","_Nul","_Nul","_Nul"
Data "_Nul","_Nul","_Nul","_Nul"
Data "_ARR","_AVT","_BAS","_HAU"
Data "_CLS","_DLI","_GG1","_GG0"
Data "_Nul","_CON","_RPT","_CLA"
Data "_COF","_Nul","_GG2","_Nul"
Data "_CAN","_GG2","_SKP","_ESC"
Data "_Nul","_Nul","_HOM","_LOC"
'
' Jeu de commandes ESCAPE
Data $39,"_dld",$3A,"_lkk",$3B,"_dlk"
Data $40,"_PEN",$41,"_PEN",$42,"_PEN",$43,"_PEN"
Data $44,"_PEN",$45,"_PEN",$46,"_PEN",$47,"_PEN"
Data $48,"_GFL",$49,"_NFL",$4A,"_Nul",$4B,"_Nul"
Data $4C,"_GNN",$4D,"_GDY",$4E,"_GDX",$4F,"_GDD"
Data $50,"_PAP",$51,"_PAP",$52,"_PAP",$53,"_PAP"
Data $54,"_PAP",$55,"_PAP",$56,"_PAP",$57,"_PAP"
Data $58,"_Nul",$59,"_G1N",$5A,"_G1L",$5B,"_CSI"
Data $5C,"_NOR",$5D,"_INV",$5E,"_Nul",$5F,"_Nul"
Data 0,""
'
End Proc
'
Procedure _DISPLAY[A,F]
'
Goto CMODE$
'
' Entree impression normale
_G0:
If A<32 Then OCMODE$=CMODE$ : Goto CMODE$(A)
ALAST=A : Gosub PRNT$ : Pop Proc
'
' Impression normale
_NNPRINT:
If GMODE=0
If A<>$20
Gosub _ATTRIB
Print At(XCU,YCU)+Chr$(A);
Gosub _CRIGHT
Else
Gosub _ATTRIB : Gosub _LATCH : Print At(XCU,YCU)+" ";
Gosub _DELIM : Gosub _CRIGHT
End If
Else
Gosub _DELIM
Print At(XCU,YCU)+Chr$(A);
Gosub _CRIGHT
End If
Return
'
' Impression double largeur
_DXPRINT:
If XCU>38 Then Goto _NNPRINT
Gosub _CRIGHT : Gosub _NNPRINT
X=X Graphic(XCU-1) : Y=Y Graphic(YCU)
Zoom 0,X,Y,X+8,Y+8 To 0,X-8,Y,X+8,Y+8
Return
'
' Impression double hauteur
_DYPRINT:
If YCU<2 Then Goto _NNPRINT
X=X Graphic(XCU) : Y=Y Graphic(YCU)
Gosub _NNPRINT
Zoom 0,X,Y,X+8,Y+8 To 0,X,Y-8,X+8,Y+8
If XCU=0 : Gosub _CDOWN : End If
Return
'
' Impression double
_DDPRINT:
If XCU>38 Then Goto _DXPRINT
If YCU<1 Then Goto _DYPRINT
X=X Graphic(XCU+1) : Y=Y Graphic(YCU)
Gosub _CRIGHT : Gosub _NNPRINT
Zoom 0,X,Y,X+8,Y+8 To 0,X-8,Y-8,X+8,Y+8
If XCU<=1 : Gosub _CDOWN : End If
Return
'
' Trouve la couleur de papier
_ATTRIB:
AA=Peek(AATR+YCU*40+XCU) : P=AA and $7
If P<>CPAP : Paper P : CPAP=P : Gosub _SINV : End If
Return
'
' Met un délimiteur dans les couleurs
_DELIM:
Gosub _LATCH : AA=CPAP+$80
If XCU<39
For XA=XCU To 39
O=Peek(AATR+YCU*40+XA) : Poke AATR+YCU*40+XA,AA
Exit If AA=O or Btst(7,O)
Bclr 7,AA
Next
End If
Return
'
' Faut-il changer la couleur de papier
_LATCH:
If GOPAP>=0
CPAP=GOPAP : GOPAP=-1 : Paper CPAP : Gosub _SINV
End If
Return
'
' Passe en inverse s'il faut
_SINV: If CINV : Inverse On Else Inverse Off : End If
Return
'
' Vers la droite
_CRIGHT: Inc XCU
If XCU>=40
XCU=0 : If YCU>0 : Gosub _CDOWN : End If
End If
Locate XCU,YCU
Return
'
' Vers la gauche
_CLEFT: Dec XCU
If XCU<0
XCU=39 : If YCU>0 : Gosub _CUP : End If
End If
Locate XCU,YCU
Return
'
' Vers le bas
_CDOWN:
If YCU=0
XCU=OXCU : YCU=OYCU : Gosub _NLINE
Else
Inc YCU : Gosub _NLINE
If YCU=25 : YCU=1 : End If
End If
Locate XCU,YCU
Return
'
' Vers le haut
_CUP:
If YCU
Dec YCU : Gosub _NLINE
If YCU=0 : YCU=24 : End If
End If
Locate XCU,YCU
Return
'
' Code non utilisé
_NUL: Pop Proc
'
' Codes de mouvement du curseur
_ARR: Gosub _CLEFT : Pop Proc
_AVT: Gosub _CRIGHT : Pop Proc
_HAU: Gosub _CUP : Pop Proc
_BAS: Gosub _CDOWN : Pop Proc
_DLI: XCU=0 : Locate XCU,YCU
Gosub _NLINE : Gosub _DELIM : Pop Proc
'
' Efface jusqu'à la fin de la ligne
_CAN: Paper CPAP : Gosub _SINV
ACAN=CPAP+$80
If XCU<40
Locate XCU,YCU
For X=XCU To 39
Print " ";
Poke AATR+YCU*40+X,ACAN : Bclr 7,ACAN
Next
Locate XCU,YCU
End If
Pop Proc
'
' Curseur
_CON: Curs On : Pop Proc
_COF: Curs Off : Pop Proc
'
' Home / Clear
_HOM: XCU=0 : YCU=1
Locate XCU,YCU : Gosub _DEF : Pop Proc
_CLS: Gosub _DEF
Window 1 : Clw : Window 0 : XCU=0 : YCU=1
Fill AATR+40 To AATR+25*40,0 : Pop Proc
'
' Mode mosaique
_GG1: _SET_FONT[1] : GMODE=1
CINV=0 : Gosub _SINV : Gosub _DEF2 : Pop Proc
_GG0: _SET_FONT[0] : GMODE=0 : Gosub _DEF2 : Pop Proc
'
' Caracteres spéciaux du jeu G2
_GG2: CMODE$="_G22" : Pop Proc
_G22: PAR1=Instr(G2$,Chr$(A))
If PAR1 : CMODE$="_G23" : Pop Proc : End If
_SET_FONT[3] : Gosub PRNT$ : _SET_FONT[GMODE]
CMODE$=OCMODE$ : Pop Proc
_G23: B=Instr(G2$,Chr$(A),PAR1)
If B : A=Asc(Mid$(G2$,B+1,1)) : Gosub PRNT$ : End If
CMODE$=OCMODE$ : Pop Proc
'
' Locate
_LOC: CMODE$="_LO2" : Pop Proc
_LO2:
If A>=$40
' Locate direct, en Y
Y=A-$40
If Y=0 and YCU<>0 : OYCU=YCU : OXCU=XCU : End If
If Y>=0 and Y<25 : YCU=Y : End If
Else
' En début de ligne, dizaines
PAR1=A-$30
End If
CMODE$="_LO3" : Pop Proc
_LO3:
If A>=$40
' Direct, en X
X=A-$41 : If X>=0 and X<40 : XCU=X : End If
Else
' En début de ligne, unités
Y=PAR1*10+A-$30
If Y>=0 and Y<25 : YCU=Y : XCU=0 : End If
End If
CMODE$=OCMODE$ : Gosub _DEF : Locate XCU,YCU
Pop Proc
'
' Repetition
_RPT: CMODE$="_RP2" : Pop Proc
_RP2: PAR1=A-$40 : A=ALAST : CMODE$=OCMODE$
For REP=1 To PAR1 : Gosub PRNT$ : Next : Pop Proc
'
' Saute le prochain code
' (par exemple, appui sur une touche du minitel)
_SKP:
_CLA: CMODE$="_CL2" : Pop Proc
_SK2:
_CL2: CMODE$=OCMODE$ : Pop Proc
'
'
' Passage en mode ESCape
_ESC: CMODE$="_ES2" : Pop Proc
_ES2: CMODE$=OCMODE$
If(A>=$40) and A<=$60 Then Goto ESC$(A)
If A>=$30 Then CMODE$="_SK2" : Pop Proc
If A>=$20 Then CMODE$="_SKP" : Pop Proc
Pop Proc
'
' Codes ESC : Paper / Pen
_PAP: If GMODE=0 : GOPAP=A-$50 : Pop Proc : End If
CPAP=A-$50 : Paper CPAP : Gosub _SINV : GOPAP=-1
Pop Proc
_PEN: Pen A-$40+FLSH : CPEN=A-$40 : Gosub _SINV
Pop Proc
' Codes ESC : Mosaiques séparées ou non
_G1N: If GMODE=2 : _SET_FONT[1] : GMODE=1 : End If
Pop Proc
_G1L: If GMODE=1 : _SET_FONT[2] : GMODE=2 : End If
Pop Proc
' Codes ESC : Inverse on / off
_INV: CINV=-1 : Inverse On : Pop Proc
_NOR: CINV=0 : Inverse Off : Pop Proc
' Codes ESC : Taille des caracteres
_GNN: PRNT$="_NNPRINT" : Pop Proc
_GDX: If GMODE=0 : PRNT$="_DXPRINT" : End If : Pop Proc
_GDY: If GMODE=0 : PRNT$="_DYPRINT" : End If : Pop Proc
_GDD: If GMODE=0 : PRNT$="_DDPRINT" : End If : Pop Proc
' Codes ESC : Flash On / Off
_GFL: FLSH=8 : Pen CPEN+FLSH : Pop Proc
_NFL: FLSH=0 : Pen CPEN : Pop Proc
'
' Reinitialisations lors de LOCATE
_DEF: GMODE=0 : _SET_FONT[GMODE]
Pen 7 : CPEN=7 : FLSH=0 : Paper 0 : CPAP=0 : GOPAP=-1
CINV=0 : Gosub _SINV
_DEF2: PRNT$="_NNPRINT"
Return
'
_NLINE:
If GMODE=0
Paper 0 : CPAP=0 : GOPAP=-1 : Gosub _SINV
End If
PRNT$="_NNPRINT" : Return
'
End Proc
'
Procedure _SERIAL_GET
'
' Attend un caractere de la série
' ou du clavier
Repeat
'
A=Serial Get(0)
'
A$=Inkey$
If A$<>"" : A=-Asc(A$) : Exit : End If
'
Until A>=0
'
End Proc[A]
'
Procedure _SET_FONT[N]
'
' Adresse du jeu de caractere dans la banque
F=Start(15)+128*8*N+Sgn(N)*128*8
' Adresse dans la structure fenetre
A=Leek(Screen Base+170)+8
'
Loke A,F
'
End Proc
|
|