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 |
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 |