]> git.vomp.tv Git - vompclient.git/blob - main.cc
WIP [broken]
[vompclient.git] / main.cc
1 /*
2     Copyright 2004-2020 Chris Tallon
3
4     This file is part of VOMP.
5
6     VOMP is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     VOMP is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with VOMP.  If not, see <https://www.gnu.org/licenses/>.
18 */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <signal.h>
24 #ifndef WIN32
25 #include <unistd.h>
26 #include <endian.h>
27 #endif
28 #include <thread>
29
30 #include "defines.h"
31
32 #ifdef HANDLE_VT_SWITCHING
33 #include <signal.h>
34 #include <sys/ioctl.h>
35 #include <linux/vt.h>
36 #endif
37 #include "log.h"
38 #include "timers.h"
39 #include "vdr.h"
40 #include "boxstack.h"
41 #include "command.h"
42
43 #ifdef VOMP_PLATTFORM_NMT
44
45 #include "lednmt.h"
46 #include "osddirectfb.h"
47 #include "audionmt.h"
48 #include "videonmt.h"
49
50 #endif
51
52 #ifdef VOMP_PLATFORM_RASPBERRY
53
54 #include "ledraspberry.h"
55 #include "osdopenvg.h"
56 #include "audioomx.h"
57 #include "videoomx.h"
58
59 #endif
60
61 #include "inputman.h"
62 #include "wol.h"
63 #include "vsleeptimer.h"
64
65
66 #ifndef WIN32 // FIXME do we need any if WIN32 stuff in here? windows has own winmain file
67 void threadSignalReceiverFunction();
68 #endif
69
70 void shutdown(int code);
71
72 // Global variables --------------------------------------------------------------------------------------------------
73 Log* logger;
74 InputMan* inputMan;
75 Led* led;
76 Osd* osd;
77 Timers* timers;
78 BoxStack* boxstack;
79 Command* command;
80 VDR* vdr;
81 Video* video;
82 Audio* audio;
83 Wol* wol;
84 Sleeptimer* sleeptimer;
85
86 #ifdef HANDLE_VT_SWITCHING
87 int fdtty;
88 struct vt_mode old_vtmode;
89 #endif
90
91 // Linux main function and sighandler
92 #ifndef WIN32
93 int main(int argc, char** argv)
94 {
95   bool daemonize = true;
96   bool debugEnabled = false;
97   bool crashed = false;
98   char* setServer = NULL;
99   int c;
100
101   while ((c = getopt(argc, argv, "cdns:")) != -1)
102   {
103     switch (c)
104     {
105       case 'c':
106         crashed = true;
107         break;
108       case 'd':
109         debugEnabled = true; // and...
110       case 'n':
111         daemonize = false;
112         break;
113       case 's':
114         setServer = optarg;
115         break;
116       case '?':
117         printf("Unknown option\n");
118         return 1;
119       default:
120         printf("Option error\n");
121         return 1;
122     }
123   }
124
125   // Init global vars ------------------------------------------------------------------------------------------------
126   logger     = new Log();
127   timers     = new Timers();
128   vdr        = new VDR();
129   inputMan   = new InputMan();
130
131   led        = new Led_TYPE();
132   osd        = new Osd_TYPE();
133   audio      = new Audio_TYPE();
134   video      = new Video_TYPE();
135
136   boxstack   = new BoxStack();
137   command    = new Command();
138   wol        = new Wol();
139   sleeptimer = new Sleeptimer();
140
141   if (!logger || !inputMan || !led || !osd || !video || !audio || !boxstack || !command || !wol || !sleeptimer)
142   {
143     printf("Could not create objects. Memory problems?\n");
144     shutdown(1);
145   }
146
147   // Get logging module started --------------------------------------------------------------------------------------
148
149   if (!logger->init(Log::DEBUG, "dummy", debugEnabled ? 1 : 0))
150   {
151     printf("Could not initialise log object. Aborting.\n");
152     shutdown(1);
153   }
154
155   logger->log("Core", Log::INFO, "Starting up...");
156
157   // Daemonize if not -d
158
159   if (daemonize)
160   {
161     // Fork away
162     pid_t forkTest = fork();
163     if (forkTest == -1)
164     { printf("Cannot fork (1).\n"); exit(1); }
165     if (forkTest != 0) _exit(0); // PID returned, I am the parent
166     // otherwise, I am the child
167     setsid();
168     forkTest = fork();
169     if (forkTest == -1)
170     { printf("Cannot fork (2).\n"); exit(1); }
171     if (forkTest != 0) _exit(0); // PID returned, I am the parent
172     // otherwise, I am the child
173     close(0);
174     close(1);
175     close(2);
176   }
177
178   // Set up signal handling ------------------------------------------------------------------------------------------
179
180   // Block all signals
181   sigset_t set;
182   sigfillset(&set);
183   int sigBlockResult = pthread_sigmask(SIG_SETMASK, &set, NULL);
184   if (sigBlockResult)
185   {
186     logger->log("Core", Log::EMERG, "Could not block signals: %i", sigBlockResult);
187     shutdown(1);
188   }
189
190   // Start signal receiver thread
191   std::thread threadSignalReceiver(threadSignalReceiverFunction);
192   threadSignalReceiver.detach();
193
194   logger->log("Core", Log::INFO, "Signal handlers set up successfully");
195
196   // VT Switching -----------------------------------------------------------------------------------------------
197
198 #ifdef HANDLE_VT_SWITCHING
199   if (
200
201
202     (fdtty = open("/dev/tty", O_WRONLY),0) == -1   // FIXME. Why the ,0 ? Surely this kills the log line below
203
204
205   )
206   {
207     logger->log("Core", Log::EMERG, "Could not open /dev/tty. Please change permissions");
208   }
209   else
210   {
211     int free_vt;
212     if (ioctl(fdtty, VT_OPENQRY, &free_vt) == -1 || free_vt == -1)
213     {
214       logger->log("Core", Log::EMERG, "Could not retrieve free virtual console, please change permissions");
215     }
216     else
217     {
218       ioctl(fdtty, VT_ACTIVATE, free_vt);
219       ioctl(fdtty, VT_WAITACTIVE, free_vt);
220       ioctl(fdtty, VT_LOCKSWITCH, 1);
221     }
222   }
223 #endif
224
225   // Init modules ----------------------------------------------------------------------------------------------------
226   int success;
227
228   success = inputMan->init();
229
230   if (success)
231   {
232     logger->log("Core", Log::INFO, "InputMan module initialised");
233   }
234   else
235   {
236     logger->log("Core", Log::EMERG, "InputMan module failed to initialise");
237     shutdown(1);
238   }
239
240   success = led->init(-1);
241   if (success)
242   {
243     logger->log("Core", Log::INFO, "LED module initialised");
244   }
245   else
246   {
247     logger->log("Core", Log::EMERG, "LED module failed to initialise");
248     shutdown(1);
249   }
250
251   success = timers->init();
252   if (success)
253   {
254     logger->log("Core", Log::INFO, "Timers module initialised");
255   }
256   else
257   {
258     logger->log("Core", Log::EMERG, "Timers module failed to initialise");
259     shutdown(1);
260   }
261
262   UCHAR videoFormat = Video::PAL; // PALNTSC FIXME
263
264   success = video->init(videoFormat);
265   if (success)
266   {
267     logger->log("Core", Log::INFO, "Video module initialised");
268   }
269   else
270   {
271     logger->log("Core", Log::EMERG, "Video module failed to initialise");
272     shutdown(1);
273   }
274
275   success = osd->init();
276   if (success)
277   {
278     logger->log("Core", Log::INFO, "OSD module initialised");
279   }
280   else
281   {
282     logger->log("Core", Log::EMERG, "OSD module failed to initialise");
283     shutdown(1);
284   }
285
286   success = audio->init(Audio::MPEG2_PES);
287   if (success)
288   {
289     logger->log("Core", Log::INFO, "Audio module initialised");
290   }
291   else
292   {
293     logger->log("Core", Log::EMERG, "Audio module failed to initialise");
294     shutdown(1);
295   }
296
297   success = vdr->init();
298   if (success)
299   {
300     logger->log("Core", Log::INFO, "VDR module initialised");
301   }
302   else
303   {
304     logger->log("Core", Log::EMERG, "VDR module failed to initialise");
305     shutdown(1);
306   }
307
308   success = boxstack->init();
309   if (success)
310   {
311     logger->log("Core", Log::INFO, "BoxStack module initialised");
312   }
313   else
314   {
315     logger->log("Core", Log::EMERG, "BoxStack module failed to initialise");
316     shutdown(1);
317   }
318
319   success = command->init(crashed, setServer);
320   if (success)
321   {
322     logger->log("Core", Log::INFO, "Command module initialised");
323   }
324   else
325   {
326     logger->log("Core", Log::EMERG, "Command module failed to initialise");
327     shutdown(1);
328   }
329
330   // Other init ------------------------------------------------------------------------------------------------------
331
332   logger->log("Core", Log::NOTICE, "Startup successful");
333
334   // Run main loop ---------------------------------------------------------------------------------------------------
335
336   // Ok, all major device components and other bits are loaded and ready
337   command->run();
338
339   // When that returns quit ------------------------------------------------------------------------------------------
340   shutdown(0);
341   return 0;
342 }
343
344 // -------------------------------------------------------------------------------------------------------------------
345
346 void threadSignalReceiverFunction()
347 {
348   int sig;
349   sigset_t set;
350   sigfillset(&set);
351   while(1)
352   {
353     if(sigwait(&set, &sig))
354     {
355       logger->log("Core", Log::CRIT, "Sigwait returned fail - signal handler exiting");
356       return;
357     }
358
359     logger->log("Core", Log::NOTICE, "Signal received: %i", sig);
360
361     if ((sig == SIGINT) || (sig == SIGTERM)) command->stop();
362   }
363 }
364
365 #endif
366
367 // -------------------------------------------------------------------------------------------------------------------
368
369 void shutdown(int code)
370 {
371   if (boxstack)
372   {
373     boxstack->shutdown();
374     delete boxstack;
375     logger->log("Core", Log::NOTICE, "BoxStack module shut down");
376   }
377
378   // FIXME, send a del all to boxstack first, then get rid of it after command?
379   if (command) // shut down command here in case views have posted messages
380   {
381     command->shutdown();
382     delete command;
383     command = NULL;
384     logger->log("Core", Log::NOTICE, "Command module shut down");
385   }
386
387   if (vdr)
388   {
389     vdr->shutdown();
390     delete vdr;
391     logger->log("Core", Log::NOTICE, "VDR module shut down");
392   }
393
394   if (osd)
395   {
396     osd->shutdown();
397     delete osd;
398     logger->log("Core", Log::NOTICE, "OSD module shut down");
399   }
400
401   if (audio)
402   {
403     audio->shutdown();
404     delete audio;
405     logger->log("Core", Log::NOTICE, "Audio module shut down");
406   }
407
408   if (video)
409   {
410     video->shutdown();
411     delete video;
412     logger->log("Core", Log::NOTICE, "Video module shut down");
413   }
414
415   if (timers)
416   {
417     timers->shutdown();
418     delete timers;
419     logger->log("Core", Log::NOTICE, "Timers module shut down");
420   }
421
422   if (led)
423   {
424     led->shutdown();
425     delete led;
426     logger->log("Core", Log::NOTICE, "LED module shut down");
427   }
428
429   if (inputMan)
430   {
431     inputMan->shutdown();
432     delete inputMan;
433     logger->log("Core", Log::NOTICE, "InputMan module shut down");
434   }
435
436   if (wol)
437   {
438     delete wol;
439     logger->log("Core", Log::NOTICE, "WOL module shut down");
440   }
441
442   if (sleeptimer)
443   {
444     delete sleeptimer;
445     logger->log("Core", Log::NOTICE, "Sleeptimer module shut down");
446   }
447 #ifdef HANDLE_VT_SWITCHING
448   ioctl(fdtty, VT_UNLOCKSWITCH, 1);
449   close(fdtty);
450 #endif
451
452   if (logger)
453   {
454     logger->log("Core", Log::NOTICE, "Log module shutting down... bye!\n\n");
455     logger->shutdown();
456     delete logger;
457   }
458
459   exit(code);
460 }
461
462 // -------------------------------------------------------------------------------------------------------------------
463
464 ULLONG htonll(ULLONG a)
465 {
466   #if BYTE_ORDER == BIG_ENDIAN
467     return a;
468   #else
469     ULLONG b = 0;
470
471     b = ((a << 56) & 0xFF00000000000000ULL)
472       | ((a << 40) & 0x00FF000000000000ULL)
473       | ((a << 24) & 0x0000FF0000000000ULL)
474       | ((a <<  8) & 0x000000FF00000000ULL)
475       | ((a >>  8) & 0x00000000FF000000ULL)
476       | ((a >> 24) & 0x0000000000FF0000ULL)
477       | ((a >> 40) & 0x000000000000FF00ULL)
478       | ((a >> 56) & 0x00000000000000FFULL) ;
479
480     return b;
481   #endif
482 }
483
484 ULLONG ntohll(ULLONG a)
485 {
486   return htonll(a);
487 }
488
489 void MILLISLEEP(ULONG a)
490 {
491 #ifndef WIN32
492   struct timespec delayTime;
493   delayTime.tv_sec = a / 1000;
494   delayTime.tv_nsec = (a % 1000) * 1000000;
495   nanosleep(&delayTime, NULL);
496 #else
497   Sleep(a);
498 #endif
499 }
500
501 long long getTimeMS()
502 {
503   struct timespec ts;
504   clock_gettime(VOMP_LINUX_CLOCK, &ts);
505   return ts.tv_sec * 1000 + ts.tv_nsec / 1000000LL;
506 }
507
508 int getClockRealTime(struct timespec *tp)
509 {
510   return clock_gettime(CLOCK_REALTIME, tp);
511 }
512
513 int min(UINT a, int b)
514 {
515   if (a > b) return b;
516   else return a;
517 }
518
519 int max(int a, int b)
520 {
521   if (a > b) return a;
522   else return b;
523 }