File indexing completed on 2024-05-05 05:34:26

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         }
0143         return QString();
0144     }
0145 
0146     long long min()
0147     {
0148         if (count() > 1) {
0149             return (*this)[1].toLongLong();
0150         }
0151         return -1;
0152     }
0153 
0154     long long max()
0155     {
0156         if (count() > 2) {
0157             return (*this)[2].toLongLong();
0158         }
0159         return -1;
0160     }
0161 
0162     QString unit()
0163     {
0164         if (count() > 3) {
0165             return QString::fromUtf8((*this)[3]);
0166         }
0167         return QString();
0168     }
0169 };
0170 
0171 /**
0172   An float info contains 4 fields separated by TABS, a description
0173   (name), the minimum and the maximum values and the unit.
0174   e.g. CPU Voltage 0.0  5.0 V
0175  */
0176 class SensorFloatInfo : public SensorTokenizer
0177 {
0178 public:
0179     explicit SensorFloatInfo(const QByteArray &info)
0180         : SensorTokenizer(info, '\t')
0181     {
0182     }
0183 
0184     ~SensorFloatInfo()
0185     {
0186     }
0187 
0188     QString name()
0189     {
0190         if (count() > 0) {
0191             return QString::fromUtf8((*this)[0]);
0192         }
0193         return QString();
0194     }
0195 
0196     double min()
0197     {
0198         if (count() > 1) {
0199             return (*this)[1].toDouble();
0200         }
0201         return -1;
0202     }
0203 
0204     double max()
0205     {
0206         if (count() > 2) {
0207             return (*this)[2].toDouble();
0208         }
0209         return -1;
0210     }
0211 
0212     QString unit()
0213     {
0214         if (count() > 3) {
0215             return QString::fromUtf8((*this)[3]);
0216         }
0217         return QString();
0218     }
0219 };
0220 
0221 }
0222 
0223 #endif