1 /*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <stdlib.h>
18 #include <string.h>
19 #include <float.h>
20
21 #include <eventnums.h>
22 #include <gpio.h>
23 #include <timer.h>
24 #include <sensors.h>
25 #include <heap.h>
26 #include <hostIntf.h>
27 #include <isr.h>
28 #include <i2c.h>
29 #include <nanohubPacket.h>
30 #include <sensors.h>
31 #include <seos.h>
32
33 #include <plat/exti.h>
34 #include <plat/gpio.h>
35 #include <plat/syscfg.h>
36 #include <variant/variant.h>
37
38 #define AMS_TMD4903_APP_ID APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 12)
39 #define AMS_TMD4903_APP_VERSION 14
40
41 #ifndef PROX_INT_PIN
42 #error "PROX_INT_PIN is not defined; please define in variant.h"
43 #endif
44
45 #ifndef PROX_IRQ
46 #error "PROX_IRQ is not defined; please define in variant.h"
47 #endif
48
49 #define I2C_BUS_ID 0
50 #define I2C_SPEED 400000
51 #define I2C_ADDR 0x39
52
53 #define AMS_TMD4903_REG_ENABLE 0x80
54 #define AMS_TMD4903_REG_ATIME 0x81
55 #define AMS_TMD4903_REG_PTIME 0x82
56 #define AMS_TMD4903_REG_WTIME 0x83
57 #define AMS_TMD4903_REG_AILTL 0x84
58 #define AMS_TMD4903_REG_AILTH 0x85
59 #define AMS_TMD4903_REG_AIHTL 0x86
60 #define AMS_TMD4903_REG_AIHTH 0x87
61 #define AMS_TMD4903_REG_PILTL 0x88
62 #define AMS_TMD4903_REG_PILTH 0x89
63 #define AMS_TMD4903_REG_PIHTL 0x8a
64 #define AMS_TMD4903_REG_PIHTH 0x8b
65 #define AMS_TMD4903_REG_PERS 0x8c
66 #define AMS_TMD4903_REG_CFG0 0x8d
67 #define AMS_TMD4903_REG_PGCFG0 0x8e
68 #define AMS_TMD4903_REG_PGCFG1 0x8f
69 #define AMS_TMD4903_REG_CFG1 0x90
70 #define AMS_TMD4903_REG_REVID 0x91
71 #define AMS_TMD4903_REG_ID 0x92
72 #define AMS_TMD4903_REG_STATUS 0x93
73 #define AMS_TMD4903_REG_CDATAL 0x94
74 #define AMS_TMD4903_REG_CDATAH 0x95
75 #define AMS_TMD4903_REG_RDATAL 0x96
76 #define AMS_TMD4903_REG_RDATAH 0x97
77 #define AMS_TMD4903_REG_GDATAL 0x98
78 #define AMS_TMD4903_REG_GDATAH 0x99
79 #define AMS_TMD4903_REG_BDATAL 0x9A
80 #define AMS_TMD4903_REG_BDATAH 0x9B
81 #define AMS_TMD4903_REG_PDATAL 0x9C
82 #define AMS_TMD4903_REG_PDATAH 0x9D
83 #define AMS_TMD4903_REG_STATUS2 0x9E
84 #define AMS_TMD4903_REG_CFG4 0xAC
85 #define AMS_TMD4903_REG_OFFSETNL 0xC0
86 #define AMS_TMD4903_REG_OFFSETNH 0xC1
87 #define AMS_TMD4903_REG_OFFSETSL 0xC2
88 #define AMS_TMD4903_REG_OFFSETSH 0xC3
89 #define AMS_TMD4903_REG_OFFSETWL 0xC4
90 #define AMS_TMD4903_REG_OFFSETWH 0xC5
91 #define AMS_TMD4903_REG_OFFSETEL 0xC6
92 #define AMS_TMD4903_REG_OFFSETEH 0xC7
93 #define AMS_TMD4903_REG_CALIB 0xD7
94 #define AMS_TMD4903_REG_INTENAB 0xDD
95 #define AMS_TMD4903_REG_INTCLEAR 0xDE
96
97 #define AMS_TMD4903_ID 0xB8
98
99 #define AMS_TMD4903_DEFAULT_RATE SENSOR_HZ(5)
100
101 #define AMS_TMD4903_ATIME_SETTING 0xdc
102 #define AMS_TMD4903_ATIME_MS ((256 - AMS_TMD4903_ATIME_SETTING) * 2.78) // in milliseconds
103 #define AMS_TMD4903_MAX_ALS_CHANNEL_COUNT ((256 - AMS_TMD4903_ATIME_SETTING) * 1024) // in ALS data units
104 #define AMS_TMD4903_ALS_MAX_REPORT_VALUE 150000.0f // in lux
105 #define AMS_TMD4903_PTIME_SETTING 0x11
106 #define AMS_TMD4903_PGCFG0_SETTING 0x41 // pulse length: 8 us, pulse count: 2
107 #define AMS_TMD4903_PGCFG1_SETTING 0x04 // gain: 1x, drive: 50 mA
108
109 #define AMS_TMD4903_ALS_DEBOUNCE_SAMPLES 5
110 #define AMS_TMD4903_ALS_GAIN_4X_THOLD 4000.0f
111 #define AMS_TMD4903_ALS_GAIN_16X_THOLD 1000.0f
112 #define AMS_TMD4903_ALS_GAIN_64X_THOLD 250.0f
113
114 /* AMS_TMD4903_REG_ENABLE */
115 #define PROX_INT_ENABLE_BIT (1 << 5)
116 #define ALS_INT_ENABLE_BIT (1 << 4)
117 #define PROX_ENABLE_BIT (1 << 2)
118 #define ALS_ENABLE_BIT (1 << 1)
119 #define POWER_ON_BIT (1 << 0)
120
121 /* AMS_TMD4903_REG_INTENAB */
122 #define CAL_INT_ENABLE_BIT (1 << 1)
123
124 #define AMS_TMD4903_REPORT_NEAR_VALUE 0.0f // centimeters
125 #define AMS_TMD4903_REPORT_FAR_VALUE 5.0f // centimeters
126 #define AMS_TMD4903_PROX_THRESHOLD_HIGH 350 // value in PS_DATA
127 #define AMS_TMD4903_PROX_THRESHOLD_LOW 150 // value in PS_DATA
128
129 #define AMS_TMD4903_ALS_INVALID UINT32_MAX
130
131 #define AMS_TMD4903_ALS_TIMER_DELAY 200000000ULL
132
133 #define AMS_TMD4903_MAX_PENDING_I2C_REQUESTS 8
134 #define AMS_TMD4903_MAX_I2C_TRANSFER_SIZE 18
135
136 #define MIN2(a,b) (((a) < (b)) ? (a) : (b))
137 #define MAX2(a,b) (((a) > (b)) ? (a) : (b))
138
139 // NOTE: Define this to be 1 to enable streaming of proximity samples instead of
140 // using the interrupt
141 #define PROX_STREAMING 0
142
143 #define INFO_PRINT(fmt, ...) do { \
144 osLog(LOG_INFO, "%s " fmt, "[TMD4903]", ##__VA_ARGS__); \
145 } while (0);
146
147 #define DEBUG_PRINT(fmt, ...) do { \
148 if (enable_debug) { \
149 INFO_PRINT(fmt, ##__VA_ARGS__); \
150 } \
151 } while (0);
152
153 static const bool enable_debug = 0;
154
155 /* Private driver events */
156 enum SensorEvents
157 {
158 EVT_SENSOR_I2C = EVT_APP_START + 1,
159 EVT_SENSOR_ALS_TIMER,
160 EVT_SENSOR_ALS_INTERRUPT,
161 EVT_SENSOR_PROX_INTERRUPT,
162 };
163
164 /* I2C state machine */
165 enum SensorState
166 {
167 SENSOR_STATE_VERIFY_ID,
168 SENSOR_STATE_INIT_0,
169 SENSOR_STATE_INIT_1,
170 SENSOR_STATE_INIT_2,
171 SENSOR_STATE_FINISH_INIT,
172 SENSOR_STATE_START_PROX_CALIBRATION_0,
173 SENSOR_STATE_START_PROX_CALIBRATION_1,
174 SENSOR_STATE_FINISH_PROX_CALIBRATION_0,
175 SENSOR_STATE_FINISH_PROX_CALIBRATION_1,
176 SENSOR_STATE_POLL_STATUS,
177 SENSOR_STATE_ENABLING_ALS,
178 SENSOR_STATE_ENABLING_PROX,
179 SENSOR_STATE_DISABLING_ALS,
180 SENSOR_STATE_DISABLING_ALS_2,
181 SENSOR_STATE_DISABLING_PROX,
182 SENSOR_STATE_DISABLING_PROX_2,
183 SENSOR_STATE_DISABLING_PROX_3,
184 SENSOR_STATE_ALS_CHANGING_GAIN,
185 SENSOR_STATE_ALS_SAMPLING,
186 SENSOR_STATE_PROX_SAMPLING,
187 SENSOR_STATE_PROX_TRANSITION_0,
188 SENSOR_STATE_IDLE,
189 };
190
191 enum ProxState
192 {
193 PROX_STATE_INIT,
194 PROX_STATE_NEAR,
195 PROX_STATE_FAR,
196 };
197
198 enum ProxOffsetIndex
199 {
200 PROX_OFFSET_NORTH = 0,
201 PROX_OFFSET_SOUTH = 1,
202 PROX_OFFSET_WEST = 2,
203 PROX_OFFSET_EAST = 3
204 };
205
206 enum AlsGain
207 {
208 ALS_GAIN_1X = 0,
209 ALS_GAIN_4X = 1,
210 ALS_GAIN_16X = 2,
211 ALS_GAIN_64X = 3
212 };
213
214 struct AlsProxTransfer
215 {
216 size_t tx;
217 size_t rx;
218 int err;
219 uint8_t txrxBuf[AMS_TMD4903_MAX_I2C_TRANSFER_SIZE];
220 uint8_t state;
221 bool inUse;
222 };
223
224 struct SensorData
225 {
226 struct Gpio *pin;
227 struct ChainedIsr isr;
228
229 uint32_t tid;
230
231 uint32_t alsHandle;
232 uint32_t proxHandle;
233 uint32_t alsTimerHandle;
234
235 float alsOffset;
236
237 union EmbeddedDataPoint lastAlsSample;
238
239 struct AlsProxTransfer transfers[AMS_TMD4903_MAX_PENDING_I2C_REQUESTS];
240
241 uint8_t lastProxState; // enum ProxState
242
243 uint8_t alsGain;
244 uint8_t nextAlsGain;
245 uint8_t alsDebounceSamples;
246
247 bool alsOn;
248 bool proxOn;
249 bool alsCalibrating;
250 bool proxCalibrating;
251 bool proxDirectMode;
252 bool alsChangingGain;
253 bool alsSkipSample;
254 };
255
256 static struct SensorData mTask;
257
258 struct AlsCalibrationData {
259 struct HostHubRawPacket header;
260 struct SensorAppEventHeader data_header;
261 float offset;
262 } __attribute__((packed));
263
264 struct ProxCalibrationData {
265 struct HostHubRawPacket header;
266 struct SensorAppEventHeader data_header;
267 int32_t offsets[4];
268 } __attribute__((packed));
269
270 static const uint32_t supportedRates[] =
271 {
272 SENSOR_HZ(5),
273 SENSOR_RATE_ONCHANGE,
274 0,
275 };
276
277 static void i2cCallback(void *cookie, size_t tx, size_t rx, int err);
278
279 /*
280 * Helper functions
281 */
282
283 // Allocate a buffer and mark it as in use with the given state, or return NULL
284 // if no buffers available. Must *not* be called from interrupt context.
allocXfer(uint8_t state)285 static struct AlsProxTransfer *allocXfer(uint8_t state)
286 {
287 size_t i;
288
289 for (i = 0; i < ARRAY_SIZE(mTask.transfers); i++) {
290 if (!mTask.transfers[i].inUse) {
291 mTask.transfers[i].inUse = true;
292 mTask.transfers[i].state = state;
293 return &mTask.transfers[i];
294 }
295 }
296
297 INFO_PRINT("Ran out of i2c buffers!");
298 return NULL;
299 }
300
301 // Helper function to write a one byte register. Returns true if we got a
302 // successful return value from i2cMasterTx().
writeRegister(uint8_t reg,uint8_t value,uint8_t state)303 static bool writeRegister(uint8_t reg, uint8_t value, uint8_t state)
304 {
305 struct AlsProxTransfer *xfer = allocXfer(state);
306 int ret = -1;
307
308 if (xfer != NULL) {
309 xfer->txrxBuf[0] = reg;
310 xfer->txrxBuf[1] = value;
311 ret = i2cMasterTx(I2C_BUS_ID, I2C_ADDR, xfer->txrxBuf, 2, i2cCallback, xfer);
312 }
313
314 return (ret == 0);
315 }
316
proxIsr(struct ChainedIsr * localIsr)317 static bool proxIsr(struct ChainedIsr *localIsr)
318 {
319 struct SensorData *data = container_of(localIsr, struct SensorData, isr);
320 uint8_t lastProxState = data->lastProxState;
321 union EmbeddedDataPoint sample;
322 bool pinState;
323
324 if (!extiIsPendingGpio(data->pin)) {
325 return false;
326 }
327
328 pinState = gpioGet(data->pin);
329
330 if (data->proxOn) {
331 #if PROX_STREAMING
332 (void)sample;
333 (void)pinState;
334 (void)lastProxState;
335 if (!pinState)
336 osEnqueuePrivateEvt(EVT_SENSOR_PROX_INTERRUPT, NULL, NULL, mTask.tid);
337 #else
338 if (data->proxDirectMode) {
339 sample.fdata = (pinState) ? AMS_TMD4903_REPORT_FAR_VALUE : AMS_TMD4903_REPORT_NEAR_VALUE;
340 data->lastProxState = (pinState) ? PROX_STATE_FAR : PROX_STATE_NEAR;
341 if (data->lastProxState != lastProxState)
342 osEnqueueEvt(sensorGetMyEventType(SENS_TYPE_PROX), sample.vptr, NULL);
343 } else {
344 osEnqueuePrivateEvt(EVT_SENSOR_PROX_INTERRUPT, NULL, NULL, mTask.tid);
345 }
346 #endif
347 } else if (data->alsOn && data->alsCalibrating && !pinState) {
348 osEnqueuePrivateEvt(EVT_SENSOR_ALS_INTERRUPT, NULL, NULL, mTask.tid);
349 }
350
351 extiClearPendingGpio(data->pin);
352 return true;
353 }
354
enableInterrupt(struct Gpio * pin,struct ChainedIsr * isr,enum ExtiTrigger trigger)355 static bool enableInterrupt(struct Gpio *pin, struct ChainedIsr *isr, enum ExtiTrigger trigger)
356 {
357 extiEnableIntGpio(pin, trigger);
358 extiChainIsr(PROX_IRQ, isr);
359 return true;
360 }
361
disableInterrupt(struct Gpio * pin,struct ChainedIsr * isr)362 static bool disableInterrupt(struct Gpio *pin, struct ChainedIsr *isr)
363 {
364 extiUnchainIsr(PROX_IRQ, isr);
365 extiDisableIntGpio(pin);
366 return true;
367 }
368
i2cCallback(void * cookie,size_t tx,size_t rx,int err)369 static void i2cCallback(void *cookie, size_t tx, size_t rx, int err)
370 {
371 struct AlsProxTransfer *xfer = cookie;
372
373 xfer->tx = tx;
374 xfer->rx = rx;
375 xfer->err = err;
376
377 osEnqueuePrivateEvt(EVT_SENSOR_I2C, cookie, NULL, mTask.tid);
378 if (err != 0)
379 INFO_PRINT("i2c error (tx: %d, rx: %d, err: %d)\n", tx, rx, err);
380 }
381
alsTimerCallback(uint32_t timerId,void * cookie)382 static void alsTimerCallback(uint32_t timerId, void *cookie)
383 {
384 osEnqueuePrivateEvt(EVT_SENSOR_ALS_TIMER, cookie, NULL, mTask.tid);
385 }
386
getAlsGainFromSetting(uint8_t gainSetting)387 static inline uint32_t getAlsGainFromSetting(uint8_t gainSetting)
388 {
389 return 0x1 << (2 * gainSetting);
390 }
391
getLuxFromAlsData(uint16_t c,uint16_t r,uint16_t g,uint16_t b)392 static float getLuxFromAlsData(uint16_t c, uint16_t r, uint16_t g, uint16_t b)
393 {
394 float lux;
395
396 // check for channel saturation
397 if (c >= AMS_TMD4903_MAX_ALS_CHANNEL_COUNT || r >= AMS_TMD4903_MAX_ALS_CHANNEL_COUNT ||
398 g >= AMS_TMD4903_MAX_ALS_CHANNEL_COUNT || b >= AMS_TMD4903_MAX_ALS_CHANNEL_COUNT)
399 return AMS_TMD4903_ALS_MAX_REPORT_VALUE;
400
401 lux = (ALS_GA_FACTOR *
402 ((c * ALS_C_COEFF) + (r * ALS_R_COEFF) + (g * ALS_G_COEFF) + (b * ALS_B_COEFF)) /
403 (AMS_TMD4903_ATIME_MS * getAlsGainFromSetting(mTask.alsGain))) * mTask.alsOffset;
404
405 return MIN2(MAX2(0.0f, lux), AMS_TMD4903_ALS_MAX_REPORT_VALUE);
406 }
407
checkForAlsAutoGain(float sample)408 static bool checkForAlsAutoGain(float sample)
409 {
410 if ((mTask.alsGain != ALS_GAIN_64X) && (sample < AMS_TMD4903_ALS_GAIN_64X_THOLD)) {
411 mTask.alsDebounceSamples = (mTask.nextAlsGain == ALS_GAIN_64X) ? (mTask.alsDebounceSamples + 1) : 1;
412 mTask.nextAlsGain = ALS_GAIN_64X;
413 } else if ((mTask.alsGain != ALS_GAIN_16X) && (sample >= AMS_TMD4903_ALS_GAIN_64X_THOLD) && (sample < AMS_TMD4903_ALS_GAIN_16X_THOLD)) {
414 mTask.alsDebounceSamples = (mTask.nextAlsGain == ALS_GAIN_16X) ? (mTask.alsDebounceSamples + 1) : 1;
415 mTask.nextAlsGain = ALS_GAIN_16X;
416 } else if ((mTask.alsGain != ALS_GAIN_4X) && (sample >= AMS_TMD4903_ALS_GAIN_16X_THOLD) && (sample < AMS_TMD4903_ALS_GAIN_4X_THOLD)) {
417 mTask.alsDebounceSamples = (mTask.nextAlsGain == ALS_GAIN_4X) ? (mTask.alsDebounceSamples + 1) : 1;
418 mTask.nextAlsGain = ALS_GAIN_4X;
419 } else if ((mTask.alsGain != ALS_GAIN_1X) && (sample >= AMS_TMD4903_ALS_GAIN_4X_THOLD)) {
420 mTask.alsDebounceSamples = (mTask.nextAlsGain == ALS_GAIN_1X) ? (mTask.alsDebounceSamples + 1) : 1;
421 mTask.nextAlsGain = ALS_GAIN_1X;
422 }
423
424 return (mTask.alsDebounceSamples >= AMS_TMD4903_ALS_DEBOUNCE_SAMPLES);
425 }
426
sendCalibrationResultAls(uint8_t status,float offset)427 static void sendCalibrationResultAls(uint8_t status, float offset) {
428 struct AlsCalibrationData *data = heapAlloc(sizeof(struct AlsCalibrationData));
429 if (!data) {
430 osLog(LOG_WARN, "Couldn't alloc als cal result pkt");
431 return;
432 }
433
434 data->header.appId = AMS_TMD4903_APP_ID;
435 data->header.dataLen = (sizeof(struct AlsCalibrationData) - sizeof(struct HostHubRawPacket));
436 data->data_header.msgId = SENSOR_APP_MSG_ID_CAL_RESULT;
437 data->data_header.sensorType = SENS_TYPE_ALS;
438 data->data_header.status = status;
439 data->offset = offset;
440
441 if (!osEnqueueEvtOrFree(EVT_APP_TO_HOST, data, heapFree))
442 osLog(LOG_WARN, "Couldn't send als cal result evt");
443 }
444
sendCalibrationResultProx(uint8_t status,int16_t * offsets)445 static void sendCalibrationResultProx(uint8_t status, int16_t *offsets) {
446 int i;
447
448 struct ProxCalibrationData *data = heapAlloc(sizeof(struct ProxCalibrationData));
449 if (!data) {
450 osLog(LOG_WARN, "Couldn't alloc prox cal result pkt");
451 return;
452 }
453
454 data->header.appId = AMS_TMD4903_APP_ID;
455 data->header.dataLen = (sizeof(struct ProxCalibrationData) - sizeof(struct HostHubRawPacket));
456 data->data_header.msgId = SENSOR_APP_MSG_ID_CAL_RESULT;
457 data->data_header.sensorType = SENS_TYPE_PROX;
458 data->data_header.status = status;
459
460 // The offsets are cast from int16_t to int32_t, so I can't use memcpy
461 for (i = 0; i < 4; i++)
462 data->offsets[i] = offsets[i];
463
464 if (!osEnqueueEvtOrFree(EVT_APP_TO_HOST, data, heapFree))
465 osLog(LOG_WARN, "Couldn't send prox cal result evt");
466 }
467
setMode(bool alsOn,bool proxOn,uint8_t state)468 static void setMode(bool alsOn, bool proxOn, uint8_t state)
469 {
470 uint8_t regEnable =
471 ((alsOn || proxOn) ? POWER_ON_BIT : 0) |
472 (alsOn ? ALS_ENABLE_BIT : 0) |
473 (proxOn ? (PROX_INT_ENABLE_BIT | PROX_ENABLE_BIT) : 0);
474 writeRegister(AMS_TMD4903_REG_ENABLE, regEnable, state);
475 }
476
sensorPowerAls(bool on,void * cookie)477 static bool sensorPowerAls(bool on, void *cookie)
478 {
479 DEBUG_PRINT("sensorPowerAls: %d\n", on);
480
481 if (on && !mTask.alsTimerHandle) {
482 mTask.alsTimerHandle = timTimerSet(AMS_TMD4903_ALS_TIMER_DELAY, 0, 50, alsTimerCallback, NULL, false);
483 } else if (!on && mTask.alsTimerHandle) {
484 timTimerCancel(mTask.alsTimerHandle);
485 mTask.alsTimerHandle = 0;
486 }
487
488 mTask.lastAlsSample.idata = AMS_TMD4903_ALS_INVALID;
489 mTask.alsOn = on;
490 mTask.nextAlsGain = ALS_GAIN_4X;
491 mTask.alsChangingGain = false;
492 // skip first sample to make sure we get an entire integration cycle
493 mTask.alsSkipSample = true;
494 mTask.alsDebounceSamples = 0;
495
496 setMode(on, mTask.proxOn, (on) ? SENSOR_STATE_ENABLING_ALS : SENSOR_STATE_DISABLING_ALS);
497 return true;
498 }
499
sensorFirmwareAls(void * cookie)500 static bool sensorFirmwareAls(void *cookie)
501 {
502 return sensorSignalInternalEvt(mTask.alsHandle, SENSOR_INTERNAL_EVT_FW_STATE_CHG, 1, 0);
503 }
504
sensorRateAls(uint32_t rate,uint64_t latency,void * cookie)505 static bool sensorRateAls(uint32_t rate, uint64_t latency, void *cookie)
506 {
507 if (rate == SENSOR_RATE_ONCHANGE)
508 rate = AMS_TMD4903_DEFAULT_RATE;
509
510 DEBUG_PRINT("sensorRateAls: rate=%ld Hz latency=%lld ns\n", rate/1024, latency);
511
512 return sensorSignalInternalEvt(mTask.alsHandle, SENSOR_INTERNAL_EVT_RATE_CHG, rate, latency);
513 }
514
sensorFlushAls(void * cookie)515 static bool sensorFlushAls(void *cookie)
516 {
517 return osEnqueueEvt(sensorGetMyEventType(SENS_TYPE_ALS), SENSOR_DATA_EVENT_FLUSH, NULL);
518 }
519
sensorCalibrateAls(void * cookie)520 static bool sensorCalibrateAls(void *cookie)
521 {
522 DEBUG_PRINT("sensorCalibrateAls");
523
524 if (mTask.alsOn || mTask.proxOn) {
525 INFO_PRINT("cannot calibrate while als or prox are active\n");
526 sendCalibrationResultAls(SENSOR_APP_EVT_STATUS_BUSY, 0.0f);
527 return false;
528 }
529
530 mTask.alsOn = true;
531 mTask.lastAlsSample.idata = AMS_TMD4903_ALS_INVALID;
532 mTask.alsCalibrating = true;
533 mTask.alsOffset = 1.0f;
534 mTask.alsChangingGain = false;
535 mTask.alsSkipSample = false;
536
537 extiClearPendingGpio(mTask.pin);
538 enableInterrupt(mTask.pin, &mTask.isr, EXTI_TRIGGER_FALLING);
539
540 return writeRegister(AMS_TMD4903_REG_ENABLE,
541 (POWER_ON_BIT | ALS_ENABLE_BIT | ALS_INT_ENABLE_BIT),
542 SENSOR_STATE_IDLE);
543 }
544
sensorCfgDataAls(void * data,void * cookie)545 static bool sensorCfgDataAls(void *data, void *cookie)
546 {
547 DEBUG_PRINT("sensorCfgDataAls");
548
549 mTask.alsOffset = *(float*)data;
550
551 INFO_PRINT("Received als cfg data: %d\n", (int)mTask.alsOffset);
552
553 return true;
554 }
555
sendLastSampleAls(void * cookie,uint32_t tid)556 static bool sendLastSampleAls(void *cookie, uint32_t tid) {
557 bool result = true;
558
559 // If we don't end up doing anything here, the expectation is that we are powering up/haven't got the
560 // first sample yet, so the client will get a broadcast event soon
561 if (mTask.lastAlsSample.idata != AMS_TMD4903_ALS_INVALID) {
562 result = osEnqueuePrivateEvt(sensorGetMyEventType(SENS_TYPE_ALS), mTask.lastAlsSample.vptr, NULL, tid);
563 }
564 return result;
565 }
566
sensorPowerProx(bool on,void * cookie)567 static bool sensorPowerProx(bool on, void *cookie)
568 {
569 DEBUG_PRINT("sensorPowerProx: %d\n", on);
570
571 if (on) {
572 extiClearPendingGpio(mTask.pin);
573 enableInterrupt(mTask.pin, &mTask.isr, EXTI_TRIGGER_FALLING);
574 } else {
575 disableInterrupt(mTask.pin, &mTask.isr);
576 extiClearPendingGpio(mTask.pin);
577 }
578
579 mTask.lastProxState = PROX_STATE_INIT;
580 mTask.proxOn = on;
581 mTask.proxDirectMode = false;
582
583 setMode(mTask.alsOn, on, (on) ? SENSOR_STATE_ENABLING_PROX : SENSOR_STATE_DISABLING_PROX);
584 return true;
585 }
586
sensorFirmwareProx(void * cookie)587 static bool sensorFirmwareProx(void *cookie)
588 {
589 return sensorSignalInternalEvt(mTask.proxHandle, SENSOR_INTERNAL_EVT_FW_STATE_CHG, 1, 0);
590 }
591
sensorRateProx(uint32_t rate,uint64_t latency,void * cookie)592 static bool sensorRateProx(uint32_t rate, uint64_t latency, void *cookie)
593 {
594 if (rate == SENSOR_RATE_ONCHANGE)
595 rate = AMS_TMD4903_DEFAULT_RATE;
596
597 DEBUG_PRINT("sensorRateProx: rate=%ld Hz latency=%lld ns\n", rate/1024, latency);
598
599 return sensorSignalInternalEvt(mTask.proxHandle, SENSOR_INTERNAL_EVT_RATE_CHG, rate, latency);
600 }
601
sensorFlushProx(void * cookie)602 static bool sensorFlushProx(void *cookie)
603 {
604 return osEnqueueEvt(sensorGetMyEventType(SENS_TYPE_PROX), SENSOR_DATA_EVENT_FLUSH, NULL);
605 }
606
sensorCalibrateProx(void * cookie)607 static bool sensorCalibrateProx(void *cookie)
608 {
609 int16_t failOffsets[4] = {0, 0, 0, 0};
610 DEBUG_PRINT("sensorCalibrateProx");
611
612 if (mTask.alsOn || mTask.proxOn) {
613 INFO_PRINT("cannot calibrate while als or prox are active\n");
614 sendCalibrationResultProx(SENSOR_APP_EVT_STATUS_BUSY, failOffsets);
615 return false;
616 }
617
618 mTask.lastProxState = PROX_STATE_INIT;
619 mTask.proxOn = true;
620 mTask.proxCalibrating = true;
621 mTask.proxDirectMode = false;
622
623 extiClearPendingGpio(mTask.pin);
624 enableInterrupt(mTask.pin, &mTask.isr, EXTI_TRIGGER_FALLING);
625
626 return writeRegister(AMS_TMD4903_REG_ENABLE, POWER_ON_BIT,
627 SENSOR_STATE_START_PROX_CALIBRATION_0);
628 }
629
sensorCfgDataProx(void * data,void * cookie)630 static bool sensorCfgDataProx(void *data, void *cookie)
631 {
632 struct AlsProxTransfer *xfer;
633 int32_t *offsets = (int32_t *) data;
634
635 INFO_PRINT("Received cfg data: {%d, %d, %d, %d}\n",
636 (int)offsets[0], (int)offsets[1], (int)offsets[2], (int)offsets[3]);
637
638 xfer = allocXfer(SENSOR_STATE_IDLE);
639 if (xfer != NULL) {
640 xfer->txrxBuf[0] = AMS_TMD4903_REG_OFFSETNL;
641 *((int16_t*)&xfer->txrxBuf[1]) = offsets[0];
642 *((int16_t*)&xfer->txrxBuf[3]) = offsets[1];
643 *((int16_t*)&xfer->txrxBuf[5]) = offsets[2];
644 *((int16_t*)&xfer->txrxBuf[7]) = offsets[3];
645 i2cMasterTx(I2C_BUS_ID, I2C_ADDR, xfer->txrxBuf, 9, i2cCallback, xfer);
646 }
647 return true;
648 }
649
sendLastSampleProx(void * cookie,uint32_t tid)650 static bool sendLastSampleProx(void *cookie, uint32_t tid) {
651 union EmbeddedDataPoint sample;
652 bool result = true;
653
654 // See note in sendLastSampleAls
655 if (mTask.lastProxState != PROX_STATE_INIT) {
656 sample.fdata = (mTask.lastProxState == PROX_STATE_NEAR) ? AMS_TMD4903_REPORT_NEAR_VALUE : AMS_TMD4903_REPORT_FAR_VALUE;
657 result = osEnqueuePrivateEvt(sensorGetMyEventType(SENS_TYPE_PROX), sample.vptr, NULL, tid);
658 }
659 return result;
660 }
661
662 static const struct SensorInfo sensorInfoAls =
663 {
664 .sensorName = "ALS",
665 .supportedRates = supportedRates,
666 .sensorType = SENS_TYPE_ALS,
667 .numAxis = NUM_AXIS_EMBEDDED,
668 .interrupt = NANOHUB_INT_NONWAKEUP,
669 .minSamples = 20
670 };
671
672 static const struct SensorOps sensorOpsAls =
673 {
674 .sensorPower = sensorPowerAls,
675 .sensorFirmwareUpload = sensorFirmwareAls,
676 .sensorSetRate = sensorRateAls,
677 .sensorFlush = sensorFlushAls,
678 .sensorTriggerOndemand = NULL,
679 .sensorCalibrate = sensorCalibrateAls,
680 .sensorCfgData = sensorCfgDataAls,
681 .sensorSendOneDirectEvt = sendLastSampleAls
682 };
683
684 static const struct SensorInfo sensorInfoProx =
685 {
686 .sensorName = "Proximity",
687 .supportedRates = supportedRates,
688 .sensorType = SENS_TYPE_PROX,
689 .numAxis = NUM_AXIS_EMBEDDED,
690 .interrupt = NANOHUB_INT_WAKEUP,
691 .minSamples = 300
692 };
693
694 static const struct SensorOps sensorOpsProx =
695 {
696 .sensorPower = sensorPowerProx,
697 .sensorFirmwareUpload = sensorFirmwareProx,
698 .sensorSetRate = sensorRateProx,
699 .sensorFlush = sensorFlushProx,
700 .sensorTriggerOndemand = NULL,
701 .sensorCalibrate = sensorCalibrateProx,
702 .sensorCfgData = sensorCfgDataProx,
703 .sensorSendOneDirectEvt = sendLastSampleProx
704 };
705
verifySensorId(const struct AlsProxTransfer * xfer)706 static void verifySensorId(const struct AlsProxTransfer *xfer)
707 {
708 struct AlsProxTransfer *nextXfer;
709 DEBUG_PRINT("REVID = 0x%02x, ID = 0x%02x\n", xfer->txrxBuf[0], xfer->txrxBuf[1]);
710
711 // Check the sensor ID
712 if (xfer->err != 0 || xfer->txrxBuf[1] != AMS_TMD4903_ID) {
713 INFO_PRINT("not detected\n");
714 sensorUnregister(mTask.alsHandle);
715 sensorUnregister(mTask.proxHandle);
716 return;
717 }
718
719 nextXfer = allocXfer(SENSOR_STATE_INIT_0);
720 if (nextXfer == NULL) {
721 return;
722 }
723
724 // There is no SW reset on the AMS TMD4903, so we have to reset all registers manually
725 nextXfer->txrxBuf[0] = AMS_TMD4903_REG_ENABLE;
726 nextXfer->txrxBuf[1] = 0x00; // REG_ENABLE - reset value from datasheet
727 nextXfer->txrxBuf[2] = AMS_TMD4903_ATIME_SETTING; // REG_ATIME - 100 ms
728 nextXfer->txrxBuf[3] = AMS_TMD4903_PTIME_SETTING; // REG_PTIME - 50 ms
729 nextXfer->txrxBuf[4] = 0xff; // REG_WTIME - reset value from datasheet
730 nextXfer->txrxBuf[5] = 0x00; // REG_AILTL - reset value from datasheet
731 nextXfer->txrxBuf[6] = 0x00; // REG_AILTH - reset value from datasheet
732 nextXfer->txrxBuf[7] = 0x00; // REG_AIHTL - reset value from datasheet
733 nextXfer->txrxBuf[8] = 0x00; // REG_AIHTH - reset value from datasheet
734 nextXfer->txrxBuf[9] = (AMS_TMD4903_PROX_THRESHOLD_LOW & 0xFF); // REG_PILTL
735 nextXfer->txrxBuf[10] = (AMS_TMD4903_PROX_THRESHOLD_LOW >> 8) & 0xFF; // REG_PILTH
736 nextXfer->txrxBuf[11] = (AMS_TMD4903_PROX_THRESHOLD_HIGH & 0xFF); // REG_PIHTL
737 nextXfer->txrxBuf[12] = (AMS_TMD4903_PROX_THRESHOLD_HIGH >> 8) & 0xFF; // REG_PIHTH
738 nextXfer->txrxBuf[13] = 0x00; // REG_PERS - reset value from datasheet
739 nextXfer->txrxBuf[14] = 0xa0; // REG_CFG0 - reset value from datasheet
740 nextXfer->txrxBuf[15] = AMS_TMD4903_PGCFG0_SETTING; // REG_PGCFG0
741 nextXfer->txrxBuf[16] = AMS_TMD4903_PGCFG1_SETTING; // REG_PGCFG1
742 nextXfer->txrxBuf[17] = mTask.alsGain; // REG_CFG1
743
744 i2cMasterTx(I2C_BUS_ID, I2C_ADDR, nextXfer->txrxBuf, 18, i2cCallback, nextXfer);
745 }
746
handleAlsSample(const struct AlsProxTransfer * xfer)747 static void handleAlsSample(const struct AlsProxTransfer *xfer)
748 {
749 union EmbeddedDataPoint sample;
750 uint16_t c = *(uint16_t*)(xfer->txrxBuf);
751 uint16_t r = *(uint16_t*)(xfer->txrxBuf+2);
752 uint16_t g = *(uint16_t*)(xfer->txrxBuf+4);
753 uint16_t b = *(uint16_t*)(xfer->txrxBuf+6);
754
755 if (mTask.alsOn) {
756 sample.fdata = getLuxFromAlsData(c, r, g, b);
757 DEBUG_PRINT("als sample ready: c=%u r=%u g=%u b=%u, gain=%dx, lux=%d\n", c, r, g, b,
758 (int)getAlsGainFromSetting(mTask.alsGain), (int)sample.fdata);
759
760 if (mTask.alsCalibrating) {
761 sendCalibrationResultAls(SENSOR_APP_EVT_STATUS_SUCCESS, sample.fdata);
762
763 mTask.alsOn = false;
764 mTask.alsCalibrating = false;
765
766 writeRegister(AMS_TMD4903_REG_ENABLE, 0, SENSOR_STATE_IDLE);
767 } else if (mTask.alsSkipSample) {
768 mTask.alsSkipSample = false;
769 } else if (!mTask.alsChangingGain) {
770 if (mTask.lastAlsSample.idata != sample.idata) {
771 osEnqueueEvt(sensorGetMyEventType(SENS_TYPE_ALS), sample.vptr, NULL);
772 mTask.lastAlsSample.fdata = sample.fdata;
773 }
774
775 if (checkForAlsAutoGain(sample.fdata)) {
776 DEBUG_PRINT("Changing ALS gain from %dx to %dx\n", (int)getAlsGainFromSetting(mTask.alsGain),
777 (int)getAlsGainFromSetting(mTask.nextAlsGain));
778 if (writeRegister(AMS_TMD4903_REG_CFG1, mTask.nextAlsGain,
779 SENSOR_STATE_ALS_CHANGING_GAIN)) {
780 mTask.alsChangingGain = true;
781 }
782 }
783 }
784 }
785 }
786
handleProxSample(const struct AlsProxTransfer * xfer)787 static void handleProxSample(const struct AlsProxTransfer *xfer)
788 {
789 union EmbeddedDataPoint sample;
790 uint16_t ps = *((uint16_t *) xfer->txrxBuf);
791 uint8_t lastProxState = mTask.lastProxState;
792
793 DEBUG_PRINT("prox sample ready: prox=%u\n", ps);
794 if (mTask.proxOn) {
795 #if PROX_STREAMING
796 (void)lastProxState;
797 sample.fdata = ps;
798 osEnqueueEvt(sensorGetMyEventType(SENS_TYPE_PROX), sample.vptr, NULL);
799 #else
800 // Lower the bar for "near" threshold so it reports "near" when the prox
801 // value is within the hysteresis threshold
802 if (ps > AMS_TMD4903_PROX_THRESHOLD_LOW) {
803 sample.fdata = AMS_TMD4903_REPORT_NEAR_VALUE;
804 mTask.lastProxState = PROX_STATE_NEAR;
805 } else {
806 sample.fdata = AMS_TMD4903_REPORT_FAR_VALUE;
807 mTask.lastProxState = PROX_STATE_FAR;
808 }
809
810 if (mTask.lastProxState != lastProxState)
811 osEnqueueEvt(sensorGetMyEventType(SENS_TYPE_PROX), sample.vptr, NULL);
812 #endif
813
814 #if PROX_STREAMING
815 // reset proximity interrupts
816 writeRegister(AMS_TMD4903_REG_INTCLEAR, 0x60, SENSOR_STATE_IDLE);
817 #else
818 // The TMD4903 direct interrupt mode does not work properly if enabled while something is covering the sensor,
819 // so we need to wait until it is far.
820 if (mTask.lastProxState == PROX_STATE_FAR) {
821 disableInterrupt(mTask.pin, &mTask.isr);
822 extiClearPendingGpio(mTask.pin);
823
824 // Switch to proximity interrupt direct mode
825 writeRegister(AMS_TMD4903_REG_CFG4, 0x27, SENSOR_STATE_PROX_TRANSITION_0);
826 } else {
827 // If we are in the "near" state, we cannot change to direct interrupt mode, so just clear the interrupt
828 writeRegister(AMS_TMD4903_REG_INTCLEAR, 0x60, SENSOR_STATE_IDLE);
829 }
830 #endif
831 }
832 }
833
834 /*
835 * Sensor i2c state machine
836 */
handle_i2c_event(struct AlsProxTransfer * xfer)837 static void handle_i2c_event(struct AlsProxTransfer *xfer)
838 {
839 int i;
840 struct AlsProxTransfer *nextXfer;
841
842 switch (xfer->state) {
843 case SENSOR_STATE_VERIFY_ID:
844 verifySensorId(xfer);
845 break;
846
847 case SENSOR_STATE_INIT_0:
848 // Set REG_CFG4 to reset value from datasheet
849 writeRegister(AMS_TMD4903_REG_CFG4, 0x07, SENSOR_STATE_INIT_1);
850 break;
851
852 case SENSOR_STATE_INIT_1:
853 nextXfer = allocXfer(SENSOR_STATE_INIT_2);
854 if (nextXfer != NULL) {
855 nextXfer->txrxBuf[0] = AMS_TMD4903_REG_OFFSETNL;
856 for (i = 0; i < 8; i++)
857 nextXfer->txrxBuf[1+i] = 0x00;
858 i2cMasterTx(I2C_BUS_ID, I2C_ADDR, nextXfer->txrxBuf, 9, i2cCallback, nextXfer);
859 }
860 break;
861
862 case SENSOR_STATE_INIT_2:
863 // Write REG_INTCLEAR to clear all interrupts
864 writeRegister(AMS_TMD4903_REG_INTCLEAR, 0xFA, SENSOR_STATE_FINISH_INIT);
865 break;
866
867 case SENSOR_STATE_FINISH_INIT:
868 sensorRegisterInitComplete(mTask.alsHandle);
869 sensorRegisterInitComplete(mTask.proxHandle);
870 break;
871
872 case SENSOR_STATE_START_PROX_CALIBRATION_0:
873 // Write REG_INTENAB to enable calibration interrupt
874 writeRegister(AMS_TMD4903_REG_INTENAB, CAL_INT_ENABLE_BIT,
875 SENSOR_STATE_START_PROX_CALIBRATION_1);
876 break;
877
878 case SENSOR_STATE_START_PROX_CALIBRATION_1:
879 // Write REG_CALIB to start calibration
880 writeRegister(AMS_TMD4903_REG_CALIB, 0x01, SENSOR_STATE_IDLE);
881 break;
882
883 case SENSOR_STATE_FINISH_PROX_CALIBRATION_0:
884 disableInterrupt(mTask.pin, &mTask.isr);
885 extiClearPendingGpio(mTask.pin);
886
887 mTask.proxOn = false;
888 mTask.proxCalibrating = false;
889
890 INFO_PRINT("Calibration offsets = {%d, %d, %d, %d}\n", *((int16_t*)&xfer->txrxBuf[0]),
891 *((int16_t*)&xfer->txrxBuf[2]), *((int16_t*)&xfer->txrxBuf[4]),
892 *((int16_t*)&xfer->txrxBuf[6]));
893
894 // Send calibration result
895 sendCalibrationResultProx(SENSOR_APP_EVT_STATUS_SUCCESS, (int16_t*)xfer->txrxBuf);
896
897 // Write REG_INTENAB to disable all interrupts
898 writeRegister(AMS_TMD4903_REG_INTENAB, 0x00,
899 SENSOR_STATE_FINISH_PROX_CALIBRATION_1);
900 break;
901
902 case SENSOR_STATE_FINISH_PROX_CALIBRATION_1:
903 writeRegister(AMS_TMD4903_REG_ENABLE, 0, SENSOR_STATE_IDLE);
904 break;
905
906 case SENSOR_STATE_ENABLING_ALS:
907 sensorSignalInternalEvt(mTask.alsHandle, SENSOR_INTERNAL_EVT_POWER_STATE_CHG, true, 0);
908 break;
909
910 case SENSOR_STATE_ENABLING_PROX:
911 sensorSignalInternalEvt(mTask.proxHandle, SENSOR_INTERNAL_EVT_POWER_STATE_CHG, true, 0);
912 break;
913
914 case SENSOR_STATE_DISABLING_ALS:
915 // Reset AGAIN to 4x
916 mTask.alsGain = ALS_GAIN_4X;
917 writeRegister(AMS_TMD4903_REG_CFG1, mTask.alsGain, SENSOR_STATE_DISABLING_ALS_2);
918 break;
919
920 case SENSOR_STATE_DISABLING_ALS_2:
921 sensorSignalInternalEvt(mTask.alsHandle, SENSOR_INTERNAL_EVT_POWER_STATE_CHG, false, 0);
922 break;
923
924 case SENSOR_STATE_DISABLING_PROX:
925 // Write REG_CFG4 to the reset value from datasheet
926 writeRegister(AMS_TMD4903_REG_CFG4, 0x07, SENSOR_STATE_DISABLING_PROX_2);
927 break;
928
929 case SENSOR_STATE_DISABLING_PROX_2:
930 // Write REG_INTCLEAR to clear proximity interrupts
931 writeRegister(AMS_TMD4903_REG_INTCLEAR, 0x60, SENSOR_STATE_DISABLING_PROX_3);
932 break;
933
934 case SENSOR_STATE_DISABLING_PROX_3:
935 sensorSignalInternalEvt(mTask.proxHandle, SENSOR_INTERNAL_EVT_POWER_STATE_CHG, false, 0);
936 break;
937
938 case SENSOR_STATE_ALS_CHANGING_GAIN:
939 if (mTask.alsOn) {
940 mTask.alsChangingGain = false;
941 mTask.alsGain = mTask.nextAlsGain;
942 mTask.alsDebounceSamples = 0;
943 mTask.alsSkipSample = true;
944 }
945 break;
946
947 case SENSOR_STATE_ALS_SAMPLING:
948 handleAlsSample(xfer);
949 break;
950
951 case SENSOR_STATE_PROX_SAMPLING:
952 handleProxSample(xfer);
953 break;
954
955 case SENSOR_STATE_PROX_TRANSITION_0:
956 if (mTask.proxOn) {
957 mTask.proxDirectMode = true;
958 extiClearPendingGpio(mTask.pin);
959 enableInterrupt(mTask.pin, &mTask.isr, EXTI_TRIGGER_BOTH);
960 }
961 break;
962
963 default:
964 break;
965 }
966
967 xfer->inUse = false;
968 }
969
970 /*
971 * Main driver entry points
972 */
973
init_app(uint32_t myTid)974 static bool init_app(uint32_t myTid)
975 {
976 /* Set up driver private data */
977 mTask.tid = myTid;
978 mTask.alsOn = false;
979 mTask.proxOn = false;
980 mTask.lastAlsSample.idata = AMS_TMD4903_ALS_INVALID;
981 mTask.lastProxState = PROX_STATE_INIT;
982 mTask.proxCalibrating = false;
983 mTask.alsOffset = 1.0f;
984 mTask.alsGain = ALS_GAIN_4X;
985
986 mTask.pin = gpioRequest(PROX_INT_PIN);
987 gpioConfigInput(mTask.pin, GPIO_SPEED_LOW, GPIO_PULL_NONE);
988 syscfgSetExtiPort(mTask.pin);
989 mTask.isr.func = proxIsr;
990
991 mTask.alsHandle = sensorRegister(&sensorInfoAls, &sensorOpsAls, NULL, false);
992 mTask.proxHandle = sensorRegister(&sensorInfoProx, &sensorOpsProx, NULL, false);
993
994 osEventSubscribe(myTid, EVT_APP_START);
995
996 return true;
997 }
998
end_app(void)999 static void end_app(void)
1000 {
1001 disableInterrupt(mTask.pin, &mTask.isr);
1002 extiUnchainIsr(PROX_IRQ, &mTask.isr);
1003 extiClearPendingGpio(mTask.pin);
1004 gpioRelease(mTask.pin);
1005
1006 sensorUnregister(mTask.alsHandle);
1007 sensorUnregister(mTask.proxHandle);
1008
1009 i2cMasterRelease(I2C_BUS_ID);
1010 }
1011
handle_event(uint32_t evtType,const void * evtData)1012 static void handle_event(uint32_t evtType, const void* evtData)
1013 {
1014 struct AlsProxTransfer *xfer;
1015
1016 switch (evtType) {
1017 case EVT_APP_START:
1018 i2cMasterRequest(I2C_BUS_ID, I2C_SPEED);
1019
1020 // Read the ID
1021 xfer = allocXfer(SENSOR_STATE_VERIFY_ID);
1022 if (xfer != NULL) {
1023 xfer->txrxBuf[0] = AMS_TMD4903_REG_REVID;
1024 i2cMasterTxRx(I2C_BUS_ID, I2C_ADDR, xfer->txrxBuf, 1, xfer->txrxBuf, 2, i2cCallback, xfer);
1025 }
1026 break;
1027
1028 case EVT_SENSOR_I2C:
1029 // Dropping const here (we own this memory)
1030 handle_i2c_event((struct AlsProxTransfer *) evtData);
1031 break;
1032
1033 case EVT_SENSOR_ALS_INTERRUPT:
1034 disableInterrupt(mTask.pin, &mTask.isr);
1035 extiClearPendingGpio(mTask.pin);
1036 // NOTE: fall-through to initiate read of ALS data registers
1037
1038 case EVT_SENSOR_ALS_TIMER:
1039 xfer = allocXfer(SENSOR_STATE_ALS_SAMPLING);
1040 if (xfer != NULL) {
1041 xfer->txrxBuf[0] = AMS_TMD4903_REG_CDATAL;
1042 i2cMasterTxRx(I2C_BUS_ID, I2C_ADDR, xfer->txrxBuf, 1, xfer->txrxBuf, 8, i2cCallback, xfer);
1043 }
1044 break;
1045
1046 case EVT_SENSOR_PROX_INTERRUPT:
1047 xfer = allocXfer(SENSOR_STATE_PROX_SAMPLING);
1048 if (xfer != NULL) {
1049 if (mTask.proxCalibrating) {
1050 xfer->txrxBuf[0] = AMS_TMD4903_REG_OFFSETNL;
1051 xfer->state = SENSOR_STATE_FINISH_PROX_CALIBRATION_0;
1052 i2cMasterTxRx(I2C_BUS_ID, I2C_ADDR, xfer->txrxBuf, 1, xfer->txrxBuf, 8, i2cCallback, xfer);
1053 } else {
1054 xfer->txrxBuf[0] = AMS_TMD4903_REG_PDATAL;
1055 i2cMasterTxRx(I2C_BUS_ID, I2C_ADDR, xfer->txrxBuf, 1, xfer->txrxBuf, 2, i2cCallback, xfer);
1056 }
1057 }
1058 break;
1059
1060 }
1061 }
1062
1063 INTERNAL_APP_INIT(AMS_TMD4903_APP_ID, AMS_TMD4903_APP_VERSION, init_app, end_app, handle_event);
1064