picodrive/platform/uiq2/SimpleServer.cpp
notaz 1cb1584b86 reset behavior changed, Puggsy detection added
git-svn-id: file:///home/notaz/opt/svn/PicoDrive@405 be3aeb3a-fb24-0410-a615-afba39da0efa
2008-03-30 20:24:17 +00:00

430 lines
10 KiB
C++

// SimpleServer.cpp
#include <e32svr.h>
#include <e32math.h>
#include <e32uid.h>
#include <string.h>
#include "debug.h"
#include "version.h"
#include "ClientServer.h"
#include "SimpleServer.h"
#include "pico\picoInt.h"
extern TInt machineUid;
extern int gamestate, gamestate_prev;
extern TPicoConfig currentConfig;
extern TPicoKeyConfigEntry keyConfigMotA[];
extern const char *actionNames[];
const char *RomFileName = 0;
int pico_was_reset = 0;
// utility
unsigned int bigend(unsigned int l)
{
return (l>>24)|((l>>8)&0xff00)|((l<<8)&0xff0000)|(l<<24);
}
//**********************************
//CPicoServServer
//**********************************
CPicoServServer::CPicoServServer(TInt aPriority)
: CServer(aPriority)
{
}
// Create and start a new count server.
void CPicoServServer::New()
{
CPicoServServer *pS=new CPicoServServer(EPriority);
__ASSERT_ALWAYS(pS!=NULL,PanicServer(ESvrCreateServer));
pS->StartL(KServerName);
}
// Create a new server session.
CSharableSession *CPicoServServer::NewSessionL(const TVersion &aVersion) const
{
// check we're the right version
TVersion v(KPicoMajorVersionNumber,KPicoMinorVersionNumber,0);
if (!User::QueryVersionSupported(v,aVersion))
User::Leave(KErrNotSupported);
// make new session
RThread aClient = Message().Client();
return CPicoServSession::NewL(aClient, (CPicoServServer*)this);
}
//**********************************
//CPicoServSession
//**********************************
// constructor - must pass client to CSession
CPicoServSession::CPicoServSession(RThread &aClient, CPicoServServer *aServer)
: CSession(aClient), rom_data(0)
{
// iPicoSvr=aServer;
}
CPicoServSession* CPicoServSession::NewL(RThread &aClient, CPicoServServer * aServer)
{
return new(ELeave) CPicoServSession(aClient,aServer);
}
void CPicoServSession::ServiceL(const RMessage& aMessage)
{
TRAPD(err,DispatchMessageL(aMessage));
aMessage.Complete(err);
}
// service a client request; test the opcode and then do appropriate servicing
void CPicoServSession::DispatchMessageL(const RMessage &aMessage)
{
switch (aMessage.Function()) {
case PicoMsgLoadState:
if(!rom_data) User::Leave(-1); // no ROM
User::LeaveIfError(saveLoadGame(1));
gamestate = PGS_Running;
return;
case PicoMsgSaveState:
if(!rom_data) User::Leave(-1);
User::LeaveIfError(saveLoadGame(0));
gamestate = PGS_Running;
return;
case PicoMsgLoadROM:
loadROM();
return;
case PicoMsgResume:
if(rom_data) gamestate = PGS_Running;
return;
case PicoMsgReset:
if(rom_data) {
PicoReset();
pico_was_reset = 1;
gamestate = PGS_Running;
}
return;
case PicoMsgKeys:
gamestate = PGS_KeyConfig;
return;
case PicoMsgPause:
gamestate = PGS_Paused;
return;
case PicoMsgQuit:
DEBUGPRINT(_L("got quit msg."));
gamestate = PGS_Quit;
return;
// config change
case PicoMsgConfigChange: // launcher -> emu
changeConfig();
return;
case PicoMsgRetrieveConfig: // emu -> launcher
sendConfig();
return;
case PicoMsgRetrieveDebugStr: // emu -> launcher
sendDebug();
return;
// requests we don't understand at all are a different thing,
// so panic the client here, this function also completes the message
default:
PanicClient(EBadRequest);
return;
}
}
void CPicoServSession::loadROM()
{
TInt res;
const TAny* pD=Message().Ptr0();
// TInt desLen=Message().Client().GetDesLength(pD);
if(rom_data) {
// save SRAM for previous ROM
if(currentConfig.iFlags & 1)
saveLoadGame(0, 1);
}
RomFileName = 0;
if(rom_data) {
free(rom_data);
rom_data = 0;
}
// read the contents of the client pointer into a TPtr.
static TBuf8<KMaxFileName> writeBuf;
TRAP(res,Message().ReadL(pD,writeBuf));
if (res!=KErrNone) {
PanicClient(EBadDescriptor);
return;
}
// detect wrong extensions (.srm and .mds)
TBuf8<5> ext;
ext.Copy(writeBuf.Right(4));
ext.LowerCase();
if(!strcmp((char *)ext.PtrZ(), ".srm") || !strcmp((char *)ext.PtrZ(), "s.gz") || // .mds.gz
!strcmp((char *)ext.PtrZ(), ".mds")) {
User::Leave(3);
return;
}
FILE *rom = fopen((char *) writeBuf.PtrZ(), "rb");
if(!rom) {
DEBUGPRINT(_L("failed to open rom."));
User::Leave(1);
return;
}
unsigned int rom_size = 0;
// zipfile support
if(!strcmp((char *)ext.PtrZ(), ".zip")) {
fclose(rom);
res = CartLoadZip((const char *) writeBuf.PtrZ(), &rom_data, &rom_size);
if(res) {
User::Leave(res);
return;
}
} else {
if( (res = PicoCartLoad(rom, &rom_data, &rom_size)) ) {
DEBUGPRINT(_L("PicoCartLoad() failed."));
fclose(rom);
User::Leave(2);
return;
}
fclose(rom);
}
// detect wrong files (Pico crashes on very small files), also see if ROM EP is good
if(rom_size <= 0x200 || strncmp((char *)rom_data, "Pico", 4) == 0 ||
((*(TUint16 *)(rom_data+4)<<16)|(*(TUint16 *)(rom_data+6))) >= (int)rom_size) {
free(rom_data);
rom_data = 0;
User::Leave(3); // not a ROM
}
DEBUGPRINT(_L("PicoCartInsert(0x%08X, %d);"), rom_data, rom_size);
if(PicoCartInsert(rom_data, rom_size)) {
User::Leave(2);
return;
}
pico_was_reset = 1;
// global ROM file name for later use
RomFileName = (const char *) writeBuf.PtrZ();
// load SRAM for this ROM
if(currentConfig.iFlags & 1)
saveLoadGame(1, 1);
// debug
#ifdef __DEBUG_PRINT
TInt cells = User::CountAllocCells();
TInt mem;
User::AllocSize(mem);
DEBUGPRINT(_L("comm: cels=%d, size=%d KB"), cells, mem/1024);
gamestate = PGS_DebugHeap;
gamestate_prev = PGS_Running;
#else
gamestate = PGS_Running;
#endif
}
void CPicoServSession::changeConfig()
{
DEBUGPRINT(_L("got new config."));
// receve it
const TAny* pD=Message().Ptr0();
TPtr8 descr((TUint8*) &currentConfig, sizeof(currentConfig));
TRAPD(res,Message().ReadL(pD, descr));
if (res!=KErrNone) {
PanicClient(EBadDescriptor);
return;
}
// Motorola: enable experimental volume control
if((machineUid&0xfffffff0) == 0x101f6b20) { // Motorolas
if(currentConfig.iFlags & 0x40) {
currentConfig.iKeyBinds[11] = 0x00100000; // vol up
currentConfig.iKeyBinds[12] = 0x00200000; // vol down
keyConfigMotA[11].flags |= 0x40; // add "not configurable" flag
keyConfigMotA[12].flags |= 0x40;
} else {
currentConfig.iKeyBinds[11] &= ~0x00100000; // remove vol actions
currentConfig.iKeyBinds[12] &= ~0x00200000;
keyConfigMotA[11].flags &= ~0x40; // remove "not configurable" flag
keyConfigMotA[12].flags &= ~0x40;
}
}
// set region, PicoOpt and rate
PicoRegionOverride = currentConfig.PicoRegion;
PicoOpt = currentConfig.iPicoOpt;
switch((currentConfig.iFlags>>3)&3) {
case 1: PsndRate=11025; break;
case 2: PsndRate=16000; break;
case 3: PsndRate=22050; break;
default: PsndRate= 8000; break;
}
// 6 button pad, enable XYZM config if needed
if(PicoOpt & 0x20) {
actionNames[8] = "Z";
actionNames[9] = "Y";
actionNames[10] = "X";
actionNames[11] = "MODE";
} else {
actionNames[8] = actionNames[9] = actionNames[10] = actionNames[11] = 0;
}
// if we are in center 90||270 modes, we can bind renderer switcher
if(currentConfig.iScreenMode == TPicoConfig::PMCenter &&
(currentConfig.iScreenRotation == TPicoConfig::PRot90 || currentConfig.iScreenRotation == TPicoConfig::PRot270))
actionNames[25] = "RENDERER";
else actionNames[25] = 0;
}
void CPicoServSession::sendConfig()
{
// send current config to client
currentConfig.iPicoOpt = PicoOpt;
TPtrC8 descr((TUint8*) &currentConfig, sizeof(currentConfig));
Write(Message().Ptr0(), descr);
}
#ifdef __DEBUG_PRINT
extern "C" char *debugString();
#endif
void CPicoServSession::sendDebug()
{
#ifdef __DEBUG_PRINT
char *str = debugString();
// send current config to client
currentConfig.iPicoOpt = PicoOpt;
TPtrC8 descr((TUint8*) str, 1024);
Write(Message().Ptr0(), descr);
#endif
}
// panic the client
void CPicoServSession::PanicClient(TInt aPanic) const
{
Panic(_L("PicoN client"), aPanic);
// client screwed up - there is nothing for us to do now
RProcess me;
me.Terminate(1);
}
// write to the client thread; if unsuccessful, panic the client
void CPicoServSession::Write(const TAny* aPtr,const TDesC8& aDes,TInt anOffset)
{
TRAPD(ret,WriteL(aPtr,aDes,anOffset);)
if (ret!=KErrNone)
PanicClient(EBadDescriptor);
}
//**********************************
//Global functions
//**********************************
// The server thread.
TInt CPicoServServer::ThreadFunction(TAny* anArg)
{
// install our exception hanler first
RThread().SetExceptionHandler(&ExceptionHandler, -1);
// convert argument into semaphore reference
// RSemaphore& semaphore=*(RSemaphore *)anArg;
// start scheduler and server
CActiveScheduler *pA=new CActiveScheduler;
__ASSERT_ALWAYS(pA!=NULL,PanicServer(EMainSchedulerError));
CActiveScheduler::Install(pA);
//CTrapCleanup::New(); // docs say this is created automatically, but I somehow got E32USER-CBase 69 panic
CPicoServServer::New();
// signal that we've started
// semaphore.Signal();
// start fielding requests from clients
CActiveScheduler::Start();
// finished
return(KErrNone);
}
// Panic the server
//GLDEF_C
void PanicServer(TPicoServPanic aPanic)
{
User::Panic(_L("PicoN server"),aPanic);
}
// Create the server thread
// This function is exported from the DLL and called from the client
//EXPORT_C
TInt StartThread()
{
TInt res=KErrNone;
// create server - if one of this name does not already exist
TFindServer findPicoServer(KServerName);
TFullName name;
if(findPicoServer.Next(name) == KErrNone) return -1; // we already exist
RThread thread;
// RSemaphore semaphore;
// semaphore.CreateLocal(0); // create a semaphore so we know when thread finished
res=thread.Create(KServerName, // create new server thread
CPicoServServer::ThreadFunction, // thread's main function
KDefaultStackSize,
KMinHeapSize,
KPicoMaxHeapSize,
// &semaphore // passed as TAny* argument to thread function
0
);
if(res==KErrNone) { // thread created ok - now start it going
thread.SetPriority(EPriorityNormal);
thread.Resume(); // start it going
// semaphore.Wait(); // wait until it's initialized
thread.Close(); // we're no longer interested in the other thread
}
// semaphore.Close();
return res;
}