Aller au menu - Aller au contenu

Icône Systèmes de connexion

Avatar
Avatar
Mise à jour : 14/10/2009
Difficulté : Facile Facile
282 visites depuis 7 jours, classé 354/786
Maintenant que vous savez faire de belles oeuvres, il ne vous manque plus que le mode multijoueur ^^ . Dans cette partie, nous allons voir comment réaliser une connexion Wifi à un site Internet, mais aussi DS à DS.
Sommaire du tutoriel :
Icône du chapitre
Chapitre précédent Sommaire Chapitre suivant

Wifi

Nous allons voir ici comment nous connecter à une adresse, envoyer des messages et en recevoir.
Rassurez-vous, la méthode ne diffère pas trop de celle employée sur ordinateur...


Initialiser et arrêter le Wifi



Tout d'abord, jetez un oeil dans votre Makefile. Il faut décommenter #ARM7_SELECTED = ARM7_MP3_DSWIFI (enlevez le caractère # ) et commenter ARM7_SELECTED = ARM7_BASIC (ajoutez un # au début de la ligne).

Maintenant, retournons à notre fichier source :) ! Nous allons initialiser le système Wifi avec la fonction void PA_InitWifi(); . A présent, il faut utiliser les paramètres définis à partir d'un jeu commercial (il faut qu'il y ait le logo Wifi) avec la fonction bool PA_ConnectWifiWFC(); . Et là, sa valeur de retour compte plus que d'autres fonctions, car cette fonction rate assez souvent. Elle renvoie vrai si la connection a pu être effectuée ou faux dans le cas contraire.

Pour vous déconnecter du point d'accès, nous utiliserons Wifi_DisconnectAP(); , et pour arrêter le Wifi Wifi_DisableWifi(); .


Créer et utiliser des sockets



Pour établir une connexion en Wifi, il faut passer par les sockets. Comme sur l'ordinateur en fait :) . Une socket est une variable de type int donnée par la fonction int PA_InitSocket(int *socket,char *host,int port,int mode); socket est un pointeur sur votre socket à initialiser, host est l'adresse IP ou la DNS à laquelle on veut se connecter, port est le... port :p et mode est le type de socket. mode ne peut prendre que deux valeurs différentes :
  • PA_NORMAL_TCP (socket TCP normale).
  • PA_NONBLOCKING_TCP (socket TCP non bloquée, c'est-à-dire qu'elle ne bloque pas le programme pour attendre la réception d'un message).


L'envoi et la réception de messages sont exatement pareils que sur ordinateur. Nous allons voir cela par le biais d'exemples.

L'envoi



Code : C
1
2
char buf[]="Hello World !";
send(sock,buf,sizeof(buf),0);


La réception



Code : C
1
2
char buf[256];
recv(sock,buf,sizeof(buf),0);


Vous le savez sûrement, mais on peut tout envoyer avec les sockets.
Nous allons voir comment faire envoi et une réception optimisée.
Pour cela, nous allons créer deux fonctions (envoi et reception) qui auront pour arguments la socket et un tableau de char (pour envoi : le message à envoyer, pour reception : le contenu du message reçu).
L'envoi doit se faire comme ceci : on envoie d'abord la taille du message, puis le message lui-même.
Et la réception doit se faire comme ceci : on reçoit la taille du message, on fait une allocation dynamique, puis on récupère le message.
On supposera que les types sont traités de la même façon de part et d'autre de la connexion.
Je vous laisse coder ;) ...

Secret (cliquez pour afficher)
Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
void envoi(int sock,char *buf)
{
    int taille=sizeof(buf);
    send(sock,&taille,sizeof(taille),0);
    send(sock,buf,taille,0);
}

void reception(int sock,char *buf)
{
    int taille=0;
    if(buf)
        free(buf);
    recv(sock,&taille,sizeof(int),0);
    buf=(char*)malloc(taille*sizeof(char));
    recv(sock,buf,sizeof(buf),0);
}

DS à DS

Nous allons utiliser une bibliothèque qui permet une connexion DS à DS. Elle s'appelle la libLobby. Elle permet des connexions directes ou alors via des rooms.
Normalement, vous l'avez sous forme de zip dans votre disque dur. Allez dans devkitpro\Other libs\ et normalement vous avez un zip dont le nom commence par "liblobby". Ouvrez-le (au besoin, dézippez-le), allez dans le dossier "include" et copiez 802.11.h, lobby.h ainsi que MessageQueue.h.
Maintenant, nous allons modifier notre Makefile. Commentez ARM7_SELECTED = ARM7_BASIC et décommentez #ARM7_SELECTED = ARM7_MP3_LIBLOBBY .

Dans votre source, il faut inclure les trois headers :
Code : C
1
2
3
#include "MessageQueue.h"
#include "802.11.h"
#include "lobby.h"


Maintenant on va initialiser la libLobby avec :
Code : C
1
2
3
IPC_Init();
IPC_SetChannelCallback(0, &LWIFI_IPC_Callback);
LOBBY_Init();


Maintenant, il faut donner une fonction de réception à la libLobby. En fait, les communications sont non-bloquantes et il n'y a pas de fonction de réception. Vous devez la créer, puis la passer en argument à void LOBBY_SetStreamHandler(unsigned short streamID, LOBBY_STREAMHANDLER_PROC callback); pour indiquer à la libLobby que votre fonction doit être appelée à chaque réception.
Elle doit être de type void et doit avoir trois arguments (dans l'ordre) :
  • un pointeur de type unsigned char : c'est le message.
  • une variable de type int : c'est la taille du message.
  • une variable de type LPLOBBY_USER : c'est l'utilisateur qui a envoyé le message.


Voici donc un exemple de fonction de réception :
Code : C
1
2
3
4
void reception(unsigned char *message,int taille,LPLOBBY_USER from)
{
    PA_OutputText(0,0,0,"Recu : %s",(char*)message);
}


Maintenant nous allons indiquer à la libLobby que la fonction reception est la fonction de réception :
Code : C
1
LOBBY_SetStreamHandler(1,&reception);


Qu'est-ce que ce nombre avant le pointeur sur recepetion ?

Il s'agit de l'indentifiant d'un canal. D'après la source, ce nombre peut aller jusqu'à 32 768 mais le canal 32 767 est réservé.

Mais à quoi servent ces canaux ?

En fait, nous le verrons juste après, quand on fait un envoi, il faut préciser le canal. Ceci permet 32 767 fonctions de réceptions différentes. A vous de les gérer pour bien séparer les tâches.

A présent il faut connaître le nombre de joueurs connectés avec unsigned short LOBBY_GetNumberOfKnownUsers(void); .


Les fonctions sur les utilisateurs



On peut obtenir un utilisateur par son identifiant avec LPLOBBY_USER LOBBY_GetUserByID(unsigned short id); id est compris entre 0 et la valeur de retour de LOBBY_GetNumberOfKnownUsers non inclus.

On peut aussi obtenir un utilisateur par son adresse MAC (à voir dans un jeu officiel) avec LPLOBBY_USER LOBBY_GetUserByMAC(unsigned char *adresse); .

Pour savoir si un utilisateur est déconnecté on utilise int LOBBY_IsTimedOut(LPLOBBY_USER utilisateur); . Cette fonction renvoie 1 s'il est déconnecté ou 0 dans le cas contraire.

Pour obtenir le nom d'un utilisateur on utilisera const char *LOBBY_GetUserName(LPLOBBY_USER utilisateur); .


Maintenant que nous connaissons beaucoup de fonctions concernant les utilisateurs, nous allons voir comment leur envoyer des messages.
Il existe la fonction void LOBBY_SendToUser(LPLOBBY_USER user,unsigned short canal,unsigned char *message,int taille); . C'est là qu'intervient la variable canal. Supposons que vous créez un jeu de combat en temps réel multijoueur. Vous pouvez utiliser la variable canal pour séparer les types d'envois. Par exemple le canal 1 peut servir d'envoi/réception d'infos concernant les autres joueurs connectés, et le canal 2 peut servir d'envoi/réception de messages du système de chat que vous avez récemment intégré au jeu ;) . Ca nous simplifie la vie, et comme nous avons quelques dizaines de milliers de canaux, on peut dire que vous n'avez pas de limite :) .

Vous pouvez aussi envoyer un message à tous les utilisateurs connus avec void LOBBY_SendToAll(unsigned short canal, unsigned char *message, int taille); .


Les rooms



Il ne peut y avoir qu'une seule room par DS.


Les rooms sont caractérisées par leur nom, le nombre d'utilisateur maximal, l'identifiant du jeu et sa version.

A quoi servent l'identifiant du jeu et sa version ?


L'identifiant du jeu est un nombre qui indique le jeu utilisant la room. Sa version permet de connaître le fonctionnement du jeu. En fait, si les deux joueurs ont le même jeu, et si chez un joueur, l'identifiant est le même que chez un autre, on peut penser que le fonctionnement est le même (sauf si la version est différente).

Alors créons notre room avec void LOBBY_CreateRoom(char *nom,int maxUsers,unsigned short gameCode,unsigned short version); .
On peut définit la visibilité de la room avec void LOBBY_SetRoomVisibility(int visible); . Si visible vaut 0 la room sera invisible. A l'inverse, si visible vaut 1 la room sera visible. Seul le créateur de la room peut effectuer cette action.

Pour savoir combien il y a de rooms visibles, on fera appel à unsigned short LOBBY_GetNumberOfKnownRooms(void); .

Pour obtenir une room, on utilisera LPLOBBY_ROOM LOBBY_GetRoomByID(unsigned long id);
Il ne faut pas confondre id avec gameCode (utilisé dans LOBBY_CreateRoom). En effet, id est le "numéro d'apparition" de la room. Par exemple, si c'est la première à avoir été détectée, il faut mettre 0.


Vous pouvez aussi obtenir une room à partir de l'adresse MAC de la DS du créateur de la room :D en utilisant LPLOBBY_ROOM LOBBY_GetRoomByMAC(unsigned char *mac); .

Si vous voulez obtenir la room d'un utilisateur en particulier, il faudra appeler la fonction LPLOBBY_ROOM LOBBY_GetRoomByUser(LPLOBBY_USER user); .

De même, si vous voulez obtenir une room à partir de son gameCode, il faudra appeler la fonction LPLOBBY_ROOM LOBBY_GetRoomByGame(LPLOBBY_ROOM anchor, unsigned short gameCode); . La variable anchor sert à déterminer à partir de quelle room on lance la recherche. Si c'est 0 ce sera la première trouvée.

Pour savoir combien il y a d'utilisateurs dans une room, on va utiliser unsigned short LOBBY_GetUsercountInRoom(LPLOBBY_ROOM room); .
De même, pour obtenir le nombre maximal d'utilisateurs, on appellera unsigned short LOBBY_GetMaxUsercountInRoom(LPLOBBY_ROOM room); . Ces deux fonctions sont très importantes car elles permettent de trouver le nombre de places restantes dans une room.

Vous pouvez obtenir le nom d'une room avec char* LOBBY_GetRoomName(LPLOBBY_ROOM room); , son gameCode avec unsigned short LOBBY_GetRoomGameCode(LPLOBBY_ROOM room); et sa version avec unsigned short LOBBY_GetRoomGameVersion(LPLOBBY_ROOM room); .

Avec les fonctions vues ci-dessus, vous pouvez choisir dans quelle room aller. Si vous voulez vous joindre à une room, il faudra utiliser void LOBBY_JoinRoom(LPLOBBY_ROOM room); . Si vous voulez la quitter, il faudra appeler void LOBBY_LeaveRoom(void); .

Vous pouvez envoyer des messages à tous les utilisateurs d'une room avec void LOBBY_SendToRoom(LPLOBBY_ROOM room, unsigned short canal, unsigned char *message, int taille); . Mais vous pouvez ne pas envoyer de message à tous. En fait, via l'argument canal, vous pouvez faire le tri. Par exemple, si vous voulez envoyer des messages au créateur de la room sans que les autres utilisateurs ne les voient, il faut créer un canal chez le créateur qui n'est pas créé chez les autres. Ainsi, par le biais de ce canal, seul le créateur de la room pourra recevoir les messages...

Dans vos boucles, au même titre que PA_WaitForVBL, il faudra systématiquement mettre :
Code : C
1
2
IPC_RcvCompleteCheck();
LOBBY_Update();

Sinon vous ne pourrez jamais ni détecter des utilisateurs et des rooms, ni envoyer ou recevoir de messages...

L'émulateur



J'ai une bonne nouvelle : l'émulateur No$GBA supporte très bien la liblobby ! Pour utiliser plus de Nintendo DS au sein de votre émulateur, faites F11 et rendez-vous dans la section "Number of Emulated Gameboys", et modifiez le nombre en mettant 2 à la place. Faites OK puis Options->Save Options. Fermez NO$GBA et lancez votre homebrew de nouveau. A présent, vous pouvez constater la résultat :magicien: .
Par contre, si vous voulez revenir à une seule Nintendo DS, il faut aller dans le dossier de NO$GBA et ouvrir NO$GBA.ini. Cherchez une ligne commençant par :
Citation : NO$GBA.ini
Number of Emulated Gameboys ==

Remplacez cette ligne intégralement par :
Citation : NO$GBA.ini
Number of Emulated Gameboys == -One Machine

Et voilà ;) !
Les connexions sur DS n'ont à présent plus aucun secret pour vous ;) !
Chapitre précédent Sommaire Chapitre suivant

Partager

14 commentaires pour "Systèmes de connexion"
Note moyenne : 3.57 / 4 (65 votes)
Pseudo Commentaire
Hors ligne piero53 # Posté le 10/05/2011 à 22:34:56

Bonjour,

Il y a une chose qui m'échappe à propos du wifi (1ère partie du tuto), je ne vois pas vraiment l’intérêt...

On crée un socket sur l'adresse IP de son PC?
On envoie un message à son PC? Mais comment voir si on la bien reçu?

merci :)
Hors ligne snake_48 # Posté le 10/05/2011 à 22:44:40
Il me manque un bit.
Avatar

Études : INSA Lyon

Tu crées une socket sur une adresse IP, ça peut être un ordinateur, mais aussi une autre NDS, un serveur, une Wii etc. Pour savoir s'il a été bien reçu, normalement le protocole TCP est prévu pour fonctionner en accusés de réceptions, ce qui le rend normalement plus lent que l'UDP. Mais tu peux toi-même coder ton accusé de réception pour en être sûr.
En espérant t'avoir aidé,
snake_48

Programmez sur votre Wii ! | Programmez sur votre Nintendo DS ! | Charger des fichiers .OBJ | Introduction au scripting avec Python
Création d'un moteur physique (en cours)
Code Lyoko Strategy Game Coder
Langages connus : AS3, Batch, C, C++, HTML, Java, Javascript, PHP, Python.
Programme sur : PC, Nintendo DS, Wii.
o----}=========>
 
Hors ligne piero53 # Posté le 10/05/2011 à 23:04:23

Ok,

si je fais un test comme ceci sur l'envoi d'un message :

Code : C
1
2
3
4
if(send(sock,&buf,256,0)>0)
    {
        PA_OutputText(0,0,0,"envoi ok");
    }


Et qu'il m'affiche bien le "envoi ok", le message à a bien été envoyé? A propos de l'accusé de réception, je suis désolé mais je ne vois pas du tout la façon de procéder (une piste?)
Hors ligne rere62960 # Posté le 12/05/2011 à 09:23:48

Bonjour,

Lorsque je veux placer ARM7_SELECTED = ARM7_MP3_LIBLOBBY dans le makeFile, j'obtiens une erreur !

Cette ligne n'était pas présente auparavant, est-ce normal ?

Merci de m'aider !
Hors ligne Aire-One # Posté le 14/01/2012 à 15:20:03
<(¤v¤)>

Avis : Très bon

Moi aussi...
Ce 'type' de complilation n'était pas présent dans mon makefile. Le rajouter dedans produit une erreur (car ce n'est pas un type valable). J'ais testé avec un autre (qui est présent de base dans mon akefile) et toutes les fonctions de libLobby sont dites 'indéclarée' au moment du linking... :o

Je pense qu'il y a une quelconque instalation ou manipulation à faire pour le fonctionnement de la libLobby. Aurriez-vous une solution pour ce probléme dont je semble ne pas être le seul à être touché ?

Merci

Reflets d'acide, la saga MP3 culte !
N'hésitez pas à me contacter
C: SDL, FMOD, (PAlib)
C++: PAlib, Qt, OpenGL
Batch (Makefile)
(xHTML/CSS + (PHP, Javascipt) occasionnellement :-° )
 

Voir tous les commentaires