1 #ifndef UTILITY_H
2 #define UTILITY_H
3 
4 #include <Qt>
5 #include <stdint.h>
6 #include <QByteArray>
7 #include <QDateTime>
8 #include <QDebug>
9 #include <QApplication>
10 #include <QRect>
11 #include <QDesktopWidget>
12 
13 class Utility
14 {
15 public:
16 
17     static bool decimalMode;
18     static bool secondsMode;
19     static bool sysTimeMode;
20     static QString timeFormat;
21 
22     //determines whether the window position is within any available screens. If it is not we default
23     //back to 0,0 which is going to be on screen. This fixes a problem where some operating systems would
24     //otherwise let you put windows on a second monitor, disconnect that monitor, and still put windows on it.
constrainedWindowPos(QPoint originalPos)25     static QPoint constrainedWindowPos(QPoint originalPos)
26     {
27         QScreen *screen = QGuiApplication::screenAt(originalPos);
28         if (!screen)
29         {
30             return QPoint(0,0);
31         }
32         return originalPos;
33     }
34 
unQuote(QString inStr)35     static QString unQuote(QString inStr)
36     {
37         QStringList temp;
38         temp = inStr.split('\"');
39         if (temp.length() >= 3)
40             return temp[1];
41         return inStr;
42     }
43 
ParseStringToNum(QByteArray input)44     static uint64_t ParseStringToNum(QByteArray input)
45     {
46         uint64_t temp = 0;
47 
48         input = input.toUpper();
49         if (input.startsWith("0X") || input.startsWith("X")) //hex number
50         {
51             if (input.length() < 3) temp = 0;
52             else temp = input.right(input.size() - 2).toLongLong(nullptr, 16);
53         }
54         else if (input.startsWith("0B") || input.startsWith("B")) //binary number
55         {
56             input = input.right(input.size() - 1); //remove the B
57             for (int i = 0; i < input.length(); i++)
58             {
59                 if (input[i] == '1') temp += (uint64_t)1 << (input.length() - i - 1);
60             }
61         }
62         else //decimal number
63         {
64             temp = input.toLongLong();
65         }
66 
67         return temp;
68     }
69 
ParseStringToNum(QString input)70     static uint64_t ParseStringToNum(QString input)
71     {
72         return ParseStringToNum(input.toUtf8());
73     }
74 
75     static uint ParseStringToNum2(QString pInput, bool* pOk_p = nullptr)
76     {
77         if(pInput.startsWith("0b"))
78         {
79             pInput.remove(0, 2);
80             return pInput.toUInt(pOk_p, 2);
81         }
82 
83         return pInput.toUInt(pOk_p, 0);
84     }
85 
GetTimeMS()86     static uint64_t GetTimeMS()
87     {
88         QDateTime stamp = QDateTime::currentDateTime();
89         return (((static_cast<uint64_t>(stamp.time().hour()) * 3600ull) + (static_cast<uint64_t>(stamp.time().minute()) * 60ull)
90                  + (static_cast<uint64_t>(stamp.time().second())) * 1000ull) + static_cast<uint64_t>(stamp.time().msec()));
91     }
92 
93     //prints hex numbers in uppercase with 0's filling out the number depending
94     //on the size needed. Promotes hex numbers to either 2, 4, or 8 digits
formatHexNum(uint64_t input)95     static QString formatHexNum(uint64_t input)
96     {
97         if (input < 256)
98             return "0x" + QString::number(input, 16).toUpper().rightJustified(2,'0');
99         if (input < 65536)
100             return "0x" + QString::number(input, 16).toUpper().rightJustified(4,'0');
101         if (input < 4294967296)
102             return "0x" + QString::number(input, 16).toUpper().rightJustified(8,'0');
103         return "0x" + QString::number(input, 16).toUpper().rightJustified(16,'0');
104     }
105 
106     //uses decimalMode to see if it should show value as decimal or hex
formatNumber(uint64_t value)107     static QString formatNumber(uint64_t value)
108     {
109         if (decimalMode)
110         {
111             return QString::number(value, 10);
112         }
113         else return formatHexNum(value);
114     }
115 
formatCANID(uint64_t id,bool extended)116     static QString formatCANID(uint64_t id, bool extended)
117     {
118         if (decimalMode) return QString::number(id, 10);
119 
120         if (extended)
121         {
122             return "0x" + QString::number(id, 16).toUpper().rightJustified(8,'0');
123         }
124         else
125         {
126             id = id & 0x7FF;
127             return "0x" + QString::number(id, 16).toUpper().rightJustified(3,'0');
128         }
129     }
130 
formatCANID(uint64_t id)131     static QString formatCANID(uint64_t id)
132     {
133         if (id < 0x800) return formatCANID(id, false);
134         return formatCANID(id, true);
135     }
136 
formatByteAsBinary(uint8_t value)137     static QString formatByteAsBinary(uint8_t value)
138     {
139         QString output;
140         for (int b = 7; b >= 0; b--)
141         {
142             if (value & (1 << b)) output += "1";
143             else output += "0";
144         }
145         return output;
146     }
147 
formatTimestamp(uint64_t timestamp)148     static QVariant formatTimestamp(uint64_t timestamp)
149     {
150         if (!sysTimeMode) {
151             if (!secondsMode) return (unsigned long long)(timestamp);
152             else return (double)timestamp / 1000000.0;
153         }
154         else return QDateTime::fromMSecsSinceEpoch(timestamp / 1000);
155     }
156 
157     //parses the input string to grab as much of it as possible while staying alpha numeric
grabAlphaNumeric(QString & input)158     static QString grabAlphaNumeric(QString &input)
159     {
160         QString builder;
161         QChar thisChar;
162         for (int i = 0; i < input.length(); i++)
163         {
164             thisChar = input[i];
165             if (thisChar.isLetterOrNumber() || thisChar == ':' || thisChar == '~') builder.append(input[i]);
166             else
167             {
168                 //qDebug() << "i: "<< i << " len: " << input.length();
169                 if (i < (input.length() - 1)) input = input.right(input.length() - i);
170                 else input = "";
171                 return builder;
172             }
173         }
174         //qDebug() << "Reached end of string in grabAlphaNumeric";
175         input = "";
176         return builder;
177     }
178 
grabOperation(QString & input)179     static QString grabOperation(QString &input)
180     {
181         QString builder;
182         QChar thisChar = input[0];
183 
184         if (thisChar == '+' || thisChar == '-' || thisChar == '*' || thisChar == '/' || thisChar == '^' || thisChar == '&' || thisChar == '|' || thisChar == '=' || thisChar == '%')
185         {
186             input = input.right(input.length() - 1);
187             builder = thisChar;
188         }
189         return builder;
190     }
191 
192     //simple linear interpolation between value1 and value2. sample point is 0.0 to 1.0
Lerp(double value1,double value2,double samplePoint)193     static double Lerp(double value1, double value2, double samplePoint)
194     {
195         return (value1 * (1.0 - samplePoint)) + (value2 * samplePoint);
196     }
197 
processIntegerSignal(const QByteArray data,int startBit,int sigSize,bool littleEndian,bool isSigned)198     static int64_t processIntegerSignal(const QByteArray data, int startBit, int sigSize, bool littleEndian, bool isSigned)
199     {
200 
201         int64_t result = 0;
202         int bit;
203 
204         int maxBytes = (startBit + sigSize) / 8;
205         if (data.size() < maxBytes) return 0;
206 
207         if (littleEndian)
208         {
209             bit = startBit;
210             for (int bitpos = 0; bitpos < sigSize; bitpos++)
211             {
212                 if (bit < 64) {
213                     int bytePos = bit / 8;
214                     if (bytePos >= data.count()) return 0; //error!
215                     if (data[bit / 8] & (1 << (bit % 8)))
216                         result += (1ULL << bitpos);
217                 }
218                 bit++;
219             }
220         }
221         else //motorola / big endian mode
222         {
223             bit = startBit;
224             for (int bitpos = 0; bitpos < sigSize; bitpos++)
225             {
226                 if (bit < 64) {
227                     int bytePos = bit / 8;
228                     if (bytePos >= data.count()) return 0; //error!
229                     if (data[bit / 8] & (1 << (bit % 8)))
230                         result += (1ULL << (sigSize - bitpos - 1));
231                 }
232 
233                 if ((bit % 8) == 0)
234                     bit += 15;
235                 else bit--;
236 
237             }
238         }
239 
240         if (isSigned)
241         {
242             int64_t mask = (1ULL << (sigSize - 1));
243             if ((result & mask) == mask) //is the highest bit possible for this signal size set?
244             {
245                 /*
246                  * if so we need to also set every bit higher in the result int too.
247                  * This leads to the below two lines that are nasty. Here's the theory behind that...
248                  * If the value is signed and the highest bit is set then it is negative. To create
249                  * a negative value out of this even though the variable result is 64 bit we have to
250                  * run 1's all of the way up to bit 63 in result. -1 is all ones for whatever size integer
251                  * you have. So, it's 64 1's in this case.
252                  * signedMask is done this way:
253                  * first you take the signal size and shift 1 up that far. Then subtract one. Lets
254                  * see that for a 16 bit signal:
255                  * (1 << 16) - 1 = the first 16 bits set as 1's. So far so good. We then negate the whole
256                  * thing which flips all bits. Thus signedMask ends up with 1's everwhere that the signal
257                  * doesn't take up in the 64 bit signed integer result. Then, result has an OR operation on
258                  * it with the old value and -1 masked so that the the 1 bits from -1 don't overwrite bits from the
259                  * actual signal. This extends the sign bits out so that the integer result reads as the proper negative
260                  * value. We dont need to do any of this if the sign bit wasn't set.
261                 */
262                 uint64_t signedMask = ~((1ULL << sigSize) - 1);
263                 result = (-1LL & signedMask) | result;
264             }
265         }
266 
267         return result;
268     }
269 };
270 
271 #endif // UTILITY_H
272