+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 <set stream path> 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 <packaging@pulse-eight.com> Wed, 5 Sep 2012 16:54:00 +0100
+
libcec (1.8.2-1) unstable; urgency=low
* changed/added:
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])
+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 <set stream path> 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 <packaging@pulse-eight.com> Wed, 5 Sep 2012 16:54:00 +0100
+
libcec (1.8.2-1) unstable; urgency=low
* changed/added:
-; Copyright (c) 2011 Pulse-Eight Limited
+; Copyright (c) 2012 Pulse-Eight Limited
[Version]
Signature="$Windows NT$"
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
;------------------------------------------------------------------------------
[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"
#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
{
* 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;
};
};
#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
{
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,
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 */
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
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
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)
/* 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
iFirmwareBuildDate = CEC_FW_BUILD_UNKNOWN;
bMonitorOnly = 0;
cecVersion = (cec_version)CEC_DEFAULT_SETTING_CEC_VERSION;
+ adapterType = ADAPTERTYPE_UNKNOWN;
memset(strDeviceName, 0, 13);
deviceTypes.clear();
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<IncludePath>$(SolutionDir)..\include;$(IncludePath)</IncludePath>
+ <LibraryPath>C:\WinDDK\7600.16385.1\lib\win7\i386;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IncludePath>$(SolutionDir)..\include;$(IncludePath)</IncludePath>
+ <LibraryPath>C:\WinDDK\7600.16385.1\lib\win7\amd64;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>$(SolutionDir)..\build\</OutDir>
<TargetName>libcec</TargetName>
<IncludePath>$(SolutionDir)..\include;$(IncludePath)</IncludePath>
+ <LibraryPath>C:\WinDDK\7600.16385.1\lib\win7\i386;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutDir>$(SolutionDir)..\build\</OutDir>
<TargetName>$(ProjectName).x64</TargetName>
<IncludePath>$(SolutionDir)..\include;$(IncludePath)</IncludePath>
+ <LibraryPath>C:\WinDDK\7600.16385.1\lib\win7\amd64;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
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;
// 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")]
[assembly:AssemblyTrademarkAttribute("")];
[assembly:AssemblyCultureAttribute("")];
-[assembly:AssemblyVersionAttribute("1.8.1.0")];
+[assembly:AssemblyVersionAttribute("1.9.0.0")];
[assembly:ComVisible(false)];
[assembly:CLSCompliantAttribute(true)];
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
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
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);
// 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")]
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;
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;
}
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);
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);
}
}
}
+ // wait until we finished allocating a new LA if it got lost
+ while (m_bStallCommunication) Sleep(5);
+
{
CLockObject lock(m_mutex);
m_iLastTransmission = GetTimeMs();
config->iFirmwareVersion = m_communication->GetFirmwareVersion();
config->iPhysicalAddress = m_communication->GetPhysicalAddress();
config->iFirmwareBuildDate = m_communication->GetFirmwareBuildDate();
+ config->adapterType = m_communication->GetAdapterType();
return true;
}
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<cec_logical_address, CCECClient *>((*it)->GetLogicalAddress(), client));
+ }
+
+ // set the new ackmask
+ SetLogicalAddresses(GetLogicalAddresses());
+
+ // resume outgoing communication
+ m_bStallCommunication = false;
+
+ return true;
+}
+
bool CCECProcessor::RegisterClient(CCECClient *client)
{
if (!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<cec_logical_address, CCECClient *>((*it)->GetLogicalAddress(), client));
- }
-
// get the settings from the rom
if (configuration.bGetSettingsFromROM == 1)
{
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;
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;
+}
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
{
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;
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);
CCECDeviceMap * m_busDevices;
std::map<cec_logical_address, CCECClient *> m_clients;
bool m_bMonitor;
+ CCECAllocateLogicalAddress* m_addrAllocator;
+ bool m_bStallCommunication;
};
};
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";
}
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";
}
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";
+ }
+ }
};
}
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)) {}
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;
*/
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;
};
*/
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;
};
};
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();
}
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)
*/
#include "lib/platform/threads/mutex.h"
+#include "USBCECAdapterMessage.h"
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.
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;
};
}
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())
{
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;
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);
#include "lib/platform/threads/threads.h"
#include "lib/adapter/AdapterCommunication.h"
+#include "USBCECAdapterMessage.h"
namespace PLATFORM
{
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);
#elif defined(__WINDOWS__)
#pragma comment(lib, "advapi32.lib")
#pragma comment(lib, "setupapi.lib")
+#pragma comment(lib, "cfgmgr32.lib")
#include <setupapi.h>
+#include <cfgmgr32.h>
// the virtual COM port only shows up when requesting devices with the raw device guid!
-static GUID USB_RAW_GUID = { 0xA5DCBF10, 0x6530, 0x11D2, { 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED } };
+static GUID USB_RAW_GUID = { 0xA5DCBF10, 0x6530, 0x11D2, { 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED } };
+static GUID USB_CDC_GUID = { 0x4D36E978, 0xE325, 0x11CE, { 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18 } };
+
#elif defined(HAVE_LIBUDEV)
#include <dirent.h>
#include <poll.h>
#include <unistd.h>
#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;
#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<LPBYTE>(strRegPortName), &dwSize) == ERROR_SUCCESS) &&
+ (dwType == REG_SZ) &&
+ _tcslen(strRegPortName) > 3 &&
+ _tcsnicmp(strRegPortName, _T("COM"), 3) == 0 &&
+ _ttoi(&(strRegPortName[3])) > 0)
+ {
+ // return the port name
+ snprintf(strPortName, iSize, "%s", strRegPortName);
+ bReturn = true;
+ }
+
+ 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);
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);
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++;
}
}
}
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;
if(!bResult)
{
+ // no (more) results
SetupDiDestroyDeviceInfoList(hDevHandle);
delete []buffer;
buffer = NULL;
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);
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<LPBYTE>(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];
(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
return "SET_OSD_NAME";
case MSGCODE_WRITE_EEPROM:
return "WRITE_EEPROM";
+ case MSGCODE_GET_ADAPTER_TYPE:
+ return "GET_ADAPTER_TYPE";
default:
break;
}
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:
#include "lib/platform/threads/threads.h"
#include "lib/platform/util/buffer.h"
#include <map>
+#include "USBCECAdapterMessage.h"
namespace CEC
{
}
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
}
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
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);
#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 <interface/vmcs_host/vc_cecservice.h>
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);
{
// 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
{
// 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)
{
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);
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 <cecloader.h>
+#include "../../include/cecloader.h"
ICECCallbacks g_callbacks;
libcec_configuration g_config;
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");
+++ /dev/null
-#!/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