1.16k likes | 1.35k Views
TTY_IT. Corrigé. Objectif du chapitre. Proposer une solution pour les exercices suggérés dans le chapitre IT_CE4.2_présentation Écrire un programme qui va communiquer avec une liaison série La transmission se fera en polling La réception sera gérée par interruption
E N D
TTY_IT Corrigé TTY_IT : corrigé
Objectif du chapitre • Proposer une solution pour les exercices suggérés dans le chapitre IT_CE4.2_présentation • Écrire un programme qui va communiquer avec une liaison série • La transmission se fera en polling • La réception sera gérée par interruption • On utilisera la deuxième liaison série connectée sur l’IRQ3 TTY_IT : corrigé
Rappel : principe des interruptions • Deux composants logiciels pour gérer les interruptions • ISR : Interrupt Service Routine • Code très court qui fait le traitement le plus court possible • retourne un numéro logique d’IT • IST : Interrupt Service Thread • Traite l’interruption TTY_IT : corrigé
Rappel : déroulement du traitement • Une IT physique se produit • Le gestionnaire d’exception lance l’ISR associé à cette interruption • L’ISR retourne le numéro logique au noyau • Le noyau arme un événement pour déclencher l’IST associé • L’IST est déclenchée • La commande IOCTL est exécutée TTY_IT : corrigé
Rappel : IST • Thread en mode user de forte priorité • En attente d’un événement associé à l’IT logique • Réveillé lorsque le Kernel signale l’événement • Traite l’interruption • Acquitte l’interruption TTY_IT : corrigé
Synchronisation IST/DRIVER • L’ IST va faire l’acquisition du caractère reçu et le stockera dans un buffer ucBufIn • Pour signaler au driver qu’un caractère a été acquis, nous utiliserons un autre EVENT géré par un handle nommé hMonEvent • L’IST positionne cet EVENT • Le driver fait le traitement demandé puis acquitte l’EVENT TTY_IT : corrigé
Gestion du port série en IT • On utilise le port 2 • IT physique 0x3 (IRQ 3) • IT logique (dwSYSINTR_A_Moi) • Adresse du port 0x2F8 TTY_IT : corrigé
IOCTL • On va définir deux IOCTL internes au driver • IOCTL_PUTC envoi de caractère en polling • IOCTL_GETC réception de caractère sous IT • On va définir un IOCTL pour la communication driver→ISR (envoi du numéro logique de l’IT) • IOCTL_VAL_SYSINTR TTY_IT : corrigé
plate-forme de travail • Générer une nouvelle plate-forme standard • Nom : z_CEPC_TTY_IT • Retirer de la configuration de base la gestion des ports série présente par défaut pour éviter des conflits TTY_IT : corrigé
Retirer le port série (1) • Onglet Features • Dérouler l’arborescence →Z_CEPC_TTY_IT features →CEPC: x86 →Devices Drivers →Serial • Cliquer à droite pour ouvrir le menu • Cliquer Delete TTY_IT : corrigé
Retirer le port série (2) Dérouler jusqu’à Serial puis clic droit Cliquer TTY_IT : corrigé
Configuration obtenue TTY_IT : corrigé
DRIVER TTY_IT : corrigé
Création du driver Dans File : Choisir New Project or File Choisir Nommer Valider TTY_IT : corrigé
Choix du projet Choisir Valider TTY_IT : corrigé
Fichier source obtenu TTY_IT : corrigé
Création du fichier .def (1) • Nous devons créer TTYIT_DRV.def • Puis l’ajouter au projet • On peut • Créer directement dans le projet un nouveau fichier de type Text File • Ajouter un fichier créé à l’avance dans un répertoire TTY_IT : corrigé
Création directe du fichier .def (1) Onglet Files Nommer Choisir Cocher Valider TTY_IT : corrigé
TTYIT_DRV.def LIBRARY TTYIT_DRV EXPORTS TTY_Init TTY_Deinit TTY_Open TTY_Close TTY_IOControl TTY_IT : corrigé
Insertion de TTYIT_DRV.def (1) • Créer le fichier • Enregistrer ce fichier dans le répertoire …\WINCE420\PUBLIC\z_CEPC_TTY_IT\TTYIT_DRV • Ajouter ce fichier au projet • Cliquer à droite sur le répertoire Source Files • Dans le menu choisir Add Files to Folder… • Dans la fenêtre ouverte, choisir le fichier à insérer • Valider TTY_IT : corrigé
Insertion de TTYIT_DRV.def (2) TTY_IT : corrigé
Insertion de TTYIT_DRV.def (3) TTY_IT : corrigé
Structure du driver TTY_IT : corrigé
Entête du driver (1) // #include nécessaires #include "stdafx.h" #include <nkintr.h> #include <wdm.h> #include <Pkfuncs.h> TTY_IT : corrigé
Entête du driver (2) // Définitions et réservations // Définition des bits de status du sérialiseur #define LS_TSR_EMPTY 0x40 #define LS_THR_EMPTY 0x20 #define LS_RX_BREAK 0x10 #define LS_RX_FRAMING_ERR 0x08 #define LS_RX_PARITY_ERR 0x04 #define LS_RX_OVERRRUN 0x02 #define LS_RX_DATA_READY 0x01 TTY_IT : corrigé
Entête du driver (3) // Définition des offsets des registres du sérialiseur #define comRxBuffer 0 #define comTxBuffer 0 #define comDivisorLow 0 #define comDivisorHigh 1 #define comIntEnable 1 #define comFIFOControl 2 #define comLineControl 3 #define comModemControl 4 #define comLineStatus 5 TTY_IT : corrigé
Entête du driver (4) // Définition des IOCTL #define IOCTL_PUTC \ CTL_CODE(FILE_DEVICE_UNKNOWN,2048,\ METHOD_BUFFERED,FILE_ANY_ACCESS) #define IOCTL_GETC \ CTL_CODE(FILE_DEVICE_UNKNOWN,2049,\ METHOD_BUFFERED,FILE_ANY_ACCESS) #define IOCTL_VAL_SYSINTR \ CTL_CODE(FILE_DEVICE_UNKNOWN,2050,\ METHOD_BUFFERED,FILE_ANY_ACCESS) TTY_IT : corrigé
Entête du driver (5) // Adresse de base du sérialiseur #define IoPortBase ((PUCHAR) 0x02F8) // Interruptions #define ItPhysique 0x3 // Définition de la structure à passer à l’IST typedef struct _ISTDATA { HANDLE hThread; // IST Handle DWORD sysIntr; // Logical ID HANDLE hEvent; // Handle to the EVENT volatile BOOL bAbort; // Flag de fin }ISTDATA; TTY_IT : corrigé
Entête du driver (6) // Prototype de l'IST DWORD TTYIST(void *); DWORD dwSYSINTR_A_Moi; //Réservations diverses UCHAR ucBufIn; HANDLE hMonEvent; ISTDATA TTY_ISTData; TTY_IT : corrigé
Entrée du driver BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { return TRUE; }// Fin DllMain TTY_IT : corrigé
TTY_Init (1) DWORD TTY_Init(DWORD dwContext) { // Déclarations diverses DWORD Buf_In[1]; DWORD Buf_Out[1]; DWORD dwNbBytes; HANDLE hChain,hIstEvent; DWORD dwErrCode; RETAILMSG(1,(TEXT("TTY: TTY_Init\n"))); TTY_IT : corrigé
TTY_INIT (2) // Initialisation des registres du sérialiseur 16550 // pas d'IT sur Receiver Ready (sera fait dans Open) //9600 bauds, 8 bits, pas de parité, DTR, RTS// pas de FIFO WRITE_PORT_UCHAR(IoPortBase+comLineControl, 0x80); WRITE_PORT_UCHAR(IoPortBase+comDivisorLow, 0x0C); WRITE_PORT_UCHAR(IoPortBase+comDivisorHigh, 0x00); TTY_IT : corrigé
TTY_Init (3) WRITE_PORT_UCHAR(IoPortBase+comLineControl, 0x03); WRITE_PORT_UCHAR(IoPortBase+comFIFOControl, 0x00); WRITE_PORT_UCHAR(IoPortBase+comIntEnable, 0x00); // Mettre OUT2 du 16550 à 1 pour autoriser les IT// globalement // (pas indiqué dans la documentation du 16550 !) TTY_IT : corrigé
TTY_Init (4) WRITE_PORT_UCHAR(IoPortBase+ comModemControl, 0x0B); // Récupération d'un numéro d’IT logique Buf_In[0]=3; KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, Buf_In,4,Buf_Out,4,NULL); dwSYSINTR_A_Moi=Buf_Out[0]; RETAILMSG(1,(TEXT("dwSYSINTR_A_Moi: %d\n"), dwSYSINTR_A_Moi)); // Chaînage de l'ISR hChain=LoadIntChainHandler(_T("TTYISR.dll"), _T("ISRHandler"),ItPhysique); TTY_IT : corrigé
TTY_Init (5) if(hChain==0) { RETAILMSG(1,(TEXT("TTY: erreur %d dans LoadIntChainHandler\n"),GetLastError())); return FALSE; } TTY_IT : corrigé
TTY_Init (6) // Passage du numéro IT Logique à l'ISR Buf_In[0]=dwSYSINTR_A_Moi; dwErrCode=KernelLibIoControl(hChain,IOCTL_VAL_ SYSINTR,Buf_In,4,NULL,NULL,&dwNbBytes); if(dwErrCode==FALSE) { RETAILMSG(1,(TEXT("TTY: erreur %d dans KernelLibIoControl\n"),GetLastError())); return FALSE; } TTY_IT : corrigé
TTY_Init (7) // Création de l’événement de lien pour l’ISThIstEvent=CreateEvent(NULL,FALSE,FALSE,NULL); if(hIstEvent==0) { RETAILMSG(1,(TEXT("TTY: erreur %d dans CreateEvent (hIstEvent)\n"),GetLastError())); return FALSE; } TTY_IT : corrigé
TTY_Init (8) // Création de l’événement de synchro IST/driver // Handle déclaré en variable globale : hMonEvent hMonEvent=CreateEvent(NULL,TRUE,FALSE,NULL); if(hMonEvent == 0) { RETAILMSG(1,(TEXT("TTY: erreur %d dans CreateEvent (hMonEvent)\n"),GetLastError())); return 0; } TTY_IT : corrigé
TTY_Init (9) // Initialisation de la structure TTY_ISTData.hEvent=hIstEvent; TTY_ISTData.sysIntr=dwSYSINTR_A_Moi; TTY_ISTData.bAbort=FALSE; // Inhibition (Disable) de l’interruption logique InterruptDisable(TTY_ISTData.sysIntr); TTY_IT : corrigé
TTY_Init (10) // Création et démarrage du thread IST TTY_ISTData.hThread=CreateThread(NULL,0, &TTYIST,&TTY_ISTData,0,NULL); if(TTY_ISTData.hThread ==0) { RETAILMSG(1,(TEXT("TTY: erreur % d dans CreateThread (TTY_ISTData)\n"),GetLastError())); return 0; } TTY_IT : corrigé
TTY_Init (11) // Connexion de l’IT logique avec l’événement dwErrCode=InterruptInitialize(dwSYSINTR_A_Moi, TTY_ISTData.hEvent,NULL,0); if(dwErrCode==FALSE) { RETAILMSG(1,(TEXT("TTY: erreur %d dans InterruptInitialize\n"),GetLastError())); return 0; } TTY_IT : corrigé
TTY_Init (12) // Mise en priorité maximale du thread dwErrCode=CeSetThreadPriority(TTY_ISTData.hThread ,0); if(dwErrCode==FALSE) { RETAILMSG(1,(TEXT("TTY: erreur %d dans CeSetThreadPriority\n"),GetLastError())); return 0; } TTY_IT : corrigé
TTY_Init (13) RETAILMSG(1,(TEXT("TTY: OK IT Init\n"))); return !0; }// Fin TTY_Init TTY_IT : corrigé
TTY_Deinit (1) BOOL TTY_Deinit(DWORD hDeviceContext) { RETAILMSG(1,(TEXT("TTY: TTY_Deinit\n"))); // Mise du flag bAbort à TRUE pour arrêter l'IST TTY_ISTData.bAbort=TRUE; // Inhibition (Disable) de l’IT logique : InterruptDisable InterruptDisable(TTY_ISTData.sysIntr); TTY_IT : corrigé
TTY_Deinit (2) // Fermeture des handles CloseHandle(TTY_ISTData.hEvent); CloseHandle(TTY_ISTData.hThread); CloseHandle(hMonEvent); return TRUE; }// Fin TTY_Deinit TTY_IT : corrigé
TTY_Open (1) DWORD TTY_Open(DWORD hDeviceContext, DWORD AccessCode, DWORD ShareMode) { RETAILMSG(1,(TEXT("TTY: TTY_Open\n"))); // Initialisations complémentaires du périphérique // Vidage du buffer de réception si nécessaire while((READ_PORT_UCHAR(IoPortBase+ comLineStatus)&LS_RX_DATA_READY)==1) READ_PORT_UCHAR(IoPortBase+comRxBuffer); TTY_IT : corrigé
TTY_Open (2) // Autoriser l'IT Receiver Ready WRITE_PORT_UCHAR(IoPortBase+comIntEnable, 0x01); return !0; }// Fin TTY_Open TTY_IT : corrigé
TTY_Close BOOL TTY_Close(DWORD hOpenContext) { RETAILMSG(1,(TEXT("TTY: TTY_Close\n"))); // Inhibition de l'IT Receiver Ready WRITE_PORT_UCHAR(IoPortBase+comIntEnable, 0x0); return TRUE; }// Fin TTY_Close TTY_IT : corrigé
TTY_IOControl (1) BOOL TTY_IOControl(DWORD hOpenContext, DWORD dwCode, PBYTE pBufIn, DWORD dwLenIn, PBYTE pBufOut, DWORD dwLenOut, PDWORD pdwActualOut) { switch(dwCode) { TTY_IT : corrigé
TTY_IOControl (2) case IOCTL_PUTC: // Attente transmetteur Ready while(!(READ_PORT_UCHAR(IoPortBase+ comLineStatus)& LS_THR_EMPTY)) ; // Envoi du caractère WRITE_PORT_UCHAR(IoPortBase+ comTxBuffer,pBufIn[0]); break; TTY_IT : corrigé