| 1 | // SimpleServer.cpp\r |
| 2 | \r |
| 3 | #include <e32svr.h>\r |
| 4 | #include <e32math.h>\r |
| 5 | #include <e32uid.h>\r |
| 6 | \r |
| 7 | #include <string.h>\r |
| 8 | \r |
| 9 | #include "debug.h"\r |
| 10 | \r |
| 11 | #include "version.h"\r |
| 12 | #include "ClientServer.h"\r |
| 13 | #include "SimpleServer.h"\r |
| 14 | #include "pico\picoInt.h"\r |
| 15 | \r |
| 16 | extern TInt machineUid;\r |
| 17 | extern int gamestate, gamestate_prev;\r |
| 18 | extern TPicoConfig currentConfig;\r |
| 19 | extern TPicoKeyConfigEntry keyConfigMotA[];\r |
| 20 | extern const char *actionNames[];\r |
| 21 | const char *RomFileName = 0;\r |
| 22 | int pico_was_reset = 0;\r |
| 23 | \r |
| 24 | \r |
| 25 | // utility\r |
| 26 | unsigned int bigend(unsigned int l)\r |
| 27 | {\r |
| 28 | return (l>>24)|((l>>8)&0xff00)|((l<<8)&0xff0000)|(l<<24);\r |
| 29 | }\r |
| 30 | \r |
| 31 | \r |
| 32 | //**********************************\r |
| 33 | //CPicoServServer\r |
| 34 | //**********************************\r |
| 35 | \r |
| 36 | \r |
| 37 | CPicoServServer::CPicoServServer(TInt aPriority)\r |
| 38 | : CServer(aPriority)\r |
| 39 | {\r |
| 40 | }\r |
| 41 | \r |
| 42 | \r |
| 43 | // Create and start a new count server.\r |
| 44 | void CPicoServServer::New()\r |
| 45 | {\r |
| 46 | CPicoServServer *pS=new CPicoServServer(EPriority);\r |
| 47 | __ASSERT_ALWAYS(pS!=NULL,PanicServer(ESvrCreateServer));\r |
| 48 | pS->StartL(KServerName);\r |
| 49 | }\r |
| 50 | \r |
| 51 | \r |
| 52 | // Create a new server session.\r |
| 53 | CSharableSession *CPicoServServer::NewSessionL(const TVersion &aVersion) const\r |
| 54 | {\r |
| 55 | // check we're the right version\r |
| 56 | TVersion v(KPicoMajorVersionNumber,KPicoMinorVersionNumber,0);\r |
| 57 | if (!User::QueryVersionSupported(v,aVersion))\r |
| 58 | User::Leave(KErrNotSupported);\r |
| 59 | // make new session\r |
| 60 | RThread aClient = Message().Client();\r |
| 61 | return CPicoServSession::NewL(aClient, (CPicoServServer*)this);\r |
| 62 | }\r |
| 63 | \r |
| 64 | \r |
| 65 | //**********************************\r |
| 66 | //CPicoServSession\r |
| 67 | //**********************************\r |
| 68 | \r |
| 69 | \r |
| 70 | // constructor - must pass client to CSession\r |
| 71 | CPicoServSession::CPicoServSession(RThread &aClient, CPicoServServer *aServer)\r |
| 72 | : CSession(aClient), rom_data(0)\r |
| 73 | {\r |
| 74 | // iPicoSvr=aServer;\r |
| 75 | }\r |
| 76 | \r |
| 77 | CPicoServSession* CPicoServSession::NewL(RThread &aClient, CPicoServServer * aServer)\r |
| 78 | {\r |
| 79 | return new(ELeave) CPicoServSession(aClient,aServer);\r |
| 80 | }\r |
| 81 | \r |
| 82 | \r |
| 83 | void CPicoServSession::ServiceL(const RMessage& aMessage)\r |
| 84 | {\r |
| 85 | TRAPD(err,DispatchMessageL(aMessage));\r |
| 86 | aMessage.Complete(err);\r |
| 87 | }\r |
| 88 | \r |
| 89 | \r |
| 90 | \r |
| 91 | // service a client request; test the opcode and then do appropriate servicing\r |
| 92 | void CPicoServSession::DispatchMessageL(const RMessage &aMessage)\r |
| 93 | {\r |
| 94 | switch (aMessage.Function()) {\r |
| 95 | case PicoMsgLoadState: \r |
| 96 | if(!rom_data) User::Leave(-1); // no ROM\r |
| 97 | User::LeaveIfError(saveLoadGame(1));\r |
| 98 | gamestate = PGS_Running;\r |
| 99 | return;\r |
| 100 | \r |
| 101 | case PicoMsgSaveState:\r |
| 102 | if(!rom_data) User::Leave(-1);\r |
| 103 | User::LeaveIfError(saveLoadGame(0));\r |
| 104 | gamestate = PGS_Running;\r |
| 105 | return;\r |
| 106 | \r |
| 107 | case PicoMsgLoadROM:\r |
| 108 | loadROM();\r |
| 109 | return;\r |
| 110 | \r |
| 111 | case PicoMsgResume:\r |
| 112 | if(rom_data) gamestate = PGS_Running;\r |
| 113 | return;\r |
| 114 | \r |
| 115 | case PicoMsgReset: \r |
| 116 | if(rom_data) {\r |
| 117 | PicoReset(0);\r |
| 118 | pico_was_reset = 1;\r |
| 119 | gamestate = PGS_Running;\r |
| 120 | }\r |
| 121 | return;\r |
| 122 | \r |
| 123 | case PicoMsgKeys:\r |
| 124 | gamestate = PGS_KeyConfig;\r |
| 125 | return;\r |
| 126 | \r |
| 127 | case PicoMsgPause:\r |
| 128 | gamestate = PGS_Paused;\r |
| 129 | return;\r |
| 130 | \r |
| 131 | case PicoMsgQuit:\r |
| 132 | DEBUGPRINT(_L("got quit msg."));\r |
| 133 | gamestate = PGS_Quit;\r |
| 134 | return;\r |
| 135 | \r |
| 136 | // config change\r |
| 137 | case PicoMsgConfigChange: // launcher -> emu\r |
| 138 | changeConfig();\r |
| 139 | return;\r |
| 140 | \r |
| 141 | case PicoMsgRetrieveConfig: // emu -> launcher\r |
| 142 | sendConfig();\r |
| 143 | return;\r |
| 144 | \r |
| 145 | case PicoMsgRetrieveDebugStr: // emu -> launcher\r |
| 146 | sendDebug();\r |
| 147 | return;\r |
| 148 | \r |
| 149 | // requests we don't understand at all are a different thing,\r |
| 150 | // so panic the client here, this function also completes the message\r |
| 151 | default:\r |
| 152 | PanicClient(EBadRequest);\r |
| 153 | return;\r |
| 154 | }\r |
| 155 | }\r |
| 156 | \r |
| 157 | \r |
| 158 | void CPicoServSession::loadROM()\r |
| 159 | {\r |
| 160 | TInt res;\r |
| 161 | \r |
| 162 | const TAny* pD=Message().Ptr0();\r |
| 163 | \r |
| 164 | // TInt desLen=Message().Client().GetDesLength(pD);\r |
| 165 | \r |
| 166 | if(rom_data) {\r |
| 167 | // save SRAM for previous ROM\r |
| 168 | if(currentConfig.iFlags & 1)\r |
| 169 | saveLoadGame(0, 1);\r |
| 170 | }\r |
| 171 | \r |
| 172 | RomFileName = 0;\r |
| 173 | if(rom_data) {\r |
| 174 | free(rom_data);\r |
| 175 | rom_data = 0;\r |
| 176 | }\r |
| 177 | \r |
| 178 | // read the contents of the client pointer into a TPtr.\r |
| 179 | static TBuf8<KMaxFileName> writeBuf;\r |
| 180 | TRAP(res,Message().ReadL(pD,writeBuf));\r |
| 181 | if (res!=KErrNone) {\r |
| 182 | PanicClient(EBadDescriptor);\r |
| 183 | return;\r |
| 184 | }\r |
| 185 | \r |
| 186 | // detect wrong extensions (.srm and .mds)\r |
| 187 | TBuf8<5> ext;\r |
| 188 | ext.Copy(writeBuf.Right(4));\r |
| 189 | ext.LowerCase();\r |
| 190 | if(!strcmp((char *)ext.PtrZ(), ".srm") || !strcmp((char *)ext.PtrZ(), "s.gz") || // .mds.gz\r |
| 191 | !strcmp((char *)ext.PtrZ(), ".mds")) {\r |
| 192 | User::Leave(3);\r |
| 193 | return;\r |
| 194 | }\r |
| 195 | \r |
| 196 | FILE *rom = fopen((char *) writeBuf.PtrZ(), "rb");\r |
| 197 | if(!rom) {\r |
| 198 | DEBUGPRINT(_L("failed to open rom."));\r |
| 199 | User::Leave(1);\r |
| 200 | return;\r |
| 201 | }\r |
| 202 | \r |
| 203 | \r |
| 204 | unsigned int rom_size = 0;\r |
| 205 | // zipfile support\r |
| 206 | if(!strcmp((char *)ext.PtrZ(), ".zip")) {\r |
| 207 | fclose(rom);\r |
| 208 | res = CartLoadZip((const char *) writeBuf.PtrZ(), &rom_data, &rom_size);\r |
| 209 | if(res) {\r |
| 210 | User::Leave(res);\r |
| 211 | return;\r |
| 212 | }\r |
| 213 | } else {\r |
| 214 | if( (res = PicoCartLoad(rom, &rom_data, &rom_size)) ) {\r |
| 215 | DEBUGPRINT(_L("PicoCartLoad() failed."));\r |
| 216 | fclose(rom);\r |
| 217 | User::Leave(2);\r |
| 218 | return;\r |
| 219 | }\r |
| 220 | fclose(rom);\r |
| 221 | }\r |
| 222 | \r |
| 223 | // detect wrong files (Pico crashes on very small files), also see if ROM EP is good\r |
| 224 | if(rom_size <= 0x200 || strncmp((char *)rom_data, "Pico", 4) == 0 ||\r |
| 225 | ((*(TUint16 *)(rom_data+4)<<16)|(*(TUint16 *)(rom_data+6))) >= (int)rom_size) {\r |
| 226 | free(rom_data);\r |
| 227 | rom_data = 0;\r |
| 228 | User::Leave(3); // not a ROM\r |
| 229 | }\r |
| 230 | \r |
| 231 | DEBUGPRINT(_L("PicoCartInsert(0x%08X, %d);"), rom_data, rom_size);\r |
| 232 | if(PicoCartInsert(rom_data, rom_size)) {\r |
| 233 | User::Leave(2);\r |
| 234 | return;\r |
| 235 | }\r |
| 236 | \r |
| 237 | pico_was_reset = 1;\r |
| 238 | \r |
| 239 | // global ROM file name for later use\r |
| 240 | RomFileName = (const char *) writeBuf.PtrZ();\r |
| 241 | \r |
| 242 | // load SRAM for this ROM\r |
| 243 | if(currentConfig.iFlags & 1)\r |
| 244 | saveLoadGame(1, 1);\r |
| 245 | \r |
| 246 | // debug\r |
| 247 | #ifdef __DEBUG_PRINT\r |
| 248 | TInt cells = User::CountAllocCells();\r |
| 249 | TInt mem;\r |
| 250 | User::AllocSize(mem);\r |
| 251 | DEBUGPRINT(_L("comm: cels=%d, size=%d KB"), cells, mem/1024);\r |
| 252 | gamestate = PGS_DebugHeap;\r |
| 253 | gamestate_prev = PGS_Running;\r |
| 254 | #else\r |
| 255 | gamestate = PGS_Running;\r |
| 256 | #endif\r |
| 257 | }\r |
| 258 | \r |
| 259 | \r |
| 260 | void CPicoServSession::changeConfig()\r |
| 261 | {\r |
| 262 | DEBUGPRINT(_L("got new config."));\r |
| 263 | \r |
| 264 | // receve it\r |
| 265 | const TAny* pD=Message().Ptr0();\r |
| 266 | TPtr8 descr((TUint8*) ¤tConfig, sizeof(currentConfig));\r |
| 267 | TRAPD(res,Message().ReadL(pD, descr));\r |
| 268 | if (res!=KErrNone) {\r |
| 269 | PanicClient(EBadDescriptor);\r |
| 270 | return;\r |
| 271 | }\r |
| 272 | \r |
| 273 | // Motorola: enable experimental volume control\r |
| 274 | if((machineUid&0xfffffff0) == 0x101f6b20) { // Motorolas\r |
| 275 | if(currentConfig.iFlags & 0x40) {\r |
| 276 | currentConfig.iKeyBinds[11] = 0x00100000; // vol up\r |
| 277 | currentConfig.iKeyBinds[12] = 0x00200000; // vol down\r |
| 278 | keyConfigMotA[11].flags |= 0x40; // add "not configurable" flag\r |
| 279 | keyConfigMotA[12].flags |= 0x40;\r |
| 280 | } else {\r |
| 281 | currentConfig.iKeyBinds[11] &= ~0x00100000; // remove vol actions\r |
| 282 | currentConfig.iKeyBinds[12] &= ~0x00200000;\r |
| 283 | keyConfigMotA[11].flags &= ~0x40; // remove "not configurable" flag\r |
| 284 | keyConfigMotA[12].flags &= ~0x40;\r |
| 285 | }\r |
| 286 | }\r |
| 287 | \r |
| 288 | // set region, PicoOpt and rate\r |
| 289 | PicoRegionOverride = currentConfig.PicoRegion;\r |
| 290 | PicoOpt = currentConfig.iPicoOpt;\r |
| 291 | switch((currentConfig.iFlags>>3)&3) {\r |
| 292 | case 1: PsndRate=11025; break;\r |
| 293 | case 2: PsndRate=16000; break;\r |
| 294 | case 3: PsndRate=22050; break;\r |
| 295 | default: PsndRate= 8000; break;\r |
| 296 | }\r |
| 297 | \r |
| 298 | // 6 button pad, enable XYZM config if needed\r |
| 299 | if(PicoOpt & 0x20) {\r |
| 300 | actionNames[8] = "Z";\r |
| 301 | actionNames[9] = "Y";\r |
| 302 | actionNames[10] = "X";\r |
| 303 | actionNames[11] = "MODE";\r |
| 304 | } else {\r |
| 305 | actionNames[8] = actionNames[9] = actionNames[10] = actionNames[11] = 0;\r |
| 306 | }\r |
| 307 | \r |
| 308 | // if we are in center 90||270 modes, we can bind renderer switcher\r |
| 309 | if(currentConfig.iScreenMode == TPicoConfig::PMCenter &&\r |
| 310 | (currentConfig.iScreenRotation == TPicoConfig::PRot90 || currentConfig.iScreenRotation == TPicoConfig::PRot270))\r |
| 311 | actionNames[25] = "RENDERER";\r |
| 312 | else actionNames[25] = 0;\r |
| 313 | }\r |
| 314 | \r |
| 315 | \r |
| 316 | void CPicoServSession::sendConfig()\r |
| 317 | {\r |
| 318 | // send current config to client\r |
| 319 | currentConfig.iPicoOpt = PicoOpt;\r |
| 320 | TPtrC8 descr((TUint8*) ¤tConfig, sizeof(currentConfig));\r |
| 321 | Write(Message().Ptr0(), descr);\r |
| 322 | }\r |
| 323 | \r |
| 324 | #ifdef __DEBUG_PRINT\r |
| 325 | extern "C" char *debugString();\r |
| 326 | #endif\r |
| 327 | \r |
| 328 | void CPicoServSession::sendDebug()\r |
| 329 | {\r |
| 330 | #ifdef __DEBUG_PRINT\r |
| 331 | char *str = debugString();\r |
| 332 | // send current config to client\r |
| 333 | currentConfig.iPicoOpt = PicoOpt;\r |
| 334 | TPtrC8 descr((TUint8*) str, 1024);\r |
| 335 | Write(Message().Ptr0(), descr);\r |
| 336 | #endif\r |
| 337 | }\r |
| 338 | \r |
| 339 | // panic the client\r |
| 340 | void CPicoServSession::PanicClient(TInt aPanic) const\r |
| 341 | {\r |
| 342 | Panic(_L("PicoN client"), aPanic);\r |
| 343 | // client screwed up - there is nothing for us to do now\r |
| 344 | RProcess me;\r |
| 345 | me.Terminate(1);\r |
| 346 | }\r |
| 347 | \r |
| 348 | \r |
| 349 | // write to the client thread; if unsuccessful, panic the client\r |
| 350 | void CPicoServSession::Write(const TAny* aPtr,const TDesC8& aDes,TInt anOffset)\r |
| 351 | {\r |
| 352 | TRAPD(ret,WriteL(aPtr,aDes,anOffset);)\r |
| 353 | if (ret!=KErrNone)\r |
| 354 | PanicClient(EBadDescriptor);\r |
| 355 | }\r |
| 356 | \r |
| 357 | \r |
| 358 | \r |
| 359 | //**********************************\r |
| 360 | //Global functions\r |
| 361 | //**********************************\r |
| 362 | \r |
| 363 | \r |
| 364 | // The server thread.\r |
| 365 | TInt CPicoServServer::ThreadFunction(TAny* anArg)\r |
| 366 | {\r |
| 367 | // install our exception hanler first\r |
| 368 | RThread().SetExceptionHandler(&ExceptionHandler, -1);\r |
| 369 | \r |
| 370 | // convert argument into semaphore reference\r |
| 371 | // RSemaphore& semaphore=*(RSemaphore *)anArg;\r |
| 372 | \r |
| 373 | // start scheduler and server\r |
| 374 | CActiveScheduler *pA=new CActiveScheduler;\r |
| 375 | __ASSERT_ALWAYS(pA!=NULL,PanicServer(EMainSchedulerError));\r |
| 376 | CActiveScheduler::Install(pA);\r |
| 377 | //CTrapCleanup::New(); // docs say this is created automatically, but I somehow got E32USER-CBase 69 panic\r |
| 378 | CPicoServServer::New();\r |
| 379 | // signal that we've started\r |
| 380 | // semaphore.Signal();\r |
| 381 | // start fielding requests from clients\r |
| 382 | CActiveScheduler::Start();\r |
| 383 | // finished\r |
| 384 | return(KErrNone);\r |
| 385 | }\r |
| 386 | \r |
| 387 | \r |
| 388 | // Panic the server\r |
| 389 | //GLDEF_C \r |
| 390 | void PanicServer(TPicoServPanic aPanic)\r |
| 391 | {\r |
| 392 | User::Panic(_L("PicoN server"),aPanic);\r |
| 393 | }\r |
| 394 | \r |
| 395 | \r |
| 396 | // Create the server thread\r |
| 397 | // This function is exported from the DLL and called from the client \r |
| 398 | //EXPORT_C\r |
| 399 | TInt StartThread()\r |
| 400 | {\r |
| 401 | TInt res=KErrNone;\r |
| 402 | // create server - if one of this name does not already exist\r |
| 403 | TFindServer findPicoServer(KServerName);\r |
| 404 | TFullName name;\r |
| 405 | if(findPicoServer.Next(name) == KErrNone) return -1; // we already exist\r |
| 406 | \r |
| 407 | RThread thread;\r |
| 408 | // RSemaphore semaphore;\r |
| 409 | // semaphore.CreateLocal(0); // create a semaphore so we know when thread finished\r |
| 410 | res=thread.Create(KServerName, // create new server thread\r |
| 411 | CPicoServServer::ThreadFunction, // thread's main function\r |
| 412 | KDefaultStackSize,\r |
| 413 | KMinHeapSize,\r |
| 414 | KPicoMaxHeapSize,\r |
| 415 | // &semaphore // passed as TAny* argument to thread function\r |
| 416 | 0\r |
| 417 | );\r |
| 418 | \r |
| 419 | if(res==KErrNone) { // thread created ok - now start it going\r |
| 420 | thread.SetPriority(EPriorityNormal);\r |
| 421 | thread.Resume(); // start it going\r |
| 422 | // semaphore.Wait(); // wait until it's initialized\r |
| 423 | thread.Close(); // we're no longer interested in the other thread\r |
| 424 | }\r |
| 425 | \r |
| 426 | // semaphore.Close();\r |
| 427 | \r |
| 428 | return res;\r |
| 429 | }\r |
| 430 | \r |