Statistics
| Branch: | Tag: | Revision:

amiro-os / components / proximity / vcnl4020.cpp @ 58fe0e0b

History | View | Annotate | Download (5.007 KB)

1 58fe0e0b Thomas Schöpping
#include <ch.hpp>
2
#include <hal.h>
3
#include <chdebug.h>
4
#include <chprintf.h>
5
6
#include <amiro/bus/i2c/I2CParams.hpp>
7
#include <amiro/bus/i2c/I2CDriver.hpp>
8
#include <amiro/proximity/vcnl4020.hpp>
9
10
using namespace chibios_rt;
11
12
namespace amiro {
13
14
VCNL4020::
15
~VCNL4020() {
16
17
}
18
19
VCNL4020::
20
VCNL4020(I2CDriver *driver, const VCNL4020Config *config) :
21
  BaseStaticThread<256>(),
22
  driver(driver),
23
  config(config),
24
  ambient(0x0000u),
25
  proximity(0x0000u),
26
  proximityOffset(0x0000u) {
27
28
  this->tx_params.addr = VCNL4020::SLA;
29
30
}
31
32
uint16_t
33
VCNL4020::
34
getAmbientLight() {
35
36
  return this->ambient;
37
}
38
39
void
40
VCNL4020::
41
setProximityOffset(uint16_t offset) {
42
43
  this->proximityOffset = offset;
44
}
45
46
uint16_t
47
VCNL4020::
48
getProximityOffset() {
49
50
  return this->proximityOffset;
51
}
52
53
EvtSource*
54
VCNL4020::
55
getEventSource() {
56
57
  return &this->eventSource;
58
}
59
60
uint16_t
61
VCNL4020::
62
getProximity() {
63
64
  return this->proximity;
65
}
66
67
uint16_t
68
VCNL4020::
69
getProximityScaledWoOffset() {
70
71
  if (this->proximity <= this->proximityOffset)
72
    return 0;
73
74
  // Scale factor for the offset-less proximity value, so that we can reach full-scale
75
  const float scaleFactor = float(0xFFFFu) / float((0xFFFFu - this->proximityOffset));
76
77
  return uint16_t(float(this->proximity - this->proximityOffset) * scaleFactor);
78
}
79
80
msg_t
81
VCNL4020::
82
main(void) {
83
84
  I2CDriver *drv = this->driver;
85
  msg_t res;
86
87
  this->setName("Vcnl4020");
88
89
  drv->acquireBus();
90
91
  /* exit if writing configuration fails */
92
  res = this->writeIRConf();
93
94
  drv->releaseBus();
95
96
  if (res)
97
    return RDY_RESET;
98
99
  //TODO Read calibration from eeprom
100
101
  while (!this->shouldTerminate()) {
102
103
    drv->acquireBus();
104
105
    this->readIntensities();
106
    drv->releaseBus();
107
108
    this->eventSource.broadcastFlags(0);
109
110
    this->waitAnyEventTimeout(ALL_EVENTS, MS2ST(200));
111
  }
112
113
  return RDY_OK;
114
}
115
116
msg_t
117
VCNL4020::
118
writeIRConf() {
119
120
  msg_t res;
121
  const VCNL4020Config *cfg = this->config;
122
123
  uint8_t buffer[4];
124
  this->tx_params.txbuf = buffer;
125
  this->tx_params.txbytes = 4;
126
  this->tx_params.rxbytes = 0;
127
128
  buffer[0] = offsetof(VCNL4020::registers, proximity_rate);
129
  buffer[1] = cfg->proximity_rate;
130
  buffer[2] = cfg->ir_led_current_mA > 200 ? 20u : cfg->ir_led_current_mA / 10u;
131
  buffer[3] = cfg->ambient_parameter;
132
133
  res = this->driver->masterTransmit(&this->tx_params);
134
135
  buffer[0] = offsetof(VCNL4020::registers, command);
136
  buffer[1] = cfg->command;
137
138
  this->tx_params.txbytes = 2;
139
140
  if (!res)
141
    res = this->driver->masterTransmit(&this->tx_params);
142
143
  return res;
144
}
145
146
msg_t
147
VCNL4020::
148
readIntensities() {
149
150
  msg_t res;
151
  uint8_t buffer[4];
152
  uint8_t reg = offsetof(VCNL4020::registers, ambient_result);
153
  this->tx_params.txbuf = &reg;
154
  this->tx_params.txbytes = 1;
155
  this->tx_params.rxbuf = buffer;
156
  this->tx_params.rxbytes = 4;
157
158
  res = this->driver->masterTransmit(&this->tx_params);
159
160
  if (!res) {
161
162
    /* update internal values */
163
    this->ambient = (buffer[0] << 8) | buffer[1];
164
    this->proximity = (buffer[2] << 8) | buffer[3];
165
166
  }
167
168
  return res;
169
170
}
171
172
uint8_t
173
VCNL4020::
174
getCheck(void) {
175
176
  int8_t resTx;
177
  uint8_t rxBuffer[2]; /** This is a bug workaround: 1 byte is impossible to read on STM32F1*/
178
  const uint8_t txBuffer = uint8_t(offsetof(VCNL4020::registers, revision));
179
180
  // Use own datastructure, so that there is now faulty
181
  // behaviour with the other threads using it
182
  I2CTxParams tx_params = this->tx_params;
183
  tx_params.txbuf = &txBuffer;
184
  tx_params.txbytes = 1;
185
  tx_params.rxbytes = 2; /** This is a bug workaround: 1 byte is impossible to read on STM32F1*/
186
  tx_params.rxbuf = rxBuffer;
187
188
  // Read the data
189
  resTx = this->driver->masterTransmit(&tx_params);
190
  // Failed to transmit
191
  if (resTx != RDY_OK || VCNL4020::PRODUCT_ID_REVISION != rxBuffer[0]) {
192
    return VCNL4020::CHECK_FAIL;
193
  } else {
194
    return VCNL4020::CHECK_OK;
195
  }
196
197
}
198
199
uint8_t
200
VCNL4020::
201
calibrate() {
202
203
  uint16_t proximityFloorMeanValue;
204
205
  // Get the offset
206
  msg_t res = calibrateOffset(proximityFloorMeanValue);
207
  if (res == CALIB_OK) {
208
    this->proximityOffset = proximityFloorMeanValue;
209
    //TODO Write value to eeprom
210
    return res;
211
  } else {
212
    return res;
213
  }
214
215
}
216
217
uint8_t
218
VCNL4020::
219
calibrateOffset(uint16_t &proximityFloorMeanValue) {
220
221
  uint32_t tmpProximityFloorMeanValue;
222
223
  // Register an event listener, to receive updates
224
  chibios_rt::EvtListener eventTimerEvtListener;
225
  chibios_rt::EvtSource *vcnlEvtSource;
226
  vcnlEvtSource = reinterpret_cast<EvtSource *>(this->getEventSource());
227
  vcnlEvtSource->registerOne(&eventTimerEvtListener,0);
228
229
  // Get the first values
230
  tmpProximityFloorMeanValue = this->getProximity();
231
232
  // Get the others with a floating mean
233
  const uint32_t maxValues = 20;
234
  for (uint32_t idxMean = 2; idxMean <= maxValues; ++idxMean) {
235
    this->waitOneEvent(ALL_EVENTS); /* Wait for a new update */
236
    tmpProximityFloorMeanValue = (((idxMean-1) * tmpProximityFloorMeanValue) + uint32_t(this->getProximity())) / idxMean;
237
  }
238
239
  vcnlEvtSource->unregister(&eventTimerEvtListener);
240
241
  // Cast the calculated offset to the temporary member variable
242
  proximityFloorMeanValue = uint16_t(tmpProximityFloorMeanValue);
243
244
  return CALIB_OK;
245
}
246
247
} /* amiro */