[TERMINÉ] Adaptateur 4 manettes PS/PS2->USB/PC

Salut tout le monde!

Vu que le driver de mon adaptateur de pads PS/PS2 est au fraises (BSOD dès que je branche plus d'une manette) je suis parti dans l'idée de m'en concocter un.
Je développe sur un Teensy 2.0 à l'aide de la bibliothèque PS2X et l'add-on teensyduino.
J'utilise l'objet Joystick implémenté par le teensyduino pour communiquer avec l'ordinateur et jusqu'ici tout fonctionne nickel.

À présent, j'aimerais instancier quatre Joystick pour que l'ordinateur reconnaisse 4 manettes, ou dans le pire des cas, enrichir l'objet Joystick de sorte que se soit une seule manette qui regroupe les axes et boutons des autres.

J'ai tenté plusieurs choses dans les fichiers de l'USB HID du Teensy: dupliquer tous ce qui avait un rapport avec l'objet Joystick, modifier son Descriptor Data, remplacer le clavier par un joystick, etc. Mais je n'arrive à rien, c'est pourquoi votre aide me serait précieuse.

J'ai attaché les fichiers USB HID au post pour que vous voyez de quoi ça à l'aire et que vous puissiez m'orienter sur la façon de modifier ce fichu USB HID ou me conseiller une autre bibliothèque pour déclarer mon propre joystick hid.

Un grand merci d'avance à celui ou celle qui prendra le temps de jeter un coup d’œil là-dessus.

PS: Les liens vers ce que j'utilise.
PS2X par Bill Porter
Teensyduino
La description de l'objet Joystick

PPS: Je peux aussi copier/coller les codes des différents fichiers si c'est plus simple pour vous.

teensy_usb_hid.zip (14.1 KB)

Est-ce que simplement ton adaptateur de pad ne serait pas simplement en surcharge? une alim externe pour fournir plus de courant résoudrait peut-être la chose?

Ton PC saura-t-il reconnaître plusieurs manettes sur un seul port USB?

Malheureusement ce n'est pas un problème de surcharge. Il fonctionne sans soucis sur un WinXP x86 avec plus d'un pad branché.
C'est le pilote Win7 x64 qui est vraiment pourri. Et pour rajouter une couche, il n'existe pas de version Linux ou Mac.

Donc voilà pourquoi je me lance là dedans (et oui mon pc reconnait plusieurs manettes sur le même port usb, je pense justement que ça se déclare dans le hid).

Bonjour,

Je crois pas qu'il soit possible de créer plusieurs joystick usb sans émuler un hub usb d'abord.
Il faudrait regarder comment teensyduino gère le combo Serial + Mouse + Keyboard.

Sinon regarde du coté de la class "Custom HID" (dans la derniére version de teensyduino) avec tu doit pouvoir créer une liaison teensy <> pc unique transportant les différents signaux des joystick mais il faudra une application pour décoder et émuler les fameux joystick par la suite coté pc (et la je sait pas trop si il est possible d'émuler des joystick ...).

Bonsoir et désolé pour la réponse tardive.

skywodd:
Je crois pas qu'il soit possible de créer plusieurs joystick usb sans émuler un hub usb d'abord.

Bizarre, car ici il déclare plusieurs gamepads dans le HID.

skywodd:
Il faudrait regarder comment teensyduino gère le combo Serial + Mouse + Keyboard.

C'est ce que j'ai attaché au premier post. Dans l'ensemble je comprends comment s'est construit, mais dès que je mets les mains dedans...

skywodd:
Sinon regarde du coté de la class "Custom HID" (dans la derniére version de teensyduino) avec tu doit pouvoir créer une liaison teensy <> pc unique transportant les différents signaux des joystick mais il faudra une application pour décoder et émuler les fameux joystick par la suite coté pc (et la je sait pas trop si il est possible d'émuler des joystick ...).

Tu parles de la "Raw HID" ? Si oui, je suis en train de regarder si il n'y aurait pas moyen d'extraire (et adapter) les lignes du Joystick pour les insérer dedans.

Neit:
Bizarre, car ici il déclare plusieurs gamepads dans le HID.

Je suis bête :. oui la classe HID supporte les collections donc pas besoin de hub, j'étais parti dans l'idée de faire plusieurs endpoints pour simuler plusieurs joystick matériellement séparé (pourquoi faire simple quand on peut faire compliquer :sweat_smile:).

Neit:
Tu parles de la "Raw HID" ? Si oui, je suis en train de regarder si il n'y aurait pas moyen d'extraire (et adapter) les lignes du Joystick pour les insérer dedans.

Avec "Raw HID" tu fait tout toi même, en gros teensyduino n'ajoute aucun extra (souris clavier serial ...) il garde juste l'api arduino classique et les fonctions LUFA, c'est ce qu'il te faut, si tu utilise un autre mode que "Raw HID" tu ne pourra pas choisir le tableau de descripteurs usb, et donc tu ne pourra pas faire ce que tu veux.

skywodd:
Je suis bête :. oui la classe HID supporte les collections donc pas besoin de hub, j'étais parti dans l'idée de faire plusieurs endpoints pour simuler plusieurs joystick matériellement séparé (pourquoi faire simple quand on peut faire compliquer :sweat_smile:).

C'était aussi mon idée de départ mais je galérais pas mal, puis je suis tombé sur cette page :).

Sinon, j'ai réussi à modifier le "Raw HID" (j'ai remplacé le Raw par le Joystick du "Keyboard + Mouse + Joystick" et conservé le Serial pour le debugging).
Avant de m'attaquer à la modification du Joystick j'aurais quelques petites questions si tu veux bien :blush:

dans l'usb.c
• Dans la fonction usb_init, des valeurs sont attribuées à chaque case du tableau joystick_report_data, à quoi correspondent-elles ? Initialisation de valeurs par défaut ?

// initialize USB serial
void usb_init(void)
{
	uint8_t u;

	u = USBCON;
	if ((u & (1<<USBE)) && !(u & (1<<FRZCLK))) return;
	HW_CONFIG();
        USB_FREEZE();				// enable USB
        PLL_CONFIG();				// config PLL
        while (!(PLLCSR & (1<<PLOCK))) ;	// wait for PLL lock
        USB_CONFIG();				// start USB clock
        UDCON = 0;				// enable attach resistor
	usb_configuration = 0;
	usb_suspended = 0;
	debug_flush_timer = 0;

	joystick_report_data[0] = 0;
	joystick_report_data[1] = 0;
	joystick_report_data[2] = 0;
	joystick_report_data[3] = 0;
	joystick_report_data[4] =  0x0F;
	joystick_report_data[5] =  0x20;
	joystick_report_data[6] =  0x80;
	joystick_report_data[7] =  0x00;
	joystick_report_data[8] =  0x02;
	joystick_report_data[9] =  0x08;
	joystick_report_data[10] = 0x20;
	joystick_report_data[11] = 0x80;

	UDINT = 0;
        UDIEN = (1<<EORSTE)|(1<<SOFE);
	//sei();  // init() in wiring.c does this
}

dans l'usb_private.h
• Comment est calculé la taille de la variable JOYSTICK_SIZE, a-t-elle un lien quelconque avec d'autres déclarations?

#define JOYSTICK_SIZE		16

Je peux t'envoyer mon raw hid modifié au besoin (je n'ai pas pu l'attacher au post, le forum bug pas mal).
Il me reste à étudier comment fonctionne la class usb_joystick_class et ses méthodes, j'espère pouvoir me débrouiller avec la référence arduino.

Merci d'avance pour ton aide :slight_smile:

Neit:
Sinon, j'ai réussi à modifier le "Raw HID" (j'ai remplacé le Raw par le Joystick du "Keyboard + Mouse + Joystick" et conservé le Serial pour le debugging).
Avant de m'attaquer à la modification du Joystick j'aurais quelques petites questions si tu veux bien :blush:

Normalement pour passer en raw hid tu n'as rien à modifier, faut juste sélectionner raw hid comme mode dans le menu teensyduino rien de plus, ensuite tu code to sketch avec l'api LUFA (par contre l'api LUFA je maitrise pas du tout, moi je tourne sous vusb, faudrait que je mis mette à LUFA ... (le serial + mouse + keyboard c'est bien beau 2sec)).

Neit:
• Dans la fonction usb_init, des valeurs sont attribuées à chaque case du tableau joystick_report_data, à quoi correspondent-elles ? Initialisation de valeurs par défaut ?
• Comment est calculé la taille de la variable JOYSTICK_SIZE, a-t-elle un lien quelconque avec d'autres déclarations?

Je pourrai pas te répondre comme ça, faudrait aller voir les tables de descripteurs sur http://www.usb.org/developers/docs/hidpage/ il ont un pdf qui décrit toute les entrées de descripteurs, l'offset, etc ... c'est le truc le plus ch*ant à calculer ... une fois que le tableau de descripteurs et faite le reste c'est juste 3-4 appel d'api ...

Neit:
Il me reste à étudier comment fonctionne la class usb_joystick_class et ses méthodes, j'espère pouvoir me débrouiller avec la référence arduino.

Regarde aussi ici : C code for Teensy: USB Raw HID - for building custom USB devices et sur la page officiel de LUFA, la référence arduino te sera pas d'une grande aide pour la classe usb.

Je vais allez voir si l'api LUFA est vraiment différente de l'api Vusb, à deux on devrai pouvoir calculer un tableau de descripteurs quand même :stuck_out_tongue:

skywodd:
Normalement pour passer en raw hid tu n'as rien à modifier, faut juste sélectionner raw hid comme mode dans le menu teensyduino rien de plus, ensuite tu code to sketch avec l'api LUFA (par contre l'api LUFA je maitrise pas du tout, moi je tourne sous vusb, faudrait que je mis mette à LUFA ... (le serial + mouse + keyboard c'est bien beau 2sec)).

Pareil de mon coté, aucune connaissance du LUFA (c'est aussi mon 1er projet arduino/C/USB).
C'est pour ça que j'aimerais partir sur de l'existant. Là, j'ai remplacé la class rawhid par la joystick, ce qui m'a fais gagner en clarté, poids et compréhension :.
Je peux essayer de partir de zéro si tu penses que c'est la meilleure solution, mais ça va surement prendre beaucoup plus de temps, non?

skywodd:
Je pourrai pas te répondre comme ça, faudrait aller voir les tables de descripteurs sur http://www.usb.org/developers/docs/hidpage/ il ont un pdf qui décrit toute les entrées de descripteurs, l'offset, etc ... c'est le truc le plus ch*ant à calculer ... une fois que le tableau de descripteurs et faite le reste c'est juste 3-4 appel d'api ...

J'ai modifié/re-déclaré le Descriptor Data à l'aide du HID Descriptor Tool et il est bien reconnu par le PC. Par contre, pas moyen de transmettre les infos.
Je pense qu'il faut recalculer la taille du joystick_report_data (défini à 12 avec le joystick par défaut). Là aussi, je ne sais pas comment faire :frowning:

skywodd:
Regarde aussi ici : C code for Teensy: USB Raw HID - for building custom USB devices et sur la page officiel de LUFA, la référence arduino te sera pas d'une grande aide pour la classe usb.

C'était par rapport à la syntaxe C utilisée. La méthode button par exemple, attribue le statut des boutons dans les quatre premières cases du joystick_report_data[12].
Elles contiennent des valeurs en hexa ou chaque bit représente l'état d'un bouton. Si joystick_report_data[0] est égal à 0x05 alors les boutons 1 et 3 sont enfoncés.

skywodd:
Je vais allez voir si l'api LUFA est vraiment différente de l'api Vusb, à deux on devrai pouvoir calculer un tableau de descripteurs quand même :stuck_out_tongue:

C'est vraiment sympa de ta part :smiley:
Je vais aussi regarder de mon coté.
Si tu pouvais néanmoins jeter un coup œil a mon rawhid (téléchargeable ici), je t'en serais très reconnaissant :stuck_out_tongue:

Neit:
Pareil de mon coté, aucune connaissance du LUFA (c'est aussi mon 1er projet arduino/C/USB).
C'est pour ça que j'aimerais partir sur de l'existant. Là, j'ai remplacé la class rawhid par la joystick, ce qui m'a fais gagner en clarté, poids et compréhension :.
Je peux essayer de partir de zéro si tu penses que c'est la meilleure solution, mais ça va surement prendre beaucoup plus de temps, non?

Moi je suis en train de me faire un petit makefile en utilisant uniquement la lib LUFA pour le moment, je vais d'abord regarder les exemples "bruts".
Perso je trouve plus simple de travailler sans arduino avec LUFA du moins jusqu'à ce que ce que je comprennent toute le subtilité de l'api LUFA histoire de ne pas avoir de conflit avec une quelconque sous classe de truc machin héritant de teensyduino.

Neit:
J'ai modifié/re-déclaré le Descriptor Data à l'aide du HID Descriptor Tool et il est bien reconnu par le PC. Par contre, pas moyen de transmettre les infos.
Je pense qu'il faut recalculer la taille du joystick_report_data (défini à 12 avec le joystick par défaut). Là aussi, je ne sais pas comment faire :frowning:

C'était par rapport à la syntaxe C utilisée. La méthode button par exemple, attribue le statut des boutons dans les quatre premières cases du joystick_report_data[12].
Elles contiennent des valeurs en hexa ou chaque bit représente l'état d'un bouton. Si joystick_report_data[0] est égal à 0x05 alors les boutons 1 et 3 sont enfoncés.

Je regarde comment est architecturé l'exemple brute de la lib LUFA et je verrai pour le descriptor/report aprés :wink:

Neit:
http://membres.multimania.fr/skateland00/teensy_usb_rawhid_mod.zip
Si tu pouvais néanmoins jeter un coup œil a mon rawhid (téléchargeable ici), je t'en serais très reconnaissant :stuck_out_tongue:

Je suis en train de DL l'archive je regarde ça ce soir :wink:

Merci c'est super sympa :slight_smile:

Bon j'ai regarder que usb.c parce que le reste c'est du pure usb (même pas du LUFA j'ai l'impression :fearful: on dirait que c'est de la manipulation de registre ...).

Edit: Bon j'ai tenté de faire marcher LUFA avec la teensy ... même l'exemple joystick de base ne marche, j'ai viré tout la partie gestion du joystick matériel pour juste garder la partie usb, rien à faire ...

Franchement je crois que la meilleur solution pour toi c'est le mode "Raw Hid" de teensyduino qui te permettrai d'envoyé 64 octets via l'usb (voir exemple teensy -> raw hid) après faudrait faire un truc coté pc pour émuler les joystick, mais franchement je pense que l'émulation coté pc serait un solution plus simple que l'émulation coté usb ...

Ps: LUFA ... j'ai jamais vu un truc aussi mal documenté ...

"Violent" n'est-ce pas? :cold_sweat:
Merci d'avoir regardé en tous cas.

J'étais déjà passé sur cette page auparavant mais ça ne m'avait pas avancé.
Je la relirai, peut-être que ça va me parler vu que je suis un peux plus avancé dans la compréhension.

Sinon, miracle!
J'ai trouvé à quoi correspondait le "12" du joystick_report_data[12].
C'est les additions de chaque multiplication de report_size et report_count dans le descriptor, le tout divisé par 8 (un octet par case de tableau).

Exemple:

    0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
    0x09, 0x04,                    // USAGE (Joystick)
    0xa1, 0x01,                    // COLLECTION (Application)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
    0x75, 0x01,                    //   REPORT_SIZE (1)
    0x95, 0x20,                    //   REPORT_COUNT (32)                    1*32
    0x05, 0x09,                    //   USAGE_PAGE (Button)
    0x19, 0x01,                    //   USAGE_MINIMUM (Button 1)
    0x29, 0x10,                    //   USAGE_MAXIMUM (Button 16)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x25, 0x07,                    //   LOGICAL_MAXIMUM (7)
    0x35, 0x00,                    //   PHYSICAL_MINIMUM (0)
    0x46, 0x3b, 0x01,              //   PHYSICAL_MAXIMUM (315)
    0x75, 0x04,                    //   REPORT_SIZE (4)
    0x95, 0x01,                    //   REPORT_COUNT (1)                    4*1
    0x65, 0x14,                    //   UNIT (Eng Rot:Angular Pos)
    0x05, 0x01,                    //   USAGE_PAGE (Generic Desktop)
    0x09, 0x39,                    //   USAGE (Hat switch)
    0x81, 0x42,                    //   INPUT (Data,Var,Abs,Null)
    0x05, 0x01,                    //   USAGE_PAGE (Generic Desktop)
    0x09, 0x01,                    //   USAGE (Pointer)
    0xa1, 0x00,                    //   COLLECTION (Physical)
    0x15, 0x00,                    //     LOGICAL_MINIMUM (0)
    0x26, 0xff, 0x03,              //     LOGICAL_MAXIMUM (1023)
    0x75, 0x0a,                    //     REPORT_SIZE (10)
    0x95, 0x04,                    //     REPORT_COUNT (4)                    10*4
    0x09, 0x30,                    //     USAGE (X)
    0x09, 0x31,                    //     USAGE (Y)
    0x09, 0x32,                    //     USAGE (Z)
    0x09, 0x35,                    //     USAGE (Rz)
    0x81, 0x02,                    //     INPUT (Data,Var,Abs)
    0xc0,                          //   END_COLLECTION
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x26, 0xff, 0x03,              //   LOGICAL_MAXIMUM (1023)
    0x75, 0x0a,                    //   REPORT_SIZE (10)
    0x95, 0x02,                    //   REPORT_COUNT (2)                    10*2
    0x09, 0x36,                    //   USAGE (Slider)
    0x09, 0x36,                    //   USAGE (Slider)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0xc0                           // END_COLLECTION

(132 + 41 + 104 + 102)/8 = 12 \o/

Par contre, je ne sais toujours pas pourquoi la JOYSTICK_SIZE dans le usb_private.h est a 16.
Je vais quand même faire un test avec un descriptor de gamepad sans report id ni joysticks pour voir si ça marche :sweat_smile:

Edit: Tu me rassures un peu sur la LUFA, j'avais aussi maté la doc et j'étais pas plus avancé. Message reçu pour le rawhid, je m'y mettrai si j'arrive vraiment à rien avec le joystick du teensy.

PS: Je suppose que si jamais je dois émuler quelque chose sur le PC, je vais devoir développer pour chaque OS sur lequel je voudrais que l'adaptateur tourne!?

Neit:
Edit: Tu me rassures un peu sur la LUFA, j'avais aussi maté la doc et j'étais pas plus avancé. Message reçu pour le rawhid, je m'y mettrai si j'arrive vraiment à rien avec le joystick du teensy.

PS: Je suppose que si jamais je dois émuler quelque chose sur le PC, je vais devoir développer pour chaque OS sur lequel je voudrais que l'adaptateur tourne!?

Bin oui c'est le probléme ... 1 OS = 1 appli :~
Mais bon ça serait la solution de derniers recours.

J'avais trouvé un zip créer par le dev de LUFA qui permettais de gérer 5 joystick avec une teensy 2.0 ... je click ... 404 not found ... :stuck_out_tongue_closed_eyes:
Je vais creuser du coté de vusb peut être que ...

skywodd:
J'avais trouvé un zip créer par le dev de LUFA qui permettais de gérer 5 joystick avec une teensy 2.0 ... je click ... 404 not found ... :stuck_out_tongue_closed_eyes:

Argh comme j'ai espéré sur le moment =(

skywodd:
Je vais creuser du coté de vusb peut être que ...

Ne creuse pas de trop, mon test de gamepad avec juste les 16 boutons s'est montré concluant. Yeah! :stuck_out_tongue_closed_eyes:
Je continue les tests avec report ID puis avec joysticks et enfin quatre gamepads... done!

Edit:
• report id: check.
• plusieurs gamepads: check.
• gestion des sticks analogiques: check.

Voilà, plus que des soudures et un peu d'optimisation logicielle à faire et c'est terminé! :smiley:
Pour ceux que ça intéresserait je peux faire un tuto sur la réalisation de l'adaptateur. Faites le moi savoir en postant ici.
Et merci à toi skywodd pour avoir porté de l'intérêt à mon projet.

Neit:
Ne creuse pas de trop, mon test de gamepad avec juste les 16 boutons s'est montré concluant. Yeah! :stuck_out_tongue_closed_eyes:
Je continue les tests avec report ID puis avec joysticks et enfin quatre gamepads... done!

Edit:
• report id: check.
• plusieurs gamepads: check.
• gestion des sticks analogiques: check.

Voilà, plus que des soudures et un peu d'optimisation logicielle à faire et c'est terminé! :smiley:
Pour ceux que ça intéresserait je peux faire un tuto sur la réalisation de l'adaptateur. Faites le moi savoir en postant ici.
Et merci à toi skywodd pour avoir porté de l'intérêt à mon projet.

Un petit tuto (ou au moins une petite explication) m'intéresserai beaucoup parce que j'aurai pas était d'une grande aide :sweat_smile:

Je te fais un copier/coller d'un autre forum où j'ai posté la démarche pour modifier l'usb hid:

Les fichiers à modifier sont dans : "dossier de l'ide arduino"\hardware\teensy\cores\usb_hid.
Les numéros entre crochets dans les balises code sont les numéros de lignes.

• usb.c
Première chose à modifier, le descriptor data du joystick. Un lien qui m'a bien aidé ici et un outil bien pratique .
Voilà ce que ça donne pour deux gamepads:

[156] static const uint8_t PROGMEM joystick_hid_report_desc[] = {
	0x05, 0x01,					// USAGE_PAGE (Generic Desktop)
	0x09, 0x05,					// USAGE (Game Pad)
	0xa1, 0x01,					// COLLECTION (Application)
	0xa1, 0x00,					//   COLLECTION (Physical)
	0x85, 0x01,					//	 REPORT_ID (1)
	0x05, 0x09,					//	 USAGE_PAGE (Button)
	0x19, 0x01,					//	 USAGE_MINIMUM (Button 1)
	0x29, 0x10,					//	 USAGE_MAXIMUM (Button 16)
	0x15, 0x00,					//	 LOGICAL_MINIMUM (0)
	0x25, 0x01,					//	 LOGICAL_MAXIMUM (1)
	0x95, 0x10,					//	 REPORT_COUNT (16)
	0x75, 0x01,					//	 REPORT_SIZE (1)
	0x81, 0x02,					//	 INPUT (Data,Var,Abs)
	0x05, 0x01,					//	 USAGE_PAGE (Generic Desktop)
	0x09, 0x30,					//	 USAGE (X)
	0x09, 0x31,					//	 USAGE (Y)
	0x09, 0x32,					//	 USAGE (Z)
	0x09, 0x33,					//	 USAGE (Rx)
	0x15, 0x00,					//	 LOGICAL_MINIMUM (0)
	0x26, 0xff, 0x00,				  //	 LOGICAL_MAXIMUM (255)
	0x75, 0x08,					//	 REPORT_SIZE (8)
	0x95, 0x04,					//	 REPORT_COUNT (4)
	0x81, 0x02,					//	 INPUT (Data,Var,Abs)
	0xc0,						  //   END_COLLECTION
	0xc0,						  // END_COLLECTION
	0x05, 0x01,					// USAGE_PAGE (Generic Desktop)
	0x09, 0x05,					// USAGE (Game Pad)
	0xa1, 0x01,					// COLLECTION (Application)
	0xa1, 0x00,					//   COLLECTION (Physical)
	0x85, 0x02,					//	 REPORT_ID (2)
	0x05, 0x09,					//	 USAGE_PAGE (Button)
	0x19, 0x01,					//	 USAGE_MINIMUM (Button 1)
	0x29, 0x10,					//	 USAGE_MAXIMUM (Button 16)
	0x15, 0x00,					//	 LOGICAL_MINIMUM (0)
	0x25, 0x01,					//	 LOGICAL_MAXIMUM (1)
	0x95, 0x10,					//	 REPORT_COUNT (16)
	0x75, 0x01,					//	 REPORT_SIZE (1)
	0x81, 0x02,					//	 INPUT (Data,Var,Abs)
	0x05, 0x01,					//	 USAGE_PAGE (Generic Desktop)
	0x09, 0x30,					//	 USAGE (X)
	0x09, 0x31,					//	 USAGE (Y)
	0x09, 0x32,					//	 USAGE (Z)
	0x09, 0x33,					//	 USAGE (Rx)
	0x15, 0x00,					//	 LOGICAL_MINIMUM (0)
	0x26, 0xff, 0x00,				  //	 LOGICAL_MAXIMUM (255)
	0x75, 0x08,					//	 REPORT_SIZE (8)
	0x95, 0x04,					//	 REPORT_COUNT (4)
	0x81, 0x02,					//	 INPUT (Data,Var,Abs)
	0xc0,						  //   END_COLLECTION
	0xc0						   // END_COLLECTION
}

Maintenant il faut calculer la taille en octets que fait le rapport:
Étant donné que nous déclarons deux gamepads il faut prendre en compte un octet de report id = 1 octet.
Ensuite, il faut multiplier les deux report_count par leur report_size respectif (exprimés en bits) et les additionner. Ce qui nous fait (161 + 84)/8 = 6 octets.
Notre report fait donc 1 + 6 = 7 octets.
Il faut en effet calculer le report pour un seul gamepad car c'est le report id qui définira à quel gamepad le report s'adresse.

À présent, il va falloir modifier les anciennes déclarations de taille du joystick par la nôtre (12 -> 7):
• toujours dans l'usb.c

[364] 7, 0,					// wMaxPacketSize
[460] uint8_t joystick_report_data[7] USBSTATE;
[843] for (i=0; i<7; i++) {

Dans la foulée on va modifier l'attribution des valeurs par défaut du report:

[503] joystick_report_data[0] = 0;		  //report id à changer avant chaque envoi
joystick_report_data[1] = 0;		  //boutons 1 à 8 non enfoncés
joystick_report_data[2] = 0;		  //boutons 9 à 16 non enfoncés
joystick_report_data[3] =  0x7F;   //axe X à 127 (centré)
joystick_report_data[4] =  0x7F;   //axe Y à 127 (centré)
joystick_report_data[5] =  0x7F;   //axe Z à 127 (centré)
joystick_report_data[6] =  0x7F;   //axe Rx à 127 (centré)

Ne pas oublier de supprimer le reste des attributions (joystick_report_data[7] à joystick_report_data[11] car le tableau a été rétréci).
Voilà qui est terminé pour l'usb.c.

• usb_api.cpp
Rendez-vous ligne 348 pour rétrécir les attributions à UEDATX:

[348] UEDATX = joystick_report_data[0];
UEDATX = joystick_report_data[1];
UEDATX = joystick_report_data[2];
UEDATX = joystick_report_data[3];
UEDATX = joystick_report_data[4];
UEDATX = joystick_report_data[5];
UEDATX = joystick_report_data[6];

• usb_api.h

[62] extern uint8_t joystick_report_data[7];

On va aussi modifier les méthodes de l'objet usb_joystick_class. Gardez juste la méthode button et dupliquez une des méthodes qui s'occupe d'un axe. Nous l'utiliseront pour prendre en charge les autres axes du pad playstation (cf. descriptor data).

[64] class usb_joystick_class
{
	public:
	inline void num(uint8_t num) {
   	 joystick_report_data[0] = num;
	}
	inline void button(uint8_t button, bool val) {
		button--;
		uint8_t mask = (1 << (button & 7));
		if (val) {
			if (button < 8) { joystick_report_data[1] |= mask; }
			else if (button < 16) { joystick_report_data[2] |= mask; }
		} else {
			mask = ~mask;
			if (button < 8) { joystick_report_data[1] &= mask; }
			else if (button < 16) { joystick_report_data[2] &= mask; }
		}
		if (!manual_mode) send_now();
	}
	inline void X(uint8_t val) {
		if (val > 255) val = 255;
   	        joystick_report_data[3] = val;
		if (!manual_mode) send_now();
	}
	inline void Y(uint8_t val) {
		if (val > 255) val = 255;
		joystick_report_data[4] = val;
		if (!manual_mode) send_now();
	}
	inline void Z(uint8_t val) {
		if (val > 255) val = 255;
   	        joystick_report_data[5] = val;
		if (!manual_mode) send_now();
	}
	inline void Rx(uint8_t val) {
		if (val > 255) val = 255;
   	        joystick_report_data[6] = val;
		if (!manual_mode) send_now();
	}
	inline void useManualSend(bool mode) {
		manual_mode = mode;
	}
	void send_now(void);
	private:
	//static uint8_t manual_mode;
	uint8_t manual_mode;
};

Une méthode num a été ajoutée, elle va stocker la valeur qu'on lui passera dans le joystick_report_data[0] (cf. le report id).
Deux else if de la méthode button on étés retirés car nos gamepads n'ont que 16 boutons.
Les méthodes des axes ont aussi été modifiées car la bibliothèque PS2X revoie une valeur codée sur un octet (ce qui rend la construction du report_data plus facile).

Pour finir dans usb_private.h

[124] extern uint8_t joystick_report_data[7];

Et le tour est joué!
Il n'y a plus qu'a utiliser l'objet Joystick et ses nouvelles méthodes dans l'IDE Arduino:

Joystick.num(1); //report id a 1 -> on cible le 1er gamepad
Joystick.button(1,1); //le boutton 1 est enfoncé
Joystick.X(0) //stick gauche a gauche
Joystcik.Y(0) //stick gauche en haut
Joystick.Z(255) //stick droit a droite
Joystcik.Rx(255) //stick droit en bas

Voilà voilà.

merci pour l'explication :slight_smile:

Du coup je viens de comprendre ou était mon erreur avec mon prog LUFA, j'avais toujours report_data[0] = 0 donc forcément ça marchait beaucoup moins bien :zipper_mouth_face:

Heureux d'avoir pu t'aider :slight_smile:

J'ai une petite question niveau code.
Pour l'instant j'envoie un report a chaque passage sur un gamepad, ça fonctionne impec.
J'aimerais optimiser le tout pour que lorsque le statut des boutons et axes n'a pas changé depuis le dernier passage (genre inactif), le programme n'envoie pas de report.

J'essaye de retenir le statut des mes boutons et axes dans deux tableaux à deux dimensions comme suit:

const byte numPads = 4;
const byte numButtons = 16;
const byte numAxes = 4;

boolean btnsPad[numPads][numButtons];
byte axesPad[numPads][numAxes];

boolean btnsChanged = false;
boolean axesChanged = false;
byte currentBtn;
byte currentAxe;

Ensuite je teste à chaque itération de i:

(...)
      for (j=0 ; j<numAxes ; j++) {
        switch (j) {
          case 0: currentAxe = listPads[i].Analog(PSS_LX); break;
          ...
        }
        if (axesPad[i][j] != currentAxe) {
          axesChanged = true;
          axesPad[i][j] = currentAxe;
          Gamepad.axe(j,axesPad[i][j]);
        }
      }
(...)
      for (k=0 ; k<numButtons ; k++) {
        switch (k) {
          case 0: currentBtn = listPads[i].Button(PSB_TRIANGLE); break;
          ...
        }
        if (btnsPad[i][k] != currentBtn) {
          btnsChanged = true;
          btnsPad[i][k] = currentBtn;
          Gamepad.button(k,btnsPad[i][k]);
        }
      }
(...)
      if (axesChanged || btnsChanged) {
        Gamepad.num(i);
        Gamepad.send_now();
        axesChanged = btnsChanged = false;
      }

Le problème c'est que les données se "chevauchent" et rentrent en conflit.
Quand j'appuie sur un bouton ou déplace un axe d'un gamepad, ce changement est répercuté sur les autres :~

Aurais-tu une idée sur le pourquoi du comment? (mauvaise déclaration de tableau?, problème de mémoire vive?, je rate une évidence logique?, mon optimisation est vaine?).

Neit:
Le problème c'est que les données se "chevauchent" et rentrent en conflit.
Quand j'appuie sur un bouton ou déplace un axe d'un gamepad, ce changement est répercuté sur les autres :~

Tu pourrais mettre ton sketch complet parce qu'avec juste des morceaux c'est pas tiptop :wink: