« SE3 PSE Binome2023-6 » : différence entre les versions
|  (→Code C) | |||
| (55 versions intermédiaires par 2 utilisateurs non affichées) | |||
| Ligne 2 : | Ligne 2 : | ||
| == ''DESIGN, LIMITES, FONCTIONNALITÉS ET DESCRIPTION DE LA MANETTE'' == | == ''DESIGN, LIMITES, FONCTIONNALITÉS ET DESCRIPTION DE LA MANETTE'' == | ||
| Ce projet a pour but de développer une manette capable jouer et interagir avec le jeu "Space Invaders" réalisé lors du projet informatique avec Monsieur DEQUIDT et Monsieur FORGET. | |||
| * Taille de la carte : 10x10 cm maximum | * Taille de la carte : 10x10 cm maximum | ||
| * Fonctionne en 5V | * Fonctionne en 5V | ||
| * Utilisation de LEDs pour visualiser les vies restantes sur la manette | * Utilisation de LEDs pour visualiser les vies restantes sur la manette | ||
| * 6 boutons : 4 de déplacement mais que deux utilisables (gauche et droite) et les deux autres (haut et bas) pour d'autres jeux à l'avenir. Les deux boutons à droite de la carte, en bas pour tirer, en haut pour quitter. | * 6 boutons : 4 de déplacement mais que deux utilisables (gauche et droite) et les deux autres (haut et bas) pour d'autres jeux à l'avenir. Les deux boutons à droite de la carte, en bas pour tirer, en haut pour quitter. | ||
| *  | * Le design de la forme de la manette est inspiré d'une vieille manette de SNES | ||
| [[Fichier:ManetteSNES.jpg|néant|vignette|Une manette SNES tout à fait basique]] | [[Fichier:ManetteSNES.jpg|néant|vignette|Une manette SNES tout à fait basique]] | ||
| Ligne 13 : | Ligne 14 : | ||
| {| class="wikitable" | {| class="wikitable" | ||
| |- | |- | ||
| | [[Fichier:Schematic2 manette.png| | | [[Fichier:Schematic2 manette.png|500px]] || Screenshot de la schématique de l'ATMega || width=15% | Screenshot de la schématique des connecteurs LEDs, Boutons, ISP et USB.  | ||
| J1 est l'ISP. | |||
| J2 est le port USB communiquant avec l'hôte (l'ordinateur) | |||
| SW1,SW2,SW3, | |||
| SW4,SW5,SW6 sont les boutons sur lesquelles nous allons appuyer pour se déplacer, tirer, quitter,... | |||
| D2,D3,D4,D5 sont les LEDs qui représenteront les vies en jeu<br> | |||
| | [[Fichier:Schematic1 manette.png|600px]]   | |||
| |- | |- | ||
| | [[Fichier:SCHEMATIC MANETTE.pdf| | | [[Fichier:SCHEMATIC MANETTE.pdf|500px|PDF du schématique complet de la manette|gauche]] || PDF avec la schématique complète de la manette   | ||
| |  | | width=15% | Vidéos montrant l'interaction entre les boutons de la manette et l'application Joystick de l'ordinateur || [[Fichier:Video joystick manette.mp4|vignette|400px|centre| 1ere itération de l'interaction entre manette et pad joystick. Il y a trois axes mais si on enlève un morceau de code on peut avoir seulement deux axes d'interactions (x et y) ]] | ||
| [[Fichier:ManetteAvecAxeCirculaire.mp4|centre|400px|vignette|2nd itération  de l'interaction entre Manette et pad joystick mais seulement avec deux axes (x et y) et non 3 (x, y et z)]] | |||
| |} | |} | ||
| == ''PCB'' == | == ''PCB et BRASURE'' == | ||
| {| class="wikitable" | {| class="wikitable" | ||
| |- | |- | ||
| |- | |- | ||
| | style="width:25%;" | [[Fichier: | | style="width:25%;" | [[Fichier:Screenshot 2024-03-11 17-47-48.png|400px]] || style="width:25%;text-align:center;" | PCB final de la manette ||  rowspan="4" | Deuxième manette qui fonctionne cette fois-ci. La manette en mode DFU, la petite LED en haut à droite allumée est dû au port connecté à cette LED. Les derniers ports PF (5,6,7) sont des PIN spéciaux qui allument les LED connectées || rowspan="4" |  [[Fichier:Bootloader.jpg|400px]] | ||
| |- | |- | ||
| |[[Fichier: | |[[Fichier:Screenshot 2024-03-11 17-48-28.png|500px|centre]]  || style="text-align:center;" | Visualisation 3D de la carte | ||
| |- | |- | ||
| | [[Fichier: | |  [[Fichier:ManetteVierge.jpg|400px]] || style="text-align:center;" | Une photo de la manette PCB sans aucun composants  | ||
| |- | |- | ||
| | [[Fichier:ManetteObsolète.jpg|400px]] || style="text-align:center;" | Première itération de soudage de la manette. Un court-circuit c'est créer lors de nos premiers soudages. La manette est devenue inutilisable par la suite, nous ne pouvions plus mettre le bootloader avec un Arduino sur l'ATMega | | [[Fichier:ManetteObsolète.jpg|400px]] || style="text-align:center;" | Première itération de soudage de la manette. Un court-circuit c'est créer lors de nos premiers soudages. La manette est devenue inutilisable par la suite, nous ne pouvions plus mettre le bootloader avec un Arduino sur l'ATMega | ||
| Ligne 33 : | Ligne 41 : | ||
| =<div class="mcwiki-header" style="border-radius: 40px; padding: 15px; font-weight: bold; color: #FFFFFF; text-align: center; font-size: 80%; background: #ED254E; vertical-align: top; width: 98%;"> Programmation </div>= | =<div class="mcwiki-header" style="border-radius: 40px; padding: 15px; font-weight: bold; color: #FFFFFF; text-align: center; font-size: 80%; background: #ED254E; vertical-align: top; width: 98%;"> Programmation </div>= | ||
| ==  | == ''CODE C'' == | ||
| Pour pouvoir avoir nos boutons fonctionnel on s'est basé sur la démo du joystick pour créer "Manette", et ensuite on est partie d'un code minimal pour pouvoir rajouté la description de notre manette, et créer deux interfaces, une pour nos boutons, et une autre pour nos LEDs. | Pour pouvoir avoir nos boutons fonctionnel on s'est basé sur la démo du joystick pour créer "Manette", et ensuite on est partie d'un code minimal pour pouvoir rajouté la description de notre manette, et créer deux interfaces, une pour nos boutons, et une autre pour nos LEDs. | ||
| === Fonctions importantes et descriptions des codes === | |||
| {| class="wikitable centre" | {| class="wikitable centre" | ||
| |- | |- | ||
| | rowspan="3" |  | | rowspan="3" | | ||
| Descriptor de notre code | |||
| <syntaxhighlight line="1" start="1"> | |||
| Device Descriptor: | |||
|   bLength                18 | |||
|   bDescriptorType         1 | |||
|   bcdUSB               1.10 | |||
|   bDeviceClass            0 | |||
|   bDeviceSubClass         0 | |||
|   bDeviceProtocol         0 | |||
|   bMaxPacketSize0         8 | |||
|   idVendor           0x054c Sony Corp.  | |||
|   idProduct          0x05c4 DualShock 4 Demo Application | |||
|   bcdDevice            0.01 | |||
|   iManufacturer           1 LUFA Library | |||
|   iProduct                2 LUFA Joystick Demo | |||
|   iSerial                 0 | |||
|   bNumConfigurations      1 | |||
|   Configuration Descriptor: | |||
|     bLength                 9 | |||
|     bDescriptorType         2 | |||
|     wTotalLength       0x0032 | |||
|     bNumInterfaces          2 | |||
|     bConfigurationValue     1 | |||
| 		iConfiguration          0 | |||
|     bmAttributes         0xc0 | |||
|       Self Powered | |||
|     MaxPower              100mA | |||
|     Interface Descriptor: | |||
|       bLength                 9 | |||
|       bDescriptorType         4 | |||
|       bInterfaceNumber        0 | |||
|       bAlternateSetting       0 | |||
|       bNumEndpoints           1 | |||
|       bInterfaceClass         3 Human Interface Device | |||
|       bInterfaceSubClass      0 | |||
|       bInterfaceProtocol      0 | |||
|       iInterface              0 | |||
|         HID Device Descriptor: | |||
|           bLength                 9 | |||
|           bDescriptorType        33 | |||
|           bcdHID               1.11 | |||
|           bCountryCode            0 Not supported | |||
|           bNumDescriptors         1 | |||
|           bDescriptorType        34 Report | |||
|           wDescriptorLength      52 | |||
|          Report Descriptors: | |||
|            ** UNAVAILABLE ** | |||
|       Endpoint Descriptor: | |||
|         bLength                 7 | |||
|         bDescriptorType         5 | |||
|         bEndpointAddress     0x81  EP 1 IN | |||
|         bmAttributes            3 | |||
|           Transfer Type            Interrupt | |||
|           Synch Type               None | |||
|           Usage Type               Data | |||
|         wMaxPacketSize     0x0008  1x 8 bytes | |||
|         bInterval               5 | |||
|     Interface Descriptor: | |||
|       bLength                 9 | |||
|       bDescriptorType         4 | |||
|       bInterfaceNumber        1 | |||
|       bAlternateSetting       0 | |||
|       bNumEndpoints           1 | |||
|       bInterfaceClass       255 Vendor Specific Class | |||
|       bInterfaceSubClass    255 Vendor Specific Subclass | |||
|       bInterfaceProtocol    255 Vendor Specific Protocol | |||
|       iInterface              0 | |||
|       Endpoint Descriptor: | |||
|         bLength                 7 | |||
|         bDescriptorType         5 | |||
|         bEndpointAddress     0x02  EP 2 OUT | |||
|         bmAttributes            3 | |||
|           Transfer Type            Interrupt | |||
|           Synch Type               None | |||
|           Usage Type               Data | |||
|         wMaxPacketSize     0x0008  1x 8 bytes | |||
|         bInterval               5 | |||
| </syntaxhighlight> | |||
| | colspan="2" | [[Fichier:Manette et minimal.png|gauche|vignette|Manette et minimal trouvable dans TPI_LUFA_LibUSB/manette_LUFA/Polytech/]] Manette et minimal trouvable dans TPI_LUFA_LibUSB/manette_LUFA/Polytech/ | |||
| |- | |- | ||
| |   | | | ||
| Code définissant les conditions de nos boutons. Quels boutons fait quoi et à quel moment. | Code définissant les conditions de nos boutons. Quels boutons fait quoi et à quel moment. | ||
| <syntaxhighlight lang="c"> | <syntaxhighlight lang="c"> | ||
| Ligne 51 : | Ligne 138 : | ||
| 	bool           InputChanged     = false; | 	bool           InputChanged     = false; | ||
| 	memset(ReportData, 0, sizeof(USB_JoystickReport_Data_t)); | 	memset(ReportData, 0, sizeof(USB_JoystickReport_Data_t)); | ||
| 	if (~(PINF>>PIN7) & 1) ReportData->Button |= (1 << 1); | 	if (~(PINF>>PIN7) & 1) ReportData->Button |= (1 << 1); | ||
| 	if (~(PINF>>PIN6) & 1) ReportData->Button |= (1 << 0); | 	if (~(PINF>>PIN6) & 1) ReportData->Button |= (1 << 0); | ||
| 	if (~(PIND>>PIN1) & 1) ReportData->Y = 100; | 	if (~(PIND>>PIN1) & 1) ReportData->Y = -100; | ||
| 	if (~(PIND>>PIN2) & 1) ReportData->X = 100; | 	if (~(PIND>>PIN2) & 1) ReportData->X = 100; | ||
| 	if (~(PIND>>PIN3) & 1) ReportData->X = -100; | 	if (~(PIND>>PIN3) & 1) ReportData->X = -100; | ||
| 	if (~(PIND>>PIN5) & 1) ReportData->Y = - | 	if (~(PIND>>PIN5) & 1) ReportData->Y = 100; | ||
| 	if ((~(PIND>>PIN5) & 1) & (~(PIND>>PIN1) & 1)) ReportData->Y = 0; | |||
| 	if ((~(PIND>>PIN3) & 1) & (~(PIND>>PIN2) & 1)) ReportData->X = 0; | |||
| Ligne 67 : | Ligne 158 : | ||
| } | } | ||
| </syntaxhighlight> | </syntaxhighlight>Cela signifie que si un bouton que nous avons paramétré est pressé, nous réglons la direction X ou Y à plus ou moins 100.  | ||
| | Les PIN6 et PIN7 contrôlent les deux boutons sur la droite de la manette. Vous pouvez voir sur la vidéo dans  | |||
| Nous avons vérifié ces réglages avec jstest-gtk, un outil permettant de visualiser les directions et les pressions d'un joystick.  | |||
| Tous nos boutons sont détectés et configurés conformément à nos attentes. | |||
| | Les PIN6 et PIN7 contrôlent les deux boutons sur la droite de la manette. Vous pouvez voir sur la vidéo dans deux sections avant celle-ci quand nous appuyons dessus les cases "0" et "1" deviennent noires quand nous appuyons sur les boutons | |||
| [[Fichier:SE3-pad-joystick-Binome6.png|néant|vignette|Pad Joystick a deux axes et deux boutons d'interactions]] | [[Fichier:SE3-pad-joystick-Binome6.png|néant|vignette|Pad Joystick a deux axes et deux boutons d'interactions]] | ||
| |- | |- | ||
| Ligne 105 : | Ligne 200 : | ||
| </syntaxhighlight> | </syntaxhighlight> | ||
| | width="300px"| En modifiant le code LUFA donné par le prof, on peut allumer les LEDs, pour celles sur les pins PF0, PF1 et PF5 il faut désactiver le JTAG en copiant deux fois cette ligne au niveau de la déclaration des pins : MCUCR |= (1<<JTD); | | width="300px"| En modifiant le code LUFA donné par le prof, on peut allumer les LEDs, pour celles sur les pins PF0, PF1 et PF5 il faut désactiver le JTAG en copiant deux fois cette ligne au niveau de la déclaration des pins : MCUCR |= (1<<JTD); | ||
| En ce qui concerne les LEDs sur PORTE, il n'y a pas de problème dessus. | En ce qui concerne les LEDs sur PORTE et PORTD, il n'y a pas de problème dessus. | ||
| |- | |||
| |} | |} | ||
| {| class="wikitable centre" | |||
| |-  | |||
| |Code permettant de contrôler les LEDs en entrant des chiffres dans le terminal | |||
| |- | |||
| | | |||
| <syntaxhighlight lang="c"> | |||
| void USB_OUT_PointManagement(void) | |||
| { | |||
|   uint8_t c = 0; | |||
|   Endpoint_SelectEndpoint(LED_OUT_EPADDR); | |||
|   if (Endpoint_IsOUTReceived()) | |||
|   { | |||
|     if (Endpoint_IsReadWriteAllowed()) | |||
|     { | |||
|       c = Endpoint_Read_8(); | |||
|       if (c != 0) { | |||
|         	PORTF |= 0b00100011; | |||
| 	        PORTE |= 0b01000000; | |||
|       } | |||
|       else{ | |||
|         	PORTF &= 0b11011100; | |||
| 	        PORTE &= 0b10111111; | |||
|       } | |||
|       if (c & 0b00000001) | |||
|         PORTF |= 0b00000001; // LED 1 ON | |||
|       else | |||
|         PORTF &= ~0b00000001; // LED 1 OFF | |||
|       if (c & 0b00000010) | |||
|         PORTF |= 0b00000010; // LED 2 ON | |||
|       else | |||
|         PORTF &= ~0b00000010; // LED 2 OFF | |||
|       if (c & 0b00000100) | |||
|         PORTF |= 0b00010000; // LED 3 ON | |||
|       else | |||
|         PORTF &= ~0b00100000; // LED 3 OFF | |||
|       if (c & 0b00001000) | |||
|         PORTE |= 0b01000000; // LED 4 ON | |||
|       else | |||
|         PORTE &= ~0b01000000; // LED 4 OFF | |||
|     } | |||
|     Endpoint_ClearOUT(); | |||
|   } | |||
| } | |||
| </syntaxhighlight> | |||
| |} | |||
| === Codes complets === | |||
| {| class="wikitable centre" | |||
| |- | |||
| | width="50%" | | |||
| Le code ci-dessous présente le code libusb.c permettant de faire la communication entre le PC et la manette. C'est ce qui nous permet d'envoyer des bits d'informations par le biais du terminal CMD qui allumeront certaines LEDs. Vous pouvez voir cet exemple sur la vidéo dans la section ''VIDÉOS DE PRÉSENTATIONS''. | |||
| | width="50%" | Ceci est le Decriptor.c de notre code Fusion qui permet d'utiliser les boutons pour jouer et que le PC puisse envoyer les informations à la manette. Il crée les interfaces nécessaires pour la bonne utilisation des LEDs et des boutons de jeu. | |||
| |- | |||
| | | |||
| <syntaxhighlight lang="c"> | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <libusb-1.0/libusb.h> | |||
| #define VENDOR_ID 0x054c | |||
| #define PRODUCT_ID 0x05c4 | |||
| int main(void) { | |||
|     // Initialisation de la bibliothèque | |||
|     libusb_context *context; | |||
|     int status = libusb_init(&context); | |||
|     if (status != 0) { | |||
|         perror("libusb_init"); | |||
|         exit(-1); | |||
|     } | |||
|     // Énumération des périphériques USB | |||
|     libusb_device **list; | |||
|     ssize_t count = libusb_get_device_list(context, &list); | |||
|     if (count < 0) { | |||
|         perror("libusb_get_device_list"); | |||
|         libusb_exit(context); | |||
|         exit(-1); | |||
|     } | |||
|     // Recherche du périphérique avec le VENDOR_ID et PRODUCT_ID spécifiés | |||
|     libusb_device *device = NULL; | |||
|     for (ssize_t i = 0; i < count; i++) { | |||
|         libusb_device *dev = list[i]; | |||
|         struct libusb_device_descriptor desc; | |||
|         int status = libusb_get_device_descriptor(dev, &desc); | |||
|         if (status != 0) continue; | |||
|         if (desc.idVendor == VENDOR_ID && desc.idProduct == PRODUCT_ID) { | |||
|             device = dev; | |||
|             break; | |||
|         } | |||
|     } | |||
|     if (device == NULL) { | |||
|         printf("Device not found\n"); | |||
|         libusb_free_device_list(list, 1); | |||
|         libusb_exit(context); | |||
|         exit(-1); | |||
|     } | |||
|     // Ouverture du périphérique | |||
|     libusb_device_handle *handle; | |||
|     status = libusb_open(device, &handle); | |||
|     if (status != 0) { | |||
|         perror("libusb_open"); | |||
|         libusb_free_device_list(list, 1); | |||
|         libusb_exit(context); | |||
|         exit(-1); | |||
|     } | |||
|     // Détacher les pilotes du noyau pour toutes les interfaces | |||
|     struct libusb_config_descriptor *configdesc; | |||
|     int interface_count, i; | |||
|     status = libusb_get_active_config_descriptor(device, &configdesc); | |||
|     if (status != 0) { | |||
|         perror("libusb_get_active_config_descriptor"); | |||
|         libusb_close(handle); | |||
|         libusb_free_device_list(list, 1); | |||
|         libusb_exit(context); | |||
|         exit(-1); | |||
|     } | |||
|     interface_count = configdesc->bNumInterfaces; | |||
|     for (i = 0; i < interface_count; i++) { | |||
|         if (libusb_kernel_driver_active(handle, i)) { | |||
|             status = libusb_detach_kernel_driver(handle, i); | |||
|             if (status != 0) { | |||
|                 perror("libusb_detach_kernel_driver"); | |||
|                 libusb_free_config_descriptor(configdesc); | |||
|                 libusb_close(handle); | |||
|                 libusb_free_device_list(list, 1); | |||
|                 libusb_exit(context); | |||
|                 exit(-1); | |||
|             } | |||
|         } | |||
|     } | |||
|     libusb_free_config_descriptor(configdesc); | |||
|     // Définir la configuration | |||
|     status = libusb_set_configuration(handle, 1); | |||
|     if (status != 0) { | |||
|         perror("libusb_set_configuration"); | |||
|         libusb_close(handle); | |||
|         libusb_free_device_list(list, 1); | |||
|         libusb_exit(context); | |||
|         exit(-1); | |||
|     } | |||
|     // Revendiquer toutes les interfaces | |||
|     for (i = 0; i < interface_count; i++) { | |||
|         status = libusb_claim_interface(handle, i); | |||
|         if (status != 0) { | |||
|             perror("libusb_claim_interface"); | |||
|             libusb_close(handle); | |||
|             libusb_free_device_list(list, 1); | |||
|             libusb_exit(context); | |||
|             exit(-1); | |||
|         } | |||
|     } | |||
|     // Envoi de données au périphérique | |||
|     int endpoint_out = 0x02; | |||
|     int bytes_out; | |||
|     unsigned char message; | |||
|     for (int j = 0; j < 10; j++) { | |||
|         scanf("%hhu", &message); | |||
|         printf("Vous avez envoyé %hhu\n", message); | |||
|         status = libusb_interrupt_transfer(handle, endpoint_out, &message, sizeof(message), &bytes_out, 0); | |||
|         if (status == 0) { | |||
|             printf("%d octets envoyés avec succès\n", bytes_out); | |||
|         } else { | |||
|             perror("libusb_interrupt_transfer"); | |||
|             for (i = 0; i < interface_count; i++) { | |||
|                 libusb_release_interface(handle, i); | |||
|             } | |||
|             libusb_close(handle); | |||
|             libusb_free_device_list(list, 1); | |||
|             libusb_exit(context); | |||
|             exit(-1); | |||
|         } | |||
|     } | |||
|     // Libération de toutes les interfaces et fermeture du périphérique | |||
|     for (i = 0; i < interface_count; i++) { | |||
|         libusb_release_interface(handle, i); | |||
|     } | |||
|     libusb_close(handle); | |||
|     libusb_free_device_list(list, 1); | |||
|     libusb_exit(context); | |||
|     return 0; | |||
| } | |||
| </syntaxhighlight> | |||
| | | |||
| <syntaxhighlight lang="c"> | |||
| #include "Descriptors.h" | |||
| const USB_Descriptor_HIDReport_Datatype_t PROGMEM JoystickReport[] = | |||
| { | |||
| 	HID_RI_USAGE_PAGE(8, 0x01), /* Generic Desktop */ | |||
| 	HID_RI_USAGE(8, 0x04), /* Joystick */ | |||
| 	HID_RI_COLLECTION(8, 0x01), /* Application */ | |||
| 		HID_RI_USAGE(8, 0x01), /* Pointer */ | |||
| 		HID_RI_COLLECTION(8, 0x00), /* Physical */ | |||
| 			HID_RI_USAGE(8, 0x30), /* Usage X */ | |||
| 			HID_RI_USAGE(8, 0x31), /* Usage Y */ | |||
| 			//HID_RI_USAGE(8, 0x32), /* Usage Z */ EN COMMENTAIRE POUR NE PAS AVOIR D'AXE Z | |||
| 			HID_RI_LOGICAL_MINIMUM(8, -100), | |||
| 			HID_RI_LOGICAL_MAXIMUM(8, 100), | |||
| 			HID_RI_PHYSICAL_MINIMUM(8, -1), | |||
| 			HID_RI_PHYSICAL_MAXIMUM(8, 1), | |||
| 			HID_RI_REPORT_COUNT(8, 0x03), | |||
| 			HID_RI_REPORT_SIZE(8, 0x08), | |||
| 			HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), | |||
| 		HID_RI_END_COLLECTION(0), | |||
| 		HID_RI_USAGE_PAGE(8, 0x09), /* Button */ | |||
| 		HID_RI_USAGE_MINIMUM(8, 0x01), | |||
| 		HID_RI_USAGE_MAXIMUM(8, 0x02), | |||
| 		HID_RI_LOGICAL_MINIMUM(8, 0x00), | |||
| 		HID_RI_LOGICAL_MAXIMUM(8, 0x01), | |||
| 		HID_RI_REPORT_SIZE(8, 0x01), | |||
| 		HID_RI_REPORT_COUNT(8, 0x02), | |||
| 		HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), | |||
| 		HID_RI_REPORT_SIZE(8, 0x06), | |||
| 		HID_RI_REPORT_COUNT(8, 0x01), | |||
| 		HID_RI_INPUT(8, HID_IOF_CONSTANT), | |||
| 	HID_RI_END_COLLECTION(0), | |||
| }; | |||
| const USB_Descriptor_Device_t PROGMEM DeviceDescriptor = | |||
| { | |||
| 	.Header                 = {.Size = sizeof(USB_Descriptor_Device_t), .Type = DTYPE_Device}, | |||
| 	.USBSpecification       = VERSION_BCD(1,1,0), | |||
| 	.Class                  = USB_CSCP_NoDeviceClass, | |||
| 	.SubClass               = USB_CSCP_NoDeviceSubclass, | |||
| 	.Protocol               = USB_CSCP_NoDeviceProtocol, | |||
| 	.Endpoint0Size          = FIXED_CONTROL_ENDPOINT_SIZE, | |||
| 	.VendorID               = 0x054c, | |||
| 	.ProductID              = 0x05c4, | |||
| 	.ReleaseNumber          = VERSION_BCD(0,0,1), | |||
| 	.ManufacturerStrIndex   = STRING_ID_Manufacturer, | |||
| 	.ProductStrIndex        = STRING_ID_Product, | |||
| 	.SerialNumStrIndex      = NO_DESCRIPTOR, | |||
| 	.NumberOfConfigurations = FIXED_NUM_CONFIGURATIONS | |||
| }; | |||
| const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor = | |||
| { | |||
| 	.Config = | |||
| 		{ | |||
| 			.Header                 = {.Size = sizeof(USB_Descriptor_Configuration_Header_t), .Type = DTYPE_Configuration}, | |||
| 			.TotalConfigurationSize = sizeof(USB_Descriptor_Configuration_t), | |||
| 			.TotalInterfaces        = 2, | |||
| 			.ConfigurationNumber    = 1, | |||
| 			.ConfigurationStrIndex  = NO_DESCRIPTOR, | |||
| 			.ConfigAttributes       = (USB_CONFIG_ATTR_RESERVED | USB_CONFIG_ATTR_SELFPOWERED), | |||
| 			.MaxPowerConsumption    = USB_CONFIG_POWER_MA(100) | |||
| 		}, | |||
| 	.HID_Interface = | |||
| 		{ | |||
| 			.Header                 = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface}, | |||
| 			.InterfaceNumber        = INTERFACE_ID_Joystick, | |||
| 			.AlternateSetting       = 0x00, | |||
| 			.TotalEndpoints         = 1, | |||
| 			.Class                  = HID_CSCP_HIDClass, | |||
| 			.SubClass               = HID_CSCP_NonBootSubclass, | |||
| 			.Protocol               = HID_CSCP_NonBootProtocol, | |||
| 			.InterfaceStrIndex      = NO_DESCRIPTOR | |||
| 		}, | |||
| 	.HID_JoystickHID = | |||
| 		{ | |||
| 			.Header                 = {.Size = sizeof(USB_HID_Descriptor_HID_t), .Type = HID_DTYPE_HID}, | |||
| 			.HIDSpec                = VERSION_BCD(1,1,1), | |||
| 			.CountryCode            = 0x00, | |||
| 			.TotalReportDescriptors = 1, | |||
| 			.HIDReportType          = HID_DTYPE_Report, | |||
| 			.HIDReportLength        = sizeof(JoystickReport) | |||
| 		}, | |||
| 	.HID_ReportINEndpoint = | |||
| 		{ | |||
| 			.Header                 = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint}, | |||
| 			.EndpointAddress        = JOYSTICK_EPADDR, | |||
| 			.Attributes             = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA), | |||
| 			.EndpointSize           = JOYSTICK_EPSIZE, | |||
| 			.PollingIntervalMS      = 0x05 | |||
| 		}, | |||
| 	.LED_Interface = | |||
| 		{ | |||
| 			.Header                 = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface}, | |||
| 			.InterfaceNumber        = INTERFACE_ID_LED, | |||
| 			.AlternateSetting       = 0x00, | |||
| 			.TotalEndpoints         = 1, | |||
| 			.Class                  = USB_CSCP_VendorSpecificClass, | |||
| 			.SubClass               = USB_CSCP_VendorSpecificSubclass, | |||
| 			.Protocol               = USB_CSCP_VendorSpecificProtocol, | |||
| 			.InterfaceStrIndex      = NO_DESCRIPTOR | |||
| 		}, | |||
| 		.LED_OUTEndpoint = | |||
| 		{ | |||
| 			.Header                 = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint}, | |||
| 			.EndpointAddress        = LED_OUT_EPADDR, | |||
| 			.Attributes             = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA), | |||
| 			.EndpointSize           = EPSIZE, | |||
| 			.PollingIntervalMS      = 0x05 | |||
| 		}, | |||
| }; | |||
| uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, | |||
|                                     const uint16_t wIndex, | |||
|                                     const void** const DescriptorAddress) | |||
| { | |||
| 	const uint8_t  DescriptorType   = (wValue >> 8); | |||
| 	const uint8_t  DescriptorNumber = (wValue & 0xFF); | |||
| 	const void* Address = NULL; | |||
| 	uint16_t    Size    = NO_DESCRIPTOR; | |||
| 	switch (DescriptorType) | |||
| 	{ | |||
| 		case DTYPE_Device: | |||
| 			Address = &DeviceDescriptor; | |||
| 			Size    = sizeof(USB_Descriptor_Device_t); | |||
| 			break; | |||
| 		case DTYPE_Configuration: | |||
| 			Address = &ConfigurationDescriptor; | |||
| 			Size    = sizeof(USB_Descriptor_Configuration_t); | |||
| 			break; | |||
| 		case DTYPE_String: | |||
| 			switch (DescriptorNumber) | |||
| 			{ | |||
| 				case STRING_ID_Language: | |||
| 					Address = &LanguageString; | |||
| 					Size    = pgm_read_byte(&LanguageString.Header.Size); | |||
| 					break; | |||
| 				case STRING_ID_Manufacturer: | |||
| 					Address = &ManufacturerString; | |||
| 					Size    = pgm_read_byte(&ManufacturerString.Header.Size); | |||
| 					break; | |||
| 				case STRING_ID_Product: | |||
| 					Address = &ProductString; | |||
| 					Size    = pgm_read_byte(&ProductString.Header.Size); | |||
| 					break; | |||
| 			} | |||
| 			break; | |||
| 		case DTYPE_HID: | |||
| 			Address = &ConfigurationDescriptor.HID_JoystickHID; | |||
| 			Size    = sizeof(USB_HID_Descriptor_HID_t); | |||
| 			break; | |||
| 		case DTYPE_Report: | |||
| 			Address = &JoystickReport; | |||
| 			Size    = sizeof(JoystickReport); | |||
| 			break; | |||
| 	} | |||
| 	*DescriptorAddress = Address; | |||
| 	return Size; | |||
| } | |||
| </syntaxhighlight> | |||
| |} | |||
| === Code pour le jeu (théorique) === | |||
| Malgré quelques problèmes rencontrés, nous souhaitons quand même offrir quelques codes auxquels nous avons pensé pour l'intégration dans le jeu | |||
| Initialisation et Check des vies pour l'allumage des LEDs. Nous avons 4 vies dans notre jeu. La fonction LEDStates allume ou éteint (0 ou 1 en paramètres) la LEDs i en paramètre.<syntaxhighlight lang="c"> | |||
| void displayVieLEDS(libusb_device *controleur, libusb_device_handle *handle, | |||
|                     struct libusb_config_descriptor *configdesc, int vies) | |||
| { | |||
|    for(int i = 0; i<vie;i++)  | |||
|    { | |||
|      LEDStates(1,i,manette,handle,configdesc); | |||
|    } | |||
|    for(int i = vies; i<4;i++) | |||
|    { | |||
|      LEDStates(0,i,manette,handle,configdesc); | |||
|    } | |||
| } | |||
| </syntaxhighlight>Initialisation des boutons et des axes de déplacements in-game<syntaxhighlight lang="c"> | |||
| void ControlDeVaisseauManette(SDL_Joystick* p_Joytsick, int *button1, int *button2, int *axe_x, int *axe_y) | |||
| { | |||
|     SDL_JoystickUpdate();  | |||
|     *axe_x = SDL_JoystickGetAxis(p_Joytsick,0); | |||
|     *axe_y = SDL_JoystickGetAxis(p_Joytsick,1); | |||
|     *button1 = SDL_JoystickGetBUtton(p_Joytsick,0); | |||
|     *button2 = SDL_JoystickGetBUtton(p_Joytsick,1); | |||
| } | |||
| </syntaxhighlight>Gestion des évènements claviers et manette<syntaxhighlight lang="c"> | |||
| void gestion_event(evenement* ev1, | |||
|                    char* touch1, | |||
|                    entite_t* vaisseau, | |||
|                    entite_t* Missile, | |||
|                    listentite* List2Missile, | |||
|                    int* compteurMissile, | |||
|                    int axe_x, | |||
|                    int bouton1) //gère les évènements claviers et fais une action en conséquence | |||
| { | |||
|       if((((*ev1==toucheBas) && | |||
|         (*touch1 == 'q')) || (axe_x <-100)) && | |||
|         (vaisseau->x >= 0)) // déplacement gauche du vaisseau par l'utilisateur et vérification que l'utlisateur ne dépasse pas l'écran | |||
|       { | |||
|         deplacement_entite(vaisseau,-VITESSE_VAISSEAU,0); | |||
|       } | |||
|       if((((*ev1==toucheBas) && | |||
|         (*touch1 == 'd')) || (axe_x > 100)) && | |||
|         (vaisseau->taillex <= SCREEN_WIDTH)) //déplacement droite du vaisseau par l'utilisateur et vérification que l'utlisateur ne dépasse pas l'écran | |||
|       { | |||
|         deplacement_entite(vaisseau,VITESSE_VAISSEAU,0); | |||
|       } | |||
| if((((*ev1==toucheBas) | |||
|         && ((*touch1 == 'z') || (*touch1 == 's'))) || (bouton2 == 1))  | |||
|         && (*compteurMissile==0)) //tir du vaisseau quand la touche s ou z est pressé et que le canon du vaisseau est eu le temps de refroidir du tir précédent (cooldown_blast) | |||
|       { | |||
|         Missile->x = vaisseau->x+18; | |||
|         Missile->y = vaisseau->y-18; | |||
|         Missile->vie = 1; | |||
|         int largeurMissile,hauteurMissile; | |||
|         tailleLutin(Missile->numsprite,&largeurMissile,&hauteurMissile); | |||
|         Missile->taillex = Missile->x + largeurMissile; | |||
|         Missile->tailley = Missile->y + hauteurMissile; | |||
|         addhead(*Missile,List2Missile); | |||
|         *compteurMissile=30; | |||
|       } | |||
| } | |||
| </syntaxhighlight> | |||
| == ''VIDÉOS PRÉSENTATIONS'' == | |||
| Communication entre Ordinateur et les LEDs sur la manette. On rentre des chiffres dans le terminal et certaines LEDs D2, D3, D4 et D5 s'allument ou s'éteignent en fonction. | |||
| On mettra de côté le fait que la luminosité des LED est très faible. (: | |||
| [[Fichier:LUFA LED PC.mp4|néant|vignette|Vidéo montrant les LEDs allumés en fonction de ce que l'on fait sur l'ordinateur]] | |||
| Jeu avec Manette sans les LEDs de vie (pour adapter le jeu on se base sur ce tutoriel: https://alexandre-laurent.developpez.com/tutoriels/sdl/joysticks/)[[Fichier:Video SpaceInvaders manette.mp4|néant|vignette|Vidéo montrant l'interaction entre la manette et le Space Invaders sans les LEDs pour les vies]]Jeu avec Manette complète. Sur la croix directionnelle, le bouton de gauche déplace à gauche le vaisseau, le droit déplace à droite. Les boutons haut et bas ne servent à rien pour notre projet. Les boutons sur la droite, celui en bas permet de tirer et celui du haut de quitter. | |||
| == ''PROBLÈMES RENCONTRÉS'' == | |||
| Bien que nous ayons réussi à simuler notre joystick via les 4 boutons directionnels et les 2 boutons d'action, et que nous ayons réussi en parallèle à communiquer avec la manette grâce à libusb et à allumer des LEDs sur commande, l'étape de la fusion de ces deux programmes LUFA ne s'est pas bien passée ... | |||
| =<div class="mcwiki-header" style="border-radius: 40px; padding: 15px; font-weight: bold; color: #FFFFFF; text-align: center; font-size: 80%; background: #ED254E; vertical-align: top; width: 98%;"> CONCLUSION ? </div>= | |||
| Nous avons réussi à concevoir et jouer avec la manette au SpaceInvaders et nous avons réussi à contrôler les LEDs grâce à l'ordinateur. Malheureusement, dû à un bug/problèmes que nous n'arrivons pas à corriger à temps, il n'est pas possible de jouer au SpaceInvaders avec les LEDs contrôlées par libusb mais il est possible de jouer au jeu avec les contrôles de tir et de déplacement sans les LEDs. | |||
| ==  | =<div class="mcwiki-header" style="border-radius: 40px; padding: 15px; font-weight: bold; color: #FFFFFF; text-align: center; font-size: 80%; background: #ED254E; vertical-align: top; width: 98%;"> Archive </div>= | ||
| == ''FICHIERS'' == | |||
| Fichiers: [[Fichier:ManetteUSBLilianPierre.zip]] | Fichiers: [[Fichier:ManetteUSBLilianPierre.zip]] | ||
| Ligne 114 : | Ligne 690 : | ||
| gerber: Fichiers: [[Fichier:SE3-pad-LGPC.zip]] | gerber: Fichiers: [[Fichier:SE3-pad-LGPC.zip]] | ||
| == GIT == | == ''GIT'' == | ||
| GiT Manette :  https://archives.plil.fr/lgrevin/TPI_LUFA_LibUSB.git | |||
Version actuelle datée du 17 juin 2024 à 16:09
 Conception de la manette
DESIGN, LIMITES, FONCTIONNALITÉS ET DESCRIPTION DE LA MANETTE
Ce projet a pour but de développer une manette capable jouer et interagir avec le jeu "Space Invaders" réalisé lors du projet informatique avec Monsieur DEQUIDT et Monsieur FORGET.
- Taille de la carte : 10x10 cm maximum
- Fonctionne en 5V
- Utilisation de LEDs pour visualiser les vies restantes sur la manette
- 6 boutons : 4 de déplacement mais que deux utilisables (gauche et droite) et les deux autres (haut et bas) pour d'autres jeux à l'avenir. Les deux boutons à droite de la carte, en bas pour tirer, en haut pour quitter.
- Le design de la forme de la manette est inspiré d'une vieille manette de SNES
SCHÉMATIQUE KiCAD
PCB et BRASURE
 Programmation 
CODE C
Pour pouvoir avoir nos boutons fonctionnel on s'est basé sur la démo du joystick pour créer "Manette", et ensuite on est partie d'un code minimal pour pouvoir rajouté la description de notre manette, et créer deux interfaces, une pour nos boutons, et une autre pour nos LEDs.
Fonctions importantes et descriptions des codes
| Descriptor de notre code Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               1.10
  bDeviceClass            0
  bDeviceSubClass         0
  bDeviceProtocol         0
  bMaxPacketSize0         8
  idVendor           0x054c Sony Corp. 
  idProduct          0x05c4 DualShock 4 Demo Application
  bcdDevice            0.01
  iManufacturer           1 LUFA Library
  iProduct                2 LUFA Joystick Demo
  iSerial                 0
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength       0x0032
    bNumInterfaces          2
    bConfigurationValue     1
		iConfiguration          0
    bmAttributes         0xc0
      Self Powered
    MaxPower              100mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           1
      bInterfaceClass         3 Human Interface Device
      bInterfaceSubClass      0
      bInterfaceProtocol      0
      iInterface              0
        HID Device Descriptor:
          bLength                 9
          bDescriptorType        33
          bcdHID               1.11
          bCountryCode            0 Not supported
          bNumDescriptors         1
          bDescriptorType        34 Report
          wDescriptorLength      52
         Report Descriptors:
           ** UNAVAILABLE **
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0008  1x 8 bytes
        bInterval               5
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        1
      bAlternateSetting       0
      bNumEndpoints           1
      bInterfaceClass       255 Vendor Specific Class
      bInterfaceSubClass    255 Vendor Specific Subclass
      bInterfaceProtocol    255 Vendor Specific Protocol
      iInterface              0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x02  EP 2 OUT
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0008  1x 8 bytes
        bInterval               5 | Manette et minimal trouvable dans TPI_LUFA_LibUSB/manette_LUFA/Polytech/ | |
| Code définissant les conditions de nos boutons. Quels boutons fait quoi et à quel moment. bool GetNextReport(USB_JoystickReport_Data_t* const ReportData)
{
	bool           InputChanged     = false;
	memset(ReportData, 0, sizeof(USB_JoystickReport_Data_t));
	if (~(PINF>>PIN7) & 1) ReportData->Button |= (1 << 1);
	if (~(PINF>>PIN6) & 1) ReportData->Button |= (1 << 0);
	if (~(PIND>>PIN1) & 1) ReportData->Y = -100;
	if (~(PIND>>PIN2) & 1) ReportData->X = 100;
	if (~(PIND>>PIN3) & 1) ReportData->X = -100;
	if (~(PIND>>PIN5) & 1) ReportData->Y = 100;
	
	if ((~(PIND>>PIN5) & 1) & (~(PIND>>PIN1) & 1)) ReportData->Y = 0;
	if ((~(PIND>>PIN3) & 1) & (~(PIND>>PIN2) & 1)) ReportData->X = 0;
	InputChanged = 1;
	return InputChanged;
}
Nous avons vérifié ces réglages avec jstest-gtk, un outil permettant de visualiser les directions et les pressions d'un joystick. Tous nos boutons sont détectés et configurés conformément à nos attentes. | Les PIN6 et PIN7 contrôlent les deux boutons sur la droite de la manette. Vous pouvez voir sur la vidéo dans deux sections avant celle-ci quand nous appuyons dessus les cases "0" et "1" deviennent noires quand nous appuyons sur les boutons | |
| Code définissant Les PORTx et DDRx de notre manette. 	/* Hardware Initialization */
	Joystick_Init();
	LEDs_Init();
	Buttons_Init();
	USB_Init();
	MCUCR |= (1<<JTD);
	MCUCR |= (1<<JTD);
	CLKSEL0 = 0b00010101;   // sélection de l'horloge externe
	CLKSEL1 = 0b00001111;   // minimum de 8Mhz
	CLKPR = 0b10000000;     // modification du diviseur d'horloge (CLKPCE=1)
	CLKPR = 0;              // 0 pour pas de diviseur (diviseur de 1)
	//Boutons A et B
	DDRF  &= 0b00111111;
	PORTF |= 0b11000000;
	
	//Boutons directionnels 
	DDRD  &= 0b11010001;
	PORTD |= 0b00101110;
	// Allumer les leds
	PORTF |= 0b00100011;
	PORTE |= 0b01000000;
 | En modifiant le code LUFA donné par le prof, on peut allumer les LEDs, pour celles sur les pins PF0, PF1 et PF5 il faut désactiver le JTAG en copiant deux fois cette ligne au niveau de la déclaration des pins : MCUCR |= (1<<JTD); En ce qui concerne les LEDs sur PORTE et PORTD, il n'y a pas de problème dessus. | |
| Code permettant de contrôler les LEDs en entrant des chiffres dans le terminal | 
| void USB_OUT_PointManagement(void)
{
  uint8_t c = 0;
  Endpoint_SelectEndpoint(LED_OUT_EPADDR);
  if (Endpoint_IsOUTReceived())
  {
    if (Endpoint_IsReadWriteAllowed())
    {
      c = Endpoint_Read_8();
      if (c != 0) {
        	PORTF |= 0b00100011;
	        PORTE |= 0b01000000;
      }
      else{
        	PORTF &= 0b11011100;
	        PORTE &= 0b10111111;
      }
      if (c & 0b00000001)
        PORTF |= 0b00000001; // LED 1 ON
      else
        PORTF &= ~0b00000001; // LED 1 OFF
      if (c & 0b00000010)
        PORTF |= 0b00000010; // LED 2 ON
      else
        PORTF &= ~0b00000010; // LED 2 OFF
      if (c & 0b00000100)
        PORTF |= 0b00010000; // LED 3 ON
      else
        PORTF &= ~0b00100000; // LED 3 OFF
      if (c & 0b00001000)
        PORTE |= 0b01000000; // LED 4 ON
      else
        PORTE &= ~0b01000000; // LED 4 OFF
    }
    
    Endpoint_ClearOUT();
  }
}
 | 
Codes complets
| Le code ci-dessous présente le code libusb.c permettant de faire la communication entre le PC et la manette. C'est ce qui nous permet d'envoyer des bits d'informations par le biais du terminal CMD qui allumeront certaines LEDs. Vous pouvez voir cet exemple sur la vidéo dans la section VIDÉOS DE PRÉSENTATIONS. | Ceci est le Decriptor.c de notre code Fusion qui permet d'utiliser les boutons pour jouer et que le PC puisse envoyer les informations à la manette. Il crée les interfaces nécessaires pour la bonne utilisation des LEDs et des boutons de jeu. | 
| #include <stdio.h>
#include <stdlib.h>
#include <libusb-1.0/libusb.h>
#define VENDOR_ID 0x054c
#define PRODUCT_ID 0x05c4
int main(void) {
    // Initialisation de la bibliothèque
    libusb_context *context;
    int status = libusb_init(&context);
    if (status != 0) {
        perror("libusb_init");
        exit(-1);
    }
    // Énumération des périphériques USB
    libusb_device **list;
    ssize_t count = libusb_get_device_list(context, &list);
    if (count < 0) {
        perror("libusb_get_device_list");
        libusb_exit(context);
        exit(-1);
    }
    // Recherche du périphérique avec le VENDOR_ID et PRODUCT_ID spécifiés
    libusb_device *device = NULL;
    for (ssize_t i = 0; i < count; i++) {
        libusb_device *dev = list[i];
        struct libusb_device_descriptor desc;
        int status = libusb_get_device_descriptor(dev, &desc);
        if (status != 0) continue;
        if (desc.idVendor == VENDOR_ID && desc.idProduct == PRODUCT_ID) {
            device = dev;
            break;
        }
    }
    if (device == NULL) {
        printf("Device not found\n");
        libusb_free_device_list(list, 1);
        libusb_exit(context);
        exit(-1);
    }
    // Ouverture du périphérique
    libusb_device_handle *handle;
    status = libusb_open(device, &handle);
    if (status != 0) {
        perror("libusb_open");
        libusb_free_device_list(list, 1);
        libusb_exit(context);
        exit(-1);
    }
    // Détacher les pilotes du noyau pour toutes les interfaces
    struct libusb_config_descriptor *configdesc;
    int interface_count, i;
    status = libusb_get_active_config_descriptor(device, &configdesc);
    if (status != 0) {
        perror("libusb_get_active_config_descriptor");
        libusb_close(handle);
        libusb_free_device_list(list, 1);
        libusb_exit(context);
        exit(-1);
    }
    interface_count = configdesc->bNumInterfaces;
    for (i = 0; i < interface_count; i++) {
        if (libusb_kernel_driver_active(handle, i)) {
            status = libusb_detach_kernel_driver(handle, i);
            if (status != 0) {
                perror("libusb_detach_kernel_driver");
                libusb_free_config_descriptor(configdesc);
                libusb_close(handle);
                libusb_free_device_list(list, 1);
                libusb_exit(context);
                exit(-1);
            }
        }
    }
    libusb_free_config_descriptor(configdesc);
    // Définir la configuration
    status = libusb_set_configuration(handle, 1);
    if (status != 0) {
        perror("libusb_set_configuration");
        libusb_close(handle);
        libusb_free_device_list(list, 1);
        libusb_exit(context);
        exit(-1);
    }
    // Revendiquer toutes les interfaces
    for (i = 0; i < interface_count; i++) {
        status = libusb_claim_interface(handle, i);
        if (status != 0) {
            perror("libusb_claim_interface");
            libusb_close(handle);
            libusb_free_device_list(list, 1);
            libusb_exit(context);
            exit(-1);
        }
    }
    // Envoi de données au périphérique
    int endpoint_out = 0x02;
    int bytes_out;
    unsigned char message;
    for (int j = 0; j < 10; j++) {
        scanf("%hhu", &message);
        printf("Vous avez envoyé %hhu\n", message);
        status = libusb_interrupt_transfer(handle, endpoint_out, &message, sizeof(message), &bytes_out, 0);
        if (status == 0) {
            printf("%d octets envoyés avec succès\n", bytes_out);
        } else {
            perror("libusb_interrupt_transfer");
            for (i = 0; i < interface_count; i++) {
                libusb_release_interface(handle, i);
            }
            libusb_close(handle);
            libusb_free_device_list(list, 1);
            libusb_exit(context);
            exit(-1);
        }
    }
    // Libération de toutes les interfaces et fermeture du périphérique
    for (i = 0; i < interface_count; i++) {
        libusb_release_interface(handle, i);
    }
    libusb_close(handle);
    libusb_free_device_list(list, 1);
    libusb_exit(context);
    return 0;
}
 | #include "Descriptors.h"
const USB_Descriptor_HIDReport_Datatype_t PROGMEM JoystickReport[] =
{
	HID_RI_USAGE_PAGE(8, 0x01), /* Generic Desktop */
	HID_RI_USAGE(8, 0x04), /* Joystick */
	HID_RI_COLLECTION(8, 0x01), /* Application */
		HID_RI_USAGE(8, 0x01), /* Pointer */
		HID_RI_COLLECTION(8, 0x00), /* Physical */
			HID_RI_USAGE(8, 0x30), /* Usage X */
			HID_RI_USAGE(8, 0x31), /* Usage Y */
			//HID_RI_USAGE(8, 0x32), /* Usage Z */ EN COMMENTAIRE POUR NE PAS AVOIR D'AXE Z
			HID_RI_LOGICAL_MINIMUM(8, -100),
			HID_RI_LOGICAL_MAXIMUM(8, 100),
			HID_RI_PHYSICAL_MINIMUM(8, -1),
			HID_RI_PHYSICAL_MAXIMUM(8, 1),
			HID_RI_REPORT_COUNT(8, 0x03),
			HID_RI_REPORT_SIZE(8, 0x08),
			HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE),
		HID_RI_END_COLLECTION(0),
		HID_RI_USAGE_PAGE(8, 0x09), /* Button */
		HID_RI_USAGE_MINIMUM(8, 0x01),
		HID_RI_USAGE_MAXIMUM(8, 0x02),
		HID_RI_LOGICAL_MINIMUM(8, 0x00),
		HID_RI_LOGICAL_MAXIMUM(8, 0x01),
		HID_RI_REPORT_SIZE(8, 0x01),
		HID_RI_REPORT_COUNT(8, 0x02),
		HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE),
		HID_RI_REPORT_SIZE(8, 0x06),
		HID_RI_REPORT_COUNT(8, 0x01),
		HID_RI_INPUT(8, HID_IOF_CONSTANT),
	HID_RI_END_COLLECTION(0),
};
const USB_Descriptor_Device_t PROGMEM DeviceDescriptor =
{
	.Header                 = {.Size = sizeof(USB_Descriptor_Device_t), .Type = DTYPE_Device},
	.USBSpecification       = VERSION_BCD(1,1,0),
	.Class                  = USB_CSCP_NoDeviceClass,
	.SubClass               = USB_CSCP_NoDeviceSubclass,
	.Protocol               = USB_CSCP_NoDeviceProtocol,
	.Endpoint0Size          = FIXED_CONTROL_ENDPOINT_SIZE,
	.VendorID               = 0x054c,
	.ProductID              = 0x05c4,
	.ReleaseNumber          = VERSION_BCD(0,0,1),
	.ManufacturerStrIndex   = STRING_ID_Manufacturer,
	.ProductStrIndex        = STRING_ID_Product,
	.SerialNumStrIndex      = NO_DESCRIPTOR,
	.NumberOfConfigurations = FIXED_NUM_CONFIGURATIONS
};
const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor =
{
	.Config =
		{
			.Header                 = {.Size = sizeof(USB_Descriptor_Configuration_Header_t), .Type = DTYPE_Configuration},
			.TotalConfigurationSize = sizeof(USB_Descriptor_Configuration_t),
			.TotalInterfaces        = 2,
			.ConfigurationNumber    = 1,
			.ConfigurationStrIndex  = NO_DESCRIPTOR,
			.ConfigAttributes       = (USB_CONFIG_ATTR_RESERVED | USB_CONFIG_ATTR_SELFPOWERED),
			.MaxPowerConsumption    = USB_CONFIG_POWER_MA(100)
		},
	.HID_Interface =
		{
			.Header                 = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface},
			.InterfaceNumber        = INTERFACE_ID_Joystick,
			.AlternateSetting       = 0x00,
			.TotalEndpoints         = 1,
			.Class                  = HID_CSCP_HIDClass,
			.SubClass               = HID_CSCP_NonBootSubclass,
			.Protocol               = HID_CSCP_NonBootProtocol,
			.InterfaceStrIndex      = NO_DESCRIPTOR
		},
	.HID_JoystickHID =
		{
			.Header                 = {.Size = sizeof(USB_HID_Descriptor_HID_t), .Type = HID_DTYPE_HID},
			.HIDSpec                = VERSION_BCD(1,1,1),
			.CountryCode            = 0x00,
			.TotalReportDescriptors = 1,
			.HIDReportType          = HID_DTYPE_Report,
			.HIDReportLength        = sizeof(JoystickReport)
		},
	.HID_ReportINEndpoint =
		{
			.Header                 = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint},
			.EndpointAddress        = JOYSTICK_EPADDR,
			.Attributes             = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
			.EndpointSize           = JOYSTICK_EPSIZE,
			.PollingIntervalMS      = 0x05
		},
	
	.LED_Interface =
		{
			.Header                 = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface},
			.InterfaceNumber        = INTERFACE_ID_LED,
			.AlternateSetting       = 0x00,
			.TotalEndpoints         = 1,
			.Class                  = USB_CSCP_VendorSpecificClass,
			.SubClass               = USB_CSCP_VendorSpecificSubclass,
			.Protocol               = USB_CSCP_VendorSpecificProtocol,
			.InterfaceStrIndex      = NO_DESCRIPTOR
		},
		.LED_OUTEndpoint =
		{
			.Header                 = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint},
			.EndpointAddress        = LED_OUT_EPADDR,
			.Attributes             = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
			.EndpointSize           = EPSIZE,
			.PollingIntervalMS      = 0x05
		},
};
uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue,
                                    const uint16_t wIndex,
                                    const void** const DescriptorAddress)
{
	const uint8_t  DescriptorType   = (wValue >> 8);
	const uint8_t  DescriptorNumber = (wValue & 0xFF);
	const void* Address = NULL;
	uint16_t    Size    = NO_DESCRIPTOR;
	switch (DescriptorType)
	{
		case DTYPE_Device:
			Address = &DeviceDescriptor;
			Size    = sizeof(USB_Descriptor_Device_t);
			break;
		case DTYPE_Configuration:
			Address = &ConfigurationDescriptor;
			Size    = sizeof(USB_Descriptor_Configuration_t);
			break;
		case DTYPE_String:
			switch (DescriptorNumber)
			{
				case STRING_ID_Language:
					Address = &LanguageString;
					Size    = pgm_read_byte(&LanguageString.Header.Size);
					break;
				case STRING_ID_Manufacturer:
					Address = &ManufacturerString;
					Size    = pgm_read_byte(&ManufacturerString.Header.Size);
					break;
				case STRING_ID_Product:
					Address = &ProductString;
					Size    = pgm_read_byte(&ProductString.Header.Size);
					break;
			}
			break;
		case DTYPE_HID:
			Address = &ConfigurationDescriptor.HID_JoystickHID;
			Size    = sizeof(USB_HID_Descriptor_HID_t);
			break;
		case DTYPE_Report:
			Address = &JoystickReport;
			Size    = sizeof(JoystickReport);
			break;
	}
	*DescriptorAddress = Address;
	return Size;
}
 | 
Code pour le jeu (théorique)
Malgré quelques problèmes rencontrés, nous souhaitons quand même offrir quelques codes auxquels nous avons pensé pour l'intégration dans le jeu
Initialisation et Check des vies pour l'allumage des LEDs. Nous avons 4 vies dans notre jeu. La fonction LEDStates allume ou éteint (0 ou 1 en paramètres) la LEDs i en paramètre.
void displayVieLEDS(libusb_device *controleur, libusb_device_handle *handle,
                    struct libusb_config_descriptor *configdesc, int vies)
{
   for(int i = 0; i<vie;i++) 
   {
     LEDStates(1,i,manette,handle,configdesc);
   }
   for(int i = vies; i<4;i++)
   {
     LEDStates(0,i,manette,handle,configdesc);
   }
}
Initialisation des boutons et des axes de déplacements in-game
void ControlDeVaisseauManette(SDL_Joystick* p_Joytsick, int *button1, int *button2, int *axe_x, int *axe_y)
{
    SDL_JoystickUpdate(); 
    *axe_x = SDL_JoystickGetAxis(p_Joytsick,0);
    *axe_y = SDL_JoystickGetAxis(p_Joytsick,1);
    *button1 = SDL_JoystickGetBUtton(p_Joytsick,0);
    *button2 = SDL_JoystickGetBUtton(p_Joytsick,1);
}
Gestion des évènements claviers et manette
void gestion_event(evenement* ev1,
                   char* touch1,
                   entite_t* vaisseau,
                   entite_t* Missile,
                   listentite* List2Missile,
                   int* compteurMissile,
                   int axe_x,
                   int bouton1) //gère les évènements claviers et fais une action en conséquence
{
      if((((*ev1==toucheBas) &&
        (*touch1 == 'q')) || (axe_x <-100)) &&
        (vaisseau->x >= 0)) // déplacement gauche du vaisseau par l'utilisateur et vérification que l'utlisateur ne dépasse pas l'écran
      {
        deplacement_entite(vaisseau,-VITESSE_VAISSEAU,0);
      }
      if((((*ev1==toucheBas) &&
        (*touch1 == 'd')) || (axe_x > 100)) &&
        (vaisseau->taillex <= SCREEN_WIDTH)) //déplacement droite du vaisseau par l'utilisateur et vérification que l'utlisateur ne dépasse pas l'écran
      {
        deplacement_entite(vaisseau,VITESSE_VAISSEAU,0);
      }
if((((*ev1==toucheBas)
        && ((*touch1 == 'z') || (*touch1 == 's'))) || (bouton2 == 1)) 
        && (*compteurMissile==0)) //tir du vaisseau quand la touche s ou z est pressé et que le canon du vaisseau est eu le temps de refroidir du tir précédent (cooldown_blast)
      {
        Missile->x = vaisseau->x+18;
        Missile->y = vaisseau->y-18;
        Missile->vie = 1;
        int largeurMissile,hauteurMissile;
        tailleLutin(Missile->numsprite,&largeurMissile,&hauteurMissile);
        Missile->taillex = Missile->x + largeurMissile;
        Missile->tailley = Missile->y + hauteurMissile;
        addhead(*Missile,List2Missile);
        *compteurMissile=30;
      }
}
VIDÉOS PRÉSENTATIONS
Communication entre Ordinateur et les LEDs sur la manette. On rentre des chiffres dans le terminal et certaines LEDs D2, D3, D4 et D5 s'allument ou s'éteignent en fonction.
On mettra de côté le fait que la luminosité des LED est très faible. (:
Jeu avec Manette sans les LEDs de vie (pour adapter le jeu on se base sur ce tutoriel: https://alexandre-laurent.developpez.com/tutoriels/sdl/joysticks/)
Jeu avec Manette complète. Sur la croix directionnelle, le bouton de gauche déplace à gauche le vaisseau, le droit déplace à droite. Les boutons haut et bas ne servent à rien pour notre projet. Les boutons sur la droite, celui en bas permet de tirer et celui du haut de quitter.
PROBLÈMES RENCONTRÉS
Bien que nous ayons réussi à simuler notre joystick via les 4 boutons directionnels et les 2 boutons d'action, et que nous ayons réussi en parallèle à communiquer avec la manette grâce à libusb et à allumer des LEDs sur commande, l'étape de la fusion de ces deux programmes LUFA ne s'est pas bien passée ...
 CONCLUSION ? 
Nous avons réussi à concevoir et jouer avec la manette au SpaceInvaders et nous avons réussi à contrôler les LEDs grâce à l'ordinateur. Malheureusement, dû à un bug/problèmes que nous n'arrivons pas à corriger à temps, il n'est pas possible de jouer au SpaceInvaders avec les LEDs contrôlées par libusb mais il est possible de jouer au jeu avec les contrôles de tir et de déplacement sans les LEDs.
 Archive 
FICHIERS
Fichiers: Fichier:ManetteUSBLilianPierre.zip
gerber: Fichiers: Fichier:SE3-pad-job.gbrjob.zip gerber: Fichiers: Fichier:SE3-pad-LGPC.zip
GIT
GiT Manette : https://archives.plil.fr/lgrevin/TPI_LUFA_LibUSB.git










