From: Lars Op den Kamp Date: Sun, 6 Nov 2011 01:59:32 +0000 (+0100) Subject: cec: added logical address autodetection and let libcec handle multiple types simulta... X-Git-Tag: upstream/2.2.0~1^2~112 X-Git-Url: https://git.piment-noir.org/?a=commitdiff_plain;h=f8513317a5f4bb2d9d0843193c3c98eca19f8e8a;p=deb_libcec.git cec: added logical address autodetection and let libcec handle multiple types simultaniously. for logical address autodetection, you have to use CECInit()/cec_init_typed() instead of CECCreate()/cec_init() --- diff --git a/include/cec.h b/include/cec.h index c1aad1c..582bf24 100644 --- a/include/cec.h +++ b/include/cec.h @@ -172,6 +172,7 @@ namespace CEC }; }; +extern "C" DECLSPEC void * CECInit(const char *strDeviceName, CEC::cec_device_type_list devicesTypes); extern "C" DECLSPEC void * CECCreate(const char *strDeviceName, CEC::cec_logical_address iLogicalAddress = CEC::CECDEVICE_PLAYBACKDEVICE1, uint16_t iPhysicalAddress = CEC_DEFAULT_PHYSICAL_ADDRESS); extern "C" DECLSPEC void CECDestroy(CEC::ICECAdapter *instance); diff --git a/include/cecc.h b/include/cecc.h index 8a06956..4667146 100644 --- a/include/cecc.h +++ b/include/cecc.h @@ -53,6 +53,19 @@ extern DECLSPEC int cec_init(const char *strDeviceName, CEC::cec_logical_address extern DECLSPEC int cec_init(const char *strDeviceName, cec_logical_address iLogicalAddress = CECDEVICE_PLAYBACKDEVICE1, uint16_t iPhysicalAddress = CEC_DEFAULT_PHYSICAL_ADDRESS); #endif +/*! + * @brief Load the CEC adapter library. + * @param strDeviceName How to present this device to other devices. + * @param deviceTypes The device types to use on the CEC bus. + * @return True when initialised, false otherwise. + */ +#ifdef __cplusplus +extern DECLSPEC int cec_init_typed(const char *strDeviceName, CEC::cec_device_type_list devicesTypes); +#else +extern DECLSPEC int cec_init_typed(const char *strDeviceName, cec_device_type_list devicesTypes); +#endif + + /*! * @brief Unload the CEC adapter library. */ diff --git a/include/cecloader.h b/include/cecloader.h index 242d4fe..d20ca2f 100644 --- a/include/cecloader.h +++ b/include/cecloader.h @@ -96,13 +96,44 @@ CEC::ICECAdapter *LoadLibCec(const char *strName, CEC::cec_logical_address iLogi _CreateLibCec* CreateLibCec = (_CreateLibCec*) dlsym(g_libCEC, "CECCreate"); if (!CreateLibCec) { - cout << "cannot find CreateLibCec" << endl; + cout << "cannot find CECCreate" << endl; return NULL; } return (CEC::ICECAdapter*) CreateLibCec(strName, iLogicalAddress, iPhysicalAddress); } +CEC::ICECAdapter *LibCecInit(const char *strDeviceName, CEC::cec_device_type_list types, const char *strLib = NULL) +{ + if (!g_libCEC) + { +#if defined(__APPLE__) + g_libCEC = dlopen(strLib ? strLib : "libcec.dylib", RTLD_LAZY); +#else + g_libCEC = dlopen(strLib ? strLib : "libcec.so", RTLD_LAZY); +#endif + if (!g_libCEC) + { +#if defined(__APPLE__) + cout << "cannot find " << (strLib ? strLib : "libcec.dylib") << dlerror() << endl; +#else + cout << "cannot find " << (strLib ? strLib : "libcec.so") << dlerror() << endl; +#endif + return NULL; + } + } + + typedef void* _LibCecInit(const char *, CEC::cec_device_type_list); + _LibCecInit* LibCecInit = (_LibCecInit*) dlsym(g_libCEC, "CECInit"); + if (!LibCecInit) + { + cout << "cannot find CECInit" << endl; + return NULL; + } + + return (CEC::ICECAdapter*) LibCecInit(strDeviceName, types); +} + void UnloadLibCec(CEC::ICECAdapter *device) { typedef void* _DestroyLibCec(CEC::ICECAdapter *); diff --git a/include/cectypes.h b/include/cectypes.h index 9481a1f..6b9e0b5 100644 --- a/include/cectypes.h +++ b/include/cectypes.h @@ -142,7 +142,7 @@ typedef enum CEC_DECK_INFO_OTHER_STATUS = 0x1F } ECecDeckInfo; -typedef enum +typedef enum cec_device_type { CEC_DEVICE_TYPE_TV = 0, CEC_DEVICE_TYPE_RECORDING_DEVICE = 1, @@ -150,7 +150,54 @@ typedef enum CEC_DEVICE_TYPE_TUNER = 3, CEC_DEVICE_TYPE_PLAYBACK_DEVICE = 4, CEC_DEVICE_TYPE_AUDIO_SYSTEM = 5 -} ECecDeviceType; +} cec_device_type; + +typedef struct cec_device_type_list +{ + cec_device_type types[5]; + +#ifdef __cplusplus + void clear(void) + { + for (unsigned int iPtr = 0; iPtr < 5; iPtr++) + types[iPtr] = CEC_DEVICE_TYPE_RESERVED; + } + + void add(const cec_device_type type) + { + for (unsigned int iPtr = 0; iPtr < 5; iPtr++) + { + if (types[iPtr] == CEC_DEVICE_TYPE_RESERVED) + { + types[iPtr] = type; + break; + } + } + } + + bool isset(cec_device_type type) + { + bool bReturn(false); + for (unsigned int iPtr = 0; !bReturn && iPtr < 5; iPtr++) + { + if (types[iPtr] == type) + bReturn = true; + } + return bReturn; + } + + bool empty() + { + bool bReturn(true); + for (unsigned int iPtr = 0; bReturn && iPtr < 5; iPtr++) + { + if (types[iPtr] != CEC_DEVICE_TYPE_RESERVED) + bReturn = false; + } + return bReturn; + } +#endif +} cec_device_type_list; typedef enum cec_display_control { @@ -463,6 +510,53 @@ typedef enum cec_logical_address CECDEVICE_BROADCAST = 15 } cec_logical_address; +typedef struct cec_logical_addresses +{ + cec_logical_address primary; + int addresses[16]; + +#ifdef __cplusplus + void clear(void) + { + primary = CECDEVICE_UNKNOWN; + for (unsigned int iPtr = 0; iPtr < 16; iPtr++) + addresses[iPtr] = 0; + } + + bool empty(void) const + { + return primary == CECDEVICE_UNKNOWN; + } + + uint16_t ackmask(void) const + { + uint16_t mask = 0; + for (unsigned int iPtr = 0; iPtr < 16; iPtr++) + if (addresses[iPtr] == 1) + mask |= 0x1 << iPtr; + return mask; + } + + void set(cec_logical_address address) + { + if (primary == CECDEVICE_UNKNOWN) + primary = address; + + addresses[(int) address] = 1; + } + + void unset(cec_logical_address address) + { + if (primary == address) + primary = CECDEVICE_UNKNOWN; + + addresses[(int) address] = 0; + } + + bool isset(cec_logical_address address) const { return addresses[(int) address] == 1; } +#endif +} cec_logical_addresses; + typedef enum cec_opcode { CEC_OPCODE_ACTIVE_SOURCE = 0x82, diff --git a/src/lib/CECProcessor.cpp b/src/lib/CECProcessor.cpp index 49b3bd2..e46f48b 100644 --- a/src/lib/CECProcessor.cpp +++ b/src/lib/CECProcessor.cpp @@ -42,16 +42,32 @@ using namespace CEC; using namespace std; CCECProcessor::CCECProcessor(CLibCEC *controller, CAdapterCommunication *serComm, const char *strDeviceName, cec_logical_address iLogicalAddress /* = CECDEVICE_PLAYBACKDEVICE1 */, uint16_t iPhysicalAddress /* = CEC_DEFAULT_PHYSICAL_ADDRESS*/) : - m_iLogicalAddress(iLogicalAddress), + m_bStarted(false), m_strDeviceName(strDeviceName), m_communication(serComm), m_controller(controller), m_bMonitor(false) { + m_logicalAddresses.clear(); + m_logicalAddresses.set(iLogicalAddress); + m_types.clear(); for (int iPtr = 0; iPtr < 16; iPtr++) m_busDevices[iPtr] = new CCECBusDevice(this, (cec_logical_address) iPtr, iPtr == iLogicalAddress ? iPhysicalAddress : 0); } +CCECProcessor::CCECProcessor(CLibCEC *controller, CAdapterCommunication *serComm, const char *strDeviceName, const cec_device_type_list &types) : + m_bStarted(false), + m_strDeviceName(strDeviceName), + m_types(types), + m_communication(serComm), + m_controller(controller), + m_bMonitor(false) +{ + m_logicalAddresses.clear(); + for (int iPtr = 0; iPtr < 16; iPtr++) + m_busDevices[iPtr] = new CCECBusDevice(this, (cec_logical_address) iPtr, 0); +} + CCECProcessor::~CCECProcessor(void) { m_startCondition.Broadcast(); @@ -73,7 +89,7 @@ bool CCECProcessor::Start(void) if (CreateThread()) { - if (!m_startCondition.Wait(&m_mutex)) + if (!m_startCondition.Wait(&m_mutex) || !m_bStarted) { m_controller->AddLog(CEC_LOG_ERROR, "could not create a processor thread"); return false; @@ -86,17 +102,111 @@ bool CCECProcessor::Start(void) return false; } +bool CCECProcessor::TryLogicalAddress(cec_logical_address address, const char *strLabel) +{ + CStdString strLog; + strLog.Format("trying logical address '%s'", strLabel); + AddLog(CEC_LOG_DEBUG, strLog); + + SetAckMask(0x1 << address); + if (!m_busDevices[address]->PollDevice(address)) + { + + strLog.Format("using logical address '%s'", strLabel); + AddLog(CEC_LOG_NOTICE, strLog); + m_logicalAddresses.set(address); + + // TODO + m_busDevices[address]->SetPhysicalAddress(CEC_DEFAULT_PHYSICAL_ADDRESS); + + return true; + } + + strLog.Format("logical address '%s' already taken", strLabel); + AddLog(CEC_LOG_DEBUG, strLog); + return false; +} + +bool CCECProcessor::FindLogicalAddressRecordingDevice(void) +{ + AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'recording device'"); + return TryLogicalAddress(CECDEVICE_RECORDINGDEVICE1, "recording 1") || + TryLogicalAddress(CECDEVICE_RECORDINGDEVICE2, "recording 2") || + TryLogicalAddress(CECDEVICE_RECORDINGDEVICE3, "recording 3"); +} + +bool CCECProcessor::FindLogicalAddressTuner(void) +{ + AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'tuner'"); + return TryLogicalAddress(CECDEVICE_TUNER1, "tuner 1") || + TryLogicalAddress(CECDEVICE_TUNER2, "tuner 2") || + TryLogicalAddress(CECDEVICE_TUNER3, "tuner 3") || + TryLogicalAddress(CECDEVICE_TUNER4, "tuner 4"); +} + +bool CCECProcessor::FindLogicalAddressPlaybackDevice(void) +{ + AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'playback device'"); + return TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE1, "playback 1") || + TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE2, "playback 2") || + TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE3, "playback 3"); +} + +bool CCECProcessor::FindLogicalAddressAudioSystem(void) +{ + AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'audio'"); + return TryLogicalAddress(CECDEVICE_AUDIOSYSTEM, "audio"); +} + +bool CCECProcessor::FindLogicalAddresses(void) +{ + bool bReturn(true); + m_logicalAddresses.clear(); + CStdString strLog; + + for (unsigned int iPtr = 0; iPtr < 5; iPtr++) + { + if (m_types.types[iPtr] == CEC_DEVICE_TYPE_RESERVED) + continue; + + strLog.Format("%s - device %d: type %d", __FUNCTION__, iPtr, m_types.types[iPtr]); + AddLog(CEC_LOG_DEBUG, strLog); + + if (m_types.types[iPtr] == CEC_DEVICE_TYPE_RECORDING_DEVICE) + bReturn &= FindLogicalAddressRecordingDevice(); + if (m_types.types[iPtr] == CEC_DEVICE_TYPE_TUNER) + bReturn &= FindLogicalAddressTuner(); + if (m_types.types[iPtr] == CEC_DEVICE_TYPE_PLAYBACK_DEVICE) + bReturn &= FindLogicalAddressPlaybackDevice(); + if (m_types.types[iPtr] == CEC_DEVICE_TYPE_AUDIO_SYSTEM) + bReturn &= FindLogicalAddressAudioSystem(); + } + + return bReturn; +} + void *CCECProcessor::Process(void) { cec_command command; CCECAdapterMessage msg; - SetAckMask(0x1 << (uint8_t)m_iLogicalAddress); - { - CLockObject lock(&m_mutex); - m_controller->AddLog(CEC_LOG_DEBUG, "processor thread started"); - m_startCondition.Signal(); + if (m_logicalAddresses.empty() && !FindLogicalAddresses()) + { + CLockObject lock(&m_mutex); + m_controller->AddLog(CEC_LOG_ERROR, "could not detect our logical addressed"); + m_startCondition.Signal(); + return NULL; + } + + SetAckMask(m_logicalAddresses.ackmask()); + + { + CLockObject lock(&m_mutex); + m_controller->AddLog(CEC_LOG_DEBUG, "processor thread started"); + m_bStarted = true; + m_startCondition.Signal(); + } } while (!IsStopped()) @@ -138,8 +248,8 @@ bool CCECProcessor::SetActiveView(void) if (!IsRunning()) return false; - if (m_iLogicalAddress != CECDEVICE_UNKNOWN && m_busDevices[m_iLogicalAddress]) - return m_busDevices[m_iLogicalAddress]->BroadcastActiveView(); + if (!m_logicalAddresses.empty() && m_busDevices[m_logicalAddresses.primary]) + return m_busDevices[m_logicalAddresses.primary]->BroadcastActiveView(); return false; } @@ -148,8 +258,8 @@ bool CCECProcessor::SetInactiveView(void) if (!IsRunning()) return false; - if (m_iLogicalAddress != CECDEVICE_UNKNOWN && m_busDevices[m_iLogicalAddress]) - return m_busDevices[m_iLogicalAddress]->BroadcastInactiveView(); + if (!m_logicalAddresses.empty() && m_busDevices[m_logicalAddresses.primary]) + return m_busDevices[m_logicalAddresses.primary]->BroadcastInactiveView(); return false; } @@ -167,13 +277,14 @@ void CCECProcessor::LogOutput(const cec_command &data) bool CCECProcessor::SetLogicalAddress(cec_logical_address iLogicalAddress) { - if (m_iLogicalAddress != iLogicalAddress) + if (m_logicalAddresses.primary != iLogicalAddress) { CStdString strLog; - strLog.Format("<< setting logical address to %1x", iLogicalAddress); + strLog.Format("<< setting primary logical address to %1x", iLogicalAddress); m_controller->AddLog(CEC_LOG_NOTICE, strLog.c_str()); - m_iLogicalAddress = iLogicalAddress; - return SetAckMask(0x1 << (uint8_t)m_iLogicalAddress); + m_logicalAddresses.primary = iLogicalAddress; + m_logicalAddresses.set(iLogicalAddress); + return SetAckMask(m_logicalAddresses.ackmask()); } return true; @@ -181,10 +292,10 @@ bool CCECProcessor::SetLogicalAddress(cec_logical_address iLogicalAddress) bool CCECProcessor::SetPhysicalAddress(uint16_t iPhysicalAddress) { - if (m_iLogicalAddress != CECDEVICE_UNKNOWN && m_busDevices[m_iLogicalAddress]) + if (!m_logicalAddresses.empty() && m_busDevices[m_logicalAddresses.primary]) { - m_busDevices[m_iLogicalAddress]->SetPhysicalAddress(iPhysicalAddress); - return m_busDevices[m_iLogicalAddress]->BroadcastActiveView(); + m_busDevices[m_logicalAddresses.primary]->SetPhysicalAddress(iPhysicalAddress); + return m_busDevices[m_logicalAddresses.primary]->BroadcastActiveView(); } return false; } @@ -199,7 +310,7 @@ bool CCECProcessor::SwitchMonitoring(bool bEnable) if (bEnable) return SetAckMask(0); else - return SetAckMask(0x1 << (uint8_t)m_iLogicalAddress); + return SetAckMask(m_logicalAddresses.ackmask()); } bool CCECProcessor::PollDevice(cec_logical_address iAddress) @@ -285,7 +396,8 @@ void CCECProcessor::TransmitAbort(cec_logical_address address, cec_opcode opcode m_controller->AddLog(CEC_LOG_DEBUG, "<< transmitting abort message"); cec_command command; - cec_command::format(command, m_iLogicalAddress, address, CEC_OPCODE_FEATURE_ABORT); + // TODO + cec_command::format(command, m_logicalAddresses.primary, address, CEC_OPCODE_FEATURE_ABORT); command.parameters.push_back((uint8_t)opcode); command.parameters.push_back((uint8_t)reason); @@ -388,8 +500,8 @@ void CCECProcessor::ParseCommand(cec_command &command) uint16_t CCECProcessor::GetPhysicalAddress(void) const { - if (m_iLogicalAddress != CECDEVICE_UNKNOWN && m_busDevices[m_iLogicalAddress]) - return m_busDevices[m_iLogicalAddress]->GetPhysicalAddress(); + if (!m_logicalAddresses.empty() && m_busDevices[m_logicalAddresses.primary]) + return m_busDevices[m_logicalAddresses.primary]->GetPhysicalAddress(); return false; } diff --git a/src/lib/CECProcessor.h b/src/lib/CECProcessor.h index ea61365..a9c1065 100644 --- a/src/lib/CECProcessor.h +++ b/src/lib/CECProcessor.h @@ -50,6 +50,7 @@ namespace CEC { public: CCECProcessor(CLibCEC *controller, CAdapterCommunication *serComm, const char *strDeviceName, cec_logical_address iLogicalAddress = CECDEVICE_PLAYBACKDEVICE1, uint16_t iPhysicalAddress = CEC_DEFAULT_PHYSICAL_ADDRESS); + CCECProcessor(CLibCEC *controller, CAdapterCommunication *serComm, const char *strDeviceName, const cec_device_type_list &types); virtual ~CCECProcessor(void); virtual bool Start(void); @@ -60,7 +61,8 @@ namespace CEC virtual const std::string & GetDeviceName(void) { return m_strDeviceName; } virtual uint64_t GetDeviceVendorId(cec_logical_address iAddress); virtual cec_power_status GetDevicePowerStatus(cec_logical_address iAddress); - virtual cec_logical_address GetLogicalAddress(void) const { return m_iLogicalAddress; } + virtual cec_logical_address GetLogicalAddress(void) const { return m_logicalAddresses.primary; } + virtual bool HasLogicalAddress(cec_logical_address address) const { return m_logicalAddresses.isset(address); } virtual uint16_t GetPhysicalAddress(void) const; virtual bool SetActiveView(void); @@ -80,22 +82,32 @@ namespace CEC virtual void AddKey(void); virtual void AddLog(cec_log_level level, const CStdString &strMessage); + virtual bool FindLogicalAddresses(void); + CCECBusDevice *m_busDevices[16]; private: + bool TryLogicalAddress(cec_logical_address address, const char *strLabel); + bool FindLogicalAddressRecordingDevice(void); + bool FindLogicalAddressTuner(void); + bool FindLogicalAddressPlaybackDevice(void); + bool FindLogicalAddressAudioSystem(void); + bool SetAckMask(uint16_t iMask); void LogOutput(const cec_command &data); bool WaitForTransmitSucceeded(uint8_t iLength, uint32_t iTimeout = 1000); bool ParseMessage(const CCECAdapterMessage &msg); void ParseCommand(cec_command &command); + bool m_bStarted; cec_command m_currentframe; - cec_logical_address m_iLogicalAddress; + cec_logical_addresses m_logicalAddresses; std::string m_strDeviceName; + cec_device_type_list m_types; CMutex m_mutex; CCondition m_startCondition; - CAdapterCommunication *m_communication; - CLibCEC *m_controller; + CAdapterCommunication* m_communication; + CLibCEC* m_controller; bool m_bMonitor; }; }; diff --git a/src/lib/LibCEC.cpp b/src/lib/LibCEC.cpp index aff5776..7c87a8f 100644 --- a/src/lib/LibCEC.cpp +++ b/src/lib/LibCEC.cpp @@ -42,6 +42,15 @@ using namespace std; using namespace CEC; +CLibCEC::CLibCEC(const char *strDeviceName, cec_device_type_list types) : + m_iStartTime(GetTimeMs()), + m_iCurrentButton(CEC_USER_CONTROL_CODE_UNKNOWN), + m_buttontime(0) +{ + m_comm = new CAdapterCommunication(this); + m_cec = new CCECProcessor(this, m_comm, strDeviceName, types); +} + CLibCEC::CLibCEC(const char *strDeviceName, cec_logical_address iLogicalAddress /* = CECDEVICE_PLAYBACKDEVICE1 */, uint16_t iPhysicalAddress /* = CEC_DEFAULT_PHYSICAL_ADDRESS */) : m_iStartTime(GetTimeMs()), m_iCurrentButton(CEC_USER_CONTROL_CODE_UNKNOWN), @@ -296,6 +305,11 @@ void * CECCreate(const char *strDeviceName, CEC::cec_logical_address iLogicalAdd return static_cast< void* > (new CLibCEC(strDeviceName, iLogicalAddress, iPhysicalAddress)); } +void * CECInit(const char *strDeviceName, CEC::cec_device_type_list types) +{ + return static_cast< void* > (new CLibCEC(strDeviceName, types)); +} + void CECDestroy(CEC::ICECAdapter *instance) { CLibCEC *lib = static_cast< CLibCEC* > (instance); diff --git a/src/lib/LibCEC.h b/src/lib/LibCEC.h index bd3ca60..69c5b18 100644 --- a/src/lib/LibCEC.h +++ b/src/lib/LibCEC.h @@ -47,6 +47,7 @@ namespace CEC * ICECAdapter implementation */ //@{ + CLibCEC(const char *strDeviceName, cec_device_type_list types); CLibCEC(const char *strDeviceName, cec_logical_address iLogicalAddress = CECDEVICE_PLAYBACKDEVICE1, uint16_t iPhysicalAddress = CEC_DEFAULT_PHYSICAL_ADDRESS); virtual ~CLibCEC(void); diff --git a/src/lib/LibCECC.cpp b/src/lib/LibCECC.cpp index 09b40db..a2e58c5 100644 --- a/src/lib/LibCECC.cpp +++ b/src/lib/LibCECC.cpp @@ -48,6 +48,12 @@ int cec_init(const char *strDeviceName, cec_logical_address iLogicalAddress /* = return (cec_parser != NULL) ? 1 : 0; } +int cec_init_typed(const char *strDeviceName, cec_device_type_list devicesTypes) +{ + cec_parser = (ICECAdapter *) CECInit(strDeviceName, devicesTypes); + return (cec_parser != NULL) ? 1 : 0; +} + void cec_destroy(void) { cec_close(); diff --git a/src/lib/devices/CECBusDevice.cpp b/src/lib/devices/CECBusDevice.cpp index 5a56dc4..d985537 100644 --- a/src/lib/devices/CECBusDevice.cpp +++ b/src/lib/devices/CECBusDevice.cpp @@ -67,6 +67,11 @@ cec_logical_address CCECBusDevice::GetMyLogicalAddress(void) const return m_processor->GetLogicalAddress(); } +bool CCECBusDevice::MyLogicalAddressContains(cec_logical_address address) const +{ + return m_processor->HasLogicalAddress(address); +} + uint16_t CCECBusDevice::GetMyPhysicalAddress(void) const { return m_processor->GetPhysicalAddress(); @@ -191,7 +196,7 @@ const cec_vendor &CCECBusDevice::GetVendor(void) { AddLog(CEC_LOG_NOTICE, "<< requesting vendor ID"); cec_command command; - cec_command::format(command, GetMyLogicalAddress(), GetLogicalAddress(), CEC_OPCODE_GIVE_DEVICE_VENDOR_ID); + cec_command::format(command, GetMyLogicalAddress(), m_iLogicalAddress, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID); CLockObject lock(&m_mutex); if (m_processor->Transmit(command)) @@ -211,7 +216,7 @@ void CCECBusDevice::PollVendorId(void) m_iLastActive = GetTimeMs(); cec_command command; - cec_command::format(command, GetMyLogicalAddress(), GetLogicalAddress(), CEC_OPCODE_GIVE_DEVICE_VENDOR_ID); + cec_command::format(command, GetMyLogicalAddress(), m_iLogicalAddress, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID); if (m_processor->Transmit(command)) m_condition.Wait(&m_mutex, 1000); } @@ -222,7 +227,7 @@ void CCECBusDevice::SetPhysicalAddress(uint16_t iNewAddress, uint16_t iOldAddres if (iNewAddress > 0) { CStdString strLog; - strLog.Format(">> %i changed physical address from %04x to %04x", GetLogicalAddress(), m_iPhysicalAddress, iNewAddress); + strLog.Format(">> %i changed physical address from %04x to %04x", m_iLogicalAddress, m_iPhysicalAddress, iNewAddress); AddLog(CEC_LOG_DEBUG, strLog.c_str()); m_iPhysicalAddress = iNewAddress; @@ -269,26 +274,26 @@ bool CCECBusDevice::SetOSDString(cec_display_control duration, const char *strMe return m_processor->Transmit(command); } -bool CCECBusDevice::ReportCECVersion(void) +bool CCECBusDevice::ReportCECVersion(cec_logical_address dest) { AddLog(CEC_LOG_NOTICE, "<< reporting CEC version as 1.3a"); cec_command command; - cec_command::format(command, GetMyLogicalAddress(), m_iLogicalAddress, CEC_OPCODE_CEC_VERSION); + cec_command::format(command, m_iLogicalAddress, dest, CEC_OPCODE_CEC_VERSION); command.parameters.push_back(CEC_VERSION_1_3A); return m_processor->Transmit(command); } -bool CCECBusDevice::ReportDeckStatus(void) +bool CCECBusDevice::ReportDeckStatus(cec_logical_address dest) { // need to support opcodes play and deck control before doing anything with this AddLog(CEC_LOG_NOTICE, "<< deck status requested, feature abort"); - m_processor->TransmitAbort(m_iLogicalAddress, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID); + m_processor->TransmitAbort(dest, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID); return false; } -bool CCECBusDevice::ReportMenuState(bool bActive /* = true */) +bool CCECBusDevice::ReportMenuState(cec_logical_address dest, bool bActive /* = true */) { if (bActive) AddLog(CEC_LOG_NOTICE, "<< reporting menu state as active"); @@ -296,13 +301,13 @@ bool CCECBusDevice::ReportMenuState(bool bActive /* = true */) AddLog(CEC_LOG_NOTICE, "<< reporting menu state as inactive"); cec_command command; - cec_command::format(command, GetMyLogicalAddress(), m_iLogicalAddress, CEC_OPCODE_MENU_STATUS); + cec_command::format(command, m_iLogicalAddress, dest, CEC_OPCODE_MENU_STATUS); command.parameters.push_back(bActive ? (uint8_t) CEC_MENU_STATE_ACTIVATED : (uint8_t) CEC_MENU_STATE_DEACTIVATED); return m_processor->Transmit(command); } -bool CCECBusDevice::ReportOSDName(void) +bool CCECBusDevice::ReportOSDName(cec_logical_address dest) { const char *osdname = m_processor->GetDeviceName().c_str(); CStdString strLog; @@ -310,31 +315,29 @@ bool CCECBusDevice::ReportOSDName(void) AddLog(CEC_LOG_NOTICE, strLog.c_str()); cec_command command; - cec_command::format(command, GetMyLogicalAddress(), m_iLogicalAddress, CEC_OPCODE_SET_OSD_NAME); + cec_command::format(command, m_iLogicalAddress, dest, CEC_OPCODE_SET_OSD_NAME); for (unsigned int iPtr = 0; iPtr < strlen(osdname); iPtr++) command.parameters.push_back(osdname[iPtr]); return m_processor->Transmit(command); } -bool CCECBusDevice::ReportPowerState(bool bOn /* = true */) +bool CCECBusDevice::ReportPowerState(cec_logical_address dest) { - if (bOn) - AddLog(CEC_LOG_NOTICE, "<< reporting \"On\" power status"); - else - AddLog(CEC_LOG_NOTICE, "<< reporting \"Off\" power status"); + AddLog(CEC_LOG_NOTICE, "<< reporting \"On\" power status"); cec_command command; - cec_command::format(command, GetMyLogicalAddress(), m_iLogicalAddress, CEC_OPCODE_REPORT_POWER_STATUS); - command.parameters.push_back(bOn ? (uint8_t) CEC_POWER_STATUS_ON : (uint8_t) CEC_POWER_STATUS_STANDBY); + cec_command::format(command, m_iLogicalAddress, dest, CEC_OPCODE_REPORT_POWER_STATUS); +// command.parameters.push_back(bOn ? (uint8_t) CEC_POWER_STATUS_ON : (uint8_t) CEC_POWER_STATUS_STANDBY); + command.parameters.push_back((uint8_t) CEC_POWER_STATUS_ON); return m_processor->Transmit(command); } -bool CCECBusDevice::ReportVendorID(void) +bool CCECBusDevice::ReportVendorID(cec_logical_address dest) { AddLog(CEC_LOG_NOTICE, "<< vendor ID requested, feature abort"); - m_processor->TransmitAbort(m_iLogicalAddress, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID); + m_processor->TransmitAbort(dest, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID); return false; } @@ -343,7 +346,7 @@ bool CCECBusDevice::BroadcastActiveView(void) AddLog(CEC_LOG_DEBUG, "<< setting active view"); cec_command command; - cec_command::format(command, GetMyLogicalAddress(), CECDEVICE_BROADCAST, CEC_OPCODE_ACTIVE_SOURCE); + cec_command::format(command, m_iLogicalAddress, CECDEVICE_BROADCAST, CEC_OPCODE_ACTIVE_SOURCE); command.parameters.push_back((m_iPhysicalAddress >> 8) & 0xFF); command.parameters.push_back(m_iPhysicalAddress & 0xFF); @@ -355,7 +358,7 @@ bool CCECBusDevice::BroadcastInactiveView(void) AddLog(CEC_LOG_DEBUG, "<< setting inactive view"); cec_command command; - cec_command::format(command, GetMyLogicalAddress(), CECDEVICE_BROADCAST, CEC_OPCODE_INACTIVE_SOURCE); + cec_command::format(command, m_iLogicalAddress, CECDEVICE_BROADCAST, CEC_OPCODE_INACTIVE_SOURCE); command.parameters.push_back((m_iPhysicalAddress >> 8) & 0xFF); command.parameters.push_back(m_iPhysicalAddress & 0xFF); @@ -369,7 +372,7 @@ bool CCECBusDevice::BroadcastPhysicalAddress(void) AddLog(CEC_LOG_NOTICE, strLog.c_str()); cec_command command; - cec_command::format(command, GetMyLogicalAddress(), CECDEVICE_BROADCAST, CEC_OPCODE_REPORT_PHYSICAL_ADDRESS); + cec_command::format(command, m_iLogicalAddress, CECDEVICE_BROADCAST, CEC_OPCODE_REPORT_PHYSICAL_ADDRESS); command.parameters.push_back((uint8_t) ((m_iPhysicalAddress >> 8) & 0xFF)); command.parameters.push_back((uint8_t) (m_iPhysicalAddress & 0xFF)); command.parameters.push_back((uint8_t) (CEC_DEVICE_TYPE_PLAYBACK_DEVICE)); @@ -382,7 +385,7 @@ bool CCECBusDevice::BroadcastActiveSource(void) AddLog(CEC_LOG_NOTICE, "<< broadcasting active source"); cec_command command; - cec_command::format(command, GetMyLogicalAddress(), CECDEVICE_BROADCAST, CEC_OPCODE_ACTIVE_SOURCE); + cec_command::format(command, m_iLogicalAddress, CECDEVICE_BROADCAST, CEC_OPCODE_ACTIVE_SOURCE); command.parameters.push_back((uint8_t) ((m_iPhysicalAddress >> 8) & 0xFF)); command.parameters.push_back((uint8_t) (m_iPhysicalAddress & 0xFF)); @@ -434,16 +437,19 @@ cec_power_status CCECBusDevice::GetPowerStatus(bool bRefresh /* = true */) return m_powerStatus; } -bool CCECBusDevice::PollDevice(void) +bool CCECBusDevice::PollDevice(cec_logical_address source /* = CECDEVICE_UNKNOWN */) { bool bReturn(false); + if (source == CECDEVICE_UNKNOWN) + source = GetMyLogicalAddress(); + CStdString strLog; - strLog.Format("<< sending POLL from device %1x to device %1x", (int8_t)GetMyLogicalAddress(), m_iLogicalAddress); + strLog.Format("<< sending POLL from device %1x to device %1x", (int8_t)source, m_iLogicalAddress); AddLog(CEC_LOG_DEBUG, strLog); cec_command command; - cec_command::format(command, GetMyLogicalAddress(), m_iLogicalAddress, CEC_OPCODE_NONE); + cec_command::format(command, source, m_iLogicalAddress, CEC_OPCODE_NONE); CLockObject lock(&m_mutex); bReturn = m_processor->Transmit(command); diff --git a/src/lib/devices/CECBusDevice.h b/src/lib/devices/CECBusDevice.h index 278c038..362e86e 100644 --- a/src/lib/devices/CECBusDevice.h +++ b/src/lib/devices/CECBusDevice.h @@ -46,6 +46,7 @@ namespace CEC CCECBusDevice(CCECProcessor *processor, cec_logical_address address, uint16_t iPhysicalAddress = 0); virtual ~CCECBusDevice(void); + virtual bool MyLogicalAddressContains(cec_logical_address address) const; virtual cec_logical_address GetMyLogicalAddress(void) const; virtual uint16_t GetMyPhysicalAddress(void) const; virtual const char * GetVendorName(void) { return GetVendor().AsString(); } @@ -58,7 +59,7 @@ namespace CEC virtual cec_version GetCecVersion(bool bRefresh = true); virtual cec_menu_language & GetMenuLanguage(bool bRefresh = true); virtual cec_power_status GetPowerStatus(bool bRefresh = true); - virtual bool PollDevice(void); + virtual bool PollDevice(cec_logical_address source = CECDEVICE_UNKNOWN); virtual bool PowerOn(void); virtual bool Standby(void); @@ -78,12 +79,12 @@ namespace CEC virtual CCECProcessor *GetProcessor() const { return m_processor; } virtual CCECCommandHandler *GetHandler(void) const { return m_handler; }; - virtual bool ReportCECVersion(void); - virtual bool ReportDeckStatus(void); - virtual bool ReportMenuState(bool bActive = true); - virtual bool ReportOSDName(void); - virtual bool ReportPowerState(bool bOn = true); - virtual bool ReportVendorID(void); + virtual bool ReportCECVersion(cec_logical_address dest); + virtual bool ReportDeckStatus(cec_logical_address dest); + virtual bool ReportMenuState(cec_logical_address dest, bool bActive = true); + virtual bool ReportOSDName(cec_logical_address dest); + virtual bool ReportPowerState(cec_logical_address dest); + virtual bool ReportVendorID(cec_logical_address dest); virtual bool BroadcastActiveView(void); virtual bool BroadcastInactiveView(void); diff --git a/src/lib/implementations/ANCommandHandler.cpp b/src/lib/implementations/ANCommandHandler.cpp index f1e3dd5..3da959e 100644 --- a/src/lib/implementations/ANCommandHandler.cpp +++ b/src/lib/implementations/ANCommandHandler.cpp @@ -75,7 +75,7 @@ bool CANCommandHandler::HandleVendorRemoteButtonDown(const cec_command &command) bool CANCommandHandler::HandleCommand(const cec_command &command) { bool bHandled(false); - if (command.destination == m_busDevice->GetMyLogicalAddress()) + if (m_busDevice->MyLogicalAddressContains(command.destination)) { switch(command.opcode) { diff --git a/src/lib/implementations/CECCommandHandler.cpp b/src/lib/implementations/CECCommandHandler.cpp index ac00ebf..625ed01 100644 --- a/src/lib/implementations/CECCommandHandler.cpp +++ b/src/lib/implementations/CECCommandHandler.cpp @@ -45,7 +45,7 @@ bool CCECCommandHandler::HandleCommand(const cec_command &command) { bool bHandled(true); - if (command.destination == m_busDevice->GetMyLogicalAddress()) + if (m_busDevice->MyLogicalAddressContains(command.destination)) { switch(command.opcode) { @@ -135,7 +135,7 @@ bool CCECCommandHandler::HandleCommand(const cec_command &command) else { CStdString strLog; - strLog.Format("ignoring frame: destination: %u != %u", command.destination, (uint8_t)m_busDevice->GetMyLogicalAddress()); + strLog.Format("ignoring frame: we're not at destination %x", command.destination); m_busDevice->AddLog(CEC_LOG_DEBUG, strLog.c_str()); bHandled = false; } @@ -175,52 +175,52 @@ bool CCECCommandHandler::HandleDeviceVendorId(const cec_command &command) bool CCECCommandHandler::HandleGetCecVersion(const cec_command &command) { - CCECBusDevice *device = GetDevice(command.initiator); + CCECBusDevice *device = GetDevice(command.destination); if (device) - return device->ReportCECVersion(); + return device->ReportCECVersion(command.initiator); return false; } bool CCECCommandHandler::HandleGiveDeckStatus(const cec_command &command) { - CCECBusDevice *device = GetDevice(command.initiator); + CCECBusDevice *device = GetDevice(command.destination); if (device) - return device->ReportDeckStatus(); + return device->ReportDeckStatus(command.initiator); return false; } bool CCECCommandHandler::HandleGiveDevicePowerStatus(const cec_command &command) { - CCECBusDevice *device = GetDevice(command.initiator); + CCECBusDevice *device = GetDevice(command.destination); if (device) - return device->ReportPowerState(); + return device->ReportPowerState(command.initiator); return false; } bool CCECCommandHandler::HandleGiveDeviceVendorId(const cec_command &command) { - CCECBusDevice *device = GetDevice(command.initiator); + CCECBusDevice *device = GetDevice(command.destination); if (device) - return device->ReportVendorID(); + return device->ReportVendorID(command.initiator); return false; } bool CCECCommandHandler::HandleGiveOSDName(const cec_command &command) { - CCECBusDevice *device = GetDevice(command.initiator); + CCECBusDevice *device = GetDevice(command.destination); if (device) - return device->ReportOSDName(); + return device->ReportOSDName(command.initiator); return false; } bool CCECCommandHandler::HandleGivePhysicalAddress(const cec_command &command) { - CCECBusDevice *device = GetThisDevice(); + CCECBusDevice *device = GetDevice(command.destination); if (device) return device->BroadcastPhysicalAddress(); @@ -231,9 +231,9 @@ bool CCECCommandHandler::HandleMenuRequest(const cec_command &command) { if (command.parameters[0] == CEC_MENU_REQUEST_TYPE_QUERY) { - CCECBusDevice *device = GetDevice(command.initiator); + CCECBusDevice *device = GetDevice(command.destination); if (device) - return device->ReportMenuState(); + return device->ReportMenuState(command.initiator); } return false; } @@ -254,7 +254,7 @@ bool CCECCommandHandler::HandleRequestActiveSource(const cec_command &command) CStdString strLog; strLog.Format(">> %i requests active source", (uint8_t) command.initiator); m_busDevice->AddLog(CEC_LOG_DEBUG, strLog.c_str()); - CCECBusDevice *device = GetThisDevice(); + CCECBusDevice *device = m_busDevice->GetProcessor()->m_busDevices[m_busDevice->GetMyLogicalAddress()]; if (device) return device->BroadcastActiveSource(); return false; @@ -302,7 +302,7 @@ bool CCECCommandHandler::HandleSetStreamPath(const cec_command &command) m_busDevice->AddLog(CEC_LOG_DEBUG, strLog.c_str()); if (streamaddr == m_busDevice->GetMyPhysicalAddress()) { - CCECBusDevice *device = GetThisDevice(); + CCECBusDevice *device = GetDevice(command.destination); if (device) return device->BroadcastActiveSource(); return false; @@ -351,8 +351,3 @@ CCECBusDevice *CCECCommandHandler::GetDevice(cec_logical_address iLogicalAddress return device; } - -CCECBusDevice *CCECCommandHandler::GetThisDevice(void) const -{ - return m_busDevice->GetProcessor()->m_busDevices[m_busDevice->GetMyLogicalAddress()]; -} diff --git a/src/lib/implementations/CECCommandHandler.h b/src/lib/implementations/CECCommandHandler.h index 0505c7c..d6acd75 100644 --- a/src/lib/implementations/CECCommandHandler.h +++ b/src/lib/implementations/CECCommandHandler.h @@ -69,7 +69,6 @@ namespace CEC void SendToCommandBuffer(const cec_command &command); CCECBusDevice *GetDevice(cec_logical_address iLogicalAddress) const; - CCECBusDevice *GetThisDevice(void) const; CCECBusDevice *m_busDevice; }; }; diff --git a/src/lib/implementations/VLCommandHandler.cpp b/src/lib/implementations/VLCommandHandler.cpp index 89f5b2e..0104e9a 100644 --- a/src/lib/implementations/VLCommandHandler.cpp +++ b/src/lib/implementations/VLCommandHandler.cpp @@ -51,13 +51,12 @@ bool CVLCommandHandler::HandleSetStreamPath(const cec_command &command) m_busDevice->AddLog(CEC_LOG_DEBUG, strLog.c_str()); if (streamaddr == m_busDevice->GetMyPhysicalAddress()) { - CCECBusDevice *device = GetThisDevice(); - CCECBusDevice *initiatorDevice = GetDevice(command.initiator); - if (device && initiatorDevice) + CCECBusDevice *device = GetDevice(command.destination); + if (device) { return device->BroadcastActiveSource() && device->BroadcastActiveView() && - initiatorDevice->ReportMenuState(); + device->ReportMenuState(command.initiator); } return false; } diff --git a/src/testclient/main.cpp b/src/testclient/main.cpp index 0481829..f16bcbf 100644 --- a/src/testclient/main.cpp +++ b/src/testclient/main.cpp @@ -49,7 +49,6 @@ using namespace std; #include int g_cecLogLevel = CEC_LOG_ALL; -int g_iLogicalAddress = CECDEVICE_PLAYBACKDEVICE1; ofstream g_logOutput; bool g_bShortLog = false; CStdString g_strPort; @@ -180,7 +179,7 @@ void show_help(const char* strExec) "parameters:" << endl << " -h --help Shows this help text" << endl << " -l --list-devices List all devices on this system" << endl << - " -la --logical-address {a} The logical address to use." << endl << + " -t --type {p|r|t|a} The device type to use. More than one is possible." << endl << " -f --log-file {file} Writes all libCEC log message to a file" << endl << " -sf --short-log-file {file} Writes all libCEC log message without timestamps" << endl << " and log levels to a file." << endl << @@ -193,6 +192,26 @@ void show_help(const char* strExec) "available commands" << endl; } +ICECAdapter *create_parser(cec_device_type_list typeList) +{ + ICECAdapter *parser = LibCecInit("CECTester", typeList); + if (!parser || parser->GetMinLibVersion() > CEC_TEST_CLIENT_VERSION) + { + #ifdef __WINDOWS__ + cout << "Cannot load libcec.dll" << endl; + #else + cout << "Cannot load libcec.so" << endl; + #endif + return NULL; + } + + CStdString strLog; + strLog.Format("CEC Parser created - libcec version %d.%d", parser->GetLibVersionMajor(), parser->GetLibVersionMinor()); + cout << strLog.c_str() << endl; + + return parser; +} + void show_console_help(void) { cout << endl << @@ -247,26 +266,8 @@ void show_console_help(void) int main (int argc, char *argv[]) { - ICECAdapter *parser = LoadLibCec("CECTester"); - if (!parser || parser->GetMinLibVersion() > CEC_TEST_CLIENT_VERSION) - { -#ifdef __WINDOWS__ - cout << "Cannot load libcec.dll" << endl; -#else - cout << "Cannot load libcec.so" << endl; -#endif - return 1; - } - CStdString strLog; - strLog.Format("CEC Parser created - libcec version %d.%d", parser->GetLibVersionMajor(), parser->GetLibVersionMinor()); - cout << strLog.c_str() << endl; - - //make stdin non-blocking -#ifndef __WINDOWS__ - int flags = fcntl(0, F_GETFL, 0); - flags |= O_NONBLOCK; - fcntl(0, F_SETFL, flags); -#endif + cec_device_type_list typeList; + typeList.clear(); int iArgPtr = 1; while (iArgPtr < argc) @@ -313,41 +314,54 @@ int main (int argc, char *argv[]) ++iArgPtr; } } - else if (!strcmp(argv[iArgPtr], "-la") || - !strcmp(argv[iArgPtr], "--logical-address")) + else if (!strcmp(argv[iArgPtr], "-t") || + !strcmp(argv[iArgPtr], "--type")) { if (argc >= iArgPtr + 2) { - int iNewAddress = atoi(argv[iArgPtr + 1]); - if (iNewAddress >= 0 && iNewAddress <= 15) + if (!strcmp(argv[iArgPtr + 1], "p")) + { + cout << "== using device type 'playback device'" << endl; + typeList.add(CEC_DEVICE_TYPE_PLAYBACK_DEVICE); + } + else if (!strcmp(argv[iArgPtr + 1], "r")) { - g_iLogicalAddress = iNewAddress; - cout << "logical address set to " << argv[iArgPtr + 1] << endl; + cout << "== using device type 'recording device'" << endl; + typeList.add(CEC_DEVICE_TYPE_RECORDING_DEVICE); + } + else if (!strcmp(argv[iArgPtr + 1], "t")) + { + cout << "== using device type 'tuner'" << endl; + typeList.add(CEC_DEVICE_TYPE_TUNER); + } + else if (!strcmp(argv[iArgPtr + 1], "a")) + { + cout << "== using device type 'audio system'" << endl; + typeList.add(CEC_DEVICE_TYPE_AUDIO_SYSTEM); } else { - cout << "== skipped logical-address parameter: invalid address '" << argv[iArgPtr + 1] << "' ==" << endl; + cout << "== skipped invalid device type '" << argv[iArgPtr + 1] << "'" << endl; } - iArgPtr += 2; - } - else - { - cout << "== skipped logical-address parameter: no address given ==" << endl; ++iArgPtr; } + ++iArgPtr; } else if (!strcmp(argv[iArgPtr], "--list-devices") || !strcmp(argv[iArgPtr], "-l")) { - list_devices(parser); - UnloadLibCec(parser); + ICECAdapter *parser = create_parser(typeList); + if (parser) + { + list_devices(parser); + UnloadLibCec(parser); + } return 0; } else if (!strcmp(argv[iArgPtr], "--help") || !strcmp(argv[iArgPtr], "-h")) { show_help(argv[0]); - UnloadLibCec(parser); return 0; } else @@ -357,6 +371,33 @@ int main (int argc, char *argv[]) } } + if (typeList.empty()) + { + cout << "No device type given. Using 'playback device'" << endl; + typeList.add(CEC_DEVICE_TYPE_PLAYBACK_DEVICE); + } + + ICECAdapter *parser = LibCecInit("CECTester", typeList); + if (!parser || parser->GetMinLibVersion() > CEC_TEST_CLIENT_VERSION) + { +#ifdef __WINDOWS__ + cout << "Cannot load libcec.dll" << endl; +#else + cout << "Cannot load libcec.so" << endl; +#endif + return 1; + } + CStdString strLog; + strLog.Format("CEC Parser created - libcec version %d.%d", parser->GetLibVersionMajor(), parser->GetLibVersionMinor()); + cout << strLog.c_str() << endl; + + //make stdin non-blocking +#ifndef __WINDOWS__ + int flags = fcntl(0, F_GETFL, 0); + flags |= O_NONBLOCK; + fcntl(0, F_SETFL, flags); +#endif + if (g_strPort.IsEmpty()) { cout << "no serial port given. trying autodetect: "; @@ -376,8 +417,6 @@ int main (int argc, char *argv[]) } } - parser->SetLogicalAddress((cec_logical_address) g_iLogicalAddress); - if (!parser->Open(g_strPort.c_str())) { cout << "unable to open the device on port " << g_strPort << endl;