};
};
+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);
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.
*/
_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 *);
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,
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
{
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,
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();
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;
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())
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;
}
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;
}
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;
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;
}
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)
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);
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;
}
{
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);
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);
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;
};
};
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),
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);
* 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);
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();
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();
{
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))
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);
}
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;
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");
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;
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;
}
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);
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);
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));
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));
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);
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(); }
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);
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);
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)
{
{
bool bHandled(true);
- if (command.destination == m_busDevice->GetMyLogicalAddress())
+ if (m_busDevice->MyLogicalAddressContains(command.destination))
{
switch(command.opcode)
{
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;
}
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();
{
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;
}
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;
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;
return device;
}
-
-CCECBusDevice *CCECCommandHandler::GetThisDevice(void) const
-{
- return m_busDevice->GetProcessor()->m_busDevices[m_busDevice->GetMyLogicalAddress()];
-}
void SendToCommandBuffer(const cec_command &command);
CCECBusDevice *GetDevice(cec_logical_address iLogicalAddress) const;
- CCECBusDevice *GetThisDevice(void) const;
CCECBusDevice *m_busDevice;
};
};
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;
}
#include <cecloader.h>
int g_cecLogLevel = CEC_LOG_ALL;
-int g_iLogicalAddress = CECDEVICE_PLAYBACKDEVICE1;
ofstream g_logOutput;
bool g_bShortLog = false;
CStdString g_strPort;
"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 <<
"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 <<
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)
++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
}
}
+ 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: ";
}
}
- 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;