DUDS
Distributed Update of Data from Something
APDS9301.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of the DUDS project. It is subject to the BSD-style
3  * license terms in the LICENSE file found in the top-level directory of this
4  * distribution and at https://github.com/jjackowski/duds/blob/master/LICENSE.
5  * No part of DUDS, including this file, may be copied, modified, propagated,
6  * or distributed except according to the terms contained in the LICENSE file.
7  *
8  * Copyright (C) 2018 Jeff Jackowski
9  */
13 
14 namespace duds { namespace hardware { namespace devices { namespace instruments {
15 
21 namespace APDS9301_internal {
22 
26 enum Regs {
40  RegInt = 6,
44  RegCh0 = 0xC,
48  RegCh1 = 0xE
49 };
50 
54 enum CmdFlags {
55  Cmd = 0x80,
56  ClearInt = 0x40,
57  Word = 0x20,
58  AddrMask = 0x0F
59 };
60 
65  HighGain = 0x10,
70  Intgrate = 0x08,
75 };
76 
80 struct PeriodData {
88  float scale;
92  int regval;
97  int maxcnt;
98 };
99 
103 static const std::map<float, PeriodData> IntegPeriodVals = {
104  { 13.7 * 0.001, { 101.0 / 13.7, 0, 5047 } },
105  { 101.0 * 0.001, { 1.0, 1, 37177 } },
106  { 402.0 * 0.001, { 101.0 / 402.0, 2, 65535 } }
107 };
108 
109 }
110 
111 using namespace APDS9301_internal;
112 
113 APDS9301::APDS9301(std::unique_ptr<duds::hardware::interface::Smbus> &c) :
114 com(std::move(c)), actualPeriod(-1) {
115  try {
116  // suspend operation
117  suspend();
118  // clear and disable interrupts
119  com->transmitByte(Cmd | ClearInt | RegInt, 0);
120  } catch (...) {
121  // return the communicator if exception is thrown
122  c = std::move(com);
123  throw;
124  }
125 }
126 
128  // suspend operation
129  com->transmitByte(Cmd | RegControl, 0);
130  // don't bother to check result; can't be throwing exceptions
131  // from destructors
132 }
133 
134 void APDS9301::init(float integration, bool hg) {
135  std::map<float, PeriodData>::const_iterator iter =
136  IntegPeriodVals.upper_bound(integration);
137  if (iter == IntegPeriodVals.cend()) {
139  }
140  actualPeriod = iter->first;
141  integTime = iter->second.regval;
142  scale = iter->second.scale;
143  // documentation specifies values for high gain operation
144  if (!(hGain = hg)) {
145  // account for low gain
146  scale *= 1.0f / 16.0f;
147  }
148  com->transmitByte(Cmd | RegConfig, (hGain << 4) | integTime);
149 }
150 
151 void APDS9301::startOrStop(int val) {
152  // start or stop operation
153  com->transmitByte(Cmd | RegControl, val);
154  // read back power value
155  if (com->receiveByte(Cmd | RegControl) != val) {
156  // wrong response
159  );
160  }
161 }
162 
164  startOrStop(0);
165 }
166 
168  if (actualPeriod < 0) {
169  // not yet initialized
171  }
172  startOrStop(3);
173 }
174 
176  // get input
177  broad = com->receiveWord(Cmd | Word | RegCh0);
178  ir = com->receiveWord(Cmd | Word | RegCh1);
179 }
180 
182  std::map<float, PeriodData>::const_iterator iter =
184  assert(iter != IntegPeriodVals.end());
185  return duds::data::Quantity(
186  (double)iter->second.maxcnt * scale * 0.275,
189  )
190  );
191 }
192 
195  std::map<float, PeriodData>::const_iterator iter =
197  assert(iter != IntegPeriodVals.end());
198  double val;
199  if (iter->second.maxcnt <= broad) {
200  val = std::numeric_limits<double>::infinity();
201  } else {
202  val = (double)broad;
203  }
204  // datasheet uses uW/cm2, which is (0.01)W/m2
205  // this channel has 27.5 counts per uW/cm2 for red (640um) light over 101ms
206  return duds::data::Quantity(
207  val * scale * 0.275,
210  )
211  );
212 }
213 
215  // datasheet uses uW/cm2, which is (0.01)W/m2
216  // this channel has 5.5 counts per uW/cm2 for IR light over 101ms
217  return duds::data::Quantity(
218  (double)ir * scale * 0.055,
221  )
222  );
223 }
224 
226  // Implementation of an algorithim in the documentation that approximates
227  // the illuminance "for the light source specified", which was subsequently
228  // not specified. At least it wasn't in the file I got from a link on
229  // Sparkfun's website. It does show test results with two light sources,
230  // but that isn't singular.
231  double ch0 = (double)broad;
232  double ch1 = (double)ir;
233  double chr = ch1 / ch0; // channel ratio
234  double result;
235  if (chr <= 0.5) {
236  result = 0.0304 * ch0 - 0.062 * ch0 * std::pow(chr, 1.4);
237  } else if (chr <= 0.61) {
238  result = 0.0224 * ch0 - 0.031 * ch1;
239  } else if (chr <= 0.8) {
240  result = 0.0128 * ch0 - 0.0153 * ch1;
241  } else if (chr <= 1.3) {
242  result = 0.00146 * ch0 - 0.00112 * ch1;
243  } else {
244  result = 0;
245  }
246  if (result != 0) {
247  // Scale to account for periods other than 402ms and for gain. The scale
248  // value is made to scale integration to 102ms, and includes gain, so
249  // adjust integration only with a constant factor.
250  result *= scale * (402.0 / 101.0);
251  }
252  return duds::data::Quantity(
253  result * scale,
255  );
256 }
257 
258 } } } }
A container for a value and a unit to better describe the value.
Definition: Quantity.hpp:37
constexpr Unit Meter(DUDS_UNIT_VALUE(0, 0, 0, 0, 1, 0, 0, 0, 0))
duds::data::Quantity illuminance() const
Computes a highly approximate value for illuminance based on the broad spectrum and IR samples using ...
Definition: APDS9301.cpp:225
int maxcnt
The maximum value the device will report for the sampling period.
Definition: APDS9301.cpp:97
void sample()
The device will update samples after it has completed integration.
Definition: APDS9301.cpp:175
Channel 0: sensitive to full visible and near IR spectrum.
Definition: APDS9301.cpp:44
Channel 1: sensitive to near IR spectrum.
Definition: APDS9301.cpp:48
Header for ConversationExtractor; includes all other conversation related header files.
void suspend()
Suspends operation by putting the device into a low-power mode.
Definition: APDS9301.cpp:163
duds::data::Quantity irradianceIr() const
Irradiance in infrared light.
Definition: APDS9301.cpp:214
float scale
A scalar applied to change the irradiance result based on the sampling period.
Definition: APDS9301.cpp:88
STL namespace.
move_impl move(unsigned int c, unsigned int r)
Display stream manipulator that moves the display cursor to the given location.
std::unique_ptr< duds::hardware::interface::Smbus > com
The SMBus communication interface.
Definition: APDS9301.hpp:40
constexpr Unit Lux(DUDS_UNIT_VALUE(0, 1, 0, 0, -2, 0, 0, 0, 1))
unsigned int hGain
High gain (16x) flag.
Definition: APDS9301.hpp:59
An attempt was made to use a device prior to running a required initialization step.
duds::data::Quantity irradiance() const
Broad spectrum irradiance.
Definition: APDS9301.cpp:193
Set to start manual integration, and clear to stop.
Definition: APDS9301.cpp:70
constexpr Unit Watt(DUDS_UNIT_VALUE(0, 0, 0, 1, 2, 0, -3, 0, 0))
int regval
The value given to the device to select the sampling period.
Definition: APDS9301.cpp:92
Information on a particular sampling rate.
Definition: APDS9301.cpp:80
void resume()
Resumes operation after a call to suspend().
Definition: APDS9301.cpp:167
An invalid integration time was specified.
Definition: APDS9301.hpp:26
boost::error_info< struct Info_smbusdevaddr, int > SmbusDeviceAddr
Provides the device (slave) address along with an error.
Definition: SmbusErrors.hpp:80
What the documentation calls timing register; really a general configuration register.
Definition: APDS9301.cpp:36
float actualPeriod
Configured integration time.
Definition: APDS9301.hpp:44
std::uint16_t broad
The values supplied by the device.
Definition: APDS9301.hpp:54
void startOrStop(int val)
Writes a value to the control register, reads it back, and checks for equality.
Definition: APDS9301.cpp:151
An attempt was made to use a device that seems to exist, but the responding device is not the type th...
Interrupt control; set to zero if not using.
Definition: APDS9301.cpp:40
float scale
Multiplier applied to the sample results to account for different integration times and gain setting ...
Definition: APDS9301.hpp:50
CmdFlags
The flags refered to as commands in the documentation.
Definition: APDS9301.cpp:54
APDS9301(std::unique_ptr< duds::hardware::interface::Smbus > &c)
Attempts to identify the device, then performs a reset.
Definition: APDS9301.cpp:113
static const std::map< float, PeriodData > IntegPeriodVals
Integration period values.
Definition: APDS9301.cpp:103
Spot for the address of register to read or write.
Definition: APDS9301.cpp:58
duds::data::Quantity maxIrradiance() const
The maximum possible irradiance value that the device can report based on its configuration set by th...
Definition: APDS9301.cpp:181
unsigned int integTime
Integration time value used in device configuration register.
Definition: APDS9301.hpp:63
void init(float integration, bool hGain)
Configures the device.
Definition: APDS9301.cpp:134
#define DUDS_THROW_EXCEPTION(x)
Works like BOOST_THROW_EXCEPTION, but includes a stack trace if DUDS_ERRORS_VERBOSE is defined...
Definition: Errors.hpp:48
~APDS9301()
Attempts to suspend the device&#39;s operation.
Definition: APDS9301.cpp:127