]> git.vomp.tv Git - vompclient-marten.git/blob - command.cc
New timers code
[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     logger->log("Command", Log::DEBUG, "un-LOCKED MASTER MUTEX");
135
136     button = remote->getButtonPress(2);  // FIXME why is this set to 2 and not 0? so it can quit
137     // something happened, lock and process
138
139     pthread_mutex_lock(&masterLock);
140     logger->log("Command", Log::DEBUG, "LOCKED MASTER MUTEX");
141
142     if ((button == Remote::NA_NONE) || (button == Remote::NA_UNKNOWN)) continue;
143
144     if (button != Remote::NA_SIGNAL) handleCommand(button);
145     processMessageQueue();
146   }
147
148   pthread_mutex_unlock(&masterLock);
149 }
150
151 void Command::postMessage(Message* m)
152 {
153   // This is locked here in case the main loop is not waiting for an event, but is processing one
154   // it could be killed but then not react to it because the signal wouldn't cause
155   // remote->getButtonPress to break
156   // locking the mutex ensures that the master thread is waiting on getButtonPress
157
158   pthread_mutex_lock(&masterLock);
159     logger->log("Command", Log::DEBUG, "LOCKED MASTER MUTEX");
160   MessageQueue::postMessage(m);
161   kill(mainPid, SIGURG);
162   pthread_mutex_unlock(&masterLock);
163     logger->log("Command", Log::DEBUG, "un-LOCKED MASTER MUTEX");
164 }
165
166 bool Command::postMessageIfNotBusy(Message* m)
167 {
168   // This is for the timers module
169   // If the masterlock is locked then the timers module wants to
170   // cancel delivery
171
172   if (pthread_mutex_trylock(&masterLock) != EBUSY)
173   {
174       logger->log("Command", Log::DEBUG, "LOCKED MASTER MUTEX");
175     MessageQueue::postMessage(m);
176     kill(mainPid, SIGURG);
177     pthread_mutex_unlock(&masterLock);
178       logger->log("Command", Log::DEBUG, "un-LOCKED MASTER MUTEX");
179     return true;
180   }
181   else
182   {
183     return false;
184   }
185 }
186
187 void Command::processMessage(Message* m)
188 {
189   logger->log("Command", Log::DEBUG, "processing message %i", m->message);
190
191   switch(m->message)
192   {
193     case Message::STANDBY:
194     {
195       doStandby();
196       break;
197     }
198     case Message::STOP_PLAYBACK:
199     {
200       handleCommand(Remote::STOP); // an odd way of doing it, but so simple
201       break;
202     }
203     case Message::STREAM_END:
204     {
205       // post a message to ViewMan and then run the viewman message queue
206       Message* m2 = new Message();
207       m2->message = Message::STREAM_END;
208       m2->to = VVideoLive::getInstance();
209       viewman->postMessage(m2);
210       handleCommand(Remote::NA_NONE);
211       break;
212     }
213     case Message::VDR_CONNECTED:
214     {
215       doJustConnected((VConnect*)m->from);
216       break;
217     }
218     case Message::TIMER:
219     {
220       // FIXME lock main mutex
221       // FIXME Reply - if messages are being processed then main loop is on processMessageQueue()
222       // -- this means the mutex is locked
223
224       // FIXME investigate whether timer can have fired, but waits on this mutex,
225       // a view is deleted, then the timer runs on a non-object
226
227       // FIXME - go to one message queue only - then instead of having
228       // objects deriving from messagequeues, make them derive from
229       // messagereceiver - then one messagequeue can deliver any message to anywhere
230
231
232       // deliver timer
233
234       logger->log("Command", Log::DEBUG, "m = %p", m);
235       logger->log("Command", Log::DEBUG, "m->message = %i", m->message);
236       logger->log("Command", Log::DEBUG, "m->from = %p", m->from);
237       logger->log("Command", Log::DEBUG, "m->to = %p", m->to);
238       logger->log("Command", Log::DEBUG, "m->parameter = %p", m->parameter);
239       ((TimerReceiver*)m->to)->timercall(m->parameter);
240       handleCommand(Remote::NA_NONE); // in case any timer has posted messages to viewman,
241                                       // run viewman message queue here. FIXME improve this!
242       // FIXME unlock main mutex
243     }
244   }
245 }
246
247 void Command::handleCommand(int button)
248 {
249   if (isStandby && (button != Remote::POWER)) return;
250
251   if (viewman->handleCommand(button)) return;
252
253   // command was not handled
254
255   switch(button)
256   {
257     case Remote::DF_LEFT:
258     case Remote::DF_RIGHT:
259     case Remote::VOLUMEUP:
260     case Remote::VOLUMEDOWN:
261     {
262       VVolume* v = new VVolume();
263       v->handleCommand(button); // this will draw+show
264       viewman->add(v);
265       return;
266     }
267     case Remote::MUTE:
268     {
269       VMute* v = new VMute();
270       v->draw();
271       v->show();
272       viewman->add(v);
273       return;
274     }
275     case Remote::POWER:
276     {
277       doStandby();
278       return;
279     }
280 #ifdef DEV
281     case Remote::RECORD:
282     {
283       Osd::getInstance()->screenShot("/out.jpg");
284       return;
285     }
286 #endif
287   }
288 }
289
290 void Command::doStandby()
291 {
292   if (isStandby)
293   {
294     Video::getInstance()->signalOn();
295     Led::getInstance()->on();
296     isStandby = 0;
297
298
299     VConnect* vconnect = new VConnect();
300     viewman->add(vconnect);
301     vconnect->run();
302   }
303   else
304   {
305     Video::getInstance()->signalOff();
306     viewman->removeAll();
307     wallpaper->show();
308
309     VDR::getInstance()->configSave("General", "Last Power State", "Off");
310     VDR::getInstance()->disconnect();
311     Led::getInstance()->off();
312     isStandby = 1;
313   }
314 }
315
316 void Command::doReboot()
317 {
318   VDR::getInstance()->disconnect();
319   // just kill it...
320   logger->log("Command", Log::NOTICE, "Reboot");
321   reboot(LINUX_REBOOT_CMD_RESTART);
322 }
323
324 void Command::doJustConnected(VConnect* vconnect)
325 {
326   I18n::initialize();
327   Video* video = Video::getInstance();
328   viewman->removeView(vconnect);
329
330   VInfo* vi = new VInfo();
331   vi->create(400, 200);
332   if (video->getFormat() == Video::PAL)
333     vi->setScreenPos(170, 200);
334   else
335     vi->setScreenPos(160, 150);
336
337   vi->setOneLiner(tr("Connected, loading config"));
338   vi->draw();
339   vi->show();
340   viewman->add(vi);
341
342
343   VDR* vdr = VDR::getInstance();
344   char* config;
345
346   // Power off if first boot and config says so
347   if (firstBoot)
348   {
349     firstBoot = 0;
350
351     config = vdr->configLoad("General", "Power After Boot");
352
353     if (config)
354     {
355       if (!strcasecmp(config, "On"))
356       {
357         logger->log("Command", Log::INFO, "Config says Power After Boot = On");
358       }
359       else if (!strcasecmp(config, "Off"))
360       {
361         logger->log("Command", Log::INFO, "Config says Power After Boot = Off");
362         doStandby();
363         delete[] config;
364         return; // quit here
365       }
366       else if (!strcasecmp(config, "Last state"))
367       {
368         char* lastPowerState = vdr->configLoad("General", "Last Power State");
369         if (lastPowerState)
370         {
371           if (!strcasecmp(lastPowerState, "On"))
372           {
373             logger->log("Command", Log::INFO, "Config says Last Power State = On");
374           }
375           else if (!strcasecmp(lastPowerState, "Off"))
376           {
377             logger->log("Command", Log::INFO, "Config says Last Power State = Off");
378             doStandby();
379             delete[] config;
380             return; // quit here
381           }
382           else
383           {
384             logger->log("Command", Log::INFO, "Config General/Last Power State not understood");
385           }
386         }
387         else
388         {
389           logger->log("Command", Log::INFO, "Config General/Last Power State not found");
390         }
391       }
392       else
393       {
394         logger->log("Command", Log::INFO, "Config/Power After Boot not understood");
395       }
396       delete[] config;
397     }
398     else
399     {
400       logger->log("Command", Log::INFO, "Config General/Power After Boot not found");
401     }
402   }
403
404
405   // Go S-Video if config says so
406
407   config = vdr->configLoad("TV", "Connection");
408
409   if (config)
410   {
411     if (!strcasecmp(config, "S-Video"))
412     {
413       logger->log("Command", Log::INFO, "Switching to S-Video as Connection=%s", config);
414       video->setConnection(Video::SVIDEO);
415     }
416     else
417     {
418       logger->log("Command", Log::INFO, "Switching to RGB/Composite as Connection=%s", config);
419       video->setConnection(Video::COMPOSITERGB);
420     }
421     delete[] config;
422   }
423   else
424   {
425     logger->log("Command", Log::INFO, "Config TV/S-Video not found");
426   }
427
428   // Set remote type
429
430   config = vdr->configLoad("General", "Remote type");
431
432   if (config)
433   {
434     if (!strcasecmp(config, "New"))
435     {
436       logger->log("Command", Log::INFO, "Switching to New remote type");
437       remote->setRemoteType(Remote::NEWREMOTE);
438     }
439     else
440     {
441       logger->log("Command", Log::INFO, "Switching to Old remote type");
442       remote->setRemoteType(Remote::OLDREMOTE);
443     }
444     delete[] config;
445   }
446   else
447   {
448     logger->log("Command", Log::INFO, "Config General/Remote type not found");
449     remote->setRemoteType(Remote::OLDREMOTE);
450   }
451
452   // Get TV aspect ratio
453
454   config = vdr->configLoad("TV", "Aspect");
455   if (config)
456   {
457     if (!strcasecmp(config, "16:9"))
458     {
459       logger->log("Command", Log::INFO, "/// Switching to TV aspect 16:9");
460       video->setTVsize(Video::ASPECT16X9);
461     }
462     else
463     {
464       logger->log("Command", Log::INFO, "/// Switching to TV aspect 4:3");
465       video->setTVsize(Video::ASPECT4X3);
466     }
467     delete[] config;
468   }
469   else
470   {
471     logger->log("Command", Log::INFO, "Config TV/Aspect type not found, going 4:3");
472     video->setTVsize(Video::ASPECT4X3);
473   }
474
475   config = vdr->configLoad("TV", "Widemode");
476   if (config)
477   {
478     if (!strcasecmp(config, "Letterbox"))
479     {
480       logger->log("Command", Log::INFO, "Setting letterbox mode");
481       video->setMode(Video::LETTERBOX);
482     }
483     else
484     {
485       logger->log("Command", Log::INFO, "Setting chop-sides mode");
486       video->setMode(Video::NORMAL);
487     }
488     delete[] config;
489   }
490   else
491   {
492     logger->log("Command", Log::INFO, "Config TV/Widemode not found, Setting chop-sides mode");
493     video->setMode(Video::NORMAL);
494   }
495
496   // config done
497
498   // Save power state = on
499
500   vdr->configSave("General", "Last Power State", "On");
501
502
503   viewman->removeView(vi);
504
505   VWelcome* vw = new VWelcome();
506   vw->draw();
507   vw->show();
508   viewman->add(vw);
509 }