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 
23 #include <array>
24 #include <iostream>
25 #include <poll.h>
26 #include <unistd.h>
27 
28 #include <QFile>
29 #include <QTextStream>
30 
32 
33 using namespace std::chrono_literals;
34 
35 const QString VERSION = "1.0";
36 
37 #define LOC Desc()
38 
40  : m_buffer(this)
41  , m_commands(this)
42 {
43  setObjectName("Control");
44 
45  m_buffer.Start();
46  m_commands.Start();
47 }
48 
50 {
51  Terminate();
52  m_commands.Join();
53  m_buffer.Join();
54 }
55 
56 Q_SLOT void MythExternControl::Opened(void)
57 {
58  std::lock_guard<std::mutex> lock(m_flowMutex);
59 
60  m_ready = true;
61  m_flowCond.notify_all();
62 }
63 
64 Q_SLOT void MythExternControl::Streaming(bool val)
65 {
66  m_streaming = val;
67  m_flowCond.notify_all();
68 }
69 
71 {
72  emit Close();
73 }
74 
75 Q_SLOT void MythExternControl::Done(void)
76 {
78  {
79  m_run = false;
80  m_flowCond.notify_all();
81  m_runCond.notify_all();
82 
83  std::this_thread::sleep_for(50us);
84 
86  {
87  std::unique_lock<std::mutex> lk(m_flowMutex);
88  m_flowCond.wait_for(lk, 1s);
89  }
90 
91  LOG(VB_RECORD, LOG_CRIT, LOC + "Terminated.");
92  }
93 }
94 
95 void MythExternControl::Error(const QString & msg)
96 {
97  LOG(VB_RECORD, LOG_CRIT, LOC + msg);
98 
99  std::unique_lock<std::mutex> lk(m_msgMutex);
100  if (m_errmsg.isEmpty())
101  m_errmsg = msg;
102  else
103  m_errmsg += "; " + msg;
104 }
105 
106 void MythExternControl::Fatal(const QString & msg)
107 {
108  Error(msg);
109  m_fatal = true;
110  Terminate();
111 }
112 
113 Q_SLOT void MythExternControl::SendMessage(const QString & cmd,
114  const QString & serial,
115  const QString & msg)
116 {
117  std::unique_lock<std::mutex> lk(m_msgMutex);
118  m_commands.SendStatus(cmd, serial, msg);
119 }
120 
121 Q_SLOT void MythExternControl::ErrorMessage(const QString & msg)
122 {
123  std::unique_lock<std::mutex> lk(m_msgMutex);
124  if (m_errmsg.isEmpty())
125  m_errmsg = msg;
126  else
127  m_errmsg += "; " + msg;
128 }
129 
130 #undef LOC
131 #define LOC QString("%1").arg(m_parent->Desc())
132 
133 void Commands::Close(void)
134 {
135  std::lock_guard<std::mutex> lock(m_parent->m_flowMutex);
136 
137  emit m_parent->Close();
138  m_parent->m_ready = false;
139  m_parent->m_flowCond.notify_all();
140 }
141 
142 void Commands::StartStreaming(const QString & serial)
143 {
144  emit m_parent->StartStreaming(serial);
145 }
146 
147 void Commands::StopStreaming(const QString & serial, bool silent)
148 {
149  emit m_parent->StopStreaming(serial, silent);
150 }
151 
152 void Commands::LockTimeout(const QString & serial) const
153 {
154  emit m_parent->LockTimeout(serial);
155 }
156 
157 void Commands::HasTuner(const QString & serial) const
158 {
159  emit m_parent->HasTuner(serial);
160 }
161 
162 void Commands::HasPictureAttributes(const QString & serial) const
163 {
164  emit m_parent->HasPictureAttributes(serial);
165 }
166 
167 void Commands::SetBlockSize(const QString & serial, int blksz)
168 {
169  emit m_parent->SetBlockSize(serial, blksz);
170 }
171 
172 void Commands::TuneChannel(const QString & serial, const QString & channum)
173 {
174  emit m_parent->TuneChannel(serial, channum);
175 }
176 
177 void Commands::TuneStatus(const QString & serial)
178 {
179  emit m_parent->TuneStatus(serial);
180 }
181 
182 void Commands::LoadChannels(const QString & serial)
183 {
184  emit m_parent->LoadChannels(serial);
185 }
186 
187 void Commands::FirstChannel(const QString & serial)
188 {
189  emit m_parent->FirstChannel(serial);
190 }
191 
192 void Commands::NextChannel(const QString & serial)
193 {
194  emit m_parent->NextChannel(serial);
195 }
196 
198 {
199  emit m_parent->Cleanup();
200 }
201 
202 bool Commands::SendStatus(const QString & command, const QString & status)
203 {
204  int len = write(2, status.toUtf8().constData(), status.size());
205  len += write(2, "\n", 1);
206 
207  if (len != status.size() + 1)
208  {
209  LOG(VB_RECORD, LOG_ERR, LOC +
210  QString("%1: Only wrote %2 of %3 bytes of message '%4'.")
211  .arg(command).arg(len).arg(status.size()).arg(status));
212  return false;
213  }
214 
215  LOG(VB_RECORD, LOG_INFO, LOC + QString("Processing '%1' --> '%2'")
216  .arg(command, status));
217 
218  m_parent->ClearError();
219  return true;
220 }
221 
222 bool Commands::SendStatus(const QString & command, const QString & serial,
223  const QString & status)
224 {
225  QString msg = QString("%1:%2").arg(serial, status);
226 
227  int len = write(2, msg.toUtf8().constData(), msg.size());
228  len += write(2, "\n", 1);
229 
230  if (len != msg.size() + 1)
231  {
232  LOG(VB_RECORD, LOG_ERR, LOC +
233  QString("%1: Only wrote %2 of %3 bytes of message '%4'.")
234  .arg(command).arg(len).arg(msg.size()).arg(msg));
235  return false;
236  }
237 
238  if (!command.isEmpty())
239  {
240  LOG(VB_RECORD, LOG_INFO, LOC + QString("Processing '%1' --> '%2'")
241  .arg(command, msg));
242  }
243 #if 0
244  else
245  LOG(VB_RECORD, LOG_INFO, LOC + QString("%1").arg(msg));
246 #endif
247 
248  m_parent->ClearError();
249  return true;
250 }
251 
252 bool Commands::ProcessCommand(const QString & cmd)
253 {
254  LOG(VB_RECORD, LOG_DEBUG, LOC + QString("Processing '%1'").arg(cmd));
255 
256  std::unique_lock<std::mutex> lk1(m_parent->m_msgMutex);
257 
258  if (cmd.startsWith("APIVersion?"))
259  {
260  if (m_parent->m_fatal)
261  SendStatus(cmd, "ERR:" + m_parent->ErrorString());
262  else
263  SendStatus(cmd, "OK:2");
264  return true;
265  }
266 
267 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
268  QStringList tokens = cmd.split(':', QString::SkipEmptyParts);
269 #else
270  QStringList tokens = cmd.split(':', Qt::SkipEmptyParts);
271 #endif
272  if (tokens.size() < 2)
273  {
274  SendStatus(cmd, "0",
275  QString("0:ERR:Version 2 API expects serial_no:msg format. "
276  "Saw '%1' instead").arg(cmd));
277  return true;
278  }
279 
280  if (tokens[1].startsWith("APIVersion?"))
281  {
282  if (m_parent->m_fatal)
283  SendStatus(cmd, tokens[0], "ERR:" + m_parent->ErrorString());
284  else
285  SendStatus(cmd, tokens[0], "OK:2");
286  }
287  else if (tokens[1].startsWith("APIVersion"))
288  {
289  if (tokens.size() > 1)
290  {
291  m_apiVersion = tokens[2].toInt();
292  SendStatus(cmd, tokens[0], QString("OK:%1").arg(m_apiVersion));
293  }
294  else
295  SendStatus(cmd, tokens[0], "ERR:Missing API Version number");
296  }
297  else if (tokens[1].startsWith("Version?"))
298  {
299  if (m_parent->m_fatal)
300  SendStatus(cmd, tokens[0], "ERR:" + m_parent->ErrorString());
301  else
302  SendStatus(cmd, tokens[0], "OK:" + VERSION);
303  }
304  else if (tokens[1].startsWith("Description?"))
305  {
306  if (m_parent->m_fatal)
307  SendStatus(cmd, tokens[0], "ERR:" + m_parent->ErrorString());
308  else if (m_parent->m_desc.trimmed().isEmpty())
309  SendStatus(cmd, tokens[0], "WARN:Not set");
310  else
311  SendStatus(cmd, tokens[0], "OK:" + m_parent->m_desc.trimmed());
312  }
313  else if (tokens[1].startsWith("HasLock?"))
314  {
315  if (m_parent->m_ready)
316  SendStatus(cmd, tokens[0], "OK:Yes");
317  else
318  SendStatus(cmd, tokens[0], "OK:No");
319  }
320  else if (tokens[1].startsWith("SignalStrengthPercent"))
321  {
322  if (m_parent->m_ready)
323  SendStatus(cmd, tokens[0], "OK:100");
324  else
325  SendStatus(cmd, tokens[0], "OK:20");
326  }
327  else if (tokens[1].startsWith("LockTimeout?"))
328  {
329  LockTimeout(tokens[0]);
330  }
331  else if (tokens[1].startsWith("HasTuner"))
332  {
333  HasTuner(tokens[0]);
334  }
335  else if (tokens[1].startsWith("HasPictureAttributes"))
336  {
337  HasPictureAttributes(tokens[0]);
338  }
339  else if (tokens[1].startsWith("SendBytes"))
340  {
341  // Used when FlowControl is Polling
342  SendStatus(cmd, tokens[0], "ERR:Not supported");
343  }
344  else if (tokens[1].startsWith("XON"))
345  {
346  // Used when FlowControl is XON/XOFF
347  if (m_parent->m_streaming)
348  {
349  SendStatus(cmd, tokens[0], "OK");
350  m_parent->m_xon = true;
351  m_parent->m_flowCond.notify_all();
352  }
353  else
354  SendStatus(cmd, tokens[0], "WARN:Not streaming");
355  }
356  else if (tokens[1].startsWith("XOFF"))
357  {
358  if (m_parent->m_streaming)
359  {
360  SendStatus(cmd, tokens[0], "OK");
361  // Used when FlowControl is XON/XOFF
362  m_parent->m_xon = false;
363  m_parent->m_flowCond.notify_all();
364  }
365  else
366  SendStatus(cmd, tokens[0], "WARN:Not streaming");
367  }
368  else if (tokens[1].startsWith("TuneChannel"))
369  {
370  if (tokens.size() > 2)
371  TuneChannel(tokens[0], tokens[2]);
372  else
373  SendStatus(cmd, tokens[0], "ERR:Missing channum");
374  }
375  else if (tokens[1].startsWith("TuneStatus?"))
376  {
377  TuneStatus(tokens[0]);
378  }
379  else if (tokens[1].startsWith("LoadChannels"))
380  {
381  LoadChannels(tokens[0]);
382  }
383  else if (tokens[1].startsWith("FirstChannel"))
384  {
385  FirstChannel(tokens[0]);
386  }
387  else if (tokens[1].startsWith("NextChannel"))
388  {
389  NextChannel(tokens[0]);
390  }
391  else if (tokens[1].startsWith("IsOpen?"))
392  {
393  std::unique_lock<std::mutex> lk2(m_parent->m_runMutex);
394  if (m_parent->m_fatal)
395  SendStatus(cmd, tokens[0], "ERR:" + m_parent->ErrorString());
396  else if (m_parent->m_ready)
397  SendStatus(cmd, tokens[0], "OK:Open");
398  else
399  SendStatus(cmd, tokens[0], "WARN:Not Open yet");
400  }
401  else if (tokens[1].startsWith("CloseRecorder"))
402  {
403  if (m_parent->m_streaming)
404  StopStreaming(tokens[0], true);
405  m_parent->Terminate();
406  SendStatus(cmd, tokens[0], "OK:Terminating");
407  Cleanup();
408  }
409  else if (tokens[1].startsWith("FlowControl?"))
410  {
411  SendStatus(cmd, tokens[0], "OK:XON/XOFF");
412  }
413  else if (tokens[1].startsWith("BlockSize"))
414  {
415  if (tokens.size() > 1)
416  SetBlockSize(tokens[0], tokens[2].toUInt());
417  else
418  SendStatus(cmd, tokens[0], "ERR:Missing block size");
419  }
420  else if (tokens[1].startsWith("StartStreaming"))
421  {
422  StartStreaming(tokens[0]);
423  }
424  else if (tokens[1].startsWith("StopStreaming"))
425  {
426  /* This does not close the stream! When Myth is done with
427  * this 'recording' ExternalChannel::EnterPowerSavingMode()
428  * will be called, which invokes CloseRecorder() */
429  StopStreaming(tokens[0], false);
430  }
431  else
432  SendStatus(cmd, tokens[0],
433  QString("ERR:Unrecognized command '%1'").arg(tokens[1]));
434 
435  return true;
436 }
437 
438 void Commands::Run(void)
439 {
440  setObjectName("Commands");
441 
442  QString cmd;
443 
444  std::array<struct pollfd,2> 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.data(), 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(250us);
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  auto send_time = std::chrono::system_clock::now() + 5min;
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, wait ? 5s : 25ms);
576  wait = false;
577  }
578 
579  if (send_time < std::chrono::system_clock::now())
580  {
581  // Every 5 minutes, write out some statistics.
582  send_time = std::chrono::system_clock::now() + 5min;
583  write_total += written;
584  if (m_parent->m_streaming)
585  {
586  LOG(VB_RECORD, LOG_NOTICE, LOC +
587  QString("Count: %1, Empty cnt %2, Written %3, Total %4")
588  .arg(write_cnt).arg(empty_cnt)
589  .arg(written).arg(write_total));
590  }
591  else
592  {
593  LOG(VB_GENERAL, LOG_NOTICE, LOC + "Not streaming.");
594  }
595 
596  write_cnt = empty_cnt = written = 0;
597  }
598 
599  if (m_parent->m_streaming)
600  {
601  if (m_parent->m_xon)
602  {
603  block_t pkt;
604  m_parent->m_flowMutex.lock();
605  if (!m_data.empty())
606  {
607  pkt = m_data.front();
608  m_data.pop();
609  is_empty = m_data.empty();
610  }
611  m_parent->m_flowMutex.unlock();
612 
613  if (!pkt.empty())
614  {
615  uint sz = write(1, pkt.data(), pkt.size());
616  written += sz;
617  ++write_cnt;
618 
619  if (sz != pkt.size())
620  {
621  LOG(VB_GENERAL, LOG_WARNING, LOC +
622  QString("Only wrote %1 of %2 bytes to mythbackend")
623  .arg(sz).arg(pkt.size()));
624  }
625  }
626 
627  if (is_empty)
628  {
629  wait = true;
630  ++empty_cnt;
631  }
632  }
633  else
634  wait = true;
635  }
636  else
637  {
638  // Clear packet queue
639  m_parent->m_flowMutex.lock();
640  if (!m_data.empty())
641  {
642  stack_t dummy;
643  std::swap(m_data, dummy);
644  }
645  m_parent->m_flowMutex.unlock();
646 
647  wait = true;
648  }
649  }
650 
651  LOG(VB_RECORD, LOG_INFO, LOC + "Buffer: shutting down");
652  m_parent->m_bufferRunning = false;
653  m_parent->m_flowCond.notify_all();
654 }
MythExternControl::Cleanup
void Cleanup(void)
hardwareprofile.smolt.timeout
float timeout
Definition: smolt.py:103
Commands::Start
void Start(void)
Definition: MythExternControl.h:82
Commands::TuneStatus
void TuneStatus(const QString &serial)
Definition: MythExternControl.cpp:177
MythExternControl::m_fatal
bool m_fatal
Definition: MythExternControl.h:179
MythExternControl::m_desc
QString m_desc
Definition: MythExternControl.h:170
MythExternControl::~MythExternControl
~MythExternControl(void) override
Definition: MythExternControl.cpp:49
MythExternControl::m_xon
std::atomic< bool > m_xon
Definition: MythExternControl.h:185
MythExternControl::FirstChannel
void FirstChannel(const QString &serial)
mythburn.write
def write(text, progress=True)
Definition: mythburn.py:308
Buffer::Join
void Join(void)
Definition: MythExternControl.h:48
Commands::NextChannel
void NextChannel(const QString &serial)
Definition: MythExternControl.cpp:192
Commands::TuneChannel
void TuneChannel(const QString &serial, const QString &channum)
Definition: MythExternControl.cpp:172
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
MythExternControl::m_ready
std::atomic< bool > m_ready
Definition: MythExternControl.h:186
MythExternControl::m_run
std::atomic< bool > m_run
Definition: MythExternControl.h:172
Buffer::m_dataSeen
bool m_dataSeen
Definition: MythExternControl.h:69
MythExternControl::HasTuner
void HasTuner(const QString &serial)
LOC
#define LOC
Definition: MythExternControl.cpp:131
Buffer::Start
void Start(void)
Definition: MythExternControl.h:45
Commands::m_apiVersion
int m_apiVersion
Definition: MythExternControl.h:116
MythExternControl.h
VERSION
const QString VERSION
Definition: MythExternControl.cpp:35
MythExternControl::m_errmsg
QString m_errmsg
Definition: MythExternControl.h:180
MythExternControl::Opened
void Opened(void)
Definition: MythExternControl.cpp:56
MythExternControl::LockTimeout
void LockTimeout(const QString &serial)
Commands::Run
void Run(void)
Definition: MythExternControl.cpp:438
Commands::Close
void Close(void)
Definition: MythExternControl.cpp:133
MythExternControl::Error
void Error(const QString &msg)
Definition: MythExternControl.cpp:95
MythExternControl::Streaming
void Streaming(bool val)
Definition: MythExternControl.cpp:64
Commands::StartStreaming
void StartStreaming(const QString &serial)
Definition: MythExternControl.cpp:142
mythlogging.h
MythExternControl::m_streaming
std::atomic< bool > m_streaming
Definition: MythExternControl.h:184
Commands::HasTuner
void HasTuner(const QString &serial) const
Definition: MythExternControl.cpp:157
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:182
MythExternControl::m_flowMutex
std::mutex m_flowMutex
Definition: MythExternControl.h:182
MythExternControl::Fatal
void Fatal(const QString &msg)
Definition: MythExternControl.cpp:106
Commands::LockTimeout
void LockTimeout(const QString &serial) const
Definition: MythExternControl.cpp:152
MythExternControl::MythExternControl
MythExternControl(void)
Definition: MythExternControl.cpp:39
MythExternControl::m_runCond
std::condition_variable m_runCond
Definition: MythExternControl.h:176
MythExternControl::m_flowCond
std::condition_variable m_flowCond
Definition: MythExternControl.h:183
Buffer::m_parent
MythExternControl * m_parent
Definition: MythExternControl.h:64
MythExternControl::m_msgMutex
std::mutex m_msgMutex
Definition: MythExternControl.h:177
Commands::Cleanup
void Cleanup(void)
Definition: MythExternControl.cpp:197
Buffer::MAX_QUEUE
@ MAX_QUEUE
Definition: MythExternControl.h:41
uint
unsigned int uint
Definition: compat.h:81
MythExternControl::StopStreaming
void StopStreaming(const QString &serial, bool silent)
Commands::HasPictureAttributes
void HasPictureAttributes(const QString &serial) const
Definition: MythExternControl.cpp:162
MythExternControl::ErrorString
QString ErrorString(void) const
Definition: MythExternControl.h:137
MythExternControl::TuneStatus
void TuneStatus(const QString &serial)
MythExternControl
Definition: MythExternControl.h:119
MythExternControl::NextChannel
void NextChannel(const QString &serial)
MythExternControl::m_runMutex
std::mutex m_runMutex
Definition: MythExternControl.h:175
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:113
MythExternControl::m_bufferRunning
std::atomic< bool > m_bufferRunning
Definition: MythExternControl.h:174
Commands::Join
void Join(void)
Definition: MythExternControl.h:85
MythExternControl::DataStarted
void DataStarted(void)
MythExternControl::StartStreaming
void StartStreaming(const QString &serial)
MythExternControl::Close
void Close(void)
Commands::SetBlockSize
void SetBlockSize(const QString &serial, int blksz)
Definition: MythExternControl.cpp:167
MythExternControl::Done
void Done(void)
Definition: MythExternControl.cpp:75
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:138
Commands::SendStatus
bool SendStatus(const QString &command, const QString &status)
Definition: MythExternControl.cpp:202
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:115
MythExternControl::m_commandsRunning
std::atomic< bool > m_commandsRunning
Definition: MythExternControl.h:173
Commands::ProcessCommand
bool ProcessCommand(const QString &cmd)
Definition: MythExternControl.cpp:252
MythExternControl::HasPictureAttributes
void HasPictureAttributes(const QString &serial)
MythExternControl::Terminate
void Terminate(void)
Definition: MythExternControl.cpp:70
Buffer::Run
void Run(void)
Definition: MythExternControl.cpp:557
Commands::StopStreaming
void StopStreaming(const QString &serial, bool silent)
Definition: MythExternControl.cpp:147
Commands::FirstChannel
void FirstChannel(const QString &serial)
Definition: MythExternControl.cpp:187
MythExternControl::m_buffer
Buffer m_buffer
Definition: MythExternControl.h:168
Buffer::block_t
std::vector< uint8_t > block_t
Definition: MythExternControl.h:61
MythExternControl::ErrorMessage
void ErrorMessage(const QString &msg)
Definition: MythExternControl.cpp:121
MythExternControl::m_commands
Commands m_commands
Definition: MythExternControl.h:169