Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (5.007 KB)

1
#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 */