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