From 16b1e052e4a14432ca3bd6007e0e977ff2bed6ae Mon Sep 17 00:00:00 2001 From: Lars Op den Kamp Date: Fri, 25 Nov 2011 16:58:15 +0100 Subject: [PATCH] cec: added SetHDMIPort()/cec_set_hdmi_port(). devices are now detected on load and when a device with the same physical address is detected, libcec will use the selected hdmi port on that device. should fix source selection on other devices, like an amplifier --- include/cec.h | 7 ++ include/cecc.h | 2 + include/cectypes.h | 1 + src/lib/CECProcessor.cpp | 78 +++++++++++++++---- src/lib/CECProcessor.h | 5 +- src/lib/LibCEC.cpp | 7 +- src/lib/LibCEC.h | 1 + src/lib/LibCECC.cpp | 7 ++ src/lib/devices/CECBusDevice.cpp | 34 ++++++++ src/lib/devices/CECBusDevice.h | 3 +- src/lib/implementations/CECCommandHandler.cpp | 30 ++++--- src/lib/implementations/CECCommandHandler.h | 2 + src/testclient/main.cpp | 39 ++++++---- 13 files changed, 172 insertions(+), 44 deletions(-) diff --git a/include/cec.h b/include/cec.h index 2e47abd..5edbe18 100644 --- a/include/cec.h +++ b/include/cec.h @@ -262,6 +262,13 @@ namespace CEC * @return True when active, false otherwise. */ virtual bool IsActiveDeviceType(cec_device_type type) = 0; + + /*! + * @brief Changes the active HDMI port. + * @param iPort The new port number. + * @return True when changed, false otherwise. + */ + virtual bool SetHDMIPort(uint8_t iPort) = 0; }; }; diff --git a/include/cecc.h b/include/cecc.h index c644662..409f03a 100644 --- a/include/cecc.h +++ b/include/cecc.h @@ -185,6 +185,8 @@ extern DECLSPEC int cec_is_active_device_type(CEC::cec_device_type type); extern DECLSPEC int cec_is_active_device_type(cec_device_type type); #endif +extern DECLSPEC int cec_set_hdmi_port(uint8_t iPort); + #ifdef __cplusplus }; #endif diff --git a/include/cectypes.h b/include/cectypes.h index bc661a8..96ac603 100644 --- a/include/cectypes.h +++ b/include/cectypes.h @@ -57,6 +57,7 @@ namespace CEC { //default physical address 1.0.0.0, HDMI port 1 #define CEC_DEFAULT_PHYSICAL_ADDRESS 0x1000 +#define CEC_DEFAULT_HDMI_PORT 1 #define MSGSTART 0xFF #define MSGEND 0xFE #define MSGESC 0xFD diff --git a/src/lib/CECProcessor.cpp b/src/lib/CECProcessor.cpp index 27bf5bb..8315cd2 100644 --- a/src/lib/CECProcessor.cpp +++ b/src/lib/CECProcessor.cpp @@ -49,6 +49,7 @@ 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_bStarted(false), + m_iHDMIPort(CEC_DEFAULT_HDMI_PORT), m_strDeviceName(strDeviceName), m_communication(serComm), m_controller(controller), @@ -63,6 +64,7 @@ CCECProcessor::CCECProcessor(CLibCEC *controller, CAdapterCommunication *serComm CCECProcessor::CCECProcessor(CLibCEC *controller, CAdapterCommunication *serComm, const char *strDeviceName, const cec_device_type_list &types) : m_bStarted(false), + m_iHDMIPort(CEC_DEFAULT_HDMI_PORT), m_strDeviceName(strDeviceName), m_types(types), m_communication(serComm), @@ -148,10 +150,6 @@ bool CCECProcessor::TryLogicalAddress(cec_logical_address address) m_busDevices[address]->m_bActiveSource = true; } m_logicalAddresses.Set(address); - - // TODO - m_busDevices[address]->SetPhysicalAddress((uint16_t)CEC_DEFAULT_PHYSICAL_ADDRESS); - return true; } @@ -226,7 +224,7 @@ void *CCECProcessor::Process(void) if (m_logicalAddresses.IsEmpty() && !FindLogicalAddresses()) { CLockObject lock(&m_mutex); - m_controller->AddLog(CEC_LOG_ERROR, "could not detect our logical addressed"); + m_controller->AddLog(CEC_LOG_ERROR, "could not detect our logical addresses"); m_startCondition.Signal(); return NULL; } @@ -235,8 +233,13 @@ void *CCECProcessor::Process(void) { CLockObject lock(&m_mutex); - m_controller->AddLog(CEC_LOG_DEBUG, "processor thread started"); m_bStarted = true; + lock.Leave(); + + SetHDMIPort(m_iHDMIPort); + + lock.Lock(); + m_controller->AddLog(CEC_LOG_DEBUG, "processor thread started"); m_startCondition.Signal(); } } @@ -301,13 +304,13 @@ bool CCECProcessor::SetActiveSource(cec_device_type type /* = CEC_DEVICE_TYPE_RE } } - return SetStreamPath(m_busDevices[addr]->GetPhysicalAddress()) && + return SetStreamPath(m_busDevices[addr]->GetPhysicalAddress(false)) && m_busDevices[addr]->TransmitActiveSource(); } bool CCECProcessor::SetActiveSource(cec_logical_address iAddress) { - return SetStreamPath(m_busDevices[iAddress]->GetPhysicalAddress()); + return SetStreamPath(m_busDevices[iAddress]->GetPhysicalAddress(false)); } bool CCECProcessor::SetActiveView(void) @@ -347,6 +350,51 @@ bool CCECProcessor::SetDeckInfo(cec_deck_info info, bool bSendUpdate /* = true * return bReturn; } +bool CCECProcessor::SetHDMIPort(uint8_t iPort) +{ + bool bReturn(false); + + CStdString strLog; + strLog.Format("setting HDMI port to %d", iPort); + AddLog(CEC_LOG_DEBUG, strLog); + + m_iHDMIPort = iPort; + if (!m_bStarted) + return true; + + uint16_t iPhysicalAddress(0); + int iPos = 3; + while(!bReturn && iPos >= 0) + { + iPhysicalAddress += ((uint16_t)iPort * (0x1 << iPos*4)); + strLog.Format("checking physical address %4x", iPhysicalAddress); + AddLog(CEC_LOG_DEBUG, strLog); + if (CheckPhysicalAddress(iPhysicalAddress)) + { + strLog.Format("physical address %4x is in use", iPhysicalAddress); + AddLog(CEC_LOG_DEBUG, strLog); + iPos--; + } + else + { + SetPhysicalAddress(iPhysicalAddress); + bReturn = true; + } + } + + return bReturn; +} + +bool CCECProcessor::CheckPhysicalAddress(uint16_t iPhysicalAddress) +{ + for (unsigned int iPtr = 0; iPtr < 16; iPtr++) + { + if (m_busDevices[iPtr]->GetPhysicalAddress(false) == iPhysicalAddress) + return true; + } + return false; +} + bool CCECProcessor::SetStreamPath(uint16_t iStreamPath) { bool bReturn(false); @@ -414,9 +462,11 @@ bool CCECProcessor::SetMenuState(cec_menu_state state, bool bSendUpdate /* = tru bool CCECProcessor::SetPhysicalAddress(uint16_t iPhysicalAddress) { - if (!m_logicalAddresses.IsEmpty() && m_busDevices[m_logicalAddresses.primary]) + if (!m_logicalAddresses.IsEmpty()) { - m_busDevices[m_logicalAddresses.primary]->SetPhysicalAddress(iPhysicalAddress); + for (uint8_t iPtr = 0; iPtr < 15; iPtr++) + if (m_logicalAddresses[iPtr]) + m_busDevices[iPtr]->SetPhysicalAddress(iPhysicalAddress); return SetActiveView(); } return false; @@ -442,15 +492,15 @@ bool CCECProcessor::PollDevice(cec_logical_address iAddress) return false; } -CCECBusDevice *CCECProcessor::GetDeviceByPhysicalAddress(uint16_t iPhysicalAddress) const +CCECBusDevice *CCECProcessor::GetDeviceByPhysicalAddress(uint16_t iPhysicalAddress, bool bRefresh /* = false */) const { - if (m_busDevices[m_logicalAddresses.primary]->GetPhysicalAddress() == iPhysicalAddress) + if (m_busDevices[m_logicalAddresses.primary]->GetPhysicalAddress(false) == iPhysicalAddress) return m_busDevices[m_logicalAddresses.primary]; CCECBusDevice *device = NULL; for (unsigned int iPtr = 0; iPtr < 16; iPtr++) { - if (m_busDevices[iPtr]->GetPhysicalAddress() == iPhysicalAddress) + if (m_busDevices[iPtr]->GetPhysicalAddress(bRefresh) == iPhysicalAddress) { device = m_busDevices[iPtr]; break; @@ -685,7 +735,7 @@ bool CCECProcessor::IsActiveDeviceType(cec_device_type type) uint16_t CCECProcessor::GetPhysicalAddress(void) const { if (!m_logicalAddresses.IsEmpty() && m_busDevices[m_logicalAddresses.primary]) - return m_busDevices[m_logicalAddresses.primary]->GetPhysicalAddress(); + return m_busDevices[m_logicalAddresses.primary]->GetPhysicalAddress(false); return false; } diff --git a/src/lib/CECProcessor.h b/src/lib/CECProcessor.h index e23561b..cf9980c 100644 --- a/src/lib/CECProcessor.h +++ b/src/lib/CECProcessor.h @@ -57,7 +57,7 @@ namespace CEC virtual void *Process(void); virtual bool IsMonitoring(void) const { return m_bMonitor; } - virtual CCECBusDevice * GetDeviceByPhysicalAddress(uint16_t iPhysicalAddress) const; + virtual CCECBusDevice * GetDeviceByPhysicalAddress(uint16_t iPhysicalAddress, bool bRefresh = false) const; virtual CCECBusDevice * GetDeviceByType(cec_device_type type) const; virtual cec_version GetDeviceCecVersion(cec_logical_address iAddress); virtual bool GetDeviceMenuLanguage(cec_logical_address iAddress, cec_menu_language *language); @@ -77,6 +77,7 @@ namespace CEC virtual bool SetActiveSource(cec_logical_address iAddress); virtual bool SetDeckControlMode(cec_deck_control_mode mode, bool bSendUpdate = true); virtual bool SetDeckInfo(cec_deck_info info, bool bSendUpdate = true); + virtual bool SetHDMIPort(uint8_t iPort); virtual bool SetInactiveView(void); virtual bool SetLogicalAddress(cec_logical_address iLogicalAddress); virtual bool SetMenuState(cec_menu_state state, bool bSendUpdate = true); @@ -101,6 +102,7 @@ namespace CEC CCECBusDevice *m_busDevices[16]; private: + bool CheckPhysicalAddress(uint16_t iPhysicalAddress); bool TryLogicalAddress(cec_logical_address address); bool FindLogicalAddressRecordingDevice(void); bool FindLogicalAddressTuner(void); @@ -113,6 +115,7 @@ namespace CEC void ParseCommand(cec_command &command); bool m_bStarted; + uint8_t m_iHDMIPort; cec_command m_currentframe; cec_logical_addresses m_logicalAddresses; std::string m_strDeviceName; diff --git a/src/lib/LibCEC.cpp b/src/lib/LibCEC.cpp index 3b47651..50ab94f 100644 --- a/src/lib/LibCEC.cpp +++ b/src/lib/LibCEC.cpp @@ -161,11 +161,16 @@ bool CLibCEC::SetLogicalAddress(cec_logical_address iLogicalAddress) return m_cec ? m_cec->SetLogicalAddress(iLogicalAddress) : false; } -bool CLibCEC::SetPhysicalAddress(uint16_t iPhysicalAddress) +bool CLibCEC::SetPhysicalAddress(uint16_t iPhysicalAddress /* = CEC_DEFAULT_PHYSICAL_ADDRESS */) { return m_cec ? m_cec->SetPhysicalAddress(iPhysicalAddress) : false; } +bool CLibCEC::SetHDMIPort(uint8_t iPort /* = CEC_DEFAULT_HDMI_PORT */) +{ + return m_cec ? m_cec->SetHDMIPort(iPort) : false; +} + bool CLibCEC::PowerOnDevices(cec_logical_address address /* = CECDEVICE_TV */) { return m_cec && address >= CECDEVICE_TV && address <= CECDEVICE_BROADCAST ? m_cec->m_busDevices[(uint8_t)address]->PowerOn() : false; diff --git a/src/lib/LibCEC.h b/src/lib/LibCEC.h index b6948e4..66f1b75 100644 --- a/src/lib/LibCEC.h +++ b/src/lib/LibCEC.h @@ -87,6 +87,7 @@ namespace CEC virtual cec_logical_addresses GetActiveDevices(void); virtual bool IsActiveDevice(cec_logical_address iAddress); virtual bool IsActiveDeviceType(cec_device_type type); + virtual bool SetHDMIPort(uint8_t iPort = CEC_DEFAULT_HDMI_PORT); //@} virtual void AddLog(cec_log_level level, const std::string &strMessage); diff --git a/src/lib/LibCECC.cpp b/src/lib/LibCECC.cpp index ec703f2..76f2992 100644 --- a/src/lib/LibCECC.cpp +++ b/src/lib/LibCECC.cpp @@ -264,4 +264,11 @@ int cec_is_active_device_type(cec_device_type type) return -1; } +int cec_set_hdmi_port(uint8_t iPort) +{ + if (cec_parser) + return cec_parser->SetHDMIPort(iPort) ? 1 : 0; + return -1; +} + //@} diff --git a/src/lib/devices/CECBusDevice.cpp b/src/lib/devices/CECBusDevice.cpp index 5ca9b57..d5a0be6 100644 --- a/src/lib/devices/CECBusDevice.cpp +++ b/src/lib/devices/CECBusDevice.cpp @@ -214,6 +214,40 @@ uint16_t CCECBusDevice::GetMyPhysicalAddress(void) const return m_processor->GetPhysicalAddress(); } +uint16_t CCECBusDevice::GetPhysicalAddress(bool bRefresh /* = true */) +{ + if (GetStatus() == CEC_DEVICE_STATUS_PRESENT) + { + CLockObject lock(&m_mutex); + if (m_iPhysicalAddress == 0xFFFF || bRefresh) + { + lock.Leave(); + RequestPhysicalAddress(); + lock.Lock(); + } + } + + CLockObject lock(&m_mutex); + return m_iPhysicalAddress; +} + +bool CCECBusDevice::RequestPhysicalAddress(void) +{ + bool bReturn(false); + if (!MyLogicalAddressContains(m_iLogicalAddress)) + { + CStdString strLog; + strLog.Format("<< requesting physical address of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress); + AddLog(CEC_LOG_NOTICE, strLog); + cec_command command; + cec_command::Format(command, GetMyLogicalAddress(), m_iLogicalAddress, CEC_OPCODE_GIVE_PHYSICAL_ADDRESS); + CLockObject lock(&m_transmitMutex); + if (m_processor->Transmit(command)) + bReturn = m_condition.Wait(&m_transmitMutex, 1000); + } + return bReturn; +} + cec_power_status CCECBusDevice::GetPowerStatus(void) { CLockObject lock(&m_mutex); diff --git a/src/lib/devices/CECBusDevice.h b/src/lib/devices/CECBusDevice.h index 9173cad..57d353b 100644 --- a/src/lib/devices/CECBusDevice.h +++ b/src/lib/devices/CECBusDevice.h @@ -63,7 +63,7 @@ namespace CEC virtual cec_menu_language & GetMenuLanguage(void); virtual cec_logical_address GetMyLogicalAddress(void) const; virtual uint16_t GetMyPhysicalAddress(void) const; - virtual uint16_t GetPhysicalAddress(void) const { return m_iPhysicalAddress; } + virtual uint16_t GetPhysicalAddress(bool bRefresh = true); virtual cec_power_status GetPowerStatus(void); virtual CCECProcessor * GetProcessor(void) const { return m_processor; } virtual cec_device_type GetType(void) const { return m_type; } @@ -76,6 +76,7 @@ namespace CEC bool RequestMenuLanguage(void); bool RequestPowerStatus(void); bool RequestVendorId(void); + bool RequestPhysicalAddress(void); virtual void SetInactiveDevice(void); virtual void SetActiveDevice(void); diff --git a/src/lib/implementations/CECCommandHandler.cpp b/src/lib/implementations/CECCommandHandler.cpp index 0a39333..a073a3f 100644 --- a/src/lib/implementations/CECCommandHandler.cpp +++ b/src/lib/implementations/CECCommandHandler.cpp @@ -341,11 +341,7 @@ bool CCECCommandHandler::HandleReportPhysicalAddress(const cec_command &command) if (command.parameters.size == 3) { uint16_t iNewAddress = ((uint16_t)command.parameters[0] << 8) | ((uint16_t)command.parameters[1]); - cec_device_type type = (cec_device_type)command.parameters[2]; - - CCECBusDevice *device = GetDevice(command.initiator); - if (device && device->GetType() == type) - device->SetPhysicalAddress(iNewAddress); + SetPhysicalAddress(command.initiator, iNewAddress); } return true; } @@ -393,13 +389,7 @@ bool CCECCommandHandler::HandleRoutingInformation(const cec_command &command) if (command.parameters.size == 2) { uint16_t iNewAddress = ((uint16_t)command.parameters[0] << 8) | ((uint16_t)command.parameters[1]); - - CCECBusDevice *device = GetDevice(command.initiator); - if (device) - { - device->SetStreamPath(iNewAddress); - return true; - } + m_busDevice->GetProcessor()->SetStreamPath(iNewAddress); } return false; @@ -601,6 +591,22 @@ void CCECCommandHandler::SetVendorId(const cec_command &command) device->SetVendorId(iVendorId); } +void CCECCommandHandler::SetPhysicalAddress(cec_logical_address iAddress, uint16_t iNewAddress) +{ + if (!m_busDevice->MyLogicalAddressContains(iAddress)) + { + bool bOurAddress(m_busDevice->GetProcessor()->GetPhysicalAddress() == iNewAddress); + GetDevice(iAddress)->SetPhysicalAddress(iNewAddress); + if (bOurAddress) + { + /* another device reported the same physical address as ours + * since we don't have physical address detection yet, we'll just use the + * given address, increased by 0x100 for now */ + m_busDevice->GetProcessor()->SetPhysicalAddress(iNewAddress + 0x100); + } + } +} + const char *CCECCommandHandler::ToString(const cec_menu_state state) { switch (state) diff --git a/src/lib/implementations/CECCommandHandler.h b/src/lib/implementations/CECCommandHandler.h index 9d3ec03..245d39e 100644 --- a/src/lib/implementations/CECCommandHandler.h +++ b/src/lib/implementations/CECCommandHandler.h @@ -97,6 +97,8 @@ namespace CEC virtual CCECBusDevice *GetDeviceByType(cec_device_type type) const; virtual void SetVendorId(const cec_command &command); + virtual void SetPhysicalAddress(cec_logical_address iAddress, uint16_t iNewAddress); + CCECBusDevice *m_busDevice; }; }; diff --git a/src/testclient/main.cpp b/src/testclient/main.cpp index dbb62e7..7a60eb2 100644 --- a/src/testclient/main.cpp +++ b/src/testclient/main.cpp @@ -180,7 +180,7 @@ void ShowHelpCommandLine(const char* strExec) " -h --help Shows this help text" << endl << " -l --list-devices List all devices on this system" << endl << " -t --type {p|r|t|a} The device type to use. More than one is possible." << endl << - " -p --physical {hex-address} The physical address to use for the primary logical device." << endl << + " -p --port {int} The HDMI port to use as active source." << 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 << @@ -225,8 +225,9 @@ void ShowHelpConsole(void) "txn {bytes} transfer bytes but don't wait for transmission ACK." << endl << "on {address} power on the device with the given logical address." << endl << "standby {address} put the device with the given address in standby mode." << endl << - "la {logical_address} change the logical address of the CEC adapter." << endl << - "pa {physical_address} change the physical address of the CEC adapter." << endl << + "la {logical address} change the logical address of the CEC adapter." << endl << + "p {port number} change the HDMI port number of the CEC adapter." << endl << + "pa {physical address} change the physical address of the CEC adapter." << endl << "osd {addr} {string} set OSD message on the specified device." << endl << "ver {addr} get the CEC version of the specified device." << endl << "ven {addr} get the vendor ID of the specified device." << endl << @@ -250,7 +251,7 @@ void ShowHelpConsole(void) int main (int argc, char *argv[]) { - int16_t iPhysicalAddress = -1; + int8_t iHDMIPort(-1); cec_device_type_list typeList; typeList.clear(); @@ -362,14 +363,12 @@ int main (int argc, char *argv[]) return 0; } else if (!strcmp(argv[iArgPtr], "-p") || - !strcmp(argv[iArgPtr], "--physical")) + !strcmp(argv[iArgPtr], "--port")) { if (argc >= iArgPtr + 2) { - if (sscanf(argv[iArgPtr + 1], "%x", &iPhysicalAddress)) - cout << "using physical address '" << std::hex << iPhysicalAddress << "'" << endl; - else - cout << "== skipped physical address parameter: invalid physical address '" << argv[iArgPtr + 1] << "' ==" << endl; + iHDMIPort= atoi(argv[iArgPtr + 1]); + cout << "using HDMI port '" << iHDMIPort << "'" << endl; ++iArgPtr; } ++iArgPtr; @@ -438,6 +437,14 @@ int main (int argc, char *argv[]) } } + if (iHDMIPort > 0) + { + parser->SetHDMIPort((uint8_t)iHDMIPort); + FlushLog(parser); + } + + cout << "scanning the CEC bus..." << endl; + if (!parser->Open(g_strPort.c_str())) { cout << "unable to open the device on port " << g_strPort << endl; @@ -450,12 +457,6 @@ int main (int argc, char *argv[]) { cout << "cec device opened" << endl; - if (-1 != iPhysicalAddress) - { - parser->SetPhysicalAddress(iPhysicalAddress); - FlushLog(parser); - } - parser->PowerOnDevices(CECDEVICE_TV); FlushLog(parser); @@ -551,6 +552,14 @@ int main (int argc, char *argv[]) parser->SetLogicalAddress((cec_logical_address) atoi(strvalue.c_str())); } } + else if (command == "p") + { + string strvalue; + if (GetWord(input, strvalue)) + { + parser->SetHDMIPort(atoi(strvalue.c_str())); + } + } else if (command == "pa") { string strB1, strB2; -- 2.34.1