5. Le projet

5.1 Présentation

  Le but de ce projet est de réaliser un petit logiciel de communication type « talk ». Le projet se fera par groupes de 2, 3, ou 4 (étant donné que l'on demande quand même plus de travail à un groupe de 4 qu'à un groupe de 2…). Un élève ne peut pas faire le projet seul, une partie de la difficulté étant justement de produire un programme ensemble. Le projet peut être réalisé en Turbo Pascal (version 4.0 seulement, c'est la dernière dont on ait la licence…), en Turbo C (version 3.1), ou gcc (djgpp version 2). D'autres langages peuvent être proposés, mais il faut d'une part qu'il y ait au moins deux personnes pour développer dans ce langage, et d'autre part ce choix est soumis à mon acceptation : il faut en effet que je puisse développer assez rapidement un ensemble de procédure d'accès à la RS-232 compatibles avec l'unité Com utilisée pour Turbo Pascal et aussi que le langage se prête « simplement » à ce genre de programmation.

  Les machines sur lesquelles vous développerez sont des 486 SX 25, en général (il y a deux 486 SX 33 et deux 486 DX2 66). En gros, ne vous attendez pas à des foudres de guerre : ce sont des machines conçues pour la programmation DOS sous DOS, et elle conviennent parfaitement pour ce genre d'utilisation. Non, ne me proposez pas de développer en Java, vous les mettriez à genoux. Ces machines sont gérées par A. AOUN et moi-même, et je ne saurais trop vous rappeler le message qui vous est affiché lors de tout démarrage de machine :

****************************************************************************
Priere à tous les utilisateurs de ce PC :

    * De n'en modifier la configuration sous AUCUN pretexte
    * De créer leurs fichiers et répertoires sous C:\USR
    * De sauvegarder leurs données sous D:\USR (sous Windows)
    -> TOUT AUTRE FICHIER SERA DETRUIT SANS PREAVIS <-

    ... d'un semestre sur l'autre, les fichiers de d:\usr sont archivés
    pendant un semestre. On peut les récuperer par simple demande auprès
    de J-M CHALLIER (challier@irit.fr, IR1-17, 63-57)

    Si vous désirez faire modifier la configuration de ces PCs,
formuler vos souhaits a A. AOUN ou J-M. CHALLIER. Merci.

***************************************************************************

  Je vous conseille donc de vous créer un répertoire sous le répertoire C:\USR, d'y placer vos fichiers, de développer à cet endroit là (et sur le disque dur, l'accès à la disquette étant bien trop lent et peu sûr), et, comme on ne sait qui passera après vous ni sur quelle machine vous serez la prochaine fois, de sauvegarder vos œuvres d'une fois sur l'autre sur une disquette ou, en rebootant sous Windows, dans le répertoire D:\USR

 Vous êtes priés de ne jamais modifier la configuration (matérielle ou logicielle) d'un PC vous même. 

  On ne dispose que d'une seule imprimante pour la salle, et elle est reliée au serveur. Ceux qui veulent imprimer leur oeuvre doivent donc d'abord rebooter pour se placer sous Windows. L'imprimantes une imprimante à aiguilles 132 colonnes. Ceux qui désirent une impression de meilleure qualité peuvent, s'ils ont un compte au CICT, au CRIE, y demander l'autorisation d'une impression laser de leur programme. Le fait de faire le module MIA09 ne vous ouvre pas les droits nécessaires.

5.2 L'unité Com

  Cette unité Turbo Pascal 6.0 est une unité en freeware écrite par un néerlandais fort sympathique répondant au nom de Willem van Schaik, en mai 1994, et disponible sur internet. Elle est très simple à utiliser, très claire, fonctionne par interruptions et permet d'atteindre la vitesse maximale de transfert de 115200 bps. Malheureusement, elle est écrite pour Turbo Pascal 6.0 et nous ne possédons que la version 4.0. J'ai donc cloné cette excellente unité en une de moins bonne qualité, nommée Com_4, laquelle, comme son nom l'indique, a l'avantage de fonctionner sous Turbo Pascal 4.0. Par contre, comme les deux unités ont (presque) la même interface, vous pouvez développer avec l'unité d'origine chez vous si vous avez TP6.0+, et en TP MIA09 avec la version clonée. Pour ceux qui ne possèderaient pas de modem, des versions « bouclées » de ces deux unités sont disponibles. Si vous voulez rapatrier l'unité pour chez vous, récupérez la paquetage complet. Si vous êtes devant votre machine et qu'il vous suffit de la source de l'unité, voici, l'unité Com, l'unité Com bouclée, l'unité Com_4, et l'unité Com_4 bouclée.

L'interface de l'unité COM_4 est la suivante :

type
  PortType    = (COM1, COM2, COM3, COM4);
  BaudType    = (B110, B150, B300, B600, B1200, B2400, B4800,
                 B9600, B19200, B38400, B57600, B115200);
  ParityType  = (None, Odd, Even, Mark, Space);
  LengthType  = (D5, D6, D7, D8);
  StopType    = (S1, S2);
  FlowType    = (No, RtsCts, XonXoff);

procedure InitCom (PortNumber  : PortType;
                   BaudRate    : BaudType;
                   ParityBit   : ParityType;
                   DataLength  : LengthType;
                   StopBits    : StopType;
                   FlowControl : FlowType);
procedure ExitCom (PortNumber : PortType);
function ComReceived (PortNumber : PortType) : boolean;
function ReadCom (PortNumber : PortType) : Char;
function ComAllowed (PortNumber : PortType) : boolean;
procedure WriteCom (PortNumber : PortType; OutByte : char);
procedure BreakCom (PortNumber : PortType);

  On commence d'abord par y définir un certain nombre de types énumérés. La différence entre COM et COM_4 se trouve d'ailleurs là ; COM possède un PortType limité à (COM1, COM2).

  La procédure InitCom doit, comme son nom l'indique, être la première procédure utilisée. Elle initialise la communication entre votre programme et l'UART. Elle prend en paramètre le numéro du port que vous voulez ouvrir, et les paramètres de communication que vous désirez mettre en œuvre. Dans le cadre du projet, les paramètre utilisés seront (com1, b19200, None, d8, s1, RtsCts). Si votre programme a une légère tendance à perdre des caractères en réception, vous pouvez diminuer la vitesse jusqu'à b9600. La plupart des projets devraient pouvoir fonctionner à cette vitesse.

  La dernière procédure à utiliser sera ExitCom. Comme on peut le supposer, cette procédure ferme l'utilisation du port RS-232 sélectionné. Après un appel à ExitCom, la seule opération pouvant être effectuée est un nouvel InitCom.

  Deux routines sont fournies pour la réception des caractères. La première, ComReceived, prend en paramètre un identificateur de port et renvoie un booléen indiquant si on a le droit de lire sur ce port (en gros, si caractère y est arrivé). Ne jamais lire un caractère sur un port avant de s'être assuré que cette fonction renvoie TRUE. Une fois que ComReceived renvoie TRUE, on peut lire le caractère sur ce port en fournissant son identificateur à ReadCom, qui renvoie alors le caractère lu. Cette lecture ne peut être faite qu'une fois, après quoi ComReceived(Port) renverra FALSE. Contrairement à ce qui se passe dans l'unité Crt pour ReadKey, ReadCom(Port) n'attendra pas qu'un caractère nouveau arrive pour vous donner une valeur en retour. Elle se contentera de vous fournir l'ancienne valeur lue.

  L'écriture se fait de façon similaire. ComAllowed(Port) vous renvoie un booléen vous indiquant si vous avez le droit d'écrire sur un port. Si elle vous renvoie TRUE, vous pouvez y écrire en utilisant WriteCom(Port, Caractere).

  Un dernière procédure est mise à votre disposition. Il s'agit de BreakCom. Cette procédure transmet un break sur la ligne RS-232 désignée par le port. Le fait que ce break soit un break court ou long n'est pas documenté. Beaucoup de modems sont programmés pour raccrocher sur la réception d'un break. La bonne manière de terminer l'utilisation d'un port de communication est donc l'utilisation en séquence de BreakCom et de ExitCom.

5.3 Autres routines utiles

  La plupart d'entre vous connaissent l'unité Crt. Cependant, quelques précisions, surtout sur la procédure Window, sont rarement superflues.

  KeyPressed est une fonction vous renvoyant un booléen qui vous indique si un caractère a été reçu depuis le clavier. ReadKey se charge de lire un caractère depuis le clavier. Si aucun caractère n'est disponible, cette procédure bloque le programme en attendant qu'un caractère soit effectivement reçu. Les touches spéciales (touches de fonctions, flèches, touches précédées de Alt, etc.) sont gérées de la façon suivante : un caractère NUL (code ascii 0) est d'abord renvoyé, puis un autre code correspondant à la touche appuyée est transmis. Ces touches n'auront pas à être utilisées pour le projet, et vous pouvez donc soit ignorer leur existence (le plus simple, mais qui risque de perturber un peu le fonctionnement du programme), soit ne pas les transmettre au programme lui-même (quand ReadKey revoit #0 et que KeyPressed est encore vrai, on peu déduire presque sûrement qu'il s'agit d'une touche spéciale).

  Au point de vue affichage, la routine la plus importante pour vous sera la procédure Window. On lui transmet 4 paramètres qui sont les coordonnées absolues du coin supérieur gauche et du coin inférieur droit de la zone où on veut pouvoir écrire, lesquels doivent être contenus dans l'écran. Cette zone est entièrement logique, c'est à dire que Window ne vous tracera rien, pas même un cadre autour de la zone que vous définissez. Elle ne déplacera même pas le curseur à l'intérieur de la zone active. Mais toutes les routines que vous utiliserez après seront relatives à cette zone. il ne peut y avoir qu'un seule zone active à la fois. Un appel à Window(1,1,80,25) vous replace dans la situation initiale, c'est à dire avec tout l'écran comme zone active. Dans la suite des explications, on supposera que l'on a réalisé un Window(5,7, 15, 10), c'est à dire que l'on a une zone active de 11 caractères de large et de 4 caractères de haut. La procédure GotoXY(x,y) vous place le curseur à la colonne x et la ligne y de votre zone active, c'est à dire qu'un GotoXY(2,3) vous placera le curseur à la 6ème colonne et à la 9ème ligne de votre écran. Elle ne placera jamais le curseur en dehors de la zone active. WhereX vous renverra la colonne de la position du curseur, c'est à dire qu'après l'appel précédent à GotoXY, WhereX vous renverra 2. De la même manière, WhereY, qui renvoie la position du curseur dans les ordonnées, vous renverra 3. Les procédures bien connues Write et Writeln sont aussi relatives à la zone courante, c'est à dire que si vous arrivez à la 11ème colonne de votre zone active, la suite du texte sera écrit de lui-même à partir de la première colonne de la ligne suivante de votre zone active. De la même manière, quand vous arrivez à la fin de la dernière ligne de votre zone active, cette dernière (et rien que ces 4 lignes de 11 caractères) sont scrollées vers le haut pour libérer une ligne en bas, exactement comme si la zone active était la totalité de votre écran. Enfin, ClrScr n'efface que la zone active.

  Quelques opérations sur les chaînes vous seront aussi utiles. Pos(SousChaine, Chaine) renvoit un entier indiquant la position d'une sous-chaîne dans une chaîne, ou 0 si cette sous-chaîne n'est pas présente dans la chaîne. Copy(Chaine, Debut, Longueur) renvoit une sous-chaîne de la chaîne initiale commençant à la position Debut d'une taille donnée par Longeur. Si la chaîne n'est pas assez longue (c'est en général le cas si Longueur=255, puisqu'une chaîne ne peut faire plus de 255 caractères en Pascal), la chaîne est copiée jusqu'à la fin. Enfin, notez que UpCase(Caractere) est une fonction qui vous renvoit le caractere passé en paramètre, mais transformé en majuscule.

  Vous devez avoir vu la gestion des fichiers, mais, d'expérience, quelques rappels succins sont rarement de trop. Il existe plusieurs types de fichiers, les fichiers détypés (File), les fichiers d'enregistrements ou à accès direct (File of <type>) et les fichiers texte (Text). C'est à ces derniers seulement que nous nous intéresserons. Il s'ouvrent comme les autres, en commençant par un appel à Assign(Fic, Nom) pour leur associer un nom, puis avec un Reset(Fic) (ouverture en lecture/écriture au début), Rewrite(Fic) (ouverture en écriture avec troncature du fichier s'il existait) ou Append (Fic) (ouverture en lecture écriture à la fin). Les lectures et les écritures se font avec les procédure habituelles Read(Fic, ...), Readln(Fic, ...), Write(Fic, ...) et Writeln(Fic, ...). Apres toute procédure d'entrée/sortie, la variable IOResult vous indique (quand elle est à 0) si tout s'est bien passé.

  Voilà. J'espère avoir répondu d'avance à la plupart des questions que vous pourriez vous poser pendant ce TP sur l'utilisation de Turbo Pascal 4.0. Si vous désirez plus de précisions, n'oubliez pas que Turbo Pascal 4.0 est doté d'une aide en ligne : il suffit de taper Ctrl-F1 avec le curseur sur le mot qui pose problème pour lire la documentation disponible sur ce sujet. A défaut, pensez à m'appeler : j'ai la prétention de me considérer comme une documentation de Turbo Pascal 4 fort honnête :-).

5.4 Spécifications

  Les spécifications du projet ne vous seront communiquées qu'au fur et à mesure de l'avancement du projet. Je sais fort bien qu'en entreprise, on vous fournit avant de commencer un projet, un document de spécifications bien ficellé. Cependant, il y a plusieurs raisons à cette option que j'ai choisie. D'une part, parce qu'un document de spécifications, même en entreprise, est sujet à amendements. Ils sont payés assez chers par le client, mais c'est celui-ci qui a toujours le dernier mot. Ensuite parce qu'un projet, ça vit, et qu'il faut le maintenir une fois qu'il a été réalisé, ce qui revient à en faire varier les spécifications. Enfin et surtout dans un but didactique : cela fait maintenant au moins 3 semestres que l'on vous dit d'écrire du code structuré, modulaire si possible et surtout évolutif. On vous donne des règles pour produire un tel code. Cependant, lors de la réalisation d'un projet, vous n'avez jamais à faire vous même évoluer votre logiciel, puisque le document concernant le projet vous est fourni dès le début. Vous écrivez un programme dont le but principal est « qu'il marche », et vous vous étonnez qu'il puisse y avoir une telle différence de notation entre deux programmes qui fonctionnent pourtant de la même manière.

  Ce qui sera fait pendant ce projet sera l'aspect inverse des choses, c'est à dire que je commence par le vous donner qu'un petit aspect du projet global. Vous écrivez cette partie, et lorsque vous la jugez satifaisante, je vous donne l'extension que j'y propose. Vous en venez donc à faire évoluer votre propre code et vous apprenez a voir de vous même ce qu'il faut faire et ne pas faire. Au bout de quelques cycles d'ajouts aux spécifications, vous finissez par réaliser un code « plus évolutif » que celui que vous écriviez avant - c'est du moins le but.

  En conséquence de quoi, seules les spécifications de base seront données dans cette page. Le reste sera fourni indiviuellement à chaque groupe au fur et à mesure de son avancement.

  Les spécifications de la première partie sont donc, comme il a été vu en introduction, de réaliser une division de l'écran texte en deux zones. Dans la zone supérieure s'afficheront les caractères tapés au clavier, alors que les caractères reçus au travers de la RS-232 seront affichés dans la zone inférieure. Il est évident qu'il faut que les entrées / sorties se fassent caractère par caractère et non pas ligne par ligne. De plus, les caractères ne doivent pas se chevaucher en position (1,1) de la zone, mais bien s'afficher « naturellement » les uns derrière les autres (si la gestion du retour chariot vous pose des problèmes, n'hésitez pas à venir me voir ; ce n'est pas forcément anormal).

  C'est tout ! Ceci ne devrait pas vous prendre plus d'une ou deux scéances, mais pensez à bien programmer dès le début. Commencez par isoler les entités avec lesquelles vous allez travailler, regardez quelles sont les données qui les définissent et faites en des structures. Réalisez ensuite des petites procédures pour effectuer des opérations de base sur ces entités. Faites ensuites des procédures plus évoluées, mais toujours aussi courtes faisant appel à ces procédures de base, etc. Montez un édifice de procédures simples (la réalisation de cette partie peut n'être faite qu'avec des procédures de 3 instructions maximum). Évitez (si ce n'est éliminez) la duplication de code. Même chose pour les variables globales. Donnez des noms explicites à vos variables. Commentez (intelligement, svp : " i = i+1; /* incrémentation de i */ " n'apporte strictement rien) vos programmes, et justifiez vos choix. Vérifiez et traitez toutes les erreurs (surtout celles de l'utilisateur, qui est l'être le plus imprévisible qui soit) que vous pouvez détecter. Et puis bon courage !

Le PC Retour à l'index La soutenance



Copyright (c) 1998 by Igx, the dreaming drummer…