From: Lars Op den Kamp Date: Tue, 11 Sep 2012 12:54:14 +0000 (+0200) Subject: Merge branch 'master' into release X-Git-Tag: upstream/2.2.0~1^2~18 X-Git-Url: https://git.piment-noir.org/?a=commitdiff_plain;h=217b236882e3f4e5303a135aae39f6207bfbd279;hp=34a9cecdd92f6b2844f9c4054da202b152ab2217;p=deb_libcec.git Merge branch 'master' into release --- diff --git a/ChangeLog b/ChangeLog index 5c43fc2..b2e908e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,32 @@ +libcec (1.9.1-1) unstable; urgency=low + + * changed/added: + * added the type of adapter to libcec_configuration, + and display the type in cec-client -l + * added device detection support for composite usb devices on windows. + needs the windows ddk, and it's expected to be found in + C:\WinDDK\7600.16385.1 + + * interface changes: + * adapter type was added to libcec_configuration + * moved cec_adapter_messagecode from cectypes.h to USBCECAdapterMessage.h + + * fixed: + * retry m_port->Read(..) if an EINTR errror occurs instead of closing the + connection. credits @Obruni. closes #38 + * make cec-client include cecloader.h from our project, not from system + * fixed duplicate entries check in CUSBCECAdapterDetection + * fixed missing cec_version updates in libcec_configuration + * transmit an active source message after to a device + that's handled by libCEC. closes #43 + * rpi: handle vendor specific remote control presses. closes #42 + * rpi: handle VC_CEC_LOGICAL_ADDR_LOST, sent by the Pi's firmware when + the logical address was taken while CEC was being reinitialised + * panasonic: send out an active source message when the tv started up + because it sometimes doesn't request this + + -- Pulse-Eight Packaging Wed, 5 Sep 2012 16:54:00 +0100 + libcec (1.8.2-1) unstable; urgency=low * changed/added: diff --git a/configure.ac b/configure.ac index ae1b5a5..0d09d42 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ AC_PREREQ(2.59) -AC_INIT([libcec], [1:8:0], [http://libcec.pulse-eight.com/]) +AC_INIT([libcec], [1:9:0], [http://libcec.pulse-eight.com/]) AC_CONFIG_HEADERS([config.h]) AH_TOP([#pragma once]) diff --git a/debian/changelog b/debian/changelog index 5c43fc2..b2e908e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,32 @@ +libcec (1.9.1-1) unstable; urgency=low + + * changed/added: + * added the type of adapter to libcec_configuration, + and display the type in cec-client -l + * added device detection support for composite usb devices on windows. + needs the windows ddk, and it's expected to be found in + C:\WinDDK\7600.16385.1 + + * interface changes: + * adapter type was added to libcec_configuration + * moved cec_adapter_messagecode from cectypes.h to USBCECAdapterMessage.h + + * fixed: + * retry m_port->Read(..) if an EINTR errror occurs instead of closing the + connection. credits @Obruni. closes #38 + * make cec-client include cecloader.h from our project, not from system + * fixed duplicate entries check in CUSBCECAdapterDetection + * fixed missing cec_version updates in libcec_configuration + * transmit an active source message after to a device + that's handled by libCEC. closes #43 + * rpi: handle vendor specific remote control presses. closes #42 + * rpi: handle VC_CEC_LOGICAL_ADDR_LOST, sent by the Pi's firmware when + the logical address was taken while CEC was being reinitialised + * panasonic: send out an active source message when the tv started up + because it sometimes doesn't request this + + -- Pulse-Eight Packaging Wed, 5 Sep 2012 16:54:00 +0100 + libcec (1.8.2-1) unstable; urgency=low * changed/added: diff --git a/driver/p8usb-cec.inf b/driver/p8usb-cec.inf index 9c89626..f196ddf 100644 --- a/driver/p8usb-cec.inf +++ b/driver/p8usb-cec.inf @@ -1,4 +1,4 @@ -; Copyright (c) 2011 Pulse-Eight Limited +; Copyright (c) 2012 Pulse-Eight Limited [Version] Signature="$Windows NT$" @@ -7,7 +7,7 @@ ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318} Provider=%MFGNAME% LayoutFile=layout.inf CatalogFile=%MFGFILENAME%.cat -DriverVer=07/04/2011,1.0.0.0 +DriverVer=08/29/2012,1.1.0.0 [Manufacturer] %MFGNAME%=DeviceList, NTamd64 @@ -22,61 +22,68 @@ DefaultDestDir=12 ;------------------------------------------------------------------------------ [DriverInstall.nt] -include=mdmcpq.inf -CopyFiles=FakeModemCopyFileSection -AddReg=DriverInstall.nt.AddReg +include = mdmcpq.inf +CopyFiles = FakeModemCopyFileSection +AddReg = DriverInstall.nt.AddReg [DriverInstall.nt.AddReg] HKR,,DevLoader,,*ntkern HKR,,NTMPDriver,,%DRIVERFILENAME%.sys HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider" +HKR,,PortSubClass,1,01 [DriverInstall.nt.Services] -AddService=usbser, 0x00000002, DriverService.nt +AddService = usbser, 0x00000002, DriverService.nt [DriverService.nt] -DisplayName=%SERVICE% -ServiceType=1 -StartType=3 -ErrorControl=1 -ServiceBinary=%12%\%DRIVERFILENAME%.sys +DisplayName = %SERVICE% +ServiceType = 1 ; SERVICE_KERNEL_DRIVER +StartType = 3 ; SERVICE_DEMAND_START +ErrorControl = 1 ; SERVICE_ERROR_NORMAL +ServiceBinary = %12%\%DRIVERFILENAME%.sys +LoadOrderGroup = Base ;------------------------------------------------------------------------------ ; Vista-64bit Sections ;------------------------------------------------------------------------------ [DriverInstall.NTamd64] -include=mdmcpq.inf -CopyFiles=FakeModemCopyFileSection -AddReg=DriverInstall.NTamd64.AddReg +include = mdmcpq.inf +CopyFiles = FakeModemCopyFileSection +AddReg = DriverInstall.NTamd64.AddReg [DriverInstall.NTamd64.AddReg] HKR,,DevLoader,,*ntkern HKR,,NTMPDriver,,%DRIVERFILENAME%.sys HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider" +HKR,,PortSubClass,1,01 [DriverInstall.NTamd64.Services] -AddService=usbser, 0x00000002, DriverService.NTamd64 +AddService = usbser, 0x00000002, DriverService.NTamd64 [DriverService.NTamd64] -DisplayName=%SERVICE% -ServiceType=1 -StartType=3 -ErrorControl=1 -ServiceBinary=%12%\%DRIVERFILENAME%.sys +DisplayName = %SERVICE% +ServiceType = 1 ; SERVICE_KERNEL_DRIVER +StartType = 3 ; SERVICE_DEMAND_START +ErrorControl = 1 ; SERVICE_ERROR_NORMAL +ServiceBinary = %12%\%DRIVERFILENAME%.sys +LoadOrderGroup = Base [SourceDisksFiles] [SourceDisksNames] [DeviceList] -%DESCRIPTION%=DriverInstall, USB\VID_2548&PID_1001 +%DESCRIPTION2% = DriverInstall, USB\VID_2548&PID_1002&MI_00 +%DESCRIPTION% = DriverInstall, USB\VID_2548&PID_1001 [DeviceList.NTamd64] -%DESCRIPTION%=DriverInstall, USB\VID_2548&PID_1001 +%DESCRIPTION2% = DriverInstall, USB\VID_2548&PID_1002&MI_00 +%DESCRIPTION% = DriverInstall, USB\VID_2548&PID_1001 [Strings] -MFGFILENAME="p8usb-cec" -DRIVERFILENAME ="usbser" -MFGNAME="Pulse-Eight Limited" -INSTDISK="Pulse-Eight USB-CEC Installation Disc" -DESCRIPTION="Pulse-Eight USB to HDMI CEC Adapter" -SERVICE="USB to HDMI-CEC" +MFGFILENAME = "p8usb-cec" +DRIVERFILENAME = "usbser" +MFGNAME = "Pulse-Eight Limited" +INSTDISK = "Pulse-Eight USB-CEC Installation Disc" +DESCRIPTION = "Pulse-Eight USB to HDMI CEC Adapter" +DESCRIPTION2 = "Pulse-Eight USB to HDMI CEC Adapter (rev.2)" +SERVICE = "USB to HDMI-CEC" diff --git a/include/cec.h b/include/cec.h index bd56fff..f5e7590 100644 --- a/include/cec.h +++ b/include/cec.h @@ -36,7 +36,7 @@ #include "cectypes.h" -#define LIBCEC_VERSION_CURRENT CEC_SERVER_VERSION_1_8_1 +#define LIBCEC_VERSION_CURRENT CEC_SERVER_VERSION_1_9_0 namespace CEC { @@ -500,6 +500,8 @@ namespace CEC * Should be called as first call to libCEC, directly after CECInitialise() and before using Open() */ virtual void InitVideoStandalone(void) = 0; + + virtual const char *ToString(const cec_adapter_type type) = 0; }; }; diff --git a/include/cectypes.h b/include/cectypes.h index 4656141..291190c 100644 --- a/include/cectypes.h +++ b/include/cectypes.h @@ -120,7 +120,7 @@ namespace CEC { #define CEC_MIN_LIB_VERSION 1 #define CEC_LIB_VERSION_MAJOR 1 #define CEC_LIB_VERSION_MAJOR_STR "1" -#define CEC_LIB_VERSION_MINOR 8 +#define CEC_LIB_VERSION_MINOR 9 typedef enum cec_abort_reason { @@ -615,52 +615,6 @@ typedef enum cec_log_level CEC_LOG_ALL = 31 } cec_log_level; -typedef enum cec_adapter_messagecode -{ - MSGCODE_NOTHING = 0, - MSGCODE_PING, - MSGCODE_TIMEOUT_ERROR, - MSGCODE_HIGH_ERROR, - MSGCODE_LOW_ERROR, - MSGCODE_FRAME_START, - MSGCODE_FRAME_DATA, - MSGCODE_RECEIVE_FAILED, - MSGCODE_COMMAND_ACCEPTED, - MSGCODE_COMMAND_REJECTED, - MSGCODE_SET_ACK_MASK, - MSGCODE_TRANSMIT, - MSGCODE_TRANSMIT_EOM, - MSGCODE_TRANSMIT_IDLETIME, - MSGCODE_TRANSMIT_ACK_POLARITY, - MSGCODE_TRANSMIT_LINE_TIMEOUT, - MSGCODE_TRANSMIT_SUCCEEDED, - MSGCODE_TRANSMIT_FAILED_LINE, - MSGCODE_TRANSMIT_FAILED_ACK, - MSGCODE_TRANSMIT_FAILED_TIMEOUT_DATA, - MSGCODE_TRANSMIT_FAILED_TIMEOUT_LINE, - MSGCODE_FIRMWARE_VERSION, - MSGCODE_START_BOOTLOADER, - MSGCODE_GET_BUILDDATE, - MSGCODE_SET_CONTROLLED, - MSGCODE_GET_AUTO_ENABLED, - MSGCODE_SET_AUTO_ENABLED, - MSGCODE_GET_DEFAULT_LOGICAL_ADDRESS, - MSGCODE_SET_DEFAULT_LOGICAL_ADDRESS, - MSGCODE_GET_LOGICAL_ADDRESS_MASK, - MSGCODE_SET_LOGICAL_ADDRESS_MASK, - MSGCODE_GET_PHYSICAL_ADDRESS, - MSGCODE_SET_PHYSICAL_ADDRESS, - MSGCODE_GET_DEVICE_TYPE, - MSGCODE_SET_DEVICE_TYPE, - MSGCODE_GET_HDMI_VERSION, - MSGCODE_SET_HDMI_VERSION, - MSGCODE_GET_OSD_NAME, - MSGCODE_SET_OSD_NAME, - MSGCODE_WRITE_EEPROM, - MSGCODE_FRAME_EOM = 0x80, - MSGCODE_FRAME_ACK = 0x40, -} cec_adapter_messagecode; - typedef enum cec_bus_device_status { CEC_DEVICE_STATUS_UNKNOWN, @@ -693,6 +647,14 @@ typedef enum cec_vendor_id CEC_VENDOR_UNKNOWN = 0 } cec_vendor_id; +typedef enum cec_adapter_type +{ + ADAPTERTYPE_UNKNOWN = 0, + ADAPTERTYPE_P8_EXTERNAL = 0x1, + ADAPTERTYPE_P8_DAUGHTERBOARD = 0x2, + ADAPTERTYPE_RPI = 0x100 +} cec_adapter_type; + typedef struct cec_menu_language { char language[4]; /**< the iso language code. @bug the language code is only 3 chars long, not 4. will be changed in v2.0, because changing it now would break backwards compat */ @@ -1231,7 +1193,9 @@ typedef enum cec_client_version CEC_CLIENT_VERSION_1_7_1 = 0x1701, CEC_CLIENT_VERSION_1_7_2 = 0x1702, CEC_CLIENT_VERSION_1_8_0 = 0x1800, - CEC_CLIENT_VERSION_1_8_1 = 0x1801 + CEC_CLIENT_VERSION_1_8_1 = 0x1801, + CEC_CLIENT_VERSION_1_8_2 = 0x1802, + CEC_CLIENT_VERSION_1_9_0 = 0x1900 } cec_client_version; typedef enum cec_server_version @@ -1249,7 +1213,9 @@ typedef enum cec_server_version CEC_SERVER_VERSION_1_7_1 = 0x1701, CEC_SERVER_VERSION_1_7_2 = 0x1702, CEC_SERVER_VERSION_1_8_0 = 0x1800, - CEC_SERVER_VERSION_1_8_1 = 0x1801 + CEC_SERVER_VERSION_1_8_1 = 0x1801, + CEC_SERVER_VERSION_1_8_2 = 0x1802, + CEC_SERVER_VERSION_1_9_0 = 0x1900 } cec_server_version; typedef struct libcec_configuration @@ -1286,6 +1252,7 @@ typedef struct libcec_configuration uint32_t iFirmwareBuildDate; /*!< (read-only) the build date of the firmware, in seconds since epoch. if not available, this value will be set to 0. added in 1.6.2 */ uint8_t bMonitorOnly; /*!< won't allocate a CCECClient when starting the connection when set (same as monitor mode). added in 1.6.3 */ cec_version cecVersion; /*!< CEC spec version to use by libCEC. defaults to v1.4. added in 1.8.0 */ + cec_adapter_type adapterType; /*!< type of the CEC adapter that we're connected to. added in 1.8.2 */ #ifdef __cplusplus // @todo re-add in v2.0 (breaks ABI) @@ -1323,7 +1290,9 @@ typedef struct libcec_configuration /* libcec 1.6.3+ */ (other.clientVersion < CEC_CLIENT_VERSION_1_6_3 || bMonitorOnly == other.bMonitorOnly) && /* libcec 1.8.0+ */ - (other.clientVersion < CEC_CLIENT_VERSION_1_8_0 || cecVersion == other.cecVersion)); + (other.clientVersion < CEC_CLIENT_VERSION_1_8_0 || cecVersion == other.cecVersion) && + /* libcec 1.8.2+ */ + (other.clientVersion < CEC_CLIENT_VERSION_1_8_2 || adapterType == other.adapterType)); } bool operator!=(const libcec_configuration &other) const @@ -1356,6 +1325,7 @@ typedef struct libcec_configuration iFirmwareBuildDate = CEC_FW_BUILD_UNKNOWN; bMonitorOnly = 0; cecVersion = (cec_version)CEC_DEFAULT_SETTING_CEC_VERSION; + adapterType = ADAPTERTYPE_UNKNOWN; memset(strDeviceName, 0, 13); deviceTypes.clear(); diff --git a/project/cec-config.rc b/project/cec-config.rc index 9355214..7940825 100644 Binary files a/project/cec-config.rc and b/project/cec-config.rc differ diff --git a/project/libcec.rc b/project/libcec.rc index 05e40fe..7b488df 100644 Binary files a/project/libcec.rc and b/project/libcec.rc differ diff --git a/project/libcec.vcxproj b/project/libcec.vcxproj index 3c26ad7..dd529e1 100644 --- a/project/libcec.vcxproj +++ b/project/libcec.vcxproj @@ -159,19 +159,23 @@ $(SolutionDir)..\include;$(IncludePath) + C:\WinDDK\7600.16385.1\lib\win7\i386;$(LibraryPath) $(SolutionDir)..\include;$(IncludePath) + C:\WinDDK\7600.16385.1\lib\win7\amd64;$(LibraryPath) $(SolutionDir)..\build\ libcec $(SolutionDir)..\include;$(IncludePath) + C:\WinDDK\7600.16385.1\lib\win7\i386;$(LibraryPath) $(SolutionDir)..\build\ $(ProjectName).x64 $(SolutionDir)..\include;$(IncludePath) + C:\WinDDK\7600.16385.1\lib\win7\amd64;$(LibraryPath) diff --git a/project/testclient.rc b/project/testclient.rc index 8d5a34b..c227b7e 100644 Binary files a/project/testclient.rc and b/project/testclient.rc differ diff --git a/src/CecSharpTester/CecSharpClient.cs b/src/CecSharpTester/CecSharpClient.cs index 0d58134..dca7ce0 100644 --- a/src/CecSharpTester/CecSharpClient.cs +++ b/src/CecSharpTester/CecSharpClient.cs @@ -43,7 +43,7 @@ namespace CecSharpClient Config = new LibCECConfiguration(); Config.DeviceTypes.Types[0] = CecDeviceType.RecordingDevice; Config.DeviceName = "CEC Tester"; - Config.ClientVersion = CecClientVersion.Version1_8_1; + Config.ClientVersion = CecClientVersion.Version1_9_0; Config.SetCallbacks(this); LogLevel = (int)CecLogLevel.All; diff --git a/src/CecSharpTester/Properties/AssemblyInfo.cs b/src/CecSharpTester/Properties/AssemblyInfo.cs index 7161761..53d167c 100644 --- a/src/CecSharpTester/Properties/AssemblyInfo.cs +++ b/src/CecSharpTester/Properties/AssemblyInfo.cs @@ -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("1.8.1.0")] -[assembly: AssemblyFileVersion("1.8.1.0")] +[assembly: AssemblyVersion("1.9.0.0")] +[assembly: AssemblyFileVersion("1.9.0.0")] diff --git a/src/LibCecSharp/AssemblyInfo.cpp b/src/LibCecSharp/AssemblyInfo.cpp index 8cfa0ad..9f633ca 100644 --- a/src/LibCecSharp/AssemblyInfo.cpp +++ b/src/LibCecSharp/AssemblyInfo.cpp @@ -13,7 +13,7 @@ using namespace System::Security::Permissions; [assembly:AssemblyTrademarkAttribute("")]; [assembly:AssemblyCultureAttribute("")]; -[assembly:AssemblyVersionAttribute("1.8.1.0")]; +[assembly:AssemblyVersionAttribute("1.9.0.0")]; [assembly:ComVisible(false)]; [assembly:CLSCompliantAttribute(true)]; diff --git a/src/LibCecSharp/CecSharpTypes.h b/src/LibCecSharp/CecSharpTypes.h index 7b02c0d..52c0b20 100644 --- a/src/LibCecSharp/CecSharpTypes.h +++ b/src/LibCecSharp/CecSharpTypes.h @@ -371,7 +371,9 @@ namespace CecSharp Version1_7_1 = 0x1701, Version1_7_2 = 0x1702, Version1_8_0 = 0x1800, - Version1_8_1 = 0x1801 + Version1_8_1 = 0x1801, + Version1_8_2 = 0x1802, + Version1_9_0 = 0x1900 }; public enum class CecServerVersion @@ -389,7 +391,9 @@ namespace CecSharp Version1_7_1 = 0x1701, Version1_7_2 = 0x1702, Version1_8_0 = 0x1800, - Version1_8_1 = 0x1801 + Version1_8_1 = 0x1801, + Version1_8_2 = 0x1802, + Version1_9_0 = 0x1900 }; public ref class CecAdapter diff --git a/src/cec-config-gui/CecConfigGUI.cs b/src/cec-config-gui/CecConfigGUI.cs index 7521b09..0e83c6a 100644 --- a/src/cec-config-gui/CecConfigGUI.cs +++ b/src/cec-config-gui/CecConfigGUI.cs @@ -28,7 +28,7 @@ namespace CecConfigGui Config.DeviceTypes.Types[0] = CecDeviceType.RecordingDevice; Config.DeviceName = "CEC Config"; Config.GetSettingsFromROM = true; - Config.ClientVersion = CecClientVersion.Version1_8_1; + Config.ClientVersion = CecClientVersion.Version1_9_0; Callbacks = new CecCallbackWrapper(this); Config.SetCallbacks(Callbacks); LoadXMLConfiguration(ref Config); diff --git a/src/cec-config-gui/Properties/AssemblyInfo.cs b/src/cec-config-gui/Properties/AssemblyInfo.cs index 91c1763..891de3e 100644 --- a/src/cec-config-gui/Properties/AssemblyInfo.cs +++ b/src/cec-config-gui/Properties/AssemblyInfo.cs @@ -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("1.8.1.0")] -[assembly: AssemblyFileVersion("1.8.1.0")] +[assembly: AssemblyVersion("1.9.0.0")] +[assembly: AssemblyFileVersion("1.9.0.0")] diff --git a/src/cec-config/cec-config.cpp b/src/cec-config/cec-config.cpp index d7775e9..a3d2b77 100644 --- a/src/cec-config/cec-config.cpp +++ b/src/cec-config/cec-config.cpp @@ -159,7 +159,7 @@ bool OpenConnection(cec_device_type type = CEC_DEVICE_TYPE_RECORDING_DEVICE) g_config.Clear(); snprintf(g_config.strDeviceName, 13, "CEC-config"); g_config.callbackParam = NULL; - g_config.clientVersion = (uint32_t)CEC_CLIENT_VERSION_1_8_1; + g_config.clientVersion = (uint32_t)CEC_CLIENT_VERSION_1_9_0; g_callbacks.CBCecLogMessage = &CecLogMessage; g_callbacks.CBCecKeyPress = &CecKeyPress; g_callbacks.CBCecCommand = &CecCommand; diff --git a/src/lib/CECClient.cpp b/src/lib/CECClient.cpp index e7ac955..c9525af 100644 --- a/src/lib/CECClient.cpp +++ b/src/lib/CECClient.cpp @@ -802,6 +802,14 @@ bool CCECClient::GetCurrentConfiguration(libcec_configuration &configuration) configuration.bMonitorOnly = m_configuration.bMonitorOnly; } + // client version 1.8.0 + if (configuration.clientVersion >= CEC_CLIENT_VERSION_1_8_0) + configuration.cecVersion = m_configuration.cecVersion; + + // client version 1.8.2 + if (configuration.clientVersion >= CEC_CLIENT_VERSION_1_8_2) + configuration.adapterType = m_configuration.adapterType; + return true; } @@ -859,6 +867,14 @@ bool CCECClient::SetConfiguration(const libcec_configuration &configuration) m_configuration.bMonitorOnly = configuration.bMonitorOnly; } + // client version 1.8.0 + if (configuration.clientVersion >= CEC_CLIENT_VERSION_1_8_0) + m_configuration.cecVersion = configuration.cecVersion; + + // client version 1.8.2 + if (configuration.clientVersion >= CEC_CLIENT_VERSION_1_8_2) + m_configuration.adapterType = configuration.adapterType; + // ensure that there is at least 1 device type set if (m_configuration.deviceTypes.IsEmpty()) m_configuration.deviceTypes.Add(CEC_DEVICE_TYPE_RECORDING_DEVICE); diff --git a/src/lib/CECProcessor.cpp b/src/lib/CECProcessor.cpp index 88795e9..9d49640 100644 --- a/src/lib/CECProcessor.cpp +++ b/src/lib/CECProcessor.cpp @@ -63,13 +63,17 @@ CCECProcessor::CCECProcessor(CLibCEC *libcec) : m_iStandardLineTimeout(3), m_iRetryLineTimeout(3), m_iLastTransmission(0), - m_bMonitor(true) + m_bMonitor(true), + m_addrAllocator(NULL), + m_bStallCommunication(false) { m_busDevices = new CCECDeviceMap(this); } CCECProcessor::~CCECProcessor(void) { + m_bStallCommunication = false; + DELETE_AND_NULL(m_addrAllocator); Close(); DELETE_AND_NULL(m_busDevices); } @@ -410,6 +414,9 @@ bool CCECProcessor::Transmit(const cec_command &data, bool bIsReply) } } + // wait until we finished allocating a new LA if it got lost + while (m_bStallCommunication) Sleep(5); + { CLockObject lock(m_mutex); m_iLastTransmission = GetTimeMs(); @@ -604,6 +611,7 @@ bool CCECProcessor::GetDeviceInformation(const char *strPort, libcec_configurati config->iFirmwareVersion = m_communication->GetFirmwareVersion(); config->iPhysicalAddress = m_communication->GetPhysicalAddress(); config->iFirmwareBuildDate = m_communication->GetFirmwareBuildDate(); + config->adapterType = m_communication->GetAdapterType(); return true; } @@ -641,6 +649,54 @@ CCECTuner *CCECProcessor::GetTuner(cec_logical_address address) const return CCECBusDevice::AsTuner(m_busDevices->At(address)); } +bool CCECProcessor::AllocateLogicalAddresses(CCECClient* client) +{ + libcec_configuration &configuration = *client->GetConfiguration(); + + // mark as unregistered + client->SetRegistered(false); + + // unregister this client from the old addresses + CECDEVICEVEC devices; + m_busDevices->GetByLogicalAddresses(devices, configuration.logicalAddresses); + for (CECDEVICEVEC::const_iterator it = devices.begin(); it != devices.end(); it++) + { + // remove client entry + CLockObject lock(m_mutex); + m_clients.erase((*it)->GetLogicalAddress()); + } + + // find logical addresses for this client + if (!client->AllocateLogicalAddresses()) + { + m_libcec->AddLog(CEC_LOG_ERROR, "failed to find a free logical address for the client"); + return false; + } + + // register this client on the new addresses + devices.clear(); + m_busDevices->GetByLogicalAddresses(devices, configuration.logicalAddresses); + for (CECDEVICEVEC::const_iterator it = devices.begin(); it != devices.end(); it++) + { + // set the physical address of the device at this LA + if (CLibCEC::IsValidPhysicalAddress(configuration.iPhysicalAddress)) + (*it)->SetPhysicalAddress(configuration.iPhysicalAddress); + + // replace a previous client + CLockObject lock(m_mutex); + m_clients.erase((*it)->GetLogicalAddress()); + m_clients.insert(make_pair((*it)->GetLogicalAddress(), client)); + } + + // set the new ackmask + SetLogicalAddresses(GetLogicalAddresses()); + + // resume outgoing communication + m_bStallCommunication = false; + + return true; +} + bool CCECProcessor::RegisterClient(CCECClient *client) { if (!client) @@ -683,36 +739,20 @@ bool CCECProcessor::RegisterClient(CCECClient *client) // get the configuration from the client m_libcec->AddLog(CEC_LOG_NOTICE, "registering new CEC client - v%s", ToString((cec_client_version)configuration.clientVersion)); - // mark as uninitialised and unregistered - client->SetRegistered(false); - client->SetInitialised(false); - // get the current ackmask, so we can restore it if polling fails cec_logical_addresses previousMask = GetLogicalAddresses(); + // mark as uninitialised + client->SetInitialised(false); + // find logical addresses for this client - if (!client->AllocateLogicalAddresses()) + if (!AllocateLogicalAddresses(client)) { m_libcec->AddLog(CEC_LOG_ERROR, "failed to register the new CEC client - cannot allocate the requested device types"); SetLogicalAddresses(previousMask); return false; } - // register this client on the new addresses - CECDEVICEVEC devices; - m_busDevices->GetByLogicalAddresses(devices, configuration.logicalAddresses); - for (CECDEVICEVEC::const_iterator it = devices.begin(); it != devices.end(); it++) - { - // set the physical address of the device at this LA - if (CLibCEC::IsValidPhysicalAddress(configuration.iPhysicalAddress)) - (*it)->SetPhysicalAddress(configuration.iPhysicalAddress); - - // replace a previous client - CLockObject lock(m_mutex); - m_clients.erase((*it)->GetLogicalAddress()); - m_clients.insert(make_pair((*it)->GetLogicalAddress(), client)); - } - // get the settings from the rom if (configuration.bGetSettingsFromROM == 1) { @@ -731,14 +771,13 @@ bool CCECProcessor::RegisterClient(CCECClient *client) configuration.serverVersion = LIBCEC_VERSION_CURRENT; configuration.iFirmwareVersion = m_communication->GetFirmwareVersion(); configuration.iFirmwareBuildDate = m_communication->GetFirmwareBuildDate(); + configuration.adapterType = m_communication->GetAdapterType(); // mark the client as registered client->SetRegistered(true); - // set the new ack mask - bool bReturn = SetLogicalAddresses(GetLogicalAddresses()) && - // and initialise the client - client->OnRegister(); + // initialise the client + bool bReturn = client->OnRegister(); // log the new registration CStdString strLog; @@ -884,3 +923,31 @@ void CCECProcessor::SwitchMonitoring(bool bSwitchTo) if (bSwitchTo) UnregisterClients(); } + +void CCECProcessor::HandleLogicalAddressLost(cec_logical_address oldAddress) +{ + // stall outgoing messages until we know our new LA + m_bStallCommunication = true; + + m_libcec->AddLog(CEC_LOG_NOTICE, "logical address %x was taken by another device, allocating a new address", oldAddress); + CCECClient* client = GetClient(oldAddress); + if (client) + { + if (m_addrAllocator) + while (m_addrAllocator->IsRunning()) Sleep(5); + delete m_addrAllocator; + + m_addrAllocator = new CCECAllocateLogicalAddress(this, client); + m_addrAllocator->CreateThread(); + } +} + +CCECAllocateLogicalAddress::CCECAllocateLogicalAddress(CCECProcessor* processor, CCECClient* client) : + m_processor(processor), + m_client(client) { } + +void* CCECAllocateLogicalAddress::Process(void) +{ + m_processor->AllocateLogicalAddresses(m_client); + return NULL; +} diff --git a/src/lib/CECProcessor.h b/src/lib/CECProcessor.h index dc8e9f5..e1f6d68 100644 --- a/src/lib/CECProcessor.h +++ b/src/lib/CECProcessor.h @@ -51,6 +51,18 @@ namespace CEC class CCECTuner; class CCECTV; class CCECClient; + class CCECProcessor; + + class CCECAllocateLogicalAddress : public PLATFORM::CThread + { + public: + CCECAllocateLogicalAddress(CCECProcessor* processor, CCECClient* client); + void* Process(void); + + private: + CCECProcessor* m_processor; + CCECClient* m_client; + }; class CCECProcessor : public PLATFORM::CThread, public IAdapterCommunicationCallback { @@ -69,6 +81,7 @@ namespace CEC CCECClient *GetClient(const cec_logical_address address); bool OnCommandReceived(const cec_command &command); + void HandleLogicalAddressLost(cec_logical_address oldAddress); CCECBusDevice * GetDevice(cec_logical_address address) const; CCECAudioSystem * GetAudioSystem(void) const; @@ -129,6 +142,7 @@ namespace CEC bool IsRunningLatestFirmware(void); void SwitchMonitoring(bool bSwitchTo); + bool AllocateLogicalAddresses(CCECClient* client); private: bool OpenConnection(const char *strPort, uint16_t iBaudRate, uint32_t iTimeoutMs, bool bStartListening = true); void SetCECInitialised(bool bSetTo = true); @@ -155,5 +169,7 @@ namespace CEC CCECDeviceMap * m_busDevices; std::map m_clients; bool m_bMonitor; + CCECAllocateLogicalAddress* m_addrAllocator; + bool m_bStallCommunication; }; }; diff --git a/src/lib/CECTypeUtils.h b/src/lib/CECTypeUtils.h index 7a50d9e..a791634 100644 --- a/src/lib/CECTypeUtils.h +++ b/src/lib/CECTypeUtils.h @@ -547,6 +547,10 @@ namespace CEC return "1.8.0"; case CEC_CLIENT_VERSION_1_8_1: return "1.8.1"; + case CEC_CLIENT_VERSION_1_8_2: + return "1.8.2"; + case CEC_CLIENT_VERSION_1_9_0: + return "1.9.0"; default: return "Unknown"; } @@ -584,6 +588,10 @@ namespace CEC return "1.8.0"; case CEC_SERVER_VERSION_1_8_1: return "1.8.1"; + case CEC_SERVER_VERSION_1_8_2: + return "1.8.2"; + case CEC_SERVER_VERSION_1_9_0: + return "1.9.0"; default: return "Unknown"; } @@ -776,5 +784,20 @@ namespace CEC return "unknown"; } } + + static const char *ToString(const cec_adapter_type type) + { + switch (type) + { + case ADAPTERTYPE_P8_EXTERNAL: + return "Pulse-Eight USB-CEC Adapter"; + case ADAPTERTYPE_P8_DAUGHTERBOARD: + return "Pulse-Eight USB-CEC Daughterboard"; + case ADAPTERTYPE_RPI: + return "Raspberry Pi"; + default: + return "unknown"; + } + } }; } diff --git a/src/lib/LibCEC.cpp b/src/lib/LibCEC.cpp index ad4ce66..252e1dc 100644 --- a/src/lib/LibCEC.cpp +++ b/src/lib/LibCEC.cpp @@ -649,6 +649,11 @@ void CLibCEC::InitVideoStandalone(void) CAdapterFactory::InitVideoStandalone(); } +const char *CLibCEC::ToString(const cec_adapter_type type) +{ + return CCECTypeUtils::ToString(type); +} + // no longer being used void CLibCEC::AddKey(const cec_keypress &UNUSED(key)) {} void CLibCEC::ConfigurationChanged(const libcec_configuration &UNUSED(config)) {} diff --git a/src/lib/LibCEC.h b/src/lib/LibCEC.h index 76d2919..fa4e632 100644 --- a/src/lib/LibCEC.h +++ b/src/lib/LibCEC.h @@ -149,6 +149,7 @@ namespace CEC const char *GetLibInfo(void); const char *ToString(const cec_user_control_code key); void InitVideoStandalone(void); + const char *ToString(const cec_adapter_type type); CCECProcessor * m_cec; diff --git a/src/lib/adapter/AdapterCommunication.h b/src/lib/adapter/AdapterCommunication.h index 03880b6..0702671 100644 --- a/src/lib/adapter/AdapterCommunication.h +++ b/src/lib/adapter/AdapterCommunication.h @@ -75,6 +75,12 @@ namespace CEC */ virtual bool HandleReceiveFailed(cec_logical_address initiator) = 0; + /*! + * @brief Callback method for IAdapterCommunication, called when a logical address that libCEC uses was taken by another device. + * @param oldAddress The logical address that was taken by another device. + */ + virtual void HandleLogicalAddressLost(cec_logical_address oldAddress) = 0; + virtual CLibCEC *GetLib(void) const = 0; }; @@ -200,6 +206,11 @@ namespace CEC */ virtual bool SupportsSourceLogicalAddress(const cec_logical_address address) = 0; + /*! + * @return The type of adapter that this instance is connected to. + */ + virtual cec_adapter_type GetAdapterType(void) = 0; + IAdapterCommunicationCallback *m_callback; }; }; diff --git a/src/lib/adapter/Pulse-Eight/USBCECAdapterCommands.cpp b/src/lib/adapter/Pulse-Eight/USBCECAdapterCommands.cpp index 457889c..ab0fa39 100644 --- a/src/lib/adapter/Pulse-Eight/USBCECAdapterCommands.cpp +++ b/src/lib/adapter/Pulse-Eight/USBCECAdapterCommands.cpp @@ -54,7 +54,8 @@ CUSBCECAdapterCommands::CUSBCECAdapterCommands(CUSBCECAdapterCommunication *comm m_iSettingLAMask(0), m_bNeedsWrite(false), m_iBuildDate(CEC_FW_BUILD_UNKNOWN), - m_bControlledMode(false) + m_bControlledMode(false), + m_adapterType(P8_ADAPTERTYPE_UNKNOWN) { m_persistedConfiguration.Clear(); } @@ -132,6 +133,19 @@ bool CUSBCECAdapterCommands::RequestSettingCECVersion(void) return false; } +p8_cec_adapter_type CUSBCECAdapterCommands::RequestAdapterType(void) +{ + if (m_adapterType == P8_ADAPTERTYPE_UNKNOWN) + { + LIB_CEC->AddLog(CEC_LOG_DEBUG, "requesting adapter type"); + + cec_datapacket response = RequestSetting(MSGCODE_GET_ADAPTER_TYPE); + if (response.size == 1) + m_adapterType = (p8_cec_adapter_type)response[0]; + } + return m_adapterType; +} + uint32_t CUSBCECAdapterCommands::RequestBuildDate(void) { if (m_iBuildDate == CEC_FW_BUILD_UNKNOWN) diff --git a/src/lib/adapter/Pulse-Eight/USBCECAdapterCommands.h b/src/lib/adapter/Pulse-Eight/USBCECAdapterCommands.h index 897ed1c..fa7f543 100644 --- a/src/lib/adapter/Pulse-Eight/USBCECAdapterCommands.h +++ b/src/lib/adapter/Pulse-Eight/USBCECAdapterCommands.h @@ -32,6 +32,7 @@ */ #include "lib/platform/threads/mutex.h" +#include "USBCECAdapterMessage.h" namespace CEC { @@ -113,6 +114,17 @@ namespace CEC */ uint32_t GetPersistedBuildDate(void) const { return m_iBuildDate; }; + /*! + * @brief Request the adapter type. + * @return The type + */ + p8_cec_adapter_type RequestAdapterType(void); + + /*! + * @return The persisted build date. + */ + p8_cec_adapter_type GetPersistedAdapterType(void) const { return m_adapterType; }; + /*! * @brief Persist the current settings in the EEPROM * @return True when persisted, false otherwise. @@ -233,6 +245,7 @@ namespace CEC libcec_configuration m_persistedConfiguration; /**< the configuration that is persisted in the eeprom */ uint32_t m_iBuildDate; /**< the build date of the firmware */ bool m_bControlledMode; /**< current value of the controlled mode feature */ + p8_cec_adapter_type m_adapterType; /**< the type of the adapter that we're connected to */ PLATFORM::CMutex m_mutex; }; } diff --git a/src/lib/adapter/Pulse-Eight/USBCECAdapterCommunication.cpp b/src/lib/adapter/Pulse-Eight/USBCECAdapterCommunication.cpp index 70e45ac..ae4c8ac 100644 --- a/src/lib/adapter/Pulse-Eight/USBCECAdapterCommunication.cpp +++ b/src/lib/adapter/Pulse-Eight/USBCECAdapterCommunication.cpp @@ -393,7 +393,11 @@ bool CUSBCECAdapterCommunication::ReadFromDevice(uint32_t iTimeout, size_t iSize if (!IsOpen()) return false; - iBytesRead = m_port->Read(buff, sizeof(uint8_t) * iSize, iTimeout); + do { + /* retry Read() if it was interrupted */ + iBytesRead = m_port->Read(buff, sizeof(uint8_t) * iSize, iTimeout); + } while(m_port->GetErrorNumber() == EINTR); + if (m_port->GetErrorNumber()) { @@ -482,8 +486,14 @@ bool CUSBCECAdapterCommunication::CheckAdapter(uint32_t iTimeoutMs /* = CEC_DEFA else bReturn = true; - /* try to read the build date */ - m_commands->RequestBuildDate(); + if (m_commands->GetFirmwareVersion() >= 2) + { + /* try to read the build date */ + m_commands->RequestBuildDate(); + + /* try to read the adapter type */ + m_commands->RequestAdapterType(); + } SetInitialised(bReturn); return bReturn; @@ -570,6 +580,17 @@ uint32_t CUSBCECAdapterCommunication::GetFirmwareBuildDate(void) return iBuildDate; } +cec_adapter_type CUSBCECAdapterCommunication::GetAdapterType(void) +{ + cec_adapter_type type(ADAPTERTYPE_UNKNOWN); + if (m_commands) + type = (cec_adapter_type)m_commands->GetPersistedAdapterType(); + if (type == ADAPTERTYPE_UNKNOWN && IsOpen()) + type = (cec_adapter_type)m_commands->RequestAdapterType(); + + return type; +} + bool CUSBCECAdapterCommunication::ProvidesExtendedResponse(void) { uint32_t iBuildDate(0); diff --git a/src/lib/adapter/Pulse-Eight/USBCECAdapterCommunication.h b/src/lib/adapter/Pulse-Eight/USBCECAdapterCommunication.h index 1144d0e..2192456 100644 --- a/src/lib/adapter/Pulse-Eight/USBCECAdapterCommunication.h +++ b/src/lib/adapter/Pulse-Eight/USBCECAdapterCommunication.h @@ -33,6 +33,7 @@ #include "lib/platform/threads/threads.h" #include "lib/adapter/AdapterCommunication.h" +#include "USBCECAdapterMessage.h" namespace PLATFORM { @@ -86,6 +87,7 @@ namespace CEC bool SetControlledMode(bool controlled); cec_vendor_id GetVendorId(void) { return CEC_VENDOR_UNKNOWN; } bool SupportsSourceLogicalAddress(const cec_logical_address UNUSED(address)) { return true; } + cec_adapter_type GetAdapterType(void); ///} bool ProvidesExtendedResponse(void); diff --git a/src/lib/adapter/Pulse-Eight/USBCECAdapterDetection.cpp b/src/lib/adapter/Pulse-Eight/USBCECAdapterDetection.cpp index f9969d8..5d72b5e 100644 --- a/src/lib/adapter/Pulse-Eight/USBCECAdapterDetection.cpp +++ b/src/lib/adapter/Pulse-Eight/USBCECAdapterDetection.cpp @@ -46,10 +46,14 @@ #elif defined(__WINDOWS__) #pragma comment(lib, "advapi32.lib") #pragma comment(lib, "setupapi.lib") +#pragma comment(lib, "cfgmgr32.lib") #include +#include // the virtual COM port only shows up when requesting devices with the raw device guid! -static GUID USB_RAW_GUID = { 0xA5DCBF10, 0x6530, 0x11D2, { 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED } }; +static GUID USB_RAW_GUID = { 0xA5DCBF10, 0x6530, 0x11D2, { 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED } }; +static GUID USB_CDC_GUID = { 0x4D36E978, 0xE325, 0x11CE, { 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18 } }; + #elif defined(HAVE_LIBUDEV) #include #include @@ -61,8 +65,9 @@ extern "C" { #include #endif -#define CEC_VID 0x2548 -#define CEC_PID 0x1001 +#define CEC_VID 0x2548 +#define CEC_PID 0x1001 +#define CEC_PID2 0x1002 using namespace CEC; using namespace std; @@ -125,6 +130,78 @@ bool CUSBCECAdapterDetection::CanAutodetect(void) #endif } +#if defined(__WINDOWS__) +static bool GetComPortFromHandle(HDEVINFO hDevHandle, PSP_DEVINFO_DATA devInfoData, char* strPortName, unsigned int iSize) +{ + bool bReturn(false); + TCHAR strRegPortName[256]; + strRegPortName[0] = _T('\0'); + DWORD dwSize = sizeof(strRegPortName); + DWORD dwType = 0; + + HKEY hDeviceKey = SetupDiOpenDevRegKey(hDevHandle, devInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE); + if (!hDeviceKey) + return bReturn; + + // locate the PortName + if ((RegQueryValueEx(hDeviceKey, _T("PortName"), NULL, &dwType, reinterpret_cast(strRegPortName), &dwSize) == ERROR_SUCCESS) && + (dwType == REG_SZ) && + _tcslen(strRegPortName) > 3 && + _tcsnicmp(strRegPortName, _T("COM"), 3) == 0 && + _ttoi(&(strRegPortName[3])) > 0) + { + // return the port name + snprintf(strPortName, iSize, "%s", strRegPortName); + bReturn = true; + } + + RegCloseKey(hDeviceKey); + + return bReturn; +} + +static bool FindComPortForComposite(const char* strLocation, char* strPortName, unsigned int iSize) +{ + bool bReturn(false); + + // find all devices of the CDC class + HDEVINFO hDevHandle = SetupDiGetClassDevs(&USB_CDC_GUID, NULL, NULL, DIGCF_PRESENT); + if (hDevHandle == INVALID_HANDLE_VALUE) + return bReturn; + + // check all devices, whether they match the location or not + char strId[512]; + bool bGetNext(true); + for (int iPtr = 0; !bReturn && bGetNext && iPtr < 1024 ; iPtr++) + { + strId[0] = 0; + + SP_DEVINFO_DATA devInfoData; + devInfoData.cbSize = sizeof(SP_DEVINFO_DATA); + + // no more devices + if (!SetupDiEnumDeviceInfo(hDevHandle, iPtr, &devInfoData)) + bGetNext = false; + else + { + // check if the location of the _parent_ device matches + DEVINST parentDevInst; + if (CM_Get_Parent(&parentDevInst, devInfoData.DevInst, 0) == CR_SUCCESS) + { + CM_Get_Device_ID(parentDevInst, strId, 512, 0); + + // match + if (!strncmp(strId, strLocation, strlen(strLocation))) + bReturn = GetComPortFromHandle(hDevHandle, &devInfoData, strPortName, iSize); + } + } + } + + SetupDiDestroyDeviceInfoList(hDevHandle); + return bReturn; +} +#endif + uint8_t CUSBCECAdapterDetection::FindAdapters(cec_adapter *deviceList, uint8_t iBufSize, const char *strDevicePath /* = NULL */) { uint8_t iFound(0); @@ -180,17 +257,21 @@ uint8_t CUSBCECAdapterDetection::FindAdapters(cec_adapter *deviceList, uint8_t i kresult = IORegistryEntryGetParentEntry(parent, kIOServicePlane, &parent); IOObjectRelease(oldparent); } - if (strlen(bsdPath) && iVendor == CEC_VID && iProduct == CEC_PID) + if (strlen(bsdPath) && iVendor == CEC_VID && (iProduct == CEC_PID || iProduct == CEC_PID2)) { if (!strDevicePath || !strcmp(bsdPath, strDevicePath)) { // on darwin, the device path is the same as the comm path. - snprintf(deviceList[iFound ].path, sizeof(deviceList[iFound].path), "%s", bsdPath); - snprintf(deviceList[iFound++].comm, sizeof(deviceList[iFound].path), "%s", bsdPath); + if (iFound == 0 || strcmp(deviceList[iFound-1].comm, bsdPath)) + { + snprintf(deviceList[iFound].path, sizeof(deviceList[iFound].path), "%s", bsdPath); + snprintf(deviceList[iFound].comm, sizeof(deviceList[iFound].path), "%s", bsdPath); + iFound++; + } } } } - IOObjectRelease(serialService); + IOObjectRelease(serialService); } } IOObjectRelease(serialPortIterator); @@ -225,16 +306,17 @@ uint8_t CUSBCECAdapterDetection::FindAdapters(cec_adapter *deviceList, uint8_t i int iVendor, iProduct; sscanf(udev_device_get_sysattr_value(pdev, "idVendor"), "%x", &iVendor); sscanf(udev_device_get_sysattr_value(pdev, "idProduct"), "%x", &iProduct); - if (iVendor == CEC_VID && iProduct == CEC_PID) + if (iVendor == CEC_VID && (iProduct == CEC_PID || iProduct == CEC_PID2)) { CStdString strPath(udev_device_get_syspath(pdev)); if (!strDevicePath || !strcmp(strPath.c_str(), strDevicePath)) { CStdString strComm(strPath); - if (FindComPort(strComm)) + if (FindComPort(strComm) && (iFound == 0 || strcmp(deviceList[iFound-1].comm, strComm.c_str()))) { - snprintf(deviceList[iFound ].path, sizeof(deviceList[iFound].path), "%s", strPath.c_str()); - snprintf(deviceList[iFound++].comm, sizeof(deviceList[iFound].path), "%s", strComm.c_str()); + snprintf(deviceList[iFound].path, sizeof(deviceList[iFound].path), "%s", strPath.c_str()); + snprintf(deviceList[iFound].comm, sizeof(deviceList[iFound].path), "%s", strComm.c_str()); + iFound++; } } } @@ -254,6 +336,7 @@ uint8_t CUSBCECAdapterDetection::FindAdapters(cec_adapter *deviceList, uint8_t i SP_DEVINFO_DATA devInfoData; devInfoData.cbSize = sizeof(SP_DEVINFO_DATA); + // find all devices if ((hDevHandle = SetupDiGetClassDevs(&USB_RAW_GUID, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE)) == INVALID_HANDLE_VALUE) return iFound; @@ -269,6 +352,7 @@ uint8_t CUSBCECAdapterDetection::FindAdapters(cec_adapter *deviceList, uint8_t i if(!bResult) { + // no (more) results SetupDiDestroyDeviceInfoList(hDevHandle); delete []buffer; buffer = NULL; @@ -297,9 +381,11 @@ uint8_t CUSBCECAdapterDetection::FindAdapters(cec_adapter *deviceList, uint8_t i if(!bDetailResult) continue; + // check whether the path matches, if a path was given if (strDevicePath && strcmp(strDevicePath, devicedetailData->DevicePath) != 0) continue; + // get the vid and pid CStdString strVendorId; CStdString strProductId; CStdString strTmp(devicedetailData->DevicePath); @@ -311,30 +397,28 @@ uint8_t CUSBCECAdapterDetection::FindAdapters(cec_adapter *deviceList, uint8_t i int iVendor, iProduct; sscanf(strVendorId, "%x", &iVendor); sscanf(strProductId, "%x", &iProduct); - if (iVendor != CEC_VID || iProduct != CEC_PID) - continue; - HKEY hDeviceKey = SetupDiOpenDevRegKey(hDevHandle, &devInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE); - if (!hDeviceKey) + // no match + if (iVendor != CEC_VID || (iProduct != CEC_PID && iProduct != CEC_PID2)) continue; - TCHAR strPortName[256]; - strPortName[0] = _T('\0'); - DWORD dwSize = sizeof(strPortName); - DWORD dwType = 0; - /* search the registry */ - if ((RegQueryValueEx(hDeviceKey, _T("PortName"), NULL, &dwType, reinterpret_cast(strPortName), &dwSize) == ERROR_SUCCESS) && (dwType == REG_SZ)) + if (iProduct == CEC_PID2) { - if (_tcslen(strPortName) > 3 && _tcsnicmp(strPortName, _T("COM"), 3) == 0 && - _ttoi(&(strPortName[3])) > 0) + // the 1002 pid indicates a composite device, that needs special treatment + char strId[512]; + CM_Get_Device_ID(devInfoData.DevInst, strId, 512, 0); + if (FindComPortForComposite(strId, deviceList[iFound].comm, sizeof(deviceList[iFound].comm))) { - snprintf(deviceList[iFound ].path, sizeof(deviceList[iFound].path), "%s", devicedetailData->DevicePath); - snprintf(deviceList[iFound++].comm, sizeof(deviceList[iFound].path), "%s", strPortName); + snprintf(deviceList[iFound].path, sizeof(deviceList[iFound].path), "%s", devicedetailData->DevicePath); + iFound++; } } - - RegCloseKey(hDeviceKey); + else if (GetComPortFromHandle(hDevHandle, &devInfoData, deviceList[iFound].comm, sizeof(deviceList[iFound].comm))) + { + snprintf(deviceList[iFound].path, sizeof(deviceList[iFound].path), "%s", devicedetailData->DevicePath); + iFound++; + } } #elif defined(__FreeBSD__) char devicePath[PATH_MAX + 1]; @@ -345,8 +429,9 @@ uint8_t CUSBCECAdapterDetection::FindAdapters(cec_adapter *deviceList, uint8_t i (void)snprintf(devicePath, sizeof(devicePath), "/dev/ttyU%d", i); if (!access(devicePath, 0)) { - snprintf(deviceList[iFound ].path, sizeof(deviceList[iFound].path), "%s", devicePath); - snprintf(deviceList[iFound++].comm, sizeof(deviceList[iFound].path), "%s", devicePath); + snprintf(deviceList[iFound].path, sizeof(deviceList[iFound].path), "%s", devicePath); + snprintf(deviceList[iFound].comm, sizeof(deviceList[iFound].path), "%s", devicePath); + iFound++; } } #else diff --git a/src/lib/adapter/Pulse-Eight/USBCECAdapterMessage.cpp b/src/lib/adapter/Pulse-Eight/USBCECAdapterMessage.cpp index 08e6c35..64efd06 100644 --- a/src/lib/adapter/Pulse-Eight/USBCECAdapterMessage.cpp +++ b/src/lib/adapter/Pulse-Eight/USBCECAdapterMessage.cpp @@ -229,6 +229,8 @@ const char *CCECAdapterMessage::ToString(cec_adapter_messagecode msgCode) return "SET_OSD_NAME"; case MSGCODE_WRITE_EEPROM: return "WRITE_EEPROM"; + case MSGCODE_GET_ADAPTER_TYPE: + return "GET_ADAPTER_TYPE"; default: break; } diff --git a/src/lib/adapter/Pulse-Eight/USBCECAdapterMessage.h b/src/lib/adapter/Pulse-Eight/USBCECAdapterMessage.h index 40ee1a4..f8ae413 100644 --- a/src/lib/adapter/Pulse-Eight/USBCECAdapterMessage.h +++ b/src/lib/adapter/Pulse-Eight/USBCECAdapterMessage.h @@ -35,6 +35,60 @@ namespace CEC { + typedef enum cec_adapter_messagecode + { + MSGCODE_NOTHING = 0, + MSGCODE_PING, + MSGCODE_TIMEOUT_ERROR, + MSGCODE_HIGH_ERROR, + MSGCODE_LOW_ERROR, + MSGCODE_FRAME_START, + MSGCODE_FRAME_DATA, + MSGCODE_RECEIVE_FAILED, + MSGCODE_COMMAND_ACCEPTED, + MSGCODE_COMMAND_REJECTED, + MSGCODE_SET_ACK_MASK, + MSGCODE_TRANSMIT, + MSGCODE_TRANSMIT_EOM, + MSGCODE_TRANSMIT_IDLETIME, + MSGCODE_TRANSMIT_ACK_POLARITY, + MSGCODE_TRANSMIT_LINE_TIMEOUT, + MSGCODE_TRANSMIT_SUCCEEDED, + MSGCODE_TRANSMIT_FAILED_LINE, + MSGCODE_TRANSMIT_FAILED_ACK, + MSGCODE_TRANSMIT_FAILED_TIMEOUT_DATA, + MSGCODE_TRANSMIT_FAILED_TIMEOUT_LINE, + MSGCODE_FIRMWARE_VERSION, + MSGCODE_START_BOOTLOADER, + MSGCODE_GET_BUILDDATE, + MSGCODE_SET_CONTROLLED, + MSGCODE_GET_AUTO_ENABLED, + MSGCODE_SET_AUTO_ENABLED, + MSGCODE_GET_DEFAULT_LOGICAL_ADDRESS, + MSGCODE_SET_DEFAULT_LOGICAL_ADDRESS, + MSGCODE_GET_LOGICAL_ADDRESS_MASK, + MSGCODE_SET_LOGICAL_ADDRESS_MASK, + MSGCODE_GET_PHYSICAL_ADDRESS, + MSGCODE_SET_PHYSICAL_ADDRESS, + MSGCODE_GET_DEVICE_TYPE, + MSGCODE_SET_DEVICE_TYPE, + MSGCODE_GET_HDMI_VERSION, + MSGCODE_SET_HDMI_VERSION, + MSGCODE_GET_OSD_NAME, + MSGCODE_SET_OSD_NAME, + MSGCODE_WRITE_EEPROM, + MSGCODE_GET_ADAPTER_TYPE, + MSGCODE_FRAME_EOM = 0x80, + MSGCODE_FRAME_ACK = 0x40, + } cec_adapter_messagecode; + + typedef enum p8_cec_adapter_type + { + P8_ADAPTERTYPE_UNKNOWN = 0, + P8_ADAPTERTYPE_EXTERNAL, + P8_ADAPTERTYPE_DAUGHTERBOARD, + } p8_cec_adapter_type; + class CCECAdapterMessage { public: diff --git a/src/lib/adapter/Pulse-Eight/USBCECAdapterMessageQueue.h b/src/lib/adapter/Pulse-Eight/USBCECAdapterMessageQueue.h index edd34be..b81c908 100644 --- a/src/lib/adapter/Pulse-Eight/USBCECAdapterMessageQueue.h +++ b/src/lib/adapter/Pulse-Eight/USBCECAdapterMessageQueue.h @@ -34,6 +34,7 @@ #include "lib/platform/threads/threads.h" #include "lib/platform/util/buffer.h" #include +#include "USBCECAdapterMessage.h" namespace CEC { diff --git a/src/lib/adapter/RPi/RPiCECAdapterCommunication.cpp b/src/lib/adapter/RPi/RPiCECAdapterCommunication.cpp index 5e1efd4..5d13368 100644 --- a/src/lib/adapter/RPi/RPiCECAdapterCommunication.cpp +++ b/src/lib/adapter/RPi/RPiCECAdapterCommunication.cpp @@ -142,10 +142,14 @@ void CRPiCECAdapterCommunication::OnDataReceived(uint32_t header, uint32_t p0, u } break; case VC_CEC_BUTTON_PRESSED: + case VC_CEC_REMOTE_PRESSED: { // translate into a cec_command cec_command command; - cec_command::Format(command, (cec_logical_address)CEC_CB_INITIATOR(p0), (cec_logical_address)CEC_CB_FOLLOWER(p0), CEC_OPCODE_USER_CONTROL_PRESSED); + cec_command::Format(command, + (cec_logical_address)CEC_CB_INITIATOR(p0), + (cec_logical_address)CEC_CB_FOLLOWER(p0), + reason == VC_CEC_BUTTON_PRESSED ? CEC_OPCODE_USER_CONTROL_PRESSED : CEC_OPCODE_VENDOR_REMOTE_BUTTON_DOWN); command.parameters.PushBack((uint8_t)CEC_CB_OPERAND1(p0)); // send to libCEC @@ -153,10 +157,14 @@ void CRPiCECAdapterCommunication::OnDataReceived(uint32_t header, uint32_t p0, u } break; case VC_CEC_BUTTON_RELEASE: + case VC_CEC_REMOTE_RELEASE: { // translate into a cec_command cec_command command; - cec_command::Format(command, (cec_logical_address)CEC_CB_INITIATOR(p0), (cec_logical_address)CEC_CB_FOLLOWER(p0), CEC_OPCODE_USER_CONTROL_RELEASE); + cec_command::Format(command, + (cec_logical_address)CEC_CB_INITIATOR(p0), + (cec_logical_address)CEC_CB_FOLLOWER(p0), + reason == VC_CEC_BUTTON_PRESSED ? CEC_OPCODE_USER_CONTROL_RELEASE : CEC_OPCODE_VENDOR_REMOTE_BUTTON_UP); command.parameters.PushBack((uint8_t)CEC_CB_OPERAND1(p0)); // send to libCEC @@ -180,9 +188,18 @@ void CRPiCECAdapterCommunication::OnDataReceived(uint32_t header, uint32_t p0, u m_logicalAddressCondition.Signal(); } break; + case VC_CEC_LOGICAL_ADDR_LOST: + { + // the logical address was taken by another device + cec_logical_address previousAddress = m_logicalAddress; + m_logicalAddress = CECDEVICE_UNKNOWN; + + // notify libCEC that we lost our LA when the connection was initialised + if (m_bInitialised) + m_callback->HandleLogicalAddressLost(previousAddress); + } + break; case VC_CEC_TOPOLOGY: - case VC_CEC_REMOTE_PRESSED: - case VC_CEC_REMOTE_RELEASE: break; default: LIB_CEC->AddLog(CEC_LOG_DEBUG, "ignoring unknown reason %x", reason); diff --git a/src/lib/adapter/RPi/RPiCECAdapterCommunication.h b/src/lib/adapter/RPi/RPiCECAdapterCommunication.h index 530aec1..7f81545 100644 --- a/src/lib/adapter/RPi/RPiCECAdapterCommunication.h +++ b/src/lib/adapter/RPi/RPiCECAdapterCommunication.h @@ -34,7 +34,7 @@ #if defined(HAVE_RPI_API) #include "lib/adapter/AdapterCommunication.h" -#include "lib/platform/threads/mutex.h" +#include "lib/platform/threads/threads.h" extern "C" { #include @@ -78,6 +78,7 @@ namespace CEC bool SetControlledMode(bool UNUSED(controlled)) { return true; }; cec_vendor_id GetVendorId(void) { return CEC_VENDOR_BROADCOM; } bool SupportsSourceLogicalAddress(const cec_logical_address address) { return address > CECDEVICE_TV && address < CECDEVICE_BROADCAST; } + cec_adapter_type GetAdapterType(void) { return ADAPTERTYPE_RPI; }; ///} bool IsInitialised(void); diff --git a/src/lib/devices/CECBusDevice.cpp b/src/lib/devices/CECBusDevice.cpp index 466e977..2998a62 100644 --- a/src/lib/devices/CECBusDevice.cpp +++ b/src/lib/devices/CECBusDevice.cpp @@ -1087,6 +1087,10 @@ void CCECBusDevice::SetStreamPath(uint16_t iNewAddress, uint16_t iOldAddress /* { // if a device is found with the new physical address, mark it as active, which will automatically mark all other devices as inactive device->MarkAsActiveSource(); + + // respond with an active source message if this device is handled by libCEC + if (device->IsHandledByLibCEC()) + device->TransmitActiveSource(true); } else { diff --git a/src/lib/implementations/VLCommandHandler.cpp b/src/lib/implementations/VLCommandHandler.cpp index e74daac..072d711 100644 --- a/src/lib/implementations/VLCommandHandler.cpp +++ b/src/lib/implementations/VLCommandHandler.cpp @@ -128,6 +128,10 @@ int CVLCommandHandler::HandleDeviceVendorCommandWithId(const cec_command &comman // send capabilties SendVendorCommandCapabilities(m_processor->GetLogicalAddress(), command.initiator); + + // reactivate the source, so the tv switches channels + if (m_processor->IsActiveSource(m_processor->GetLogicalAddress())) + m_processor->GetDevice(m_processor->GetLogicalAddress())->TransmitActiveSource(false); } else if (command.parameters.At(4) == VL_POWERED_DOWN) { diff --git a/src/lib/platform/windows/serialport.cpp b/src/lib/platform/windows/serialport.cpp index c595468..00ba7bb 100644 --- a/src/lib/platform/windows/serialport.cpp +++ b/src/lib/platform/windows/serialport.cpp @@ -103,7 +103,7 @@ ssize_t CSerialSocket::Write(void* data, size_t len) if (IsOpen()) { ssize_t iReturn = SerialSocketWrite(m_socket, &m_iError, data, len); - if (iReturn != len) + if (iReturn != (ssize_t)len) { m_strError = "unable to write to the serial port"; FormatWindowsError(GetLastError(), m_strError); diff --git a/src/testclient/main.cpp b/src/testclient/main.cpp index e594eaf..84133a9 100644 --- a/src/testclient/main.cpp +++ b/src/testclient/main.cpp @@ -47,9 +47,9 @@ using namespace CEC; using namespace std; using namespace PLATFORM; -#define CEC_CONFIG_VERSION CEC_CLIENT_VERSION_1_8_1; +#define CEC_CONFIG_VERSION CEC_CLIENT_VERSION_1_9_0; -#include +#include "../../include/cecloader.h" ICECCallbacks g_callbacks; libcec_configuration g_config; @@ -224,7 +224,12 @@ void ListDevices(ICECAdapter *parser) time_t buildTime = (time_t)config.iFirmwareBuildDate; strDeviceInfo.AppendFormat("firmware build date: %s", asctime(gmtime(&buildTime))); strDeviceInfo = strDeviceInfo.Left(strDeviceInfo.length() > 1 ? (unsigned)(strDeviceInfo.length() - 1) : 0); // strip \n added by asctime - strDeviceInfo.append(" +0000"); + strDeviceInfo.append(" +0000\n"); + } + + if (config.adapterType != ADAPTERTYPE_UNKNOWN) + { + strDeviceInfo.AppendFormat("type: %s\n", parser->ToString(config.adapterType)); } } strDeviceInfo.append("\n"); diff --git a/support/cec-flash-device.sh b/support/cec-flash-device.sh deleted file mode 100755 index 10715cb..0000000 --- a/support/cec-flash-device.sh +++ /dev/null @@ -1,120 +0,0 @@ -#!/bin/bash - -_usage() -{ - echo "Usage: $0 /path/to/firmware.hex" -} - -_check_bootloader_device() -{ - cec_adapter=`lsusb | grep "03eb:2ffa" | wc -l` - if [ $cec_adapter -eq 0 ]; then - _enter_bootloader - cec_adapter=`lsusb | grep "03eb:2ffa" | wc -l` - fi - - if [ $cec_adapter -eq 0 ]; then - echo "ERROR: failed to find any CEC adapter in bootloader mode" - return 1 - fi - - return 0 -} - -_enter_bootloader() -{ - echo "Instructing the CEC adapter to enter bootloader mode" - cec_adapter=`lsusb | grep "2548:1001" | wc -l` - if [ $cec_adapter -gt 0 ]; then - echo "bl" | cec-client --bootloader - echo "Waiting for the device to reinitialise" - sleep 5 - fi -} - -_flash() -{ - file=$1 - - if [ ! -f "$file" ]; then - echo "ERROR: firmware file '$file' does not exist" - exit 1 - fi - - cat << EOB -Flash '$file' onto the CEC adapter - -DISCONNECT THE HDMI CABLES BEFORE STARTING AND -DO NOT POWER OFF OR DISCONNECT THE DEVICE WHILE THIS OPERATION IS IN PROGRESS! - - -Are you sure you want to flash '$file' onto the CEC adapter? -Type 'do it!' if you're sure. Anything else will cancel the operation. - -EOB - read confirmation - if [ ! "$confirmation" == "do it!" ]; then - echo "Exiting" - exit 0 - fi - - _prereq - if [ $? -eq 1 ]; then - exit 1 - fi - - _check_bootloader_device - if [ $? -eq 1 ]; then - exit 1 - fi - - - echo "Erasing the previous firmware" - sudo dfu-programmer at90usb162 erase - - echo "Flashing the new firmware" - sudo dfu-programmer at90usb162 flash "$file" - - cat << EOB - -=============================================================================== - -Done! - -Remove the USB cable from the device and reconnect it to use the new firmware. - -EOB - exit 0 -} - -_prereq() -{ - programmer=`which dfu-programmer` - if [ -z "$programmer" ]; then - echo "dfu-programmer was not found in your path, installing" - sudo apt-get install -y dfu-programmer - fi - - programmer=`which dfu-programmer` - if [ -z "$programmer" ]; then - echo "ERROR: failed to find dfu-programmer" - return 1 - fi - return 0 -} - - -cat << EOB -=============================================================================== - Pulse-Eight CEC Adapter firmware flash tool -=============================================================================== - -EOB - -if [ -z "$1" ]; then - _usage -else - _flash $1 -fi - -exit 0 diff --git a/support/p8-usbcec-driver-installer.exe b/support/p8-usbcec-driver-installer.exe index 13596e7..310a1f8 100644 Binary files a/support/p8-usbcec-driver-installer.exe and b/support/p8-usbcec-driver-installer.exe differ