File indexing completed on 2024-05-05 17:39:48

0001 /*
0002     KSysGuard, the KDE System Guard
0003 
0004     SPDX-FileCopyrightText: 1999, 2000 Chris Schlaeger <cs@kde.org>
0005     SPDX-FileCopyrightText: 2006 John Tapsell <tapsell@kde.org>
0006 
0007     SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0008 
0009 */
0010 
0011 #ifndef KSG_SENSORCLIENT_H
0012 #define KSG_SENSORCLIENT_H
0013 
0014 #include <QByteArray>
0015 #include <QList>
0016 #include <QString>
0017 
0018 namespace KSGRD
0019 {
0020 /**
0021   Every object that should act as a client to a sensor must inherit from
0022   this class. A pointer to the client object is passed as SensorClient*
0023   to the SensorAgent. When the requested information is available or a
0024   problem occurred one of the member functions is called.
0025  */
0026 class SensorClient
0027 {
0028 public:
0029     explicit SensorClient()
0030     {
0031     }
0032     virtual ~SensorClient()
0033     {
0034     }
0035 
0036     /**
0037       This function is called whenever the information from the sensor has
0038       been received by the sensor agent. This function must be reimplemented
0039       by the sensor client to receive and process this information.
0040      */
0041     virtual void answerReceived(int id, const QList<QByteArray> &answer)
0042     {
0043         Q_UNUSED(id);
0044         Q_UNUSED(answer);
0045     }
0046 
0047     /**
0048       In case of an unexpected fatal problem with the sensor the sensor
0049       agent will call this function to notify the client about it.
0050      */
0051     virtual void sensorLost(int id)
0052     {
0053         Q_UNUSED(id);
0054     }
0055 };
0056 
0057 /**
0058   The following classes are utility classes that provide a
0059   convenient way to retrieve pieces of information from the sensor
0060   answers. For each type of answer there is a separate class.
0061  */
0062 class SensorTokenizer
0063 {
0064 public:
0065     SensorTokenizer(const QByteArray &info, char separator)
0066     {
0067         if (separator == '/') {
0068             // This is a special case where we assume that info is a '\' escaped string
0069 
0070             int i = 0;
0071             int lastTokenAt = -1;
0072 
0073             for (; i < info.length(); ++i) {
0074                 if (info[i] == '\\') {
0075                     ++i;
0076                 } else if (info[i] == separator) {
0077                     mTokens.append(unEscapeString(info.mid(lastTokenAt + 1, i - lastTokenAt - 1)));
0078                     lastTokenAt = i;
0079                 }
0080             }
0081 
0082             // Add everything after the last token
0083             mTokens.append(unEscapeString(info.mid(lastTokenAt + 1, i - lastTokenAt - 1)));
0084         } else {
0085             mTokens = info.split(separator);
0086         }
0087     }
0088 
0089     ~SensorTokenizer()
0090     {
0091     }
0092 
0093     const QByteArray &operator[](unsigned idx)
0094     {
0095         Q_ASSERT(idx < (unsigned)(mTokens.count()));
0096         return mTokens[idx];
0097     }
0098 
0099     uint count()
0100     {
0101         return mTokens.count();
0102     }
0103 
0104 private:
0105     QList<QByteArray> mTokens;
0106 
0107     QByteArray unEscapeString(QByteArray string)
0108     {
0109         int i = 0;
0110         for (; i < string.length(); ++i) {
0111             if (string[i] == '\\') {
0112                 string.remove(i, 1);
0113                 ++i;
0114             }
0115         }
0116 
0117         return string;
0118     }
0119 };
0120 
0121 /**
0122   An integer info contains 4 fields separated by TABS, a description
0123   (name), the minimum and the maximum values and the unit.
0124   e.g. Swap Memory  0   133885952   KB
0125  */
0126 class SensorIntegerInfo : public SensorTokenizer
0127 {
0128 public:
0129     explicit SensorIntegerInfo(const QByteArray &info)
0130         : SensorTokenizer(info, '\t')
0131     {
0132     }
0133 
0134     ~SensorIntegerInfo()
0135     {
0136     }
0137 
0138     QString name()
0139     {
0140         if (count() > 0)
0141             return QString::fromUtf8((*this)[0]);
0142         return QString();
0143     }
0144 
0145     long long min()
0146     {
0147         if (count() > 1)
0148             return (*this)[1].toLongLong();
0149         return -1;
0150     }
0151 
0152     long long max()
0153     {
0154         if (count() > 2)
0155             return (*this)[2].toLongLong();
0156         return -1;
0157     }
0158 
0159     QString unit()
0160     {
0161         if (count() > 3)
0162             return QString::fromUtf8((*this)[3]);
0163         return QString();
0164     }
0165 };
0166 
0167 /**
0168   An float info contains 4 fields separated by TABS, a description
0169   (name), the minimum and the maximum values and the unit.
0170   e.g. CPU Voltage 0.0  5.0 V
0171  */
0172 class SensorFloatInfo : public SensorTokenizer
0173 {
0174 public:
0175     explicit SensorFloatInfo(const QByteArray &info)
0176         : SensorTokenizer(info, '\t')
0177     {
0178     }
0179 
0180     ~SensorFloatInfo()
0181     {
0182     }
0183 
0184     QString name()
0185     {
0186         if (count() > 0)
0187             return QString::fromUtf8((*this)[0]);
0188         return QString();
0189     }
0190 
0191     double min()
0192     {
0193         if (count() > 1)
0194             return (*this)[1].toDouble();
0195         return -1;
0196     }
0197 
0198     double max()
0199     {
0200         if (count() > 2)
0201             return (*this)[2].toDouble();
0202         return -1;
0203     }
0204 
0205     QString unit()
0206     {
0207         if (count() > 3)
0208             return QString::fromUtf8((*this)[3]);
0209         return QString();
0210     }
0211 };
0212 
0213 }
0214 
0215 #endif