Release 2.1.4: merge remote-tracking branch 'origin/master' into release
authorLars Op den Kamp <lars@opdenkamp.eu>
Fri, 13 Dec 2013 18:58:56 +0000 (19:58 +0100)
committerLars Op den Kamp <lars@opdenkamp.eu>
Fri, 13 Dec 2013 18:59:07 +0000 (19:59 +0100)
46 files changed:
ChangeLog
configure.ac
debian/changelog
include/cectypes.h
project/LibCecSharp/LibCecSharp.rc
project/libcec/libcec.rc
project/libcec/libcec.vcxproj
project/libcec/libcec.vcxproj.filters
project/testclient/resource.h
project/testclient/testclient.rc
project/testclient/testclient.vcxproj
src/CecSharpTester/Properties/AssemblyInfo.cs
src/LibCecSharp/AssemblyInfo.cpp
src/LibCecSharp/CecSharpTypes.h
src/LibCecTray/LibCECTray.csproj
src/LibCecTray/Properties/AssemblyInfo.cs
src/LibCecTray/controller/Actions.cs
src/LibCecTray/controller/actions/ActivateSource.cs [new file with mode: 0644]
src/LibCecTray/controller/actions/ConnectToDevice.cs
src/LibCecTray/ui/CECTray.cs
src/LibCecTray/ui/DeviceInformation.cs
src/lib/CECClient.cpp
src/lib/CECProcessor.cpp
src/lib/CECProcessor.h
src/lib/CECTypeUtils.h
src/lib/Makefile.am
src/lib/adapter/Pulse-Eight/USBCECAdapterCommands.cpp
src/lib/adapter/Pulse-Eight/USBCECAdapterCommunication.cpp
src/lib/adapter/Pulse-Eight/USBCECAdapterCommunication.h
src/lib/adapter/Pulse-Eight/USBCECAdapterDetection.cpp
src/lib/devices/CECBusDevice.cpp
src/lib/devices/CECBusDevice.h
src/lib/implementations/ANCommandHandler.cpp
src/lib/implementations/ANCommandHandler.h
src/lib/implementations/AQCommandHandler.cpp [new file with mode: 0644]
src/lib/implementations/AQCommandHandler.h [new file with mode: 0644]
src/lib/implementations/CECCommandHandler.cpp
src/lib/implementations/CECCommandHandler.h
src/lib/implementations/PHCommandHandler.cpp
src/lib/implementations/PHCommandHandler.h
src/lib/implementations/RHCommandHandler.cpp [new file with mode: 0644]
src/lib/implementations/RHCommandHandler.h [new file with mode: 0644]
src/lib/implementations/SLCommandHandler.cpp
src/lib/implementations/SLCommandHandler.h
src/lib/implementations/VLCommandHandler.cpp
src/testclient/main.cpp

index 0a17f5e052fba8c72d81d8576e5b8d813eeb94c7..2ec6ebb6e35edf808501541365d6282fd00da949 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,60 @@
+libcec (2.1.4-1) unstable; urgency=low
+
+  * changed / added:
+    * set the vendor id of devices handled by libCEC to our vendor id
+    * added protection against standby without a notification from XBMC and
+      clock changes. issue #186
+    * update system audio mode when audio system devices are activated
+    * added vendor id and name 'Harman/Kardon'
+    * added vendor id and name 'Marantz'
+    * cec-tray: support for away mode
+    * cec-tray: support for screensaver events
+  * fixed:
+    * fixed potential crash when SendCommand returns NULL
+    * fixed crash when CCECProcessor::Transmit was called after
+      CCECProcessor::Close
+    * always call the SourceActivated() callback in
+      CCECBusDevice::MarkAsActiveSource(), even when we were already active,
+      and let clients handle dupes. this prevented the screensaver from
+      being cancelled in XBMC
+    * send our vendor id when the tv sends it's vendor id
+    * transmit our physical address when the TV sends it's physical address
+    * potential deadlock
+    * leak on exit in CWaitForResponse::Clear()
+    * also transmit an active source message as response to a set stream path
+      command when we were already marked as active. bugzid: 3116
+    * only send an active source message when receiving a routing change to an
+      address handled by libCEC. issue #56
+    * HandleVendorRemoteButtonUp -> HandleUserControlRelease for all vendors
+    * silence warning for xx:a0:00:09:b0:00:80:20. bugzid: 2559
+    * fixed comboKeyTimeout=0. closes #168
+    * Panasonic: doesn't request the active source status when powered up, but
+      it does send a vendor command. send an active source message when we're
+      marked as active source after receiving this command. issue #192
+    * possible crash when the tv does not respond to polls and the client isn't
+      registered yet. don't poll the tv in monitoring mode. closes #163
+    * Panasonic: standby command
+    * Panasonic: silence 'unmapped code' warning. bugzid: 2375
+    * LG: clean up and attempt to fix issue #176
+    * LG: newer firmwares don't send a second power status request after it's
+      been requested once and replied with 'standby -> on' like previous
+      versions. send an active source message in an attempt to fix this. issue:
+      #176
+    * Sharp: check whether the 'auto power on' option is disabled and tell the
+      user how to enable it
+    * Samsung: respond to vendor command 0x23 sent by samsung. attempt to fix
+      bugzid: 2164
+    * cec-client: try to reconnect when the connection was lost
+    * cec-tray: crash on load (MissingManifestResourceException)
+    * cec-tray: crash or deadlock on exit
+    * cec-tray: crash when the connection to the adapter was lost
+    * cec-tray: display TV not responding warning on top
+    * windows: build libCEC and cec-client against toolset v100 (VS2010)
+    * FreeBSD: proper the adapter detection. credits @fneufneu
+    * suppress mangling warning. credits @warped-rudi. closes #190
+
+ -- Pulse-Eight Packaging <packaging@pulse-eight.com>  Sat, 13 Dec 2013 16:02:00 +0100
+
 libcec (2.1.3-1) unstable; urgency=low
 
   * changed / added:
index 9b2ac344b039b3455052cb30fe99b9b3c81c40ad..772ca7f7aee7722389d9a1ecc1a92fcaf8da8f8c 100644 (file)
@@ -342,7 +342,7 @@ fi
 LIBS_LIBCEC="$LIBS"
 LIBS="$libs_client"
 
-CXXFLAGS="$CXXFLAGS -fPIC -Wall -Wextra -Wno-missing-field-initializers"
+CXXFLAGS="$CXXFLAGS -fPIC -Wall -Wextra -Wno-missing-field-initializers -Wno-psabi"
 
 if test "x$use_debug" = "xyes"; then
   CXXFLAGS="$CXXFLAGS -g"
index 0a17f5e052fba8c72d81d8576e5b8d813eeb94c7..2ec6ebb6e35edf808501541365d6282fd00da949 100644 (file)
@@ -1,3 +1,60 @@
+libcec (2.1.4-1) unstable; urgency=low
+
+  * changed / added:
+    * set the vendor id of devices handled by libCEC to our vendor id
+    * added protection against standby without a notification from XBMC and
+      clock changes. issue #186
+    * update system audio mode when audio system devices are activated
+    * added vendor id and name 'Harman/Kardon'
+    * added vendor id and name 'Marantz'
+    * cec-tray: support for away mode
+    * cec-tray: support for screensaver events
+  * fixed:
+    * fixed potential crash when SendCommand returns NULL
+    * fixed crash when CCECProcessor::Transmit was called after
+      CCECProcessor::Close
+    * always call the SourceActivated() callback in
+      CCECBusDevice::MarkAsActiveSource(), even when we were already active,
+      and let clients handle dupes. this prevented the screensaver from
+      being cancelled in XBMC
+    * send our vendor id when the tv sends it's vendor id
+    * transmit our physical address when the TV sends it's physical address
+    * potential deadlock
+    * leak on exit in CWaitForResponse::Clear()
+    * also transmit an active source message as response to a set stream path
+      command when we were already marked as active. bugzid: 3116
+    * only send an active source message when receiving a routing change to an
+      address handled by libCEC. issue #56
+    * HandleVendorRemoteButtonUp -> HandleUserControlRelease for all vendors
+    * silence warning for xx:a0:00:09:b0:00:80:20. bugzid: 2559
+    * fixed comboKeyTimeout=0. closes #168
+    * Panasonic: doesn't request the active source status when powered up, but
+      it does send a vendor command. send an active source message when we're
+      marked as active source after receiving this command. issue #192
+    * possible crash when the tv does not respond to polls and the client isn't
+      registered yet. don't poll the tv in monitoring mode. closes #163
+    * Panasonic: standby command
+    * Panasonic: silence 'unmapped code' warning. bugzid: 2375
+    * LG: clean up and attempt to fix issue #176
+    * LG: newer firmwares don't send a second power status request after it's
+      been requested once and replied with 'standby -> on' like previous
+      versions. send an active source message in an attempt to fix this. issue:
+      #176
+    * Sharp: check whether the 'auto power on' option is disabled and tell the
+      user how to enable it
+    * Samsung: respond to vendor command 0x23 sent by samsung. attempt to fix
+      bugzid: 2164
+    * cec-client: try to reconnect when the connection was lost
+    * cec-tray: crash on load (MissingManifestResourceException)
+    * cec-tray: crash or deadlock on exit
+    * cec-tray: crash when the connection to the adapter was lost
+    * cec-tray: display TV not responding warning on top
+    * windows: build libCEC and cec-client against toolset v100 (VS2010)
+    * FreeBSD: proper the adapter detection. credits @fneufneu
+    * suppress mangling warning. credits @warped-rudi. closes #190
+
+ -- Pulse-Eight Packaging <packaging@pulse-eight.com>  Sat, 13 Dec 2013 16:02:00 +0100
+
 libcec (2.1.3-1) unstable; urgency=low
 
   * changed / added:
index 01adebee49e856d20da9a882aa978d6e8799fc8a..9f86253801b6a2be14d981f5ab952c8d309eed30 100644 (file)
@@ -825,28 +825,31 @@ typedef enum cec_bus_device_status
 
 typedef enum cec_vendor_id
 {
-  CEC_VENDOR_TOSHIBA   = 0x000039,
-  CEC_VENDOR_SAMSUNG   = 0x0000F0,
-  CEC_VENDOR_DENON     = 0x0005CD,
-  CEC_VENDOR_LOEWE     = 0x000982,
-  CEC_VENDOR_ONKYO     = 0x0009B0,
-  CEC_VENDOR_MEDION    = 0x000CB8,
-  CEC_VENDOR_TOSHIBA2  = 0x000CE7,
-  CEC_VENDOR_AKAI      = 0x0020C7,
-  CEC_VENDOR_AOC       = 0x002467,
-  CEC_VENDOR_PANASONIC = 0x008045,
-  CEC_VENDOR_PHILIPS   = 0x00903E,
-  CEC_VENDOR_DAEWOO    = 0x009053,
-  CEC_VENDOR_YAMAHA    = 0x00A0DE,
-  CEC_VENDOR_GRUNDIG   = 0x00D0D5,
-  CEC_VENDOR_PIONEER   = 0x00E036,
-  CEC_VENDOR_LG        = 0x00E091,
-  CEC_VENDOR_SHARP     = 0x08001F,
-  CEC_VENDOR_SONY      = 0x080046,
-  CEC_VENDOR_BROADCOM  = 0x18C086,
-  CEC_VENDOR_VIZIO     = 0x6B746D,
-  CEC_VENDOR_BENQ      = 0x8065E9,
-  CEC_VENDOR_UNKNOWN   = 0
+  CEC_VENDOR_TOSHIBA       = 0x000039,
+  CEC_VENDOR_SAMSUNG       = 0x0000F0,
+  CEC_VENDOR_DENON         = 0x0005CD,
+  CEC_VENDOR_MARANTZ       = 0x000678,
+  CEC_VENDOR_LOEWE         = 0x000982,
+  CEC_VENDOR_ONKYO         = 0x0009B0,
+  CEC_VENDOR_MEDION        = 0x000CB8,
+  CEC_VENDOR_TOSHIBA2      = 0x000CE7,
+  CEC_VENDOR_PULSE_EIGHT   = 0x001582,
+  CEC_VENDOR_AKAI          = 0x0020C7,
+  CEC_VENDOR_AOC           = 0x002467,
+  CEC_VENDOR_PANASONIC     = 0x008045,
+  CEC_VENDOR_PHILIPS       = 0x00903E,
+  CEC_VENDOR_DAEWOO        = 0x009053,
+  CEC_VENDOR_YAMAHA        = 0x00A0DE,
+  CEC_VENDOR_GRUNDIG       = 0x00D0D5,
+  CEC_VENDOR_PIONEER       = 0x00E036,
+  CEC_VENDOR_LG            = 0x00E091,
+  CEC_VENDOR_SHARP         = 0x08001F,
+  CEC_VENDOR_SONY          = 0x080046,
+  CEC_VENDOR_BROADCOM      = 0x18C086,
+  CEC_VENDOR_VIZIO         = 0x6B746D,
+  CEC_VENDOR_BENQ          = 0x8065E9,
+  CEC_VENDOR_HARMAN_KARDON = 0x9C645E,
+  CEC_VENDOR_UNKNOWN       = 0
 } cec_vendor_id;
 
 typedef enum cec_adapter_type
@@ -1420,7 +1423,8 @@ typedef enum cec_client_version
   CEC_CLIENT_VERSION_2_1_1   = 0x2101,
   CEC_CLIENT_VERSION_2_1_2   = 0x2102,
   CEC_CLIENT_VERSION_2_1_3   = 0x2103,
-  CEC_CLIENT_VERSION_CURRENT = 0x2103
+  CEC_CLIENT_VERSION_2_1_4   = 0x2104,
+  CEC_CLIENT_VERSION_CURRENT = 0x2104
 } cec_client_version;
 
 typedef enum cec_server_version
@@ -1452,7 +1456,8 @@ typedef enum cec_server_version
   CEC_SERVER_VERSION_2_1_1   = 0x2101,
   CEC_SERVER_VERSION_2_1_2   = 0x2102,
   CEC_SERVER_VERSION_2_1_3   = 0x2103,
-  CEC_SERVER_VERSION_CURRENT = 0x2103
+  CEC_SERVER_VERSION_2_1_4   = 0x2104,
+  CEC_SERVER_VERSION_CURRENT = 0x2104
 } cec_server_version;
 
 struct libcec_configuration
index 81ae7b48c7953e8300a20633b9ef48091b048e39..514fef2eeb78e07d977ca0c1c649e2f3a77e9f94 100644 (file)
Binary files a/project/LibCecSharp/LibCecSharp.rc and b/project/LibCecSharp/LibCecSharp.rc differ
index dd5aea5f2eba5e4eb92b4fbf31b6c0cb7a13027b..a302d99a5e525516220209720fd37af914c16349 100644 (file)
Binary files a/project/libcec/libcec.rc and b/project/libcec/libcec.rc differ
index b8db0b1366f7a436291396a3b505b026f0f9a279..dc8daf8a42194da55eb58d89a1dcb7bf7892bba2 100644 (file)
@@ -47,6 +47,8 @@
     <ClInclude Include="..\..\src\lib\implementations\RLCommandHandler.h" />
     <ClInclude Include="..\..\src\lib\implementations\SLCommandHandler.h" />
     <ClInclude Include="..\..\src\lib\implementations\VLCommandHandler.h" />
+    <ClInclude Include="..\..\src\lib\implementations\RHCommandHandler.h" />
+    <ClInclude Include="..\..\src\lib\implementations\AQCommandHandler.h" />
     <ClInclude Include="..\..\src\lib\LibCEC.h" />
     <ClInclude Include="..\..\src\lib\platform\adl\adl-edid.h" />
     <ClInclude Include="..\..\src\lib\platform\adl\adl_defines.h" />
@@ -93,6 +95,8 @@
     <ClCompile Include="..\..\src\lib\implementations\RLCommandHandler.cpp" />
     <ClCompile Include="..\..\src\lib\implementations\SLCommandHandler.cpp" />
     <ClCompile Include="..\..\src\lib\implementations\VLCommandHandler.cpp" />
+    <ClCompile Include="..\..\src\lib\implementations\RHCommandHandler.cpp" />
+    <ClCompile Include="..\..\src\lib\implementations\AQCommandHandler.cpp" />
     <ClCompile Include="..\..\src\lib\LibCEC.cpp" />
     <ClCompile Include="..\..\src\lib\LibCECC.cpp" />
     <ClCompile Include="..\..\src\lib\LibCECDll.cpp" />
     <ConfigurationType>DynamicLibrary</ConfigurationType>
     <UseDebugLibraries>true</UseDebugLibraries>
     <CharacterSet>MultiByte</CharacterSet>
-    <PlatformToolset>v110</PlatformToolset>
+    <PlatformToolset>v100</PlatformToolset>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
     <ConfigurationType>DynamicLibrary</ConfigurationType>
     <UseDebugLibraries>true</UseDebugLibraries>
     <CharacterSet>MultiByte</CharacterSet>
-    <PlatformToolset>v110</PlatformToolset>
+    <PlatformToolset>v100</PlatformToolset>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
     <ConfigurationType>DynamicLibrary</ConfigurationType>
     <UseDebugLibraries>false</UseDebugLibraries>
     <CharacterSet>MultiByte</CharacterSet>
-    <PlatformToolset>v110</PlatformToolset>
+    <PlatformToolset>v100</PlatformToolset>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
     <ConfigurationType>DynamicLibrary</ConfigurationType>
     <UseDebugLibraries>false</UseDebugLibraries>
     <CharacterSet>MultiByte</CharacterSet>
-    <PlatformToolset>v110</PlatformToolset>
+    <PlatformToolset>v100</PlatformToolset>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
   <ImportGroup Label="ExtensionSettings">
index b9e41ed1a4d96b407495f927d4338bd2d8e05787..903f44dbeba67cf4c3e9ef2b044d4b499d822402 100644 (file)
     <ClInclude Include="..\..\src\lib\implementations\VLCommandHandler.h">
       <Filter>implementations</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\src\lib\implementations\RHCommandHandler.h">
+      <Filter>implementations</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\lib\implementations\ANCommandHandler.h">
+      <Filter>implementations</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\src\lib\devices\CECAudioSystem.h">
       <Filter>devices</Filter>
     </ClInclude>
     <ClCompile Include="..\..\src\lib\implementations\VLCommandHandler.cpp">
       <Filter>implementations</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\lib\implementations\RHCommandHandler.cpp">
+      <Filter>implementations</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\lib\implementations\AQCommandHandler.cpp">
+      <Filter>implementations</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\lib\devices\CECAudioSystem.cpp">
       <Filter>devices</Filter>
     </ClCompile>
index 84edc7f7a649e894fda759475a1b8efac9045483..95a6c1a0b4768f520eba6640bd802d7a592e47c0 100644 (file)
Binary files a/project/testclient/resource.h and b/project/testclient/resource.h differ
index 5be543716e369255152c5004e85f15ffad62da76..5990a9c2c2fa2646ecd8551d13a430c17a8fd3f1 100644 (file)
Binary files a/project/testclient/testclient.rc and b/project/testclient/testclient.rc differ
index 9e910ac7dd123d1aee1a5be462a0fa01bdaef38b..07b54875cb9340c7734881c0084ca806cadfded3 100644 (file)
     <ConfigurationType>Application</ConfigurationType>
     <UseDebugLibraries>true</UseDebugLibraries>
     <CharacterSet>MultiByte</CharacterSet>
-    <PlatformToolset>v110</PlatformToolset>
+    <PlatformToolset>v100</PlatformToolset>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <UseDebugLibraries>true</UseDebugLibraries>
     <CharacterSet>MultiByte</CharacterSet>
-    <PlatformToolset>v110</PlatformToolset>
+    <PlatformToolset>v100</PlatformToolset>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <UseDebugLibraries>false</UseDebugLibraries>
     <CharacterSet>MultiByte</CharacterSet>
-    <PlatformToolset>v110</PlatformToolset>
+    <PlatformToolset>v100</PlatformToolset>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <UseDebugLibraries>false</UseDebugLibraries>
     <CharacterSet>MultiByte</CharacterSet>
-    <PlatformToolset>v110</PlatformToolset>
+    <PlatformToolset>v100</PlatformToolset>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
   <ImportGroup Label="ExtensionSettings">
index de041e6f5f6c16cd7874d0c0106bd0cca67c6728..cb4952fa81dcf4906f98091c10fb4bb864bf9247 100644 (file)
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
 // 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("2.1.3.0")]
-[assembly: AssemblyFileVersion("2.1.3.0")]
+[assembly: AssemblyVersion("2.1.4.0")]
+[assembly: AssemblyFileVersion("2.1.4.0")]
index 50e65ec37773effd7fedadd6062a34184c31aced..19f1b439feb6b4f8e5f5dcd1ac19beff689ec7dd 100644 (file)
@@ -13,7 +13,7 @@ using namespace System::Security::Permissions;
 [assembly:AssemblyTrademarkAttribute("")];
 [assembly:AssemblyCultureAttribute("")];
 
-[assembly:AssemblyVersionAttribute("2.1.3.0")];
+[assembly:AssemblyVersionAttribute("2.1.4.0")];
 
 [assembly:ComVisible(false)];
 [assembly:CLSCompliantAttribute(true)];
index 89c9d3bd49eb2257a899176b8c85421fc35fac8b..2de94bf015800c2b3680b65d605ba2e025d560c4 100644 (file)
@@ -784,27 +784,31 @@ namespace CecSharp
   /// </summary>
   public enum class CecVendorId
   {
-    Toshiba   = 0x000039,
-    Samsung   = 0x0000F0,
-    Denon     = 0x0005CD,
-    Loewe     = 0x000982,
-    Onkyo     = 0x0009B0,
-    Medion    = 0x000CB8,
-    Akai      = 0x0020C7,
-    AOC       = 0x002467,
-    Panasonic = 0x008045,
-    Philips   = 0x00903E,
-    Daewoo    = 0x009053,
-    Yamaha    = 0x00A0DE,
-    Grundig   = 0x00D0D5,
-    Pioneer   = 0x00E036,
-    LG        = 0x00E091,
-    Sharp     = 0x08001F,
-    Sony      = 0x080046,
-    Broadcom  = 0x18C086,
-    Vizio     = 0x6B746D,
-    Benq      = 0x8065E9,
-    Unknown   = 0
+    Toshiba      = 0x000039,
+    Samsung      = 0x0000F0,
+    Denon        = 0x0005CD,
+    Marantz      = 0x000678,
+    Loewe        = 0x000982,
+    Onkyo        = 0x0009B0,
+    Medion       = 0x000CB8,
+    Toshiba2     = 0x000CE7,
+    PulseEight   = 0x001582,
+    Akai         = 0x0020C7,
+    AOC          = 0x002467,
+    Panasonic    = 0x008045,
+    Philips      = 0x00903E,
+    Daewoo       = 0x009053,
+    Yamaha       = 0x00A0DE,
+    Grundig      = 0x00D0D5,
+    Pioneer      = 0x00E036,
+    LG           = 0x00E091,
+    Sharp        = 0x08001F,
+    Sony         = 0x080046,
+    Broadcom     = 0x18C086,
+    Vizio        = 0x6B746D,
+    Benq         = 0x8065E9,
+    HarmanKardon = 0x9C645E,
+    Unknown      = 0
   };
 
   /// <summary>
@@ -1225,9 +1229,13 @@ namespace CecSharp
     /// </summary>
     Version2_1_3   = 0x2103,
     /// <summary>
+    /// v2.1.4
+    /// </summary>
+    Version2_1_4   = 0x2104,
+       /// <summary>
     /// The current version
     /// </summary>
-    CurrentVersion = 0x2103
+    CurrentVersion = 0x2104
   };
 
   /// <summary>
@@ -1343,10 +1351,14 @@ namespace CecSharp
     /// v2.1.3
     /// </summary>
     Version2_1_3   = 0x2103,
+       /// <summary>
+    /// v2.1.4
+    /// </summary>
+    Version2_1_4   = 0x2104,
     /// <summary>
     /// The current version
     /// </summary>
-    CurrentVersion = 0x2103
+    CurrentVersion = 0x2104
   };
 
   /// <summary>
@@ -2401,7 +2413,7 @@ namespace CecSharp
         CecParameterType newType = (CecParameterType)data.paramType;
         if (newType == CecParameterType::ParameterTypeString)
         {
-          System::String ^ newData = gcnew System::String((const char *)data.paramData, 0, 128);
+          System::String ^ newData = gcnew System::String(data.paramData ? (const char *)data.paramData : "", 0, 128);
           CecParameter ^ newParam = gcnew CecParameter(newType, newData);
           iReturn = m_callbacks->ReceiveAlert((CecAlert)alert, newParam);
         }
index bfa1d9f81533752c5af000eab71e1b47979775bd..86cc6de3475dce9fadadb5d07b561b19b96bda2e 100644 (file)
@@ -78,6 +78,7 @@
   </ItemGroup>
   <ItemGroup>
     <Compile Include="controller\Actions.cs" />
+    <Compile Include="controller\actions\ActivateSource.cs" />
     <Compile Include="controller\actions\GetCurrentPhysicalAddress.cs" />
     <Compile Include="controller\actions\UpdateConfiguration.cs" />
     <Compile Include="controller\actions\ConnectToDevice.cs" />
index edb540034f22690fb2e35ebb6600ebf457861f11..8d6e8ed8634b25b46765c3a5e799f95e712e06e8 100644 (file)
@@ -31,5 +31,5 @@ using System.Runtime.InteropServices;
 // 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("2.1.3.0")]
-[assembly: AssemblyFileVersion("2.1.3.0")]
+[assembly: AssemblyVersion("2.1.4.0")]
+[assembly: AssemblyFileVersion("2.1.4.0")]
index 13dc92035be67a078ffb42660552a6d98c78baf8..355f94ee4c5b6fa2bf8d5604482636d252028c10 100644 (file)
@@ -94,7 +94,7 @@ namespace LibCECTray.controller
           _controller.CheckActiveDevices();
           break;
         case UpdateEventType.ProcessCompleted:
-          if (!(_activeProcess is GetCurrentPhysicalAddress))
+          if (!(_activeProcess is GetCurrentPhysicalAddress) && !SuppressUpdates)
           {
             _activeProcess = new GetCurrentPhysicalAddress(_controller.Lib);
             _activeProcess.EventHandler += ProcessEventHandler;
@@ -123,6 +123,7 @@ namespace LibCECTray.controller
 
           break;
         case UpdateEventType.ExitApplication:
+          SuppressUpdates = true;
           _activeProcess = null;
           Application.Exit();
           break;
@@ -207,7 +208,7 @@ namespace LibCECTray.controller
     /// Activate the source at the given logical address. 
     /// </summary>
     /// <param name="address">The logical address of the device to activate</param>
-    public void ActivateSource(CecLogicalAddress address)
+    public void SetStreamPath(CecLogicalAddress address)
     {
       if (SuppressUpdates || _activeProcess != null) return;
 
@@ -217,6 +218,16 @@ namespace LibCECTray.controller
       (new Thread(_activeProcess.Run)).Start();
     }
 
+    public void ActivateSource()
+    {
+      if (SuppressUpdates || _activeProcess != null) return;
+
+      _controller.SetControlsEnabled(false);
+      _activeProcess = new ActivateSource(_controller.Lib);
+      _activeProcess.EventHandler += ProcessEventHandler;
+      (new Thread(_activeProcess.Run)).Start();
+    }
+
     /// <summary>
     /// Send a standby command to the device at the given logical address
     /// </summary>
diff --git a/src/LibCecTray/controller/actions/ActivateSource.cs b/src/LibCecTray/controller/actions/ActivateSource.cs
new file mode 100644 (file)
index 0000000..44d2d50
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2013 Pulse-Eight Limited.  All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing       <license@pulse-eight.com>
+ *     http://www.pulse-eight.com/
+ *     http://www.pulse-eight.net/
+ */
+
+using CecSharp;
+using LibCECTray.Properties;
+
+namespace LibCECTray.controller.actions
+{
+  class ActivateSource : UpdateProcess
+  {
+    public ActivateSource(LibCecSharp lib)
+    {
+      _lib = lib;
+    }
+
+    public override void Process()
+    {
+      SendEvent(UpdateEventType.StatusText, Resources.action_activating_source);
+      SendEvent(UpdateEventType.ProgressBar, 50);
+
+      var bResult = _lib.SetActiveSource(CecDeviceType.Reserved);
+      SendEvent(UpdateEventType.ProgressBar, 100);
+    }
+
+    private readonly LibCecSharp _lib;
+  }
+}
index 6a832c5f9096c48b8ce71b1b9181dbfb3cf687a6..e35906a792eaff8645e99eed54c4e4b7cc39642f 100644 (file)
@@ -74,9 +74,12 @@ namespace LibCECTray.controller.actions
       SendEvent(UpdateEventType.StatusText, Resources.action_sending_power_on);
       _lib.PowerOnDevices(CecLogicalAddress.Broadcast);
 
-      SendEvent(UpdateEventType.StatusText, Resources.action_detecting_tv_vendor);
-      SendEvent(UpdateEventType.ProgressBar, 30);
-      SendEvent(UpdateEventType.TVVendorId, (int)_lib.GetDeviceVendorId(CecLogicalAddress.Tv));
+      if (_lib.IsActiveDevice(CecLogicalAddress.Tv))
+      {
+        SendEvent(UpdateEventType.StatusText, Resources.action_detecting_tv_vendor);
+        SendEvent(UpdateEventType.ProgressBar, 30);
+        SendEvent(UpdateEventType.TVVendorId, (int)_lib.GetDeviceVendorId(CecLogicalAddress.Tv));
+      }
 
       SendEvent(UpdateEventType.ProgressBar, 50);
       SendEvent(UpdateEventType.StatusText, Resources.action_detecting_avr);
@@ -91,7 +94,7 @@ namespace LibCECTray.controller.actions
         SendEvent(UpdateEventType.AVRVendorId, (int)_lib.GetDeviceVendorId(CecLogicalAddress.AudioSystem));
       }
 
-      if (!_lib.GetDevicePowerStatus(CecLogicalAddress.Tv).Equals(CecPowerStatus.On))
+      if (_lib.IsActiveDevice(CecLogicalAddress.Tv)&& !_lib.GetDevicePowerStatus(CecLogicalAddress.Tv).Equals(CecPowerStatus.On))
       {
         SendEvent(UpdateEventType.ProgressBar, 70);
         SendEvent(UpdateEventType.StatusText, Resources.action_activating_source);
@@ -110,7 +113,7 @@ namespace LibCECTray.controller.actions
 
       if (!_lib.IsActiveDevice(CecLogicalAddress.Tv))
       {
-        MessageBox.Show(Resources.alert_tv_poll_failed, Resources.cec_alert, MessageBoxButtons.OK, MessageBoxIcon.Warning);
+        MessageBox.Show(Resources.alert_tv_poll_failed, Resources.cec_alert, MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly);
       }
 
       SendEvent(UpdateEventType.ProgressBar, 100);
index 6a04d62f2301da982ecb970cf78547c9031351bc..0b8d17c5636e0d81aa4fd9cffbfb53dfe21ce13c 100644 (file)
@@ -40,22 +40,11 @@ using LibCECTray.controller.applications;
 using LibCECTray.settings;
 using Microsoft.Win32;
 using System.Security.Permissions;
+using System.Runtime.InteropServices;
+using System.Threading;
 
 namespace LibCECTray.ui
 {
-  /// <summary>
-  /// The tab pages in this application
-  /// </summary>
-  internal enum ConfigTab
-  {
-    Configuration,
-    KeyConfiguration,
-    Tester,
-    Log,
-    WMC,
-    XBMC
-  }
-
   /// <summary>
   /// Main LibCecTray GUI
   /// </summary>
@@ -65,6 +54,13 @@ namespace LibCECTray.ui
     {
       Text = Resources.app_name;
       InitializeComponent();
+
+      _sstimer.Interval = 5000;
+      _sstimer.Tick += ScreensaverActiveCheck;
+      _sstimer.Enabled = false;
+
+      _lastScreensaverActivated = DateTime.Now;
+
       VisibleChanged += delegate
                        {
                          if (!Visible)
@@ -72,28 +68,133 @@ namespace LibCECTray.ui
                          else
                            OnShow();
                        };
-      SystemEvents.PowerModeChanged += new PowerModeChangedEventHandler(OnPowerModeChanged);
+
       SystemEvents.SessionEnding += new SessionEndingEventHandler(OnSessionEnding);
     }
 
     public void OnSessionEnding(object sender, SessionEndingEventArgs e)
     {
+      Controller.CECActions.SuppressUpdates = true;
       Controller.Close();
     }
 
-    public void OnPowerModeChanged(Object sender, PowerModeChangedEventArgs e)
+    #region Power state change window messages
+    private const int WM_POWERBROADCAST      = 0x0218;
+    private const int WM_SYSCOMMAND          = 0x0112;
+
+    private const int PBT_APMSUSPEND         = 0x0004;
+    private const int PBT_APMRESUMESUSPEND   = 0x0007;
+    private const int PBT_APMRESUMECRITICAL  = 0x0006;
+    private const int PBT_APMRESUMEAUTOMATIC = 0x0012;
+    private const int PBT_POWERSETTINGCHANGE = 0x8013;
+
+    private static Guid GUID_SYSTEM_AWAYMODE = new Guid("98a7f580-01f7-48aa-9c0f-44352c29e5c0");
+
+    private const int SC_SCREENSAVE             = 0xF140;
+    private const int SPI_GETSCREENSAVERRUNNING = 0x0072;
+
+    [DllImport("user32.dll", SetLastError = true)]
+    static extern bool SystemParametersInfo(int action, int param, ref int retval, int updini);
+
+    [StructLayout(LayoutKind.Sequential, Pack = 4)]
+    internal struct POWERBROADCAST_SETTING
+    {
+      public Guid PowerSetting;
+      public uint DataLength;
+      public byte Data;
+    }
+    #endregion
+
+    /// <summary>
+    /// Check for power state changes, and pass up when it's something we don't care about
+    /// </summary>
+    /// <param name="msg">The incoming window message</param>
+    protected override void WndProc(ref Message msg)
     {
-      switch (e.Mode)
+      if (msg.Msg == WM_SYSCOMMAND && (msg.WParam.ToInt32() & 0xfff0) == SC_SCREENSAVE)
       {
-        case PowerModes.Resume:
-          Controller.Initialise();
-          break;
-        case PowerModes.Suspend:
-          Controller.Close();
-          break;
-        case PowerModes.StatusChange:
-          break;
+        // there's no event for screensaver exit
+        if (!_sstimer.Enabled)
+        {
+          // guard against screensaver failing, and resulting in power up and down spam to the tv
+          TimeSpan diff = DateTime.Now - _lastScreensaverActivated;
+          if (diff.TotalSeconds > 60)
+          {
+            _sstimer.Enabled = true;
+            _lastScreensaverActivated = DateTime.Now;
+            Controller.CECActions.SendStandby(CecLogicalAddress.Broadcast);
+          }
+        }
       }
+      else if (msg.Msg == WM_POWERBROADCAST)
+      {
+        switch (msg.WParam.ToInt32())
+        {
+          case PBT_APMSUSPEND:
+            OnSleep();
+            return;
+
+          case PBT_APMRESUMESUSPEND:
+          case PBT_APMRESUMECRITICAL:
+          case PBT_APMRESUMEAUTOMATIC:
+            OnWake();
+            return;
+
+          case PBT_POWERSETTINGCHANGE:
+            {
+              POWERBROADCAST_SETTING pwr = (POWERBROADCAST_SETTING)Marshal.PtrToStructure(msg.LParam, typeof(POWERBROADCAST_SETTING));
+              if (pwr.PowerSetting == GUID_SYSTEM_AWAYMODE && pwr.DataLength == Marshal.SizeOf(typeof(Int32)))
+              {
+                switch (pwr.Data)
+                {
+                  case 0:
+                    // do _not_ wake the pc when away mode is deactivated
+                    //OnWake();
+                    //return;
+                  case 1:
+                    Controller.CECActions.SendStandby(CecLogicalAddress.Broadcast);
+                    return;
+                  default:
+                    break;
+                }
+              }
+            }
+            break;
+          default:
+            break;
+        }
+      }
+
+      // pass up when not handled
+      base.WndProc(ref msg);
+    }
+
+    private void ScreensaverActiveCheck(object sender, EventArgs e)
+    {
+      if (!IsScreensaverActive())
+      {
+        _sstimer.Enabled = false;
+        Controller.CECActions.ActivateSource();
+      }
+    }
+
+    private bool IsScreensaverActive()
+    {
+      int active = 1;
+      SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, ref active, 0);
+      return active == 1;
+    }
+
+    private void OnWake()
+    {
+      Controller.Initialise();
+    }
+
+    private void OnSleep()
+    {
+      Controller.CECActions.SuppressUpdates = true;
+      AsyncDisconnect dc = new AsyncDisconnect(Controller);
+      (new Thread(dc.Process)).Start();
     }
 
     public override sealed string Text
@@ -112,7 +213,7 @@ namespace LibCECTray.ui
       Hide();
       if (disposing)
       {
-        Controller.Close();
+        OnSleep();
       }
       if (disposing && (components != null))
       {
@@ -208,7 +309,7 @@ namespace LibCECTray.ui
 
     private void BActivateSourceClick(object sender, EventArgs e)
     {
-      Controller.CECActions.ActivateSource(GetTargetDevice());
+      Controller.CECActions.SetStreamPath(GetTargetDevice());
     }
 
     private void CbCommandDestinationSelectedIndexChanged(object sender, EventArgs e)
@@ -521,6 +622,9 @@ namespace LibCECTray.ui
     {
       get { return GetSelectedTabName(tabPanel, tabPanel.TabPages); }
     }
+
+    private System.Windows.Forms.Timer _sstimer = new System.Windows.Forms.Timer();
+    private DateTime _lastScreensaverActivated;
     #endregion
 
     private void AddNewApplicationToolStripMenuItemClick(object sender, EventArgs e)
@@ -529,4 +633,32 @@ namespace LibCECTray.ui
       Controller.DisplayDialog(appConfig, false);
     }
   }
+
+  /// <summary>
+  /// The tab pages in this application
+  /// </summary>
+  internal enum ConfigTab
+  {
+    Configuration,
+    KeyConfiguration,
+    Tester,
+    Log,
+    WMC,
+    XBMC
+  }
+
+  class AsyncDisconnect
+  {
+    public AsyncDisconnect(CECController controller)
+    {
+      _controller = controller;
+    }
+
+    public void Process()
+    {
+      _controller.Close();
+    }
+
+    private CECController _controller;
+  }
 }
index 581a41797fb8ff189431bfea849d33374aabea86..1feed3bef862357e73980d1c2968af5ec255f98a 100644 (file)
@@ -72,7 +72,7 @@ namespace LibCECTray.ui
     {
       SetControlVisible(lInactiveSource, false);
       SetControlVisible(lActiveSource, true);
-      _controller.CECActions.ActivateSource(Address);
+      _controller.CECActions.SetStreamPath(Address);
     }
 
     private void LStandbyLinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
index 4db7fcd50f1476eb2caf9df8e77966253f808cc7..85df46d376859c9c24575abb175b110202af7a90 100644 (file)
@@ -973,10 +973,10 @@ void CCECClient::AddKey(bool bSendComboKey /* = false */)
     {
       key.duration = (unsigned int) (GetTimeMs() - m_buttontime);
 
-      cec_user_control_code comboKey(m_configuration.comboKey);
-      uint32_t iTimeoutMs(m_configuration.iComboKeyTimeoutMs);
-
-      if (key.duration > iTimeoutMs || m_iCurrentButton != comboKey || bSendComboKey)
+      if (key.duration > m_configuration.iComboKeyTimeoutMs ||
+          m_configuration.iComboKeyTimeoutMs == 0 ||
+          m_iCurrentButton != m_configuration.comboKey ||
+          bSendComboKey)
       {
         key.keycode = m_iCurrentButton;
 
@@ -1009,7 +1009,7 @@ void CCECClient::AddKey(const cec_keypress &key)
 
   {
     CLockObject lock(m_mutex);
-    if (m_iCurrentButton == comboKey && key.duration == 0)
+    if (m_configuration.iComboKeyTimeoutMs > 0 && m_iCurrentButton == comboKey && key.duration == 0)
     {
       // stop + ok -> exit
       if (key.keycode == CEC_USER_CONTROL_CODE_SELECT)
@@ -1070,7 +1070,7 @@ void CCECClient::CheckKeypressTimeout(void)
         m_configuration.iComboKeyTimeoutMs : CEC_DEFAULT_COMBO_TIMEOUT_MS);
 
     if (m_iCurrentButton != CEC_USER_CONTROL_CODE_UNKNOWN &&
-          ((m_iCurrentButton == comboKey && iNow - m_buttontime > iTimeoutMs) ||
+          ((m_iCurrentButton == comboKey && iTimeoutMs > 0 && iNow - m_buttontime > iTimeoutMs) ||
           (m_iCurrentButton != comboKey && iNow - m_buttontime > CEC_BUTTON_TIMEOUT)))
     {
       key.duration = (unsigned int) (iNow - m_buttontime);
index a44b81eb6a314167395916af458c7ab3d26c91f4..557b76d904e15cf48d0ff291cf4db0e7dd61f839 100644 (file)
@@ -57,6 +57,34 @@ using namespace PLATFORM;
 
 #define ToString(x) CCECTypeUtils::ToString(x)
 
+CCECStandbyProtection::CCECStandbyProtection(CCECProcessor* processor) :
+    m_processor(processor) {}
+CCECStandbyProtection::~CCECStandbyProtection(void) {}
+
+void* CCECStandbyProtection::Process(void)
+{
+  int64_t last = GetTimeMs();
+  int64_t next;
+  while (!IsStopped())
+  {
+    PLATFORM::CEvent::Sleep(1000);
+
+    next = GetTimeMs();
+
+    // reset the connection if the clock changed
+    if (next < last || next - last > 10000)
+    {
+      libcec_parameter param;
+      param.paramData = NULL; param.paramType = CEC_PARAMETER_TYPE_UNKOWN;
+      m_processor->GetLib()->Alert(CEC_ALERT_CONNECTION_LOST, param);
+      break;
+    }
+
+    last = next;
+  }
+  return NULL;
+}
+
 CCECProcessor::CCECProcessor(CLibCEC *libcec) :
     m_bInitialised(false),
     m_communication(NULL),
@@ -66,7 +94,8 @@ CCECProcessor::CCECProcessor(CLibCEC *libcec) :
     m_iLastTransmission(0),
     m_bMonitor(true),
     m_addrAllocator(NULL),
-    m_bStallCommunication(false)
+    m_bStallCommunication(false),
+    m_connCheck(NULL)
 {
   m_busDevices = new CCECDeviceMap(this);
 }
@@ -105,11 +134,13 @@ void CCECProcessor::Close(void)
   SetCECInitialised(false);
 
   // stop the processor
+  DELETE_AND_NULL(m_connCheck);
   StopThread(-1);
   m_inBuffer.Broadcast();
   StopThread();
 
   // close the connection
+  CLockObject lock(m_mutex);
   DELETE_AND_NULL(m_communication);
 }
 
@@ -215,6 +246,10 @@ void *CCECProcessor::Process(void)
 {
   m_libcec->AddLog(CEC_LOG_DEBUG, "processor thread started");
 
+  if (!m_connCheck)
+    m_connCheck = new CCECStandbyProtection(this);
+  m_connCheck->CreateThread();
+
   cec_command command; command.Clear();
   CTimeout activeSourceCheck(ACTIVE_SOURCE_CHECK_INTERVAL);
   CTimeout tvPresentCheck(TV_PRESENT_CHECK_INTERVAL);
@@ -245,12 +280,17 @@ void *CCECProcessor::Process(void)
       // check whether the TV is present and responding
       if (tvPresentCheck.TimeLeft() == 0)
       {
-        if (!m_busDevices->At(CECDEVICE_TV)->IsPresent())
+        CCECClient *primary = GetPrimaryClient();
+        // only check whether the tv responds to polls when a client is connected and not in monitoring mode
+        if (primary && primary->GetConfiguration()->bMonitorOnly != 1)
         {
-          libcec_parameter param;
-          param.paramType = CEC_PARAMETER_TYPE_STRING;
-          param.paramData = (void*)"TV does not respond to CEC polls";
-          GetPrimaryClient()->Alert(CEC_ALERT_TV_POLL_FAILED, param);
+          if (!m_busDevices->At(CECDEVICE_TV)->IsPresent())
+          {
+            libcec_parameter param;
+            param.paramType = CEC_PARAMETER_TYPE_STRING;
+            param.paramData = (void*)"TV does not respond to CEC polls";
+            primary->Alert(CEC_ALERT_TV_POLL_FAILED, param);
+          }
         }
         tvPresentCheck.Init(TV_PRESENT_CHECK_INTERVAL);
       }
@@ -400,6 +440,10 @@ bool CCECProcessor::Transmit(const cec_command &data, bool bIsReply)
   // reset the state of this message to 'unknown'
   cec_adapter_message_state adapterState = ADAPTER_MESSAGE_STATE_UNKNOWN;
 
+  CLockObject lock(m_mutex);
+  if (!m_communication)
+    return false;
+
   if (!m_communication->SupportsSourceLogicalAddress(transmitData.initiator))
   {
     if (transmitData.initiator == CECDEVICE_UNREGISTERED && m_communication->SupportsSourceLogicalAddress(CECDEVICE_FREEUSE))
@@ -438,15 +482,14 @@ bool CCECProcessor::Transmit(const cec_command &data, bool bIsReply)
   }
 
   // wait until we finished allocating a new LA if it got lost
+  lock.Unlock();
   while (m_bStallCommunication) Sleep(5);
+  lock.Lock();
 
-  {
-    CLockObject lock(m_mutex);
-    m_iLastTransmission = GetTimeMs();
-    // set the number of tries
-    iMaxTries = initiator->GetHandler()->GetTransmitRetries() + 1;
-    initiator->MarkHandlerReady();
-  }
+  m_iLastTransmission = GetTimeMs();
+  // set the number of tries
+  iMaxTries = initiator->GetHandler()->GetTransmitRetries() + 1;
+  initiator->MarkHandlerReady();
 
   // and try to send the command
   while (bRetry && ++iTries < iMaxTries)
@@ -854,7 +897,7 @@ bool CCECProcessor::RegisterClient(CCECClient *client)
   client->GetPrimaryDevice()->TransmitOSDName(CECDEVICE_TV, false);
 
   // request the power status of the TV
-  tv->RequestPowerStatus(sourceAddress, true);
+  tv->RequestPowerStatus(sourceAddress, true, true);
 
   return bReturn;
 }
index 268be64ae0dc9d2956b7fb37df79ec2809a3d937..44f1fc170bf1d22d674e7d057c44fa4024b5afb6 100644 (file)
@@ -52,6 +52,7 @@ namespace CEC
   class CCECTV;
   class CCECClient;
   class CCECProcessor;
+  class CCECStandbyProtection;
 
   class CCECAllocateLogicalAddress : public PLATFORM::CThread
   {
@@ -177,5 +178,17 @@ namespace CEC
       bool                                        m_bMonitor;
       CCECAllocateLogicalAddress*                 m_addrAllocator;
       bool                                        m_bStallCommunication;
+      CCECStandbyProtection*                      m_connCheck;
+  };
+
+  class CCECStandbyProtection : public PLATFORM::CThread
+  {
+  public:
+    CCECStandbyProtection(CCECProcessor* processor);
+    virtual ~CCECStandbyProtection(void);
+    void* Process(void);
+
+  private:
+    CCECProcessor* m_processor;
   };
 };
index 506974b74f58d1172c0d549170f573a10fc91f95..dc4e5f1df74b59cb779e33586dbcab634adcb429 100644 (file)
@@ -517,6 +517,12 @@ namespace CEC
         return "Loewe";
       case CEC_VENDOR_DENON:
         return "Denon";
+      case CEC_VENDOR_MARANTZ:
+        return "Marantz";
+      case CEC_VENDOR_HARMAN_KARDON:
+        return "Harman/Kardon";
+      case CEC_VENDOR_PULSE_EIGHT:
+        return "Pulse Eight";
       default:
         return "Unknown";
       }
@@ -580,6 +586,8 @@ namespace CEC
         return "2.1.2";
       case CEC_CLIENT_VERSION_2_1_3:
         return "2.1.3";
+      case CEC_CLIENT_VERSION_2_1_4:
+        return "2.1.4";
       default:
         return "Unknown";
       }
@@ -643,6 +651,8 @@ namespace CEC
         return "2.1.2";
       case CEC_SERVER_VERSION_2_1_3:
         return "2.1.3";
+      case CEC_SERVER_VERSION_2_1_4:
+        return "2.1.4";
       default:
         return "Unknown";
       }
index 35166f2d584026444d585846caa9a31d30a9032a..9117d8ebf3ce8fb7e9880b8b3497b4b8e3b946aa 100644 (file)
@@ -26,7 +26,9 @@ libcec_la_SOURCES = CECProcessor.cpp \
                     implementations/SLCommandHandler.cpp \
                     implementations/VLCommandHandler.cpp \
                     implementations/RLCommandHandler.cpp \
-                    implementations/PHCommandHandler.cpp
+                    implementations/PHCommandHandler.cpp \
+                    implementations/RHCommandHandler.cpp \
+                    implementations/AQCommandHandler.cpp
 
 ## server sockets, currently unused
 ##libcec_la_SOURCES += platform/posix/serversocket.cpp
index f70c8ef76f80582955fd9222e85552241824a2b3..85050334a0a99841370251e11229cc964a0173bd 100644 (file)
@@ -38,6 +38,7 @@
 #include "lib/LibCEC.h"
 #include "lib/CECProcessor.h"
 #include "lib/CECTypeUtils.h"
+#include "lib/platform/util/util.h"
 #include <stdio.h>
 
 using namespace CEC;
@@ -67,14 +68,14 @@ cec_datapacket CUSBCECAdapterCommands::RequestSetting(cec_adapter_messagecode ms
 
   CCECAdapterMessage params;
   CCECAdapterMessage *message = m_comm->SendCommand(msgCode, params);
-  if (message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED)
+  if (message && message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED)
   {
     retVal = message->response;
     retVal.Shift(2); // shift out start and msgcode
     retVal.size -= 1; // remove end
   }
 
-  delete message;
+  DELETE_AND_NULL(message);
   return retVal;
 }
 
@@ -281,8 +282,8 @@ bool CUSBCECAdapterCommands::SetSettingAutoEnabled(bool enabled)
   CCECAdapterMessage params;
   params.PushEscaped(enabled ? 1 : 0);
   CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_SET_AUTO_ENABLED, params);
-  bReturn = message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED;
-  delete message;
+  bReturn = message && message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED;
+  DELETE_AND_NULL(message);
 
   if (bReturn)
   {
@@ -310,8 +311,8 @@ bool CUSBCECAdapterCommands::SetSettingDeviceType(cec_device_type type)
   CCECAdapterMessage params;
   params.PushEscaped((uint8_t)type);
   CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_SET_DEVICE_TYPE, params);
-  bReturn = message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED;
-  delete message;
+  bReturn = message && message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED;
+  DELETE_AND_NULL(message);
 
   if (bReturn)
   {
@@ -339,8 +340,8 @@ bool CUSBCECAdapterCommands::SetSettingDefaultLogicalAddress(cec_logical_address
   CCECAdapterMessage params;
   params.PushEscaped((uint8_t)address);
   CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_SET_DEFAULT_LOGICAL_ADDRESS, params);
-  bReturn = message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED;
-  delete message;
+  bReturn = message && message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED;
+  DELETE_AND_NULL(message);
 
   if (bReturn)
   {
@@ -369,8 +370,8 @@ bool CUSBCECAdapterCommands::SetSettingLogicalAddressMask(uint16_t iMask)
   params.PushEscaped(iMask >> 8);
   params.PushEscaped((uint8_t)iMask);
   CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_SET_LOGICAL_ADDRESS_MASK, params);
-  bReturn = message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED;
-  delete message;
+  bReturn = message && message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED;
+  DELETE_AND_NULL(message);
 
   if (bReturn)
   {
@@ -399,8 +400,8 @@ bool CUSBCECAdapterCommands::SetSettingPhysicalAddress(uint16_t iPhysicalAddress
   params.PushEscaped(iPhysicalAddress >> 8);
   params.PushEscaped((uint8_t)iPhysicalAddress);
   CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_SET_PHYSICAL_ADDRESS, params);
-  bReturn = message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED;
-  delete message;
+  bReturn = message && message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED;
+  DELETE_AND_NULL(message);
 
   if (bReturn)
   {
@@ -428,8 +429,8 @@ bool CUSBCECAdapterCommands::SetSettingCECVersion(cec_version version)
   CCECAdapterMessage params;
   params.PushEscaped((uint8_t)version);
   CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_SET_HDMI_VERSION, params);
-  bReturn = message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED;
-  delete message;
+  bReturn = message && message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED;
+  DELETE_AND_NULL(message);
 
   if (bReturn)
   {
@@ -454,8 +455,8 @@ bool CUSBCECAdapterCommands::SetSettingOSDName(const char *strOSDName)
   for (size_t iPtr = 0; iPtr < strlen(strOSDName); iPtr++)
     params.PushEscaped(strOSDName[iPtr]);
   CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_SET_OSD_NAME, params);
-  bReturn = message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED;
-  delete message;
+  bReturn = message && message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED;
+  DELETE_AND_NULL(message);
 
   if (bReturn)
     snprintf(m_persistedConfiguration.strDeviceName, 13, "%s", strOSDName);
@@ -475,8 +476,8 @@ bool CUSBCECAdapterCommands::WriteEEPROM(void)
 
   CCECAdapterMessage params;
   CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_WRITE_EEPROM, params);
-  bool bReturn = message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED;
-  delete message;
+  bool bReturn = message && message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED;
+  DELETE_AND_NULL(message);
 
   if (bReturn)
   {
@@ -574,8 +575,8 @@ bool CUSBCECAdapterCommands::PingAdapter(void)
 
   CCECAdapterMessage params;
   CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_PING, params);
-  bool bReturn = message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED;
-  delete message;
+  bool bReturn = message && message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED;
+  DELETE_AND_NULL(message);
   return bReturn;
 }
 
@@ -587,8 +588,8 @@ bool CUSBCECAdapterCommands::SetAckMask(uint16_t iMask)
   params.PushEscaped(iMask >> 8);
   params.PushEscaped((uint8_t)iMask);
   CCECAdapterMessage *message  = m_comm->SendCommand(MSGCODE_SET_ACK_MASK, params);
-  bool bReturn = message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED;
-  delete message;
+  bool bReturn = message && message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED;
+  DELETE_AND_NULL(message);
   return bReturn;
 }
 
@@ -601,7 +602,7 @@ void CUSBCECAdapterCommands::SetActiveSource(bool bSetTo, bool bClientUnregister
     CCECAdapterMessage params;
     params.PushEscaped(bSetTo ? 1 : 0);
     CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_SET_ACTIVE_SOURCE, params);
-    delete message;
+    DELETE_AND_NULL(message);
   }
 }
 
@@ -611,8 +612,8 @@ bool CUSBCECAdapterCommands::StartBootloader(void)
 
   CCECAdapterMessage params;
   CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_START_BOOTLOADER, params);
-  bool bReturn = message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED;
-  delete message;
+  bool bReturn = message && message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED;
+  DELETE_AND_NULL(message);
   return bReturn;
 }
 
@@ -622,8 +623,8 @@ bool CUSBCECAdapterCommands::SetLineTimeout(uint8_t iTimeout)
   CCECAdapterMessage params;
   params.PushEscaped(iTimeout);
   CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_TRANSMIT_IDLETIME, params);
-  bool bReturn = message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED;
-  delete message;
+  bool bReturn = message && message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED;
+  DELETE_AND_NULL(message);
   return bReturn;
 }
 
@@ -640,8 +641,8 @@ bool CUSBCECAdapterCommands::SetControlledMode(bool controlled)
   CCECAdapterMessage params;
   params.PushEscaped(controlled ? 1 : 0);
   CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_SET_CONTROLLED, params);
-  bool bReturn = message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED;
-  delete message;
+  bool bReturn = message && message->state == ADAPTER_MESSAGE_STATE_SENT_ACKED;
+  DELETE_AND_NULL(message);
 
   if (bReturn)
   {
index 07255a79c84fa5c52500d0da6362a048c95c3e1e..037359599be766fce14a87779e3405318393927f 100644 (file)
@@ -304,6 +304,7 @@ bool CUSBCECAdapterCommunication::HandlePoll(const CCECAdapterMessage &msg)
     m_lastPollDestination = msg.Destination();
     if (msg.Destination() < CECDEVICE_BROADCAST)
     {
+      CLockObject waitingLock(m_waitingMutex);
       if (!m_bWaitingForAck[msg.Destination()] && !msg.IsEOM())
       {
         if (m_callback)
@@ -328,7 +329,7 @@ void CUSBCECAdapterCommunication::MarkAsWaiting(const cec_logical_address dest)
   /* mark as waiting for an ack from the destination */
   if (dest < CECDEVICE_BROADCAST)
   {
-    CLockObject lock(m_mutex);
+    CLockObject waitingLock(m_waitingMutex);
     m_bWaitingForAck[dest] = true;
   }
 }
@@ -382,8 +383,7 @@ bool CUSBCECAdapterCommunication::WriteToDevice(CCECAdapterMessage *message)
   {
     LIB_CEC->AddLog(CEC_LOG_DEBUG, "error writing command '%s' to serial port '%s': %s", CCECAdapterMessage::ToString(message->Message()), m_port->GetName().c_str(), m_port->GetError().c_str());
     message->state = ADAPTER_MESSAGE_STATE_ERROR;
-    // this will trigger an alert in the reader thread
-    m_port->Close();
+    // let the higher level close the port
     return false;
   }
 
@@ -416,7 +416,7 @@ bool CUSBCECAdapterCommunication::ReadFromDevice(uint32_t iTimeout, size_t iSize
     if (m_port->GetErrorNumber())
     {
       LIB_CEC->AddLog(CEC_LOG_ERROR, "error reading from serial port: %s", m_port->GetError().c_str());
-      m_port->Close();
+      // let the higher level close the port
       return false;
     }
   }
@@ -729,6 +729,11 @@ void *CAdapterPingThread::Process(void)
         /* failed to ping the adapter 3 times in a row. something must be wrong with the connection */
         m_com->LIB_CEC->AddLog(CEC_LOG_ERROR, "failed to ping the adapter 3 times in a row. closing the connection.");
         m_com->StopThread(false);
+
+        libcec_parameter param;
+        param.paramData = NULL; param.paramType = CEC_PARAMETER_TYPE_UNKOWN;
+        m_com->LIB_CEC->Alert(CEC_ALERT_CONNECTION_LOST, param);
+
         break;
       }
     }
index ba5d7ca65bd40a4cc81e29fd3ea92a1ccb4ac87f..bac9437917cd4d06d3437aac331cf7568a426991 100644 (file)
@@ -182,6 +182,7 @@ namespace CEC
     CUSBCECAdapterCommands *                     m_commands;             /**< commands that can be sent to the adapter */
     CCECAdapterMessageQueue *                    m_adapterMessageQueue;  /**< the incoming and outgoing message queue */
     cec_logical_addresses                        m_logicalAddresses;     /**< the logical address list that this instance is using */
+    PLATFORM::CMutex                             m_waitingMutex;
   };
 
   class CAdapterEepromWriteThread : public PLATFORM::CThread
index 35ba386788a93dcab316b466da3230aca0957058..58bf4a562abd17697a85c15e5fe6bf99e2d237e9 100644 (file)
@@ -61,6 +61,8 @@ extern "C" {
 #include <libudev.h>
 }
 #elif defined(__FreeBSD__)
+#include <sys/param.h>
+#include <sys/sysctl.h>
 #include <stdio.h>
 #include <unistd.h>
 #endif
@@ -434,22 +436,77 @@ uint8_t CUSBCECAdapterDetection::FindAdapters(cec_adapter_descriptor *deviceList
   }
 #elif defined(__FreeBSD__)
   char devicePath[PATH_MAX + 1];
+  char infos[512];
+  char sysctlname[32];
+  char ttyname[8];
+  char *pos;
+  size_t infos_size = sizeof(infos);
   int i;
 
-  for (i = 0; i < 8; ++i)
+  for (i = 0; ; ++i)
   {
-    (void)snprintf(devicePath, sizeof(devicePath), "/dev/ttyU%d", i);
-    if (strDevicePath && strcmp(devicePath, strDevicePath) != 0)
+    unsigned int iVendor, iProduct;
+    memset(infos, 0, sizeof(infos));
+    (void)snprintf(sysctlname, sizeof(sysctlname),
+      "dev.umodem.%d.%%pnpinfo", i);
+    if (sysctlbyname(sysctlname, infos, &infos_size,
+      NULL, 0) != 0)
+        break;
+    pos = strstr(infos, "vendor=");
+    if (pos == NULL)
       continue;
-    if (!access(devicePath, 0))
-    {
-      snprintf(deviceList[iFound].strComPath, sizeof(deviceList[iFound].strComPath), "%s", devicePath);
-      snprintf(deviceList[iFound].strComName, sizeof(deviceList[iFound].strComName), "%s", devicePath);
-      deviceList[iFound].iVendorId = CEC_VID;
-      deviceList[iFound].iProductId = CEC_VID;
-      deviceList[iFound].adapterType = ADAPTERTYPE_P8_EXTERNAL; // will be overridden when not doing a "quick scan" by the actual type
-      iFound++;
+    sscanf(pos, "vendor=%x ", &iVendor);
+
+    pos = strstr(infos, "product=");
+    if (pos == NULL)
+      continue;
+    sscanf(pos, "product=%x ", &iProduct);
+
+    if (iVendor != CEC_VID || (iProduct != CEC_PID && iProduct != CEC_PID2))
+      continue;
+
+    pos = strstr(infos, "ttyname=");
+    if (pos == NULL)
+      continue;
+    sscanf(pos, "ttyname=%s ", ttyname);
+
+    (void)snprintf(devicePath, sizeof(devicePath),
+      "/dev/tty%s", ttyname);
+
+    if (strDevicePath) {
+      char currStrDevicePath[512];
+      int port = 0;
+      int devaddr = 0;
+      memset(currStrDevicePath, 0, sizeof(currStrDevicePath));
+      memset(infos, 0, sizeof(infos));
+      (void)snprintf(sysctlname, sizeof(sysctlname),
+        "dev.umodem.%d.%%location", i);
+      if (sysctlbyname(sysctlname, infos, &infos_size,
+        NULL, 0) != 0)
+          break;
+
+      pos = strstr(infos, "port=");
+      if (pos == NULL)
+        continue;
+      sscanf(pos, "port=%d ", &port);
+
+      pos = strstr(infos, "devaddr=");
+      if (pos == NULL)
+        continue;
+      sscanf(pos, "devaddr=%d ", &devaddr);
+
+      (void)snprintf(currStrDevicePath, sizeof(currStrDevicePath),
+        "/dev/ugen%d.%d", port, devaddr);
+
+      if (strcmp(currStrDevicePath, strDevicePath) != 0)
+        continue;
     }
+    snprintf(deviceList[iFound].strComPath, sizeof(deviceList[iFound].strComPath), "%s", devicePath);
+    snprintf(deviceList[iFound].strComName, sizeof(deviceList[iFound].strComName), "%s", devicePath);
+    deviceList[iFound].iVendorId = iVendor;
+    deviceList[iFound].iProductId = iProduct;
+    deviceList[iFound].adapterType = ADAPTERTYPE_P8_EXTERNAL; // will be overridden when not doing a "quick scan" by the actual type
+    iFound++;
   }
 #else
   //silence "unused" warnings
index a2cfbee65da002f306f7c74961871ca87065ba0b..489ded2cec4f441d379922e76f5be7459795c452 100644 (file)
@@ -41,6 +41,8 @@
 #include "lib/implementations/VLCommandHandler.h"
 #include "lib/implementations/PHCommandHandler.h"
 #include "lib/implementations/RLCommandHandler.h"
+#include "lib/implementations/RHCommandHandler.h"
+#include "lib/implementations/AQCommandHandler.h"
 #include "lib/LibCEC.h"
 #include "lib/CECTypeUtils.h"
 #include "lib/platform/util/timeutils.h"
@@ -59,6 +61,78 @@ using namespace PLATFORM;
 #define LIB_CEC     m_processor->GetLib()
 #define ToString(p) CCECTypeUtils::ToString(p)
 
+CResponse::CResponse(cec_opcode opcode) :
+    m_opcode(opcode)
+{
+}
+
+CResponse::~CResponse(void)
+{
+  Broadcast();
+}
+
+bool CResponse::Wait(uint32_t iTimeout)
+{
+  return m_event.Wait(iTimeout);
+}
+
+void CResponse::Broadcast(void)
+{
+  m_event.Broadcast();
+}
+
+CWaitForResponse::CWaitForResponse(void)
+{
+}
+
+CWaitForResponse::~CWaitForResponse(void)
+{
+  Clear();
+}
+
+void CWaitForResponse::Clear()
+{
+  PLATFORM::CLockObject lock(m_mutex);
+  for (std::map<cec_opcode, CResponse*>::iterator it = m_waitingFor.begin(); it != m_waitingFor.end(); it++)
+  {
+    it->second->Broadcast();
+    delete it->second;
+  }
+  m_waitingFor.clear();
+}
+
+bool CWaitForResponse::Wait(cec_opcode opcode, uint32_t iTimeout)
+{
+  CResponse *response = GetEvent(opcode);
+  return response ? response->Wait(iTimeout) : false;
+}
+
+void CWaitForResponse::Received(cec_opcode opcode)
+{
+  CResponse *response = GetEvent(opcode);
+  if (response)
+    response->Broadcast();
+}
+
+CResponse* CWaitForResponse::GetEvent(cec_opcode opcode)
+{
+  CResponse *retVal(NULL);
+  {
+    PLATFORM::CLockObject lock(m_mutex);
+    std::map<cec_opcode, CResponse*>::iterator it = m_waitingFor.find(opcode);
+    if (it != m_waitingFor.end())
+    {
+      retVal = it->second;
+    }
+    else
+    {
+      retVal = new CResponse(opcode);
+      m_waitingFor[opcode] = retVal;
+    }
+    return retVal;
+  }
+}
+
 CCECBusDevice::CCECBusDevice(CCECProcessor *processor, cec_logical_address iLogicalAddress, uint16_t iPhysicalAddress /* = CEC_INVALID_PHYSICAL_ADDRESS */) :
   m_type                  (CEC_DEVICE_TYPE_RESERVED),
   m_iPhysicalAddress      (iPhysicalAddress),
@@ -141,6 +215,12 @@ bool CCECBusDevice::ReplaceHandler(bool bActivateSource /* = true */)
         case CEC_VENDOR_TOSHIBA2:
           m_handler = new CRLCommandHandler(this, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending);
           break;
+        case CEC_VENDOR_ONKYO:
+          m_handler = new CRHCommandHandler(this, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending);
+          break;
+        case CEC_VENDOR_SHARP:
+          m_handler = new CAQCommandHandler(this, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending);
+          break;
         default:
           m_handler = new CCECCommandHandler(this, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending);
           break;
@@ -605,7 +685,7 @@ cec_power_status CCECBusDevice::GetPowerStatus(const cec_logical_address initiat
   if (bRequestUpdate)
   {
     CheckVendorIdRequested(initiator);
-    RequestPowerStatus(initiator);
+    RequestPowerStatus(initiator, bUpdate);
   }
 
   CLockObject lock(m_mutex);
@@ -642,7 +722,7 @@ bool CCECBusDevice::ImageViewOnSent(void)
   return m_bImageViewOnSent;
 }
 
-bool CCECBusDevice::RequestPowerStatus(const cec_logical_address initiator, bool bWaitForResponse /* = true */)
+bool CCECBusDevice::RequestPowerStatus(const cec_logical_address initiator, bool bUpdate, bool bWaitForResponse /* = true */)
 {
   bool bReturn(false);
 
@@ -650,7 +730,7 @@ bool CCECBusDevice::RequestPowerStatus(const cec_logical_address initiator, bool
       !IsUnsupportedFeature(CEC_OPCODE_GIVE_DEVICE_POWER_STATUS))
   {
     MarkBusy();
-    bReturn = m_handler->TransmitRequestPowerStatus(initiator, m_iLogicalAddress, bWaitForResponse);
+    bReturn = m_handler->TransmitRequestPowerStatus(initiator, m_iLogicalAddress, bUpdate, bWaitForResponse);
     if (!bReturn)
       SetPowerStatus(CEC_POWER_STATUS_UNKNOWN);
     MarkReady();
@@ -809,7 +889,7 @@ void CCECBusDevice::SetDeviceStatus(const cec_bus_device_status newStatus, cec_v
       if (m_deviceStatus != newStatus)
         LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): device status changed into 'handled by libCEC'", GetLogicalAddressName(), m_iLogicalAddress);
       SetPowerStatus   (CEC_POWER_STATUS_ON);
-      SetVendorId      (CEC_VENDOR_UNKNOWN);
+      SetVendorId      (CEC_VENDOR_PULSE_EIGHT);
       SetMenuState     (CEC_MENU_STATE_ACTIVATED);
       SetCecVersion    (libCECSpecVersion);
       SetStreamPath    (CEC_INVALID_PHYSICAL_ADDRESS);
@@ -1002,14 +1082,12 @@ void CCECBusDevice::MarkAsActiveSource(void)
     if ((*it)->GetLogicalAddress() != m_iLogicalAddress)
       (*it)->MarkAsInactiveSource();
 
-  if (bWasActivated)
-  {
-    if (IsHandledByLibCEC())
-      m_processor->SetActiveSource(true, false);
-    CCECClient *client = GetClient();
-    if (client)
-      client->SourceActivated(m_iLogicalAddress);
-  }
+  if (bWasActivated && IsHandledByLibCEC())
+    m_processor->SetActiveSource(true, false);
+
+  CCECClient *client = GetClient();
+  if (client)
+    client->SourceActivated(m_iLogicalAddress);
 }
 
 void CCECBusDevice::MarkAsInactiveSource(bool bClientUnregistered /* = false */)
@@ -1139,14 +1217,10 @@ void CCECBusDevice::SetActiveRoute(uint16_t iRoute)
     return;
 
   CCECBusDevice* newRoute = m_processor->GetDeviceByPhysicalAddress(iRoute, true);
-  if (newRoute)
+  if (newRoute && newRoute->IsHandledByLibCEC())
   {
     // we were made the active source, send notification
-    if (newRoute->IsHandledByLibCEC())
-      newRoute->ActivateSource();
-    // another device was made active
-    else
-      newRoute->MarkAsActiveSource();
+    newRoute->ActivateSource();
   }
 }
 
index e159aea2289d243b65d2b6bd83fd7d3b8d267d80..d227c0312749611f7bc753a51abab5de3542a1df 100644 (file)
@@ -50,22 +50,11 @@ namespace CEC
   class CResponse
   {
   public:
-    CResponse(cec_opcode opcode) :
-        m_opcode(opcode){}
-    ~CResponse(void)
-    {
-      Broadcast();
-    }
-
-    bool Wait(uint32_t iTimeout)
-    {
-      return m_event.Wait(iTimeout);
-    }
-
-    void Broadcast(void)
-    {
-      m_event.Broadcast();
-    }
+    CResponse(cec_opcode opcode);
+    ~CResponse(void);
+
+    bool Wait(uint32_t iTimeout);
+    void Broadcast(void);
 
   private:
     cec_opcode       m_opcode;
@@ -75,52 +64,15 @@ namespace CEC
   class CWaitForResponse
   {
   public:
-    CWaitForResponse(void) {}
-    ~CWaitForResponse(void)
-    {
-      Clear();
-    }
-
-    void Clear()
-    {
-      PLATFORM::CLockObject lock(m_mutex);
-      for (std::map<cec_opcode, CResponse*>::iterator it = m_waitingFor.begin(); it != m_waitingFor.end(); it++)
-        it->second->Broadcast();
-      m_waitingFor.clear();
-    }
-
-    bool Wait(cec_opcode opcode, uint32_t iTimeout = CEC_DEFAULT_TRANSMIT_WAIT)
-    {
-      CResponse *response = GetEvent(opcode);
-      return response ? response->Wait(iTimeout) : false;
-    }
-
-    void Received(cec_opcode opcode)
-    {
-      CResponse *response = GetEvent(opcode);
-      if (response)
-        response->Broadcast();
-    }
+    CWaitForResponse(void);
+    ~CWaitForResponse(void);
+
+    void Clear();
+    bool Wait(cec_opcode opcode, uint32_t iTimeout = CEC_DEFAULT_TRANSMIT_WAIT);
+    void Received(cec_opcode opcode);
 
   private:
-    CResponse *GetEvent(cec_opcode opcode)
-    {
-      CResponse *retVal(NULL);
-      {
-        PLATFORM::CLockObject lock(m_mutex);
-        std::map<cec_opcode, CResponse*>::iterator it = m_waitingFor.find(opcode);
-        if (it != m_waitingFor.end())
-        {
-          retVal = it->second;
-        }
-        else
-        {
-          retVal = new CResponse(opcode);
-          m_waitingFor[opcode] = retVal;
-        }
-        return retVal;
-      }
-    }
+    CResponse *GetEvent(cec_opcode opcode);
 
     PLATFORM::CMutex                 m_mutex;
     std::map<cec_opcode, CResponse*> m_waitingFor;
@@ -194,7 +146,7 @@ namespace CEC
     virtual void                  SetPowerStatus(const cec_power_status powerStatus);
     virtual void                  OnImageViewOnSent(bool bSentByLibCEC);
     virtual bool                  ImageViewOnSent(void);
-    virtual bool                  RequestPowerStatus(const cec_logical_address initiator, bool bWaitForResponse = true);
+    virtual bool                  RequestPowerStatus(const cec_logical_address initiator, bool bUpdate, bool bWaitForResponse = true);
     virtual bool                  TransmitPowerState(const cec_logical_address destination, bool bIsReply);
 
     virtual cec_vendor_id         GetCurrentVendorId(void);
index 16831a974c4680bd897b24ac54708bc4121348dc..7e0e9b9062eb977d4278c68613e98476f9acdc7a 100644 (file)
@@ -76,11 +76,6 @@ int CANCommandHandler::HandleVendorRemoteButtonDown(const cec_command &command)
   return COMMAND_HANDLED;
 }
 
-int CANCommandHandler::HandleVendorRemoteButtonUp(const cec_command &command)
-{
-  return HandleUserControlRelease(command);
-}
-
 bool CANCommandHandler::PowerOn(const cec_logical_address iInitiator, const cec_logical_address iDestination)
 {
   if (iDestination == CECDEVICE_AUDIOSYSTEM)
@@ -92,3 +87,32 @@ bool CANCommandHandler::PowerOn(const cec_logical_address iInitiator, const cec_
 
   return CCECCommandHandler::PowerOn(iInitiator, iDestination);
 }
+
+int CANCommandHandler::HandleDeviceVendorCommandWithId(const cec_command &command)
+{
+  if (!m_processor->IsHandledByLibCEC(command.destination))
+    return CEC_ABORT_REASON_INVALID_OPERAND;
+
+  // samsung's vendor id
+  if (command.parameters[0] == 0x00 && command.parameters[1] == 0x00 && command.parameters[2] == 0xf0)
+  {
+    // unknown vendor command sent to devices
+    if (command.parameters[3] == 0x23)
+    {
+      cec_command response;
+      cec_command::Format(response, command.destination, command.initiator, CEC_OPCODE_VENDOR_COMMAND_WITH_ID);
+
+      // samsung vendor id
+      response.parameters.PushBack(0x00); response.parameters.PushBack(0x00); response.parameters.PushBack(0xf0);
+
+      // XXX see bugzid 2164. reply sent back by audio systems, we might have to send something different
+      response.parameters.PushBack(0x24);
+      response.parameters.PushBack(0x00);
+      response.parameters.PushBack(0x80);
+
+      Transmit(response, false, true);
+      return COMMAND_HANDLED;
+    }
+  }
+  return CEC_ABORT_REASON_INVALID_OPERAND;
+}
index bc4b921cf83f7eb4f0e8adad7116997d4f009826..595170ac887101088f5627b9db9f8c2a300bfba3 100644 (file)
@@ -46,7 +46,7 @@ namespace CEC
     virtual ~CANCommandHandler(void) {};
 
     int HandleVendorRemoteButtonDown(const cec_command &command);
-    int HandleVendorRemoteButtonUp(const cec_command &command);
+    int HandleDeviceVendorCommandWithId(const cec_command &command);
 
   protected:
     bool PowerOn(const cec_logical_address iInitiator, const cec_logical_address iDestination);
diff --git a/src/lib/implementations/AQCommandHandler.cpp b/src/lib/implementations/AQCommandHandler.cpp
new file mode 100644 (file)
index 0000000..93bba24
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2013 Pulse-Eight Limited.  All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing       <license@pulse-eight.com>
+ *     http://www.pulse-eight.com/
+ *     http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include "AQCommandHandler.h"
+
+#include "lib/devices/CECBusDevice.h"
+#include "lib/CECProcessor.h"
+#include "lib/LibCEC.h"
+#include "lib/CECClient.h"
+
+using namespace CEC;
+using namespace PLATFORM;
+
+#define LIB_CEC     m_busDevice->GetProcessor()->GetLib()
+#define ToString(p) LIB_CEC->ToString(p)
+
+CAQCommandHandler::CAQCommandHandler(CCECBusDevice *busDevice,
+                                     int32_t iTransmitTimeout /* = CEC_DEFAULT_TRANSMIT_TIMEOUT */,
+                                     int32_t iTransmitWait /* = CEC_DEFAULT_TRANSMIT_WAIT */,
+                                     int8_t iTransmitRetries /* = CEC_DEFAULT_TRANSMIT_RETRIES */,
+                                     int64_t iActiveSourcePending /* = 0 */) :
+    CCECCommandHandler(busDevice, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending),
+    m_powerOnCheck(NULL)
+{
+  m_vendorId = CEC_VENDOR_SHARP;
+}
+
+CAQCommandHandler::~CAQCommandHandler(void)
+{
+  delete m_powerOnCheck;
+}
+
+bool CAQCommandHandler::PowerOn(const cec_logical_address iInitiator, const cec_logical_address iDestination)
+{
+  bool bCheck(false);
+  bool bRetval(false);
+  if (m_busDevice->GetCurrentPowerStatus() != CEC_POWER_STATUS_ON && (!m_powerOnCheck || !m_powerOnCheck->IsRunning()))
+    bCheck = true;
+  bRetval = CCECCommandHandler::PowerOn(iInitiator, iDestination);
+
+  if (bRetval && bCheck)
+  {
+    if (!m_powerOnCheck)
+      m_powerOnCheck = new CAQPowerStatusCheck(this, iInitiator, iDestination);
+    if (m_powerOnCheck)
+      m_powerOnCheck->CreateThread();
+  }
+
+  return bRetval;
+}
+
+void* CAQPowerStatusCheck::Process(void)
+{
+  // sleep for 2 seconds and query the power status
+  Sleep(2000);
+  if (m_handler->m_busDevice->GetProcessor()->GetDevice(m_iDestination)->GetPowerStatus(m_iInitiator, true) == CEC_POWER_STATUS_STANDBY)
+    m_handler->m_busDevice->GetProcessor()->GetLib()->AddLog(CEC_LOG_WARNING, "AQUOS LINK 'auto power on' is disabled, which prevents the TV from being powered on. To correct this, press the menu button on your remote, go to 'link operation' -> 'AQUOS LINK setup' -> 'Auto power on' and set it to 'On'");
+  return NULL;
+}
diff --git a/src/lib/implementations/AQCommandHandler.h b/src/lib/implementations/AQCommandHandler.h
new file mode 100644 (file)
index 0000000..6833b41
--- /dev/null
@@ -0,0 +1,74 @@
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2013 Pulse-Eight Limited.  All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing       <license@pulse-eight.com>
+ *     http://www.pulse-eight.com/
+ *     http://www.pulse-eight.net/
+ */
+
+#include "CECCommandHandler.h"
+#include "lib/platform/threads/threads.h"
+
+namespace CEC
+{
+  class CAQPowerStatusCheck;
+
+  class CAQCommandHandler : public CCECCommandHandler
+  {
+    friend class CAQPowerStatusCheck;
+  public:
+    CAQCommandHandler(CCECBusDevice *busDevice,
+                      int32_t iTransmitTimeout = CEC_DEFAULT_TRANSMIT_TIMEOUT,
+                      int32_t iTransmitWait = CEC_DEFAULT_TRANSMIT_WAIT,
+                      int8_t iTransmitRetries = CEC_DEFAULT_TRANSMIT_RETRIES,
+                      int64_t iActiveSourcePending = 0);
+    virtual ~CAQCommandHandler(void);
+
+  protected:
+    virtual bool PowerOn(const cec_logical_address iInitiator, const cec_logical_address iDestination);
+
+  private:
+    CAQPowerStatusCheck* m_powerOnCheck;
+  };
+
+  class CAQPowerStatusCheck : public PLATFORM::CThread
+  {
+  public:
+    CAQPowerStatusCheck(CAQCommandHandler* handler, cec_logical_address iInitiator, cec_logical_address iDestination) :
+      m_handler(handler),
+      m_iInitiator(iInitiator),
+      m_iDestination(iDestination) {}
+    virtual ~CAQPowerStatusCheck(void) {}
+
+  private:
+    void* Process(void);
+    CAQCommandHandler* m_handler;
+    cec_logical_address m_iInitiator;
+    cec_logical_address m_iDestination;
+  };
+};
index 2859d5aaddc74dccff69528b2be31ac2a3fb6856..29d1ffbcc7444b9725555de8f7f76d7d1b28fa58 100644 (file)
@@ -257,6 +257,14 @@ int CCECCommandHandler::HandleDeviceVendorCommandWithId(const cec_command & UNUS
 int CCECCommandHandler::HandleDeviceVendorId(const cec_command &command)
 {
   SetVendorId(command);
+
+  if (command.initiator == CECDEVICE_TV)
+  {
+    CCECBusDevice* primary = m_processor->GetPrimaryDevice();
+    if (primary)
+      primary->TransmitVendorID(CECDEVICE_BROADCAST, false, false);
+  }
+
   return COMMAND_HANDLED;
 }
 
@@ -455,6 +463,13 @@ int CCECCommandHandler::HandleReportPhysicalAddress(const cec_command &command)
   {
     uint16_t iNewAddress = ((uint16_t)command.parameters[0] << 8) | ((uint16_t)command.parameters[1]);
     SetPhysicalAddress(command.initiator, iNewAddress);
+
+    if (command.initiator == CECDEVICE_TV)
+    {
+      CCECBusDevice* primary = m_processor->GetPrimaryDevice();
+      if (primary)
+        primary->TransmitPhysicalAddress(false);
+    }
     return COMMAND_HANDLED;
   }
   return CEC_ABORT_REASON_INVALID_OPERAND;
@@ -580,7 +595,10 @@ int CCECCommandHandler::HandleSetStreamPath(const cec_command &command)
       if (device->IsHandledByLibCEC() && !device->IsActiveSource())
         device->ActivateSource();
       else
+      {
         device->MarkAsActiveSource();
+        device->TransmitActiveSource(true);
+      }
       return COMMAND_HANDLED;
     }
   }
@@ -910,12 +928,12 @@ bool CCECCommandHandler::TransmitRequestPhysicalAddress(const cec_logical_addres
   return Transmit(command, !bWaitForResponse, false);
 }
 
-bool CCECCommandHandler::TransmitRequestPowerStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWaitForResponse /* = true */)
+bool CCECCommandHandler::TransmitRequestPowerStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bUpdate, bool bWaitForResponse /* = true */)
 {
   if (iDestination == CECDEVICE_TV)
   {
     int64_t now(GetTimeMs());
-    if (now - m_iPowerStatusRequested < REQUEST_POWER_STATUS_TIMEOUT)
+    if (!bUpdate && now - m_iPowerStatusRequested < REQUEST_POWER_STATUS_TIMEOUT)
       return true;
     m_iPowerStatusRequested = now;
   }
@@ -1207,7 +1225,7 @@ bool CCECCommandHandler::ActivateSource(bool bTransmitDelayedCommandsOnly /* = f
     bool bTvPresent = (tv && tv->GetStatus() == CEC_DEVICE_STATUS_PRESENT);
     bool bActiveSourceFailed(false);
     if (bTvPresent)
-      bActiveSourceFailed = !m_busDevice->TransmitImageViewOn();
+      bActiveSourceFailed = !tv->PowerOn(m_busDevice->GetLogicalAddress());
     else
       LIB_CEC->AddLog(CEC_LOG_DEBUG, "TV not present, not sending 'image view on'");
 
@@ -1230,6 +1248,14 @@ bool CCECCommandHandler::ActivateSource(bool bTransmitDelayedCommandsOnly /* = f
         if (playbackDevice && SendDeckStatusUpdateOnActiveSource())
           bActiveSourceFailed = !playbackDevice->TransmitDeckStatus(CECDEVICE_TV, false);
       }
+
+      // update system audio mode for audiosystem devices
+      if (bTvPresent && !bActiveSourceFailed)
+      {
+        CCECAudioSystem* audioDevice = m_busDevice->AsAudioSystem();
+        if (audioDevice)
+          bActiveSourceFailed = !audioDevice->TransmitSetSystemAudioMode(CECDEVICE_TV, false);
+      }
     }
 
     // retry later
index 9902a08bc7ec9c9fd6ec9e5bbf39911e73d35ad5..aeace0233a3ae673ed1a71977b858c29689b915e 100644 (file)
@@ -58,7 +58,7 @@ namespace CEC
     virtual bool HandleCommand(const cec_command &command);
     virtual cec_vendor_id GetVendorId(void) { return m_vendorId; };
     virtual void SetVendorId(cec_vendor_id vendorId) { m_vendorId = vendorId; }
-    static bool HasSpecificHandler(cec_vendor_id vendorId) { return vendorId == CEC_VENDOR_LG || vendorId == CEC_VENDOR_SAMSUNG || vendorId == CEC_VENDOR_PANASONIC || vendorId == CEC_VENDOR_PHILIPS;}
+    static bool HasSpecificHandler(cec_vendor_id vendorId) { return vendorId == CEC_VENDOR_LG || vendorId == CEC_VENDOR_SAMSUNG || vendorId == CEC_VENDOR_PANASONIC || vendorId == CEC_VENDOR_PHILIPS || vendorId == CEC_VENDOR_SHARP;}
 
     virtual bool InitHandler(void) { return true; }
     virtual bool ActivateSource(bool bTransmitDelayedCommandsOnly = false);
@@ -73,7 +73,7 @@ namespace CEC
     virtual bool TransmitRequestOSDName(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWaitForResponse = true);
     virtual bool TransmitRequestAudioStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWaitForResponse = true);
     virtual bool TransmitRequestPhysicalAddress(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWaitForResponse = true);
-    virtual bool TransmitRequestPowerStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWaitForResponse = true);
+    virtual bool TransmitRequestPowerStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bUpdate, bool bWaitForResponse = true);
     virtual bool TransmitRequestVendorId(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWaitForResponse = true);
     virtual bool TransmitActiveSource(const cec_logical_address iInitiator, uint16_t iPhysicalAddress, bool bIsReply);
     virtual bool TransmitCECVersion(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_version cecVersion, bool bIsReply);
@@ -138,7 +138,7 @@ namespace CEC
     virtual int HandleUserControlRelease(const cec_command &command);
     virtual int HandleVendorCommand(const cec_command &command);
     virtual int HandleVendorRemoteButtonDown(const cec_command& command);
-    virtual int HandleVendorRemoteButtonUp(const cec_command & UNUSED(command)) { return COMMAND_HANDLED; }
+    virtual int HandleVendorRemoteButtonUp(const cec_command& command) { return HandleUserControlRelease(command); }
     virtual void UnhandledCommand(const cec_command &command, const cec_abort_reason reason);
     virtual void RequestEmailFromCustomer(const cec_command& command);
 
index d7e484860304788a3365089d938a4cbc9ca52e84..edb084c853af0fd7d0f6eda2c27b1872c09dbbe6 100644 (file)
@@ -152,9 +152,8 @@ int CPHCommandHandler::HandleDeviceVendorId(const cec_command& command)
   return CCECCommandHandler::HandleDeviceVendorId(command);
 }
 
-bool CPHCommandHandler::TransmitVendorID(const cec_logical_address iInitiator, const cec_logical_address iDestination, uint64_t UNUSED(iVendorId), bool UNUSED(bIsReply))
+bool CPHCommandHandler::TransmitVendorID(const cec_logical_address iInitiator, const cec_logical_address iDestination, uint64_t UNUSED(iVendorId), bool bIsReply)
 {
-  LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) -> %s (%X): vendor id feature abort", ToString(iInitiator), iInitiator, ToString(iDestination), iDestination);
-  m_processor->TransmitAbort(iInitiator, iDestination, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID);
-  return true;
+  // XXX hack around the hack in CPHCommandHandler::InitHandler
+  return CCECCommandHandler::TransmitVendorID(iInitiator, iDestination, CEC_VENDOR_PULSE_EIGHT, bIsReply);
 }
index f6f3fcc8fcbb2623716bafc1f75fdd02a5f4904f..5e300479b9fbf8ba4dd54654dcd71171dd1d527c 100644 (file)
@@ -71,7 +71,6 @@ namespace CEC
     virtual int HandleUserControlRelease(const cec_command& command);
     virtual bool TransmitVendorID(const cec_logical_address iInitiator, const cec_logical_address iDestination, uint64_t iVendorId, bool bIsReply);
     virtual int HandleDeviceVendorId(const cec_command& command);
-    virtual int HandleVendorRemoteButtonUp(const cec_command & command) { return HandleUserControlRelease(command); }
     uint8_t            m_iLastKeyCode;
     CImageViewOnCheck* m_imageViewOnCheck;
   };
diff --git a/src/lib/implementations/RHCommandHandler.cpp b/src/lib/implementations/RHCommandHandler.cpp
new file mode 100644 (file)
index 0000000..66c9065
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2013 Pulse-Eight Limited.  All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing       <license@pulse-eight.com>
+ *     http://www.pulse-eight.com/
+ *     http://www.pulse-eight.net/
+ */
+
+#include "env.h"
+#include "RHCommandHandler.h"
+
+#include "lib/devices/CECBusDevice.h"
+#include "lib/CECProcessor.h"
+#include "lib/LibCEC.h"
+#include "lib/CECClient.h"
+
+using namespace CEC;
+
+#define LIB_CEC     m_busDevice->GetProcessor()->GetLib()
+#define ToString(p) LIB_CEC->ToString(p)
+
+CRHCommandHandler::CRHCommandHandler(CCECBusDevice *busDevice,
+                                     int32_t iTransmitTimeout /* = CEC_DEFAULT_TRANSMIT_TIMEOUT */,
+                                     int32_t iTransmitWait /* = CEC_DEFAULT_TRANSMIT_WAIT */,
+                                     int8_t iTransmitRetries /* = CEC_DEFAULT_TRANSMIT_RETRIES */,
+                                     int64_t iActiveSourcePending /* = 0 */) :
+    CCECCommandHandler(busDevice, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending)
+{
+  m_vendorId = CEC_VENDOR_ONKYO;
+}
+
+int CRHCommandHandler::HandleDeviceVendorCommandWithId(const cec_command &command)
+{
+  // onkyo's vendor id
+  if (command.parameters[0] == 0x00 && command.parameters[1] == 0x09 && command.parameters[2] == 0xb0)
+  {
+    // ignore unknown vendor commands sent by onkyo devices, bugzid: 2559
+  }
+  return CEC_ABORT_REASON_INVALID_OPERAND;
+
+}
diff --git a/src/lib/implementations/RHCommandHandler.h b/src/lib/implementations/RHCommandHandler.h
new file mode 100644 (file)
index 0000000..1992262
--- /dev/null
@@ -0,0 +1,51 @@
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2013 Pulse-Eight Limited.  All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing       <license@pulse-eight.com>
+ *     http://www.pulse-eight.com/
+ *     http://www.pulse-eight.net/
+ */
+
+#include "CECCommandHandler.h"
+
+namespace CEC
+{
+  class CRHCommandHandler : public CCECCommandHandler
+  {
+  public:
+    CRHCommandHandler(CCECBusDevice *busDevice,
+                      int32_t iTransmitTimeout = CEC_DEFAULT_TRANSMIT_TIMEOUT,
+                      int32_t iTransmitWait = CEC_DEFAULT_TRANSMIT_WAIT,
+                      int8_t iTransmitRetries = CEC_DEFAULT_TRANSMIT_RETRIES,
+                      int64_t iActiveSourcePending = 0);
+    virtual ~CRHCommandHandler(void) {};
+
+  protected:
+    int HandleDeviceVendorCommandWithId(const cec_command &command);
+  };
+};
index ec12b0226f7279191c1d92c6c7472ce1e166dc35..ff47e1e8bc6e5fce27c854aa4b9a07273720ff8b 100644 (file)
 using namespace CEC;
 using namespace PLATFORM;
 
-#define SL_COMMAND_UNKNOWN_01           0x01
-#define SL_COMMAND_UNKNOWN_02           0x02
-
 #define SL_COMMAND_TYPE_HDDRECORDER_DISC  0x01
 #define SL_COMMAND_TYPE_VCR               0x02
 #define SL_COMMAND_TYPE_DVDPLAYER         0x03
 #define SL_COMMAND_TYPE_HDDRECORDER_DISC2 0x04
 #define SL_COMMAND_TYPE_HDDRECORDER       0x05
 
-#define SL_COMMAND_REQUEST_POWER_STATUS 0xa0
+#define SL_COMMAND_INIT                 0x01
+#define SL_COMMAND_ACK_INIT             0x02
 #define SL_COMMAND_POWER_ON             0x03
 #define SL_COMMAND_CONNECT_REQUEST      0x04
 #define SL_COMMAND_SET_DEVICE_MODE      0x05
+#define SL_COMMAND_REQUEST_POWER_STATUS 0xa0
 
 #define LIB_CEC     m_busDevice->GetProcessor()->GetLib()
 #define ToString(p) LIB_CEC->ToString(p)
@@ -65,8 +64,7 @@ CSLCommandHandler::CSLCommandHandler(CCECBusDevice *busDevice,
                                      int8_t iTransmitRetries /* = CEC_DEFAULT_TRANSMIT_RETRIES */,
                                      int64_t iActiveSourcePending /* = 0 */) :
     CCECCommandHandler(busDevice, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending),
-    m_bSLEnabled(false),
-    m_bActiveSourceSent(false)
+    m_bSLEnabled(false)
 {
   m_vendorId = CEC_VENDOR_LG;
 
@@ -98,74 +96,20 @@ bool CSLCommandHandler::InitHandler(void)
       primary->SetVendorId(CEC_VENDOR_LG);
       primary->ReplaceHandler(false);
     }
-
-    if (m_busDevice->GetLogicalAddress() == CECDEVICE_TV)
-    {
-      /* start as 'in transition standby->on' */
-      primary->SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON);
-      primary->TransmitPowerState(CECDEVICE_TV, false);
-
-      /* send the vendor id */
-      primary->TransmitVendorID(CECDEVICE_BROADCAST, false, false);
-    }
   }
 
   return true;
 }
 
-int CSLCommandHandler::HandleActiveSource(const cec_command &command)
-{
-  if (command.parameters.size == 2)
-  {
-    uint16_t iAddress = ((uint16_t)command.parameters[0] << 8) | ((uint16_t)command.parameters[1]);
-    CCECBusDevice *device = m_processor->GetDeviceByPhysicalAddress(iAddress);
-    if (device)
-      device->MarkAsActiveSource();
-
-    {
-      CLockObject lock(m_SLMutex);
-      m_bActiveSourceSent = false;
-    }
-
-    return COMMAND_HANDLED;
-  }
-
-  return CEC_ABORT_REASON_INVALID_OPERAND;
-
-}
-
-int CSLCommandHandler::HandleDeviceVendorId(const cec_command &command)
-{
-  SetVendorId(command);
-
-  if (!SLInitialised() && command.initiator == CECDEVICE_TV)
-  {
-    CCECBusDevice *destination = m_processor->GetDevice(command.destination);
-    if (destination && (destination->GetLogicalAddress() == CECDEVICE_BROADCAST || destination->IsHandledByLibCEC()))
-    {
-      cec_logical_address initiator = destination->GetLogicalAddress();
-      if (initiator == CECDEVICE_BROADCAST)
-        initiator = m_processor->GetPrimaryDevice()->GetLogicalAddress();
-
-      cec_command response;
-      cec_command::Format(response, initiator, command.initiator, CEC_OPCODE_FEATURE_ABORT);
-      Transmit(response, false, true);
-      return COMMAND_HANDLED;
-    }
-  }
-
-  return CCECCommandHandler::HandleDeviceVendorId(command);
-}
-
 int CSLCommandHandler::HandleVendorCommand(const cec_command &command)
 {
   if (!m_processor->IsHandledByLibCEC(command.destination))
     return true;
 
   if (command.parameters.size == 1 &&
-      command.parameters[0] == SL_COMMAND_UNKNOWN_01)
+      command.parameters[0] == SL_COMMAND_INIT)
   {
-    HandleVendorCommand01(command);
+    HandleVendorCommandSLInit(command);
     return COMMAND_HANDLED;
   }
   else if (command.parameters.size == 2 &&
@@ -190,21 +134,26 @@ int CSLCommandHandler::HandleVendorCommand(const cec_command &command)
   return CCECCommandHandler::HandleVendorCommand(command);
 }
 
-void CSLCommandHandler::HandleVendorCommand01(const cec_command &command)
+void CSLCommandHandler::HandleVendorCommandSLInit(const cec_command &command)
 {
-  m_processor->GetPrimaryDevice()->SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON);
-  TransmitVendorCommand0205(command.destination, command.initiator);
-
   CCECBusDevice* dev = m_processor->GetDevice(command.destination);
-  if (dev && dev->IsHandledByLibCEC() && dev->IsActiveSource())
-    dev->TransmitActiveSource(false);
+  if (dev && dev->IsHandledByLibCEC())
+  {
+    if (!dev->IsActiveSource())
+    {
+      dev->SetPowerStatus(CEC_POWER_STATUS_STANDBY);
+      dev->TransmitPowerState(command.initiator, true);
+    }
+
+    TransmitVendorCommandSLAckInit(command.destination, command.initiator);
+  }
 }
 
-void CSLCommandHandler::TransmitVendorCommand0205(const cec_logical_address iSource, const cec_logical_address iDestination)
+void CSLCommandHandler::TransmitVendorCommandSLAckInit(const cec_logical_address iSource, const cec_logical_address iDestination)
 {
   cec_command response;
   cec_command::Format(response, iSource, iDestination, CEC_OPCODE_VENDOR_COMMAND);
-  response.PushBack(SL_COMMAND_UNKNOWN_02);
+  response.PushBack(SL_COMMAND_ACK_INIT);
   response.PushBack(SL_COMMAND_TYPE_HDDRECORDER);
 
   Transmit(response, false, true);
@@ -228,10 +177,9 @@ void CSLCommandHandler::HandleVendorCommandPowerOn(const cec_command &command)
     device->SetPowerStatus(CEC_POWER_STATUS_ON);
     device->TransmitPowerState(command.initiator, false);
     device->TransmitPhysicalAddress(false);
-    {
-      CLockObject lock(m_SLMutex);
-      m_bActiveSourceSent = false;
-    }
+
+    if (device->IsActiveSource())
+      ActivateSource();
   }
 }
 void CSLCommandHandler::HandleVendorCommandPowerOnStatus(const cec_command &command)
@@ -253,7 +201,15 @@ void CSLCommandHandler::HandleVendorCommandSLConnect(const cec_command &command)
   SetSLInitialised();
   TransmitVendorCommandSetDeviceMode(command.destination, command.initiator, CEC_DEVICE_TYPE_RECORDING_DEVICE);
 
-  ActivateSource();
+
+  if (m_processor->IsActiveSource(command.destination) && m_processor->IsHandledByLibCEC(command.destination))
+  {
+    CCECBusDevice* dev = m_processor->GetDevice(command.destination);
+    CCECPlaybackDevice* pb = dev->AsPlaybackDevice();
+    if (pb)
+      pb->TransmitDeckStatus(command.initiator, true);
+    dev->TransmitPowerState(command.initiator, true);
+  }
 }
 
 void CSLCommandHandler::TransmitVendorCommandSetDeviceMode(const cec_logical_address iSource, const cec_logical_address iDestination, const cec_device_type type)
@@ -279,8 +235,7 @@ int CSLCommandHandler::HandleGiveDeckStatus(const cec_command &command)
   if (command.parameters[0] == CEC_STATUS_REQUEST_ON)
   {
     device->TransmitDeckStatus(command.initiator, true);
-    if (!ActiveSourceSent())
-      ActivateSource();
+    ActivateSource();
     return COMMAND_HANDLED;
   }
   else if (command.parameters[0] == CEC_STATUS_REQUEST_ONCE)
@@ -304,20 +259,10 @@ int CSLCommandHandler::HandleGiveDevicePowerStatus(const cec_command &command)
     }
     else
     {
-      if (!ActiveSourceSent())
-      {
-        device->SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON);
-        device->TransmitPowerState(command.initiator, true);
-        ActivateSource();
-      }
-      else if (m_resetPowerState.IsSet() && m_resetPowerState.TimeLeft() > 0)
+      if (m_resetPowerState.IsSet() && m_resetPowerState.TimeLeft() > 0)
       {
         /* TODO assume that we've bugged out. the return button no longer works after this */
         LIB_CEC->AddLog(CEC_LOG_WARNING, "FIXME: LG seems to have bugged out. resetting to 'in transition standby to on'. the return button will not work");
-        {
-          CLockObject lock(m_SLMutex);
-          m_bActiveSourceSent = false;
-        }
         device->SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON);
         device->TransmitPowerState(command.initiator, true);
         device->SetPowerStatus(CEC_POWER_STATUS_ON);
@@ -340,22 +285,25 @@ int CSLCommandHandler::HandleRequestActiveSource(const cec_command &command)
 {
   if (m_processor->CECInitialised())
   {
-    if (ActiveSourceSent())
-      LIB_CEC->AddLog(CEC_LOG_DEBUG, ">> %i requests active source, ignored", (uint8_t) command.initiator);
-    else
-      ActivateSource();
-    return COMMAND_HANDLED;
+    if (!SLInitialised())
+      TransmitVendorCommandSLAckInit(m_processor->GetPrimaryDevice()->GetLogicalAddress(), command.initiator);
+    CCECCommandHandler::HandleRequestActiveSource(command);
   }
   return CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND;
 }
 
 int CSLCommandHandler::HandleFeatureAbort(const cec_command &command)
 {
-  if (command.parameters.size == 0 && m_processor->GetPrimaryDevice()->GetCurrentPowerStatus() == CEC_POWER_STATUS_ON && !SLInitialised() &&
+  CCECBusDevice* primary = m_processor->GetPrimaryDevice();
+  if (command.parameters.size == 0 && primary->GetLogicalAddress() != CECDEVICE_UNKNOWN &&
+      primary->GetCurrentPowerStatus() == CEC_POWER_STATUS_ON && !SLInitialised() &&
       command.initiator == CECDEVICE_TV)
   {
-    m_processor->GetPrimaryDevice()->TransmitPowerState(command.initiator, false);
-    m_processor->GetPrimaryDevice()->TransmitVendorID(CECDEVICE_BROADCAST, false, false);
+    if (!SLInitialised() && m_processor->IsActiveSource(command.destination))
+    {
+      TransmitVendorCommandSLAckInit(command.destination, command.initiator);
+      return COMMAND_HANDLED;
+    }
   }
 
   return CCECCommandHandler::HandleFeatureAbort(command);
@@ -363,11 +311,7 @@ int CSLCommandHandler::HandleFeatureAbort(const cec_command &command)
 
 int CSLCommandHandler::HandleStandby(const cec_command &command)
 {
-  if (command.initiator == CECDEVICE_TV)
-  {
-    CLockObject lock(m_SLMutex);
-    m_bActiveSourceSent = false;
-  }
+  ResetSLState();
 
   return CCECCommandHandler::HandleStandby(command);
 }
@@ -377,7 +321,6 @@ void CSLCommandHandler::ResetSLState(void)
   LIB_CEC->AddLog(CEC_LOG_NOTICE, "resetting SL initialised state");
   CLockObject lock(m_SLMutex);
   m_bSLEnabled = false;
-  m_bActiveSourceSent = false;
   m_processor->GetPrimaryDevice()->SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON);
 }
 
@@ -394,12 +337,6 @@ bool CSLCommandHandler::SLInitialised(void)
   return m_bSLEnabled;
 }
 
-bool CSLCommandHandler::ActiveSourceSent(void)
-{
-  CLockObject lock(m_SLMutex);
-  return m_bActiveSourceSent;
-}
-
 bool CSLCommandHandler::PowerOn(const cec_logical_address iInitiator, const cec_logical_address iDestination)
 {
   if (iDestination != CECDEVICE_TV)
@@ -419,9 +356,73 @@ bool CSLCommandHandler::PowerOn(const cec_logical_address iInitiator, const cec_
   return CCECCommandHandler::PowerOn(iInitiator, iDestination);
 }
 
-void CSLCommandHandler::VendorPreActivateSourceHook(void)
+bool CSLCommandHandler::ActivateSource(bool bTransmitDelayedCommandsOnly /* = false */)
 {
-  CCECPlaybackDevice *device = m_busDevice->AsPlaybackDevice();
-  if (device)
-    device->SetDeckStatus(!device->IsActiveSource() ? CEC_DECK_INFO_OTHER_STATUS : CEC_DECK_INFO_OTHER_STATUS_LG);
+  if (m_busDevice->IsActiveSource() &&
+      m_busDevice->IsHandledByLibCEC())
+  {
+    {
+      CLockObject lock(m_mutex);
+      // check if we need to send a delayed source switch
+      if (bTransmitDelayedCommandsOnly)
+      {
+        if (m_iActiveSourcePending == 0 || GetTimeMs() < m_iActiveSourcePending)
+          return false;
+
+#ifdef CEC_DEBUGGING
+        LIB_CEC->AddLog(CEC_LOG_DEBUG, "transmitting delayed activate source command");
+#endif
+      }
+    }
+
+    CCECPlaybackDevice *device = m_busDevice->AsPlaybackDevice();
+    if (device)
+      device->SetDeckStatus(!device->IsActiveSource() ? CEC_DECK_INFO_OTHER_STATUS : CEC_DECK_INFO_OTHER_STATUS_LG);
+
+    // power on the TV
+    CCECBusDevice* tv = m_processor->GetDevice(CECDEVICE_TV);
+    bool bTvPresent = (tv && tv->GetStatus() == CEC_DEVICE_STATUS_PRESENT);
+    bool bActiveSourceFailed(false);
+    if (bTvPresent)
+    {
+      bActiveSourceFailed = !device->TransmitImageViewOn();
+    }
+    else
+    {
+      LIB_CEC->AddLog(CEC_LOG_DEBUG, "TV not present, not sending 'image view on'");
+    }
+
+    // check if we're allowed to switch sources
+    bool bSourceSwitchAllowed = SourceSwitchAllowed();
+    if (!bSourceSwitchAllowed)
+      LIB_CEC->AddLog(CEC_LOG_DEBUG, "source switch is currently not allowed by command handler");
+
+    // switch sources (if allowed)
+    if (!bActiveSourceFailed && bSourceSwitchAllowed)
+    {
+      bActiveSourceFailed = !m_busDevice->TransmitActiveSource(false);
+    }
+
+    // retry later
+    if (bActiveSourceFailed || !bSourceSwitchAllowed)
+    {
+      LIB_CEC->AddLog(CEC_LOG_DEBUG, "failed to make '%s' the active source. will retry later", m_busDevice->GetLogicalAddressName());
+      int64_t now(GetTimeMs());
+      CLockObject lock(m_mutex);
+      if (m_iActiveSourcePending == 0 || m_iActiveSourcePending < now)
+        m_iActiveSourcePending = now + (int64_t)CEC_ACTIVE_SOURCE_SWITCH_RETRY_TIME_MS;
+      return false;
+    }
+    else
+    {
+      CLockObject lock(m_mutex);
+      // clear previous pending active source command
+      m_iActiveSourcePending = 0;
+    }
+
+    // mark the handler as initialised
+    CLockObject lock(m_mutex);
+    m_bHandlerInited = true;
+  }
+  return true;
 }
index ac8cb5c66fa515bee3a89f151c4b680abf5fe4ed..166bac02609e9027515d8e3cf658dd9affb978e5 100644 (file)
@@ -46,14 +46,13 @@ namespace CEC
     virtual ~CSLCommandHandler(void) {};
 
     bool InitHandler(void);
+    bool ActivateSource(bool bTransmitDelayedCommandsOnly = false);
 
   protected:
-    int HandleActiveSource(const cec_command &command);
-    int HandleDeviceVendorId(const cec_command &command);
     int HandleVendorCommand(const cec_command &command);
 
-    void HandleVendorCommand01(const cec_command &command);
-    void TransmitVendorCommand0205(const cec_logical_address iSource, const cec_logical_address iDestination);
+    void HandleVendorCommandSLInit(const cec_command &command);
+    void TransmitVendorCommandSLAckInit(const cec_logical_address iSource, const cec_logical_address iDestination);
 
     void HandleVendorCommandPowerOn(const cec_command &command);
     void HandleVendorCommandPowerOnStatus(const cec_command &command);
@@ -68,17 +67,12 @@ namespace CEC
     int HandleStandby(const cec_command &command);
     bool TransmitMenuState(const cec_logical_address UNUSED(iInitiator), const cec_logical_address UNUSED(iDestination), cec_menu_state UNUSED(menuState), bool UNUSED(bIsReply)) { return true; }
     bool PowerOn(const cec_logical_address iInitiator, const cec_logical_address iDestination);
-    int HandleVendorRemoteButtonUp(const cec_command& command) { return HandleUserControlRelease(command); }
 
     void ResetSLState(void);
     bool SLInitialised(void);
     void SetSLInitialised(void);
-    bool ActiveSourceSent(void);
-
-    void VendorPreActivateSourceHook(void);
 
     bool               m_bSLEnabled;
-    bool               m_bActiveSourceSent;
     PLATFORM::CTimeout m_resetPowerState;
     PLATFORM::CMutex   m_SLMutex;
   };
index 44feabc4f4e5efe0e6cd74739121605646ca74fd..0e74a06cd052b35b2af409571947e0c2e4da74bc 100644 (file)
@@ -106,23 +106,28 @@ int CVLCommandHandler::HandleDeviceVendorCommandWithId(const cec_command &comman
       command.parameters[2] != 0x45)
     return CEC_ABORT_REASON_INVALID_OPERAND;
 
-  // XXX this is also sent when the TV is powered off
-#if 0
   if (command.initiator == CECDEVICE_TV &&
       command.parameters.At(3) == VL_UNKNOWN1)
   {
-    // set the power up event time
+    if (command.parameters.size >= 5 && command.parameters.At(4) == 0x05)
     {
-      CLockObject lock(m_mutex);
-      if (m_iPowerUpEventReceived == 0)
-        m_iPowerUpEventReceived = GetTimeMs();
+      // set the power up event time
+      {
+        CLockObject lock(m_mutex);
+        if (m_iPowerUpEventReceived == 0)
+          m_iPowerUpEventReceived = GetTimeMs();
+      }
+      // mark the TV as powered on
+      m_processor->GetTV()->SetPowerStatus(CEC_POWER_STATUS_ON);
+
+      CCECBusDevice* dev = m_processor->GetPrimaryDevice();
+      if (dev && dev->IsActiveSource())
+        dev->TransmitActiveSource(false);
+
+      return COMMAND_HANDLED;
     }
-    // mark the TV as powered on
-    m_processor->GetTV()->SetPowerStatus(CEC_POWER_STATUS_ON);
   }
-  else
-#endif
-    if (command.initiator == CECDEVICE_TV &&
+  else if (command.initiator == CECDEVICE_TV &&
       command.destination == CECDEVICE_BROADCAST &&
       command.parameters.At(3) == VL_POWER_CHANGE)
   {
@@ -248,10 +253,15 @@ int CVLCommandHandler::HandleVendorCommand(const cec_command &command)
   if (command.parameters.size == 3 &&
       command.parameters[0] == 0x10 &&
       command.parameters[1] == 0x01 &&
-      command.parameters[2] == 0x05 &&
       m_processor->IsHandledByLibCEC(command.destination))
   {
+    // XXX i've seen 0x05 and 0x03 as third param. these probably indicate different types of TVs/capabilities
+    // when we feature abort this, then the TV will try the same thing with a vendor command with id
     SendVendorCommandCapabilities(m_processor->GetLogicalAddress(), command.initiator);
+
+    CCECBusDevice* dev = m_processor->GetDevice(command.destination);
+    if (dev && dev->IsActiveSource())
+      dev->ActivateSource(500);
     return COMMAND_HANDLED;
   }
 
@@ -261,7 +271,7 @@ int CVLCommandHandler::HandleVendorCommand(const cec_command &command)
 bool CVLCommandHandler::SourceSwitchAllowed(void)
 {
   if (!PowerUpEventReceived())
-    TransmitRequestPowerStatus(m_processor->GetPrimaryDevice()->GetLogicalAddress(), CECDEVICE_TV, false);
+    TransmitRequestPowerStatus(m_processor->GetPrimaryDevice()->GetLogicalAddress(), CECDEVICE_TV, false, false);
 
   return PowerUpEventReceived();
 }
index b6c2cafb6e49247d121db9f1085d9a426be0db68..03ca91d373d06d5aef8fd35eadf394532916e1a0 100644 (file)
@@ -43,6 +43,7 @@
 #include "../lib/platform/os.h"
 #include "../lib/implementations/CECCommandHandler.h"
 #include "../lib/platform/util/StdString.h"
+#include "../lib/platform/threads/threads.h"
 
 using namespace CEC;
 using namespace std;
@@ -52,6 +53,8 @@ using namespace PLATFORM;
 
 #include "../../include/cecloader.h"
 
+static void PrintToStdOut(const char *strFormat, ...);
+
 ICECCallbacks        g_callbacks;
 libcec_configuration g_config;
 int                  g_cecLogLevel(-1);
@@ -63,8 +66,38 @@ bool                 g_bSingleCommand(false);
 bool                 g_bExit(false);
 bool                 g_bHardExit(false);
 CMutex               g_outputMutex;
+ICECAdapter*         g_parser;
+
+class CReconnect : public PLATFORM::CThread
+{
+public:
+  static CReconnect& Get(void)
+  {
+    static CReconnect _instance;
+    return _instance;
+  }
+
+  virtual ~CReconnect(void) {}
+
+  void* Process(void)
+  {
+    if (g_parser)
+    {
+      g_parser->Close();
+      if (!g_parser->Open(g_strPort.c_str()))
+      {
+        PrintToStdOut("Failed to reconnect\n");
+        g_bExit = true;
+      }
+    }
+    return NULL;
+  }
+
+private:
+  CReconnect(void) {}
+};
 
-inline void PrintToStdOut(const char *strFormat, ...)
+static void PrintToStdOut(const char *strFormat, ...)
 {
   CStdString strLog;
 
@@ -186,8 +219,11 @@ int CecAlert(void *UNUSED(cbParam), const libcec_alert type, const libcec_parame
   switch (type)
   {
   case CEC_ALERT_CONNECTION_LOST:
-    PrintToStdOut("Connection lost - exiting\n");
-    g_bExit = true;
+    if (!CReconnect::Get().IsRunning())
+    {
+      PrintToStdOut("Connection lost - trying to reconnect\n");
+      CReconnect::Get().CreateThread(false);
+    }
     break;
   default:
     break;
@@ -1190,8 +1226,8 @@ int main (int argc, char *argv[])
     g_config.deviceTypes.Add(CEC_DEVICE_TYPE_RECORDING_DEVICE);
   }
 
-  ICECAdapter *parser = LibCecInitialise(&g_config);
-  if (!parser)
+  g_parser = LibCecInitialise(&g_config);
+  if (!g_parser)
   {
 #ifdef __WINDOWS__
     cout << "Cannot load libcec.dll" << endl;
@@ -1199,19 +1235,19 @@ int main (int argc, char *argv[])
     cout << "Cannot load libcec.so" << endl;
 #endif
 
-    if (parser)
-      UnloadLibCec(parser);
+    if (g_parser)
+      UnloadLibCec(g_parser);
 
     return 1;
   }
 
   // init video on targets that need this
-  parser->InitVideoStandalone();
+  g_parser->InitVideoStandalone();
 
   if (!g_bSingleCommand)
   {
     CStdString strLog;
-    strLog.Format("CEC Parser created - libCEC version %s", parser->ToString((cec_server_version)g_config.serverVersion));
+    strLog.Format("CEC Parser created - libCEC version %s", g_parser->ToString((cec_server_version)g_config.serverVersion));
     cout << strLog.c_str() << endl;
 
     //make stdin non-blocking
@@ -1227,13 +1263,13 @@ int main (int argc, char *argv[])
     if (!g_bSingleCommand)
       cout << "no serial port given. trying autodetect: ";
     cec_adapter devices[10];
-    uint8_t iDevicesFound = parser->FindAdapters(devices, 10, NULL);
+    uint8_t iDevicesFound = g_parser->FindAdapters(devices, 10, NULL);
     if (iDevicesFound <= 0)
     {
       if (g_bSingleCommand)
         cout << "autodetect ";
       cout << "FAILED" << endl;
-      UnloadLibCec(parser);
+      UnloadLibCec(g_parser);
       return 1;
     }
     else
@@ -1249,10 +1285,10 @@ int main (int argc, char *argv[])
 
   PrintToStdOut("opening a connection to the CEC adapter...");
 
-  if (!parser->Open(g_strPort.c_str()))
+  if (!g_parser->Open(g_strPort.c_str()))
   {
     PrintToStdOut("unable to open the device on port %s", g_strPort.c_str());
-    UnloadLibCec(parser);
+    UnloadLibCec(g_parser);
     return 1;
   }
 
@@ -1265,7 +1301,7 @@ int main (int argc, char *argv[])
     getline(cin, input);
     cin.clear();
 
-    if (ProcessConsoleCommand(parser, input) && !g_bSingleCommand && !g_bExit && !g_bHardExit)
+    if (ProcessConsoleCommand(g_parser, input) && !g_bSingleCommand && !g_bExit && !g_bHardExit)
     {
       if (!input.empty())
         PrintToStdOut("waiting for input");
@@ -1277,8 +1313,8 @@ int main (int argc, char *argv[])
       CEvent::Sleep(50);
   }
 
-  parser->Close();
-  UnloadLibCec(parser);
+  g_parser->Close();
+  UnloadLibCec(g_parser);
 
   if (g_logOutput.is_open())
     g_logOutput.close();