[Résolu] Adaptateur 4 manettes PS/PS2->USB/PC

Salut la zone!

Vu que le driver de mon adaptateur de pads PS/PS2 est aux 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 modifier USB HID du Teensy pour que l’ordi reconnaisse 4 manettes, ou dans le pire des cas, enrichir le Joystick de sorte que se soit une seule manette qui regroupe tous 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. Malgré les tutos/documentations consultés, je n’arrive à rien.

Ci-joint, les fichiers USB HID pour que vous voyez de quoi ça à l’air (et si vous le voulez bien, m’aider à me sortir de ce casse tête :crying: ).

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.

Problème réglé, on peut fermer (sauf si ça intéresse quelqu’un de voir la solution/tuto).

Je pense que tu devrais partager avec la communauté.
Si quelqu’un passe par là, ça peut l’intéresser.

Ok, c’est parti.

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 &agrave; changer avant chaque envoi
joystick_report_data[1] = 0;		  //boutons 1 &agrave; 8 non enfonc&eacute;s
joystick_report_data[2] = 0;		  //boutons 9 &agrave; 16 non enfonc&eacute;s
joystick_report_data[3] =  0x7F;   //axe X &agrave; 127 (centr&eacute;)
joystick_report_data[4] =  0x7F;   //axe Y &agrave; 127 (centr&eacute;)
joystick_report_data[5] =  0x7F;   //axe Z &agrave; 127 (centr&eacute;)
joystick_report_data[6] =  0x7F;   //axe Rx &agrave; 127 (centr&eacute;)

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 &amp; 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&eacute;
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à. En espérant que ça serve :slight_smile:

ha ouais. Je crois que j’avais pas lu de code de ce style depuis 1999 !

En tout cas chapeau, t’as du bien galérer pour trouver !!

J’avais jamais lu/fais de C++/USB/HID avec préparation de données en hexa, je l’ai bien senti passer.
En plus avec ma chance, la construction du joystick était différente comparée à celle des autres périphériques <_<

PS: maintenant que c’est fais, je crois que je vais enchaîner avec un adaptateur 4NES+4SNES :stuck_out_tongue: