]> git.vomp.tv Git - vompclient.git/blob - main.cc
Preparations for dynamic mode switching
[vompclient.git] / main.cc
1 /*\r
2     Copyright 2004-2005 Chris Tallon\r
3 \r
4     This file is part of VOMP.\r
5 \r
6     VOMP is free software; you can redistribute it and/or modify\r
7     it under the terms of the GNU General Public License as published by\r
8     the Free Software Foundation; either version 2 of the License, or\r
9     (at your option) any later version.\r
10 \r
11     VOMP is distributed in the hope that it will be useful,\r
12     but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
14     GNU General Public License for more details.\r
15 \r
16     You should have received a copy of the GNU General Public License\r
17     along with VOMP; if not, write to the Free Software\r
18     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
19 */\r
20 \r
21 #include <stdio.h>\r
22 #include <stdlib.h>\r
23 #include <string.h>\r
24 #include <signal.h>\r
25 #ifndef WIN32\r
26 #include <unistd.h>\r
27 #include <endian.h>\r
28 #endif\r
29 \r
30 #include "defines.h"\r
31 \r
32 #ifdef HANDLE_VT_SWITCHING\r
33 #include <signal.h>\r
34 #include <sys/ioctl.h>\r
35 #include <linux/vt.h>\r
36 #endif\r
37 #include "log.h"\r
38 #include "timers.h"\r
39 #include "vdr.h"\r
40 #include "boxstack.h"\r
41 #include "command.h"\r
42 \r
43 \r
44 #ifdef VOMP_PLATTFORM_MVP\r
45 \r
46 \r
47 #include "mtdmvp.h"\r
48 #include "remotemvp.h"\r
49 #include "ledmvp.h"\r
50 #include "osdmvp.h"\r
51 #include "audiomvp.h"\r
52 #include "videomvp.h"\r
53 \r
54 extern "C"\r
55 {\r
56   int ticonfig_main(int, char**);\r
57 }\r
58 \r
59 #endif\r
60 \r
61 #ifdef VOMP_PLATTFORM_NMT\r
62 \r
63 #include "mtdnmt.h"\r
64 #include "remotelirc.h"\r
65 #include "lednmt.h"\r
66 #include "osddirectfb.h"\r
67 #include "audionmt.h"\r
68 #include "videonmt.h"\r
69 \r
70 #endif\r
71 \r
72 #ifdef VOMP_PLATTFORM_RASPBERRY\r
73 \r
74 #include "mtdraspberry.h"\r
75 #include "remotelinux.h"\r
76 #include "ledraspberry.h"\r
77 #include "osdopenvg.h"\r
78 #include "audioomx.h"\r
79 #include "videoomx.h"\r
80 \r
81 #endif\r
82 \r
83 \r
84 \r
85 \r
86 #include "wol.h"\r
87 #include "vsleeptimer.h"\r
88 \r
89 \r
90 #ifndef WIN32\r
91 void sighandler(int signalReceived);\r
92 #endif\r
93 \r
94 void shutdown(int code);\r
95 \r
96 \r
97 \r
98 // Global variables --------------------------------------------------------------------------------------------------\r
99 Log* logger;\r
100 Remote* remote;\r
101 Mtd* mtd;\r
102 Led* led;\r
103 Osd* osd;\r
104 Timers* timers;\r
105 BoxStack* boxstack;\r
106 Command* command;\r
107 VDR* vdr;\r
108 Video* video;\r
109 Audio* audio;\r
110 Wol* wol;\r
111 Sleeptimer* sleeptimer;\r
112 \r
113 #ifdef HANDLE_VT_SWITCHING\r
114 int fdtty;\r
115 struct vt_mode old_vtmode;\r
116 #endif\r
117 \r
118 // Linux MVP main function and sighandler\r
119 #ifndef WIN32\r
120 int main(int argc, char** argv)\r
121 {\r
122 #ifdef VOMP_PLATTFORM_MVP\r
123   if (strstr(argv[0], "ticonfig")) return ticonfig_main(argc, argv);\r
124 #endif\r
125 \r
126   bool daemonize = true;\r
127   bool debugEnabled = false;\r
128   bool crashed = false;\r
129   char* setServer = NULL;\r
130   int c;\r
131 \r
132   while ((c = getopt(argc, argv, "cdns:")) != -1)\r
133   {\r
134     switch (c)\r
135     {\r
136       case 'c':\r
137         crashed = true;\r
138         break;\r
139       case 'd':\r
140         debugEnabled = true; // and...\r
141       case 'n':\r
142         daemonize = false;\r
143         break;\r
144       case 's':\r
145         setServer = optarg;\r
146         break;\r
147       case '?':\r
148         printf("Unknown option\n");\r
149         return 1;\r
150       default:\r
151         printf("Option error\n");\r
152         return 1;\r
153     }\r
154   }\r
155 \r
156   // Init global vars ------------------------------------------------------------------------------------------------\r
157   logger     = new Log();\r
158   timers     = new Timers();\r
159   vdr        = new VDR();\r
160 \r
161   mtd        = new Mtd_TYPE();\r
162   remote     = new Remote_TYPE();\r
163   led        = new Led_TYPE();\r
164   osd        = new Osd_TYPE();\r
165   audio      = new Audio_TYPE();\r
166   video      = new Video_TYPE();\r
167 \r
168 \r
169 \r
170   boxstack   = new BoxStack();\r
171   command    = new Command();\r
172   wol        = new Wol();\r
173   sleeptimer = new Sleeptimer();\r
174 \r
175   if (!logger || !remote || !mtd || !led || !osd || !video || !audio || !boxstack || !command || !wol || !sleeptimer)\r
176   {\r
177     printf("Could not create objects. Memory problems?\n");\r
178     shutdown(1);\r
179   }\r
180 \r
181   // Get logging module started --------------------------------------------------------------------------------------\r
182 \r
183   if (!logger->init(Log::DEBUG, "dummy", debugEnabled ? 1 : 0))\r
184   {\r
185     printf("Could not initialise log object. Aborting.\n");\r
186     shutdown(1);\r
187   }\r
188 \r
189   logger->log("Core", Log::INFO, "Starting up...");\r
190 \r
191   // Daemonize if not -d\r
192 \r
193   if (daemonize)\r
194   {\r
195     // Fork away\r
196     pid_t forkTest = fork();\r
197     if (forkTest == -1)\r
198     { printf("Cannot fork (1).\n"); exit(1); }\r
199     if (forkTest != 0) _exit(0); // PID returned, I am the parent\r
200     // otherwise, I am the child\r
201     setsid();\r
202     forkTest = fork();\r
203     if (forkTest == -1)\r
204     { printf("Cannot fork (2).\n"); exit(1); }\r
205     if (forkTest != 0) _exit(0); // PID returned, I am the parent\r
206     // otherwise, I am the child\r
207     close(0);\r
208     close(1);\r
209     close(2);\r
210   }\r
211 \r
212   // Set up signal handling ------------------------------------------------------------------------------------------\r
213 \r
214   sighandler_t sigtest;\r
215 \r
216   sigtest = signal(SIGPIPE, SIG_IGN);\r
217   if (sigtest == SIG_ERR)\r
218   {\r
219     logger->log("Core", Log::EMERG, "Could not set up signal handler for SIGPIPE. Aborting.");\r
220     shutdown(1);\r
221   }\r
222   sigtest = signal(SIGINT, sighandler);\r
223   if (sigtest == SIG_ERR)\r
224   {\r
225     logger->log("Core", Log::EMERG, "Could not set up signal handler for SIGINT. Aborting.");\r
226     shutdown(1);\r
227   }\r
228   sigtest = signal(SIGTERM, sighandler);\r
229   if (sigtest == SIG_ERR)\r
230   {\r
231     logger->log("Core", Log::EMERG, "Could not set up signal handler for SIGTERM. Aborting.");\r
232     shutdown(1);\r
233   }\r
234   sigtest = signal(SIGUSR1, sighandler);\r
235   if (sigtest == SIG_ERR)\r
236   {\r
237     logger->log("Core", Log::EMERG, "Could not set up signal handler for SIGUSR1. Aborting.");\r
238     shutdown(1);\r
239   }\r
240 /*\r
241   sigtest = signal(SIGUSR2, sighandler);\r
242   if (sigtest == SIG_ERR)\r
243   {\r
244     logger->log("Core", Log::EMERG, "Could not set up signal handler for SIGUSR2. Aborting.");\r
245     shutdown(1);\r
246   }\r
247 */\r
248   sigtest = signal(SIGURG, sighandler);\r
249   if (sigtest == SIG_ERR)\r
250   {\r
251     logger->log("Core", Log::EMERG, "Could not set up signal handler for SIGURG. Aborting.");\r
252     shutdown(1);\r
253   }\r
254 \r
255   logger->log("Core", Log::INFO, "Signal handlers set up successfully");\r
256 \r
257 #ifdef HANDLE_VT_SWITCHING\r
258   if ((fdtty = open("/dev/tty", O_WRONLY),0) == -1) {\r
259           logger->log("Core", Log::EMERG, "Could not open /dev/tty. Please change permissions");\r
260   } else {\r
261           int free_vt;\r
262           if (ioctl(fdtty,VT_OPENQRY,&free_vt)==-1 || free_vt==-1){\r
263                   logger->log("Core", Log::EMERG, "Could not retrieve free virtual console, please change permissions");\r
264           } else {\r
265                   ioctl(fdtty,VT_ACTIVATE,free_vt);\r
266                   ioctl(fdtty,VT_WAITACTIVE,free_vt);\r
267                   ioctl(fdtty, VT_LOCKSWITCH, 1);\r
268           }\r
269   }\r
270 \r
271 #endif\r
272 \r
273   // Init modules ----------------------------------------------------------------------------------------------------\r
274   int success;\r
275 \r
276   success = remote->init(RemoteStartDev);\r
277 \r
278   if (success)\r
279   {\r
280     logger->log("Core", Log::INFO, "Remote module initialised");\r
281   }\r
282   else\r
283   {\r
284     logger->log("Core", Log::EMERG, "Remote module failed to initialise");\r
285     shutdown(1);\r
286   }\r
287 #ifdef VOMP_PLATTFORM_MVP\r
288   success = led->init(((RemoteMVP*)remote)->getDevice());\r
289 #else\r
290   success = led->init(-1);\r
291 #endif\r
292   if (success)\r
293   {\r
294     logger->log("Core", Log::INFO, "LED module initialised");\r
295   }\r
296   else\r
297   {\r
298     logger->log("Core", Log::EMERG, "LED module failed to initialise");\r
299     shutdown(1);\r
300   }\r
301 \r
302   success = mtd->init();\r
303   if (success)\r
304   {\r
305     logger->log("Core", Log::INFO, "Mtd module initialised");\r
306   }\r
307   else\r
308   {\r
309     logger->log("Core", Log::EMERG, "Mtd module failed to initialise");\r
310     shutdown(1);\r
311   }\r
312 \r
313   success = timers->init();\r
314   if (success)\r
315   {\r
316     logger->log("Core", Log::INFO, "Timers module initialised");\r
317   }\r
318   else\r
319   {\r
320     logger->log("Core", Log::EMERG, "Timers module failed to initialise");\r
321     shutdown(1);\r
322   }\r
323 \r
324   UCHAR videoFormat = (UCHAR)mtd->getPALorNTSC();\r
325   if      (videoFormat == Video::PAL)  logger->log("Core", Log::INFO, "Read from MTD: PAL 720x576");\r
326   else if (videoFormat == Video::NTSC) logger->log("Core", Log::INFO, "Read from MTD: NTSC 720x480");\r
327   else                                 logger->log("Core", Log::INFO, "No help from MTD. Assuming NTSC 720x480");\r
328 \r
329   success = video->init(videoFormat);\r
330   if (success)\r
331   {\r
332     logger->log("Core", Log::INFO, "Video module initialised");\r
333   }\r
334   else\r
335   {\r
336     logger->log("Core", Log::EMERG, "Video module failed to initialise");\r
337     shutdown(1);\r
338   }\r
339 \r
340   success = osd->init((void*)OsdStartDev);\r
341   if (success)\r
342   {\r
343     logger->log("Core", Log::INFO, "OSD module initialised");\r
344   }\r
345   else\r
346   {\r
347     logger->log("Core", Log::EMERG, "OSD module failed to initialise");\r
348     shutdown(1);\r
349   }\r
350 \r
351   success = audio->init(Audio::MPEG2_PES);\r
352   if (success)\r
353   {\r
354     logger->log("Core", Log::INFO, "Audio module initialised");\r
355   }\r
356   else\r
357   {\r
358     logger->log("Core", Log::EMERG, "Audio module failed to initialise");\r
359     shutdown(1);\r
360   }\r
361 \r
362   success = vdr->init(3024);\r
363   if (success)\r
364   {\r
365     logger->log("Core", Log::INFO, "VDR module initialised");\r
366   }\r
367   else\r
368   {\r
369     logger->log("Core", Log::EMERG, "VDR module failed to initialise");\r
370     shutdown(1);\r
371   }\r
372 \r
373   success = boxstack->init();\r
374   if (success)\r
375   {\r
376     logger->log("Core", Log::INFO, "BoxStack module initialised");\r
377   }\r
378   else\r
379   {\r
380     logger->log("Core", Log::EMERG, "BoxStack module failed to initialise");\r
381     shutdown(1);\r
382   }\r
383 \r
384   success = command->init(crashed, setServer);\r
385   if (success)\r
386   {\r
387     logger->log("Core", Log::INFO, "Command module initialised");\r
388   }\r
389   else\r
390   {\r
391     logger->log("Core", Log::EMERG, "Command module failed to initialise");\r
392     shutdown(1);\r
393   }\r
394 \r
395   // Other init ------------------------------------------------------------------------------------------------------\r
396 \r
397   logger->log("Core", Log::NOTICE, "Startup successful");\r
398 \r
399   // Run main loop ---------------------------------------------------------------------------------------------------\r
400 \r
401   // Ok, all major device components and other bits are loaded and ready\r
402   command->run();\r
403 \r
404   // When that returns quit ------------------------------------------------------------------------------------------\r
405 \r
406   shutdown(0);\r
407   return 0;\r
408 }\r
409 \r
410 // -------------------------------------------------------------------------------------------------------------------\r
411 \r
412 void sighandler(int signalReceived)\r
413 {\r
414   logger->log("Core", Log::NOTICE, "Signal %i received", signalReceived);\r
415 \r
416   switch (signalReceived)\r
417   {\r
418     case SIGINT:\r
419     {\r
420       logger->log("Core", Log::NOTICE, "Interrupt signal, shutting down...");\r
421       command->stop(); // FIXME this is probably not safe - use the messaging system / is that even safe?\r
422       break;\r
423     }\r
424     case SIGTERM:\r
425     {\r
426       logger->log("Core", Log::NOTICE, "Term signal, shutting down...");\r
427       command->stop(); // FIXME this is probably not safe - use the messaging system / is that even safe?\r
428       break;\r
429     }\r
430     case SIGUSR1:\r
431     {\r
432       command->sig1();\r
433       break;\r
434     }\r
435 /*\r
436     case SIGUSR1:\r
437     {\r
438       logger->log("Core", Log::DEBUG, "SIGUSR1 caught");\r
439       logger->upLogLevel();\r
440       break;\r
441     }\r
442     case SIGUSR2:\r
443     {\r
444       logger->log("Core", Log::DEBUG, "SIGUSR2 caught");\r
445       logger->downLogLevel();\r
446       break;\r
447     }\r
448 */\r
449     case SIGURG:\r
450     {\r
451       logger->log("Core", Log::DEBUG, "SIGURG caught");\r
452       break;\r
453     }\r
454   }\r
455 }\r
456 #endif\r
457 \r
458 // -------------------------------------------------------------------------------------------------------------------\r
459 \r
460 void shutdown(int code)\r
461 {\r
462   if (boxstack)\r
463   {\r
464     boxstack->shutdown();\r
465     delete boxstack;\r
466     logger->log("Core", Log::NOTICE, "BoxStack module shut down");\r
467   }\r
468 \r
469   // FIXME, send a del all to boxstack first, then get rid of it after command?\r
470   if (command) // shut down command here in case views have posted messages\r
471   {\r
472     command->shutdown();\r
473     delete command;\r
474     logger->log("Core", Log::NOTICE, "Command module shut down");\r
475   }\r
476 \r
477   if (vdr)\r
478   {\r
479     vdr->shutdown();\r
480     delete vdr;\r
481     logger->log("Core", Log::NOTICE, "VDR module shut down");\r
482   }\r
483 \r
484   if (osd)\r
485   {\r
486     osd->shutdown();\r
487     delete osd;\r
488     logger->log("Core", Log::NOTICE, "OSD module shut down");\r
489   }\r
490 \r
491   if (audio)\r
492   {\r
493     audio->shutdown();\r
494     delete audio;\r
495     logger->log("Core", Log::NOTICE, "Audio module shut down");\r
496   }\r
497 \r
498   if (video)\r
499   {\r
500     video->shutdown();\r
501     delete video;\r
502     logger->log("Core", Log::NOTICE, "Video module shut down");\r
503   }\r
504 \r
505   if (timers)\r
506   {\r
507     timers->shutdown();\r
508     delete timers;\r
509     logger->log("Core", Log::NOTICE, "Timers module shut down");\r
510   }\r
511 \r
512   if (mtd)\r
513   {\r
514     mtd->shutdown();\r
515     delete mtd;\r
516     logger->log("Core", Log::NOTICE, "MTD module shut down");\r
517   }\r
518 \r
519   if (led)\r
520   {\r
521     led->shutdown();\r
522     delete led;\r
523     logger->log("Core", Log::NOTICE, "LED module shut down");\r
524   }\r
525 \r
526   if (remote)\r
527   {\r
528     remote->shutdown();\r
529     delete remote;\r
530     logger->log("Core", Log::NOTICE, "Remote module shut down");\r
531   }\r
532 \r
533   if (wol)\r
534   {\r
535     delete wol;\r
536     logger->log("Core", Log::NOTICE, "WOL module shut down");\r
537   }\r
538 \r
539   if (sleeptimer)\r
540   {\r
541     delete sleeptimer;\r
542     logger->log("Core", Log::NOTICE, "Sleeptimer module shut down");\r
543   }\r
544 #ifdef HANDLE_VT_SWITCHING\r
545   ioctl(fdtty, VT_UNLOCKSWITCH, 1);\r
546   close(fdtty);\r
547 #endif\r
548 \r
549   if (logger)\r
550   {\r
551     logger->log("Core", Log::NOTICE, "Log module shutting down... bye!\n\n");\r
552     logger->shutdown();\r
553     delete logger;\r
554   }\r
555 \r
556   exit(code);\r
557 }\r
558 \r
559 // -------------------------------------------------------------------------------------------------------------------\r
560 \r
561 ULLONG htonll(ULLONG a)\r
562 {\r
563   #if BYTE_ORDER == BIG_ENDIAN\r
564     return a;\r
565   #else\r
566     ULLONG b = 0;\r
567 \r
568     b = ((a << 56) & 0xFF00000000000000ULL)\r
569       | ((a << 40) & 0x00FF000000000000ULL)\r
570       | ((a << 24) & 0x0000FF0000000000ULL)\r
571       | ((a <<  8) & 0x000000FF00000000ULL)\r
572       | ((a >>  8) & 0x00000000FF000000ULL)\r
573       | ((a >> 24) & 0x0000000000FF0000ULL)\r
574       | ((a >> 40) & 0x000000000000FF00ULL)\r
575       | ((a >> 56) & 0x00000000000000FFULL) ;\r
576 \r
577     return b;\r
578   #endif\r
579 }\r
580 \r
581 ULLONG ntohll(ULLONG a)\r
582 {\r
583   return htonll(a);\r
584 }\r
585 \r
586 void MILLISLEEP(ULONG a)\r
587 {\r
588 #ifndef WIN32\r
589   struct timespec delayTime;\r
590   delayTime.tv_sec = a / 1000;\r
591   delayTime.tv_nsec = (a % 1000) * 1000000;\r
592   nanosleep(&delayTime, NULL);\r
593 #else\r
594   Sleep(a);\r
595 #endif\r
596 }\r
597 \r
598 long long getTimeMS() {\r
599         struct timespec ts;\r
600         clock_gettime(VOMP_LINUX_CLOCK, &ts);\r
601         return ts.tv_sec*1000+ts.tv_nsec/1000000LL;\r
602 }\r
603 \r
604 int min(UINT a, int b)\r
605 {\r
606   if (a > b) return b;\r
607   else return a;\r
608 }\r
609 \r
610 int max(int a, int b)\r
611 {\r
612   if (a > b) return a;\r
613   else return b;\r
614 }\r
615 \r