Laelaps  2.3.5
RoadNarrows Robotics Small Outdoor Mobile Robot Project
laeVL6180.cxx
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // Package: Laelaps
4 //
5 // Library: liblaelaps
6 //
7 // File: laeVL6180.cxx
8 //
9 /*! \file
10  *
11  * \brief Laelaps Time-of-Flight sensors. The ToFs are used as a virtual bumper
12  * for close-in obstacle detection.
13  *
14  * The hardware changed between Laelaps v2.0 and subsequence v2.1+ versions.
15  * See laeVL6180.h for details.
16  *
17  * This code is based on the Arduino library freely available from Sparkfun.
18  * See original comment block below.
19  *
20  * \sa https://github.com/sparkfun/ToF_Range_Finder_Sensor-VL6180/tree/master/Libraries/Arduino
21  * \sa https://www.sparkfun.com/products/12785
22  *
23  * \author Robin Knight (robin.knight@roadnarrows.com)
24  *
25  * \par Copyright
26  * \h_copy 2015-2017. RoadNarrows LLC.\n
27  * http://www.roadnarrows.com\n
28  * All Rights Reserved
29  */
30 ////////////////////////////////////////////////////////////////////////////////
31 
32 /******************************************************************************
33  * SparkFun_VL6180x.cpp
34  * Library for VL6180x time of flight range finder.
35  * Casey Kuhns @ SparkFun Electronics
36  * 10/29/2014
37  * https://github.com/sparkfun/SparkFun_ToF_Range_Finder-VL6180_Arduino_Library
38  *
39  * The VL6180x by ST micro is a time of flight range finder that
40  * uses pulsed IR light to determine distances from object at close
41  * range. The average range of a sensor is between 0-200mm
42  *
43  * In this file are the functions in the VL6180x class
44  *
45  * Resources:
46  * This library uses the Arduino Wire.h to complete I2C transactions.
47  *
48  * Development environment specifics:
49  * IDE: Arduino 1.0.5
50  * Hardware Platform: Arduino Pro 3.3V/8MHz
51  * VL6180x Breakout Version: 1.0
52  * **Updated for Arduino 1.6.4 5/2015**
53  *
54  * This code is beerware. If you see me (or any other SparkFun employee) at the
55  * local pub, and you've found our code helpful, please buy us a round!
56  *
57  * Distributed as-is; no warranty is given.
58  ******************************************************************************/
59 
60 #include <inttypes.h>
61 #include <unistd.h>
62 #include <math.h>
63 
64 #include <string>
65 #include <vector>
66 #include <map>
67 
68 #include "rnr/rnrconfig.h"
69 #include "rnr/log.h"
70 #include "rnr/i2c.h"
71 
72 #include "Laelaps/laelaps.h"
73 #include "Laelaps/laeDesc.h"
74 #include "Laelaps/laeTune.h"
75 #include "Laelaps/laeUtils.h"
76 #include "Laelaps/laeDb.h"
77 
78 #include "Laelaps/laeI2CMux.h" // v2.0
79 #include "Laelaps/laeToFMux.h" // v2.1+
80 
81 #include "Laelaps/laeVL6180.h"
82 
83 using namespace std;
84 using namespace laelaps;
85 using namespace sensor::vl6180;
86 
87 
88 //------------------------------------------------------------------------------
89 // Private Data
90 //------------------------------------------------------------------------------
91 
92 /*!
93  * \brief Ambient Light Sensor gain table.
94  */
95 static double AlsGainAnalogTbl[GAIN_NumOf] =
96 {
97  20.0, // [GAIN_20]
98  10.32, // [GAIN_10]
99  5.21, // [GAIN_5]
100  2.60, // [GAIN_2_5]
101  1.72, // [GAIN_1_67]
102  1.28, // [GAIN_1_25]
103  1.01, // [GAIN_1]
104  40.0 // [GAIN_40]
105 };
106 
107 //------------------------------------------------------------------------------
108 // LaeRangeSensorInfo Class
109 //------------------------------------------------------------------------------
110 
111 LaeVL6180SensorInfo::LaeVL6180SensorInfo()
112 {
113  m_nIndex = -1;
114  m_nChan = -1;
115  m_fBeamDir = 0.0;
116  m_fDeadzone = 0.0;
117 }
118 
119 LaeVL6180SensorInfo::LaeVL6180SensorInfo(int nIndex,
120  int nChan,
121  double fBeamDir,
122  double fDeadzone,
123  const std::string &strDesc)
124 {
125  m_nIndex = nIndex;
126  m_nChan = nChan;
127  m_fBeamDir = fBeamDir;
128  m_fDeadzone = fDeadzone;
129  m_strDesc = strDesc;
130 }
131 
132 LaeVL6180SensorInfo::LaeVL6180SensorInfo(const LaeVL6180SensorInfo &src)
133 {
134  m_nIndex = src.m_nIndex;
135  m_nChan = src.m_nChan;
136  m_fBeamDir = src.m_fBeamDir;
137  m_fDeadzone = src.m_fDeadzone;
138  m_strDesc = src.m_strDesc;
139 }
140 
141 LaeVL6180SensorInfo::~LaeVL6180SensorInfo()
142 {
143 }
144 
145 LaeVL6180SensorInfo LaeVL6180SensorInfo::operator=(
146  const LaeVL6180SensorInfo &rhs)
147 {
148  m_nIndex = rhs.m_nIndex;
149  m_nChan = rhs.m_nChan;
150  m_fBeamDir = rhs.m_fBeamDir;
151  m_fDeadzone = rhs.m_fDeadzone;
152  m_strDesc = rhs.m_strDesc;
153 
154  return *this;
155 }
156 
157 void LaeVL6180SensorInfo::getProps(int &nIndex,
158  int &nChan,
159  std::string &strRadiationType,
160  double &fFoV,
161  double &fBeamDir,
162  double &fDeadzone,
163  double &fMin,
164  double &fMax,
165  std::string &strDesc)
166 {
167  nIndex = m_nIndex;
168  nChan = m_nChan;
169  strRadiationType = "infrared";
170  fFoV = degToRad(VL6180X_RANGE_FOV);
171  fBeamDir = m_fBeamDir;
172  fDeadzone = m_fDeadzone;
173  fMin = VL6180X_RANGE_MIN;
174  fMax = VL6180X_RANGE_MAX;
175  strDesc = m_strDesc;
176 }
177 
178 
179 //------------------------------------------------------------------------------
180 // LaeVL6180Mux Class
181 //------------------------------------------------------------------------------
182 
183 LaeVL6180Mux::LaeVL6180Mux(LaeI2CMux &mux,
184  int nChan,
185  double fBeamDir,
186  double fDeadzone,
187  const string &strNameId,
188  const string &strDesc) :
189  m_mux(mux), m_nChan(nChan), m_fBeamDir(fBeamDir), m_fDeadzone(fDeadzone),
190  m_strNameId(strNameId), m_strDesc(strDesc)
191 {
192  m_nErrorCnt = 0;
193  m_bBlackListed = false;
194 
195  m_fAlsGain = 1.0; // gain with the highest dynamic range
196  m_uAlsIntPeriod = 50; // datasheet recommends the forever 100 msec
197 
198  m_regRangeOffset = (byte_t)0;
199  m_regRangeCrossTalk = (u16_t)0;
200  m_regAlsGain = (byte_t)gainAnalogToEnum(m_fAlsGain);
201  m_regAlsIntPeriod = (u16_t)(m_uAlsIntPeriod - 1);
202 
203  m_fRange = 0.0;
204  m_fAmbientLight = 0.0;
205 
206  pthread_mutex_init(&m_mutex, NULL);
207 }
208 
209 LaeVL6180Mux::LaeVL6180Mux(const LaeVL6180Mux &src) :
210  m_mux(src.m_mux), m_nChan(src.m_nChan),
211  m_fBeamDir(src.m_fBeamDir), m_fDeadzone(src.m_fDeadzone),
212  m_strNameId(src.m_strNameId)
213 {
214  m_nErrorCnt = src.m_nErrorCnt;
216  m_fAlsGain = src.m_fAlsGain;
222  m_fRange = src.m_fRange;
224 
225  pthread_mutex_destroy(&m_mutex);
226 }
227 
229 {
230 }
231 
232 int LaeVL6180Mux::initSensor(bool bForce)
233 {
234  byte_t reset;
235  bool bReinit = true;
236  int rc = LAE_OK;
237 
238  m_nErrorCnt = 0;
239  m_bBlackListed = false;
240 
241  if( !bForce )
242  {
243  rc = readReg8(VL6180X_SYSTEM_FRESH_OUT_OF_RESET, reset);
244 
245  if( (rc == LAE_OK) && (reset == 0) )
246  {
247  LOGDIAG3("VL6180 sensor %s(%d): "
248  "Not fresh out of reset: No initialization required.",
249  m_strNameId.c_str(), m_nChan);
250  bReinit = false;
251  }
252  }
253 
254  if( bReinit )
255  {
256  if( (rc = outOfResetInit()) == LAE_OK )
257  {
258  rc = writeDefaults();
259  }
260  }
261 
262  readShadowRegs();
263 
264  if( rc == LAE_OK )
265  {
266  LOGDIAG3("VL6180 sensor %s(%d): Initialized.",
267  m_strNameId.c_str(), m_nChan);
268  }
269 
270  else
271  {
272  m_bBlackListed = true;
273  LOGERROR("VL6180 sensor %s(%d): Black listed: Failed to initialize.",
274  m_strNameId.c_str(), m_nChan);
275  }
276 
277  return rc;
278 }
279 
281 {
282  int rc;
283 
284  //
285  // Required by datasheet.
286  // http://www.st.com/st-web-ui/static/active/en/resource/technical/document/application_note/DM00122600.pdf
287  //
288  writeReg8(0x0207, 0x01);
289  writeReg8(0x0208, 0x01);
290  writeReg8(0x0096, 0x00);
291  writeReg8(0x0097, 0xfd);
292  writeReg8(0x00e3, 0x00);
293  writeReg8(0x00e4, 0x04);
294  writeReg8(0x00e5, 0x02);
295  writeReg8(0x00e6, 0x01);
296  writeReg8(0x00e7, 0x03);
297  writeReg8(0x00f5, 0x02);
298  writeReg8(0x00d9, 0x05);
299  writeReg8(0x00db, 0xce);
300  writeReg8(0x00dc, 0x03);
301  writeReg8(0x00dd, 0xf8);
302  writeReg8(0x009f, 0x00);
303  writeReg8(0x00a3, 0x3c);
304  writeReg8(0x00b7, 0x00);
305  writeReg8(0x00bb, 0x3c);
306  writeReg8(0x00b2, 0x09);
307  writeReg8(0x00ca, 0x09);
308  writeReg8(0x0198, 0x01);
309  writeReg8(0x01b0, 0x17);
310  writeReg8(0x01ad, 0x00);
311  writeReg8(0x00ff, 0x05);
312  writeReg8(0x0100, 0x05);
313  writeReg8(0x0199, 0x05);
314  writeReg8(0x01a6, 0x1b);
315  writeReg8(0x01ac, 0x3e);
316  writeReg8(0x01a7, 0x1f);
317  writeReg8(0x0030, 0x00);
318 
319  //
320  // Clear fresh reset bit. Default is 1 after boot/reset. Setting to 0 can
321  // be used to detect reset condition.
322  //
323  rc = writeReg8(VL6180X_SYSTEM_FRESH_OUT_OF_RESET, 0);
324 
325  return rc;
326 }
327 
329 {
330  // Recommended settings from datasheet
331  // http://www.st.com/st-web-ui/static/active/en/resource/technical/document/application_note/DM00122600.pdf
332 
333  // Disable interrupts.
334  //writeReg8(VL6180X_SYSTEM_INTERRUPT_CONFIG_GPIO, 0);
335  // Set GPIO1 high when sample complete
336  writeReg8(VL6180X_SYSTEM_INTERRUPT_CONFIG_GPIO, (4 << 3)|(4));
337 
338  // Set GPIO1 high when sample complete. N/A since interrupts are disabled.
339  writeReg8(VL6180X_SYSTEM_MODE_GPIO1, 0x10);
340 
341  // Set the readout averaging sample period.
342  // RDK: Possible TUNE parameter.
343  writeReg8(VL6180X_READOUT_AVERAGING_SAMPLE_PERIOD, 48);
344 
345  // Set the ALS analog gain.
346  writeReg8(VL6180X_SYSALS_ANALOGUE_GAIN, (byte_t)(0x40 | m_regAlsGain));
347 
348  // Set auto calibration period (Max = 255)/(OFF = 0).
349  writeReg8(VL6180X_SYSRANGE_VHV_REPEAT_RATE, 0xFF);
350 
351  // Perform a single temperature calibration
352  writeReg8(VL6180X_SYSRANGE_VHV_RECALIBRATE, 0x01);
353 
354  // Set ALS integration time in msec.
355  writeReg16(VL6180X_SYSALS_INTEGRATION_PERIOD, m_regAlsIntPeriod);
356 
357  // Optional settings from datasheet
358  // http://www.st.com/st-web-ui/static/active/en/resource/technical/document/application_note/DM00122600.pdf
359 
360  // Set default ranging inter-measurement period to 100ms.
361  // RDK: Used in interleaved mode which may be the optimal mode.
362  writeReg8(VL6180X_SYSRANGE_INTERMEASUREMENT_PERIOD, 0x09);
363 
364  // Set default ALS inter-measurement period to 100ms.
365  // RDK: Used in interleaved mode which may be the optimal mode.
366  writeReg8(VL6180X_SYSALS_INTERMEASUREMENT_PERIOD, 0x0A);
367 
368  // Additional settings defaults from community
369  // RDK Investigate
370  writeReg8(VL6180X_SYSRANGE_MAX_CONVERGENCE_TIME, 0x32);
371  writeReg8(VL6180X_SYSRANGE_RANGE_CHECK_ENABLES, 0x10 | 0x01);
372  writeReg16(VL6180X_SYSRANGE_EARLY_CONVERGENCE_ESTIMATE, 0x7B );
373 
374  writeReg8(VL6180X_SYSRANGE_RANGE_IGNORE_VALID_HEIGHT, 255);
375 
376  writeReg8(VL6180X_FIRMWARE_RESULT_SCALER, 0x01);
377 }
378 
379 int LaeVL6180Mux::tune(uint_t uRangeOffset, uint_t uRangeCrossTalk,
380  double fAlsGain, uint_t uAlsIntPeriod)
381 {
382  byte_t regRangeOffset;
383  u16_t regRangeCrossTalk;
384  byte_t regAlsGain;
385  u16_t regAlsIntPeriod;
386  int rc;
387 
388  //
389  // Convert to new register values.
390  //
391  if( (int)uRangeOffset == VL6180X_FACTORY_DFT)
392  {
393  regRangeOffset = m_regRangeOffset;
394  }
395  else
396  {
397  regRangeOffset = (byte_t)cap((int)uRangeOffset,
400  }
401 
402  if( (int)uRangeCrossTalk == VL6180X_FACTORY_DFT)
403  {
404  regRangeCrossTalk = m_regRangeCrossTalk;
405  }
406  else
407  {
408  regRangeCrossTalk = (u16_t)cap(uRangeCrossTalk,
409  (uint_t)VL6180X_RANGE_XTALK_MIN,
410  (uint_t)VL6180X_RANGE_XTALK_MAX);
411  }
412 
413  // map analog to register enum, then find exact analog gain value
414  regAlsGain = (byte_t)gainAnalogToEnum(fAlsGain);
415  fAlsGain = gainEnumToAnalog((vl6180x_als_gain)regAlsGain);
416 
417  uAlsIntPeriod = cap(uAlsIntPeriod, (uint_t)VL6180X_AMBIENT_INT_T_MIN,
418  (uint_t)VL6180X_AMBIENT_INT_T_MAX);
419 
420  regAlsIntPeriod = (u16_t)(uAlsIntPeriod - 1);
421 
422  //
423  // New offset value.
424  //
425  if( regRangeOffset != m_regRangeOffset )
426  {
427  rc = writeReg8(VL6180X_SYSRANGE_PART_TO_PART_RANGE_OFFSET, regRangeOffset);
428  if( rc == LAE_OK )
429  {
430  m_regRangeOffset = regRangeOffset;
431  }
432  else
433  {
434  LOGDIAG3("Failed to write new range part-to-part "
435  "offset register value %u.", regRangeOffset);
436  }
437  }
438 
439  //
440  // New cross-talk value.
441  //
442  if( regRangeCrossTalk != m_regRangeCrossTalk )
443  {
444  rc = writeReg16(VL6180X_SYSRANGE_CROSSTALK_COMPENSATION_RATE,
445  regRangeCrossTalk);
446  if( rc == LAE_OK )
447  {
448  m_regRangeOffset = regRangeOffset;
449  }
450  else
451  {
452  LOGDIAG3("Failed to write new range cross-talk compensation "
453  "register value %u.", regRangeCrossTalk);
454  }
455  }
456 
457  //
458  // New gain value.
459  //
460  if( regAlsGain != m_regAlsGain )
461  {
462  rc = writeReg8(VL6180X_SYSALS_ANALOGUE_GAIN, (byte_t)(0x40|regAlsGain));
463  if( rc == LAE_OK )
464  {
465  m_fAlsGain = fAlsGain;
466  m_regAlsGain = regAlsGain;
467  }
468  else
469  {
470  LOGDIAG3("Failed to write new ALS gain register value %u.", regAlsGain);
471  }
472  }
473 
474  //
475  // New integration period value.
476  //
477  if( regAlsIntPeriod != m_regAlsIntPeriod )
478  {
479  rc = writeReg16(VL6180X_SYSALS_INTEGRATION_PERIOD, regAlsIntPeriod);
480  if( rc == LAE_OK )
481  {
482  m_uAlsIntPeriod = uAlsIntPeriod;
483  m_regAlsIntPeriod = regAlsIntPeriod;
484  }
485  else
486  {
487  LOGDIAG3("Failed to write new ALS integration period register value %u.",
488  regAlsIntPeriod);
489  }
490  }
491 
492  // always return success for now
493  return LAE_OK;
494 }
495 
497 {
498  lock();
499 
500  readReg8(VL6180X_SYSRANGE_PART_TO_PART_RANGE_OFFSET, m_regRangeOffset);
501  readReg16(VL6180X_SYSRANGE_CROSSTALK_COMPENSATION_RATE, m_regRangeCrossTalk);
502  readReg8(VL6180X_SYSALS_ANALOGUE_GAIN, m_regAlsGain);
503  readReg16(VL6180X_SYSALS_INTEGRATION_PERIOD, m_regAlsIntPeriod);
504 
505  //
506  // Massage
507  //
512 
513  unlock();
514 }
515 
516 void LaeVL6180Mux::readShadowRegs(byte_t &regRangeOffset,
517  u16_t &regRangeCrossTalk,
518  byte_t &regAlsGain,
519  u16_t &regAlsIntPeriod)
520 {
521  readShadowRegs();
522 
523  regRangeOffset = m_regRangeOffset;
524  regRangeCrossTalk = m_regRangeCrossTalk;
525  regAlsGain = m_regAlsGain;
526  regAlsIntPeriod = m_regAlsIntPeriod;
527 }
528 
530 {
531  lock();
532 
533  readReg8(VL6180X_IDENTIFICATION_MODEL_ID, id.idModel);
534  readReg8(VL6180X_IDENTIFICATION_MODEL_REV_MAJOR, id.idModelRevMajor);
535  readReg8(VL6180X_IDENTIFICATION_MODEL_REV_MINOR, id.idModelRevMinor);
536  readReg8(VL6180X_IDENTIFICATION_MODULE_REV_MAJOR, id.idModuleRevMajor);
537  readReg8(VL6180X_IDENTIFICATION_MODULE_REV_MINOR, id.idModuleRevMinor);
538 
539  readReg16(VL6180X_IDENTIFICATION_DATE, id.idDate);
540  readReg16(VL6180X_IDENTIFICATION_TIME, id.idTime);
541 
542  unlock();
543 
544  return LAE_OK;
545 }
546 
547 double LaeVL6180Mux::measureRange(u32_t msecWait)
548 {
549  static byte_t startMeas = 0x01; // start measurement
550  static byte_t measDone = 0x04; // measurement done bit
551  static byte_t statusErrMask = 0xf0; // status error bit mask
552  static byte_t statusErrOverflowRaw = 0xd0; // raw range overflow
553  static byte_t statusErrOverflow = 0xf0; // range overflow
554  static byte_t clearInterrupts = 0x07; // clear all interrupts
555 
556  double fRange; // working measured range
557  byte_t valRange; // raw range value
558  byte_t valStatus; // range sensor status
559  u32_t msec; // milliseconds
560  int rc = LAE_OK; // return code
561 
562  if( m_bBlackListed )
563  {
564  return VL6180X_ERR_MEAS;
565  }
566 
567  lock();
568 
569  // auto-determine max wait time
570  if( msecWait == VL6180X_T_AUTO )
571  {
572  msecWait = 15;
573  }
574 
575  //
576  // Wait for device and sensor to be ready.
577  //
578  msec = waitForSensorReady(VL6180X_RESULT_RANGE_STATUS, msecWait);
579 
580  if( msec > msecWait )
581  {
582  LOGDIAG3("VL6180 sensor %s(%d): Range sensor busy.",
583  m_strNameId.c_str(), m_nChan);
584  rc = -LAE_ECODE_TIMEDOUT;
585  }
586 
587  //
588  // Start single shot measurement.
589  //
590  if( rc == LAE_OK )
591  {
592  rc = writeReg8(VL6180X_SYSRANGE_START, startMeas);
593  }
594 
595  //
596  // Wait for range sensor measurement to complete.
597  //
598  if( rc == LAE_OK )
599  {
600  msec += waitForSensorMeasurement(msecWait-msec, measDone);
601 
602  //
603  // Note:
604  // Typically, this timeout indicates that there a no objects in range.
605  // If it is logged, the too many errors will be printed.
606  //
607  if( msec > msecWait )
608  {
609  LOGDIAG3("VL6180 sensor %s(%d): Range measurement timed out.",
610  m_strNameId.c_str(), m_nChan);
611  rc = -LAE_ECODE_TIMEDOUT;
612  }
613  }
614 
615  writeReg8(VL6180X_SYSTEM_INTERRUPT_CLEAR, clearInterrupts);
616 
617  //
618  // Read range value (mm) and status.
619  //
620  if( rc == LAE_OK )
621  {
622  if( (rc = readReg8(VL6180X_RESULT_RANGE_VAL, valRange)) == LAE_OK )
623  {
624  //rc = readReg8(VL6180X_RESULT_RANGE_STATUS, valStatus);
625  //fprintf(stderr, "DBG: range_status=0x%02x\n", val);
626  }
627  }
628 
629  //
630  // Validate measurement and convert to SI units.
631  //
632  if( rc == LAE_OK )
633  {
634  // relevant bits
635  //valStatus &= statusErrMask;
636 
637  // Sensor overflow error. Usually indicates no detected object.
638  //if( (valStatus == statusErrOverflowRaw) ||
639  // (valStatus == statusErrOverflow) )
640  //{
641  // fRange = VL6180X_RANGE_NO_OBJ;
642  //}
643 
644  // other bits indicate sensor error
645  //else if( valStatus )
646  //{
647  // rc = -LAE_ECODE_BAD_VAL;
648  //}
649 
650  // good
651  //else
652  //{
653  // meters
654  fRange = (double)valRange / 1000.0;
655 
656  // range sensor not trusted after maximum distance
657  if( fRange > VL6180X_RANGE_MAX )
658  {
659  fRange = VL6180X_RANGE_NO_OBJ;
660  }
661  //}
662  }
663 
664  //
665  // Save
666  //
667  if( rc == LAE_OK )
668  {
669  m_fRange = fRange;
670  m_nErrorCnt = 0;
671  RtDb.m_range[m_nChan].m_fRange = m_fRange;
672  }
673  else if( rc == -LAE_ECODE_TIMEDOUT )
674  {
675  fRange = VL6180X_RANGE_NO_OBJ;
676  m_fRange = fRange;
677  ++m_nErrorCnt;
678  RtDb.m_range[m_nChan].m_fRange = m_fRange;
679  }
680  else
681  {
682  fRange = VL6180X_ERR_MEAS;
683  ++m_nErrorCnt;
684  }
685 
687  {
688  m_bBlackListed = true;
689  }
690 
691  unlock();
692 
693  return fRange;
694 }
695 
696 double LaeVL6180Mux::measureAmbientLight(u32_t msecWait)
697 {
698  static byte_t startMeas = 0x01; // start measurement
699  static byte_t measDone = 0x20; // measurement done bit
700  static byte_t statusErrMask = 0xf0; // status error bit mask
701  static double alsRes = 0.32; // .32 lux/count (default without window)
702 
703  double alsLux; // working lux value
704  u16_t valAlsRaw; // raw als value
705  byte_t valStatus; // als sensor status
706  u32_t msec; // milliseconds
707  int rc = LAE_OK; // return code
708 
709  if( m_bBlackListed )
710  {
711  return VL6180X_ERR_MEAS;
712  }
713 
714  lock();
715 
716  // auto-determine max wait time
717  if( msecWait == VL6180X_T_AUTO )
718  {
719  msecWait = (u32_t)((double)m_uAlsIntPeriod * 1.2);
720  }
721 
722  //
723  // Wait for sensor to be ready.
724  //
725  msec = waitForSensorReady(VL6180X_RESULT_ALS_STATUS, msecWait);
726 
727  if( msec > msecWait )
728  {
729  LOGDIAG3("VL6180 sensor %s(%d): Ambient light sensor busy.",
730  m_strNameId.c_str(), m_nChan);
731  rc = -LAE_ECODE_TIMEDOUT;
732  }
733 
734  //
735  // Start single shot measurement.
736  //
737  if( rc == LAE_OK )
738  {
739  rc = writeReg8(VL6180X_SYSALS_START, startMeas);
740  }
741 
742  //
743  // Wait for ambient sensor measurement to complete.
744  //
745  if( rc == LAE_OK )
746  {
747  msec += waitForSensorMeasurement(msecWait-msec, measDone);
748 
749  if( msec > msecWait )
750  {
751  LOGDIAG3("VL6180 sensor %s(%d): Ambient light measurement timed out.",
752  m_strNameId.c_str(), m_nChan);
753  rc = -LAE_ECODE_TIMEDOUT;
754  }
755  }
756 
757  //
758  // Read ALS raw value and status.
759  //
760  if( rc == LAE_OK )
761  {
762  if( (rc = readReg16(VL6180X_RESULT_ALS_VAL, valAlsRaw)) == LAE_OK )
763  {
764  rc = readReg8(VL6180X_RESULT_ALS_STATUS, valStatus);
765  }
766  }
767 
768  //
769  // Validate measurement and convert to SI units.
770  //
771  if( rc == LAE_OK )
772  {
773  // relevant bits
774  valStatus &= statusErrMask;
775 
776  // bits indicate sensor error
777  if( valStatus )
778  {
779  rc = -LAE_ECODE_BAD_VAL;
780  }
781 
782  // good
783  else
784  {
785  // calculate LUX from formula in AppNotes
786  alsLux = alsRes * ((double)valAlsRaw / m_fAlsGain) *
787  100.0 / (double)(m_uAlsIntPeriod);
788  }
789  }
790 
791  //
792  // Save
793  //
794  if( rc == LAE_OK )
795  {
796  m_fAmbientLight = alsLux;
797  m_nErrorCnt = 0;
798  RtDb.m_range[m_nChan].m_fAmbientLight = m_fAmbientLight;
799  }
800  else
801  {
802  alsLux = VL6180X_ERR_MEAS;
803  ++m_nErrorCnt;
804  }
805 
807  {
808  m_bBlackListed = true;
809  }
810 
811  unlock();
812 
813  return alsLux;
814 }
815 
816 u32_t LaeVL6180Mux::waitForSensorReady(u16_t regStatus, u32_t msecWait)
817 {
818  static byte_t statusReady = 0x01; // device and sensor is ready bit
819 
820  byte_t val;
821  u32_t msec;
822 
823  //
824  // Wait for sensor device to become available.
825  //
826  for(msec = 0; msec <= msecWait; ++msec)
827  {
828  // sensor not busy
829  if( (readReg8(regStatus, val) == LAE_OK) && (val & statusReady) )
830  {
831  return msec;
832  }
833 
834  // sleep 1 msec == 1000 usec
835  else
836  {
837  usleep(1000);
838  }
839  }
840 
841  return msec;
842 }
843 
844 u32_t LaeVL6180Mux::waitForSensorMeasurement(u32_t msecWait, byte_t bitDone)
845 {
846  static byte_t clearInterrupts = 0x07; // clear all interrupts
847 
848  byte_t val;
849  u32_t msec;
850 
851  //
852  // Wait for sensor device to become available.
853  //
854  for(msec = 0; msec <= msecWait; ++msec)
855  {
856  if( readReg8(VL6180X_RESULT_INTERRUPT_STATUS_GPIO, val) == LAE_OK )
857  {
858  // sensor not busy
859  if( val & bitDone )
860  {
861  // writeReg8(VL6180X_SYSTEM_INTERRUPT_CLEAR, clearInterrupts);
862  return msec;
863  }
864 
865  // sleep 1 msec == 1000 usec
866  else
867  {
868  usleep(1000);
869  }
870  }
871  }
872 
873  //fprintf(stderr, "DBG: status_gpio=0x%02x\n", val);
874 
875  return msec;
876 }
877 
878 int LaeVL6180Mux::calibOffset(int &nOffsetPre,
879  double &fAvgPre,
880  int &nOffsetPost,
881  double &fAvgPost)
882 {
883  u16_t regOffset = VL6180X_SYSRANGE_PART_TO_PART_RANGE_OFFSET;
884  double fWhiteTgt = 0.050; // required white target distance
885  double fRes = 0.003; // range plus/minus resolution is best possible
886  int minGood = 10; // minimum number of measurement to be valid
887  int maxIters = 20; // should >= min as per data sheet
888 
889  s8_t offset; // part-to-part offset in 2's compliment
890  double fRange; // range measurement
891  double fSum; // sum
892  int nMeasured; // number of sucessful range measurements
893  int i; // iterator
894  int rc; // return code
895 
896  //
897  // Read current, pre-calibrated offset register value.
898  //
899  if( (rc = readReg8(regOffset, (byte_t &)offset)) == LAE_OK )
900  {
901  m_regRangeOffset = (byte_t)offset; // update shadow register
902  }
903  else
904  {
905  LOGDIAG3("Failed to read SYSRANGE_PART_TO_PART_RANGE_OFFSET (0x%04x) "
906  "register. Cannot proceed with calibration.",
907  regOffset);
908  return rc;
909  }
910 
911  //
912  // Make a set of measurements to gather performance statistics.
913  //
914  for(i = 0, fSum = 0.0, nMeasured = 0; i<maxIters; ++i)
915  {
916  fRange = measureRange();
917  if( (fRange >= 0.0) && (fRange <= VL6180X_RANGE_MAX) )
918  {
919  fSum += fRange;
920  ++nMeasured;
921  }
922  }
923 
924  //
925  // Not of enough good measurements to determine performance.
926  //
927  if( nMeasured < minGood )
928  {
929  LOGDIAG3("Made %d/%d range meassurements. A minimum of %d are required."
930  "Cannot proceed with calibration.",
931  nMeasured, minGood);
932  return -LAE_ECODE_IO;
933  }
934 
935  nOffsetPre = (int)offset;
936  fAvgPre = fSum / (double)nMeasured;
937 
938  //
939  // No part-to-part offset calibaration required.
940  //
941  if( (fAvgPre >= fWhiteTgt-fRes) && (fAvgPre <= fWhiteTgt+fRes) )
942  {
943  nOffsetPost = nOffsetPre;
944  fAvgPost = fAvgPre;
945  return LAE_OK;
946  }
947 
948  //
949  // Clear offset register.
950  //
951  if( (rc = writeReg8(regOffset, 0)) == LAE_OK )
952  {
953  m_regRangeOffset = 0; // update shadow register
954  }
955  else
956  {
957  LOGDIAG3("Failed to write SYSRANGE_PART_TO_PART_RANGE_OFFSET (0x%04x) "
958  "register. Cannot proceed with calibration.",
959  regOffset);
960  return rc;
961  }
962 
963  //
964  // Make another set of measurements.
965  //
966  for(i = 0, fSum = 0.0, nMeasured = 0; i<maxIters; ++i)
967  {
968  fRange = measureRange();
969  if( (fRange >= 0.0) && (fRange <= VL6180X_RANGE_MAX) )
970  {
971  fSum += fRange;
972  ++nMeasured;
973  }
974  }
975 
976  //
977  // Not of enough good measurements to determine calibration offset.
978  //
979  if( nMeasured < minGood )
980  {
981  LOGDIAG3("Made %d/%d range meassurements. A minimum of %d are required."
982  "Cannot proceed with calibration.",
983  nMeasured, minGood);
984  return -LAE_ECODE_IO;
985  }
986 
987  fAvgPost = fSum / (double)nMeasured;
988  nOffsetPost = (int)((fWhiteTgt - fAvgPost) * 1000.0);
989 
990  offset = (s8_t)(nOffsetPost);
991 
992  //
993  // Write new offset value.
994  //
995  if( (rc = writeReg8(regOffset, (byte_t)offset)) == LAE_OK )
996  {
997  m_regRangeOffset = (byte_t)offset; // update shadow register
998  }
999  else
1000  {
1001  LOGDIAG3("Failed to write new SYSRANGE_PART_TO_PART_RANGE_OFFSET (0x%04x) "
1002  "register. Calibration failed.",
1003  regOffset);
1004  return rc;
1005  }
1006 
1007  //
1008  // One final performance evaluation.
1009  //
1010  for(i = 0, fSum = 0.0, nMeasured = 0; i<maxIters; ++i)
1011  {
1012  fRange = measureRange();
1013  if( (fRange >= 0.0) && (fRange <= VL6180X_RANGE_MAX) )
1014  {
1015  fSum += fRange;
1016  ++nMeasured;
1017  }
1018  }
1019 
1020  //
1021  // Not of enough good measurements to determine performance.
1022  //
1023  if( nMeasured < minGood )
1024  {
1025  LOGWARN("Made %d/%d range meassurements. A minimum of %d are required."
1026  "Post performance evaluation is unknown.",
1027  nMeasured, minGood);
1028  }
1029  else
1030  {
1031  fAvgPost = fSum / (double)nMeasured;
1032  }
1033 
1034  return LAE_OK;
1035 }
1036 
1037 int LaeVL6180Mux::calibCrossTalk(int &nCrossTalk)
1038 {
1039  u16_t regComp = VL6180X_SYSRANGE_CROSSTALK_COMPENSATION_RATE;
1040  u16_t regRate = VL6180X_RESULT_RANGE_RETURN_RATE;
1041  double fBlackTgt = 0.100; // required black target distance
1042  int minGood = 10; // minimum number of measurement to be valid
1043  int maxIters = 20; // should >= min as per data sheet
1044 
1045  byte_t val; // register value
1046  double fRate; // range return rate measurement
1047  double fSumRate; // return rate sum
1048  double fAvgRate; // return rate average
1049  double fRange; // range measurement
1050  double fSumRange; // range sum
1051  double fAvgRange; // range average
1052  int nMeasured; // number of sucessful range measurements
1053  int i; // iterator
1054  int rc; // return code
1055 
1056  //
1057  // Clear compensation register.
1058  //
1059  if( (rc = writeReg16(regComp, 0)) == LAE_OK )
1060  {
1061  m_regRangeCrossTalk = 0; // update shadow register
1062  }
1063  else
1064  {
1065  LOGDIAG3("Failed to write SYSRANGE_CROSSTALK_COMPENSATION_RATE (0x%04x) "
1066  "register. Cannot proceed with calibration.",
1067  regComp);
1068  return rc;
1069  }
1070 
1071  //
1072  // Make set of measurements.
1073  //
1074  for(i = 0, fSumRange = 0.0, fSumRate = 0.0, nMeasured = 0; i<maxIters; ++i)
1075  {
1076  fRange = measureRange();
1077  rc = readReg8(regRate, val);
1078 
1079  if( (fRange >= 0.0) && (fRange <= VL6180X_RANGE_MAX) && (rc == LAE_OK) )
1080  {
1081  fSumRange += fRange;
1082  fSumRate += (double)val;
1083  ++nMeasured;
1084  }
1085  }
1086 
1087  //
1088  // Not of enough good measurements to determine calibration offset.
1089  //
1090  if( nMeasured < minGood )
1091  {
1092  LOGDIAG3("Made %d/%d rate/range meassurements. "
1093  "A minimum of %d are required."
1094  "Cannot proceed with calibration.",
1095  nMeasured, minGood);
1096  return -LAE_ECODE_IO;
1097  }
1098 
1099  fAvgRange = fSumRange / (double)nMeasured;
1100  fAvgRate = fSumRate / (double)nMeasured;
1101 
1102  val = (byte_t)(fAvgRate * (1.0 - fAvgRange/fBlackTgt));
1103 
1104  //
1105  // Write new compensation value.
1106  //
1107  if( (rc = writeReg16(regComp, val)) == LAE_OK )
1108  {
1109  m_regRangeCrossTalk = val; // update shadow register
1110  }
1111  else
1112  {
1113  LOGDIAG3("Failed to write new SYSRANGE_CROSSTALK_COMPENSATION_RATE (0x%04x)"
1114  " register value. Calibration failed.",
1115  regComp);
1116 
1117  return rc;
1118  }
1119 
1120  nCrossTalk = (int)val & 0x0ff;
1121 
1122  return LAE_OK;
1123 }
1124 
1126 {
1127  if( (eAlsGain >= 0) && (eAlsGain < GAIN_NumOf) )
1128  {
1129  return AlsGainAnalogTbl[eAlsGain];
1130  }
1131  else
1132  {
1133  return AlsGainAnalogTbl[GAIN_1];
1134  }
1135 }
1136 
1138 {
1139  int i;
1140  int eGain;
1141  double diff, minDiff;
1142 
1143  fAlsGain = fabs(fAlsGain);
1144 
1145  if( fAlsGain >= AlsGainAnalogTbl[GAIN_40] )
1146  {
1147  return GAIN_40;
1148  }
1149  else if( fAlsGain <= AlsGainAnalogTbl[GAIN_1] )
1150  {
1151  return GAIN_1;
1152  }
1153 
1154  eGain = 0;
1155  minDiff = fabs(AlsGainAnalogTbl[eGain] - fAlsGain);
1156 
1157  //
1158  // Find closest enum.
1159  //
1160  for(i=1; i<GAIN_NumOf; ++i)
1161  {
1162  diff = fabs(AlsGainAnalogTbl[i] - fAlsGain);
1163  if( diff < minDiff )
1164  {
1165  eGain = i;
1166  minDiff = diff;
1167  }
1168  }
1169 
1170  return (vl6180x_als_gain)eGain;
1171 }
1172 
1173 int LaeVL6180Mux::readReg8(u16_t reg, byte_t &val)
1174 {
1175  byte_t req[2];
1176  int n = 0;
1177  int rc;
1178 
1179  req[n++] = (byte_t)((reg >> 8) & 0xff);
1180  req[n++] = (byte_t)(reg & 0xff);
1181 
1182  rc = m_mux.transact(m_nChan, VL6180X_ADDR, req, n, &val, 1, 0);
1183 
1184  if( rc != LAE_OK )
1185  {
1186  LOGDIAG3("VL6180 sensor %s(%d): Failed to read register 0x%04x.",
1187  m_strNameId.c_str(), m_nChan, reg);
1188  }
1189 
1190  return rc;
1191 }
1192 
1193 int LaeVL6180Mux::readReg16(u16_t reg, u16_t &val)
1194 {
1195  byte_t req[2];
1196  byte_t rsp[2];
1197  int n = 0;
1198  int rc;
1199 
1200  req[n++] = (byte_t)((reg >> 8) & 0xff);
1201  req[n++] = (byte_t)(reg & 0xff);
1202 
1203  rc = m_mux.transact(m_nChan, VL6180X_ADDR, req, n, rsp, 2, 0);
1204 
1205  if( rc == LAE_OK )
1206  {
1207  val = ((u16_t)(rsp[0]) << 8) | (u16_t)rsp[1];
1208  }
1209  else
1210  {
1211  LOGDIAG3("VL6180 sensor %s(%d): Failed to read register 0x%04x.",
1212  m_strNameId.c_str(), m_nChan, reg);
1213  }
1214 
1215  return rc;
1216 }
1217 
1218 int LaeVL6180Mux::writeReg8(u16_t reg, byte_t val)
1219 {
1220  byte_t req[3];
1221  int n = 0;
1222  int k;
1223  int rc;
1224 
1225  req[n++] = (byte_t)((reg >> 8) & 0xff);
1226  req[n++] = (byte_t)(reg & 0xff);
1227  req[n++] = val;
1228 
1229  if( (k = m_mux.write(m_nChan, VL6180X_ADDR, req, n)) == n )
1230  {
1231  rc = LAE_OK;
1232  }
1233  else
1234  {
1235  LOGDIAG3("VL6180 sensor %s(%d): Failed to write register 0x%04x.",
1236  m_strNameId.c_str(), m_nChan, reg);
1237  rc = -LAE_ECODE_IO;
1238  }
1239 
1240  return rc;
1241 }
1242 
1243 int LaeVL6180Mux::writeReg16(u16_t reg, u16_t val)
1244 {
1245  byte_t req[4];
1246  int n = 0;
1247  int k;
1248  int rc;
1249 
1250  req[n++] = (byte_t)((reg >> 8) & 0xff);
1251  req[n++] = (byte_t)(reg & 0xff);
1252  req[n++] = (byte_t)((val >> 8) & 0xff);
1253  req[n++] = (byte_t)(val & 0xff);
1254 
1255  if( (k = m_mux.write(m_nChan, VL6180X_ADDR, req, n)) == n )
1256  {
1257  rc = LAE_OK;
1258  }
1259  else
1260  {
1261  LOGDIAG3("VL6180 sensor %s(%d): Failed to write register 0x%04x.",
1262  m_strNameId.c_str(), m_nChan, reg);
1263  rc = -LAE_ECODE_IO;
1264  }
1265 
1266  return rc;
1267 }
1268 
1269 
1270 //------------------------------------------------------------------------------
1271 // LaeVL6180MuxArray Class
1272 //------------------------------------------------------------------------------
1273 
1275  LaeRangeInterface(i2cBus), m_mux(i2cBus)
1276 {
1277  m_nAlsIndex = 0;
1279 }
1280 
1282 {
1283  for(size_t i = 0; i < m_vecToF.size(); ++i)
1284  {
1285  delete m_vecToF[i];
1286  }
1287  m_vecToF.clear();
1288 
1289 }
1290 
1292  uint_t &uVerMinor,
1293  uint_t &uFwVer)
1294 {
1295  uVerMajor = LAE_VER_MAJOR(RtDb.m_product.m_uProdHwVer);
1296  uVerMinor = LAE_VER_MINOR(RtDb.m_product.m_uProdHwVer);
1297  uFwVer = 0;
1298 
1299  return laelaps::LAE_OK;
1300 }
1301 
1303 {
1304  for(size_t i = 0; i < m_vecToF.size(); ++i)
1305  {
1306  delete m_vecToF[i];
1307  }
1308  m_vecToF.clear();
1309 }
1310 
1312 {
1313  LaeDesc::MapDescRangeSensor::const_iterator iter;
1314  VL6180xIdentification ident;
1315  int rc;
1316 
1317  //
1318  // Time of Flight proximity sensors.
1319  //
1320  for(iter = desc.m_mapDescRangeSensor.begin();
1321  iter != desc.m_mapDescRangeSensor.end();
1322  ++iter)
1323  {
1324  m_vecToF.push_back(new LaeVL6180Mux(m_mux,
1325  iter->second->m_nChan,
1326  iter->second->m_fDir,
1327  iter->second->m_fDeadzone,
1328  iter->first,
1329  iter->second->m_strDesc));
1330  }
1331 
1332  //
1333  // Try to initialize the sensors. But any failures will map only to warnings,
1334  // since we want the robot to still operate.
1335  //
1336  for(size_t i = 0; i < m_vecToF.size(); ++i)
1337  {
1338  if( (rc = m_vecToF[i]->readId(ident)) < 0 )
1339  {
1340  LOGWARN("VL6180 %s sensor: Failed to read identity.",
1341  m_vecToF[i]->getNameId().c_str());
1342  }
1343 
1344  if( (rc = m_vecToF[i]->initSensor(true)) < 0 )
1345  {
1346  LOGWARN("VL6180 %s sensor: Failed to initialize sensor.",
1347  m_vecToF[i]->getNameId().c_str());
1348  }
1349 
1350  if( rc == LAE_OK )
1351  {
1352  LOGDIAG3("VL6180 %s sensor connected:\n"
1353  " Location: %s\n"
1354  " Model: %u v%u.%u\n"
1355  " Module: v%u.%u\n"
1356  " Date: %u %u",
1357  m_vecToF[i]->getNameId().c_str(),
1358  m_vecToF[i]->getDesc().c_str(),
1359  ident.idModel, ident.idModelRevMajor, ident.idModelRevMinor,
1360  ident.idModuleRevMajor, ident.idModuleRevMinor,
1361  ident.idDate, ident.idTime);
1362 
1363  }
1364  }
1365 
1366  return LAE_OK;
1367 }
1368 
1370 {
1371  string strKey;
1372  int nRangeOffset;
1373  int nRangeCrossTalk;
1374  double fAlsGain;
1375  int nAlsIntPeriod;
1376  int rc;
1377 
1378  for(size_t i = 0; i < m_vecToF.size(); ++i)
1379  {
1380  strKey = m_vecToF[i]->getNameId();
1381 
1382  tunes.getVL6180Params(strKey, nRangeOffset, nRangeCrossTalk,
1383  fAlsGain, nAlsIntPeriod);
1384 
1385  rc = m_vecToF[i]->tune((uint_t)nRangeOffset, (uint_t)nRangeCrossTalk,
1386  fAlsGain, (uint_t)nAlsIntPeriod);
1387 
1388  if( rc == LAE_OK )
1389  {
1390  LOGDIAG3("VL6180 range sensor %s tuned.", strKey.c_str());
1391  }
1392  else
1393  {
1394  LOGERROR("VL6180 range sensor %s: Failed to tune sensor.",
1395  strKey.c_str());
1396  return rc;
1397  }
1398  }
1399 
1400  LOGDIAG2("Tuned VL6180 range sensor group.");
1401 
1402  return LAE_OK;
1403 }
1404 
1406 {
1407  LOGDIAG2("Reloading VL6180 range sensor group tuning parameters...");
1408 
1409  return configure(tunes);
1410 }
1411 
1413 {
1414  int nNumSensors;
1415  double fRange;
1416  double fAmbient;
1417 
1418  // no sensors
1419  if( (nNumSensors = (int)m_vecToF.size()) == 0 )
1420  {
1421  return;
1422  }
1423 
1424  // take all range measurements
1425  if( --m_nAlsCounter > 0 )
1426  {
1427  for(int sensorIndex = 0; sensorIndex < nNumSensors; ++sensorIndex)
1428  {
1429  fRange = m_vecToF[sensorIndex]->measureRange(fAmbient);
1430  RtDb.m_range[sensorIndex].m_fRange = fRange;
1431  }
1432  }
1433 
1434  // take single ambient light measurement
1435  else
1436  {
1437  fAmbient = m_vecToF[m_nAlsIndex]->measureAmbientLight();
1438  RtDb.m_range[m_nAlsIndex].m_fAmbientLight = fAmbient;
1439 
1440  m_nAlsIndex = (m_nAlsIndex + 1) % nNumSensors;
1442  }
1443 }
1444 
1445 int LaeVL6180MuxArray::getRange(const std::string &strKey, double &fRange)
1446 {
1447  double fAmbient; // not used
1448  int i;
1449 
1450  if( (i = keyIndex(strKey)) >= 0 )
1451  {
1452  m_vecToF[i]->getMeasurements(fRange, fAmbient);
1453  return LAE_OK;
1454  }
1455  else
1456  {
1457  LOGERROR("VL6180 range sensor %s does not exist.", strKey.c_str());
1458  return -LAE_ECODE_BAD_VAL;
1459  }
1460 }
1461 
1462 int LaeVL6180MuxArray::getRange(std::vector<std::string> &vecNames,
1463  std::vector<double> &vecRanges)
1464 {
1465  double fRange;
1466  double fAmbient;
1467 
1468  vecNames.clear();
1469  vecRanges.clear();
1470 
1471  for(size_t i = 0; i < m_vecToF.size(); ++i)
1472  {
1473  m_vecToF[i]->getMeasurements(fRange, fAmbient);
1474 
1475  vecNames.push_back(m_vecToF[i]->getNameId());
1476  vecRanges.push_back(fRange);
1477  }
1478 
1479  return LAE_OK;
1480 }
1481 
1482 int LaeVL6180MuxArray::getAmbientLight(const std::string &strKey, double &fLux)
1483 {
1484  double fRange; // not used
1485  int i;
1486 
1487  if( (i = keyIndex(strKey)) >= 0 )
1488  {
1489  m_vecToF[i]->getMeasurements(fRange, fLux);
1490  return LAE_OK;
1491  }
1492  else
1493  {
1494  LOGERROR("VL6180 range sensor %s does not exist.", strKey.c_str());
1495  return -LAE_ECODE_BAD_VAL;
1496  }
1497 }
1498 
1499 int LaeVL6180MuxArray::getAmbientLight(std::vector<std::string> &vecNames,
1500  std::vector<double> &vecLux)
1501 {
1502  double fRange;
1503  double fAmbient;
1504 
1505  vecNames.clear();
1506  vecLux.clear();
1507 
1508  for(size_t i = 0; i < m_vecToF.size(); ++i)
1509  {
1510  m_vecToF[i]->getMeasurements(fRange, fAmbient);
1511 
1512  vecNames.push_back(m_vecToF[i]->getNameId());
1513  vecLux.push_back(fAmbient);
1514  }
1515 
1516  return LAE_OK;
1517 }
1518 
1519 int LaeVL6180MuxArray::getSensorProps(const std::string &strKey,
1520  std::string &strRadiationType,
1521  double &fFoV,
1522  double &fBeamDir,
1523  double &fMin,
1524  double &fMax)
1525 {
1526  int i;
1527 
1528  if( (i = keyIndex(strKey)) >= 0 )
1529  {
1530  strRadiationType = m_vecToF[i]->getRadiationType();
1531  fFoV = m_vecToF[i]->getFoV();
1532  fBeamDir = m_vecToF[i]->getBeamDir();
1533  m_vecToF[i]->getMinMax(fMin, fMax);
1534  return LAE_OK;
1535  }
1536  else
1537  {
1538  LOGERROR("VL6180 range sensor %s does not exist.", strKey.c_str());
1539  return -LAE_ECODE_BAD_VAL;
1540  }
1541 }
1542 
1543 int LaeVL6180MuxArray::readSensorIdentity(const string &strKey,
1544  VL6180xIdentification &ident)
1545 {
1546  int i;
1547 
1548  if( (i = keyIndex(strKey)) >= 0 )
1549  {
1550  return m_vecToF[i]->readId(ident);
1551  }
1552  else
1553  {
1554  LOGERROR("VL6180 range sensor %s does not exist.", strKey.c_str());
1555  return -LAE_ECODE_BAD_VAL;
1556  }
1557 }
1558 
1559 int LaeVL6180MuxArray::readSensorTunes(const string &strKey,
1560  uint_t &uRangeOffset,
1561  uint_t &uRangeCrossTalk,
1562  double &fAlsGain,
1563  uint_t &uAlsIntPeriod)
1564 {
1565  byte_t regRangeOffset;
1566  u16_t regRangeCrossTalk;
1567  byte_t regAlsGain;
1568  u16_t regAlsIntPeriod;
1569  int i;
1570 
1571  if( (i = keyIndex(strKey)) >= 0 )
1572  {
1573  m_vecToF[i]->readShadowRegs(regRangeOffset, regRangeCrossTalk,
1574  regAlsGain, regAlsIntPeriod);
1575 
1576  uRangeOffset = (uint_t)regRangeOffset;
1577  uRangeCrossTalk = (uint_t)regRangeCrossTalk;
1578 
1579  fAlsGain = LaeVL6180Mux::gainEnumToAnalog((vl6180x_als_gain)regAlsGain);
1580  uAlsIntPeriod = (uint)regAlsIntPeriod + 1;
1581  return LAE_OK;
1582  }
1583  else
1584  {
1585  LOGERROR("VL6180 range sensor %s does not exist.", strKey.c_str());
1586  return -LAE_ECODE_BAD_VAL;
1587  }
1588 }
1589 
1590 int LaeVL6180MuxArray::keyIndex(const string &strKey)
1591 {
1592  for(size_t i = 0; i < m_vecToF.size(); ++i)
1593  {
1594  if( m_vecToF[i]->getNameId() == strKey )
1595  {
1596  return (int)i;
1597  }
1598  }
1599  return -1;
1600 }
1601 
1602 //------------------------------------------------------------------------------
1603 // LaeRangeMuxSubproc Class
1604 //------------------------------------------------------------------------------
1605 
1607  LaeRangeInterface(i2cBus), m_addrSubProc(addr),
1608  m_vecRanges(ToFSensorMaxNumOf, 0.0),
1609  m_vecLux(ToFSensorMaxNumOf, 0.0)
1610 {
1611  m_uFwVer = 0;
1612 
1613  pthread_mutex_init(&m_mutex, NULL);
1614 }
1615 
1617 {
1618  pthread_mutex_destroy(&m_mutex);
1619 }
1620 
1622  uint_t &uVerMinor,
1623  uint_t &uFwVer)
1624 {
1625  int rc;
1626 
1627  rc = cmdGetFwVersion(m_uFwVer);
1628 
1629  uVerMajor = LAE_VER_MAJOR(RtDb.m_product.m_uProdHwVer);
1630  uVerMinor = LAE_VER_MINOR(RtDb.m_product.m_uProdHwVer);
1631  uFwVer = m_uFwVer;
1632 
1633  return rc;
1634 }
1635 
1637 {
1638  m_mapInfo.clear();
1639 
1640  for(size_t i = 0; i < m_vecRanges.size(); ++i)
1641  {
1643  }
1644 
1645  for(size_t i = 0; i < m_vecLux.size(); ++i)
1646  {
1647  m_vecLux[i] = 0.0;
1648  }
1649 }
1650 
1652 {
1653  LaeDesc::MapDescRangeSensor::const_iterator iter;
1654  SensorInfoMap::iterator iter2;
1655 
1656  // subproc version
1657  uint_t uFwVer;
1658 
1659  // sensor identity
1660  VL6180xIdentification ident;
1661  bool bIdent;
1662 
1663  // sensor tuning values
1664  uint_t uRangeOffset;
1665  uint_t uRangeCrossTalk;
1666  double fAlsGain;
1667  uint_t uAlsIntPeriod;
1668  s8_t nOffset;
1669  bool bTunes;
1670 
1671  // sensor properties
1672  string strRadiationType;
1673  double fFoV;
1674  double fBeamDir;
1675  double fMin;
1676  double fMax;
1677 
1678  int rc;
1679 
1680  //
1681  // Read firmware version, if necessary.
1682  //
1683  if( m_uFwVer == 0 )
1684  {
1685  if( (rc = cmdGetFwVersion(uFwVer)) != LAE_OK )
1686  {
1687  LOGERROR("Failed to read ToFMux firmware version.");
1688  }
1689  }
1690 
1691  //
1692  // Product Time of Flight proximity sensors.
1693  //
1694  for(iter = desc.m_mapDescRangeSensor.begin();
1695  iter != desc.m_mapDescRangeSensor.end();
1696  ++iter)
1697  {
1698  // map key - index assoc. (channel number is index for now)
1699  m_mapInfo[iter->first] = LaeVL6180SensorInfo(iter->second->m_nChan,
1700  iter->second->m_nChan,
1701  iter->second->m_fDir,
1702  iter->second->m_fDeadzone,
1703  iter->second->m_strDesc);
1704  }
1705 
1706  //
1707  // Get identity on each sensor.
1708  //
1709  for(iter2 = m_mapInfo.begin(); iter2 != m_mapInfo.end(); ++iter2)
1710  {
1711  bIdent = false;
1712  bTunes = false;
1713 
1714  if( (rc = cmdGetIdent(iter2->first, ident)) == LAE_OK )
1715  {
1716  bIdent = true;
1717  }
1718  else
1719  {
1720  LOGERROR("VL6180 range %s sensor: Failed to read identify.",
1721  iter2->first.c_str());
1722  }
1723 
1724  rc = cmdGetTunes(iter2->first, uRangeOffset, uRangeCrossTalk,
1725  fAlsGain, uAlsIntPeriod);
1726 
1727  if( rc == LAE_OK )
1728  {
1729  bTunes = true;
1730  }
1731  else
1732  {
1733  LOGERROR("VL6180 range %s sensor: Failed to read tune parameters.",
1734  iter2->first.c_str());
1735  }
1736 
1737  nOffset = (s8_t)(uRangeOffset & 0xff);
1738 
1739  getSensorProps(iter2->first, strRadiationType,
1740  fFoV, fBeamDir, fMin, fMax);
1741 
1742  LOGDIAG2("VL6180 %s(%d) Sensor Info:\n"
1743  " Properties\n"
1744  " Location: %s\n"
1745  " Beam Direction: %.1lf degrees\n"
1746  " Radiation: %s\n"
1747  " FoV: %.1lf degrees\n"
1748  " Min Distance: %.3lf meters\n"
1749  " MAx Distance: %.3lf meters\n"
1750  " Identity\n"
1751  " Model: 0x%02x v%u.%u\n"
1752  " Module: v%u.%u\n"
1753  " Date/Time: %u/%u\n"
1754  " Tuning\n"
1755  " ToF Offset: %d(%u)\n"
1756  " ToF Cross-Talk: %u\n"
1757  " ALS Gain: %.2lf\n"
1758  " ALS Int. Period: %u msec",
1759  iter2->first.c_str(), iter2->second.m_nIndex,
1760  iter2->first.c_str(),
1761  radToDeg(fBeamDir),
1762  strRadiationType.c_str(),
1763  radToDeg(fFoV),
1764  fMin,
1765  fMax,
1766  ident.idModel, ident.idModelRevMajor, ident.idModelRevMinor,
1767  ident.idModuleRevMajor, ident.idModuleRevMinor,
1768  ident.idDate, ident.idTime,
1769  nOffset, uRangeOffset,
1770  uRangeCrossTalk,
1771  fAlsGain,
1772  uAlsIntPeriod);
1773  }
1774 
1775  LOGDIAG2("Configured Range Sensor Group from robot description.");
1776 
1777  return LAE_OK;
1778 }
1779 
1781 {
1782  int nRangeOffset;
1783  int nRangeCrossTalk;
1784  double fAlsGain;
1785  int nAlsIntPeriod;
1786  int rc;
1787 
1788  SensorInfoMap::iterator iter;
1789 
1790  for(iter = m_mapInfo.begin(); iter != m_mapInfo.end(); ++iter)
1791  {
1792  tunes.getVL6180Params(iter->first, nRangeOffset, nRangeCrossTalk,
1793  fAlsGain, nAlsIntPeriod);
1794 
1795  //
1796  // Time-of-flight sensor tuning.
1797  //
1798  if( (nRangeOffset != VL6180X_FACTORY_DFT) &&
1799  (nRangeCrossTalk != VL6180X_FACTORY_DFT) )
1800  {
1801  rc = cmdTuneToFSensor(iter->first, (uint_t)nRangeOffset,
1802  (uint_t)nRangeCrossTalk);
1803 
1804  if( rc == LAE_OK )
1805  {
1806  LOGDIAG3("VL6180 range sensor %s: Time-of-flight sensor tuned.",
1807  iter->first.c_str());
1808  }
1809  else
1810  {
1811  LOGERROR("VL6180 range sensor %s: Failed to tune time-of-flight.",
1812  iter->first.c_str());
1813  return rc;
1814  }
1815  }
1816 
1817  //
1818  // Ambient light sensor tuning.
1819  //
1820  rc = cmdTuneAls(iter->first, fAlsGain, (uint_t)nAlsIntPeriod);
1821 
1822  if( rc == LAE_OK )
1823  {
1824  LOGDIAG3("VL6180 range sensor %s: Ambient light sensor tuned.",
1825  iter->first.c_str());
1826  }
1827  else
1828  {
1829  LOGERROR("VL6180 range sensor %s: Failed to tune ambient light sensor.",
1830  iter->first.c_str());
1831  return rc;
1832  }
1833  }
1834 
1835  LOGDIAG2("Tuned VL6180 range sensor group.");
1836 
1837  return rc;
1838 }
1839 
1841 {
1842  LOGDIAG2("Reloading VL6180 range sensor group tuning parameters...");
1843 
1844  return configure(tunes);
1845 }
1846 
1848 {
1849  cmdGetRanges();
1850 
1851 #ifdef LAE_USE_ALS
1853 #endif // LAE_USE_ALS
1854 }
1855 
1857 {
1858  byte_t cmd[LaeToFMuxI2CMaxCmdLen];
1859  byte_t rsp[LaeToFMuxI2CMaxRspLen];
1860  size_t lenCmd = 0;
1861  size_t lenRsp = LaeToFMuxI2CRspLenGetVersion;
1862  int rc;
1863 
1864  lock();
1865 
1866  cmd[lenCmd++] = LaeToFMuxI2CCmdIdGetVersion;
1867 
1868  rc = m_i2cBus.write_read(m_addrSubProc, cmd, lenCmd, rsp, lenRsp, TStd);
1869 
1870  if( rc == LAE_OK )
1871  {
1872  uVerNum = (uint_t)rsp[0];
1873  m_uFwVer = uVerNum;
1874  RtDb.m_product.m_uToFMuxFwVer = m_uFwVer;
1875  }
1876 
1877  unlock();
1878 
1879  return rc;
1880 }
1881 
1882 int LaeRangeMuxSubproc::cmdGetIdent(const std::string &strKey,
1883  VL6180xIdentification &ident)
1884 {
1885  byte_t cmd[LaeToFMuxI2CMaxCmdLen];
1886  byte_t rsp[LaeToFMuxI2CMaxRspLen];
1887  size_t lenCmd = 0;
1888  size_t lenRsp = LaeToFMuxI2CRspLenGetIdent;
1889  byte_t sensorIndex;
1890  u16_t val_hi, val_lo;
1891  int n;
1892  int rc;
1893 
1894  SensorInfoMap::iterator pos;
1895 
1896  if( (pos = m_mapInfo.find(strKey)) == m_mapInfo.end() )
1897  {
1898  LOGERROR("VL6180 sensor %s not found.", strKey.c_str());
1899  return -LAE_ECODE_BAD_VAL;
1900  }
1901 
1902  sensorIndex = pos->second.m_nIndex;
1903 
1904  lock();
1905 
1906  cmd[lenCmd++] = LaeToFMuxI2CCmdIdGetIdent;
1907  cmd[lenCmd++] = sensorIndex;
1908 
1909  rc = m_i2cBus.write_read(m_addrSubProc, cmd, lenCmd, rsp, lenRsp, TStd);
1910 
1911  if( rc == LAE_OK )
1912  {
1913  n = 0;
1914  ident.idModel = rsp[n++];
1915  ident.idModelRevMajor = rsp[n++];
1916  ident.idModelRevMinor = rsp[n++];
1917  ident.idModuleRevMajor = rsp[n++];
1918  ident.idModuleRevMinor = rsp[n++];
1919 
1920  val_hi = ((u16_t)rsp[n++]) << 8;
1921  val_lo = (u16_t)rsp[n++];
1922  ident.idDate = val_hi | val_lo;
1923 
1924  val_hi = ((u16_t)rsp[n++]) << 8;
1925  val_lo = (u16_t)rsp[n++];
1926  ident.idTime = val_hi | val_lo;
1927  }
1928 
1929  unlock();
1930 
1931  return rc;
1932 }
1933 
1935 {
1936  byte_t cmd[LaeToFMuxI2CMaxCmdLen];
1937  byte_t rsp[LaeToFMuxI2CMaxRspLen];
1938  size_t lenCmd = 0;
1939  size_t lenRsp = LaeToFMuxI2CRspLenGetRanges;
1940  int sensorIndex;
1941  byte_t val;
1942  double fRange;
1943  int rc;
1944 
1945  lock();
1946 
1947  cmd[lenCmd++] = LaeToFMuxI2CCmdIdGetRanges;
1948 
1949  rc = m_i2cBus.write_read(m_addrSubProc, cmd, lenCmd, rsp, lenRsp, TStd);
1950 
1951  if( rc == LAE_OK )
1952  {
1953  for(sensorIndex = 0; sensorIndex < ToFSensorMaxNumOf; ++sensorIndex)
1954  {
1955  val = rsp[sensorIndex];
1956  if( val <= LaeToFMuxRangeMax )
1957  {
1958  fRange = (double)val * 0.001; // mm to meters
1959  }
1960  else if( val == LaeToFMuxRangeNoObj )
1961  {
1962  fRange = VL6180X_RANGE_NO_OBJ;
1963  }
1964  else if( val == LaeToFMuxRangeNoDev )
1965  {
1966  fRange = VL6180X_RANGE_MIN;
1967  }
1968  else
1969  {
1970  fRange = VL6180X_ERR_MEAS;
1971  }
1972 
1973  m_vecRanges[sensorIndex] = fRange;
1974  }
1975  RtDb.m_range[sensorIndex].m_fRange = fRange;
1976  }
1977 
1978  unlock();
1979 
1980  return rc;
1981 }
1982 
1983 int LaeRangeMuxSubproc::cmdGetRanges(std::vector<double> &vecRanges)
1984 {
1985  int rc;
1986 
1987  if( (rc = cmdGetRanges()) == LAE_OK )
1988  {
1989  vecRanges = m_vecRanges;
1990  }
1991 
1992  return rc;
1993 }
1994 
1996 {
1997  byte_t cmd[LaeToFMuxI2CMaxCmdLen];
1998  byte_t rsp[LaeToFMuxI2CMaxRspLen];
1999  size_t lenCmd = 0;
2000  size_t lenRsp = LaeToFMuxI2CRspLenGetLux;
2001  int sensorIndex;
2002  int n;
2003  u32_t val;
2004  double fLux;
2005  int rc;
2006 
2007  lock();
2008 
2009  cmd[lenCmd++] = LaeToFMuxI2CCmdIdGetLux;
2010 
2011  rc = m_i2cBus.write_read(m_addrSubProc, cmd, lenCmd, rsp, lenRsp, TStd);
2012 
2013  if( rc == LAE_OK )
2014  {
2015  n = 0;
2016 
2017  for(sensorIndex = 0; sensorIndex < ToFSensorMaxNumOf; ++sensorIndex)
2018  {
2019  val = 0;
2020  for(int i = 0; i < 4; ++i)
2021  {
2022  val << 8;
2023  val |= rsp[n++];
2024  }
2025 
2026  fLux = (double)val * (double)LaeToFMuxI2CArgLuxScale;
2027 
2028  RtDb.m_range[sensorIndex].m_fAmbientLight = fLux;
2029  }
2030  }
2031 
2032  unlock();
2033 
2034  return rc;
2035 }
2036 
2037 int LaeRangeMuxSubproc::cmdGetAmbientLight(std::vector<double> &vecLux)
2038 {
2039  int rc;
2040 
2041  if( (rc = cmdGetAmbientLight()) == LAE_OK )
2042  {
2043  vecLux = m_vecLux;
2044  }
2045 
2046  return rc;
2047 }
2048 
2049 int LaeRangeMuxSubproc::cmdGetTunes(const std::string &strKey,
2050  uint_t &uRangeOffset,
2051  uint_t &uRangeCrossTalk,
2052  double &fAlsGain,
2053  uint_t &uAlsIntPeriod)
2054 {
2055  byte_t cmd[LaeToFMuxI2CMaxCmdLen];
2056  byte_t rsp[LaeToFMuxI2CMaxRspLen];
2057  size_t lenCmd = 0;
2058  size_t lenRsp = LaeToFMuxI2CRspLenGetTunes;
2059  byte_t sensorIndex;
2060  byte_t val;
2061  uint_t val_hi, val_lo;
2062  int n;
2063  int rc;
2064 
2065  SensorInfoMap::iterator pos;
2066 
2067  if( (pos = m_mapInfo.find(strKey)) == m_mapInfo.end() )
2068  {
2069  LOGERROR("VL6180 sensor %s not found.", strKey.c_str());
2070  return -LAE_ECODE_BAD_VAL;
2071  }
2072 
2073  sensorIndex = pos->second.m_nIndex;
2074 
2075  lock();
2076 
2077  cmd[lenCmd++] = LaeToFMuxI2CCmdIdGetTunes;
2078  cmd[lenCmd++] = sensorIndex;
2079 
2080  rc = m_i2cBus.write_read(m_addrSubProc, cmd, lenCmd, rsp, lenRsp, TStd);
2081 
2082  if( rc == LAE_OK )
2083  {
2084  n = 0;
2085 
2086  uRangeOffset = rsp[n++];
2087 
2088  if( m_uFwVer >= 2 )
2089  {
2090  val_hi = ((uint_t)rsp[n++]) << 8;
2091  val_lo = (uint_t)rsp[n++];
2092  uRangeCrossTalk = val_hi | val_lo;
2093  }
2094  else
2095  {
2096  uRangeCrossTalk = rsp[n++];
2097  }
2098 
2099  val = rsp[n++];
2101 
2102  val_hi = ((uint_t)rsp[n++]) << 8;
2103  val_lo = (uint_t)rsp[n++];
2104  uAlsIntPeriod = val_hi | val_lo;
2105  }
2106 
2107  unlock();
2108 
2109  return rc;
2110 }
2111 
2112 int LaeRangeMuxSubproc::cmdTuneToFSensor(const std::string &strKey,
2113  uint_t uRangeOffset,
2114  uint_t uRangeCrossTalk)
2115 {
2116  byte_t cmd[LaeToFMuxI2CMaxCmdLen];
2117  byte_t rsp[LaeToFMuxI2CMaxRspLen];
2118  size_t lenCmd = 0;
2119  size_t lenRsp = LaeToFMuxI2CRspLenTuneToFSensor;
2120  byte_t sensorIndex;
2121  byte_t regOffset;
2122  u16_t regCrossTalk;
2123  byte_t val_hi, val_lo;
2124  byte_t pf;
2125  int rc;
2126 
2127  SensorInfoMap::iterator pos;
2128 
2129  if( (pos = m_mapInfo.find(strKey)) == m_mapInfo.end() )
2130  {
2131  LOGERROR("VL6180 sensor %s not found.", strKey.c_str());
2132  return -LAE_ECODE_BAD_VAL;
2133  }
2134 
2135  sensorIndex = pos->second.m_nIndex;
2136 
2137  lock();
2138 
2139  regOffset = (byte_t)(uRangeOffset, (uint_t)VL6180X_RANGE_OFFSET_MIN,
2140  (uint_t)VL6180X_RANGE_OFFSET_MAX);
2141 
2142  regCrossTalk = (u16_t)cap(uRangeCrossTalk, (uint_t)VL6180X_RANGE_XTALK_MIN,
2143  (uint_t)VL6180X_RANGE_XTALK_MAX);
2144 
2145  cmd[lenCmd++] = LaeToFMuxI2CCmdIdTuneToFSensor;
2146  cmd[lenCmd++] = sensorIndex;
2147  cmd[lenCmd++] = regOffset;
2148 
2149  if( m_uFwVer >= 2 )
2150  {
2151  val_hi = (byte_t)((regCrossTalk >> 8) & 0xff);
2152  val_lo = (byte_t)(regCrossTalk & 0xff);
2153  cmd[lenCmd++] = val_hi;
2154  cmd[lenCmd++] = val_lo;
2155  }
2156  else
2157  {
2158  cmd[lenCmd++] = regCrossTalk;
2159  }
2160 
2161  rc = m_i2cBus.write_read(m_addrSubProc, cmd, lenCmd, rsp, lenRsp, TStd);
2162 
2163  if( rc == LAE_OK )
2164  {
2165  pf = rsp[0]; // pass/fail
2166  }
2167 
2168  unlock();
2169 
2170  return rc;
2171 }
2172 
2173 int LaeRangeMuxSubproc::cmdTuneAls(const std::string &strKey,
2174  double fAlsGain,
2175  uint_t uAlsIntPeriod)
2176 {
2177  byte_t cmd[LaeToFMuxI2CMaxCmdLen];
2178  byte_t rsp[LaeToFMuxI2CMaxRspLen];
2179  size_t lenCmd = 0;
2180  size_t lenRsp = LaeToFMuxI2CRspLenTuneAls;
2181  byte_t sensorIndex;
2182  byte_t regAlsGain;
2183  byte_t val_hi, val_lo;
2184  byte_t pf;
2185  int rc;
2186 
2187  SensorInfoMap::iterator pos;
2188 
2189  if( (pos = m_mapInfo.find(strKey)) == m_mapInfo.end() )
2190  {
2191  LOGERROR("VL6180 sensor %s not found.", strKey.c_str());
2192  return -LAE_ECODE_BAD_VAL;
2193  }
2194 
2195  sensorIndex = pos->second.m_nIndex;
2196 
2197  lock();
2198 
2199  regAlsGain = (byte_t)LaeVL6180Mux::gainAnalogToEnum(fAlsGain);
2200 
2201  uAlsIntPeriod = cap(uAlsIntPeriod, (uint_t)VL6180X_AMBIENT_INT_T_MIN,
2202  (uint_t)VL6180X_AMBIENT_INT_T_MAX);
2203 
2204  val_hi = (byte_t)((uAlsIntPeriod >> 8) & 0xff);
2205  val_lo = (byte_t)(uAlsIntPeriod & 0xff);
2206 
2207  cmd[lenCmd++] = LaeToFMuxI2CCmdIdTuneAls;
2208  cmd[lenCmd++] = sensorIndex;
2209  cmd[lenCmd++] = regAlsGain;
2210  cmd[lenCmd++] = val_hi;
2211  cmd[lenCmd++] = val_lo;
2212 
2213  rc = m_i2cBus.write_read(m_addrSubProc, cmd, lenCmd, rsp, lenRsp, TStd);
2214 
2215  if( rc == LAE_OK )
2216  {
2217  pf = rsp[0]; // pass/fail
2218  }
2219 
2220  unlock();
2221 
2222  return rc;
2223 }
2224 
2225 int LaeRangeMuxSubproc::getRange(const std::string &strKey, double &fRange)
2226 {
2227  SensorInfoMap::iterator pos;
2228 
2229  if( (pos = m_mapInfo.find(strKey)) == m_mapInfo.end() )
2230  {
2231  LOGERROR("VL6180 sensor %s not found.", strKey.c_str());
2232  return -LAE_ECODE_BAD_VAL;
2233  }
2234 
2235  int sensorIndex = pos->second.m_nIndex;
2236 
2237  fRange = m_vecRanges[sensorIndex];
2238 
2239  return LAE_OK;
2240 }
2241 
2242 int LaeRangeMuxSubproc::getRange(std::vector<std::string> &vecNames,
2243  std::vector<double> &vecRanges)
2244 {
2245  SensorInfoMap::iterator iter;
2246 
2247  vecNames.clear();
2248  vecRanges.clear();
2249 
2250  for(iter = m_mapInfo.begin(); iter != m_mapInfo.end(); ++iter)
2251  {
2252  vecNames.push_back(iter->first);
2253  vecRanges.push_back(m_vecRanges[iter->second.m_nIndex]);
2254  }
2255 
2256  return LAE_OK;
2257 }
2258 
2259 int LaeRangeMuxSubproc::getAmbientLight(const std::string &strKey, double &fLux)
2260 {
2261  SensorInfoMap::iterator pos;
2262 
2263  if( (pos = m_mapInfo.find(strKey)) == m_mapInfo.end() )
2264  {
2265  LOGERROR("VL6180 sensor %s not found.", strKey.c_str());
2266  return -LAE_ECODE_BAD_VAL;
2267  }
2268 
2269  int sensorIndex = pos->second.m_nIndex;
2270 
2271  fLux = m_vecLux[sensorIndex];
2272 
2273  return LAE_OK;
2274 }
2275 
2276 int LaeRangeMuxSubproc::getAmbientLight(std::vector<std::string> &vecNames,
2277  std::vector<double> &vecLux)
2278 {
2279  SensorInfoMap::iterator iter;
2280 
2281  vecNames.clear();
2282  vecLux.clear();
2283 
2284  for(iter = m_mapInfo.begin(); iter != m_mapInfo.end(); ++iter)
2285  {
2286  vecNames.push_back(iter->first);
2287  vecLux.push_back(m_vecLux[iter->second.m_nIndex]);
2288  }
2289 
2290 }
2291 
2292 int LaeRangeMuxSubproc::getSensorProps(const std::string &strKey,
2293  std::string &strRadiationType,
2294  double &fFoV,
2295  double &fBeamDir,
2296  double &fMin,
2297  double &fMax)
2298 {
2299  SensorInfoMap::iterator pos;
2300 
2301  if( (pos = m_mapInfo.find(strKey)) == m_mapInfo.end() )
2302  {
2303  LOGERROR("VL6180 range sensor %s not found.", strKey.c_str());
2304  return -LAE_ECODE_BAD_VAL;
2305  }
2306 
2307  int nIndex;
2308  int nChan;
2309  double fDeadzone;
2310  std::string strDesc;
2311 
2312  pos->second.getProps(nIndex, nChan, strRadiationType, fFoV, fBeamDir,
2313  fDeadzone, fMin, fMax, strDesc);
2314 
2315  return LAE_OK;
2316 }
2317 
2319  VL6180xIdentification &ident)
2320 
2321 {
2322  return cmdGetIdent(strKey, ident);
2323 }
2324 
2325 int LaeRangeMuxSubproc::readSensorTunes(const string &strKey,
2326  uint_t &uRangeOffset,
2327  uint_t &uRangeCrossTalk,
2328  double &fAlsGain,
2329  uint_t &uAlsIntPeriod)
2330 {
2331  return cmdGetTunes(strKey, uRangeOffset, uRangeCrossTalk,
2332  fAlsGain, uAlsIntPeriod);
2333 }
2334 
2335 
2336 //------------------------------------------------------------------------------
2337 // LaeRangeSensorGroup Class
2338 //------------------------------------------------------------------------------
2339 
2341  m_i2cBus(i2cBus)
2342 {
2343  m_interface = new LaeRangeInterface(i2cBus); // no-op version
2344  m_bBlackListed = false;
2345  RtDb.m_enable.m_bRange = true;
2346 }
2347 
2349 {
2350  if( m_interface != NULL )
2351  {
2352  delete m_interface;
2353  }
2354 }
2355 
2357 {
2358  m_bBlackListed = true;
2359  RtDb.m_enable.m_bRange = false;
2360 }
2361 
2363 {
2364  m_bBlackListed = false;
2365  RtDb.m_enable.m_bRange = true;
2366 }
2367 
2369 {
2370  if( m_interface != NULL )
2371  {
2372  delete m_interface;
2373  m_interface = NULL;
2374  }
2375 
2376  if( uProdHwVer >= LAE_VERSION(2, 1, 0) )
2377  {
2379  }
2380  else
2381  {
2383  }
2384 
2385  return LAE_OK;
2386 }
2387 
2389 {
2391 }
2392 
2394  uint_t &uVerMinor,
2395  uint_t &uFwVer)
2396 {
2397  // ignore blacklist
2398  return m_interface->getInterfaceVersion(uVerMajor, uVerMinor, uFwVer);
2399 }
2400 
2402 {
2403  if( !isBlackListed() )
2404  {
2405  return m_interface->configure(desc);
2406  }
2407  else
2408  {
2409  return LAE_OK;
2410  }
2411 }
2412 
2414 {
2415  if( !isBlackListed() )
2416  {
2417  return m_interface->configure(tunes);
2418  }
2419  else
2420  {
2421  return LAE_OK;
2422  }
2423 }
2424 
2426 {
2427  if( !isBlackListed() )
2428  {
2429  return m_interface->reload(tunes);
2430  }
2431  else
2432  {
2433  return LAE_OK;
2434  }
2435 }
2436 
2437 int LaeRangeSensorGroup::getSensorProps(const string &strKey,
2438  string &strRadiationType,
2439  double &fFoV,
2440  double &fBeamDir,
2441  double &fMin,
2442  double &fMax)
2443 {
2444  // read-only data - nothing to blacklist
2445  return m_interface->getSensorProps(strKey,
2446  strRadiationType,
2447  fFoV, fBeamDir,
2448  fMin, fMax);
2449 }
2450 
2452  VL6180xIdentification &ident)
2453 
2454 {
2455  if( !isBlackListed() )
2456  {
2457  m_interface->readSensorIdentity(strKey, ident);
2458  }
2459  else
2460  {
2461  memset(&ident, 0, sizeof(VL6180xIdentification));
2462  return LAE_OK;
2463  }
2464 }
2465 
2466 int LaeRangeSensorGroup::readSensorTunes(const string &strKey,
2467  uint_t &uRangeOffset,
2468  uint_t &uRangeCrossTalk,
2469  double &fAlsGain,
2470  uint_t &uAlsIntPeriod)
2471 {
2472  if( !isBlackListed() )
2473  {
2474  m_interface->readSensorTunes(strKey, uRangeOffset, uRangeCrossTalk,
2475  fAlsGain, uAlsIntPeriod);
2476  }
2477  else
2478  {
2479  uRangeOffset = 0;
2480  uRangeCrossTalk = 0;
2481  fAlsGain = 0.0;
2482  uAlsIntPeriod = 0;
2483  return LAE_OK;
2484  }
2485 }
2486 
2487 int LaeRangeSensorGroup::getRange(const string &strKey, double &fRange)
2488 {
2489  // shadowed data - nothing to blacklist
2490  return m_interface->getRange(strKey, fRange);
2491 }
2492 
2493 int LaeRangeSensorGroup::getRange(vector<string> &vecNames,
2494  vector<double> &vecRanges)
2495 {
2496  // shadowed data - nothing to blacklist
2497  return m_interface->getRange(vecNames, vecRanges);
2498 }
2499 
2500 int LaeRangeSensorGroup::getAmbientLight(const string &strKey, double &fAmbient)
2501 {
2502  // shadowed data - nothing to blacklist
2503  return m_interface->getAmbientLight(strKey, fAmbient);
2504 }
2505 
2506 int LaeRangeSensorGroup::getAmbientLight(vector<string> &vecNames,
2507  vector<double> &vecAmbient)
2508 {
2509  // shadowed data - nothing to blacklist
2510  return m_interface->getAmbientLight(vecNames, vecAmbient);
2511 }
2512 
2514 {
2515  if( !isBlackListed() )
2516  {
2517  m_interface->exec();
2518  }
2519 }
uint_t m_uAlsIntPeriod
ALS integration period (msec)
Definition: laeVL6180.h:695
#define VL6180X_AMBIENT_INT_T_MIN
minimum als int. period (msec)
Definition: laeVL6180.h:156
pthread_mutex_t m_mutex
mutex
Definition: laeVL6180.h:708
#define VL6180X_RANGE_MAX
maximum range (m)
Definition: laeVL6180.h:131
Multiplexed range sensors class.
Definition: laeVL6180.h:1211
#define VL6180X_RANGE_XTALK_MIN
minimum tof cross-talk
Definition: laeVL6180.h:140
void lock()
Lock the share resource.
Definition: laeVL6180.h:718
vl6180x_als_gain
Ambient Light Sensor gain value enumeration.
Definition: laeVL6180.h:247
virtual int getRange(const std::string &strKey, double &fRange)
Get the shadowed range measurement.
static const int AlsFreq
take an ambient measurement cycle rate
Definition: laeVL6180.h:1008
int cmdTuneAls(const std::string &strKey, double fAlsGain, uint_t uAlsIntPeriod)
Tune ambient light sensor command.
Definition: laeVL6180.cxx:2173
static const int NSenseErrorsThreshold
Consecutive sensed error count threshold.
Definition: laeVL6180.h:376
virtual ~LaeVL6180Mux()
Destructor.
Definition: laeVL6180.cxx:228
virtual void exec()
Execute task in one cycle to take measurements.
Definition: laeVL6180.h:869
int cmdGetTunes(const std::string &strKey, uint_t &uRangeOffset, uint_t &uRangeCrossTalk, double &fAlsGain, uint_t &uAlsIntPeriod)
Read exported tuning parameters command.
Definition: laeVL6180.cxx:2049
Laelaps tuning data class.
Definition: laeTune.h:566
actual ALS Gain of 40
Definition: laeVL6180.h:256
int writeDefaults()
Write defaults to sensor.
Definition: laeVL6180.cxx:328
#define VL6180X_RANGE_OFFSET_MAX
maximum tof offset
Definition: laeVL6180.h:137
virtual int reload(const laelaps::LaeTunes &tunes)
Reload configuration tuning parameters.
Definition: laeVL6180.cxx:1405
virtual int getSensorProps(const std::string &strKey, std::string &strRadiationType, double &fFoV, double &fBeamDir, double &fMin, double &fMax)
Get range sensor properties.
Definition: laeVL6180.cxx:2292
number of gain enum values
Definition: laeVL6180.h:257
virtual int getInterfaceVersion(uint_t &uVerMajor, uint_t &uVerMinor, uint_t &uFwVer)
Get interface version.
Definition: laeVL6180.h:809
Laelaps robotic mobile platform full description class.
Definition: laeDesc.h:451
void clearSensedData()
Clear sensed data.
Definition: laeVL6180.cxx:2388
virtual int write_read(uint_t addr, const byte_t wbuf[], size_t wlen, byte_t rbuf[], size_t rlen, long usec=0)
Perform a write/read transaction to/from an I2C slave endpoint device.
Definition: laeI2C.cxx:249
LaeRangeInterface * m_interface
the interface
Definition: laeVL6180.h:1732
double degToRad(double d)
Convert degrees to radians.
Definition: laeUtils.h:124
int m_nAlsCounter
when zero, make measurement
Definition: laeVL6180.h:1184
u16_t m_regAlsIntPeriod
ALS itegration period register.
Definition: laeVL6180.h:701
#define VL6180X_AMBIENT_INT_T_MAX
maximum als int. period (msec)
Definition: laeVL6180.h:157
virtual int reload(const laelaps::LaeTunes &tunes)
Reload configuration tuning parameters.
Definition: laeVL6180.cxx:2425
static double AlsGainAnalogTbl[GAIN_NumOf]
Ambient Light Sensor gain table.
Definition: laeVL6180.cxx:95
virtual int readSensorIdentity(const std::string &strKey, VL6180xIdentification &ident)
Read sensor&#39;s identification.
Definition: laeVL6180.h:960
#define LAE_VER_MINOR(ver)
Get version minor number from version.
Definition: laelaps.h:177
laelaps::LaeI2CMux & m_mux
I2C multiplexor.
Definition: laeVL6180.h:684
control register mask
Definition: laeI2CMux.h:100
int cmdGetAmbientLight()
Get ambient light measurments command.
Definition: laeVL6180.cxx:1995
int m_nAlsIndex
ambient light sensor index
Definition: laeVL6180.h:1183
double m_fAmbientLight
ambient light (lux)
Definition: laeVL6180.h:705
laelaps::LaeI2C & m_i2cBus
bound I2C bus instance
Definition: laeVL6180.h:988
virtual int configure(const laelaps::LaeDesc &desc)
Configure sensor array from product description.
Definition: laeVL6180.cxx:1651
virtual int getAmbientLight(const std::string &strKey, double &fAmbient)
Get an ambient light illuminance measurement.
Definition: laeVL6180.cxx:2259
double m_fDeadzone
sensor deadzone (m)
Definition: laeVL6180.h:286
virtual int getSensorProps(const std::string &strKey, std::string &strRadiationType, double &fFoV, double &fBeamDir, double &fMin, double &fMax)
Get range sensor properties.
Definition: laeVL6180.h:942
virtual int getInterfaceVersion(uint_t &uVerMajor, uint_t &uVerMinor, uint_t &uFwVer)
Get interface version.
Definition: laeVL6180.cxx:2393
virtual ~LaeVL6180MuxArray()
Destructor.
Definition: laeVL6180.cxx:1281
static vl6180x_als_gain gainAnalogToEnum(double fAlsGain)
Convert ambient light sensor analog gain to associated register value enum.
Definition: laeVL6180.cxx:1137
std::string m_strNameId
name identifier of sensor
Definition: laeVL6180.h:688
Container class to hold VL6180 time-of-flight sensor static information.
Definition: laeVL6180.h:280
virtual int cmdGetFwVersion(uint_t &uVerNum)
Get the firmware version command.
Definition: laeVL6180.cxx:1856
Laelaps PCA9548A I2C multiplexer switch interface.
int m_nChan
multiplexed channel number
Definition: laeVL6180.h:284
#define VL6180X_ADDR
I2C 7-bit address.
Definition: laeVL6180.h:124
#define VL6180X_AMBIENT_GAIN_MASK
als analog gain mask
Definition: laeVL6180.h:153
virtual int getSensorProps(const std::string &strKey, std::string &strRadiationType, double &fFoV, double &fBeamDir, double &fMin, double &fMax)
Get range sensor properties.
Definition: laeVL6180.cxx:1519
VL6180 Time of Flight Class.
Definition: laeVL6180.h:368
virtual int reload(const laelaps::LaeTunes &tunes)
Reload configuration tuning parameters.
Definition: laeVL6180.h:858
u32_t waitForSensorMeasurement(u32_t msecWait, byte_t bitDone)
Wait for sensor measurement to complete.
Definition: laeVL6180.cxx:844
int calibCrossTalk(int &nCrossTalk)
Calibrate cross-talk compensation.
Definition: laeVL6180.cxx:1037
byte_t m_regAlsGain
ambient light sensor gain register
Definition: laeVL6180.h:700
std::vector< double > m_vecRanges
measured distances (meters)
Definition: laeVL6180.h:1394
pthread_mutex_t m_mutex
mutex
Definition: laeVL6180.h:1398
virtual void exec()
Execute task in one cycle to take measurements.
Definition: laeVL6180.cxx:2513
int writeReg16(u16_t reg, u16_t val)
Write a 16-bit value to a register.
Definition: laeVL6180.cxx:1243
int m_nErrorCnt
consecutive error count
Definition: laeVL6180.h:690
void unlock()
Unlock the shared resource.
Definition: laeVL6180.h:1419
virtual int write(int chan, uint_t addr, byte_t buf[], size_t len)
Write from an I2C endpoint device.
Definition: laeI2CMux.cxx:106
virtual void exec()
Execute one cycle to take measurements.
Definition: laeVL6180.cxx:1847
double radToDeg(double r)
Convert radians to degrees.
Definition: laeUtils.h:136
std::string m_strDesc
short description
Definition: laeVL6180.h:287
Range sensors interface base class.
Definition: laeVL6180.h:779
int calibOffset(int &nOffsetPre, double &fAvgPre, int &nOffsetPost, double &fAvgPost)
Calibrate part-to-part offset.
Definition: laeVL6180.cxx:878
#define VL6180X_RANGE_XTALK_MAX
maximum tof cross-talk
Definition: laeVL6180.h:141
virtual int configure(const laelaps::LaeDesc &desc)
Configure sensor group from product description.
Definition: laeVL6180.cxx:2401
Laelaps Time-of-Flight sensors. The ToFs are used as a virtual bumper for close-in obstacle detection...
int initSensor(bool bForce=false)
Initialize sensor with recommended settings and defaults.
Definition: laeVL6180.cxx:232
void getVL6180Params(const std::string &strName, int &nTofOffset, int &nTofCrossTalk, double &fAlsGain, int &nAlsIntPeriod) const
Get VL6180 range sensor tune parameters.
Definition: laeTune.cxx:421
virtual int getInterfaceVersion(uint_t &uVerMajor, uint_t &uVerMinor, uint_t &uFwVer)
Get interface version.
Definition: laeVL6180.cxx:1621
LaeRangeSensorGroup(laelaps::LaeI2C &i2cBus)
Default constructor.
Definition: laeVL6180.cxx:2340
The <b><i>Laelaps</i></b> namespace encapsulates all <b><i>Laelaps</i></b> related constructs...
Definition: laeAlarms.h:64
Laelaps robotic base mobile platform description class interface.
int readId(struct VL6180xIdentification &id)
Read sensor identification.
Definition: laeVL6180.cxx:529
#define VL6180X_RANGE_NO_OBJ
no object detected
Definition: laeVL6180.h:133
void readShadowRegs()
Read shadows register values and update derived data.
Definition: laeVL6180.cxx:496
VecToFSensors m_vecToF
time of flight sensors
Definition: laeVL6180.h:1182
virtual void clearSensedData()
Clear sensed data.
Definition: laeVL6180.cxx:1302
virtual int getInterfaceVersion(uint_t &uVerMajor, uint_t &uVerMinor, uint_t &uFwVer)
Get interface version.
Definition: laeVL6180.cxx:1291
Laelaps common utilities.
virtual ~LaeRangeMuxSubproc()
Destructor.
Definition: laeVL6180.cxx:1616
int cap(int a, int min, int max)
Cap value within limits [min, max].
Definition: laeUtils.h:176
virtual void clearSensedData()
Clear sensed data.
Definition: laeVL6180.h:823
#define VL6180X_T_AUTO
auto-determine wait time
Definition: laeVL6180.h:169
void lock()
Lock the share resource.
Definition: laeVL6180.h:1408
virtual int readSensorIdentity(const std::string &strKey, VL6180xIdentification &ident)
Read sensor&#39;s identification.
Definition: laeVL6180.cxx:1543
actual ALS Gain of 1.01
Definition: laeVL6180.h:255
void unlock()
Unlock the shared resource.
Definition: laeVL6180.h:729
Laelaps built-in Time-of-Flight Multiplexer Arduino sub-processor interface.
virtual int readSensorIdentity(const std::string &strKey, VL6180xIdentification &ident)
Read sensor&#39;s identification.
Definition: laeVL6180.cxx:2451
Laelaps tuning.
double m_fBeamDir
center of beam direction(radians)
Definition: laeVL6180.h:285
int m_nChan
multiplexed channel number
Definition: laeVL6180.h:685
LaeVL6180MuxArray(laelaps::LaeI2C &i2cBus)
Initialization constructor.
Definition: laeVL6180.cxx:1274
virtual void whitelist()
White list range sensor group from robot sensors.
Definition: laeVL6180.cxx:2362
#define VL6180X_ERR_MEAS
error meassurement
Definition: laeVL6180.h:164
virtual int getAmbientLight(const std::string &strKey, double &fAmbient)
Get the shadowed ambient light illuminance measurement.
Definition: laeVL6180.cxx:1482
virtual int readSensorTunes(const std::string &strKey, uint_t &uRangeOffset, uint_t &uRangeCrossTalk, double &fAlsGain, uint_t &uAlsIntPeriod)
Read sensor&#39;s current tuning parameters.
Definition: laeVL6180.cxx:1559
virtual void blacklist()
Black list range sensor group from robot sensors.
Definition: laeVL6180.cxx:2356
virtual void exec()
Execute task in one cycle to take measurements.
Definition: laeVL6180.cxx:1412
static double gainEnumToAnalog(vl6180x_als_gain eAlsGain)
Convert ambient light sensor gain register value enum to analog gain.
Definition: laeVL6180.cxx:1125
double m_fAlsGain
ambient light sensor analog gain
Definition: laeVL6180.h:694
LaeRangeMuxSubproc(laelaps::LaeI2C &i2cBus, uint_t addr=laelaps::LaeI2CAddrToFMux)
Initialization constructor.
Definition: laeVL6180.cxx:1606
uint_t m_uFwVer
firmware version number
Definition: laeVL6180.h:1388
bool m_bBlackListed
sensor group [not] black listed.
Definition: laeVL6180.h:1733
int setInterface(uint_t uProdHwVer)
Set the interface, given the <b><i>Laelaps</i></b> hardware version.
Definition: laeVL6180.cxx:2368
#define VL6180X_RANGE_OFFSET_MIN
minimum tof offset
Definition: laeVL6180.h:136
int cmdTuneToFSensor(const std::string &strKey, uint_t uRangeOffset, uint_t uRangeCrossTalk)
Tune time-of-flight range sensor command.
Definition: laeVL6180.cxx:2112
virtual int readSensorTunes(const std::string &strKey, uint_t &uRangeOffset, uint_t &uRangeCrossTalk, double &fAlsGain, uint_t &uAlsIntPeriod)
Read sensor&#39;s current tuning parameters.
Definition: laeVL6180.cxx:2325
static const long TStd
standard wait write_read (usec)
Definition: laeVL6180.h:1217
#define LAE_VERSION(major, minor, revision)
Convert version triplet to integer equivalent.
Definition: laelaps.h:158
int readReg8(u16_t reg, byte_t &val)
Read an 8-bit value from a register.
Definition: laeVL6180.cxx:1173
int readReg16(u16_t reg, u16_t &val)
Read a 16-bit value from a register.
Definition: laeVL6180.cxx:1193
bool m_bBlackListed
sensor is [not] black listed
Definition: laeVL6180.h:691
virtual int readSensorTunes(const std::string &strKey, uint_t &uRangeOffset, uint_t &uRangeCrossTalk, double &fAlsGain, uint_t &uAlsIntPeriod)
Read sensor&#39;s current tuning parameters.
Definition: laeVL6180.h:978
int writeReg8(u16_t reg, byte_t val)
Write an 8-bit value to a register.
Definition: laeVL6180.cxx:1218
virtual int configure(const laelaps::LaeDesc &desc)
Configure sensor array from product description.
Definition: laeVL6180.h:834
#define LAE_VER_MAJOR(ver)
Get version major number from version.
Definition: laelaps.h:168
virtual int getRange(const std::string &strKey, double &fRange)
Get the shadowed range measurement.
Definition: laeVL6180.cxx:1445
virtual void clearSensedData()
Clear sensed data.
Definition: laeVL6180.cxx:1636
u32_t waitForSensorReady(u16_t regStatus, u32_t msecWait)
Wait for sensor to be ready.
Definition: laeVL6180.cxx:816
laelaps::LaeI2CMux m_mux
I2C multiplexor.
Definition: laeVL6180.h:1181
u16_t m_regRangeCrossTalk
range cross-talk register
Definition: laeVL6180.h:699
virtual int reload(const laelaps::LaeTunes &tunes)
Reload configuration tuning parameters.
Definition: laeVL6180.cxx:1840
virtual bool isBlackListed()
Test if range sensor group is black listed.
Definition: laeVL6180.h:1565
SensorInfoMap m_mapInfo
map of sensor properties by key
Definition: laeVL6180.h:1391
int cmdGetIdent(const std::string &strKey, VL6180xIdentification &ident)
Read sensor identification command.
Definition: laeVL6180.cxx:1882
virtual int getAmbientLight(const std::string &strKey, double &fAmbient)
Get the shadowed ambient light illuminance measurement.
virtual int getRange(const std::string &strKey, double &fRange)
Get a range measurement.
Definition: laeVL6180.h:881
laelaps::LaeI2C & m_i2cBus
bound I2C bus instance
Definition: laeVL6180.h:1731
uint_t m_addrSubProc
I2C sub-processor address.
Definition: laeVL6180.h:1387
#define VL6180X_RANGE_MIN
minimum range (m)
Definition: laeVL6180.h:130
std::vector< double > m_vecLux
measured ambient light (lux)
Definition: laeVL6180.h:1395
virtual int getSensorProps(const std::string &strKey, std::string &strRadiationType, double &fFoV, double &fBeamDir, double &fMin, double &fMax)
Get range sensor properties.
Definition: laeVL6180.cxx:2437
virtual int getAmbientLight(const std::string &strKey, double &fAmbient)
Get an ambient light illuminance measurement.
Definition: laeVL6180.h:909
double measureRange(u32_t msecWait=0xffff)
Measure the sensed target range.
Definition: laeVL6180.cxx:547
virtual int transact(int chan, uint_t addr, const byte_t wbuf[], size_t wlen, byte_t rbuf[], size_t rlen, long usec=0)
Perform a write/read transaction to/from an I2C slave endpoint device.
Definition: laeI2CMux.cxx:136
double measureAmbientLight(u32_t msecWait=0xffff)
Measure the sensed ambient light illuminance.
Definition: laeVL6180.cxx:696
int tune(uint_t uRangeOffset, uint_t uRangeCrossTalk, double fAlsGain, uint_t uAlsIntPeriod)
Tune sensor configuration.
Definition: laeVL6180.cxx:379
virtual int readSensorIdentity(const std::string &strKey, VL6180xIdentification &ident)
Read sensor&#39;s identification.
Definition: laeVL6180.cxx:2318
Laelaps real-time "database".
#define VL6180X_RANGE_FOV
field of view (degrees)
Definition: laeVL6180.h:132
double m_fRange
range (m)
Definition: laeVL6180.h:704
int cmdGetRanges()
Get range distance measurments command.
Definition: laeVL6180.cxx:1934
virtual int readSensorTunes(const std::string &strKey, uint_t &uRangeOffset, uint_t &uRangeCrossTalk, double &fAlsGain, uint_t &uAlsIntPeriod)
Read sensor&#39;s current tuning parameters.
Definition: laeVL6180.cxx:2466
#define VL6180X_FACTORY_DFT
use factory default
Definition: laeVL6180.h:170
VL6180 Time of Flight Array Class.
Definition: laeVL6180.h:1005
byte_t m_regRangeOffset
range part-to-part offset register
Definition: laeVL6180.h:698
Top-level package include file.
int outOfResetInit()
Initialize sensor out-of-reset.
Definition: laeVL6180.cxx:280
#define VL6180X_AMBIENT_INT_T_MASK
als integration period mask
Definition: laeVL6180.h:159
virtual int getRange(const std::string &strKey, double &fRange)
Get a range measurement.
Definition: laeVL6180.cxx:2225
static const int LAE_OK
not an error, success
Definition: laelaps.h:71
MapDescRangeSensor m_mapDescRangeSensor
range sensor descriptions
Definition: laeDesc.h:526
virtual int configure(const laelaps::LaeDesc &desc)
Configure sensor array from product description.
Definition: laeVL6180.cxx:1311