« TPI SE3 2024/2025 » : différence entre les versions

De projets-se.plil.fr
Aller à la navigation Aller à la recherche
(Page créée avec «  == Objectif du projet informatique == Le but de ce projet est de vous faire concevoir et réaliser deux programmes. Un programme classique sur PC et un programme tournant sur un système embarqué. Les deux programmes vont utiliser des bibliothèques, à la fois des bibliothèques USB (libusb-1.0, bibliothèque joystick et LUFA) mais aussi des bibliothèques que vous allez devoir concevoir et écrire. == Matériel == Poour 2024/2025 vous pouvez utiliser la ca... »)
 
 
(18 versions intermédiaires par un autre utilisateur non affichées)
Ligne 1 : Ligne 1 :


== Objectif du projet informatique ==
== Généralités ==


Le but de ce projet est de vous faire concevoir et réaliser deux programmes. Un programme classique sur PC et un programme tournant sur un système embarqué. Les deux programmes vont utiliser des bibliothèques, à la fois des bibliothèques USB (libusb-1.0, bibliothèque joystick et LUFA) mais aussi des bibliothèques que vous allez devoir concevoir et écrire.
=== Objectif du projet ===


== Matériel ==
Le but de ce projet de programmation matérielle est de vous faire concevoir et réaliser :
* un programme tournant sur un système embarqué utilisant la bibliothèque <code>LUFA</code> ;
* un programme classique sur PC utilisant la bibliothèque <code>libusb-1.0</code>.


Poour 2024/2025 vous pouvez utiliser la carte "programmateur ISP" que vous avez réalisé en "programmation des systèmes embarqués", en particulier si vous avez prévu assez de boutons et de LED. Si votre carte ne vous parait pas adaptée, vous pouvez utiliser une des [https://wiki-ima.plil.fr/mediawiki//index.php/IMA4_2018/2019_SEC4|manettes déjà réalisées].
=== Matériel ===


Pour cette année vous construisez vous-même votre manette. Cette manette comporte des boutons pour diriger votre vaisseau et des LED pour afficher votre nombre de vies restantes.
Pour 2024/2025, vous pouvez utiliser la carte "programmateur ISP" que vous avez réalisée en "programmation des systèmes embarqués", en particulier si vous avez prévu assez de boutons et de LED. Si votre carte ne vous parait pas adaptée, vous pouvez utiliser une des [https://wiki-ima.plil.fr/mediawiki//index.php/IMA4_2018/2019_SEC4 manettes] déjà réalisées.


En cas de microcontrôleur non initialisé ou briqué, il est toujours possible de flasher l’ATMega32u4 au travers du connecteur ICSP prévu. Un connecteur ICSP dispose de toutes les lignes permettant de flasher un ATMega, à savoir l’alimentation, le reset et les lignes du bus SPI. Si vous en arrivez là, il vous faudra un Arduino à utiliser comme programmateur et quelques câbles pour connecter l’Arduino à la manette.
Les boutons seront utilisés pour diriger votre vaisseau et les LED pour afficher votre nombre de vies restantes.
3  Le jeu : envahisseurs de l’espace


Vous allez programmer un très classique jeu des envahisseurs de l’espace (space invader en patoi). Le terrain est en deux dimensions. Les envahisseurs arrivent par le haut de l’écran en rangées qui se déplacent de gauche à droite et descendent d’un cran quand elles arrivent en butée sur un bord du terrain. Le joueur contrôle un vaisseau pouvant se déplacer horizontalement en bas du terrain, le vaisseau peut s’abriter derrière des boucliers. Les envahisseurs laissent tomber aléatoirement et verticalement des bombes. Le vaisseau peut envoyer des missiles. Plusieurs bombes et plusieurs missiles peuvent être présents sur le terrain simultanément. Un envahisseur peut être détruit par un ou plusieurs missiles, un missile ne peut toucher qu’un envahisseur. Les bombes peut ébrécher les boucliers et endommager le vaisseau, si le vaisseau est trop endommagé il explose et la partie est terminée. Si un envahisseur touche le vaisseau, il explose.
=== Installation d'un chargeur DFU ===
3.1  Gestion des niveaux


Sur destruction du vaisseau, le score est remis à zéro et le jeu reprend sur la liste des plus hauts scores. Ces scores sont stockés dans un fichier. Si tous les envahisseurs d’un niveau sont détruits, un niveau supérieur est proposé. Les niveaux doivent être de difficulté croissante (augmentation de la vitesse de descente des rangées, nombre de missiles nécessaire à tuer un type d’envahisseur, etc.).
Cette étape n'est probablement pas nécessaire, les AVR avec gestion USB matérielle étant généralement programmés d'usine avec un tel chargeur.
3.2  Structuration du jeu


Prévoyez les répertoires suivants avec un système de makefile pour compiler l’ensemble du projet :
En cas de microcontrôleur non initialisé ou briqué, il est toujours possible de le flasher au travers du connecteur ICSP prévu. Un connecteur ICSP dispose de toutes les lignes permettant de programmer un ATmega, à savoir l’alimentation, le reset et les lignes du bus SPI. Si vous en arrivez là, il vous faudra un Arduino UNO à utiliser comme programmateur et quelques câbles pour connecter l’Arduino à la manette. Plus précisément, il faut connecter GND, VCC et les lignes SPI de l'Arduino avec celles de votre carte. Il faut aussi connecter l'E/S de numéro Arduino 10 vers le RST de votre carte.


    récupérez l’archive fournie GraphiqueJeux.tgz et décompressez la ;
Commencez par modifier les fuses du microcontrôleur pour lui demander d’utiliser une horloge externe (à partir de 8Mhz) et permettre d’appeler le chargeur avec le bouton HWB. Ci-dessous un exemple de modification avec l'utilitaire <code>avrdude</code> pour l'ATmega32u4 :
    la bibliothèque graphique se trouve dans src/Graphique ;
    les images nécessaires au jeu se trouvent dans Lutins ;
    créez un sous-répertoire ListeChainee dans src pour stocker la bibliothèque statique éponyme ;
    prévoyez un sous-répertoire Controleur dans src pour les bibliothèques dynamique permettant un contrôle du jeu par clavier ou manette.


3.3 Structures de données
  avrdude -c stk500v1 -p atmega32u4 -P /dev/ttyACM0 -b 19200 -U lfuse:w:0xFF:m -U efuse:w:0xF7:m


Le vaisseau est facilement représenté par une structure cartésienne contenant sa position, son état, etc. Les boucliers font partie intégrante du décor et l’effet des bombes est directement appliqué au dit décor.
Ensuite utilisez l'un des binaires de l'archive [[File:AVR_DFU_bootloaders.zip]] et flashez-le sur le microcontrôleur. Ci-dessous, un exemple pour l'ATmega32u4 :


Pour les autres objets : envahisseurs, bombes et missiles, une représentation plus complexe est nécessaire. Ces objets sont clairement multiples et dynamiques. Aucune structure simple (pile ou file) ne convient : un missile tiré après un autre peut être amené à disparaître avant le premier, les bombes les plus récemment lancées peuvent aussi devoir être effacées avant d’autres lancées plus anciennement. Enfin les envahisseurs peuvent être détruits totalement aléatoirement. La seule structure qui convient est donc la liste chaînée. Les structures chaînées doivent inclure la position et l’état des objets.
avrdude -c stk500v1 -p atmega32u4 -P /dev/ttyACM0 -b 19200 -U flash:w:ATMega32U4-usbdevice_dfu-1_0_0.hex
3.4  Gestion des bombes


La fonction de gestion des bombes doit respecter les points suivants :
Enfin, connectez votre carte en USB et vérifiez qu’elle est bien en mode DFU/USB avec la commande <code>lsusb</code>.


    la fonction gère la trajectoire des bombes ;
== Programmation sur microcontrôleur ==
    les bombes sortant par le bas du terrain sont supprimées de la liste ;
    les bombes touchant un bouclier (test direct sur le décor) écornent le bouclier (action directe sur le décor) et sont supprimées de la liste ;
    la fonction indique en retour si le canon a été touché.


3.5  Gestion des missiles
=== Principe ===


La fonction de gestion des missiles doit respecter les points suivants :
Vous devez programmer l'ATmega8u2 de votre carte ou l’ATMega32u4 de la manette pour gérer le bus USB et réaliser un périphérique USB. Vous utiliserez <code>avr-gcc</code> comme compilateur C. Le téléchargement du programme sur le microcontrôleur se fera en utilisant l’utilitaire <code>dfu-programmer</code> capable de programmer les AVR ATMega8u2 et ATMega32u4 via le bus USB. Vous n’aurez pas à programmer directement les registres du microntrôleur pour gérer l’USB, vous utiliserez une bibliothèque nommée LUFA.


    la fonction gère la trajectoire des missiles ;
En première approche, vous devez implanter un périphérique USB HID (périphérique d’interface homme-machine, Human Interface Device en patoi). Plus précisement vous devez implanter un périphérique USB HID clavier. Un tel périphérique comporte une interface de classe HID avec au minimum un point d’accès entrant (IN). Vous devez faire en sorte que votre clavier gère les boutons de la carte comme des touches. Votre clavier USB doit aussi contrôler les LED présentes sur la carte.
    les missiles sortant par le haut du terrain sont supprimées de la liste ;
    la collision avec tous les envahisseurs est testée en utilisant les positions 2D ;
    une collision entraine la suppression du missile de la liste chaînée et un dommage sur l’envahisseur avec une éventuelle suppression de la liste des envahisseurs ;
    la fonction indique en retour s’il ne reste plus aucun monstre.  


3.6  Gestion des envahisseurs
Vous ajouterez à ce périphérique USB une interface supplémentaire pour gérer les codes des touches. Grâce à cette interface supplémentaire vous pourrez programmer votre "clavier USB" pour envoyer les codes des touches utilisées par votre jeu "envahisseurs".


Une première fonction va initialiser la liste chaînée des envahisseurs selon le niveau.
=== Téléversement du programme sur le microcontrôleur ===


La seconde fonction de gestion des envahisseurs doit déplacer tous les envahisseurs selon le principe cité plus haut. Aléatoirement un ou plusieurs envahisseurs sont choisis pour lancer une bombe.
Pour téléverser votre programme sur le microcontrôleur, le paquetage Debian <code>dfu-programmer</code> est nécessaire. Installez le au besoin. La procédure à suivre pour charger votre programme est la suivante :
3.7  Moteur du jeu sur un niveau
* appuyez sur le bouton de passage en mode chargeur (bouton HWB) puis sur le bouton de réinitialisation (RST), relachez d’abord le second puis le premier ;
* la carte doit être listée comme en mode DFU dans un <code>lsusb</code>, vous pouvez alors exécuter les commandes suivantes :
dfu-programmer atmega32u4 erase
dfu-programmer atmega32u4 flash programme.hex
dfu-programmer atmega32u4 reset
* vous pouvez aussi taper simplement <code>make dfu</code> dans votre projet LUFA ;
* débranchez et rebranchez votre carte, votre programme doit être actif.  


L’algorithme du moteur de jeu pour un niveau donnée comporte les étapes suivantes :
=== Premier test sur la carte ===


    initialisation de la liste chaînée des envahisseurs pour le niveau ;
Commencez par un test basique : faites clignoter des LED. Testez aussi les boutons.
    initialisation des listes chaînées bombes et missiles à une liste vide ;
    boucle sur les actions suivantes :
        le canon est déplacé en utilisant le contrôleur de la bibliothèque dynamique chargée au lancement du jeu ;
        si tir du vaisseau un missile est ajouté dans la liste chaînée correspondante ;
        appel de la fonction de déplacement des envahisseurs ;
        appels des fonctions de gestion des missiles et des bombes ;
        si le canon est détruit par les envahisseurs ou une bombe arrêter le jeu ;
        s’il ne reste plus d’envahisseurs, terminer le niveau.  


4  Bibliothèques dynamiques pour les contrôleurs
=== Code LUFA d’exemple ===


Votre jeu doit pouvoir être contrôlé par plusieurs types de contrôleurs (clavier, manette, joystick, etc.). Dans un but de modularité maximale, le type de périphérique doit être déterminé en début de jeu et va donner lieu au chargement d’une bibliothèque dynamique (fonction dlopen et ses amies).
Dans le répertoire de la bibliothèque LUFA dont une version utilisable est disponible [https://rex.plil.fr/Enseignement/Systeme/Systeme.PSE/lufa-LUFA-210130-NSI.zip ici], créez un répertoire <code>PolytechLille</code> au même niveau que les répertoires <code>Demos</code> et <code>Projects</code>. Dans ce répertoire, copiez la démonstration du sous-chemin <code>Device/LowLevel/Keyboard</code> sous le nom, par exemple, <code>Clavier</code>. Renommez aussi les fichiers dans le répertoire et modifiez le makefile. Au niveau du makefile indiquez le microcontrôleur correct, <code>NONE</code> comme platine de test, ajustez le chemin d’accès <code>LUFA_PATH</code> et passez à la bonne fréquence.


Chaque bibliothèque dynamique de gestion de contrôleur doit comporter une fonction d’initialisation du périphérique, une fonction d’interrogation du périphérique et une fonction de cloture de l’utilisation du périphérique. Concevez ces fonctions avec des prototypes permettant d’utiliser une large gamme de contrôleurs.
Vous pouvez compiler cet exemple et le charger sur votre carte (rappel un simple <code>make dfu</code> suffit). Vérifiez ensuite que le périphérique USB est bien présent avec un <code>lsusb</code>. A ce point le clavier ne doit pas encore fonctionner.


Pour tester vos prototypes écrivez la bibliothèque dynamique utilisant le clavier.
=== Adaptation de l'exemple à la carte ===


Pour charger la bibliothèque correspondant aux voeux de l’utilisateur vous pouvez, soit sélectionner la bibliothèque via un paramêtre de l’exécutable du jeu, soit passer par un item du menu principal du jeu.
Modifiez le fichier <code>Clavier.c</code>, en particulier la fonction <code>CreateKeyboardReport</code> pour créer des rapports HID en fonction des valeurs retournées par les boutons et la fonction <code>ProcessLEDReport</code> pour gérer les LED. Programmez de façon structurée en positionnant le code d'initialisation en fin de la fonction <code>SetupHardware</code>.
5  Manette USB


Vous devez programmer l’ATMega32u4 de la manette pour gérer le bus USB et implanter un périphérique USB. Vous utiliserez avr-gcc comme compilateur C. Le téléchargement du programme sur le microcontrôleur se fera en utilisant l’utilitaire dfu-programmer capable de programmer l’ATMega32u4 via le bus USB. Vous n’aurez pas à programmer directement les registres de l’ATMega32u4 pour gérer l’USB, vous utiliserez une bibliothèque nommée LUFA.
Prennez soin de modifier le descripteur HID dans <code>Descriptors.c</code> pour adapter le nombre de LED à votre carte.


Sur le principe vous devez implanter un périphérique USB HID (périphérique d’interface homme-machine, Human Interface Device en patoi). Plus précisement vous devez implanter un périphérique USB HID joystick. Un tel périphérique comporte une interface de classe HID avec au minimum un point d’accès entrant (IN). Il vous est demandé d’utiliser deux boutons pour simuler un axe du Joystick et un autre bouton dans son rôle normal de bouton.
=== Gestion des codes de touches ===


Vous ajouterez à ce périphérique USB une interface supplémentaire pour gérer les LED. L’interface supplémentaire doit présenter un point d’accès de type interruption en écriture (endpoint OUT). Les données envoyéies sur ce point d’accès doivent avoir une taille d’un octet. Organisez les bits correspondant aux LED comme vous l’entendez.
Vous allez ajouter, à l’interface standard HID, une autre interface de classe spécifique au vendeur (<code>USB_CSCP_VendorSpecificClass</code>, pas de descripteur supplémentaire nécessaire) peuplée d’un point d’accès de type interruption en écriture (endpoint OUT). Les données envoyées sur ce point d’accès doivent avoir une taille de deux octets. Le premier octet représente le numéro du bouton sur la carte, le second octet représente le code (symbole) retourné au PC par votre clavier lorsque le bouton est utilisé.
5.1  Programmation initiale de la carte


Si vous avez un microcontrôleur sans chargeur DFU/USB vous allez devoir l’installer. Pour cela utilisez un programmateur AVR sous la forme d’un Arduino Uno avec quelques câbles et programmé avec le programme ArduinoISP.
Référez-vous au cours "programmation des systèmes embarqués" pour la gestion du point d'accès de type interruption.


Commencez par modifier les fuses du microcontrôleur pour lui demander d’utiliser une horloge externe (à partir de 8Mhz) et permettre d’appeler le chargeur avec le bouton HWB :
Les associations doivent être sauvées en EEPROM. Pour cela vous pouvez utiliser les fonctions d'<code>avr-gcc</code> dont les prototypes se trouvent dans <code><avr/eeprom.h</code>, à savoir <code>eeprom_write_byte</code> et <code>eeprom_read_byte</code>.
 
avrdude -c stk500v1 -p atmega32u4 -P /dev/ttyACM0 -b 19200 -U lfuse:w:0xFF:m -U efuse:w:0xF7:m
== Programmation sur le PC ==
 
Ensuite il faut télécharger le chargeur DFU/USB à partir du site Microchip https://www.microchip.com/en-us/product/atmega32u4 (cherchez "Embedded Software"). Une fois le fichier ATMega32U4-usbdevice_dfu-1_0_0.hex sous la main, flashez le sur le microcontrôleur :


avrdude -c stk500v1 -p atmega32u4 -P /dev/ttyACM0 -b 19200 -U flash:w:ATMega32U4-usbdevice_dfu-1_0_0.hex
En plus du programme "envahisseurs" que vous réalisez par ailleurs, vous allez devoir écrire un programme annexe pour gérer les codes de touches à utiliser.


Enfin connectez votre carte en USB et vérifiez qu’elle est bien en mode DFU/USB avec la commande lsusb.
=== Utilisation de la carte dans le jeu "envahisseurs" ===
5.2  Téléversement du programme


Pour téléverser votre programme sur l’ATMega32u4, le paquetage Debian dfu-programmer est nécessaire. Installez le au besoin. La procédure à suivre pour charger votre programme sur l’ATMega32u4 est la suivante :
Il n'y a de modification à apporter au jeu pour utiliser la carte en tant que dispositif de contrôle du vaisseau. Pour le nombre de vies utilisez le système de fichiers virtuel <code>sysfs</code>. Regardez du coté du répertoire <code>/sys/class/leds</code>.


    appuyez sur le bouton de passage en mode chargeur (bouton HWB) puis sur le bouton de réinitialisation (RST), relachez d’abord le second puis le premier ;
=== Gestion des codes de touches ===
    la carte doit être listée comme en mode DFU dans un lsusb, vous pouvez alors exécuter les commandes suivantes :


    dfu-programmer atmega32u4 erase
Nous souhaitons pouvoir associer les boutons de la carte aux codes des touches utilisés dans le jeu pour cela nous avons créé une interface spécifique au niveau du périphérique USB.
    dfu-programmer atmega32u4 flash Manette.hex
    dfu-programmer atmega32u4 reset


    vous pouvez aussi taper simplement make dfu ;
Nous allons donc utiliser la bibliothèque USB <code>libusb-1.0</code> pour interagir avec cette interface. Vous avez le manuel complet de la bibliothèque à l’URL [http://libusb.sourceforge.net/api-1.0/modules.html]. Vous trouverez un résumé de la bibliothèque à l’URL [https://rex.plil.fr/Enseignement/Systeme/Systeme.PSE]/. Pour cette utilisation assez basique nous utiliserons les fonctions de communication bloquantes.
    débranchez et rebranchez votre carte, votre programme doit être actif sur l’ATMega32u4.  


5.3  Prise en main
==== Enumération des périphériques USB ====


Commencez par un test basique de la manette : faites clignoter des LED. Testez aussi les boutons. Pour le programme de test, vous pouvez partir du programme que vous avez écrit dans le module "microprocesseur".
Ecrivez une fonction pour examiner tous les périphériques USB disponibles sur les bus USB de votre machine de TP. Dès qu’un périphérique s’avère être un périphérique USB du type cherché, sauvez la "poignée" (obtenue avec <code>libusb_open</code>) vers ce périphérique dans un tableau statique global de type <code>libusb_device_handle* periphs[MAX_PERIPH]</code>.   
5.4  Code LUFA d’exemple
 
Sur le site http://www.fourwalledcubicle.com/LUFA.php, téléchargez la dernière version de la bibliothèque USB LUFA. Créez un répertoire PolytechLille au même niveau que les répertoires Demos et Projects. Dans ce répertoire, copiez la démonstration du sous-chemin Device/LowLevel/Joystick sous le nom, par exemple, Manette. Renommez aussi les fichiers dans le répertoire et modifiez le makefile. Au niveau du makefile indiquez atmega32u4 comme microcontrôleur, NONE comme platine, ajustez le chemin d’accès LUFA_PATH et passez à 8Mhz.
5.5  Adaptation du code à la manette
 
Modifiez le fichier makefile. Modifiez ensuite le fichier Manette.c, en particulier la fonction CALLBACK_HID_Device_CreateHIDReport pour créer des rapports HID en fonction des valeurs retournées par les boutons.
5.6  Gestion des actionneurs
 
En toute théorie, il serait possible d’intégrer la gestion des LED sous la classe USB HID. Le moins que l’on puisse dire c’est que cela complexifie considérablement le descripteur HID et encore il faut faire de l’ingéniérie inverse pour le constituer. Nous allons donc procéder autrement. Vous allez ajouter, à l’interface standard HID, une autre interface de classe spécifique au vendeur (USB_CSCP_VendorSpecificClass, pas de descripteur supplémentaire nécessaire) peuplée d’un point d’accès de type interruption en écriture (endpoint OUT). La communication sur ce point d’accès se fera sur un octet. Ce octet doit commander les LED de la carte.   
   
   
Pour la gestion des points d’accès interruption, vous pouvez vous aider de la démonstration Keyboard dans le répertoire Device/LowLevel. La déclaration des interfaces et des points d’accès est clairement montrée dans les fichiers Descriptors.c et Descriptors.h de cette démonstration. La gestion de points d’accès de type interruption est montrée dans l’autre source C de la démonstration, cherchez les fonctions Endpoint_ConfigureEndpoint, Endpoint_SelectEndpoint, etc. 
Vous pouvez utiliser la commande <code>lsusb</code> pour trouver les identifiants USB de votre type de périphérique, même si ce n'est pas vraiment nécessaire puisque vous avez vous-même donné ces identifiants lors de la programmation du microcontrôleur. Pour chaque périphérique sélectionné, faites afficher le numéro du bus sur lequel se trouve le périphérique ainsi que son adresse sur ce bus.
N’hésitez pas à consulter la documentation de la bibliothèque sur Internet.
6  Utilisation en tant que manette dans le jeu


Pour utiliser votre manette dans le jeu "envahisseurs" que vous programmez utilisez le pilote joystick SDL.
==== Appropriation des interfaces spécifiques ====


Vous pouvez vous appuyer sur le tutoriel : https://alexandre-laurent.developpez.com/tutoriels/sdl/joysticks/.
Une fois un périphérique détecté, il faut récupérer sa configuration. La fonction <code>libusb_get_active_config_descriptor</code> qui permet cela nécessite un pointeur sur périphérique de type <code>libusb_device *</code>. Vous pouvez retrouver ce pointeur en fonction de la "poignée" par la fonction <code>libusb_get_device</code>. Faites afficher la valeur de cette configuration.   
7  Utilisation des LED de la manette dans le jeu
 
Nous souhaitons enfin pouvoir utiliser les actionneurs de la manette (LED). Nous n’avons pas intégré ces actionneurs à l’interface HID mais nous avons créé une interface spécifique pour les contrôler.
 
Nous allons donc utiliser la bibliothèque USB libusb-1.0 pour écrire des fonctions C permettant de contrôler les LED. Vous avez le manuel complet de la bibliothèque à l’URL http://libusb.sourceforge.net/api-1.0/modules.html. Vous trouverez un résumé de la bibliothèque à l’URL https://rex.plil.fr/Enseignement/Systeme/Systeme.PSE/. Pour cette utilisation assez basique nous utiliserons les fonctions de communication bloquantes.
7.1  Enumération des périphériques USB
 
Ecrivez une fonction pour examiner tous les périphériques USB disponibles sur les bus USB de votre machine de TP. Dès qu’un périphérique s’avère être un périphérique USB du type cherché, sauvez la "poignée" (obtenue avec libusb_open) vers ce périphérique dans un tableau statique global de type libusb_device_handle* periphs[MAX_PERIPH]. 
Vous pouvez utiliser la commande lsusb pour trouver les identifiants USB de votre type de périphérique. Pour chaque périphérique sélectionné, faites afficher le numéro du bus sur lequel se trouve le périphérique ainsi que son adresse sur ce bus.
7.2  Appropriation des interfaces spécifiques
 
Une fois un périphérique détecté, il faut récupérer sa configuration. La fonction libusb_get_active_config_descriptor qui permet cela nécessite un pointeur sur périphérique de type libusb_device *. Vous pouvez retrouver ce pointeur en fonction de la "poignée" par la fonction libusb_get_device. Faites afficher la valeur de cette configuration.   
   
   
Il vous reste ensuite, à réclamer les interfaces nécessaires pour votre usage. Attention, la fonction libusb_claim_interface nécessite le numéro de l’interface et pas son indice. Vous allez donc parcourir la structure arborescente de description de configuration du périphérique de la façon suivante :
Il vous reste ensuite, à réclamer les interfaces nécessaires pour votre usage. Attention, la fonction <code>libusb_claim_interface</code> nécessite le numéro de l’interface et pas son indice. Vous allez donc parcourir la structure arborescente de description de configuration du périphérique de la façon suivante :
 
* itérer sur le nombre d’interfaces ;
    itérer sur le nombre d’interfaces ;
* explorer chaque sous-structure d’interface de classe <code>LIBUSB_CLASS_VENDOR_SPEC</code> ;
    explorer chaque sous-structure d’interface de classe LIBUSB_CLASS_VENDOR_SPEC ;
* pour chaque interface, prendre la première alternative d’interface ;
    pour chaque interface, prendre la première alternative d’interface ;
* trouver le numéro d’interface pour utilisation avec <code>libusb_claim_interface</code> ;
    trouver le numéro d’interface pour utilisation avec libusb_claim_interface ;
* récupérer le point d’accès présent, sauver l'adresse du point d’accès dans un tableau global.  
    récupérer le point d’accès présent, sauver le numéro du point d’accès dans une variable globale (pas la peine de déclarer un tableau, tous les périphériques de même identifiant sont réputés avoir les mêmes numéros de point d’accès).  


Affichez l’indice et le numéro de chaque interface détectée et réclamée. Affichez aussi le numéro du point d’accès trouvé.
Affichez l’indice et le numéro de chaque interface détectée et réclamée. Affichez aussi l'adresse du point d’accès trouvé.
7.3  Fermeture du périphérique USB


Ecrivez une fonction qui libère les périphériques détectés. Pour cela, relachez toutes les interfaces réclamées puis fermez la "poignée". Vous allez devoir, à nouveau, explorer la structure arborescente de description de configuration du périphérique ou sauver les numéros des interfaces dans le tableau global. Affichez l’indice et le numéro de chaque interface libérée.
==== Fermeture du périphérique USB ====
7.4  Gestion des actionneurs


Vous pouvez maintenant ajouter le contrôle des LED sous la forme d’une bibliothèque dynamique (répertoire à part dans votre projet "envahisseurs"). Les fonctions de cette bibliothèque sont a appeler dans votre jeu.
Ecrivez une fonction qui libère les périphériques détectés. Pour cela, relachez toutes les interfaces réclamées puis fermez la "poignée". Vous allez devoir, à nouveau, explorer la structure arborescente de description de configuration du périphérique ou sauver les numéros des interfaces dans un tableau global. Affichez l’indice et le numéro de chaque interface libérée.


L’état du vaisseau doit être affiché, sous la forme d’un barre de vie, sur les LED de la manette.
==== Association bouton / code ====


    Ce document a été traduit de LATEX par HEVEA
Vous pouvez maintenant écrire le coeur du programme PC. Le programme doit prendre en argument un numéro de bouton et un code de touche. Une interruption USB doit être lancée pour demander à la carte d'effectuer une association entre ce numéro et ce code.

Version actuelle datée du 22 avril 2025 à 16:12

Généralités

Objectif du projet

Le but de ce projet de programmation matérielle est de vous faire concevoir et réaliser :

  • un programme tournant sur un système embarqué utilisant la bibliothèque LUFA ;
  • un programme classique sur PC utilisant la bibliothèque libusb-1.0.

Matériel

Pour 2024/2025, vous pouvez utiliser la carte "programmateur ISP" que vous avez réalisée en "programmation des systèmes embarqués", en particulier si vous avez prévu assez de boutons et de LED. Si votre carte ne vous parait pas adaptée, vous pouvez utiliser une des manettes déjà réalisées.

Les boutons seront utilisés pour diriger votre vaisseau et les LED pour afficher votre nombre de vies restantes.

Installation d'un chargeur DFU

Cette étape n'est probablement pas nécessaire, les AVR avec gestion USB matérielle étant généralement programmés d'usine avec un tel chargeur.

En cas de microcontrôleur non initialisé ou briqué, il est toujours possible de le flasher au travers du connecteur ICSP prévu. Un connecteur ICSP dispose de toutes les lignes permettant de programmer un ATmega, à savoir l’alimentation, le reset et les lignes du bus SPI. Si vous en arrivez là, il vous faudra un Arduino UNO à utiliser comme programmateur et quelques câbles pour connecter l’Arduino à la manette. Plus précisément, il faut connecter GND, VCC et les lignes SPI de l'Arduino avec celles de votre carte. Il faut aussi connecter l'E/S de numéro Arduino 10 vers le RST de votre carte.

Commencez par modifier les fuses du microcontrôleur pour lui demander d’utiliser une horloge externe (à partir de 8Mhz) et permettre d’appeler le chargeur avec le bouton HWB. Ci-dessous un exemple de modification avec l'utilitaire avrdude pour l'ATmega32u4 :

avrdude -c stk500v1 -p atmega32u4 -P /dev/ttyACM0 -b 19200 -U lfuse:w:0xFF:m -U efuse:w:0xF7:m

Ensuite utilisez l'un des binaires de l'archive Fichier:AVR DFU bootloaders.zip et flashez-le sur le microcontrôleur. Ci-dessous, un exemple pour l'ATmega32u4 :

avrdude -c stk500v1 -p atmega32u4 -P /dev/ttyACM0 -b 19200 -U flash:w:ATMega32U4-usbdevice_dfu-1_0_0.hex

Enfin, connectez votre carte en USB et vérifiez qu’elle est bien en mode DFU/USB avec la commande lsusb.

Programmation sur microcontrôleur

Principe

Vous devez programmer l'ATmega8u2 de votre carte ou l’ATMega32u4 de la manette pour gérer le bus USB et réaliser un périphérique USB. Vous utiliserez avr-gcc comme compilateur C. Le téléchargement du programme sur le microcontrôleur se fera en utilisant l’utilitaire dfu-programmer capable de programmer les AVR ATMega8u2 et ATMega32u4 via le bus USB. Vous n’aurez pas à programmer directement les registres du microntrôleur pour gérer l’USB, vous utiliserez une bibliothèque nommée LUFA.

En première approche, vous devez implanter un périphérique USB HID (périphérique d’interface homme-machine, Human Interface Device en patoi). Plus précisement vous devez implanter un périphérique USB HID clavier. Un tel périphérique comporte une interface de classe HID avec au minimum un point d’accès entrant (IN). Vous devez faire en sorte que votre clavier gère les boutons de la carte comme des touches. Votre clavier USB doit aussi contrôler les LED présentes sur la carte.

Vous ajouterez à ce périphérique USB une interface supplémentaire pour gérer les codes des touches. Grâce à cette interface supplémentaire vous pourrez programmer votre "clavier USB" pour envoyer les codes des touches utilisées par votre jeu "envahisseurs".

Téléversement du programme sur le microcontrôleur

Pour téléverser votre programme sur le microcontrôleur, le paquetage Debian dfu-programmer est nécessaire. Installez le au besoin. La procédure à suivre pour charger votre programme est la suivante :

  • appuyez sur le bouton de passage en mode chargeur (bouton HWB) puis sur le bouton de réinitialisation (RST), relachez d’abord le second puis le premier ;
  • la carte doit être listée comme en mode DFU dans un lsusb, vous pouvez alors exécuter les commandes suivantes :
dfu-programmer atmega32u4 erase
dfu-programmer atmega32u4 flash programme.hex
dfu-programmer atmega32u4 reset
  • vous pouvez aussi taper simplement make dfu dans votre projet LUFA ;
  • débranchez et rebranchez votre carte, votre programme doit être actif.

Premier test sur la carte

Commencez par un test basique : faites clignoter des LED. Testez aussi les boutons.

Code LUFA d’exemple

Dans le répertoire de la bibliothèque LUFA dont une version utilisable est disponible ici, créez un répertoire PolytechLille au même niveau que les répertoires Demos et Projects. Dans ce répertoire, copiez la démonstration du sous-chemin Device/LowLevel/Keyboard sous le nom, par exemple, Clavier. Renommez aussi les fichiers dans le répertoire et modifiez le makefile. Au niveau du makefile indiquez le microcontrôleur correct, NONE comme platine de test, ajustez le chemin d’accès LUFA_PATH et passez à la bonne fréquence.

Vous pouvez compiler cet exemple et le charger sur votre carte (rappel un simple make dfu suffit). Vérifiez ensuite que le périphérique USB est bien présent avec un lsusb. A ce point le clavier ne doit pas encore fonctionner.

Adaptation de l'exemple à la carte

Modifiez le fichier Clavier.c, en particulier la fonction CreateKeyboardReport pour créer des rapports HID en fonction des valeurs retournées par les boutons et la fonction ProcessLEDReport pour gérer les LED. Programmez de façon structurée en positionnant le code d'initialisation en fin de la fonction SetupHardware.

Prennez soin de modifier le descripteur HID dans Descriptors.c pour adapter le nombre de LED à votre carte.

Gestion des codes de touches

Vous allez ajouter, à l’interface standard HID, une autre interface de classe spécifique au vendeur (USB_CSCP_VendorSpecificClass, pas de descripteur supplémentaire nécessaire) peuplée d’un point d’accès de type interruption en écriture (endpoint OUT). Les données envoyées sur ce point d’accès doivent avoir une taille de deux octets. Le premier octet représente le numéro du bouton sur la carte, le second octet représente le code (symbole) retourné au PC par votre clavier lorsque le bouton est utilisé.

Référez-vous au cours "programmation des systèmes embarqués" pour la gestion du point d'accès de type interruption.

Les associations doivent être sauvées en EEPROM. Pour cela vous pouvez utiliser les fonctions d'avr-gcc dont les prototypes se trouvent dans <avr/eeprom.h, à savoir eeprom_write_byte et eeprom_read_byte.

Programmation sur le PC

En plus du programme "envahisseurs" que vous réalisez par ailleurs, vous allez devoir écrire un programme annexe pour gérer les codes de touches à utiliser.

Utilisation de la carte dans le jeu "envahisseurs"

Il n'y a de modification à apporter au jeu pour utiliser la carte en tant que dispositif de contrôle du vaisseau. Pour le nombre de vies utilisez le système de fichiers virtuel sysfs. Regardez du coté du répertoire /sys/class/leds.

Gestion des codes de touches

Nous souhaitons pouvoir associer les boutons de la carte aux codes des touches utilisés dans le jeu pour cela nous avons créé une interface spécifique au niveau du périphérique USB.

Nous allons donc utiliser la bibliothèque USB libusb-1.0 pour interagir avec cette interface. Vous avez le manuel complet de la bibliothèque à l’URL [1]. Vous trouverez un résumé de la bibliothèque à l’URL [2]/. Pour cette utilisation assez basique nous utiliserons les fonctions de communication bloquantes.

Enumération des périphériques USB

Ecrivez une fonction pour examiner tous les périphériques USB disponibles sur les bus USB de votre machine de TP. Dès qu’un périphérique s’avère être un périphérique USB du type cherché, sauvez la "poignée" (obtenue avec libusb_open) vers ce périphérique dans un tableau statique global de type libusb_device_handle* periphs[MAX_PERIPH].

Vous pouvez utiliser la commande lsusb pour trouver les identifiants USB de votre type de périphérique, même si ce n'est pas vraiment nécessaire puisque vous avez vous-même donné ces identifiants lors de la programmation du microcontrôleur. Pour chaque périphérique sélectionné, faites afficher le numéro du bus sur lequel se trouve le périphérique ainsi que son adresse sur ce bus.

Appropriation des interfaces spécifiques

Une fois un périphérique détecté, il faut récupérer sa configuration. La fonction libusb_get_active_config_descriptor qui permet cela nécessite un pointeur sur périphérique de type libusb_device *. Vous pouvez retrouver ce pointeur en fonction de la "poignée" par la fonction libusb_get_device. Faites afficher la valeur de cette configuration.

Il vous reste ensuite, à réclamer les interfaces nécessaires pour votre usage. Attention, la fonction libusb_claim_interface nécessite le numéro de l’interface et pas son indice. Vous allez donc parcourir la structure arborescente de description de configuration du périphérique de la façon suivante :

  • itérer sur le nombre d’interfaces ;
  • explorer chaque sous-structure d’interface de classe LIBUSB_CLASS_VENDOR_SPEC ;
  • pour chaque interface, prendre la première alternative d’interface ;
  • trouver le numéro d’interface pour utilisation avec libusb_claim_interface ;
  • récupérer le point d’accès présent, sauver l'adresse du point d’accès dans un tableau global.

Affichez l’indice et le numéro de chaque interface détectée et réclamée. Affichez aussi l'adresse du point d’accès trouvé.

Fermeture du périphérique USB

Ecrivez une fonction qui libère les périphériques détectés. Pour cela, relachez toutes les interfaces réclamées puis fermez la "poignée". Vous allez devoir, à nouveau, explorer la structure arborescente de description de configuration du périphérique ou sauver les numéros des interfaces dans un tableau global. Affichez l’indice et le numéro de chaque interface libérée.

Association bouton / code

Vous pouvez maintenant écrire le coeur du programme PC. Le programme doit prendre en argument un numéro de bouton et un code de touche. Une interruption USB doit être lancée pour demander à la carte d'effectuer une association entre ce numéro et ce code.