* @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;
};
};
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
//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
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),
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),
m_busDevices[address]->m_bActiveSource = true;
}
m_logicalAddresses.Set(address);
-
- // TODO
- m_busDevices[address]->SetPhysicalAddress((uint16_t)CEC_DEFAULT_PHYSICAL_ADDRESS);
-
return true;
}
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;
}
{
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();
}
}
}
}
- 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)
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);
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;
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;
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;
}
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);
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);
CCECBusDevice *m_busDevices[16];
private:
+ bool CheckPhysicalAddress(uint16_t iPhysicalAddress);
bool TryLogicalAddress(cec_logical_address address);
bool FindLogicalAddressRecordingDevice(void);
bool FindLogicalAddressTuner(void);
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;
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;
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);
return -1;
}
+int cec_set_hdmi_port(uint8_t iPort)
+{
+ if (cec_parser)
+ return cec_parser->SetHDMIPort(iPort) ? 1 : 0;
+ return -1;
+}
+
//@}
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);
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; }
bool RequestMenuLanguage(void);
bool RequestPowerStatus(void);
bool RequestVendorId(void);
+ bool RequestPhysicalAddress(void);
virtual void SetInactiveDevice(void);
virtual void SetActiveDevice(void);
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;
}
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;
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)
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;
};
};
" -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 <<
"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 <<
int main (int argc, char *argv[])
{
- int16_t iPhysicalAddress = -1;
+ int8_t iHDMIPort(-1);
cec_device_type_list typeList;
typeList.clear();
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;
}
}
+ 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;
{
cout << "cec device opened" << endl;
- if (-1 != iPhysicalAddress)
- {
- parser->SetPhysicalAddress(iPhysicalAddress);
- FlushLog(parser);
- }
-
parser->PowerOnDevices(CECDEVICE_TV);
FlushLog(parser);
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;