amiro-os / components / proximity / vcnl4020.cpp @ 22b85da1
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 = ®
|
||
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 */ |