/**************************************************************************** ** ** Copyright (C) 2014 Digia Plc ** All rights reserved. ** For any questions to Digia, please use the contact form at ** http://www.qt.io ** ** This file is part of Qt Enterprise Embedded. ** ** Licensees holding valid Qt Enterprise licenses may use this file in ** accordance with the Qt Enterprise License Agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Digia. ** ** If you have questions regarding the use of this file, please use ** the contact form at http://www.qt.io ** ****************************************************************************/ #include "b2qtdevice.h" #include #include #include #include #include #include #include #include #include #include // When we can't query directly, at least remember what we have set it to static quint8 knownBrightness = 255; B2QtDevice::B2QtDevice(QObject *parent) : QObject(parent) { } B2QtDevice::~B2QtDevice() { } /*! * Reboots the system. Does not return. * * \sa powerOff() */ void B2QtDevice::reboot() { sync(); ::reboot(RB_AUTOBOOT); qWarning("reboot returned"); } /*! * Shuts down the system. Does not return. * * \sa reboot() */ void B2QtDevice::powerOff() { sync(); ::reboot(RB_POWER_OFF); qWarning("powerOff returned"); } class LightDevice { public: QString name; QString deviceFile; quint8 value; uint maxValue; }; static QList lightDevices; static bool lightDevicesInitialized = false; static void initLightDevices() { if (lightDevicesInitialized) return; QDirIterator it(QStringLiteral("/sys/class/backlight")); while (it.hasNext()) { LightDevice ld; ld.deviceFile = it.next() + QStringLiteral("/brightness"); QFile maxFile(it.filePath() + QStringLiteral("/max_brightness")); if (!maxFile.open(QIODevice::ReadOnly)) continue; bool ok = false; ld.maxValue = maxFile.read(10).simplified().toUInt(&ok); if (!ok || !ld.maxValue) continue; QFile valFile(ld.deviceFile); if (!valFile.open(QIODevice::ReadOnly)) continue; ok = false; uint val = valFile.read(10).simplified().toUInt(&ok); if (!ok) continue; // map max->max as that is a common case, otherwise choose a reasonable value ld.value = (val == ld.maxValue) ? 255 : (val * 256)/(ld.maxValue+1); ld.name = it.fileName(); lightDevices.append(ld); } if (!lightDevices.isEmpty()) knownBrightness = lightDevices.at(0).value; lightDevicesInitialized = true; } /*! * Sets the display brightness (i.e. the intensity of the backlight) * to \a value. A value of 255 requests maximum brightness, while 0 requests * minimum (typically, the backlight turned off). * * Returns true on success. */ bool B2QtDevice::setDisplayBrightness(int v) { quint8 value = qBound(0, v, 255); initLightDevices(); for (int i = 0; i < lightDevices.size(); i++) { LightDevice &ld = lightDevices[i]; QFile devFile(ld.deviceFile); if (!devFile.open(QIODevice::WriteOnly)) continue; // Maps only 0 to 0, since 0 often means "off"; other values are degrees of "on". uint newVal = value ? 1 + ((value * ld.maxValue) / 256) : 0; devFile.write(QByteArray::number(newVal)); ld.value = value; } knownBrightness = value; return true; } /*! * Returns the current backlight intensity. * \sa setDisplayBrightness */ int B2QtDevice::displayBrightness() const { initLightDevices(); return knownBrightness; } /*! * Gets the current IP address(es) of the device */ QString B2QtDevice::getIPAddress() const { QStringList addresses; foreach (const QNetworkInterface &interface, QNetworkInterface::allInterfaces()) { QNetworkInterface::InterfaceFlags flags = interface.flags(); if (flags.testFlag(QNetworkInterface::IsRunning) && !flags.testFlag(QNetworkInterface::IsLoopBack)) { foreach (const QNetworkAddressEntry &entry, interface.addressEntries()) addresses.append(entry.ip().toString().split('%').first()); } } return addresses.join(QStringLiteral(", ")); } /*! * Gets the current hostname of the device */ QString B2QtDevice::hostname() const { QString name; name = QHostInfo::localHostName(); return name; } /*! * Sets new hostname for the device */ bool B2QtDevice::setHostname(const QString &name) { QByteArray lname = name.toLocal8Bit(); if (::sethostname(lname.constData(), lname.length())) { qWarning("Could not set system hostname"); return false; } // Also store it for next boot: QFile file(QStringLiteral("/etc/hostname")); if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { qWarning("Could not write to /etc/hostname"); return false; } file.write(lname.append('\n')); file.close(); emit hostnameChanged(name); return true; } /*! * Sets the master volume to \a volume. * The volume can range from 0 to 100 and is linear. */ void B2QtDevice::setMasterVolume(int volume) { Q_UNUSED(volume) } /*! * Returns the current master volume. * The volume can range from 0 to 100 and is linear. */ int B2QtDevice::masterVolume() const { return 0; } /*! * Initializes the audio subsystem, setting the volume to max. * This is done during system startup, so there is normally no need to call this function from applications. */ void B2QtDevice::initAudio() { } class PhysicalScreenSize : public QObject { Q_OBJECT public: PhysicalScreenSize(); void setSize(int inches); int size() const { return physScreenSizeInch; } bool enabled() const; void setEnabled(bool enable); private slots: void onTimeout(); private: void read(const QString &filename); void write(bool includePhysSize = true); void write(const QString &filename, bool includePhysSize = true); bool physScreenSizeEnabled; int physScreenSizeInch; QTimer physWriteTimer; }; Q_GLOBAL_STATIC(PhysicalScreenSize, physScreenSize) PhysicalScreenSize::PhysicalScreenSize() : physScreenSizeEnabled(false), physScreenSizeInch(7) { physWriteTimer.setSingleShot(true); physWriteTimer.setInterval(1000); QObject::connect(&physWriteTimer, SIGNAL(timeout()), this, SLOT(onTimeout())); read(QStringLiteral("/etc/appcontroller.conf")); read(QStringLiteral("/var/lib/b2qt/appcontroller.conf.d/physical_screen_size.conf")); } void PhysicalScreenSize::read(const QString &filename) { QFile f(filename); if (!f.open(QIODevice::ReadOnly | QIODevice::Text)) return; int physScreenWidth = 154, physScreenHeight = 90; int found = 0; while (!f.atEnd()) { QByteArray line = f.readLine().trimmed(); if (line.startsWith(QByteArrayLiteral("env="))) { QByteArrayList values = line.split('='); if (values.count() == 3) { bool ok; if (values[1] == QByteArrayLiteral("QT_QPA_EGLFS_PHYSICAL_WIDTH")) { int val = values[2].toInt(&ok); if (ok) { ++found; physScreenWidth = val; } } else if (values[1] == QByteArrayLiteral("QT_QPA_EGLFS_PHYSICAL_HEIGHT")) { int val = values[2].toInt(&ok); if (ok) { ++found; physScreenHeight = val; } } } } } if (found == 2) physScreenSizeEnabled = true; const qreal diagMM = qSqrt(physScreenWidth * physScreenWidth + physScreenHeight * physScreenHeight); physScreenSizeInch = qRound(diagMM / 25.4); } void PhysicalScreenSize::onTimeout() { write(); } void PhysicalScreenSize::write(bool includePhysSize) { QDir(QStringLiteral("/var/lib")).mkpath(QStringLiteral("b2qt/appcontroller.conf.d")); write(QStringLiteral("/var/lib/b2qt/appcontroller.conf.d/physical_screen_size.conf"), includePhysSize); } void PhysicalScreenSize::write(const QString &filename, bool includePhysSize) { QFile f(filename); QByteArrayList lines; if (f.open(QIODevice::ReadOnly | QIODevice::Text)) { while (!f.atEnd()) { QByteArray line = f.readLine().trimmed(); if (!line.startsWith(QByteArrayLiteral("env=QT_QPA_EGLFS_PHYSICAL_WIDTH=")) && !line.startsWith(QByteArrayLiteral("env=QT_QPA_EGLFS_PHYSICAL_HEIGHT="))) lines.append(line); } f.close(); } if (!f.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) return; const qreal diagMM = physScreenSizeInch * 25.4; // Assume 16:9 aspect ratio const int physScreenHeight = qRound(diagMM / 1.975); const int physScreenWidth = qRound(physScreenHeight * 1.777); foreach (const QByteArray &line, lines) f.write(line + QByteArrayLiteral("\n")); if (includePhysSize) f.write(QByteArrayLiteral("env=QT_QPA_EGLFS_PHYSICAL_WIDTH=") + QByteArray::number(physScreenWidth) + QByteArrayLiteral("\nenv=QT_QPA_EGLFS_PHYSICAL_HEIGHT=") + QByteArray::number(physScreenHeight) + QByteArrayLiteral("\n")); } void PhysicalScreenSize::setSize(int inches) { physScreenSizeInch = inches; physWriteTimer.start(); } bool PhysicalScreenSize::enabled() const { return physScreenSizeEnabled; } void PhysicalScreenSize::setEnabled(bool enable) { physScreenSizeEnabled = enable; // Rewrite appcontroller.conf with or without the physical width/height lines. write(enable); } int B2QtDevice::physicalScreenSizeInch() const { return physScreenSize()->size(); } void B2QtDevice::setPhysicalScreenSizeInch(int inches) { if (physScreenSize()->size() != inches) { physScreenSize()->setSize(inches); emit physicalScreenSizeInchChanged(inches); } } bool B2QtDevice::physicalScreenSizeOverride() const { return physScreenSize()->enabled(); } void B2QtDevice::setPhysicalScreenSizeOverride(bool enable) { if (physScreenSize()->enabled() != enable) { physScreenSize()->setEnabled(enable); emit physicalScreenSizeOverrideChanged(enable); } } #include "b2qtdevice.moc"