+ return true;
+}
+
+int CecLogMessage(void *UNUSED(cbParam), const cec_log_message &message)
+{
+ if ((message.level & g_cecLogLevel) == message.level)
+ {
+ CStdString strLevel;
+ switch (message.level)
+ {
+ case CEC_LOG_ERROR:
+ strLevel = "ERROR: ";
+ break;
+ case CEC_LOG_WARNING:
+ strLevel = "WARNING: ";
+ break;
+ case CEC_LOG_NOTICE:
+ strLevel = "NOTICE: ";
+ break;
+ case CEC_LOG_TRAFFIC:
+ strLevel = "TRAFFIC: ";
+ break;
+ case CEC_LOG_DEBUG:
+ strLevel = "DEBUG: ";
+ break;
+ default:
+ break;
+ }
+
+ CStdString strFullLog;
+ strFullLog.Format("%s[%16lld]\t%s", strLevel.c_str(), message.time, message.message);
+ PrintToStdOut(strFullLog.c_str());
+
+ if (g_logOutput.is_open())
+ {
+ if (g_bShortLog)
+ g_logOutput << message.message << endl;
+ else
+ g_logOutput << strFullLog.c_str() << endl;
+ }
+ }
+
+ return 0;
+}
+
+int CecKeyPress(void *UNUSED(cbParam), const cec_keypress &UNUSED(key))
+{
+ return 0;
+}
+
+int CecCommand(void *UNUSED(cbParam), const cec_command &UNUSED(command))
+{
+ return 0;
+}
+
+int CecAlert(void *UNUSED(cbParam), const libcec_alert type, const libcec_parameter &UNUSED(param))
+{
+ switch (type)
+ {
+ case CEC_ALERT_CONNECTION_LOST:
+ PrintToStdOut("Connection lost - exiting\n");
+ g_bExit = true;
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+void ListDevices(ICECAdapter *parser)
+{
+ cec_adapter *devices = new cec_adapter[10];
+ int8_t iDevicesFound = parser->FindAdapters(devices, 10, NULL);
+ if (iDevicesFound <= 0)
+ {
+ PrintToStdOut("Found devices: NONE");
+ }
+ else
+ {
+ CStdString strDeviceInfo;
+ strDeviceInfo.Format("Found devices: %d\n\n", iDevicesFound);
+
+ for (int8_t iDevicePtr = 0; iDevicePtr < iDevicesFound; iDevicePtr++)
+ {
+ strDeviceInfo.AppendFormat("device: %d\ncom port: %s\n", iDevicePtr + 1, devices[iDevicePtr].comm);
+ libcec_configuration config;
+ config.Clear();
+
+ if (!parser->GetDeviceInformation(devices[iDevicePtr].comm, &config))
+ PrintToStdOut("WARNING: unable to open the device on port %s", devices[iDevicePtr].comm);
+ else
+ {
+ strDeviceInfo.AppendFormat("firmware version: %d\n", config.iFirmwareVersion);
+
+ if (config.iFirmwareBuildDate != CEC_FW_BUILD_UNKNOWN)
+ {
+ time_t buildTime = (time_t)config.iFirmwareBuildDate;
+ strDeviceInfo.AppendFormat("firmware build date: %s", asctime(gmtime(&buildTime)));
+ strDeviceInfo = strDeviceInfo.Left(strDeviceInfo.length() > 1 ? (unsigned)(strDeviceInfo.length() - 1) : 0); // strip \n added by asctime
+ strDeviceInfo.append(" +0000");
+ }
+ }
+ strDeviceInfo.append("\n");
+ }
+ PrintToStdOut(strDeviceInfo.c_str());
+ }
+}
+
+void ShowHelpCommandLine(const char* strExec)
+{
+ CLockObject lock(g_outputMutex);
+ cout << endl <<
+ strExec << " {-h|--help|-l|--list-devices|[COM PORT]}" << endl <<
+ endl <<
+ "parameters:" << endl <<
+ " -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 --port {int} The HDMI port to use as active source." << endl <<
+ " -b --base {int} The logical address of the device to with this " << endl <<
+ " adapter is connected." << endl <<
+ " -f --log-file {file} Writes all libCEC log message to a file" << endl <<
+ " -r --rom Read persisted settings from the EEPROM" << endl <<
+ " -sf --short-log-file {file} Writes all libCEC log message without timestamps" << endl <<
+ " and log levels to a file." << endl <<
+ " -d --log-level {level} Sets the log level. See cectypes.h for values." << endl <<
+ " -s --single-command Execute a single command and exit. Does not power" << endl <<
+ " on devices on startup and power them off on exit." << endl <<
+ " -o --osd-name {osd name} Use a custom osd name." << endl <<
+ " -m --monitor Start a monitor-only client." << endl <<
+ " -i --info Shows information about how libCEC was compiled." << endl <<
+ " [COM PORT] The com port to connect to. If no COM" << endl <<
+ " port is given, the client tries to connect to the" << endl <<
+ " first device that is detected." << endl <<
+ endl <<
+ "Type 'h' or 'help' and press enter after starting the client to display all " << endl <<
+ "available commands" << endl;
+}
+
+void ShowHelpConsole(void)
+{
+ CLockObject lock(g_outputMutex);
+ cout << endl <<
+ "================================================================================" << endl <<
+ "Available commands:" << endl <<
+ endl <<
+ "[tx] {bytes} transfer bytes over the CEC line." << 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 <<
+ "[p] {device} {port} change the HDMI port number of the CEC adapter." << endl <<
+ "[pa] {physical address} change the physical address of the CEC adapter." << endl <<
+ "[as] make the CEC adapter the active source." << 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 <<
+ "[lang] {addr} get the menu language of the specified device." << endl <<
+ "[pow] {addr} get the power status of the specified device." << endl <<
+ "[name] {addr} get the OSD name of the specified device." << endl <<
+ "[poll] {addr} poll the specified device." << endl <<
+ "[lad] lists active devices on the bus" << endl <<
+ "[ad] {addr} checks whether the specified device is active." << endl <<
+ "[at] {type} checks whether the specified device type is active." << endl <<
+ "[sp] {addr} makes the specified physical address active." << endl <<
+ "[spl] {addr} makes the specified logical address active." << endl <<
+ "[volup] send a volume up command to the amp if present" << endl <<
+ "[voldown] send a volume down command to the amp if present" << endl <<
+ "[mute] send a mute/unmute command to the amp if present" << endl <<
+ "[self] show the list of addresses controlled by libCEC" << endl <<
+ "[scan] scan the CEC bus and display device info" << endl <<
+ "[mon] {1|0} enable or disable CEC bus monitoring." << endl <<
+ "[log] {1 - 31} change the log level. see cectypes.h for values." << endl <<
+ "[ping] send a ping command to the CEC adapter." << endl <<
+ "[bl] to let the adapter enter the bootloader, to upgrade" << endl <<
+ " the flash rom." << endl <<
+ "[r] reconnect to the CEC adapter." << endl <<
+ "[h] or [help] show this help." << endl <<
+ "[q] or [quit] to quit the CEC test client and switch off all" << endl <<
+ " connected CEC devices." << endl <<
+ "================================================================================" << endl;
+}
+
+bool ProcessCommandSELF(ICECAdapter *parser, const string &command, string & UNUSED(arguments))
+{
+ if (command == "self")
+ {
+ cec_logical_addresses addr = parser->GetLogicalAddresses();
+ CStdString strOut = "Addresses controlled by libCEC: ";
+ bool bFirst(true);
+ for (uint8_t iPtr = 0; iPtr <= 15; iPtr++)
+ {
+ if (addr[iPtr])
+ {
+ strOut.AppendFormat((bFirst ? "%d%s" : ", %d%s"), iPtr, parser->IsActiveSource((cec_logical_address)iPtr) ? "*" : "");
+ bFirst = false;
+ }
+ }
+ PrintToStdOut(strOut.c_str());
+ return true;
+ }
+
+ return false;
+}
+
+bool ProcessCommandSP(ICECAdapter *parser, const string &command, string &arguments)
+{
+ if (command == "sp")
+ {
+ string strAddress;
+ int iAddress;
+ if (GetWord(arguments, strAddress))
+ {
+ sscanf(strAddress.c_str(), "%x", &iAddress);
+ if (iAddress >= 0 && iAddress <= CEC_INVALID_PHYSICAL_ADDRESS)
+ parser->SetStreamPath((uint16_t)iAddress);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool ProcessCommandSPL(ICECAdapter *parser, const string &command, string &arguments)
+{
+ if (command == "spl")
+ {
+ string strAddress;
+ cec_logical_address iAddress;
+ if (GetWord(arguments, strAddress))
+ {
+ iAddress = (cec_logical_address)atoi(strAddress.c_str());
+ if (iAddress >= CECDEVICE_TV && iAddress < CECDEVICE_BROADCAST)
+ parser->SetStreamPath(iAddress);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool ProcessCommandTX(ICECAdapter *parser, const string &command, string &arguments)
+{
+ if (command == "tx" || command == "txn")
+ {
+ string strvalue;
+ uint8_t ivalue;
+ cec_command bytes;
+ bytes.Clear();
+
+ while (GetWord(arguments, strvalue) && HexStrToInt(strvalue, ivalue))
+ bytes.PushBack(ivalue);
+
+ if (command == "txn")
+ bytes.transmit_timeout = 0;
+
+ parser->Transmit(bytes);
+
+ return true;
+ }
+
+ return false;
+}
+
+bool ProcessCommandON(ICECAdapter *parser, const string &command, string &arguments)
+{
+ if (command == "on")
+ {
+ string strValue;
+ uint8_t iValue = 0;
+ if (GetWord(arguments, strValue) && HexStrToInt(strValue, iValue) && iValue <= 0xF)
+ {
+ parser->PowerOnDevices((cec_logical_address) iValue);
+ return true;
+ }
+ else
+ {
+ PrintToStdOut("invalid destination");
+ }
+ }
+
+ return false;
+}
+
+bool ProcessCommandSTANDBY(ICECAdapter *parser, const string &command, string &arguments)
+{
+ if (command == "standby")
+ {
+ string strValue;
+ uint8_t iValue = 0;
+ if (GetWord(arguments, strValue) && HexStrToInt(strValue, iValue) && iValue <= 0xF)
+ {
+ parser->StandbyDevices((cec_logical_address) iValue);
+ return true;
+ }
+ else
+ {
+ PrintToStdOut("invalid destination");
+ }
+ }
+
+ return false;
+}
+
+bool ProcessCommandPOLL(ICECAdapter *parser, const string &command, string &arguments)
+{
+ if (command == "poll")
+ {
+ string strValue;
+ uint8_t iValue = 0;
+ if (GetWord(arguments, strValue) && HexStrToInt(strValue, iValue) && iValue <= 0xF)
+ {
+ if (parser->PollDevice((cec_logical_address) iValue))
+ PrintToStdOut("POLL message sent");
+ else
+ PrintToStdOut("POLL message not sent");
+ return true;
+ }
+ else
+ {
+ PrintToStdOut("invalid destination");
+ }
+ }
+
+ return false;
+}
+
+bool ProcessCommandLA(ICECAdapter *parser, const string &command, string &arguments)
+{
+ if (command == "la")
+ {
+ string strvalue;
+ if (GetWord(arguments, strvalue))
+ {
+ parser->SetLogicalAddress((cec_logical_address) atoi(strvalue.c_str()));
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool ProcessCommandP(ICECAdapter *parser, const string &command, string &arguments)
+{
+ if (command == "p")
+ {
+ string strPort, strDevice;
+ if (GetWord(arguments, strDevice) && GetWord(arguments, strPort))
+ {
+ parser->SetHDMIPort((cec_logical_address)atoi(strDevice.c_str()), (uint8_t)atoi(strPort.c_str()));
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool ProcessCommandPA(ICECAdapter *parser, const string &command, string &arguments)
+{
+ if (command == "pa")
+ {
+ string strB1, strB2;
+ uint8_t iB1, iB2;
+ if (GetWord(arguments, strB1) && HexStrToInt(strB1, iB1) &&
+ GetWord(arguments, strB2) && HexStrToInt(strB2, iB2))
+ {
+ uint16_t iPhysicalAddress = ((uint16_t)iB1 << 8) + iB2;
+ parser->SetPhysicalAddress(iPhysicalAddress);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool ProcessCommandOSD(ICECAdapter *parser, const string &command, string &arguments)
+{
+ if (command == "osd")
+ {
+ bool bFirstWord(false);
+ string strAddr, strMessage, strWord;
+ uint8_t iAddr;
+ if (GetWord(arguments, strAddr) && HexStrToInt(strAddr, iAddr) && iAddr < 0xF)
+ {
+ while (GetWord(arguments, strWord))
+ {
+ if (bFirstWord)
+ {
+ bFirstWord = false;
+ strMessage.append(" ");
+ }
+ strMessage.append(strWord);
+ }
+ parser->SetOSDString((cec_logical_address) iAddr, CEC_DISPLAY_CONTROL_DISPLAY_FOR_DEFAULT_TIME, strMessage.c_str());
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool ProcessCommandAS(ICECAdapter *parser, const string &command, string & UNUSED(arguments))
+{
+ if (command == "as")
+ {
+ parser->SetActiveSource();
+ return true;
+ }
+
+ return false;
+}
+
+
+bool ProcessCommandPING(ICECAdapter *parser, const string &command, string & UNUSED(arguments))
+{
+ if (command == "ping")
+ {
+ parser->PingAdapter();
+ return true;
+ }
+
+ return false;
+}
+
+bool ProcessCommandVOLUP(ICECAdapter *parser, const string &command, string & UNUSED(arguments))
+{
+ if (command == "volup")
+ {
+ PrintToStdOut("volume up: %2X", parser->VolumeUp());
+ return true;
+ }
+
+ return false;
+}
+
+bool ProcessCommandVOLDOWN(ICECAdapter *parser, const string &command, string & UNUSED(arguments))
+{
+ if (command == "voldown")
+ {
+ PrintToStdOut("volume down: %2X", parser->VolumeDown());
+ return true;
+ }
+
+ return false;
+}
+
+bool ProcessCommandMUTE(ICECAdapter *parser, const string &command, string & UNUSED(arguments))
+{
+ if (command == "mute")
+ {
+ PrintToStdOut("mute: %2X", parser->MuteAudio());
+ return true;
+ }
+
+ return false;
+}
+
+bool ProcessCommandMON(ICECAdapter *parser, const string &command, string &arguments)
+{
+ if (command == "mon")
+ {
+ CStdString strEnable;
+ if (GetWord(arguments, strEnable) && (strEnable.Equals("0") || strEnable.Equals("1")))
+ {
+ parser->SwitchMonitoring(strEnable.Equals("1"));
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool ProcessCommandBL(ICECAdapter *parser, const string &command, string & UNUSED(arguments))
+{
+ if (command == "bl")
+ {
+ if (parser->StartBootloader())
+ {
+ PrintToStdOut("entered bootloader mode. exiting cec-client");
+ g_bExit = true;
+ g_bHardExit = true;
+ }
+ return true;
+ }
+
+ return false;
+}
+
+bool ProcessCommandLANG(ICECAdapter *parser, const string &command, string &arguments)
+{
+ if (command == "lang")
+ {
+ CStdString strDev;
+ if (GetWord(arguments, strDev))
+ {
+ int iDev = atoi(strDev);
+ if (iDev >= 0 && iDev < 15)
+ {
+ CStdString strLog;
+ cec_menu_language language;
+ if (parser->GetDeviceMenuLanguage((cec_logical_address) iDev, &language))
+ strLog.Format("menu language '%s'", language.language);
+ else
+ strLog = "failed!";
+ PrintToStdOut(strLog);
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool ProcessCommandVEN(ICECAdapter *parser, const string &command, string &arguments)
+{
+ if (command == "ven")
+ {
+ CStdString strDev;
+ if (GetWord(arguments, strDev))
+ {
+ int iDev = atoi(strDev);
+ if (iDev >= 0 && iDev < 15)
+ {
+ uint64_t iVendor = parser->GetDeviceVendorId((cec_logical_address) iDev);
+ PrintToStdOut("vendor id: %06x", iVendor);
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool ProcessCommandVER(ICECAdapter *parser, const string &command, string &arguments)
+{
+ if (command == "ver")
+ {
+ CStdString strDev;
+ if (GetWord(arguments, strDev))
+ {
+ int iDev = atoi(strDev);
+ if (iDev >= 0 && iDev < 15)
+ {
+ cec_version iVersion = parser->GetDeviceCecVersion((cec_logical_address) iDev);
+ PrintToStdOut("CEC version %s", parser->ToString(iVersion));
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool ProcessCommandPOW(ICECAdapter *parser, const string &command, string &arguments)
+{
+ if (command == "pow")
+ {
+ CStdString strDev;
+ if (GetWord(arguments, strDev))
+ {
+ int iDev = atoi(strDev);
+ if (iDev >= 0 && iDev < 15)
+ {
+ cec_power_status iPower = parser->GetDevicePowerStatus((cec_logical_address) iDev);
+ PrintToStdOut("power status: %s", parser->ToString(iPower));
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool ProcessCommandNAME(ICECAdapter *parser, const string &command, string &arguments)
+{
+ if (command == "name")
+ {
+ CStdString strDev;
+ if (GetWord(arguments, strDev))
+ {
+ int iDev = atoi(strDev);
+ if (iDev >= 0 && iDev < 15)
+ {
+ cec_osd_name name = parser->GetDeviceOSDName((cec_logical_address)iDev);
+ PrintToStdOut("OSD name of device %d is '%s'", iDev, name.name);
+ }
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool ProcessCommandLAD(ICECAdapter *parser, const string &command, string & UNUSED(arguments))
+{
+ if (command == "lad")
+ {
+ PrintToStdOut("listing active devices:");
+ cec_logical_addresses addresses = parser->GetActiveDevices();
+ for (uint8_t iPtr = 0; iPtr <= 11; iPtr++)
+ if (addresses[iPtr])
+ {
+ PrintToStdOut("logical address %X", (int)iPtr);
+ }
+ return true;
+ }
+
+ return false;
+}
+
+bool ProcessCommandAD(ICECAdapter *parser, const string &command, string &arguments)
+{
+ if (command == "ad")
+ {
+ CStdString strDev;
+ if (GetWord(arguments, strDev))
+ {
+ int iDev = atoi(strDev);
+ if (iDev >= 0 && iDev < 15)
+ PrintToStdOut("logical address %X is %s", iDev, (parser->IsActiveDevice((cec_logical_address)iDev) ? "active" : "not active"));
+ }
+ }
+
+ return false;
+}
+
+bool ProcessCommandAT(ICECAdapter *parser, const string &command, string &arguments)
+{
+ if (command == "at")
+ {
+ CStdString strType;
+ if (GetWord(arguments, strType))
+ {
+ cec_device_type type = CEC_DEVICE_TYPE_TV;
+ if (strType.Equals("a"))
+ type = CEC_DEVICE_TYPE_AUDIO_SYSTEM;
+ else if (strType.Equals("p"))
+ type = CEC_DEVICE_TYPE_PLAYBACK_DEVICE;
+ else if (strType.Equals("r"))
+ type = CEC_DEVICE_TYPE_RECORDING_DEVICE;
+ else if (strType.Equals("t"))
+ type = CEC_DEVICE_TYPE_TUNER;
+
+ PrintToStdOut("device %d is %s", type, (parser->IsActiveDeviceType(type) ? "active" : "not active"));
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool ProcessCommandR(ICECAdapter *parser, const string &command, string & UNUSED(arguments))
+{
+ if (command == "r")
+ {
+ bool bReactivate = parser->IsLibCECActiveSource();
+
+ PrintToStdOut("closing the connection");
+ parser->Close();
+
+ PrintToStdOut("opening a new connection");
+ parser->Open(g_strPort.c_str());
+
+ if (bReactivate)
+ {
+ PrintToStdOut("setting active source");
+ parser->SetActiveSource();
+ }
+ return true;
+ }
+
+ return false;
+}
+
+bool ProcessCommandH(ICECAdapter * UNUSED(parser), const string &command, string & UNUSED(arguments))
+{
+ if (command == "h" || command == "help")
+ {
+ ShowHelpConsole();
+ return true;
+ }
+
+ return false;