reset behavior changed, Puggsy detection added
[picodrive.git] / platform / uiq2 / SimpleServer.cpp
CommitLineData
cc68a136 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
16extern TInt machineUid;\r
17extern int gamestate, gamestate_prev;\r
18extern TPicoConfig currentConfig;\r
19extern TPicoKeyConfigEntry keyConfigMotA[];\r
20extern const char *actionNames[];\r
21const char *RomFileName = 0;\r
22int pico_was_reset = 0;\r
23\r
24\r
25// utility\r
26unsigned 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
37CPicoServServer::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
44void 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
53CSharableSession *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
71CPicoServSession::CPicoServSession(RThread &aClient, CPicoServServer *aServer)\r
72: CSession(aClient), rom_data(0)\r
73{\r
74// iPicoSvr=aServer;\r
75}\r
76\r
77CPicoServSession* CPicoServSession::NewL(RThread &aClient, CPicoServServer * aServer)\r
78{\r
79 return new(ELeave) CPicoServSession(aClient,aServer);\r
80}\r
81\r
82\r
83void 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
92void 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
1cb1584b 117 PicoReset();\r
cc68a136 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
158void 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
260void 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*) &currentConfig, 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
316void CPicoServSession::sendConfig()\r
317{\r
318 // send current config to client\r
319 currentConfig.iPicoOpt = PicoOpt;\r
320 TPtrC8 descr((TUint8*) &currentConfig, sizeof(currentConfig));\r
321 Write(Message().Ptr0(), descr);\r
322}\r
323\r
324#ifdef __DEBUG_PRINT\r
325extern "C" char *debugString();\r
326#endif\r
327\r
328void 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
340void 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
350void 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
365TInt 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
390void 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
399TInt 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