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