]> git.vomp.tv Git - vompclient.git/blob - main.cc
Fix VRecording showing graphic at bottom left when it shouldn't
[vompclient.git] / main.cc
1 /*
2     Copyright 2004-2021 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 <cstdlib>
26
27 // For open
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <fcntl.h>
31
32 #include <thread>
33 #include <string>
34
35 #ifndef WIN32
36   #include <unistd.h>
37   #include <endian.h>
38 #endif
39
40 #include "defines.h"
41
42 #ifdef HANDLE_VT_SWITCHING
43   #include <sys/ioctl.h>
44   #include <linux/vt.h>
45 #endif
46
47 #include "config.h"
48 #include "log.h"
49 #include "util.h"
50 #include "control.h"
51
52 #ifdef VOMP_PLATTFORM_NMT
53   #include "lednmt.h"
54   #include "osddirectfb.h"
55   #include "audionmt.h"
56   #include "videonmt.h"
57 #endif
58
59
60 #ifndef WIN32 // FIXME do we need any if WIN32 stuff in here? windows has own winmain file
61 void threadSignalReceiverFunction();
62 #endif
63
64 [[ noreturn ]] void shutdown(int code);
65
66 Config* config;
67 LogNT* loggerNT;
68 Control* control;
69
70 #ifdef HANDLE_VT_SWITCHING
71 int fdtty;
72 struct vt_mode old_vtmode;
73 #endif
74
75 static const char* TAG = "Main";
76
77 // Linux main function and sighandler
78 #ifndef WIN32
79 int main(int argc, char** argv)
80 {
81   bool crashed = false;
82
83   config = new Config();
84   if (!config->loadFile())
85   {
86     printf("Parse error in config.json\n");
87     shutdown(1);
88   }
89
90   int c;
91   while ((c = getopt(argc, argv, "hclf:ns:p:")) != -1)
92   {
93     switch (c)
94     {
95       case 'c':
96         crashed = true;
97         break;
98       case 'l':
99         config->set("log", "enabled", true);
100         break;
101       case 'f':
102         config->set("log", "filename", optarg);
103         break;
104       case 'n':
105         config->set("main", "daemonize", false);
106         break;
107       case 's':
108         config->set("server", "address", optarg);
109         break;
110       case 'p':
111         config->set("server", "port", std::atoi(optarg));
112         break;
113       case '?':
114       case 'h':
115         printf("Vompclient\n\n");
116         printf("Usage:\n");
117         printf("  -l     Enable logging\n");
118         printf("  -f F   Log to file F instead of stdout\n");
119         printf("  -n     Disable daemonize\n");
120         printf("  -s S   Connect to server S\n");
121         printf("  -p P     .. at port P\n");
122         return 1;
123       default:
124         printf("Option error\n");
125         return 1;
126     }
127   }
128
129   // Start Log --------------------------------------------------------------------------------------------------
130
131   loggerNT = new LogNT();
132   if (!loggerNT)
133   {
134     printf("Failed to create LogNT object\n");
135     shutdown(1);
136   }
137
138   std::string logFileName;
139   config->getString("log", "filename", logFileName);
140   bool logEnabled;
141   config->getBool("log", "enabled", logEnabled);
142   bool daemonize;
143   config->getBool("main", "daemonize", daemonize);
144
145   if (logEnabled && daemonize && !logFileName.compare("stdout"))
146   {
147     printf("Cannot daemonize and log to stdout\n");
148     shutdown(1);
149   }
150
151   if (!loggerNT->init(logFileName, logEnabled))
152   {
153     printf("Could not initialise log object. Aborting.\n");
154     shutdown(1);
155   }
156
157   loggerNT->info(TAG, "Starting up...");
158
159   // Daemonize --------------------------------------------------------------------------------------------------
160
161   // Would read config for daemonize here, but actually it's just above in the log section
162   // to detect attempts to log to stdout while daemonized
163   if (daemonize)
164   {
165     // Fork away
166     pid_t forkTest = fork();
167     if (forkTest == -1)
168     { printf("Cannot fork (1).\n"); exit(1); }
169     if (forkTest != 0) _exit(0); // PID returned, I am the parent
170     // otherwise, I am the child
171     setsid();
172     forkTest = fork();
173     if (forkTest == -1)
174     { printf("Cannot fork (2).\n"); exit(1); }
175     if (forkTest != 0) _exit(0); // PID returned, I am the parent
176     // otherwise, I am the child
177     close(0);
178     close(1);
179     close(2);
180   }
181
182   // Set up signal handling ------------------------------------------------------------------------------------------
183
184   // Block all signals
185   sigset_t set;
186   sigfillset(&set);
187   int sigBlockResult = pthread_sigmask(SIG_SETMASK, &set, NULL);
188   if (sigBlockResult)
189   {
190     //logger->log("Main", Log::EMERG, "Could not block signals: %i", sigBlockResult);
191     loggerNT->crit(TAG, "Could not block signals: {}", sigBlockResult);
192     shutdown(1);
193   }
194
195   // Start signal receiver thread
196   std::thread threadSignalReceiver(threadSignalReceiverFunction);
197   threadSignalReceiver.detach();
198
199   loggerNT->info(TAG, "Signal handlers set up successfully");
200
201   // VT Switching -----------------------------------------------------------------------------------------------
202
203 #ifdef HANDLE_VT_SWITCHING
204   if (
205
206
207     (fdtty = open("/dev/tty", O_WRONLY),0) == -1   // FIXME. Why the ,0 ? Surely this kills the log line below
208
209
210   )
211   {
212     loggerNT->warn(TAG, "Could not open /dev/tty. Please change permissions");
213   }
214   else
215   {
216     int free_vt;
217     if (ioctl(fdtty, VT_OPENQRY, &free_vt) == -1 || free_vt == -1)
218     {
219       loggerNT->crit(TAG, "Could not retrieve free virtual console, please change permissions");
220     }
221     else
222     {
223       ioctl(fdtty, VT_ACTIVATE, free_vt);
224       ioctl(fdtty, VT_WAITACTIVE, free_vt);
225       ioctl(fdtty, VT_LOCKSWITCH, 1);
226     }
227   }
228 #endif
229
230   // Test area ------------------------------------------------------------------------------------------------------
231
232   //shutdown(0);
233
234   // Run control ----------------------------------------------------------------------------------------------------
235
236   control = new Control();
237   if (!control)
238   {
239     loggerNT->crit(TAG, "Control module failed to create");
240     shutdown(1);
241   }
242
243   if (!control->init(crashed))
244   {
245     loggerNT->crit(TAG, "Control module failed to initialise");
246     delete control;
247     control = NULL;
248     shutdown(1);
249   }
250
251   control->run();
252   control->shutdown();
253
254   shutdown(0);
255 }
256
257 // -------------------------------------------------------------------------------------------------------------------
258
259 void threadSignalReceiverFunction()
260 {
261   int sig;
262   sigset_t set;
263   sigfillset(&set);
264   while(1)
265   {
266     if(sigwait(&set, &sig))
267     {
268       loggerNT->crit(TAG, "Sigwait returned fail - signal handler exiting");
269       return;
270     }
271
272     loggerNT->info(TAG, "Signal received: {}", sig);
273
274     if ((sig == SIGINT) || (sig == SIGTERM)) control->stop();
275   }
276 }
277
278 #endif
279
280 // -------------------------------------------------------------------------------------------------------------------
281
282 [[ noreturn ]] void shutdown(int code)
283 {
284   // FIXME, send a del all to boxstack first, then get rid of it after control?
285   if (control) // shut down control here in case views have posted messages
286   {
287     delete control;
288     control = NULL;
289     loggerNT->info(TAG, "Control module shut down");
290   }
291
292 #ifdef HANDLE_VT_SWITCHING
293   ioctl(fdtty, VT_UNLOCKSWITCH, 1);
294   close(fdtty);
295 #endif
296
297   if (loggerNT)
298   {
299     loggerNT->info(TAG, "Log module shutting down... bye!\n\n");
300 #warning loggerNT has no shutdown
301     //loggerNT->shutdown();
302     delete loggerNT;
303   }
304
305   if (config)
306   {
307     delete config;
308   }
309
310   exit(code);
311 }
312
313 // -------------------------------------------------------------------------------------------------------------------
314
315 long long getTimeMS()
316 {
317   struct timespec ts;
318   clock_gettime(VOMP_LINUX_CLOCK, &ts);
319   return ts.tv_sec * 1000 + ts.tv_nsec / 1000000LL;
320 }
321
322 int getClockRealTime(struct timespec *tp) // FIXME - del if all goes chrono
323 {
324   return clock_gettime(CLOCK_REALTIME, tp);
325 }
326