]> git.vomp.tv Git - vompclient.git/blob - main.cc
Fixes for Windows
[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 // FIXME
21 // Work towards main and winmain only containing what they need for their own platforms
22 // Move anything common to utils or control. Move any module startup / shutdown that can
23 // be done in control to there.
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <signal.h>
29
30 #include <thread>
31 #include <string>
32
33
34 #ifndef WIN32
35   #include <unistd.h>
36   #include <endian.h>
37 #endif
38
39 #include "defines.h"
40
41 #ifdef HANDLE_VT_SWITCHING
42   #include <sys/ioctl.h>
43   #include <linux/vt.h>
44 #endif
45
46 #include "log.h"
47 #include "timers.h"
48 #include "control.h"
49 #include "inputman.h"
50
51 #ifdef VOMP_PLATTFORM_NMT
52   #include "lednmt.h"
53   #include "osddirectfb.h"
54   #include "audionmt.h"
55   #include "videonmt.h"
56 #endif
57
58 #ifdef VOMP_PLATFORM_RASPBERRY
59   #include "ledraspberry.h"
60   #include "osdopenvg.h"
61   #include "audioomx.h"
62   #include "videoomx.h"
63 #endif
64
65
66
67 #ifndef WIN32 // FIXME do we need any if WIN32 stuff in here? windows has own winmain file
68 void threadSignalReceiverFunction();
69 #endif
70
71 ULLONG htonll(ULLONG);
72 ULLONG ntohll(ULLONG);
73 void shutdown(int code);
74 const std::string& getCommandLineServer();
75
76 // Global variables --------------------------------------------------------------------------------------------------
77 Log* logger;
78 InputMan* inputMan;
79 Led* led;
80 Osd* osd;
81 Timers* timers;
82 Control* control;
83 Video* video;
84 Audio* audio;
85
86 // Temporary, will move to Config system
87 std::string argvServer;
88
89 #ifdef HANDLE_VT_SWITCHING
90 int fdtty;
91 struct vt_mode old_vtmode;
92 #endif
93
94 // Linux main function and sighandler
95 #ifndef WIN32
96 int main(int argc, char** argv)
97 {
98   bool daemonize = true;
99   bool debugEnabled = false;
100   bool crashed = false;
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         argvServer = 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   inputMan   = new InputMan();
132
133   led        = new Led_TYPE();
134   osd        = new Osd_TYPE();
135   audio      = new Audio_TYPE();
136   video      = new Video_TYPE();
137
138   control    = new Control();
139
140   if (!logger || !timers || !inputMan || !led || !osd || !video || !audio || !control)
141   {
142     printf("Could not create objects. Memory problems?\n");
143     shutdown(1);
144   }
145
146   // Get logging module started --------------------------------------------------------------------------------------
147
148   if (!logger->init(Log::DEBUG, "dummy", debugEnabled ? 1 : 0)) // NCONFIG x2
149   {
150     printf("Could not initialise log object. Aborting.\n");
151     shutdown(1);
152   }
153
154   logger->log("Core", Log::INFO, "Starting up...");
155
156   // Daemonize if not -d
157
158   if (daemonize)
159   {
160     // Fork away
161     pid_t forkTest = fork();
162     if (forkTest == -1)
163     { printf("Cannot fork (1).\n"); exit(1); }
164     if (forkTest != 0) _exit(0); // PID returned, I am the parent
165     // otherwise, I am the child
166     setsid();
167     forkTest = fork();
168     if (forkTest == -1)
169     { printf("Cannot fork (2).\n"); exit(1); }
170     if (forkTest != 0) _exit(0); // PID returned, I am the parent
171     // otherwise, I am the child
172     close(0);
173     close(1);
174     close(2);
175   }
176
177   // Set up signal handling ------------------------------------------------------------------------------------------
178
179   // Block all signals
180   sigset_t set;
181   sigfillset(&set);
182   int sigBlockResult = pthread_sigmask(SIG_SETMASK, &set, NULL);
183   if (sigBlockResult)
184   {
185     logger->log("Core", Log::EMERG, "Could not block signals: %i", sigBlockResult);
186     shutdown(1);
187   }
188
189   // Start signal receiver thread
190   std::thread threadSignalReceiver(threadSignalReceiverFunction);
191   threadSignalReceiver.detach();
192
193   logger->log("Core", Log::INFO, "Signal handlers set up successfully");
194
195   // VT Switching -----------------------------------------------------------------------------------------------
196
197 #ifdef HANDLE_VT_SWITCHING
198   if (
199
200
201     (fdtty = open("/dev/tty", O_WRONLY),0) == -1   // FIXME. Why the ,0 ? Surely this kills the log line below
202
203
204   )
205   {
206     logger->log("Core", Log::EMERG, "Could not open /dev/tty. Please change permissions");
207   }
208   else
209   {
210     int free_vt;
211     if (ioctl(fdtty, VT_OPENQRY, &free_vt) == -1 || free_vt == -1)
212     {
213       logger->log("Core", Log::EMERG, "Could not retrieve free virtual console, please change permissions");
214     }
215     else
216     {
217       ioctl(fdtty, VT_ACTIVATE, free_vt);
218       ioctl(fdtty, VT_WAITACTIVE, free_vt);
219       ioctl(fdtty, VT_LOCKSWITCH, 1);
220     }
221   }
222 #endif
223
224   // Init modules ----------------------------------------------------------------------------------------------------
225   int success;
226
227   success = inputMan->init();
228
229   if (success)
230   {
231     logger->log("Core", Log::INFO, "InputMan module initialised");
232   }
233   else
234   {
235     logger->log("Core", Log::EMERG, "InputMan module failed to initialise");
236     shutdown(1);
237   }
238
239   success = led->init(-1);
240   if (success)
241   {
242     logger->log("Core", Log::INFO, "LED module initialised");
243   }
244   else
245   {
246     logger->log("Core", Log::EMERG, "LED module failed to initialise");
247     shutdown(1);
248   }
249
250   success = timers->init();
251   if (success)
252   {
253     logger->log("Core", Log::INFO, "Timers module initialised");
254   }
255   else
256   {
257     logger->log("Core", Log::EMERG, "Timers module failed to initialise");
258     shutdown(1);
259   }
260
261   UCHAR videoFormat = Video::PAL; // PALNTSC FIXME
262
263   success = video->init(videoFormat);
264   if (success)
265   {
266     logger->log("Core", Log::INFO, "Video module initialised");
267   }
268   else
269   {
270     logger->log("Core", Log::EMERG, "Video module failed to initialise");
271     shutdown(1);
272   }
273
274   success = osd->init();
275   if (success)
276   {
277     logger->log("Core", Log::INFO, "OSD module initialised");
278   }
279   else
280   {
281     logger->log("Core", Log::EMERG, "OSD module failed to initialise");
282     shutdown(1);
283   }
284
285   success = audio->init(Audio::MPEG2_PES);
286   if (success)
287   {
288     logger->log("Core", Log::INFO, "Audio module initialised");
289   }
290   else
291   {
292     logger->log("Core", Log::EMERG, "Audio module failed to initialise");
293     shutdown(1);
294   }
295
296
297
298
299
300
301   bool bsuccess = control->init(crashed);
302   if (bsuccess)
303   {
304     logger->log("Core", Log::INFO, "Control module initialised");
305   }
306   else
307   {
308     logger->log("Core", Log::EMERG, "Control module failed to initialise");
309     shutdown(1);
310   }
311
312   // Other init ------------------------------------------------------------------------------------------------------
313
314   logger->log("Core", Log::NOTICE, "Startup successful");
315
316   // Run main loop ---------------------------------------------------------------------------------------------------
317
318   // Ok, all major device components and other bits are loaded and ready
319   control->run();
320
321   // When that returns quit ------------------------------------------------------------------------------------------
322
323   control->shutdown();
324
325   shutdown(0);
326   return 0;
327 }
328
329 // -------------------------------------------------------------------------------------------------------------------
330
331 void threadSignalReceiverFunction()
332 {
333   int sig;
334   sigset_t set;
335   sigfillset(&set);
336   while(1)
337   {
338     if(sigwait(&set, &sig))
339     {
340       logger->log("Core", Log::CRIT, "Sigwait returned fail - signal handler exiting");
341       return;
342     }
343
344     logger->log("Core", Log::NOTICE, "Signal received: %i", sig);
345
346     if ((sig == SIGINT) || (sig == SIGTERM)) control->stop();
347   }
348 }
349
350 #endif
351
352 // -------------------------------------------------------------------------------------------------------------------
353
354 void shutdown(int code)
355 {
356   // FIXME, send a del all to boxstack first, then get rid of it after control?
357   if (control) // shut down control here in case views have posted messages
358   {
359     delete control;
360     control = NULL;
361     logger->log("Core", Log::NOTICE, "Control module shut down");
362   }
363
364   if (osd)
365   {
366     osd->shutdown();
367     delete osd;
368     logger->log("Core", Log::NOTICE, "OSD module shut down");
369   }
370
371   if (audio)
372   {
373     audio->shutdown();
374     delete audio;
375     logger->log("Core", Log::NOTICE, "Audio module shut down");
376   }
377
378   if (video)
379   {
380     video->shutdown();
381     delete video;
382     logger->log("Core", Log::NOTICE, "Video module shut down");
383   }
384
385   if (timers)
386   {
387     timers->shutdown();
388     delete timers;
389     logger->log("Core", Log::NOTICE, "Timers module shut down");
390   }
391
392   if (led)
393   {
394     led->shutdown();
395     delete led;
396     logger->log("Core", Log::NOTICE, "LED module shut down");
397   }
398
399   if (inputMan)
400   {
401     inputMan->shutdown();
402     delete inputMan;
403     logger->log("Core", Log::NOTICE, "InputMan module shut down");
404   }
405
406
407
408 #ifdef HANDLE_VT_SWITCHING
409   ioctl(fdtty, VT_UNLOCKSWITCH, 1);
410   close(fdtty);
411 #endif
412
413   if (logger)
414   {
415     logger->log("Core", Log::NOTICE, "Log module shutting down... bye!\n\n");
416     logger->shutdown();
417     delete logger;
418   }
419
420   exit(code);
421 }
422
423 // -------------------------------------------------------------------------------------------------------------------
424
425 ULLONG htonll(ULLONG a)
426 {
427   #if BYTE_ORDER == BIG_ENDIAN
428     return a;
429   #else
430     ULLONG b = 0;
431
432     b = ((a << 56) & 0xFF00000000000000ULL)
433       | ((a << 40) & 0x00FF000000000000ULL)
434       | ((a << 24) & 0x0000FF0000000000ULL)
435       | ((a <<  8) & 0x000000FF00000000ULL)
436       | ((a >>  8) & 0x00000000FF000000ULL)
437       | ((a >> 24) & 0x0000000000FF0000ULL)
438       | ((a >> 40) & 0x000000000000FF00ULL)
439       | ((a >> 56) & 0x00000000000000FFULL) ;
440
441     return b;
442   #endif
443 }
444
445 ULLONG ntohll(ULLONG a)
446 {
447   return htonll(a);
448 }
449
450 void MILLISLEEP(ULONG a)
451 {
452 #ifndef WIN32
453   struct timespec delayTime;
454   delayTime.tv_sec = a / 1000;
455   delayTime.tv_nsec = (a % 1000) * 1000000;
456   nanosleep(&delayTime, NULL);
457 #else
458   Sleep(a);
459 #endif
460 }
461
462 long long getTimeMS()
463 {
464   struct timespec ts;
465   clock_gettime(VOMP_LINUX_CLOCK, &ts);
466   return ts.tv_sec * 1000 + ts.tv_nsec / 1000000LL;
467 }
468
469 int getClockRealTime(struct timespec *tp) // FIXME - del if all goes chrono
470 {
471   return clock_gettime(CLOCK_REALTIME, tp);
472 }
473
474 int min(UINT a, int b)
475 {
476   if (a > b) return b;
477   else return a;
478 }
479
480 int max(int a, int b)
481 {
482   if (a > b) return a;
483   else return b;
484 }
485
486 const std::string& getCommandLineServer()
487 {
488   return argvServer;
489 }