Merge branch 'master' into release
authorLars Op den Kamp <lars@opdenkamp.eu>
Fri, 9 Dec 2011 12:48:22 +0000 (13:48 +0100)
committerLars Op den Kamp <lars@opdenkamp.eu>
Fri, 9 Dec 2011 12:48:22 +0000 (13:48 +0100)
48 files changed:
.gitignore
ChangeLog
README
configure.ac
debian/changelog
include/cec.h
include/cecc.h
include/cectypes.h
project/CecSharpClient.sln [new file with mode: 0644]
project/LibCecSharp.vcxproj [new file with mode: 0644]
project/LibCecSharp.vcxproj.filters [new file with mode: 0644]
project/create-installer.cmd
project/libCEC.nsi
project/libcec.rc
project/libcec.sln
project/testclient.rc
src/CecSharpTester/AssemblyInfo.cs [new file with mode: 0644]
src/CecSharpTester/CecSharpClient.cs [new file with mode: 0644]
src/CecSharpTester/CecSharpClient.csproj [new file with mode: 0644]
src/LibCecSharp/AssemblyInfo.cpp [new file with mode: 0644]
src/LibCecSharp/LibCecSharp.cpp [new file with mode: 0644]
src/LibCecSharp/Stdafx.cpp [new file with mode: 0644]
src/LibCecSharp/Stdafx.h [new file with mode: 0644]
src/LibCecSharp/resource.h [new file with mode: 0644]
src/lib/AdapterCommunication.cpp
src/lib/AdapterCommunication.h
src/lib/AdapterDetection.cpp
src/lib/CECProcessor.cpp
src/lib/CECProcessor.h
src/lib/LibCEC.cpp
src/lib/LibCEC.h
src/lib/LibCECC.cpp
src/lib/devices/CECAudioSystem.cpp
src/lib/devices/CECAudioSystem.h
src/lib/devices/CECBusDevice.cpp
src/lib/devices/CECBusDevice.h
src/lib/devices/CECPlaybackDevice.cpp
src/lib/devices/CECPlaybackDevice.h
src/lib/devices/CECRecordingDevice.cpp
src/lib/devices/CECRecordingDevice.h
src/lib/implementations/ANCommandHandler.cpp
src/lib/implementations/CECCommandHandler.cpp
src/lib/implementations/CECCommandHandler.h
src/lib/implementations/SLCommandHandler.cpp
src/lib/implementations/SLCommandHandler.h
src/lib/platform/linux/serialport.cpp
src/lib/platform/serialport.h
src/testclient/main.cpp

index e196aa93c1abec77ca760b5e01a2aad495bc0892..2ad44d538bcec269395fe1118fe4b0393a5eac47 100644 (file)
@@ -1,5 +1,6 @@
 .project
 .cproject
+*.manifest
 
 aclocal.m4
 autom4te.cache
@@ -25,18 +26,28 @@ libcec.pdb
 cec-client.exe
 cec-client.ilk
 cec-client.pdb
+CecSharpClient.exe
+CecSharpClient.pdb
+CecSharpClient.vshost.exe
+CecSharpClient.vshost.exe.manifest
+
+LibCecSharp.dll
+LibCecSharp.ilk
+LibCecSharp.pdb
 
 build
 
 include/boost
 
-project/boost-1_46_1-xbmc-win32
+project/bin
 project/Debug/
+project/Release/
 project/ipch/
 project/libcec.sdf
 project/libcec.suo
-project/libcec.vcxproj.user
-project/testclient.vcxproj.user
+project/obj
+project/Properties
+project/*.user
 
 src/lib/.deps
 src/lib/.libs
@@ -59,6 +70,7 @@ src/testclient/.libs
 src/testclient/cec-client
 src/testclient/*.o
 
+src/CecSharpTester/obj
 
 /dpinst-x86.exe
 /dpinst-amd64.exe
index 57b6228d8dd841b720a1b4372b8906831a1644f9..c24e40090915e5c0880c72a00d24f241c9ee3042 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,87 @@
+libcec (1.3-1) unstable; urgency=low
+
+  * changed/added:
+    * make libudev optional. if libudev is not available on linux, adapter
+      autodetection will also not be available. fixes compilation on Hardy/ATV1
+    * added a C++ CLR wrapper for libCEC, so libCEC can be used by any .NET
+      language
+    * added vendor support for LG
+    * added vendor support for Philips
+    * added vendor support for Yamaha
+    * added vendor support for Onkyo
+    * added 'scan' command to cec-client, that displays info about devices on
+      the bus. made all ToString() methods available on the interface.
+    * added '-s' or '--single-command' to cec-client. starting cec-client with
+      this parameter executes a single command in cec-client and does not power
+      on devices on startup and power them off on exit. this way, you can use
+      cec-client in a shell script. since there's some handshaking involved at
+      startup, this is not very fast. to execute a command and only display the
+      result and any error/warning, execute it with
+      RESULT=`echo command | cec-client -s -d 3` (on linux/osx, win32 batch
+      files are a bit different)
+    * added HDMI port ('-p' or '--port') and base device ('-b' or '--base') to
+      cec-client's parameters
+    * handle image view on and text view on
+    * handle routing information and report physical address opcodes
+    * handle audio status updates
+    * send ping and bootloader commands via the output queue
+    * scan the CEC bus for devices when starting libcec
+    * pass all commands that are directed at libcec to listeners
+  * interface changes:
+    * added GetActiveSource()/cec_get_active_source()
+    * added IsActiveSource()/cec_is_active_source()
+    * added GetDevicePhysicalAddress()/cec_get_device_physical_address()
+    * added GetDeviceOSDName()/cec_get_osd_name()
+    * added SendKeypress()/cec_send_keypress() and SendKeyRelease()/
+      cec_send_key_release()
+    * added VolumeUp()/cec_volume_up(), VolumeDown()/cec_volume_down(),
+      MuteAudio()/cec_mute_audio()
+    * added GetActiveDevices()/cec_get_active_devices(), IsActiveDevice()/
+      cec_is_active_device(), IsActiveDeviceType()/cec_is_active_device_type().
+    * added SetHDMIPort()/cec_set_hdmi_port(). devices are now detected on load
+      and when a device with the same physical address is detected, libcec will
+      use the selected hdmi port on that device. should fix source selection on
+      other devices, like an amplifier
+    * added a hook in libcec for physical address autodetection
+  * fixed:
+    * don't request the physical address from the tv (it's always 0x0000)
+    * set the proper ackmask before doing anything else
+    * don't unlock the transmit mutex in CCECProcessor while waiting for an
+      answer
+    * fix device polling
+    * refactor CEC read/write. keep a single lock for all writes, not one per
+      device
+    * ignore other data while waiting for a response
+    * retry failed tranmissions
+    * don't delete a message before it's been sent when starting the bootloader
+    * or when sending a ping
+    * fixed possible segfault when switching the command handler after a vendor
+    * id changed
+    * handle audio opcodes correctly
+    * inactive source should be directly addressed at the TV
+    * don't report a changed physical address when it hasn't changed
+    * routing information sets the stream path, not the physical address
+    * don't scan the whole bus in CCECProcessor::IsActiveDeviceType()
+    * don't request the vendor id from devices that are handled by libcec
+    * mark device status as present when a command was received from a device
+    * always send a power on command in CCECBusDevice::PowerOn()
+    * don't request updates statusses unless needed
+    * report physical address sends 3 parameters, not 2. check whether the
+      device type is correct
+    * devices can send vendor commands from other vendors, so don't assume the
+      device is of a certain vendor when it sends commands with a vendor id
+    * thread safety fixes. bugzid: 19
+    * clear any previous input when opening a connection to the adapter.
+      bugzid: 54
+    * use the correct source address in CSLCommandHandler::HandleVendorCommand()
+    * uncorrected CEC_OPCODE_DEVICE_VENDOR_ID. closes #5
+    * renamed enum methods. fixes potential macro collision with isset().
+      thanks davilla
+    * don't change the active device when receiving stream path changed
+      messages. fixes wrong source selection when powering after the TV.
+
+ -- Pulse-Eight Packaging <packaging@pulse-eight.com>  Fri, 09 Dec 2011 12:16:00 +0100
+
 libcec (1.2-1) unstable; urgency=low
 
   * bugfixes:
diff --git a/README b/README
index 6c23712ff3c8a82c0c22f15d54e653ab231a3f41..5ef90e3c5f830551c79b8b23a4c46ab7ed973df1 100644 (file)
--- a/README
+++ b/README
@@ -22,6 +22,12 @@ Test the device:
 
 For developers:
 * see /include/cec.h for the C++ API and /include/cecc.h for the C version.
+* see src/testclient/main.cpp for an example
+
+For .NET developers:
+* build project/libcec.sln first
+* add a reference to LibCecSharp.dll
+* see src\CecSharpTester\CecSharpClient.cs for an example
 
 If you wish to contribute to this project, you must first sign our contributors agreement
 Please see http://www.pulse-eight.net/contributors for more information
\ No newline at end of file
index e961c1b2e6e1837a92d929d74749a8d04b91dd2b..6c8c7fda33a0c5ae35968149defae2b53c73ef48 100644 (file)
@@ -1,19 +1,26 @@
-AC_INIT([libcec], 1:2:0)
+AC_INIT([libcec], 1:3:0)
 AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION)
 
 AC_PROG_CXX
 AC_PROG_LIBTOOL
 
+has_libudev="yes"
 case "${host}" in
   *-*-linux*)
-    AC_SEARCH_LIBS([udev_new], [udev],, AC_MSG_ERROR("required library 'udev' is missing"))
-    REQUIRES="udev"
+    PKG_CHECK_MODULES([UDEV],[libudev],,[has_libudev="no";AC_MSG_WARN("library 'udev' is missing - adapter detection will not be available")])
     ;;
   *-apple-darwin*)
+    has_libudev="no";
     LIBS+="-framework CoreVideo -framework IOKit"
     ;;
 esac
 
+if test "x$has_libudev" != "xno"; then
+  INCLUDES="$INCLUDES $UDEV_CFLAGS";LIBS="$LIBS $UDEV_LIBS"
+  AC_DEFINE([HAVE_LIBUDEV],[1],["Define to 1 if libudev is installed"])
+  REQUIRES="udev"
+fi
+
 AC_SEARCH_LIBS([pthread_create],[pthread],, AC_MSG_ERROR("required library 'pthread' is missing"))
 
 libs_pre_dl=$LIBS
index 57b6228d8dd841b720a1b4372b8906831a1644f9..c24e40090915e5c0880c72a00d24f241c9ee3042 100644 (file)
@@ -1,3 +1,87 @@
+libcec (1.3-1) unstable; urgency=low
+
+  * changed/added:
+    * make libudev optional. if libudev is not available on linux, adapter
+      autodetection will also not be available. fixes compilation on Hardy/ATV1
+    * added a C++ CLR wrapper for libCEC, so libCEC can be used by any .NET
+      language
+    * added vendor support for LG
+    * added vendor support for Philips
+    * added vendor support for Yamaha
+    * added vendor support for Onkyo
+    * added 'scan' command to cec-client, that displays info about devices on
+      the bus. made all ToString() methods available on the interface.
+    * added '-s' or '--single-command' to cec-client. starting cec-client with
+      this parameter executes a single command in cec-client and does not power
+      on devices on startup and power them off on exit. this way, you can use
+      cec-client in a shell script. since there's some handshaking involved at
+      startup, this is not very fast. to execute a command and only display the
+      result and any error/warning, execute it with
+      RESULT=`echo command | cec-client -s -d 3` (on linux/osx, win32 batch
+      files are a bit different)
+    * added HDMI port ('-p' or '--port') and base device ('-b' or '--base') to
+      cec-client's parameters
+    * handle image view on and text view on
+    * handle routing information and report physical address opcodes
+    * handle audio status updates
+    * send ping and bootloader commands via the output queue
+    * scan the CEC bus for devices when starting libcec
+    * pass all commands that are directed at libcec to listeners
+  * interface changes:
+    * added GetActiveSource()/cec_get_active_source()
+    * added IsActiveSource()/cec_is_active_source()
+    * added GetDevicePhysicalAddress()/cec_get_device_physical_address()
+    * added GetDeviceOSDName()/cec_get_osd_name()
+    * added SendKeypress()/cec_send_keypress() and SendKeyRelease()/
+      cec_send_key_release()
+    * added VolumeUp()/cec_volume_up(), VolumeDown()/cec_volume_down(),
+      MuteAudio()/cec_mute_audio()
+    * added GetActiveDevices()/cec_get_active_devices(), IsActiveDevice()/
+      cec_is_active_device(), IsActiveDeviceType()/cec_is_active_device_type().
+    * added SetHDMIPort()/cec_set_hdmi_port(). devices are now detected on load
+      and when a device with the same physical address is detected, libcec will
+      use the selected hdmi port on that device. should fix source selection on
+      other devices, like an amplifier
+    * added a hook in libcec for physical address autodetection
+  * fixed:
+    * don't request the physical address from the tv (it's always 0x0000)
+    * set the proper ackmask before doing anything else
+    * don't unlock the transmit mutex in CCECProcessor while waiting for an
+      answer
+    * fix device polling
+    * refactor CEC read/write. keep a single lock for all writes, not one per
+      device
+    * ignore other data while waiting for a response
+    * retry failed tranmissions
+    * don't delete a message before it's been sent when starting the bootloader
+    * or when sending a ping
+    * fixed possible segfault when switching the command handler after a vendor
+    * id changed
+    * handle audio opcodes correctly
+    * inactive source should be directly addressed at the TV
+    * don't report a changed physical address when it hasn't changed
+    * routing information sets the stream path, not the physical address
+    * don't scan the whole bus in CCECProcessor::IsActiveDeviceType()
+    * don't request the vendor id from devices that are handled by libcec
+    * mark device status as present when a command was received from a device
+    * always send a power on command in CCECBusDevice::PowerOn()
+    * don't request updates statusses unless needed
+    * report physical address sends 3 parameters, not 2. check whether the
+      device type is correct
+    * devices can send vendor commands from other vendors, so don't assume the
+      device is of a certain vendor when it sends commands with a vendor id
+    * thread safety fixes. bugzid: 19
+    * clear any previous input when opening a connection to the adapter.
+      bugzid: 54
+    * use the correct source address in CSLCommandHandler::HandleVendorCommand()
+    * uncorrected CEC_OPCODE_DEVICE_VENDOR_ID. closes #5
+    * renamed enum methods. fixes potential macro collision with isset().
+      thanks davilla
+    * don't change the active device when receiving stream path changed
+      messages. fixes wrong source selection when powering after the TV.
+
+ -- Pulse-Eight Packaging <packaging@pulse-eight.com>  Fri, 09 Dec 2011 12:16:00 +0100
+
 libcec (1.2-1) unstable; urgency=low
 
   * bugfixes:
index 7a306dddc82f37d4d26e8c68132af1c638f61e9a..88381c4d54fc81bf816bbd77279f159e091d0fa9 100644 (file)
@@ -137,6 +137,20 @@ namespace CEC
      */
     virtual bool SetPhysicalAddress(uint16_t iPhysicalAddress = CEC_DEFAULT_PHYSICAL_ADDRESS) = 0;
 
+    /*!
+     * @brief Enable physical address detection (if the connected adapter supports this).
+     * @return True when physical address detection was enabled, false otherwise.
+     */
+    virtual bool EnablePhysicalAddressDetection(void) = 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 Power on the connected CEC capable devices.
      * @param address The logical address to power on.
@@ -237,12 +251,108 @@ namespace CEC
      */
     virtual cec_power_status GetDevicePowerStatus(cec_logical_address iAddress) = 0;
 
+    /*!
+     * @brief Get the physical address of the device with the given logical address.
+     * @param iLogicalAddress The device to get the vendor id for.
+     * @return The physical address or 0 if it wasn't found.
+     */
+    virtual uint16_t GetDevicePhysicalAddress(cec_logical_address iAddress) = 0;
+
     /*!
      * @brief Sends a POLL message to a device.
      * @param iAddress The device to send the message to.
      * @return True if the POLL was acked, false otherwise.
      */
     virtual bool PollDevice(cec_logical_address iAddress) = 0;
+
+    /*!
+     * @return The devices that are active on the bus and not handled by libcec.
+     */
+    virtual cec_logical_addresses GetActiveDevices(void) = 0;
+
+    /*!
+     * @brief Check whether a device is active on the bus.
+     * @param iAddress The address to check.
+     * @return True when active, false otherwise.
+     */
+    virtual bool IsActiveDevice(cec_logical_address iAddress) = 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 bWait Wait for the response of the audiosystem when true.
+     * @return The new audio status.
+     */
+    virtual uint8_t VolumeUp(bool bWait = true) = 0;
+
+    /*!
+     * @brief Sends a volume down keypress to an audiosystem if it's present.
+     * @param bWait Wait for the response of the audiosystem when true.
+     * @return The new audio status.
+     */
+    virtual uint8_t VolumeDown(bool bWait = true) = 0;
+
+    /*!
+     * @brief Sends a mute keypress to an audiosystem if it's present.
+     * @param bWait Wait for the response of the audiosystem when true.
+     * @return The new audio status.
+     */
+    virtual uint8_t MuteAudio(bool bWait = true) = 0;
+
+    /*!
+     * @brief Send a keypress to a device on the CEC bus.
+     * @param iDestination The address 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 address to send the message to.
+     * @param bWait True to wait for a response, false otherwise.
+     * @return True when the keypress 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 iAddress The device to get the OSD name for.
+     * @return The OSD name.
+     */
+    virtual cec_osd_name 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 iAddress The address to check.
+     * @return True when it is the active source, false otherwise.
+     */
+    virtual bool IsActiveSource(cec_logical_address iAddress) = 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) = 0;
+
   };
 };
 
index 0b0f2fecbc3cc5a6bcf5cbd2c6a2d305135bb461..37bccc187b23aefc856d4dac18d4a32ad6b3cf61 100644 (file)
@@ -95,8 +95,26 @@ extern DECLSPEC int cec_set_active_source(CEC::cec_device_type type);
 extern DECLSPEC int cec_set_active_source(cec_device_type type);
 #endif
 
+#ifdef __cplusplus
+extern DECLSPEC int cec_set_deck_control_mode(CEC::cec_deck_control_mode mode, int bSendUpdate);
+#else
+extern DECLSPEC int cec_set_deck_control_mode(cec_deck_control_mode mode, int bSendUpdate);
+#endif
+
+#ifdef __cplusplus
+extern DECLSPEC int cec_set_deck_info(CEC::cec_deck_info info, int bSendUpdate);
+#else
+extern DECLSPEC int cec_set_deck_info(cec_deck_info info, int bSendUpdate);
+#endif
+
 extern DECLSPEC int cec_set_inactive_view(void);
 
+#ifdef __cplusplus
+extern DECLSPEC int cec_set_menu_state(CEC::cec_menu_state state, int bSendUpdate);
+#else
+extern DECLSPEC int cec_set_menu_state(cec_menu_state state, int bSendUpdate);
+#endif
+
 #ifdef __cplusplus
 extern DECLSPEC int cec_get_next_log_message(CEC::cec_log_message *message);
 #else
@@ -155,6 +173,24 @@ extern DECLSPEC uint64_t cec_get_device_vendor_id(CEC::cec_logical_address iLogi
 extern DECLSPEC uint64_t cec_get_device_vendor_id(cec_logical_address iLogicalAddress);
 #endif
 
+#ifdef __cplusplus
+extern DECLSPEC uint16_t cec_get_device_physical_address(CEC::cec_logical_address iLogicalAddress);
+#else
+extern DECLSPEC uint16_t cec_get_device_physical_address(cec_logical_address iLogicalAddress);
+#endif
+
+#ifdef __cplusplus
+extern DECLSPEC CEC::cec_logical_address cec_get_active_source(void);
+#else
+extern DECLSPEC cec_logical_address cec_get_active_source(void);
+#endif
+
+#ifdef __cplusplus
+extern DECLSPEC int cec_is_active_source(CEC::cec_logical_address iAddress);
+#else
+extern DECLSPEC int cec_is_active_source(cec_logical_address iAddress);
+#endif
+
 #ifdef __cplusplus
 extern DECLSPEC CEC::cec_power_status cec_get_device_power_status(CEC::cec_logical_address iLogicalAddress);
 #else
@@ -167,6 +203,56 @@ extern DECLSPEC int cec_poll_device(CEC::cec_logical_address iLogicalAddress);
 extern DECLSPEC int cec_poll_device(cec_logical_address iLogicalAddress);
 #endif
 
+#ifdef __cplusplus
+extern DECLSPEC CEC::cec_logical_addresses cec_get_active_devices(void);
+#else
+extern DECLSPEC cec_logical_addresses cec_get_active_devices(void);
+#endif
+
+#ifdef __cplusplus
+extern DECLSPEC int cec_is_active_device(CEC::cec_logical_address iAddress);
+#else
+extern DECLSPEC int cec_is_active_device(cec_logical_address iAddress);
+#endif
+
+#ifdef __cplusplus
+extern DECLSPEC int cec_is_active_device_type(CEC::cec_device_type type);
+#else
+extern DECLSPEC int cec_is_active_device_type(cec_device_type type);
+#endif
+
+#ifdef __cplusplus
+extern DECLSPEC int cec_set_hdmi_port(CEC::cec_logical_address iBaseDevice, uint8_t iPort);
+#else
+extern DECLSPEC int cec_set_hdmi_port(cec_logical_address iBaseDevice, uint8_t iPort);
+#endif
+
+extern DECLSPEC int cec_volume_up(int bWait);
+
+extern DECLSPEC int cec_volume_down(int bWait);
+
+extern DECLSPEC int cec_mute_audio(int bWait);
+
+#ifdef __cplusplus
+extern DECLSPEC int cec_send_keypress(CEC::cec_logical_address iDestination, CEC::cec_user_control_code key, int bWait);
+#else
+extern DECLSPEC int cec_send_keypress(cec_logical_address iDestination, cec_user_control_code key, int bWait);
+#endif
+
+#ifdef __cplusplus
+extern DECLSPEC int cec_send_key_release(CEC::cec_logical_address iDestination, int bWait);
+#else
+extern DECLSPEC int cec_send_key_release(cec_logical_address iDestination, int bWait);
+#endif
+
+#ifdef __cplusplus
+extern DECLSPEC CEC::cec_osd_name cec_get_device_osd_name(CEC::cec_logical_address iAddress);
+#else
+extern DECLSPEC cec_osd_name cec_get_device_osd_name(cec_logical_address iAddress);
+#endif
+
+extern DECLSPEC int cec_enable_physical_address_detection(void);
+
 #ifdef __cplusplus
 };
 #endif
index 3f2fb9825a783c0dcc8acc50652ce4647ba32445..f2b2f02b3c9c49fc4060474833ef792fdc49a7f7 100644 (file)
@@ -55,46 +55,64 @@ extern "C" {
 namespace CEC {
 #endif
 
+//default physical address 1.0.0.0, HDMI port 1
+#define CEC_DEFAULT_PHYSICAL_ADDRESS 0x1000
+#define CEC_DEFAULT_HDMI_PORT        1
+#define CEC_DEFAULT_BASE_DEVICE      0
+#define MSGSTART                     0xFF
+#define MSGEND                       0xFE
+#define MSGESC                       0xFD
+#define ESCOFFSET                    3
+#define CEC_BUTTON_TIMEOUT           500
+
+#define CEC_DEFAULT_TRANSMIT_TIMEOUT 1000
+#define CEC_DEFAULT_TRANSMIT_WAIT    2000
+#define CEC_DEFAULT_TRANSMIT_RETRIES 1
+
+#define CEC_MIN_LIB_VERSION          1
+#define CEC_LIB_VERSION_MAJOR        1
+#define CEC_LIB_VERSION_MINOR        3
+
 typedef enum cec_abort_reason
 {
-  CEC_ABORT_REASON_UNRECOGNIZED_OPCODE = 0,
+  CEC_ABORT_REASON_UNRECOGNIZED_OPCODE            = 0,
   CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND = 1,
-  CEC_ABORT_REASON_CANNOT_PROVIDE_SOURCE = 2,
-  CEC_ABORT_REASON_INVALID_OPERAND = 3,
-  CEC_ABORT_REASON_REFUSED = 4
+  CEC_ABORT_REASON_CANNOT_PROVIDE_SOURCE          = 2,
+  CEC_ABORT_REASON_INVALID_OPERAND                = 3,
+  CEC_ABORT_REASON_REFUSED                        = 4
 } 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_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_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_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_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_TRUE  = 1
 } cec_boolean;
 
 typedef enum cec_version
@@ -110,378 +128,330 @@ typedef enum 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_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_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_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_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         = 0x1F,
+  CEC_DECK_INFO_OTHER_STATUS_LG      = 0x20
 } cec_deck_info;
 
 typedef enum cec_device_type
 {
-  CEC_DEVICE_TYPE_TV = 0,
+  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_RESERVED         = 2,
+  CEC_DEVICE_TYPE_TUNER            = 3,
+  CEC_DEVICE_TYPE_PLAYBACK_DEVICE  = 4,
+  CEC_DEVICE_TYPE_AUDIO_SYSTEM     = 5
 } cec_device_type;
 
-typedef struct cec_device_type_list
-{
-  cec_device_type types[5];
-
-#ifdef __cplusplus
-  void clear(void)
-  {
-    for (unsigned int iPtr = 0; iPtr < 5; iPtr++)
-     types[iPtr] = CEC_DEVICE_TYPE_RESERVED;
-  }
-
-  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;
-      }
-    }
-  }
-
-  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;
-  }
-
-  bool empty()
-  {
-    bool bReturn(true);
-    for (unsigned int iPtr = 0; bReturn && iPtr < 5; iPtr++)
-    {
-      if (types[iPtr] != CEC_DEVICE_TYPE_RESERVED)
-        bReturn = false;
-    }
-    return bReturn;
-  }
-
-  cec_device_type operator[](uint8_t pos) const { return pos < 5 ? types[pos] : CEC_DEVICE_TYPE_RESERVED; }
-#endif
-} cec_device_type_list;
-
 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_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_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_ACTIVATE   = 0,
   CEC_MENU_REQUEST_TYPE_DEACTIVATE = 1,
-  CEC_MENU_REQUEST_TYPE_QUERY = 2
+  CEC_MENU_REQUEST_TYPE_QUERY      = 2
 } cec_menu_request_type;
 
 typedef enum cec_menu_state
 {
-  CEC_MENU_STATE_ACTIVATED = 0,
+  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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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,
-  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,
-  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,
-  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_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                      = 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,
+  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,
+  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,
+  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_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,
-  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,
-  CEC_USER_CONTROL_CODE_MAX = 0x76,
+  CEC_USER_CONTROL_CODE_POWER_TOGGLE_FUNCTION       = 0x6B,
+  CEC_USER_CONTROL_CODE_POWER_OFF_FUNCTION          = 0x6C,
+  CEC_USER_CONTROL_CODE_POWER_ON_FUNCTION           = 0x6D,
+  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,
+  CEC_USER_CONTROL_CODE_MAX                         = 0x76,
   CEC_USER_CONTROL_CODE_UNKNOWN
 } cec_user_control_code;
 
@@ -492,139 +462,92 @@ typedef enum cec_an_user_control_code
 
 typedef enum cec_logical_address
 {
-  CECDEVICE_UNKNOWN = -1, //not a valid logical address
-  CECDEVICE_TV,
-  CECDEVICE_RECORDINGDEVICE1,
-  CECDEVICE_RECORDINGDEVICE2,
-  CECDEVICE_TUNER1,
-  CECDEVICE_PLAYBACKDEVICE1,
-  CECDEVICE_AUDIOSYSTEM,
-  CECDEVICE_TUNER2,
-  CECDEVICE_TUNER3,
-  CECDEVICE_PLAYBACKDEVICE2,
-  CECDEVICE_RECORDINGDEVICE3,
-  CECDEVICE_TUNER4,
-  CECDEVICE_PLAYBACKDEVICE3,
-  CECDEVICE_RESERVED1,
-  CECDEVICE_RESERVED2,
-  CECDEVICE_FREEUSE,
-  CECDEVICE_UNREGISTERED = 15,
-  CECDEVICE_BROADCAST = 15
+  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 struct cec_logical_addresses
-{
-  cec_logical_address primary;
-  int                 addresses[16];
-
-#ifdef __cplusplus
-  void clear(void)
-  {
-    primary = CECDEVICE_UNKNOWN;
-    for (unsigned int iPtr = 0; iPtr < 16; iPtr++)
-      addresses[iPtr] = 0;
-  }
-
-  bool empty(void) const
-  {
-    return primary == CECDEVICE_UNKNOWN;
-  }
-
-  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;
-  }
-
-  void set(cec_logical_address address)
-  {
-    if (primary == CECDEVICE_UNKNOWN)
-      primary = address;
-
-    addresses[(int) address] = 1;
-  }
-
-  void unset(cec_logical_address address)
-  {
-    if (primary == address)
-      primary = CECDEVICE_UNKNOWN;
-
-    addresses[(int) address] = 0;
-  }
-
-  bool isset(cec_logical_address address) const { return addresses[(int) address] == 1; }
-  bool operator[](uint8_t pos) const { return pos < 16 ? isset((cec_logical_address) pos) : false; }
-#endif
-} cec_logical_addresses;
-
 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_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_OPCODE_NONE = 0xFD /* when this opcode is set, no opcode will be sent to the device. this is one of the reserved numbers */
+  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,
+  /* 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
@@ -637,31 +560,6 @@ typedef enum cec_log_level
   CEC_LOG_ALL     = 31
 } cec_log_level;
 
-typedef struct cec_menu_language
-{
-  char                language[4];
-  cec_logical_address device;
-} cec_menu_language;
-
-typedef struct cec_log_message
-{
-  char          message[1024];
-  cec_log_level level;
-  int64_t       time;
-} cec_log_message;
-
-typedef struct cec_keypress
-{
-  cec_user_control_code keycode;
-  unsigned int          duration;
-} cec_keypress;
-
-typedef struct cec_adapter
-{
-  char path[1024];
-  char comm[1024];
-} cec_adapter;
-
 typedef enum cec_adapter_messagecode
 {
   MSGCODE_NOTHING = 0,
@@ -691,6 +589,57 @@ typedef enum cec_adapter_messagecode
   MSGCODE_FRAME_ACK = 0x40,
 } cec_adapter_messagecode;
 
+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_SAMSUNG   = 0x00F0,
+  CEC_VENDOR_LG        = 0xE091,
+  CEC_VENDOR_PANASONIC = 0x8045,
+  CEC_VENDOR_PIONEER   = 0xE036,
+  CEC_VENDOR_ONKYO     = 0x09B0,
+  CEC_VENDOR_YAMAHA    = 0xA0DE,
+  CEC_VENDOR_PHILIPS   = 0x903E,
+  CEC_VENDOR_UNKNOWN   = 0
+} cec_vendor_id;
+
+typedef struct cec_menu_language
+{
+  char                language[4];
+  cec_logical_address device;
+} cec_menu_language;
+
+typedef struct cec_osd_name
+{
+  char                name[14];
+  cec_logical_address device;
+} cec_osd_name;
+
+typedef struct cec_log_message
+{
+  char          message[1024];
+  cec_log_level level;
+  int64_t       time;
+} cec_log_message;
+
+typedef struct cec_keypress
+{
+  cec_user_control_code keycode;
+  unsigned int          duration;
+} cec_keypress;
+
+typedef struct cec_adapter
+{
+  char path[1024];
+  char comm[1024];
+} cec_adapter;
+
 typedef struct cec_datapacket
 {
   uint8_t data[100];
@@ -699,23 +648,23 @@ typedef struct cec_datapacket
 #ifdef __cplusplus
   cec_datapacket &operator =(const struct cec_datapacket &packet)
   {
-    clear();
+    Clear();
     for (uint8_t iPtr = 0; iPtr < packet.size; iPtr++)
-      push_back(packet[iPtr]);
+      PushBack(packet[iPtr]);
 
     return *this;
   }
 
-  bool    empty(void) const             { return size == 0; }
-  bool    full(void) const              { return size == 100; }
+  bool    IsEmpty(void) const             { return size == 0; }
+  bool    IsFull(void) const              { return size == 100; }
   uint8_t operator[](uint8_t pos) const { return pos < size ? data[pos] : 0; }
-  uint8_t at(uint8_t pos) const         { return pos < size ? data[pos] : 0; }
+  uint8_t At(uint8_t pos) const         { return pos < size ? data[pos] : 0; }
 
-  void shift(uint8_t iShiftBy)
+  void Shift(uint8_t iShiftBy)
   {
     if (iShiftBy >= size)
     {
-      clear();
+      Clear();
     }
     else
     {
@@ -725,13 +674,13 @@ typedef struct cec_datapacket
     }
   }
 
-  void push_back(uint8_t add)
+  void PushBack(uint8_t add)
   {
     if (size < 100)
       data[size++] = add;
   }
 
-  void clear(void)
+  void Clear(void)
   {
     memset(data, 0, sizeof(data));
     size = 0;
@@ -766,11 +715,12 @@ typedef struct cec_command
     return *this;
   }
 
-  static void format(cec_command &command, cec_logical_address initiator, cec_logical_address destination, cec_opcode opcode)
+  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.Clear();
+    command.initiator        = initiator;
+    command.destination      = destination;
+    command.transmit_timeout = timeout;
     if (opcode != CEC_OPCODE_NONE)
     {
       command.opcode     = opcode;
@@ -778,7 +728,7 @@ typedef struct cec_command
     }
   }
 
-  void push_back(uint8_t data)
+  void PushBack(uint8_t data)
   {
     if (initiator == CECDEVICE_UNKNOWN && destination == CECDEVICE_UNKNOWN)
     {
@@ -791,10 +741,10 @@ typedef struct cec_command
       opcode = (cec_opcode) data;
     }
     else
-      parameters.push_back(data);
+      parameters.PushBack(data);
   }
 
-  void clear(void)
+  void Clear(void)
   {
     initiator        = CECDEVICE_UNKNOWN;
     destination      = CECDEVICE_UNKNOWN;
@@ -802,32 +752,117 @@ typedef struct cec_command
     eom              = 0;
     opcode_set       = 0;
     opcode           = CEC_OPCODE_FEATURE_ABORT;
-    transmit_timeout = 1000;
-    parameters.clear();
+    transmit_timeout = CEC_DEFAULT_TRANSMIT_TIMEOUT;
+    parameters.Clear();
   };
 #endif
 } cec_command;
 
-typedef enum cec_vendor_id
+typedef struct cec_device_type_list
 {
-  CEC_VENDOR_SAMSUNG   = 0x00F0,
-  CEC_VENDOR_LG        = 0xE091,
-  CEC_VENDOR_PANASONIC = 0x8045,
-  CEC_VENDOR_PIONEER   = 0xE036,
-  CEC_VENDOR_UNKNOWN   = 0
-} cec_vendor_id;
+  cec_device_type types[5];
 
-//default physical address 1.0.0.0, HDMI port 1
-#define CEC_DEFAULT_PHYSICAL_ADDRESS 0x1000
-#define MSGSTART                     0xFF
-#define MSGEND                       0xFE
-#define MSGESC                       0xFD
-#define ESCOFFSET                    3
-#define CEC_BUTTON_TIMEOUT           500
+#ifdef __cplusplus
+  /*!
+   * @deprecated
+   */
+  void clear(void) { Clear(); }
+  /*!
+   * @deprecated
+   */
+  void add(const cec_device_type type) { Add(type); }
+
+  void Clear(void)
+  {
+    for (unsigned int iPtr = 0; iPtr < 5; iPtr++)
+     types[iPtr] = CEC_DEVICE_TYPE_RESERVED;
+  }
 
-#define CEC_MIN_LIB_VERSION          1
-#define CEC_LIB_VERSION_MAJOR        1
-#define CEC_LIB_VERSION_MINOR        2
+  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;
+      }
+    }
+  }
+
+  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;
+  }
+
+  bool IsEmpty()
+  {
+    bool bReturn(true);
+    for (unsigned int iPtr = 0; bReturn && iPtr < 5; iPtr++)
+    {
+      if (types[iPtr] != CEC_DEVICE_TYPE_RESERVED)
+        bReturn = false;
+    }
+    return bReturn;
+  }
+
+  cec_device_type operator[](uint8_t pos) const { return pos < 5 ? types[pos] : CEC_DEVICE_TYPE_RESERVED; }
+#endif
+} cec_device_type_list;
+
+typedef struct cec_logical_addresses
+{
+  cec_logical_address primary;
+  int                 addresses[16];
+
+#ifdef __cplusplus
+  void Clear(void)
+  {
+    primary = CECDEVICE_UNKNOWN;
+    for (unsigned int iPtr = 0; iPtr < 16; iPtr++)
+      addresses[iPtr] = 0;
+  }
+
+  bool IsEmpty(void) const
+  {
+    return primary == CECDEVICE_UNKNOWN;
+  }
+
+  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;
+  }
+
+  void Set(cec_logical_address address)
+  {
+    if (primary == CECDEVICE_UNKNOWN)
+      primary = address;
+
+    addresses[(int) address] = 1;
+  }
+
+  void Unset(cec_logical_address address)
+  {
+    if (primary == address)
+      primary = CECDEVICE_UNKNOWN;
+
+    addresses[(int) address] = 0;
+  }
+
+  bool IsSet(cec_logical_address address) const { return addresses[(int) address] == 1; }
+  bool operator[](uint8_t pos) const { return pos < 16 ? IsSet((cec_logical_address) pos) : false; }
+#endif
+} cec_logical_addresses;
 
 #ifdef __cplusplus
 };
diff --git a/project/CecSharpClient.sln b/project/CecSharpClient.sln
new file mode 100644 (file)
index 0000000..0a4d822
--- /dev/null
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CecSharpClient", "..\src\CecSharpTester\CecSharpClient.csproj", "{47EF8EFE-5758-4E82-B9BA-F9B002F9C0D4}"
+EndProject
+Global
+       GlobalSection(SolutionConfigurationPlatforms) = preSolution
+               Debug|x86 = Debug|x86
+               Release|x86 = Release|x86
+       EndGlobalSection
+       GlobalSection(ProjectConfigurationPlatforms) = postSolution
+               {47EF8EFE-5758-4E82-B9BA-F9B002F9C0D4}.Debug|x86.ActiveCfg = Debug|x86
+               {47EF8EFE-5758-4E82-B9BA-F9B002F9C0D4}.Debug|x86.Build.0 = Debug|x86
+               {47EF8EFE-5758-4E82-B9BA-F9B002F9C0D4}.Release|x86.ActiveCfg = Release|x86
+               {47EF8EFE-5758-4E82-B9BA-F9B002F9C0D4}.Release|x86.Build.0 = Release|x86
+       EndGlobalSection
+       GlobalSection(SolutionProperties) = preSolution
+               HideSolutionNode = FALSE
+       EndGlobalSection
+EndGlobal
diff --git a/project/LibCecSharp.vcxproj b/project/LibCecSharp.vcxproj
new file mode 100644 (file)
index 0000000..2ced898
--- /dev/null
@@ -0,0 +1,101 @@
+<?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="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{1AC27FBD-653A-4F5F-ADBC-2A8FD074EEB7}</ProjectGuid>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <Keyword>ManagedCProj</Keyword>
+    <RootNamespace>LibCecSharp</RootNamespace>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CLRSupport>true</CLRSupport>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <CLRSupport>true</CLRSupport>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <LinkIncremental>true</LinkIncremental>
+    <IncludePath>$(SolutionDir)\..\include;$(IncludePath)</IncludePath>
+    <TargetName>$(ProjectName)</TargetName>
+    <OutDir>$(SolutionDir)..\</OutDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <LinkIncremental>false</LinkIncremental>
+    <IncludePath>$(SolutionDir)\..\include;$(IncludePath)</IncludePath>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+    </ClCompile>
+    <Link>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <AdditionalDependencies>
+      </AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <PreprocessorDefinitions>WIN32;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+    </ClCompile>
+    <Link>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <AdditionalDependencies>
+      </AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="..\include\cec.h" />
+    <ClInclude Include="..\include\cectypes.h" />
+    <ClInclude Include="..\src\LibCecSharp\resource.h" />
+    <ClInclude Include="..\src\LibCecSharp\Stdafx.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="..\src\LibCecSharp\AssemblyInfo.cpp" />
+    <ClCompile Include="..\src\LibCecSharp\LibCecSharp.cpp" />
+    <ClCompile Include="..\src\LibCecSharp\Stdafx.cpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="libcec.vcxproj">
+      <Project>{c04b0fb1-667d-4f1c-bdae-a07cdffaaaa0}</Project>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
\ No newline at end of file
diff --git a/project/LibCecSharp.vcxproj.filters b/project/LibCecSharp.vcxproj.filters
new file mode 100644 (file)
index 0000000..cdfa851
--- /dev/null
@@ -0,0 +1,42 @@
+<?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>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="..\src\LibCecSharp\resource.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\LibCecSharp\Stdafx.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\cec.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\cectypes.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="..\src\LibCecSharp\AssemblyInfo.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\LibCecSharp\LibCecSharp.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\LibCecSharp\Stdafx.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+  </ItemGroup>
+</Project>
\ No newline at end of file
index 5187528a28c53886cc1e54b24e08394d84e7a394..f82db3dde79463ff396e9b21e7be76cdb80c5dfa 100644 (file)
@@ -16,8 +16,11 @@ echo Cleaning libCEC
 %COMPILER% libcec.sln /clean Release
 
 echo Compiling libCEC
-%COMPILER% libcec.sln /clean Release
-%COMPILER% libcec.sln /build Release
+%COMPILER% libcec.sln /build Release /project libcec
+echo Compiling cec-client
+%COMPILER% libcec.sln /build Release /project testclient
+echo Compiling LibCecSharp
+%COMPILER% libcec.sln /build Release /project LibCecSharp
 
 rem Copy driver installer
 echo Copying driver installer
index eaf10932e36d54215ddbf196183116a5d6561b98..591cc1da9ab7a6e609a08c67002aa212fefa454e 100644 (file)
@@ -16,7 +16,7 @@ InstallDirRegKey HKCU "Software\libCEC" ""
 RequestExecutionLevel admin
 Var StartMenuFolder
 
-!define MUI_FINISHPAGE_LINK "Please visit http://www.pulse-eight.com/ for more information."
+!define MUI_FINISHPAGE_LINK "Visit http://www.pulse-eight.com/ for more information."
 !define MUI_FINISHPAGE_LINK_LOCATION "http://www.pulse-eight.com/"
 !define MUI_ABORTWARNING  
 
@@ -52,6 +52,7 @@ Section "libCEC" SecLibCEC
   File "..\COPYING"
   File "..\libcec.dll"
   File "..\libcec.lib"
+  File "Release\LibCecSharp.dll"
   File "..\pthreadVC2.dll"
   File "..\README"
 
@@ -130,6 +131,7 @@ Section "Uninstall"
   Delete "$INSTDIR\libcec.dll"
   Delete "$INSTDIR\libcec.lib"
   Delete "$INSTDIR\libcec.pdb"
+  Delete "$INSTDIR\LibCecSharp.dll"
   Delete "$INSTDIR\pthreadVC2.dll"
   Delete "$INSTDIR\README"
   Delete "$INSTDIR\driver\OEM001.inf"
index ee83cc9d3ec604e58f823652806cbfa334ea94d4..1fe06c575219956617b7051aedb1a55d52037348 100644 (file)
Binary files a/project/libcec.rc and b/project/libcec.rc differ
index 2255a1b0f0f9362ea2ac5c53b70d8b2e0f5d2644..facfeceea5b7e2141020f2bb1cbbd1003b8f8714 100644 (file)
@@ -8,20 +8,59 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testclient", "testclient.vc
                {C04B0FB1-667D-4F1C-BDAE-A07CDFFAAAA0} = {C04B0FB1-667D-4F1C-BDAE-A07CDFFAAAA0}
        EndProjectSection
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LibCecSharp", "LibCecSharp.vcxproj", "{1AC27FBD-653A-4F5F-ADBC-2A8FD074EEB7}"
+       ProjectSection(ProjectDependencies) = postProject
+               {C04B0FB1-667D-4F1C-BDAE-A07CDFFAAAA0} = {C04B0FB1-667D-4F1C-BDAE-A07CDFFAAAA0}
+       EndProjectSection
+EndProject
 Global
        GlobalSection(SolutionConfigurationPlatforms) = preSolution
+               Debug|Any CPU = Debug|Any CPU
+               Debug|Mixed Platforms = Debug|Mixed Platforms
                Debug|Win32 = Debug|Win32
+               Debug|x86 = Debug|x86
+               Release|Any CPU = Release|Any CPU
+               Release|Mixed Platforms = Release|Mixed Platforms
                Release|Win32 = Release|Win32
+               Release|x86 = Release|x86
        EndGlobalSection
        GlobalSection(ProjectConfigurationPlatforms) = postSolution
+               {C04B0FB1-667D-4F1C-BDAE-A07CDFFAAAA0}.Debug|Any CPU.ActiveCfg = Debug|Win32
+               {C04B0FB1-667D-4F1C-BDAE-A07CDFFAAAA0}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
+               {C04B0FB1-667D-4F1C-BDAE-A07CDFFAAAA0}.Debug|Mixed Platforms.Build.0 = Debug|Win32
                {C04B0FB1-667D-4F1C-BDAE-A07CDFFAAAA0}.Debug|Win32.ActiveCfg = Debug|Win32
                {C04B0FB1-667D-4F1C-BDAE-A07CDFFAAAA0}.Debug|Win32.Build.0 = Debug|Win32
+               {C04B0FB1-667D-4F1C-BDAE-A07CDFFAAAA0}.Debug|x86.ActiveCfg = Debug|Win32
+               {C04B0FB1-667D-4F1C-BDAE-A07CDFFAAAA0}.Release|Any CPU.ActiveCfg = Release|Win32
+               {C04B0FB1-667D-4F1C-BDAE-A07CDFFAAAA0}.Release|Mixed Platforms.ActiveCfg = Release|Win32
+               {C04B0FB1-667D-4F1C-BDAE-A07CDFFAAAA0}.Release|Mixed Platforms.Build.0 = Release|Win32
                {C04B0FB1-667D-4F1C-BDAE-A07CDFFAAAA0}.Release|Win32.ActiveCfg = Release|Win32
                {C04B0FB1-667D-4F1C-BDAE-A07CDFFAAAA0}.Release|Win32.Build.0 = Release|Win32
+               {C04B0FB1-667D-4F1C-BDAE-A07CDFFAAAA0}.Release|x86.ActiveCfg = Release|Win32
+               {F01222BF-6B3D-43BD-B254-434031CB9887}.Debug|Any CPU.ActiveCfg = Debug|Win32
+               {F01222BF-6B3D-43BD-B254-434031CB9887}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
+               {F01222BF-6B3D-43BD-B254-434031CB9887}.Debug|Mixed Platforms.Build.0 = Debug|Win32
                {F01222BF-6B3D-43BD-B254-434031CB9887}.Debug|Win32.ActiveCfg = Debug|Win32
                {F01222BF-6B3D-43BD-B254-434031CB9887}.Debug|Win32.Build.0 = Debug|Win32
+               {F01222BF-6B3D-43BD-B254-434031CB9887}.Debug|x86.ActiveCfg = Debug|Win32
+               {F01222BF-6B3D-43BD-B254-434031CB9887}.Release|Any CPU.ActiveCfg = Release|Win32
+               {F01222BF-6B3D-43BD-B254-434031CB9887}.Release|Mixed Platforms.ActiveCfg = Release|Win32
+               {F01222BF-6B3D-43BD-B254-434031CB9887}.Release|Mixed Platforms.Build.0 = Release|Win32
                {F01222BF-6B3D-43BD-B254-434031CB9887}.Release|Win32.ActiveCfg = Release|Win32
                {F01222BF-6B3D-43BD-B254-434031CB9887}.Release|Win32.Build.0 = Release|Win32
+               {F01222BF-6B3D-43BD-B254-434031CB9887}.Release|x86.ActiveCfg = Release|Win32
+               {1AC27FBD-653A-4F5F-ADBC-2A8FD074EEB7}.Debug|Any CPU.ActiveCfg = Debug|Win32
+               {1AC27FBD-653A-4F5F-ADBC-2A8FD074EEB7}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
+               {1AC27FBD-653A-4F5F-ADBC-2A8FD074EEB7}.Debug|Mixed Platforms.Build.0 = Debug|Win32
+               {1AC27FBD-653A-4F5F-ADBC-2A8FD074EEB7}.Debug|Win32.ActiveCfg = Debug|Win32
+               {1AC27FBD-653A-4F5F-ADBC-2A8FD074EEB7}.Debug|Win32.Build.0 = Debug|Win32
+               {1AC27FBD-653A-4F5F-ADBC-2A8FD074EEB7}.Debug|x86.ActiveCfg = Debug|Win32
+               {1AC27FBD-653A-4F5F-ADBC-2A8FD074EEB7}.Release|Any CPU.ActiveCfg = Release|Win32
+               {1AC27FBD-653A-4F5F-ADBC-2A8FD074EEB7}.Release|Mixed Platforms.ActiveCfg = Release|Win32
+               {1AC27FBD-653A-4F5F-ADBC-2A8FD074EEB7}.Release|Mixed Platforms.Build.0 = Release|Win32
+               {1AC27FBD-653A-4F5F-ADBC-2A8FD074EEB7}.Release|Win32.ActiveCfg = Release|Win32
+               {1AC27FBD-653A-4F5F-ADBC-2A8FD074EEB7}.Release|Win32.Build.0 = Release|Win32
+               {1AC27FBD-653A-4F5F-ADBC-2A8FD074EEB7}.Release|x86.ActiveCfg = Release|Win32
        EndGlobalSection
        GlobalSection(SolutionProperties) = preSolution
                HideSolutionNode = FALSE
index 8d44ff262f359dddc7ea1c00e4ad8628f56bb5db..c63d3c9ebfdb49ffe33cc05778ef8c141e5b6412 100644 (file)
Binary files a/project/testclient.rc and b/project/testclient.rc differ
diff --git a/src/CecSharpTester/AssemblyInfo.cs b/src/CecSharpTester/AssemblyInfo.cs
new file mode 100644 (file)
index 0000000..058bbb9
--- /dev/null
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("CecSharpClient")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Pulse-Eight Ltd.")]
+[assembly: AssemblyProduct("CecSharpClient")]
+[assembly: AssemblyCopyright("Copyright Â© Pulse-Eight Ltd. 2011")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("fb8d5961-9ba9-4e56-8706-ac150183706f")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/src/CecSharpTester/CecSharpClient.cs b/src/CecSharpTester/CecSharpClient.cs
new file mode 100644 (file)
index 0000000..3d8ec32
--- /dev/null
@@ -0,0 +1,355 @@
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011 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/
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace CecSharpClient
+{
+  class CecSharpClient
+  {
+    public CecSharpClient()
+    {
+      CecDeviceTypeList types = new CecDeviceTypeList();
+      types.Types[0] = CecDeviceType.RecordingDevice;
+
+      Lib = new LibCecSharp("CEC Tester", types);
+      LogLevel = (int) CecLogLevel.All;
+
+      Console.WriteLine("CEC Parser created - libcec version " + Lib.GetLibVersionMajor() + "." + Lib.GetLibVersionMinor());
+    }
+
+    void FlushLog()
+    {
+      CecLogMessage message = Lib.GetNextLogMessage();
+      bool bGotMessage = !message.Empty;
+      while (bGotMessage)
+      {
+        if (((int)message.Level & LogLevel) == (int)message.Level)
+        {
+          string strLevel = "";
+          switch (message.Level)
+          {
+            case CecLogLevel.Error:
+              strLevel = "ERROR:   ";
+              break;
+            case CecLogLevel.Warning:
+              strLevel = "WARNING: ";
+              break;
+            case CecLogLevel.Notice:
+              strLevel = "NOTICE:  ";
+              break;
+            case CecLogLevel.Traffic:
+              strLevel = "TRAFFIC: ";
+              break;
+            case CecLogLevel.Debug:
+              strLevel = "DEBUG:   ";
+              break;
+            default:
+              break;
+          }
+          string strLog = string.Format("{0} {1,16} {2}", strLevel, message.Time, message.Message);
+          Console.WriteLine(strLog);
+        }
+
+        message = Lib.GetNextLogMessage();
+        bGotMessage = !message.Empty;
+      }
+    }
+
+    public bool Connect(int timeout)
+    {
+      CecAdapter[] adapters = Lib.FindAdapters(string.Empty);
+      if (adapters.Length > 0)
+        return Connect(adapters[0].ComPort, timeout);
+      else
+      {
+        Console.WriteLine("Did not find any CEC adapters");
+        return false;
+      }
+    }
+
+    public bool Connect(string port, int timeout)
+    {
+      return Lib.Open(port, timeout);
+    }
+
+    public void Close()
+    {
+      Lib.Close();
+    }
+
+    public void ListDevices()
+    {
+      int iAdapter = 0;
+      foreach (CecAdapter adapter in Lib.FindAdapters(string.Empty))
+      {
+        Console.WriteLine("Adapter:  " + iAdapter++);
+        Console.WriteLine("Path:     " + adapter.Path);
+        Console.WriteLine("Com port: " + adapter.ComPort);
+      }
+    }
+
+    void ShowConsoleHelp()
+    {
+      Console.WriteLine(
+        "================================================================================" + System.Environment.NewLine +
+        "Available commands:" + System.Environment.NewLine +
+        System.Environment.NewLine +
+        "[tx] {bytes}              transfer bytes over the CEC line." + System.Environment.NewLine +
+        "[txn] {bytes}             transfer bytes but don't wait for transmission ACK." + System.Environment.NewLine +
+        "[on] {address}            power on the device with the given logical address." + System.Environment.NewLine +
+        "[standby] {address}       put the device with the given address in standby mode." + System.Environment.NewLine +
+        "[la] {logical_address}    change the logical address of the CEC adapter." + System.Environment.NewLine +
+        "[pa] {physical_address}   change the physical address of the CEC adapter." + System.Environment.NewLine +
+        "[osd] {addr} {string}     set OSD message on the specified device." + System.Environment.NewLine +
+        "[ver] {addr}              get the CEC version of the specified device." + System.Environment.NewLine +
+        "[ven] {addr}              get the vendor ID of the specified device." + System.Environment.NewLine +
+        "[lang] {addr}             get the menu language of the specified device." + System.Environment.NewLine +
+        "[pow] {addr}              get the power status of the specified device." + System.Environment.NewLine +
+        "[poll] {addr}             poll the specified device." + System.Environment.NewLine +
+        "[scan]                    scan the CEC bus and display device info" + System.Environment.NewLine +
+        "[mon] {1|0}               enable or disable CEC bus monitoring." + System.Environment.NewLine +
+        "[log] {1 - 31}            change the log level. see cectypes.h for values." + System.Environment.NewLine +
+        "[ping]                    send a ping command to the CEC adapter." + System.Environment.NewLine +
+        "[bl]                      to let the adapter enter the bootloader, to upgrade" + System.Environment.NewLine +
+        "                          the flash rom." + System.Environment.NewLine +
+        "[r]                       reconnect to the CEC adapter." + System.Environment.NewLine +
+        "[h] or [help]             show this help." + System.Environment.NewLine +
+        "[q] or [quit]             to quit the CEC test client and switch off all" + System.Environment.NewLine +
+        "                          connected CEC devices." + System.Environment.NewLine +
+        "================================================================================");
+    }
+
+    public void MainLoop()
+    {
+      Lib.PowerOnDevices(CecLogicalAddress.Tv);
+      FlushLog();
+
+      Lib.SetActiveSource(CecDeviceType.PlaybackDevice);
+      FlushLog();
+
+      bool bContinue = true;
+      string command;
+      while (bContinue)
+      {
+        FlushLog();
+        Console.WriteLine("waiting for input");
+
+        command = Console.ReadLine();
+        if (command.Length == 0)
+          continue;
+        string[] splitCommand = command.Split(' ');
+        if (splitCommand[0] == "tx" || splitCommand[0] == "txn")
+        {
+          CecCommand bytes = new CecCommand();
+          for (int iPtr = 1; iPtr < splitCommand.Length; iPtr++)
+          {
+            bytes.PushBack(byte.Parse(splitCommand[iPtr], System.Globalization.NumberStyles.HexNumber));
+          }
+
+          if (command == "txn")
+            bytes.TransmitTimeout = 0;
+
+          Lib.Transmit(bytes);
+        }
+        else if (splitCommand[0] == "on")
+        {
+          if (splitCommand.Length > 1)
+            Lib.PowerOnDevices((CecLogicalAddress)byte.Parse(splitCommand[1], System.Globalization.NumberStyles.HexNumber));
+          else
+            Lib.PowerOnDevices(CecLogicalAddress.Broadcast);
+        }
+        else if (splitCommand[0] == "standby")
+        {
+          if (splitCommand.Length > 1)
+            Lib.StandbyDevices((CecLogicalAddress)byte.Parse(splitCommand[1], System.Globalization.NumberStyles.HexNumber));
+          else
+            Lib.StandbyDevices(CecLogicalAddress.Broadcast);
+        }
+        else if (splitCommand[0] == "poll")
+        {
+          bool bSent = false;
+          if (splitCommand.Length > 1)
+            bSent = Lib.PollDevice((CecLogicalAddress)byte.Parse(splitCommand[1], System.Globalization.NumberStyles.HexNumber));
+          else
+            bSent = Lib.PollDevice(CecLogicalAddress.Broadcast);
+          if (bSent)
+            Console.WriteLine("POLL message sent");
+          else
+            Console.WriteLine("POLL message not sent");
+        }
+        else if (splitCommand[0] == "la")
+        {
+          if (splitCommand.Length > 1)
+            Lib.SetLogicalAddress((CecLogicalAddress)byte.Parse(splitCommand[1], System.Globalization.NumberStyles.HexNumber));
+        }
+        else if (splitCommand[0] == "pa")
+        {
+          if (splitCommand.Length > 1)
+            Lib.SetPhysicalAddress(short.Parse(splitCommand[1], System.Globalization.NumberStyles.HexNumber));
+        }
+        else if (splitCommand[0] == "osd")
+        {
+          if (splitCommand.Length > 2)
+          {
+            StringBuilder osdString = new StringBuilder();
+            for (int iPtr = 1; iPtr < splitCommand.Length; iPtr++)
+            {
+              osdString.Append(splitCommand[iPtr]);
+              if (iPtr != splitCommand.Length - 1)
+                osdString.Append(" ");
+            }
+            Lib.SetOSDString((CecLogicalAddress)byte.Parse(splitCommand[1], System.Globalization.NumberStyles.HexNumber), CecDisplayControl.DisplayForDefaultTime, osdString.ToString());
+          }
+        }
+        else if (splitCommand[0] == "ping")
+        {
+          Lib.PingAdapter();
+        }
+        else if (splitCommand[0] == "mon")
+        {
+          bool enable = splitCommand.Length > 1 ? splitCommand[1] == "1" : false;
+          Lib.SwitchMonitoring(enable);
+        }
+        else if (splitCommand[0] == "bl")
+        {
+          Lib.StartBootloader();
+        }
+        else if (splitCommand[0] == "lang")
+        {
+          if (splitCommand.Length > 1)
+          {
+            string language = Lib.GetDeviceMenuLanguage((CecLogicalAddress)byte.Parse(splitCommand[1], System.Globalization.NumberStyles.HexNumber));
+            Console.WriteLine("Menu language: " + language);
+          }
+        }
+        else if (splitCommand[0] == "ven")
+        {
+          if (splitCommand.Length > 1)
+          {
+            CecVendorId vendor = Lib.GetDeviceVendorId((CecLogicalAddress)byte.Parse(splitCommand[1], System.Globalization.NumberStyles.HexNumber));
+            Console.WriteLine("Vendor ID: " + Lib.ToString(vendor));
+          }
+        }
+        else if (splitCommand[0] == "ver")
+        {
+          if (splitCommand.Length > 1)
+          {
+            CecVersion version = Lib.GetDeviceCecVersion((CecLogicalAddress)byte.Parse(splitCommand[1], System.Globalization.NumberStyles.HexNumber));
+            Console.WriteLine("CEC version: " + Lib.ToString(version));
+          }
+        }
+        else if (splitCommand[0] == "pow")
+        {
+          if (splitCommand.Length > 1)
+          {
+            CecPowerStatus power = Lib.GetDevicePowerStatus((CecLogicalAddress)byte.Parse(splitCommand[1], System.Globalization.NumberStyles.HexNumber));
+            Console.WriteLine("power status: " + Lib.ToString(power));
+          }
+        }
+        else if (splitCommand[0] == "r")
+        {
+          Console.WriteLine("closing the connection");
+          Lib.Close();
+          FlushLog();
+
+          Console.WriteLine("opening a new connection");
+          Connect(10000);
+          FlushLog();
+
+          Console.WriteLine("setting active source");
+          Lib.SetActiveSource(CecDeviceType.PlaybackDevice);
+        }
+        else if (splitCommand[0] == "scan")
+        {
+          Console.WriteLine("CEC bus information");
+          Console.WriteLine("===================");
+          CecLogicalAddresses addresses = Lib.GetActiveDevices();
+          for (int iPtr = 0; iPtr < addresses.Addresses.Count(); iPtr++)
+          {
+            CecLogicalAddress address = (CecLogicalAddress)iPtr;
+            if (!addresses.IsSet(address))
+              continue;
+
+            CecVendorId iVendorId = Lib.GetDeviceVendorId(address);
+            bool bActive = Lib.IsActiveDevice(address);
+            ushort iPhysicalAddress = Lib.GetDevicePhysicalAddress(address);
+            string strAddr = string.Format("{0,4:X}", iPhysicalAddress);
+            CecVersion iCecVersion = Lib.GetDeviceCecVersion(address);
+            CecPowerStatus power = Lib.GetDevicePowerStatus(address);
+            string osdName = Lib.GetDeviceOSDName(address);
+            string lang = Lib.GetDeviceMenuLanguage(address);
+
+            StringBuilder output = new StringBuilder();
+            output.AppendLine("device #" + iPtr + ": " + Lib.ToString(address));
+            output.AppendLine("address:       " + strAddr);
+            output.AppendLine("active source: " + (bActive ? "yes" : "no"));
+            output.AppendLine("vendor:        " + Lib.ToString(iVendorId));
+            output.AppendLine("osd string:    " + osdName);
+            output.AppendLine("CEC version:   " + Lib.ToString(iCecVersion));
+            output.AppendLine("power status:  " + Lib.ToString(power));
+            if (!string.IsNullOrEmpty(lang))
+              output.AppendLine("language:      " + lang);
+
+            Console.WriteLine(output.ToString());
+          }
+        }
+        else if (splitCommand[0] == "h" || splitCommand[0] == "help")
+          ShowConsoleHelp();
+        else if (splitCommand[0] == "q" || splitCommand[0] == "quit")
+          bContinue = false;
+        else if (splitCommand[0] == "log" && splitCommand.Length > 1)
+          LogLevel = int.Parse(splitCommand[1]);        
+      }
+    }
+
+    static void Main(string[] args)
+    {
+      CecSharpClient p = new CecSharpClient();
+      if (p.Connect(10000))
+      {
+        p.MainLoop();
+      }
+      else
+      {
+        Console.WriteLine("Could not open a connection to the CEC adapter");
+      }
+      p.FlushLog();
+    }
+
+    private int         LogLevel;
+    private LibCecSharp Lib;
+  }
+}
diff --git a/src/CecSharpTester/CecSharpClient.csproj b/src/CecSharpTester/CecSharpClient.csproj
new file mode 100644 (file)
index 0000000..eff98ef
--- /dev/null
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
+    <ProductVersion>8.0.30703</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{47EF8EFE-5758-4E82-B9BA-F9B002F9C0D4}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>CecSharpClient</RootNamespace>
+    <AssemblyName>CecSharpClient</AssemblyName>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <TargetFrameworkProfile>Client</TargetFrameworkProfile>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+    <PlatformTarget>x86</PlatformTarget>
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>..\..\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+    <PlatformTarget>x86</PlatformTarget>
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="LibCecSharp, Version=1.0.4334.36379, Culture=neutral, processorArchitecture=x86">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\LibCecSharp.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="AssemblyInfo.cs" />
+    <Compile Include="CecSharpClient.cs" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file
diff --git a/src/LibCecSharp/AssemblyInfo.cpp b/src/LibCecSharp/AssemblyInfo.cpp
new file mode 100644 (file)
index 0000000..459ae9f
--- /dev/null
@@ -0,0 +1,40 @@
+#include "stdafx.h"
+
+using namespace System;
+using namespace System::Reflection;
+using namespace System::Runtime::CompilerServices;
+using namespace System::Runtime::InteropServices;
+using namespace System::Security::Permissions;
+
+//
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+//
+[assembly:AssemblyTitleAttribute("LibCecSharp")];
+[assembly:AssemblyDescriptionAttribute("")];
+[assembly:AssemblyConfigurationAttribute("")];
+[assembly:AssemblyCompanyAttribute("Pulse-Eight Ltd.")];
+[assembly:AssemblyProductAttribute("LibCecSharp")];
+[assembly:AssemblyCopyrightAttribute("Copyright (c) Pulse-Eight Ltd. 2011")];
+[assembly:AssemblyTrademarkAttribute("")];
+[assembly:AssemblyCultureAttribute("")];
+
+//
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version
+//      Build Number
+//      Revision
+//
+// You can specify all the value or you can default the Revision and Build Numbers
+// by using the '*' as shown below:
+
+[assembly:AssemblyVersionAttribute("1.0.*")];
+
+[assembly:ComVisible(false)];
+
+[assembly:CLSCompliantAttribute(true)];
+
+[assembly:SecurityPermission(SecurityAction::RequestMinimum, UnmanagedCode = true)];
diff --git a/src/LibCecSharp/LibCecSharp.cpp b/src/LibCecSharp/LibCecSharp.cpp
new file mode 100644 (file)
index 0000000..088c9ef
--- /dev/null
@@ -0,0 +1,862 @@
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011 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 "stdafx.h"
+#include <windows.h>
+#include <vcclr.h>
+#include <msclr/marshal.h>
+#include <cec.h>
+#using <System.dll>
+
+using namespace System;
+using namespace CEC;
+using namespace msclr::interop;
+
+public enum class CecDeviceType
+{
+  Tv              = 0,
+  RecordingDevice = 1,
+  Reserved        = 2,
+  Tuner           = 3,
+  PlaybackDevice  = 4,
+  AudioSystem     = 5
+};
+
+public enum class CecLogLevel
+{
+  None    = 0,
+  Error   = 1,
+  Warning = 2,
+  Notice  = 4,
+  Traffic = 8,
+  Debug   = 16,
+  All     = 31
+};
+
+public enum class CecLogicalAddress
+{
+  Unknown          = -1, //not a valid logical address
+  Tv               = 0,
+  RecordingDevice1 = 1,
+  RecordingDevice2 = 2,
+  Tuner1           = 3,
+  PlaybackDevice1  = 4,
+  AudioSystem      = 5,
+  Tuner2           = 6,
+  Tuner3           = 7,
+  PlaybackDevice2  = 8,
+  RecordingDevice3 = 9,
+  Tuner4           = 10,
+  PlaybackDevice3  = 11,
+  Reserved1        = 12,
+  Reserved2        = 13,
+  FreeUse          = 14,
+  Unregistered     = 15,
+  Broadcast        = 15
+};
+
+public enum class CecPowerStatus
+{
+  On                      = 0x00,
+  Standby                 = 0x01,
+  InTransitionStandbyToOn = 0x02,
+  InTransitionOnToStandby = 0x03,
+  Unknown                 = 0x99
+};
+
+public enum class CecVersion
+{
+  Unknown = 0x00,
+  V1_2    = 0x01,
+  V1_2A   = 0x02,
+  V1_3    = 0x03,
+  V1_3A   = 0x04,
+  V1_4    = 0x05
+};
+
+public enum class CecDisplayControl
+{
+  DisplayForDefaultTime = 0x00,
+  DisplayUntilCleared   = 0x40,
+  ClearPreviousMessage  = 0x80,
+  ReservedForFutureUse  = 0xC0
+};
+
+public enum class CecMenuState
+{
+  Activated   = 0,
+  Deactivated = 1
+};
+
+public enum class CecDeckControlMode
+{
+  SkipForwardWind   = 1,
+  SkipReverseRewind = 2,
+  Stop              = 3,
+  Eject             = 4
+};
+
+public enum class CecDeckInfo
+{
+  Play               = 0x11,
+  Record             = 0x12,
+  Reverse            = 0x13,
+  Still              = 0x14,
+  Slow               = 0x15,
+  SlowReverse        = 0x16,
+  FastForward        = 0x17,
+  FastReverse        = 0x18,
+  NoMedia            = 0x19,
+  Stop               = 0x1A,
+  SkipForwardWind    = 0x1B,
+  SkipReverseRewind  = 0x1C,
+  IndexSearchForward = 0x1D,
+  IndexSearchReverse = 0x1E,
+  OtherStatus        = 0x1F
+};
+
+public enum class CecUserControlCode
+{
+  Select                      = 0x00,
+  Up                          = 0x01,
+  Down                        = 0x02,
+  Left                        = 0x03,
+  Right                       = 0x04,
+  RightUp                     = 0x05,
+  RightDown                   = 0x06,
+  LeftUp                      = 0x07,
+  LeftDown                    = 0x08,
+  RootMenu                    = 0x09,
+  SetupMenu                   = 0x0A,
+  ContentsMenu                = 0x0B,
+  FavoriteMenu                = 0x0C,
+  Exit                        = 0x0D,
+  Number0                     = 0x20,
+  Number1                     = 0x21,
+  Number2                     = 0x22,
+  Number3                     = 0x23,
+  Number4                     = 0x24,
+  Number5                     = 0x25,
+  Number6                     = 0x26,
+  Number7                     = 0x27,
+  Number8                     = 0x28,
+  Number9                     = 0x29,
+  Dot                         = 0x2A,
+  Enter                       = 0x2B,
+  Clear                       = 0x2C,
+  NextFavorite                = 0x2F,
+  ChannelUp                   = 0x30,
+  ChannelDown                 = 0x31,
+  PreviousChannel             = 0x32,
+  SoundSelect                 = 0x33,
+  InputSelect                 = 0x34,
+  DisplayInformation          = 0x35,
+  Help                        = 0x36,
+  PageUp                      = 0x37,
+  PageDown                    = 0x38,
+  Power                       = 0x40,
+  VolumeUp                    = 0x41,
+  VolumeDown                  = 0x42,
+  Mute                        = 0x43,
+  Play                        = 0x44,
+  Stop                        = 0x45,
+  Pause                       = 0x46,
+  Record                      = 0x47,
+  Rewind                      = 0x48,
+  FastForward                 = 0x49,
+  Eject                       = 0x4A,
+  Forward                     = 0x4B,
+  Backward                    = 0x4C,
+  StopRecord                  = 0x4D,
+  PauseRecord                 = 0x4E,
+  Angle                       = 0x50,
+  SubPicture                  = 0x51,
+  VideoOnDemand               = 0x52,
+  ElectronicProgramGuide      = 0x53,
+  TimerProgramming            = 0x54,
+  InitialConfiguration        = 0x55,
+  PlayFunction                = 0x60,
+  PausePlayFunction           = 0x61,
+  RecordFunction              = 0x62,
+  PauseRecordFunction         = 0x63,
+  StopFunction                = 0x64,
+  MuteFunction                = 0x65,
+  RestoreVolumeFunction       = 0x66,
+  TuneFunction                = 0x67,
+  SelectMediaFunction         = 0x68,
+  SelectAVInputFunction       = 0x69,
+  SelectAudioInputFunction    = 0x6A,
+  PowerToggleFunction         = 0x6B,
+  PowerOffFunction            = 0x6C,
+  PowerOnFunction             = 0x6D,
+  F1Blue                      = 0x71,
+  F2Red                       = 0X72,
+  F3Green                     = 0x73,
+  F4Yellow                    = 0x74,
+  F5                          = 0x75,
+  Data                        = 0x76,
+  Max                         = 0x76,
+  Unknown
+};
+
+public enum class CecVendorId
+{
+  Samsung   = 0x00F0,
+  LG        = 0xE091,
+  Panasonic = 0x8045,
+  Pioneer   = 0xE036,
+  Onkyo     = 0x09B0,
+  Yamaha    = 0xA0DE,
+  Philips   = 0x903E,
+  Unknown   = 0
+};
+
+public enum class CecAudioStatus
+{
+  MuteStatusMask      = 0x80,
+  VolumeStatusMask    = 0x7F,
+  VolumeMin           = 0x00,
+  VolumeMax           = 0x64,
+  VolumeStatusUnknown = 0x7F
+};
+
+public enum class CecOpcode
+{
+  ActiveSource                  = 0x82,
+  ImageViewOn                   = 0x04,
+  TextViewOn                    = 0x0D,
+  InactiveSource                = 0x9D,
+  RequestActiveSource           = 0x85,
+  RoutingChange                 = 0x80,
+  RoutingInformation            = 0x81,
+  SetStreamPath                 = 0x86,
+  Standby                       = 0x36,
+  RecordOff                     = 0x0B,
+  RecordOn                      = 0x09,
+  RecordStatus                  = 0x0A,
+  RecordTvScreen                = 0x0F,
+  ClearAnalogueTimer            = 0x33,
+  ClearDigitalTimer             = 0x99,
+  ClearExternalTimer            = 0xA1,
+  SetAnalogueTimer              = 0x34,
+  SetDigitalTimer               = 0x97,
+  SetExternalTimer              = 0xA2,
+  SetTimerProgramTitle          = 0x67,
+  TimerClearedStatus            = 0x43,
+  TimerStatus                   = 0x35,
+  CecVersion                    = 0x9E,
+  GetCecVersion                 = 0x9F,
+  GivePhysicalAddress           = 0x83,
+  GetMenuLanguage               = 0x91,
+  ReportPhysicalAddress         = 0x84,
+  SetMenuLanguage               = 0x32,
+  DeckControl                   = 0x42,
+  DeckStatus                    = 0x1B,
+  GiveDeckStatus                = 0x1A,
+  Play                          = 0x41,
+  GiveTunerDeviceStatus         = 0x08,
+  SelectAnalogueService         = 0x92,
+  SelectDigtalService           = 0x93,
+  TunerDeviceStatus             = 0x07,
+  TunerStepDecrement            = 0x06,
+  TunerStepIncrement            = 0x05,
+  DeviceVendorId                = 0x87,
+  GiveDeviceVendorId            = 0x8C,
+  VendorCommand                 = 0x89,
+  VendorCommandWithId           = 0xA0,
+  VendorRemoteButtonDown        = 0x8A,
+  VendorRemoteButtonUp          = 0x8B,
+  SetOsdString                  = 0x64,
+  GiveOsdName                   = 0x46,
+  SetOsdName                    = 0x47,
+  MenuRequest                   = 0x8D,
+  MenuStatus                    = 0x8E,
+  UserControlPressed            = 0x44,
+  UserControlRelease            = 0x45,
+  GiveDevicePowerStatus         = 0x8F,
+  ReportPowerStatus             = 0x90,
+  FeatureAbort                  = 0x00,
+  Abort                         = 0xFF,
+  GiveAudioStatus               = 0x71,
+  GiveSystemAudioMode           = 0x7D,
+  ReportAudioStatus             = 0x7A,
+  SetSystemAudioMode            = 0x72,
+  SystemAudioModeRequest        = 0x70,
+  SystemAudioModeStatus         = 0x7E,
+  SetAudioRate                  = 0x9A,
+  /* when this opcode is set, no opcode will be sent to the device. this is one of the reserved numbers */
+  None                          = 0xFD
+};
+
+public enum class CecSystemAudioStatus
+{
+  Off = 0,
+  On  = 1
+};
+
+public ref class CecAdapter
+{
+public:
+  CecAdapter(String ^ strPath, String ^ strComPort)
+  {
+    Path = strPath;
+    ComPort = strComPort;
+  }
+
+  property String ^ Path;
+  property String ^ ComPort;
+};
+
+public ref class CecDeviceTypeList
+{
+public:
+  CecDeviceTypeList(void)
+  {
+    Types = gcnew array<CecDeviceType>(5);
+    for (unsigned int iPtr = 0; iPtr < 5; iPtr++)
+      Types[iPtr] = CecDeviceType::Reserved;
+  }
+
+  property array<CecDeviceType> ^ Types;
+};
+
+public ref class CecLogicalAddresses
+{
+public:
+  CecLogicalAddresses(void)
+  {
+    Addresses = gcnew array<CecLogicalAddress>(16);
+    for (unsigned int iPtr = 0; iPtr < 16; iPtr++)
+      Addresses[iPtr] = CecLogicalAddress::Unregistered;
+  }
+
+  bool IsSet(CecLogicalAddress iAddress)
+  {
+    return Addresses[(unsigned int)iAddress] != CecLogicalAddress::Unregistered;
+  }
+
+  property array<CecLogicalAddress> ^ Addresses;
+};
+
+public ref class CecDatapacket
+{
+public:
+  CecDatapacket(void)
+  {
+    Data = gcnew array<uint8_t>(100);
+    Size = 0;
+  }
+
+  void PushBack(uint8_t data)
+  {
+    if (Size < 100)
+    {
+      Data[Size] = data;
+      Size++;
+    }
+  }
+
+  property array<uint8_t> ^ Data;
+  property uint8_t          Size;
+};
+
+public ref class CecCommand
+{
+public:
+  CecCommand(CecLogicalAddress iInitiator, CecLogicalAddress iDestination, bool bAck, bool bEom, CecOpcode iOpcode, int32_t iTransmitTimeout)
+  {
+    Initiator       = iInitiator;
+    Destination     = iDestination;
+    Ack             = bAck;
+    Eom             = bEom;
+    Opcode          = iOpcode;
+    OpcodeSet       = true;
+    TransmitTimeout = iTransmitTimeout;
+    Parameters      = gcnew CecDatapacket;
+    Empty           = false;
+  }
+
+  CecCommand(void)
+  {
+    Initiator       = CecLogicalAddress::Unknown;
+    Destination     = CecLogicalAddress::Unknown;
+    Ack             = false;
+    Eom             = false;
+    Opcode          = CecOpcode::None;
+    OpcodeSet       = false;
+    TransmitTimeout = 0;
+    Parameters      = gcnew CecDatapacket;
+    Empty           = true;
+  }
+
+  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);
+    }
+  }
+
+  property bool               Empty;
+  property CecLogicalAddress  Initiator;
+  property CecLogicalAddress  Destination;
+  property bool               Ack;
+  property bool               Eom;
+  property CecOpcode          Opcode;
+  property CecDatapacket ^    Parameters;
+  property bool               OpcodeSet;
+  property int32_t            TransmitTimeout;
+};
+
+public ref class CecKeypress
+{
+public:
+  CecKeypress(int iKeycode, unsigned int iDuration)
+  {
+    Keycode  = iKeycode;
+    Duration = iDuration;
+    Empty    = false;
+  }
+
+  CecKeypress(void)
+  {
+    Keycode  = 0;
+    Duration = 0;
+    Empty    = true;
+  }
+
+  property bool         Empty;
+  property int          Keycode;
+  property unsigned int Duration;
+};
+
+public ref class CecLogMessage
+{
+public:
+  CecLogMessage(String ^ strMessage, CecLogLevel iLevel, int64_t iTime)
+  {
+    Message = strMessage;
+    Level   = iLevel;
+    Time    = iTime;
+    Empty   = false;
+  }
+
+  CecLogMessage(void)
+  {
+    Message = "";
+    Level   = CecLogLevel::None;
+    Time    = 0;
+    Empty   = true;
+  }
+
+  property bool        Empty;
+  property String ^    Message;
+  property CecLogLevel Level;
+  property int64_t     Time;
+};
+
+public ref class LibCecSharp
+{
+public:
+   LibCecSharp(String ^ strDeviceName, CecDeviceTypeList ^ deviceTypes)
+   {
+     marshal_context ^ context = gcnew marshal_context();
+
+     const char* strDeviceNameC = context->marshal_as<const char*>(strDeviceName);
+
+     cec_device_type_list types;
+     for (unsigned int iPtr = 0; iPtr < 5; iPtr++)
+       types.types[iPtr] = (cec_device_type)deviceTypes->Types[iPtr];
+     m_libCec = (ICECAdapter *) CECInit(strDeviceNameC, types);
+     delete context;
+   }
+   
+   ~LibCecSharp(void)
+   {
+     CECDestroy(m_libCec);
+     m_libCec = NULL;
+   }
+
+protected:
+   !LibCecSharp(void)
+   {
+     CECDestroy(m_libCec);
+     m_libCec = NULL;
+   }
+
+public:
+  array<CecAdapter ^> ^ FindAdapters(String ^ path)
+  {
+    cec_adapter *devices = new cec_adapter[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->FindAdapters(devices, 10, NULL);
+
+    array<CecAdapter ^> ^ adapters = gcnew array<CecAdapter ^>(iDevicesFound);
+    for (unsigned int iPtr = 0; iPtr < iDevicesFound; iPtr++)
+      adapters[iPtr] = gcnew CecAdapter(gcnew String(devices[iPtr].path), gcnew String(devices[iPtr].comm));
+
+    delete devices;
+    delete context;
+    return adapters;
+  }
+
+  bool Open(String ^ strPort, int iTimeoutMs)
+  {
+    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;
+  }
+
+  void Close(void)
+  {
+    m_libCec->Close();
+  }
+
+  bool PingAdapter(void)
+  {
+    return m_libCec->PingAdapter();
+  }
+
+  bool StartBootloader(void)
+  {
+    return m_libCec->StartBootloader();
+  }
+
+  int GetMinLibVersion(void)
+  {
+    return m_libCec->GetMinLibVersion();
+  }
+
+  int GetLibVersionMajor(void)
+  {
+    return m_libCec->GetLibVersionMajor();
+  }
+
+  int GetLibVersionMinor(void)
+  {
+    return m_libCec->GetLibVersionMinor();
+  }
+
+  CecLogMessage ^ GetNextLogMessage(void)
+  {
+    cec_log_message msg;
+    if (m_libCec->GetNextLogMessage(&msg))
+    {
+      return gcnew CecLogMessage(gcnew String(msg.message), (CecLogLevel)msg.level, msg.time);
+    }
+
+    return gcnew CecLogMessage();
+  }
+
+  CecKeypress ^ GetNextKeypress(void)
+  {
+    cec_keypress key;
+    if (m_libCec->GetNextKeypress(&key))
+    {
+      return gcnew CecKeypress(key.keycode, key.duration);
+    }
+
+    return gcnew CecKeypress();
+  }
+
+  CecCommand ^ GetNextCommand(void)
+  {
+    cec_command command;
+    if (m_libCec->GetNextCommand(&command))
+    {
+      CecCommand ^ retVal = 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++)
+        retVal->Parameters->PushBack(command.parameters[iPtr]);
+      return retVal;
+    }
+
+    return gcnew CecCommand();
+  }
+
+  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);
+  }
+
+  bool SetLogicalAddress(CecLogicalAddress logicalAddress)
+  {
+    return m_libCec->SetLogicalAddress((cec_logical_address) logicalAddress);
+  }
+
+  bool SetPhysicalAddress(int16_t physicalAddress)
+  {
+    return m_libCec->SetPhysicalAddress(physicalAddress);
+  }
+
+  bool PowerOnDevices(CecLogicalAddress logicalAddress)
+  {
+    return m_libCec->PowerOnDevices((cec_logical_address) logicalAddress);
+  }
+
+  bool StandbyDevices(CecLogicalAddress logicalAddress)
+  {
+    return m_libCec->StandbyDevices((cec_logical_address) logicalAddress);
+  }
+
+  bool PollDevice(CecLogicalAddress logicalAddress)
+  {
+    return m_libCec->PollDevice((cec_logical_address) logicalAddress);
+  }
+
+  bool SetActiveSource(CecDeviceType type)
+  {
+    return m_libCec->SetActiveSource((cec_device_type) type);
+  }
+
+  bool SetDeckControlMode(CecDeckControlMode mode, bool sendUpdate)
+  {
+    return m_libCec->SetDeckControlMode((cec_deck_control_mode) mode, sendUpdate);
+  }
+
+  bool SetDeckInfo(CecDeckInfo info, bool sendUpdate)
+  {
+    return m_libCec->SetDeckInfo((cec_deck_info) info, sendUpdate);
+  }
+
+  bool SetInactiveView(void)
+  {
+    return m_libCec->SetInactiveView();
+  }
+
+  bool SetMenuState(CecMenuState state, bool sendUpdate)
+  {
+    return m_libCec->SetMenuState((cec_menu_state) state, sendUpdate);
+  }
+
+  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;
+  }
+
+  bool SwitchMonitoring(bool enable)
+  {
+    return m_libCec->SwitchMonitoring(enable);
+  }
+
+  CecVersion GetDeviceCecVersion(CecLogicalAddress logicalAddress)
+  {
+    return (CecVersion) m_libCec->GetDeviceCecVersion((cec_logical_address) logicalAddress);
+  }
+
+  String ^ GetDeviceMenuLanguage(CecLogicalAddress logicalAddress)
+  {
+    cec_menu_language lang;
+    if (m_libCec->GetDeviceMenuLanguage((cec_logical_address) logicalAddress, &lang))
+    {
+      return gcnew String(lang.language);
+    }
+
+    return gcnew String("");
+  }
+
+  CecVendorId GetDeviceVendorId(CecLogicalAddress logicalAddress)
+  {
+    return (CecVendorId)m_libCec->GetDeviceVendorId((cec_logical_address) logicalAddress);
+  }
+
+  CecPowerStatus GetDevicePowerStatus(CecLogicalAddress logicalAddress)
+  {
+    return (CecPowerStatus) m_libCec->GetDevicePowerStatus((cec_logical_address) logicalAddress);
+  }
+
+  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->Addresses[iDevices++] = (CecLogicalAddress)iPtr;
+
+    return retVal;
+  }
+
+  bool IsActiveDevice(CecLogicalAddress logicalAddress)
+  {
+    return m_libCec->IsActiveDevice((cec_logical_address)logicalAddress);
+  }
+
+  bool IsActiveDeviceType(CecDeviceType type)
+  {
+    return m_libCec->IsActiveDeviceType((cec_device_type)type);
+  }
+
+  bool SetHDMIPort(CecLogicalAddress address, uint8_t port)
+  {
+    return m_libCec->SetHDMIPort((cec_logical_address)address, port);
+  }
+
+  uint8_t VolumeUp(bool wait)
+  {
+    return m_libCec->VolumeUp(wait);
+  }
+
+  uint8_t VolumeDown(bool wait)
+  {
+    return m_libCec->VolumeDown(wait);
+  }
+
+  uint8_t MuteAudio(bool wait)
+  {
+    return m_libCec->MuteAudio(wait);
+  }
+
+  bool SendKeypress(CecLogicalAddress destination, CecUserControlCode key, bool wait)
+  {
+    return m_libCec->SendKeypress((cec_logical_address)destination, (cec_user_control_code)key, wait);
+  }
+
+  bool SendKeyRelease(CecLogicalAddress destination, bool wait)
+  {
+    return m_libCec->SendKeyRelease((cec_logical_address)destination, wait);
+  }
+
+  String ^ GetDeviceOSDName(CecLogicalAddress logicalAddress)
+  {
+    cec_osd_name osd = m_libCec->GetDeviceOSDName((cec_logical_address) logicalAddress);
+    return gcnew String(osd.name);
+  }
+
+  CecLogicalAddress GetActiveSource()
+  {
+    return (CecLogicalAddress)m_libCec->GetActiveSource();
+  }
+
+  bool IsActiveSource(CecLogicalAddress logicalAddress)
+  {
+    return m_libCec->IsActiveSource((cec_logical_address)logicalAddress);
+  }
+
+  uint16_t GetDevicePhysicalAddress(CecLogicalAddress iAddress)
+  {
+    return m_libCec->GetDevicePhysicalAddress((cec_logical_address)iAddress);
+  }
+
+  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);
+  }
+
+private:
+   ICECAdapter *m_libCec;
+};
diff --git a/src/LibCecSharp/Stdafx.cpp b/src/LibCecSharp/Stdafx.cpp
new file mode 100644 (file)
index 0000000..70d5258
--- /dev/null
@@ -0,0 +1,5 @@
+// stdafx.cpp : source file that includes just the standard includes
+// LibCecSharp.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
diff --git a/src/LibCecSharp/Stdafx.h b/src/LibCecSharp/Stdafx.h
new file mode 100644 (file)
index 0000000..3cc4c24
--- /dev/null
@@ -0,0 +1,7 @@
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently,
+// but are changed infrequently
+
+#pragma once
+
+
diff --git a/src/LibCecSharp/resource.h b/src/LibCecSharp/resource.h
new file mode 100644 (file)
index 0000000..d5ac7c4
--- /dev/null
@@ -0,0 +1,3 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by app.rc
index 1aaf3c8573c4efac9784650b28f939006036177b..54077d6ed776b4b6ef72f0dcc0d76cffd948ab45 100644 (file)
@@ -32,7 +32,7 @@
 
 #include "AdapterCommunication.h"
 
-#include "LibCEC.h"
+#include "CECProcessor.h"
 #include "platform/serialport.h"
 #include "util/StdString.h"
 #include "platform/timeutils.h"
@@ -64,7 +64,7 @@ CCECAdapterMessage::CCECAdapterMessage(const cec_command &command)
   if (command.opcode_set == 1)
   {
     push_back(MSGSTART);
-    push_escaped(command.parameters.empty() ? (uint8_t)MSGCODE_TRANSMIT_EOM : (uint8_t)MSGCODE_TRANSMIT);
+    push_escaped(command.parameters.IsEmpty() ? (uint8_t)MSGCODE_TRANSMIT_EOM : (uint8_t)MSGCODE_TRANSMIT);
     push_back((uint8_t) command.opcode);
     push_back(MSGEND);
 
@@ -183,30 +183,37 @@ CStdString CCECAdapterMessage::MessageCodeAsString(void) const
 CStdString CCECAdapterMessage::ToString(void) const
 {
   CStdString strMsg;
-  strMsg = MessageCodeAsString();
-
-  switch (message())
+  if (size() == 0)
   {
-  case MSGCODE_TIMEOUT_ERROR:
-  case MSGCODE_HIGH_ERROR:
-  case MSGCODE_LOW_ERROR:
+    strMsg = "empty message";
+  }
+  else
+  {
+    strMsg = MessageCodeAsString();
+
+    switch (message())
     {
-      int iLine      = (size() >= 3) ? (at(1) << 8) | at(2) : 0;
-      uint32_t iTime = (size() >= 7) ? (at(3) << 24) | (at(4) << 16) | (at(5) << 8) | at(6) : 0;
-      strMsg.AppendFormat(" line:%i", iLine);
-      strMsg.AppendFormat(" time:%u", iTime);
+    case MSGCODE_TIMEOUT_ERROR:
+    case MSGCODE_HIGH_ERROR:
+    case MSGCODE_LOW_ERROR:
+      {
+        int iLine      = (size() >= 3) ? (at(1) << 8) | at(2) : 0;
+        uint32_t iTime = (size() >= 7) ? (at(3) << 24) | (at(4) << 16) | (at(5) << 8) | at(6) : 0;
+        strMsg.AppendFormat(" line:%i", iLine);
+        strMsg.AppendFormat(" time:%u", iTime);
+      }
+      break;
+    case MSGCODE_FRAME_START:
+      if (size() >= 2)
+        strMsg.AppendFormat(" initiator:%1x destination:%1x ack:%s %s", initiator(), destination(), ack() ? "high" : "low", eom() ? "eom" : "");
+      break;
+    case MSGCODE_FRAME_DATA:
+      if (size() >= 2)
+        strMsg.AppendFormat(" %02x %s", at(1), eom() ? "eom" : "");
+      break;
+    default:
+      break;
     }
-    break;
-  case MSGCODE_FRAME_START:
-    if (size() >= 2)
-      strMsg.AppendFormat(" initiator:%1x destination:%1x ack:%s %s", initiator(), destination(), ack() ? "high" : "low", eom() ? "eom" : "");
-    break;
-  case MSGCODE_FRAME_DATA:
-    if (size() >= 2)
-      strMsg.AppendFormat(" %02x %s", at(1), eom() ? "eom" : "");
-    break;
-  default:
-    break;
   }
 
   return strMsg;
@@ -215,21 +222,20 @@ CStdString CCECAdapterMessage::ToString(void) const
 bool CCECAdapterMessage::is_error(void) const
 {
   cec_adapter_messagecode code = message();
-  return (code == MSGCODE_TIMEOUT_ERROR ||
-    code == MSGCODE_HIGH_ERROR ||
+  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_LINE_TIMEOUT ||
     code == MSGCODE_TRANSMIT_FAILED_LINE ||
-    code ==  MSGCODE_TRANSMIT_FAILED_ACK ||
+    code == MSGCODE_TRANSMIT_FAILED_ACK ||
     code == MSGCODE_TRANSMIT_FAILED_TIMEOUT_DATA ||
     code == MSGCODE_TRANSMIT_FAILED_TIMEOUT_LINE);
 }
 
 void CCECAdapterMessage::push_escaped(uint8_t byte)
 {
-  if (byte >= MSGESC && byte != MSGSTART)
+  if (byte >= MSGESC)
   {
     push_back(MSGESC);
     push_back(byte - ESCOFFSET);
@@ -238,9 +244,10 @@ void CCECAdapterMessage::push_escaped(uint8_t byte)
     push_back(byte);
 }
 
-CAdapterCommunication::CAdapterCommunication(CLibCEC *controller) :
+CAdapterCommunication::CAdapterCommunication(CCECProcessor *processor) :
     m_port(NULL),
-    m_controller(controller)
+    m_processor(processor),
+    m_iLineTimeout(0)
 {
   m_port = new CSerialPort;
 }
@@ -261,38 +268,38 @@ bool CAdapterCommunication::Open(const char *strPort, uint16_t iBaudRate /* = 38
   CLockObject lock(&m_mutex);
   if (!m_port)
   {
-    m_controller->AddLog(CEC_LOG_ERROR, "port is NULL");
+    m_processor->AddLog(CEC_LOG_ERROR, "port is NULL");
     return false;
   }
 
   if (IsOpen())
   {
-    m_controller->AddLog(CEC_LOG_ERROR, "port is already open");
+    m_processor->AddLog(CEC_LOG_ERROR, "port is already open");
   }
 
   if (!m_port->Open(strPort, iBaudRate))
   {
     CStdString strError;
     strError.Format("error opening serial port '%s': %s", strPort, m_port->GetError().c_str());
-    m_controller->AddLog(CEC_LOG_ERROR, strError);
+    m_processor->AddLog(CEC_LOG_ERROR, strError);
     return false;
   }
 
-  m_controller->AddLog(CEC_LOG_DEBUG, "connection opened");
+  m_processor->AddLog(CEC_LOG_DEBUG, "connection opened");
 
   //clear any input bytes
-  uint8_t buff[1024];
-  m_port->Read(buff, sizeof(buff), 500);
+  uint8_t buff[1];
+  while (m_port->Read(buff, 1, 5) == 1) {}
 
   if (CreateThread())
   {
     m_startCondition.Wait(&m_mutex);
-    m_controller->AddLog(CEC_LOG_DEBUG, "communication thread started");
+    m_processor->AddLog(CEC_LOG_DEBUG, "communication thread started");
     return true;
   }
   else
   {
-    m_controller->AddLog(CEC_LOG_DEBUG, "could not create a communication thread");
+    m_processor->AddLog(CEC_LOG_DEBUG, "could not create a communication thread");
   }
 
   return false;
@@ -315,11 +322,15 @@ void *CAdapterCommunication::Process(void)
 
   while (!IsStopped())
   {
-    ReadFromDevice(500);
+    ReadFromDevice(50);
     Sleep(5);
     WriteNextCommand();
   }
 
+  CCECAdapterMessage *msg;
+  if (m_outBuffer.Pop(msg))
+    msg->condition.Broadcast();
+
   return NULL;
 }
 
@@ -335,7 +346,7 @@ bool CAdapterCommunication::ReadFromDevice(uint32_t iTimeout)
   {
     CStdString strError;
     strError.Format("error reading from serial port: %s", m_port->GetError().c_str());
-    m_controller->AddLog(CEC_LOG_ERROR, strError);
+    m_processor->AddLog(CEC_LOG_ERROR, strError);
     return false;
   }
   else if (iBytesRead > 0)
@@ -357,23 +368,25 @@ void CAdapterCommunication::WriteNextCommand(void)
 {
   CCECAdapterMessage *msg;
   if (m_outBuffer.Pop(msg))
+    SendMessageToAdapter(msg);
+}
+
+void CAdapterCommunication::SendMessageToAdapter(CCECAdapterMessage *msg)
+{
+  CLockObject lock(&msg->mutex);
+  if (m_port->Write(msg) != (int32_t) msg->size())
   {
-    CLockObject lock(&msg->mutex);
-    if (m_port->Write(msg) != (int32_t) msg->size())
-    {
-      CStdString strError;
-      strError.Format("error writing to serial port: %s", m_port->GetError().c_str());
-      m_controller->AddLog(CEC_LOG_ERROR, strError);
-      msg->state = ADAPTER_MESSAGE_STATE_ERROR;
-    }
-    else
-    {
-      m_controller->AddLog(CEC_LOG_DEBUG, "command sent");
-      CCondition::Sleep((uint32_t) msg->size() * 24 /*data*/ + 5 /*start bit (4.5 ms)*/ + 10);
-      msg->state = ADAPTER_MESSAGE_STATE_SENT;
-    }
-    msg->condition.Signal();
+    CStdString strError;
+    strError.Format("error writing to serial port: %s", m_port->GetError().c_str());
+    m_processor->AddLog(CEC_LOG_ERROR, strError);
+    msg->state = ADAPTER_MESSAGE_STATE_ERROR;
   }
+  else
+  {
+    m_processor->AddLog(CEC_LOG_DEBUG, "command sent");
+    msg->state = ADAPTER_MESSAGE_STATE_SENT;
+  }
+  msg->condition.Signal();
 }
 
 bool CAdapterCommunication::Write(CCECAdapterMessage *data)
@@ -411,7 +424,8 @@ bool CAdapterCommunication::Read(CCECAdapterMessage &msg, uint32_t iTimeout)
     }
     else if (buf == MSGSTART) //we found a msgstart before msgend, this is not right, remove
     {
-      m_controller->AddLog(CEC_LOG_ERROR, "received MSGSTART before MSGEND");
+      if (msg.size() > 0)
+        m_processor->AddLog(CEC_LOG_WARNING, "received MSGSTART before MSGEND, removing previous buffer contents");
       msg.clear();
       bGotStart = true;
     }
@@ -448,16 +462,17 @@ bool CAdapterCommunication::StartBootloader(void)
   if (!IsRunning())
     return bReturn;
 
-  m_controller->AddLog(CEC_LOG_DEBUG, "starting the bootloader");
+  m_processor->AddLog(CEC_LOG_DEBUG, "starting the bootloader");
   CCECAdapterMessage *output = new CCECAdapterMessage;
 
   output->push_back(MSGSTART);
   output->push_escaped(MSGCODE_START_BOOTLOADER);
   output->push_back(MSGEND);
 
-  if ((bReturn = Write(output)) == false)
-    m_controller->AddLog(CEC_LOG_ERROR, "could not start the bootloader");
-
+  CLockObject lock(&output->mutex);
+  if (Write(output))
+    output->condition.Wait(&output->mutex);
+  bReturn = output->state == ADAPTER_MESSAGE_STATE_SENT;
   delete output;
 
   return bReturn;
@@ -469,22 +484,43 @@ bool CAdapterCommunication::PingAdapter(void)
   if (!IsRunning())
     return bReturn;
 
-  m_controller->AddLog(CEC_LOG_DEBUG, "sending ping");
+  m_processor->AddLog(CEC_LOG_DEBUG, "sending ping");
   CCECAdapterMessage *output = new CCECAdapterMessage;
 
   output->push_back(MSGSTART);
   output->push_escaped(MSGCODE_PING);
   output->push_back(MSGEND);
 
-  if ((bReturn = Write(output)) == false)
-    m_controller->AddLog(CEC_LOG_ERROR, "could not send ping command");
-
-  // TODO check for pong
+  CLockObject lock(&output->mutex);
+  if (Write(output))
+    output->condition.Wait(&output->mutex);
+  bReturn = output->state == ADAPTER_MESSAGE_STATE_SENT;
   delete output;
 
   return bReturn;
 }
 
+bool CAdapterCommunication::SetLineTimeout(uint8_t iTimeout)
+{
+  bool bReturn(m_iLineTimeout != iTimeout);
+
+  if (!bReturn)
+  {
+    CCECAdapterMessage *output = new CCECAdapterMessage;
+
+    output->push_back(MSGSTART);
+    output->push_escaped(MSGCODE_TRANSMIT_IDLETIME);
+    output->push_escaped(iTimeout);
+    output->push_back(MSGEND);
+
+    if ((bReturn = Write(output)) == false)
+      m_processor->AddLog(CEC_LOG_ERROR, "could not set the idletime");
+    delete output;
+  }
+
+  return bReturn;
+}
+
 bool CAdapterCommunication::IsOpen(void) const
 {
   return !IsStopped() && m_port->IsOpen() && IsRunning();
index d140a1b5a0f0b8c563d3bdc91c832dc4488454f3..1b815269f8ebb4cf65f2c96a43b64e1aa80133d1 100644 (file)
@@ -58,21 +58,31 @@ namespace CEC
     CStdString ToString(void) const;
     CStdString MessageCodeAsString(void) const;
 
-    bool                    empty(void) const             { return packet.empty(); }
+    bool                    empty(void) const             { return packet.IsEmpty(); }
     uint8_t                 operator[](uint8_t pos) const { return packet[pos]; }
     uint8_t                 at(uint8_t pos) const         { return packet[pos]; }
     uint8_t                 size(void) const              { return packet.size; }
-    void                    clear(void)                   { state = ADAPTER_MESSAGE_STATE_UNKNOWN; transmit_timeout = 0; packet.clear(); }
-    void                    shift(uint8_t iShiftBy)       { packet.shift(iShiftBy); }
-    void                    push_back(uint8_t add)        { packet.push_back(add); }
-    cec_adapter_messagecode message(void) const           { return packet.size >= 1 ? (cec_adapter_messagecode) (packet.at(0) & ~(MSGCODE_FRAME_EOM | MSGCODE_FRAME_ACK))  : MSGCODE_NOTHING; }
-    bool                    eom(void) const               { return packet.size >= 1 ? (packet.at(0) & MSGCODE_FRAME_EOM) != 0 : false; }
-    bool                    ack(void) const               { return packet.size >= 1 ? (packet.at(0) & MSGCODE_FRAME_ACK) != 0 : false; }
-    cec_logical_address     initiator(void) const         { return packet.size >= 2 ? (cec_logical_address) (packet.at(1) >> 4)  : CECDEVICE_UNKNOWN; };
-    cec_logical_address     destination(void) const       { return packet.size >= 2 ? (cec_logical_address) (packet.at(1) & 0xF) : CECDEVICE_UNKNOWN; };
+    void                    clear(void)                   { state = ADAPTER_MESSAGE_STATE_UNKNOWN; transmit_timeout = 0; packet.Clear(); maxTries = CEC_DEFAULT_TRANSMIT_RETRIES + 1; tries = 0; reply = MSGCODE_NOTHING; }
+    void                    shift(uint8_t iShiftBy)       { packet.Shift(iShiftBy); }
+    void                    push_back(uint8_t add)        { packet.PushBack(add); }
+    cec_adapter_messagecode message(void) const           { return packet.size >= 1 ? (cec_adapter_messagecode) (packet.At(0) & ~(MSGCODE_FRAME_EOM | MSGCODE_FRAME_ACK))  : MSGCODE_NOTHING; }
+    bool                    eom(void) const               { return packet.size >= 1 ? (packet.At(0) & MSGCODE_FRAME_EOM) != 0 : false; }
+    bool                    ack(void) const               { return packet.size >= 1 ? (packet.At(0) & MSGCODE_FRAME_ACK) != 0 : false; }
+    cec_logical_address     initiator(void) const         { return packet.size >= 2 ? (cec_logical_address) (packet.At(1) >> 4)  : CECDEVICE_UNKNOWN; };
+    cec_logical_address     destination(void) const       { return packet.size >= 2 ? (cec_logical_address) (packet.At(1) & 0xF) : CECDEVICE_UNKNOWN; };
     bool                    is_error(void) const;
     void                    push_escaped(uint8_t byte);
+    bool                    needs_retry(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; }
 
+    uint8_t                   maxTries;
+    uint8_t                   tries;
+    cec_adapter_messagecode   reply;
     cec_datapacket            packet;
     cec_adapter_message_state state;
     int32_t                   transmit_timeout;
@@ -81,12 +91,12 @@ namespace CEC
   };
 
   class CSerialPort;
-  class CLibCEC;
+  class CCECProcessor;
 
   class CAdapterCommunication : private CThread
   {
   public:
-    CAdapterCommunication(CLibCEC *controller);
+    CAdapterCommunication(CCECProcessor *processor);
     virtual ~CAdapterCommunication();
 
     bool Open(const char *strPort, uint16_t iBaudRate = 38400, uint32_t iTimeoutMs = 10000);
@@ -99,19 +109,22 @@ namespace CEC
 
     void *Process(void);
 
+    bool SetLineTimeout(uint8_t iTimeout);
     bool StartBootloader(void);
 
   private:
+    void SendMessageToAdapter(CCECAdapterMessage *msg);
     void WriteNextCommand(void);
     void AddData(uint8_t *data, uint8_t iLen);
     bool ReadFromDevice(uint32_t iTimeout);
 
     CSerialPort *                    m_port;
-    CLibCEC *                        m_controller;
+    CCECProcessor *                  m_processor;
     CecBuffer<uint8_t>               m_inBuffer;
     CecBuffer<CCECAdapterMessage *>  m_outBuffer;
     CMutex                           m_mutex;
     CCondition                       m_rcvCondition;
     CCondition                       m_startCondition;
+    uint8_t                          m_iLineTimeout;
   };
 };
index 98c3a0e60a09a083daf38fc9e8cbc80d03b2a500..b304e43561d2eb5c0961a425b140b35bda88cd6a 100644 (file)
 #include <IOKit/usb/IOUSBLib.h>
 #include <IOKit/serial/IOSerialKeys.h>
 #include <CoreFoundation/CoreFoundation.h>
-
-#elif !defined(__WINDOWS__)
-#include <dirent.h>
-#include <libudev.h>
-#include <poll.h>
-#else
+#elif defined(__WINDOWS__)
 #include <setupapi.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 } };
+#elif defined(HAVE_LIBUDEV)
+#include <dirent.h>
+#include <libudev.h>
+#include <poll.h>
 #endif
 
 #define CEC_VID 0x2548
@@ -61,7 +60,7 @@ static GUID USB_RAW_GUID =  { 0xA5DCBF10, 0x6530, 0x11D2, { 0x90, 0x1F, 0x00, 0x
 using namespace CEC;
 using namespace std;
 
-#if !defined(__WINDOWS__)
+#if defined(HAVE_LIBUDEV)
 bool TranslateComPort(CStdString &strString)
 {
   CStdString strTmp(strString);
@@ -180,8 +179,7 @@ uint8_t CAdapterDetection::FindAdapters(cec_adapter *deviceList, uint8_t iBufSiz
     }
     IOObjectRelease(serialPortIterator);
   }
-
-#elif !defined(__WINDOWS__)
+#elif defined(HAVE_LIBUDEV)
   struct udev *udev;
   if (!(udev = udev_new()))
     return -1;
@@ -229,7 +227,7 @@ uint8_t CAdapterDetection::FindAdapters(cec_adapter *deviceList, uint8_t iBufSiz
 
   udev_enumerate_unref(enumerate);
   udev_unref(udev);
-#else
+#elif defined(__WINDOWS__)
   HDEVINFO hDevHandle;
   DWORD    required = 0, iMemberIndex = 0;
   int      nBufferSize = 0;
index b0bf49f335065dfd9af4479ebf30b1c5b1b23d01..60a6d1921944c1bbb6be47cfb610867003b91e32 100644 (file)
 using namespace CEC;
 using namespace std;
 
-CCECProcessor::CCECProcessor(CLibCEC *controller, CAdapterCommunication *serComm, const char *strDeviceName, cec_logical_address iLogicalAddress /* = CECDEVICE_PLAYBACKDEVICE1 */, uint16_t iPhysicalAddress /* = CEC_DEFAULT_PHYSICAL_ADDRESS*/) :
+CCECProcessor::CCECProcessor(CLibCEC *controller, const char *strDeviceName, cec_logical_address iLogicalAddress /* = CECDEVICE_PLAYBACKDEVICE1 */, uint16_t iPhysicalAddress /* = CEC_DEFAULT_PHYSICAL_ADDRESS*/) :
     m_bStarted(false),
+    m_iHDMIPort(CEC_DEFAULT_HDMI_PORT),
+    m_iBaseDevice((cec_logical_address)CEC_DEFAULT_BASE_DEVICE),
+    m_lastInitiator(CECDEVICE_UNKNOWN),
     m_strDeviceName(strDeviceName),
-    m_communication(serComm),
     m_controller(controller),
-    m_bMonitor(false)
+    m_bMonitor(false),
+    m_busScan(NULL),
+    m_iStandardLineTimeout(3),
+    m_iRetryLineTimeout(3),
+    m_iLastTransmission(0)
 {
-  m_logicalAddresses.clear();
-  m_logicalAddresses.set(iLogicalAddress);
+  m_communication = new CAdapterCommunication(this);
+  m_logicalAddresses.Clear();
+  m_logicalAddresses.Set(iLogicalAddress);
   m_types.clear();
   for (int iPtr = 0; iPtr <= 16; iPtr++)
     m_busDevices[iPtr] = new CCECBusDevice(this, (cec_logical_address) iPtr, iPtr == iLogicalAddress ? iPhysicalAddress : 0);
 }
 
-CCECProcessor::CCECProcessor(CLibCEC *controller, CAdapterCommunication *serComm, const char *strDeviceName, const cec_device_type_list &types) :
+CCECProcessor::CCECProcessor(CLibCEC *controller, const char *strDeviceName, const cec_device_type_list &types) :
     m_bStarted(false),
+    m_iHDMIPort(CEC_DEFAULT_HDMI_PORT),
+    m_iBaseDevice((cec_logical_address)CEC_DEFAULT_BASE_DEVICE),
     m_strDeviceName(strDeviceName),
     m_types(types),
-    m_communication(serComm),
     m_controller(controller),
-    m_bMonitor(false)
+    m_bMonitor(false),
+    m_iStandardLineTimeout(3),
+    m_iRetryLineTimeout(3),
+    m_iLastTransmission(0)
 {
-  m_logicalAddresses.clear();
+  m_communication = new CAdapterCommunication(this);
+  m_logicalAddresses.Clear();
   for (int iPtr = 0; iPtr < 16; iPtr++)
   {
     switch(iPtr)
@@ -105,20 +117,29 @@ CCECProcessor::CCECProcessor(CLibCEC *controller, CAdapterCommunication *serComm
 
 CCECProcessor::~CCECProcessor(void)
 {
+  m_bStarted = false;
   m_startCondition.Broadcast();
   StopThread();
+
+  delete m_communication;
   m_communication = NULL;
   m_controller = NULL;
   for (unsigned int iPtr = 0; iPtr < 16; iPtr++)
     delete m_busDevices[iPtr];
 }
 
-bool CCECProcessor::Start(void)
+bool CCECProcessor::Start(const char *strPort, uint16_t iBaudRate /* = 38400 */, uint32_t iTimeoutMs /* = 10000 */)
 {
   CLockObject lock(&m_mutex);
-  if (!m_communication || !m_communication->IsOpen())
+  if (!m_communication || m_communication->IsOpen())
+  {
+    m_controller->AddLog(CEC_LOG_ERROR, "connection already opened");
+    return false;
+  }
+
+  if (!m_communication->Open(strPort, iBaudRate, iTimeoutMs))
   {
-    m_controller->AddLog(CEC_LOG_ERROR, "connection is closed");
+    m_controller->AddLog(CEC_LOG_ERROR, "could not open a connection");
     return false;
   }
 
@@ -129,84 +150,74 @@ bool CCECProcessor::Start(void)
       m_controller->AddLog(CEC_LOG_ERROR, "could not create a processor thread");
       return false;
     }
-    return true;
-  }
-  else
-    m_controller->AddLog(CEC_LOG_ERROR, "could not create a processor thread");
-
-  return false;
-}
 
-bool CCECProcessor::TryLogicalAddress(cec_logical_address address, unsigned int iIndex)
-{
-  const char *strLabel = CCECCommandHandler::ToString(address);
-  CStdString strLog;
-  strLog.Format("trying logical address '%s'", strLabel);
-  AddLog(CEC_LOG_DEBUG, strLog);
+    lock.Leave();
 
-  SetAckMask(0x1 << address);
-  if (!m_busDevices[address]->TransmitPoll(address))
-  {
-    strLog.Format("using logical address '%s'", strLabel);
-    AddLog(CEC_LOG_NOTICE, strLog);
+    m_busDevices[CECDEVICE_TV]->GetVendorId();
 
-    /* only set our OSD name and active source for the primary device */
-    if (m_logicalAddresses.empty())
+    if (SetHDMIPort(m_iBaseDevice, m_iHDMIPort, true))
     {
-      m_busDevices[address]->m_strDeviceName = m_strDeviceName;
-      m_busDevices[address]->m_bActiveSource = true;
+      m_controller->AddLog(CEC_LOG_DEBUG, "processor thread started");
+      m_busScan = new CCECBusScan(this);
+      m_busScan->CreateThread(true);
+      return true;
     }
-    m_busDevices[address]->m_powerStatus = CEC_POWER_STATUS_STANDBY;
-    m_busDevices[address]->m_cecVersion =  CEC_VERSION_1_3A;
-
-    m_logicalAddresses.set(address);
+    else
+    {
+      m_controller->AddLog(CEC_LOG_ERROR, "failed to initialise the processor");
+    }
+  }
 
-    // TODO
-    m_busDevices[address]->SetPhysicalAddress((uint16_t)CEC_DEFAULT_PHYSICAL_ADDRESS + ((uint16_t)iIndex * 0x100));
+  m_controller->AddLog(CEC_LOG_ERROR, "could not create a processor thread");
+  return false;
+}
 
+bool CCECProcessor::TryLogicalAddress(cec_logical_address address)
+{
+  if (m_busDevices[address]->TryLogicalAddress())
+  {
+    m_logicalAddresses.Set(address);
     return true;
   }
 
-  strLog.Format("logical address '%s' already taken", strLabel);
-  AddLog(CEC_LOG_DEBUG, strLog);
   return false;
 }
 
-bool CCECProcessor::FindLogicalAddressRecordingDevice(unsigned int iIndex)
+bool CCECProcessor::FindLogicalAddressRecordingDevice(void)
 {
   AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'recording device'");
-  return TryLogicalAddress(CECDEVICE_RECORDINGDEVICE1, iIndex) ||
-      TryLogicalAddress(CECDEVICE_RECORDINGDEVICE2, iIndex) ||
-      TryLogicalAddress(CECDEVICE_RECORDINGDEVICE3, iIndex);
+  return TryLogicalAddress(CECDEVICE_RECORDINGDEVICE1) ||
+      TryLogicalAddress(CECDEVICE_RECORDINGDEVICE2) ||
+      TryLogicalAddress(CECDEVICE_RECORDINGDEVICE3);
 }
 
-bool CCECProcessor::FindLogicalAddressTuner(unsigned int iIndex)
+bool CCECProcessor::FindLogicalAddressTuner(void)
 {
   AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'tuner'");
-  return TryLogicalAddress(CECDEVICE_TUNER1, iIndex) ||
-      TryLogicalAddress(CECDEVICE_TUNER2, iIndex) ||
-      TryLogicalAddress(CECDEVICE_TUNER3, iIndex) ||
-      TryLogicalAddress(CECDEVICE_TUNER4, iIndex);
+  return TryLogicalAddress(CECDEVICE_TUNER1) ||
+      TryLogicalAddress(CECDEVICE_TUNER2) ||
+      TryLogicalAddress(CECDEVICE_TUNER3) ||
+      TryLogicalAddress(CECDEVICE_TUNER4);
 }
 
-bool CCECProcessor::FindLogicalAddressPlaybackDevice(unsigned int iIndex)
+bool CCECProcessor::FindLogicalAddressPlaybackDevice(void)
 {
   AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'playback device'");
-  return TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE1, iIndex) ||
-      TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE2, iIndex) ||
-      TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE3, iIndex);
+  return TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE1) ||
+      TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE2) ||
+      TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE3);
 }
 
-bool CCECProcessor::FindLogicalAddressAudioSystem(unsigned int iIndex)
+bool CCECProcessor::FindLogicalAddressAudioSystem(void)
 {
   AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'audio'");
-  return TryLogicalAddress(CECDEVICE_AUDIOSYSTEM, iIndex);
+  return TryLogicalAddress(CECDEVICE_AUDIOSYSTEM);
 }
 
 bool CCECProcessor::FindLogicalAddresses(void)
 {
   bool bReturn(true);
-  m_logicalAddresses.clear();
+  m_logicalAddresses.Clear();
   CStdString strLog;
 
   for (unsigned int iPtr = 0; iPtr < 5; iPtr++)
@@ -218,13 +229,13 @@ bool CCECProcessor::FindLogicalAddresses(void)
     AddLog(CEC_LOG_DEBUG, strLog);
 
     if (m_types.types[iPtr] == CEC_DEVICE_TYPE_RECORDING_DEVICE)
-      bReturn &= FindLogicalAddressRecordingDevice(iPtr);
+      bReturn &= FindLogicalAddressRecordingDevice();
     if (m_types.types[iPtr] == CEC_DEVICE_TYPE_TUNER)
-      bReturn &= FindLogicalAddressTuner(iPtr);
+      bReturn &= FindLogicalAddressTuner();
     if (m_types.types[iPtr] == CEC_DEVICE_TYPE_PLAYBACK_DEVICE)
-      bReturn &= FindLogicalAddressPlaybackDevice(iPtr);
+      bReturn &= FindLogicalAddressPlaybackDevice();
     if (m_types.types[iPtr] == CEC_DEVICE_TYPE_AUDIO_SYSTEM)
-      bReturn &= FindLogicalAddressAudioSystem(iPtr);
+      bReturn &= FindLogicalAddressAudioSystem();
   }
 
   return bReturn;
@@ -236,28 +247,30 @@ void *CCECProcessor::Process(void)
   cec_command           command;
   CCECAdapterMessage    msg;
 
+  if (m_logicalAddresses.IsEmpty() && !FindLogicalAddresses())
   {
-    if (m_logicalAddresses.empty() && !FindLogicalAddresses())
-    {
-      CLockObject lock(&m_mutex);
-      m_controller->AddLog(CEC_LOG_ERROR, "could not detect our logical addressed");
-      m_startCondition.Signal();
-      return NULL;
-    }
+    CLockObject lock(&m_mutex);
+    m_controller->AddLog(CEC_LOG_ERROR, "could not detect our logical addresses");
+    m_startCondition.Signal();
+    return NULL;
+  }
+  else
+  {
+    /* only set our OSD name and active source for the primary device */
+    m_busDevices[m_logicalAddresses.primary]->m_strDeviceName = m_strDeviceName;
+    m_busDevices[m_logicalAddresses.primary]->m_bActiveSource = true;
 
-    SetAckMask(m_logicalAddresses.ackmask());
+    SetAckMask(m_logicalAddresses.AckMask());
 
-    {
-      CLockObject lock(&m_mutex);
-      m_controller->AddLog(CEC_LOG_DEBUG, "processor thread started");
-      m_bStarted = true;
-      m_startCondition.Signal();
-    }
+    CLockObject lock(&m_mutex);
+    m_bStarted = true;
+    m_controller->AddLog(CEC_LOG_DEBUG, "processor thread started");
+    m_startCondition.Signal();
   }
 
   while (!IsStopped())
   {
-    command.clear();
+    command.Clear();
     msg.clear();
 
     {
@@ -268,7 +281,6 @@ void *CCECProcessor::Process(void)
       }
       else if (m_communication->IsOpen() && m_communication->Read(msg, 50))
       {
-        m_controller->AddLog(msg.is_error() ? CEC_LOG_WARNING : CEC_LOG_DEBUG, msg.ToString());
         if ((bParseFrame = (ParseMessage(msg) && !IsStopped())) == true)
           command = m_currentframe;
       }
@@ -281,13 +293,18 @@ void *CCECProcessor::Process(void)
     Sleep(5);
 
     m_controller->CheckKeypressTimeout();
+  }
 
-    for (unsigned int iDevicePtr = 0; iDevicePtr < 16; iDevicePtr++)
-      m_busDevices[iDevicePtr]->PollVendorId();
-
-    Sleep(5);
+  if (m_busScan)
+  {
+    m_busScan->StopThread();
+    delete m_busScan;
+    m_busScan = NULL;
   }
 
+  if (m_communication)
+    m_communication->Close();
+
   return NULL;
 }
 
@@ -302,7 +319,7 @@ bool CCECProcessor::SetActiveSource(cec_device_type type /* = CEC_DEVICE_TYPE_RE
 
   if (type != CEC_DEVICE_TYPE_RESERVED)
   {
-    for (uint8_t iPtr = 0; iPtr < 16; iPtr++)
+    for (uint8_t iPtr = 0; iPtr <= 11; iPtr++)
     {
       if (m_logicalAddresses[iPtr] && m_busDevices[iPtr]->m_type == type)
       {
@@ -312,12 +329,47 @@ bool CCECProcessor::SetActiveSource(cec_device_type type /* = CEC_DEVICE_TYPE_RE
     }
   }
 
-  return SetStreamPath(m_busDevices[addr]->GetPhysicalAddress());
+  m_busDevices[addr]->SetActiveSource();
+  bReturn = m_busDevices[addr]->TransmitActiveSource();
+
+  if (bReturn && (m_busDevices[addr]->GetType() == CEC_DEVICE_TYPE_PLAYBACK_DEVICE ||
+      m_busDevices[addr]->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE))
+  {
+    bReturn = ((CCECPlaybackDevice *)m_busDevices[addr])->TransmitDeckStatus(CECDEVICE_TV);
+  }
+
+  return bReturn;
+}
+
+bool CCECProcessor::SetActiveSource(uint16_t iStreamPath)
+{
+  bool bReturn(false);
+
+  CCECBusDevice *device = GetDeviceByPhysicalAddress(iStreamPath);
+  if (device)
+  {
+    device->SetActiveSource();
+    bReturn = true;
+  }
+
+  return bReturn;
+}
+
+void CCECProcessor::SetStandardLineTimeout(uint8_t iTimeout)
+{
+  CLockObject lock(&m_mutex);
+  m_iStandardLineTimeout = iTimeout;
+}
+
+void CCECProcessor::SetRetryLineTimeout(uint8_t iTimeout)
+{
+  CLockObject lock(&m_mutex);
+  m_iRetryLineTimeout = iTimeout;
 }
 
 bool CCECProcessor::SetActiveView(void)
 {
-  return SetActiveSource();
+  return SetActiveSource(m_types.IsEmpty() ? CEC_DEVICE_TYPE_RESERVED : m_types[0]);
 }
 
 bool CCECProcessor::SetDeckControlMode(cec_deck_control_mode mode, bool bSendUpdate /* = true */)
@@ -352,32 +404,81 @@ bool CCECProcessor::SetDeckInfo(cec_deck_info info, bool bSendUpdate /* = true *
   return bReturn;
 }
 
-bool CCECProcessor::SetStreamPath(uint16_t iStreamPath)
+bool CCECProcessor::SetHDMIPort(cec_logical_address iBaseDevice, uint8_t iPort, bool bForce /* = false */)
 {
   bool bReturn(false);
 
-  CCECBusDevice *device = GetDeviceByPhysicalAddress(iStreamPath);
-  if (device)
-  {
-    for (unsigned int iPtr = 0; iPtr < 16; iPtr++)
-      m_busDevices[iPtr]->m_bActiveSource = false;
+  m_iBaseDevice = iBaseDevice;
+  m_iHDMIPort = iPort;
+  if (!m_bStarted && !bForce)
+    return true;
 
-    device->m_bActiveSource = true;
-    device->m_powerStatus   = CEC_POWER_STATUS_ON;
+  CStdString strLog;
+  strLog.Format("setting HDMI port to %d on device %s (%d)", iPort, ToString(iBaseDevice), (int)iBaseDevice);
+  AddLog(CEC_LOG_DEBUG, strLog);
 
-    bReturn = true;
+  uint16_t iPhysicalAddress(0);
+  if (iBaseDevice > CECDEVICE_TV)
+    iPhysicalAddress = m_busDevices[iBaseDevice]->GetPhysicalAddress();
+
+  if (iPhysicalAddress == 0xffff)
+  {
+    SetPhysicalAddress((uint16_t)iPort * 0x1000);
+    bReturn = false;
+  }
+  else
+  {
+    uint16_t iPos = 0;
+    if (iPhysicalAddress == 0)
+      iPos = 0x1000;
+    else if (iPhysicalAddress % 0x1000 == 0)
+      iPos = 0x100;
+    else if (iPhysicalAddress % 0x100 == 0)
+      iPos = 0x10;
+    else if (iPhysicalAddress % 0x10 == 0)
+      iPos = 0x1;
+
+    while(!bReturn && iPos > 0)
+    {
+      iPhysicalAddress += (uint16_t)(iPort * iPos);
+      strLog.Format("checking physical address %4x", iPhysicalAddress);
+      AddLog(CEC_LOG_DEBUG, strLog);
+      if (PhysicalAddressInUse(iPhysicalAddress))
+      {
+        strLog.Format("physical address %4x is in use", iPhysicalAddress);
+        AddLog(CEC_LOG_DEBUG, strLog);
+        iPos = (iPos == 1) ? 0 : iPos / 0x10;
+      }
+      else
+      {
+        strLog.Format("physical address %4x is free", iPhysicalAddress);
+        AddLog(CEC_LOG_DEBUG, strLog);
+        SetPhysicalAddress(iPhysicalAddress);
+        bReturn = true;
+      }
+    }
   }
 
   return bReturn;
 }
 
-bool CCECProcessor::SetInactiveView(void)
+bool CCECProcessor::PhysicalAddressInUse(uint16_t iPhysicalAddress)
+{
+  for (unsigned int iPtr = 0; iPtr < 15; iPtr++)
+  {
+    if (m_busDevices[iPtr]->GetPhysicalAddress(false) == iPhysicalAddress)
+      return true;
+  }
+  return false;
+}
+
+bool CCECProcessor::TransmitInactiveSource(void)
 {
   if (!IsRunning())
     return false;
 
-  if (!m_logicalAddresses.empty() && m_busDevices[m_logicalAddresses.primary])
-    return m_busDevices[m_logicalAddresses.primary]->TransmitInactiveView();
+  if (!m_logicalAddresses.IsEmpty() && m_busDevices[m_logicalAddresses.primary])
+    return m_busDevices[m_logicalAddresses.primary]->TransmitInactiveSource();
   return false;
 }
 
@@ -401,8 +502,8 @@ bool CCECProcessor::SetLogicalAddress(cec_logical_address iLogicalAddress)
     strLog.Format("<< setting primary logical address to %1x", iLogicalAddress);
     m_controller->AddLog(CEC_LOG_NOTICE, strLog.c_str());
     m_logicalAddresses.primary = iLogicalAddress;
-    m_logicalAddresses.set(iLogicalAddress);
-    return SetAckMask(m_logicalAddresses.ackmask());
+    m_logicalAddresses.Set(iLogicalAddress);
+    return SetAckMask(m_logicalAddresses.AckMask());
   }
 
   return true;
@@ -424,9 +525,15 @@ bool CCECProcessor::SetMenuState(cec_menu_state state, bool bSendUpdate /* = tru
 
 bool CCECProcessor::SetPhysicalAddress(uint16_t iPhysicalAddress)
 {
-  if (!m_logicalAddresses.empty() && m_busDevices[m_logicalAddresses.primary])
+  if (!m_logicalAddresses.IsEmpty())
   {
-    m_busDevices[m_logicalAddresses.primary]->SetPhysicalAddress(iPhysicalAddress);
+    for (uint8_t iPtr = 0; iPtr < 15; iPtr++)
+      if (m_logicalAddresses[iPtr])
+      {
+        m_busDevices[iPtr]->SetInactiveSource();
+        m_busDevices[iPtr]->SetPhysicalAddress(iPhysicalAddress);
+        m_busDevices[iPtr]->TransmitPhysicalAddress();
+      }
     return SetActiveView();
   }
   return false;
@@ -438,27 +545,82 @@ bool CCECProcessor::SwitchMonitoring(bool bEnable)
   strLog.Format("== %s monitoring mode ==", bEnable ? "enabling" : "disabling");
   m_controller->AddLog(CEC_LOG_NOTICE, strLog.c_str());
 
-  m_bMonitor = bEnable;
+  {
+    CLockObject lock(&m_mutex);
+    m_bMonitor = bEnable;
+
+    if (!bEnable)
+    {
+      if (!m_busScan)
+      {
+        m_busScan = new CCECBusScan(this);
+        m_busScan->CreateThread(true);
+      }
+    }
+    else
+    {
+      if (m_busScan)
+      {
+        m_busScan->StopThread();
+        delete m_busScan;
+        m_busScan = NULL;
+      }
+    }
+  }
+
   if (bEnable)
     return SetAckMask(0);
   else
-    return SetAckMask(m_logicalAddresses.ackmask());
+    return SetAckMask(m_logicalAddresses.AckMask());
 }
 
 bool CCECProcessor::PollDevice(cec_logical_address iAddress)
 {
   if (iAddress != CECDEVICE_UNKNOWN && m_busDevices[iAddress])
-    return m_busDevices[m_logicalAddresses.primary]->TransmitPoll(iAddress);
+  {
+    return m_logicalAddresses.primary == CECDEVICE_UNKNOWN ?
+        m_busDevices[iAddress]->TransmitPoll(iAddress) :
+        m_busDevices[m_logicalAddresses.primary]->TransmitPoll(iAddress);
+  }
   return false;
 }
 
-CCECBusDevice *CCECProcessor::GetDeviceByPhysicalAddress(uint16_t iPhysicalAddress) const
+uint8_t CCECProcessor::VolumeUp(void)
 {
-  CCECBusDevice *device = NULL;
+  uint8_t status = 0;
+  if (IsPresentDevice(CECDEVICE_AUDIOSYSTEM))
+    status = ((CCECAudioSystem *)m_busDevices[CECDEVICE_AUDIOSYSTEM])->VolumeUp();
+
+  return status;
+}
+
+uint8_t CCECProcessor::VolumeDown(void)
+{
+  uint8_t status = 0;
+  if (IsPresentDevice(CECDEVICE_AUDIOSYSTEM))
+    status = ((CCECAudioSystem *)m_busDevices[CECDEVICE_AUDIOSYSTEM])->VolumeDown();
+
+  return status;
+}
 
+uint8_t CCECProcessor::MuteAudio(void)
+{
+  uint8_t status = 0;
+  if (IsPresentDevice(CECDEVICE_AUDIOSYSTEM))
+    status = ((CCECAudioSystem *)m_busDevices[CECDEVICE_AUDIOSYSTEM])->MuteAudio();
+
+  return status;
+}
+
+CCECBusDevice *CCECProcessor::GetDeviceByPhysicalAddress(uint16_t iPhysicalAddress, bool bRefresh /* = false */) const
+{
+  if (m_busDevices[m_logicalAddresses.primary]->GetPhysicalAddress(false) == iPhysicalAddress)
+    return m_busDevices[m_logicalAddresses.primary];
+
+  CCECBusDevice *device = NULL;
   for (unsigned int iPtr = 0; iPtr < 16; iPtr++)
   {
-    if (m_busDevices[iPtr]->GetPhysicalAddress() == iPhysicalAddress)
+    if (m_busDevices[iPtr]->GetPhysicalAddress(bRefresh) == iPhysicalAddress)
     {
       device = m_busDevices[iPtr];
       break;
@@ -489,6 +651,17 @@ cec_version CCECProcessor::GetDeviceCecVersion(cec_logical_address iAddress)
   return m_busDevices[iAddress]->GetCecVersion();
 }
 
+cec_osd_name CCECProcessor::GetDeviceOSDName(cec_logical_address iAddress)
+{
+  CStdString strOSDName = m_busDevices[iAddress]->GetOSDName();
+  cec_osd_name retVal;
+
+  snprintf(retVal.name, sizeof(retVal.name), "%s", strOSDName.c_str());
+  retVal.device = iAddress;
+
+  return retVal;
+}
+
 bool CCECProcessor::GetDeviceMenuLanguage(cec_logical_address iAddress, cec_menu_language *language)
 {
   if (m_busDevices[iAddress])
@@ -506,6 +679,13 @@ uint64_t CCECProcessor::GetDeviceVendorId(cec_logical_address iAddress)
   return false;
 }
 
+uint16_t CCECProcessor::GetDevicePhysicalAddress(cec_logical_address iAddress)
+{
+  if (m_busDevices[iAddress])
+    return m_busDevices[iAddress]->GetPhysicalAddress(false);
+  return false;
+}
+
 cec_power_status CCECProcessor::GetDevicePowerStatus(cec_logical_address iAddress)
 {
   if (m_busDevices[iAddress])
@@ -513,15 +693,43 @@ cec_power_status CCECProcessor::GetDevicePowerStatus(cec_logical_address iAddres
   return CEC_POWER_STATUS_UNKNOWN;
 }
 
+cec_logical_address CCECProcessor::GetActiveSource(void)
+{
+  for (uint8_t iPtr = 0; iPtr <= 11; iPtr++)
+  {
+    if (m_busDevices[iPtr]->IsActiveSource())
+      return (cec_logical_address)iPtr;
+  }
+
+  return CECDEVICE_UNKNOWN;
+}
+
+bool CCECProcessor::IsActiveSource(cec_logical_address iAddress)
+{
+  return m_busDevices[iAddress]->IsActiveSource();
+}
+
 bool CCECProcessor::Transmit(const cec_command &data)
 {
   bool bReturn(false);
   LogOutput(data);
 
   CCECAdapterMessage *output = new CCECAdapterMessage(data);
+
+  /* set the number of retries */
+  if (data.opcode == CEC_OPCODE_NONE)
+    output->maxTries = 1;
+  else if (data.initiator != CECDEVICE_BROADCAST)
+    output->maxTries = m_busDevices[data.initiator]->GetHandler()->GetTransmitRetries() + 1;
+
   bReturn = Transmit(output);
-  delete output;
 
+  /* set to "not present" on failed ack */
+  if (output->is_error() && output->reply == MSGCODE_TRANSMIT_FAILED_ACK &&
+      output->destination() != CECDEVICE_BROADCAST)
+    m_busDevices[output->destination()]->SetDeviceStatus(CEC_DEVICE_STATUS_NOT_PRESENT);
+
+  delete output;
   return bReturn;
 }
 
@@ -530,28 +738,40 @@ bool CCECProcessor::Transmit(CCECAdapterMessage *output)
   bool bReturn(false);
   CLockObject lock(&m_mutex);
   {
-    CLockObject msgLock(&output->mutex);
-    if (!m_communication || !m_communication->Write(output))
-      return bReturn;
-    else
+    m_iLastTransmission = GetTimeMs();
+    m_communication->SetLineTimeout(m_iStandardLineTimeout);
+    output->tries = 1;
+
+    do
     {
-      output->condition.Wait(&output->mutex);
-      if (output->state != ADAPTER_MESSAGE_STATE_SENT)
-      {
-        m_controller->AddLog(CEC_LOG_ERROR, "command was not sent");
+      if (output->tries > 0)
+        m_communication->SetLineTimeout(m_iRetryLineTimeout);
+
+      CLockObject msgLock(&output->mutex);
+      if (!m_communication || !m_communication->Write(output))
         return bReturn;
+      else
+      {
+        output->condition.Wait(&output->mutex);
+        if (output->state != ADAPTER_MESSAGE_STATE_SENT)
+        {
+          m_controller->AddLog(CEC_LOG_ERROR, "command was not sent");
+          return bReturn;
+        }
       }
-    }
 
-    if (output->transmit_timeout > 0)
-    {
-      if ((bReturn = WaitForTransmitSucceeded(output->size(), output->transmit_timeout)) == false)
-        m_controller->AddLog(CEC_LOG_DEBUG, "did not receive ack");
-    }
-    else
-      bReturn = true;
+      if (output->transmit_timeout > 0)
+      {
+        if ((bReturn = WaitForTransmitSucceeded(output)) == false)
+          m_controller->AddLog(CEC_LOG_DEBUG, "did not receive ack");
+      }
+      else
+        bReturn = true;
+    }while (output->transmit_timeout > 0 && output->needs_retry() && ++output->tries < output->maxTries);
   }
 
+  m_communication->SetLineTimeout(m_iStandardLineTimeout);
+
   return bReturn;
 }
 
@@ -561,49 +781,72 @@ void CCECProcessor::TransmitAbort(cec_logical_address address, cec_opcode opcode
 
   cec_command command;
   // TODO
-  cec_command::format(command, m_logicalAddresses.primary, address, CEC_OPCODE_FEATURE_ABORT);
-  command.parameters.push_back((uint8_t)opcode);
-  command.parameters.push_back((uint8_t)reason);
+  cec_command::Format(command, m_logicalAddresses.primary, address, CEC_OPCODE_FEATURE_ABORT);
+  command.parameters.PushBack((uint8_t)opcode);
+  command.parameters.PushBack((uint8_t)reason);
 
   Transmit(command);
 }
 
-bool CCECProcessor::WaitForTransmitSucceeded(uint8_t iLength, uint32_t iTimeout /* = 1000 */)
+bool CCECProcessor::WaitForTransmitSucceeded(CCECAdapterMessage *message)
 {
   bool bError(false);
   bool bTransmitSucceeded(false);
-  uint8_t iPacketsLeft(iLength / 4);
+  uint8_t iPacketsLeft(message->size() / 4);
 
   int64_t iNow = GetTimeMs();
-  int64_t iTargetTime = iNow + (uint64_t) iTimeout;
+  int64_t iTargetTime = iNow + message->transmit_timeout;
 
-  while (!bTransmitSucceeded && !bError && (iTimeout == 0 || iNow < iTargetTime))
+  while (!bTransmitSucceeded && !bError && (message->transmit_timeout == 0 || iNow < iTargetTime))
   {
     CCECAdapterMessage msg;
 
-    if (!m_communication->Read(msg, iTimeout > 0 ? (int32_t)(iTargetTime - iNow) : 1000))
+    if (!m_communication->Read(msg, message->transmit_timeout > 0 ? (int32_t)(iTargetTime - iNow) : 1000))
+    {
+      iNow = GetTimeMs();
+      continue;
+    }
+
+    if (msg.message() == MSGCODE_FRAME_START && msg.ack())
     {
+      m_busDevices[msg.initiator()]->GetHandler()->HandlePoll(msg.initiator(), msg.destination());
+      m_lastInitiator = msg.initiator();
       iNow = GetTimeMs();
       continue;
     }
 
-    if ((bError = msg.is_error()) == false)
+    bError = msg.is_error();
+    if (msg.message() == MSGCODE_RECEIVE_FAILED &&
+        m_lastInitiator != CECDEVICE_UNKNOWN &&
+        !m_busDevices[m_lastInitiator]->GetHandler()->HandleReceiveFailed())
     {
-      m_controller->AddLog(bError ? CEC_LOG_WARNING : CEC_LOG_DEBUG, msg.ToString());
+      iNow = GetTimeMs();
+      continue;
+    }
 
+    if (bError)
+    {
+      message->reply = msg.message();
+      m_controller->AddLog(CEC_LOG_DEBUG, msg.ToString());
+    }
+    else
+    {
       switch(msg.message())
       {
       case MSGCODE_COMMAND_ACCEPTED:
+        m_controller->AddLog(CEC_LOG_DEBUG, msg.ToString());
         if (iPacketsLeft > 0)
           iPacketsLeft--;
         break;
       case MSGCODE_TRANSMIT_SUCCEEDED:
+        m_controller->AddLog(CEC_LOG_DEBUG, msg.ToString());
         bTransmitSucceeded = (iPacketsLeft == 0);
         bError = !bTransmitSucceeded;
+        message->reply = MSGCODE_TRANSMIT_SUCCEEDED;
         break;
       default:
-        if (ParseMessage(msg))
-          m_commandBuffer.Push(m_currentframe);
+        // ignore other data while waiting
+        break;
       }
 
       iNow = GetTimeMs();
@@ -615,7 +858,8 @@ bool CCECProcessor::WaitForTransmitSucceeded(uint8_t iLength, uint32_t iTimeout
 
 bool CCECProcessor::ParseMessage(const CCECAdapterMessage &msg)
 {
-  bool bEom = false;
+  bool bEom(false);
+  bool bIsError(msg.is_error());
 
   if (msg.empty())
     return bEom;
@@ -624,7 +868,7 @@ bool CCECProcessor::ParseMessage(const CCECAdapterMessage &msg)
   {
   case MSGCODE_FRAME_START:
     {
-      m_currentframe.clear();
+      m_currentframe.Clear();
       if (msg.size() >= 2)
       {
         m_currentframe.initiator   = msg.initiator();
@@ -632,13 +876,24 @@ bool CCECProcessor::ParseMessage(const CCECAdapterMessage &msg)
         m_currentframe.ack         = msg.ack();
         m_currentframe.eom         = msg.eom();
       }
+      if (m_currentframe.ack == 0x1)
+      {
+        m_lastInitiator = m_currentframe.initiator;
+        m_busDevices[m_lastInitiator]->GetHandler()->HandlePoll(m_currentframe.initiator, m_currentframe.destination);
+      }
+    }
+    break;
+  case MSGCODE_RECEIVE_FAILED:
+    {
+      if (m_lastInitiator != CECDEVICE_UNKNOWN)
+        bIsError = m_busDevices[m_lastInitiator]->GetHandler()->HandleReceiveFailed();
     }
     break;
   case MSGCODE_FRAME_DATA:
     {
       if (msg.size() >= 2)
       {
-        m_currentframe.push_back(msg[1]);
+        m_currentframe.PushBack(msg[1]);
         m_currentframe.eom = msg.eom();
       }
       bEom = msg.eom();
@@ -648,6 +903,7 @@ bool CCECProcessor::ParseMessage(const CCECAdapterMessage &msg)
     break;
   }
 
+  m_controller->AddLog(bIsError ? CEC_LOG_WARNING : CEC_LOG_DEBUG, msg.ToString());
   return bEom;
 }
 
@@ -663,10 +919,38 @@ void CCECProcessor::ParseCommand(cec_command &command)
     m_busDevices[(uint8_t)command.initiator]->HandleCommand(command);
 }
 
+cec_logical_addresses CCECProcessor::GetActiveDevices(void)
+{
+  cec_logical_addresses addresses;
+  addresses.Clear();
+  for (unsigned int iPtr = 0; iPtr < 15; iPtr++)
+  {
+    if (m_busDevices[iPtr]->GetStatus() == CEC_DEVICE_STATUS_PRESENT)
+      addresses.Set((cec_logical_address) iPtr);
+  }
+  return addresses;
+}
+
+bool CCECProcessor::IsPresentDevice(cec_logical_address address)
+{
+  return m_busDevices[address]->GetStatus() == CEC_DEVICE_STATUS_PRESENT;
+}
+
+bool CCECProcessor::IsPresentDeviceType(cec_device_type type)
+{
+  for (unsigned int iPtr = 0; iPtr < 15; iPtr++)
+  {
+    if (m_busDevices[iPtr]->GetType() == type && m_busDevices[iPtr]->GetStatus() == CEC_DEVICE_STATUS_PRESENT)
+      return true;
+  }
+
+  return false;
+}
+
 uint16_t CCECProcessor::GetPhysicalAddress(void) const
 {
-  if (!m_logicalAddresses.empty() && m_busDevices[m_logicalAddresses.primary])
-    return m_busDevices[m_logicalAddresses.primary]->GetPhysicalAddress();
+  if (!m_logicalAddresses.IsEmpty() && m_busDevices[m_logicalAddresses.primary])
+    return m_busDevices[m_logicalAddresses.primary]->GetPhysicalAddress(false);
   return false;
 }
 
@@ -717,3 +1001,389 @@ bool CCECProcessor::SetAckMask(uint16_t iMask)
 
   return bReturn;
 }
+
+bool CCECProcessor::TransmitKeypress(cec_logical_address iDestination, cec_user_control_code key)
+{
+  return m_busDevices[iDestination]->TransmitKeypress(key);
+}
+
+bool CCECProcessor::TransmitKeyRelease(cec_logical_address iDestination)
+{
+  return m_busDevices[iDestination]->TransmitKeyRelease();
+}
+
+const char *CCECProcessor::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";
+  }
+}
+
+const char *CCECProcessor::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";
+  }
+}
+
+const char *CCECProcessor::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";
+  }
+}
+
+const char *CCECProcessor::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";
+  }
+}
+
+const char *CCECProcessor::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";
+  }
+}
+
+const char *CCECProcessor::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";
+  default:
+    return "unknown";
+  }
+}
+
+const char *CCECProcessor::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";
+  default:
+    return "UNKNOWN";
+  }
+}
+
+const char *CCECProcessor::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";
+  }
+}
+
+const char *CCECProcessor::ToString(const cec_audio_status status)
+{
+  // TODO this is a mask
+  return "TODO";
+}
+
+const char *CCECProcessor::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";
+  default:
+    return "Unknown";
+  }
+}
+
+void *CCECBusScan::Process(void)
+{
+  CCECBusDevice *device(NULL);
+  uint8_t iCounter(0);
+
+  while (!IsStopped())
+  {
+    if (++iCounter < 10)
+    {
+      Sleep(1000);
+      continue;
+    }
+    for (unsigned int iPtr = 0; iPtr <= 11 && !IsStopped(); iPtr++)
+    {
+      device = m_processor->m_busDevices[iPtr];
+      WaitUntilIdle();
+      if (device && device->GetStatus(true) == CEC_DEVICE_STATUS_PRESENT)
+      {
+        WaitUntilIdle();
+        if (!IsStopped())
+          device->GetVendorId();
+
+        WaitUntilIdle();
+        if (!IsStopped())
+          device->GetPowerStatus(true);
+      }
+    }
+  }
+
+  return NULL;
+}
+
+void CCECBusScan::WaitUntilIdle(void)
+{
+  if (IsStopped())
+    return;
+
+  int32_t iWaitTime = 3000 - (int32_t)(GetTimeMs() - m_processor->GetLastTransmission());
+  while (iWaitTime > 0)
+  {
+    Sleep(iWaitTime);
+    iWaitTime = 3000 - (int32_t)(GetTimeMs() - m_processor->GetLastTransmission());
+  }
+}
+
+bool CCECProcessor::StartBootloader(void)
+{
+  return m_communication->StartBootloader();
+}
+
+bool CCECProcessor::PingAdapter(void)
+{
+  return m_communication->PingAdapter();
+}
index 8f8e892ddba795623a89bb88dd78b4744ed397b9..a0e0e73b8b5e95113305d0f1473acbf326bbf787 100644 (file)
@@ -49,37 +49,68 @@ namespace CEC
   class CCECProcessor : public CThread
   {
     public:
-      CCECProcessor(CLibCEC *controller, CAdapterCommunication *serComm, const char *strDeviceName, cec_logical_address iLogicalAddress = CECDEVICE_PLAYBACKDEVICE1, uint16_t iPhysicalAddress = CEC_DEFAULT_PHYSICAL_ADDRESS);
-      CCECProcessor(CLibCEC *controller, CAdapterCommunication *serComm, const char *strDeviceName, const cec_device_type_list &types);
+      CCECProcessor(CLibCEC *controller, const char *strDeviceName, cec_logical_address iLogicalAddress = CECDEVICE_PLAYBACKDEVICE1, uint16_t iPhysicalAddress = CEC_DEFAULT_PHYSICAL_ADDRESS);
+      CCECProcessor(CLibCEC *controller, const char *strDeviceName, const cec_device_type_list &types);
       virtual ~CCECProcessor(void);
 
-      virtual bool Start(void);
+      virtual bool Start(const char *strPort, uint16_t iBaudRate = 38400, uint32_t iTimeoutMs = 10000);
       virtual void *Process(void);
 
       virtual bool                  IsMonitoring(void) const { return m_bMonitor; }
-      virtual CCECBusDevice *       GetDeviceByPhysicalAddress(uint16_t iPhysicalAddress) const;
+      virtual CCECBusDevice *       GetDeviceByPhysicalAddress(uint16_t iPhysicalAddress, bool bRefresh = false) const;
       virtual CCECBusDevice *       GetDeviceByType(cec_device_type type) const;
       virtual cec_version           GetDeviceCecVersion(cec_logical_address iAddress);
       virtual bool                  GetDeviceMenuLanguage(cec_logical_address iAddress, cec_menu_language *language);
       virtual const std::string &   GetDeviceName(void) { return m_strDeviceName; }
+      virtual cec_osd_name          GetDeviceOSDName(cec_logical_address iAddress);
       virtual uint64_t              GetDeviceVendorId(cec_logical_address iAddress);
       virtual cec_power_status      GetDevicePowerStatus(cec_logical_address iAddress);
       virtual cec_logical_address   GetLogicalAddress(void) const { return m_logicalAddresses.primary; }
       virtual cec_logical_addresses GetLogicalAddresses(void) const { return m_logicalAddresses; }
-      virtual bool                  HasLogicalAddress(cec_logical_address address) const { return m_logicalAddresses.isset(address); }
+      virtual cec_logical_addresses GetActiveDevices(void);
+      virtual uint16_t              GetDevicePhysicalAddress(cec_logical_address iAddress);
+      virtual bool                  HasLogicalAddress(cec_logical_address address) const { return m_logicalAddresses.IsSet(address); }
+      virtual bool                  IsPresentDevice(cec_logical_address address);
+      virtual bool                  IsPresentDeviceType(cec_device_type type);
       virtual uint16_t              GetPhysicalAddress(void) const;
+      virtual uint64_t              GetLastTransmission(void) const { return m_iLastTransmission; }
+      virtual bool                  IsStarted(void) const { return m_bStarted; }
+      virtual cec_logical_address   GetActiveSource(void);
+      virtual bool                  IsActiveSource(cec_logical_address iAddress);
 
       virtual bool SetActiveView(void);
       virtual bool SetActiveSource(cec_device_type type = CEC_DEVICE_TYPE_RESERVED);
       virtual bool SetDeckControlMode(cec_deck_control_mode mode, bool bSendUpdate = true);
       virtual bool SetDeckInfo(cec_deck_info info, bool bSendUpdate = true);
-      virtual bool SetInactiveView(void);
+      virtual bool SetHDMIPort(cec_logical_address iBaseDevice, uint8_t iPort, bool bForce = false);
+      virtual bool TransmitInactiveSource(void);
       virtual bool SetLogicalAddress(cec_logical_address iLogicalAddress);
       virtual bool SetMenuState(cec_menu_state state, bool bSendUpdate = true);
       virtual bool SetPhysicalAddress(uint16_t iPhysicalAddress);
-      virtual bool SetStreamPath(uint16_t iStreamPath);
+      virtual bool SetActiveSource(uint16_t iStreamPath);
       virtual bool SwitchMonitoring(bool bEnable);
       virtual bool PollDevice(cec_logical_address iAddress);
+      virtual uint8_t VolumeUp(void);
+      virtual uint8_t VolumeDown(void);
+      virtual uint8_t MuteAudio(void);
+      virtual bool TransmitKeypress(cec_logical_address iDestination, cec_user_control_code key);
+      virtual bool TransmitKeyRelease(cec_logical_address iDestination);
+      virtual bool EnablePhysicalAddressDetection(void) { return false; };
+      void SetStandardLineTimeout(uint8_t iTimeout);
+      void SetRetryLineTimeout(uint8_t iTimeout);
+
+      bool SetLineTimeout(uint8_t iTimeout);
+
+      const char *ToString(const cec_menu_state state);
+      const char *ToString(const cec_version version);
+      const char *ToString(const cec_power_status status);
+      const char *ToString(const cec_logical_address address);
+      const char *ToString(const cec_deck_control_mode mode);
+      const char *ToString(const cec_deck_info status);
+      const char *ToString(const cec_opcode opcode);
+      const char *ToString(const cec_system_audio_status mode);
+      const char *ToString(const cec_audio_status status);
+      const char *ToString(const cec_vendor_id vendor);
 
       virtual bool Transmit(const cec_command &data);
       virtual bool Transmit(CCECAdapterMessage *output);
@@ -92,25 +123,34 @@ namespace CEC
       virtual void AddLog(cec_log_level level, const CStdString &strMessage);
 
       virtual bool FindLogicalAddresses(void);
+      virtual bool SetAckMask(uint16_t iMask);
+
+      virtual bool StartBootloader(void);
+      virtual bool PingAdapter(void);
 
       CCECBusDevice *m_busDevices[16];
+      CMutex         m_transmitMutex;
 
   private:
-      bool TryLogicalAddress(cec_logical_address address, unsigned int iIndex);
-      bool FindLogicalAddressRecordingDevice(unsigned int iIndex);
-      bool FindLogicalAddressTuner(unsigned int iIndex);
-      bool FindLogicalAddressPlaybackDevice(unsigned int iIndex);
-      bool FindLogicalAddressAudioSystem(unsigned int iIndex);
+      void ScanCECBus(void);
+      bool PhysicalAddressInUse(uint16_t iPhysicalAddress);
+      bool TryLogicalAddress(cec_logical_address address);
+      bool FindLogicalAddressRecordingDevice(void);
+      bool FindLogicalAddressTuner(void);
+      bool FindLogicalAddressPlaybackDevice(void);
+      bool FindLogicalAddressAudioSystem(void);
 
-      bool SetAckMask(uint16_t iMask);
       void LogOutput(const cec_command &data);
-      bool WaitForTransmitSucceeded(uint8_t iLength, uint32_t iTimeout = 1000);
+      bool WaitForTransmitSucceeded(CCECAdapterMessage *message);
       bool ParseMessage(const CCECAdapterMessage &msg);
       void ParseCommand(cec_command &command);
 
       bool                   m_bStarted;
+      uint8_t                m_iHDMIPort;
+      cec_logical_address    m_iBaseDevice;
       cec_command            m_currentframe;
       cec_logical_addresses  m_logicalAddresses;
+      cec_logical_address    m_lastInitiator;
       std::string            m_strDeviceName;
       cec_device_type_list   m_types;
       CMutex                 m_mutex;
@@ -119,5 +159,24 @@ namespace CEC
       CLibCEC*               m_controller;
       bool                   m_bMonitor;
       CecBuffer<cec_command> m_commandBuffer;
+      cec_keypress           m_previousKey;
+      CThread *              m_busScan;
+      uint8_t                m_iLineTimeout;
+      uint8_t                m_iStandardLineTimeout;
+      uint8_t                m_iRetryLineTimeout;
+      uint64_t               m_iLastTransmission;
+  };
+
+  class CCECBusScan : public CThread
+  {
+  public:
+    CCECBusScan(CCECProcessor *processor) { m_processor = processor; }
+    virtual ~CCECBusScan(void) { StopThread(true); }
+    virtual void *Process(void);
+
+  private:
+    void WaitUntilIdle(void);
+
+    CCECProcessor *m_processor;
   };
 };
index c0675622e32db807817195d61f9270b02d66cf2f..0ca0188bfa0b596847beafcfdeb7622cb7b78e18 100644 (file)
@@ -47,8 +47,7 @@ CLibCEC::CLibCEC(const char *strDeviceName, cec_device_type_list types) :
     m_iCurrentButton(CEC_USER_CONTROL_CODE_UNKNOWN),
     m_buttontime(0)
 {
-  m_comm = new CAdapterCommunication(this);
-  m_cec = new CCECProcessor(this, m_comm, strDeviceName, types);
+  m_cec = new CCECProcessor(this, strDeviceName, types);
 }
 
 CLibCEC::CLibCEC(const char *strDeviceName, cec_logical_address iLogicalAddress /* = CECDEVICE_PLAYBACKDEVICE1 */, uint16_t iPhysicalAddress /* = CEC_DEFAULT_PHYSICAL_ADDRESS */) :
@@ -56,48 +55,24 @@ CLibCEC::CLibCEC(const char *strDeviceName, cec_logical_address iLogicalAddress
     m_iCurrentButton(CEC_USER_CONTROL_CODE_UNKNOWN),
     m_buttontime(0)
 {
-  m_comm = new CAdapterCommunication(this);
-  m_cec = new CCECProcessor(this, m_comm, strDeviceName, iLogicalAddress, iPhysicalAddress);
+  m_cec = new CCECProcessor(this, strDeviceName, iLogicalAddress, iPhysicalAddress);
 }
 
 CLibCEC::~CLibCEC(void)
 {
   Close();
   delete m_cec;
-  delete m_comm;
 }
 
 bool CLibCEC::Open(const char *strPort, uint32_t iTimeoutMs /* = 10000 */)
 {
-  if (!m_comm)
-  {
-    AddLog(CEC_LOG_ERROR, "no comm port");
-    return false;
-  }
-
-  if (m_comm->IsOpen())
+  if (m_cec->IsRunning())
   {
     AddLog(CEC_LOG_ERROR, "connection already open");
     return false;
   }
 
-  int64_t iNow = GetTimeMs();
-  int64_t iTarget = iNow + iTimeoutMs;
-
-  bool bOpened(false);
-  while (!bOpened && iNow < iTarget)
-  {
-    bOpened = m_comm->Open(strPort, 38400, iTimeoutMs);
-    iNow = GetTimeMs();
-  }
-
-  if (!bOpened)
-  {
-    AddLog(CEC_LOG_ERROR, "could not open a connection");
-    return false;
-  }
-
-  if (!m_cec->Start())
+  if (!m_cec->Start(strPort, 38400, iTimeoutMs))
   {
     AddLog(CEC_LOG_ERROR, "could not start CEC communications");
     return false;
@@ -110,8 +85,6 @@ void CLibCEC::Close(void)
 {
   if (m_cec)
     m_cec->StopThread();
-  if (m_comm)
-    m_comm->Close();
 }
 
 int8_t CLibCEC::FindAdapters(cec_adapter *deviceList, uint8_t iBufSize, const char *strDevicePath /* = NULL */)
@@ -128,12 +101,12 @@ int8_t CLibCEC::FindAdapters(cec_adapter *deviceList, uint8_t iBufSize, const ch
 
 bool CLibCEC::PingAdapter(void)
 {
-  return m_comm ? m_comm->PingAdapter() : false;
+  return m_cec ? m_cec->PingAdapter() : false;
 }
 
 bool CLibCEC::StartBootloader(void)
 {
-  return m_comm ? m_comm->StartBootloader() : false;
+  return m_cec ? m_cec->StartBootloader() : false;
 }
 
 bool CLibCEC::GetNextLogMessage(cec_log_message *message)
@@ -161,11 +134,21 @@ bool CLibCEC::SetLogicalAddress(cec_logical_address iLogicalAddress)
   return m_cec ? m_cec->SetLogicalAddress(iLogicalAddress) : false;
 }
 
-bool CLibCEC::SetPhysicalAddress(uint16_t iPhysicalAddress)
+bool CLibCEC::SetPhysicalAddress(uint16_t iPhysicalAddress /* = CEC_DEFAULT_PHYSICAL_ADDRESS */)
 {
   return m_cec ? m_cec->SetPhysicalAddress(iPhysicalAddress) : false;
 }
 
+bool CLibCEC::SetHDMIPort(cec_logical_address iBaseDevice, uint8_t iPort /* = CEC_DEFAULT_HDMI_PORT */)
+{
+  return m_cec ? m_cec->SetHDMIPort(iBaseDevice, iPort) : false;
+}
+
+bool CLibCEC::EnablePhysicalAddressDetection(void)
+{
+  return m_cec ? m_cec->EnablePhysicalAddressDetection() : false;
+}
+
 bool CLibCEC::PowerOnDevices(cec_logical_address address /* = CECDEVICE_TV */)
 {
   return m_cec && address >= CECDEVICE_TV && address <= CECDEVICE_BROADCAST ? m_cec->m_busDevices[(uint8_t)address]->PowerOn() : false;
@@ -198,7 +181,7 @@ bool CLibCEC::SetDeckInfo(cec_deck_info info, bool bSendUpdate /* = true */)
 
 bool CLibCEC::SetInactiveView(void)
 {
-  return m_cec ? m_cec->SetInactiveView() : false;
+  return m_cec ? m_cec->TransmitInactiveSource() : false;
 }
 
 bool CLibCEC::SetMenuState(cec_menu_state state, bool bSendUpdate /* = true */)
@@ -239,6 +222,25 @@ uint64_t CLibCEC::GetDeviceVendorId(cec_logical_address iAddress)
   return 0;
 }
 
+uint16_t CLibCEC::GetDevicePhysicalAddress(cec_logical_address iAddress)
+{
+  if (m_cec && iAddress >= CECDEVICE_TV && iAddress < CECDEVICE_BROADCAST)
+    return m_cec->GetDevicePhysicalAddress(iAddress);
+  return 0;
+}
+
+cec_logical_address CLibCEC::GetActiveSource(void)
+{
+  return m_cec ? m_cec->GetActiveSource() : CECDEVICE_UNKNOWN;
+}
+
+bool CLibCEC::IsActiveSource(cec_logical_address iAddress)
+{
+  if (m_cec && iAddress >= CECDEVICE_TV && iAddress < CECDEVICE_BROADCAST)
+    return m_cec->IsActiveSource(iAddress);
+  return false;
+}
+
 cec_power_status CLibCEC::GetDevicePowerStatus(cec_logical_address iAddress)
 {
   if (m_cec && iAddress >= CECDEVICE_TV && iAddress < CECDEVICE_BROADCAST)
@@ -253,6 +255,77 @@ bool CLibCEC::PollDevice(cec_logical_address iAddress)
   return false;
 }
 
+cec_logical_addresses CLibCEC::GetActiveDevices(void)
+{
+  cec_logical_addresses addresses;
+  addresses.Clear();
+  if (m_cec)
+    addresses = m_cec->GetActiveDevices();
+  return addresses;
+}
+
+bool CLibCEC::IsActiveDevice(cec_logical_address iAddress)
+{
+  if (m_cec && iAddress >= CECDEVICE_TV && iAddress < CECDEVICE_BROADCAST)
+    return m_cec->IsPresentDevice(iAddress);
+  return false;
+}
+
+bool CLibCEC::IsActiveDeviceType(cec_device_type type)
+{
+  if (m_cec && type >= CEC_DEVICE_TYPE_TV && type <= CEC_DEVICE_TYPE_AUDIO_SYSTEM)
+    return m_cec->IsPresentDeviceType(type);
+  return false;
+}
+
+uint8_t CLibCEC::VolumeUp(bool bWait /* = true */)
+{
+  if (m_cec)
+    return m_cec->VolumeUp();
+  return 0;
+}
+
+uint8_t CLibCEC::VolumeDown(bool bWait /* = true */)
+{
+  if (m_cec)
+    return m_cec->VolumeDown();
+  return 0;
+}
+
+
+uint8_t CLibCEC::MuteAudio(bool bWait /* = true */)
+{
+  if (m_cec)
+    return m_cec->MuteAudio();
+  return 0;
+}
+
+bool CLibCEC::SendKeypress(cec_logical_address iDestination, cec_user_control_code key, bool bWait /* = false */)
+{
+  if (m_cec)
+    return m_cec->TransmitKeypress(iDestination, key);
+  return false;
+}
+
+bool CLibCEC::SendKeyRelease(cec_logical_address iDestination, bool bWait /* = false */)
+{
+  if (m_cec)
+    return m_cec->TransmitKeyRelease(iDestination);
+  return false;
+}
+
+cec_osd_name CLibCEC::GetDeviceOSDName(cec_logical_address iAddress)
+{
+  cec_osd_name retVal;
+  retVal.device = iAddress;
+  retVal.name[0] = 0;
+
+  if (m_cec)
+    retVal = m_cec->GetDeviceOSDName(iAddress);
+
+  return retVal;
+}
+
 void CLibCEC::AddLog(cec_log_level level, const string &strMessage)
 {
   if (m_cec)
@@ -338,3 +411,53 @@ void CECDestroy(CEC::ICECAdapter *instance)
   if (lib)
     delete lib;
 }
+
+const char *CLibCEC::ToString(const cec_menu_state state)
+{
+  return m_cec->ToString(state);
+}
+
+const char *CLibCEC::ToString(const cec_version version)
+{
+  return m_cec->ToString(version);
+}
+
+const char *CLibCEC::ToString(const cec_power_status status)
+{
+  return m_cec->ToString(status);
+}
+
+const char *CLibCEC::ToString(const cec_logical_address address)
+{
+  return m_cec->ToString(address);
+}
+
+const char *CLibCEC::ToString(const cec_deck_control_mode mode)
+{
+  return m_cec->ToString(mode);
+}
+
+const char *CLibCEC::ToString(const cec_deck_info status)
+{
+  return m_cec->ToString(status);
+}
+
+const char *CLibCEC::ToString(const cec_opcode opcode)
+{
+  return m_cec->ToString(opcode);
+}
+
+const char *CLibCEC::ToString(const cec_system_audio_status mode)
+{
+  return m_cec->ToString(mode);
+}
+
+const char *CLibCEC::ToString(const cec_audio_status status)
+{
+  return m_cec->ToString(status);
+}
+
+const char *CLibCEC::ToString(const cec_vendor_id vendor)
+{
+  return m_cec->ToString(vendor);
+}
index 7a69c96b66da525e9cdc90673effacc3da03337c..c8917906cf8222a71118c74455afb29ee56e1f89 100644 (file)
@@ -82,8 +82,33 @@ namespace CEC
       virtual cec_version GetDeviceCecVersion(cec_logical_address iAddress);
       virtual bool GetDeviceMenuLanguage(cec_logical_address iAddress, cec_menu_language *language);
       virtual uint64_t GetDeviceVendorId(cec_logical_address iAddress);
+      virtual uint16_t GetDevicePhysicalAddress(cec_logical_address iAddress);
       virtual cec_power_status GetDevicePowerStatus(cec_logical_address iAddress);
       virtual bool PollDevice(cec_logical_address iAddress);
+      virtual cec_logical_addresses GetActiveDevices(void);
+      virtual bool IsActiveDevice(cec_logical_address iAddress);
+      virtual bool IsActiveDeviceType(cec_device_type type);
+      virtual bool SetHDMIPort(cec_logical_address iBaseDevice, uint8_t iPort = CEC_DEFAULT_HDMI_PORT);
+      virtual uint8_t VolumeUp(bool bWait = true);
+      virtual uint8_t VolumeDown(bool bWait = true);
+      virtual uint8_t MuteAudio(bool bWait = true);
+      virtual bool SendKeypress(cec_logical_address iDestination, cec_user_control_code key, bool bWait = false);
+      virtual bool SendKeyRelease(cec_logical_address iDestination, bool bWait = false);
+      virtual cec_osd_name GetDeviceOSDName(cec_logical_address iAddress);
+      virtual bool EnablePhysicalAddressDetection(void);
+      virtual cec_logical_address GetActiveSource(void);
+      virtual bool IsActiveSource(cec_logical_address iAddress);
+
+      const char *ToString(const cec_menu_state state);
+      const char *ToString(const cec_version version);
+      const char *ToString(const cec_power_status status);
+      const char *ToString(const cec_logical_address address);
+      const char *ToString(const cec_deck_control_mode mode);
+      const char *ToString(const cec_deck_info status);
+      const char *ToString(const cec_opcode opcode);
+      const char *ToString(const cec_system_audio_status mode);
+      const char *ToString(const cec_audio_status status);
+      const char *ToString(const cec_vendor_id vendor);
     //@}
 
       virtual void AddLog(cec_log_level level, const std::string &strMessage);
@@ -98,7 +123,6 @@ namespace CEC
       cec_user_control_code      m_iCurrentButton;
       int64_t                    m_buttontime;
       CCECProcessor             *m_cec;
-      CAdapterCommunication     *m_comm;
       CecBuffer<cec_log_message> m_logBuffer;
       CecBuffer<cec_keypress>    m_keyBuffer;
       CecBuffer<cec_command>     m_commandBuffer;
index c95741c2356d930be974fe677db0636d5aa6fbea..938e0b716daa571893ea52f45f96e17f7ca3f9cf 100644 (file)
@@ -186,6 +186,19 @@ int cec_set_active_source(cec_device_type type)
   return -1;
 }
 
+int cec_set_deck_control_mode(cec_deck_control_mode mode, int bSendUpdate) {
+  if (cec_parser)
+    return cec_parser->SetDeckControlMode(mode, bSendUpdate == 1) ? 1 : 0;
+  return -1;
+}
+
+int cec_set_deck_info(cec_deck_info info, int bSendUpdate) {
+  if (cec_parser)
+    return cec_parser->SetDeckInfo(info, bSendUpdate == 1) ? 1 : 0;
+  return -1;
+
+}
+
 int cec_set_inactive_view(void)
 {
   if (cec_parser)
@@ -193,6 +206,12 @@ int cec_set_inactive_view(void)
   return -1;
 }
 
+int cec_set_menu_state(cec_menu_state state, int bSendUpdate) {
+  if (cec_parser)
+    return cec_parser->SetMenuState(state, bSendUpdate == 1) ? 1 : 0;
+  return -1;
+}
+
 int cec_set_osd_string(cec_logical_address iLogicalAddress, cec_display_control duration, const char *strMessage)
 {
   if (cec_parser)
@@ -228,6 +247,27 @@ uint64_t cec_get_device_vendor_id(cec_logical_address iLogicalAddress)
   return 0;
 }
 
+uint16_t cec_get_device_physical_address(cec_logical_address iLogicalAddress)
+{
+  if (cec_parser)
+    return cec_parser->GetDevicePhysicalAddress(iLogicalAddress);
+  return 0;
+}
+
+cec_logical_address cec_get_active_source(void)
+{
+  if (cec_parser)
+    return cec_parser->GetActiveSource();
+  return CECDEVICE_UNKNOWN;
+}
+
+int cec_is_active_source(cec_logical_address iAddress)
+{
+  if (cec_parser)
+    return cec_parser->IsActiveSource(iAddress);
+  return false;
+}
+
 cec_power_status cec_get_device_power_status(cec_logical_address iLogicalAddress)
 {
   if (cec_parser)
@@ -238,8 +278,90 @@ cec_power_status cec_get_device_power_status(cec_logical_address iLogicalAddress
 int cec_poll_device(cec_logical_address iLogicalAddress)
 {
   if (cec_parser)
-    return cec_parser->PollDevice(iLogicalAddress);
+    return cec_parser->PollDevice(iLogicalAddress) ? 1 : 0;
+  return -1;
+}
+
+cec_logical_addresses cec_get_active_devices(void)
+{
+  cec_logical_addresses addresses;
+  addresses.Clear();
+  if (cec_parser)
+    addresses = cec_parser->GetActiveDevices();
+  return addresses;
+}
+
+int cec_is_active_device(cec_logical_address iAddress)
+{
+  if (cec_parser)
+    return cec_parser->IsActiveDevice(iAddress) ? 1 : 0;
+  return -1;
+}
+
+int cec_is_active_device_type(cec_device_type type)
+{
+  if (cec_parser)
+    return cec_parser->IsActiveDeviceType(type) ? 1 : 0;
+  return -1;
+}
+
+int cec_set_hdmi_port(cec_logical_address iBaseDevice, uint8_t iPort)
+{
+  if (cec_parser)
+    return cec_parser->SetHDMIPort(iBaseDevice, iPort) ? 1 : 0;
+  return -1;
+}
+
+int cec_volume_up(int bWait)
+{
+  if (cec_parser)
+    return cec_parser->VolumeUp(bWait == 1);
+  return -1;
+}
+
+int cec_volume_down(int bWait)
+{
+  if (cec_parser)
+    return cec_parser->VolumeDown(bWait == 1);
+  return -1;
+}
+
+int cec_mute_audio(int bWait)
+{
+  if (cec_parser)
+    return cec_parser->MuteAudio(bWait == 1);
+  return -1;
+}
+
+int cec_send_keypress(cec_logical_address iDestination, cec_user_control_code key, int bWait)
+{
+  if (cec_parser)
+    return cec_parser->SendKeypress(iDestination, key, bWait == 1) ? 1 : 0;
+  return -1;
+}
+
+int cec_send_key_release(cec_logical_address iDestination, int bWait)
+{
+  if (cec_parser)
+    return cec_parser->SendKeyRelease(iDestination, bWait == 1) ? 1 : 0;
   return -1;
 }
 
+cec_osd_name cec_get_device_osd_name(cec_logical_address iAddress)
+{
+  cec_osd_name retVal;
+  retVal.device = iAddress;
+  retVal.name[0] = 0;
+
+  if (cec_parser)
+    retVal = cec_parser->GetDeviceOSDName(iAddress);
+
+  return retVal;
+}
+
+int cec_enable_physical_address_detection(void)
+{
+  return cec_parser ? (cec_parser->EnablePhysicalAddressDetection() ? 1 : 0) : -1;
+}
+
 //@}
index d6c6f70d53d99f1960b3bf9ab20bf863945fc268..81a92c39a90707db6bb0e7afed9572b024bf01ab 100644 (file)
@@ -36,6 +36,8 @@
 
 using namespace CEC;
 
+#define ToString(p) m_processor->ToString(p)
+
 CCECAudioSystem::CCECAudioSystem(CCECProcessor *processor, cec_logical_address address, uint16_t iPhysicalAddress /* = 0 */) :
     CCECBusDevice(processor, address, iPhysicalAddress),
     m_systemAudioStatus(CEC_SYSTEM_AUDIO_STATUS_ON),
@@ -44,12 +46,13 @@ CCECAudioSystem::CCECAudioSystem(CCECProcessor *processor, cec_logical_address a
   m_type = CEC_DEVICE_TYPE_AUDIO_SYSTEM;
 }
 
-bool CCECAudioSystem::SetAudioStatus(const cec_audio_status status)
+bool CCECAudioSystem::SetAudioStatus(uint8_t status)
 {
+  CLockObject lock(&m_writeMutex);
   if (m_audioStatus != status)
   {
     CStdString strLog;
-    strLog.Format(">> %s (%X): audio status changed from %s to %s", GetLogicalAddressName(), m_iLogicalAddress, CCECCommandHandler::ToString(m_audioStatus), CCECCommandHandler::ToString(status));
+    strLog.Format(">> %s (%X): audio status changed from %2x to %2x", GetLogicalAddressName(), m_iLogicalAddress, m_audioStatus, status);
     AddLog(CEC_LOG_DEBUG, strLog.c_str());
 
     m_audioStatus = status;
@@ -59,12 +62,13 @@ bool CCECAudioSystem::SetAudioStatus(const cec_audio_status status)
   return false;
 }
 
-bool CCECAudioSystem::SetSystemAudioMode(const cec_system_audio_status mode)
+bool CCECAudioSystem::SetSystemAudioModeStatus(const cec_system_audio_status mode)
 {
+  CLockObject lock(&m_writeMutex);
   if (m_systemAudioStatus != mode)
   {
     CStdString strLog;
-    strLog.Format(">> %s (%X): system audio mode changed from %s to %s", GetLogicalAddressName(), m_iLogicalAddress, CCECCommandHandler::ToString(m_systemAudioStatus), CCECCommandHandler::ToString(mode));
+    strLog.Format(">> %s (%X): system audio mode status changed from %s to %s", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_systemAudioStatus), ToString(mode));
     AddLog(CEC_LOG_DEBUG, strLog.c_str());
 
     m_systemAudioStatus = mode;
@@ -74,37 +78,71 @@ bool CCECAudioSystem::SetSystemAudioMode(const cec_system_audio_status mode)
   return false;
 }
 
-bool CCECAudioSystem::SetSystemAudioMode(const cec_command &command)
+bool CCECAudioSystem::TransmitAudioStatus(cec_logical_address dest)
 {
-  SetSystemAudioMode((command.parameters.size == 0) ?
-    CEC_SYSTEM_AUDIO_STATUS_OFF :
-  CEC_SYSTEM_AUDIO_STATUS_ON);
+  uint8_t state;
+  {
+    CLockObject lock(&m_writeMutex);
+    CStdString strLog;
+    strLog.Format("<< %x -> %x: audio status '%2x'", m_iLogicalAddress, dest, m_audioStatus);
+    AddLog(CEC_LOG_NOTICE, strLog);
+    state = m_audioStatus;
+  }
 
-  return TransmitAudioStatus(command.initiator);
+  return m_handler->TransmitAudioStatus(m_iLogicalAddress, dest, state);
 }
 
-bool CCECAudioSystem::TransmitAudioStatus(cec_logical_address dest)
+bool CCECAudioSystem::TransmitSetSystemAudioMode(cec_logical_address dest)
 {
-  CStdString strLog;
-  strLog.Format("<< %x -> %x: audio status '%2x'", m_iLogicalAddress, dest, CCECCommandHandler::ToString(m_audioStatus));
-  AddLog(CEC_LOG_NOTICE, strLog);
-
-  cec_command command;
-  cec_command::format(command, m_iLogicalAddress, dest, CEC_OPCODE_REPORT_AUDIO_STATUS);
-  command.parameters.push_back((uint8_t) m_audioStatus);
+  cec_system_audio_status state;
+  {
+    CLockObject lock(&m_writeMutex);
+    CStdString strLog;
+    strLog.Format("<< %x -> %x: set system audio mode '%2x'", m_iLogicalAddress, dest, m_audioStatus);
+    AddLog(CEC_LOG_NOTICE, strLog);
+    state = m_systemAudioStatus;
+  }
 
-  return m_processor->Transmit(command);
+  return m_handler->TransmitSetSystemAudioMode(m_iLogicalAddress, dest, state);
 }
 
 bool CCECAudioSystem::TransmitSystemAudioModeStatus(cec_logical_address dest)
 {
-  CStdString strLog;
-  strLog.Format("<< %x -> %x: system audio mode '%s'", m_iLogicalAddress, dest, CCECCommandHandler::ToString(m_systemAudioStatus));
-  AddLog(CEC_LOG_NOTICE, strLog);
+  cec_system_audio_status state;
+  {
+    CLockObject lock(&m_writeMutex);
+    CStdString strLog;
+    strLog.Format("<< %x -> %x: system audio mode '%s'", m_iLogicalAddress, dest, ToString(m_systemAudioStatus));
+    AddLog(CEC_LOG_NOTICE, strLog);
+    state = m_systemAudioStatus;
+  }
+
+  return m_handler->TransmitSystemAudioModeStatus(m_iLogicalAddress, dest, state);
+}
+
+uint8_t CCECAudioSystem::VolumeUp(void)
+{
+  if (TransmitKeypress(CEC_USER_CONTROL_CODE_VOLUME_UP))
+    TransmitKeyRelease();
+
+  CLockObject lock(&m_mutex);
+  return m_audioStatus;
+}
+
+uint8_t CCECAudioSystem::VolumeDown(void)
+{
+  if (TransmitKeypress(CEC_USER_CONTROL_CODE_VOLUME_DOWN))
+    TransmitKeyRelease();
 
-  cec_command command;
-  cec_command::format(command, m_iLogicalAddress, dest, CEC_OPCODE_SYSTEM_AUDIO_MODE_STATUS);
-  command.parameters.push_back((uint8_t) m_systemAudioStatus);
+  CLockObject lock(&m_mutex);
+  return m_audioStatus;
+}
+
+uint8_t CCECAudioSystem::MuteAudio(void)
+{
+  if (TransmitKeypress(CEC_USER_CONTROL_CODE_MUTE))
+    TransmitKeyRelease();
 
-  return m_processor->Transmit(command);
+  CLockObject lock(&m_mutex);
+  return m_audioStatus;
 }
index 0a80dacf60146cca8249cd37f06fa4bde7a39c89..291b0ecadc09d39bab87f7d9528aaf5452f75136 100644 (file)
@@ -41,16 +41,20 @@ namespace CEC
     CCECAudioSystem(CCECProcessor *processor, cec_logical_address address, uint16_t iPhysicalAddress = 0);
     virtual ~CCECAudioSystem(void) {};
 
-    virtual bool SetAudioStatus(const cec_audio_status status);
-    virtual bool SetSystemAudioMode(const cec_system_audio_status mode);
-    virtual bool SetSystemAudioMode(const cec_command &command);
+    virtual bool SetAudioStatus(uint8_t status);
+    virtual bool SetSystemAudioModeStatus(const cec_system_audio_status mode);
     virtual bool TransmitAudioStatus(cec_logical_address dest);
+    virtual bool TransmitSetSystemAudioMode(cec_logical_address dest);
     virtual bool TransmitSystemAudioModeStatus(cec_logical_address dest);
 
+    virtual uint8_t VolumeUp(void);
+    virtual uint8_t VolumeDown(void);
+    virtual uint8_t MuteAudio(void);
+
     virtual bool TransmitActiveSource(void) { return false; }
 
   protected:
     cec_system_audio_status m_systemAudioStatus;
-    cec_audio_status        m_audioStatus;
+    uint8_t                 m_audioStatus;
   };
 }
index ca91ba7a91d6b060bdc125ecd635035449c9c867..41643a3519263a238d025fe92c6b2adc68750dde 100644 (file)
@@ -40,7 +40,7 @@
 
 using namespace CEC;
 
-#define ToString(p) CCECCommandHandler::ToString(p)
+#define ToString(p) m_processor->ToString(p)
 
 CCECBusDevice::CCECBusDevice(CCECProcessor *processor, cec_logical_address iLogicalAddress, uint16_t iPhysicalAddress) :
   m_type(CEC_DEVICE_TYPE_RESERVED),
@@ -52,9 +52,9 @@ CCECBusDevice::CCECBusDevice(CCECProcessor *processor, cec_logical_address iLogi
   m_vendor(CEC_VENDOR_UNKNOWN),
   m_menuState(CEC_MENU_STATE_ACTIVATED),
   m_bActiveSource(false),
-  m_iLastCommandSent(0),
   m_iLastActive(0),
-  m_cecVersion(CEC_VERSION_UNKNOWN)
+  m_cecVersion(CEC_VERSION_UNKNOWN),
+  m_deviceStatus(CEC_DEVICE_STATUS_UNKNOWN)
 {
   m_handler = new CCECCommandHandler(this);
 
@@ -68,7 +68,6 @@ CCECBusDevice::CCECBusDevice(CCECProcessor *processor, cec_logical_address iLogi
 
 CCECBusDevice::~CCECBusDevice(void)
 {
-  m_condition.Broadcast();
   delete m_handler;
 }
 
@@ -79,52 +78,67 @@ void CCECBusDevice::AddLog(cec_log_level level, const CStdString &strMessage)
 
 bool CCECBusDevice::HandleCommand(const cec_command &command)
 {
-  CLockObject lock(&m_mutex);
-  m_iLastActive = GetTimeMs();
-  m_handler->HandleCommand(command);
-  m_condition.Signal();
-  return true;
-}
+  bool bHandled(false);
 
-void CCECBusDevice::PollVendorId(void)
-{
-  CLockObject lock(&m_mutex);
-  if (m_iLastActive > 0 && m_iLogicalAddress != CECDEVICE_BROADCAST &&
-      m_vendor == CEC_VENDOR_UNKNOWN &&
-      GetTimeMs() - m_iLastCommandSent > 5000 &&
-      !m_processor->IsMonitoring())
+  /* update "last active" */
   {
-    CStdString strLog;
-    strLog.Format("<< requesting vendor ID of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
-    AddLog(CEC_LOG_NOTICE, strLog);
-    m_iLastCommandSent = GetTimeMs();
+    CLockObject lock(&m_writeMutex);
+    m_iLastActive = GetTimeMs();
 
-    cec_command command;
-    cec_command::format(command, GetMyLogicalAddress(), m_iLogicalAddress, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID);
-    if (m_processor->Transmit(command))
-      m_condition.Wait(&m_mutex, 1000);
+    if (m_deviceStatus != CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC)
+      m_deviceStatus = CEC_DEVICE_STATUS_PRESENT;
   }
-}
 
-bool CCECBusDevice::PowerOn(void)
-{
-  cec_power_status current = GetPowerStatus();
-  if (current != CEC_POWER_STATUS_ON &&
-      current != CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON)
+  /* handle the command */
+  bHandled = m_handler->HandleCommand(command);
+
+  /* change status to present */
+  if (bHandled)
   {
-    CStdString strLog;
-    strLog.Format("<< powering on '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
-    AddLog(CEC_LOG_DEBUG, strLog.c_str());
+    CLockObject lock(&m_writeMutex);
+    if (m_deviceStatus != CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC)
+    {
+      if (m_deviceStatus != CEC_DEVICE_STATUS_PRESENT)
+      {
+        CStdString strLog;
+        strLog.Format("device %s (%x) status changed to present after command %s", GetLogicalAddressName(), (uint8_t)GetLogicalAddress(), ToString(command.opcode));
+        AddLog(CEC_LOG_DEBUG, strLog);
+      }
+      m_deviceStatus = CEC_DEVICE_STATUS_PRESENT;
+    }
+  }
 
-    SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON);
+  return bHandled;
+}
 
-    cec_command command;
-    cec_command::format(command, GetMyLogicalAddress(), m_iLogicalAddress, CEC_OPCODE_IMAGE_VIEW_ON);
+bool CCECBusDevice::PowerOn(void)
+{
+  CStdString strLog;
+  strLog.Format("<< powering on '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
+  AddLog(CEC_LOG_DEBUG, strLog.c_str());
 
-    return m_processor->Transmit(command);
+  if (m_handler->TransmitPowerOn(GetMyLogicalAddress(), m_iLogicalAddress))
+  {
+    {
+      CLockObject lock(&m_mutex);
+//      m_powerStatus = CEC_POWER_STATUS_UNKNOWN;
+      m_powerStatus = CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON;
+    }
+//    cec_power_status status = GetPowerStatus();
+//    if (status == CEC_POWER_STATUS_STANDBY || status == CEC_POWER_STATUS_UNKNOWN)
+//    {
+//      /* sending the normal power on command appears to have failed */
+//      CStdString strLog;
+//      strLog.Format("<< sending power on keypress to '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
+//      AddLog(CEC_LOG_DEBUG, strLog.c_str());
+//
+//      TransmitKeypress(CEC_USER_CONTROL_CODE_POWER);
+//      return TransmitKeyRelease();
+//    }
+    return true;
   }
 
-  return true;
+  return false;
 }
 
 bool CCECBusDevice::Standby(void)
@@ -133,59 +147,63 @@ bool CCECBusDevice::Standby(void)
   strLog.Format("<< putting '%s' (%X) in standby mode", GetLogicalAddressName(), m_iLogicalAddress);
   AddLog(CEC_LOG_DEBUG, strLog.c_str());
 
-  cec_command command;
-  cec_command::format(command, GetMyLogicalAddress(), m_iLogicalAddress, CEC_OPCODE_STANDBY);
-
-  return m_processor->Transmit(command);
+  return m_handler->TransmitStandby(GetMyLogicalAddress(), m_iLogicalAddress);
 }
 
 /** @name Getters */
 //@{
-cec_version CCECBusDevice::GetCecVersion(void)
+cec_version CCECBusDevice::GetCecVersion(bool bUpdate /* = false */)
 {
-  if (m_cecVersion == CEC_VERSION_UNKNOWN)
-  {
-    if (!MyLogicalAddressContains(m_iLogicalAddress))
-    {
-      CStdString strLog;
-      strLog.Format("<< requesting CEC version of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
-      AddLog(CEC_LOG_NOTICE, strLog);
-      cec_command command;
-      cec_command::format(command, GetMyLogicalAddress(), m_iLogicalAddress, CEC_OPCODE_GET_CEC_VERSION);
-      CLockObject lock(&m_mutex);
-      if (m_processor->Transmit(command))
-        m_condition.Wait(&m_mutex, 1000);
-    }
-  }
+  CLockObject lock(&m_mutex);
+  if (GetStatus() == CEC_DEVICE_STATUS_PRESENT &&
+      (bUpdate || m_cecVersion == CEC_VERSION_UNKNOWN))
+    RequestCecVersion();
 
   return m_cecVersion;
 }
 
+bool CCECBusDevice::RequestCecVersion(void)
+{
+  bool bReturn(false);
+  if (!MyLogicalAddressContains(m_iLogicalAddress))
+  {
+    CStdString strLog;
+    strLog.Format("<< requesting CEC version of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
+    AddLog(CEC_LOG_NOTICE, strLog);
+
+    bReturn = m_handler->TransmitRequestCecVersion(GetMyLogicalAddress(), m_iLogicalAddress);
+  }
+  return bReturn;
+}
+
 const char* CCECBusDevice::GetLogicalAddressName(void) const
 {
   return ToString(m_iLogicalAddress);
 }
 
-cec_menu_language &CCECBusDevice::GetMenuLanguage(void)
+cec_menu_language &CCECBusDevice::GetMenuLanguage(bool bUpdate /* = false */)
 {
-  if (!strcmp(m_menuLanguage.language, "???"))
-  {
-    if (!MyLogicalAddressContains(m_iLogicalAddress))
-    {
-      CStdString strLog;
-      strLog.Format("<< requesting menu language of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
-      AddLog(CEC_LOG_NOTICE, strLog);
-      cec_command command;
-      cec_command::format(command, GetMyLogicalAddress(), m_iLogicalAddress, CEC_OPCODE_GET_MENU_LANGUAGE);
-      CLockObject lock(&m_mutex);
-      if (m_processor->Transmit(command))
-        m_condition.Wait(&m_mutex, 1000);
-    }
-  }
+  CLockObject lock(&m_mutex);
+  if (GetStatus() == CEC_DEVICE_STATUS_PRESENT &&
+      (bUpdate || !strcmp(m_menuLanguage.language, "???")))
+    RequestMenuLanguage();
 
   return m_menuLanguage;
 }
 
+bool CCECBusDevice::RequestMenuLanguage(void)
+{
+  bool bReturn(false);
+  if (!MyLogicalAddressContains(m_iLogicalAddress))
+  {
+    CStdString strLog;
+    strLog.Format("<< requesting menu language of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
+    AddLog(CEC_LOG_NOTICE, strLog);
+    bReturn = m_handler->TransmitRequestMenuLanguage(GetMyLogicalAddress(), m_iLogicalAddress);
+  }
+  return bReturn;
+}
+
 cec_logical_address CCECBusDevice::GetMyLogicalAddress(void) const
 {
   return m_processor->GetLogicalAddress();
@@ -196,51 +214,105 @@ uint16_t CCECBusDevice::GetMyPhysicalAddress(void) const
   return m_processor->GetPhysicalAddress();
 }
 
-cec_power_status CCECBusDevice::GetPowerStatus(void)
+CStdString CCECBusDevice::GetOSDName(bool bUpdate /* = false */)
+{
+  CLockObject lock(&m_mutex);
+  if (GetStatus() == CEC_DEVICE_STATUS_PRESENT &&
+      (bUpdate || m_strDeviceName.Equals(ToString(m_iLogicalAddress))) &&
+      m_type != CEC_DEVICE_TYPE_TV)
+    RequestOSDName();
+
+  return m_strDeviceName;
+}
+
+bool CCECBusDevice::RequestOSDName(void)
 {
-  if (m_powerStatus == CEC_POWER_STATUS_UNKNOWN)
+  bool bReturn(false);
+  if (!MyLogicalAddressContains(m_iLogicalAddress))
   {
-    if (!MyLogicalAddressContains(m_iLogicalAddress))
-    {
-      CStdString strLog;
-      strLog.Format("<< requesting power status of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
-      AddLog(CEC_LOG_NOTICE, strLog);
-      cec_command command;
-      cec_command::format(command, GetMyLogicalAddress(), m_iLogicalAddress, CEC_OPCODE_GIVE_DEVICE_POWER_STATUS);
-      CLockObject lock(&m_mutex);
-      if (m_processor->Transmit(command))
-        m_condition.Wait(&m_mutex, 1000);
-    }
+    CStdString strLog;
+    strLog.Format("<< requesting OSD name of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
+    AddLog(CEC_LOG_NOTICE, strLog);
+    bReturn = m_handler->TransmitRequestOSDName(GetMyLogicalAddress(), m_iLogicalAddress);
   }
+  return bReturn;
+}
 
-  return m_powerStatus;
+uint16_t CCECBusDevice::GetPhysicalAddress(bool bUpdate /* = false */)
+{
+  CLockObject lock(&m_mutex);
+  if (GetStatus() == CEC_DEVICE_STATUS_PRESENT &&
+      (m_iPhysicalAddress == 0xFFFF || bUpdate))
+  {
+    if (!RequestPhysicalAddress())
+      AddLog(CEC_LOG_ERROR, "failed to request the physical address");
+  }
+
+  return m_iPhysicalAddress;
 }
 
-const cec_vendor_id CCECBusDevice::GetVendorId(void)
+bool CCECBusDevice::RequestPhysicalAddress(void)
 {
-  if (m_vendor == CEC_VENDOR_UNKNOWN)
+  bool bReturn(false);
+  if (!MyLogicalAddressContains(m_iLogicalAddress))
   {
-    if (!MyLogicalAddressContains(m_iLogicalAddress))
-    {
-      CStdString strLog;
-      strLog.Format("<< requesting vendor ID of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
-      AddLog(CEC_LOG_NOTICE, strLog);
-      cec_command command;
-      cec_command::format(command, GetMyLogicalAddress(), m_iLogicalAddress, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID);
-      CLockObject lock(&m_mutex);
+    CStdString strLog;
+    strLog.Format("<< requesting physical address of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
+    AddLog(CEC_LOG_NOTICE, strLog);
+    bReturn = m_handler->TransmitRequestPhysicalAddress(GetMyLogicalAddress(), m_iLogicalAddress);
+  }
+  return bReturn;
+}
 
-      if (m_processor->Transmit(command))
-        m_condition.Wait(&m_mutex, 1000);
-    }
+cec_power_status CCECBusDevice::GetPowerStatus(bool bUpdate /* = false */)
+{
+  CLockObject lock(&m_mutex);
+  if (GetStatus() == CEC_DEVICE_STATUS_PRESENT &&
+      (bUpdate || m_powerStatus == CEC_POWER_STATUS_UNKNOWN))
+    RequestPowerStatus();
+
+  return m_powerStatus;
+}
+
+bool CCECBusDevice::RequestPowerStatus(void)
+{
+  bool bReturn(false);
+  if (!MyLogicalAddressContains(m_iLogicalAddress))
+  {
+    CStdString strLog;
+    strLog.Format("<< requesting power status of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
+    AddLog(CEC_LOG_NOTICE, strLog);
+    bReturn = m_handler->TransmitRequestPowerStatus(GetMyLogicalAddress(), m_iLogicalAddress);
   }
+  return bReturn;
+}
+
+cec_vendor_id CCECBusDevice::GetVendorId(bool bUpdate /* = false */)
+{
+  CLockObject lock(&m_mutex);
+  if (GetStatus() == CEC_DEVICE_STATUS_PRESENT &&
+      (bUpdate || m_vendor == CEC_VENDOR_UNKNOWN))
+    RequestVendorId();
 
   return m_vendor;
 }
 
-const char *CCECBusDevice::GetVendorName(void)
+bool CCECBusDevice::RequestVendorId(void)
+{
+  bool bReturn(false);
+  if (!MyLogicalAddressContains(m_iLogicalAddress))
+  {
+    CStdString strLog;
+    strLog.Format("<< requesting vendor ID of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
+    AddLog(CEC_LOG_NOTICE, strLog);
+    bReturn = m_handler->TransmitRequestVendorId(GetMyLogicalAddress(), m_iLogicalAddress);
+  }
+  return bReturn;
+}
+
+const char *CCECBusDevice::GetVendorName(bool bUpdate /* = false */)
 {
-  GetVendorId();
-  return ToString(m_vendor);
+  return ToString(GetVendorId(bUpdate));
 }
 
 bool CCECBusDevice::MyLogicalAddressContains(cec_logical_address address) const
@@ -248,6 +320,71 @@ bool CCECBusDevice::MyLogicalAddressContains(cec_logical_address address) const
   return m_processor->HasLogicalAddress(address);
 }
 
+bool CCECBusDevice::NeedsPoll(void)
+{
+  bool bSendPoll(false);
+  switch (m_iLogicalAddress)
+  {
+  case CECDEVICE_PLAYBACKDEVICE3:
+    if (m_processor->m_busDevices[CECDEVICE_PLAYBACKDEVICE2]->GetStatus() == CEC_DEVICE_STATUS_PRESENT)
+      bSendPoll = true;
+    break;
+  case CECDEVICE_PLAYBACKDEVICE2:
+    if (m_processor->m_busDevices[CECDEVICE_PLAYBACKDEVICE1]->GetStatus() == CEC_DEVICE_STATUS_PRESENT)
+      bSendPoll = true;
+    break;
+  case CECDEVICE_RECORDINGDEVICE3:
+    if (m_processor->m_busDevices[CECDEVICE_RECORDINGDEVICE2]->GetStatus() == CEC_DEVICE_STATUS_PRESENT)
+      bSendPoll = true;
+    break;
+  case CECDEVICE_RECORDINGDEVICE2:
+    if (m_processor->m_busDevices[CECDEVICE_RECORDINGDEVICE1]->GetStatus() == CEC_DEVICE_STATUS_PRESENT)
+      bSendPoll = true;
+    break;
+  case CECDEVICE_TUNER4:
+    if (m_processor->m_busDevices[CECDEVICE_TUNER3]->GetStatus() == CEC_DEVICE_STATUS_PRESENT)
+      bSendPoll = true;
+    break;
+  case CECDEVICE_TUNER3:
+    if (m_processor->m_busDevices[CECDEVICE_TUNER2]->GetStatus() == CEC_DEVICE_STATUS_PRESENT)
+      bSendPoll = true;
+    break;
+  case CECDEVICE_TUNER2:
+    if (m_processor->m_busDevices[CECDEVICE_TUNER1]->GetStatus() == CEC_DEVICE_STATUS_PRESENT)
+      bSendPoll = true;
+    break;
+  case CECDEVICE_AUDIOSYSTEM:
+  case CECDEVICE_PLAYBACKDEVICE1:
+  case CECDEVICE_RECORDINGDEVICE1:
+  case CECDEVICE_TUNER1:
+  case CECDEVICE_TV:
+    bSendPoll = true;
+    break;
+  default:
+    break;
+  }
+
+  return bSendPoll;
+}
+
+cec_bus_device_status CCECBusDevice::GetStatus(bool bForcePoll /* = false */)
+{
+  CLockObject lock(&m_writeMutex);
+  if (m_deviceStatus != CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC &&
+      (m_deviceStatus == CEC_DEVICE_STATUS_UNKNOWN || bForcePoll))
+  {
+    lock.Leave();
+    bool bPollAcked(false);
+    if (bForcePoll || NeedsPoll())
+      bPollAcked = m_processor->PollDevice(m_iLogicalAddress);
+
+    lock.Lock();
+    m_deviceStatus = bPollAcked ? CEC_DEVICE_STATUS_PRESENT : CEC_DEVICE_STATUS_NOT_PRESENT;
+  }
+
+  return m_deviceStatus;
+}
+
 //@}
 
 /** @name Setters */
@@ -263,6 +400,7 @@ void CCECBusDevice::SetCecVersion(const cec_version newVersion)
 
 void CCECBusDevice::SetMenuLanguage(const cec_menu_language &language)
 {
+  CLockObject lock(&m_writeMutex);
   if (language.device == m_iLogicalAddress)
   {
     CStdString strLog;
@@ -272,8 +410,21 @@ void CCECBusDevice::SetMenuLanguage(const cec_menu_language &language)
   }
 }
 
+void CCECBusDevice::SetOSDName(CStdString strName)
+{
+  CLockObject lock(&m_writeMutex);
+  if (m_strDeviceName != strName)
+  {
+    CStdString strLog;
+    strLog.Format(">> %s (%X): osd name set to '%s'", GetLogicalAddressName(), m_iLogicalAddress, strName);
+    m_processor->AddLog(CEC_LOG_DEBUG, strLog);
+    m_strDeviceName = strName;
+  }
+}
+
 void CCECBusDevice::SetMenuState(const cec_menu_state state)
 {
+  CLockObject lock(&m_writeMutex);
   if (m_menuState != state)
   {
     CStdString strLog;
@@ -283,9 +434,87 @@ void CCECBusDevice::SetMenuState(const cec_menu_state state)
   }
 }
 
+void CCECBusDevice::SetInactiveSource(void)
+{
+  {
+    CLockObject lock(&m_writeMutex);
+    m_bActiveSource = false;
+  }
+
+  if (MyLogicalAddressContains(m_iLogicalAddress))
+    SetPowerStatus(CEC_POWER_STATUS_STANDBY);
+}
+
+void CCECBusDevice::SetActiveSource(void)
+{
+  CLockObject lock(&m_writeMutex);
+
+  for (int iPtr = 0; iPtr < 16; iPtr++)
+    if (iPtr != m_iLogicalAddress)
+      m_processor->m_busDevices[iPtr]->SetInactiveSource();
+
+  m_bActiveSource = true;
+  m_powerStatus   = CEC_POWER_STATUS_ON;
+}
+
+bool CCECBusDevice::TryLogicalAddress(void)
+{
+  CStdString strLog;
+  strLog.Format("trying logical address '%s'", GetLogicalAddressName());
+  AddLog(CEC_LOG_DEBUG, strLog);
+
+  m_processor->SetAckMask(0x1 << m_iLogicalAddress);
+  if (!TransmitPoll(m_iLogicalAddress))
+  {
+    strLog.Format("using logical address '%s'", GetLogicalAddressName());
+    AddLog(CEC_LOG_NOTICE, strLog);
+    SetDeviceStatus(CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC);
+
+    return true;
+  }
+
+  strLog.Format("logical address '%s' already taken", GetLogicalAddressName());
+  AddLog(CEC_LOG_DEBUG, strLog);
+  SetDeviceStatus(CEC_DEVICE_STATUS_PRESENT);
+  return false;
+}
+
+void CCECBusDevice::SetDeviceStatus(const cec_bus_device_status newStatus)
+{
+  CLockObject lock(&m_writeMutex);
+  switch (newStatus)
+  {
+  case CEC_DEVICE_STATUS_UNKNOWN:
+    m_iStreamPath      = 0;
+    m_powerStatus      = CEC_POWER_STATUS_UNKNOWN;
+    m_vendor           = CEC_VENDOR_UNKNOWN;
+    m_menuState        = CEC_MENU_STATE_ACTIVATED;
+    m_bActiveSource    = false;
+    m_iLastActive      = 0;
+    m_cecVersion       = CEC_VERSION_UNKNOWN;
+    m_deviceStatus     = newStatus;
+    break;
+  case CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC:
+    m_iStreamPath      = 0;
+    m_powerStatus      = CEC_POWER_STATUS_ON;
+    m_vendor           = CEC_VENDOR_UNKNOWN;
+    m_menuState        = CEC_MENU_STATE_ACTIVATED;
+    m_bActiveSource    = false;
+    m_iLastActive      = 0;
+    m_cecVersion       = CEC_VERSION_1_3A;
+    m_deviceStatus     = newStatus;
+    break;
+  case CEC_DEVICE_STATUS_PRESENT:
+  case CEC_DEVICE_STATUS_NOT_PRESENT:
+    m_deviceStatus = newStatus;
+    break;
+  }
+}
+
 void CCECBusDevice::SetPhysicalAddress(uint16_t iNewAddress)
 {
-  if (iNewAddress > 0)
+  CLockObject lock(&m_writeMutex);
+  if (iNewAddress > 0 && m_iPhysicalAddress != iNewAddress)
   {
     CStdString strLog;
     strLog.Format(">> %s (%X): physical address changed from %04x to %04x", GetLogicalAddressName(), m_iLogicalAddress, m_iPhysicalAddress, iNewAddress);
@@ -297,21 +526,26 @@ void CCECBusDevice::SetPhysicalAddress(uint16_t iNewAddress)
 
 void CCECBusDevice::SetStreamPath(uint16_t iNewAddress, uint16_t iOldAddress /* = 0 */)
 {
+  CLockObject lock(&m_writeMutex);
   if (iNewAddress > 0)
   {
     CStdString strLog;
-    strLog.Format(">> %s (%X): stream path changed from %04x to %04x", GetLogicalAddressName(), m_iLogicalAddress, iOldAddress, iNewAddress);
+    strLog.Format(">> %s (%X): stream path changed from %04x to %04x", GetLogicalAddressName(), m_iLogicalAddress, iOldAddress == 0 ? m_iStreamPath : iOldAddress, iNewAddress);
     AddLog(CEC_LOG_DEBUG, strLog.c_str());
 
     m_iStreamPath = iNewAddress;
 
     if (iNewAddress > 0)
+    {
+      lock.Leave();
       SetPowerStatus(CEC_POWER_STATUS_ON);
+    }
   }
 }
 
 void CCECBusDevice::SetPowerStatus(const cec_power_status powerStatus)
 {
+  CLockObject lock(&m_writeMutex);
   if (m_powerStatus != powerStatus)
   {
     CStdString strLog;
@@ -321,45 +555,47 @@ void CCECBusDevice::SetPowerStatus(const cec_power_status powerStatus)
   }
 }
 
-void CCECBusDevice::SetVendorId(uint64_t iVendorId)
+bool CCECBusDevice::SetVendorId(uint64_t iVendorId, bool bInitHandler /* = true */)
 {
-  m_vendor = (cec_vendor_id)iVendorId;
+  bool bVendorChanged(false);
 
-  switch (iVendorId)
   {
-  case CEC_VENDOR_SAMSUNG:
-    if (m_handler->GetVendorId() != CEC_VENDOR_SAMSUNG)
-    {
-      delete m_handler;
-      m_handler = new CANCommandHandler(this);
-    }
-    break;
-  case CEC_VENDOR_LG:
-    if (m_handler->GetVendorId() != CEC_VENDOR_LG)
-    {
-      delete m_handler;
-      m_handler = new CSLCommandHandler(this);
-    }
-    break;
-  case CEC_VENDOR_PANASONIC:
-    if (m_handler->GetVendorId() != CEC_VENDOR_PANASONIC)
-    {
+    CLockObject lock(&m_writeMutex);
+    bVendorChanged = (m_vendor != (cec_vendor_id)iVendorId);
+    m_vendor = (cec_vendor_id)iVendorId;
+
+    if (bVendorChanged)
       delete m_handler;
-      m_handler = new CVLCommandHandler(this);
-    }
-    break;
-  default:
-    if (m_handler->GetVendorId() != CEC_VENDOR_UNKNOWN)
+
+    switch (iVendorId)
     {
-      delete m_handler;
-      m_handler = new CCECCommandHandler(this);
+    case CEC_VENDOR_SAMSUNG:
+      if (bVendorChanged)
+        m_handler = new CANCommandHandler(this);
+      break;
+    case CEC_VENDOR_LG:
+      if (bVendorChanged)
+        m_handler = new CSLCommandHandler(this);
+      break;
+    case CEC_VENDOR_PANASONIC:
+      if (bVendorChanged)
+        m_handler = new CVLCommandHandler(this);
+      break;
+    default:
+      if (bVendorChanged)
+        m_handler = new CCECCommandHandler(this);
+      break;
     }
-    break;
   }
 
+  if (bVendorChanged && bInitHandler)
+    m_handler->InitHandler();
+
   CStdString strLog;
-  strLog.Format("%s (%X): vendor = %s (%06x)", GetLogicalAddressName(), m_iLogicalAddress, GetVendorName(), GetVendorId());
+  strLog.Format("%s (%X): vendor = %s (%06x)", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_vendor), m_vendor);
   m_processor->AddLog(CEC_LOG_DEBUG, strLog.c_str());
+
+  return bVendorChanged;
 }
 //@}
 
@@ -367,87 +603,88 @@ void CCECBusDevice::SetVendorId(uint64_t iVendorId)
 //@{
 bool CCECBusDevice::TransmitActiveSource(void)
 {
-  if (m_powerStatus != CEC_POWER_STATUS_ON)
-  {
-    CStdString strLog;
-    strLog.Format("<< %s (%X) is not powered on", GetLogicalAddressName(), m_iLogicalAddress);
-    AddLog(CEC_LOG_DEBUG, strLog);
-  }
-  else if (m_bActiveSource)
-  {
-    CStdString strLog;
-    strLog.Format("<< %s (%X) -> broadcast (F): active source (%4x)", GetLogicalAddressName(), m_iLogicalAddress, m_iPhysicalAddress);
-    AddLog(CEC_LOG_NOTICE, strLog);
+  bool bSendActiveSource(false);
 
-    cec_command command;
-    cec_command::format(command, m_iLogicalAddress, CECDEVICE_BROADCAST, CEC_OPCODE_ACTIVE_SOURCE);
-    command.parameters.push_back((uint8_t) ((m_iPhysicalAddress >> 8) & 0xFF));
-    command.parameters.push_back((uint8_t) (m_iPhysicalAddress & 0xFF));
-
-    return m_processor->Transmit(command);
-  }
-  else
   {
-    CStdString strLog;
-    strLog.Format("<< %s (%X) is not the active source", GetLogicalAddressName(), m_iLogicalAddress);
-    AddLog(CEC_LOG_DEBUG, strLog);
+    CLockObject lock(&m_writeMutex);
+    if (m_powerStatus != CEC_POWER_STATUS_ON)
+    {
+      CStdString strLog;
+      strLog.Format("<< %s (%X) is not powered on", GetLogicalAddressName(), m_iLogicalAddress);
+      AddLog(CEC_LOG_DEBUG, strLog);
+    }
+    else if (m_bActiveSource)
+    {
+      CStdString strLog;
+      strLog.Format("<< %s (%X) -> broadcast (F): active source (%4x)", GetLogicalAddressName(), m_iLogicalAddress, m_iPhysicalAddress);
+      AddLog(CEC_LOG_NOTICE, strLog);
+      bSendActiveSource = true;
+    }
+    else
+    {
+      CStdString strLog;
+      strLog.Format("<< %s (%X) is not the active source", GetLogicalAddressName(), m_iLogicalAddress);
+      AddLog(CEC_LOG_DEBUG, strLog);
+    }
   }
 
-  return false;
+  return bSendActiveSource ? m_handler->TransmitActiveSource(m_iLogicalAddress, m_iPhysicalAddress) : false;
 }
 
 bool CCECBusDevice::TransmitCECVersion(cec_logical_address dest)
 {
-  CStdString strLog;
-  strLog.Format("<< %s (%X) -> %s (%X): cec version %s", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, ToString(m_cecVersion));
-  AddLog(CEC_LOG_NOTICE, strLog);
-
-  cec_command command;
-  cec_command::format(command, m_iLogicalAddress, dest, CEC_OPCODE_CEC_VERSION);
-  command.parameters.push_back((uint8_t)m_cecVersion);
+  cec_version version;
+  {
+    CLockObject lock(&m_writeMutex);
+    CStdString strLog;
+    strLog.Format("<< %s (%X) -> %s (%X): cec version %s", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, ToString(m_cecVersion));
+    AddLog(CEC_LOG_NOTICE, strLog);
+    version = m_cecVersion;
+  }
 
-  return m_processor->Transmit(command);
+  return m_handler->TransmitCECVersion(m_iLogicalAddress, dest, version);
 }
 
-bool CCECBusDevice::TransmitInactiveView(void)
+bool CCECBusDevice::TransmitInactiveSource(void)
 {
-  CStdString strLog;
-  strLog.Format("<< %s (%X) -> broadcast (F): inactive view", GetLogicalAddressName(), m_iLogicalAddress);
-  AddLog(CEC_LOG_NOTICE, strLog);
-
-  cec_command command;
-  cec_command::format(command, m_iLogicalAddress, CECDEVICE_BROADCAST, CEC_OPCODE_INACTIVE_SOURCE);
-  command.parameters.push_back((m_iPhysicalAddress >> 8) & 0xFF);
-  command.parameters.push_back(m_iPhysicalAddress & 0xFF);
+  uint16_t iPhysicalAddress;
+  {
+    CLockObject lock(&m_writeMutex);
+    CStdString strLog;
+    strLog.Format("<< %s (%X) -> broadcast (F): inactive source", GetLogicalAddressName(), m_iLogicalAddress);
+    AddLog(CEC_LOG_NOTICE, strLog);
+    iPhysicalAddress = m_iPhysicalAddress;
+  }
 
-  return m_processor->Transmit(command);
+  return m_handler->TransmitInactiveSource(m_iLogicalAddress, iPhysicalAddress);
 }
 
 bool CCECBusDevice::TransmitMenuState(cec_logical_address dest)
 {
-  CStdString strLog;
-  strLog.Format("<< %s (%X) -> %s (%X): menu state '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, ToString(m_menuState));
-  AddLog(CEC_LOG_NOTICE, strLog);
-
-  cec_command command;
-  cec_command::format(command, m_iLogicalAddress, dest, CEC_OPCODE_MENU_STATUS);
-  command.parameters.push_back((uint8_t)m_menuState);
+  cec_menu_state menuState;
+  {
+    CLockObject lock(&m_writeMutex);
+    CStdString strLog;
+    strLog.Format("<< %s (%X) -> %s (%X): menu state '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, ToString(m_menuState));
+    AddLog(CEC_LOG_NOTICE, strLog);
+    menuState = m_menuState;
+  }
 
-  return m_processor->Transmit(command);
+  return m_handler->TransmitMenuState(m_iLogicalAddress, dest, menuState);
 }
 
 bool CCECBusDevice::TransmitOSDName(cec_logical_address dest)
 {
-  CStdString strLog;
-  strLog.Format("<< %s (%X) -> %s (%X): OSD name '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, m_strDeviceName.c_str());
-  AddLog(CEC_LOG_NOTICE, strLog.c_str());
-
-  cec_command command;
-  cec_command::format(command, m_iLogicalAddress, dest, CEC_OPCODE_SET_OSD_NAME);
-  for (unsigned int iPtr = 0; iPtr < m_strDeviceName.length(); iPtr++)
-    command.parameters.push_back(m_strDeviceName.at(iPtr));
+  CStdString strDeviceName;
+  {
+    CLockObject lock(&m_writeMutex);
+    CStdString strLog;
+    strLog.Format("<< %s (%X) -> %s (%X): OSD name '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, m_strDeviceName.c_str());
+    AddLog(CEC_LOG_NOTICE, strLog.c_str());
+    strDeviceName = m_strDeviceName;
+  }
 
-  return m_processor->Transmit(command);
+  return m_handler->TransmitOSDName(m_iLogicalAddress, dest, strDeviceName);
 }
 
 bool CCECBusDevice::TransmitOSDString(cec_logical_address dest, cec_display_control duration, const char *strMessage)
@@ -456,92 +693,108 @@ bool CCECBusDevice::TransmitOSDString(cec_logical_address dest, cec_display_cont
   strLog.Format("<< %s (%X) -> %s (%X): display OSD message '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, strMessage);
   AddLog(CEC_LOG_NOTICE, strLog.c_str());
 
-  cec_command command;
-  cec_command::format(command, m_iLogicalAddress, dest, CEC_OPCODE_SET_OSD_STRING);
-  command.parameters.push_back((uint8_t)duration);
-
-  unsigned int iLen = strlen(strMessage);
-  if (iLen > 13) iLen = 13;
-
-  for (unsigned int iPtr = 0; iPtr < iLen; iPtr++)
-    command.parameters.push_back(strMessage[iPtr]);
-
-  return m_processor->Transmit(command);
+  return m_handler->TransmitOSDString(m_iLogicalAddress, dest, duration, strMessage);
 }
 
 bool CCECBusDevice::TransmitPhysicalAddress(void)
 {
-  CStdString strLog;
-  strLog.Format("<< %s (%X) -> broadcast (F): physical adddress %4x", GetLogicalAddressName(), m_iLogicalAddress, m_iPhysicalAddress);
-  AddLog(CEC_LOG_NOTICE, strLog.c_str());
+  uint16_t iPhysicalAddress;
+  cec_device_type type;
+  {
+    CLockObject lock(&m_writeMutex);
+    if (m_iPhysicalAddress == 0xffff)
+      return false;
 
-  cec_command command;
-  cec_command::format(command, m_iLogicalAddress, CECDEVICE_BROADCAST, CEC_OPCODE_REPORT_PHYSICAL_ADDRESS);
-  command.parameters.push_back((uint8_t) ((m_iPhysicalAddress >> 8) & 0xFF));
-  command.parameters.push_back((uint8_t) (m_iPhysicalAddress & 0xFF));
-  command.parameters.push_back((uint8_t) (m_type));
+    CStdString strLog;
+    strLog.Format("<< %s (%X) -> broadcast (F): physical adddress %4x", GetLogicalAddressName(), m_iLogicalAddress, m_iPhysicalAddress);
+    AddLog(CEC_LOG_NOTICE, strLog.c_str());
 
-  return m_processor->Transmit(command);
+    iPhysicalAddress = m_iPhysicalAddress;
+    type = m_type;
+  }
+
+  return m_handler->TransmitPhysicalAddress(m_iLogicalAddress, iPhysicalAddress, type);
 }
 
 bool CCECBusDevice::TransmitPoll(cec_logical_address dest)
 {
   bool bReturn(false);
-
   if (dest == CECDEVICE_UNKNOWN)
     dest = m_iLogicalAddress;
 
+  CCECBusDevice *destDevice = m_processor->m_busDevices[dest];
+  if (destDevice->m_deviceStatus == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC)
+    return bReturn;
+
   CStdString strLog;
   strLog.Format("<< %s (%X) -> %s (%X): POLL", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest);
   AddLog(CEC_LOG_NOTICE, strLog.c_str());
+  bReturn = m_handler->TransmitPoll(m_iLogicalAddress, dest);
+  AddLog(CEC_LOG_DEBUG, bReturn ? ">> POLL sent" : ">> POLL not sent");
 
-  cec_command command;
-  cec_command::format(command, m_iLogicalAddress, dest, CEC_OPCODE_NONE);
-  CLockObject lock(&m_mutex);
+  CLockObject lock(&m_writeMutex);
+  if (bReturn)
+  {
+    m_iLastActive = GetTimeMs();
+    destDevice->m_deviceStatus = CEC_DEVICE_STATUS_PRESENT;
+  }
+  else
+    destDevice->m_deviceStatus = CEC_DEVICE_STATUS_NOT_PRESENT;
 
-  bReturn = m_processor->Transmit(command);
-  AddLog(CEC_LOG_DEBUG, bReturn ? ">> POLL sent" : ">> POLL not sent");
   return bReturn;
 }
 
 bool CCECBusDevice::TransmitPowerState(cec_logical_address dest)
 {
-  CStdString strLog;
-  strLog.Format("<< %s (%X) -> %s (%X): %s", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, ToString(m_powerStatus));
-  AddLog(CEC_LOG_NOTICE, strLog.c_str());
-
-  cec_command command;
-  cec_command::format(command, m_iLogicalAddress, dest, CEC_OPCODE_REPORT_POWER_STATUS);
-  command.parameters.push_back((uint8_t) m_powerStatus);
+  cec_power_status state;
+  {
+    CLockObject lock(&m_writeMutex);
+    CStdString strLog;
+    strLog.Format("<< %s (%X) -> %s (%X): %s", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, ToString(m_powerStatus));
+    AddLog(CEC_LOG_NOTICE, strLog.c_str());
+    state = m_powerStatus;
+  }
 
-  return m_processor->Transmit(command);
+  return m_handler->TransmitPowerState(m_iLogicalAddress, dest, state);
 }
 
-bool CCECBusDevice::TransmitVendorID(cec_logical_address dest)
+bool CCECBusDevice::TransmitVendorID(cec_logical_address dest, bool bSendAbort /* = true */)
 {
-  if (m_vendor == CEC_VENDOR_UNKNOWN)
+  uint64_t iVendorId;
   {
-    CStdString strLog;
-    strLog.Format("<< %s (%X) -> %s (%X): vendor id feature abort", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest);
-    AddLog(CEC_LOG_NOTICE, strLog);
+    CLockObject lock(&m_writeMutex);
+    iVendorId = (uint64_t)m_vendor;
+  }
 
-    m_processor->TransmitAbort(dest, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID);
+  if (iVendorId == CEC_VENDOR_UNKNOWN)
+  {
+    if (bSendAbort)
+    {
+      CStdString strLog;
+      strLog.Format("<< %s (%X) -> %s (%X): vendor id feature abort", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest);
+      AddLog(CEC_LOG_NOTICE, strLog);
+
+      m_processor->TransmitAbort(dest, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID);
+    }
     return false;
   }
   else
   {
     CStdString strLog;
-    strLog.Format("<< %s (%X) -> %s (%X): vendor id %s (%x)", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, ToString(m_vendor), (uint64_t)m_vendor);
+    strLog.Format("<< %s (%X) -> %s (%X): vendor id %s (%x)", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, ToString((cec_vendor_id)iVendorId), iVendorId);
     AddLog(CEC_LOG_NOTICE, strLog);
 
-    cec_command command;
-    cec_command::format(command, m_iLogicalAddress, dest, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID);
+    return m_handler->TransmitVendorID(m_iLogicalAddress, iVendorId);
+  }
+}
 
-    command.parameters.push_back((uint8_t) (((uint64_t)m_vendor >> 16) & 0xFF));
-    command.parameters.push_back((uint8_t) (((uint64_t)m_vendor >> 8) & 0xFF));
-    command.parameters.push_back((uint8_t) ((uint64_t)m_vendor & 0xFF));
+bool CCECBusDevice::TransmitKeypress(cec_user_control_code key)
+{
+  return m_handler->TransmitKeypress(m_processor->GetLogicalAddress(), m_iLogicalAddress, key);
+}
 
-    return m_processor->Transmit(command);
-  }
+bool CCECBusDevice::TransmitKeyRelease(void)
+{
+  return m_handler->TransmitKeyRelease(m_processor->GetLogicalAddress(), m_iLogicalAddress);
 }
 //@}
index 245f829405ece5fa8cdca9c24caa3309b5b72726..b8a9aa94f74a59bc524415c433808a7503d5c45e 100644 (file)
@@ -39,10 +39,12 @@ namespace CEC
 {
   class CCECProcessor;
   class CCECCommandHandler;
+  class CSLCommandHandler;
 
   class CCECBusDevice
   {
     friend class CCECProcessor;
+    friend class CSLCommandHandler;
 
   public:
     CCECBusDevice(CCECProcessor *processor, cec_logical_address address, uint16_t iPhysicalAddress = 0);
@@ -50,63 +52,82 @@ namespace CEC
 
     virtual void AddLog(cec_log_level level, const CStdString &strMessage);
     virtual bool HandleCommand(const cec_command &command);
-    virtual void PollVendorId(void);
     virtual bool PowerOn(void);
     virtual bool Standby(void);
 
-    virtual cec_version         GetCecVersion(void);
-    virtual CCECCommandHandler *GetHandler(void) const { return m_handler; };
-    virtual uint64_t            GetCommandSent(void) const { return m_iLastCommandSent; }
-    virtual uint64_t            GetLastActive(void) const { return m_iLastActive; }
-    virtual cec_logical_address GetLogicalAddress(void) const { return m_iLogicalAddress; }
-    virtual const char*         GetLogicalAddressName(void) const;
-    virtual cec_menu_language & GetMenuLanguage(void);
-    virtual cec_logical_address GetMyLogicalAddress(void) const;
-    virtual uint16_t            GetMyPhysicalAddress(void) const;
-    virtual uint16_t            GetPhysicalAddress(void) const { return m_iPhysicalAddress; }
-    virtual cec_power_status    GetPowerStatus(void);
-    virtual CCECProcessor *     GetProcessor(void) const { return m_processor; }
-    virtual cec_device_type     GetType(void) const { return m_type; }
-    virtual const cec_vendor_id GetVendorId(void);
-    virtual const char *        GetVendorName(void);
-    virtual bool                MyLogicalAddressContains(cec_logical_address address) const;
+    virtual cec_version           GetCecVersion(bool bUpdate = false);
+    virtual CCECCommandHandler *  GetHandler(void) const { return m_handler; };
+    virtual uint64_t              GetLastActive(void) const { return m_iLastActive; }
+    virtual cec_logical_address   GetLogicalAddress(void) const { return m_iLogicalAddress; }
+    virtual const char*           GetLogicalAddressName(void) const;
+    virtual cec_menu_language &   GetMenuLanguage(bool bUpdate = false);
+    virtual cec_logical_address   GetMyLogicalAddress(void) const;
+    virtual uint16_t              GetMyPhysicalAddress(void) const;
+    virtual CStdString            GetOSDName(bool bUpdate = false);
+    virtual uint16_t              GetPhysicalAddress(bool bUpdate = false);
+    virtual cec_power_status      GetPowerStatus(bool bUpdate = false);
+    virtual CCECProcessor *       GetProcessor(void) const { return m_processor; }
+    virtual cec_device_type       GetType(void) const { return m_type; }
+    virtual cec_vendor_id         GetVendorId(bool bUpdate = false);
+    virtual const char *          GetVendorName(bool bUpdate = false);
+    virtual bool                  MyLogicalAddressContains(cec_logical_address address) const;
+    virtual cec_bus_device_status GetStatus(bool bForcePoll = false);
+    virtual bool                  IsActiveSource(void) const { return m_bActiveSource; }
 
+
+    virtual void SetInactiveSource(void);
+    virtual void SetActiveSource(void);
+    virtual bool TryLogicalAddress(void);
+
+    virtual void SetDeviceStatus(const cec_bus_device_status newStatus);
     virtual void SetPhysicalAddress(uint16_t iNewAddress);
     virtual void SetStreamPath(uint16_t iNewAddress, uint16_t iOldAddress = 0);
     virtual void SetCecVersion(const cec_version newVersion);
     virtual void SetMenuLanguage(const cec_menu_language &menuLanguage);
+    virtual void SetOSDName(CStdString strName);
     virtual void SetMenuState(const cec_menu_state state);
-    virtual void SetVendorId(uint64_t iVendorId);
+    virtual bool SetVendorId(uint64_t iVendorId, bool bInitHandler = true);
     virtual void SetPowerStatus(const cec_power_status powerStatus);
 
     virtual bool TransmitActiveSource(void);
     virtual bool TransmitCECVersion(cec_logical_address dest);
-    virtual bool TransmitInactiveView(void);
+    virtual bool TransmitInactiveSource(void);
     virtual bool TransmitMenuState(cec_logical_address dest);
     virtual bool TransmitOSDName(cec_logical_address dest);
     virtual bool TransmitOSDString(cec_logical_address dest, cec_display_control duration, const char *strMessage);
     virtual bool TransmitPhysicalAddress(void);
     virtual bool TransmitPowerState(cec_logical_address dest);
     virtual bool TransmitPoll(cec_logical_address dest);
-    virtual bool TransmitVendorID(cec_logical_address dest);
+    virtual bool TransmitVendorID(cec_logical_address dest, bool bSendAbort = true);
+    virtual bool TransmitKeypress(cec_user_control_code key);
+    virtual bool TransmitKeyRelease(void);
 
   protected:
-    cec_device_type     m_type;
-    CStdString          m_strDeviceName;
-    uint16_t            m_iPhysicalAddress;
-    uint16_t            m_iStreamPath;
-    cec_logical_address m_iLogicalAddress;
-    cec_power_status    m_powerStatus;
-    cec_menu_language   m_menuLanguage;
-    CCECProcessor      *m_processor;
-    CCECCommandHandler *m_handler;
-    cec_vendor_id       m_vendor;
-    cec_menu_state      m_menuState;
-    bool                m_bActiveSource;
-    uint64_t            m_iLastCommandSent;
-    uint64_t            m_iLastActive;
-    cec_version         m_cecVersion;
-    CMutex              m_mutex;
-    CCondition          m_condition;
+    bool RequestCecVersion(void);
+    bool RequestMenuLanguage(void);
+    bool RequestPowerStatus(void);
+    bool RequestVendorId(void);
+    bool RequestPhysicalAddress(void);
+    bool RequestOSDName(void);
+
+    bool NeedsPoll(void);
+
+    cec_device_type       m_type;
+    CStdString            m_strDeviceName;
+    uint16_t              m_iPhysicalAddress;
+    uint16_t              m_iStreamPath;
+    cec_logical_address   m_iLogicalAddress;
+    cec_power_status      m_powerStatus;
+    cec_menu_language     m_menuLanguage;
+    CCECProcessor      *  m_processor;
+    CCECCommandHandler *  m_handler;
+    cec_vendor_id         m_vendor;
+    cec_menu_state        m_menuState;
+    bool                  m_bActiveSource;
+    uint64_t              m_iLastActive;
+    cec_version           m_cecVersion;
+    cec_bus_device_status m_deviceStatus;
+    CMutex                m_writeMutex;
+    CMutex                m_mutex;
   };
 };
index 02b9d43bbac89a7661e69da4be0f9eab3dbe14f1..4c90b9fa470c734e7e617aad2cf97363b6693300 100644 (file)
@@ -36,6 +36,8 @@
 
 using namespace CEC;
 
+#define ToString(p) m_processor->ToString(p)
+
 CCECPlaybackDevice::CCECPlaybackDevice(CCECProcessor *processor, cec_logical_address address, uint16_t iPhysicalAddress /* = 0 */) :
     CCECBusDevice(processor, address, iPhysicalAddress),
     m_deckStatus(CEC_DECK_INFO_STOP),
@@ -44,24 +46,38 @@ CCECPlaybackDevice::CCECPlaybackDevice(CCECProcessor *processor, cec_logical_add
   m_type = CEC_DEVICE_TYPE_PLAYBACK_DEVICE;
 }
 
+cec_deck_info CCECPlaybackDevice::GetDeckStatus(void)
+{
+  CLockObject lock(&m_mutex);
+  return m_deckStatus;
+}
+
 void CCECPlaybackDevice::SetDeckStatus(cec_deck_info deckStatus)
 {
-  if (m_deckStatus != deckStatus)
+  CLockObject lock(&m_writeMutex);
+  if (m_deckStatus != deckStatus && m_deckStatus != CEC_DECK_INFO_OTHER_STATUS_LG)
   {
     CStdString strLog;
-    strLog.Format(">> %s (%X): deck status changed from '%s' to '%s'", GetLogicalAddressName(), m_iLogicalAddress, CCECCommandHandler::ToString(m_deckStatus), CCECCommandHandler::ToString(deckStatus));
+    strLog.Format(">> %s (%X): deck status changed from '%s' to '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_deckStatus), ToString(deckStatus));
     AddLog(CEC_LOG_DEBUG, strLog.c_str());
 
     m_deckStatus = deckStatus;
   }
 }
 
+cec_deck_control_mode CCECPlaybackDevice::GetDeckControlMode(void)
+{
+  CLockObject lock(&m_mutex);
+  return m_deckControlMode;
+}
+
 void CCECPlaybackDevice::SetDeckControlMode(cec_deck_control_mode mode)
 {
+  CLockObject lock(&m_writeMutex);
   if (m_deckControlMode != mode)
   {
     CStdString strLog;
-    strLog.Format(">> %s (%X): deck control mode changed from '%s' to '%s'", GetLogicalAddressName(), m_iLogicalAddress, CCECCommandHandler::ToString(m_deckControlMode), CCECCommandHandler::ToString(mode));
+    strLog.Format(">> %s (%X): deck control mode changed from '%s' to '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_deckControlMode), ToString(mode));
     AddLog(CEC_LOG_DEBUG, strLog.c_str());
 
     m_deckControlMode = mode;
@@ -70,13 +86,14 @@ void CCECPlaybackDevice::SetDeckControlMode(cec_deck_control_mode mode)
 
 bool CCECPlaybackDevice::TransmitDeckStatus(cec_logical_address dest)
 {
-  CStdString strLog;
-  strLog.Format("<< %s (%X) -> %s (%X): deck status '%s'", GetLogicalAddressName(), m_iLogicalAddress, CCECCommandHandler::ToString(dest), dest, CCECCommandHandler::ToString(m_deckStatus));
-  AddLog(CEC_LOG_NOTICE, strLog);
-
-  cec_command command;
-  cec_command::format(command, m_iLogicalAddress, dest, CEC_OPCODE_DECK_STATUS);
-  command.push_back((uint8_t)m_deckStatus);
+  cec_deck_info state;
+  {
+    CLockObject lock(&m_writeMutex);
+    CStdString strLog;
+    strLog.Format("<< %s (%X) -> %s (%X): deck status '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, ToString(m_deckStatus));
+    AddLog(CEC_LOG_NOTICE, strLog);
+    state = m_deckStatus;
+  }
 
-  return m_processor->Transmit(command);
+  return m_handler->TransmitDeckStatus(m_iLogicalAddress, dest, state);
 }
index db504f7c6d673318568f5a82ec68289eb182f16d..a188489efc9ba1a53512ffdb7f2dbee5fda5ad0c 100644 (file)
@@ -41,8 +41,8 @@ namespace CEC
     CCECPlaybackDevice(CCECProcessor *processor, cec_logical_address address, uint16_t iPhysicalAddress = 0);
     virtual ~CCECPlaybackDevice(void) {};
 
-    virtual cec_deck_info GetDeckStatus(void) const { return m_deckStatus; };
-    virtual cec_deck_control_mode GetDeckControlMode(void) const { return m_deckControlMode; };
+    virtual cec_deck_info GetDeckStatus(void);
+    virtual cec_deck_control_mode GetDeckControlMode(void);
 
     virtual void SetDeckStatus(cec_deck_info deckStatus);
     virtual void SetDeckControlMode(cec_deck_control_mode mode);
index a5fd567b5e67c6c110346a32ff107cdd297ab9d6..702f7a47b40175261c02c01ef6cb515898759cb0 100644 (file)
 using namespace CEC;
 
 CCECRecordingDevice::CCECRecordingDevice(CCECProcessor *processor, cec_logical_address address, uint16_t iPhysicalAddress /* = 0 */) :
-    CCECBusDevice(processor, address, iPhysicalAddress)
+    CCECBusDevice(processor, address, iPhysicalAddress),
+    m_playbackDevice(processor, address, iPhysicalAddress),
+    m_tuner(processor, address, iPhysicalAddress)
 {
-  m_type          = CEC_DEVICE_TYPE_RECORDING_DEVICE;
+  m_type = CEC_DEVICE_TYPE_RECORDING_DEVICE;
+}
+
+cec_deck_info CCECRecordingDevice::GetDeckStatus(void)
+{
+  return m_playbackDevice.GetDeckStatus();
+}
+
+cec_deck_control_mode CCECRecordingDevice::GetDeckControlMode(void)
+{
+  return m_playbackDevice.GetDeckControlMode();
+}
+
+void CCECRecordingDevice::SetDeckStatus(cec_deck_info deckStatus)
+{
+  m_playbackDevice.SetDeckStatus(deckStatus);
+}
+
+void CCECRecordingDevice::SetDeckControlMode(cec_deck_control_mode mode)
+{
+  m_playbackDevice.SetDeckControlMode(mode);
+}
+
+bool CCECRecordingDevice::TransmitDeckStatus(cec_logical_address dest)
+{
+  return m_playbackDevice.TransmitDeckStatus(dest);
 }
index 45c0407cd8341b6d9dc878ae3973cd13bf4a2d50..c19b2d16f5aa7ebf0099c8a984f639e26792d1d0 100644 (file)
@@ -32,6 +32,8 @@
  */
 
 #include "CECBusDevice.h"
+#include "CECPlaybackDevice.h"
+#include "CECTuner.h"
 
 namespace CEC
 {
@@ -40,5 +42,21 @@ namespace CEC
   public:
     CCECRecordingDevice(CCECProcessor *processor, cec_logical_address address, uint16_t iPhysicalAddress = 0);
     virtual ~CCECRecordingDevice(void) {};
+
+    /* playback device methods */
+    virtual cec_deck_info GetDeckStatus(void);
+    virtual cec_deck_control_mode GetDeckControlMode(void);
+
+    virtual void SetDeckStatus(cec_deck_info deckStatus);
+    virtual void SetDeckControlMode(cec_deck_control_mode mode);
+
+    virtual bool TransmitDeckStatus(cec_logical_address dest);
+
+    /* tuner methods */
+    //TODO
+
+  protected:
+    CCECPlaybackDevice m_playbackDevice;
+    CCECTuner          m_tuner;
   };
 }
index 3da959eb5939f61c2e1189cddac4abbe1d297bfc..e9674baafb22f84ca8f575d46e407884156cf8a4 100644 (file)
@@ -44,7 +44,7 @@ CANCommandHandler::CANCommandHandler(CCECBusDevice *busDevice) :
 
 bool CANCommandHandler::HandleVendorRemoteButtonDown(const cec_command &command)
 {
-  if (command.parameters.size > 0)
+  if (m_processor->IsStarted() && command.parameters.size > 0)
   {
     cec_keypress key;
     key.duration = CEC_BUTTON_TIMEOUT;
index 3c3d84146cf96fc56b48da7c5b2e913542b0d6cd..80bc280a3bb9b8af47e7be43582baa8ef9f22111 100644 (file)
 using namespace CEC;
 using namespace std;
 
-CCECCommandHandler::CCECCommandHandler(CCECBusDevice *busDevice)
+CCECCommandHandler::CCECCommandHandler(CCECBusDevice *busDevice) :
+    m_busDevice(busDevice),
+    m_processor(m_busDevice->GetProcessor()),
+    m_iTransmitTimeout(CEC_DEFAULT_TRANSMIT_TIMEOUT),
+    m_iTransmitWait(CEC_DEFAULT_TRANSMIT_WAIT),
+    m_iTransmitRetries(CEC_DEFAULT_TRANSMIT_RETRIES)
 {
-  m_busDevice = busDevice;
+}
+
+CCECCommandHandler::~CCECCommandHandler(void)
+{
+  m_condition.Broadcast();
 }
 
 bool CCECCommandHandler::HandleCommand(const cec_command &command)
 {
-  bool bHandled(true);
+  bool bHandled(true), bHandlerChanged(false);
 
   CStdString strLog;
-  strLog.Format(">> %s (%X) -> %s (%X): %s (%2X)", ToString(command.initiator), command.initiator, ToString(command.destination), command.destination, ToString(command.opcode), command.opcode);
+  strLog.Format(">> %s (%X) -> %s (%X): %s (%2X)", m_processor->ToString(command.initiator), command.initiator, m_processor->ToString(command.destination), command.destination, m_processor->ToString(command.opcode), command.opcode);
   m_busDevice->AddLog(CEC_LOG_NOTICE, strLog);
 
-  if (m_busDevice->MyLogicalAddressContains(command.destination))
-  {
-    switch(command.opcode)
-    {
-    case CEC_OPCODE_REPORT_POWER_STATUS:
-      HandleReportPowerStatus(command);
-      break;
-    case CEC_OPCODE_CEC_VERSION:
-      HandleDeviceCecVersion(command);
-      break;
-    case CEC_OPCODE_SET_MENU_LANGUAGE:
-      HandleSetMenuLanguage(command);
-      /* pass to listeners */
-      m_busDevice->GetProcessor()->AddCommand(command);
-      break;
-    case CEC_OPCODE_GIVE_PHYSICAL_ADDRESS:
-      HandleGivePhysicalAddress(command);
-      break;
-    case CEC_OPCODE_GIVE_OSD_NAME:
-      HandleGiveOSDName(command);
-      break;
-    case CEC_OPCODE_GIVE_DEVICE_VENDOR_ID:
-      HandleGiveDeviceVendorId(command);
-      break;
-    case CEC_OPCODE_DEVICE_VENDOR_ID:
-      HandleDeviceVendorId(command);
-      break;
-    case CEC_OPCODE_VENDOR_COMMAND_WITH_ID:
-      HandleDeviceVendorCommandWithId(command);
-      break;
-    case CEC_OPCODE_GIVE_DECK_STATUS:
-      HandleGiveDeckStatus(command);
-      break;
-    case CEC_OPCODE_DECK_CONTROL:
-      HandleDeckControl(command);
-      /* pass to listeners */
-      m_busDevice->GetProcessor()->AddCommand(command);
-      break;
-    case CEC_OPCODE_MENU_REQUEST:
-      HandleMenuRequest(command);
-      break;
-    case CEC_OPCODE_GIVE_DEVICE_POWER_STATUS:
-      HandleGiveDevicePowerStatus(command);
-      break;
-    case CEC_OPCODE_GET_CEC_VERSION:
-      HandleGetCecVersion(command);
-      break;
-    case CEC_OPCODE_USER_CONTROL_PRESSED:
-      HandleUserControlPressed(command);
-      break;
-    case CEC_OPCODE_USER_CONTROL_RELEASE:
-      HandleUserControlRelease(command);
-      break;
-    case CEC_OPCODE_GIVE_AUDIO_STATUS:
-      HandleGiveAudioStatus(command);
-      break;
-    case CEC_OPCODE_GIVE_SYSTEM_AUDIO_MODE_STATUS:
-      HandleGiveSystemAudioModeStatus(command);
-      break;
-    case CEC_OPCODE_SYSTEM_AUDIO_MODE_REQUEST:
-      HandleSetSystemAudioModeRequest(command);
-      break;
-    default:
-      UnhandledCommand(command);
-      /* pass to listeners */
-      m_busDevice->GetProcessor()->AddCommand(command);
-      bHandled = false;
-      break;
-    }
-  }
-  else if (command.destination == CECDEVICE_BROADCAST)
+  m_processor->AddCommand(command);
+
+  switch(command.opcode)
   {
-    CStdString strLog;
-    switch (command.opcode)
-    {
-    case CEC_OPCODE_SET_MENU_LANGUAGE:
-      HandleSetMenuLanguage(command);
-      /* pass to listeners */
-      m_busDevice->GetProcessor()->AddCommand(command);
-      break;
-    case CEC_OPCODE_REQUEST_ACTIVE_SOURCE:
-      HandleRequestActiveSource(command);
-      break;
-    case CEC_OPCODE_SET_STREAM_PATH:
-      HandleSetStreamPath(command);
-      break;
-    case CEC_OPCODE_ROUTING_CHANGE:
-      HandleRoutingChange(command);
-      break;
-    case CEC_OPCODE_DEVICE_VENDOR_ID:
-      HandleDeviceVendorId(command);
-      break;
-    case CEC_OPCODE_VENDOR_COMMAND_WITH_ID:
-      HandleDeviceVendorCommandWithId(command);
-     break;
-    case CEC_OPCODE_STANDBY:
-      HandleStandby(command);
-      /* pass to listeners */
-      m_busDevice->GetProcessor()->AddCommand(command);
-     break;
-    case CEC_OPCODE_ACTIVE_SOURCE:
-      HandleActiveSource(command);
-      /* pass to listeners */
-      m_busDevice->GetProcessor()->AddCommand(command);
-      break;
-    default:
-      UnhandledCommand(command);
-      /* pass to listeners */
-      m_busDevice->GetProcessor()->AddCommand(command);
-      bHandled = false;
-      break;
-    }
+  case CEC_OPCODE_REPORT_POWER_STATUS:
+    HandleReportPowerStatus(command);
+    break;
+  case CEC_OPCODE_CEC_VERSION:
+    HandleDeviceCecVersion(command);
+    break;
+  case CEC_OPCODE_SET_MENU_LANGUAGE:
+    HandleSetMenuLanguage(command);
+    break;
+  case CEC_OPCODE_GIVE_PHYSICAL_ADDRESS:
+    HandleGivePhysicalAddress(command);
+    break;
+  case CEC_OPCODE_GIVE_OSD_NAME:
+     HandleGiveOSDName(command);
+    break;
+  case CEC_OPCODE_GIVE_DEVICE_VENDOR_ID:
+    HandleGiveDeviceVendorId(command);
+    break;
+  case CEC_OPCODE_DEVICE_VENDOR_ID:
+    bHandlerChanged = HandleDeviceVendorId(command);
+    break;
+  case CEC_OPCODE_VENDOR_COMMAND_WITH_ID:
+    HandleDeviceVendorCommandWithId(command);
+    break;
+  case CEC_OPCODE_GIVE_DECK_STATUS:
+    HandleGiveDeckStatus(command);
+    break;
+  case CEC_OPCODE_DECK_CONTROL:
+    HandleDeckControl(command);
+    break;
+  case CEC_OPCODE_MENU_REQUEST:
+    HandleMenuRequest(command);
+    break;
+  case CEC_OPCODE_GIVE_DEVICE_POWER_STATUS:
+    HandleGiveDevicePowerStatus(command);
+    break;
+  case CEC_OPCODE_GET_CEC_VERSION:
+    HandleGetCecVersion(command);
+    break;
+  case CEC_OPCODE_USER_CONTROL_PRESSED:
+    HandleUserControlPressed(command);
+    break;
+  case CEC_OPCODE_USER_CONTROL_RELEASE:
+    HandleUserControlRelease(command);
+    break;
+  case CEC_OPCODE_GIVE_AUDIO_STATUS:
+    HandleGiveAudioStatus(command);
+    break;
+  case CEC_OPCODE_GIVE_SYSTEM_AUDIO_MODE_STATUS:
+    HandleGiveSystemAudioModeStatus(command);
+    break;
+  case CEC_OPCODE_SYSTEM_AUDIO_MODE_REQUEST:
+    HandleSystemAudioModeRequest(command);
+    break;
+  case CEC_OPCODE_REPORT_AUDIO_STATUS:
+    HandleReportAudioStatus(command);
+    break;
+  case CEC_OPCODE_SYSTEM_AUDIO_MODE_STATUS:
+    HandleSystemAudioModeStatus(command);
+    break;
+  case CEC_OPCODE_SET_SYSTEM_AUDIO_MODE:
+    HandleSetSystemAudioMode(command);
+    break;
+  case CEC_OPCODE_REQUEST_ACTIVE_SOURCE:
+    HandleRequestActiveSource(command);
+    break;
+  case CEC_OPCODE_SET_STREAM_PATH:
+    HandleSetStreamPath(command);
+    break;
+  case CEC_OPCODE_ROUTING_CHANGE:
+    HandleRoutingChange(command);
+    break;
+  case CEC_OPCODE_ROUTING_INFORMATION:
+    HandleRoutingInformation(command);
+    break;
+  case CEC_OPCODE_STANDBY:
+    HandleStandby(command);
+    break;
+  case CEC_OPCODE_ACTIVE_SOURCE:
+    HandleActiveSource(command);
+    break;
+  case CEC_OPCODE_REPORT_PHYSICAL_ADDRESS:
+    HandleReportPhysicalAddress(command);
+    break;
+  case CEC_OPCODE_SET_OSD_NAME:
+    HandleSetOSDName(command);
+    break;
+  case CEC_OPCODE_IMAGE_VIEW_ON:
+    HandleImageViewOn(command);
+    break;
+  case CEC_OPCODE_TEXT_VIEW_ON:
+    HandleTextViewOn(command);
+    break;
+  default:
+    UnhandledCommand(command);
+    bHandled = false;
+    break;
   }
-  else
+
+  if (bHandled && !bHandlerChanged)
   {
-    CStdString strLog;
-    strLog.Format("ignoring frame: we're not at destination %x", command.destination);
-    m_busDevice->AddLog(CEC_LOG_DEBUG, strLog.c_str());
-    bHandled = false;
+    CLockObject lock(&m_receiveMutex);
+    m_condition.Signal();
   }
 
   return bHandled;
@@ -181,7 +178,7 @@ bool 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]);
-    return m_busDevice->GetProcessor()->SetStreamPath(iAddress);
+    return m_processor->SetActiveSource(iAddress);
   }
 
   return true;
@@ -190,7 +187,7 @@ bool CCECCommandHandler::HandleActiveSource(const cec_command &command)
 bool CCECCommandHandler::HandleDeckControl(const cec_command &command)
 {
   CCECBusDevice *device = GetDevice(command.destination);
-  if (device && device->GetType() == CEC_DEVICE_TYPE_PLAYBACK_DEVICE && command.parameters.size > 0)
+  if (device && (device->GetType() == CEC_DEVICE_TYPE_PLAYBACK_DEVICE || device->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE) && command.parameters.size > 0)
   {
     ((CCECPlaybackDevice *) device)->SetDeckControlMode((cec_deck_control_mode) command.parameters[0]);
     return true;
@@ -213,91 +210,158 @@ bool CCECCommandHandler::HandleDeviceCecVersion(const cec_command &command)
 
 bool CCECCommandHandler::HandleDeviceVendorCommandWithId(const cec_command &command)
 {
-  SetVendorId(command);
-  m_busDevice->GetProcessor()->TransmitAbort(command.initiator, command.opcode, CEC_ABORT_REASON_REFUSED);
+  if (m_processor->IsStarted() && m_busDevice->MyLogicalAddressContains(command.destination))
+    m_processor->TransmitAbort(command.initiator, command.opcode, CEC_ABORT_REASON_REFUSED);
+
   return true;
 }
 
 bool CCECCommandHandler::HandleDeviceVendorId(const cec_command &command)
 {
-  SetVendorId(command);
-  return true;
+  return SetVendorId(command);
 }
 
 bool CCECCommandHandler::HandleGetCecVersion(const cec_command &command)
 {
-  CCECBusDevice *device = GetDevice(command.destination);
-  if (device)
-    return device->TransmitCECVersion(command.initiator);
+  if (m_processor->IsStarted() && m_busDevice->MyLogicalAddressContains(command.destination))
+  {
+    CCECBusDevice *device = GetDevice(command.destination);
+    if (device)
+      return device->TransmitCECVersion(command.initiator);
+  }
 
   return false;
 }
 
 bool CCECCommandHandler::HandleGiveAudioStatus(const cec_command &command)
 {
-  CCECBusDevice *device = GetDevice(command.destination);
-  if (device && device->GetType() == CEC_DEVICE_TYPE_AUDIO_SYSTEM)
-    return ((CCECAudioSystem *) device)->TransmitAudioStatus(command.initiator);
+  if (m_processor->IsStarted() && m_busDevice->MyLogicalAddressContains(command.destination))
+  {
+    CCECBusDevice *device = GetDevice(command.destination);
+    if (device && device->GetType() == CEC_DEVICE_TYPE_AUDIO_SYSTEM)
+      return ((CCECAudioSystem *) device)->TransmitAudioStatus(command.initiator);
+  }
 
   return false;
 }
 
 bool CCECCommandHandler::HandleGiveDeckStatus(const cec_command &command)
 {
-  CCECBusDevice *device = GetDevice(command.destination);
-  if (device && device->GetType() == CEC_DEVICE_TYPE_PLAYBACK_DEVICE)
-    return ((CCECPlaybackDevice *) device)->TransmitDeckStatus(command.initiator);
+  if (m_processor->IsStarted() && m_busDevice->MyLogicalAddressContains(command.destination))
+  {
+    CCECBusDevice *device = GetDevice(command.destination);
+    if (device && (device->GetType() == CEC_DEVICE_TYPE_PLAYBACK_DEVICE || device->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE))
+      return ((CCECPlaybackDevice *) device)->TransmitDeckStatus(command.initiator);
+  }
 
   return false;
 }
 
 bool CCECCommandHandler::HandleGiveDevicePowerStatus(const cec_command &command)
 {
-  CCECBusDevice *device = GetDevice(command.destination);
-  if (device)
-    return device->TransmitPowerState(command.initiator);
+  if (m_processor->IsStarted() && m_busDevice->MyLogicalAddressContains(command.destination))
+  {
+    CCECBusDevice *device = GetDevice(command.destination);
+    if (device)
+      return device->TransmitPowerState(command.initiator);
+  }
 
   return false;
 }
 
 bool CCECCommandHandler::HandleGiveDeviceVendorId(const cec_command &command)
 {
-  CCECBusDevice *device = GetDevice(command.destination);
-  if (device)
-    return device->TransmitVendorID(command.initiator);
+  if (m_processor->IsStarted() && m_busDevice->MyLogicalAddressContains(command.destination))
+  {
+    CCECBusDevice *device = GetDevice(command.destination);
+    if (device)
+      return device->TransmitVendorID(command.initiator);
+  }
 
   return false;
 }
 
 bool CCECCommandHandler::HandleGiveOSDName(const cec_command &command)
 {
-  CCECBusDevice *device = GetDevice(command.destination);
-  if (device)
-    return device->TransmitOSDName(command.initiator);
+  if (m_processor->IsStarted() && m_busDevice->MyLogicalAddressContains(command.destination))
+  {
+    CCECBusDevice *device = GetDevice(command.destination);
+    if (device)
+      return device->TransmitOSDName(command.initiator);
+  }
 
   return false;
 }
 
 bool CCECCommandHandler::HandleGivePhysicalAddress(const cec_command &command)
 {
-  CCECBusDevice *device = GetDevice(command.destination);
-  if (device)
-    return device->TransmitPhysicalAddress();
+  if (m_processor->IsStarted() && m_busDevice->MyLogicalAddressContains(command.destination))
+  {
+    CCECBusDevice *device = GetDevice(command.destination);
+    if (device)
+      return device->TransmitPhysicalAddress();
+  }
 
   return false;
 }
 
-bool CCECCommandHandler::HandleMenuRequest(const cec_command &command)
+bool CCECCommandHandler::HandleGiveSystemAudioModeStatus(const cec_command &command)
 {
-  if (command.parameters[0] == CEC_MENU_REQUEST_TYPE_QUERY)
+  if (m_processor->IsStarted() && m_busDevice->MyLogicalAddressContains(command.destination))
   {
     CCECBusDevice *device = GetDevice(command.destination);
-    if (device)
-      return device->TransmitMenuState(command.initiator);
+    if (device && device->GetType() == CEC_DEVICE_TYPE_AUDIO_SYSTEM)
+      return ((CCECAudioSystem *) device)->TransmitSystemAudioModeStatus(command.initiator);
+  }
+
+  return false;
+}
+
+bool CCECCommandHandler::HandleImageViewOn(const cec_command &command)
+{
+  m_processor->m_busDevices[command.initiator]->SetActiveSource();
+  return true;
+}
+
+bool CCECCommandHandler::HandleMenuRequest(const cec_command &command)
+{
+  if (m_processor->IsStarted() && m_busDevice->MyLogicalAddressContains(command.destination))
+  {
+    if (command.parameters[0] == CEC_MENU_REQUEST_TYPE_QUERY)
+    {
+      CCECBusDevice *device = GetDevice(command.destination);
+      if (device)
+        return device->TransmitMenuState(command.initiator);
+    }
   }
+
   return false;
 }
 
+bool CCECCommandHandler::HandleReportAudioStatus(const cec_command &command)
+{
+  if (command.parameters.size == 1)
+  {
+    CCECBusDevice *device = GetDevice(command.initiator);
+    if (device && device->GetType() == CEC_DEVICE_TYPE_AUDIO_SYSTEM)
+    {
+      ((CCECAudioSystem *)device)->SetAudioStatus(command.parameters[0]);
+      return true;
+    }
+  }
+  return false;
+}
+
+bool 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);
+  }
+  return true;
+}
+
 bool CCECCommandHandler::HandleReportPowerStatus(const cec_command &command)
 {
   if (command.parameters.size == 1)
@@ -311,15 +375,19 @@ bool CCECCommandHandler::HandleReportPowerStatus(const cec_command &command)
 
 bool CCECCommandHandler::HandleRequestActiveSource(const cec_command &command)
 {
-  CStdString strLog;
-  strLog.Format(">> %i requests active source", (uint8_t) command.initiator);
-  m_busDevice->AddLog(CEC_LOG_DEBUG, strLog.c_str());
+  if (m_processor->IsStarted())
+  {
+    CStdString strLog;
+    strLog.Format(">> %i requests active source", (uint8_t) command.initiator);
+    m_busDevice->AddLog(CEC_LOG_DEBUG, strLog.c_str());
 
-  vector<CCECBusDevice *> devices;
-  for (int iDevicePtr = (int)GetMyDevices(devices)-1; iDevicePtr >=0; iDevicePtr--)
-    devices[iDevicePtr]->TransmitActiveSource();
+    vector<CCECBusDevice *> devices;
+    for (int iDevicePtr = (int)GetMyDevices(devices)-1; iDevicePtr >=0; iDevicePtr--)
+      devices[iDevicePtr]->TransmitActiveSource();
 
-  return true;
+    return true;
+  }
+  return false;
 }
 
 bool CCECCommandHandler::HandleRoutingChange(const cec_command &command)
@@ -336,6 +404,17 @@ bool CCECCommandHandler::HandleRoutingChange(const cec_command &command)
   return true;
 }
 
+bool CCECCommandHandler::HandleRoutingInformation(const cec_command &command)
+{
+  if (command.parameters.size == 2)
+  {
+    uint16_t iNewAddress = ((uint16_t)command.parameters[0] << 8) | ((uint16_t)command.parameters[1]);
+    m_processor->SetActiveSource(iNewAddress);
+  }
+
+  return false;
+}
+
 bool CCECCommandHandler::HandleSetMenuLanguage(const cec_command &command)
 {
   if (command.parameters.size == 3)
@@ -349,43 +428,78 @@ bool CCECCommandHandler::HandleSetMenuLanguage(const cec_command &command)
         language.language[iPtr] = command.parameters[iPtr];
       language.language[3] = 0;
       device->SetMenuLanguage(language);
+      return true;
     }
   }
-  return true;
+  return false;
+}
+
+bool 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;
+
+      CStdString strName(buf);
+      device->SetOSDName(strName);
+
+      return true;
+    }
+  }
+  return false;
 }
 
 bool CCECCommandHandler::HandleSetStreamPath(const cec_command &command)
 {
-  if (command.parameters.size >= 2)
+  if (m_processor->IsStarted() && command.parameters.size >= 2)
   {
     uint16_t iStreamAddress = ((uint16_t)command.parameters[0] << 8) | ((uint16_t)command.parameters[1]);
     CStdString strLog;
     strLog.Format(">> %i sets stream path to physical address %04x", command.initiator, iStreamAddress);
     m_busDevice->AddLog(CEC_LOG_DEBUG, strLog.c_str());
 
-    if (m_busDevice->GetProcessor()->SetStreamPath(iStreamAddress))
+    /* one of the device handled by libCEC has been made active */
+    CCECBusDevice *device = GetDeviceByPhysicalAddress(iStreamAddress);
+    if (device && m_busDevice->MyLogicalAddressContains(device->GetLogicalAddress()))
     {
-      CCECBusDevice *device = GetDeviceByPhysicalAddress(iStreamAddress);
-      if (device)
-      {
-        return device->TransmitActiveSource() &&
-            device->TransmitMenuState(command.initiator);
-      }
+      device->SetActiveSource();
+      device->TransmitActiveSource();
     }
-    return false;
   }
-  return true;
+  return false;
 }
 
-bool CCECCommandHandler::HandleSetSystemAudioModeRequest(const cec_command &command)
+bool CCECCommandHandler::HandleSystemAudioModeRequest(const cec_command &command)
 {
-  if (command.parameters.size >= 1)
+  if (m_processor->IsStarted() && m_busDevice->MyLogicalAddressContains(command.destination))
   {
     CCECBusDevice *device = GetDevice(command.destination);
-    if (device&& device->GetType() == CEC_DEVICE_TYPE_AUDIO_SYSTEM)
-      return ((CCECAudioSystem *) device)->SetSystemAudioMode(command);
+    if (device && device->GetType() == CEC_DEVICE_TYPE_AUDIO_SYSTEM)
+    {
+      if (command.parameters.size >= 2)
+      {
+        device->SetPowerStatus(CEC_POWER_STATUS_ON);
+        ((CCECAudioSystem *) 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->SetActiveSource();
+        return ((CCECAudioSystem *) device)->TransmitSetSystemAudioMode(command.initiator);
+      }
+      else
+      {
+        ((CCECAudioSystem *) device)->SetSystemAudioModeStatus(CEC_SYSTEM_AUDIO_STATUS_OFF);
+        return ((CCECAudioSystem *) device)->TransmitSetSystemAudioMode(command.initiator);
+      }
+    }
   }
-  return true;
+  return false;
 }
 
 bool CCECCommandHandler::HandleStandby(const cec_command &command)
@@ -393,23 +507,51 @@ bool CCECCommandHandler::HandleStandby(const cec_command &command)
   CCECBusDevice *device = GetDevice(command.initiator);
   if (device)
     device->SetPowerStatus(CEC_POWER_STATUS_STANDBY);
+
   return true;
 }
 
-bool CCECCommandHandler::HandleGiveSystemAudioModeStatus(const cec_command &command)
+bool CCECCommandHandler::HandleSystemAudioModeStatus(const cec_command &command)
 {
-  CCECBusDevice *device = GetDevice(command.destination);
-  if (device && device->GetType() == CEC_DEVICE_TYPE_AUDIO_SYSTEM)
-    return ((CCECAudioSystem *) device)->TransmitSystemAudioModeStatus(command.initiator);
+  if (command.parameters.size == 1)
+  {
+    CCECBusDevice *device = GetDevice(command.initiator);
+    if (device && device->GetType() == CEC_DEVICE_TYPE_AUDIO_SYSTEM)
+    {
+      ((CCECAudioSystem *)device)->SetSystemAudioModeStatus((cec_system_audio_status)command.parameters[0]);
+      return true;
+    }
+  }
+
+  return false;
+}
+
+bool CCECCommandHandler::HandleSetSystemAudioMode(const cec_command &command)
+{
+  if (command.parameters.size == 1)
+  {
+    CCECBusDevice *device = GetDevice(command.initiator);
+    if (device && device->GetType() == CEC_DEVICE_TYPE_AUDIO_SYSTEM)
+    {
+      ((CCECAudioSystem *)device)->SetSystemAudioModeStatus((cec_system_audio_status)command.parameters[0]);
+      return true;
+    }
+  }
 
   return false;
 }
 
+bool CCECCommandHandler::HandleTextViewOn(const cec_command &command)
+{
+  m_processor->m_busDevices[command.initiator]->SetActiveSource();
+  return true;
+}
+
 bool CCECCommandHandler::HandleUserControlPressed(const cec_command &command)
 {
-  if (command.parameters.size > 0)
+  if (m_processor->IsStarted() && m_busDevice->MyLogicalAddressContains(command.destination) && command.parameters.size > 0)
   {
-    m_busDevice->GetProcessor()->AddKey();
+    m_processor->AddKey();
 
     if (command.parameters[0] <= CEC_USER_CONTROL_CODE_MAX)
     {
@@ -422,18 +564,32 @@ bool CCECCommandHandler::HandleUserControlPressed(const cec_command &command)
       {
         CCECBusDevice *device = GetDevice(command.destination);
         if (device)
+        {
           device->SetPowerStatus(CEC_POWER_STATUS_ON);
+          if (device->MyLogicalAddressContains(device->GetLogicalAddress()))
+          {
+            device->SetActiveSource();
+            device->TransmitActiveSource();
+
+            if (device->GetType() == CEC_DEVICE_TYPE_PLAYBACK_DEVICE ||
+                device->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE)
+              ((CCECPlaybackDevice *)device)->TransmitDeckStatus(command.initiator);
+          }
+        }
       }
 
-      m_busDevice->GetProcessor()->SetCurrentButton((cec_user_control_code) command.parameters[0]);
+      m_processor->SetCurrentButton((cec_user_control_code) command.parameters[0]);
+      return true;
     }
   }
-  return true;
+  return false;
 }
 
 bool CCECCommandHandler::HandleUserControlRelease(const cec_command &command)
 {
-  m_busDevice->GetProcessor()->AddKey();
+  if (m_processor->IsStarted() && m_busDevice->MyLogicalAddressContains(command.destination))
+    m_processor->AddKey();
+
   return true;
 }
 
@@ -448,7 +604,7 @@ unsigned int CCECCommandHandler::GetMyDevices(vector<CCECBusDevice *> &devices)
 {
   unsigned int iReturn(0);
 
-  cec_logical_addresses addresses = m_busDevice->GetProcessor()->GetLogicalAddresses();
+  cec_logical_addresses addresses = m_processor->GetLogicalAddresses();
   for (uint8_t iPtr = 0; iPtr < 16; iPtr++)
   {
     if (addresses[iPtr])
@@ -466,27 +622,28 @@ CCECBusDevice *CCECCommandHandler::GetDevice(cec_logical_address iLogicalAddress
   CCECBusDevice *device = NULL;
 
   if (iLogicalAddress >= CECDEVICE_TV && iLogicalAddress <= CECDEVICE_BROADCAST)
-    device = m_busDevice->GetProcessor()->m_busDevices[iLogicalAddress];
+    device = m_processor->m_busDevices[iLogicalAddress];
 
   return device;
 }
 
 CCECBusDevice *CCECCommandHandler::GetDeviceByPhysicalAddress(uint16_t iPhysicalAddress) const
 {
-  return m_busDevice->GetProcessor()->GetDeviceByPhysicalAddress(iPhysicalAddress);
+  return m_processor->GetDeviceByPhysicalAddress(iPhysicalAddress);
 }
 
 CCECBusDevice *CCECCommandHandler::GetDeviceByType(cec_device_type type) const
 {
-  return m_busDevice->GetProcessor()->GetDeviceByType(type);
+  return m_processor->GetDeviceByType(type);
 }
 
-void CCECCommandHandler::SetVendorId(const cec_command &command)
+bool CCECCommandHandler::SetVendorId(const cec_command &command)
 {
+  bool bChanged(false);
   if (command.parameters.size < 3)
   {
     m_busDevice->AddLog(CEC_LOG_WARNING, "invalid vendor ID received");
-    return;
+    return bChanged;
   }
 
   uint64_t iVendorId = ((uint64_t)command.parameters[0] << 16) +
@@ -495,320 +652,271 @@ void CCECCommandHandler::SetVendorId(const cec_command &command)
 
   CCECBusDevice *device = GetDevice((cec_logical_address) command.initiator);
   if (device)
-    device->SetVendorId(iVendorId);
+    bChanged = device->SetVendorId(iVendorId);
+  return bChanged;
 }
 
-const char *CCECCommandHandler::ToString(const cec_menu_state state)
+void CCECCommandHandler::SetPhysicalAddress(cec_logical_address iAddress, uint16_t iNewAddress)
 {
-  switch (state)
+  if (!m_busDevice->MyLogicalAddressContains(iAddress))
   {
-  case CEC_MENU_STATE_ACTIVATED:
-    return "activated";
-  case CEC_MENU_STATE_DEACTIVATED:
-    return "deactivated";
-  default:
-    return "unknown";
+    bool bOurAddress(m_processor->GetPhysicalAddress() == iNewAddress);
+    GetDevice(iAddress)->SetPhysicalAddress(iNewAddress);
+    if (bOurAddress)
+    {
+      /* another device reported the same physical address as ours
+       * since we don't have physical address detection yet, we'll just use the
+       * given address, increased by 0x100 for now */
+      m_processor->SetPhysicalAddress(iNewAddress + 0x100);
+    }
   }
 }
 
-const char *CCECCommandHandler::ToString(const cec_version version)
+void CCECCommandHandler::HandlePoll(const cec_logical_address iInitiator, const cec_logical_address iDestination)
 {
-  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";
-  }
+  CStdString strLog;
+  strLog.Format("<< POLL: %s (%x) -> %s (%x)", m_processor->ToString(iInitiator), iInitiator, m_processor->ToString(iDestination), iDestination);
+  m_processor->AddLog(CEC_LOG_DEBUG, strLog);
 }
 
-const char *CCECCommandHandler::ToString(const cec_power_status status)
+bool CCECCommandHandler::HandleReceiveFailed(void)
 {
-  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";
-  }
+  /* default = error */
+  return true;
 }
 
-const char *CCECCommandHandler::ToString(const cec_logical_address address)
+bool CCECCommandHandler::TransmitPowerOn(const cec_logical_address iInitiator, const cec_logical_address iDestination)
 {
-  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";
-  }
+  cec_command command;
+  cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_IMAGE_VIEW_ON);
+
+  return Transmit(command);
 }
 
-const char *CCECCommandHandler::ToString(const cec_deck_control_mode mode)
+bool CCECCommandHandler::TransmitStandby(const cec_logical_address iInitiator, const cec_logical_address iDestination)
 {
-  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";
-  }
+  cec_command command;
+  cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_STANDBY);
+
+  return Transmit(command);
 }
 
-const char *CCECCommandHandler::ToString(const cec_deck_info status)
+bool CCECCommandHandler::TransmitRequestCecVersion(const cec_logical_address iInitiator, const cec_logical_address iDestination)
 {
-  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";
-  default:
-    return "unknown";
-  }
+  cec_command command;
+  cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GET_CEC_VERSION);
+
+  return Transmit(command);
 }
 
-const char *CCECCommandHandler::ToString(const cec_opcode opcode)
+bool CCECCommandHandler::TransmitRequestMenuLanguage(const cec_logical_address iInitiator, const cec_logical_address iDestination)
 {
-  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";
-  default:
-    return "UNKNOWN";
-  }
+  cec_command command;
+  cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GET_MENU_LANGUAGE);
+
+  return Transmit(command);
 }
 
-const char *CCECCommandHandler::ToString(const cec_system_audio_status mode)
+bool CCECCommandHandler::TransmitRequestOSDName(const cec_logical_address iInitiator, const cec_logical_address iDestination)
 {
-  switch(mode)
-  {
-  case CEC_SYSTEM_AUDIO_STATUS_ON:
-    return "on";
-  case CEC_SYSTEM_AUDIO_STATUS_OFF:
-    return "off";
-  default:
-    return "unknown";
-  }
+  cec_command command;
+  cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GIVE_OSD_NAME);
+
+  return Transmit(command);
+}
+
+bool CCECCommandHandler::TransmitRequestPhysicalAddress(const cec_logical_address iInitiator, const cec_logical_address iDestination)
+{
+  cec_command command;
+  cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GIVE_PHYSICAL_ADDRESS);
+
+  return Transmit(command);
+}
+
+bool CCECCommandHandler::TransmitRequestPowerStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination)
+{
+  cec_command command;
+  cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GIVE_DEVICE_POWER_STATUS);
+
+  return Transmit(command);
+}
+
+bool CCECCommandHandler::TransmitRequestVendorId(const cec_logical_address iInitiator, const cec_logical_address iDestination)
+{
+  cec_command command;
+  cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID);
+
+  return Transmit(command);
+}
+
+bool CCECCommandHandler::TransmitActiveSource(const cec_logical_address iInitiator, uint16_t iPhysicalAddress)
+{
+  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);
+}
+
+bool CCECCommandHandler::TransmitCECVersion(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_version cecVersion)
+{
+  cec_command command;
+  cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_CEC_VERSION);
+  command.parameters.PushBack((uint8_t)cecVersion);
+
+  return Transmit(command);
+}
+
+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);
+}
+
+bool CCECCommandHandler::TransmitMenuState(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_menu_state menuState)
+{
+  cec_command command;
+  cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_MENU_STATUS);
+  command.parameters.PushBack((uint8_t)menuState);
+
+  return Transmit(command);
+}
+
+bool CCECCommandHandler::TransmitOSDName(const cec_logical_address iInitiator, const cec_logical_address iDestination, CStdString strDeviceName)
+{
+  cec_command command;
+  cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_SET_OSD_NAME);
+  for (unsigned int iPtr = 0; iPtr < strDeviceName.length(); iPtr++)
+    command.parameters.PushBack(strDeviceName.at(iPtr));
+
+  return Transmit(command);
+}
+
+bool CCECCommandHandler::TransmitOSDString(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_display_control duration, const char *strMessage)
+{
+  cec_command command;
+  cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_SET_OSD_STRING);
+  command.parameters.PushBack((uint8_t)duration);
+
+  unsigned int iLen = strlen(strMessage);
+  if (iLen > 13) iLen = 13;
+
+  for (unsigned int iPtr = 0; iPtr < iLen; iPtr++)
+    command.parameters.PushBack(strMessage[iPtr]);
+
+  return Transmit(command);
+}
+
+bool CCECCommandHandler::TransmitPhysicalAddress(const cec_logical_address iInitiator, uint16_t iPhysicalAddress, cec_device_type type)
+{
+  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);
+}
+
+bool CCECCommandHandler::TransmitPoll(const cec_logical_address iInitiator, const cec_logical_address iDestination)
+{
+  cec_command command;
+  cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_NONE);
+
+  return Transmit(command, false);
+}
+
+bool CCECCommandHandler::TransmitPowerState(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_power_status state)
+{
+  cec_command command;
+  cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_REPORT_POWER_STATUS);
+  command.parameters.PushBack((uint8_t) state);
+
+  return Transmit(command);
+}
+
+bool CCECCommandHandler::TransmitVendorID(const cec_logical_address iInitiator, uint64_t iVendorId)
+{
+  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);
+}
+
+bool CCECCommandHandler::TransmitAudioStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, uint8_t state)
+{
+  cec_command command;
+  cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_REPORT_AUDIO_STATUS);
+  command.parameters.PushBack(state);
+
+  return Transmit(command);
+}
+
+bool CCECCommandHandler::TransmitSetSystemAudioMode(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_system_audio_status state)
+{
+  cec_command command;
+  cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_SET_SYSTEM_AUDIO_MODE);
+  command.parameters.PushBack((uint8_t)state);
+
+  return Transmit(command);
 }
 
-const char *CCECCommandHandler::ToString(const cec_audio_status status)
+bool CCECCommandHandler::TransmitSystemAudioModeStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_system_audio_status state)
 {
-  // TODO this is a mask
-  return "TODO";
+  cec_command command;
+  cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_SYSTEM_AUDIO_MODE_STATUS);
+  command.parameters.PushBack((uint8_t)state);
+
+  return Transmit(command);
 }
 
-const char *CCECCommandHandler::ToString(const cec_vendor_id vendor)
+bool CCECCommandHandler::TransmitDeckStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_deck_info state)
 {
-  switch (vendor)
+  cec_command command;
+  cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_DECK_STATUS);
+  command.PushBack((uint8_t)state);
+
+  return Transmit(command);
+}
+
+bool CCECCommandHandler::TransmitKeypress(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_user_control_code key)
+{
+  cec_command command;
+  cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_USER_CONTROL_PRESSED);
+  command.parameters.PushBack((uint8_t)key);
+
+  return Transmit(command);
+}
+
+bool CCECCommandHandler::TransmitKeyRelease(const cec_logical_address iInitiator, const cec_logical_address iDestination)
+{
+  cec_command command;
+  cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_USER_CONTROL_RELEASE);
+
+  return Transmit(command);
+}
+
+bool CCECCommandHandler::Transmit(cec_command &command, bool bExpectResponse /* = true */)
+{
+  command.transmit_timeout = m_iTransmitTimeout;
+
+  CLockObject writeLock(&m_processor->m_transmitMutex);
+  CLockObject receiveLock(&m_receiveMutex);
+  if (m_processor->Transmit(command))
   {
-  case CEC_VENDOR_SAMSUNG:
-    return "Samsung";
-  case CEC_VENDOR_LG:
-    return "LG";
-  case CEC_VENDOR_PANASONIC:
-    return "Panasonic";
-  case CEC_VENDOR_PIONEER:
-    return "Pioneer";
-  default:
-    return "Unknown";
+    if (bExpectResponse)
+      return m_condition.Wait(&m_receiveMutex, m_iTransmitWait);
+    return true;
   }
+
+  return false;
 }
index 9bf98982da7949f847d26a07f12dbf9dfe0f1582..e5d19ed102097c1a1e7901dd644365ffc60a675c 100644 (file)
 
 #include <cectypes.h>
 #include <vector>
+#include "../util/StdString.h"
+#include "../platform/threads.h"
 
 namespace CEC
 {
+  class CCECProcessor;
   class CCECBusDevice;
 
   class CCECCommandHandler
   {
   public:
     CCECCommandHandler(CCECBusDevice *busDevice);
-    virtual ~CCECCommandHandler(void) {};
+    virtual ~CCECCommandHandler(void);
 
     virtual bool HandleCommand(const cec_command &command);
     virtual cec_vendor_id GetVendorId(void) { return CEC_VENDOR_UNKNOWN; };
+    virtual void HandlePoll(const cec_logical_address iInitiator, const cec_logical_address iDestination);
+    virtual bool HandleReceiveFailed(void);
 
-    static const char *ToString(const cec_menu_state state);
-    static const char *ToString(const cec_deck_control_mode mode);
-    static const char *ToString(const cec_version version);
-    static const char *ToString(const cec_power_status status);
-    static const char *ToString(const cec_deck_info status);
-    static const char* ToString(const cec_logical_address address);
-    static const char* ToString(const cec_opcode opcode);
-    static const char *ToString(const cec_system_audio_status mode);
-    static const char *ToString(const cec_audio_status status);
-    static const char *ToString(const cec_vendor_id vendor);
+    virtual bool InitHandler(void) { return true; }
+    virtual uint8_t GetTransmitRetries(void) const { return m_iTransmitRetries; }
+
+    virtual bool TransmitPowerOn(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 TransmitRequestCecVersion(const cec_logical_address iInitiator, const cec_logical_address iDestination);
+    virtual bool TransmitRequestMenuLanguage(const cec_logical_address iInitiator, const cec_logical_address iDestination);
+    virtual bool TransmitRequestOSDName(const cec_logical_address iInitiator, const cec_logical_address iDestination);
+    virtual bool TransmitRequestPhysicalAddress(const cec_logical_address iInitiator, const cec_logical_address iDestination);
+    virtual bool TransmitRequestPowerStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination);
+    virtual bool TransmitRequestVendorId(const cec_logical_address iInitiator, const cec_logical_address iDestination);
+    virtual bool TransmitActiveSource(const cec_logical_address iInitiator, uint16_t iPhysicalAddress);
+    virtual bool TransmitCECVersion(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_version cecVersion);
+    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);
+    virtual bool TransmitOSDName(const cec_logical_address iInitiator, const cec_logical_address iDestination, CStdString strDeviceName);
+    virtual bool TransmitOSDString(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_display_control duration, const char *strMessage);
+    virtual bool TransmitPhysicalAddress(const cec_logical_address iInitiator, uint16_t iPhysicalAddress, cec_device_type type);
+    virtual bool TransmitPoll(const cec_logical_address iInitiator, const cec_logical_address iDestination);
+    virtual bool TransmitPowerState(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_power_status state);
+    virtual bool TransmitVendorID(const cec_logical_address iInitiator, uint64_t iVendorId);
+    virtual bool TransmitAudioStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, uint8_t state);
+    virtual bool TransmitSetSystemAudioMode(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_system_audio_status state);
+    virtual bool TransmitSystemAudioModeStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_system_audio_status state);
+    virtual bool TransmitDeckStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_deck_info state);
+    virtual bool TransmitKeypress(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_user_control_code key);
+    virtual bool TransmitKeyRelease(const cec_logical_address iInitiator, const cec_logical_address iDestination);
 
   protected:
     virtual bool HandleActiveSource(const cec_command &command);
@@ -71,15 +93,23 @@ namespace CEC
     virtual bool HandleGiveDeviceVendorId(const cec_command &command);
     virtual bool HandleGiveOSDName(const cec_command &command);
     virtual bool HandleGivePhysicalAddress(const cec_command &command);
+    virtual bool HandleGiveSystemAudioModeStatus(const cec_command &command);
+    virtual bool HandleImageViewOn(const cec_command &command);
     virtual bool HandleMenuRequest(const cec_command &command);
+    virtual bool HandleReportAudioStatus(const cec_command &command);
+    virtual bool HandleReportPhysicalAddress(const cec_command &command);
     virtual bool HandleReportPowerStatus(const cec_command &command);
     virtual bool HandleRequestActiveSource(const cec_command &command);
     virtual bool HandleRoutingChange(const cec_command &command);
+    virtual bool HandleRoutingInformation(const cec_command &command);
     virtual bool HandleSetMenuLanguage(const cec_command &command);
+    virtual bool HandleSetOSDName(const cec_command &command);
     virtual bool HandleSetStreamPath(const cec_command &command);
-    virtual bool HandleSetSystemAudioModeRequest(const cec_command &command);
+    virtual bool HandleSystemAudioModeRequest(const cec_command &command);
     virtual bool HandleStandby(const cec_command &command);
-    virtual bool HandleGiveSystemAudioModeStatus(const cec_command &command);
+    virtual bool HandleSystemAudioModeStatus(const cec_command &command);
+    virtual bool HandleSetSystemAudioMode(const cec_command &command);
+    virtual bool HandleTextViewOn(const cec_command &command);
     virtual bool HandleUserControlPressed(const cec_command &command);
     virtual bool HandleUserControlRelease(const cec_command &command);
     virtual void UnhandledCommand(const cec_command &command);
@@ -89,7 +119,17 @@ namespace CEC
     virtual CCECBusDevice *GetDeviceByPhysicalAddress(uint16_t iPhysicalAddress) const;
     virtual CCECBusDevice *GetDeviceByType(cec_device_type type) const;
 
-    virtual void SetVendorId(const cec_command &command);
+    virtual bool SetVendorId(const cec_command &command);
+    virtual void SetPhysicalAddress(cec_logical_address iAddress, uint16_t iNewAddress);
+
+    virtual bool Transmit(cec_command &command, bool bExpectResponse = true);
+
     CCECBusDevice *m_busDevice;
+    CCECProcessor *m_processor;
+    int32_t        m_iTransmitTimeout;
+    int32_t        m_iTransmitWait;
+    int8_t         m_iTransmitRetries;
+    CMutex         m_receiveMutex;
+    CCondition     m_condition;
   };
 };
index 144cfc92d933bd033f4d7ac79908f30eef03770e..0f007176d623f9e83732abbef114790b97446d28 100644 (file)
  */
 
 #include "SLCommandHandler.h"
+#include "../devices/CECBusDevice.h"
+#include "../devices/CECPlaybackDevice.h"
+#include "../CECProcessor.h"
+#include "../platform/timeutils.h"
 
 using namespace CEC;
 
+#define SL_COMMAND_UNKNOWN_01           0x01
+#define SL_COMMAND_UNKNOWN_02           0x02
+#define SL_COMMAND_UNKNOWN_03           0x05
+
+#define SL_COMMAND_REQUEST_POWER_STATUS 0xa0
+#define SL_COMMAND_POWER_ON             0x03
+#define SL_COMMAND_CONNECT_REQUEST      0x04
+#define SL_COMMAND_CONNECT_ACCEPT       0x05
+
 CSLCommandHandler::CSLCommandHandler(CCECBusDevice *busDevice) :
-    CCECCommandHandler(busDevice)
+    CCECCommandHandler(busDevice),
+    m_bAwaitingReceiveFailed(false),
+    m_bSLEnabled(false),
+    m_bVendorIdSent(false)
+{
+  /* TODO set to powered off until we fixed the connect on start loop issue */
+  m_processor->m_busDevices[m_processor->GetLogicalAddresses().primary]->m_powerStatus = CEC_POWER_STATUS_STANDBY;
+}
+
+bool CSLCommandHandler::HandleVendorCommand(const cec_command &command)
+{
+  if (command.parameters.size == 1 &&
+      command.parameters[0] == SL_COMMAND_UNKNOWN_01)
+  {
+    HandleVendorCommand01(command);
+    return true;
+  }
+  else if (command.parameters.size == 2 &&
+      command.parameters[0] == SL_COMMAND_POWER_ON)
+  {
+    HandleVendorCommandPowerOn(command);
+    return true;
+  }
+  else if (command.parameters.size == 2 &&
+      command.parameters[0] == SL_COMMAND_CONNECT_REQUEST)
+  {
+    HandleVendorCommandSLConnect(command);
+    return true;
+  }
+  else if (command.parameters.size == 1 &&
+      command.parameters[0] == SL_COMMAND_REQUEST_POWER_STATUS)
+  {
+    HandleVendorCommandPowerOnStatus(command);
+    return true;
+  }
+
+  return false;
+}
+
+bool CSLCommandHandler::HandleGiveDeckStatus(const cec_command &command)
+{
+  if (command.parameters.size == 1)
+  {
+    if (command.parameters[0] == CEC_STATUS_REQUEST_ONCE ||
+        command.parameters[0] == CEC_STATUS_REQUEST_ON)
+    {
+      TransmitDeckStatus(command.initiator);
+    }
+    else
+    {
+      CCECCommandHandler::HandleGiveDeckStatus(command);
+    }
+  }
+  return true;
+}
+
+void CSLCommandHandler::HandleVendorCommand01(const cec_command &command)
+{
+  TransmitVendorCommand0205(command.destination, command.initiator);
+}
+
+void CSLCommandHandler::TransmitVendorCommand0205(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_UNKNOWN_02);
+  response.PushBack(SL_COMMAND_UNKNOWN_03);
+
+  Transmit(response);
+}
+
+void CSLCommandHandler::TransmitVendorCommand05(const cec_logical_address iSource, const cec_logical_address iDestination)
+{
+  m_bSLEnabled = true;
+  cec_command response;
+  cec_command::Format(response, iSource, iDestination, CEC_OPCODE_VENDOR_COMMAND);
+  response.PushBack(SL_COMMAND_CONNECT_ACCEPT);
+  response.PushBack((uint8_t)iSource);
+  Transmit(response);
+}
+
+void CSLCommandHandler::HandleVendorCommandPowerOn(const cec_command &command)
+{
+  CCECBusDevice *device = m_processor->m_busDevices[m_processor->GetLogicalAddresses().primary];
+  if (device)
+  {
+    m_bSLEnabled = true;
+    device->SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON);
+    device->TransmitPowerState(command.initiator);
+    device->TransmitVendorID(command.initiator);
+    TransmitPowerOn(device->GetLogicalAddress(), command.initiator);
+  }
+}
+
+void CSLCommandHandler::HandleVendorCommandSLConnect(const cec_command &command)
+{
+  m_bSLEnabled = true;
+  m_processor->m_busDevices[command.initiator]->SetActiveSource();
+  m_processor->m_busDevices[command.destination]->TransmitActiveSource();
+  TransmitVendorCommand05(command.destination, command.initiator);
+  TransmitDeckStatus(command.initiator);
+}
+
+void CSLCommandHandler::HandleVendorCommandPowerOnStatus(const cec_command &command)
+{
+  if (command.destination != CECDEVICE_BROADCAST)
+  {
+    CCECBusDevice *device = m_processor->m_busDevices[m_processor->GetLogicalAddresses().primary];
+    device->SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON);
+    device->TransmitPowerState(command.initiator);
+    device->SetPowerStatus(CEC_POWER_STATUS_ON);
+  }
+}
+
+void CSLCommandHandler::TransmitDeckStatus(const cec_logical_address iDestination)
+{
+  /* set deck status for the playback device */
+  CCECBusDevice *primary = m_processor->m_busDevices[m_processor->GetLogicalAddresses().primary];
+  if (primary->GetType() == CEC_DEVICE_TYPE_PLAYBACK_DEVICE || primary->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE)
+  {
+    ((CCECPlaybackDevice *)primary)->SetDeckStatus(CEC_DECK_INFO_OTHER_STATUS_LG);
+    ((CCECPlaybackDevice *)primary)->TransmitDeckStatus(iDestination);
+  }
+}
+
+bool CSLCommandHandler::TransmitLGVendorId(const cec_logical_address iInitiator, const cec_logical_address iDestination)
 {
+  cec_command response;
+  cec_command::Format(response, iInitiator, iDestination, CEC_OPCODE_DEVICE_VENDOR_ID);
+  response.parameters.PushBack((uint8_t) (((uint64_t)CEC_VENDOR_LG >> 16) & 0xFF));
+  response.parameters.PushBack((uint8_t) (((uint64_t)CEC_VENDOR_LG >> 8) & 0xFF));
+  response.parameters.PushBack((uint8_t) ((uint64_t)CEC_VENDOR_LG & 0xFF));
+
+  Transmit(response);
+  return true;
+}
+
+bool CSLCommandHandler::HandleGiveDeviceVendorId(const cec_command &command)
+{
+  /* imitate LG devices */
+  CCECBusDevice *device = GetDevice(command.destination);
+  if (device)
+    device->SetVendorId(CEC_VENDOR_LG);
+
+  return CCECCommandHandler::HandleGiveDeviceVendorId(command);
+}
+
+bool CSLCommandHandler::HandleCommand(const cec_command &command)
+{
+  bool bHandled(false);
+
+  if (m_processor->IsStarted() && (m_busDevice->MyLogicalAddressContains(command.destination) ||
+      command.destination == CECDEVICE_BROADCAST))
+  {
+    switch(command.opcode)
+    {
+    case CEC_OPCODE_VENDOR_COMMAND:
+      bHandled = HandleVendorCommand(command);
+      break;
+    case CEC_OPCODE_FEATURE_ABORT:
+      {
+        if (!m_bVendorIdSent)
+        {
+          m_bVendorIdSent = true;
+          TransmitLGVendorId(m_processor->GetLogicalAddresses().primary, CECDEVICE_BROADCAST);
+        }
+      }
+      bHandled = true;
+    default:
+      break;
+    }
+  }
+
+  if (!bHandled)
+    bHandled = CCECCommandHandler::HandleCommand(command);
+
+  return bHandled;
+}
+
+void CSLCommandHandler::HandlePoll(const cec_logical_address iInitiator, const cec_logical_address iDestination)
+{
+  CCECCommandHandler::HandlePoll(iInitiator, iDestination);
+  m_bAwaitingReceiveFailed = true;
+}
+
+bool CSLCommandHandler::HandleReceiveFailed(void)
+{
+  if (m_bAwaitingReceiveFailed)
+  {
+    m_bAwaitingReceiveFailed = false;
+    return false;
+  }
+
+  return true;
 }
+
+bool CSLCommandHandler::InitHandler(void)
+{
+  m_processor->SetStandardLineTimeout(3);
+  m_processor->SetRetryLineTimeout(3);
+
+  /* increase the number of retries because the tv is keeping the bus busy at times */
+  m_iTransmitWait    = 2000;
+  m_iTransmitRetries = 4;
+  m_iTransmitTimeout = 500;
+
+  CCECBusDevice *primary = m_processor->m_busDevices[m_processor->GetLogicalAddresses().primary];
+  if (m_busDevice->GetLogicalAddress() != primary->GetLogicalAddress())
+  {
+    primary->SetVendorId(CEC_VENDOR_LG, false);
+    primary->TransmitVendorID(CECDEVICE_TV, false);
+  }
+
+  if (m_busDevice->GetLogicalAddress() == CECDEVICE_TV)
+  {
+    /* LG TVs 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;
+  lang.device = m_busDevice->GetLogicalAddress();
+  snprintf(lang.language, 4, "eng");
+  m_busDevice->SetMenuLanguage(lang);
+
+  if (m_busDevice->GetLogicalAddress() == CECDEVICE_TV)
+  {
+    m_processor->SetActiveSource();
+
+    /* LG TVs only route keypresses when the deck status is set to 0x20 */
+    cec_logical_addresses addr = m_processor->GetLogicalAddresses();
+    for (uint8_t iPtr = 0; iPtr < 15; iPtr++)
+    {
+      CCECBusDevice *device = m_processor->m_busDevices[iPtr];
+
+      if (addr[iPtr])
+      {
+        if (device && (device->GetType() == CEC_DEVICE_TYPE_PLAYBACK_DEVICE ||
+                       device->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE))
+        {
+          ((CCECPlaybackDevice *)device)->SetDeckStatus(CEC_DECK_INFO_OTHER_STATUS_LG);
+          ((CCECPlaybackDevice *)device)->TransmitDeckStatus(CECDEVICE_TV);
+        }
+      }
+    }
+  }
+
+  return true;
+}
+
+bool CSLCommandHandler::TransmitPowerOn(const cec_logical_address iInitiator, const cec_logical_address iDestination)
+{
+  if (iDestination != CECDEVICE_BROADCAST &&
+      iDestination != CECDEVICE_TV &&
+      m_processor->m_busDevices[iDestination]->GetVendorId(false) == CEC_VENDOR_LG)
+  {
+    cec_command command;
+    cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_VENDOR_COMMAND);
+    command.parameters.PushBack((uint8_t)SL_COMMAND_POWER_ON);
+    command.parameters.PushBack(0x00);
+    return Transmit(command);
+  }
+
+  return CCECCommandHandler::TransmitPowerOn(iInitiator, iDestination);
+}
+
index 76a99701c0db91386a3492bb6bb2283b34e72e5b..3a5a779e5195340898b6b08dd6b0a045f98a7086 100644 (file)
@@ -41,5 +41,29 @@ namespace CEC
     CSLCommandHandler(CCECBusDevice *busDevice);
     virtual ~CSLCommandHandler(void) {};
     virtual cec_vendor_id GetVendorId(void) { return CEC_VENDOR_LG; };
+
+    virtual bool HandleCommand(const cec_command &command);
+    virtual void HandlePoll(const cec_logical_address iInitiator, const cec_logical_address iDestination);
+    virtual bool HandleReceiveFailed(void);
+    virtual bool InitHandler(void);
+    virtual bool TransmitLGVendorId(const cec_logical_address iInitiator, const cec_logical_address iDestination);
+    virtual bool TransmitPowerOn(const cec_logical_address iInitiator, const cec_logical_address iDestination);
+
+  protected:
+    virtual void HandleVendorCommand01(const cec_command &command);
+    virtual void HandleVendorCommandPowerOn(const cec_command &command);
+    virtual void HandleVendorCommandSLConnect(const cec_command &command);
+    virtual void HandleVendorCommandPowerOnStatus(const cec_command &command);
+
+    virtual void TransmitVendorCommand0205(const cec_logical_address iSource, const cec_logical_address iDestination);
+    virtual void TransmitVendorCommand05(const cec_logical_address iSource, const cec_logical_address iDestination);
+    virtual void TransmitDeckStatus(const cec_logical_address iDestination);
+    virtual bool HandleGiveDeviceVendorId(const cec_command &command);
+    virtual bool HandleVendorCommand(const cec_command &command);
+    virtual bool HandleGiveDeckStatus(const cec_command &command);
+
+    bool    m_bAwaitingReceiveFailed;
+    bool    m_bSLEnabled;
+    bool    m_bVendorIdSent;
   };
 };
index 3a274fec12f35f88e9f1ec3e07b439a324fa3aa7..f0408574dad1670238a571ab0dcadfb8acedcff3 100644 (file)
@@ -53,6 +53,7 @@ using namespace CEC;
 CSerialPort::CSerialPort()
 {
   m_fd = -1;
+  m_tostdout = false;
 }
 
 CSerialPort::~CSerialPort()
@@ -73,16 +74,33 @@ int8_t CSerialPort::Write(CCECAdapterMessage *data)
 
   int32_t byteswritten = 0;
 
+  struct timeval timeout, *tv;
+  if (data->transmit_timeout <= 0)
+  {
+    tv = NULL;
+  }
+  else
+  {
+    timeout.tv_sec  = (long int)data->transmit_timeout / (long int)1000.;
+    timeout.tv_usec = (long int)data->transmit_timeout % (long int)1000.;
+    tv = &timeout;
+  }
+
   while (byteswritten < (int32_t) data->size())
   {
     FD_ZERO(&port);
     FD_SET(m_fd, &port);
-    int returnv = select(m_fd + 1, NULL, &port, NULL, NULL);
-    if (returnv == -1)
+    int returnv = select(m_fd + 1, NULL, &port, NULL, tv);
+    if (returnv < 0)
     {
       m_error = strerror(errno);
       return -1;
     }
+    else if (returnv == 0)
+    {
+      m_error = "timeout";
+      return -1;
+    }
 
     returnv = write(m_fd, data->packet.data + byteswritten, data->size() - byteswritten);
     if (returnv == -1)
@@ -94,14 +112,14 @@ int8_t CSerialPort::Write(CCECAdapterMessage *data)
   }
 
   //print what's written to stdout for debugging
-//  if (m_tostdout)
-//  {
-//    printf("%s write:", m_name.c_str());
-//    for (int i = 0; i < byteswritten; i++)
-//      printf(" %02x", (unsigned int)data[i]);
-//
-//    printf("\n");
-//  }
+  if (m_tostdout)
+  {
+    printf("%s write:", m_name.c_str());
+    for (int i = 0; i < byteswritten; i++)
+      printf(" %02x", data->at(i));
+
+    printf("\n");
+  }
 
   return byteswritten;
 }
@@ -167,14 +185,14 @@ int32_t CSerialPort::Read(uint8_t* data, uint32_t len, uint64_t iTimeoutMs /*= 0
   }
 
   //print what's read to stdout for debugging
-//  if (m_tostdout && bytesread > 0)
-//  {
-//    printf("%s read:", m_name.c_str());
-//    for (int i = 0; i < bytesread; i++)
-//      printf(" %02x", (unsigned int)data[i]);
-//
-//    printf("\n");
-//  }
+  if (m_tostdout && bytesread > 0)
+  {
+    printf("%s read:", m_name.c_str());
+    for (int i = 0; i < bytesread; i++)
+      printf(" %02x", data[i]);
+
+    printf("\n");
+  }
 
   return bytesread;
 }
index 45c28506ee575498230adca2de0b234aac65fc24..f5035b908f21705a57bdee173b5e127784145198 100644 (file)
@@ -72,6 +72,7 @@ namespace CEC
       std::string     m_error;
       std::string     m_name;
       CMutex          m_mutex;
+      bool            m_tostdout;
 
   #ifdef __WINDOWS__
       bool SetTimeouts(bool bBlocking);
index 3e67723328f4de77b2590caa794c6159566cc2c5..9a0bf3a6130c9c7466f72945f96e2c0c010fe9fa 100644 (file)
@@ -40,6 +40,7 @@
 #include <sstream>
 #include "../lib/platform/threads.h"
 #include "../lib/util/StdString.h"
+#include "../lib/implementations/CECCommandHandler.h"
 
 using namespace CEC;
 using namespace std;
@@ -48,10 +49,15 @@ using namespace std;
 
 #include <cecloader.h>
 
-int        g_cecLogLevel = CEC_LOG_ALL;
-ofstream   g_logOutput;
-bool       g_bShortLog = false;
-CStdString g_strPort;
+int                  g_cecLogLevel(CEC_LOG_ALL);
+ofstream             g_logOutput;
+bool                 g_bShortLog(false);
+CStdString           g_strPort;
+uint8_t              g_iHDMIPort(CEC_DEFAULT_HDMI_PORT);
+cec_logical_address  g_iBaseDevice((cec_logical_address)CEC_DEFAULT_BASE_DEVICE);
+cec_device_type_list g_typeList;
+bool                 g_bSingleCommand(false);
+
 
 inline bool HexStrToInt(const std::string& data, uint8_t& value)
 {
@@ -105,7 +111,7 @@ bool GetWord(string& data, string& word)
   return true;
 }
 
-void flush_log(ICECAdapter *cecParser)
+void FlushLog(ICECAdapter *cecParser)
 {
   cec_log_message message;
   while (cecParser && cecParser->GetNextLogMessage(&message))
@@ -149,7 +155,7 @@ void flush_log(ICECAdapter *cecParser)
   }
 }
 
-void list_devices(ICECAdapter *parser)
+void ListDevices(ICECAdapter *parser)
 {
   cec_adapter *devices = new cec_adapter[10];
   uint8_t iDevicesFound = parser->FindAdapters(devices, 10, NULL);
@@ -171,7 +177,7 @@ void list_devices(ICECAdapter *parser)
   }
 }
 
-void show_help(const char* strExec)
+void ShowHelpCommandLine(const char* strExec)
 {
   cout << endl <<
       strExec << " {-h|--help|-l|--list-devices|[COM PORT]}" << endl <<
@@ -180,10 +186,15 @@ void show_help(const char* strExec)
       "  -h --help                   Shows this help text" << endl <<
       "  -l --list-devices           List all devices on this system" << endl <<
       "  -t --type {p|r|t|a}         The device type to use. More than one is possible." << endl <<
+      "  -p --port {int}             The HDMI port to use as active source." << endl <<
+      "  -b --base {int}             The logical address of the device to with this " << endl <<
+      "                              adapter is connected." << endl <<
       "  -f --log-file {file}        Writes all libCEC log message to a file" << endl <<
       "  -sf --short-log-file {file} Writes all libCEC log message without timestamps" << endl <<
       "                              and log levels to a file." << endl <<
       "  -d --log-level {level}      Sets the log level. See cectypes.h for values." << endl <<
+      "  -s --single-command         Execute a single command and exit. Does not power" << endl <<
+      "                              on devices on startup and power them off on exit." << endl <<
       "  [COM PORT]                  The com port to connect to. If no COM" << endl <<
       "                              port is given, the client tries to connect to the" << endl <<
       "                              first device that is detected." << endl <<
@@ -192,7 +203,7 @@ void show_help(const char* strExec)
       "available commands" << endl;
 }
 
-ICECAdapter *create_parser(cec_device_type_list typeList)
+ICECAdapter *CreateParser(cec_device_type_list typeList)
 {
   ICECAdapter *parser = LibCecInit("CECTester", typeList);
   if (!parser || parser->GetMinLibVersion() > CEC_TEST_CLIENT_VERSION)
@@ -212,46 +223,34 @@ ICECAdapter *create_parser(cec_device_type_list typeList)
   return parser;
 }
 
-void show_console_help(void)
+void ShowHelpConsole(void)
 {
   cout << endl <<
   "================================================================================" << endl <<
   "Available commands:" << endl <<
   endl <<
-  "tx {bytes}                transfer bytes over the CEC line." << endl <<
-  "txn {bytes}               transfer bytes but don't wait for transmission ACK." << endl <<
-  "[tx 40 00 FF 11 22 33]    sends bytes 0x40 0x00 0xFF 0x11 0x22 0x33" << endl <<
-  endl <<
-  "on {address}              power on the device with the given logical address." << endl <<
-  "[on 5]                    power on a connected audio system" << endl <<
-  endl <<
-  "standby {address}         put the device with the given address in standby mode." << endl <<
-  "[standby 0]               powers off the TV" << endl <<
-  endl <<
-  "la {logical_address}      change the logical address of the CEC adapter." << endl <<
-  "[la 4]                    logical address 4" << endl <<
-  endl <<
-  "pa {physical_address}     change the physical address of the CEC adapter." << endl <<
-  "[pa 10 00]                physical address 1.0.0.0" << endl <<
-  endl <<
-  "osd {addr} {string}       set OSD message on the specified device." << endl <<
-  "[osd 0 Test Message]      displays 'Test Message' on the TV" << endl <<
-  endl <<
-  "ver {addr}                get the CEC version of the specified device." << endl <<
-  "[ver 0]                   get the CEC version of the TV" << endl <<
-  endl <<
-  "ven {addr}                get the vendor ID of the specified device." << endl <<
-  "[ven 0]                   get the vendor ID of the TV" << endl <<
-  endl <<
-  "lang {addr}               get the menu language of the specified device." << endl <<
-  "[lang 0]                  get the menu language of the TV" << endl <<
-  endl <<
-  "pow {addr}                get the power status of the specified device." << endl <<
-  "[pow 0]                   get the power status of the TV" << endl <<
-  endl <<
-  "poll {addr}               poll the specified device." << endl <<
-  "[poll 0]                  sends a poll message to the TV" << endl <<
-  endl <<
+  "[tx] {bytes}              transfer bytes over the CEC line." << endl <<
+  "[txn] {bytes}             transfer bytes but don't wait for transmission ACK." << endl <<
+  "[on] {address}            power on the device with the given logical address." << endl <<
+  "[standby] {address}       put the device with the given address in standby mode." << endl <<
+  "[la] {logical address}    change the logical address of the CEC adapter." << endl <<
+  "[p] {device} {port}       change the HDMI port number of the CEC adapter." << endl <<
+  "[pa] {physical address}   change the physical address of the CEC adapter." << endl <<
+  "[as]                      make the CEC adapter the active source." << endl <<
+  "[osd] {addr} {string}     set OSD message on the specified device." << endl <<
+  "[ver] {addr}              get the CEC version of the specified device." << endl <<
+  "[ven] {addr}              get the vendor ID of the specified device." << endl <<
+  "[lang] {addr}             get the menu language of the specified device." << endl <<
+  "[pow] {addr}              get the power status of the specified device." << endl <<
+  "[name] {addr}             get the OSD name of the specified device." << endl <<
+  "[poll] {addr}             poll the specified device." << endl <<
+  "[lad]                     lists active devices on the bus" << endl <<
+  "[ad] {addr}               checks whether the specified device is active." << endl <<
+  "[at] {type}               checks whether the specified device type is active." << endl <<
+  "[volup]                   send a volume up command to the amp if present" << endl <<
+  "[voldown]                 send a volume down command to the amp if present" << endl <<
+  "[mute]                    send a mute/unmute command to the amp if present" << endl <<
+  "[scan]                    scan the CEC bus and display device info" << endl <<
   "[mon] {1|0}               enable or disable CEC bus monitoring." << endl <<
   "[log] {1 - 31}            change the log level. see cectypes.h for values." << endl <<
   "[ping]                    send a ping command to the CEC adapter." << endl <<
@@ -264,13 +263,556 @@ void show_console_help(void)
   "================================================================================" << endl;
 }
 
-int main (int argc, char *argv[])
+bool ProcessCommandTX(ICECAdapter *parser, const string &command, string &arguments)
+{
+  if (command == "tx" || command == "txn")
+  {
+    string strvalue;
+    uint8_t ivalue;
+    cec_command bytes;
+    bytes.Clear();
+
+    while (GetWord(arguments, strvalue) && HexStrToInt(strvalue, ivalue))
+      bytes.PushBack(ivalue);
+
+    if (command == "txn")
+      bytes.transmit_timeout = 0;
+
+    parser->Transmit(bytes);
+
+    return true;
+  }
+
+  return false;
+}
+
+bool ProcessCommandON(ICECAdapter *parser, const string &command, string &arguments)
+{
+  if (command == "on")
+  {
+    string strValue;
+    uint8_t iValue = 0;
+    if (GetWord(arguments, strValue) && HexStrToInt(strValue, iValue) && iValue <= 0xF)
+    {
+      parser->PowerOnDevices((cec_logical_address) iValue);
+      return true;
+    }
+    else
+    {
+      cout << "invalid destination" << endl;
+    }
+  }
+
+  return false;
+}
+
+bool ProcessCommandSTANDBY(ICECAdapter *parser, const string &command, string &arguments)
+{
+  if (command == "standby")
+  {
+    string strValue;
+    uint8_t iValue = 0;
+    if (GetWord(arguments, strValue) && HexStrToInt(strValue, iValue) && iValue <= 0xF)
+    {
+      parser->StandbyDevices((cec_logical_address) iValue);
+      return true;
+    }
+    else
+    {
+      cout << "invalid destination" << endl;
+    }
+  }
+
+  return false;
+}
+
+bool ProcessCommandPOLL(ICECAdapter *parser, const string &command, string &arguments)
+{
+  if (command == "poll")
+  {
+    string strValue;
+    uint8_t iValue = 0;
+    if (GetWord(arguments, strValue) && HexStrToInt(strValue, iValue) && iValue <= 0xF)
+    {
+      if (parser->PollDevice((cec_logical_address) iValue))
+        cout << "POLL message sent" << endl;
+      else
+        cout << "POLL message not sent" << endl;
+      return true;
+    }
+    else
+    {
+      cout << "invalid destination" << endl;
+    }
+  }
+
+  return false;
+}
+
+bool ProcessCommandLA(ICECAdapter *parser, const string &command, string &arguments)
+{
+  if (command == "la")
+  {
+    string strvalue;
+    if (GetWord(arguments, strvalue))
+    {
+      parser->SetLogicalAddress((cec_logical_address) atoi(strvalue.c_str()));
+      return true;
+    }
+  }
+
+  return false;
+}
+
+bool ProcessCommandP(ICECAdapter *parser, const string &command, string &arguments)
+{
+  if (command == "p")
+  {
+    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 string &command, string &arguments)
+{
+  if (command == "pa")
+  {
+    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 string &command, string &arguments)
+{
+  if (command == "osd")
+  {
+    bool bFirstWord(false);
+    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 string &command, string &arguments)
+{
+  if (command == "as")
+  {
+    parser->SetActiveView();
+    return true;
+  }
+
+  return false;
+}
+
+
+bool ProcessCommandPING(ICECAdapter *parser, const string &command, string &arguments)
+{
+  if (command == "ping")
+  {
+    parser->PingAdapter();
+    return true;
+  }
+
+  return false;
+}
+
+bool ProcessCommandVOLUP(ICECAdapter *parser, const string &command, string &arguments)
+{
+  if (command == "volup")
+  {
+    CStdString strLog;
+    strLog.Format("volume up: %2X", parser->VolumeUp());
+    cout << strLog.c_str() << endl;
+    return true;
+  }
+
+  return false;
+}
+
+bool ProcessCommandVOLDOWN(ICECAdapter *parser, const string &command, string &arguments)
+{
+  if (command == "voldown")
+  {
+    CStdString strLog;
+    strLog.Format("volume up: %2X", parser->VolumeDown());
+    cout << strLog.c_str() << endl;
+    return true;
+  }
+
+  return false;
+}
+
+bool ProcessCommandMUTE(ICECAdapter *parser, const string &command, string &arguments)
+{
+  if (command == "mute")
+  {
+    CStdString strLog;
+    strLog.Format("mute: %2X", parser->MuteAudio());
+    cout << strLog.c_str() << endl;
+    return true;
+  }
+
+  return false;
+}
+
+bool ProcessCommandMON(ICECAdapter *parser, const string &command, string &arguments)
+{
+  if (command == "mon")
+  {
+    CStdString strEnable;
+    if (GetWord(arguments, strEnable) && (strEnable.Equals("0") || strEnable.Equals("1")))
+    {
+      parser->SwitchMonitoring(strEnable.Equals("1"));
+      return true;
+    }
+  }
+
+  return false;
+}
+
+bool ProcessCommandBL(ICECAdapter *parser, const string &command, string &arguments)
 {
-  cec_device_type_list typeList;
-  typeList.clear();
+  if (command == "bl")
+  {
+    parser->StartBootloader();
+    return true;
+  }
+
+  return false;
+}
+
+bool ProcessCommandLANG(ICECAdapter *parser, const string &command, string &arguments)
+{
+  if (command == "lang")
+  {
+    CStdString strDev;
+    if (GetWord(arguments, strDev))
+    {
+      int iDev = atoi(strDev);
+      if (iDev >= 0 && iDev < 15)
+      {
+        CStdString strLog;
+        cec_menu_language language;
+        if (parser->GetDeviceMenuLanguage((cec_logical_address) iDev, &language))
+          strLog.Format("menu language '%s'", language.language);
+        else
+          strLog = "failed!";
+        cout << strLog.c_str() << endl;
+        return true;
+      }
+    }
+  }
+
+  return false;
+}
+
+bool ProcessCommandVEN(ICECAdapter *parser, const string &command, string &arguments)
+{
+  if (command == "ven")
+  {
+    CStdString strDev;
+    if (GetWord(arguments, strDev))
+    {
+      int iDev = atoi(strDev);
+      if (iDev >= 0 && iDev < 15)
+      {
+        uint64_t iVendor = parser->GetDeviceVendorId((cec_logical_address) iDev);
+        CStdString strLog;
+        strLog.Format("vendor id: %06x", iVendor);
+        cout << strLog.c_str() << endl;
+        return true;
+      }
+    }
+  }
+
+  return false;
+}
+
+bool ProcessCommandVER(ICECAdapter *parser, const string &command, string &arguments)
+{
+  if (command == "ver")
+  {
+    CStdString strDev;
+    if (GetWord(arguments, strDev))
+    {
+      int iDev = atoi(strDev);
+      if (iDev >= 0 && iDev < 15)
+      {
+        cec_version iVersion = parser->GetDeviceCecVersion((cec_logical_address) iDev);
+        cout << "CEC version " << parser->ToString(iVersion) << endl;
+        return true;
+      }
+    }
+  }
+
+  return false;
+}
+
+bool ProcessCommandPOW(ICECAdapter *parser, const string &command, string &arguments)
+{
+  if (command == "pow")
+  {
+    CStdString strDev;
+    if (GetWord(arguments, strDev))
+    {
+      int iDev = atoi(strDev);
+      if (iDev >= 0 && iDev < 15)
+      {
+        cec_power_status iPower = parser->GetDevicePowerStatus((cec_logical_address) iDev);
+        cout << "power status: " << parser->ToString(iPower) << endl;
+
+        return true;
+      }
+    }
+  }
+
+  return false;
+}
 
+bool ProcessCommandNAME(ICECAdapter *parser, const string &command, string &arguments)
+{
+  if (command == "name")
+  {
+    CStdString strDev;
+    if (GetWord(arguments, strDev))
+    {
+      int iDev = atoi(strDev);
+      if (iDev >= 0 && iDev < 15)
+      {
+        cec_osd_name name = parser->GetDeviceOSDName((cec_logical_address)iDev);
+        cout << "OSD name of device " << iDev << " is '" << name.name << "'" << endl;
+      }
+      return true;
+    }
+  }
+
+  return false;
+}
+
+bool ProcessCommandLAD(ICECAdapter *parser, const string &command, string &arguments)
+{
+  if (command == "lad")
+  {
+    cout << "listing active devices:" << endl;
+    cec_logical_addresses addresses = parser->GetActiveDevices();
+    for (uint8_t iPtr = 0; iPtr <= 11; iPtr++)
+      if (addresses[iPtr])
+        cout << "logical address " << (int)iPtr << endl;
+    return true;
+  }
+
+  return false;
+}
+
+bool ProcessCommandAD(ICECAdapter *parser, const string &command, string &arguments)
+{
+  if (command == "ad")
+  {
+    CStdString strDev;
+    if (GetWord(arguments, strDev))
+    {
+      int iDev = atoi(strDev);
+      if (iDev >= 0 && iDev < 15)
+        cout << "logical address " << iDev << " is " << (parser->IsActiveDevice((cec_logical_address)iDev) ? "active" : "not active") << endl;
+    }
+  }
+
+  return false;
+}
+
+bool ProcessCommandAT(ICECAdapter *parser, const string &command, string &arguments)
+{
+  if (command == "at")
+  {
+    CStdString strType;
+    if (GetWord(arguments, strType))
+    {
+      cec_device_type type = CEC_DEVICE_TYPE_TV;
+      if (strType.Equals("a"))
+        type = CEC_DEVICE_TYPE_AUDIO_SYSTEM;
+      else if (strType.Equals("p"))
+        type = CEC_DEVICE_TYPE_PLAYBACK_DEVICE;
+      else if (strType.Equals("r"))
+        type = CEC_DEVICE_TYPE_RECORDING_DEVICE;
+      else if (strType.Equals("t"))
+        type = CEC_DEVICE_TYPE_TUNER;
+      cout << "device " << type << " is " << (parser->IsActiveDeviceType(type) ? "active" : "not active") << endl;
+      return true;
+    }
+  }
+
+  return false;
+}
+
+bool ProcessCommandR(ICECAdapter *parser, const string &command, string &arguments)
+{
+  if (command == "r")
+  {
+    cout << "closing the connection" << endl;
+    parser->Close();
+    FlushLog(parser);
+
+    cout << "opening a new connection" << endl;
+    parser->Open(g_strPort.c_str());
+    FlushLog(parser);
+
+    cout << "setting active source" << endl;
+    parser->SetActiveSource();
+    return true;
+  }
+
+  return false;
+}
+
+bool ProcessCommandH(ICECAdapter *parser, const string &command, string &arguments)
+{
+  if (command == "h" || command == "help")
+  {
+    ShowHelpConsole();
+    return true;
+  }
+
+  return false;
+}
+
+bool ProcessCommandLOG(ICECAdapter *parser, const string &command, string &arguments)
+{
+  if (command == "log")
+  {
+    CStdString strLevel;
+    if (GetWord(arguments, strLevel))
+    {
+      int iNewLevel = atoi(strLevel);
+      if (iNewLevel >= CEC_LOG_ERROR && iNewLevel <= CEC_LOG_ALL)
+      {
+        g_cecLogLevel = iNewLevel;
+        cout << "log level changed to " << strLevel.c_str() << endl;
+        return true;
+      }
+    }
+  }
+
+  return false;
+}
+
+bool ProcessCommandSCAN(ICECAdapter *parser, const string &command, string &arguments)
+{
+  if (command == "scan")
+  {
+    cout << "CEC bus information" << endl;
+    cout << "===================" << endl;
+    cec_logical_addresses addresses = parser->GetActiveDevices();
+    for (uint8_t iPtr = 0; iPtr < 16; iPtr++)
+    {
+      if (addresses[iPtr])
+      {
+        uint64_t iVendorId        = parser->GetDeviceVendorId((cec_logical_address)iPtr);
+        bool     bActive          = parser->IsActiveSource((cec_logical_address)iPtr);
+        uint16_t iPhysicalAddress = parser->GetDevicePhysicalAddress((cec_logical_address)iPtr);
+        cec_version iCecVersion   = parser->GetDeviceCecVersion((cec_logical_address)iPtr);
+        cec_power_status power    = parser->GetDevicePowerStatus((cec_logical_address)iPtr);
+        cec_osd_name osdName      = parser->GetDeviceOSDName((cec_logical_address)iPtr);
+        CStdString strAddr;
+        strAddr.Format("%04x", iPhysicalAddress);
+        cec_menu_language lang;
+        lang.device = CECDEVICE_UNKNOWN;
+        parser->GetDeviceMenuLanguage((cec_logical_address)iPtr, &lang);
+
+        cout << "device #" << (int)iPtr << ": " << parser->ToString((cec_logical_address)iPtr) << endl;
+        cout << "address:       " << strAddr.c_str() << endl;
+        cout << "active source: " << (bActive ? "yes" : "no") << endl;
+        cout << "vendor:        " << parser->ToString((cec_vendor_id)iVendorId) << endl;
+        cout << "osd string:    " << osdName.name << endl;
+        cout << "CEC version:   " << parser->ToString(iCecVersion) << endl;
+        cout << "power status:  " << parser->ToString(power) << endl;
+        if ((uint8_t)lang.device == iPtr)
+          cout << "language:      " << lang.language << endl;
+        cout << endl;
+      }
+    }
+    return true;
+  }
+
+  return false;
+}
+
+bool ProcessConsoleCommand(ICECAdapter *parser, string &input)
+{
+  if (!input.empty())
+  {
+    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) ||
+      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);
+    }
+  }
+  return true;
+}
+
+bool ProcessCommandLineArguments(int argc, char *argv[])
+{
+  bool bReturn(true);
   int iArgPtr = 1;
-  while (iArgPtr < argc)
+  while (iArgPtr < argc && bReturn)
   {
     if (argc >= iArgPtr + 1)
     {
@@ -300,7 +842,8 @@ int main (int argc, char *argv[])
           if (iNewLevel >= CEC_LOG_ERROR && iNewLevel <= CEC_LOG_ALL)
           {
             g_cecLogLevel = iNewLevel;
-            cout << "log level set to " << argv[iArgPtr + 1] << endl;
+            if (!g_bSingleCommand)
+              cout << "log level set to " << argv[iArgPtr + 1] << endl;
           }
           else
           {
@@ -321,23 +864,27 @@ int main (int argc, char *argv[])
         {
           if (!strcmp(argv[iArgPtr + 1], "p"))
           {
-            cout << "== using device type 'playback device'" << endl;
-            typeList.add(CEC_DEVICE_TYPE_PLAYBACK_DEVICE);
+            if (!g_bSingleCommand)
+              cout << "== using device type 'playback device'" << endl;
+            g_typeList.add(CEC_DEVICE_TYPE_PLAYBACK_DEVICE);
           }
           else if (!strcmp(argv[iArgPtr + 1], "r"))
           {
-            cout << "== using device type 'recording device'" << endl;
-            typeList.add(CEC_DEVICE_TYPE_RECORDING_DEVICE);
+            if (!g_bSingleCommand)
+              cout << "== using device type 'recording device'" << endl;
+            g_typeList.add(CEC_DEVICE_TYPE_RECORDING_DEVICE);
           }
           else if (!strcmp(argv[iArgPtr + 1], "t"))
           {
-            cout << "== using device type 'tuner'" << endl;
-            typeList.add(CEC_DEVICE_TYPE_TUNER);
+            if (!g_bSingleCommand)
+              cout << "== using device type 'tuner'" << endl;
+            g_typeList.add(CEC_DEVICE_TYPE_TUNER);
           }
           else if (!strcmp(argv[iArgPtr + 1], "a"))
           {
-            cout << "== using device type 'audio system'" << endl;
-            typeList.add(CEC_DEVICE_TYPE_AUDIO_SYSTEM);
+            if (!g_bSingleCommand)
+              cout << "== using device type 'audio system'" << endl;
+            g_typeList.add(CEC_DEVICE_TYPE_AUDIO_SYSTEM);
           }
           else
           {
@@ -350,20 +897,49 @@ int main (int argc, char *argv[])
       else if (!strcmp(argv[iArgPtr], "--list-devices") ||
                !strcmp(argv[iArgPtr], "-l"))
       {
-        ICECAdapter *parser = create_parser(typeList);
+        ICECAdapter *parser = CreateParser(g_typeList);
         if (parser)
         {
-          list_devices(parser);
+          ListDevices(parser);
           UnloadLibCec(parser);
+          parser = NULL;
         }
-        return 0;
+        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"))
       {
-        show_help(argv[0]);
+        ShowHelpCommandLine(argv[0]);
         return 0;
       }
+      else if (!strcmp(argv[iArgPtr], "-b") ||
+               !strcmp(argv[iArgPtr], "--base"))
+      {
+        if (argc >= iArgPtr + 2)
+        {
+          g_iBaseDevice = (cec_logical_address)atoi(argv[iArgPtr + 1]);
+          cout << "using base device '" << (int)g_iBaseDevice << "'" << endl;
+          ++iArgPtr;
+        }
+        ++iArgPtr;
+      }
+      else if (!strcmp(argv[iArgPtr], "-p") ||
+               !strcmp(argv[iArgPtr], "--port"))
+      {
+        if (argc >= iArgPtr + 2)
+        {
+          g_iHDMIPort = (int8_t)atoi(argv[iArgPtr + 1]);
+          cout << "using HDMI port '" << (int)g_iHDMIPort << "'" << endl;
+          ++iArgPtr;
+        }
+        ++iArgPtr;
+      }
       else
       {
         g_strPort = argv[iArgPtr++];
@@ -371,13 +947,24 @@ int main (int argc, char *argv[])
     }
   }
 
-  if (typeList.empty())
+  return bReturn;
+}
+
+int main (int argc, char *argv[])
+{
+  g_typeList.clear();
+
+  if (!ProcessCommandLineArguments(argc, argv))
+    return 0;
+
+  if (g_typeList.IsEmpty())
   {
-    cout << "No device type given. Using 'playback device'" << endl;
-    typeList.add(CEC_DEVICE_TYPE_PLAYBACK_DEVICE);
+    if (!g_bSingleCommand)
+      cout << "No device type given. Using 'recording device'" << endl;
+    g_typeList.add(CEC_DEVICE_TYPE_RECORDING_DEVICE);
   }
 
-  ICECAdapter *parser = LibCecInit("CECTester", typeList);
+  ICECAdapter *parser = LibCecInit("CECTester", g_typeList);
   if (!parser || parser->GetMinLibVersion() > CEC_TEST_CLIENT_VERSION)
   {
 #ifdef __WINDOWS__
@@ -387,57 +974,75 @@ int main (int argc, char *argv[])
 #endif
     return 1;
   }
-  CStdString strLog;
-  strLog.Format("CEC Parser created - libcec version %d.%d", parser->GetLibVersionMajor(), parser->GetLibVersionMinor());
-  cout << strLog.c_str() << 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_bSingleCommand)
+  {
+    CStdString strLog;
+    strLog.Format("CEC Parser created - libcec version %d.%d", parser->GetLibVersionMajor(), parser->GetLibVersionMinor());
+    cout << strLog.c_str() << 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.IsEmpty())
   {
-    cout << "no serial port given. trying autodetect: ";
+    if (!g_bSingleCommand)
+      cout << "no serial port given. trying autodetect: ";
     cec_adapter devices[10];
     uint8_t iDevicesFound = parser->FindAdapters(devices, 10, NULL);
     if (iDevicesFound <= 0)
     {
+      if (g_bSingleCommand)
+        cout << "autodetect ";
       cout << "FAILED" << endl;
       UnloadLibCec(parser);
       return 1;
     }
     else
     {
-      cout << endl << " path:     " << devices[0].path << endl <<
-          " com port: " << devices[0].comm << endl << endl;
+      if (!g_bSingleCommand)
+      {
+        cout << endl << " path:     " << devices[0].path << endl <<
+            " com port: " << devices[0].comm << endl << endl;
+      }
       g_strPort = devices[0].comm;
     }
   }
 
+  parser->SetHDMIPort(g_iBaseDevice, g_iHDMIPort);
+  cout << "opening a connection to the CEC adapter..." << endl;
+
   if (!parser->Open(g_strPort.c_str()))
   {
     cout << "unable to open the device on port " << g_strPort << endl;
-    flush_log(parser);
+    FlushLog(parser);
     UnloadLibCec(parser);
     return 1;
   }
 
-  cout << "cec device opened" << endl;
+  if (!g_bSingleCommand)
+  {
+    FlushLog(parser);
+    cout << "cec device opened" << endl;
+
+    parser->PowerOnDevices(CECDEVICE_TV);
+    FlushLog(parser);
 
-  parser->PowerOnDevices(CECDEVICE_TV);
-  flush_log(parser);
+    parser->SetActiveSource();
+    FlushLog(parser);
 
-  parser->SetActiveSource();
-  flush_log(parser);
+    cout << "waiting for input" << endl;
+  }
 
   bool bContinue(true);
-  cout << "waiting for input" << endl;
   while (bContinue)
   {
-    flush_log(parser);
+    FlushLog(parser);
 
     /* just ignore the command buffer and clear it */
     cec_command dummy;
@@ -447,259 +1052,23 @@ int main (int argc, char *argv[])
     getline(cin, input);
     cin.clear();
 
-    if (!input.empty())
+    if (ProcessConsoleCommand(parser, input) && !g_bSingleCommand)
     {
-      string command;
-      if (GetWord(input, command))
-      {
-        if (command == "tx" || command == "txn")
-        {
-          string strvalue;
-          uint8_t ivalue;
-          cec_command bytes;
-          bytes.clear();
-
-          while (GetWord(input, strvalue) && HexStrToInt(strvalue, ivalue))
-            bytes.push_back(ivalue);
-
-          if (command == "txn")
-            bytes.transmit_timeout = 0;
-
-          parser->Transmit(bytes);
-        }
-        else if (command == "on")
-        {
-          string strValue;
-          uint8_t iValue = 0;
-          if (GetWord(input, strValue) && HexStrToInt(strValue, iValue) && iValue <= 0xF)
-          {
-            parser->PowerOnDevices((cec_logical_address) iValue);
-          }
-          else
-          {
-            cout << "invalid destination" << endl;
-          }
-        }
-        else if (command == "standby")
-        {
-          string strValue;
-          uint8_t iValue = 0;
-          if (GetWord(input, strValue) && HexStrToInt(strValue, iValue) && iValue <= 0xF)
-          {
-            parser->StandbyDevices((cec_logical_address) iValue);
-          }
-          else
-          {
-            cout << "invalid destination" << endl;
-          }
-        }
-        else if (command == "poll")
-        {
-          string strValue;
-          uint8_t iValue = 0;
-          if (GetWord(input, strValue) && HexStrToInt(strValue, iValue) && iValue <= 0xF)
-          {
-            if (parser->PollDevice((cec_logical_address) iValue))
-              cout << "POLL message sent" << endl;
-            else
-              cout << "POLL message not sent" << endl;
-          }
-          else
-          {
-            cout << "invalid destination" << endl;
-          }
-        }
-        else if (command == "la")
-        {
-          string strvalue;
-          if (GetWord(input, strvalue))
-          {
-            parser->SetLogicalAddress((cec_logical_address) atoi(strvalue.c_str()));
-          }
-        }
-        else if (command == "pa")
-        {
-          string strB1, strB2;
-          uint8_t iB1, iB2;
-          if (GetWord(input, strB1) && HexStrToInt(strB1, iB1) &&
-              GetWord(input, strB2) && HexStrToInt(strB2, iB2))
-          {
-            uint16_t iPhysicalAddress = ((uint16_t)iB1 << 8) + iB2;
-            parser->SetPhysicalAddress(iPhysicalAddress);
-          }
-        }
-        else if (command == "osd")
-        {
-          bool bFirstWord(false);
-          string strAddr, strMessage, strWord;
-          uint8_t iAddr;
-          if (GetWord(input, strAddr) && HexStrToInt(strAddr, iAddr) && iAddr < 0xF)
-          {
-            while (GetWord(input, 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());
-          }
-        }
-        else if (command == "ping")
-        {
-          parser->PingAdapter();
-        }
-        else if (command == "mon")
-        {
-          CStdString strEnable;
-          if (GetWord(input, strEnable) && (strEnable.Equals("0") || strEnable.Equals("1")))
-          {
-            parser->SwitchMonitoring(strEnable.Equals("1"));
-          }
-        }
-        else if (command == "bl")
-        {
-          parser->StartBootloader();
-        }
-        else if (command == "lang")
-        {
-          CStdString strDev;
-          if (GetWord(input, strDev))
-          {
-            int iDev = atoi(strDev);
-            if (iDev >= 0 && iDev < 15)
-            {
-              CStdString strLog;
-              cec_menu_language language;
-              if (parser->GetDeviceMenuLanguage((cec_logical_address) iDev, &language))
-                strLog.Format("menu language '%s'", language.language);
-              else
-                strLog = "failed!";
-              cout << strLog.c_str() << endl;
-            }
-          }
-        }
-        else if (command == "ven")
-        {
-          CStdString strDev;
-          if (GetWord(input, strDev))
-          {
-            int iDev = atoi(strDev);
-            if (iDev >= 0 && iDev < 15)
-            {
-              uint64_t iVendor = parser->GetDeviceVendorId((cec_logical_address) iDev);
-              CStdString strLog;
-              strLog.Format("vendor id: %06x", iVendor);
-              cout << strLog.c_str() << endl;
-            }
-          }
-        }
-        else if (command == "ver")
-        {
-          CStdString strDev;
-          if (GetWord(input, strDev))
-          {
-            int iDev = atoi(strDev);
-            if (iDev >= 0 && iDev < 15)
-            {
-              cec_version iVersion = parser->GetDeviceCecVersion((cec_logical_address) iDev);
-              switch (iVersion)
-              {
-              case CEC_VERSION_1_2:
-                cout << "CEC version 1.2" << endl;
-                break;
-              case CEC_VERSION_1_2A:
-                cout << "CEC version 1.2a" << endl;
-                break;
-              case CEC_VERSION_1_3:
-                cout << "CEC version 1.3" << endl;
-                break;
-              case CEC_VERSION_1_3A:
-                cout << "CEC version 1.3a" << endl;
-                break;
-              default:
-                cout << "unknown CEC version" << endl;
-                break;
-              }
-            }
-          }
-        }
-        else if (command == "pow")
-        {
-          CStdString strDev;
-          if (GetWord(input, strDev))
-          {
-            int iDev = atoi(strDev);
-            if (iDev >= 0 && iDev < 15)
-            {
-              cec_power_status iPower = parser->GetDevicePowerStatus((cec_logical_address) iDev);
-              switch (iPower)
-              {
-              case CEC_POWER_STATUS_ON:
-                cout << "powered on" << endl;
-                break;
-              case CEC_POWER_STATUS_IN_TRANSITION_ON_TO_STANDBY:
-                cout << "on -> standby" << endl;
-                break;
-              case CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON:
-                cout << "standby -> on" << endl;
-                break;
-              case CEC_POWER_STATUS_STANDBY:
-                cout << "standby" << endl;
-                break;
-              default:
-                cout << "unknown power status" << endl;
-                break;
-              }
-            }
-          }
-        }
-        else if (command == "r")
-        {
-          cout << "closing the connection" << endl;
-          parser->Close();
-          flush_log(parser);
-
-          cout << "opening a new connection" << endl;
-          parser->Open(g_strPort.c_str());
-          flush_log(parser);
-
-          cout << "setting active source" << endl;
-          parser->SetActiveSource();
-        }
-        else if (command == "h" || command == "help")
-        {
-          show_console_help();
-        }
-        else if (command == "q" || command == "quit")
-        {
-          bContinue = false;
-        }
-        else if (command == "log")
-        {
-          CStdString strLevel;
-          if (GetWord(input, strLevel))
-          {
-            int iNewLevel = atoi(strLevel);
-            if (iNewLevel >= CEC_LOG_ERROR && iNewLevel <= CEC_LOG_ALL)
-            {
-              g_cecLogLevel = iNewLevel;
-              cout << "log level changed to " << strLevel.c_str() << endl;
-            }
-          }
-        }
-      }
-      if (bContinue)
+      if (!input.empty())
         cout << "waiting for input" << endl;
     }
-    CCondition::Sleep(50);
+    else
+      bContinue = false;
+
+    if (bContinue)
+      CCondition::Sleep(50);
   }
 
-  parser->StandbyDevices(CECDEVICE_BROADCAST);
+  if (!g_bSingleCommand)
+    parser->StandbyDevices(CECDEVICE_BROADCAST);
+
   parser->Close();
-  flush_log(parser);
+  FlushLog(parser);
   UnloadLibCec(parser);
 
   if (g_logOutput.is_open())