]> git.vomp.tv Git - vompclient-marten.git/blob - command.cc
New timers system. New program structure for handling buttons/timers
[vompclient-marten.git] / command.cc
1 /*
2     Copyright 2004-2005 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, write to the Free Software
18     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21 #include "command.h"
22
23 Command* Command::instance = NULL;
24
25 Command::Command()
26 {
27   if (instance) return;
28   instance = this;
29   initted = 0;
30   isStandby = 0;
31   firstBoot = 1;
32 }
33
34 Command::~Command()
35 {
36   instance = NULL;
37 }
38
39 Command* Command::getInstance()
40 {
41   return instance;
42 }
43
44 int Command::init()
45 {
46   if (initted) return 0;
47   initted = 1;
48
49   logger = Log::getInstance();
50   viewman = ViewMan::getInstance();
51   remote = Remote::getInstance();
52
53   if (!logger || !viewman || !remote)
54   {
55     initted = 0;
56     return 0;
57   }
58
59   pthread_mutex_init(&masterLock, NULL);
60
61   return 1;
62 }
63
64 int Command::shutdown()
65 {
66   if (!initted) return 0;
67   initted = 0;
68   return 1;
69 }
70
71 void Command::stop()
72 {
73 //  VDR::getInstance()->cancelFindingServer();
74   irun = 0;
75 }
76
77 void Command::run()
78 {
79   if (!initted) return;
80   irun = 1;
81
82   mainPid = getpid();
83
84   Video* video = Video::getInstance();
85
86   UCHAR screenSize = video->getFormat();
87
88   // moved from startup because surface delete doesn't work
89
90   // just in case
91   video->signalOn();
92   Led::getInstance()->on();
93
94   // Blue background
95   View* v = new View();
96   v->create(video->getScreenWidth(), video->getScreenHeight());
97   v->setBackgroundColour(Colour::VIDEOBLUE);
98   v->draw();
99   v->show();
100   viewman->add(v);
101   viewman->removeView(v);
102
103   // Wallpaper
104   wallpaper = new VWallpaper();
105   if (screenSize == Video::PAL)
106   {
107     logger->log("Command", Log::DEBUG, "PAL wallpaper selected");
108     wallpaper->init("/wallpaperPAL.jpg");
109   }
110   else
111   {
112     logger->log("Command", Log::DEBUG, "NTSC wallpaper selected");
113     wallpaper->init("/wallpaperNTSC.jpg");
114   }
115   wallpaper->draw();
116   wallpaper->show();
117   viewman->add(wallpaper);
118
119   // End of startup. Lock the mutex and put the first view up
120
121   pthread_mutex_lock(&masterLock);
122
123
124   VConnect* vconnect = new VConnect();
125   viewman->add(vconnect);
126   vconnect->run();
127
128
129   UCHAR button = 0;
130   while(irun)
131   {
132     // unlock and wait
133     pthread_mutex_unlock(&masterLock);
134
135     button = remote->getButtonPress(2);  // FIXME why is this set to 2 and not 0? so it can quit
136     // something happened, lock and process
137
138     pthread_mutex_lock(&masterLock);
139
140     if ((button == Remote::NA_NONE) || (button == Remote::NA_UNKNOWN)) continue;
141
142     if (button != Remote::NA_SIGNAL) handleCommand(button);
143     processMessageQueue();
144   }
145
146   pthread_mutex_unlock(&masterLock);
147 }
148
149 void Command::postMessage(Message* m)
150 {
151   // This is locked here in case the main loop is not waiting for an event, but is processing one
152   // it could be killed but then not react to it because the signal wouldn't cause
153   // remote->getButtonPress to break
154   // locking the mutex ensures that the master thread is waiting on getButtonPress
155
156   pthread_mutex_lock(&masterLock);
157   MessageQueue::postMessage(m);
158   kill(mainPid, SIGURG);
159   pthread_mutex_unlock(&masterLock);
160 }
161
162 void Command::processMessage(Message* m)
163 {
164   logger->log("Command", Log::DEBUG, "processing message %i", m->message);
165
166   switch(m->message)
167   {
168     case Message::STANDBY:
169     {
170       doStandby();
171       break;
172     }
173     case Message::STOP_PLAYBACK:
174     {
175       handleCommand(Remote::STOP); // an odd way of doing it, but so simple
176       break;
177     }
178     case Message::STREAM_END:
179     {
180       // post a message to ViewMan and then run the viewman message queue
181       Message* m2 = new Message();
182       m2->message = Message::STREAM_END;
183       m2->to = VVideoLive::getInstance();
184       viewman->postMessage(m2);
185       handleCommand(Remote::NA_NONE);
186       break;
187     }
188     case Message::VDR_CONNECTED:
189     {
190       doJustConnected((VConnect*)m->from);
191       break;
192     }
193     case Message::TIMER:
194     {
195       // FIXME lock main mutex
196       // FIXME Reply - if messages are being processed then main loop is on processMessageQueue()
197       // -- this means the mutex is locked
198
199       // FIXME investigate whether timer can have fired, but waits on this mutex,
200       // a view is deleted, then the timer runs on a non-object
201
202       // FIXME - go to one message queue only - then instead of having
203       // objects deriving from messagequeues, make them derive from
204       // messagereceiver - then one messagequeue can deliver any message to anywhere
205
206
207       // deliver timer
208       ((TimerReceiver*)m->to)->timercall(m->parameter);
209       handleCommand(Remote::NA_NONE); // in case any timer has posted messages to viewman,
210                                       // run viewman message queue here. FIXME improve this!
211       // FIXME unlock main mutex
212     }
213   }
214 }
215
216 void Command::handleCommand(int button)
217 {
218   if (isStandby && (button != Remote::POWER)) return;
219
220   if (viewman->handleCommand(button)) return;
221
222   // command was not handled
223
224   switch(button)
225   {
226     case Remote::DF_LEFT:
227     case Remote::DF_RIGHT:
228     case Remote::VOLUMEUP:
229     case Remote::VOLUMEDOWN:
230     {
231       VVolume* v = new VVolume();
232       v->handleCommand(button); // this will draw+show
233       viewman->add(v);
234       return;
235     }
236     case Remote::MUTE:
237     {
238       VMute* v = new VMute();
239       v->draw();
240       v->show();
241       viewman->add(v);
242       return;
243     }
244     case Remote::POWER:
245     {
246       doStandby();
247       return;
248     }
249 #ifdef DEV
250     case Remote::RECORD:
251     {
252       Osd::getInstance()->screenShot("/out.jpg");
253       return;
254     }
255 #endif
256   }
257 }
258
259 void Command::doStandby()
260 {
261   if (isStandby)
262   {
263     Video::getInstance()->signalOn();
264     Led::getInstance()->on();
265     isStandby = 0;
266
267
268     VConnect* vconnect = new VConnect();
269     viewman->add(vconnect);
270     vconnect->run();
271   }
272   else
273   {
274     Video::getInstance()->signalOff();
275     viewman->removeAll();
276     wallpaper->show();
277
278     VDR::getInstance()->configSave("General", "Last Power State", "Off");
279     VDR::getInstance()->disconnect();
280     Led::getInstance()->off();
281     isStandby = 1;
282   }
283 }
284
285 void Command::doReboot()
286 {
287   VDR::getInstance()->disconnect();
288   // just kill it...
289   logger->log("Command", Log::NOTICE, "Reboot");
290   reboot(LINUX_REBOOT_CMD_RESTART);
291 }
292
293 void Command::doJustConnected(VConnect* vconnect)
294 {
295   I18n::initialize();
296   Video* video = Video::getInstance();
297   viewman->removeView(vconnect, 0);
298
299   VInfo* vi = new VInfo();
300   vi->create(400, 200);
301   if (video->getFormat() == Video::PAL)
302     vi->setScreenPos(170, 200);
303   else
304     vi->setScreenPos(160, 150);
305
306   vi->setOneLiner(tr("Connected, loading config"));
307   vi->draw();
308   vi->show();
309   viewman->add(vi);
310
311
312   VDR* vdr = VDR::getInstance();
313   char* config;
314
315   // Power off if first boot and config says so
316   if (firstBoot)
317   {
318     firstBoot = 0;
319
320     config = vdr->configLoad("General", "Power After Boot");
321
322     if (config)
323     {
324       if (!strcasecmp(config, "On"))
325       {
326         logger->log("Command", Log::INFO, "Config says Power After Boot = On");
327       }
328       else if (!strcasecmp(config, "Off"))
329       {
330         logger->log("Command", Log::INFO, "Config says Power After Boot = Off");
331         doStandby();
332         delete[] config;
333         return; // quit here
334       }
335       else if (!strcasecmp(config, "Last state"))
336       {
337         char* lastPowerState = vdr->configLoad("General", "Last Power State");
338         if (lastPowerState)
339         {
340           if (!strcasecmp(lastPowerState, "On"))
341           {
342             logger->log("Command", Log::INFO, "Config says Last Power State = On");
343           }
344           else if (!strcasecmp(lastPowerState, "Off"))
345           {
346             logger->log("Command", Log::INFO, "Config says Last Power State = Off");
347             doStandby();
348             delete[] config;
349             return; // quit here
350           }
351           else
352           {
353             logger->log("Command", Log::INFO, "Config General/Last Power State not understood");
354           }
355         }
356         else
357         {
358           logger->log("Command", Log::INFO, "Config General/Last Power State not found");
359         }
360       }
361       else
362       {
363         logger->log("Command", Log::INFO, "Config/Power After Boot not understood");
364       }
365       delete[] config;
366     }
367     else
368     {
369       logger->log("Command", Log::INFO, "Config General/Power After Boot not found");
370     }
371   }
372
373
374   // Go S-Video if config says so
375
376   config = vdr->configLoad("TV", "Connection");
377
378   if (config)
379   {
380     if (!strcasecmp(config, "S-Video"))
381     {
382       logger->log("Command", Log::INFO, "Switching to S-Video as Connection=%s", config);
383       video->setConnection(Video::SVIDEO);
384     }
385     else
386     {
387       logger->log("Command", Log::INFO, "Switching to RGB/Composite as Connection=%s", config);
388       video->setConnection(Video::COMPOSITERGB);
389     }
390     delete[] config;
391   }
392   else
393   {
394     logger->log("Command", Log::INFO, "Config TV/S-Video not found");
395   }
396
397   // Set remote type
398
399   config = vdr->configLoad("General", "Remote type");
400
401   if (config)
402   {
403     if (!strcasecmp(config, "New"))
404     {
405       logger->log("Command", Log::INFO, "Switching to New remote type");
406       remote->setRemoteType(Remote::NEWREMOTE);
407     }
408     else
409     {
410       logger->log("Command", Log::INFO, "Switching to Old remote type");
411       remote->setRemoteType(Remote::OLDREMOTE);
412     }
413     delete[] config;
414   }
415   else
416   {
417     logger->log("Command", Log::INFO, "Config General/Remote type not found");
418     remote->setRemoteType(Remote::OLDREMOTE);
419   }
420
421   // Get TV aspect ratio
422
423   config = vdr->configLoad("TV", "Aspect");
424   if (config)
425   {
426     if (!strcasecmp(config, "16:9"))
427     {
428       logger->log("Command", Log::INFO, "/// Switching to TV aspect 16:9");
429       video->setTVsize(Video::ASPECT16X9);
430     }
431     else
432     {
433       logger->log("Command", Log::INFO, "/// Switching to TV aspect 4:3");
434       video->setTVsize(Video::ASPECT4X3);
435     }
436     delete[] config;
437   }
438   else
439   {
440     logger->log("Command", Log::INFO, "Config TV/Aspect type not found, going 4:3");
441     video->setTVsize(Video::ASPECT4X3);
442   }
443
444   config = vdr->configLoad("TV", "Widemode");
445   if (config)
446   {
447     if (!strcasecmp(config, "Letterbox"))
448     {
449       logger->log("Command", Log::INFO, "Setting letterbox mode");
450       video->setMode(Video::LETTERBOX);
451     }
452     else
453     {
454       logger->log("Command", Log::INFO, "Setting chop-sides mode");
455       video->setMode(Video::NORMAL);
456     }
457     delete[] config;
458   }
459   else
460   {
461     logger->log("Command", Log::INFO, "Config TV/Widemode not found, Setting chop-sides mode");
462     video->setMode(Video::NORMAL);
463   }
464
465   // config done
466
467   // Save power state = on
468
469   vdr->configSave("General", "Last Power State", "On");
470
471
472   viewman->removeView(vi);
473
474   VWelcome* vw = new VWelcome();
475   vw->draw();
476   vw->show();
477   viewman->add(vw);
478 }