00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include <cstdlib>
00012 #include <cmath>
00013
00014
00015 #include <unistd.h>
00016
00017
00018 #include <qapplication.h>
00019 #include <qregexp.h>
00020
00021
00022 #include "libmythui/mythmainwindow.h"
00023 #include "lcddevice.h"
00024 #include "mythcontext.h"
00025 #include "mythdialogs.h"
00026 #include "compat.h"
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 #define LCD_DEVICE_DEBUG 0
00038
00039 LCD::LCD()
00040 : QObject(NULL, "LCD"),
00041 socket(NULL), socketLock(true),
00042 hostname("localhost"), port(6545),
00043 bConnected(false),
00044
00045 retryTimer(new QTimer(this)), LEDTimer(new QTimer(this)),
00046
00047 send_buffer(""), last_command(QString::null),
00048
00049 lcd_width(0), lcd_height(0),
00050
00051 lcd_ready(false), lcd_showtime(false),
00052 lcd_showmenu(false), lcd_showgeneric(false),
00053 lcd_showmusic(false), lcd_showchannel(false),
00054 lcd_showvolume(false), lcd_showrecstatus(false),
00055 lcd_backlighton(false), lcd_heartbeaton(false),
00056
00057 lcd_popuptime(0),
00058
00059 lcd_showmusic_items(QString::null),
00060 lcd_keystring(QString::null),
00061
00062 GetLEDMask(NULL)
00063 {
00064
00065
00066
00067
00068
00069 #if LCD_DEVICE_DEBUG > 0
00070 VERBOSE(VB_IMPORTANT, "lcddevice: An LCD object now exists "
00071 "(LCD() was called)");
00072 #endif
00073
00074 connect(retryTimer, SIGNAL(timeout()), this, SLOT(restartConnection()));
00075 connect(LEDTimer, SIGNAL(timeout()), this, SLOT(outputLEDs()));
00076 }
00077
00078 bool LCD::m_enabled = false;
00079 bool LCD::m_server_unavailable = false;
00080 class LCD *LCD::m_lcd = NULL;
00081
00082 class LCD * LCD::Get(void)
00083 {
00084 if (m_enabled && m_lcd == NULL && m_server_unavailable == false)
00085 m_lcd = new LCD;
00086 return m_lcd;
00087 }
00088
00089 void LCD::SetupLCD (void)
00090 {
00091 QString lcd_host;
00092 int lcd_port;
00093
00094 if (m_lcd)
00095 {
00096 delete m_lcd;
00097 m_lcd = NULL;
00098 m_server_unavailable = false;
00099 }
00100
00101 lcd_host = gContext->GetSetting("LCDServerHost", "localhost");
00102 lcd_port = gContext->GetNumSetting("LCDServerPort", 6545);
00103 m_enabled = gContext->GetNumSetting("LCDEnable", 0);
00104
00105 if (m_enabled && lcd_host.length() > 0 && lcd_port > 1024)
00106 {
00107 class LCD * lcd = LCD::Get();
00108 if (lcd->connectToHost(lcd_host, lcd_port) == false)
00109 {
00110 delete m_lcd;
00111 m_lcd = NULL;
00112 m_server_unavailable = false;
00113 }
00114 }
00115 }
00116
00117 bool LCD::connectToHost(const QString &lhostname, unsigned int lport)
00118 {
00119 QMutexLocker locker(&socketLock);
00120
00121 #if LCD_DEVICE_DEBUG > 0
00122 VERBOSE(VB_IMPORTANT, "lcddevice: connecting to host: "
00123 << lhostname << " - port: " << lport);
00124 #endif
00125
00126
00127
00128 int timeout = 1000;
00129 hostname = lhostname;
00130 port = lport;
00131
00132
00133 if (!(m_enabled = gContext->GetNumSetting("LCDEnable", 0)))
00134 {
00135 bConnected = false;
00136 m_server_unavailable = true;
00137 return bConnected;
00138 }
00139
00140
00141 int res = system("ret=`ps cax | grep -c mythlcdserver`; exit $ret");
00142 if (WIFEXITED(res))
00143 res = WEXITSTATUS(res);
00144
00145 if (res == 0)
00146 {
00147
00148 VERBOSE(VB_GENERAL, "Starting mythlcdserver");
00149 system(gContext->GetInstallPrefix() + "/bin/mythlcdserver -v none&");
00150 usleep(500000);
00151 }
00152
00153 if (!bConnected)
00154 {
00155 int count = 0;
00156 do
00157 {
00158 ++count;
00159
00160 VERBOSE(VB_GENERAL, QString("Connecting to lcd server: "
00161 "%1:%2 (try %3 of 10)").arg(hostname).arg(port)
00162 .arg(count));
00163
00164 if (socket)
00165 socket->DownRef();
00166
00167 socket = new MythSocket();
00168 socket->setCallbacks(this);
00169 socket->connect(hostname, port);
00170
00171 timeout = 1000;
00172 while (--timeout && socket->state() != MythSocket::Idle)
00173 {
00174 qApp->lock();
00175 qApp->processEvents();
00176 qApp->unlock();
00177 usleep(1000);
00178
00179 if (socket->state() == MythSocket::Connected)
00180 {
00181 lcd_ready = false;
00182 bConnected = true;
00183
00184 QTextStream os(socket);
00185 os << "HELLO\n";
00186
00187
00188 usleep(1000);
00189 socket->Lock();
00190 socket->Unlock();
00191
00192 break;
00193 }
00194 }
00195
00196 usleep(500000);
00197 }
00198 while (count < 10 && !bConnected);
00199 }
00200
00201 if (bConnected == false)
00202 m_server_unavailable = true;
00203
00204 return bConnected;
00205 }
00206
00207 void LCD::sendToServer(const QString &someText)
00208 {
00209 QMutexLocker locker(&socketLock);
00210
00211 if (!socket || !lcd_ready)
00212 return;
00213
00214
00215 if (socket->state() == MythSocket::Idle)
00216 {
00217 lcd_ready = false;
00218
00219
00220
00221 retryTimer->start(10000, false);
00222 VERBOSE(VB_IMPORTANT, "lcddevice: Connection to LCDServer died unexpectedly.\n\t\t\t"
00223 "Trying to reconnect every 10 seconds. . .");
00224
00225 bConnected = false;
00226 return;
00227 }
00228
00229 QTextStream os(socket);
00230 os.setEncoding(QTextStream::Latin1);
00231
00232 last_command = someText;
00233
00234 if (bConnected)
00235 {
00236 #if LCD_DEVICE_DEBUG > 9
00237 VERBOSE(VB_IMPORTANT, "lcddevice: Sending to Server: " << someText);
00238 #endif
00239
00240
00241 os << someText << "\n";
00242 }
00243 else
00244 {
00245
00246
00247 send_buffer += someText;
00248 send_buffer += "\n";
00249 }
00250 }
00251
00252 void LCD::restartConnection()
00253 {
00254
00255 lcd_ready = false;
00256 bConnected = false;
00257 m_server_unavailable = false;
00258
00259
00260 connectToHost(hostname, port);
00261 }
00262
00263 void LCD::readyRead(MythSocket *sock)
00264 {
00265 (void) sock;
00266
00267 QMutexLocker locker(&socketLock);
00268
00269 QString lineFromServer, tempString;
00270 QStringList aList;
00271 QStringList::Iterator it;
00272
00273
00274
00275
00276
00277
00278
00279 int dataSize = socket->bytesAvailable() + 1;
00280 QCString data(dataSize);
00281
00282 socket->readBlock(data.data(), dataSize);
00283
00284 lineFromServer = data;
00285 lineFromServer = lineFromServer.replace( QRegExp("\n"), " " );
00286 lineFromServer = lineFromServer.replace( QRegExp("\r"), " " );
00287 lineFromServer.simplifyWhiteSpace();
00288
00289 #if LCD_DEVICE_DEBUG > 4
00290
00291 if (lineFromServer != "OK")
00292 VERBOSE(VB_IMPORTANT, "lcddevice: Received from server: " << lineFromServer);
00293 #endif
00294
00295 aList = QStringList::split(" ", lineFromServer);
00296 if (aList[0] == "CONNECTED")
00297 {
00298
00299
00300 if (aList.count() != 3)
00301 {
00302 VERBOSE(VB_IMPORTANT, "lcddevice: received bad no. of arguments "
00303 "in CONNECTED response from LCDServer");
00304 }
00305
00306 bool bOK;
00307 lcd_width = aList[1].toInt(&bOK);
00308 if (!bOK)
00309 {
00310 VERBOSE(VB_IMPORTANT, "lcddevice: received bad int for width"
00311 "in CONNECTED response from LCDServer");
00312 }
00313
00314 lcd_height = aList[2].toInt(&bOK);
00315 if (!bOK)
00316 {
00317 VERBOSE(VB_IMPORTANT, "lcddevice: received bad int for height"
00318 "in CONNECTED response from LCDServer");
00319 }
00320
00321 init();
00322 }
00323 else if (aList[0] == "HUH?")
00324 {
00325 VERBOSE(VB_IMPORTANT, "lcddevice: WARNING: Something is getting passed"
00326 "to LCDServer that it doesn't understand");
00327 VERBOSE(VB_IMPORTANT, "lcddevice: last command: " << last_command);
00328 }
00329 else if (aList[0] == "KEY")
00330 handleKeyPress(aList.last().stripWhiteSpace());
00331 }
00332
00333 void LCD::handleKeyPress(QString key_pressed)
00334 {
00335 int key = 0;
00336
00337 QChar mykey = key_pressed.at(0);
00338 if (mykey == lcd_keystring.at(0))
00339 key = Qt::Key_Up;
00340 else if (mykey == lcd_keystring.at(1))
00341 key = Qt::Key_Down;
00342 else if (mykey == lcd_keystring.at(2))
00343 key = Qt::Key_Left;
00344 else if (mykey == lcd_keystring.at(3))
00345 key = Qt::Key_Right;
00346 else if (mykey == lcd_keystring.at(4))
00347 key = Qt::Key_Space;
00348 else if (mykey == lcd_keystring.at(5))
00349 key = Qt::Key_Escape;
00350
00351 QApplication::postEvent(gContext->GetMainWindow(),
00352 new ExternalKeycodeEvent(key));
00353 }
00354
00355 void LCD::init()
00356 {
00357
00358 retryTimer->stop();
00359
00360
00361 lcd_showmusic = (gContext->GetSetting("LCDShowMusic", "1") == "1");
00362 lcd_showtime = (gContext->GetSetting("LCDShowTime", "1") == "1");
00363 lcd_showchannel = (gContext->GetSetting("LCDShowChannel", "1") == "1");
00364 lcd_showgeneric = (gContext->GetSetting("LCDShowGeneric", "1") == "1");
00365 lcd_showvolume = (gContext->GetSetting("LCDShowVolume", "1") == "1");
00366 lcd_showmenu = (gContext->GetSetting("LCDShowMenu", "1") == "1");
00367 lcd_showrecstatus = (gContext->GetSetting("LCDShowRecStatus", "1") == "1");
00368 lcd_keystring = gContext->GetSetting("LCDKeyString", "ABCDEF");
00369
00370 bConnected = true;
00371 lcd_ready = true;
00372
00373
00374 if (send_buffer.length() > 0)
00375 {
00376 sendToServer(send_buffer);
00377 send_buffer = "";
00378 }
00379 }
00380
00381 void LCD::connectionClosed(MythSocket *sock)
00382 {
00383 (void) sock;
00384 bConnected = false;
00385 }
00386
00387 void LCD::connectionFailed(MythSocket *sock)
00388 {
00389 QMutexLocker locker(&socketLock);
00390 QString err = sock->errorToString();
00391 VERBOSE(VB_IMPORTANT, QString("Could not connect to LCDServer: %1").arg(err));
00392 }
00393
00394 void LCD::stopAll()
00395 {
00396 if (!lcd_ready)
00397 return;
00398
00399 #if LCD_DEVICE_DEBUG > 1
00400 VERBOSE(VB_IMPORTANT, "lcddevice: stopAll");
00401 #endif
00402
00403 sendToServer("STOP_ALL");
00404 }
00405
00406 void LCD::setChannelProgress(float value)
00407 {
00408 if (!lcd_ready || !lcd_showchannel)
00409 return;
00410
00411 value = min(max(0.0f, value), 1.0f);
00412 sendToServer(QString("SET_CHANNEL_PROGRESS %1").arg(value));
00413 }
00414
00415 void LCD::setGenericProgress(float value)
00416 {
00417 if (!lcd_ready || !lcd_showgeneric)
00418 return;
00419
00420 value = min(max(0.0f, value), 1.0f);
00421 sendToServer(QString("SET_GENERIC_PROGRESS 0 %1").arg(value));
00422 }
00423
00424 void LCD::setGenericBusy()
00425 {
00426 if (!lcd_ready || !lcd_showgeneric)
00427 return;
00428
00429 sendToServer("SET_GENERIC_PROGRESS 1 0.0");
00430 }
00431
00432 void LCD::setMusicProgress(QString time, float value)
00433 {
00434 if (!lcd_ready || !lcd_showmusic)
00435 return;
00436
00437 value = min(max(0.0f, value), 1.0f);
00438 sendToServer("SET_MUSIC_PROGRESS " + quotedString(time) + " " +
00439 QString().setNum(value));
00440 }
00441
00442 void LCD::setMusicShuffle(int shuffle)
00443 {
00444 if (!lcd_ready || !lcd_showmusic)
00445 return;
00446
00447 sendToServer(QString("SET_MUSIC_PLAYER_PROP SHUFFLE %1").arg(shuffle));
00448 }
00449
00450 void LCD::setMusicRepeat(int repeat)
00451 {
00452 if (!lcd_ready || !lcd_showmusic)
00453 return;
00454
00455 sendToServer(QString("SET_MUSIC_PLAYER_PROP REPEAT %1").arg(repeat));
00456 }
00457
00458 void LCD::setVolumeLevel(float value)
00459 {
00460 if (!lcd_ready || !lcd_showvolume)
00461 return;
00462
00463 if (value < 0.0)
00464 value = 0.0;
00465 else if (value > 1.0)
00466 value = 1.0;
00467
00468 sendToServer("SET_VOLUME_LEVEL " + QString().setNum(value));
00469 }
00470
00471 void LCD::setupLEDs(int(*LedMaskFunc)(void))
00472 {
00473 GetLEDMask = LedMaskFunc;
00474
00475 LEDTimer->start(10000, FALSE);
00476 }
00477
00478 void LCD::outputLEDs()
00479 {
00480 if (!lcd_ready)
00481 return;
00482
00483 QString aString;
00484 int mask = 0;
00485 if (0 && GetLEDMask)
00486 mask = GetLEDMask();
00487 aString = "UPDATE_LEDS ";
00488 aString += QString::number(mask);
00489 sendToServer(aString);
00490 }
00491
00492 void LCD::switchToTime()
00493 {
00494 if (!lcd_ready || !lcd_showtime)
00495 return;
00496
00497 #if LCD_DEVICE_DEBUG > 1
00498 VERBOSE(VB_IMPORTANT, "lcddevice: switchToTime");
00499 #endif
00500
00501 sendToServer("SWITCH_TO_TIME");
00502 }
00503
00504 void LCD::switchToMusic(const QString &artist, const QString &album, const QString &track)
00505 {
00506 if (!lcd_ready || !lcd_showmusic)
00507 return;
00508
00509 #if LCD_DEVICE_DEBUG > 1
00510 VERBOSE(VB_IMPORTANT, "lcddevice: switchToMusic");
00511 #endif
00512
00513 sendToServer("SWITCH_TO_MUSIC " + quotedString(artist) + " "
00514 + quotedString(album) + " "
00515 + quotedString(track));
00516 }
00517
00518 void LCD::switchToChannel(QString channum, QString title, QString subtitle)
00519 {
00520 if (!lcd_ready || !lcd_showchannel)
00521 return;
00522
00523 #if LCD_DEVICE_DEBUG > 1
00524 VERBOSE(VB_IMPORTANT, "lcddevice: switchToChannel");
00525 #endif
00526
00527 sendToServer("SWITCH_TO_CHANNEL " + quotedString(channum) + " "
00528 + quotedString(title) + " "
00529 + quotedString(subtitle));
00530 }
00531
00532 void LCD::switchToMenu(QPtrList<LCDMenuItem> *menuItems, QString app_name,
00533 bool popMenu)
00534 {
00535 if (!lcd_ready || !lcd_showmenu)
00536 return;
00537
00538 #if LCD_DEVICE_DEBUG > 1
00539 VERBOSE(VB_IMPORTANT, "lcddevice: switchToMenu");
00540 #endif
00541
00542 if (menuItems->isEmpty())
00543 return;
00544
00545 QString s = "SWITCH_TO_MENU ";
00546
00547 s += quotedString(app_name);
00548 s += " " + QString(popMenu ? "TRUE" : "FALSE");
00549
00550
00551 QPtrListIterator<LCDMenuItem> it(*menuItems);
00552 LCDMenuItem *curItem;
00553
00554 while ((curItem = it.current()) != 0)
00555 {
00556 ++it;
00557 s += " " + quotedString(curItem->ItemName());
00558
00559 if (curItem->isChecked() == CHECKED)
00560 s += " CHECKED";
00561 else if (curItem->isChecked() == UNCHECKED)
00562 s += " UNCHECKED";
00563 else if (curItem->isChecked() == NOTCHECKABLE)
00564 s += " NOTCHECKABLE";
00565
00566 s += " " + QString(curItem->isSelected() ? "TRUE" : "FALSE");
00567 s += " " + QString(curItem->Scroll() ? "TRUE" : "FALSE");
00568 QString sIndent;
00569 sIndent.setNum(curItem->getIndent());
00570 s += " " + sIndent;
00571 }
00572
00573 sendToServer(s);
00574 }
00575
00576 void LCD::switchToGeneric(QPtrList<LCDTextItem> *textItems)
00577 {
00578 if (!lcd_ready || !lcd_showgeneric)
00579 return;
00580
00581 #if LCD_DEVICE_DEBUG > 1
00582 VERBOSE(VB_IMPORTANT, "lcddevice: switchToGeneric ");
00583 #endif
00584
00585 if (textItems->isEmpty())
00586 return;
00587
00588 QString s = "SWITCH_TO_GENERIC";
00589
00590 QPtrListIterator<LCDTextItem> it(*textItems);
00591 LCDTextItem *curItem;
00592
00593 while ((curItem = it.current()) != 0)
00594 {
00595 ++it;
00596 QString sRow;
00597 sRow.setNum(curItem->getRow());
00598 s += " " + sRow;
00599
00600 if (curItem->getAlignment() == ALIGN_LEFT)
00601 s += " ALIGN_LEFT";
00602 else if (curItem->getAlignment() == ALIGN_RIGHT)
00603 s += " ALIGN_RIGHT";
00604 else if (curItem->getAlignment() == ALIGN_CENTERED)
00605 s += " ALIGN_CENTERED";
00606
00607 s += " " + quotedString(curItem->getText());
00608 s += " " + quotedString(curItem->getScreen());
00609 s += " " + QString(curItem->getScroll() ? "TRUE" : "FALSE");
00610 }
00611
00612 sendToServer(s);
00613 }
00614
00615 void LCD::switchToVolume(QString app_name)
00616 {
00617 if (!lcd_ready || !lcd_showvolume)
00618 return;
00619
00620 #if LCD_DEVICE_DEBUG > 1
00621 VERBOSE(VB_IMPORTANT, "lcddevice: switchToVolume ");
00622 #endif
00623
00624 sendToServer("SWITCH_TO_VOLUME " + quotedString(app_name));
00625 }
00626
00627 void LCD::switchToNothing()
00628 {
00629 if (!lcd_ready)
00630 return;
00631
00632 #if LCD_DEVICE_DEBUG > 1
00633 VERBOSE(VB_IMPORTANT, "lcddevice: switchToNothing");
00634 #endif
00635
00636 sendToServer("SWITCH_TO_NOTHING");
00637 }
00638
00639 void LCD::shutdown()
00640 {
00641 QMutexLocker locker(&socketLock);
00642
00643 #if LCD_DEVICE_DEBUG > 1
00644 VERBOSE(VB_IMPORTANT, "lcddevice: shutdown");
00645 #endif
00646
00647 if (socket)
00648 socket->close();
00649
00650 lcd_ready = false;
00651 bConnected = false;
00652 }
00653
00654 void LCD::resetServer()
00655 {
00656 QMutexLocker locker(&socketLock);
00657
00658 if (!lcd_ready)
00659 return;
00660
00661 #if LCD_DEVICE_DEBUG > 1
00662 VERBOSE(VB_IMPORTANT, "lcddevice: RESET");
00663 #endif
00664
00665 sendToServer("RESET");
00666 }
00667
00668 LCD::~LCD()
00669 {
00670 m_lcd = NULL;
00671
00672 #if LCD_DEVICE_DEBUG > 0
00673 VERBOSE(VB_IMPORTANT, "lcddevice: An LCD device is being snuffed out of "
00674 "existence (~LCD() was called)");
00675 #endif
00676
00677 if (socket)
00678 {
00679 socket->DownRef();
00680 lcd_ready = false;
00681 }
00682 }
00683
00684
00685 void LCD::setLevels(int numbLevels, float *values)
00686 {
00687 numbLevels = numbLevels;
00688 values = values;
00689
00690 #if LCD_DEVICE_DEBUG > 0
00691 VERBOSE(VB_IMPORTANT, "lcddevice: setLevels");
00692 #endif
00693 }
00694
00695 QString LCD::quotedString(const QString &s)
00696 {
00697 QString sRes = s;
00698 sRes.replace(QRegExp("\""), QString("\"\""));
00699 sRes = "\"" + sRes + "\"";
00700
00701 return(sRes);
00702 }