Laelaps  2.3.5
RoadNarrows Robotics Small Outdoor Mobile Robot Project
diagCpu.cxx
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // Package: Laelaps
4 //
5 // Program: laelaps_diag
6 //
7 // File: diagCpu.cxx
8 //
9 /*! \file
10  *
11  * $LastChangedDate: 2016-02-01 15:14:45 -0700 (Mon, 01 Feb 2016) $
12  * $Rev: 4289 $
13  *
14  * \brief Perform Laelaps main CPU diagnostics.
15  *
16  * \author Robin Knight (robin.knight@roadnarrows.com)
17  *
18  * \par Copyright
19  * \h_copy 2015-2017. RoadNarrows LLC.\n
20  * http://www.roadnarrows.com\n
21  * All Rights Reserved
22  */
23 /*
24  * @EulaBegin@
25  *
26  * Unless otherwise stated explicitly, all materials contained are copyrighted
27  * and may not be used without RoadNarrows LLC's written consent,
28  * except as provided in these terms and conditions or in the copyright
29  * notice (documents and software) or other proprietary notice provided with
30  * the relevant materials.
31  *
32  * IN NO EVENT SHALL THE AUTHOR, ROADNARROWS LLC, OR ANY
33  * MEMBERS/EMPLOYEES/CONTRACTORS OF ROADNARROWS OR DISTRIBUTORS OF THIS SOFTWARE
34  * BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR
35  * CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
36  * DOCUMENTATION, EVEN IF THE AUTHORS OR ANY OF THE ABOVE PARTIES HAVE BEEN
37  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38  *
39  * THE AUTHORS AND ROADNARROWS LLC SPECIFICALLY DISCLAIM ANY WARRANTIES,
40  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
41  * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN
42  * "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO
43  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
44  *
45  * @EulaEnd@
46  */
47 ////////////////////////////////////////////////////////////////////////////////
48 
49 #include <sys/utsname.h>
50 #include <unistd.h>
51 #include <termios.h>
52 #include <string.h>
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <stdarg.h>
56 
57 #include <iostream>
58 #include <fstream>
59 #include <string>
60 #include <vector>
61 #include <algorithm>
62 
63 #include "rnr/rnrconfig.h"
64 #include "rnr/log.h"
65 #include "rnr/opts.h"
66 #include "rnr/pkg.h"
67 
68 // common
69 #include "Laelaps/laelaps.h"
70 #include "Laelaps/laeUtils.h"
71 
72 // hardware
73 #include "Laelaps/laeSysDev.h"
74 
75 #include "laelaps_diag.h"
76 
77 using namespace std;
78 using namespace laelaps;
79 
80 static const char *SubSysName = "CPU";
81 static const char *ProdName = "Odroid";
82 
83 static void trim(string &str)
84 {
85  string strWork(str);
86  size_t i, j, k;
87 
88  // leading white space
89  for(i=0; i<strWork.size(); ++i)
90  {
91  if( (strWork[i] != ' ') && (strWork[i] != '\t') &&
92  (strWork[i] != '\n') && (strWork[i] != '\r') )
93  {
94  break;
95  }
96  }
97 
98  // trailing white space
99  for(j=strWork.size()-1; j>=i; --j)
100  {
101  if( (strWork[j] != ' ') && (strWork[j] != '\t') &&
102  (strWork[j] != '\n') && (strWork[j] != '\r') )
103  {
104  break;
105  }
106  }
107 
108  // copy back
109  if( j >= i )
110  {
111  str.resize(j-i+1);
112  for(k=0; k<str.size(); ++k)
113  {
114  str[k] = strWork[i++];
115  }
116  }
117  else
118  {
119  str.clear();
120  }
121 }
122 
123 static void tolower(string &str)
124 {
125  for(size_t i=0; i<str.size(); ++i)
126  {
127  str[i] = ::tolower(str[i]);
128  }
129 }
130 
131 static string normalize(string str)
132 {
133  //fprintf(stderr, "DBG: normalize: \"%s\" --> ", str.c_str());
134 
135  trim(str);
136  //fprintf(stderr, "\"%s\" --> ", str.c_str());
137 
138  tolower(str);
139  //fprintf(stderr, "\"%s\"\n", str.c_str());
140 
141  return str;
142 }
143 
144 static bool parseCpuInfo(string &strCpuHw,
145  string &strCpuRev,
146  int &numCores)
147 {
148  const size_t maxlen = 256;
149 
150  FILE *fp;
151  char line[maxlen];
152  char *tokKey, *tokVal;
153  string strKey;
154 
155  strCpuHw.clear();
156  strCpuRev.clear();
157  numCores = 0;
158 
159  if( (fp = fopen("/proc/cpuinfo", "r")) == NULL )
160  {
161  return false;
162  }
163 
164  while( fgets(line, maxlen, fp) != NULL )
165  {
166  line[maxlen-1] = 0; // paranoia
167 
168  if( (tokKey = strtok(line, ":")) == NULL )
169  {
170  continue;
171  }
172  else if( (tokVal = strtok(NULL, "\n")) == NULL )
173  {
174  continue;
175  }
176 
177  strKey = normalize(tokKey);
178 
179  if( strKey == "processor" )
180  {
181  ++numCores;
182  }
183  else if( strKey == "hardware" )
184  {
185  strCpuHw = tokVal;
186  trim(strCpuHw);
187  }
188  else if( strKey == "revision" )
189  {
190  strCpuRev = tokVal;
191  trim(strCpuRev);
192  }
193  }
194 
195  fclose(fp);
196 
197  return true;
198 }
199 
200 static bool parseLsbRelease(string &strDistribId,
201  string &strDistribRel,
202  string &strDistribCode,
203  string &strDistribDesc)
204 {
205  const size_t maxlen = 256;
206 
207  FILE *fp;
208  char line[maxlen];
209  char *tokKey, *tokVal;
210  string strKey;
211 
212  strDistribId.clear();
213  strDistribRel.clear();
214  strDistribCode.clear();
215  strDistribDesc.clear();
216 
217  if( (fp = fopen("/etc/lsb-release", "r")) == NULL )
218  {
219  return false;
220  }
221 
222  while( fgets(line, maxlen, fp) != NULL )
223  {
224  line[maxlen-1] = 0; // paranoia
225 
226  if( (tokKey = strtok(line, "=")) == NULL )
227  {
228  continue;
229  }
230  else if( (tokVal = strtok(NULL, "\n")) == NULL )
231  {
232  continue;
233  }
234 
235  strKey = normalize(tokKey);
236 
237  if( strKey == "distrib_id" )
238  {
239  strDistribId = tokVal;
240  trim(strDistribId);
241  }
242  else if( strKey == "distrib_release" )
243  {
244  strDistribRel = tokVal;
245  trim(strDistribRel);
246  }
247  else if( strKey == "distrib_codename" )
248  {
249  strDistribCode = tokVal;
250  trim(strDistribCode);
251  }
252  else if( strKey == "distrib_description" )
253  {
254  strDistribDesc = tokVal;
255  trim(strDistribDesc);
256  }
257  }
258 
259  fclose(fp);
260 
261  return true;
262 }
263 
264 static bool parseEthMacAddr(string &strEthMacAddr)
265 {
266  const size_t maxlen = 256;
267 
268  FILE *fp;
269  char line[maxlen];
270  int n;
271 
272  strEthMacAddr.clear();
273 
274  if( (fp = fopen("/sys/class/net/eth0/address", "r")) == NULL )
275  {
276  return false;
277  }
278 
279  if (fgets(line, maxlen, fp) != NULL )
280  {
281  line[maxlen-1] = 0; // paranoia
282  n = strlen(line);
283  if( n > 1 ) // zap newline
284  {
285  line[n] = 0;
286  }
287  strEthMacAddr = line;
288  trim(strEthMacAddr);
289  }
290 
291  fclose(fp);
292 
293  return true;
294 }
295 
296 static bool parseMmcCid(string &strMmcCid)
297 {
298  const size_t maxlen = 256;
299 
300  FILE *fp;
301  char line[maxlen];
302  int n;
303 
304  strMmcCid.clear();
305 
306  if( (fp = fopen("/sys/block/mmcblk0/device/cid", "r")) == NULL )
307  {
308  return false;
309  }
310 
311  if (fgets(line, maxlen, fp) != NULL )
312  {
313  line[maxlen-1] = 0; // paranoia
314  n = strlen(line);
315  if( n > 1 ) // zap newline
316  {
317  line[n] = 0;
318  }
319  strMmcCid = line;
320  trim(strMmcCid);
321  }
322 
323  fclose(fp);
324 
325  return true;
326 }
327 
328 static DiagStats readInfo()
329 {
330  string strCpuHw;
331  string strCpuRev;
332  int numCores;
333  string strDistribId;
334  string strDistribRel;
335  string strDistribCode;
336  string strDistribDesc;
337  struct utsname utsInfo;
338  string strEthMacAddr;
339  string strMmcCid;
340 
341  const char *sTag;
342  DiagStats stats;
343 
344  printSubHdr("Main Processor Info");
345 
346  ++stats.testCnt;
347  if( parseCpuInfo(strCpuHw, strCpuRev, numCores) )
348  {
349  ++stats.passCnt;
350  sTag = PassTag;
351  }
352  else
353  {
354  sTag = FailTag;
355  }
356  printTestResult(sTag, "Get CPU info.");
357 
358  ++stats.testCnt;
359  if( parseLsbRelease(strDistribId, strDistribRel,
360  strDistribCode, strDistribDesc) )
361  {
362  ++stats.passCnt;
363  sTag = PassTag;
364  }
365  else
366  {
367  sTag = FailTag;
368  }
369  printTestResult(sTag, "Get system release info.");
370 
371  ++stats.testCnt;
372  if( uname(&utsInfo) == 0 )
373  {
374  ++stats.passCnt;
375  sTag = PassTag;
376  }
377  else
378  {
379  memset(&utsInfo, 0, sizeof(struct utsname));
380  sTag = FailTag;
381  }
382  printTestResult(sTag, "Get kernel info.");
383 
384  ++stats.testCnt;
385  if( parseEthMacAddr(strEthMacAddr) )
386  {
387  ++stats.passCnt;
388  sTag = PassTag;
389  }
390  else
391  {
392  sTag = FailTag;
393  }
394  printTestResult(sTag, "Get Ethernet hardware info.");
395 
396  ++stats.testCnt;
397  if( parseMmcCid(strMmcCid) )
398  {
399  ++stats.passCnt;
400  sTag = PassTag;
401  }
402  else
403  {
404  sTag = FailTag;
405  }
406  printTestResult(sTag, "Get eMMC CID info.");
407 
408  printf("\n");
409  printf("Main Processor Summary:\n");
410  printf(" Hardware:\n");
411  printf(" Product: %s\n", ProdName);
412  printf(" SOC: %s\n", "Samsung Exynos5 Octa ARM Cortex");
413  printf(" Architecture: %s\n", utsInfo.machine);
414  printf(" Hardware Rev: %s\n", strCpuRev.c_str());
415  printf(" Number of Cores: %d\n", numCores);
416  printf(" eMMC CID: %s\n", strMmcCid.c_str());
417  printf(" Ethernet MAC: %s\n", strEthMacAddr.c_str());
418  printf(" Operating System:\n");
419  printf(" Kernel: %s\n", utsInfo.sysname);
420  printf(" Release: %s\n", utsInfo.release);
421  printf(" Version: %s\n", utsInfo.version);
422  printf(" Node: %s\n", utsInfo.nodename);
423  printf(" Distribution:\n");
424  printf(" Name: %s\n", strDistribId.c_str());
425  printf(" Release: %s\n", strDistribRel.c_str());
426  printf(" Code Name: %s\n", strDistribCode.c_str());
427  printf(" Description: %s\n", strDistribDesc.c_str());
428  printf(" System Devices:\n");
429  printf(" Motor Controllers: %s\n", LaeDevMotorCtlrs);
430  printf(" I2C Bus: %s\n", LaeDevI2C_0);
431  printf(" %s\n", LaeDevI2C_1);
432  printf(" %s\n", LaeDevI2C_2);
433  printf(" IMU: %s\n", LaeDevIMU);
434  printf(" Dynamixel Bus: %s\n", LaeDevDynabus);
435  printf(" Front Camera: %s\n", LaeDevFCam);
436  printf("\n");
437 
438  return stats;
439 }
440 
441 DiagStats runCpuDiagnostics()
442 {
443  DiagStats statsTest;
444  DiagStats statsTotal;
445 
446  printHdr("Main CPU Diagnostics");
447 
448  //
449  // Read Main Processor Info
450  //
451  statsTest = readInfo();
452 
453  printSubTotals(statsTest);
454 
455  statsTotal += statsTest;
456 
457 #if 0
458  //
459  // X Tests
460  //
461  if( !statsTotal.fatal )
462  {
463  statsTest = readInfo();
464 
465  printSubTotals(statsTest);
466 
467  statsTotal += statsTest;
468  }
469 #endif
470 
471  //
472  // Summary
473  //
474  printTotals(statsTotal);
475 
476  return statsTotal;
477 }
Diagnotics header file.
The <b><i>Laelaps</i></b> namespace encapsulates all <b><i>Laelaps</i></b> related constructs...
Definition: laeAlarms.h:64
Simple diagnostics statistics class.
Definition: laelaps_diag.h:106
Laelaps common utilities.
Laelaps system devices.
Top-level package include file.