]> git.vomp.tv Git - vompclient.git/blob - command.cc
Connection failure detection
[vompclient.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   connLost = NULL;
33 }
34
35 Command::~Command()
36 {
37   instance = NULL;
38 }
39
40 Command* Command::getInstance()
41 {
42   return instance;
43 }
44
45 int Command::init()
46 {
47   if (initted) return 0;
48   initted = 1;
49
50   logger = Log::getInstance();
51   viewman = ViewMan::getInstance();
52   remote = Remote::getInstance();
53
54   if (!logger || !viewman || !remote)
55   {
56     initted = 0;
57     return 0;
58   }
59
60   pthread_mutex_init(&masterLock, NULL);
61
62   return 1;
63 }
64
65 int Command::shutdown()
66 {
67   if (!initted) return 0;
68   initted = 0;
69   return 1;
70 }
71
72 void Command::stop()
73 {
74 //  VDR::getInstance()->cancelFindingServer();
75   irun = 0;
76 }
77
78 void Command::doWallpaper()
79 {
80   Video* video = Video::getInstance();
81
82   // Blue background
83   View* v = new View();
84   v->create(video->getScreenWidth(), video->getScreenHeight());
85   v->setBackgroundColour(Colour::VIDEOBLUE);
86   v->draw();
87   viewman->add(v);
88   viewman->updateView(v);
89   viewman->removeView(v);
90
91   // Wallpaper
92   wallpaper = new VWallpaper();
93   if (video->getFormat() == Video::PAL)
94   {
95     logger->log("Command", Log::DEBUG, "PAL wallpaper selected");
96     wallpaper->init("/wallpaperPAL.jpg");
97   }
98   else
99   {
100     logger->log("Command", Log::DEBUG, "NTSC wallpaper selected");
101     wallpaper->init("/wallpaperNTSC.jpg");
102   }
103   wallpaper->draw();
104   viewman->add(wallpaper);
105   viewman->updateView(wallpaper);
106 }
107
108 void Command::run()
109 {
110   if (!initted) return;
111   irun = 1;
112
113   mainPid = getpid();
114
115   // just in case
116   Video::getInstance()->signalOn();
117   Led::getInstance()->on();
118
119   doWallpaper();
120
121   // End of startup. Lock the mutex and put the first view up
122
123   pthread_mutex_lock(&masterLock);
124
125
126   VConnect* vconnect = new VConnect();
127   viewman->add(vconnect);
128   vconnect->run();
129
130
131   UCHAR button = 0;
132   while(irun)
133   {
134     // unlock and wait
135     pthread_mutex_unlock(&masterLock);
136
137     button = remote->getButtonPress(2);  // FIXME why is this set to 2 and not 0? so it can quit
138     // something happened, lock and process
139
140     pthread_mutex_lock(&masterLock);
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
159   pthread_mutex_lock(&masterLock);
160   MessageQueue::postMessage(m);
161   kill(mainPid, SIGURG);
162   pthread_mutex_unlock(&masterLock);
163 }
164
165 void Command::postMessageNoLock(Message* m)
166 {
167   // As above but use this one if this message is being posted because of a button press
168   // the mutex is already locked, locking around postMessage is not needed as the
169   // queue is guaranteed to be run when the button has been processed
170   MessageQueue::postMessage(m);
171 }
172
173 bool Command::postMessageIfNotBusy(Message* m)
174 {
175   // This is for the timers module
176   // If the masterlock is locked then the timers module wants to
177   // cancel delivery
178
179   if (pthread_mutex_trylock(&masterLock) != EBUSY)
180   {
181     MessageQueue::postMessage(m);
182     kill(mainPid, SIGURG);
183     pthread_mutex_unlock(&masterLock);
184     return true;
185   }
186   else
187   {
188     return false;
189   }
190 }
191
192 void Command::processMessage(Message* m)
193 {
194   logger->log("Command", Log::DEBUG, "processing message %i", m->message);
195
196   switch(m->message)
197   {
198     case Message::STANDBY:
199     {
200       doStandby();
201       break;
202     }
203     case Message::STOP_PLAYBACK:
204     {
205       handleCommand(Remote::STOP); // an odd way of doing it, but so simple
206       break;
207     }
208     case Message::STREAM_END:
209     {
210       VVideoLive::getInstance()->streamEnd();
211       break;
212     }
213     case Message::VDR_CONNECTED:
214     {
215       doJustConnected((VConnect*)m->from);
216       break;
217     }
218     case Message::TIMER:
219     {
220       // FIXME - go to one message queue only - then instead of having
221       // objects deriving from messagequeues, make them derive from
222       // messagereceiver - then one messagequeue can deliver any message to anywhere
223
224       // deliver timer
225
226       ((TimerReceiver*)m->to)->timercall(m->parameter);
227       handleCommand(Remote::NA_NONE); // in case any timer has posted messages to viewman,
228                                       // run viewman message queue here. FIXME improve this!
229       break;
230     }
231     case Message::SCREENSHOT:
232     {
233       Osd::getInstance()->screenShot("/out.jpg");
234       break;
235     }
236     case Message::CONNECTION_LOST:
237     {
238       doFromTheTop(true);
239       break;
240     }
241   }
242 }
243
244 void Command::handleCommand(int button)
245 {
246   if (isStandby && (button != Remote::POWER)) return;
247
248   if (!connLost && viewman->handleCommand(button)) return; // don't send to viewman if connLost
249
250   // command was not handled
251
252   switch(button)
253   {
254     case Remote::DF_LEFT:
255     case Remote::DF_RIGHT:
256     case Remote::VOLUMEUP:
257     case Remote::VOLUMEDOWN:
258     {
259       VVolume* v = new VVolume();
260       viewman->add(v);
261       v->handleCommand(button); // this will draw+show
262       return;
263     }
264     case Remote::MUTE:
265     {
266       VMute* v = new VMute();
267       v->draw();
268       viewman->add(v);
269       viewman->updateView(v);
270       return;
271     }
272     case Remote::POWER:
273     {
274       doStandby();
275       return;
276     }
277     case Remote::OK:
278     {
279       if (!connLost) return; // if connLost, handle Remote::OK
280       doFromTheTop(false);
281       return;
282     }
283   }
284 }
285
286 void Command::sig1()
287 {
288 #ifdef DEV
289   Message* m = new Message(); // break into master mutex
290   m->message = Message::SCREENSHOT;
291   m->to = this;
292   postMessage(m);
293 #endif
294 }
295
296 void Command::doStandby()
297 {
298   if (isStandby)
299   {
300     Video::getInstance()->signalOn();
301     Led::getInstance()->on();
302     isStandby = 0;
303
304
305     VConnect* vconnect = new VConnect();
306     viewman->add(vconnect);
307     vconnect->run();
308   }
309   else
310   {
311     viewman->removeAll();
312     Video::getInstance()->signalOff();
313     viewman->updateView(wallpaper);
314
315     VDR::getInstance()->configSave("General", "Last Power State", "Off");
316     VDR::getInstance()->disconnect();
317     Led::getInstance()->off();
318     isStandby = 1;
319   }
320 }
321
322 void Command::doFromTheTop(bool which)
323 {
324   if (which)
325   {
326     connLost = new VInfo();
327     connLost->create(360, 200);
328     if (Video::getInstance()->getFormat() == Video::PAL)
329       connLost->setScreenPos(190, 170);
330     else
331       connLost->setScreenPos(180, 120);
332     connLost->setOneLiner(tr("Connection lost"));
333     connLost->setDropThrough();
334     connLost->setBorderOn(1);
335     connLost->setTitleBarColour(Colour::DANGER);
336     connLost->okButton();
337     connLost->draw();
338     viewman->add(connLost);
339     viewman->updateView(connLost);
340     remote->clearBuffer();
341   }
342   else
343   {
344     VDR::getInstance()->disconnect();
345     viewman->removeAll();
346     viewman->updateView(wallpaper);
347     connLost = NULL;
348     VConnect* vconnect = new VConnect();
349     viewman->add(vconnect);
350     vconnect->run();
351   }
352 }
353
354 void Command::doReboot()
355 {
356   VDR::getInstance()->disconnect();
357   // just kill it...
358   logger->log("Command", Log::NOTICE, "Reboot");
359   reboot(LINUX_REBOOT_CMD_RESTART);
360 }
361
362 void Command::connectionLost()
363 {
364   Message* m = new Message(); // break into master mutex
365   m->message = Message::CONNECTION_LOST;
366   m->to = this;
367   postMessageNoLock(m);
368 }
369
370 void Command::doJustConnected(VConnect* vconnect)
371 {
372   I18n::initialize();
373   Video* video = Video::getInstance();
374   viewman->removeView(vconnect);
375
376   VInfo* vi = new VInfo();
377   vi->create(400, 200);
378   if (video->getFormat() == Video::PAL)
379     vi->setScreenPos(170, 200);
380   else
381     vi->setScreenPos(160, 150);
382
383   vi->setOneLiner(tr("Connected, loading config"));
384   vi->draw();
385   viewman->add(vi);
386   viewman->updateView(vi);
387
388   VDR* vdr = VDR::getInstance();
389   char* config;
390
391   // See if config says to override video format (PAL/NTSC)
392   config = vdr->configLoad("General", "Override Video Format");
393   if (config)
394   {
395     logger->log("Command", Log::DEBUG, "Override Video Format is present");
396
397     if (   (!strcmp(config, "PAL") && (video->getFormat() == Video::NTSC))
398         || (!strcmp(config, "NTSC") && (video->getFormat() == Video::PAL))  )
399     {
400       // Oh sheesh, need to switch format. Bye bye TV...
401
402       // Take everything down
403       viewman->removeAll();
404       viewman->removeView(wallpaper);
405       Osd* osd = Osd::getInstance();
406       osd->shutdown();
407       video->shutdown();
408
409       // Get video and osd back up with the new mode
410       if (!strcmp(config, "PAL"))
411       {
412         logger->log("Command", Log::DEBUG, "Switching to PAL");
413         video->init(Video::PAL);
414       }
415       else if (!strcmp(config, "NTSC"))
416       {
417         logger->log("Command", Log::DEBUG, "Switching to NTSC");
418         video->init(Video::NTSC);
419       }
420       osd->init("/dev/stbgfx");
421
422       // Put the wallpaper back
423       doWallpaper();
424
425       // Re add the vinfo
426       vi = new VInfo();
427       vi->create(400, 200);
428       if (video->getFormat() == Video::PAL)
429         vi->setScreenPos(170, 200);
430       else
431         vi->setScreenPos(160, 150);
432
433       vi->setOneLiner(tr("Connected, loading config"));
434       vi->draw();
435       viewman->add(vi);
436       viewman->updateView(vi);
437     }
438     else
439     {
440       logger->log("Command", Log::DEBUG, "Already in requested mode, or request was not 'PAL' or 'NTSC'");
441     }
442   }
443   else
444   {
445     logger->log("Command", Log::DEBUG, "Phew, no dangerous on-the-fly mode switching to do!");
446   }
447
448   // Power off if first boot and config says so
449   if (firstBoot)
450   {
451     firstBoot = 0;
452
453     logger->log("Command", Log::DEBUG, "Load power after boot");
454
455     config = vdr->configLoad("General", "Power After Boot");
456
457     if (config)
458     {
459       if (!strcasecmp(config, "On"))
460       {
461         logger->log("Command", Log::INFO, "Config says Power After Boot = On");
462       }
463       else if (!strcasecmp(config, "Off"))
464       {
465         logger->log("Command", Log::INFO, "Config says Power After Boot = Off");
466         doStandby();
467         delete[] config;
468         return; // quit here
469       }
470       else if (!strcasecmp(config, "Last state"))
471       {
472         char* lastPowerState = vdr->configLoad("General", "Last Power State");
473         if (lastPowerState)
474         {
475           if (!strcasecmp(lastPowerState, "On"))
476           {
477             logger->log("Command", Log::INFO, "Config says Last Power State = On");
478           }
479           else if (!strcasecmp(lastPowerState, "Off"))
480           {
481             logger->log("Command", Log::INFO, "Config says Last Power State = Off");
482             doStandby();
483             delete[] config;
484             return; // quit here
485           }
486           else
487           {
488             logger->log("Command", Log::INFO, "Config General/Last Power State not understood");
489           }
490         }
491         else
492         {
493           logger->log("Command", Log::INFO, "Config General/Last Power State not found");
494         }
495       }
496       else
497       {
498         logger->log("Command", Log::INFO, "Config/Power After Boot not understood");
499       }
500       delete[] config;
501     }
502     else
503     {
504       logger->log("Command", Log::INFO, "Config General/Power After Boot not found");
505     }
506   }
507
508
509   // Go S-Video if config says so
510
511   config = vdr->configLoad("TV", "Connection");
512
513   if (config)
514   {
515     if (!strcasecmp(config, "S-Video"))
516     {
517       logger->log("Command", Log::INFO, "Switching to S-Video as Connection=%s", config);
518       video->setConnection(Video::SVIDEO);
519     }
520     else
521     {
522       logger->log("Command", Log::INFO, "Switching to RGB/Composite as Connection=%s", config);
523       video->setConnection(Video::COMPOSITERGB);
524     }
525     delete[] config;
526   }
527   else
528   {
529     logger->log("Command", Log::INFO, "Config TV/S-Video not found");
530   }
531
532   // Set remote type
533
534   config = vdr->configLoad("General", "Remote type");
535
536   if (config)
537   {
538     if (!strcasecmp(config, "New"))
539     {
540       logger->log("Command", Log::INFO, "Switching to New remote type");
541       remote->setRemoteType(Remote::NEWREMOTE);
542     }
543     else
544     {
545       logger->log("Command", Log::INFO, "Switching to Old remote type");
546       remote->setRemoteType(Remote::OLDREMOTE);
547     }
548     delete[] config;
549   }
550   else
551   {
552     logger->log("Command", Log::INFO, "Config General/Remote type not found");
553     remote->setRemoteType(Remote::OLDREMOTE);
554   }
555
556   // Get TV aspect ratio
557
558   config = vdr->configLoad("TV", "Aspect");
559   if (config)
560   {
561     if (!strcasecmp(config, "16:9"))
562     {
563       logger->log("Command", Log::INFO, "/// Switching to TV aspect 16:9");
564       video->setTVsize(Video::ASPECT16X9);
565     }
566     else
567     {
568       logger->log("Command", Log::INFO, "/// Switching to TV aspect 4:3");
569       video->setTVsize(Video::ASPECT4X3);
570     }
571     delete[] config;
572   }
573   else
574   {
575     logger->log("Command", Log::INFO, "Config TV/Aspect type not found, going 4:3");
576     video->setTVsize(Video::ASPECT4X3);
577   }
578
579   config = vdr->configLoad("TV", "Widemode");
580   if (config)
581   {
582     if (!strcasecmp(config, "Letterbox"))
583     {
584       logger->log("Command", Log::INFO, "Setting letterbox mode");
585       video->setMode(Video::LETTERBOX);
586     }
587     else
588     {
589       logger->log("Command", Log::INFO, "Setting chop-sides mode");
590       video->setMode(Video::NORMAL);
591     }
592     delete[] config;
593   }
594   else
595   {
596     logger->log("Command", Log::INFO, "Config TV/Widemode not found, Setting chop-sides mode");
597     video->setMode(Video::NORMAL);
598   }
599
600   config = vdr->configLoad("Advanced", "TCP receive window");
601   if (config)
602   {
603     size_t newTCPsize = atoi(config);
604     delete[] config;
605
606     logger->log("Command", Log::INFO, "Setting TCP window size %i", newTCPsize);
607     vdr->setReceiveWindow(newTCPsize);
608   }
609   else
610   {
611     logger->log("Command", Log::INFO, "TCP window size not found, setting 2048");
612     vdr->setReceiveWindow(2048); // Default
613   }
614
615
616   // config done
617
618   // Save power state = on
619
620   vdr->configSave("General", "Last Power State", "On");
621
622   // Make sure connection didn't die
623   if (!vdr->isConnected())
624   {
625     Command::getInstance()->connectionLost();
626   }
627   else
628   {
629     viewman->removeView(vi);
630
631     VWelcome* vw = new VWelcome();
632     vw->draw();
633     viewman->add(vw);
634     viewman->updateView(vw);
635
636   // Enter pre-keys here
637 //  handleCommand(Remote::THREE);
638 //  handleCommand(Remote::DOWN);
639 //  handleCommand(Remote::OK);
640 //  handleCommand(Remote::PLAY);
641   }
642 }