Statistics
| Branch: | Tag: | Revision:

amiro-os / components / proximity / vcnl4020.cpp @ 81b48c66

History | View | Annotate | Download (5.043 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
#include <amiro/Constants.h>
10

    
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
    this->waitAnyEventTimeout(ALL_EVENTS, CAN::UPDATE_PERIOD);
112
  }
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 */