MythTV  master
MythExternControl.cpp
Go to the documentation of this file.
1 /* -*- Mode: c++ -*-
2  *
3  * Copyright (C) John Poet 2018
4  *
5  * This file is part of MythTV
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program. If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 #include "MythExternControl.h"
22 #include "mythlogging.h"
23 
24 #include <QFile>
25 #include <QTextStream>
26 
27 #include <unistd.h>
28 #include <poll.h>
29 
30 #include <iostream>
31 
32 using namespace std;
33 
34 const QString VERSION = "0.6";
35 
36 #define LOC Desc()
37 
39  : m_buffer(this)
40  , m_commands(this)
41 {
42  setObjectName("Control");
43 
44  m_buffer.Start();
45  m_commands.Start();
46 }
47 
49 {
50  Terminate();
51  m_commands.Join();
52  m_buffer.Join();
53 }
54 
55 Q_SLOT void MythExternControl::Opened(void)
56 {
57  std::lock_guard<std::mutex> lock(m_flowMutex);
58 
59  m_ready = true;
60  m_flowCond.notify_all();
61 }
62 
63 Q_SLOT void MythExternControl::Streaming(bool val)
64 {
65  m_streaming = val;
66  m_flowCond.notify_all();
67 }
68 
70 {
71  emit Close();
72 }
73 
74 Q_SLOT void MythExternControl::Done(void)
75 {
77  {
78  m_run = false;
79  m_flowCond.notify_all();
80  m_runCond.notify_all();
81 
82  std::this_thread::sleep_for(std::chrono::microseconds(50));
83 
85  {
86  std::unique_lock<std::mutex> lk(m_flowMutex);
87  m_flowCond.wait_for(lk, std::chrono::milliseconds(1000));
88  }
89 
90  LOG(VB_RECORD, LOG_CRIT, LOC + "Terminated.");
91  }
92 }
93 
94 void MythExternControl::Error(const QString & msg)
95 {
96  LOG(VB_RECORD, LOG_CRIT, LOC + msg);
97 
98  std::unique_lock<std::mutex> lk(m_msgMutex);
99  if (m_errmsg.isEmpty())
100  m_errmsg = msg;
101  else
102  m_errmsg += "; " + msg;
103 }
104 
105 void MythExternControl::Fatal(const QString & msg)
106 {
107  Error(msg);
108  m_fatal = true;
109  Terminate();
110 }
111 
112 Q_SLOT void MythExternControl::SendMessage(const QString & cmd,
113  const QString & serial,
114  const QString & msg)
115 {
116  std::unique_lock<std::mutex> lk(m_msgMutex);
117  m_commands.SendStatus(cmd, serial, msg);
118 }
119 
120 Q_SLOT void MythExternControl::ErrorMessage(const QString & msg)
121 {
122  std::unique_lock<std::mutex> lk(m_msgMutex);
123  if (m_errmsg.isEmpty())
124  m_errmsg = msg;
125  else
126  m_errmsg += "; " + msg;
127 }
128 
129 #undef LOC
130 #define LOC QString("%1").arg(m_parent->Desc())
131 
132 void Commands::Close(void)
133 {
134  std::lock_guard<std::mutex> lock(m_parent->m_flowMutex);
135 
136  emit m_parent->Close();
137  m_parent->m_ready = false;
138  m_parent->m_flowCond.notify_all();
139 }
140 
141 void Commands::StartStreaming(const QString & serial)
142 {
143  emit m_parent->StartStreaming(serial);
144 }
145 
146 void Commands::StopStreaming(const QString & serial, bool silent)
147 {
148  emit m_parent->StopStreaming(serial, silent);
149 }
150 
151 void Commands::LockTimeout(const QString & serial) const
152 {
153  emit m_parent->LockTimeout(serial);
154 }
155 
156 void Commands::HasTuner(const QString & serial) const
157 {
158  emit m_parent->HasTuner(serial);
159 }
160 
161 void Commands::HasPictureAttributes(const QString & serial) const
162 {
163  emit m_parent->HasPictureAttributes(serial);
164 }
165 
166 void Commands::SetBlockSize(const QString & serial, int blksz)
167 {
168  emit m_parent->SetBlockSize(serial, blksz);
169 }
170 
171 void Commands::TuneChannel(const QString & serial, const QString & channum)
172 {
173  emit m_parent->TuneChannel(serial, channum);
174 }
175 
176 void Commands::TuneStatus(const QString & serial)
177 {
178  emit m_parent->TuneStatus(serial);
179 }
180 
181 void Commands::LoadChannels(const QString & serial)
182 {
183  emit m_parent->LoadChannels(serial);
184 }
185 
186 void Commands::FirstChannel(const QString & serial)
187 {
188  emit m_parent->FirstChannel(serial);
189 }
190 
191 void Commands::NextChannel(const QString & serial)
192 {
193  emit m_parent->NextChannel(serial);
194 }
195 
197 {
198  emit m_parent->Cleanup();
199 }
200 
201 bool Commands::SendStatus(const QString & command, const QString & status)
202 {
203  int len = write(2, status.toUtf8().constData(), status.size());
204  write(2, "\n", 1);
205 
206  if (len != status.size())
207  {
208  LOG(VB_RECORD, LOG_ERR, LOC +
209  QString("%1: Only wrote %2 of %3 bytes of message '%4'.")
210  .arg(command).arg(len).arg(status.size()).arg(status));
211  return false;
212  }
213 
214  LOG(VB_RECORD, LOG_INFO, LOC + QString("Processing '%1' --> '%2'")
215  .arg(command).arg(status));
216 
217  m_parent->ClearError();
218  return true;
219 }
220 
221 bool Commands::SendStatus(const QString & command, const QString & serial,
222  const QString & status)
223 {
224  QString msg = QString("%1:%2").arg(serial).arg(status);
225 
226  int len = write(2, msg.toUtf8().constData(), msg.size());
227  write(2, "\n", 1);
228 
229  if (len != msg.size())
230  {
231  LOG(VB_RECORD, LOG_ERR, LOC +
232  QString("%1: Only wrote %2 of %3 bytes of message '%4'.")
233  .arg(command).arg(len).arg(msg.size()).arg(msg));
234  return false;
235  }
236 
237  if (!command.isEmpty())
238  {
239  LOG(VB_RECORD, LOG_INFO, LOC + QString("Processing '%1' --> '%2'")
240  .arg(command).arg(msg));
241  }
242 #if 0
243  else
244  LOG(VB_RECORD, LOG_INFO, LOC + QString("%1").arg(msg));
245 #endif
246 
247  m_parent->ClearError();
248  return true;
249 }
250 
251 bool Commands::ProcessCommand(const QString & cmd)
252 {
253  LOG(VB_RECORD, LOG_DEBUG, LOC + QString("Processing '%1'").arg(cmd));
254 
255  std::unique_lock<std::mutex> lk1(m_parent->m_msgMutex);
256 
257  if (cmd.startsWith("APIVersion?"))
258  {
259  if (m_parent->m_fatal)
260  SendStatus(cmd, "ERR:" + m_parent->ErrorString());
261  else
262  SendStatus(cmd, "OK:2");
263  return true;
264  }
265 
266 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
267  QStringList tokens = cmd.split(':', QString::SkipEmptyParts);
268 #else
269  QStringList tokens = cmd.split(':', Qt::SkipEmptyParts);
270 #endif
271  if (tokens.size() < 2)
272  {
273  SendStatus(cmd, "0",
274  QString("0:ERR:Version 2 API expects serial_no:msg format. "
275  "Saw '%1' instead").arg(cmd));
276  return true;
277  }
278 
279  if (tokens[1].startsWith("APIVersion?"))
280  {
281  if (m_parent->m_fatal)
282  SendStatus(cmd, tokens[0], "ERR:" + m_parent->ErrorString());
283  else
284  SendStatus(cmd, tokens[0], "OK:2");
285  }
286  else if (tokens[1].startsWith("APIVersion"))
287  {
288  if (tokens.size() > 1)
289  {
290  m_apiVersion = tokens[2].toInt();
291  SendStatus(cmd, tokens[0], QString("OK:%1").arg(m_apiVersion));
292  }
293  else
294  SendStatus(cmd, tokens[0], "ERR:Missing API Version number");
295  }
296  else if (tokens[1].startsWith("Version?"))
297  {
298  if (m_parent->m_fatal)
299  SendStatus(cmd, tokens[0], "ERR:" + m_parent->ErrorString());
300  else
301  SendStatus(cmd, tokens[0], "OK:" + VERSION);
302  }
303  else if (tokens[1].startsWith("Description?"))
304  {
305  if (m_parent->m_fatal)
306  SendStatus(cmd, tokens[0], "ERR:" + m_parent->ErrorString());
307  else if (m_parent->m_desc.trimmed().isEmpty())
308  SendStatus(cmd, tokens[0], "WARN:Not set");
309  else
310  SendStatus(cmd, tokens[0], "OK:" + m_parent->m_desc.trimmed());
311  }
312  else if (tokens[1].startsWith("HasLock?"))
313  {
314  if (m_parent->m_ready)
315  SendStatus(cmd, tokens[0], "OK:Yes");
316  else
317  SendStatus(cmd, tokens[0], "OK:No");
318  }
319  else if (tokens[1].startsWith("SignalStrengthPercent"))
320  {
321  if (m_parent->m_ready)
322  SendStatus(cmd, tokens[0], "OK:100");
323  else
324  SendStatus(cmd, tokens[0], "OK:20");
325  }
326  else if (tokens[1].startsWith("LockTimeout?"))
327  {
328  LockTimeout(tokens[0]);
329  }
330  else if (tokens[1].startsWith("HasTuner"))
331  {
332  HasTuner(tokens[0]);
333  }
334  else if (tokens[1].startsWith("HasPictureAttributes"))
335  {
336  HasPictureAttributes(tokens[0]);
337  }
338  else if (tokens[1].startsWith("SendBytes"))
339  {
340  // Used when FlowControl is Polling
341  SendStatus(cmd, tokens[0], "ERR:Not supported");
342  }
343  else if (tokens[1].startsWith("XON"))
344  {
345  // Used when FlowControl is XON/XOFF
346  if (m_parent->m_streaming)
347  {
348  SendStatus(cmd, tokens[0], "OK");
349  m_parent->m_xon = true;
350  m_parent->m_flowCond.notify_all();
351  }
352  else
353  SendStatus(cmd, tokens[0], "WARN:Not streaming");
354  }
355  else if (tokens[1].startsWith("XOFF"))
356  {
357  if (m_parent->m_streaming)
358  {
359  SendStatus(cmd, tokens[0], "OK");
360  // Used when FlowControl is XON/XOFF
361  m_parent->m_xon = false;
362  m_parent->m_flowCond.notify_all();
363  }
364  else
365  SendStatus(cmd, tokens[0], "WARN:Not streaming");
366  }
367  else if (tokens[1].startsWith("TuneChannel"))
368  {
369  if (tokens.size() > 2)
370  TuneChannel(tokens[0], tokens[2]);
371  else
372  SendStatus(cmd, tokens[0], "ERR:Missing channum");
373  }
374  else if (tokens[1].startsWith("TuneStatus?"))
375  {
376  TuneStatus(tokens[0]);
377  }
378  else if (tokens[1].startsWith("LoadChannels"))
379  {
380  LoadChannels(tokens[0]);
381  }
382  else if (tokens[1].startsWith("FirstChannel"))
383  {
384  FirstChannel(tokens[0]);
385  }
386  else if (tokens[1].startsWith("NextChannel"))
387  {
388  NextChannel(tokens[0]);
389  }
390  else if (tokens[1].startsWith("IsOpen?"))
391  {
392  std::unique_lock<std::mutex> lk2(m_parent->m_runMutex);
393  if (m_parent->m_fatal)
394  SendStatus(cmd, tokens[0], "ERR:" + m_parent->ErrorString());
395  else if (m_parent->m_ready)
396  SendStatus(cmd, tokens[0], "OK:Open");
397  else
398  SendStatus(cmd, tokens[0], "WARN:Not Open yet");
399  }
400  else if (tokens[1].startsWith("CloseRecorder"))
401  {
402  if (m_parent->m_streaming)
403  StopStreaming(tokens[0], true);
404  m_parent->Terminate();
405  SendStatus(cmd, tokens[0], "OK:Terminating");
406  Cleanup();
407  }
408  else if (tokens[1].startsWith("FlowControl?"))
409  {
410  SendStatus(cmd, tokens[0], "OK:XON/XOFF");
411  }
412  else if (tokens[1].startsWith("BlockSize"))
413  {
414  if (tokens.size() > 1)
415  SetBlockSize(tokens[0], tokens[2].toUInt());
416  else
417  SendStatus(cmd, tokens[0], "ERR:Missing block size");
418  }
419  else if (tokens[1].startsWith("StartStreaming"))
420  {
421  StartStreaming(tokens[0]);
422  }
423  else if (tokens[1].startsWith("StopStreaming"))
424  {
425  /* This does not close the stream! When Myth is done with
426  * this 'recording' ExternalChannel::EnterPowerSavingMode()
427  * will be called, which invokes CloseRecorder() */
428  StopStreaming(tokens[0], false);
429  }
430  else
431  SendStatus(cmd, tokens[0],
432  QString("ERR:Unrecognized command '%1'").arg(tokens[1]));
433 
434  return true;
435 }
436 
437 void Commands::Run(void)
438 {
439  setObjectName("Commands");
440 
441  QString cmd;
442 
443  struct pollfd polls[2];
444  memset(polls, 0, sizeof(polls));
445 
446  polls[0].fd = 0;
447  polls[0].events = POLLIN | POLLPRI;
448  polls[0].revents = 0;
449 
450  QFile input;
451  input.open(stdin, QIODevice::ReadOnly);
452  QTextStream qtin(&input);
453 
454  LOG(VB_RECORD, LOG_INFO, LOC + "Command parser ready.");
455 
456  while (m_parent->m_run)
457  {
458  int timeout = 250;
459  int poll_cnt = 1;
460  int ret = poll(polls, poll_cnt, timeout);
461 
462  if (polls[0].revents & POLLHUP)
463  {
464  LOG(VB_RECORD, LOG_ERR, LOC + "poll eof (POLLHUP)");
465  break;
466  }
467  if (polls[0].revents & POLLNVAL)
468  {
469  m_parent->Fatal("poll error");
470  return;
471  }
472 
473  if (polls[0].revents & POLLIN)
474  {
475  if (ret > 0)
476  {
477  cmd = qtin.readLine();
478  if (!ProcessCommand(cmd))
479  m_parent->Fatal("Invalid command");
480  }
481  else if (ret < 0)
482  {
483  if ((EOVERFLOW == errno))
484  {
485  LOG(VB_RECORD, LOG_ERR, "command overflow");
486  break; // we have an error to handle
487  }
488 
489  if ((EAGAIN == errno) || (EINTR == errno))
490  {
491  LOG(VB_RECORD, LOG_ERR, LOC + "retry command read.");
492  continue; // errors that tell you to try again
493  }
494 
495  LOG(VB_RECORD, LOG_ERR, LOC + "unknown error reading command.");
496  }
497  }
498  }
499 
500  LOG(VB_RECORD, LOG_INFO, LOC + "Command parser: shutting down");
501  m_parent->m_commandsRunning = false;
502  m_parent->m_flowCond.notify_all();
503 }
504 
506  : m_parent(parent)
507 {
508  m_heartbeat = std::chrono::system_clock::now();
509 }
510 
511 bool Buffer::Fill(const QByteArray & buffer)
512 {
513  if (buffer.size() < 1)
514  return false;
515 
516  static int s_dropped = 0;
517  static int s_droppedBytes = 0;
518 
519  m_parent->m_flowMutex.lock();
520 
521  if (!m_dataSeen)
522  {
523  m_dataSeen = true;
524  emit m_parent->DataStarted();
525  }
526 
527  if (m_data.size() < MAX_QUEUE)
528  {
529  block_t blk(reinterpret_cast<const uint8_t *>(buffer.constData()),
530  reinterpret_cast<const uint8_t *>(buffer.constData())
531  + buffer.size());
532 
533  m_data.push(blk);
534  s_dropped = 0;
535 
536  LOG(VB_GENERAL, LOG_DEBUG, LOC +
537  QString("Adding %1 bytes").arg(buffer.size()));
538  }
539  else
540  {
541  s_droppedBytes += buffer.size();
542  LOG(VB_RECORD, LOG_WARNING, LOC +
543  QString("Packet queue overrun. Dropped %1 packets, %2 bytes.")
544  .arg(++s_dropped).arg(s_droppedBytes));
545 
546  std::this_thread::sleep_for(std::chrono::microseconds(250));
547  }
548 
549  m_parent->m_flowMutex.unlock();
550  m_parent->m_flowCond.notify_all();
551 
552  m_heartbeat = std::chrono::system_clock::now();
553 
554  return true;
555 }
556 
557 void Buffer::Run(void)
558 {
559  setObjectName("Buffer");
560 
561  bool is_empty = false;
562  bool wait = false;
563  time_t send_time = time (nullptr) + (60 * 5);
564  uint64_t write_total = 0;
565  uint64_t written = 0;
566  uint64_t write_cnt = 0;
567  uint64_t empty_cnt = 0;
568 
569  LOG(VB_RECORD, LOG_INFO, LOC + "Buffer: Ready for data.");
570 
571  while (m_parent->m_run)
572  {
573  {
574  std::unique_lock<std::mutex> lk(m_parent->m_flowMutex);
575  m_parent->m_flowCond.wait_for(lk,
576  std::chrono::milliseconds
577  (wait ? 5000 : 25));
578  wait = false;
579  }
580 
581  if (send_time < static_cast<double>(time (nullptr)))
582  {
583  // Every 5 minutes, write out some statistics.
584  send_time = time (nullptr) + (60 * 5);
585  write_total += written;
586  if (m_parent->m_streaming)
587  {
588  LOG(VB_RECORD, LOG_NOTICE, LOC +
589  QString("Count: %1, Empty cnt %2, Written %3, Total %4")
590  .arg(write_cnt).arg(empty_cnt)
591  .arg(written).arg(write_total));
592  }
593  else
594  {
595  LOG(VB_GENERAL, LOG_NOTICE, LOC + "Not streaming.");
596  }
597 
598  write_cnt = empty_cnt = written = 0;
599  }
600 
601  if (m_parent->m_streaming)
602  {
603  if (m_parent->m_xon)
604  {
605  block_t pkt;
606  m_parent->m_flowMutex.lock();
607  if (!m_data.empty())
608  {
609  pkt = m_data.front();
610  m_data.pop();
611  is_empty = m_data.empty();
612  }
613  m_parent->m_flowMutex.unlock();
614 
615  if (!pkt.empty())
616  {
617  uint sz = write(1, pkt.data(), pkt.size());
618  written += sz;
619  ++write_cnt;
620 
621  if (sz != pkt.size())
622  {
623  LOG(VB_GENERAL, LOG_WARNING, LOC +
624  QString("Only wrote %1 of %2 bytes to mythbackend")
625  .arg(sz).arg(pkt.size()));
626  }
627  }
628 
629  if (is_empty)
630  {
631  wait = true;
632  ++empty_cnt;
633  }
634  }
635  else
636  wait = true;
637  }
638  else
639  {
640  // Clear packet queue
641  m_parent->m_flowMutex.lock();
642  if (!m_data.empty())
643  {
644  stack_t dummy;
645  std::swap(m_data, dummy);
646  }
647  m_parent->m_flowMutex.unlock();
648 
649  wait = true;
650  }
651  }
652 
653  LOG(VB_RECORD, LOG_INFO, LOC + "Buffer: shutting down");
654  m_parent->m_bufferRunning = false;
655  m_parent->m_flowCond.notify_all();
656 }
MythExternControl::HasTuner
void HasTuner(const QString &serial) const
MythExternControl::Cleanup
void Cleanup(void)
hardwareprofile.smolt.timeout
float timeout
Definition: smolt.py:103
Commands::Start
void Start(void)
Definition: MythExternControl.h:83
Commands::TuneStatus
void TuneStatus(const QString &serial)
Definition: MythExternControl.cpp:176
MythExternControl::m_fatal
bool m_fatal
Definition: MythExternControl.h:180
MythExternControl::m_desc
QString m_desc
Definition: MythExternControl.h:171
MythExternControl::~MythExternControl
~MythExternControl(void) override
Definition: MythExternControl.cpp:48
MythExternControl::m_xon
std::atomic< bool > m_xon
Definition: MythExternControl.h:186
MythExternControl::FirstChannel
void FirstChannel(const QString &serial)
mythburn.write
def write(text, progress=True)
Definition: mythburn.py:308
arg
arg(title).arg(filename).arg(doDelete))
Buffer::Join
void Join(void)
Definition: MythExternControl.h:48
Commands::NextChannel
void NextChannel(const QString &serial)
Definition: MythExternControl.cpp:191
Commands::TuneChannel
void TuneChannel(const QString &serial, const QString &channum)
Definition: MythExternControl.cpp:171
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
MythExternControl::m_ready
std::atomic< bool > m_ready
Definition: MythExternControl.h:187
MythExternControl::m_run
std::atomic< bool > m_run
Definition: MythExternControl.h:173
Buffer::m_dataSeen
bool m_dataSeen
Definition: MythExternControl.h:69
LOC
#define LOC
Definition: MythExternControl.cpp:130
Buffer::Start
void Start(void)
Definition: MythExternControl.h:45
Commands::m_apiVersion
int m_apiVersion
Definition: MythExternControl.h:117
MythExternControl.h
VERSION
const QString VERSION
Definition: MythExternControl.cpp:34
MythExternControl::m_errmsg
QString m_errmsg
Definition: MythExternControl.h:181
MythExternControl::Opened
void Opened(void)
Definition: MythExternControl.cpp:55
Commands::Run
void Run(void)
Definition: MythExternControl.cpp:437
Commands::Close
void Close(void)
Definition: MythExternControl.cpp:132
MythExternControl::Error
void Error(const QString &msg)
Definition: MythExternControl.cpp:94
MythExternControl::Streaming
void Streaming(bool val)
Definition: MythExternControl.cpp:63
Commands::StartStreaming
void StartStreaming(const QString &serial)
Definition: MythExternControl.cpp:141
mythlogging.h
MythExternControl::m_streaming
std::atomic< bool > m_streaming
Definition: MythExternControl.h:185
Commands::HasTuner
void HasTuner(const QString &serial) const
Definition: MythExternControl.cpp:156
MythExternControl::TuneChannel
void TuneChannel(const QString &serial, const QString &channum)
Buffer::m_data
stack_t m_data
Definition: MythExternControl.h:68
Commands::LoadChannels
void LoadChannels(const QString &serial)
Definition: MythExternControl.cpp:181
MythExternControl::m_flowMutex
std::mutex m_flowMutex
Definition: MythExternControl.h:183
MythExternControl::Fatal
void Fatal(const QString &msg)
Definition: MythExternControl.cpp:105
Commands::LockTimeout
void LockTimeout(const QString &serial) const
Definition: MythExternControl.cpp:151
MythExternControl::MythExternControl
MythExternControl(void)
Definition: MythExternControl.cpp:38
MythExternControl::m_runCond
std::condition_variable m_runCond
Definition: MythExternControl.h:177
MythExternControl::m_flowCond
std::condition_variable m_flowCond
Definition: MythExternControl.h:184
MythExternControl::HasPictureAttributes
void HasPictureAttributes(const QString &serial) const
Buffer::m_parent
MythExternControl * m_parent
Definition: MythExternControl.h:64
MythExternControl::m_msgMutex
std::mutex m_msgMutex
Definition: MythExternControl.h:178
Commands::Cleanup
void Cleanup(void)
Definition: MythExternControl.cpp:196
Buffer::MAX_QUEUE
@ MAX_QUEUE
Definition: MythExternControl.h:41
uint
unsigned int uint
Definition: compat.h:140
MythExternControl::StopStreaming
void StopStreaming(const QString &serial, bool silent)
Commands::HasPictureAttributes
void HasPictureAttributes(const QString &serial) const
Definition: MythExternControl.cpp:161
MythExternControl::ErrorString
QString ErrorString(void) const
Definition: MythExternControl.h:138
MythExternControl::TuneStatus
void TuneStatus(const QString &serial)
MythExternControl
Definition: MythExternControl.h:121
MythExternControl::NextChannel
void NextChannel(const QString &serial)
MythExternControl::m_runMutex
std::mutex m_runMutex
Definition: MythExternControl.h:176
Buffer::Buffer
Buffer(MythExternControl *parent)
Definition: MythExternControl.cpp:505
MythExternControl::SendMessage
void SendMessage(const QString &cmd, const QString &serial, const QString &msg)
Definition: MythExternControl.cpp:112
MythExternControl::m_bufferRunning
std::atomic< bool > m_bufferRunning
Definition: MythExternControl.h:175
Commands::Join
void Join(void)
Definition: MythExternControl.h:86
MythExternControl::DataStarted
void DataStarted(void)
MythExternControl::StartStreaming
void StartStreaming(const QString &serial)
MythExternControl::LockTimeout
void LockTimeout(const QString &serial) const
MythExternControl::Close
void Close(void)
Commands::SetBlockSize
void SetBlockSize(const QString &serial, int blksz)
Definition: MythExternControl.cpp:166
MythExternControl::Done
void Done(void)
Definition: MythExternControl.cpp:74
MythExternControl::LoadChannels
void LoadChannels(const QString &serial)
Buffer::m_heartbeat
std::chrono::time_point< std::chrono::system_clock > m_heartbeat
Definition: MythExternControl.h:71
MythExternControl::SetBlockSize
void SetBlockSize(const QString &serial, int blksz)
MythExternControl::ClearError
void ClearError(void)
Definition: MythExternControl.h:139
Commands::SendStatus
bool SendStatus(const QString &command, const QString &status)
Definition: MythExternControl.cpp:201
Buffer::stack_t
std::queue< block_t > stack_t
Definition: MythExternControl.h:62
Buffer::Fill
bool Fill(const QByteArray &buffer)
Definition: MythExternControl.cpp:511
Commands::m_parent
MythExternControl * m_parent
Definition: MythExternControl.h:116
MythExternControl::m_commandsRunning
std::atomic< bool > m_commandsRunning
Definition: MythExternControl.h:174
Commands::ProcessCommand
bool ProcessCommand(const QString &cmd)
Definition: MythExternControl.cpp:251
MythExternControl::Terminate
void Terminate(void)
Definition: MythExternControl.cpp:69
Buffer::Run
void Run(void)
Definition: MythExternControl.cpp:557
Commands::StopStreaming
void StopStreaming(const QString &serial, bool silent)
Definition: MythExternControl.cpp:146
Commands::FirstChannel
void FirstChannel(const QString &serial)
Definition: MythExternControl.cpp:186
MythExternControl::m_buffer
Buffer m_buffer
Definition: MythExternControl.h:169
Buffer::block_t
std::vector< uint8_t > block_t
Definition: MythExternControl.h:61
MythExternControl::ErrorMessage
void ErrorMessage(const QString &msg)
Definition: MythExternControl.cpp:120
MythExternControl::m_commands
Commands m_commands
Definition: MythExternControl.h:170