1 /*
2     KSysGuard, the KDE System Guard
3 
4     SPDX-FileCopyrightText: 1999, 2000 Chris Schlaeger <cs@kde.org>
5     SPDX-FileCopyrightText: 2006 John Tapsell <tapsell@kde.org>
6 
7     SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
8 
9 */
10 
11 #ifndef KSG_SENSORCLIENT_H
12 #define KSG_SENSORCLIENT_H
13 
14 #include <QByteArray>
15 #include <QList>
16 #include <QString>
17 
18 namespace KSGRD
19 {
20 /**
21   Every object that should act as a client to a sensor must inherit from
22   this class. A pointer to the client object is passed as SensorClient*
23   to the SensorAgent. When the requested information is available or a
24   problem occurred one of the member functions is called.
25  */
26 class SensorClient
27 {
28 public:
SensorClient()29     explicit SensorClient()
30     {
31     }
~SensorClient()32     virtual ~SensorClient()
33     {
34     }
35 
36     /**
37       This function is called whenever the information from the sensor has
38       been received by the sensor agent. This function must be reimplemented
39       by the sensor client to receive and process this information.
40      */
answerReceived(int id,const QList<QByteArray> & answer)41     virtual void answerReceived(int id, const QList<QByteArray> &answer)
42     {
43         Q_UNUSED(id);
44         Q_UNUSED(answer);
45     }
46 
47     /**
48       In case of an unexpected fatal problem with the sensor the sensor
49       agent will call this function to notify the client about it.
50      */
sensorLost(int id)51     virtual void sensorLost(int id)
52     {
53         Q_UNUSED(id);
54     }
55 };
56 
57 /**
58   The following classes are utility classes that provide a
59   convenient way to retrieve pieces of information from the sensor
60   answers. For each type of answer there is a separate class.
61  */
62 class SensorTokenizer
63 {
64 public:
SensorTokenizer(const QByteArray & info,char separator)65     SensorTokenizer(const QByteArray &info, char separator)
66     {
67         if (separator == '/') {
68             // This is a special case where we assume that info is a '\' escaped string
69 
70             int i = 0;
71             int lastTokenAt = -1;
72 
73             for (; i < info.length(); ++i) {
74                 if (info[i] == '\\') {
75                     ++i;
76                 } else if (info[i] == separator) {
77                     mTokens.append(unEscapeString(info.mid(lastTokenAt + 1, i - lastTokenAt - 1)));
78                     lastTokenAt = i;
79                 }
80             }
81 
82             // Add everything after the last token
83             mTokens.append(unEscapeString(info.mid(lastTokenAt + 1, i - lastTokenAt - 1)));
84         } else {
85             mTokens = info.split(separator);
86         }
87     }
88 
~SensorTokenizer()89     ~SensorTokenizer()
90     {
91     }
92 
93     const QByteArray &operator[](unsigned idx)
94     {
95         Q_ASSERT(idx < (unsigned)(mTokens.count()));
96         return mTokens[idx];
97     }
98 
count()99     uint count()
100     {
101         return mTokens.count();
102     }
103 
104 private:
105     QList<QByteArray> mTokens;
106 
unEscapeString(QByteArray string)107     QByteArray unEscapeString(QByteArray string)
108     {
109         int i = 0;
110         for (; i < string.length(); ++i) {
111             if (string[i] == '\\') {
112                 string.remove(i, 1);
113                 ++i;
114             }
115         }
116 
117         return string;
118     }
119 };
120 
121 /**
122   An integer info contains 4 fields separated by TABS, a description
123   (name), the minimum and the maximum values and the unit.
124   e.g. Swap Memory	0	133885952	KB
125  */
126 class SensorIntegerInfo : public SensorTokenizer
127 {
128 public:
SensorIntegerInfo(const QByteArray & info)129     explicit SensorIntegerInfo(const QByteArray &info)
130         : SensorTokenizer(info, '\t')
131     {
132     }
133 
~SensorIntegerInfo()134     ~SensorIntegerInfo()
135     {
136     }
137 
name()138     QString name()
139     {
140         if (count() > 0)
141             return QString::fromUtf8((*this)[0]);
142         return QString();
143     }
144 
min()145     long long min()
146     {
147         if (count() > 1)
148             return (*this)[1].toLongLong();
149         return -1;
150     }
151 
max()152     long long max()
153     {
154         if (count() > 2)
155             return (*this)[2].toLongLong();
156         return -1;
157     }
158 
unit()159     QString unit()
160     {
161         if (count() > 3)
162             return QString::fromUtf8((*this)[3]);
163         return QString();
164     }
165 };
166 
167 /**
168   An float info contains 4 fields separated by TABS, a description
169   (name), the minimum and the maximum values and the unit.
170   e.g. CPU Voltage 0.0	5.0	V
171  */
172 class SensorFloatInfo : public SensorTokenizer
173 {
174 public:
SensorFloatInfo(const QByteArray & info)175     explicit SensorFloatInfo(const QByteArray &info)
176         : SensorTokenizer(info, '\t')
177     {
178     }
179 
~SensorFloatInfo()180     ~SensorFloatInfo()
181     {
182     }
183 
name()184     QString name()
185     {
186         if (count() > 0)
187             return QString::fromUtf8((*this)[0]);
188         return QString();
189     }
190 
min()191     double min()
192     {
193         if (count() > 1)
194             return (*this)[1].toDouble();
195         return -1;
196     }
197 
max()198     double max()
199     {
200         if (count() > 2)
201             return (*this)[2].toDouble();
202         return -1;
203     }
204 
unit()205     QString unit()
206     {
207         if (count() > 3)
208             return QString::fromUtf8((*this)[3]);
209         return QString();
210     }
211 };
212 
213 }
214 
215 #endif
216