From ccf6e0f9c6b0481ed13e0f4794e3fbead750f385 Mon Sep 17 00:00:00 2001 From: Lars Heer Date: Wed, 18 Sep 2013 05:50:03 +0200 Subject: added vdr-plugin-mcli-0.0.1+svn20120927 --- COPYING | 340 +++++ HISTORY | 10 + Makefile | 168 +++ README | 60 + cam_menu.c | 627 +++++++++ cam_menu.h | 56 + def.h.defs | 73 ++ defs2.h | 366 ++++++ device.c | 962 ++++++++++++++ device.h | 165 +++ filter.c | 463 +++++++ filter.h | 56 + mcast/.svn/entries | 40 + mcast/client/.indent.pro | 1 + mcast/client/.svn/entries | 1357 ++++++++++++++++++++ .../client/.svn/prop-base/api_shm_test.c.svn-base | 5 + .../client/.svn/prop-base/api_sock_test.c.svn-base | 5 + mcast/client/.svn/prop-base/ciparser.c.svn-base | 5 + mcast/client/.svn/prop-base/inet_aton.c.svn-base | 5 + mcast/client/.svn/prop-base/inet_ntop.c.svn-base | 5 + mcast/client/.svn/prop-base/inet_pton.c.svn-base | 5 + mcast/client/.svn/prop-base/interfaces.c.svn-base | 5 + mcast/client/.svn/prop-base/mcast.c.svn-base | 5 + mcast/client/.svn/prop-base/mld_client.c.svn-base | 5 + mcast/client/.svn/prop-base/mld_common.c.svn-base | 5 + mcast/client/.svn/prop-base/recv_ccpp.c.svn-base | 5 + mcast/client/.svn/prop-base/tools.c.svn-base | 5 + mcast/client/.svn/prop-base/win32.svn-base | 5 + mcast/client/.svn/text-base/.indent.pro.svn-base | 1 + mcast/client/.svn/text-base/Makefile.svn-base | 210 +++ mcast/client/.svn/text-base/api_server.c.svn-base | 397 ++++++ mcast/client/.svn/text-base/api_server.h.svn-base | 67 + .../client/.svn/text-base/api_shm_test.c.svn-base | 1 + .../client/.svn/text-base/api_sock_test.c.svn-base | 1 + mcast/client/.svn/text-base/api_test.c.svn-base | 127 ++ mcast/client/.svn/text-base/ci_handler.c.svn-base | 321 +++++ mcast/client/.svn/text-base/ci_handler.h.svn-base | 30 + mcast/client/.svn/text-base/ciparser.c.svn-base | 1 + .../client/.svn/text-base/dummy_client.c.svn-base | 101 ++ .../client/.svn/text-base/dummy_client.h.svn-base | 10 + .../client/.svn/text-base/dvblo_handler.c.svn-base | 716 +++++++++++ .../client/.svn/text-base/dvblo_handler.h.svn-base | 40 + mcast/client/.svn/text-base/headers.h.svn-base | 32 + mcast/client/.svn/text-base/inet_aton.c.svn-base | 1 + mcast/client/.svn/text-base/inet_ntop.c.svn-base | 1 + mcast/client/.svn/text-base/inet_pton.c.svn-base | 1 + mcast/client/.svn/text-base/input.c.svn-base | 145 +++ mcast/client/.svn/text-base/interfaces.c.svn-base | 1 + mcast/client/.svn/text-base/main.c.svn-base | 83 ++ mcast/client/.svn/text-base/mcast.c.svn-base | 1 + mcast/client/.svn/text-base/mld_client.c.svn-base | 1 + mcast/client/.svn/text-base/mld_common.c.svn-base | 1 + .../client/.svn/text-base/mld_reporter.c.svn-base | 225 ++++ .../client/.svn/text-base/mld_reporter.h.svn-base | 11 + mcast/client/.svn/text-base/mmi_handler.c.svn-base | 336 +++++ mcast/client/.svn/text-base/mmi_handler.h.svn-base | 46 + mcast/client/.svn/text-base/recv_ccpp.c.svn-base | 1 + mcast/client/.svn/text-base/recv_tv.c.svn-base | 905 +++++++++++++ mcast/client/.svn/text-base/recv_tv.h.svn-base | 96 ++ mcast/client/.svn/text-base/satlists.c.svn-base | 133 ++ mcast/client/.svn/text-base/sock_test.c.svn-base | 93 ++ mcast/client/.svn/text-base/tca_handler.c.svn-base | 84 ++ mcast/client/.svn/text-base/tca_handler.h.svn-base | 18 + mcast/client/.svn/text-base/tools.c.svn-base | 1 + mcast/client/.svn/text-base/tra_handler.c.svn-base | 56 + mcast/client/.svn/text-base/tra_handler.h.svn-base | 10 + mcast/client/.svn/text-base/win32.svn-base | 1 + mcast/client/Makefile | 210 +++ mcast/client/api_server.c | 397 ++++++ mcast/client/api_server.h | 67 + mcast/client/api_shm_test.c | 1 + mcast/client/api_sock_test.c | 1 + mcast/client/api_test.c | 127 ++ mcast/client/ci_handler.c | 321 +++++ mcast/client/ci_handler.h | 30 + mcast/client/ciparser.c | 1 + mcast/client/dummy_client.c | 101 ++ mcast/client/dummy_client.h | 10 + mcast/client/dvblo_handler.c | 716 +++++++++++ mcast/client/dvblo_handler.h | 40 + mcast/client/headers.h | 32 + mcast/client/inet_aton.c | 1 + mcast/client/inet_ntop.c | 1 + mcast/client/inet_pton.c | 1 + mcast/client/input.c | 145 +++ mcast/client/interfaces.c | 1 + mcast/client/main.c | 83 ++ mcast/client/mcast.c | 1 + mcast/client/mingw/.svn/entries | 96 ++ .../client/mingw/.svn/text-base/Makefile.svn-base | 55 + .../client/mingw/.svn/text-base/build.cmd.svn-base | 2 + mcast/client/mingw/Makefile | 55 + mcast/client/mingw/build.cmd | 2 + mcast/client/mld_client.c | 1 + mcast/client/mld_common.c | 1 + mcast/client/mld_reporter.c | 225 ++++ mcast/client/mld_reporter.h | 11 + mcast/client/mmi_handler.c | 336 +++++ mcast/client/mmi_handler.h | 46 + mcast/client/recv_ccpp.c | 1 + mcast/client/recv_tv.c | 905 +++++++++++++ mcast/client/recv_tv.h | 96 ++ mcast/client/satlists.c | 133 ++ mcast/client/sock_test.c | 93 ++ mcast/client/tca_handler.c | 84 ++ mcast/client/tca_handler.h | 18 + mcast/client/tools.c | 1 + mcast/client/tra_handler.c | 56 + mcast/client/tra_handler.h | 10 + mcast/client/win32 | 1 + mcast/common/.indent.pro | 1 + mcast/common/.svn/entries | 847 ++++++++++++ mcast/common/.svn/text-base/.indent.pro.svn-base | 1 + mcast/common/.svn/text-base/ciparser.c.svn-base | 702 ++++++++++ mcast/common/.svn/text-base/ciparser.h.svn-base | 140 ++ mcast/common/.svn/text-base/crc32.c.svn-base | 88 ++ mcast/common/.svn/text-base/crc32.h.svn-base | 35 + mcast/common/.svn/text-base/defs.h.svn-base | 389 ++++++ .../.svn/text-base/dvb_ca_wrapper.h.svn-base | 18 + mcast/common/.svn/text-base/input.h.svn-base | 38 + mcast/common/.svn/text-base/interfaces.c.svn-base | 347 +++++ mcast/common/.svn/text-base/interfaces.h.svn-base | 52 + mcast/common/.svn/text-base/list.h.svn-base | 238 ++++ mcast/common/.svn/text-base/mcast.c.svn-base | 674 ++++++++++ mcast/common/.svn/text-base/mcast.h.svn-base | 64 + mcast/common/.svn/text-base/mld.h.svn-base | 339 +++++ mcast/common/.svn/text-base/mld_client.c.svn-base | 244 ++++ mcast/common/.svn/text-base/mld_common.c.svn-base | 243 ++++ mcast/common/.svn/text-base/recv_ccpp.c.svn-base | 1333 +++++++++++++++++++ mcast/common/.svn/text-base/recv_ccpp.h.svn-base | 129 ++ mcast/common/.svn/text-base/satlists.h.svn-base | 92 ++ mcast/common/.svn/text-base/siparser.c.svn-base | 1049 +++++++++++++++ mcast/common/.svn/text-base/siparser.h.svn-base | 369 ++++++ mcast/common/.svn/text-base/tools.c.svn-base | 777 +++++++++++ mcast/common/.svn/text-base/tools.h.svn-base | 108 ++ mcast/common/.svn/text-base/version.h.svn-base | 18 + mcast/common/ciparser.c | 702 ++++++++++ mcast/common/ciparser.h | 140 ++ mcast/common/crc32.c | 88 ++ mcast/common/crc32.h | 35 + mcast/common/darwin/.svn/entries | 31 + mcast/common/darwin/include/.svn/entries | 62 + .../darwin/include/.svn/prop-base/linux.svn-base | 5 + .../darwin/include/.svn/text-base/linux.svn-base | 1 + mcast/common/darwin/include/linux | 1 + mcast/common/defs.h | 389 ++++++ mcast/common/dvb_ca_wrapper.h | 18 + mcast/common/input.h | 38 + mcast/common/interfaces.c | 347 +++++ mcast/common/interfaces.h | 52 + mcast/common/list.h | 238 ++++ mcast/common/mcast.c | 674 ++++++++++ mcast/common/mcast.h | 64 + mcast/common/mld.h | 339 +++++ mcast/common/mld_client.c | 244 ++++ mcast/common/mld_common.c | 243 ++++ mcast/common/recv_ccpp.c | 1333 +++++++++++++++++++ mcast/common/recv_ccpp.h | 129 ++ mcast/common/satlists.h | 92 ++ mcast/common/siparser.c | 1049 +++++++++++++++ mcast/common/siparser.h | 369 ++++++ mcast/common/tools.c | 777 +++++++++++ mcast/common/tools.h | 108 ++ mcast/common/version.h | 18 + mcast/dvbloop/.svn/entries | 266 ++++ mcast/dvbloop/.svn/text-base/dvblo.h.svn-base | 58 + mcast/dvbloop/.svn/text-base/dvblo_adap.h.svn-base | 155 +++ .../.svn/text-base/dvblo_adap_ca.h.svn-base | 43 + .../.svn/text-base/dvblo_adap_fe.h.svn-base | 30 + mcast/dvbloop/.svn/text-base/dvblo_char.h.svn-base | 33 + .../dvbloop/.svn/text-base/dvblo_ioctl.h.svn-base | 203 +++ mcast/dvbloop/.svn/text-base/dvblo_util.h.svn-base | 45 + mcast/dvbloop/dvblo.h | 58 + mcast/dvbloop/dvblo_adap.h | 155 +++ mcast/dvbloop/dvblo_adap_ca.h | 43 + mcast/dvbloop/dvblo_adap_fe.h | 30 + mcast/dvbloop/dvblo_char.h | 33 + mcast/dvbloop/dvblo_ioctl.h | 203 +++ mcast/dvbloop/dvblo_util.h | 45 + mcast/tool/.svn/entries | 232 ++++ mcast/tool/.svn/prop-base/mcast.c.svn-base | 5 + mcast/tool/.svn/prop-base/tools.c.svn-base | 5 + mcast/tool/.svn/text-base/Makefile.svn-base | 137 ++ mcast/tool/.svn/text-base/mcast.c.svn-base | 1 + mcast/tool/.svn/text-base/netcvdiag.c.svn-base | 433 +++++++ mcast/tool/.svn/text-base/netcvlogview.c.svn-base | 206 +++ mcast/tool/.svn/text-base/netcvupdate.c.svn-base | 773 +++++++++++ mcast/tool/.svn/text-base/tools.c.svn-base | 1 + mcast/tool/Makefile | 137 ++ mcast/tool/mcast.c | 1 + mcast/tool/netcvdiag.c | 433 +++++++ mcast/tool/netcvlogview.c | 206 +++ mcast/tool/netcvupdate.c | 773 +++++++++++ mcast/tool/tools.c | 1 + mcli-i18n.diff | 22 + mcli.c | 1122 ++++++++++++++++ mcli.h | 180 +++ mcli_service.h | 25 + mcliheaders.h | 29 + packetbuffer.c | 283 ++++ packetbuffer.h | 57 + patches/.svn/entries | 232 ++++ .../reelvdr-device-handling-patch.diff.svn-base | 158 +++ .../text-base/vdr-1.4.0-closefilter.patch.svn-base | 45 + ...r-1.6-device-consistent-destruct.patch.svn-base | 97 ++ ...vdr-1.6-section-read-abstraction.patch.svn-base | 38 + .../vdr-1.6.0-altmenuaction.patch.svn-base | 38 + .../vdr-1.6.0-intcamdevices.patch.svn-base | 78 ++ patches/reelvdr-device-handling-patch.diff | 158 +++ patches/vdr-1.4.0-closefilter.patch | 45 + patches/vdr-1.6-device-consistent-destruct.patch | 97 ++ patches/vdr-1.6-section-read-abstraction.patch | 38 + patches/vdr-1.6.0-altmenuaction.patch | 38 + patches/vdr-1.6.0-intcamdevices.patch | 78 ++ po/.svn/entries | 96 ++ po/.svn/text-base/de_DE.po.svn-base | 86 ++ po/.svn/text-base/nl_NL.po.svn-base | 87 ++ po/de_DE.po | 86 ++ po/nl_NL.po | 87 ++ wait4ncv.diff | 61 + 220 files changed, 37656 insertions(+) create mode 100644 COPYING create mode 100644 HISTORY create mode 100644 Makefile create mode 100644 README create mode 100644 cam_menu.c create mode 100644 cam_menu.h create mode 100644 def.h.defs create mode 100644 defs2.h create mode 100644 device.c create mode 100644 device.h create mode 100644 filter.c create mode 100644 filter.h create mode 100644 mcast/.svn/entries create mode 100644 mcast/client/.indent.pro create mode 100644 mcast/client/.svn/entries create mode 100644 mcast/client/.svn/prop-base/api_shm_test.c.svn-base create mode 100644 mcast/client/.svn/prop-base/api_sock_test.c.svn-base create mode 100644 mcast/client/.svn/prop-base/ciparser.c.svn-base create mode 100644 mcast/client/.svn/prop-base/inet_aton.c.svn-base create mode 100644 mcast/client/.svn/prop-base/inet_ntop.c.svn-base create mode 100644 mcast/client/.svn/prop-base/inet_pton.c.svn-base create mode 100644 mcast/client/.svn/prop-base/interfaces.c.svn-base create mode 100644 mcast/client/.svn/prop-base/mcast.c.svn-base create mode 100644 mcast/client/.svn/prop-base/mld_client.c.svn-base create mode 100644 mcast/client/.svn/prop-base/mld_common.c.svn-base create mode 100644 mcast/client/.svn/prop-base/recv_ccpp.c.svn-base create mode 100644 mcast/client/.svn/prop-base/tools.c.svn-base create mode 100644 mcast/client/.svn/prop-base/win32.svn-base create mode 100644 mcast/client/.svn/text-base/.indent.pro.svn-base create mode 100644 mcast/client/.svn/text-base/Makefile.svn-base create mode 100644 mcast/client/.svn/text-base/api_server.c.svn-base create mode 100644 mcast/client/.svn/text-base/api_server.h.svn-base create mode 100644 mcast/client/.svn/text-base/api_shm_test.c.svn-base create mode 100644 mcast/client/.svn/text-base/api_sock_test.c.svn-base create mode 100644 mcast/client/.svn/text-base/api_test.c.svn-base create mode 100644 mcast/client/.svn/text-base/ci_handler.c.svn-base create mode 100644 mcast/client/.svn/text-base/ci_handler.h.svn-base create mode 100644 mcast/client/.svn/text-base/ciparser.c.svn-base create mode 100644 mcast/client/.svn/text-base/dummy_client.c.svn-base create mode 100644 mcast/client/.svn/text-base/dummy_client.h.svn-base create mode 100644 mcast/client/.svn/text-base/dvblo_handler.c.svn-base create mode 100644 mcast/client/.svn/text-base/dvblo_handler.h.svn-base create mode 100644 mcast/client/.svn/text-base/headers.h.svn-base create mode 100644 mcast/client/.svn/text-base/inet_aton.c.svn-base create mode 100644 mcast/client/.svn/text-base/inet_ntop.c.svn-base create mode 100644 mcast/client/.svn/text-base/inet_pton.c.svn-base create mode 100644 mcast/client/.svn/text-base/input.c.svn-base create mode 100644 mcast/client/.svn/text-base/interfaces.c.svn-base create mode 100644 mcast/client/.svn/text-base/main.c.svn-base create mode 100644 mcast/client/.svn/text-base/mcast.c.svn-base create mode 100644 mcast/client/.svn/text-base/mld_client.c.svn-base create mode 100644 mcast/client/.svn/text-base/mld_common.c.svn-base create mode 100644 mcast/client/.svn/text-base/mld_reporter.c.svn-base create mode 100644 mcast/client/.svn/text-base/mld_reporter.h.svn-base create mode 100644 mcast/client/.svn/text-base/mmi_handler.c.svn-base create mode 100644 mcast/client/.svn/text-base/mmi_handler.h.svn-base create mode 100644 mcast/client/.svn/text-base/recv_ccpp.c.svn-base create mode 100644 mcast/client/.svn/text-base/recv_tv.c.svn-base create mode 100644 mcast/client/.svn/text-base/recv_tv.h.svn-base create mode 100644 mcast/client/.svn/text-base/satlists.c.svn-base create mode 100644 mcast/client/.svn/text-base/sock_test.c.svn-base create mode 100644 mcast/client/.svn/text-base/tca_handler.c.svn-base create mode 100644 mcast/client/.svn/text-base/tca_handler.h.svn-base create mode 100644 mcast/client/.svn/text-base/tools.c.svn-base create mode 100644 mcast/client/.svn/text-base/tra_handler.c.svn-base create mode 100644 mcast/client/.svn/text-base/tra_handler.h.svn-base create mode 100644 mcast/client/.svn/text-base/win32.svn-base create mode 100644 mcast/client/Makefile create mode 100644 mcast/client/api_server.c create mode 100644 mcast/client/api_server.h create mode 120000 mcast/client/api_shm_test.c create mode 120000 mcast/client/api_sock_test.c create mode 100644 mcast/client/api_test.c create mode 100644 mcast/client/ci_handler.c create mode 100644 mcast/client/ci_handler.h create mode 120000 mcast/client/ciparser.c create mode 100644 mcast/client/dummy_client.c create mode 100644 mcast/client/dummy_client.h create mode 100644 mcast/client/dvblo_handler.c create mode 100644 mcast/client/dvblo_handler.h create mode 100644 mcast/client/headers.h create mode 120000 mcast/client/inet_aton.c create mode 120000 mcast/client/inet_ntop.c create mode 120000 mcast/client/inet_pton.c create mode 100644 mcast/client/input.c create mode 120000 mcast/client/interfaces.c create mode 100644 mcast/client/main.c create mode 120000 mcast/client/mcast.c create mode 100644 mcast/client/mingw/.svn/entries create mode 100644 mcast/client/mingw/.svn/text-base/Makefile.svn-base create mode 100644 mcast/client/mingw/.svn/text-base/build.cmd.svn-base create mode 100644 mcast/client/mingw/Makefile create mode 100644 mcast/client/mingw/build.cmd create mode 120000 mcast/client/mld_client.c create mode 120000 mcast/client/mld_common.c create mode 100644 mcast/client/mld_reporter.c create mode 100644 mcast/client/mld_reporter.h create mode 100644 mcast/client/mmi_handler.c create mode 100644 mcast/client/mmi_handler.h create mode 120000 mcast/client/recv_ccpp.c create mode 100644 mcast/client/recv_tv.c create mode 100644 mcast/client/recv_tv.h create mode 100644 mcast/client/satlists.c create mode 100644 mcast/client/sock_test.c create mode 100644 mcast/client/tca_handler.c create mode 100644 mcast/client/tca_handler.h create mode 120000 mcast/client/tools.c create mode 100644 mcast/client/tra_handler.c create mode 100644 mcast/client/tra_handler.h create mode 120000 mcast/client/win32 create mode 100644 mcast/common/.indent.pro create mode 100644 mcast/common/.svn/entries create mode 100644 mcast/common/.svn/text-base/.indent.pro.svn-base create mode 100644 mcast/common/.svn/text-base/ciparser.c.svn-base create mode 100644 mcast/common/.svn/text-base/ciparser.h.svn-base create mode 100644 mcast/common/.svn/text-base/crc32.c.svn-base create mode 100644 mcast/common/.svn/text-base/crc32.h.svn-base create mode 100644 mcast/common/.svn/text-base/defs.h.svn-base create mode 100644 mcast/common/.svn/text-base/dvb_ca_wrapper.h.svn-base create mode 100644 mcast/common/.svn/text-base/input.h.svn-base create mode 100644 mcast/common/.svn/text-base/interfaces.c.svn-base create mode 100644 mcast/common/.svn/text-base/interfaces.h.svn-base create mode 100644 mcast/common/.svn/text-base/list.h.svn-base create mode 100644 mcast/common/.svn/text-base/mcast.c.svn-base create mode 100644 mcast/common/.svn/text-base/mcast.h.svn-base create mode 100644 mcast/common/.svn/text-base/mld.h.svn-base create mode 100644 mcast/common/.svn/text-base/mld_client.c.svn-base create mode 100644 mcast/common/.svn/text-base/mld_common.c.svn-base create mode 100644 mcast/common/.svn/text-base/recv_ccpp.c.svn-base create mode 100644 mcast/common/.svn/text-base/recv_ccpp.h.svn-base create mode 100644 mcast/common/.svn/text-base/satlists.h.svn-base create mode 100644 mcast/common/.svn/text-base/siparser.c.svn-base create mode 100644 mcast/common/.svn/text-base/siparser.h.svn-base create mode 100644 mcast/common/.svn/text-base/tools.c.svn-base create mode 100644 mcast/common/.svn/text-base/tools.h.svn-base create mode 100644 mcast/common/.svn/text-base/version.h.svn-base create mode 100644 mcast/common/ciparser.c create mode 100644 mcast/common/ciparser.h create mode 100644 mcast/common/crc32.c create mode 100644 mcast/common/crc32.h create mode 100644 mcast/common/darwin/.svn/entries create mode 100644 mcast/common/darwin/include/.svn/entries create mode 100644 mcast/common/darwin/include/.svn/prop-base/linux.svn-base create mode 100644 mcast/common/darwin/include/.svn/text-base/linux.svn-base create mode 120000 mcast/common/darwin/include/linux create mode 100644 mcast/common/defs.h create mode 100644 mcast/common/dvb_ca_wrapper.h create mode 100644 mcast/common/input.h create mode 100644 mcast/common/interfaces.c create mode 100644 mcast/common/interfaces.h create mode 100644 mcast/common/list.h create mode 100644 mcast/common/mcast.c create mode 100644 mcast/common/mcast.h create mode 100644 mcast/common/mld.h create mode 100644 mcast/common/mld_client.c create mode 100644 mcast/common/mld_common.c create mode 100644 mcast/common/recv_ccpp.c create mode 100644 mcast/common/recv_ccpp.h create mode 100644 mcast/common/satlists.h create mode 100644 mcast/common/siparser.c create mode 100644 mcast/common/siparser.h create mode 100644 mcast/common/tools.c create mode 100644 mcast/common/tools.h create mode 100644 mcast/common/version.h create mode 100644 mcast/dvbloop/.svn/entries create mode 100644 mcast/dvbloop/.svn/text-base/dvblo.h.svn-base create mode 100644 mcast/dvbloop/.svn/text-base/dvblo_adap.h.svn-base create mode 100644 mcast/dvbloop/.svn/text-base/dvblo_adap_ca.h.svn-base create mode 100644 mcast/dvbloop/.svn/text-base/dvblo_adap_fe.h.svn-base create mode 100644 mcast/dvbloop/.svn/text-base/dvblo_char.h.svn-base create mode 100644 mcast/dvbloop/.svn/text-base/dvblo_ioctl.h.svn-base create mode 100644 mcast/dvbloop/.svn/text-base/dvblo_util.h.svn-base create mode 100644 mcast/dvbloop/dvblo.h create mode 100644 mcast/dvbloop/dvblo_adap.h create mode 100644 mcast/dvbloop/dvblo_adap_ca.h create mode 100644 mcast/dvbloop/dvblo_adap_fe.h create mode 100644 mcast/dvbloop/dvblo_char.h create mode 100644 mcast/dvbloop/dvblo_ioctl.h create mode 100644 mcast/dvbloop/dvblo_util.h create mode 100644 mcast/tool/.svn/entries create mode 100644 mcast/tool/.svn/prop-base/mcast.c.svn-base create mode 100644 mcast/tool/.svn/prop-base/tools.c.svn-base create mode 100644 mcast/tool/.svn/text-base/Makefile.svn-base create mode 100644 mcast/tool/.svn/text-base/mcast.c.svn-base create mode 100644 mcast/tool/.svn/text-base/netcvdiag.c.svn-base create mode 100644 mcast/tool/.svn/text-base/netcvlogview.c.svn-base create mode 100644 mcast/tool/.svn/text-base/netcvupdate.c.svn-base create mode 100644 mcast/tool/.svn/text-base/tools.c.svn-base create mode 100644 mcast/tool/Makefile create mode 120000 mcast/tool/mcast.c create mode 100644 mcast/tool/netcvdiag.c create mode 100644 mcast/tool/netcvlogview.c create mode 100644 mcast/tool/netcvupdate.c create mode 120000 mcast/tool/tools.c create mode 100644 mcli-i18n.diff create mode 100644 mcli.c create mode 100644 mcli.h create mode 100644 mcli_service.h create mode 100644 mcliheaders.h create mode 100644 packetbuffer.c create mode 100644 packetbuffer.h create mode 100644 patches/.svn/entries create mode 100644 patches/.svn/text-base/reelvdr-device-handling-patch.diff.svn-base create mode 100644 patches/.svn/text-base/vdr-1.4.0-closefilter.patch.svn-base create mode 100644 patches/.svn/text-base/vdr-1.6-device-consistent-destruct.patch.svn-base create mode 100644 patches/.svn/text-base/vdr-1.6-section-read-abstraction.patch.svn-base create mode 100644 patches/.svn/text-base/vdr-1.6.0-altmenuaction.patch.svn-base create mode 100644 patches/.svn/text-base/vdr-1.6.0-intcamdevices.patch.svn-base create mode 100644 patches/reelvdr-device-handling-patch.diff create mode 100644 patches/vdr-1.4.0-closefilter.patch create mode 100644 patches/vdr-1.6-device-consistent-destruct.patch create mode 100644 patches/vdr-1.6-section-read-abstraction.patch create mode 100644 patches/vdr-1.6.0-altmenuaction.patch create mode 100644 patches/vdr-1.6.0-intcamdevices.patch create mode 100644 po/.svn/entries create mode 100644 po/.svn/text-base/de_DE.po.svn-base create mode 100644 po/.svn/text-base/nl_NL.po.svn-base create mode 100644 po/de_DE.po create mode 100644 po/nl_NL.po create mode 100644 wait4ncv.diff diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..f90922e --- /dev/null +++ b/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/HISTORY b/HISTORY new file mode 100644 index 0000000..c16981a --- /dev/null +++ b/HISTORY @@ -0,0 +1,10 @@ +VDR Plugin 'mcli' Revision History +---------------------------------- + +2008-12-18: Version 0.0.1 + +- Initial revision. + +2010-06-23: + +- Moved the mcli-library to LGPL-2.1-license. \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..103e0c3 --- /dev/null +++ b/Makefile @@ -0,0 +1,168 @@ +# +# Makefile for a Video Disk Recorder plugin +# + +# The official name of this plugin. +# This name will be used in the '-P...' option of VDR to load the plugin. +# By default the main source file also carries this name. +# IMPORTANT: the presence of this macro is important for the Make.config +# file. So it must be defined, even if it is not used here! +# +#MCLI_SHARED=1 +PLUGIN = mcli +APPLE_DARWIN = $(shell gcc -dumpmachine | grep -q 'apple-darwin' && echo "1" || echo "0") + +### The version number of this plugin (taken from the main source file): + +VERSION = $(shell grep 'static const char \*VERSION *=' $(PLUGIN).c | awk '{ print $$6 }' | sed -e 's/[";]//g') + +### The C++ compiler and options: + +CXX ?= g++ +ifeq ($(APPLE_DARWIN), 1) +CXXFLAGS ?= -fPIC -pg -O2 -Wall -Woverloaded-virtual -Wno-parentheses -fno-common -bundle -flat_namespace -undefined suppress +else +CXXFLAGS ?= -fPIC -pg -O2 -Wall -Woverloaded-virtual -Wno-parentheses +endif + +### The directory environment: + +VDRDIR = ../../.. +LIBDIR = ../../lib +TMPDIR = /tmp + +### Make sure that necessary options are included: + +-include $(VDRDIR)/Make.global + +### Allow user defined options to overwrite defaults: + +-include $(VDRDIR)/Make.config + +### The version number of VDR's plugin API (taken from VDR's "config.h"): + +APIVERSION = $(shell sed -ne '/define APIVERSION/s/^.*"\(.*\)".*$$/\1/p' $(VDRDIR)/config.h) + +### The name of the distribution archive: + +ARCHIVE = $(PLUGIN)-$(VERSION) +PACKAGE = vdr-$(ARCHIVE) + +### Includes and Defines (add further entries here): + +ifdef RBMINI + XML_INC := -I/usr/arm-linux-gnueabi/include/libxml2 + XML_LIB := -lxml2 +else + XML_INC := `xml2-config --cflags` + XML_LIB := `xml2-config --libs` +endif + + +ifdef MCLI_SHARED + LIBS = -lmcli -Lmcast/client $(XML_LIB) +else + LIBS = mcast/client/libmcli.a $(XML_LIB) +endif + +INCLUDES += -I$(VDRDIR)/include -I. $(XML_INC) + + +ifeq ($(APPLE_DARWIN), 1) +INCLUDES += -I/sw/include -Imcast/common/darwin/include/ +DEFINES += -DAPPLE +ifdef MCLI_SHARED +DEFINES += -Imcast/common/darwin/include/ +endif +endif + +ifdef REELVDR + DEFINES += -DREELVDR +endif + +DEFINES += -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"' +# -DDEVICE_ATTRIBUTES + +### The object files (add further files here): + +OBJS = $(PLUGIN).o cam_menu.o device.o filter.o packetbuffer.o + +### The main target: + +plug: libmcli.so libvdr-$(PLUGIN).so + +all: libmcli.so libvdr-$(PLUGIN).so i18n + +libmcli.so: + $(MAKE) -C mcast/client/ + + +### Implicit rules: + +%.o: %.c + $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $< + +### Dependencies: + +MAKEDEP = $(CXX) -MM -MG +DEPFILE = .dependencies +$(DEPFILE): Makefile + @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@ + +-include $(DEPFILE) + +### Internationalization (I18N): + +PODIR = po +LOCALEDIR = $(VDRDIR)/locale +I18Npo = $(wildcard $(PODIR)/*.po) +I18Nmsgs = $(addprefix $(LOCALEDIR)/, $(addsuffix /LC_MESSAGES/vdr-$(PLUGIN).mo, $(notdir $(foreach file, $(I18Npo), $(basename $(file)))))) +I18Npot = $(PODIR)/$(PLUGIN).pot + +%.mo: %.po + msgfmt -c -o $@ $< + +$(I18Npot): $(wildcard *.c) + xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --msgid-bugs-address='' -o $@ $^ + +%.po: $(I18Npot) + msgmerge -U --no-wrap --no-location --backup=none -q $@ $< + @touch $@ + +$(I18Nmsgs): $(LOCALEDIR)/%/LC_MESSAGES/vdr-$(PLUGIN).mo: $(PODIR)/%.mo + @mkdir -p $(dir $@) + cp $< $@ + +.PHONY: i18n +i18n: $(I18Nmsgs) $(I18Npot) + +i18n-dist: $(I18Nmsgs) + +### Targets: + +libvdr-$(PLUGIN).so: $(OBJS) +ifeq ($(APPLE_DARWIN), 1) + $(CXX) $(CXXFLAGS) $(OBJS) $(LIBS) -o $@ + @cp $@ $(LIBDIR)/$@.$(APIVERSION) +else + $(CXX) $(CXXFLAGS) -shared $(OBJS) $(LIBS) -o $@ + @cp --remove-destination $@ $(LIBDIR)/$@.$(APIVERSION) +endif + +install: +ifdef MCLI_SHARED + install -m 755 -D mcast/client/libmcli.so /usr/lib +endif + install -m 755 -D libvdr-$(PLUGIN).so $(PLUGINLIBDIR)/libvdr-$(PLUGIN).so.$(APIVERSION) + + +dist: clean + @-rm -rf $(TMPDIR)/$(ARCHIVE) + @mkdir $(TMPDIR)/$(ARCHIVE) + @cp -a * $(TMPDIR)/$(ARCHIVE) + @tar czf $(PACKAGE).tgz -C $(TMPDIR) $(ARCHIVE) + @-rm -rf $(TMPDIR)/$(ARCHIVE) + @echo Distribution package created as $(PACKAGE).tgz + +clean: + @-rm -f $(OBJS) $(DEPFILE) *.so *.tgz core* *~ $(PODIR)/*.mo $(PODIR)/*.pot $(LIBDIR)/libvdr-$(PLUGIN).so.* mcast/client/*.o mcast/client/*.so mcast/client/*.a diff --git a/README b/README new file mode 100644 index 0000000..b9a3800 --- /dev/null +++ b/README @@ -0,0 +1,60 @@ +This is a "plugin" for the Video Disk Recorder (VDR) to access DVB-streams +produced by the NetCeiver-hardware. + +Project's homepage: +http://www.baycom.de/wiki/index.php/Products::netceiver + +Latest version available via SVN at: +https://svn.baycom.de/repos/vdr-mcli-plugin/ + +The vdr-plugin, mcli-library and associated tools&drivers +except netcv2dvbip are +Copyright (C) 2007-2010 by BayCom GmbH + +netcv2dvbip is +Copyright (C) 2010 by Christian Cier-Zniewski + +------------------------------------------------------------------ + +The mcli-library (libmcli.so) is covered by the +GNU LESSER GENERAL PUBLIC LICENSE (LGPL), version 2.1: + +This library is free software; you can redistribute it and/or modify it +under the terms of the GNU Lesser General Public License version 2.1 as +published by the Free Software Foundation. + +This library is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +------------------------------------------------------------------ + +The vdr-plugin and associated tools are covered by the +GNU GENERAL PUBLIC LICENSE (GPL), version 2: + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License version 2 as published by +the Free Software Foundation. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +more details. + +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 51 +Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +To properly integrate the mcli plugin into your VDR please apply these two +patches: + +vdr-1.6.0-altmenuaction.patch (allows CAM messages to be displayed) +vdr-1.6.0-intcamdevices.patch (enables selection of encrypted channels + without local CI stack). + \ No newline at end of file diff --git a/cam_menu.c b/cam_menu.c new file mode 100644 index 0000000..8af1eef --- /dev/null +++ b/cam_menu.c @@ -0,0 +1,627 @@ +/*************************************************************************** + * Copyright (C) 2009; Author: Tobias Bratfisch * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * + ***************************************************************************/ + + +#include "cam_menu.h" +#include "filter.h" +#include "device.h" + +#include +#include + +#define TMP_PATH "/tmp" +#define TMP_FILE TMP_PATH"/netceiver.conf" + +class cCamMtd : public cMenuEditIntItem { + friend class cNCUpdate; + public: + cCamMtd(const char *uuid, int slot, const char *info, nc_ca_caps_t flags) : + cMenuEditIntItem((const char *)cString::sprintf(" %s", tr("Multi-Transponder")), &m_flags, 1, 2, trVDR("no"), trVDR("yes")) { + m_oflags = m_flags = flags; + if(uuid) strcpy (m_uuid, uuid); else m_uuid[0]=0; + if(info) strcpy (m_info, info); else m_info[0]=0; + m_slot = slot; + Set(); + }; // cCamMtd + virtual bool MtdModified() { return m_flags != m_oflags; }; + virtual void MtdSaved() { m_oflags = m_flags; } + protected: + char m_uuid[UUID_SIZE]; + int m_slot; + char m_info[MMI_TEXT_LENGTH]; + int m_flags; + int m_oflags; + +}; // cCamMtd + +class cCamInfo : public cOsdItem { + public: + cCamInfo(const char *uuid, int slot, const char *info) { + SetText(cString::sprintf (" %s:\t%s", slot == 0 ? trVDR ("lower slot") : trVDR ("upper slot"), + info ? info[0] ? info : trVDR ("Error") : trVDR ("No CI-Module"))); + if(uuid) strcpy (m_uuid, uuid); else m_uuid[0]=0; + if(info) strcpy (m_info, info); else m_info[0]=0; + m_hascam = (info!=NULL); + m_slot = slot; + }; // cCamInfo + int CamMenuOpen (char *iface) { + isyslog("Opening CAM Menu at NetCeiver %s Slot %d info %s\n", m_uuid, m_slot, m_info); + int mmi_session = 0; + if(m_slot != -1 && strlen(m_info)) { + mmi_session = mmi_open_menu_session (m_uuid, iface, 0, m_slot); + if (mmi_session > 0) { + sleep (1); + const char *c = "00000000000000\n"; + mmi_send_menu_answer (mmi_session, (char *) c, strlen (c)); + } else { + esyslog("Could not open mcli menu session for %s/%d(%s): %d", m_uuid, m_slot, m_info, mmi_session); + mmi_session = -1; + } // if + } // if + return mmi_session; + }; // CamMenuOpen + virtual void CamReset (char *iface) { + if(CanCamReset()) + mmi_cam_reset(m_uuid, iface, 0, m_slot); + }; // CamMenuOpen + virtual bool CanCamReset() { + return (m_slot != -1) && m_hascam; + }; // CanCamReset + virtual bool MtdPossible() { + return MtdPossible(m_info); + }; // MtdPossible + static bool MtdPossible(const char *info) { + if(info && strlen(info)) + if (strncmp(info, "Alpha", 5) == 0 + || strncmp(info, "easy.TV", 7) == 0 + || strncmp(info, "Power", 5) == 0 + ) + return true; + return false; + }; // MtdPossible + protected: + bool m_hascam; + char m_uuid[UUID_SIZE]; + int m_slot; + char m_info[MMI_TEXT_LENGTH]; +}; // cCamInfo + +class cNCUpdate : public cThread { + public: + cNCUpdate(cCamMenu *menu, const char *iface) { + m_menu = menu; + m_iface = iface; + if(m_iface && !strlen(m_iface)) m_iface = NULL; + m_state=1; + Start(); + }; // cNCUpdate + virtual bool Done() { return !m_state; }; + virtual const char *GetStateStr() { + return m_statestr; + }; // GetStateStr + protected: + virtual void Action() { + char uuid[UUID_SIZE]; + while(Running() && m_menu && m_state) { + switch(m_state) { + case 1: { + m_statestr=tr("Updating configuration..."); + m_state = 0; + for(cOsdItem *i=m_menu->First(); i; i=m_menu->Next(i)) { + cCamMtd *m = dynamic_cast(i); + if(m && m->MtdModified()) { + strcpy(uuid, m->m_uuid); + m_state = 2; + break; + } // if + } // for + if(!m_state) m_statestr=tr("Configuration is up to date..."); + break; + } // case 1 + case 2: { + m_statestr = cString::sprintf(tr("Getting configuration from Netceiver %s"), uuid); + cString c = cString::sprintf("rm -f %s; cd %s; netcvupdate -i %s%s%s -D", TMP_FILE, TMP_PATH, uuid, m_iface ? " -d " : "", m_iface ? m_iface : ""); +//isyslog("EXEC1 %s", (const char *)c); + if(SystemExec(c)) { + m_statestr = cString::sprintf(tr("Failed to get configuration from Netceiver %s"), uuid); + m_state = 0; + continue; + } // if + m_state = 3; + break; + } // case 2 + case 3: { + m_statestr = cString::sprintf(tr("Changing configuration for Netceiver %s"), uuid); + xmlDocPtr doc = xmlReadFile(TMP_FILE, NULL, 0); + if(doc == NULL) { + m_statestr = cString::sprintf(tr("Failed to parse configuration from Netceiver %s"), uuid); + m_state = 0; + continue; + } // if + if(!PatchAllCamFlags(doc, uuid)) { + xmlFreeDoc(doc); + m_statestr = cString::sprintf(tr("Failed to set configuration for Netceiver %s"), uuid); + m_state = 0; + continue; + } // if + if(xmlSaveFormatFileEnc(TMP_FILE, doc, "UTF-8", 1)==-1) { + xmlFreeDoc(doc); + m_statestr = cString::sprintf(tr("Failed to save configuration for Netceiver %s"), uuid); + m_state = 0; + continue; + } // if + xmlFreeDoc(doc); + m_state=4; + break; + } // case 3 + case 4: { + m_statestr = cString::sprintf(tr("Saving configuration for Netceiver %s"), uuid); + cString c = cString::sprintf("netcvupdate -i %s%s%s -U %s -K", uuid, m_iface ? " -d " : "", m_iface ? m_iface : "", TMP_FILE); +//isyslog("EXEC2 %s", (const char *)c); + if(SystemExec(c)) { + m_statestr = cString::sprintf(tr("Failed to save configuration for Netceiver %s"), uuid); + m_state = 0; + continue; + } // if + m_state=1; + break; + } // case 4 + } // switch + } // while + m_state = 0; + }; // Action + virtual bool PatchAllCamFlags(xmlDocPtr doc, const char *uuid) { + for(cOsdItem *i=m_menu->First(); i; i=m_menu->Next(i)) { + cCamMtd *m = dynamic_cast(i); + if(m && !strcmp(m->m_uuid, uuid)) { + if(!PatchCamFlags(doc, uuid, itoa(m->m_slot), itoa(m->m_flags))) + return false; + m->MtdSaved(); + } // if + } // for + return true; + }; // PatchAllCamFlags + virtual bool PatchCamFlags(xmlDocPtr doc, const char *uuid, const char *slot, const char *flags) { + bool uuid_match=false; + bool flags_set =false; + xmlNode *node = xmlDocGetRootElement(doc); + node = node ? node->children : NULL; + while(node && xmlStrcmp(node->name, (const xmlChar *)"Description")) + node=node->next; + node = node ? node->children : NULL; + while(node) { + if(node && !xmlStrcmp(node->name, (const xmlChar *)"component")) { + xmlNode *item = node->children; + while(item && xmlStrcmp(item->name, (const xmlChar *)"Description")) { + item = item->next; + } // while + xmlChar *about = item ? xmlGetProp(item, (const xmlChar *)"about") : NULL; + if(about) { + if (!xmlStrcmp(about, (const xmlChar *)"Platform")) { + xmlNode *sub = item->children; + while(sub) { + if(!xmlStrcmp(sub->name, (const xmlChar *)"UUID")) { + xmlChar *value=xmlNodeListGetString(doc, sub->children, 1); + if(value) { + uuid_match=!xmlStrcmp(value, (const xmlChar *)uuid); + xmlFree(value); + } // if + } // if + sub = sub->next; + } // while + } else if(!xmlStrcmp(about, (const xmlChar *)"CAM")) { + xmlNode *sub = item->children; + while(sub) { + if(!xmlStrcmp(sub->name, (const xmlChar *)"Slot")) { + xmlChar *value=xmlNodeListGetString(doc, sub->children, 1); + if(value) { + if (!xmlStrcmp(value, (const xmlChar *)slot)) { + xmlNode *tst = item->children; + while(tst) { + if(!xmlStrcmp(tst->name, (const xmlChar *)"Flags")) { + xmlReplaceNode(tst, xmlNewChild(item, xmlSearchNs(doc, tst, (const xmlChar *)"prf"), (const xmlChar *)"Flags", (const xmlChar *)flags)); + xmlFreeNode(tst); + flags_set=true; + tst = NULL; + continue; + } // if + tst = tst->next; + } // while + } // if + xmlFree(value); + } // if + } // if + sub = sub->next; + } // while + } // if + xmlFree(about); + } // if + } // if + node = node->next; + } // while + return uuid_match && flags_set; + }; // PatchCamFlags + cCamMenu *m_menu; + const char *m_iface; + unsigned int m_state; + cString m_statestr; +}; // cNCUpdate + +cCamMenu::cCamMenu (cmdline_t * cmd) +#if APIVERSNUM < 10700 +: cOsdMenu (trVDR ("Common Interface"), 18) +#else +: cOsdMenu (trVDR ("Common Interface"), 23) +#endif +{ + NCUpdate=NULL; + m_cmd = cmd; + inCamMenu = false; + inMMIBroadcastMenu = false; + inputRequested = eInputNone; + end = false; + currentSelected = -1; + pinCounter = 0; + alreadyReceived = false; + mmi_session = -1; + SetNeedsFastResponse (true); + CamFind (); +} + +cCamMenu::cCamMenu (cmdline_t * cmd, mmi_info_t * mmi_info):cOsdMenu (trVDR ("Common Interface"), 18) +{ + NCUpdate=NULL; + m_cmd = cmd; + inCamMenu = false; + inMMIBroadcastMenu = false; + inputRequested = eInputNone; + end = false; + currentSelected = -1; + pinCounter = 0; + alreadyReceived = false; + mmi_session = -1; + SetNeedsFastResponse (true); + mmi_session = CamMenuOpen (mmi_info); +} + + +cCamMenu::~cCamMenu () +{ + CamMenuClose (mmi_session); +} + +void cCamMenu::OpenCamMenu () +{ + bool timeout = true; + cCamInfo *item = dynamic_cast(Get(currentSelected)); + mmi_session = item ? item->CamMenuOpen (m_cmd->iface) : 0; + char buf2[MMI_TEXT_LENGTH * 2]; + printf ("mmi_session: %d\n", mmi_session); + if (mmi_session > 0) { + Clear (); + Skins.Message(mtWarning, trVDR("Opening CAM menu...")); + inCamMenu = true; + time_t t = time (NULL); + while ((time (NULL) - t) < CAMMENU_TIMEOUT) { + memset(buf2, 0, sizeof(buf2)); + // receive the CAM MENU + if (CamMenuReceive (mmi_session, buf, MMI_TEXT_LENGTH) > 0) { + cCharSetConv conv = cCharSetConv ("ISO-8859-1", "UTF-8"); + conv.Convert (buf, buf2, MMI_TEXT_LENGTH * 2); + char *saveptr = NULL; + char *ret = strtok_r (buf2, "\n", &saveptr); + if (ret) { + Add (new cOsdItem (ret)); + while (ret != NULL) { + ret = strtok_r (NULL, "\n", &saveptr); + if (ret) + Add (new cOsdItem (ret)); + } + } + timeout = false; + break; + } + } + } + if (mmi_session && timeout) { + printf ("%s: Error\n", __PRETTY_FUNCTION__); + Clear (); + Add (new cOsdItem (trVDR ("Error"))); + } + Display (); +} + +void cCamMenu::Receive () +{ + bool timeout = true; + if (mmi_session > 0) { + char buf2[MMI_TEXT_LENGTH * 2]; + time_t t = time (NULL); + while ((time (NULL) - t) < CAMMENU_TIMEOUT) { + memset(buf2, 0, sizeof(buf2)); + // receive the CAM MENU + if (alreadyReceived || CamMenuReceive (mmi_session, buf, MMI_TEXT_LENGTH) > 0) { + Clear (); + alreadyReceived = false; + printf ("MMI: \"%s\"\n", buf); + if (!strncmp (buf, "blind = 0", 9)) + inputRequested = eInputNotBlind; + else if (!strncmp (buf, "blind = 1", 9)) + inputRequested = eInputBlind; + cCharSetConv conv = cCharSetConv ("ISO-8859-1", "UTF-8"); + conv.Convert (inputRequested ? buf + 28 : buf, buf2, MMI_TEXT_LENGTH * 2); + printf ("MMI-UTF8: \"%s\"\n", buf2); + if (!strcmp (buf, "end")) { + /** The Alphacrypt returns "end" when pressing "Back" in it's main menu */ + end = true; + return; + } + char *saveptr = NULL; + char *ret = strtok_r (buf2, "\n", &saveptr); + if (ret) { + Add (new cOsdItem (ret)); + while (ret != NULL) { + ret = strtok_r (NULL, "\n", &saveptr); + if (ret) + Add (new cOsdItem (ret)); + } + } + timeout = false; + break; + } + } + } + if (timeout) { + printf ("%s: mmi_session: %i\n", __PRETTY_FUNCTION__, mmi_session); + Add (new cOsdItem (trVDR ("Error"))); + } + Display (); +} + +int cCamMenu::CamFind () +{ + Clear (); + int n, cnt = 0, i; + netceiver_info_list_t *nc_list = nc_get_list (); + //printf ("Looking for netceivers out there....\n"); + nc_lock_list (); + for (n = 0; n < nc_list->nci_num; n++) { + netceiver_info_t *nci = nc_list->nci + n; + //printf ("\nFound NetCeiver: %s \n", nci->uuid); + char buf[128]; + Add (new cOsdItem ("Netceiver", osUnknown, false)); + snprintf (buf, 128, " %s: %s", "ID", nci->uuid); + Add (new cOsdItem (buf, osUnknown, false)); + Add (new cOsdItem ("", osUnknown, false)); + printf (" CAMS [%d]: \n", nci->cam_num); + int nrAlphaCrypts = 0; + int nrOtherCams = 0; + + for (i = nci->cam_num - 1; i >= 0 /*nci->cam_num */ ; i--) { + if((2==nci->cam[i].status)&&strlen(nci->cam[i].menu_string)) { + if (cCamInfo::MtdPossible(nci->cam[i].menu_string)) + nrAlphaCrypts++; + else + nrOtherCams++; + } // if + } // for + bool mtdImpossible = nrAlphaCrypts > 0 && nrOtherCams > 0; // as in netcvmenu.c + for (i = nci->cam_num - 1; i >= 0 /*nci->cam_num */ ; i--) { + switch (nci->cam[i].status) { + case 2: {//DVBCA_CAMSTATE_READY: + cCamInfo *item = new cCamInfo(nci->uuid, nci->cam[i].slot, nci->cam[i].menu_string); + Add(item); + if(!mtdImpossible && item->MtdPossible()) + Add(new cCamMtd(nci->uuid, nci->cam[i].slot, nci->cam[i].menu_string, nci->cam[i].flags)); + break; + } + case 0: // no cam? + Add(new cCamInfo(nci->uuid, nci->cam[i].slot, NULL)); + break; + default: + Add(new cCamInfo(nci->uuid, nci->cam[i].slot, nci->cam[i].menu_string)); + } + Add (new cOsdItem ("", osUnknown, false)); + cnt++; + } + if (mtdImpossible) { + Add(new cOsdItem(cString::sprintf(" %s", tr("Multi-Transponder-Decryption is")))); + Add(new cOsdItem(cString::sprintf(" %s", tr("impossible because of mixed CAMs")))); + Add (new cOsdItem ("", osUnknown, false)); + } // if + } + nc_unlock_list (); + Display (); + return cnt; +} + +int cCamMenu::CamMenuOpen (mmi_info_t * mmi_info) +{ + //printf ("Opening CAM Menu at NetCeiver %s Slot %d\n", mmi_info->uuid, mmi_info->slot); + + char buf[MMI_TEXT_LENGTH * 2]; + + inMMIBroadcastMenu = true; + inCamMenu = true; + cCharSetConv conv = cCharSetConv ("ISO-8859-1", "UTF-8"); + conv.Convert (mmi_info->mmi_text, buf, MMI_TEXT_LENGTH * 2); + //printf ("MMI-UTF8: \"%s\"\n", buf); + char *saveptr = NULL; + char *ret = strtok_r (buf, "\n", &saveptr); + if (ret) { + Add (new cOsdItem (ret)); + while (ret != NULL) { + ret = strtok_r (NULL, "\n", &saveptr); + if (ret) + Add (new cOsdItem (ret)); + } + } + + int mmi_session = mmi_open_menu_session (mmi_info->uuid, m_cmd->iface, 0, mmi_info->slot); + + //printf ("CamMenuOpen: mmi_session: %i\n", mmi_session); + return mmi_session; +} + +int cCamMenu::CamMenuSend (int mmi_session, const char *c) +{ + return mmi_send_menu_answer (mmi_session, (char *) c, strlen (c)); +} + +int cCamMenu::CamMenuReceive (int mmi_session, char *buf, int bufsize) +{ + return mmi_get_menu_text (mmi_session, buf, bufsize, 50000); +} + +void cCamMenu::CamMenuClose (int mmi_session) +{ + close (mmi_session); +} + +int cCamMenu::CamPollText (mmi_info_t * text) +{ + return mmi_poll_for_menu_text (m_cam_mmi, text, 10); +} + +eOSState cCamMenu::ProcessKey (eKeys Key) +{ + if(NCUpdate) { + if(NCUpdate->Done()) { + SetStatus(""); + Skins.Message(mtWarning, NCUpdate->GetStateStr()); + delete NCUpdate; + NCUpdate=NULL; + return osBack; + } else + SetStatus(NCUpdate->GetStateStr()); + Display(); + return osContinue; + } // if + eOSState ret = cOsdMenu::ProcessKey (Key); + + currentSelected = Current (); + + if (end) { + end = false; + inCamMenu = false; + if (inMMIBroadcastMenu) + return osEnd; + CamMenuClose (mmi_session); + CamFind (); + return osContinue; + } + bool MtdModified=false; + for(cOsdItem *i=First(); i; i=Next(i)){ + cCamMtd *m = dynamic_cast(i); + if(m&&m->MtdModified()) MtdModified=true; + } // for + cCamInfo *info = dynamic_cast(Get(Current())); + SetHelp(MtdModified?tr("Save"):NULL, NULL, (info&&info->CanCamReset()) ? trVDR("Reset") : NULL, NULL); + switch (Key) { +#if 0 + case kUp: + case kDown: + { + unsigned int nrInCamList = currentSelected - ((int) currentSelected / 5) * 3 - 3; // minus the empty rows + if(strlen(cam_list[nrInCamList].info)) + SetHelp(trVDR("Reset"), NULL, NULL, NULL); + else + SetHelp(NULL, NULL, NULL, NULL); + break; + } +#endif + case kRed: { // modify mtd settings + NCUpdate = new cNCUpdate(this, m_cmd->iface); + SetHelp(NULL, NULL, NULL, NULL); + SetStatus(tr("Updating configuration...")); + Display(); + return osContinue; + } + case kYellow: { + cCamInfo *item = dynamic_cast(Get(currentSelected)); + if(item) item->CamReset(m_cmd->iface); + break; + } + case kOk: + SetStatus (""); + pinCounter = 0; // reset pin + if (inCamMenu && inputRequested) { + inputRequested = eInputNone; // input was sent + //printf ("Sending pin: \"%s\"\n", pin); + CamMenuSend (mmi_session, pin); + Receive (); + } else if (inMMIBroadcastMenu) { + //printf ("Sending: \"%s\"\n", Get (Current())->Text()); + CamMenuSend (mmi_session, Get (Current ())->Text ()); + Receive (); + } else if (inCamMenu) { + //printf ("Sending: \"%s\"\n", Get (Current ())->Text ()); + if (strcmp(Get ( Current ())->Text(), trVDR("Error"))) // never send Error... + CamMenuSend (mmi_session, Get (Current ())->Text ()); + Receive (); + } else + OpenCamMenu (); + break; + case kBack: + pinCounter = 0; // reset pin + if (!inCamMenu) + return osBack; + inCamMenu = false; + SetStatus (""); + CamMenuClose (mmi_session); + CamFind (); + return osContinue; + case k0...k9: + if (inputRequested) { + pin[pinCounter++] = 48 + Key - k0; + pin[pinCounter] = '\0'; + printf ("key: %c, pin: \"%s\"\n", 48 + Key - k0, pin); + char buf[16]; + int i; + for (i = 0; i < pinCounter; i++) + (inputRequested == eInputBlind) ? buf[i] = '*' : buf[i] = pin[i]; + buf[i] = '\0'; + SetStatus (buf); + } else { + pinCounter = 0; // reset pin + SetStatus (""); + for (int i = 0; Get (i); i++) { + const char *txt = Get (i)->Text (); + if (txt[0] == 48 + Key - k0 && txt[1] == '.') { + CamMenuSend (mmi_session, txt); + Receive (); + } + } + } + break; + default: + int bla = 0; + if (mmi_session > 0) { + bla = CamMenuReceive (mmi_session, buf, MMI_TEXT_LENGTH); + if (bla > 0) { + alreadyReceived = true; + //printf ("bla: %i\n", bla); + Receive (); + } + } + break; + } + return ret; +} diff --git a/cam_menu.h b/cam_menu.h new file mode 100644 index 0000000..3ee5f51 --- /dev/null +++ b/cam_menu.h @@ -0,0 +1,56 @@ +#ifndef CAM_MENU_H +#define CAM_MENU_H + +#include +#include "filter.h" +#include "device.h" + +#define MAX_CAMS_IN_MENU 16 +#define CAMMENU_TIMEOUT 15 + +typedef struct +{ + int port; + char iface[IFNAMSIZ]; + char cmd_sock_path[_POSIX_PATH_MAX]; + int tuner_type_limit[FE_DVBS2 + 1]; + int mld_start; +} cmdline_t; + +enum eInputRequest +{ eInputNone, eInputBlind, eInputNotBlind }; + +class cNCUpdate; + +class cCamMenu:public cOsdMenu +{ +private: + int CamFind (); + int CamMenuOpen (mmi_info_t * mmi_info); + int CamMenuSend (int fd, const char *c); + int CamMenuReceive (int fd, char *buf, int bufsize); + void CamMenuClose (int fd); + int CamPollText (mmi_info_t * text); + cmdline_t *m_cmd; + UDPContext *m_cam_mmi; + int mmi_session; + bool inCamMenu; + bool inMMIBroadcastMenu; + bool end; + int currentSelected; + eInputRequest inputRequested; + char pin[32]; + int pinCounter; + char buf[MMI_TEXT_LENGTH]; + bool alreadyReceived; + cNCUpdate *NCUpdate;; +public: + cCamMenu (cmdline_t * m_cmd); + cCamMenu (cmdline_t * m_cmd, mmi_info_t * mmi_info); + ~cCamMenu (); + eOSState ProcessKey (eKeys Key); + void OpenCamMenu (); + void Receive (); +}; + +#endif diff --git a/def.h.defs b/def.h.defs new file mode 100644 index 0000000..2e7b9b7 --- /dev/null +++ b/def.h.defs @@ -0,0 +1,73 @@ +#ifndef __DEFS_H__ +#ifdef WIN32 + #ifdef __CYGWIN__ + #else + #ifndef IP_ADAPTER_IPV6_ENABLED + #endif + + #ifndef s6_addr16 + #endif + + #if ! defined _GNU_SOURCE && defined __cplusplus + #else + #endif + + #ifdef LIBRARY + #else + #endif + #endif +#else + #if defined __cplusplus + #else + #endif + + #if ! (defined __uClinux__ || defined APPLE || defined MIPSEL) + #endif + + #ifndef APPLE + #else + #ifndef s6_addr16 + #endif + #endif + + #ifdef APPLE + #endif + + #if defined __uClinux__ + #endif +#endif // WIN32 + +#ifndef __uClinux__ + #if ! (defined WIN32 || defined APPLE) + #endif +// #else +// #endif +#else +#endif // __uClinux__ + +#ifdef DMALLOC +#endif + +#if ! defined GETTID && ! defined WIN32 && ! defined APPLE +#else +#endif + +#ifndef WIN32 + #ifdef SYSLOG + #ifdef DEBUG + #else + #endif + #else + #endif // Syslog +#else // WIN32 + #ifdef DEBUG + #else + #endif //DEBUG +#endif // WIN32 + + #ifndef MICROBLAZE + #endif + #ifdef MICROBLAZE + #else + #endif +#endif //__DEFS_H__ diff --git a/defs2.h b/defs2.h new file mode 100644 index 0000000..bab5cbf --- /dev/null +++ b/defs2.h @@ -0,0 +1,366 @@ +/* + * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de + * + * See the COPYING file for copyright information and + * how to reach the author. + * + */ + +#ifndef __DEFS_H__ +#define __DEFS_H__ + +#ifdef WIN32 +#ifdef __CYGWIN__ +#include +#include +#include +#else +#define _CRT_SECURE_NO_WARNINGS +#define _WIN32_WINNT 0x0502 +#include +#include +#include + +#define _SOTYPE char* +#define IFNAMSIZ 1024 +#define CA_TPDU_MAX 2048 +#define _POSIX_PATH_MAX MAX_PATH +#define usleep(useconds) Sleep((useconds+500)/1000) +#define sleep(seconds) Sleep((seconds)*1000) +#define EAFNOSUPPORT WSAEAFNOSUPPORT +#ifndef IP_ADAPTER_IPV6_ENABLED +#define IP_ADAPTER_IPV6_ENABLED 0x0100 +#endif + +int inet_pton(int af, const char *src, void *dst); +const char *inet_ntop(int af, const void *src, char *dst, size_t size); +int inet_aton(const char *cp, struct in_addr *addr); +int getopt(int nargc, char **nargv, char *ostr); +extern int opterr, optind, optopt, optreset; +extern char *optarg; + +typedef struct +{ + DWORD thread; + HANDLE threadH; /* Win32 thread handle - POSIX thread is invalid if threadH == 0 */ +} ptw32_thread_t; + +typedef unsigned int uint32_t; +typedef uint32_t __u32; +typedef uint32_t u_int32_t; +typedef unsigned short uint16_t; +typedef uint16_t __u16; +typedef uint16_t u_int16_t; +typedef unsigned char uint8_t; +typedef uint8_t __u8; +typedef uint8_t u_int8_t; +#ifndef s6_addr16 +#define s6_addr16 s6_words +#endif +#if ! defined _GNU_SOURCE && defined __cplusplus +#define CALLCONV extern "C" +#else +#define CALLCONV +#endif +#ifdef LIBRARY +#define DLL_SYMBOL CALLCONV __declspec( dllexport ) +#else +#define DLL_SYMBOL CALLCONV __declspec( dllimport ) +#endif + +#define pthread_exist(x) (x).p +#define pthread_null(x) (x).p=NULL +#define _SOTYPE char* +#define INET6 +#define API_WIN +#define LIBXML_STATIC +#define PTW32_STATIC_LIB +#define MULTI_THREAD_RECEIVER +#endif +#else +#if defined __cplusplus +#define CALLCONV extern "C" +#else +#define CALLCONV +#endif +#define DLL_SYMBOL CALLCONV +#define pthread_exist(x) x +#define pthread_null(x) x=0 +#define _SOTYPE void* +#define SOCKET int + +#if ! (defined __uClinux__ || defined APPLE || defined MIPSEL) +#include +#include +#endif +#include +#include +#include +#include +#include +#include +#include + +#include +#ifndef APPLE +#include +#include +#include +#else +typedef unsigned int uint32_t; +typedef uint32_t __u32; +typedef uint32_t u_int32_t; +typedef unsigned short uint16_t; +typedef uint16_t __u16; +typedef uint16_t u_int16_t; +typedef unsigned char uint8_t; +typedef uint8_t __u8; +typedef uint8_t u_int8_t; + +#define CA_TPDU_MAX 2048 + +#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP +#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP +#ifndef s6_addr16 +#define s6_addr16 __u6_addr.__u6_addr16 +#endif +#endif + +#include + +#include +#ifdef APPLE +#include +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include /* for iovec{} and readv/writev */ +#include /* for Unix domain sockets */ +#include +#include + +#if defined __uClinux__ +#include +#endif +#define closesocket close +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +//---------------------------------------------------------------------- +#ifndef __uClinux__ + //DVBAPI +#include +#include +#if ! (defined WIN32 || defined APPLE) +#include +#endif +// #else +// #endif + +#define dvb_ioctl ioctl +#define dvb_close close +#else +#include +#include +#endif // __uClinux__ + +#define CA_TPDU_MAX 2048 + +typedef struct recv_sec +{ + struct dvb_diseqc_master_cmd diseqc_cmd; + fe_sec_mini_cmd_t mini_cmd; + fe_sec_tone_mode_t tone_mode; + fe_sec_voltage_t voltage; +} recv_sec_t; + +#define CA_MAX_SLOTS 16 +typedef struct +{ + ca_caps_t cap; + ca_slot_info_t info[CA_MAX_SLOTS]; +} recv_cacaps_t; + +typedef struct recv_festatus +{ + fe_status_t st; + uint32_t ber; + uint16_t strength; + uint16_t snr; + uint32_t ucblocks; +} recv_festatus_t; + +//XML +#include +#include +#include +#include +#include + +#ifdef DMALLOC +#include +#endif + +#if ! defined GETTID && ! defined WIN32 && ! defined APPLE +#include +#define gettid() syscall (__NR_gettid) +#else +#define gettid pthread_self +#endif + +#define UUID_SIZE 256 + + +#ifndef WIN32 + +#ifdef SYSLOG +extern char *_logstr; +extern pthread_mutex_t _loglock; + +#ifdef DEBUG +#define dbg(format, arg...) { pthread_mutex_lock (&_loglock); sprintf(_logstr, "%s:%d " format , __FILE__ , __LINE__ , ## arg); syslog_write(_logstr); pthread_mutex_unlock (&_loglock);} +#else +#define dbg(format, arg...) do {} while (0) +#endif + +#define err(format, arg...) {pthread_mutex_lock (&_loglock); sprintf(_logstr, "err:%s:%d: %s (%d): " format , __FILE__ , __LINE__ ,strerror(errno), errno, ## arg); fprintf(stdout, "%s", _logstr); syslog_write(_logstr);abort(); pthread_mutex_unlock (&_loglock);} +#define info(format, arg...){pthread_mutex_lock (&_loglock); sprintf(_logstr, format ,## arg); fprintf(stdout, "%s", _logstr); syslog_write(_logstr); pthread_mutex_unlock (&_loglock);} +#define warn(format, arg...){pthread_mutex_lock (&_loglock); sprintf(_logstr, format ,## arg); fprintf(stdout, "%s", _logstr); syslog_write(_logstr); pthread_mutex_unlock (&_loglock);} +#define sys(format, arg...){pthread_mutex_lock (&_loglock); sprintf(_logstr, format ,## arg); syslog_write(_logstr); pthread_mutex_unlock (&_loglock);} +#elif defined DEBUG +#define dbg(format, arg...) {printf("%s:%d " format , __FILE__ , __LINE__ , ## arg)} +#define err(format, arg...) {fprintf(stderr,"err:%s:%d: %s (%d): " format , __FILE__ , __LINE__ ,strerror(errno), errno, ## arg);print_trace();abort();} +#define info(format, arg...) printf("%s:%d: " format , __FILE__ , __LINE__ ,## arg) +#define warn(format, arg...) fprintf(stderr,"%s:%d: " format , __FILE__ , __LINE__ ,## arg) +#else +#define dbg(format, arg...) do {} while (0) +#define err(format, arg...) {fprintf(stderr,"%s (%d): " format, strerror(errno), errno, ## arg);exit(-1);} +#define info(format, arg...) printf(format , ## arg) +#define warn(format, arg...) fprintf(stderr, format , ## arg) +#define sys(format, arg...) printf(format, ## arg) +#endif // Syslog + +#else // WIN32 +#ifdef DEBUG +static void inline dbg(char *format, ...) +{ + char buffer[1024]; + va_list args; + va_start(args, format); + vsprintf(buffer, format, args); + printf("%s:%d %s", __FILE__, __LINE__, buffer); + va_end(args); +} +static void inline err(char *format, ...) +{ + char buffer[1024]; + va_list args; + va_start(args, format); + vsprintf(buffer, format, args); + fprintf(stderr, "err:%s:%d: %s (%d): %s ", __FILE__, __LINE__, + strerror(errno), errno, buffer); + va_end(args); + abort(); +} +static void inline info(const char *format, ...) +{ + char buffer[1024]; + va_list args; + va_start(args, format); + vsprintf(buffer, format, args); + printf("%s:%d: %s", __FILE__, __LINE__, buffer); + va_end(args); +} +static void inline warn(const char *format, ...) +{ + char buffer[1024]; + va_list args; + va_start(args, format); + vsprintf(buffer, format, args); + fprintf(stderr, "%s:%d: %s", __FILE__, __LINE__, buffer); + va_end(args); +} +#else +static void inline dbg(char *format, ...) +{ +} +static void inline err(char *format, ...) +{ + char buffer[1024]; + va_list args; + va_start(args, format); + vsprintf(buffer, format, args); + fprintf(stderr, "err:%s:%d: %s", strerror(errno), errno, buffer); + va_end(args); + abort(); +} +static void inline info(const char *format, ...) +{ + char buffer[1024]; + va_list args; + va_start(args, format); + vsprintf(buffer, format, args); + puts(buffer); + va_end(args); +} +static void inline warn(const char *format, ...) +{ + char buffer[1024]; + va_list args; + va_start(args, format); + vsprintf(buffer, format, args); + fputs(buffer, stderr); + va_end(args); +} + +#endif //DEBUG +#endif // WIN32 + +#ifndef MICROBLAZE +#define FE_DVBS2 (FE_ATSC+1) +#endif + +// RMM S2 Extension +#define FEC_1_4 10 +#define FEC_1_3 11 +#define FEC_2_5 12 +#define FEC_3_5 13 +#define FEC_9_10 14 +#define QPSK_S2 9 +#define PSK8 10 + +#ifdef MICROBLAZE +#define STATIC +#else +#define STATIC static +#endif +#endif diff --git a/device.c b/device.c new file mode 100644 index 0000000..2acabe0 --- /dev/null +++ b/device.c @@ -0,0 +1,962 @@ +/* + * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de + * + * See the COPYING file for copyright information and + * how to reach the author. + * + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "filter.h" +#include "device.h" +#include "mcli.h" + +#define st_Pos 0x07FF +#define st_Neg 0x0800 + +using namespace std; + +static int handle_ts (unsigned char *buffer, size_t len, void *p) +{ + return p ? ((cMcliDevice *) p)->HandleTsData (buffer, len) : len; +} + +//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +static int handle_ten (tra_t * ten, void *p) +{ + cMcliDevice *m = (cMcliDevice *) p; + if (ten) { +// fprintf (stderr, "Status:%02X, Strength:%04X, SNR:%04X, BER:%04X\n", ten->s.st, ten->s.strength, ten->s.snr, ten->s.ber); + m->SetTenData (ten); + if (ten->s.st & FE_HAS_LOCK) { + m->m_locked.Broadcast (); + } + } else { + tra_t ten; + memset (&ten, 0, sizeof (tra_t)); + m->SetTenData (&ten); +// fprintf (stderr, "Signal lost\n"); + } + return 0; +} + +cMcliDevice::cMcliDevice (void) +{ + m_enable = false; + m_tuned = false; + StartSectionHandler (); +#ifdef USE_VDR_PACKET_BUFFER + m_PB = new cRingBufferLinear(MEGABYTE(4), TS_SIZE, false, "MCLI_TS"); + m_PB->SetTimeouts (0, 100); + delivered = false; +#else + m_PB = new cMyPacketBuffer (10000 * TS_SIZE, 10000); + m_PB->SetTimeouts (0, CLOCKS_PER_SEC * 20 / 1000); +#endif + m_filters = new cMcliFilters (); +// printf ("cMcliDevice: got device number %d\n", CardIndex () + 1); + m_pidsnum = 0; + m_mcpidsnum = 0; + m_filternum = 0; + m_mcli = NULL; + m_fetype = -1; + m_last = 0; + m_showtuning = 0; + m_ca_enable = false; + m_ca_override = false; + memset (m_pids, 0, sizeof (m_pids)); + memset (&m_ten, 0, sizeof (tra_t)); + m_pids[0].pid=-1; + m_disabletimeout = TEMP_DISABLE_TIMEOUT_DEFAULT; + m_tunerref = NULL; + m_camref = NULL; + InitMcli (); +} + +cMcliDevice::~cMcliDevice () +{ + LOCK_THREAD; + StopSectionHandler (); + printf ("Device %d gets destructed\n", CardIndex () + 1); + Cancel (0); + m_locked.Broadcast (); + ExitMcli (); + DELETENULL (m_filters); + DELETENULL (m_PB); +} + +bool cMcliDevice::Ready() { + return m_mcli ? m_mcli->Ready() : false; +} + +void cMcliDevice::SetTenData (tra_t * ten) +{ + if(!ten->lastseen) { + ten->lastseen=m_ten.lastseen; + } + m_ten = *ten; +} + +//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +void cMcliDevice::SetEnable (bool val) +{ + LOCK_THREAD; + m_enable = val; + if (!m_enable) { + recv_stop (m_r); + m_tuned = false; + if(GetCaEnable()) { + SetCaEnable(false); + m_mcli->CAMFree(m_camref); + m_camref = NULL; + } + if(m_tunerref) { + m_mcli->TunerFree(m_tunerref); + m_tunerref = NULL; + m_fetype = -1; + } + } else { + if(m_tunerref == NULL) { +#if VDRVERSNUM < 10702 + bool s2=m_chan.Modulation() == QPSK_S2 || m_chan.Modulation() == PSK8; +#elif VDRVERSNUM < 10714 + bool s2=m_chan.System() == SYS_DVBS2; +#else + cDvbTransponderParameters dtp(m_chan.Parameters()); + bool s2=dtp.System() == SYS_DVBS2; +#endif + bool ret = false; + int pos; + int type; + + TranslateTypePos(type, pos, m_chan.Source()); + if(s2) { + type=FE_DVBS2; + } + ret = m_mcli->TunerAvailable((fe_type_t)type, pos); + if(!ret && type == FE_QPSK) { + type = FE_DVBS2; + ret = m_mcli->TunerAvailable((fe_type_t)type, pos); + } + if(!ret) { + return; + } + m_fetype = type; + + int slot = -1; + if(m_chan.Ca(0)<=0xff) { + slot=m_chan.Ca(0)&0x03; + if(slot) { + slot--; + } + } + + if(m_chan.Ca() && !GetCaEnable() && m_mcli->CAMAvailable(NULL, slot) && (m_camref=m_mcli->CAMAlloc(NULL, slot))) { + SetCaEnable(); + } + + recv_tune (m_r, (fe_type_t)m_fetype, m_pos, &m_sec, &m_fep, m_pids); + m_tuned = true; + } + } +} + +bool cMcliDevice::SetTempDisable (bool now) +{ + if(!now) { + Lock(); + } +//#ifndef REELVDR // they might find it out in some other place + // Check for tuning timeout + if(m_showtuning && Receiving(true) && ((time(NULL)-m_ten.lastseen)>=LASTSEEN_TIMEOUT)) { + Skins.QueueMessage(mtInfo, cString::sprintf(tr("Waiting for a free tuner (%s)"),m_chan.Name())); + m_showtuning = false; + } +//#endif +// printf("Device %d Receiving %d Priority %d\n",CardIndex () + 1, Receiving (true), Priority()); + if(!Receiving (true) && (((time(NULL)-m_last) >= m_disabletimeout)) || now) { + recv_stop (m_r); + m_tuned = false; + if(GetCaEnable()) { + SetCaEnable(false); +#ifdef DEBUG_TUNE + printf("Releasing CAM on %d (%s) (disable, %d)\n",CardIndex()+1, m_chan.Name(), now); +#endif + m_mcli->CAMFree(m_camref); + m_camref = NULL; + } + if(m_tunerref) { +#ifdef DEBUG_TUNE + printf("Releasing tuner on %d (%s)\n",CardIndex()+1, m_chan.Name()); +#endif + m_mcli->TunerFree(m_tunerref, false); + m_tunerref = NULL; + m_fetype = -1; + } + if(!now) { + Unlock(); + } + return true; + } + if(!now) { + Unlock(); + } + return false; +} + +void cMcliDevice::SetFEType (fe_type_t val) +{ + m_fetype = (int)val; +} + +int cMcliDevice::HandleTsData (unsigned char *buffer, size_t len) +{ +#ifdef USE_VDR_PACKET_BUFFER + cMutexLock lock (&m_PB_Lock); +#endif + m_filters->PutTS (buffer, len); +#ifdef GET_TS_PACKETS + unsigned char *ptr = m_PB->PutStart (len); + if (ptr) { + memcpy (ptr, buffer, len); + m_PB->PutEnd (len, 0, 0); + } +#else +#ifdef USE_VDR_PACKET_BUFFER + if(m_PB->Free() < len) { + m_PB->Clear(); + if(Receiving(true)) isyslog("MCLI: HandleTsData buffer overflow [%d] %s", CardIndex()+1, m_chan.Name()); + } + return m_PB->Put(buffer, len); +#else + unsigned int i; + for (i = 0; i < len; i += TS_SIZE) { + unsigned char *ptr = m_PB->PutStart (TS_SIZE); + if (ptr) { + memcpy (ptr, buffer + i, TS_SIZE); + m_PB->PutEnd (TS_SIZE, 0, 0); + } + } +#endif +#endif + return len; +} + + +void cMcliDevice::InitMcli (void) +{ + m_r = recv_add (); + + register_ten_handler (m_r, handle_ten, this); + register_ts_handler (m_r, handle_ts, this); +} + +void cMcliDevice::ExitMcli (void) +{ + register_ten_handler (m_r, NULL, NULL); + register_ts_handler (m_r, NULL, NULL); + recv_del (m_r); + m_r = NULL; +} + +bool cMcliDevice::ProvidesSource (int Source) const +{ + int pos; + int type; + bool ret=false; + + if (!m_enable) { + return false; + } + + TranslateTypePos(type, pos, Source); + + if(m_tunerref) { + ret= (type == m_fetype) || (type == FE_QPSK && m_fetype == FE_DVBS2); + if(ret) { + ret = m_mcli->TunerSatelitePositionLookup(m_tunerref, pos); + } + } + + if(!ret) { + ret = m_mcli->TunerAvailable((fe_type_t)type, pos); + if(!ret && type == FE_QPSK) { + type = FE_DVBS2; + ret = m_mcli->TunerAvailable((fe_type_t)type, pos); + } + } +#ifdef DEBUG_TUNE_EXTRA + printf ("ProvidesSource:%d Type:%d Pos:%d -> %d\n", CardIndex () + 1, type, pos, ret); +#endif + return ret; +} + +bool cMcliDevice::ProvidesTransponder (const cChannel * Channel) const +{ + if (!m_enable) { + return false; + } +#if VDRVERSNUM < 10702 + bool s2=Channel->Modulation() == QPSK_S2 || Channel->Modulation() == PSK8; +#elif VDRVERSNUM < 10714 + bool s2=Channel->System() == SYS_DVBS2; +#else + cDvbTransponderParameters dtp(Channel->Parameters()); + bool s2=dtp.System() == SYS_DVBS2; +#endif + bool ret=ProvidesSource (Channel->Source ()); + if(ret) { + int pos; + int type; + TranslateTypePos(type, pos, Channel->Source()); + if(s2) { + type=FE_DVBS2; + } + if(m_tunerref) { + ret = (m_fetype == type) || (type == FE_QPSK && m_fetype == FE_DVBS2); + } else { + ret = false; + } + if(!ret) { + ret = m_mcli->TunerAvailable((fe_type_t)type, pos); + if(!ret && type == FE_QPSK) { + type = FE_DVBS2; + ret = m_mcli->TunerAvailable((fe_type_t)type, pos); + } + } + } +#ifdef DEBUG_TUNE_EXTRA + printf ("ProvidesTransponder:%d S2:%d %s@%p -> %d\n", CardIndex () + 1, s2, Channel->Name (), this, ret); +#endif + return ret; +} + +bool cMcliDevice::IsTunedToTransponderConst (const cChannel * Channel) const +{ +// printf ("IsTunedToTransponder %s == %s \n", Channel->Name (), m_chan.Name ()); + if (!m_enable || !m_tuned) { + return false; + } + +#if VDRVERSNUM > 10713 + cDvbTransponderParameters m_dtp(m_chan.Parameters()); + cDvbTransponderParameters dtp(Channel->Parameters()); +#endif + + if (m_ten.s.st & FE_HAS_LOCK && m_chan.Source() == Channel->Source() && + m_chan.Transponder() == Channel->Transponder() && m_chan.Frequency() == Channel->Frequency() && +#if VDRVERSNUM > 10713 + m_dtp.Modulation() == dtp.Modulation() && +#else + m_chan.Modulation() == Channel->Modulation() && +#endif + m_chan.Srate() == Channel->Srate()) { +// printf ("Yes!!!"); + return true; + } +// printf ("Nope!!!"); + return false; +} + +bool cMcliDevice::IsTunedToTransponder (const cChannel * Channel) +{ + return IsTunedToTransponderConst(Channel); +} + +bool cMcliDevice::CheckCAM(const cChannel * Channel, bool steal) const +{ + if(GetCaOverride() || !Channel->Ca()) { + return true; + } + int slot = -1; + if(Channel->Ca(0)<=0xff) { + slot=Channel->Ca(0)&0x03; + if(slot) { + slot--; + } + } + if(m_camref && (m_camref->slot == slot || slot == -1)) { + return true; + } + if(!m_mcli->CAMAvailable(NULL, slot) && !m_mcli->CAMSteal(NULL, slot, steal)) { + return false; + } + return true; +} + +bool cMcliDevice::ProvidesChannel (const cChannel * Channel, int Priority, bool * NeedsDetachReceivers) const +{ + bool result = false; + bool hasPriority = Priority < 0 || Priority > this->Priority (); + bool needsDetachReceivers = false; + if (!m_enable) { + return false; + } + if(!CheckCAM(Channel, false)) { +#ifdef DEBUG_TUNE + printf ("ProvidesChannel:%d Channel:%s, Prio:%d this->Prio:%d m_chan.Name:%s -> %d\n", CardIndex () + 1, Channel->Name (), Priority, this->Priority (), m_chan.Name(), false); +#endif + return false; + } + if(ProvidesTransponder(Channel)) { + result = hasPriority; + if (Priority >= 0 && Receiving (true)) + { + if (!IsTunedToTransponderConst(Channel)) { + needsDetachReceivers = true; + } else { + result = true; + } + } + } +#ifdef DEBUG_TUNE + printf ("ProvidesChannel:%d Channel:%s, Prio:%d this->Prio:%d m_chan.Name:%s NeedsDetachReceivers:%d -> %d\n", CardIndex () + 1, Channel->Name (), Priority, this->Priority (), m_chan.Name(), needsDetachReceivers, result); +#endif + if (NeedsDetachReceivers) { + *NeedsDetachReceivers = needsDetachReceivers; + } + return result; +} + +void cMcliDevice::TranslateTypePos(int &type, int &pos, const int Source) const +{ +#if VDRVERSNUM < 10713 + pos = Source; + pos = ((pos & st_Neg) ? 1 : -1) * (pos & st_Pos); +#else + int n = (Source & 0xffff); + + if (n > 0x00007FFF) { + n |= 0xFFFF0000; + } + + pos=abs(n); + + if (n > 0 ){ + pos = -pos; + } +#endif + if (pos) { + pos += 1800; + } else { + pos = NO_SAT_POS; + } + + type = Source & cSource::st_Mask; + switch(type) { + case cSource::stCable: + type = FE_QAM; + break; + case cSource::stSat: + type = FE_QPSK; + break; + case cSource::stTerr: + type = FE_OFDM; + break; + default: + type = -1; + } +} + +bool cMcliDevice::SetChannelDevice (const cChannel * Channel, bool LiveView) +{ + bool is_scan = false; + int pos; + int type; + bool s2; + + is_scan = !strlen(Channel->Name()) && !strlen(Channel->Provider()); + +#ifdef DEBUG_TUNE + printf ("SetChannelDevice:%d Channel(%p):%s, Provider:%s, Source:%d, LiveView:%s, IsScan:%d, m_chan.Name:%s\n", CardIndex () + 1, Channel, Channel->Name (), Channel->Provider (), Channel->Source (), LiveView ? "true" : "false", is_scan, m_chan.Name()); +#endif + if (!m_enable) { + return false; + } + LOCK_THREAD; + + if(is_scan) { + m_disabletimeout = TEMP_DISABLE_TIMEOUT_SCAN; + } else if (GetCaOverride()) { + m_disabletimeout = TEMP_DISABLE_TIMEOUT_CAOVERRIDE; + } else { + m_disabletimeout = TEMP_DISABLE_TIMEOUT_DEFAULT; + } + bool cam_force=!EITScanner.UsesDevice(this); + if(cam_force && !CheckCAM(Channel, true)) { +#ifdef DEBUG_TUNE + printf("No CAM on %d available even after tried to steal one\n", CardIndex () + 1); +#endif + return false; + } + + if(!GetCaOverride() && Channel->Ca() && !GetCaEnable()) { + int slot = -1; + if(Channel->Ca(0)<=0xff) { + slot=Channel->Ca(0)&0x03; + if(slot) { + slot--; + } + } + if(!(m_camref=m_mcli->CAMAlloc(NULL, slot))) { +#ifdef DEBUG_TUNE + printf("failed to get CAM on %d\n",CardIndex () + 1); +#endif + if(cam_force) { + return false; + } + } + if(m_camref) { + SetCaEnable(); + } + } + TranslateTypePos(type, pos, Channel->Source()); +#if VDRVERSNUM < 10702 + s2=Channel->Modulation() == QPSK_S2 || Channel->Modulation() == PSK8; +#elif VDRVERSNUM < 10714 + s2=Channel->System() == SYS_DVBS2; +#else + cDvbTransponderParameters dtp(Channel->Parameters()); + s2=dtp.System() == SYS_DVBS2; +#endif + if(s2) { + type = FE_DVBS2; + } + + if(m_tunerref && (FE_QPSK == type) && (FE_DVBS2 == m_fetype)) type = FE_DVBS2; + if(m_tunerref && (m_fetype != type || !m_mcli->TunerSatelitePositionLookup(m_tunerref, pos))) { + m_mcli->TunerFree(m_tunerref); + m_tunerref = NULL; + } + + if(s2 && (m_fetype != FE_DVBS2)) { + if(m_tunerref) { + m_mcli->TunerFree(m_tunerref); + m_tunerref = NULL; + } + type=FE_DVBS2; + } + + if(m_tunerref == NULL) { + m_tunerref = m_mcli->TunerAlloc((fe_type_t)type, pos); + if(m_tunerref == NULL && type == FE_QPSK) { + type = FE_DVBS2; + m_tunerref = m_mcli->TunerAlloc((fe_type_t)type, pos); + } + m_tuned = false; + if(m_tunerref == NULL) { + return false; + } + m_fetype = type; + } + + m_pos = pos; + + if (IsTunedToTransponder (Channel) && !is_scan) { + m_chan = *Channel; + +#ifdef DEBUG_TUNE + printf("Already tuned to transponder on %d\n",CardIndex () + 1); +#endif + return true; + } else { + memset (&m_ten, 0, sizeof (tra_t)); + } + memset (&m_sec, 0, sizeof (recv_sec_t)); + memset (&m_fep, 0, sizeof (struct dvb_frontend_parameters)); + m_chan = *Channel; + +// printf("Really tuning on %d\n",CardIndex () + 1); + switch (m_fetype) { + case FE_DVBS2: + case FE_QPSK:{ // DVB-S + + unsigned int frequency = Channel->Frequency (); + +#if VDRVERSNUM < 10714 + fe_sec_voltage_t volt = (Channel->Polarization () == 'v' || Channel->Polarization () == 'V' || Channel->Polarization () == 'r' || Channel->Polarization () == 'R') ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18; +#else + fe_sec_voltage_t volt = (dtp.Polarization () == 'v' || dtp.Polarization () == 'V' || dtp.Polarization () == 'r' || dtp.Polarization () == 'R') ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18; +#endif + m_sec.voltage = volt; + frequency =::abs (frequency); // Allow for C-band, where the frequency is less than the LOF + m_fep.frequency = frequency * 1000UL; +#if VDRVERSNUM < 10714 + m_fep.inversion = fe_spectral_inversion_t (Channel->Inversion ()); +#else + m_fep.inversion = fe_spectral_inversion_t (dtp.Inversion ()); +#endif + m_fep.u.qpsk.symbol_rate = Channel->Srate () * 1000UL; +#if VDRVERSNUM < 10702 +// m_fep.u.qpsk.fec_inner = fe_code_rate_t (Channel->CoderateH () | (Channel->Modulation () << 16)); + int modulation = Channel->Modulation (); +#if DVB_API_VERSION > 3 + if (modulation==PSK_8) // Needed if PSK_8 != PSK8 + modulation = PSK8; + else if(modulation==PSK_8+4) // patched DVB_V5 QPSK for S2 + modulation = QPSK_S2; +#endif + m_fep.u.qpsk.fec_inner = fe_code_rate_t (Channel->CoderateH () | (modulation << 16)); +#elif VDRVERSNUM < 10714 + if(s2) { + int modulation = 0; + switch(Channel->Modulation ()) { + case QPSK: + modulation = QPSK_S2; + break; + case PSK_8: + modulation = PSK8; + break; + } + m_fep.u.qpsk.fec_inner = fe_code_rate_t (Channel->CoderateH () | (modulation << 16)); + } +#else + if(s2) { + int modulation = 0; + switch(dtp.Modulation ()) { + case QPSK: + modulation = QPSK_S2; + break; + case PSK_8: + modulation = PSK8; + break; + } + int coderateH = dtp.CoderateH (); + switch(dtp.CoderateH()) { + case FEC_AUTO+1: // DVB-API 5 FEC_3_5 + coderateH = FEC_AUTO+4; // MCLI-API FEC_3_5 + break; + case FEC_AUTO+2: // DVB-API 5 FEC_9_10 + coderateH = FEC_AUTO+5; // MCLI-API FEC_9_10 + break; + } + m_fep.u.qpsk.fec_inner = fe_code_rate_t (coderateH | (modulation << 16)); + } +#endif + } + break; + case FE_QAM:{ // DVB-C + + // Frequency and symbol rate: + m_fep.frequency = FrequencyToHz (Channel->Frequency ()); +#if VDRVERSNUM < 10714 + m_fep.inversion = fe_spectral_inversion_t (Channel->Inversion ()); + m_fep.u.qam.fec_inner = fe_code_rate_t (Channel->CoderateH ()); + m_fep.u.qam.modulation = fe_modulation_t (Channel->Modulation ()); +#else + m_fep.inversion = fe_spectral_inversion_t (dtp.Inversion ()); + m_fep.u.qam.fec_inner = fe_code_rate_t (dtp.CoderateH ()); + m_fep.u.qam.modulation = fe_modulation_t (dtp.Modulation ()); +#endif + m_fep.u.qam.symbol_rate = Channel->Srate () * 1000UL; + } + break; + case FE_OFDM:{ // DVB-T + + // Frequency and OFDM paramaters: + m_fep.frequency = FrequencyToHz (Channel->Frequency ()); +#if VDRVERSNUM < 10714 + m_fep.inversion = fe_spectral_inversion_t (Channel->Inversion ()); + m_fep.u.ofdm.bandwidth = fe_bandwidth_t (Channel->Bandwidth ()); + m_fep.u.ofdm.code_rate_HP = fe_code_rate_t (Channel->CoderateH ()); + m_fep.u.ofdm.code_rate_LP = fe_code_rate_t (Channel->CoderateL ()); + m_fep.u.ofdm.constellation = fe_modulation_t (Channel->Modulation ()); + m_fep.u.ofdm.transmission_mode = fe_transmit_mode_t (Channel->Transmission ()); + m_fep.u.ofdm.guard_interval = fe_guard_interval_t (Channel->Guard ()); + m_fep.u.ofdm.hierarchy_information = fe_hierarchy_t (Channel->Hierarchy ()); +#else + m_fep.inversion = fe_spectral_inversion_t (dtp.Inversion ()); + m_fep.u.ofdm.bandwidth = fe_bandwidth_t (dtp.Bandwidth ()); + m_fep.u.ofdm.code_rate_HP = fe_code_rate_t (dtp.CoderateH ()); + m_fep.u.ofdm.code_rate_LP = fe_code_rate_t (dtp.CoderateL ()); + m_fep.u.ofdm.constellation = fe_modulation_t (dtp.Modulation ()); + m_fep.u.ofdm.transmission_mode = fe_transmit_mode_t (dtp.Transmission ()); + m_fep.u.ofdm.guard_interval = fe_guard_interval_t (dtp.Guard ()); + m_fep.u.ofdm.hierarchy_information = fe_hierarchy_t (dtp.Hierarchy ()); +#endif + } + break; + default: + esyslog ("ERROR: attempt to set channel with unknown DVB frontend type"); + return false; + } + + recv_tune (m_r, (fe_type_t)m_fetype, m_pos, &m_sec, &m_fep, m_pids); + m_tuned = true; + if((m_pids[0].pid==-1)) { + dvb_pid_t pi; + memset(&pi, 0, sizeof(dvb_pid_t)); + recv_pid_add (m_r, &pi); +// printf("add dummy pid 0 @ %p\n", this); + } +#ifdef DEBUG_PIDS + printf ("%p SetChannelDevice: Pidsnum:%d m_pidsnum:%d\n", m_r, m_mcpidsnum, m_pidsnum); + for (int i = 0; i < m_mcpidsnum; i++) { + printf ("Pid:%d\n", m_pids[i].pid); + } +#endif + m_ten.lastseen=m_last=time(NULL); + m_showtuning = true; + return true; +} + +bool cMcliDevice::HasLock (int TimeoutMs) +{ +// printf ("HasLock TimeoutMs:%d\n", TimeoutMs); + + if ((m_ten.s.st & FE_HAS_LOCK) || !TimeoutMs) { + return m_ten.s.st & FE_HAS_LOCK; + } + cMutexLock MutexLock (&mutex); + if (TimeoutMs && !(m_ten.s.st & FE_HAS_LOCK)) { + m_locked.TimedWait (mutex, TimeoutMs); + } + if (m_ten.s.st & FE_HAS_LOCK) { + return true; + } + return false; +} + +bool cMcliDevice::SetPid (cPidHandle * Handle, int Type, bool On) +{ +#ifdef DEBUG_TUNE + printf ("SetPid %d Pid:%d (%s), Type:%d, On:%d, used:%d sid:%d ca_enable:%d channel_ca:%d\n", CardIndex () + 1, Handle->pid, m_chan.Name(), Type, On, Handle->used, m_chan.Sid(), GetCaEnable(), m_chan.Ca (0)); +#endif + dvb_pid_t pi; + memset (&pi, 0, sizeof (dvb_pid_t)); + if (!m_enable) { + return false; + } + LOCK_THREAD; + if (Handle->pid && (On || !Handle->used)) { + m_pidsnum += On ? 1 : -1; + if (m_pidsnum < 0) { + m_pidsnum = 0; + } + + if (On) { + pi.pid = Handle->pid; + if (GetCaEnable() && m_chan.Ca (0)) { + pi.id= m_chan.Sid(); + if(m_chan.Ca(0)<=0xff) { + pi.priority=m_chan.Ca(0)&0x03; + } + } +#ifdef ENABLE_DEVICE_PRIORITY + int Prio = Priority(); + if(Prio>50) // Recording prio high + pi.priority |= 3<<2; + else if(Prio > 10) // Recording prio normal + pi.priority |= 2<<2; + else if(Prio >= 0) // Recording prio low + pi.priority |= 1<<2; + else if(Prio == -1) // Live + pi.priority |= 1<<2; +#endif +// printf ("Add Pid:%d Sid:%d Type:%d Prio:%d %d\n", pi.pid, pi.id, Type, pi.priority, m_chan.Ca(0)); + recv_pid_add (m_r, &pi); + } else { +// printf ("Del Pid:%d\n", Handle->pid); + recv_pid_del (m_r, Handle->pid); + } + } + m_mcpidsnum = recv_pids_get (m_r, m_pids); +#ifdef DEBUG_PIDS + printf ("%p SetPid: Pidsnum:%d m_pidsnum:%d m_filternum:%d\n", m_r, m_mcpidsnum, m_pidsnum, m_filternum); + for (int i = 0; i < m_mcpidsnum; i++) { + printf ("Pid:%d\n", m_pids[i].pid); + } +#endif + m_last=time(NULL); + return true; +} + +bool cMcliDevice::OpenDvr (void) +{ +// printf ("OpenDvr\n"); + m_dvr_open = true; + return true; +} + +void cMcliDevice::CloseDvr (void) +{ +// printf ("CloseDvr\n"); + m_dvr_open = false; +} + +#ifdef GET_TS_PACKETS +int cMcliDevice::GetTSPackets (uchar * Data, int count) +{ + if (!m_enable || !m_dvr_open) { + return 0; + } + m_PB->GetEnd (); + + int size; + uchar *buf = m_PB->GetStartMultiple (count, &size, 0, 0); + if (buf) { + memcpy (Data, buf, size); + m_PB->GetEnd (); + return size; + } else { + return 0; + } +} // cMcliDevice::GetTSPackets +#endif + +bool cMcliDevice::GetTSPacket (uchar * &Data) +{ +#ifdef USE_VDR_PACKET_BUFFER + if (!m_enable || !m_dvr_open) return false; + Data = NULL; + int Count = 0; + if(delivered) { + m_PB->Del(TS_SIZE); + delivered=false; + } + uchar *p = m_PB->Get(Count); + if (p && Count >= TS_SIZE) { + if (*p != TS_SYNC_BYTE) { + for (int i = 1; i < Count; i++) { + if (p[i] == TS_SYNC_BYTE) { + Count = i; + break; + } + } + m_PB->Del(Count); + esyslog("cMcliDevice::GetTSPacket: skipped %d bytes to sync on TS packet on device %d", Count, CardIndex()); + return true; + } + delivered = true; + Data = p; + } + return true; +#else + if (m_enable && m_dvr_open) { + m_PB->GetEnd (); + + int size; + Data = m_PB->GetStart (&size, 0, 0); + } + return true; +#endif +} + +int cMcliDevice::OpenFilter (u_short Pid, u_char Tid, u_char Mask) +{ + if (!m_enable) { + return -1; + } + LOCK_THREAD; + m_filternum++; +// printf ("OpenFilter (%d/%d/%d) pid:%d tid:%d mask:%04x %s\n", m_filternum, m_pidsnum, m_mcpidsnum, Pid, Tid, Mask, ((m_filternum+m_pidsnum) < m_mcpidsnum) ? "PROBLEM!!!":""); + dvb_pid_t pi; + memset (&pi, 0, sizeof (dvb_pid_t)); + pi.pid = Pid; +// printf ("Add Pid:%d\n", pi.pid); + recv_pid_add (m_r, &pi); + m_mcpidsnum = recv_pids_get (m_r, m_pids); +#ifdef DEBUG_PIDS + printf ("%p OpenFilter: Pidsnum:%d m_pidsnum:%d\n", m_r, m_mcpidsnum, m_pidsnum); + for (int i = 0; i < m_mcpidsnum; i++) { + printf ("Pid:%d\n", m_pids[i].pid); + } +#endif + return m_filters->OpenFilter (Pid, Tid, Mask); +} + +void cMcliDevice::CloseFilter (int Handle) +{ + if (!m_enable) { + return; + } + + LOCK_THREAD; + int pid = m_filters->CloseFilter (Handle); + + if ( pid != -1) { +// printf("CloseFilter FULL\n"); + recv_pid_del (m_r, pid); + m_mcpidsnum = recv_pids_get (m_r, m_pids); + } + m_filternum--; +// printf ("CloseFilter(%d/%d/%d) pid:%d %s\n", m_filternum, m_pidsnum, m_mcpidsnum, pid, pid==-1?"PID STILL USED":""); +} + +#ifdef DEVICE_ATTRIBUTES +/* Attribute classes for dvbdevice + main main attributes + .name (String) "DVB", "IPTV", ... + + fe : frontend attributes (-> get from tuner) + .type (int) FE_QPSK, ... + .name (string) Tuner name + .status,.snr,... (int) +*/ +int cMcliDevice::GetAttribute (const char *attr_name, uint64_t * val) +{ + int ret = 0; + uint64_t rval = 0; + + if (!strcmp (attr_name, "fe.status")) { + rval = m_ten.s.st; + if ((m_ten.lastseen+LASTSEEN_TIMEOUT)>time(0)) { + rval|= (m_ten.rotor_status&3)<<8; + rval|= (1+m_ten.slot)<<12; + } + } else if (!strcmp (attr_name, "fe.signal")) { + rval = m_ten.s.strength; + } else if (!strcmp (attr_name, "fe.snr")) { + rval = m_ten.s.snr; + } else if (!strcmp (attr_name, "fe.ber")) { + rval = m_ten.s.ber; + } else if (!strcmp (attr_name, "fe.unc")) { + rval = m_ten.s.ucblocks; + } else if (!strcmp (attr_name, "fe.type")) { + rval = m_fetype; + } else if (!strcmp (attr_name, "is.mcli")) { + rval = 1; + } else if (!strcmp (attr_name, "fe.lastseen")) { + rval = m_ten.lastseen; + } else + ret = -1; + + if (val) + *val = rval; + return ret; +} + +int cMcliDevice::GetAttribute (const char *attr_name, char *val, int maxret) +{ + int ret = 0; + if (!strcmp (attr_name, "fe.uuid")) { + strncpy (val, "NetCeiver", maxret); + val[maxret - 1] = 0; + } else if (!strcmp (attr_name, "fe.name")) { + strncpy (val, "NetCeiver", maxret); + val[maxret - 1] = 0; + } else if (!strncmp (attr_name, "main.", 5)) { + if (!strncmp (attr_name + 5, "name", 4)) { + if (val && maxret > 0) { + strncpy (val, "NetCeiver", maxret); + val[maxret - 1] = 0; + } + return 0; + } + } else { + ret = -1; + } + return ret; +} +#endif diff --git a/device.h b/device.h new file mode 100644 index 0000000..a8cb426 --- /dev/null +++ b/device.h @@ -0,0 +1,165 @@ +/* + * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de + * + * See the COPYING file for copyright information and + * how to reach the author. + * + */ + +#ifndef VDR_MCLI_DEVICE_H +#define VDR_MCLI_DEVICE_H + +#include +#include + +#include "packetbuffer.h" + +class cPluginMcli; +struct tuner_pool; +struct cam_pool; + +class cMcliDevice:public cDevice +{ + + private: + int m_pidsnum; + int m_mcpidsnum; + bool m_dvr_open; + recv_info_t *m_r; + recv_sec_t m_sec; + int m_pos; + struct dvb_frontend_parameters m_fep; + dvb_pid_t m_pids[RECV_MAX_PIDS]; + tra_t m_ten; + int m_fetype; + cChannel m_chan; + cMutex mutex; + bool m_enable; + time_t m_last; + int m_filternum; + int m_disabletimeout; + bool m_tuned; + bool m_showtuning; + bool m_ca_enable; + bool m_ca_override; + struct tuner_pool *m_tunerref; + struct cam_pool *m_camref; + + protected: + cPluginMcli *m_mcli; + virtual bool SetChannelDevice (const cChannel * Channel, bool LiveView); + virtual bool HasLock (int TimeoutMs); + virtual bool SetPid (cPidHandle * Handle, int Type, bool On); + virtual bool OpenDvr (void); + virtual void CloseDvr (void); + virtual bool GetTSPacket (uchar * &Data); + + virtual int OpenFilter (u_short Pid, u_char Tid, u_char Mask); + virtual void CloseFilter (int Handle); + virtual bool CheckCAM(const cChannel * Channel, bool steal=false) const; + +#ifdef GET_TS_PACKETS + virtual int GetTSPackets (uchar *, int); +#endif + bool IsTunedToTransponderConst (const cChannel * Channel) const; + void TranslateTypePos(int &type, int &pos, const int Source) const; + + + public: + cCondVar m_locked; +#ifdef USE_VDR_PACKET_BUFFER + cRingBufferLinear *m_PB; + cMutex m_PB_Lock; + bool delivered; +#else + cMyPacketBuffer *m_PB; +#endif + cMcliFilters *m_filters; + cMcliDevice (void); + virtual ~ cMcliDevice (); + virtual bool Ready(); + void SetMcliRef(cPluginMcli *m) + { + m_mcli=m; + } + virtual int NumProvidedSystems(void) const + { + return (m_fetype == FE_DVBS2)?2:1; + } + +#ifdef REELVDR + const cChannel *CurChan () const + { + return &m_chan; + }; +#endif + unsigned int FrequencyToHz (unsigned int f) + { + while (f && f < 1000000) + f *= 1000; + return f; + } + virtual bool HasInternalCam (void) + { + return true; + } + virtual bool ProvidesSource (int Source) const; + virtual bool ProvidesTransponder (const cChannel * Channel) const; + virtual bool ProvidesChannel (const cChannel * Channel, int Priority = -1, bool * NeedsDetachReceivers = NULL) const; + virtual bool IsTunedToTransponder (const cChannel * Channel); + + virtual int HandleTsData (unsigned char *buffer, size_t len); + tra_t *GetTenData (void) { + return &m_ten; + } + void SetTenData (tra_t * ten); + void SetCaEnable (bool val = true) + { + m_ca_enable=val; + } + bool GetCaEnable (void) const + { + return m_ca_enable; + } + struct cam_pool *GetCAMref (void) const + { + return m_camref; + } + void SetCaOverride (bool val = true) + { + m_ca_override=val; + } + bool GetCaOverride (void) const + { + return m_ca_override; + } + void SetEnable (bool val = true); + bool SetTempDisable (bool now = false); + void SetFEType (fe_type_t val); + fe_type_t GetFEType (void) + { + return (fe_type_t)m_fetype; + }; + void InitMcli (void); + void ExitMcli (void); + virtual bool ProvidesS2 () const + { + return m_fetype == FE_DVBS2; + } + virtual bool HasInput (void) const + { + return m_enable; + } +#ifdef DEVICE_ATTRIBUTES + // Reel extension + virtual int GetAttribute (const char *attr_name, uint64_t * val); + virtual int GetAttribute (const char *attr_name, char *val, int maxret); +#endif +#if VDRVERSNUM > 10720 + bool ProvidesEIT(void) const { + return true; + } +#endif +}; + +#endif // VDR_MCLI_DEVICE_H diff --git a/filter.c b/filter.c new file mode 100644 index 0000000..fdcbe7a --- /dev/null +++ b/filter.c @@ -0,0 +1,463 @@ +/* + * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de + * + * See the COPYING file for copyright information and + * how to reach the author. + * + */ + +#include "filter.h" +#include "device.h" + +#include + +#define PID_MASK_HI 0x1F + +class cMcliPid:public cListObject +{ + private: + int m_Pid; + int m_Tid; + + public: + cMcliPid (int Pid, int Tid) + { + m_Pid = Pid; + m_Tid = Tid; + } + ~cMcliPid () + { + } + + int Tid (void) + { + return m_Tid; + } + int Pid (void) + { + return m_Pid; + } + void SetTid (int Tid) + { + m_Tid = Tid; + } +}; + +// --- cMcliFilter ------------------------------------------------------ + +class cMcliFilter:public cListObject +{ + private: + uchar m_Buffer[65536]; + int m_Used; + bool m_closed; + int m_Pipe[2]; + u_short m_Pid; + u_char m_Tid; + u_char m_Mask; + + public: + cMcliFilter (u_short Pid, u_char Tid, u_char Mask); + virtual ~ cMcliFilter (); + + bool Matches (u_short Pid, u_char Tid); + bool PutSection (const uchar * Data, int Length, bool Pusi); + int ReadPipe (void) const + { + return m_Pipe[0]; + } + + bool IsClosed (void); + void Close (void); + void Reset (void); + + u_short Pid (void) const + { + return m_Pid; + } + u_char Tid (void) const + { + return m_Tid; + } + u_char Mask (void) const + { + return m_Mask; + } +}; + +inline bool cMcliFilter::Matches (u_short Pid, u_char Tid) +{ +// printf("Match: %d == %d m_Tid %d == %d %02x\n", m_Pid, Pid, m_Tid, Tid & m_Mask, m_Mask); + return m_Pid == Pid && m_Tid == (Tid & m_Mask); +} + +cMcliFilter::cMcliFilter (u_short Pid, u_char Tid, u_char Mask) +{ + m_Used = 0; + m_Pid = Pid; + m_Tid = Tid; + m_Mask = Mask; + m_Pipe[0] = m_Pipe[1] = -1; + m_closed = false; + +#ifdef SOCK_SEQPACKET + // SOCK_SEQPACKET (since kernel 2.6.4) + if (socketpair (AF_UNIX, SOCK_SEQPACKET, 0, m_Pipe) != 0) { + esyslog ("mcli: socketpair(SOCK_SEQPACKET) failed: %m, trying SOCK_DGRAM"); + } +#endif + if (m_Pipe[0] < 0 && socketpair (AF_UNIX, SOCK_DGRAM, 0, m_Pipe) != 0) { + esyslog ("mcli: couldn't open section filter socket: %m"); + } + + else if (fcntl (m_Pipe[0], F_SETFL, O_NONBLOCK) != 0 || fcntl (m_Pipe[1], F_SETFL, O_NONBLOCK) != 0) { + esyslog ("mcli: couldn't set section filter socket to non-blocking mode: %m"); + } +} + +cMcliFilter::~cMcliFilter () +{ +// printf ("~cMcliFilter %p\n", this); + Close(); +} + + +bool cMcliFilter::PutSection (const uchar * Data, int Length, bool Pusi) +{ + + if (!m_Used && !Pusi) { /* wait for payload unit start indicator */ +// printf("Mittendrin pid %d tid %d mask %02x \n", Pid(), Tid(), Mask()); + return true; + } + if (m_Used && Pusi) { /* reset at payload unit start */ +// int length = (((m_Buffer[1] & 0x0F) << 8) | m_Buffer[2]) + 3; +// printf("RESET expect %d got %d for pid %d tid %d mask %02x \n",length, m_Used, Pid(), Tid(), Mask()); + Reset (); + } + if (m_Used + Length >= (int) sizeof (m_Buffer)) { + esyslog ("ERROR: Mcli: Section handler buffer overflow (%d bytes lost)", Length); + Reset (); + return true; + } + + memcpy (m_Buffer + m_Used, Data, Length); + m_Used += Length; + if (m_Used > 3) { + int length = (((m_Buffer[1] & 0x0F) << 8) | m_Buffer[2]) + 3; +// printf("-> pid %d Tid %d Mask %02x expect %d got %d\n",Pid(), Tid(), Mask(), length, m_Used); + if (m_Used >= length) { +// printf("Section complete\n"); + m_Used = 0; + if (write (m_Pipe[1], m_Buffer, length) < 0) { + if (errno == EAGAIN || errno == EWOULDBLOCK) + //dsyslog ("cMcliFilter::PutSection socket overflow, " "Pid %4d Tid %3d", m_Pid, m_Tid); + ; + else { + m_closed=true; + return false; + } + } + } + + if (m_Used > length) { + dsyslog ("cMcliFilter::PutSection: m_Used > length ! Pid %2d, Tid%2d " "(len %3d, got %d/%d)", m_Pid, m_Tid, Length, m_Used, length); + if (Length < TS_SIZE - 5) { + // TS packet not full -> this must be last TS packet of section data -> safe to reset now + Reset (); + } + } + } + return true; +} + +void cMcliFilter::Reset (void) +{ +#ifdef DEBUG_FILTER + if (m_Used) + dsyslog ("cMcliFilter::Reset skipping %d bytes", m_Used); +#endif + m_Used = 0; +} + +bool cMcliFilter::IsClosed (void) +{ + char m_Buffer[3] = { 0, 0, 0 }; /* tid 0, 0 bytes */ + if(m_closed) { + return m_closed; + } + + // Test if pipe/socket has been closed by writing empty section + if ((write (m_Pipe[1], m_Buffer, 3) < 0 && errno != EAGAIN && errno != EWOULDBLOCK)) { + if (errno != ECONNREFUSED && errno != ECONNRESET && errno != EPIPE) + esyslog ("cMcliFilter::IsClosed failed: %m"); + m_closed = true; + return true; + } + + return false; +} + +void cMcliFilter::Close (void) +{ + if(m_Pipe[0]>=0) { + close (m_Pipe[0]); + m_Pipe[0]=-1; + } + if(m_Pipe[1]>=0) { + close (m_Pipe[1]); + m_Pipe[1]=-1; + } + m_closed=true; +} + +// --- cMcliFilters ----------------------------------------------------- + +cMcliFilters::cMcliFilters (void): +cThread ("mcli: sections assembler") +{ + m_PB = NULL; +} + +cMcliFilters::~cMcliFilters () +{ +} + +int cMcliFilters::PutTS (const uchar * data, int len) +{ + u_short pid = (((u_short) data[1] & PID_MASK_HI) << 8) | data[2]; + if (m_PB && WantPid (pid)) { + int i; + for (i = 0; i < len; i += TS_SIZE) { + unsigned char *ptr = m_PB->PutStart (TS_SIZE); + if (ptr) { + memcpy (ptr, data + i, TS_SIZE); + m_PB->PutEnd (TS_SIZE, 0, 0); + } + } + } + return 0; +} + +int cMcliFilters::CloseFilter (int Handle) +{ +// printf("cMcliFilters::CloseFilter: %d\n", Handle); + GarbageCollect (); + + int pid = GetPid (Handle); + if (pid != -1) { + m_pl.SetPid (pid, -1); + } + cMcliFilter *f=GetFilter(Handle); + if(f) { + LOCK_THREAD; + f->Close(); + Del(f); + } + return pid; +} + +int cMcliFilters::OpenFilter (u_short Pid, u_char Tid, u_char Mask) +{ +// printf("cMcliFilters::OpenFilter: %d %d %02x\n", Pid, Tid, Mask); + GarbageCollect (); + + if (!WantPid (Pid)) { + m_pl.SetPid (Pid, 0xffff); + } + + if (!m_PB) { + m_PB = new cMyPacketBuffer (10000 * TS_SIZE, 10000); + m_PB->SetTimeouts (0, CLOCKS_PER_SEC * 20 / 1000); + } + Start (); + + cMcliFilter *f = new cMcliFilter (Pid, Tid, Mask); + int fh = f->ReadPipe (); + + Lock (); + Add (f); + Unlock (); + + return fh; +} + +int cMcliPidList::GetTidFromPid (int pid) +{ + for (cMcliPid * p = First (); p; p = Next (p)) { + if (p->Pid () == pid) { +// printf("Found pid %d -> tid %d\n",pid, p->Tid()); + return p->Tid (); + } + } + return -1; +} + +void cMcliPidList::SetPid (int Pid, int Tid) +{ + if (Tid >= 0) { + for (cMcliPid * p = First (); p; p = Next (p)) { + if (p->Pid () == Pid) { +// printf("Change pid %d -> tid %d\n", Pid, Tid); + if (Tid != 0xffff) { + p->SetTid (Tid); + } + return; + } + } + cMcliPid *pid = new cMcliPid (Pid, Tid); + Add (pid); +// printf("Add pid %d -> tid %d\n", Pid, Tid); + } else { + for (cMcliPid * p = First (); p; p = Next (p)) { + if (p->Pid () == Pid) { +// printf("Del pid %d\n", Pid); + Del (p); + return; + } + } + } +} + +int cMcliFilters::GetPid (int Handle) +{ + int used = 0; + int pid = -1; + + LOCK_THREAD; + for (cMcliFilter * fi = First (); fi; fi = Next (fi)) { + if (fi->ReadPipe () == Handle) { + pid = fi->Pid (); + break; + } + } + if(pid != -1) { + for (cMcliFilter * fi = First (); fi; fi = Next (fi)) { + if (pid == fi->Pid ()) { + used++; + } + } + } +// printf("Pid %d used %dx\n", pid, used); + if (used==1) { + return pid; + } + return -1; +} + +cMcliFilter *cMcliFilters::GetFilter (int Handle) +{ + LOCK_THREAD; + for (cMcliFilter * fi = First (); fi; fi = Next (fi)) { + if (fi->ReadPipe () == Handle) { + return fi; + } + } + return NULL; +} + +bool cMcliFilters::WantPid (int pid) +{ + LOCK_THREAD; + for (cMcliFilter * fi = First (); fi; fi = Next (fi)) { + if (pid == fi->Pid ()) { + return true; + } + } + return false; +} + +void cMcliFilters::GarbageCollect (void) +{ + LOCK_THREAD; + for (cMcliFilter * fi = First (); fi;) { + if (fi->IsClosed ()) { + if (errno == ECONNREFUSED || errno == ECONNRESET || errno == EPIPE) { +// printf ("cMcliFilters::GarbageCollector: filter closed: Pid %4d, Tid %3d, Mask %2x (%d filters left)\n", (int) fi->Pid (), (int) fi->Tid (), fi->Mask (), Count () - 1); + + cMcliFilter *next = Prev (fi); + Del (fi); + fi = next ? Next (next) : First (); + } else { + esyslog ("cMcliFilters::GarbageCollector() error: " "Pid %4d, Tid %3d, Mask %2x (%d filters left) failed", (int) fi->Pid (), (int) fi->Tid (), fi->Mask (), Count () - 1); + LOG_ERROR; + fi = Next (fi); + } + } else { + fi = Next (fi); + } + } +} + +void cMcliFilters::Action (void) +{ + + while (Running ()) { + m_PB->GetEnd (); + int size; + const uchar *block = m_PB->GetStart (&size, 0, 0); + if (block) { + u_short pid = (((u_short) block[1] & PID_MASK_HI) << 8) | block[2]; + int offset = ((block[3] & 0x20) >> 5) * (block[4] + 1); // offset is the length of the adaption field (see vdr/remux.c). + bool Pusi = (block[1] & 0x40) >> 6; + int len=188-4-offset; //payload len + block=block+4+offset; //point to payload + if ( Pusi ) { + if ( len>(block[0]) ) { //process last section chunk + ProcessChunk(pid,block+1,block[0],0); + len -= block[0]+1; + block += block[0]+1; + } else { + len=0; //error!?! + } + } else { + if ( len>0 ) { //process section chunk + ProcessChunk(pid,block,len,0); + block +=len; + len = 0; + } + } + while ( len>0 ) { //process complete section or initial chunk + int chunklen= ( ( (block[1]<<8) | block[2] ) & 0xFFF ) + 3 ; + if ( chunklen>len ) { + chunklen=len; + } + ProcessChunk(pid,block,chunklen,1); + block +=chunklen; + len -= chunklen; + } + } + } + DELETENULL (m_PB); + dsyslog ("McliFilters::Action() ended"); +} + +void cMcliFilters::ProcessChunk(u_short pid, const uchar *block, int len, bool Pusi) { + int tid = -1; + if (Pusi) { + tid = (int) block[0]; + m_pl.SetPid (pid, tid); + } else { + tid = m_pl.GetTidFromPid (pid); + if (tid == -1) { + //printf("Failed to get tid for pid %d\n", pid); + } + } + //printf("pid:%d tid:%d Pusi: %d len: %d\n", pid, tid, Pusi, len); + LOCK_THREAD; + cMcliFilter *f = First (); + while (f) { + cMcliFilter *next = Next (f); + if (tid != -1 && f->Matches (pid, tid)) { + //printf("Match!!!!"); + if (!f->PutSection (block, len, Pusi)) { + if (errno != ECONNREFUSED && errno != ECONNRESET && errno != EPIPE) { + esyslog ("mcli: couldn't send section packet"); + } + Del (f); + // Filter was closed. + // - need to check remaining filters for another match + } // if + } + f = next; + } +} diff --git a/filter.h b/filter.h new file mode 100644 index 0000000..d42bc18 --- /dev/null +++ b/filter.h @@ -0,0 +1,56 @@ +/* + * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de + * + * See the COPYING file for copyright information and + * how to reach the author. + * + */ + +#ifndef VDR_STREAMDEV_FILTER_H +#define VDR_STREAMDEV_FILTER_H + +#include +#include +#include +#include "packetbuffer.h" + +class cMcliFilter; +class cMcliPid; + +class cMcliPidList:public cList < cMcliPid > +{ + public: + cMcliPidList (void) + { + }; + ~cMcliPidList () { + }; + int GetTidFromPid (int pid); + void SetPid (int Pid, int Tid); +}; + +class cMcliFilters:public cList < cMcliFilter >, public cThread +{ + private: + cMyPacketBuffer * m_PB; + cMcliPidList m_pl; + bool m_closed; + + protected: + virtual void Action (void); + void GarbageCollect (void); + void ProcessChunk(u_short pid, const uchar *block, int len, bool Pusi); + + public: + cMcliFilters (void); + virtual ~ cMcliFilters (); + bool WantPid (int pid); + int GetTidFromPid (int pid); + int GetPid (int Handle); + cMcliFilter *GetFilter (int Handle); + int PutTS (const uchar * data, int len); + int OpenFilter (u_short Pid, u_char Tid, u_char Mask); + int CloseFilter (int Handle); +}; + +#endif // VDR_STREAMDEV_FILTER_H diff --git a/mcast/.svn/entries b/mcast/.svn/entries new file mode 100644 index 0000000..2fee7ce --- /dev/null +++ b/mcast/.svn/entries @@ -0,0 +1,40 @@ +10 + +dir +18963 +svn://reelbox.org/testing/src/vdr-plugins/src/mcli-1/mcast +svn://reelbox.org + + + +2011-08-18T10:09:14.813360Z +17158 +dirk + + + + + + + + + + + + + + +12be777f-adf9-0310-842f-e37ecc4c7426 + +tool +dir + +client +dir + +dvbloop +dir + +common +dir + diff --git a/mcast/client/.indent.pro b/mcast/client/.indent.pro new file mode 100644 index 0000000..2faef85 --- /dev/null +++ b/mcast/client/.indent.pro @@ -0,0 +1 @@ +-i8 -br -l0 -ce -npsl diff --git a/mcast/client/.svn/entries b/mcast/client/.svn/entries new file mode 100644 index 0000000..11f10fe --- /dev/null +++ b/mcast/client/.svn/entries @@ -0,0 +1,1357 @@ +10 + +dir +18963 +svn://reelbox.org/testing/src/vdr-plugins/src/mcli-1/mcast/client +svn://reelbox.org + + + +2011-08-18T10:09:14.813360Z +17158 +dirk + + + + + + + + + + + + + + +12be777f-adf9-0310-842f-e37ecc4c7426 + +dvblo_handler.c +file + + + + +2012-09-27T17:22:49.690848Z +c4b6b1eb8cd3a18164b5e331f0a38e66 +2011-08-18T10:09:14.813360Z +17158 +dirk + + + + + + + + + + + + + + + + + + + + + +20024 + +recv_ccpp.c +file + + + + +2012-09-27T17:22:49.690848Z +5f878ec9ebd38288cfcc82ee5020c35f +2011-07-12T13:36:23.313379Z +16905 +rollercoaster +has-props + + +svn:special + + + + + + + + + + + + + + + + + +21 + +api_server.h +file + + + + +2012-09-27T17:22:49.690848Z +b8b3a949bf3dd399db5549c95421ddcb +2011-07-12T13:36:23.313379Z +16905 +rollercoaster + + + + + + + + + + + + + + + + + + + + + +1357 + +tca_handler.c +file + + + + +2012-09-27T17:22:49.690848Z +2b508aed689369915aa2901edb11ac20 +2011-07-12T13:36:23.313379Z +16905 +rollercoaster + + + + + + + + + + + + + + + + + + + + + +1840 + +satlists.c +file + + + + +2012-09-27T17:22:49.690848Z +d3b50554e8c693cfd4af919fad07fbc0 +2011-08-18T10:09:14.813360Z +17158 +dirk + + + + + + + + + + + + + + + + + + + + + +5049 + +api_test.c +file + + + + +2012-09-27T17:22:49.690848Z +fce170fc6462af495657d8669b043b41 +2011-07-12T13:36:23.313379Z +16905 +rollercoaster + + + + + + + + + + + + + + + + + + + + + +4459 + +dvblo_handler.h +file + + + + +2012-09-27T17:22:49.690848Z +9adb433e99e33b9e2d694ff475b740de +2011-07-12T13:36:23.313379Z +16905 +rollercoaster + + + + + + + + + + + + + + + + + + + + + +743 + +tca_handler.h +file + + + + +2012-09-27T17:22:49.690848Z +3a3b79eee5e1dba852b69f2000a3ccee +2011-07-12T13:36:23.313379Z +16905 +rollercoaster + + + + + + + + + + + + + + + + + + + + + +405 + +mld_client.c +file + + + + +2012-09-27T17:22:49.690848Z +e05bdc7ebc621c510360568867dfdecf +2011-07-12T13:36:23.313379Z +16905 +rollercoaster +has-props + + +svn:special + + + + + + + + + + + + + + + + + +22 + +.indent.pro +file + + + + +2012-09-27T17:22:49.690848Z +536d6397e801893325c24ec292dee74f +2011-07-12T13:36:23.313379Z +16905 +rollercoaster + + + + + + + + + + + + + + + + + + + + + +22 + +mmi_handler.c +file + + + + +2012-09-27T17:22:49.690848Z +f85ea2246efdb5607ee9a20366bfcd51 +2011-08-18T10:09:14.813360Z +17158 +dirk + + + + + + + + + + + + + + + + + + + + + +9851 + +inet_aton.c +file + + + + +2012-09-27T17:22:49.690848Z +48b37f322a2ae164aa3fb4204c83f6a3 +2011-07-12T13:36:23.313379Z +16905 +rollercoaster +has-props + + +svn:special + + + + + + + + + + + + + + + + + +27 + +headers.h +file + + + + +2012-09-27T17:22:49.690848Z +aeaf120e1dfc0892b0c49cdf722c9fef +2011-07-12T13:36:23.313379Z +16905 +rollercoaster + + + + + + + + + + + + + + + + + + + + + +638 + +interfaces.c +file + + + + +2012-09-27T17:22:49.690848Z +bd70360e68db12e0e2fe335bc92ad0e3 +2011-07-12T13:36:23.313379Z +16905 +rollercoaster +has-props + + +svn:special + + + + + + + + + + + + + + + + + +22 + +mmi_handler.h +file + + + + +2012-09-27T17:22:49.690848Z +ed868ea810d05d4fe0ea795cad357faa +2011-07-12T13:36:23.313379Z +16905 +rollercoaster + + + + + + + + + + + + + + + + + + + + + +1225 + +ci_handler.c +file + + + + +2012-09-27T17:22:49.690848Z +d8f14df45e26ee759bb661076b00df2f +2011-08-18T10:09:14.813360Z +17158 +dirk + + + + + + + + + + + + + + + + + + + + + +8218 + +dummy_client.c +file + + + + +2012-09-27T17:22:49.690848Z +c109d8ba8e2dec6b0b5b519c605148f5 +2011-08-18T10:09:14.813360Z +17158 +dirk + + + + + + + + + + + + + + + + + + + + + +2677 + +Makefile +file + + + + +2012-09-27T17:22:49.690848Z +ece098cc6788e85c17ce068287a98921 +2011-07-12T13:36:23.313379Z +16905 +rollercoaster + + + + + + + + + + + + + + + + + + + + + +4977 + +ci_handler.h +file + + + + +2012-09-27T17:22:49.690848Z +fefcc7f7895850402b2326d8801c41c7 +2011-07-12T13:36:23.313379Z +16905 +rollercoaster + + + + + + + + + + + + + + + + + + + + + +859 + +dummy_client.h +file + + + + +2012-09-27T17:22:49.690848Z +1d353edb3158ed94c160c71b499b6591 +2011-07-12T13:36:23.313379Z +16905 +rollercoaster + + + + + + + + + + + + + + + + + + + + + +180 + +mld_reporter.c +file + + + + +2012-09-27T17:22:49.690848Z +e3965ad4570cff659778eec00fbb7e4c +2011-08-18T10:09:14.813360Z +17158 +dirk + + + + + + + + + + + + + + + + + + + + + +6670 + +input.c +file + + + + +2012-09-27T17:22:49.694848Z +d1e761e12f3e1dec2a559289cb35cde8 +2011-08-18T10:09:14.813360Z +17158 +dirk + + + + + + + + + + + + + + + + + + + + + +3730 + +tools.c +file + + + + +2012-09-27T17:22:49.694848Z +c0906e8f658e6d84d4e12dca1e3ffc57 +2011-07-12T13:36:23.313379Z +16905 +rollercoaster +has-props + + +svn:special + + + + + + + + + + + + + + + + + +17 + +mingw +dir + +mld_reporter.h +file + + + + +2012-09-27T17:22:49.694848Z +d2eab4a0ce39c3aa79acf912f5bdf7ae +2011-07-12T13:36:23.313379Z +16905 +rollercoaster + + + + + + + + + + + + + + + + + + + + + +239 + +mcast.c +file + + + + +2012-09-27T17:22:49.694848Z +b6c289caaedfc9f9a24d597c72a5d8ce +2011-07-12T13:36:23.313379Z +16905 +rollercoaster +has-props + + +svn:special + + + + + + + + + + + + + + + + + +17 + +recv_tv.c +file + + + + +2012-09-27T17:22:49.694848Z +e7bafc54679736def7ce798acacea0e7 +2011-08-18T10:09:14.813360Z +17158 +dirk + + + + + + + + + + + + + + + + + + + + + +25663 + +ciparser.c +file + + + + +2012-09-27T17:22:49.694848Z +0cc85089fb87cd0fd0e240e4163510ae +2011-07-12T13:36:23.313379Z +16905 +rollercoaster +has-props + + +svn:special + + + + + + + + + + + + + + + + + +20 + +recv_tv.h +file + + + + +2012-09-27T17:22:49.694848Z +e270bffd77d17ca32d976a57be19ea2c +2011-07-12T13:36:23.313379Z +16905 +rollercoaster + + + + + + + + + + + + + + + + + + + + + +2396 + +api_shm_test.c +file + + + + +2012-09-27T17:22:49.694848Z +3be100d9064c5186f90d3efe17ae5e0a +2011-07-12T13:36:23.313379Z +16905 +rollercoaster +has-props + + +svn:special + + + + + + + + + + + + + + + + + +10 + +win32 +file + + + + +2012-09-27T17:22:49.694848Z +7e2c1fbd0a7ddc76a7a55f662d59e6e3 +2011-07-12T13:36:23.313379Z +16905 +rollercoaster +has-props + + +svn:special + + + + + + + + + + + + + + + + + +15 + +tra_handler.c +file + + + + +2012-09-27T17:22:49.694848Z +720a9b9450e8d072850a8632f9efb3bc +2011-07-12T13:36:23.313379Z +16905 +rollercoaster + + + + + + + + + + + + + + + + + + + + + +1121 + +mld_common.c +file + + + + +2012-09-27T17:22:49.694848Z +d0224283be18ec0774fb34c10667634a +2011-07-12T13:36:23.313379Z +16905 +rollercoaster +has-props + + +svn:special + + + + + + + + + + + + + + + + + +22 + +main.c +file + + + + +2012-09-27T17:22:49.694848Z +f1a5585bbe9a3711ad03bc10cb2def5a +2011-08-18T10:09:14.813360Z +17158 +dirk + + + + + + + + + + + + + + + + + + + + + +1599 + +api_sock_test.c +file + + + + +2012-09-27T17:22:49.694848Z +3be100d9064c5186f90d3efe17ae5e0a +2011-07-12T13:36:23.313379Z +16905 +rollercoaster +has-props + + +svn:special + + + + + + + + + + + + + + + + + +10 + +tra_handler.h +file + + + + +2012-09-27T17:22:49.694848Z +694293ed706ea26dc96111413def41d4 +2011-07-12T13:36:23.313379Z +16905 +rollercoaster + + + + + + + + + + + + + + + + + + + + + +234 + +sock_test.c +file + + + + +2012-09-27T17:22:49.686848Z +7d714bc587133294a02cb2edf0e6a841 +2011-07-12T13:36:23.313379Z +16905 +rollercoaster + + + + + + + + + + + + + + + + + + + + + +2911 + +inet_pton.c +file + + + + +2012-09-27T17:22:49.686848Z +935bd6f5bff2d3724e7e1913bf6f0b81 +2011-07-12T13:36:23.313379Z +16905 +rollercoaster +has-props + + +svn:special + + + + + + + + + + + + + + + + + +27 + +inet_ntop.c +file + + + + +2012-09-27T17:22:49.690848Z +04380ba6685b175467f790aba9963a01 +2011-07-12T13:36:23.313379Z +16905 +rollercoaster +has-props + + +svn:special + + + + + + + + + + + + + + + + + +27 + +api_server.c +file + + + + +2012-09-27T17:22:49.690848Z +853f06ad8aec7ec15e6fda43b1f66a77 +2011-07-12T13:36:23.313379Z +16905 +rollercoaster + + + + + + + + + + + + + + + + + + + + + +10766 + diff --git a/mcast/client/.svn/prop-base/api_shm_test.c.svn-base b/mcast/client/.svn/prop-base/api_shm_test.c.svn-base new file mode 100644 index 0000000..d222469 --- /dev/null +++ b/mcast/client/.svn/prop-base/api_shm_test.c.svn-base @@ -0,0 +1,5 @@ +K 11 +svn:special +V 1 +* +END diff --git a/mcast/client/.svn/prop-base/api_sock_test.c.svn-base b/mcast/client/.svn/prop-base/api_sock_test.c.svn-base new file mode 100644 index 0000000..d222469 --- /dev/null +++ b/mcast/client/.svn/prop-base/api_sock_test.c.svn-base @@ -0,0 +1,5 @@ +K 11 +svn:special +V 1 +* +END diff --git a/mcast/client/.svn/prop-base/ciparser.c.svn-base b/mcast/client/.svn/prop-base/ciparser.c.svn-base new file mode 100644 index 0000000..d222469 --- /dev/null +++ b/mcast/client/.svn/prop-base/ciparser.c.svn-base @@ -0,0 +1,5 @@ +K 11 +svn:special +V 1 +* +END diff --git a/mcast/client/.svn/prop-base/inet_aton.c.svn-base b/mcast/client/.svn/prop-base/inet_aton.c.svn-base new file mode 100644 index 0000000..d222469 --- /dev/null +++ b/mcast/client/.svn/prop-base/inet_aton.c.svn-base @@ -0,0 +1,5 @@ +K 11 +svn:special +V 1 +* +END diff --git a/mcast/client/.svn/prop-base/inet_ntop.c.svn-base b/mcast/client/.svn/prop-base/inet_ntop.c.svn-base new file mode 100644 index 0000000..d222469 --- /dev/null +++ b/mcast/client/.svn/prop-base/inet_ntop.c.svn-base @@ -0,0 +1,5 @@ +K 11 +svn:special +V 1 +* +END diff --git a/mcast/client/.svn/prop-base/inet_pton.c.svn-base b/mcast/client/.svn/prop-base/inet_pton.c.svn-base new file mode 100644 index 0000000..d222469 --- /dev/null +++ b/mcast/client/.svn/prop-base/inet_pton.c.svn-base @@ -0,0 +1,5 @@ +K 11 +svn:special +V 1 +* +END diff --git a/mcast/client/.svn/prop-base/interfaces.c.svn-base b/mcast/client/.svn/prop-base/interfaces.c.svn-base new file mode 100644 index 0000000..d222469 --- /dev/null +++ b/mcast/client/.svn/prop-base/interfaces.c.svn-base @@ -0,0 +1,5 @@ +K 11 +svn:special +V 1 +* +END diff --git a/mcast/client/.svn/prop-base/mcast.c.svn-base b/mcast/client/.svn/prop-base/mcast.c.svn-base new file mode 100644 index 0000000..d222469 --- /dev/null +++ b/mcast/client/.svn/prop-base/mcast.c.svn-base @@ -0,0 +1,5 @@ +K 11 +svn:special +V 1 +* +END diff --git a/mcast/client/.svn/prop-base/mld_client.c.svn-base b/mcast/client/.svn/prop-base/mld_client.c.svn-base new file mode 100644 index 0000000..d222469 --- /dev/null +++ b/mcast/client/.svn/prop-base/mld_client.c.svn-base @@ -0,0 +1,5 @@ +K 11 +svn:special +V 1 +* +END diff --git a/mcast/client/.svn/prop-base/mld_common.c.svn-base b/mcast/client/.svn/prop-base/mld_common.c.svn-base new file mode 100644 index 0000000..d222469 --- /dev/null +++ b/mcast/client/.svn/prop-base/mld_common.c.svn-base @@ -0,0 +1,5 @@ +K 11 +svn:special +V 1 +* +END diff --git a/mcast/client/.svn/prop-base/recv_ccpp.c.svn-base b/mcast/client/.svn/prop-base/recv_ccpp.c.svn-base new file mode 100644 index 0000000..d222469 --- /dev/null +++ b/mcast/client/.svn/prop-base/recv_ccpp.c.svn-base @@ -0,0 +1,5 @@ +K 11 +svn:special +V 1 +* +END diff --git a/mcast/client/.svn/prop-base/tools.c.svn-base b/mcast/client/.svn/prop-base/tools.c.svn-base new file mode 100644 index 0000000..d222469 --- /dev/null +++ b/mcast/client/.svn/prop-base/tools.c.svn-base @@ -0,0 +1,5 @@ +K 11 +svn:special +V 1 +* +END diff --git a/mcast/client/.svn/prop-base/win32.svn-base b/mcast/client/.svn/prop-base/win32.svn-base new file mode 100644 index 0000000..d222469 --- /dev/null +++ b/mcast/client/.svn/prop-base/win32.svn-base @@ -0,0 +1,5 @@ +K 11 +svn:special +V 1 +* +END diff --git a/mcast/client/.svn/text-base/.indent.pro.svn-base b/mcast/client/.svn/text-base/.indent.pro.svn-base new file mode 100644 index 0000000..2faef85 --- /dev/null +++ b/mcast/client/.svn/text-base/.indent.pro.svn-base @@ -0,0 +1 @@ +-i8 -br -l0 -ce -npsl diff --git a/mcast/client/.svn/text-base/Makefile.svn-base b/mcast/client/.svn/text-base/Makefile.svn-base new file mode 100644 index 0000000..1ea0844 --- /dev/null +++ b/mcast/client/.svn/text-base/Makefile.svn-base @@ -0,0 +1,210 @@ +#Comment this out to disable debugging output +#DEBUG=1 +#VERBOSE=1 +#WIN32=1 +#API_SOCK=1 +#VERBOSE=1 +#BACKTRACE=1 + +ifdef RBMINI + ARMEL=1 +endif + +ARCH= $(shell $(CC) -dumpmachine) +APPLE_DARWIN = $(shell echo $(ARCH) | grep -q 'apple-darwin' && echo "1" || echo "0") +CYGWIN = $(shell echo $(ARCH) | grep -q 'cygwin' && echo "1" || echo "0") +MIPSEL = $(shell echo $(ARCH) | grep -q 'mipsel' && echo "1" || echo "0") + +DEFS=-DCLIENT -DLIBRARY -D_REENTRANT -D_GNU_SOURCE + +ifeq ($(CYGWIN), 1) +WIN32=1 +else +API_SOCK=1 +endif + +ifeq ($(APPLE_DARWIN), 1) +DEFS:=$(DEFS) -I../common/darwin/include/ -DAPPLE +APPLE=1 +endif + +VDRDIR=../../../../.. +-include $(VDRDIR)/Make.config + +ifdef ARMEL + XML_INC := -I/usr/arm-linux-gnueabi/include/libxml2 + XML_LIB := -lxml2 + CROSS = arm-linux-gnueabi- +else +ifeq ($(MIPSEL),1) +DEFS:=$(DEFS) -DMIPSEL +XML_INC:=-I../../libxml2/include +XML_LIB:=-L../../libxml2/lib +else +XML_INC:=`xml2-config --cflags` +XML_LIB:=`xml2-config --libs` +LIBRARY_PATH=/usr/lib +endif +endif +ifeq ($(APPLE_DARWIN), 1) +CFLAGS:= $(CFLAGS) -fPIC -fno-common -Wall -I../common $(DEFS) +else +CFLAGS:= $(CFLAGS) -fPIC -Wall -I../common $(DEFS) +endif + +ifdef BACKTRACE +CFLAGS:= $(CFLAGS) -DBACKTRACE -g +endif + +ifdef API_SHM +LDFLAGS:= $(LDFLAGS) -lrt +CFLAGS:= $(CFLAGS) -DAPI_SHM +endif +ifdef API_SOCK +CFLAGS:= $(CFLAGS) -DAPI_SOCK +endif + +ifdef VERBOSE +CFLAGS:= $(CFLAGS) -DDEBUG +DEBUG=1 +endif + +ifdef WIN32 +CFLAGS:= -Iwin32/include $(CFLAGS) -mno-cygwin -fPIC -DWIN32 +LDFLAGS:= -Lwin32/lib $(LDFLAGS) -mno-cygwin +LDLIBS:= -lpthreadGC2 -lxml2 -lz -lws2_32 -liphlpapi +else +CFLAGS:= $(CFLAGS) -I../dvbloop $(XML_INC) +LDFLAGS:=$(LDFLAGS) +LDLIBS:=$(XML_LIB) -lpthread -lz -lm +endif + +ifdef DEBUG +LDFLAGS:= $(LDFLAGS) -g -rdynamic +CFLAGS:= $(CFLAGS) -g -O0 +else +CFLAGS:= $(CFLAGS) -O3 +endif + +MCLI = mcli + +MCLI_OBJS= mld_common.o mld_client.o mld_reporter.o mcast.o recv_tv.o recv_ccpp.o tools.o tca_handler.o tra_handler.o satlists.o interfaces.o api_server.o ciparser.o ci_handler.o mmi_handler.o +ifdef WIN32 +MCLI_OBJS := $(MCLI_OBJS) inet_pton.o inet_ntop.o inet_aton.o +else +MCLI_OBJS := $(MCLI_OBJS) +endif + +MCLI_SOBJS = main.o +ifdef WIN32 +MCLI_SOBJS := $(MCLI_SOBJS) dummy_client.o +else +ifdef APPLE +MCLI_SOBJS := $(MCLI_SOBJS) dummy_client.o input.o +else +MCLI_SOBJS := $(MCLI_SOBJS) dvblo_handler.o input.o +endif +endif + +all: lib$(MCLI) + +static: $(MCLI)-static + + +MAKEDEP = $(CXX) -MM -MG +DEPFILE = .dependencies +$(DEPFILE): Makefile + $(MAKEDEP) $(CFLAGS) $(MCLI_OBJS:%.o=%.c) > $@ + +-include $(DEPFILE) + + +$(MCLI): $(MCLI_OBJS) $(MCLI_SOBJS) + $(CC) $(LDFLAGS) -o $@ $(MCLI_OBJS) $(MCLI_SOBJS) $(LDLIBS) +ifndef DEBUG +ifndef WIN32 + strip $(MCLI) +endif +endif + +lib$(MCLI): $(MCLI_OBJS) +ifdef WIN32 + $(CC) $(LDFLAGS) -shared -o $@.dll $(MCLI_OBJS) $(LDLIBS) -Wl,--out-implib,$@.a -Wl,--output-def,$@.def + lib /def:$@.def /machine:x86 /out:..\\common\\win32\\lib\\$@.lib +# dlltool -k --dllname $@.dll --output-lib win32/lib/$@.lib --def $@.def + cp -a $@.dll win32/lib/ + cp -a $@.a win32/lib/ + cp -a $@.def win32/lib/ +endif +ifdef APPLE + $(CC) $(LDFLAGS) -dynamiclib -o $@.dylib $(MCLI_OBJS) $(LDLIBS) + $(AR) $(ARFLAGS) $@.a $(MCLI_OBJS) +else + $(CC) $(LDFLAGS) -shared -o $@.so $(MCLI_OBJS) $(LDLIBS) + $(AR) $(ARFLAGS) $@.a $(MCLI_OBJS) +endif + + +$(MCLI)-shared: lib$(MCLI) + $(CC) -c $(CFLAGS) -ULIBRARY -o main.o main.c +ifdef WIN32 + $(CC) -c $(CFLAGS) -ULIBRARY -o dummy_client.o dummy_client.c +else +ifdef APPLE + $(CC) -c $(CFLAGS) -ULIBRARY -o input.o input.c + $(CC) -c $(CFLAGS) -ULIBRARY -o dummy_client.o dummy_client.c +else + $(CC) -c $(CFLAGS) -ULIBRARY -o input.o input.c + $(CC) -c $(CFLAGS) -ULIBRARY -o dvblo_handler.o dvblo_handler.c +endif +endif + $(CC) $(LDFLAGS) -o $@ $(MCLI_SOBJS) $(LDLIBS) -L. -lmcli + +$(MCLI)-static: $(MCLI_OBJS) $(MCLI_SOBJS) + $(CC) $(LDFLAGS) -static -static-libgcc -o $@ $(MCLI_OBJS) $(MCLI_SOBJS) $(LDLIBS) $(LIBRARY_PATH)/libxml2.a $(LIBRARY_PATH)/libz.a $(LIBRARY_PATH)/libm.a $(LIBRARY_PATH)/libpthread.a +ifndef DEBUG +ifndef WIN32 + strip $(MCLI)-static +endif +endif + +api_shm_test.o: api_shm_test.c + $(CC) -c $(CFLAGS) -DUSE_SHM_API -o $@ $< + +api_sock_test.o:api_sock_test.c + $(CC) -c $(CFLAGS) -DUSE_SOCK_API -o $@ $< + +$(MCLI)-shmtest: api_shm_test.o + $(CC) $(LDFLAGS) -o $@ api_shm_test.o $(LDLIBS) -lrt + +$(MCLI)-socktest: api_sock_test.o + $(CC) $(LDFLAGS) -o $@ api_sock_test.o + +install: mcli + install -p $< /usr/sbin/$< + +install-lib: libmcli.la + libtool --mode=install install $< /usr/local/lib/ + +install-shared: mcli-shared + libtool --mode=install install $< /usr/local/bin + +depend: .dependencies + #makedepend -Y -- $(CFLAGS) -- *c >/dev/null 2>&1 + +clean: + rm -f $(MCLI) $(MCLI)-* *.elf *.gdb *.o *.lo *.la *~ *.so *.a *.def *.dll *.dylib out.ts + +mingw32: + rm -rf mingw/*.c mingw/*.h mingw/win32 + cp *.c *.h mingw/ + mkdir mingw/win32 + cp -a win32/lib mingw/win32/ + cp -a win32/include mingw/win32/ + @echo "Created mingw directory - now ready to rumble... (call build.cmd)" + +%.o: %.c + $(CC) -c $(CFLAGS) -o $@ $< + +%.lo: %.c + $(CC) -c $(CFLAGS) -o $@ $< diff --git a/mcast/client/.svn/text-base/api_server.c.svn-base b/mcast/client/.svn/text-base/api_server.c.svn-base new file mode 100644 index 0000000..c3d7617 --- /dev/null +++ b/mcast/client/.svn/text-base/api_server.c.svn-base @@ -0,0 +1,397 @@ +/* + * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de + * + * See the COPYING file for copyright information and + * how to reach the author. + * + */ + +#include "headers.h" + +#if defined(API_SOCK) || defined(API_SHM) || defined (API_WIN) + +static int process_cmd (api_cmd_t * api_cmd, tra_info_t * trl, netceiver_info_list_t * nci) +{ + if(api_cmd->magic != MCLI_MAGIC || api_cmd->version != MCLI_VERSION) { + api_cmd->magic = MCLI_MAGIC; + api_cmd->version = MCLI_VERSION; + api_cmd->state = API_RESPONSE; + return 0; + } + if (api_cmd->state != API_REQUEST) { + return 0; + } + + switch (api_cmd->cmd) { + case API_GET_NC_NUM: + api_cmd->parm[API_PARM_NC_NUM] = nci->nci_num; + api_cmd->state = API_RESPONSE; + break; + + case API_GET_NC_INFO: + if (api_cmd->parm[API_PARM_NC_NUM] < nci->nci_num) { + api_cmd->u.nc_info = nci->nci[api_cmd->parm[API_PARM_NC_NUM]]; + api_cmd->state = API_RESPONSE; + } else { + api_cmd->state = API_ERROR; + } + break; + case API_GET_TUNER_INFO: + if (api_cmd->parm[API_PARM_NC_NUM] < nci->nci_num) { + if (api_cmd->parm[API_PARM_TUNER_NUM] < nci->nci[api_cmd->parm[API_PARM_NC_NUM]].tuner_num) { + api_cmd->u.tuner_info = nci->nci[api_cmd->parm[API_PARM_NC_NUM]].tuner[api_cmd->parm[API_PARM_TUNER_NUM]]; + api_cmd->state = API_RESPONSE; + } else { + api_cmd->state = API_ERROR; + } + } else { + api_cmd->state = API_ERROR; + } + break; + case API_GET_SAT_LIST_INFO: + if (api_cmd->parm[API_PARM_NC_NUM] < nci->nci_num) { + if (api_cmd->parm[API_PARM_SAT_LIST_NUM] < nci->nci[api_cmd->parm[API_PARM_NC_NUM]].sat_list_num) { + api_cmd->u.sat_list = nci->nci[api_cmd->parm[API_PARM_NC_NUM]].sat_list[api_cmd->parm[API_PARM_SAT_LIST_NUM]]; + api_cmd->state = API_RESPONSE; + } else { + api_cmd->state = API_ERROR; + } + } else { + api_cmd->state = API_ERROR; + } + break; + case API_GET_SAT_INFO: + if (api_cmd->parm[API_PARM_NC_NUM] < nci->nci_num) { + if (api_cmd->parm[API_PARM_SAT_LIST_NUM] < nci->nci[api_cmd->parm[API_PARM_NC_NUM]].sat_list_num) { + if (api_cmd->parm[API_PARM_SAT_NUM] < nci->nci[api_cmd->parm[API_PARM_NC_NUM]].sat_list[api_cmd->parm[API_PARM_SAT_LIST_NUM]].sat_num) { + api_cmd->u.sat_info = nci->nci[api_cmd->parm[API_PARM_NC_NUM]].sat_list[api_cmd->parm[API_PARM_SAT_LIST_NUM]].sat[api_cmd->parm[API_PARM_SAT_NUM]]; + api_cmd->state = API_RESPONSE; + } else { + api_cmd->state = API_ERROR; + } + } else { + api_cmd->state = API_ERROR; + } + } else { + api_cmd->state = API_ERROR; + } + break; + + case API_GET_SAT_COMP_INFO: + if (api_cmd->parm[API_PARM_NC_NUM] < nci->nci_num) { + if (api_cmd->parm[API_PARM_SAT_LIST_NUM] < nci->nci[api_cmd->parm[API_PARM_NC_NUM]].sat_list_num) { + if (api_cmd->parm[API_PARM_SAT_NUM] < nci->nci[api_cmd->parm[API_PARM_NC_NUM]].sat_list[api_cmd->parm[API_PARM_SAT_LIST_NUM]].sat_num) { + if (api_cmd->parm[API_PARM_SAT_COMP_NUM] < nci->nci[api_cmd->parm[API_PARM_NC_NUM]].sat_list[api_cmd->parm[API_PARM_SAT_LIST_NUM]].sat[api_cmd->parm[API_PARM_SAT_NUM]].comp_num) { + api_cmd->u.sat_comp = nci->nci[api_cmd->parm[API_PARM_NC_NUM]].sat_list[api_cmd->parm[API_PARM_SAT_LIST_NUM]].sat[api_cmd->parm[API_PARM_SAT_NUM]].comp[api_cmd->parm[API_PARM_SAT_COMP_NUM]]; + api_cmd->state = API_RESPONSE; + } else { + api_cmd->state = API_ERROR; + } + } else { + api_cmd->state = API_ERROR; + } + } else { + api_cmd->state = API_ERROR; + } + } else { + api_cmd->state = API_ERROR; + } + break; + case API_GET_TRA_NUM: + api_cmd->parm[API_PARM_TRA_NUM] = trl->tra_num; + api_cmd->state = API_RESPONSE; + break; + case API_GET_TRA_INFO: + if (api_cmd->parm[API_PARM_TRA_NUM] < trl->tra_num) { + api_cmd->u.tra = trl->tra[api_cmd->parm[API_PARM_TRA_NUM]]; + api_cmd->state = API_RESPONSE; + } else { + api_cmd->state = API_ERROR; + } + break; + default: + api_cmd->state = API_ERROR; + } + return 1; +} +#endif +#ifdef API_SOCK +typedef struct +{ + pthread_t thread; + int fd; + struct sockaddr_un addr; + socklen_t len; + int run; +} sock_t; + +static void *sock_cmd_loop (void *p) +{ + sock_t *s = (sock_t *) p; + api_cmd_t sock_cmd; + int n; + netceiver_info_list_t *nc_list=nc_get_list(); + tra_info_t *tra_list=tra_get_list(); + + dbg ("new api client connected\n"); + s->run = 1; + while (s->run){ + n = recv (s->fd, &sock_cmd, sizeof (api_cmd_t), 0); + if (n == sizeof (api_cmd_t)) { + nc_lock_list(); + process_cmd (&sock_cmd, tra_list, nc_list); + nc_unlock_list(); + send (s->fd, &sock_cmd, sizeof (api_cmd_t), 0); + } else { + sock_cmd.magic = MCLI_MAGIC; + sock_cmd.version = MCLI_VERSION; + sock_cmd.state = API_RESPONSE; + send (s->fd, &sock_cmd, sizeof (api_cmd_t), 0); + break; + } + pthread_testcancel(); + } + + close (s->fd); + pthread_detach (s->thread); + free (s); + return NULL; +} + +static void *sock_cmd_listen_loop (void *p) +{ + sock_t tmp; + sock_t *s = (sock_t *) p; + dbg ("sock api listen loop started\n"); + s->run = 1; + + while (s->run) { + tmp.len = sizeof (struct sockaddr_un); + tmp.fd = accept (s->fd, (struct sockaddr*)&tmp.addr, &tmp.len); + if (tmp.fd >= 0) { + sock_t *as = (sock_t *) malloc (sizeof (sock_t)); + if (as == NULL) { + err ("Cannot get memory for socket\n"); + } + *as=tmp; + as->run = 0; + pthread_create (&as->thread, NULL, sock_cmd_loop, as); + } else { + break; + } + pthread_testcancel(); + } + pthread_detach (s->thread); + return NULL; +} + +static sock_t s; +int api_sock_init (const char *cmd_sock_path) +{ + s.addr.sun_family = AF_UNIX; + strcpy (s.addr.sun_path, cmd_sock_path); + s.len = sizeof(struct sockaddr_un); //strlen (cmd_sock_path) + sizeof (s.addr.sun_family); + + if ((s.fd = socket (AF_UNIX, SOCK_STREAM, 0)) < 0) { + warn ("Cannot get socket %d\n", errno); + return -1; + } + unlink (cmd_sock_path); + if (bind (s.fd, (struct sockaddr*)&s.addr, s.len) < 0) { + warn ("Cannot bind control socket\n"); + return -1; + } + if (chmod(cmd_sock_path, S_IRWXU|S_IRWXG|S_IRWXO)) { + warn ("Cannot chmod 777 socket %s\n", cmd_sock_path); + } + if (listen (s.fd, 5) < 0) { + warn ("Cannot listen on socket\n"); + return -1; + } + return pthread_create (&s.thread, NULL, sock_cmd_listen_loop, &s); +} + +void api_sock_exit (void) +{ + //FIXME memory leak on exit in context structres + s.run=0; + close(s.fd); + + if(pthread_exist(s.thread) && !pthread_cancel (s.thread)) { + pthread_join (s.thread, NULL); + } +} +#endif +#ifdef API_SHM +static api_cmd_t *api_cmd = NULL; +static pthread_t api_cmd_loop_thread; + +static void *api_cmd_loop (void *p) +{ + netceiver_info_list_t *nc_list=nc_get_list(); + tra_info_t *tra_list=tra_get_list(); + while (1) { + nc_lock_list(); + process_cmd (api_cmd, tra_list, nc_list); + nc_unlock_list(); + usleep (1); + pthread_testcancel(); + } + + return NULL; +} + +int api_shm_init (void) +{ + int fd = shm_open (API_SHM_NAMESPACE, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + if (fd == -1) { + warn ("Cannot get a shared memory handle\n"); + return -1; + } + if (ftruncate (fd, sizeof (api_cmd_t)) == -1) { + err ("Cannot truncate shared memory\n"); + } + api_cmd = mmap (NULL, sizeof (api_cmd_t), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (api_cmd == MAP_FAILED) { + err ("MMap of shared memory region failed\n"); + } + close (fd); + + memset (api_cmd, 0, sizeof (api_cmd_t)); + + pthread_create (&api_cmd_loop_thread, NULL, api_cmd_loop, NULL); + return 0; +} + +void api_shm_exit (void) +{ + if(pthread_exist(api_cmd_loop_thread) && !pthread_cancel (api_cmd_loop_thread)) { + pthread_join (api_cmd_loop_thread, NULL); + } + shm_unlink (API_SHM_NAMESPACE); +} +#endif +#ifdef API_WIN + +void *api_cmd_loop(void *lpvParam) +{ + netceiver_info_list_t *nc_list=nc_get_list(); + tra_info_t *tra_list=tra_get_list(); + api_cmd_t sock_cmd; + DWORD cbBytesRead, cbWritten; + BOOL fSuccess; + HANDLE hPipe; + + hPipe = (HANDLE) lpvParam; + + while (1) { + fSuccess = ReadFile( + hPipe, // handle to pipe + &sock_cmd, // buffer to receive data + sizeof(sock_cmd), // size of buffer + &cbBytesRead, // number of bytes read + NULL); // not overlapped I/O + + if (! fSuccess || cbBytesRead == 0) { + break; + } + + if (cbBytesRead == sizeof (api_cmd_t)) { + nc_lock_list(); + process_cmd (&sock_cmd, tra_list, nc_list); + nc_unlock_list(); + + fSuccess = WriteFile( + hPipe, // handle to pipe + &sock_cmd, // buffer to write from + sizeof(sock_cmd), // number of bytes to write + &cbWritten, // number of bytes written + NULL); // not overlapped I/O + + if (! fSuccess || sizeof(sock_cmd) != cbWritten) { + break; + } + } else { + sock_cmd.magic = MCLI_MAGIC; + sock_cmd.version = MCLI_VERSION; + sock_cmd.state = API_RESPONSE; + fSuccess = WriteFile( + hPipe, // handle to pipe + &sock_cmd, // buffer to write from + sizeof(sock_cmd), // number of bytes to write + &cbWritten, // number of bytes written + NULL); // not overlapped I/O + + if (! fSuccess || sizeof(sock_cmd) != cbWritten) { + break; + } + break; + } + } + + FlushFileBuffers(hPipe); + DisconnectNamedPipe(hPipe); + CloseHandle(hPipe); + + return NULL; +} + +#define BUFSIZE 2048 +void *api_listen_loop(void *p) +{ + BOOL fConnected; + pthread_t api_cmd_loop_thread; + HANDLE hPipe; + LPTSTR lpszPipename=(LPTSTR)p; + + while(1) { + hPipe = CreateNamedPipe( + lpszPipename, // pipe name + PIPE_ACCESS_DUPLEX, // read/write access + PIPE_TYPE_MESSAGE | // message type pipe + PIPE_READMODE_MESSAGE | // message-read mode + PIPE_WAIT, // blocking mode + PIPE_UNLIMITED_INSTANCES, // max. instances + BUFSIZE, // output buffer size + BUFSIZE, // input buffer size + 0, // client time-out + NULL); // default security attribute + + if (hPipe == INVALID_HANDLE_VALUE) { + err ("CreatePipe failed"); + return NULL; + } + pthread_testcancel(); + fConnected = ConnectNamedPipe(hPipe, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED); + + if (fConnected) { + if(pthread_create(&api_cmd_loop_thread, NULL, api_cmd_loop, hPipe)) { + err ("CreateThread failed"); + return NULL; + } else { + pthread_detach(api_cmd_loop_thread); + } + } + else { + CloseHandle(hPipe); + } + } + return NULL; +} + +pthread_t api_listen_loop_thread; + +int api_init (LPTSTR cmd_pipe_path) +{ + return pthread_create (&api_listen_loop_thread, NULL, api_listen_loop, cmd_pipe_path); +} + +void api_exit (void) +{ + if(pthread_exist(api_listen_loop_thread) && !pthread_cancel (api_listen_loop_thread)) { + TerminateThread(pthread_getw32threadhandle_np(api_listen_loop_thread),0); + pthread_join (api_listen_loop_thread, NULL); + } +} + +#endif diff --git a/mcast/client/.svn/text-base/api_server.h.svn-base b/mcast/client/.svn/text-base/api_server.h.svn-base new file mode 100644 index 0000000..e0f946f --- /dev/null +++ b/mcast/client/.svn/text-base/api_server.h.svn-base @@ -0,0 +1,67 @@ +/* + * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de + * + * See the COPYING file for copyright information and + * how to reach the author. + * + */ + +#define API_SHM_NAMESPACE "/mcli" +#define API_SOCK_NAMESPACE "/var/tmp/mcli.sock" + +typedef enum { API_IDLE, + API_REQUEST, + API_RESPONSE, + API_ERROR +} api_state_t; + +typedef enum { API_GET_NC_NUM, + API_GET_NC_INFO, + API_GET_TUNER_INFO, + API_GET_SAT_LIST_INFO, + API_GET_SAT_INFO, + API_GET_SAT_COMP_INFO, + API_GET_TRA_NUM, + API_GET_TRA_INFO, + API_GET_DEVICE_INFO +} api_cmdval_t; + +typedef enum { API_PARM_NC_NUM=0, + API_PARM_DEVICE_NUM=0, + API_PARM_TUNER_NUM, + API_PARM_SAT_LIST_NUM, + API_PARM_SAT_NUM, + API_PARM_SAT_COMP_NUM, + API_PARM_TRA_NUM, + API_PARM_MAX +} api_parm_t; + +typedef struct { + int magic; + int version; + + api_cmdval_t cmd; + api_state_t state; + int parm[API_PARM_MAX]; + union { + netceiver_info_t nc_info; + tuner_info_t tuner_info; + satellite_list_t sat_list; + satellite_info_t sat_info; + satellite_component_t sat_comp; + tra_t tra; + } u; +} api_cmd_t; + +#ifdef API_SHM +DLL_SYMBOL int api_shm_init (void); +DLL_SYMBOL void api_shm_exit (void); +#endif +#ifdef API_SOCK +DLL_SYMBOL int api_sock_init (const char *cmd_sock_path); +DLL_SYMBOL void api_sock_exit (void); +#endif +#ifdef API_WIN +DLL_SYMBOL int api_init (LPTSTR cmd_pipe_path); +DLL_SYMBOL void api_exit (void); +#endif diff --git a/mcast/client/.svn/text-base/api_shm_test.c.svn-base b/mcast/client/.svn/text-base/api_shm_test.c.svn-base new file mode 100644 index 0000000..fa5a0e7 --- /dev/null +++ b/mcast/client/.svn/text-base/api_shm_test.c.svn-base @@ -0,0 +1 @@ +link api_test.c \ No newline at end of file diff --git a/mcast/client/.svn/text-base/api_sock_test.c.svn-base b/mcast/client/.svn/text-base/api_sock_test.c.svn-base new file mode 100644 index 0000000..fa5a0e7 --- /dev/null +++ b/mcast/client/.svn/text-base/api_sock_test.c.svn-base @@ -0,0 +1 @@ +link api_test.c \ No newline at end of file diff --git a/mcast/client/.svn/text-base/api_test.c.svn-base b/mcast/client/.svn/text-base/api_test.c.svn-base new file mode 100644 index 0000000..cfe6afd --- /dev/null +++ b/mcast/client/.svn/text-base/api_test.c.svn-base @@ -0,0 +1,127 @@ +/* + * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de + * + * See the COPYING file for copyright information and + * how to reach the author. + * + */ + +#include "headers.h" + + +int main (int argc, char **argv) +{ +#ifdef USE_SHM_API + #define API_WAIT_RESPONSE(cmd) { cmd->state=API_REQUEST; while (cmd->state == API_REQUEST) usleep(10*1000); if (cmd->state == API_ERROR) warn ("SHM parameter error\n");} + + int fd = shm_open (API_SHM_NAMESPACE, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + if (fd == -1 ) { + warn ("Cannot get a shared memory handle\n"); + return -1; + } + + if (ftruncate (fd, sizeof(api_cmd_t)) == -1) { + err ("Cannot truncate shared memory\n"); + } + + api_cmd_t *api_cmd = mmap(NULL, sizeof(api_cmd_t), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if ( api_cmd == MAP_FAILED ) { + err ("MMap of shared memory region failed\n"); + } + close(fd); +#endif +#ifdef USE_SOCK_API + #define API_WAIT_RESPONSE(cmd) { cmd->state=API_REQUEST; send (sock_comm, &sock_cmd, sizeof(api_cmd_t), 0); recv (sock_comm, &sock_cmd, sizeof(api_cmd_t), 0); if (cmd->state == API_ERROR) warn ("SHM parameter error\n");} + + int sock_comm; + int sock_name_len = 0; + struct sockaddr_un sock_name; + api_cmd_t sock_cmd; + api_cmd_t *api_cmd=&sock_cmd; + sock_name.sun_family = AF_UNIX; + + strcpy(sock_name.sun_path, API_SOCK_NAMESPACE); + sock_name_len = strlen(API_SOCK_NAMESPACE) + sizeof(sock_name.sun_family); + + if((sock_comm = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) + { + warn ("socket create failure %d\n", errno); + return -1; + } + + if (connect(sock_comm, &sock_name, sock_name_len) < 0) { + err ("connect failure\n"); + } +#endif + api_cmd->cmd=API_GET_NC_NUM; + API_WAIT_RESPONSE(api_cmd); + + printf("nc_num: %d\n", api_cmd->parm[API_PARM_NC_NUM]); + int nc_num=api_cmd->parm[API_PARM_NC_NUM]; + int i; + for(i=0;icmd=API_GET_NC_INFO; + api_cmd->parm[API_PARM_NC_NUM]=i; + API_WAIT_RESPONSE(api_cmd); + printf("nc_info.uuid: %s nc_info.lastseen: %u nc_info.tuner_num: %d\n", api_cmd->u.nc_info.uuid, (unsigned int) api_cmd->u.nc_info.lastseen, api_cmd->u.nc_info.tuner_num); + int j; + int tuner_num=api_cmd->u.nc_info.tuner_num; + for(j=0;jcmd=API_GET_TUNER_INFO; + api_cmd->parm[API_PARM_TUNER_NUM]=j; + API_WAIT_RESPONSE(api_cmd); + printf("tuner_info.fe_info.name: %s SatList: %s\n",api_cmd->u.tuner_info.fe_info.name, api_cmd->u.tuner_info.SatelliteListName); + } + + + int sat_list_num=api_cmd->u.nc_info.sat_list_num; + for(j=0;jcmd=API_GET_SAT_LIST_INFO; + api_cmd->parm[API_PARM_NC_NUM]=i; + api_cmd->parm[API_PARM_SAT_LIST_NUM]=j; + API_WAIT_RESPONSE(api_cmd); + + printf("sat_list_info.Name: %s sat_list_info.sat_num: %d\n", api_cmd->u.sat_list.Name, api_cmd->u.sat_list.sat_num); + + int sat_num=api_cmd->u.sat_list.sat_num; + int k; + for(k=0;kcmd=API_GET_SAT_INFO; + api_cmd->parm[API_PARM_SAT_LIST_NUM]=j; + api_cmd->parm[API_PARM_SAT_NUM]=k; + API_WAIT_RESPONSE(api_cmd); + printf("sat_info.Name: %s\n",api_cmd->u.sat_info.Name); + int comp_num=api_cmd->u.sat_info.comp_num; + int l; + for(l=0;lcmd=API_GET_SAT_COMP_INFO; + api_cmd->parm[API_PARM_SAT_LIST_NUM]=j; + api_cmd->parm[API_PARM_SAT_NUM]=k; + api_cmd->parm[API_PARM_SAT_COMP_NUM]=l; + API_WAIT_RESPONSE(api_cmd); + printf("sat_comp.Polarisation: %d sat_comp.RangeMin: %d sat_comp.RangeMax: %d sat_comp.LOF: %d\n", api_cmd->u.sat_comp.Polarisation, api_cmd->u.sat_comp.RangeMin, api_cmd->u.sat_comp.RangeMax, api_cmd->u.sat_comp.LOF); + } + } + } + } + + while (1) { + api_cmd->cmd=API_GET_TRA_NUM; + API_WAIT_RESPONSE(api_cmd); + + printf("tra_num: %d\n", api_cmd->parm[API_PARM_TRA_NUM]); + int tra_num=api_cmd->parm[API_PARM_TRA_NUM]; + for(i=0;icmd=API_GET_TRA_INFO; + api_cmd->parm[API_PARM_TRA_NUM]=i; + API_WAIT_RESPONSE(api_cmd); + char host[INET6_ADDRSTRLEN]; + inet_ntop (AF_INET6, &api_cmd->u.tra.mcg, (char *) host, INET6_ADDRSTRLEN); + + printf("tra.slot:%d tra.fe_type: %d tra.InUse: % 3d tra.mcg: %s tra.uuid: %s tra.lastseen: %u tra.lock:%d tra.strength:%d tra.snr:%d tra.ber:%d\n", api_cmd->u.tra.slot, api_cmd->u.tra.fe_type, api_cmd->u.tra.InUse, host, api_cmd->u.tra.uuid, (unsigned int) api_cmd->u.tra.lastseen, api_cmd->u.tra.s.st, api_cmd->u.tra.s.strength, api_cmd->u.tra.s.snr, api_cmd->u.tra.s.ber); + } + sleep(2); + } + return 0; +} + diff --git a/mcast/client/.svn/text-base/ci_handler.c.svn-base b/mcast/client/.svn/text-base/ci_handler.c.svn-base new file mode 100644 index 0000000..beef8ff --- /dev/null +++ b/mcast/client/.svn/text-base/ci_handler.c.svn-base @@ -0,0 +1,321 @@ +/* + * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de + * + * See the COPYING file for copyright information and + * how to reach the author. + * + */ + +#include "headers.h" + +//#define SHOW_TPDU + +static ci_dev_t devs; +static int dev_num = 0; +static int ci_run = 0; +static pthread_t ci_handler_thread; +static int port = 23000; +static char iface[IFNAMSIZ]; + +//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +static int ci_connect (ci_dev_t * c) +{ + int ret; + int j; + struct in6_addr nc; + + if (c->connected) { + return 0; + } + + if (c->fd_ci) { + closesocket (c->fd_ci); + } + + c->fd_ci = socket (PF_INET6, SOCK_STREAM, 0); + j = 1; + if (setsockopt (c->fd_ci, SOL_SOCKET, SO_REUSEADDR, (_SOTYPE) & j, sizeof (j)) < 0) { + warn ("setsockopt REUSEADDR\n"); + } + + j = 1; + if (setsockopt (c->fd_ci, SOL_SOCKET, TCP_NODELAY, (_SOTYPE) & j, sizeof (j)) < 0) { + warn ("setsockopt TCP_NODELAY\n"); + } + + inet_pton (AF_INET6, c->uuid, &nc); +#ifdef SHOW_TPDU + char host[INET6_ADDRSTRLEN]; + inet_ntop (AF_INET6, &nc, (char *) host, INET6_ADDRSTRLEN); + info ("Connect To: %s\n", host); +#endif + struct sockaddr_in6 addr; + memset (&addr, 0, sizeof (struct sockaddr_in6)); + + addr.sin6_family = AF_INET6; + addr.sin6_port = htons (port); + addr.sin6_addr = nc; + addr.sin6_scope_id = if_nametoindex (iface); + + ret = connect (c->fd_ci, (struct sockaddr *) &addr, sizeof (struct sockaddr_in6)); + if (ret < 0) { + warn ("Failed to access NetCeiver CA support\n"); + } else { + c->connected = 1; + } + return ret; +} + +//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +int ci_write_pdu (ci_dev_t * c, ci_pdu_t * tpdu) +{ + int ret = -1; + + dbg ("ci_write_pdu: %p %d\n", tpdu->data, tpdu->len); + + ci_decode_ll (tpdu->data, tpdu->len); + memcpy (c->txdata + 2, tpdu->data, tpdu->len); + c->txdata[0] = tpdu->len >> 8; + c->txdata[1] = tpdu->len & 0xff; + if (!ci_connect (c)) { +#ifdef SHOW_TPDU + int j; + info ("Send TPDU: "); + for (j = 0; j < tpdu->len; j++) { + info ("%02x ", tpdu->data[j]); + } + info ("\n"); +#endif + ret = send (c->fd_ci, (char *) c->txdata, tpdu->len + 2, 0); + if (ret < 0) { + c->connected = 0; + } + } + return ret; +} + +//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +static void clean_ci_recv_thread (void *argp) +{ + ci_dev_t *c = (ci_dev_t *) argp; + if (c->txdata) { + free (c->txdata); + } + if (c->rxdata) { + free (c->rxdata); + } + closesocket (c->fd_ci); +} + +//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +static void *ci_recv (void *argp) +{ + ci_dev_t *c = (ci_dev_t *) argp; + ci_pdu_t tpdu; + int ret = -1; + + pthread_cleanup_push (clean_ci_recv_thread, c); + + c->rxdata = (u_int8_t *) malloc (CA_TPDU_MAX + 2); + if (!c->rxdata) + err ("ci_recv: out of memory\n"); + c->txdata = (u_int8_t *) malloc (CA_TPDU_MAX + 2); + if (!c->txdata) + err ("ci_recv: out of memory\n"); + + if (c->rxdata && c->txdata) { + c->recv_run = 1; + + while (c->recv_run) { + if (c->connected) { + ret = recv (c->fd_ci, (char *) c->rxdata, CA_TPDU_MAX + 2, 0); + if (ret > 0) { + tpdu.data = c->rxdata; + while (ret > 0) { + tpdu.len = ntohs16 (tpdu.data); + if (tpdu.len >= ret) { + break; + } + tpdu.data += 2; +#ifdef SHOW_TPDU + int j; + info ("Received TPDU: "); + for (j = 0; j < tpdu.len; j++) { + info ("%02x ", tpdu.data[j]); + } + info ("\n"); +#endif + ci_decode_ll (tpdu.data, tpdu.len); + unsigned int slot = (unsigned int) tpdu.data[0]; + if (slot < CA_MAX_SLOTS) { + if (c->handle_ci_slot[slot]) { + c->handle_ci_slot[slot] (&tpdu, c->handle_ci_slot_context[slot]); + } + } + + tpdu.data += tpdu.len; + ret -= tpdu.len + 2; + } + } else { + if (errno == EAGAIN) { + ret = 0; + } else { + c->connected = 0; + } + } + } + usleep (10 * 1000); + } + } + pthread_cleanup_pop (1); + + return NULL; +} + +//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +int ci_register_handler (ci_dev_t * c, int slot, int (*p) (ci_pdu_t *, void *), void *context) +{ + if (slot < CA_MAX_SLOTS) { + c->handle_ci_slot[slot] = p; + c->handle_ci_slot_context[slot] = context; + return 0; + } + return -1; +} + +//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +int ci_unregister_handler (ci_dev_t * c, int slot) +{ + if (slot < CA_MAX_SLOTS) { + c->handle_ci_slot[slot] = NULL; + c->handle_ci_slot_context[slot] = NULL; + return 0; + } + return -1; +} + +//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +static ci_dev_t *ci_add (void) +{ + ci_dev_t *c = (ci_dev_t *) malloc (sizeof (ci_dev_t)); + if (!c) + return NULL; + memset (c, 0, sizeof (ci_dev_t)); + dvbmc_list_add_head (&devs.list, &c->list); + return c; +} + +//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +static void ci_del (ci_dev_t * c) +{ + c->recv_run = 0; + if (pthread_exist(c->ci_recv_thread) && !pthread_cancel (c->ci_recv_thread)) { + pthread_join (c->ci_recv_thread, NULL); + } + dvbmc_list_remove (&c->list); + free (c); +} + +//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + + +ci_dev_t *ci_find_dev_by_uuid (char *uuid) +{ + ci_dev_t *c; + DVBMC_LIST_FOR_EACH_ENTRY (c, &devs.list, ci_dev_t, list) { + if (!strcmp (c->uuid, uuid)) { + return c; + } + } + return NULL; +} + +//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +static void *ci_handler (void *p) +{ + int n; + netceiver_info_list_t *nc_list = nc_get_list (); + ci_run = 1; + while (ci_run) { + nc_lock_list (); + for (n = 0; n < nc_list->nci_num; n++) { + netceiver_info_t *nci = nc_list->nci + n; + char *uuid = nci->uuid; + if (!strlen (uuid) || ci_find_dev_by_uuid (uuid)) { + //already seen + continue; + } + + ci_dev_t *c = ci_add (); + if (!c) { + err ("Cannot get memory for dvb loopback context\n"); + } + + dbg ("allocate ci dev %d for uuid %s\n", dev_num, uuid); + + strcpy (c->uuid, uuid); + c->cacaps = &nci->ci; + c->device = dev_num++; + + info ("Starting ci thread for netceiver UUID %s\n", c->uuid); + int ret = pthread_create (&c->ci_recv_thread, NULL, ci_recv, c); + while (!ret && !c->recv_run) { + usleep (10000); + } + if (ret) { + err ("pthread_create failed with %d\n", ret); + } + } + nc_unlock_list (); + sleep (1); + } + return NULL; +} + +int ci_init (int ca_enable, char *intf, int p) +{ + int ret = 0; + if (intf) { + strcpy (iface, intf); + } else { + iface[0] = 0; + } + if (p) { + port = p; + } + + dvbmc_list_init (&devs.list); + if (ca_enable) { + ret = pthread_create (&ci_handler_thread, NULL, ci_handler, NULL); + while (!ret && !ci_run) { + usleep (10000); + } + } + return ret; +} + +//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +void ci_exit (void) +{ + ci_dev_t *c; + ci_dev_t *ctmp; + if (pthread_exist (ci_handler_thread)) { + if (pthread_exist(ci_handler_thread) && !pthread_cancel (ci_handler_thread)) { + pthread_join (ci_handler_thread, NULL); + } + + DVBMC_LIST_FOR_EACH_ENTRY_SAFE (c, ctmp, &devs.list, ci_dev_t, list) { + ci_del (c); + } + } +} diff --git a/mcast/client/.svn/text-base/ci_handler.h.svn-base b/mcast/client/.svn/text-base/ci_handler.h.svn-base new file mode 100644 index 0000000..3ecfc02 --- /dev/null +++ b/mcast/client/.svn/text-base/ci_handler.h.svn-base @@ -0,0 +1,30 @@ +/* + * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de + * + * See the COPYING file for copyright information and + * how to reach the author. + * + */ + +typedef struct { + struct list list; + + pthread_t ci_recv_thread; + char uuid[UUID_SIZE]; + SOCKET fd_ci; + int recv_run; + int device; + int connected; + recv_cacaps_t *cacaps; + u_int8_t *txdata; + u_int8_t *rxdata; + int (*handle_ci_slot[CA_MAX_SLOTS]) (ci_pdu_t *tpdu, void *context); + void *handle_ci_slot_context[CA_MAX_SLOTS]; +} ci_dev_t; + +DLL_SYMBOL int ci_register_handler(ci_dev_t *c, int slot, int (*p) (ci_pdu_t *, void *), void *context); +DLL_SYMBOL int ci_unregister_handler(ci_dev_t *c, int slot); +DLL_SYMBOL int ci_write_pdu(ci_dev_t *c, ci_pdu_t *tpdu); +DLL_SYMBOL ci_dev_t *ci_find_dev_by_uuid (char *uuid); +DLL_SYMBOL int ci_init (int ca_enable, char *intf, int p); +DLL_SYMBOL void ci_exit (void); diff --git a/mcast/client/.svn/text-base/ciparser.c.svn-base b/mcast/client/.svn/text-base/ciparser.c.svn-base new file mode 100644 index 0000000..0a2c0bf --- /dev/null +++ b/mcast/client/.svn/text-base/ciparser.c.svn-base @@ -0,0 +1 @@ +link ../common/ciparser.c \ No newline at end of file diff --git a/mcast/client/.svn/text-base/dummy_client.c.svn-base b/mcast/client/.svn/text-base/dummy_client.c.svn-base new file mode 100644 index 0000000..2a397d9 --- /dev/null +++ b/mcast/client/.svn/text-base/dummy_client.c.svn-base @@ -0,0 +1,101 @@ +/* + * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de + * + * See the COPYING file for copyright information and + * how to reach the author. + * + */ + +#define DEBUG 1 +#include "headers.h" + + +//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +static int dummy_handle_ts (unsigned char *buffer, size_t len, void *p) +{ + FILE *f=(FILE*)p; + fwrite(buffer, len, 1, f); + return len; +} + +//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +static int dummy_handle_ten (tra_t *ten, void *p) +{ + FILE *f=(FILE*)p; + if(ten) { + fprintf(f,"Status: %02X, Strength: %04X, SNR: %04X, BER: %04X\n",ten->s.st,ten->s.strength, ten->s.snr, ten->s.ber); + } + return 0; +} + +//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +void dummy_client (void) +{ + int i; + int n; + int run=1; + FILE *f; + recv_info_t *r; + recv_sec_t sec; + struct dvb_frontend_parameters fep; + dvb_pid_t pids[3]; + + netceiver_info_list_t *nc_list=nc_get_list(); +#if 0 + printf("Looking for netceivers out there....\n"); + while(run) { + nc_lock_list(); + for (n = 0; n < nc_list->nci_num; n++) { + netceiver_info_t *nci = nc_list->nci + n; + printf("\nFound NetCeiver: %s\n",nci->uuid); + for (i = 0; i < nci->tuner_num; i++) { + printf(" Tuner: %s, Type %d\n",nci->tuner[i].fe_info.name, nci->tuner[i].fe_info.type); + } + } + nc_unlock_list(); + if(nc_list->nci_num) { + break; + } + sleep(1); + } +#endif + f=fopen("out.ts","wb"); + + r = recv_add(); + if (!r) { + fprintf (stderr, "Cannot get memory for receiver\n"); + return; + } + register_ten_handler (r, dummy_handle_ten, stderr); + register_ts_handler (r, dummy_handle_ts, f); + + memset(&sec, 0, sizeof(recv_sec_t)); + sec.voltage=SEC_VOLTAGE_18; + sec.mini_cmd=SEC_MINI_A; + sec.tone_mode=SEC_TONE_ON; + + memset(&fep, 0, sizeof(struct dvb_frontend_parameters)); + fep.frequency=12544000; + fep.inversion=INVERSION_AUTO; + fep.u.qpsk.symbol_rate=22000000; + fep.u.qpsk.fec_inner=FEC_5_6; + + memset(&pids, 0, sizeof(pids)); + pids[0].pid=511; + pids[1].pid=512; + pids[2].pid=511; + pids[2].id=2; + pids[3].pid=511; + pids[3].id=1; + pids[4].pid=-1; + + printf("\nTuning a station and writing transport data to file 'out.ts':\n"); + recv_tune (r, (fe_type_t)FE_QPSK, 1800+192, &sec, &fep, pids); + getchar(); + register_ten_handler (r, NULL, NULL); + register_ts_handler (r, NULL, NULL); + fclose(f); +} diff --git a/mcast/client/.svn/text-base/dummy_client.h.svn-base b/mcast/client/.svn/text-base/dummy_client.h.svn-base new file mode 100644 index 0000000..e79cbf1 --- /dev/null +++ b/mcast/client/.svn/text-base/dummy_client.h.svn-base @@ -0,0 +1,10 @@ +/* + * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de + * + * See the COPYING file for copyright information and + * how to reach the author. + * + */ + +void dummy_client (void); + diff --git a/mcast/client/.svn/text-base/dvblo_handler.c.svn-base b/mcast/client/.svn/text-base/dvblo_handler.c.svn-base new file mode 100644 index 0000000..875749d --- /dev/null +++ b/mcast/client/.svn/text-base/dvblo_handler.c.svn-base @@ -0,0 +1,716 @@ +/* + * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de + * + * See the COPYING file for copyright information and + * how to reach the author. + * + */ + +#include "headers.h" +#include "dvblo_ioctl.h" +#include "dvblo_handler.h" + +//#define SHOW_EVENTS +//#define SHOW_TPDU +//#define SHOW_PIDS + +#define TUNE_FORCED_TIMEOUT 5 + +extern pthread_mutex_t lock; +extern recv_info_t receivers; + +static dvblo_dev_t devs; +static int dev_num = 0; +static int dvblo_run = 1; +static int cidev = 0; +static int reload = 0; +static dvblo_cacaps_t cacaps; + +static int special_status_mode=0; // 1: return rotor mode and tuner slot in status + +static int dvblo_get_nc_addr (char *addrstr, char *uuid) +{ + int len = strlen (uuid); + if (len <= 5) { + return -1; + } + memset (addrstr, 0, INET6_ADDRSTRLEN); + + strncpy (addrstr, uuid, len - 5); + return 0; +} + +//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +static int dvblo_handle_ts (unsigned char *buffer, size_t len, void *p) +{ + dvblo_dev_t * d=( dvblo_dev_t *)p; + return write (d->fd, buffer, len); +} + +//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +static int dvblo_handle_ten (tra_t * ten, void *c) +{ + dvblo_dev_t *d = (dvblo_dev_t *) c; + dbg ("TEN: %ld %p %p\n", gettid (), ten, d); + + if (ten) { + dvblo_festatus_t stat; + memcpy(&stat, &ten->s, sizeof(dvblo_festatus_t)); + + d->ten = *ten; + + if (special_status_mode) { + stat.st|=(ten->rotor_status&3)<<8; + stat.st|=(1+ten->slot)<<12; + } + + return ioctl (d->fd, DVBLO_SET_FRONTEND_STATUS, (dvblo_festatus_t*)&stat); + } else { + dvblo_festatus_t s; + memset (&s, 0, sizeof (dvblo_festatus_t)); + + return ioctl (d->fd, DVBLO_SET_FRONTEND_STATUS, &s); + } +} + +//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +static void sig_handler (int signal) +{ + dbg ("Signal: %d\n", signal); + + switch (signal) { + case SIGHUP: + reload = 1; + break; + case SIGTERM: + case SIGINT: + dbg ("Trying to exit, got signal %d...\n", signal); + dvblo_run = 0; + break; + } +} + +//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +int dvblo_init (void) +{ + char char_dev[100]; + int j, k = 0; + struct dvb_frontend_info fe_info; + dvblo_festatus_t fe_status; + + dvbmc_list_init (&devs.list); + + memset (&fe_info, 0, sizeof (struct dvb_frontend_info)); + fe_info.type = -1; + strcpy (fe_info.name, "Unconfigured"); + memset (&fe_status, 0, sizeof (dvblo_festatus_t)); + + for (j = 0; j < MAX_DEVICES; j++) { + + sprintf (char_dev, "/dev/dvblo%d", j); + int fd = open (char_dev, O_RDWR); + + if (fd == -1) { + warn ("Cannot Open %s\n", char_dev); + continue; + } + k++; + ioctl (fd, DVBLO_SET_FRONTEND_INFO, &fe_info); + ioctl (fd, DVBLO_SET_FRONTEND_STATUS, &fe_status); + ioctl (fd, DVBLO_SET_CA_CAPS, &cacaps); + dvblo_tpdu_t tpdu; + while (1) { + if (ioctl (fd, DVBLO_GET_TPDU, &tpdu) || !tpdu.len) { + break; + } + } + close (fd); + } + + signal (SIGTERM, &sig_handler); + signal (SIGINT, &sig_handler); + signal (SIGHUP, &sig_handler); + signal (SIGPIPE, &sig_handler); + return k; +} + +//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +static int dvblo_convert_pids (dvblo_dev_t * d) +{ + dvb_pid_t *dst = d->dstpids; + dvblo_pids_t *src = &d->pids; + int i; +#ifdef SHOW_PIDS + info ("devnum:%d pidnum:%d\n", d->device, src->num); +#endif + for (i = 0; i < src->num; i++) { +#ifdef SHOW_PIDS + printf ("devnum:%d pid:%04x\n", d->device, src->pid[i]); +#endif + dst[i].pid = src->pid[i]; + if (d->ca_enable) { + dst[i].id = ci_cpl_find_caid_by_pid (src->pid[i]); + if (dst[i].id != 0) { + dbg ("pid: %04x id: %04x\n", dst[i].pid, dst[i].id); + } + } + } + dst[i].pid = -1; + return i; +} + +//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +static int dvblo_tune (dvblo_dev_t * d, int force) +{ + satellite_reference_t satref; + int SatPos; + int mode; + int ret = 0; + + nc_lock_list (); + + for (mode = 0; mode < 3; mode++) { + if (satellite_find_by_diseqc (&satref, (recv_sec_t*)&d->sec, &d->fe_parms, mode)) + break; + } + + if (mode == 3 || (mode == 2 && (d->type == FE_QAM || d->type == FE_OFDM))) { + SatPos = NO_SAT_POS; + } else { + int LOF = 0; + if (mode) { + LOF = satellite_get_lof_by_ref (&satref); + d->fe_parms.frequency += LOF * 1000; + } + SatPos = satellite_get_pos_by_ref (&satref); + recv_sec_t *sec=satellite_find_sec_by_ref (&satref); + memcpy(&d->sec, sec, sizeof(recv_sec_t)); + d->sec.voltage = satellite_find_pol_by_ref (&satref); +#if 1 //def SHOW_EVENTS + printf ("Found satellite position: %d fe_parms: %d LOF: %d voltage: %d mode: %d\n", SatPos, d->fe_parms.frequency, LOF, d->sec.voltage, mode); +#endif + } + nc_unlock_list (); + if (force && d->pids.num == 0) { + d->dstpids[0].pid = 0; + d->dstpids[0].id = 0; + d->dstpids[1].pid = -1; + ret = 2; + } else { + dvblo_convert_pids (d); + } + recv_tune (d->r, d->type, SatPos, (recv_sec_t*)&d->sec, &d->fe_parms, d->dstpids); + return ret; +} + +//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +int dvblo_write_ci (ci_pdu_t * pdu, void *context) +{ + dvblo_dev_t *d = (dvblo_dev_t *) context; + dvblo_tpdu_t tpdu; + memcpy (tpdu.data, pdu->data, pdu->len); + tpdu.len = pdu->len; + if (!cmd.reelcammode) + tpdu.data[0] = 0; + return ioctl (d->fd, DVBLO_SET_TPDU, &tpdu); +} + +//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +static void clean_dvblo_recv_thread (void *argp) +{ + dvblo_dev_t *d = (dvblo_dev_t *) argp; + recv_del (d->r); + close (d->fd); +} + +//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +static void *dvblo_recv (void *argp) +{ + dvblo_dev_t *d = (dvblo_dev_t *) argp; + dvblo_tpdu_t tpdu; + struct dvb_frontend_parameters old_fe_parms; + dvblo_sec_t old_sec; + struct pollfd fds[1]; + int timeout_msecs = 50; + int ret; + time_t last_ci_reset = 0; + char char_dev[100]; + int need_tune = 0; + time_t forced = 0; + unsigned int event = 0; + + dvblo_cacaps_t cacap; + + sprintf (char_dev, "/dev/dvblo%d", d->device); + dbg ("Using character device %s for dvb loopback\n", char_dev); + + d->fd = open (char_dev, O_RDWR); + + if (d->fd < 0) { + err ("Cannot open %s - dvbloop driver loaded?\n", char_dev); + } + + pthread_cleanup_push (clean_dvblo_recv_thread, d); + + fds[0].fd = d->fd; + + if (!ioctl (d->fd, DVBLO_IOCCHECKDEV)) { + if (!ioctl (d->fd, DVBLO_IOCADDDEV)) { + info ("created dvb adapter: %d\n", d->device); + } + } + d->info.frequency_min = 1; + d->info.frequency_max = 2000000000; + + ioctl (d->fd, DVBLO_SET_FRONTEND_INFO, &d->info); + ioctl (d->fd, DVBLO_GET_FRONTEND_PARAMETERS, &d->fe_parms); + ioctl (d->fd, DVBLO_GET_PIDLIST, &d->pids); + ioctl (d->fd, DVBLO_GET_SEC_PARAMETERS, &d->sec); + + old_fe_parms = d->fe_parms; + old_sec = d->sec; +#ifdef DEBUG + print_fe_info (&d->info); +#endif + d->recv_run = 1; + + if (dvblo_tune (d, 1) == 2) { + forced = time (NULL); + } + + while (d->recv_run) { + if (d->cacaps->cap.slot_num) { + nc_lock_list (); +#ifdef SHOW_TPDU + info ("ca_caps->: %p ci_slot:%d info[0]:%02x info[1]:%02x\n", d->cacaps, d->ci_slot, d->cacaps->info[0].flags, d->cacaps->info[1].flags); +#endif + cacap = *d->cacaps; + if (!cmd.reelcammode) { + if (d->ci_slot != 0) { + cacap.info[0] = cacap.info[d->ci_slot]; + } + cacap.cap.slot_num = 1; + } + if ((time (NULL) - last_ci_reset) < cmd.ci_timeout) { + cacap.info[0].flags = 0; + } + ioctl (d->fd, DVBLO_SET_CA_CAPS, &cacap); + nc_unlock_list (); + } + + fds[0].events = POLLIN; + ret = poll (fds, 1, timeout_msecs); + if (ret > 0) { + ioctl (d->fd, DVBLO_GET_EVENT_MASK, &event); + ioctl (d->fd, DVBLO_GET_FRONTEND_PARAMETERS, &d->fe_parms); + ioctl (d->fd, DVBLO_GET_PIDLIST, &d->pids); + ioctl (d->fd, DVBLO_GET_SEC_PARAMETERS, &d->sec); + if (event & EV_MASK_FE) { +#ifdef SHOW_EVENTS + printf ("%p/%p Event Received: FE+Tuner/", d, d->r); + if (event & EV_FRONTEND) { + printf ("Frontend "); + } + if (event & EV_TUNER) { + printf ("Tuner "); + } + if (event & EV_FREQUENCY) { + printf ("Frequency:%d ", d->fe_parms.frequency); + } + if (event & EV_BANDWIDTH) { + printf ("Bandwidth "); + } + printf ("\n"); +#endif + if (memcmp (&d->fe_parms, &old_fe_parms, sizeof (struct dvb_frontend_parameters))) { + old_fe_parms = d->fe_parms; + dbg ("fe_parms have changed!\n"); + need_tune = 1; + if (d->ca_enable) { + ci_cpl_clear (d->ci_slot); + } + } + } + if (event & EV_MASK_SEC) { +#ifdef SHOW_EVENTS + printf ("%p/%p Event Received: SEC/", d, d->r); + if (event & EV_TONE) { + printf ("Tone:%d ", d->sec.tone_mode); + } + if (event & EV_VOLTAGE) { + printf ("Voltage:%d ", d->sec.voltage); + } + if (event & EV_DISEC_MSG) { + printf ("DISEC-Message:"); + int j; + for (j = 0; j < d->sec.diseqc_cmd.msg_len; j++) { + printf ("%02x ", d->sec.diseqc_cmd.msg[j]); + } + } + if (event & EV_DISEC_BURST) { + printf ("DISEC-Burst:%d ", d->sec.mini_cmd); + } + printf ("\n"); +#endif + if (d->sec.voltage == SEC_VOLTAGE_OFF) { + recv_stop (d->r); + memset (&old_fe_parms, 0, sizeof (struct dvb_frontend_parameters)); + need_tune = 0; + dbg ("Stop %p\n", d->r); + } else if (memcmp (&d->sec, &old_sec, sizeof (dvblo_sec_t))) { + dbg ("SEC parms have changed!\n"); + old_sec = d->sec; + need_tune = 1; + if (d->ca_enable) { + ci_cpl_clear (d->ci_slot); + } + } + } + if (event & EV_MASK_CA) { +#ifdef SHOW_EVENTS + printf ("%p/%p Event Received: CA/", d, d->r); +#endif + if (event & EV_CA_WRITE) { +#ifdef SHOW_EVENTS + printf ("WRITE "); +#endif + while (1) { + if (!ioctl (d->fd, DVBLO_GET_TPDU, &tpdu) && tpdu.len) { + if (d->c && d->ca_enable) { + ci_pdu_t pdu; + pdu.len = tpdu.len; + pdu.data = tpdu.data; + if (!cmd.reelcammode) { + pdu.data[0] = d->ci_slot; + } + ci_write_pdu (d->c, &pdu); + event |= EV_PIDFILTER; + } + } else { + break; + } + } + } + if (event & EV_CA_RESET) { +#ifdef SHOW_EVENTS + printf ("RESET "); +#endif + last_ci_reset = time (NULL); + if (d->ca_enable) { + ci_cpl_clear (d->ci_slot); + } + } +#ifdef SHOW_EVENTS + printf ("\n"); +#endif + } + if (need_tune) { + if (dvblo_tune (d, 1) == 2) { + forced = time (NULL); + } + need_tune = 0; + } else if (event & EV_MASK_PID) { +#ifdef SHOW_EVENTS + printf ("%p/%p Event Received: Demux/", d, d->r); + if (event & EV_PIDFILTER) { + printf ("PID filter: %d pids", d->pids.num); + } + printf ("\n"); +#endif + forced = 0; + } + } + if (forced) { + if ((time (NULL) - forced) < TUNE_FORCED_TIMEOUT) { + event &= ~EV_PIDFILTER; + } else { + event |= EV_PIDFILTER; + forced = 0; + } + } + if (event & EV_PIDFILTER) { + dvblo_convert_pids (d); + recv_pids (d->r, d->dstpids); + } + event = 0; + } + pthread_cleanup_pop (1); + return NULL; +} + +//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +static dvblo_dev_t *dvblo_add (void) +{ + dvblo_dev_t *d = (dvblo_dev_t *) malloc (sizeof (dvblo_dev_t)); + + if (!d) + return NULL; + memset (d, 0, sizeof (dvblo_dev_t)); + dvbmc_list_add_head (&devs.list, &d->list); + return d; +} + +//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +static void dvblo_del (dvblo_dev_t * d) +{ + d->recv_run = 0; + if (pthread_exist(d->dvblo_recv_thread) && !pthread_cancel (d->dvblo_recv_thread)) { + pthread_join (d->dvblo_recv_thread, NULL); + } + dvbmc_list_remove (&d->list); + free (d); +} + +//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +void dvblo_exit (void) +{ + dvblo_dev_t *d; + dvblo_dev_t *dtmp; + + DVBMC_LIST_FOR_EACH_ENTRY_SAFE (d, dtmp, &devs.list, dvblo_dev_t, list) { + dvblo_del (d); + } +} + +static dvblo_dev_t *find_dev_by_uuid (dvblo_dev_t * devs, char *uuid) +{ + dvblo_dev_t *d; + DVBMC_LIST_FOR_EACH_ENTRY (d, &devs->list, dvblo_dev_t, list) { + if (!strcmp (d->uuid, uuid)) { + return d; + } + } + return NULL; +} + +//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +static int count_dev_by_type (dvblo_dev_t * devs, fe_type_t type) +{ + int ret = 0; + dvblo_dev_t *d; + DVBMC_LIST_FOR_EACH_ENTRY (d, &devs->list, dvblo_dev_t, list) { + if (type == d->type) { + ret++; + } + } + return ret; +} + +//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +satellite_list_t *dvblo_get_sat_list (char *SatelliteListName, netceiver_info_t * nci) +{ + int i; + dbg ("looking for %s\n", SatelliteListName); + for (i = 0; i < nci->sat_list_num; i++) { + if (!strcmp (SatelliteListName, nci->sat_list[i].Name)) { + dbg ("found uuid in sat list %d\n", i); + return nci->sat_list + i; + } + } + return NULL; +} + +//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +static int diseqc_write_conf (char *disec_conf_path, char *rotor_conf_path, dvblo_dev_t * devs, int mode) +{ + int j, k; + dvblo_dev_t *d; + char buf[80]; + char tstr[16]; + FILE *f = NULL; + FILE *fr = NULL; + + f = fopen (disec_conf_path, "wt"); + if (f == NULL) { + return 0; + } + fprintf (f, "# diseqc.conf in VDR format auto generated\n\n"); + + if (strlen(rotor_conf_path)) { + special_status_mode=1; + fr = fopen (rotor_conf_path, "wt"); + } + if (fr) + fprintf (fr, "# rotor.conf auto generated\n\n"); + + DVBMC_LIST_FOR_EACH_ENTRY (d, &devs->list, dvblo_dev_t, list) { + satellite_list_t *sat_list = dvblo_get_sat_list (d->nci->tuner[d->tuner].SatelliteListName, d->nci); + if (!sat_list) { + continue; + } + for (j = 0; j < sat_list->sat_num; j++) { + satellite_info_t *sat = sat_list->sat + j; + for (k = 0; k < sat->comp_num; k++) { + satellite_component_t *comp = sat->comp + k; + int newpos = sat->SatPos ^ 1800; + sprintf (buf, "e0 10 6f %02x %02x %02x", newpos & 0xff, (newpos >> 8) & 0xff, comp->Polarisation << 1 | !(comp->sec.tone_mode & 1)); + if (mode) { + sprintf (tstr, "A%d ", d->device + 1); + } else { + tstr[0] = 0; + } + fprintf (f, "%s%s %d %c 0 [ %s ]\n", tstr, sat->Name, comp->RangeMax, comp->Polarisation == POL_H ? 'H' : 'V', buf); + } + fprintf (f, "\n"); + if (j==0 && fr && sat->type==SAT_SRC_ROTOR) { + fprintf(fr, "%s %i %i %i %i %i\n", tstr, sat->SatPosMin, sat->SatPosMax, + sat->AutoFocus, sat->Latitude, sat->Longitude); + } + } + } + info ("created %s\n", disec_conf_path); + fclose (f); + if (fr) { + info ("created %s\n", rotor_conf_path); + fclose(fr); + } + return 1; +} + +void dvblo_handler (void) +{ + int i; + int n; + int nci_num = 0; + int write_conf = strlen (cmd.disec_conf_path); + netceiver_info_list_t *nc_list = nc_get_list (); + memset (&cacaps, 0, sizeof (dvblo_cacaps_t)); + + info ("Device Type Limits: DVB-S: %d DVB-C: %d DVB-T: %d ATSC: %d DVB-S2: %d\n\n", cmd.tuner_type_limit[FE_QPSK], cmd.tuner_type_limit[FE_QAM], cmd.tuner_type_limit[FE_OFDM], cmd.tuner_type_limit[FE_ATSC], cmd.tuner_type_limit[FE_DVBS2]); + + while (dvblo_run) { + nc_lock_list (); + for (n = 0; n < nc_list->nci_num; n++) { + netceiver_info_t *nci = nc_list->nci + n; + for (i = 0; i < nci->tuner_num; i++) { + char *uuid = nci->tuner[i].uuid; + if (nci->tuner[i].preference < 0 || !strlen (uuid) || find_dev_by_uuid (&devs, uuid)) { + //already seen + continue; + } + fe_type_t type = nci->tuner[i].fe_info.type; + + if (type > FE_DVBS2) { + continue; + } + if(dev_num >= MAX_DEVICES) { + dbg("Limit dev_num reached limit of "MAX_DEVICES"\n"); + continue; + } + if (count_dev_by_type (&devs, type) == cmd.tuner_type_limit[type]) { + dbg ("Limit: %d %d>%d\n", type, count_dev_by_type (&devs, type), cmd.tuner_type_limit[type]); + continue; + } + + dvblo_dev_t *d = dvblo_add (); + if (!d) { + err ("Cannot get memory for dvb loopback context\n"); + } + + dbg ("allocate dev %d for uuid %s\n", dev_num, uuid); + + d->info = nci->tuner[i].fe_info; + + if (type == FE_DVBS2) { + d->info.type = FE_QPSK; + } + + strcpy (d->uuid, nci->tuner[i].uuid); + if (!cmd.reelcammode) { + if (cidev < CA_MAX_SLOTS && (cmd.ca_enable & (1 << dev_num))) { + d->cacaps=(dvblo_cacaps_t*)((void *) &nci->ci); + d->ca_enable = 1; + dbg ("Enabling CA support for device %d\n", dev_num); + char addrstr[INET6_ADDRSTRLEN]; + dvblo_get_nc_addr (addrstr, d->uuid); + dbg ("dvblo_get_nc_addr: %s %s\n", addrstr, d->uuid); + d->c = ci_find_dev_by_uuid (addrstr); + if (d->c) { + dbg ("Attaching ci dev %p to dvblo dev %p\n", d->c, d); + ci_register_handler (d->c, cidev, dvblo_write_ci, d); + d->ci_slot = cidev++; + } else { + dvblo_del (d); //retry next time + break; + } + } else { + d->cacaps = &cacaps; + d->ca_enable = 0; + dbg ("Disabling CA support for device %d\n", dev_num); + } + } else { + if (nci->ci.cap.slot_num && cmd.ca_enable) { + d->ca_enable = 1; + dbg ("Enabling CA support for device %d\n", dev_num); + if (!cidev) { + d->cacaps = (dvblo_cacaps_t*)((void *) &nci->ci); + char addrstr[INET6_ADDRSTRLEN]; + dvblo_get_nc_addr (addrstr, d->uuid); + dbg ("dvblo_get_nc_addr: %s %s\n", addrstr, d->uuid); + d->c = ci_find_dev_by_uuid (addrstr); + if (d->c) { + dbg ("Attaching ci dev %p to dvblo dev %p\n", d->c, d); + ci_register_handler (d->c, cidev++, dvblo_write_ci, d); + ci_register_handler (d->c, cidev++, dvblo_write_ci, d); + } else { + dvblo_del (d); //retry next time + break; + } + } else { + d->cacaps = &cacaps; + } + } else { + d->cacaps = &cacaps; + d->ca_enable = 0; + dbg ("Disabling CA support for device %d\n", dev_num); + } + } + + d->r = recv_add (); + if (!d->r) { + err ("Cannot get memory for receiver\n"); + } + + d->device = dev_num++; + d->type = type; + d->tuner = i; + d->nci = nci; + + register_ten_handler (d->r, dvblo_handle_ten, d); + register_ts_handler (d->r, dvblo_handle_ts, d); + + info ("Starting thread for tuner UUID %s [%s] at device %d with type %d\n", d->uuid, nci->tuner[i].fe_info.name, nci->tuner[i].slot, nci->tuner[i].fe_info.type); + int ret = pthread_create (&d->dvblo_recv_thread, NULL, dvblo_recv, d); + while (!ret && !d->recv_run) { + usleep (10000); + } + if (ret) { + err ("pthread_create failed with %d\n", ret); + } + } + } + if (write_conf) { + if (reload || (nci_num != nc_list->nci_num)) { + nci_num = nc_list->nci_num; + diseqc_write_conf (cmd.disec_conf_path, cmd.rotor_conf_path, &devs, cmd.vdrdiseqcmode); + reload = 0; + } + } + nc_unlock_list (); + sleep (1); + } +} diff --git a/mcast/client/.svn/text-base/dvblo_handler.h.svn-base b/mcast/client/.svn/text-base/dvblo_handler.h.svn-base new file mode 100644 index 0000000..beaa7ac --- /dev/null +++ b/mcast/client/.svn/text-base/dvblo_handler.h.svn-base @@ -0,0 +1,40 @@ +/* + * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de + * + * See the COPYING file for copyright information and + * how to reach the author. + * + */ + +#define MAX_DEVICES 8 + +typedef struct dvblo_dev { + struct list list; + + pthread_t dvblo_recv_thread; + char uuid[UUID_SIZE]; + int device; + int fd; + pthread_t dvblo_ca_thread; + int fd_ca; + int recv_run; + int ci_slot; + int ca_enable; + + fe_type_t type; + recv_info_t *r; + ci_dev_t *c; + struct dvb_frontend_info info; + dvblo_cacaps_t *cacaps; + dvblo_pids_t pids; + dvb_pid_t dstpids[RECV_MAX_PIDS]; + dvblo_sec_t sec; + struct dvb_frontend_parameters fe_parms; + tra_t ten; + int tuner; + netceiver_info_t *nci; +} dvblo_dev_t; + +int dvblo_init (void); +void dvblo_exit (void); +void dvblo_handler (void); diff --git a/mcast/client/.svn/text-base/headers.h.svn-base b/mcast/client/.svn/text-base/headers.h.svn-base new file mode 100644 index 0000000..c371395 --- /dev/null +++ b/mcast/client/.svn/text-base/headers.h.svn-base @@ -0,0 +1,32 @@ +/* + * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de + * + * See the COPYING file for copyright information and + * how to reach the author. + * + */ + +#ifndef __HEADERS_H__ +#define __HEADERS_H__ + +#include "defs.h" +#include "version.h" +#include "list.h" +#include "satlists.h" +#include "mcast.h" +#include "input.h" +#include "recv_ccpp.h" +#include "recv_tv.h" +#include "tools.h" +#include "interfaces.h" +#include "mcast.h" +#include "mld.h" +#include "api_server.h" +#include "tca_handler.h" +#include "tra_handler.h" +#include "mld_reporter.h" +#include "ciparser.h" +#include "ci_handler.h" +#include "mmi_handler.h" +#include "siparser.h" +#endif diff --git a/mcast/client/.svn/text-base/inet_aton.c.svn-base b/mcast/client/.svn/text-base/inet_aton.c.svn-base new file mode 100644 index 0000000..1fd34cc --- /dev/null +++ b/mcast/client/.svn/text-base/inet_aton.c.svn-base @@ -0,0 +1 @@ +link ../common/win32/inet_aton.c \ No newline at end of file diff --git a/mcast/client/.svn/text-base/inet_ntop.c.svn-base b/mcast/client/.svn/text-base/inet_ntop.c.svn-base new file mode 100644 index 0000000..d11af10 --- /dev/null +++ b/mcast/client/.svn/text-base/inet_ntop.c.svn-base @@ -0,0 +1 @@ +link ../common/win32/inet_ntop.c \ No newline at end of file diff --git a/mcast/client/.svn/text-base/inet_pton.c.svn-base b/mcast/client/.svn/text-base/inet_pton.c.svn-base new file mode 100644 index 0000000..7956a55 --- /dev/null +++ b/mcast/client/.svn/text-base/inet_pton.c.svn-base @@ -0,0 +1 @@ +link ../common/win32/inet_pton.c \ No newline at end of file diff --git a/mcast/client/.svn/text-base/input.c.svn-base b/mcast/client/.svn/text-base/input.c.svn-base new file mode 100644 index 0000000..f10cf4f --- /dev/null +++ b/mcast/client/.svn/text-base/input.c.svn-base @@ -0,0 +1,145 @@ +/* + * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de + * + * See the COPYING file for copyright information and + * how to reach the author. + * + */ + +#include "headers.h" +#define CI_RESET_WAIT 10 + +#ifdef __MINGW32__ +#include +#endif + +cmdline_t cmd; + +//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +static void print_help (int argc, char *argv[]) +{ + printf ("Usage:\n" \ + " mcli --ifname \n" \ + " mcli --port (default: -port 23000)\n" \ + " mcli --dvb-s --dvb-c --dvb-t --atsc --dvb-s2 \n" \ + " limit number of device types (default: 8 of every type)\n" \ + " mcli --diseqc-conf \n" \ + " mcli --rotor-conf \n" \ + " mcli --mld-reporter-disable\n" \ + " mcli --sock-path \n"\ + " mcli --ca-enable \n"\ + " mcli --ci-timeout