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