<h3>LES ENTREES/SORTIES SUR LE PORT PARALLELE</h3>
<p class="spip">Le port IEEE 1284 dit aussi "parallèle" ou "imprimante" ou "centronic" est présent sur la plupart des micro-ordinateurs de type compatible IBM-PC.</p>

<p class="spip">Il peut facilement être détourné de son rôle d’impression et être utilisé comme port d’entrées/sorties universel.</p>

<p class="spip">Le connecteur est un DB25 femelle.</p>

<p class="spip">Au niveau du Bios, ce port peut être configurer dans 3 modes :
<br /></p>
<li> SPP : Standard Parrallel Port
<br /><li> EPP : Enhanced Parrallel Port
<br /><li> ECP : Extended Capabilities Port
<p class="spip">Seul sera traité ici le mode SPP.</p>

<p class="spip">Généralement, sur les Bios modernes, les deux autres modes basculent automatiquement en SPP quand ils reçoivent une commande destinée à un port SPP. Donc tout va bien pour nous.</p>

<hr>
<h3>L’aspect Matériel</h3>
<p class="spip">Dans le plan d’adressage du PC, l’ensemble des signaux présents sur le connecteur occupe 3 adresses. Généralement c’est les adresses (pour lpt0) :
<br /></p>
<li> 0x378 (port appelé Data) utilisable en sortie sur 8 lignes
<br /><li> 0x379 (port appelé Etat) utilisable en entrée sur 5 lignes
<br /><li> 0x37a (port appelé Cont) utilisable en sortie sur 4 lignes
<p class="spip">Des informations sur ce port (et tous les ports en général) peuvent être obtenues en visitant /proc/interrupts et /proc/ioports</p>

<p class="spip">Voilà la liste des 25 lignes présentes sur le connecteur DB25 :</p>

<div style='text-align: left;' class='spip_code' dir='ltr'><code><br />
1  : => sortie (Cont 0 logique négative)<br />
2  : => sortie (Data 0 logique positive)<br />
3  : => sortie (Data 1 logique positive)<br />
4  : => sortie (Data 2 logique positive)<br />
5  : => sortie (Data 3 logique positive)<br />
6  : => sortie (Data 4 logique positive)<br />
7  : => sortie (Data 5 logique positive)<br />
8  : => sortie (Data 6 logique positive)<br />
9  : => sortie (Data 7 logique positive)<br />
10 : <= entrée (Etat 6 logique positive)<br />
11 : <= entrée (Etat 7 logique négative)<br />
12 : <= entrée (Etat 5 logique positive)<br />
13 : <= entrée (Etat 4 logique positive)<br />
14 : => sortie (Cont 1 logique négative)<br />
15 : <= entrée (Etat 3 logique positive)<br />
16 : => sortie (Cont 2 logique positive)<br />
17 : => sortie (Cont 3 logique négative)<br />
18 à 25 = masse<br />
</code></div>
<p class="spip">Attention : au démarrage de la machine, les sorties peuvent être dans un état quelconque. il est donc très imprudent de connecter un périphérique sur ce port et de l’alimenter tant que le bios n’a pas stabilisé les sorties.</p>

<hr>
<h3>D’un point de vue électronique</h3>
<p class="spip">La normalisation du port IEEE 1284 prévoit des signaux TTL :
<br /></p>
<li> un 0 logique correspond à 0 volt (la masse) (0 à 0,7 volt)
<br /><li> un 1 logique correspond à +5 volts (de 2,4 volts à 5 volts)
<p class="spip"><u>Les Entrées :</u></p>

<p class="spip">En logique TTL :
<br /></p>
<li> une entrée reliée au 5v par une résistance de rappel de 10k retourne un 1 logique.
<br /><li> une entrée reliée au 0 volt par une résistance de 1K retourne un 0 logique.
<br /><li> une entrée qui reste "en l’air" retourne un 1 logique.
<p class="spip">Les entrées du port IEEE 1284 retourne donc un 1 par défaut si elle ne sont pas polarisées. Cet état n’étant pas très stable, il est conseillé d’utiliser systématiquement des résistances de polarisation (reliées au 5V de préférence)</p>

<p class="spip"><span class='spip_document_717 spip_documents spip_documents_center' >
<img src='http://download.tuxfamily.org/assocoagul/drupal-files/spip/hard03.gif' width="196" height="145" alt="" /></span><p>

<p class="spip">Dans le cas où le port doit travailler en ambiance "difficile", il est conseillé de protéger les entrées avec des opto-coupleur :</p>

<p class="spip"><span class='spip_document_713 spip_documents spip_documents_center' >
<img src='http://download.tuxfamily.org/assocoagul/drupal-files/spip/hard02.gif' width="295" height="121" alt="" /></span><p>

<p class="spip">Pour utiliser une entrée opto-couplée, il suffit de la relier à la masse à travers un interrupteur ou un transistor. Quand l’interrupteur se ferme ou quand le transistor conduit, le niveau zéro (la masse) remonte, allume la led de l’optocoupleur qui devient passant et porte l’entrée au potentiel 0 (par défaut, une entrée débranchée est donc à 1).</p>

<p class="spip"><u>Les sorties :</u></p>

<p class="spip">En théorie, une sortie TTL ne peut délivrer qu’un niveau logique. En pratique, cette tension de sortie peut être chargée de façon à débiter un courant faible de l’ordre de 10mA maximum. C’est suffisant pour allumer une led reliée à la masse par une résistance de 470 ohm ( (5v - 1,5) / 0,01A = 350 ohm minimum )</p>

<p class="spip">Ce courant peut commander un transistor en commutation ou un opto-coupleur.</p>

<p class="spip">Le montage suivant à été dévellopé au collège Camille Claude de Chevigny St Sauveur.
 (http://perso.wanadoo.fr/college.claudel.chevigny/techno/eclaire/secteur.htm)</p>

<p class="spip">Il permet de commander un appareil en 220 volts grâce à n’importe quelle petite sortie binaire (port parallele, port serie...)
Les composants sont très ordinaires et le prix de revient est ridicule.</p>

<p class="spip"><span class='spip_document_716 spip_documents spip_documents_center' >
<img src='http://download.tuxfamily.org/assocoagul/drupal-files/spip/secteur.gif' width="196" height="123" alt="" /></span><p>

<p class="spip">La mise en boite se fait dans un boitier du type "adaptateur secteur" avec une prise mâle secteur et une prise femelle en sortie.</p>

<li> Le montage est entièrement dans le boitier (sobriété )
<br /><li> La commande est isolée du secteur par un opto-coupleur puis par un relais (sécurité )
<br /><li> L’isolation est double et dépasse dans tout les cas 1500 volts. ( tranquilité )
<hr>
<h3>L’aspect logiciel.</h3>
<p class="spip">Le PC ayant une architecture basée sur le processeur i386, on peut faire appel directement aux ports d’entrée/sortie. Selon le système d’exploitation utilisé, il est éventuellement possible de passer par des fonctions systèmes. Cette méthode est respectueuse du système mais elle oblige souvent à adapter l’écriture du 
logiciel aux différentes et successives version de systèmes. Elle ne sera donc utilisée que dans le cas ou on connais précisément la version du système utilisée.</p>

<p class="spip"><u>en assembleur, on utilise les fonctions :</u></p>

<li> out(octet,adresse) pour écrire sur un port
<br /><li> in(adresse) pour lire un port
<p class="spip"><u>en C, on utilise :</u></p>

<div style='text-align: left;' class='spip_code' dir='ltr'><code><br />
        #include <stdio.h><br />
        #include <asm/io.h> <br />
<br />
        int data,etat,cont,octet;<br />
<br />
        int main()<br />
        {<br />
                unsigned int lu;<br />
        <br />
                data=0x378;  /* pour le port lpt0 */<br />
                etat=0x379;<br />
                cont=0x37a;<br />
        <br />
                if(ioperm(data,3,1))<br />
                  {perror("ioperm"); exit(1);}<br />
<br />
                octet=0xFF;<br />
                outb(octet, data);<br />
        <br />
                lu=inb(etat);<br />
                printf("%X", lu);<br />
        <br />
                exit(0);<br />
        }<br />
</code></div>
<p class="spip"><u>en FreePascal, on utilise :</u></p>

<div style='text-align: left;' class='spip_code' dir='ltr'><code><br />
        Program test_IO;<br />
        <br />
        uses Linux,crt;<br />
        var Octet : byte;<br />
        <br />
        const         Data=$378;  /* pour le port lpt0 */<br />
                Stat=$379;<br />
                Cont=$37A;<br />
        <br />
        begin /* main */<br />
          if not(IOperm(Data,3,1)) then exit;<br />
          <br />
          Octet := $FF<br />
          writeport(Data,Octet); //octet -> port(Data)<br />
          <br />
          readport(Stat,Octet);  //port(Etat) -> octet<br />
        end;<br />
</code></div>
<p class="spip">Sous Linux, les commandes IOperm, inb et outb ne peuvent être utilisées que par l’utilisateur root.</p>

<p class="spip">Il existe différentes façons de contourner cette limitation. Une méthode relativement simple consiste à écrire un petit programme très limité capable uniquement d’effectuer des entrées/sorties. Ce programme appartient à root et est doté du bit SUID. Il peut être appelé par n’importe quel programme utilisateur qui lui passera les paramètres à échanger avec le port parallèle. Il faut écrire ce mini programme avec soin afin d’éviter toute faille de sécurité.</p>

<hr>
<h3>Marche a suivre (exercice pratique)</h3>
<p class="spip">Écrire les programmes write378.c et read379.c</p>

<p class="spip">Les compiler : 
<br /></p>
<li> gcc write378.c -o write378
<br /><li> gcc read379.c -o read379
<p class="spip">Modifier leur droits pour que le propriétaire soit root :
<br /></p>
<li> chown root.root write378
<br /><li> chown root.root read379
<p class="spip">Modifier leurs droits pour qu’ils deviennent -rwsr-sr-x (bien positionner "s" )
<br /></p>
<li> chmod 6755 write378
<br /><li> chmod 6755 read379
<p class="spip">Ecrire les scripts allume.sh et lecture.sh</p>

<p class="spip">Positionner leurs droits en exécutable par tous</p>

<li> chmod 755 allume.sh
<br /><li> chmod 755 lecture.sh
<p class="spip">Faire des tests avec une entrée et une sortie simplifiée.</p>

<div style='text-align: left;' class='spip_code' dir='ltr'><code><br />
--------------<br />
-  write378  -<br />
--------------<br />
#include <stdlib.h><br />
#include <stdio.h><br />
#include <asm/io.h><br />
<br />
const unsigned int DATA=0x378;<br />
int octet;<br />
<br />
int main(int argc, char *argv[])<br />
<br />
{<br />
  if(ioperm(DATA,1,1)) {perror("ioperm"); exit(1);}<br />
  if (argc != 2) {perror("erreur de parametres"); exit(1);}  <br />
<br />
  octet=atoi(argv[1]);<br />
  outb(octet,DATA);<br />
  <br />
  return(0);<br />
}<br />
--------------<br />
-   read379  -<br />
--------------<br />
#include <stdlib.h><br />
#include <stdio.h><br />
#include <asm/io.h><br />
<br />
const unsigned int ETAT=0x379;<br />
int octet;<br />
<br />
int main(int argc, char *argv[])<br />
{<br />
  if(ioperm(ETAT,1,1)) {perror("ioperm"); exit(1);}<br />
  octet=inb(ETAT);<br />
  <br />
  printf("%d",octet);<br />
  return(0);<br />
}<br />
--------------<br />
- allume.sh -<br />
--------------<br />
#!/bin/bash<br />
<br />
# argument $1 = tempo en secondes<br />
<br />
echo<br />
echo ECLAIRAGE : ON<br />
<br />
octet='255'<br />
./write378 $octet<br />
<br />
sleep $1<br />
<br />
echo<br />
echo ECLAIRAGE : OFF<br />
<br />
octet='0'<br />
./write378 $octet<br />
<br />
echo<br />
--------------<br />
- lecture.sh -<br />
--------------<br />
#!/bin/bash<br />
<br />
echo Lance lecture<br />
echo<br />
<br />
octet=`./read379`<br />
<br />
echo  "octet lu : "$octet<br />
echo<br />
<br />
if [ "$octet" -gt 127 ]<br />
  then echo 1 ; <br />
  else echo 0<br />
fi<br />
<br />
echo<br />
echo fin de lecture<br />
echo<br />
--------------<br />
</code></div>