MythTV  master
dvbci.cpp
Go to the documentation of this file.
1 /*
2  * ci.cc: Common Interface
3  *
4  * Copyright (C) 2000 Klaus Schmidinger
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
19  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
20  *
21  * The author can be reached at kls@cadsoft.de
22  *
23  * The project's page is at http://www.cadsoft.de/people/kls/vdr
24  *
25  */
26 
27 #include "dvbci.h"
28 
29 #include <array>
30 #include <cctype>
31 #include <cerrno>
32 #include <cstring>
33 #include <ctime>
34 #include <fcntl.h>
35 #include <linux/dvb/ca.h>
36 #include <netinet/in.h>
37 #include <poll.h>
38 #include <sys/ioctl.h>
39 #include <sys/time.h>
40 #include <unistd.h>
41 #ifdef __FreeBSD__
42 # include <stdlib.h>
43 #else
44 # include <malloc.h>
45 #endif
46 
47 #include <QString>
48 
50 
51 // NOLINTBEGIN(cppcoreguidelines-macro-usage)
52 #define esyslog(a...) LOG(VB_GENERAL, LOG_ERR, QString::asprintf(a))
53 #define isyslog(a...) LOG(VB_DVBCAM, LOG_INFO, QString::asprintf(a))
54 #define dsyslog(a...) LOG(VB_DVBCAM, LOG_DEBUG, QString::asprintf(a))
55 
56 #define LOG_ERROR esyslog("ERROR (%s,%d): %m", __FILE__, __LINE__)
57 #define LOG_ERROR_STR(s) esyslog("ERROR: %s: %m", s)
58 // NOLINTEND(cppcoreguidelines-macro-usage)
59 
60 
61 // Set these to 'true' for debug output:
62 static bool sDumpTPDUDataTransfer = false;
63 static bool sDebugProtocol = false;
64 static bool sConnected = false;
65 
66 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
67 #define dbgprotocol(a...) if (sDebugProtocol) LOG(VB_DVBCAM, LOG_DEBUG, QString::asprintf(a))
68 
69 static constexpr int OK { 0 };
70 static constexpr int TIMEOUT { -1 };
71 static constexpr int ERROR { -2 };
72 
73 // --- Workarounds -----------------------------------------------------------
74 
75 // The Irdeto AllCAM 4.7 (and maybe others, too) does not react on AOT_ENTER_MENU
76 // during the first few seconds of a newly established connection
77 static constexpr time_t WRKRND_TIME_BEFORE_ENTER_MENU { 15 }; // seconds
78 
79 // --- Helper functions ------------------------------------------------------
80 
81 static constexpr int SIZE_INDICATOR { 0x80 };
82 
83 static ssize_t safe_read(int filedes, void *buffer, size_t size)
84 {
85  for (;;) {
86  ssize_t p = read(filedes, buffer, size);
87  if (p < 0 && (errno == EINTR || errno == EAGAIN)) {
88  dsyslog("EINTR while reading from file handle %d - retrying", filedes);
89  continue;
90  }
91  return p;
92  }
93 }
94 
95 static const uint8_t *GetLength(const uint8_t *Data, int &Length)
106 {
107  Length = *Data++;
108  if ((Length & SIZE_INDICATOR) != 0) {
109  int l = Length & ~SIZE_INDICATOR;
110  Length = 0;
111  for (int i = 0; i < l; i++)
112  Length = (Length << 8) | *Data++;
113  }
114  return Data;
115 }
116 
117 static uint8_t *SetLength(uint8_t *Data, int Length)
127 {
128  uint8_t *p = Data;
129  if (Length < 128)
130  *p++ = Length;
131  else {
132  int n = sizeof(Length);
133  for (int i = n - 1; i >= 0; i--) {
134  int b = (Length >> (8 * i)) & 0xFF;
135  if (p != Data || b)
136  *++p = b;
137  }
138  *Data = (p - Data) | SIZE_INDICATOR;
139  p++;
140  }
141  return p;
142 }
143 
145 static void SetLength(std::vector<uint8_t> &Data, int Length)
146 {
147  if (Length < 128)
148  {
149  Data.push_back(Length);
150  return;
151  }
152 
153  // This will be replaced with the number of bytes in the length
154  size_t len_offset = Data.size();
155  Data.push_back(0);
156 
157  int n = sizeof(Length);
158  for (int i = n - 1; i >= 0; i--) {
159  int b = (Length >> (8 * i)) & 0xFF;
160  if ((len_offset != Data.size()) || b)
161  Data.push_back(b);
162  }
163  Data[len_offset] = (Data.size() - len_offset) | SIZE_INDICATOR;
164 }
165 
166 static char *CopyString(int Length, const uint8_t *Data)
171 {
172  char *s = (char *)malloc(Length + 1);
173  strncpy(s, (char *)Data, Length);
174  s[Length] = 0;
175  return s;
176 }
177 
178 static char *GetString(int &Length, const uint8_t **Data)
186 {
187  if (Length > 0 && Data && *Data) {
188  int l = 0;
189  const uint8_t *d = GetLength(*Data, l);
190  char *s = CopyString(l, d);
191  Length -= d - *Data + l;
192  *Data = d + l;
193  return s;
194  }
195  return nullptr;
196 }
197 
198 
199 
200 // --- cMutex ----------------------------------------------------------------
201 
202 void cMutex::Lock(void)
203 {
204  if (getpid() != m_lockingPid || !m_locked) {
205  pthread_mutex_lock(&m_mutex);
206  m_lockingPid = getpid();
207  }
208  m_locked++;
209 }
210 
211 void cMutex::Unlock(void)
212 {
213  if (--m_locked <= 0) {
214  if (m_locked < 0) {
215  esyslog("cMutex Lock inbalance detected");
216  m_locked = 0;
217  }
218  m_lockingPid = 0;
219  pthread_mutex_unlock(&m_mutex);
220  }
221 }
222 // --- cMutexLock ------------------------------------------------------------
223 
225 {
226  if (m_mutex && m_locked)
227  m_mutex->Unlock();
228 }
229 
231 {
232  if (Mutex && !m_mutex) {
233  m_mutex = Mutex;
234  Mutex->Lock();
235  m_locked = true;
236  return true;
237  }
238  return false;
239 }
240 
241 
242 
243 // --- cTPDU -----------------------------------------------------------------
244 
245 static constexpr size_t MAX_TPDU_SIZE { 2048 };
246 static constexpr int MAX_TPDU_DATA { MAX_TPDU_SIZE - 4 };
247 
248 static constexpr uint8_t DATA_INDICATOR { 0x80 };
249 
250 enum T_VALUES : std::uint8_t {
251  T_SB = 0x80,
252  T_RCV = 0x81,
253  T_CREATE_TC = 0x82,
254  T_CTC_REPLY = 0x83,
255  T_DELETE_TC = 0x84,
256  T_DTC_REPLY = 0x85,
257  T_REQUEST_TC = 0x86,
258  T_NEW_TC = 0x87,
259  T_TC_ERROR = 0x88,
260  T_DATA_LAST = 0xA0,
261  T_DATA_MORE = 0xA1,
262 };
263 
264 class cTPDU {
265 private:
266  ssize_t m_size {0};
267  std::array<uint8_t,MAX_TPDU_SIZE> m_data {0};
268  const uint8_t *GetData(const uint8_t *Data, int &Length) const;
269 public:
270  cTPDU(void) = default;
271  cTPDU(uint8_t Slot, uint8_t Tcid, uint8_t Tag, int Length = 0, const uint8_t *Data = nullptr);
272  uint8_t Slot(void) { return m_data[0]; }
273  uint8_t Tcid(void) { return m_data[1]; }
274  uint8_t Tag(void) { return m_data[2]; }
275  const uint8_t *Data(int &Length) { return GetData(m_data.data() + 3, Length); }
276  uint8_t Status(void);
277  int Write(int fd);
278  int Read(int fd);
279  void Dump(bool Outgoing);
280  };
281 
282 cTPDU::cTPDU(uint8_t Slot, uint8_t Tcid, uint8_t Tag, int Length, const uint8_t *Data)
283 {
284  m_data[0] = Slot;
285  m_data[1] = Tcid;
286  m_data[2] = Tag;
287  switch (Tag) {
288  case T_RCV:
289  case T_CREATE_TC:
290  case T_CTC_REPLY:
291  case T_DELETE_TC:
292  case T_DTC_REPLY:
293  case T_REQUEST_TC:
294  m_data[3] = 1; // length
295  m_data[4] = Tcid;
296  m_size = 5;
297  break;
298  case T_NEW_TC:
299  case T_TC_ERROR:
300  if (Length == 1) {
301  m_data[3] = 2; // length
302  m_data[4] = Tcid;
303  m_data[5] = Data[0];
304  m_size = 6;
305  }
306  else {
307  esyslog("ERROR: illegal data length for TPDU tag 0x%02X: %d", Tag, Length);
308  }
309  break;
310  case T_DATA_LAST:
311  case T_DATA_MORE:
312  if (Length <= MAX_TPDU_DATA) {
313  uint8_t *p = m_data.data() + 3;
314  p = SetLength(p, Length + 1);
315  *p++ = Tcid;
316  if (Length)
317  memcpy(p, Data, Length);
318  m_size = Length + (p - m_data.data());
319  }
320  else {
321  esyslog("ERROR: illegal data length for TPDU tag 0x%02X: %d", Tag, Length);
322  }
323  break;
324  default:
325  esyslog("ERROR: unknown TPDU tag: 0x%02X", Tag);
326  }
327  }
328 
329 int cTPDU::Write(int fd)
330 {
331  Dump(true);
332  if (m_size)
333  return write(fd, m_data.data(), m_size) == m_size ? OK : ERROR;
334  esyslog("ERROR: attemp to write TPDU with zero size");
335  return ERROR;
336 }
337 
338 int cTPDU::Read(int fd)
339 {
340  m_size = safe_read(fd, m_data.data(), m_data.size());
341  if (m_size < 0) {
342  esyslog("ERROR: %m");
343  m_size = 0;
344  return ERROR;
345  }
346  Dump(false);
347  return OK;
348 }
349 
350 void cTPDU::Dump(bool Outgoing)
351 {
352  if (sDumpTPDUDataTransfer) {
353  static constexpr ssize_t MAX_DUMP { 256 };
354  QString msg = QString("%1 ").arg(Outgoing ? "-->" : "<--");
355  for (int i = 0; i < m_size && i < MAX_DUMP; i++)
356  msg += QString("%1 ").arg((short int)m_data[i], 2, 16, QChar('0'));
357  if (m_size >= MAX_DUMP)
358  msg += "...";
359  LOG(VB_DVBCAM, LOG_INFO, msg);
360  if (!Outgoing) {
361  msg = QString(" ");
362  for (int i = 0; i < m_size && i < MAX_DUMP; i++)
363  msg += QString("%1 ").arg(isprint(m_data[i]) ? m_data[i] : '.', 2);
364  if (m_size >= MAX_DUMP)
365  msg += "...";
366  LOG(VB_DVBCAM, LOG_INFO, msg);
367  }
368  }
369 }
370 
371 const uint8_t *cTPDU::GetData(const uint8_t *Data, int &Length) const
372 {
373  if (m_size) {
374  Data = GetLength(Data, Length);
375  if (Length) {
376  Length--; // the first byte is always the tcid
377  return Data + 1;
378  }
379  }
380  return nullptr;
381 }
382 
383 uint8_t cTPDU::Status(void)
384 {
385  if (m_size >= 4 && m_data[m_size - 4] == T_SB && m_data[m_size - 3] == 2) {
386  //XXX test tcid???
387  return m_data[m_size - 1];
388  }
389  return 0;
390 }
391 
392 // --- cCiTransportConnection ------------------------------------------------
393 
394 enum eState : std::uint8_t { stIDLE, stCREATION, stACTIVE, stDELETION };
395 
397  friend class cCiTransportLayer;
398 private:
399  int m_fd {-1};
400  uint8_t m_slot {0};
401  uint8_t m_tcid {0};
403  cTPDU *m_tpdu {nullptr};
404  std::chrono::milliseconds m_lastPoll {0ms};
406  bool m_dataAvailable {false};
407  void Init(int Fd, uint8_t Slot, uint8_t Tcid);
408  int SendTPDU(uint8_t Tag, int Length = 0, const uint8_t *Data = nullptr) const;
409  int RecvTPDU(void);
410  int CreateConnection(void);
411  int Poll(void);
412  eState State(void) { return m_state; }
413  int LastResponse(void) const { return m_lastResponse; }
414  bool DataAvailable(void) const { return m_dataAvailable; }
415 public:
418  int Slot(void) const { return m_slot; }
419  int SendData(int Length, const uint8_t *Data);
420  int SendData(std::vector<uint8_t> &Data)
421  { return SendData(Data.size(), Data.data()); }
422  int RecvData(void);
423  const uint8_t *Data(int &Length);
424  //XXX Close()
425  };
426 
428 {
429  Init(-1, 0, 0);
430 }
431 
433 {
434  delete m_tpdu;
435 }
436 
437 void cCiTransportConnection::Init(int Fd, uint8_t Slot, uint8_t Tcid)
438 {
439  m_fd = Fd;
440  m_slot = Slot;
441  m_tcid = Tcid;
442  m_state = stIDLE;
443  if (m_fd >= 0 && !m_tpdu)
444  m_tpdu = new cTPDU;
446  m_dataAvailable = false;
447 //XXX Clear()???
448 }
449 
450 int cCiTransportConnection::SendTPDU(uint8_t Tag, int Length, const uint8_t *Data) const
451 {
452  cTPDU TPDU(m_slot, m_tcid, Tag, Length, Data);
453  return TPDU.Write(m_fd);
454 }
455 
456 static constexpr int CAM_READ_TIMEOUT { 5000 }; // ms
457 
459 {
460  std::array<struct pollfd,1> pfd {};
461  pfd[0].fd = m_fd;
462  pfd[0].events = POLLIN;
464 
465  for (;;) {
466  int ret = poll(pfd.data(), 1, CAM_READ_TIMEOUT);
467  if (ret == -1 && (errno == EAGAIN || errno == EINTR))
468  continue;
469  break;
470  }
471 
472  if (
473  (pfd[0].revents & POLLIN) &&
474  m_tpdu->Read(m_fd) == OK &&
475  m_tpdu->Tcid() == m_tcid
476  )
477  {
478  switch (m_state) {
479  case stIDLE: break;
480  case stCREATION: if (m_tpdu->Tag() == T_CTC_REPLY) {
482  m_state = stACTIVE;
484  }
485  break;
486  case stACTIVE: switch (m_tpdu->Tag()) {
487  case T_SB:
488  case T_DATA_LAST:
489  case T_DATA_MORE:
490  case T_REQUEST_TC: break;
491  case T_DELETE_TC: if (SendTPDU(T_DTC_REPLY) != OK)
492  return ERROR;
493  Init(m_fd, m_slot, m_tcid);
494  break;
495  default: return ERROR;
496  }
499  break;
500  case stDELETION: if (m_tpdu->Tag() == T_DTC_REPLY) {
501  Init(m_fd, m_slot, m_tcid);
502  //XXX Status()???
504  }
505  break;
506  }
507  }
508  else {
509  esyslog("ERROR: CAM: Read failed: slot %d, tcid %d\n", m_slot, m_tcid);
510  if (m_tpdu->Tcid() == m_tcid)
511  Init(-1, m_slot, m_tcid);
512  }
513  return m_lastResponse;
514 }
515 
516 int cCiTransportConnection::SendData(int Length, const uint8_t *Data)
517 {
518  while (m_state == stACTIVE && Length > 0) {
519  uint8_t Tag = T_DATA_LAST;
520  int l = Length;
521  if (l > MAX_TPDU_DATA) {
522  Tag = T_DATA_MORE;
523  l = MAX_TPDU_DATA;
524  }
525  if (SendTPDU(Tag, l, Data) != OK || RecvTPDU() != T_SB)
526  break;
527  Length -= l;
528  Data += l;
529  }
530  return Length ? ERROR : OK;
531 }
532 
534 {
535  if (SendTPDU(T_RCV) == OK)
536  return RecvTPDU();
537  return ERROR;
538 }
539 
540 const uint8_t *cCiTransportConnection::Data(int &Length)
541 {
542  return m_tpdu->Data(Length);
543 }
544 
545 static constexpr int8_t MAX_CONNECT_RETRIES { 25 };
546 
548 {
549  if (m_state == stIDLE) {
550  if (SendTPDU(T_CREATE_TC) == OK) {
552  if (RecvTPDU() == T_CTC_REPLY) {
553  sConnected=true;
554  return OK;
555  // the following is a workaround for CAMs that don't quite follow the specs...
556  }
557 
558  for (int i = 0; i < MAX_CONNECT_RETRIES; i++) {
559  dsyslog("CAM: retrying to establish connection");
560  if (RecvTPDU() == T_CTC_REPLY) {
561  dsyslog("CAM: connection established");
562  sConnected=true;
563  return OK;
564  }
565  }
566  return ERROR;
567  }
568  }
569  return ERROR;
570 }
571 
572 // Polls can be done with a 100ms interval (EN50221 - A.4.1.12)
573 static constexpr std::chrono::milliseconds POLL_INTERVAL { 100ms };
574 
576 {
577  if (m_state != stACTIVE)
578  return ERROR;
579 
580  auto curr_time = nowAsDuration<std::chrono::milliseconds>();
581  std::chrono::milliseconds msdiff = curr_time - m_lastPoll;
582 
583  if (msdiff < POLL_INTERVAL)
584  return OK;
585 
586  m_lastPoll = curr_time;
587 
588  if (SendTPDU(T_DATA_LAST) != OK)
589  return ERROR;
590 
591  return RecvTPDU();
592 }
593 
594 // --- cCiTransportLayer -----------------------------------------------------
595 
596 static constexpr size_t MAX_CI_CONNECT { 16 }; // maximum possible value is 254
597 
599 private:
600  int m_fd;
602  std::array<cCiTransportConnection,MAX_CI_CONNECT> m_tc;
603 public:
604  cCiTransportLayer(int Fd, int NumSlots);
606  bool ResetSlot(int Slot) const;
607  bool ModuleReady(int Slot) const;
608  cCiTransportConnection *Process(int Slot);
609  };
610 
612  : m_fd(Fd),
613  m_numSlots(NumSlots)
614 {
615  for (int s = 0; s < m_numSlots; s++)
616  ResetSlot(s);
617 }
618 
620 {
621  for (size_t i = 0; i < MAX_CI_CONNECT; i++) {
622  if (m_tc[i].State() == stIDLE) {
623  dbgprotocol("Creating connection: slot %d, tcid %zd\n", Slot, i + 1);
624  m_tc[i].Init(m_fd, Slot, i + 1);
625  if (m_tc[i].CreateConnection() == OK)
626  return &m_tc[i];
627  break;
628  }
629  }
630  return nullptr;
631 }
632 
633 bool cCiTransportLayer::ResetSlot(int Slot) const
634 {
635  dbgprotocol("Resetting slot %d...", Slot);
636  if (ioctl(m_fd, CA_RESET, 1 << Slot) != -1) {
637  dbgprotocol("ok.\n");
638  return true;
639  }
640  esyslog("ERROR: can't reset CAM slot %d: %m", Slot);
641  dbgprotocol("failed!\n");
642  return false;
643 }
644 
645 bool cCiTransportLayer::ModuleReady(int Slot) const
646 {
647  ca_slot_info_t sinfo;
648  sinfo.num = Slot;
649  if (ioctl(m_fd, CA_GET_SLOT_INFO, &sinfo) != -1)
650  return (sinfo.flags & CA_CI_MODULE_READY) != 0U;
651  esyslog("ERROR: can't get info on CAM slot %d: %m", Slot);
652  return false;
653 }
654 
656 {
657  for (auto & conn : m_tc) {
658  cCiTransportConnection *Tc = &conn;
659  if (Tc->Slot() == Slot) {
660  switch (Tc->State()) {
661  case stCREATION:
662  case stACTIVE:
663  if (!Tc->DataAvailable()) {
664  Tc->Poll();
665  }
666  switch (Tc->LastResponse()) {
667  case T_REQUEST_TC:
668  //XXX
669  break;
670  case T_DATA_MORE:
671  case T_DATA_LAST:
672  case T_CTC_REPLY:
673  case T_SB:
674  if (Tc->DataAvailable())
675  Tc->RecvData();
676  break;
677  case TIMEOUT:
678  case ERROR:
679  default:
680  //XXX Tc->state = stIDLE;//XXX Init()???
681  return nullptr;
682  break;
683  }
684  //XXX this will only work with _one_ transport connection per slot!
685  return Tc;
686  break;
687  default: ;
688  }
689  }
690  }
691  return nullptr;
692 }
693 
694 // -- cCiSession -------------------------------------------------------------
695 
696 // Session Tags:
697 
698 enum SESSION_TAGS : std::uint8_t {
706 };
707 
708 // Session Status:
709 
710 enum SESSION_STATUS : std::uint8_t {
711  SS_OK = 0x00,
713 };
714 
715 // Resource Identifiers:
716 
718  RI_RESOURCE_MANAGER = 0x00010041,
721  RI_HOST_CONTROL = 0x00200041,
722  RI_DATE_TIME = 0x00240041,
723  RI_MMI = 0x00400041,
724 };
725 
726 // Application Object Tags:
727 
729  AOT_NONE = 0x000000,
730  AOT_PROFILE_ENQ = 0x9F8010,
731  AOT_PROFILE = 0x9F8011,
732  AOT_PROFILE_CHANGE = 0x9F8012,
735  AOT_ENTER_MENU = 0x9F8022,
736  AOT_CA_INFO_ENQ = 0x9F8030,
737  AOT_CA_INFO = 0x9F8031,
738  AOT_CA_PMT = 0x9F8032,
739  AOT_CA_PMT_REPLY = 0x9F8033,
740  AOT_TUNE = 0x9F8400,
741  AOT_REPLACE = 0x9F8401,
742  AOT_CLEAR_REPLACE = 0x9F8402,
743  AOT_ASK_RELEASE = 0x9F8403,
744  AOT_DATE_TIME_ENQ = 0x9F8440,
745  AOT_DATE_TIME = 0x9F8441,
746  AOT_CLOSE_MMI = 0x9F8800,
748  AOT_DISPLAY_REPLY = 0x9F8802,
749  AOT_TEXT_LAST = 0x9F8803,
750  AOT_TEXT_MORE = 0x9F8804,
751  AOT_KEYPAD_CONTROL = 0x9F8805,
752  AOT_KEYPRESS = 0x9F8806,
753  AOT_ENQ = 0x9F8807,
754  AOT_ANSW = 0x9F8808,
755  AOT_MENU_LAST = 0x9F8809,
756  AOT_MENU_MORE = 0x9F880A,
757  AOT_MENU_ANSW = 0x9F880B,
758  AOT_LIST_LAST = 0x9F880C,
759  AOT_LIST_MORE = 0x9F880D,
763  AOT_SCENE_END_MARK = 0x9F8811,
764  AOT_SCENE_DONE = 0x9F8812,
765  AOT_SCENE_CONTROL = 0x9F8813,
768  AOT_FLUSH_DOWNLOAD = 0x9F8816,
769  AOT_DOWNLOAD_REPLY = 0x9F8817,
770  AOT_COMMS_CMD = 0x9F8C00,
772  AOT_COMMS_REPLY = 0x9F8C02,
775  AOT_COMMS_RCV_LAST = 0x9F8C05,
776  AOT_COMMS_RCV_MORE = 0x9F8C06,
777 };
778 
779 class cCiSession {
780 private:
784 protected:
785  static int GetTag(int &Length, const uint8_t **Data);
786  static const uint8_t *GetData(const uint8_t *Data, int &Length);
787  int SendData(int Tag, int Length = 0, const uint8_t *Data = nullptr);
788  int SendData(int Tag, std::vector<uint8_t> &Data)
789  { return SendData(Tag, Data.size(), Data.data()); };
790 public:
792  virtual ~cCiSession() = default;
793  const cCiTransportConnection *Tc(void) { return m_tc; }
794  int SessionId(void) const { return m_sessionId; }
795  int ResourceId(void) const { return m_resourceId; }
796  virtual bool HasUserIO(void) { return false; }
797  virtual bool Process(int Length = 0, const uint8_t *Data = nullptr);
798  };
799 
800 cCiSession::cCiSession(int SessionId, int ResourceId, cCiTransportConnection *Tc)
801  : m_sessionId(SessionId),
802  m_resourceId(ResourceId),
803  m_tc(Tc)
804 {
805 }
806 
807 int cCiSession::GetTag(int &Length, const uint8_t **Data)
815 {
816  if (Length >= 3 && Data && *Data) {
817  int t = 0;
818  for (int i = 0; i < 3; i++)
819  t = (t << 8) | *(*Data)++;
820  Length -= 3;
821  return t;
822  }
823  return AOT_NONE;
824 }
825 
826 const uint8_t *cCiSession::GetData(const uint8_t *Data, int &Length)
827 {
828  Data = GetLength(Data, Length);
829  return Length ? Data : nullptr;
830 }
831 
832 int cCiSession::SendData(int Tag, int Length, const uint8_t *Data)
833 {
834  if (Length < 0)
835  {
836  esyslog("ERROR: CAM: data length (%d) is negative", Length);
837  return ERROR;
838  }
839 
840  if ((Length > 0) && !Data)
841  {
842  esyslog("ERROR: CAM: Data pointer null");
843  return ERROR;
844  }
845 
846  std::vector<uint8_t> buffer {
847  ST_SESSION_NUMBER, 0x02,
848  static_cast<uint8_t>((m_sessionId >> 8) & 0xFF),
849  static_cast<uint8_t>((m_sessionId ) & 0xFF),
850  static_cast<uint8_t>((Tag >> 16) & 0xFF),
851  static_cast<uint8_t>((Tag >> 8) & 0xFF),
852  static_cast<uint8_t>((Tag ) & 0xFF)} ;
853  buffer.reserve(2048);
854 
855  SetLength(buffer, Length);
856  if (buffer.size() + Length >= buffer.capacity())
857  {
858  esyslog("ERROR: CAM: data length (%d) exceeds buffer size", Length);
859  return ERROR;
860  }
861 
862  if (Length != 0)
863  {
864  buffer.insert(buffer.end(), Data, Data + Length);
865  }
866  return m_tc->SendData(buffer);
867 }
868 
869 bool cCiSession::Process([[maybe_unused]] int Length,
870  [[maybe_unused]] const uint8_t *Data)
871 {
872  return true;
873 }
874 
875 // -- cCiResourceManager -----------------------------------------------------
876 
878 private:
879  int m_state;
880 public:
882  bool Process(int Length = 0, const uint8_t *Data = nullptr) override; // cCiSession
883  };
884 
886 :cCiSession(SessionId, RI_RESOURCE_MANAGER, Tc)
887 {
888  dbgprotocol("New Resource Manager (session id %d)\n", SessionId);
889  m_state = 0;
890 }
891 
892 bool cCiResourceManager::Process(int Length, const uint8_t *Data)
893 {
894  if (Data) {
895  int Tag = GetTag(Length, &Data);
896  switch (Tag) {
897  case AOT_PROFILE_ENQ: {
898  dbgprotocol("%d: <== Profile Enquiry\n", SessionId());
899  const std::array<const uint32_t,5> resources
900  {
901  htonl(RI_RESOURCE_MANAGER),
904  htonl(RI_DATE_TIME),
905  htonl(RI_MMI)
906  };
907  dbgprotocol("%d: ==> Profile\n", SessionId());
908  SendData(AOT_PROFILE, resources.size() * sizeof(uint32_t),
909  reinterpret_cast<const uint8_t*>(resources.data()));
910  m_state = 3;
911  }
912  break;
913  case AOT_PROFILE: {
914  dbgprotocol("%d: <== Profile\n", SessionId());
915  if (m_state == 1) {
916  int l = 0;
917  const uint8_t *d = GetData(Data, l);
918  if (l > 0 && d)
919  esyslog("CI resource manager: unexpected data");
920  dbgprotocol("%d: ==> Profile Change\n", SessionId());
922  m_state = 2;
923  }
924  else {
925  esyslog("ERROR: CI resource manager: unexpected tag %06X in state %d", Tag, m_state);
926  }
927  }
928  break;
929  default: esyslog("ERROR: CI resource manager: unknown tag %06X", Tag);
930  return false;
931  }
932  }
933  else if (m_state == 0) {
934  dbgprotocol("%d: ==> Profile Enq\n", SessionId());
936  m_state = 1;
937  }
938  return true;
939 }
940 
941 // --- cCiApplicationInformation ---------------------------------------------
942 
944 private:
945  int m_state;
951 public:
953  ~cCiApplicationInformation() override;
954  bool Process(int Length = 0, const uint8_t *Data = nullptr) override; // cCiSession
955  bool EnterMenu(void);
956  char *GetApplicationString() { return strdup(m_menuString); };
959  };
960 
962 :cCiSession(SessionId, RI_APPLICATION_INFORMATION, Tc)
963 {
964  dbgprotocol("New Application Information (session id %d)\n", SessionId);
965  m_state = 0;
966  m_creationTime = time(nullptr);
967  m_applicationType = 0;
969  m_manufacturerCode = 0;
970  m_menuString = nullptr;
971 }
972 
974 {
975  free(m_menuString);
976 }
977 
978 bool cCiApplicationInformation::Process(int Length, const uint8_t *Data)
979 {
980  if (Data) {
981  int Tag = GetTag(Length, &Data);
982  switch (Tag) {
983  case AOT_APPLICATION_INFO: {
984  dbgprotocol("%d: <== Application Info\n", SessionId());
985  int l = 0;
986  const uint8_t *d = GetData(Data, l);
987  l -= 1;
988  if (l < 0) break;
989  m_applicationType = *d++;
990  l -= 2;
991  if (l < 0) break;
992  m_applicationManufacturer = ntohs(*(uint16_t *)d);
993  d += 2;
994  l -= 2;
995  if (l < 0) break;
996  m_manufacturerCode = ntohs(*(uint16_t *)d);
997  d += 2;
998  free(m_menuString);
999  m_menuString = GetString(l, &d);
1000  isyslog("CAM: %s, %02X, %04X, %04X", m_menuString, m_applicationType,
1002  }
1003  m_state = 2;
1004  break;
1005  default: esyslog("ERROR: CI application information: unknown tag %06X", Tag);
1006  return false;
1007  }
1008  }
1009  else if (m_state == 0) {
1010  dbgprotocol("%d: ==> Application Info Enq\n", SessionId());
1012  m_state = 1;
1013  }
1014  return true;
1015 }
1016 
1018 {
1019  if (m_state == 2 && time(nullptr) - m_creationTime > WRKRND_TIME_BEFORE_ENTER_MENU) {
1020  dbgprotocol("%d: ==> Enter Menu\n", SessionId());
1022  return true;//XXX
1023  }
1024  return false;
1025 }
1026 
1027 // --- cCiConditionalAccessSupport -------------------------------------------
1028 
1030 private:
1031  int m_state {0};
1033  bool m_needCaPmt {false};
1034 public:
1036  bool Process(int Length = 0, const uint8_t *Data = nullptr) override; // cCiSession
1038  bool SendPMT(const cCiCaPmt &CaPmt);
1039  bool NeedCaPmt(void) const { return m_needCaPmt; }
1040  };
1041 
1043  int SessionId, cCiTransportConnection *Tc) :
1045 {
1046  dbgprotocol("New Conditional Access Support (session id %d)\n", SessionId);
1047 }
1048 
1049 bool cCiConditionalAccessSupport::Process(int Length, const uint8_t *Data)
1050 {
1051  if (Data) {
1052  int Tag = GetTag(Length, &Data);
1053  switch (Tag) {
1054  case AOT_CA_INFO: {
1055  dbgprotocol("%d: <== Ca Info", SessionId());
1056  int l = 0;
1057  const uint8_t *d = GetData(Data, l);
1058  while (l > 1) {
1059  unsigned short id = ((unsigned short)(*d) << 8) | *(d + 1);
1060  dbgprotocol(" %04X", id);
1061  d += 2;
1062  l -= 2;
1063 
1064  // Make sure the id is not already present
1065  if (std::find(m_caSystemIds.cbegin(), m_caSystemIds.cend(), id)
1066  != m_caSystemIds.end())
1067  continue;
1068 
1069  // Insert before the last element.
1070  m_caSystemIds.emplace_back(id);
1071  }
1072 
1073  dbgprotocol("\n");
1074  }
1075  m_state = 2;
1076  m_needCaPmt = true;
1077  break;
1078  default: esyslog("ERROR: CI conditional access support: unknown tag %06X", Tag);
1079  return false;
1080  }
1081  }
1082  else if (m_state == 0) {
1083  dbgprotocol("%d: ==> Ca Info Enq\n", SessionId());
1085  m_state = 1;
1086  }
1087  return true;
1088 }
1089 
1091 {
1092  if (m_state == 2) {
1093  SendData(AOT_CA_PMT, CaPmt.m_length, CaPmt.m_capmt);
1094  m_needCaPmt = false;
1095  return true;
1096  }
1097  return false;
1098 }
1099 
1100 // --- cCiDateTime -----------------------------------------------------------
1101 
1102 class cCiDateTime : public cCiSession {
1103 private:
1104  int m_interval { 0 };
1105  time_t m_lastTime { 0 };
1106  int m_timeOffset { 0 };
1107  bool SendDateTime(void);
1108 public:
1110  bool Process(int Length = 0, const uint8_t *Data = nullptr) override; // cCiSession
1111  void SetTimeOffset(double offset);
1112  };
1113 
1115 :cCiSession(SessionId, RI_DATE_TIME, Tc)
1116 {
1117  dbgprotocol("New Date Time (session id %d)\n", SessionId);
1118 }
1119 
1120 void cCiDateTime::SetTimeOffset(double offset)
1121 {
1122  m_timeOffset = (int) offset;
1123  dbgprotocol("New Time Offset: %i secs\n", m_timeOffset);
1124 }
1125 
1126 static constexpr uint8_t DEC2BCD(uint8_t d)
1127  { return ((d / 10) << 4) + (d % 10); }
1128 static constexpr uint8_t BYTE0(uint16_t a)
1129  { return static_cast<uint8_t>(a & 0xFF); }
1130 static constexpr uint8_t BYTE1(uint16_t a)
1131  { return static_cast<uint8_t>((a >> 8) & 0xFF); }
1132 
1134 {
1135  time_t t = time(nullptr);
1136  struct tm tm_gmt {};
1137  struct tm tm_loc {};
1138 
1139  // Avoid using signed time_t types
1140  if (m_timeOffset < 0)
1141  t -= (time_t)(-m_timeOffset);
1142  else
1143  t += (time_t)(m_timeOffset);
1144 
1145  if (gmtime_r(&t, &tm_gmt) && localtime_r(&t, &tm_loc)) {
1146  int Y = tm_gmt.tm_year;
1147  int M = tm_gmt.tm_mon + 1;
1148  int D = tm_gmt.tm_mday;
1149  int L = (M == 1 || M == 2) ? 1 : 0;
1150  int MJD = 14956 + D + int((Y - L) * 365.25) + int((M + 1 + L * 12) * 30.6001);
1151  uint16_t mjd = htons(MJD);
1152  int16_t local_offset = htons(tm_loc.tm_gmtoff / 60);
1153  std::vector<uint8_t> T {
1154  BYTE0(mjd),
1155  BYTE1(mjd),
1156  DEC2BCD(tm_gmt.tm_hour),
1157  DEC2BCD(tm_gmt.tm_min),
1158  DEC2BCD(tm_gmt.tm_sec),
1159  BYTE0(local_offset),
1160  BYTE1(local_offset)
1161  };
1162 
1163  dbgprotocol("%d: ==> Date Time\n", SessionId());
1164  SendData(AOT_DATE_TIME, T);
1165  //XXX return value of all SendData() calls???
1166  return true;
1167  }
1168  return false;
1169 }
1170 
1171 bool cCiDateTime::Process(int Length, const uint8_t *Data)
1172 {
1173  if (Data) {
1174  int Tag = GetTag(Length, &Data);
1175  switch (Tag) {
1176  case AOT_DATE_TIME_ENQ: {
1177  m_interval = 0;
1178  int l = 0;
1179  const uint8_t *d = GetData(Data, l);
1180  if (l > 0)
1181  m_interval = *d;
1182  dbgprotocol("%d: <== Date Time Enq, interval = %d\n", SessionId(), m_interval);
1183  m_lastTime = time(nullptr);
1184  return SendDateTime();
1185  }
1186  break;
1187  default: esyslog("ERROR: CI date time: unknown tag %06X", Tag);
1188  return false;
1189  }
1190  }
1191  else if (m_interval && time(nullptr) - m_lastTime > m_interval) {
1192  m_lastTime = time(nullptr);
1193  return SendDateTime();
1194  }
1195  return true;
1196 }
1197 
1198 // --- cCiMMI ----------------------------------------------------------------
1199 
1200 // Close MMI Commands:
1201 
1202 enum CLOSE_MMI : std::uint8_t {
1205 };
1206 
1207 // Display Control Commands:
1208 
1209 enum DISPLAY_CONTROL : std::uint8_t {
1215 };
1216 
1217 // MMI Modes:
1218 
1219 enum MMI_MODES : std::uint8_t {
1223 };
1224 
1225 // Display Reply IDs:
1226 
1227 enum DISPLAY_REPLY_IDS : std::uint8_t {
1236 };
1237 
1238 // Enquiry Flags:
1239 
1240 static constexpr uint8_t EF_BLIND { 0x01 };
1241 
1242 // Answer IDs:
1243 
1244 enum ANSWER_IDS : std::uint8_t {
1245  AI_CANCEL = 0x00,
1246  AI_ANSWER = 0x01,
1247 };
1248 
1249 class cCiMMI : public cCiSession {
1250 private:
1251  char *GetText(int &Length, const uint8_t **Data);
1254 public:
1256  ~cCiMMI() override;
1257  bool Process(int Length = 0, const uint8_t *Data = nullptr) override; // cCiSession
1258  bool HasUserIO(void) override { return m_menu || m_enquiry; } // cCiSession
1259  cCiMenu *Menu(void);
1260  cCiEnquiry *Enquiry(void);
1261  bool SendMenuAnswer(uint8_t Selection);
1262  bool SendAnswer(const char *Text);
1263  };
1264 
1266 :cCiSession(SessionId, RI_MMI, Tc)
1267 {
1268  dbgprotocol("New MMI (session id %d)\n", SessionId);
1269  m_menu = nullptr;
1270  m_enquiry = nullptr;
1271 }
1272 
1274 {
1275  delete m_menu;
1276  delete m_enquiry;
1277 }
1278 
1279 char *cCiMMI::GetText(int &Length, const uint8_t **Data)
1287 {
1288  int Tag = GetTag(Length, Data);
1289  if (Tag == AOT_TEXT_LAST) {
1290  char *s = GetString(Length, Data);
1291  dbgprotocol("%d: <== Text Last '%s'\n", SessionId(), s);
1292  return s;
1293  }
1294  esyslog("CI MMI: unexpected text tag: %06X", Tag);
1295  return nullptr;
1296 }
1297 
1298 bool cCiMMI::Process(int Length, const uint8_t *Data)
1299 {
1300  if (Data) {
1301  int Tag = GetTag(Length, &Data);
1302  switch (Tag) {
1303  case AOT_DISPLAY_CONTROL: {
1304  dbgprotocol("%d: <== Display Control\n", SessionId());
1305  int l = 0;
1306  const uint8_t *d = GetData(Data, l);
1307  if (l > 0) {
1308  switch (*d) {
1309  case DCC_SET_MMI_MODE:
1310  if (l == 2 && *++d == MM_HIGH_LEVEL) {
1311  struct tDisplayReply { uint8_t m_id; uint8_t m_mode; };
1312  tDisplayReply dr {};
1313  dr.m_id = DRI_MMI_MODE_ACK;
1314  dr.m_mode = MM_HIGH_LEVEL;
1315  dbgprotocol("%d: ==> Display Reply\n", SessionId());
1316  SendData(AOT_DISPLAY_REPLY, 2, (uint8_t *)&dr);
1317  }
1318  break;
1319  default: esyslog("CI MMI: unsupported display control command %02X", *d);
1320  return false;
1321  }
1322  }
1323  }
1324  break;
1325  case AOT_LIST_LAST:
1326  case AOT_MENU_LAST: {
1327  dbgprotocol("%d: <== Menu Last\n", SessionId());
1328  delete m_menu;
1329  m_menu = new cCiMenu(this, Tag == AOT_MENU_LAST);
1330  int l = 0;
1331  const uint8_t *d = GetData(Data, l);
1332  if (l > 0) {
1333  // since the specification allows choiceNb to be undefined it is useless, so let's just skip it:
1334  d++;
1335  l--;
1336  if (l > 0) m_menu->m_titleText = GetText(l, &d);
1337  if (l > 0) m_menu->m_subTitleText = GetText(l, &d);
1338  if (l > 0) m_menu->m_bottomText = GetText(l, &d);
1339  while (l > 0) {
1340  char *s = GetText(l, &d);
1341  if (s) {
1342  if (!m_menu->AddEntry(s))
1343  free(s);
1344  }
1345  else {
1346  break;
1347  }
1348  }
1349  }
1350  }
1351  break;
1352  case AOT_ENQ: {
1353  dbgprotocol("%d: <== Enq\n", SessionId());
1354  delete m_enquiry;
1355  m_enquiry = new cCiEnquiry(this);
1356  int l = 0;
1357  const uint8_t *d = GetData(Data, l);
1358  if (l > 0) {
1359  uint8_t blind = *d++;
1360  //XXX GetByte()???
1361  l--;
1362  m_enquiry->m_blind = ((blind & EF_BLIND) != 0);
1364  l--;
1365  // I really wonder why there is no text length field here...
1366  m_enquiry->m_text = CopyString(l, d);
1367  }
1368  }
1369  break;
1370  case AOT_CLOSE_MMI: {
1371  int l = 0;
1372  const uint8_t *d = GetData(Data, l);
1373 
1374  if(l > 0){
1375  switch(*d){
1376  case CLOSE_MMI_IMMEDIATE:
1377  dbgprotocol("%d <== Menu Close: immediate\n", SessionId());
1378  break;
1379  case CLOSE_MMI_DELAY:
1380  dbgprotocol("%d <== Menu Close: delay\n", SessionId());
1381  break;
1382  default: esyslog("ERROR: CI MMI: unknown close_mmi_cmd_id %02X", *d);
1383  return false;
1384  }
1385  }
1386 
1387  break;
1388  }
1389  default: esyslog("ERROR: CI MMI: unknown tag %06X", Tag);
1390  return false;
1391  }
1392  }
1393  return true;
1394 }
1395 
1397 {
1398  cCiMenu *m = m_menu;
1399  m_menu = nullptr;
1400  return m;
1401 }
1402 
1404 {
1405  cCiEnquiry *e = m_enquiry;
1406  m_enquiry = nullptr;
1407  return e;
1408 }
1409 
1410 bool cCiMMI::SendMenuAnswer(uint8_t Selection)
1411 {
1412  dbgprotocol("%d: ==> Menu Answ\n", SessionId());
1413  SendData(AOT_MENU_ANSW, 1, &Selection);
1414  //XXX return value of all SendData() calls???
1415  return true;
1416 }
1417 
1418 // Define protocol structure
1419 extern "C" {
1420  struct tAnswer { uint8_t m_id; char m_text[256]; };
1421 }
1422 
1423 bool cCiMMI::SendAnswer(const char *Text)
1424 {
1425  dbgprotocol("%d: ==> Answ\n", SessionId());
1426  tAnswer answer {};
1427  answer.m_id = Text ? AI_ANSWER : AI_CANCEL;
1428  if (Text) {
1429  strncpy(answer.m_text, Text, sizeof(answer.m_text) - 1);
1430  answer.m_text[255] = '\0';
1431  }
1432  SendData(AOT_ANSW, Text ? strlen(Text) + 1 : 1, (uint8_t *)&answer);
1433  //XXX return value of all SendData() calls???
1434  return true;
1435 }
1436 
1437 // --- cCiMenu ---------------------------------------------------------------
1438 
1439 cCiMenu::cCiMenu(cCiMMI *MMI, bool Selectable)
1440  : m_mmi(MMI),
1441  m_selectable(Selectable)
1442 {
1443 }
1444 
1446 {
1447  free(m_titleText);
1448  free(m_subTitleText);
1449  free(m_bottomText);
1450  for (int i = 0; i < m_numEntries; i++)
1451  free(m_entries[i]);
1452 }
1453 
1454 bool cCiMenu::AddEntry(char *s)
1455 {
1457  m_entries[m_numEntries++] = s;
1458  return true;
1459  }
1460  return false;
1461 }
1462 
1463 bool cCiMenu::Select(int Index)
1464 {
1465  if (m_mmi && -1 <= Index && Index < m_numEntries)
1466  return m_mmi->SendMenuAnswer(Index + 1);
1467  return false;
1468 }
1469 
1471 {
1472  return Select(-1);
1473 }
1474 
1475 // --- cCiEnquiry ------------------------------------------------------------
1476 
1478 {
1479  free(m_text);
1480 }
1481 
1482 bool cCiEnquiry::Reply(const char *s)
1483 {
1484  return m_mmi ? m_mmi->SendAnswer(s) : false;
1485 }
1486 
1488 {
1489  return Reply(nullptr);
1490 }
1491 
1492 // --- cCiCaPmt --------------------------------------------------------------
1493 
1494 // Ca Pmt Cmd Ids:
1495 
1496 enum CPCI_IDS : std::uint8_t {
1498  CPCI_OK_MMI = 0x02,
1499  CPCI_QUERY = 0x03,
1501 };
1502 
1503 cCiCaPmt::cCiCaPmt(int ProgramNumber, uint8_t cplm)
1504  : m_infoLengthPos(m_length)
1505 {
1506  m_capmt[m_length++] = cplm; // ca_pmt_list_management
1507  m_capmt[m_length++] = (ProgramNumber >> 8) & 0xFF;
1508  m_capmt[m_length++] = ProgramNumber & 0xFF;
1509  m_capmt[m_length++] = 0x01; // version_number, current_next_indicator - apparently vn doesn't matter, but cni must be 1
1510 
1511  m_capmt[m_length++] = 0x00;
1512  m_capmt[m_length++] = 0x00;
1513 }
1514 
1516 {
1517  if (m_length + 5 > int(sizeof(m_capmt)))
1518  {
1519  esyslog("ERROR: buffer overflow in CA_PMT");
1520  return;
1521  }
1522 
1523  m_capmt[m_length++] = type & 0xFF;
1524  m_capmt[m_length++] = (pid >> 8) & 0xFF;
1525  m_capmt[m_length++] = pid & 0xFF;
1526 
1527  // ES_info_length
1529  m_capmt[m_length++] = 0x00;
1530  m_capmt[m_length++] = 0x00;
1531 }
1532 
1550 void cCiCaPmt::AddCaDescriptor(int ca_system_id, int ca_pid, int data_len,
1551  const uint8_t *data)
1552 {
1553  if (!m_infoLengthPos)
1554  {
1555  esyslog("ERROR: adding CA descriptor without program/stream!");
1556  return;
1557  }
1558 
1559  if (m_length + data_len + 7 > int(sizeof(m_capmt)))
1560  {
1561  esyslog("ERROR: buffer overflow in CA_PMT");
1562  return;
1563  }
1564 
1565  // We are either at start of program descriptors or stream descriptors.
1566  if (m_infoLengthPos + 2 == m_length)
1567  m_capmt[m_length++] = CPCI_OK_DESCRAMBLING; // ca_pmt_cmd_id
1568 
1569  m_capmt[m_length++] = 0x09; // CA descriptor tag
1570  m_capmt[m_length++] = 4 + data_len; // descriptor length
1571 
1572  m_capmt[m_length++] = (ca_system_id >> 8) & 0xFF;
1573  m_capmt[m_length++] = ca_system_id & 0xFF;
1574  m_capmt[m_length++] = (ca_pid >> 8) & 0xFF;
1575  m_capmt[m_length++] = ca_pid & 0xFF;
1576 
1577  if (data_len > 0)
1578  {
1579  memcpy(&m_capmt[m_length], data, data_len);
1580  m_length += data_len;
1581  }
1582 
1583  // update program_info_length/ES_info_length
1584  int l = m_length - m_infoLengthPos - 2;
1585  m_capmt[m_infoLengthPos] = (l >> 8) & 0xFF;
1586  m_capmt[m_infoLengthPos + 1] = l & 0xFF;
1587 }
1588 
1589 // -- cLlCiHandler -------------------------------------------------------------
1590 
1591 cLlCiHandler::cLlCiHandler(int Fd, int NumSlots)
1592  : m_fdCa(Fd),
1593  m_numSlots(NumSlots),
1594  m_tpl(new cCiTransportLayer(Fd, m_numSlots))
1595 {
1596 }
1597 
1599 {
1600  cMutexLock MutexLock(&m_mutex);
1601  for (auto & session : m_sessions)
1602  delete session;
1603  delete m_tpl;
1604  close(m_fdCa);
1605 }
1606 
1608 {
1609  int fd_ca = open(FileName, O_RDWR);
1610  if (fd_ca >= 0)
1611  {
1612  ca_caps_t Caps;
1613  if (ioctl(fd_ca, CA_GET_CAP, &Caps) == 0)
1614  {
1615  int NumSlots = Caps.slot_num;
1616  if (NumSlots > 0)
1617  {
1618  if (Caps.slot_type & CA_CI_LINK)
1619  return new cLlCiHandler(fd_ca, NumSlots);
1620  if (Caps.slot_type & CA_CI)
1621  return new cHlCiHandler(fd_ca, NumSlots);
1622  isyslog("CAM doesn't support either high or low level CI,"
1623  " Caps.slot_type=%i", Caps.slot_type);
1624  }
1625  else
1626  {
1627  esyslog("ERROR: no CAM slots found");
1628  }
1629  }
1630  else
1631  {
1632  LOG_ERROR_STR(FileName);
1633  }
1634  close(fd_ca);
1635  }
1636  return nullptr;
1637 }
1638 
1639 int cLlCiHandler::ResourceIdToInt(const uint8_t *Data)
1640 {
1641  return (ntohl(*(int *)Data));
1642 }
1643 
1644 bool cLlCiHandler::Send(uint8_t Tag, int SessionId, int ResourceId, int Status)
1645 {
1646  std::vector<uint8_t> buffer {Tag, 0x00} ; // 0x00 will be replaced with length
1647  if (Status >= 0)
1648  buffer.push_back(Status);
1649  if (ResourceId) {
1650  buffer.push_back((ResourceId >> 24) & 0xFF);
1651  buffer.push_back((ResourceId >> 16) & 0xFF);
1652  buffer.push_back((ResourceId >> 8) & 0xFF);
1653  buffer.push_back( ResourceId & 0xFF);
1654  }
1655  buffer.push_back((SessionId >> 8) & 0xFF);
1656  buffer.push_back( SessionId & 0xFF);
1657  buffer[1] = buffer.size() - 2; // length
1658  return m_tc && m_tc->SendData(buffer) == OK;
1659 }
1660 
1662 {
1663  for (auto & session : m_sessions) {
1664  if (session && session->SessionId() == SessionId)
1665  return session;
1666  }
1667  return nullptr;
1668 }
1669 
1671 {
1672  for (auto & session : m_sessions) {
1673  if (session && session->Tc()->Slot() == Slot && session->ResourceId() == ResourceId)
1674  return session;
1675  }
1676  return nullptr;
1677 }
1678 
1680 {
1681  if (!GetSessionByResourceId(ResourceId, m_tc->Slot())) {
1682  for (int i = 0; i < MAX_CI_SESSION; i++) {
1683  if (!m_sessions[i]) {
1684  switch (ResourceId) {
1685  case RI_RESOURCE_MANAGER: return m_sessions[i] = new cCiResourceManager(i + 1, m_tc);
1688  return m_sessions[i] = new cCiConditionalAccessSupport(i + 1, m_tc);
1689  case RI_HOST_CONTROL: break; //XXX
1690  case RI_DATE_TIME: return m_sessions[i] = new cCiDateTime(i + 1, m_tc);
1691  case RI_MMI: return m_sessions[i] = new cCiMMI(i + 1, m_tc);
1692  }
1693  }
1694  }
1695  }
1696  return nullptr;
1697 }
1698 
1699 bool cLlCiHandler::OpenSession(int Length, const uint8_t *Data)
1700 {
1701  if (Length == 6 && *(Data + 1) == 0x04) {
1702  int ResourceId = ResourceIdToInt(Data + 2);
1703  dbgprotocol("OpenSession %08X\n", ResourceId);
1704  switch (ResourceId) {
1705  case RI_RESOURCE_MANAGER:
1708  case RI_HOST_CONTROL:
1709  case RI_DATE_TIME:
1710  case RI_MMI:
1711  {
1712  cCiSession *Session = CreateSession(ResourceId);
1713  if (Session)
1714  {
1716  Session->ResourceId(), SS_OK);
1717  return true;
1718  }
1719  esyslog("ERROR: can't create session for resource identifier: %08X",
1720  ResourceId);
1721  break;
1722  }
1723  default: esyslog("ERROR: unknown resource identifier: %08X", ResourceId);
1724  }
1725  }
1726  return false;
1727 }
1728 
1729 bool cLlCiHandler::CloseSession(int SessionId)
1730 {
1731  dbgprotocol("CloseSession %08X\n", SessionId);
1732  cCiSession *Session = GetSessionBySessionId(SessionId);
1733  if (Session && m_sessions[SessionId - 1] == Session) {
1734  delete Session;
1735  m_sessions[SessionId - 1] = nullptr;
1736  Send(ST_CLOSE_SESSION_RESPONSE, SessionId, 0, SS_OK);
1737  return true;
1738  }
1739 
1740  esyslog("ERROR: unknown session id: %d", SessionId);
1742  return false;
1743 }
1744 
1746 {
1747  int result = 0;
1748  for (auto & session : m_sessions) {
1749  if (session && session->Tc()->Slot() == Slot) {
1750  CloseSession(session->SessionId());
1751  result++;
1752  }
1753  }
1754  return result;
1755 }
1756 
1758 {
1759  bool result = true;
1760  cMutexLock MutexLock(&m_mutex);
1761 
1762  for (int Slot = 0; Slot < m_numSlots; Slot++)
1763  {
1764  m_tc = m_tpl->Process(Slot);
1765  if (m_tc)
1766  {
1767  int Length = 0;
1768  const uint8_t *Data = m_tc->Data(Length);
1769  if (Data && Length > 1)
1770  {
1771  switch (*Data)
1772  {
1773  case ST_SESSION_NUMBER:
1774  if (Length > 4)
1775  {
1776  int SessionId = ntohs(*(short *)&Data[2]);
1777  cCiSession *Session = GetSessionBySessionId(SessionId);
1778  if (Session)
1779  {
1780  Session->Process(Length - 4, Data + 4);
1781  if (Session->ResourceId() == RI_APPLICATION_INFORMATION)
1782  {
1783 #if 0
1784  esyslog("Test: %x",
1785  ((cCiApplicationInformation*)Session)->GetApplicationManufacturer());
1786 #endif
1787  }
1788  }
1789  else
1790  {
1791  esyslog("ERROR: unknown session id: %d", SessionId);
1792  }
1793  }
1794  break;
1795 
1797  OpenSession(Length, Data);
1798  break;
1799 
1801  if (Length == 4)
1802  CloseSession(ntohs(*(short *)&Data[2]));
1803  break;
1804 
1805  case ST_CREATE_SESSION_RESPONSE: //XXX fall through to default
1806  case ST_CLOSE_SESSION_RESPONSE: //XXX fall through to default
1807  default:
1808  esyslog("ERROR: unknown session tag: %02X", *Data);
1809  }
1810  }
1811  }
1812  else if (CloseAllSessions(Slot))
1813  {
1814  m_tpl->ResetSlot(Slot);
1815  result = false;
1816  }
1817  else if (m_tpl->ModuleReady(Slot))
1818  {
1819  dbgprotocol("Module ready in slot %d\n", Slot);
1820  m_tpl->NewConnection(Slot);
1821  }
1822  }
1823 
1824  bool UserIO = false;
1825  m_needCaPmt = false;
1826  for (auto & session : m_sessions)
1827  {
1828  if (session && session->Process())
1829  {
1830  UserIO |= session->HasUserIO();
1831  if (session->ResourceId() == RI_CONDITIONAL_ACCESS_SUPPORT)
1832  {
1833  auto *cas = dynamic_cast<cCiConditionalAccessSupport *>(session);
1834  if (cas == nullptr)
1835  continue;
1836  m_needCaPmt |= cas->NeedCaPmt();
1837  }
1838  }
1839  }
1840  m_hasUserIO = UserIO;
1841 
1842  if (m_newCaSupport)
1843  m_newCaSupport = result = false; // triggers new SetCaPmt at caller!
1844  return result;
1845 }
1846 
1848 {
1849  cMutexLock MutexLock(&m_mutex);
1851  return api ? api->EnterMenu() : false;
1852 }
1853 
1855 {
1856  cMutexLock MutexLock(&m_mutex);
1857  for (int Slot = 0; Slot < m_numSlots; Slot++) {
1858  auto *mmi = dynamic_cast<cCiMMI *>(GetSessionByResourceId(RI_MMI, Slot));
1859  if (mmi)
1860  return mmi->Menu();
1861  }
1862  return nullptr;
1863 }
1864 
1866 {
1867  cMutexLock MutexLock(&m_mutex);
1868  for (int Slot = 0; Slot < m_numSlots; Slot++) {
1869  auto *mmi = dynamic_cast<cCiMMI *>(GetSessionByResourceId(RI_MMI, Slot));
1870  if (mmi)
1871  return mmi->Enquiry();
1872  }
1873  return nullptr;
1874 }
1875 
1877  {
1878  static dvbca_vector empty {};
1879  cMutexLock MutexLock(&m_mutex);
1881  return cas ? cas->GetCaSystemIds() : empty;
1882 }
1883 
1884 bool cLlCiHandler::SetCaPmt(cCiCaPmt &CaPmt, int Slot)
1885 {
1886  cMutexLock MutexLock(&m_mutex);
1888  return cas && cas->SendPMT(CaPmt);
1889 }
1890 
1891 void cLlCiHandler::SetTimeOffset(double offset_in_seconds)
1892 {
1893  cMutexLock MutexLock(&m_mutex);
1894  cCiDateTime *dt = nullptr;
1895 
1896  for (uint i = 0; i < (uint) NumSlots(); i++)
1897  {
1898  dt = dynamic_cast<cCiDateTime*>(GetSessionByResourceId(RI_DATE_TIME, i));
1899  if (dt)
1900  dt->SetTimeOffset(offset_in_seconds);
1901  }
1902 }
1903 
1904 bool cLlCiHandler::Reset(int Slot)
1905 {
1906  cMutexLock MutexLock(&m_mutex);
1907  CloseAllSessions(Slot);
1908  return m_tpl->ResetSlot(Slot);
1909 }
1910 
1912 {
1913  return sConnected;
1914 }
1915 
1916 // -- cHlCiHandler -------------------------------------------------------------
1917 
1918 cHlCiHandler::cHlCiHandler(int Fd, int NumSlots)
1919  : m_fdCa(Fd),
1920  m_numSlots(NumSlots)
1921 {
1922  esyslog("New High level CI handler");
1923 }
1924 
1926 {
1927  cMutexLock MutexLock(&m_mutex);
1928  close(m_fdCa);
1929 }
1930 
1931 int cHlCiHandler::CommHL(unsigned tag, unsigned function, struct ca_msg *msg) const
1932 {
1933  if (tag) {
1934  msg->msg[2] = tag & 0xff;
1935  msg->msg[1] = (tag & 0xff00) >> 8;
1936  msg->msg[0] = (tag & 0xff0000) >> 16;
1937  esyslog("Sending message=[%02x %02x %02x ]",
1938  msg->msg[0], msg->msg[1], msg->msg[2]);
1939  }
1940 
1941  return ioctl(m_fdCa, function, msg);
1942 }
1943 
1944 int cHlCiHandler::GetData(unsigned tag, struct ca_msg *msg)
1945 {
1946  return CommHL(tag, CA_GET_MSG, msg);
1947 }
1948 
1949 int cHlCiHandler::SendData(unsigned tag, struct ca_msg *msg)
1950 {
1951  return CommHL(tag, CA_SEND_MSG, msg);
1952 }
1953 
1955 {
1956  cMutexLock MutexLock(&m_mutex);
1957 
1958  struct ca_msg msg {};
1959  switch(m_state) {
1960  case 0:
1961  // Get CA_system_ids
1962  /* Enquire */
1963  if ((SendData(AOT_CA_INFO_ENQ, &msg)) < 0) {
1964  esyslog("HLCI communication failed");
1965  } else {
1966  dbgprotocol("==> Ca Info Enquiry");
1967  /* Receive */
1968  if ((GetData(AOT_CA_INFO, &msg)) < 0) {
1969  esyslog("HLCI communication failed");
1970  } else {
1971  QString message("Debug: ");
1972  for(int i = 0; i < 20; i++) {
1973  message += QString("%1 ").arg(msg.msg[i]);
1974  }
1975  LOG(VB_GENERAL, LOG_DEBUG, message);
1976  dbgprotocol("<== Ca Info");
1977  int l = msg.msg[3];
1978  const uint8_t *d = &msg.msg[4];
1979  while (l > 1) {
1980  unsigned short id = ((unsigned short)(*d) << 8) | *(d + 1);
1981  dbgprotocol(" %04X", id);
1982  d += 2;
1983  l -= 2;
1984 
1985  // Insert before the last element.
1986  m_caSystemIds.emplace_back(id);
1987  }
1988  dbgprotocol("\n");
1989  }
1990  m_state = 1;
1991  break;
1992  }
1993  }
1994 
1995  bool result = true;
1996 
1997  return result;
1998 }
1999 
2000 bool cHlCiHandler::EnterMenu(int /*Slot*/)
2001 {
2002  return false;
2003 }
2004 
2006 {
2007  return nullptr;
2008 }
2009 
2011 {
2012  return nullptr;
2013 }
2014 
2016 {
2017  return m_caSystemIds;
2018 }
2019 
2020 bool cHlCiHandler::SetCaPmt(cCiCaPmt &CaPmt, int /*Slot*/)
2021 {
2022  cMutexLock MutexLock(&m_mutex);
2023  struct ca_msg msg {};
2024 
2025  esyslog("Setting CA PMT.");
2026  m_state = 2;
2027 
2028  msg.msg[3] = CaPmt.m_length;
2029 
2030  if (CaPmt.m_length > (256 - 4))
2031  {
2032  esyslog("CA message too long");
2033  return false;
2034  }
2035 
2036  memcpy(&msg.msg[4], CaPmt.m_capmt, CaPmt.m_length);
2037 
2038  if ((SendData(AOT_CA_PMT, &msg)) < 0) {
2039  esyslog("HLCI communication failed");
2040  return false;
2041  }
2042 
2043  return true;
2044 }
2045 
2046 bool cHlCiHandler::Reset(int /*Slot*/) const
2047 {
2048  if ((ioctl(m_fdCa, CA_RESET)) < 0) {
2049  esyslog("ioctl CA_RESET failed.");
2050  return false;
2051  }
2052  return true;
2053 }
2054 
2056 {
2057  return m_state == 1;
2058 }
stCREATION
@ stCREATION
Definition: dvbci.cpp:394
cCiDateTime::m_lastTime
time_t m_lastTime
Definition: dvbci.cpp:1105
cCiConditionalAccessSupport::m_state
int m_state
Definition: dvbci.cpp:1031
cCiConditionalAccessSupport
Definition: dvbci.cpp:1029
cCiApplicationInformation::~cCiApplicationInformation
~cCiApplicationInformation() override
Definition: dvbci.cpp:973
cCiApplicationInformation::GetManufacturerCode
uint16_t GetManufacturerCode() const
Definition: dvbci.cpp:958
cLlCiHandler::SetTimeOffset
void SetTimeOffset(double offset_in_seconds) override
Definition: dvbci.cpp:1891
dvbci.h
AOT_DISPLAY_CONTROL
@ AOT_DISPLAY_CONTROL
Definition: dvbci.cpp:747
cTPDU::cTPDU
cTPDU(void)=default
cLlCiHandler::connected
static bool connected()
Definition: dvbci.cpp:1911
cCiTransportConnection::RecvTPDU
int RecvTPDU(void)
Definition: dvbci.cpp:458
stDELETION
@ stDELETION
Definition: dvbci.cpp:394
RI_CONDITIONAL_ACCESS_SUPPORT
@ RI_CONDITIONAL_ACCESS_SUPPORT
Definition: dvbci.cpp:720
DISPLAY_CONTROL
DISPLAY_CONTROL
Definition: dvbci.cpp:1209
MMI_MODES
MMI_MODES
Definition: dvbci.cpp:1219
cCiTransportConnection::DataAvailable
bool DataAvailable(void) const
Definition: dvbci.cpp:414
cCiCaPmt::AddCaDescriptor
void AddCaDescriptor(int ca_system_id, int ca_pid, int data_len, const uint8_t *data)
Definition: dvbci.cpp:1550
DISPLAY_REPLY_IDS
DISPLAY_REPLY_IDS
Definition: dvbci.cpp:1227
DATA_INDICATOR
static constexpr uint8_t DATA_INDICATOR
Definition: dvbci.cpp:248
tAnswer::m_text
char m_text[256]
Definition: dvbci.cpp:1420
AOT_CONNECTION_DESCRIPTOR
@ AOT_CONNECTION_DESCRIPTOR
Definition: dvbci.cpp:771
AOT_SCENE_END_MARK
@ AOT_SCENE_END_MARK
Definition: dvbci.cpp:763
ST_CREATE_SESSION
@ ST_CREATE_SESSION
Definition: dvbci.cpp:702
cLlCiHandler::GetSessionBySessionId
cCiSession * GetSessionBySessionId(int SessionId)
Definition: dvbci.cpp:1661
cCiTransportConnection::~cCiTransportConnection
~cCiTransportConnection()
Definition: dvbci.cpp:432
cCiTransportConnection::m_lastResponse
int m_lastResponse
Definition: dvbci.cpp:405
cTPDU
Definition: dvbci.cpp:264
CPCI_OK_MMI
@ CPCI_OK_MMI
Definition: dvbci.cpp:1498
cLlCiHandler::CloseAllSessions
int CloseAllSessions(int Slot)
Definition: dvbci.cpp:1745
cCiSession::GetTag
static int GetTag(int &Length, const uint8_t **Data)
Definition: dvbci.cpp:807
AOT_DISPLAY_MESSAGE
@ AOT_DISPLAY_MESSAGE
Definition: dvbci.cpp:762
T_NEW_TC
@ T_NEW_TC
Definition: dvbci.cpp:258
cCiConditionalAccessSupport::m_needCaPmt
bool m_needCaPmt
Definition: dvbci.cpp:1033
dvbca_vector
std::vector< uint16_t > dvbca_vector
Definition: dvbci.h:44
AOT_CA_PMT_REPLY
@ AOT_CA_PMT_REPLY
Definition: dvbci.cpp:739
cCiApplicationInformation::cCiApplicationInformation
cCiApplicationInformation(int SessionId, cCiTransportConnection *Tc)
Definition: dvbci.cpp:961
T_CTC_REPLY
@ T_CTC_REPLY
Definition: dvbci.cpp:254
AOT_TEXT_MORE
@ AOT_TEXT_MORE
Definition: dvbci.cpp:750
cCiTransportConnection::m_slot
uint8_t m_slot
Definition: dvbci.cpp:400
T_DELETE_TC
@ T_DELETE_TC
Definition: dvbci.cpp:255
cCiConditionalAccessSupport::m_caSystemIds
dvbca_vector m_caSystemIds
Definition: dvbci.cpp:1032
AOT_APPLICATION_INFO
@ AOT_APPLICATION_INFO
Definition: dvbci.cpp:734
AOT_APPLICATION_INFO_ENQ
@ AOT_APPLICATION_INFO_ENQ
Definition: dvbci.cpp:733
DCC_FULL_SCREEN_GRAPHICS_CHARACTERISTICS
@ DCC_FULL_SCREEN_GRAPHICS_CHARACTERISTICS
Definition: dvbci.cpp:1214
cHlCiHandler::cHlCiHandler
cHlCiHandler(int Fd, int NumSlots)
Definition: dvbci.cpp:1918
cCiMMI
Definition: dvbci.cpp:1249
discid.disc.read
def read(device=None, features=[])
Definition: disc.py:35
cMutex::m_mutex
pthread_mutex_t m_mutex
Definition: dvbci.h:49
cHlCiHandler::SetCaPmt
bool SetCaPmt(cCiCaPmt &CaPmt)
RI_DATE_TIME
@ RI_DATE_TIME
Definition: dvbci.cpp:722
AOT_CA_INFO
@ AOT_CA_INFO
Definition: dvbci.cpp:737
GetString
static char * GetString(int &Length, const uint8_t **Data)
Definition: dvbci.cpp:178
cCiTransportLayer::m_numSlots
int m_numSlots
Definition: dvbci.cpp:601
AOT_SUBTITLE_DOWNLOAD_MORE
@ AOT_SUBTITLE_DOWNLOAD_MORE
Definition: dvbci.cpp:767
AOT_SUBTITLE_SEGMENT_MORE
@ AOT_SUBTITLE_SEGMENT_MORE
Definition: dvbci.cpp:761
cLlCiHandler::NumSlots
int NumSlots(void) override
Definition: dvbci.h:184
DCC_SET_MMI_MODE
@ DCC_SET_MMI_MODE
Definition: dvbci.cpp:1210
cCiTransportConnection::SendData
int SendData(int Length, const uint8_t *Data)
Definition: dvbci.cpp:516
cHlCiHandler::GetData
int GetData(unsigned tag, struct ca_msg *msg)
Definition: dvbci.cpp:1944
AOT_ENTER_MENU
@ AOT_ENTER_MENU
Definition: dvbci.cpp:735
cCiMenu::cCiMenu
cCiMenu(cCiMMI *MMI, bool Selectable)
Definition: dvbci.cpp:1439
mythburn.write
def write(text, progress=True)
Definition: mythburn.py:308
cCiCaPmt::m_length
int m_length
Definition: dvbci.h:127
cCiEnquiry::Cancel
bool Cancel(void)
Definition: dvbci.cpp:1487
cTPDU::Write
int Write(int fd)
Definition: dvbci.cpp:329
DRI_MMI_MODE_ACK
@ DRI_MMI_MODE_ACK
Definition: dvbci.cpp:1228
cCiTransportConnection::Init
void Init(int Fd, uint8_t Slot, uint8_t Tcid)
Definition: dvbci.cpp:437
LOG_ERROR_STR
#define LOG_ERROR_STR(s)
Definition: dvbci.cpp:57
cTPDU::m_data
std::array< uint8_t, MAX_TPDU_SIZE > m_data
Definition: dvbci.cpp:267
AOT_CA_PMT
@ AOT_CA_PMT
Definition: dvbci.cpp:738
AOT_MENU_LAST
@ AOT_MENU_LAST
Definition: dvbci.cpp:755
AOT_COMMS_RCV_MORE
@ AOT_COMMS_RCV_MORE
Definition: dvbci.cpp:776
CLOSE_MMI_DELAY
@ CLOSE_MMI_DELAY
Definition: dvbci.cpp:1204
cLlCiHandler::m_tc
cCiTransportConnection * m_tc
Definition: dvbci.h:170
AOT_DISPLAY_REPLY
@ AOT_DISPLAY_REPLY
Definition: dvbci.cpp:748
cLlCiHandler::GetEnquiry
cCiEnquiry * GetEnquiry(void) override
Definition: dvbci.cpp:1865
CPCI_NOT_SELECTED
@ CPCI_NOT_SELECTED
Definition: dvbci.cpp:1500
cCiCaPmt
Definition: dvbci.h:123
AOT_DATE_TIME_ENQ
@ AOT_DATE_TIME_ENQ
Definition: dvbci.cpp:744
TIMEOUT
static constexpr int TIMEOUT
Definition: dvbci.cpp:70
cHlCiHandler::SendData
int SendData(unsigned tag, struct ca_msg *msg)
Definition: dvbci.cpp:1949
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
cLlCiHandler::Process
bool Process(void) override
Definition: dvbci.cpp:1757
cMutexLock::~cMutexLock
~cMutexLock()
Definition: dvbci.cpp:224
AOT_REPLACE
@ AOT_REPLACE
Definition: dvbci.cpp:741
sDebugProtocol
static bool sDebugProtocol
Definition: dvbci.cpp:63
AOT_DOWNLOAD_REPLY
@ AOT_DOWNLOAD_REPLY
Definition: dvbci.cpp:769
cCiMenu::m_mmi
cCiMMI * m_mmi
Definition: dvbci.h:76
DRI_LIST_INPUT_CHARACTER_TABLES
@ DRI_LIST_INPUT_CHARACTER_TABLES
Definition: dvbci.cpp:1230
ST_OPEN_SESSION_RESPONSE
@ ST_OPEN_SESSION_RESPONSE
Definition: dvbci.cpp:701
cCiTransportConnection::m_lastPoll
std::chrono::milliseconds m_lastPoll
Definition: dvbci.cpp:404
AOT_COMMS_SEND_MORE
@ AOT_COMMS_SEND_MORE
Definition: dvbci.cpp:774
cCiTransportLayer::m_tc
std::array< cCiTransportConnection, MAX_CI_CONNECT > m_tc
Definition: dvbci.cpp:602
AOT_ANSW
@ AOT_ANSW
Definition: dvbci.cpp:754
cCiEnquiry::Reply
bool Reply(const char *s)
Definition: dvbci.cpp:1482
SS_OK
@ SS_OK
Definition: dvbci.cpp:711
DRI_LIST_DISPLAY_CHARACTER_TABLES
@ DRI_LIST_DISPLAY_CHARACTER_TABLES
Definition: dvbci.cpp:1229
cMutexLock
Definition: dvbci.h:59
cCiTransportLayer::Process
cCiTransportConnection * Process(int Slot)
Definition: dvbci.cpp:655
cHlCiHandler::~cHlCiHandler
~cHlCiHandler() override
Definition: dvbci.cpp:1925
cCiMMI::cCiMMI
cCiMMI(int SessionId, cCiTransportConnection *Tc)
Definition: dvbci.cpp:1265
cCiApplicationInformation::m_applicationManufacturer
uint16_t m_applicationManufacturer
Definition: dvbci.cpp:948
cLlCiHandler::m_mutex
cMutex m_mutex
Definition: dvbci.h:162
cCiTransportConnection::m_tcid
uint8_t m_tcid
Definition: dvbci.cpp:401
cCiDateTime::m_timeOffset
int m_timeOffset
Definition: dvbci.cpp:1106
cCiCaPmt::m_capmt
uint8_t m_capmt[2048]
XXX is there a specified maximum?
Definition: dvbci.h:129
EF_BLIND
static constexpr uint8_t EF_BLIND
Definition: dvbci.cpp:1240
cCiResourceManager::Process
bool Process(int Length=0, const uint8_t *Data=nullptr) override
Definition: dvbci.cpp:892
RI_RESOURCE_MANAGER
@ RI_RESOURCE_MANAGER
Definition: dvbci.cpp:718
cHlCiHandler::Process
bool Process(void) override
Definition: dvbci.cpp:1954
CPCI_OK_DESCRAMBLING
@ CPCI_OK_DESCRAMBLING
Definition: dvbci.cpp:1497
close
#define close
Definition: compat.h:43
AOT_DATE_TIME
@ AOT_DATE_TIME
Definition: dvbci.cpp:745
DCC_OVERLAY_GRAPHICS_CHARACTERISTICS
@ DCC_OVERLAY_GRAPHICS_CHARACTERISTICS
Definition: dvbci.cpp:1213
State
State
Definition: zmserver.h:68
AI_ANSWER
@ AI_ANSWER
Definition: dvbci.cpp:1246
cLlCiHandler::m_numSlots
int m_numSlots
Definition: dvbci.h:164
cLlCiHandler::~cLlCiHandler
~cLlCiHandler() override
Definition: dvbci.cpp:1598
AOT_CLEAR_REPLACE
@ AOT_CLEAR_REPLACE
Definition: dvbci.cpp:742
DRI_UNKNOWN_DISPLAY_CONTROL_CMD
@ DRI_UNKNOWN_DISPLAY_CONTROL_CMD
Definition: dvbci.cpp:1233
AOT_SCENE_DONE
@ AOT_SCENE_DONE
Definition: dvbci.cpp:764
AOT_CA_INFO_ENQ
@ AOT_CA_INFO_ENQ
Definition: dvbci.cpp:736
cCiMenu::m_subTitleText
char * m_subTitleText
Definition: dvbci.h:79
AOT_KEYPAD_CONTROL
@ AOT_KEYPAD_CONTROL
Definition: dvbci.cpp:751
cLlCiHandler::m_sessions
cCiSession * m_sessions[MAX_CI_SESSION]
Definition: dvbci.h:168
SESSION_TAGS
SESSION_TAGS
Definition: dvbci.cpp:698
MM_LOW_LEVEL_FULL_SCREEN_GRAPHICS
@ MM_LOW_LEVEL_FULL_SCREEN_GRAPHICS
Definition: dvbci.cpp:1222
cHlCiHandler::m_state
int m_state
Definition: dvbci.h:208
T_CREATE_TC
@ T_CREATE_TC
Definition: dvbci.cpp:253
T_RCV
@ T_RCV
Definition: dvbci.cpp:252
cMutex
Definition: dvbci.h:46
cHlCiHandler::EnterMenu
bool EnterMenu(int Slot) override
Definition: dvbci.cpp:2000
cCiApplicationInformation::m_menuString
char * m_menuString
Definition: dvbci.cpp:950
cMutex::m_locked
int m_locked
Definition: dvbci.h:51
cCiTransportConnection
Definition: dvbci.cpp:396
AOT_COMMS_CMD
@ AOT_COMMS_CMD
Definition: dvbci.cpp:770
cTPDU::Dump
void Dump(bool Outgoing)
Definition: dvbci.cpp:350
AOT_PROFILE_ENQ
@ AOT_PROFILE_ENQ
Definition: dvbci.cpp:730
safe_read
static ssize_t safe_read(int filedes, void *buffer, size_t size)
Definition: dvbci.cpp:83
cCiTransportLayer::ModuleReady
bool ModuleReady(int Slot) const
Definition: dvbci.cpp:645
AOT_FLUSH_DOWNLOAD
@ AOT_FLUSH_DOWNLOAD
Definition: dvbci.cpp:768
mythlogging.h
SetLength
static uint8_t * SetLength(uint8_t *Data, int Length)
Definition: dvbci.cpp:117
cCiSession::~cCiSession
virtual ~cCiSession()=default
cMutexLock::m_locked
bool m_locked
Definition: dvbci.h:62
cCiMMI::SendAnswer
bool SendAnswer(const char *Text)
Definition: dvbci.cpp:1423
AOT_CLOSE_MMI
@ AOT_CLOSE_MMI
Definition: dvbci.cpp:746
cCiEnquiry::m_blind
bool m_blind
Definition: dvbci.h:102
cCiHandler::NumSlots
virtual int NumSlots(void)=0
MAX_TPDU_DATA
static constexpr int MAX_TPDU_DATA
Definition: dvbci.cpp:246
cLlCiHandler::SetCaPmt
bool SetCaPmt(cCiCaPmt &CaPmt)
T_DTC_REPLY
@ T_DTC_REPLY
Definition: dvbci.cpp:256
hardwareprofile.config.p
p
Definition: config.py:33
hardwareprofile.i18n.t
t
Definition: i18n.py:36
cCiSession::SessionId
int SessionId(void) const
Definition: dvbci.cpp:794
cTPDU::Tcid
uint8_t Tcid(void)
Definition: dvbci.cpp:273
cCiEnquiry::~cCiEnquiry
~cCiEnquiry()
Definition: dvbci.cpp:1477
AOT_LIST_LAST
@ AOT_LIST_LAST
Definition: dvbci.cpp:758
cCiResourceManager
Definition: dvbci.cpp:877
SIZE_INDICATOR
static constexpr int SIZE_INDICATOR
Definition: dvbci.cpp:81
cLlCiHandler::GetCaSystemIds
dvbca_vector GetCaSystemIds(int Slot) override
Definition: dvbci.cpp:1876
T_REQUEST_TC
@ T_REQUEST_TC
Definition: dvbci.cpp:257
cLlCiHandler::m_fdCa
int m_fdCa
Definition: dvbci.h:163
AOT_SUBTITLE_DOWNLOAD_LAST
@ AOT_SUBTITLE_DOWNLOAD_LAST
Definition: dvbci.cpp:766
CLOSE_MMI_IMMEDIATE
@ CLOSE_MMI_IMMEDIATE
Definition: dvbci.cpp:1203
cCiSession::GetData
static const uint8_t * GetData(const uint8_t *Data, int &Length)
Definition: dvbci.cpp:826
AOT_MENU_MORE
@ AOT_MENU_MORE
Definition: dvbci.cpp:756
SESSION_STATUS
SESSION_STATUS
Definition: dvbci.cpp:710
cCiMenu::Select
bool Select(int Index)
Definition: dvbci.cpp:1463
MAX_CI_SESSION
#define MAX_CI_SESSION
Definition: dvbci.h:137
AOT_COMMS_REPLY
@ AOT_COMMS_REPLY
Definition: dvbci.cpp:772
cHlCiHandler
Definition: dvbci.h:202
CPCI_QUERY
@ CPCI_QUERY
Definition: dvbci.cpp:1499
ST_SESSION_NUMBER
@ ST_SESSION_NUMBER
Definition: dvbci.cpp:699
AOT_TEXT_LAST
@ AOT_TEXT_LAST
Definition: dvbci.cpp:749
cCiMenu::m_bottomText
char * m_bottomText
Definition: dvbci.h:80
cCiMenu::m_titleText
char * m_titleText
Definition: dvbci.h:78
tAnswer::m_id
uint8_t m_id
Definition: dvbci.cpp:1420
cCiTransportConnection::SendData
int SendData(std::vector< uint8_t > &Data)
Definition: dvbci.cpp:420
cCiTransportConnection::Poll
int Poll(void)
Definition: dvbci.cpp:575
cLlCiHandler::Send
bool Send(uint8_t Tag, int SessionId, int ResourceId=0, int Status=-1)
Definition: dvbci.cpp:1644
cMutex::Unlock
void Unlock(void)
Definition: dvbci.cpp:211
cMutexLock::m_mutex
cMutex * m_mutex
Definition: dvbci.h:61
cCiMMI::m_menu
cCiMenu * m_menu
Definition: dvbci.cpp:1252
cLlCiHandler::m_hasUserIO
bool m_hasUserIO
Definition: dvbci.h:166
cCiTransportConnection::m_dataAvailable
bool m_dataAvailable
Definition: dvbci.cpp:406
OBJECT_TAG
OBJECT_TAG
Definition: dvbci.cpp:728
cCiConditionalAccessSupport::GetCaSystemIds
dvbca_vector GetCaSystemIds(void)
Definition: dvbci.cpp:1037
AOT_LIST_MORE
@ AOT_LIST_MORE
Definition: dvbci.cpp:759
cLlCiHandler::CloseSession
bool CloseSession(int SessionId)
Definition: dvbci.cpp:1729
cLlCiHandler
Definition: dvbci.h:159
cMutexLock::Lock
bool Lock(cMutex *Mutex)
Definition: dvbci.cpp:230
cCiDateTime::SetTimeOffset
void SetTimeOffset(double offset)
Definition: dvbci.cpp:1120
eState
eState
Definition: dvbci.cpp:394
DCC_INPUT_CHARACTER_TABLE_LIST
@ DCC_INPUT_CHARACTER_TABLE_LIST
Definition: dvbci.cpp:1212
cMutex::Lock
void Lock(void)
Definition: dvbci.cpp:202
cTPDU::Status
uint8_t Status(void)
Definition: dvbci.cpp:383
cLlCiHandler::CreateSession
cCiSession * CreateSession(int ResourceId)
Definition: dvbci.cpp:1679
AOT_MENU_ANSW
@ AOT_MENU_ANSW
Definition: dvbci.cpp:757
cCiApplicationInformation::GetApplicationManufacturer
uint16_t GetApplicationManufacturer() const
Definition: dvbci.cpp:957
CPCI_IDS
CPCI_IDS
Definition: dvbci.cpp:1496
cCiTransportLayer
Definition: dvbci.cpp:598
cCiSession::cCiSession
cCiSession(int SessionId, int ResourceId, cCiTransportConnection *Tc)
Definition: dvbci.cpp:800
cCiTransportConnection::Data
const uint8_t * Data(int &Length)
Definition: dvbci.cpp:540
cCiMenu::~cCiMenu
~cCiMenu()
Definition: dvbci.cpp:1445
cCiApplicationInformation::GetApplicationString
char * GetApplicationString()
Definition: dvbci.cpp:956
IDENTIFIERS
IDENTIFIERS
Definition: dvbci.cpp:717
MAX_CI_CONNECT
static constexpr size_t MAX_CI_CONNECT
Definition: dvbci.cpp:596
cHlCiHandler::m_caSystemIds
dvbca_vector m_caSystemIds
Definition: dvbci.h:210
RI_HOST_CONTROL
@ RI_HOST_CONTROL
Definition: dvbci.cpp:721
cCiSession::Process
virtual bool Process(int Length=0, const uint8_t *Data=nullptr)
Definition: dvbci.cpp:869
uint
unsigned int uint
Definition: compat.h:81
cTPDU::m_size
ssize_t m_size
Definition: dvbci.cpp:266
cCiResourceManager::cCiResourceManager
cCiResourceManager(int SessionId, cCiTransportConnection *Tc)
Definition: dvbci.cpp:885
ST_CREATE_SESSION_RESPONSE
@ ST_CREATE_SESSION_RESPONSE
Definition: dvbci.cpp:703
cCiSession::Tc
const cCiTransportConnection * Tc(void)
Definition: dvbci.cpp:793
cCiMenu::m_entries
char * m_entries[MAX_CIMENU_ENTRIES]
Definition: dvbci.h:81
cCiApplicationInformation::m_manufacturerCode
uint16_t m_manufacturerCode
Definition: dvbci.cpp:949
cTPDU::Tag
uint8_t Tag(void)
Definition: dvbci.cpp:274
DEC2BCD
static constexpr uint8_t DEC2BCD(uint8_t d)
Definition: dvbci.cpp:1126
cHlCiHandler::Reset
bool Reset(int Slot) const
Definition: dvbci.cpp:2046
DRI_UNKNOWN_MMI_MODE
@ DRI_UNKNOWN_MMI_MODE
Definition: dvbci.cpp:1234
cCiConditionalAccessSupport::SendPMT
bool SendPMT(const cCiCaPmt &CaPmt)
Definition: dvbci.cpp:1090
cHlCiHandler::CommHL
int CommHL(unsigned tag, unsigned function, struct ca_msg *msg) const
Definition: dvbci.cpp:1931
AI_CANCEL
@ AI_CANCEL
Definition: dvbci.cpp:1245
AOT_PROFILE
@ AOT_PROFILE
Definition: dvbci.cpp:731
cCiTransportLayer::ResetSlot
bool ResetSlot(int Slot) const
Definition: dvbci.cpp:633
WRKRND_TIME_BEFORE_ENTER_MENU
static constexpr time_t WRKRND_TIME_BEFORE_ENTER_MENU
Definition: dvbci.cpp:77
MAX_TPDU_SIZE
static constexpr size_t MAX_TPDU_SIZE
Definition: dvbci.cpp:245
cCiConditionalAccessSupport::Process
bool Process(int Length=0, const uint8_t *Data=nullptr) override
Definition: dvbci.cpp:1049
cCiMMI::HasUserIO
bool HasUserIO(void) override
Definition: dvbci.cpp:1258
cCiApplicationInformation::Process
bool Process(int Length=0, const uint8_t *Data=nullptr) override
Definition: dvbci.cpp:978
dsyslog
#define dsyslog(a...)
Definition: dvbci.cpp:54
cCiApplicationInformation::EnterMenu
bool EnterMenu(void)
Definition: dvbci.cpp:1017
cHlCiHandler::m_fdCa
int m_fdCa
Definition: dvbci.h:206
T_DATA_MORE
@ T_DATA_MORE
Definition: dvbci.cpp:261
esyslog
#define esyslog(a...)
Definition: dvbci.cpp:52
cTPDU::Slot
uint8_t Slot(void)
Definition: dvbci.cpp:272
cCiSession::SendData
int SendData(int Tag, std::vector< uint8_t > &Data)
Definition: dvbci.cpp:788
RI_APPLICATION_INFORMATION
@ RI_APPLICATION_INFORMATION
Definition: dvbci.cpp:719
sConnected
static bool sConnected
Definition: dvbci.cpp:64
cCiMMI::SendMenuAnswer
bool SendMenuAnswer(uint8_t Selection)
Definition: dvbci.cpp:1410
cCiApplicationInformation
Definition: dvbci.cpp:943
cCiSession
Definition: dvbci.cpp:779
cLlCiHandler::m_tpl
cCiTransportLayer * m_tpl
Definition: dvbci.h:169
cCiTransportConnection::m_state
eState m_state
Definition: dvbci.cpp:402
cCiMMI::~cCiMMI
~cCiMMI() override
Definition: dvbci.cpp:1273
cHlCiHandler::GetCaSystemIds
dvbca_vector GetCaSystemIds(int Slot) override
Definition: dvbci.cpp:2015
cCiTransportConnection::Slot
int Slot(void) const
Definition: dvbci.cpp:418
T_VALUES
T_VALUES
Definition: dvbci.cpp:250
cCiDateTime::Process
bool Process(int Length=0, const uint8_t *Data=nullptr) override
Definition: dvbci.cpp:1171
cMutex::m_lockingPid
pid_t m_lockingPid
Definition: dvbci.h:50
DCC_DISPLAY_CHARACTER_TABLE_LIST
@ DCC_DISPLAY_CHARACTER_TABLE_LIST
Definition: dvbci.cpp:1211
cCiMMI::m_enquiry
cCiEnquiry * m_enquiry
Definition: dvbci.cpp:1253
dbgprotocol
#define dbgprotocol(a...)
Definition: dvbci.cpp:67
ST_OPEN_SESSION_REQUEST
@ ST_OPEN_SESSION_REQUEST
Definition: dvbci.cpp:700
cCiEnquiry::m_mmi
cCiMMI * m_mmi
Definition: dvbci.h:100
cCiTransportLayer::NewConnection
cCiTransportConnection * NewConnection(int Slot)
Definition: dvbci.cpp:619
DRI_LIST_FULL_SCREEN_GRAPHIC_CHARACTERISTICS
@ DRI_LIST_FULL_SCREEN_GRAPHIC_CHARACTERISTICS
Definition: dvbci.cpp:1232
cCiTransportConnection::cCiTransportConnection
cCiTransportConnection(void)
Definition: dvbci.cpp:427
cTPDU::GetData
const uint8_t * GetData(const uint8_t *Data, int &Length) const
Definition: dvbci.cpp:371
AOT_PROFILE_CHANGE
@ AOT_PROFILE_CHANGE
Definition: dvbci.cpp:732
cCiDateTime
Definition: dvbci.cpp:1102
MM_HIGH_LEVEL
@ MM_HIGH_LEVEL
Definition: dvbci.cpp:1220
AOT_ASK_RELEASE
@ AOT_ASK_RELEASE
Definition: dvbci.cpp:743
cCiTransportConnection::LastResponse
int LastResponse(void) const
Definition: dvbci.cpp:413
cCiTransportLayer::m_fd
int m_fd
Definition: dvbci.cpp:600
cLlCiHandler::cLlCiHandler
cLlCiHandler(int Fd, int NumSlots)
Definition: dvbci.cpp:1591
cCiTransportLayer::cCiTransportLayer
cCiTransportLayer(int Fd, int NumSlots)
Definition: dvbci.cpp:611
POLL_INTERVAL
static constexpr std::chrono::milliseconds POLL_INTERVAL
Definition: dvbci.cpp:573
cCiMMI::GetText
char * GetText(int &Length, const uint8_t **Data)
Definition: dvbci.cpp:1279
cTPDU::Data
const uint8_t * Data(int &Length)
Definition: dvbci.cpp:275
cHlCiHandler::NeedCaPmt
bool NeedCaPmt(void) override
Definition: dvbci.cpp:2055
OK
static constexpr int OK
Definition: dvbci.cpp:69
BYTE1
static constexpr uint8_t BYTE1(uint16_t a)
Definition: dvbci.cpp:1130
DRI_LIST_GRAPHIC_OVERLAY_CHARACTERISTICS
@ DRI_LIST_GRAPHIC_OVERLAY_CHARACTERISTICS
Definition: dvbci.cpp:1231
cCiSession::m_tc
cCiTransportConnection * m_tc
Definition: dvbci.cpp:783
cCiEnquiry::m_text
char * m_text
Definition: dvbci.h:101
cLlCiHandler::Reset
bool Reset(int Slot)
Definition: dvbci.cpp:1904
cLlCiHandler::m_needCaPmt
bool m_needCaPmt
Definition: dvbci.h:167
cLlCiHandler::EnterMenu
bool EnterMenu(int Slot) override
Definition: dvbci.cpp:1847
cLlCiHandler::ResourceIdToInt
static int ResourceIdToInt(const uint8_t *Data)
Definition: dvbci.cpp:1639
sDumpTPDUDataTransfer
static bool sDumpTPDUDataTransfer
Definition: dvbci.cpp:62
CopyString
static char * CopyString(int Length, const uint8_t *Data)
Definition: dvbci.cpp:166
AOT_COMMS_RCV_LAST
@ AOT_COMMS_RCV_LAST
Definition: dvbci.cpp:775
stACTIVE
@ stACTIVE
Definition: dvbci.cpp:394
cCiHandler::CreateCiHandler
static cCiHandler * CreateCiHandler(const char *FileName)
Definition: dvbci.cpp:1607
GetLength
static const uint8_t * GetLength(const uint8_t *Data, int &Length)
Definition: dvbci.cpp:95
uint16_t
unsigned short uint16_t
Definition: iso6937tables.h:3
cCiApplicationInformation::m_state
int m_state
Definition: dvbci.cpp:945
cCiMenu
Definition: dvbci.h:72
cCiSession::m_resourceId
int m_resourceId
Definition: dvbci.cpp:782
cTPDU::Read
int Read(int fd)
Definition: dvbci.cpp:338
tAnswer
Definition: dvbci.cpp:1420
cCiEnquiry
Definition: dvbci.h:97
cCiSession::HasUserIO
virtual bool HasUserIO(void)
Definition: dvbci.cpp:796
cCiDateTime::SendDateTime
bool SendDateTime(void)
Definition: dvbci.cpp:1133
AOT_SCENE_CONTROL
@ AOT_SCENE_CONTROL
Definition: dvbci.cpp:765
cCiSession::m_sessionId
int m_sessionId
Definition: dvbci.cpp:781
cHlCiHandler::m_mutex
cMutex m_mutex
Definition: dvbci.h:205
AOT_NONE
@ AOT_NONE
Definition: dvbci.cpp:729
cCiResourceManager::m_state
int m_state
Definition: dvbci.cpp:879
d
static const iso6937table * d
Definition: iso6937tables.cpp:1025
cCiCaPmt::m_infoLengthPos
int m_infoLengthPos
Definition: dvbci.h:128
AOT_TUNE
@ AOT_TUNE
Definition: dvbci.cpp:740
cCiTransportConnection::State
eState State(void)
Definition: dvbci.cpp:412
MAX_CONNECT_RETRIES
static constexpr int8_t MAX_CONNECT_RETRIES
Definition: dvbci.cpp:545
stIDLE
@ stIDLE
Definition: dvbci.cpp:394
cCiTransportConnection::CreateConnection
int CreateConnection(void)
Definition: dvbci.cpp:547
cCiApplicationInformation::m_applicationType
uint8_t m_applicationType
Definition: dvbci.cpp:947
cLlCiHandler::GetSessionByResourceId
cCiSession * GetSessionByResourceId(int ResourceId, int Slot)
Definition: dvbci.cpp:1670
cCiConditionalAccessSupport::cCiConditionalAccessSupport
cCiConditionalAccessSupport(int SessionId, cCiTransportConnection *Tc)
Definition: dvbci.cpp:1042
RI_MMI
@ RI_MMI
Definition: dvbci.cpp:723
MM_LOW_LEVEL_OVERLAY_GRAPHICS
@ MM_LOW_LEVEL_OVERLAY_GRAPHICS
Definition: dvbci.cpp:1221
cCiTransportConnection::m_fd
int m_fd
Definition: dvbci.cpp:399
cCiCaPmt::cCiCaPmt
cCiCaPmt(int ProgramNumber, uint8_t cplm=CPLM_ONLY)
Definition: dvbci.cpp:1503
cCiMMI::Menu
cCiMenu * Menu(void)
Definition: dvbci.cpp:1396
CLOSE_MMI
CLOSE_MMI
Definition: dvbci.cpp:1202
AOT_SUBTITLE_SEGMENT_LAST
@ AOT_SUBTITLE_SEGMENT_LAST
Definition: dvbci.cpp:760
T_TC_ERROR
@ T_TC_ERROR
Definition: dvbci.cpp:259
cCiConditionalAccessSupport::NeedCaPmt
bool NeedCaPmt(void) const
Definition: dvbci.cpp:1039
D
#define D(i, j)
cCiTransportConnection::m_tpdu
cTPDU * m_tpdu
Definition: dvbci.cpp:403
ST_CLOSE_SESSION_RESPONSE
@ ST_CLOSE_SESSION_RESPONSE
Definition: dvbci.cpp:705
SS_NOT_ALLOCATED
@ SS_NOT_ALLOCATED
Definition: dvbci.cpp:712
ST_CLOSE_SESSION_REQUEST
@ ST_CLOSE_SESSION_REQUEST
Definition: dvbci.cpp:704
cLlCiHandler::GetMenu
cCiMenu * GetMenu(void) override
Definition: dvbci.cpp:1854
cLlCiHandler::m_newCaSupport
bool m_newCaSupport
Definition: dvbci.h:165
cCiTransportConnection::RecvData
int RecvData(void)
Definition: dvbci.cpp:533
cCiSession::ResourceId
int ResourceId(void) const
Definition: dvbci.cpp:795
ANSWER_IDS
ANSWER_IDS
Definition: dvbci.cpp:1244
AOT_COMMS_SEND_LAST
@ AOT_COMMS_SEND_LAST
Definition: dvbci.cpp:773
cCiEnquiry::m_expectedLength
int m_expectedLength
Definition: dvbci.h:103
cCiDateTime::m_interval
int m_interval
Definition: dvbci.cpp:1104
cCiHandler
Definition: dvbci.h:143
cCiMenu::AddEntry
bool AddEntry(char *s)
Definition: dvbci.cpp:1454
BYTE0
static constexpr uint8_t BYTE0(uint16_t a)
Definition: dvbci.cpp:1128
cCiTransportConnection::SendTPDU
int SendTPDU(uint8_t Tag, int Length=0, const uint8_t *Data=nullptr) const
Definition: dvbci.cpp:450
cCiApplicationInformation::m_creationTime
time_t m_creationTime
Definition: dvbci.cpp:946
T_DATA_LAST
@ T_DATA_LAST
Definition: dvbci.cpp:260
AOT_ENQ
@ AOT_ENQ
Definition: dvbci.cpp:753
cCiMMI::Process
bool Process(int Length=0, const uint8_t *Data=nullptr) override
Definition: dvbci.cpp:1298
T_SB
@ T_SB
Definition: dvbci.cpp:251
isyslog
#define isyslog(a...)
Definition: dvbci.cpp:53
cCiSession::SendData
int SendData(int Tag, int Length=0, const uint8_t *Data=nullptr)
Definition: dvbci.cpp:832
find
static pid_list_t::iterator find(const PIDInfoMap &map, pid_list_t &list, pid_list_t::iterator begin, pid_list_t::iterator end, bool find_open)
Definition: dvbstreamhandler.cpp:363
CAM_READ_TIMEOUT
static constexpr int CAM_READ_TIMEOUT
Definition: dvbci.cpp:456
cCiMenu::m_numEntries
int m_numEntries
Definition: dvbci.h:82
AOT_KEYPRESS
@ AOT_KEYPRESS
Definition: dvbci.cpp:752
cCiMenu::MAX_CIMENU_ENTRIES
@ MAX_CIMENU_ENTRIES
Definition: dvbci.h:75
DRI_UNKNOWN_CHARACTER_TABLE
@ DRI_UNKNOWN_CHARACTER_TABLE
Definition: dvbci.cpp:1235
cLlCiHandler::OpenSession
bool OpenSession(int Length, const uint8_t *Data)
Definition: dvbci.cpp:1699
cCiMenu::Cancel
bool Cancel(void)
Definition: dvbci.cpp:1470
cCiMMI::Enquiry
cCiEnquiry * Enquiry(void)
Definition: dvbci.cpp:1403
cHlCiHandler::GetMenu
cCiMenu * GetMenu(void) override
Definition: dvbci.cpp:2005
cHlCiHandler::GetEnquiry
cCiEnquiry * GetEnquiry(void) override
Definition: dvbci.cpp:2010
ERROR
static constexpr int ERROR
Definition: dvbci.cpp:71
cCiCaPmt::AddElementaryStream
void AddElementaryStream(int type, int pid)
Definition: dvbci.cpp:1515
cCiDateTime::cCiDateTime
cCiDateTime(int SessionId, cCiTransportConnection *Tc)
Definition: dvbci.cpp:1114