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