forums.ps2dev.org Forum Index forums.ps2dev.org
Homebrew PS2, PSP & PS3 Development Discussions
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Prx help

 
Post new topic   Reply to topic    forums.ps2dev.org Forum Index -> PSP Development
View previous topic :: View next topic  
Author Message
*mUrDeRc0dE*



Joined: 16 Jun 2008
Posts: 13
Location: IDSTORAGE

PostPosted: Mon Sep 01, 2008 7:04 pm    Post subject: Prx help Reply with quote

I have the following prx that works in kernel mode

Code:
#include <pspsdk.h>
#include <pspkernel.h>
#include <pspidstorage.h>
#include <string.h>

PSP_MODULE_INFO("KernelStuff_driver", 0x1006, 3, 2);
PSP_MAIN_THREAD_ATTR(0);

//Get Fuse Id
u64 sceSysreg_driver_4F46EEDE();
int sceSyscon_driver_7EC5A957(u32 *baryon);
u32 sceSysreg_driver_E2A5D1EE(void);


int ReadKey(int key, char *buffer)
{
        int err;
        u32 k1;

        k1 = pspSdkSetK1(0);

        memset(buffer, 0, 512);
        err = sceIdStorageReadLeaf(key, buffer);

        pspSdkSetK1(k1);

        return err;
}

int WriteKey(int key, char *buffer)
{
        int err;
        u32 k1;

        k1 = pspSdkSetK1(0);

        err = sceIdStorageWriteLeaf(key, buffer);
        sceIdStorageFlush();

        pspSdkSetK1(k1);

        return err;
}



void GetMoboInfo(int* baryon, int* tachyon)
{
  u32 by, ty;
  int k;

  k = pspSdkSetK1(0);
  ty = sceSysreg_driver_E2A5D1EE();
  sceSyscon_driver_7EC5A957(&by);
  pspSdkSetK1(k);
  (*baryon) = by;
  (*tachyon) = ty;
}

u64 GetFuseId()
{
   u64 fuseId = sceSysreg_driver_4F46EEDE();
    return fuseId;
}

int module_start(SceSize args, void *argp)
{
  return 0;
}

int module_stop()
{
  return 0;
}


Exports

Code:
# Define the exports for the prx
PSP_BEGIN_EXPORTS

# These four lines are mandatory (although you can add other functions like module_stop)
# syslib is a psynonym for the single mandatory export.
PSP_EXPORT_START(syslib, 0, 0x8000)
PSP_EXPORT_FUNC_HASH(module_start)
PSP_EXPORT_VAR_HASH(module_info)
PSP_EXPORT_END

PSP_EXPORT_START(kernel_driver, 0, 0x4001)
PSP_EXPORT_FUNC_HASH(GetFuseId)
PSP_EXPORT_FUNC_HASH(GetMoboInfo)
PSP_EXPORT_FUNC_HASH(ReadKey)
PSP_EXPORT_FUNC_HASH(WriteKey)
PSP_EXPORT_END

PSP_END_EXPORTS


and the main eboot that works in user mode

Code:
#include <pspsdk.h>
#include <pspkernel.h>
#include <pspdebug.h>
#include <pspmoduleinfo.h>
#include <kubridge.h>

#include "kernel.h"

#define printf pspDebugScreenPrintf

/* Define the module info section */
PSP_MODULE_INFO("tpb", 0x1000, 1, 0); 


int main(int argc, char *argv[])
{
   pspDebugScreenInit();
   
   int r = kuKernelLoadModule("kernelstuff.prx",0,NULL);
   if (r < 0)
   {
      printf( "Error 0x%08X loading/starting pspdecrypt.prx.\n", r);
      sceKernelDelayThread(7000000);
   }
   sceKernelStartModule(r, 0, NULL, 0, NULL);




   u32 sceSysreg_driver_E2A5D1EE(void);
   u32 sceSyscon_driver_E7E87741(u32 *pommel);
   u32 sceSyscon_driver_7EC5A957(u32 *baryon);

   u32 tachyon;
   u32 pommel;
   u32 baryon;
      
   tachyon = sceSysreg_driver_E2A5D1EE();
   sceSyscon_driver_E7E87741(&pommel);
   sceSyscon_driver_7EC5A957(&baryon);
   
   int bar,tac;
   GetMoboInfo(&bar,&tac);
   printf("%i - %i\n",bar,tac);

   printf("Tachyon: 0x%08X\n", tachyon);
   printf("Pommel: 0x%08X\n", pommel);
   printf("Baryon: 0x%08X\n", baryon);
   
   printf("%#llx",GetFuseId());
   
   char wifi_module_mac[512];
   ReadKey(0x44, wifi_module_mac);
   printf("Mac : %s",wifi_module_mac);

   
   sceKernelDelayThread(10000000);


   return 0;
}


but it doesn't work at all... can anyone help me?
_________________
Source code is for noobs...
Back to top
View user's profile Send private message
jean



Joined: 05 Jan 2008
Posts: 489

PostPosted: Mon Sep 01, 2008 8:21 pm    Post subject: Reply with quote

What kind of problem does it have? Compile time or run time?
does
Code:
int r = kuKernelLoadModule("kernelstuff.prx",0,NULL);

have current working directory awareness?? search for CWD.
Back to top
View user's profile Send private message
*mUrDeRc0dE*



Joined: 16 Jun 2008
Posts: 13
Location: IDSTORAGE

PostPosted: Mon Sep 01, 2008 9:03 pm    Post subject: Reply with quote

at run time it return an error during the module loading

EDIT : I got it to work but now the GetFuseid return 0x4401475400000000 but my fuse id starts with 7 and neither the mac address is displayed. Ah, and the baryon and tachion version result as 0 - 0
_________________
Source code is for noobs...
Back to top
View user's profile Send private message
J.F.



Joined: 22 Feb 2004
Posts: 2906

PostPosted: Tue Sep 02, 2008 5:10 am    Post subject: Reply with quote

To use a kernel prx from a user app in 3.xx/4.xx, you need to modify the module info like this (in main.c)

Code:
PSP_MODULE_INFO("TEST", 0, VERS, REVS);
PSP_MAIN_THREAD_ATTR(PSP_THREAD_ATTR_USER);
PSP_HEAP_SIZE_KB(-64);


And make it a PRX itself like this (in the makefile)

Code:
BUILD_PRX = 1
PSP_FW_VERSION = 401
PSP_LARGE_MEMORY = 1


That also allows you to use the extra memory in the Slim if it's run on a Slim.
Back to top
View user's profile Send private message AIM Address
sauron_le_noir



Joined: 05 Jul 2008
Posts: 229

PostPosted: Tue Sep 02, 2008 6:45 am    Post subject: Reply with quote

Just Modify a little bit your user program:
Code:

#include <pspsdk.h>
#include <pspkernel.h>
#include <pspdebug.h>
#include <pspmoduleinfo.h>
#include <kubridge.h>

// #include "kernel.h"

#define printf pspDebugScreenPrintf

/* Define the module info section */
PSP_MODULE_INFO("info", 0, 1, 0);
PSP_MAIN_THREAD_ATTR(PSP_THREAD_ATTR_USER);
PSP_HEAP_SIZE_KB(-64);



extern   int ReadKey(int key, char *buffer);
extern        int WriteKey(int key, char *buffer);
extern        void GetMoboInfo(int* baryon, int* tachyon);
extern        u64 GetFuseId();

int main(int argc, char *argv[])
{
  int i;
   pspDebugScreenInit();
   
   int r = kuKernelLoadModule("kernel.prx",0,NULL);
   if (r < 0)
   {
      printf( "Error 0x%08X loading/starting kernel.prx.\n", r);
      sceKernelDelayThread(7000000);
   }
   sceKernelStartModule(r, 0, NULL, 0, NULL);

   
   int bar,tac;
   GetMoboInfo(&bar,&tac);
   printf("baryon %i - Tachyon %i\n",bar,tac);

   
   printf("Fuseid %#llx\n",GetFuseId());
   
   char wifi_module_mac[512];
   ReadKey(0x44, wifi_module_mac);
   printf("Mac : ");
   for(i=0;i<12;i++)
      printf("%02X:",wifi_module_mac[i]);

   
   sceKernelDelayThread(10000000);


   return 0;
}


The Makefile
Code:

# Set Here the path where you want to copy your EBOOUT

MOUNT_POINT = /media/disk/psp/game/info



# name displayed by the XMB

PSP_EBOOT_TITLE = Info-PSP



# fisrt icon displayed (*.PNG)  by the XMB

PSP_EBOOT_ICON = NULL



# animation (*.PMF) displayed by the XMB

PSP_EBOOT_ANIM = NULL



# it's a picture (*.PNG)displayed after some seconds rather  with transparency to allow us to see the first icon and the anim.

PSP_EBOOT_FOREGROUND = NULL

 

# background image (*.PNG) displayed

PSP_EBOOT_BACKGROUND = NULL





# music (*.AT3) rather a loop but not mandatory

PSP_EBOOT_SND0 = NULL





 

CXXFLAGS = -G0 -Wall -O3 -D_PSP_FW_VERSION=401  -fno-exceptions

INCDIR = -I. -I$(PSPSDK)/include -I ./SDK/include

LIBDIR = -L. -L/usr/local/pspdev/lib -L$(PSPSDK)/lib -specs=/usr/local/pspdev/psp/sdk/lib/prxspecs -Wl,-q,-T/usr/local/pspdev/psp/sdk/lib/linkfile.prx -L../SDK/lib

LIBS =  /usr/local/pspdev/psp/sdk/lib/prxexports.o -lstdc++ -lpspctrl -lpspdebug -lpspge -lpspdisplay -lpspsdk -lc -lpspuser -lpspkubridge

 

OBJECTS = main.o kernel.o



CC = psp-g++

#########################################################

all: EBOOT.PBP



EBOOT.PBP: PARAM.SFO a.prx $(PSP_EBOOT_ICON)  $(PSP_EBOOT_FOREGROUND) $(PSP_EBOOT_BACKGROUND) $(PSP_EBOOT_ANIM) $(PSP_EBOOT_SND0)

   pack-pbp $@ PARAM.SFO $(PSP_EBOOT_ICON) $(PSP_EBOOT_ANIM) $(PSP_EBOOT_FOREGROUND) $(PSP_EBOOT_BACKGROUND) $(PSP_EBOOT_SND0) a.prx NULL

   echo cp eboot.pbp $(MOUNT_POINT)



PARAM.SFO: a.prx

   mksfo $(PSP_EBOOT_TITLE) $@

   

a.prx: a.elf

   psp-prxgen $< $@   

   



a.elf: $(OBJECTS) Makefile

   psp-gcc $(CXXFLAGS) $(LIBDIR) $(OBJECTS) $(LIBS) -o $@

   psp-fixup-imports  $@





main.o: main.c

   psp-gcc $(INCDIR)  $(CXXFLAGS) -c -o $@ $<





kernel.o: kernel.S

   psp-gcc $(INCDIR)  $(CXXFLAGS) -c -o $@ $<





NULL:

   

   

clean:

   rm -f $(OBJECTS) *.elf PARAM.SFO EBOOT.PBP




Back to top
View user's profile Send private message Send e-mail MSN Messenger
J.F.



Joined: 22 Feb 2004
Posts: 2906

PostPosted: Tue Sep 02, 2008 7:23 am    Post subject: Reply with quote

That makefile won't make large memory for the Slim. It needs

Code:
mksfoex -d MEMSIZE=1 $(PSP_EBOOT_TITLE) $@


instead of

Code:
mksfo $(PSP_EBOOT_TITLE) $@


In fact, you shouldn't be trying to do the makefile that way in any case... you need to use the PSPSDK form:

Code:
TARGET = program_name
OBJS = main.o kernel.o

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

BUILD_PRX = 1
PSP_FW_VERSION = 401
PSP_LARGE_MEMORY = 1

LIBDIR =
LIBS = libraries_go_here
LDFLAGS =

EXTRA_TARGETS = EBOOT.PBP
PSP_EBOOT_TITLE = PSP XMB Title For App
PSP_EBOOT_ICON1 = ICON1.PMF
PSP_EBOOT_ICON = ICON0.PNG
PSP_EBOOT_PIC1 = PIC1.PNG
PSP_EBOOT_SND0 = SND0.AT3

PSPSDK=$(shell psp-config --pspsdk-path)
include $(PSPSDK)/lib/build.mak
Back to top
View user's profile Send private message AIM Address
*mUrDeRc0dE*



Joined: 16 Jun 2008
Posts: 13
Location: IDSTORAGE

PostPosted: Tue Sep 02, 2008 5:25 pm    Post subject: Reply with quote

Very thanks of the help but now at boot time my program crash anda report a 8002013C error, module not found, but i've tryed to load it from ms0:/kernelstuff.prx and only kenrelstuff.prx but it doesn't load...

PS: Anyone knows a place with a complete list of all psp motherboards with the respective tachyon and bryon version?

Thanks...
Sorry for my english but i'm an italian programmer of 13 years :P
_________________
Source code is for noobs...
Back to top
View user's profile Send private message
sauron_le_noir



Joined: 05 Jul 2008
Posts: 229

PostPosted: Wed Sep 03, 2008 5:51 am    Post subject: Reply with quote

Correct Jf i have taken this from a old makefile
Back to top
View user's profile Send private message Send e-mail MSN Messenger
sauron_le_noir



Joined: 05 Jul 2008
Posts: 229

PostPosted: Wed Sep 03, 2008 5:52 am    Post subject: Reply with quote

Correct Jf i have taken this from a old makefile
Back to top
View user's profile Send private message Send e-mail MSN Messenger
*mUrDeRc0dE*



Joined: 16 Jun 2008
Posts: 13
Location: IDSTORAGE

PostPosted: Wed Sep 03, 2008 5:01 pm    Post subject: Reply with quote

please, i dint't want the entire source made from you, i want only understand because the prx give me error...it's simple
_________________
Source code is for noobs...
Back to top
View user's profile Send private message
J.F.



Joined: 22 Feb 2004
Posts: 2906

PostPosted: Wed Sep 03, 2008 6:27 pm    Post subject: Reply with quote

:)

Well, too much info is better than too little.
Back to top
View user's profile Send private message AIM Address
*mUrDeRc0dE*



Joined: 16 Jun 2008
Posts: 13
Location: IDSTORAGE

PostPosted: Wed Sep 03, 2008 6:40 pm    Post subject: Reply with quote

ok, after a bit of testing i fond the preoblem, now the entire program isn't booted with that shitty error...plz help needed
_________________
Source code is for noobs...
Back to top
View user's profile Send private message
*mUrDeRc0dE*



Joined: 16 Jun 2008
Posts: 13
Location: IDSTORAGE

PostPosted: Wed Sep 03, 2008 11:41 pm    Post subject: Reply with quote

oh shit, there is anyone that can read that piece of crap code and tell me where my program skills lacks and correct my code...
_________________
Source code is for noobs...
Back to top
View user's profile Send private message
J.F.



Joined: 22 Feb 2004
Posts: 2906

PostPosted: Thu Sep 04, 2008 7:20 am    Post subject: Reply with quote

Why don't you post your current code for us to check.
Back to top
View user's profile Send private message AIM Address
*mUrDeRc0dE*



Joined: 16 Jun 2008
Posts: 13
Location: IDSTORAGE

PostPosted: Thu Sep 04, 2008 4:54 pm    Post subject: Reply with quote

i've got to work some things but...

Code:
void GetMoboInfo(int* baryon, int* tachyon)
{
     k1 = pspSdkSetK1(0);
     u32 by, ty, pm;
     ty = sceSysreg_driver_E2A5D1EE();
     sceSyscon_driver_7EC5A957(&by);
     (*baryon) = by;
     (*tachyon) = ty;
     (*pommel) = pm;
     pspSdkSetK1(k1);
}

return strange values and
Code:
   printf("Mac : ");
   for(i=0;i<12;i++)
      printf("%i:",wifi_module_mac[i]);

return the correct mac but with a lot of FFFFF. Ah, the function sceKernelDevkitVersion return a strange number but not my kernel version
_________________
Source code is for noobs...
Back to top
View user's profile Send private message
*mUrDeRc0dE*



Joined: 16 Jun 2008
Posts: 13
Location: IDSTORAGE

PostPosted: Thu Sep 04, 2008 9:33 pm    Post subject: Reply with quote

now a library not linked yet error... this is the prx src

Code:
#include <pspsdk.h>
#include <pspkernel.h>
#include <pspidstorage.h>
#include <string.h>
#include <pspsysmem_kernel.h>

PSP_MODULE_INFO("KernelStuff_driver", 0x1006, 3, 2);
PSP_MAIN_THREAD_ATTR(0);

//Get Fuse Id
u64 sceSysreg_driver_4F46EEDE();


u32 sceSysreg_driver_E2A5D1EE(void);
u32 sceSyscon_driver_E7E87741(u32 *pommel);
u32 sceSyscon_driver_7EC5A957(u32 *baryon);


u32 k1;


int ReadKey(int key, char *buffer)
{
        int err;

        k1 = pspSdkSetK1(0);

        memset(buffer, 0, 512);
        err = sceIdStorageReadLeaf(key, buffer);

        pspSdkSetK1(k1);

        return err;
}

int WriteKey(int key, char *buffer)
{
        int err;

        k1 = pspSdkSetK1(0);

        err = sceIdStorageWriteLeaf(key, buffer);
        sceIdStorageFlush();

        pspSdkSetK1(k1);

        return err;
}

void GetMoboInfo(int* baryon, int* tachyon)
{
     k1 = pspSdkSetK1(0);
     u32 by, ty;
     ty = sceSysreg_driver_E2A5D1EE();
     sceSyscon_driver_7EC5A957(&by);
     (*baryon) = by;
     (*tachyon) = ty;
     pspSdkSetK1(k1);
}

int GetPspVer(){
   k1 = pspSdkSetK1(0);
   int model = sceKernelGetModel();
   return model;
   pspSdkSetK1(k1);
}

int GetPspFirmware(){
   k1 = pspSdkSetK1(0);
   int fw = sceKernelDevkitVersion ();
   return fw;
   pspSdkSetK1(k1);
}

u64 GetFuseId()
{
   k1 = pspSdkSetK1(0);
   u64 fuseId = sceSysreg_driver_4F46EEDE();
    return fuseId;
   pspSdkSetK1(k1);
}

int module_start(SceSize args, void *argp)
{
   return 0;
}

int module_stop()
{
   return 0;
}

_________________
Source code is for noobs...
Back to top
View user's profile Send private message
everlasting



Joined: 19 Mar 2007
Posts: 41

PostPosted: Tue Sep 16, 2008 6:19 am    Post subject: Reply with quote

I'm a noob with prx at all, but i am reading a couple of tutorials for playing around with them and i have read that the PSP_MODULE_INFO in the prx has to have the same "name info" in the exp file. I have noticed that in your prx you have:
Code:
PSP_MODULE_INFO("KernelStuff_driver", 0x1006, 3, 2);


While in your export you have:

Code:
PSP_EXPORT_START(kernel_driver, 0, 0x4001)


May be this is the reason for your "library not linked error".
Back to top
View user's profile Send private message
Pirata Nervo



Joined: 09 Oct 2007
Posts: 409

PostPosted: Tue Sep 16, 2008 7:28 am    Post subject: Reply with quote

exports are not mandatory so I don't think that is the problem but maybe it is.
Let's wait and see
_________________

Upgrade your PSP
Back to top
View user's profile Send private message
Super Sheep



Joined: 23 Mar 2008
Posts: 31

PostPosted: Sat Sep 20, 2008 8:48 am    Post subject: Reply with quote

Pirata Nervo wrote:
exports are not mandatory so I don't think that is the problem but maybe it is.
Let's wait and see


Well, module_start is mandantory...
Back to top
View user's profile Send private message Visit poster's website MSN Messenger
cory1492



Joined: 10 Dec 2004
Posts: 216

PostPosted: Sat Sep 20, 2008 8:54 pm    Post subject: Reply with quote

Exports are somewhat mandatory if you plan to import them into a different module so you can call the functions...

Maybe the import stub is looking/set for kernel imports instead of the user ones that are exported. But of course, they didn't post the method they are using to import the kernel prx's exports - it should be important to keep the main module names straight between MODULE_INFO, exports, and imports (if it's trying to import from the wrong module, of course they won't be linked yet) though prxtool -u might cover it when you make the import stub.

Something I used to help with a not linked yet problem, is in the import stub instead of having
Code:
STUB_START   "module_name",0x40010000,0x00010005

I changed it to
Code:
STUB_START   "module_name",0x40090000,0x00010005

Changing that 1 to a 9 delays linking (though I could not explain how, I believe moonlight mentioned it here... somewhere.)

... just realized this is a month old bump ...
Back to top
View user's profile Send private message
Pirata Nervo



Joined: 09 Oct 2007
Posts: 409

PostPosted: Sat Sep 20, 2008 9:04 pm    Post subject: Reply with quote

Only if you want to export them but if you don't want they are not mandatory.
@Super Sheep, wtf.
_________________

Upgrade your PSP
Back to top
View user's profile Send private message
Super Sheep



Joined: 23 Mar 2008
Posts: 31

PostPosted: Sun Sep 21, 2008 12:52 am    Post subject: Reply with quote

Pirata Nervo wrote:
Only if you want to export them but if you don't want they are not mandatory.
@Super Sheep, wtf.


Exporting module_start is mandantory.
Back to top
View user's profile Send private message Visit poster's website MSN Messenger
Pirata Nervo



Joined: 09 Oct 2007
Posts: 409

PostPosted: Sun Sep 21, 2008 2:46 am    Post subject: Reply with quote

Oh really, can you explain me why did I make prx plugins without exporting anything?
_________________

Upgrade your PSP
Back to top
View user's profile Send private message
Super Sheep



Joined: 23 Mar 2008
Posts: 31

PostPosted: Mon Sep 22, 2008 12:59 am    Post subject: Reply with quote

If isn't exported, it'll make module_start the first function in the module, which LoadCore will jump to directly, although this might work, you are running in a vurnable and low priority thread, and crashes might happen faster than when exporting it like normal.
Back to top
View user's profile Send private message Visit poster's website MSN Messenger
Pirata Nervo



Joined: 09 Oct 2007
Posts: 409

PostPosted: Mon Sep 22, 2008 1:07 am    Post subject: Reply with quote

You are now contradicting yourself.
You said it is mandatory and you have just said that it might work.
:)
_________________

Upgrade your PSP
Back to top
View user's profile Send private message
Super Sheep



Joined: 23 Mar 2008
Posts: 31

PostPosted: Mon Sep 22, 2008 1:10 am    Post subject: Reply with quote

Pirata Nervo wrote:
You are now contradicting yourself.
You said it is mandatory and you have just said that it might work.
:)


Yeah, I bet you're totally inlove with your unstable programs...
Back to top
View user's profile Send private message Visit poster's website MSN Messenger
Pirata Nervo



Joined: 09 Oct 2007
Posts: 409

PostPosted: Mon Sep 22, 2008 1:36 am    Post subject: Reply with quote

Lol, now you are insulting me just because I was right about it not being mandatory.

You don't know how I code and you never saw any of my code. And you don't even know if the prx plugins I was talking about were personal prx or not.
_________________

Upgrade your PSP
Back to top
View user's profile Send private message
Super Sheep



Joined: 23 Mar 2008
Posts: 31

PostPosted: Mon Sep 22, 2008 1:58 am    Post subject: Reply with quote

Pirata Nervo wrote:
Lol, now you are insulting me just because I was right about it not being mandatory.

You don't know how I code and you never saw any of my code. And you don't even know if the prx plugins I was talking about were personal prx or not.


Well you just said that you don't export module_start...
I could easily reverse your public programs and ill see how you code. It's not worth the effort though.

module_start is mandantory, unless you're foolish...
Back to top
View user's profile Send private message Visit poster's website MSN Messenger
Pirata Nervo



Joined: 09 Oct 2007
Posts: 409

PostPosted: Mon Sep 22, 2008 2:09 am    Post subject: Reply with quote

I won't continue this as this won't go anywhere.
Edit:
Feel free to reverse my programs :)
_________________

Upgrade your PSP
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    forums.ps2dev.org Forum Index -> PSP Development All times are GMT + 10 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group