--- /dev/null
+/build
+/cmake-build
+/.cproject
+/.project
+/.settings
+/compile
+*.dll
+*.exe
+*.exp
+*.ilk
+*.lib
+*.manifest
+*.metagen
+*.ncb
+*.opensdf
+*.pdb
+*.suo
+*.user
+*.aps
+env.h
+version.h
+
+*.rc
+AssemblyInfo.cs
+AssemblyInfo.cpp
+
+*~
+
+/support/private
+
+/driver/p8usb-cec.cat
+/bootloader-driver/p8_usb_dfu.cat
+
+aclocal.m4
+autom4te.cache
+config.guess
+config.log
+config.status
+config.sub
+depcomp
+configure
+install-sh
+INSTALL
+libtool
+ltmain.sh
+Makefile
+Makefile.in
+missing
+config.h
+config.h.in
+config.h.in~
+stamp-h1
+
+/debian/*.log
+/debian/*.substvars
+/debian/*.debhelper
+/debian/files
+/debian/cec-utils
+/debian/libcec-dev
+/debian/libcec
+/debian/libcec2
+/debian/tmp
+
+include/boost
+
+project/bin
+project/Debug/
+project/*.exe
+project/Release/
+project/ipch/
+project/libcec.sdf
+project/obj
+project/Properties
+project/_*
+project/x64
+project/LibCecSharp/x64
+project/LibCecSharp/Debug
+project/LibCecSharp/Release
+project/libcec/x64
+project/libcec/Debug
+project/libcec/Release
+project/testclient/x64
+project/testclient/Debug
+project/testclient/Release
+
+project/RPi/toolchain
+project/RPi/firmware
+project/RPi/deps
+
+src/libcec/libcec.pc
+
+src/CecSharpTester/bin
+src/CecSharpTester/obj
+
+src/cec-config-gui/obj
+src/cec-config/cec-config
+src/cec-config/*.o
+src/cec-config/.deps
+
+src/libcec-wmc/bin
+src/libcec-wmc/obj
+
+/dpinst-x86.exe
+/dpinst-amd64.exe
+
+/documentation
--- /dev/null
+[submodule "src/platform"]
+ path = src/platform
+ url = https://github.com/Pulse-Eight/platform
+[submodule "support"]
+ path = support
+ url = https://github.com/Pulse-Eight/libcec-support.git
+[submodule "src/dotnet"]
+ path = src/dotnet
+ url = https://github.com/Pulse-Eight/cec-dotnet.git
--- /dev/null
+Lars Op den Kamp <lars.opdenkamp@pulse-eight.com>
+Bob van Loosen <bob.loosen@gmail.com>
+Martin Ellis <martin.ellis@pulse-eight.com>
\ No newline at end of file
--- /dev/null
+project(libcec)
+cmake_minimum_required(VERSION 2.8.9)
+
+set(LIBCEC_VERSION_MAJOR 4)
+set(LIBCEC_VERSION_MINOR 0)
+set(LIBCEC_VERSION_PATCH 2)
+
+# cec-client
+add_subdirectory(src/cec-client)
+add_dependencies(cec-client cec)
+
+# cecc-client
+add_subdirectory(src/cecc-client)
+add_dependencies(cecc-client cec)
+
+# pyCecClient
+add_subdirectory(src/pyCecClient)
+
+# libCEC
+add_subdirectory(src/libcec)
+
+# version number
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/include/version.h.in
+ ${CMAKE_CURRENT_SOURCE_DIR}/include/version.h)
+
+# resource files for windows
+if(WIN32)
+ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/project/LibCecSharp/LibCecSharp.rc.in
+ ${CMAKE_CURRENT_SOURCE_DIR}/project/LibCecSharp/LibCecSharp.rc)
+ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/LibCecSharp/AssemblyInfo.cpp.in
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/LibCecSharp/AssemblyInfo.cpp)
+ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/project/libCEC-version.nsh.in
+ ${CMAKE_CURRENT_SOURCE_DIR}/project/libCEC-version.nsh)
+endif()
--- /dev/null
+This file is part of the libCEC(R) library.
+
+libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+libCEC(R) is a original work, containing original code.
+
+libCEC(R) is a trademark of Pulse-Eight Limited.
+
+This program is dual-licensed; 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.
+
+Alternatively, you can license this library under a commercial license,
+please contact Pulse-Eight Licensing for more information.
+
+For more information contact:
+Pulse-Eight Licensing <license@pulse-eight.com>
+ http://www.pulse-eight.com/
+ http://www.pulse-eight.net/
+
+
+
+ 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
--- /dev/null
+See debian/changelog.in
--- /dev/null
+# Doxyfile 1.6.3
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = libCEC
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = documentation
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak,
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 2
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it parses.
+# With this tag you can assign which parser to use for a given extension.
+# Doxygen has a built-in mapping, but you can override or extend it using this tag.
+# The format is ext=language, where ext is a file extension, and language is one of
+# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP,
+# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat
+# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran),
+# use: inc=Fortran f=C. Note that for custom extensions you also need to set
+# FILE_PATTERNS otherwise the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT = YES
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter
+# and setter methods for a property. Setting this option to YES (the default)
+# will make doxygen to replace the get and set methods by a property in the
+# documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
+# determine which symbols to keep in memory and which to flush to disk.
+# When the cache is full, less often used symbols will be written to disk.
+# For small to medium size projects (<1000 input files) the default value is
+# probably good enough. For larger projects a too small cache size can cause
+# doxygen to be busy swapping symbols to and from disk most of the time
+# causing a significant performance penality.
+# If the system has enough physical memory increasing the cache will improve the
+# performance by keeping more symbols in memory. Note that the value works on
+# a logarithmic scale so increasing the size by one will roughly double the
+# memory usage. The cache size is given by this formula:
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols
+
+SYMBOL_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = YES
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespace are hidden.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
+# will list include files with double quotes in the documentation
+# rather than with sharp brackets.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
+# will sort the (brief and detailed) documentation of class members so that
+# constructors and destructors are listed first. If set to NO (the default)
+# the constructors will appear in the respective orders defined by
+# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
+# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
+# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES = NO
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page. This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by
+# doxygen. The layout file controls the global structure of the generated output files
+# in an output format independent way. The create the layout file that represents
+# doxygen's defaults, run doxygen with the -l option. You can optionally specify a
+# file name after the option, if omitted DoxygenLayout.xml will be used as the name
+# of the layout file.
+
+LAYOUT_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = include
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
+
+FILE_PATTERNS =
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output. If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code. Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET =
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting
+# this to NO can help when comparing the output of multiple runs.
+
+HTML_TIMESTAMP = YES
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information.
+
+GENERATE_DOCSET = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER
+# are set, an additional index file will be generated that can be used as input for
+# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated
+# HTML documentation.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add.
+# For more information please see
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
+# will be generated, which together with the HTML files, form an Eclipse help
+# plugin. To install this plugin and make it available under the help contents
+# menu in Eclipse, the contents of the directory containing the HTML and XML
+# files needs to be copied into the plugins directory of eclipse. The name of
+# the directory within the plugins directory should be the same as
+# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
+# the help appears.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have
+# this name.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 4
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
+# Windows users are probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW = NO
+
+# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
+# and Class Hierarchy pages using a tree view instead of an ordered list.
+
+USE_INLINE_TREES = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE = 10
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box
+# for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using
+# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
+# (GENERATE_DOCSET) there is already a search function so this one should
+# typically be disabled. For large projects the javascript based search engine
+# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
+
+SEARCHENGINE = NO
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a PHP enabled web server instead of at the web client
+# using Javascript. Doxygen will generate the search PHP script and index
+# file to put on the web server. The advantage of the server
+# based approach is that it scales better to large projects and allows
+# full text search. The disadvances is that it is more difficult to setup
+# and does not have live searching capabilities.
+
+SERVER_BASED_SEARCH = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+# Note that when enabling USE_PDFLATEX this option is only used for
+# generating bitmaps for formulas in the HTML output, but not in the
+# Makefile that is written to the output directory.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include
+# source code with syntax highlighting in the LaTeX output.
+# Note that which sources are shown also depends on other settings
+# such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader. This is useful
+# if you want to understand what is going on. On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS = config.h
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED = __cplusplus
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS = NO
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = NO
+
+# By default doxygen will write a font called FreeSans.ttf to the output
+# directory and reference it in all dot files that doxygen generates. This
+# font does not include all possible unicode characters however, so when you need
+# these (or just want a differently looking font) you can specify the font name
+# using DOT_FONTNAME. You need need to make sure dot is able to find the font,
+# which can be done by putting it in a standard location or by setting the
+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
+# containing the font.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the output directory to look for the
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a
+# different font using DOT_FONTNAME you can set the path where dot
+# can find it using this tag.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = NO
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS = YES
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
--- /dev/null
+
+
+# About
+This library provides support for Pulse-Eight's USB-CEC adapter and other CEC capable hardware, like the Raspberry Pi.
+
+A list of frequently asked questions can be found on [libCEC's FAQ page] (http://libcec.pulse-eight.com/faq).
+
+.Net client applications, previously part of this repository, have been moved to [this repository](https://github.com/Pulse-Eight/cec-dotnet).
+
+# Supported platforms
+
+## Linux & BSD
+See [docs/README.linux.md](docs/README.linux.md).
+
+## Apple OS X
+See [docs/README.osx.md](docs/README.osx.md).
+
+## Microsoft Windows
+See [docs/README.windows.md](docs/README.windows.md).
+
+# Supported hardware
+* [Pulse-Eight USB-CEC Adapter](https://www.pulse-eight.com/p/104/usb-hdmi-cec-adapter)
+* [Pulse-Eight Intel NUC CEC Adapter](https://www.pulse-eight.com/p/154/intel-nuc-hdmi-cec-adapter)
+* [Raspberry Pi](https://www.raspberrypi.org/)
+* Some Exynos SoCs
+* NXP TDA995x
+* Odroid C2 (Amlogic S905)
+
+# Developers
+See [docs/README.developers.md](docs/README.developers.md).
--- /dev/null
+SET(XCOMPILE_BASE_PATH "" CACHE STRING "Path to the compiler")
+SET(XCOMPILE_PREFIX "arm-bcm2708hardfp-linux-gnueabi-" CACHE STRING "Toolchain prefix")
+SET(XCOMPILE_LIB_PATH "" CACHE STRING "Path to the libraries")
+
+SET(CMAKE_SYSTEM_NAME Linux)
+SET(CMAKE_SYSTEM_VERSION 1)
+
+# specify the cross compiler
+SET(CMAKE_C_COMPILER ${XCOMPILE_BASE_PATH}/bin/${XCOMPILE_PREFIX}gcc)
+
+SET(CMAKE_CXX_COMPILER ${XCOMPILE_BASE_PATH}/bin/${XCOMPILE_PREFIX}g++)
+
+# where is the target environment
+SET(CMAKE_FIND_ROOT_PATH ${XCOMPILE_LIB_PATH})
+
--- /dev/null
+# translate a list of libraries into a command-line that can be passed to the
+# compiler/linker. first parameter is the name of the variable that will
+# receive this list, the rest is considered the list of libraries
+function (linker_cmdline what INTO outvar FROM)
+ # if we are going to put these in regexps, we must escape period
+ string (REPLACE "." "\\." esc_dl_pref "${CMAKE_SHARED_LIBRARY_PREFIX}")
+ string (REPLACE "." "\\." esc_dl_suff "${CMAKE_SHARED_LIBRARY_SUFFIX}")
+ string (REPLACE "." "\\." esc_ar_pref "${CMAKE_STATIC_LIBRARY_PREFIX}")
+ string (REPLACE "." "\\." esc_ar_suff "${CMAKE_STATIC_LIBRARY_PREFIX}")
+
+ # CMake loves absolute paths, whereas libtool won't have any of it!
+ # (you get an error message about argument not parsed). translate each
+ # of the libraries into a linker option
+ set (deplib_list "")
+ foreach (deplib IN LISTS ARGN)
+ # starts with a hyphen already? then just add it
+ string (SUBSTRING ${deplib} 0 1 dash)
+ if (${dash} STREQUAL "-")
+ list (APPEND deplib_list ${deplib})
+ else (${dash} STREQUAL "-")
+ # otherwise, parse the name into a directory and a name
+ get_filename_component (deplib_dir ${deplib} PATH)
+ get_filename_component (deplib_orig ${deplib} NAME)
+ string (REGEX REPLACE
+ "^${esc_dl_pref}(.*)${esc_dl_suff}$"
+ "\\1"
+ deplib_name
+ ${deplib_orig}
+ )
+ string (REGEX REPLACE
+ "^${esc_ar_pref}(.*)${esc_ar_suff}$"
+ "\\1"
+ deplib_name
+ ${deplib_name}
+ )
+ # directory and name each on their own; this is somewhat
+ # unsatisfactory because it may be that a system dir is specified
+ # by an earlier directory and you start picking up libraries from
+ # there instead of the "closest" path here. also, the soversion
+ # is more or less lost. remove system default path, to lessen the
+ # chance that we pick the wrong library
+ if (NOT ((deplib_dir STREQUAL "/usr/lib") OR
+ (deplib_dir STREQUAL "/usr/${CMAKE_INSTALL_LIBDIR}")))
+ list (APPEND deplib_list "-L${deplib_dir}")
+ endif (NOT ((deplib_dir STREQUAL "/usr/lib") OR
+ (deplib_dir STREQUAL "/usr/${CMAKE_INSTALL_LIBDIR}")))
+ # if there was no translation of the name, the library is named
+ # unconventionally (.so.3gf, I'm looking at you), so pass this
+ # name unmodified to the linker switch
+ if (deplib_orig STREQUAL deplib_name)
+ list (APPEND deplib_list "-l:${deplib_orig}")
+ else (deplib_orig STREQUAL deplib_name)
+ list (APPEND deplib_list "-l${deplib_name}")
+ endif (deplib_orig STREQUAL deplib_name)
+ endif (${dash} STREQUAL "-")
+ endforeach (deplib)
+ # caller determines whether we want it returned as a list or a string
+ if ("${what}" STREQUAL "LIST")
+ set (${outvar} ${deplib_list})
+ else ("${what}" STREQUAL "LIST")
+ set (${outvar} "${deplib_list}")
+ string (REPLACE ";" " " ${outvar} "${${outvar}}")
+ endif ("${what}" STREQUAL "LIST")
+ set (${outvar} "${${outvar}}" PARENT_SCOPE)
+endfunction (linker_cmdline what INTO outvar FROM)
+
+# convert a list back to a command-line string
+function (unseparate_args var_name prefix value)
+ separate_arguments (value)
+ foreach (item IN LISTS value)
+ set (prefixed_item "${prefix}${item}")
+ if (${var_name})
+ set (${var_name} "${${var_name}} ${prefixed_item}")
+ else (${var_name})
+ set (${var_name} "${prefixed_item}")
+ endif (${var_name})
+ endforeach (item)
+ set (${var_name} "${${var_name}}" PARENT_SCOPE)
+endfunction (unseparate_args var_name prefix value)
+
+# wrapper to set variables in pkg-config file
+function (configure_pc_file name source dest prefix libdir includedir)
+ # escape set of standard strings
+ unseparate_args (includes "-I" "${${name}_INCLUDE_DIRS}")
+ unseparate_args (defs "" "${${name}_DEFINITIONS}")
+ linker_cmdline (STRING INTO libs FROM ${${name}_LIBRARIES})
+
+ # necessary to make these variables visible to configure_file
+ set (name "${${name}_NAME}")
+ set (description "${${name}_DESCRIPTION}")
+ set (major "${${name}_VERSION_MAJOR}")
+ set (minor "${${name}_VERSION_MINOR}")
+ set (target "${name}")
+ linker_cmdline (STRING INTO target from ${target})
+
+ configure_file (${source} ${dest} @ONLY)
+endfunction (configure_pc_file name source dist prefix libdir includedir)
--- /dev/null
+# - Multiarch support in object code library directories
+#
+# This module sets the following variable
+# CMAKE_INSTALL_LIBDIR to lib, lib64 or lib/x86_64-linux-gnu
+# depending on the platform; use this path
+# for platform-specific binaries.
+#
+# CMAKE_INSTALL_LIBDIR_NOARCH to lib or lib64 depending on the platform;
+# use this path for architecture-independent
+# files.
+#
+# Note that it will override the results of GNUInstallDirs if included after
+# that module.
+
+# Fedora uses lib64/ for 64-bit systems, Debian uses lib/x86_64-linux-gnu;
+# Fedora put module files in lib64/ too, but Debian uses lib/ for that
+if ("${CMAKE_SYSTEM_NAME}" MATCHES "Linux" AND
+ "${CMAKE_INSTALL_PREFIX}" STREQUAL "/usr")
+ # Debian or Ubuntu?
+ if (EXISTS "/etc/debian_version")
+ set (_libdir_def "lib/${CMAKE_LIBRARY_ARCHITECTURE}")
+ set (_libdir_noarch "lib")
+ elseif (EXISTS "/etc/fedora-release" OR
+ EXISTS "/etc/redhat-release" OR
+ EXISTS "/etc/slackware-version")
+ # 64-bit system?
+ if (CMAKE_SIZEOF_VOID_P EQUAL 8)
+ set (_libdir_noarch "lib64")
+ else (CMAKE_SIZEOF_VOID_P EQUAL 8)
+ set (_libdir_noarch "lib")
+ endif (CMAKE_SIZEOF_VOID_P EQUAL 8)
+ set (_libdir_def "${_libdir_noarch}")
+ else ()
+ set (_libdir_def "lib")
+ set (_libdir_noarch "lib")
+ endif ()
+else ()
+ set (_libdir_def "lib")
+ set (_libdir_noarch "lib")
+endif ()
+
+# let the user override if somewhere else is desirable
+set (CMAKE_INSTALL_LIBDIR "${_libdir_def}" CACHE PATH "Object code libraries")
+set (CMAKE_INSTALL_LIBDIR_NOARCH "${_libdir_noarch}" CACHE PATH "Architecture-independent library files")
+mark_as_advanced (
+ CMAKE_INSTALL_LIBDIR
+ CMAKE_INSTALL_LIBDIR_NOARCH
+ )
+
--- /dev/null
+### Debian
+Use the following commands to create a Debian package:
+```
+source /etc/lsb-release
+sed "s/#DIST#/${DISTRIB_CODENAME}/g" debian/changelog.in > debian/changelog
+dpkg-buildpackage
+```
--- /dev/null
+# Developers
+
+We provide a C, C++, Python and .NET CLR interface to the adapter.
+
+## C++ developers
+* the API can be found in `include/cec.h`
+* an example implementation can be found on https://github.com/Pulse-Eight/cec-utils/blob/master/src/cec-client/cec-client.cpp
+
+## C developers
+* the API can be found in `include/cecc.h`
+* an example implementation can be found on https://github.com/Pulse-Eight/cec-utils/blob/master/src/cecc-client/cecc-client.cpp
+
+## .NET developers
+* add a reference to `LibCecSharp.dll`
+* add `cec.dll` to your project and enable "copy to output directory"
+* an example implementation can be found on https://github.com/Pulse-Eight/cec-utils/blob/master/src/CecSharpTester/CecSharpClient.cs
+
+## Python developers
+* the API is exported to Python through Swig
+* an example implementation can be found on https://github.com/Pulse-Eight/cec-utils/blob/master/src/pyCecClient/pyCecClient.py
+
+# Developers Agreement
+
+If you wish to contribute to this project, you must first sign our contributors agreement.
+Please see [the contributors agreement] (http://www.pulse-eight.net/contributors) for more information.
--- /dev/null
+## Linux & BSD
+
+### Prerequisites
+libCEC needs the following dependencies in order to work correctly:
+* [p8-platform] (https://github.com/Pulse-Eight/platform) 2.0 or later
+* udev v151 or later
+* cdc-acm support compiled into the kernel or available as module
+
+To compile libCEC on Linux, you'll need the following dependencies:
+* [cmake 2.6 or better] (http://www.cmake.org/)
+* a supported C++ 11 compiler
+
+The following dependencies are recommended. Without them, the adapter can not
+be (fully) auto-detected.
+* pkg-config
+* udev development headers v151 or later
+* X randr development headers
+
+### Compilation
+To compile libCEC on a new Debian/Ubuntu installation, follow these instructions:
+```
+apt-get update
+apt-get install cmake libudev-dev libxrandr-dev python-dev swig
+git clone https://github.com/Pulse-Eight/libcec.git
+mkdir libcec/build
+cd libcec/build
+cmake ..
+make -j4
+sudo make install
+sudo ldconfig
+```
+
+### Raspberry Pi
+See [docs/README.raspberrypi.md](README.raspberrypi.md).
+
+### Exynos
+Pass the argument `-DHAVE_EXYNOS_API=1` to the cmake command in the compilation instructions:
+```
+cmake -DHAVE_EXYNOS_API=1 ..
+```
+
+### AOCEC
+Pass the argument `-DHAVE_AOCEC_API=1` to the cmake command in the compilation instructions:
+```
+cmake -DHAVE_AOCEC_API=1 ..
+```
+
+### TDA995x
+Pass the argument `-DHAVE_TDA995X_API=1` to the cmake command in the compilation instructions:
+```
+cmake -DHAVE_TDA995X_API=1 ..
+```
+
+### Debian / Ubuntu .deb packaging
+See [docs/README.debian.md](README.debian.md).
\ No newline at end of file
--- /dev/null
+## Apple OS X
+
+### MacPorts
+
+libCEC is available through [MacPorts] (https://www.macports.org/) and has been tested on OS X 10.9 through 10.12
+
+### Prerequisites
+To compile libCEC on OS X, you'll need the following dependencies:
+* [p8-platform] (https://github.com/Pulse-Eight/platform) 2.0 or later
+* [cmake 2.6 or better] (http://www.cmake.org/)
+* a supported C++ 11 compiler. Support for C++11 was added in OS X 10.9
+* xcode 3.2.6 or later
+* optional: [Python 3.4 or later] (https://www.python.org/) and [Swig] (http://www.swig.org/) to generate Python bindings
+* optional: libX11 and xrandr to read the sink's EDID, used to determine the PC's HDMI physical address
+
+### Compilation
+To compile, execute the following command:
+```
+mkdir build
+cd build
+cmake ..
+make
+sudo make install
+```
+
+_Note:_ You may need to copy pkg.m4 to your m4 sources directory
--- /dev/null
+### Raspberry Pi
+If you're compiling for a Raspberry Pi, then the path to the required headers and libraries can be set manually, in case it's not in a standard system directory:
+```
+cmake -DRPI_INCLUDE_DIR=/path/to/vc/include \
+ -DRPI_LIB_DIR=/path/to/vc/lib \
+ ..
+```
+
+The headers and libraries are installed in /opt/vc when using Raspbian, but they may be installed somewhere else when using another distribution. Please ask the distribution's maintainers for help in case compilation fails and you're not using Raspbian.
+
+If you're cross compiling, then you can set the correct toolchain like this (for the Raspberry Pi):
+```
+cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/CrossCompile.cmake \
+ -DXCOMPILE_BASE_PATH=/path/to/tools/arm-bcm2708/arm-bcm2708hardfp-linux-gnueabi \
+ -DXCOMPILE_LIB_PATH=/path/to/firmware/hardfp/opt/vc/lib \
+ -DRPI_INCLUDE_DIR=/path/to/firmware/hardfp/opt/vc/include \
+ -DRPI_LIB_DIR=/path/to/firmware/hardfp/opt/vc/lib \
+ ..
+```
+
+To compile libCEC on a new Raspbian installation, follow these instructions:
+```
+sudo apt-get update
+sudo apt-get install cmake libudev-dev libxrandr-dev python-dev swig
+cd
+git clone https://github.com/Pulse-Eight/platform.git
+mkdir platform/build
+cd platform/build
+cmake ..
+make
+sudo make install
+cd
+git clone https://github.com/Pulse-Eight/libcec.git
+mkdir libcec/build
+cd libcec/build
+cmake -DRPI_INCLUDE_DIR=/opt/vc/include -DRPI_LIB_DIR=/opt/vc/lib ..
+make -j4
+sudo make install
+sudo ldconfig
+```
\ No newline at end of file
--- /dev/null
+## Microsoft Windows
+
+### Developing a .Net application
+Building this library is only required if you want to change libCEC or LibCecSharp internally.
+To develop a .Net application that uses LibCecSharp:
+* download the latest binary version from [our website](http://libcec.pulse-eight.com/Downloads)
+* add a reference to LibCecSharp.dll for the target architecture (x86/amd64). It's installed to `C:\Program Files (x86)\Pulse-Eight\USB-CEC Adapter` by default
+* add cec.dll to your project from the same directory
+* right click on cec.dll in the project explorer
+* change the copy mode to "copy if newer"
+
+Example implementations can be found on [Github](https://github.com/Pulse-Eight/cec-dotnet).
+
+### Prerequisites
+To compile libCEC on Windows, you'll need the following dependencies:
+* [p8-platform] (https://github.com/Pulse-Eight/platform) 2.0 or later
+* [cmake 2.6 or better] (http://www.cmake.org/)
+* [Visual Studio 2008 (v90) Professional] (https://www.visualstudio.com/)
+* [Visual Studio 2010 (v110) (for x64 builds: Professional)] (https://www.visualstudio.com/)
+* [Visual Studio 2013 (v120) or 2015 (v140)] (https://www.visualstudio.com/)
+* To create an installer, you'll need [Nullsoft's NSIS] (http://nsis.sourceforge.net/)
+
+Visual Studio version must be installed in ascending order, and each version of Visual Studio must be started at least once before the next version is installed.
+
+The reason for needing all of these versions is that LibCecSharp targets .Net 2.0, to maximise compatibility, but libCEC itself requires C++11.
+This means that LibCecSharp requires the 9.0 toolchain and libCEC the 12.0 toolchain.
+Because of changes in Visual Studio's build system, Visual Studio 2010 Professional is required to build LibCecSharp in Visual Studio 2013.
+
+### Installation check
+
+You can check whether all versions of Visual Studio got installed correctly by checking if the following directories exist:
+* Visual Studio 2008: `X:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\include\msclr`
+* Visual Studio 2010: `X:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\Platforms\Win32\PlatformToolsets\v90`
+* Visual Studio 2010 x64: `X:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\Platforms\x64\PlatformToolsets\v90`
+
+### Visual Studio 2015
+The build scripts have been configured for building with Visual Studio 2013. To use Visual Studio 2015, change `windows\build.cmd`: `SET VSVERSION=12` to `SET VSVERSION=14`.
+
+### Compilation
+To compile libCEC, follow these instructions:
+* `git submodule update --init --recursive`
+* run `windows\build.cmd` to build libCEC and LibCecSharp
+
+To develop for libCEC in Visual Studio:
+* `git submodule update --init --recursive`
+* run `windows\visual-studio.cmd`
+
+To build an installer on Windows:
+* `git submodule update --init --recursive`
+* run `windows\create-installer.cmd`
+* the installer is stored as `build\libCEC-VERSION.exe`
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#ifndef CECEXPORTS_H_
+#define CECEXPORTS_H_
+
+#include "cectypes.h"
+#include <string>
+
+namespace CEC
+{
+ /*!
+ * To create a new libCEC instance, call CECInitialise() and pass the
+ * configuration as argument. Then call Open() to open a connection to the
+ * adapter. Close() closes the connection and CECDestroy() cleans up the
+ * libCEC instance.
+ *
+ * libCEC can send commands to other devices on the CEC bus via the methods
+ * on this interface, and all commands that libCEC received are sent back
+ * to the application via callback methods. The callback methods can be
+ * found in cectypes.h, ICECCallbacks.
+ */
+ class ICECAdapter
+ {
+ public:
+ virtual ~ICECAdapter() {};
+ /*! @name Adapter methods */
+ //@{
+
+ /*!
+ * @brief Open a connection to the CEC adapter.
+ * @param strPort The path to the port.
+ * @param iTimeoutMs Connection timeout in ms.
+ * @return True when connected, false otherwise.
+ */
+ virtual bool Open(const char *strPort, uint32_t iTimeoutMs = 10000) = 0;
+
+ /*!
+ * @brief Close the connection to the CEC adapter.
+ */
+ virtual void Close(void) = 0;
+
+ /*!
+ * @brief Sends a ping command to the adapter, to check if it's responding.
+ * @return True when the ping was successful, false otherwise.
+ */
+ virtual bool PingAdapter(void) = 0;
+
+ /*!
+ * @brief Start the bootloader of the CEC adapter. Closes the connection when successful.
+ * @return True when the command was sent successfully, false otherwise.
+ */
+ virtual bool StartBootloader(void) = 0;
+ //@}
+
+ /*!
+ * @brief Transmit a raw CEC command over the CEC line.
+ * @param data The command to send.
+ * @return True when the data was sent and acked, false otherwise.
+ */
+ virtual bool Transmit(const cec_command &data) = 0;
+
+ /*!
+ * @brief Change the logical address on the CEC bus of the CEC adapter. libCEC automatically assigns a logical address, and this method is only available for debugging purposes.
+ * @param iLogicalAddress The CEC adapter's new logical address.
+ * @return True when the logical address was set successfully, false otherwise.
+ */
+ virtual bool SetLogicalAddress(cec_logical_address iLogicalAddress = CECDEVICE_PLAYBACKDEVICE1) = 0;
+
+ /*!
+ * @brief Change the physical address (HDMI port) of the CEC adapter. libCEC will try to autodetect the physical address when connecting. If it did, it's set in libcec_configuration.
+ * @param iPhysicalAddress The CEC adapter's new physical address.
+ * @brief True when the physical address was set successfully, false otherwise.
+ */
+ virtual bool SetPhysicalAddress(uint16_t iPhysicalAddress = CEC_DEFAULT_PHYSICAL_ADDRESS) = 0;
+
+ /*!
+ * @brief Power on the given CEC capable devices. If CECDEVICE_BROADCAST is used, then wakeDevice in libcec_configuration will be used.
+ * @param address The logical address to power on.
+ * @return True when the command was sent successfully, false otherwise.
+ */
+ virtual bool PowerOnDevices(cec_logical_address address = CECDEVICE_TV) = 0;
+
+ /*!
+ * @brief Put the given CEC capable devices in standby mode. If CECDEVICE_BROADCAST is used, then standbyDevices in libcec_configuration will be used.
+ * @brief address The logical address of the device to put in standby.
+ * @return True when the command was sent successfully, false otherwise.
+ */
+ virtual bool StandbyDevices(cec_logical_address address = CECDEVICE_BROADCAST) = 0;
+
+ /*!
+ * @brief Change the active source to a device type handled by libCEC. Use CEC_DEVICE_TYPE_RESERVED to make the default type used by libCEC active.
+ * @param type The new active source. Leave empty to use the primary type
+ * @return True when the command was sent successfully, false otherwise.
+ */
+ virtual bool SetActiveSource(cec_device_type type = CEC_DEVICE_TYPE_RESERVED) = 0;
+
+ /*!
+ * @brief Change the deck control mode, if this adapter is registered as playback or recording device.
+ * @param mode The new control mode.
+ * @param bSendUpdate True to send the new status over the CEC line.
+ * @return True if set, false otherwise.
+ */
+ virtual bool SetDeckControlMode(cec_deck_control_mode mode, bool bSendUpdate = true) = 0;
+
+ /*!
+ * @brief Change the deck info, if this adapter is a playback or recording device.
+ * @param info The new deck info.
+ * @param bSendUpdate True to send the new status over the CEC line.
+ * @return True if set, false otherwise.
+ */
+ virtual bool SetDeckInfo(cec_deck_info info, bool bSendUpdate = true) = 0;
+
+ /*!
+ * @brief Broadcast a message that notifies connected CEC capable devices that this device is no longer the active source.
+ * @return True when the command was sent successfully, false otherwise.
+ */
+ virtual bool SetInactiveView(void) = 0;
+
+ /*!
+ * @brief Change the menu state. This value is already changed by libCEC automatically if a device is (de)activated.
+ * @param state The new state.
+ * @param bSendUpdate True to send the new status over the CEC line.
+ * @return True if set, false otherwise.
+ */
+ virtual bool SetMenuState(cec_menu_state state, bool bSendUpdate = true) = 0;
+
+ /*!
+ * @brief Display a message on the device with the given logical address. Not supported by most TVs.
+ * @param iLogicalAddress The logical address of the device to display the message on.
+ * @param duration The duration of the message
+ * @param strMessage The message to display.
+ * @return True when the command was sent, false otherwise.
+ */
+ virtual bool SetOSDString(cec_logical_address iLogicalAddress, cec_display_control duration, const char *strMessage) = 0;
+
+ /*!
+ * @brief Enable or disable monitoring mode, for debugging purposes. If monitoring mode is enabled, libCEC won't respond to any command, but only log incoming data.
+ * @param bEnable True to enable, false to disable.
+ * @return True when switched successfully, false otherwise.
+ */
+ virtual bool SwitchMonitoring(bool bEnable) = 0;
+
+ /*!
+ * @brief Get the CEC version of the device with the given logical address
+ * @param iLogicalAddress The logical address of the device to get the CEC version for.
+ * @return The version or CEC_VERSION_UNKNOWN when the version couldn't be fetched.
+ */
+ virtual cec_version GetDeviceCecVersion(cec_logical_address iLogicalAddress) = 0;
+
+ /*!
+ * @brief Get the menu language of the device with the given logical address
+ * @param iLogicalAddress The logical address of the device to get the menu language for.
+ * @return The requested menu language, or '???' if unknown
+ */
+ virtual std::string GetDeviceMenuLanguage(cec_logical_address iLogicalAddress) = 0;
+
+ /*!
+ * @brief Get the vendor ID of the device with the given logical address.
+ * @param iLogicalAddress The logical address of the device to get the vendor ID for.
+ * @return The vendor ID or 0 if it wasn't found.
+ */
+ virtual uint32_t GetDeviceVendorId(cec_logical_address iLogicalAddress) = 0;
+
+ /*!
+ * @brief Get the power status of the device with the given logical address.
+ * @param iLogicalAddress The logical address of the device to get the power status for.
+ * @return The power status or CEC_POWER_STATUS_UNKNOWN if it wasn't found.
+ */
+ virtual cec_power_status GetDevicePowerStatus(cec_logical_address iLogicalAddress) = 0;
+
+ /*!
+ * @brief Sends a POLL message to a device, to check if it's present and responding.
+ * @param iLogicalAddress The device to send the message to.
+ * @return True if the POLL was acked, false otherwise.
+ */
+ virtual bool PollDevice(cec_logical_address iLogicalAddress) = 0;
+
+ /*!
+ * @return The logical addresses of the devices that are active on the bus, including those handled by libCEC.
+ */
+ virtual cec_logical_addresses GetActiveDevices(void) = 0;
+
+ /*!
+ * @brief Check whether a device is active on the bus.
+ * @param iLogicalAddress The address to check.
+ * @return True when active, false otherwise.
+ */
+ virtual bool IsActiveDevice(cec_logical_address iLogicalAddress) = 0;
+
+ /*!
+ * @brief Check whether a device of the given type is active on the bus.
+ * @param type The type to check.
+ * @return True when active, false otherwise.
+ */
+ virtual bool IsActiveDeviceType(cec_device_type type) = 0;
+
+ /*!
+ * @brief Sends a volume up keypress to an audiosystem if it's present.
+ * @param bSendRelease Send a key release after the keypress.
+ * @return The new audio status.
+ */
+ virtual uint8_t VolumeUp(bool bSendRelease = true) = 0;
+
+ /*!
+ * @brief Sends a volume down keypress to an audiosystem if it's present.
+ * @param bSendRelease Send a key release after the keypress.
+ * @return The new audio status.
+ */
+ virtual uint8_t VolumeDown(bool bSendRelease = true) = 0;
+
+ /*!
+ * @brief Send a keypress to a device on the CEC bus.
+ * @param iDestination The logical address of the device to send the message to.
+ * @param key The key to send.
+ * @param bWait True to wait for a response, false otherwise.
+ * @return True when the keypress was acked, false otherwise.
+ */
+ virtual bool SendKeypress(cec_logical_address iDestination, cec_user_control_code key, bool bWait = false) = 0;
+
+ /*!
+ * @brief Send a key release to a device on the CEC bus.
+ * @param iDestination The logical address of the device to send the message to.
+ * @param bWait True to wait for a response, false otherwise.
+ * @return True when the key release was acked, false otherwise.
+ */
+ virtual bool SendKeyRelease(cec_logical_address iDestination, bool bWait = false) = 0;
+
+ /*!
+ * @brief Get the OSD name of a device on the CEC bus.
+ * @param iLogicalAddress The device to get the OSD name for.
+ * @return The requested OSD name, or an empty string if unknown
+ */
+ virtual std::string GetDeviceOSDName(cec_logical_address iAddress) = 0;
+
+ /*!
+ * @brief Get the logical address of the device that is currently the active source on the CEC bus.
+ * @return The active source or CECDEVICE_UNKNOWN when unknown.
+ */
+ virtual cec_logical_address GetActiveSource(void) = 0;
+
+ /*!
+ * @brief Check whether a device is currently the active source on the CEC bus.
+ * @param iLogicalAddress The logical address of the device to check.
+ * @return True when it is the active source, false otherwise.
+ */
+ virtual bool IsActiveSource(cec_logical_address iLogicalAddress) = 0;
+
+ /*!
+ * @brief Sets the stream path to the device on the given logical address.
+ * @param iLogicalAddress The address to activate.
+ * @return True when the command was sent, false otherwise.
+ */
+ virtual bool SetStreamPath(cec_logical_address iLogicalAddress) = 0;
+
+ /*!
+ * @brief Sets the stream path to the device on the given physical address.
+ * @param iPhysicalAddress The address to activate.
+ * @return True when the command was sent, false otherwise.
+ */
+ virtual bool SetStreamPath(uint16_t iPhysicalAddress) = 0;
+
+ /*!
+ * @return The list of logical addresses that libCEC is controlling
+ */
+ virtual cec_logical_addresses GetLogicalAddresses(void) = 0;
+
+ /*!
+ * @brief Get libCEC's current configuration.
+ * @param configuration The configuration.
+ * @return True when the configuration was updated, false otherwise.
+ */
+ virtual bool GetCurrentConfiguration(libcec_configuration *configuration) = 0;
+
+ /*!
+ * @brief Change libCEC's configuration.
+ * @param configuration The new configuration.
+ * @return True when the configuration was changed successfully, false otherwise.
+ */
+ virtual bool SetConfiguration(const libcec_configuration *configuration) = 0;
+
+ /*!
+ * @return True when this CEC adapter can persist the user configuration, false otherwise.
+ */
+ virtual bool CanPersistConfiguration(void) = 0;
+
+ /*!
+ * @brief Persist the given configuration in adapter (if supported)
+ * @brief configuration The configuration to store.
+ * @return True when the configuration was persisted, false otherwise.
+ */
+ virtual bool PersistConfiguration(libcec_configuration *configuration) = 0;
+
+ /*!
+ * @brief Tell libCEC to poll for active devices on the bus.
+ */
+ virtual void RescanActiveDevices(void) = 0;
+
+ /*!
+ * @return true when libCEC is the active source on the bus, false otherwise.
+ */
+ virtual bool IsLibCECActiveSource(void) = 0;
+
+ /*!
+ * @brief Get information about the given CEC adapter.
+ * @param strPort The port to which the device is connected
+ * @param config The device configuration
+ * @param iTimeoutMs The timeout in milliseconds
+ * @return True when the device was found, false otherwise
+ */
+ virtual bool GetDeviceInformation(const char *strPort, libcec_configuration *config, uint32_t iTimeoutMs = 10000) = 0;
+
+ /*!
+ * @brief Set and enable the callback methods. If this method is not called, the GetNext...() methods will have to be used.
+ * @param cbParam Parameter to pass to callback methods.
+ * @param callbacks The callbacks to set.
+ * @return True when enabled, false otherwise.
+ */
+ virtual bool EnableCallbacks(void *cbParam, ICECCallbacks *callbacks) = 0;
+
+ /*!
+ * @brief Changes the active HDMI port.
+ * @param iBaseDevice The device to which this libCEC is connected.
+ * @param iPort The new port number.
+ * @return True when changed, false otherwise.
+ */
+ virtual bool SetHDMIPort(cec_logical_address iBaseDevice, uint8_t iPort) = 0;
+
+ /*!
+ * @brief Get the physical address of the device with the given logical address.
+ * @param iLogicalAddress The logical address of the device to get the physical address for.
+ * @return The physical address or 0 if it wasn't found.
+ */
+ virtual uint16_t GetDevicePhysicalAddress(cec_logical_address iLogicalAddress) = 0;
+
+ /*!
+ * @return A string with information about how libCEC was compiled.
+ */
+ virtual const char *GetLibInfo(void) = 0;
+
+ /*!
+ * @brief Calling this method will initialise the host on which libCEC is running.
+ * Calling this method will initialise the host on which libCEC is running. On the RPi, it calls
+ * bcm_host_init(), which may only be called once per process, and is called by any process using
+ * the video api on that system. So only call this method if libCEC is used in an application that
+ * does not already initialise the video api.
+ *
+ * Should be called as first call to libCEC, directly after CECInitialise() and before using Open()
+ */
+ virtual void InitVideoStandalone(void) = 0;
+
+ /*!
+ * @return The (virtual) USB vendor id
+ */
+ virtual uint16_t GetAdapterVendorId(void) const = 0;
+
+ /*!
+ * @return The (virtual) USB product id
+ */
+ virtual uint16_t GetAdapterProductId(void) const = 0;
+
+ virtual const char* ToString(const cec_menu_state state) = 0;
+ virtual const char* ToString(const cec_version version) = 0;
+ virtual const char* ToString(const cec_power_status status) = 0;
+ virtual const char* ToString(const cec_logical_address address) = 0;
+ virtual const char* ToString(const cec_deck_control_mode mode) = 0;
+ virtual const char* ToString(const cec_deck_info status) = 0;
+ virtual const char* ToString(const cec_opcode opcode) = 0;
+ virtual const char* ToString(const cec_system_audio_status mode) = 0;
+ virtual const char* ToString(const cec_audio_status status) = 0;
+ virtual const char* ToString(const cec_vendor_id vendor) { return VendorIdToString((uint32_t)vendor); }
+ virtual const char* ToString(const cec_device_type type) = 0;
+ virtual const char* ToString(const cec_user_control_code key) = 0;
+ virtual const char* ToString(const cec_adapter_type type) = 0;
+ virtual std::string VersionToString(uint32_t version) = 0;
+ virtual void PrintVersion(uint32_t version, char* buf, size_t bufSize) = 0;
+ virtual const char* VendorIdToString(uint32_t vendor) = 0;
+
+ /*!
+ * @brief Toggle the mute status of the AVR (if present)
+ * @return The new audio status.
+ */
+ virtual uint8_t AudioToggleMute(void) = 0;
+
+ /*!
+ * @brief Mute the AVR (if present)
+ * @return The new audio status.
+ */
+ virtual uint8_t AudioMute(void) = 0;
+
+ /*!
+ * @brief Mute the AVR (if connected)
+ * @return The new audio status.
+ */
+ virtual uint8_t AudioUnmute(void) = 0;
+
+ /*!
+ * @brief Get the current audio status (if an AVR is connected)
+ * @return The current audio status, or cec_audio_status if unknown.
+ */
+ virtual uint8_t AudioStatus(void) = 0;
+
+ /*!
+ * @brief Try to find all connected CEC adapters.
+ * @param deviceList The vector to store device descriptors in.
+ * @param iBufSize The size of the deviceList buffer.
+ * @param strDevicePath Optional device path. Only adds device descriptors that match the given device path.
+ * @param bQuickScan True to do a "quick scan", which will not open a connection to the adapter. Firmware version information and the exact device type will be missing
+ * @return The number of devices that were found, or -1 when an error occurred.
+ */
+ virtual int8_t DetectAdapters(cec_adapter_descriptor *deviceList, uint8_t iBufSize, const char *strDevicePath = NULL, bool bQuickScan = false) = 0;
+
+ /*!
+ * Create a new cec_command from a string
+ * @param strCommand The string with the command data
+ * @return The command
+ */
+ virtual cec_command CommandFromString(const char* strCommand) = 0;
+
+ /**
+ * Enable or disable system audio mode
+ * @param enable True to enable, false to disable
+ * @return True if the command was sent, false otherwise
+ */
+ virtual bool AudioEnable(bool enable) = 0;
+ };
+};
+
+/*!
+ * @brief Unload the CEC adapter library.
+ */
+extern "C" DECLSPEC void CECDestroy(CEC::ICECAdapter *instance);
+
+/*!
+ * @brief Load the CEC adapter library.
+ * @param configuration The configuration to pass to libCEC
+ * @return An instance of ICECAdapter or NULL on error.
+ */
+extern "C" DECLSPEC CEC::ICECAdapter* CECInitialise(CEC::libcec_configuration *configuration);
+
+/*!
+ * @brief Try to connect to the adapter and send the "start bootloader" command, without initialising libCEC and going through all checks
+ * @return True when the command was send, false otherwise.
+ */
+extern "C" DECLSPEC bool CECStartBootloader(void);
+
+#endif /* CECEXPORTS_H_ */
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#ifndef CECEXPORTS_C_H_
+#define CECEXPORTS_C_H_
+
+#include "cectypes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+#define CEC_NAMESPACE CEC::
+typedef CEC::ICECAdapter* libcec_connection_t;
+#else
+#define CEC_NAMESPACE
+typedef void* libcec_connection_t;
+#endif
+
+extern DECLSPEC libcec_connection_t libcec_initialise(CEC_NAMESPACE libcec_configuration* configuration);
+extern DECLSPEC void libcec_destroy(libcec_connection_t connection);
+extern DECLSPEC int libcec_open(libcec_connection_t connection, const char* strPort, uint32_t iTimeout);
+extern DECLSPEC void libcec_close(libcec_connection_t connection);
+extern DECLSPEC void libcec_clear_configuration(CEC_NAMESPACE libcec_configuration* configuration);
+extern DECLSPEC int libcec_enable_callbacks(libcec_connection_t connection, void* cbParam, CEC_NAMESPACE ICECCallbacks* callbacks);
+extern DECLSPEC int8_t libcec_find_adapters(libcec_connection_t connection, CEC_NAMESPACE cec_adapter* deviceList, uint8_t iBufSize, const char* strDevicePath);
+extern DECLSPEC int libcec_ping_adapters(libcec_connection_t connection);
+extern DECLSPEC int libcec_start_bootloader(libcec_connection_t connection);
+extern DECLSPEC int libcec_power_on_devices(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address address);
+extern DECLSPEC int libcec_standby_devices(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address address);
+extern DECLSPEC int libcec_set_active_source(libcec_connection_t connection, CEC_NAMESPACE cec_device_type type);
+extern DECLSPEC int libcec_set_deck_control_mode(libcec_connection_t connection, CEC_NAMESPACE cec_deck_control_mode mode, int bSendUpdate);
+extern DECLSPEC int libcec_set_deck_info(libcec_connection_t connection, CEC_NAMESPACE cec_deck_info info, int bSendUpdate);
+extern DECLSPEC int libcec_set_inactive_view(libcec_connection_t connection);
+extern DECLSPEC int libcec_set_menu_state(libcec_connection_t connection, CEC_NAMESPACE cec_menu_state state, int bSendUpdate);
+extern DECLSPEC int libcec_transmit(libcec_connection_t connection, const CEC_NAMESPACE cec_command* data);
+extern DECLSPEC int libcec_set_logical_address(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address iLogicalAddress);
+extern DECLSPEC int libcec_set_physical_address(libcec_connection_t connection, uint16_t iPhysicalAddress);
+extern DECLSPEC int libcec_set_osd_string(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address iLogicalAddress, CEC_NAMESPACE cec_display_control duration, const char* strMessage);
+extern DECLSPEC int libcec_switch_monitoring(libcec_connection_t connection, int bEnable);
+extern DECLSPEC CEC_NAMESPACE cec_version libcec_get_device_cec_version(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address iLogicalAddress);
+extern DECLSPEC int libcec_get_device_menu_language(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address iLogicalAddress, CEC_NAMESPACE cec_menu_language language);
+extern DECLSPEC uint32_t libcec_get_device_vendor_id(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address iLogicalAddress);
+extern DECLSPEC uint16_t libcec_get_device_physical_address(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address iLogicalAddress);
+extern DECLSPEC CEC_NAMESPACE cec_logical_address libcec_get_active_source(libcec_connection_t connection);
+extern DECLSPEC int libcec_is_active_source(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address iAddress);
+extern DECLSPEC CEC_NAMESPACE cec_power_status libcec_get_device_power_status(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address iLogicalAddress);
+extern DECLSPEC int libcec_poll_device(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address iLogicalAddress);
+extern DECLSPEC CEC_NAMESPACE cec_logical_addresses libcec_get_active_devices(libcec_connection_t connection);
+extern DECLSPEC int libcec_is_active_device(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address address);
+extern DECLSPEC int libcec_is_active_device_type(libcec_connection_t connection, CEC_NAMESPACE cec_device_type type);
+extern DECLSPEC int libcec_set_hdmi_port(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address baseDevice, uint8_t iPort);
+extern DECLSPEC int libcec_volume_up(libcec_connection_t connection, int bSendRelease);
+extern DECLSPEC int libcec_volume_down(libcec_connection_t connection, int bSendRelease);
+extern DECLSPEC int libcec_mute_audio(libcec_connection_t connection, int bSendRelease);
+extern DECLSPEC int libcec_send_keypress(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address iDestination, CEC_NAMESPACE cec_user_control_code key, int bWait);
+extern DECLSPEC int libcec_send_key_release(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address iDestination, int bWait);
+extern DECLSPEC int libcec_get_device_osd_name(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address iAddress, CEC_NAMESPACE cec_osd_name name);
+extern DECLSPEC int libcec_set_stream_path_logical(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address iAddress);
+extern DECLSPEC int libcec_set_stream_path_physical(libcec_connection_t connection, uint16_t iPhysicalAddress);
+extern DECLSPEC CEC_NAMESPACE cec_logical_addresses libcec_get_logical_addresses(libcec_connection_t connection);
+extern DECLSPEC int libcec_get_current_configuration(libcec_connection_t connection, CEC_NAMESPACE libcec_configuration* configuration);
+extern DECLSPEC int libcec_can_persist_configuration(libcec_connection_t connection);
+extern DECLSPEC int libcec_persist_configuration(libcec_connection_t connection, CEC_NAMESPACE libcec_configuration* configuration);
+extern DECLSPEC int libcec_set_configuration(libcec_connection_t connection, const CEC_NAMESPACE libcec_configuration* configuration);
+extern DECLSPEC void libcec_rescan_devices(libcec_connection_t connection);
+extern DECLSPEC int libcec_is_libcec_active_source(libcec_connection_t connection);
+extern DECLSPEC int libcec_get_device_information(libcec_connection_t connection, const char* strPort, CEC_NAMESPACE libcec_configuration* config, uint32_t iTimeoutMs);
+extern DECLSPEC const char* libcec_get_lib_info(libcec_connection_t connection);
+extern DECLSPEC void libcec_init_video_standalone(libcec_connection_t connection);
+extern DECLSPEC uint16_t libcec_get_adapter_vendor_id(libcec_connection_t connection);
+extern DECLSPEC uint16_t libcec_get_adapter_product_id(libcec_connection_t connection);
+extern DECLSPEC uint8_t libcec_audio_toggle_mute(libcec_connection_t connection);
+extern DECLSPEC uint8_t libcec_audio_mute(libcec_connection_t connection);
+extern DECLSPEC uint8_t libcec_audio_unmute(libcec_connection_t connection);
+extern DECLSPEC uint8_t libcec_audio_get_status(libcec_connection_t connection);
+extern DECLSPEC int8_t libcec_detect_adapters(libcec_connection_t connection, CEC_NAMESPACE cec_adapter_descriptor* deviceList, uint8_t iBufSize, const char* strDevicePath, int bQuickScan);
+#ifdef SWIG
+%cstring_bounded_output(char* buf, 50);
+#endif
+extern DECLSPEC void libcec_menu_state_to_string(const CEC_NAMESPACE cec_menu_state state, char* buf, size_t bufsize);
+extern DECLSPEC void libcec_cec_version_to_string(const CEC_NAMESPACE cec_version version, char* buf, size_t bufsize);
+extern DECLSPEC void libcec_power_status_to_string(const CEC_NAMESPACE cec_power_status status, char* buf, size_t bufsize);
+extern DECLSPEC void libcec_logical_address_to_string(const CEC_NAMESPACE cec_logical_address address, char* buf, size_t bufsize);
+extern DECLSPEC void libcec_deck_control_mode_to_string(const CEC_NAMESPACE cec_deck_control_mode mode, char* buf, size_t bufsize);
+extern DECLSPEC void libcec_deck_status_to_string(const CEC_NAMESPACE cec_deck_info status, char* buf, size_t bufsize);
+extern DECLSPEC void libcec_opcode_to_string(const CEC_NAMESPACE cec_opcode opcode, char* buf, size_t bufsize);
+extern DECLSPEC void libcec_system_audio_status_to_string(const CEC_NAMESPACE cec_system_audio_status mode, char* buf, size_t bufsize);
+extern DECLSPEC void libcec_audio_status_to_string(const CEC_NAMESPACE cec_audio_status status, char* buf, size_t bufsize);
+extern DECLSPEC void libcec_vendor_id_to_string(const CEC_NAMESPACE cec_vendor_id vendor, char* buf, size_t bufsize);
+extern DECLSPEC void libcec_user_control_key_to_string(const CEC_NAMESPACE cec_user_control_code key, char* buf, size_t bufsize);
+extern DECLSPEC void libcec_adapter_type_to_string(const CEC_NAMESPACE cec_adapter_type type, char* buf, size_t bufsize);
+extern DECLSPEC void libcec_version_to_string(uint32_t version, char* buf, size_t bufsize);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* CECEXPORTS_C_H_ */
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "cecc.h"
+
+#include <stdio.h>
+#if defined(_WIN32) || defined(_WIN64)
+#include <windows.h>
+#include <conio.h>
+typedef HINSTANCE libcecc_lib_instance_t;
+#else
+#include <dlfcn.h>
+typedef void* libcecc_lib_instance_t;
+#ifndef CDECL
+#define CDECL
+#endif
+#endif
+
+static libcecc_lib_instance_t libcecc_load_library(const char* strLib);
+static void libcecc_close_library(libcecc_lib_instance_t lib);
+static void* libcecc_resolve(void* lib, const char* name);
+
+#define _libcecc_resolve(lib, tar, name, method) \
+ do { \
+ tar = (method) libcecc_resolve(lib, name); \
+ if (tar == NULL) \
+ { \
+ libcecc_close_library(lib); \
+ return -1; \
+ } \
+ } while(0)
+
+typedef struct {
+ libcec_connection_t connection;
+ libcecc_lib_instance_t lib_instance;
+ void (CDECL *destroy)(libcec_connection_t connection);
+ int (CDECL *open)(libcec_connection_t connection, const char* strPort, uint32_t iTimeout);
+ void (CDECL *close)(libcec_connection_t connection);
+ void (CDECL *clear_configuration)(CEC_NAMESPACE libcec_configuration* configuration);
+ int (CDECL *enable_callbacks)(libcec_connection_t connection, void* cbParam, CEC_NAMESPACE ICECCallbacks* callbacks);
+ int8_t (CDECL *find_adapters)(libcec_connection_t connection, CEC_NAMESPACE cec_adapter* deviceList, uint8_t iBufSize, const char* strDevicePath);
+ int (CDECL *ping_adapters)(libcec_connection_t connection);
+ int (CDECL *start_bootloader)(libcec_connection_t connection);
+ int (CDECL *power_on_devices)(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address address);
+ int (CDECL *standby_devices)(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address address);
+ int (CDECL *set_active_source)(libcec_connection_t connection, CEC_NAMESPACE cec_device_type type);
+ int (CDECL *set_deck_control_mode)(libcec_connection_t connection, CEC_NAMESPACE cec_deck_control_mode mode, int bSendUpdate);
+ int (CDECL *set_deck_info)(libcec_connection_t connection, CEC_NAMESPACE cec_deck_info info, int bSendUpdate);
+ int (CDECL *set_inactive_view)(libcec_connection_t connection);
+ int (CDECL *set_menu_state)(libcec_connection_t connection, CEC_NAMESPACE cec_menu_state state, int bSendUpdate);
+ int (CDECL *transmit)(libcec_connection_t connection, const CEC_NAMESPACE cec_command* data);
+ int (CDECL *set_logical_address)(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address iLogicalAddress);
+ int (CDECL *set_physical_address)(libcec_connection_t connection, uint16_t iPhysicalAddress);
+ int (CDECL *set_osd_string)(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address iLogicalAddress, CEC_NAMESPACE cec_display_control duration, const char* strMessage);
+ int (CDECL *switch_monitoring)(libcec_connection_t connection, int bEnable);
+ CEC_NAMESPACE cec_version (CDECL *get_device_cec_version)(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address iLogicalAddress);
+ int (CDECL *get_device_menu_language)(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address iLogicalAddress, CEC_NAMESPACE cec_menu_language language);
+ uint64_t (CDECL *get_device_vendor_id)(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address iLogicalAddress);
+ uint16_t (CDECL *get_device_physical_address)(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address iLogicalAddress);
+ CEC_NAMESPACE cec_logical_address (CDECL *get_active_source)(libcec_connection_t connection);
+ int (CDECL *is_active_source)(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address iAddress);
+ CEC_NAMESPACE cec_power_status (CDECL *get_device_power_status)(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address iLogicalAddress);
+ int (CDECL *poll_device)(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address iLogicalAddress);
+ CEC_NAMESPACE cec_logical_addresses (CDECL *get_active_devices)(libcec_connection_t connection);
+ int (CDECL *is_active_device)(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address address);
+ int (CDECL *is_active_device_type)(libcec_connection_t connection, CEC_NAMESPACE cec_device_type type);
+ int (CDECL *set_hdmi_port)(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address baseDevice, uint8_t iPort);
+ int (CDECL *volume_up)(libcec_connection_t connection, int bSendRelease);
+ int (CDECL *volume_down)(libcec_connection_t connection, int bSendRelease);
+ int (CDECL *mute_audio)(libcec_connection_t connection, int bSendRelease);
+ int (CDECL *send_keypress)(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address iDestination, CEC_NAMESPACE cec_user_control_code key, int bWait);
+ int (CDECL *send_key_release)(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address iDestination, int bWait);
+ int (CDECL *get_device_osd_name)(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address iAddress, CEC_NAMESPACE cec_osd_name name);
+ int (CDECL *set_stream_path_logical)(libcec_connection_t connection, CEC_NAMESPACE cec_logical_address iAddress);
+ int (CDECL *set_stream_path_physical)(libcec_connection_t connection, uint16_t iPhysicalAddress);
+ CEC_NAMESPACE cec_logical_addresses (CDECL *get_logical_addresses)(libcec_connection_t connection);
+ int (CDECL *get_current_configuration)(libcec_connection_t connection, CEC_NAMESPACE libcec_configuration* configuration);
+ int (CDECL *can_persist_configuration)(libcec_connection_t connection);
+ int (CDECL *persist_configuration)(libcec_connection_t connection, CEC_NAMESPACE libcec_configuration* configuration);
+ int (CDECL *set_configuration)(libcec_connection_t connection, const CEC_NAMESPACE libcec_configuration* configuration);
+ void (CDECL *rescan_devices)(libcec_connection_t connection);
+ int (CDECL *is_libcec_active_source)(libcec_connection_t connection);
+ int (CDECL *get_device_information)(libcec_connection_t connection, const char* strPort, CEC_NAMESPACE libcec_configuration* config, uint32_t iTimeoutMs);
+ const char* (CDECL *get_lib_info)(libcec_connection_t connection);
+ void (CDECL *init_video_standalone)(libcec_connection_t connection);
+ uint16_t (CDECL *get_adapter_vendor_id)(libcec_connection_t connection);
+ uint16_t (CDECL *get_adapter_product_id)(libcec_connection_t connection);
+ uint8_t (CDECL *audio_toggle_mute)(libcec_connection_t connection);
+ uint8_t (CDECL *audio_mute)(libcec_connection_t connection);
+ uint8_t (CDECL *audio_unmute)(libcec_connection_t connection);
+ uint8_t (CDECL *audio_get_status)(libcec_connection_t connection);
+ int8_t (CDECL *detect_adapters)(libcec_connection_t connection, CEC_NAMESPACE cec_adapter_descriptor* deviceList, uint8_t iBufSize, const char* strDevicePath, int bQuickScan);
+ void (CDECL *menu_state_to_string)(const CEC_NAMESPACE cec_menu_state state, char* buf, size_t bufsize);
+ void (CDECL *cec_version_to_string)(const CEC_NAMESPACE cec_version version, char* buf, size_t bufsize);
+ void (CDECL *power_status_to_string)(const CEC_NAMESPACE cec_power_status status, char* buf, size_t bufsize);
+ void (CDECL *logical_address_to_string)(const CEC_NAMESPACE cec_logical_address address, char* buf, size_t bufsize);
+ void (CDECL *deck_control_mode_to_string)(const CEC_NAMESPACE cec_deck_control_mode mode, char* buf, size_t bufsize);
+ void (CDECL *deck_status_to_string)(const CEC_NAMESPACE cec_deck_info status, char* buf, size_t bufsize);
+ void (CDECL *opcode_to_string)(const CEC_NAMESPACE cec_opcode opcode, char* buf, size_t bufsize);
+ void (CDECL *system_audio_status_to_string)(const CEC_NAMESPACE cec_system_audio_status mode, char* buf, size_t bufsize);
+ void (CDECL *audio_status_to_string)(const CEC_NAMESPACE cec_audio_status status, char* buf, size_t bufsize);
+ void (CDECL *vendor_id_to_string)(const CEC_NAMESPACE cec_vendor_id vendor, char* buf, size_t bufsize);
+ void (CDECL *user_control_key_to_string)(const CEC_NAMESPACE cec_user_control_code key, char* buf, size_t bufsize);
+ void (CDECL *adapter_type_to_string)(const CEC_NAMESPACE cec_adapter_type type, char* buf, size_t bufsize);
+ void (CDECL *version_to_string)(uint32_t version, char* buf, size_t bufsize);
+} libcec_interface_t;
+
+static int libcecc_resolve_all(void* lib, libcec_interface_t* iface)
+{
+ if (!lib || !iface)
+ return -1;
+
+ _libcecc_resolve(lib, iface->destroy, "libcec_destroy", void(CDECL *)(libcec_connection_t));
+ _libcecc_resolve(lib, iface->open, "libcec_open", int(CDECL *)(libcec_connection_t, const char*, uint32_t));
+ _libcecc_resolve(lib, iface->close, "libcec_close", void(CDECL *)(libcec_connection_t));
+ _libcecc_resolve(lib, iface->clear_configuration, "libcec_clear_configuration", void(CDECL *)(CEC_NAMESPACE libcec_configuration*));
+ _libcecc_resolve(lib, iface->enable_callbacks, "libcec_enable_callbacks", int(CDECL *)(libcec_connection_t, void*, CEC_NAMESPACE ICECCallbacks*));
+ _libcecc_resolve(lib, iface->find_adapters, "libcec_find_adapters", int8_t(CDECL *)(libcec_connection_t, CEC_NAMESPACE cec_adapter*, uint8_t, const char*));
+ _libcecc_resolve(lib, iface->ping_adapters, "libcec_ping_adapters", int(CDECL *)(libcec_connection_t));
+ _libcecc_resolve(lib, iface->start_bootloader, "libcec_start_bootloader", int(CDECL *)(libcec_connection_t));
+ _libcecc_resolve(lib, iface->power_on_devices, "libcec_power_on_devices", int(CDECL *)(libcec_connection_t, CEC_NAMESPACE cec_logical_address));
+ _libcecc_resolve(lib, iface->standby_devices, "libcec_standby_devices", int(CDECL *)(libcec_connection_t, CEC_NAMESPACE cec_logical_address));
+ _libcecc_resolve(lib, iface->set_active_source, "libcec_set_active_source", int(CDECL *)(libcec_connection_t, CEC_NAMESPACE cec_device_type));
+ _libcecc_resolve(lib, iface->set_deck_control_mode, "libcec_set_deck_control_mode", int(CDECL *)(libcec_connection_t, CEC_NAMESPACE cec_deck_control_mode, int));
+ _libcecc_resolve(lib, iface->set_deck_info, "libcec_set_deck_info", int(CDECL *)(libcec_connection_t, CEC_NAMESPACE cec_deck_info, int));
+ _libcecc_resolve(lib, iface->set_inactive_view, "libcec_set_inactive_view", int(CDECL *)(libcec_connection_t));
+ _libcecc_resolve(lib, iface->set_menu_state, "libcec_set_menu_state", int(CDECL *)(libcec_connection_t, CEC_NAMESPACE cec_menu_state, int));
+ _libcecc_resolve(lib, iface->transmit, "libcec_transmit", int(CDECL *)(libcec_connection_t, const CEC_NAMESPACE cec_command*));
+ _libcecc_resolve(lib, iface->set_logical_address, "libcec_set_logical_address", int(CDECL *)(libcec_connection_t, CEC_NAMESPACE cec_logical_address));
+ _libcecc_resolve(lib, iface->set_physical_address, "libcec_set_physical_address", int(CDECL *)(libcec_connection_t, uint16_t));
+ _libcecc_resolve(lib, iface->set_osd_string, "libcec_set_osd_string", int(CDECL *)(libcec_connection_t, CEC_NAMESPACE cec_logical_address, CEC_NAMESPACE cec_display_control, const char*));
+ _libcecc_resolve(lib, iface->switch_monitoring, "libcec_switch_monitoring", int(CDECL *)(libcec_connection_t, int));
+ _libcecc_resolve(lib, iface->get_device_cec_version, "libcec_get_device_cec_version", CEC_NAMESPACE cec_version(CDECL *)(libcec_connection_t, CEC_NAMESPACE cec_logical_address));
+ _libcecc_resolve(lib, iface->get_device_menu_language, "libcec_get_device_menu_language", int(CDECL *)(libcec_connection_t, CEC_NAMESPACE cec_logical_address, CEC_NAMESPACE cec_menu_language));
+ _libcecc_resolve(lib, iface->get_device_vendor_id, "libcec_get_device_vendor_id", uint64_t(CDECL *)(libcec_connection_t, CEC_NAMESPACE cec_logical_address));
+ _libcecc_resolve(lib, iface->get_device_physical_address, "libcec_get_device_physical_address", uint16_t(CDECL *)(libcec_connection_t, CEC_NAMESPACE cec_logical_address));
+ _libcecc_resolve(lib, iface->get_active_source, "libcec_get_active_source", CEC_NAMESPACE cec_logical_address(CDECL *)(libcec_connection_t));
+ _libcecc_resolve(lib, iface->is_active_source, "libcec_is_active_source", int(CDECL *)(libcec_connection_t, CEC_NAMESPACE cec_logical_address));
+ _libcecc_resolve(lib, iface->get_device_power_status, "libcec_get_device_power_status", CEC_NAMESPACE cec_power_status(CDECL *)(libcec_connection_t, CEC_NAMESPACE cec_logical_address));
+ _libcecc_resolve(lib, iface->poll_device, "libcec_poll_device", int(CDECL *)(libcec_connection_t, CEC_NAMESPACE cec_logical_address));
+ _libcecc_resolve(lib, iface->get_active_devices, "libcec_get_active_devices", CEC_NAMESPACE cec_logical_addresses(CDECL *)(libcec_connection_t));
+ _libcecc_resolve(lib, iface->is_active_device, "libcec_is_active_device", int(CDECL *)(libcec_connection_t, CEC_NAMESPACE cec_logical_address));
+ _libcecc_resolve(lib, iface->is_active_device_type, "libcec_is_active_device_type", int(CDECL *)(libcec_connection_t, CEC_NAMESPACE cec_device_type));
+ _libcecc_resolve(lib, iface->set_hdmi_port, "libcec_set_hdmi_port", int(CDECL *)(libcec_connection_t, CEC_NAMESPACE cec_logical_address, uint8_t));
+ _libcecc_resolve(lib, iface->volume_up, "libcec_volume_up", int(CDECL *)(libcec_connection_t, int));
+ _libcecc_resolve(lib, iface->volume_down, "libcec_volume_down", int(CDECL *)(libcec_connection_t, int));
+ _libcecc_resolve(lib, iface->mute_audio, "libcec_mute_audio", int(CDECL *)(libcec_connection_t, int));
+ _libcecc_resolve(lib, iface->send_keypress, "libcec_send_keypress", int(CDECL *)(libcec_connection_t, CEC_NAMESPACE cec_logical_address, CEC_NAMESPACE cec_user_control_code, int));
+ _libcecc_resolve(lib, iface->send_key_release, "libcec_send_key_release", int(CDECL *)(libcec_connection_t, CEC_NAMESPACE cec_logical_address, int));
+ _libcecc_resolve(lib, iface->get_device_osd_name, "libcec_get_device_osd_name", int(CDECL *)(libcec_connection_t, CEC_NAMESPACE cec_logical_address, CEC_NAMESPACE cec_osd_name));
+ _libcecc_resolve(lib, iface->set_stream_path_logical, "libcec_set_stream_path_logical", int(CDECL *)(libcec_connection_t, CEC_NAMESPACE cec_logical_address));
+ _libcecc_resolve(lib, iface->set_stream_path_physical, "libcec_set_stream_path_physical", int(CDECL *)(libcec_connection_t, uint16_t));
+ _libcecc_resolve(lib, iface->get_logical_addresses, "libcec_get_logical_addresses", CEC_NAMESPACE cec_logical_addresses(CDECL *)(libcec_connection_t));
+ _libcecc_resolve(lib, iface->get_current_configuration, "libcec_get_current_configuration", int(CDECL *)(libcec_connection_t, CEC_NAMESPACE libcec_configuration*));
+ _libcecc_resolve(lib, iface->can_persist_configuration, "libcec_can_persist_configuration", int(CDECL *)(libcec_connection_t));
+ _libcecc_resolve(lib, iface->persist_configuration, "libcec_persist_configuration", int(CDECL *)(libcec_connection_t, CEC_NAMESPACE libcec_configuration*));
+ _libcecc_resolve(lib, iface->set_configuration, "libcec_set_configuration", int(CDECL *)(libcec_connection_t, const CEC_NAMESPACE libcec_configuration*));
+ _libcecc_resolve(lib, iface->rescan_devices, "libcec_rescan_devices", void(CDECL *)(libcec_connection_t));
+ _libcecc_resolve(lib, iface->is_libcec_active_source, "libcec_is_libcec_active_source", int(CDECL *)(libcec_connection_t));
+ _libcecc_resolve(lib, iface->get_device_information, "libcec_get_device_information", int(CDECL *)(libcec_connection_t, const char*, CEC_NAMESPACE libcec_configuration*, uint32_t));
+ _libcecc_resolve(lib, iface->get_lib_info, "libcec_get_lib_info", const char*(CDECL *)(libcec_connection_t));
+ _libcecc_resolve(lib, iface->init_video_standalone, "libcec_init_video_standalone", void(CDECL *)(libcec_connection_t));
+ _libcecc_resolve(lib, iface->get_adapter_vendor_id, "libcec_get_adapter_vendor_id", uint16_t(CDECL *)(libcec_connection_t));
+ _libcecc_resolve(lib, iface->get_adapter_product_id, "libcec_get_adapter_product_id", uint16_t(CDECL *)(libcec_connection_t));
+ _libcecc_resolve(lib, iface->audio_toggle_mute, "libcec_audio_toggle_mute", uint8_t(CDECL *)(libcec_connection_t));
+ _libcecc_resolve(lib, iface->audio_mute, "libcec_audio_mute", uint8_t(CDECL *)(libcec_connection_t));
+ _libcecc_resolve(lib, iface->audio_unmute, "libcec_audio_unmute", uint8_t(CDECL *)(libcec_connection_t));
+ _libcecc_resolve(lib, iface->audio_get_status, "libcec_audio_get_status", uint8_t(CDECL *)(libcec_connection_t));
+ _libcecc_resolve(lib, iface->detect_adapters, "libcec_detect_adapters", int8_t(CDECL *)(libcec_connection_t, CEC_NAMESPACE cec_adapter_descriptor*, uint8_t, const char*, int));
+ _libcecc_resolve(lib, iface->menu_state_to_string, "libcec_menu_state_to_string", void(CDECL *)(const CEC_NAMESPACE cec_menu_state, char*, size_t));
+ _libcecc_resolve(lib, iface->cec_version_to_string, "libcec_cec_version_to_string", void(CDECL *)(const CEC_NAMESPACE cec_version, char*, size_t));
+ _libcecc_resolve(lib, iface->power_status_to_string, "libcec_power_status_to_string", void(CDECL *)(const CEC_NAMESPACE cec_power_status, char*, size_t));
+ _libcecc_resolve(lib, iface->logical_address_to_string, "libcec_logical_address_to_string", void(CDECL *)(const CEC_NAMESPACE cec_logical_address, char*, size_t));
+ _libcecc_resolve(lib, iface->deck_control_mode_to_string, "libcec_deck_control_mode_to_string", void(CDECL *)(const CEC_NAMESPACE cec_deck_control_mode, char*, size_t));
+ _libcecc_resolve(lib, iface->deck_status_to_string, "libcec_deck_status_to_string", void(CDECL *)(const CEC_NAMESPACE cec_deck_info, char*, size_t));
+ _libcecc_resolve(lib, iface->opcode_to_string, "libcec_opcode_to_string", void(CDECL *)(const CEC_NAMESPACE cec_opcode, char*, size_t));
+ _libcecc_resolve(lib, iface->system_audio_status_to_string, "libcec_system_audio_status_to_string", void(CDECL *)(const CEC_NAMESPACE cec_system_audio_status, char*, size_t));
+ _libcecc_resolve(lib, iface->audio_status_to_string, "libcec_audio_status_to_string", void(CDECL *)(const CEC_NAMESPACE cec_audio_status, char*, size_t));
+ _libcecc_resolve(lib, iface->vendor_id_to_string, "libcec_vendor_id_to_string", void(CDECL *)(const CEC_NAMESPACE cec_vendor_id, char*, size_t));
+ _libcecc_resolve(lib, iface->user_control_key_to_string, "libcec_user_control_key_to_string", void(CDECL *)(const CEC_NAMESPACE cec_user_control_code, char*, size_t));
+ _libcecc_resolve(lib, iface->adapter_type_to_string, "libcec_adapter_type_to_string", void(CDECL *)(const CEC_NAMESPACE cec_adapter_type, char*, size_t));
+ _libcecc_resolve(lib, iface->version_to_string, "libcec_version_to_string", void(CDECL *)(uint32_t, char*, size_t));
+
+ return 1;
+}
+
+static libcecc_lib_instance_t libcecc_load_library(const char* strLib)
+{
+ libcecc_lib_instance_t lib;
+#if defined(_WIN32) || defined(_WIN64)
+ lib = LoadLibrary(strLib ? strLib : "cec.dll");
+ if (lib == NULL)
+ printf("failed to load cec.dll\n");
+#else
+ #if defined(__APPLE__)
+ lib = dlopen(strLib ? strLib : "libcec." CEC_LIB_VERSION_MAJOR_STR ".dylib", RTLD_LAZY);
+ #else
+ lib = dlopen(strLib ? strLib : "libcec.so." CEC_LIB_VERSION_MAJOR_STR, RTLD_LAZY);
+ #endif
+ if (lib == NULL)
+ printf("%s\n", dlerror());
+#endif
+ return lib;
+}
+
+static void libcecc_close_library(libcecc_lib_instance_t lib)
+{
+#if defined(_WIN32) || defined(_WIN64)
+ FreeLibrary(lib);
+#else
+ dlclose(lib);
+#endif
+}
+
+static void* libcecc_resolve(void* lib, const char* name)
+{
+#if defined(_WIN32) || defined(_WIN64)
+ return GetProcAddress(lib, name);
+#else
+ return dlsym(lib, name);
+#endif
+}
+
+void libcecc_reset_configuration(CEC_NAMESPACE libcec_configuration* configuration)
+{
+ void(CDECL * _clear_configuration)(CEC_NAMESPACE libcec_configuration*);
+ libcecc_lib_instance_t lib;
+
+ memset(configuration, 0, sizeof(CEC_NAMESPACE libcec_configuration));
+ lib = libcecc_load_library(NULL);
+ if (lib == NULL)
+ return;
+
+ _clear_configuration = (void(CDECL *)(CEC_NAMESPACE libcec_configuration*)) libcecc_resolve(lib, "libcec_clear_configuration");
+ if (_clear_configuration)
+ _clear_configuration(configuration);
+
+ libcecc_close_library(lib);
+}
+
+/*!
+ * @brief Create a new libCEC instance.
+ * @param configuration The configuration to pass to libCEC
+ * @param strLib The name of and/or path to libCEC
+ * @return 1 when loaded, 0 if libCEC failed to initialise, -1 if methods failed to be resolved
+ */
+int libcecc_initialise(CEC_NAMESPACE libcec_configuration* configuration, libcec_interface_t* iface, const char* strLib)
+{
+ void* (CDECL *_cec_initialise)(CEC_NAMESPACE libcec_configuration*);
+
+ libcecc_lib_instance_t lib;
+ lib = libcecc_load_library(strLib);
+ if (lib == NULL)
+ return -1;
+
+ _libcecc_resolve(lib, _cec_initialise, "libcec_initialise", void* (CDECL *)(CEC_NAMESPACE libcec_configuration*));
+
+ iface->lib_instance = lib;
+ iface->connection = _cec_initialise(configuration);
+
+ return iface->connection ?
+ libcecc_resolve_all(lib, iface) :
+ 0;
+}
+
+/*!
+ * @brief Destroy an instance of libCEC.
+ * @param device The instance to destroy.
+ */
+void libcecc_destroy(libcec_interface_t* iface)
+{
+ if (iface->destroy)
+ iface->destroy(iface->connection);
+ libcecc_close_library(iface->lib_instance);
+ memset(iface, 0, sizeof(libcec_interface_t));
+}
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#if defined(_WIN32) || defined(_WIN64)
+#include <windows.h>
+#include <conio.h>
+
+HINSTANCE g_libCEC = NULL;
+
+/*!
+ * @brief Create a new libCEC instance.
+ * @param configuration The configuration to pass to libCEC
+ * @param strLib The name of and/or path to libCEC
+ * @return An instance of ICECAdapter or NULL on error.
+ */
+CEC::ICECAdapter *LibCecInitialise(CEC::libcec_configuration *configuration, const char *strLib = NULL)
+{
+ if (!g_libCEC)
+ g_libCEC = LoadLibrary(strLib ? strLib : "cec.dll");
+ if (!g_libCEC)
+ return NULL;
+
+ typedef void* (__cdecl*_LibCecInitialise)(CEC::libcec_configuration *);
+ _LibCecInitialise LibCecInitialise;
+ LibCecInitialise = (_LibCecInitialise) (GetProcAddress(g_libCEC, "CECInitialise"));
+ if (!LibCecInitialise)
+ {
+ std::cout << "cannot find CECInitialise" << std::endl;
+ return NULL;
+ }
+
+ return static_cast< CEC::ICECAdapter* > (LibCecInitialise(configuration));
+}
+
+/*!
+ * @brief Destroy an instance of libCEC.
+ * @param device The instance to destroy.
+ */
+void UnloadLibCec(CEC::ICECAdapter *device)
+{
+ typedef void (__cdecl*_DestroyLibCec)(void * device);
+ _DestroyLibCec DestroyLibCec;
+ DestroyLibCec = (_DestroyLibCec) (GetProcAddress(g_libCEC, "CECDestroy"));
+ if (DestroyLibCec)
+ DestroyLibCec(device);
+
+ FreeLibrary(g_libCEC);
+ g_libCEC = NULL;
+}
+
+/*!
+ * @brief Start the bootloader on the first device that was detected.
+ * @param strLib The name of and/or path to libCEC
+ * @return True when the command was sent, false otherwise.
+ */
+bool LibCecBootloader(const char *strLib = NULL)
+{
+ if (!g_libCEC)
+ g_libCEC = LoadLibrary(strLib ? strLib : "cec.dll");
+ if (!g_libCEC)
+ return NULL;
+
+ typedef bool (__cdecl*_LibCecBootloader)(void);
+ _LibCecBootloader LibCecBootloader;
+ LibCecBootloader = (_LibCecBootloader) (GetProcAddress(g_libCEC, "CECStartBootloader"));
+ if (!LibCecBootloader)
+ return false;
+
+ bool bReturn = LibCecBootloader();
+ FreeLibrary(g_libCEC);
+ g_libCEC = NULL;
+ return bReturn;
+}
+
+#else
+
+#include <dlfcn.h>
+
+void *g_libCEC = NULL;
+
+/*!
+ * @brief Create a new libCEC instance.
+ * @param configuration The configuration to pass to libCEC
+ * @param strLib The name of and/or path to libCEC
+ * @return An instance of ICECAdapter or NULL on error.
+ */
+CEC::ICECAdapter *LibCecInitialise(CEC::libcec_configuration *configuration, const char *strLib = NULL)
+{
+ if (!g_libCEC)
+ {
+#if defined(__APPLE__)
+ g_libCEC = dlopen(strLib ? strLib : "libcec." CEC_LIB_VERSION_MAJOR_STR ".dylib", RTLD_LAZY);
+#else
+ g_libCEC = dlopen(strLib ? strLib : "libcec.so." CEC_LIB_VERSION_MAJOR_STR, RTLD_LAZY);
+#endif
+ if (!g_libCEC)
+ {
+ std::cout << dlerror() << std::endl;
+ return NULL;
+ }
+ }
+
+ typedef void* _LibCecInitialise(CEC::libcec_configuration *);
+ _LibCecInitialise* LibCecInitialise = (_LibCecInitialise*) dlsym(g_libCEC, "CECInitialise");
+ if (!LibCecInitialise)
+ {
+ std::cout << "cannot find CECInitialise" << std::endl;
+ return NULL;
+ }
+
+ return (CEC::ICECAdapter*) LibCecInitialise(configuration);
+}
+
+/*!
+ * @brief Destroy an instance of libCEC.
+ * @param device The instance to destroy.
+ */
+void UnloadLibCec(CEC::ICECAdapter *device)
+{
+ typedef void* _DestroyLibCec(CEC::ICECAdapter *);
+ _DestroyLibCec *DestroyLibCec = (_DestroyLibCec*) dlsym(g_libCEC, "CECDestroy");
+ if (DestroyLibCec)
+ DestroyLibCec(device);
+
+ dlclose(g_libCEC);
+}
+
+/*!
+ * @brief Start the bootloader on the first device that was detected.
+ * @param strLib The name of and/or path to libCEC
+ * @return True when the command was sent, false otherwise.
+ */
+bool LibCecBootloader(const char *strLib = NULL)
+{
+ if (!g_libCEC)
+ {
+#if defined(__APPLE__)
+ g_libCEC = dlopen(strLib ? strLib : "libcec.dylib", RTLD_LAZY);
+#else
+ g_libCEC = dlopen(strLib ? strLib : "libcec.so." CEC_LIB_VERSION_MAJOR_STR, RTLD_LAZY);
+#endif
+ if (!g_libCEC)
+ {
+ std::cout << dlerror() << std::endl;
+ return NULL;
+ }
+ }
+
+ typedef bool _LibCecBootloader(void);
+ _LibCecBootloader* LibCecBootloader = (_LibCecBootloader*) dlsym(g_libCEC, "CECStartBootloader");
+ if (!LibCecBootloader)
+ {
+ std::cout << "cannot find CECStartBootloader" << std::endl;
+ return NULL;
+ }
+
+ bool bReturn = LibCecBootloader();
+ dlclose(g_libCEC);
+ return bReturn;
+}
+
+#endif
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#ifndef CECTYPES_H_
+#define CECTYPES_H_
+
+#include "version.h"
+#include <stdint.h>
+#include <string.h>
+
+#if defined(_WIN32) || defined(_WIN64)
+#define CEC_CDECL __cdecl
+#else
+#define CEC_CDECL
+#endif
+
+#if !defined(DECLSPEC)
+#if defined(_WIN32) || defined(_WIN64)
+#include <windows.h>
+#if defined DLL_EXPORT
+#define DECLSPEC __declspec(dllexport)
+#else
+#define DECLSPEC __declspec(dllimport)
+#endif
+#else
+#define DECLSPEC
+#endif
+#endif
+
+#ifdef __cplusplus
+#include <string>
+extern "C" {
+namespace CEC {
+#endif
+
+/*!
+ * default physical address 1.0.0.0, HDMI port 1
+ */
+#define CEC_DEFAULT_PHYSICAL_ADDRESS 0x1000
+/*!
+ * default HDMI port to which the adapter is connected, port 1
+ */
+#define CEC_DEFAULT_HDMI_PORT 1
+/*!
+ * default logical address of the device to which the adapter is connected, TV
+ */
+#define CEC_DEFAULT_BASE_DEVICE 0
+
+/*!
+ * timeout in milliseconds to send a key release event after receiving a key press
+ */
+#define CEC_BUTTON_TIMEOUT 500
+
+/*!
+ * don't send the same key twice within this timeout in milliseconds
+ */
+#define CEC_DOUBLE_TAP_TIMEOUT_MS 200
+
+/*!
+ * don't query the power state for the same device within this timeout in milliseconds
+ */
+#define CEC_POWER_STATE_REFRESH_TIME 30000
+
+/*!
+ * unknown firmware version value
+ */
+#define CEC_FW_VERSION_UNKNOWN 0xFFFF
+
+/*!
+ * unknown build date value
+ */
+#define CEC_FW_BUILD_UNKNOWN 0
+
+/*!
+ * maximum number of retries when opening a connection
+ */
+#define CEC_CONNECT_TRIES 3
+
+/*!
+ * physical address of the TV
+ */
+#define CEC_PHYSICAL_ADDRESS_TV 0
+
+/*!
+ * minimum physical address for the adapter
+ */
+#define CEC_MIN_PHYSICAL_ADDRESS 0x1000
+
+/*!
+ * maximum physical address for the adapter
+ */
+#define CEC_MAX_PHYSICAL_ADDRESS 0xFFFE
+
+/*!
+ * invalid physical address value
+ */
+#define CEC_INVALID_PHYSICAL_ADDRESS 0xFFFF
+
+/*!
+ * minimum vendor ID value
+ */
+#define CEC_MIN_VENDORID 1
+
+/*!
+ * maximum vendor ID value
+ */
+#define CEC_MAX_VENDORID 0xFFFFFE
+
+/*!
+ * invalid vendor ID value
+ */
+#define CEC_INVALID_VENDORID 0xFFFFFF
+
+/*!
+ * minimum HDMI port number value
+ */
+#define CEC_MIN_HDMI_PORTNUMBER 1
+
+/*!
+ * maximum HDMI port number value
+ */
+#define CEC_MAX_HDMI_PORTNUMBER 15
+
+/*!
+ * invalid HDMI port number value
+ */
+#define CEC_HDMI_PORTNUMBER_NONE 0
+
+/*!
+ * default value for settings "activate source"
+ */
+#define CEC_DEFAULT_SETTING_ACTIVATE_SOURCE 1
+
+/*!
+ * default value for settings "power off on shutdown"
+ */
+#define CEC_DEFAULT_SETTING_POWER_OFF_SHUTDOWN 1
+
+/*!
+ * default value for settings "power off on standby"
+ */
+#define CEC_DEFAULT_SETTING_POWER_OFF_ON_STANDBY 1
+
+/*!
+ * default value for settings "device menu language"
+ */
+#define CEC_DEFAULT_DEVICE_LANGUAGE "eng"
+
+/*!
+ * default value for settings "autodetect physical address"
+ */
+#define CEC_DEFAULT_SETTING_AUTODETECT_ADDRESS 0
+
+/*!
+ * default value for settings "get settings from ROM"
+ */
+#define CEC_DEFAULT_SETTING_GET_SETTINGS_FROM_ROM 0
+
+/*!
+ * default value for settings "libCEC CEC version"
+ */
+#define CEC_DEFAULT_SETTING_CEC_VERSION 0x05
+
+/*!
+ * wait this amount of milliseconds before retrying to send a failed message
+ */
+#define CEC_DEFAULT_TRANSMIT_RETRY_WAIT 500
+
+/*!
+ * transmission fails when not acked within this amount of milliseconds after sending the initial packet
+ */
+#define CEC_DEFAULT_TRANSMIT_TIMEOUT 1000
+
+/*!
+ * wait this amount of milliseconds for an ack
+ */
+#define CEC_DEFAULT_TRANSMIT_WAIT 1000
+
+/*!
+ * default number of retries
+ */
+#define CEC_DEFAULT_TRANSMIT_RETRIES 1
+
+/*!
+ * default connection timeout in milliseconds
+ */
+#define CEC_DEFAULT_CONNECT_TIMEOUT 10000
+
+/*!
+ * wait this amount of milliseconds before retrying when failing to connect
+ */
+#define CEC_DEFAULT_CONNECT_RETRY_WAIT 1000
+
+/*!
+ * default serial baudrate
+ */
+#define CEC_SERIAL_DEFAULT_BAUDRATE 38400
+
+/*!
+ * maximum time to wait when clearing input
+ */
+#define CEC_CLEAR_INPUT_DEFAULT_WAIT 1000
+
+/*!
+ * wait this amount of milliseconds before retrying when libCEC failed to make itself the active source
+ */
+#define CEC_ACTIVE_SOURCE_SWITCH_RETRY_TIME_MS 1000
+
+/*!
+ * don't forward any power off command to the client application for this amount of milliseconds after sending a power off command
+ */
+#define CEC_FORWARD_STANDBY_MIN_INTERVAL 10000
+
+/*!
+ * default timeout in milliseconds for combo keys
+ */
+#define CEC_DEFAULT_COMBO_TIMEOUT_MS 1000
+
+/*!
+ * the virtual device path to use for the Raspberry Pi's CEC wire
+ */
+#define CEC_RPI_VIRTUAL_PATH "Raspberry Pi"
+
+/*!
+ * the name of the virtual COM port to use for the Raspberry Pi's CEC wire
+ */
+#define CEC_RPI_VIRTUAL_COM "RPI"
+
+/*!
+ * the path to use for the TDA995x's CEC wire
+ */
+#define CEC_TDA995x_PATH "/dev/hdmicec"
+
+/*!
+ * the name of the virtual COM port to use for the TDA995x's CEC wire
+ */
+#define CEC_TDA995x_VIRTUAL_COM "CuBox"
+
+/*!
+ * the path to use for the Exynos HDMI CEC device
+ */
+#define CEC_EXYNOS_PATH "/dev/CEC"
+
+/*!
+ * the name of the virtual COM port to use for the EXYNOS' CEC wire
+ */
+#define CEC_EXYNOS_VIRTUAL_COM "Exynos"
+
+/**
+ * Maximum size of a data packet
+ */
+#define CEC_MAX_DATA_PACKET_SIZE (16 * 4)
+
+/*!
+ * the path to use for the AOCEC HDMI CEC device
+ */
+#define CEC_AOCEC_PATH "/dev/aocec"
+
+/*!
+ * the name of the virtual COM port to use for the AOCEC' CEC wire
+ */
+#define CEC_AOCEC_VIRTUAL_COM "AOCEC"
+
+/*!
+ * Mimimum client version
+ */
+#define CEC_MIN_LIB_VERSION 4
+
+#define MSGSTART 0xFF
+#define MSGEND 0xFE
+#define MSGESC 0xFD
+#define ESCOFFSET 3
+
+#define DOUBLE_TAP_TIMEOUT_UNIT_SIZE (50)
+
+// defines to make compile time checks for certain features easy
+#define CEC_FEATURE_CONFIGURABLE_COMBO_KEY 1
+
+typedef enum cec_abort_reason
+{
+ CEC_ABORT_REASON_UNRECOGNIZED_OPCODE = 0,//!< CEC_ABORT_REASON_UNRECOGNIZED_OPCODE
+ CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND = 1,//!< CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND
+ CEC_ABORT_REASON_CANNOT_PROVIDE_SOURCE = 2,//!< CEC_ABORT_REASON_CANNOT_PROVIDE_SOURCE
+ CEC_ABORT_REASON_INVALID_OPERAND = 3,//!< CEC_ABORT_REASON_INVALID_OPERAND
+ CEC_ABORT_REASON_REFUSED = 4 //!< CEC_ABORT_REASON_REFUSED
+} cec_abort_reason;
+
+typedef enum cec_analogue_broadcast_type
+{
+ CEC_ANALOGUE_BROADCAST_TYPE_CABLE = 0x00,
+ CEC_ANALOGUE_BROADCAST_TYPE_SATELLITE = 0x01,
+ CEC_ANALOGUE_BROADCAST_TYPE_TERRESTIAL = 0x02
+} cec_analogue_broadcast_type;
+
+typedef enum cec_audio_rate
+{
+ CEC_AUDIO_RATE_RATE_CONTROL_OFF = 0,
+ CEC_AUDIO_RATE_STANDARD_RATE_100 = 1,
+ CEC_AUDIO_RATE_FAST_RATE_MAX_101 = 2,
+ CEC_AUDIO_RATE_SLOW_RATE_MIN_99 = 3,
+ CEC_AUDIO_RATE_STANDARD_RATE_100_0 = 4,
+ CEC_AUDIO_RATE_FAST_RATE_MAX_100_1 = 5,
+ CEC_AUDIO_RATE_SLOW_RATE_MIN_99_9 = 6
+} cec_audio_rate;
+
+typedef enum cec_audio_status
+{
+ CEC_AUDIO_MUTE_STATUS_MASK = 0x80,
+ CEC_AUDIO_VOLUME_STATUS_MASK = 0x7F,
+ CEC_AUDIO_VOLUME_MIN = 0x00,
+ CEC_AUDIO_VOLUME_MAX = 0x64,
+ CEC_AUDIO_VOLUME_STATUS_UNKNOWN = 0x7F
+} cec_audio_status;
+
+typedef enum cec_boolean
+{
+ CEC_FALSE = 0,
+ CEC_TRUE = 1
+} cec_boolean;
+
+typedef enum cec_version
+{
+ CEC_VERSION_UNKNOWN = 0x00,
+ CEC_VERSION_1_2 = 0x01,
+ CEC_VERSION_1_2A = 0x02,
+ CEC_VERSION_1_3 = 0x03,
+ CEC_VERSION_1_3A = 0x04,
+ CEC_VERSION_1_4 = 0x05
+} cec_version;
+
+typedef enum cec_channel_identifier
+{
+ CEC_CHANNEL_NUMBER_FORMAT_MASK = 0xFC000000,
+ CEC_1_PART_CHANNEL_NUMBER = 0x04000000,
+ CEC_2_PART_CHANNEL_NUMBER = 0x08000000,
+ CEC_MAJOR_CHANNEL_NUMBER_MASK = 0x3FF0000,
+ CEC_MINOR_CHANNEL_NUMBER_MASK = 0xFFFF
+} cec_channel_identifier;
+
+typedef enum cec_deck_control_mode
+{
+ CEC_DECK_CONTROL_MODE_SKIP_FORWARD_WIND = 1,
+ CEC_DECK_CONTROL_MODE_SKIP_REVERSE_REWIND = 2,
+ CEC_DECK_CONTROL_MODE_STOP = 3,
+ CEC_DECK_CONTROL_MODE_EJECT = 4
+} cec_deck_control_mode;
+
+typedef enum cec_deck_info
+{
+ CEC_DECK_INFO_PLAY = 0x11,
+ CEC_DECK_INFO_RECORD = 0x12,
+ CEC_DECK_INFO_PLAY_REVERSE = 0x13,
+ CEC_DECK_INFO_STILL = 0x14,
+ CEC_DECK_INFO_SLOW = 0x15,
+ CEC_DECK_INFO_SLOW_REVERSE = 0x16,
+ CEC_DECK_INFO_FAST_FORWARD = 0x17,
+ CEC_DECK_INFO_FAST_REVERSE = 0x18,
+ CEC_DECK_INFO_NO_MEDIA = 0x19,
+ CEC_DECK_INFO_STOP = 0x1A,
+ CEC_DECK_INFO_SKIP_FORWARD_WIND = 0x1B,
+ CEC_DECK_INFO_SKIP_REVERSE_REWIND = 0x1C,
+ CEC_DECK_INFO_INDEX_SEARCH_FORWARD = 0x1D,
+ CEC_DECK_INFO_INDEX_SEARCH_REVERSE = 0x1E,
+ CEC_DECK_INFO_OTHER_STATUS = 0x1F,
+ CEC_DECK_INFO_OTHER_STATUS_LG = 0x20
+} cec_deck_info;
+
+typedef enum cec_device_type
+{
+ CEC_DEVICE_TYPE_TV = 0,
+ CEC_DEVICE_TYPE_RECORDING_DEVICE = 1,
+ CEC_DEVICE_TYPE_RESERVED = 2,
+ CEC_DEVICE_TYPE_TUNER = 3,
+ CEC_DEVICE_TYPE_PLAYBACK_DEVICE = 4,
+ CEC_DEVICE_TYPE_AUDIO_SYSTEM = 5
+} cec_device_type;
+
+typedef enum cec_display_control
+{
+ CEC_DISPLAY_CONTROL_DISPLAY_FOR_DEFAULT_TIME = 0x00,
+ CEC_DISPLAY_CONTROL_DISPLAY_UNTIL_CLEARED = 0x40,
+ CEC_DISPLAY_CONTROL_CLEAR_PREVIOUS_MESSAGE = 0x80,
+ CEC_DISPLAY_CONTROL_RESERVED_FOR_FUTURE_USE = 0xC0
+} cec_display_control;
+
+typedef enum cec_external_source_specifier
+{
+ CEC_EXTERNAL_SOURCE_SPECIFIER_EXTERNAL_PLUG = 4,
+ CEC_EXTERNAL_SOURCE_SPECIFIER_EXTERNAL_PHYSICAL_ADDRESS = 5
+} cec_external_source_specifier;
+
+typedef enum cec_menu_request_type
+{
+ CEC_MENU_REQUEST_TYPE_ACTIVATE = 0,
+ CEC_MENU_REQUEST_TYPE_DEACTIVATE = 1,
+ CEC_MENU_REQUEST_TYPE_QUERY = 2
+} cec_menu_request_type;
+
+typedef enum cec_menu_state
+{
+ CEC_MENU_STATE_ACTIVATED = 0,
+ CEC_MENU_STATE_DEACTIVATED = 1
+} cec_menu_state;
+
+typedef enum cec_play_mode
+{
+ CEC_PLAY_MODE_PLAY_FORWARD = 0x24,
+ CEC_PLAY_MODE_PLAY_REVERSE = 0x20,
+ CEC_PLAY_MODE_PLAY_STILL = 0x25,
+ CEC_PLAY_MODE_FAST_FORWARD_MIN_SPEED = 0x05,
+ CEC_PLAY_MODE_FAST_FORWARD_MEDIUM_SPEED = 0x06,
+ CEC_PLAY_MODE_FAST_FORWARD_MAX_SPEED = 0x07,
+ CEC_PLAY_MODE_FAST_REVERSE_MIN_SPEED = 0x09,
+ CEC_PLAY_MODE_FAST_REVERSE_MEDIUM_SPEED = 0x0A,
+ CEC_PLAY_MODE_FAST_REVERSE_MAX_SPEED = 0x0B,
+ CEC_PLAY_MODE_SLOW_FORWARD_MIN_SPEED = 0x15,
+ CEC_PLAY_MODE_SLOW_FORWARD_MEDIUM_SPEED = 0x16,
+ CEC_PLAY_MODE_SLOW_FORWARD_MAX_SPEED = 0x17,
+ CEC_PLAY_MODE_SLOW_REVERSE_MIN_SPEED = 0x19,
+ CEC_PLAY_MODE_SLOW_REVERSE_MEDIUM_SPEED = 0x1A,
+ CEC_PLAY_MODE_SLOW_REVERSE_MAX_SPEED = 0x1B
+} cec_play_mode;
+
+typedef enum cec_power_status
+{
+ CEC_POWER_STATUS_ON = 0x00,
+ CEC_POWER_STATUS_STANDBY = 0x01,
+ CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON = 0x02,
+ CEC_POWER_STATUS_IN_TRANSITION_ON_TO_STANDBY = 0x03,
+ CEC_POWER_STATUS_UNKNOWN = 0x99
+} cec_power_status;
+
+typedef enum cec_record_source_type
+{
+ CEC_RECORD_SOURCE_TYPE_OWN_SOURCE = 1,
+ CEC_RECORD_SOURCE_TYPE_DIGITAL_SERVICE = 2,
+ CEC_RECORD_SOURCE_TYPE_ANALOGUE_SERVICE = 3,
+ CEC_RECORD_SOURCE_TYPE_EXTERNAL_PLUS = 4,
+ CEC_RECORD_SOURCE_TYPE_EXTERNAL_PHYSICAL_ADDRESS = 5
+} cec_record_source_type;
+
+typedef enum cec_record_status_info
+{
+ CEC_RECORD_STATUS_INFO_RECORDING_CURRENTLY_SELECTED_SOURCE = 0x01,
+ CEC_RECORD_STATUS_INFO_RECORDING_DIGITAL_SERVICE = 0x02,
+ CEC_RECORD_STATUS_INFO_RECORDING_ANALOGUE_SERVICE = 0x03,
+ CEC_RECORD_STATUS_INFO_RECORDING_EXTERNAL_INPUT = 0x04,
+ CEC_RECORD_STATUS_INFO_NO_RECORDING_UNABLE_TO_RECORD_DIGITAL_SERVICE = 0x05,
+ CEC_RECORD_STATUS_INFO_NO_RECORDING_UNABLE_TO_RECORD_ANALOGUE_SERVICE = 0x06,
+ CEC_RECORD_STATUS_INFO_NO_RECORDING_UNABLE_TO_SELECT_REQUIRED_SERVICE = 0x07,
+ CEC_RECORD_STATUS_INFO_NO_RECORDING_INVALID_EXTERNAL_PLUG_NUMBER = 0x09,
+ CEC_RECORD_STATUS_INFO_NO_RECORDING_INVALID_EXTERNAL_ADDRESS = 0x0A,
+ CEC_RECORD_STATUS_INFO_NO_RECORDING_CA_SYSTEM_NOT_SUPPORTED = 0x0B,
+ CEC_RECORD_STATUS_INFO_NO_RECORDING_NO_OR_INSUFFICIENT_ENTITLEMENTS = 0x0C,
+ CEC_RECORD_STATUS_INFO_NO_RECORDING_NOT_ALLOWED_TO_COPY_SOURCE = 0x0D,
+ CEC_RECORD_STATUS_INFO_NO_RECORDING_NO_FURTHER_COPIES_ALLOWED = 0x0E,
+ CEC_RECORD_STATUS_INFO_NO_RECORDING_NO_MEDIA = 0x10,
+ CEC_RECORD_STATUS_INFO_NO_RECORDING_PLAYING = 0x11,
+ CEC_RECORD_STATUS_INFO_NO_RECORDING_ALREADY_RECORDING = 0x12,
+ CEC_RECORD_STATUS_INFO_NO_RECORDING_MEDIA_PROTECTED = 0x13,
+ CEC_RECORD_STATUS_INFO_NO_RECORDING_NO_SOURCE_SIGNAL = 0x14,
+ CEC_RECORD_STATUS_INFO_NO_RECORDING_MEDIA_PROBLEM = 0x15,
+ CEC_RECORD_STATUS_INFO_NO_RECORDING_NOT_ENOUGH_SPACE_AVAILABLE = 0x16,
+ CEC_RECORD_STATUS_INFO_NO_RECORDING_PARENTAL_LOCK_ON = 0x17,
+ CEC_RECORD_STATUS_INFO_RECORDING_TERMINATED_NORMALLY = 0x1A,
+ CEC_RECORD_STATUS_INFO_RECORDING_HAS_ALREADY_TERMINATED = 0x1B,
+ CEC_RECORD_STATUS_INFO_NO_RECORDING_OTHER_REASON = 0x1F
+} cec_record_status_info;
+
+typedef enum cec_recording_sequence
+{
+ CEC_RECORDING_SEQUENCE_SUNDAY = 0x01,
+ CEC_RECORDING_SEQUENCE_MONDAY = 0x02,
+ CEC_RECORDING_SEQUENCE_TUESDAY = 0x04,
+ CEC_RECORDING_SEQUENCE_WEDNESDAY = 0x08,
+ CEC_RECORDING_SEQUENCE_THURSDAY = 0x10,
+ CEC_RECORDING_SEQUENCE_FRIDAY = 0x20,
+ CEC_RECORDING_SEQUENCE_SATURDAY = 0x40,
+ CEC_RECORDING_SEQUENCE_ONCE_ONLY = 0x00
+} cec_recording_sequence;
+
+typedef enum cec_status_request
+{
+ CEC_STATUS_REQUEST_ON = 1,
+ CEC_STATUS_REQUEST_OFF = 2,
+ CEC_STATUS_REQUEST_ONCE = 3
+} cec_status_request;
+
+typedef enum cec_system_audio_status
+{
+ CEC_SYSTEM_AUDIO_STATUS_OFF = 0,
+ CEC_SYSTEM_AUDIO_STATUS_ON = 1
+} cec_system_audio_status;
+
+typedef enum cec_timer_cleared_status_data
+{
+ CEC_TIMER_CLEARED_STATUS_DATA_TIMER_NOT_CLEARED_RECORDING = 0x00,
+ CEC_TIMER_CLEARED_STATUS_DATA_TIMER_NOT_CLEARED_NO_MATCHING = 0x01,
+ CEC_TIMER_CLEARED_STATUS_DATA_TIMER_NOT_CLEARED_NO_INF0_AVAILABLE = 0x02,
+ CEC_TIMER_CLEARED_STATUS_DATA_TIMER_CLEARED = 0x80
+} cec_timer_cleared_status_data;
+
+typedef enum cec_timer_overlap_warning
+{
+ CEC_TIMER_OVERLAP_WARNING_NO_OVERLAP = 0,
+ CEC_TIMER_OVERLAP_WARNING_TIMER_BLOCKS_OVERLAP = 1
+} cec_timer_overlap_warning;
+
+typedef enum cec_media_info
+{
+ CEC_MEDIA_INFO_MEDIA_PRESENT_AND_NOT_PROTECTED = 0x00,
+ CEC_MEDIA_INFO_MEDIA_PRESENT_BUT_PROTECTED = 0x01,
+ CEC_MEDIA_INFO_MEDIA_NOT_PRESENT = 0x02,
+ CEC_MEDIA_INFO_FUTURE_USE = 0x03
+} cec_media_info;
+
+typedef enum cec_programmed_indicator
+{
+ CEC_PROGRAMMED_INDICATOR_NOT_PROGRAMMED = 0,
+ CEC_PROGRAMMED_INDICATOR_PROGRAMMED = 1
+} cec_programmed_indicator;
+
+typedef enum cec_programmed_info
+{
+ CEC_PROGRAMMED_INFO_FUTURE_USE = 0x0,
+ CEC_PROGRAMMED_INFO_ENOUGH_SPACE_AVAILABLE_FOR_RECORDING = 0x08,
+ CEC_PROGRAMMED_INFO_NOT_ENOUGH_SPACE_AVAILABLE_FOR_RECORDING = 0x09,
+ CEC_PROGRAMMED_INFO_MAY_NOT_BE_ENOUGH_SPACE_AVAILABLE = 0x0B,
+ CEC_PROGRAMMED_INFO_NO_MEDIA_INFO_AVAILABLE = 0x0A
+} cec_programmed_info;
+
+typedef enum cec_not_programmed_error_info
+{
+ CEC_NOT_PROGRAMMED_ERROR_INFO_FUTURE_USE = 0x0,
+ CEC_NOT_PROGRAMMED_ERROR_INFO_NO_FREE_TIMER_AVAILABLE = 0x01,
+ CEC_NOT_PROGRAMMED_ERROR_INFO_DATE_OUT_OF_RANGE = 0x02,
+ CEC_NOT_PROGRAMMED_ERROR_INFO_RECORDING_SEQUENCE_ERROR = 0x03,
+ CEC_NOT_PROGRAMMED_ERROR_INFO_INVALID_EXTERNAL_PLUG_NUMBER = 0x04,
+ CEC_NOT_PROGRAMMED_ERROR_INFO_INVALID_EXTERNAL_PHYSICAL_ADDRESS = 0x05,
+ CEC_NOT_PROGRAMMED_ERROR_INFO_CA_SYSTEM_NOT_SUPPORTED = 0x06,
+ CEC_NOT_PROGRAMMED_ERROR_INFO_NO_OR_INSUFFICIENT_CA_ENTITLEMENTS = 0x07,
+ CEC_NOT_PROGRAMMED_ERROR_INFO_DOES_NOT_SUPPORT_RESOLUTION = 0x08,
+ CEC_NOT_PROGRAMMED_ERROR_INFO_PARENTAL_LOCK_ON = 0x09,
+ CEC_NOT_PROGRAMMED_ERROR_INFO_CLOCK_FAILURE = 0x0A,
+ CEC_NOT_PROGRAMMED_ERROR_INFO_RESERVED_FOR_FUTURE_USE_START = 0x0B,
+ CEC_NOT_PROGRAMMED_ERROR_INFO_RESERVED_FOR_FUTURE_USE_END = 0x0D,
+ CEC_NOT_PROGRAMMED_ERROR_INFO_DUPLICATE_ALREADY_PROGRAMMED = 0x0E
+} cec_not_programmed_error_info;
+
+typedef enum cec_recording_flag
+{
+ CEC_RECORDING_FLAG_NOT_BEING_USED_FOR_RECORDING = 0,
+ CEC_RECORDING_FLAG_BEING_USED_FOR_RECORDING = 1
+} cec_recording_flag;
+
+typedef enum cec_tuner_display_info
+{
+ CEC_TUNER_DISPLAY_INFO_DISPLAYING_DIGITAL_TUNER = 0,
+ CEC_TUNER_DISPLAY_INFO_NOT_DISPLAYING_TUNER = 1,
+ CEC_TUNER_DISPLAY_INFO_DISPLAYING_ANALOGUE_TUNER = 2
+} cec_tuner_display_info;
+
+typedef enum cec_broadcast_system
+{
+ CEC_BROADCAST_SYSTEM_PAL_B_G = 0,
+ CEC_BROADCAST_SYSTEM_SECAM_L1 = 1,
+ CEC_BROADCAST_SYSTEM_PAL_M = 2,
+ CEC_BROADCAST_SYSTEM_NTSC_M = 3,
+ CEC_BROADCAST_SYSTEM_PAL_I = 4,
+ CEC_BROADCAST_SYSTEM_SECAM_DK = 5,
+ CEC_BROADCAST_SYSTEM_SECAM_B_G = 6,
+ CEC_BROADCAST_SYSTEM_SECAM_L2 = 7,
+ CEC_BROADCAST_SYSTEM_PAL_DK = 8,
+ CEC_BROADCAST_SYSTEM_OTHER_SYSTEM = 30
+} cec_broadcast_system;
+
+typedef enum cec_user_control_code
+{
+ CEC_USER_CONTROL_CODE_SELECT = 0x00,
+ CEC_USER_CONTROL_CODE_UP = 0x01,
+ CEC_USER_CONTROL_CODE_DOWN = 0x02,
+ CEC_USER_CONTROL_CODE_LEFT = 0x03,
+ CEC_USER_CONTROL_CODE_RIGHT = 0x04,
+ CEC_USER_CONTROL_CODE_RIGHT_UP = 0x05,
+ CEC_USER_CONTROL_CODE_RIGHT_DOWN = 0x06,
+ CEC_USER_CONTROL_CODE_LEFT_UP = 0x07,
+ CEC_USER_CONTROL_CODE_LEFT_DOWN = 0x08,
+ CEC_USER_CONTROL_CODE_ROOT_MENU = 0x09,
+ CEC_USER_CONTROL_CODE_SETUP_MENU = 0x0A,
+ CEC_USER_CONTROL_CODE_CONTENTS_MENU = 0x0B,
+ CEC_USER_CONTROL_CODE_FAVORITE_MENU = 0x0C,
+ CEC_USER_CONTROL_CODE_EXIT = 0x0D,
+ // reserved: 0x0E, 0x0F
+ CEC_USER_CONTROL_CODE_TOP_MENU = 0x10,
+ CEC_USER_CONTROL_CODE_DVD_MENU = 0x11,
+ // reserved: 0x12 ... 0x1C
+ CEC_USER_CONTROL_CODE_NUMBER_ENTRY_MODE = 0x1D,
+ CEC_USER_CONTROL_CODE_NUMBER11 = 0x1E,
+ CEC_USER_CONTROL_CODE_NUMBER12 = 0x1F,
+ CEC_USER_CONTROL_CODE_NUMBER0 = 0x20,
+ CEC_USER_CONTROL_CODE_NUMBER1 = 0x21,
+ CEC_USER_CONTROL_CODE_NUMBER2 = 0x22,
+ CEC_USER_CONTROL_CODE_NUMBER3 = 0x23,
+ CEC_USER_CONTROL_CODE_NUMBER4 = 0x24,
+ CEC_USER_CONTROL_CODE_NUMBER5 = 0x25,
+ CEC_USER_CONTROL_CODE_NUMBER6 = 0x26,
+ CEC_USER_CONTROL_CODE_NUMBER7 = 0x27,
+ CEC_USER_CONTROL_CODE_NUMBER8 = 0x28,
+ CEC_USER_CONTROL_CODE_NUMBER9 = 0x29,
+ CEC_USER_CONTROL_CODE_DOT = 0x2A,
+ CEC_USER_CONTROL_CODE_ENTER = 0x2B,
+ CEC_USER_CONTROL_CODE_CLEAR = 0x2C,
+ CEC_USER_CONTROL_CODE_NEXT_FAVORITE = 0x2F,
+ CEC_USER_CONTROL_CODE_CHANNEL_UP = 0x30,
+ CEC_USER_CONTROL_CODE_CHANNEL_DOWN = 0x31,
+ CEC_USER_CONTROL_CODE_PREVIOUS_CHANNEL = 0x32,
+ CEC_USER_CONTROL_CODE_SOUND_SELECT = 0x33,
+ CEC_USER_CONTROL_CODE_INPUT_SELECT = 0x34,
+ CEC_USER_CONTROL_CODE_DISPLAY_INFORMATION = 0x35,
+ CEC_USER_CONTROL_CODE_HELP = 0x36,
+ CEC_USER_CONTROL_CODE_PAGE_UP = 0x37,
+ CEC_USER_CONTROL_CODE_PAGE_DOWN = 0x38,
+ // reserved: 0x39 ... 0x3F
+ CEC_USER_CONTROL_CODE_POWER = 0x40,
+ CEC_USER_CONTROL_CODE_VOLUME_UP = 0x41,
+ CEC_USER_CONTROL_CODE_VOLUME_DOWN = 0x42,
+ CEC_USER_CONTROL_CODE_MUTE = 0x43,
+ CEC_USER_CONTROL_CODE_PLAY = 0x44,
+ CEC_USER_CONTROL_CODE_STOP = 0x45,
+ CEC_USER_CONTROL_CODE_PAUSE = 0x46,
+ CEC_USER_CONTROL_CODE_RECORD = 0x47,
+ CEC_USER_CONTROL_CODE_REWIND = 0x48,
+ CEC_USER_CONTROL_CODE_FAST_FORWARD = 0x49,
+ CEC_USER_CONTROL_CODE_EJECT = 0x4A,
+ CEC_USER_CONTROL_CODE_FORWARD = 0x4B,
+ CEC_USER_CONTROL_CODE_BACKWARD = 0x4C,
+ CEC_USER_CONTROL_CODE_STOP_RECORD = 0x4D,
+ CEC_USER_CONTROL_CODE_PAUSE_RECORD = 0x4E,
+ // reserved: 0x4F
+ CEC_USER_CONTROL_CODE_ANGLE = 0x50,
+ CEC_USER_CONTROL_CODE_SUB_PICTURE = 0x51,
+ CEC_USER_CONTROL_CODE_VIDEO_ON_DEMAND = 0x52,
+ CEC_USER_CONTROL_CODE_ELECTRONIC_PROGRAM_GUIDE = 0x53,
+ CEC_USER_CONTROL_CODE_TIMER_PROGRAMMING = 0x54,
+ CEC_USER_CONTROL_CODE_INITIAL_CONFIGURATION = 0x55,
+ CEC_USER_CONTROL_CODE_SELECT_BROADCAST_TYPE = 0x56,
+ CEC_USER_CONTROL_CODE_SELECT_SOUND_PRESENTATION = 0x57,
+ // reserved: 0x58 ... 0x5F
+ CEC_USER_CONTROL_CODE_PLAY_FUNCTION = 0x60,
+ CEC_USER_CONTROL_CODE_PAUSE_PLAY_FUNCTION = 0x61,
+ CEC_USER_CONTROL_CODE_RECORD_FUNCTION = 0x62,
+ CEC_USER_CONTROL_CODE_PAUSE_RECORD_FUNCTION = 0x63,
+ CEC_USER_CONTROL_CODE_STOP_FUNCTION = 0x64,
+ CEC_USER_CONTROL_CODE_MUTE_FUNCTION = 0x65,
+ CEC_USER_CONTROL_CODE_RESTORE_VOLUME_FUNCTION = 0x66,
+ CEC_USER_CONTROL_CODE_TUNE_FUNCTION = 0x67,
+ CEC_USER_CONTROL_CODE_SELECT_MEDIA_FUNCTION = 0x68,
+ CEC_USER_CONTROL_CODE_SELECT_AV_INPUT_FUNCTION = 0x69,
+ CEC_USER_CONTROL_CODE_SELECT_AUDIO_INPUT_FUNCTION = 0x6A,
+ CEC_USER_CONTROL_CODE_POWER_TOGGLE_FUNCTION = 0x6B,
+ CEC_USER_CONTROL_CODE_POWER_OFF_FUNCTION = 0x6C,
+ CEC_USER_CONTROL_CODE_POWER_ON_FUNCTION = 0x6D,
+ // reserved: 0x6E ... 0x70
+ CEC_USER_CONTROL_CODE_F1_BLUE = 0x71,
+ CEC_USER_CONTROL_CODE_F2_RED = 0X72,
+ CEC_USER_CONTROL_CODE_F3_GREEN = 0x73,
+ CEC_USER_CONTROL_CODE_F4_YELLOW = 0x74,
+ CEC_USER_CONTROL_CODE_F5 = 0x75,
+ CEC_USER_CONTROL_CODE_DATA = 0x76,
+ // reserved: 0x77 ... 0xFF
+ CEC_USER_CONTROL_CODE_AN_RETURN = 0x91, // return (Samsung)
+ CEC_USER_CONTROL_CODE_AN_CHANNELS_LIST = 0x96, // channels list (Samsung)
+ CEC_USER_CONTROL_CODE_MAX = 0x96,
+ CEC_USER_CONTROL_CODE_UNKNOWN = 0xFF
+} cec_user_control_code;
+
+typedef enum cec_logical_address
+{
+ CECDEVICE_UNKNOWN = -1, //not a valid logical address
+ CECDEVICE_TV = 0,
+ CECDEVICE_RECORDINGDEVICE1 = 1,
+ CECDEVICE_RECORDINGDEVICE2 = 2,
+ CECDEVICE_TUNER1 = 3,
+ CECDEVICE_PLAYBACKDEVICE1 = 4,
+ CECDEVICE_AUDIOSYSTEM = 5,
+ CECDEVICE_TUNER2 = 6,
+ CECDEVICE_TUNER3 = 7,
+ CECDEVICE_PLAYBACKDEVICE2 = 8,
+ CECDEVICE_RECORDINGDEVICE3 = 9,
+ CECDEVICE_TUNER4 = 10,
+ CECDEVICE_PLAYBACKDEVICE3 = 11,
+ CECDEVICE_RESERVED1 = 12,
+ CECDEVICE_RESERVED2 = 13,
+ CECDEVICE_FREEUSE = 14,
+ CECDEVICE_UNREGISTERED = 15,
+ CECDEVICE_BROADCAST = 15
+} cec_logical_address;
+
+typedef enum cec_opcode
+{
+ CEC_OPCODE_ACTIVE_SOURCE = 0x82,
+ CEC_OPCODE_IMAGE_VIEW_ON = 0x04,
+ CEC_OPCODE_TEXT_VIEW_ON = 0x0D,
+ CEC_OPCODE_INACTIVE_SOURCE = 0x9D,
+ CEC_OPCODE_REQUEST_ACTIVE_SOURCE = 0x85,
+ CEC_OPCODE_ROUTING_CHANGE = 0x80,
+ CEC_OPCODE_ROUTING_INFORMATION = 0x81,
+ CEC_OPCODE_SET_STREAM_PATH = 0x86,
+ CEC_OPCODE_STANDBY = 0x36,
+ CEC_OPCODE_RECORD_OFF = 0x0B,
+ CEC_OPCODE_RECORD_ON = 0x09,
+ CEC_OPCODE_RECORD_STATUS = 0x0A,
+ CEC_OPCODE_RECORD_TV_SCREEN = 0x0F,
+ CEC_OPCODE_CLEAR_ANALOGUE_TIMER = 0x33,
+ CEC_OPCODE_CLEAR_DIGITAL_TIMER = 0x99,
+ CEC_OPCODE_CLEAR_EXTERNAL_TIMER = 0xA1,
+ CEC_OPCODE_SET_ANALOGUE_TIMER = 0x34,
+ CEC_OPCODE_SET_DIGITAL_TIMER = 0x97,
+ CEC_OPCODE_SET_EXTERNAL_TIMER = 0xA2,
+ CEC_OPCODE_SET_TIMER_PROGRAM_TITLE = 0x67,
+ CEC_OPCODE_TIMER_CLEARED_STATUS = 0x43,
+ CEC_OPCODE_TIMER_STATUS = 0x35,
+ CEC_OPCODE_CEC_VERSION = 0x9E,
+ CEC_OPCODE_GET_CEC_VERSION = 0x9F,
+ CEC_OPCODE_GIVE_PHYSICAL_ADDRESS = 0x83,
+ CEC_OPCODE_GET_MENU_LANGUAGE = 0x91,
+ CEC_OPCODE_REPORT_PHYSICAL_ADDRESS = 0x84,
+ CEC_OPCODE_SET_MENU_LANGUAGE = 0x32,
+ CEC_OPCODE_DECK_CONTROL = 0x42,
+ CEC_OPCODE_DECK_STATUS = 0x1B,
+ CEC_OPCODE_GIVE_DECK_STATUS = 0x1A,
+ CEC_OPCODE_PLAY = 0x41,
+ CEC_OPCODE_GIVE_TUNER_DEVICE_STATUS = 0x08,
+ CEC_OPCODE_SELECT_ANALOGUE_SERVICE = 0x92,
+ CEC_OPCODE_SELECT_DIGITAL_SERVICE = 0x93,
+ CEC_OPCODE_TUNER_DEVICE_STATUS = 0x07,
+ CEC_OPCODE_TUNER_STEP_DECREMENT = 0x06,
+ CEC_OPCODE_TUNER_STEP_INCREMENT = 0x05,
+ CEC_OPCODE_DEVICE_VENDOR_ID = 0x87,
+ CEC_OPCODE_GIVE_DEVICE_VENDOR_ID = 0x8C,
+ CEC_OPCODE_VENDOR_COMMAND = 0x89,
+ CEC_OPCODE_VENDOR_COMMAND_WITH_ID = 0xA0,
+ CEC_OPCODE_VENDOR_REMOTE_BUTTON_DOWN = 0x8A,
+ CEC_OPCODE_VENDOR_REMOTE_BUTTON_UP = 0x8B,
+ CEC_OPCODE_SET_OSD_STRING = 0x64,
+ CEC_OPCODE_GIVE_OSD_NAME = 0x46,
+ CEC_OPCODE_SET_OSD_NAME = 0x47,
+ CEC_OPCODE_MENU_REQUEST = 0x8D,
+ CEC_OPCODE_MENU_STATUS = 0x8E,
+ CEC_OPCODE_USER_CONTROL_PRESSED = 0x44,
+ CEC_OPCODE_USER_CONTROL_RELEASE = 0x45,
+ CEC_OPCODE_GIVE_DEVICE_POWER_STATUS = 0x8F,
+ CEC_OPCODE_REPORT_POWER_STATUS = 0x90,
+ CEC_OPCODE_FEATURE_ABORT = 0x00,
+ CEC_OPCODE_ABORT = 0xFF,
+ CEC_OPCODE_GIVE_AUDIO_STATUS = 0x71,
+ CEC_OPCODE_GIVE_SYSTEM_AUDIO_MODE_STATUS = 0x7D,
+ CEC_OPCODE_REPORT_AUDIO_STATUS = 0x7A,
+ CEC_OPCODE_SET_SYSTEM_AUDIO_MODE = 0x72,
+ CEC_OPCODE_SYSTEM_AUDIO_MODE_REQUEST = 0x70,
+ CEC_OPCODE_SYSTEM_AUDIO_MODE_STATUS = 0x7E,
+ CEC_OPCODE_SET_AUDIO_RATE = 0x9A,
+
+ /* CEC 1.4 */
+ CEC_OPCODE_START_ARC = 0xC0,
+ CEC_OPCODE_REPORT_ARC_STARTED = 0xC1,
+ CEC_OPCODE_REPORT_ARC_ENDED = 0xC2,
+ CEC_OPCODE_REQUEST_ARC_START = 0xC3,
+ CEC_OPCODE_REQUEST_ARC_END = 0xC4,
+ CEC_OPCODE_END_ARC = 0xC5,
+ CEC_OPCODE_CDC = 0xF8,
+ /* when this opcode is set, no opcode will be sent to the device. this is one of the reserved numbers */
+ CEC_OPCODE_NONE = 0xFD
+} cec_opcode;
+
+typedef enum cec_log_level
+{
+ CEC_LOG_ERROR = 1,
+ CEC_LOG_WARNING = 2,
+ CEC_LOG_NOTICE = 4,
+ CEC_LOG_TRAFFIC = 8,
+ CEC_LOG_DEBUG = 16,
+ CEC_LOG_ALL = 31
+} cec_log_level;
+
+typedef enum cec_bus_device_status
+{
+ CEC_DEVICE_STATUS_UNKNOWN,
+ CEC_DEVICE_STATUS_PRESENT,
+ CEC_DEVICE_STATUS_NOT_PRESENT,
+ CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC
+} cec_bus_device_status;
+
+typedef enum cec_vendor_id
+{
+ CEC_VENDOR_TOSHIBA = 0x000039,
+ CEC_VENDOR_SAMSUNG = 0x0000F0,
+ CEC_VENDOR_DENON = 0x0005CD,
+ CEC_VENDOR_MARANTZ = 0x000678,
+ CEC_VENDOR_LOEWE = 0x000982,
+ CEC_VENDOR_ONKYO = 0x0009B0,
+ CEC_VENDOR_MEDION = 0x000CB8,
+ CEC_VENDOR_TOSHIBA2 = 0x000CE7,
+ CEC_VENDOR_PULSE_EIGHT = 0x001582,
+ CEC_VENDOR_HARMAN_KARDON2 = 0x001950,
+ CEC_VENDOR_GOOGLE = 0x001A11,
+ CEC_VENDOR_AKAI = 0x0020C7,
+ CEC_VENDOR_AOC = 0x002467,
+ CEC_VENDOR_PANASONIC = 0x008045,
+ CEC_VENDOR_PHILIPS = 0x00903E,
+ CEC_VENDOR_DAEWOO = 0x009053,
+ CEC_VENDOR_YAMAHA = 0x00A0DE,
+ CEC_VENDOR_GRUNDIG = 0x00D0D5,
+ CEC_VENDOR_PIONEER = 0x00E036,
+ CEC_VENDOR_LG = 0x00E091,
+ CEC_VENDOR_SHARP = 0x08001F,
+ CEC_VENDOR_SONY = 0x080046,
+ CEC_VENDOR_BROADCOM = 0x18C086,
+ CEC_VENDOR_SHARP2 = 0x534850,
+ CEC_VENDOR_VIZIO = 0x6B746D,
+ CEC_VENDOR_BENQ = 0x8065E9,
+ CEC_VENDOR_HARMAN_KARDON = 0x9C645E,
+ CEC_VENDOR_UNKNOWN = 0
+} cec_vendor_id;
+
+typedef enum cec_adapter_type
+{
+ ADAPTERTYPE_UNKNOWN = 0,
+ ADAPTERTYPE_P8_EXTERNAL = 0x1,
+ ADAPTERTYPE_P8_DAUGHTERBOARD = 0x2,
+ ADAPTERTYPE_RPI = 0x100,
+ ADAPTERTYPE_TDA995x = 0x200,
+ ADAPTERTYPE_EXYNOS = 0x300,
+ ADAPTERTYPE_AOCEC = 0x500
+} cec_adapter_type;
+
+/** force exporting through swig */
+enum libcec_version
+{
+ LIBCEC_VERSION_CURRENT = _LIBCEC_VERSION_CURRENT
+};
+
+typedef char cec_menu_language[4]; /**< the iso language code + (char)0 */
+typedef char cec_osd_name[14]; /**< the name of the device */
+
+typedef struct cec_log_message
+{
+ const char* message; /**< the actual message, valid until returning from the log callback */
+ cec_log_level level; /**< log level of the message */
+ int64_t time; /**< the timestamp of this message */
+} cec_log_message;
+
+typedef struct cec_keypress
+{
+ cec_user_control_code keycode; /**< the keycode */
+ unsigned int duration; /**< the duration of the keypress */
+} cec_keypress;
+
+typedef struct cec_adapter
+{
+ char path[1024]; /**< the path to the com port */
+ char comm[1024]; /**< the name of the com port */
+} cec_adapter;
+
+typedef struct cec_adapter_descriptor
+{
+ char strComPath[1024]; /**< the path to the com port */
+ char strComName[1024]; /**< the name of the com port */
+ uint16_t iVendorId;
+ uint16_t iProductId;
+ uint16_t iFirmwareVersion;
+ uint16_t iPhysicalAddress;
+ uint32_t iFirmwareBuildDate;
+ cec_adapter_type adapterType;
+} cec_adapter_descriptor;
+
+#if defined(__cplusplus)
+typedef struct AdapterDescriptor
+{
+ AdapterDescriptor(void) :
+ iVendorId(0),
+ iProductId(0),
+ iFirmwareVersion(0),
+ iPhysicalAddress(0),
+ iFirmwareBuildDate(0),
+ adapterType(ADAPTERTYPE_UNKNOWN)
+ {
+ }
+
+ AdapterDescriptor(const cec_adapter_descriptor& other)
+ {
+ strComPath = other.strComPath;
+ strComName = other.strComName;
+ iVendorId = other.iVendorId;
+ iProductId = other.iProductId;
+ iFirmwareVersion = other.iFirmwareVersion;
+ iPhysicalAddress = other.iPhysicalAddress;
+ iFirmwareBuildDate = other.iFirmwareBuildDate;
+ adapterType = other.adapterType;
+ }
+
+ std::string strComPath; /**< the path to the com port */
+ std::string strComName; /**< the name of the com port */
+ uint16_t iVendorId;
+ uint16_t iProductId;
+ uint16_t iFirmwareVersion;
+ uint16_t iPhysicalAddress;
+ uint32_t iFirmwareBuildDate;
+ cec_adapter_type adapterType;
+} AdapterDescriptor;
+#endif
+
+typedef struct cec_datapacket
+{
+ uint8_t data[CEC_MAX_DATA_PACKET_SIZE]; /**< the actual data */
+ uint8_t size; /**< the size of the data */
+
+#ifdef __cplusplus
+ cec_datapacket &operator =(const struct cec_datapacket &packet)
+ {
+ Clear();
+ for (uint8_t iPtr = 0; iPtr < packet.size; iPtr++)
+ PushBack(packet[iPtr]);
+
+ return *this;
+ }
+
+ bool operator ==(const struct cec_datapacket& packet) const
+ {
+ if (size != packet.size)
+ return false;
+ for (uint8_t iPtr = 0; iPtr < size; iPtr++)
+ if (packet.data[iPtr] != data[iPtr])
+ return false;
+ return true;
+ }
+
+ /** @return True when this packet is empty, false otherwise. */
+ bool IsEmpty(void) const { return size == 0; }
+ /** @return True when this packet is false, false otherwise. */
+ bool IsFull(void) const { return size == CEC_MAX_DATA_PACKET_SIZE; }
+
+ /*!
+ * @brief Get the byte at the requested position.
+ * @param pos The position.
+ * @return The byte, or 0 when out of bounds.
+ */
+ uint8_t operator[](uint8_t pos) const { return pos < size ? data[pos] : 0; }
+ /*!
+ * @brief Get the byte at the requested position.
+ * @param pos The position.
+ * @return The byte, or 0 when out of bounds.
+ */
+ uint8_t At(uint8_t pos) const { return pos < size ? data[pos] : 0; }
+
+ /*!
+ * @brief Shift the contents of this packet.
+ * @param iShiftBy The number of positions to shift.
+ */
+ void Shift(uint8_t iShiftBy)
+ {
+ if (iShiftBy >= size)
+ {
+ Clear();
+ }
+ else
+ {
+ for (uint8_t iPtr = 0; iPtr < size; iPtr++)
+ data[iPtr] = (iPtr + iShiftBy < size) ? data[iPtr + iShiftBy] : 0;
+ size = (uint8_t) (size - iShiftBy);
+ }
+ }
+
+ /*!
+ * @brief Push a byte to the end of this packet.
+ * @param add The byte to add.
+ */
+ void PushBack(uint8_t add)
+ {
+ if (size < CEC_MAX_DATA_PACKET_SIZE)
+ data[size++] = add;
+ }
+
+ /*!
+ * @brief Clear this packet.
+ */
+ void Clear(void)
+ {
+ memset(data, 0, sizeof(data));
+ size = 0;
+ }
+#endif
+
+} cec_datapacket;
+
+typedef struct cec_command
+{
+ cec_logical_address initiator; /**< the logical address of the initiator of this message */
+ cec_logical_address destination; /**< the logical address of the destination of this message */
+ int8_t ack; /**< 1 when the ACK bit is set, 0 otherwise */
+ int8_t eom; /**< 1 when the EOM bit is set, 0 otherwise */
+ cec_opcode opcode; /**< the opcode of this message */
+ cec_datapacket parameters; /**< the parameters attached to this message */
+ int8_t opcode_set; /**< 1 when an opcode is set, 0 otherwise (POLL message) */
+ int32_t transmit_timeout; /**< the timeout to use in ms */
+
+#ifdef __cplusplus
+ cec_command(void)
+ {
+ Clear();
+ }
+
+ cec_command &operator =(const struct cec_command &command)
+ {
+ initiator = command.initiator;
+ destination = command.destination;
+ ack = command.ack;
+ eom = command.eom;
+ opcode = command.opcode;
+ opcode_set = command.opcode_set;
+ transmit_timeout = command.transmit_timeout;
+ parameters = command.parameters;
+
+ return *this;
+ }
+
+ uint8_t Size(void) const
+ {
+ return parameters.size + opcode_set + 1;
+ }
+
+ /*!
+ * @brief Formats a cec_command.
+ * @param command The command to format.
+ * @param initiator The logical address of the initiator.
+ * @param destination The logical address of the destination.
+ * @param opcode The opcode of the command.
+ * @param timeout The transmission timeout.
+ */
+ static void Format(cec_command &command, cec_logical_address initiator, cec_logical_address destination, cec_opcode opcode, int32_t timeout = CEC_DEFAULT_TRANSMIT_TIMEOUT)
+ {
+ command.Clear();
+ command.initiator = initiator;
+ command.destination = destination;
+ command.transmit_timeout = timeout;
+ if (opcode != CEC_OPCODE_NONE)
+ {
+ command.opcode = opcode;
+ command.opcode_set = 1;
+ }
+ }
+
+ /*!
+ * @brief Push a byte to the back of this command.
+ * @param data The byte to push.
+ */
+ void PushBack(uint8_t data)
+ {
+ if (initiator == CECDEVICE_UNKNOWN && destination == CECDEVICE_UNKNOWN)
+ {
+ initiator = (cec_logical_address) (data >> 4);
+ destination = (cec_logical_address) (data & 0xF);
+ }
+ else if (!opcode_set)
+ {
+ opcode_set = 1;
+ opcode = (cec_opcode) data;
+ }
+ else
+ parameters.PushBack(data);
+ }
+
+ /*!
+ * @brief Clear this command, resetting everything to the default values.
+ */
+ void Clear(void)
+ {
+ initiator = CECDEVICE_UNKNOWN;
+ destination = CECDEVICE_UNKNOWN;
+ ack = 0;
+ eom = 0;
+ opcode_set = 0;
+ opcode = CEC_OPCODE_FEATURE_ABORT;
+ transmit_timeout = CEC_DEFAULT_TRANSMIT_TIMEOUT;
+ parameters.Clear();
+ };
+
+ static cec_opcode GetResponseOpcode(cec_opcode opcode)
+ {
+ switch (opcode)
+ {
+ case CEC_OPCODE_REQUEST_ACTIVE_SOURCE:
+ return CEC_OPCODE_ACTIVE_SOURCE;
+ case CEC_OPCODE_GET_CEC_VERSION:
+ return CEC_OPCODE_CEC_VERSION;
+ case CEC_OPCODE_GIVE_PHYSICAL_ADDRESS:
+ return CEC_OPCODE_REPORT_PHYSICAL_ADDRESS;
+ case CEC_OPCODE_GET_MENU_LANGUAGE:
+ return CEC_OPCODE_SET_MENU_LANGUAGE;
+ case CEC_OPCODE_GIVE_DECK_STATUS:
+ return CEC_OPCODE_DECK_STATUS;
+ case CEC_OPCODE_GIVE_TUNER_DEVICE_STATUS:
+ return CEC_OPCODE_TUNER_DEVICE_STATUS;
+ case CEC_OPCODE_GIVE_DEVICE_VENDOR_ID:
+ return CEC_OPCODE_DEVICE_VENDOR_ID;
+ case CEC_OPCODE_GIVE_OSD_NAME:
+ return CEC_OPCODE_SET_OSD_NAME;
+ case CEC_OPCODE_MENU_REQUEST:
+ return CEC_OPCODE_MENU_STATUS;
+ case CEC_OPCODE_GIVE_DEVICE_POWER_STATUS:
+ return CEC_OPCODE_REPORT_POWER_STATUS;
+ case CEC_OPCODE_GIVE_AUDIO_STATUS:
+ return CEC_OPCODE_REPORT_AUDIO_STATUS;
+ case CEC_OPCODE_GIVE_SYSTEM_AUDIO_MODE_STATUS:
+ return CEC_OPCODE_SYSTEM_AUDIO_MODE_STATUS;
+ case CEC_OPCODE_SYSTEM_AUDIO_MODE_REQUEST:
+ return CEC_OPCODE_SET_SYSTEM_AUDIO_MODE;
+ default:
+ break;
+ }
+
+ return CEC_OPCODE_NONE;
+ }
+
+ void PushArray(size_t len, const uint8_t *data)
+ {
+ for (size_t iPtr = 0; iPtr < len; iPtr++)
+ PushBack(data[iPtr]);
+ }
+#endif
+} cec_command;
+
+typedef struct cec_device_type_list
+{
+ cec_device_type types[5]; /**< the list of device types */
+
+#ifdef __cplusplus
+ /*!
+ * @brief Clear this list.
+ */
+ void Clear(void)
+ {
+ for (unsigned int iPtr = 0; iPtr < 5; iPtr++)
+ types[iPtr] = CEC_DEVICE_TYPE_RESERVED;
+ }
+
+ /*!
+ * @brief Add a type to this list.
+ * @param type The type to add.
+ */
+ void Add(const cec_device_type type)
+ {
+ for (unsigned int iPtr = 0; iPtr < 5; iPtr++)
+ {
+ if (types[iPtr] == CEC_DEVICE_TYPE_RESERVED)
+ {
+ types[iPtr] = type;
+ break;
+ }
+ }
+ }
+
+ /*!
+ * @brief Check whether a type is set in this list.
+ * @param type The type to check.
+ * @return True when set, false otherwise.
+ */
+ bool IsSet(cec_device_type type)
+ {
+ bool bReturn(false);
+ for (unsigned int iPtr = 0; !bReturn && iPtr < 5; iPtr++)
+ {
+ if (types[iPtr] == type)
+ bReturn = true;
+ }
+ return bReturn;
+ }
+
+ /*!
+ * @return True when this list is empty, false otherwise.
+ */
+ bool IsEmpty() const
+ {
+ bool bReturn(true);
+ for (unsigned int iPtr = 0; bReturn && iPtr < 5; iPtr++)
+ {
+ if (types[iPtr] != CEC_DEVICE_TYPE_RESERVED)
+ bReturn = false;
+ }
+ return bReturn;
+ }
+
+ /*!
+ * @brief Get the type at the requested position.
+ * @param pos The position.
+ * @return The type, or CEC_DEVICE_TYPE_RESERVED when out of bounds.
+ */
+ cec_device_type operator[](uint8_t pos) const { return pos < 5 ? types[pos] : CEC_DEVICE_TYPE_RESERVED; }
+
+ bool operator==(const cec_device_type_list &other) const
+ {
+ bool bEqual(true);
+ for (uint8_t iPtr = 0; iPtr < 5; iPtr++)
+ bEqual &= (types[iPtr] == other[iPtr]);
+ return bEqual;
+ }
+
+ bool operator!=(const cec_device_type_list &other) const
+ {
+ return !(*this == other);
+ }
+#endif
+} cec_device_type_list;
+
+typedef struct cec_logical_addresses
+{
+ cec_logical_address primary; /**< the primary logical address to use */
+ int addresses[16]; /**< the list of addresses */
+
+#ifdef __cplusplus
+ /*!
+ * @brief Clear this list.
+ */
+ void Clear(void)
+ {
+ primary = CECDEVICE_UNREGISTERED;
+ for (unsigned int iPtr = 0; iPtr < 16; iPtr++)
+ addresses[iPtr] = 0;
+ }
+
+ /*!
+ * @return True when empty, false otherwise.
+ */
+ bool IsEmpty(void) const
+ {
+ return primary == CECDEVICE_UNREGISTERED;
+ }
+
+ /*!
+ * @brief Calculate the ack-mask for this list, the mask to use when determining whether to send an ack message or not.
+ * @return The ack-mask.
+ */
+ uint16_t AckMask(void) const
+ {
+ uint16_t mask = 0;
+ for (unsigned int iPtr = 0; iPtr < 16; iPtr++)
+ if (addresses[iPtr] == 1)
+ mask |= 0x1 << iPtr;
+ return mask;
+ }
+
+ /*!
+ * @brief Mark a logical address as 'set'
+ * @param address The logical address to add to this list.
+ */
+ void Set(cec_logical_address address)
+ {
+ if (primary == CECDEVICE_UNREGISTERED)
+ primary = address;
+
+ addresses[(int) address] = 1;
+ }
+
+ /*!
+ * @brief Mark a logical address as 'unset'
+ * @param address The logical address to remove from this list.
+ */
+ void Unset(const cec_logical_address address)
+ {
+ if (primary == address)
+ primary = CECDEVICE_UNREGISTERED;
+
+ addresses[(int) address] = 0;
+ }
+
+ /*!
+ * @brief Check whether an address is set in this list.
+ * @param address The address to check.
+ * @return True when set, false otherwise.
+ */
+ bool IsSet(cec_logical_address address) const { return addresses[(int) address] == 1; }
+
+ /*!
+ * @brief Check whether an address is set in this list.
+ * @param pos The address to check.
+ * @return True when set, false otherwise.
+ */
+ bool operator[](uint8_t pos) const { return pos < 16 ? IsSet((cec_logical_address) pos) : false; }
+
+ bool operator==(const cec_logical_addresses &other) const
+ {
+ bool bEqual(true);
+ for (uint8_t iPtr = 0; iPtr < 16; iPtr++)
+ bEqual &= ((addresses[(int)iPtr] == 1) == other[iPtr]);
+ return bEqual;
+ }
+
+ bool operator!=(const cec_logical_addresses &other) const
+ {
+ return !(*this == other);
+ }
+#endif
+} cec_logical_addresses;
+
+typedef enum libcec_alert
+{
+ CEC_ALERT_SERVICE_DEVICE,
+ CEC_ALERT_CONNECTION_LOST,
+ CEC_ALERT_PERMISSION_ERROR,
+ CEC_ALERT_PORT_BUSY,
+ CEC_ALERT_PHYSICAL_ADDRESS_ERROR,
+ CEC_ALERT_TV_POLL_FAILED
+} libcec_alert;
+
+typedef enum libcec_parameter_type
+{
+ CEC_PARAMETER_TYPE_STRING,
+ CEC_PARAMETER_TYPE_UNKOWN
+} libcec_parameter_type;
+
+typedef struct libcec_parameter
+{
+ libcec_parameter_type paramType; /**< the type of this parameter */
+ void* paramData; /**< the value of this parameter */
+} libcec_parameter;
+
+typedef struct libcec_configuration libcec_configuration;
+
+typedef struct ICECCallbacks
+{
+ /*!
+ * @brief Transfer a log message from libCEC to the client.
+ * @param cbparam Callback parameter provided when the callbacks were set up
+ * @param message The message to transfer.
+ */
+ void (CEC_CDECL* logMessage)(void* cbparam, const cec_log_message* message);
+
+ /*!
+ * @brief Transfer a keypress from libCEC to the client.
+ * @param cbparam Callback parameter provided when the callbacks were set up
+ * @param key The keypress to transfer.
+ */
+ void (CEC_CDECL* keyPress)(void* cbparam, const cec_keypress* key);
+
+ /*!
+ * @brief Transfer a CEC command from libCEC to the client.
+ * @param cbparam Callback parameter provided when the callbacks were set up
+ * @param command The command to transfer.
+ */
+ void (CEC_CDECL* commandReceived)(void* cbparam, const cec_command* command);
+
+ /*!
+ * @brief Transfer a changed configuration from libCEC to the client
+ * @param cbparam Callback parameter provided when the callbacks were set up
+ * @param configuration The configuration to transfer
+ */
+ void (CEC_CDECL* configurationChanged)(void* cbparam, const libcec_configuration* configuration);
+
+ /*!
+ * @brief Transfer a libcec alert message from libCEC to the client
+ * @param cbparam Callback parameter provided when the callbacks were set up
+ * @param alert The alert type transfer.
+ * @param data Misc. additional information.
+ */
+ void (CEC_CDECL* alert)(void* cbparam, const libcec_alert alert, const libcec_parameter param);
+
+ /*!
+ * @brief Transfer a menu state change to the client.
+ * Transfer a menu state change to the client. If the command returns 1, then the change will be processed by
+ * the busdevice. If 0, then the state of the busdevice won't be changed, and will always be kept 'activated',
+ * @warning CEC does not allow the player to suppress the menu state change on the TV, so the menu on the TV will always be displayed, whatever the return value of this method is.
+ * so keypresses are always routed.
+ * @param cbparam Callback parameter provided when the callbacks were set up
+ * @param state The new value.
+ *
+ * @return 1 if libCEC should use this new value, 0 otherwise.
+ */
+ int (CEC_CDECL* menuStateChanged)(void* cbparam, const cec_menu_state state);
+
+ /*!
+ * @brief Called when a source that's handled by this client is activated.
+ * @param cbparam Callback parameter provided when the callbacks were set up
+ * @param logicalAddress The address that was just activated.
+ * @param bActivated 1 if activated, 0 when deactivated.
+ */
+ void (CEC_CDECL* sourceActivated)(void* cbParam, const cec_logical_address logicalAddress, const uint8_t bActivated);
+
+#ifdef __cplusplus
+ ICECCallbacks(void) { Clear(); }
+ ~ICECCallbacks(void) { Clear(); };
+
+ void Clear(void)
+ {
+ logMessage = nullptr;
+ keyPress = nullptr;
+ commandReceived = nullptr;
+ configurationChanged = nullptr;
+ alert = nullptr;
+ menuStateChanged = nullptr;
+ sourceActivated = nullptr;
+ }
+#endif
+} ICECCallbacks;
+
+struct libcec_configuration
+{
+ uint32_t clientVersion; /*!< the version of the client that is connecting */
+ char strDeviceName[13]; /*!< the device name to use on the CEC bus */
+ cec_device_type_list deviceTypes; /*!< the device type(s) to use on the CEC bus for libCEC */
+ uint8_t bAutodetectAddress; /*!< (read only) set to 1 by libCEC when the physical address was autodetected */
+ uint16_t iPhysicalAddress; /*!< the physical address of the CEC adapter */
+ cec_logical_address baseDevice; /*!< the logical address of the device to which the adapter is connected. only used when iPhysicalAddress = 0 or when the adapter doesn't support autodetection */
+ uint8_t iHDMIPort; /*!< the HDMI port to which the adapter is connected. only used when iPhysicalAddress = 0 or when the adapter doesn't support autodetection */
+ uint32_t tvVendor; /*!< override the vendor ID of the TV. leave this untouched to autodetect */
+ cec_logical_addresses wakeDevices; /*!< list of devices to wake when initialising libCEC or when calling PowerOnDevices() without any parameter. */
+ cec_logical_addresses powerOffDevices; /*!< list of devices to power off when calling StandbyDevices() without any parameter. */
+
+ uint32_t serverVersion; /*!< the version number of the server. read-only */
+
+ // player specific settings
+ uint8_t bGetSettingsFromROM; /*!< true to get the settings from the ROM (if set, and a v2 ROM is present), false to use these settings. */
+ uint8_t bActivateSource; /*!< make libCEC the active source on the bus when starting the player application */
+ uint8_t bPowerOffOnStandby; /*!< put this PC in standby mode when the TV is switched off. only used when bShutdownOnStandby = 0 */
+
+ void * callbackParam; /*!< the object to pass along with a call of the callback methods. NULL to ignore */
+ ICECCallbacks * callbacks; /*!< the callback methods to use. set this to NULL when not using callbacks */
+
+ cec_logical_addresses logicalAddresses; /*!< (read-only) the current logical addresses. added in 1.5.3 */
+ uint16_t iFirmwareVersion; /*!< (read-only) the firmware version of the adapter. added in 1.6.0 */
+ char strDeviceLanguage[3]; /*!< the menu language used by the client. 3 character ISO 639-2 country code. see http://http://www.loc.gov/standards/iso639-2/ added in 1.6.2 */
+ uint32_t iFirmwareBuildDate; /*!< (read-only) the build date of the firmware, in seconds since epoch. if not available, this value will be set to 0. added in 1.6.2 */
+ uint8_t bMonitorOnly; /*!< won't allocate a CCECClient when starting the connection when set (same as monitor mode). added in 1.6.3 */
+ cec_version cecVersion; /*!< CEC spec version to use by libCEC. defaults to v1.4. added in 1.8.0 */
+ cec_adapter_type adapterType; /*!< type of the CEC adapter that we're connected to. added in 1.8.2 */
+ cec_user_control_code comboKey; /*!< key code that initiates combo keys. defaults to CEC_USER_CONTROL_CODE_F1_BLUE. CEC_USER_CONTROL_CODE_UNKNOWN to disable. added in 2.0.5 */
+ uint32_t iComboKeyTimeoutMs; /*!< timeout until the combo key is sent as normal keypress */
+ uint32_t iButtonRepeatRateMs; /*!< rate at which buttons autorepeat. 0 means rely on CEC device */
+ uint32_t iButtonReleaseDelayMs;/*!< duration after last update until a button is considered released */
+ uint32_t iDoubleTapTimeoutMs; /*!< prevent double taps within this timeout. defaults to 200ms. added in 4.0.0 */
+ uint8_t bAutoWakeAVR; /*!< set to 1 to automatically waking an AVR when the source is activated. added in 4.0.0 */
+
+#ifdef __cplusplus
+ libcec_configuration(void) { Clear(); }
+ ~libcec_configuration(void) { Clear(); }
+
+ bool operator==(const libcec_configuration &other) const
+ {
+ return ( clientVersion == other.clientVersion &&
+ !strncmp(strDeviceName, other.strDeviceName, 13) &&
+ deviceTypes == other.deviceTypes &&
+ bAutodetectAddress == other.bAutodetectAddress &&
+ iPhysicalAddress == other.iPhysicalAddress &&
+ baseDevice == other.baseDevice &&
+ iHDMIPort == other.iHDMIPort &&
+ tvVendor == other.tvVendor &&
+ wakeDevices == other.wakeDevices &&
+ powerOffDevices == other.powerOffDevices &&
+ serverVersion == other.serverVersion &&
+ bGetSettingsFromROM == other.bGetSettingsFromROM &&
+ bActivateSource == other.bActivateSource &&
+ bPowerOffOnStandby == other.bPowerOffOnStandby &&
+ logicalAddresses == other.logicalAddresses &&
+ iFirmwareVersion == other.iFirmwareVersion &&
+ !strncmp(strDeviceLanguage, other.strDeviceLanguage, 3) &&
+ iFirmwareBuildDate == other.iFirmwareBuildDate &&
+ bMonitorOnly == other.bMonitorOnly &&
+ cecVersion == other.cecVersion &&
+ adapterType == other.adapterType &&
+ iDoubleTapTimeoutMs == other.iDoubleTapTimeoutMs &&
+ iButtonRepeatRateMs == other.iButtonRepeatRateMs &&
+ iButtonReleaseDelayMs == other.iButtonReleaseDelayMs &&
+ comboKey == other.comboKey &&
+ iComboKeyTimeoutMs == other.iComboKeyTimeoutMs &&
+ bAutoWakeAVR == other.bAutoWakeAVR);
+ }
+
+ bool operator!=(const libcec_configuration &other) const
+ {
+ return !(*this == other);
+ }
+
+ /*!
+ * @brief Reset this configution struct to the default values.
+ */
+ void Clear(void)
+ {
+ iPhysicalAddress = CEC_PHYSICAL_ADDRESS_TV;
+ baseDevice = (cec_logical_address)CEC_DEFAULT_BASE_DEVICE;
+ iHDMIPort = CEC_DEFAULT_HDMI_PORT;
+ tvVendor = (uint32_t)CEC_VENDOR_UNKNOWN;
+ clientVersion = LIBCEC_VERSION_CURRENT;
+ serverVersion = LIBCEC_VERSION_CURRENT;
+ bAutodetectAddress = 0;
+ bGetSettingsFromROM = CEC_DEFAULT_SETTING_GET_SETTINGS_FROM_ROM;
+ bActivateSource = CEC_DEFAULT_SETTING_ACTIVATE_SOURCE;
+ bPowerOffOnStandby = CEC_DEFAULT_SETTING_POWER_OFF_ON_STANDBY;
+ iFirmwareVersion = CEC_FW_VERSION_UNKNOWN;
+ memcpy(strDeviceLanguage, CEC_DEFAULT_DEVICE_LANGUAGE, 3);
+ iFirmwareBuildDate = CEC_FW_BUILD_UNKNOWN;
+ bMonitorOnly = 0;
+ cecVersion = (cec_version)CEC_DEFAULT_SETTING_CEC_VERSION;
+ adapterType = ADAPTERTYPE_UNKNOWN;
+ iDoubleTapTimeoutMs = CEC_DOUBLE_TAP_TIMEOUT_MS;
+ comboKey = CEC_USER_CONTROL_CODE_STOP;
+ iComboKeyTimeoutMs = CEC_DEFAULT_COMBO_TIMEOUT_MS;
+ iButtonRepeatRateMs = 0;
+ iButtonReleaseDelayMs = CEC_BUTTON_TIMEOUT;
+ bAutoWakeAVR = 0;
+
+ memset(strDeviceName, 0, 13);
+ deviceTypes.Clear();
+ logicalAddresses.Clear();
+ wakeDevices.Clear();
+ powerOffDevices.Clear();
+
+ #if CEC_DEFAULT_SETTING_POWER_OFF_SHUTDOWN == 1
+ powerOffDevices.Set(CECDEVICE_BROADCAST);
+ #endif
+ #if CEC_DEFAULT_SETTING_ACTIVATE_SOURCE == 1
+ wakeDevices.Set(CECDEVICE_TV);
+ #endif
+
+ callbackParam = nullptr;
+ callbacks = nullptr;
+ }
+#endif
+};
+
+#ifdef __cplusplus
+};
+};
+#endif
+
+#endif /* CECTYPES_H_ */
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+/**
+ * Convert a version number to an uint32_t
+ * @param[in] major Major version number
+ * @param[in] minor Minor version number
+ * @param[in] patch Patch number
+ *
+ * @return The version number as uint32_t
+ */
+#define LIBCEC_VERSION_TO_UINT(major, minor, patch) \
+ ((major < 2 || (major == 2 && minor <= 2)) ? \
+ (uint32_t) (major << 8) | (minor << 4) | (patch) : \
+ (uint32_t) (major << 16) | (minor << 8) | (patch))
+
+/* new style version numbers, 2.3.0 and later */
+#define LIBCEC_UINT_TO_VERSION_MAJOR(x) ((x >> 16) & 0xFF)
+#define LIBCEC_UINT_TO_VERSION_MINOR(x) ((x >> 8 ) & 0xFF)
+#define LIBCEC_UINT_TO_VERSION_PATCH(x) ((x >> 0 ) & 0xFF)
+
+/* old style version numbers, before 2.3.0 */
+#define LIBCEC_UINT_TO_VERSION_MAJOR_OLD(x) ((x >> 8) & 0xFF)
+#define LIBCEC_UINT_TO_VERSION_MINOR_OLD(x) ((x >> 4) & 0x0F)
+#define LIBCEC_UINT_TO_VERSION_PATCH_OLD(x) ((x >> 0) & 0x0F)
+
+/*!
+ * libCEC's major version number
+ */
+#define CEC_LIB_VERSION_MAJOR @LIBCEC_VERSION_MAJOR@
+
+/*!
+ * libCEC's major version number as string
+ */
+#define CEC_LIB_VERSION_MAJOR_STR "@LIBCEC_VERSION_MAJOR@"
+
+/*!
+ * libCEC's minor version number
+ */
+#define CEC_LIB_VERSION_MINOR @LIBCEC_VERSION_MINOR@
+
+/* current libCEC version number */
+#define _LIBCEC_VERSION_CURRENT \
+ LIBCEC_VERSION_TO_UINT(@LIBCEC_VERSION_MAJOR@, @LIBCEC_VERSION_MINOR@, @LIBCEC_VERSION_PATCH@)
+
\ No newline at end of file
--- /dev/null
+#include "winres.h"
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION ${LIBCEC_VERSION_MAJOR},${LIBCEC_VERSION_MINOR},${LIBCEC_VERSION_PATCH},0
+ PRODUCTVERSION ${LIBCEC_VERSION_MAJOR},${LIBCEC_VERSION_MINOR},${LIBCEC_VERSION_PATCH},0
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "000004b0"
+ BEGIN
+ VALUE "CompanyName", "Pulse-Eight Limited"
+ VALUE "FileDescription", "LibCecSharp"
+ VALUE "FileVersion", "${LIBCEC_VERSION_MAJOR}.${LIBCEC_VERSION_MINOR}.${LIBCEC_VERSION_PATCH}.0"
+ VALUE "InternalName", "LibCecSharp.dll"
+ VALUE "LegalCopyright", "Copyright (c) Pulse-Eight Limited 2011-2015"
+ VALUE "OriginalFilename", "LibCecSharp.dll"
+ VALUE "ProductName", "LibCecSharp"
+ VALUE "ProductVersion", "${LIBCEC_VERSION_MAJOR}.${LIBCEC_VERSION_MINOR}.${LIBCEC_VERSION_PATCH}.0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x0, 1200
+ END
+END
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{E54D4581-CD59-4687-BB10-694B8192EABA}</ProjectGuid>
+ <RootNamespace>LibCecSharp</RootNamespace>
+ <Keyword>ManagedCProj</Keyword>
+ <TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v90</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ <CLRSupport>true</CLRSupport>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v90</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ <CLRSupport>true</CLRSupport>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v90</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ <CLRSupport>true</CLRSupport>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v90</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ <CLRSupport>true</CLRSupport>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>11.0.50727.1</_ProjectFileVersion>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ReferencePath>$(SolutionDir)..;$(ReferencePath)</ReferencePath>
+ <OutDir>$(SolutionDir)..\build\x86\</OutDir>
+ <IntDir>$(Configuration)\</IntDir>
+ <IncludePath>$(SolutionDir)..\src\libcec\platform\windows;$(OutDir)\include;$(IncludePath)</IncludePath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ReferencePath>$(SolutionDir)..;$(ReferencePath)</ReferencePath>
+ <OutDir>$(SolutionDir)..\build\amd64\</OutDir>
+ <IntDir>$(Platform)\$(Configuration)\</IntDir>
+ <LinkIncremental>true</LinkIncremental>
+ <IncludePath>$(SolutionDir)..\src\libcec\platform\windows;$(OutDir)\include;$(IncludePath)</IncludePath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ReferencePath>$(SolutionDir)..;$(ReferencePath)</ReferencePath>
+ <OutDir>$(SolutionDir)..\build\x86\</OutDir>
+ <IntDir>$(Configuration)\</IntDir>
+ <LinkIncremental>false</LinkIncremental>
+ <IncludePath>$(SolutionDir)..\src\libcec\platform\windows;$(OutDir)\include;$(IncludePath)</IncludePath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ReferencePath>$(SolutionDir)..;$(ReferencePath)</ReferencePath>
+ <OutDir>$(SolutionDir)..\build\amd64\</OutDir>
+ <IntDir>$(Platform)\$(Configuration)\</IntDir>
+ <IncludePath>$(SolutionDir)..\src\libcec\platform\windows;$(OutDir)\include;$(IncludePath)</IncludePath>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Midl>
+ <TargetEnvironment>X64</TargetEnvironment>
+ </Midl>
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>$(SolutionDir)..\include;$(SolutionDir)..\src;$(SolutionDir)..\src\lib\platform\windows;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_DEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <PrecompiledHeader />
+ <GenerateXMLDocumentationFiles>true</GenerateXMLDocumentationFiles>
+ <WarningLevel>Level3</WarningLevel>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>$(OutDir)cec.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AssemblyDebug>true</AssemblyDebug>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Midl>
+ <TargetEnvironment>X64</TargetEnvironment>
+ </Midl>
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>$(SolutionDir)..\include;$(SolutionDir)..\src;$(SolutionDir)..\src\lib\platform\windows;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_DEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <PrecompiledHeader />
+ <GenerateXMLDocumentationFiles>true</GenerateXMLDocumentationFiles>
+ <WarningLevel>Level3</WarningLevel>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>$(OutDir)cec.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AssemblyDebug>true</AssemblyDebug>
+ <TargetMachine>MachineX64</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Midl>
+ <TargetEnvironment>X64</TargetEnvironment>
+ </Midl>
+ <ClCompile>
+ <AdditionalIncludeDirectories>$(SolutionDir)..\include;$(SolutionDir)..\src;$(SolutionDir)..\src\lib\platform\windows;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>NDEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <PrecompiledHeader />
+ <GenerateXMLDocumentationFiles>true</GenerateXMLDocumentationFiles>
+ <WarningLevel>Level3</WarningLevel>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>$(OutDir)cec.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Midl>
+ <TargetEnvironment>X64</TargetEnvironment>
+ </Midl>
+ <ClCompile>
+ <AdditionalIncludeDirectories>$(SolutionDir)..\include;$(SolutionDir)..\src;$(SolutionDir)..\src\lib\platform\windows;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>NDEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <PrecompiledHeader />
+ <GenerateXMLDocumentationFiles>true</GenerateXMLDocumentationFiles>
+ <WarningLevel>Level3</WarningLevel>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>$(OutDir)cec.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <Reference Include="System">
+ <CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
+ <ReferenceOutputAssembly>true</ReferenceOutputAssembly>
+ </Reference>
+ <Reference Include="System.Data">
+ <CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
+ <ReferenceOutputAssembly>true</ReferenceOutputAssembly>
+ </Reference>
+ <Reference Include="System.Xml">
+ <CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
+ <ReferenceOutputAssembly>true</ReferenceOutputAssembly>
+ </Reference>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\..\src\LibCecSharp\AssemblyInfo.cpp" />
+ <ClCompile Include="..\..\src\LibCecSharp\LibCecSharp.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\..\include\cec.h" />
+ <ClInclude Include="..\..\src\LibCecSharp\CecSharpTypes.h" />
+ <ClInclude Include="..\..\include\cectypes.h" />
+ <ClInclude Include="..\..\src\libcec\platform\windows\stdint.h" />
+ <ClInclude Include="resource.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="LibCecSharp.rc" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\..\src\LibCecSharp\AssemblyInfo.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\LibCecSharp\LibCecSharp.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\..\include\cec.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\src\LibCecSharp\CecSharpTypes.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\include\cectypes.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="resource.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\src\libcec\platform\windows\stdint.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="LibCecSharp.rc" />
+ </ItemGroup>
+</Project>
\ No newline at end of file
--- /dev/null
+Name "Pulse-Eight libCEC v${LIBCEC_VERSION_MAJOR}.${LIBCEC_VERSION_MINOR}.${LIBCEC_VERSION_PATCH}"
+OutFile "..\build\libCEC-${LIBCEC_VERSION_MAJOR}.${LIBCEC_VERSION_MINOR}.${LIBCEC_VERSION_PATCH}.exe"
\ No newline at end of file
--- /dev/null
+;libCEC installer
+;Copyright (C) 2011-2016 Pulse-Eight Ltd.
+;http://www.pulse-eight.com/
+
+!include "MUI2.nsh"
+!include "nsDialogs.nsh"
+!include "LogicLib.nsh"
+!include "x64.nsh"
+!include "libCEC-version.nsh"
+
+XPStyle on
+InstallDir "$PROGRAMFILES\Pulse-Eight\USB-CEC Adapter"
+InstallDirRegKey HKLM "Software\Pulse-Eight\USB-CEC Adapter software" ""
+RequestExecutionLevel admin
+Var StartMenuFolder
+Var VSRedistSetupError
+Var VSRedistInstalledX64
+Var VSRedistInstalledX86
+Var EventGhostLocation
+
+!define MUI_FINISHPAGE_LINK "Visit http://libcec.pulse-eight.com/ for more information."
+!define MUI_FINISHPAGE_LINK_LOCATION "http://libcec.pulse-eight.com/"
+!define MUI_ABORTWARNING
+
+!insertmacro MUI_PAGE_WELCOME
+!insertmacro MUI_PAGE_LICENSE "..\COPYING"
+!insertmacro MUI_PAGE_COMPONENTS
+!insertmacro MUI_PAGE_DIRECTORY
+
+!define MUI_STARTMENUPAGE_REGISTRY_ROOT "HKLM"
+!define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\Pulse-Eight\USB-CEC Adapter sofware"
+!define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder"
+!insertmacro MUI_PAGE_STARTMENU Application $StartMenuFolder
+
+!insertmacro MUI_PAGE_INSTFILES
+!insertmacro MUI_PAGE_FINISH
+
+!insertmacro MUI_UNPAGE_WELCOME
+!insertmacro MUI_UNPAGE_CONFIRM
+!insertmacro MUI_UNPAGE_INSTFILES
+!insertmacro MUI_UNPAGE_FINISH
+
+!insertmacro MUI_LANGUAGE "English"
+
+InstType "USB-CEC Driver & libCEC"
+InstType "USB-CEC Driver Only"
+InstType "Full installation"
+
+Section "USB-CEC Driver" SecDriver
+ SetShellVarContext current
+ SectionIn RO
+ SectionIn 1 2 3
+
+ ; Renamed to cec.dll
+ Delete "$INSTDIR\libcec.dll"
+ ${If} ${RunningX64}
+ Delete "$INSTDIR\x64\libcec.dll"
+ ${EndIf}
+
+ ; Copy to the installation directory
+ SetOutPath "$INSTDIR"
+ File "..\AUTHORS"
+ File "..\COPYING"
+
+ ; Copy the driver installer
+ SetOutPath "$INSTDIR\driver"
+ File "..\build\p8-usbcec-driver-installer.exe"
+
+ ;Store installation folder
+ WriteRegStr HKLM "Software\Pulse-Eight\USB-CEC Adapter software" "" $INSTDIR
+
+ ;Create uninstaller
+ WriteUninstaller "$INSTDIR\Uninstall.exe"
+
+ !insertmacro MUI_STARTMENU_WRITE_BEGIN Application
+ SetOutPath "$INSTDIR"
+
+ CreateDirectory "$SMPROGRAMS\$StartMenuFolder"
+ CreateShortCut "$SMPROGRAMS\$StartMenuFolder\Uninstall Pulse-Eight USB-CEC Adapter software.lnk" "$INSTDIR\Uninstall.exe" \
+ "" "$INSTDIR\Uninstall.exe" 0 SW_SHOWNORMAL \
+ "" "Uninstall Pulse-Eight USB-CEC Adapter software."
+
+ WriteINIStr "$SMPROGRAMS\$StartMenuFolder\Visit Pulse-Eight.url" "InternetShortcut" "URL" "http://www.pulse-eight.com/"
+ !insertmacro MUI_STARTMENU_WRITE_END
+
+ ;add entry to add/remove programs
+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pulse-Eight USB-CEC Adapter sofware" \
+ "DisplayName" "Pulse-Eight USB-CEC Adapter software"
+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pulse-Eight USB-CEC Adapter sofware" \
+ "UninstallString" "$INSTDIR\uninstall.exe"
+ WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pulse-Eight USB-CEC Adapter sofware" \
+ "NoModify" 1
+ WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pulse-Eight USB-CEC Adapter sofware" \
+ "NoRepair" 1
+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pulse-Eight USB-CEC Adapter sofware" \
+ "InstallLocation" "$INSTDIR"
+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pulse-Eight USB-CEC Adapter sofware" \
+ "DisplayIcon" "$INSTDIR\cec-client.exe,0"
+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pulse-Eight USB-CEC Adapter sofware" \
+ "Publisher" "Pulse-Eight Limited"
+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pulse-Eight USB-CEC Adapter sofware" \
+ "HelpLink" "http://www.pulse-eight.com/"
+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pulse-Eight USB-CEC Adapter sofware" \
+ "URLInfoAbout" "http://www.pulse-eight.com"
+
+ ;install driver
+ ExecWait '"$INSTDIR\driver\p8-usbcec-driver-installer.exe" /S'
+ Delete "$INSTDIR\driver\p8-usbcec-driver-installer.exe"
+SectionEnd
+
+Section "libCEC" SecLibCec
+ SetShellVarContext current
+ SectionIn 1 3
+
+ ; Copy to the installation directory
+ SetOutPath "$INSTDIR"
+ File "..\ChangeLog"
+ File "..\README.md"
+ File "..\build\x86\*.dll"
+ File "..\build\x86\*.xml"
+ SetOutPath "$INSTDIR\x64"
+ File /nonfatal "..\build\amd64\*.dll"
+ File /nonfatal "..\build\amd64\*.xml"
+
+ ; Copy to Kodi\system
+ ReadRegStr $1 HKCU "Software\Kodi" ""
+ ${If} $1 != ""
+ SetOutPath "$1\system"
+ File "..\build\x86\libcec.dll"
+ ${EndIf}
+
+ ; Copy the headers
+ SetOutPath "$INSTDIR\include"
+ File /r /x *.so "..\build\x86\include\libcec\cec*.*"
+ File /r /x *.so "..\build\x86\include\libcec\version.h"
+SectionEnd
+
+Section "CEC Debug Client" SecCecClient
+ SetShellVarContext current
+ SectionIn 3
+
+ ; Copy to the installation directory
+ SetOutPath "$INSTDIR"
+ File "..\build\x86\cec-client.exe"
+ File "..\build\x86\cecc-client.exe"
+ SetOutPath "$INSTDIR\x64"
+ File /nonfatal "..\build\amd64\cec-client.exe"
+ File /nonfatal "..\build\amd64\cecc-client.exe"
+
+ !insertmacro MUI_STARTMENU_WRITE_BEGIN Application
+ SetOutPath "$INSTDIR"
+
+ CreateDirectory "$SMPROGRAMS\$StartMenuFolder"
+ ${If} ${RunningX64}
+ CreateShortCut "$SMPROGRAMS\$StartMenuFolder\CEC Test client (x64).lnk" "$INSTDIR\x64\cec-client.exe" \
+ "" "$INSTDIR\x64\cec-client.exe" 0 SW_SHOWNORMAL \
+ "" "Start the CEC Test client (x64)."
+ ${Else}
+ CreateShortCut "$SMPROGRAMS\$StartMenuFolder\CEC Test client.lnk" "$INSTDIR\cec-client.exe" \
+ "" "$INSTDIR\cec-client.exe" 0 SW_SHOWNORMAL \
+ "" "Start the CEC Test client."
+ ${EndIf}
+ !insertmacro MUI_STARTMENU_WRITE_END
+
+SectionEnd
+
+Section "libCEC Tray" SecDotNet
+ SetShellVarContext current
+ SectionIn 1 3
+
+ ; Copy to the installation directory
+ SetOutPath "$INSTDIR"
+ File "..\build\x86\CecSharpTester.exe"
+ File "..\build\x86\cec-tray.exe"
+ SetOutPath "$INSTDIR\x64"
+ File /nonfatal "..\build\amd64\CecSharpTester.exe"
+ File /nonfatal "..\build\amd64\cec-tray.exe"
+
+ !insertmacro MUI_STARTMENU_WRITE_BEGIN Application
+ SetOutPath "$INSTDIR"
+
+ CreateDirectory "$SMPROGRAMS\$StartMenuFolder"
+ ${If} ${RunningX64}
+ CreateShortCut "$SMPROGRAMS\$StartMenuFolder\cec-tray.lnk" "$INSTDIR\x64\cec-tray.exe" \
+ "" "$INSTDIR\x64\cec-tray.exe" 0 SW_SHOWNORMAL \
+ "" "Start libCEC Tray (x64)."
+ ${Else}
+ CreateShortCut "$SMPROGRAMS\$StartMenuFolder\cec-tray.lnk" "$INSTDIR\cec-tray.exe" \
+ "" "$INSTDIR\cec-tray.exe" 0 SW_SHOWNORMAL \
+ "" "Start libCEC Tray."
+ ${EndIf}
+ !insertmacro MUI_STARTMENU_WRITE_END
+
+SectionEnd
+
+Section "Python bindings" SecPythonCec
+ SetShellVarContext current
+ SectionIn 1 3
+
+ ; Copy to the installation directory
+ SetOutPath "$INSTDIR\python"
+ File "..\build\x86\python\pyCecClient.py"
+ SetOutPath "$INSTDIR\python\cec"
+ File "..\build\x86\python\cec\__init__.py"
+ File "..\build\x86\python\cec\_cec.pyd"
+SectionEnd
+
+!define EVENTGHOST_SECTIONNAME "EventGhost plugin"
+Section "" SecEvGhostCec
+ SetShellVarContext current
+ SectionIn 1 3
+
+ ${If} $EventGhostLocation != ""
+ SetOutPath "$EventGhostLocation\plugins\libCEC\cec"
+ File "..\build\x86\cec.dll"
+ File "..\build\x86\python\cec\__init__.py"
+ File "..\build\x86\python\cec\_cec.pyd"
+
+ SetOutPath "$EventGhostLocation\plugins\libCEC"
+ File "..\src\EventGhost\__init__.py"
+ File "..\src\EventGhost\cec.png"
+
+ SetOutPath $EventGhostLocation
+ File "..\src\EventGhost\libCEC_Demo_Configuration.xml"
+ ${EndIf}
+SectionEnd
+
+!define REDISTRIBUTABLE_X86_SECTIONNAME "Microsoft Visual C++ 2013 Redistributable Package (x86)"
+Section "" SecVCRedistX86
+ SetShellVarContext current
+ SectionIn 1 3
+
+ SetOutPath "$TEMP\vc2013_x86"
+
+ ${If} $VSRedistInstalledX86 != "Yes"
+ NSISdl::download http://download.microsoft.com/download/2/E/6/2E61CFA4-993B-4DD4-91DA-3737CD5CD6E3/vcredist_x86.exe vcredist_x86.exe
+ ExecWait '"$TEMP\vc2013_x86\vcredist_x86.exe" /q' $VSRedistSetupError
+ ${Endif}
+
+ RMDIR /r "$TEMP\vc2013_x86"
+SectionEnd
+
+!define REDISTRIBUTABLE_X64_SECTIONNAME "Microsoft Visual C++ 2013 Redistributable Package (x64)"
+Section "" SecVCRedistX64
+ SetShellVarContext current
+ SectionIn 1 3
+
+ SetOutPath "$TEMP\vc2013_x64"
+
+ ${If} $VSRedistInstalledX64 != "Yes"
+ NSISdl::download http://download.microsoft.com/download/2/E/6/2E61CFA4-993B-4DD4-91DA-3737CD5CD6E3/vcredist_x64.exe vcredist_x64.exe
+ ExecWait '"$TEMP\vc2013_x64\vcredist_x64.exe" /q' $VSRedistSetupError
+ ${Endif}
+
+ RMDIR /r "$TEMP\vc2013_x64"
+SectionEnd
+
+Function .onInit
+ ; check for vc2013 x86 redist
+ ReadRegDword $1 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{f65db027-aff3-4070-886a-0d87064aabb1}" "BundleVersion"
+ ${If} $1 != ""
+ StrCpy $VSRedistInstalledX86 "Yes"
+ ${Endif}
+
+ ${If} $VSRedistInstalledX86 == "Yes"
+ !insertMacro UnSelectSection ${SecVCRedistX86}
+ SectionSetText ${SecVCRedistX86} ""
+ ${Else}
+ !insertMacro SelectSection ${SecVCRedistX86}
+ SectionSetText ${SecVCRedistX86} "${REDISTRIBUTABLE_X86_SECTIONNAME}"
+ ${Endif}
+
+ ${If} ${RunningX64}
+ ; check for vc2013 x64 redist
+ ReadRegDword $1 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{050d4fc8-5d48-4b8f-8972-47c82c46020f}" "BundleVersion"
+ ${If} $1 != ""
+ StrCpy $VSRedistInstalledX64 "Yes"
+ ${Endif}
+
+ ${If} $VSRedistInstalledX64 == "Yes"
+ !insertMacro UnSelectSection ${SecVCRedistX64}
+ SectionSetText ${SecVCRedistX64} ""
+ ${Else}
+ !insertMacro SelectSection ${SecVCRedistX64}
+ SectionSetText ${SecVCRedistX64} "${REDISTRIBUTABLE_X64_SECTIONNAME}"
+ ${Endif}
+ ${Else}
+ !insertMacro UnSelectSection ${SecVCRedistX64}
+ SectionSetText ${SecVCRedistX64} ""
+ ${Endif}
+
+ ; check for EventGhost
+ ReadRegDword $1 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\EventGhost_is1" "InstallLocation"
+ ${If} $1 != ""
+ StrCpy $EventGhostLocation "$1"
+ !insertMacro SelectSection ${SecEvGhostCec}
+ SectionSetText ${SecEvGhostCec} "${EVENTGHOST_SECTIONNAME}"
+ ${Else}
+ !insertMacro UnSelectSection ${SecEvGhostCec}
+ SectionSetText ${SecEvGhostCec} ""
+ MessageBox MB_OK \
+ "EventGhost was found found, so the plugin for EventGhost will not be installed. You can download EventGhost from http://www.eventghost.org/"
+ ${Endif}
+
+FunctionEnd
+
+;--------------------------------
+;Uninstaller Section
+Section "Uninstall"
+
+ SetShellVarContext current
+
+ Delete "$INSTDIR\AUTHORS"
+ Delete "$INSTDIR\*.exe"
+ Delete "$INSTDIR\ChangeLog"
+ Delete "$INSTDIR\COPYING"
+ Delete "$INSTDIR\*.dll"
+ Delete "$INSTDIR\*.lib"
+ Delete "$INSTDIR\*.xml"
+ Delete "$INSTDIR\x64\*.dll"
+ Delete "$INSTDIR\x64\*.lib"
+ Delete "$INSTDIR\x64\*.exe"
+ Delete "$INSTDIR\x64\*.xml"
+ Delete "$INSTDIR\README.md"
+ Delete "$SYSDIR\libcec.dll"
+ ${If} ${RunningX64}
+ Delete "$SYSDIR\libcec.x64.dll"
+ ${EndIf}
+
+ ; Uninstall EventGhost plugin
+ ReadRegDword $1 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\EventGhost_is1" "InstallLocation"
+ ${If} $1 != ""
+ RMDir /r "$1\plugins\libCEC"
+ Delete "$1\libCEC_Demo_Configuration.xml"
+ ${Endif}
+
+ ; Uninstall the driver
+ ReadRegStr $1 HKLM "Software\Pulse-Eight\USB-CEC Adapter driver" ""
+ ${If} $1 != ""
+ ExecWait '"$1\Uninstall.exe" /S _?=$1'
+ ${EndIf}
+
+ RMDir /r "$INSTDIR\include"
+ Delete "$INSTDIR\Uninstall.exe"
+ RMDir /r "$INSTDIR"
+ RMDir "$PROGRAMFILES\Pulse-Eight"
+
+ !insertmacro MUI_STARTMENU_GETFOLDER Application $StartMenuFolder
+ Delete "$SMPROGRAMS\$StartMenuFolder\libCEC Tray.lnk"
+ ${If} ${RunningX64}
+ Delete "$SMPROGRAMS\$StartMenuFolder\libCEC Tray (x64).lnk"
+ ${EndIf}
+ Delete "$SMPROGRAMS\$StartMenuFolder\cec-tray.lnk"
+ Delete "$SMPROGRAMS\$StartMenuFolder\CEC Test client.lnk"
+ ${If} ${RunningX64}
+ Delete "$SMPROGRAMS\$StartMenuFolder\CEC Test client (x64).lnk"
+ ${EndIf}
+ Delete "$SMPROGRAMS\$StartMenuFolder\Uninstall Pulse-Eight USB-CEC Adapter software.lnk"
+ Delete "$SMPROGRAMS\$StartMenuFolder\Visit Pulse-Eight.url"
+ RMDir "$SMPROGRAMS\$StartMenuFolder"
+
+ DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pulse-Eight USB-CEC Adapter sofware"
+ DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pulse-Eight USB-CEC Adapter driver"
+ DeleteRegKey /ifempty HKLM "Software\Pulse-Eight\USB-CEC Adapter software"
+ DeleteRegKey /ifempty HKLM "Software\Pulse-Eight"
+SectionEnd
--- /dev/null
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0.31101.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LibCecSharp", "LibCecSharp\LibCecSharp.vcxproj", "{E54D4581-CD59-4687-BB10-694B8192EABA}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{B119505D-5CD1-48E4-BED1-9C2BF26153D5}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {E54D4581-CD59-4687-BB10-694B8192EABA}.Debug|x64.ActiveCfg = Debug|x64
+ {E54D4581-CD59-4687-BB10-694B8192EABA}.Debug|x64.Build.0 = Debug|x64
+ {E54D4581-CD59-4687-BB10-694B8192EABA}.Debug|x86.ActiveCfg = Debug|Win32
+ {E54D4581-CD59-4687-BB10-694B8192EABA}.Debug|x86.Build.0 = Debug|Win32
+ {E54D4581-CD59-4687-BB10-694B8192EABA}.Release|x64.ActiveCfg = Release|x64
+ {E54D4581-CD59-4687-BB10-694B8192EABA}.Release|x64.Build.0 = Release|x64
+ {E54D4581-CD59-4687-BB10-694B8192EABA}.Release|x86.ActiveCfg = Release|Win32
+ {E54D4581-CD59-4687-BB10-694B8192EABA}.Release|x86.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
--- /dev/null
+# -*- coding: utf-8 -*-
+# This file is part of the libCEC(R) library.
+#
+# libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+# libCEC(R) is an original work, containing original code.
+#
+# libCEC(R) is a trademark of Pulse-Eight Limited.
+#
+# This program is dual-licensed; 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
+#
+#
+# Alternatively, you can license this library under a commercial license,
+# please contact Pulse-Eight Licensing for more information.
+#
+# For more information contact:
+# Pulse-Eight Licensing <license@pulse-eight.com>
+# http://www.pulse-eight.com/
+# http://www.pulse-eight.net/
+
+description = """<rst>
+Integration with libCEC, which adds support for Pulse-Eight's `CEC adapters <http://www.pulse-eight.com/>`_.
+
+|
+
+.. image:: cec.png
+ :align: center
+
+**Notice:**
+Set up the HDMI input to which your adapter is connected correctly, or remote control input won't work.
+"""
+
+import cec
+
+eg.RegisterPlugin(
+ name = 'Pulse-Eight CEC adapter',
+ author = 'Lars Op den Kamp',
+ version = '0.3',
+ kind = 'remote',
+ guid = '{fd322eea-c897-470c-bef7-77bf15c52db4}',
+ url = 'http://libcec.pulse-eight.com/',
+ description = description,
+ createMacrosOnAdd = False,
+ hardwareId = "USB\\VID_2548&PID_1002",
+)
+
+# logging callback
+def log_callback(level, time, message):
+ return CEC.instance.LogCallback(level, time, message)
+
+# key press callback
+def key_press_callback(key, duration):
+ return CEC.instance.KeyPressCallback(key, duration)
+
+class CEC(eg.PluginClass):
+ instance = {}
+ logicalAddressNames = []
+ lastKeyPressed = 255
+
+ # detect an adapter and return the com port path
+ def DetectAdapter(self):
+ retval = None
+ adapters = self.lib.DetectAdapters()
+ for adapter in adapters:
+ print("found a CEC adapter: " + adapter.strComName)
+ retval = adapter.strComName
+ return retval
+
+ # initialise libCEC
+ def InitLibCec(self, connectedAvr, portNumber, deviceName):
+ if connectedAvr:
+ self.cecconfig.baseDevice = cec.CECDEVICE_AUDIOSYSTEM
+ else:
+ self.cecconfig.baseDevice = cec.CECDEVICE_TV
+ self.cecconfig.iHDMIPort = portNumber
+ self.cecconfig.strDeviceName = str(deviceName)
+ self.cecconfig.bActivateSource = 0
+
+ self.lib = cec.ICECAdapter.Create(self.cecconfig)
+
+ # search for adapters
+ adapter = self.DetectAdapter()
+ if adapter == None:
+ print("No adapters found")
+ else:
+ if self.lib.Open(adapter):
+ print("connection opened")
+ return True
+ else:
+ print("failed to open a connection to the CEC adapter")
+ return False
+
+ def __init__(self):
+ self.log_level = cec.CEC_LOG_WARNING
+ self.cecconfig = cec.libcec_configuration()
+ self.cecconfig.clientVersion = cec.LIBCEC_VERSION_CURRENT
+ self.cecconfig.deviceTypes.Add(cec.CEC_DEVICE_TYPE_RECORDING_DEVICE)
+ self.cecconfig.SetLogCallback(log_callback)
+ self.cecconfig.SetKeyPressCallback(key_press_callback)
+ CEC.instance = self
+ self.AddGroup("Actions", ACTIONS)
+ self.AddActionsFromList(ACTIONS)
+ self.AddGroup("Queries", QUERIES)
+ self.AddActionsFromList(QUERIES)
+
+ def __start__(self, connectedAvr, portNumber, deviceName):
+ if self.InitLibCec(connectedAvr, portNumber, deviceName):
+ # print libCEC version and compilation information
+ print("libCEC version " + self.lib.VersionToString(self.cecconfig.serverVersion) + " loaded: " + self.lib.GetLibInfo())
+ self.logicalAddressNames = [ self.lib.LogicalAddressToString(cec.CECDEVICE_TV),
+ self.lib.LogicalAddressToString(cec.CECDEVICE_RECORDINGDEVICE1),
+ self.lib.LogicalAddressToString(cec.CECDEVICE_RECORDINGDEVICE2),
+ self.lib.LogicalAddressToString(cec.CECDEVICE_TUNER1),
+ self.lib.LogicalAddressToString(cec.CECDEVICE_PLAYBACKDEVICE1),
+ self.lib.LogicalAddressToString(cec.CECDEVICE_AUDIOSYSTEM),
+ self.lib.LogicalAddressToString(cec.CECDEVICE_TUNER2),
+ self.lib.LogicalAddressToString(cec.CECDEVICE_TUNER3),
+ self.lib.LogicalAddressToString(cec.CECDEVICE_PLAYBACKDEVICE2),
+ self.lib.LogicalAddressToString(cec.CECDEVICE_RECORDINGDEVICE3),
+ self.lib.LogicalAddressToString(cec.CECDEVICE_TUNER4),
+ self.lib.LogicalAddressToString(cec.CECDEVICE_PLAYBACKDEVICE3),
+ self.lib.LogicalAddressToString(cec.CECDEVICE_RESERVED1),
+ self.lib.LogicalAddressToString(cec.CECDEVICE_RESERVED2),
+ self.lib.LogicalAddressToString(cec.CECDEVICE_FREEUSE),
+ self.lib.LogicalAddressToString(cec.CECDEVICE_BROADCAST),
+ self.lib.LogicalAddressToString(cec.CECDEVICE_UNKNOWN),]
+ else:
+ print("Couldn't initialise libCEC. Please check your configuration.")
+
+ def __stop__(self):
+ self.lib.Close()
+
+ def Configure(self, connectedAvr = False, portNumber = 1, deviceName = "libCEC"):
+ panel = eg.ConfigPanel()
+ spPortNumber = panel.SpinIntCtrl(portNumber, min=1, max=15)
+ cbConnectedAvr = panel.CheckBox(connectedAvr, "")
+ bxConnection = panel.BoxedGroup(
+ "Connection",
+ ("Connected to AVR", cbConnectedAvr),
+ ("HDMI port number:", spPortNumber),
+ )
+ panel.sizer.Add(bxConnection, 0, wx.EXPAND)
+
+ txDeviceName = panel.TextCtrl(deviceName)
+ bxDevice = panel.BoxedGroup(
+ "Device configuration",
+ ("Device name", txDeviceName),
+ )
+ panel.sizer.Add(bxDevice, 0, wx.EXPAND)
+
+ while panel.Affirmed():
+ panel.SetResult(cbConnectedAvr.GetValue(), spPortNumber.GetValue(), txDeviceName.GetValue())
+
+ def Transmit(self, txcmd):
+ self.lib.Transmit(self.lib.CommandFromString(txcmd))
+
+ # logging callback
+ def LogCallback(self, level, time, message):
+ if level > self.log_level:
+ return 0
+
+ if level == cec.CEC_LOG_ERROR:
+ levelstr = "ERROR: "
+ elif level == cec.CEC_LOG_WARNING:
+ levelstr = "WARNING: "
+ elif level == cec.CEC_LOG_NOTICE:
+ levelstr = "NOTICE: "
+ elif level == cec.CEC_LOG_TRAFFIC:
+ levelstr = "TRAFFIC: "
+ elif level == cec.CEC_LOG_DEBUG:
+ levelstr = "DEBUG: "
+
+ print("CEC " + levelstr + "[" + str(time) + "] " + message)
+ return 0
+
+ # key press callback
+ def KeyPressCallback(self, key, duration):
+ if duration == 0 and self.lastKeyPressed != key:
+ self.lastKeyPressed = key
+ self.TriggerEnduringEvent(self.lib.UserControlCodeToString(key))
+ elif duration > 0 and self.lastKeyPressed == key:
+ self.lastKeyPressed = 255
+ self.EndLastEvent()
+ elif self.lastKeyPressed != key:
+ self.lastKeyPressed = 255
+ self.TriggerEvent(self.lib.UserControlCodeToString(key))
+ return 0
+
+ def NumberToLogicalAddress(self, value):
+ if value == 0:
+ return "cec.CECDEVICE_TV"
+ elif value == 1:
+ return "cec.CECDEVICE_RECORDINGDEVICE1"
+ elif value == 2:
+ return "cec.CECDEVICE_RECORDINGDEVICE2"
+ elif value == 3:
+ return "cec.CECDEVICE_TUNER1"
+ elif value == 4:
+ return "cec.CECDEVICE_PLAYBACKDEVICE1"
+ elif value == 5:
+ return "cec.CECDEVICE_AUDIOSYSTEM"
+ elif value == 6:
+ return "cec.CECDEVICE_TUNER2"
+ elif value == 7:
+ return "cec.CECDEVICE_TUNER3"
+ elif value == 8:
+ return "cec.CECDEVICE_PLAYBACKDEVICE2"
+ elif value == 9:
+ return "cec.CECDEVICE_RECORDINGDEVICE3"
+ elif value == 10:
+ return "cec.CECDEVICE_TUNER4"
+ elif value == 11:
+ return "cec.CECDEVICE_PLAYBACKDEVICE3"
+ elif value == 12:
+ return "cec.CECDEVICE_RESERVED1"
+ elif value == 13:
+ return "cec.CECDEVICE_RESERVED2"
+ elif value == 14:
+ return "cec.CECDEVICE_FREEUSE"
+ elif value == 15:
+ return "cec.CECDEVICE_BROADCAST"
+ return "cec.CECDEVICE_UNKNOWN"
+
+ def command(self, command):
+ eval(command)
+
+ def query(self, command):
+ return eval(command)
+
+class ActionNoParam(eg.ActionClass):
+ def __call__(self):
+ self.plugin.command(self.value)
+
+class ActionParamString(eg.ActionClass):
+ def __call__(self, value = ""):
+ self.plugin.command(self.value.format(str(value)))
+
+ def Configure(self, value = ""):
+ panel = eg.ConfigPanel()
+ valueCtrl = panel.TextCtrl(value)
+ valueBox = panel.BoxedGroup("Enter value", ("Value:", valueCtrl),)
+ panel.sizer.Add(valueBox, 0, wx.EXPAND)
+ while panel.Affirmed():
+ panel.SetResult(valueCtrl.GetValue(),)
+
+class ActionParamLogicalAddress(eg.ActionClass):
+ names = []
+ selectedValue = 0
+
+ def __call__(self, value = "cec.CECDEVICE_UNKNOWN"):
+ self.plugin.command(self.value.format(value))
+
+ def Configure(self, value = "cec.CECDEVICE_UNKNOWN"):
+ self.names = self.plugin.logicalAddressNames
+ panel = eg.ConfigPanel()
+
+ cbAddresses = wx.ComboBox(panel, -1, choices = self.names)
+ cbAddresses.SetStringSelection(self.plugin.lib.LogicalAddressToString(cec.CECDEVICE_UNKNOWN))
+
+ def cbAddressesChanged(event = None):
+ evtName = cbAddresses.GetValue()
+ if evtName in self.names:
+ self.selectedValue = self.names.index(evtName)
+ if event:
+ event.Skip()
+ cbAddressesChanged()
+ cbAddresses.Bind(wx.EVT_COMBOBOX, cbAddressesChanged)
+ panel.sizer.Add(cbAddresses)
+
+ while panel.Affirmed():
+ panel.SetResult(self.plugin.NumberToLogicalAddress(self.selectedValue),)
+
+class QueryParamLogicalAddress(eg.ActionClass):
+ names = []
+ selectedValue = 0
+
+ def __call__(self, value = "cec.CECDEVICE_UNKNOWN"):
+ return self.plugin.query(self.value.format(value))
+
+ def Configure(self, value = "cec.CECDEVICE_UNKNOWN"):
+ self.names = self.plugin.logicalAddressNames
+ panel = eg.ConfigPanel()
+
+ cbAddresses = wx.ComboBox(panel, -1, choices = self.names)
+ cbAddresses.SetStringSelection(self.plugin.lib.LogicalAddressToString(cec.CECDEVICE_UNKNOWN))
+
+ def cbAddressesChanged(event = None):
+ evtName = cbAddresses.GetValue()
+ if evtName in self.names:
+ self.selectedValue = self.names.index(evtName)
+ if event:
+ event.Skip()
+ cbAddressesChanged()
+ cbAddresses.Bind(wx.EVT_COMBOBOX, cbAddressesChanged)
+ panel.sizer.Add(cbAddresses)
+
+ while panel.Affirmed():
+ panel.SetResult(self.plugin.NumberToLogicalAddress(self.selectedValue),)
+
+ACTIONS = (
+ (ActionNoParam, 'ActiveSource', 'Active source', 'Mark this device as active source, which will turn on the TV and switch it to the correct input', u'self.lib.SetActiveSource()'),
+ (ActionNoParam, 'InactiveView', 'Inactive view', 'Mark this source as inactive. The result can be different per TV. Most will switch to the previous source', u'self.lib.SetInactiveView()'),
+ (ActionParamLogicalAddress, 'PowerOn', 'Power on device', 'Power on the given device', u'self.lib.PowerOnDevices({0})'),
+ (ActionNoParam, 'StandbyAll', 'Standby all devices', 'Send the TV and any other CEC capable device to standby', u'self.lib.StandbyDevices(cec.CECDEVICE_BROADCAST)'),
+ (ActionParamLogicalAddress, 'Standby', 'Standby device', 'Send the given device to standby (if present)', u'self.lib.StandbyDevices({0})'),
+
+ (ActionNoParam, 'VolumeUp', 'Volume up', 'Send a volume up command to the AVR (if present)', u'self.lib.VolumeUp()'),
+ (ActionNoParam, 'VolumeDown', 'Volume down', 'Send a volume down command to the AVR (if present)', u'self.lib.VolumeDown()'),
+ (ActionNoParam, 'ToggleMute', 'Toggle volume mute', 'Send a mute toggle command to the AVR (if present)', u'self.lib.MuteAudio()'),
+
+ (ActionParamString, 'RawCommand', 'Send command', 'Send a raw CEC command', u'self.lib.Transmit(self.lib.CommandFromString(\'{0}\'))'),
+)
+
+QUERIES = (
+ (QueryParamLogicalAddress, 'GetCecVersion', 'Get device CEC version', 'Request the CEC version', u'self.lib.CecVersionToString(self.lib.GetDeviceCecVersion({0}))'),
+ (QueryParamLogicalAddress, 'GetMenuLanguage', 'Get device menu language', 'Request the menu language', u'self.lib.GetDeviceMenuLanguage({0})'),
+ (QueryParamLogicalAddress, 'GetVendorId', 'Get device vendor id', 'Request the vendor id', u'self.lib.VendorIdToString(self.lib.GetDeviceVendorId({0}))'),
+ (QueryParamLogicalAddress, 'GetPowerStatus', 'Get device power status', 'Request the power status', u'self.lib.PowerStatusToString(self.lib.GetDevicePowerStatus({0}))'),
+)
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" ?>
+<EventGhost Version="1700" Guid="{3D8D6723-D5B0-4546-B12F-23B5C6CE223A}" Time="1428063932.02">
+ <Autostart Name="Autostart" Expanded="True">
+ <Plugin Identifier="CEC" Guid="{FD322EEA-C897-470C-BEF7-77BF15C52DB4}" File="evcec">
+ gAKJSwFYBgAAAGxpYkNFQ3EAh3EBLg==
+ </Plugin>
+ </Autostart>
+ <Folder Name="CEC adapter demo" Expanded="True">
+ <Folder Name="AVR">
+ <Macro Name="Power on AVR" id="6">
+ <Action>
+ CEC.PowerOn('cec.CECDEVICE_AUDIOSYSTEM')
+ </Action>
+ </Macro>
+ <Macro Name="Power on AVR if in standby">
+ <Action>
+ CEC.GetPowerStatus('cec.CECDEVICE_AUDIOSYSTEM')
+ </Action>
+ <Action>
+ EventGhost.PythonCommand(u"eg.result == 'standby'")
+ </Action>
+ <Action>
+ EventGhost.NewJumpIf(XmlIdLink(6), 0, False)
+ </Action>
+ </Macro>
+ <Macro Name="Power off AVR if on">
+ <Action>
+ CEC.GetPowerStatus('cec.CECDEVICE_AUDIOSYSTEM')
+ </Action>
+ <Action>
+ EventGhost.PythonCommand(u"eg.result == 'on'")
+ </Action>
+ <Action>
+ EventGhost.NewJumpIf(XmlIdLink(16), 0, False)
+ </Action>
+ </Macro>
+ <Macro Name="Power off AVR" id="16">
+ <Action>
+ CEC.Standby('cec.CECDEVICE_AUDIOSYSTEM')
+ </Action>
+ </Macro>
+ <Macro Name="Pulse-Eight CEC adapter: Volume up">
+ <Action>
+ CEC.VolumeUp()
+ </Action>
+ </Macro>
+ <Macro Name="Pulse-Eight CEC adapter: Volume down">
+ <Action>
+ CEC.VolumeDown()
+ </Action>
+ </Macro>
+ <Macro Name="Pulse-Eight CEC adapter: Toggle volume mute">
+ <Action>
+ CEC.ToggleMute()
+ </Action>
+ </Macro>
+ </Folder>
+ <Folder Name="TV" Expanded="True">
+ <Macro Name="Power on TV" id="19">
+ <Action>
+ CEC.PowerOn('cec.CECDEVICE_TV')
+ </Action>
+ </Macro>
+ <Macro Name="Power off TV" id="21">
+ <Action>
+ CEC.Standby('cec.CECDEVICE_TV')
+ </Action>
+ </Macro>
+ <Macro Name="Power on TV if in standby">
+ <Action>
+ CEC.GetPowerStatus('cec.CECDEVICE_TV')
+ </Action>
+ <Action>
+ EventGhost.PythonCommand(u"eg.result == 'standby'")
+ </Action>
+ <Action>
+ EventGhost.NewJumpIf(XmlIdLink(19), 0, False)
+ </Action>
+ </Macro>
+ <Macro Name="Power off TV if on">
+ <Action>
+ CEC.GetPowerStatus('cec.CECDEVICE_TV')
+ </Action>
+ <Action>
+ EventGhost.PythonCommand(u"eg.result == 'standby'")
+ </Action>
+ <Action>
+ EventGhost.NewJumpIf(XmlIdLink(21), 0, False)
+ </Action>
+ </Macro>
+ </Folder>
+ <Macro Name="Pulse-Eight CEC adapter: Active source">
+ <Action>
+ CEC.ActiveSource()
+ </Action>
+ </Macro>
+ <Macro Name="Pulse-Eight CEC adapter: Inactive view">
+ <Action>
+ CEC.InactiveView()
+ </Action>
+ </Macro>
+ <Folder Name="Keyboard">
+ <Macro Name="Emulate Keystrokes: {Up}">
+ <Event Name="CEC.up" />
+ <Action>
+ Window.SendKeys(u'{Up}', False)
+ </Action>
+ <Action>
+ EventGhost.AutoRepeat(0.59999999999999998, 0.29999999999999999, 0.01, 3.0)
+ </Action>
+ </Macro>
+ <Macro Name="Emulate Keystrokes: {Down}">
+ <Event Name="CEC.down" />
+ <Action>
+ Window.SendKeys(u'{Down}', False)
+ </Action>
+ <Action>
+ EventGhost.AutoRepeat(0.59999999999999998, 0.29999999999999999, 0.01, 3.0)
+ </Action>
+ </Macro>
+ <Macro Name="Emulate Keystrokes: {Left}">
+ <Event Name="CEC.left" />
+ <Action>
+ Window.SendKeys(u'{Left}', False)
+ </Action>
+ <Action>
+ EventGhost.AutoRepeat(0.59999999999999998, 0.29999999999999999, 0.01, 3.0)
+ </Action>
+ </Macro>
+ <Macro Name="Emulate Keystrokes: {Right}">
+ <Event Name="CEC.right" />
+ <Action>
+ Window.SendKeys(u'{Right}', False)
+ </Action>
+ <Action>
+ EventGhost.AutoRepeat(0.59999999999999998, 0.29999999999999999, 0.01, 3.0)
+ </Action>
+ </Macro>
+ <Macro Name="Emulate Keystrokes: {Backspace}">
+ <Event Name="CEC.exit" />
+ <Action>
+ EventGhost.JumpIfLongPress(1.0, XmlIdLink(25))
+ </Action>
+ <Action>
+ Window.SendKeys(u'{Backspace}', False)
+ </Action>
+ </Macro>
+ <Macro Name="Emulate Keystrokes: {Escape}" id="25">
+ <Action>
+ Window.SendKeys(u'{Escape}', False)
+ </Action>
+ </Macro>
+ <Macro Name="Emulate Keystrokes: {Enter}">
+ <Event Name="CEC.select" />
+ <Action>
+ Window.SendKeys(u'{Enter}', False)
+ </Action>
+ </Macro>
+ <Macro Name="Emulate Keystrokes: 1">
+ <Event Name="CEC.1" />
+ <Action>
+ Window.SendKeys(u'1', False)
+ </Action>
+ </Macro>
+ <Macro Name="Emulate Keystrokes: 2">
+ <Event Name="CEC.2" />
+ <Action>
+ Window.SendKeys(u'2', False)
+ </Action>
+ </Macro>
+ <Macro Name="Emulate Keystrokes: 3">
+ <Event Name="CEC.3" />
+ <Action>
+ Window.SendKeys(u'3', False)
+ </Action>
+ </Macro>
+ <Macro Name="Emulate Keystrokes: 4">
+ <Event Name="CEC.4" />
+ <Action>
+ Window.SendKeys(u'4', False)
+ </Action>
+ </Macro>
+ <Macro Name="Emulate Keystrokes: 5">
+ <Event Name="CEC.5" />
+ <Action>
+ Window.SendKeys(u'5', False)
+ </Action>
+ </Macro>
+ <Macro Name="Emulate Keystrokes: 6">
+ <Event Name="CEC.6" />
+ <Action>
+ Window.SendKeys(u'6', False)
+ </Action>
+ </Macro>
+ <Macro Name="Emulate Keystrokes: 7">
+ <Event Name="CEC.7" />
+ <Action>
+ Window.SendKeys(u'7', False)
+ </Action>
+ </Macro>
+ <Macro Name="Emulate Keystrokes: 8">
+ <Event Name="CEC.8" />
+ <Action>
+ Window.SendKeys(u'8', False)
+ </Action>
+ </Macro>
+ <Macro Name="Emulate Keystrokes: 9">
+ <Event Name="CEC.9" />
+ <Action>
+ Window.SendKeys(u'9', False)
+ </Action>
+ </Macro>
+ <Macro Name="Emulate Keystrokes: 0">
+ <Event Name="CEC.0" />
+ <Action>
+ Window.SendKeys(u'0', False)
+ </Action>
+ </Macro>
+ <Macro Name="Emulate Keystrokes: {F1}">
+ <Event Name="CEC.F1 (blue)" />
+ <Action>
+ Window.SendKeys(u'{F1}', False)
+ </Action>
+ </Macro>
+ <Macro Name="Emulate Keystrokes: {F2}">
+ <Event Name="CEC.F2 (red)" />
+ <Action>
+ Window.SendKeys(u'{F2}', False)
+ </Action>
+ </Macro>
+ <Macro Name="Emulate Keystrokes: {F3}">
+ <Event Name="CEC.F3 (green)" />
+ <Action>
+ Window.SendKeys(u'{F3}', False)
+ </Action>
+ </Macro>
+ <Macro Name="Emulate Keystrokes: {F4}">
+ <Event Name="CEC.F4 (yellow)" />
+ <Action>
+ Window.SendKeys(u'{F4}', False)
+ </Action>
+ </Macro>
+ </Folder>
+ </Folder>
+</EventGhost>
--- /dev/null
+using namespace System;
+using namespace System::Reflection;
+using namespace System::Runtime::CompilerServices;
+using namespace System::Runtime::InteropServices;
+using namespace System::Security::Permissions;
+
+[assembly:AssemblyTitleAttribute("LibCecSharp")];
+[assembly:AssemblyDescriptionAttribute("")];
+[assembly:AssemblyConfigurationAttribute("")];
+[assembly:AssemblyCompanyAttribute("Pulse-Eight Limited")];
+[assembly:AssemblyProductAttribute("LibCecSharp")];
+[assembly:AssemblyCopyrightAttribute("Copyright (c) Pulse-Eight Limited 2011-2015")];
+[assembly:AssemblyTrademarkAttribute("")];
+[assembly:AssemblyCultureAttribute("")];
+
+[assembly:AssemblyVersionAttribute("@LIBCEC_VERSION_MAJOR@.@LIBCEC_VERSION_MINOR@.@LIBCEC_VERSION_PATCH@.0")];
+
+[assembly:ComVisible(false)];
+[assembly:CLSCompliantAttribute(true)];
+[assembly:SecurityPermission(SecurityAction::RequestMinimum, UnmanagedCode = true)];
--- /dev/null
+#pragma once
+/*
+* This file is part of the libCEC(R) library.
+*
+* libCEC(R) is Copyright (C) 2011-2013 Pulse-Eight Limited. All rights reserved.
+* libCEC(R) is an original work, containing original code.
+*
+* libCEC(R) is a trademark of Pulse-Eight Limited.
+*
+* This program is dual-licensed; 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.
+*
+*
+* Alternatively, you can license this library under a commercial license,
+* please contact Pulse-Eight Licensing for more information.
+*
+* For more information contact:
+* Pulse-Eight Licensing <license@pulse-eight.com>
+* http://www.pulse-eight.com/
+* http://www.pulse-eight.net/
+*/
+
+#include <p8-platform/threads/mutex.h>
+#include <vcclr.h>
+#include <msclr/marshal.h>
+#include "../../include/cec.h"
+#include <vector>
+
+#using <System.dll>
+
+/// <summary>
+/// LibCecSharp namespace
+/// </summary>
+/// <see cref="LibCecSharp" />
+namespace CecSharp
+{
+ /// <summary>
+ /// The device type. For client applications, libCEC only supports RecordingDevice, PlaybackDevice or Tuner.
+ /// libCEC uses RecordingDevice by default.
+ /// </summary>
+ public enum class CecDeviceType
+ {
+ /// <summary>
+ /// Television
+ /// </summary>
+ Tv = 0,
+ /// <summary>
+ /// Recording device
+ /// </summary>
+ RecordingDevice = 1,
+ /// <summary>
+ /// Reserved / do not use
+ /// </summary>
+ Reserved = 2,
+ /// <summary>
+ /// Tuner
+ /// </summary>
+ Tuner = 3,
+ /// <summary>
+ /// Playback device
+ /// </summary>
+ PlaybackDevice = 4,
+ /// <summary>
+ /// Audio system / AVR
+ /// </summary>
+ AudioSystem = 5
+ };
+
+ /// <summary>
+ /// Log level that can be used by the logging callback method to filter messages from libCEC.
+ /// </summary>
+ public enum class CecLogLevel
+ {
+ /// <summary>
+ /// No logging
+ /// </summary>
+ None = 0,
+ /// <summary>
+ /// libCEC encountered a serious problem, and couldn't complete an action.
+ /// </summary>
+ Error = 1,
+ /// <summary>
+ /// libCEC warns that it encountered a problem, but recovered.
+ /// </summary>
+ Warning = 2,
+ /// <summary>
+ /// libCEC informs the client about a CEC state change.
+ /// </summary>
+ Notice = 4,
+ /// <summary>
+ /// Raw CEC data traffic
+ /// </summary>
+ Traffic = 8,
+ /// <summary>
+ /// Debugging messages
+ /// </summary>
+ Debug = 16,
+ /// <summary>
+ /// Display all messages
+ /// </summary>
+ All = 31
+ };
+
+ /// <summary>
+ /// A logical address on the CEC bus
+ /// </summary>
+ public enum class CecLogicalAddress
+ {
+ /// <summary>
+ /// Not a valid logical address
+ /// </summary>
+ Unknown = -1,
+ /// <summary>
+ /// Television
+ /// </summary>
+ Tv = 0,
+ /// <summary>
+ /// Recording device 1
+ /// </summary>
+ RecordingDevice1 = 1,
+ /// <summary>
+ /// Recording device 2
+ /// </summary>
+ RecordingDevice2 = 2,
+ /// <summary>
+ /// Tuner 1
+ /// </summary>
+ Tuner1 = 3,
+ /// <summary>
+ /// Playback device 1
+ /// </summary>
+ PlaybackDevice1 = 4,
+ /// <summary>
+ /// Audio system / AVR
+ /// </summary>
+ AudioSystem = 5,
+ /// <summary>
+ /// Tuner 2
+ /// </summary>
+ Tuner2 = 6,
+ /// <summary>
+ /// Tuner 3
+ /// </summary>
+ Tuner3 = 7,
+ /// <summary>
+ /// Playback device 2
+ /// </summary>
+ PlaybackDevice2 = 8,
+ /// <summary>
+ /// Recording device 3
+ /// </summary>
+ RecordingDevice3 = 9,
+ /// <summary>
+ /// Tuner 4
+ /// </summary>
+ Tuner4 = 10,
+ /// <summary>
+ /// Playback device 3
+ /// </summary>
+ PlaybackDevice3 = 11,
+ /// <summary>
+ /// Reserved address 1
+ /// </summary>
+ Reserved1 = 12,
+ /// <summary>
+ /// Reserved address 2
+ /// </summary>
+ Reserved2 = 13,
+ /// <summary>
+ /// Free to use
+ /// </summary>
+ FreeUse = 14,
+ /// <summary>
+ /// Unregistered / new device
+ /// </summary>
+ Unregistered = 15,
+ /// <summary>
+ /// Broadcast address
+ /// </summary>
+ Broadcast = 15
+ };
+
+ /// <summary>
+ /// The type of alert when libCEC calls the CecAlert callback
+ /// </summary>
+ public enum class CecAlert
+ {
+ /// <summary>
+ /// The device needs servicing. This is set when the firmware can be upgraded, or when a problem with the firmware is detected.
+ /// The latest firmware flash tool can be downloaded from http://packages.pulse-eight.net/
+ /// </summary>
+ ServiceDevice = 0,
+ /// <summary>
+ /// The connection to the adapter was lost, probably because the device got unplugged.
+ /// </summary>
+ ConnectionLost,
+ /// <summary>
+ /// No permission from the OS to access the adapter.
+ /// </summary>
+ PermissionError,
+ /// <summary>
+ /// The device is being used by another program.
+ /// </summary>
+ PortBusy,
+ /// <summary>
+ /// The physical address that is assigned to the adapter is already being used.
+ /// </summary>
+ PhysicalAddressError,
+ /// <summary>
+ /// The TV does not respond to polls.
+ /// </summary>
+ TVPollFailed
+ };
+
+ /// <summary>
+ /// The type of parameter that is sent with the CecAlert callback
+ /// </summary>
+ public enum class CecParameterType
+ {
+ /// <summary>
+ /// The parameter is a string
+ /// </summary>
+ ParameterTypeString = 1
+ };
+
+ /// <summary>
+ /// A parameter for the CecAlert callback
+ /// </summary>
+ public ref class CecParameter
+ {
+ public:
+ /// <summary>
+ /// Create a new parameter
+ /// </summary>
+ /// <param name="type">The type of this parameter.</param>
+ /// <param name="data">The value of this parameter.</param>
+ CecParameter(CecParameterType type, System::String ^ data)
+ {
+ Type = type;
+ Data = data;
+ }
+
+ /// <summary>
+ /// The type of this parameter
+ /// </summary>
+ property CecParameterType Type;
+ /// <summary>
+ /// The value of this parameter
+ /// </summary>
+ property System::String ^ Data;
+ };
+
+ /// <summary>
+ /// The power status of a CEC device
+ /// </summary>
+ public enum class CecPowerStatus
+ {
+ /// <summary>
+ /// Powered on
+ /// </summary>
+ On = 0x00,
+ /// <summary>
+ /// In standby mode
+ /// </summary>
+ Standby = 0x01,
+ /// <summary>
+ /// In transition from standby to on
+ /// </summary>
+ InTransitionStandbyToOn = 0x02,
+ /// <summary>
+ /// In transition from on to standby
+ /// </summary>
+ InTransitionOnToStandby = 0x03,
+ /// <summary>
+ /// Unknown status
+ /// </summary>
+ Unknown = 0x99
+ };
+
+ /// <summary>
+ /// The CEC version of a CEC device
+ /// </summary>
+ public enum class CecVersion
+ {
+ /// <summary>
+ /// Unknown version
+ /// </summary>
+ Unknown = 0x00,
+ /// <summary>
+ /// Version 1.2
+ /// </summary>
+ V1_2 = 0x01,
+ /// <summary>
+ /// Version 1.2a
+ /// </summary>
+ V1_2A = 0x02,
+ /// <summary>
+ /// Version 1.3
+ /// </summary>
+ V1_3 = 0x03,
+ /// <summary>
+ /// Version 1.3a
+ /// </summary>
+ V1_3A = 0x04,
+ /// <summary>
+ /// Version 1.4
+ /// </summary>
+ V1_4 = 0x05
+ };
+
+ /// <summary>
+ /// Parameter for OSD string display, that controls how to display the string
+ /// </summary>
+ public enum class CecDisplayControl
+ {
+ /// <summary>
+ /// Display for the default time
+ /// </summary>
+ DisplayForDefaultTime = 0x00,
+ /// <summary>
+ /// Display until it is cleared by ClearPreviousMessage
+ /// </summary>
+ DisplayUntilCleared = 0x40,
+ /// <summary>
+ /// Clear message displayed by DisplayUntilCleared
+ /// </summary>
+ ClearPreviousMessage = 0x80,
+ /// <summary>
+ /// Reserved / do not use
+ /// </summary>
+ ReservedForFutureUse = 0xC0
+ };
+
+ /// <summary>
+ /// The menu state of a CEC device
+ /// </summary>
+ public enum class CecMenuState
+ {
+ /// <summary>
+ /// Menu active
+ /// </summary>
+ Activated = 0,
+ /// <summary>
+ /// Menu not active
+ /// </summary>
+ Deactivated = 1
+ };
+
+ /// <summary>
+ /// Deck control mode for playback and recording devices
+ /// </summary>
+ public enum class CecDeckControlMode
+ {
+ /// <summary>
+ /// Skip forward / wind
+ /// </summary>
+ SkipForwardWind = 1,
+ /// <summary>
+ /// Skip reverse / rewind
+ /// </summary>
+ SkipReverseRewind = 2,
+ /// <summary>
+ /// Stop
+ /// </summary>
+ Stop = 3,
+ /// <summary>
+ /// Eject
+ /// </summary>
+ Eject = 4
+ };
+
+ /// <summary>
+ /// Deck status for playback and recording devices
+ /// </summary>
+ public enum class CecDeckInfo
+ {
+ /// <summary>
+ /// Playing
+ /// </summary>
+ Play = 0x11,
+ /// <summary>
+ /// Recording
+ /// </summary>
+ Record = 0x12,
+ /// <summary>
+ /// Reverse
+ /// </summary>
+ Reverse = 0x13,
+ /// <summary>
+ /// Showing still frame
+ /// </summary>
+ Still = 0x14,
+ /// <summary>
+ /// Playing slow
+ /// </summary>
+ Slow = 0x15,
+ /// <summary>
+ /// Playing slow reverse
+ /// </summary>
+ SlowReverse = 0x16,
+ /// <summary>
+ /// Fast forward
+ /// </summary>
+ FastForward = 0x17,
+ /// <summary>
+ /// Fast reverse
+ /// </summary>
+ FastReverse = 0x18,
+ /// <summary>
+ /// No media detected
+ /// </summary>
+ NoMedia = 0x19,
+ /// <summary>
+ /// Stop / not playing
+ /// </summary>
+ Stop = 0x1A,
+ /// <summary>
+ /// Skip forward / wind
+ /// </summary>
+ SkipForwardWind = 0x1B,
+ /// <summary>
+ /// Skip reverse / rewind
+ /// </summary>
+ SkipReverseRewind = 0x1C,
+ /// <summary>
+ /// Index search forward
+ /// </summary>
+ IndexSearchForward = 0x1D,
+ /// <summary>
+ /// Index search reverse
+ /// </summary>
+ IndexSearchReverse = 0x1E,
+ /// <summary>
+ /// Other / unknown status
+ /// </summary>
+ OtherStatus = 0x1F
+ };
+
+ /// <summary>
+ /// User control code, the key code when the user presses or releases a button on the remote.
+ /// Used by SendKeypress() and the CecKey callback.
+ /// </summary>
+ public enum class CecUserControlCode
+ {
+ /// <summary>
+ /// Select / OK
+ /// </summary>
+ Select = 0x00,
+ /// <summary>
+ /// Direction up
+ /// </summary>
+ Up = 0x01,
+ /// <summary>
+ /// Direction down
+ /// </summary>
+ Down = 0x02,
+ /// <summary>
+ /// Direction left
+ /// </summary>
+ Left = 0x03,
+ /// <summary>
+ /// Direction right
+ /// </summary>
+ Right = 0x04,
+ /// <summary>
+ /// Direction right + up
+ /// </summary>
+ RightUp = 0x05,
+ /// <summary>
+ /// Direction right + down
+ /// </summary>
+ RightDown = 0x06,
+ /// <summary>
+ /// Direction left + up
+ /// </summary>
+ LeftUp = 0x07,
+ /// <summary>
+ /// Direction left + down
+ /// </summary>
+ LeftDown = 0x08,
+ /// <summary>
+ /// Root menu
+ /// </summary>
+ RootMenu = 0x09,
+ /// <summary>
+ /// Setup menu
+ /// </summary>
+ SetupMenu = 0x0A,
+ /// <summary>
+ /// Contents menu
+ /// </summary>
+ ContentsMenu = 0x0B,
+ /// <summary>
+ /// Favourite menu
+ /// </summary>
+ FavoriteMenu = 0x0C,
+ /// <summary>
+ /// Exit / back
+ /// </summary>
+ Exit = 0x0D,
+ /// <summary>
+ /// Number 0
+ /// </summary>
+ Number0 = 0x20,
+ /// <summary>
+ /// Number 1
+ /// </summary>
+ Number1 = 0x21,
+ /// <summary>
+ /// Number 2
+ /// </summary>
+ Number2 = 0x22,
+ /// <summary>
+ /// Number 3
+ /// </summary>
+ Number3 = 0x23,
+ /// <summary>
+ /// Number 4
+ /// </summary>
+ Number4 = 0x24,
+ /// <summary>
+ /// Number 5
+ /// </summary>
+ Number5 = 0x25,
+ /// <summary>
+ /// Number 6
+ /// </summary>
+ Number6 = 0x26,
+ /// <summary>
+ /// Number 7
+ /// </summary>
+ Number7 = 0x27,
+ /// <summary>
+ /// Number 8
+ /// </summary>
+ Number8 = 0x28,
+ /// <summary>
+ /// Number 9
+ /// </summary>
+ Number9 = 0x29,
+ /// <summary>
+ /// .
+ /// </summary>
+ Dot = 0x2A,
+ /// <summary>
+ /// Enter input
+ /// </summary>
+ Enter = 0x2B,
+ /// <summary>
+ /// Clear input
+ /// </summary>
+ Clear = 0x2C,
+ /// <summary>
+ /// Next favourite
+ /// </summary>
+ NextFavorite = 0x2F,
+ /// <summary>
+ /// Channel up
+ /// </summary>
+ ChannelUp = 0x30,
+ /// <summary>
+ /// Channel down
+ /// </summary>
+ ChannelDown = 0x31,
+ /// <summary>
+ /// Previous channel
+ /// </summary>
+ PreviousChannel = 0x32,
+ /// <summary>
+ /// Select sound track
+ /// </summary>
+ SoundSelect = 0x33,
+ /// <summary>
+ /// Select input
+ /// </summary>
+ InputSelect = 0x34,
+ /// <summary>
+ /// Display information
+ /// </summary>
+ DisplayInformation = 0x35,
+ /// <summary>
+ /// Show help
+ /// </summary>
+ Help = 0x36,
+ /// <summary>
+ /// Page up
+ /// </summary>
+ PageUp = 0x37,
+ /// <summary>
+ /// Page down
+ /// </summary>
+ PageDown = 0x38,
+ /// <summary>
+ /// Toggle powered on / standby
+ /// </summary>
+ Power = 0x40,
+ /// <summary>
+ /// Volume up
+ /// </summary>
+ VolumeUp = 0x41,
+ /// <summary>
+ /// Volume down
+ /// </summary>
+ VolumeDown = 0x42,
+ /// <summary>
+ /// Mute audio
+ /// </summary>
+ Mute = 0x43,
+ /// <summary>
+ /// Start playback
+ /// </summary>
+ Play = 0x44,
+ /// <summary>
+ /// Stop playback
+ /// </summary>
+ Stop = 0x45,
+ /// <summary>
+ /// Pause playback
+ /// </summary>
+ Pause = 0x46,
+ /// <summary>
+ /// Toggle recording
+ /// </summary>
+ Record = 0x47,
+ /// <summary>
+ /// Rewind
+ /// </summary>
+ Rewind = 0x48,
+ /// <summary>
+ /// Fast forward
+ /// </summary>
+ FastForward = 0x49,
+ /// <summary>
+ /// Eject media
+ /// </summary>
+ Eject = 0x4A,
+ /// <summary>
+ /// Forward
+ /// </summary>
+ Forward = 0x4B,
+ /// <summary>
+ /// Backward
+ /// </summary>
+ Backward = 0x4C,
+ /// <summary>
+ /// Stop recording
+ /// </summary>
+ StopRecord = 0x4D,
+ /// <summary>
+ /// Pause recording
+ /// </summary>
+ PauseRecord = 0x4E,
+ /// <summary>
+ /// Change angle
+ /// </summary>
+ Angle = 0x50,
+ /// <summary>
+ /// Toggle sub picture
+ /// </summary>
+ SubPicture = 0x51,
+ /// <summary>
+ /// Toggle video on demand
+ /// </summary>
+ VideoOnDemand = 0x52,
+ /// <summary>
+ /// Toggle electronic program guide (EPG)
+ /// </summary>
+ ElectronicProgramGuide = 0x53,
+ /// <summary>
+ /// Toggle timer programming
+ /// </summary>
+ TimerProgramming = 0x54,
+ /// <summary>
+ /// Set initial configuration
+ /// </summary>
+ InitialConfiguration = 0x55,
+ /// <summary>
+ /// Start playback function
+ /// </summary>
+ PlayFunction = 0x60,
+ /// <summary>
+ /// Pause playback function
+ /// </summary>
+ PausePlayFunction = 0x61,
+ /// <summary>
+ /// Toggle recording function
+ /// </summary>
+ RecordFunction = 0x62,
+ /// <summary>
+ /// Pause recording function
+ /// </summary>
+ PauseRecordFunction = 0x63,
+ /// <summary>
+ /// Stop playback function
+ /// </summary>
+ StopFunction = 0x64,
+ /// <summary>
+ /// Mute audio function
+ /// </summary>
+ MuteFunction = 0x65,
+ /// <summary>
+ /// Restore volume function
+ /// </summary>
+ RestoreVolumeFunction = 0x66,
+ /// <summary>
+ /// Tune function
+ /// </summary>
+ TuneFunction = 0x67,
+ /// <summary>
+ /// Select media function
+ /// </summary>
+ SelectMediaFunction = 0x68,
+ /// <summary>
+ /// Select AV input function
+ /// </summary>
+ SelectAVInputFunction = 0x69,
+ /// <summary>
+ /// Select audio input function
+ /// </summary>
+ SelectAudioInputFunction = 0x6A,
+ /// <summary>
+ /// Toggle powered on / standby function
+ /// </summary>
+ PowerToggleFunction = 0x6B,
+ /// <summary>
+ /// Power off function
+ /// </summary>
+ PowerOffFunction = 0x6C,
+ /// <summary>
+ /// Power on function
+ /// </summary>
+ PowerOnFunction = 0x6D,
+ /// <summary>
+ /// F1 / blue button
+ /// </summary>
+ F1Blue = 0x71,
+ /// <summary>
+ /// F2 / red button
+ /// </summary>
+ F2Red = 0X72,
+ /// <summary>
+ /// F3 / green button
+ /// </summary>
+ F3Green = 0x73,
+ /// <summary>
+ /// F4 / yellow button
+ /// </summary>
+ F4Yellow = 0x74,
+ /// <summary>
+ /// F5
+ /// </summary>
+ F5 = 0x75,
+ /// <summary>
+ /// Data / teletext
+ /// </summary>
+ Data = 0x76,
+ /// <summary>
+ /// Max. valid key code for standard buttons
+ /// </summary>
+ Max = 0x76,
+ /// <summary>
+ /// Extra return button on Samsung remotes
+ /// </summary>
+ SamsungReturn = 0x91,
+ /// <summary>
+ /// Unknown / invalid key code
+ /// </summary>
+ Unknown
+ };
+
+ /// <summary>
+ /// Vendor IDs for CEC devices
+ /// </summary>
+ public enum class CecVendorId
+ {
+ Toshiba = 0x000039,
+ Samsung = 0x0000F0,
+ Denon = 0x0005CD,
+ Marantz = 0x000678,
+ Loewe = 0x000982,
+ Onkyo = 0x0009B0,
+ Medion = 0x000CB8,
+ Toshiba2 = 0x000CE7,
+ PulseEight = 0x001582,
+ HarmanKardon2 = 0x001950,
+ Google = 0x001A11,
+ Akai = 0x0020C7,
+ AOC = 0x002467,
+ Panasonic = 0x008045,
+ Philips = 0x00903E,
+ Daewoo = 0x009053,
+ Yamaha = 0x00A0DE,
+ Grundig = 0x00D0D5,
+ Pioneer = 0x00E036,
+ LG = 0x00E091,
+ Sharp = 0x08001F,
+ Sony = 0x080046,
+ Broadcom = 0x18C086,
+ Sharp2 = 0x534850,
+ Vizio = 0x6B746D,
+ Benq = 0x8065E9,
+ HarmanKardon = 0x9C645E,
+ Unknown = 0
+ };
+
+ /// <summary>
+ /// Audio status of audio system / AVR devices
+ /// </summary>
+ public enum class CecAudioStatus
+ {
+ /// <summary>
+ /// Muted
+ /// </summary>
+ MuteStatusMask = 0x80,
+ /// <summary>
+ /// Not muted, volume status mask
+ /// </summary>
+ VolumeStatusMask = 0x7F,
+ /// <summary>
+ /// Minimum volume
+ /// </summary>
+ VolumeMin = 0x00,
+ /// <summary>
+ /// Maximum volume
+ /// </summary>
+ VolumeMax = 0x64,
+ /// <summary>
+ /// Unknown status
+ /// </summary>
+ VolumeStatusUnknown = 0x7F
+ };
+
+ /// <summary>
+ /// CEC opcodes, as described in the HDMI CEC specification
+ /// </summary>
+ public enum class CecOpcode
+ {
+ /// <summary>
+ /// Active source
+ /// </summary>
+ ActiveSource = 0x82,
+ /// <summary>
+ /// Image view on: power on display for image display
+ /// </summary>
+ ImageViewOn = 0x04,
+ /// <summary>
+ /// Text view on: power on display for text display
+ /// </summary>
+ TextViewOn = 0x0D,
+ /// <summary>
+ /// Device no longer is the active source
+ /// </summary>
+ InactiveSource = 0x9D,
+ /// <summary>
+ /// Request which device has the active source status
+ /// </summary>
+ RequestActiveSource = 0x85,
+ /// <summary>
+ /// Routing change for HDMI switches
+ /// </summary>
+ RoutingChange = 0x80,
+ /// <summary>
+ /// Routing information for HDMI switches
+ /// </summary>
+ RoutingInformation = 0x81,
+ /// <summary>
+ /// Change the stream path to the given physical address
+ /// </summary>
+ SetStreamPath = 0x86,
+ /// <summary>
+ /// Inform that a device went into standby mode
+ /// </summary>
+ Standby = 0x36,
+ /// <summary>
+ /// Stop recording
+ /// </summary>
+ RecordOff = 0x0B,
+ /// <summary>
+ /// Start recording
+ /// </summary>
+ RecordOn = 0x09,
+ /// <summary>
+ /// Recording status information
+ /// </summary>
+ RecordStatus = 0x0A,
+ /// <summary>
+ /// Record current display
+ /// </summary>
+ RecordTvScreen = 0x0F,
+ /// <summary>
+ /// Clear analogue timer
+ /// </summary>
+ ClearAnalogueTimer = 0x33,
+ /// <summary>
+ /// Clear digital timer
+ /// </summary>
+ ClearDigitalTimer = 0x99,
+ /// <summary>
+ /// Clear external timer
+ /// </summary>
+ ClearExternalTimer = 0xA1,
+ /// <summary>
+ /// Set analogue timer
+ /// </summary>
+ SetAnalogueTimer = 0x34,
+ /// <summary>
+ /// Set digital timer
+ /// </summary>
+ SetDigitalTimer = 0x97,
+ /// <summary>
+ /// Set external timer
+ /// </summary>
+ SetExternalTimer = 0xA2,
+ /// <summary>
+ /// Set program title of a timer
+ /// </summary>
+ SetTimerProgramTitle = 0x67,
+ /// <summary>
+ /// Timer status cleared
+ /// </summary>
+ TimerClearedStatus = 0x43,
+ /// <summary>
+ /// Timer status information
+ /// </summary>
+ TimerStatus = 0x35,
+ /// <summary>
+ /// CEC version used by a device
+ /// </summary>
+ CecVersion = 0x9E,
+ /// <summary>
+ /// Request CEC version of a device
+ /// </summary>
+ GetCecVersion = 0x9F,
+ /// <summary>
+ /// Request physical address of a device
+ /// </summary>
+ GivePhysicalAddress = 0x83,
+ /// <summary>
+ /// Request language code of the menu language of a device
+ /// 3 character ISO 639-2 country code. see http://http://www.loc.gov/standards/iso639-2/
+ /// </summary>
+ GetMenuLanguage = 0x91,
+ /// <summary>
+ /// Report the physical address
+ /// </summary>
+ ReportPhysicalAddress = 0x84,
+ /// <summary>
+ /// Report the language code of the menu language
+ /// 3 character ISO 639-2 country code. see http://http://www.loc.gov/standards/iso639-2/
+ /// </summary>
+ SetMenuLanguage = 0x32,
+ /// <summary>
+ /// Deck control for playback and recording devices
+ /// </summary>
+ DeckControl = 0x42,
+ /// <summary>
+ /// Deck status for playback and recording devices
+ /// </summary>
+ DeckStatus = 0x1B,
+ /// <summary>
+ /// Request deck status from playback and recording devices
+ /// </summary>
+ GiveDeckStatus = 0x1A,
+ /// <summary>
+ /// Start playback on playback and recording devices
+ /// </summary>
+ Play = 0x41,
+ /// <summary>
+ /// Request tuner status
+ /// </summary>
+ GiveTunerDeviceStatus = 0x08,
+ /// <summary>
+ /// Select analogue service on a tuner
+ /// </summary>
+ SelectAnalogueService = 0x92,
+ /// <summary>
+ /// Select digital service on a tuner
+ /// </summary>
+ SelectDigtalService = 0x93,
+ /// <summary>
+ /// Report tuner device status
+ /// </summary>
+ TunerDeviceStatus = 0x07,
+ /// <summary>
+ /// Tuner step decrement
+ /// </summary>
+ TunerStepDecrement = 0x06,
+ /// <summary>
+ /// Tuner step increment
+ /// </summary>
+ TunerStepIncrement = 0x05,
+ /// <summary>
+ /// Report device vendor ID
+ /// </summary>
+ DeviceVendorId = 0x87,
+ /// <summary>
+ /// Request device vendor ID
+ /// </summary>
+ GiveDeviceVendorId = 0x8C,
+ /// <summary>
+ /// Vendor specific command
+ /// </summary>
+ VendorCommand = 0x89,
+ /// <summary>
+ /// Vendor specific command with vendor ID
+ /// </summary>
+ VendorCommandWithId = 0xA0,
+ /// <summary>
+ /// Vendor specific remote button pressed
+ /// </summary>
+ VendorRemoteButtonDown = 0x8A,
+ /// <summary>
+ /// Vendor specific remote button released
+ /// </summary>
+ VendorRemoteButtonUp = 0x8B,
+ /// <summary>
+ /// Display / clear OSD string
+ /// </summary>
+ SetOsdString = 0x64,
+ /// <summary>
+ /// Request device OSD name
+ /// </summary>
+ GiveOsdName = 0x46,
+ /// <summary>
+ /// Report device OSD name
+ /// </summary>
+ SetOsdName = 0x47,
+ /// <summary>
+ /// Request device menu status
+ /// </summary>
+ MenuRequest = 0x8D,
+ /// <summary>
+ /// Report device menu status
+ /// </summary>
+ MenuStatus = 0x8E,
+ /// <summary>
+ /// Remote button pressed
+ /// </summary>
+ UserControlPressed = 0x44,
+ /// <summary>
+ /// Remote button released
+ /// </summary>
+ UserControlRelease = 0x45,
+ /// <summary>
+ /// Request device power status
+ /// </summary>
+ GiveDevicePowerStatus = 0x8F,
+ /// <summary>
+ /// Report device power status
+ /// </summary>
+ ReportPowerStatus = 0x90,
+ /// <summary>
+ /// Feature abort / unsupported command
+ /// </summary>
+ FeatureAbort = 0x00,
+ /// <summary>
+ /// Abort command
+ /// </summary>
+ Abort = 0xFF,
+ /// <summary>
+ /// Give audio status
+ /// </summary>
+ GiveAudioStatus = 0x71,
+ /// <summary>
+ /// Give audiosystem mode
+ /// </summary>
+ GiveSystemAudioMode = 0x7D,
+ /// <summary>
+ /// Report device audio status
+ /// </summary>
+ ReportAudioStatus = 0x7A,
+ /// <summary>
+ /// Set audiosystem mode
+ /// </summary>
+ SetSystemAudioMode = 0x72,
+ /// <summary>
+ /// Request audiosystem mode
+ /// </summary>
+ SystemAudioModeRequest = 0x70,
+ /// <summary>
+ /// Report audiosystem mode
+ /// </summary>
+ SystemAudioModeStatus = 0x7E,
+ /// <summary>
+ /// Set audio bitrate
+ /// </summary>
+ SetAudioRate = 0x9A,
+ /// <summary>
+ /// When this opcode is set, no opcode will be sent to the device / poll message
+ /// This is one of the reserved numbers
+ /// </summary>
+ None = 0xFD
+ };
+
+ /// <summary>
+ /// Audiosystem status
+ /// </summary>
+ public enum class CecSystemAudioStatus
+ {
+ /// <summary>
+ /// Turned off
+ /// </summary>
+ Off = 0,
+ /// <summary>
+ /// Turned on
+ /// </summary>
+ On = 1
+ };
+
+ /// <summary>
+ /// Type of adapter to which libCEC is connected
+ /// </summary>
+ public enum class CecAdapterType
+ {
+ /// <summary>
+ /// Unknown adapter type
+ /// </summary>
+ Unknown = 0,
+ /// <summary>
+ /// Pulse-Eight USB-CEC adapter
+ /// </summary>
+ PulseEightExternal = 0x1,
+ /// <summary>
+ /// Pulse-Eight CEC daughterboard
+ /// </summary>
+ PulseEightDaughterboard = 0x2,
+ /// <summary>
+ /// Raspberry Pi
+ /// </summary>
+ RaspberryPi = 0x100,
+ /// <summary>
+ /// TDA995x
+ /// </summary>
+ TDA995x = 0x200
+ };
+
+ /// <summary>
+ /// Descriptor of a CEC adapter, returned when scanning for adapters that are connected to the system
+ /// </summary>
+ public ref class CecAdapter
+ {
+ public:
+ /// <summary>
+ /// Create a new CEC adapter descriptor
+ /// </summary>
+ /// <param name="path"> The path descriptor for this CEC adapter</param>
+ /// <param name="comPort">The COM port of this CEC adapter</param>
+ CecAdapter(System::String ^ path, System::String ^ comPort,
+ uint16_t vendorID, uint16_t productID, uint16_t firmwareVersion,
+ uint32_t firmwareBuildDate, uint16_t physicalAddress)
+ {
+ Path = path;
+ ComPort = comPort;
+ VendorID = vendorID;
+ ProductID = productID;
+ FirmwareVersion = firmwareVersion;
+ System::DateTime ^ dt = gcnew System::DateTime(1970, 1, 1, 0, 0, 0, 0, System::DateTimeKind::Utc);
+ FirmwareBuildDate = dt->AddSeconds(firmwareBuildDate);
+ PhysicalAddress = physicalAddress;
+ }
+
+ /// <summary>
+ /// The path descriptor for this CEC adapter
+ /// </summary>
+ property System::String ^ Path;
+
+ /// <summary>
+ /// The COM port of this CEC adapter
+ /// </summary>
+ property System::String ^ ComPort;
+
+ /// <summary>
+ /// USB vendor ID
+ /// </summary>
+ property uint16_t VendorID;
+
+ /// <summary>
+ /// USB product ID
+ /// </summary>
+ property uint16_t ProductID;
+
+ /// <summary>
+ /// Adapter firmware version
+ /// </summary>
+ property uint16_t FirmwareVersion;
+
+ /// <summary>
+ /// Adapter firmware build date
+ /// </summary>
+ property System::DateTime ^ FirmwareBuildDate;
+
+ /// <summary>
+ /// Adapter physical address
+ /// </summary>
+ property uint16_t PhysicalAddress;
+ };
+
+ /// <summary>
+ /// A list of CEC device types
+ /// </summary>
+ public ref class CecDeviceTypeList
+ {
+ public:
+ /// <summary>
+ /// Create a new empty list of CEC device types
+ /// </summary>
+ CecDeviceTypeList(void)
+ {
+ Types = gcnew array<CecDeviceType>(5);
+ for (unsigned int iPtr = 0; iPtr < 5; iPtr++)
+ Types[iPtr] = CecDeviceType::Reserved;
+ }
+
+ /// <summary>
+ /// The array with CecDeviceType instances in this list.
+ /// </summary>
+ property array<CecDeviceType> ^ Types;
+ };
+
+ /// <summary>
+ /// A list of logical addresses
+ /// </summary>
+ public ref class CecLogicalAddresses
+ {
+ public:
+ /// <summary>
+ /// Create a new empty list of logical addresses
+ /// </summary>
+ CecLogicalAddresses(void)
+ {
+ Addresses = gcnew array<CecLogicalAddress>(16);
+ Clear();
+ }
+
+ /// <summary>
+ /// Clears this list
+ /// </summary>
+ void Clear(void)
+ {
+ Primary = CecLogicalAddress::Unknown;
+ for (unsigned int iPtr = 0; iPtr < 16; iPtr++)
+ Addresses[iPtr] = CecLogicalAddress::Unknown;
+ }
+
+ /// <summary>
+ /// Checks whether a logical address is set in this list.
+ /// </summary>
+ /// <param name="address">The address to check.</param>
+ /// <returns>True when set, false otherwise</returns>
+ bool IsSet(CecLogicalAddress address)
+ {
+ return Addresses[(unsigned int)address] != CecLogicalAddress::Unknown;
+ }
+
+ /// <summary>
+ /// Add a logical address to this list (if it's not set already)
+ /// </summary>
+ /// <param name="address">The address to add.</param>
+ void Set(CecLogicalAddress address)
+ {
+ Addresses[(unsigned int)address] = address;
+ if (Primary == CecLogicalAddress::Unknown)
+ Primary = address;
+ }
+
+ /// <summary>
+ /// The primary (first) address in this list
+ /// </summary>
+ property CecLogicalAddress Primary;
+
+ /// <summary>
+ /// The list of addresses
+ /// </summary>
+ property array<CecLogicalAddress> ^ Addresses;
+ };
+
+
+ /// <summary>
+ /// Byte array used for CEC command parameters
+ /// </summary>
+ public ref class CecDatapacket
+ {
+ public:
+ /// <summary>
+ /// Create a new byte array with maximum size 100
+ /// </summary>
+ CecDatapacket(void)
+ {
+ Data = gcnew array<uint8_t>(100);
+ Size = 0;
+ }
+
+ /// <summary>
+ /// Adds a byte to this byte array
+ /// </summary>
+ /// <param name="data">The byte to add.</param>
+ void PushBack(uint8_t data)
+ {
+ if (Size < 100)
+ {
+ Data[Size] = data;
+ Size++;
+ }
+ }
+
+ /// <summary>
+ /// Array data
+ /// </summary>
+ property array<uint8_t> ^ Data;
+
+ /// <summary>
+ /// Current data size
+ /// </summary>
+ property uint8_t Size;
+ };
+
+ /// <summary>
+ /// A CEC command that is received or transmitted over the CEC bus
+ /// </summary>
+ public ref class CecCommand
+ {
+ public:
+ /// <summary>
+ /// Create a new CEC command instance
+ /// </summary>
+ /// <param name="initiator">The initiator of the command</param>
+ /// <param name="destination">The receiver of the command</param>
+ /// <param name="ack">True when the ack bit is set, false otherwise</param>
+ /// <param name="eom">True when the eom bit is set, false otherwise</param>
+ /// <param name="opcode">The CEC opcode of this command</param>
+ /// <param name="transmitTimeout">The timeout to use when transmitting a command</param>
+ CecCommand(CecLogicalAddress initiator, CecLogicalAddress destination, bool ack, bool eom, CecOpcode opcode, int32_t transmitTimeout)
+ {
+ Initiator = initiator;
+ Destination = destination;
+ Ack = ack;
+ Eom = eom;
+ Opcode = opcode;
+ OpcodeSet = true;
+ TransmitTimeout = transmitTimeout;
+ Parameters = gcnew CecDatapacket;
+ Empty = false;
+ }
+
+ /// <summary>
+ /// Create a new empty CEC command instance
+ /// </summary>
+ CecCommand(void)
+ {
+ Initiator = CecLogicalAddress::Unknown;
+ Destination = CecLogicalAddress::Unknown;
+ Ack = false;
+ Eom = false;
+ Opcode = CecOpcode::None;
+ OpcodeSet = false;
+ TransmitTimeout = 0;
+ Parameters = gcnew CecDatapacket;
+ Empty = true;
+ }
+
+ /// <summary>
+ /// Pushes a byte of data to this CEC command
+ /// </summary>
+ /// <param name="data">The byte to add</param>
+ void PushBack(uint8_t data)
+ {
+ if (Initiator == CecLogicalAddress::Unknown && Destination == CecLogicalAddress::Unknown)
+ {
+ Initiator = (CecLogicalAddress) (data >> 4);
+ Destination = (CecLogicalAddress) (data & 0xF);
+ }
+ else if (!OpcodeSet)
+ {
+ OpcodeSet = true;
+ Opcode = (CecOpcode)data;
+ }
+ else
+ {
+ Parameters->PushBack(data);
+ }
+ }
+
+ /// <summary>
+ /// True when this command is empty, false otherwise.
+ /// </summary>
+ property bool Empty;
+ /// <summary>
+ /// The initiator of the command
+ /// </summary>
+ property CecLogicalAddress Initiator;
+ /// <summary>
+ /// The destination of the command
+ /// </summary>
+ property CecLogicalAddress Destination;
+ /// <summary>
+ /// True when the ack bit is set, false otherwise
+ /// </summary>
+ property bool Ack;
+ /// <summary>
+ /// True when the eom bit is set, false otherwise
+ /// </summary>
+ property bool Eom;
+ /// <summary>
+ /// The CEC opcode of the command
+ /// </summary>
+ property CecOpcode Opcode;
+ /// <summary>
+ /// The parameters of this command
+ /// </summary>
+ property CecDatapacket ^ Parameters;
+ /// <summary>
+ /// True when an opcode is set, false otherwise (poll message)
+ /// </summary>
+ property bool OpcodeSet;
+ /// <summary>
+ /// The timeout to use when transmitting a command
+ /// </summary>
+ property int32_t TransmitTimeout;
+ };
+
+ /// <summary>
+ /// A key press that was received
+ /// </summary>
+ public ref class CecKeypress
+ {
+ public:
+ /// <summary>
+ /// Create a new key press instance
+ /// </summary>
+ /// <param name="keycode">The key code of this key press</param>
+ /// <param name="duration">The duration of this key press in milliseconds</param>
+ CecKeypress(CecUserControlCode keycode, unsigned int duration)
+ {
+ Keycode = keycode;
+ Duration = duration;
+ Empty = false;
+ }
+
+ /// <summary>
+ /// Create a new empty key press instance
+ /// </summary>
+ CecKeypress(void)
+ {
+ Keycode = CecUserControlCode::Unknown;
+ Duration = 0;
+ Empty = true;
+ }
+
+ /// <summary>
+ /// True when empty, false otherwise
+ /// </summary>
+ property bool Empty;
+ /// <summary>
+ /// The key code of this key press
+ /// </summary>
+ property CecUserControlCode Keycode;
+ /// <summary>
+ /// The duration of this key press in milliseconds
+ /// </summary>
+ property unsigned int Duration;
+ };
+
+ /// <summary>
+ /// A log message that libCEC generated
+ /// </summary>
+ public ref class CecLogMessage
+ {
+ public:
+ /// <summary>
+ /// Create a new log message
+ /// </summary>
+ /// <param name="message">The actual message</param>
+ /// <param name="level">The log level, so the application can choose what type information to display</param>
+ /// <param name="time">The timestamp of this message, in milliseconds after connecting</param>
+ CecLogMessage(System::String ^ message, CecLogLevel level, int64_t time)
+ {
+ Message = message;
+ Level = level;
+ Time = time;
+ Empty = false;
+ }
+
+ /// <summary>
+ /// Create a new empty log message
+ /// </summary>
+ CecLogMessage(void)
+ {
+ Message = "";
+ Level = CecLogLevel::None;
+ Time = 0;
+ Empty = true;
+ }
+
+ /// <summary>
+ /// True when empty, false otherwise.
+ /// </summary>
+ property bool Empty;
+ /// <summary>
+ /// The actual message
+ /// </summary>
+ property System::String ^Message;
+ /// <summary>
+ /// The log level, so the application can choose what type information to display
+ /// </summary>
+ property CecLogLevel Level;
+ /// <summary>
+ /// The timestamp of this message, in milliseconds after connecting
+ /// </summary>
+ property int64_t Time;
+ };
+
+ ref class CecCallbackMethods; //forward declaration
+
+ /// <summary>
+ /// The configuration that libCEC uses.
+ /// </summary>
+ public ref class LibCECConfiguration
+ {
+ public:
+ /// <summary>
+ /// Create a new configuration instance with default settings.
+ /// </summary>
+ LibCECConfiguration(void)
+ {
+ DeviceName = "";
+ DeviceTypes = gcnew CecDeviceTypeList();
+ AutodetectAddress = true;
+ PhysicalAddress = CEC_DEFAULT_PHYSICAL_ADDRESS;
+ BaseDevice = (CecLogicalAddress)CEC_DEFAULT_BASE_DEVICE;
+ HDMIPort = CEC_DEFAULT_HDMI_PORT;
+ ClientVersion = _LIBCEC_VERSION_CURRENT;
+ ServerVersion = 0;
+ TvVendor = CecVendorId::Unknown;
+
+ GetSettingsFromROM = false;
+ ActivateSource = CEC_DEFAULT_SETTING_ACTIVATE_SOURCE == 1;
+
+ WakeDevices = gcnew CecLogicalAddresses();
+ if (CEC_DEFAULT_SETTING_ACTIVATE_SOURCE == 1)
+ WakeDevices->Set(CecLogicalAddress::Tv);
+
+ PowerOffDevices = gcnew CecLogicalAddresses();
+ if (CEC_DEFAULT_SETTING_POWER_OFF_SHUTDOWN == 1)
+ PowerOffDevices->Set(CecLogicalAddress::Broadcast);
+
+ PowerOffOnStandby = CEC_DEFAULT_SETTING_POWER_OFF_ON_STANDBY == 1;
+
+ LogicalAddresses = gcnew CecLogicalAddresses();
+ FirmwareVersion = 1;
+ DeviceLanguage = "";
+ FirmwareBuildDate = gcnew System::DateTime(1970,1,1,0,0,0,0);
+ CECVersion = (CecVersion)CEC_DEFAULT_SETTING_CEC_VERSION;
+ AdapterType = CecAdapterType::Unknown;
+ }
+
+ static uint32_t CurrentVersion = _LIBCEC_VERSION_CURRENT;
+
+ /// <summary>
+ /// Change the callback method pointers in this configuration instance.
+ /// </summary>
+ /// <param name="callbacks">The new callbacks</param>
+ void SetCallbacks(CecCallbackMethods ^callbacks)
+ {
+ Callbacks = callbacks;
+ }
+
+ /// <summary>
+ /// Update this configuration with data received from libCEC
+ /// </summary>
+ /// <param name="config">The configuration that was received from libCEC</param>
+ void Update(const CEC::libcec_configuration &config)
+ {
+ DeviceName = gcnew System::String(config.strDeviceName);
+
+ for (unsigned int iPtr = 0; iPtr < 5; iPtr++)
+ DeviceTypes->Types[iPtr] = (CecDeviceType)config.deviceTypes.types[iPtr];
+
+ AutodetectAddress = config.bAutodetectAddress == 1;
+ PhysicalAddress = config.iPhysicalAddress;
+ BaseDevice = (CecLogicalAddress)config.baseDevice;
+ HDMIPort = config.iHDMIPort;
+ ClientVersion = config.clientVersion;
+ ServerVersion = config.serverVersion;
+ TvVendor = (CecVendorId)config.tvVendor;
+
+ // player specific settings
+ GetSettingsFromROM = config.bGetSettingsFromROM == 1;
+ ActivateSource = config.bActivateSource == 1;
+
+ WakeDevices->Clear();
+ for (uint8_t iPtr = 0; iPtr <= 16; iPtr++)
+ if (config.wakeDevices[iPtr])
+ WakeDevices->Set((CecLogicalAddress)iPtr);
+
+ PowerOffDevices->Clear();
+ for (uint8_t iPtr = 0; iPtr <= 16; iPtr++)
+ if (config.powerOffDevices[iPtr])
+ PowerOffDevices->Set((CecLogicalAddress)iPtr);
+
+ PowerOffOnStandby = config.bPowerOffOnStandby == 1;
+
+ LogicalAddresses->Clear();
+ for (uint8_t iPtr = 0; iPtr <= 16; iPtr++)
+ if (config.logicalAddresses[iPtr])
+ LogicalAddresses->Set((CecLogicalAddress)iPtr);
+
+ FirmwareVersion = config.iFirmwareVersion;
+
+ DeviceLanguage = gcnew System::String(config.strDeviceLanguage);
+ FirmwareBuildDate = gcnew System::DateTime(1970,1,1,0,0,0,0);
+ FirmwareBuildDate = FirmwareBuildDate->AddSeconds(config.iFirmwareBuildDate);
+
+ MonitorOnlyClient = config.bMonitorOnly == 1;
+ CECVersion = (CecVersion)config.cecVersion;
+ AdapterType = (CecAdapterType)config.adapterType;
+ }
+
+ /// <summary>
+ /// The device name to use on the CEC bus
+ /// </summary>
+ property System::String ^ DeviceName;
+
+ /// <summary>
+ /// The device type(s) to use on the CEC bus for libCEC
+ /// </summary>
+ property CecDeviceTypeList ^ DeviceTypes;
+
+ /// <summary>
+ /// (read only) set to true by libCEC when the physical address was autodetected
+ /// </summary>
+ property bool AutodetectAddress;
+
+ /// <summary>
+ /// The physical address of the CEC adapter
+ /// </summary>
+ property uint16_t PhysicalAddress;
+
+ /// <summary>
+ /// The logical address of the device to which the adapter is connected. Only used when PhysicalAddress = 0 or when the adapter doesn't support autodetection
+ /// </summary>
+ property CecLogicalAddress BaseDevice;
+
+ /// <summary>
+ /// The HDMI port to which the adapter is connected. Only used when iPhysicalAddress = 0 or when the adapter doesn't support autodetection
+ /// </summary>
+ property uint8_t HDMIPort;
+
+ /// <summary>
+ /// The client API version to use
+ /// </summary>
+ property uint32_t ClientVersion;
+
+ /// <summary>
+ /// The version of libCEC
+ /// </summary>
+ property uint32_t ServerVersion;
+
+ /// <summary>
+ /// Override the vendor ID of the TV. Leave this untouched to autodetect
+ /// </summary>
+ property CecVendorId TvVendor;
+
+ /// <summary>
+ /// True to read the settings from the EEPROM, which possibly override the settings passed here
+ /// </summary>
+ property bool GetSettingsFromROM;
+
+ /// <summary>
+ /// Make libCEC the active source when starting the client application
+ /// </summary>
+ property bool ActivateSource;
+
+ /// <summary>
+ /// List of devices to wake when initialising libCEC or when calling PowerOnDevices() without any parameter.
+ /// </summary>
+ property CecLogicalAddresses ^WakeDevices;
+
+ /// <summary>
+ /// List of devices to power off when calling StandbyDevices() without any parameter.
+ /// </summary>
+ property CecLogicalAddresses ^PowerOffDevices;
+
+ /// <summary>
+ /// Power off the PC when the TV powers off. Must be implemented by the client application.
+ /// </summary>
+ property bool PowerOffOnStandby;
+
+ /// <summary>
+ /// The list of logical addresses that libCEC is using
+ /// </summary>
+ property CecLogicalAddresses ^LogicalAddresses;
+
+ /// <summary>
+ /// The firmware version of the adapter to which libCEC is connected
+ /// </summary>
+ property uint16_t FirmwareVersion;
+
+ /// <summary>
+ /// True to start a monitor-only client, false to start a standard client.
+ /// </summary>
+ property bool MonitorOnlyClient;
+
+ /// <summary>
+ /// The language code of the menu language that libCEC reports to other devices.
+ /// 3 character ISO 639-2 country code. see http://http://www.loc.gov/standards/iso639-2/
+ /// </summary>
+ property System::String ^ DeviceLanguage;
+
+ /// <summary>
+ /// The callback methods to use.
+ /// </summary>
+ property CecCallbackMethods ^ Callbacks;
+
+ /// <summary>
+ /// The build date of the firmware.
+ /// </summary>
+ property System::DateTime ^ FirmwareBuildDate;
+
+ /// <summary>
+ /// The CEC version that libCEC uses.
+ /// </summary>
+ property CecVersion CECVersion;
+
+ /// <summary>
+ /// The type of adapter that libCEC is connected to.
+ /// </summary>
+ property CecAdapterType AdapterType;
+
+ };
+
+ // the callback methods are called by unmanaged code, so we need some delegates for this
+#pragma unmanaged
+ // unmanaged callback methods
+ typedef void (__stdcall *LOGCB) (const CEC::cec_log_message* message);
+ typedef void (__stdcall *KEYCB) (const CEC::cec_keypress* key);
+ typedef void (__stdcall *COMMANDCB)(const CEC::cec_command* command);
+ typedef void (__stdcall *CONFIGCB) (const CEC::libcec_configuration* config);
+ typedef void (__stdcall *ALERTCB) (const CEC::libcec_alert, const CEC::libcec_parameter &data);
+ typedef int (__stdcall *MENUCB) (const CEC::cec_menu_state newVal);
+ typedef void (__stdcall *ACTICB) (const CEC::cec_logical_address logicalAddress, const uint8_t bActivated);
+
+ /// <summary>
+ /// libCEC callback methods. Unmanaged code.
+ /// </summary>
+ typedef struct
+ {
+ /// <summary>
+ /// Log message callback
+ /// </summary>
+ LOGCB logCB;
+ /// <summary>
+ /// Key press/release callback
+ /// </summary>
+ KEYCB keyCB;
+ /// <summary>
+ /// Raw CEC data callback
+ /// </summary>
+ COMMANDCB commandCB;
+ /// <summary>
+ /// Updated configuration callback
+ /// </summary>
+ CONFIGCB configCB;
+ /// <summary>
+ /// Alert message callback
+ /// </summary>
+ ALERTCB alertCB;
+ /// <summary>
+ /// Menu status change callback
+ /// </summary>
+ MENUCB menuCB;
+ /// <summary>
+ /// Source (de)activated callback
+ /// </summary>
+ ACTICB sourceActivatedCB;
+ } UnmanagedCecCallbacks;
+
+ static P8PLATFORM::CMutex g_callbackMutex;
+ static std::vector<UnmanagedCecCallbacks> g_unmanagedCallbacks;
+ static CEC::ICECCallbacks g_cecCallbacks;
+
+ /// <summary>
+ /// Called by libCEC to send back a log message to the application
+ /// </summary>
+ /// <param name="cbParam">Pointer to the callback struct</param>
+ /// <param name="message">The log message</param>
+ void CecLogMessageCB(void *cbParam, const CEC::cec_log_message* message)
+ {
+ if (cbParam)
+ {
+ size_t iPtr = (size_t)cbParam;
+ P8PLATFORM::CLockObject lock(g_callbackMutex);
+ if (iPtr >= 0 && iPtr < g_unmanagedCallbacks.size())
+ g_unmanagedCallbacks[iPtr].logCB(message);
+ }
+ }
+
+ /// <summary>
+ /// Called by libCEC to send back a key press or release to the application
+ /// </summary>
+ /// <param name="cbParam">Pointer to the callback struct</param>
+ /// <param name="key">The key press command that libCEC received</param>
+ void CecKeyPressCB(void *cbParam, const CEC::cec_keypress* key)
+ {
+ if (cbParam)
+ {
+ size_t iPtr = (size_t)cbParam;
+ P8PLATFORM::CLockObject lock(g_callbackMutex);
+ if (iPtr >= 0 && iPtr < g_unmanagedCallbacks.size())
+ g_unmanagedCallbacks[iPtr].keyCB(key);
+ }
+ }
+
+ /// <summary>
+ /// Called by libCEC to send back raw CEC data to the application
+ /// </summary>
+ /// <param name="cbParam">Pointer to the callback struct</param>
+ /// <param name="command">The raw CEC data</param>
+ void CecCommandCB(void *cbParam, const CEC::cec_command* command)
+ {
+ if (cbParam)
+ {
+ size_t iPtr = (size_t)cbParam;
+ P8PLATFORM::CLockObject lock(g_callbackMutex);
+ if (iPtr >= 0 && iPtr < g_unmanagedCallbacks.size())
+ g_unmanagedCallbacks[iPtr].commandCB(command);
+ }
+ }
+
+ /// <summary>
+ /// Called by libCEC to send back an updated configuration to the application
+ /// </summary>
+ /// <param name="cbParam">Pointer to the callback struct</param>
+ /// <param name="config">The new configuration</param>
+ void CecConfigCB(void *cbParam, const CEC::libcec_configuration* config)
+ {
+ if (cbParam)
+ {
+ size_t iPtr = (size_t)cbParam;
+ P8PLATFORM::CLockObject lock(g_callbackMutex);
+ if (iPtr >= 0 && iPtr < g_unmanagedCallbacks.size())
+ g_unmanagedCallbacks[iPtr].configCB(config);
+ }
+ }
+
+ /// <summary>
+ /// Called by libCEC to send back an alert message to the application
+ /// </summary>
+ /// <param name="cbParam">Pointer to the callback struct</param>
+ /// <param name="data">The alert message</param>
+ void CecAlertCB(void *cbParam, const CEC::libcec_alert alert, const CEC::libcec_parameter data)
+ {
+ if (cbParam)
+ {
+ size_t iPtr = (size_t)cbParam;
+ P8PLATFORM::CLockObject lock(g_callbackMutex);
+ if (iPtr >= 0 && iPtr < g_unmanagedCallbacks.size())
+ g_unmanagedCallbacks[iPtr].alertCB(alert, data);
+ }
+ }
+
+ /// <summary>
+ /// Called by libCEC to send back a menu state change to the application
+ /// </summary>
+ /// <param name="cbParam">Pointer to the callback struct</param>
+ /// <param name="newVal">The new menu state</param>
+ /// <return>1 when handled, 0 otherwise</return>
+ int CecMenuCB(void *cbParam, const CEC::cec_menu_state newVal)
+ {
+ if (cbParam)
+ {
+ size_t iPtr = (size_t)cbParam;
+ P8PLATFORM::CLockObject lock(g_callbackMutex);
+ if (iPtr >= 0 && iPtr < g_unmanagedCallbacks.size())
+ return g_unmanagedCallbacks[iPtr].menuCB(newVal);
+ }
+ return 0;
+ }
+
+ /// <summary>
+ /// Called by libCEC to notify the application that the source that is handled by libCEC was (de)activated
+ /// </summary>
+ /// <param name="cbParam">Pointer to the callback struct</param>
+ /// <param name="logicalAddress">The logical address that was (de)activated</param>
+ /// <param name="activated">True when activated, false when deactivated</param>
+ void CecSourceActivatedCB(void *cbParam, const CEC::cec_logical_address logicalAddress, const uint8_t activated)
+ {
+ if (cbParam)
+ {
+ size_t iPtr = (size_t)cbParam;
+ P8PLATFORM::CLockObject lock(g_callbackMutex);
+ if (iPtr >= 0 && iPtr < g_unmanagedCallbacks.size())
+ g_unmanagedCallbacks[iPtr].sourceActivatedCB(logicalAddress, activated);
+ }
+ }
+
+#pragma managed
+ /// <summary>
+ /// Delegate method for the CecLogMessageCB callback in CecCallbackMethods
+ /// </summary>
+ public delegate int CecLogMessageManagedDelegate(const CEC::cec_log_message &);
+ /// <summary>
+ /// Delegate method for the CecKeyPressCB callback in CecCallbackMethods
+ /// </summary>
+ public delegate int CecKeyPressManagedDelegate(const CEC::cec_keypress &);
+ /// <summary>
+ /// Delegate method for the CecCommandCB callback in CecCallbackMethods
+ /// </summary>
+ public delegate int CecCommandManagedDelegate(const CEC::cec_command &);
+ /// <summary>
+ /// Delegate method for the CecConfigCB callback in CecCallbackMethods
+ /// </summary>
+ public delegate int CecConfigManagedDelegate(const CEC::libcec_configuration &);
+ /// <summary>
+ /// Delegate method for the CecAlertCB callback in CecCallbackMethods
+ /// </summary>
+ public delegate int CecAlertManagedDelegate(const CEC::libcec_alert, const CEC::libcec_parameter &);
+ /// <summary>
+ /// Delegate method for the CecMenuCB callback in CecCallbackMethods
+ /// </summary>
+ public delegate int CecMenuManagedDelegate(const CEC::cec_menu_state);
+ /// <summary>
+ /// Delegate method for the CecSourceActivatedCB callback in CecCallbackMethods
+ /// </summary>
+ public delegate void CecSourceActivatedManagedDelegate(const CEC::cec_logical_address, const uint8_t);
+
+ /// <summary>
+ /// Assign the callback methods in the g_cecCallbacks struct
+ /// </summary>
+ void AssignCallbacks()
+ {
+ g_cecCallbacks.logMessage = CecLogMessageCB;
+ g_cecCallbacks.keyPress = CecKeyPressCB;
+ g_cecCallbacks.commandReceived = CecCommandCB;
+ g_cecCallbacks.configurationChanged = CecConfigCB;
+ g_cecCallbacks.alert = CecAlertCB;
+ g_cecCallbacks.menuStateChanged = CecMenuCB;
+ g_cecCallbacks.sourceActivated = CecSourceActivatedCB;
+ }
+
+ /// <summary>
+ /// The callback methods that libCEC uses
+ /// </summary>
+ public ref class CecCallbackMethods
+ {
+ public:
+ CecCallbackMethods(void)
+ {
+ m_iCallbackPtr = -1;
+ AssignCallbacks();
+ m_bHasCallbacks = false;
+ m_bDelegatesCreated = false;
+ }
+
+ ~CecCallbackMethods(void)
+ {
+ DestroyDelegates();
+ }
+
+ /// <summary>
+ /// Pointer to the callbacks struct entry
+ /// </summary>
+ size_t GetCallbackPtr(void)
+ {
+ P8PLATFORM::CLockObject lock(g_callbackMutex);
+ return m_iCallbackPtr;
+ }
+
+ protected:
+ !CecCallbackMethods(void)
+ {
+ DestroyDelegates();
+ }
+
+ public:
+ /// <summary>
+ /// Disable callback methods
+ /// </summary>
+ virtual void DisableCallbacks(void)
+ {
+ DestroyDelegates();
+ }
+
+ /// <summary>
+ /// Enable callback methods
+ /// </summary>
+ /// <param name="callbacks">Callback methods to activate</param>
+ /// <return>true when handled, false otherwise</return>
+ virtual bool EnableCallbacks(CecCallbackMethods ^ callbacks)
+ {
+ CreateDelegates();
+ if (!m_bHasCallbacks)
+ {
+ m_bHasCallbacks = true;
+ m_callbacks = callbacks;
+ return true;
+ }
+
+ return false;
+ }
+
+ /// <summary>
+ /// Called by libCEC to send back a log message to the application.
+ /// Override in the application to handle this callback.
+ /// </summary>
+ /// <param name="message">The log message</param>
+ /// <return>1 when handled, 0 otherwise</return>
+ virtual int ReceiveLogMessage(CecLogMessage ^ message)
+ {
+ return 0;
+ }
+
+ /// <summary>
+ /// Called by libCEC to send back a key press or release to the application.
+ /// Override in the application to handle this callback.
+ /// </summary>
+ /// <param name="key">The key press command that libCEC received</param>
+ /// <return>1 when handled, 0 otherwise</return>
+ virtual int ReceiveKeypress(CecKeypress ^ key)
+ {
+ return 0;
+ }
+
+ /// <summary>
+ /// Called by libCEC to send back raw CEC data to the application.
+ /// Override in the application to handle this callback.
+ /// </summary>
+ /// <param name="command">The raw CEC data</param>
+ /// <return>1 when handled, 0 otherwise</return>
+ virtual int ReceiveCommand(CecCommand ^ command)
+ {
+ return 0;
+ }
+
+ /// <summary>
+ /// Called by libCEC to send back an updated configuration to the application.
+ /// Override in the application to handle this callback.
+ /// </summary>
+ /// <param name="config">The new configuration</param>
+ /// <return>1 when handled, 0 otherwise</return>
+ virtual int ConfigurationChanged(LibCECConfiguration ^ config)
+ {
+ return 0;
+ }
+
+ /// <summary>
+ /// Called by libCEC to send back an alert message to the application.
+ /// Override in the application to handle this callback.
+ /// </summary>
+ /// <param name="data">The alert message</param>
+ /// <return>1 when handled, 0 otherwise</return>
+ virtual int ReceiveAlert(CecAlert alert, CecParameter ^ data)
+ {
+ return 0;
+ }
+
+ /// <summary>
+ /// Called by libCEC to send back a menu state change to the application.
+ /// Override in the application to handle this callback.
+ /// </summary>
+ /// <param name="newVal">The new menu state</param>
+ /// <return>1 when handled, 0 otherwise</return>
+ virtual int ReceiveMenuStateChange(CecMenuState newVal)
+ {
+ return 0;
+ }
+
+ /// <summary>
+ /// Called by libCEC to notify the application that the source that is handled by libCEC was (de)activated.
+ /// Override in the application to handle this callback.
+ /// </summary>
+ /// <param name="logicalAddress">The logical address that was (de)activated</param>
+ /// <param name="activated">True when activated, false when deactivated</param>
+ virtual void SourceActivated(CecLogicalAddress logicalAddress, bool activated)
+ {
+ }
+
+ protected:
+ // managed callback methods
+ int CecLogMessageManaged(const CEC::cec_log_message &message)
+ {
+ int iReturn(0);
+ if (m_bHasCallbacks)
+ iReturn = m_callbacks->ReceiveLogMessage(gcnew CecLogMessage(gcnew System::String(message.message), (CecLogLevel)message.level, message.time));
+ return iReturn;
+ }
+
+ int CecKeyPressManaged(const CEC::cec_keypress &key)
+ {
+ int iReturn(0);
+ if (m_bHasCallbacks)
+ iReturn = m_callbacks->ReceiveKeypress(gcnew CecKeypress((CecUserControlCode)key.keycode, key.duration));
+ return iReturn;
+ }
+
+ int CecCommandManaged(const CEC::cec_command &command)
+ {
+ int iReturn(0);
+ if (m_bHasCallbacks)
+ {
+ CecCommand ^ newCommand = gcnew CecCommand((CecLogicalAddress)command.initiator, (CecLogicalAddress)command.destination, command.ack == 1 ? true : false, command.eom == 1 ? true : false, (CecOpcode)command.opcode, command.transmit_timeout);
+ for (uint8_t iPtr = 0; iPtr < command.parameters.size; iPtr++)
+ newCommand->Parameters->PushBack(command.parameters[iPtr]);
+ iReturn = m_callbacks->ReceiveCommand(newCommand);
+ }
+ return iReturn;
+ }
+
+ int CecConfigManaged(const CEC::libcec_configuration &config)
+ {
+ int iReturn(0);
+ if (m_bHasCallbacks)
+ {
+ LibCECConfiguration ^netConfig = gcnew LibCECConfiguration();
+ netConfig->Update(config);
+ iReturn = m_callbacks->ConfigurationChanged(netConfig);
+ }
+ return iReturn;
+ }
+
+ int CecAlertManaged(const CEC::libcec_alert alert, const CEC::libcec_parameter &data)
+ {
+ int iReturn(0);
+ if (m_bHasCallbacks)
+ {
+ CecParameterType newType = (CecParameterType)data.paramType;
+ if (newType == CecParameterType::ParameterTypeString)
+ {
+ System::String ^ newData = gcnew System::String(data.paramData ? (const char *)data.paramData : "", 0, 128);
+ CecParameter ^ newParam = gcnew CecParameter(newType, newData);
+ iReturn = m_callbacks->ReceiveAlert((CecAlert)alert, newParam);
+ }
+ }
+ return iReturn;
+ }
+
+ int CecMenuManaged(const CEC::cec_menu_state newVal)
+ {
+ int iReturn(0);
+ if (m_bHasCallbacks)
+ {
+ iReturn = m_callbacks->ReceiveMenuStateChange((CecMenuState)newVal);
+ }
+ return iReturn;
+ }
+
+ void CecSourceActivatedManaged(const CEC::cec_logical_address logicalAddress, const uint8_t bActivated)
+ {
+ if (m_bHasCallbacks)
+ m_callbacks->SourceActivated((CecLogicalAddress)logicalAddress, bActivated == 1);
+ }
+
+ void DestroyDelegates()
+ {
+ m_bHasCallbacks = false;
+ if (m_bDelegatesCreated)
+ {
+ m_bDelegatesCreated = false;
+ m_logMessageGCHandle.Free();
+ m_keypressGCHandle.Free();
+ m_commandGCHandle.Free();
+ m_alertGCHandle.Free();
+ m_menuGCHandle.Free();
+ m_sourceActivatedGCHandle.Free();
+ }
+ }
+
+ void CreateDelegates()
+ {
+ DestroyDelegates();
+
+ if (!m_bDelegatesCreated)
+ {
+ msclr::interop::marshal_context ^ context = gcnew msclr::interop::marshal_context();
+
+ // create the delegate method for the log message callback
+ m_logMessageDelegate = gcnew CecLogMessageManagedDelegate(this, &CecCallbackMethods::CecLogMessageManaged);
+ m_logMessageGCHandle = System::Runtime::InteropServices::GCHandle::Alloc(m_logMessageDelegate);
+ m_logMessageCallback = static_cast<LOGCB>(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_logMessageDelegate).ToPointer());
+
+ // create the delegate method for the keypress callback
+ m_keypressDelegate = gcnew CecKeyPressManagedDelegate(this, &CecCallbackMethods::CecKeyPressManaged);
+ m_keypressGCHandle = System::Runtime::InteropServices::GCHandle::Alloc(m_keypressDelegate);
+ m_keypressCallback = static_cast<KEYCB>(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_keypressDelegate).ToPointer());
+
+ // create the delegate method for the command callback
+ m_commandDelegate = gcnew CecCommandManagedDelegate(this, &CecCallbackMethods::CecCommandManaged);
+ m_commandGCHandle = System::Runtime::InteropServices::GCHandle::Alloc(m_commandDelegate);
+ m_commandCallback = static_cast<COMMANDCB>(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_commandDelegate).ToPointer());
+
+ // create the delegate method for the configuration change callback
+ m_configDelegate = gcnew CecConfigManagedDelegate(this, &CecCallbackMethods::CecConfigManaged);
+ m_configGCHandle = System::Runtime::InteropServices::GCHandle::Alloc(m_configDelegate);
+ m_configCallback = static_cast<CONFIGCB>(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_configDelegate).ToPointer());
+
+ // create the delegate method for the alert callback
+ m_alertDelegate = gcnew CecAlertManagedDelegate(this, &CecCallbackMethods::CecAlertManaged);
+ m_alertGCHandle = System::Runtime::InteropServices::GCHandle::Alloc(m_alertDelegate);
+ m_alertCallback = static_cast<ALERTCB>(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_alertDelegate).ToPointer());
+
+ // create the delegate method for the menu callback
+ m_menuDelegate = gcnew CecMenuManagedDelegate(this, &CecCallbackMethods::CecMenuManaged);
+ m_menuGCHandle = System::Runtime::InteropServices::GCHandle::Alloc(m_menuDelegate);
+ m_menuCallback = static_cast<MENUCB>(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_menuDelegate).ToPointer());
+
+ // create the delegate method for the source activated callback
+ m_sourceActivatedDelegate = gcnew CecSourceActivatedManagedDelegate(this, &CecCallbackMethods::CecSourceActivatedManaged);
+ m_sourceActivatedGCHandle = System::Runtime::InteropServices::GCHandle::Alloc(m_sourceActivatedDelegate);
+ m_sourceActivatedCallback = static_cast<ACTICB>(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_sourceActivatedDelegate).ToPointer());
+
+ delete context;
+
+ UnmanagedCecCallbacks unmanagedCallbacks;
+ unmanagedCallbacks.logCB = m_logMessageCallback;
+ unmanagedCallbacks.keyCB = m_keypressCallback;
+ unmanagedCallbacks.commandCB = m_commandCallback;
+ unmanagedCallbacks.configCB = m_configCallback;
+ unmanagedCallbacks.alertCB = m_alertCallback;
+ unmanagedCallbacks.menuCB = m_menuCallback;
+ unmanagedCallbacks.sourceActivatedCB = m_sourceActivatedCallback;
+
+ P8PLATFORM::CLockObject lock(g_callbackMutex);
+ g_unmanagedCallbacks.push_back(unmanagedCallbacks);
+ m_iCallbackPtr = g_unmanagedCallbacks.size() - 1;
+ m_bDelegatesCreated = true;
+ }
+ }
+
+ CecLogMessageManagedDelegate ^ m_logMessageDelegate;
+ static System::Runtime::InteropServices::GCHandle m_logMessageGCHandle;
+ LOGCB m_logMessageCallback;
+
+ CecKeyPressManagedDelegate ^ m_keypressDelegate;
+ static System::Runtime::InteropServices::GCHandle m_keypressGCHandle;
+ KEYCB m_keypressCallback;
+
+ CecCommandManagedDelegate ^ m_commandDelegate;
+ static System::Runtime::InteropServices::GCHandle m_commandGCHandle;
+ COMMANDCB m_commandCallback;
+
+ CecConfigManagedDelegate ^ m_configDelegate;
+ static System::Runtime::InteropServices::GCHandle m_configGCHandle;
+ CONFIGCB m_configCallback;
+
+ CecAlertManagedDelegate ^ m_alertDelegate;
+ static System::Runtime::InteropServices::GCHandle m_alertGCHandle;
+ ALERTCB m_alertCallback;
+
+ CecMenuManagedDelegate ^ m_menuDelegate;
+ static System::Runtime::InteropServices::GCHandle m_menuGCHandle;
+ MENUCB m_menuCallback;
+
+ CecSourceActivatedManagedDelegate ^ m_sourceActivatedDelegate;
+ static System::Runtime::InteropServices::GCHandle m_sourceActivatedGCHandle;
+ ACTICB m_sourceActivatedCallback;
+
+ CecCallbackMethods ^ m_callbacks;
+ bool m_bHasCallbacks;
+ bool m_bDelegatesCreated;
+ size_t m_iCallbackPtr;
+ };
+}
--- /dev/null
+/*
+* This file is part of the libCEC(R) library.
+*
+* libCEC(R) is Copyright (C) 2011-2013 Pulse-Eight Limited. All rights reserved.
+* libCEC(R) is an original work, containing original code.
+*
+* libCEC(R) is a trademark of Pulse-Eight Limited.
+*
+* This program is dual-licensed; 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.
+*
+*
+* Alternatively, you can license this library under a commercial license,
+* please contact Pulse-Eight Licensing for more information.
+*
+* For more information contact:
+* Pulse-Eight Licensing <license@pulse-eight.com>
+* http://www.pulse-eight.com/
+* http://www.pulse-eight.net/
+*/
+
+#include "CecSharpTypes.h"
+#using <System.dll>
+
+using namespace System;
+using namespace System::Runtime::InteropServices;
+using namespace CEC;
+using namespace msclr::interop;
+
+namespace CecSharp
+{
+ /// <summary>
+ /// Create a LibCecSharp instance and pass the configuration as argument.
+ /// Then call Open() to open a connection to the adapter. Close() closes the
+ /// connection.
+ ///
+ /// libCEC can send commands to other devices on the CEC bus via the methods
+ /// on this interface, and all commands that libCEC received are sent back
+ /// to the application via callback methods. The callback methods can be
+ /// found in CecSharpTypes.h, CecCallbackMethods.
+ /// </summary>
+ public ref class LibCecSharp : public CecCallbackMethods
+ {
+ public:
+ /// <summary>
+ /// Create a new LibCecSharp instance.
+ /// </summary>
+ /// <param name="config">The configuration to pass to libCEC.</param>
+ LibCecSharp(LibCECConfiguration ^config)
+ {
+ m_callbacks = config->Callbacks;
+ CecCallbackMethods::EnableCallbacks(m_callbacks);
+ if (!InitialiseLibCec(config))
+ throw gcnew Exception("Could not initialise LibCecSharp");
+ }
+
+ ~LibCecSharp(void)
+ {
+ Close();
+ m_libCec = NULL;
+ }
+
+ /// <summary>
+ /// Try to find all connected CEC adapters.
+ /// </summary>
+ /// <param name="path">The path filter for adapters. Leave empty to return all adapters.</param>
+ /// <returns>The adapters that were found.</returns>
+ array<CecAdapter ^> ^ FindAdapters(String ^ path)
+ {
+ cec_adapter_descriptor *devices = new cec_adapter_descriptor[10];
+
+ marshal_context ^ context = gcnew marshal_context();
+ const char* strPathC = path->Length > 0 ? context->marshal_as<const char*>(path) : NULL;
+
+ uint8_t iDevicesFound = m_libCec->DetectAdapters(devices, 10, NULL, false);
+
+ array<CecAdapter ^> ^ adapters = gcnew array<CecAdapter ^>(iDevicesFound);
+ for (unsigned int iPtr = 0; iPtr < iDevicesFound; iPtr++)
+ adapters[iPtr] = gcnew CecAdapter(gcnew String(devices[iPtr].strComPath), gcnew String(devices[iPtr].strComName), devices[iPtr].iVendorId, devices[iPtr].iProductId, devices[iPtr].iFirmwareVersion, devices[iPtr].iFirmwareBuildDate, devices[iPtr].iPhysicalAddress);
+
+ delete devices;
+ delete context;
+ return adapters;
+ }
+
+ /// <summary>
+ /// Open a connection to the CEC adapter.
+ /// </summary>
+ /// <param name="strPort">The COM port of the adapter</param>
+ /// <param name="iTimeoutMs">Connection timeout in milliseconds</param>
+ /// <returns>True when a connection was opened, false otherwise.</returns>
+ bool Open(String ^ strPort, int iTimeoutMs)
+ {
+ CecCallbackMethods::EnableCallbacks(m_callbacks);
+ EnableCallbacks(m_callbacks);
+ marshal_context ^ context = gcnew marshal_context();
+ const char* strPortC = context->marshal_as<const char*>(strPort);
+ bool bReturn = m_libCec->Open(strPortC, iTimeoutMs);
+ delete context;
+ return bReturn;
+ }
+
+ /// <summary>
+ /// Close the connection to the CEC adapter
+ /// </summary>
+ void Close(void)
+ {
+ DisableCallbacks();
+ m_libCec->Close();
+ }
+
+ /// <summary>
+ /// Disable all calls to callback methods.
+ /// </summary>
+ virtual void DisableCallbacks(void) override
+ {
+ // delete the callbacks, since these might already have been destroyed in .NET
+ CecCallbackMethods::DisableCallbacks();
+ if (m_libCec)
+ m_libCec->EnableCallbacks(NULL, NULL);
+ }
+
+ /// <summary>
+ /// Enable or change the callback methods that libCEC uses to send changes to the client application.
+ /// </summary>
+ /// <param name="callbacks">The new callback methods to use.</param>
+ /// <returns>True when the callbacks were changed, false otherwise</returns>
+ virtual bool EnableCallbacks(CecCallbackMethods ^ callbacks) override
+ {
+ if (m_libCec && CecCallbackMethods::EnableCallbacks(callbacks))
+ return m_libCec->EnableCallbacks((void*)GetCallbackPtr(), &g_cecCallbacks);
+
+ return false;
+ }
+
+ /// <summary>
+ /// Sends a ping command to the adapter, to check if it's responding.
+ /// </summary>
+ /// <returns>True when the ping was successful, false otherwise</returns>
+ bool PingAdapter(void)
+ {
+ return m_libCec->PingAdapter();
+ }
+
+ /// <summary>
+ /// Start the bootloader of the CEC adapter. Closes the connection when successful.
+ /// </summary>
+ /// <returns>True when the command was sent successfully, false otherwise.</returns>
+ bool StartBootloader(void)
+ {
+ return m_libCec->StartBootloader();
+ }
+
+ /// <summary>
+ /// Transmit a raw CEC command over the CEC line.
+ /// </summary>
+ /// <param name="command">The command to transmit</param>
+ /// <returns>True when the data was sent and acked, false otherwise.</returns>
+ bool Transmit(CecCommand ^ command)
+ {
+ cec_command ccommand;
+ cec_command::Format(ccommand, (cec_logical_address)command->Initiator, (cec_logical_address)command->Destination, (cec_opcode)command->Opcode);
+ ccommand.transmit_timeout = command->TransmitTimeout;
+ ccommand.eom = command->Eom;
+ ccommand.ack = command->Ack;
+ for (unsigned int iPtr = 0; iPtr < command->Parameters->Size; iPtr++)
+ ccommand.parameters.PushBack(command->Parameters->Data[iPtr]);
+
+ return m_libCec->Transmit(ccommand);
+ }
+
+ /// <summary>
+ /// Change the logical address on the CEC bus of the CEC adapter. libCEC automatically assigns a logical address, and this method is only available for debugging purposes.
+ /// </summary>
+ /// <param name="logicalAddress">The CEC adapter's new logical address.</param>
+ /// <returns>True when the logical address was set successfully, false otherwise.</returns>
+ bool SetLogicalAddress(CecLogicalAddress logicalAddress)
+ {
+ return m_libCec->SetLogicalAddress((cec_logical_address) logicalAddress);
+ }
+
+ /// <summary>
+ /// Change the physical address (HDMI port) of the CEC adapter. libCEC will try to autodetect the physical address when connecting. If it did, it's set in libcec_configuration.
+ /// </summary>
+ /// <param name="physicalAddress">The CEC adapter's new physical address.</param>
+ /// <returns>True when the physical address was set successfully, false otherwise.</returns>
+ bool SetPhysicalAddress(uint16_t physicalAddress)
+ {
+ return m_libCec->SetPhysicalAddress(physicalAddress);
+ }
+
+ /// <summary>
+ /// Power on the given CEC capable devices. If CECDEVICE_BROADCAST is used, then wakeDevice in libcec_configuration will be used.
+ /// </summary>
+ /// <param name="logicalAddress">The logical address to power on.</param>
+ /// <returns>True when the command was sent successfully, false otherwise.</returns>
+ bool PowerOnDevices(CecLogicalAddress logicalAddress)
+ {
+ return m_libCec->PowerOnDevices((cec_logical_address) logicalAddress);
+ }
+
+ /// <summary>
+ /// Put the given CEC capable devices in standby mode. If CECDEVICE_BROADCAST is used, then standbyDevices in libcec_configuration will be used.
+ /// </summary>
+ /// <param name="logicalAddress">The logical address of the device to put in standby.</param>
+ /// <returns>True when the command was sent successfully, false otherwise.</returns>
+ bool StandbyDevices(CecLogicalAddress logicalAddress)
+ {
+ return m_libCec->StandbyDevices((cec_logical_address) logicalAddress);
+ }
+
+ /// <summary>
+ /// Sends a POLL message to a device, to check if it's present and responding.
+ /// </summary>
+ /// <param name="logicalAddress">The device to send the message to.</param>
+ /// <returns>True if the POLL was acked, false otherwise.</returns>
+ bool PollDevice(CecLogicalAddress logicalAddress)
+ {
+ return m_libCec->PollDevice((cec_logical_address) logicalAddress);
+ }
+
+ /// <summary>
+ /// Change the active source to a device type handled by libCEC. Use CEC_DEVICE_TYPE_RESERVED to make the default type used by libCEC active.
+ /// </summary>
+ /// <param name="type">The new active source. Use CEC_DEVICE_TYPE_RESERVED to use the primary type</param>
+ /// <returns>True when the command was sent successfully, false otherwise.</returns>
+ bool SetActiveSource(CecDeviceType type)
+ {
+ return m_libCec->SetActiveSource((cec_device_type) type);
+ }
+
+ /// <summary>
+ /// Change the deck control mode, if this adapter is registered as playback or recording device.
+ /// </summary>
+ /// <param name="mode">The new control mode.</param>
+ /// <param name="sendUpdate">True to send the new status over the CEC line.</param>
+ /// <returns>True if set, false otherwise.</returns>
+ bool SetDeckControlMode(CecDeckControlMode mode, bool sendUpdate)
+ {
+ return m_libCec->SetDeckControlMode((cec_deck_control_mode) mode, sendUpdate);
+ }
+
+ /// <summary>
+ /// Change the deck info, if this adapter is a playback or recording device.
+ /// </summary>
+ /// <param name="info">The new deck info.</param>
+ /// <param name="sendUpdate">True to send the new status over the CEC line.</param>
+ /// <returns>True if set, false otherwise.</returns>
+ bool SetDeckInfo(CecDeckInfo info, bool sendUpdate)
+ {
+ return m_libCec->SetDeckInfo((cec_deck_info) info, sendUpdate);
+ }
+
+ /// <summary>
+ /// Broadcast a message that notifies connected CEC capable devices that this device is no longer the active source.
+ /// </summary>
+ /// <returns>True when the command was sent successfully, false otherwise.</returns>
+ bool SetInactiveView(void)
+ {
+ return m_libCec->SetInactiveView();
+ }
+
+ /// <summary>
+ /// Change the menu state. This value is already changed by libCEC automatically if a device is (de)activated.
+ /// </summary>
+ /// <param name="state">The new state.</param>
+ /// <param name="sendUpdate">True to send the new status over the CEC line.</param>
+ /// <returns>True if set, false otherwise.</returns>
+ bool SetMenuState(CecMenuState state, bool sendUpdate)
+ {
+ return m_libCec->SetMenuState((cec_menu_state) state, sendUpdate);
+ }
+
+ /// <summary>
+ /// Display a message on the device with the given logical address. Not supported by most TVs.
+ /// </summary>
+ /// <param name="logicalAddress">The logical address of the device to display the message on.</param>
+ /// <param name="duration">The duration of the message</param>
+ /// <param name="message">The message to display.</param>
+ /// <returns>True when the command was sent, false otherwise.</returns>
+ bool SetOSDString(CecLogicalAddress logicalAddress, CecDisplayControl duration, String ^ message)
+ {
+ marshal_context ^ context = gcnew marshal_context();
+ const char* strMessageC = context->marshal_as<const char*>(message);
+
+ bool bReturn = m_libCec->SetOSDString((cec_logical_address) logicalAddress, (cec_display_control) duration, strMessageC);
+
+ delete context;
+ return bReturn;
+ }
+
+ /// <summary>
+ /// Enable or disable monitoring mode, for debugging purposes. If monitoring mode is enabled, libCEC won't respond to any command, but only log incoming data.
+ /// </summary>
+ /// <param name="enable">True to enable, false to disable.</param>
+ /// <returns>True when switched successfully, false otherwise.</returns>
+ bool SwitchMonitoring(bool enable)
+ {
+ return m_libCec->SwitchMonitoring(enable);
+ }
+
+ /// <summary>
+ /// Get the CEC version of the device with the given logical address
+ /// </summary>
+ /// <param name="logicalAddress">The logical address of the device to get the CEC version for.</param>
+ /// <returns>The version or CEC_VERSION_UNKNOWN when the version couldn't be fetched.</returns>
+ CecVersion GetDeviceCecVersion(CecLogicalAddress logicalAddress)
+ {
+ return (CecVersion) m_libCec->GetDeviceCecVersion((cec_logical_address) logicalAddress);
+ }
+
+ /// <summary>
+ /// Get the menu language of the device with the given logical address
+ /// </summary>
+ /// <param name="logicalAddress">The logical address of the device to get the menu language for.</param>
+ /// <returns>The requested menu language.</returns>
+ String ^ GetDeviceMenuLanguage(CecLogicalAddress logicalAddress)
+ {
+ std::string strLang = m_libCec->GetDeviceMenuLanguage((cec_logical_address)logicalAddress);
+ return gcnew String(strLang.c_str());
+ }
+
+ /// <summary>
+ /// Get the vendor ID of the device with the given logical address.
+ /// </summary>
+ /// <param name="logicalAddress">The logical address of the device to get the vendor ID for.</param>
+ /// <returns>The vendor ID or 0 if it wasn't found.</returns>
+ CecVendorId GetDeviceVendorId(CecLogicalAddress logicalAddress)
+ {
+ return (CecVendorId)m_libCec->GetDeviceVendorId((cec_logical_address) logicalAddress);
+ }
+
+ /// <summary>
+ /// Get the power status of the device with the given logical address.
+ /// </summary>
+ /// <param name="logicalAddress">The logical address of the device to get the power status for.</param>
+ /// <returns>The power status or CEC_POWER_STATUS_UNKNOWN if it wasn't found.</returns>
+ CecPowerStatus GetDevicePowerStatus(CecLogicalAddress logicalAddress)
+ {
+ return (CecPowerStatus) m_libCec->GetDevicePowerStatus((cec_logical_address) logicalAddress);
+ }
+
+ /// <summary>
+ /// Tell libCEC to poll for active devices on the bus.
+ /// </summary>
+ void RescanActiveDevices(void)
+ {
+ m_libCec->RescanActiveDevices();
+ }
+
+ /// <summary>
+ /// Get the logical addresses of the devices that are active on the bus, including those handled by libCEC.
+ /// </summary>
+ /// <returns>The logical addresses of the active devices</returns>
+ CecLogicalAddresses ^ GetActiveDevices(void)
+ {
+ CecLogicalAddresses ^ retVal = gcnew CecLogicalAddresses();
+ unsigned int iDevices = 0;
+
+ cec_logical_addresses activeDevices = m_libCec->GetActiveDevices();
+
+ for (uint8_t iPtr = 0; iPtr < 16; iPtr++)
+ if (activeDevices[iPtr])
+ retVal->Set((CecLogicalAddress)iPtr);
+
+ return retVal;
+ }
+
+ /// <summary>
+ /// Check whether a device is active on the bus.
+ /// </summary>
+ /// <param name="logicalAddress">The address to check.</param>
+ /// <returns>True when active, false otherwise.</returns>
+ bool IsActiveDevice(CecLogicalAddress logicalAddress)
+ {
+ return m_libCec->IsActiveDevice((cec_logical_address)logicalAddress);
+ }
+
+ /// <summary>
+ /// Check whether a device of the given type is active on the bus.
+ /// </summary>
+ /// <param name="type">The type to check.</param>
+ /// <returns>True when active, false otherwise.</returns>
+ bool IsActiveDeviceType(CecDeviceType type)
+ {
+ return m_libCec->IsActiveDeviceType((cec_device_type)type);
+ }
+
+ /// <summary>
+ /// Changes the active HDMI port.
+ /// </summary>
+ /// <param name="address">The device to which this libCEC is connected.</param>
+ /// <param name="port">The new port number.</param>
+ /// <returns>True when changed, false otherwise.</returns>
+ bool SetHDMIPort(CecLogicalAddress address, uint8_t port)
+ {
+ return m_libCec->SetHDMIPort((cec_logical_address)address, port);
+ }
+
+ /// <summary>
+ /// Sends a volume up keypress to an audiosystem if it's present.
+ /// </summary>
+ /// <param name="sendRelease">Send a key release after the keypress.</param>
+ /// <returns>The new audio status.</returns>
+ uint8_t VolumeUp(bool sendRelease)
+ {
+ return m_libCec->VolumeUp(sendRelease);
+ }
+
+ /// <summary>
+ /// Sends a volume down keypress to an audiosystem if it's present.
+ /// </summary>
+ /// <param name="sendRelease">Send a key release after the keypress.</param>
+ /// <returns>The new audio status.</returns>
+ uint8_t VolumeDown(bool sendRelease)
+ {
+ return m_libCec->VolumeDown(sendRelease);
+ }
+
+ /// <summary>
+ /// Sends a mute keypress to an audiosystem if it's present.
+ /// </summary>
+ /// <returns>The new audio status.</returns>
+ uint8_t MuteAudio()
+ {
+ return m_libCec->AudioToggleMute();
+ }
+
+ /// <summary>
+ /// Send a keypress to a device on the CEC bus.
+ /// </summary>
+ /// <param name="destination">The logical address of the device to send the message to.</param>
+ /// <param name="key">The key to send.</param>
+ /// <param name="wait">True to wait for a response, false otherwise.</param>
+ /// <returns>True when the keypress was acked, false otherwise.</returns>
+ bool SendKeypress(CecLogicalAddress destination, CecUserControlCode key, bool wait)
+ {
+ return m_libCec->SendKeypress((cec_logical_address)destination, (cec_user_control_code)key, wait);
+ }
+
+ /// <summary>
+ /// Send a key release to a device on the CEC bus.
+ /// </summary>
+ /// <param name="destination">The logical address of the device to send the message to.</param>
+ /// <param name="wait">True to wait for a response, false otherwise.</param>
+ /// <returns>True when the key release was acked, false otherwise.</returns>
+ bool SendKeyRelease(CecLogicalAddress destination, bool wait)
+ {
+ return m_libCec->SendKeyRelease((cec_logical_address)destination, wait);
+ }
+
+ /// <summary>
+ /// Get the OSD name of a device on the CEC bus.
+ /// </summary>
+ /// <param name="logicalAddress">The logical address of the device to get the OSD name for.</param>
+ /// <returns>The OSD name.</returns>
+ String ^ GetDeviceOSDName(CecLogicalAddress logicalAddress)
+ {
+ std::string osdName = m_libCec->GetDeviceOSDName((cec_logical_address) logicalAddress);
+ // we need to terminate with \0, and we only got 14 chars in osd.name
+ char strOsdName[15];
+ strncpy(strOsdName, osdName.c_str(), 15);
+ return gcnew String(strOsdName);
+ }
+
+ /// <summary>
+ /// Get the logical address of the device that is currently the active source on the CEC bus.
+ /// </summary>
+ /// <returns>The active source or CECDEVICE_UNKNOWN when unknown.</returns>
+ CecLogicalAddress GetActiveSource()
+ {
+ return (CecLogicalAddress)m_libCec->GetActiveSource();
+ }
+
+ /// <summary>
+ /// Check whether a device is currently the active source on the CEC bus.
+ /// </summary>
+ /// <param name="logicalAddress">The logical address of the device to check.</param>
+ /// <returns>True when it is the active source, false otherwise.</returns>
+ bool IsActiveSource(CecLogicalAddress logicalAddress)
+ {
+ return m_libCec->IsActiveSource((cec_logical_address)logicalAddress);
+ }
+
+ /// <summary>
+ /// Get the physical address of the device with the given logical address.
+ /// </summary>
+ /// <param name="address">The logical address of the device to get the physical address for.</param>
+ /// <returns>The physical address or 0 if it wasn't found.</returns>
+ uint16_t GetDevicePhysicalAddress(CecLogicalAddress address)
+ {
+ return m_libCec->GetDevicePhysicalAddress((cec_logical_address)address);
+ }
+
+ /// <summary>
+ /// Sets the stream path to the device on the given logical address.
+ /// </summary>
+ /// <param name="address">The address to activate.</param>
+ /// <returns>True when the command was sent, false otherwise.</returns>
+ bool SetStreamPath(CecLogicalAddress address)
+ {
+ return m_libCec->SetStreamPath((cec_logical_address)address);
+ }
+
+ /// <summary>
+ /// Sets the stream path to the device on the given physical address.
+ /// </summary>
+ /// <param name="physicalAddress">The address to activate.</param>
+ /// <returns>True when the command was sent, false otherwise.</returns>
+ bool SetStreamPath(uint16_t physicalAddress)
+ {
+ return m_libCec->SetStreamPath(physicalAddress);
+ }
+
+ /// <summary>
+ /// Get the list of logical addresses that libCEC is controlling
+ /// </summary>
+ /// <returns>The list of logical addresses that libCEC is controlling</returns>
+ CecLogicalAddresses ^GetLogicalAddresses(void)
+ {
+ CecLogicalAddresses ^addr = gcnew CecLogicalAddresses();
+ cec_logical_addresses libAddr = m_libCec->GetLogicalAddresses();
+ for (unsigned int iPtr = 0; iPtr < 16; iPtr++)
+ addr->Addresses[iPtr] = (CecLogicalAddress)libAddr.addresses[iPtr];
+ addr->Primary = (CecLogicalAddress)libAddr.primary;
+ return addr;
+ }
+
+ /// <summary>
+ /// Get libCEC's current configuration.
+ /// </summary>
+ /// <param name="configuration">The configuration.</param>
+ /// <returns>True when the configuration was updated, false otherwise.</returns>
+ bool GetCurrentConfiguration(LibCECConfiguration ^configuration)
+ {
+ libcec_configuration config;
+ config.Clear();
+
+ if (m_libCec->GetCurrentConfiguration(&config))
+ {
+ configuration->Update(config);
+ return true;
+ }
+ return false;
+ }
+
+ /// <summary>
+ /// Check whether the CEC adapter can persist a configuration.
+ /// </summary>
+ /// <returns>True when this CEC adapter can persist the user configuration, false otherwise.</returns>
+ bool CanPersistConfiguration(void)
+ {
+ return m_libCec->CanPersistConfiguration();
+ }
+
+ /// <summary>
+ /// Persist the given configuration in adapter (if supported)
+ /// </summary>
+ /// <param name="configuration">The configuration to store.</param>
+ /// <returns>True when the configuration was persisted, false otherwise.</returns>
+ bool PersistConfiguration(LibCECConfiguration ^configuration)
+ {
+ marshal_context ^ context = gcnew marshal_context();
+ libcec_configuration config;
+ ConvertConfiguration(context, configuration, config);
+
+ bool bReturn = m_libCec->PersistConfiguration(&config);
+
+ delete context;
+ return bReturn;
+ }
+
+ /// <summary>
+ /// Change libCEC's configuration.
+ /// </summary>
+ /// <param name="configuration">The new configuration.</param>
+ /// <returns>True when the configuration was changed successfully, false otherwise.</returns>
+ bool SetConfiguration(LibCECConfiguration ^configuration)
+ {
+ marshal_context ^ context = gcnew marshal_context();
+ libcec_configuration config;
+ ConvertConfiguration(context, configuration, config);
+
+ bool bReturn = m_libCec->SetConfiguration(&config);
+
+ delete context;
+ return bReturn;
+ }
+
+ /// <summary>
+ /// Check whether libCEC is the active source on the bus.
+ /// </summary>
+ /// <returns>True when libCEC is the active source on the bus, false otherwise.</returns>
+ bool IsLibCECActiveSource()
+ {
+ return m_libCec->IsLibCECActiveSource();
+ }
+
+ /// <summary>
+ /// Get information about the given CEC adapter.
+ /// </summary>
+ /// <param name="port">The COM port to which the device is connected</param>
+ /// <param name="configuration">The device configuration</param>
+ /// <param name="timeoutMs">The timeout in milliseconds</param>
+ /// <returns>True when the device was found, false otherwise</returns>
+ bool GetDeviceInformation(String ^ port, LibCECConfiguration ^configuration, uint32_t timeoutMs)
+ {
+ bool bReturn(false);
+ marshal_context ^ context = gcnew marshal_context();
+
+ libcec_configuration config;
+ config.Clear();
+
+ const char* strPortC = port->Length > 0 ? context->marshal_as<const char*>(port) : NULL;
+
+ if (m_libCec->GetDeviceInformation(strPortC, &config, timeoutMs))
+ {
+ configuration->Update(config);
+ bReturn = true;
+ }
+
+ delete context;
+ return bReturn;
+ }
+
+ String ^ ToString(CecLogicalAddress iAddress)
+ {
+ const char *retVal = m_libCec->ToString((cec_logical_address)iAddress);
+ return gcnew String(retVal);
+ }
+
+ String ^ ToString(CecVendorId iVendorId)
+ {
+ const char *retVal = m_libCec->ToString((cec_vendor_id)iVendorId);
+ return gcnew String(retVal);
+ }
+
+ String ^ ToString(CecVersion iVersion)
+ {
+ const char *retVal = m_libCec->ToString((cec_version)iVersion);
+ return gcnew String(retVal);
+ }
+
+ String ^ ToString(CecPowerStatus iState)
+ {
+ const char *retVal = m_libCec->ToString((cec_power_status)iState);
+ return gcnew String(retVal);
+ }
+
+ String ^ ToString(CecMenuState iState)
+ {
+ const char *retVal = m_libCec->ToString((cec_menu_state)iState);
+ return gcnew String(retVal);
+ }
+
+ String ^ ToString(CecDeckControlMode iMode)
+ {
+ const char *retVal = m_libCec->ToString((cec_deck_control_mode)iMode);
+ return gcnew String(retVal);
+ }
+
+ String ^ ToString(CecDeckInfo status)
+ {
+ const char *retVal = m_libCec->ToString((cec_deck_info)status);
+ return gcnew String(retVal);
+ }
+
+ String ^ ToString(CecOpcode opcode)
+ {
+ const char *retVal = m_libCec->ToString((cec_opcode)opcode);
+ return gcnew String(retVal);
+ }
+
+ String ^ ToString(CecSystemAudioStatus mode)
+ {
+ const char *retVal = m_libCec->ToString((cec_system_audio_status)mode);
+ return gcnew String(retVal);
+ }
+
+ String ^ ToString(CecAudioStatus status)
+ {
+ const char *retVal = m_libCec->ToString((cec_audio_status)status);
+ return gcnew String(retVal);
+ }
+
+ String ^ VersionToString(uint32_t version)
+ {
+ char buf[20];
+ m_libCec->PrintVersion(version, buf, 20);
+ return gcnew String(buf);
+ }
+
+ String ^ PhysicalAddressToString(uint16_t physicalAddress)
+ {
+ char buf[8];
+ snprintf(buf, 8, "%X.%X.%X.%X", (physicalAddress >> 12) & 0xF, (physicalAddress >> 8) & 0xF, (physicalAddress >> 4) & 0xF, physicalAddress & 0xF);
+ return gcnew String(buf);
+ }
+
+ /// <summary>
+ /// Get a string with information about how libCEC was compiled.
+ /// </summary>
+ /// <returns>A string with information about how libCEC was compiled.</returns>
+ String ^ GetLibInfo()
+ {
+ const char *retVal = m_libCec->GetLibInfo();
+ return gcnew String(retVal);
+ }
+
+ /// <summary>
+ /// Calling this method will initialise the host on which libCEC is running.
+ /// On the RPi, it calls bcm_host_init(), which may only be called once per process, and is called by any process using
+ /// the video api on that system. So only call this method if libCEC is used in an application that
+ /// does not already initialise the video api.
+ /// </summary>
+ /// <remarks>Should be called as first call to libCEC, directly after CECInitialise() and before using Open()</remarks>
+ void InitVideoStandalone()
+ {
+ m_libCec->InitVideoStandalone();
+ }
+
+ /// <summary>
+ /// Get the (virtual) USB vendor id
+ /// </summary>
+ /// <returns>The (virtual) USB vendor id</returns>
+ uint16_t GetAdapterVendorId()
+ {
+ return m_libCec->GetAdapterVendorId();
+ }
+
+ /// <summary>
+ /// Get the (virtual) USB product id
+ /// </summary>
+ /// <returns>The (virtual) USB product id</returns>
+ uint16_t GetAdapterProductId()
+ {
+ return m_libCec->GetAdapterProductId();
+ }
+
+ private:
+ !LibCecSharp(void)
+ {
+ Close();
+ m_libCec = NULL;
+ }
+
+ bool InitialiseLibCec(LibCECConfiguration ^config)
+ {
+ marshal_context ^ context = gcnew marshal_context();
+ libcec_configuration libCecConfig;
+ ConvertConfiguration(context, config, libCecConfig);
+
+ m_libCec = (ICECAdapter *) CECInitialise(&libCecConfig);
+ config->Update(libCecConfig);
+
+ delete context;
+ return m_libCec != NULL;
+ }
+
+ void ConvertConfiguration(marshal_context ^context, LibCECConfiguration ^netConfig, CEC::libcec_configuration &config)
+ {
+ config.Clear();
+
+ const char *strDeviceName = context->marshal_as<const char*>(netConfig->DeviceName);
+ memcpy_s(config.strDeviceName, 13, strDeviceName, 13);
+ for (unsigned int iPtr = 0; iPtr < 5; iPtr++)
+ config.deviceTypes.types[iPtr] = (cec_device_type)netConfig->DeviceTypes->Types[iPtr];
+
+ config.bAutodetectAddress = netConfig->AutodetectAddress ? 1 : 0;
+ config.iPhysicalAddress = netConfig->PhysicalAddress;
+ config.baseDevice = (cec_logical_address)netConfig->BaseDevice;
+ config.iHDMIPort = netConfig->HDMIPort;
+ config.clientVersion = netConfig->ClientVersion;
+ config.bGetSettingsFromROM = netConfig->GetSettingsFromROM ? 1 : 0;
+ config.bActivateSource = netConfig->ActivateSource ? 1 : 0;
+ config.tvVendor = (cec_vendor_id)netConfig->TvVendor;
+ config.wakeDevices.Clear();
+ for (int iPtr = 0; iPtr < 16; iPtr++)
+ {
+ if (netConfig->WakeDevices->IsSet((CecLogicalAddress)iPtr))
+ config.wakeDevices.Set((cec_logical_address)iPtr);
+ }
+ config.powerOffDevices.Clear();
+ for (int iPtr = 0; iPtr < 16; iPtr++)
+ {
+ if (netConfig->PowerOffDevices->IsSet((CecLogicalAddress)iPtr))
+ config.powerOffDevices.Set((cec_logical_address)iPtr);
+ }
+ config.bPowerOffOnStandby = netConfig->PowerOffOnStandby ? 1 : 0;
+ const char *strDeviceLanguage = context->marshal_as<const char*>(netConfig->DeviceLanguage);
+ memcpy_s(config.strDeviceLanguage, 3, strDeviceLanguage, 3);
+ config.bMonitorOnly = netConfig->MonitorOnlyClient ? 1 : 0;
+ config.cecVersion = (cec_version)netConfig->CECVersion;
+ config.callbacks = &g_cecCallbacks;
+ }
+
+
+ ICECAdapter * m_libCec;
+ CecCallbackMethods ^ m_callbacks;
+ };
+}
--- /dev/null
+project(cecclient)
+cmake_minimum_required(VERSION 2.8.9)
+
+set(cecclient_NAME cecclient)
+set(cecclient_DESCRIPTION "libCEC test client")
+set(cecclient_VERSION_MAJOR ${LIBCEC_VERSION_MAJOR})
+set(cecclient_VERSION_MINOR ${LIBCEC_VERSION_MINOR})
+set(cecclient_VERSION_PATCH ${LIBCEC_VERSION_PATCH})
+
+enable_language(CXX)
+include(CheckCXXSourceCompiles)
+include(CheckLibraryExists)
+include(CheckIncludeFiles)
+include(CheckCXXCompilerFlag)
+
+check_cxx_compiler_flag("-std=c++11" SUPPORTS_CXX11)
+if (SUPPORTS_CXX11)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
+endif()
+
+find_package(p8-platform REQUIRED)
+find_package(Threads REQUIRED)
+
+set(cecclient_SOURCES cec-client.cpp)
+
+# curses
+check_library_exists(curses initscr "" HAVE_CURSES_API)
+if (HAVE_CURSES_API)
+ list(APPEND cecclient_SOURCES curses/CursesControl.cpp)
+endif()
+
+add_executable(cec-client ${cecclient_SOURCES})
+set_target_properties(cec-client PROPERTIES VERSION ${LIBCEC_VERSION_MAJOR}.${LIBCEC_VERSION_MINOR}.${LIBCEC_VERSION_PATCH})
+target_link_libraries(cec-client ${p8-platform_LIBRARIES})
+target_link_libraries(cec-client ${CMAKE_THREAD_LIBS_INIT})
+
+if (NOT WIN32)
+ # check for dlopen
+ check_library_exists(dl dlopen "" HAVE_DLOPEN)
+ if (HAVE_DLOPEN)
+ target_link_libraries(cec-client dl)
+ endif()
+
+ # curses
+ if (HAVE_CURSES_API)
+ target_link_libraries(cec-client curses)
+ endif()
+
+ # rt
+ check_library_exists(rt clock_gettime "" HAVE_RT)
+ if (HAVE_RT)
+ target_link_libraries(cec-client rt)
+ endif()
+
+ # CoreVideo
+ if (APPLE)
+ target_link_libraries(cec-client "-framework CoreVideo")
+ endif()
+else()
+ add_definitions(-DTARGET_WINDOWS -DNOMINMAX -D_CRT_SECURE_NO_WARNINGS -D_WINSOCKAPI_)
+ if (NOT ${WIN64})
+ add_definitions(-D_USE_32BIT_TIME_T)
+ endif()
+endif()
+
+include_directories(${p8-platform_INCLUDE_DIRS}
+ ${PROJECT_SOURCE_DIR}
+ ${PROJECT_SOURCE_DIR}/../../include)
+
+# write env.h
+CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/env.h.in ${CMAKE_CURRENT_SOURCE_DIR}/env.h)
+
+if (WIN32)
+ install(TARGETS cec-client
+ DESTINATION .)
+else()
+ install(TARGETS cec-client
+ DESTINATION bin/.)
+endif()
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include "cec.h"
+
+#include <cstdio>
+#include <fcntl.h>
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <sstream>
+#include <signal.h>
+#include <stdlib.h>
+#include <p8-platform/os.h>
+#include <p8-platform/util/StringUtils.h>
+#include <p8-platform/threads/threads.h>
+#if defined(HAVE_CURSES_API)
+ #include "curses/CursesControl.h"
+#endif
+
+using namespace CEC;
+using namespace P8PLATFORM;
+
+#include "cecloader.h"
+
+static void PrintToStdOut(const char *strFormat, ...);
+
+ICECCallbacks g_callbacks;
+libcec_configuration g_config;
+int g_cecLogLevel(-1);
+int g_cecDefaultLogLevel(CEC_LOG_ALL);
+std::ofstream g_logOutput;
+bool g_bShortLog(false);
+std::string g_strPort;
+bool g_bSingleCommand(false);
+bool g_bExit(false);
+bool g_bHardExit(false);
+CMutex g_outputMutex;
+ICECAdapter* g_parser;
+#if defined(HAVE_CURSES_API)
+bool g_cursesEnable(false);
+CCursesControl g_cursesControl("1", "0");
+#endif
+
+class CReconnect : public P8PLATFORM::CThread
+{
+public:
+ static CReconnect& Get(void)
+ {
+ static CReconnect _instance;
+ return _instance;
+ }
+
+ virtual ~CReconnect(void) {}
+
+ void* Process(void)
+ {
+ if (g_parser)
+ {
+ g_parser->Close();
+ if (!g_parser->Open(g_strPort.c_str()))
+ {
+ PrintToStdOut("Failed to reconnect\n");
+ g_bExit = true;
+ }
+ }
+ return NULL;
+ }
+
+private:
+ CReconnect(void) {}
+};
+
+static void PrintToStdOut(const char *strFormat, ...)
+{
+ std::string strLog;
+
+ va_list argList;
+ va_start(argList, strFormat);
+ strLog = StringUtils::FormatV(strFormat, argList);
+ va_end(argList);
+
+ CLockObject lock(g_outputMutex);
+ std::cout << strLog << std::endl;
+}
+
+inline bool HexStrToInt(const std::string& data, uint8_t& value)
+{
+ int iTmp(0);
+ if (sscanf(data.c_str(), "%x", &iTmp) == 1)
+ {
+ if (iTmp > 256)
+ value = 255;
+ else if (iTmp < 0)
+ value = 0;
+ else
+ value = (uint8_t) iTmp;
+
+ return true;
+ }
+
+ return false;
+}
+
+//get the first word (separated by whitespace) from string data and place that in word
+//then remove that word from string data
+bool GetWord(std::string& data, std::string& word)
+{
+ std::stringstream datastream(data);
+ std::string end;
+
+ datastream >> word;
+ if (datastream.fail())
+ {
+ data.clear();
+ return false;
+ }
+
+ size_t pos = data.find(word) + word.length();
+
+ if (pos >= data.length())
+ {
+ data.clear();
+ return true;
+ }
+
+ data = data.substr(pos);
+
+ datastream.clear();
+ datastream.str(data);
+
+ datastream >> end;
+ if (datastream.fail())
+ data.clear();
+
+ return true;
+}
+
+void CecLogMessage(void *UNUSED(cbParam), const cec_log_message* message)
+{
+ if ((message->level & g_cecLogLevel) == message->level)
+ {
+ std::string strLevel;
+ switch (message->level)
+ {
+ case CEC_LOG_ERROR:
+ strLevel = "ERROR: ";
+ break;
+ case CEC_LOG_WARNING:
+ strLevel = "WARNING: ";
+ break;
+ case CEC_LOG_NOTICE:
+ strLevel = "NOTICE: ";
+ break;
+ case CEC_LOG_TRAFFIC:
+ strLevel = "TRAFFIC: ";
+ break;
+ case CEC_LOG_DEBUG:
+ strLevel = "DEBUG: ";
+ break;
+ default:
+ break;
+ }
+
+ std::string strFullLog;
+ strFullLog = StringUtils::Format("%s[%16lld]\t%s", strLevel.c_str(), message->time, message->message);
+ PrintToStdOut(strFullLog.c_str());
+
+ if (g_logOutput.is_open())
+ {
+ if (g_bShortLog)
+ g_logOutput << message->message << std::endl;
+ else
+ g_logOutput << strFullLog.c_str() << std::endl;
+ }
+ }
+}
+
+void CecKeyPress(void *UNUSED(cbParam), const cec_keypress* UNUSED(key))
+{
+}
+
+void CecCommand(void *UNUSED(cbParam), const cec_command* UNUSED(command))
+{
+}
+
+void CecAlert(void *UNUSED(cbParam), const libcec_alert type, const libcec_parameter UNUSED(param))
+{
+ switch (type)
+ {
+ case CEC_ALERT_CONNECTION_LOST:
+ if (!CReconnect::Get().IsRunning())
+ {
+ PrintToStdOut("Connection lost - trying to reconnect\n");
+ CReconnect::Get().CreateThread(false);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void ListDevices(ICECAdapter *parser)
+{
+ cec_adapter_descriptor devices[10];
+ std::string strMessage = StringUtils::Format("libCEC version: %s, %s",
+ parser->VersionToString(g_config.serverVersion).c_str(),
+ parser->GetLibInfo());
+ PrintToStdOut(strMessage.c_str());
+
+ int8_t iDevicesFound = parser->DetectAdapters(devices, 10, NULL);
+ if (iDevicesFound <= 0)
+ {
+ PrintToStdOut("Found devices: NONE");
+ }
+ else
+ {
+ PrintToStdOut("Found devices: %d\n", iDevicesFound);
+
+ for (int8_t iDevicePtr = 0; iDevicePtr < iDevicesFound; iDevicePtr++)
+ {
+ PrintToStdOut("device: %d", iDevicePtr + 1);
+ PrintToStdOut("com port: %s", devices[iDevicePtr].strComName);
+ PrintToStdOut("vendor id: %04x", devices[iDevicePtr].iVendorId);
+ PrintToStdOut("product id: %04x", devices[iDevicePtr].iProductId);
+ PrintToStdOut("firmware version: %d", devices[iDevicePtr].iFirmwareVersion);
+
+ if (devices[iDevicePtr].iFirmwareBuildDate != CEC_FW_BUILD_UNKNOWN)
+ {
+ time_t buildTime = (time_t)devices[iDevicePtr].iFirmwareBuildDate;
+ std::string strDeviceInfo;
+ strDeviceInfo = StringUtils::Format("firmware build date: %s", asctime(gmtime(&buildTime)));
+ strDeviceInfo = StringUtils::Left(strDeviceInfo, strDeviceInfo.length() > 1 ? (unsigned)(strDeviceInfo.length() - 1) : 0); // strip \n added by asctime
+ strDeviceInfo.append(" +0000");
+ PrintToStdOut(strDeviceInfo.c_str());
+ }
+
+ if (devices[iDevicePtr].adapterType != ADAPTERTYPE_UNKNOWN)
+ {
+ PrintToStdOut("type: %s", parser->ToString(devices[iDevicePtr].adapterType));
+ }
+
+ PrintToStdOut("");
+ }
+ }
+}
+
+void ShowHelpCommandLine(const char* strExec)
+{
+ CLockObject lock(g_outputMutex);
+ std::cout << std::endl <<
+ strExec << " {-h|--help|-l|--list-devices|[COM PORT]}" << std::endl <<
+ std::endl <<
+ "parameters:" << std::endl <<
+ " -h --help Shows this help text" << std::endl <<
+ " -l --list-devices List all devices on this system" << std::endl <<
+ " -t --type {p|r|t|a} The device type to use. More than one is possible." << std::endl <<
+ " -p --port {int} The HDMI port to use as active source." << std::endl <<
+ " -b --base {int} The logical address of the device to which this " << std::endl <<
+ " adapter is connected." << std::endl <<
+ " -f --log-file {file} Writes all libCEC log message to a file" << std::endl <<
+ " -r --rom Read persisted settings from the EEPROM" << std::endl <<
+ " -sf --short-log-file {file} Writes all libCEC log message without timestamps" << std::endl <<
+ " and log levels to a file." << std::endl <<
+ " -d --log-level {level} Sets the log level. See cectypes.h for values." << std::endl <<
+ " -s --single-command Execute a single command and exit. Does not power" << std::endl <<
+ " on devices on startup and power them off on exit." << std::endl <<
+ " -o --osd-name {osd name} Use a custom osd name." << std::endl <<
+ " -m --monitor Start a monitor-only client." << std::endl <<
+ " -i --info Shows information about how libCEC was compiled." << std::endl <<
+ " [COM PORT] The com port to connect to. If no COM" << std::endl <<
+ " port is given, the client tries to connect to the" << std::endl <<
+ " first device that is detected." << std::endl <<
+ std::endl <<
+ "Type 'h' or 'help' and press enter after starting the client to display all " << std::endl <<
+ "available commands" << std::endl;
+}
+
+void ShowHelpConsole(void)
+{
+ CLockObject lock(g_outputMutex);
+ std::cout << std::endl <<
+ "================================================================================" << std::endl <<
+ "Available commands:" << std::endl <<
+ std::endl <<
+ "[tx] {bytes} transfer bytes over the CEC line." << std::endl <<
+ "[txn] {bytes} transfer bytes but don't wait for transmission ACK." << std::endl <<
+ "[on] {address} power on the device with the given logical address." << std::endl <<
+ "[standby] {address} put the device with the given address in standby mode." << std::endl <<
+ "[la] {logical address} change the logical address of the CEC adapter." << std::endl <<
+ "[p] {device} {port} change the HDMI port number of the CEC adapter." << std::endl <<
+ "[pa] {physical address} change the physical address of the CEC adapter." << std::endl <<
+ "[as] make the CEC adapter the active source." << std::endl <<
+ "[is] mark the CEC adapter as inactive source." << std::endl <<
+ "[osd] {addr} {string} set OSD message on the specified device." << std::endl <<
+ "[ver] {addr} get the CEC version of the specified device." << std::endl <<
+ "[ven] {addr} get the vendor ID of the specified device." << std::endl <<
+ "[lang] {addr} get the menu language of the specified device." << std::endl <<
+ "[pow] {addr} get the power status of the specified device." << std::endl <<
+ "[name] {addr} get the OSD name of the specified device." << std::endl <<
+ "[poll] {addr} poll the specified device." << std::endl <<
+ "[lad] lists active devices on the bus" << std::endl <<
+ "[ad] {addr} checks whether the specified device is active." << std::endl <<
+ "[at] {type} checks whether the specified device type is active." << std::endl <<
+ "[sp] {addr} makes the specified physical address active." << std::endl <<
+ "[spl] {addr} makes the specified logical address active." << std::endl <<
+ "[volup] send a volume up command to the amp if present" << std::endl <<
+ "[voldown] send a volume down command to the amp if present" << std::endl <<
+ "[mute] send a mute/unmute command to the amp if present" << std::endl <<
+ "[self] show the list of addresses controlled by libCEC" << std::endl <<
+ "[scan] scan the CEC bus and display device info" << std::endl <<
+ "[mon] {1|0} enable or disable CEC bus monitoring." << std::endl <<
+ "[log] {1 - 31} change the log level. see cectypes.h for values." << std::endl <<
+ "[ping] send a ping command to the CEC adapter." << std::endl <<
+ "[bl] to let the adapter enter the bootloader, to upgrade" << std::endl <<
+ " the flash rom." << std::endl <<
+ "[r] reconnect to the CEC adapter." << std::endl <<
+ "[h] or [help] show this help." << std::endl <<
+ "[q] or [quit] to quit the CEC test client and switch off all" << std::endl <<
+ " connected CEC devices." << std::endl <<
+ "================================================================================" << std::endl;
+}
+
+bool ProcessCommandSELF(ICECAdapter *parser, const std::string &command, std::string & UNUSED(arguments))
+{
+ if (command == "self")
+ {
+ cec_logical_addresses addr = parser->GetLogicalAddresses();
+ std::string strOut = "Addresses controlled by libCEC: ";
+ bool bFirst(true);
+ for (uint8_t iPtr = 0; iPtr <= 15; iPtr++)
+ {
+ if (addr[iPtr])
+ {
+ strOut += StringUtils::Format((bFirst ? "%d%s" : ", %d%s"), iPtr, parser->IsActiveSource((cec_logical_address)iPtr) ? "*" : "");
+ bFirst = false;
+ }
+ }
+ PrintToStdOut(strOut.c_str());
+ return true;
+ }
+
+ return false;
+}
+
+bool ProcessCommandSP(ICECAdapter *parser, const std::string &command, std::string &arguments)
+{
+ if (command == "sp")
+ {
+ std::string strAddress;
+ int iAddress;
+ if (GetWord(arguments, strAddress))
+ {
+ sscanf(strAddress.c_str(), "%x", &iAddress);
+ if (iAddress >= 0 && iAddress <= CEC_INVALID_PHYSICAL_ADDRESS)
+ parser->SetStreamPath((uint16_t)iAddress);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool ProcessCommandSPL(ICECAdapter *parser, const std::string &command, std::string &arguments)
+{
+ if (command == "spl")
+ {
+ std::string strAddress;
+ cec_logical_address iAddress;
+ if (GetWord(arguments, strAddress))
+ {
+ iAddress = (cec_logical_address)atoi(strAddress.c_str());
+ if (iAddress >= CECDEVICE_TV && iAddress < CECDEVICE_BROADCAST)
+ parser->SetStreamPath(iAddress);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool ProcessCommandTX(ICECAdapter *parser, const std::string &command, std::string &arguments)
+{
+ if (command == "tx" || command == "txn")
+ {
+ std::string strvalue;
+ cec_command bytes = parser->CommandFromString(arguments.c_str());
+
+ if (command == "txn")
+ bytes.transmit_timeout = 0;
+
+ parser->Transmit(bytes);
+
+ return true;
+ }
+
+ return false;
+}
+
+bool ProcessCommandON(ICECAdapter *parser, const std::string &command, std::string &arguments)
+{
+ if (command == "on")
+ {
+ std::string strValue;
+ uint8_t iValue = 0;
+ if (GetWord(arguments, strValue) && HexStrToInt(strValue, iValue) && iValue <= 0xF)
+ {
+ parser->PowerOnDevices((cec_logical_address) iValue);
+ return true;
+ }
+ else
+ {
+ PrintToStdOut("invalid destination");
+ }
+ }
+
+ return false;
+}
+
+bool ProcessCommandSTANDBY(ICECAdapter *parser, const std::string &command, std::string &arguments)
+{
+ if (command == "standby")
+ {
+ std::string strValue;
+ uint8_t iValue = 0;
+ if (GetWord(arguments, strValue) && HexStrToInt(strValue, iValue) && iValue <= 0xF)
+ {
+ parser->StandbyDevices((cec_logical_address) iValue);
+ return true;
+ }
+ else
+ {
+ PrintToStdOut("invalid destination");
+ }
+ }
+
+ return false;
+}
+
+bool ProcessCommandPOLL(ICECAdapter *parser, const std::string &command, std::string &arguments)
+{
+ if (command == "poll")
+ {
+ std::string strValue;
+ uint8_t iValue = 0;
+ if (GetWord(arguments, strValue) && HexStrToInt(strValue, iValue) && iValue <= 0xF)
+ {
+ if (parser->PollDevice((cec_logical_address) iValue))
+ PrintToStdOut("POLL message sent");
+ else
+ PrintToStdOut("POLL message not sent");
+ return true;
+ }
+ else
+ {
+ PrintToStdOut("invalid destination");
+ }
+ }
+
+ return false;
+}
+
+bool ProcessCommandLA(ICECAdapter *parser, const std::string &command, std::string &arguments)
+{
+ if (command == "la")
+ {
+ std::string strvalue;
+ if (GetWord(arguments, strvalue))
+ {
+ parser->SetLogicalAddress((cec_logical_address) atoi(strvalue.c_str()));
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool ProcessCommandP(ICECAdapter *parser, const std::string &command, std::string &arguments)
+{
+ if (command == "p")
+ {
+ std::string strPort, strDevice;
+ if (GetWord(arguments, strDevice) && GetWord(arguments, strPort))
+ {
+ parser->SetHDMIPort((cec_logical_address)atoi(strDevice.c_str()), (uint8_t)atoi(strPort.c_str()));
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool ProcessCommandPA(ICECAdapter *parser, const std::string &command, std::string &arguments)
+{
+ if (command == "pa")
+ {
+ std::string strB1, strB2;
+ uint8_t iB1, iB2;
+ if (GetWord(arguments, strB1) && HexStrToInt(strB1, iB1) &&
+ GetWord(arguments, strB2) && HexStrToInt(strB2, iB2))
+ {
+ uint16_t iPhysicalAddress = ((uint16_t)iB1 << 8) + iB2;
+ parser->SetPhysicalAddress(iPhysicalAddress);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool ProcessCommandOSD(ICECAdapter *parser, const std::string &command, std::string &arguments)
+{
+ if (command == "osd")
+ {
+ bool bFirstWord(false);
+ std::string strAddr, strMessage, strWord;
+ uint8_t iAddr;
+ if (GetWord(arguments, strAddr) && HexStrToInt(strAddr, iAddr) && iAddr < 0xF)
+ {
+ while (GetWord(arguments, strWord))
+ {
+ if (bFirstWord)
+ {
+ bFirstWord = false;
+ strMessage.append(" ");
+ }
+ strMessage.append(strWord);
+ }
+ parser->SetOSDString((cec_logical_address) iAddr, CEC_DISPLAY_CONTROL_DISPLAY_FOR_DEFAULT_TIME, strMessage.c_str());
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool ProcessCommandAS(ICECAdapter *parser, const std::string &command, std::string & UNUSED(arguments))
+{
+ if (command == "as")
+ {
+ parser->SetActiveSource();
+ // wait for the source switch to finish for 15 seconds tops
+ if (g_bSingleCommand)
+ {
+ CTimeout timeout(15000);
+ bool bActiveSource(false);
+ while (timeout.TimeLeft() > 0 && !bActiveSource)
+ {
+ bActiveSource = parser->IsLibCECActiveSource();
+ if (!bActiveSource)
+ CEvent::Sleep(100);
+ }
+ }
+ return true;
+ }
+
+ return false;
+}
+
+bool ProcessCommandIS(ICECAdapter *parser, const std::string &command, std::string & UNUSED(arguments))
+{
+ if (command == "is")
+ return parser->SetInactiveView();
+
+ return false;
+}
+
+bool ProcessCommandPING(ICECAdapter *parser, const std::string &command, std::string & UNUSED(arguments))
+{
+ if (command == "ping")
+ {
+ parser->PingAdapter();
+ return true;
+ }
+
+ return false;
+}
+
+bool ProcessCommandVOLUP(ICECAdapter *parser, const std::string &command, std::string & UNUSED(arguments))
+{
+ if (command == "volup")
+ {
+ PrintToStdOut("volume up: %2X", parser->VolumeUp());
+ return true;
+ }
+
+ return false;
+}
+
+bool ProcessCommandVOLDOWN(ICECAdapter *parser, const std::string &command, std::string & UNUSED(arguments))
+{
+ if (command == "voldown")
+ {
+ PrintToStdOut("volume down: %2X", parser->VolumeDown());
+ return true;
+ }
+
+ return false;
+}
+
+bool ProcessCommandMUTE(ICECAdapter *parser, const std::string &command, std::string & UNUSED(arguments))
+{
+ if (command == "mute")
+ {
+ PrintToStdOut("mute: %2X", parser->AudioToggleMute());
+ return true;
+ }
+
+ return false;
+}
+
+bool ProcessCommandMON(ICECAdapter *parser, const std::string &command, std::string &arguments)
+{
+ if (command == "mon")
+ {
+ std::string strEnable;
+ if (GetWord(arguments, strEnable) && (strEnable == "0" || strEnable == "1"))
+ {
+ parser->SwitchMonitoring(strEnable == "1");
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool ProcessCommandBL(ICECAdapter *parser, const std::string &command, std::string & UNUSED(arguments))
+{
+ if (command == "bl")
+ {
+ if (parser->StartBootloader())
+ {
+ PrintToStdOut("entered bootloader mode. exiting cec-client");
+ g_bExit = true;
+ g_bHardExit = true;
+ }
+ return true;
+ }
+
+ return false;
+}
+
+bool ProcessCommandLANG(ICECAdapter *parser, const std::string &command, std::string &arguments)
+{
+ if (command == "lang")
+ {
+ std::string strDev;
+ if (GetWord(arguments, strDev))
+ {
+ int iDev = atoi(strDev.c_str());
+ if (iDev >= 0 && iDev < 15)
+ {
+ std::string strLog;
+ strLog = StringUtils::Format("menu language '%s'", parser->GetDeviceMenuLanguage((cec_logical_address)iDev).c_str());
+ PrintToStdOut(strLog.c_str());
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool ProcessCommandVEN(ICECAdapter *parser, const std::string &command, std::string &arguments)
+{
+ if (command == "ven")
+ {
+ std::string strDev;
+ if (GetWord(arguments, strDev))
+ {
+ int iDev = atoi(strDev.c_str());
+ if (iDev >= 0 && iDev < 15)
+ {
+ uint64_t iVendor = parser->GetDeviceVendorId((cec_logical_address) iDev);
+ PrintToStdOut("vendor id: %06llx", iVendor);
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool ProcessCommandVER(ICECAdapter *parser, const std::string &command, std::string &arguments)
+{
+ if (command == "ver")
+ {
+ std::string strDev;
+ if (GetWord(arguments, strDev))
+ {
+ int iDev = atoi(strDev.c_str());
+ if (iDev >= 0 && iDev < 15)
+ {
+ cec_version iVersion = parser->GetDeviceCecVersion((cec_logical_address) iDev);
+ PrintToStdOut("CEC version %s", parser->ToString(iVersion));
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool ProcessCommandPOW(ICECAdapter *parser, const std::string &command, std::string &arguments)
+{
+ if (command == "pow")
+ {
+ std::string strDev;
+ if (GetWord(arguments, strDev))
+ {
+ int iDev = atoi(strDev.c_str());
+ if (iDev >= 0 && iDev < 15)
+ {
+ cec_power_status iPower = parser->GetDevicePowerStatus((cec_logical_address) iDev);
+ PrintToStdOut("power status: %s", parser->ToString(iPower));
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool ProcessCommandNAME(ICECAdapter *parser, const std::string &command, std::string &arguments)
+{
+ if (command == "name")
+ {
+ std::string strDev;
+ if (GetWord(arguments, strDev))
+ {
+ int iDev = atoi(strDev.c_str());
+ if (iDev >= 0 && iDev < 15)
+ {
+ std::string name = parser->GetDeviceOSDName((cec_logical_address)iDev);
+ PrintToStdOut("OSD name of device %d is '%s'", iDev, name.c_str());
+ }
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool ProcessCommandLAD(ICECAdapter *parser, const std::string &command, std::string & UNUSED(arguments))
+{
+ if (command == "lad")
+ {
+ PrintToStdOut("listing active devices:");
+ cec_logical_addresses addresses = parser->GetActiveDevices();
+ for (uint8_t iPtr = 0; iPtr <= 11; iPtr++)
+ if (addresses[iPtr])
+ {
+ PrintToStdOut("logical address %X", (int)iPtr);
+ }
+ return true;
+ }
+
+ return false;
+}
+
+bool ProcessCommandAD(ICECAdapter *parser, const std::string &command, std::string &arguments)
+{
+ if (command == "ad")
+ {
+ std::string strDev;
+ if (GetWord(arguments, strDev))
+ {
+ int iDev = atoi(strDev.c_str());
+ if (iDev >= 0 && iDev < 15)
+ PrintToStdOut("logical address %X is %s", iDev, (parser->IsActiveDevice((cec_logical_address)iDev) ? "active" : "not active"));
+ }
+ }
+
+ return false;
+}
+
+bool ProcessCommandAT(ICECAdapter *parser, const std::string &command, std::string &arguments)
+{
+ if (command == "at")
+ {
+ std::string strType;
+ if (GetWord(arguments, strType))
+ {
+ cec_device_type type = CEC_DEVICE_TYPE_TV;
+ if (strType == "a")
+ type = CEC_DEVICE_TYPE_AUDIO_SYSTEM;
+ else if (strType == "p")
+ type = CEC_DEVICE_TYPE_PLAYBACK_DEVICE;
+ else if (strType == "r")
+ type = CEC_DEVICE_TYPE_RECORDING_DEVICE;
+ else if (strType == "t")
+ type = CEC_DEVICE_TYPE_TUNER;
+
+ PrintToStdOut("device %d is %s", type, (parser->IsActiveDeviceType(type) ? "active" : "not active"));
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool ProcessCommandR(ICECAdapter *parser, const std::string &command, std::string & UNUSED(arguments))
+{
+ if (command == "r")
+ {
+ bool bReactivate = parser->IsLibCECActiveSource();
+
+ PrintToStdOut("closing the connection");
+ parser->Close();
+
+ PrintToStdOut("opening a new connection");
+ parser->Open(g_strPort.c_str());
+
+ if (bReactivate)
+ {
+ PrintToStdOut("setting active source");
+ parser->SetActiveSource();
+ }
+ return true;
+ }
+
+ return false;
+}
+
+bool ProcessCommandH(ICECAdapter * UNUSED(parser), const std::string &command, std::string & UNUSED(arguments))
+{
+ if (command == "h" || command == "help")
+ {
+ ShowHelpConsole();
+ return true;
+ }
+
+ return false;
+}
+
+bool ProcessCommandLOG(ICECAdapter * UNUSED(parser), const std::string &command, std::string &arguments)
+{
+ if (command == "log")
+ {
+ std::string strLevel;
+ if (GetWord(arguments, strLevel))
+ {
+ int iNewLevel = atoi(strLevel.c_str());
+ if (iNewLevel >= CEC_LOG_ERROR && iNewLevel <= CEC_LOG_ALL)
+ {
+ g_cecLogLevel = iNewLevel;
+
+ PrintToStdOut("log level changed to %s", strLevel.c_str());
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool ProcessCommandSCAN(ICECAdapter *parser, const std::string &command, std::string & UNUSED(arguments))
+{
+ if (command == "scan")
+ {
+ std::string strLog;
+ PrintToStdOut("requesting CEC bus information ...");
+
+ strLog.append("CEC bus information\n===================\n");
+ cec_logical_addresses addresses = parser->GetActiveDevices();
+ cec_logical_address activeSource = parser->GetActiveSource();
+ for (uint8_t iPtr = 0; iPtr < 16; iPtr++)
+ {
+ if (addresses[iPtr])
+ {
+ uint64_t iVendorId = parser->GetDeviceVendorId((cec_logical_address)iPtr);
+ uint16_t iPhysicalAddress = parser->GetDevicePhysicalAddress((cec_logical_address)iPtr);
+ bool bActive = parser->IsActiveSource((cec_logical_address)iPtr);
+ cec_version iCecVersion = parser->GetDeviceCecVersion((cec_logical_address)iPtr);
+ cec_power_status power = parser->GetDevicePowerStatus((cec_logical_address)iPtr);
+ std::string osdName = parser->GetDeviceOSDName((cec_logical_address)iPtr);
+ std::string strAddr;
+ strAddr = StringUtils::Format("%x.%x.%x.%x", (iPhysicalAddress >> 12) & 0xF, (iPhysicalAddress >> 8) & 0xF, (iPhysicalAddress >> 4) & 0xF, iPhysicalAddress & 0xF);
+ std::string lang = parser->GetDeviceMenuLanguage((cec_logical_address)iPtr);
+
+ strLog += StringUtils::Format("device #%X: %s\n", (int)iPtr, parser->ToString((cec_logical_address)iPtr));
+ strLog += StringUtils::Format("address: %s\n", strAddr.c_str());
+ strLog += StringUtils::Format("active source: %s\n", (bActive ? "yes" : "no"));
+ strLog += StringUtils::Format("vendor: %s\n", parser->ToString((cec_vendor_id)iVendorId));
+ strLog += StringUtils::Format("osd string: %s\n", osdName.c_str());
+ strLog += StringUtils::Format("CEC version: %s\n", parser->ToString(iCecVersion));
+ strLog += StringUtils::Format("power status: %s\n", parser->ToString(power));
+ strLog += StringUtils::Format("language: %s\n", lang.c_str());
+ strLog.append("\n\n");
+ }
+ }
+
+ activeSource = parser->GetActiveSource();
+ strLog += StringUtils::Format("currently active source: %s (%d)", parser->ToString(activeSource), (int)activeSource);
+
+ PrintToStdOut(strLog.c_str());
+ return true;
+ }
+
+ return false;
+}
+
+bool ProcessConsoleCommand(ICECAdapter *parser, std::string &input)
+{
+ if (!input.empty())
+ {
+ std::string command;
+ if (GetWord(input, command))
+ {
+ if (command == "q" || command == "quit")
+ return false;
+
+ ProcessCommandTX(parser, command, input) ||
+ ProcessCommandON(parser, command, input) ||
+ ProcessCommandSTANDBY(parser, command, input) ||
+ ProcessCommandPOLL(parser, command, input) ||
+ ProcessCommandLA(parser, command, input) ||
+ ProcessCommandP(parser, command, input) ||
+ ProcessCommandPA(parser, command, input) ||
+ ProcessCommandAS(parser, command, input) ||
+ ProcessCommandIS(parser, command, input) ||
+ ProcessCommandOSD(parser, command, input) ||
+ ProcessCommandPING(parser, command, input) ||
+ ProcessCommandVOLUP(parser, command, input) ||
+ ProcessCommandVOLDOWN(parser, command, input) ||
+ ProcessCommandMUTE(parser, command, input) ||
+ ProcessCommandMON(parser, command, input) ||
+ ProcessCommandBL(parser, command, input) ||
+ ProcessCommandLANG(parser, command, input) ||
+ ProcessCommandVEN(parser, command, input) ||
+ ProcessCommandVER(parser, command, input) ||
+ ProcessCommandPOW(parser, command, input) ||
+ ProcessCommandNAME(parser, command, input) ||
+ ProcessCommandLAD(parser, command, input) ||
+ ProcessCommandAD(parser, command, input) ||
+ ProcessCommandAT(parser, command, input) ||
+ ProcessCommandR(parser, command, input) ||
+ ProcessCommandH(parser, command, input) ||
+ ProcessCommandLOG(parser, command, input) ||
+ ProcessCommandSCAN(parser, command, input) ||
+ ProcessCommandSP(parser, command, input) ||
+ ProcessCommandSPL(parser, command, input) ||
+ ProcessCommandSELF(parser, command, input);
+ }
+ }
+ return true;
+}
+
+bool ProcessCommandLineArguments(int argc, char *argv[])
+{
+ bool bReturn(true);
+ int iArgPtr = 1;
+ while (iArgPtr < argc && bReturn)
+ {
+ if (argc >= iArgPtr + 1)
+ {
+ if (!strcmp(argv[iArgPtr], "-f") ||
+ !strcmp(argv[iArgPtr], "--log-file") ||
+ !strcmp(argv[iArgPtr], "-sf") ||
+ !strcmp(argv[iArgPtr], "--short-log-file"))
+ {
+ if (argc >= iArgPtr + 2)
+ {
+ g_logOutput.open(argv[iArgPtr + 1]);
+ g_bShortLog = (!strcmp(argv[iArgPtr], "-sf") || !strcmp(argv[iArgPtr], "--short-log-file"));
+ iArgPtr += 2;
+ }
+ else
+ {
+ std::cout << "== skipped log-file parameter: no file given ==" << std::endl;
+ ++iArgPtr;
+ }
+ }
+ else if (!strcmp(argv[iArgPtr], "-d") ||
+ !strcmp(argv[iArgPtr], "--log-level"))
+ {
+ if (argc >= iArgPtr + 2)
+ {
+ int iNewLevel = atoi(argv[iArgPtr + 1]);
+ if (iNewLevel >= CEC_LOG_ERROR && iNewLevel <= CEC_LOG_ALL)
+ {
+ g_cecLogLevel = iNewLevel;
+ if (!g_bSingleCommand)
+ std::cout << "log level set to " << argv[iArgPtr + 1] << std::endl;
+ }
+ else
+ {
+ std::cout << "== skipped log-level parameter: invalid level '" << argv[iArgPtr + 1] << "' ==" << std::endl;
+ }
+ iArgPtr += 2;
+ }
+ else
+ {
+ std::cout << "== skipped log-level parameter: no level given ==" << std::endl;
+ ++iArgPtr;
+ }
+ }
+ else if (!strcmp(argv[iArgPtr], "-t") ||
+ !strcmp(argv[iArgPtr], "--type"))
+ {
+ if (argc >= iArgPtr + 2)
+ {
+ if (!strcmp(argv[iArgPtr + 1], "p"))
+ {
+ if (!g_bSingleCommand)
+ std::cout << "== using device type 'playback device'" << std::endl;
+ g_config.deviceTypes.Add(CEC_DEVICE_TYPE_PLAYBACK_DEVICE);
+ }
+ else if (!strcmp(argv[iArgPtr + 1], "r"))
+ {
+ if (!g_bSingleCommand)
+ std::cout << "== using device type 'recording device'" << std::endl;
+ g_config.deviceTypes.Add(CEC_DEVICE_TYPE_RECORDING_DEVICE);
+ }
+ else if (!strcmp(argv[iArgPtr + 1], "t"))
+ {
+ if (!g_bSingleCommand)
+ std::cout << "== using device type 'tuner'" << std::endl;
+ g_config.deviceTypes.Add(CEC_DEVICE_TYPE_TUNER);
+ }
+ else if (!strcmp(argv[iArgPtr + 1], "a"))
+ {
+ if (!g_bSingleCommand)
+ std::cout << "== using device type 'audio system'" << std::endl;
+ g_config.deviceTypes.Add(CEC_DEVICE_TYPE_AUDIO_SYSTEM);
+ }
+ else if (!strcmp(argv[iArgPtr + 1], "x"))
+ {
+ if (!g_bSingleCommand)
+ std::cout << "== using device type 'tv'" << std::endl;
+ g_config.deviceTypes.Add(CEC_DEVICE_TYPE_TV);
+ }
+ else
+ {
+ std::cout << "== skipped invalid device type '" << argv[iArgPtr + 1] << "'" << std::endl;
+ }
+ ++iArgPtr;
+ }
+ ++iArgPtr;
+ }
+ else if (!strcmp(argv[iArgPtr], "--info") ||
+ !strcmp(argv[iArgPtr], "-i"))
+ {
+ if (g_cecLogLevel == -1)
+ g_cecLogLevel = CEC_LOG_WARNING + CEC_LOG_ERROR;
+ ICECAdapter *parser = LibCecInitialise(&g_config);
+ if (parser)
+ {
+ std::string strMessage;
+ strMessage = StringUtils::Format("libCEC version: %s, %s",
+ parser->VersionToString(g_config.serverVersion).c_str(),
+ parser->GetLibInfo());
+ PrintToStdOut(strMessage.c_str());
+ UnloadLibCec(parser);
+ parser = NULL;
+ }
+ bReturn = false;
+ }
+ else if (!strcmp(argv[iArgPtr], "--list-devices") ||
+ !strcmp(argv[iArgPtr], "-l"))
+ {
+ if (g_cecLogLevel == -1)
+ g_cecLogLevel = CEC_LOG_WARNING + CEC_LOG_ERROR;
+ ICECAdapter *parser = LibCecInitialise(&g_config);
+ if (parser)
+ {
+ ListDevices(parser);
+ UnloadLibCec(parser);
+ parser = NULL;
+ }
+ bReturn = false;
+ }
+ else if (!strcmp(argv[iArgPtr], "--bootloader"))
+ {
+ LibCecBootloader();
+ bReturn = false;
+ }
+ else if (!strcmp(argv[iArgPtr], "--single-command") ||
+ !strcmp(argv[iArgPtr], "-s"))
+ {
+ g_bSingleCommand = true;
+ ++iArgPtr;
+ }
+ else if (!strcmp(argv[iArgPtr], "--help") ||
+ !strcmp(argv[iArgPtr], "-h"))
+ {
+ if (g_cecLogLevel == -1)
+ g_cecLogLevel = CEC_LOG_WARNING + CEC_LOG_ERROR;
+
+ ShowHelpCommandLine(argv[0]);
+ return 0;
+ }
+ else if (!strcmp(argv[iArgPtr], "-b") ||
+ !strcmp(argv[iArgPtr], "--base"))
+ {
+ if (argc >= iArgPtr + 2)
+ {
+ g_config.baseDevice = (cec_logical_address)atoi(argv[iArgPtr + 1]);
+ std::cout << "using base device '" << (int)g_config.baseDevice << "'" << std::endl;
+ ++iArgPtr;
+ }
+ ++iArgPtr;
+ }
+ else if (!strcmp(argv[iArgPtr], "-p") ||
+ !strcmp(argv[iArgPtr], "--port"))
+ {
+ if (argc >= iArgPtr + 2)
+ {
+ uint8_t hdmiport = (int8_t)atoi(argv[iArgPtr + 1]);
+ if (hdmiport < 1)
+ hdmiport = 1;
+ if (hdmiport > 15)
+ hdmiport = 15;
+ g_config.iHDMIPort = hdmiport;
+ std::cout << "using HDMI port '" << (int)g_config.iHDMIPort << "'" << std::endl;
+ ++iArgPtr;
+ }
+ ++iArgPtr;
+ }
+ else if (!strcmp(argv[iArgPtr], "-r") ||
+ !strcmp(argv[iArgPtr], "--rom"))
+ {
+ std::cout << "using settings from EEPROM" << std::endl;
+ g_config.bGetSettingsFromROM = 1;
+ ++iArgPtr;
+ }
+ else if (!strcmp(argv[iArgPtr], "-o") ||
+ !strcmp(argv[iArgPtr], "--osd-name"))
+ {
+ if (argc >= iArgPtr + 2)
+ {
+ snprintf(g_config.strDeviceName, 13, "%s", argv[iArgPtr + 1]);
+ std::cout << "using osd name " << g_config.strDeviceName << std::endl;
+ ++iArgPtr;
+ }
+ ++iArgPtr;
+ }
+ else if (!strcmp(argv[iArgPtr], "-m") ||
+ !strcmp(argv[iArgPtr], "--monitor"))
+ {
+ std::cout << "starting a monitor-only client. use 'mon 0' to switch to normal mode" << std::endl;
+ g_config.bMonitorOnly = 1;
+ ++iArgPtr;
+ }
+#if defined(HAVE_CURSES_API)
+ else if (!strcmp(argv[iArgPtr], "-c"))
+ {
+ g_cursesEnable = true;
+ if (argc >= iArgPtr + 2)
+ {
+ std::string input = std::string(argv[iArgPtr + 1]);
+ if (input.size() > 2)
+ {
+ PrintToStdOut("== using default: 10 == ");
+ }
+ else
+ {
+ std::string g_in(1, input[0]);
+ std::string g_out(1, input[1]);
+ g_cursesControl.SetInput(g_in);
+ g_cursesControl.SetOutput(g_out);
+ }
+ iArgPtr += 2;
+ }
+ else
+ {
+ PrintToStdOut("== using default: 10 == ");
+ ++iArgPtr;
+ }
+ }
+#endif
+ else
+ {
+ g_strPort = argv[iArgPtr++];
+ }
+ }
+ }
+
+ return bReturn;
+}
+
+void sighandler(int iSignal)
+{
+ PrintToStdOut("signal caught: %d - exiting", iSignal);
+ g_bExit = true;
+#if defined(HAVE_CURSES_API)
+ if (g_cursesEnable)
+ g_cursesControl.End();
+#endif
+}
+
+int main (int argc, char *argv[])
+{
+ if (signal(SIGINT, sighandler) == SIG_ERR)
+ {
+ PrintToStdOut("can't register sighandler");
+ return -1;
+ }
+
+ g_config.Clear();
+ g_callbacks.Clear();
+ snprintf(g_config.strDeviceName, 13, "CECTester");
+ g_config.clientVersion = LIBCEC_VERSION_CURRENT;
+ g_config.bActivateSource = 0;
+ g_callbacks.logMessage = &CecLogMessage;
+ g_callbacks.keyPress = &CecKeyPress;
+ g_callbacks.commandReceived = &CecCommand;
+ g_callbacks.alert = &CecAlert;
+ g_config.callbacks = &g_callbacks;
+
+ if (!ProcessCommandLineArguments(argc, argv))
+ return 0;
+
+ if (g_cecLogLevel == -1)
+ g_cecLogLevel = g_cecDefaultLogLevel;
+
+ if (g_config.deviceTypes.IsEmpty())
+ {
+ if (!g_bSingleCommand)
+ std::cout << "No device type given. Using 'recording device'" << std::endl;
+ g_config.deviceTypes.Add(CEC_DEVICE_TYPE_RECORDING_DEVICE);
+ }
+
+ g_parser = LibCecInitialise(&g_config);
+ if (!g_parser)
+ {
+#ifdef __WINDOWS__
+ std::cout << "Cannot load cec.dll" << std::endl;
+#else
+ std::cout << "Cannot load libcec.so" << std::endl;
+#endif
+
+ if (g_parser)
+ UnloadLibCec(g_parser);
+
+ return 1;
+ }
+
+ // init video on targets that need this
+ g_parser->InitVideoStandalone();
+
+ if (!g_bSingleCommand)
+ {
+ std::string strLog;
+ strLog = StringUtils::Format("CEC Parser created - libCEC version %s", g_parser->VersionToString(g_config.serverVersion).c_str());
+ std::cout << strLog.c_str() << std::endl;
+
+ //make stdin non-blocking
+ #ifndef __WINDOWS__
+ int flags = fcntl(0, F_GETFL, 0);
+ flags |= O_NONBLOCK;
+ fcntl(0, F_SETFL, flags);
+ #endif
+ }
+
+ if (g_strPort.empty())
+ {
+ if (!g_bSingleCommand)
+ std::cout << "no serial port given. trying autodetect: ";
+ cec_adapter_descriptor devices[10];
+ uint8_t iDevicesFound = g_parser->DetectAdapters(devices, 10, NULL, true);
+ if (iDevicesFound <= 0)
+ {
+ if (g_bSingleCommand)
+ std::cout << "autodetect ";
+ std::cout << "FAILED" << std::endl;
+ UnloadLibCec(g_parser);
+ return 1;
+ }
+ else
+ {
+ if (!g_bSingleCommand)
+ {
+ std::cout << std::endl << " path: " << devices[0].strComPath << std::endl <<
+ " com port: " << devices[0].strComName << std::endl << std::endl;
+ }
+ g_strPort = devices[0].strComName;
+ }
+ }
+
+ PrintToStdOut("opening a connection to the CEC adapter...");
+
+ if (!g_parser->Open(g_strPort.c_str()))
+ {
+ PrintToStdOut("unable to open the device on port %s", g_strPort.c_str());
+ UnloadLibCec(g_parser);
+ return 1;
+ }
+
+#if defined(HAVE_CURSES_API)
+ if (g_cursesEnable)
+ g_cursesControl.Init();
+#endif
+
+ if (!g_bSingleCommand)
+ PrintToStdOut("waiting for input");
+
+ while (!g_bExit && !g_bHardExit)
+ {
+ std::string input;
+#if defined(HAVE_CURSES_API)
+ if (!g_cursesEnable) {
+ getline(std::cin, input);
+ std::cin.clear();
+ }
+ else
+ {
+ input = g_cursesControl.ParseCursesKey();
+ }
+#else
+ getline(std::cin, input);
+ std::cin.clear();
+#endif
+
+ if (ProcessConsoleCommand(g_parser, input) && !g_bSingleCommand && !g_bExit && !g_bHardExit)
+ {
+ if (!input.empty())
+ PrintToStdOut("waiting for input");
+ }
+ else
+ {
+#if defined(HAVE_CURSES_API)
+ if (g_cursesEnable)
+ g_cursesControl.End();
+#endif
+ g_bExit = true;
+ }
+
+ if (!g_bExit && !g_bHardExit)
+ CEvent::Sleep(50);
+ }
+
+ g_parser->Close();
+ UnloadLibCec(g_parser);
+
+ if (g_logOutput.is_open())
+ g_logOutput.close();
+
+ return 0;
+}
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "CursesControl.h"
+#include <p8-platform/util/StringUtils.h>
+#include <curses.h>
+
+void CCursesControl::Init()
+{
+ initscr();
+ noecho();
+ keypad(stdscr, true);
+ printw("Curses enabled.");
+}
+
+void CCursesControl::End(void)
+{
+ endwin();
+ printw("Curses closed.");
+}
+
+void CCursesControl::SetInput(const std::string& in)
+{
+ m_in = in;
+}
+
+void CCursesControl::SetOutput(const std::string& out)
+{
+ m_out = out;
+}
+
+std::string CCursesControl::ParseCursesKey(void)
+{
+ int key = getch();
+ std::string strKey;
+ switch(key){
+ case KEY_DOWN:
+ strKey = "42";
+ break;
+ case KEY_UP:
+ strKey = "41";
+ break;
+ case 109: // KEY_m
+ strKey = "43";
+ break;
+ case 10: // KEY_ENTER
+ strKey = "6B";
+ break;
+ case 113: // KEY_q
+ strKey = "q";
+ break;
+ }
+
+ return strKey.empty() ?
+ "" :
+ StringUtils::Format("tx %s%s 44 %s", m_in.c_str(), m_out.c_str(), strKey.c_str());
+}
--- /dev/null
+#pragma once
+
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include <string>
+
+class CCursesControl
+{
+ public:
+ CCursesControl() {}
+ CCursesControl(const std::string& in, const std::string& out) :
+ m_in(in),
+ m_out(out) {}
+ virtual ~CCursesControl() {}
+
+ void Init(void);
+ void End(void);
+ void SetInput(const std::string& in);
+ void SetOutput(const std::string& out);
+ std::string ParseCursesKey(void);
+
+ private:
+ std::string m_in, m_out;
+};
--- /dev/null
+#pragma once
+/*
+ * WARNING: Auto-generated file from env.h.in
+ *
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "cectypes.h"
+#include <p8-platform/os.h>
+
+#ifdef UNUSED
+#elif defined(__GNUC__)
+#define UNUSED(x) UNUSED_ ## x __attribute__((unused))
+#elif defined(__LCLINT__)
+#define UNUSED(x) /*@unused@*/ x
+#else
+#define UNUSED(x) x
+#endif
+
+/* Define to 1 for curses support */
+#cmakedefine HAVE_CURSES_API @HAVE_CURSES_API@
--- /dev/null
+project(ceccclient)
+cmake_minimum_required(VERSION 2.8.9)
+
+set(ceccclient_NAME ceccclient)
+set(ceccclient_DESCRIPTION "libCEC test client")
+set(ceccclient_VERSION_MAJOR ${LIBCEC_VERSION_MAJOR})
+set(ceccclient_VERSION_MINOR ${LIBCEC_VERSION_MINOR})
+set(ceccclient_VERSION_PATCH ${LIBCEC_VERSION_PATCH})
+
+enable_language(C)
+include(CheckCSourceCompiles)
+include(CheckLibraryExists)
+include(CheckIncludeFiles)
+
+find_package(p8-platform REQUIRED)
+find_package(Threads REQUIRED)
+
+set(ceccclient_SOURCES cecc-client.c)
+
+add_executable(cecc-client ${ceccclient_SOURCES})
+set_target_properties(cecc-client PROPERTIES VERSION ${LIBCEC_VERSION_MAJOR}.${LIBCEC_VERSION_MINOR}.${LIBCEC_VERSION_PATCH})
+target_link_libraries(cecc-client ${p8-platform_LIBRARIES})
+target_link_libraries(cecc-client ${CMAKE_THREAD_LIBS_INIT})
+
+if (NOT WIN32)
+ # check for dlopen
+ check_library_exists(dl dlopen "" HAVE_DLOPEN)
+ if (HAVE_DLOPEN)
+ target_link_libraries(cecc-client dl)
+ endif()
+
+ # CoreVideo
+ if (APPLE)
+ target_link_libraries(cecc-client "-framework CoreVideo")
+ endif()
+else()
+ add_definitions(-DTARGET_WINDOWS -DNOMINMAX -D_CRT_SECURE_NO_WARNINGS -D_WINSOCKAPI_)
+ if (NOT ${WIN64})
+ add_definitions(-D_USE_32BIT_TIME_T)
+ endif()
+endif()
+
+include_directories(${p8-platform_INCLUDE_DIRS}
+ ${PROJECT_SOURCE_DIR}
+ ${PROJECT_SOURCE_DIR}/../../include)
+
+# write env.h
+CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/env.h.in ${CMAKE_CURRENT_SOURCE_DIR}/env.h)
+
+if (WIN32)
+ install(TARGETS cecc-client
+ DESTINATION .)
+else()
+ install(TARGETS cecc-client
+ DESTINATION bin/.)
+endif()
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include "ceccloader.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <fcntl.h>
+
+static void cb_cec_log_message(void* lib, const cec_log_message* message);
+
+#if defined(__WINDOWS__)
+#include <Windows.h>
+static void usleep(__int64 usec)
+{
+ HANDLE timer;
+ LARGE_INTEGER ft;
+ ft.QuadPart = -(10 * usec); // Convert to 100 nanosecond interval, negative value indicates relative time
+ timer = CreateWaitableTimer(NULL, TRUE, NULL);
+ SetWaitableTimer(timer, &ft, 0, NULL, NULL, 0);
+ WaitForSingleObject(timer, INFINITE);
+ CloseHandle(timer);
+}
+
+#define sleep(x) usleep(1000000 * x)
+#define PRId64 "%lld"
+#endif
+
+static ICECCallbacks g_callbacks = {
+ .logMessage = cb_cec_log_message,
+ .keyPress = NULL,
+ .commandReceived = NULL,
+ .configurationChanged = NULL,
+ .alert = NULL,
+ .menuStateChanged = NULL,
+ .sourceActivated = NULL
+};
+
+static libcec_configuration g_config;
+static int g_cecLogLevel = -1;
+static int g_cecDefaultLogLevel = CEC_LOG_ALL;
+static char g_strPort[50] = { 0 };
+static int g_bSingleCommand = 0;
+static int g_bExit = 0;
+static int g_bHardExit = 0;
+static libcec_interface_t g_iface;
+
+static void sighandler(int iSignal)
+{
+ printf("signal caught: %d - exiting\n", iSignal);
+ g_bExit = 1;
+}
+
+static void cb_cec_log_message(void* lib, const cec_log_message* message)
+{
+ if ((message->level & g_cecLogLevel) == message->level)
+ {
+ const char* strLevel;
+ switch (message->level)
+ {
+ case CEC_LOG_ERROR:
+ strLevel = "ERROR: ";
+ break;
+ case CEC_LOG_WARNING:
+ strLevel = "WARNING: ";
+ break;
+ case CEC_LOG_NOTICE:
+ strLevel = "NOTICE: ";
+ break;
+ case CEC_LOG_TRAFFIC:
+ strLevel = "TRAFFIC: ";
+ break;
+ case CEC_LOG_DEBUG:
+ strLevel = "DEBUG: ";
+ break;
+ default:
+ break;
+ }
+
+ printf("%s[%" PRId64 "]\t%s\n", strLevel, message->time, message->message);
+ }
+}
+
+static void cec_list_devices(void)
+{
+ //TODO
+}
+
+static int cec_process_command_line_arguments(int argc, char *argv[])
+{
+ int bReturn = 1;
+ int iArgPtr = 1;
+ while (iArgPtr < argc && bReturn)
+ {
+ if (argc >= iArgPtr + 1)
+ {
+ if (!strcmp(argv[iArgPtr], "-d") ||
+ !strcmp(argv[iArgPtr], "--log-level"))
+ {
+ if (argc >= iArgPtr + 2)
+ {
+ int iNewLevel = atoi(argv[iArgPtr + 1]);
+ if (iNewLevel >= CEC_LOG_ERROR && iNewLevel <= CEC_LOG_ALL)
+ {
+ g_cecLogLevel = iNewLevel;
+ if (!g_bSingleCommand)
+ printf("log level set to %s\n", argv[iArgPtr + 1]);
+ }
+ else
+ {
+ printf("== skipped log-level parameter: invalid level %s' ==\n", argv[iArgPtr + 1]);
+ }
+ iArgPtr += 2;
+ }
+ else
+ {
+ printf("== skipped log-level parameter: no level given ==\n");
+ ++iArgPtr;
+ }
+ }
+ else if (!strcmp(argv[iArgPtr], "-t") ||
+ !strcmp(argv[iArgPtr], "--type"))
+ {
+ if (argc >= iArgPtr + 2)
+ {
+ if (!strcmp(argv[iArgPtr + 1], "p"))
+ {
+ if (!g_bSingleCommand)
+ printf("== using device type 'playback device'\n");
+ g_config.deviceTypes.types[0] = CEC_DEVICE_TYPE_PLAYBACK_DEVICE;
+ }
+ else if (!strcmp(argv[iArgPtr + 1], "r"))
+ {
+ if (!g_bSingleCommand)
+ printf("== using device type 'recording device'\n");
+ g_config.deviceTypes.types[0] = CEC_DEVICE_TYPE_RECORDING_DEVICE;
+ }
+ else if (!strcmp(argv[iArgPtr + 1], "t"))
+ {
+ if (!g_bSingleCommand)
+ printf("== using device type 'tuner'\n");
+ g_config.deviceTypes.types[0] = CEC_DEVICE_TYPE_TUNER;
+ }
+ else if (!strcmp(argv[iArgPtr + 1], "a"))
+ {
+ if (!g_bSingleCommand)
+ printf("== using device type 'audio system'\n");
+ g_config.deviceTypes.types[0] = CEC_DEVICE_TYPE_AUDIO_SYSTEM;
+ }
+ else if (!strcmp(argv[iArgPtr + 1], "x"))
+ {
+ if (!g_bSingleCommand)
+ printf("== using device type 'tv'\n");
+ g_config.deviceTypes.types[0] = CEC_DEVICE_TYPE_TV;
+ }
+ else
+ {
+ printf("== skipped invalid device type %s'\n", argv[iArgPtr + 1]);
+ }
+ ++iArgPtr;
+ }
+ ++iArgPtr;
+ }
+ else if (!strcmp(argv[iArgPtr], "--info") ||
+ !strcmp(argv[iArgPtr], "-i"))
+ {
+ if (g_cecLogLevel == -1)
+ g_cecLogLevel = CEC_LOG_WARNING + CEC_LOG_ERROR;
+ if (libcecc_initialise(&g_config, &g_iface, NULL) == 1)
+ {
+ char verbuf[10];
+ g_iface.version_to_string(g_config.serverVersion, verbuf, sizeof(verbuf));
+ printf("libCEC version: %s %s\n", verbuf, g_iface.get_lib_info(g_iface.connection));
+ libcecc_destroy(&g_iface);
+ }
+ bReturn = 0;
+ }
+ else if (!strcmp(argv[iArgPtr], "--list-devices") ||
+ !strcmp(argv[iArgPtr], "-l"))
+ {
+ if (g_cecLogLevel == -1)
+ g_cecLogLevel = CEC_LOG_WARNING + CEC_LOG_ERROR;
+ if (libcecc_initialise(&g_config, &g_iface, NULL) == 1)
+ {
+ cec_list_devices();
+ libcecc_destroy(&g_iface);
+ }
+ bReturn = 0;
+ }
+ else if (!strcmp(argv[iArgPtr], "--single-command") ||
+ !strcmp(argv[iArgPtr], "-s"))
+ {
+ g_bSingleCommand = 1;
+ ++iArgPtr;
+ }
+ else if (!strcmp(argv[iArgPtr], "--help") ||
+ !strcmp(argv[iArgPtr], "-h"))
+ {
+ if (g_cecLogLevel == -1)
+ g_cecLogLevel = CEC_LOG_WARNING + CEC_LOG_ERROR;
+
+// TODO ShowHelpCommandLine(argv[0]);
+ return 0;
+ }
+ else if (!strcmp(argv[iArgPtr], "-b") ||
+ !strcmp(argv[iArgPtr], "--base"))
+ {
+ if (argc >= iArgPtr + 2)
+ {
+ g_config.baseDevice = (cec_logical_address)atoi(argv[iArgPtr + 1]);
+ printf("using base device '%d'\n", (int)g_config.baseDevice);
+ ++iArgPtr;
+ }
+ ++iArgPtr;
+ }
+ else if (!strcmp(argv[iArgPtr], "-p") ||
+ !strcmp(argv[iArgPtr], "--port"))
+ {
+ if (argc >= iArgPtr + 2)
+ {
+ uint8_t hdmiport = (int8_t)atoi(argv[iArgPtr + 1]);
+ if (hdmiport < 1)
+ hdmiport = 1;
+ if (hdmiport > 15)
+ hdmiport = 15;
+ g_config.iHDMIPort = hdmiport;
+ printf("using HDMI port '%d'\n", (int)g_config.iHDMIPort);
+ ++iArgPtr;
+ }
+ ++iArgPtr;
+ }
+ else if (!strcmp(argv[iArgPtr], "-r") ||
+ !strcmp(argv[iArgPtr], "--rom"))
+ {
+ printf("using settings from EEPROM\n");
+ g_config.bGetSettingsFromROM = 1;
+ ++iArgPtr;
+ }
+ else if (!strcmp(argv[iArgPtr], "-o") ||
+ !strcmp(argv[iArgPtr], "--osd-name"))
+ {
+ if (argc >= iArgPtr + 2)
+ {
+ snprintf(g_config.strDeviceName, 13, "%s", argv[iArgPtr + 1]);
+ printf("using osd name '%s'\n", g_config.strDeviceName);
+ ++iArgPtr;
+ }
+ ++iArgPtr;
+ }
+ else if (!strcmp(argv[iArgPtr], "-m") ||
+ !strcmp(argv[iArgPtr], "--monitor"))
+ {
+ printf("starting a monitor-only client. use 'mon 0' to switch to normal mode\n");
+ g_config.bMonitorOnly = 1;
+ ++iArgPtr;
+ }
+ else
+ {
+ strcpy(g_strPort, argv[iArgPtr++]);
+ }
+ }
+ }
+
+ return bReturn;
+}
+
+static int cec_process_command_as(const char* data)
+{
+ if (strncmp(data, "as", 2) == 0)
+ {
+ g_iface.set_active_source(g_iface.connection, g_config.deviceTypes.types[0]);
+ // wait for the source switch to finish for 15 seconds tops
+ if (g_bSingleCommand)
+ {
+ int isactive = 0;
+ int timeout = 15;
+ while (timeout-- > 0)
+ {
+ isactive = g_iface.is_libcec_active_source(g_iface.connection);
+ if (!isactive)
+ sleep(1);
+ }
+ }
+ return 1;
+ }
+
+ return 0;
+}
+
+static int cec_process_command_scan(const char* data)
+{
+ if (strncmp(data, "scan", 4) == 0)
+ {
+ char buffer[10000] = { 0 };
+ char tmpbuf[50];
+ int bufferpos = 0;
+ cec_logical_addresses addresses;
+ cec_logical_address activeSource;
+ uint8_t iPtr;
+
+ printf("requesting CEC bus information ...\n");
+
+ bufferpos += snprintf(buffer + bufferpos, sizeof(buffer) - bufferpos, "CEC bus information\n===================\n");
+ addresses = g_iface.get_active_devices(g_iface.connection);
+ activeSource = g_iface.get_active_source(g_iface.connection);
+ for (iPtr = 0; iPtr < 16; iPtr++)
+ {
+ if (addresses.addresses[iPtr])
+ {
+ cec_menu_language lang;
+ cec_osd_name osdName;
+ uint64_t iVendorId = g_iface.get_device_vendor_id(g_iface.connection, (cec_logical_address)iPtr);
+ uint16_t iPhysicalAddress = g_iface.get_device_physical_address(g_iface.connection, (cec_logical_address)iPtr);
+ int bActive = g_iface.is_active_source(g_iface.connection, (cec_logical_address)iPtr);
+ cec_version iCecVersion = g_iface.get_device_cec_version(g_iface.connection, (cec_logical_address)iPtr);
+ cec_power_status power = g_iface.get_device_power_status(g_iface.connection, (cec_logical_address)iPtr);
+
+ g_iface.logical_address_to_string(iPtr, tmpbuf, sizeof(tmpbuf));
+ bufferpos += snprintf(buffer + bufferpos, sizeof(buffer) - bufferpos, "device #%X: %s\n", (int)iPtr, tmpbuf);
+ bufferpos += snprintf(buffer + bufferpos, sizeof(buffer) - bufferpos, "address: %x.%x.%x.%x\n", (iPhysicalAddress >> 12) & 0xF, (iPhysicalAddress >> 8) & 0xF, (iPhysicalAddress >> 4) & 0xF, iPhysicalAddress & 0xF);
+ bufferpos += snprintf(buffer + bufferpos, sizeof(buffer) - bufferpos, "active source: %s\n", (bActive ? "yes" : "no"));
+ g_iface.vendor_id_to_string(iVendorId, tmpbuf, sizeof(tmpbuf));
+ bufferpos += snprintf(buffer + bufferpos, sizeof(buffer) - bufferpos, "vendor: %s\n", tmpbuf);
+ g_iface.get_device_osd_name(g_iface.connection, (cec_logical_address)iPtr, osdName);
+ bufferpos += snprintf(buffer + bufferpos, sizeof(buffer) - bufferpos, "osd string: %s\n", osdName);
+ g_iface.cec_version_to_string(iCecVersion, tmpbuf, sizeof(tmpbuf));
+ bufferpos += snprintf(buffer + bufferpos, sizeof(buffer) - bufferpos, "CEC version: %s\n", tmpbuf);
+ g_iface.power_status_to_string(power, tmpbuf, sizeof(tmpbuf));
+ bufferpos += snprintf(buffer + bufferpos, sizeof(buffer) - bufferpos, "power status: %s\n", tmpbuf);
+ g_iface.get_device_menu_language(g_iface.connection, iPtr, lang);
+ bufferpos += snprintf(buffer + bufferpos, sizeof(buffer) - bufferpos, "language: %s\n", lang);
+ bufferpos += snprintf(buffer + bufferpos, sizeof(buffer) - bufferpos, "\n\n");
+ }
+ }
+
+ activeSource = g_iface.get_active_source(g_iface.connection);
+ g_iface.logical_address_to_string(activeSource, tmpbuf, sizeof(tmpbuf));
+ bufferpos += snprintf(buffer + bufferpos, sizeof(buffer) - bufferpos, "currently active source: %s (%d)", tmpbuf, (int)activeSource);
+
+ printf("%s\n", buffer);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int cec_process_console_command(const char* buffer)
+{
+ size_t buflen;
+ buflen = strlen(buffer);
+
+ if (strncmp(buffer, "q", 1) == 0 || strncmp(buffer, "quit", 4) == 0)
+ return 0;
+
+ cec_process_command_as(buffer) ||
+ cec_process_command_scan(buffer);
+ //TODO
+
+ return 1;
+}
+
+int main(int argc, char *argv[])
+{
+ char buffer[100];
+ if (signal(SIGINT, sighandler) == SIG_ERR)
+ {
+ printf("can't register sighandler\n");
+ return -1;
+ }
+
+ libcecc_reset_configuration(&g_config);
+ g_config.clientVersion = LIBCEC_VERSION_CURRENT;
+ g_config.bActivateSource = 0;
+ g_config.callbacks = &g_callbacks;
+ snprintf(g_config.strDeviceName, sizeof(g_config.strDeviceName), "CEC tester");
+
+ if (!cec_process_command_line_arguments(argc, argv))
+ return 0;
+
+ if (g_cecLogLevel == -1)
+ g_cecLogLevel = g_cecDefaultLogLevel;
+
+ if (g_config.deviceTypes.types[0] == CEC_DEVICE_TYPE_RESERVED)
+ {
+ if (!g_bSingleCommand)
+ printf("No device type given. Using 'recording device'\n");
+ g_config.deviceTypes.types[0] = CEC_DEVICE_TYPE_RECORDING_DEVICE;
+ }
+
+ if (libcecc_initialise(&g_config, &g_iface, NULL) != 1)
+ {
+ printf("can't initialise libCEC\n");
+ return -1;
+ }
+
+ // init video on targets that need this
+ g_iface.init_video_standalone(g_iface.connection);
+
+ if (!g_bSingleCommand)
+ {
+ g_iface.version_to_string(g_config.serverVersion, buffer, sizeof(buffer));
+ printf("CEC Parser created - libCEC version %s\n", buffer);
+
+ //make stdin non-blocking
+ #ifndef __WINDOWS__
+ int flags = fcntl(0, F_GETFL, 0);
+ flags |= O_NONBLOCK;
+ fcntl(0, F_SETFL, flags);
+ #endif
+ }
+
+ if (g_strPort[0] == 0)
+ {
+ cec_adapter devices[10];
+ int8_t iDevicesFound;
+ if (!g_bSingleCommand)
+ printf("no serial port given. trying autodetect: ");
+
+ iDevicesFound = g_iface.find_adapters(g_iface.connection, devices, sizeof(devices) / sizeof(devices), NULL);
+ if (iDevicesFound <= 0)
+ {
+ if (g_bSingleCommand)
+ printf("autodetect ");
+ printf("FAILED\n");
+ libcecc_destroy(&g_iface);
+ return 1;
+ }
+ else
+ {
+ if (!g_bSingleCommand)
+ {
+ printf("\n path: %s\n com port: %s\n\n", devices[0].path, devices[0].comm);
+ }
+ strcpy(g_strPort, devices[0].comm);
+ }
+ }
+
+ printf("opening a connection to the CEC adapter...\n");
+
+ if (!g_iface.open(g_iface.connection, g_strPort, 5000))
+ {
+ printf("unable to open the device on port %s\n", g_strPort);
+ libcecc_destroy(&g_iface);
+ return 1;
+ }
+
+ if (!g_bSingleCommand)
+ printf("waiting for input\n");
+
+ while (!g_bExit && !g_bHardExit)
+ {
+ memset(buffer, 0, sizeof(buffer));
+ fgets(buffer, sizeof(buffer), stdin);
+
+ if (cec_process_console_command(buffer) && !g_bSingleCommand && !g_bExit && !g_bHardExit)
+ {
+ if (buffer[0] != 0 && buffer[0] != '\n' && buffer[0] != '\r')
+ printf("waiting for input\n");
+ }
+ else
+ {
+ g_bExit = 1;
+ }
+
+ if (!g_bExit && !g_bHardExit)
+ usleep(50000);
+ }
+
+ libcecc_destroy(&g_iface);
+ return 0;
+}
--- /dev/null
+#pragma once
+/*
+ * WARNING: Auto-generated file from env.h.in
+ *
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "cectypes.h"
+#include <p8-platform/os.h>
+
+#ifdef UNUSED
+#elif defined(__GNUC__)
+#define UNUSED(x) UNUSED_ ## x __attribute__((unused))
+#elif defined(__LCLINT__)
+#define UNUSED(x) /*@unused@*/ x
+#else
+#define UNUSED(x) x
+#endif
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include "CECClient.h"
+
+#include "CECProcessor.h"
+#include "LibCEC.h"
+#include "CECTypeUtils.h"
+#include "devices/CECPlaybackDevice.h"
+#include "devices/CECAudioSystem.h"
+#include "devices/CECTV.h"
+#include "implementations/CECCommandHandler.h"
+#include <stdio.h>
+
+using namespace CEC;
+using namespace P8PLATFORM;
+
+#define LIB_CEC m_processor->GetLib()
+#define ToString(x) CCECTypeUtils::ToString(x)
+
+CCECClient::CCECClient(CCECProcessor *processor, const libcec_configuration &configuration) :
+ m_processor(processor),
+ m_bInitialised(false),
+ m_bRegistered(false),
+ m_iCurrentButton(CEC_USER_CONTROL_CODE_UNKNOWN),
+ m_initialButtontime(0),
+ m_updateButtontime(0),
+ m_repeatButtontime(0),
+ m_releaseButtontime(0),
+ m_pressedButtoncount(0),
+ m_releasedButtoncount(0),
+ m_iPreventForwardingPowerOffCommand(0)
+{
+ m_configuration.Clear();
+ // set the initial configuration
+ SetConfiguration(configuration);
+ CreateThread(false);
+}
+
+CCECClient::~CCECClient(void)
+{
+ StopThread();
+ CCallbackWrap* cb;
+ while (!m_callbackCalls.IsEmpty())
+ if (m_callbackCalls.Pop(cb, 0))
+ delete cb;
+
+ // unregister the client
+ if (m_processor && IsRegistered())
+ m_processor->UnregisterClient(this);
+}
+
+bool CCECClient::IsInitialised(void)
+{
+ CLockObject lock(m_mutex);
+ return m_bInitialised && m_processor;
+}
+
+void CCECClient::SetInitialised(bool bSetTo)
+{
+ CLockObject lock(m_mutex);
+ m_bInitialised = bSetTo;
+}
+
+bool CCECClient::IsRegistered(void)
+{
+ CLockObject lock(m_mutex);
+ return m_bRegistered && m_processor;
+}
+
+void CCECClient::SetRegistered(bool bSetTo)
+{
+ CLockObject lock(m_mutex);
+ m_bRegistered = bSetTo;
+}
+
+bool CCECClient::OnRegister(void)
+{
+ // return false if already initialised
+ if (IsInitialised())
+ return true;
+
+ // get all device we control
+ CECDEVICEVEC devices;
+ m_processor->GetDevices()->GetByLogicalAddresses(devices, m_configuration.logicalAddresses);
+
+ // return false when no devices were found
+ if (devices.empty())
+ {
+ LIB_CEC->AddLog(CEC_LOG_WARNING, "cannot find the primary device (logical address %x)", GetPrimaryLogicalAddress());
+ return false;
+ }
+
+ // mark as initialised
+ SetInitialised(true);
+
+ // configure all devices
+ for (CECDEVICEVEC::iterator it = devices.begin(); it != devices.end(); it++)
+ {
+ // only set our OSD name for the primary device
+ if ((*it)->GetLogicalAddress() == GetPrimaryLogicalAddress())
+ (*it)->SetOSDName(m_configuration.strDeviceName);
+
+ // set the default menu language for devices we control
+ (*it)->SetMenuLanguage(m_configuration.strDeviceLanguage);
+ }
+
+ // set the physical address
+ SetPhysicalAddress(m_configuration);
+
+ // make the primary device the active source if the option is set
+ if (m_configuration.bActivateSource == 1)
+ GetPrimaryDevice()->ActivateSource(500);
+
+ return true;
+}
+
+bool CCECClient::SetHDMIPort(const cec_logical_address iBaseDevice, const uint8_t iPort, bool bForce /* = false */)
+{
+ bool bReturn(false);
+
+ // limit the HDMI port range to 1-15
+ if (iPort < CEC_MIN_HDMI_PORTNUMBER ||
+ iPort > CEC_MAX_HDMI_PORTNUMBER)
+ return bReturn;
+
+ // update the configuration
+ {
+ CLockObject lock(m_mutex);
+ if (m_configuration.baseDevice == iBaseDevice &&
+ m_configuration.iHDMIPort == iPort &&
+ CLibCEC::IsValidPhysicalAddress(m_configuration.iPhysicalAddress) &&
+ m_configuration.iPhysicalAddress > 0)
+ return true;
+ m_configuration.baseDevice = iBaseDevice;
+ m_configuration.iHDMIPort = iPort;
+ }
+
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, "setting HDMI port to %d on device %s (%d)", iPort, ToString(iBaseDevice), (int)iBaseDevice);
+
+ // don't continue if the connection isn't opened
+ if (!m_processor->CECInitialised() && !bForce)
+ return true;
+
+ // get the PA of the base device
+ uint16_t iPhysicalAddress(CEC_INVALID_PHYSICAL_ADDRESS);
+ CCECBusDevice *baseDevice = m_processor->GetDevice(iBaseDevice);
+ if (baseDevice)
+ iPhysicalAddress = baseDevice->GetPhysicalAddress(GetPrimaryLogicalAddress());
+
+ // add our port number
+ if (iPhysicalAddress <= CEC_MAX_PHYSICAL_ADDRESS)
+ {
+ if (iPhysicalAddress == 0)
+ iPhysicalAddress += 0x1000 * iPort;
+ else if (iPhysicalAddress % 0x1000 == 0)
+ iPhysicalAddress += 0x100 * iPort;
+ else if (iPhysicalAddress % 0x100 == 0)
+ iPhysicalAddress += 0x10 * iPort;
+ else if (iPhysicalAddress % 0x10 == 0)
+ iPhysicalAddress += iPort;
+
+ bReturn = true;
+ }
+
+ // set the default address when something went wrong
+ if (!bReturn)
+ {
+ uint16_t iEepromAddress = m_processor->GetPhysicalAddressFromEeprom();
+ if (CLibCEC::IsValidPhysicalAddress(iEepromAddress))
+ {
+ LIB_CEC->AddLog(CEC_LOG_WARNING, "failed to set the physical address to %04X, setting it to the value that was persisted in the eeprom, %04X", iPhysicalAddress, iEepromAddress);
+ iPhysicalAddress = iEepromAddress;
+ bReturn = true;
+ }
+ else
+ {
+ LIB_CEC->AddLog(CEC_LOG_WARNING, "failed to set the physical address to %04X, setting it to the default value %04X", iPhysicalAddress, CEC_DEFAULT_PHYSICAL_ADDRESS);
+ iPhysicalAddress = CEC_DEFAULT_PHYSICAL_ADDRESS;
+ }
+ }
+
+ // and set the address
+ SetDevicePhysicalAddress(iPhysicalAddress);
+
+ QueueConfigurationChanged(m_configuration);
+
+ return bReturn;
+}
+
+void CCECClient::ResetPhysicalAddress(void)
+{
+ SetPhysicalAddress(CEC_DEFAULT_PHYSICAL_ADDRESS);
+}
+
+void CCECClient::SetPhysicalAddress(const libcec_configuration &configuration)
+{
+ bool bPASet(false);
+
+ // override the physical address from configuration.iPhysicalAddress if it's set
+ if (!bPASet && CLibCEC::IsValidPhysicalAddress(configuration.iPhysicalAddress))
+ bPASet = SetPhysicalAddress(configuration.iPhysicalAddress);
+
+ // try to autodetect the address
+ if (!bPASet && m_processor->CECInitialised())
+ {
+ bPASet = AutodetectPhysicalAddress();
+ if (bPASet)
+ SetDevicePhysicalAddress(m_configuration.iPhysicalAddress);
+ m_configuration.bAutodetectAddress = bPASet ? 1 : 0;
+ }
+
+ // use the base device + hdmi port settings
+ if (!bPASet)
+ bPASet = SetHDMIPort(configuration.baseDevice, configuration.iHDMIPort);
+
+ // reset to defaults if something went wrong
+ if (!bPASet)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - resetting HDMI port and base device to defaults", __FUNCTION__);
+ m_configuration.baseDevice = CECDEVICE_UNKNOWN;
+ m_configuration.iHDMIPort = CEC_HDMI_PORTNUMBER_NONE;
+ }
+}
+
+bool CCECClient::SetPhysicalAddress(const uint16_t iPhysicalAddress)
+{
+ // update the configuration
+ bool bChanged(true);
+ {
+ CLockObject lock(m_mutex);
+ if (m_configuration.iPhysicalAddress == iPhysicalAddress)
+ bChanged = false;
+ else
+ m_configuration.iPhysicalAddress = iPhysicalAddress;
+ }
+ if (!bChanged)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "physical address unchanged (%04X)", iPhysicalAddress);
+ return true;
+ }
+
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "setting physical address to '%04X'", iPhysicalAddress);
+
+ // set the physical address for each device
+ SetDevicePhysicalAddress(iPhysicalAddress);
+
+ // and send back the updated configuration
+ QueueConfigurationChanged(m_configuration);
+
+ return true;
+}
+
+void CCECClient::SetSupportedDeviceTypes(void)
+{
+ cec_device_type_list types;
+ types.Clear();
+
+ // get the command handler for the tv
+ CCECCommandHandler *tvHandler = m_processor->GetTV()->GetHandler();
+ if (!tvHandler)
+ return;
+
+ // check all device types
+ for (uint8_t iPtr = 0; iPtr < 5; iPtr++)
+ {
+ if (m_configuration.deviceTypes.types[iPtr] == CEC_DEVICE_TYPE_RESERVED)
+ continue;
+
+ // get the supported device type. the handler will replace types it doesn't support by one it does support
+ cec_device_type type = tvHandler->GetReplacementDeviceType(m_configuration.deviceTypes.types[iPtr]);
+ if (!types.IsSet(type))
+ types.Add(type);
+ }
+ m_processor->GetTV()->MarkHandlerReady();
+
+ // set the new type list
+ m_configuration.deviceTypes = types;
+
+ // persist the new configuration
+ PersistConfiguration(m_configuration);
+}
+
+bool CCECClient::AllocateLogicalAddresses(void)
+{
+ // reset all previous LAs that were set
+ m_configuration.logicalAddresses.Clear();
+
+ // get the supported device types from the command handler of the TV
+ SetSupportedDeviceTypes();
+
+ // display an error if no device types are set
+ if (m_configuration.deviceTypes.IsEmpty())
+ {
+ LIB_CEC->AddLog(CEC_LOG_ERROR, "no device types given");
+ return false;
+ }
+
+ // check each entry of the list
+ for (uint8_t iPtr = 0; iPtr < 5; iPtr++)
+ {
+ if (m_configuration.deviceTypes.types[iPtr] == CEC_DEVICE_TYPE_RESERVED)
+ continue;
+
+ // find an LA for this type
+ cec_logical_address address(CECDEVICE_UNKNOWN);
+ if (m_configuration.deviceTypes.types[iPtr] == CEC_DEVICE_TYPE_TV)
+ address = CECDEVICE_TV;
+ if (m_configuration.deviceTypes.types[iPtr] == CEC_DEVICE_TYPE_RECORDING_DEVICE)
+ address = AllocateLogicalAddressRecordingDevice();
+ if (m_configuration.deviceTypes.types[iPtr] == CEC_DEVICE_TYPE_TUNER)
+ address = AllocateLogicalAddressTuner();
+ if (m_configuration.deviceTypes.types[iPtr] == CEC_DEVICE_TYPE_PLAYBACK_DEVICE)
+ address = AllocateLogicalAddressPlaybackDevice();
+ if (m_configuration.deviceTypes.types[iPtr] == CEC_DEVICE_TYPE_AUDIO_SYSTEM)
+ address = AllocateLogicalAddressAudioSystem();
+
+ // display an error if no LA could be allocated
+ if (address == CECDEVICE_UNKNOWN)
+ {
+ LIB_CEC->AddLog(CEC_LOG_ERROR, "%s - failed to allocate device '%d', type '%s'", __FUNCTION__, iPtr, ToString(m_configuration.deviceTypes.types[iPtr]));
+ return false;
+ }
+
+ // display the registered LA
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - device '%d', type '%s', LA '%X'", __FUNCTION__, iPtr, ToString(m_configuration.deviceTypes.types[iPtr]), address);
+ m_configuration.logicalAddresses.Set(address);
+ }
+
+ // persist the new configuration
+ PersistConfiguration(m_configuration);
+
+ return true;
+}
+
+cec_logical_address CCECClient::AllocateLogicalAddressRecordingDevice(void)
+{
+ cec_logical_address retVal(CECDEVICE_UNKNOWN);
+
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'recording device'");
+ if (m_processor->TryLogicalAddress(CECDEVICE_RECORDINGDEVICE1, m_configuration.cecVersion))
+ retVal = CECDEVICE_RECORDINGDEVICE1;
+ else if (m_processor->TryLogicalAddress(CECDEVICE_RECORDINGDEVICE2, m_configuration.cecVersion))
+ retVal = CECDEVICE_RECORDINGDEVICE2;
+ else if (m_processor->TryLogicalAddress(CECDEVICE_RECORDINGDEVICE3, m_configuration.cecVersion))
+ retVal = CECDEVICE_RECORDINGDEVICE3;
+
+ return retVal;
+}
+
+cec_logical_address CCECClient::AllocateLogicalAddressTuner(void)
+{
+ cec_logical_address retVal(CECDEVICE_UNKNOWN);
+
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'tuner'");
+ if (m_processor->TryLogicalAddress(CECDEVICE_TUNER1, m_configuration.cecVersion))
+ retVal = CECDEVICE_TUNER1;
+ else if (m_processor->TryLogicalAddress(CECDEVICE_TUNER2, m_configuration.cecVersion))
+ retVal = CECDEVICE_TUNER2;
+ else if (m_processor->TryLogicalAddress(CECDEVICE_TUNER3, m_configuration.cecVersion))
+ retVal = CECDEVICE_TUNER3;
+ else if (m_processor->TryLogicalAddress(CECDEVICE_TUNER4, m_configuration.cecVersion))
+ retVal = CECDEVICE_TUNER4;
+
+ return retVal;
+}
+
+cec_logical_address CCECClient::AllocateLogicalAddressPlaybackDevice(void)
+{
+ cec_logical_address retVal(CECDEVICE_UNKNOWN);
+
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'playback device'");
+ if (m_processor->TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE1, m_configuration.cecVersion))
+ retVal = CECDEVICE_PLAYBACKDEVICE1;
+ else if (m_processor->TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE2, m_configuration.cecVersion))
+ retVal = CECDEVICE_PLAYBACKDEVICE2;
+ else if (m_processor->TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE3, m_configuration.cecVersion))
+ retVal = CECDEVICE_PLAYBACKDEVICE3;
+
+ return retVal;
+}
+
+cec_logical_address CCECClient::AllocateLogicalAddressAudioSystem(void)
+{
+ cec_logical_address retVal(CECDEVICE_UNKNOWN);
+
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'audiosystem'");
+ if (m_processor->TryLogicalAddress(CECDEVICE_AUDIOSYSTEM, m_configuration.cecVersion))
+ retVal = CECDEVICE_AUDIOSYSTEM;
+
+ return retVal;
+}
+
+CCECBusDevice *CCECClient::GetDeviceByType(const cec_device_type type) const
+{
+ // get all devices that match our logical addresses
+ CECDEVICEVEC devices;
+ m_processor->GetDevices()->GetByLogicalAddresses(devices, m_configuration.logicalAddresses);
+
+ // filter the type we need
+ CCECDeviceMap::FilterType(type, devices);
+
+ return devices.empty() ?
+ NULL :
+ *devices.begin();
+}
+
+bool CCECClient::ChangeDeviceType(const cec_device_type from, const cec_device_type to)
+{
+ if (from == to)
+ return true;
+
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, "changing device type '%s' into '%s'", ToString(from), ToString(to));
+
+ {
+ CLockObject lock(m_mutex);
+
+ // get the previous device that was allocated
+ CCECBusDevice *previousDevice = GetDeviceByType(from);
+ if (!previousDevice)
+ return false;
+
+ // change the type in the device type list
+ bool bChanged(false);
+ for (uint8_t iPtr = 0; iPtr < 5; iPtr++)
+ {
+ if (m_configuration.deviceTypes.types[iPtr] == CEC_DEVICE_TYPE_RESERVED)
+ continue;
+
+ if (m_configuration.deviceTypes.types[iPtr] == from)
+ {
+ bChanged = true;
+ m_configuration.deviceTypes.types[iPtr] = to;
+ }
+ else if (m_configuration.deviceTypes.types[iPtr] == to && bChanged)
+ {
+ // ensure that dupes are removed
+ m_configuration.deviceTypes.types[iPtr] = CEC_DEVICE_TYPE_RESERVED;
+ }
+ }
+ }
+
+ // re-register the client to set the new ackmask
+ if (!m_processor->RegisterClient(this))
+ return false;
+
+ // persist the new configuration
+ PersistConfiguration(m_configuration);
+
+ return true;
+}
+
+bool CCECClient::SetLogicalAddress(const cec_logical_address iLogicalAddress)
+{
+ bool bReturn(true);
+
+ if (GetPrimaryLogicalAddress() != iLogicalAddress)
+ {
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, "setting primary logical address to %1x", iLogicalAddress);
+ {
+ CLockObject lock(m_mutex);
+ m_configuration.logicalAddresses.primary = iLogicalAddress;
+ m_configuration.logicalAddresses.Set(iLogicalAddress);
+ }
+
+ bReturn = m_processor->RegisterClient(this);
+
+ // persist the new configuration
+ if (bReturn)
+ PersistConfiguration(m_configuration);
+ }
+
+ return bReturn;
+}
+
+bool CCECClient::Transmit(const cec_command &data, bool bIsReply)
+{
+ return m_processor ? m_processor->Transmit(data, bIsReply) : false;
+}
+
+bool CCECClient::SendPowerOnDevices(const cec_logical_address address /* = CECDEVICE_TV */)
+{
+ // if the broadcast address if set as destination, read the wakeDevices setting
+ if (address == CECDEVICE_BROADCAST)
+ {
+ CECDEVICEVEC devices;
+ m_processor->GetDevices()->GetWakeDevices(m_configuration, devices);
+ return m_processor->PowerOnDevices(GetPrimaryLogicalAddress(), devices);
+ }
+
+ return m_processor->PowerOnDevice(GetPrimaryLogicalAddress(), address);
+}
+
+bool CCECClient::SendStandbyDevices(const cec_logical_address address /* = CECDEVICE_BROADCAST */)
+{
+ // if the broadcast address if set as destination, read the standbyDevices setting
+ if (address == CECDEVICE_BROADCAST)
+ {
+ CECDEVICEVEC devices;
+ m_processor->GetDevices()->GetPowerOffDevices(m_configuration, devices);
+ return m_processor->StandbyDevices(GetPrimaryLogicalAddress(), devices);
+ }
+
+ return m_processor->StandbyDevice(GetPrimaryLogicalAddress(), address);
+}
+
+bool CCECClient::SendSetActiveSource(const cec_device_type type /* = CEC_DEVICE_TYPE_RESERVED */)
+{
+ // get the devices that are controlled by us
+ CECDEVICEVEC devices;
+ m_processor->GetDevices()->GetByLogicalAddresses(devices, m_configuration.logicalAddresses);
+
+ // filter out the device that matches the given type
+ if (type != CEC_DEVICE_TYPE_RESERVED)
+ CCECDeviceMap::FilterType(type, devices);
+
+ // no devices left, re-fetch the list of devices that are controlled by us
+ if (devices.empty())
+ m_processor->GetDevices()->GetByLogicalAddresses(devices, m_configuration.logicalAddresses);
+
+ if (!devices.empty())
+ {
+ // get the first device from the list
+ CCECBusDevice *device = *devices.begin();
+
+ // and activate it
+ if (!m_processor->CECInitialised())
+ device->MarkAsActiveSource();
+ else if (device->HasValidPhysicalAddress())
+ return device->ActivateSource();
+ }
+
+ return false;
+}
+
+CCECPlaybackDevice *CCECClient::GetPlaybackDevice(void)
+{
+ CCECPlaybackDevice *device(NULL);
+ CECDEVICEVEC devices;
+
+ // get the playback devices
+ m_processor->GetDevices()->GetByLogicalAddresses(devices, m_configuration.logicalAddresses);
+ CCECDeviceMap::FilterType(CEC_DEVICE_TYPE_PLAYBACK_DEVICE, devices);
+
+ // no matches, get the recording devices
+ if (devices.empty())
+ {
+ m_processor->GetDevices()->GetByLogicalAddresses(devices, m_configuration.logicalAddresses);
+ CCECDeviceMap::FilterType(CEC_DEVICE_TYPE_RECORDING_DEVICE, devices);
+ }
+
+ // get the first device that matches, and cast it to CCECPlaybackDevice
+ if (!devices.empty())
+ device = (*devices.begin())->AsPlaybackDevice();
+
+ return device;
+}
+
+cec_logical_address CCECClient::GetPrimaryLogicalAddress(void)
+{
+ CLockObject lock(m_mutex);
+ return m_configuration.logicalAddresses.primary;
+}
+
+CCECBusDevice *CCECClient::GetPrimaryDevice(void)
+{
+ return m_processor->GetDevice(GetPrimaryLogicalAddress());
+}
+
+bool CCECClient::SendSetDeckControlMode(const cec_deck_control_mode mode, bool bSendUpdate /* = true */)
+{
+ // find a playback device that we control
+ CCECPlaybackDevice *device = GetPlaybackDevice();
+ if (device)
+ {
+ // and set the deck control mode if there is a match
+ device->SetDeckControlMode(mode);
+ if (bSendUpdate)
+ return device->TransmitDeckStatus(CECDEVICE_TV, false);
+ return true;
+ }
+
+ // no match
+ return false;
+}
+
+bool CCECClient::SendSetDeckInfo(const cec_deck_info info, bool bSendUpdate /* = true */)
+{
+ // find a playback device that we control
+ CCECPlaybackDevice *device = GetPlaybackDevice();
+ if (device)
+ {
+ // and set the deck status if there is a match
+ device->SetDeckStatus(info);
+ if (bSendUpdate)
+ return device->AsPlaybackDevice()->TransmitDeckStatus(CECDEVICE_TV, false);
+ return true;
+ }
+
+ // no match
+ return false;
+}
+
+bool CCECClient::SendSetMenuState(const cec_menu_state state, bool bSendUpdate /* = true */)
+{
+ CECDEVICEVEC devices;
+
+ // set the menu state for all devices that are controlled by us
+ m_processor->GetDevices()->GetByLogicalAddresses(devices, m_configuration.logicalAddresses);
+ for (CECDEVICEVEC::iterator it = devices.begin(); it != devices.end(); it++)
+ {
+ (*it)->SetMenuState(state);
+ if (bSendUpdate)
+ (*it)->TransmitMenuState(CECDEVICE_TV, false);
+ }
+
+ return true;
+}
+
+bool CCECClient::SendSetInactiveView(void)
+{
+ CECDEVICEVEC devices;
+
+ // mark all devices that are controlled by us as inactive source
+ m_processor->GetDevices()->GetByLogicalAddresses(devices, m_configuration.logicalAddresses);
+ for (CECDEVICEVEC::iterator it = devices.begin(); it != devices.end(); it++)
+ {
+ if ((*it)->IsActiveSource())
+ {
+ (*it)->MarkAsInactiveSource();
+ return (*it)->TransmitInactiveSource();
+ }
+ }
+
+ return true;
+}
+
+bool CCECClient::SendSetOSDString(const cec_logical_address iLogicalAddress, const cec_display_control duration, const char *strMessage)
+{
+ CCECBusDevice *primary = GetPrimaryDevice();
+ if (primary)
+ return primary->TransmitOSDString(iLogicalAddress, duration, strMessage, false);
+
+ return false;
+}
+
+cec_version CCECClient::GetDeviceCecVersion(const cec_logical_address iAddress)
+{
+ CCECBusDevice *device = m_processor->GetDevice(iAddress);
+ if (device)
+ return device->GetCecVersion(GetPrimaryLogicalAddress());
+ return CEC_VERSION_UNKNOWN;
+}
+
+std::string CCECClient::GetDeviceMenuLanguage(const cec_logical_address iAddress)
+{
+ CCECBusDevice *device = m_processor->GetDevice(iAddress);
+ return !!device ?
+ device->GetMenuLanguage(GetPrimaryLogicalAddress()) :
+ "??";
+}
+
+std::string CCECClient::GetDeviceOSDName(const cec_logical_address iAddress)
+{
+ CCECBusDevice *device = m_processor->GetDevice(iAddress);
+ return !!device?
+ device->GetOSDName(GetPrimaryLogicalAddress()) :
+ "";
+}
+
+uint16_t CCECClient::GetDevicePhysicalAddress(const cec_logical_address iAddress)
+{
+ CCECBusDevice *device = m_processor->GetDevice(iAddress);
+ if (device)
+ return device->GetPhysicalAddress(GetPrimaryLogicalAddress());
+ return CEC_INVALID_PHYSICAL_ADDRESS;
+}
+
+cec_power_status CCECClient::GetDevicePowerStatus(const cec_logical_address iAddress)
+{
+ CCECBusDevice *device = m_processor->GetDevice(iAddress);
+ if (device)
+ return device->GetPowerStatus(GetPrimaryLogicalAddress());
+ return CEC_POWER_STATUS_UNKNOWN;
+}
+
+uint32_t CCECClient::GetDeviceVendorId(const cec_logical_address iAddress)
+{
+ CCECBusDevice *device = m_processor->GetDevice(iAddress);
+ if (device)
+ return device->GetVendorId(GetPrimaryLogicalAddress());
+ return CEC_VENDOR_UNKNOWN;
+}
+
+uint8_t CCECClient::SendVolumeUp(bool bSendRelease /* = true */)
+{
+ cec_logical_address primary(GetPrimaryLogicalAddress());
+ CCECAudioSystem* audio(m_processor->GetAudioSystem());
+
+ if (primary == CECDEVICE_UNKNOWN)
+ return (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
+
+ if (!audio || !audio->IsPresent())
+ {
+ CCECTV* tv(m_processor->GetTV());
+ tv->TransmitVolumeUp(primary, bSendRelease);
+ return (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
+ }
+ else
+ {
+ return audio->VolumeUp(primary, bSendRelease);
+ }
+}
+
+uint8_t CCECClient::SendVolumeDown(bool bSendRelease /* = true */)
+{
+ cec_logical_address primary(GetPrimaryLogicalAddress());
+ CCECAudioSystem* audio(m_processor->GetAudioSystem());
+
+ if (primary == CECDEVICE_UNKNOWN)
+ return (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
+
+ if (!audio || !audio->IsPresent())
+ {
+ CCECTV* tv(m_processor->GetTV());
+ tv->TransmitVolumeDown(primary, bSendRelease);
+ return (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
+ }
+ else
+ {
+ return audio->VolumeDown(primary, bSendRelease);
+ }
+}
+
+uint8_t CCECClient::SendMuteAudio(void)
+{
+ cec_logical_address primary(GetPrimaryLogicalAddress());
+ CCECAudioSystem* audio(m_processor->GetAudioSystem());
+
+ if (primary == CECDEVICE_UNKNOWN)
+ return (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
+
+ if (!audio || !audio->IsPresent())
+ {
+ CCECTV* tv(m_processor->GetTV());
+ tv->TransmitMuteAudio(primary);
+ return (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
+ }
+ else
+ {
+ return audio->MuteAudio(primary);
+ }
+
+}
+
+uint8_t CCECClient::AudioToggleMute(void)
+{
+ CCECBusDevice *device = GetPrimaryDevice();
+ CCECAudioSystem *audio = m_processor->GetAudioSystem();
+
+ return device && audio && audio->IsPresent() ?
+ audio->MuteAudio(device->GetLogicalAddress()) :
+ (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
+}
+
+uint8_t CCECClient::AudioMute(void)
+{
+ CCECBusDevice *device = GetPrimaryDevice();
+ CCECAudioSystem *audio = m_processor->GetAudioSystem();
+ uint8_t iStatus = device && audio && audio->IsPresent() ? audio->GetAudioStatus(device->GetLogicalAddress()) : (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
+ if ((iStatus & CEC_AUDIO_MUTE_STATUS_MASK) != CEC_AUDIO_MUTE_STATUS_MASK)
+ iStatus = audio->MuteAudio(device->GetLogicalAddress());
+
+ return iStatus;
+}
+
+uint8_t CCECClient::AudioUnmute(void)
+{
+ CCECBusDevice *device = GetPrimaryDevice();
+ CCECAudioSystem *audio = m_processor->GetAudioSystem();
+ uint8_t iStatus = device && audio && audio->IsPresent() ? audio->GetAudioStatus(device->GetLogicalAddress()) : (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
+ if ((iStatus & CEC_AUDIO_MUTE_STATUS_MASK) == CEC_AUDIO_MUTE_STATUS_MASK)
+ iStatus = audio->MuteAudio(device->GetLogicalAddress());
+
+ return iStatus;
+}
+
+uint8_t CCECClient::AudioStatus(void)
+{
+ CCECBusDevice *device = GetPrimaryDevice();
+ CCECAudioSystem *audio = m_processor->GetAudioSystem();
+ return device && audio && audio->IsPresent() ? audio->GetAudioStatus(device->GetLogicalAddress()) : (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
+}
+
+bool CCECClient::SendKeypress(const cec_logical_address iDestination, const cec_user_control_code key, bool bWait /* = true */)
+{
+ CCECBusDevice *dest = m_processor->GetDevice(iDestination);
+
+ return dest ?
+ dest->TransmitKeypress(GetPrimaryLogicalAddress(), key, bWait) :
+ false;
+}
+
+bool CCECClient::SendKeyRelease(const cec_logical_address iDestination, bool bWait /* = true */)
+{
+ CCECBusDevice *dest = m_processor->GetDevice(iDestination);
+
+ return dest ?
+ dest->TransmitKeyRelease(GetPrimaryLogicalAddress(), bWait) :
+ false;
+}
+
+bool CCECClient::GetCurrentConfiguration(libcec_configuration &configuration)
+{
+ CLockObject lock(m_mutex);
+
+ snprintf(configuration.strDeviceName, 13, "%s", m_configuration.strDeviceName);
+ configuration.deviceTypes = m_configuration.deviceTypes;
+ configuration.bAutodetectAddress = m_configuration.bAutodetectAddress;
+ configuration.iPhysicalAddress = m_configuration.iPhysicalAddress;
+ configuration.baseDevice = m_configuration.baseDevice;
+ configuration.iHDMIPort = m_configuration.iHDMIPort;
+ configuration.clientVersion = m_configuration.clientVersion;
+ configuration.serverVersion = m_configuration.serverVersion;
+ configuration.tvVendor = m_configuration.tvVendor;
+ configuration.bGetSettingsFromROM = m_configuration.bGetSettingsFromROM;
+ configuration.bActivateSource = m_configuration.bActivateSource;
+ configuration.wakeDevices = m_configuration.wakeDevices;
+ configuration.powerOffDevices = m_configuration.powerOffDevices;
+ configuration.logicalAddresses = m_configuration.logicalAddresses;
+ configuration.iFirmwareVersion = m_configuration.iFirmwareVersion;
+ memcpy(configuration.strDeviceLanguage, m_configuration.strDeviceLanguage, 3);
+ configuration.iFirmwareBuildDate = m_configuration.iFirmwareBuildDate;
+ configuration.bMonitorOnly = m_configuration.bMonitorOnly;
+ configuration.cecVersion = m_configuration.cecVersion;
+ configuration.adapterType = m_configuration.adapterType;
+ configuration.iDoubleTapTimeoutMs = m_configuration.iDoubleTapTimeoutMs;
+ configuration.iButtonRepeatRateMs = m_configuration.iButtonRepeatRateMs;
+ configuration.iButtonReleaseDelayMs = m_configuration.iButtonReleaseDelayMs;
+ configuration.bAutoWakeAVR = m_configuration.bAutoWakeAVR;
+
+ return true;
+}
+
+bool CCECClient::SetConfiguration(const libcec_configuration &configuration)
+{
+ libcec_configuration defaultSettings;
+ bool bIsRunning(m_processor && m_processor->CECInitialised());
+ CCECBusDevice *primary = bIsRunning ? GetPrimaryDevice() : NULL;
+ uint16_t iPA = primary ? primary->GetCurrentPhysicalAddress() : CEC_INVALID_PHYSICAL_ADDRESS;
+
+ // update the callbacks
+ if (configuration.callbacks)
+ EnableCallbacks(configuration.callbackParam, configuration.callbacks);
+
+ // update the client version
+ SetClientVersion(configuration.clientVersion);
+
+ // update the OSD name
+ std::string strOSDName(configuration.strDeviceName);
+ SetOSDName(strOSDName);
+
+ // update the TV vendor override
+ SetTVVendorOverride((cec_vendor_id)configuration.tvVendor);
+
+ // just copy these
+ {
+ CLockObject lock(m_mutex);
+ m_configuration.bActivateSource = configuration.bActivateSource;
+ m_configuration.bGetSettingsFromROM = configuration.bGetSettingsFromROM;
+ m_configuration.wakeDevices = configuration.wakeDevices;
+ m_configuration.powerOffDevices = configuration.powerOffDevices;
+ memcpy(m_configuration.strDeviceLanguage, configuration.strDeviceLanguage, 3);
+ m_configuration.bMonitorOnly = configuration.bMonitorOnly;
+ m_configuration.cecVersion = configuration.cecVersion;
+ m_configuration.adapterType = configuration.adapterType;
+ m_configuration.iDoubleTapTimeoutMs = configuration.iDoubleTapTimeoutMs;
+ m_configuration.deviceTypes.Add(configuration.deviceTypes[0]);
+ m_configuration.comboKey = configuration.comboKey;
+ m_configuration.iComboKeyTimeoutMs = configuration.iComboKeyTimeoutMs;
+ m_configuration.iButtonRepeatRateMs = configuration.iButtonRepeatRateMs;
+ m_configuration.iButtonReleaseDelayMs = configuration.iButtonReleaseDelayMs;
+ m_configuration.bAutoWakeAVR = configuration.bAutoWakeAVR;
+ }
+
+ bool bNeedReinit(false);
+
+ // device types
+ if (SetDeviceTypes(configuration.deviceTypes))
+ {
+ // the device type changed. just copy the rest, and re-register
+ {
+ CLockObject lock(m_mutex);
+ m_configuration.iPhysicalAddress = configuration.iPhysicalAddress;
+ m_configuration.baseDevice = configuration.baseDevice;
+ m_configuration.iHDMIPort = configuration.iHDMIPort;
+ bNeedReinit = true;
+ }
+ }
+ else
+ {
+ // set the physical address
+ SetPhysicalAddress(configuration);
+ }
+
+ // persist the new configuration
+ PersistConfiguration(m_configuration);
+
+ if (!primary)
+ primary = GetPrimaryDevice();
+
+ if (bNeedReinit || !primary || primary->GetCurrentPhysicalAddress() != iPA)
+ {
+ // PA or device type changed
+ m_processor->RegisterClient(this);
+ }
+ else if (primary && configuration.bActivateSource == 1 && bIsRunning && !primary->IsActiveSource())
+ {
+ // activate the source if we're not already the active source
+ primary->ActivateSource();
+ }
+
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s: %d:%d:%d", __FUNCTION__, DoubleTapTimeoutMS(), m_configuration.iButtonRepeatRateMs, m_configuration.iButtonReleaseDelayMs);
+ return true;
+}
+
+void CCECClient::AddCommand(const cec_command &command)
+{
+ // don't forward the standby opcode more than once every 10 seconds
+ if (command.opcode == CEC_OPCODE_STANDBY)
+ {
+ CLockObject lock(m_mutex);
+ if (m_iPreventForwardingPowerOffCommand != 0 &&
+ m_iPreventForwardingPowerOffCommand > GetTimeMs())
+ return;
+ else
+ m_iPreventForwardingPowerOffCommand = GetTimeMs() + CEC_FORWARD_STANDBY_MIN_INTERVAL;
+ }
+
+ if (command.destination == CECDEVICE_BROADCAST || GetLogicalAddresses().IsSet(command.destination))
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, ">> %s (%X) -> %s (%X): %s (%2X)", ToString(command.initiator), command.initiator, ToString(command.destination), command.destination, ToString(command.opcode), command.opcode);
+ CallbackAddCommand(command);
+ }
+}
+
+void CCECClient::AddKey(bool bSendComboKey /* = false */, bool bButtonRelease /* = false */)
+{
+ cec_keypress key;
+ key.keycode = CEC_USER_CONTROL_CODE_UNKNOWN;
+
+ {
+ CLockObject lock(m_mutex);
+ if (m_iCurrentButton != CEC_USER_CONTROL_CODE_UNKNOWN)
+ {
+ unsigned int duration = (unsigned int) (GetTimeMs() - m_updateButtontime);
+ key.duration = (unsigned int) (GetTimeMs() - m_initialButtontime);
+
+ if (duration > m_configuration.iComboKeyTimeoutMs ||
+ m_configuration.iComboKeyTimeoutMs == 0 ||
+ m_iCurrentButton != m_configuration.comboKey ||
+ bSendComboKey)
+ {
+ key.keycode = m_iCurrentButton;
+
+ m_iCurrentButton = CEC_USER_CONTROL_CODE_UNKNOWN;
+ m_initialButtontime = 0;
+ m_updateButtontime = 0;
+ m_repeatButtontime = 0;
+ m_releaseButtontime = 0;
+ m_pressedButtoncount = 0;
+ m_releasedButtoncount = 0;
+ }
+ }
+ }
+
+ // we don't forward releases when supporting repeating keys
+ if (bButtonRelease && m_configuration.iButtonRepeatRateMs)
+ return;
+
+ if (key.keycode != CEC_USER_CONTROL_CODE_UNKNOWN)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "key released: %s (%1x) D:%dms", ToString(key.keycode), key.keycode, key.duration);
+ QueueAddKey(key);
+ }
+}
+
+void CCECClient::AddKey(const cec_keypress &key)
+{
+ if (key.keycode > CEC_USER_CONTROL_CODE_MAX ||
+ key.keycode < CEC_USER_CONTROL_CODE_SELECT)
+ {
+ // send back the previous key if there is one
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "Unexpected key %s (%1x) D:%dms", ToString(key.keycode), key.keycode, key.duration);
+ AddKey();
+ return;
+ }
+ bool isrepeat = false;
+ cec_keypress transmitKey(key);
+ cec_user_control_code comboKey(m_configuration.comboKey);
+
+ {
+ CLockObject lock(m_mutex);
+ if (m_configuration.iComboKeyTimeoutMs > 0 && m_iCurrentButton == comboKey && key.duration == 0)
+ {
+ // stop + ok -> exit
+ if (key.keycode == CEC_USER_CONTROL_CODE_SELECT)
+ transmitKey.keycode = CEC_USER_CONTROL_CODE_EXIT;
+ // stop + pause -> root menu
+ else if (key.keycode == CEC_USER_CONTROL_CODE_PAUSE)
+ transmitKey.keycode = CEC_USER_CONTROL_CODE_ROOT_MENU;
+ // stop + play -> dot (which is handled as context menu in xbmc)
+ else if (key.keycode == CEC_USER_CONTROL_CODE_PLAY)
+ transmitKey.keycode = CEC_USER_CONTROL_CODE_DOT;
+ // default, send back the previous key
+ else
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "Combo key %s (%1x) D%dms:", ToString(key.keycode), key.keycode, key.duration);
+ AddKey(true);
+ }
+ }
+
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "key pressed: %s (%1x) current(%lx) duration(%d)", ToString(transmitKey.keycode), transmitKey.keycode, m_iCurrentButton, key.duration);
+
+ if (m_iCurrentButton == key.keycode)
+ {
+ m_updateButtontime = GetTimeMs();
+ m_releaseButtontime = m_updateButtontime + (m_configuration.iButtonReleaseDelayMs ? m_configuration.iButtonReleaseDelayMs : CEC_BUTTON_TIMEOUT);
+ // want to have seen some updated before considering a repeat
+ if (m_configuration.iButtonRepeatRateMs)
+ {
+ if (!m_repeatButtontime && m_pressedButtoncount > 1)
+ m_repeatButtontime = m_initialButtontime + DoubleTapTimeoutMS();
+ isrepeat = true;
+ }
+ m_pressedButtoncount++;
+ }
+ else
+ {
+ if (m_iCurrentButton != transmitKey.keycode)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "Changed key %s (%1x) D:%dms cur:%lx", ToString(transmitKey.keycode), transmitKey.keycode, transmitKey.duration, m_iCurrentButton);
+ AddKey();
+ }
+ if (key.duration == 0)
+ {
+ m_iCurrentButton = transmitKey.keycode;
+ if (m_iCurrentButton == CEC_USER_CONTROL_CODE_UNKNOWN)
+ {
+ m_initialButtontime = 0;
+ m_updateButtontime = 0;
+ m_repeatButtontime = 0;
+ m_releaseButtontime = 0;
+ m_pressedButtoncount = 0;
+ m_releasedButtoncount = 0;
+ }
+ else
+ {
+ m_initialButtontime = GetTimeMs();
+ m_updateButtontime = m_initialButtontime;
+ m_repeatButtontime = 0; // set this on next update
+ m_releaseButtontime = m_initialButtontime + (m_configuration.iButtonReleaseDelayMs ? m_configuration.iButtonReleaseDelayMs : CEC_BUTTON_TIMEOUT);
+ m_pressedButtoncount = 1;
+ m_releasedButtoncount = 0;
+ }
+ }
+ }
+ }
+
+ if (!isrepeat && (key.keycode != comboKey || key.duration > 0))
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "key pressed: %s (%1x, %d)", ToString(transmitKey.keycode), transmitKey.keycode, transmitKey.duration);
+ QueueAddKey(transmitKey);
+ }
+}
+
+void CCECClient::SetCurrentButton(const cec_user_control_code iButtonCode)
+{
+ // push a keypress to the buffer with 0 duration and another with the duration set when released
+ cec_keypress key;
+ key.duration = 0;
+ key.keycode = iButtonCode;
+
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "SetCurrentButton %s (%1x) D:%dms cur:%lx", ToString(key.keycode), key.keycode, key.duration);
+ AddKey(key);
+}
+
+uint16_t CCECClient::CheckKeypressTimeout(void)
+{
+ // time when we'd like to be called again
+ uint64_t timeout = CEC_PROCESSOR_SIGNAL_WAIT_TIME;
+ cec_keypress key;
+ key.keycode = CEC_USER_CONTROL_CODE_UNKNOWN;
+ key.duration = 0;
+
+ if (m_iCurrentButton == CEC_USER_CONTROL_CODE_UNKNOWN)
+ return (uint16_t)timeout;
+ {
+ CLockObject lock(m_mutex);
+ uint64_t iNow = GetTimeMs();
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s T:%.3f", __FUNCTION__, iNow*1e-3);
+ cec_user_control_code comboKey(m_configuration.comboKey);
+ uint32_t iTimeoutMs(m_configuration.iComboKeyTimeoutMs);
+
+ if (m_iCurrentButton == comboKey && iTimeoutMs > 0 && iNow - m_updateButtontime >= iTimeoutMs)
+ {
+ key.duration = (unsigned int) (iNow - m_initialButtontime);
+ key.keycode = m_iCurrentButton;
+
+ m_iCurrentButton = CEC_USER_CONTROL_CODE_UNKNOWN;
+ m_initialButtontime = 0;
+ m_updateButtontime = 0;
+ m_repeatButtontime = 0;
+ m_releaseButtontime = 0;
+ m_pressedButtoncount = 0;
+ m_releasedButtoncount = 0;
+ }
+ else if (m_iCurrentButton != comboKey && m_releaseButtontime && iNow >= (uint64_t)m_releaseButtontime)
+ {
+ key.duration = (unsigned int) (iNow - m_initialButtontime);
+ key.keycode = CEC_USER_CONTROL_CODE_UNKNOWN;
+
+ m_iCurrentButton = CEC_USER_CONTROL_CODE_UNKNOWN;
+ m_initialButtontime = 0;
+ m_updateButtontime = 0;
+ m_repeatButtontime = 0;
+ m_releaseButtontime = 0;
+ m_pressedButtoncount = 0;
+ m_releasedButtoncount = 0;
+ }
+ else if (m_iCurrentButton != comboKey && m_repeatButtontime && iNow >= (uint64_t)m_repeatButtontime)
+ {
+ key.duration = (unsigned int) (iNow - m_initialButtontime);
+ key.keycode = m_iCurrentButton;
+ m_repeatButtontime = iNow + m_configuration.iButtonRepeatRateMs;
+ timeout = std::min((uint64_t)timeout, m_repeatButtontime - iNow);
+ }
+ else
+ {
+ if (m_iCurrentButton == comboKey && iTimeoutMs > 0)
+ timeout = std::min((uint64_t)timeout, m_updateButtontime - iNow + iTimeoutMs);
+ if (m_iCurrentButton != comboKey && m_releaseButtontime)
+ timeout = std::min((uint64_t)timeout, m_releaseButtontime - iNow);
+ if (m_iCurrentButton != comboKey && m_repeatButtontime)
+ timeout = std::min((uint64_t)timeout, m_repeatButtontime - iNow);
+ if (timeout > CEC_PROCESSOR_SIGNAL_WAIT_TIME)
+ {
+ LIB_CEC->AddLog(CEC_LOG_ERROR, "Unexpected timeout: %d (%.3f %.3f %.3f) k:%02x", timeout, iNow*1e-3, m_updateButtontime*1e-3, m_releaseButtontime*1e-3, m_iCurrentButton);
+ timeout = CEC_PROCESSOR_SIGNAL_WAIT_TIME;
+ }
+ }
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "Key %s: %s (duration:%d) (%1x) timeout:%dms (rel:%d,rep:%d,prs:%d,rel:%d)", ToString(m_iCurrentButton), key.keycode == CEC_USER_CONTROL_CODE_UNKNOWN ? "idle" : m_repeatButtontime ? "repeated" : "released", key.duration,
+ m_iCurrentButton, timeout, (int)(m_releaseButtontime ? m_releaseButtontime - iNow : 0), (int)(m_repeatButtontime ? m_repeatButtontime - iNow : 0), m_pressedButtoncount, m_releasedButtoncount);
+ }
+
+ if (key.keycode != CEC_USER_CONTROL_CODE_UNKNOWN)
+ QueueAddKey(key);
+
+ return (uint16_t)timeout;
+}
+
+bool CCECClient::EnableCallbacks(void *cbParam, ICECCallbacks *callbacks)
+{
+ CLockObject lock(m_cbMutex);
+ m_configuration.callbackParam = cbParam;
+ m_configuration.callbacks = callbacks;
+ return true;
+}
+
+bool CCECClient::PingAdapter(void)
+{
+ return m_processor ? m_processor->PingAdapter() : false;
+}
+
+std::string CCECClient::GetConnectionInfo(void)
+{
+ std::string strLog;
+ strLog = StringUtils::Format("libCEC version = %s, client version = %s, firmware version = %d",
+ CCECTypeUtils::VersionToString(m_configuration.serverVersion).c_str(),
+ CCECTypeUtils::VersionToString(m_configuration.clientVersion).c_str(),
+ m_configuration.iFirmwareVersion);
+ if (m_configuration.iFirmwareBuildDate != CEC_FW_BUILD_UNKNOWN)
+ {
+ time_t buildTime = (time_t)m_configuration.iFirmwareBuildDate;
+ strLog += StringUtils::Format(", firmware build date: %s", asctime(gmtime(&buildTime)));
+ strLog = strLog.substr(0, strLog.length() > 0 ? (size_t)(strLog.length() - 1) : 0); // strip \n added by asctime
+ strLog.append(" +0000");
+ }
+
+ // log the addresses that are being used
+ if (!m_configuration.logicalAddresses.IsEmpty())
+ {
+ strLog.append(", logical address(es) = ");
+ CECDEVICEVEC devices;
+ m_processor->GetDevices()->GetByLogicalAddresses(devices, m_configuration.logicalAddresses);
+ for (CECDEVICEVEC::iterator it = devices.begin(); it != devices.end(); it++)
+ strLog += StringUtils::Format("%s (%X) ", (*it)->GetLogicalAddressName(), (*it)->GetLogicalAddress());
+ }
+
+ if (!CLibCEC::IsValidPhysicalAddress(m_configuration.iPhysicalAddress))
+ strLog += StringUtils::Format(", base device: %s (%X), HDMI port number: %d", ToString(m_configuration.baseDevice), m_configuration.baseDevice, m_configuration.iHDMIPort);
+ uint16_t iPhysicalAddress = GetPrimaryDevice()->GetPhysicalAddress(GetLogicalAddresses().primary, false);
+ strLog += StringUtils::Format(", physical address: %x.%x.%x.%x", (iPhysicalAddress >> 12) & 0xF, (iPhysicalAddress >> 8) & 0xF, (iPhysicalAddress >> 4) & 0xF, iPhysicalAddress & 0xF);
+
+ strLog += StringUtils::Format(", %s", LIB_CEC->GetLibInfo());
+
+ std::string strReturn(strLog.c_str());
+ return strReturn;
+}
+
+void CCECClient::SetTVVendorOverride(const cec_vendor_id id)
+{
+ {
+ CLockObject lock(m_mutex);
+ m_configuration.tvVendor = id;
+ }
+
+ if (id != CEC_VENDOR_UNKNOWN)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - vendor id '%s'", __FUNCTION__, ToString(id));
+
+ CCECBusDevice *tv = m_processor ? m_processor->GetTV() : NULL;
+ if (tv)
+ tv->SetVendorId((uint32_t)id);
+ }
+
+ // persist the new configuration
+ PersistConfiguration(m_configuration);
+}
+
+cec_vendor_id CCECClient::GetTVVendorOverride(void)
+{
+ CLockObject lock(m_mutex);
+ return (cec_vendor_id)m_configuration.tvVendor;
+}
+
+void CCECClient::SetOSDName(const std::string &strDeviceName)
+{
+ {
+ CLockObject lock(m_mutex);
+ snprintf(m_configuration.strDeviceName, 13, "%s", strDeviceName.c_str());
+ }
+
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - using OSD name '%s'", __FUNCTION__, strDeviceName.c_str());
+
+ CCECBusDevice *primary = GetPrimaryDevice();
+ if (primary && primary->GetCurrentOSDName() != strDeviceName.c_str())
+ {
+ primary->SetOSDName(strDeviceName);
+ if (m_processor && m_processor->CECInitialised())
+ primary->TransmitOSDName(CECDEVICE_TV, false);
+ }
+
+ // persist the new configuration
+ PersistConfiguration(m_configuration);
+}
+
+std::string CCECClient::GetOSDName(void)
+{
+ CLockObject lock(m_mutex);
+ std::string strOSDName(m_configuration.strDeviceName);
+ return strOSDName;
+}
+
+void CCECClient::SetWakeDevices(const cec_logical_addresses &addresses)
+{
+ {
+ CLockObject lock(m_mutex);
+ m_configuration.wakeDevices = addresses;
+ }
+ // persist the new configuration
+ PersistConfiguration(m_configuration);
+}
+
+cec_logical_addresses CCECClient::GetWakeDevices(void)
+{
+ CLockObject lock(m_mutex);
+ return m_configuration.wakeDevices;
+}
+
+bool CCECClient::AutodetectPhysicalAddress(void)
+{
+ bool bPhysicalAutodetected(false);
+ uint16_t iPhysicalAddress = m_processor ? m_processor->GetDetectedPhysicalAddress() : CEC_INVALID_PHYSICAL_ADDRESS;
+
+ if (CLibCEC::IsValidPhysicalAddress(iPhysicalAddress) && iPhysicalAddress != 0)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - autodetected physical address '%04X'", __FUNCTION__, iPhysicalAddress);
+
+ CLockObject lock(m_mutex);
+ m_configuration.iPhysicalAddress = iPhysicalAddress;
+ m_configuration.iHDMIPort = CEC_HDMI_PORTNUMBER_NONE;
+ m_configuration.baseDevice = CECDEVICE_UNKNOWN;
+ bPhysicalAutodetected = true;
+ }
+
+ return bPhysicalAutodetected;
+}
+
+void CCECClient::SetClientVersion(uint32_t version)
+{
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - using client version '%s'", __FUNCTION__, CCECTypeUtils::VersionToString(version).c_str());
+
+ CLockObject lock(m_mutex);
+ m_configuration.clientVersion = (uint32_t)version;
+}
+
+uint32_t CCECClient::GetClientVersion(void)
+{
+ CLockObject lock(m_mutex);
+ return m_configuration.clientVersion;
+}
+
+bool CCECClient::SetDeviceTypes(const cec_device_type_list &deviceTypes)
+{
+ bool bNeedReinit(false);
+
+ {
+ CLockObject lock(m_mutex);
+ bNeedReinit = m_processor && m_processor->CECInitialised() &&
+ (m_configuration.deviceTypes != deviceTypes);
+ m_configuration.deviceTypes = deviceTypes;
+ }
+
+ // persist the new configuration
+ PersistConfiguration(m_configuration);
+
+ if (bNeedReinit)
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - using primary device type '%s'", __FUNCTION__, ToString(deviceTypes[0]));
+
+ return bNeedReinit;
+}
+
+cec_device_type_list CCECClient::GetDeviceTypes(void)
+{
+ cec_device_type_list retVal;
+ CLockObject lock(m_mutex);
+ retVal = m_configuration.deviceTypes;
+ return retVal;
+}
+
+bool CCECClient::SetDevicePhysicalAddress(const uint16_t iPhysicalAddress)
+{
+ if (!CLibCEC::IsValidPhysicalAddress(iPhysicalAddress))
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - not setting invalid physical address %04x", __FUNCTION__, iPhysicalAddress);
+ return false;
+ }
+
+ // reconfigure all devices
+ cec_logical_address reactivateSource(CECDEVICE_UNKNOWN);
+ CECDEVICEVEC devices;
+ m_processor->GetDevices()->GetByLogicalAddresses(devices, m_configuration.logicalAddresses);
+ for (CECDEVICEVEC::iterator it = devices.begin(); it != devices.end(); it++)
+ {
+ // if this device was the active source, reactivate it afterwards
+ if ((*it)->IsActiveSource())
+ reactivateSource = (*it)->GetLogicalAddress();
+
+ // mark the device as inactive source
+ if (IsInitialised())
+ (*it)->MarkAsInactiveSource();
+
+ // set the new physical address
+ (*it)->SetPhysicalAddress(iPhysicalAddress);
+
+ // and transmit it
+ if (IsInitialised())
+ (*it)->TransmitPhysicalAddress(false);
+ }
+
+ // reactivate the previous active source
+ if (reactivateSource != CECDEVICE_UNKNOWN &&
+ m_processor->CECInitialised() &&
+ IsInitialised())
+ {
+ CCECBusDevice *device = m_processor->GetDevice(reactivateSource);
+ if (device)
+ device->ActivateSource();
+ }
+
+ // persist the new configuration
+ PersistConfiguration(m_configuration);
+
+ return true;
+}
+
+bool CCECClient::SwitchMonitoring(bool bEnable)
+{
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, "== %s monitoring mode ==", bEnable ? "enabling" : "disabling");
+
+ if (m_processor)
+ {
+ m_processor->SwitchMonitoring(bEnable);
+ m_configuration.bMonitorOnly = bEnable;
+ return bEnable ? true: m_processor->RegisterClient(this);
+ }
+
+ return false;
+}
+
+bool CCECClient::PollDevice(const cec_logical_address iAddress)
+{
+ // try to find the primary device
+ CCECBusDevice *primary = GetPrimaryDevice();
+ // poll the destination, with the primary as source
+ if (primary)
+ return primary->TransmitPoll(iAddress, true);
+
+ return m_processor ? m_processor->PollDevice(iAddress) : false;
+}
+
+cec_logical_addresses CCECClient::GetActiveDevices(void)
+{
+ CECDEVICEVEC activeDevices;
+ if (m_processor)
+ m_processor->GetDevices()->GetActive(activeDevices);
+ return CCECDeviceMap::ToLogicalAddresses(activeDevices);
+}
+
+bool CCECClient::IsActiveDevice(const cec_logical_address iAddress)
+{
+ cec_logical_addresses activeDevices = GetActiveDevices();
+ return activeDevices.IsSet(iAddress);
+}
+
+bool CCECClient::IsActiveDeviceType(const cec_device_type type)
+{
+ CECDEVICEVEC activeDevices;
+ if (m_processor)
+ m_processor->GetDevices()->GetActive(activeDevices);
+ CCECDeviceMap::FilterType(type, activeDevices);
+ return !activeDevices.empty();
+}
+
+cec_logical_address CCECClient::GetActiveSource(void)
+{
+ return m_processor ? m_processor->GetActiveSource() : CECDEVICE_UNKNOWN;
+}
+
+bool CCECClient::IsActiveSource(const cec_logical_address iAddress)
+{
+ return m_processor ? m_processor->IsActiveSource(iAddress) : false;
+}
+
+bool CCECClient::SetStreamPath(const cec_logical_address iAddress)
+{
+ uint16_t iPhysicalAddress = GetDevicePhysicalAddress(iAddress);
+ if (iPhysicalAddress != CEC_INVALID_PHYSICAL_ADDRESS)
+ return SetStreamPath(iPhysicalAddress);
+ return false;
+}
+
+bool CCECClient::SetStreamPath(const uint16_t iPhysicalAddress)
+{
+ bool bReturn(false);
+
+ CCECBusDevice *device = GetDeviceByType(CEC_DEVICE_TYPE_TV);
+ if (device)
+ {
+ device->SetStreamPath(iPhysicalAddress);
+ bReturn = device->GetHandler()->TransmitSetStreamPath(iPhysicalAddress, false);
+ device->MarkHandlerReady();
+ }
+ else
+ {
+ LIB_CEC->AddLog(CEC_LOG_ERROR, "only the TV is allowed to send CEC_OPCODE_SET_STREAM_PATH");
+ }
+
+ return bReturn;
+}
+
+cec_logical_addresses CCECClient::GetLogicalAddresses(void)
+{
+ cec_logical_addresses addresses;
+ CLockObject lock(m_mutex);
+ addresses = m_configuration.logicalAddresses;
+ return addresses;
+}
+
+bool CCECClient::CanPersistConfiguration(void)
+{
+ return m_processor ? m_processor->CanPersistConfiguration() : false;
+}
+
+bool CCECClient::PersistConfiguration(const libcec_configuration &configuration)
+{
+ return m_processor && IsRegistered() ?
+ m_processor->PersistConfiguration(configuration) :
+ false;
+}
+
+void CCECClient::RescanActiveDevices(void)
+{
+ if (m_processor)
+ m_processor->RescanActiveDevices();
+}
+
+bool CCECClient::IsLibCECActiveSource(void)
+{
+ bool bReturn(false);
+ if (m_processor)
+ {
+ cec_logical_address activeSource = m_processor->GetActiveSource();
+ CCECBusDevice *device = m_processor->GetDevice(activeSource);
+ if (device)
+ bReturn = device->IsHandledByLibCEC() && !device->GetHandler()->ActiveSourcePending();
+ }
+ return bReturn;
+}
+
+void CCECClient::SourceActivated(const cec_logical_address logicalAddress)
+{
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, ">> source activated: %s (%x)", ToString(logicalAddress), logicalAddress);
+ QueueSourceActivated(true, logicalAddress);
+}
+
+void CCECClient::SourceDeactivated(const cec_logical_address logicalAddress)
+{
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, ">> source deactivated: %s (%x)", ToString(logicalAddress), logicalAddress);
+ QueueSourceActivated(false, logicalAddress);
+}
+
+void CCECClient::CallbackAddCommand(const cec_command &command)
+{
+ CLockObject lock(m_cbMutex);
+ if (m_configuration.callbacks && !!m_configuration.callbacks->commandReceived)
+ m_configuration.callbacks->commandReceived(m_configuration.callbackParam, &command);
+}
+
+uint32_t CCECClient::DoubleTapTimeoutMS(void)
+{
+ CLockObject lock(m_cbMutex);
+ return m_configuration.iDoubleTapTimeoutMs;
+}
+
+void CCECClient::QueueAddCommand(const cec_command& command)
+{
+ m_callbackCalls.Push(new CCallbackWrap(command));
+}
+
+void CCECClient::QueueAddKey(const cec_keypress& key)
+{
+ m_callbackCalls.Push(new CCallbackWrap(key));
+}
+
+void CCECClient::QueueAddLog(const cec_log_message_cpp& message)
+{
+ m_callbackCalls.Push(new CCallbackWrap(message));
+}
+
+void CCECClient::QueueAlert(const libcec_alert type, const libcec_parameter& param)
+{
+ m_callbackCalls.Push(new CCallbackWrap(type, param));
+}
+
+void CCECClient::QueueConfigurationChanged(const libcec_configuration& config)
+{
+ m_callbackCalls.Push(new CCallbackWrap(config));
+}
+
+int CCECClient::QueueMenuStateChanged(const cec_menu_state newState)
+{
+ CCallbackWrap *wrapState = new CCallbackWrap(newState, true);
+ m_callbackCalls.Push(wrapState);
+ int result(wrapState->Result(1000));
+
+ delete wrapState;
+ return result;
+}
+
+void CCECClient::QueueSourceActivated(bool bActivated, const cec_logical_address logicalAddress)
+{
+ m_callbackCalls.Push(new CCallbackWrap(bActivated, logicalAddress));
+}
+
+void* CCECClient::Process(void)
+{
+ CCallbackWrap* cb(NULL);
+ while (!IsStopped())
+ {
+ if (m_callbackCalls.Pop(cb, 500))
+ {
+ switch (cb->m_type)
+ {
+ case CCallbackWrap::CEC_CB_LOG_MESSAGE:
+ CallbackAddLog(cb->m_message);
+ break;
+ case CCallbackWrap::CEC_CB_KEY_PRESS:
+ CallbackAddKey(cb->m_key);
+ break;
+ case CCallbackWrap::CEC_CB_COMMAND:
+ AddCommand(cb->m_command);
+ break;
+ case CCallbackWrap::CEC_CB_ALERT:
+ CallbackAlert(cb->m_alertType, cb->m_alertParam);
+ break;
+ case CCallbackWrap::CEC_CB_CONFIGURATION:
+ CallbackConfigurationChanged(cb->m_config);
+ break;
+ case CCallbackWrap::CEC_CB_MENU_STATE:
+ cb->Report(CallbackMenuStateChanged(cb->m_menuState));
+ break;
+ case CCallbackWrap::CEC_CB_SOURCE_ACTIVATED:
+ CallbackSourceActivated(cb->m_bActivated, cb->m_logicalAddress);
+ break;
+ default:
+ break;
+ }
+
+ if (!cb->m_keepResult)
+ delete cb;
+ }
+ }
+ return NULL;
+}
+
+void CCECClient::CallbackAddKey(const cec_keypress &key)
+{
+ CLockObject lock(m_cbMutex);
+ if (m_configuration.callbacks && !!m_configuration.callbacks->keyPress)
+ m_configuration.callbacks->keyPress(m_configuration.callbackParam, &key);
+}
+
+void CCECClient::CallbackAddLog(const cec_log_message_cpp &message)
+{
+ CLockObject lock(m_cbMutex);
+ if (m_configuration.callbacks && !!m_configuration.callbacks->logMessage)
+ {
+ cec_log_message toClient;
+ toClient.level = message.level;
+ toClient.message = message.message.c_str();
+ toClient.time = message.time;
+ m_configuration.callbacks->logMessage(m_configuration.callbackParam, &toClient);
+ }
+}
+
+void CCECClient::CallbackConfigurationChanged(const libcec_configuration &config)
+{
+ CLockObject lock(m_cbMutex);
+ if (m_configuration.callbacks &&
+ !!m_configuration.callbacks->configurationChanged &&
+ m_processor->CECInitialised())
+ m_configuration.callbacks->configurationChanged(m_configuration.callbackParam, &config);
+}
+
+void CCECClient::CallbackSourceActivated(bool bActivated, const cec_logical_address logicalAddress)
+{
+ CLockObject lock(m_cbMutex);
+ if (m_configuration.callbacks && !!m_configuration.callbacks->sourceActivated)
+ m_configuration.callbacks->sourceActivated(m_configuration.callbackParam, logicalAddress, bActivated ? 1 : 0);
+}
+
+void CCECClient::CallbackAlert(const libcec_alert type, const libcec_parameter ¶m)
+{
+ CLockObject lock(m_cbMutex);
+ if (m_configuration.callbacks && !!m_configuration.callbacks->alert)
+ m_configuration.callbacks->alert(m_configuration.callbackParam, type, param);
+}
+
+int CCECClient::CallbackMenuStateChanged(const cec_menu_state newState)
+{
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, ">> %s: %s", ToString(CEC_OPCODE_MENU_REQUEST), ToString(newState));
+
+ CLockObject lock(m_cbMutex);
+ if (m_configuration.callbacks && !!m_configuration.callbacks->menuStateChanged)
+ return m_configuration.callbacks->menuStateChanged(m_configuration.callbackParam, newState);
+ return 0;
+}
+
+bool CCECClient::AudioEnable(bool enable)
+{
+ CCECBusDevice* device = enable ? GetPrimaryDevice() : nullptr;
+ CCECAudioSystem* audio = m_processor->GetAudioSystem();
+
+ return !!audio ?
+ audio->EnableAudio(device) :
+ false;
+}
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include "LibCEC.h"
+#include <string>
+#include <p8-platform/threads/threads.h>
+#include <p8-platform/util/buffer.h>
+#include <p8-platform/threads/mutex.h>
+#include <memory>
+
+namespace CEC
+{
+ class CCECProcessor;
+ class CCECBusDevice;
+ class CCECPlaybackDevice;
+ class CCECClient;
+
+ typedef std::shared_ptr<CCECClient> CECClientPtr;
+
+ class CCallbackWrap
+ {
+ public:
+ CCallbackWrap(const cec_command& command) :
+ m_type(CEC_CB_COMMAND),
+ m_command(command),
+ m_alertType(CEC_ALERT_SERVICE_DEVICE),
+ m_menuState(CEC_MENU_STATE_ACTIVATED),
+ m_bActivated(false),
+ m_logicalAddress(CECDEVICE_UNKNOWN),
+ m_keepResult(false),
+ m_result(0),
+ m_bSucceeded(false) {}
+
+ CCallbackWrap(const cec_keypress& key) :
+ m_type(CEC_CB_KEY_PRESS),
+ m_key(key),
+ m_alertType(CEC_ALERT_SERVICE_DEVICE),
+ m_menuState(CEC_MENU_STATE_ACTIVATED),
+ m_bActivated(false),
+ m_logicalAddress(CECDEVICE_UNKNOWN),
+ m_keepResult(false),
+ m_result(0),
+ m_bSucceeded(false) {}
+
+ CCallbackWrap(const cec_log_message_cpp& message) :
+ m_type(CEC_CB_LOG_MESSAGE),
+ m_message(message),
+ m_alertType(CEC_ALERT_SERVICE_DEVICE),
+ m_menuState(CEC_MENU_STATE_ACTIVATED),
+ m_bActivated(false),
+ m_logicalAddress(CECDEVICE_UNKNOWN),
+ m_keepResult(false),
+ m_result(0),
+ m_bSucceeded(false) {}
+
+ CCallbackWrap(const libcec_alert type, const libcec_parameter& param) :
+ m_type(CEC_CB_ALERT),
+ m_alertType(type),
+ m_alertParam(param),
+ m_menuState(CEC_MENU_STATE_ACTIVATED),
+ m_bActivated(false),
+ m_logicalAddress(CECDEVICE_UNKNOWN),
+ m_keepResult(false),
+ m_result(0),
+ m_bSucceeded(false) {}
+
+ CCallbackWrap(const libcec_configuration& config) :
+ m_type(CEC_CB_CONFIGURATION),
+ m_alertType(CEC_ALERT_SERVICE_DEVICE),
+ m_config(config),
+ m_menuState(CEC_MENU_STATE_ACTIVATED),
+ m_bActivated(false),
+ m_logicalAddress(CECDEVICE_UNKNOWN),
+ m_keepResult(false),
+ m_result(0),
+ m_bSucceeded(false) {}
+
+ CCallbackWrap(const cec_menu_state newState, const bool keepResult = false) :
+ m_type(CEC_CB_MENU_STATE),
+ m_alertType(CEC_ALERT_SERVICE_DEVICE),
+ m_menuState(newState),
+ m_bActivated(false),
+ m_logicalAddress(CECDEVICE_UNKNOWN),
+ m_keepResult(keepResult),
+ m_result(0),
+ m_bSucceeded(false) {}
+
+ CCallbackWrap(bool bActivated, const cec_logical_address logicalAddress) :
+ m_type(CEC_CB_SOURCE_ACTIVATED),
+ m_alertType(CEC_ALERT_SERVICE_DEVICE),
+ m_menuState(CEC_MENU_STATE_ACTIVATED),
+ m_bActivated(bActivated),
+ m_logicalAddress(logicalAddress),
+ m_keepResult(false),
+ m_result(0),
+ m_bSucceeded(false) {}
+
+ int Result(uint32_t iTimeout)
+ {
+ P8PLATFORM::CLockObject lock(m_mutex);
+
+ bool bReturn = m_bSucceeded ? true : m_condition.Wait(m_mutex, m_bSucceeded, iTimeout);
+ if (bReturn)
+ return m_result;
+ return 0;
+ }
+
+ void Report(int result)
+ {
+ P8PLATFORM::CLockObject lock(m_mutex);
+
+ m_result = result;
+ m_bSucceeded = true;
+ m_condition.Signal();
+ }
+
+ enum callbackWrapType {
+ CEC_CB_LOG_MESSAGE,
+ CEC_CB_KEY_PRESS,
+ CEC_CB_COMMAND,
+ CEC_CB_ALERT,
+ CEC_CB_CONFIGURATION,
+ CEC_CB_MENU_STATE,
+ CEC_CB_SOURCE_ACTIVATED,
+ } m_type;
+
+ cec_command m_command;
+ cec_keypress m_key;
+ cec_log_message_cpp m_message;
+ libcec_alert m_alertType;
+ libcec_parameter m_alertParam;
+ libcec_configuration m_config;
+ cec_menu_state m_menuState;
+ bool m_bActivated;
+ cec_logical_address m_logicalAddress;
+ bool m_keepResult;
+ int m_result;
+ P8PLATFORM::CCondition<bool> m_condition;
+ P8PLATFORM::CMutex m_mutex;
+ bool m_bSucceeded;
+ };
+
+ class CCECClient : private P8PLATFORM::CThread
+ {
+ friend class CCECProcessor;
+
+ public:
+ CCECClient(CCECProcessor *processor, const libcec_configuration &configuration);
+ virtual ~CCECClient(void);
+
+ /*!
+ * @return True when initialised and registered, false otherwise.
+ */
+ virtual bool IsInitialised(void);
+
+ /*!
+ * @return True when registered in the processor, false otherwise.
+ */
+ virtual bool IsRegistered(void);
+
+ /*!
+ * @return The primary logical address that this client is controlling.
+ */
+ virtual cec_logical_address GetPrimaryLogicalAddress(void);
+
+ /*!
+ * @return The primary device that this client is controlling, or NULL if none.
+ */
+ virtual CCECBusDevice *GetPrimaryDevice(void);
+
+ /*!
+ * @return Get the playback device or recording device that this client is controlling, or NULL if none.
+ */
+ virtual CCECPlaybackDevice *GetPlaybackDevice(void);
+
+ /*!
+ * @brief Change one of the device types that this client is controlling into another.
+ * @param from The type to change.
+ * @param to The new value.
+ * @return True when changed, false otherwise.
+ */
+ virtual bool ChangeDeviceType(const cec_device_type from, const cec_device_type to);
+
+ /*!
+ * @brief Get a device that this client is controlling, given it's type.
+ * @param type The type of the device to get.
+ * @return The requested device, or NULL if not found.
+ */
+ virtual CCECBusDevice *GetDeviceByType(const cec_device_type type) const;
+
+ /*!
+ * @brief Reset the physical address from the configuration.
+ */
+ virtual void ResetPhysicalAddress(void);
+
+ /*!
+ * @return A string that describes this client.
+ */
+ virtual std::string GetConnectionInfo(void);
+
+ /*!
+ * @return The current value of the TV vendor override setting.
+ */
+ virtual cec_vendor_id GetTVVendorOverride(void);
+
+ /*!
+ * @return The current value of the OSD name setting.
+ */
+ virtual std::string GetOSDName(void);
+
+ /*!
+ * @return Get the current value of the wake device setting.
+ */
+ virtual cec_logical_addresses GetWakeDevices(void);
+
+ /*!
+ * @return The version of this client.
+ */
+ virtual uint32_t GetClientVersion(void);
+
+ /*!
+ * @return The device types that this client is controlling.
+ */
+ virtual cec_device_type_list GetDeviceTypes(void);
+
+ // client-specific part of ICECAdapter
+ virtual bool EnableCallbacks(void *cbParam, ICECCallbacks *callbacks);
+ virtual bool PingAdapter(void);
+ virtual bool Transmit(const cec_command &data, bool bIsReply);
+ virtual bool SetLogicalAddress(const cec_logical_address iLogicalAddress);
+ virtual bool SetPhysicalAddress(const uint16_t iPhysicalAddress);
+ virtual bool SetHDMIPort(const cec_logical_address iBaseDevice, const uint8_t iPort, bool bForce = false);
+ virtual bool SendPowerOnDevices(const cec_logical_address address = CECDEVICE_TV);
+ virtual bool SendStandbyDevices(const cec_logical_address address = CECDEVICE_BROADCAST);
+ virtual bool SendSetActiveSource(const cec_device_type type = CEC_DEVICE_TYPE_RESERVED);
+ virtual bool SendSetDeckControlMode(const cec_deck_control_mode mode, bool bSendUpdate = true);
+ virtual bool SendSetDeckInfo(const cec_deck_info info, bool bSendUpdate = true);
+ virtual bool SendSetInactiveView(void);
+ virtual bool SendSetMenuState(const cec_menu_state state, bool bSendUpdate = true);
+ virtual bool SendSetOSDString(const cec_logical_address iLogicalAddress, const cec_display_control duration, const char *strMessage);
+ virtual bool SwitchMonitoring(bool bEnable);
+ virtual cec_version GetDeviceCecVersion(const cec_logical_address iAddress);
+ virtual std::string GetDeviceMenuLanguage(const cec_logical_address iAddress);
+ virtual uint32_t GetDeviceVendorId(const cec_logical_address iAddress);
+ virtual cec_power_status GetDevicePowerStatus(const cec_logical_address iAddress);
+ virtual uint16_t GetDevicePhysicalAddress(const cec_logical_address iAddress);
+ virtual bool PollDevice(const cec_logical_address iAddress);
+ virtual cec_logical_addresses GetActiveDevices(void);
+ virtual bool IsActiveDevice(const cec_logical_address iAddress);
+ virtual bool IsActiveDeviceType(const cec_device_type type);
+ virtual uint8_t SendVolumeUp(bool bSendRelease = true);
+ virtual uint8_t SendVolumeDown(bool bSendRelease = true);
+ virtual uint8_t SendMuteAudio(void);
+ virtual uint8_t AudioToggleMute(void);
+ virtual uint8_t AudioMute(void);
+ virtual uint8_t AudioUnmute(void);
+ virtual uint8_t AudioStatus(void);
+ virtual bool SendKeypress(const cec_logical_address iDestination, const cec_user_control_code key, bool bWait = true);
+ virtual bool SendKeyRelease(const cec_logical_address iDestination, bool bWait = true);
+ virtual std::string GetDeviceOSDName(const cec_logical_address iAddress);
+ virtual cec_logical_address GetActiveSource(void);
+ virtual bool IsActiveSource(const cec_logical_address iAddress);
+ virtual bool SetStreamPath(const cec_logical_address iAddress);
+ virtual bool SetStreamPath(const uint16_t iPhysicalAddress);
+ virtual cec_logical_addresses GetLogicalAddresses(void);
+ virtual void RescanActiveDevices(void);
+ virtual bool IsLibCECActiveSource(void);
+ bool AudioEnable(bool enable);
+
+ // configuration
+ virtual bool GetCurrentConfiguration(libcec_configuration &configuration);
+ virtual bool SetConfiguration(const libcec_configuration &configuration);
+ virtual bool CanPersistConfiguration(void);
+ virtual bool PersistConfiguration(const libcec_configuration &configuration);
+ virtual void SetPhysicalAddress(const libcec_configuration &configuration);
+
+ void QueueAddCommand(const cec_command& command);
+ void QueueAddKey(const cec_keypress& key);
+ void QueueAddLog(const cec_log_message_cpp& message);
+ void QueueAlert(const libcec_alert type, const libcec_parameter& param);
+ void QueueConfigurationChanged(const libcec_configuration& config);
+ int QueueMenuStateChanged(const cec_menu_state newState); //TODO
+ void QueueSourceActivated(bool bActivated, const cec_logical_address logicalAddress);
+
+ // callbacks
+ virtual void Alert(const libcec_alert type, const libcec_parameter ¶m) { QueueAlert(type, param); }
+ virtual void AddLog(const cec_log_message_cpp &message) { QueueAddLog(message); }
+ virtual void AddKey(bool bSendComboKey = false, bool bButtonRelease = false);
+ virtual void AddKey(const cec_keypress &key);
+ virtual void SetCurrentButton(const cec_user_control_code iButtonCode);
+ virtual uint16_t CheckKeypressTimeout(void);
+ virtual void SourceActivated(const cec_logical_address logicalAddress);
+ virtual void SourceDeactivated(const cec_logical_address logicalAddress);
+
+ protected:
+ void* Process(void);
+
+ /*!
+ * @brief Register this client in the processor
+ * @return True when registered, false otherwise.
+ */
+ virtual bool OnRegister(void);
+
+ /*!
+ * @brief Called by the processor when this client is unregistered
+ */
+ virtual void OnUnregister(void) { SetRegistered(false); SetInitialised(false); }
+
+ /*!
+ * @brief Set the registered state of this client.
+ * @param bSetTo The new value.
+ */
+ virtual void SetRegistered(bool bSetTo);
+
+ /*!
+ * @brief Set the initialised state of this client.
+ * @param bSetTo The new value
+ */
+ virtual void SetInitialised(bool bSetTo);
+
+ /*!
+ * @brief Change the TV vendor id override setting.
+ * @param id The new value.
+ */
+ virtual void SetTVVendorOverride(const cec_vendor_id id);
+
+ /*!
+ * @brief Change the OSD name of the primary device that this client is controlling.
+ * @param strDeviceName The new value.
+ */
+ virtual void SetOSDName(const std::string &strDeviceName);
+
+ /*!
+ * @brief Change the value of the devices to wake.
+ * @param addresses The new value.
+ */
+ virtual void SetWakeDevices(const cec_logical_addresses &addresses);
+
+ /*!
+ * @brief Change the value of the client version setting.
+ * @param version The new version setting.
+ */
+ virtual void SetClientVersion(uint32_t version);
+
+ /*!
+ * @brief Change the device types that this client is controlling.
+ * @param deviceTypes The new types.
+ * @return True when the client needs to be re-registered to pick up the new setting, false otherwise.
+ */
+ virtual bool SetDeviceTypes(const cec_device_type_list &deviceTypes);
+
+ /*!
+ * @return A pointer to the current configuration of this client.
+ */
+ virtual libcec_configuration *GetConfiguration(void) { return &m_configuration; }
+
+ /*!
+ * @brief Called by the processor when registering this client to allocate the logical addresses.
+ * @return True when the addresses for all types were allocated, false otherwise.
+ */
+ virtual bool AllocateLogicalAddresses(void);
+
+ /*!
+ * @brief Try to allocate a logical address for a recording device controlled by this client.
+ * @return The logical address that was allocated, or CECDEVICE_UNKNOWN if none could be allocated.
+ */
+ virtual cec_logical_address AllocateLogicalAddressRecordingDevice(void);
+
+ /*!
+ * @brief Try to allocate a logical address for a tuner controlled by this client.
+ * @return The logical address that was allocated, or CECDEVICE_UNKNOWN if none could be allocated.
+ */
+ virtual cec_logical_address AllocateLogicalAddressTuner(void);
+
+ /*!
+ * @brief Try to allocate a logical address for a playback device controlled by this client.
+ * @return The logical address that was allocated, or CECDEVICE_UNKNOWN if none could be allocated.
+ */
+ virtual cec_logical_address AllocateLogicalAddressPlaybackDevice(void);
+
+ /*!
+ * @brief Try to allocate a logical address for an audiosystem controlled by this client.
+ * @return The logical address that was allocated, or CECDEVICE_UNKNOWN if none could be allocated.
+ */
+ virtual cec_logical_address AllocateLogicalAddressAudioSystem(void);
+
+ /*!
+ * @brief Change the physical address of the devices controlled by this client.
+ * @param iPhysicalAddress The new physical address.
+ * @return True when changed, false otherwise.
+ */
+ virtual bool SetDevicePhysicalAddress(const uint16_t iPhysicalAddress);
+
+ /*!
+ * @brief Try to autodetect the physical address.
+ * @return True when autodetected (and set in m_configuration), false otherwise.
+ */
+ virtual bool AutodetectPhysicalAddress(void);
+
+ /*!
+ * @brief Replaces all device types in m_configuration by types that are supported by the command handler of the TV
+ */
+ virtual void SetSupportedDeviceTypes(void);
+
+ void AddCommand(const cec_command &command);
+ void CallbackAddCommand(const cec_command& command);
+ void CallbackAddKey(const cec_keypress& key);
+ void CallbackAddLog(const cec_log_message_cpp& message);
+ void CallbackAlert(const libcec_alert type, const libcec_parameter& param);
+ void CallbackConfigurationChanged(const libcec_configuration& config);
+ int CallbackMenuStateChanged(const cec_menu_state newState);
+ void CallbackSourceActivated(bool bActivated, const cec_logical_address logicalAddress);
+
+ uint32_t DoubleTapTimeoutMS(void);
+
+ CCECProcessor * m_processor; /**< a pointer to the processor */
+ libcec_configuration m_configuration; /**< the configuration of this client */
+ bool m_bInitialised; /**< true when initialised, false otherwise */
+ bool m_bRegistered; /**< true when registered in the processor, false otherwise */
+ P8PLATFORM::CMutex m_mutex; /**< mutex for changes to this instance */
+ P8PLATFORM::CMutex m_cbMutex; /**< mutex that is held when doing anything with callbacks */
+ cec_user_control_code m_iCurrentButton; /**< the control code of the button that's currently held down (if any) */
+ int64_t m_initialButtontime; /**< the timestamp when the button was initially pressed (in seconds since epoch), or 0 if none was pressed. */
+ int64_t m_updateButtontime; /**< the timestamp when the button was updated (in seconds since epoch), or 0 if none was pressed. */
+ int64_t m_repeatButtontime; /**< the timestamp when the button will next repeat (in seconds since epoch), or 0 if repeat is disabled. */
+ int64_t m_releaseButtontime; /**< the timestamp when the button will be released (in seconds since epoch), or 0 if none was pressed. */
+ int32_t m_pressedButtoncount; /**< the number of times a button released message has been seen for this press. */
+ int32_t m_releasedButtoncount; /**< the number of times a button pressed message has been seen for this press. */
+ int64_t m_iPreventForwardingPowerOffCommand; /**< prevent forwarding standby commands until this time */
+ P8PLATFORM::SyncedBuffer<CCallbackWrap*> m_callbackCalls;
+ };
+}
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include <p8-platform/threads/mutex.h>
+#include <p8-platform/util/buffer.h>
+
+namespace CEC
+{
+ // a buffer that priotises the input from the TV.
+ // if we need more than this, we'll have to change it into a priority_queue
+ class CCECInputBuffer
+ {
+ public:
+ CCECInputBuffer(void) : m_bHasData(false) {}
+ virtual ~CCECInputBuffer(void)
+ {
+ Broadcast();
+ }
+
+ void Broadcast(void)
+ {
+ P8PLATFORM::CLockObject lock(m_mutex);
+ m_bHasData = true;
+ m_condition.Broadcast();
+ }
+
+ bool Push(const cec_command &command)
+ {
+ bool bReturn(false);
+ P8PLATFORM::CLockObject lock(m_mutex);
+ if (command.initiator == CECDEVICE_TV)
+ bReturn = m_tvInBuffer.Push(command);
+ else
+ bReturn = m_inBuffer.Push(command);
+
+ m_bHasData |= bReturn;
+ if (m_bHasData)
+ m_condition.Signal();
+
+ return bReturn;
+ }
+
+ bool Pop(cec_command &command, uint16_t iTimeout)
+ {
+ bool bReturn(false);
+ P8PLATFORM::CLockObject lock(m_mutex);
+ if (m_tvInBuffer.IsEmpty() && m_inBuffer.IsEmpty() &&
+ !m_condition.Wait(m_mutex, m_bHasData, iTimeout))
+ return bReturn;
+
+ if (m_tvInBuffer.Pop(command))
+ bReturn = true;
+ else if (m_inBuffer.Pop(command))
+ bReturn = true;
+
+ m_bHasData = !m_tvInBuffer.IsEmpty() || !m_inBuffer.IsEmpty();
+ return bReturn;
+ }
+
+ private:
+ P8PLATFORM::CMutex m_mutex;
+ P8PLATFORM::CCondition<volatile bool> m_condition;
+ volatile bool m_bHasData;
+ P8PLATFORM::SyncedBuffer<cec_command> m_tvInBuffer;
+ P8PLATFORM::SyncedBuffer<cec_command> m_inBuffer;
+ };
+};
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include "CECProcessor.h"
+
+#include "adapter/AdapterFactory.h"
+#include "devices/CECBusDevice.h"
+#include "devices/CECAudioSystem.h"
+#include "devices/CECPlaybackDevice.h"
+#include "devices/CECRecordingDevice.h"
+#include "devices/CECTuner.h"
+#include "devices/CECTV.h"
+#include "implementations/CECCommandHandler.h"
+#include "LibCEC.h"
+#include "CECClient.h"
+#include "CECTypeUtils.h"
+#include <p8-platform/util/timeutils.h>
+#include <p8-platform/util/util.h>
+#include <stdio.h>
+
+using namespace CEC;
+using namespace P8PLATFORM;
+
+#define ACTIVE_SOURCE_CHECK_INTERVAL 500
+#define TV_PRESENT_CHECK_INTERVAL 30000
+
+#define ToString(x) CCECTypeUtils::ToString(x)
+
+CCECStandbyProtection::CCECStandbyProtection(CCECProcessor* processor) :
+ m_processor(processor) {}
+CCECStandbyProtection::~CCECStandbyProtection(void) {}
+
+void* CCECStandbyProtection::Process(void)
+{
+ int64_t last = GetTimeMs();
+ int64_t next;
+ while (!IsStopped())
+ {
+ P8PLATFORM::CEvent::Sleep(1000);
+
+ next = GetTimeMs();
+
+ // reset the connection if the clock changed
+ if (next < last || next - last > 10000)
+ {
+ libcec_parameter param;
+ param.paramData = NULL; param.paramType = CEC_PARAMETER_TYPE_UNKOWN;
+ m_processor->GetLib()->Alert(CEC_ALERT_CONNECTION_LOST, param);
+ break;
+ }
+
+ last = next;
+ }
+ return NULL;
+}
+
+CCECProcessor::CCECProcessor(CLibCEC *libcec) :
+ m_bInitialised(false),
+ m_communication(NULL),
+ m_libcec(libcec),
+ m_iStandardLineTimeout(3),
+ m_iRetryLineTimeout(3),
+ m_iLastTransmission(0),
+ m_bMonitor(true),
+ m_addrAllocator(NULL),
+ m_bStallCommunication(false),
+ m_connCheck(NULL)
+{
+ m_busDevices = new CCECDeviceMap(this);
+}
+
+CCECProcessor::~CCECProcessor(void)
+{
+ m_bStallCommunication = false;
+ SAFE_DELETE(m_addrAllocator);
+ Close();
+ SAFE_DELETE(m_busDevices);
+}
+
+bool CCECProcessor::Start(const char *strPort, uint16_t iBaudRate /* = CEC_SERIAL_DEFAULT_BAUDRATE */, uint32_t iTimeoutMs /* = CEC_DEFAULT_CONNECT_TIMEOUT */)
+{
+ CLockObject lock(m_mutex);
+ // open a connection
+ if (!OpenConnection(strPort, iBaudRate, iTimeoutMs))
+ return false;
+
+ // create the processor thread
+ if (!IsRunning())
+ {
+ if (!CreateThread())
+ {
+ m_libcec->AddLog(CEC_LOG_ERROR, "could not create a processor thread");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void CCECProcessor::Close(void)
+{
+ // mark as uninitialised
+ SetCECInitialised(false);
+
+ // stop the processor
+ SAFE_DELETE(m_connCheck);
+ StopThread(-1);
+ m_inBuffer.Broadcast();
+ StopThread();
+
+ // close the connection
+ CLockObject lock(m_mutex);
+ SAFE_DELETE(m_communication);
+}
+
+void CCECProcessor::ResetMembers(void)
+{
+ // close the connection
+ SAFE_DELETE(m_communication);
+
+ // reset the other members to the initial state
+ m_iStandardLineTimeout = 3;
+ m_iRetryLineTimeout = 3;
+ m_iLastTransmission = 0;
+ m_busDevices->ResetDeviceStatus();
+}
+
+bool CCECProcessor::OpenConnection(const char *strPort, uint16_t iBaudRate, uint32_t iTimeoutMs, bool bStartListening /* = true */)
+{
+ bool bReturn(false);
+ CTimeout timeout(iTimeoutMs > 0 ? iTimeoutMs : CEC_DEFAULT_TRANSMIT_WAIT);
+
+ // ensure that a previous connection is closed
+ if (m_communication)
+ Close();
+
+ // reset all member to the initial state
+ ResetMembers();
+
+ // check whether the Close() method deleted any previous connection
+ if (m_communication)
+ {
+ m_libcec->AddLog(CEC_LOG_ERROR, "previous connection could not be closed");
+ return bReturn;
+ }
+
+ // create a new connection
+ m_communication = CAdapterFactory(this->m_libcec).GetInstance(strPort, iBaudRate);
+
+ // open a new connection
+ unsigned iConnectTry(0);
+ while (timeout.TimeLeft() > 0 && (bReturn = m_communication->Open((timeout.TimeLeft() / CEC_CONNECT_TRIES), false, bStartListening)) == false)
+ {
+ m_libcec->AddLog(CEC_LOG_ERROR, "could not open a connection (try %d)", ++iConnectTry);
+ m_communication->Close();
+ CEvent::Sleep(CEC_DEFAULT_CONNECT_RETRY_WAIT);
+ }
+
+ m_libcec->AddLog(CEC_LOG_NOTICE, "connection opened");
+
+ // mark as initialised
+ SetCECInitialised(true);
+
+ return bReturn;
+}
+
+bool CCECProcessor::CECInitialised(void)
+{
+ CLockObject lock(m_mutex);
+ return m_bInitialised;
+}
+
+void CCECProcessor::SetCECInitialised(bool bSetTo /* = true */)
+{
+ {
+ CLockObject lock(m_mutex);
+ m_bInitialised = bSetTo;
+ }
+ if (!bSetTo)
+ UnregisterClients();
+}
+
+bool CCECProcessor::TryLogicalAddress(cec_logical_address address, cec_version libCECSpecVersion /* = CEC_VERSION_1_4 */)
+{
+ // find the device
+ CCECBusDevice *device = m_busDevices->At(address);
+ if (device)
+ {
+ // check if it's already marked as present or used
+ if (device->IsPresent() || device->IsHandledByLibCEC())
+ return false;
+
+ // poll the LA if not
+ return device->TryLogicalAddress(libCECSpecVersion);
+ }
+
+ return false;
+}
+
+void CCECProcessor::ReplaceHandlers(void)
+{
+ CLockObject lock(m_mutex);
+ if (!CECInitialised())
+ return;
+
+ // check each device
+ for (CECDEVICEMAP::iterator it = m_busDevices->Begin(); it != m_busDevices->End(); ++it)
+ it->second->ReplaceHandler(true);
+
+ for (std::vector<device_type_change_t>::const_iterator it = m_deviceTypeChanges.begin(); it != m_deviceTypeChanges.end(); ++it)
+ (*it).client->ChangeDeviceType((*it).from, (*it).to);
+ m_deviceTypeChanges.clear();
+}
+
+void CCECProcessor::ChangeDeviceType(CECClientPtr client, cec_device_type from, cec_device_type to)
+{
+ CLockObject lock(m_mutex);
+ if (!CECInitialised())
+ return;
+ device_type_change_t change = { client, from, to };
+ m_deviceTypeChanges.push_back(change);
+}
+
+bool CCECProcessor::OnCommandReceived(const cec_command &command)
+{
+ return m_inBuffer.Push(command);
+}
+
+void *CCECProcessor::Process(void)
+{
+ uint16_t timeout = CEC_PROCESSOR_SIGNAL_WAIT_TIME;
+ m_libcec->AddLog(CEC_LOG_DEBUG, "processor thread started");
+
+ if (!m_connCheck)
+ m_connCheck = new CCECStandbyProtection(this);
+ m_connCheck->CreateThread();
+
+ cec_command command; command.Clear();
+ CTimeout activeSourceCheck(ACTIVE_SOURCE_CHECK_INTERVAL);
+ CTimeout tvPresentCheck(TV_PRESENT_CHECK_INTERVAL);
+
+ // as long as we're not being stopped and the connection is open
+ while (!IsStopped() && m_communication->IsOpen())
+ {
+ // wait for a new incoming command, and process it
+ if (m_inBuffer.Pop(command, timeout))
+ ProcessCommand(command);
+
+ if (CECInitialised() && !IsStopped())
+ {
+ // check clients for keypress timeouts
+ timeout = m_libcec->CheckKeypressTimeout();
+
+ // check if we need to replace handlers
+ ReplaceHandlers();
+
+ // check whether we need to activate a source, if it failed before
+ if (activeSourceCheck.TimeLeft() == 0)
+ {
+ if (CECInitialised())
+ TransmitPendingActiveSourceCommands();
+ activeSourceCheck.Init(ACTIVE_SOURCE_CHECK_INTERVAL);
+ }
+
+ // check whether the TV is present and responding
+ if (tvPresentCheck.TimeLeft() == 0)
+ {
+ CECClientPtr primary = GetPrimaryClient();
+ // only check whether the tv responds to polls when a client is connected and not in monitoring mode
+ if (primary && primary->GetConfiguration()->bMonitorOnly != 1)
+ {
+ if (!m_busDevices->At(CECDEVICE_TV)->IsPresent())
+ {
+ libcec_parameter param;
+ param.paramType = CEC_PARAMETER_TYPE_STRING;
+ param.paramData = (void*)"TV does not respond to CEC polls";
+ primary->Alert(CEC_ALERT_TV_POLL_FAILED, param);
+ }
+ }
+ tvPresentCheck.Init(TV_PRESENT_CHECK_INTERVAL);
+ }
+ }
+ else
+ timeout = CEC_PROCESSOR_SIGNAL_WAIT_TIME;
+ }
+
+ return NULL;
+}
+
+bool CCECProcessor::ActivateSource(uint16_t iStreamPath)
+{
+ bool bReturn(false);
+
+ // find the device with the given PA
+ CCECBusDevice *device = GetDeviceByPhysicalAddress(iStreamPath);
+ // and make it the active source when found
+ if (device)
+ bReturn = device->ActivateSource();
+ else
+ m_libcec->AddLog(CEC_LOG_DEBUG, "device with PA '%04x' not found", iStreamPath);
+
+ return bReturn;
+}
+
+void CCECProcessor::SetActiveSource(bool bSetTo, bool bClientUnregistered)
+{
+ if (m_communication)
+ m_communication->SetActiveSource(bSetTo, bClientUnregistered);
+}
+
+void CCECProcessor::SetStandardLineTimeout(uint8_t iTimeout)
+{
+ CLockObject lock(m_mutex);
+ m_iStandardLineTimeout = iTimeout;
+}
+
+uint8_t CCECProcessor::GetStandardLineTimeout(void)
+{
+ CLockObject lock(m_mutex);
+ return m_iStandardLineTimeout;
+}
+
+void CCECProcessor::SetRetryLineTimeout(uint8_t iTimeout)
+{
+ CLockObject lock(m_mutex);
+ m_iRetryLineTimeout = iTimeout;
+}
+
+uint8_t CCECProcessor::GetRetryLineTimeout(void)
+{
+ CLockObject lock(m_mutex);
+ return m_iRetryLineTimeout;
+}
+
+bool CCECProcessor::PhysicalAddressInUse(uint16_t iPhysicalAddress)
+{
+ CCECBusDevice *device = GetDeviceByPhysicalAddress(iPhysicalAddress);
+ return device != NULL;
+}
+
+void CCECProcessor::LogOutput(const cec_command &data)
+{
+ std::string strTx;
+
+ // initiator and destination
+ strTx = StringUtils::Format("<< %02x", ((uint8_t)data.initiator << 4) + (uint8_t)data.destination);
+
+ // append the opcode
+ if (data.opcode_set)
+ strTx += StringUtils::Format(":%02x", (uint8_t)data.opcode);
+
+ // append the parameters
+ for (uint8_t iPtr = 0; iPtr < data.parameters.size; iPtr++)
+ strTx += StringUtils::Format(":%02x", data.parameters[iPtr]);
+
+ // and log it
+ m_libcec->AddLog(CEC_LOG_TRAFFIC, strTx.c_str());
+}
+
+bool CCECProcessor::PollDevice(cec_logical_address iAddress)
+{
+ // try to find the primary device
+ CCECBusDevice *primary = GetPrimaryDevice();
+ // poll the destination, with the primary as source
+ if (primary)
+ return primary->TransmitPoll(iAddress, true);
+
+ CCECBusDevice *device = m_busDevices->At(CECDEVICE_UNREGISTERED);
+ if (device)
+ return device->TransmitPoll(iAddress, true);
+
+ return false;
+}
+
+CCECBusDevice *CCECProcessor::GetDeviceByPhysicalAddress(uint16_t iPhysicalAddress, bool bSuppressUpdate /* = true */)
+{
+ return m_busDevices ?
+ m_busDevices->GetDeviceByPhysicalAddress(iPhysicalAddress, bSuppressUpdate) :
+ NULL;
+}
+
+CCECBusDevice *CCECProcessor::GetDevice(cec_logical_address address) const
+{
+ return m_busDevices ?
+ m_busDevices->At(address) :
+ NULL;
+}
+
+cec_logical_address CCECProcessor::GetActiveSource(bool bRequestActiveSource /* = true */)
+{
+ // get the device that is marked as active source from the device map
+ CCECBusDevice *activeSource = m_busDevices->GetActiveSource();
+ if (activeSource)
+ return activeSource->GetLogicalAddress();
+
+ if (bRequestActiveSource)
+ {
+ // request the active source from the bus
+ CCECBusDevice *primary = GetPrimaryDevice();
+ if (primary)
+ {
+ primary->RequestActiveSource();
+ return GetActiveSource(false);
+ }
+ }
+
+ // unknown or none
+ return CECDEVICE_UNKNOWN;
+}
+
+bool CCECProcessor::IsActiveSource(cec_logical_address iAddress)
+{
+ CCECBusDevice *device = m_busDevices->At(iAddress);
+ return device && device->IsActiveSource();
+}
+
+bool CCECProcessor::Transmit(const cec_command &data, bool bIsReply)
+{
+ cec_command transmitData(data);
+ uint8_t iMaxTries(0);
+ bool bRetry(true);
+ uint8_t iTries(0);
+
+ // get the current timeout setting
+ uint8_t iLineTimeout(GetStandardLineTimeout());
+
+ // reset the state of this message to 'unknown'
+ cec_adapter_message_state adapterState = ADAPTER_MESSAGE_STATE_UNKNOWN;
+
+ if (data.initiator == CECDEVICE_UNKNOWN && data.destination == CECDEVICE_UNKNOWN)
+ return false;
+
+ CLockObject lock(m_mutex);
+ if (!m_communication)
+ return false;
+
+ if (!m_communication->SupportsSourceLogicalAddress(transmitData.initiator))
+ {
+ if (transmitData.initiator == CECDEVICE_UNREGISTERED && m_communication->SupportsSourceLogicalAddress(CECDEVICE_FREEUSE))
+ {
+ m_libcec->AddLog(CEC_LOG_DEBUG, "initiator '%s' is not supported by the CEC adapter. using '%s' instead", ToString(transmitData.initiator), ToString(CECDEVICE_FREEUSE));
+ transmitData.initiator = CECDEVICE_FREEUSE;
+ }
+ else
+ {
+ m_libcec->AddLog(CEC_LOG_DEBUG, "initiator '%s' is not supported by the CEC adapter", ToString(transmitData.initiator));
+ return false;
+ }
+ }
+
+ LogOutput(transmitData);
+
+ // find the initiator device
+ CCECBusDevice *initiator = m_busDevices->At(transmitData.initiator);
+ if (!initiator)
+ {
+ m_libcec->AddLog(CEC_LOG_WARNING, "invalid initiator");
+ return false;
+ }
+
+ // find the destination device, if it's not the broadcast address
+ if (transmitData.destination != CECDEVICE_BROADCAST)
+ {
+ // check if the device is marked as handled by libCEC
+ CCECBusDevice *destination = m_busDevices->At(transmitData.destination);
+ if (destination && destination->IsHandledByLibCEC())
+ {
+ // and reject the command if it's trying to send data to a device that is handled by libCEC
+ m_libcec->AddLog(CEC_LOG_WARNING, "not sending data to myself!");
+ return false;
+ }
+ }
+
+ // wait until we finished allocating a new LA if it got lost if this is not a poll
+ if (data.opcode_set)
+ {
+ lock.Unlock();
+ while (m_bStallCommunication) Sleep(5);
+ lock.Lock();
+ }
+
+ m_iLastTransmission = GetTimeMs();
+ // set the number of tries
+ iMaxTries = initiator->GetHandler()->GetTransmitRetries() + 1;
+ initiator->MarkHandlerReady();
+
+ // and try to send the command
+ while (bRetry && ++iTries < iMaxTries)
+ {
+ if (initiator->IsUnsupportedFeature(transmitData.opcode))
+ return false;
+
+ adapterState = !IsStopped() && m_communication && m_communication->IsOpen() ?
+ m_communication->Write(transmitData, bRetry, iLineTimeout, bIsReply) :
+ ADAPTER_MESSAGE_STATE_ERROR;
+ iLineTimeout = m_iRetryLineTimeout;
+ }
+
+ return bIsReply ?
+ adapterState == ADAPTER_MESSAGE_STATE_SENT_ACKED || adapterState == ADAPTER_MESSAGE_STATE_SENT || adapterState == ADAPTER_MESSAGE_STATE_WAITING_TO_BE_SENT :
+ adapterState == ADAPTER_MESSAGE_STATE_SENT_ACKED;
+}
+
+void CCECProcessor::TransmitAbort(cec_logical_address source, cec_logical_address destination, cec_opcode opcode, cec_abort_reason reason /* = CEC_ABORT_REASON_UNRECOGNIZED_OPCODE */)
+{
+ m_libcec->AddLog(CEC_LOG_DEBUG, "<< transmitting abort message");
+
+ cec_command command;
+ cec_command::Format(command, source, destination, CEC_OPCODE_FEATURE_ABORT);
+ command.parameters.PushBack((uint8_t)opcode);
+ command.parameters.PushBack((uint8_t)reason);
+
+ Transmit(command, true);
+}
+
+void CCECProcessor::ProcessCommand(const cec_command &command)
+{
+ // log the command
+ m_libcec->AddLog(CEC_LOG_TRAFFIC, ToString(command).c_str());
+
+ // find the initiator
+ CCECBusDevice *device = m_busDevices->At(command.initiator);
+
+ if (device)
+ device->HandleCommand(command);
+}
+
+bool CCECProcessor::IsPresentDevice(cec_logical_address address)
+{
+ CCECBusDevice *device = m_busDevices->At(address);
+ return device && device->GetStatus() == CEC_DEVICE_STATUS_PRESENT;
+}
+
+bool CCECProcessor::IsPresentDeviceType(cec_device_type type)
+{
+ CECDEVICEVEC devices;
+ m_busDevices->GetByType(type, devices);
+ CCECDeviceMap::FilterActive(devices);
+ return !devices.empty();
+}
+
+uint16_t CCECProcessor::GetDetectedPhysicalAddress(void) const
+{
+ return m_communication ? m_communication->GetPhysicalAddress() : CEC_INVALID_PHYSICAL_ADDRESS;
+}
+
+bool CCECProcessor::ClearLogicalAddresses(void)
+{
+ cec_logical_addresses addresses; addresses.Clear();
+ return SetLogicalAddresses(addresses);
+}
+
+bool CCECProcessor::SetLogicalAddresses(const cec_logical_addresses &addresses)
+{
+ return m_communication ? m_communication->SetLogicalAddresses(addresses) : false;
+}
+
+bool CCECProcessor::StandbyDevices(const cec_logical_address initiator, const CECDEVICEVEC &devices)
+{
+ bool bReturn(true);
+ for (CECDEVICEVEC::const_iterator it = devices.begin(); it != devices.end(); it++)
+ bReturn &= (*it)->Standby(initiator);
+ return bReturn;
+}
+
+bool CCECProcessor::StandbyDevice(const cec_logical_address initiator, cec_logical_address address)
+{
+ CCECBusDevice *device = m_busDevices->At(address);
+ return device ? device->Standby(initiator) : false;
+}
+
+bool CCECProcessor::PowerOnDevices(const cec_logical_address initiator, const CECDEVICEVEC &devices)
+{
+ bool bReturn(true);
+ for (CECDEVICEVEC::const_iterator it = devices.begin(); it != devices.end(); it++)
+ bReturn &= (*it)->PowerOn(initiator);
+ return bReturn;
+}
+
+bool CCECProcessor::PowerOnDevice(const cec_logical_address initiator, cec_logical_address address)
+{
+ CCECBusDevice *device = m_busDevices->At(address);
+ return device ? device->PowerOn(initiator) : false;
+}
+
+bool CCECProcessor::StartBootloader(const char *strPort /* = NULL */)
+{
+ bool bReturn(false);
+ // open a connection if no connection has been opened
+ if (!m_communication && strPort)
+ {
+ CAdapterFactory factory(this->m_libcec);
+ IAdapterCommunication *comm = factory.GetInstance(strPort);
+ CTimeout timeout(CEC_DEFAULT_CONNECT_TIMEOUT);
+ int iConnectTry(0);
+ while (timeout.TimeLeft() > 0 && (bReturn = comm->Open(timeout.TimeLeft() / CEC_CONNECT_TRIES, true)) == false)
+ {
+ m_libcec->AddLog(CEC_LOG_ERROR, "could not open a connection (try %d)", ++iConnectTry);
+ comm->Close();
+ Sleep(CEC_DEFAULT_TRANSMIT_RETRY_WAIT);
+ }
+ if (comm->IsOpen())
+ {
+ bReturn = comm->StartBootloader();
+ SAFE_DELETE(comm);
+ }
+ return bReturn;
+ }
+ else
+ {
+ m_communication->StartBootloader();
+ Close();
+ bReturn = true;
+ }
+
+ return bReturn;
+}
+
+bool CCECProcessor::PingAdapter(void)
+{
+ return m_communication->PingAdapter();
+}
+
+void CCECProcessor::HandlePoll(cec_logical_address initiator, cec_logical_address destination)
+{
+ CCECBusDevice *device = m_busDevices->At(destination);
+ if (device)
+ device->HandlePollFrom(initiator);
+}
+
+bool CCECProcessor::HandleReceiveFailed(cec_logical_address initiator)
+{
+ CCECBusDevice *device = m_busDevices->At(initiator);
+ return !device || !device->HandleReceiveFailed();
+}
+
+bool CCECProcessor::CanPersistConfiguration(void)
+{
+ return m_communication ? m_communication->GetFirmwareVersion() >= 2 : false;
+}
+
+bool CCECProcessor::PersistConfiguration(const libcec_configuration &configuration)
+{
+ libcec_configuration persistConfiguration = configuration;
+ if (!CLibCEC::IsValidPhysicalAddress(configuration.iPhysicalAddress))
+ {
+ CCECBusDevice *device = GetPrimaryDevice();
+ if (device)
+ persistConfiguration.iPhysicalAddress = device->GetCurrentPhysicalAddress();
+ }
+
+ return m_communication ? m_communication->PersistConfiguration(persistConfiguration) : false;
+}
+
+void CCECProcessor::RescanActiveDevices(void)
+{
+ for (CECDEVICEMAP::iterator it = m_busDevices->Begin(); it != m_busDevices->End(); it++)
+ it->second->GetStatus(true);
+}
+
+bool CCECProcessor::GetDeviceInformation(const char *strPort, libcec_configuration *config, uint32_t iTimeoutMs /* = CEC_DEFAULT_CONNECT_TIMEOUT */)
+{
+ if (!OpenConnection(strPort, CEC_SERIAL_DEFAULT_BAUDRATE, iTimeoutMs, false))
+ return false;
+
+ config->iFirmwareVersion = m_communication->GetFirmwareVersion();
+ config->iPhysicalAddress = m_communication->GetPhysicalAddress();
+ config->iFirmwareBuildDate = m_communication->GetFirmwareBuildDate();
+ config->adapterType = m_communication->GetAdapterType();
+
+ Close();
+
+ return true;
+}
+
+bool CCECProcessor::TransmitPendingActiveSourceCommands(void)
+{
+ bool bReturn(true);
+ for (CECDEVICEMAP::iterator it = m_busDevices->Begin(); it != m_busDevices->End(); it++)
+ bReturn &= it->second->TransmitPendingActiveSourceCommands();
+ return bReturn;
+}
+
+CCECTV *CCECProcessor::GetTV(void) const
+{
+ return CCECBusDevice::AsTV(m_busDevices->At(CECDEVICE_TV));
+}
+
+CCECAudioSystem *CCECProcessor::GetAudioSystem(void) const
+{
+ return CCECBusDevice::AsAudioSystem(m_busDevices->At(CECDEVICE_AUDIOSYSTEM));
+}
+
+CCECPlaybackDevice *CCECProcessor::GetPlaybackDevice(cec_logical_address address) const
+{
+ return CCECBusDevice::AsPlaybackDevice(m_busDevices->At(address));
+}
+
+CCECRecordingDevice *CCECProcessor::GetRecordingDevice(cec_logical_address address) const
+{
+ return CCECBusDevice::AsRecordingDevice(m_busDevices->At(address));
+}
+
+CCECTuner *CCECProcessor::GetTuner(cec_logical_address address) const
+{
+ return CCECBusDevice::AsTuner(m_busDevices->At(address));
+}
+
+bool CCECProcessor::AllocateLogicalAddresses(CECClientPtr client)
+{
+ libcec_configuration &configuration = *client->GetConfiguration();
+
+ // mark as unregistered
+ client->SetRegistered(false);
+
+ // unregister this client from the old addresses
+ CECDEVICEVEC devices;
+ m_busDevices->GetByLogicalAddresses(devices, configuration.logicalAddresses);
+ for (CECDEVICEVEC::const_iterator it = devices.begin(); it != devices.end(); it++)
+ {
+ // remove client entry
+ CLockObject lock(m_mutex);
+ m_clients.erase((*it)->GetLogicalAddress());
+ }
+
+ // find logical addresses for this client
+ if (!client->AllocateLogicalAddresses())
+ {
+ m_libcec->AddLog(CEC_LOG_ERROR, "failed to find a free logical address for the client");
+ return false;
+ }
+
+ // refresh the address
+ if (configuration.bAutodetectAddress)
+ client->AutodetectPhysicalAddress();
+
+ // register this client on the new addresses
+ devices.clear();
+ m_busDevices->GetByLogicalAddresses(devices, configuration.logicalAddresses);
+ for (CECDEVICEVEC::const_iterator it = devices.begin(); it != devices.end(); it++)
+ {
+ // set the physical address of the device at this LA
+ if (CLibCEC::IsValidPhysicalAddress(configuration.iPhysicalAddress))
+ (*it)->SetPhysicalAddress(configuration.iPhysicalAddress);
+
+ // replace a previous client
+ CLockObject lock(m_mutex);
+ m_clients.erase((*it)->GetLogicalAddress());
+ m_clients.insert(make_pair((*it)->GetLogicalAddress(), client));
+ }
+
+ // set the new ackmask
+ SetLogicalAddresses(GetLogicalAddresses());
+
+ // resume outgoing communication
+ m_bStallCommunication = false;
+
+ return true;
+}
+
+uint16_t CCECProcessor::GetPhysicalAddressFromEeprom(void)
+{
+ libcec_configuration config; config.Clear();
+ if (m_communication)
+ m_communication->GetConfiguration(config);
+ return config.iPhysicalAddress;
+}
+
+bool CCECProcessor::RegisterClient(CCECClient* client)
+{
+ for (std::map<cec_logical_address, CECClientPtr>::iterator it = m_clients.begin(); it != m_clients.end(); ++it)
+ {
+ if (it->second.get() == client)
+ return RegisterClient(it->second);
+ }
+ return RegisterClient(CECClientPtr(client));
+}
+
+bool CCECProcessor::RegisterClient(CECClientPtr client)
+{
+ if (!client)
+ return false;
+
+ libcec_configuration &configuration = *client->GetConfiguration();
+ if (configuration.bMonitorOnly == 1)
+ return true;
+
+ if (!CECInitialised())
+ {
+ m_libcec->AddLog(CEC_LOG_ERROR, "failed to register a new CEC client: CEC processor is not initialised");
+ return false;
+ }
+
+ // unregister the client first if it's already been marked as registered
+ if (client->IsRegistered())
+ UnregisterClient(client);
+
+ // ensure that controlled mode is enabled
+ m_communication->SetControlledMode(true);
+ m_bMonitor = false;
+
+ // source logical address for requests
+ cec_logical_address sourceAddress(CECDEVICE_UNREGISTERED);
+ if (!m_communication->SupportsSourceLogicalAddress(CECDEVICE_UNREGISTERED))
+ {
+ if (m_communication->SupportsSourceLogicalAddress(CECDEVICE_FREEUSE))
+ sourceAddress = CECDEVICE_FREEUSE;
+ else
+ {
+ m_libcec->AddLog(CEC_LOG_ERROR, "failed to register a new CEC client: both unregistered and free use are not supported by the device");
+ return false;
+ }
+ }
+
+ // ensure that we know the vendor id of the TV
+ CCECBusDevice *tv = GetTV();
+ cec_vendor_id tvVendor(tv->GetVendorId(sourceAddress));
+
+ // wait until the handler is replaced, to avoid double registrations
+ if (tvVendor != CEC_VENDOR_UNKNOWN &&
+ CCECCommandHandler::HasSpecificHandler(tvVendor))
+ {
+ while (!tv->ReplaceHandler(false))
+ CEvent::Sleep(5);
+ }
+
+ // get the configuration from the client
+ m_libcec->AddLog(CEC_LOG_NOTICE, "registering new CEC client - v%s", CCECTypeUtils::VersionToString(configuration.clientVersion).c_str());
+
+ // get the current ackmask, so we can restore it if polling fails
+ cec_logical_addresses previousMask = GetLogicalAddresses();
+
+ // mark as uninitialised
+ client->SetInitialised(false);
+
+ // find logical addresses for this client
+ if (!AllocateLogicalAddresses(client))
+ {
+ m_libcec->AddLog(CEC_LOG_ERROR, "failed to register the new CEC client - cannot allocate the requested device types");
+ SetLogicalAddresses(previousMask);
+ return false;
+ }
+
+ // get the settings from the rom
+ if (configuration.bGetSettingsFromROM == 1)
+ {
+ libcec_configuration config; config.Clear();
+ m_communication->GetConfiguration(config);
+
+ CLockObject lock(m_mutex);
+ if (!config.deviceTypes.IsEmpty())
+ configuration.deviceTypes = config.deviceTypes;
+ if (CLibCEC::IsValidPhysicalAddress(config.iPhysicalAddress))
+ configuration.iPhysicalAddress = config.iPhysicalAddress;
+ snprintf(configuration.strDeviceName, 13, "%s", config.strDeviceName);
+ }
+
+ // set the firmware version and build date
+ configuration.serverVersion = LIBCEC_VERSION_CURRENT;
+ configuration.iFirmwareVersion = m_communication->GetFirmwareVersion();
+ configuration.iFirmwareBuildDate = m_communication->GetFirmwareBuildDate();
+ configuration.adapterType = m_communication->GetAdapterType();
+
+ // mark the client as registered
+ client->SetRegistered(true);
+
+ sourceAddress = client->GetPrimaryLogicalAddress();
+
+ // initialise the client
+ bool bReturn = client->OnRegister();
+
+ // log the new registration
+ std::string strLog;
+ strLog = StringUtils::Format("%s: %s", bReturn ? "CEC client registered" : "failed to register the CEC client", client->GetConnectionInfo().c_str());
+ m_libcec->AddLog(bReturn ? CEC_LOG_NOTICE : CEC_LOG_ERROR, strLog.c_str());
+
+ // display a warning if the firmware can be upgraded
+ if (bReturn && !IsRunningLatestFirmware())
+ {
+ const char *strUpgradeMessage = "The firmware of this adapter can be upgraded. Please visit http://blog.pulse-eight.com/ for more information.";
+ m_libcec->AddLog(CEC_LOG_WARNING, strUpgradeMessage);
+ libcec_parameter param;
+ param.paramData = (void*)strUpgradeMessage; param.paramType = CEC_PARAMETER_TYPE_STRING;
+ client->Alert(CEC_ALERT_SERVICE_DEVICE, param);
+ }
+
+ // ensure that the command handler for the TV is initialised
+ if (bReturn)
+ {
+ CCECCommandHandler *handler = GetTV()->GetHandler();
+ if (handler)
+ handler->InitHandler();
+ GetTV()->MarkHandlerReady();
+ }
+
+ // report our OSD name to the TV, since some TVs don't request it
+ client->GetPrimaryDevice()->TransmitOSDName(CECDEVICE_TV, false);
+
+ // request the power status of the TV
+ tv->RequestPowerStatus(sourceAddress, true, true);
+
+ return bReturn;
+}
+
+bool CCECProcessor::UnregisterClient(CCECClient* client)
+{
+ for (std::map<cec_logical_address, CECClientPtr>::iterator it = m_clients.begin(); it != m_clients.end(); ++it)
+ {
+ if (it->second.get() == client)
+ return UnregisterClient(it->second);
+ }
+ return true;
+}
+
+bool CCECProcessor::UnregisterClient(CECClientPtr client)
+{
+ if (!client)
+ return false;
+
+ if (client->IsRegistered())
+ m_libcec->AddLog(CEC_LOG_NOTICE, "unregistering client: %s", client->GetConnectionInfo().c_str());
+
+ // notify the client that it will be unregistered
+ client->OnUnregister();
+
+ {
+ CLockObject lock(m_mutex);
+ // find all devices that match the LA's of this client
+ CECDEVICEVEC devices;
+ m_busDevices->GetByLogicalAddresses(devices, client->GetConfiguration()->logicalAddresses);
+ for (CECDEVICEVEC::const_iterator it = devices.begin(); it != devices.end(); it++)
+ {
+ // find the client
+ std::map<cec_logical_address, CECClientPtr>::iterator entry = m_clients.find((*it)->GetLogicalAddress());
+ // unregister the client
+ if (entry != m_clients.end())
+ m_clients.erase(entry);
+
+ // reset the device status
+ (*it)->ResetDeviceStatus(true);
+ }
+ }
+
+ // set the new ackmask
+ cec_logical_addresses addresses = GetLogicalAddresses();
+ if (SetLogicalAddresses(addresses))
+ {
+ // no more clients left, disable controlled mode
+ if (addresses.IsEmpty() && !m_bMonitor)
+ m_communication->SetControlledMode(false);
+
+ return true;
+ }
+
+ return false;
+}
+
+void CCECProcessor::UnregisterClients(void)
+{
+ m_libcec->AddLog(CEC_LOG_DEBUG, "unregistering all CEC clients");
+
+ std::vector<CECClientPtr> clients = m_libcec->GetClients();
+ for (std::vector<CECClientPtr>::iterator it = clients.begin(); it != clients.end(); ++it)
+ UnregisterClient(*it);
+}
+
+CECClientPtr CCECProcessor::GetClient(const cec_logical_address address)
+{
+ CLockObject lock(m_mutex);
+ std::map<cec_logical_address, CECClientPtr>::const_iterator client = m_clients.find(address);
+ if (client != m_clients.end())
+ return client->second;
+ return CECClientPtr();
+}
+
+CECClientPtr CCECProcessor::GetPrimaryClient(void)
+{
+ CLockObject lock(m_mutex);
+ std::map<cec_logical_address, CECClientPtr>::const_iterator client = m_clients.begin();
+ if (client != m_clients.end())
+ return client->second;
+ return CECClientPtr();
+}
+
+CCECBusDevice *CCECProcessor::GetPrimaryDevice(void)
+{
+ return m_busDevices->At(GetLogicalAddress());
+}
+
+cec_logical_address CCECProcessor::GetLogicalAddress(void)
+{
+ cec_logical_addresses addresses = GetLogicalAddresses();
+ return addresses.primary;
+}
+
+cec_logical_addresses CCECProcessor::GetLogicalAddresses(void)
+{
+ CLockObject lock(m_mutex);
+ cec_logical_addresses addresses;
+ addresses.Clear();
+ for (std::map<cec_logical_address, CECClientPtr>::const_iterator client = m_clients.begin(); client != m_clients.end(); client++)
+ addresses.Set(client->first);
+
+ return addresses;
+}
+
+bool CCECProcessor::IsHandledByLibCEC(const cec_logical_address address) const
+{
+ CCECBusDevice *device = GetDevice(address);
+ return device && device->IsHandledByLibCEC();
+}
+
+bool CCECProcessor::IsRunningLatestFirmware(void)
+{
+ return m_communication && m_communication->IsOpen() ?
+ m_communication->IsRunningLatestFirmware() :
+ true;
+}
+
+void CCECProcessor::SwitchMonitoring(bool bSwitchTo)
+{
+ {
+ CLockObject lock(m_mutex);
+ m_bMonitor = bSwitchTo;
+ }
+ if (bSwitchTo)
+ UnregisterClients();
+}
+
+void CCECProcessor::HandleLogicalAddressLost(cec_logical_address oldAddress)
+{
+ m_libcec->AddLog(CEC_LOG_NOTICE, "logical address %x was taken by another device, allocating a new address", oldAddress);
+
+ // stall outgoing messages until we know our new LA
+ m_bStallCommunication = true;
+
+ // reset the TV and the previous address
+ GetTV()->SetDeviceStatus(CEC_DEVICE_STATUS_UNKNOWN);
+ if (oldAddress < CECDEVICE_BROADCAST)
+ m_busDevices->At(oldAddress)->SetDeviceStatus(CEC_DEVICE_STATUS_UNKNOWN);
+
+ // try to detect the vendor id
+ GetTV()->GetVendorId(CECDEVICE_UNREGISTERED);
+
+ CECClientPtr client = GetClient(oldAddress);
+ if (!client)
+ client = GetPrimaryClient();
+ if (client)
+ {
+ if (m_addrAllocator)
+ while (m_addrAllocator->IsRunning()) Sleep(5);
+ delete m_addrAllocator;
+
+ m_addrAllocator = new CCECAllocateLogicalAddress(this, client);
+ m_addrAllocator->CreateThread();
+ }
+}
+
+void CCECProcessor::HandlePhysicalAddressChanged(uint16_t iNewAddress)
+{
+ if (!m_bStallCommunication) {
+ CECClientPtr client = GetPrimaryClient();
+ if (!!client)
+ client->SetPhysicalAddress(iNewAddress);
+ }
+}
+
+uint16_t CCECProcessor::GetAdapterVendorId(void) const
+{
+ return m_communication ? m_communication->GetAdapterVendorId() : 0;
+}
+
+uint16_t CCECProcessor::GetAdapterProductId(void) const
+{
+ return m_communication ? m_communication->GetAdapterProductId() : 0;
+}
+
+CCECAllocateLogicalAddress::CCECAllocateLogicalAddress(CCECProcessor* processor, CECClientPtr client) :
+ m_processor(processor),
+ m_client(client) { }
+
+void* CCECAllocateLogicalAddress::Process(void)
+{
+ m_processor->AllocateLogicalAddresses(m_client);
+ return NULL;
+}
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include <string>
+
+#include <p8-platform/threads/threads.h>
+#include <p8-platform/util/buffer.h>
+
+#include "adapter/AdapterCommunication.h"
+#include "devices/CECDeviceMap.h"
+#include "CECInputBuffer.h"
+#include <memory>
+
+namespace CEC
+{
+ class CLibCEC;
+ class IAdapterCommunication;
+ class CCECBusDevice;
+ class CCECAudioSystem;
+ class CCECPlaybackDevice;
+ class CCECRecordingDevice;
+ class CCECTuner;
+ class CCECTV;
+ class CCECClient;
+ class CCECProcessor;
+ class CCECStandbyProtection;
+ typedef std::shared_ptr<CCECClient> CECClientPtr;
+
+ typedef struct
+ {
+ CECClientPtr client;
+ cec_device_type from;
+ cec_device_type to;
+ } device_type_change_t;
+
+ class CCECAllocateLogicalAddress : public P8PLATFORM::CThread
+ {
+ public:
+ CCECAllocateLogicalAddress(CCECProcessor* processor, CECClientPtr client);
+ void* Process(void);
+
+ private:
+ CCECProcessor* m_processor;
+ CECClientPtr m_client;
+ };
+
+ class CCECProcessor : public P8PLATFORM::CThread, public IAdapterCommunicationCallback
+ {
+ public:
+ CCECProcessor(CLibCEC *libcec);
+ virtual ~CCECProcessor(void);
+
+ bool Start(const char *strPort, uint16_t iBaudRate = CEC_SERIAL_DEFAULT_BAUDRATE, uint32_t iTimeoutMs = CEC_DEFAULT_CONNECT_TIMEOUT);
+ void *Process(void);
+ void Close(void);
+
+ bool RegisterClient(CCECClient* client);
+ bool RegisterClient(CECClientPtr client);
+ bool UnregisterClient(CCECClient* client);
+ bool UnregisterClient(CECClientPtr client);
+ void UnregisterClients(void);
+ uint16_t GetPhysicalAddressFromEeprom(void);
+ CECClientPtr GetPrimaryClient(void);
+ CECClientPtr GetClient(const cec_logical_address address);
+
+ bool OnCommandReceived(const cec_command &command);
+ void HandleLogicalAddressLost(cec_logical_address oldAddress);
+ void HandlePhysicalAddressChanged(uint16_t iNewAddress);
+
+ CCECBusDevice * GetDevice(cec_logical_address address) const;
+ CCECAudioSystem * GetAudioSystem(void) const;
+ CCECPlaybackDevice * GetPlaybackDevice(cec_logical_address address) const;
+ CCECRecordingDevice * GetRecordingDevice(cec_logical_address address) const;
+ CCECTuner * GetTuner(cec_logical_address address) const;
+ CCECTV * GetTV(void) const;
+
+ CCECBusDevice * GetDeviceByPhysicalAddress(uint16_t iPhysicalAddress, bool bSuppressUpdate = true);
+ CCECBusDevice * GetPrimaryDevice(void);
+ cec_logical_address GetLogicalAddress(void);
+ cec_logical_addresses GetLogicalAddresses(void);
+ bool IsPresentDevice(cec_logical_address address);
+ bool IsPresentDeviceType(cec_device_type type);
+ uint16_t GetDetectedPhysicalAddress(void) const;
+ uint64_t GetLastTransmission(void) const { return m_iLastTransmission; }
+ cec_logical_address GetActiveSource(bool bRequestActiveSource = true);
+ bool IsActiveSource(cec_logical_address iAddress);
+ bool CECInitialised(void);
+
+ bool StandbyDevices(const cec_logical_address initiator, const CECDEVICEVEC &devices);
+ bool StandbyDevice(const cec_logical_address initiator, cec_logical_address address);
+ bool PowerOnDevices(const cec_logical_address initiator, const CECDEVICEVEC &devices);
+ bool PowerOnDevice(const cec_logical_address initiator, cec_logical_address address);
+
+ void ChangeDeviceType(CECClientPtr client, cec_device_type from, cec_device_type to);
+ bool SetDeckInfo(cec_deck_info info, bool bSendUpdate = true);
+ bool ActivateSource(uint16_t iStreamPath);
+ void SetActiveSource(bool bSetTo, bool bClientUnregistered);
+ bool PollDevice(cec_logical_address iAddress);
+ void SetStandardLineTimeout(uint8_t iTimeout);
+ uint8_t GetStandardLineTimeout(void);
+ void SetRetryLineTimeout(uint8_t iTimeout);
+ uint8_t GetRetryLineTimeout(void);
+ bool CanPersistConfiguration(void);
+ bool PersistConfiguration(const libcec_configuration &configuration);
+ void RescanActiveDevices(void);
+
+ bool SetLineTimeout(uint8_t iTimeout);
+
+ bool Transmit(const cec_command &data, bool bIsReply);
+ void TransmitAbort(cec_logical_address source, cec_logical_address destination, cec_opcode opcode, cec_abort_reason reason = CEC_ABORT_REASON_UNRECOGNIZED_OPCODE);
+
+ bool StartBootloader(const char *strPort = NULL);
+ bool PingAdapter(void);
+ void HandlePoll(cec_logical_address initiator, cec_logical_address destination);
+ bool HandleReceiveFailed(cec_logical_address initiator);
+
+ bool GetDeviceInformation(const char *strPort, libcec_configuration *config, uint32_t iTimeoutMs = CEC_DEFAULT_CONNECT_TIMEOUT);
+
+ bool TransmitPendingActiveSourceCommands(void);
+
+ CCECDeviceMap *GetDevices(void) const { return m_busDevices; }
+ CLibCEC *GetLib(void) const { return m_libcec; }
+
+ bool IsHandledByLibCEC(const cec_logical_address address) const;
+
+ bool TryLogicalAddress(cec_logical_address address, cec_version libCECSpecVersion = CEC_VERSION_1_4);
+
+ bool IsRunningLatestFirmware(void);
+ void SwitchMonitoring(bool bSwitchTo);
+
+ bool AllocateLogicalAddresses(CECClientPtr client);
+
+ uint16_t GetAdapterVendorId(void) const;
+ uint16_t GetAdapterProductId(void) const;
+ private:
+ bool OpenConnection(const char *strPort, uint16_t iBaudRate, uint32_t iTimeoutMs, bool bStartListening = true);
+ void SetCECInitialised(bool bSetTo = true);
+
+ void ReplaceHandlers(void);
+ bool PhysicalAddressInUse(uint16_t iPhysicalAddress);
+
+ bool ClearLogicalAddresses(void);
+ bool SetLogicalAddresses(const cec_logical_addresses &addresses);
+
+ void LogOutput(const cec_command &data);
+ void ProcessCommand(const cec_command &command);
+
+ void ResetMembers(void);
+
+ bool m_bInitialised;
+ P8PLATFORM::CMutex m_mutex;
+ IAdapterCommunication * m_communication;
+ CLibCEC* m_libcec;
+ uint8_t m_iStandardLineTimeout;
+ uint8_t m_iRetryLineTimeout;
+ uint64_t m_iLastTransmission;
+ CCECInputBuffer m_inBuffer;
+ CCECDeviceMap * m_busDevices;
+ std::map<cec_logical_address, CECClientPtr> m_clients;
+ bool m_bMonitor;
+ CCECAllocateLogicalAddress* m_addrAllocator;
+ bool m_bStallCommunication;
+ CCECStandbyProtection* m_connCheck;
+ std::vector<device_type_change_t> m_deviceTypeChanges;
+ };
+
+ class CCECStandbyProtection : public P8PLATFORM::CThread
+ {
+ public:
+ CCECStandbyProtection(CCECProcessor* processor);
+ virtual ~CCECStandbyProtection(void);
+ void* Process(void);
+
+ private:
+ CCECProcessor* m_processor;
+ };
+};
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include <p8-platform/util/StringUtils.h>
+
+namespace CEC
+{
+ class CCECTypeUtils
+ {
+ public:
+ /*!
+ * @brief Get the device type for the given logical address.
+ * @param address The address to get the type for.
+ * @return The type, or CEC_DEVICE_TYPE_RESERVED if unknown.
+ */
+ static cec_device_type GetType(const cec_logical_address address)
+ {
+ switch (address)
+ {
+ case CECDEVICE_AUDIOSYSTEM:
+ return CEC_DEVICE_TYPE_AUDIO_SYSTEM;
+ case CECDEVICE_PLAYBACKDEVICE1:
+ case CECDEVICE_PLAYBACKDEVICE2:
+ case CECDEVICE_PLAYBACKDEVICE3:
+ return CEC_DEVICE_TYPE_PLAYBACK_DEVICE;
+ case CECDEVICE_RECORDINGDEVICE1:
+ case CECDEVICE_RECORDINGDEVICE2:
+ case CECDEVICE_RECORDINGDEVICE3:
+ return CEC_DEVICE_TYPE_RECORDING_DEVICE;
+ case CECDEVICE_TUNER1:
+ case CECDEVICE_TUNER2:
+ case CECDEVICE_TUNER3:
+ case CECDEVICE_TUNER4:
+ return CEC_DEVICE_TYPE_TUNER;
+ case CECDEVICE_TV:
+ return CEC_DEVICE_TYPE_TV;
+ default:
+ return CEC_DEVICE_TYPE_RESERVED;
+ }
+ }
+
+ /*!
+ * @brief Get the ackmask for all devices of the same type as the given logical address.
+ * @param address The address to get the ackmask for.
+ * @return The ackmask for this type.
+ */
+ static uint16_t GetMaskForType(cec_logical_address address)
+ {
+ return GetMaskForType(GetType(address));
+ }
+
+ /*!
+ * @brief Get the ackmask for all devices of the given type.
+ * @param type The type to get the ackmask for.
+ * @return The ackmask for this type, or 0 of no types match.
+ */
+ static uint16_t GetMaskForType(const cec_device_type type)
+ {
+ switch (type)
+ {
+ case CEC_DEVICE_TYPE_AUDIO_SYSTEM:
+ {
+ cec_logical_addresses addr;
+ addr.Clear();
+ addr.Set(CECDEVICE_AUDIOSYSTEM);
+ return addr.AckMask();
+ }
+ case CEC_DEVICE_TYPE_PLAYBACK_DEVICE:
+ {
+ cec_logical_addresses addr;
+ addr.Clear();
+ addr.Set(CECDEVICE_PLAYBACKDEVICE1);
+ addr.Set(CECDEVICE_PLAYBACKDEVICE2);
+ addr.Set(CECDEVICE_PLAYBACKDEVICE3);
+ return addr.AckMask();
+ }
+ case CEC_DEVICE_TYPE_RECORDING_DEVICE:
+ {
+ cec_logical_addresses addr;
+ addr.Clear();
+ addr.Set(CECDEVICE_RECORDINGDEVICE1);
+ addr.Set(CECDEVICE_RECORDINGDEVICE2);
+ addr.Set(CECDEVICE_RECORDINGDEVICE3);
+ return addr.AckMask();
+ }
+ case CEC_DEVICE_TYPE_TUNER:
+ {
+ cec_logical_addresses addr;
+ addr.Clear();
+ addr.Set(CECDEVICE_TUNER1);
+ addr.Set(CECDEVICE_TUNER2);
+ addr.Set(CECDEVICE_TUNER3);
+ addr.Set(CECDEVICE_TUNER4);
+ return addr.AckMask();
+ }
+ case CEC_DEVICE_TYPE_TV:
+ {
+ cec_logical_addresses addr;
+ addr.Clear();
+ addr.Set(CECDEVICE_TV);
+ return addr.AckMask();
+ }
+ default:
+ return 0;
+ }
+ }
+
+ static const char *ToString(const cec_device_type type)
+ {
+ switch (type)
+ {
+ case CEC_DEVICE_TYPE_AUDIO_SYSTEM:
+ return "audio system";
+ case CEC_DEVICE_TYPE_PLAYBACK_DEVICE:
+ return "playback device";
+ case CEC_DEVICE_TYPE_RECORDING_DEVICE:
+ return "recording device";
+ case CEC_DEVICE_TYPE_RESERVED:
+ return "reserved";
+ case CEC_DEVICE_TYPE_TUNER:
+ return "tuner";
+ case CEC_DEVICE_TYPE_TV:
+ return "TV";
+ default:
+ return "unknown";
+ }
+ }
+
+ static const char *ToString(const cec_menu_state state)
+ {
+ switch (state)
+ {
+ case CEC_MENU_STATE_ACTIVATED:
+ return "activated";
+ case CEC_MENU_STATE_DEACTIVATED:
+ return "deactivated";
+ default:
+ return "unknown";
+ }
+ }
+
+ static const char *ToString(const cec_version version)
+ {
+ switch (version)
+ {
+ case CEC_VERSION_1_2:
+ return "1.2";
+ case CEC_VERSION_1_2A:
+ return "1.2a";
+ case CEC_VERSION_1_3:
+ return "1.3";
+ case CEC_VERSION_1_3A:
+ return "1.3a";
+ case CEC_VERSION_1_4:
+ return "1.4";
+ default:
+ return "unknown";
+ }
+ }
+
+ static const char *ToString(const cec_power_status status)
+ {
+ switch (status)
+ {
+ case CEC_POWER_STATUS_ON:
+ return "on";
+ case CEC_POWER_STATUS_STANDBY:
+ return "standby";
+ case CEC_POWER_STATUS_IN_TRANSITION_ON_TO_STANDBY:
+ return "in transition from on to standby";
+ case CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON:
+ return "in transition from standby to on";
+ default:
+ return "unknown";
+ }
+ }
+
+ static const char *ToString(const cec_logical_address address)
+ {
+ switch(address)
+ {
+ case CECDEVICE_AUDIOSYSTEM:
+ return "Audio";
+ case CECDEVICE_BROADCAST:
+ return "Broadcast";
+ case CECDEVICE_FREEUSE:
+ return "Free use";
+ case CECDEVICE_PLAYBACKDEVICE1:
+ return "Playback 1";
+ case CECDEVICE_PLAYBACKDEVICE2:
+ return "Playback 2";
+ case CECDEVICE_PLAYBACKDEVICE3:
+ return "Playback 3";
+ case CECDEVICE_RECORDINGDEVICE1:
+ return "Recorder 1";
+ case CECDEVICE_RECORDINGDEVICE2:
+ return "Recorder 2";
+ case CECDEVICE_RECORDINGDEVICE3:
+ return "Recorder 3";
+ case CECDEVICE_RESERVED1:
+ return "Reserved 1";
+ case CECDEVICE_RESERVED2:
+ return "Reserved 2";
+ case CECDEVICE_TUNER1:
+ return "Tuner 1";
+ case CECDEVICE_TUNER2:
+ return "Tuner 2";
+ case CECDEVICE_TUNER3:
+ return "Tuner 3";
+ case CECDEVICE_TUNER4:
+ return "Tuner 4";
+ case CECDEVICE_TV:
+ return "TV";
+ default:
+ return "unknown";
+ }
+ }
+
+ static const char *ToString(const cec_deck_control_mode mode)
+ {
+ switch (mode)
+ {
+ case CEC_DECK_CONTROL_MODE_SKIP_FORWARD_WIND:
+ return "skip forward wind";
+ case CEC_DECK_CONTROL_MODE_EJECT:
+ return "eject";
+ case CEC_DECK_CONTROL_MODE_SKIP_REVERSE_REWIND:
+ return "reverse rewind";
+ case CEC_DECK_CONTROL_MODE_STOP:
+ return "stop";
+ default:
+ return "unknown";
+ }
+ }
+
+ static const char *ToString(const cec_deck_info status)
+ {
+ switch (status)
+ {
+ case CEC_DECK_INFO_PLAY:
+ return "play";
+ case CEC_DECK_INFO_RECORD:
+ return "record";
+ case CEC_DECK_INFO_PLAY_REVERSE:
+ return "play reverse";
+ case CEC_DECK_INFO_STILL:
+ return "still";
+ case CEC_DECK_INFO_SLOW:
+ return "slow";
+ case CEC_DECK_INFO_SLOW_REVERSE:
+ return "slow reverse";
+ case CEC_DECK_INFO_FAST_FORWARD:
+ return "fast forward";
+ case CEC_DECK_INFO_FAST_REVERSE:
+ return "fast reverse";
+ case CEC_DECK_INFO_NO_MEDIA:
+ return "no media";
+ case CEC_DECK_INFO_STOP:
+ return "stop";
+ case CEC_DECK_INFO_SKIP_FORWARD_WIND:
+ return "info skip forward wind";
+ case CEC_DECK_INFO_SKIP_REVERSE_REWIND:
+ return "info skip reverse rewind";
+ case CEC_DECK_INFO_INDEX_SEARCH_FORWARD:
+ return "info index search forward";
+ case CEC_DECK_INFO_INDEX_SEARCH_REVERSE:
+ return "info index search reverse";
+ case CEC_DECK_INFO_OTHER_STATUS:
+ return "other";
+ case CEC_DECK_INFO_OTHER_STATUS_LG:
+ return "LG other";
+ default:
+ return "unknown";
+ }
+ }
+
+ static const char *ToString(const cec_opcode opcode)
+ {
+ switch (opcode)
+ {
+ case CEC_OPCODE_ACTIVE_SOURCE:
+ return "active source";
+ case CEC_OPCODE_IMAGE_VIEW_ON:
+ return "image view on";
+ case CEC_OPCODE_TEXT_VIEW_ON:
+ return "text view on";
+ case CEC_OPCODE_INACTIVE_SOURCE:
+ return "inactive source";
+ case CEC_OPCODE_REQUEST_ACTIVE_SOURCE:
+ return "request active source";
+ case CEC_OPCODE_ROUTING_CHANGE:
+ return "routing change";
+ case CEC_OPCODE_ROUTING_INFORMATION:
+ return "routing information";
+ case CEC_OPCODE_SET_STREAM_PATH:
+ return "set stream path";
+ case CEC_OPCODE_STANDBY:
+ return "standby";
+ case CEC_OPCODE_RECORD_OFF:
+ return "record off";
+ case CEC_OPCODE_RECORD_ON:
+ return "record on";
+ case CEC_OPCODE_RECORD_STATUS:
+ return "record status";
+ case CEC_OPCODE_RECORD_TV_SCREEN:
+ return "record tv screen";
+ case CEC_OPCODE_CLEAR_ANALOGUE_TIMER:
+ return "clear analogue timer";
+ case CEC_OPCODE_CLEAR_DIGITAL_TIMER:
+ return "clear digital timer";
+ case CEC_OPCODE_CLEAR_EXTERNAL_TIMER:
+ return "clear external timer";
+ case CEC_OPCODE_SET_ANALOGUE_TIMER:
+ return "set analogue timer";
+ case CEC_OPCODE_SET_DIGITAL_TIMER:
+ return "set digital timer";
+ case CEC_OPCODE_SET_EXTERNAL_TIMER:
+ return "set external timer";
+ case CEC_OPCODE_SET_TIMER_PROGRAM_TITLE:
+ return "set timer program title";
+ case CEC_OPCODE_TIMER_CLEARED_STATUS:
+ return "timer cleared status";
+ case CEC_OPCODE_TIMER_STATUS:
+ return "timer status";
+ case CEC_OPCODE_CEC_VERSION:
+ return "cec version";
+ case CEC_OPCODE_GET_CEC_VERSION:
+ return "get cec version";
+ case CEC_OPCODE_GIVE_PHYSICAL_ADDRESS:
+ return "give physical address";
+ case CEC_OPCODE_GET_MENU_LANGUAGE:
+ return "get menu language";
+ case CEC_OPCODE_REPORT_PHYSICAL_ADDRESS:
+ return "report physical address";
+ case CEC_OPCODE_SET_MENU_LANGUAGE:
+ return "set menu language";
+ case CEC_OPCODE_DECK_CONTROL:
+ return "deck control";
+ case CEC_OPCODE_DECK_STATUS:
+ return "deck status";
+ case CEC_OPCODE_GIVE_DECK_STATUS:
+ return "give deck status";
+ case CEC_OPCODE_PLAY:
+ return "play";
+ case CEC_OPCODE_GIVE_TUNER_DEVICE_STATUS:
+ return "give tuner status";
+ case CEC_OPCODE_SELECT_ANALOGUE_SERVICE:
+ return "select analogue service";
+ case CEC_OPCODE_SELECT_DIGITAL_SERVICE:
+ return "set digital service";
+ case CEC_OPCODE_TUNER_DEVICE_STATUS:
+ return "tuner device status";
+ case CEC_OPCODE_TUNER_STEP_DECREMENT:
+ return "tuner step decrement";
+ case CEC_OPCODE_TUNER_STEP_INCREMENT:
+ return "tuner step increment";
+ case CEC_OPCODE_DEVICE_VENDOR_ID:
+ return "device vendor id";
+ case CEC_OPCODE_GIVE_DEVICE_VENDOR_ID:
+ return "give device vendor id";
+ case CEC_OPCODE_VENDOR_COMMAND:
+ return "vendor command";
+ case CEC_OPCODE_VENDOR_COMMAND_WITH_ID:
+ return "vendor command with id";
+ case CEC_OPCODE_VENDOR_REMOTE_BUTTON_DOWN:
+ return "vendor remote button down";
+ case CEC_OPCODE_VENDOR_REMOTE_BUTTON_UP:
+ return "vendor remote button up";
+ case CEC_OPCODE_SET_OSD_STRING:
+ return "set osd string";
+ case CEC_OPCODE_GIVE_OSD_NAME:
+ return "give osd name";
+ case CEC_OPCODE_SET_OSD_NAME:
+ return "set osd name";
+ case CEC_OPCODE_MENU_REQUEST:
+ return "menu request";
+ case CEC_OPCODE_MENU_STATUS:
+ return "menu status";
+ case CEC_OPCODE_USER_CONTROL_PRESSED:
+ return "user control pressed";
+ case CEC_OPCODE_USER_CONTROL_RELEASE:
+ return "user control release";
+ case CEC_OPCODE_GIVE_DEVICE_POWER_STATUS:
+ return "give device power status";
+ case CEC_OPCODE_REPORT_POWER_STATUS:
+ return "report power status";
+ case CEC_OPCODE_FEATURE_ABORT:
+ return "feature abort";
+ case CEC_OPCODE_ABORT:
+ return "abort";
+ case CEC_OPCODE_GIVE_AUDIO_STATUS:
+ return "give audio status";
+ case CEC_OPCODE_GIVE_SYSTEM_AUDIO_MODE_STATUS:
+ return "give audio mode status";
+ case CEC_OPCODE_REPORT_AUDIO_STATUS:
+ return "report audio status";
+ case CEC_OPCODE_SET_SYSTEM_AUDIO_MODE:
+ return "set system audio mode";
+ case CEC_OPCODE_SYSTEM_AUDIO_MODE_REQUEST:
+ return "system audio mode request";
+ case CEC_OPCODE_SYSTEM_AUDIO_MODE_STATUS:
+ return "system audio mode status";
+ case CEC_OPCODE_SET_AUDIO_RATE:
+ return "set audio rate";
+ case CEC_OPCODE_START_ARC:
+ return "start ARC";
+ case CEC_OPCODE_REPORT_ARC_STARTED:
+ return "report ARC started";
+ case CEC_OPCODE_REPORT_ARC_ENDED:
+ return "report ARC ended";
+ case CEC_OPCODE_REQUEST_ARC_START:
+ return "request ARC start";
+ case CEC_OPCODE_REQUEST_ARC_END:
+ return "request ARC end";
+ case CEC_OPCODE_END_ARC:
+ return "end ARC";
+ case CEC_OPCODE_CDC:
+ return "CDC";
+ case CEC_OPCODE_NONE:
+ return "poll";
+ default:
+ return "UNKNOWN";
+ }
+ }
+
+ static const char *ToString(const cec_system_audio_status mode)
+ {
+ switch(mode)
+ {
+ case CEC_SYSTEM_AUDIO_STATUS_ON:
+ return "on";
+ case CEC_SYSTEM_AUDIO_STATUS_OFF:
+ return "off";
+ default:
+ return "unknown";
+ }
+ }
+
+ static const char *ToString(const cec_audio_status UNUSED(status))
+ {
+ // TODO this is a mask
+ return "TODO";
+ }
+
+ static const char *ToString(const cec_vendor_id vendor)
+ {
+ switch (vendor)
+ {
+ case CEC_VENDOR_SAMSUNG:
+ return "Samsung";
+ case CEC_VENDOR_LG:
+ return "LG";
+ case CEC_VENDOR_PANASONIC:
+ return "Panasonic";
+ case CEC_VENDOR_PIONEER:
+ return "Pioneer";
+ case CEC_VENDOR_ONKYO:
+ return "Onkyo";
+ case CEC_VENDOR_YAMAHA:
+ return "Yamaha";
+ case CEC_VENDOR_PHILIPS:
+ return "Philips";
+ case CEC_VENDOR_SONY:
+ return "Sony";
+ case CEC_VENDOR_TOSHIBA:
+ case CEC_VENDOR_TOSHIBA2:
+ return "Toshiba";
+ case CEC_VENDOR_AKAI:
+ return "Akai";
+ case CEC_VENDOR_AOC:
+ return "AOC";
+ case CEC_VENDOR_BENQ:
+ return "Benq";
+ case CEC_VENDOR_DAEWOO:
+ return "Daewoo";
+ case CEC_VENDOR_GRUNDIG:
+ return "Grundig";
+ case CEC_VENDOR_MEDION:
+ return "Medion";
+ case CEC_VENDOR_SHARP:
+ case CEC_VENDOR_SHARP2:
+ return "Sharp";
+ case CEC_VENDOR_VIZIO:
+ return "Vizio";
+ case CEC_VENDOR_BROADCOM:
+ return "Broadcom";
+ case CEC_VENDOR_LOEWE:
+ return "Loewe";
+ case CEC_VENDOR_DENON:
+ return "Denon";
+ case CEC_VENDOR_MARANTZ:
+ return "Marantz";
+ case CEC_VENDOR_HARMAN_KARDON:
+ case CEC_VENDOR_HARMAN_KARDON2:
+ return "Harman/Kardon";
+ case CEC_VENDOR_PULSE_EIGHT:
+ return "Pulse Eight";
+ case CEC_VENDOR_GOOGLE:
+ return "Google";
+ default:
+ return "Unknown";
+ }
+ }
+
+ static std::string VersionToString(uint32_t version)
+ {
+ uint32_t major, minor, patch;
+ if (version <= 0x2200)
+ {
+ major = LIBCEC_UINT_TO_VERSION_MAJOR_OLD(version);
+ minor = LIBCEC_UINT_TO_VERSION_MINOR_OLD(version);
+ patch = LIBCEC_UINT_TO_VERSION_PATCH_OLD(version);
+ }
+ else
+ {
+ major = LIBCEC_UINT_TO_VERSION_MAJOR(version);
+ minor = LIBCEC_UINT_TO_VERSION_MINOR(version);
+ patch = LIBCEC_UINT_TO_VERSION_PATCH(version);
+ }
+ return StringUtils::Format("%u.%u.%u", major, minor, patch);
+ }
+
+ static const char *ToString(const cec_abort_reason reason)
+ {
+ switch(reason)
+ {
+ case CEC_ABORT_REASON_UNRECOGNIZED_OPCODE:
+ return "unrecognised opcode";
+ case CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND:
+ return "not in correct mode to respond";
+ case CEC_ABORT_REASON_CANNOT_PROVIDE_SOURCE:
+ return "cannot provide source";
+ case CEC_ABORT_REASON_INVALID_OPERAND:
+ return "invalid operand";
+ case CEC_ABORT_REASON_REFUSED:
+ return "refused";
+ default:
+ return "unknown";
+ }
+ }
+
+ static const char *ToString(const cec_user_control_code key)
+ {
+ switch (key)
+ {
+ case CEC_USER_CONTROL_CODE_SELECT:
+ return "select";
+ case CEC_USER_CONTROL_CODE_UP:
+ return "up";
+ case CEC_USER_CONTROL_CODE_DOWN:
+ return "down";
+ case CEC_USER_CONTROL_CODE_LEFT:
+ return "left";
+ case CEC_USER_CONTROL_CODE_RIGHT:
+ return "right";
+ case CEC_USER_CONTROL_CODE_RIGHT_UP:
+ return "right+up";
+ case CEC_USER_CONTROL_CODE_RIGHT_DOWN:
+ return "right+down";
+ case CEC_USER_CONTROL_CODE_LEFT_UP:
+ return "left+up";
+ case CEC_USER_CONTROL_CODE_LEFT_DOWN:
+ return "left+down";
+ case CEC_USER_CONTROL_CODE_ROOT_MENU:
+ return "root menu";
+ case CEC_USER_CONTROL_CODE_SETUP_MENU:
+ return "setup menu";
+ case CEC_USER_CONTROL_CODE_CONTENTS_MENU:
+ return "contents menu";
+ case CEC_USER_CONTROL_CODE_FAVORITE_MENU:
+ return "favourite menu";
+ case CEC_USER_CONTROL_CODE_EXIT:
+ return "exit";
+ case CEC_USER_CONTROL_CODE_TOP_MENU:
+ return "top menu";
+ case CEC_USER_CONTROL_CODE_DVD_MENU:
+ return "dvd menu";
+ case CEC_USER_CONTROL_CODE_NUMBER_ENTRY_MODE:
+ return "number entry mode";
+ case CEC_USER_CONTROL_CODE_NUMBER11:
+ return "11";
+ case CEC_USER_CONTROL_CODE_NUMBER12:
+ return "12";
+ case CEC_USER_CONTROL_CODE_NUMBER0:
+ return "0";
+ case CEC_USER_CONTROL_CODE_NUMBER1:
+ return "1";
+ case CEC_USER_CONTROL_CODE_NUMBER2:
+ return "2";
+ case CEC_USER_CONTROL_CODE_NUMBER3:
+ return "3";
+ case CEC_USER_CONTROL_CODE_NUMBER4:
+ return "4";
+ case CEC_USER_CONTROL_CODE_NUMBER5:
+ return "5";
+ case CEC_USER_CONTROL_CODE_NUMBER6:
+ return "6";
+ case CEC_USER_CONTROL_CODE_NUMBER7:
+ return "7";
+ case CEC_USER_CONTROL_CODE_NUMBER8:
+ return "8";
+ case CEC_USER_CONTROL_CODE_NUMBER9:
+ return "9";
+ case CEC_USER_CONTROL_CODE_DOT:
+ return ".";
+ case CEC_USER_CONTROL_CODE_ENTER:
+ return "enter";
+ case CEC_USER_CONTROL_CODE_CLEAR:
+ return "clear";
+ case CEC_USER_CONTROL_CODE_NEXT_FAVORITE:
+ return "next favourite";
+ case CEC_USER_CONTROL_CODE_CHANNEL_UP:
+ return "channel up";
+ case CEC_USER_CONTROL_CODE_CHANNEL_DOWN:
+ return "channel down";
+ case CEC_USER_CONTROL_CODE_PREVIOUS_CHANNEL:
+ return "previous channel";
+ case CEC_USER_CONTROL_CODE_SOUND_SELECT:
+ return "sound select";
+ case CEC_USER_CONTROL_CODE_INPUT_SELECT:
+ return "input select";
+ case CEC_USER_CONTROL_CODE_DISPLAY_INFORMATION:
+ return "display information";
+ case CEC_USER_CONTROL_CODE_HELP:
+ return "help";
+ case CEC_USER_CONTROL_CODE_PAGE_UP:
+ return "page up";
+ case CEC_USER_CONTROL_CODE_PAGE_DOWN:
+ return "page down";
+ case CEC_USER_CONTROL_CODE_POWER:
+ return "power";
+ case CEC_USER_CONTROL_CODE_VOLUME_UP:
+ return "volume up";
+ case CEC_USER_CONTROL_CODE_VOLUME_DOWN:
+ return "volume down";
+ case CEC_USER_CONTROL_CODE_MUTE:
+ return "mute";
+ case CEC_USER_CONTROL_CODE_PLAY:
+ return "play";
+ case CEC_USER_CONTROL_CODE_STOP:
+ return "stop";
+ case CEC_USER_CONTROL_CODE_PAUSE:
+ return "pause";
+ case CEC_USER_CONTROL_CODE_RECORD:
+ return "record";
+ case CEC_USER_CONTROL_CODE_REWIND:
+ return "rewind";
+ case CEC_USER_CONTROL_CODE_FAST_FORWARD:
+ return "Fast forward";
+ case CEC_USER_CONTROL_CODE_EJECT:
+ return "eject";
+ case CEC_USER_CONTROL_CODE_FORWARD:
+ return "forward";
+ case CEC_USER_CONTROL_CODE_BACKWARD:
+ return "backward";
+ case CEC_USER_CONTROL_CODE_STOP_RECORD:
+ return "stop record";
+ case CEC_USER_CONTROL_CODE_PAUSE_RECORD:
+ return "pause record";
+ case CEC_USER_CONTROL_CODE_ANGLE:
+ return "angle";
+ case CEC_USER_CONTROL_CODE_SUB_PICTURE:
+ return "sub picture";
+ case CEC_USER_CONTROL_CODE_VIDEO_ON_DEMAND:
+ return "video on demand";
+ case CEC_USER_CONTROL_CODE_ELECTRONIC_PROGRAM_GUIDE:
+ return "electronic program guide";
+ case CEC_USER_CONTROL_CODE_TIMER_PROGRAMMING:
+ return "timer programming";
+ case CEC_USER_CONTROL_CODE_INITIAL_CONFIGURATION:
+ return "initial configuration";
+ case CEC_USER_CONTROL_CODE_SELECT_BROADCAST_TYPE:
+ return "select broadcast type";
+ case CEC_USER_CONTROL_CODE_SELECT_SOUND_PRESENTATION:
+ return "select sound presentation";
+ case CEC_USER_CONTROL_CODE_PLAY_FUNCTION:
+ return "play (function)";
+ case CEC_USER_CONTROL_CODE_PAUSE_PLAY_FUNCTION:
+ return "pause play (function)";
+ case CEC_USER_CONTROL_CODE_RECORD_FUNCTION:
+ return "record (function)";
+ case CEC_USER_CONTROL_CODE_PAUSE_RECORD_FUNCTION:
+ return "pause record (function)";
+ case CEC_USER_CONTROL_CODE_STOP_FUNCTION:
+ return "stop (function)";
+ case CEC_USER_CONTROL_CODE_MUTE_FUNCTION:
+ return "mute (function)";
+ case CEC_USER_CONTROL_CODE_RESTORE_VOLUME_FUNCTION:
+ return "restore volume";
+ case CEC_USER_CONTROL_CODE_TUNE_FUNCTION:
+ return "tune";
+ case CEC_USER_CONTROL_CODE_SELECT_MEDIA_FUNCTION:
+ return "select media";
+ case CEC_USER_CONTROL_CODE_SELECT_AV_INPUT_FUNCTION:
+ return "select AV input";
+ case CEC_USER_CONTROL_CODE_SELECT_AUDIO_INPUT_FUNCTION:
+ return "select audio input";
+ case CEC_USER_CONTROL_CODE_POWER_TOGGLE_FUNCTION:
+ return "power toggle";
+ case CEC_USER_CONTROL_CODE_POWER_OFF_FUNCTION:
+ return "power off";
+ case CEC_USER_CONTROL_CODE_POWER_ON_FUNCTION:
+ return "power on";
+ case CEC_USER_CONTROL_CODE_F1_BLUE:
+ return "F1 (blue)";
+ case CEC_USER_CONTROL_CODE_F2_RED:
+ return "F2 (red)";
+ case CEC_USER_CONTROL_CODE_F3_GREEN:
+ return "F3 (green)";
+ case CEC_USER_CONTROL_CODE_F4_YELLOW:
+ return "F4 (yellow)";
+ case CEC_USER_CONTROL_CODE_F5:
+ return "F5";
+ case CEC_USER_CONTROL_CODE_DATA:
+ return "data";
+ case CEC_USER_CONTROL_CODE_AN_RETURN:
+ return "return (Samsung)";
+ case CEC_USER_CONTROL_CODE_AN_CHANNELS_LIST:
+ return "channels list (Samsung)";
+ default:
+ return "unknown";
+ }
+ }
+
+ static const char *ToString(const cec_adapter_type type)
+ {
+ switch (type)
+ {
+ case ADAPTERTYPE_P8_EXTERNAL:
+ return "Pulse-Eight USB-CEC Adapter";
+ case ADAPTERTYPE_P8_DAUGHTERBOARD:
+ return "Pulse-Eight USB-CEC Daughterboard";
+ case ADAPTERTYPE_RPI:
+ return "Raspberry Pi";
+ case ADAPTERTYPE_TDA995x:
+ return "TDA995x";
+ default:
+ return "unknown";
+ }
+ }
+
+ static bool PhysicalAddressIsIncluded(uint16_t iParent, uint16_t iChild)
+ {
+ for (int iPtr = 3; iPtr >= 0; iPtr--)
+ {
+ if (((iParent >> 4*iPtr) & 0xF) > 0 &&
+ ((iParent >> 4*iPtr) & 0xF) != ((iChild >> 4*iPtr) & 0xF))
+ return false;
+ }
+ return true;
+ }
+
+ static std::string ToString(const cec_command& command)
+ {
+ std::string dataStr;
+ dataStr = StringUtils::Format(">> %1x%1x", command.initiator, command.destination);
+ if (command.opcode_set == 1)
+ dataStr += StringUtils::Format(":%02x", command.opcode);
+ for (uint8_t iPtr = 0; iPtr < command.parameters.size; iPtr++)
+ dataStr += StringUtils::Format(":%02x", (unsigned int)command.parameters[iPtr]);
+ return dataStr;
+ }
+ };
+}
--- /dev/null
+project(cec)
+
+cmake_minimum_required(VERSION 2.8.9)
+
+set(cec_NAME cec)
+set(cec_DESCRIPTION "libCEC")
+
+enable_language(CXX)
+
+include(CheckCXXSourceCompiles)
+include(CheckLibraryExists)
+include(CheckIncludeFiles)
+include(CheckCXXCompilerFlag)
+include(../../cmake/UseMultiArch.cmake)
+
+check_cxx_compiler_flag("-std=c++11" SUPPORTS_CXX11)
+if (SUPPORTS_CXX11)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
+endif()
+
+find_package(p8-platform REQUIRED)
+if (p8-platform_VERSION VERSION_LESS 2.0)
+ message(FATAL_ERROR "p8-platform 2.0+ is required")
+endif()
+
+find_package(Threads REQUIRED)
+
+include_directories(${p8-platform_INCLUDE_DIRS}
+ ${PROJECT_SOURCE_DIR}
+ ${PROJECT_SOURCE_DIR}/../../include)
+
+set(CMAKE_POSITION_INDEPENDENT_CODE on)
+
+# main libCEC files
+set(CEC_SOURCES CECClient.cpp
+ CECProcessor.cpp
+ LibCEC.cpp
+ LibCECC.cpp)
+
+# /adapter
+set(CEC_SOURCES_ADAPTER adapter/AdapterFactory.cpp)
+
+# /adapter/Pulse-Eight
+set(CEC_SOURCES_ADAPTER_P8 adapter/Pulse-Eight/USBCECAdapterMessage.cpp
+ adapter/Pulse-Eight/USBCECAdapterCommands.cpp
+ adapter/Pulse-Eight/USBCECAdapterCommunication.cpp
+ adapter/Pulse-Eight/USBCECAdapterMessageQueue.cpp
+ adapter/Pulse-Eight/USBCECAdapterDetection.cpp)
+
+# /devices
+set(CEC_SOURCES_DEVICES devices/CECAudioSystem.cpp
+ devices/CECBusDevice.cpp
+ devices/CECDeviceMap.cpp
+ devices/CECPlaybackDevice.cpp
+ devices/CECRecordingDevice.cpp
+ devices/CECTuner.cpp
+ devices/CECTV.cpp)
+
+# /implementations
+set(CEC_SOURCES_IMPLEMENTATIONS implementations/ANCommandHandler.cpp
+ implementations/CECCommandHandler.cpp
+ implementations/SLCommandHandler.cpp
+ implementations/VLCommandHandler.cpp
+ implementations/RLCommandHandler.cpp
+ implementations/PHCommandHandler.cpp
+ implementations/RHCommandHandler.cpp
+ implementations/AQCommandHandler.cpp)
+
+# /platform/*
+set(CEC_SOURCES_PLATFORM platform/adl/adl-edid.cpp
+ platform/nvidia/nv-edid.cpp
+ platform/drm/drm-edid.cpp)
+
+# headers
+set(CEC_EXT_HEADERS ${PROJECT_SOURCE_DIR}/../../include/cec.h
+ ${PROJECT_SOURCE_DIR}/../../include/cecc.h
+ ${PROJECT_SOURCE_DIR}/../../include/cecloader.h
+ ${PROJECT_SOURCE_DIR}/../../include/cectypes.h
+ ${PROJECT_SOURCE_DIR}/../../include/version.h)
+source_group("Header Files (external)" FILES ${CEC_EXT_HEADERS})
+set(CEC_HEADERS devices/CECRecordingDevice.h
+ devices/CECTuner.h
+ devices/CECAudioSystem.h
+ devices/CECTV.h
+ devices/CECBusDevice.h
+ devices/CECDeviceMap.h
+ devices/CECPlaybackDevice.h
+ adapter/Exynos/ExynosCEC.h
+ adapter/Exynos/ExynosCECAdapterDetection.h
+ adapter/Exynos/ExynosCECAdapterCommunication.h
+ adapter/AOCEC/AOCEC.h
+ adapter/AOCEC/AOCECAdapterDetection.h
+ adapter/AOCEC/AOCECAdapterCommunication.h
+ adapter/Pulse-Eight/USBCECAdapterMessageQueue.h
+ adapter/Pulse-Eight/USBCECAdapterCommunication.h
+ adapter/Pulse-Eight/USBCECAdapterCommands.h
+ adapter/Pulse-Eight/USBCECAdapterDetection.h
+ adapter/Pulse-Eight/USBCECAdapterMessage.h
+ adapter/TDA995x/TDA995xCECAdapterDetection.h
+ adapter/TDA995x/AdapterMessageQueue.h
+ adapter/TDA995x/TDA995xCECAdapterCommunication.h
+ adapter/AdapterFactory.h
+ adapter/AdapterCommunication.h
+ adapter/RPi/RPiCECAdapterMessageQueue.h
+ adapter/RPi/RPiCECAdapterCommunication.h
+ adapter/RPi/RPiCECAdapterDetection.h
+ CECInputBuffer.h
+ platform/util/baudrate.h
+ platform/util/edid.h
+ platform/nvidia/nv-edid.h
+ platform/adl/adl_structures.h
+ platform/adl/adl_defines.h
+ platform/adl/adl-edid.h
+ platform/adl/adl_sdk.h
+ platform/sockets/serialport.h
+ platform/X11/randr-edid.h
+ CECClient.h
+ LibCEC.h
+ CECTypeUtils.h
+ implementations/SLCommandHandler.h
+ implementations/CECCommandHandler.h
+ implementations/VLCommandHandler.h
+ implementations/RLCommandHandler.h
+ implementations/ANCommandHandler.h
+ implementations/RHCommandHandler.h
+ implementations/PHCommandHandler.h
+ implementations/AQCommandHandler.h
+ CECProcessor.h)
+source_group("Header Files" FILES ${CEC_HEADERS})
+
+# platform and device specific
+include(cmake/SetBuildInfo.cmake)
+include(cmake/CheckPlatformSupport.cmake)
+
+## create project groups
+source_group("Source Files" FILES ${CEC_SOURCES})
+source_group("Source Files\\adapter" FILES ${CEC_SOURCES_ADAPTER})
+source_group("Source Files\\adapter\\Pulse-Eight" FILES ${CEC_SOURCES_ADAPTER_P8})
+source_group("Source Files\\devices" FILES ${CEC_SOURCES_DEVICES})
+source_group("Source Files\\implementations" FILES ${CEC_SOURCES_IMPLEMENTATIONS})
+source_group("Source Files\\platform" FILES ${CEC_SOURCES_PLATFORM})
+
+list(APPEND CEC_SOURCES ${CEC_HEADERS}
+ ${CEC_EXT_HEADERS}
+ ${CEC_SOURCES_ADAPTER}
+ ${CEC_SOURCES_ADAPTER_P8}
+ ${CEC_SOURCES_DEVICES}
+ ${CEC_SOURCES_IMPLEMENTATIONS}
+ ${CEC_SOURCES_PLATFORM})
+
+# write env.h
+set(LIBCEC_LIBREQUIRES "p8-platform ${PLATFORM_LIBREQUIRES}")
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/env.h.in ${CMAKE_CURRENT_SOURCE_DIR}/env.h)
+if (WIN32)
+ # write libcec.rc
+ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/libcec.rc.in ${CMAKE_CURRENT_SOURCE_DIR}/libcec.rc)
+ add_definitions(-DDLL_EXPORT)
+else()
+ # write pkgconfig
+ include(../../cmake/PkgConfigHandler.cmake)
+ configure_pc_file(cec ${CMAKE_CURRENT_SOURCE_DIR}/libcec.pc.in
+ ${CMAKE_CURRENT_SOURCE_DIR}/libcec.pc
+ ${CMAKE_INSTALL_PREFIX}
+ ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}
+ ${CMAKE_INSTALL_PREFIX}/include)
+
+ install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/libcec.pc
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
+endif()
+
+# install headers
+install(FILES ${PROJECT_SOURCE_DIR}/../../include/cec.h
+ ${PROJECT_SOURCE_DIR}/../../include/cecc.h
+ ${PROJECT_SOURCE_DIR}/../../include/cecloader.h
+ ${PROJECT_SOURCE_DIR}/../../include/cectypes.h
+ ${PROJECT_SOURCE_DIR}/../../include/version.h
+ DESTINATION include/libcec)
+
+# libCEC target
+add_library(cec SHARED ${CEC_SOURCES})
+install(TARGETS cec
+ DESTINATION ${LIB_DESTINATION})
+set_target_properties(cec PROPERTIES VERSION ${LIBCEC_VERSION_MAJOR}.${LIBCEC_VERSION_MINOR}.${LIBCEC_VERSION_PATCH}
+ SOVERSION ${LIBCEC_VERSION_MAJOR})
+target_link_libraries(cec ${p8-platform_LIBRARIES})
+target_link_libraries(cec ${CMAKE_THREAD_LIBS_INIT})
+
+include(cmake/LinkPlatformSupport.cmake)
+include(cmake/DisplayPlatformSupport.cmake)
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include "LibCEC.h"
+
+#include "adapter/AdapterFactory.h"
+#include "adapter/AdapterCommunication.h"
+#include "CECProcessor.h"
+#include "devices/CECAudioSystem.h"
+#include "devices/CECBusDevice.h"
+#include "devices/CECPlaybackDevice.h"
+#include "devices/CECTV.h"
+#include <p8-platform/util/timeutils.h>
+#include <p8-platform/util/util.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "CECClient.h"
+
+using namespace CEC;
+using namespace P8PLATFORM;
+
+CLibCEC::CLibCEC(void) :
+ m_iStartTime(GetTimeMs()),
+ m_client(NULL)
+{
+ m_cec = new CCECProcessor(this);
+}
+
+CLibCEC::~CLibCEC(void)
+{
+ // unregister all clients
+ if (m_cec && m_cec->IsRunning())
+ m_cec->UnregisterClients();
+
+ m_clients.clear();
+
+ // delete the adapter connection
+ SAFE_DELETE(m_cec);
+
+ // delete active client
+ m_client.reset();
+}
+
+bool CLibCEC::Open(const char *strPort, uint32_t iTimeoutMs /* = CEC_DEFAULT_CONNECT_TIMEOUT */)
+{
+ if (!m_cec || !strPort)
+ return false;
+
+ // open a new connection
+ if (!m_cec->Start(strPort, CEC_SERIAL_DEFAULT_BAUDRATE, iTimeoutMs))
+ {
+ AddLog(CEC_LOG_ERROR, "could not start CEC communications");
+ return false;
+ }
+
+ // register all clients
+ for (std::vector<CECClientPtr>::iterator it = m_clients.begin(); it != m_clients.end(); it++)
+ {
+ if (!m_cec->RegisterClient(*it))
+ {
+ AddLog(CEC_LOG_ERROR, "failed to register a CEC client");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void CLibCEC::Close(void)
+{
+ if (!m_cec)
+ return;
+
+ // unregister all clients
+ m_cec->UnregisterClients();
+
+ // close the connection
+ m_cec->Close();
+}
+
+int8_t CLibCEC::FindAdapters(cec_adapter *deviceList, uint8_t iBufSize, const char *strDevicePath /* = NULL */)
+{
+ return CAdapterFactory(this).FindAdapters(deviceList, iBufSize, strDevicePath);
+}
+
+bool CLibCEC::StartBootloader(void)
+{
+ return m_cec ? m_cec->StartBootloader() : false;
+}
+
+bool CLibCEC::PingAdapter(void)
+{
+ return m_client ? m_client->PingAdapter() : false;
+}
+
+bool CLibCEC::EnableCallbacks(void *cbParam, ICECCallbacks *callbacks)
+{
+ return m_client ? m_client->EnableCallbacks(cbParam, callbacks) : false;
+}
+
+bool CLibCEC::GetCurrentConfiguration(libcec_configuration *configuration)
+{
+ return m_client ? m_client->GetCurrentConfiguration(*configuration) : false;
+}
+
+bool CLibCEC::SetConfiguration(const libcec_configuration *configuration)
+{
+ return m_client ? m_client->SetConfiguration(*configuration) : false;
+}
+
+bool CLibCEC::CanPersistConfiguration(void)
+{
+ return m_client ? m_client->CanPersistConfiguration() : false;
+}
+
+bool CLibCEC::PersistConfiguration(libcec_configuration *configuration)
+{
+ return m_client ? m_client->PersistConfiguration(*configuration) : false;
+}
+
+void CLibCEC::RescanActiveDevices(void)
+{
+ if (m_client)
+ m_client->RescanActiveDevices();
+}
+
+bool CLibCEC::IsLibCECActiveSource(void)
+{
+ return m_client ? m_client->IsLibCECActiveSource() : false;
+}
+
+bool CLibCEC::Transmit(const cec_command &data)
+{
+ return m_client ? m_client->Transmit(data, false) : false;
+}
+
+bool CLibCEC::SetLogicalAddress(cec_logical_address iLogicalAddress)
+{
+ return m_client ? m_client->SetLogicalAddress(iLogicalAddress) : false;
+}
+
+bool CLibCEC::SetPhysicalAddress(uint16_t iPhysicalAddress /* = CEC_DEFAULT_PHYSICAL_ADDRESS */)
+{
+ return m_client ? m_client->SetPhysicalAddress(iPhysicalAddress) : false;
+}
+
+bool CLibCEC::SetHDMIPort(cec_logical_address iBaseDevice, uint8_t iPort /* = CEC_DEFAULT_HDMI_PORT */)
+{
+ return m_client ? m_client->SetHDMIPort(iBaseDevice, iPort) : false;
+}
+
+bool CLibCEC::PowerOnDevices(cec_logical_address address /* = CECDEVICE_TV */)
+{
+ return m_client ? m_client->SendPowerOnDevices(address) : false;
+}
+
+bool CLibCEC::StandbyDevices(cec_logical_address address /* = CECDEVICE_BROADCAST */)
+{
+ return m_client ? m_client->SendStandbyDevices(address) : false;
+}
+
+bool CLibCEC::SetActiveSource(cec_device_type type /* = CEC_DEVICE_TYPE_RESERVED */)
+{
+ return m_client ? m_client->SendSetActiveSource(type) : false;
+}
+
+bool CLibCEC::SetDeckControlMode(cec_deck_control_mode mode, bool bSendUpdate /* = true */)
+{
+ return m_client ? m_client->SendSetDeckControlMode(mode, bSendUpdate) : false;
+}
+
+bool CLibCEC::SetDeckInfo(cec_deck_info info, bool bSendUpdate /* = true */)
+{
+ return m_client ? m_client->SendSetDeckInfo(info, bSendUpdate) : false;
+}
+
+bool CLibCEC::SetInactiveView(void)
+{
+ return m_client ? m_client->SendSetInactiveView() : false;
+}
+
+bool CLibCEC::SetMenuState(cec_menu_state state, bool bSendUpdate /* = true */)
+{
+ return m_client ? m_client->SendSetMenuState(state, bSendUpdate) : false;
+}
+
+bool CLibCEC::SetOSDString(cec_logical_address iLogicalAddress, cec_display_control duration, const char *strMessage)
+{
+ return m_client ? m_client->SendSetOSDString(iLogicalAddress, duration, strMessage) : false;
+}
+
+bool CLibCEC::SwitchMonitoring(bool bEnable)
+{
+ return m_client ? m_client->SwitchMonitoring(bEnable) : false;
+}
+
+cec_version CLibCEC::GetDeviceCecVersion(cec_logical_address iAddress)
+{
+ return m_client ? m_client->GetDeviceCecVersion(iAddress) : CEC_VERSION_UNKNOWN;
+}
+
+std::string CLibCEC::GetDeviceMenuLanguage(cec_logical_address iAddress)
+{
+ return !!m_client ? m_client->GetDeviceMenuLanguage(iAddress) : "???";
+}
+
+uint32_t CLibCEC::GetDeviceVendorId(cec_logical_address iAddress)
+{
+ return m_client ? m_client->GetDeviceVendorId(iAddress) : (uint32_t)CEC_VENDOR_UNKNOWN;
+}
+
+uint16_t CLibCEC::GetDevicePhysicalAddress(cec_logical_address iAddress)
+{
+ return m_client ? m_client->GetDevicePhysicalAddress(iAddress) : CEC_INVALID_PHYSICAL_ADDRESS;
+}
+
+cec_power_status CLibCEC::GetDevicePowerStatus(cec_logical_address iAddress)
+{
+ return m_client ? m_client->GetDevicePowerStatus(iAddress) : CEC_POWER_STATUS_UNKNOWN;
+}
+
+bool CLibCEC::PollDevice(cec_logical_address iAddress)
+{
+ return m_client ? m_client->PollDevice(iAddress) : false;
+}
+
+cec_logical_addresses CLibCEC::GetActiveDevices(void)
+{
+ cec_logical_addresses addresses;
+ addresses.Clear();
+ if (m_client)
+ addresses = m_client->GetActiveDevices();
+ return addresses;
+}
+
+bool CLibCEC::IsActiveDevice(cec_logical_address iAddress)
+{
+ return m_client ? m_client->IsActiveDevice(iAddress) : false;
+}
+
+bool CLibCEC::IsActiveDeviceType(cec_device_type type)
+{
+ return m_client ? m_client->IsActiveDeviceType(type) : false;
+}
+
+uint8_t CLibCEC::VolumeUp(bool bSendRelease /* = true */)
+{
+ return m_client ? m_client->SendVolumeUp(bSendRelease) : (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
+}
+
+uint8_t CLibCEC::VolumeDown(bool bSendRelease /* = true */)
+{
+ return m_client ? m_client->SendVolumeDown(bSendRelease) : (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
+}
+
+bool CLibCEC::SendKeypress(cec_logical_address iDestination, cec_user_control_code key, bool bWait /* = true */)
+{
+ return m_client ? m_client->SendKeypress(iDestination, key, bWait) : false;
+}
+
+bool CLibCEC::SendKeyRelease(cec_logical_address iDestination, bool bWait /* = true */)
+{
+ return m_client ? m_client->SendKeyRelease(iDestination, bWait) : false;
+}
+
+std::string CLibCEC::GetDeviceOSDName(cec_logical_address iAddress)
+{
+ return !!m_client ?
+ m_client->GetDeviceOSDName(iAddress) :
+ "";
+}
+
+cec_logical_address CLibCEC::GetActiveSource(void)
+{
+ return m_client ? m_client->GetActiveSource() : CECDEVICE_UNKNOWN;
+}
+
+bool CLibCEC::IsActiveSource(cec_logical_address iAddress)
+{
+ return m_client ? m_client->IsActiveSource(iAddress) : false;
+}
+bool CLibCEC::SetStreamPath(cec_logical_address iAddress)
+{
+ return m_client ? m_client->SetStreamPath(iAddress) : false;
+}
+
+bool CLibCEC::SetStreamPath(uint16_t iPhysicalAddress)
+{
+ return m_client ? m_client->SetStreamPath(iPhysicalAddress) : false;
+}
+
+cec_logical_addresses CLibCEC::GetLogicalAddresses(void)
+{
+ cec_logical_addresses addresses;
+ addresses.Clear();
+ if (m_client)
+ addresses = m_client->GetLogicalAddresses();
+ return addresses;
+}
+
+cec_device_type CLibCEC::GetType(cec_logical_address address)
+{
+ return CCECTypeUtils::GetType(address);
+}
+
+uint16_t CLibCEC::GetMaskForType(cec_logical_address address)
+{
+ return CCECTypeUtils::GetMaskForType(address);
+}
+
+uint16_t CLibCEC::GetMaskForType(cec_device_type type)
+{
+ return CCECTypeUtils::GetMaskForType(type);
+}
+
+bool CLibCEC::IsValidPhysicalAddress(uint16_t iPhysicalAddress)
+{
+ return iPhysicalAddress >= CEC_MIN_PHYSICAL_ADDRESS &&
+ iPhysicalAddress <= CEC_MAX_PHYSICAL_ADDRESS;
+}
+
+uint16_t CLibCEC::CheckKeypressTimeout(void)
+{
+ uint16_t timeout = CEC_PROCESSOR_SIGNAL_WAIT_TIME;
+ // check all clients
+ for (std::vector<CECClientPtr>::iterator it = m_clients.begin(); it != m_clients.end(); it++)
+ {
+ uint16_t t = (*it)->CheckKeypressTimeout();
+ if (t < timeout)
+ timeout = t;
+ }
+ return timeout;
+}
+
+void CLibCEC::AddLog(const cec_log_level level, const char *strFormat, ...)
+{
+ // format the message
+ va_list argList;
+ cec_log_message_cpp message;
+ message.level = level;
+ message.time = GetTimeMs() - m_iStartTime;
+ va_start(argList, strFormat);
+ message.message = StringUtils::FormatV(strFormat, argList);
+ va_end(argList);
+
+ // send the message to all clients
+ CLockObject lock(m_mutex);
+ for (std::vector<CECClientPtr>::iterator it = m_clients.begin(); it != m_clients.end(); it++)
+ (*it)->AddLog(message);
+}
+
+void CLibCEC::AddCommand(const cec_command &command)
+{
+ // send the command to all clients
+ CLockObject lock(m_mutex);
+ for (std::vector<CECClientPtr>::iterator it = m_clients.begin(); it != m_clients.end(); it++)
+ (*it)->QueueAddCommand(command);
+}
+
+void CLibCEC::Alert(const libcec_alert type, const libcec_parameter ¶m)
+{
+ // send the alert to all clients
+ CLockObject lock(m_mutex);
+ for (std::vector<CECClientPtr>::iterator it = m_clients.begin(); it != m_clients.end(); it++)
+ (*it)->Alert(type, param);
+}
+
+CECClientPtr CLibCEC::RegisterClient(libcec_configuration &configuration)
+{
+ if (!m_cec)
+ return CECClientPtr();
+ if (configuration.clientVersion < LIBCEC_VERSION_TO_UINT(4, 0, 0))
+ {
+ AddLog(CEC_LOG_ERROR, "failed to register a new CEC client: client version %s is no longer supported", CCECTypeUtils::VersionToString(configuration.clientVersion).c_str());
+ return CECClientPtr();
+ }
+
+ // create a new client instance
+ CECClientPtr newClient = CECClientPtr(new CCECClient(m_cec, configuration));
+ if (!newClient)
+ return newClient;
+ m_clients.push_back(newClient);
+
+ // if the default client isn't set, set it
+ if (!m_client)
+ m_client = newClient;
+
+ // register the new client
+ if (m_cec->CECInitialised())
+ {
+ if (!m_cec->RegisterClient(newClient))
+ newClient = CECClientPtr();
+ }
+
+ return newClient;
+}
+
+ICECAdapter* CECInitialise(libcec_configuration *configuration)
+{
+ if (!configuration)
+ return NULL;
+
+ // create a new libCEC instance
+ CLibCEC *lib = new CLibCEC;
+
+ // register a new client
+ CECClientPtr client;
+ if (lib && configuration)
+ client = lib->RegisterClient(*configuration);
+
+ // update the current configuration
+ if (client)
+ client->GetCurrentConfiguration(*configuration);
+
+ // ensure that the correct server version is set
+ configuration->serverVersion = LIBCEC_VERSION_CURRENT;
+
+ return static_cast<ICECAdapter*> (lib);
+}
+
+void * CECInit(const char *strDeviceName, CEC::cec_device_type_list types)
+{
+ libcec_configuration configuration; configuration.Clear();
+
+ // client version < 1.5.0
+ snprintf(configuration.strDeviceName, 13, "%s", strDeviceName);
+ configuration.deviceTypes = types;
+ configuration.iPhysicalAddress = CEC_INVALID_PHYSICAL_ADDRESS;
+
+ if (configuration.deviceTypes.IsEmpty())
+ configuration.deviceTypes.Add(CEC_DEVICE_TYPE_RECORDING_DEVICE);
+
+ return CECInitialise(&configuration);
+}
+
+bool CECStartBootloader(void)
+{
+ bool bReturn(false);
+ cec_adapter deviceList[1];
+ if (CAdapterFactory(NULL).FindAdapters(deviceList, 1, 0) > 0)
+ {
+ CAdapterFactory factory(NULL);
+ IAdapterCommunication *comm = factory.GetInstance(deviceList[0].comm);
+ if (comm)
+ {
+ CTimeout timeout(CEC_DEFAULT_CONNECT_TIMEOUT);
+ while (timeout.TimeLeft() > 0 &&
+ (bReturn = comm->Open(timeout.TimeLeft() / CEC_CONNECT_TRIES, true)) == false)
+ {
+ comm->Close();
+ CEvent::Sleep(500);
+ }
+ if (comm->IsOpen())
+ bReturn = comm->StartBootloader();
+
+ delete comm;
+ }
+ }
+
+ return bReturn;
+}
+
+void CECDestroy(CEC::ICECAdapter *instance)
+{
+ SAFE_DELETE(instance);
+}
+
+bool CLibCEC::GetDeviceInformation(const char *strPort, libcec_configuration *config, uint32_t iTimeoutMs /* = CEC_DEFAULT_CONNECT_TIMEOUT */)
+{
+ if (m_cec->IsRunning())
+ return false;
+
+ return m_cec->GetDeviceInformation(strPort, config, iTimeoutMs);
+}
+
+const char *CLibCEC::GetLibInfo(void)
+{
+#ifndef LIB_INFO
+#ifdef _WIN32
+#define FEATURES "'P8 USB' 'P8 USB detect'"
+#ifdef _WIN64
+#define HOST_TYPE "Windows (x64)"
+#else
+#define HOST_TYPE "Windows (x86)"
+#endif
+#else
+#define HOST_TYPE "unknown"
+#define FEATURES "unknown"
+#endif
+
+ return "host: " HOST_TYPE ", features: " FEATURES ", compiled: " __DATE__;
+#else
+ return LIB_INFO;
+#endif
+}
+
+void CLibCEC::InitVideoStandalone(void)
+{
+ CAdapterFactory::InitVideoStandalone();
+}
+uint16_t CLibCEC::GetAdapterVendorId(void) const
+{
+ return m_cec && m_cec->IsRunning() ? m_cec->GetAdapterVendorId() : 0;
+}
+
+uint16_t CLibCEC::GetAdapterProductId(void) const
+{
+ return m_cec && m_cec->IsRunning() ? m_cec->GetAdapterProductId() : 0;
+}
+
+uint8_t CLibCEC::AudioToggleMute(void)
+{
+ return m_client ? m_client->AudioToggleMute() : (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
+}
+
+uint8_t CLibCEC::AudioMute(void)
+{
+ return m_client ? m_client->AudioMute() : (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
+}
+
+uint8_t CLibCEC::AudioUnmute(void)
+{
+ return m_client ? m_client->AudioUnmute() : (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
+}
+
+uint8_t CLibCEC::AudioStatus(void)
+{
+ return m_client ? m_client->AudioStatus() : (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
+}
+
+int8_t CLibCEC::DetectAdapters(cec_adapter_descriptor *deviceList, uint8_t iBufSize, const char *strDevicePath /* = NULL */, bool bQuickScan /* = false */)
+{
+ int8_t iAdaptersFound = CAdapterFactory(this).DetectAdapters(deviceList, iBufSize, strDevicePath);
+ if (!bQuickScan)
+ {
+ for (int8_t iPtr = 0; iPtr < iAdaptersFound; iPtr++)
+ {
+ libcec_configuration config;
+ GetDeviceInformation(deviceList[iPtr].strComName, &config);
+ deviceList[iPtr].iFirmwareVersion = config.iFirmwareVersion;
+ deviceList[iPtr].iPhysicalAddress = config.iPhysicalAddress;
+ deviceList[iPtr].iFirmwareBuildDate = config.iFirmwareBuildDate;
+ deviceList[iPtr].adapterType = config.adapterType;
+ }
+ }
+ return iAdaptersFound;
+}
+
+inline bool HexStrToInt(const std::string& data, uint8_t& value)
+{
+ int iTmp(0);
+ if (sscanf(data.c_str(), "%x", &iTmp) == 1)
+ {
+ if (iTmp > 256)
+ value = 255;
+ else if (iTmp < 0)
+ value = 0;
+ else
+ value = (uint8_t) iTmp;
+
+ return true;
+ }
+
+ return false;
+}
+
+cec_command CLibCEC::CommandFromString(const char* strCommand)
+{
+ std::vector<std::string> splitCommand = StringUtils::Split(strCommand, ":");
+ cec_command retval;
+ unsigned long tmpVal;
+
+ for (std::vector<std::string>::const_iterator it = splitCommand.begin(); it != splitCommand.end(); ++it)
+ {
+ tmpVal = strtoul((*it).c_str(), NULL, 16);
+ if (tmpVal <= 0xFF)
+ retval.PushBack((uint8_t)tmpVal);
+ }
+
+ return retval;
+}
+
+void CLibCEC::PrintVersion(uint32_t version, char* buf, size_t bufSize)
+{
+ std::string strVersion = CCECTypeUtils::VersionToString(version);
+ snprintf(buf, bufSize, "%s", strVersion.c_str());
+}
+
+bool CLibCEC::AudioEnable(bool enable)
+{
+ return !!m_client ?
+ m_client->AudioEnable(enable) :
+ false;
+}
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include <string>
+#include "cec.h"
+#include <p8-platform/util/buffer.h>
+#include "CECTypeUtils.h"
+#include <memory>
+
+#define CEC_PROCESSOR_SIGNAL_WAIT_TIME 1000
+
+namespace CEC
+{
+ class CAdapterCommunication;
+ class CCECProcessor;
+ class CCECClient;
+ typedef std::shared_ptr<CCECClient> CECClientPtr;
+
+ typedef struct cec_log_message_cpp
+ {
+ std::string message; /**< the actual message, valid until returning from the log callback */
+ cec_log_level level; /**< log level of the message */
+ int64_t time; /**< the timestamp of this message */
+ } cec_log_message_cpp;
+
+ class CLibCEC : public ICECAdapter
+ {
+ public:
+ CLibCEC(void);
+ virtual ~CLibCEC(void);
+
+ bool Open(const char *strPort, uint32_t iTimeout = CEC_DEFAULT_CONNECT_TIMEOUT);
+ void Close(void);
+ bool EnableCallbacks(void *cbParam, ICECCallbacks *callbacks);
+ int8_t FindAdapters(cec_adapter *deviceList, uint8_t iBufSize, const char *strDevicePath = NULL);
+ int8_t DetectAdapters(cec_adapter_descriptor *deviceList, uint8_t iBufSize, const char *strDevicePath = NULL, bool bQuickScan = false);
+ bool PingAdapter(void);
+ bool StartBootloader(void);
+
+ bool Transmit(const cec_command &data);
+ bool SetLogicalAddress(cec_logical_address iLogicalAddress = CECDEVICE_PLAYBACKDEVICE1);
+ bool SetPhysicalAddress(uint16_t iPhysicalAddress = CEC_DEFAULT_PHYSICAL_ADDRESS);
+
+ bool PowerOnDevices(cec_logical_address address = CECDEVICE_TV);
+ bool StandbyDevices(cec_logical_address address = CECDEVICE_BROADCAST);
+ bool SetActiveSource(cec_device_type type = CEC_DEVICE_TYPE_RESERVED);
+ bool SetDeckControlMode(cec_deck_control_mode mode, bool bSendUpdate = true);
+ bool SetDeckInfo(cec_deck_info info, bool bSendUpdate = true);
+ bool SetInactiveView(void);
+ bool SetMenuState(cec_menu_state state, bool bSendUpdate = true);
+ bool SetOSDString(cec_logical_address iLogicalAddress, cec_display_control duration, const char *strMessage);
+ bool SwitchMonitoring(bool bEnable);
+ cec_version GetDeviceCecVersion(cec_logical_address iAddress);
+ std::string GetDeviceMenuLanguage(cec_logical_address iAddress);
+ uint32_t GetDeviceVendorId(cec_logical_address iAddress);
+ uint16_t GetDevicePhysicalAddress(cec_logical_address iAddress);
+ cec_power_status GetDevicePowerStatus(cec_logical_address iAddress);
+ bool PollDevice(cec_logical_address iAddress);
+ cec_logical_addresses GetActiveDevices(void);
+ bool IsActiveDevice(cec_logical_address iAddress);
+ bool IsActiveDeviceType(cec_device_type type);
+ bool SetHDMIPort(cec_logical_address iBaseDevice, uint8_t iPort = CEC_DEFAULT_HDMI_PORT);
+ uint8_t VolumeUp(bool bSendRelease = true);
+ uint8_t VolumeDown(bool bSendRelease = true);
+ uint8_t MuteAudio(bool bSendRelease = true);
+ bool SendKeypress(cec_logical_address iDestination, cec_user_control_code key, bool bWait = true);
+ bool SendKeyRelease(cec_logical_address iDestination, bool bWait = true);
+ std::string GetDeviceOSDName(cec_logical_address iAddress);
+ cec_logical_address GetActiveSource(void);
+ bool IsActiveSource(cec_logical_address iAddress);
+ bool SetStreamPath(cec_logical_address iAddress);
+ bool SetStreamPath(uint16_t iPhysicalAddress);
+ cec_logical_addresses GetLogicalAddresses(void);
+ bool GetCurrentConfiguration(libcec_configuration *configuration);
+ bool SetConfiguration(const libcec_configuration *configuration);
+ bool CanPersistConfiguration(void);
+ bool PersistConfiguration(libcec_configuration *configuration);
+ void RescanActiveDevices(void);
+ bool IsLibCECActiveSource(void);
+
+ const char* ToString(const cec_menu_state state) { return CCECTypeUtils::ToString(state); }
+ const char* ToString(const cec_version version) { return CCECTypeUtils::ToString(version); }
+ const char* ToString(const cec_power_status status) { return CCECTypeUtils::ToString(status); }
+ const char* ToString(const cec_logical_address address) { return CCECTypeUtils::ToString(address); }
+ const char* ToString(const cec_deck_control_mode mode) { return CCECTypeUtils::ToString(mode); }
+ const char* ToString(const cec_deck_info status) { return CCECTypeUtils::ToString(status); }
+ const char* ToString(const cec_opcode opcode) { return CCECTypeUtils::ToString(opcode); }
+ const char* ToString(const cec_system_audio_status mode) { return CCECTypeUtils::ToString(mode); }
+ const char* ToString(const cec_audio_status status) { return CCECTypeUtils::ToString(status); }
+ const char* ToString(const cec_device_type type) { return CCECTypeUtils::ToString(type); }
+ const char* ToString(const cec_user_control_code key) { return CCECTypeUtils::ToString(key); }
+ const char* ToString(const cec_adapter_type type) { return CCECTypeUtils::ToString(type); }
+ std::string VersionToString(uint32_t version) { return CCECTypeUtils::VersionToString(version); }
+ void PrintVersion(uint32_t version, char* buf, size_t bufSize);
+ const char* VendorIdToString(uint32_t vendor) { return CCECTypeUtils::ToString((cec_vendor_id)vendor); }
+
+ static cec_device_type GetType(cec_logical_address address);
+ static uint16_t GetMaskForType(cec_logical_address address);
+ static uint16_t GetMaskForType(cec_device_type type);
+
+ bool GetDeviceInformation(const char *strPort, libcec_configuration *config, uint32_t iTimeoutMs = CEC_DEFAULT_CONNECT_TIMEOUT);
+
+ void AddLog(const cec_log_level level, const char *strFormat, ...);
+ void AddCommand(const cec_command &command);
+ uint16_t CheckKeypressTimeout(void);
+ void Alert(const libcec_alert type, const libcec_parameter ¶m);
+
+ static bool IsValidPhysicalAddress(uint16_t iPhysicalAddress);
+ CECClientPtr RegisterClient(libcec_configuration &configuration);
+ std::vector<CECClientPtr> GetClients(void) { return m_clients; };
+ const char *GetLibInfo(void);
+ void InitVideoStandalone(void);
+ uint16_t GetAdapterVendorId(void) const;
+ uint16_t GetAdapterProductId(void) const;
+
+ uint8_t AudioToggleMute(void);
+ uint8_t AudioMute(void);
+ uint8_t AudioUnmute(void);
+ uint8_t AudioStatus(void);
+
+ cec_command CommandFromString(const char* strCommand);
+
+ bool AudioEnable(bool enable);
+
+ CCECProcessor * m_cec;
+
+ protected:
+ int64_t m_iStartTime;
+ P8PLATFORM::CMutex m_mutex;
+ CECClientPtr m_client;
+ std::vector<CECClientPtr> m_clients;
+ };
+};
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include "cec.h"
+#include "cecc.h"
+#include "LibCEC.h"
+#include "CECTypeUtils.h"
+#include <algorithm>
+
+using namespace CEC;
+
+/*!
+ * C interface implementation
+ */
+//@{
+
+libcec_connection_t libcec_initialise(libcec_configuration* configuration)
+{
+ return (ICECAdapter*) CECInitialise(configuration);
+}
+
+void libcec_destroy(libcec_connection_t connection)
+{
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ if (adapter)
+ {
+ libcec_close(connection);
+ CECDestroy(adapter);
+ }
+}
+
+int libcec_open(libcec_connection_t connection, const char* strPort, uint32_t iTimeout)
+{
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ return adapter && adapter->Open(strPort, iTimeout);
+}
+
+void libcec_close(libcec_connection_t connection)
+{
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ if (adapter)
+ adapter->Close();
+}
+
+void libcec_clear_configuration(libcec_configuration* configuration)
+{
+ if (configuration)
+ configuration->Clear();
+}
+
+int libcec_enable_callbacks(libcec_connection_t connection, void* cbParam, ICECCallbacks* callbacks)
+{
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ if (adapter)
+ return adapter->EnableCallbacks(cbParam, callbacks) ? 1 : 0;
+ return -1;
+}
+
+int8_t libcec_find_adapters(libcec_connection_t connection, cec_adapter* deviceList, uint8_t iBufSize, const char* strDevicePath)
+{
+ //TODO change to use DetectAdapters()
+ CLibCEC* adapter = static_cast<CLibCEC*>(connection);
+ return adapter ?
+ adapter->FindAdapters(deviceList, iBufSize, strDevicePath) :
+ -1;
+}
+
+int libcec_ping_adapters(libcec_connection_t connection)
+{
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ return adapter ?
+ (adapter->PingAdapter() ? 1 : 0) :
+ -1;
+}
+
+int libcec_start_bootloader(libcec_connection_t connection)
+{
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ return adapter ?
+ (adapter->StartBootloader() ? 1 : 0) :
+ -1;
+}
+
+int libcec_transmit(libcec_connection_t connection, const CEC::cec_command* data)
+{
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ return adapter ?
+ (adapter->Transmit(*data) ? 1 : 0) :
+ -1;
+}
+
+int libcec_set_logical_address(libcec_connection_t connection, cec_logical_address iLogicalAddress)
+{
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ return adapter ?
+ (adapter->SetLogicalAddress(iLogicalAddress) ? 1 : 0) :
+ -1;
+}
+
+int libcec_set_physical_address(libcec_connection_t connection, uint16_t iPhysicalAddress)
+{
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ return adapter ?
+ (adapter->SetPhysicalAddress(iPhysicalAddress) ? 1 : 0) :
+ -1;
+}
+
+int libcec_power_on_devices(libcec_connection_t connection, cec_logical_address address)
+{
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ return adapter ?
+ (adapter->PowerOnDevices(address) ? 1 : 0) :
+ -1;
+}
+
+int libcec_standby_devices(libcec_connection_t connection, cec_logical_address address)
+{
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ return adapter ?
+ (adapter->StandbyDevices(address) ? 1 : 0) :
+ -1;
+}
+
+int libcec_set_active_source(libcec_connection_t connection, cec_device_type type)
+{
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ return adapter ?
+ (adapter->SetActiveSource(type) ? 1 : 0) :
+ -1;
+}
+
+int libcec_set_deck_control_mode(libcec_connection_t connection, cec_deck_control_mode mode, int bSendUpdate) {
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ return adapter ?
+ (adapter->SetDeckControlMode(mode, bSendUpdate == 1) ? 1 : 0) :
+ -1;
+}
+
+int libcec_set_deck_info(libcec_connection_t connection, cec_deck_info info, int bSendUpdate) {
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ return adapter ?
+ (adapter->SetDeckInfo(info, bSendUpdate == 1) ? 1 : 0) :
+ -1;
+
+}
+
+int libcec_set_inactive_view(libcec_connection_t connection)
+{
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ return adapter ?
+ (adapter->SetInactiveView() ? 1 : 0) :
+ -1;
+}
+
+int libcec_set_menu_state(libcec_connection_t connection, cec_menu_state state, int bSendUpdate) {
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ return adapter ?
+ (adapter->SetMenuState(state, bSendUpdate == 1) ? 1 : 0) :
+ -1;
+}
+
+int libcec_set_osd_string(libcec_connection_t connection, cec_logical_address iLogicalAddress, cec_display_control duration, const char* strMessage)
+{
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ return adapter ?
+ (adapter->SetOSDString(iLogicalAddress, duration, strMessage) ? 1 : 0) :
+ -1;
+}
+
+int libcec_switch_monitoring(libcec_connection_t connection, int bEnable)
+{
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ return adapter ?
+ (adapter->SwitchMonitoring(bEnable == 1) ? 1 : 0) :
+ -1;
+}
+
+cec_version libcec_get_device_cec_version(libcec_connection_t connection, cec_logical_address iLogicalAddress)
+{
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ return adapter ?
+ adapter->GetDeviceCecVersion(iLogicalAddress) :
+ CEC_VERSION_UNKNOWN;
+}
+
+int libcec_get_device_menu_language(libcec_connection_t connection, cec_logical_address iLogicalAddress, cec_menu_language language)
+{
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ if (!!adapter)
+ {
+ std::string menuLang(adapter->GetDeviceMenuLanguage(iLogicalAddress));
+ strncpy(language, menuLang.c_str(), 4);
+ return 0;
+ }
+ return -1;
+}
+
+uint32_t libcec_get_device_vendor_id(libcec_connection_t connection, cec_logical_address iLogicalAddress)
+{
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ return adapter ?
+ adapter->GetDeviceVendorId(iLogicalAddress) :
+ 0;
+}
+
+uint16_t libcec_get_device_physical_address(libcec_connection_t connection, cec_logical_address iLogicalAddress)
+{
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ return adapter ?
+ adapter->GetDevicePhysicalAddress(iLogicalAddress) :
+ 0;
+}
+
+cec_logical_address libcec_get_active_source(libcec_connection_t connection)
+{
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ return adapter ?
+ adapter->GetActiveSource() :
+ CECDEVICE_UNKNOWN;
+}
+
+int libcec_is_active_source(libcec_connection_t connection, cec_logical_address iAddress)
+{
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ return adapter ?
+ adapter->IsActiveSource(iAddress) :
+ 0;
+}
+
+cec_power_status libcec_get_device_power_status(libcec_connection_t connection, cec_logical_address iLogicalAddress)
+{
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ return adapter ?
+ adapter->GetDevicePowerStatus(iLogicalAddress) :
+ CEC_POWER_STATUS_UNKNOWN;
+}
+
+int libcec_poll_device(libcec_connection_t connection, cec_logical_address iLogicalAddress)
+{
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ return adapter ?
+ (adapter->PollDevice(iLogicalAddress) ? 1 : 0) :
+ -1;
+}
+
+cec_logical_addresses libcec_get_active_devices(libcec_connection_t connection)
+{
+ cec_logical_addresses addresses;
+ addresses.Clear();
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ if (adapter)
+ addresses = adapter->GetActiveDevices();
+ return addresses;
+}
+
+int libcec_is_active_device(libcec_connection_t connection, cec_logical_address iAddress)
+{
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ return adapter ?
+ (adapter->IsActiveDevice(iAddress) ? 1 : 0) :
+ -1;
+}
+
+int libcec_is_active_device_type(libcec_connection_t connection, cec_device_type type)
+{
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ return adapter ?
+ (adapter->IsActiveDeviceType(type) ? 1 : 0) :
+ -1;
+}
+
+int libcec_set_hdmi_port(libcec_connection_t connection, cec_logical_address iBaseDevice, uint8_t iPort)
+{
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ return adapter ?
+ (adapter->SetHDMIPort(iBaseDevice, iPort) ? 1 : 0) :
+ -1;
+}
+
+int libcec_volume_up(libcec_connection_t connection, int bSendRelease)
+{
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ return adapter ?
+ adapter->VolumeUp(bSendRelease == 1) :
+ -1;
+}
+
+int libcec_volume_down(libcec_connection_t connection, int bSendRelease)
+{
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ return adapter ?
+ adapter->VolumeDown(bSendRelease == 1) :
+ -1;
+}
+
+int libcec_mute_audio(libcec_connection_t connection, int UNUSED(bSendRelease))
+{
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ return adapter ?
+ adapter->AudioToggleMute() :
+ -1;
+}
+
+int libcec_send_keypress(libcec_connection_t connection, cec_logical_address iDestination, cec_user_control_code key, int bWait)
+{
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ return adapter ?
+ (adapter->SendKeypress(iDestination, key, bWait == 1) ? 1 : 0) :
+ -1;
+}
+
+int libcec_send_key_release(libcec_connection_t connection, cec_logical_address iDestination, int bWait)
+{
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ return adapter ?
+ (adapter->SendKeyRelease(iDestination, bWait == 1) ? 1 : 0) :
+ -1;
+}
+
+int libcec_get_device_osd_name(libcec_connection_t connection, cec_logical_address iAddress, cec_osd_name name)
+{
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ if (!!adapter)
+ {
+ std::string osdName(adapter->GetDeviceOSDName(iAddress));
+ strncpy(name, osdName.c_str(), std::min(sizeof(cec_osd_name), osdName.size()));
+ return 0;
+ }
+ return -1;
+}
+
+int libcec_set_stream_path_logical(libcec_connection_t connection, cec_logical_address iAddress)
+{
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ return adapter ?
+ (adapter->SetStreamPath(iAddress) ? 1 : 0) :
+ -1;
+}
+
+int libcec_set_stream_path_physical(libcec_connection_t connection, uint16_t iPhysicalAddress)
+{
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ return adapter ?
+ (adapter->SetStreamPath(iPhysicalAddress) ? 1 : 0) :
+ -1;
+}
+
+cec_logical_addresses libcec_get_logical_addresses(libcec_connection_t connection)
+{
+ cec_logical_addresses addr;
+ addr.Clear();
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ if (adapter)
+ addr = adapter->GetLogicalAddresses();
+ return addr;
+}
+
+int libcec_get_current_configuration(libcec_connection_t connection, libcec_configuration* configuration)
+{
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ return adapter ?
+ (adapter->GetCurrentConfiguration(configuration) ? 1 : 0) :
+ -1;
+}
+
+int libcec_can_persist_configuration(libcec_connection_t connection)
+{
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ return adapter ?
+ (adapter->CanPersistConfiguration() ? 1 : 0) :
+ -1;
+}
+
+int libcec_persist_configuration(libcec_connection_t connection, libcec_configuration* configuration)
+{
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ return adapter ?
+ (adapter->PersistConfiguration(configuration) ? 1 : 0) :
+ -1;
+}
+
+int libcec_set_configuration(libcec_connection_t connection, libcec_configuration* configuration)
+{
+ return libcec_set_configuration(connection, static_cast<const libcec_configuration*>(configuration));
+}
+
+int libcec_set_configuration(libcec_connection_t connection, const libcec_configuration* configuration)
+{
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ return adapter ?
+ (adapter->SetConfiguration(configuration) ? 1 : 0) :
+ -1;
+}
+
+void libcec_rescan_devices(libcec_connection_t connection)
+{
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ if (adapter)
+ adapter->RescanActiveDevices();
+}
+
+int libcec_is_libcec_active_source(libcec_connection_t connection)
+{
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ return adapter ?
+ (adapter->IsLibCECActiveSource() ? 1 : 0) :
+ -1;
+}
+
+int libcec_get_device_information(libcec_connection_t connection, const char* strPort, CEC::libcec_configuration* config, uint32_t iTimeoutMs)
+{
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ return adapter ?
+ (adapter->GetDeviceInformation(strPort, config, iTimeoutMs) ? 1 : 0) :
+ -1;
+}
+
+const char* libcec_get_lib_info(libcec_connection_t connection)
+{
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ return adapter ?
+ adapter->GetLibInfo() :
+ NULL;
+}
+
+void libcec_init_video_standalone(libcec_connection_t connection)
+{
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ if (adapter)
+ adapter->InitVideoStandalone();
+}
+
+uint16_t libcec_get_adapter_vendor_id(libcec_connection_t connection)
+{
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ return adapter ?
+ adapter->GetAdapterVendorId() :
+ 0;
+}
+
+uint16_t libcec_get_adapter_product_id(libcec_connection_t connection)
+{
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ return adapter ?
+ adapter->GetAdapterProductId() :
+ 0;
+}
+
+uint8_t libcec_audio_toggle_mute(libcec_connection_t connection)
+{
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ return adapter ?
+ adapter->AudioToggleMute() :
+ (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
+}
+
+uint8_t libcec_audio_mute(libcec_connection_t connection)
+{
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ return adapter ?
+ adapter->AudioMute() :
+ (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
+}
+
+uint8_t libcec_audio_unmute(libcec_connection_t connection)
+{
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ return adapter ?
+ adapter->AudioUnmute() :
+ (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
+}
+
+uint8_t libcec_audio_get_status(libcec_connection_t connection)
+{
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ return adapter ?
+ adapter->AudioStatus() :
+ (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
+}
+
+int8_t libcec_detect_adapters(libcec_connection_t connection, cec_adapter_descriptor* deviceList, uint8_t iBufSize, const char* strDevicePath, int bQuickScan)
+{
+ ICECAdapter* adapter = static_cast<ICECAdapter*>(connection);
+ return adapter ?
+ adapter->DetectAdapters(deviceList, iBufSize, strDevicePath, bQuickScan == 1) :
+ -1;
+}
+
+void libcec_menu_state_to_string(const CEC_NAMESPACE cec_menu_state state, char* buf, size_t bufsize)
+{
+ std::string strBuf(CCECTypeUtils::ToString(state));
+ strncpy(buf, strBuf.c_str(), bufsize);
+}
+
+void libcec_cec_version_to_string(const CEC_NAMESPACE cec_version version, char* buf, size_t bufsize)
+{
+ std::string strBuf(CCECTypeUtils::ToString(version));
+ strncpy(buf, strBuf.c_str(), bufsize);
+}
+
+void libcec_power_status_to_string(const CEC_NAMESPACE cec_power_status status, char* buf, size_t bufsize)
+{
+ std::string strBuf(CCECTypeUtils::ToString(status));
+ strncpy(buf, strBuf.c_str(), bufsize);
+}
+
+void libcec_logical_address_to_string(const CEC_NAMESPACE cec_logical_address address, char* buf, size_t bufsize)
+{
+ std::string strBuf(CCECTypeUtils::ToString(address));
+ strncpy(buf, strBuf.c_str(), bufsize);
+}
+
+void libcec_deck_control_mode_to_string(const CEC_NAMESPACE cec_deck_control_mode mode, char* buf, size_t bufsize)
+{
+ std::string strBuf(CCECTypeUtils::ToString(mode));
+ strncpy(buf, strBuf.c_str(), bufsize);
+}
+
+void libcec_deck_status_to_string(const CEC_NAMESPACE cec_deck_info status, char* buf, size_t bufsize)
+{
+ std::string strBuf(CCECTypeUtils::ToString(status));
+ strncpy(buf, strBuf.c_str(), bufsize);
+}
+
+void libcec_opcode_to_string(const CEC_NAMESPACE cec_opcode opcode, char* buf, size_t bufsize)
+{
+ std::string strBuf(CCECTypeUtils::ToString(opcode));
+ strncpy(buf, strBuf.c_str(), bufsize);
+}
+
+void libcec_system_audio_status_to_string(const CEC_NAMESPACE cec_system_audio_status mode, char* buf, size_t bufsize)
+{
+ std::string strBuf(CCECTypeUtils::ToString(mode));
+ strncpy(buf, strBuf.c_str(), bufsize);
+}
+
+void libcec_audio_status_to_string(const CEC_NAMESPACE cec_audio_status status, char* buf, size_t bufsize)
+{
+ std::string strBuf(CCECTypeUtils::ToString(status));
+ strncpy(buf, strBuf.c_str(), bufsize);
+}
+
+void libcec_vendor_id_to_string(const CEC_NAMESPACE cec_vendor_id vendor, char* buf, size_t bufsize)
+{
+ std::string strBuf(CCECTypeUtils::ToString(vendor));
+ strncpy(buf, strBuf.c_str(), bufsize);
+}
+
+void libcec_user_control_key_to_string(const CEC_NAMESPACE cec_user_control_code key, char* buf, size_t bufsize)
+{
+ std::string strBuf(CCECTypeUtils::ToString(key));
+ strncpy(buf, strBuf.c_str(), bufsize);
+}
+
+void libcec_adapter_type_to_string(const CEC_NAMESPACE cec_adapter_type type, char* buf, size_t bufsize)
+{
+ std::string strBuf(CCECTypeUtils::ToString(type));
+ strncpy(buf, strBuf.c_str(), bufsize);
+}
+
+void libcec_version_to_string(uint32_t version, char* buf, size_t bufsize)
+{
+ std::string strBuf(CCECTypeUtils::VersionToString(version));
+ strncpy(buf, strBuf.c_str(), bufsize);
+}
+
+//@}
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+
+int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*)
+{
+ return 1;
+}
+
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#define SWIG_FILE_WITH_INIT
+#define SWIG_PYTHON_THREADS
+#define SWIG_PYTHON_USE_GIL
+#define LIBCEC_SWIG_EXPORTS
+
+#include "cectypes.h"
+#include "cec.h"
+#include "CECTypeUtils.h"
+#include <p8-platform/threads/mutex.h>
+/** XXX only to keep the IDE happy, using the actual Python.h with the correct system version when building */
+#ifndef Py_PYTHON_H
+#include <python2.7/Python.h>
+#include <assert.h>
+#endif
+
+namespace CEC
+{
+ enum libcecSwigCallback {
+ PYTHON_CB_LOG_MESSAGE,
+ PYTHON_CB_KEY_PRESS,
+ PYTHON_CB_COMMAND,
+ PYTHON_CB_ALERT,
+ PYTHON_CB_MENU_STATE,
+ PYTHON_CB_SOURCE_ACTIVATED,
+ NB_PYTHON_CB,
+ };
+
+ class CCecPythonCallbacks
+ {
+ public:
+ /**
+ * Create a new python callbacks instance, and set callbacks in the configuration
+ * @param config the configuration to set the callbacks in
+ */
+ CCecPythonCallbacks(libcec_configuration* config) :
+ m_configuration(config)
+ {
+ assert(m_configuration);
+
+ config->callbacks = new ICECCallbacks;
+ if (!config->callbacks)
+ throw std::bad_alloc();
+
+ for (size_t ptr = 0; ptr < NB_PYTHON_CB; ++ptr)
+ m_callbacks[ptr] = NULL;
+
+ m_configuration->callbacks->logMessage = CBCecLogMessage;
+ m_configuration->callbacks->keyPress = CBCecKeyPress;
+ m_configuration->callbacks->commandReceived = CBCecCommand;
+ m_configuration->callbacks->menuStateChanged = CBCecMenuStateChanged;
+ m_configuration->callbacks->sourceActivated = CBCecSourceActivated;
+ }
+
+ /**
+ * Unreferences all python callbacks, and deletes the callbacks
+ */
+ virtual ~CCecPythonCallbacks(void)
+ {
+ for (size_t ptr = 0; ptr < NB_PYTHON_CB; ++ptr)
+ if (m_callbacks[ptr])
+ Py_XDECREF(m_callbacks[ptr]);
+ delete m_configuration->callbacks;
+ m_configuration->callbacks = nullptr;
+ }
+
+ /**
+ * Call a python callback (if set)
+ * @param callback the callback to call
+ * @param arglist the arguments to pass to the callback
+ * @return 0 if the callback failed, the result returned by python otherwise
+ */
+ int CallPythonCallback(enum libcecSwigCallback callback, PyObject* arglist)
+ {
+ int retval = 0;
+
+ if (callback >= NB_PYTHON_CB || !m_callbacks[callback])
+ return retval;
+
+ PyObject* result = NULL;
+ if (m_callbacks[callback])
+ {
+ /** call the callback */
+ result = PyEval_CallObject(m_callbacks[callback], arglist);
+
+ /** unref the argument and result */
+ if (!!arglist)
+ Py_DECREF(arglist);
+ if (!!result)
+ {
+ if (PyInt_Check(result))
+ retval = (int)PyInt_AsLong(result);
+ Py_XDECREF(result);
+ }
+ }
+
+ return retval;
+ }
+
+ /**
+ * Set a python callable as callback
+ * @param cb the callback to set
+ * @param pyfunc the python callable to call
+ */
+ void SetCallback(size_t cb, PyObject* pyfunc)
+ {
+ assert(cb < NB_PYTHON_CB);
+ assert(PyCallable_Check(pyfunc));
+
+ /** unref previous callback (if any) */
+ if (m_callbacks[cb])
+ Py_XDECREF(m_callbacks[cb]);
+
+ /** set the new callback */
+ m_callbacks[cb] = pyfunc;
+ Py_XINCREF(pyfunc);
+ }
+
+ private:
+ static inline int CallPythonCallback(void* param, enum libcecSwigCallback callback, PyObject* arglist)
+ {
+ CCecPythonCallbacks* pCallbacks = static_cast<CCecPythonCallbacks*>(param);
+ return pCallbacks ?
+ pCallbacks->CallPythonCallback(callback, arglist) :
+ 0;
+ }
+
+ static void CBCecLogMessage(void* param, const CEC::cec_log_message* message)
+ {
+ PyGILState_STATE gstate = PyGILState_Ensure();
+ PyObject* arglist = Py_BuildValue("(I,I,s)", message->level, (long)message->time, message->message);
+ CallPythonCallback(param, PYTHON_CB_LOG_MESSAGE, arglist);
+ PyGILState_Release(gstate);
+ }
+
+ static void CBCecKeyPress(void* param, const CEC::cec_keypress* key)
+ {
+ PyGILState_STATE gstate = PyGILState_Ensure();
+ CallPythonCallback(param, PYTHON_CB_KEY_PRESS,
+ Py_BuildValue("(I,I)", (long)key->keycode, (long)key->duration));
+ PyGILState_Release(gstate);
+ }
+
+ static void CBCecCommand(void* param, const CEC::cec_command* command)
+ {
+ PyGILState_STATE gstate = PyGILState_Ensure();
+ CallPythonCallback(param, PYTHON_CB_COMMAND,
+ Py_BuildValue("(s)", CEC::CCECTypeUtils::ToString(*command).c_str()));
+ PyGILState_Release(gstate);
+ }
+
+ static int CBCecMenuStateChanged(void* param, const CEC::cec_menu_state state)
+ {
+ PyGILState_STATE gstate = PyGILState_Ensure();
+ int retval = CallPythonCallback(param, PYTHON_CB_MENU_STATE,
+ Py_BuildValue("(I)", state));
+ PyGILState_Release(gstate);
+ return retval;
+ }
+
+ static void CBCecSourceActivated(void* param, const CEC::cec_logical_address logicalAddress, const uint8_t activated)
+ {
+ PyGILState_STATE gstate = PyGILState_Ensure();
+ CallPythonCallback(param, PYTHON_CB_SOURCE_ACTIVATED,
+ Py_BuildValue("(I,I)", logicalAddress, activated));
+ PyGILState_Release(gstate);
+ }
+
+ PyObject* m_callbacks[NB_PYTHON_CB];
+ libcec_configuration* m_configuration;
+ };
+
+ static CCecPythonCallbacks* _GetCallbacks(CEC::libcec_configuration* self)
+ {
+ /** allocate callbacks struct and python callbacks if needed */
+ if (!self->callbackParam)
+ self->callbackParam = new CCecPythonCallbacks(self);
+
+ return static_cast<CCecPythonCallbacks*>(self->callbackParam);
+ }
+}
+
+static void _SetCallback(CEC::libcec_configuration* self, size_t cb, PyObject* pyfunc)
+{
+ assert(self);
+ CEC::CCecPythonCallbacks* pCallbacks = CEC::_GetCallbacks(self);
+ if (pCallbacks)
+ pCallbacks->SetCallback(cb, pyfunc);
+ else
+ printf("ERROR: cannot set callback to %p: out of memory\n", pyfunc);
+}
+
+void _ClearCallbacks(CEC::libcec_configuration* self)
+{
+ CEC::CCecPythonCallbacks* pCallbacks = static_cast<CEC::CCecPythonCallbacks*>(self->callbackParam);
+ if (pCallbacks)
+ delete pCallbacks;
+ self->callbackParam = NULL;
+}
+
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC AOCEC Code Copyright (C) 2016 Gerald Dachs
+ * based heavily on:
+ * libCEC Exynos Code Copyright (C) 2014 Valentin Manea
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+
+#define CEC_IOC_MAGIC 'C'
+#define CEC_IOC_GET_PHYSICAL_ADDR _IOR(CEC_IOC_MAGIC, 0x00, uint16_t)
+#define CEC_IOC_GET_VERSION _IOR(CEC_IOC_MAGIC, 0x01, int)
+#define CEC_IOC_GET_VENDOR_ID _IOR(CEC_IOC_MAGIC, 0x02, uint32_t)
+#define CEC_IOC_GET_PORT_INFO _IOR(CEC_IOC_MAGIC, 0x03, int)
+#define CEC_IOC_GET_PORT_NUM _IOR(CEC_IOC_MAGIC, 0x04, int)
+#define CEC_IOC_GET_SEND_FAIL_REASON _IOR(CEC_IOC_MAGIC, 0x05, uint32_t)
+#define CEC_IOC_SET_OPTION_WAKEUP _IOW(CEC_IOC_MAGIC, 0x06, uint32_t)
+#define CEC_IOC_SET_OPTION_ENALBE_CEC _IOW(CEC_IOC_MAGIC, 0x07, uint32_t)
+#define CEC_IOC_SET_OPTION_SYS_CTRL _IOW(CEC_IOC_MAGIC, 0x08, uint32_t)
+#define CEC_IOC_SET_OPTION_SET_LANG _IOW(CEC_IOC_MAGIC, 0x09, uint32_t)
+#define CEC_IOC_GET_CONNECT_STATUS _IOR(CEC_IOC_MAGIC, 0x0A, uint32_t)
+#define CEC_IOC_ADD_LOGICAL_ADDR _IOW(CEC_IOC_MAGIC, 0x0B, uint32_t)
+#define CEC_IOC_CLR_LOGICAL_ADDR _IOW(CEC_IOC_MAGIC, 0x0C, uint32_t)
+
+#define CEC_MAX_FRAME_SIZE 16
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC AOCEC Code Copyright (C) 2016 Gerald Dachs
+ * based heavily on:
+ * libCEC Exynos Code Copyright (C) 2014 Valentin Manea
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+#if defined(HAVE_AOCEC_API)
+#include "AOCEC.h"
+#include "AOCECAdapterCommunication.h"
+#include "CECTypeUtils.h"
+#include "LibCEC.h"
+#include <p8-platform/util/buffer.h>
+
+using namespace CEC;
+using namespace P8PLATFORM;
+
+#define LIB_CEC m_callback->GetLib()
+
+CAOCECAdapterCommunication::CAOCECAdapterCommunication(IAdapterCommunicationCallback *callback) :
+ IAdapterCommunication(callback),
+ m_bLogicalAddressChanged(false)
+{
+ CLockObject lock(m_mutex);
+
+ m_logicalAddresses.Clear();
+ m_fd = INVALID_SOCKET_VALUE;
+}
+
+CAOCECAdapterCommunication::~CAOCECAdapterCommunication(void)
+{
+ Close();
+}
+
+bool CAOCECAdapterCommunication::IsOpen(void)
+{
+ CLockObject lock(m_mutex);
+ return IsInitialised() && m_fd != INVALID_SOCKET_VALUE;
+}
+
+bool CAOCECAdapterCommunication::Open(uint32_t UNUSED(iTimeoutMs), bool UNUSED(bSkipChecks), bool bStartListening)
+{
+ CLockObject lock(m_mutex);
+
+ if (IsOpen())
+ Close();
+
+ if ((m_fd = open(CEC_AOCEC_PATH, O_RDWR)) > 0)
+ {
+ uint32_t enable = 1;
+
+ if (ioctl(m_fd, CEC_IOC_SET_OPTION_SYS_CTRL, enable))
+ {
+ LIB_CEC->AddLog(CEC_LOG_WARNING, "%s: ioctl(CEC_IOC_SET_OPTION_SYS_CTRL) failed", __func__);
+ return false;
+ }
+
+ if (!bStartListening || CreateThread()) {
+ return true;
+ }
+ close(m_fd);
+ m_fd = INVALID_SOCKET_VALUE;
+ }
+ return false;
+}
+
+void CAOCECAdapterCommunication::Close(void)
+{
+ StopThread(0);
+
+ CLockObject lock(m_mutex);
+
+ uint32_t enable = 0;
+
+ if (ioctl(m_fd, CEC_IOC_SET_OPTION_SYS_CTRL, enable))
+ {
+ LIB_CEC->AddLog(CEC_LOG_WARNING, "%s: ioctl(CEC_IOC_SET_OPTION_SYS_CTRL) failed", __func__);
+ }
+
+ close(m_fd);
+ m_fd = INVALID_SOCKET_VALUE;
+}
+
+std::string CAOCECAdapterCommunication::GetError(void) const
+{
+// TODO CLockObject lock(m_mutex);
+ std::string strError(m_strError);
+ return strError;
+}
+
+cec_adapter_message_state CAOCECAdapterCommunication::Write(
+ const cec_command &data, bool &UNUSED(bRetry), uint8_t UNUSED(iLineTimeout), bool UNUSED(bIsReply))
+{
+ uint8_t buffer[CEC_MAX_FRAME_SIZE];
+ int32_t size = 1;
+ cec_adapter_message_state rc = ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED;
+
+ CLockObject lock(m_mutex);
+
+ if (!IsOpen())
+ return rc;
+
+ if ((size_t)data.parameters.size + data.opcode_set > sizeof(buffer))
+ {
+ LIB_CEC->AddLog(CEC_LOG_WARNING, "%s: buffer too small for data", __func__);
+ return ADAPTER_MESSAGE_STATE_ERROR;
+ }
+
+ buffer[0] = (data.initiator << 4) | (data.destination & 0x0f);
+
+ if (data.opcode_set)
+ {
+ buffer[1] = data.opcode;
+ size++;
+
+ memcpy(&buffer[size], data.parameters.data, data.parameters.size);
+ size += data.parameters.size;
+ }
+
+ if (write(m_fd, (void *)buffer, size) == size)
+ {
+ rc = ADAPTER_MESSAGE_STATE_SENT_ACKED;
+ }
+ else
+ {
+ LIB_CEC->AddLog(CEC_LOG_WARNING, "%s: write failed", __func__);
+ }
+
+ return rc;
+}
+
+uint16_t CAOCECAdapterCommunication::GetFirmwareVersion(void)
+{
+ int version = 0;
+
+ CLockObject lock(m_mutex);
+
+ if (!IsOpen())
+ return version;
+
+ if (ioctl(m_fd, CEC_IOC_GET_VERSION, &version) < 0)
+ {
+ LIB_CEC->AddLog(CEC_LOG_WARNING, "%s: ioctl(CEC_IOC_GET_VERSION) failed", __func__);
+ }
+ return (uint16_t)version;
+}
+
+cec_vendor_id CAOCECAdapterCommunication::GetVendorId(void)
+{
+ int vendor_id = CEC_VENDOR_UNKNOWN;
+
+ CLockObject lock(m_mutex);
+
+ if (!IsOpen())
+ return cec_vendor_id(vendor_id);
+
+ if (ioctl(m_fd, CEC_IOC_GET_VENDOR_ID, &vendor_id) < 0)
+ {
+ LIB_CEC->AddLog(CEC_LOG_WARNING, "%s: ioctl(CEC_IOC_GET_VENDOR_ID) failed", __func__);
+ }
+ return cec_vendor_id(vendor_id);
+}
+
+uint16_t CAOCECAdapterCommunication::GetPhysicalAddress(void)
+{
+ int phys_addr = CEC_INVALID_PHYSICAL_ADDRESS;
+
+ CLockObject lock(m_mutex);
+
+ if (!IsOpen())
+ return (uint16_t)phys_addr;
+
+ if (ioctl(m_fd, CEC_IOC_GET_PHYSICAL_ADDR, &phys_addr) < 0)
+ {
+ LIB_CEC->AddLog(CEC_LOG_WARNING, "%s: ioctl(CEC_IOC_GET_PHYSICAL_ADDR) failed", __func__);
+ phys_addr = CEC_INVALID_PHYSICAL_ADDRESS;
+ }
+ return (uint16_t)phys_addr;
+}
+
+cec_logical_addresses CAOCECAdapterCommunication::GetLogicalAddresses(void)
+{
+ CLockObject lock(m_mutex);
+ return m_logicalAddresses;
+}
+
+bool CAOCECAdapterCommunication::SetLogicalAddresses(const cec_logical_addresses &addresses)
+{
+ CLockObject lock(m_mutex);
+
+ unsigned int log_addr = addresses.primary;
+ if (!IsOpen())
+ return false;
+
+ if (ioctl(m_fd, CEC_IOC_ADD_LOGICAL_ADDR, log_addr))
+ {
+ LIB_CEC->AddLog(CEC_LOG_WARNING, "%s: ioctl(CEC_IOC_ADD_LOGICAL_ADDR) failed", __func__);
+ return false;
+ }
+ m_logicalAddresses = addresses;
+ m_bLogicalAddressChanged = true;
+
+ return true;
+}
+
+void CAOCECAdapterCommunication::HandleLogicalAddressLost(cec_logical_address UNUSED(oldAddress))
+{
+ unsigned int log_addr = CECDEVICE_BROADCAST;
+
+ CLockObject lock(m_mutex);
+
+ if (!IsOpen())
+ return;
+
+ if (ioctl(m_fd, CEC_IOC_ADD_LOGICAL_ADDR, log_addr))
+ {
+ LIB_CEC->AddLog(CEC_LOG_WARNING, "%s: ioctl(CEC_IOC_ADD_LOGICAL_ADDR) failed", __func__);
+ }
+}
+
+void *CAOCECAdapterCommunication::Process(void)
+{
+ uint8_t buffer[CEC_MAX_FRAME_SIZE];
+ uint32_t size;
+ fd_set rfds;
+ cec_logical_address initiator, destination;
+ struct timeval tv;
+
+ if (!IsOpen())
+ return 0;
+
+ while (!IsStopped())
+ {
+ if (m_fd == INVALID_SOCKET_VALUE)
+ {
+ break;
+ }
+
+ FD_ZERO(&rfds);
+ FD_SET(m_fd, &rfds);
+
+ tv.tv_sec = 1;
+ tv.tv_usec = 0;
+
+ if (select(m_fd + 1, &rfds, NULL, NULL, &tv) >= 0 )
+ {
+
+ if (!FD_ISSET(m_fd, &rfds))
+ continue;
+
+ size = read(m_fd, buffer, CEC_MAX_FRAME_SIZE);
+
+ if (size > 0)
+ {
+ initiator = cec_logical_address(buffer[0] >> 4);
+ destination = cec_logical_address(buffer[0] & 0x0f);
+
+ cec_command cmd;
+
+ cec_command::Format(
+ cmd, initiator, destination,
+ ( size > 1 ) ? cec_opcode(buffer[1]) : CEC_OPCODE_NONE);
+
+ for (uint8_t i = 2; i < size; i++ )
+ cmd.parameters.PushBack(buffer[i]);
+
+ if (!IsStopped())
+ m_callback->OnCommandReceived(cmd);
+ }
+ }
+ }
+
+ return 0;
+}
+
+#endif // HAVE_AOCEC_API
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC AOCEC Code Copyright (C) 2016 Gerald Dachs
+ * based heavily on:
+ * libCEC Exynos Code Copyright (C) 2014 Valentin Manea
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+
+#if defined(HAVE_AOCEC_API)
+
+#include <p8-platform/threads/mutex.h>
+#include <p8-platform/threads/threads.h>
+#include "../AdapterCommunication.h"
+#include <map>
+
+namespace CEC
+{
+ class CAOCECAdapterCommunication : public IAdapterCommunication, public P8PLATFORM::CThread
+ {
+ public:
+ /*!
+ * @brief Create a new AOCEC HDMI CEC communication handler.
+ * @param callback The callback to use for incoming CEC commands.
+ */
+ CAOCECAdapterCommunication(IAdapterCommunicationCallback *callback);
+ virtual ~CAOCECAdapterCommunication(void);
+
+ /** @name IAdapterCommunication implementation */
+ ///{
+ bool Open(uint32_t iTimeoutMs = CEC_DEFAULT_CONNECT_TIMEOUT, bool bSkipChecks = false, bool bStartListening = true);
+ void Close(void);
+ bool IsOpen(void);
+ std::string GetError(void) const;
+ cec_adapter_message_state Write(const cec_command &data, bool &bRetry, uint8_t iLineTimeout, bool bIsReply);
+
+ bool SetLineTimeout(uint8_t UNUSED(iTimeout)) { return true; }
+ bool StartBootloader(void) { return false; }
+ bool SetLogicalAddresses(const cec_logical_addresses &addresses);
+ cec_logical_addresses GetLogicalAddresses(void);
+ bool PingAdapter(void) { return IsInitialised(); }
+ uint16_t GetFirmwareVersion(void);
+ uint32_t GetFirmwareBuildDate(void) { return 0; }
+ bool IsRunningLatestFirmware(void) { return true; }
+ bool PersistConfiguration(const libcec_configuration & UNUSED(configuration)) { return false; }
+ bool GetConfiguration(libcec_configuration & UNUSED(configuration)) { return false; }
+ std::string GetPortName(void) { return std::string("AOCEC"); }
+ uint16_t GetPhysicalAddress(void);
+ bool SetControlledMode(bool UNUSED(controlled)) { return true; }
+ cec_vendor_id GetVendorId(void);
+ bool SupportsSourceLogicalAddress(const cec_logical_address address) { return address > CECDEVICE_TV && address <= CECDEVICE_BROADCAST; }
+ cec_adapter_type GetAdapterType(void) { return ADAPTERTYPE_AOCEC; }
+ uint16_t GetAdapterVendorId(void) const { return 1; }
+ uint16_t GetAdapterProductId(void) const { return 1; }
+ void HandleLogicalAddressLost(cec_logical_address oldAddress);
+ void SetActiveSource(bool UNUSED(bSetTo), bool UNUSED(bClientUnregistered)) {}
+ ///}
+
+ /** @name P8PLATFORM::CThread implementation */
+ ///{
+ void *Process(void);
+ ///}
+
+ private:
+ bool IsInitialised(void) const { return 1; };
+
+ std::string m_strError; /**< current error message */
+
+ bool m_bLogicalAddressChanged;
+ cec_logical_addresses m_logicalAddresses;
+ P8PLATFORM::CMutex m_mutex;
+ int m_fd;
+ };
+};
+#endif
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC AOCEC Code Copyright (C) 2016 Gerald Dachs
+ * based heavily on:
+ * libCEC Exynos Code Copyright (C) 2014 Valentin Manea
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include <stdio.h>
+
+#if defined(HAVE_AOCEC_API)
+#include "AOCECAdapterDetection.h"
+#include "AOCEC.h"
+
+using namespace CEC;
+
+bool CAOCECAdapterDetection::FindAdapter(void)
+{
+ return access(CEC_AOCEC_PATH, 0) == 0;
+}
+
+#endif
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC AOCEC Code Copyright (C) 2016 Gerald Dachs
+ * based heavily on:
+ * libCEC Exynos Code Copyright (C) 2014 Valentin Manea
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+
+namespace CEC
+{
+ class CAOCECAdapterDetection
+ {
+ public:
+ static bool FindAdapter(void);
+ };
+}
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include <string>
+
+namespace CEC
+{
+ class CLibCEC;
+
+ typedef enum cec_adapter_message_state
+ {
+ ADAPTER_MESSAGE_STATE_UNKNOWN = 0, /**< the initial state */
+ ADAPTER_MESSAGE_STATE_WAITING_TO_BE_SENT, /**< waiting in the send queue of the adapter, or timed out */
+ ADAPTER_MESSAGE_STATE_SENT, /**< sent and waiting on an ACK */
+ ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED, /**< sent, but failed to ACK */
+ ADAPTER_MESSAGE_STATE_SENT_ACKED, /**< sent, and ACK received */
+ ADAPTER_MESSAGE_STATE_INCOMING, /**< received from another device */
+ ADAPTER_MESSAGE_STATE_ERROR /**< an error occurred */
+ } cec_adapter_message_state;
+
+ class IAdapterCommunicationCallback
+ {
+ public:
+ IAdapterCommunicationCallback(void) {}
+ virtual ~IAdapterCommunicationCallback(void) {}
+
+ /*!
+ * @brief Callback method for IAdapterCommunication, called when a new cec_command is received
+ * @param command The command that has been received
+ * @return True when it was handled by this listener, false otherwise.
+ */
+ virtual bool OnCommandReceived(const cec_command &command) = 0;
+
+ /*!
+ * @brief Callback method for IAdapterCommunication, called when a poll was received.
+ * @param initiator The initiator that sent the poll.
+ * @param destination The destination of the poll message.
+ */
+ virtual void HandlePoll(cec_logical_address initiator, cec_logical_address destination) = 0;
+
+ /*!
+ * @brief Callback method for IAdapterCommunication, called when a receive failed message was received.
+ * @param initiator The initiator that sent the receive failed message.
+ * @return True when this is an error, false otherwise.
+ */
+ virtual bool HandleReceiveFailed(cec_logical_address initiator) = 0;
+
+ /*!
+ * @brief Callback method for IAdapterCommunication, called when a logical address that libCEC uses was taken by another device.
+ * @param oldAddress The logical address that was taken by another device.
+ */
+ virtual void HandleLogicalAddressLost(cec_logical_address oldAddress) = 0;
+
+ /*!
+ * @brief Callback method for IAdapterCommunication, called when the physical address changed.
+ * @param iNewAddress The new physical address.
+ */
+ virtual void HandlePhysicalAddressChanged(uint16_t iNewAddress) = 0;
+
+ virtual CLibCEC *GetLib(void) const = 0;
+ };
+
+ class IAdapterCommunication
+ {
+ public:
+ /*!
+ * @param callback The callback struct. if set to NULL, the Read() method has to be used to read commands. if set, OnCommandReceived() will be called for each command that was received
+ */
+ IAdapterCommunication(IAdapterCommunicationCallback *callback) :
+ m_callback(callback) {}
+ virtual ~IAdapterCommunication(void) {}
+
+ /*!
+ * @brief Open a connection to the CEC adapter
+ * @param iTimeoutMs Connection timeout in ms
+ * @param bSkipChecks Skips all initial checks of the adapter, and starts the reader/writer threads directly after connecting.
+ * @param bStartListening Start a listener thread when true. False to just open a connection, read the device info, and close the connection.
+ * @return True when connected, false otherwise
+ */
+ virtual bool Open(uint32_t iTimeoutMs = CEC_DEFAULT_CONNECT_TIMEOUT, bool bSkipChecks = false, bool bStartListening = true) = 0;
+
+ /*!
+ * @brief Close an open connection
+ */
+ virtual void Close(void) = 0;
+
+ /*!
+ * @return True when the connection is open, false otherwise
+ */
+ virtual bool IsOpen(void) = 0;
+
+ /*!
+ * @brief Write a cec_command to the adapter
+ * @param data The command to write
+ * @param bRetry The command can be retried
+ * @param iLineTimeout The line timeout to be used
+ * @param bIsReply True when this message is a reply, false otherwise
+ * @return The last state of the transmitted command
+ */
+ virtual cec_adapter_message_state Write(const cec_command &data, bool &bRetry, uint8_t iLineTimeout, bool bIsReply) = 0;
+
+ /*!
+ * @brief Change the current line timeout on the CEC bus
+ * @param iTimeout The new timeout
+ * @return True when set, false otherwise
+ */
+ virtual bool SetLineTimeout(uint8_t iTimeout) = 0;
+
+ /*!
+ * @brief Put the device in bootloader mode (which will disrupt CEC communication when it succeeds)
+ * @return True when the bootloader command has been sent, false otherwise.
+ */
+ virtual bool StartBootloader(void) = 0;
+
+ virtual bool SetLogicalAddresses(const cec_logical_addresses &addresses) = 0;
+ virtual cec_logical_addresses GetLogicalAddresses(void) = 0;
+
+ /*!
+ * @brief Check whether the CEC adapter responds
+ * @return True when the ping was sent and acked, false otherwise.
+ */
+ virtual bool PingAdapter(void) = 0;
+
+ /*!
+ * @return The firmware version of this CEC adapter, or 0 if it's unknown.
+ */
+ virtual uint16_t GetFirmwareVersion(void) = 0;
+
+ /*!
+ * @return The build date in seconds since epoch, or 0 when no (valid) reply was received.
+ */
+ virtual uint32_t GetFirmwareBuildDate(void) = 0;
+
+ /*!
+ * @return True when this adapter is using the latest firmware build, or when the latest firmware build for this adapter type is unknown. False otherwise.
+ */
+ virtual bool IsRunningLatestFirmware(void) = 0;
+
+ /*!
+ * @return True when the control mode has been set, false otherwise.
+ */
+ virtual bool SetControlledMode(bool controlled) = 0;
+
+ /*!
+ * @brief Persist the given configuration in adapter (if supported)
+ * @brief The configuration to store.
+ * @return True when the configuration was persisted, false otherwise.
+ */
+ virtual bool PersistConfiguration(const libcec_configuration &configuration) = 0;
+
+ /*!
+ * @brief Get the persisted configuration from the adapter (if supported)
+ * @param configuration The updated configuration.
+ * @return True when the configuration was updated, false otherwise.
+ */
+ virtual bool GetConfiguration(libcec_configuration &configuration) = 0;
+
+ /*!
+ * @return The name of the port
+ */
+ virtual std::string GetPortName(void) = 0;
+
+ /*!
+ * @return The physical address, if the adapter supports this. 0 otherwise.
+ */
+ virtual uint16_t GetPhysicalAddress(void) = 0;
+
+ /*!
+ * @return The vendor id for this device
+ */
+ virtual cec_vendor_id GetVendorId(void) = 0;
+
+ /*!
+ * @brief Checks whether a logical address is supported by the adapter.
+ * @param address The address to check.
+ * @return True when supported, false otherwise.
+ */
+ virtual bool SupportsSourceLogicalAddress(const cec_logical_address address) = 0;
+
+ /*!
+ * @return The type of adapter that this instance is connected to.
+ */
+ virtual cec_adapter_type GetAdapterType(void) = 0;
+
+ /*!
+ * @return The (virtual) USB vendor id
+ */
+ virtual uint16_t GetAdapterVendorId(void) const = 0;
+
+ /*!
+ * @return The (virtual) USB product id
+ */
+ virtual uint16_t GetAdapterProductId(void) const = 0;
+
+ /*!
+ * @brief Marks the adapter as active or inactive source
+ * @param bSetTo True to mark as active source, false to mark as inactive source
+ * @param bClientUnregistered True when the client was unregistered, false when the device was explicitly marked as (in)active source
+ */
+ virtual void SetActiveSource(bool bSetTo, bool bClientUnregistered) = 0;
+
+ IAdapterCommunicationCallback *m_callback;
+ };
+};
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include "AdapterFactory.h"
+
+#include <stdio.h>
+#include "LibCEC.h"
+#include "CECProcessor.h"
+
+#if defined(HAVE_P8_USB)
+#include "Pulse-Eight/USBCECAdapterDetection.h"
+#include "Pulse-Eight/USBCECAdapterCommunication.h"
+#endif
+
+#if defined(HAVE_RPI_API)
+#include "RPi/RPiCECAdapterDetection.h"
+#include "RPi/RPiCECAdapterCommunication.h"
+#endif
+
+#if defined(HAVE_TDA995X_API)
+#include "TDA995x/TDA995xCECAdapterDetection.h"
+#include "TDA995x/TDA995xCECAdapterCommunication.h"
+#endif
+
+#if defined(HAVE_EXYNOS_API)
+#include "Exynos/ExynosCECAdapterDetection.h"
+#include "Exynos/ExynosCECAdapterCommunication.h"
+#endif
+
+#if defined(HAVE_AOCEC_API)
+#include "AOCEC/AOCECAdapterDetection.h"
+#include "AOCEC/AOCECAdapterCommunication.h"
+#endif
+
+using namespace CEC;
+
+int8_t CAdapterFactory::FindAdapters(cec_adapter *deviceList, uint8_t iBufSize, const char *strDevicePath /* = NULL */)
+{
+ cec_adapter_descriptor devices[50];
+ int8_t iReturn = DetectAdapters(devices, iBufSize, strDevicePath);
+ for (int8_t iPtr = 0; iPtr < iReturn && iPtr < iBufSize; iPtr++)
+ {
+ strncpy(deviceList[iPtr].comm, devices[iPtr].strComName, sizeof(deviceList[iPtr].comm));
+ strncpy(deviceList[iPtr].path, devices[iPtr].strComPath, sizeof(deviceList[iPtr].path));
+ }
+ return iReturn;
+}
+
+int8_t CAdapterFactory::DetectAdapters(cec_adapter_descriptor *deviceList, uint8_t iBufSize, const char *strDevicePath /* = NULL */)
+{
+ int8_t iAdaptersFound(0);
+
+#if defined(HAVE_P8_USB)
+ if (!CUSBCECAdapterDetection::CanAutodetect())
+ {
+ if (m_lib)
+ m_lib->AddLog(CEC_LOG_WARNING, "libCEC has not been compiled with detection code for the Pulse-Eight USB-CEC Adapter, so the path to the COM port has to be provided to libCEC if this adapter is being used");
+ }
+ else
+ iAdaptersFound += CUSBCECAdapterDetection::FindAdapters(deviceList, iBufSize, strDevicePath);
+#else
+ m_lib->AddLog(CEC_LOG_WARNING, "libCEC has not been compiled with support for the Pulse-Eight USB-CEC Adapter");
+#endif
+
+#if defined(HAVE_RPI_API)
+ if (iAdaptersFound < iBufSize && CRPiCECAdapterDetection::FindAdapter() &&
+ (!strDevicePath || !strcmp(strDevicePath, CEC_RPI_VIRTUAL_COM)))
+ {
+ snprintf(deviceList[iAdaptersFound].strComPath, sizeof(deviceList[iAdaptersFound].strComPath), CEC_RPI_VIRTUAL_PATH);
+ snprintf(deviceList[iAdaptersFound].strComName, sizeof(deviceList[iAdaptersFound].strComName), CEC_RPI_VIRTUAL_COM);
+ deviceList[iAdaptersFound].iVendorId = RPI_ADAPTER_VID;
+ deviceList[iAdaptersFound].iProductId = RPI_ADAPTER_PID;
+ deviceList[iAdaptersFound].adapterType = ADAPTERTYPE_RPI;
+ iAdaptersFound++;
+ }
+#endif
+
+#if defined(HAVE_TDA995X_API)
+ if (iAdaptersFound < iBufSize && CTDA995xCECAdapterDetection::FindAdapter() &&
+ (!strDevicePath || !strcmp(strDevicePath, CEC_TDA995x_VIRTUAL_COM)))
+ {
+ snprintf(deviceList[iAdaptersFound].strComPath, sizeof(deviceList[iAdaptersFound].strComPath), CEC_TDA995x_PATH);
+ snprintf(deviceList[iAdaptersFound].strComName, sizeof(deviceList[iAdaptersFound].strComName), CEC_TDA995x_VIRTUAL_COM);
+ deviceList[iAdaptersFound].iVendorId = TDA995X_ADAPTER_VID;
+ deviceList[iAdaptersFound].iProductId = TDA995X_ADAPTER_PID;
+ deviceList[iAdaptersFound].adapterType = ADAPTERTYPE_TDA995x;
+ iAdaptersFound++;
+ }
+#endif
+
+#if defined(HAVE_EXYNOS_API)
+ if (iAdaptersFound < iBufSize && CExynosCECAdapterDetection::FindAdapter())
+ {
+ snprintf(deviceList[iAdaptersFound].strComPath, sizeof(deviceList[iAdaptersFound].strComPath), CEC_EXYNOS_PATH);
+ snprintf(deviceList[iAdaptersFound].strComName, sizeof(deviceList[iAdaptersFound].strComName), CEC_EXYNOS_VIRTUAL_COM);
+ deviceList[iAdaptersFound].iVendorId = 0;
+ deviceList[iAdaptersFound].iProductId = 0;
+ deviceList[iAdaptersFound].adapterType = ADAPTERTYPE_EXYNOS;
+ iAdaptersFound++;
+ }
+#endif
+
+#if defined(HAVE_AOCEC_API)
+ if (iAdaptersFound < iBufSize && CAOCECAdapterDetection::FindAdapter())
+ {
+ snprintf(deviceList[iAdaptersFound].strComPath, sizeof(deviceList[iAdaptersFound].strComPath), CEC_AOCEC_PATH);
+ snprintf(deviceList[iAdaptersFound].strComName, sizeof(deviceList[iAdaptersFound].strComName), CEC_AOCEC_VIRTUAL_COM);
+ deviceList[iAdaptersFound].iVendorId = 0;
+ deviceList[iAdaptersFound].iProductId = 0;
+ deviceList[iAdaptersFound].adapterType = ADAPTERTYPE_AOCEC;
+ iAdaptersFound++;
+ }
+#endif
+
+
+#if !defined(HAVE_RPI_API) && !defined(HAVE_P8_USB) && !defined(HAVE_TDA995X_API) && !defined(HAVE_AOCEC_API)
+#error "libCEC doesn't have support for any type of adapter. please check your build system or configuration"
+#endif
+
+ return iAdaptersFound;
+}
+
+IAdapterCommunication *CAdapterFactory::GetInstance(const char *strPort, uint16_t iBaudRate)
+{
+#if defined(HAVE_TDA995X_API)
+ if (!strcmp(strPort, CEC_TDA995x_VIRTUAL_COM))
+ return new CTDA995xCECAdapterCommunication(m_lib->m_cec);
+#endif
+
+#if defined(HAVE_EXYNOS_API)
+ if (!strcmp(strPort, CEC_EXYNOS_VIRTUAL_COM))
+ return new CExynosCECAdapterCommunication(m_lib->m_cec);
+#endif
+
+#if defined(HAVE_AOCEC_API)
+ if (!strcmp(strPort, CEC_AOCEC_VIRTUAL_COM))
+ return new CAOCECAdapterCommunication(m_lib->m_cec);
+#endif
+
+#if defined(HAVE_RPI_API)
+ if (!strcmp(strPort, CEC_RPI_VIRTUAL_COM))
+ return new CRPiCECAdapterCommunication(m_lib->m_cec);
+#endif
+
+#if defined(HAVE_P8_USB)
+ return new CUSBCECAdapterCommunication(m_lib->m_cec, strPort, iBaudRate);
+#endif
+
+#if !defined(HAVE_RPI_API) && !defined(HAVE_P8_USB) && !defined(HAVE_TDA995X_API) && !defined(HAVE_EXYNOS_API) && !defined(HAVE_AOCEC_API)
+ return NULL;
+#endif
+}
+
+void CAdapterFactory::InitVideoStandalone(void)
+{
+#if defined(HAVE_RPI_API)
+ CRPiCECAdapterCommunication::InitHost();
+#endif
+}
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include <map>
+#include <string>
+
+namespace CEC
+{
+ class CLibCEC;
+ class IAdapterCommunication;
+
+ class CAdapterFactory
+ {
+ public:
+ CAdapterFactory(CLibCEC *lib) :
+ m_lib(lib) {}
+ virtual ~CAdapterFactory(void) {};
+
+ int8_t FindAdapters(cec_adapter *deviceList, uint8_t iBufSize, const char *strDevicePath = NULL);
+ int8_t DetectAdapters(cec_adapter_descriptor *deviceList, uint8_t iBufSize, const char *strDevicePath = NULL);
+ IAdapterCommunication *GetInstance(const char *strPort, uint16_t iBaudRate = CEC_SERIAL_DEFAULT_BAUDRATE);
+
+ static void InitVideoStandalone(void);
+
+ private:
+ CLibCEC *m_lib;
+ };
+}
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC Exynos Code is Copyright (C) 2014 Valentin Manea
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+
+#define CEC_DEFAULT_PADDR 0x1000
+#define CEC_PADDR_NAME "/sys/module/s5p_hdmi/parameters/source_phy_addr"
+#define CEC_IOC_SETLADDR _IOW('c', 0, unsigned int)
+#define CEC_MAX_FRAME_SIZE 16
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC Exynos Code is Copyright (C) 2014 Valentin Manea
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+
+#if defined(HAVE_EXYNOS_API)
+#include "ExynosCEC.h"
+#include "ExynosCECAdapterCommunication.h"
+
+#include "CECTypeUtils.h"
+#include "LibCEC.h"
+#include <p8-platform/util/buffer.h>
+
+using namespace CEC;
+using namespace P8PLATFORM;
+
+#define LIB_CEC m_callback->GetLib()
+
+
+CExynosCECAdapterCommunication::CExynosCECAdapterCommunication(IAdapterCommunicationCallback *callback) :
+ IAdapterCommunication(callback),
+ m_bLogicalAddressChanged(false)
+{
+ CLockObject lock(m_mutex);
+
+ m_logicalAddresses.Clear();
+ m_fd = INVALID_SOCKET_VALUE;
+}
+
+
+CExynosCECAdapterCommunication::~CExynosCECAdapterCommunication(void)
+{
+ Close();
+}
+
+
+bool CExynosCECAdapterCommunication::IsOpen(void)
+{
+ return IsInitialised() && m_fd != INVALID_SOCKET_VALUE;
+}
+
+
+bool CExynosCECAdapterCommunication::Open(uint32_t UNUSED(iTimeoutMs), bool UNUSED(bSkipChecks), bool bStartListening)
+{
+ if (m_fd != INVALID_SOCKET_VALUE)
+ close(m_fd);
+
+ if ((m_fd = open(CEC_EXYNOS_PATH, O_RDWR)) > 0)
+ {
+ if (!bStartListening || CreateThread()) {
+ return true;
+ }
+ close(m_fd);
+ }
+ return false;
+}
+
+
+void CExynosCECAdapterCommunication::Close(void)
+{
+ StopThread(0);
+
+ close(m_fd);
+ m_fd = INVALID_SOCKET_VALUE;
+}
+
+
+std::string CExynosCECAdapterCommunication::GetError(void) const
+{
+ std::string strError(m_strError);
+ return strError;
+}
+
+
+cec_adapter_message_state CExynosCECAdapterCommunication::Write(
+ const cec_command &data, bool &UNUSED(bRetry), uint8_t UNUSED(iLineTimeout), bool UNUSED(bIsReply))
+{
+ uint8_t buffer[CEC_MAX_FRAME_SIZE];
+ int32_t size = 1;
+ cec_adapter_message_state rc = ADAPTER_MESSAGE_STATE_ERROR;
+
+ if (!IsOpen())
+ return rc;
+
+ if ((size_t)data.parameters.size + data.opcode_set > sizeof(buffer))
+ {
+ LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: data size too large !", __func__);
+ return ADAPTER_MESSAGE_STATE_ERROR;
+ }
+
+ buffer[0] = (data.initiator << 4) | (data.destination & 0x0f);
+
+ if (data.opcode_set)
+ {
+ buffer[1] = data.opcode;
+ size++;
+
+ memcpy(&buffer[size], data.parameters.data, data.parameters.size);
+ size += data.parameters.size;
+ }
+
+ if (write(m_fd, (void *)buffer, size) == size)
+ {
+ rc = ADAPTER_MESSAGE_STATE_SENT_ACKED;
+ }
+ else
+ {
+ LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: write failed !", __func__);
+ }
+
+ return rc;
+}
+
+
+uint16_t CExynosCECAdapterCommunication::GetFirmwareVersion(void)
+{
+ return 0;
+}
+
+
+cec_vendor_id CExynosCECAdapterCommunication::GetVendorId(void)
+{
+ return cec_vendor_id(CEC_VENDOR_SAMSUNG);
+}
+
+
+uint16_t CExynosCECAdapterCommunication::GetPhysicalAddress(void)
+{
+ uint16_t phys_addr = CEC_DEFAULT_PADDR;
+
+ FILE *f = fopen(CEC_PADDR_NAME, "r");
+ if(f) {
+ if(fscanf(f, "%hu", &phys_addr) != 1)
+ phys_addr = CEC_DEFAULT_PADDR;
+
+ fclose(f);
+ }
+ return phys_addr;
+}
+
+
+cec_logical_addresses CExynosCECAdapterCommunication::GetLogicalAddresses(void)
+{
+ return m_logicalAddresses;
+}
+
+
+bool CExynosCECAdapterCommunication::SetLogicalAddresses(const cec_logical_addresses &addresses)
+{
+ unsigned int log_addr = addresses.primary;
+ CLockObject lock(m_mutex);
+
+ if (!IsOpen())
+ return false;
+
+ if (ioctl(m_fd, CEC_IOC_SETLADDR, &log_addr))
+ {
+ LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: IOCTL SetLogicalAddr failed !", __func__);
+ return false;
+ }
+ m_logicalAddresses = addresses;
+ m_bLogicalAddressChanged = true;
+
+ return true;
+}
+
+
+void CExynosCECAdapterCommunication::HandleLogicalAddressLost(cec_logical_address UNUSED(oldAddress))
+{
+ unsigned int log_addr = CECDEVICE_BROADCAST;
+ if (ioctl(m_fd, CEC_IOC_SETLADDR, &log_addr))
+ {
+ LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: IOCTL SetLogicalAddr failed !", __func__);
+ }
+}
+
+
+void *CExynosCECAdapterCommunication::Process(void)
+{
+ uint8_t buffer[CEC_MAX_FRAME_SIZE];
+ uint32_t size;
+ fd_set rfds;
+ cec_logical_address initiator, destination;
+
+ if (!IsOpen())
+ return 0;
+
+ FD_ZERO(&rfds);
+ FD_SET(m_fd, &rfds);
+
+ while (!IsStopped())
+ {
+ if (select(m_fd + 1, &rfds, NULL, NULL, NULL) >= 0 )
+ {
+ size = read(m_fd, buffer, CEC_MAX_FRAME_SIZE);
+
+ if (size > 0)
+ {
+ initiator = cec_logical_address(buffer[0] >> 4);
+ destination = cec_logical_address(buffer[0] & 0x0f);
+
+ cec_command cmd;
+
+ cec_command::Format(
+ cmd, initiator, destination,
+ ( size > 1 ) ? cec_opcode(buffer[1]) : CEC_OPCODE_NONE);
+
+ for( uint8_t i = 2; i < size; i++ )
+ cmd.parameters.PushBack(buffer[i]);
+
+ if (!IsStopped())
+ m_callback->OnCommandReceived(cmd);
+ }
+ }
+
+ }
+
+ return 0;
+}
+
+#endif // HAVE_EXYNOS_API
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC Exynos Code is Copyright (C) 2014 Valentin Manea
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+
+#if defined(HAVE_EXYNOS_API)
+
+#include <p8-platform/threads/mutex.h>
+#include <p8-platform/threads/threads.h>
+#include "../AdapterCommunication.h"
+#include <map>
+
+namespace CEC
+{
+ class CExynosCECAdapterCommunication : public IAdapterCommunication, public P8PLATFORM::CThread
+ {
+ public:
+ /*!
+ * @brief Create a new Exynos HDMI CEC communication handler.
+ * @param callback The callback to use for incoming CEC commands.
+ */
+ CExynosCECAdapterCommunication(IAdapterCommunicationCallback *callback);
+ virtual ~CExynosCECAdapterCommunication(void);
+
+ /** @name IAdapterCommunication implementation */
+ ///{
+ bool Open(uint32_t iTimeoutMs = CEC_DEFAULT_CONNECT_TIMEOUT, bool bSkipChecks = false, bool bStartListening = true);
+ void Close(void);
+ bool IsOpen(void);
+ std::string GetError(void) const;
+ cec_adapter_message_state Write(const cec_command &data, bool &bRetry, uint8_t iLineTimeout, bool bIsReply);
+
+ bool SetLineTimeout(uint8_t UNUSED(iTimeout)) { return true; }
+ bool StartBootloader(void) { return false; }
+ bool SetLogicalAddresses(const cec_logical_addresses &addresses);
+ cec_logical_addresses GetLogicalAddresses(void);
+ bool PingAdapter(void) { return IsInitialised(); }
+ uint16_t GetFirmwareVersion(void);
+ uint32_t GetFirmwareBuildDate(void) { return 0; }
+ bool IsRunningLatestFirmware(void) { return true; }
+ bool PersistConfiguration(const libcec_configuration & UNUSED(configuration)) { return false; }
+ bool GetConfiguration(libcec_configuration & UNUSED(configuration)) { return false; }
+ std::string GetPortName(void) { return std::string("EXYNOS"); }
+ uint16_t GetPhysicalAddress(void);
+ bool SetControlledMode(bool UNUSED(controlled)) { return true; }
+ cec_vendor_id GetVendorId(void);
+ bool SupportsSourceLogicalAddress(const cec_logical_address address) { return address > CECDEVICE_TV && address <= CECDEVICE_BROADCAST; }
+ cec_adapter_type GetAdapterType(void) { return ADAPTERTYPE_EXYNOS; }
+ uint16_t GetAdapterVendorId(void) const { return 1; }
+ uint16_t GetAdapterProductId(void) const { return 1; }
+ void HandleLogicalAddressLost(cec_logical_address oldAddress);
+ void SetActiveSource(bool UNUSED(bSetTo), bool UNUSED(bClientUnregistered)) {}
+ ///}
+
+ /** @name P8PLATFORM::CThread implementation */
+ ///{
+ void *Process(void);
+ ///}
+
+ private:
+ bool IsInitialised(void) const { return 1; };
+
+ std::string m_strError; /**< current error message */
+
+ bool m_bLogicalAddressChanged;
+ cec_logical_addresses m_logicalAddresses;
+
+ P8PLATFORM::CMutex m_mutex;
+ int m_fd;
+ };
+};
+#endif
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC Exynos Code is Copyright (C) 2014 Valentin Manea
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include <stdio.h>
+
+#if defined(HAVE_EXYNOS_API)
+#include "ExynosCECAdapterDetection.h"
+#include "ExynosCEC.h"
+
+using namespace CEC;
+
+bool CExynosCECAdapterDetection::FindAdapter(void)
+{
+ return access(CEC_EXYNOS_PATH, 0) == 0;
+}
+
+#endif
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC Exynos Code is Copyright (C) 2014 Valentin Manea
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+
+namespace CEC
+{
+ class CExynosCECAdapterDetection
+ {
+ public:
+ static bool FindAdapter(void);
+ };
+}
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include "USBCECAdapterCommands.h"
+
+#include "USBCECAdapterMessage.h"
+#include "USBCECAdapterCommunication.h"
+#include "LibCEC.h"
+#include "CECProcessor.h"
+#include "CECTypeUtils.h"
+#include <p8-platform/util/util.h>
+#include <stdio.h>
+
+using namespace CEC;
+using namespace P8PLATFORM;
+
+#define LIB_CEC m_comm->m_callback->GetLib()
+#define ToString(p) CCECTypeUtils::ToString(p)
+
+CUSBCECAdapterCommands::CUSBCECAdapterCommands(CUSBCECAdapterCommunication *comm) :
+ m_comm(comm),
+ m_bSettingsRetrieved(false),
+ m_bSettingAutoEnabled(false),
+ m_settingCecVersion(CEC_VERSION_UNKNOWN),
+ m_iSettingLAMask(0),
+ m_bNeedsWrite(false),
+ m_iBuildDate(CEC_FW_BUILD_UNKNOWN),
+ m_bControlledMode(false),
+ m_adapterType(P8_ADAPTERTYPE_UNKNOWN)
+{
+ m_persistedConfiguration.Clear();
+}
+
+cec_datapacket CUSBCECAdapterCommands::RequestSetting(cec_adapter_messagecode msgCode)
+{
+ cec_datapacket retVal;
+ retVal.Clear();
+
+ CCECAdapterMessage params;
+ CCECAdapterMessage *message = m_comm->SendCommand(msgCode, params);
+ if (message && message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED)
+ {
+ retVal = message->response;
+ retVal.Shift(2); // shift out start and msgcode
+ retVal.size -= 1; // remove end
+ }
+
+ SAFE_DELETE(message);
+ return retVal;
+}
+
+uint16_t CUSBCECAdapterCommands::RequestFirmwareVersion(void)
+{
+ m_persistedConfiguration.iFirmwareVersion = CEC_FW_VERSION_UNKNOWN;
+ unsigned int iFwVersionTry(0);
+
+ while (m_persistedConfiguration.iFirmwareVersion == CEC_FW_VERSION_UNKNOWN && iFwVersionTry++ < 3)
+ {
+#ifdef CEC_DEBUGGING
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "requesting the firmware version");
+#endif
+ cec_datapacket response = RequestSetting(MSGCODE_FIRMWARE_VERSION);
+ if (response.size == 2)
+ m_persistedConfiguration.iFirmwareVersion = (response[0] << 8 | response[1]);
+ else
+ {
+ LIB_CEC->AddLog(CEC_LOG_WARNING, "the adapter did not respond with a correct firmware version (try %d, size = %d)", iFwVersionTry, response.size);
+ CEvent::Sleep(500);
+ }
+ }
+
+ if (m_persistedConfiguration.iFirmwareVersion == CEC_FW_VERSION_UNKNOWN)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "defaulting to firmware version 1");
+ m_persistedConfiguration.iFirmwareVersion = 1;
+ }
+
+ // firmware versions < 2 don't have an autonomous mode
+ if (m_persistedConfiguration.iFirmwareVersion < 2)
+ m_bControlledMode = true;
+
+ return m_persistedConfiguration.iFirmwareVersion;
+}
+
+bool CUSBCECAdapterCommands::RequestSettingAutoEnabled(void)
+{
+#ifdef CEC_DEBUGGING
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "requesting autonomous mode setting");
+#endif
+
+ cec_datapacket response = RequestSetting(MSGCODE_GET_AUTO_ENABLED);
+ if (response.size == 1)
+ {
+ m_bSettingAutoEnabled = response[0] == 1;
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "using persisted autonomous mode setting: '%s'", m_bSettingAutoEnabled ? "enabled" : "disabled");
+ return true;
+ }
+ return false;
+}
+
+bool CUSBCECAdapterCommands::RequestSettingCECVersion(void)
+{
+#ifdef CEC_DEBUGGING
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "requesting CEC version setting");
+#endif
+
+ cec_datapacket response = RequestSetting(MSGCODE_GET_HDMI_VERSION);
+ if (response.size == 1)
+ {
+ m_settingCecVersion = (cec_version)response[0];
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "using persisted CEC version setting: '%s'", ToString(m_settingCecVersion));
+ return true;
+ }
+ return false;
+}
+
+p8_cec_adapter_type CUSBCECAdapterCommands::RequestAdapterType(void)
+{
+ if (m_adapterType == P8_ADAPTERTYPE_UNKNOWN)
+ {
+#ifdef CEC_DEBUGGING
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "requesting adapter type");
+#endif
+
+ cec_datapacket response = RequestSetting(MSGCODE_GET_ADAPTER_TYPE);
+ if (response.size == 1)
+ m_adapterType = (p8_cec_adapter_type)response[0];
+ }
+ return m_adapterType;
+}
+
+uint32_t CUSBCECAdapterCommands::RequestBuildDate(void)
+{
+ if (m_iBuildDate == CEC_FW_BUILD_UNKNOWN)
+ {
+#ifdef CEC_DEBUGGING
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "requesting firmware build date");
+#endif
+
+ cec_datapacket response = RequestSetting(MSGCODE_GET_BUILDDATE);
+ if (response.size == 4)
+ m_iBuildDate = (uint32_t)response[0] << 24 | (uint32_t)response[1] << 16 | (uint32_t)response[2] << 8 | (uint32_t)response[3];
+ }
+ return m_iBuildDate;
+}
+
+bool CUSBCECAdapterCommands::RequestSettingDefaultLogicalAddress(void)
+{
+#ifdef CEC_DEBUGGING
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "requesting default logical address setting");
+#endif
+
+ cec_datapacket response = RequestSetting(MSGCODE_GET_DEFAULT_LOGICAL_ADDRESS);
+ if (response.size == 1)
+ {
+ m_persistedConfiguration.logicalAddresses.primary = (cec_logical_address)response[0];
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "using persisted logical address setting: '%s'", ToString(m_persistedConfiguration.logicalAddresses.primary));
+ return true;
+ }
+ return false;
+}
+
+bool CUSBCECAdapterCommands::RequestSettingDeviceType(void)
+{
+#ifdef CEC_DEBUGGING
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "requesting device type setting");
+#endif
+ m_persistedConfiguration.deviceTypes.Clear();
+
+ cec_datapacket response = RequestSetting(MSGCODE_GET_DEVICE_TYPE);
+ if (response.size == 1)
+ {
+ m_persistedConfiguration.deviceTypes.Add((cec_device_type)response[0]);
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "using persisted device type setting: '%s'", ToString((cec_device_type)response[0]));
+ return true;
+ }
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "no persisted device type setting");
+ return false;
+}
+
+bool CUSBCECAdapterCommands::RequestSettingLogicalAddressMask(void)
+{
+#ifdef CEC_DEBUGGING
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "requesting logical address mask setting");
+#endif
+
+ cec_datapacket response = RequestSetting(MSGCODE_GET_LOGICAL_ADDRESS_MASK);
+ if (response.size == 2)
+ {
+ m_iSettingLAMask = ((uint16_t)response[0] << 8) | ((uint16_t)response[1]);
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "using persisted logical address mask setting: '%x'", m_iSettingLAMask);
+ return true;
+ }
+ return false;
+}
+
+bool CUSBCECAdapterCommands::RequestSettingOSDName(void)
+{
+#ifdef CEC_DEBUGGING
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "requesting OSD name setting");
+#endif
+
+ memset(m_persistedConfiguration.strDeviceName, 0, 13);
+ cec_datapacket response = RequestSetting(MSGCODE_GET_OSD_NAME);
+ if (response.size == 0)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "no persisted device name setting");
+ return false;
+ }
+
+ char buf[14];
+ for (uint8_t iPtr = 0; iPtr < response.size && iPtr < 13; iPtr++)
+ buf[iPtr] = (char)response[iPtr];
+ buf[response.size] = 0;
+
+ snprintf(m_persistedConfiguration.strDeviceName, 13, "%s", buf);
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "using persisted device name setting: '%s'", buf);
+ return true;
+}
+
+bool CUSBCECAdapterCommands::RequestSettingPhysicalAddress(void)
+{
+#ifdef CEC_DEBUGGING
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "requesting physical address setting");
+#endif
+
+ cec_datapacket response = RequestSetting(MSGCODE_GET_PHYSICAL_ADDRESS);
+ if (response.size == 2)
+ {
+ m_persistedConfiguration.iPhysicalAddress = ((uint16_t)response[0] << 8) | ((uint16_t)response[1]);
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "using persisted physical address setting: '%4x'", m_persistedConfiguration.iPhysicalAddress);
+ return true;
+ }
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "no persisted physical address setting");
+ return false;
+}
+
+bool CUSBCECAdapterCommands::SetSettingAutoEnabled(bool enabled)
+{
+ bool bReturn(false);
+
+ /* check whether this value was changed */
+ {
+ CLockObject lock(m_mutex);
+ if (m_bSettingAutoEnabled == enabled)
+ return bReturn;
+ m_bNeedsWrite = true;
+ }
+
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "turning autonomous mode %s", enabled ? "on" : "off");
+
+ CCECAdapterMessage params;
+ params.PushEscaped(enabled ? 1 : 0);
+ CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_SET_AUTO_ENABLED, params);
+ bReturn = message && message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED;
+ SAFE_DELETE(message);
+
+ if (bReturn)
+ {
+ CLockObject lock(m_mutex);
+ m_bSettingAutoEnabled = enabled;
+ }
+
+ return bReturn;
+}
+
+bool CUSBCECAdapterCommands::SetSettingDeviceType(cec_device_type type)
+{
+ bool bReturn(false);
+
+ /* check whether this value was changed */
+ {
+ CLockObject lock(m_mutex);
+ if (m_persistedConfiguration.deviceTypes.types[0] == type)
+ return bReturn;
+ m_bNeedsWrite = true;
+ }
+
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "setting the device type to %X (previous: %X)", (uint8_t)type, (uint8_t)m_persistedConfiguration.deviceTypes.types[0]);
+
+ CCECAdapterMessage params;
+ params.PushEscaped((uint8_t)type);
+ CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_SET_DEVICE_TYPE, params);
+ bReturn = message && message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED;
+ SAFE_DELETE(message);
+
+ if (bReturn)
+ {
+ CLockObject lock(m_mutex);
+ m_persistedConfiguration.deviceTypes.types[0] = type;
+ }
+
+ return bReturn;
+}
+
+bool CUSBCECAdapterCommands::SetSettingDefaultLogicalAddress(cec_logical_address address)
+{
+ bool bReturn(false);
+
+ /* check whether this value was changed */
+ {
+ CLockObject lock(m_mutex);
+ if (m_persistedConfiguration.logicalAddresses.primary == address)
+ return bReturn;
+ m_bNeedsWrite = true;
+ }
+
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "setting the default logical address to %X (previous: %X)", (uint8_t)address, (uint8_t)m_persistedConfiguration.logicalAddresses.primary);
+
+ CCECAdapterMessage params;
+ params.PushEscaped((uint8_t)address);
+ CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_SET_DEFAULT_LOGICAL_ADDRESS, params);
+ bReturn = message && message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED;
+ SAFE_DELETE(message);
+
+ if (bReturn)
+ {
+ CLockObject lock(m_mutex);
+ m_persistedConfiguration.logicalAddresses.primary = address;
+ }
+
+ return bReturn;
+}
+
+bool CUSBCECAdapterCommands::SetSettingLogicalAddressMask(uint16_t iMask)
+{
+ bool bReturn(false);
+
+ /* check whether this value was changed */
+ {
+ CLockObject lock(m_mutex);
+ if (m_iSettingLAMask == iMask)
+ return bReturn;
+ m_bNeedsWrite = true;
+ }
+
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "setting the logical address mask to %2X (previous: %2X)", iMask, m_iSettingLAMask);
+
+ CCECAdapterMessage params;
+ params.PushEscaped(iMask >> 8);
+ params.PushEscaped((uint8_t)iMask);
+ CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_SET_LOGICAL_ADDRESS_MASK, params);
+ bReturn = message && message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED;
+ SAFE_DELETE(message);
+
+ if (bReturn)
+ {
+ CLockObject lock(m_mutex);
+ m_iSettingLAMask = iMask;
+ }
+
+ return bReturn;
+}
+
+bool CUSBCECAdapterCommands::SetSettingPhysicalAddress(uint16_t iPhysicalAddress)
+{
+ bool bReturn(false);
+
+ /* check whether this value was changed */
+ {
+ CLockObject lock(m_mutex);
+ if (m_persistedConfiguration.iPhysicalAddress == iPhysicalAddress)
+ return bReturn;
+ m_bNeedsWrite = true;
+ }
+
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "setting the physical address to %04X (previous: %04X)", iPhysicalAddress, m_persistedConfiguration.iPhysicalAddress);
+
+ CCECAdapterMessage params;
+ params.PushEscaped(iPhysicalAddress >> 8);
+ params.PushEscaped((uint8_t)iPhysicalAddress);
+ CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_SET_PHYSICAL_ADDRESS, params);
+ bReturn = message && message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED;
+ SAFE_DELETE(message);
+
+ if (bReturn)
+ {
+ CLockObject lock(m_mutex);
+ m_persistedConfiguration.iPhysicalAddress = iPhysicalAddress;
+ }
+
+ return bReturn;
+}
+
+bool CUSBCECAdapterCommands::SetSettingCECVersion(cec_version version)
+{
+ bool bReturn(false);
+
+ /* check whether this value was changed */
+ {
+ CLockObject lock(m_mutex);
+ if (m_settingCecVersion == version)
+ return bReturn;
+ m_bNeedsWrite = true;
+ }
+
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "setting the CEC version to %s (previous: %s)", ToString(version), ToString(m_settingCecVersion));
+
+ CCECAdapterMessage params;
+ params.PushEscaped((uint8_t)version);
+ CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_SET_HDMI_VERSION, params);
+ bReturn = message && message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED;
+ SAFE_DELETE(message);
+
+ if (bReturn)
+ {
+ CLockObject lock(m_mutex);
+ m_settingCecVersion = version;
+ }
+
+ return bReturn;
+}
+
+bool CUSBCECAdapterCommands::SetSettingOSDName(const char *strOSDName)
+{
+ bool bReturn(false);
+
+ /* check whether this value was changed */
+ if (!strcmp(m_persistedConfiguration.strDeviceName, strOSDName))
+ return bReturn;
+
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "setting the OSD name to %s (previous: %s)", strOSDName, m_persistedConfiguration.strDeviceName);
+
+ CCECAdapterMessage params;
+ for (size_t iPtr = 0; iPtr < strlen(strOSDName); iPtr++)
+ params.PushEscaped(strOSDName[iPtr]);
+ CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_SET_OSD_NAME, params);
+ bReturn = message && message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED;
+ SAFE_DELETE(message);
+
+ if (bReturn)
+ snprintf(m_persistedConfiguration.strDeviceName, 13, "%s", strOSDName);
+
+ return bReturn;
+}
+
+bool CUSBCECAdapterCommands::WriteEEPROM(void)
+{
+ {
+ CLockObject lock(m_mutex);
+ if (!m_bNeedsWrite)
+ return true;
+ }
+
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "writing settings in the EEPROM");
+
+ CCECAdapterMessage params;
+ CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_WRITE_EEPROM, params);
+ bool bReturn = message && message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED;
+ SAFE_DELETE(message);
+
+ if (bReturn)
+ {
+ CLockObject lock(m_mutex);
+ m_bNeedsWrite = false;
+ }
+
+ return bReturn;
+}
+
+bool CUSBCECAdapterCommands::PersistConfiguration(const libcec_configuration &configuration)
+{
+ bool bReturn(false);
+ if (m_persistedConfiguration.iFirmwareVersion < 2)
+ return bReturn;
+
+ if (!RequestSettings())
+ return bReturn;
+
+ bReturn |= SetSettingAutoEnabled(true);
+ bReturn |= SetSettingDeviceType(CLibCEC::GetType(configuration.logicalAddresses.primary));
+ bReturn |= SetSettingDefaultLogicalAddress(configuration.logicalAddresses.primary);
+ bReturn |= SetSettingLogicalAddressMask(CLibCEC::GetMaskForType(configuration.logicalAddresses.primary));
+ bReturn |= SetSettingPhysicalAddress(configuration.iPhysicalAddress);
+ bReturn |= SetSettingCECVersion(configuration.cecVersion);
+ bReturn |= SetSettingOSDName(configuration.strDeviceName);
+
+ return bReturn;
+}
+
+bool CUSBCECAdapterCommands::RequestSettings(void)
+{
+ if (m_persistedConfiguration.iFirmwareVersion < 2)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - firmware version %d does not have any eeprom settings", __FUNCTION__, m_persistedConfiguration.iFirmwareVersion);
+ // settings can only be persisted with firmware v2+
+ return false;
+ }
+
+ if (m_bSettingsRetrieved)
+ return true;
+
+ bool bReturn(true);
+ bReturn &= RequestSettingAutoEnabled();
+ bReturn &= RequestSettingCECVersion();
+ bReturn &= RequestSettingDefaultLogicalAddress();
+ bReturn &= RequestSettingDeviceType();
+ bReturn &= RequestSettingLogicalAddressMask();
+ bReturn &= RequestSettingOSDName();
+ bReturn &= RequestSettingPhysicalAddress();
+
+ // don't read the following settings:
+ // - auto enabled (always enabled)
+ // - default logical address (autodetected)
+ // - logical address mask (autodetected)
+ // - CEC version (1.3a)
+
+ // TODO to be added to the firmware:
+ // - base device (4 bits)
+ // - HDMI port number (4 bits)
+ // - TV vendor id (12 bits)
+ // - wake devices (8 bits)
+ // - standby devices (8 bits)
+ // - use TV menu language (1 bit)
+ // - activate source (1 bit)
+ // - power off screensaver (1 bit)
+ // - power off on standby (1 bit)
+ // - send inactive source (1 bit)
+
+ m_bSettingsRetrieved = true;
+
+ return bReturn;
+}
+
+bool CUSBCECAdapterCommands::GetConfiguration(libcec_configuration &configuration)
+{
+ // get the settings from the eeprom if needed
+ if (!RequestSettings())
+ return false;
+
+ // copy the settings
+ configuration.iFirmwareVersion = m_persistedConfiguration.iFirmwareVersion;
+ configuration.deviceTypes = m_persistedConfiguration.deviceTypes;
+ configuration.iPhysicalAddress = m_persistedConfiguration.iPhysicalAddress;
+ snprintf(configuration.strDeviceName, 13, "%s", m_persistedConfiguration.strDeviceName);
+
+ return true;
+}
+
+bool CUSBCECAdapterCommands::PingAdapter(void)
+{
+#ifdef CEC_DEBUGGING
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "sending ping");
+#endif
+
+ CCECAdapterMessage params;
+ CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_PING, params);
+ bool bReturn = message && message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED;
+ SAFE_DELETE(message);
+ return bReturn;
+}
+
+bool CUSBCECAdapterCommands::SetAckMask(uint16_t iMask)
+{
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "setting ackmask to %2x", iMask);
+
+ CCECAdapterMessage params;
+ params.PushEscaped(iMask >> 8);
+ params.PushEscaped((uint8_t)iMask);
+ CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_SET_ACK_MASK, params);
+ bool bReturn = message && message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED;
+ SAFE_DELETE(message);
+ return bReturn;
+}
+
+void CUSBCECAdapterCommands::SetActiveSource(bool bSetTo, bool bClientUnregistered)
+{
+ if (bClientUnregistered) return;
+ if (m_persistedConfiguration.iFirmwareVersion >= 3)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "marking the adapter as %s source", bSetTo ? "active" : "inactive");
+ CCECAdapterMessage params;
+ params.PushEscaped(bSetTo ? 1 : 0);
+ CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_SET_ACTIVE_SOURCE, params);
+ SAFE_DELETE(message);
+ }
+}
+
+bool CUSBCECAdapterCommands::StartBootloader(void)
+{
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "starting the bootloader");
+
+ CCECAdapterMessage params;
+ CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_START_BOOTLOADER, params);
+ bool bReturn = message && message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED;
+ SAFE_DELETE(message);
+ return bReturn;
+}
+
+bool CUSBCECAdapterCommands::SetLineTimeout(uint8_t iTimeout)
+{
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "setting the line timeout to %d", iTimeout);
+ CCECAdapterMessage params;
+ params.PushEscaped(iTimeout);
+ CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_TRANSMIT_IDLETIME, params);
+ bool bReturn = message && message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED;
+ SAFE_DELETE(message);
+ return bReturn;
+}
+
+bool CUSBCECAdapterCommands::SetControlledMode(bool controlled)
+{
+ {
+ CLockObject lock(m_mutex);
+ if (m_bControlledMode == controlled)
+ return true;
+ }
+
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "turning controlled mode %s", controlled ? "on" : "off");
+
+ CCECAdapterMessage params;
+ params.PushEscaped(controlled ? 1 : 0);
+ CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_SET_CONTROLLED, params);
+ bool bReturn = message && message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED;
+ SAFE_DELETE(message);
+
+ if (bReturn)
+ {
+ CLockObject lock(m_mutex);
+ m_bControlledMode = controlled;
+ }
+
+ return bReturn;
+}
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include <p8-platform/threads/mutex.h>
+#include "USBCECAdapterMessage.h"
+
+namespace CEC
+{
+ class CUSBCECAdapterCommunication;
+
+ class CUSBCECAdapterCommands
+ {
+ public:
+ CUSBCECAdapterCommands(CUSBCECAdapterCommunication *comm);
+
+ /*!
+ * @brief Request the firmware version from the adapter.
+ * @return The firmware version, or 1 (default) if it couldn't be retrieved.
+ */
+ uint16_t RequestFirmwareVersion(void);
+
+ /*!
+ * @return The firmware version of the adapter, retrieved when the connection is opened.
+ */
+ uint16_t GetFirmwareVersion(void) const { return m_persistedConfiguration.iFirmwareVersion; };
+
+ /*!
+ * @brief Update the current configuration in the adapter. Does not do an eeprom update.
+ * @attention Not all settings are persisted at this time.
+ * @param configuration The configuration to persist.
+ * @return True when something changed, false otherwise.
+ */
+ bool PersistConfiguration(const libcec_configuration &configuration);
+
+ /*!
+ * @brief Get the persisted configuration from the EEPROM.
+ * @param configuration The persisted configuration.
+ * @return True when retrieved, false otherwise.
+ */
+ bool GetConfiguration(libcec_configuration &configuration);
+
+ /*!
+ * @brief Send a ping command to the adapter.
+ * @return True when acked by the adapter, false otherwise.
+ */
+ bool PingAdapter(void);
+
+ /*!
+ * @brief Change the ackmask of the adapter.
+ * @param iMask The new mask.
+ * @return True when the change was acked by the adapter, false otherwise.
+ */
+ bool SetAckMask(uint16_t iMask);
+
+ /*!
+ * @brief Put the adapter in bootloader mode.
+ * @attention The connection needs to be closed after this call, since the adapter will no longer be available.
+ * @return True when the command was sent, false otherwise.
+ */
+ bool StartBootloader(void);
+
+ /*!
+ * @brief Change the current CEC line timeout.
+ * @param iTimeout The new timeout.
+ * @return True when the change was acked by the adapter, false otherwise.
+ */
+ bool SetLineTimeout(uint8_t iTimeout);
+
+ /*!
+ * @brief Put the adapter in controlled or autonomous mode.
+ * @param controlled True to switch to controlled mode, false to switch to auto mode.
+ * @return True when acked by the controller, false otherwise.
+ */
+ bool SetControlledMode(bool controlled);
+
+ /*!
+ * @brief Request the firmware build date from the device.
+ * @return The build date in seconds since epoch, or 0 when no (valid) reply was received.
+ */
+ uint32_t RequestBuildDate(void);
+
+ /*!
+ * @return The persisted build date.
+ */
+ uint32_t GetPersistedBuildDate(void) const { return m_iBuildDate; };
+
+ /*!
+ * @brief Request the adapter type.
+ * @return The type
+ */
+ p8_cec_adapter_type RequestAdapterType(void);
+
+ /*!
+ * @return The persisted build date.
+ */
+ p8_cec_adapter_type GetPersistedAdapterType(void) const { return m_adapterType; };
+
+ /*!
+ * @brief Persist the current settings in the EEPROM
+ * @return True when persisted, false otherwise.
+ */
+ bool WriteEEPROM(void);
+
+ void SetActiveSource(bool bSetTo, bool bClientUnregistered);
+
+ private:
+ /*!
+ * @brief Reads all settings from the eeprom.
+ * @return True when read, false otherwise.
+ */
+ bool RequestSettings(void);
+
+ /*!
+ * @brief Request a setting value from the adapter.
+ * @param msgCode The setting to retrieve.
+ * @return The response from the adapter.
+ */
+ cec_datapacket RequestSetting(cec_adapter_messagecode msgCode);
+
+ /*!
+ * @brief Change the value of the "auto enabled" setting.
+ * @param enabled The new value.
+ * @return True when changed and set, false otherwise.
+ */
+ bool SetSettingAutoEnabled(bool enabled);
+
+ /*!
+ * @brief Request the value of the "auto enabled" setting from the adapter.
+ * @return True when retrieved, false otherwise.
+ */
+ bool RequestSettingAutoEnabled(void);
+
+ /*!
+ * @brief Change the value of the "device type" setting, used when the device is in autonomous mode.
+ * @param type The new value.
+ * @return True when changed and set, false otherwise.
+ */
+ bool SetSettingDeviceType(cec_device_type type);
+
+ /*!
+ * @brief Request the value of the "device type" setting from the adapter.
+ * @return True when retrieved, false otherwise.
+ */
+ bool RequestSettingDeviceType(void);
+
+ /*!
+ * @brief Change the value of the "default logical address" setting, used when the device is in autonomous mode.
+ * @param address The new value.
+ * @return True when changed and set, false otherwise.
+ */
+ bool SetSettingDefaultLogicalAddress(cec_logical_address address);
+
+ /*!
+ * @brief Request the value of the "default logical address" setting from the adapter.
+ * @return True when retrieved, false otherwise.
+ */
+ bool RequestSettingDefaultLogicalAddress(void);
+
+ /*!
+ * @brief Change the value of the "logical address mask" setting, used when the device is in autonomous mode.
+ * @param iMask The new value.
+ * @return True when changed and set, false otherwise.
+ */
+ bool SetSettingLogicalAddressMask(uint16_t iMask);
+
+ /*!
+ * @brief Request the value of the "logical address mask" setting from the adapter.
+ * @return True when retrieved, false otherwise.
+ */
+ bool RequestSettingLogicalAddressMask(void);
+
+ /*!
+ * @brief Change the value of the "physical address" setting, used when the device is in autonomous mode.
+ * @param iPhysicalAddress The new value.
+ * @return True when changed and set, false otherwise.
+ */
+ bool SetSettingPhysicalAddress(uint16_t iPhysicalAddress);
+
+ /*!
+ * @brief Request the value of the "physical address" setting from the adapter.
+ * @return True when retrieved, false otherwise.
+ */
+ bool RequestSettingPhysicalAddress(void);
+
+ /*!
+ * @brief Change the value of the "CEC version" setting, used when the device is in autonomous mode.
+ * @param version The new value.
+ * @return True when changed and set, false otherwise.
+ */
+ bool SetSettingCECVersion(cec_version version);
+
+ /*!
+ * @brief Request the value of the "CEC version" setting from the adapter.
+ * @return True when retrieved, false otherwise.
+ */
+ bool RequestSettingCECVersion(void);
+
+ /*!
+ * @brief Change the value of the "OSD name" setting, used when the device is in autonomous mode.
+ * @param strOSDName The new value.
+ * @return True when set, false otherwise.
+ */
+ bool SetSettingOSDName(const char *strOSDName);
+
+ /*!
+ * @brief Request the value of the "OSD name" setting from the adapter.
+ * @return True when retrieved, false otherwise.
+ */
+ bool RequestSettingOSDName(void);
+
+ CUSBCECAdapterCommunication *m_comm; /**< the communication handler */
+ bool m_bSettingsRetrieved; /**< true when the settings were read from the eeprom, false otherwise */
+ bool m_bSettingAutoEnabled; /**< the value of the auto-enabled setting */
+ cec_version m_settingCecVersion; /**< the value of the cec version setting */
+ uint16_t m_iSettingLAMask; /**< the value of the LA mask setting */
+ bool m_bNeedsWrite; /**< true when we sent changed settings to the adapter that have not been persisted */
+ libcec_configuration m_persistedConfiguration; /**< the configuration that is persisted in the eeprom */
+ uint32_t m_iBuildDate; /**< the build date of the firmware */
+ bool m_bControlledMode; /**< current value of the controlled mode feature */
+ p8_cec_adapter_type m_adapterType; /**< the type of the adapter that we're connected to */
+ P8PLATFORM::CMutex m_mutex;
+ };
+}
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include "USBCECAdapterCommunication.h"
+
+#include "USBCECAdapterCommands.h"
+#include "USBCECAdapterMessageQueue.h"
+#include "USBCECAdapterMessage.h"
+#include "USBCECAdapterDetection.h"
+#include "platform/sockets/serialport.h"
+#include <p8-platform/util/timeutils.h>
+#include <p8-platform/util/util.h>
+#include "platform/util/edid.h"
+#include "platform/adl/adl-edid.h"
+#include "platform/nvidia/nv-edid.h"
+#include "platform/drm/drm-edid.h"
+#include "LibCEC.h"
+#include "CECProcessor.h"
+
+using namespace CEC;
+using namespace P8PLATFORM;
+
+#define CEC_ADAPTER_PING_TIMEOUT 15000
+#define CEC_ADAPTER_EEPROM_WRITE_INTERVAL 30000
+#define CEC_ADAPTER_EEPROM_WRITE_RETRY 5000
+
+// firmware version 3
+#define CEC_LATEST_ADAPTER_FW_VERSION 3
+// firmware date Thu Nov 15 11:09:45 2012
+#define CEC_LATEST_ADAPTER_FW_DATE 0x50a4cd79
+
+#define CEC_FW_DATE_EXTENDED_RESPONSE 0x501a4b0c
+#define CEC_FW_DATE_DESCRIPTOR2 0x5045dbf5
+
+#define LIB_CEC m_callback->GetLib()
+
+CUSBCECAdapterCommunication::CUSBCECAdapterCommunication(IAdapterCommunicationCallback *callback, const char *strPort, uint16_t iBaudRate /* = CEC_SERIAL_DEFAULT_BAUDRATE */) :
+ IAdapterCommunication(callback),
+ m_port(NULL),
+ m_iLineTimeout(0),
+ m_lastPollDestination(CECDEVICE_UNKNOWN),
+ m_bInitialised(false),
+ m_pingThread(NULL),
+ m_eepromWriteThread(NULL),
+ m_commands(NULL),
+ m_adapterMessageQueue(NULL)
+{
+ m_logicalAddresses.Clear();
+ for (unsigned int iPtr = CECDEVICE_TV; iPtr < CECDEVICE_BROADCAST; iPtr++)
+ m_bWaitingForAck[iPtr] = false;
+ m_port = new CSerialPort(strPort, iBaudRate);
+ m_commands = new CUSBCECAdapterCommands(this);
+}
+
+CUSBCECAdapterCommunication::~CUSBCECAdapterCommunication(void)
+{
+ Close();
+ SAFE_DELETE(m_commands);
+ SAFE_DELETE(m_adapterMessageQueue);
+ SAFE_DELETE(m_port);
+}
+
+void CUSBCECAdapterCommunication::ResetMessageQueue(void)
+{
+ SAFE_DELETE(m_adapterMessageQueue);
+ m_adapterMessageQueue = new CCECAdapterMessageQueue(this);
+ m_adapterMessageQueue->CreateThread();
+}
+
+bool CUSBCECAdapterCommunication::Open(uint32_t iTimeoutMs /* = CEC_DEFAULT_CONNECT_TIMEOUT */, bool bSkipChecks /* = false */, bool bStartListening /* = true */)
+{
+ bool bConnectionOpened(false);
+ {
+ CLockObject lock(m_mutex);
+
+ /* we need the port settings here */
+ if (!m_port)
+ {
+ LIB_CEC->AddLog(CEC_LOG_ERROR, "port is NULL");
+ return bConnectionOpened;
+ }
+
+ /* return true when the port is already open */
+ if (IsOpen())
+ {
+ LIB_CEC->AddLog(CEC_LOG_WARNING, "port is already open");
+ return true;
+ }
+
+ ResetMessageQueue();
+
+ /* try to open the connection */
+ std::string strError;
+ CTimeout timeout(iTimeoutMs);
+ while (!bConnectionOpened && timeout.TimeLeft() > 0)
+ {
+ if ((bConnectionOpened = m_port->Open(timeout.TimeLeft())) == false)
+ {
+ strError = StringUtils::Format("error opening serial port '%s': %s", m_port->GetName().c_str(), m_port->GetError().c_str());
+ Sleep(250);
+ }
+ /* and retry every 250ms until the timeout passed */
+ }
+
+ /* return false when we couldn't connect */
+ if (!bConnectionOpened)
+ {
+ LIB_CEC->AddLog(CEC_LOG_ERROR, strError.c_str());
+
+ if (m_port->GetErrorNumber() == EACCES)
+ {
+ libcec_parameter param;
+ param.paramType = CEC_PARAMETER_TYPE_STRING;
+ param.paramData = (void*)"No permission to open the device";
+ LIB_CEC->Alert(CEC_ALERT_PERMISSION_ERROR, param);
+ }
+ else if (m_port->GetErrorNumber() == EBUSY)
+ {
+ libcec_parameter param;
+ param.paramType = CEC_PARAMETER_TYPE_STRING;
+ param.paramData = (void*)"The serial port is busy. Only one program can access the device directly.";
+ LIB_CEC->Alert(CEC_ALERT_PORT_BUSY, param);
+ }
+ return false;
+ }
+
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "connection opened, clearing any previous input and waiting for active transmissions to end before starting");
+ ClearInputBytes();
+ }
+
+ // always start by setting the ackmask to 0, to clear previous values
+ cec_logical_addresses addresses; addresses.Clear();
+ SetLogicalAddresses(addresses);
+
+ if (!CreateThread())
+ {
+ bConnectionOpened = false;
+ LIB_CEC->AddLog(CEC_LOG_ERROR, "could not create a communication thread");
+ }
+ else if (!bSkipChecks && !CheckAdapter())
+ {
+ bConnectionOpened = false;
+ LIB_CEC->AddLog(CEC_LOG_ERROR, "the adapter failed to pass basic checks");
+ }
+ else if (bStartListening)
+ {
+ /* start the eeprom write thread, that handles all eeprom writes async */
+ m_eepromWriteThread = new CAdapterEepromWriteThread(this);
+ if (!m_eepromWriteThread->CreateThread())
+ {
+ bConnectionOpened = false;
+ LIB_CEC->AddLog(CEC_LOG_ERROR, "could not create the eeprom write thread");
+ }
+ else
+ {
+ /* start a ping thread, that will ping the adapter every 15 seconds
+ if it doesn't receive any ping for 30 seconds, it'll switch to auto mode */
+ m_pingThread = new CAdapterPingThread(this, CEC_ADAPTER_PING_TIMEOUT);
+ if (m_pingThread->CreateThread())
+ {
+ bConnectionOpened = true;
+ }
+ else
+ {
+ bConnectionOpened = false;
+ LIB_CEC->AddLog(CEC_LOG_ERROR, "could not create a ping thread");
+ }
+ }
+ }
+
+ if (!bConnectionOpened || !bStartListening)
+ StopThread(0);
+
+ return bConnectionOpened;
+}
+
+void CUSBCECAdapterCommunication::Close(void)
+{
+ /* stop the reader thread */
+ StopThread(0);
+
+ CLockObject lock(m_mutex);
+
+ /* set the ackmask to 0 before closing the connection */
+ if (IsOpen() && m_port->GetErrorNumber() == 0)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - closing the connection", __FUNCTION__);
+ cec_logical_addresses addresses; addresses.Clear();
+ SetLogicalAddresses(addresses);
+ if (m_commands->GetFirmwareVersion() >= 2)
+ SetControlledMode(false);
+ }
+
+ m_adapterMessageQueue->Clear();
+
+ /* stop and delete the write thread */
+ if (m_eepromWriteThread)
+ m_eepromWriteThread->Stop();
+ SAFE_DELETE(m_eepromWriteThread);
+
+ /* stop and delete the ping thread */
+ SAFE_DELETE(m_pingThread);
+
+ /* close and delete the com port connection */
+ if (m_port)
+ m_port->Close();
+}
+
+cec_adapter_message_state CUSBCECAdapterCommunication::Write(const cec_command &data, bool &bRetry, uint8_t iLineTimeout, bool bIsReply)
+{
+ cec_adapter_message_state retVal(ADAPTER_MESSAGE_STATE_UNKNOWN);
+ if (!IsRunning())
+ return retVal;
+
+ CCECAdapterMessage *output = new CCECAdapterMessage(data, iLineTimeout);
+ output->bFireAndForget = bIsReply;
+
+ /* mark as waiting for an ack from the destination */
+ MarkAsWaiting(data.destination);
+
+ /* send the message */
+ if (bIsReply)
+ {
+ retVal = m_adapterMessageQueue->Write(output) ?
+ ADAPTER_MESSAGE_STATE_WAITING_TO_BE_SENT : ADAPTER_MESSAGE_STATE_ERROR;
+ }
+ else
+ {
+ bRetry = (!m_adapterMessageQueue->Write(output) || output->NeedsRetry()) && output->transmit_timeout > 0;
+ if (bRetry)
+ Sleep(CEC_DEFAULT_TRANSMIT_RETRY_WAIT);
+ retVal = output->state;
+
+ delete output;
+ }
+ return retVal;
+}
+
+void *CUSBCECAdapterCommunication::Process(void)
+{
+ CCECAdapterMessage msg;
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "communication thread started");
+
+ while (!IsStopped())
+ {
+ /* read from the serial port */
+ if (!ReadFromDevice(50, 5))
+ {
+ libcec_parameter param;
+ param.paramData = NULL; param.paramType = CEC_PARAMETER_TYPE_UNKOWN;
+ LIB_CEC->Alert(CEC_ALERT_CONNECTION_LOST, param);
+
+ break;
+ }
+
+ /* TODO sleep 5 ms so other threads can get a lock */
+ if (!IsStopped())
+ Sleep(5);
+ }
+
+ m_adapterMessageQueue->Clear();
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "communication thread ended");
+ return NULL;
+}
+
+bool CUSBCECAdapterCommunication::HandlePoll(const CCECAdapterMessage &msg)
+{
+ bool bIsError(msg.IsError());
+ cec_adapter_messagecode messageCode(msg.Message());
+ CLockObject lock(m_mutex);
+
+ if (messageCode == MSGCODE_FRAME_START && msg.IsACK())
+ {
+ m_lastPollDestination = msg.Destination();
+ if (msg.Destination() < CECDEVICE_BROADCAST)
+ {
+ CLockObject waitingLock(m_waitingMutex);
+ if (!m_bWaitingForAck[msg.Destination()] && !msg.IsEOM())
+ {
+ if (m_callback)
+ m_callback->HandlePoll(msg.Initiator(), msg.Destination());
+ }
+ else
+ m_bWaitingForAck[msg.Destination()] = false;
+ }
+ }
+ else if (messageCode == MSGCODE_RECEIVE_FAILED)
+ {
+ /* hack to suppress warnings when an LG is polling */
+ if (m_lastPollDestination != CECDEVICE_UNKNOWN)
+ bIsError = m_callback->HandleReceiveFailed(m_lastPollDestination);
+ }
+
+ return bIsError;
+}
+
+void CUSBCECAdapterCommunication::MarkAsWaiting(const cec_logical_address dest)
+{
+ /* mark as waiting for an ack from the destination */
+ if (dest < CECDEVICE_BROADCAST)
+ {
+ CLockObject waitingLock(m_waitingMutex);
+ m_bWaitingForAck[dest] = true;
+ }
+}
+
+void CUSBCECAdapterCommunication::ClearInputBytes(uint32_t iTimeout /* = CEC_CLEAR_INPUT_DEFAULT_WAIT */)
+{
+ CTimeout timeout(iTimeout);
+ uint8_t buff[1024];
+ ssize_t iBytesRead(0);
+ bool bGotMsgEnd(true);
+
+ while (timeout.TimeLeft() > 0 && ((iBytesRead = m_port->Read(buff, 1024, 5)) > 0 || !bGotMsgEnd))
+ {
+ bGotMsgEnd = false;
+ /* if something was received, wait for MSGEND */
+ for (ssize_t iPtr = 0; iPtr < iBytesRead; iPtr++)
+ bGotMsgEnd = buff[iPtr] == MSGEND;
+ }
+}
+
+bool CUSBCECAdapterCommunication::SetLineTimeout(uint8_t iTimeout)
+{
+ bool bReturn(true);
+ bool bChanged(false);
+
+ /* only send the command if the timeout changed */
+ {
+ CLockObject lock(m_mutex);
+ bChanged = (m_iLineTimeout != iTimeout);
+ m_iLineTimeout = iTimeout;
+ }
+
+ if (bChanged)
+ bReturn = m_commands->SetLineTimeout(iTimeout);
+
+ return bReturn;
+}
+
+bool CUSBCECAdapterCommunication::WriteToDevice(CCECAdapterMessage *message)
+{
+ CLockObject adapterLock(m_mutex);
+ if (!IsOpen())
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "error writing command '%s' to serial port '%s': the connection is closed", CCECAdapterMessage::ToString(message->Message()), m_port->GetName().c_str());
+ message->state = ADAPTER_MESSAGE_STATE_ERROR;
+ return false;
+ }
+
+ /* write the message */
+ if (m_port->Write(message->packet.data, message->Size()) != (ssize_t) message->Size())
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "error writing command '%s' to serial port '%s': %s", CCECAdapterMessage::ToString(message->Message()), m_port->GetName().c_str(), m_port->GetError().c_str());
+ message->state = ADAPTER_MESSAGE_STATE_ERROR;
+ // let the higher level close the port
+ return false;
+ }
+
+#ifdef CEC_DEBUGGING
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "command '%s' sent", message->IsTransmission() ? "CEC transmission" : CCECAdapterMessage::ToString(message->Message()));
+#endif
+ message->state = ADAPTER_MESSAGE_STATE_SENT;
+ return true;
+}
+
+bool CUSBCECAdapterCommunication::ReadFromDevice(uint32_t iTimeout, size_t iSize /* = 256 */)
+{
+ ssize_t iBytesRead(0);
+ uint8_t buff[256];
+ if (iSize > 256)
+ iSize = 256;
+
+ /* read from the serial port */
+ {
+ CLockObject lock(m_mutex);
+ if (!IsOpen())
+ return false;
+
+ do {
+ /* retry Read() if it was interrupted */
+ iBytesRead = m_port->Read(buff, sizeof(uint8_t) * iSize, iTimeout);
+ } while(m_port->GetErrorNumber() == EINTR);
+
+
+ if (m_port->GetErrorNumber())
+ {
+ LIB_CEC->AddLog(CEC_LOG_ERROR, "error reading from serial port: %s", m_port->GetError().c_str());
+ // let the higher level close the port
+ return false;
+ }
+ }
+
+ if (iBytesRead < 0 || iBytesRead > 256)
+ return false;
+ else if (iBytesRead > 0)
+ {
+ /* add the data to the current frame */
+ m_adapterMessageQueue->AddData(buff, iBytesRead);
+ }
+
+ return true;
+}
+
+CCECAdapterMessage *CUSBCECAdapterCommunication::SendCommand(cec_adapter_messagecode msgCode, CCECAdapterMessage ¶ms, bool bIsRetry /* = false */)
+{
+ if (!IsOpen() || !m_adapterMessageQueue)
+ return NULL;
+
+ /* create the adapter message for this command */
+ CCECAdapterMessage *output = new CCECAdapterMessage;
+ output->PushBack(MSGSTART);
+ output->PushEscaped((uint8_t)msgCode);
+ output->Append(params);
+ output->PushBack(MSGEND);
+
+ /* write the command */
+ if (!m_adapterMessageQueue->Write(output))
+ {
+ // this will trigger an alert in the reader thread
+ if (output->state == ADAPTER_MESSAGE_STATE_ERROR)
+ m_port->Close();
+ return output;
+ }
+ else
+ {
+ if (!bIsRetry && output->Reply() == MSGCODE_COMMAND_REJECTED && msgCode != MSGCODE_SET_CONTROLLED &&
+ msgCode != MSGCODE_GET_BUILDDATE /* same messagecode value had a different meaning in older fw builds */)
+ {
+ /* if the controller reported that the command was rejected, and we didn't send the command
+ to set controlled mode, then the controller probably switched to auto mode. set controlled
+ mode and retry */
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "setting controlled mode and retrying");
+ delete output;
+ if (SetControlledMode(true))
+ return SendCommand(msgCode, params, true);
+ }
+ }
+
+ return output;
+}
+
+bool CUSBCECAdapterCommunication::CheckAdapter(uint32_t iTimeoutMs /* = CEC_DEFAULT_CONNECT_TIMEOUT */)
+{
+ bool bReturn(false);
+ CTimeout timeout(iTimeoutMs > 0 ? iTimeoutMs : CEC_DEFAULT_TRANSMIT_WAIT);
+
+ /* try to ping the adapter */
+ bool bPinged(false);
+ unsigned iPingTry(0);
+ while (timeout.TimeLeft() > 0 && (bPinged = PingAdapter()) == false)
+ {
+ LIB_CEC->AddLog(CEC_LOG_ERROR, "the adapter did not respond correctly to a ping (try %d)", ++iPingTry);
+ CEvent::Sleep(500);
+ }
+
+ /* try to read the firmware version */
+ if (bPinged && timeout.TimeLeft() > 0 && m_commands->RequestFirmwareVersion() >= 2)
+ {
+ /* try to set controlled mode for v2+ firmwares */
+ unsigned iControlledTry(0);
+ bool bControlled(false);
+ while (timeout.TimeLeft() > 0 && (bControlled = SetControlledMode(true)) == false)
+ {
+ LIB_CEC->AddLog(CEC_LOG_ERROR, "the adapter did not respond correctly to setting controlled mode (try %d)", ++iControlledTry);
+ CEvent::Sleep(500);
+ }
+ bReturn = bControlled;
+ }
+ else
+ bReturn = true;
+
+ if (m_commands->GetFirmwareVersion() >= 2)
+ {
+ /* try to read the build date */
+ m_commands->RequestBuildDate();
+
+ /* try to read the adapter type */
+ m_commands->RequestAdapterType();
+ }
+
+ SetInitialised(bReturn);
+ return bReturn;
+}
+
+bool CUSBCECAdapterCommunication::IsOpen(void)
+{
+ /* thread is not being stopped, the port is open and the thread is running */
+ return !IsStopped() && m_port->IsOpen() && IsRunning();
+}
+
+std::string CUSBCECAdapterCommunication::GetError(void) const
+{
+ return m_port->GetError();
+}
+
+void CUSBCECAdapterCommunication::SetInitialised(bool bSetTo /* = true */)
+{
+ CLockObject lock(m_mutex);
+ m_bInitialised = bSetTo;
+}
+
+bool CUSBCECAdapterCommunication::IsInitialised(void)
+{
+ CLockObject lock(m_mutex);
+ return m_bInitialised;
+}
+
+bool CUSBCECAdapterCommunication::StartBootloader(void)
+{
+ if (m_port->IsOpen() && m_commands->StartBootloader())
+ {
+ m_port->Close();
+ return true;
+ }
+ return false;
+}
+
+bool CUSBCECAdapterCommunication::SetLogicalAddresses(const cec_logical_addresses &addresses)
+{
+ {
+ CLockObject lock(m_mutex);
+ if (m_logicalAddresses == addresses)
+ return true;
+ }
+
+ if (IsOpen() && m_commands->SetAckMask(addresses.AckMask()))
+ {
+ CLockObject lock(m_mutex);
+ m_logicalAddresses = addresses;
+ return true;
+ }
+
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "couldn't change the ackmask: the connection is closed");
+ return false;
+}
+
+cec_logical_addresses CUSBCECAdapterCommunication::GetLogicalAddresses(void)
+{
+ cec_logical_addresses addresses;
+ CLockObject lock(m_mutex);
+ addresses = m_logicalAddresses;
+ return addresses;
+}
+
+bool CUSBCECAdapterCommunication::PingAdapter(void)
+{
+ return IsOpen() ? m_commands->PingAdapter() : false;
+}
+
+uint16_t CUSBCECAdapterCommunication::GetFirmwareVersion(void)
+{
+ return m_commands ? m_commands->GetFirmwareVersion() : CEC_FW_VERSION_UNKNOWN;
+}
+
+uint32_t CUSBCECAdapterCommunication::GetFirmwareBuildDate(void)
+{
+ uint32_t iBuildDate(0);
+ if (m_commands)
+ iBuildDate = m_commands->GetPersistedBuildDate();
+ if (iBuildDate == 0 && IsOpen())
+ iBuildDate = m_commands->RequestBuildDate();
+
+ return iBuildDate;
+}
+
+cec_adapter_type CUSBCECAdapterCommunication::GetAdapterType(void)
+{
+ cec_adapter_type type(ADAPTERTYPE_UNKNOWN);
+ if (m_commands)
+ type = (cec_adapter_type)m_commands->GetPersistedAdapterType();
+ if (type == ADAPTERTYPE_UNKNOWN && IsOpen())
+ type = (cec_adapter_type)m_commands->RequestAdapterType();
+
+ return type;
+}
+
+bool CUSBCECAdapterCommunication::ProvidesExtendedResponse(void)
+{
+ uint32_t iBuildDate(0);
+ if (m_commands)
+ iBuildDate = m_commands->GetPersistedBuildDate();
+
+ return iBuildDate >= CEC_FW_DATE_EXTENDED_RESPONSE;
+}
+
+uint16_t CUSBCECAdapterCommunication::GetAdapterVendorId(void) const
+{
+ return CEC_VID;
+}
+
+uint16_t CUSBCECAdapterCommunication::GetAdapterProductId(void) const
+{
+ uint32_t iBuildDate(0);
+ if (m_commands)
+ iBuildDate = m_commands->GetPersistedBuildDate();
+
+ return iBuildDate >= CEC_FW_DATE_DESCRIPTOR2 ? CEC_PID2 : CEC_PID;
+}
+
+void CUSBCECAdapterCommunication::SetActiveSource(bool bSetTo, bool bClientUnregistered)
+{
+ if (m_commands)
+ m_commands->SetActiveSource(bSetTo, bClientUnregistered);
+}
+
+bool CUSBCECAdapterCommunication::IsRunningLatestFirmware(void)
+{
+ return GetFirmwareBuildDate() >= CEC_LATEST_ADAPTER_FW_DATE &&
+ GetFirmwareVersion() >= CEC_LATEST_ADAPTER_FW_VERSION;
+}
+
+bool CUSBCECAdapterCommunication::PersistConfiguration(const libcec_configuration &configuration)
+{
+ return IsOpen() ?
+ m_commands->PersistConfiguration(configuration) && m_eepromWriteThread->Write() :
+ false;
+}
+
+bool CUSBCECAdapterCommunication::GetConfiguration(libcec_configuration &configuration)
+{
+ return IsOpen() ? m_commands->GetConfiguration(configuration) : false;
+}
+
+std::string CUSBCECAdapterCommunication::GetPortName(void)
+{
+ return m_port->GetName();
+}
+
+bool CUSBCECAdapterCommunication::SetControlledMode(bool controlled)
+{
+ return IsOpen() ? m_commands->SetControlledMode(controlled) : false;
+}
+
+uint16_t CUSBCECAdapterCommunication::GetPhysicalAddress(void)
+{
+ uint16_t iPA(0);
+
+ // try to get the PA from ADL
+#if defined(HAVE_ADL_EDID_PARSER)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - trying to get the physical address via ADL", __FUNCTION__);
+ CADLEdidParser adl;
+ iPA = adl.GetPhysicalAddress();
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - ADL returned physical address %04x", __FUNCTION__, iPA);
+ }
+#endif
+
+ // try to get the PA from the nvidia driver
+#if defined(HAVE_NVIDIA_EDID_PARSER)
+ if (iPA == 0)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - trying to get the physical address via nvidia driver", __FUNCTION__);
+ CNVEdidParser nv;
+ iPA = nv.GetPhysicalAddress();
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - nvidia driver returned physical address %04x", __FUNCTION__, iPA);
+ }
+#endif
+
+// try to get the PA from the intel driver
+#if defined(HAVE_DRM_EDID_PARSER)
+ if (iPA == 0)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - trying to get the physical address via drm files", __FUNCTION__);
+ CDRMEdidParser nv;
+ iPA = nv.GetPhysicalAddress();
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - drm files returned physical address %04x", __FUNCTION__, iPA);
+ }
+#endif
+
+ // try to get the PA from the OS
+ if (iPA == 0)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - trying to get the physical address from the OS", __FUNCTION__);
+ iPA = CEDIDParser::GetPhysicalAddress();
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - OS returned physical address %04x", __FUNCTION__, iPA);
+ }
+
+ return iPA;
+}
+
+void *CAdapterPingThread::Process(void)
+{
+ while (!IsStopped())
+ {
+ if (m_timeout.TimeLeft() == 0)
+ {
+ /* reinit the timeout */
+ m_timeout.Init(CEC_ADAPTER_PING_TIMEOUT);
+
+ /* send a ping to the adapter */
+ bool bPinged(false);
+ int iFailedCounter(0);
+ while (!bPinged && iFailedCounter < 3 && !IsStopped())
+ {
+ if (!m_com->PingAdapter())
+ {
+ /* sleep and retry */
+ Sleep(CEC_DEFAULT_TRANSMIT_RETRY_WAIT);
+ ++iFailedCounter;
+ }
+ else
+ {
+ bPinged = true;
+ }
+ }
+
+ if (iFailedCounter == 3 && !IsStopped())
+ {
+ /* failed to ping the adapter 3 times in a row. something must be wrong with the connection */
+ m_com->LIB_CEC->AddLog(CEC_LOG_ERROR, "failed to ping the adapter 3 times in a row. closing the connection.");
+ m_com->StopThread(false);
+
+ libcec_parameter param;
+ param.paramData = NULL; param.paramType = CEC_PARAMETER_TYPE_UNKOWN;
+ m_com->LIB_CEC->Alert(CEC_ALERT_CONNECTION_LOST, param);
+
+ break;
+ }
+ }
+
+ Sleep(5);
+ }
+ return NULL;
+}
+
+void CAdapterEepromWriteThread::Stop(void)
+{
+ StopThread(-1);
+ {
+ CLockObject lock(m_mutex);
+ if (m_iScheduleEepromWrite > 0)
+ m_com->LIB_CEC->AddLog(CEC_LOG_WARNING, "write thread stopped while a write was queued");
+ m_bWrite = true;
+ m_condition.Signal();
+ }
+ StopThread();
+}
+
+void *CAdapterEepromWriteThread::Process(void)
+{
+ while (!IsStopped())
+ {
+ CLockObject lock(m_mutex);
+ if ((m_iScheduleEepromWrite > 0 && m_iScheduleEepromWrite < GetTimeMs()) ||
+ m_condition.Wait(m_mutex, m_bWrite, 100))
+ {
+ if (IsStopped())
+ break;
+ m_bWrite = false;
+ if (m_com->m_commands->WriteEEPROM())
+ {
+ m_iLastEepromWrite = GetTimeMs();
+ m_iScheduleEepromWrite = 0;
+ }
+ else
+ {
+ m_iScheduleEepromWrite = GetTimeMs() + CEC_ADAPTER_EEPROM_WRITE_RETRY;
+ }
+ }
+ }
+ return NULL;
+}
+
+bool CAdapterEepromWriteThread::Write(void)
+{
+ CLockObject lock(m_mutex);
+ if (m_iScheduleEepromWrite == 0)
+ {
+ int64_t iNow = GetTimeMs();
+ if (m_iLastEepromWrite + CEC_ADAPTER_EEPROM_WRITE_INTERVAL > iNow)
+ {
+ m_com->LIB_CEC->AddLog(CEC_LOG_DEBUG, "delaying eeprom write by %ld ms", m_iLastEepromWrite + CEC_ADAPTER_EEPROM_WRITE_INTERVAL - iNow);
+ m_iScheduleEepromWrite = m_iLastEepromWrite + CEC_ADAPTER_EEPROM_WRITE_INTERVAL;
+ }
+ else
+ {
+ m_bWrite = true;
+ m_condition.Signal();
+ }
+ }
+ return true;
+}
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include <p8-platform/threads/threads.h>
+#include "adapter/AdapterCommunication.h"
+#include "USBCECAdapterMessage.h"
+
+namespace P8PLATFORM
+{
+ class ISocket;
+}
+
+namespace CEC
+{
+ class CCECProcessor;
+ class CAdapterPingThread;
+ class CAdapterEepromWriteThread;
+ class CUSBCECAdapterCommands;
+ class CCECAdapterMessageQueue;
+ class CCECAdapterMessage;
+
+ class CUSBCECAdapterCommunication : public IAdapterCommunication, public P8PLATFORM::CThread
+ {
+ friend class CUSBCECAdapterCommands;
+ friend class CCECAdapterMessageQueue;
+ friend class CAdapterEepromWriteThread;
+
+ public:
+ /*!
+ * @brief Create a new USB-CEC communication handler.
+ * @param callback The callback to use for incoming CEC commands.
+ * @param strPort The name of the com port to use.
+ * @param iBaudRate The baudrate to use on the com port connection.
+ */
+ CUSBCECAdapterCommunication(IAdapterCommunicationCallback *callback, const char *strPort, uint16_t iBaudRate = CEC_SERIAL_DEFAULT_BAUDRATE);
+ virtual ~CUSBCECAdapterCommunication(void);
+
+ /** @name IAdapterCommunication implementation */
+ ///{
+ bool Open(uint32_t iTimeoutMs = CEC_DEFAULT_CONNECT_TIMEOUT, bool bSkipChecks = false, bool bStartListening = true);
+ void Close(void);
+ bool IsOpen(void);
+ std::string GetError(void) const;
+ cec_adapter_message_state Write(const cec_command &data, bool &bRetry, uint8_t iLineTimeout, bool bIsReply);
+
+ bool StartBootloader(void);
+ bool SetLogicalAddresses(const cec_logical_addresses &addresses);
+ cec_logical_addresses GetLogicalAddresses(void);
+ bool PingAdapter(void);
+ uint16_t GetFirmwareVersion(void);
+ uint32_t GetFirmwareBuildDate(void);
+ bool IsRunningLatestFirmware(void);
+ bool PersistConfiguration(const libcec_configuration &configuration);
+ bool GetConfiguration(libcec_configuration &configuration);
+ std::string GetPortName(void);
+ uint16_t GetPhysicalAddress(void);
+ bool SetControlledMode(bool controlled);
+ cec_vendor_id GetVendorId(void) { return CEC_VENDOR_UNKNOWN; }
+ bool SupportsSourceLogicalAddress(const cec_logical_address UNUSED(address)) { return true; }
+ cec_adapter_type GetAdapterType(void);
+ uint16_t GetAdapterVendorId(void) const;
+ uint16_t GetAdapterProductId(void) const;
+ void SetActiveSource(bool bSetTo, bool bClientUnregistered);
+ ///}
+
+ bool ProvidesExtendedResponse(void);
+
+ void *Process(void);
+
+ private:
+ /*!
+ * @brief Clear all input bytes.
+ * @param iTimeout Timeout when anything was received.
+ */
+ void ClearInputBytes(uint32_t iTimeout = CEC_CLEAR_INPUT_DEFAULT_WAIT);
+
+ /*!
+ * @brief Change the current CEC line timeout.
+ * @param iTimeout The new timeout.
+ * @return True when acked by the controller, false otherwise.
+ */
+ bool SetLineTimeout(uint8_t iTimeout);
+
+ /*!
+ * @brief Send a command to the controller and wait for an ack.
+ * @param msgCode The command to send.
+ * @param params The parameters to the command.
+ * @param bIsRetry True when this command is being retried, false otherwise.
+ * @return The message. Delete when done with it.
+ */
+ CCECAdapterMessage *SendCommand(cec_adapter_messagecode msgCode, CCECAdapterMessage ¶ms, bool bIsRetry = false);
+
+ /*!
+ * @brief Change the "initialised" status.
+ * @param bSetTo The new value.
+ */
+ void SetInitialised(bool bSetTo = true);
+
+ /*!
+ * @return True when initialised, false otherwise.
+ */
+ bool IsInitialised(void);
+
+ /*!
+ * @brief Pings the adapter, checks the firmware version and sets controlled mode.
+ * @param iTimeoutMs The timeout after which this fails if no proper data was received.
+ * @return True when the checks passed, false otherwise.
+ */
+ bool CheckAdapter(uint32_t iTimeoutMs = CEC_DEFAULT_CONNECT_TIMEOUT);
+
+ /*!
+ * @brief Handle a poll message inside the adapter message (checks if one is present).
+ * @param msg The adapter message to parse.
+ * @return True when the message resulted in a CEC error, false otherwise.
+ */
+ bool HandlePoll(const CCECAdapterMessage &msg);
+
+ /*!
+ * @brief Read data from the device.
+ * @param iTimeout The read timeout to use.
+ * @param iSize The maximum read size.
+ * @return True when something was read, false otherwise.
+ */
+ bool ReadFromDevice(uint32_t iTimeout, size_t iSize = 256);
+
+ /*!
+ * @brief Writes a message to the serial port.
+ * @param message The message to write.
+ * @return True when written, false otherwise.
+ */
+ bool WriteToDevice(CCECAdapterMessage *message);
+
+ /*!
+ * @brief Called before sending a CEC command over the line, so we know we're expecting an ack.
+ * @param dest The destination of the CEC command.
+ */
+ void MarkAsWaiting(const cec_logical_address dest);
+
+ /*!
+ * @brief Clear and reset the message queue.
+ */
+ void ResetMessageQueue(void);
+
+ P8PLATFORM::ISocket * m_port; /**< the com port connection */
+ P8PLATFORM::CMutex m_mutex; /**< mutex for changes in this class */
+ uint8_t m_iLineTimeout; /**< the current line timeout on the CEC line */
+ cec_logical_address m_lastPollDestination; /**< the destination of the last poll message that was received */
+ bool m_bInitialised; /**< true when the connection is initialised, false otherwise */
+ bool m_bWaitingForAck[15]; /**< array in which we store from which devices we're expecting acks */
+ CAdapterPingThread * m_pingThread; /**< ping thread, that pings the adapter every 15 seconds */
+ CAdapterEepromWriteThread * m_eepromWriteThread; /**< eeprom writes are done async */
+ CUSBCECAdapterCommands * m_commands; /**< commands that can be sent to the adapter */
+ CCECAdapterMessageQueue * m_adapterMessageQueue; /**< the incoming and outgoing message queue */
+ cec_logical_addresses m_logicalAddresses; /**< the logical address list that this instance is using */
+ P8PLATFORM::CMutex m_waitingMutex;
+ };
+
+ class CAdapterEepromWriteThread : public P8PLATFORM::CThread
+ {
+ public:
+ CAdapterEepromWriteThread(CUSBCECAdapterCommunication *com) :
+ m_com(com),
+ m_bWrite(false),
+ m_iLastEepromWrite(0),
+ m_iScheduleEepromWrite(0) {}
+ virtual ~CAdapterEepromWriteThread(void) {}
+
+ bool Write(void);
+ void* Process(void);
+ void Stop(void);
+ private:
+ CUSBCECAdapterCommunication *m_com;
+ bool m_bWrite;
+ P8PLATFORM::CCondition<bool> m_condition;
+ P8PLATFORM::CMutex m_mutex;
+ int64_t m_iLastEepromWrite; /**< last time that this instance did an eeprom write */
+ int64_t m_iScheduleEepromWrite; /**< in case there were more than 2 changes within 30 seconds, do another write at this time */
+ };
+
+ class CAdapterPingThread : public P8PLATFORM::CThread
+ {
+ public:
+ CAdapterPingThread(CUSBCECAdapterCommunication *com, uint32_t iTimeout) :
+ m_com(com),
+ m_timeout(iTimeout){}
+ virtual ~CAdapterPingThread(void) {}
+
+ void* Process(void);
+ private:
+ CUSBCECAdapterCommunication* m_com;
+ P8PLATFORM::CTimeout m_timeout;
+ };
+};
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include "USBCECAdapterDetection.h"
+
+#if defined(__APPLE__)
+#include <dirent.h>
+#include <sys/param.h>
+#include <IOKit/IOKitLib.h>
+#include <IOKit/IOMessage.h>
+#include <IOKit/IOCFPlugIn.h>
+#include <IOKit/usb/IOUSBLib.h>
+#include <IOKit/serial/IOSerialKeys.h>
+#include <CoreFoundation/CoreFoundation.h>
+#elif defined(__WINDOWS__)
+#pragma comment(lib, "advapi32.lib")
+#pragma comment(lib, "setupapi.lib")
+#pragma comment(lib, "cfgmgr32.lib")
+#include <setupapi.h>
+#include <cfgmgr32.h>
+#include <tchar.h>
+
+// the virtual COM port only shows up when requesting devices with the raw device guid!
+static GUID USB_RAW_GUID = { 0xA5DCBF10, 0x6530, 0x11D2, { 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED } };
+static GUID USB_CDC_GUID = { 0x4D36E978, 0xE325, 0x11CE, { 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18 } };
+
+#elif defined(HAVE_LIBUDEV)
+#include <dirent.h>
+#include <poll.h>
+extern "C" {
+#include <libudev.h>
+}
+#elif defined(__FreeBSD__)
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <stdio.h>
+#include <unistd.h>
+#endif
+
+#include <string>
+#include <algorithm>
+#include <stdio.h>
+#include <p8-platform/util/StringUtils.h>
+
+#define CEC_VID 0x2548
+#define CEC_PID 0x1001
+#define CEC_PID2 0x1002
+
+using namespace CEC;
+
+#if defined(HAVE_LIBUDEV)
+bool TranslateComPort(std::string& strString)
+{
+ std::string strTmp(strString);
+ std::reverse(strTmp.begin(), strTmp.end());
+ const char* iSlash = strchr(strTmp.c_str(), '/');
+ if (iSlash)
+ {
+ strTmp = StringUtils::Left(strTmp, iSlash - strTmp.c_str());
+ std::reverse(strTmp.begin(), strTmp.end());
+ strString = StringUtils::Format("%s/%s:1.0/tty", strString.c_str(), strTmp.c_str());
+ return true;
+ }
+
+ return false;
+}
+
+bool FindComPort(std::string& strLocation)
+{
+ std::string strPort = strLocation;
+ bool bReturn(!strPort.empty());
+ std::string strConfigLocation(strLocation);
+ if (TranslateComPort(strConfigLocation))
+ {
+ DIR *dir;
+ struct dirent *dirent;
+ if((dir = opendir(strConfigLocation.c_str())) == NULL)
+ return bReturn;
+
+ while ((dirent = readdir(dir)) != NULL)
+ {
+ if(strcmp((char*)dirent->d_name, "." ) != 0 && strcmp((char*)dirent->d_name, ".." ) != 0)
+ {
+ strPort = StringUtils::Format("/dev/%s", dirent->d_name);
+ if (!strPort.empty())
+ {
+ strLocation = strPort;
+ bReturn = true;
+ break;
+ }
+ }
+ }
+ closedir(dir);
+ }
+
+ return bReturn;
+}
+#endif
+
+bool CUSBCECAdapterDetection::CanAutodetect(void)
+{
+#if defined(__APPLE__) || defined(HAVE_LIBUDEV) || defined(__WINDOWS__) || defined(__FreeBSD__)
+ return true;
+#else
+ return false;
+#endif
+}
+
+#if defined(__WINDOWS__)
+static bool GetComPortFromDevNode(DEVINST hDevInst, char* strPortName, unsigned int iSize)
+{
+ bool bReturn(false);
+ TCHAR strRegPortName[256];
+ strRegPortName[0] = _T('\0');
+ DWORD dwSize = sizeof(strRegPortName);
+ DWORD dwType = 0;
+ HKEY hDeviceKey;
+
+ // open the device node key
+ if (CM_Open_DevNode_Key(hDevInst, KEY_QUERY_VALUE, 0, RegDisposition_OpenExisting, &hDeviceKey, CM_REGISTRY_HARDWARE) != CR_SUCCESS)
+ {
+ printf("reg key not found\n");
+ return bReturn;
+ }
+
+ // locate the PortName entry. TODO this one doesn't seem to be available in universal
+ if ((RegQueryValueEx(hDeviceKey, _T("PortName"), NULL, &dwType, reinterpret_cast<LPBYTE>(strRegPortName), &dwSize) == ERROR_SUCCESS) &&
+ (dwType == REG_SZ) &&
+ _tcslen(strRegPortName) > 3 &&
+ _tcsnicmp(strRegPortName, _T("COM"), 3) == 0 &&
+ _ttoi(&(strRegPortName[3])) > 0)
+ {
+ // return the port name
+ snprintf(strPortName, iSize, "%s", strRegPortName);
+ bReturn = true;
+ }
+
+ // TODO this one doesn't seem to be available in universal
+ RegCloseKey(hDeviceKey);
+
+ return bReturn;
+}
+
+static bool GetPidVidFromDeviceName(const std::string strDevName, int* vid, int* pid)
+{
+ std::string strDevNameUpper(strDevName);
+ StringUtils::ToUpper(strDevNameUpper);
+ size_t iPidPos = strDevNameUpper.find("PID_");
+ size_t iVidPos = strDevNameUpper.find("VID_");
+ if (iPidPos == std::string::npos || iVidPos == std::string::npos || (strDevNameUpper.find("&MI_") != std::string::npos && strDevNameUpper.find("&MI_00") == std::string::npos))
+ return false;
+
+ std::string strVendorId(strDevNameUpper.substr(iVidPos + 4, 4));
+ std::string strProductId(strDevNameUpper.substr(iPidPos + 4, 4));
+
+ sscanf(strVendorId.c_str(), "%x", vid);
+ sscanf(strProductId.c_str(), "%x", pid);
+
+ return true;
+}
+#endif
+
+uint8_t CUSBCECAdapterDetection::FindAdaptersWindows(cec_adapter_descriptor* deviceList, uint8_t iBufSize, const char* strDevicePath /* = NULL */)
+{
+ uint8_t iFound(0);
+
+#if defined(__WINDOWS__)
+ ULONG len;
+ PCHAR buffer;
+
+ CM_Get_Device_ID_List_Size(&len, 0, CM_GETIDLIST_FILTER_NONE);
+ buffer = (PCHAR)malloc(sizeof(CHAR) * len);
+ if (buffer)
+ {
+ CM_Get_Device_ID_List(0, buffer, len, CM_GETIDLIST_FILTER_NONE);
+
+ for (CHAR* devId = buffer; *devId; devId += strlen(devId) + 1)
+ {
+ // check whether the path matches, if a path was given
+ if (strDevicePath && strcmp(strDevicePath, devId) != 0)
+ continue;
+
+ // get the vid and pid
+ int iVendor, iProduct;
+ if (!GetPidVidFromDeviceName(devId, &iVendor, &iProduct))
+ continue;
+
+ // no match
+ if (iVendor != CEC_VID || (iProduct != CEC_PID && iProduct != CEC_PID2))
+ continue;
+
+ // locate the device node
+ DEVINST devInst = 0, childInst = 0;
+ if (CM_Locate_DevNode(&devInst, devId, 0) != CR_SUCCESS)
+ continue;
+
+ // get the child node if this is a composite device
+ if (iProduct == CEC_PID2)
+ {
+ if (CM_Get_Child(&childInst, devInst, 0) != CR_SUCCESS)
+ continue;
+ devInst = childInst;
+ }
+
+ // get the com port
+ if (devInst != 0)
+ {
+ if (GetComPortFromDevNode(devInst, deviceList[iFound].strComName, sizeof(deviceList[iFound].strComName)))
+ {
+ snprintf(deviceList[iFound].strComPath, sizeof(deviceList[iFound].strComPath), "%s", devId);
+ deviceList[iFound].iVendorId = (uint16_t)iVendor;
+ deviceList[iFound].iProductId = (uint16_t)iProduct;
+ deviceList[iFound].adapterType = ADAPTERTYPE_P8_EXTERNAL; // will be overridden when not doing a "quick scan" by the actual type
+ iFound++;
+ }
+ }
+ }
+
+ free(buffer);
+ }
+#else
+ (void)deviceList;
+ (void)iBufSize;
+ (void)strDevicePath;
+#endif
+
+ return iFound;
+}
+
+uint8_t CUSBCECAdapterDetection::FindAdaptersApple(cec_adapter_descriptor *deviceList, uint8_t iBufSize, const char *strDevicePath /* = NULL */)
+{
+ uint8_t iFound(0);
+
+#if defined(__APPLE__)
+ kern_return_t kresult;
+ char bsdPath[MAXPATHLEN] = { 0 };
+ io_iterator_t serialPortIterator;
+
+ CFMutableDictionaryRef classesToMatch = IOServiceMatching(kIOSerialBSDServiceValue);
+ if (classesToMatch)
+ {
+ CFDictionarySetValue(classesToMatch, CFSTR(kIOSerialBSDTypeKey), CFSTR(kIOSerialBSDModemType));
+ kresult = IOServiceGetMatchingServices(kIOMasterPortDefault, classesToMatch, &serialPortIterator);
+ if (kresult == KERN_SUCCESS)
+ {
+ io_object_t serialService;
+ while ((serialService = IOIteratorNext(serialPortIterator)))
+ {
+ int iVendor = 0, iProduct = 0;
+ CFTypeRef bsdPathAsCFString;
+
+ // fetch the device path.
+ bsdPathAsCFString = IORegistryEntryCreateCFProperty(serialService,
+ CFSTR(kIOCalloutDeviceKey), kCFAllocatorDefault, 0);
+ if (bsdPathAsCFString)
+ {
+ // convert the path from a CFString to a C (NUL-terminated) string.
+ CFStringGetCString((CFStringRef)bsdPathAsCFString, bsdPath, MAXPATHLEN - 1, kCFStringEncodingUTF8);
+ CFRelease(bsdPathAsCFString);
+
+ // now walk up the hierarchy until we find the entry with vendor/product IDs
+ io_registry_entry_t parent;
+ CFTypeRef vendorIdAsCFNumber = NULL;
+ CFTypeRef productIdAsCFNumber = NULL;
+ kern_return_t kresult = IORegistryEntryGetParentEntry(serialService, kIOServicePlane, &parent);
+ while (kresult == KERN_SUCCESS)
+ {
+ vendorIdAsCFNumber = IORegistryEntrySearchCFProperty(parent,
+ kIOServicePlane, CFSTR(kUSBVendorID), kCFAllocatorDefault, 0);
+ productIdAsCFNumber = IORegistryEntrySearchCFProperty(parent,
+ kIOServicePlane, CFSTR(kUSBProductID), kCFAllocatorDefault, 0);
+ if (vendorIdAsCFNumber && productIdAsCFNumber)
+ {
+ CFNumberGetValue((CFNumberRef)vendorIdAsCFNumber, kCFNumberIntType, &iVendor);
+ CFRelease(vendorIdAsCFNumber);
+ CFNumberGetValue((CFNumberRef)productIdAsCFNumber, kCFNumberIntType, &iProduct);
+ CFRelease(productIdAsCFNumber);
+ IOObjectRelease(parent);
+ break;
+ }
+ io_registry_entry_t oldparent = parent;
+ kresult = IORegistryEntryGetParentEntry(parent, kIOServicePlane, &parent);
+ IOObjectRelease(oldparent);
+ }
+ if (strlen(bsdPath) && iVendor == CEC_VID && (iProduct == CEC_PID || iProduct == CEC_PID2))
+ {
+ if (!strDevicePath || !strcmp(bsdPath, strDevicePath))
+ {
+ // on darwin, the device path is the same as the comm path.
+ if (iFound == 0 || strcmp(deviceList[iFound - 1].strComName, bsdPath))
+ {
+ snprintf(deviceList[iFound].strComPath, sizeof(deviceList[iFound].strComPath), "%s", bsdPath);
+ snprintf(deviceList[iFound].strComName, sizeof(deviceList[iFound].strComName), "%s", bsdPath);
+ deviceList[iFound].iVendorId = iVendor;
+ deviceList[iFound].iProductId = iProduct;
+ deviceList[iFound].adapterType = ADAPTERTYPE_P8_EXTERNAL; // will be overridden when not doing a "quick scan" by the actual type
+ iFound++;
+ }
+ }
+ }
+ }
+ IOObjectRelease(serialService);
+ }
+ }
+ IOObjectRelease(serialPortIterator);
+ }
+#else
+ (void)deviceList;
+ (void)iBufSize;
+ (void)strDevicePath;
+#endif
+ return iFound;
+}
+
+uint8_t CUSBCECAdapterDetection::FindAdaptersUdev(cec_adapter_descriptor *deviceList, uint8_t iBufSize, const char *strDevicePath /* = NULL */)
+{
+ uint8_t iFound(0);
+
+#if defined(HAVE_LIBUDEV)
+ struct udev *udev;
+ if (!(udev = udev_new()))
+ return -1;
+
+ struct udev_enumerate *enumerate;
+ struct udev_list_entry *devices, *dev_list_entry;
+ struct udev_device *dev, *pdev;
+ enumerate = udev_enumerate_new(udev);
+ udev_enumerate_scan_devices(enumerate);
+ devices = udev_enumerate_get_list_entry(enumerate);
+ udev_list_entry_foreach(dev_list_entry, devices)
+ {
+ const char *strPath;
+ strPath = udev_list_entry_get_name(dev_list_entry);
+
+ dev = udev_device_new_from_syspath(udev, strPath);
+ if (!dev)
+ continue;
+
+ pdev = udev_device_get_parent(udev_device_get_parent(dev));
+ if (!pdev || !udev_device_get_sysattr_value(pdev, "idVendor") || !udev_device_get_sysattr_value(pdev, "idProduct"))
+ {
+ udev_device_unref(dev);
+ continue;
+ }
+
+ int iVendor, iProduct;
+ sscanf(udev_device_get_sysattr_value(pdev, "idVendor"), "%x", &iVendor);
+ sscanf(udev_device_get_sysattr_value(pdev, "idProduct"), "%x", &iProduct);
+ if (iVendor == CEC_VID && (iProduct == CEC_PID || iProduct == CEC_PID2))
+ {
+ std::string strPath(udev_device_get_syspath(pdev));
+ if (!strDevicePath || !strcmp(strPath.c_str(), strDevicePath))
+ {
+ std::string strComm(strPath);
+ if (FindComPort(strComm) && (iFound == 0 || strcmp(deviceList[iFound - 1].strComName, strComm.c_str())))
+ {
+ snprintf(deviceList[iFound].strComPath, sizeof(deviceList[iFound].strComPath), "%s", strPath.c_str());
+ snprintf(deviceList[iFound].strComName, sizeof(deviceList[iFound].strComName), "%s", strComm.c_str());
+ deviceList[iFound].iVendorId = iVendor;
+ deviceList[iFound].iProductId = iProduct;
+ deviceList[iFound].adapterType = ADAPTERTYPE_P8_EXTERNAL; // will be overridden when not doing a "quick scan" by the actual type
+ iFound++;
+ }
+ }
+ }
+ udev_device_unref(dev);
+
+ if (iFound >= iBufSize)
+ break;
+ }
+
+ udev_enumerate_unref(enumerate);
+ udev_unref(udev);
+#else
+ (void)deviceList;
+ (void)iBufSize;
+ (void)strDevicePath;
+#endif
+
+ return iFound;
+}
+
+uint8_t CUSBCECAdapterDetection::FindAdaptersFreeBSD(cec_adapter_descriptor *deviceList, uint8_t iBufSize, const char *strDevicePath /* = NULL */)
+{
+ uint8_t iFound(0);
+
+#if defined(__FreeBSD__)
+ char devicePath[PATH_MAX + 1];
+ char infos[512];
+ char sysctlname[32];
+ char ttyname[8];
+ char *pos;
+ size_t infos_size = sizeof(infos);
+ int i;
+
+ for (i = 0;; ++i)
+ {
+ unsigned int iVendor, iProduct;
+ memset(infos, 0, sizeof(infos));
+ (void)snprintf(sysctlname, sizeof(sysctlname),
+ "dev.umodem.%d.%%pnpinfo", i);
+ if (sysctlbyname(sysctlname, infos, &infos_size,
+ NULL, 0) != 0)
+ break;
+ pos = strstr(infos, "vendor=");
+ if (pos == NULL)
+ continue;
+ sscanf(pos, "vendor=%x ", &iVendor);
+
+ pos = strstr(infos, "product=");
+ if (pos == NULL)
+ continue;
+ sscanf(pos, "product=%x ", &iProduct);
+
+ if (iVendor != CEC_VID || (iProduct != CEC_PID && iProduct != CEC_PID2))
+ continue;
+
+ pos = strstr(infos, "ttyname=");
+ if (pos == NULL)
+ continue;
+ sscanf(pos, "ttyname=%s ", ttyname);
+
+ (void)snprintf(devicePath, sizeof(devicePath),
+ "/dev/tty%s", ttyname);
+
+ if (strDevicePath) {
+ char currStrDevicePath[512];
+ int port = 0;
+ int devaddr = 0;
+ memset(currStrDevicePath, 0, sizeof(currStrDevicePath));
+ memset(infos, 0, sizeof(infos));
+ (void)snprintf(sysctlname, sizeof(sysctlname),
+ "dev.umodem.%d.%%location", i);
+ if (sysctlbyname(sysctlname, infos, &infos_size,
+ NULL, 0) != 0)
+ break;
+
+ pos = strstr(infos, "port=");
+ if (pos == NULL)
+ continue;
+ sscanf(pos, "port=%d ", &port);
+
+ pos = strstr(infos, "devaddr=");
+ if (pos == NULL)
+ continue;
+ sscanf(pos, "devaddr=%d ", &devaddr);
+
+ (void)snprintf(currStrDevicePath, sizeof(currStrDevicePath),
+ "/dev/ugen%d.%d", port, devaddr);
+
+ if (strcmp(currStrDevicePath, strDevicePath) != 0)
+ continue;
+ }
+ snprintf(deviceList[iFound].strComPath, sizeof(deviceList[iFound].strComPath), "%s", devicePath);
+ snprintf(deviceList[iFound].strComName, sizeof(deviceList[iFound].strComName), "%s", devicePath);
+ deviceList[iFound].iVendorId = iVendor;
+ deviceList[iFound].iProductId = iProduct;
+ deviceList[iFound].adapterType = ADAPTERTYPE_P8_EXTERNAL; // will be overridden when not doing a "quick scan" by the actual type
+ iFound++;
+ }
+#else
+ (void)deviceList;
+ (void)iBufSize;
+ (void)strDevicePath;
+#endif
+
+ return iFound;
+}
+
+uint8_t CUSBCECAdapterDetection::FindAdapters(cec_adapter_descriptor *deviceList, uint8_t iBufSize, const char *strDevicePath /* = NULL */)
+{
+ uint8_t iFound(0);
+ iFound = FindAdaptersApple(deviceList, iBufSize, strDevicePath);
+ if (iFound == 0)
+ iFound = FindAdaptersFreeBSD(deviceList, iBufSize, strDevicePath);
+ if (iFound == 0)
+ iFound = FindAdaptersUdev(deviceList, iBufSize, strDevicePath);
+ if (iFound == 0)
+ iFound = FindAdaptersWindows(deviceList, iBufSize, strDevicePath);
+ return iFound;
+}
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+
+namespace CEC
+{
+ #define CEC_VID 0x2548
+ #define CEC_PID 0x1001
+ #define CEC_PID2 0x1002
+
+ class CUSBCECAdapterDetection
+ {
+ public:
+ static uint8_t FindAdapters(cec_adapter_descriptor *deviceList, uint8_t iBufSize, const char *strDevicePath = NULL);
+ static bool CanAutodetect(void);
+
+ private:
+ static uint8_t FindAdaptersWindows(cec_adapter_descriptor *deviceList, uint8_t iBufSize, const char *strDevicePath = NULL);
+ static uint8_t FindAdaptersApple(cec_adapter_descriptor *deviceList, uint8_t iBufSize, const char *strDevicePath = NULL);
+ static uint8_t FindAdaptersUdev(cec_adapter_descriptor *deviceList, uint8_t iBufSize, const char *strDevicePath = NULL);
+ static uint8_t FindAdaptersFreeBSD(cec_adapter_descriptor *deviceList, uint8_t iBufSize, const char *strDevicePath = NULL);
+ };
+};
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include "USBCECAdapterMessage.h"
+
+#include "LibCEC.h"
+
+using namespace CEC;
+using namespace P8PLATFORM;
+
+CCECAdapterMessage::CCECAdapterMessage(void)
+{
+ Clear();
+}
+
+CCECAdapterMessage::CCECAdapterMessage(const cec_command &command, uint8_t iLineTimeout /* = 3 */)
+{
+ Clear();
+
+ //set ack polarity to high when transmitting to the broadcast address
+ //set ack polarity low when transmitting to any other address
+ PushBack(MSGSTART);
+ PushEscaped(MSGCODE_TRANSMIT_ACK_POLARITY);
+ if (command.destination == CECDEVICE_BROADCAST)
+ PushEscaped(CEC_TRUE);
+ else
+ PushEscaped(CEC_FALSE);
+ PushBack(MSGEND);
+
+ // add source and destination
+ PushBack(MSGSTART);
+ PushEscaped(command.opcode_set == 0 ? (uint8_t)MSGCODE_TRANSMIT_EOM : (uint8_t)MSGCODE_TRANSMIT);
+ PushBack(((uint8_t)command.initiator << 4) + (uint8_t)command.destination);
+ PushBack(MSGEND);
+
+ // add opcode
+ if (command.opcode_set == 1)
+ {
+ PushBack(MSGSTART);
+ PushEscaped(command.parameters.IsEmpty() ? (uint8_t)MSGCODE_TRANSMIT_EOM : (uint8_t)MSGCODE_TRANSMIT);
+ PushBack((uint8_t) command.opcode);
+ PushBack(MSGEND);
+
+ // add parameters
+ for (int8_t iPtr = 0; iPtr < command.parameters.size; iPtr++)
+ {
+ PushBack(MSGSTART);
+
+ if (iPtr == command.parameters.size - 1)
+ PushEscaped( MSGCODE_TRANSMIT_EOM);
+ else
+ PushEscaped(MSGCODE_TRANSMIT);
+
+ PushEscaped(command.parameters[iPtr]);
+
+ PushBack(MSGEND);
+ }
+ }
+
+ // set timeout
+ transmit_timeout = command.transmit_timeout;
+
+ lineTimeout = iLineTimeout;
+}
+
+std::string CCECAdapterMessage::ToString(void) const
+{
+ std::string strMsg;
+ if (Size() == 0)
+ {
+ strMsg = "empty message";
+ }
+ else
+ {
+ strMsg = ToString(Message());
+
+ switch (Message())
+ {
+ case MSGCODE_TIMEOUT_ERROR:
+ case MSGCODE_HIGH_ERROR:
+ case MSGCODE_LOW_ERROR:
+ {
+ uint32_t iLine = (Size() >= 4) ? (At(2) << 8) | At(3) : 0;
+ uint32_t iTime = (Size() >= 8) ? (At(4) << 24) | (At(5) << 16) | (At(6) << 8) | At(7) : 0;
+ strMsg += StringUtils::Format(" line:%u", iLine);
+ strMsg += StringUtils::Format(" time:%u", iTime);
+ }
+ break;
+ case MSGCODE_FRAME_START:
+ if (Size() >= 3)
+ strMsg += StringUtils::Format(" initiator:%1x destination:%1x ack:%s %s", Initiator(), Destination(), IsACK() ? "high" : "low", IsEOM() ? "eom" : "");
+ break;
+ case MSGCODE_FRAME_DATA:
+ if (Size() >= 3)
+ strMsg += StringUtils::Format(" %02x %s", At(2), IsEOM() ? "eom" : "");
+ break;
+ default:
+ if (Size() >= 2 && (Message() == MSGCODE_COMMAND_ACCEPTED || Message() == MSGCODE_COMMAND_REJECTED))
+ strMsg += StringUtils::Format(": %s", ToString((cec_adapter_messagecode)At(2)));
+ else
+ {
+ for (uint8_t iPtr = 2; iPtr < Size(); iPtr++)
+ if (At(iPtr) != MSGEND)
+ strMsg += StringUtils::Format(" %02x", At(iPtr));
+ }
+ break;
+ }
+ }
+
+ return std::string(strMsg.c_str());
+}
+
+const char *CCECAdapterMessage::ToString(cec_adapter_messagecode msgCode)
+{
+ switch (msgCode)
+ {
+ case MSGCODE_NOTHING:
+ return "NOTHING";
+ case MSGCODE_PING:
+ return "PING";
+ case MSGCODE_TIMEOUT_ERROR:
+ return "TIMEOUT";
+ case MSGCODE_HIGH_ERROR:
+ return "HIGH_ERROR";
+ case MSGCODE_LOW_ERROR:
+ return "LOW_ERROR";
+ case MSGCODE_FRAME_START:
+ return "FRAME_START";
+ case MSGCODE_FRAME_DATA:
+ return "FRAME_DATA";
+ case MSGCODE_RECEIVE_FAILED:
+ return "RECEIVE_FAILED";
+ case MSGCODE_COMMAND_ACCEPTED:
+ return "COMMAND_ACCEPTED";
+ case MSGCODE_COMMAND_REJECTED:
+ return "COMMAND_REJECTED";
+ case MSGCODE_SET_ACK_MASK:
+ return "SET_ACK_MASK";
+ case MSGCODE_TRANSMIT:
+ return "TRANSMIT";
+ case MSGCODE_TRANSMIT_EOM:
+ return "TRANSMIT_EOM";
+ case MSGCODE_TRANSMIT_IDLETIME:
+ return "TRANSMIT_IDLETIME";
+ case MSGCODE_TRANSMIT_ACK_POLARITY:
+ return "CEC transmission";
+ case MSGCODE_TRANSMIT_LINE_TIMEOUT:
+ return "TRANSMIT_LINE_TIMEOUT";
+ case MSGCODE_TRANSMIT_SUCCEEDED:
+ return "TRANSMIT_SUCCEEDED";
+ case MSGCODE_TRANSMIT_FAILED_LINE:
+ return "TRANSMIT_FAILED_LINE";
+ case MSGCODE_TRANSMIT_FAILED_ACK:
+ return "TRANSMIT_FAILED_ACK";
+ case MSGCODE_TRANSMIT_FAILED_TIMEOUT_DATA:
+ return "TRANSMIT_FAILED_TIMEOUT_DATA";
+ case MSGCODE_TRANSMIT_FAILED_TIMEOUT_LINE:
+ return "TRANSMIT_FAILED_TIMEOUT_LINE";
+ case MSGCODE_FIRMWARE_VERSION:
+ return "FIRMWARE_VERSION";
+ case MSGCODE_START_BOOTLOADER:
+ return "START_BOOTLOADER";
+ case MSGCODE_FRAME_EOM:
+ return "FRAME_EOM";
+ case MSGCODE_FRAME_ACK:
+ return "FRAME_ACK";
+ case MSGCODE_GET_BUILDDATE:
+ return "GET_BUILDDATE";
+ case MSGCODE_SET_CONTROLLED:
+ return "SET_CONTROLLED";
+ case MSGCODE_GET_AUTO_ENABLED:
+ return "GET_AUTO_ENABLED";
+ case MSGCODE_SET_AUTO_ENABLED:
+ return "SET_AUTO_ENABLED";
+ case MSGCODE_GET_DEFAULT_LOGICAL_ADDRESS:
+ return "GET_DEFAULT_LOGICAL_ADDRESS";
+ case MSGCODE_SET_DEFAULT_LOGICAL_ADDRESS:
+ return "SET_DEFAULT_LOGICAL_ADDRESS";
+ case MSGCODE_GET_LOGICAL_ADDRESS_MASK:
+ return "GET_LOGICAL_ADDRESS_MASK";
+ case MSGCODE_SET_LOGICAL_ADDRESS_MASK:
+ return "SET_LOGICAL_ADDRESS_MASK";
+ case MSGCODE_GET_PHYSICAL_ADDRESS:
+ return "GET_PHYSICAL_ADDRESS";
+ case MSGCODE_SET_PHYSICAL_ADDRESS:
+ return "SET_PHYSICAL_ADDRESS";
+ case MSGCODE_GET_DEVICE_TYPE:
+ return "GET_DEVICE_TYPE";
+ case MSGCODE_SET_DEVICE_TYPE:
+ return "SET_DEVICE_TYPE";
+ case MSGCODE_GET_HDMI_VERSION:
+ return "GET_HDMI_VERSION";
+ case MSGCODE_SET_HDMI_VERSION:
+ return "SET_HDMI_VERSION";
+ case MSGCODE_GET_OSD_NAME:
+ return "GET_OSD_NAME";
+ case MSGCODE_SET_OSD_NAME:
+ return "SET_OSD_NAME";
+ case MSGCODE_WRITE_EEPROM:
+ return "WRITE_EEPROM";
+ case MSGCODE_GET_ADAPTER_TYPE:
+ return "GET_ADAPTER_TYPE";
+ default:
+ break;
+ }
+
+ return "unknown";
+}
+
+uint8_t CCECAdapterMessage::operator[](uint8_t pos) const
+{
+ return pos < packet.size ? packet[pos] : 0;
+}
+
+uint8_t CCECAdapterMessage::At(uint8_t pos) const
+{
+ return pos < packet.size ? packet[pos] : 0;
+}
+
+uint8_t CCECAdapterMessage::Size(void) const
+{
+ return packet.size;
+}
+
+bool CCECAdapterMessage::IsEmpty(void) const
+{
+ return packet.IsEmpty();
+}
+
+void CCECAdapterMessage::Clear(void)
+{
+ state = ADAPTER_MESSAGE_STATE_UNKNOWN;
+ transmit_timeout = CEC_DEFAULT_TRANSMIT_TIMEOUT;
+ response.Clear();
+ packet.Clear();
+ lineTimeout = 3;
+ bNextByteIsEscaped = false;
+ bFireAndForget = false;
+}
+
+void CCECAdapterMessage::Shift(uint8_t iShiftBy)
+{
+ packet.Shift(iShiftBy);
+}
+
+void CCECAdapterMessage::Append(CCECAdapterMessage &data)
+{
+ Append(data.packet);
+}
+
+void CCECAdapterMessage::Append(cec_datapacket &data)
+{
+ for (uint8_t iPtr = 0; iPtr < data.size; iPtr++)
+ PushBack(data[iPtr]);
+}
+
+void CCECAdapterMessage::PushBack(uint8_t byte)
+{
+ packet.PushBack(byte);
+}
+
+void CCECAdapterMessage::PushEscaped(uint8_t byte)
+{
+ if (byte >= MSGESC)
+ {
+ PushBack(MSGESC);
+ PushBack(byte - ESCOFFSET);
+ }
+ else
+ {
+ PushBack(byte);
+ }
+}
+
+bool CCECAdapterMessage::PushReceivedByte(uint8_t byte)
+{
+ if (byte == MSGSTART)
+ {
+ if (HasStartMessage())
+ {
+ //TODO CLibCEC::AddLog(CEC_LOG_WARNING, "received MSGSTART before MSGEND, removing previous buffer contents");
+ Clear();
+ }
+ PushBack(byte);
+ }
+ else
+ {
+ if (bNextByteIsEscaped)
+ {
+ PushBack(byte + (uint8_t)ESCOFFSET);
+ bNextByteIsEscaped = false;
+ }
+ else if (byte == MSGESC)
+ bNextByteIsEscaped = true;
+ else
+ PushBack(byte);
+ }
+
+ return byte == MSGEND;
+}
+
+cec_adapter_messagecode CCECAdapterMessage::Message(void) const
+{
+ return packet.size >= 2 ?
+ (cec_adapter_messagecode) (packet.At(1) & ~(MSGCODE_FRAME_EOM | MSGCODE_FRAME_ACK)) :
+ MSGCODE_NOTHING;
+}
+
+cec_adapter_messagecode CCECAdapterMessage::ResponseTo(void) const
+{
+ return packet.size >= 3 ?
+ (cec_adapter_messagecode) (packet.At(2) & ~(MSGCODE_FRAME_EOM | MSGCODE_FRAME_ACK)) :
+ MSGCODE_NOTHING;
+}
+
+bool CCECAdapterMessage::IsTransmission(void) const
+{
+ cec_adapter_messagecode msgCode = Message();
+ return msgCode == MSGCODE_FRAME_ACK ||
+ msgCode == MSGCODE_FRAME_DATA ||
+ msgCode == MSGCODE_FRAME_EOM ||
+ msgCode == MSGCODE_FRAME_START ||
+ msgCode == MSGCODE_HIGH_ERROR ||
+ msgCode == MSGCODE_LOW_ERROR ||
+ msgCode == MSGCODE_RECEIVE_FAILED ||
+ msgCode == MSGCODE_TRANSMIT_ACK_POLARITY ||
+ msgCode == MSGCODE_TRANSMIT_EOM ||
+ msgCode == MSGCODE_TRANSMIT_FAILED_ACK ||
+ msgCode == MSGCODE_TRANSMIT_FAILED_LINE ||
+ msgCode == MSGCODE_TRANSMIT_FAILED_TIMEOUT_DATA ||
+ msgCode == MSGCODE_TRANSMIT_FAILED_TIMEOUT_LINE ||
+ msgCode == MSGCODE_TRANSMIT_LINE_TIMEOUT ||
+ msgCode == MSGCODE_TRANSMIT_SUCCEEDED;
+}
+
+bool CCECAdapterMessage::IsEOM(void) const
+{
+ return packet.size >= 2 ?
+ (packet.At(1) & MSGCODE_FRAME_EOM) != 0 :
+ false;
+}
+
+bool CCECAdapterMessage::IsACK(void) const
+{
+ return packet.size >= 2 ?
+ (packet.At(1) & MSGCODE_FRAME_ACK) != 0 :
+ false;
+}
+
+bool CCECAdapterMessage::MessageCodeIsError(const cec_adapter_messagecode code)
+{
+ return (code == MSGCODE_HIGH_ERROR ||
+ code == MSGCODE_LOW_ERROR ||
+ code == MSGCODE_RECEIVE_FAILED ||
+ code == MSGCODE_COMMAND_REJECTED ||
+ code == MSGCODE_TRANSMIT_LINE_TIMEOUT ||
+ code == MSGCODE_TRANSMIT_FAILED_LINE ||
+ code == MSGCODE_TRANSMIT_FAILED_ACK ||
+ code == MSGCODE_TRANSMIT_FAILED_TIMEOUT_DATA ||
+ code == MSGCODE_TRANSMIT_FAILED_TIMEOUT_LINE);
+}
+
+bool CCECAdapterMessage::IsError(void) const
+{
+ return MessageCodeIsError(Message());
+}
+
+bool CCECAdapterMessage::ReplyIsError(void) const
+{
+ return MessageCodeIsError(Reply());
+}
+
+bool CCECAdapterMessage::NeedsRetry(void) const
+{
+ return Reply() == MSGCODE_NOTHING ||
+ Reply() == MSGCODE_RECEIVE_FAILED ||
+ Reply() == MSGCODE_TIMEOUT_ERROR ||
+ Reply() == MSGCODE_TRANSMIT_FAILED_LINE ||
+ Reply() == MSGCODE_TRANSMIT_FAILED_TIMEOUT_DATA ||
+ Reply() == MSGCODE_TRANSMIT_FAILED_TIMEOUT_LINE ||
+ Reply() == MSGCODE_TRANSMIT_LINE_TIMEOUT;
+}
+
+cec_logical_address CCECAdapterMessage::Initiator(void) const
+{
+ return packet.size >= 3 ?
+ (cec_logical_address) (packet.At(2) >> 4) :
+ CECDEVICE_UNKNOWN;
+}
+
+cec_logical_address CCECAdapterMessage::Destination(void) const
+{
+ return packet.size >= 3 ?
+ (cec_logical_address) (packet.At(2) & 0xF) :
+ CECDEVICE_UNKNOWN;
+}
+
+bool CCECAdapterMessage::HasStartMessage(void) const
+{
+ return packet.size >= 1 && packet.At(0) == MSGSTART;
+}
+
+bool CCECAdapterMessage::PushToCecCommand(cec_command &command) const
+{
+ // empty message
+ if (IsEmpty())
+ return false;
+
+ cec_adapter_messagecode msgCode = Message();
+ if (msgCode == MSGCODE_FRAME_START)
+ {
+ command.Clear();
+ if (Size() >= 3)
+ {
+ command.initiator = Initiator();
+ command.destination = Destination();
+ command.ack = IsACK();
+ command.eom = IsEOM();
+ }
+ return IsEOM() && !IsError();
+ }
+ else if (msgCode == MSGCODE_FRAME_DATA)
+ {
+ if (Size() >= 3)
+ {
+ command.PushBack(At(2));
+ command.eom = IsEOM();
+ }
+ return IsEOM() && !IsError();
+ }
+
+ return false;
+}
+
+cec_adapter_messagecode CCECAdapterMessage::Reply(void) const
+{
+ return response.size >= 2 ?
+ (cec_adapter_messagecode) (response.At(1) & ~(MSGCODE_FRAME_EOM | MSGCODE_FRAME_ACK)) :
+ MSGCODE_NOTHING;
+}
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include "adapter/AdapterCommunication.h"
+
+namespace CEC
+{
+ typedef enum cec_adapter_messagecode
+ {
+ MSGCODE_NOTHING = 0,
+ MSGCODE_PING,
+ MSGCODE_TIMEOUT_ERROR,
+ MSGCODE_HIGH_ERROR,
+ MSGCODE_LOW_ERROR,
+ MSGCODE_FRAME_START,
+ MSGCODE_FRAME_DATA,
+ MSGCODE_RECEIVE_FAILED,
+ MSGCODE_COMMAND_ACCEPTED,
+ MSGCODE_COMMAND_REJECTED,
+ MSGCODE_SET_ACK_MASK,
+ MSGCODE_TRANSMIT,
+ MSGCODE_TRANSMIT_EOM,
+ MSGCODE_TRANSMIT_IDLETIME,
+ MSGCODE_TRANSMIT_ACK_POLARITY,
+ MSGCODE_TRANSMIT_LINE_TIMEOUT,
+ MSGCODE_TRANSMIT_SUCCEEDED,
+ MSGCODE_TRANSMIT_FAILED_LINE,
+ MSGCODE_TRANSMIT_FAILED_ACK,
+ MSGCODE_TRANSMIT_FAILED_TIMEOUT_DATA,
+ MSGCODE_TRANSMIT_FAILED_TIMEOUT_LINE,
+ MSGCODE_FIRMWARE_VERSION,
+ MSGCODE_START_BOOTLOADER,
+ MSGCODE_GET_BUILDDATE,
+ MSGCODE_SET_CONTROLLED,
+ MSGCODE_GET_AUTO_ENABLED,
+ MSGCODE_SET_AUTO_ENABLED,
+ MSGCODE_GET_DEFAULT_LOGICAL_ADDRESS,
+ MSGCODE_SET_DEFAULT_LOGICAL_ADDRESS,
+ MSGCODE_GET_LOGICAL_ADDRESS_MASK,
+ MSGCODE_SET_LOGICAL_ADDRESS_MASK,
+ MSGCODE_GET_PHYSICAL_ADDRESS,
+ MSGCODE_SET_PHYSICAL_ADDRESS,
+ MSGCODE_GET_DEVICE_TYPE,
+ MSGCODE_SET_DEVICE_TYPE,
+ MSGCODE_GET_HDMI_VERSION,
+ MSGCODE_SET_HDMI_VERSION,
+ MSGCODE_GET_OSD_NAME,
+ MSGCODE_SET_OSD_NAME,
+ MSGCODE_WRITE_EEPROM,
+ MSGCODE_GET_ADAPTER_TYPE,
+ MSGCODE_SET_ACTIVE_SOURCE,
+
+ MSGCODE_FRAME_EOM = 0x80,
+ MSGCODE_FRAME_ACK = 0x40,
+ } cec_adapter_messagecode;
+
+ typedef enum p8_cec_adapter_type
+ {
+ P8_ADAPTERTYPE_UNKNOWN = 0,
+ P8_ADAPTERTYPE_EXTERNAL,
+ P8_ADAPTERTYPE_DAUGHTERBOARD,
+ } p8_cec_adapter_type;
+
+ class CCECAdapterMessage
+ {
+ public:
+ /*!
+ * @brief Create an empty message.
+ */
+ CCECAdapterMessage(void);
+
+ /*!
+ * @brief Create a message with a command that is to be transmitted over the CEC line.
+ * @param command The command to transmit.
+ * @param iLineTimeout The line timeout to use when sending this message.
+ */
+ CCECAdapterMessage(const cec_command &command, uint8_t iLineTimeout = 3);
+
+ /*!
+ * @return the message as human readable string.
+ */
+ std::string ToString(void) const;
+
+ /*!
+ * @brief Translate the messagecode into a human readable string.
+ * @param msgCode The messagecode to translate.
+ * @return The messagecode as string.
+ */
+ static const char *ToString(cec_adapter_messagecode msgCode);
+
+ /*!
+ * @brief Get the byte at the given position.
+ * @param pos The position to get.
+ * @return The requested byte, or 0 when it's out of range.
+ */
+ uint8_t At(uint8_t pos) const;
+ uint8_t operator[](uint8_t pos) const;
+
+ /*!
+ * @return The size of the packet in bytes.
+ */
+ uint8_t Size(void) const;
+
+ /*!
+ * @return True when empty, false otherwise.
+ */
+ bool IsEmpty(void) const;
+
+ /*!
+ * @brief Clear this message and reset everything to the initial values.
+ */
+ void Clear(void);
+
+ /*!
+ * @brief Shift the message by the given number of bytes.
+ * @param iShiftBy The number of bytes to shift.
+ */
+ void Shift(uint8_t iShiftBy);
+
+ /*!
+ * @brief Append the given message to this message.
+ * @param data The message to append.
+ */
+ void Append(CCECAdapterMessage &data);
+
+ /*!
+ * @brief Append the given datapacket to this message.
+ * @param data The packet to add.
+ */
+ void Append(cec_datapacket &data);
+
+ /*!
+ * @brief Adds a byte to this message. Does not escape the byte.
+ * @param byte The byte to add.
+ */
+ void PushBack(uint8_t byte);
+
+ /*!
+ * @brief Adds a byte to this message and escapes the byte if needed.
+ * @param byte The byte to add.
+ */
+ void PushEscaped(uint8_t byte);
+
+ /*!
+ * @brief Adds a byte to this message.
+ * @param byte The byte to add.
+ * @return True when a full message was received, false otherwise.
+ */
+ bool PushReceivedByte(uint8_t byte);
+
+ /*!
+ * @return The messagecode inside this adapter message, or MSGCODE_NOTHING if there is none.
+ */
+ cec_adapter_messagecode Message(void) const;
+
+ /*!
+ * @return The messagecode (if provided) that this message is responding to
+ */
+ cec_adapter_messagecode ResponseTo(void) const;
+
+ /*!
+ * @return True when this message is a transmission, false otherwise.
+ */
+ bool IsTransmission(void) const;
+
+ /*!
+ * @return True when the EOM bit is set, false otherwise.
+ */
+ bool IsEOM(void) const;
+
+ /*!
+ * @return True when the ACK bit is set, false otherwise.
+ */
+ bool IsACK(void) const;
+
+ /*!
+ * @brief Checks whether the given messagecode is an error message.
+ * @param code The code to check.
+ * @return True when it's an error, false otherwise.
+ */
+ static bool MessageCodeIsError(const cec_adapter_messagecode code);
+
+ /*!
+ * @return True when this message contains an error code, false otherwise.
+ */
+ bool IsError(void) const;
+
+ /*!
+ * @return True when this message has been replied with an error code, false otherwise.
+ */
+ bool ReplyIsError(void) const;
+
+ /*!
+ * @return True when this message has been replied with an error code and needs to be retried, false otherwise.
+ */
+ bool NeedsRetry(void) const;
+
+ /*!
+ * @return The logical address of the initiator, or CECDEVICE_UNKNOWN if unknown.
+ */
+ cec_logical_address Initiator(void) const;
+
+ /*!
+ * @return The logical address of the destination, or CECDEVICE_UNKNOWN if unknown.
+ */
+ cec_logical_address Destination(void) const;
+
+ /*!
+ * @return True when this message contains a start message, false otherwise.
+ */
+ bool HasStartMessage(void) const;
+
+ /*!
+ * @brief Push this adapter message to the end of the given cec_command.
+ * @param command The command to push this message to.
+ * @return True when a full CEC message was received, false otherwise.
+ */
+ bool PushToCecCommand(cec_command &command) const;
+
+ /*!
+ * @return The response messagecode.
+ */
+ cec_adapter_messagecode Reply(void) const;
+
+ cec_datapacket response; /**< the response to this message */
+ cec_datapacket packet; /**< the actual data */
+ cec_adapter_message_state state; /**< the current state of this message */
+ int32_t transmit_timeout; /**< the timeout to use when sending this message */
+ uint8_t lineTimeout; /**< the default CEC line timeout to use when sending this message */
+ bool bFireAndForget; /**< true to auto delete, don't wait for a response */
+
+ private:
+ bool bNextByteIsEscaped; /**< true when the next byte that is added will be escaped, false otherwise */
+ };
+}
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include "USBCECAdapterMessageQueue.h"
+
+#include "USBCECAdapterCommunication.h"
+#include "USBCECAdapterMessage.h"
+#include <p8-platform/sockets/socket.h>
+#include "LibCEC.h"
+
+using namespace CEC;
+using namespace P8PLATFORM;
+
+#define MESSAGE_QUEUE_SIGNAL_WAIT_TIME 1000
+
+CCECAdapterMessageQueueEntry::CCECAdapterMessageQueueEntry(CCECAdapterMessageQueue *queue, CCECAdapterMessage *message) :
+ m_queue(queue),
+ m_message(message),
+ m_iPacketsLeft(message->IsTransmission() ? message->Size() / 4 : 1),
+ m_bSucceeded(false),
+ m_bWaiting(true),
+ m_queueTimeout(message->transmit_timeout) {}
+
+CCECAdapterMessageQueueEntry::~CCECAdapterMessageQueueEntry(void) { }
+
+void CCECAdapterMessageQueueEntry::Broadcast(void)
+{
+ CLockObject lock(m_mutex);
+ m_condition.Broadcast();
+}
+
+bool CCECAdapterMessageQueueEntry::MessageReceived(const CCECAdapterMessage &message)
+{
+ bool bHandled(false);
+
+ if (IsResponse(message))
+ {
+ switch (message.Message())
+ {
+ case MSGCODE_COMMAND_ACCEPTED:
+ bHandled = MessageReceivedCommandAccepted(message);
+ break;
+ case MSGCODE_TRANSMIT_SUCCEEDED:
+ bHandled = MessageReceivedTransmitSucceeded(message);
+ break;
+ default:
+ bHandled = MessageReceivedResponse(message);
+ break;
+ }
+ }
+
+ return bHandled;
+}
+
+void CCECAdapterMessageQueueEntry::Signal(void)
+{
+ CLockObject lock(m_mutex);
+ m_bSucceeded = true;
+ m_condition.Signal();
+}
+
+bool CCECAdapterMessageQueueEntry::Wait(uint32_t iTimeout)
+{
+ bool bReturn(false);
+ /* wait until we receive a signal when the tranmission succeeded */
+ {
+ CLockObject lock(m_mutex);
+ bReturn = m_bSucceeded ? true : m_condition.Wait(m_mutex, m_bSucceeded, iTimeout);
+ m_bWaiting = false;
+ }
+ return bReturn;
+}
+
+bool CCECAdapterMessageQueueEntry::IsWaiting(void)
+{
+ CLockObject lock(m_mutex);
+ return m_bWaiting;
+}
+
+cec_adapter_messagecode CCECAdapterMessageQueueEntry::MessageCode(void)
+{
+ return m_message->Message();
+}
+
+bool CCECAdapterMessageQueueEntry::IsResponseOld(const CCECAdapterMessage &msg)
+{
+ cec_adapter_messagecode msgCode = msg.Message();
+
+ return msgCode == MessageCode() ||
+ msgCode == MSGCODE_COMMAND_ACCEPTED ||
+ msgCode == MSGCODE_COMMAND_REJECTED ||
+ (m_message->IsTransmission() && (msgCode == MSGCODE_TIMEOUT_ERROR ||
+ msgCode == MSGCODE_HIGH_ERROR ||
+ msgCode == MSGCODE_LOW_ERROR ||
+ msgCode == MSGCODE_RECEIVE_FAILED ||
+ msgCode == MSGCODE_TRANSMIT_FAILED_LINE ||
+ msgCode == MSGCODE_TRANSMIT_FAILED_ACK ||
+ msgCode == MSGCODE_TRANSMIT_FAILED_TIMEOUT_DATA ||
+ msgCode == MSGCODE_TRANSMIT_FAILED_TIMEOUT_LINE ||
+ msgCode == MSGCODE_TRANSMIT_SUCCEEDED));
+}
+
+bool CCECAdapterMessageQueueEntry::IsResponse(const CCECAdapterMessage &msg)
+{
+ if (m_message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED)
+ return false;
+
+ cec_adapter_messagecode thisMsgCode = m_message->Message();
+ cec_adapter_messagecode msgCode = msg.Message();
+ cec_adapter_messagecode msgResponse = msg.ResponseTo();
+
+ // msgcode matches, always a response
+ if (msgCode == MessageCode())
+ return true;
+
+ if (!ProvidesExtendedResponse())
+ return IsResponseOld(msg);
+
+ // response without a msgcode
+ if (msgResponse == MSGCODE_NOTHING)
+ return false;
+
+ // commands that only repond with accepted/rejected
+ if (thisMsgCode == MSGCODE_PING ||
+ thisMsgCode == MSGCODE_SET_ACK_MASK ||
+ thisMsgCode == MSGCODE_SET_CONTROLLED ||
+ thisMsgCode == MSGCODE_SET_AUTO_ENABLED ||
+ thisMsgCode == MSGCODE_SET_DEFAULT_LOGICAL_ADDRESS ||
+ thisMsgCode == MSGCODE_SET_LOGICAL_ADDRESS_MASK ||
+ thisMsgCode == MSGCODE_SET_PHYSICAL_ADDRESS ||
+ thisMsgCode == MSGCODE_SET_DEVICE_TYPE ||
+ thisMsgCode == MSGCODE_SET_HDMI_VERSION ||
+ thisMsgCode == MSGCODE_SET_OSD_NAME ||
+ thisMsgCode == MSGCODE_WRITE_EEPROM ||
+ thisMsgCode == MSGCODE_TRANSMIT_IDLETIME ||
+ thisMsgCode == MSGCODE_SET_ACTIVE_SOURCE)
+ return thisMsgCode == msgResponse;
+
+ if (!m_message->IsTransmission())
+ return false;
+
+ return ((msgCode == MSGCODE_COMMAND_ACCEPTED || msgCode == MSGCODE_COMMAND_REJECTED) &&
+ (msgResponse == MSGCODE_TRANSMIT_ACK_POLARITY || msgResponse == MSGCODE_TRANSMIT || msgResponse == MSGCODE_TRANSMIT_EOM)) ||
+ msgCode == MSGCODE_TIMEOUT_ERROR ||
+ msgCode == MSGCODE_RECEIVE_FAILED ||
+ msgCode == MSGCODE_TRANSMIT_FAILED_ACK ||
+ msgCode == MSGCODE_TRANSMIT_FAILED_TIMEOUT_DATA ||
+ msgCode == MSGCODE_TRANSMIT_FAILED_TIMEOUT_LINE ||
+ msgCode == MSGCODE_TRANSMIT_SUCCEEDED;
+}
+
+const char *CCECAdapterMessageQueueEntry::ToString(void) const
+{
+ /* CEC transmissions got the 'set ack polarity' msgcode, which doesn't look nice */
+ if (m_message->IsTransmission())
+ return "CEC transmission";
+ else
+ return CCECAdapterMessage::ToString(m_message->Message());
+}
+
+bool CCECAdapterMessageQueueEntry::MessageReceivedCommandAccepted(const CCECAdapterMessage &message)
+{
+ bool bSendSignal(false);
+ bool bHandled(false);
+ {
+ CLockObject lock(m_mutex);
+ if (m_iPacketsLeft > 0)
+ {
+ /* decrease by 1 */
+ m_iPacketsLeft--;
+
+#ifdef CEC_DEBUGGING
+ /* log this message */
+ std::string strLog;
+ strLog = StringUtils::Format("%s - command accepted", ToString());
+ if (m_iPacketsLeft > 0)
+ strLog += StringUtils::Format(" - waiting for %d more", m_iPacketsLeft);
+ m_queue->m_com->m_callback->GetLib()->AddLog(CEC_LOG_DEBUG, "%s", strLog.c_str());
+#endif
+
+ /* no more packets left and not a transmission, so we're done */
+ if (!m_message->IsTransmission() && m_iPacketsLeft == 0)
+ {
+ m_message->state = ADAPTER_MESSAGE_STATE_SENT_ACKED;
+ m_message->response = message.packet;
+ bSendSignal = true;
+ }
+ bHandled = true;
+ }
+ }
+
+ if (bSendSignal)
+ Signal();
+
+ return bHandled;
+}
+
+bool CCECAdapterMessageQueueEntry::MessageReceivedTransmitSucceeded(const CCECAdapterMessage &message)
+{
+ {
+ CLockObject lock(m_mutex);
+ if (m_iPacketsLeft == 0)
+ {
+ /* transmission succeeded, so we're done */
+#ifdef CEC_DEBUGGING
+ m_queue->m_com->m_callback->GetLib()->AddLog(CEC_LOG_DEBUG, "%s - transmit succeeded", m_message->ToString().c_str());
+#endif
+ m_message->state = ADAPTER_MESSAGE_STATE_SENT_ACKED;
+ m_message->response = message.packet;
+ }
+ else
+ {
+ /* error, we expected more acks
+ since the messages are processed in order, this should not happen, so this is an error situation */
+ m_queue->m_com->m_callback->GetLib()->AddLog(CEC_LOG_WARNING, "%s - received 'transmit succeeded' but not enough 'command accepted' messages (%d left)", ToString(), m_iPacketsLeft);
+ m_message->state = ADAPTER_MESSAGE_STATE_ERROR;
+ }
+ }
+
+ Signal();
+
+ return true;
+}
+
+bool CCECAdapterMessageQueueEntry::MessageReceivedResponse(const CCECAdapterMessage &message)
+{
+ {
+ CLockObject lock(m_mutex);
+#ifdef CEC_DEBUGGING
+ m_queue->m_com->m_callback->GetLib()->AddLog(CEC_LOG_DEBUG, "%s - received response - %s", ToString(), message.ToString().c_str());
+#else
+ if (message.IsError())
+ m_queue->m_com->m_callback->GetLib()->AddLog(CEC_LOG_DEBUG, "%s - received response - %s", ToString(), message.ToString().c_str());
+#endif
+ m_message->response = message.packet;
+ if (m_message->IsTransmission())
+ m_message->state = message.Message() == MSGCODE_TRANSMIT_SUCCEEDED ? ADAPTER_MESSAGE_STATE_SENT_ACKED : ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED;
+ else
+ m_message->state = ADAPTER_MESSAGE_STATE_SENT_ACKED;
+ }
+
+ Signal();
+
+ return true;
+}
+
+bool CCECAdapterMessageQueueEntry::ProvidesExtendedResponse(void)
+{
+ return m_queue && m_queue->ProvidesExtendedResponse();
+}
+
+bool CCECAdapterMessageQueueEntry::TimedOutOrSucceeded(void) const
+{
+ return m_message->bFireAndForget && (m_bSucceeded || m_queueTimeout.TimeLeft() == 0);
+}
+
+CCECAdapterMessageQueue::CCECAdapterMessageQueue(CUSBCECAdapterCommunication *com) :
+ P8PLATFORM::CThread(),
+ m_com(com),
+ m_iNextMessage(0)
+{
+ m_incomingAdapterMessage = new CCECAdapterMessage;
+ m_currentCECFrame.Clear();
+}
+
+CCECAdapterMessageQueue::~CCECAdapterMessageQueue(void)
+{
+ StopThread(-1);
+ Clear();
+ StopThread();
+ delete m_incomingAdapterMessage;
+}
+
+void CCECAdapterMessageQueue::Clear(void)
+{
+ StopThread(5);
+ CLockObject lock(m_mutex);
+ m_writeQueue.Clear();
+ m_messages.clear();
+}
+
+void *CCECAdapterMessageQueue::Process(void)
+{
+ CCECAdapterMessageQueueEntry *message(NULL);
+ while (!IsStopped())
+ {
+ /* wait for a new message */
+ if (m_writeQueue.Pop(message, MESSAGE_QUEUE_SIGNAL_WAIT_TIME) && message)
+ {
+ /* write this message */
+ {
+ CLockObject lock(m_mutex);
+ m_com->WriteToDevice(message->m_message);
+ }
+ if (message->m_message->state == ADAPTER_MESSAGE_STATE_ERROR ||
+ message->m_message->Message() == MSGCODE_START_BOOTLOADER)
+ {
+ message->Signal();
+ Clear();
+ break;
+ }
+ }
+
+ CheckTimedOutMessages();
+ }
+ return NULL;
+}
+
+void CCECAdapterMessageQueue::CheckTimedOutMessages(void)
+{
+ CLockObject lock(m_mutex);
+ std::vector<uint64_t> timedOut;
+ for (std::map<uint64_t, CCECAdapterMessageQueueEntry *>::iterator it = m_messages.begin(); it != m_messages.end(); it++)
+ {
+ if (it->second->TimedOutOrSucceeded())
+ {
+ timedOut.push_back(it->first);
+ if (!it->second->m_bSucceeded)
+ m_com->m_callback->GetLib()->AddLog(CEC_LOG_DEBUG, "command '%s' was not acked by the controller", CCECAdapterMessage::ToString(it->second->m_message->Message()));
+ delete it->second->m_message;
+ delete it->second;
+ }
+ }
+
+ for (std::vector<uint64_t>::iterator it = timedOut.begin(); it != timedOut.end(); it++)
+ {
+ uint64_t iEntryId = *it;
+ m_messages.erase(iEntryId);
+ }
+}
+
+void CCECAdapterMessageQueue::MessageReceived(const CCECAdapterMessage &msg)
+{
+ bool bHandled(false);
+ CLockObject lock(m_mutex);
+ /* send the received message to each entry in the queue until it is handled */
+ for (std::map<uint64_t, CCECAdapterMessageQueueEntry *>::iterator it = m_messages.begin(); !bHandled && it != m_messages.end(); it++)
+ bHandled = it->second->MessageReceived(msg);
+
+ if (!bHandled)
+ {
+ /* the message wasn't handled */
+ bool bIsError(m_com->HandlePoll(msg));
+#ifdef CEC_DEBUGGING
+ m_com->m_callback->GetLib()->AddLog(bIsError ? CEC_LOG_WARNING : CEC_LOG_DEBUG, msg.ToString().c_str());
+#else
+ if (bIsError)
+ m_com->m_callback->GetLib()->AddLog(CEC_LOG_WARNING, msg.ToString().c_str());
+#endif
+
+ /* push this message to the current frame */
+ if (!bIsError && msg.PushToCecCommand(m_currentCECFrame))
+ {
+ /* and push the current frame back over the callback method when a full command was received */
+ if (m_com->IsInitialised())
+ m_com->m_callback->OnCommandReceived(m_currentCECFrame);
+
+ /* clear the current frame */
+ m_currentCECFrame.Clear();
+ }
+ }
+}
+
+void CCECAdapterMessageQueue::AddData(uint8_t *data, size_t iLen)
+{
+ for (size_t iPtr = 0; iPtr < iLen; iPtr++)
+ {
+ bool bFullMessage(false);
+ {
+ CLockObject lock(m_mutex);
+ bFullMessage = m_incomingAdapterMessage->PushReceivedByte(data[iPtr]);
+ }
+
+ if (bFullMessage)
+ {
+ /* a full message was received */
+ CCECAdapterMessage newMessage;
+ newMessage.packet = m_incomingAdapterMessage->packet;
+ MessageReceived(newMessage);
+
+ /* clear the current message */
+ CLockObject lock(m_mutex);
+ m_incomingAdapterMessage->Clear();
+ }
+ }
+}
+
+bool CCECAdapterMessageQueue::Write(CCECAdapterMessage *msg)
+{
+ msg->state = ADAPTER_MESSAGE_STATE_WAITING_TO_BE_SENT;
+
+ /* set the correct line timeout */
+ if (msg->IsTransmission())
+ {
+ m_com->SetLineTimeout(msg->lineTimeout);
+ }
+
+ CCECAdapterMessageQueueEntry *entry = new CCECAdapterMessageQueueEntry(this, msg);
+ if (!entry)
+ {
+ m_com->m_callback->GetLib()->AddLog(CEC_LOG_ERROR, "couldn't create queue entry for '%s'", CCECAdapterMessage::ToString(msg->Message()));
+ msg->state = ADAPTER_MESSAGE_STATE_ERROR;
+ return false;
+ }
+
+ uint64_t iEntryId(0);
+ /* add to the wait for ack queue */
+ if (msg->Message() != MSGCODE_START_BOOTLOADER)
+ {
+ CLockObject lock(m_mutex);
+ iEntryId = m_iNextMessage++;
+ m_messages.insert(std::make_pair(iEntryId, entry));
+ }
+
+ /* add the message to the write queue */
+ m_writeQueue.Push(entry);
+
+ bool bReturn(true);
+ if (!msg->bFireAndForget)
+ {
+ if (!entry->Wait(msg->transmit_timeout <= 5 ? CEC_DEFAULT_TRANSMIT_WAIT : msg->transmit_timeout))
+ {
+ m_com->m_callback->GetLib()->AddLog(CEC_LOG_DEBUG, "command '%s' was not acked by the controller", CCECAdapterMessage::ToString(msg->Message()));
+ msg->state = ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED;
+ bReturn = false;
+ }
+
+ if (msg->Message() != MSGCODE_START_BOOTLOADER)
+ {
+ CLockObject lock(m_mutex);
+ m_messages.erase(iEntryId);
+ }
+
+ if (msg->ReplyIsError() && msg->state != ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED)
+ msg->state = ADAPTER_MESSAGE_STATE_ERROR;
+
+ delete entry;
+ }
+
+ return bReturn;
+}
+
+bool CCECAdapterMessageQueue::ProvidesExtendedResponse(void)
+{
+ return m_com && m_com->ProvidesExtendedResponse();
+}
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include <p8-platform/threads/threads.h>
+#include <p8-platform/util/buffer.h>
+#include <p8-platform/util/timeutils.h>
+#include <map>
+#include "USBCECAdapterMessage.h"
+
+namespace CEC
+{
+ class CUSBCECAdapterCommunication;
+ class CCECAdapterMessageQueue;
+ class CCECAdapterMessage;
+
+ class CCECAdapterMessageQueueEntry
+ {
+ public:
+ CCECAdapterMessageQueueEntry(CCECAdapterMessageQueue *queue, CCECAdapterMessage *message);
+ virtual ~CCECAdapterMessageQueueEntry(void);
+
+ /*!
+ * @brief Signal waiting threads
+ */
+ void Broadcast(void);
+
+ /*!
+ * @brief Called when a message was received.
+ * @param message The message that was received.
+ * @return True when this message was handled by this entry, false otherwise.
+ */
+ bool MessageReceived(const CCECAdapterMessage &message);
+
+ /*!
+ * @brief Wait for a response to this command.
+ * @param iTimeout The timeout to use while waiting.
+ * @return True when a response was received before the timeout passed, false otherwise.
+ */
+ bool Wait(uint32_t iTimeout);
+
+ /*!
+ * @return True while a thread is waiting for a signal or isn't waiting yet, false otherwise.
+ */
+ bool IsWaiting(void);
+
+ /*!
+ * @return The msgcode of the command that was sent.
+ */
+ cec_adapter_messagecode MessageCode(void);
+
+ /*!
+ * @brief Check whether a message is a response to this command.
+ * @param msg The message to check.
+ * @return True when it's a response, false otherwise.
+ */
+ bool IsResponse(const CCECAdapterMessage &msg);
+ bool IsResponseOld(const CCECAdapterMessage &msg);
+
+ /*!
+ * @return The command that was sent in human readable form.
+ */
+ const char *ToString(void) const;
+
+ /*!
+ * @brief Called when a 'command accepted' message was received.
+ * @param message The message that was received.
+ * @return True when the message was handled, false otherwise.
+ */
+ bool MessageReceivedCommandAccepted(const CCECAdapterMessage &message);
+
+ /*!
+ * @brief Called when a 'transmit succeeded' message was received.
+ * @param message The message that was received.
+ * @return True when the message was handled, false otherwise.
+ */
+ bool MessageReceivedTransmitSucceeded(const CCECAdapterMessage &message);
+
+ /*!
+ * @brief Called when a message that's not a 'command accepted' or 'transmit succeeded' message was received.
+ * @param message The message that was received.
+ * @return True when the message was handled, false otherwise.
+ */
+ bool MessageReceivedResponse(const CCECAdapterMessage &message);
+
+ /*!
+ * @brief Signals the waiting thread.
+ */
+ void Signal(void);
+
+ bool ProvidesExtendedResponse(void);
+
+ /*!
+ * @return True when a fire and forget packet timed out or succeeded, false otherwise
+ */
+ bool TimedOutOrSucceeded(void) const;
+
+ CCECAdapterMessageQueue * m_queue;
+ CCECAdapterMessage * m_message; /**< the message that was sent */
+ uint8_t m_iPacketsLeft; /**< the amount of acks that we're waiting on */
+ bool m_bSucceeded; /**< true when the command received a response, false otherwise */
+ bool m_bWaiting; /**< true while a thread is waiting or when it hasn't started waiting yet */
+ P8PLATFORM::CCondition<bool> m_condition; /**< the condition to wait on */
+ P8PLATFORM::CMutex m_mutex; /**< mutex for changes to this class */
+ P8PLATFORM::CTimeout m_queueTimeout; /**< ack timeout for fire and forget commands */
+ };
+
+ class CCECAdapterMessageQueue : public P8PLATFORM::CThread
+ {
+ friend class CUSBCECAdapterCommunication;
+ friend class CCECAdapterMessageQueueEntry;
+
+ public:
+ /*!
+ * @brief Create a new message queue.
+ * @param com The communication handler callback to use.
+ * @param iQueueSize The outgoing message queue size.
+ */
+ CCECAdapterMessageQueue(CUSBCECAdapterCommunication *com);
+ virtual ~CCECAdapterMessageQueue(void);
+
+ /*!
+ * @brief Signal and delete everything in the queue
+ */
+ void Clear(void);
+
+ /*!
+ * @brief Called when a message was received from the adapter.
+ * @param msg The message that was received.
+ */
+ void MessageReceived(const CCECAdapterMessage &msg);
+
+ /*!
+ * @brief Adds received data to the current frame.
+ * @param data The data to add.
+ * @param iLen The length of the data to add.
+ */
+ void AddData(uint8_t *data, size_t iLen);
+
+ /*!
+ * @brief Transmit a command to the adapter and wait for a response.
+ * @param msg The command to send.
+ * @return True when written, false otherwise.
+ */
+ bool Write(CCECAdapterMessage *msg);
+
+ bool ProvidesExtendedResponse(void);
+
+ virtual void *Process(void);
+
+ void CheckTimedOutMessages(void);
+
+ private:
+ CUSBCECAdapterCommunication * m_com; /**< the communication handler */
+ P8PLATFORM::CMutex m_mutex; /**< mutex for changes to this class */
+ std::map<uint64_t, CCECAdapterMessageQueueEntry *> m_messages; /**< the outgoing message queue */
+ P8PLATFORM::SyncedBuffer<CCECAdapterMessageQueueEntry *> m_writeQueue; /**< the queue for messages that are to be written */
+ uint64_t m_iNextMessage; /**< the index of the next message */
+ CCECAdapterMessage * m_incomingAdapterMessage; /**< the current incoming message that's being assembled */
+ cec_command m_currentCECFrame; /**< the current incoming CEC command that's being assembled */
+ };
+}
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+
+#if defined(HAVE_RPI_API)
+#include "RPiCECAdapterCommunication.h"
+
+extern "C" {
+#include <bcm_host.h>
+}
+
+#include "CECTypeUtils.h"
+#include "LibCEC.h"
+#include "RPiCECAdapterMessageQueue.h"
+
+using namespace CEC;
+using namespace P8PLATFORM;
+
+#define LIB_CEC m_callback->GetLib()
+
+static bool g_bHostInited = false;
+
+// callback for the RPi CEC service
+void rpi_cec_callback(void *callback_data, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4)
+{
+ if (callback_data)
+ static_cast<CRPiCECAdapterCommunication *>(callback_data)->OnDataReceived(p0, p1, p2, p3, p4);
+}
+
+// callback for the TV service
+void rpi_tv_callback(void *callback_data, uint32_t reason, uint32_t p0, uint32_t p1)
+{
+ if (callback_data)
+ static_cast<CRPiCECAdapterCommunication *>(callback_data)->OnTVServiceCallback(reason, p0, p1);
+}
+
+CRPiCECAdapterCommunication::CRPiCECAdapterCommunication(IAdapterCommunicationCallback *callback) :
+ IAdapterCommunication(callback),
+ m_bInitialised(false),
+ m_logicalAddress(CECDEVICE_UNKNOWN),
+ m_bLogicalAddressChanged(false),
+ m_previousLogicalAddress(CECDEVICE_FREEUSE),
+ m_bLogicalAddressRegistered(false),
+ m_bDisableCallbacks(false)
+{
+ m_queue = new CRPiCECAdapterMessageQueue(this);
+}
+
+CRPiCECAdapterCommunication::~CRPiCECAdapterCommunication(void)
+{
+ delete(m_queue);
+ UnregisterLogicalAddress();
+ Close();
+ vc_cec_set_passive(false);
+}
+
+const char *ToString(const VC_CEC_ERROR_T error)
+{
+ switch(error)
+ {
+ case VC_CEC_SUCCESS:
+ return "success";
+ case VC_CEC_ERROR_NO_ACK:
+ return "no ack";
+ case VC_CEC_ERROR_SHUTDOWN:
+ return "shutdown";
+ case VC_CEC_ERROR_BUSY:
+ return "device is busy";
+ case VC_CEC_ERROR_NO_LA:
+ return "no logical address";
+ case VC_CEC_ERROR_NO_PA:
+ return "no physical address";
+ case VC_CEC_ERROR_NO_TOPO:
+ return "no topology";
+ case VC_CEC_ERROR_INVALID_FOLLOWER:
+ return "invalid follower";
+ case VC_CEC_ERROR_INVALID_ARGUMENT:
+ return "invalid arg";
+ default:
+ return "unknown";
+ }
+}
+
+bool CRPiCECAdapterCommunication::IsInitialised(void)
+{
+ CLockObject lock(m_mutex);
+ return m_bInitialised;
+}
+
+void CRPiCECAdapterCommunication::OnTVServiceCallback(uint32_t reason, uint32_t UNUSED(p0), uint32_t UNUSED(p1))
+{
+ switch(reason)
+ {
+ case VC_HDMI_ATTACHED:
+ {
+ uint16_t iNewAddress = GetPhysicalAddress();
+ m_callback->HandlePhysicalAddressChanged(iNewAddress);
+ break;
+ }
+ case VC_HDMI_UNPLUGGED:
+ case VC_HDMI_DVI:
+ case VC_HDMI_HDMI:
+ case VC_HDMI_HDCP_UNAUTH:
+ case VC_HDMI_HDCP_AUTH:
+ case VC_HDMI_HDCP_KEY_DOWNLOAD:
+ case VC_HDMI_HDCP_SRM_DOWNLOAD:
+ default:
+ break;
+ }
+}
+
+void CRPiCECAdapterCommunication::OnDataReceived(uint32_t header, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3)
+{
+ {
+ CLockObject lock(m_mutex);
+ if (m_bDisableCallbacks)
+ return;
+ }
+
+ VC_CEC_NOTIFY_T reason = (VC_CEC_NOTIFY_T)CEC_CB_REASON(header);
+
+#ifdef CEC_DEBUGGING
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "received data: header:%08X p0:%08X p1:%08X p2:%08X p3:%08X reason:%x", header, p0, p1, p2, p3, reason);
+#endif
+
+ switch (reason)
+ {
+ case VC_CEC_RX:
+ // CEC data received
+ {
+ // translate into a VC_CEC_MESSAGE_T
+ VC_CEC_MESSAGE_T message;
+ vc_cec_param2message(header, p0, p1, p2, p3, &message);
+
+ // translate to a cec_command
+ cec_command command;
+ cec_command::Format(command,
+ (cec_logical_address)message.initiator,
+ (cec_logical_address)message.follower,
+ (cec_opcode)CEC_CB_OPCODE(p0));
+
+ // copy parameters
+ for (uint8_t iPtr = 1; iPtr < message.length; iPtr++)
+ command.PushBack(message.payload[iPtr]);
+
+ // send to libCEC
+ m_callback->OnCommandReceived(command);
+ }
+ break;
+ case VC_CEC_TX:
+ {
+ // handle response to a command that was sent earlier
+ m_queue->MessageReceived((cec_opcode)CEC_CB_OPCODE(p0), (cec_logical_address)CEC_CB_INITIATOR(p0), (cec_logical_address)CEC_CB_FOLLOWER(p0), CEC_CB_RC(header));
+ }
+ break;
+ case VC_CEC_BUTTON_PRESSED:
+ case VC_CEC_REMOTE_PRESSED:
+ {
+ // translate into a cec_command
+ cec_command command;
+ cec_command::Format(command,
+ (cec_logical_address)CEC_CB_INITIATOR(p0),
+ (cec_logical_address)CEC_CB_FOLLOWER(p0),
+ reason == VC_CEC_BUTTON_PRESSED ? CEC_OPCODE_USER_CONTROL_PRESSED : CEC_OPCODE_VENDOR_REMOTE_BUTTON_DOWN);
+ command.parameters.PushBack((uint8_t)CEC_CB_OPERAND1(p0));
+
+ // send to libCEC
+ m_callback->OnCommandReceived(command);
+ }
+ break;
+ case VC_CEC_BUTTON_RELEASE:
+ case VC_CEC_REMOTE_RELEASE:
+ {
+ // translate into a cec_command
+ cec_command command;
+ cec_command::Format(command,
+ (cec_logical_address)CEC_CB_INITIATOR(p0),
+ (cec_logical_address)CEC_CB_FOLLOWER(p0),
+ reason == VC_CEC_BUTTON_PRESSED ? CEC_OPCODE_USER_CONTROL_RELEASE : CEC_OPCODE_VENDOR_REMOTE_BUTTON_UP);
+ command.parameters.PushBack((uint8_t)CEC_CB_OPERAND1(p0));
+
+ // send to libCEC
+ m_callback->OnCommandReceived(command);
+ }
+ break;
+ case VC_CEC_LOGICAL_ADDR:
+ {
+ CLockObject lock(m_mutex);
+ m_previousLogicalAddress = m_logicalAddress;
+ if (CEC_CB_RC(header) == VCHIQ_SUCCESS)
+ {
+ m_bLogicalAddressChanged = true;
+ m_logicalAddress = (cec_logical_address)(p0 & 0xF);
+ m_bLogicalAddressRegistered = true;
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "logical address changed to %s (%x)", LIB_CEC->ToString(m_logicalAddress), m_logicalAddress);
+ }
+ else
+ {
+ m_logicalAddress = CECDEVICE_FREEUSE;
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "failed to change the logical address, reset to %s (%x)", LIB_CEC->ToString(m_logicalAddress), m_logicalAddress);
+ }
+ m_logicalAddressCondition.Signal();
+ }
+ break;
+ case VC_CEC_LOGICAL_ADDR_LOST:
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "logical %s (%x) address lost", LIB_CEC->ToString(m_logicalAddress), m_logicalAddress);
+ // the logical address was taken by another device
+ cec_logical_address previousAddress = m_logicalAddress == CECDEVICE_FREEUSE ? m_previousLogicalAddress : m_logicalAddress;
+ m_logicalAddress = CECDEVICE_UNKNOWN;
+
+ // notify libCEC that we lost our LA when the connection was initialised
+ bool bNotify(false);
+ {
+ CLockObject lock(m_mutex);
+ bNotify = m_bInitialised && m_bLogicalAddressRegistered;
+ }
+ if (bNotify)
+ m_callback->HandleLogicalAddressLost(previousAddress);
+ }
+ break;
+ case VC_CEC_TOPOLOGY:
+ break;
+ default:
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "ignoring unknown reason %x", reason);
+ break;
+ }
+}
+
+bool CRPiCECAdapterCommunication::Open(uint32_t iTimeoutMs /* = CEC_DEFAULT_CONNECT_TIMEOUT */, bool UNUSED(bSkipChecks) /* = false */, bool bStartListening)
+{
+ Close();
+
+ InitHost();
+
+ if (bStartListening)
+ {
+ // enable passive mode
+ vc_cec_set_passive(true);
+
+ // register the callbacks
+ vc_cec_register_callback(rpi_cec_callback, (void*)this);
+ vc_tv_register_callback(rpi_tv_callback, (void*)this);
+
+ // register LA "freeuse"
+ if (RegisterLogicalAddress(CECDEVICE_FREEUSE, iTimeoutMs))
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - vc_cec initialised", __FUNCTION__);
+ CLockObject lock(m_mutex);
+ m_bInitialised = true;
+ }
+ else
+ {
+ LIB_CEC->AddLog(CEC_LOG_ERROR, "%s - vc_cec could not be initialised", __FUNCTION__);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+uint16_t CRPiCECAdapterCommunication::GetPhysicalAddress(void)
+{
+ uint16_t iPA(CEC_INVALID_PHYSICAL_ADDRESS);
+ if (!IsInitialised())
+ return iPA;
+
+ if (vc_cec_get_physical_address(&iPA) == VCHIQ_SUCCESS)
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - physical address = %04x", __FUNCTION__, iPA);
+ else
+ {
+ LIB_CEC->AddLog(CEC_LOG_WARNING, "%s - failed to get the physical address", __FUNCTION__);
+ iPA = CEC_INVALID_PHYSICAL_ADDRESS;
+ }
+
+ return iPA;
+}
+
+void CRPiCECAdapterCommunication::Close(void)
+{
+ if (m_bInitialised) {
+ vc_tv_unregister_callback(rpi_tv_callback);
+ m_bInitialised = false;
+ }
+
+ if (!g_bHostInited)
+ {
+ g_bHostInited = false;
+ bcm_host_deinit();
+ }
+}
+
+std::string CRPiCECAdapterCommunication::GetError(void) const
+{
+ std::string strError(m_strError);
+ return strError;
+}
+
+void CRPiCECAdapterCommunication::SetDisableCallback(const bool disable)
+{
+ CLockObject lock(m_mutex);
+ m_bDisableCallbacks = disable;
+}
+
+cec_adapter_message_state CRPiCECAdapterCommunication::Write(const cec_command &data, bool &bRetry, uint8_t iLineTimeout, bool bIsReply)
+{
+ VC_CEC_ERROR_T vcAnswer;
+ uint32_t iTimeout = (data.transmit_timeout ? data.transmit_timeout : iLineTimeout*1000);
+ cec_adapter_message_state rc;
+
+ // to send a real POLL (dest & source LA the same - eg 11), VC
+ // needs us to be in passivemode(we are) and with no actual LA
+ // registered
+ // libCEC sends 'true' POLLs only when at LA choosing process.
+ // any other POLLing of devices happens with regular 'empty'
+ // msg (just header, no OPCODE) with actual LA as source to X.
+ // for us this means, that libCEC already registered tmp LA
+ // (0xf, 0xe respectively) before it calls us for LA POLLing.
+ //
+ // that means - unregistering any A from adapter, _while_
+ // ignoring callbacks (and especially not reporting the
+ // subsequent actions generated from VC layer - like
+ // LA change to 0xf ...)
+ //
+ // calling vc_cec_release_logical_address() over and over is
+ // fine.
+ // once libCEC gets NACK on tested A, it calls RegisterLogicalAddress()
+ // on it's own - so we don't need to take care of re-registering
+ if (!data.opcode_set && data.initiator == data.destination)
+ {
+ SetDisableCallback(true);
+
+ vc_cec_release_logical_address();
+ // accept nothing else than NACK or ACK, repeat until this happens
+ while (ADAPTER_MESSAGE_STATE_WAITING_TO_BE_SENT ==
+ (rc = m_queue->Write(data, bRetry, iTimeout, bIsReply, vcAnswer)));
+
+ SetDisableCallback(false);
+ return rc;
+ }
+
+ rc = m_queue->Write(data, bRetry, iTimeout, bIsReply, vcAnswer);
+#ifdef CEC_DEBUGGING
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "sending data: result %s", ToString(vcAnswer));
+#endif
+ return rc;
+}
+
+uint16_t CRPiCECAdapterCommunication::GetFirmwareVersion(void)
+{
+ return VC_CECSERVICE_VER;
+}
+
+cec_logical_address CRPiCECAdapterCommunication::GetLogicalAddress(void)
+{
+ CLockObject lock(m_mutex);
+
+ return m_logicalAddress;
+}
+
+bool CRPiCECAdapterCommunication::UnregisterLogicalAddress(void)
+{
+ CLockObject lock(m_mutex);
+ if (!m_bInitialised)
+ return true;
+
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - releasing previous logical address", __FUNCTION__);
+ {
+ CLockObject lock(m_mutex);
+ m_bLogicalAddressRegistered = false;
+ m_bLogicalAddressChanged = false;
+ }
+
+ vc_cec_release_logical_address();
+
+ return m_logicalAddressCondition.Wait(m_mutex, m_bLogicalAddressChanged);
+}
+
+bool CRPiCECAdapterCommunication::RegisterLogicalAddress(const cec_logical_address address, uint32_t iTimeoutMs)
+{
+ {
+ CLockObject lock(m_mutex);
+ if ((m_logicalAddress == address) && m_bLogicalAddressRegistered)
+ return true;
+ }
+
+ m_bLogicalAddressChanged = false;
+
+ // register the new LA
+ int iRetval = vc_cec_set_logical_address((CEC_AllDevices_T)address, (CEC_DEVICE_TYPE_T)CCECTypeUtils::GetType(address), CEC_VENDOR_ID_BROADCOM);
+ if (iRetval != VCHIQ_SUCCESS)
+ {
+ LIB_CEC->AddLog(CEC_LOG_ERROR, "%s - vc_cec_set_logical_address(%X) returned %s (%d)", __FUNCTION__, address, ToString((VC_CEC_ERROR_T)iRetval), iRetval);
+ UnregisterLogicalAddress();
+ }
+ else if (m_logicalAddressCondition.Wait(m_mutex, m_bLogicalAddressChanged, iTimeoutMs))
+ {
+ return true;
+ }
+ return false;
+}
+
+cec_logical_addresses CRPiCECAdapterCommunication::GetLogicalAddresses(void)
+{
+ cec_logical_addresses addresses; addresses.Clear();
+ if (m_bLogicalAddressRegistered)
+ addresses.primary = GetLogicalAddress();
+
+ return addresses;
+}
+
+bool CRPiCECAdapterCommunication::SetLogicalAddresses(const cec_logical_addresses &addresses)
+{
+ // the current generation RPi only supports 1 LA, so just ensure that the primary address is registered
+ return SupportsSourceLogicalAddress(addresses.primary) &&
+ RegisterLogicalAddress(addresses.primary);
+}
+
+void CRPiCECAdapterCommunication::InitHost(void)
+{
+ if (!g_bHostInited)
+ {
+ g_bHostInited = true;
+ bcm_host_init();
+ }
+}
+
+#endif
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#if defined(HAVE_RPI_API)
+
+#include "adapter/AdapterCommunication.h"
+#include <p8-platform/threads/threads.h>
+
+#define RPI_ADAPTER_VID 0x2708
+#define RPI_ADAPTER_PID 0x1001
+
+extern "C" {
+#include <interface/vmcs_host/vc_cecservice.h>
+#include <interface/vchiq_arm/vchiq_if.h>
+}
+
+namespace CEC
+{
+ class CRPiCECAdapterMessageQueue;
+
+ class CRPiCECAdapterCommunication : public IAdapterCommunication
+ {
+ public:
+ /*!
+ * @brief Create a new USB-CEC communication handler.
+ * @param callback The callback to use for incoming CEC commands.
+ */
+ CRPiCECAdapterCommunication(IAdapterCommunicationCallback *callback);
+ virtual ~CRPiCECAdapterCommunication(void);
+
+ /** @name IAdapterCommunication implementation */
+ ///{
+ bool Open(uint32_t iTimeoutMs = CEC_DEFAULT_CONNECT_TIMEOUT, bool bSkipChecks = false, bool bStartListening = true);
+ void Close(void);
+ bool IsOpen(void) { return m_bInitialised; };
+ std::string GetError(void) const;
+ cec_adapter_message_state Write(const cec_command &data, bool &bRetry, uint8_t iLineTimeout, bool bIsReply);
+
+ bool SetLineTimeout(uint8_t UNUSED(iTimeout)) { return true; };
+ bool StartBootloader(void) { return false; };
+ bool SetLogicalAddresses(const cec_logical_addresses &addresses);
+ cec_logical_addresses GetLogicalAddresses(void);
+ bool PingAdapter(void) { return m_bInitialised; };
+ uint16_t GetFirmwareVersion(void);
+ uint32_t GetFirmwareBuildDate(void) { return 0; };
+ bool IsRunningLatestFirmware(void) { return true; };
+ bool PersistConfiguration(const libcec_configuration & UNUSED(configuration)) { return false; };
+ bool GetConfiguration(libcec_configuration & UNUSED(configuration)) { return false; };
+ std::string GetPortName(void) { std::string strReturn("RPI"); return strReturn; };
+ uint16_t GetPhysicalAddress(void);
+ bool SetControlledMode(bool UNUSED(controlled)) { return true; };
+ cec_vendor_id GetVendorId(void) { return CEC_VENDOR_BROADCOM; }
+ bool SupportsSourceLogicalAddress(const cec_logical_address address) { return address > CECDEVICE_TV && address < CECDEVICE_BROADCAST; }
+ cec_adapter_type GetAdapterType(void) { return ADAPTERTYPE_RPI; };
+ uint16_t GetAdapterVendorId(void) const { return RPI_ADAPTER_VID; }
+ uint16_t GetAdapterProductId(void) const { return RPI_ADAPTER_PID; }
+ void SetActiveSource(bool UNUSED(bSetTo), bool UNUSED(bClientUnregistered)) {}
+ ///}
+
+ bool IsInitialised(void);
+ void OnDataReceived(uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4);
+ void OnTVServiceCallback(uint32_t reason, uint32_t p0, uint32_t p1);
+
+ static void InitHost(void);
+
+ private:
+ cec_logical_address GetLogicalAddress(void);
+ bool UnregisterLogicalAddress(void);
+ bool RegisterLogicalAddress(const cec_logical_address address, uint32_t iTimeoutMs = CEC_DEFAULT_CONNECT_TIMEOUT);
+ void SetDisableCallback(const bool disable);
+
+ bool m_bInitialised; /**< true when the connection is initialised, false otherwise */
+ std::string m_strError; /**< current error message */
+ CRPiCECAdapterMessageQueue *m_queue;
+ cec_logical_address m_logicalAddress;
+
+ bool m_bLogicalAddressChanged;
+ P8PLATFORM::CCondition<bool> m_logicalAddressCondition;
+ P8PLATFORM::CMutex m_mutex;
+ VCHI_INSTANCE_T m_vchi_instance;
+ VCHI_CONNECTION_T * m_vchi_connection;
+ cec_logical_address m_previousLogicalAddress;
+ bool m_bLogicalAddressRegistered;
+
+ bool m_bDisableCallbacks;
+ };
+};
+
+#endif
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+
+#if defined(HAVE_RPI_API)
+#include "RPiCECAdapterDetection.h"
+
+extern "C" {
+#include <interface/vmcs_host/vc_cecservice.h>
+#include <interface/vchiq_arm/vchiq_if.h>
+}
+
+using namespace CEC;
+
+bool CRPiCECAdapterDetection::FindAdapter(void)
+{
+ uint8_t iResult;
+
+ VCHI_INSTANCE_T vchiq_instance;
+ if ((iResult = vchi_initialise(&vchiq_instance)) != VCHIQ_SUCCESS)
+ return false;
+
+ if ((iResult = vchi_connect(NULL, 0, vchiq_instance)) != VCHIQ_SUCCESS)
+ return false;
+
+ return true;
+}
+
+#endif
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+
+namespace CEC
+{
+ class CRPiCECAdapterDetection
+ {
+ public:
+ static bool FindAdapter(void);
+ };
+}
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+
+#if defined(HAVE_RPI_API)
+#include "RPiCECAdapterMessageQueue.h"
+#include <p8-platform/util/StringUtils.h>
+
+// use vc_cec_send_message2() if defined and vc_cec_send_message() if not
+//#define RPI_USE_SEND_MESSAGE2
+
+#include "RPiCECAdapterCommunication.h"
+#include "LibCEC.h"
+#include "CECTypeUtils.h"
+
+extern "C" {
+#include <interface/vmcs_host/vc_cecservice.h>
+#include <interface/vchiq_arm/vchiq.h>
+}
+
+using namespace CEC;
+using namespace P8PLATFORM;
+
+#define LIB_CEC m_com->m_callback->GetLib()
+
+// initialise new msg with unsuccesfull status, also
+// set default return state to "UNKNOWN" - instead
+// of NACK (which has special meaning for dev POLLing)
+CRPiCECAdapterMessageQueueEntry::CRPiCECAdapterMessageQueueEntry(CRPiCECAdapterMessageQueue *queue, const cec_command &command) :
+ m_queue(queue),
+ m_command(command),
+ m_retval(VC_CEC_ERROR_BUSY),
+ m_bSucceeded(false)
+{
+
+}
+
+void CRPiCECAdapterMessageQueueEntry::Broadcast(void)
+{
+ CLockObject lock(m_mutex);
+ m_condition.Broadcast();
+}
+
+bool CRPiCECAdapterMessageQueueEntry::MessageReceived(cec_opcode opcode, cec_logical_address initiator, cec_logical_address destination, uint32_t response)
+{
+ if ((m_command.opcode_set && m_command.opcode == opcode &&
+ m_command.initiator == initiator &&
+ m_command.destination == destination)
+ ||
+ (!m_command.opcode_set &&
+ m_command.destination == destination))
+ {
+ CLockObject lock(m_mutex);
+ m_retval = response;
+ m_bSucceeded = true;
+ m_condition.Signal();
+ return true;
+ }
+
+ return false;
+}
+
+bool CRPiCECAdapterMessageQueueEntry::Wait(uint32_t iTimeout)
+{
+ bool bReturn(false);
+ /* wait until we receive a signal when the tranmission succeeded */
+ {
+ CLockObject lock(m_mutex);
+ bReturn = m_bSucceeded ? true : m_condition.Wait(m_mutex, m_bSucceeded, iTimeout);
+ m_bWaiting = false;
+ }
+ return bReturn;
+}
+
+bool CRPiCECAdapterMessageQueueEntry::IsWaiting(void)
+{
+ CLockObject lock(m_mutex);
+ return m_bWaiting;
+}
+
+void CRPiCECAdapterMessageQueue::Clear(void)
+{
+ CLockObject lock(m_mutex);
+ m_messages.clear();
+}
+
+void CRPiCECAdapterMessageQueue::MessageReceived(cec_opcode opcode, cec_logical_address initiator, cec_logical_address destination, uint32_t response)
+{
+ bool bHandled(false);
+ CLockObject lock(m_mutex);
+ /* send the received message to each entry in the queue until it is handled */
+ for (std::map<uint64_t, CRPiCECAdapterMessageQueueEntry *>::iterator it = m_messages.begin(); !bHandled && it != m_messages.end(); it++)
+ bHandled = it->second->MessageReceived(opcode, initiator, destination, response);
+
+ if (!bHandled)
+ LIB_CEC->AddLog(CEC_LOG_WARNING, "unhandled response received: opcode=%x initiator=%x destination=%x response=%x", (int)opcode, (int)initiator, (int)destination, response);
+}
+
+uint32_t CRPiCECAdapterMessageQueueEntry::Result() const
+{
+ return m_retval;
+}
+
+cec_adapter_message_state CRPiCECAdapterMessageQueue::Write(const cec_command &command, bool &bRetry, uint32_t iLineTimeout, bool bIsReply, VC_CEC_ERROR_T &vcReply)
+{
+ // handle POLL (msg like '11') in a special way - the way it was
+ // originally designed by BCM, expected to happen and documented
+ // in API docs (/opt/vc/includes)
+ // due to often (more than 20% test cases - CEC bus with 8 devices)
+ // irregularities on returned status, repeat until we get SAME
+ // result twice in a row
+ if (!command.opcode_set && command.destination == command.initiator)
+ {
+ int iReturnPrev = -1;
+ int iReturn = 0;
+
+ while((iReturn = vc_cec_poll_address((CEC_AllDevices_T)command.destination)) != iReturnPrev)
+ iReturnPrev = iReturn;
+ if (iReturn == 0)
+ return ADAPTER_MESSAGE_STATE_SENT_ACKED;
+ else if (iReturn > 0)
+ return ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED;
+ else
+ return ADAPTER_MESSAGE_STATE_WAITING_TO_BE_SENT;
+ }
+
+ CRPiCECAdapterMessageQueueEntry *entry = new CRPiCECAdapterMessageQueueEntry(this, command);
+ uint64_t iEntryId(0);
+ /* add to the wait for ack queue */
+ {
+ CLockObject lock(m_mutex);
+ iEntryId = m_iNextMessage++;
+ m_messages.insert(std::make_pair(iEntryId, entry));
+ }
+
+#if defined(RPI_USE_SEND_MESSAGE2)
+ VC_CEC_MESSAGE_T message;
+ message.initiator = (CEC_AllDevices_T)command.initiator;
+ message.follower = (CEC_AllDevices_T)command.destination;
+ message.length = 1;
+
+ if (command.opcode_set)
+ {
+ message.length += 1;
+ message.payload[0] = command.opcode;
+
+ message.length += command.parameters.size;
+ for (uint8_t iPtr = 0; iPtr < command.parameters.size; iPtr++)
+ message.payload[iPtr + 1] = command.parameters.At(iPtr);
+ }
+
+#ifdef CEC_DEBUGGING
+ std::string strDump;
+ strDump = StringUtils::Format("len = %d, payload = %X%X", message.length, (int)message.initiator, (int)message.follower);
+ for (uint8_t iPtr = 0; iPtr < message.length - 1; iPtr++)
+ strDump += StringUtils::Format(":%02X", message.payload[iPtr]);
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "sending data: %s", strDump.c_str());
+#endif
+
+ int iReturn = vc_cec_send_message2(&message);
+#else
+ uint8_t payload[32];
+ uint32_t iLength(0);
+
+ if (command.opcode_set)
+ {
+ iLength += 1;
+ payload[0] = command.opcode;
+
+ iLength += command.parameters.size;
+ for (uint8_t iPtr = 0; iPtr < command.parameters.size; iPtr++)
+ payload[iPtr + 1] = command.parameters.At(iPtr);
+ }
+
+#ifdef CEC_DEBUGGING
+ std:string strDump;
+ strDump = StringUtils::Format("len = %d, payload = %X%X", iLength, (int)command.initiator, (int)command.destination);
+ for (uint8_t iPtr = 0; iPtr < iLength; iPtr++)
+ strDump += StringUtils::Format(":%02X", payload[iPtr]);
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "sending data: %s", strDump.c_str());
+#endif
+
+ int iReturn = vc_cec_send_message((uint32_t)command.destination, command.opcode_set ? (uint8_t*)&payload : NULL, iLength, bIsReply);
+#endif
+
+ bRetry = false;
+ if (iReturn != VCHIQ_SUCCESS)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "sending command '%s' failed (%d)", CCECTypeUtils::ToString(command.opcode), iReturn);
+ delete entry;
+ m_messages.erase(iEntryId);
+ return ADAPTER_MESSAGE_STATE_ERROR;
+ }
+
+ cec_adapter_message_state bReturn(ADAPTER_MESSAGE_STATE_ERROR);
+ if (entry)
+ {
+ if (entry->Wait(iLineTimeout))
+ {
+ int status = entry->Result();
+
+ if (status == VC_CEC_ERROR_NO_ACK)
+ bReturn = ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED;
+ else if (status == VC_CEC_SUCCESS)
+ bReturn = ADAPTER_MESSAGE_STATE_SENT_ACKED;
+ else
+ bReturn = ADAPTER_MESSAGE_STATE_SENT;
+ }
+ else
+ {
+ bRetry = true;
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "command '%s' timeout", CCECTypeUtils::ToString(command.opcode));
+ CEvent::Sleep(CEC_DEFAULT_TRANSMIT_RETRY_WAIT);
+ bReturn = ADAPTER_MESSAGE_STATE_WAITING_TO_BE_SENT;
+ }
+
+ vcReply = (VC_CEC_ERROR_T)entry->Result();
+
+ CLockObject lock(m_mutex);
+ m_messages.erase(iEntryId);
+ delete entry;
+ }
+
+ return bReturn;
+}
+
+#endif
+
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include <p8-platform/util/buffer.h>
+#include <map>
+#include "adapter/AdapterCommunication.h"
+
+extern "C" {
+#include <interface/vmcs_host/vc_cecservice.h>
+#include <interface/vchiq_arm/vchiq_if.h>
+}
+
+namespace CEC
+{
+ class CRPiCECAdapterCommunication;
+ class CRPiCECAdapterMessageQueue;
+
+ class CRPiCECAdapterMessageQueueEntry
+ {
+ public:
+ CRPiCECAdapterMessageQueueEntry(CRPiCECAdapterMessageQueue *queue, const cec_command &command);
+ virtual ~CRPiCECAdapterMessageQueueEntry(void) {}
+
+ /*!
+ * @brief Signal waiting threads
+ */
+ void Broadcast(void);
+
+ bool MessageReceived(cec_opcode opcode, cec_logical_address initiator, cec_logical_address destination, uint32_t response);
+
+ /*!
+ * @brief Wait for a response to this command.
+ * @param iTimeout The timeout to use while waiting.
+ * @return True when a response was received before the timeout passed, false otherwise.
+ */
+ bool Wait(uint32_t iTimeout);
+
+ /*!
+ * @return True while a thread is waiting for a signal or isn't waiting yet, false otherwise.
+ */
+ bool IsWaiting(void);
+
+ /*!
+ * @brief Query result from worker thread
+ */
+ uint32_t Result() const;
+
+ /*!
+ * @return The command that was sent in human readable form.
+ */
+ const char *ToString(void) const { return "CEC transmission"; }
+
+ CRPiCECAdapterMessageQueue * m_queue;
+ bool m_bWaiting; /**< true while a thread is waiting or when it hasn't started waiting yet */
+ P8PLATFORM::CCondition<bool> m_condition; /**< the condition to wait on */
+ P8PLATFORM::CMutex m_mutex; /**< mutex for changes to this class */
+ cec_command m_command;
+ uint32_t m_retval;
+ bool m_bSucceeded;
+ };
+
+ class CRPiCECAdapterMessageQueue
+ {
+ friend class CRPiCECAdapterMessageQueueEntry;
+
+ public:
+ /*!
+ * @brief Create a new message queue.
+ * @param com The communication handler callback to use.
+ * @param iQueueSize The outgoing message queue size.
+ */
+ CRPiCECAdapterMessageQueue(CRPiCECAdapterCommunication *com) :
+ m_com(com),
+ m_iNextMessage(0)
+ {
+ }
+
+ virtual ~CRPiCECAdapterMessageQueue(void)
+ {
+ Clear();
+ }
+
+ /*!
+ * @brief Signal and delete everything in the queue
+ */
+ void Clear(void);
+
+ void MessageReceived(cec_opcode opcode, cec_logical_address initiator, cec_logical_address destination, uint32_t response);
+
+ cec_adapter_message_state Write(const cec_command &command, bool &bRetry, uint32_t iLineTimeout, bool bIsReply, VC_CEC_ERROR_T &vcReply);
+
+ private:
+ CRPiCECAdapterCommunication * m_com; /**< the communication handler */
+ P8PLATFORM::CMutex m_mutex; /**< mutex for changes to this class */
+ std::map<uint64_t, CRPiCECAdapterMessageQueueEntry *> m_messages; /**< the outgoing message queue */
+ uint64_t m_iNextMessage; /**< the index of the next message */
+ };
+};
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include <p8-platform/threads/mutex.h>
+
+namespace CEC
+{
+ using namespace P8PLATFORM;
+
+ class CAdapterMessageQueueEntry
+ {
+ public:
+ CAdapterMessageQueueEntry(const cec_command &command)
+ : m_bWaiting(true), m_retval((uint32_t)-1), m_bSucceeded(false)
+ {
+ m_hash = hashValue(
+ uint32_t(command.opcode_set ? command.opcode : CEC_OPCODE_NONE),
+ command.initiator, command.destination);
+ }
+
+ virtual ~CAdapterMessageQueueEntry(void) {}
+
+ /*!
+ * @brief Query result from worker thread
+ */
+ uint32_t Result() const
+ {
+ return m_retval;
+ }
+
+ /*!
+ * @brief Signal waiting threads
+ */
+ void Broadcast(void)
+ {
+ CLockObject lock(m_mutex);
+ m_condition.Broadcast();
+ }
+
+ /*!
+ * @brief Signal waiting thread(s) when message matches this entry
+ */
+ bool CheckMatch(uint32_t opcode, cec_logical_address initiator,
+ cec_logical_address destination, uint32_t response)
+ {
+ uint32_t hash = hashValue(opcode, initiator, destination);
+
+ if (hash == m_hash)
+ {
+ CLockObject lock(m_mutex);
+
+ m_retval = response;
+ m_bSucceeded = true;
+ m_condition.Signal();
+ return true;
+ }
+
+ return false;
+ }
+
+ /*!
+ * @brief Wait for a response to this command.
+ * @param iTimeout The timeout to use while waiting.
+ * @return True when a response was received before the timeout passed, false otherwise.
+ */
+ bool Wait(uint32_t iTimeout)
+ {
+ CLockObject lock(m_mutex);
+
+ bool bReturn = m_bSucceeded ? true : m_condition.Wait(m_mutex, m_bSucceeded, iTimeout);
+ m_bWaiting = false;
+ return bReturn;
+ }
+
+ /*!
+ * @return True while a thread is waiting for a signal or isn't waiting yet, false otherwise.
+ */
+ bool IsWaiting(void)
+ {
+ CLockObject lock(m_mutex);
+ return m_bWaiting;
+ }
+
+ /*!
+ * @return Hash value for given cec_command
+ */
+ static uint32_t hashValue(uint32_t opcode,
+ cec_logical_address initiator,
+ cec_logical_address destination)
+ {
+ return 1 | ((uint32_t)initiator << 8) |
+ ((uint32_t)destination << 16) | ((uint32_t)opcode << 16);
+ }
+
+ private:
+ bool m_bWaiting; /**< true while a thread is waiting or when it hasn't started waiting yet */
+ P8PLATFORM::CCondition<bool> m_condition; /**< the condition to wait on */
+ P8PLATFORM::CMutex m_mutex; /**< mutex for changes to this class */
+ uint32_t m_hash;
+ uint32_t m_retval;
+ bool m_bSucceeded;
+ };
+
+};
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+
+#if defined(HAVE_TDA995X_API)
+#include "TDA995xCECAdapterCommunication.h"
+
+#include "CECTypeUtils.h"
+#include "LibCEC.h"
+#include <p8-platform/sockets/cdevsocket.h>
+#include <p8-platform/util/buffer.h>
+
+extern "C" {
+#define __cec_h__
+#include <comps/tmdlHdmiCEC/inc/tmdlHdmiCEC_Types.h>
+#include <tda998x_ioctl.h>
+}
+
+using namespace CEC;
+using namespace P8PLATFORM;
+
+#include "AdapterMessageQueue.h"
+
+#define LIB_CEC m_callback->GetLib()
+
+// these are defined in nxp private header file
+#define CEC_MSG_SUCCESS 0x00 /*Message transmisson Succeed*/
+#define CEC_CSP_OFF_STATE 0x80 /*CSP in Off State*/
+#define CEC_BAD_REQ_SERVICE 0x81 /*Bad .req service*/
+#define CEC_MSG_FAIL_UNABLE_TO_ACCESS 0x82 /*Message transmisson failed: Unable to access CEC line*/
+#define CEC_MSG_FAIL_ARBITRATION_ERROR 0x83 /*Message transmisson failed: Arbitration error*/
+#define CEC_MSG_FAIL_BIT_TIMMING_ERROR 0x84 /*Message transmisson failed: Bit timming error*/
+#define CEC_MSG_FAIL_DEST_NOT_ACK 0x85 /*Message transmisson failed: Destination Address not aknowledged*/
+#define CEC_MSG_FAIL_DATA_NOT_ACK 0x86 /*Message transmisson failed: Databyte not acknowledged*/
+
+
+CTDA995xCECAdapterCommunication::CTDA995xCECAdapterCommunication(IAdapterCommunicationCallback *callback) :
+ IAdapterCommunication(callback),
+ m_bLogicalAddressChanged(false)
+{
+ CLockObject lock(m_mutex);
+
+ m_iNextMessage = 0;
+ m_logicalAddresses.Clear();
+ m_dev = new CCDevSocket(CEC_TDA995x_PATH);
+}
+
+
+CTDA995xCECAdapterCommunication::~CTDA995xCECAdapterCommunication(void)
+{
+ Close();
+
+ CLockObject lock(m_mutex);
+ delete m_dev;
+ m_dev = 0;
+}
+
+
+bool CTDA995xCECAdapterCommunication::IsOpen(void)
+{
+ return IsInitialised() && m_dev->IsOpen();
+}
+
+
+bool CTDA995xCECAdapterCommunication::Open(uint32_t iTimeoutMs, bool UNUSED(bSkipChecks), bool bStartListening)
+{
+ if (m_dev->Open(iTimeoutMs))
+ {
+ unsigned char raw_mode = 0xff;
+
+ if (m_dev->Ioctl(CEC_IOCTL_GET_RAW_MODE, &raw_mode) == 0)
+ {
+ raw_mode = 1;
+ if (m_dev->Ioctl(CEC_IOCTL_SET_RAW_MODE, &raw_mode) == 0)
+ {
+ if (!bStartListening || CreateThread())
+ return true;
+ }
+ else
+ {
+ LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: CEC_IOCTL_SET_RAW_MODE failed !", __func__);
+ }
+
+ raw_mode = 0;
+ m_dev->Ioctl(CEC_IOCTL_SET_RAW_MODE, &raw_mode);
+ }
+ else
+ {
+ LIB_CEC->AddLog(CEC_LOG_ERROR,
+ "%s: CEC_IOCTL_GET_RAW_MODE not supported. Please update your kernel.", __func__);
+ }
+
+ m_dev->Close();
+ }
+
+ return false;
+}
+
+
+void CTDA995xCECAdapterCommunication::Close(void)
+{
+ StopThread(0);
+
+ unsigned char raw_mode = 0;
+ m_dev->Ioctl(CEC_IOCTL_SET_RAW_MODE, &raw_mode);
+
+ m_dev->Close();
+}
+
+
+std::string CTDA995xCECAdapterCommunication::GetError(void) const
+{
+ std::string strError(m_strError);
+ return strError;
+}
+
+
+cec_adapter_message_state CTDA995xCECAdapterCommunication::Write(
+ const cec_command &data, bool &UNUSED(bRetry), uint8_t UNUSED(iLineTimeout), bool UNUSED(bIsReply))
+{
+ cec_frame frame;
+ CAdapterMessageQueueEntry *entry;
+ cec_adapter_message_state rc = ADAPTER_MESSAGE_STATE_ERROR;
+
+ if ((size_t)data.parameters.size + data.opcode_set > sizeof(frame.data))
+ {
+ LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: data size too large !", __func__);
+ return ADAPTER_MESSAGE_STATE_ERROR;
+ }
+
+ frame.size = 0;
+ frame.service = 0;
+ frame.addr = (data.initiator << 4) | (data.destination & 0x0f);
+
+ if (data.opcode_set)
+ {
+ frame.data[0] = data.opcode;
+ frame.size++;
+
+ memcpy(&frame.data[frame.size], data.parameters.data, data.parameters.size);
+ frame.size += data.parameters.size;
+ }
+
+ frame.size += 3;
+
+ entry = new CAdapterMessageQueueEntry(data);
+
+ m_messageMutex.Lock();
+ uint32_t msgKey = ++m_iNextMessage;
+ m_messages.insert(std::make_pair(msgKey, entry));
+
+ if (m_dev->Write((char *)&frame, sizeof(frame)) == sizeof(frame))
+ {
+ m_messageMutex.Unlock();
+
+ if (entry->Wait(CEC_DEFAULT_TRANSMIT_WAIT))
+ {
+ uint32_t status = entry->Result();
+
+ if (status == CEC_MSG_FAIL_DEST_NOT_ACK)
+ rc = ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED;
+ else if (status == CEC_MSG_SUCCESS)
+ rc = ADAPTER_MESSAGE_STATE_SENT_ACKED;
+ }
+ else
+ LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: command timed out !", __func__);
+
+ m_messageMutex.Lock();
+ }
+ else
+ LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: write failed !", __func__);
+
+ m_messages.erase(msgKey);
+ m_messageMutex.Unlock();
+
+ delete entry;
+
+ return rc;
+}
+
+
+uint16_t CTDA995xCECAdapterCommunication::GetFirmwareVersion(void)
+{
+ cec_sw_version vers = { 0 };
+
+ m_dev->Ioctl(CEC_IOCTL_GET_SW_VERSION, &vers);
+
+ return vers.majorVersionNr;
+}
+
+
+cec_vendor_id CTDA995xCECAdapterCommunication::GetVendorId(void)
+{
+ cec_raw_info info;
+
+ if (m_dev->Ioctl(CEC_IOCTL_GET_RAW_INFO, &info) != 0)
+ {
+ LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: CEC_IOCTL_GET_RAW_INFO failed !", __func__);
+ return CEC_VENDOR_LG;
+ }
+
+ return cec_vendor_id(info.VendorID);
+}
+
+
+uint16_t CTDA995xCECAdapterCommunication::GetPhysicalAddress(void)
+{
+ cec_raw_info info;
+
+ if (m_dev->Ioctl(CEC_IOCTL_GET_RAW_INFO, &info) != 0)
+ {
+ LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: CEC_IOCTL_GET_RAW_INFO failed !", __func__);
+ return CEC_INVALID_PHYSICAL_ADDRESS;
+ }
+
+ return info.PhysicalAddress;
+}
+
+
+cec_logical_addresses CTDA995xCECAdapterCommunication::GetLogicalAddresses(void)
+{
+ CLockObject lock(m_mutex);
+
+ if (m_bLogicalAddressChanged || m_logicalAddresses.IsEmpty() )
+ {
+ cec_raw_info info;
+
+ m_logicalAddresses.Clear();
+
+ if (m_dev->Ioctl(CEC_IOCTL_GET_RAW_INFO, &info) != 0)
+ {
+ LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: CEC_IOCTL_GET_RAW_INFO failed !", __func__);
+ }
+ else if (info.LogicalAddress != CECDEVICE_UNREGISTERED)
+ {
+ m_logicalAddresses.Set(cec_logical_address(info.LogicalAddress));
+
+ for (int la = CECDEVICE_TV; la < CECDEVICE_BROADCAST; la++)
+ {
+ m_logicalAddresses.Set(cec_logical_address(la));
+ }
+ }
+
+ m_bLogicalAddressChanged = false;
+ }
+
+ return m_logicalAddresses;
+}
+
+
+bool CTDA995xCECAdapterCommunication::SetLogicalAddresses(const cec_logical_addresses &addresses)
+{
+ unsigned char log_addr = addresses.primary;
+
+ if (m_dev->Ioctl(CEC_IOCTL_RX_ADDR, &log_addr) != 0)
+ {
+ LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: CEC_IOCTL_RX_ADDR failed !", __func__);
+ return false;
+ }
+
+ cec_rx_mask all_addresses;
+
+ all_addresses.SwitchOn = addresses.AckMask() & 0x7fff;
+ all_addresses.SwitchOff = ~all_addresses.SwitchOn;
+
+ if (all_addresses.SwitchOn != (1 << addresses.primary) &&
+ m_dev->Ioctl(CEC_IOCTL_SET_RX_ADDR_MASK, &all_addresses) != 0)
+ {
+ LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: CEC_IOCTL_SET_RX_ADDR_MASK failed !", __func__);
+ return false;
+ }
+
+ m_bLogicalAddressChanged = true;
+
+ return true;
+}
+
+
+void CTDA995xCECAdapterCommunication::HandleLogicalAddressLost(cec_logical_address UNUSED(oldAddress))
+{
+ unsigned char log_addr = CECDEVICE_BROADCAST;
+
+ if (m_dev->Ioctl(CEC_IOCTL_RX_ADDR, &log_addr) != 0)
+ {
+ LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: CEC_IOCTL_RX_ADDR failed !", __func__);
+ }
+}
+
+
+void *CTDA995xCECAdapterCommunication::Process(void)
+{
+ bool bHandled;
+ cec_frame frame;
+ uint32_t opcode, status;
+ cec_logical_address initiator, destination;
+
+ while (!IsStopped())
+ {
+ if (m_dev->Read((char *)&frame, sizeof(frame), 500) == sizeof(frame))
+ {
+ initiator = cec_logical_address(frame.addr >> 4);
+ destination = cec_logical_address(frame.addr & 0x0f);
+
+ if (frame.service == CEC_RX_PKT)
+ {
+ cec_command cmd;
+
+ cec_command::Format(
+ cmd, initiator, destination,
+ ( frame.size > 3 ) ? cec_opcode(frame.data[0]) : CEC_OPCODE_NONE);
+
+ for( uint8_t i = 1; i < frame.size-3; i++ )
+ cmd.parameters.PushBack(frame.data[i]);
+
+ if (!IsStopped())
+ m_callback->OnCommandReceived(cmd);
+ }
+ else if (frame.service == CEC_ACK_PKT)
+ {
+ bHandled = false;
+ status = ( frame.size > 3 ) ? frame.data[0] : 255;
+ opcode = ( frame.size > 4 ) ? frame.data[1] : (uint32_t)CEC_OPCODE_NONE;
+
+ m_messageMutex.Lock();
+ for (std::map<uint32_t, CAdapterMessageQueueEntry *>::iterator it = m_messages.begin();
+ !bHandled && it != m_messages.end(); it++)
+ {
+ bHandled = it->second->CheckMatch(opcode, initiator, destination, status);
+ }
+ m_messageMutex.Unlock();
+
+ if (!bHandled)
+ LIB_CEC->AddLog(CEC_LOG_WARNING, "%s: unhandled response received !", __func__);
+ }
+ }
+ }
+
+ return 0;
+}
+
+#endif // HAVE_TDA995X_API
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#if defined(HAVE_TDA995X_API)
+
+#include <p8-platform/threads/mutex.h>
+#include <p8-platform/threads/threads.h>
+#include <p8-platform/sockets/socket.h>
+#include "adapter/AdapterCommunication.h"
+#include <map>
+
+#define TDA995X_ADAPTER_VID 0x0471
+#define TDA995X_ADAPTER_PID 0x1001
+
+namespace P8PLATFORM
+{
+ class CCDevSocket;
+};
+
+
+namespace CEC
+{
+ class CAdapterMessageQueueEntry;
+
+ class CTDA995xCECAdapterCommunication : public IAdapterCommunication, public P8PLATFORM::CThread
+ {
+ public:
+ /*!
+ * @brief Create a new USB-CEC communication handler.
+ * @param callback The callback to use for incoming CEC commands.
+ */
+ CTDA995xCECAdapterCommunication(IAdapterCommunicationCallback *callback);
+ virtual ~CTDA995xCECAdapterCommunication(void);
+
+ /** @name IAdapterCommunication implementation */
+ ///{
+ bool Open(uint32_t iTimeoutMs = CEC_DEFAULT_CONNECT_TIMEOUT, bool bSkipChecks = false, bool bStartListening = true);
+ void Close(void);
+ bool IsOpen(void);
+ std::string GetError(void) const;
+ cec_adapter_message_state Write(const cec_command &data, bool &bRetry, uint8_t iLineTimeout, bool bIsReply);
+
+ bool SetLineTimeout(uint8_t UNUSED(iTimeout)) { return true; }
+ bool StartBootloader(void) { return false; }
+ bool SetLogicalAddresses(const cec_logical_addresses &addresses);
+ cec_logical_addresses GetLogicalAddresses(void);
+ bool PingAdapter(void) { return IsInitialised(); }
+ uint16_t GetFirmwareVersion(void);
+ uint32_t GetFirmwareBuildDate(void) { return 0; }
+ bool IsRunningLatestFirmware(void) { return true; }
+ bool PersistConfiguration(const libcec_configuration & UNUSED(configuration)) { return false; }
+ bool GetConfiguration(libcec_configuration & UNUSED(configuration)) { return false; }
+ std::string GetPortName(void) { return std::string("TDA995X"); }
+ uint16_t GetPhysicalAddress(void);
+ bool SetControlledMode(bool UNUSED(controlled)) { return true; }
+ cec_vendor_id GetVendorId(void);
+ bool SupportsSourceLogicalAddress(const cec_logical_address address) { return address > CECDEVICE_TV && address <= CECDEVICE_BROADCAST; }
+ cec_adapter_type GetAdapterType(void) { return ADAPTERTYPE_TDA995x; }
+ uint16_t GetAdapterVendorId(void) const { return TDA995X_ADAPTER_VID; }
+ uint16_t GetAdapterProductId(void) const { return TDA995X_ADAPTER_PID; }
+ void HandleLogicalAddressLost(cec_logical_address oldAddress);
+ void SetActiveSource(bool UNUSED(bSetTo), bool UNUSED(bClientUnregistered)) {}
+ ///}
+
+ /** @name P8PLATFORM::CThread implementation */
+ ///{
+ void *Process(void);
+ ///}
+
+ private:
+ bool IsInitialised(void) const { return m_dev != 0; };
+
+ std::string m_strError; /**< current error message */
+
+ bool m_bLogicalAddressChanged;
+ cec_logical_addresses m_logicalAddresses;
+
+ P8PLATFORM::CMutex m_mutex;
+ P8PLATFORM::CCDevSocket *m_dev; /**< the device connection */
+
+ P8PLATFORM::CMutex m_messageMutex;
+ uint32_t m_iNextMessage;
+ std::map<uint32_t, CAdapterMessageQueueEntry *> m_messages;
+ };
+
+};
+
+#endif
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include <stdio.h>
+
+#if defined(HAVE_TDA995X_API)
+#include "TDA995xCECAdapterDetection.h"
+
+extern "C" {
+#define __cec_h__
+#include <comps/tmdlHdmiCEC/inc/tmdlHdmiCEC_Types.h>
+#include <tda998x_ioctl.h>
+}
+
+using namespace CEC;
+
+bool CTDA995xCECAdapterDetection::FindAdapter(void)
+{
+ return access(CEC_TDA995x_PATH, 0) == 0;
+}
+
+#endif
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+namespace CEC
+{
+ class CTDA995xCECAdapterDetection
+ {
+ public:
+ static bool FindAdapter(void);
+ };
+}
--- /dev/null
+# - Check for platform support and set variables and definitions
+#
+# This module sets the following variables
+# PLATFORM_LIBREQUIRES dependencies
+# LIB_INFO supported features and compilation information
+# LIB_DESTINATION destination for the .so/.dll files
+# HAVE_RANDR ON if xrandr is supported
+# HAVE_LIBUDEV ON if udev is supported
+# HAVE_RPI_API ON if Raspberry Pi is supported
+# HAVE_TDA995X_API ON if TDA995X is supported
+# HAVE_EXYNOS_API ON if Exynos is supported
+# HAVE_AOCEC_API ON if AOCEC is supported
+# HAVE_P8_USB ON if Pulse-Eight devices are supported
+# HAVE_P8_USB_DETECT ON if Pulse-Eight devices can be auto-detected
+# HAVE_DRM_EDID_PARSER ON if DRM EDID parsing is supported
+#
+
+set(RPI_LIB_DIR "" CACHE STRING "Path to Raspberry Pi libraries")
+set(RPI_INCLUDE_DIR "" CACHE STRING "Path to Raspberry Pi headers")
+
+set(PLATFORM_LIBREQUIRES "")
+
+include(CheckFunctionExists)
+include(FindPkgConfig)
+
+# defaults
+SET(HAVE_RANDR OFF CACHE BOOL "xrandr not supported")
+SET(HAVE_LIBUDEV OFF CACHE BOOL "udev not supported")
+SET(HAVE_RPI_API OFF CACHE BOOL "raspberry pi not supported")
+SET(HAVE_TDA995X_API OFF CACHE BOOL "tda995x not supported")
+SET(HAVE_EXYNOS_API OFF CACHE BOOL "exynos not supported")
+SET(HAVE_AOCEC_API OFF CACHE BOOL "aocec not supported")
+# Pulse-Eight devices are always supported
+set(HAVE_P8_USB ON CACHE BOOL "p8 usb-cec supported" FORCE)
+set(HAVE_P8_USB_DETECT OFF CACHE BOOL "p8 usb-cec detection not supported")
+set(HAVE_DRM_EDID_PARSER OFF CACHE BOOL "drm edid parser not supported")
+# Raspberry Pi libs and headers are in a non-standard path on some distributions
+set(RPI_INCLUDE_DIR "" CACHE FILEPATH "root path to Raspberry Pi includes")
+set(RPI_LIB_DIR "" CACHE FILEPATH "root path to Raspberry Pi libs")
+
+if(WIN32)
+ # Windows
+ add_definitions(-DTARGET_WINDOWS -DNOMINMAX -D_CRT_SECURE_NO_WARNINGS -D_WINSOCKAPI_)
+ set(LIB_DESTINATION ".")
+ if (${WIN64})
+ set(LIB_INFO "${LIB_INFO} (x64)")
+ else()
+ add_definitions(-D_USE_32BIT_TIME_T)
+ endif()
+ set(HAVE_P8_USB_DETECT ON CACHE BOOL "p8 usb-cec detection supported" FORCE)
+ set(LIB_INFO "${LIB_INFO}, features: P8_USB, P8_detect")
+
+ list(APPEND CEC_SOURCES_PLATFORM platform/windows/os-edid.cpp
+ platform/windows/serialport.cpp)
+ list(APPEND CEC_SOURCES LibCECDll.cpp
+ libcec.rc)
+else()
+ # not Windows
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-missing-field-initializers")
+ list(APPEND CEC_SOURCES_PLATFORM platform/posix/os-edid.cpp
+ platform/posix/serialport.cpp)
+ set(LIB_DESTINATION "${CMAKE_INSTALL_LIBDIR}")
+ set(LIB_INFO "${LIB_INFO}, features: P8_USB")
+
+ # always try DRM on Linux if other methods fail
+ if(NOT CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
+ set(HAVE_DRM_EDID_PARSER ON CACHE BOOL "drm edid parser not supported" FORCE)
+ set(LIB_INFO "${LIB_INFO}, DRM")
+ endif()
+
+ # flock
+ check_include_files(sys/file.h HAVE_SYS_FILE_HEADER)
+ check_function_exists(flock HAVE_FLOCK)
+
+ # udev
+ pkg_check_modules(UDEV udev)
+ if (UDEV_FOUND)
+ set(PLATFORM_LIBREQUIRES "${PLATFORM_LIBREQUIRES} ${UDEV_LIBRARIES}")
+ else()
+ # fall back to finding libudev.pc
+ pkg_check_modules(UDEV libudev)
+ if (UDEV_FOUND)
+ set(PLATFORM_LIBREQUIRES "${PLATFORM_LIBREQUIRES} libudev")
+ endif()
+ endif()
+ if (UDEV_FOUND)
+ SET(HAVE_LIBUDEV ON CACHE BOOL "udev supported" FORCE)
+ set(LIB_INFO "${LIB_INFO}, P8_detect")
+ list(APPEND CMAKE_REQUIRED_LIBRARIES "${UDEV_LIBRARIES}")
+ set(HAVE_P8_USB_DETECT ON CACHE BOOL "p8 usb-cec detection supported" FORCE)
+ endif()
+
+ # xrandr
+ check_include_files("X11/Xlib.h;X11/Xatom.h;X11/extensions/Xrandr.h" HAVE_RANDR_HEADERS)
+ check_library_exists(Xrandr XRRGetScreenResources "" HAVE_RANDR_LIB)
+ if (HAVE_RANDR_HEADERS AND HAVE_RANDR_LIB)
+ set(LIB_INFO "${LIB_INFO}, randr")
+ list(APPEND CEC_SOURCES_PLATFORM platform/X11/randr-edid.cpp)
+ SET(HAVE_RANDR ON CACHE BOOL "xrandr supported" FORCE)
+ endif()
+
+ # raspberry pi
+ find_library(RPI_BCM_HOST bcm_host "${RPI_LIB_DIR}")
+ check_library_exists(bcm_host bcm_host_init "${RPI_LIB_DIR}" HAVE_RPI_LIB)
+ if (HAVE_RPI_LIB)
+ SET(HAVE_RPI_API ON CACHE BOOL "raspberry pi supported" FORCE)
+ find_library(RPI_VCOS vcos "${RPI_LIB_DIR}")
+ find_library(RPI_VCHIQ_ARM vchiq_arm "${RPI_LIB_DIR}")
+ include_directories(${RPI_INCLUDE_DIR} ${RPI_INCLUDE_DIR}/interface/vcos/pthreads ${RPI_INCLUDE_DIR}/interface/vmcs_host/linux)
+
+ set(LIB_INFO "${LIB_INFO}, RPi")
+ set(CEC_SOURCES_ADAPTER_RPI adapter/RPi/RPiCECAdapterDetection.cpp
+ adapter/RPi/RPiCECAdapterCommunication.cpp
+ adapter/RPi/RPiCECAdapterMessageQueue.cpp)
+ source_group("Source Files\\adapter\\RPi" FILES ${CEC_SOURCES_ADAPTER_RPI})
+ list(APPEND CEC_SOURCES ${CEC_SOURCES_ADAPTER_RPI})
+ endif()
+
+ # TDA995x
+ check_include_files("tda998x_ioctl.h;comps/tmdlHdmiCEC/inc/tmdlHdmiCEC_Types.h" HAVE_TDA995X_API_INC)
+ if (HAVE_TDA995X_API_INC)
+ SET(HAVE_TDA995X_API ON CACHE BOOL "tda995x supported" FORCE)
+ set(LIB_INFO "${LIB_INFO}, TDA995x")
+ set(CEC_SOURCES_ADAPTER_TDA995x adapter/TDA995x/TDA995xCECAdapterDetection.cpp
+ adapter/TDA995x/TDA995xCECAdapterCommunication.cpp)
+ source_group("Source Files\\adapter\\TDA995x" FILES ${CEC_SOURCES_ADAPTER_TDA995x})
+ list(APPEND CEC_SOURCES ${CEC_SOURCES_ADAPTER_TDA995x})
+ endif()
+
+ # Exynos
+ if (${HAVE_EXYNOS_API})
+ set(LIB_INFO "${LIB_INFO}, Exynos")
+ SET(HAVE_EXYNOS_API ON CACHE BOOL "exynos supported" FORCE)
+ set(CEC_SOURCES_ADAPTER_EXYNOS adapter/Exynos/ExynosCECAdapterDetection.cpp
+ adapter/Exynos/ExynosCECAdapterCommunication.cpp)
+ source_group("Source Files\\adapter\\Exynos" FILES ${CEC_SOURCES_ADAPTER_EXYNOS})
+ list(APPEND CEC_SOURCES ${CEC_SOURCES_ADAPTER_EXYNOS})
+ endif()
+
+ # AOCEC
+ if (${HAVE_AOCEC_API})
+ set(LIB_INFO "${LIB_INFO}, AOCEC")
+ SET(HAVE_AOCEC_API ON CACHE BOOL "AOCEC supported" FORCE)
+ set(CEC_SOURCES_ADAPTER_AOCEC adapter/AOCEC/AOCECAdapterDetection.cpp
+ adapter/AOCEC/AOCECAdapterCommunication.cpp)
+ source_group("Source Files\\adapter\\AOCEC" FILES ${CEC_SOURCES_ADAPTER_AOCEC})
+ list(APPEND CEC_SOURCES ${CEC_SOURCES_ADAPTER_AOCEC})
+ else()
+ set(HAVE_AOCEC_API 0)
+ endif()
+endif()
+
+# rt
+check_library_exists(rt clock_gettime "" HAVE_RT)
+
+# check for dlopen
+check_library_exists(dl dlopen "" HAVE_DLOPEN)
+
+SET(SKIP_PYTHON_WRAPPER 0 CACHE STRING "Define to 1 to not generate the Python wrapper")
+
+if (${SKIP_PYTHON_WRAPPER})
+ message(STATUS "Not generating Python wrapper")
+else()
+ # Python
+ include(FindPythonLibs)
+ find_package(PythonLibs)
+
+ # Swig
+ find_package(SWIG)
+ if (PYTHONLIBS_FOUND AND SWIG_FOUND)
+ set(CMAKE_SWIG_FLAGS "-threads")
+ set(HAVE_PYTHON 1)
+ if ("${PYTHONLIBS_VERSION_STRING}" STREQUAL "")
+ message(STATUS "Python version not found, defaulting to 2.7")
+ set(PYTHONLIBS_VERSION_STRING "2.7.x")
+ set(PYTHON_VERSION "2.7")
+ else()
+ string(REGEX REPLACE "\\.[0-9]+\\+?$" "" PYTHON_VERSION ${PYTHONLIBS_VERSION_STRING})
+ endif()
+
+ include(${SWIG_USE_FILE})
+ include_directories(${PYTHON_INCLUDE_PATH})
+ include_directories(${CMAKE_CURRENT_SOURCE_DIR})
+
+ SET_SOURCE_FILES_PROPERTIES(libcec.i PROPERTIES CPLUSPLUS ON)
+ swig_add_module(cec python libcec.i)
+ swig_link_libraries(cec ${PYTHON_LIBRARIES})
+ swig_link_libraries(cec cec)
+
+ if(WIN32)
+ install(TARGETS ${SWIG_MODULE_cec_REAL_NAME}
+ DESTINATION python/cec)
+ install(FILES ${CMAKE_BINARY_DIR}/src/libcec/cec.py
+ DESTINATION python/cec
+ RENAME __init__.py)
+ else()
+ if(EXISTS "/etc/lsb-release")
+ SET(PYTHON_PKG_DIR "dist-packages")
+ else()
+ SET(PYTHON_PKG_DIR "site-packages")
+ endif()
+ install(TARGETS ${SWIG_MODULE_cec_REAL_NAME}
+ DESTINATION lib/python${PYTHON_VERSION}/${PYTHON_PKG_DIR}/cec)
+ install(FILES ${CMAKE_BINARY_DIR}/src/libcec/cec.py
+ DESTINATION lib/python${PYTHON_VERSION}/${PYTHON_PKG_DIR}/cec
+ RENAME __init__.py)
+ endif()
+ endif()
+endif()
--- /dev/null
+# - Display platform support found by CheckPlatformSupport.cmake
+
+message(STATUS "Configured features:")
+
+if (HAVE_P8_USB)
+ message(STATUS "Pulse-Eight CEC Adapter: yes")
+else()
+ message(STATUS "Pulse-Eight CEC Adapter: no")
+endif()
+
+if (HAVE_P8_USB_DETECT)
+ message(STATUS "Pulse-Eight CEC Adapter detection: yes")
+else()
+ message(STATUS "Pulse-Eight CEC Adapter detection: no")
+endif()
+
+if (HAVE_RANDR)
+ message(STATUS "xrandr support: yes")
+else()
+ message(STATUS "xrandr support: no")
+endif()
+
+if (HAVE_RPI_API)
+ message(STATUS "Raspberry Pi support: yes")
+else()
+ message(STATUS "Raspberry Pi support: no")
+endif()
+
+if (HAVE_TDA995X_API)
+ message(STATUS "TDA995x support: yes")
+else()
+ message(STATUS "TDA995x support: no")
+endif()
+
+if (HAVE_EXYNOS_API)
+ message(STATUS "Exynos support: yes")
+else()
+ message(STATUS "Exynos support: no")
+endif()
+
+if (HAVE_DRM_EDID_PARSER)
+ message(STATUS "DRM support: yes")
+else()
+ message(STATUS "DRM support: no")
+endif()
+
+if (HAVE_AOCEC_API)
+ message(STATUS "AOCEC support: yes")
+else()
+ message(STATUS "AOCEC support: no")
+endif()
+
+if (HAVE_PYTHON)
+ message(STATUS "Python support: version ${PYTHONLIBS_VERSION_STRING} (${PYTHON_VERSION})")
+else()
+ message(STATUS "Python support: no")
+endif()
+
+message(STATUS "lib info: ${LIB_INFO}")
+
--- /dev/null
+# - Link platform support dependencies found by CheckPlatformSupport.cmake
+
+# lockdev
+if (HAVE_LOCKDEV)
+ target_link_libraries(cec lockdev)
+endif()
+
+# udev
+if (HAVE_LIBUDEV)
+ target_link_libraries(cec udev)
+endif()
+
+# xrandr
+if (HAVE_RANDR)
+ target_link_libraries(cec Xrandr)
+ target_link_libraries(cec X11)
+endif()
+
+# rt
+if (HAVE_RT)
+ target_link_libraries(cec rt)
+endif()
+
+# dl
+if (HAVE_DLOPEN)
+ target_link_libraries(cec dl)
+endif()
+
+# raspberry pi
+if (HAVE_RPI_API)
+ target_link_libraries(cec ${RPI_VCOS} ${RPI_VCHIQ_ARM} ${RPI_BCM_HOST})
+endif()
+
+# Apple
+if (APPLE)
+ target_link_libraries(cec "-framework CoreFoundation")
+ target_link_libraries(cec "-framework IOKit")
+ target_link_libraries(cec "-framework CoreVideo")
+endif()
+
--- /dev/null
+# - Set information about the system on which this was built in LIB_INFO
+#
+# This module sets the following variables
+# LIB_INFO supported features and compilation information
+#
+
+if(WIN32)
+
+ # Windows
+ set(LIB_INFO "compiled on ${CMAKE_SYSTEM}")
+
+else()
+ # not Windows
+ set(LIB_INFO "")
+
+ # add git revision to compile info
+ find_program(HAVE_GIT_BIN git /bin /usr/bin /usr/local/bin)
+ if(HAVE_GIT_BIN)
+ exec_program(${CMAKE_CURRENT_SOURCE_DIR}/cmake/git-rev.sh HEAD OUTPUT_VARIABLE GIT_REVISION)
+ message(STATUS "git found: ${GIT_REVISION}")
+ endif()
+ if (GIT_REVISION)
+ set(LIB_INFO "git revision: ${GIT_REVISION},")
+ endif()
+
+ # add compilation date to compile info
+ find_program(HAVE_DATE_BIN date /bin /usr/bin /usr/local/bin)
+ if(HAVE_DATE_BIN)
+ exec_program(date ARGS -u OUTPUT_VARIABLE BUILD_DATE)
+ set(LIB_INFO "${LIB_INFO} compiled on ${BUILD_DATE}")
+ else()
+ set(LIB_INFO "${LIB_INFO} compiled on (unknown date)")
+ endif()
+
+ # add user who built this to compile info
+ find_program(HAVE_WHOAMI_BIN whoami /bin /usr/bin /usr/local/bin)
+ if(HAVE_WHOAMI_BIN)
+ exec_program(whoami OUTPUT_VARIABLE BUILD_USER)
+ set(LIB_INFO "${LIB_INFO} by ${BUILD_USER}")
+ else()
+ set(LIB_INFO "${LIB_INFO} by (unknown user)")
+ endif()
+
+
+ # add host on which this was built to compile info
+ find_program(HAVE_HOSTNAME_BIN hostname /bin /usr/bin /usr/local/bin)
+ if(HAVE_HOSTNAME_BIN)
+ exec_program(hostname ARGS -f OUTPUT_VARIABLE BUILD_HOST)
+ set(LIB_INFO "${LIB_INFO}@${BUILD_HOST}")
+ endif()
+
+ # add host info on which this was built to compile info
+ find_program(HAVE_UNAME_BIN uname /bin /usr/bin /usr/local/bin)
+ if(HAVE_UNAME_BIN)
+ exec_program(uname ARGS -s OUTPUT_VARIABLE BUILD_SYSNAME)
+ exec_program(uname ARGS -r OUTPUT_VARIABLE BUILD_SYSVER)
+ exec_program(uname ARGS -m OUTPUT_VARIABLE BUILD_SYSARCH)
+
+ set(LIB_INFO "${LIB_INFO} on ${BUILD_SYSNAME} ${BUILD_SYSVER} (${BUILD_SYSARCH})")
+ endif()
+
+endif()
+
--- /dev/null
+#!/bin/sh
+
+## cmake doesn't read the variable when it doesn't end with a newline, and I haven't figured out how to have it add a newline directly...
+if git rev-parse --git-dir > /dev/null 2>&1; then
+ last_tag=`git describe --tags --abbrev=0`
+ last_hash=`git --no-pager log --abbrev=7 -n 1 --pretty=format:"%h"`
+ commits_since_tag=`git log ${last_tag}..HEAD --oneline | wc -l`
+ git_dirty=`git diff HEAD | wc -l`
+ if [ $commits_since_tag -gt 0 ]; then
+ dirty=""
+ if [ $git_dirty -gt 0 ]; then
+ dirty="~dirty"
+ fi
+ echo "${last_tag}+${commits_since_tag}-${last_hash}${dirty}"
+ else
+ echo $last_tag
+ fi
+else
+ echo "<unknown>"
+fi
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include "CECAudioSystem.h"
+
+#include "CECProcessor.h"
+#include "implementations/CECCommandHandler.h"
+#include "LibCEC.h"
+#include "CECTypeUtils.h"
+
+using namespace CEC;
+using namespace P8PLATFORM;
+
+#define LIB_CEC m_processor->GetLib()
+#define ToString(p) CCECTypeUtils::ToString(p)
+
+CCECAudioSystem::CCECAudioSystem(CCECProcessor *processor, cec_logical_address address, uint16_t iPhysicalAddress /* = CEC_INVALID_PHYSICAL_ADDRESS */) :
+ CCECBusDevice(processor, address, iPhysicalAddress),
+ m_systemAudioStatus(CEC_SYSTEM_AUDIO_STATUS_ON),
+ m_audioStatus(CEC_AUDIO_VOLUME_STATUS_UNKNOWN)
+{
+ m_type = CEC_DEVICE_TYPE_AUDIO_SYSTEM;
+}
+
+bool CCECAudioSystem::SetAudioStatus(uint8_t status)
+{
+ CLockObject lock(m_mutex);
+ if (m_audioStatus != status)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, ">> %s (%X): audio status changed from %2x to %2x", GetLogicalAddressName(), m_iLogicalAddress, m_audioStatus, status);
+ m_audioStatus = status;
+ return true;
+ }
+
+ return false;
+}
+
+bool CCECAudioSystem::SetSystemAudioModeStatus(const cec_system_audio_status mode)
+{
+ CLockObject lock(m_mutex);
+ if (m_systemAudioStatus != mode)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, ">> %s (%X): system audio mode status changed from %s to %s", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_systemAudioStatus), ToString(mode));
+ m_systemAudioStatus = mode;
+ return true;
+ }
+
+ return false;
+}
+
+bool CCECAudioSystem::TransmitAudioStatus(cec_logical_address dest, bool bIsReply)
+{
+ uint8_t state;
+ {
+ CLockObject lock(m_mutex);
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %x -> %x: audio status '%2x'", m_iLogicalAddress, dest, m_audioStatus);
+ state = m_audioStatus;
+ }
+
+ return m_handler->TransmitAudioStatus(m_iLogicalAddress, dest, state, bIsReply);
+}
+
+bool CCECAudioSystem::TransmitSetSystemAudioMode(cec_logical_address dest, bool bIsReply)
+{
+ cec_system_audio_status state;
+ {
+ CLockObject lock(m_mutex);
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %x -> %x: set system audio mode '%2x'", m_iLogicalAddress, dest, m_audioStatus);
+ state = m_systemAudioStatus;
+ }
+
+ return m_handler->TransmitSetSystemAudioMode(m_iLogicalAddress, dest, state, bIsReply);
+}
+
+bool CCECAudioSystem::TransmitSystemAudioModeStatus(cec_logical_address dest, bool bIsReply)
+{
+ cec_system_audio_status state;
+ {
+ CLockObject lock(m_mutex);
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %x -> %x: system audio mode '%s'", m_iLogicalAddress, dest, ToString(m_systemAudioStatus));
+ state = m_systemAudioStatus;
+ }
+
+ return m_handler->TransmitSystemAudioModeStatus(m_iLogicalAddress, dest, state, bIsReply);
+}
+
+uint8_t CCECAudioSystem::VolumeUp(const cec_logical_address source, bool bSendRelease /* = true */)
+{
+ TransmitVolumeUp(source, bSendRelease);
+ CLockObject lock(m_mutex);
+ return m_audioStatus;
+}
+
+uint8_t CCECAudioSystem::VolumeDown(const cec_logical_address source, bool bSendRelease /* = true */)
+{
+ TransmitVolumeDown(source, bSendRelease);
+ CLockObject lock(m_mutex);
+ return m_audioStatus;
+}
+
+uint8_t CCECAudioSystem::MuteAudio(const cec_logical_address source)
+{
+ TransmitMuteAudio(source);
+ return GetAudioStatus(source, true);
+}
+
+bool CCECAudioSystem::RequestAudioStatus(const cec_logical_address initiator, bool bWaitForResponse /* = true */)
+{
+ bool bReturn(false);
+
+ if (!IsHandledByLibCEC() &&
+ !IsUnsupportedFeature(CEC_OPCODE_GIVE_AUDIO_STATUS))
+ {
+ MarkBusy();
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< requesting audio status of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
+ bReturn = m_handler->TransmitRequestAudioStatus(initiator, m_iLogicalAddress, bWaitForResponse);
+ MarkReady();
+ }
+ return bReturn;
+}
+
+uint8_t CCECAudioSystem::GetAudioStatus(const cec_logical_address initiator, bool bUpdate /* = false */)
+{
+ bool bIsPresent(GetStatus() == CEC_DEVICE_STATUS_PRESENT);
+ bool bRequestUpdate(false);
+ {
+ CLockObject lock(m_mutex);
+ bRequestUpdate = bIsPresent &&
+ (bUpdate || m_audioStatus == CEC_AUDIO_VOLUME_STATUS_UNKNOWN);
+ }
+
+ if (bRequestUpdate)
+ {
+ CheckVendorIdRequested(initiator);
+ RequestAudioStatus(initiator);
+ }
+
+ CLockObject lock(m_mutex);
+ return m_audioStatus;
+}
+
+bool CCECAudioSystem::EnableAudio(CCECBusDevice* device /* = nullptr */)
+{
+ uint16_t audioAddress = !!device ?
+ device->GetCurrentPhysicalAddress() :
+ CEC_INVALID_PHYSICAL_ADDRESS;
+ return m_handler->TransmitSystemAudioModeRequest(m_iLogicalAddress, audioAddress);
+}
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include "CECBusDevice.h"
+
+namespace CEC
+{
+ class CCECAudioSystem : public CCECBusDevice
+ {
+ public:
+ CCECAudioSystem(CCECProcessor *processor, cec_logical_address address, uint16_t iPhysicalAddress = CEC_INVALID_PHYSICAL_ADDRESS);
+ virtual ~CCECAudioSystem(void) {};
+
+ bool SetAudioStatus(uint8_t status);
+ bool SetSystemAudioModeStatus(const cec_system_audio_status mode);
+ bool TransmitAudioStatus(cec_logical_address dest, bool bIsReply);
+ bool TransmitSetSystemAudioMode(cec_logical_address dest, bool bIsReply);
+ bool TransmitSystemAudioModeStatus(cec_logical_address dest, bool bIsReply);
+
+ uint8_t VolumeUp(const cec_logical_address source, bool bSendRelease = true);
+ uint8_t VolumeDown(const cec_logical_address source, bool bSendRelease = true);
+ uint8_t MuteAudio(const cec_logical_address source);
+ uint8_t GetAudioStatus(const cec_logical_address initiator, bool bUpdate = false);
+ bool EnableAudio(CCECBusDevice* device = nullptr);
+
+ bool TransmitActiveSource(void) { return false; }
+
+ protected:
+ bool RequestAudioStatus(const cec_logical_address initiator, bool bWaitForResponse = true);
+
+ cec_system_audio_status m_systemAudioStatus;
+ uint8_t m_audioStatus;
+ };
+}
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include "CECBusDevice.h"
+
+#include "CECProcessor.h"
+#include "CECClient.h"
+#include "implementations/ANCommandHandler.h"
+#include "implementations/CECCommandHandler.h"
+#include "implementations/SLCommandHandler.h"
+#include "implementations/VLCommandHandler.h"
+#include "implementations/PHCommandHandler.h"
+#include "implementations/RLCommandHandler.h"
+#include "implementations/RHCommandHandler.h"
+#include "implementations/AQCommandHandler.h"
+#include "LibCEC.h"
+#include "CECTypeUtils.h"
+#include <p8-platform/util/timeutils.h>
+#include <p8-platform/util/util.h>
+
+#include "CECAudioSystem.h"
+#include "CECPlaybackDevice.h"
+#include "CECRecordingDevice.h"
+#include "CECTuner.h"
+#include "CECTV.h"
+
+using namespace CEC;
+using namespace P8PLATFORM;
+
+#define LIB_CEC m_processor->GetLib()
+#define ToString(p) CCECTypeUtils::ToString(p)
+
+CResponse::CResponse(cec_opcode opcode) :
+ m_opcode(opcode)
+{
+}
+
+CResponse::~CResponse(void)
+{
+ Broadcast();
+}
+
+bool CResponse::Wait(uint32_t iTimeout)
+{
+ return m_event.Wait(iTimeout);
+}
+
+void CResponse::Broadcast(void)
+{
+ m_event.Broadcast();
+}
+
+CWaitForResponse::CWaitForResponse(void)
+{
+}
+
+CWaitForResponse::~CWaitForResponse(void)
+{
+ Clear();
+}
+
+void CWaitForResponse::Clear()
+{
+ P8PLATFORM::CLockObject lock(m_mutex);
+ for (std::map<cec_opcode, CResponse*>::iterator it = m_waitingFor.begin(); it != m_waitingFor.end(); it++)
+ {
+ it->second->Broadcast();
+ delete it->second;
+ }
+ m_waitingFor.clear();
+}
+
+bool CWaitForResponse::Wait(cec_opcode opcode, uint32_t iTimeout)
+{
+ CResponse *response = GetEvent(opcode);
+ return response ? response->Wait(iTimeout) : false;
+}
+
+void CWaitForResponse::Received(cec_opcode opcode)
+{
+ CResponse *response = GetEvent(opcode);
+ if (response)
+ response->Broadcast();
+}
+
+CResponse* CWaitForResponse::GetEvent(cec_opcode opcode)
+{
+ CResponse *retVal(NULL);
+ {
+ P8PLATFORM::CLockObject lock(m_mutex);
+ std::map<cec_opcode, CResponse*>::iterator it = m_waitingFor.find(opcode);
+ if (it != m_waitingFor.end())
+ {
+ retVal = it->second;
+ }
+ else
+ {
+ retVal = new CResponse(opcode);
+ m_waitingFor[opcode] = retVal;
+ }
+ return retVal;
+ }
+}
+
+CCECBusDevice::CCECBusDevice(CCECProcessor *processor, cec_logical_address iLogicalAddress, uint16_t iPhysicalAddress /* = CEC_INVALID_PHYSICAL_ADDRESS */) :
+ m_type (CEC_DEVICE_TYPE_RESERVED),
+ m_iPhysicalAddress (iPhysicalAddress),
+ m_iStreamPath (CEC_INVALID_PHYSICAL_ADDRESS),
+ m_iLogicalAddress (iLogicalAddress),
+ m_powerStatus (CEC_POWER_STATUS_UNKNOWN),
+ m_menuLanguage ("???"),
+ m_processor (processor),
+ m_vendor (CEC_VENDOR_UNKNOWN),
+ m_bReplaceHandler (false),
+ m_menuState (CEC_MENU_STATE_ACTIVATED),
+ m_bActiveSource (false),
+ m_iLastActive (0),
+ m_iLastPowerStateUpdate (0),
+ m_cecVersion (CEC_VERSION_UNKNOWN),
+ m_deviceStatus (CEC_DEVICE_STATUS_UNKNOWN),
+ m_iHandlerUseCount (0),
+ m_bAwaitingReceiveFailed(false),
+ m_bVendorIdRequested (false),
+ m_waitForResponse (new CWaitForResponse),
+ m_bImageViewOnSent (false)
+{
+ m_handler = new CCECCommandHandler(this);
+ m_strDeviceName = ToString(m_iLogicalAddress);
+}
+
+CCECBusDevice::~CCECBusDevice(void)
+{
+ SAFE_DELETE(m_handler);
+ SAFE_DELETE(m_waitForResponse);
+}
+
+bool CCECBusDevice::ReplaceHandler(bool bActivateSource /* = true */)
+{
+ if (m_iLogicalAddress == CECDEVICE_BROADCAST)
+ return false;
+
+ bool bInitHandler(false);
+ {
+ CLockObject lock(m_mutex);
+ CLockObject handlerLock(m_handlerMutex);
+ if (m_iHandlerUseCount > 0)
+ return false;
+
+ MarkBusy();
+
+ if (m_vendor != m_handler->GetVendorId())
+ {
+ if (CCECCommandHandler::HasSpecificHandler(m_vendor))
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "replacing the command handler for device '%s' (%x)", GetLogicalAddressName(), GetLogicalAddress());
+
+ int32_t iTransmitTimeout = m_handler->m_iTransmitTimeout;
+ int32_t iTransmitWait = m_handler->m_iTransmitWait;
+ int8_t iTransmitRetries = m_handler->m_iTransmitRetries;
+ int64_t iActiveSourcePending = m_handler->m_iActiveSourcePending;
+
+ SAFE_DELETE(m_handler);
+
+ switch (m_vendor)
+ {
+ case CEC_VENDOR_SAMSUNG:
+ m_handler = new CANCommandHandler(this, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending);
+ break;
+ case CEC_VENDOR_LG:
+ m_handler = new CSLCommandHandler(this, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending);
+ break;
+ case CEC_VENDOR_PANASONIC:
+ m_handler = new CVLCommandHandler(this, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending);
+ break;
+ case CEC_VENDOR_PHILIPS:
+ m_handler = new CPHCommandHandler(this, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending);
+ break;
+ case CEC_VENDOR_TOSHIBA:
+ case CEC_VENDOR_TOSHIBA2:
+ m_handler = new CRLCommandHandler(this, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending);
+ break;
+ case CEC_VENDOR_ONKYO:
+ m_handler = new CRHCommandHandler(this, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending);
+ break;
+ case CEC_VENDOR_SHARP:
+ case CEC_VENDOR_SHARP2:
+ m_handler = new CAQCommandHandler(this, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending);
+ break;
+ default:
+ m_handler = new CCECCommandHandler(this, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending);
+ break;
+ }
+
+ /** override the vendor ID set in the handler, as a single vendor may have multiple IDs */
+ m_handler->SetVendorId(m_vendor);
+ bInitHandler = true;
+ }
+ }
+ }
+
+ if (bInitHandler)
+ {
+ CCECBusDevice *primary = GetProcessor()->GetPrimaryDevice();
+ if (primary->GetLogicalAddress() != CECDEVICE_UNREGISTERED)
+ {
+ m_handler->InitHandler();
+
+ if (bActivateSource && IsHandledByLibCEC() && IsActiveSource())
+ m_handler->ActivateSource();
+ }
+ }
+
+ MarkReady();
+
+ return true;
+}
+
+CCECCommandHandler *CCECBusDevice::GetHandler(void)
+{
+ ReplaceHandler(false);
+ MarkBusy();
+ return m_handler;
+}
+
+bool CCECBusDevice::HandleCommand(const cec_command &command)
+{
+ bool bHandled(false);
+
+ /* update "last active" */
+ {
+ CLockObject lock(m_mutex);
+ m_iLastActive = GetTimeMs();
+ MarkBusy();
+ }
+
+ /* handle the command */
+ bHandled = m_handler->HandleCommand(command);
+
+ /* change status to present */
+ if (bHandled && GetLogicalAddress() != CECDEVICE_BROADCAST && command.opcode_set == 1)
+ {
+ CLockObject lock(m_mutex);
+ if (m_deviceStatus != CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC)
+ {
+ if (m_deviceStatus != CEC_DEVICE_STATUS_PRESENT)
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "device %s (%x) status changed to present after command %s", GetLogicalAddressName(), (uint8_t)GetLogicalAddress(), ToString(command.opcode));
+ m_deviceStatus = CEC_DEVICE_STATUS_PRESENT;
+ }
+ }
+
+ MarkReady();
+ return bHandled;
+}
+
+const char* CCECBusDevice::GetLogicalAddressName(void) const
+{
+ return ToString(m_iLogicalAddress);
+}
+
+bool CCECBusDevice::IsPresent(void)
+{
+ CLockObject lock(m_mutex);
+ return m_deviceStatus == CEC_DEVICE_STATUS_PRESENT;
+}
+
+bool CCECBusDevice::IsHandledByLibCEC(void)
+{
+ CLockObject lock(m_mutex);
+ return m_deviceStatus == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC;
+}
+
+void CCECBusDevice::SetUnsupportedFeature(cec_opcode opcode)
+{
+ // some commands should never be marked as unsupported
+ if (opcode == CEC_OPCODE_VENDOR_COMMAND ||
+ opcode == CEC_OPCODE_VENDOR_COMMAND_WITH_ID ||
+ opcode == CEC_OPCODE_VENDOR_REMOTE_BUTTON_DOWN ||
+ opcode == CEC_OPCODE_VENDOR_REMOTE_BUTTON_UP ||
+ opcode == CEC_OPCODE_ABORT ||
+ opcode == CEC_OPCODE_FEATURE_ABORT ||
+ opcode == CEC_OPCODE_NONE ||
+ opcode == CEC_OPCODE_USER_CONTROL_PRESSED ||
+ opcode == CEC_OPCODE_USER_CONTROL_RELEASE)
+ return;
+
+ {
+ CLockObject lock(m_mutex);
+ if (m_unsupportedFeatures.find(opcode) == m_unsupportedFeatures.end())
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "marking opcode '%s' as unsupported feature for device '%s'", ToString(opcode), GetLogicalAddressName());
+ m_unsupportedFeatures.insert(opcode);
+ }
+ }
+
+ // signal threads that are waiting for a response
+ MarkBusy();
+ SignalOpcode(cec_command::GetResponseOpcode(opcode));
+ MarkReady();
+}
+
+bool CCECBusDevice::IsUnsupportedFeature(cec_opcode opcode)
+{
+ CLockObject lock(m_mutex);
+ bool bUnsupported = (m_unsupportedFeatures.find(opcode) != m_unsupportedFeatures.end());
+ if (bUnsupported)
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "'%s' is marked as unsupported feature for device '%s'", ToString(opcode), GetLogicalAddressName());
+ return bUnsupported;
+}
+
+bool CCECBusDevice::TransmitKeypress(const cec_logical_address initiator, cec_user_control_code key, bool bWait /* = true */)
+{
+ MarkBusy();
+ bool bReturn = m_handler->TransmitKeypress(initiator, m_iLogicalAddress, key, bWait);
+ MarkReady();
+ return bReturn;
+}
+
+bool CCECBusDevice::TransmitKeyRelease(const cec_logical_address initiator, bool bWait /* = true */)
+{
+ MarkBusy();
+ bool bReturn = m_handler->TransmitKeyRelease(initiator, m_iLogicalAddress, bWait);
+ MarkReady();
+ return bReturn;
+}
+
+cec_version CCECBusDevice::GetCecVersion(const cec_logical_address initiator, bool bUpdate /* = false */)
+{
+ bool bIsPresent(GetStatus() == CEC_DEVICE_STATUS_PRESENT);
+ bool bRequestUpdate(false);
+ {
+ CLockObject lock(m_mutex);
+ bRequestUpdate = bIsPresent &&
+ (bUpdate || m_cecVersion == CEC_VERSION_UNKNOWN);
+ }
+
+ if (bRequestUpdate)
+ {
+ CheckVendorIdRequested(initiator);
+ RequestCecVersion(initiator);
+ }
+
+ CLockObject lock(m_mutex);
+ return m_cecVersion;
+}
+
+void CCECBusDevice::SetCecVersion(const cec_version newVersion)
+{
+ CLockObject lock(m_mutex);
+ if (m_cecVersion != newVersion)
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): CEC version %s", GetLogicalAddressName(), m_iLogicalAddress, ToString(newVersion));
+ m_cecVersion = newVersion;
+}
+
+bool CCECBusDevice::RequestCecVersion(const cec_logical_address initiator, bool bWaitForResponse /* = true */)
+{
+ bool bReturn(false);
+
+ if (!IsHandledByLibCEC() &&
+ !IsUnsupportedFeature(CEC_OPCODE_GET_CEC_VERSION))
+ {
+ MarkBusy();
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< requesting CEC version of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
+ bReturn = m_handler->TransmitRequestCecVersion(initiator, m_iLogicalAddress, bWaitForResponse);
+ MarkReady();
+ }
+ return bReturn;
+}
+
+bool CCECBusDevice::TransmitCECVersion(const cec_logical_address destination, bool bIsReply)
+{
+ cec_version version;
+ {
+ CLockObject lock(m_mutex);
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) -> %s (%X): cec version %s", GetLogicalAddressName(), m_iLogicalAddress, ToString(destination), destination, ToString(m_cecVersion));
+ version = m_cecVersion;
+ }
+
+ MarkBusy();
+ bool bReturn = m_handler->TransmitCECVersion(m_iLogicalAddress, destination, version, bIsReply);
+ MarkReady();
+ return bReturn;
+}
+
+std::string CCECBusDevice::GetMenuLanguage(const cec_logical_address initiator, bool bUpdate /* = false */)
+{
+ bool bIsPresent(GetStatus() == CEC_DEVICE_STATUS_PRESENT);
+ bool bRequestUpdate(false);
+ {
+ CLockObject lock(m_mutex);
+ bRequestUpdate = (bIsPresent &&
+ (bUpdate || m_menuLanguage == "???"));
+ }
+
+ if (bRequestUpdate)
+ {
+ CheckVendorIdRequested(initiator);
+ RequestMenuLanguage(initiator);
+ }
+
+ CLockObject lock(m_mutex);
+ return m_menuLanguage;
+}
+
+void CCECBusDevice::SetMenuLanguage(const std::string& strLanguage)
+{
+ CLockObject lock(m_mutex);
+ if (m_menuLanguage != strLanguage)
+ {
+ m_menuLanguage = strLanguage;
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): menu language set to '%s'", GetLogicalAddressName(), m_iLogicalAddress, m_menuLanguage.c_str());
+ }
+}
+
+void CCECBusDevice::SetMenuLanguage(const cec_menu_language& language)
+{
+ std::string strLanguage(language);
+ SetMenuLanguage(strLanguage);
+}
+
+bool CCECBusDevice::RequestMenuLanguage(const cec_logical_address initiator, bool bWaitForResponse /* = true */)
+{
+ bool bReturn(false);
+
+ if (!IsHandledByLibCEC() &&
+ !IsUnsupportedFeature(CEC_OPCODE_GET_MENU_LANGUAGE))
+ {
+ MarkBusy();
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< requesting menu language of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
+ bReturn = m_handler->TransmitRequestMenuLanguage(initiator, m_iLogicalAddress, bWaitForResponse);
+ MarkReady();
+ }
+ return bReturn;
+}
+
+bool CCECBusDevice::TransmitSetMenuLanguage(const cec_logical_address destination, bool bIsReply)
+{
+ bool bReturn(false);
+ char lang[4];
+ {
+ CLockObject lock(m_mutex);
+ memcpy(lang, m_menuLanguage.c_str(), 4);
+ }
+
+ MarkBusy();
+ if (lang[0] == '?' && lang[1] == '?' && lang[2] == '?')
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) -> %s (%X): menu language feature abort", GetLogicalAddressName(), m_iLogicalAddress, ToString(destination), destination);
+ m_processor->TransmitAbort(m_iLogicalAddress, destination, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID);
+ bReturn = true;
+ }
+ else
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) -> broadcast (F): menu language '%s'", GetLogicalAddressName(), m_iLogicalAddress, lang);
+ bReturn = m_handler->TransmitSetMenuLanguage(m_iLogicalAddress, lang, bIsReply);
+ }
+ MarkReady();
+ return bReturn;
+}
+
+bool CCECBusDevice::TransmitOSDString(const cec_logical_address destination, cec_display_control duration, const char *strMessage, bool bIsReply)
+{
+ bool bReturn(false);
+ if (!m_processor->GetDevice(destination)->IsUnsupportedFeature(CEC_OPCODE_SET_OSD_STRING))
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) -> %s (%X): display OSD message '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(destination), destination, strMessage);
+ MarkBusy();
+ bReturn = m_handler->TransmitOSDString(m_iLogicalAddress, destination, duration, strMessage, bIsReply);
+ MarkReady();
+ }
+ return bReturn;
+}
+
+std::string CCECBusDevice::GetCurrentOSDName(void)
+{
+ CLockObject lock(m_mutex);
+ return m_strDeviceName;
+}
+
+std::string CCECBusDevice::GetOSDName(const cec_logical_address initiator, bool bUpdate /* = false */)
+{
+ bool bIsPresent(GetStatus() == CEC_DEVICE_STATUS_PRESENT);
+ bool bRequestUpdate(false);
+ {
+ CLockObject lock(m_mutex);
+ bRequestUpdate = bIsPresent &&
+ (bUpdate || m_strDeviceName == ToString(m_iLogicalAddress)) &&
+ m_type != CEC_DEVICE_TYPE_TV;
+ }
+
+ if (bRequestUpdate)
+ {
+ CheckVendorIdRequested(initiator);
+ RequestOSDName(initiator);
+ }
+
+ CLockObject lock(m_mutex);
+ return m_strDeviceName;
+}
+
+void CCECBusDevice::SetOSDName(const std::string& strName)
+{
+ CLockObject lock(m_mutex);
+ if (m_strDeviceName != strName)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): osd name set to '%s'", GetLogicalAddressName(), m_iLogicalAddress, strName.c_str());
+ m_strDeviceName = strName;
+ }
+}
+
+bool CCECBusDevice::RequestOSDName(const cec_logical_address initiator, bool bWaitForResponse /* = true */)
+{
+ bool bReturn(false);
+
+ if (!IsHandledByLibCEC() &&
+ !IsUnsupportedFeature(CEC_OPCODE_GIVE_OSD_NAME))
+ {
+ MarkBusy();
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< requesting OSD name of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
+ bReturn = m_handler->TransmitRequestOSDName(initiator, m_iLogicalAddress, bWaitForResponse);
+ MarkReady();
+ }
+ return bReturn;
+}
+
+bool CCECBusDevice::TransmitOSDName(const cec_logical_address destination, bool bIsReply)
+{
+ std::string strDeviceName;
+ {
+ CLockObject lock(m_mutex);
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) -> %s (%X): OSD name '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(destination), destination, m_strDeviceName.c_str());
+ strDeviceName = m_strDeviceName;
+ }
+
+ MarkBusy();
+ bool bReturn = m_handler->TransmitOSDName(m_iLogicalAddress, destination, strDeviceName, bIsReply);
+ MarkReady();
+ return bReturn;
+}
+
+bool CCECBusDevice::HasValidPhysicalAddress(void)
+{
+ CLockObject lock(m_mutex);
+ return CLibCEC::IsValidPhysicalAddress(m_iPhysicalAddress);
+}
+
+uint16_t CCECBusDevice::GetCurrentPhysicalAddress(void)
+{
+ CLockObject lock(m_mutex);
+ return m_iPhysicalAddress;
+}
+
+uint16_t CCECBusDevice::GetPhysicalAddress(const cec_logical_address initiator, bool bSuppressUpdate /* = false */)
+{
+ if (!bSuppressUpdate)
+ {
+ bool bIsPresent(GetStatus() == CEC_DEVICE_STATUS_PRESENT);
+ bool bRequestUpdate(false);
+ {
+ CLockObject lock(m_mutex);
+ bRequestUpdate = bIsPresent && m_iPhysicalAddress == CEC_INVALID_PHYSICAL_ADDRESS;
+ }
+
+ if (bRequestUpdate)
+ {
+ CheckVendorIdRequested(initiator);
+ if (!RequestPhysicalAddress(initiator))
+ LIB_CEC->AddLog(CEC_LOG_ERROR, "failed to request the physical address");
+ }
+ }
+
+ CLockObject lock(m_mutex);
+ return m_iPhysicalAddress;
+}
+
+bool CCECBusDevice::SetPhysicalAddress(uint16_t iNewAddress)
+{
+ CLockObject lock(m_mutex);
+ if (iNewAddress > 0 && m_iPhysicalAddress != iNewAddress)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): physical address changed from %04x to %04x", GetLogicalAddressName(), m_iLogicalAddress, m_iPhysicalAddress, iNewAddress);
+ m_iPhysicalAddress = iNewAddress;
+ }
+ return true;
+}
+
+bool CCECBusDevice::RequestPhysicalAddress(const cec_logical_address initiator, bool bWaitForResponse /* = true */)
+{
+ bool bReturn(false);
+
+ if (!IsHandledByLibCEC())
+ {
+ MarkBusy();
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< requesting physical address of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
+ bReturn = m_handler->TransmitRequestPhysicalAddress(initiator, m_iLogicalAddress, bWaitForResponse);
+ MarkReady();
+ }
+ return bReturn;
+}
+
+bool CCECBusDevice::TransmitPhysicalAddress(bool bIsReply)
+{
+ uint16_t iPhysicalAddress;
+ cec_device_type type;
+ {
+ CLockObject lock(m_mutex);
+ if (m_iPhysicalAddress == CEC_INVALID_PHYSICAL_ADDRESS)
+ return false;
+
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) -> broadcast (F): physical address %4x", GetLogicalAddressName(), m_iLogicalAddress, m_iPhysicalAddress);
+ iPhysicalAddress = m_iPhysicalAddress;
+ type = m_type;
+ }
+
+ MarkBusy();
+ bool bReturn = m_handler->TransmitPhysicalAddress(m_iLogicalAddress, iPhysicalAddress, type, bIsReply);
+ MarkReady();
+ return bReturn;
+}
+
+cec_power_status CCECBusDevice::GetCurrentPowerStatus(void)
+{
+ CLockObject lock(m_mutex);
+ return m_powerStatus;
+}
+
+cec_power_status CCECBusDevice::GetPowerStatus(const cec_logical_address initiator, bool bUpdate /* = false */)
+{
+ bool bIsPresent(GetStatus() == CEC_DEVICE_STATUS_PRESENT);
+ bool bRequestUpdate(false);
+ {
+ CLockObject lock(m_mutex);
+ bRequestUpdate = (bIsPresent &&
+ (bUpdate || m_powerStatus == CEC_POWER_STATUS_UNKNOWN ||
+ m_powerStatus == CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON ||
+ m_powerStatus == CEC_POWER_STATUS_IN_TRANSITION_ON_TO_STANDBY ||
+ GetTimeMs() - m_iLastPowerStateUpdate >= CEC_POWER_STATE_REFRESH_TIME));
+ }
+
+ if (bRequestUpdate)
+ {
+ CheckVendorIdRequested(initiator);
+ RequestPowerStatus(initiator, bUpdate);
+ }
+
+ CLockObject lock(m_mutex);
+ return m_powerStatus;
+}
+
+void CCECBusDevice::SetPowerStatus(const cec_power_status powerStatus)
+{
+ CLockObject lock(m_mutex);
+ if (m_powerStatus != powerStatus)
+ {
+ m_iLastPowerStateUpdate = GetTimeMs();
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): power status changed from '%s' to '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_powerStatus), ToString(powerStatus));
+ m_powerStatus = powerStatus;
+ }
+}
+
+void CCECBusDevice::OnImageViewOnSent(bool bSentByLibCEC)
+{
+ CLockObject lock(m_mutex);
+ m_bImageViewOnSent = bSentByLibCEC;
+
+ if (m_powerStatus != CEC_POWER_STATUS_ON && m_powerStatus != CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON)
+ {
+ m_iLastPowerStateUpdate = GetTimeMs();
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): power status changed from '%s' to '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_powerStatus), ToString(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON));
+ m_powerStatus = CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON;
+ }
+}
+
+bool CCECBusDevice::ImageViewOnSent(void)
+{
+ CLockObject lock(m_mutex);
+ return m_bImageViewOnSent;
+}
+
+bool CCECBusDevice::RequestPowerStatus(const cec_logical_address initiator, bool bUpdate, bool bWaitForResponse /* = true */)
+{
+ bool bReturn(false);
+
+ if (!IsHandledByLibCEC() &&
+ !IsUnsupportedFeature(CEC_OPCODE_GIVE_DEVICE_POWER_STATUS))
+ {
+ MarkBusy();
+ bReturn = m_handler->TransmitRequestPowerStatus(initiator, m_iLogicalAddress, bUpdate, bWaitForResponse);
+ if (!bReturn)
+ SetPowerStatus(CEC_POWER_STATUS_UNKNOWN);
+ MarkReady();
+ }
+ return bReturn;
+}
+
+bool CCECBusDevice::TransmitPowerState(const cec_logical_address destination, bool bIsReply)
+{
+ cec_power_status state;
+ {
+ CLockObject lock(m_mutex);
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) -> %s (%X): %s", GetLogicalAddressName(), m_iLogicalAddress, ToString(destination), destination, ToString(m_powerStatus));
+ state = m_powerStatus;
+ }
+
+ MarkBusy();
+ bool bReturn = m_handler->TransmitPowerState(m_iLogicalAddress, destination, state, bIsReply);
+ MarkReady();
+ return bReturn;
+}
+
+cec_vendor_id CCECBusDevice::GetCurrentVendorId(void)
+{
+ CLockObject lock(m_mutex);
+ return m_vendor;
+}
+
+cec_vendor_id CCECBusDevice::GetVendorId(const cec_logical_address initiator, bool bUpdate /* = false */)
+{
+ bool bIsPresent(GetStatus() == CEC_DEVICE_STATUS_PRESENT);
+ bool bRequestUpdate(false);
+ {
+ CLockObject lock(m_mutex);
+ bRequestUpdate = (bIsPresent &&
+ (bUpdate || m_vendor == CEC_VENDOR_UNKNOWN));
+ }
+
+ if (bRequestUpdate)
+ RequestVendorId(initiator);
+
+ CLockObject lock(m_mutex);
+ return m_vendor;
+}
+
+const char *CCECBusDevice::GetVendorName(const cec_logical_address initiator, bool bUpdate /* = false */)
+{
+ return ToString(GetVendorId(initiator, bUpdate));
+}
+
+bool CCECBusDevice::SetVendorId(uint64_t iVendorId)
+{
+ bool bVendorChanged(false);
+
+ {
+ CLockObject lock(m_mutex);
+ bVendorChanged = (m_vendor != (cec_vendor_id)iVendorId);
+ m_vendor = (cec_vendor_id)iVendorId;
+ }
+
+ if (bVendorChanged)
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): vendor = %s (%06x)", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_vendor), m_vendor);
+
+ return bVendorChanged;
+}
+
+bool CCECBusDevice::RequestVendorId(const cec_logical_address initiator, bool bWaitForResponse /* = true */)
+{
+ bool bReturn(false);
+
+ if (!IsHandledByLibCEC() && initiator != CECDEVICE_UNKNOWN)
+ {
+ MarkBusy();
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< requesting vendor ID of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
+ bReturn = m_handler->TransmitRequestVendorId(initiator, m_iLogicalAddress, bWaitForResponse);
+ MarkReady();
+
+ if (bWaitForResponse)
+ ReplaceHandler(true);
+ }
+ return bReturn;
+}
+
+bool CCECBusDevice::TransmitVendorID(const cec_logical_address destination, bool bSendAbort, bool bIsReply)
+{
+ bool bReturn(false);
+ uint64_t iVendorId;
+ {
+ CLockObject lock(m_mutex);
+ iVendorId = (uint64_t)m_vendor;
+ }
+
+ MarkBusy();
+ if (iVendorId == CEC_VENDOR_UNKNOWN)
+ {
+ if (bSendAbort)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) -> %s (%X): vendor id feature abort", GetLogicalAddressName(), m_iLogicalAddress, ToString(destination), destination);
+ m_processor->TransmitAbort(m_iLogicalAddress, destination, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID);
+ bReturn = true;
+ }
+ }
+ else
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) -> %s (%X): vendor id %s (%x)", GetLogicalAddressName(), m_iLogicalAddress, ToString(destination), destination, ToString((cec_vendor_id)iVendorId), iVendorId);
+ bReturn = m_handler->TransmitVendorID(m_iLogicalAddress, destination, iVendorId, bIsReply);
+ }
+ MarkReady();
+ return bReturn;
+}
+
+cec_bus_device_status CCECBusDevice::GetStatus(bool bForcePoll /* = false */, bool bSuppressPoll /* = false */)
+{
+ if (m_iLogicalAddress == CECDEVICE_BROADCAST)
+ return CEC_DEVICE_STATUS_NOT_PRESENT;
+
+ cec_bus_device_status status(CEC_DEVICE_STATUS_UNKNOWN);
+ bool bNeedsPoll(false);
+
+ {
+ CLockObject lock(m_mutex);
+ status = m_deviceStatus;
+ bNeedsPoll = !bSuppressPoll &&
+ m_deviceStatus != CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC &&
+ // poll forced
+ (bForcePoll ||
+ // don't know the status
+ m_deviceStatus == CEC_DEVICE_STATUS_UNKNOWN ||
+ // always poll the TV if it's marked as not present
+ (m_deviceStatus == CEC_DEVICE_STATUS_NOT_PRESENT && m_iLogicalAddress == CECDEVICE_TV));
+ }
+
+ if (bNeedsPoll)
+ {
+ bool bPollAcked(false);
+ if (bNeedsPoll)
+ bPollAcked = m_processor->PollDevice(m_iLogicalAddress);
+
+ status = bPollAcked ? CEC_DEVICE_STATUS_PRESENT : CEC_DEVICE_STATUS_NOT_PRESENT;
+ SetDeviceStatus(status);
+ }
+
+ return status;
+}
+
+void CCECBusDevice::SetDeviceStatus(const cec_bus_device_status newStatus, cec_version libCECSpecVersion /* = CEC_VERSION_1_4 */)
+{
+ if (m_iLogicalAddress == CECDEVICE_UNREGISTERED)
+ return;
+
+ {
+ CLockObject lock(m_mutex);
+ switch (newStatus)
+ {
+ case CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC:
+ if (m_deviceStatus != newStatus)
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): device status changed into 'handled by libCEC'", GetLogicalAddressName(), m_iLogicalAddress);
+ SetPowerStatus (CEC_POWER_STATUS_ON);
+ SetVendorId (CEC_VENDOR_PULSE_EIGHT);
+ SetMenuState (CEC_MENU_STATE_ACTIVATED);
+ SetCecVersion (libCECSpecVersion);
+ SetStreamPath (CEC_INVALID_PHYSICAL_ADDRESS);
+ MarkAsInactiveSource();
+ m_iLastActive = 0;
+ m_deviceStatus = newStatus;
+ break;
+ case CEC_DEVICE_STATUS_PRESENT:
+ if (m_deviceStatus != newStatus)
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): device status changed into 'present'", GetLogicalAddressName(), m_iLogicalAddress);
+ m_deviceStatus = newStatus;
+ m_iLastActive = GetTimeMs();
+ break;
+ case CEC_DEVICE_STATUS_NOT_PRESENT:
+ if (m_deviceStatus != newStatus)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): device status changed into 'not present'", GetLogicalAddressName(), m_iLogicalAddress);
+ ResetDeviceStatus(true);
+ m_deviceStatus = newStatus;
+ }
+ break;
+ default:
+ ResetDeviceStatus();
+ break;
+ }
+ }
+}
+
+void CCECBusDevice::ResetDeviceStatus(bool bClientUnregistered /* = false */)
+{
+ CLockObject lock(m_mutex);
+ SetPowerStatus (CEC_POWER_STATUS_UNKNOWN);
+ SetVendorId (CEC_VENDOR_UNKNOWN);
+ SetMenuState (CEC_MENU_STATE_ACTIVATED);
+ SetCecVersion (CEC_VERSION_UNKNOWN);
+ SetStreamPath (CEC_INVALID_PHYSICAL_ADDRESS);
+ SetOSDName (ToString(m_iLogicalAddress));
+ MarkAsInactiveSource(bClientUnregistered);
+
+ m_iLastActive = 0;
+ m_bVendorIdRequested = false;
+ m_unsupportedFeatures.clear();
+ m_waitForResponse->Clear();
+
+ if (m_deviceStatus != CEC_DEVICE_STATUS_UNKNOWN)
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): device status changed into 'unknown'", GetLogicalAddressName(), m_iLogicalAddress);
+ m_deviceStatus = CEC_DEVICE_STATUS_UNKNOWN;
+}
+
+bool CCECBusDevice::TransmitPoll(const cec_logical_address dest, bool bUpdateDeviceStatus)
+{
+ bool bReturn(false);
+ cec_logical_address destination(dest);
+ if (destination == CECDEVICE_UNKNOWN)
+ destination = m_iLogicalAddress;
+
+ CCECBusDevice *destDevice = m_processor->GetDevice(destination);
+ if (destDevice->m_deviceStatus == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC)
+ return bReturn;
+
+ MarkBusy();
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) -> %s (%X): POLL", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest);
+ bReturn = m_handler->TransmitPoll(m_iLogicalAddress, destination, false);
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, bReturn ? ">> POLL sent" : ">> POLL not sent");
+
+ if (bUpdateDeviceStatus)
+ destDevice->SetDeviceStatus(bReturn ? CEC_DEVICE_STATUS_PRESENT : CEC_DEVICE_STATUS_NOT_PRESENT);
+
+ MarkReady();
+ return bReturn;
+}
+
+void CCECBusDevice::HandlePoll(const cec_logical_address destination)
+{
+ if (destination >= 0 && destination < CECDEVICE_BROADCAST)
+ {
+ CCECBusDevice *device = m_processor->GetDevice(destination);
+ if (device)
+ device->HandlePollFrom(m_iLogicalAddress);
+ }
+}
+
+void CCECBusDevice::HandlePollFrom(const cec_logical_address initiator)
+{
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< POLL: %s (%x) -> %s (%x)", ToString(initiator), initiator, ToString(m_iLogicalAddress), m_iLogicalAddress);
+ m_bAwaitingReceiveFailed = true;
+}
+
+bool CCECBusDevice::HandleReceiveFailed(void)
+{
+ bool bReturn = m_bAwaitingReceiveFailed;
+ m_bAwaitingReceiveFailed = false;
+ return bReturn;
+}
+
+cec_menu_state CCECBusDevice::GetMenuState(const cec_logical_address UNUSED(initiator))
+{
+ CLockObject lock(m_mutex);
+ return m_menuState;
+}
+
+void CCECBusDevice::SetMenuState(const cec_menu_state state)
+{
+ CLockObject lock(m_mutex);
+ if (m_menuState != state)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): menu state set to '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_menuState));
+ m_menuState = state;
+ }
+}
+
+bool CCECBusDevice::TransmitMenuState(const cec_logical_address dest, bool bIsReply)
+{
+ cec_menu_state menuState;
+ {
+ CLockObject lock(m_mutex);
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) -> %s (%X): menu state '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, ToString(m_menuState));
+ menuState = m_menuState;
+ }
+
+ MarkBusy();
+ bool bReturn = m_handler->TransmitMenuState(m_iLogicalAddress, dest, menuState, bIsReply);
+ MarkReady();
+ return bReturn;
+}
+
+bool CCECBusDevice::ActivateSource(uint64_t iDelay /* = 0 */)
+{
+ MarkAsActiveSource();
+ MarkBusy();
+ bool bReturn(true);
+ if (iDelay == 0)
+ {
+ libcec_configuration config;
+ /** send system audio mode request if AVR exists */
+ if (m_iLogicalAddress != CECDEVICE_AUDIOSYSTEM &&
+ LIB_CEC->GetCurrentConfiguration(&config) && config.bAutoWakeAVR == 1)
+ {
+ CCECBusDevice* audioSystem(m_processor->GetDevice(CECDEVICE_AUDIOSYSTEM));
+ if (audioSystem && audioSystem->IsPresent())
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "powering up the AVR");
+ SystemAudioModeRequest();
+ }
+ }
+
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "sending active source message for '%s'", ToString(m_iLogicalAddress));
+ bReturn = m_handler->ActivateSource();
+ }
+ else
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "scheduling active source message for '%s'", ToString(m_iLogicalAddress));
+ m_handler->ScheduleActivateSource(iDelay);
+ }
+ MarkReady();
+ return bReturn;
+}
+
+bool CCECBusDevice::RequestActiveSource(bool bWaitForResponse /* = true */)
+{
+ bool bReturn(false);
+
+ if (IsHandledByLibCEC())
+ {
+ MarkBusy();
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< requesting active source");
+
+ bReturn = m_handler->TransmitRequestActiveSource(m_iLogicalAddress, bWaitForResponse);
+ MarkReady();
+ }
+ return bReturn;
+}
+
+void CCECBusDevice::MarkAsActiveSource(void)
+{
+ bool bWasActivated(false);
+
+ // set the power status to powered on
+ SetPowerStatus(CEC_POWER_STATUS_ON);
+
+ // mark this device as active source
+ {
+ CLockObject lock(m_mutex);
+ if (!m_bActiveSource)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "making %s (%x) the active source", GetLogicalAddressName(), m_iLogicalAddress);
+ bWasActivated = true;
+ }
+ else
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%x) was already marked as active source", GetLogicalAddressName(), m_iLogicalAddress);
+
+ m_bActiveSource = true;
+ }
+
+ CCECBusDevice* tv = m_processor->GetDevice(CECDEVICE_TV);
+ if (tv)
+ tv->OnImageViewOnSent(false);
+
+ // mark other devices as inactive sources
+ CECDEVICEVEC devices;
+ m_processor->GetDevices()->Get(devices);
+ for (CECDEVICEVEC::iterator it = devices.begin(); it != devices.end(); it++)
+ if ((*it)->GetLogicalAddress() != m_iLogicalAddress)
+ (*it)->MarkAsInactiveSource();
+
+ if (bWasActivated && IsHandledByLibCEC())
+ m_processor->SetActiveSource(true, false);
+
+ CECClientPtr client = GetClient();
+ if (client)
+ client->SourceActivated(m_iLogicalAddress);
+}
+
+void CCECBusDevice::MarkAsInactiveSource(bool bClientUnregistered /* = false */)
+{
+ bool bWasDeactivated(false);
+ {
+ CLockObject lock(m_mutex);
+ if (m_bActiveSource)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "marking %s (%X) as inactive source", GetLogicalAddressName(), m_iLogicalAddress);
+ bWasDeactivated = true;
+ }
+ m_bActiveSource = false;
+ }
+
+ if (bWasDeactivated)
+ {
+ if (IsHandledByLibCEC())
+ m_processor->SetActiveSource(false, bClientUnregistered);
+ CECClientPtr client = GetClient();
+ if (client)
+ client->SourceDeactivated(m_iLogicalAddress);
+ }
+}
+
+bool CCECBusDevice::TransmitActiveSource(bool bIsReply)
+{
+ bool bSendActiveSource(false);
+ uint16_t iPhysicalAddress(CEC_INVALID_PHYSICAL_ADDRESS);
+
+ {
+ CLockObject lock(m_mutex);
+ if (!HasValidPhysicalAddress())
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X) has an invalid physical address (%04x), not sending active source commands", GetLogicalAddressName(), m_iLogicalAddress, m_iPhysicalAddress);
+ return false;
+ }
+
+ iPhysicalAddress = m_iPhysicalAddress;
+
+ if (m_powerStatus != CEC_POWER_STATUS_ON && m_powerStatus != CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON)
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) is not powered on", GetLogicalAddressName(), m_iLogicalAddress);
+ else if (m_bActiveSource)
+ {
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> broadcast (F): active source (%4x)", GetLogicalAddressName(), m_iLogicalAddress, m_iPhysicalAddress);
+ bSendActiveSource = true;
+ }
+ else
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) is not the active source", GetLogicalAddressName(), m_iLogicalAddress);
+ }
+
+ bool bActiveSourceSent(false);
+ if (bSendActiveSource)
+ {
+ MarkBusy();
+ bActiveSourceSent = m_handler->TransmitActiveSource(m_iLogicalAddress, iPhysicalAddress, bIsReply);
+ MarkReady();
+ }
+
+ return bActiveSourceSent;
+}
+
+bool CCECBusDevice::TransmitImageViewOn(void)
+{
+ {
+ CLockObject lock(m_mutex);
+ if (m_powerStatus != CEC_POWER_STATUS_ON && m_powerStatus != CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) is not powered on", GetLogicalAddressName(), m_iLogicalAddress);
+ return false;
+ }
+ }
+
+ CCECBusDevice* tv = m_processor->GetDevice(CECDEVICE_TV);
+ if (!tv)
+ {
+ LIB_CEC->AddLog(CEC_LOG_ERROR, "%s - couldn't get TV instance", __FUNCTION__);
+ return false;
+ }
+
+ if (tv->ImageViewOnSent())
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - 'image view on' already sent", __FUNCTION__);
+ return true;
+ }
+
+ bool bImageViewOnSent(false);
+ MarkBusy();
+ bImageViewOnSent = m_handler->TransmitImageViewOn(m_iLogicalAddress, CECDEVICE_TV);
+ MarkReady();
+
+ if (bImageViewOnSent)
+ tv->OnImageViewOnSent(true);
+
+ return bImageViewOnSent;
+}
+
+bool CCECBusDevice::TransmitInactiveSource(void)
+{
+ uint16_t iPhysicalAddress;
+ {
+ CLockObject lock(m_mutex);
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> broadcast (F): inactive source", GetLogicalAddressName(), m_iLogicalAddress);
+ iPhysicalAddress = m_iPhysicalAddress;
+ }
+
+ MarkBusy();
+ bool bReturn = m_handler->TransmitInactiveSource(m_iLogicalAddress, iPhysicalAddress);
+ MarkReady();
+ return bReturn;
+}
+
+bool CCECBusDevice::TransmitPendingActiveSourceCommands(void)
+{
+ MarkBusy();
+ bool bReturn = m_handler->ActivateSource(true);
+ MarkReady();
+ return bReturn;
+}
+
+void CCECBusDevice::SetActiveRoute(uint16_t iRoute)
+{
+ SetPowerStatus(CEC_POWER_STATUS_ON);
+
+ CCECDeviceMap* map = m_processor->GetDevices();
+ if (!map)
+ return;
+
+ CCECBusDevice* newRoute = m_processor->GetDeviceByPhysicalAddress(iRoute, true);
+ if (newRoute && newRoute->IsHandledByLibCEC() && !newRoute->IsActiveSource())
+ {
+ // we were made the active source, send notification
+ newRoute->ActivateSource();
+ }
+}
+
+void CCECBusDevice::SetStreamPath(uint16_t iNewAddress, uint16_t iOldAddress /* = CEC_INVALID_PHYSICAL_ADDRESS */)
+{
+ if (iNewAddress != CEC_INVALID_PHYSICAL_ADDRESS)
+ SetPowerStatus(CEC_POWER_STATUS_ON);
+
+ CLockObject lock(m_mutex);
+ if (iNewAddress != m_iStreamPath)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): stream path changed from %04x to %04x", GetLogicalAddressName(), m_iLogicalAddress, iOldAddress == 0 ? m_iStreamPath : iOldAddress, iNewAddress);
+ m_iStreamPath = iNewAddress;
+ }
+
+ if (!LIB_CEC->IsValidPhysicalAddress(iNewAddress))
+ return;
+
+ CCECBusDevice *device = m_processor->GetDeviceByPhysicalAddress(iNewAddress);
+ if (device)
+ {
+ // if a device is found with the new physical address, mark it as active, which will automatically mark all other devices as inactive
+ device->MarkAsActiveSource();
+
+ // respond with an active source message if this device is handled by libCEC
+ if (device->IsHandledByLibCEC())
+ device->TransmitActiveSource(true);
+ }
+ else
+ {
+ // try to find the device with the old address, and mark it as inactive when found
+ device = m_processor->GetDeviceByPhysicalAddress(iOldAddress);
+ if (device)
+ device->MarkAsInactiveSource();
+ }
+}
+
+bool CCECBusDevice::PowerOn(const cec_logical_address initiator)
+{
+ bool bReturn(false);
+ GetVendorId(initiator); // ensure that we got the vendor id, because the implementations vary per vendor
+
+ MarkBusy();
+ cec_power_status currentStatus;
+ if (m_iLogicalAddress == CECDEVICE_TV ||
+ ((currentStatus = GetPowerStatus(initiator, false)) != CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON &&
+ currentStatus != CEC_POWER_STATUS_ON))
+ {
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< powering on '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
+ bReturn = m_handler->PowerOn(initiator, m_iLogicalAddress);
+ }
+ else
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "'%s' (%X) is already '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(currentStatus));
+ }
+
+ MarkReady();
+ return bReturn;
+}
+
+bool CCECBusDevice::Standby(const cec_logical_address initiator)
+{
+ GetVendorId(initiator); // ensure that we got the vendor id, because the implementations vary per vendor
+
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< putting '%s' (%X) in standby mode", GetLogicalAddressName(), m_iLogicalAddress);
+ MarkBusy();
+ bool bReturn = m_handler->TransmitStandby(initiator, m_iLogicalAddress);
+ MarkReady();
+ return bReturn;
+}
+
+bool CCECBusDevice::NeedsPoll(void)
+{
+ bool bSendPoll(false);
+ cec_logical_address pollAddress(CECDEVICE_UNKNOWN);
+ switch (m_iLogicalAddress)
+ {
+ case CECDEVICE_PLAYBACKDEVICE3:
+ pollAddress = CECDEVICE_PLAYBACKDEVICE2;
+ break;
+ case CECDEVICE_PLAYBACKDEVICE2:
+ pollAddress = CECDEVICE_PLAYBACKDEVICE1;
+ break;
+ case CECDEVICE_RECORDINGDEVICE3:
+ pollAddress = CECDEVICE_RECORDINGDEVICE2;
+ break;
+ case CECDEVICE_RECORDINGDEVICE2:
+ pollAddress = CECDEVICE_RECORDINGDEVICE1;
+ break;
+ case CECDEVICE_TUNER4:
+ pollAddress = CECDEVICE_TUNER3;
+ break;
+ case CECDEVICE_TUNER3:
+ pollAddress = CECDEVICE_TUNER2;
+ break;
+ case CECDEVICE_TUNER2:
+ pollAddress = CECDEVICE_TUNER1;
+ break;
+ case CECDEVICE_AUDIOSYSTEM:
+ case CECDEVICE_PLAYBACKDEVICE1:
+ case CECDEVICE_RECORDINGDEVICE1:
+ case CECDEVICE_TUNER1:
+ case CECDEVICE_TV:
+ bSendPoll = true;
+ break;
+ default:
+ break;
+ }
+
+ if (!bSendPoll && pollAddress != CECDEVICE_UNKNOWN)
+ {
+ CCECBusDevice *device = m_processor->GetDevice(pollAddress);
+ if (device)
+ {
+ cec_bus_device_status status = device->GetStatus();
+ bSendPoll = (status == CEC_DEVICE_STATUS_PRESENT || status == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC);
+ }
+ else
+ {
+ bSendPoll = true;
+ }
+ }
+
+ return bSendPoll;
+}
+
+void CCECBusDevice::CheckVendorIdRequested(const cec_logical_address initiator)
+{
+ bool bRequestVendorId(false);
+ {
+ CLockObject lock(m_mutex);
+ bRequestVendorId = !m_bVendorIdRequested;
+ m_bVendorIdRequested = true;
+ }
+
+ if (bRequestVendorId)
+ {
+ ReplaceHandler(false);
+ GetVendorId(initiator);
+ }
+}
+//@}
+
+CCECAudioSystem *CCECBusDevice::AsAudioSystem(void)
+{
+ return AsAudioSystem(this);
+}
+
+CCECPlaybackDevice *CCECBusDevice::AsPlaybackDevice(void)
+{
+ return AsPlaybackDevice(this);
+}
+
+CCECRecordingDevice *CCECBusDevice::AsRecordingDevice(void)
+{
+ return AsRecordingDevice(this);
+}
+
+CCECTuner *CCECBusDevice::AsTuner(void)
+{
+ return AsTuner(this);
+}
+
+CCECTV *CCECBusDevice::AsTV(void)
+{
+ return AsTV(this);
+}
+
+CCECAudioSystem *CCECBusDevice::AsAudioSystem(CCECBusDevice *device)
+{
+ if (device && device->GetType() == CEC_DEVICE_TYPE_AUDIO_SYSTEM)
+ return static_cast<CCECAudioSystem *>(device);
+ return NULL;
+}
+
+CCECPlaybackDevice *CCECBusDevice::AsPlaybackDevice(CCECBusDevice *device)
+{
+ if (device &&
+ (device->GetType() == CEC_DEVICE_TYPE_PLAYBACK_DEVICE ||
+ device->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE))
+ return static_cast<CCECPlaybackDevice *>(device);
+ return NULL;
+}
+
+CCECRecordingDevice *CCECBusDevice::AsRecordingDevice(CCECBusDevice *device)
+{
+ if (device && device->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE)
+ return static_cast<CCECRecordingDevice *>(device);
+ return NULL;
+}
+
+CCECTuner *CCECBusDevice::AsTuner(CCECBusDevice *device)
+{
+ if (device && device->GetType() == CEC_DEVICE_TYPE_TUNER)
+ return static_cast<CCECTuner *>(device);
+ return NULL;
+}
+
+CCECTV *CCECBusDevice::AsTV(CCECBusDevice *device)
+{
+ if (device && device->GetType() == CEC_DEVICE_TYPE_TV)
+ return static_cast<CCECTV *>(device);
+ return NULL;
+}
+
+void CCECBusDevice::MarkBusy(void)
+{
+ CLockObject handlerLock(m_handlerMutex);
+ ++m_iHandlerUseCount;
+}
+
+void CCECBusDevice::MarkReady(void)
+{
+ CLockObject handlerLock(m_handlerMutex);
+ if (m_iHandlerUseCount > 0)
+ --m_iHandlerUseCount;
+}
+
+bool CCECBusDevice::TryLogicalAddress(cec_version libCECSpecVersion /* = CEC_VERSION_1_4 */)
+{
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "trying logical address '%s'", GetLogicalAddressName());
+
+ if (!TransmitPoll(m_iLogicalAddress, false))
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "using logical address '%s'", GetLogicalAddressName());
+ SetDeviceStatus(CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC, libCECSpecVersion);
+
+ return true;
+ }
+
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "logical address '%s' already taken", GetLogicalAddressName());
+ SetDeviceStatus(CEC_DEVICE_STATUS_PRESENT);
+ return false;
+}
+
+CECClientPtr CCECBusDevice::GetClient(void)
+{
+ return m_processor->GetClient(m_iLogicalAddress);
+}
+
+void CCECBusDevice::SignalOpcode(cec_opcode opcode)
+{
+ m_waitForResponse->Received(opcode);
+}
+
+bool CCECBusDevice::WaitForOpcode(cec_opcode opcode)
+{
+ return m_waitForResponse->Wait(opcode);
+}
+
+bool CCECBusDevice::SystemAudioModeRequest(void)
+{
+ uint16_t iPhysicalAddress(GetCurrentPhysicalAddress());
+ return iPhysicalAddress != CEC_INVALID_PHYSICAL_ADDRESS && !!m_handler ?
+ m_handler->TransmitSystemAudioModeRequest(m_iLogicalAddress, iPhysicalAddress) :
+ false;
+}
+
+bool CCECBusDevice::TransmitVolumeUp(const cec_logical_address source, bool bSendRelease /* = true */)
+{
+ bool retval = TransmitKeypress(source, CEC_USER_CONTROL_CODE_VOLUME_UP);
+ if (bSendRelease && retval)
+ retval &= TransmitKeyRelease(source);
+ return retval;
+}
+
+bool CCECBusDevice::TransmitVolumeDown(const cec_logical_address source, bool bSendRelease /* = true */)
+{
+ bool retval = TransmitKeypress(source, CEC_USER_CONTROL_CODE_VOLUME_DOWN);
+ if (bSendRelease && retval)
+ retval &= TransmitKeyRelease(source);
+ return retval;
+}
+
+bool CCECBusDevice::TransmitMuteAudio(const cec_logical_address source)
+{
+ return TransmitKeypress(source, CEC_USER_CONTROL_CODE_MUTE) &&
+ TransmitKeyRelease(source);
+}
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include <set>
+#include <map>
+#include <string>
+#include <p8-platform/threads/mutex.h>
+#include <memory>
+
+namespace CEC
+{
+ class CCECClient;
+ class CCECProcessor;
+ class CCECCommandHandler;
+ class CCECAudioSystem;
+ class CCECPlaybackDevice;
+ class CCECRecordingDevice;
+ class CCECTuner;
+ class CCECTV;
+ typedef std::shared_ptr<CCECClient> CECClientPtr;
+
+ class CResponse
+ {
+ public:
+ CResponse(cec_opcode opcode);
+ ~CResponse(void);
+
+ bool Wait(uint32_t iTimeout);
+ void Broadcast(void);
+
+ private:
+ cec_opcode m_opcode;
+ P8PLATFORM::CEvent m_event;
+ };
+
+ class CWaitForResponse
+ {
+ public:
+ CWaitForResponse(void);
+ ~CWaitForResponse(void);
+
+ void Clear();
+ bool Wait(cec_opcode opcode, uint32_t iTimeout = CEC_DEFAULT_TRANSMIT_WAIT);
+ void Received(cec_opcode opcode);
+
+ private:
+ CResponse *GetEvent(cec_opcode opcode);
+
+ P8PLATFORM::CMutex m_mutex;
+ std::map<cec_opcode, CResponse*> m_waitingFor;
+ };
+
+ class CCECBusDevice
+ {
+ friend class CCECProcessor;
+
+ public:
+ CCECBusDevice(CCECProcessor *processor, cec_logical_address address, uint16_t iPhysicalAddress = CEC_INVALID_PHYSICAL_ADDRESS);
+ virtual ~CCECBusDevice(void);
+
+ virtual bool ReplaceHandler(bool bActivateSource = true);
+
+ // TODO use something smarter than this
+ /*!
+ * @brief Get the command handler for this device. Call MarkHandlerReady() when done with it.
+ * @return The current handler.
+ */
+ virtual CCECCommandHandler * GetHandler(void);
+
+ /*!
+ * @brief To be called after GetHandler(), when no longer using it.
+ */
+ virtual void MarkHandlerReady(void) { MarkReady(); }
+
+ virtual CCECProcessor * GetProcessor(void) const { return m_processor; }
+ virtual uint64_t GetLastActive(void) const { return m_iLastActive; }
+ virtual cec_device_type GetType(void) const { return m_type; }
+ virtual cec_logical_address GetLogicalAddress(void) const { return m_iLogicalAddress; }
+ virtual const char* GetLogicalAddressName(void) const;
+ virtual bool IsPresent(void);
+ virtual bool IsHandledByLibCEC(void);
+
+ virtual bool HandleCommand(const cec_command &command);
+ virtual bool IsUnsupportedFeature(cec_opcode opcode);
+ virtual void SetUnsupportedFeature(cec_opcode opcode);
+
+ virtual bool TransmitKeypress(const cec_logical_address initiator, cec_user_control_code key, bool bWait = true);
+ virtual bool TransmitKeyRelease(const cec_logical_address initiator, bool bWait = true);
+
+ virtual cec_version GetCecVersion(const cec_logical_address initiator, bool bUpdate = false);
+ virtual void SetCecVersion(const cec_version newVersion);
+ virtual bool RequestCecVersion(const cec_logical_address initiator, bool bWaitForResponse = true);
+ virtual bool TransmitCECVersion(const cec_logical_address destination, bool bIsReply);
+
+ virtual std::string GetMenuLanguage(const cec_logical_address initiator, bool bUpdate = false);
+ virtual void SetMenuLanguage(const std::string& strLanguage);
+ virtual void SetMenuLanguage(const cec_menu_language &menuLanguage);
+ virtual bool RequestMenuLanguage(const cec_logical_address initiator, bool bWaitForResponse = true);
+ virtual bool TransmitSetMenuLanguage(const cec_logical_address destination, bool bIsReply);
+
+ virtual bool TransmitOSDString(const cec_logical_address destination, cec_display_control duration, const char *strMessage, bool bIsReply);
+
+ virtual std::string GetCurrentOSDName(void);
+ virtual std::string GetOSDName(const cec_logical_address initiator, bool bUpdate = false);
+ virtual void SetOSDName(const std::string& strName);
+ virtual bool RequestOSDName(const cec_logical_address source, bool bWaitForResponse = true);
+ virtual bool TransmitOSDName(const cec_logical_address destination, bool bIsReply);
+
+ virtual uint16_t GetCurrentPhysicalAddress(void);
+ virtual bool HasValidPhysicalAddress(void);
+ virtual uint16_t GetPhysicalAddress(const cec_logical_address initiator, bool bSuppressUpdate = false);
+ virtual bool SetPhysicalAddress(uint16_t iNewAddress);
+ virtual bool RequestPhysicalAddress(const cec_logical_address initiator, bool bWaitForResponse = true);
+ virtual bool TransmitPhysicalAddress(bool bIsReply);
+
+ virtual cec_power_status GetCurrentPowerStatus(void);
+ virtual cec_power_status GetPowerStatus(const cec_logical_address initiator, bool bUpdate = false);
+ virtual void SetPowerStatus(const cec_power_status powerStatus);
+ virtual void OnImageViewOnSent(bool bSentByLibCEC);
+ virtual bool ImageViewOnSent(void);
+ virtual bool RequestPowerStatus(const cec_logical_address initiator, bool bUpdate, bool bWaitForResponse = true);
+ virtual bool TransmitPowerState(const cec_logical_address destination, bool bIsReply);
+
+ virtual cec_vendor_id GetCurrentVendorId(void);
+ virtual cec_vendor_id GetVendorId(const cec_logical_address initiator, bool bUpdate = false);
+ virtual const char * GetVendorName(const cec_logical_address initiator, bool bUpdate = false);
+ virtual bool SetVendorId(uint64_t iVendorId);
+ virtual bool RequestVendorId(const cec_logical_address initiator, bool bWaitForResponse = true);
+ virtual bool TransmitVendorID(const cec_logical_address destination, bool bSendAbort, bool bIsReply);
+
+ virtual cec_bus_device_status GetCurrentStatus(void) { return GetStatus(false, true); }
+ virtual cec_bus_device_status GetStatus(bool bForcePoll = false, bool bSuppressPoll = false);
+ virtual void SetDeviceStatus(const cec_bus_device_status newStatus, cec_version libCECSpecVersion = CEC_VERSION_1_4);
+ virtual void ResetDeviceStatus(bool bClientUnregistered = false);
+ virtual bool TransmitPoll(const cec_logical_address destination, bool bUpdateDeviceStatus);
+ virtual void HandlePoll(const cec_logical_address destination);
+ virtual void HandlePollFrom(const cec_logical_address initiator);
+ virtual bool HandleReceiveFailed(void);
+
+ virtual cec_menu_state GetMenuState(const cec_logical_address initiator);
+ virtual void SetMenuState(const cec_menu_state state);
+ virtual bool TransmitMenuState(const cec_logical_address destination, bool bIsReply);
+
+ virtual bool ActivateSource(uint64_t iDelay = 0);
+ virtual bool IsActiveSource(void) const { return m_bActiveSource; }
+ virtual bool RequestActiveSource(bool bWaitForResponse = true);
+ virtual void MarkAsActiveSource(void);
+ virtual void MarkAsInactiveSource(bool bClientUnregistered = false);
+ virtual bool TransmitActiveSource(bool bIsReply);
+ virtual bool TransmitImageViewOn(void);
+ virtual bool TransmitInactiveSource(void);
+ virtual bool TransmitPendingActiveSourceCommands(void);
+ virtual void SetActiveRoute(uint16_t iRoute);
+ virtual void SetStreamPath(uint16_t iNewAddress, uint16_t iOldAddress = CEC_INVALID_PHYSICAL_ADDRESS);
+
+ virtual bool PowerOn(const cec_logical_address initiator);
+ virtual bool Standby(const cec_logical_address initiator);
+
+ virtual bool SystemAudioModeRequest(void);
+ virtual bool TransmitVolumeUp(const cec_logical_address source, bool bSendRelease = true);
+ virtual bool TransmitVolumeDown(const cec_logical_address source, bool bSendRelease = true);
+ virtual bool TransmitMuteAudio(const cec_logical_address source);
+
+ virtual bool TryLogicalAddress(cec_version libCECSpecVersion = CEC_VERSION_1_4);
+
+ CECClientPtr GetClient(void);
+ void SignalOpcode(cec_opcode opcode);
+ bool WaitForOpcode(cec_opcode opcode);
+
+ CCECAudioSystem * AsAudioSystem(void);
+ static CCECAudioSystem * AsAudioSystem(CCECBusDevice *device);
+ CCECPlaybackDevice * AsPlaybackDevice(void);
+ static CCECPlaybackDevice * AsPlaybackDevice(CCECBusDevice *device);
+ CCECRecordingDevice * AsRecordingDevice(void);
+ static CCECRecordingDevice * AsRecordingDevice(CCECBusDevice *device);
+ CCECTuner * AsTuner(void);
+ static CCECTuner * AsTuner(CCECBusDevice *device);
+ CCECTV * AsTV(void);
+ static CCECTV * AsTV(CCECBusDevice *device);
+
+ protected:
+ void CheckVendorIdRequested(const cec_logical_address source);
+ void MarkBusy(void);
+ void MarkReady(void);
+
+ bool NeedsPoll(void);
+
+ cec_device_type m_type;
+ std::string m_strDeviceName;
+ uint16_t m_iPhysicalAddress;
+ uint16_t m_iStreamPath;
+ cec_logical_address m_iLogicalAddress;
+ cec_power_status m_powerStatus;
+ std::string m_menuLanguage;
+ CCECProcessor * m_processor;
+ CCECCommandHandler * m_handler;
+ cec_vendor_id m_vendor;
+ bool m_bReplaceHandler;
+ cec_menu_state m_menuState;
+ bool m_bActiveSource;
+ int64_t m_iLastActive;
+ int64_t m_iLastPowerStateUpdate;
+ cec_version m_cecVersion;
+ cec_bus_device_status m_deviceStatus;
+ std::set<cec_opcode> m_unsupportedFeatures;
+ P8PLATFORM::CMutex m_mutex;
+ P8PLATFORM::CMutex m_handlerMutex;
+ P8PLATFORM::CEvent m_replacing;
+ unsigned m_iHandlerUseCount;
+ bool m_bAwaitingReceiveFailed;
+ bool m_bVendorIdRequested;
+ CWaitForResponse *m_waitForResponse;
+ bool m_bImageViewOnSent;
+ };
+};
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include "CECDeviceMap.h"
+
+#include "CECAudioSystem.h"
+#include "CECPlaybackDevice.h"
+#include "CECRecordingDevice.h"
+#include "CECTuner.h"
+#include "CECTV.h"
+#include "CECProcessor.h"
+#include "CECTypeUtils.h"
+
+using namespace CEC;
+
+CCECDeviceMap::CCECDeviceMap(CCECProcessor *processor) :
+ m_processor(processor)
+{
+ for (uint8_t iPtr = CECDEVICE_TV; iPtr <= CECDEVICE_BROADCAST; iPtr++)
+ {
+ switch(iPtr)
+ {
+ case CECDEVICE_AUDIOSYSTEM:
+ m_busDevices.insert(std::make_pair<cec_logical_address, CCECBusDevice *>((cec_logical_address)iPtr, new CCECAudioSystem(processor, (cec_logical_address) iPtr)));
+ break;
+ case CECDEVICE_PLAYBACKDEVICE1:
+ case CECDEVICE_PLAYBACKDEVICE2:
+ case CECDEVICE_PLAYBACKDEVICE3:
+ m_busDevices.insert(std::make_pair<cec_logical_address, CCECBusDevice *>((cec_logical_address)iPtr, new CCECPlaybackDevice(processor, (cec_logical_address) iPtr)));
+ break;
+ case CECDEVICE_RECORDINGDEVICE1:
+ case CECDEVICE_RECORDINGDEVICE2:
+ case CECDEVICE_RECORDINGDEVICE3:
+ m_busDevices.insert(std::make_pair<cec_logical_address, CCECBusDevice *>((cec_logical_address)iPtr, new CCECRecordingDevice(processor, (cec_logical_address) iPtr)));
+ break;
+ case CECDEVICE_TUNER1:
+ case CECDEVICE_TUNER2:
+ case CECDEVICE_TUNER3:
+ case CECDEVICE_TUNER4:
+ m_busDevices.insert(std::make_pair<cec_logical_address, CCECBusDevice *>((cec_logical_address)iPtr, new CCECTuner(processor, (cec_logical_address) iPtr)));
+ break;
+ case CECDEVICE_TV:
+ m_busDevices.insert(std::make_pair<cec_logical_address, CCECBusDevice *>((cec_logical_address)iPtr, new CCECTV(processor, (cec_logical_address) iPtr)));
+ break;
+ default:
+ m_busDevices.insert(std::make_pair<cec_logical_address, CCECBusDevice *>((cec_logical_address)iPtr, new CCECBusDevice(processor, (cec_logical_address) iPtr)));
+ break;
+ }
+ }
+}
+CCECDeviceMap::~CCECDeviceMap(void)
+{
+ Clear();
+}
+
+CECDEVICEMAP::iterator CCECDeviceMap::Begin(void)
+{
+ return m_busDevices.begin();
+}
+
+CECDEVICEMAP::iterator CCECDeviceMap::End(void)
+{
+ return m_busDevices.end();
+}
+
+void CCECDeviceMap::ResetDeviceStatus(void)
+{
+ for (CECDEVICEMAP::iterator it = m_busDevices.begin(); it != m_busDevices.end(); it++)
+ it->second->ResetDeviceStatus();
+}
+
+CCECBusDevice *CCECDeviceMap::operator[] (cec_logical_address iAddress) const
+{
+ return At(iAddress);
+}
+
+CCECBusDevice *CCECDeviceMap::operator[] (uint8_t iAddress) const
+{
+ return At(iAddress);
+}
+
+CCECBusDevice *CCECDeviceMap::At(cec_logical_address iAddress) const
+{
+ return At((uint8_t) iAddress);
+}
+
+CCECBusDevice *CCECDeviceMap::At(uint8_t iAddress) const
+{
+ CECDEVICEMAP::const_iterator it = m_busDevices.find((cec_logical_address)iAddress);
+ if (it != m_busDevices.end())
+ return it->second;
+ return NULL;
+}
+
+void CCECDeviceMap::Clear(void)
+{
+ for (CECDEVICEMAP::iterator it = m_busDevices.begin(); it != m_busDevices.end(); it++)
+ delete it->second;
+ m_busDevices.clear();
+}
+
+CCECBusDevice *CCECDeviceMap::GetDeviceByPhysicalAddress(uint16_t iPhysicalAddress, bool bSuppressUpdate /* = true */)
+{
+ CCECBusDevice *device(NULL);
+
+ // check each device until we found a match
+ for (CECDEVICEMAP::iterator it = m_busDevices.begin(); !device && it != m_busDevices.end(); it++)
+ {
+ if (it->second->GetPhysicalAddress(m_processor->GetLogicalAddress(), bSuppressUpdate) == iPhysicalAddress)
+ device = it->second;
+ }
+
+ return device;
+}
+
+void CCECDeviceMap::Get(CECDEVICEVEC &devices) const
+{
+ for (CECDEVICEMAP::const_iterator it = m_busDevices.begin(); it != m_busDevices.end(); it++)
+ devices.push_back(it->second);
+}
+
+void CCECDeviceMap::GetByLogicalAddresses(CECDEVICEVEC &devices, const cec_logical_addresses &addresses)
+{
+ for (CECDEVICEMAP::const_iterator it = m_busDevices.begin(); it != m_busDevices.end(); it++)
+ {
+ if (addresses.IsSet(it->first))
+ devices.push_back(it->second);
+ }
+}
+
+void CCECDeviceMap::GetByType(const cec_device_type type, CECDEVICEVEC &devices) const
+{
+ for (CECDEVICEMAP::const_iterator it = m_busDevices.begin(); it != m_busDevices.end(); it++)
+ if (it->second->GetType() == type)
+ devices.push_back(it->second);
+}
+
+void CCECDeviceMap::GetLibCECControlled(CECDEVICEVEC &devices) const
+{
+ for (CECDEVICEMAP::const_iterator it = m_busDevices.begin(); it != m_busDevices.end(); it++)
+ if (it->second->IsHandledByLibCEC())
+ devices.push_back(it->second);
+}
+
+void CCECDeviceMap::GetActive(CECDEVICEVEC &devices) const
+{
+ for (CECDEVICEMAP::const_iterator it = m_busDevices.begin(); it != m_busDevices.end(); it++)
+ {
+ cec_bus_device_status status = it->second->GetStatus();
+ if (status == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC ||
+ status == CEC_DEVICE_STATUS_PRESENT)
+ devices.push_back(it->second);
+ }
+}
+
+void CCECDeviceMap::GetPowerOffDevices(const libcec_configuration &configuration, CECDEVICEVEC &devices) const
+{
+ for (CECDEVICEMAP::const_iterator it = m_busDevices.begin(); it != m_busDevices.end(); it++)
+ {
+ if (configuration.powerOffDevices[(uint8_t)it->first])
+ devices.push_back(it->second);
+ }
+}
+
+void CCECDeviceMap::GetWakeDevices(const libcec_configuration &configuration, CECDEVICEVEC &devices) const
+{
+ for (CECDEVICEMAP::const_iterator it = m_busDevices.begin(); it != m_busDevices.end(); it++)
+ {
+ if (configuration.wakeDevices[(uint8_t)it->first])
+ devices.push_back(it->second);
+ }
+}
+
+CCECBusDevice *CCECDeviceMap::GetActiveSource(void) const
+{
+ for (CECDEVICEMAP::const_iterator it = m_busDevices.begin(); it != m_busDevices.end(); it++)
+ {
+ if (it->second->IsActiveSource())
+ return it->second;
+ }
+ return NULL;
+}
+
+void CCECDeviceMap::FilterLibCECControlled(CECDEVICEVEC &devices)
+{
+ CECDEVICEVEC newDevices;
+ for (CECDEVICEVEC::const_iterator it = devices.begin(); it != devices.end(); it++)
+ {
+ if ((*it)->IsHandledByLibCEC())
+ newDevices.push_back(*it);
+ }
+ devices = newDevices;
+}
+
+void CCECDeviceMap::FilterActive(CECDEVICEVEC &devices)
+{
+ CECDEVICEVEC newDevices;
+ for (CECDEVICEVEC::const_iterator it = devices.begin(); it != devices.end(); it++)
+ {
+ cec_bus_device_status status = (*it)->GetCurrentStatus();
+ if (status == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC ||
+ status == CEC_DEVICE_STATUS_PRESENT)
+ newDevices.push_back(*it);
+ }
+ devices = newDevices;
+}
+
+void CCECDeviceMap::FilterTypes(const cec_device_type_list &types, CECDEVICEVEC &devices)
+{
+ cec_device_type_list t(types);//silly, but needed to retain abi
+ CECDEVICEVEC newDevices;
+ for (CECDEVICEVEC::const_iterator it = devices.begin(); it != devices.end(); it++)
+ {
+ if (t.IsSet((*it)->GetType()))
+ newDevices.push_back(*it);
+ }
+ devices = newDevices;
+}
+
+void CCECDeviceMap::FilterType(const cec_device_type type, CECDEVICEVEC &devices)
+{
+ CECDEVICEVEC newDevices;
+ for (CECDEVICEVEC::const_iterator it = devices.begin(); it != devices.end(); it++)
+ {
+ if ((*it)->GetType() == type)
+ newDevices.push_back(*it);
+ }
+ devices = newDevices;
+}
+
+cec_logical_addresses CCECDeviceMap::ToLogicalAddresses(const CECDEVICEVEC &devices)
+{
+ cec_logical_addresses addresses;
+ addresses.Clear();
+ for (CECDEVICEVEC::const_iterator it = devices.begin(); it != devices.end(); it++)
+ addresses.Set((*it)->GetLogicalAddress());
+ return addresses;
+}
+
+void CCECDeviceMap::GetChildrenOf(CECDEVICEVEC& devices, CCECBusDevice* device) const
+{
+ devices.clear();
+ if (!device)
+ return;
+
+ uint16_t iPA = device->GetCurrentPhysicalAddress();
+
+ for (CECDEVICEMAP::const_iterator it = m_busDevices.begin(); it != m_busDevices.end(); it++)
+ {
+ uint16_t iCurrentPA = it->second->GetCurrentPhysicalAddress();
+ if (CCECTypeUtils::PhysicalAddressIsIncluded(iPA, iCurrentPA))
+ devices.push_back(it->second);
+ }
+}
+
+void CCECDeviceMap::SignalAll(cec_opcode opcode)
+{
+ for (CECDEVICEMAP::iterator it = m_busDevices.begin(); it != m_busDevices.end(); it++)
+ it->second->SignalOpcode(opcode);
+}
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include <map>
+#include <vector>
+
+namespace CEC
+{
+ class CCECBusDevice;
+
+ typedef std::map<cec_logical_address, CCECBusDevice *> CECDEVICEMAP;
+ typedef std::vector<CCECBusDevice *> CECDEVICEVEC;
+
+ class CCECProcessor;
+
+ class CCECDeviceMap
+ {
+ public:
+ CCECDeviceMap(CCECProcessor *processor);
+ virtual ~CCECDeviceMap(void);
+ CECDEVICEMAP::iterator Begin(void);
+ CECDEVICEMAP::iterator End(void);
+ void ResetDeviceStatus(void);
+ CCECBusDevice * operator[] (cec_logical_address iAddress) const;
+ CCECBusDevice * operator[] (uint8_t iAddress) const;
+ CCECBusDevice * At(cec_logical_address iAddress) const;
+ CCECBusDevice * At(uint8_t iAddress) const;
+ CCECBusDevice * GetDeviceByPhysicalAddress(uint16_t iPhysicalAddress, bool bSuppressUpdate = true);
+
+ void Get(CECDEVICEVEC &devices) const;
+ void GetLibCECControlled(CECDEVICEVEC &devices) const;
+ void GetByLogicalAddresses(CECDEVICEVEC &devices, const cec_logical_addresses &addresses);
+ void GetActive(CECDEVICEVEC &devices) const;
+ void GetByType(const cec_device_type type, CECDEVICEVEC &devices) const;
+ void GetChildrenOf(CECDEVICEVEC& devices, CCECBusDevice* device) const;
+ void SignalAll(cec_opcode opcode);
+
+ void GetPowerOffDevices(const libcec_configuration &configuration, CECDEVICEVEC &devices) const;
+ void GetWakeDevices(const libcec_configuration &configuration, CECDEVICEVEC &devices) const;
+
+ CCECBusDevice *GetActiveSource(void) const;
+
+ static void FilterLibCECControlled(CECDEVICEVEC &devices);
+ static void FilterActive(CECDEVICEVEC &devices);
+ static void FilterTypes(const cec_device_type_list &types, CECDEVICEVEC &devices);
+ static void FilterType(const cec_device_type type, CECDEVICEVEC &devices);
+ static cec_logical_addresses ToLogicalAddresses(const CECDEVICEVEC &devices);
+ private:
+ void Clear(void);
+
+ CECDEVICEMAP m_busDevices;
+ CCECProcessor *m_processor;
+ };
+}
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include "CECPlaybackDevice.h"
+
+#include "implementations/CECCommandHandler.h"
+#include "CECProcessor.h"
+#include "LibCEC.h"
+#include "CECTypeUtils.h"
+
+using namespace CEC;
+using namespace P8PLATFORM;
+
+#define ToString(p) CCECTypeUtils::ToString(p)
+
+CCECPlaybackDevice::CCECPlaybackDevice(CCECProcessor *processor, cec_logical_address address, uint16_t iPhysicalAddress /* = CEC_INVALID_PHYSICAL_ADDRESS */) :
+ CCECBusDevice(processor, address, iPhysicalAddress),
+ m_deckStatus(CEC_DECK_INFO_STOP),
+ m_deckControlMode(CEC_DECK_CONTROL_MODE_STOP)
+{
+ m_type = CEC_DEVICE_TYPE_PLAYBACK_DEVICE;
+}
+
+cec_deck_info CCECPlaybackDevice::GetDeckStatus(const cec_logical_address UNUSED(initiator))
+{
+ CLockObject lock(m_mutex);
+ return m_deckStatus;
+}
+
+void CCECPlaybackDevice::SetDeckStatus(cec_deck_info deckStatus)
+{
+ CLockObject lock(m_mutex);
+ if (m_deckStatus != deckStatus)
+ {
+ m_processor->GetLib()->AddLog(CEC_LOG_DEBUG, ">> %s (%X): deck status changed from '%s' to '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_deckStatus), ToString(deckStatus));
+ m_deckStatus = deckStatus;
+ }
+}
+
+cec_deck_control_mode CCECPlaybackDevice::GetDeckControlMode(const cec_logical_address UNUSED(initiator))
+{
+ CLockObject lock(m_mutex);
+ return m_deckControlMode;
+}
+
+void CCECPlaybackDevice::SetDeckControlMode(cec_deck_control_mode mode)
+{
+ CLockObject lock(m_mutex);
+ if (m_deckControlMode != mode)
+ {
+ m_processor->GetLib()->AddLog(CEC_LOG_DEBUG, ">> %s (%X): deck control mode changed from '%s' to '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_deckControlMode), ToString(mode));
+ m_deckControlMode = mode;
+ }
+}
+
+bool CCECPlaybackDevice::TransmitDeckStatus(cec_logical_address dest, bool bIsReply)
+{
+ cec_deck_info state;
+ {
+ CLockObject lock(m_mutex);
+ m_processor->GetLib()->AddLog(CEC_LOG_DEBUG, "<< %s (%X) -> %s (%X): deck status '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, ToString(m_deckStatus));
+ state = m_deckStatus;
+ }
+
+ return m_handler->TransmitDeckStatus(m_iLogicalAddress, dest, state, bIsReply);
+}
+
+void CCECPlaybackDevice::ResetDeviceStatus(void)
+{
+ CLockObject lock(m_mutex);
+ m_deckStatus = CEC_DECK_INFO_STOP;
+ m_deckControlMode = CEC_DECK_CONTROL_MODE_STOP;
+ CCECBusDevice::ResetDeviceStatus();
+}
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include "CECBusDevice.h"
+
+namespace CEC
+{
+ class CCECPlaybackDevice : public CCECBusDevice
+ {
+ public:
+ CCECPlaybackDevice(CCECProcessor *processor, cec_logical_address address, uint16_t iPhysicalAddress = CEC_INVALID_PHYSICAL_ADDRESS);
+ virtual ~CCECPlaybackDevice(void) {};
+
+ cec_deck_info GetDeckStatus(const cec_logical_address initiator);
+ cec_deck_control_mode GetDeckControlMode(const cec_logical_address initiator);
+
+ void SetDeckStatus(cec_deck_info deckStatus);
+ void SetDeckControlMode(cec_deck_control_mode mode);
+
+ bool TransmitDeckStatus(cec_logical_address dest, bool bIsReply);
+
+ virtual void ResetDeviceStatus(void);
+
+ protected:
+ cec_deck_info m_deckStatus;
+ cec_deck_control_mode m_deckControlMode;
+ };
+}
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include "CECRecordingDevice.h"
+
+using namespace CEC;
+using namespace P8PLATFORM;
+
+CCECRecordingDevice::CCECRecordingDevice(CCECProcessor *processor, cec_logical_address address, uint16_t iPhysicalAddress /* = CEC_INVALID_PHYSICAL_ADDRESS */) :
+ CCECPlaybackDevice(processor, address, iPhysicalAddress),
+ m_tuner(processor, address, iPhysicalAddress)
+{
+ m_type = CEC_DEVICE_TYPE_RECORDING_DEVICE;
+}
+
+void CCECRecordingDevice::ResetDeviceStatus(void)
+{
+ CLockObject lock(m_mutex);
+ m_tuner.ResetDeviceStatus();
+ CCECPlaybackDevice::ResetDeviceStatus();
+}
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include "CECBusDevice.h"
+#include "CECPlaybackDevice.h"
+#include "CECTuner.h"
+
+namespace CEC
+{
+ class CCECRecordingDevice : public CCECPlaybackDevice
+ {
+ public:
+ CCECRecordingDevice(CCECProcessor *processor, cec_logical_address address, uint16_t iPhysicalAddress = CEC_INVALID_PHYSICAL_ADDRESS);
+ virtual ~CCECRecordingDevice(void) {};
+
+ virtual void ResetDeviceStatus(void);
+
+ /* TODO: tuner methods */
+ protected:
+ CCECTuner m_tuner;
+ };
+}
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include "CECTV.h"
+
+using namespace CEC;
+using namespace P8PLATFORM;
+
+CCECTV::CCECTV(CCECProcessor *processor, cec_logical_address address) :
+ CCECBusDevice(processor, address, CEC_PHYSICAL_ADDRESS_TV)
+{
+ m_type = CEC_DEVICE_TYPE_TV;
+}
+
+void CCECTV::ResetDeviceStatus(void)
+{
+ CLockObject lock(m_mutex);
+ CCECBusDevice::ResetDeviceStatus();
+}
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include "CECBusDevice.h"
+
+namespace CEC
+{
+ class CCECTV : public CCECBusDevice
+ {
+ public:
+ CCECTV(CCECProcessor *processor, cec_logical_address address);
+ virtual ~CCECTV(void) {};
+
+ virtual void ResetDeviceStatus(void);
+ };
+}
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include "CECTuner.h"
+
+using namespace CEC;
+using namespace P8PLATFORM;
+
+CCECTuner::CCECTuner(CCECProcessor *processor, cec_logical_address address, uint16_t iPhysicalAddress /* = CEC_INVALID_PHYSICAL_ADDRESS */) :
+ CCECBusDevice(processor, address, iPhysicalAddress)
+{
+ m_type = CEC_DEVICE_TYPE_TUNER;
+}
+
+void CCECTuner::ResetDeviceStatus(void)
+{
+ CLockObject lock(m_mutex);
+ CCECBusDevice::ResetDeviceStatus();
+}
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include "CECBusDevice.h"
+
+namespace CEC
+{
+ class CCECTuner : public CCECBusDevice
+ {
+ public:
+ CCECTuner(CCECProcessor *processor, cec_logical_address address, uint16_t iPhysicalAddress = CEC_INVALID_PHYSICAL_ADDRESS);
+ virtual ~CCECTuner(void) {};
+
+ virtual void ResetDeviceStatus(void);
+ };
+}
--- /dev/null
+#pragma once
+/*
+ * WARNING: Auto-generated file from env.h.in
+ *
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "cectypes.h"
+#include <p8-platform/os.h>
+
+#ifdef UNUSED
+#elif defined(__GNUC__)
+#define UNUSED(x) UNUSED_ ## x __attribute__((unused))
+#elif defined(__LCLINT__)
+#define UNUSED(x) /*@unused@*/ x
+#else
+#define UNUSED(x) x
+#endif
+
+#ifndef ON
+#define ON (1)
+#endif
+
+/* Define to 1 for xrandr support */
+#cmakedefine HAVE_RANDR @HAVE_RANDR@
+
+/* Define to 1 if <sys/file.h> should be included for flock() */
+#cmakedefine HAVE_SYS_FILE_HEADER @HAVE_SYS_FILE_HEADER@
+
+/* Define to 1 for flock() support */
+#cmakedefine HAVE_FLOCK @HAVE_FLOCK@
+
+/* Define to 1 for udev support */
+#cmakedefine HAVE_LIBUDEV @HAVE_LIBUDEV@
+
+/* Define to 1 for Pulse-Eight CEC Adapter support */
+#cmakedefine HAVE_P8_USB @HAVE_P8_USB@
+
+/* Define to 1 for Pulse-Eight CEC Adapter detection support */
+#cmakedefine HAVE_P8_USB_DETECT @HAVE_P8_USB_DETECT@
+
+/* Define to 1 for Raspberry Pi support */
+#cmakedefine HAVE_RPI_API @HAVE_RPI_API@
+
+/* Define to 1 for TDA995x support */
+#cmakedefine HAVE_TDA995X_API @HAVE_TDA995X_API@
+
+/* Define to 1 for Exynos support */
+#cmakedefine HAVE_EXYNOS_API @HAVE_EXYNOS_API@
+
+/* Define to 1 for AOCEC support */
+#cmakedefine HAVE_AOCEC_API @HAVE_AOCEC_API@
+
+/* Define to 1 for nVidia EDID parsing support (on selected models) */
+#cmakedefine HAVE_NVIDIA_EDID_PARSER @HAVE_NVIDIA_EDID_PARSER@
+
+/* Define to 1 for DRM EDID parsing support */
+#cmakedefine HAVE_DRM_EDID_PARSER @HAVE_DRM_EDID_PARSER@
+
+/* Define to 1 for Python support */
+#cmakedefine HAVE_PYTHON @HAVE_PYTHON@
+
+/* information about how libCEC was compiled */
+#define LIB_INFO ("@LIB_INFO@")
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include "ANCommandHandler.h"
+
+#include "devices/CECBusDevice.h"
+#include "CECProcessor.h"
+#include "LibCEC.h"
+#include "CECClient.h"
+
+using namespace CEC;
+
+#define LIB_CEC m_busDevice->GetProcessor()->GetLib()
+#define ToString(p) LIB_CEC->ToString(p)
+
+CANCommandHandler::CANCommandHandler(CCECBusDevice *busDevice,
+ int32_t iTransmitTimeout /* = CEC_DEFAULT_TRANSMIT_TIMEOUT */,
+ int32_t iTransmitWait /* = CEC_DEFAULT_TRANSMIT_WAIT */,
+ int8_t iTransmitRetries /* = CEC_DEFAULT_TRANSMIT_RETRIES */,
+ int64_t iActiveSourcePending /* = 0 */) :
+ CCECCommandHandler(busDevice, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending)
+{
+ m_vendorId = CEC_VENDOR_SAMSUNG;
+ m_bOPTSendDeckStatusUpdateOnActiveSource = false;
+}
+
+int CANCommandHandler::HandleVendorRemoteButtonDown(const cec_command &command)
+{
+ if (command.parameters.size == 0)
+ return CEC_ABORT_REASON_INVALID_OPERAND;
+
+ if (!m_processor->CECInitialised())
+ return CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND;
+
+ CECClientPtr client = m_processor->GetClient(command.destination);
+ if (!client)
+ return CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND;
+
+ cec_keypress key;
+ key.duration = CEC_BUTTON_TIMEOUT;
+ key.keycode = (cec_user_control_code)command.parameters[0];
+
+ if (client)
+ client->AddKey(key);
+
+ return COMMAND_HANDLED;
+}
+
+bool CANCommandHandler::PowerOn(const cec_logical_address iInitiator, const cec_logical_address iDestination)
+{
+ if (iDestination == CECDEVICE_AUDIOSYSTEM)
+ {
+ /* Samsung AVR devices need to be woken up with key CEC_USER_CONTROL_CODE_POWER_ON_FUNCTION */
+ return TransmitKeypress(iInitiator, iDestination, CEC_USER_CONTROL_CODE_POWER_ON_FUNCTION) &&
+ TransmitKeyRelease(iInitiator, iDestination);
+ }
+
+ return CCECCommandHandler::PowerOn(iInitiator, iDestination);
+}
+
+int CANCommandHandler::HandleDeviceVendorCommandWithId(const cec_command &command)
+{
+ if (!m_processor->IsHandledByLibCEC(command.destination))
+ return CEC_ABORT_REASON_INVALID_OPERAND;
+
+ // samsung's vendor id
+ if (command.parameters[0] == 0x00 && command.parameters[1] == 0x00 && command.parameters[2] == 0xf0)
+ {
+ // unknown vendor command sent to devices
+ if (command.parameters[3] == 0x23)
+ {
+ cec_command response;
+ cec_command::Format(response, command.destination, command.initiator, CEC_OPCODE_VENDOR_COMMAND_WITH_ID);
+
+ // samsung vendor id
+ response.parameters.PushBack(0x00); response.parameters.PushBack(0x00); response.parameters.PushBack(0xf0);
+
+ // XXX see bugzid 2164. reply sent back by audio systems, we might have to send something different
+ response.parameters.PushBack(0x24);
+ response.parameters.PushBack(0x00);
+ response.parameters.PushBack(0x80);
+
+ Transmit(response, false, true);
+ return COMMAND_HANDLED;
+ }
+ }
+ return CEC_ABORT_REASON_INVALID_OPERAND;
+}
+
+int CANCommandHandler::HandleSetMenuLanguage(const cec_command &command)
+{
+ if (m_processor->CECInitialised() && command.initiator == CECDEVICE_TV && command.destination == CECDEVICE_BROADCAST)
+ {
+ m_processor->GetDevice(command.initiator)->SetPowerStatus(CEC_POWER_STATUS_ON);
+ }
+
+ return CCECCommandHandler::HandleSetMenuLanguage(command);
+}
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include "CECCommandHandler.h"
+
+namespace CEC
+{
+ class CANCommandHandler : public CCECCommandHandler
+ {
+ public:
+ CANCommandHandler(CCECBusDevice *busDevice,
+ int32_t iTransmitTimeout = CEC_DEFAULT_TRANSMIT_TIMEOUT,
+ int32_t iTransmitWait = CEC_DEFAULT_TRANSMIT_WAIT,
+ int8_t iTransmitRetries = CEC_DEFAULT_TRANSMIT_RETRIES,
+ int64_t iActiveSourcePending = 0);
+ virtual ~CANCommandHandler(void) {};
+
+ int HandleVendorRemoteButtonDown(const cec_command &command);
+ int HandleDeviceVendorCommandWithId(const cec_command &command);
+ int HandleSetMenuLanguage(const cec_command &command);
+
+ protected:
+ bool PowerOn(const cec_logical_address iInitiator, const cec_logical_address iDestination);
+ };
+};
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include "AQCommandHandler.h"
+
+#include "devices/CECBusDevice.h"
+#include "CECProcessor.h"
+#include "LibCEC.h"
+#include "CECClient.h"
+
+using namespace CEC;
+using namespace P8PLATFORM;
+
+#define LIB_CEC m_busDevice->GetProcessor()->GetLib()
+#define ToString(p) LIB_CEC->ToString(p)
+
+CAQCommandHandler::CAQCommandHandler(CCECBusDevice *busDevice,
+ int32_t iTransmitTimeout /* = CEC_DEFAULT_TRANSMIT_TIMEOUT */,
+ int32_t iTransmitWait /* = CEC_DEFAULT_TRANSMIT_WAIT */,
+ int8_t iTransmitRetries /* = CEC_DEFAULT_TRANSMIT_RETRIES */,
+ int64_t iActiveSourcePending /* = 0 */) :
+ CCECCommandHandler(busDevice, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending),
+ m_powerOnCheck(NULL)
+{
+ m_vendorId = CEC_VENDOR_SHARP;
+}
+
+CAQCommandHandler::~CAQCommandHandler(void)
+{
+ delete m_powerOnCheck;
+}
+
+bool CAQCommandHandler::PowerOn(const cec_logical_address iInitiator, const cec_logical_address iDestination)
+{
+ bool bCheck(false);
+ bool bRetval(false);
+ if (m_busDevice->GetCurrentPowerStatus() != CEC_POWER_STATUS_ON && (!m_powerOnCheck || !m_powerOnCheck->IsRunning()))
+ bCheck = true;
+ bRetval = CCECCommandHandler::PowerOn(iInitiator, iDestination);
+
+ if (bRetval && bCheck)
+ {
+ if (!m_powerOnCheck)
+ m_powerOnCheck = new CAQPowerStatusCheck(this, iInitiator, iDestination);
+ if (m_powerOnCheck)
+ m_powerOnCheck->CreateThread();
+ }
+
+ return bRetval;
+}
+
+void* CAQPowerStatusCheck::Process(void)
+{
+ // sleep for 2 seconds and query the power status
+ Sleep(2000);
+ if (m_handler->m_busDevice->GetProcessor()->GetDevice(m_iDestination)->GetPowerStatus(m_iInitiator, true) == CEC_POWER_STATUS_STANDBY)
+ m_handler->m_busDevice->GetProcessor()->GetLib()->AddLog(CEC_LOG_WARNING, "AQUOS LINK 'auto power on' is disabled, which prevents the TV from being powered on. To correct this, press the menu button on your remote, go to 'link operation' -> 'AQUOS LINK setup' -> 'Auto power on' and set it to 'On'");
+ return NULL;
+}
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include "CECCommandHandler.h"
+#include <p8-platform/threads/threads.h>
+
+namespace CEC
+{
+ class CAQPowerStatusCheck;
+
+ class CAQCommandHandler : public CCECCommandHandler
+ {
+ friend class CAQPowerStatusCheck;
+ public:
+ CAQCommandHandler(CCECBusDevice *busDevice,
+ int32_t iTransmitTimeout = CEC_DEFAULT_TRANSMIT_TIMEOUT,
+ int32_t iTransmitWait = CEC_DEFAULT_TRANSMIT_WAIT,
+ int8_t iTransmitRetries = CEC_DEFAULT_TRANSMIT_RETRIES,
+ int64_t iActiveSourcePending = 0);
+ virtual ~CAQCommandHandler(void);
+
+ protected:
+ virtual bool PowerOn(const cec_logical_address iInitiator, const cec_logical_address iDestination);
+
+ private:
+ CAQPowerStatusCheck* m_powerOnCheck;
+ };
+
+ class CAQPowerStatusCheck : public P8PLATFORM::CThread
+ {
+ public:
+ CAQPowerStatusCheck(CAQCommandHandler* handler, cec_logical_address iInitiator, cec_logical_address iDestination) :
+ m_handler(handler),
+ m_iInitiator(iInitiator),
+ m_iDestination(iDestination) {}
+ virtual ~CAQPowerStatusCheck(void) {}
+
+ private:
+ void* Process(void);
+ CAQCommandHandler* m_handler;
+ cec_logical_address m_iInitiator;
+ cec_logical_address m_iDestination;
+ };
+};
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include "CECCommandHandler.h"
+
+#include "devices/CECBusDevice.h"
+#include "devices/CECAudioSystem.h"
+#include "devices/CECPlaybackDevice.h"
+#include "CECClient.h"
+#include "CECProcessor.h"
+#include "LibCEC.h"
+#include "CECTypeUtils.h"
+#include <p8-platform/util/util.h>
+
+using namespace CEC;
+using namespace P8PLATFORM;
+
+#define LIB_CEC m_busDevice->GetProcessor()->GetLib()
+#define ToString(p) CCECTypeUtils::ToString(p)
+#define REQUEST_POWER_STATUS_TIMEOUT 5000
+
+CCECCommandHandler::CCECCommandHandler(CCECBusDevice *busDevice,
+ int32_t iTransmitTimeout /* = CEC_DEFAULT_TRANSMIT_TIMEOUT */,
+ int32_t iTransmitWait /* = CEC_DEFAULT_TRANSMIT_WAIT */,
+ int8_t iTransmitRetries /* = CEC_DEFAULT_TRANSMIT_RETRIES */,
+ int64_t iActiveSourcePending /* = 0 */) :
+ m_busDevice(busDevice),
+ m_processor(m_busDevice->GetProcessor()),
+ m_iTransmitTimeout(iTransmitTimeout),
+ m_iTransmitWait(iTransmitWait),
+ m_iTransmitRetries(iTransmitRetries),
+ m_bHandlerInited(false),
+ m_bOPTSendDeckStatusUpdateOnActiveSource(false),
+ m_vendorId(CEC_VENDOR_UNKNOWN),
+ m_iActiveSourcePending(iActiveSourcePending),
+ m_iPowerStatusRequested(0)
+{
+}
+
+bool CCECCommandHandler::HandleCommand(const cec_command &command)
+{
+ if (command.opcode_set == 0)
+ return HandlePoll(command);
+
+ int iHandled(CEC_ABORT_REASON_UNRECOGNIZED_OPCODE);
+
+ LIB_CEC->AddCommand(command);
+
+ switch(command.opcode)
+ {
+ case CEC_OPCODE_REPORT_POWER_STATUS:
+ iHandled = HandleReportPowerStatus(command);
+ break;
+ case CEC_OPCODE_CEC_VERSION:
+ iHandled = HandleDeviceCecVersion(command);
+ break;
+ case CEC_OPCODE_SET_MENU_LANGUAGE:
+ iHandled = HandleSetMenuLanguage(command);
+ break;
+ case CEC_OPCODE_GIVE_PHYSICAL_ADDRESS:
+ iHandled = HandleGivePhysicalAddress(command);
+ break;
+ case CEC_OPCODE_GET_MENU_LANGUAGE:
+ iHandled = HandleGiveMenuLanguage(command);
+ break;
+ case CEC_OPCODE_GIVE_OSD_NAME:
+ iHandled = HandleGiveOSDName(command);
+ break;
+ case CEC_OPCODE_GIVE_DEVICE_VENDOR_ID:
+ iHandled = HandleGiveDeviceVendorId(command);
+ break;
+ case CEC_OPCODE_DEVICE_VENDOR_ID:
+ iHandled = HandleDeviceVendorId(command);
+ break;
+ case CEC_OPCODE_VENDOR_COMMAND_WITH_ID:
+ iHandled = HandleDeviceVendorCommandWithId(command);
+ break;
+ case CEC_OPCODE_GIVE_DECK_STATUS:
+ iHandled = HandleGiveDeckStatus(command);
+ break;
+ case CEC_OPCODE_DECK_CONTROL:
+ iHandled = HandleDeckControl(command);
+ break;
+ case CEC_OPCODE_MENU_REQUEST:
+ iHandled = HandleMenuRequest(command);
+ break;
+ case CEC_OPCODE_GIVE_DEVICE_POWER_STATUS:
+ iHandled = HandleGiveDevicePowerStatus(command);
+ break;
+ case CEC_OPCODE_GET_CEC_VERSION:
+ iHandled = HandleGetCecVersion(command);
+ break;
+ case CEC_OPCODE_USER_CONTROL_PRESSED:
+ iHandled = HandleUserControlPressed(command);
+ break;
+ case CEC_OPCODE_USER_CONTROL_RELEASE:
+ iHandled = HandleUserControlRelease(command);
+ break;
+ case CEC_OPCODE_GIVE_AUDIO_STATUS:
+ iHandled = HandleGiveAudioStatus(command);
+ break;
+ case CEC_OPCODE_GIVE_SYSTEM_AUDIO_MODE_STATUS:
+ iHandled = HandleGiveSystemAudioModeStatus(command);
+ break;
+ case CEC_OPCODE_SYSTEM_AUDIO_MODE_REQUEST:
+ iHandled = HandleSystemAudioModeRequest(command);
+ break;
+ case CEC_OPCODE_REPORT_AUDIO_STATUS:
+ iHandled = HandleReportAudioStatus(command);
+ break;
+ case CEC_OPCODE_SYSTEM_AUDIO_MODE_STATUS:
+ iHandled = HandleSystemAudioModeStatus(command);
+ break;
+ case CEC_OPCODE_SET_SYSTEM_AUDIO_MODE:
+ iHandled = HandleSetSystemAudioMode(command);
+ break;
+ case CEC_OPCODE_REQUEST_ACTIVE_SOURCE:
+ iHandled = HandleRequestActiveSource(command);
+ break;
+ case CEC_OPCODE_SET_STREAM_PATH:
+ iHandled = HandleSetStreamPath(command);
+ break;
+ case CEC_OPCODE_ROUTING_CHANGE:
+ iHandled = HandleRoutingChange(command);
+ break;
+ case CEC_OPCODE_ROUTING_INFORMATION:
+ iHandled = HandleRoutingInformation(command);
+ break;
+ case CEC_OPCODE_STANDBY:
+ iHandled = HandleStandby(command);
+ break;
+ case CEC_OPCODE_ACTIVE_SOURCE:
+ iHandled = HandleActiveSource(command);
+ break;
+ case CEC_OPCODE_REPORT_PHYSICAL_ADDRESS:
+ iHandled = HandleReportPhysicalAddress(command);
+ break;
+ case CEC_OPCODE_SET_OSD_NAME:
+ iHandled = HandleSetOSDName(command);
+ break;
+ case CEC_OPCODE_IMAGE_VIEW_ON:
+ iHandled = HandleImageViewOn(command);
+ break;
+ case CEC_OPCODE_TEXT_VIEW_ON:
+ iHandled = HandleTextViewOn(command);
+ break;
+ case CEC_OPCODE_FEATURE_ABORT:
+ iHandled = HandleFeatureAbort(command);
+ break;
+ case CEC_OPCODE_VENDOR_COMMAND:
+ iHandled = HandleVendorCommand(command);
+ break;
+ case CEC_OPCODE_VENDOR_REMOTE_BUTTON_DOWN:
+ iHandled = HandleVendorRemoteButtonDown(command);
+ break;
+ case CEC_OPCODE_VENDOR_REMOTE_BUTTON_UP:
+ iHandled = HandleVendorRemoteButtonUp(command);
+ break;
+ case CEC_OPCODE_PLAY:
+ // libCEC (currently) doesn't need to do anything with this, since player applications handle it
+ // but it should not respond with a feature abort
+ iHandled = COMMAND_HANDLED;
+ break;
+ default:
+ break;
+ }
+
+ if (iHandled == COMMAND_HANDLED)
+ m_busDevice->SignalOpcode((command.opcode == CEC_OPCODE_FEATURE_ABORT && command.parameters.size > 0) ? (cec_opcode)command.parameters[0] : command.opcode);
+ else
+ UnhandledCommand(command, (cec_abort_reason)iHandled);
+
+ return iHandled == COMMAND_HANDLED;
+}
+
+int CCECCommandHandler::HandleActiveSource(const cec_command &command)
+{
+ if (command.parameters.size == 2)
+ {
+ uint16_t iAddress = ((uint16_t)command.parameters[0] << 8) | ((uint16_t)command.parameters[1]);
+ CCECBusDevice *device = m_processor->GetDevice(command.initiator);
+ if (device)
+ {
+ device->SetPhysicalAddress(iAddress);
+ device->MarkAsActiveSource();
+ }
+
+ m_processor->GetDevices()->SignalAll(command.opcode);
+ return COMMAND_HANDLED;
+ }
+
+ return CEC_ABORT_REASON_INVALID_OPERAND;
+}
+
+int CCECCommandHandler::HandleDeckControl(const cec_command &command)
+{
+ CCECPlaybackDevice *device = CCECBusDevice::AsPlaybackDevice(GetDevice(command.destination));
+ if (device && command.parameters.size > 0)
+ {
+ device->SetDeckControlMode((cec_deck_control_mode) command.parameters[0]);
+ return COMMAND_HANDLED;
+ }
+
+ return CEC_ABORT_REASON_INVALID_OPERAND;
+}
+
+int CCECCommandHandler::HandleDeviceCecVersion(const cec_command &command)
+{
+ if (command.parameters.size == 1)
+ {
+ CCECBusDevice *device = GetDevice(command.initiator);
+ if (device)
+ device->SetCecVersion((cec_version) command.parameters[0]);
+
+ return COMMAND_HANDLED;
+ }
+
+ return CEC_ABORT_REASON_INVALID_OPERAND;
+}
+
+int CCECCommandHandler::HandleDeviceVendorCommandWithId(const cec_command& command)
+{
+ if (command.parameters.size < 3)
+ return CEC_ABORT_REASON_INVALID_OPERAND;
+
+ CCECBusDevice *device = GetDevice((cec_logical_address) command.initiator);
+ uint64_t iVendorId = ((uint64_t)command.parameters[0] << 16) +
+ ((uint64_t)command.parameters[1] << 8) +
+ (uint64_t)command.parameters[2];
+
+ if (device && device->GetCurrentVendorId() == CEC_VENDOR_UNKNOWN && device->SetVendorId(iVendorId))
+ {
+ /** vendor id changed, parse command after the handler has been replaced */
+ if (HasSpecificHandler((cec_vendor_id)iVendorId))
+ {
+ LIB_CEC->AddLog(CEC_LOG_TRAFFIC, ">> process after replacing vendor handler: %s", ToString(command).c_str());
+ m_processor->OnCommandReceived(command);
+ return COMMAND_HANDLED;
+ }
+ }
+
+ if (iVendorId == CEC_VENDOR_PIONEER && command.initiator == CECDEVICE_AUDIOSYSTEM)
+ {
+ /** ignore vendor commands from pioneer AVRs */
+ return CEC_ABORT_REASON_REFUSED;
+ }
+
+ return CEC_ABORT_REASON_INVALID_OPERAND;
+}
+
+int CCECCommandHandler::HandleDeviceVendorId(const cec_command &command)
+{
+ SetVendorId(command);
+
+ if (command.initiator == CECDEVICE_TV)
+ {
+ CCECBusDevice* primary = m_processor->GetPrimaryDevice();
+ if (primary)
+ primary->TransmitVendorID(CECDEVICE_BROADCAST, false, false);
+ }
+
+ return COMMAND_HANDLED;
+}
+
+int CCECCommandHandler::HandleFeatureAbort(const cec_command &command)
+{
+ if (command.parameters.size == 2 &&
+ (command.parameters[1] == CEC_ABORT_REASON_UNRECOGNIZED_OPCODE ||
+ command.parameters[1] == CEC_ABORT_REASON_REFUSED))
+ m_processor->GetDevice(command.initiator)->SetUnsupportedFeature((cec_opcode)command.parameters[0]);
+ return COMMAND_HANDLED;
+}
+
+int CCECCommandHandler::HandleGetCecVersion(const cec_command &command)
+{
+ if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
+ {
+ CCECBusDevice *device = GetDevice(command.destination);
+ if (device)
+ {
+ device->TransmitCECVersion(command.initiator, true);
+ return COMMAND_HANDLED;
+ }
+ return CEC_ABORT_REASON_INVALID_OPERAND;
+ }
+
+ return CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND;
+}
+
+int CCECCommandHandler::HandleGiveAudioStatus(const cec_command &command)
+{
+ if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
+ {
+ CCECAudioSystem *device = CCECBusDevice::AsAudioSystem(GetDevice(command.destination));
+ if (device)
+ {
+ device->TransmitAudioStatus(command.initiator, true);
+ return COMMAND_HANDLED;
+ }
+ return CEC_ABORT_REASON_INVALID_OPERAND;
+ }
+
+ return CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND;
+}
+
+int CCECCommandHandler::HandleGiveDeckStatus(const cec_command &command)
+{
+ if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
+ {
+ CCECPlaybackDevice *device = CCECBusDevice::AsPlaybackDevice(GetDevice(command.destination));
+ if (device)
+ {
+ device->TransmitDeckStatus(command.initiator, true);
+ return COMMAND_HANDLED;
+ }
+ return CEC_ABORT_REASON_INVALID_OPERAND;
+ }
+
+ return CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND;
+}
+
+int CCECCommandHandler::HandleGiveDevicePowerStatus(const cec_command &command)
+{
+ if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
+ {
+ CCECBusDevice *device = GetDevice(command.destination);
+ if (device)
+ {
+ device->TransmitPowerState(command.initiator, true);
+ return COMMAND_HANDLED;
+ }
+ return CEC_ABORT_REASON_INVALID_OPERAND;
+ }
+
+ return CEC_ABORT_REASON_INVALID_OPERAND;
+}
+
+int CCECCommandHandler::HandleGiveDeviceVendorId(const cec_command &command)
+{
+ if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
+ {
+ CCECBusDevice *device = GetDevice(command.destination);
+ if (device)
+ {
+ device->TransmitVendorID(command.initiator, true, true);
+ return COMMAND_HANDLED;
+ }
+ }
+
+ return CEC_ABORT_REASON_INVALID_OPERAND;
+}
+
+int CCECCommandHandler::HandleGiveOSDName(const cec_command &command)
+{
+ if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
+ {
+ CCECBusDevice *device = GetDevice(command.destination);
+ if (device)
+ {
+ device->TransmitOSDName(command.initiator, true);
+ return COMMAND_HANDLED;
+ }
+ }
+
+ return CEC_ABORT_REASON_INVALID_OPERAND;
+}
+
+int CCECCommandHandler::HandleGivePhysicalAddress(const cec_command &command)
+{
+ if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
+ {
+ CCECBusDevice *device = GetDevice(command.destination);
+ if (device)
+ {
+ device->TransmitPhysicalAddress(true);
+ return COMMAND_HANDLED;
+ }
+ return CEC_ABORT_REASON_INVALID_OPERAND;
+ }
+
+ return CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND;
+}
+
+int CCECCommandHandler::HandleGiveMenuLanguage(const cec_command &command)
+{
+ if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
+ {
+ CCECBusDevice *device = GetDevice(command.destination);
+ if (device)
+ {
+ device->TransmitSetMenuLanguage(command.initiator, true);
+ return COMMAND_HANDLED;
+ }
+ return CEC_ABORT_REASON_INVALID_OPERAND;
+ }
+
+ return CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND;
+}
+
+int CCECCommandHandler::HandleGiveSystemAudioModeStatus(const cec_command &command)
+{
+ if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
+ {
+ CCECAudioSystem *device = CCECBusDevice::AsAudioSystem(GetDevice(command.destination));
+ if (device)
+ {
+ device->TransmitSystemAudioModeStatus(command.initiator, true);
+ return COMMAND_HANDLED;
+ }
+ return CEC_ABORT_REASON_INVALID_OPERAND;
+ }
+
+ return CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND;
+}
+
+int CCECCommandHandler::HandleImageViewOn(const cec_command &command)
+{
+ CCECBusDevice *device = GetDevice(command.destination);
+ if (device && device->GetCurrentStatus() == CEC_DEVICE_STATUS_PRESENT)
+ {
+ if (device->GetCurrentPowerStatus() == CEC_POWER_STATUS_STANDBY ||
+ device->GetCurrentPowerStatus() == CEC_POWER_STATUS_IN_TRANSITION_ON_TO_STANDBY)
+ device->SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON);
+ CCECBusDevice* tv = GetDevice(CECDEVICE_TV);
+ if (tv)
+ tv->OnImageViewOnSent(false);
+ }
+ return COMMAND_HANDLED;
+}
+
+int CCECCommandHandler::HandleMenuRequest(const cec_command &command)
+{
+ if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
+ {
+ CCECBusDevice *device = GetDevice(command.destination);
+ if (device)
+ {
+ CECClientPtr client = device->GetClient();
+ if (client)
+ {
+ if (command.parameters[0] == CEC_MENU_REQUEST_TYPE_ACTIVATE)
+ {
+ if (client->QueueMenuStateChanged(CEC_MENU_STATE_ACTIVATED) == 1)
+ device->SetMenuState(CEC_MENU_STATE_ACTIVATED);
+ }
+ else if (command.parameters[0] == CEC_MENU_REQUEST_TYPE_DEACTIVATE)
+ {
+ if (client->QueueMenuStateChanged(CEC_MENU_STATE_DEACTIVATED) == 1)
+ device->SetMenuState(CEC_MENU_STATE_DEACTIVATED);
+ }
+ }
+ device->TransmitMenuState(command.initiator, true);
+ return COMMAND_HANDLED;
+ }
+ return CEC_ABORT_REASON_INVALID_OPERAND;
+ }
+
+ return CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND;
+}
+
+bool CCECCommandHandler::HandlePoll(const cec_command &command)
+{
+ m_busDevice->HandlePoll(command.destination);
+ return true;
+}
+
+int CCECCommandHandler::HandleReportAudioStatus(const cec_command &command)
+{
+ if (command.parameters.size == 1)
+ {
+ CCECAudioSystem *device = CCECBusDevice::AsAudioSystem(GetDevice(command.initiator));
+ if (device)
+ {
+ device->SetAudioStatus(command.parameters[0]);
+ return COMMAND_HANDLED;
+ }
+ }
+ return CEC_ABORT_REASON_INVALID_OPERAND;
+}
+
+int CCECCommandHandler::HandleReportPhysicalAddress(const cec_command &command)
+{
+ if (command.parameters.size == 3)
+ {
+ uint16_t iNewAddress = ((uint16_t)command.parameters[0] << 8) | ((uint16_t)command.parameters[1]);
+ SetPhysicalAddress(command.initiator, iNewAddress);
+
+ if (command.initiator == CECDEVICE_TV)
+ {
+ CCECBusDevice* primary = m_processor->GetPrimaryDevice();
+ if (primary)
+ primary->TransmitPhysicalAddress(false);
+ }
+ return COMMAND_HANDLED;
+ }
+ return CEC_ABORT_REASON_INVALID_OPERAND;
+}
+
+int CCECCommandHandler::HandleReportPowerStatus(const cec_command &command)
+{
+ if (command.parameters.size == 1)
+ {
+ CCECBusDevice *device = GetDevice(command.initiator);
+ if (device)
+ {
+ device->SetPowerStatus((cec_power_status) command.parameters[0]);
+ return COMMAND_HANDLED;
+ }
+ }
+ return CEC_ABORT_REASON_INVALID_OPERAND;
+}
+
+int CCECCommandHandler::HandleRequestActiveSource(const cec_command &command)
+{
+ if (m_processor->CECInitialised())
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, ">> %i requests active source", (uint8_t) command.initiator);
+ m_processor->GetDevice(command.initiator)->SetPowerStatus(CEC_POWER_STATUS_ON);
+
+ std::vector<CCECBusDevice *> devices;
+ for (size_t iDevicePtr = 0; iDevicePtr < GetMyDevices(devices); iDevicePtr++)
+ devices[iDevicePtr]->TransmitActiveSource(true);
+ }
+
+ return COMMAND_HANDLED;
+}
+
+int CCECCommandHandler::HandleRoutingChange(const cec_command &command)
+{
+ if (command.parameters.size == 4)
+ {
+ CCECBusDevice *device = GetDevice(command.initiator);
+ if (device)
+ {
+ uint16_t iNewAddress = ((uint16_t)command.parameters[2] << 8) | ((uint16_t)command.parameters[3]);
+ /** only powered on device send routing changes */
+ device->SetPowerStatus(CEC_POWER_STATUS_ON);
+ device->SetActiveRoute(iNewAddress);
+ return COMMAND_HANDLED;
+ }
+ }
+
+ return CEC_ABORT_REASON_INVALID_OPERAND;
+}
+
+int CCECCommandHandler::HandleRoutingInformation(const cec_command &command)
+{
+ if (command.parameters.size == 2)
+ {
+ CCECBusDevice *device = GetDevice(command.initiator);
+ if (device)
+ {
+ uint16_t iNewAddress = ((uint16_t)command.parameters[0] << 8) | ((uint16_t)command.parameters[1]);
+ device->SetActiveRoute(iNewAddress);
+ return COMMAND_HANDLED;
+ }
+ }
+
+ return CEC_ABORT_REASON_INVALID_OPERAND;
+}
+
+int CCECCommandHandler::HandleSetMenuLanguage(const cec_command &command)
+{
+ if (command.parameters.size == 3)
+ {
+ CCECBusDevice *device = GetDevice(command.initiator);
+ if (device)
+ {
+ cec_menu_language language;
+ for (uint8_t iPtr = 0; iPtr < 3; iPtr++)
+ language[iPtr] = command.parameters[iPtr];
+ language[3] = (char)0;
+ device->SetMenuLanguage(language);
+ return COMMAND_HANDLED;
+ }
+ }
+
+ return CEC_ABORT_REASON_INVALID_OPERAND;
+}
+
+int CCECCommandHandler::HandleSetOSDName(const cec_command &command)
+{
+ if (command.parameters.size > 0)
+ {
+ CCECBusDevice *device = GetDevice(command.initiator);
+ if (device)
+ {
+ char buf[1024];
+ for (uint8_t iPtr = 0; iPtr < command.parameters.size; iPtr++)
+ buf[iPtr] = (char)command.parameters[iPtr];
+ buf[command.parameters.size] = 0;
+
+ std::string strName(buf);
+ device->SetOSDName(strName);
+
+ return COMMAND_HANDLED;
+ }
+ }
+
+ return CEC_ABORT_REASON_INVALID_OPERAND;
+}
+
+int CCECCommandHandler::HandleSetStreamPath(const cec_command &command)
+{
+ if (!m_processor->CECInitialised())
+ return CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND;
+
+ if (command.parameters.size >= 2)
+ {
+ uint16_t iStreamAddress = ((uint16_t)command.parameters[0] << 8) | ((uint16_t)command.parameters[1]);
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, ">> %s (%x) sets stream path to physical address %04x", ToString(command.initiator), command.initiator, iStreamAddress);
+
+ /* one of the device handled by libCEC has been made active */
+ CCECBusDevice *device = GetDeviceByPhysicalAddress(iStreamAddress);
+ if (device)
+ {
+ if (device->IsHandledByLibCEC())
+ {
+ if (!device->IsActiveSource())
+ device->ActivateSource();
+ else
+ {
+ device->MarkAsActiveSource();
+ device->TransmitActiveSource(true);
+ }
+ }
+ return COMMAND_HANDLED;
+ }
+ }
+
+ return CEC_ABORT_REASON_INVALID_OPERAND;
+}
+
+int CCECCommandHandler::HandleSystemAudioModeRequest(const cec_command &command)
+{
+ if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
+ {
+ CCECAudioSystem *device = CCECBusDevice::AsAudioSystem(GetDevice(command.destination));
+ if (device)
+ {
+ if (command.parameters.size >= 2)
+ {
+ device->SetPowerStatus(CEC_POWER_STATUS_ON);
+ device->SetSystemAudioModeStatus(CEC_SYSTEM_AUDIO_STATUS_ON);
+ uint16_t iNewAddress = ((uint16_t)command.parameters[0] << 8) | ((uint16_t)command.parameters[1]);
+ CCECBusDevice *newActiveDevice = GetDeviceByPhysicalAddress(iNewAddress);
+ if (newActiveDevice)
+ newActiveDevice->MarkAsActiveSource();
+ device->TransmitSetSystemAudioMode(command.initiator, true);
+ }
+ else
+ {
+ device->SetSystemAudioModeStatus(CEC_SYSTEM_AUDIO_STATUS_OFF);
+ device->TransmitSetSystemAudioMode(command.initiator, true);
+ }
+
+ return COMMAND_HANDLED;
+ }
+ }
+
+ return CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND;
+}
+
+int CCECCommandHandler::HandleStandby(const cec_command &command)
+{
+ CCECBusDevice *device = GetDevice(command.initiator);
+ if (device)
+ device->SetPowerStatus(CEC_POWER_STATUS_STANDBY);
+
+ return COMMAND_HANDLED;
+}
+
+int CCECCommandHandler::HandleSystemAudioModeStatus(const cec_command &command)
+{
+ if (command.parameters.size == 1)
+ {
+ CCECAudioSystem *device = CCECBusDevice::AsAudioSystem(GetDevice(command.initiator));
+ if (device)
+ {
+ device->SetSystemAudioModeStatus((cec_system_audio_status)command.parameters[0]);
+ return COMMAND_HANDLED;
+ }
+ }
+
+ return CEC_ABORT_REASON_INVALID_OPERAND;
+}
+
+int CCECCommandHandler::HandleSetSystemAudioMode(const cec_command &command)
+{
+ if (command.parameters.size == 1)
+ {
+ CCECAudioSystem *device = CCECBusDevice::AsAudioSystem(GetDevice(command.initiator));
+ if (device)
+ {
+ device->SetSystemAudioModeStatus((cec_system_audio_status)command.parameters[0]);
+ return COMMAND_HANDLED;
+ }
+ }
+
+ return CEC_ABORT_REASON_INVALID_OPERAND;
+}
+
+int CCECCommandHandler::HandleTextViewOn(const cec_command &command)
+{
+ m_processor->GetDevice(command.initiator)->MarkAsActiveSource();
+ return COMMAND_HANDLED;
+}
+
+int CCECCommandHandler::HandleUserControlPressed(const cec_command &command)
+{
+ if (!m_processor->CECInitialised() ||
+ !m_processor->IsHandledByLibCEC(command.destination))
+ return CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND;
+
+ if (command.parameters.size == 0)
+ return CEC_ABORT_REASON_INVALID_OPERAND;
+
+ CCECBusDevice *device = GetDevice(command.destination);
+ if (!device)
+ return CEC_ABORT_REASON_INVALID_OPERAND;
+
+ CECClientPtr client = device->GetClient();
+ if (client)
+ client->SetCurrentButton((cec_user_control_code) command.parameters[0]);
+
+ if (command.parameters[0] == CEC_USER_CONTROL_CODE_POWER ||
+ command.parameters[0] == CEC_USER_CONTROL_CODE_POWER_ON_FUNCTION||
+ command.parameters[0] == CEC_USER_CONTROL_CODE_POWER_TOGGLE_FUNCTION)
+ {
+ bool bPowerOn(true);
+
+ // CEC_USER_CONTROL_CODE_POWER and CEC_USER_CONTROL_CODE_POWER_TOGGLE_FUNCTION operate as a toggle
+ // assume CEC_USER_CONTROL_CODE_POWER_ON_FUNCTION does not
+ if (command.parameters[0] == CEC_USER_CONTROL_CODE_POWER ||
+ command.parameters[0] == CEC_USER_CONTROL_CODE_POWER_TOGGLE_FUNCTION)
+ {
+ cec_power_status status = device->GetCurrentPowerStatus();
+ bPowerOn = !(status == CEC_POWER_STATUS_ON || status == CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON);
+ }
+
+ if (bPowerOn)
+ {
+ device->ActivateSource();
+ }
+ else
+ {
+ device->MarkAsInactiveSource();
+ device->TransmitInactiveSource();
+ device->SetMenuState(CEC_MENU_STATE_DEACTIVATED);
+ }
+ }
+ else if (command.parameters[0] != CEC_USER_CONTROL_CODE_POWER_OFF_FUNCTION)
+ {
+ // we're not marked as active source, but the tv sends keypresses to us, so assume it forgot to activate us
+ if (!device->IsActiveSource() && command.initiator == CECDEVICE_TV && command.destination != CECDEVICE_AUDIOSYSTEM)
+ device->MarkAsActiveSource();
+ }
+
+ return COMMAND_HANDLED;
+}
+
+int CCECCommandHandler::HandleUserControlRelease(const cec_command &command)
+{
+ if (!m_processor->CECInitialised() ||
+ !m_processor->IsHandledByLibCEC(command.destination))
+ return CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND;
+
+ CECClientPtr client = m_processor->GetClient(command.destination);
+ if (client)
+ client->AddKey(false, true);
+
+ return COMMAND_HANDLED;
+}
+
+int CCECCommandHandler::HandleVendorCommand(const cec_command & UNUSED(command))
+{
+ return CEC_ABORT_REASON_INVALID_OPERAND;
+}
+
+int CCECCommandHandler::HandleVendorRemoteButtonDown(const cec_command& command)
+{
+ if (command.parameters.size == 0)
+ return CEC_ABORT_REASON_INVALID_OPERAND;
+
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, "unhandled vendor remote button received with keycode %x", command.parameters[0]);
+ return COMMAND_HANDLED;
+}
+
+void CCECCommandHandler::UnhandledCommand(const cec_command &command, const cec_abort_reason reason)
+{
+ if (m_processor->IsHandledByLibCEC(command.destination))
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "sending abort with opcode %02x and reason '%s' to %s", command.opcode, ToString(reason), ToString(command.initiator));
+ m_processor->TransmitAbort(command.destination, command.initiator, command.opcode, reason);
+
+ if (reason == CEC_ABORT_REASON_INVALID_OPERAND)
+ RequestEmailFromCustomer(command);
+ }
+}
+
+size_t CCECCommandHandler::GetMyDevices(std::vector<CCECBusDevice *> &devices) const
+{
+ size_t iReturn(0);
+
+ cec_logical_addresses addresses = m_processor->GetLogicalAddresses();
+ for (uint8_t iPtr = CECDEVICE_TV; iPtr < CECDEVICE_BROADCAST; iPtr++)
+ {
+ if (addresses[iPtr])
+ {
+ devices.push_back(GetDevice((cec_logical_address) iPtr));
+ ++iReturn;
+ }
+ }
+
+ return iReturn;
+}
+
+CCECBusDevice *CCECCommandHandler::GetDevice(cec_logical_address iLogicalAddress) const
+{
+ return m_processor->GetDevice(iLogicalAddress);
+}
+
+CCECBusDevice *CCECCommandHandler::GetDeviceByPhysicalAddress(uint16_t iPhysicalAddress) const
+{
+ return m_processor->GetDeviceByPhysicalAddress(iPhysicalAddress);
+}
+
+bool CCECCommandHandler::SetVendorId(const cec_command &command)
+{
+ bool bChanged(false);
+ if (command.parameters.size < 3)
+ {
+ LIB_CEC->AddLog(CEC_LOG_WARNING, "invalid vendor ID received");
+ return bChanged;
+ }
+
+ uint64_t iVendorId = ((uint64_t)command.parameters[0] << 16) +
+ ((uint64_t)command.parameters[1] << 8) +
+ (uint64_t)command.parameters[2];
+
+ CCECBusDevice *device = GetDevice((cec_logical_address) command.initiator);
+ if (device)
+ bChanged = device->SetVendorId(iVendorId);
+ return bChanged;
+}
+
+void CCECCommandHandler::SetPhysicalAddress(cec_logical_address iAddress, uint16_t iNewAddress)
+{
+ if (!m_processor->IsHandledByLibCEC(iAddress))
+ {
+ CCECBusDevice *otherDevice = m_processor->GetDeviceByPhysicalAddress(iNewAddress);
+ CECClientPtr client = otherDevice ? otherDevice->GetClient() : CECClientPtr();
+
+ CCECBusDevice *device = m_processor->GetDevice(iAddress);
+ if (device)
+ device->SetPhysicalAddress(iNewAddress);
+ else
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "device with logical address %X not found", iAddress);
+
+ /* another device reported the same physical address as ours */
+ if (client)
+ {
+ libcec_parameter param;
+ param.paramType = CEC_PARAMETER_TYPE_STRING;
+ param.paramData = (void*)"Physical address in use by another device. Please verify your settings";
+ client->Alert(CEC_ALERT_PHYSICAL_ADDRESS_ERROR, param);
+ client->ResetPhysicalAddress();
+ }
+ }
+ else
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "ignore physical address report for device %s (%X) because it's marked as handled by libCEC", ToString(iAddress), iAddress);
+ }
+}
+
+bool CCECCommandHandler::PowerOn(const cec_logical_address iInitiator, const cec_logical_address iDestination)
+{
+ if (iDestination == CECDEVICE_TV)
+ return TransmitImageViewOn(iInitiator, iDestination);
+
+ return TransmitKeypress(iInitiator, iDestination, CEC_USER_CONTROL_CODE_POWER) &&
+ TransmitKeyRelease(iInitiator, iDestination);
+}
+
+bool CCECCommandHandler::TransmitImageViewOn(const cec_logical_address iInitiator, const cec_logical_address iDestination)
+{
+ cec_command command;
+ cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_IMAGE_VIEW_ON);
+
+ if (Transmit(command, false, false))
+ {
+ CCECBusDevice* dest = m_processor->GetDevice(iDestination);
+ if (dest && dest->GetCurrentPowerStatus() != CEC_POWER_STATUS_ON)
+ dest->SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON);
+ return true;
+ }
+ return false;
+}
+
+bool CCECCommandHandler::TransmitStandby(const cec_logical_address iInitiator, const cec_logical_address iDestination)
+{
+ cec_command command;
+ cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_STANDBY);
+
+ return Transmit(command, false, false);
+}
+
+bool CCECCommandHandler::TransmitRequestActiveSource(const cec_logical_address iInitiator, bool bWaitForResponse /* = true */)
+{
+ cec_command command;
+ cec_command::Format(command, iInitiator, CECDEVICE_BROADCAST, CEC_OPCODE_REQUEST_ACTIVE_SOURCE);
+
+ return Transmit(command, !bWaitForResponse, false);
+}
+
+bool CCECCommandHandler::TransmitRequestCecVersion(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWaitForResponse /* = true */)
+{
+ cec_command command;
+ cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GET_CEC_VERSION);
+
+ return Transmit(command, !bWaitForResponse, false);
+}
+
+bool CCECCommandHandler::TransmitRequestMenuLanguage(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWaitForResponse /* = true */)
+{
+ cec_command command;
+ cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GET_MENU_LANGUAGE);
+
+ return Transmit(command, !bWaitForResponse, false);
+}
+
+bool CCECCommandHandler::TransmitRequestOSDName(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWaitForResponse /* = true */)
+{
+ cec_command command;
+ cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GIVE_OSD_NAME);
+
+ return Transmit(command, !bWaitForResponse, false);
+}
+
+bool CCECCommandHandler::TransmitRequestAudioStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWaitForResponse /* = true */)
+{
+ cec_command command;
+ cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GIVE_AUDIO_STATUS);
+
+ return Transmit(command, !bWaitForResponse, false);
+}
+
+bool CCECCommandHandler::TransmitRequestPhysicalAddress(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWaitForResponse /* = true */)
+{
+ cec_command command;
+ cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GIVE_PHYSICAL_ADDRESS);
+
+ return Transmit(command, !bWaitForResponse, false);
+}
+
+bool CCECCommandHandler::TransmitRequestPowerStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bUpdate, bool bWaitForResponse /* = true */)
+{
+ if (iDestination == CECDEVICE_TV)
+ {
+ int64_t now(GetTimeMs());
+ if (!bUpdate && now - m_iPowerStatusRequested < REQUEST_POWER_STATUS_TIMEOUT)
+ return true;
+ m_iPowerStatusRequested = now;
+ }
+
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< requesting power status of '%s' (%X)", m_busDevice->GetLogicalAddressName(), iDestination);
+
+ cec_command command;
+ cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GIVE_DEVICE_POWER_STATUS);
+
+ return Transmit(command, !bWaitForResponse, false);
+}
+
+bool CCECCommandHandler::TransmitRequestVendorId(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWaitForResponse /* = true */)
+{
+ cec_command command;
+ cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID);
+
+ return Transmit(command, !bWaitForResponse, false);
+}
+
+bool CCECCommandHandler::TransmitActiveSource(const cec_logical_address iInitiator, uint16_t iPhysicalAddress, bool bIsReply)
+{
+ cec_command command;
+ cec_command::Format(command, iInitiator, CECDEVICE_BROADCAST, CEC_OPCODE_ACTIVE_SOURCE);
+ command.parameters.PushBack((uint8_t) ((iPhysicalAddress >> 8) & 0xFF));
+ command.parameters.PushBack((uint8_t) (iPhysicalAddress & 0xFF));
+
+ return Transmit(command, false, bIsReply);
+}
+
+bool CCECCommandHandler::TransmitCECVersion(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_version cecVersion, bool bIsReply)
+{
+ cec_command command;
+ cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_CEC_VERSION);
+ command.parameters.PushBack((uint8_t)cecVersion);
+
+ return Transmit(command, false, bIsReply);
+}
+
+bool CCECCommandHandler::TransmitInactiveSource(const cec_logical_address iInitiator, uint16_t iPhysicalAddress)
+{
+ cec_command command;
+ cec_command::Format(command, iInitiator, CECDEVICE_TV, CEC_OPCODE_INACTIVE_SOURCE);
+ command.parameters.PushBack((iPhysicalAddress >> 8) & 0xFF);
+ command.parameters.PushBack(iPhysicalAddress & 0xFF);
+
+ return Transmit(command, false, false);
+}
+
+bool CCECCommandHandler::TransmitMenuState(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_menu_state menuState, bool bIsReply)
+{
+ cec_command command;
+ cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_MENU_STATUS);
+ command.parameters.PushBack((uint8_t)menuState);
+
+ return Transmit(command, false, bIsReply);
+}
+
+bool CCECCommandHandler::TransmitOSDName(const cec_logical_address iInitiator, const cec_logical_address iDestination, std::string strDeviceName, bool bIsReply)
+{
+ cec_command command;
+ cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_SET_OSD_NAME);
+ for (size_t iPtr = 0; iPtr < strDeviceName.length(); iPtr++)
+ command.parameters.PushBack(strDeviceName.at(iPtr));
+
+ return Transmit(command, false, bIsReply);
+}
+
+bool CCECCommandHandler::TransmitOSDString(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_display_control duration, const char *strMessage, bool bIsReply)
+{
+ cec_command command;
+ cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_SET_OSD_STRING);
+ command.parameters.PushBack((uint8_t)duration);
+
+ size_t iLen = strlen(strMessage);
+ if (iLen > 13) iLen = 13;
+
+ for (size_t iPtr = 0; iPtr < iLen; iPtr++)
+ command.parameters.PushBack(strMessage[iPtr]);
+
+ return Transmit(command, false, bIsReply);
+}
+
+bool CCECCommandHandler::TransmitPhysicalAddress(const cec_logical_address iInitiator, uint16_t iPhysicalAddress, cec_device_type type, bool bIsReply)
+{
+ cec_command command;
+ cec_command::Format(command, iInitiator, CECDEVICE_BROADCAST, CEC_OPCODE_REPORT_PHYSICAL_ADDRESS);
+ command.parameters.PushBack((uint8_t) ((iPhysicalAddress >> 8) & 0xFF));
+ command.parameters.PushBack((uint8_t) (iPhysicalAddress & 0xFF));
+ command.parameters.PushBack((uint8_t) (type));
+
+ return Transmit(command, false, bIsReply);
+}
+
+bool CCECCommandHandler::TransmitSetMenuLanguage(const cec_logical_address iInitiator, const char lang[4], bool bIsReply)
+{
+ cec_command command;
+ command.Format(command, iInitiator, CECDEVICE_BROADCAST, CEC_OPCODE_SET_MENU_LANGUAGE);
+ command.parameters.PushBack((uint8_t) lang[0]);
+ command.parameters.PushBack((uint8_t) lang[1]);
+ command.parameters.PushBack((uint8_t) lang[2]);
+
+ return Transmit(command, false, bIsReply);
+}
+
+bool CCECCommandHandler::TransmitPoll(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bIsReply)
+{
+ cec_command command;
+ cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_NONE);
+
+ return Transmit(command, false, bIsReply);
+}
+
+bool CCECCommandHandler::TransmitPowerState(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_power_status state, bool bIsReply)
+{
+ cec_command command;
+ cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_REPORT_POWER_STATUS);
+ command.parameters.PushBack((uint8_t) state);
+
+ return Transmit(command, false, bIsReply);
+}
+
+bool CCECCommandHandler::TransmitVendorID(const cec_logical_address iInitiator, const cec_logical_address UNUSED(iDestination), uint64_t iVendorId, bool bIsReply)
+{
+ cec_command command;
+ cec_command::Format(command, iInitiator, CECDEVICE_BROADCAST, CEC_OPCODE_DEVICE_VENDOR_ID);
+
+ command.parameters.PushBack((uint8_t) (((uint64_t)iVendorId >> 16) & 0xFF));
+ command.parameters.PushBack((uint8_t) (((uint64_t)iVendorId >> 8) & 0xFF));
+ command.parameters.PushBack((uint8_t) ((uint64_t)iVendorId & 0xFF));
+
+ return Transmit(command, false, bIsReply);
+}
+
+bool CCECCommandHandler::TransmitAudioStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, uint8_t state, bool bIsReply)
+{
+ cec_command command;
+ cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_REPORT_AUDIO_STATUS);
+ command.parameters.PushBack(state);
+
+ return Transmit(command, false, bIsReply);
+}
+
+bool CCECCommandHandler::TransmitSetSystemAudioMode(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_system_audio_status state, bool bIsReply)
+{
+ cec_command command;
+ cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_SET_SYSTEM_AUDIO_MODE);
+ command.parameters.PushBack((uint8_t)state);
+
+ return Transmit(command, false, bIsReply);
+}
+
+bool CCECCommandHandler::TransmitSetStreamPath(uint16_t iStreamPath, bool bIsReply)
+{
+ if (m_busDevice->GetLogicalAddress() != CECDEVICE_TV)
+ {
+ LIB_CEC->AddLog(CEC_LOG_ERROR, "only the TV is allowed to send CEC_OPCODE_SET_STREAM_PATH");
+ return false;
+ }
+ cec_command command;
+ cec_command::Format(command, m_busDevice->GetLogicalAddress(), CECDEVICE_BROADCAST, CEC_OPCODE_SET_STREAM_PATH);
+ command.parameters.PushBack((uint8_t) ((iStreamPath >> 8) & 0xFF));
+ command.parameters.PushBack((uint8_t) (iStreamPath & 0xFF));
+
+ return Transmit(command, false, bIsReply);
+}
+
+bool CCECCommandHandler::TransmitSystemAudioModeStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_system_audio_status state, bool bIsReply)
+{
+ cec_command command;
+ cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_SYSTEM_AUDIO_MODE_STATUS);
+ command.parameters.PushBack((uint8_t)state);
+
+ return Transmit(command, false, bIsReply);
+}
+
+bool CCECCommandHandler::TransmitDeckStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_deck_info state, bool bIsReply)
+{
+ cec_command command;
+ cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_DECK_STATUS);
+ command.PushBack((uint8_t)state);
+
+ return Transmit(command, false, bIsReply);
+}
+
+bool CCECCommandHandler::TransmitKeypress(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_user_control_code key, bool bWait /* = true */)
+{
+ cec_command command;
+ cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_USER_CONTROL_PRESSED);
+ command.parameters.PushBack((uint8_t)key);
+
+ return Transmit(command, !bWait, false);
+}
+
+bool CCECCommandHandler::TransmitKeyRelease(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWait /* = true */)
+{
+ cec_command command;
+ cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_USER_CONTROL_RELEASE);
+
+ return Transmit(command, !bWait, false);
+}
+
+bool CCECCommandHandler::TransmitSystemAudioModeRequest(const cec_logical_address iInitiator, uint16_t iPhysicalAddress)
+{
+ cec_command command;
+
+ cec_command::Format(command, iInitiator, CECDEVICE_AUDIOSYSTEM, CEC_OPCODE_SYSTEM_AUDIO_MODE_REQUEST);
+ if (iPhysicalAddress != CEC_INVALID_PHYSICAL_ADDRESS) {
+ command.parameters.PushBack((uint8_t) ((iPhysicalAddress >> 8) & 0xFF));
+ command.parameters.PushBack((uint8_t) (iPhysicalAddress & 0xFF));
+ }
+
+ return Transmit(command, false, false);
+}
+
+bool CCECCommandHandler::Transmit(cec_command &command, bool bSuppressWait, bool bIsReply)
+{
+ bool bReturn(false);
+ cec_opcode expectedResponse(cec_command::GetResponseOpcode(command.opcode));
+ bool bExpectResponse(expectedResponse != CEC_OPCODE_NONE && !bSuppressWait);
+ command.transmit_timeout = m_iTransmitTimeout;
+
+ if (command.initiator == CECDEVICE_UNKNOWN)
+ {
+ LIB_CEC->AddLog(CEC_LOG_ERROR, "not transmitting a command without a valid initiator");
+ return bReturn;
+ }
+
+ // check whether the destination is not marked as not present or handled by libCEC
+ if (command.destination != CECDEVICE_BROADCAST && command.opcode_set)
+ {
+ CCECBusDevice* destinationDevice = m_processor->GetDevice(command.destination);
+ cec_bus_device_status status = destinationDevice ? destinationDevice->GetStatus() : CEC_DEVICE_STATUS_NOT_PRESENT;
+ if (status == CEC_DEVICE_STATUS_NOT_PRESENT)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "not sending command '%s': destination device '%s' marked as not present", ToString(command.opcode),ToString(command.destination));
+ return bReturn;
+ }
+ else if (status == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "not sending command '%s': destination device '%s' marked as handled by libCEC", ToString(command.opcode),ToString(command.destination));
+ return bReturn;
+ }
+ else if (destinationDevice->IsUnsupportedFeature(command.opcode))
+ {
+ return true;
+ }
+ }
+
+ {
+ uint8_t iTries(0), iMaxTries(m_iTransmitRetries + 1);
+ while (!bReturn && ++iTries <= iMaxTries)
+ {
+ if ((bReturn = m_processor->Transmit(command, bIsReply)) == true)
+ {
+#ifdef CEC_DEBUGGING
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "command transmitted");
+#endif
+ if (bExpectResponse)
+ {
+ bReturn = m_busDevice->WaitForOpcode(expectedResponse);
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, bReturn ? "expected response received (%X: %s)" : "expected response not received (%X: %s)", (int)expectedResponse, ToString(expectedResponse));
+ }
+ }
+ }
+ }
+
+ return bReturn;
+}
+
+bool CCECCommandHandler::ActivateSource(bool bTransmitDelayedCommandsOnly /* = false */)
+{
+ if (m_busDevice->IsActiveSource() &&
+ m_busDevice->IsHandledByLibCEC())
+ {
+ {
+ CLockObject lock(m_mutex);
+ // check if we need to send a delayed source switch
+ if (bTransmitDelayedCommandsOnly)
+ {
+ if (m_iActiveSourcePending == 0 || GetTimeMs() < m_iActiveSourcePending)
+ return false;
+
+#ifdef CEC_DEBUGGING
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "transmitting delayed activate source command");
+#endif
+ }
+ }
+
+ // update the power state and menu state
+ if (!bTransmitDelayedCommandsOnly)
+ {
+ m_busDevice->SetPowerStatus(CEC_POWER_STATUS_ON);
+ m_busDevice->SetMenuState(CEC_MENU_STATE_ACTIVATED);
+ }
+
+ // vendor specific hook
+ VendorPreActivateSourceHook();
+
+ // power on the TV
+ CCECBusDevice* tv = m_processor->GetDevice(CECDEVICE_TV);
+ bool bTvPresent = (tv && tv->GetStatus() == CEC_DEVICE_STATUS_PRESENT);
+ bool bActiveSourceFailed(false);
+ if (bTvPresent)
+ tv->PowerOn(m_busDevice->GetLogicalAddress());
+ else
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "TV not present, not sending 'image view on'");
+
+ // check if we're allowed to switch sources
+ bool bSourceSwitchAllowed = SourceSwitchAllowed();
+ if (!bSourceSwitchAllowed)
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "source switch is currently not allowed by command handler");
+
+ // switch sources (if allowed)
+ if (!bActiveSourceFailed && bSourceSwitchAllowed)
+ {
+ bActiveSourceFailed = !m_busDevice->TransmitActiveSource(false);
+ if (bTvPresent && !bActiveSourceFailed)
+ m_busDevice->TransmitMenuState(CECDEVICE_TV, false);
+
+ // update the deck status for playback devices
+ if (bTvPresent && !bActiveSourceFailed)
+ {
+ CCECPlaybackDevice *playbackDevice = m_busDevice->AsPlaybackDevice();
+ if (playbackDevice && SendDeckStatusUpdateOnActiveSource())
+ bActiveSourceFailed = !playbackDevice->TransmitDeckStatus(CECDEVICE_TV, false);
+ }
+
+ // update system audio mode for audiosystem devices
+ if (bTvPresent && !bActiveSourceFailed)
+ {
+ CCECAudioSystem* audioDevice = m_busDevice->AsAudioSystem();
+ if (audioDevice)
+ bActiveSourceFailed = !audioDevice->TransmitSetSystemAudioMode(CECDEVICE_TV, false);
+ }
+ }
+
+ // retry later
+ if (bActiveSourceFailed || !bSourceSwitchAllowed)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "failed to make '%s' the active source. will retry later", m_busDevice->GetLogicalAddressName());
+ int64_t now(GetTimeMs());
+ CLockObject lock(m_mutex);
+ if (m_iActiveSourcePending == 0 || m_iActiveSourcePending < now)
+ m_iActiveSourcePending = now + (int64_t)CEC_ACTIVE_SOURCE_SWITCH_RETRY_TIME_MS;
+ return false;
+ }
+ else
+ {
+ CLockObject lock(m_mutex);
+ // clear previous pending active source command
+ m_iActiveSourcePending = 0;
+ }
+
+ // mark the handler as initialised
+ CLockObject lock(m_mutex);
+ m_bHandlerInited = true;
+ }
+ return true;
+}
+
+void CCECCommandHandler::ScheduleActivateSource(uint64_t iDelay)
+{
+ CLockObject lock(m_mutex);
+ m_iActiveSourcePending = GetTimeMs() + iDelay;
+}
+
+void CCECCommandHandler::RequestEmailFromCustomer(const cec_command& command)
+{
+ bool bInserted(false);
+ std::map<cec_opcode, std::vector<cec_command> >::iterator it = m_logsRequested.find(command.opcode);
+ if (it != m_logsRequested.end())
+ {
+ for (std::vector<cec_command>::const_iterator it2 = it->second.begin(); it2 != it->second.end(); it2++)
+ {
+ // we already logged this one
+ if ((*it2).parameters == command.parameters)
+ return;
+ }
+
+ it->second.push_back(command);
+ bInserted = true;
+ }
+
+ if (!bInserted)
+ {
+ std::vector<cec_command> commands;
+ commands.push_back(command);
+ m_logsRequested.insert(make_pair(command.opcode, commands));
+ }
+
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, "Unmapped code detected. Please send an email to support@pulse-eight.com with the following details, and if you pressed a key, tell us which one you pressed, and we'll add support for this it.\nCEC command: %s\nVendor ID: %s (%06x)", ToString(command).c_str(), ToString(m_vendorId), m_vendorId);
+}
+
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include <vector>
+#include <string>
+#include <map>
+#include <p8-platform/threads/mutex.h>
+
+namespace CEC
+{
+ #define COMMAND_HANDLED 0xFF
+
+ class CCECProcessor;
+ class CCECBusDevice;
+
+ class CCECCommandHandler
+ {
+ friend class CCECBusDevice;
+
+ public:
+ CCECCommandHandler(CCECBusDevice *busDevice,
+ int32_t iTransmitTimeout = CEC_DEFAULT_TRANSMIT_TIMEOUT,
+ int32_t iTransmitWait = CEC_DEFAULT_TRANSMIT_WAIT,
+ int8_t iTransmitRetries = CEC_DEFAULT_TRANSMIT_RETRIES,
+ int64_t iActiveSourcePending = 0);
+ virtual ~CCECCommandHandler(void) {};
+
+ virtual bool HandleCommand(const cec_command &command);
+ virtual cec_vendor_id GetVendorId(void) { return m_vendorId; };
+ virtual void SetVendorId(cec_vendor_id vendorId) { m_vendorId = vendorId; }
+ static bool HasSpecificHandler(cec_vendor_id vendorId) { return vendorId == CEC_VENDOR_LG || vendorId == CEC_VENDOR_SAMSUNG || vendorId == CEC_VENDOR_PANASONIC || vendorId == CEC_VENDOR_PHILIPS || vendorId == CEC_VENDOR_SHARP || vendorId == CEC_VENDOR_SHARP2 || vendorId == CEC_VENDOR_TOSHIBA || vendorId == CEC_VENDOR_TOSHIBA2 || vendorId == CEC_VENDOR_ONKYO;}
+
+ virtual bool InitHandler(void) { return true; }
+ virtual bool ActivateSource(bool bTransmitDelayedCommandsOnly = false);
+ virtual uint8_t GetTransmitRetries(void) const { return m_iTransmitRetries; }
+
+ virtual bool PowerOn(const cec_logical_address iInitiator, const cec_logical_address iDestination);
+ virtual bool TransmitImageViewOn(const cec_logical_address iInitiator, const cec_logical_address iDestination);
+ virtual bool TransmitStandby(const cec_logical_address iInitiator, const cec_logical_address iDestination);
+ virtual bool TransmitRequestActiveSource(const cec_logical_address iInitiator, bool bWaitForResponse = true);
+ virtual bool TransmitRequestCecVersion(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWaitForResponse = true);
+ virtual bool TransmitRequestMenuLanguage(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWaitForResponse = true);
+ virtual bool TransmitRequestOSDName(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWaitForResponse = true);
+ virtual bool TransmitRequestAudioStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWaitForResponse = true);
+ virtual bool TransmitRequestPhysicalAddress(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWaitForResponse = true);
+ virtual bool TransmitRequestPowerStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bUpdate, bool bWaitForResponse = true);
+ virtual bool TransmitRequestVendorId(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWaitForResponse = true);
+ virtual bool TransmitActiveSource(const cec_logical_address iInitiator, uint16_t iPhysicalAddress, bool bIsReply);
+ virtual bool TransmitCECVersion(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_version cecVersion, bool bIsReply);
+ virtual bool TransmitInactiveSource(const cec_logical_address iInitiator, uint16_t iPhysicalAddress);
+ virtual bool TransmitMenuState(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_menu_state menuState, bool bIsReply);
+ virtual bool TransmitOSDName(const cec_logical_address iInitiator, const cec_logical_address iDestination, std::string strDeviceName, bool bIsReply);
+ virtual bool TransmitOSDString(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_display_control duration, const char *strMessage, bool bIsReply);
+ virtual bool TransmitPhysicalAddress(const cec_logical_address iInitiator, uint16_t iPhysicalAddress, cec_device_type type, bool bIsReply);
+ virtual bool TransmitSetMenuLanguage(const cec_logical_address iInitiator, const char lang[4], bool bIsReply);
+ virtual bool TransmitPoll(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bIsReply);
+ virtual bool TransmitPowerState(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_power_status state, bool bIsReply);
+ virtual bool TransmitVendorID(const cec_logical_address iInitiator, const cec_logical_address iDestination, uint64_t iVendorId, bool bIsReply);
+ virtual bool TransmitAudioStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, uint8_t state, bool bIsReply);
+ virtual bool TransmitSetSystemAudioMode(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_system_audio_status state, bool bIsReply);
+ virtual bool TransmitSystemAudioModeStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_system_audio_status state, bool bIsReply);
+ virtual bool TransmitDeckStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_deck_info state, bool bIsReply);
+ virtual bool TransmitKeypress(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_user_control_code key, bool bWait = true);
+ virtual bool TransmitKeyRelease(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWait = true);
+ virtual bool TransmitSystemAudioModeRequest(const cec_logical_address iInitiator, uint16_t iPhysicalAddress);
+ virtual bool TransmitSetStreamPath(uint16_t iStreamPath, bool bIsReply);
+ virtual bool SendDeckStatusUpdateOnActiveSource(void) const { return m_bOPTSendDeckStatusUpdateOnActiveSource; };
+
+ virtual void ScheduleActivateSource(uint64_t iDelay);
+
+ virtual bool SupportsDeviceType(const cec_device_type UNUSED(type)) const { return true; };
+ virtual cec_device_type GetReplacementDeviceType(const cec_device_type type) const { return type; }
+ virtual bool ActiveSourcePending(void) const { return m_iActiveSourcePending != 0; }
+
+ protected:
+ virtual int HandleActiveSource(const cec_command &command);
+ virtual int HandleDeckControl(const cec_command &command);
+ virtual int HandleDeviceCecVersion(const cec_command &command);
+ virtual int HandleDeviceVendorCommandWithId(const cec_command &command);
+ virtual int HandleDeviceVendorId(const cec_command &command);
+ virtual int HandleFeatureAbort(const cec_command &command);
+ virtual int HandleGetCecVersion(const cec_command &command);
+ virtual int HandleGiveAudioStatus(const cec_command &command);
+ virtual int HandleGiveDeckStatus(const cec_command &command);
+ virtual int HandleGiveDevicePowerStatus(const cec_command &command);
+ virtual int HandleGiveDeviceVendorId(const cec_command &command);
+ virtual int HandleGiveOSDName(const cec_command &command);
+ virtual int HandleGivePhysicalAddress(const cec_command &command);
+ virtual int HandleGiveMenuLanguage(const cec_command &command);
+ virtual int HandleGiveSystemAudioModeStatus(const cec_command &command);
+ virtual int HandleImageViewOn(const cec_command &command);
+ virtual int HandleMenuRequest(const cec_command &command);
+ virtual bool HandlePoll(const cec_command &command);
+ virtual int HandleReportAudioStatus(const cec_command &command);
+ virtual int HandleReportPhysicalAddress(const cec_command &command);
+ virtual int HandleReportPowerStatus(const cec_command &command);
+ virtual int HandleRequestActiveSource(const cec_command &command);
+ virtual int HandleRoutingChange(const cec_command &command);
+ virtual int HandleRoutingInformation(const cec_command &command);
+ virtual int HandleSetMenuLanguage(const cec_command &command);
+ virtual int HandleSetOSDName(const cec_command &command);
+ virtual int HandleSetStreamPath(const cec_command &command);
+ virtual int HandleSystemAudioModeRequest(const cec_command &command);
+ virtual int HandleStandby(const cec_command &command);
+ virtual int HandleSystemAudioModeStatus(const cec_command &command);
+ virtual int HandleSetSystemAudioMode(const cec_command &command);
+ virtual int HandleTextViewOn(const cec_command &command);
+ virtual int HandleUserControlPressed(const cec_command &command);
+ virtual int HandleUserControlRelease(const cec_command &command);
+ virtual int HandleVendorCommand(const cec_command &command);
+ virtual int HandleVendorRemoteButtonDown(const cec_command& command);
+ virtual int HandleVendorRemoteButtonUp(const cec_command& command) { return HandleUserControlRelease(command); }
+ virtual void UnhandledCommand(const cec_command &command, const cec_abort_reason reason);
+ virtual void RequestEmailFromCustomer(const cec_command& command);
+
+ virtual void VendorPreActivateSourceHook(void) {};
+
+ virtual size_t GetMyDevices(std::vector<CCECBusDevice *> &devices) const;
+ virtual CCECBusDevice *GetDevice(cec_logical_address iLogicalAddress) const;
+ virtual CCECBusDevice *GetDeviceByPhysicalAddress(uint16_t iPhysicalAddress) const;
+
+ virtual bool SetVendorId(const cec_command &command);
+ virtual void SetPhysicalAddress(cec_logical_address iAddress, uint16_t iNewAddress);
+
+ virtual bool Transmit(cec_command &command, bool bSuppressWait, bool bIsReply);
+
+ virtual bool SourceSwitchAllowed(void) { return true; }
+
+ CCECBusDevice * m_busDevice;
+ CCECProcessor * m_processor;
+ int32_t m_iTransmitTimeout;
+ int32_t m_iTransmitWait;
+ int8_t m_iTransmitRetries;
+ bool m_bHandlerInited;
+ bool m_bOPTSendDeckStatusUpdateOnActiveSource;
+ cec_vendor_id m_vendorId;
+ int64_t m_iActiveSourcePending;
+ P8PLATFORM::CMutex m_mutex;
+ int64_t m_iPowerStatusRequested;
+ std::map<cec_opcode, std::vector<cec_command> > m_logsRequested;
+ };
+};
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include "PHCommandHandler.h"
+
+#include "devices/CECBusDevice.h"
+#include "CECProcessor.h"
+#include "LibCEC.h"
+#include "CECClient.h"
+
+using namespace CEC;
+using namespace P8PLATFORM;
+
+#define LIB_CEC m_busDevice->GetProcessor()->GetLib()
+#define ToString(p) LIB_CEC->ToString(p)
+
+#define TV_ON_CHECK_TIME_MS 5000
+
+CImageViewOnCheck::~CImageViewOnCheck(void)
+{
+ StopThread(-1);
+ m_event.Broadcast();
+ StopThread();
+}
+
+void* CImageViewOnCheck::Process(void)
+{
+ CCECBusDevice* tv = m_handler->m_processor->GetDevice(CECDEVICE_TV);
+ cec_power_status status(CEC_POWER_STATUS_UNKNOWN);
+ while (status != CEC_POWER_STATUS_ON)
+ {
+ m_event.Wait(TV_ON_CHECK_TIME_MS);
+ if (!IsRunning())
+ return NULL;
+
+ status = tv->GetPowerStatus(m_handler->m_busDevice->GetLogicalAddress());
+
+ if (status != CEC_POWER_STATUS_ON &&
+ status != CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON)
+ {
+ CLockObject lock(m_handler->m_mutex);
+ tv->OnImageViewOnSent(false);
+ m_handler->m_iActiveSourcePending = GetTimeMs();
+ }
+ }
+ return NULL;
+}
+
+CPHCommandHandler::CPHCommandHandler(CCECBusDevice *busDevice,
+ int32_t iTransmitTimeout /* = CEC_DEFAULT_TRANSMIT_TIMEOUT */,
+ int32_t iTransmitWait /* = CEC_DEFAULT_TRANSMIT_WAIT */,
+ int8_t iTransmitRetries /* = CEC_DEFAULT_TRANSMIT_RETRIES */,
+ int64_t iActiveSourcePending /* = 0 */) :
+ CCECCommandHandler(busDevice, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending),
+ m_iLastKeyCode(CEC_USER_CONTROL_CODE_UNKNOWN)
+{
+ m_imageViewOnCheck = new CImageViewOnCheck(this);
+ m_vendorId = CEC_VENDOR_PHILIPS;
+ m_bOPTSendDeckStatusUpdateOnActiveSource = false;
+}
+
+CPHCommandHandler::~CPHCommandHandler(void)
+{
+ delete m_imageViewOnCheck;
+}
+
+bool CPHCommandHandler::InitHandler(void)
+{
+ CCECBusDevice *primary = m_processor->GetPrimaryDevice();
+ if (primary && primary->GetLogicalAddress() != CECDEVICE_UNREGISTERED)
+ {
+ //XXX hack to use this handler for the primary device
+ if (m_busDevice->GetLogicalAddress() == CECDEVICE_TV &&
+ primary && m_busDevice->GetLogicalAddress() != primary->GetLogicalAddress())
+ {
+ primary->SetVendorId(CEC_VENDOR_PHILIPS);
+ primary->ReplaceHandler(false);
+ }
+ }
+
+ return CCECCommandHandler::InitHandler();
+}
+
+bool CPHCommandHandler::ActivateSource(bool bTransmitDelayedCommandsOnly /* = false */)
+{
+
+ CCECBusDevice* tv = m_processor->GetDevice(CECDEVICE_TV);
+ if (m_busDevice->IsActiveSource() &&
+ m_busDevice->IsHandledByLibCEC() &&
+ tv && tv->GetCurrentPowerStatus() != CEC_POWER_STATUS_ON &&
+ !bTransmitDelayedCommandsOnly)
+ {
+ // tv sometimes ignores image view on. check the power status of the tv in 5 seconds, and retry when it failed to power up
+ if (m_imageViewOnCheck && !m_imageViewOnCheck->IsRunning())
+ return m_imageViewOnCheck->CreateThread(false);
+ }
+
+ return CCECCommandHandler::ActivateSource(bTransmitDelayedCommandsOnly);
+}
+
+int CPHCommandHandler::HandleUserControlPressed(const cec_command& command)
+{
+ // TV sends key presses without releases when holding a button
+ if (m_iLastKeyCode == command.parameters[0])
+ {
+ // TV keeps sending key presses after pressing the display information key once (arguably another firmware bug)
+ // So we only allow holding buttons forwarded from the 'device menu control feature' (see cec specs 1.3a table 27)
+ if (m_iLastKeyCode <= CEC_USER_CONTROL_CODE_LEFT_DOWN ||
+ m_iLastKeyCode == CEC_USER_CONTROL_CODE_EXIT ||
+ (m_iLastKeyCode >= CEC_USER_CONTROL_CODE_NUMBER0 && m_iLastKeyCode <= CEC_USER_CONTROL_CODE_NUMBER9) ||
+ (m_iLastKeyCode >= CEC_USER_CONTROL_CODE_F1_BLUE && m_iLastKeyCode <= CEC_USER_CONTROL_CODE_F5))
+ {
+ cec_command release;
+ release.parameters.size = 0;
+ release.opcode = CEC_OPCODE_USER_CONTROL_RELEASE;
+ release.initiator = command.initiator;
+ release.destination = command.destination;
+ CCECCommandHandler::HandleUserControlRelease(release);
+ }
+ else
+ {
+ return COMMAND_HANDLED;
+ }
+ }
+
+ m_iLastKeyCode = command.parameters[0];
+
+ return CCECCommandHandler::HandleUserControlPressed(command);
+}
+
+int CPHCommandHandler::HandleUserControlRelease(const cec_command& command)
+{
+ m_iLastKeyCode = CEC_USER_CONTROL_CODE_UNKNOWN;
+
+ return CCECCommandHandler::HandleUserControlRelease(command);
+}
+
+int CPHCommandHandler::HandleDeviceVendorId(const cec_command& command)
+{
+ m_busDevice->SetPowerStatus(CEC_POWER_STATUS_ON);
+ return CCECCommandHandler::HandleDeviceVendorId(command);
+}
+
+bool CPHCommandHandler::TransmitVendorID(const cec_logical_address iInitiator, const cec_logical_address iDestination, uint64_t UNUSED(iVendorId), bool bIsReply)
+{
+ // XXX hack around the hack in CPHCommandHandler::InitHandler
+ return CCECCommandHandler::TransmitVendorID(iInitiator, iDestination, CEC_VENDOR_PULSE_EIGHT, bIsReply);
+}
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include "CECCommandHandler.h"
+#include <p8-platform/threads/threads.h>
+
+namespace CEC
+{
+ class CPHCommandHandler;
+
+ class CImageViewOnCheck : public P8PLATFORM::CThread
+ {
+ public:
+ CImageViewOnCheck(CPHCommandHandler* handler):
+ m_handler(handler) {}
+ virtual ~CImageViewOnCheck(void);
+
+ void* Process(void);
+
+ private:
+ CPHCommandHandler* m_handler;
+ P8PLATFORM::CEvent m_event;
+ };
+
+ class CPHCommandHandler : public CCECCommandHandler
+ {
+ friend class CImageViewOnCheck;
+ public:
+ CPHCommandHandler(CCECBusDevice *busDevice,
+ int32_t iTransmitTimeout = CEC_DEFAULT_TRANSMIT_TIMEOUT,
+ int32_t iTransmitWait = CEC_DEFAULT_TRANSMIT_WAIT,
+ int8_t iTransmitRetries = CEC_DEFAULT_TRANSMIT_RETRIES,
+ int64_t iActiveSourcePending = 0);
+ virtual ~CPHCommandHandler(void);
+
+ bool InitHandler(void);
+
+ protected:
+ virtual bool ActivateSource(bool bTransmitDelayedCommandsOnly = false);
+ virtual int HandleUserControlPressed(const cec_command& command);
+ virtual int HandleUserControlRelease(const cec_command& command);
+ virtual bool TransmitVendorID(const cec_logical_address iInitiator, const cec_logical_address iDestination, uint64_t iVendorId, bool bIsReply);
+ virtual int HandleDeviceVendorId(const cec_command& command);
+ uint8_t m_iLastKeyCode;
+ CImageViewOnCheck* m_imageViewOnCheck;
+ };
+};
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include "RHCommandHandler.h"
+
+#include "devices/CECBusDevice.h"
+#include "CECProcessor.h"
+#include "LibCEC.h"
+#include "CECClient.h"
+
+using namespace CEC;
+
+#define LIB_CEC m_busDevice->GetProcessor()->GetLib()
+#define ToString(p) LIB_CEC->ToString(p)
+
+CRHCommandHandler::CRHCommandHandler(CCECBusDevice *busDevice,
+ int32_t iTransmitTimeout /* = CEC_DEFAULT_TRANSMIT_TIMEOUT */,
+ int32_t iTransmitWait /* = CEC_DEFAULT_TRANSMIT_WAIT */,
+ int8_t iTransmitRetries /* = CEC_DEFAULT_TRANSMIT_RETRIES */,
+ int64_t iActiveSourcePending /* = 0 */) :
+ CCECCommandHandler(busDevice, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending)
+{
+ m_vendorId = CEC_VENDOR_ONKYO;
+}
+
+int CRHCommandHandler::HandleDeviceVendorCommandWithId(const cec_command &command)
+{
+ // onkyo's vendor id
+ if (command.parameters[0] == 0x00 && command.parameters[1] == 0x09 && command.parameters[2] == 0xb0)
+ {
+ // ignore unknown vendor commands sent by onkyo devices, bugzid: 2559
+ }
+ return CEC_ABORT_REASON_REFUSED;
+}
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include "CECCommandHandler.h"
+
+namespace CEC
+{
+ class CRHCommandHandler : public CCECCommandHandler
+ {
+ public:
+ CRHCommandHandler(CCECBusDevice *busDevice,
+ int32_t iTransmitTimeout = CEC_DEFAULT_TRANSMIT_TIMEOUT,
+ int32_t iTransmitWait = CEC_DEFAULT_TRANSMIT_WAIT,
+ int8_t iTransmitRetries = CEC_DEFAULT_TRANSMIT_RETRIES,
+ int64_t iActiveSourcePending = 0);
+ virtual ~CRHCommandHandler(void) {};
+
+ protected:
+ int HandleDeviceVendorCommandWithId(const cec_command &command);
+ };
+};
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include "RLCommandHandler.h"
+
+#include <p8-platform/util/timeutils.h>
+#include "devices/CECBusDevice.h"
+#include "CECProcessor.h"
+#include "LibCEC.h"
+#include "CECClient.h"
+
+using namespace CEC;
+using namespace P8PLATFORM;
+
+#define RL_KEY_TOP_MENU 0x10
+#define RL_KEY_DVD_MENU 0x11
+
+CRLCommandHandler::CRLCommandHandler(CCECBusDevice *busDevice,
+ int32_t iTransmitTimeout /* = CEC_DEFAULT_TRANSMIT_TIMEOUT */,
+ int32_t iTransmitWait /* = CEC_DEFAULT_TRANSMIT_WAIT */,
+ int8_t iTransmitRetries /* = CEC_DEFAULT_TRANSMIT_RETRIES */,
+ int64_t iActiveSourcePending /* = 0 */) :
+ CCECCommandHandler(busDevice, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending)
+{
+ m_vendorId = CEC_VENDOR_TOSHIBA;
+}
+
+bool CRLCommandHandler::InitHandler(void)
+{
+ if (m_bHandlerInited)
+ return true;
+ m_bHandlerInited = true;
+
+ if (m_busDevice->GetLogicalAddress() != CECDEVICE_TV)
+ return true;
+
+ CCECBusDevice *primary = m_processor->GetPrimaryDevice();
+ if (primary && primary->GetLogicalAddress() != CECDEVICE_UNREGISTERED)
+ {
+ /* imitate Toshiba devices */
+ if (m_busDevice->GetLogicalAddress() != primary->GetLogicalAddress())
+ {
+ primary->SetVendorId(CEC_VENDOR_TOSHIBA);
+ primary->ReplaceHandler(false);
+ }
+
+ if (m_busDevice->GetLogicalAddress() == CECDEVICE_TV)
+ {
+ /* send the vendor id */
+ primary->TransmitVendorID(CECDEVICE_BROADCAST, false, false);
+ }
+ }
+
+ return true;
+}
+
+int CRLCommandHandler::HandleDeviceVendorCommandWithId(const cec_command &command)
+{
+ if (!m_processor->IsHandledByLibCEC(command.destination))
+ return CEC_ABORT_REASON_INVALID_OPERAND;
+
+ if (command.parameters.size < 4)
+ return CEC_ABORT_REASON_INVALID_OPERAND;
+
+ // check whether the vendor id matches
+ if (command.parameters[0] != 0x00 ||
+ command.parameters[1] != 0x00 ||
+ command.parameters[2] != 0x39)
+ return CEC_ABORT_REASON_INVALID_OPERAND;
+
+ bool bHandled(false);
+ CECClientPtr client = m_processor->GetClient(command.destination);
+ if (client)
+ {
+ switch (command.parameters[3])
+ {
+ // user control pressed
+ case CEC_OPCODE_USER_CONTROL_PRESSED:
+ if (command.parameters.size == 5)
+ {
+ bHandled = true;
+ switch (command.parameters[4])
+ {
+ // top menu
+ case RL_KEY_TOP_MENU:
+ client->SetCurrentButton(CEC_USER_CONTROL_CODE_TOP_MENU);
+ break;
+ // dvd menu
+ case RL_KEY_DVD_MENU:
+ client->SetCurrentButton(CEC_USER_CONTROL_CODE_DVD_MENU);
+ break;
+ default:
+ bHandled = false;
+ break;
+ }
+ }
+ break;
+ // user control released
+ case CEC_OPCODE_USER_CONTROL_RELEASE:
+ client->AddKey();
+ bHandled = true;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return bHandled ?
+ COMMAND_HANDLED :
+ CCECCommandHandler::HandleDeviceVendorCommandWithId(command);
+}
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include "CECCommandHandler.h"
+
+namespace CEC
+{
+ class CRLCommandHandler : public CCECCommandHandler
+ {
+ public:
+ CRLCommandHandler(CCECBusDevice *busDevice,
+ int32_t iTransmitTimeout = CEC_DEFAULT_TRANSMIT_TIMEOUT,
+ int32_t iTransmitWait = CEC_DEFAULT_TRANSMIT_WAIT,
+ int8_t iTransmitRetries = CEC_DEFAULT_TRANSMIT_RETRIES,
+ int64_t iActiveSourcePending = 0);
+ virtual ~CRLCommandHandler(void) {};
+
+ bool InitHandler(void);
+ int HandleDeviceVendorCommandWithId(const cec_command &command);
+ };
+};
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include "SLCommandHandler.h"
+
+#include <p8-platform/util/timeutils.h>
+#include "devices/CECBusDevice.h"
+#include "devices/CECPlaybackDevice.h"
+#include "CECProcessor.h"
+#include "LibCEC.h"
+#include <stdio.h>
+
+using namespace CEC;
+using namespace P8PLATFORM;
+
+#define SL_COMMAND_TYPE_HDDRECORDER_DISC 0x01
+#define SL_COMMAND_TYPE_VCR 0x02
+#define SL_COMMAND_TYPE_DVDPLAYER 0x03
+#define SL_COMMAND_TYPE_HDDRECORDER_DISC2 0x04
+#define SL_COMMAND_TYPE_HDDRECORDER 0x05
+
+#define SL_COMMAND_INIT 0x01
+#define SL_COMMAND_ACK_INIT 0x02
+#define SL_COMMAND_POWER_ON 0x03
+#define SL_COMMAND_CONNECT_REQUEST 0x04
+#define SL_COMMAND_SET_DEVICE_MODE 0x05
+#define SL_COMMAND_REQUEST_RECONNECT 0x0b
+#define SL_COMMAND_REQUEST_POWER_STATUS 0xa0
+
+#define LIB_CEC m_busDevice->GetProcessor()->GetLib()
+#define ToString(p) LIB_CEC->ToString(p)
+
+CSLCommandHandler::CSLCommandHandler(CCECBusDevice *busDevice,
+ int32_t iTransmitTimeout /* = CEC_DEFAULT_TRANSMIT_TIMEOUT */,
+ int32_t iTransmitWait /* = CEC_DEFAULT_TRANSMIT_WAIT */,
+ int8_t iTransmitRetries /* = CEC_DEFAULT_TRANSMIT_RETRIES */,
+ int64_t iActiveSourcePending /* = 0 */) :
+ CCECCommandHandler(busDevice, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending),
+ m_bSLEnabled(false)
+{
+ m_vendorId = CEC_VENDOR_LG;
+
+ /* LG devices don't always reply to CEC version requests, so just set it to 1.3a */
+ m_busDevice->SetCecVersion(CEC_VERSION_1_3A);
+
+ /* LG devices always return "korean" as language */
+ cec_menu_language lang;
+ snprintf(lang, 4, "eng");
+ m_busDevice->SetMenuLanguage(lang);
+}
+
+bool CSLCommandHandler::InitHandler(void)
+{
+ if (m_bHandlerInited)
+ return true;
+ m_bHandlerInited = true;
+
+ if (m_busDevice->GetLogicalAddress() != CECDEVICE_TV)
+ return true;
+
+ CCECBusDevice *primary = m_processor->GetPrimaryDevice();
+ if (primary && primary->GetLogicalAddress() != CECDEVICE_UNREGISTERED)
+ {
+ /* imitate LG devices */
+ if (m_busDevice->GetLogicalAddress() != primary->GetLogicalAddress())
+ {
+ primary->SetVendorId(CEC_VENDOR_LG);
+ primary->ReplaceHandler(false);
+ }
+ }
+
+ return true;
+}
+
+int CSLCommandHandler::HandleVendorCommand(const cec_command &command)
+{
+ if (!m_processor->IsHandledByLibCEC(command.destination))
+ return true;
+
+ if (command.parameters.size == 1 &&
+ command.parameters[0] == SL_COMMAND_INIT)
+ {
+ HandleVendorCommandSLInit(command);
+ return COMMAND_HANDLED;
+ }
+ else if (command.parameters.size == 2 &&
+ command.parameters[0] == SL_COMMAND_POWER_ON)
+ {
+ HandleVendorCommandPowerOn(command);
+ return COMMAND_HANDLED;
+ }
+ else if (command.parameters.size == 2 &&
+ command.parameters[0] == SL_COMMAND_CONNECT_REQUEST)
+ {
+ HandleVendorCommandSLConnect(command);
+ return COMMAND_HANDLED;
+ }
+ else if (command.parameters.size == 1 &&
+ command.parameters[0] == SL_COMMAND_REQUEST_RECONNECT)
+ {
+ HandleVendorCommandPowerOn(command);
+ return COMMAND_HANDLED;
+ }
+ else if (command.parameters.size == 1 &&
+ command.parameters[0] == SL_COMMAND_REQUEST_POWER_STATUS)
+ {
+ HandleVendorCommandPowerOnStatus(command);
+ return COMMAND_HANDLED;
+ }
+
+ return CCECCommandHandler::HandleVendorCommand(command);
+}
+
+void CSLCommandHandler::HandleVendorCommandSLInit(const cec_command &command)
+{
+ CCECBusDevice* dev = m_processor->GetDevice(command.destination);
+ if (dev && dev->IsHandledByLibCEC())
+ {
+ if (!dev->IsActiveSource())
+ {
+ dev->SetPowerStatus(CEC_POWER_STATUS_STANDBY);
+ dev->TransmitPowerState(command.initiator, true);
+ }
+
+ TransmitVendorCommandSLAckInit(command.destination, command.initiator);
+ }
+}
+
+void CSLCommandHandler::TransmitVendorCommandSLAckInit(const cec_logical_address iSource, const cec_logical_address iDestination)
+{
+ cec_command response;
+ cec_command::Format(response, iSource, iDestination, CEC_OPCODE_VENDOR_COMMAND);
+ response.PushBack(SL_COMMAND_ACK_INIT);
+ response.PushBack(SL_COMMAND_TYPE_HDDRECORDER);
+
+ Transmit(response, false, true);
+ SetSLInitialised();
+}
+
+void CSLCommandHandler::HandleVendorCommandPowerOn(const cec_command &command)
+{
+ if (command.initiator != CECDEVICE_TV)
+ return;
+
+ CCECBusDevice *device = m_processor->GetPrimaryDevice();
+ if (device)
+ {
+ SetSLInitialised();
+ device->MarkAsActiveSource();
+ device->SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON);
+ device->TransmitPowerState(command.initiator, true);
+
+ CEvent::Sleep(2000);
+ device->SetPowerStatus(CEC_POWER_STATUS_ON);
+ device->TransmitPowerState(command.initiator, false);
+ device->TransmitPhysicalAddress(false);
+
+ if (device->IsActiveSource())
+ ActivateSource();
+ }
+}
+void CSLCommandHandler::HandleVendorCommandPowerOnStatus(const cec_command &command)
+{
+ if (command.destination != CECDEVICE_BROADCAST)
+ {
+ CCECBusDevice *device = m_processor->GetPrimaryDevice();
+ if (device)
+ {
+ device->SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON);
+ device->TransmitPowerState(command.initiator, true);
+ device->SetPowerStatus(CEC_POWER_STATUS_ON);
+ }
+ }
+}
+
+void CSLCommandHandler::HandleVendorCommandSLConnect(const cec_command &command)
+{
+ SetSLInitialised();
+ TransmitVendorCommandSetDeviceMode(command.destination, command.initiator, CEC_DEVICE_TYPE_RECORDING_DEVICE);
+
+
+ if (m_processor->IsActiveSource(command.destination) && m_processor->IsHandledByLibCEC(command.destination))
+ {
+ CCECBusDevice* dev = m_processor->GetDevice(command.destination);
+ CCECPlaybackDevice* pb = dev->AsPlaybackDevice();
+ if (pb)
+ pb->TransmitDeckStatus(command.initiator, true);
+ dev->TransmitPowerState(command.initiator, true);
+ }
+}
+
+void CSLCommandHandler::TransmitVendorCommandSetDeviceMode(const cec_logical_address iSource, const cec_logical_address iDestination, const cec_device_type type)
+{
+ cec_command response;
+ cec_command::Format(response, iSource, iDestination, CEC_OPCODE_VENDOR_COMMAND);
+ response.PushBack(SL_COMMAND_SET_DEVICE_MODE);
+ response.PushBack((uint8_t)type);
+ Transmit(response, false, true);
+}
+
+int CSLCommandHandler::HandleGiveDeckStatus(const cec_command &command)
+{
+ if (!m_processor->CECInitialised() ||
+ !m_processor->IsHandledByLibCEC(command.destination))
+ return CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND;
+
+ CCECPlaybackDevice *device = CCECBusDevice::AsPlaybackDevice(GetDevice(command.destination));
+ if (!device || command.parameters.size == 0)
+ return CEC_ABORT_REASON_INVALID_OPERAND;
+
+ device->SetDeckStatus(CEC_DECK_INFO_OTHER_STATUS_LG);
+ if (command.parameters[0] == CEC_STATUS_REQUEST_ON)
+ {
+ device->TransmitDeckStatus(command.initiator, true);
+ ActivateSource();
+ return COMMAND_HANDLED;
+ }
+ else if (command.parameters[0] == CEC_STATUS_REQUEST_ONCE)
+ {
+ device->TransmitDeckStatus(command.initiator, true);
+ return COMMAND_HANDLED;
+ }
+
+ return CCECCommandHandler::HandleGiveDeckStatus(command);
+}
+
+int CSLCommandHandler::HandleGiveDevicePowerStatus(const cec_command &command)
+{
+ if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination) && command.initiator == CECDEVICE_TV)
+ {
+ CCECBusDevice *device = GetDevice(command.destination);
+ if (device && device->GetCurrentPowerStatus() != CEC_POWER_STATUS_ON)
+ {
+ device->TransmitPowerState(command.initiator, true);
+ device->SetPowerStatus(CEC_POWER_STATUS_ON);
+ }
+ else
+ {
+ if (m_resetPowerState.IsSet() && m_resetPowerState.TimeLeft() > 0)
+ {
+ /* TODO assume that we've bugged out. the return button no longer works after this */
+ LIB_CEC->AddLog(CEC_LOG_WARNING, "FIXME: LG seems to have bugged out. resetting to 'in transition standby to on'. the return button will not work");
+ device->SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON);
+ device->TransmitPowerState(command.initiator, true);
+ device->SetPowerStatus(CEC_POWER_STATUS_ON);
+ m_resetPowerState.Init(5000);
+ }
+ else
+ {
+ device->TransmitPowerState(command.initiator, true);
+ m_resetPowerState.Init(5000);
+ }
+ }
+
+ return COMMAND_HANDLED;
+ }
+
+ return CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND;
+}
+
+int CSLCommandHandler::HandleRequestActiveSource(const cec_command &command)
+{
+ if (m_processor->CECInitialised())
+ {
+ if (!SLInitialised())
+ TransmitVendorCommandSLAckInit(m_processor->GetPrimaryDevice()->GetLogicalAddress(), command.initiator);
+ CCECCommandHandler::HandleRequestActiveSource(command);
+ }
+ return CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND;
+}
+
+int CSLCommandHandler::HandleFeatureAbort(const cec_command &command)
+{
+ CCECBusDevice* primary = m_processor->GetPrimaryDevice();
+ if (command.parameters.size == 0 && primary->GetLogicalAddress() != CECDEVICE_UNKNOWN &&
+ primary->GetCurrentPowerStatus() == CEC_POWER_STATUS_ON && !SLInitialised() &&
+ command.initiator == CECDEVICE_TV)
+ {
+ if (!SLInitialised() && m_processor->IsActiveSource(command.destination))
+ {
+ TransmitVendorCommandSLAckInit(command.destination, command.initiator);
+ return COMMAND_HANDLED;
+ }
+ }
+
+ return CCECCommandHandler::HandleFeatureAbort(command);
+}
+
+int CSLCommandHandler::HandleStandby(const cec_command &command)
+{
+ ResetSLState();
+
+ return CCECCommandHandler::HandleStandby(command);
+}
+
+void CSLCommandHandler::ResetSLState(void)
+{
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, "resetting SL initialised state");
+ CLockObject lock(m_SLMutex);
+ m_bSLEnabled = false;
+ m_processor->GetPrimaryDevice()->SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON);
+}
+
+void CSLCommandHandler::SetSLInitialised(void)
+{
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, "SL initialised");
+ CLockObject lock(m_SLMutex);
+ m_bSLEnabled = true;
+}
+
+bool CSLCommandHandler::SLInitialised(void)
+{
+ CLockObject lock(m_SLMutex);
+ return m_bSLEnabled;
+}
+
+bool CSLCommandHandler::PowerOn(const cec_logical_address iInitiator, const cec_logical_address iDestination)
+{
+ if (iDestination != CECDEVICE_TV)
+ {
+ /* LG devices only allow themselves to be woken up by the TV with a vendor command */
+ cec_command command;
+
+ if (!m_bSLEnabled)
+ TransmitVendorID(CECDEVICE_TV, iDestination, CEC_VENDOR_LG, false);
+
+ cec_command::Format(command, CECDEVICE_TV, iDestination, CEC_OPCODE_VENDOR_COMMAND);
+ command.PushBack(SL_COMMAND_POWER_ON);
+ command.PushBack(0);
+ return Transmit(command, false, false);
+ }
+
+ return CCECCommandHandler::PowerOn(iInitiator, iDestination);
+}
+
+bool CSLCommandHandler::ActivateSource(bool bTransmitDelayedCommandsOnly /* = false */)
+{
+ if (m_busDevice->IsActiveSource() &&
+ m_busDevice->IsHandledByLibCEC())
+ {
+ {
+ CLockObject lock(m_mutex);
+ // check if we need to send a delayed source switch
+ if (bTransmitDelayedCommandsOnly)
+ {
+ if (m_iActiveSourcePending == 0 || GetTimeMs() < m_iActiveSourcePending)
+ return false;
+
+#ifdef CEC_DEBUGGING
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "transmitting delayed activate source command");
+#endif
+ }
+ }
+
+ CCECPlaybackDevice *device = m_busDevice->AsPlaybackDevice();
+ if (device)
+ device->SetDeckStatus(!device->IsActiveSource() ? CEC_DECK_INFO_OTHER_STATUS : CEC_DECK_INFO_OTHER_STATUS_LG);
+
+ // power on the TV
+ CCECBusDevice* tv = m_processor->GetDevice(CECDEVICE_TV);
+ bool bTvPresent = (tv && tv->GetStatus() == CEC_DEVICE_STATUS_PRESENT);
+ bool bActiveSourceFailed(false);
+ if (bTvPresent)
+ {
+ bActiveSourceFailed = !device->TransmitImageViewOn();
+ }
+ else
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "TV not present, not sending 'image view on'");
+ }
+
+ // check if we're allowed to switch sources
+ bool bSourceSwitchAllowed = SourceSwitchAllowed();
+ if (!bSourceSwitchAllowed)
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "source switch is currently not allowed by command handler");
+
+ // switch sources (if allowed)
+ if (!bActiveSourceFailed && bSourceSwitchAllowed)
+ {
+ bActiveSourceFailed = !m_busDevice->TransmitActiveSource(false);
+ }
+
+ // retry later
+ if (bActiveSourceFailed || !bSourceSwitchAllowed)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "failed to make '%s' the active source. will retry later", m_busDevice->GetLogicalAddressName());
+ int64_t now(GetTimeMs());
+ CLockObject lock(m_mutex);
+ if (m_iActiveSourcePending == 0 || m_iActiveSourcePending < now)
+ m_iActiveSourcePending = now + (int64_t)CEC_ACTIVE_SOURCE_SWITCH_RETRY_TIME_MS;
+ return false;
+ }
+ else
+ {
+ CLockObject lock(m_mutex);
+ // clear previous pending active source command
+ m_iActiveSourcePending = 0;
+ }
+
+ // mark the handler as initialised
+ CLockObject lock(m_mutex);
+ m_bHandlerInited = true;
+ }
+ return true;
+}
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include "CECCommandHandler.h"
+
+namespace CEC
+{
+ class CSLCommandHandler : public CCECCommandHandler
+ {
+ public:
+ CSLCommandHandler(CCECBusDevice *busDevice,
+ int32_t iTransmitTimeout = CEC_DEFAULT_TRANSMIT_TIMEOUT,
+ int32_t iTransmitWait = CEC_DEFAULT_TRANSMIT_WAIT,
+ int8_t iTransmitRetries = CEC_DEFAULT_TRANSMIT_RETRIES,
+ int64_t iActiveSourcePending = 0);
+ virtual ~CSLCommandHandler(void) {};
+
+ bool InitHandler(void);
+ bool ActivateSource(bool bTransmitDelayedCommandsOnly = false);
+
+ protected:
+ int HandleVendorCommand(const cec_command &command);
+
+ void HandleVendorCommandSLInit(const cec_command &command);
+ void TransmitVendorCommandSLAckInit(const cec_logical_address iSource, const cec_logical_address iDestination);
+
+ void HandleVendorCommandPowerOn(const cec_command &command);
+ void HandleVendorCommandPowerOnStatus(const cec_command &command);
+
+ void HandleVendorCommandSLConnect(const cec_command &command);
+ void TransmitVendorCommandSetDeviceMode(const cec_logical_address iSource, const cec_logical_address iDestination, const cec_device_type type);
+
+ int HandleGiveDevicePowerStatus(const cec_command &command);
+ int HandleGiveDeckStatus(const cec_command &command);
+ int HandleRequestActiveSource(const cec_command &command);
+ int HandleFeatureAbort(const cec_command &command);
+ int HandleStandby(const cec_command &command);
+ bool TransmitMenuState(const cec_logical_address UNUSED(iInitiator), const cec_logical_address UNUSED(iDestination), cec_menu_state UNUSED(menuState), bool UNUSED(bIsReply)) { return true; }
+ bool PowerOn(const cec_logical_address iInitiator, const cec_logical_address iDestination);
+
+ void ResetSLState(void);
+ bool SLInitialised(void);
+ void SetSLInitialised(void);
+
+ bool m_bSLEnabled;
+ P8PLATFORM::CTimeout m_resetPowerState;
+ P8PLATFORM::CMutex m_SLMutex;
+ };
+};
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include "VLCommandHandler.h"
+
+#include "devices/CECBusDevice.h"
+#include "devices/CECPlaybackDevice.h"
+#include "devices/CECTV.h"
+#include "CECProcessor.h"
+#include "LibCEC.h"
+#include "CECClient.h"
+
+#define VL_POWER_CHANGE 0x20
+#define VL_POWERED_UP 0x00
+#define VL_POWERED_DOWN 0x01
+#define VL_UNKNOWN1 0x06
+
+using namespace CEC;
+using namespace P8PLATFORM;
+
+#define LIB_CEC m_busDevice->GetProcessor()->GetLib()
+#define ToString(p) LIB_CEC->ToString(p)
+
+// wait this amount of ms before trying to switch sources after receiving the message from the TV that it's powered on
+#define SOURCE_SWITCH_DELAY_MS 3000
+
+CVLCommandHandler::CVLCommandHandler(CCECBusDevice *busDevice,
+ int32_t iTransmitTimeout /* = CEC_DEFAULT_TRANSMIT_TIMEOUT */,
+ int32_t iTransmitWait /* = CEC_DEFAULT_TRANSMIT_WAIT */,
+ int8_t iTransmitRetries /* = CEC_DEFAULT_TRANSMIT_RETRIES */,
+ int64_t iActiveSourcePending /* = 0 */) :
+ CCECCommandHandler(busDevice, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending),
+ m_iPowerUpEventReceived(0),
+ m_bCapabilitiesSent(false)
+{
+ m_vendorId = CEC_VENDOR_PANASONIC;
+}
+
+bool CVLCommandHandler::InitHandler(void)
+{
+ CCECBusDevice *primary = m_processor->GetPrimaryDevice();
+ if (primary && primary->GetLogicalAddress() != CECDEVICE_UNREGISTERED)
+ {
+ /* use the VL commandhandler for the primary device that is handled by libCEC */
+ if (m_busDevice->GetLogicalAddress() == CECDEVICE_TV)
+ {
+ if (primary && m_busDevice->GetLogicalAddress() != primary->GetLogicalAddress() &&
+ primary->GetLogicalAddress() != CECDEVICE_AUDIOSYSTEM)
+ {
+ libcec_configuration config;
+ m_processor->GetPrimaryClient()->GetCurrentConfiguration(config);
+ if (config.iDoubleTapTimeoutMs == 0)
+ {
+ config.iDoubleTapTimeoutMs = CEC_DOUBLE_TAP_TIMEOUT_MS;
+ m_processor->GetPrimaryClient()->SetConfiguration(config);
+ }
+
+ primary->SetVendorId(CEC_VENDOR_PANASONIC);
+ primary->ReplaceHandler(false);
+ }
+
+ if (primary->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE)
+ {
+ m_processor->ChangeDeviceType(m_processor->GetPrimaryClient(), CEC_DEVICE_TYPE_RECORDING_DEVICE, CEC_DEVICE_TYPE_PLAYBACK_DEVICE);
+ return true;
+ }
+ }
+ }
+
+ return CCECCommandHandler::InitHandler();
+}
+
+int CVLCommandHandler::HandleDeviceVendorCommandWithId(const cec_command &command)
+{
+ if (!m_processor->IsHandledByLibCEC(command.destination))
+ return CEC_ABORT_REASON_INVALID_OPERAND;
+
+ if (command.parameters[0] != 0x00 ||
+ command.parameters[1] != 0x80 ||
+ command.parameters[2] != 0x45)
+ return CEC_ABORT_REASON_INVALID_OPERAND;
+
+ if (command.initiator == CECDEVICE_TV &&
+ command.parameters.At(3) == VL_UNKNOWN1)
+ {
+ if (command.parameters.size >= 5 && command.parameters.At(4) == 0x05)
+ {
+ // set the power up event time
+ {
+ CLockObject lock(m_mutex);
+ if (m_iPowerUpEventReceived == 0)
+ m_iPowerUpEventReceived = GetTimeMs();
+ }
+ // mark the TV as powered on
+ m_processor->GetTV()->SetPowerStatus(CEC_POWER_STATUS_ON);
+
+ CCECBusDevice* dev = m_processor->GetPrimaryDevice();
+ if (dev && dev->IsActiveSource())
+ dev->TransmitActiveSource(false);
+
+ return COMMAND_HANDLED;
+ }
+ }
+ else if (command.initiator == CECDEVICE_TV &&
+ command.destination == CECDEVICE_BROADCAST &&
+ command.parameters.At(3) == VL_POWER_CHANGE)
+ {
+ if (command.parameters.At(4) == VL_POWERED_UP)
+ {
+ // set the power up event time
+ {
+ CLockObject lock(m_mutex);
+ if (m_iPowerUpEventReceived == 0)
+ m_iPowerUpEventReceived = GetTimeMs();
+ }
+ // mark the TV as powered on
+ m_processor->GetTV()->SetPowerStatus(CEC_POWER_STATUS_ON);
+
+ // send capabilties
+ SendVendorCommandCapabilities(m_processor->GetLogicalAddress(), command.initiator);
+
+ // reactivate the source, so the tv switches channels
+ if (m_processor->IsActiveSource(m_processor->GetLogicalAddress()))
+ m_processor->GetDevice(m_processor->GetLogicalAddress())->TransmitActiveSource(false);
+ }
+ else if (command.parameters.At(4) == VL_POWERED_DOWN)
+ {
+ // reset the power up event time
+ {
+ CLockObject lock(m_mutex);
+ m_iPowerUpEventReceived = 0;
+ }
+ // mark the TV as powered off
+ m_processor->GetTV()->SetPowerStatus(CEC_POWER_STATUS_STANDBY);
+ }
+ else
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "skipping unknown vendor command");
+
+ return COMMAND_HANDLED;
+ }
+
+ return CCECCommandHandler::HandleDeviceVendorCommandWithId(command);
+}
+
+bool CVLCommandHandler::PowerUpEventReceived(void)
+{
+ bool bPowerUpEventReceived(true);
+
+ if (m_busDevice->GetLogicalAddress() != CECDEVICE_TV)
+ {
+ CCECBusDevice* tv = m_processor->GetTV();
+ if (tv && tv->GetStatus() != CEC_DEVICE_STATUS_PRESENT)
+ return true;
+
+ // get the status from the TV
+ if (tv && tv->GetCurrentVendorId() == CEC_VENDOR_PANASONIC)
+ {
+ CVLCommandHandler *handler = static_cast<CVLCommandHandler *>(tv->GetHandler());
+ bPowerUpEventReceived = handler ? handler->PowerUpEventReceived() : false;
+ tv->MarkHandlerReady();
+ }
+ }
+ else
+ {
+ // get the current status
+ {
+ CLockObject lock(m_mutex);
+ bPowerUpEventReceived = m_iPowerUpEventReceived > 0 &&
+ GetTimeMs() - m_iPowerUpEventReceived > SOURCE_SWITCH_DELAY_MS;
+ }
+
+ // if we didn't receive the event, check if the TV is already marked as powered on
+ if (!bPowerUpEventReceived && m_busDevice->GetCurrentPowerStatus() == CEC_POWER_STATUS_ON)
+ {
+ CLockObject lock(m_mutex);
+ m_iPowerUpEventReceived = GetTimeMs();
+ bPowerUpEventReceived = true;
+ }
+ }
+
+ return bPowerUpEventReceived;
+}
+
+int CVLCommandHandler::HandleStandby(const cec_command &command)
+{
+ // reset the power up event time
+ {
+ CLockObject lock(m_mutex);
+ m_iPowerUpEventReceived = 0;
+ m_bCapabilitiesSent = false;
+ }
+
+ return CCECCommandHandler::HandleStandby(command);
+}
+
+void CVLCommandHandler::VendorPreActivateSourceHook(void)
+{
+ bool bTransmit(false);
+ {
+ CLockObject lock(m_mutex);
+ bTransmit = !m_bCapabilitiesSent;
+ }
+ if (bTransmit)
+ SendVendorCommandCapabilities(m_processor->GetLogicalAddress(), CECDEVICE_TV);
+}
+
+void CVLCommandHandler::SendVendorCommandCapabilities(const cec_logical_address initiator, const cec_logical_address destination)
+{
+ if (PowerUpEventReceived())
+ {
+ cec_command response;
+ cec_command::Format(response, initiator, destination, CEC_OPCODE_VENDOR_COMMAND);
+ uint8_t iResponseData[] = {0x10, 0x02, 0xFF, 0xFF, 0x00, 0x05, 0x05, 0x45, 0x55, 0x5c, 0x58, 0x32};
+ response.PushArray(12, iResponseData);
+
+ if (Transmit(response, false, true))
+ {
+ CLockObject lock(m_mutex);
+ m_bCapabilitiesSent = true;
+ }
+ }
+}
+
+int CVLCommandHandler::HandleVendorCommand(const cec_command &command)
+{
+ // some vendor command voodoo that will enable more buttons on the remote
+ if (command.parameters.size == 3 &&
+ command.parameters[0] == 0x10 &&
+ command.parameters[1] == 0x01 &&
+ m_processor->IsHandledByLibCEC(command.destination))
+ {
+ // XXX i've seen 0x05 and 0x03 as third param. these probably indicate different types of TVs/capabilities
+ // when we feature abort this, then the TV will try the same thing with a vendor command with id
+ SendVendorCommandCapabilities(m_processor->GetLogicalAddress(), command.initiator);
+
+ CCECBusDevice* dev = m_processor->GetDevice(command.destination);
+ if (dev && dev->IsActiveSource())
+ dev->ActivateSource(500);
+ return COMMAND_HANDLED;
+ }
+
+ return CEC_ABORT_REASON_INVALID_OPERAND;
+}
+
+bool CVLCommandHandler::SourceSwitchAllowed(void)
+{
+ if (!PowerUpEventReceived())
+ TransmitRequestPowerStatus(m_processor->GetPrimaryDevice()->GetLogicalAddress(), CECDEVICE_TV, false, false);
+
+ return PowerUpEventReceived();
+}
+
+int CVLCommandHandler::HandleSystemAudioModeRequest(const cec_command &command)
+{
+ if (command.initiator == CECDEVICE_TV)
+ {
+ // set the power up event time
+ {
+ CLockObject lock(m_mutex);
+ if (m_iPowerUpEventReceived == 0)
+ m_iPowerUpEventReceived = GetTimeMs();
+ }
+ // mark the TV as powered on
+ m_processor->GetTV()->SetPowerStatus(CEC_POWER_STATUS_ON);
+ }
+
+ return CCECCommandHandler::HandleSystemAudioModeRequest(command);
+}
+
+int CVLCommandHandler::HandleReportPowerStatus(const cec_command &command)
+{
+ if (command.initiator == m_busDevice->GetLogicalAddress() &&
+ command.parameters.size == 1 &&
+ (cec_power_status)command.parameters[0] == CEC_POWER_STATUS_ON)
+ {
+ CLockObject lock(m_mutex);
+ if (m_iPowerUpEventReceived == 0)
+ m_iPowerUpEventReceived = GetTimeMs();
+ }
+
+ return CCECCommandHandler::HandleReportPowerStatus(command);
+}
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include "CECCommandHandler.h"
+
+namespace CEC
+{
+ class CVLCommandHandler : public CCECCommandHandler
+ {
+ public:
+ CVLCommandHandler(CCECBusDevice *busDevice,
+ int32_t iTransmitTimeout = CEC_DEFAULT_TRANSMIT_TIMEOUT,
+ int32_t iTransmitWait = CEC_DEFAULT_TRANSMIT_WAIT,
+ int8_t iTransmitRetries = CEC_DEFAULT_TRANSMIT_RETRIES,
+ int64_t iActiveSourcePending = 0);
+ virtual ~CVLCommandHandler(void) {};
+
+ bool InitHandler(void);
+
+ int HandleDeviceVendorCommandWithId(const cec_command &command);
+ int HandleStandby(const cec_command &command);
+ int HandleSystemAudioModeRequest(const cec_command &command);
+
+ int HandleVendorCommand(const cec_command &command);
+ bool PowerUpEventReceived(void);
+ bool SupportsDeviceType(const cec_device_type type) const { return type != CEC_DEVICE_TYPE_RECORDING_DEVICE; };
+ cec_device_type GetReplacementDeviceType(const cec_device_type type) const { return type == CEC_DEVICE_TYPE_RECORDING_DEVICE ? CEC_DEVICE_TYPE_PLAYBACK_DEVICE : type; }
+
+ bool SourceSwitchAllowed(void);
+
+ protected:
+ void VendorPreActivateSourceHook(void);
+ void SendVendorCommandCapabilities(const cec_logical_address initiator, const cec_logical_address destination);
+ int HandleReportPowerStatus(const cec_command &command);
+
+ P8PLATFORM::CMutex m_mutex;
+ uint64_t m_iPowerUpEventReceived;
+ bool m_bCapabilitiesSent;
+ };
+};
--- /dev/null
+%module cec
+
+%{
+#include "SwigHelper.h"
+%}
+
+%include "stdint.i"
+%include "cstring.i"
+%include "std_string.i"
+%include "std_vector.i"
+
+%ignore *::operator=;
+
+%typemap(out) CEC::cec_osd_name {
+ $result = PyString_FromString($1.name);
+}
+
+/////// replace operator[]() ///////
+
+// CEC::cec_datapacket::operator[]()
+%extend CEC::cec_datapacket {
+ public:
+ uint8_t __getitem__(uint8_t pos)
+ {
+ return (*($self))[pos];
+ }
+}
+
+// CEC::cec_device_type::operator[]()
+%extend CEC::cec_device_type_list {
+ public:
+ CEC::cec_device_type __getitem__(uint8_t pos)
+ {
+ return (*($self))[pos];
+ }
+}
+
+// CEC::cec_logical_addresses::operator[]()
+%extend CEC::cec_logical_addresses {
+ public:
+ bool __getitem__(uint8_t pos)
+ {
+ return (*($self))[pos];
+ }
+}
+%ignore *::operator[];
+
+/////// rename ToString() ///////
+%rename("MenuStateToString") ToString(const cec_menu_state);
+%rename("CecVersionToString") ToString(const cec_version);
+%rename("PowerStatusToString") ToString(const cec_power_status);
+%rename("LogicalAddressToString") ToString(const cec_logical_address);
+%rename("DeckControlModeToString") ToString(const cec_deck_control_mode);
+%rename("DeckInfoToString") ToString(const cec_deck_info);
+%rename("OpcodeToString") ToString(const cec_opcode);
+%rename("AudioStatusToString") ToString(const cec_audio_status);
+%ignore *::ToString(const cec_vendor_id);
+%rename("DeviceTypeToString") ToString(const cec_device_type);
+%rename("UserControlCodeToString") ToString(const cec_user_control_code);
+%rename("AdapterTypeToString") ToString(const cec_adapter_type);
+
+/////// callbacks ///////
+%extend CEC::libcec_configuration {
+ public:
+ virtual ~libcec_configuration(void)
+ {
+ _ClearCallbacks(self);
+ self->Clear();
+ }
+
+ void SetLogCallback(PyObject* pyfunc)
+ {
+ _SetCallback(self, CEC::PYTHON_CB_LOG_MESSAGE, pyfunc);
+ }
+
+ void SetKeyPressCallback(PyObject* pyfunc)
+ {
+ _SetCallback(self, CEC::PYTHON_CB_KEY_PRESS, pyfunc);
+ }
+
+ void SetCommandCallback(PyObject* pyfunc)
+ {
+ _SetCallback(self, CEC::PYTHON_CB_COMMAND, pyfunc);
+ }
+
+ void SetMenuStateCallback(PyObject* pyfunc)
+ {
+ _SetCallback(self, CEC::PYTHON_CB_MENU_STATE, pyfunc);
+ }
+
+ void SetSourceActivatedCallback(PyObject* pyfunc)
+ {
+ _SetCallback(self, CEC::PYTHON_CB_SOURCE_ACTIVATED, pyfunc);
+ }
+
+ void ClearCallbacks(void)
+ {
+ _ClearCallbacks(self);
+ }
+}
+
+%ignore CEC::libcec_configuration::~libcec_configuration;
+%ignore CEC::libcec_configuration::callbacks;
+%ignore CEC::libcec_configuration::callbackParam;
+
+namespace std {
+ %template(AdapterVector) vector<CEC::AdapterDescriptor>;
+}
+
+/////// replace CECInitialise(), CECDestroy() and DetectAdapters() ///////
+
+%extend CEC::ICECAdapter {
+ public:
+ virtual ~ICECAdapter(void)
+ {
+ CEC::libcec_configuration config;
+ if (self->GetCurrentConfiguration(&config))
+ {
+ _ClearCallbacks(&config);
+ self->EnableCallbacks(NULL, NULL);
+ }
+ }
+
+ static CEC::ICECAdapter* Create(CEC::libcec_configuration* configuration)
+ {
+ CEC::ICECAdapter* lib = CECInitialise(configuration);
+ if (lib)
+ {
+ lib->InitVideoStandalone();
+ PyEval_InitThreads();
+ }
+ return lib;
+ }
+
+ std::vector<CEC::AdapterDescriptor> DetectAdapters(const char *strDevicePath = NULL, bool bQuickScan = false)
+ {
+ std::vector<CEC::AdapterDescriptor> retval;
+ CEC::cec_adapter_descriptor devList[10];
+ int nbAdapters = self->DetectAdapters(devList, 10, strDevicePath, bQuickScan);
+ for (int adapter = 0; adapter < nbAdapters; ++adapter)
+ retval.push_back(CEC::AdapterDescriptor(devList[adapter]));
+ return retval;
+ }
+}
+
+%ignore CEC::ICECAdapter::~ICECAdapter;
+%ignore CEC::ICECCallbacks;
+%ignore CEC::DetectAdapters;
+%ignore CEC::GetDeviceMenuLanguage;
+
+%ignore CEC::cec_keypress;
+%ignore CEC::cec_log_message;
+%ignore CEC::cec_adapter_descriptor;
+%ignore CEC::cec_adapter;
+%ignore CECInitialise;
+%ignore CECDestroy;
+
+%include "cectypes.h"
+%include "cec.h"
+
+%ignore *::ToString;
--- /dev/null
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libcec
+Description: Pulse-Eight libCEC @LIBCEC_VERSION_MAJOR@.@LIBCEC_VERSION_MINOR@.@LIBCEC_VERSION_PATCH@
+URL: http://www.pulse-eight.com/
+Version: @LIBCEC_VERSION_MAJOR@.@LIBCEC_VERSION_MINOR@.@LIBCEC_VERSION_PATCH@
+Requires: @LIBCEC_LIBREQUIRES@
+Libs: -L${libdir} -lcec
+Cflags: -I${includedir} -I${includedir}/libcec
--- /dev/null
+#include "winres.h"
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION @LIBCEC_VERSION_MAJOR@,@LIBCEC_VERSION_MINOR@,@LIBCEC_VERSION_PATCH@,0
+ PRODUCTVERSION @LIBCEC_VERSION_MAJOR@,@LIBCEC_VERSION_MINOR@,@LIBCEC_VERSION_PATCH@,0
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "000004b0"
+ BEGIN
+ VALUE "CompanyName", "Pulse-Eight Limited"
+ VALUE "FileDescription", "Pulse-Eight USB-CEC adapter interface"
+ VALUE "FileVersion", "@cec_VERSION_MAJOR@.@LIBCEC_VERSION_MINOR@.@LIBCEC_VERSION_PATCH@.0"
+ VALUE "InternalName", "libcec.dll"
+ VALUE "LegalCopyright", "Copyright (c) Pulse-Eight Limited 2011-2015"
+ VALUE "OriginalFilename", "cec.dll"
+ VALUE "ProductName", "libCEC"
+ VALUE "ProductVersion", "@LIBCEC_VERSION_MAJOR@.@LIBCEC_VERSION_MINOR@.@LIBCEC_VERSION_PATCH@.0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x0, 1200
+ END
+END
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include "randr-edid.h"
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <X11/extensions/Xrandr.h>
+#include <stdlib.h>
+
+using namespace P8PLATFORM;
+
+static const char * const edid_names[] =
+{
+#if (RANDR_MAJOR > 1) || (RANDR_MAJOR == 1 && RANDR_MINOR >2)
+ RR_PROPERTY_RANDR_EDID,
+#else
+ "EDID",
+#endif
+ "EDID_DATA",
+ "XFree86_DDC_EDID1_RAWDATA"
+};
+
+#define EDID_NAME_COUNT (sizeof(edid_names)/sizeof(*edid_names))
+
+uint16_t CRandrEdidParser::GetPhysicalAddress(void)
+{
+ uint16_t physical_address = 0;
+
+ /* open default X11 DISPLAY */
+ Display *disp = XOpenDisplay(NULL);
+ if( disp )
+ {
+ int event_base, error_base;
+ int maj, min;
+
+ if( XRRQueryExtension(disp, &event_base, &error_base)
+ && XRRQueryVersion(disp, &maj, &min) )
+ {
+ int version = (maj << 8) | min;
+
+ if( version >= 0x0102 )
+ {
+ size_t atom_avail = 0;
+ Atom edid_atoms[EDID_NAME_COUNT];
+
+ if( XInternAtoms(disp, (char **)edid_names, EDID_NAME_COUNT, True, edid_atoms) )
+ {
+ /* remove missing some atoms */
+ atom_avail = 0;
+ for(size_t atom_count=0; atom_count<EDID_NAME_COUNT; ++atom_count)
+ {
+ Atom edid_atom = edid_atoms[atom_count];
+ if( None != edid_atom )
+ {
+ if( atom_avail < atom_count )
+ {
+ edid_atoms[atom_avail] = edid_atom;
+ }
+ ++atom_avail;
+ }
+ }
+ }
+
+ if( atom_avail > 0 )
+ {
+ int scr_count = ScreenCount(disp);
+ int screen;
+
+ for(screen=0; screen<scr_count; ++screen)
+ {
+ XRRScreenResources *rsrc = NULL;
+ Window root = RootWindow(disp, screen);
+
+#if (RANDR_MAJOR > 1) || (RANDR_MAJOR == 1 && RANDR_MINOR >=3)
+ if( version >= 0x0103 )
+ {
+ /* get cached resources if they are available */
+ rsrc = XRRGetScreenResourcesCurrent(disp, root);
+ }
+
+ if( NULL == rsrc )
+#endif
+ rsrc = XRRGetScreenResources(disp, root);
+
+ if( NULL != rsrc )
+ {
+ int output_id;
+ for( output_id=0; 0 == physical_address && output_id < rsrc->noutput; ++output_id )
+ {
+ RROutput rr_output_id = rsrc->outputs[output_id];
+ XRROutputInfo *output_info = XRRGetOutputInfo(disp, rsrc, rr_output_id);
+ if( NULL != output_info )
+ {
+ if( RR_Connected == output_info->connection )
+ {
+ for(size_t atom_count=0; 0 == physical_address && atom_count<atom_avail; ++atom_count)
+ {
+ Atom actual_type;
+ int actual_format;
+ unsigned long nitems;
+ unsigned long bytes_after;
+ unsigned char *data;
+ int status;
+
+ status = XRRGetOutputProperty(disp, rr_output_id, edid_atoms[atom_count], 0, 128, False, False,
+ AnyPropertyType, &actual_type, &actual_format,
+ &nitems, &bytes_after, &data);
+ if( Success == status )
+ {
+ if((actual_type == XA_INTEGER) && (actual_format == 8) )
+ {
+ physical_address = CEDIDParser::GetPhysicalAddressFromEDID(data, nitems);
+ }
+ XFree(data);
+ }
+ }
+ }
+ XRRFreeOutputInfo(output_info);
+ }
+ else
+ break; /* problem ? */
+ }
+ XRRFreeScreenResources(rsrc);
+ }
+ }
+ }
+ }
+ }
+ XCloseDisplay(disp);
+ }
+ return physical_address;
+}
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include "platform/util/edid.h"
+
+namespace P8PLATFORM
+{
+ class CRandrEdidParser
+ {
+ public:
+ CRandrEdidParser(void) {};
+ virtual ~CRandrEdidParser(void) {};
+
+ uint16_t GetPhysicalAddress(void);
+ };
+}
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include "adl-edid.h"
+
+#if defined(HAVE_ADL_EDID_PARSER)
+
+// for dlsym and friends
+#if defined(__WINDOWS__)
+#include <p8-platform/windows/dlfcn-win32.h>
+#endif
+
+using namespace P8PLATFORM;
+
+CADLEdidParser::CADLEdidParser(void) :
+ m_bOpen(false),
+ m_handle(NULL)
+{
+ Initialise();
+}
+
+CADLEdidParser::~CADLEdidParser(void)
+{
+ CloseLibrary();
+}
+
+bool CADLEdidParser::OpenLibrary(void)
+{
+ CloseLibrary();
+
+#if !defined(__WINDOWS__)
+ m_handle = dlopen("libatiadlxx.so", RTLD_LAZY|RTLD_GLOBAL);
+#else
+ m_handle = LoadLibrary("atiadlxx.dll");
+ // try 32 bit
+ if (!m_handle)
+ m_handle = LoadLibrary("atiadlxy.dll");
+#endif
+
+ return m_handle != NULL;
+}
+
+void CADLEdidParser::CloseLibrary(void)
+{
+ if (LibOpen())
+ ADL_Main_Control_Destroy();
+
+ if (m_handle)
+ dlclose(m_handle);
+ m_handle = NULL;
+}
+
+void *__stdcall ADL_AllocMemory(int iSize)
+{
+ void* lpBuffer = malloc(iSize);
+ return lpBuffer;
+}
+
+void CADLEdidParser::Initialise(void)
+{
+ if (OpenLibrary())
+ {
+ // dlsym the methods we need
+ ADL_Main_Control_Create = (ADL_MAIN_CONTROL_CREATE) dlsym(m_handle, "ADL_Main_Control_Create");
+ ADL_Main_Control_Destroy = (ADL_MAIN_CONTROL_DESTROY) dlsym(m_handle, "ADL_Main_Control_Destroy");
+ ADL_Adapter_NumberOfAdapters_Get = (ADL_ADAPTER_NUMBEROFADAPTERS_GET) dlsym(m_handle, "ADL_Adapter_NumberOfAdapters_Get");
+ ADL_Adapter_AdapterInfo_Get = (ADL_ADAPTER_ADAPTERINFO_GET) dlsym(m_handle, "ADL_Adapter_AdapterInfo_Get");
+ ADL_Display_DisplayInfo_Get = (ADL_DISPLAY_DISPLAYINFO_GET) dlsym(m_handle, "ADL_Display_DisplayInfo_Get");
+ ADL_Display_EdidData_Get = (ADL_DISPLAY_EDIDDATA_GET) dlsym(m_handle, "ADL_Display_EdidData_Get");
+
+ // check whether they could all be resolved
+ if (ADL_Main_Control_Create &&
+ ADL_Main_Control_Destroy &&
+ ADL_Adapter_NumberOfAdapters_Get &&
+ ADL_Adapter_AdapterInfo_Get &&
+ ADL_Display_DisplayInfo_Get &&
+ ADL_Display_EdidData_Get)
+ {
+ // and try to initialise it
+ m_bOpen = (ADL_OK == ADL_Main_Control_Create(ADL_AllocMemory, 1));
+ }
+ }
+}
+
+int CADLEdidParser::GetNumAdapters(void)
+{
+ int iNumAdapters(0);
+
+ if (!LibOpen() || ADL_OK != ADL_Adapter_NumberOfAdapters_Get(&iNumAdapters))
+ iNumAdapters = 0;
+
+ return iNumAdapters;
+}
+
+LPAdapterInfo CADLEdidParser::GetAdapterInfo(int iNumAdapters)
+{
+ // validate input
+ if (iNumAdapters <= 0)
+ return NULL;
+
+ LPAdapterInfo adapterInfo = (LPAdapterInfo)malloc(sizeof(AdapterInfo) * iNumAdapters);
+ memset(adapterInfo, 0, sizeof(AdapterInfo) * iNumAdapters);
+
+ // get the info
+ ADL_Adapter_AdapterInfo_Get(adapterInfo, sizeof(AdapterInfo) * iNumAdapters);
+
+ return adapterInfo;
+}
+
+bool CADLEdidParser::GetAdapterEDID(int iAdapterIndex, int iDisplayIndex, ADLDisplayEDIDData *data)
+{
+ // validate input
+ if (iAdapterIndex < 0 || iDisplayIndex < 0)
+ return false;
+
+ memset(data, 0, sizeof(ADLDisplayEDIDData));
+ data->iSize = sizeof(ADLDisplayEDIDData);
+ data->iBlockIndex = 1;
+
+ return (ADL_Display_EdidData_Get(iAdapterIndex, iDisplayIndex, data) == ADL_OK);
+}
+
+uint16_t CADLEdidParser::GetPhysicalAddress(void)
+{
+ uint16_t iPA(0);
+
+ // get the number of adapters
+ int iNumAdapters = GetNumAdapters();
+ if (iNumAdapters <= 0)
+ return 0;
+
+ // get the adapter info
+ LPAdapterInfo adapterInfo = GetAdapterInfo(iNumAdapters);
+ if (!adapterInfo)
+ return 0;
+
+ // iterate over it
+ for (int iAdapterPtr = 0; iAdapterPtr < iNumAdapters; iAdapterPtr++)
+ {
+ int iNumDisplays(-1);
+ LPADLDisplayInfo displayInfo(NULL);
+ int iAdapterIndex = adapterInfo[iAdapterPtr].iAdapterIndex;
+
+ // get the display info
+ if (ADL_OK != ADL_Display_DisplayInfo_Get(iAdapterIndex, &iNumDisplays, &displayInfo, 0))
+ continue;
+
+ // iterate over it
+ for (int iDisplayPtr = 0; iDisplayPtr < iNumDisplays; iDisplayPtr++)
+ {
+ // check whether the display is connected
+ if ((displayInfo[iDisplayPtr].iDisplayInfoValue & ADL_DISPLAY_CONNECTED) != ADL_DISPLAY_CONNECTED)
+ continue;
+
+ int iDisplayIndex = displayInfo[iDisplayPtr].displayID.iDisplayLogicalIndex;
+
+ // try to get the EDID
+ ADLDisplayEDIDData edidData;
+ if (GetAdapterEDID(iAdapterIndex, iDisplayIndex, &edidData))
+ {
+ // try to get the PA from the EDID
+ iPA = CEDIDParser::GetPhysicalAddressFromEDID(edidData.cEDIDData, edidData.iEDIDSize);
+
+ // found it
+ if (iPA != 0)
+ break;
+ }
+ }
+
+ free(displayInfo);
+ }
+
+ free(adapterInfo);
+
+ return iPA;
+}
+
+#endif
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#define HAVE_ADL_EDID_PARSER
+
+#include "platform/util/edid.h"
+
+#if !defined(__WINDOWS__)
+#include "adl_sdk.h"
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+typedef void* ADL_LIB_HANDLE;
+
+#else
+#include <windows.h>
+#include <tchar.h>
+#include "adl_sdk.h"
+
+typedef HINSTANCE ADL_LIB_HANDLE;
+#endif
+
+typedef int (*ADL_MAIN_CONTROL_CREATE ) (ADL_MAIN_MALLOC_CALLBACK, int);
+typedef int (*ADL_MAIN_CONTROL_DESTROY) (void);
+typedef int (*ADL_ADAPTER_NUMBEROFADAPTERS_GET) (int*);
+typedef int (*ADL_ADAPTER_ADAPTERINFO_GET) (LPAdapterInfo, int);
+typedef int (*ADL_DISPLAY_DISPLAYINFO_GET) (int, int *, ADLDisplayInfo **, int);
+typedef int (*ADL_DISPLAY_EDIDDATA_GET) (int, int, ADLDisplayEDIDData *);
+
+#define ADL_DISPLAY_CONNECTED (ADL_DISPLAY_DISPLAYINFO_DISPLAYCONNECTED | ADL_DISPLAY_DISPLAYINFO_DISPLAYMAPPED)
+
+namespace P8PLATFORM
+{
+ class CADLEdidParser
+ {
+ public:
+ CADLEdidParser(void);
+ virtual ~CADLEdidParser(void);
+
+ uint16_t GetPhysicalAddress(void);
+ int GetNumAdapters(void);
+
+ private:
+ bool LibOpen(void) { return m_bOpen; }
+ void Initialise(void);
+ bool OpenLibrary(void);
+ void CloseLibrary(void);
+
+ LPAdapterInfo GetAdapterInfo(int iNumAdapters);
+ bool GetAdapterEDID(int iAdapterIndex, int iDisplayIndex, ADLDisplayEDIDData *data);
+
+ bool m_bOpen;
+ ADL_LIB_HANDLE m_handle;
+
+ ADL_MAIN_CONTROL_CREATE ADL_Main_Control_Create;
+ ADL_MAIN_CONTROL_DESTROY ADL_Main_Control_Destroy;
+ ADL_ADAPTER_NUMBEROFADAPTERS_GET ADL_Adapter_NumberOfAdapters_Get;
+ ADL_ADAPTER_ADAPTERINFO_GET ADL_Adapter_AdapterInfo_Get;
+ ADL_DISPLAY_DISPLAYINFO_GET ADL_Display_DisplayInfo_Get;
+ ADL_DISPLAY_EDIDDATA_GET ADL_Display_EdidData_Get;
+ };
+}
--- /dev/null
+//
+// Copyright (c) 2008 - 2012 Advanced Micro Devices, Inc.
+
+// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
+// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
+
+/// \file adl_defines.h
+/// \brief Contains all definitions exposed by ADL for \ALL platforms.\n <b>Included in ADL SDK</b>
+///
+/// This file contains all definitions used by ADL.
+/// The ADL definitions include the following:
+/// \li ADL error codes
+/// \li Enumerations for the ADLDisplayInfo structure
+/// \li Maximum limits
+///
+
+#ifndef ADL_DEFINES_H_
+#define ADL_DEFINES_H_
+
+/// \defgroup DEFINES Constants and Definitions
+// @{
+
+/// \defgroup define_misc Miscellaneous Constant Definitions
+// @{
+
+/// \name General Definitions
+// @{
+
+/// Defines ADL_TRUE
+#define ADL_TRUE 1
+/// Defines ADL_FALSE
+#define ADL_FALSE 0
+
+/// Defines the maximum string length
+#define ADL_MAX_CHAR 4096
+/// Defines the maximum string length
+#define ADL_MAX_PATH 256
+/// Defines the maximum number of supported adapters
+#define ADL_MAX_ADAPTERS 250
+/// Defines the maxumum number of supported displays
+#define ADL_MAX_DISPLAYS 150
+/// Defines the maxumum string length for device name
+#define ADL_MAX_DEVICENAME 32
+/// Defines for all adapters
+#define ADL_ADAPTER_INDEX_ALL -1
+/// Defines APIs with iOption none
+#define ADL_MAIN_API_OPTION_NONE 0
+// @}
+
+/// \name Definitions for iOption parameter used by
+/// ADL_Display_DDCBlockAccess_Get()
+// @{
+
+/// Switch to DDC line 2 before sending the command to the display.
+#define ADL_DDC_OPTION_SWITCHDDC2 0x00000001
+/// Save command in the registry under a unique key, corresponding to parameter \b iCommandIndex
+#define ADL_DDC_OPTION_RESTORECOMMAND 0x00000002
+/// Combine write-read DDC block access command.
+#define ADL_DDC_OPTION_COMBOWRITEREAD 0x00000010
+// @}
+
+/// \name Values for
+/// ADLI2C.iAction used with ADL_Display_WriteAndReadI2C()
+// @{
+
+#define ADL_DL_I2C_ACTIONREAD 0x00000001
+#define ADL_DL_I2C_ACTIONWRITE 0x00000002
+#define ADL_DL_I2C_ACTIONREAD_REPEATEDSTART 0x00000003
+// @}
+
+
+// @} //Misc
+
+/// \defgroup define_adl_results Result Codes
+/// This group of definitions are the various results returned by all ADL functions \n
+// @{
+/// All OK, but need to wait
+#define ADL_OK_WAIT 4
+/// All OK, but need restart
+#define ADL_OK_RESTART 3
+/// All OK but need mode change
+#define ADL_OK_MODE_CHANGE 2
+/// All OK, but with warning
+#define ADL_OK_WARNING 1
+/// ADL function completed successfully
+#define ADL_OK 0
+/// Generic Error. Most likely one or more of the Escape calls to the driver failed!
+#define ADL_ERR -1
+/// ADL not initialized
+#define ADL_ERR_NOT_INIT -2
+/// One of the parameter passed is invalid
+#define ADL_ERR_INVALID_PARAM -3
+/// One of the parameter size is invalid
+#define ADL_ERR_INVALID_PARAM_SIZE -4
+/// Invalid ADL index passed
+#define ADL_ERR_INVALID_ADL_IDX -5
+/// Invalid controller index passed
+#define ADL_ERR_INVALID_CONTROLLER_IDX -6
+/// Invalid display index passed
+#define ADL_ERR_INVALID_DIPLAY_IDX -7
+/// Function not supported by the driver
+#define ADL_ERR_NOT_SUPPORTED -8
+/// Null Pointer error
+#define ADL_ERR_NULL_POINTER -9
+/// Call can't be made due to disabled adapter
+#define ADL_ERR_DISABLED_ADAPTER -10
+/// Invalid Callback
+#define ADL_ERR_INVALID_CALLBACK -11
+/// Display Resource conflict
+#define ADL_ERR_RESOURCE_CONFLICT -12
+
+// @}
+/// </A>
+
+/// \defgroup define_display_type Display Type
+/// Define Monitor/CRT display type
+// @{
+/// Define Monitor display type
+#define ADL_DT_MONITOR 0
+/// Define TV display type
+#define ADL_DT_TELEVISION 1
+/// Define LCD display type
+#define ADL_DT_LCD_PANEL 2
+/// Define DFP display type
+#define ADL_DT_DIGITAL_FLAT_PANEL 3
+/// Define Componment Video display type
+#define ADL_DT_COMPONENT_VIDEO 4
+/// Define Projector display type
+#define ADL_DT_PROJECTOR 5
+// @}
+
+/// \defgroup define_display_connection_type Display Connection Type
+// @{
+/// Define unknown display output type
+#define ADL_DOT_UNKNOWN 0
+/// Define composite display output type
+#define ADL_DOT_COMPOSITE 1
+/// Define SVideo display output type
+#define ADL_DOT_SVIDEO 2
+/// Define analog display output type
+#define ADL_DOT_ANALOG 3
+/// Define digital display output type
+#define ADL_DOT_DIGITAL 4
+// @}
+
+/// \defgroup define_color_type Display Color Type and Source
+/// Define Display Color Type and Source
+// @{
+#define ADL_DISPLAY_COLOR_BRIGHTNESS (1 << 0)
+#define ADL_DISPLAY_COLOR_CONTRAST (1 << 1)
+#define ADL_DISPLAY_COLOR_SATURATION (1 << 2)
+#define ADL_DISPLAY_COLOR_HUE (1 << 3)
+#define ADL_DISPLAY_COLOR_TEMPERATURE (1 << 4)
+
+/// Color Temperature Source is EDID
+#define ADL_DISPLAY_COLOR_TEMPERATURE_SOURCE_EDID (1 << 5)
+/// Color Temperature Source is User
+#define ADL_DISPLAY_COLOR_TEMPERATURE_SOURCE_USER (1 << 6)
+// @}
+
+/// \defgroup define_adjustment_capabilities Display Adjustment Capabilities
+/// Display adjustment capabilities values. Returned by ADL_Display_AdjustCaps_Get
+// @{
+#define ADL_DISPLAY_ADJUST_OVERSCAN (1 << 0)
+#define ADL_DISPLAY_ADJUST_VERT_POS (1 << 1)
+#define ADL_DISPLAY_ADJUST_HOR_POS (1 << 2)
+#define ADL_DISPLAY_ADJUST_VERT_SIZE (1 << 3)
+#define ADL_DISPLAY_ADJUST_HOR_SIZE (1 << 4)
+#define ADL_DISPLAY_ADJUST_SIZEPOS (ADL_DISPLAY_ADJUST_VERT_POS | ADL_DISPLAY_ADJUST_HOR_POS | ADL_DISPLAY_ADJUST_VERT_SIZE | ADL_DISPLAY_ADJUST_HOR_SIZE)
+#define ADL_DISPLAY_CUSTOMMODES (1<<5)
+#define ADL_DISPLAY_ADJUST_UNDERSCAN (1<<6)
+// @}
+
+
+/// \defgroup define_desktop_config Desktop Configuration Flags
+/// These flags are used by ADL_DesktopConfig_xxx
+// @{
+#define ADL_DESKTOPCONFIG_UNKNOWN 0 /* UNKNOWN desktop config */
+#define ADL_DESKTOPCONFIG_SINGLE (1 << 0) /* Single */
+#define ADL_DESKTOPCONFIG_CLONE (1 << 2) /* Clone */
+#define ADL_DESKTOPCONFIG_BIGDESK_H (1 << 4) /* Big Desktop Horizontal */
+#define ADL_DESKTOPCONFIG_BIGDESK_V (1 << 5) /* Big Desktop Vertical */
+#define ADL_DESKTOPCONFIG_BIGDESK_HR (1 << 6) /* Big Desktop Reverse Horz */
+#define ADL_DESKTOPCONFIG_BIGDESK_VR (1 << 7) /* Big Desktop Reverse Vert */
+#define ADL_DESKTOPCONFIG_RANDR12 (1 << 8) /* RandR 1.2 Multi-display */
+// @}
+
+/// needed for ADLDDCInfo structure
+#define ADL_MAX_DISPLAY_NAME 256
+
+/// \defgroup define_edid_flags Values for ulDDCInfoFlag
+/// defines for ulDDCInfoFlag EDID flag
+// @{
+#define ADL_DISPLAYDDCINFOEX_FLAG_PROJECTORDEVICE (1 << 0)
+#define ADL_DISPLAYDDCINFOEX_FLAG_EDIDEXTENSION (1 << 1)
+#define ADL_DISPLAYDDCINFOEX_FLAG_DIGITALDEVICE (1 << 2)
+#define ADL_DISPLAYDDCINFOEX_FLAG_HDMIAUDIODEVICE (1 << 3)
+#define ADL_DISPLAYDDCINFOEX_FLAG_SUPPORTS_AI (1 << 4)
+#define ADL_DISPLAYDDCINFOEX_FLAG_SUPPORT_xvYCC601 (1 << 5)
+#define ADL_DISPLAYDDCINFOEX_FLAG_SUPPORT_xvYCC709 (1 << 6)
+// @}
+
+/// \defgroup define_displayinfo_connector Display Connector Type
+/// defines for ADLDisplayInfo.iDisplayConnector
+// @{
+#define ADL_DISPLAY_CONTYPE_UNKNOWN 0
+#define ADL_DISPLAY_CONTYPE_VGA 1
+#define ADL_DISPLAY_CONTYPE_DVI_D 2
+#define ADL_DISPLAY_CONTYPE_DVI_I 3
+#define ADL_DISPLAY_CONTYPE_ATICVDONGLE_NTSC 4
+#define ADL_DISPLAY_CONTYPE_ATICVDONGLE_JPN 5
+#define ADL_DISPLAY_CONTYPE_ATICVDONGLE_NONI2C_JPN 6
+#define ADL_DISPLAY_CONTYPE_ATICVDONGLE_NONI2C_NTSC 7
+#define ADL_DISPLAY_CONTYPE_PROPRIETARY 8
+#define ADL_DISPLAY_CONTYPE_HDMI_TYPE_A 10
+#define ADL_DISPLAY_CONTYPE_HDMI_TYPE_B 11
+#define ADL_DISPLAY_CONTYPE_SVIDEO 12
+#define ADL_DISPLAY_CONTYPE_COMPOSITE 13
+#define ADL_DISPLAY_CONTYPE_RCA_3COMPONENT 14
+#define ADL_DISPLAY_CONTYPE_DISPLAYPORT 15
+#define ADL_DISPLAY_CONTYPE_EDP 16
+#define ADL_DISPLAY_CONTYPE_WIRELESSDISPLAY 17
+// @}
+
+/// TV Capabilities and Standards
+/// \defgroup define_tv_caps TV Capabilities and Standards
+// @{
+#define ADL_TV_STANDARDS (1 << 0)
+#define ADL_TV_SCART (1 << 1)
+
+/// TV Standards Definitions
+#define ADL_STANDARD_NTSC_M (1 << 0)
+#define ADL_STANDARD_NTSC_JPN (1 << 1)
+#define ADL_STANDARD_NTSC_N (1 << 2)
+#define ADL_STANDARD_PAL_B (1 << 3)
+#define ADL_STANDARD_PAL_COMB_N (1 << 4)
+#define ADL_STANDARD_PAL_D (1 << 5)
+#define ADL_STANDARD_PAL_G (1 << 6)
+#define ADL_STANDARD_PAL_H (1 << 7)
+#define ADL_STANDARD_PAL_I (1 << 8)
+#define ADL_STANDARD_PAL_K (1 << 9)
+#define ADL_STANDARD_PAL_K1 (1 << 10)
+#define ADL_STANDARD_PAL_L (1 << 11)
+#define ADL_STANDARD_PAL_M (1 << 12)
+#define ADL_STANDARD_PAL_N (1 << 13)
+#define ADL_STANDARD_PAL_SECAM_D (1 << 14)
+#define ADL_STANDARD_PAL_SECAM_K (1 << 15)
+#define ADL_STANDARD_PAL_SECAM_K1 (1 << 16)
+#define ADL_STANDARD_PAL_SECAM_L (1 << 17)
+// @}
+
+
+/// \defgroup define_video_custom_mode Video Custom Mode flags
+/// Component Video Custom Mode flags. This is used by the iFlags parameter in ADLCustomMode
+// @{
+#define ADL_CUSTOMIZEDMODEFLAG_MODESUPPORTED (1 << 0)
+#define ADL_CUSTOMIZEDMODEFLAG_NOTDELETETABLE (1 << 1)
+#define ADL_CUSTOMIZEDMODEFLAG_INSERTBYDRIVER (1 << 2)
+#define ADL_CUSTOMIZEDMODEFLAG_INTERLACED (1 << 3)
+#define ADL_CUSTOMIZEDMODEFLAG_BASEMODE (1 << 4)
+// @}
+
+/// \defgroup define_ddcinfoflag Values used for DDCInfoFlag
+/// ulDDCInfoFlag field values used by the ADLDDCInfo structure
+// @{
+#define ADL_DISPLAYDDCINFOEX_FLAG_PROJECTORDEVICE (1 << 0)
+#define ADL_DISPLAYDDCINFOEX_FLAG_EDIDEXTENSION (1 << 1)
+#define ADL_DISPLAYDDCINFOEX_FLAG_DIGITALDEVICE (1 << 2)
+#define ADL_DISPLAYDDCINFOEX_FLAG_HDMIAUDIODEVICE (1 << 3)
+#define ADL_DISPLAYDDCINFOEX_FLAG_SUPPORTS_AI (1 << 4)
+#define ADL_DISPLAYDDCINFOEX_FLAG_SUPPORT_xvYCC601 (1 << 5)
+#define ADL_DISPLAYDDCINFOEX_FLAG_SUPPORT_xvYCC709 (1 << 6)
+// @}
+
+/// \defgroup define_cv_dongle Values used by ADL_CV_DongleSettings_xxx
+/// The following is applicable to ADL_DISPLAY_CONTYPE_ATICVDONGLE_JP and ADL_DISPLAY_CONTYPE_ATICVDONGLE_NONI2C_D only
+// @{
+#define ADL_DISPLAY_CV_DONGLE_D1 (1 << 0)
+#define ADL_DISPLAY_CV_DONGLE_D2 (1 << 1)
+#define ADL_DISPLAY_CV_DONGLE_D3 (1 << 2)
+#define ADL_DISPLAY_CV_DONGLE_D4 (1 << 3)
+#define ADL_DISPLAY_CV_DONGLE_D5 (1 << 4)
+
+/// The following is applicable to ADL_DISPLAY_CONTYPE_ATICVDONGLE_NA and ADL_DISPLAY_CONTYPE_ATICVDONGLE_NONI2C only
+
+#define ADL_DISPLAY_CV_DONGLE_480I (1 << 0)
+#define ADL_DISPLAY_CV_DONGLE_480P (1 << 1)
+#define ADL_DISPLAY_CV_DONGLE_540P (1 << 2)
+#define ADL_DISPLAY_CV_DONGLE_720P (1 << 3)
+#define ADL_DISPLAY_CV_DONGLE_1080I (1 << 4)
+#define ADL_DISPLAY_CV_DONGLE_1080P (1 << 5)
+#define ADL_DISPLAY_CV_DONGLE_16_9 (1 << 6)
+#define ADL_DISPLAY_CV_DONGLE_720P50 (1 << 7)
+#define ADL_DISPLAY_CV_DONGLE_1080I25 (1 << 8)
+#define ADL_DISPLAY_CV_DONGLE_576I25 (1 << 9)
+#define ADL_DISPLAY_CV_DONGLE_576P50 (1 << 10)
+#define ADL_DISPLAY_CV_DONGLE_1080P24 (1 << 11)
+#define ADL_DISPLAY_CV_DONGLE_1080P25 (1 << 12)
+#define ADL_DISPLAY_CV_DONGLE_1080P30 (1 << 13)
+#define ADL_DISPLAY_CV_DONGLE_1080P50 (1 << 14)
+// @}
+
+/// \defgroup define_formats_ovr Formats Override Settings
+/// Display force modes flags
+// @{
+///
+#define ADL_DISPLAY_FORMAT_FORCE_720P 0x00000001
+#define ADL_DISPLAY_FORMAT_FORCE_1080I 0x00000002
+#define ADL_DISPLAY_FORMAT_FORCE_1080P 0x00000004
+#define ADL_DISPLAY_FORMAT_FORCE_720P50 0x00000008
+#define ADL_DISPLAY_FORMAT_FORCE_1080I25 0x00000010
+#define ADL_DISPLAY_FORMAT_FORCE_576I25 0x00000020
+#define ADL_DISPLAY_FORMAT_FORCE_576P50 0x00000040
+#define ADL_DISPLAY_FORMAT_FORCE_1080P24 0x00000080
+#define ADL_DISPLAY_FORMAT_FORCE_1080P25 0x00000100
+#define ADL_DISPLAY_FORMAT_FORCE_1080P30 0x00000200
+#define ADL_DISPLAY_FORMAT_FORCE_1080P50 0x00000400
+
+///< Below are \b EXTENDED display mode flags
+
+#define ADL_DISPLAY_FORMAT_CVDONGLEOVERIDE 0x00000001
+#define ADL_DISPLAY_FORMAT_CVMODEUNDERSCAN 0x00000002
+#define ADL_DISPLAY_FORMAT_FORCECONNECT_SUPPORTED 0x00000004
+#define ADL_DISPLAY_FORMAT_RESTRICT_FORMAT_SELECTION 0x00000008
+#define ADL_DISPLAY_FORMAT_SETASPECRATIO 0x00000010
+#define ADL_DISPLAY_FORMAT_FORCEMODES 0x00000020
+#define ADL_DISPLAY_FORMAT_LCDRTCCOEFF 0x00000040
+// @}
+
+/// Defines used by OD5
+#define ADL_PM_PARAM_DONT_CHANGE 0
+
+/// The following defines Bus types
+// @{
+#define ADL_BUSTYPE_PCI 0 /* PCI bus */
+#define ADL_BUSTYPE_AGP 1 /* AGP bus */
+#define ADL_BUSTYPE_PCIE 2 /* PCI Express bus */
+#define ADL_BUSTYPE_PCIE_GEN2 3 /* PCI Express 2nd generation bus */
+#define ADL_BUSTYPE_PCIE_GEN3 4 /* PCI Express 3rd generation bus */
+// @}
+
+/// \defgroup define_ws_caps Workstation Capabilities
+/// Workstation values
+// @{
+
+/// This value indicates that the workstation card supports active stereo though stereo output connector
+#define ADL_STEREO_SUPPORTED (1 << 2)
+/// This value indicates that the workstation card supports active stereo via "blue-line"
+#define ADL_STEREO_BLUE_LINE (1 << 3)
+/// This value is used to turn off stereo mode.
+#define ADL_STEREO_OFF 0
+/// This value indicates that the workstation card supports active stereo. This is also used to set the stereo mode to active though the stereo output connector
+#define ADL_STEREO_ACTIVE (1 << 1)
+/// This value indicates that the workstation card supports auto-stereo monitors with horizontal interleave. This is also used to set the stereo mode to use the auto-stereo monitor with horizontal interleave
+#define ADL_STEREO_AUTO_HORIZONTAL (1 << 30)
+/// This value indicates that the workstation card supports auto-stereo monitors with vertical interleave. This is also used to set the stereo mode to use the auto-stereo monitor with vertical interleave
+#define ADL_STEREO_AUTO_VERTICAL (1 << 31)
+/// This value indicates that the workstation card supports passive stereo, ie. non stereo sync
+#define ADL_STEREO_PASSIVE (1 << 6)
+/// This value indicates that the workstation card supports auto-stereo monitors with vertical interleave. This is also used to set the stereo mode to use the auto-stereo monitor with vertical interleave
+#define ADL_STEREO_PASSIVE_HORIZ (1 << 7)
+/// This value indicates that the workstation card supports auto-stereo monitors with vertical interleave. This is also used to set the stereo mode to use the auto-stereo monitor with vertical interleave
+#define ADL_STEREO_PASSIVE_VERT (1 << 8)
+/// This value indicates that the workstation card supports DeepBitDepth (10 bpp)
+#define ADL_DEEPBITDEPTH_10BPP_SUPPORTED (1 << 5)
+
+/// This value indicates that the workstation supports 8-Bit Grayscale
+#define ADL_8BIT_GREYSCALE_SUPPORTED (1 << 9)
+
+/// Load balancing is supported.
+#define ADL_WORKSTATION_LOADBALANCING_SUPPORTED 0x00000001
+/// Load balancing is available.
+#define ADL_WORKSTATION_LOADBALANCING_AVAILABLE 0x00000002
+
+/// Load balancing is disabled.
+#define ADL_WORKSTATION_LOADBALANCING_DISABLED 0x00000000
+/// Load balancing is Enabled.
+#define ADL_WORKSTATION_LOADBALANCING_ENABLED 0x00000001
+
+
+
+// @}
+
+/// \defgroup define_adapterspeed speed setting from the adapter
+// @{
+#define ADL_CONTEXT_SPEED_UNFORCED 0 /* default asic running speed */
+#define ADL_CONTEXT_SPEED_FORCEHIGH 1 /* asic running speed is forced to high */
+#define ADL_CONTEXT_SPEED_FORCELOW 2 /* asic running speed is forced to low */
+
+#define ADL_ADAPTER_SPEEDCAPS_SUPPORTED (1 << 0) /* change asic running speed setting is supported */
+// @}
+
+/// \defgroup define_glsync Genlock related values
+/// GL-Sync port types (unique values)
+// @{
+/// Unknown port of GL-Sync module
+#define ADL_GLSYNC_PORT_UNKNOWN 0
+/// BNC port of of GL-Sync module
+#define ADL_GLSYNC_PORT_BNC 1
+/// RJ45(1) port of of GL-Sync module
+#define ADL_GLSYNC_PORT_RJ45PORT1 2
+/// RJ45(2) port of of GL-Sync module
+#define ADL_GLSYNC_PORT_RJ45PORT2 3
+
+// GL-Sync Genlock settings mask (bit-vector)
+
+/// None of the ADLGLSyncGenlockConfig members are valid
+#define ADL_GLSYNC_CONFIGMASK_NONE 0
+/// The ADLGLSyncGenlockConfig.lSignalSource member is valid
+#define ADL_GLSYNC_CONFIGMASK_SIGNALSOURCE (1 << 0)
+/// The ADLGLSyncGenlockConfig.iSyncField member is valid
+#define ADL_GLSYNC_CONFIGMASK_SYNCFIELD (1 << 1)
+/// The ADLGLSyncGenlockConfig.iSampleRate member is valid
+#define ADL_GLSYNC_CONFIGMASK_SAMPLERATE (1 << 2)
+/// The ADLGLSyncGenlockConfig.lSyncDelay member is valid
+#define ADL_GLSYNC_CONFIGMASK_SYNCDELAY (1 << 3)
+/// The ADLGLSyncGenlockConfig.iTriggerEdge member is valid
+#define ADL_GLSYNC_CONFIGMASK_TRIGGEREDGE (1 << 4)
+/// The ADLGLSyncGenlockConfig.iScanRateCoeff member is valid
+#define ADL_GLSYNC_CONFIGMASK_SCANRATECOEFF (1 << 5)
+/// The ADLGLSyncGenlockConfig.lFramelockCntlVector member is valid
+#define ADL_GLSYNC_CONFIGMASK_FRAMELOCKCNTL (1 << 6)
+
+
+// GL-Sync Framelock control mask (bit-vector)
+
+/// Framelock is disabled
+#define ADL_GLSYNC_FRAMELOCKCNTL_NONE 0
+/// Framelock is enabled
+#define ADL_GLSYNC_FRAMELOCKCNTL_ENABLE ( 1 << 0)
+
+#define ADL_GLSYNC_FRAMELOCKCNTL_DISABLE ( 1 << 1)
+#define ADL_GLSYNC_FRAMELOCKCNTL_SWAP_COUNTER_RESET ( 1 << 2)
+#define ADL_GLSYNC_FRAMELOCKCNTL_SWAP_COUNTER_ACK ( 1 << 3)
+
+#define ADL_GLSYNC_FRAMELOCKCNTL_STATE_ENABLE ( 1 << 0)
+
+// GL-Sync Framelock counters mask (bit-vector)
+#define ADL_GLSYNC_COUNTER_SWAP ( 1 << 0 )
+
+// GL-Sync Signal Sources (unique values)
+
+/// GL-Sync signal source is undefined
+#define ADL_GLSYNC_SIGNALSOURCE_UNDEFINED 0x00000100
+/// GL-Sync signal source is Free Run
+#define ADL_GLSYNC_SIGNALSOURCE_FREERUN 0x00000101
+/// GL-Sync signal source is the BNC GL-Sync port
+#define ADL_GLSYNC_SIGNALSOURCE_BNCPORT 0x00000102
+/// GL-Sync signal source is the RJ45(1) GL-Sync port
+#define ADL_GLSYNC_SIGNALSOURCE_RJ45PORT1 0x00000103
+/// GL-Sync signal source is the RJ45(2) GL-Sync port
+#define ADL_GLSYNC_SIGNALSOURCE_RJ45PORT2 0x00000104
+
+
+// GL-Sync Signal Types (unique values)
+
+/// GL-Sync signal type is unknown
+#define ADL_GLSYNC_SIGNALTYPE_UNDEFINED 0
+/// GL-Sync signal type is 480I
+#define ADL_GLSYNC_SIGNALTYPE_480I 1
+/// GL-Sync signal type is 576I
+#define ADL_GLSYNC_SIGNALTYPE_576I 2
+/// GL-Sync signal type is 480P
+#define ADL_GLSYNC_SIGNALTYPE_480P 3
+/// GL-Sync signal type is 576P
+#define ADL_GLSYNC_SIGNALTYPE_576P 4
+/// GL-Sync signal type is 720P
+#define ADL_GLSYNC_SIGNALTYPE_720P 5
+/// GL-Sync signal type is 1080P
+#define ADL_GLSYNC_SIGNALTYPE_1080P 6
+/// GL-Sync signal type is 1080I
+#define ADL_GLSYNC_SIGNALTYPE_1080I 7
+/// GL-Sync signal type is SDI
+#define ADL_GLSYNC_SIGNALTYPE_SDI 8
+/// GL-Sync signal type is TTL
+#define ADL_GLSYNC_SIGNALTYPE_TTL 9
+/// GL_Sync signal type is Analog
+#define ADL_GLSYNC_SIGNALTYPE_ANALOG 10
+
+// GL-Sync Sync Field options (unique values)
+
+///GL-Sync sync field option is undefined
+#define ADL_GLSYNC_SYNCFIELD_UNDEFINED 0
+///GL-Sync sync field option is Sync to Field 1 (used for Interlaced signal types)
+#define ADL_GLSYNC_SYNCFIELD_BOTH 1
+///GL-Sync sync field option is Sync to Both fields (used for Interlaced signal types)
+#define ADL_GLSYNC_SYNCFIELD_1 2
+
+
+// GL-Sync trigger edge options (unique values)
+
+/// GL-Sync trigger edge is undefined
+#define ADL_GLSYNC_TRIGGEREDGE_UNDEFINED 0
+/// GL-Sync trigger edge is the rising edge
+#define ADL_GLSYNC_TRIGGEREDGE_RISING 1
+/// GL-Sync trigger edge is the falling edge
+#define ADL_GLSYNC_TRIGGEREDGE_FALLING 2
+/// GL-Sync trigger edge is both the rising and the falling edge
+#define ADL_GLSYNC_TRIGGEREDGE_BOTH 3
+
+
+// GL-Sync scan rate coefficient/multiplier options (unique values)
+
+/// GL-Sync scan rate coefficient/multiplier is undefined
+#define ADL_GLSYNC_SCANRATECOEFF_UNDEFINED 0
+/// GL-Sync scan rate coefficient/multiplier is 5
+#define ADL_GLSYNC_SCANRATECOEFF_x5 1
+/// GL-Sync scan rate coefficient/multiplier is 4
+#define ADL_GLSYNC_SCANRATECOEFF_x4 2
+/// GL-Sync scan rate coefficient/multiplier is 3
+#define ADL_GLSYNC_SCANRATECOEFF_x3 3
+/// GL-Sync scan rate coefficient/multiplier is 5:2 (SMPTE)
+#define ADL_GLSYNC_SCANRATECOEFF_x5_DIV_2 4
+/// GL-Sync scan rate coefficient/multiplier is 2
+#define ADL_GLSYNC_SCANRATECOEFF_x2 5
+/// GL-Sync scan rate coefficient/multiplier is 3 : 2
+#define ADL_GLSYNC_SCANRATECOEFF_x3_DIV_2 6
+/// GL-Sync scan rate coefficient/multiplier is 5 : 4
+#define ADL_GLSYNC_SCANRATECOEFF_x5_DIV_4 7
+/// GL-Sync scan rate coefficient/multiplier is 1 (default)
+#define ADL_GLSYNC_SCANRATECOEFF_x1 8
+/// GL-Sync scan rate coefficient/multiplier is 4 : 5
+#define ADL_GLSYNC_SCANRATECOEFF_x4_DIV_5 9
+/// GL-Sync scan rate coefficient/multiplier is 2 : 3
+#define ADL_GLSYNC_SCANRATECOEFF_x2_DIV_3 10
+/// GL-Sync scan rate coefficient/multiplier is 1 : 2
+#define ADL_GLSYNC_SCANRATECOEFF_x1_DIV_2 11
+/// GL-Sync scan rate coefficient/multiplier is 2 : 5 (SMPTE)
+#define ADL_GLSYNC_SCANRATECOEFF_x2_DIV_5 12
+/// GL-Sync scan rate coefficient/multiplier is 1 : 3
+#define ADL_GLSYNC_SCANRATECOEFF_x1_DIV_3 13
+/// GL-Sync scan rate coefficient/multiplier is 1 : 4
+#define ADL_GLSYNC_SCANRATECOEFF_x1_DIV_4 14
+/// GL-Sync scan rate coefficient/multiplier is 1 : 5
+#define ADL_GLSYNC_SCANRATECOEFF_x1_DIV_5 15
+
+
+// GL-Sync port (signal presence) states (unique values)
+
+/// GL-Sync port state is undefined
+#define ADL_GLSYNC_PORTSTATE_UNDEFINED 0
+/// GL-Sync port is not connected
+#define ADL_GLSYNC_PORTSTATE_NOCABLE 1
+/// GL-Sync port is Idle
+#define ADL_GLSYNC_PORTSTATE_IDLE 2
+/// GL-Sync port has an Input signal
+#define ADL_GLSYNC_PORTSTATE_INPUT 3
+/// GL-Sync port is Output
+#define ADL_GLSYNC_PORTSTATE_OUTPUT 4
+
+
+// GL-Sync LED types (used index within ADL_Workstation_GLSyncPortState_Get returned ppGlSyncLEDs array) (unique values)
+
+/// Index into the ADL_Workstation_GLSyncPortState_Get returned ppGlSyncLEDs array for the one LED of the BNC port
+#define ADL_GLSYNC_LEDTYPE_BNC 0
+/// Index into the ADL_Workstation_GLSyncPortState_Get returned ppGlSyncLEDs array for the Left LED of the RJ45(1) or RJ45(2) port
+#define ADL_GLSYNC_LEDTYPE_RJ45_LEFT 0
+/// Index into the ADL_Workstation_GLSyncPortState_Get returned ppGlSyncLEDs array for the Right LED of the RJ45(1) or RJ45(2) port
+#define ADL_GLSYNC_LEDTYPE_RJ45_RIGHT 1
+
+
+// GL-Sync LED colors (unique values)
+
+/// GL-Sync LED undefined color
+#define ADL_GLSYNC_LEDCOLOR_UNDEFINED 0
+/// GL-Sync LED is unlit
+#define ADL_GLSYNC_LEDCOLOR_NOLIGHT 1
+/// GL-Sync LED is yellow
+#define ADL_GLSYNC_LEDCOLOR_YELLOW 2
+/// GL-Sync LED is red
+#define ADL_GLSYNC_LEDCOLOR_RED 3
+/// GL-Sync LED is green
+#define ADL_GLSYNC_LEDCOLOR_GREEN 4
+/// GL-Sync LED is flashing green
+#define ADL_GLSYNC_LEDCOLOR_FLASH_GREEN 5
+
+
+// GL-Sync Port Control (refers one GL-Sync Port) (unique values)
+
+/// Used to configure the RJ54(1) or RJ42(2) port of GL-Sync is as Idle
+#define ADL_GLSYNC_PORTCNTL_NONE 0x00000000
+/// Used to configure the RJ54(1) or RJ42(2) port of GL-Sync is as Output
+#define ADL_GLSYNC_PORTCNTL_OUTPUT 0x00000001
+
+
+// GL-Sync Mode Control (refers one Display/Controller) (bitfields)
+
+/// Used to configure the display to use internal timing (not genlocked)
+#define ADL_GLSYNC_MODECNTL_NONE 0x00000000
+/// Bitfield used to configure the display as genlocked (either as Timing Client or as Timing Server)
+#define ADL_GLSYNC_MODECNTL_GENLOCK 0x00000001
+/// Bitfield used to configure the display as Timing Server
+#define ADL_GLSYNC_MODECNTL_TIMINGSERVER 0x00000002
+
+// GL-Sync Mode Status
+/// Display is currently not genlocked
+#define ADL_GLSYNC_MODECNTL_STATUS_NONE 0x00000000
+/// Display is currently genlocked
+#define ADL_GLSYNC_MODECNTL_STATUS_GENLOCK 0x00000001
+/// Display requires a mode switch
+#define ADL_GLSYNC_MODECNTL_STATUS_SETMODE_REQUIRED 0x00000002
+/// Display is capable of being genlocked
+#define ADL_GLSYNC_MODECNTL_STATUS_GENLOCK_ALLOWED 0x00000004
+
+#define ADL_MAX_GLSYNC_PORTS 8
+#define ADL_MAX_GLSYNC_PORT_LEDS 8
+
+// @}
+
+/// \defgroup define_crossfirestate CrossfireX state of a particular adapter CrossfireX combination
+// @{
+#define ADL_XFIREX_STATE_NOINTERCONNECT ( 1 << 0 ) /* Dongle / cable is missing */
+#define ADL_XFIREX_STATE_DOWNGRADEPIPES ( 1 << 1 ) /* CrossfireX can be enabled if pipes are downgraded */
+#define ADL_XFIREX_STATE_DOWNGRADEMEM ( 1 << 2 ) /* CrossfireX cannot be enabled unless mem downgraded */
+#define ADL_XFIREX_STATE_REVERSERECOMMENDED ( 1 << 3 ) /* Card reversal recommended, CrossfireX cannot be enabled. */
+#define ADL_XFIREX_STATE_3DACTIVE ( 1 << 4 ) /* 3D client is active - CrossfireX cannot be safely enabled */
+#define ADL_XFIREX_STATE_MASTERONSLAVE ( 1 << 5 ) /* Dongle is OK but master is on slave */
+#define ADL_XFIREX_STATE_NODISPLAYCONNECT ( 1 << 6 ) /* No (valid) display connected to master card. */
+#define ADL_XFIREX_STATE_NOPRIMARYVIEW ( 1 << 7 ) /* CrossfireX is enabled but master is not current primary device */
+#define ADL_XFIREX_STATE_DOWNGRADEVISMEM ( 1 << 8 ) /* CrossfireX cannot be enabled unless visible mem downgraded */
+#define ADL_XFIREX_STATE_LESSTHAN8LANE_MASTER ( 1 << 9 ) /* CrossfireX can be enabled however performance not optimal due to <8 lanes */
+#define ADL_XFIREX_STATE_LESSTHAN8LANE_SLAVE ( 1 << 10 ) /* CrossfireX can be enabled however performance not optimal due to <8 lanes */
+#define ADL_XFIREX_STATE_PEERTOPEERFAILED ( 1 << 11 ) /* CrossfireX cannot be enabled due to failed peer to peer test */
+#define ADL_XFIREX_STATE_MEMISDOWNGRADED ( 1 << 16 ) /* Notification that memory is currently downgraded */
+#define ADL_XFIREX_STATE_PIPESDOWNGRADED ( 1 << 17 ) /* Notification that pipes are currently downgraded */
+#define ADL_XFIREX_STATE_XFIREXACTIVE ( 1 << 18 ) /* CrossfireX is enabled on current device */
+#define ADL_XFIREX_STATE_VISMEMISDOWNGRADED ( 1 << 19 ) /* Notification that visible FB memory is currently downgraded */
+#define ADL_XFIREX_STATE_INVALIDINTERCONNECTION ( 1 << 20 ) /* Cannot support current inter-connection configuration */
+#define ADL_XFIREX_STATE_NONP2PMODE ( 1 << 21 ) /* CrossfireX will only work with clients supporting non P2P mode */
+#define ADL_XFIREX_STATE_DOWNGRADEMEMBANKS ( 1 << 22 ) /* CrossfireX cannot be enabled unless memory banks downgraded */
+#define ADL_XFIREX_STATE_MEMBANKSDOWNGRADED ( 1 << 23 ) /* Notification that memory banks are currently downgraded */
+#define ADL_XFIREX_STATE_DUALDISPLAYSALLOWED ( 1 << 24 ) /* Extended desktop or clone mode is allowed. */
+#define ADL_XFIREX_STATE_P2P_APERTURE_MAPPING ( 1 << 25 ) /* P2P mapping was through peer aperture */
+#define ADL_XFIREX_STATE_P2PFLUSH_REQUIRED ADL_XFIREX_STATE_P2P_APERTURE_MAPPING /* For back compatible */
+#define ADL_XFIREX_STATE_XSP_CONNECTED ( 1 << 26 ) /* There is CrossfireX side port connection between GPUs */
+#define ADL_XFIREX_STATE_ENABLE_CF_REBOOT_REQUIRED ( 1 << 27 ) /* System needs a reboot bofore enable CrossfireX */
+#define ADL_XFIREX_STATE_DISABLE_CF_REBOOT_REQUIRED ( 1 << 28 ) /* System needs a reboot after disable CrossfireX */
+#define ADL_XFIREX_STATE_DRV_HANDLE_DOWNGRADE_KEY ( 1 << 29 ) /* Indicate base driver handles the downgrade key updating */
+#define ADL_XFIREX_STATE_CF_RECONFIG_REQUIRED ( 1 << 30 ) /* CrossfireX need to be reconfigured by CCC because of a LDA chain broken */
+#define ADL_XFIREX_STATE_ERRORGETTINGSTATUS ( 1 << 31 ) /* Could not obtain current status */
+// @}
+
+///////////////////////////////////////////////////////////////////////////
+// ADL_DISPLAY_ADJUSTMENT_PIXELFORMAT adjustment values
+// (bit-vector)
+///////////////////////////////////////////////////////////////////////////
+/// \defgroup define_pixel_formats Pixel Formats values
+/// This group defines the various Pixel Formats that a particular digital display can support. \n
+/// Since a display can support multiple formats, these values can be bit-or'ed to indicate the various formats \n
+// @{
+#define ADL_DISPLAY_PIXELFORMAT_UNKNOWN 0
+#define ADL_DISPLAY_PIXELFORMAT_RGB (1 << 0)
+#define ADL_DISPLAY_PIXELFORMAT_YCRCB444 (1 << 1) //Limited range
+#define ADL_DISPLAY_PIXELFORMAT_YCRCB422 (1 << 2) //Limited range
+#define ADL_DISPLAY_PIXELFORMAT_RGB_LIMITED_RANGE (1 << 3)
+#define ADL_DISPLAY_PIXELFORMAT_RGB_FULL_RANGE ADL_DISPLAY_PIXELFORMAT_RGB //Full range
+// @}
+
+/// \defgroup define_contype Connector Type Values
+/// ADLDisplayConfig.ulConnectorType defines
+// @{
+#define ADL_DL_DISPLAYCONFIG_CONTYPE_UNKNOWN 0
+#define ADL_DL_DISPLAYCONFIG_CONTYPE_CV_NONI2C_JP 1
+#define ADL_DL_DISPLAYCONFIG_CONTYPE_CV_JPN 2
+#define ADL_DL_DISPLAYCONFIG_CONTYPE_CV_NA 3
+#define ADL_DL_DISPLAYCONFIG_CONTYPE_CV_NONI2C_NA 4
+#define ADL_DL_DISPLAYCONFIG_CONTYPE_VGA 5
+#define ADL_DL_DISPLAYCONFIG_CONTYPE_DVI_D 6
+#define ADL_DL_DISPLAYCONFIG_CONTYPE_DVI_I 7
+#define ADL_DL_DISPLAYCONFIG_CONTYPE_HDMI_TYPE_A 8
+#define ADL_DL_DISPLAYCONFIG_CONTYPE_HDMI_TYPE_B 9
+#define ADL_DL_DISPLAYCONFIG_CONTYPE_DISPLAYPORT 10
+// @}
+
+
+///////////////////////////////////////////////////////////////////////////
+// ADL_DISPLAY_DISPLAYINFO_ Definitions
+// for ADLDisplayInfo.iDisplayInfoMask and ADLDisplayInfo.iDisplayInfoValue
+// (bit-vector)
+///////////////////////////////////////////////////////////////////////////
+/// \defgroup define_displayinfomask Display Info Mask Values
+// @{
+#define ADL_DISPLAY_DISPLAYINFO_DISPLAYCONNECTED 0x00000001
+#define ADL_DISPLAY_DISPLAYINFO_DISPLAYMAPPED 0x00000002
+#define ADL_DISPLAY_DISPLAYINFO_NONLOCAL 0x00000004
+#define ADL_DISPLAY_DISPLAYINFO_FORCIBLESUPPORTED 0x00000008
+#define ADL_DISPLAY_DISPLAYINFO_GENLOCKSUPPORTED 0x00000010
+#define ADL_DISPLAY_DISPLAYINFO_MULTIVPU_SUPPORTED 0x00000020
+
+#define ADL_DISPLAY_DISPLAYINFO_MANNER_SUPPORTED_SINGLE 0x00000100
+#define ADL_DISPLAY_DISPLAYINFO_MANNER_SUPPORTED_CLONE 0x00000200
+
+/// Legacy support for XP
+#define ADL_DISPLAY_DISPLAYINFO_MANNER_SUPPORTED_2VSTRETCH 0x00000400
+#define ADL_DISPLAY_DISPLAYINFO_MANNER_SUPPORTED_2HSTRETCH 0x00000800
+#define ADL_DISPLAY_DISPLAYINFO_MANNER_SUPPORTED_EXTENDED 0x00001000
+
+/// More support manners
+#define ADL_DISPLAY_DISPLAYINFO_MANNER_SUPPORTED_NSTRETCH1GPU 0x00010000
+#define ADL_DISPLAY_DISPLAYINFO_MANNER_SUPPORTED_NSTRETCHNGPU 0x00020000
+#define ADL_DISPLAY_DISPLAYINFO_MANNER_SUPPORTED_RESERVED2 0x00040000
+#define ADL_DISPLAY_DISPLAYINFO_MANNER_SUPPORTED_RESERVED3 0x00080000
+
+/// Projector display type
+#define ADL_DISPLAY_DISPLAYINFO_SHOWTYPE_PROJECTOR 0x00100000
+
+// @}
+
+
+///////////////////////////////////////////////////////////////////////////
+// ADL_ADAPTER_DISPLAY_MANNER_SUPPORTED_ Definitions
+// for ADLAdapterDisplayCap of ADL_Adapter_Display_Cap()
+// (bit-vector)
+///////////////////////////////////////////////////////////////////////////
+/// \defgroup define_adaptermanner Adapter Manner Support Values
+// @{
+#define ADL_ADAPTER_DISPLAYCAP_MANNER_SUPPORTED_NOTACTIVE 0x00000001
+#define ADL_ADAPTER_DISPLAYCAP_MANNER_SUPPORTED_SINGLE 0x00000002
+#define ADL_ADAPTER_DISPLAYCAP_MANNER_SUPPORTED_CLONE 0x00000004
+#define ADL_ADAPTER_DISPLAYCAP_MANNER_SUPPORTED_NSTRETCH1GPU 0x00000008
+#define ADL_ADAPTER_DISPLAYCAP_MANNER_SUPPORTED_NSTRETCHNGPU 0x00000010
+
+/// Legacy support for XP
+#define ADL_ADAPTER_DISPLAYCAP_MANNER_SUPPORTED_2VSTRETCH 0x00000020
+#define ADL_ADAPTER_DISPLAYCAP_MANNER_SUPPORTED_2HSTRETCH 0x00000040
+#define ADL_ADAPTER_DISPLAYCAP_MANNER_SUPPORTED_EXTENDED 0x00000080
+
+#define ADL_ADAPTER_DISPLAYCAP_PREFERDISPLAY_SUPPORTED 0x00000100
+#define ADL_ADAPTER_DISPLAYCAP_BEZEL_SUPPORTED 0x00000200
+
+
+///////////////////////////////////////////////////////////////////////////
+// ADL_DISPLAY_DISPLAYMAP_MANNER_ Definitions
+// for ADLDisplayMap.iDisplayMapMask and ADLDisplayMap.iDisplayMapValue
+// (bit-vector)
+///////////////////////////////////////////////////////////////////////////
+#define ADL_DISPLAY_DISPLAYMAP_MANNER_RESERVED 0x00000001
+#define ADL_DISPLAY_DISPLAYMAP_MANNER_NOTACTIVE 0x00000002
+#define ADL_DISPLAY_DISPLAYMAP_MANNER_SINGLE 0x00000004
+#define ADL_DISPLAY_DISPLAYMAP_MANNER_CLONE 0x00000008
+#define ADL_DISPLAY_DISPLAYMAP_MANNER_RESERVED1 0x00000010 // Removed NSTRETCH
+#define ADL_DISPLAY_DISPLAYMAP_MANNER_HSTRETCH 0x00000020
+#define ADL_DISPLAY_DISPLAYMAP_MANNER_VSTRETCH 0x00000040
+#define ADL_DISPLAY_DISPLAYMAP_MANNER_VLD 0x00000080
+
+// @}
+
+///////////////////////////////////////////////////////////////////////////
+// ADL_DISPLAY_DISPLAYMAP_OPTION_ Definitions
+// for iOption in function ADL_Display_DisplayMapConfig_Get
+// (bit-vector)
+///////////////////////////////////////////////////////////////////////////
+#define ADL_DISPLAY_DISPLAYMAP_OPTION_GPUINFO 0x00000001
+
+///////////////////////////////////////////////////////////////////////////
+// ADL_DISPLAY_DISPLAYTARGET_ Definitions
+// for ADLDisplayTarget.iDisplayTargetMask and ADLDisplayTarget.iDisplayTargetValue
+// (bit-vector)
+///////////////////////////////////////////////////////////////////////////
+#define ADL_DISPLAY_DISPLAYTARGET_PREFERRED 0x00000001
+
+///////////////////////////////////////////////////////////////////////////
+// ADL_DISPLAY_POSSIBLEMAPRESULT_VALID Definitions
+// for ADLPossibleMapResult.iPossibleMapResultMask and ADLPossibleMapResult.iPossibleMapResultValue
+// (bit-vector)
+///////////////////////////////////////////////////////////////////////////
+#define ADL_DISPLAY_POSSIBLEMAPRESULT_VALID 0x00000001
+#define ADL_DISPLAY_POSSIBLEMAPRESULT_BEZELSUPPORTED 0x00000002
+#define ADL_DISPLAY_POSSIBLEMAPRESULT_OVERLAPSUPPORTED 0x00000004
+
+///////////////////////////////////////////////////////////////////////////
+// ADL_DISPLAY_MODE_ Definitions
+// for ADLMode.iModeMask, ADLMode.iModeValue, and ADLMode.iModeFlag
+// (bit-vector)
+///////////////////////////////////////////////////////////////////////////
+/// \defgroup define_displaymode Display Mode Values
+// @{
+#define ADL_DISPLAY_MODE_COLOURFORMAT_565 0x00000001
+#define ADL_DISPLAY_MODE_COLOURFORMAT_8888 0x00000002
+#define ADL_DISPLAY_MODE_ORIENTATION_SUPPORTED_000 0x00000004
+#define ADL_DISPLAY_MODE_ORIENTATION_SUPPORTED_090 0x00000008
+#define ADL_DISPLAY_MODE_ORIENTATION_SUPPORTED_180 0x00000010
+#define ADL_DISPLAY_MODE_ORIENTATION_SUPPORTED_270 0x00000020
+#define ADL_DISPLAY_MODE_REFRESHRATE_ROUNDED 0x00000040
+#define ADL_DISPLAY_MODE_REFRESHRATE_ONLY 0x00000080
+
+#define ADL_DISPLAY_MODE_PROGRESSIVE_FLAG 0
+#define ADL_DISPLAY_MODE_INTERLACED_FLAG 2
+// @}
+
+///////////////////////////////////////////////////////////////////////////
+// ADL_OSMODEINFO Definitions
+///////////////////////////////////////////////////////////////////////////
+/// \defgroup define_osmode OS Mode Values
+// @{
+#define ADL_OSMODEINFOXPOS_DEFAULT -640
+#define ADL_OSMODEINFOYPOS_DEFAULT 0
+#define ADL_OSMODEINFOXRES_DEFAULT 640
+#define ADL_OSMODEINFOYRES_DEFAULT 480
+#define ADL_OSMODEINFOXRES_DEFAULT800 800
+#define ADL_OSMODEINFOYRES_DEFAULT600 600
+#define ADL_OSMODEINFOREFRESHRATE_DEFAULT 60
+#define ADL_OSMODEINFOCOLOURDEPTH_DEFAULT 8
+#define ADL_OSMODEINFOCOLOURDEPTH_DEFAULT16 16
+#define ADL_OSMODEINFOCOLOURDEPTH_DEFAULT24 24
+#define ADL_OSMODEINFOCOLOURDEPTH_DEFAULT32 32
+#define ADL_OSMODEINFOORIENTATION_DEFAULT 0
+#define ADL_OSMODEINFOORIENTATION_DEFAULT_WIN7 DISPLAYCONFIG_ROTATION_FORCE_UINT32
+#define ADL_OSMODEFLAG_DEFAULT 0
+// @}
+
+
+///////////////////////////////////////////////////////////////////////////
+// ADLPurposeCode Enumeration
+///////////////////////////////////////////////////////////////////////////
+enum ADLPurposeCode
+{
+ ADL_PURPOSECODE_NORMAL = 0,
+ ADL_PURPOSECODE_HIDE_MODE_SWITCH,
+ ADL_PURPOSECODE_MODE_SWITCH,
+ ADL_PURPOSECODE_ATTATCH_DEVICE,
+ ADL_PURPOSECODE_DETACH_DEVICE,
+ ADL_PURPOSECODE_SETPRIMARY_DEVICE,
+ ADL_PURPOSECODE_GDI_ROTATION,
+ ADL_PURPOSECODE_ATI_ROTATION,
+};
+///////////////////////////////////////////////////////////////////////////
+// ADLAngle Enumeration
+///////////////////////////////////////////////////////////////////////////
+enum ADLAngle
+{
+ ADL_ANGLE_LANDSCAPE = 0,
+ ADL_ANGLE_ROTATERIGHT = 90,
+ ADL_ANGLE_ROTATE180 = 180,
+ ADL_ANGLE_ROTATELEFT = 270,
+};
+
+///////////////////////////////////////////////////////////////////////////
+// ADLOrientationDataType Enumeration
+///////////////////////////////////////////////////////////////////////////
+enum ADLOrientationDataType
+{
+ ADL_ORIENTATIONTYPE_OSDATATYPE,
+ ADL_ORIENTATIONTYPE_NONOSDATATYPE
+};
+
+///////////////////////////////////////////////////////////////////////////
+// ADLPanningMode Enumeration
+///////////////////////////////////////////////////////////////////////////
+enum ADLPanningMode
+{
+ ADL_PANNINGMODE_NO_PANNING = 0,
+ ADL_PANNINGMODE_AT_LEAST_ONE_NO_PANNING = 1,
+ ADL_PANNINGMODE_ALLOW_PANNING = 2,
+};
+
+///////////////////////////////////////////////////////////////////////////
+// ADLLARGEDESKTOPTYPE Enumeration
+///////////////////////////////////////////////////////////////////////////
+enum ADLLARGEDESKTOPTYPE
+{
+ ADL_LARGEDESKTOPTYPE_NORMALDESKTOP = 0,
+ ADL_LARGEDESKTOPTYPE_PSEUDOLARGEDESKTOP = 1,
+ ADL_LARGEDESKTOPTYPE_VERYLARGEDESKTOP = 2,
+};
+
+// Other Definitions for internal use
+
+// Values for ADL_Display_WriteAndReadI2CRev_Get()
+
+#define ADL_I2C_MAJOR_API_REV 0x00000001
+#define ADL_I2C_MINOR_DEFAULT_API_REV 0x00000000
+#define ADL_I2C_MINOR_OEM_API_REV 0x00000001
+
+// Values for ADL_Display_WriteAndReadI2C()
+#define ADL_DL_I2C_LINE_OEM 0x00000001
+#define ADL_DL_I2C_LINE_OD_CONTROL 0x00000002
+#define ADL_DL_I2C_LINE_OEM2 0x00000003
+#define ADL_DL_I2C_LINE_OEM3 0x00000004
+#define ADL_DL_I2C_LINE_OEM4 0x00000005
+#define ADL_DL_I2C_LINE_OEM5 0x00000006
+#define ADL_DL_I2C_LINE_OEM6 0x00000007
+
+// Max size of I2C data buffer
+#define ADL_DL_I2C_MAXDATASIZE 0x00000040
+#define ADL_DL_I2C_MAXWRITEDATASIZE 0x0000000C
+#define ADL_DL_I2C_MAXADDRESSLENGTH 0x00000006
+#define ADL_DL_I2C_MAXOFFSETLENGTH 0x00000004
+
+
+/// Values for ADLDisplayProperty.iPropertyType
+#define ADL_DL_DISPLAYPROPERTY_TYPE_UNKNOWN 0
+#define ADL_DL_DISPLAYPROPERTY_TYPE_EXPANSIONMODE 1
+#define ADL_DL_DISPLAYPROPERTY_TYPE_USEUNDERSCANSCALING 2
+/// Enables ITC processing for HDMI panels that are capable of the feature
+#define ADL_DL_DISPLAYPROPERTY_TYPE_ITCFLAGENABLE 9
+
+
+/// Values for ADLDisplayContent.iContentType
+/// Certain HDMI panels that support ITC have support for a feature such that, the display on the panel
+/// can be adjusted to optimize the view of the content being displayed, depending on the type of content.
+#define ADL_DL_DISPLAYCONTENT_TYPE_GRAPHICS 1
+#define ADL_DL_DISPLAYCONTENT_TYPE_PHOTO 2
+#define ADL_DL_DISPLAYCONTENT_TYPE_CINEMA 4
+#define ADL_DL_DISPLAYCONTENT_TYPE_GAME 8
+
+
+
+
+
+//values for ADLDisplayProperty.iExpansionMode
+#define ADL_DL_DISPLAYPROPERTY_EXPANSIONMODE_CENTER 0
+#define ADL_DL_DISPLAYPROPERTY_EXPANSIONMODE_FULLSCREEN 1
+#define ADL_DL_DISPLAYPROPERTY_EXPANSIONMODE_ASPECTRATIO 2
+
+//values for ADL_Display_DitherState_Get
+#define ADL_DL_DISPLAY_DITHER_UNKNOWN 0
+#define ADL_DL_DISPLAY_DITHER_DISABLED 1
+#define ADL_DL_DISPLAY_DITHER_ENABLED 2
+
+/// Display Get Cached EDID flag
+#define ADL_MAX_EDIDDATA_SIZE 256 // number of UCHAR
+#define ADL_MAX_OVERRIDEEDID_SIZE 512 // number of UCHAR
+#define ADL_MAX_EDID_EXTENSION_BLOCKS 3
+
+#define ADL_DL_CONTROLLER_OVERLAY_ALPHA 0
+#define ADL_DL_CONTROLLER_OVERLAY_ALPHAPERPIX 1
+
+#define ADL_DL_DISPLAY_DATA_PACKET__INFO_PACKET_RESET 0x00000000
+#define ADL_DL_DISPLAY_DATA_PACKET__INFO_PACKET_SET 0x00000001
+#define ADL_DL_DISPLAY_DATA_PACKET__INFO_PACKET_SCAN 0x00000002
+
+///\defgroup define_display_packet Display Data Packet Types
+// @{
+#define ADL_DL_DISPLAY_DATA_PACKET__TYPE__AVI 0x00000001
+#define ADL_DL_DISPLAY_DATA_PACKET__TYPE__RESERVED 0x00000002
+#define ADL_DL_DISPLAY_DATA_PACKET__TYPE__VENDORINFO 0x00000004
+// @}
+
+// matrix types
+#define ADL_GAMUT_MATRIX_SD 1 // SD matrix i.e. BT601
+#define ADL_GAMUT_MATRIX_HD 2 // HD matrix i.e. BT709
+
+///\defgroup define_clockinfo_flags Clock flags
+/// Used by ADLAdapterODClockInfo.iFlag
+// @{
+#define ADL_DL_CLOCKINFO_FLAG_FULLSCREEN3DONLY 0x00000001
+#define ADL_DL_CLOCKINFO_FLAG_ALWAYSFULLSCREEN3D 0x00000002
+#define ADL_DL_CLOCKINFO_FLAG_VPURECOVERYREDUCED 0x00000004
+#define ADL_DL_CLOCKINFO_FLAG_THERMALPROTECTION 0x00000008
+// @}
+
+// Supported GPUs
+// ADL_Display_PowerXpressActiveGPU_Get()
+#define ADL_DL_POWERXPRESS_GPU_INTEGRATED 1
+#define ADL_DL_POWERXPRESS_GPU_DISCRETE 2
+
+// Possible values for lpOperationResult
+// ADL_Display_PowerXpressActiveGPU_Get()
+#define ADL_DL_POWERXPRESS_SWITCH_RESULT_STARTED 1 // Switch procedure has been started - Windows platform only
+#define ADL_DL_POWERXPRESS_SWITCH_RESULT_DECLINED 2 // Switch procedure cannot be started - All platforms
+#define ADL_DL_POWERXPRESS_SWITCH_RESULT_ALREADY 3 // System already has required status - All platforms
+#define ADL_DL_POWERXPRESS_SWITCH_RESULT_DEFERRED 5 // Switch was deferred and requires an X restart - Linux platform only
+
+// PowerXpress support version
+// ADL_Display_PowerXpressVersion_Get()
+#define ADL_DL_POWERXPRESS_VERSION_MAJOR 2 // Current PowerXpress support version 2.0
+#define ADL_DL_POWERXPRESS_VERSION_MINOR 0
+
+#define ADL_DL_POWERXPRESS_VERSION (((ADL_DL_POWERXPRESS_VERSION_MAJOR) << 16) | ADL_DL_POWERXPRESS_VERSION_MINOR)
+
+//values for ADLThermalControllerInfo.iThermalControllerDomain
+#define ADL_DL_THERMAL_DOMAIN_OTHER 0
+#define ADL_DL_THERMAL_DOMAIN_GPU 1
+
+//values for ADLThermalControllerInfo.iFlags
+#define ADL_DL_THERMAL_FLAG_INTERRUPT 1
+#define ADL_DL_THERMAL_FLAG_FANCONTROL 2
+
+///\defgroup define_fanctrl Fan speed control
+/// Values for ADLFanSpeedInfo.iFlags
+// @{
+#define ADL_DL_FANCTRL_SUPPORTS_PERCENT_READ 1
+#define ADL_DL_FANCTRL_SUPPORTS_PERCENT_WRITE 2
+#define ADL_DL_FANCTRL_SUPPORTS_RPM_READ 4
+#define ADL_DL_FANCTRL_SUPPORTS_RPM_WRITE 8
+// @}
+
+//values for ADLFanSpeedValue.iSpeedType
+#define ADL_DL_FANCTRL_SPEED_TYPE_PERCENT 1
+#define ADL_DL_FANCTRL_SPEED_TYPE_RPM 2
+
+//values for ADLFanSpeedValue.iFlags
+#define ADL_DL_FANCTRL_FLAG_USER_DEFINED_SPEED 1
+
+// MVPU interfaces
+#define ADL_DL_MAX_MVPU_ADAPTERS 4
+#define MVPU_ADAPTER_0 0x00000001
+#define MVPU_ADAPTER_1 0x00000002
+#define MVPU_ADAPTER_2 0x00000004
+#define MVPU_ADAPTER_3 0x00000008
+#define ADL_DL_MAX_REGISTRY_PATH 256
+
+//values for ADLMVPUStatus.iStatus
+#define ADL_DL_MVPU_STATUS_OFF 0
+#define ADL_DL_MVPU_STATUS_ON 1
+
+// values for ASIC family
+///\defgroup define_Asic_type Detailed asic types
+/// Defines for Adapter ASIC family type
+// @{
+#define ADL_ASIC_UNDEFINED 0
+#define ADL_ASIC_DISCRETE (1 << 0)
+#define ADL_ASIC_INTEGRATED (1 << 1)
+#define ADL_ASIC_FIREGL (1 << 2)
+#define ADL_ASIC_FIREMV (1 << 3)
+#define ADL_ASIC_XGP (1 << 4)
+#define ADL_ASIC_FUSION (1 << 5)
+#define ADL_ASIC_FIRESTREAM (1 << 6)
+// @}
+
+///\defgroup define_detailed_timing_flags Detailed Timimg Flags
+/// Defines for ADLDetailedTiming.sTimingFlags field
+// @{
+#define ADL_DL_TIMINGFLAG_DOUBLE_SCAN 0x0001
+#define ADL_DL_TIMINGFLAG_INTERLACED 0x0002
+#define ADL_DL_TIMINGFLAG_H_SYNC_POLARITY 0x0004
+#define ADL_DL_TIMINGFLAG_V_SYNC_POLARITY 0x0008
+// @}
+
+///\defgroup define_modetiming_standard Timing Standards
+/// Defines for ADLDisplayModeInfo.iTimingStandard field
+// @{
+#define ADL_DL_MODETIMING_STANDARD_CVT 0x00000001 // CVT Standard
+#define ADL_DL_MODETIMING_STANDARD_GTF 0x00000002 // GFT Standard
+#define ADL_DL_MODETIMING_STANDARD_DMT 0x00000004 // DMT Standard
+#define ADL_DL_MODETIMING_STANDARD_CUSTOM 0x00000008 // User-defined standard
+#define ADL_DL_MODETIMING_STANDARD_DRIVER_DEFAULT 0x00000010 // Remove Mode from overriden list
+// @}
+
+// \defgroup define_xserverinfo driver x-server info
+/// These flags are used by ADL_XServerInfo_Get()
+// @
+
+/// Xinerama is active in the x-server, Xinerama extension may report it to be active but it
+/// may not be active in x-server
+#define ADL_XSERVERINFO_XINERAMAACTIVE (1<<0)
+
+/// RandR 1.2 is supported by driver, RandR extension may report version 1.2
+/// but driver may not support it
+#define ADL_XSERVERINFO_RANDR12SUPPORTED (1<<1)
+// @
+
+
+///\defgroup define_eyefinity_constants Eyefinity Definitions
+// @{
+
+#define ADL_CONTROLLERVECTOR_0 1 // ADL_CONTROLLERINDEX_0 = 0, (1 << ADL_CONTROLLERINDEX_0)
+#define ADL_CONTROLLERVECTOR_1 2 // ADL_CONTROLLERINDEX_1 = 1, (1 << ADL_CONTROLLERINDEX_1)
+
+#define ADL_DISPLAY_SLSGRID_ORIENTATION_000 0x00000001
+#define ADL_DISPLAY_SLSGRID_ORIENTATION_090 0x00000002
+#define ADL_DISPLAY_SLSGRID_ORIENTATION_180 0x00000004
+#define ADL_DISPLAY_SLSGRID_ORIENTATION_270 0x00000008
+#define ADL_DISPLAY_SLSGRID_CAP_OPTION_RELATIVETO_LANDSCAPE 0x00000001
+#define ADL_DISPLAY_SLSGRID_CAP_OPTION_RELATIVETO_CURRENTANGLE 0x00000002
+#define ADL_DISPLAY_SLSGRID_PORTAIT_MODE 0x00000004
+
+
+#define ADL_DISPLAY_SLSMAPCONFIG_GET_OPTION_RELATIVETO_LANDSCAPE 0x00000001
+#define ADL_DISPLAY_SLSMAPCONFIG_GET_OPTION_RELATIVETO_CURRENTANGLE 0x00000002
+
+#define ADL_DISPLAY_SLSMAPCONFIG_CREATE_OPTION_RELATIVETO_LANDSCAPE 0x00000001
+#define ADL_DISPLAY_SLSMAPCONFIG_CREATE_OPTION_RELATIVETO_CURRENTANGLE 0x00000002
+
+#define ADL_DISPLAY_SLSMAPCONFIG_REARRANGE_OPTION_RELATIVETO_LANDSCAPE 0x00000001
+#define ADL_DISPLAY_SLSMAPCONFIG_REARRANGE_OPTION_RELATIVETO_CURRENTANGLE 0x00000002
+
+
+#define ADL_DISPLAY_SLSGRID_RELATIVETO_LANDSCAPE 0x00000010
+#define ADL_DISPLAY_SLSGRID_RELATIVETO_CURRENTANGLE 0x00000020
+
+
+/// The bit mask identifies displays is currently in bezel mode.
+#define ADL_DISPLAY_SLSMAP_BEZELMODE 0x00000010
+/// The bit mask identifies displays from this map is arranged.
+#define ADL_DISPLAY_SLSMAP_DISPLAYARRANGED 0x00000002
+/// The bit mask identifies this map is currently in used for the current adapter.
+#define ADL_DISPLAY_SLSMAP_CURRENTCONFIG 0x00000004
+
+ ///For onlay active SLS map info
+#define ADL_DISPLAY_SLSMAPINDEXLIST_OPTION_ACTIVE 0x00000001
+
+///For Bezel
+#define ADL_DISPLAY_BEZELOFFSET_STEPBYSTEPSET 0x00000004
+#define ADL_DISPLAY_BEZELOFFSET_COMMIT 0x00000008
+
+// @}
+
+///\defgroup define_powerxpress_constants PowerXpress Definitions
+// @{
+
+/// The bit mask identifies PX caps for ADLPXConfigCaps.iPXConfigCapMask and ADLPXConfigCaps.iPXConfigCapValue
+#define ADL_PX_CONFIGCAPS_SPLASHSCREEN_SUPPORT 0x0001
+#define ADL_PX_CONFIGCAPS_CF_SUPPORT 0x0002
+#define ADL_PX_CONFIGCAPS_MUXLESS 0x0004
+#define ADL_PX_CONFIGCAPS_PROFILE_COMPLIANT 0x0008
+#define ADL_PX_CONFIGCAPS_NON_AMD_DRIVEN_DISPLAYS 0x0010
+#define ADL_PX_CONFIGCAPS_FIXED_SUPPORT 0x0020
+#define ADL_PX_CONFIGCAPS_DYNAMIC_SUPPORT 0x0040
+#define ADL_PX_CONFIGCAPS_HIDE_AUTO_SWITCH 0x0080
+
+/// The bit mask identifies PX schemes for ADLPXSchemeRange
+#define ADL_PX_SCHEMEMASK_FIXED 0x0001
+#define ADL_PX_SCHEMEMASK_DYNAMIC 0x0002
+
+/// PX Schemes
+typedef enum _ADLPXScheme
+{
+ ADL_PX_SCHEME_INVALID = 0,
+ ADL_PX_SCHEME_FIXED = ADL_PX_SCHEMEMASK_FIXED,
+ ADL_PX_SCHEME_DYNAMIC = ADL_PX_SCHEMEMASK_DYNAMIC,
+}ADLPXScheme;
+
+/// Just keep the old definitions for compatibility, need to be removed later
+typedef enum PXScheme
+{
+ PX_SCHEME_INVALID = 0,
+ PX_SCHEME_FIXED = 1,
+ PX_SCHEME_DYNAMIC = 2
+} PXScheme;
+
+
+// @}
+
+///\defgroup define_appprofiles For Application Profiles
+// @{
+
+#define ADL_APP_PROFILE_FILENAME_LENGTH 64
+#define ADL_APP_PROFILE_TIMESTAMP_LENGTH 32
+#define ADL_APP_PROFILE_VERSION_LENGTH 32
+#define ADL_APP_PROFILE_PROPERTY_LENGTH 64
+
+enum ApplicationListType
+{
+ ADL_PX40_MRU,
+ ADL_PX40_MISSED,
+ ADL_PX40_DISCRETE,
+ ADL_PX40_INTEGRATED,
+
+ ADL_PX40_TOTAL,
+};
+
+typedef enum _ADLProfilePropertyType
+{
+ ADL_PROFILEPROPERTY_TYPE_BINARY = 0,
+ ADL_PROFILEPROPERTY_TYPE_BOOLEAN,
+ ADL_PROFILEPROPERTY_TYPE_DWORD,
+ ADL_PROFILEPROPERTY_TYPE_QWORD,
+ ADL_PROFILEPROPERTY_TYPE_ENUMERATED,
+ ADL_PROFILEPROPERTY_TYPE_STRING,
+}ADLProfilePropertyType;
+
+// @}
+
+///\defgroup define_dp12 For Display Port 1.2
+// @{
+
+/// Maximum Relative Address Link
+#define ADL_MAX_RAD_LINK_COUNT 15
+
+// @}
+
+///\defgroup defines_gamutspace Driver Supported Gamut Space
+// @{
+
+/// The flags desribes that gamut is related to source or to destination and to overlay or to graphics
+#define ADL_GAMUT_REFERENCE_SOURCE (1 << 0)
+#define ADL_GAMUT_GAMUT_VIDEO_CONTENT (1 << 1)
+
+/// The flags are used to describe the source of gamut and how read information from struct ADLGamutData
+#define ADL_CUSTOM_WHITE_POINT (1 << 0)
+#define ADL_CUSTOM_GAMUT (1 << 1)
+
+/// The define means the predefined gamut values .
+///Driver uses to find entry in the table and apply appropriate gamut space.
+#define ADL_GAMUT_SPACE_CCIR_709 (1 << 0)
+#define ADL_GAMUT_SPACE_CCIR_601 (1 << 1)
+#define ADL_GAMUT_SPACE_ADOBE_RGB (1 << 2)
+#define ADL_GAMUT_SPACE_CIE_RGB (1 << 3)
+#define ADL_GAMUT_SPACE_CUSTOM (1 << 4)
+
+/// Predefine white point values are structed similar to gamut .
+#define ADL_WHITE_POINT_5000K (1 << 0)
+#define ADL_WHITE_POINT_6500K (1 << 1)
+#define ADL_WHITE_POINT_7500K (1 << 2)
+#define ADL_WHITE_POINT_9300K (1 << 3)
+#define ADL_WHITE_POINT_CUSTOM (1 << 4)
+
+///gamut and white point coordinates are from 0.0 -1.0 and divider is used to find the real value .
+/// X float = X int /divider
+#define ADL_GAMUT_WHITEPOINT_DIVIDER 10000
+
+///gamma a0 coefficient uses the following divider:
+#define ADL_REGAMMA_COEFFICIENT_A0_DIVIDER 10000000
+///gamma a1 ,a2,a3 coefficients use the following divider:
+#define ADL_REGAMMA_COEFFICIENT_A1A2A3_DIVIDER 1000
+
+///describes whether the coefficients are from EDID or custom user values.
+#define ADL_EDID_REGAMMA_COEFFICIENTS (1 << 0)
+///Used for struct ADLRegamma.Feature if set use gamma ramp , if missing use regamma coefficents
+#define ADL_USE_GAMMA_RAMP (1 << 4)
+
+// @}
+
+/// \defgroup define_ddcinfo_pixelformats DDCInfo Pixel Formats
+// @{
+/// defines for iPanelPixelFormat in struct ADLDDCInfo2
+#define ADL_DISPLAY_DDCINFO_PIXEL_FORMAT_RGB656 0x00000001L
+#define ADL_DISPLAY_DDCINFO_PIXEL_FORMAT_RGB666 0x00000002L
+#define ADL_DISPLAY_DDCINFO_PIXEL_FORMAT_RGB888 0x00000004L
+#define ADL_DISPLAY_DDCINFO_PIXEL_FORMAT_RGB101010 0x00000008L
+#define ADL_DISPLAY_DDCINFO_PIXEL_FORMAT_RGB161616 0x00000010L
+#define ADL_DISPLAY_DDCINFO_PIXEL_FORMAT_RGB_RESERVED1 0x00000020L
+#define ADL_DISPLAY_DDCINFO_PIXEL_FORMAT_RGB_RESERVED2 0x00000040L
+#define ADL_DISPLAY_DDCINFO_PIXEL_FORMAT_RGB_RESERVED3 0x00000080L
+#define ADL_DISPLAY_DDCINFO_PIXEL_FORMAT_XRGB_BIAS101010 0x00000100L
+#define ADL_DISPLAY_DDCINFO_PIXEL_FORMAT_YCBCR444_8BPCC 0x00000200L
+#define ADL_DISPLAY_DDCINFO_PIXEL_FORMAT_YCBCR444_10BPCC 0x00000400L
+#define ADL_DISPLAY_DDCINFO_PIXEL_FORMAT_YCBCR444_12BPCC 0x00000800L
+#define ADL_DISPLAY_DDCINFO_PIXEL_FORMAT_YCBCR422_8BPCC 0x00001000L
+#define ADL_DISPLAY_DDCINFO_PIXEL_FORMAT_YCBCR422_10BPCC 0x00002000L
+#define ADL_DISPLAY_DDCINFO_PIXEL_FORMAT_YCBCR422_12BPCC 0x00004000L
+// @}
+
+
+
+/// \defgroup define_dbd_state Deep Bit Depth
+// @{
+
+/// defines for ADL_Workstation_DeepBitDepth_Get and ADL_Workstation_DeepBitDepth_Set functions
+// This value indicates that the deep bit depth state is forced off
+#define ADL_DEEPBITDEPTH_FORCEOFF 0
+/// This value indicates that the deep bit depth state is set to auto, the driver will automatically enable the
+/// appropriate deep bit depth state depending on what connected display supports.
+#define ADL_DEEPBITDEPTH_10BPP_AUTO 1
+/// This value indicates that the deep bit depth state is forced on to 10 bits per pixel, this is regardless if the display
+/// supports 10 bpp.
+#define ADL_DEEPBITDEPTH_10BPP_FORCEON 2
+
+/// defines for ADLAdapterConfigMemory of ADL_Adapter_ConfigMemory_Get
+/// If this bit is set, it indicates that the Deep Bit Depth pixel is set on the display
+#define ADL_ADAPTER_CONFIGMEMORY_DBD (1 << 0)
+/// If this bit is set, it indicates that the display is rotated (90, 180 or 270)
+#define ADL_ADAPTER_CONFIGMEMORY_ROTATE (1 << 1)
+/// If this bit is set, it indicates that passive stereo is set on the display
+#define ADL_ADAPTER_CONFIGMEMORY_STEREO_PASSIVE (1 << 2)
+/// If this bit is set, it indicates that the active stereo is set on the display
+#define ADL_ADAPTER_CONFIGMEMORY_STEREO_ACTIVE (1 << 3)
+/// If this bit is set, it indicates that the tear free vsync is set on the display
+#define ADL_ADAPTER_CONFIGMEMORY_ENHANCEDVSYNC (1 << 4)
+#define ADL_ADAPTER_CONFIGMEMORY_TEARFREEVSYNC (1 << 4)
+/// @}
+
+/// \defgroup define_adl_validmemoryrequiredfields Memory Type
+/// @{
+
+/// This group defines memory types in ADLMemoryRequired struct \n
+/// Indicates that this is the visible memory
+#define ADL_MEMORYREQTYPE_VISIBLE (1 << 0)
+/// Indicates that this is the invisible memory.
+#define ADL_MEMORYREQTYPE_INVISIBLE (1 << 1)
+/// Indicates that this is amount of visible memory per GPU that should be reserved for all other allocations.
+#define ADL_MEMORYREQTYPE_GPURESERVEDVISIBLE (1 << 2)
+/// @}
+
+/// \defgroup define_adapter_tear_free_status
+/// Used in ADL_Adapter_TEAR_FREE_Set and ADL_Adapter_TFD_Get functions to indicate the tear free
+/// desktop status.
+/// @{
+/// Tear free desktop is enabled.
+#define ADL_ADAPTER_TEAR_FREE_ON 1
+/// Tear free desktop can't be enabled due to a lack of graphic adapter memory.
+#define ADL_ADAPTER_TEAR_FREE_NOTENOUGHMEM -1
+/// Tear free desktop can't be enabled due to quad buffer stereo being enabled.
+#define ADL_ADAPTER_TEAR_FREE_OFF_ERR_QUADBUFFERSTEREO -2
+/// Tear free desktop is disabled.
+#define ADL_ADAPTER_TEAR_FREE_OFF 0
+/// @}
+
+/// \defgroup define_adapter_crossdisplay_platforminfo
+/// Used in ADL_Adapter_CrossDisplayPlatformInfo_Get function to indicate the Crossdisplay platform info.
+/// @{
+/// CROSSDISPLAY platform.
+#define ADL_CROSSDISPLAY_PLATFORM (1 << 0)
+/// CROSSDISPLAY platform for Lasso station.
+#define ADL_CROSSDISPLAY_PLATFORM_LASSO (1 << 1)
+/// CROSSDISPLAY platform for docking station.
+#define ADL_CROSSDISPLAY_PLATFORM_DOCKSTATION (1 << 2)
+/// @}
+
+/// \defgroup define_adapter_crossdisplay_option
+/// Used in ADL_Adapter_CrossdisplayInfoX2_Set function to indicate cross display options.
+/// @{
+/// Checking if 3D application is running. If yes, don't switch, return ADL_OK_WAIT; otherwise do switch.
+#define ADL_CROSSDISPLAY_OPTION_NONE 0
+/// Force switching without checking for running 3D applications
+#define ADL_CROSSDISPLAY_OPTION_FORCESWITCH (1 << 0)
+/// @}
+
+/// \defgroup define_adapter_states Adapter Capabilities
+/// These defines the capabilities supported by an adapter. It is used by \ref ADL_Adapter_ConfigureState_Get
+/// @{
+/// Indicates that the adapter is headless (i.e. no displays can be connected to it)
+#define ADL_ADAPTERCONFIGSTATE_HEADLESS ( 1 << 2 )
+/// Indicates that the adapter is configured to define the main rendering capabilities. For example, adapters
+/// in Crossfire(TM) configuration, this bit would only be set on the adapter driving the display(s).
+#define ADL_ADAPTERCONFIGSTATE_REQUISITE_RENDER ( 1 << 0 )
+/// Indicates that the adapter is configured to be used to unload some of the rendering work for a particular
+/// requisite rendering adapter. For eample, for adapters in a Crossfire configuration, this bit would be set
+/// on all adapters that are currently not driving the display(s)
+#define ADL_ADAPTERCONFIGSTATE_ANCILLARY_RENDER ( 1 << 1 )
+/// @}
+
+/// \defgroup define_controllermode_ulModifiers
+/// These defines the detailed actions supported by set viewport. It is used by \ref ADL_Display_ViewPort_Set
+/// @{
+/// Indicate that the viewport set will change the view position
+#define ADL_CONTROLLERMODE_CM_MODIFIER_VIEW_POSITION 0x00000001
+/// Indicate that the viewport set will change the view PanLock
+#define ADL_CONTROLLERMODE_CM_MODIFIER_VIEW_PANLOCK 0x00000002
+/// Indicate that the viewport set will change the view size
+#define ADL_CONTROLLERMODE_CM_MODIFIER_VIEW_SIZE 0x00000008
+/// @}
+
+
+// End Bracket for Constants and Definitions. Add new groups ABOVE this line!
+
+// @}
+#endif /* ADL_DEFINES_H_ */
+
+
--- /dev/null
+///
+/// Copyright (c) 2008 - 2009 Advanced Micro Devices, Inc.
+
+/// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
+/// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+/// WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
+
+/// \file adl_sdk.h
+/// \brief Contains the definition of the Memory Allocation Callback.\n <b>Included in ADL SDK</b>
+///
+/// \n\n
+/// This file contains the definition of the Memory Allocation Callback.\n
+/// It also includes definitions of the respective structures and constants.\n
+/// <b> This is the only header file to be included in a C/C++ project using ADL </b>
+
+#ifndef ADL_SDK_H_
+#define ADL_SDK_H_
+
+#include "adl_structures.h"
+
+#if !defined(__WINDOWS__)
+#define __stdcall
+#endif /* (LINUX) */
+
+/// Memory Allocation Call back
+typedef void* ( __stdcall *ADL_MAIN_MALLOC_CALLBACK )( int );
+
+
+#endif /* ADL_SDK_H_ */
--- /dev/null
+///
+/// Copyright (c) 2008 - 2012 Advanced Micro Devices, Inc.
+
+/// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
+/// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+/// WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
+
+/// \file adl_structures.h
+///\brief This file contains the structure declarations that are used by the public ADL interfaces for \ALL platforms.\n <b>Included in ADL SDK</b>
+///
+/// All data structures used in AMD Display Library (ADL) public interfaces should be defined in this header file.
+///
+
+#ifndef ADL_STRUCTURES_H_
+#define ADL_STRUCTURES_H_
+
+#include "adl_defines.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing information about the graphics adapter.
+///
+/// This structure is used to store various information about the graphics adapter. This
+/// information can be returned to the user. Alternatively, it can be used to access various driver calls to set
+/// or fetch various settings upon the user's request.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct AdapterInfo
+{
+/// \ALL_STRUCT_MEM
+
+/// Size of the structure.
+ int iSize;
+/// The ADL index handle. One GPU may be associated with one or two index handles
+ int iAdapterIndex;
+/// The unique device ID associated with this adapter.
+ char strUDID[ADL_MAX_PATH];
+/// The BUS number associated with this adapter.
+ int iBusNumber;
+/// The driver number associated with this adapter.
+ int iDeviceNumber;
+/// The function number.
+ int iFunctionNumber;
+/// The vendor ID associated with this adapter.
+ int iVendorID;
+/// Adapter name.
+ char strAdapterName[ADL_MAX_PATH];
+/// Display name. For example, "\\Display0" for Windows or ":0:0" for Linux.
+ char strDisplayName[ADL_MAX_PATH];
+/// Present or not; 1 if present and 0 if not present.It the logical adapter is present, the display name such as \\.\Display1 can be found from OS
+ int iPresent;
+// @}
+
+#if defined (_WIN32) || defined (_WIN64)
+/// \WIN_STRUCT_MEM
+
+/// Exist or not; 1 is exist and 0 is not present.
+ int iExist;
+/// Driver registry path.
+ char strDriverPath[ADL_MAX_PATH];
+/// Driver registry path Ext for.
+ char strDriverPathExt[ADL_MAX_PATH];
+/// PNP string from Windows.
+ char strPNPString[ADL_MAX_PATH];
+/// It is generated from EnumDisplayDevices.
+ int iOSDisplayIndex;
+// @}
+#endif /* (_WIN32) || (_WIN64) */
+
+#if defined (LINUX)
+/// \LNX_STRUCT_MEM
+
+/// Internal X screen number from GPUMapInfo (DEPRICATED use XScreenInfo)
+ int iXScreenNum;
+/// Internal driver index from GPUMapInfo
+ int iDrvIndex;
+/// \deprecated Internal x config file screen identifier name. Use XScreenInfo instead.
+ char strXScreenConfigName[ADL_MAX_PATH];
+
+// @}
+#endif /* (LINUX) */
+} AdapterInfo, *LPAdapterInfo;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing information about the Linux X screen information.
+///
+/// This structure is used to store the current screen number and xorg.conf ID name associated with an adapter index.
+/// This structure is updated during ADL_Main_Control_Refresh or ADL_ScreenInfo_Update.
+/// Note: This structure should be used in place of iXScreenNum and strXScreenConfigName in AdapterInfo as they will be
+/// deprecated.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+#if defined (LINUX)
+typedef struct XScreenInfo
+{
+/// Internal X screen number from GPUMapInfo.
+ int iXScreenNum;
+/// Internal x config file screen identifier name.
+ char strXScreenConfigName[ADL_MAX_PATH];
+} XScreenInfo, *LPXScreenInfo;
+#endif /* (LINUX) */
+
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing information about the ASIC memory.
+///
+/// This structure is used to store various information about the ASIC memory. This
+/// information can be returned to the user.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLMemoryInfo
+{
+/// Memory size in bytes.
+ long long iMemorySize;
+/// Memory type in string.
+ char strMemoryType[ADL_MAX_PATH];
+/// Memory bandwidth in Mbytes/s.
+ long long iMemoryBandwidth;
+} ADLMemoryInfo, *LPADLMemoryInfo;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing information about memory required by type
+///
+/// This structure is returned by ADL_Adapter_ConfigMemory_Get, which given a desktop and display configuration
+/// will return the Memory used.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLMemoryRequired
+{
+ long long iMemoryReq; /// Memory in bytes required
+ int iType; /// Type of Memory \ref define_adl_validmemoryrequiredfields
+ int iDisplayFeatureValue; /// Display features \ref define_adl_visiblememoryfeatures that are using this type of memory
+} ADLMemoryRequired, *LPADLMemoryRequired;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing information about the features associated with a display
+///
+/// This structure is a parameter to ADL_Adapter_ConfigMemory_Get, which given a desktop and display configuration
+/// will return the Memory used.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLMemoryDisplayFeatures
+{
+ int iDisplayIndex; /// ADL Display index
+ int iDisplayFeatureValue; /// features that the display is using \ref define_adl_visiblememoryfeatures
+} ADLMemoryDisplayFeatures, *LPADLMemoryDisplayFeatures;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing DDC information.
+///
+/// This structure is used to store various DDC information that can be returned to the user.
+/// Note that all fields of type int are actually defined as unsigned int types within the driver.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLDDCInfo
+{
+/// Size of the structure
+ int ulSize;
+/// Indicates whether the attached display supports DDC. If this field is zero on return, no other DDC information fields will be used.
+ int ulSupportsDDC;
+/// Returns the manufacturer ID of the display device. Should be zeroed if this information is not available.
+ int ulManufacturerID;
+/// Returns the product ID of the display device. Should be zeroed if this information is not available.
+ int ulProductID;
+/// Returns the name of the display device. Should be zeroed if this information is not available.
+ char cDisplayName[ADL_MAX_DISPLAY_NAME];
+/// Returns the maximum Horizontal supported resolution. Should be zeroed if this information is not available.
+ int ulMaxHResolution;
+/// Returns the maximum Vertical supported resolution. Should be zeroed if this information is not available.
+ int ulMaxVResolution;
+/// Returns the maximum supported refresh rate. Should be zeroed if this information is not available.
+ int ulMaxRefresh;
+/// Returns the display device preferred timing mode's horizontal resolution.
+ int ulPTMCx;
+/// Returns the display device preferred timing mode's vertical resolution.
+ int ulPTMCy;
+/// Returns the display device preferred timing mode's refresh rate.
+ int ulPTMRefreshRate;
+/// Return EDID flags.
+ int ulDDCInfoFlag;
+} ADLDDCInfo, *LPADLDDCInfo;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing DDC information.
+///
+/// This structure is used to store various DDC information that can be returned to the user.
+/// Note that all fields of type int are actually defined as unsigned int types within the driver.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLDDCInfo2
+{
+/// Size of the structure
+ int ulSize;
+/// Indicates whether the attached display supports DDC. If this field is zero on return, no other DDC
+/// information fields will be used.
+ int ulSupportsDDC;
+/// Returns the manufacturer ID of the display device. Should be zeroed if this information is not available.
+ int ulManufacturerID;
+/// Returns the product ID of the display device. Should be zeroed if this information is not available.
+ int ulProductID;
+/// Returns the name of the display device. Should be zeroed if this information is not available.
+ char cDisplayName[ADL_MAX_DISPLAY_NAME];
+/// Returns the maximum Horizontal supported resolution. Should be zeroed if this information is not available.
+ int ulMaxHResolution;
+/// Returns the maximum Vertical supported resolution. Should be zeroed if this information is not available.
+ int ulMaxVResolution;
+/// Returns the maximum supported refresh rate. Should be zeroed if this information is not available.
+ int ulMaxRefresh;
+/// Returns the display device preferred timing mode's horizontal resolution.
+ int ulPTMCx;
+/// Returns the display device preferred timing mode's vertical resolution.
+ int ulPTMCy;
+/// Returns the display device preferred timing mode's refresh rate.
+ int ulPTMRefreshRate;
+/// Return EDID flags.
+ int ulDDCInfoFlag;
+// Returns 1 if the display supported packed pixel, 0 otherwise
+ int bPackedPixelSupported;
+// Returns the Pixel formats the display supports \ref define_ddcinfo_pixelformats
+ int iPanelPixelFormat;
+/// Return EDID serial ID.
+ int ulSerialID;
+// Reserved for future use
+ int iReserved[26];
+} ADLDDCInfo2, *LPADLDDCInfo2;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing information controller Gamma settings.
+///
+/// This structure is used to store the red, green and blue color channel information for the.
+/// controller gamma setting. This information is returned by ADL, and it can also be used to
+/// set the controller gamma setting.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLGamma
+{
+/// Red color channel gamma value.
+ float fRed;
+/// Green color channel gamma value.
+ float fGreen;
+/// Blue color channel gamma value.
+ float fBlue;
+} ADLGamma, *LPADLGamma;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing information about component video custom modes.
+///
+/// This structure is used to store the component video custom mode.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLCustomMode
+{
+/// Custom mode flags. They are returned by the ADL driver.
+ int iFlags;
+/// Custom mode width.
+ int iModeWidth;
+/// Custom mode height.
+ int iModeHeight;
+/// Custom mode base width.
+ int iBaseModeWidth;
+/// Custom mode base height.
+ int iBaseModeHeight;
+/// Custom mode refresh rate.
+ int iRefreshRate;
+} ADLCustomMode, *LPADLCustomMode;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing Clock information for OD5 calls.
+///
+/// This structure is used to retrieve clock information for OD5 calls.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLGetClocksOUT
+{
+ long ulHighCoreClock;
+ long ulHighMemoryClock;
+ long ulHighVddc;
+ long ulCoreMin;
+ long ulCoreMax;
+ long ulMemoryMin;
+ long ulMemoryMax;
+ long ulActivityPercent;
+ long ulCurrentCoreClock;
+ long ulCurrentMemoryClock;
+ long ulReserved;
+} ADLGetClocksOUT;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing HDTV information for display calls.
+///
+/// This structure is used to retrieve HDTV information information for display calls.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLDisplayConfig
+{
+/// Size of the structure
+ long ulSize;
+/// HDTV connector type.
+ long ulConnectorType;
+/// HDTV capabilities.
+ long ulDeviceData;
+/// Overridden HDTV capabilities.
+ long ulOverridedDeviceData;
+/// Reserved field
+ long ulReserved;
+} ADLDisplayConfig;
+
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing information about the display device.
+///
+/// This structure is used to store display device information
+/// such as display index, type, name, connection status, mapped adapter and controller indexes,
+/// whether or not multiple VPUs are supported, local display connections or not (through Lasso), etc.
+/// This information can be returned to the user. Alternatively, it can be used to access various driver calls to set
+/// or fetch various display device related settings upon the user's request.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLDisplayID
+{
+/// The logical display index belonging to this adapter.
+ int iDisplayLogicalIndex;
+
+///\brief The physical display index.
+/// For example, display index 2 from adapter 2 can be used by current adapter 1.\n
+/// So current adapter may enumerate this adapter as logical display 7 but the physical display
+/// index is still 2.
+ int iDisplayPhysicalIndex;
+
+/// The persistent logical adapter index for the display.
+ int iDisplayLogicalAdapterIndex;
+
+///\brief The persistent physical adapter index for the display.
+/// It can be the current adapter or a non-local adapter. \n
+/// If this adapter index is different than the current adapter,
+/// the Display Non Local flag is set inside DisplayInfoValue.
+ int iDisplayPhysicalAdapterIndex;
+} ADLDisplayID, *LPADLDisplayID;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing information about the display device.
+///
+/// This structure is used to store various information about the display device. This
+/// information can be returned to the user, or used to access various driver calls to set
+/// or fetch various display-device-related settings upon the user's request
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLDisplayInfo
+{
+/// The DisplayID structure
+ ADLDisplayID displayID;
+
+///\deprecated The controller index to which the display is mapped.\n Will not be used in the future\n
+ int iDisplayControllerIndex;
+
+/// The display's EDID name.
+ char strDisplayName[ADL_MAX_PATH];
+
+/// The display's manufacturer name.
+ char strDisplayManufacturerName[ADL_MAX_PATH];
+
+/// The Display type. For example: CRT, TV, CV, DFP.
+ int iDisplayType;
+
+/// The display output type. For example: HDMI, SVIDEO, COMPONMNET VIDEO.
+ int iDisplayOutputType;
+
+/// The connector type for the device.
+ int iDisplayConnector;
+
+///\brief The bit mask identifies the number of bits ADLDisplayInfo is currently using. \n
+/// It will be the sum all the bit definitions in ADL_DISPLAY_DISPLAYINFO_xxx.
+ int iDisplayInfoMask;
+
+/// The bit mask identifies the display status. \ref define_displayinfomask
+ int iDisplayInfoValue;
+} ADLDisplayInfo, *LPADLDisplayInfo;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing information about the display port MST device.
+///
+/// This structure is used to store various MST information about the display port device. This
+/// information can be returned to the user, or used to access various driver calls to
+/// fetch various display-device-related settings upon the user's request
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLDisplayDPMSTInfo
+{
+ /// The ADLDisplayID structure
+ ADLDisplayID displayID;
+
+ /// total bandwidth available on the DP connector
+ int iTotalAvailableBandwidthInMpbs;
+ /// bandwidth allocated to this display
+ int iAllocatedBandwidthInMbps;
+
+ // info from DAL DpMstSinkInfo
+ /// string identifier for the display
+ char strGlobalUniqueIdentifier[ADL_MAX_PATH];
+
+ /// The link count of relative address, rad[0] up to rad[linkCount] are valid
+ int radLinkCount;
+ /// The physical connector ID, used to identify the physical DP port
+ int iPhysicalConnectorID;
+
+ /// Relative address, address scheme starts from source side
+ char rad[ADL_MAX_RAD_LINK_COUNT];
+} ADLDisplayDPMSTInfo, *LPADLDisplayDPMSTInfo;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing the display mode definition used per controller.
+///
+/// This structure is used to store the display mode definition used per controller.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLDisplayMode
+{
+/// Vertical resolution (in pixels).
+ int iPelsHeight;
+/// Horizontal resolution (in pixels).
+ int iPelsWidth;
+/// Color depth.
+ int iBitsPerPel;
+/// Refresh rate.
+ int iDisplayFrequency;
+} ADLDisplayMode;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing detailed timing parameters.
+///
+/// This structure is used to store the detailed timing parameters.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLDetailedTiming
+{
+/// Size of the structure.
+ int iSize;
+/// Timing flags. \ref define_detailed_timing_flags
+ short sTimingFlags;
+/// Total width (columns).
+ short sHTotal;
+/// Displayed width.
+ short sHDisplay;
+/// Horizontal sync signal offset.
+ short sHSyncStart;
+/// Horizontal sync signal width.
+ short sHSyncWidth;
+/// Total height (rows).
+ short sVTotal;
+/// Displayed height.
+ short sVDisplay;
+/// Vertical sync signal offset.
+ short sVSyncStart;
+/// Vertical sync signal width.
+ short sVSyncWidth;
+/// Pixel clock value.
+ short sPixelClock;
+/// Overscan right.
+ short sHOverscanRight;
+/// Overscan left.
+ short sHOverscanLeft;
+/// Overscan bottom.
+ short sVOverscanBottom;
+/// Overscan top.
+ short sVOverscanTop;
+ short sOverscan8B;
+ short sOverscanGR;
+} ADLDetailedTiming;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing display mode information.
+///
+/// This structure is used to store the display mode information.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLDisplayModeInfo
+{
+/// Timing standard of the current mode. \ref define_modetiming_standard
+ int iTimingStandard;
+/// Applicable timing standards for the current mode.
+ int iPossibleStandard;
+/// Refresh rate factor.
+ int iRefreshRate;
+/// Num of pixels in a row.
+ int iPelsWidth;
+/// Num of pixels in a column.
+ int iPelsHeight;
+/// Detailed timing parameters.
+ ADLDetailedTiming sDetailedTiming;
+} ADLDisplayModeInfo;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+/// \brief Structure containing information about display property.
+///
+/// This structure is used to store the display property for the current adapter.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLDisplayProperty
+{
+/// Must be set to sizeof the structure
+ int iSize;
+/// Must be set to \ref ADL_DL_DISPLAYPROPERTY_TYPE_EXPANSIONMODE or \ref ADL_DL_DISPLAYPROPERTY_TYPE_USEUNDERSCANSCALING
+ int iPropertyType;
+/// Get or Set \ref ADL_DL_DISPLAYPROPERTY_EXPANSIONMODE_CENTER or \ref ADL_DL_DISPLAYPROPERTY_EXPANSIONMODE_FULLSCREEN or \ref ADL_DL_DISPLAYPROPERTY_EXPANSIONMODE_ASPECTRATIO or \ref ADL_DL_DISPLAYPROPERTY_TYPE_ITCFLAGENABLE
+ int iExpansionMode;
+/// Display Property supported? 1: Supported, 0: Not supported
+ int iSupport;
+/// Display Property current value
+ int iCurrent;
+/// Display Property Default value
+ int iDefault;
+} ADLDisplayProperty;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing information about Clock.
+///
+/// This structure is used to store the clock information for the current adapter
+/// such as core clock and memory clock info.
+///\nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLClockInfo
+{
+/// Core clock in 10 KHz.
+ int iCoreClock;
+/// Memory clock in 10 KHz.
+ int iMemoryClock;
+} ADLClockInfo, *LPADLClockInfo;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing information about I2C.
+///
+/// This structure is used to store the I2C information for the current adapter.
+/// This structure is used by the ADL_Display_WriteAndReadI2C() function.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLI2C
+{
+/// Size of the structure
+ int iSize;
+/// Numerical value representing hardware I2C.
+ int iLine;
+/// The 7-bit I2C slave device address, shifted one bit to the left.
+ int iAddress;
+/// The offset of the data from the address.
+ int iOffset;
+/// Read from or write to slave device. \ref ADL_DL_I2C_ACTIONREAD or \ref ADL_DL_I2C_ACTIONWRITE or \ref ADL_DL_I2C_ACTIONREAD_REPEATEDSTART
+ int iAction;
+/// I2C clock speed in KHz.
+ int iSpeed;
+/// A numerical value representing the number of bytes to be sent or received on the I2C bus.
+ int iDataSize;
+/// Address of the characters which are to be sent or received on the I2C bus.
+ char *pcData;
+} ADLI2C;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing information about EDID data.
+///
+/// This structure is used to store the information about EDID data for the adapter.
+/// This structure is used by the ADL_Display_EdidData_Get() and ADL_Display_EdidData_Set() functions.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLDisplayEDIDData
+{
+/// Size of the structure
+ int iSize;
+/// Set to 0
+ int iFlag;
+ /// Size of cEDIDData. Set by ADL_Display_EdidData_Get() upon return
+ int iEDIDSize;
+/// 0, 1 or 2. If set to 3 or above an error ADL_ERR_INVALID_PARAM is generated
+ int iBlockIndex;
+/// EDID data
+ char cEDIDData[ADL_MAX_EDIDDATA_SIZE];
+/// Reserved
+ int iReserved[4];
+}ADLDisplayEDIDData;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing information about input of controller overlay adjustment.
+///
+/// This structure is used to store the information about input of controller overlay adjustment for the adapter.
+/// This structure is used by the ADL_Display_ControllerOverlayAdjustmentCaps_Get, ADL_Display_ControllerOverlayAdjustmentData_Get, and
+/// ADL_Display_ControllerOverlayAdjustmentData_Set() functions.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLControllerOverlayInput
+{
+/// Should be set to the sizeof the structure
+ int iSize;
+///\ref ADL_DL_CONTROLLER_OVERLAY_ALPHA or \ref ADL_DL_CONTROLLER_OVERLAY_ALPHAPERPIX
+ int iOverlayAdjust;
+/// Data.
+ int iValue;
+/// Should be 0.
+ int iReserved;
+} ADLControllerOverlayInput;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing information about overlay adjustment.
+///
+/// This structure is used to store the information about overlay adjustment for the adapter.
+/// This structure is used by the ADLControllerOverlayInfo() function.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLAdjustmentinfo
+{
+/// Default value
+ int iDefault;
+/// Minimum value
+ int iMin;
+/// Maximum Value
+ int iMax;
+/// Step value
+ int iStep;
+} ADLAdjustmentinfo;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing information about controller overlay information.
+///
+/// This structure is used to store information about controller overlay info for the adapter.
+/// This structure is used by the ADL_Display_ControllerOverlayAdjustmentCaps_Get() function.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLControllerOverlayInfo
+{
+/// Should be set to the sizeof the structure
+ int iSize;
+/// Data.
+ ADLAdjustmentinfo sOverlayInfo;
+/// Should be 0.
+ int iReserved[3];
+} ADLControllerOverlayInfo;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing GL-Sync module information.
+///
+/// This structure is used to retrieve GL-Sync module information for
+/// Workstation Framelock/Genlock.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLGLSyncModuleID
+{
+/// Unique GL-Sync module ID.
+ int iModuleID;
+/// GL-Sync GPU port index (to be passed into ADLGLSyncGenlockConfig.lSignalSource and ADLGlSyncPortControl.lSignalSource).
+ int iGlSyncGPUPort;
+/// GL-Sync module firmware version of Boot Sector.
+ int iFWBootSectorVersion;
+/// GL-Sync module firmware version of User Sector.
+ int iFWUserSectorVersion;
+} ADLGLSyncModuleID , *LPADLGLSyncModuleID;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing GL-Sync ports capabilities.
+///
+/// This structure is used to retrieve hardware capabilities for the ports of the GL-Sync module
+/// for Workstation Framelock/Genlock (such as port type and number of associated LEDs).
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLGLSyncPortCaps
+{
+/// Port type. Bitfield of ADL_GLSYNC_PORTTYPE_* \ref define_glsync
+ int iPortType;
+/// Number of LEDs associated for this port.
+ int iNumOfLEDs;
+}ADLGLSyncPortCaps, *LPADLGLSyncPortCaps;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing GL-Sync Genlock settings.
+///
+/// This structure is used to get and set genlock settings for the GPU ports of the GL-Sync module
+/// for Workstation Framelock/Genlock.\n
+/// \see define_glsync
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLGLSyncGenlockConfig
+{
+/// Specifies what fields in this structure are valid \ref define_glsync
+ int iValidMask;
+/// Delay (ms) generating a sync signal.
+ int iSyncDelay;
+/// Vector of framelock control bits. Bitfield of ADL_GLSYNC_FRAMELOCKCNTL_* \ref define_glsync
+ int iFramelockCntlVector;
+/// Source of the sync signal. Either GL_Sync GPU Port index or ADL_GLSYNC_SIGNALSOURCE_* \ref define_glsync
+ int iSignalSource;
+/// Use sampled sync signal. A value of 0 specifies no sampling.
+ int iSampleRate;
+/// For interlaced sync signals, the value can be ADL_GLSYNC_SYNCFIELD_1 or *_BOTH \ref define_glsync
+ int iSyncField;
+/// The signal edge that should trigger synchronization. ADL_GLSYNC_TRIGGEREDGE_* \ref define_glsync
+ int iTriggerEdge;
+/// Scan rate multiplier applied to the sync signal. ADL_GLSYNC_SCANRATECOEFF_* \ref define_glsync
+ int iScanRateCoeff;
+}ADLGLSyncGenlockConfig, *LPADLGLSyncGenlockConfig;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing GL-Sync port information.
+///
+/// This structure is used to get status of the GL-Sync ports (BNC or RJ45s)
+/// for Workstation Framelock/Genlock.
+/// \see define_glsync
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLGlSyncPortInfo
+{
+/// Type of GL-Sync port (ADL_GLSYNC_PORT_*).
+ int iPortType;
+/// The number of LEDs for this port. It's also filled within ADLGLSyncPortCaps.
+ int iNumOfLEDs;
+/// Port state ADL_GLSYNC_PORTSTATE_* \ref define_glsync
+ int iPortState;
+/// Scanned frequency for this port (vertical refresh rate in milliHz; 60000 means 60 Hz).
+ int iFrequency;
+/// Used for ADL_GLSYNC_PORT_BNC. It is ADL_GLSYNC_SIGNALTYPE_* \ref define_glsync
+ int iSignalType;
+/// Used for ADL_GLSYNC_PORT_RJ45PORT*. It is GL_Sync GPU Port index or ADL_GLSYNC_SIGNALSOURCE_*. \ref define_glsync
+ int iSignalSource;
+
+} ADLGlSyncPortInfo, *LPADLGlSyncPortInfo;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing GL-Sync port control settings.
+///
+/// This structure is used to configure the GL-Sync ports (RJ45s only)
+/// for Workstation Framelock/Genlock.
+/// \see define_glsync
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLGlSyncPortControl
+{
+/// Port to control ADL_GLSYNC_PORT_RJ45PORT1 or ADL_GLSYNC_PORT_RJ45PORT2 \ref define_glsync
+ int iPortType;
+/// Port control data ADL_GLSYNC_PORTCNTL_* \ref define_glsync
+ int iControlVector;
+/// Source of the sync signal. Either GL_Sync GPU Port index or ADL_GLSYNC_SIGNALSOURCE_* \ref define_glsync
+ int iSignalSource;
+} ADLGlSyncPortControl;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing GL-Sync mode of a display.
+///
+/// This structure is used to get and set GL-Sync mode settings for a display connected to
+/// an adapter attached to a GL-Sync module for Workstation Framelock/Genlock.
+/// \see define_glsync
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLGlSyncMode
+{
+/// Mode control vector. Bitfield of ADL_GLSYNC_MODECNTL_* \ref define_glsync
+ int iControlVector;
+/// Mode status vector. Bitfield of ADL_GLSYNC_MODECNTL_STATUS_* \ref define_glsync
+ int iStatusVector;
+/// Index of GL-Sync connector used to genlock the display/controller.
+ int iGLSyncConnectorIndex;
+} ADLGlSyncMode, *LPADLGlSyncMode;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing GL-Sync mode of a display.
+///
+/// This structure is used to get and set GL-Sync mode settings for a display connected to
+/// an adapter attached to a GL-Sync module for Workstation Framelock/Genlock.
+/// \see define_glsync
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLGlSyncMode2
+{
+/// Mode control vector. Bitfield of ADL_GLSYNC_MODECNTL_* \ref define_glsync
+ int iControlVector;
+/// Mode status vector. Bitfield of ADL_GLSYNC_MODECNTL_STATUS_* \ref define_glsync
+ int iStatusVector;
+/// Index of GL-Sync connector used to genlock the display/controller.
+ int iGLSyncConnectorIndex;
+/// Index of the display to which this GLSync applies to.
+ int iDisplayIndex;
+} ADLGlSyncMode2, *LPADLGlSyncMode2;
+
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing the packet info of a display.
+///
+/// This structure is used to get and set the packet information of a display.
+/// This structure is used by ADLDisplayDataPacket.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLInfoPacket
+{
+ char hb0;
+ char hb1;
+ char hb2;
+/// sb0~sb27
+ char sb[28];
+}ADLInfoPacket;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing the AVI packet info of a display.
+///
+/// This structure is used to get and set AVI the packet info of a display.
+/// This structure is used by ADLDisplayDataPacket.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLAVIInfoPacket //Valid user defined data/
+{
+/// byte 3, bit 7
+ char bPB3_ITC;
+/// byte 5, bit [7:4].
+ char bPB5;
+}ADLAVIInfoPacket;
+
+// Overdrive clock setting structure definition.
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing the Overdrive clock setting.
+///
+/// This structure is used to get the Overdrive clock setting.
+/// This structure is used by ADLAdapterODClockInfo.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLODClockSetting
+{
+/// Deafult clock
+ int iDefaultClock;
+/// Current clock
+ int iCurrentClock;
+/// Maximum clcok
+ int iMaxClock;
+/// Minimum clock
+ int iMinClock;
+/// Requested clcock
+ int iRequestedClock;
+/// Step
+ int iStepClock;
+} ADLODClockSetting;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing the Overdrive clock information.
+///
+/// This structure is used to get the Overdrive clock information.
+/// This structure is used by the ADL_Display_ODClockInfo_Get() function.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLAdapterODClockInfo
+{
+/// Size of the structure
+ int iSize;
+/// Flag \ref define_clockinfo_flags
+ int iFlags;
+/// Memory Clock
+ ADLODClockSetting sMemoryClock;
+/// Engine Clock
+ ADLODClockSetting sEngineClock;
+} ADLAdapterODClockInfo;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing the Overdrive clock configuration.
+///
+/// This structure is used to set the Overdrive clock configuration.
+/// This structure is used by the ADL_Display_ODClockConfig_Set() function.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLAdapterODClockConfig
+{
+/// Size of the structure
+ int iSize;
+/// Flag \ref define_clockinfo_flags
+ int iFlags;
+/// Memory Clock
+ int iMemoryClock;
+/// Engine Clock
+ int iEngineClock;
+} ADLAdapterODClockConfig;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing information about current power management related activity.
+///
+/// This structure is used to store information about current power management related activity.
+/// This structure (Overdrive 5 interfaces) is used by the ADL_PM_CurrentActivity_Get() function.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLPMActivity
+{
+/// Must be set to the size of the structure
+ int iSize;
+/// Current engine clock.
+ int iEngineClock;
+/// Current memory clock.
+ int iMemoryClock;
+/// Current core voltage.
+ int iVddc;
+/// GPU utilization.
+ int iActivityPercent;
+/// Performance level index.
+ int iCurrentPerformanceLevel;
+/// Current PCIE bus speed.
+ int iCurrentBusSpeed;
+/// Number of PCIE bus lanes.
+ int iCurrentBusLanes;
+/// Maximum number of PCIE bus lanes.
+ int iMaximumBusLanes;
+/// Reserved for future purposes.
+ int iReserved;
+} ADLPMActivity;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing information about thermal controller.
+///
+/// This structure is used to store information about thermal controller.
+/// This structure is used by ADL_PM_ThermalDevices_Enum.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLThermalControllerInfo
+{
+/// Must be set to the size of the structure
+ int iSize;
+/// Possible valies: \ref ADL_DL_THERMAL_DOMAIN_OTHER or \ref ADL_DL_THERMAL_DOMAIN_GPU.
+ int iThermalDomain;
+/// GPU 0, 1, etc.
+ int iDomainIndex;
+/// Possible valies: \ref ADL_DL_THERMAL_FLAG_INTERRUPT or \ref ADL_DL_THERMAL_FLAG_FANCONTROL
+ int iFlags;
+} ADLThermalControllerInfo;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing information about thermal controller temperature.
+///
+/// This structure is used to store information about thermal controller temperature.
+/// This structure is used by the ADL_PM_Temperature_Get() function.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLTemperature
+{
+/// Must be set to the size of the structure
+ int iSize;
+/// Temperature in millidegrees Celsius.
+ int iTemperature;
+} ADLTemperature;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing information about thermal controller fan speed.
+///
+/// This structure is used to store information about thermal controller fan speed.
+/// This structure is used by the ADL_PM_FanSpeedInfo_Get() function.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLFanSpeedInfo
+{
+/// Must be set to the size of the structure
+ int iSize;
+/// \ref define_fanctrl
+ int iFlags;
+/// Minimum possible fan speed value in percents.
+ int iMinPercent;
+/// Maximum possible fan speed value in percents.
+ int iMaxPercent;
+/// Minimum possible fan speed value in RPM.
+ int iMinRPM;
+/// Maximum possible fan speed value in RPM.
+ int iMaxRPM;
+} ADLFanSpeedInfo;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing information about fan speed reported by thermal controller.
+///
+/// This structure is used to store information about fan speed reported by thermal controller.
+/// This structure is used by the ADL_Overdrive5_FanSpeed_Get() and ADL_Overdrive5_FanSpeed_Set() functions.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLFanSpeedValue
+{
+/// Must be set to the size of the structure
+ int iSize;
+/// Possible valies: \ref ADL_DL_FANCTRL_SPEED_TYPE_PERCENT or \ref ADL_DL_FANCTRL_SPEED_TYPE_RPM
+ int iSpeedType;
+/// Fan speed value
+ int iFanSpeed;
+/// The only flag for now is: \ref ADL_DL_FANCTRL_FLAG_USER_DEFINED_SPEED
+ int iFlags;
+} ADLFanSpeedValue;
+
+////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing the range of Overdrive parameter.
+///
+/// This structure is used to store information about the range of Overdrive parameter.
+/// This structure is used by ADLODParameters.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLODParameterRange
+{
+/// Minimum parameter value.
+ int iMin;
+/// Maximum parameter value.
+ int iMax;
+/// Parameter step value.
+ int iStep;
+} ADLODParameterRange;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing information about Overdrive parameters.
+///
+/// This structure is used to store information about Overdrive parameters.
+/// This structure is used by the ADL_Overdrive5_ODParameters_Get() function.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLODParameters
+{
+/// Must be set to the size of the structure
+ int iSize;
+/// Number of standard performance states.
+ int iNumberOfPerformanceLevels;
+/// Indicates whether the GPU is capable to measure its activity.
+ int iActivityReportingSupported;
+/// Indicates whether the GPU supports discrete performance levels or performance range.
+ int iDiscretePerformanceLevels;
+/// Reserved for future use.
+ int iReserved;
+/// Engine clock range.
+ ADLODParameterRange sEngineClock;
+/// Memory clock range.
+ ADLODParameterRange sMemoryClock;
+/// Core voltage range.
+ ADLODParameterRange sVddc;
+} ADLODParameters;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing information about Overdrive level.
+///
+/// This structure is used to store information about Overdrive level.
+/// This structure is used by ADLODPerformanceLevels.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLODPerformanceLevel
+{
+/// Engine clock.
+ int iEngineClock;
+/// Memory clock.
+ int iMemoryClock;
+/// Core voltage.
+ int iVddc;
+} ADLODPerformanceLevel;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing information about Overdrive performance levels.
+///
+/// This structure is used to store information about Overdrive performance levels.
+/// This structure is used by the ADL_Overdrive5_ODPerformanceLevels_Get() and ADL_Overdrive5_ODPerformanceLevels_Set() functions.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLODPerformanceLevels
+{
+/// Must be set to sizeof( \ref ADLODPerformanceLevels ) + sizeof( \ref ADLODPerformanceLevel ) * (ADLODParameters.iNumberOfPerformanceLevels - 1)
+ int iSize;
+ int iReserved;
+/// Array of performance state descriptors. Must have ADLODParameters.iNumberOfPerformanceLevels elements.
+ ADLODPerformanceLevel aLevels [1];
+} ADLODPerformanceLevels;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing information about the proper CrossfireX chains combinations.
+///
+/// This structure is used to store information about the CrossfireX chains combination for a particular adapter.
+/// This structure is used by the ADL_Adapter_Crossfire_Caps(), ADL_Adapter_Crossfire_Get(), and ADL_Adapter_Crossfire_Set() functions.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLCrossfireComb
+{
+/// Number of adapters in this combination.
+ int iNumLinkAdapter;
+/// A list of ADL indexes of the linked adapters in this combination.
+ int iAdaptLink[3];
+} ADLCrossfireComb;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing CrossfireX state and error information.
+///
+/// This structure is used to store state and error information about a particular adapter CrossfireX combination.
+/// This structure is used by the ADL_Adapter_Crossfire_Get() function.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLCrossfireInfo
+{
+/// Current error code of this CrossfireX combination.
+ int iErrorCode;
+/// Current \ref define_crossfirestate
+ int iState;
+/// If CrossfireX is supported by this combination. The value is either \ref ADL_TRUE or \ref ADL_FALSE.
+ int iSupported;
+} ADLCrossfireInfo;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+/// \brief Structure containing information about the BIOS.
+///
+/// This structure is used to store various information about the Chipset. This
+/// information can be returned to the user.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLBiosInfo
+{
+ char strPartNumber[ADL_MAX_PATH]; ///< Part number.
+ char strVersion[ADL_MAX_PATH]; ///< Version number.
+ char strDate[ADL_MAX_PATH]; ///< BIOS date in yyyy/mm/dd hh:mm format.
+} ADLBiosInfo, *LPADLBiosInfo;
+
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+/// \brief Structure containing information about adapter location.
+///
+/// This structure is used to store information about adapter location.
+/// This structure is used by ADLMVPUStatus.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLAdapterLocation
+{
+/// PCI Bus number : 8 bits
+ int iBus;
+/// Device number : 5 bits
+ int iDevice;
+/// Function number : 3 bits
+ int iFunction;
+} ADLAdapterLocation,ADLBdf;
+
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+/// \brief Structure containing information about MultiVPU capabilities.
+///
+/// This structure is used to store information about MultiVPU capabilities.
+/// This structure is used by the ADL_Display_MVPUCaps_Get() function.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLMVPUCaps
+{
+/// Must be set to sizeof( ADLMVPUCaps ).
+ int iSize;
+/// Number of adapters.
+ int iAdapterCount;
+/// Bits set for all possible MVPU masters. \ref MVPU_ADAPTER_0 .. \ref MVPU_ADAPTER_3
+ int iPossibleMVPUMasters;
+/// Bits set for all possible MVPU slaves. \ref MVPU_ADAPTER_0 .. \ref MVPU_ADAPTER_3
+ int iPossibleMVPUSlaves;
+/// Registry path for each adapter.
+ char cAdapterPath[ADL_DL_MAX_MVPU_ADAPTERS][ADL_DL_MAX_REGISTRY_PATH];
+} ADLMVPUCaps;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+/// \brief Structure containing information about MultiVPU status.
+///
+/// This structure is used to store information about MultiVPU status.
+/// Ths structure is used by the ADL_Display_MVPUStatus_Get() function.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLMVPUStatus
+{
+/// Must be set to sizeof( ADLMVPUStatus ).
+ int iSize;
+/// Number of active adapters.
+ int iActiveAdapterCount;
+/// MVPU status.
+ int iStatus;
+/// PCI Bus/Device/Function for each active adapter participating in MVPU.
+ ADLAdapterLocation aAdapterLocation[ADL_DL_MAX_MVPU_ADAPTERS];
+} ADLMVPUStatus;
+
+// Displays Manager structures
+
+///////////////////////////////////////////////////////////////////////////
+/// \brief Structure containing information about the activatable source.
+///
+/// This structure is used to store activatable source information
+/// This information can be returned to the user.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLActivatableSource
+{
+ /// The Persistent logical Adapter Index.
+ int iAdapterIndex;
+ /// The number of Activatable Sources.
+ int iNumActivatableSources;
+ /// The bit mask identifies the number of bits ActivatableSourceValue is using. (Not currnetly used)
+ int iActivatableSourceMask;
+ /// The bit mask identifies the status. (Not currnetly used)
+ int iActivatableSourceValue;
+} ADLActivatableSource, *LPADLActivatableSource;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+/// \brief Structure containing information about display mode.
+///
+/// This structure is used to store the display mode for the current adapter
+/// such as X, Y positions, screen resolutions, orientation,
+/// color depth, refresh rate, progressive or interlace mode, etc.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+
+typedef struct ADLMode
+{
+/// Adapter index.
+ int iAdapterIndex;
+/// Display IDs.
+ ADLDisplayID displayID;
+/// Screen position X coordinate.
+ int iXPos;
+/// Screen position Y coordinate.
+ int iYPos;
+/// Screen resolution Width.
+ int iXRes;
+/// Screen resolution Height.
+ int iYRes;
+/// Screen Color Depth. E.g., 16, 32.
+ int iColourDepth;
+/// Screen refresh rate. Could be fractional E.g. 59.97
+ float fRefreshRate;
+/// Screen orientation. E.g., 0, 90, 180, 270.
+ int iOrientation;
+/// Vista mode flag indicating Progressive or Interlaced mode.
+ int iModeFlag;
+/// The bit mask identifying the number of bits this Mode is currently using. It is the sum of all the bit definitions defined in \ref define_displaymode
+ int iModeMask;
+/// The bit mask identifying the display status. The detailed definition is in \ref define_displaymode
+ int iModeValue;
+} ADLMode, *LPADLMode;
+
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+/// \brief Structure containing information about display target information.
+///
+/// This structure is used to store the display target information.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLDisplayTarget
+{
+ /// The Display ID.
+ ADLDisplayID displayID;
+
+ /// The display map index identify this manner and the desktop surface.
+ int iDisplayMapIndex;
+
+ /// The bit mask identifies the number of bits DisplayTarget is currently using. It is the sum of all the bit definitions defined in \ref ADL_DISPLAY_DISPLAYTARGET_PREFERRED.
+ int iDisplayTargetMask;
+
+ /// The bit mask identifies the display status. The detailed definition is in \ref ADL_DISPLAY_DISPLAYTARGET_PREFERRED.
+ int iDisplayTargetValue;
+
+} ADLDisplayTarget, *LPADLDisplayTarget;
+
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing information about the display SLS bezel Mode information.
+///
+/// This structure is used to store the display SLS bezel Mode information.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct tagADLBezelTransientMode
+{
+ /// Adapter Index
+ int iAdapterIndex;
+
+ /// SLS Map Index
+ int iSLSMapIndex;
+
+ /// The mode index
+ int iSLSModeIndex;
+
+ /// The mode
+ ADLMode displayMode;
+
+ /// The number of bezel offsets belongs to this map
+ int iNumBezelOffset;
+
+ /// The first bezel offset array index in the native mode array
+ int iFirstBezelOffsetArrayIndex;
+
+ /// The bit mask identifies the bits this structure is currently using. It will be the total OR of all the bit definitions.
+ int iSLSBezelTransientModeMask;
+
+ /// The bit mask identifies the display status. The detail definition is defined below.
+ int iSLSBezelTransientModeValue;
+
+} ADLBezelTransientMode, *LPADLBezelTransientMode;
+
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+/// \brief Structure containing information about the adapter display manner.
+///
+/// This structure is used to store adapter display manner information
+/// This information can be returned to the user. Alternatively, it can be used to access various driver calls to
+/// fetch various display device related display manner settings upon the user's request.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLAdapterDisplayCap
+{
+ /// The Persistent logical Adapter Index.
+ int iAdapterIndex;
+ /// The bit mask identifies the number of bits AdapterDisplayCap is currently using. Sum all the bits defined in ADL_ADAPTER_DISPLAYCAP_XXX
+ int iAdapterDisplayCapMask;
+ /// The bit mask identifies the status. Refer to ADL_ADAPTER_DISPLAYCAP_XXX
+ int iAdapterDisplayCapValue;
+} ADLAdapterDisplayCap, *LPADLAdapterDisplayCap;
+
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing information about display mapping.
+///
+/// This structure is used to store the display mapping data such as display manner.
+/// For displays with horizontal or vertical stretch manner,
+/// this structure also stores the display order, display row, and column data.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLDisplayMap
+{
+/// The current display map index. It is the OS desktop index. For example, if the OS index 1 is showing clone mode, the display map will be 1.
+ int iDisplayMapIndex;
+
+/// The Display Mode for the current map
+ ADLMode displayMode;
+
+/// The number of display targets belongs to this map\n
+ int iNumDisplayTarget;
+
+/// The first target array index in the Target array\n
+ int iFirstDisplayTargetArrayIndex;
+
+/// The bit mask identifies the number of bits DisplayMap is currently using. It is the sum of all the bit definitions defined in ADL_DISPLAY_DISPLAYMAP_MANNER_xxx.
+ int iDisplayMapMask;
+
+///The bit mask identifies the display status. The detailed definition is in ADL_DISPLAY_DISPLAYMAP_MANNER_xxx.
+ int iDisplayMapValue;
+
+} ADLDisplayMap, *LPADLDisplayMap;
+
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+/// \brief Structure containing information about the display device possible map for one GPU
+///
+/// This structure is used to store the display device possible map
+/// This information can be returned to the user.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLPossibleMap
+{
+ /// The current PossibleMap index. Each PossibleMap is assigned an index
+ int iIndex;
+ /// The adapter index identifying the GPU for which to validate these Maps & Targets
+ int iAdapterIndex;
+ /// Number of display Maps for this GPU to be validated
+ int iNumDisplayMap;
+ /// The display Maps list to validate
+ ADLDisplayMap* displayMap;
+ /// the number of display Targets for these display Maps
+ int iNumDisplayTarget;
+ /// The display Targets list for these display Maps to be validated.
+ ADLDisplayTarget* displayTarget;
+} ADLPossibleMap, *LPADLPossibleMap;
+
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+/// \brief Structure containing information about display possible mapping.
+///
+/// This structure is used to store the display possible mapping's controller index for the current display.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLPossibleMapping
+{
+ int iDisplayIndex; ///< The display index. Each display is assigned an index.
+ int iDisplayControllerIndex; ///< The controller index to which display is mapped.
+ int iDisplayMannerSupported; ///< The supported display manner.
+} ADLPossibleMapping, *LPADLPossibleMapping;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+/// \brief Structure containing information about the validated display device possible map result.
+///
+/// This structure is used to store the validated display device possible map result
+/// This information can be returned to the user.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLPossibleMapResult
+{
+ /// The current display map index. It is the OS Desktop index. For example, OS Index 1 showing clone mode. The Display Map will be 1.
+ int iIndex;
+ // The bit mask identifies the number of bits PossibleMapResult is currently using. It will be the sum all the bit definitions defined in ADL_DISPLAY_POSSIBLEMAPRESULT_VALID.
+ int iPossibleMapResultMask;
+ /// The bit mask identifies the possible map result. The detail definition is defined in ADL_DISPLAY_POSSIBLEMAPRESULT_XXX.
+ int iPossibleMapResultValue;
+} ADLPossibleMapResult, *LPADLPossibleMapResult;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing information about the display SLS Grid information.
+///
+/// This structure is used to store the display SLS Grid information.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLSLSGrid
+{
+/// The Adapter index.
+ int iAdapterIndex;
+
+/// The grid index.
+ int iSLSGridIndex;
+
+/// The grid row.
+ int iSLSGridRow;
+
+/// The grid column.
+ int iSLSGridColumn;
+
+/// The grid bit mask identifies the number of bits DisplayMap is currently using. Sum of all bits defined in ADL_DISPLAY_SLSGRID_ORIENTATION_XXX
+ int iSLSGridMask;
+
+/// The grid bit value identifies the display status. Refer to ADL_DISPLAY_SLSGRID_ORIENTATION_XXX
+ int iSLSGridValue;
+
+} ADLSLSGrid, *LPADLSLSGrid;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing information about the display SLS Map information.
+///
+/// This structure is used to store the display SLS Map information.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLSLSMap
+{
+ /// The Adapter Index
+ int iAdapterIndex;
+
+ /// The current display map index. It is the OS Desktop index. For example, OS Index 1 showing clone mode. The Display Map will be 1.
+ int iSLSMapIndex;
+
+ /// Indicate the current grid
+ ADLSLSGrid grid;
+
+ /// OS surface index
+ int iSurfaceMapIndex;
+
+ /// Screen orientation. E.g., 0, 90, 180, 270
+ int iOrientation;
+
+ /// The number of display targets belongs to this map
+ int iNumSLSTarget;
+
+ /// The first target array index in the Target array
+ int iFirstSLSTargetArrayIndex;
+
+ /// The number of native modes belongs to this map
+ int iNumNativeMode;
+
+ /// The first native mode array index in the native mode array
+ int iFirstNativeModeArrayIndex;
+
+ /// The number of bezel modes belongs to this map
+ int iNumBezelMode;
+
+ /// The first bezel mode array index in the native mode array
+ int iFirstBezelModeArrayIndex;
+
+ /// The number of bezel offsets belongs to this map
+ int iNumBezelOffset;
+
+ /// The first bezel offset array index in the
+ int iFirstBezelOffsetArrayIndex;
+
+ /// The bit mask identifies the number of bits DisplayMap is currently using. Sum all the bit definitions defined in ADL_DISPLAY_SLSMAP_XXX.
+ int iSLSMapMask;
+
+ /// The bit mask identifies the display map status. Refer to ADL_DISPLAY_SLSMAP_XXX
+ int iSLSMapValue;
+
+
+} ADLSLSMap, *LPADLSLSMap;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing information about the display SLS Offset information.
+///
+/// This structure is used to store the display SLS Offset information.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLSLSOffset
+{
+ /// The Adapter Index
+ int iAdapterIndex;
+
+ /// The current display map index. It is the OS Desktop index. For example, OS Index 1 showing clone mode. The Display Map will be 1.
+ int iSLSMapIndex;
+
+ /// The Display ID.
+ ADLDisplayID displayID;
+
+ /// SLS Bezel Mode Index
+ int iBezelModeIndex;
+
+ /// SLS Bezel Offset X
+ int iBezelOffsetX;
+
+ /// SLS Bezel Offset Y
+ int iBezelOffsetY;
+
+ /// SLS Display Width
+ int iDisplayWidth;
+
+ /// SLS Display Height
+ int iDisplayHeight;
+
+ /// The bit mask identifies the number of bits Offset is currently using.
+ int iBezelOffsetMask;
+
+ /// The bit mask identifies the display status.
+ int iBezelffsetValue;
+} ADLSLSOffset, *LPADLSLSOffset;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing information about the display SLS Mode information.
+///
+/// This structure is used to store the display SLS Mode information.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLSLSMode
+{
+ /// The Adapter Index
+ int iAdapterIndex;
+
+ /// The current display map index. It is the OS Desktop index. For example, OS Index 1 showing clone mode. The Display Map will be 1.
+ int iSLSMapIndex;
+
+ /// The mode index
+ int iSLSModeIndex;
+
+ /// The mode for this map.
+ ADLMode displayMode;
+
+ /// The bit mask identifies the number of bits Mode is currently using.
+ int iSLSNativeModeMask;
+
+ /// The bit mask identifies the display status.
+ int iSLSNativeModeValue;
+} ADLSLSMode, *LPADLSLSMode;
+
+
+
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing information about the display Possible SLS Map information.
+///
+/// This structure is used to store the display Possible SLS Map information.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLPossibleSLSMap
+{
+ /// The current display map index. It is the OS Desktop index.
+ /// For example, OS Index 1 showing clone mode. The Display Map will be 1.
+ int iSLSMapIndex;
+
+ /// Number of display map to be validated.
+ int iNumSLSMap;
+
+ /// The display map list for validation
+ ADLSLSMap* lpSLSMap;
+
+ /// the number of display map config to be validated.
+ int iNumSLSTarget;
+
+ /// The display target list for validation.
+ ADLDisplayTarget* lpDisplayTarget;
+} ADLPossibleSLSMap, *LPADLPossibleSLSMap;
+
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing information about the SLS targets.
+///
+/// This structure is used to store the SLS targets information.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLSLSTarget
+{
+ /// the logic adapter index
+ int iAdapterIndex;
+
+ /// The SLS map index
+ int iSLSMapIndex;
+
+ /// The target ID
+ ADLDisplayTarget displayTarget;
+
+ /// Target position X in SLS grid
+ int iSLSGridPositionX;
+
+ /// Target position Y in SLS grid
+ int iSLSGridPositionY;
+
+ /// The view size width, height and rotation angle per SLS Target
+ ADLMode viewSize;
+
+ /// The bit mask identifies the bits in iSLSTargetValue are currently used
+ int iSLSTargetMask;
+
+ /// The bit mask identifies status info. It is for function extension purpose
+ int iSLSTargetValue;
+
+} ADLSLSTarget, *LPADLSLSTarget;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing information about the Adapter offset stepping size.
+///
+/// This structure is used to store the Adapter offset stepping size information.
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLBezelOffsetSteppingSize
+{
+ /// the logic adapter index
+ int iAdapterIndex;
+
+ /// The SLS map index
+ int iSLSMapIndex;
+
+ /// Bezel X stepping size offset
+ int iBezelOffsetSteppingSizeX;
+
+ /// Bezel Y stepping size offset
+ int iBezelOffsetSteppingSizeY;
+
+ /// Identifies the bits this structure is currently using. It will be the total OR of all the bit definitions.
+ int iBezelOffsetSteppingSizeMask;
+
+ /// Bit mask identifies the display status.
+ int iBezelOffsetSteppingSizeValue;
+
+} ADLBezelOffsetSteppingSize, *LPADLBezelOffsetSteppingSize;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing information about driver supported PowerExpress Config Caps
+///
+/// This structure is used to store the driver supported PowerExpress Config Caps
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLPXConfigCaps
+{
+ /// The Persistent logical Adapter Index.
+ int iAdapterIndex;
+
+ /// The bit mask identifies the number of bits PowerExpress Config Caps is currently using. It is the sum of all the bit definitions defined in \ref ADL_PX_CONFIGCAPS_XXXX.
+ int iPXConfigCapMask;
+
+ /// The bit mask identifies the PowerExpress Config Caps value. The detailed definition is in \ref ADL_PX_CONFIGCAPS_XXXX.
+ int iPXConfigCapValue;
+
+} ADLPXConfigCaps, *LPADLPXConfigCaps;
+
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing information about an application
+///
+/// This structure is used to store basic information of an application
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct _ADLApplicationData
+{
+ /// Path Name
+ char strPathName[ADL_MAX_PATH];
+ /// File Name
+ char strFileName[ADL_APP_PROFILE_FILENAME_LENGTH];
+ /// Creation timestamp
+ char strTimeStamp[ADL_APP_PROFILE_TIMESTAMP_LENGTH];
+ /// Version
+ char strVersion[ADL_APP_PROFILE_VERSION_LENGTH];
+}ADLApplicationData;
+
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing information of a property of an application profile
+///
+/// This structure is used to store property information of an application profile
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct _PropertyRecord
+{
+ /// Property Name
+ char strName [ADL_APP_PROFILE_PROPERTY_LENGTH];
+ /// Property Type
+ ADLProfilePropertyType eType;
+ /// Data Size in bytes
+ int iDataSize;
+ /// Property Value, can be any data type
+ unsigned char uData[1];
+}PropertyRecord;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing information about an application profile
+///
+/// This structure is used to store information of an application profile
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct _ADLApplicationProfile
+{
+ /// Number of properties
+ int iCount;
+ /// Buffer to store all property records
+ PropertyRecord record[1];
+}ADLApplicationProfile;
+
+// @}
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing information about an OD5 Power Control feature
+///
+/// This structure is used to store information of an Power Control feature
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct ADLPowerControlInfo
+{
+/// Minimum value.
+int iMinValue;
+/// Maximum value.
+int iMaxValue;
+/// The minimum change in between minValue and maxValue.
+int iStepValue;
+ } ADLPowerControlInfo;
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+///\brief Structure containing information about an controller mode
+///
+/// This structure is used to store information of an controller mode
+/// \nosubgrouping
+////////////////////////////////////////////////////////////////////////////////////////////
+typedef struct _ADLControllerMode
+{
+ /// This falg indicates actions that will be applied by set viewport
+ /// The value can be a combination of ADL_CONTROLLERMODE_CM_MODIFIER_VIEW_POSITION,
+ /// ADL_CONTROLLERMODE_CM_MODIFIER_VIEW_PANLOCK and ADL_CONTROLLERMODE_CM_MODIFIER_VIEW_SIZE
+ int iModifiers;
+
+ /// Horizontal view starting position
+ int iViewPositionCx;
+
+ /// Vertical view starting position
+ int iViewPositionCy;
+
+ /// Horizontal left panlock position
+ int iViewPanLockLeft;
+
+ /// Horizontal right panlock position
+ int iViewPanLockRight;
+
+ /// Vertical top panlock position
+ int iViewPanLockTop;
+
+ /// Vertical bottom panlock position
+ int iViewPanLockBottom;
+
+ /// View resolution in pixels (width)
+ int iViewResolutionCx;
+
+ /// View resolution in pixels (hight)
+ int iViewResolutionCy;
+}ADLControllerMode;
+
+
+#endif /* ADL_STRUCTURES_H_ */
+
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2013 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#ifdef HAVE_DRM_EDID_PARSER
+
+#include <p8-platform/os.h>
+#include "drm-edid.h"
+#include <dirent.h>
+#include <fstream>
+
+using namespace P8PLATFORM;
+
+uint16_t CDRMEdidParser::GetPhysicalAddress(void)
+{
+ uint16_t iPA(0);
+
+ // Fisrt we look for all DRM subfolder
+ std::string baseDir = "/sys/class/drm/";
+
+ DIR *dir = opendir(baseDir.c_str());
+
+ // DRM subfolder may not exist on some systems
+ if (dir == NULL)
+ {
+ return iPA;
+ }
+
+ struct dirent *entry = readdir(dir);
+ std::string enablededid;
+ std::string line;
+
+ while (entry != NULL && enablededid.empty())
+ {
+ // We look if the element is a symlinl
+ if (entry->d_type == DT_LNK)
+ {
+ // We look for the file enable to find the active video card
+ std::string path, enabledPath, edidPath;
+ path = baseDir + entry->d_name;
+ enabledPath = path + "/enabled";
+ edidPath = path + "/edid";
+
+ std::ifstream f(enabledPath.c_str());
+ if (f.is_open())
+ {
+ if (f.good() && !f.eof())
+ {
+ getline(f, line);
+
+ // We look if the card is "Enabled"
+ if (line == "enabled")
+ {
+ // We look if the directory have an edid file
+ std::ifstream edid(edidPath.c_str());
+ if (edid.is_open())
+ {
+ if (edid.good()) {
+ enablededid = edidPath;
+ }
+ edid.close();
+ }
+ }
+ }
+ f.close();
+ }
+ }
+ entry = readdir(dir);
+ }
+
+ closedir(dir);
+
+ if (!enablededid.empty())
+ {
+ FILE *fp = fopen(enablededid.c_str(), "r");
+
+ if (fp)
+ {
+ char* buf = (char*)calloc(4096, sizeof(char));
+ int iPtr(0);
+ int c(0);
+ if (buf)
+ {
+ while (c != EOF)
+ {
+ c = fgetc(fp);
+ if (c != EOF)
+ buf[iPtr++] = c;
+ }
+
+ iPA = CEDIDParser::GetPhysicalAddressFromEDID(buf, iPtr);
+ free(buf);
+ }
+
+ fclose(fp);
+ }
+ }
+
+ return iPA;
+}
+
+#endif
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2013 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+#ifdef HAVE_DRM_EDID_PARSER
+
+#include "platform/util/edid.h"
+
+namespace P8PLATFORM
+{
+ class CDRMEdidParser
+ {
+ public:
+ CDRMEdidParser(void) {};
+ virtual ~CDRMEdidParser(void) {};
+
+ uint16_t GetPhysicalAddress(void);
+ };
+}
+
+#endif
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include "nv-edid.h"
+
+#if defined(HAVE_NVIDIA_EDID_PARSER)
+
+#include <p8-platform/os.h>
+#include <stdio.h>
+
+using namespace P8PLATFORM;
+
+uint16_t CNVEdidParser::GetPhysicalAddress(void)
+{
+ uint16_t iPA(0);
+
+#if !defined(__WINDOWS__)
+ FILE *fp = fopen("/proc/acpi/video/NGFX/HDMI/EDID", "r");
+
+ if (fp)
+ {
+ char buf[4096];
+ memset(buf, 0, sizeof(buf));
+ int iPtr(0);
+ int c(0);
+ while (c != EOF)
+ {
+ c = fgetc(fp);
+ if (c != EOF)
+ buf[iPtr++] = c;
+ }
+
+ iPA = CEDIDParser::GetPhysicalAddressFromEDID(buf, iPtr);
+ fclose(fp);
+ }
+#endif
+
+ return iPA;
+}
+
+#endif
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#define HAVE_NVIDIA_EDID_PARSER
+
+#include "platform/util/edid.h"
+
+namespace P8PLATFORM
+{
+ class CNVEdidParser
+ {
+ public:
+ CNVEdidParser(void) {};
+ virtual ~CNVEdidParser(void) {};
+
+ uint16_t GetPhysicalAddress(void);
+
+ };
+}
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include "platform/util/edid.h"
+#include "platform/X11/randr-edid.h"
+
+using namespace P8PLATFORM;
+
+uint16_t CEDIDParser::GetPhysicalAddress(void)
+{
+#if HAVE_RANDR
+ return CRandrEdidParser().GetPhysicalAddress();
+#else
+ // TODO
+ return 0;
+#endif
+}
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include <stdio.h>
+#include <fcntl.h>
+#include "../sockets/serialport.h"
+#include "../util/baudrate.h"
+#include <p8-platform/posix/os-socket.h>
+
+#if defined(__APPLE__) || defined(__FreeBSD__)
+#ifndef XCASE
+#define XCASE 0
+#endif
+#ifndef OLCUC
+#define OLCUC 0
+#endif
+#ifndef IUCLC
+#define IUCLC 0
+#endif
+#else
+#ifdef HAVE_SYS_FILE_HEADER
+#include <sys/file.h>
+#endif
+#endif
+
+/** XCASE was deprecated on removed from posix */
+#ifndef XCASE
+#define XCASE 0
+#endif
+
+using namespace P8PLATFORM;
+
+inline bool RemoveLock(int sock)
+{
+ #if HAVE_FLOCK
+ return flock(sock, LOCK_UN) == 0;
+ #else
+ (void)strDeviceName; // silence unused warning
+ return true;
+ #endif
+}
+
+void CSerialSocket::Close(void)
+{
+ if (IsOpen())
+ {
+ RemoveLock(m_socket);
+ SocketClose(m_socket);
+ }
+}
+
+void CSerialSocket::Shutdown(void)
+{
+ if (IsOpen())
+ {
+ RemoveLock(m_socket);
+ SocketClose(m_socket);
+ }
+}
+
+ssize_t CSerialSocket::Write(void* data, size_t len)
+{
+ return IsOpen() ? SocketWrite(m_socket, &m_iError, data, len) : -1;
+}
+
+ssize_t CSerialSocket::Read(void* data, size_t len, uint64_t iTimeoutMs /* = 0 */)
+{
+ return IsOpen() ? SocketRead(m_socket, &m_iError, data, len, iTimeoutMs) : -1;
+}
+
+//setting all this stuff up is a pain in the ass
+bool CSerialSocket::Open(uint64_t iTimeoutMs /* = 0 */)
+{
+ iTimeoutMs = 0; if (!iTimeoutMs){} // silence unused warning
+ if (IsOpen())
+ {
+ m_iError = EINVAL;
+ return false;
+ }
+
+ if (m_iDatabits != SERIAL_DATA_BITS_FIVE && m_iDatabits != SERIAL_DATA_BITS_SIX &&
+ m_iDatabits != SERIAL_DATA_BITS_SEVEN && m_iDatabits != SERIAL_DATA_BITS_EIGHT)
+ {
+ m_strError = "Databits has to be between 5 and 8";
+ m_iError = EINVAL;
+ return false;
+ }
+
+ if (m_iStopbits != SERIAL_STOP_BITS_ONE && m_iStopbits != SERIAL_STOP_BITS_TWO)
+ {
+ m_strError = "Stopbits has to be 1 or 2";
+ m_iError = EINVAL;
+ return false;
+ }
+
+ if (m_iParity != SERIAL_PARITY_NONE && m_iParity != SERIAL_PARITY_EVEN && m_iParity != SERIAL_PARITY_ODD)
+ {
+ m_strError = "Parity has to be none, even or odd";
+ m_iError = EINVAL;
+ return false;
+ }
+
+ m_socket = open(m_strName.c_str(), O_RDWR | O_NOCTTY | O_NDELAY);
+
+ if (m_socket == INVALID_SERIAL_SOCKET_VALUE)
+ {
+ m_strError = strerror(errno);
+ return false;
+ }
+
+#if HAVE_FLOCK
+ if (flock(m_socket, LOCK_EX | LOCK_NB) != 0)
+ {
+ m_strError = "Couldn't lock the serial port";
+ m_iError = EBUSY;
+ SocketClose(m_socket);
+ return false;
+ }
+#endif
+
+ SocketSetBlocking(m_socket, false);
+
+ if (!SetBaudRate(m_iBaudrate))
+ return false;
+
+ m_options.c_cflag |= (CLOCAL | CREAD);
+ m_options.c_cflag &= ~HUPCL;
+
+ m_options.c_cflag &= ~CSIZE;
+ if (m_iDatabits == SERIAL_DATA_BITS_FIVE) m_options.c_cflag |= CS5;
+ if (m_iDatabits == SERIAL_DATA_BITS_SIX) m_options.c_cflag |= CS6;
+ if (m_iDatabits == SERIAL_DATA_BITS_SEVEN) m_options.c_cflag |= CS7;
+ if (m_iDatabits == SERIAL_DATA_BITS_EIGHT) m_options.c_cflag |= CS8;
+
+ m_options.c_cflag &= ~PARENB;
+ if (m_iParity == SERIAL_PARITY_EVEN || m_iParity == SERIAL_PARITY_ODD)
+ m_options.c_cflag |= PARENB;
+ if (m_iParity == SERIAL_PARITY_ODD)
+ m_options.c_cflag |= PARODD;
+
+#ifdef CRTSCTS
+ m_options.c_cflag &= ~CRTSCTS;
+#elif defined(CNEW_RTSCTS)
+ m_options.c_cflag &= ~CNEW_RTSCTS;
+#endif
+
+ if (m_iStopbits == SERIAL_STOP_BITS_ONE) m_options.c_cflag &= ~CSTOPB;
+ else m_options.c_cflag |= CSTOPB;
+
+ //I guessed a little here
+ m_options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG | XCASE | ECHOK | ECHONL | ECHOCTL | ECHOPRT | ECHOKE | TOSTOP);
+
+ if (m_iParity == SERIAL_PARITY_NONE)
+ m_options.c_iflag &= ~INPCK;
+ else
+ m_options.c_iflag |= INPCK | ISTRIP;
+
+ m_options.c_iflag &= ~(IXON | IXOFF | IXANY | BRKINT | INLCR | IGNCR | ICRNL | IUCLC | IMAXBEL);
+ m_options.c_oflag &= ~(OPOST | ONLCR | OCRNL);
+
+ if (tcsetattr(m_socket, TCSANOW, &m_options) != 0)
+ {
+ m_strError = strerror(errno);
+ RemoveLock(m_socket);
+ SocketClose(m_socket);
+ return false;
+ }
+
+ SocketSetBlocking(m_socket, true);
+ m_bIsOpen = true;
+
+ return true;
+}
+
+bool CSerialSocket::SetBaudRate(uint32_t baudrate)
+{
+ int rate = IntToBaudrate(baudrate);
+ if (rate == -1)
+ {
+ char buff[255];
+ sprintf(buff, "%i is not a valid baudrate", baudrate);
+ m_strError = buff;
+ return false;
+ }
+
+ //get the current port attributes
+ if (tcgetattr(m_socket, &m_options) != 0)
+ {
+ m_strError = strerror(errno);
+ return false;
+ }
+
+ if (cfsetispeed(&m_options, rate) != 0)
+ {
+ m_strError = strerror(errno);
+ return false;
+ }
+
+ if (cfsetospeed(&m_options, rate) != 0)
+ {
+ m_strError = strerror(errno);
+ return false;
+ }
+
+ return true;
+}
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include <p8-platform/util/buffer.h>
+
+#include <string>
+#include <stdint.h>
+
+#if !defined(__WINDOWS__)
+#include <termios.h>
+#endif
+
+#include <p8-platform/sockets/socket.h>
+
+namespace P8PLATFORM
+{
+ enum SerialParity
+ {
+ SERIAL_PARITY_NONE = 0,
+ SERIAL_PARITY_EVEN,
+ SERIAL_PARITY_ODD
+ };
+
+ enum SerialStopBits
+ {
+ SERIAL_STOP_BITS_ONE = 1,
+ SERIAL_STOP_BITS_TWO = 2
+ };
+
+ enum SerialDataBits
+ {
+ SERIAL_DATA_BITS_FIVE = 5,
+ SERIAL_DATA_BITS_SIX = 6,
+ SERIAL_DATA_BITS_SEVEN = 7,
+ SERIAL_DATA_BITS_EIGHT = 8
+ };
+
+ class CSerialSocket : public CCommonSocket<serial_socket_t>
+ {
+ public:
+ CSerialSocket(const std::string &strName, uint32_t iBaudrate, SerialDataBits iDatabits = SERIAL_DATA_BITS_EIGHT, SerialStopBits iStopbits = SERIAL_STOP_BITS_ONE, SerialParity iParity = SERIAL_PARITY_NONE) :
+ CCommonSocket<serial_socket_t>(INVALID_SERIAL_SOCKET_VALUE, strName),
+ #ifdef __WINDOWS__
+ m_iCurrentReadTimeout(MAXDWORD),
+ #endif
+ m_bIsOpen(false),
+ m_iBaudrate(iBaudrate),
+ m_iDatabits(iDatabits),
+ m_iStopbits(iStopbits),
+ m_iParity(iParity) {}
+
+ virtual ~CSerialSocket(void) { Close(); }
+
+ virtual bool Open(uint64_t iTimeoutMs = 0);
+ virtual void Close(void);
+ virtual void Shutdown(void);
+ virtual ssize_t Write(void* data, size_t len);
+ virtual ssize_t Read(void* data, size_t len, uint64_t iTimeoutMs = 0);
+
+ virtual bool IsOpen(void)
+ {
+ return m_socket != INVALID_SERIAL_SOCKET_VALUE &&
+ m_bIsOpen;
+ }
+
+ virtual bool SetBaudRate(uint32_t baudrate);
+
+ protected:
+ #ifndef __WINDOWS__
+ struct termios m_options;
+ #else
+ bool SetTimeouts(serial_socket_t socket, int* iError, DWORD iTimeoutMs);
+ DWORD m_iCurrentReadTimeout;
+ #endif
+
+ bool m_bIsOpen;
+ uint32_t m_iBaudrate;
+ SerialDataBits m_iDatabits;
+ SerialStopBits m_iStopbits;
+ SerialParity m_iParity;
+ };
+
+ class CSerialPort : public CProtectedSocket<CSerialSocket>
+ {
+ public:
+ CSerialPort(const std::string &strName, uint32_t iBaudrate, SerialDataBits iDatabits = SERIAL_DATA_BITS_EIGHT, SerialStopBits iStopbits = SERIAL_STOP_BITS_ONE, SerialParity iParity = SERIAL_PARITY_NONE) :
+ CProtectedSocket<CSerialSocket> (new CSerialSocket(strName, iBaudrate, iDatabits, iStopbits, iParity)) {}
+ virtual ~CSerialPort(void) {}
+ };
+};
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+//every baudrate I could find is in here in an #ifdef block
+//so it should compile on everything
+
+#include "env.h"
+
+#ifndef __WINDOWS__
+#include <termios.h>
+#endif
+
+namespace P8PLATFORM
+{
+ static struct sbaudrate
+ {
+ int32_t rate;
+ int32_t symbol;
+ }
+
+ baudrates[] =
+ {
+ #ifdef B50
+ { 50, B50 },
+ #endif
+ #ifdef B75
+ { 75, B75 },
+ #endif
+ #ifdef B110
+ { 110, B110 },
+ #endif
+ #ifdef B134
+ { 134, B134 },
+ #endif
+ #ifdef B150
+ { 150, B150 },
+ #endif
+ #ifdef B200
+ { 200, B200 },
+ #endif
+ #ifdef B300
+ { 300, B300 },
+ #endif
+ #ifdef B600
+ { 600, B600 },
+ #endif
+ #ifdef B1200
+ { 1200, B1200 },
+ #endif
+ #ifdef B1800
+ { 1800, B1800 },
+ #endif
+ #ifdef B2400
+ { 2400, B2400 },
+ #endif
+ #ifdef B4800
+ { 4800, B4800 },
+ #endif
+ #ifdef B9600
+ { 9600, B9600 },
+ #endif
+ #ifdef B14400
+ { 14400, B14400 },
+ #endif
+ #ifdef B19200
+ { 19200, B19200 },
+ #endif
+ #ifdef B28800
+ { 28800, B28800 },
+ #endif
+ #ifdef B38400
+ { 38400, B38400 },
+ #endif
+ #ifdef B57600
+ { 57600, B57600 },
+ #endif
+ #ifdef B76800
+ { 76800, B76800 },
+ #endif
+ #ifdef B115200
+ { 115200, B115200 },
+ #endif
+ #ifdef B230400
+ { 230400, B230400 },
+ #endif
+ #ifdef B250000
+ { 250000, B250000 },
+ #endif
+ #ifdef B460800
+ { 460800, B460800 },
+ #endif
+ #ifdef B500000
+ { 500000, B500000 },
+ #endif
+ #ifdef B576000
+ { 576000, B576000 },
+ #endif
+ #ifdef B921600
+ { 921600, B921600 },
+ #endif
+ #ifdef B1000000
+ { 1000000, B1000000 },
+ #endif
+ #ifdef B1152000
+ { 1152000, B1152000 },
+ #endif
+ #ifdef B1500000
+ { 1500000, B1500000 },
+ #endif
+ #ifdef B2000000
+ { 2000000, B2000000 },
+ #endif
+ #ifdef B2500000
+ { 2500000, B2500000 },
+ #endif
+ #ifdef B3000000
+ { 3000000, B3000000 },
+ #endif
+ #ifdef B3500000
+ { 3500000, B3500000 },
+ #endif
+ #ifdef B4000000
+ { 4000000, B4000000 },
+ #endif
+ #ifdef CBR_110
+ { 110, CBR_110 },
+ #endif
+ #ifdef CBR_300
+ { 300, CBR_300 },
+ #endif
+ #ifdef CBR_600
+ { 600, CBR_600 },
+ #endif
+ #ifdef CBR_1200
+ { 1200, CBR_1200 },
+ #endif
+ #ifdef CBR_2400
+ { 2400, CBR_2400 },
+ #endif
+ #ifdef CBR_4800
+ { 4800, CBR_4800 },
+ #endif
+ #ifdef CBR_9600
+ { 9600, CBR_9600 },
+ #endif
+ #ifdef CBR_11400
+ { 11400, CBR_14400 },
+ #endif
+ #ifdef CBR_19200
+ { 19200, CBR_19200 },
+ #endif
+ #ifdef CBR_38400
+ { 38400, CBR_38400 },
+ #endif
+ #ifdef CBR_56000
+ { 56000, CBR_56000 },
+ #endif
+ #ifdef CBR_57600
+ { 57600, CBR_57600 },
+ #endif
+ #ifdef CBR_115200
+ { 115200, CBR_115200 },
+ #endif
+ #ifdef CBR_128000
+ { 128000, CBR_128000 },
+ #endif
+ #ifdef CBR_256000
+ { 256000, CBR_256000 },
+ #endif
+ { -1, -1}
+ };
+
+ inline int32_t IntToBaudrate(uint32_t baudrate)
+ {
+ for (unsigned int i = 0; i < sizeof(baudrates) / sizeof(P8PLATFORM::sbaudrate) - 1; i++)
+ {
+ if (baudrates[i].rate == (int32_t) baudrate)
+ return baudrates[i].symbol;
+ }
+
+ return -1;
+ };
+};
--- /dev/null
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+
+namespace P8PLATFORM
+{
+ class CEDIDParser
+ {
+ public:
+ static uint16_t GetPhysicalAddress(void);
+
+ static uint16_t GetPhysicalAddressFromEDID(unsigned char *data, size_t size)
+ {
+ return GetPhysicalAddressFromEDID((char *)data, size);
+ }
+
+ static uint16_t GetPhysicalAddressFromEDID(char *data, size_t size)
+ {
+ uint16_t iPA(0);
+
+ for (size_t iPtr = 0; data && size > 0 && iPtr < size - 4; iPtr++)
+ {
+ if (data[iPtr] == 0x03 &&
+ data[iPtr + 1] == 0x0C &&
+ data[iPtr + 2] == 0x0)
+ {
+ //found the hdmi marker
+ iPA = (data[iPtr + 3] << 8) + data[iPtr + 4];
+ break;
+ }
+ }
+
+ return iPA;
+ }
+ };
+}
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include "platform/util/edid.h"
+
+#include "windows.h"
+#include "setupapi.h"
+#include "initguid.h"
+#include "stdio.h"
+
+using namespace P8PLATFORM;
+
+static GUID MONITOR_GUID = { 0x4D36E96E, 0xE325, 0x11CE, { 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18 } };
+#define PA_MAX_REGENTRIES_TO_CHECK 1024
+
+uint16_t GetPhysicalAddressFromDevice(IN HDEVINFO hDevHandle, IN PSP_DEVINFO_DATA deviceInfoData)
+{
+ uint16_t iPA(0);
+
+ HKEY hDevRegKey = SetupDiOpenDevRegKey(hDevHandle, deviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_ALL_ACCESS);
+ if (hDevRegKey)
+ {
+ CHAR regEntryName[128];
+ DWORD regEntryNameLength(128);
+ DWORD type;
+ LONG retVal(ERROR_SUCCESS);
+
+ for (LONG ptr = 0; iPA == 0 && retVal == ERROR_SUCCESS && ptr < PA_MAX_REGENTRIES_TO_CHECK; ptr++)
+ {
+ BYTE regEntryData[1024];
+ DWORD regEntryDataSize = sizeof(regEntryData);
+
+ retVal = RegEnumValue(hDevRegKey, ptr, ®EntryName[0], ®EntryNameLength, NULL, &type, regEntryData, ®EntryDataSize);
+
+ if (retVal == ERROR_SUCCESS && !strcmp(regEntryName,"EDID"))
+ iPA = CEDIDParser::GetPhysicalAddressFromEDID(regEntryData, regEntryDataSize);
+ }
+ RegCloseKey(hDevRegKey);
+ }
+
+ return iPA;
+}
+
+uint16_t CEDIDParser::GetPhysicalAddress(void)
+{
+ HDEVINFO hDevHandle;
+ uint16_t iPA(0);
+ SP_DEVINFO_DATA deviceInfoData;
+
+ hDevHandle = SetupDiGetClassDevsEx(&MONITOR_GUID, NULL, NULL, DIGCF_PRESENT, NULL, NULL, NULL);
+ if (!hDevHandle)
+ return iPA;
+
+ for (int i=0; ERROR_NO_MORE_ITEMS != GetLastError(); i++)
+ {
+ memset(&deviceInfoData, 0, sizeof(SP_DEVINFO_DATA));
+ deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
+
+ if (SetupDiEnumDeviceInfo(hDevHandle,i, &deviceInfoData))
+ {
+ iPA = GetPhysicalAddressFromDevice(hDevHandle, &deviceInfoData);
+ }
+ }
+
+ return iPA;
+}
--- /dev/null
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; 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
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing <license@pulse-eight.com>
+ * http://www.pulse-eight.com/
+ * http://www.pulse-eight.net/
+ */
+
+#include "../sockets/serialport.h"
+#include "../util/baudrate.h"
+#include <p8-platform/util/timeutils.h>
+
+using namespace P8PLATFORM;
+
+void FormatWindowsError(int iErrorCode, std::string& strMessage)
+{
+ if (iErrorCode != ERROR_SUCCESS)
+ {
+ char strAddMessage[1024];
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, iErrorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), strAddMessage, 1024, NULL);
+ strMessage.append(": ");
+ strMessage.append(strAddMessage);
+ }
+}
+
+bool CSerialSocket::SetTimeouts(serial_socket_t socket, int* iError, DWORD iTimeoutMs)
+{
+ if (socket == INVALID_HANDLE_VALUE)
+ return false;
+
+ COMMTIMEOUTS cto;
+ if (!GetCommTimeouts(socket, &cto))
+ {
+ *iError = GetLastError();
+ return false;
+ }
+
+ if (iTimeoutMs == 0)
+ {
+ cto.ReadIntervalTimeout = MAXDWORD;
+ cto.ReadTotalTimeoutConstant = 0;
+ cto.ReadTotalTimeoutMultiplier = 0;
+ }
+ else
+ {
+ cto.ReadIntervalTimeout = 0;
+ cto.ReadTotalTimeoutConstant = iTimeoutMs;
+ cto.ReadTotalTimeoutMultiplier = 0;
+ }
+
+ if (!SetCommTimeouts(socket, &cto))
+ {
+ *iError = GetLastError();
+ return false;
+ }
+
+ return true;
+}
+
+void CSerialSocket::Close(void)
+{
+ if (IsOpen())
+ SerialSocketClose(m_socket);
+ m_socket = INVALID_SERIAL_SOCKET_VALUE;
+}
+
+void CSerialSocket::Shutdown(void)
+{
+ if (IsOpen())
+ SerialSocketClose(m_socket);
+ m_socket = INVALID_SERIAL_SOCKET_VALUE;
+}
+
+ssize_t CSerialSocket::Write(void* data, size_t len)
+{
+ return IsOpen() ? SerialSocketWrite(m_socket, &m_iError, data, len) : -1;
+}
+
+ssize_t CSerialSocket::Read(void* data, size_t len, uint64_t iTimeoutMs /* = 0 */)
+{
+ return IsOpen() ? SerialSocketRead(m_socket, &m_iError, data, len, iTimeoutMs) : -1;
+}
+
+bool CSerialSocket::Open(uint64_t iTimeoutMs /* = 0 */)
+{
+ iTimeoutMs = 0;
+ if (IsOpen())
+ return false;
+
+ std::string strComPath = "\\\\.\\" + m_strName;
+ CLockObject lock(m_mutex);
+ m_socket = CreateFile(strComPath.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
+ if (m_socket == INVALID_HANDLE_VALUE)
+ {
+ m_strError = "Unable to open COM port";
+ FormatWindowsError(GetLastError(), m_strError);
+ return false;
+ }
+
+ COMMCONFIG commConfig = {0};
+ DWORD dwSize = sizeof(commConfig);
+ commConfig.dwSize = dwSize;
+ if (GetDefaultCommConfig(strComPath.c_str(), &commConfig,&dwSize))
+ {
+ if (!SetCommConfig(m_socket, &commConfig,dwSize))
+ {
+ m_strError = "unable to set default config";
+ FormatWindowsError(GetLastError(), m_strError);
+ }
+ }
+ else
+ {
+ m_strError = "unable to get default config";
+ FormatWindowsError(GetLastError(), m_strError);
+ }
+
+ if (!SetupComm(m_socket, 64, 64))
+ {
+ m_strError = "unable to set up the com port";
+ FormatWindowsError(GetLastError(), m_strError);
+ }
+
+ if (!SetBaudRate(m_iBaudrate))
+ {
+ m_strError = "unable to set baud rate";
+ FormatWindowsError(GetLastError(), m_strError);
+ Close();
+ return false;
+ }
+
+ if (!SetTimeouts(m_socket, &m_iError, false))
+ {
+ m_strError = "unable to set timeouts";
+ FormatWindowsError(GetLastError(), m_strError);
+ Close();
+ return false;
+ }
+
+ m_bIsOpen = true;
+ return m_bIsOpen;
+}
+
+bool CSerialSocket::SetBaudRate(uint32_t baudrate)
+{
+ int32_t rate = IntToBaudrate(baudrate);
+ if (rate < 0)
+ m_iBaudrate = baudrate > 0 ? baudrate : 0;
+ else
+ m_iBaudrate = rate;
+
+ DCB dcb;
+ memset(&dcb,0,sizeof(dcb));
+ dcb.DCBlength = sizeof(dcb);
+ dcb.BaudRate = IntToBaudrate(m_iBaudrate);
+ dcb.fBinary = true;
+ dcb.fDtrControl = DTR_CONTROL_DISABLE;
+ dcb.fRtsControl = RTS_CONTROL_DISABLE;
+ dcb.fOutxCtsFlow = false;
+ dcb.fOutxDsrFlow = false;
+ dcb.fOutX = false;
+ dcb.fInX = false;
+ dcb.fAbortOnError = true;
+
+ if (m_iParity == SERIAL_PARITY_NONE)
+ dcb.Parity = NOPARITY;
+ else if (m_iParity == SERIAL_PARITY_EVEN)
+ dcb.Parity = EVENPARITY;
+ else
+ dcb.Parity = ODDPARITY;
+
+ if (m_iStopbits == SERIAL_STOP_BITS_TWO)
+ dcb.StopBits = TWOSTOPBITS;
+ else
+ dcb.StopBits = ONESTOPBIT;
+
+ dcb.ByteSize = (BYTE)m_iDatabits;
+
+ if(!SetCommState(m_socket,&dcb))
+ {
+ m_strError = "SetCommState failed";
+ FormatWindowsError(GetLastError(), m_strError);
+ return false;
+ }
+
+ return true;
+}
--- /dev/null
+// ISO C9x compliant stdint.h for Microsoft Visual Studio
+// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
+//
+// Copyright (c) 2006-2013 Alexander Chemeris
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the product nor the names of its contributors may
+// be used to endorse or promote products derived from this software
+// without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef _MSC_VER // [
+#error "Use this header only with Microsoft Visual C++ compilers!"
+#endif // _MSC_VER ]
+
+#ifndef _MSC_STDINT_H_ // [
+#define _MSC_STDINT_H_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif
+
+#if _MSC_VER >= 1600 // [
+#include <stdint.h>
+#else // ] _MSC_VER >= 1600 [
+
+#include <limits.h>
+
+// For Visual Studio 6 in C++ mode and for many Visual Studio versions when
+// compiling for ARM we should wrap <wchar.h> include with 'extern "C++" {}'
+// or compiler give many errors like this:
+// error C2733: second C linkage of overloaded function 'wmemchr' not allowed
+#ifdef __cplusplus
+extern "C" {
+#endif
+# include <wchar.h>
+#ifdef __cplusplus
+}
+#endif
+
+// Define _W64 macros to mark types changing their size, like intptr_t.
+#ifndef _W64
+# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
+# define _W64 __w64
+# else
+# define _W64
+# endif
+#endif
+
+
+// 7.18.1 Integer types
+
+// 7.18.1.1 Exact-width integer types
+
+// Visual Studio 6 and Embedded Visual C++ 4 doesn't
+// realize that, e.g. char has the same size as __int8
+// so we give up on __intX for them.
+#if (_MSC_VER < 1300)
+typedef signed char int8_t;
+typedef signed short int16_t;
+typedef signed int int32_t;
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
+#else
+typedef signed __int8 int8_t;
+typedef signed __int16 int16_t;
+typedef signed __int32 int32_t;
+typedef unsigned __int8 uint8_t;
+typedef unsigned __int16 uint16_t;
+typedef unsigned __int32 uint32_t;
+#endif
+typedef signed __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+
+
+// 7.18.1.2 Minimum-width integer types
+typedef int8_t int_least8_t;
+typedef int16_t int_least16_t;
+typedef int32_t int_least32_t;
+typedef int64_t int_least64_t;
+typedef uint8_t uint_least8_t;
+typedef uint16_t uint_least16_t;
+typedef uint32_t uint_least32_t;
+typedef uint64_t uint_least64_t;
+
+// 7.18.1.3 Fastest minimum-width integer types
+typedef int8_t int_fast8_t;
+typedef int16_t int_fast16_t;
+typedef int32_t int_fast32_t;
+typedef int64_t int_fast64_t;
+typedef uint8_t uint_fast8_t;
+typedef uint16_t uint_fast16_t;
+typedef uint32_t uint_fast32_t;
+typedef uint64_t uint_fast64_t;
+
+// 7.18.1.4 Integer types capable of holding object pointers
+#ifdef _WIN64 // [
+typedef signed __int64 intptr_t;
+typedef unsigned __int64 uintptr_t;
+#else // _WIN64 ][
+typedef _W64 signed int intptr_t;
+typedef _W64 unsigned int uintptr_t;
+#endif // _WIN64 ]
+
+// 7.18.1.5 Greatest-width integer types
+typedef int64_t intmax_t;
+typedef uint64_t uintmax_t;
+
+
+// 7.18.2 Limits of specified-width integer types
+
+#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259
+
+// 7.18.2.1 Limits of exact-width integer types
+#define INT8_MIN ((int8_t)_I8_MIN)
+#define INT8_MAX _I8_MAX
+#define INT16_MIN ((int16_t)_I16_MIN)
+#define INT16_MAX _I16_MAX
+#define INT32_MIN ((int32_t)_I32_MIN)
+#define INT32_MAX _I32_MAX
+#define INT64_MIN ((int64_t)_I64_MIN)
+#define INT64_MAX _I64_MAX
+#define UINT8_MAX _UI8_MAX
+#define UINT16_MAX _UI16_MAX
+#define UINT32_MAX _UI32_MAX
+#define UINT64_MAX _UI64_MAX
+
+// 7.18.2.2 Limits of minimum-width integer types
+#define INT_LEAST8_MIN INT8_MIN
+#define INT_LEAST8_MAX INT8_MAX
+#define INT_LEAST16_MIN INT16_MIN
+#define INT_LEAST16_MAX INT16_MAX
+#define INT_LEAST32_MIN INT32_MIN
+#define INT_LEAST32_MAX INT32_MAX
+#define INT_LEAST64_MIN INT64_MIN
+#define INT_LEAST64_MAX INT64_MAX
+#define UINT_LEAST8_MAX UINT8_MAX
+#define UINT_LEAST16_MAX UINT16_MAX
+#define UINT_LEAST32_MAX UINT32_MAX
+#define UINT_LEAST64_MAX UINT64_MAX
+
+// 7.18.2.3 Limits of fastest minimum-width integer types
+#define INT_FAST8_MIN INT8_MIN
+#define INT_FAST8_MAX INT8_MAX
+#define INT_FAST16_MIN INT16_MIN
+#define INT_FAST16_MAX INT16_MAX
+#define INT_FAST32_MIN INT32_MIN
+#define INT_FAST32_MAX INT32_MAX
+#define INT_FAST64_MIN INT64_MIN
+#define INT_FAST64_MAX INT64_MAX
+#define UINT_FAST8_MAX UINT8_MAX
+#define UINT_FAST16_MAX UINT16_MAX
+#define UINT_FAST32_MAX UINT32_MAX
+#define UINT_FAST64_MAX UINT64_MAX
+
+// 7.18.2.4 Limits of integer types capable of holding object pointers
+#ifdef _WIN64 // [
+# define INTPTR_MIN INT64_MIN
+# define INTPTR_MAX INT64_MAX
+# define UINTPTR_MAX UINT64_MAX
+#else // _WIN64 ][
+# define INTPTR_MIN INT32_MIN
+# define INTPTR_MAX INT32_MAX
+# define UINTPTR_MAX UINT32_MAX
+#endif // _WIN64 ]
+
+// 7.18.2.5 Limits of greatest-width integer types
+#define INTMAX_MIN INT64_MIN
+#define INTMAX_MAX INT64_MAX
+#define UINTMAX_MAX UINT64_MAX
+
+// 7.18.3 Limits of other integer types
+
+#ifdef _WIN64 // [
+# define PTRDIFF_MIN _I64_MIN
+# define PTRDIFF_MAX _I64_MAX
+#else // _WIN64 ][
+# define PTRDIFF_MIN _I32_MIN
+# define PTRDIFF_MAX _I32_MAX
+#endif // _WIN64 ]
+
+#define SIG_ATOMIC_MIN INT_MIN
+#define SIG_ATOMIC_MAX INT_MAX
+
+#ifndef SIZE_MAX // [
+# ifdef _WIN64 // [
+# define SIZE_MAX _UI64_MAX
+# else // _WIN64 ][
+# define SIZE_MAX _UI32_MAX
+# endif // _WIN64 ]
+#endif // SIZE_MAX ]
+
+// WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h>
+#ifndef WCHAR_MIN // [
+# define WCHAR_MIN 0
+#endif // WCHAR_MIN ]
+#ifndef WCHAR_MAX // [
+# define WCHAR_MAX _UI16_MAX
+#endif // WCHAR_MAX ]
+
+#define WINT_MIN 0
+#define WINT_MAX _UI16_MAX
+
+#endif // __STDC_LIMIT_MACROS ]
+
+
+// 7.18.4 Limits of other integer types
+
+#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260
+
+// 7.18.4.1 Macros for minimum-width integer constants
+
+#define INT8_C(val) val##i8
+#define INT16_C(val) val##i16
+#define INT32_C(val) val##i32
+#define INT64_C(val) val##i64
+
+#define UINT8_C(val) val##ui8
+#define UINT16_C(val) val##ui16
+#define UINT32_C(val) val##ui32
+#define UINT64_C(val) val##ui64
+
+// 7.18.4.2 Macros for greatest-width integer constants
+// These #ifndef's are needed to prevent collisions with <boost/cstdint.hpp>.
+// Check out Issue 9 for the details.
+#ifndef INTMAX_C // [
+# define INTMAX_C INT64_C
+#endif // INTMAX_C ]
+#ifndef UINTMAX_C // [
+# define UINTMAX_C UINT64_C
+#endif // UINTMAX_C ]
+
+#endif // __STDC_CONSTANT_MACROS ]
+
+#endif // _MSC_VER >= 1600 ]
+
+#endif // _MSC_STDINT_H_ ]
\ No newline at end of file
--- /dev/null
+project(pyCecClient)
+cmake_minimum_required(VERSION 2.8.9)
+
+# Python
+include(FindPythonLibs)
+find_package(PythonLibs)
+
+if (PYTHONLIBS_FOUND)
+ if (WIN32)
+ install(PROGRAMS pyCecClient.py
+ DESTINATION python/.)
+ else()
+ install(PROGRAMS pyCecClient.py
+ DESTINATION bin/.
+ RENAME pyCecClient)
+ endif()
+endif()
--- /dev/null
+#! /usr/bin/python
+## demo of the python-libcec API
+
+# This file is part of the libCEC(R) library.
+#
+# libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved.
+# libCEC(R) is an original work, containing original code.
+#
+# libCEC(R) is a trademark of Pulse-Eight Limited.
+#
+# This program is dual-licensed; 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
+#
+#
+# Alternatively, you can license this library under a commercial license,
+# please contact Pulse-Eight Licensing for more information.
+#
+# For more information contact:
+# Pulse-Eight Licensing <license@pulse-eight.com>
+# http://www.pulse-eight.com/
+# http://www.pulse-eight.net/
+
+import cec
+print(cec)
+
+class pyCecClient:
+ cecconfig = cec.libcec_configuration()
+ lib = {}
+ # don't enable debug logging by default
+ log_level = cec.CEC_LOG_TRAFFIC
+
+ # create a new libcec_configuration
+ def SetConfiguration(self):
+ self.cecconfig.strDeviceName = "pyLibCec"
+ self.cecconfig.bActivateSource = 0
+ self.cecconfig.deviceTypes.Add(cec.CEC_DEVICE_TYPE_RECORDING_DEVICE)
+ self.cecconfig.clientVersion = cec.LIBCEC_VERSION_CURRENT
+
+ def SetLogCallback(self, callback):
+ self.cecconfig.SetLogCallback(callback)
+
+ def SetKeyPressCallback(self, callback):
+ self.cecconfig.SetKeyPressCallback(callback)
+
+ def SetCommandCallback(self, callback):
+ self.cecconfig.SetCommandCallback(callback)
+
+ # detect an adapter and return the com port path
+ def DetectAdapter(self):
+ retval = None
+ adapters = self.lib.DetectAdapters()
+ for adapter in adapters:
+ print("found a CEC adapter:")
+ print("port: " + adapter.strComName)
+ print("vendor: " + hex(adapter.iVendorId))
+ print("product: " + hex(adapter.iProductId))
+ retval = adapter.strComName
+ return retval
+
+ # initialise libCEC
+ def InitLibCec(self):
+ self.lib = cec.ICECAdapter.Create(self.cecconfig)
+ # print libCEC version and compilation information
+ print("libCEC version " + self.lib.VersionToString(self.cecconfig.serverVersion) + " loaded: " + self.lib.GetLibInfo())
+
+ # search for adapters
+ adapter = self.DetectAdapter()
+ if adapter == None:
+ print("No adapters found")
+ else:
+ if self.lib.Open(adapter):
+ print("connection opened")
+ self.MainLoop()
+ else:
+ print("failed to open a connection to the CEC adapter")
+
+ # display the addresses controlled by libCEC
+ def ProcessCommandSelf(self):
+ addresses = self.lib.GetLogicalAddresses()
+ strOut = "Addresses controlled by libCEC: "
+ x = 0
+ notFirst = False
+ while x < 15:
+ if addresses.IsSet(x):
+ if notFirst:
+ strOut += ", "
+ strOut += self.lib.LogicalAddressToString(x)
+ if self.lib.IsActiveSource(x):
+ strOut += " (*)"
+ notFirst = True
+ x += 1
+ print(strOut)
+
+ # send an active source message
+ def ProcessCommandActiveSource(self):
+ self.lib.SetActiveSource()
+
+ # send a standby command
+ def ProcessCommandStandby(self):
+ self.lib.StandbyDevices(cec.CECDEVICE_BROADCAST)
+
+ # send a custom command
+ def ProcessCommandTx(self, data):
+ cmd = self.lib.CommandFromString(data)
+ print("transmit " + data)
+ if self.lib.Transmit(cmd):
+ print("command sent")
+ else:
+ print("failed to send command")
+
+ # scan the bus and display devices that were found
+ def ProcessCommandScan(self):
+ print("requesting CEC bus information ...")
+ strLog = "CEC bus information\n===================\n"
+ addresses = self.lib.GetActiveDevices()
+ activeSource = self.lib.GetActiveSource()
+ x = 0
+ while x < 15:
+ if addresses.IsSet(x):
+ vendorId = self.lib.GetDeviceVendorId(x)
+ physicalAddress = self.lib.GetDevicePhysicalAddress(x)
+ active = self.lib.IsActiveSource(x)
+ cecVersion = self.lib.GetDeviceCecVersion(x)
+ power = self.lib.GetDevicePowerStatus(x)
+ osdName = self.lib.GetDeviceOSDName(x)
+ strLog += "device #" + str(x) +": " + self.lib.LogicalAddressToString(x) + "\n"
+ strLog += "address: " + str(physicalAddress) + "\n"
+ strLog += "active source: " + str(active) + "\n"
+ strLog += "vendor: " + self.lib.VendorIdToString(vendorId) + "\n"
+ strLog += "CEC version: " + self.lib.CecVersionToString(cecVersion) + "\n"
+ strLog += "OSD name: " + osdName + "\n"
+ strLog += "power status: " + self.lib.PowerStatusToString(power) + "\n\n\n"
+ x += 1
+ print(strLog)
+
+ # main loop, ask for commands
+ def MainLoop(self):
+ runLoop = True
+ while runLoop:
+ command = raw_input("Enter command:").lower()
+ if command == 'q' or command == 'quit':
+ runLoop = False
+ elif command == 'self':
+ self.ProcessCommandSelf()
+ elif command == 'as' or command == 'activesource':
+ self.ProcessCommandActiveSource()
+ elif command == 'standby':
+ self.ProcessCommandStandby()
+ elif command == 'scan':
+ self.ProcessCommandScan()
+ elif command[:2] == 'tx':
+ self.ProcessCommandTx(command[3:])
+ print('Exiting...')
+
+ # logging callback
+ def LogCallback(self, level, time, message):
+ if level > self.log_level:
+ return 0
+
+ if level == cec.CEC_LOG_ERROR:
+ levelstr = "ERROR: "
+ elif level == cec.CEC_LOG_WARNING:
+ levelstr = "WARNING: "
+ elif level == cec.CEC_LOG_NOTICE:
+ levelstr = "NOTICE: "
+ elif level == cec.CEC_LOG_TRAFFIC:
+ levelstr = "TRAFFIC: "
+ elif level == cec.CEC_LOG_DEBUG:
+ levelstr = "DEBUG: "
+
+ print(levelstr + "[" + str(time) + "] " + message)
+ return 0
+
+ # key press callback
+ def KeyPressCallback(self, key, duration):
+ print("[key pressed] " + str(key))
+ return 0
+
+ # command received callback
+ def CommandCallback(self, cmd):
+ print("[command received] " + cmd)
+ return 0
+
+ def __init__(self):
+ self.SetConfiguration()
+
+# logging callback
+def log_callback(level, time, message):
+ return lib.LogCallback(level, time, message)
+
+# key press callback
+def key_press_callback(key, duration):
+ return lib.KeyPressCallback(key, duration)
+
+# command callback
+def command_callback(cmd):
+ return lib.CommandCallback(cmd)
+
+if __name__ == '__main__':
+ # initialise libCEC
+ lib = pyCecClient()
+ lib.SetLogCallback(log_callback)
+ lib.SetKeyPressCallback(key_press_callback)
+ lib.SetCommandCallback(command_callback)
+
+ # initialise libCEC and enter the main loop
+ lib.InitLibCec()
+
--- /dev/null
+@ECHO OFF
+
+rem Build libCEC for Windows
+
+SETLOCAL
+
+SET MYDIR=%~dp0
+SET BUILDARCH=%1
+SET BUILDTYPE=%2
+SET VSVERSION=%3
+SET INSTALLPATH=%4
+SET GENTYPE=%5
+IF [%5] == [] GOTO missingparams
+
+SET BUILDTARGET=%INSTALLPATH%\cmake\%BUILDARCH%
+SET TARGET=%INSTALLPATH%\%BUILDARCH%
+
+IF NOT EXIST "%MYDIR%..\src\platform\windows\build.cmd" (
+ ECHO "platform git submodule was not checked out"
+ GOTO exit
+)
+
+ECHO Build platform library for %BUILDARCH%
+CALL %MYDIR%..\src\platform\windows\build-lib.cmd %BUILDARCH% %BUILDTYPE% %VSVERSION% %INSTALLPATH%
+del /s /f /q %BUILDTARGET%
+
+ECHO Build libCEC for %BUILDARCH%
+CALL %MYDIR%..\support\windows\cmake\generate.cmd %BUILDARCH% %GENTYPE% %MYDIR%..\ %BUILDTARGET% %TARGET% %BUILDTYPE% %VSVERSION%
+IF "%GENTYPE%" == "nmake" (
+ CALL %MYDIR%..\support\windows\cmake\build.cmd %BUILDARCH% %BUILDTARGET% %VSVERSION%
+ IF NOT EXIST "%TARGET%\cec.dll" (
+ echo "Failed to build %TARGET%\cec.dll"
+ exit /b 1
+ )
+)
+
+exit /b 0
+
+:missingparams
+ECHO "build-lib.cmd requires 4 parameters"
+
+:exit
+exit 1
\ No newline at end of file
--- /dev/null
+@ECHO OFF
+
+rem Build libCEC for Windows
+
+SETLOCAL
+
+SET MYDIR=%~dp0
+SET BUILDTYPE=Release
+SET VSVERSION=12
+SET INSTALLPATH=%MYDIR%..\build
+
+IF NOT EXIST "%MYDIR%..\support\windows\cmake\build.cmd" (
+ ECHO "support git submodule was not checked out"
+ GOTO exit
+)
+
+IF NOT EXIST "%MYDIR%..\src\platform\windows\build.cmd" (
+ ECHO "platform git submodule was not checked out"
+ GOTO exit
+)
+
+rmdir /s /q %MYDIR%..\build
+
+FOR %%T IN (amd64 x86) DO (
+ CALL %MYDIR%build-lib.cmd %%T %BUILDTYPE% %VSVERSION% %INSTALLPATH% nmake
+ IF NOT ERRORLEVEL 0 (
+ GOTO builderror
+ )
+)
+
+rmdir /s /q %MYDIR%..\build\cmake
+exit /b 0
+
+:builderror
+echo "Failed to build"
+
+:exit
+exit /b 1
\ No newline at end of file
--- /dev/null
+@echo off
+
+set EXITCODE=1
+SET MYDIR=%~dp0
+
+rem Check for support folder
+IF NOT EXIST "%MYDIR%..\support\windows\p8-usbcec-driver-installer.exe" (
+ echo "support submodule was not checked out"
+ goto RETURNEXIT
+)
+
+rem Check for NSIS
+IF EXIST "%ProgramFiles%\NSIS\makensis.exe" (
+ set NSIS="%ProgramFiles%\NSIS\makensis.exe"
+) ELSE IF EXIST "%ProgramFiles(x86)%\NSIS\makensis.exe" (
+ set NSIS="%ProgramFiles(x86)%\NSIS\makensis.exe"
+) ELSE GOTO NONSIS
+
+rem Check for VC12
+IF "%VS120COMNTOOLS%"=="" (
+ set COMPILER12="%ProgramFiles%\Microsoft Visual Studio 12.0\Common7\IDE\devenv.com"
+) ELSE IF EXIST "%VS120COMNTOOLS%\..\IDE\VCExpress.exe" (
+ set COMPILER12="%VS120COMNTOOLS%\..\IDE\VCExpress.exe"
+) ELSE IF EXIST "%VS120COMNTOOLS%\..\IDE\devenv.com" (
+ set COMPILER12="%VS120COMNTOOLS%\..\IDE\devenv.com"
+) ELSE GOTO NOSDK11
+
+rmdir /s /q %MYDIR%..\build
+call build.cmd
+IF NOT ERRORLEVEL 0 (
+ GOTO ERRORCREATINGINSTALLER
+)
+
+copy "%MYDIR%..\support\windows\p8-usbcec-driver-installer.exe" "%MYDIR%..\build\."
+cd "%MYDIR%..\project"
+
+rem Skip to libCEC/x86 when we're running on win32
+if "%PROCESSOR_ARCHITECTURE%"=="x86" if "%PROCESSOR_ARCHITEW6432%"=="" goto libcecx86
+
+rem Compile libCEC and cec-client x64
+echo. Cleaning libCEC (x64)
+%COMPILER12% libcec.sln /Clean "Release|x64"
+echo. Compiling libCEC (x64)
+%COMPILER12% libcec.sln /Build "Release|x64" /Project LibCecSharp
+%COMPILER12% libcec.sln /Build "Release|x64"
+echo. Compiling .Net applications
+cd "%MYDIR%..\src\dotnet\project"
+%COMPILER12% cec-dotnet.sln /Build "Release|x64"
+copy ..\build\x64\CecSharpTester.exe %MYDIR%..\build\amd64\CecSharpTester.exe
+copy ..\build\x64\cec-tray.exe %MYDIR%..\build\amd64\cec-tray.exe
+
+:libcecx86
+rem Compile libCEC and cec-client Win32
+cd "%MYDIR%..\project"
+echo. Cleaning libCEC (x86)
+%COMPILER12% libcec.sln /Clean "Release|x86"
+echo. Compiling libCEC (x86)
+%COMPILER12% libcec.sln /Build "Release|x86" /Project LibCecSharp
+%COMPILER12% libcec.sln /Build "Release|x86"
+echo. Compiling .Net applications
+cd "%MYDIR%..\src\dotnet\project"
+%COMPILER12% cec-dotnet.sln /Build "Release|x86"
+copy ..\build\x86\CecSharpTester.exe %MYDIR%..\build\x86\CecSharpTester.exe
+copy ..\build\x86\cec-tray.exe %MYDIR%..\build\x86\cec-tray.exe
+cd "%MYDIR%..\project"
+
+rem Clean things up before creating the installer
+del /q /f %MYDIR%..\build\x86\LibCecSharp.pdb
+del /q /f %MYDIR%..\build\amd64\LibCecSharp.pdb
+
+rem Check for sign-binary.cmd, only present on the Pulse-Eight production build system
+rem Calls signtool.exe and signs the DLLs with Pulse-Eight's code signing key
+IF NOT EXIST "..\support\private\sign-binary.cmd" GOTO CREATEINSTALLER
+echo. Signing all binaries
+CALL ..\support\private\sign-binary.cmd %MYDIR%..\build\x86\cec.dll
+CALL ..\support\private\sign-binary.cmd %MYDIR%..\build\x86\LibCecSharp.dll
+CALL ..\support\private\sign-binary.cmd %MYDIR%..\build\x86\cec-client.exe
+CALL ..\support\private\sign-binary.cmd %MYDIR%..\build\x86\cecc-client.exe
+CALL ..\support\private\sign-binary.cmd %MYDIR%..\build\x86\cec-tray.exe
+CALL ..\support\private\sign-binary.cmd %MYDIR%..\build\x86\CecSharpTester.exe
+CALL ..\support\private\sign-binary.cmd %MYDIR%..\build\amd64\cec.dll
+CALL ..\support\private\sign-binary.cmd %MYDIR%..\build\amd64\LibCecSharp.dll
+CALL ..\support\private\sign-binary.cmd %MYDIR%..\build\amd64\cec-client.exe
+CALL ..\support\private\sign-binary.cmd %MYDIR%..\build\amd64\cecc-client.exe
+CALL ..\support\private\sign-binary.cmd %MYDIR%..\build\amd64\cec-tray.exe
+CALL ..\support\private\sign-binary.cmd %MYDIR%..\build\amd64\CecSharpTester.exe
+
+:CREATEINSTALLER
+echo. Creating the installer
+cd %MYDIR%..\build\x86
+copy cec.dll libcec.dll
+cd ..\amd64
+copy cec.dll cec.x64.dll
+cd %MYDIR%..\project
+%NSIS% /V1 /X"SetCompressor /FINAL lzma" "libCEC.nsi"
+
+FOR /F "delims=" %%F IN ('dir /b /s "%MYDIR%..\build\libCEC-*.exe" 2^>nul') DO SET INSTALLER=%%F
+IF [%INSTALLER%] == [] GOTO :ERRORCREATINGINSTALLER
+
+rem Sign the installer if sign-binary.cmd exists
+IF EXIST "..\support\private\sign-binary.cmd" (
+ echo. Signing the installer binaries
+ CALL ..\support\private\sign-binary.cmd %INSTALLER%
+)
+
+echo. The installer can be found here: %INSTALLER%
+set EXITCODE=0
+GOTO EXIT
+
+:NOSDK11
+echo. Visual Studio 2012 was not found on your system.
+GOTO EXIT
+
+:NOSIS
+echo. NSIS could not be found on your system.
+GOTO EXIT
+
+:NODDK
+echo. Windows DDK could not be found on your system
+GOTO EXIT
+
+:ERRORCREATINGINSTALLER
+echo. The installer could not be created. The most likely cause is that something went wrong while compiling.
+GOTO RETURNEXIT
+
+:EXIT
+cd %MYDIR%
+
+:RETURNEXIT
+exit /b %EXITCODE%
+pause
\ No newline at end of file
--- /dev/null
+@ECHO OFF
+
+rem Generate Visual Studio projects for libCEC
+
+SETLOCAL
+
+SET MYDIR=%~dp0
+SET BUILDTYPE=Debug
+SET VSVERSION=12
+SET INSTALLPATH=%MYDIR%..\build
+
+IF NOT EXIST "%MYDIR%..\support\windows\cmake\build.cmd" (
+ ECHO "support git submodule was not checked out"
+ GOTO exit
+)
+
+IF NOT EXIST "%MYDIR%..\src\platform\windows\build.cmd" (
+ ECHO "platform git submodule was not checked out"
+ GOTO exit
+)
+
+del /s /f /q %MYDIR%..\build
+
+FOR %%T IN (amd64 x86) DO (
+ CALL %MYDIR%build-lib.cmd %%T %BUILDTYPE% %VSVERSION% %INSTALLPATH% vs
+)
+
+ECHO Visual Studio solutions can be found in:
+ECHO 32 bits: %MYDIR%..\build\cmake\x86\libcec.sln
+ECHO 64 bits: %MYDIR%..\build\cmake\amd64\libcec.sln
+ECHO.
+ECHO These projects only compile in %BUILDTYPE% mode
+
+:exit