Statistics
| Branch: | Tag: | Revision:

amiro-os / components / proximity / vcnl4020.cpp @ 1b3adcdd

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