I. Introduction : 

Dans toutes les applications que l'on peut créer pour la PSP, il faut penser que l'utilisateur doit pouvoir quitter l'application. Pour cela, il faut paramétrer la manière dont ce fait cette fermeture de programme.

Nous allons donc voir de manière succinte le mécanisme des callbacks et des threads adaptés à notre besoin.

 

II. Convention de développement : 

Pour commencer, on va créer 2 fichiers : smartCallbacks.h et smartCallbacks.c.

Le premier contiendra les déclaration de types et les déclarations de fonctions, tandis que le second contiendra le code de toutes les fonctions déclarées dans le header (fichier .h).

Le fichier source (.c) incluera le fichier header (.h) ainsi que tous les headers nécessaires au bon développement de notre librairie.

Chaque type de données que nous déclarons sera préfixé par le mot-clé smart et les fonctions par le nom de la librairie ici smartCallbacks.

Les nom de variables seront toujours explicites afin de ne pas commettre d'erreurs lors de l'écriture du code.

 

III. Comment initialiser correctement une application PSP ?

Afin de pouvoir quitter correctement notre homebrew, il nous faut quelque chose qui puisse le faire à notre demande. On va donc utiliser une callback : c'est une fonction qui se déclenche lors d'un évènement. Dans notre cas, l'évènement est l'appui sur la touche HOME.

Cependant, ce n'est pas à nous de détecter cet évènement mais au kernel de la PSP. En effet, il existe une fonction permettant de définir qu'elle est la callback à appeler pour la fermeture du programme : sceKernelRegisterExitCallback.

Enfin, pour ne pas avoir de problème avec l'éxecution du reste de notre code, on lance un thread en parallèle pour s'occuper de toute cette configuration.

Notre système a donc besoin de 3 fonctions : la première va créer et lancer le thread d'initialisation, la seconde est le thread d'initialisation qui va créer et enregistrer la callback d'arrêt et la troisième c'est notre callback d'arrêt.

 

a) smartCallbacks_exitCallback :

Pour commencer, nous allons déclarer une fonction permettant d'ajouter une ligne dans un fichier : smartCallbacks_exitCallback.

Il suffit de mettre cette ligne dans smartCallbacks.h :

1
int smartCallbacks_exitCallback(void);

 

Le contenu de cette callback est simple, il suffit d'appeler la fonction sceKernelExitGame pour en faire une callback d'arrêt.

Voici donc le code de notre callback, à placer dans smartCallbacks.c :

1
2
sceKernelExitGame();
return 0;

 

b) smartCallbacks_thread :

Pour que cette callback puisse être appelée, nous allons écrire une fonction qui va servir de thread et qui va configurer notre callback pour que le kernel de la PSP l'appelle au bon moment : smartCallbacks_thread.

On rajoute la déclaration de notre fonction dans smartCallbacks.h :

1
int smartCallbacks_thread(SceSize args, void *argp); 

Le premier paramètre est le nombre d'arguments passés au thread et le second paramètre contient tous les paramètres qui lui sont passés. Tous les threads que vous voudrez créer doivent impérativement avoir ces 2 paramètres.

 

Maintenant, on peut s'attaquer au code de cette fonction.

D'abord, il nous faut déclarer une variable de type int pour stocker l'identifiant de la callback que nous allons créer.

1
int callback_id;

 

Pour créer une callback et obtenir un identifiant, il faut faire appel à la fonction sceKernelCreateCallback. Le premier paramètre est un nom que l'on choisit et peut donc être n'importe quoi : ici nous l'appellerons "Exit Callback". Le second paramètre est le nom de la fonction qui va être défini comme étant une callback : dans notre cas, il s'agit de smartCallbacks_exitCallback. Enfin, le dernier paramètre contient les arguments que l'on veut passer à notre callback : ici rien donc on passera la valeur NULL.

1
callback_id=sceKernelCreateCallback("Exit Callback", smartCallbacks_exitCallback, NULL);

 

Ensuite, il nous faut "enregistrer" la callback comme étant une callback d'arrêt en appelant la fonction sceKernelRegisterExitCallback. Cela a pour effet de notifier au kernel que notre callback doit être appelée lorsque l'utilisateur désire quitter le programme. D'ailleurs, sans l'enregistrement de cette callback, il est impossible de quitter (en appelant sceKernelExitGame) un homebrew sans faire crasher le système.

1
sceKernelRegisterExitCallback(callback_id);

 

Pour ne pas que le thread se termine et donc empêche l'arrêt de notre homebrew, nous devons l'endormir sans que cela affecte l'éxecution de callbacks : on utilise la fonction sceKernelSleepThreadCB.

1
sceKernelSleepThreadCB();

 

c) smartCallbacks_setup :

Pour terminer, il nous faut écrire une fonction qui va créer le thread à partir de la fonction que l'on a vu précedement et qui va le démarrer : smartCallbacks_setup.

On rajoute donc cette ligne dans notre fichier smartCallbacks.h :

1
int smartCallbacks_setup(void);

 

Lorsque l'on programme avec des threads, il nous faut toujours au moins une variable qui va contenir l'identifiant d'un thread. Nous déclarons donc un entier que l'on nomme thread_id (ou ce que vous voulez) :

1
int thread_id=0;

 

Maintenant, il nous faut créer le thread au moyen de la fonction sceKernelCreateThread. Cette fonction prend en paramètre un nom que l'on choisit, le nom de la fonction faisant office de thread, le niveau de priorité, la taille de la pile (stackSize), des attributs (ou données) à passer au thread et des paramètres additionnels.

1
thread_id=sceKernelCreateThread("init_thread", smartCallbacks_thread, 0x11, 0xFA0, 0, 0);

 

Il faut vérifier si le thread a été créé correctement : thread_id doit être supérieur ou égal à 0. Dans ce cas nous pouvons démarrer le thread à l'aide de sceKernelStartThread :

1
2
3
4
if(thread_id>=0)
{
	sceKernelStartThread(thread_id, 0, 0);
}

 

Enfin, il nous faut retourner thread_id afin que l'on puisse effectuer les traitements adéquats an cas de problème :

1
return thread_id;

 

IV. Exemple d'utilisation : 

Voici le code source d'un programme de type Hello World qui utilise notre librairie :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <pspkernel.h>
#include <pspdebug.h>
#include <pspctrl.h>
#include "smartCallbacks.h"

PSP_MODULE_INFO("Hello World", 0, 0, 1);

#define printf pspDebugScreenPrintf

int main(void)
{
	SceCtrlData pad;

	pspDebugScreenInit();
	smartCallbacks_setup();

	printf("Hello World !\n");
	while(1)
	{
		sceCtrlReadBufferPositive(&pad, 1);
		if (pad.Buttons & PSP_CTRL_CROSS)
		{
			sceKernelExitGame();
		} 
		sceKernelSleepThread();
	}

	return 0;
}

 

Et voici le fichier Makefile permettant la compilation. A noter, que pour utiliser la librairie, il faut bien penser à ajouter smartCallbacks.o dans le champ TARGET :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
TARGET = hello-world
OBJS = hello-world.o smartCallbacks.o

INCDIR = 
CFLAGS = -O2 -G0 -Wall
CXXFLAGS = $(CFLAGS) -fno-exceptions -fno-rtti
ASFLAGS = $(CFLAGS)

LIBDIR = 
LDFLAGS = 
LIBS = -lpspgum -lpspgu

EXTRA_TARGETS = EBOOT.PBP
PSP_EBOOT_TITLE = Hello World
PSP_FW_VERSION = 372

PSPSDK = $(shell psp-config --pspsdk-path)
include $(PSPSDK)/lib/build.mak

 

V. Code source de la librairie :

 

Attachments:
Download this file (smartCallbacks.tar.gz)smartCallbacks.tar.gz[ ]12 kB