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