bugfix
[picodrive.git] / platform / uiq2 / SimpleServer.cpp
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();\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*) &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
316 void 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
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