• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/inc/exti.h>
34 #include <plat/inc/gpio.h>
35 #include <plat/inc/syscfg.h>
36 #include <variant/inc/variant.h>
37 
38 #define AMS_TMD4903_APP_ID      APP_ID_MAKE(APP_ID_VENDOR_GOOGLE, 12)
39 #define AMS_TMD4903_APP_VERSION 6
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_PTIME_SETTING              0x11
104 #define AMS_TMD4903_PGCFG0_SETTING             0x41 // pulse length: 8 us, pulse count: 2
105 #define AMS_TMD4903_PGCFG1_SETTING             0x04 // gain: 1x, drive: 50 mA
106 
107 /* AMS_TMD4903_REG_ENABLE */
108 #define PROX_INT_ENABLE_BIT                    (1 << 5)
109 #define ALS_INT_ENABLE_BIT                     (1 << 4)
110 #define PROX_ENABLE_BIT                        (1 << 2)
111 #define ALS_ENABLE_BIT                         (1 << 1)
112 #define POWER_ON_BIT                           (1 << 0)
113 
114 /* AMS_TMD4903_REG_INTENAB */
115 #define CAL_INT_ENABLE_BIT                     (1 << 1)
116 
117 
118 #define AMS_TMD4903_REPORT_NEAR_VALUE          0.0f // centimeters
119 #define AMS_TMD4903_REPORT_FAR_VALUE           5.0f // centimeters
120 #define AMS_TMD4903_PROX_THRESHOLD_HIGH        350  // value in PS_DATA
121 #define AMS_TMD4903_PROX_THRESHOLD_LOW         250  // value in PS_DATA
122 
123 #define AMS_TMD4903_ALS_INVALID                UINT32_MAX
124 
125 #define AMS_TMD4903_ALS_TIMER_DELAY            200000000ULL
126 
127 // NOTE: Define this to be 1 to enable streaming of proximity samples instead of
128 // using the interrupt
129 #define PROX_STREAMING 0
130 
131 #define INFO_PRINT(fmt, ...) do { \
132         osLog(LOG_INFO, "%s " fmt, "[TMD4903]", ##__VA_ARGS__); \
133     } while (0);
134 
135 #define DEBUG_PRINT(fmt, ...) do { \
136         if (enable_debug) {  \
137             INFO_PRINT(fmt, ##__VA_ARGS__); \
138         } \
139     } while (0);
140 
141 static const bool enable_debug = 0;
142 
143 /* Private driver events */
144 enum SensorEvents
145 {
146     EVT_SENSOR_I2C = EVT_APP_START + 1,
147     EVT_SENSOR_ALS_TIMER,
148     EVT_SENSOR_ALS_INTERRUPT,
149     EVT_SENSOR_PROX_INTERRUPT,
150 };
151 
152 /* I2C state machine */
153 enum SensorState
154 {
155     SENSOR_STATE_VERIFY_ID,
156     SENSOR_STATE_INIT_0,
157     SENSOR_STATE_INIT_1,
158     SENSOR_STATE_INIT_2,
159     SENSOR_STATE_FINISH_INIT,
160     SENSOR_STATE_START_PROX_CALIBRATION_0,
161     SENSOR_STATE_START_PROX_CALIBRATION_1,
162     SENSOR_STATE_FINISH_PROX_CALIBRATION_0,
163     SENSOR_STATE_FINISH_PROX_CALIBRATION_1,
164     SENSOR_STATE_POLL_STATUS,
165     SENSOR_STATE_ENABLING_ALS,
166     SENSOR_STATE_ENABLING_PROX,
167     SENSOR_STATE_DISABLING_ALS,
168     SENSOR_STATE_DISABLING_PROX,
169     SENSOR_STATE_DISABLING_PROX_2,
170     SENSOR_STATE_DISABLING_PROX_3,
171     SENSOR_STATE_ALS_SAMPLING,
172     SENSOR_STATE_PROX_SAMPLING,
173     SENSOR_STATE_PROX_TRANSITION_0,
174     SENSOR_STATE_IDLE,
175 };
176 
177 enum ProxState
178 {
179     PROX_STATE_INIT,
180     PROX_STATE_NEAR,
181     PROX_STATE_FAR,
182 };
183 
184 enum ProxOffsetIndex
185 {
186     PROX_OFFSET_NORTH = 0,
187     PROX_OFFSET_SOUTH = 1,
188     PROX_OFFSET_WEST  = 2,
189     PROX_OFFSET_EAST  = 3
190 };
191 
192 struct SensorData
193 {
194     struct Gpio *pin;
195     struct ChainedIsr isr;
196 
197     uint8_t txrxBuf[18];
198 
199     uint32_t tid;
200 
201     uint32_t alsHandle;
202     uint32_t proxHandle;
203     uint32_t alsTimerHandle;
204 
205     float alsOffset;
206 
207     union EmbeddedDataPoint lastAlsSample;
208 
209     uint8_t lastProxState; // enum ProxState
210 
211     bool alsOn;
212     bool proxOn;
213     bool alsCalibrating;
214     bool proxCalibrating;
215     bool proxDirectMode;
216 };
217 
218 static struct SensorData mTask;
219 
220 struct AlsCalibrationData {
221     struct HostHubRawPacket header;
222     struct SensorAppEventHeader data_header;
223     float offset;
224 } __attribute__((packed));
225 
226 struct ProxCalibrationData {
227     struct HostHubRawPacket header;
228     struct SensorAppEventHeader data_header;
229     int32_t offsets[4];
230 } __attribute__((packed));
231 
232 static const uint32_t supportedRates[] =
233 {
234     SENSOR_HZ(5),
235     SENSOR_RATE_ONCHANGE,
236     0,
237 };
238 
239 /*
240  * Helper functions
241  */
proxIsr(struct ChainedIsr * localIsr)242 static bool proxIsr(struct ChainedIsr *localIsr)
243 {
244     struct SensorData *data = container_of(localIsr, struct SensorData, isr);
245     uint8_t lastProxState = data->lastProxState;
246     union EmbeddedDataPoint sample;
247     bool pinState;
248 
249     if (!extiIsPendingGpio(data->pin)) {
250         return false;
251     }
252 
253     pinState = gpioGet(data->pin);
254 
255     if (data->proxOn) {
256 #if PROX_STREAMING
257         (void)sample;
258         (void)pinState;
259         (void)lastProxState;
260         if (!pinState)
261             osEnqueuePrivateEvt(EVT_SENSOR_PROX_INTERRUPT, NULL, NULL, mTask.tid);
262 #else
263         if (data->proxDirectMode) {
264             sample.fdata = (pinState) ? AMS_TMD4903_REPORT_FAR_VALUE : AMS_TMD4903_REPORT_NEAR_VALUE;
265             data->lastProxState = (pinState) ? PROX_STATE_FAR : PROX_STATE_NEAR;
266             if (data->lastProxState != lastProxState)
267                 osEnqueueEvt(sensorGetMyEventType(SENS_TYPE_PROX), sample.vptr, NULL);
268         } else {
269             osEnqueuePrivateEvt(EVT_SENSOR_PROX_INTERRUPT, NULL, NULL, mTask.tid);
270         }
271 #endif
272     } else if (data->alsOn && data->alsCalibrating && !pinState) {
273         osEnqueuePrivateEvt(EVT_SENSOR_ALS_INTERRUPT, NULL, NULL, mTask.tid);
274     }
275 
276     extiClearPendingGpio(data->pin);
277     return true;
278 }
279 
enableInterrupt(struct Gpio * pin,struct ChainedIsr * isr,enum ExtiTrigger trigger)280 static bool enableInterrupt(struct Gpio *pin, struct ChainedIsr *isr, enum ExtiTrigger trigger)
281 {
282     extiEnableIntGpio(pin, trigger);
283     extiChainIsr(PROX_IRQ, isr);
284     return true;
285 }
286 
disableInterrupt(struct Gpio * pin,struct ChainedIsr * isr)287 static bool disableInterrupt(struct Gpio *pin, struct ChainedIsr *isr)
288 {
289     extiUnchainIsr(PROX_IRQ, isr);
290     extiDisableIntGpio(pin);
291     return true;
292 }
293 
i2cCallback(void * cookie,size_t tx,size_t rx,int err)294 static void i2cCallback(void *cookie, size_t tx, size_t rx, int err)
295 {
296     if (err == 0)
297         osEnqueuePrivateEvt(EVT_SENSOR_I2C, cookie, NULL, mTask.tid);
298     else
299         INFO_PRINT("i2c error (%d)\n", err);
300 }
301 
alsTimerCallback(uint32_t timerId,void * cookie)302 static void alsTimerCallback(uint32_t timerId, void *cookie)
303 {
304     osEnqueuePrivateEvt(EVT_SENSOR_ALS_TIMER, cookie, NULL, mTask.tid);
305 }
306 
307 #define LUX_PER_COUNTS   (799.397f/AMS_TMD4903_ATIME_MS)
308 #define C_COEFF           2.387f
309 #define R_COEFF           -1.57f
310 #define G_COEFF           2.69f
311 #define B_COEFF           -3.307f
312 
getLuxFromAlsData(uint16_t c,uint16_t r,uint16_t g,uint16_t b)313 static inline float getLuxFromAlsData(uint16_t c, uint16_t r, uint16_t g, uint16_t b)
314 {
315     // TODO (trevorbunker): need to check for c saturation
316     // AMS_TMG4903_ALS_MAX_CHANNEL_COUNT
317 
318     // TODO (trevorbunker): You can use IR ratio (depends on light source) to
319     // select between different R, G, and B coefficients
320 
321     return LUX_PER_COUNTS * ((c * C_COEFF) + (r * R_COEFF) + (g * G_COEFF) + (b * B_COEFF)) * mTask.alsOffset;
322 }
323 
sendCalibrationResultAls(uint8_t status,float offset)324 static void sendCalibrationResultAls(uint8_t status, float offset) {
325     struct AlsCalibrationData *data = heapAlloc(sizeof(struct AlsCalibrationData));
326     if (!data) {
327         osLog(LOG_WARN, "Couldn't alloc als cal result pkt");
328         return;
329     }
330 
331     data->header.appId = AMS_TMD4903_APP_ID;
332     data->header.dataLen = (sizeof(struct AlsCalibrationData) - sizeof(struct HostHubRawPacket));
333     data->data_header.msgId = SENSOR_APP_MSG_ID_CAL_RESULT;
334     data->data_header.sensorType = SENS_TYPE_ALS;
335     data->data_header.status = status;
336     data->offset = offset;
337 
338     if (!osEnqueueEvtOrFree(EVT_APP_TO_HOST, data, heapFree))
339         osLog(LOG_WARN, "Couldn't send als cal result evt");
340 }
341 
sendCalibrationResultProx(uint8_t status,int16_t * offsets)342 static void sendCalibrationResultProx(uint8_t status, int16_t *offsets) {
343     int i;
344 
345     struct ProxCalibrationData *data = heapAlloc(sizeof(struct ProxCalibrationData));
346     if (!data) {
347         osLog(LOG_WARN, "Couldn't alloc prox cal result pkt");
348         return;
349     }
350 
351     data->header.appId = AMS_TMD4903_APP_ID;
352     data->header.dataLen = (sizeof(struct ProxCalibrationData) - sizeof(struct HostHubRawPacket));
353     data->data_header.msgId = SENSOR_APP_MSG_ID_CAL_RESULT;
354     data->data_header.sensorType = SENS_TYPE_PROX;
355     data->data_header.status = status;
356 
357     // The offsets are cast from int16_t to int32_t, so I can't use memcpy
358     for (i = 0; i < 4; i++)
359         data->offsets[i] = offsets[i];
360 
361     if (!osEnqueueEvtOrFree(EVT_APP_TO_HOST, data, heapFree))
362         osLog(LOG_WARN, "Couldn't send prox cal result evt");
363 }
364 
setMode(bool alsOn,bool proxOn,void * cookie)365 static void setMode(bool alsOn, bool proxOn, void *cookie)
366 {
367     mTask.txrxBuf[0] = AMS_TMD4903_REG_ENABLE;
368     mTask.txrxBuf[1] =
369         ((alsOn || proxOn) ? POWER_ON_BIT : 0) |
370         (alsOn ? ALS_ENABLE_BIT : 0) |
371         (proxOn ? (PROX_INT_ENABLE_BIT | PROX_ENABLE_BIT) : 0);
372     i2cMasterTx(I2C_BUS_ID, I2C_ADDR, mTask.txrxBuf, 2, &i2cCallback, cookie);
373 }
374 
sensorPowerAls(bool on,void * cookie)375 static bool sensorPowerAls(bool on, void *cookie)
376 {
377     DEBUG_PRINT("sensorPowerAls: %d\n", on);
378 
379     if (on && !mTask.alsTimerHandle) {
380         mTask.alsTimerHandle = timTimerSet(AMS_TMD4903_ALS_TIMER_DELAY, 0, 50, alsTimerCallback, NULL, false);
381     } else if (!on && mTask.alsTimerHandle) {
382         timTimerCancel(mTask.alsTimerHandle);
383         mTask.alsTimerHandle = 0;
384     }
385 
386     mTask.lastAlsSample.idata = AMS_TMD4903_ALS_INVALID;
387     mTask.alsOn = on;
388 
389     setMode(on, mTask.proxOn, (void *)(on ? SENSOR_STATE_ENABLING_ALS : SENSOR_STATE_DISABLING_ALS));
390     return true;
391 }
392 
sensorFirmwareAls(void * cookie)393 static bool sensorFirmwareAls(void *cookie)
394 {
395     return sensorSignalInternalEvt(mTask.alsHandle, SENSOR_INTERNAL_EVT_FW_STATE_CHG, 1, 0);
396 }
397 
sensorRateAls(uint32_t rate,uint64_t latency,void * cookie)398 static bool sensorRateAls(uint32_t rate, uint64_t latency, void *cookie)
399 {
400     if (rate == SENSOR_RATE_ONCHANGE)
401         rate = AMS_TMD4903_DEFAULT_RATE;
402 
403     DEBUG_PRINT("sensorRateAls: rate=%ld Hz latency=%lld ns\n", rate/1024, latency);
404 
405     return sensorSignalInternalEvt(mTask.alsHandle, SENSOR_INTERNAL_EVT_RATE_CHG, rate, latency);
406 }
407 
sensorFlushAls(void * cookie)408 static bool sensorFlushAls(void *cookie)
409 {
410     return osEnqueueEvt(sensorGetMyEventType(SENS_TYPE_ALS), SENSOR_DATA_EVENT_FLUSH, NULL);
411 }
412 
sensorCalibrateAls(void * cookie)413 static bool sensorCalibrateAls(void *cookie)
414 {
415     DEBUG_PRINT("sensorCalibrateAls");
416 
417     if (mTask.alsOn || mTask.proxOn) {
418         INFO_PRINT("cannot calibrate while als or prox are active\n");
419         sendCalibrationResultAls(SENSOR_APP_EVT_STATUS_BUSY, 0.0f);
420         return false;
421     }
422 
423     mTask.alsOn = true;
424     mTask.lastAlsSample.idata = AMS_TMD4903_ALS_INVALID;
425     mTask.alsCalibrating = true;
426     mTask.alsOffset = 1.0f;
427 
428     extiClearPendingGpio(mTask.pin);
429     enableInterrupt(mTask.pin, &mTask.isr, EXTI_TRIGGER_FALLING);
430 
431     mTask.txrxBuf[0] = AMS_TMD4903_REG_ENABLE;
432     mTask.txrxBuf[1] = POWER_ON_BIT | ALS_ENABLE_BIT | ALS_INT_ENABLE_BIT;
433     i2cMasterTx(I2C_BUS_ID, I2C_ADDR, mTask.txrxBuf, 2, &i2cCallback, (void*)SENSOR_STATE_IDLE);
434 
435     return true;
436 }
437 
sensorCfgDataAls(void * data,void * cookie)438 static bool sensorCfgDataAls(void *data, void *cookie)
439 {
440     DEBUG_PRINT("sensorCfgDataAls");
441 
442     mTask.alsOffset = *(float*)data;
443 
444     INFO_PRINT("Received als cfg data: %d\n", (int)mTask.alsOffset);
445 
446     return true;
447 }
448 
sendLastSampleAls(void * cookie,uint32_t tid)449 static bool sendLastSampleAls(void *cookie, uint32_t tid) {
450     bool result = true;
451 
452     // If we don't end up doing anything here, the expectation is that we are powering up/haven't got the
453     // first sample yet, so the client will get a broadcast event soon
454     if (mTask.lastAlsSample.idata != AMS_TMD4903_ALS_INVALID) {
455         result = osEnqueuePrivateEvt(sensorGetMyEventType(SENS_TYPE_ALS), mTask.lastAlsSample.vptr, NULL, tid);
456     }
457     return result;
458 }
459 
sensorPowerProx(bool on,void * cookie)460 static bool sensorPowerProx(bool on, void *cookie)
461 {
462     DEBUG_PRINT("sensorPowerProx: %d\n", on);
463 
464     if (on) {
465         extiClearPendingGpio(mTask.pin);
466         enableInterrupt(mTask.pin, &mTask.isr, EXTI_TRIGGER_FALLING);
467     } else {
468         disableInterrupt(mTask.pin, &mTask.isr);
469         extiClearPendingGpio(mTask.pin);
470     }
471 
472     mTask.lastProxState = PROX_STATE_INIT;
473     mTask.proxOn = on;
474     mTask.proxDirectMode = false;
475 
476     setMode(mTask.alsOn, on, (void *)(on ? SENSOR_STATE_ENABLING_PROX : SENSOR_STATE_DISABLING_PROX));
477     return true;
478 }
479 
sensorFirmwareProx(void * cookie)480 static bool sensorFirmwareProx(void *cookie)
481 {
482     return sensorSignalInternalEvt(mTask.proxHandle, SENSOR_INTERNAL_EVT_FW_STATE_CHG, 1, 0);
483 }
484 
sensorRateProx(uint32_t rate,uint64_t latency,void * cookie)485 static bool sensorRateProx(uint32_t rate, uint64_t latency, void *cookie)
486 {
487     if (rate == SENSOR_RATE_ONCHANGE)
488         rate = AMS_TMD4903_DEFAULT_RATE;
489 
490     DEBUG_PRINT("sensorRateProx: rate=%ld Hz latency=%lld ns\n", rate/1024, latency);
491 
492     return sensorSignalInternalEvt(mTask.proxHandle, SENSOR_INTERNAL_EVT_RATE_CHG, rate, latency);
493 }
494 
sensorFlushProx(void * cookie)495 static bool sensorFlushProx(void *cookie)
496 {
497     return osEnqueueEvt(sensorGetMyEventType(SENS_TYPE_PROX), SENSOR_DATA_EVENT_FLUSH, NULL);
498 }
499 
sensorCalibrateProx(void * cookie)500 static bool sensorCalibrateProx(void *cookie)
501 {
502     int16_t failOffsets[4] = {0, 0, 0, 0};
503     DEBUG_PRINT("sensorCalibrateProx");
504 
505     if (mTask.alsOn || mTask.proxOn) {
506         INFO_PRINT("cannot calibrate while als or prox are active\n");
507         sendCalibrationResultProx(SENSOR_APP_EVT_STATUS_BUSY, failOffsets);
508         return false;
509     }
510 
511     mTask.lastProxState = PROX_STATE_INIT;
512     mTask.proxOn = true;
513     mTask.proxCalibrating = true;
514     mTask.proxDirectMode = false;
515 
516     extiClearPendingGpio(mTask.pin);
517     enableInterrupt(mTask.pin, &mTask.isr, EXTI_TRIGGER_FALLING);
518 
519     mTask.txrxBuf[0] = AMS_TMD4903_REG_ENABLE;
520     mTask.txrxBuf[1] = POWER_ON_BIT; // REG_ENABLE
521     i2cMasterTx(I2C_BUS_ID, I2C_ADDR, mTask.txrxBuf, 2, &i2cCallback, (void*)SENSOR_STATE_START_PROX_CALIBRATION_0);
522 
523     return true;
524 }
525 
sensorCfgDataProx(void * data,void * cookie)526 static bool sensorCfgDataProx(void *data, void *cookie)
527 {
528     DEBUG_PRINT("sensorCfgDataProx");
529 
530     int32_t *offsets = (int32_t*)data;
531 
532     INFO_PRINT("Received cfg data: {%d, %d, %d, %d}\n",
533                 (int)offsets[0], (int)offsets[1], (int)offsets[2], (int)offsets[3]);
534 
535     mTask.txrxBuf[0] = AMS_TMD4903_REG_OFFSETNL;
536     *((int16_t*)&mTask.txrxBuf[1]) = offsets[0];
537     *((int16_t*)&mTask.txrxBuf[3]) = offsets[1];
538     *((int16_t*)&mTask.txrxBuf[5]) = offsets[2];
539     *((int16_t*)&mTask.txrxBuf[7]) = offsets[3];
540     i2cMasterTx(I2C_BUS_ID, I2C_ADDR, mTask.txrxBuf, 9, &i2cCallback, (void *)SENSOR_STATE_IDLE);
541     return true;
542 }
543 
sendLastSampleProx(void * cookie,uint32_t tid)544 static bool sendLastSampleProx(void *cookie, uint32_t tid) {
545     union EmbeddedDataPoint sample;
546     bool result = true;
547 
548     // See note in sendLastSampleAls
549     if (mTask.lastProxState != PROX_STATE_INIT) {
550         sample.fdata = (mTask.lastProxState == PROX_STATE_NEAR) ? AMS_TMD4903_REPORT_NEAR_VALUE : AMS_TMD4903_REPORT_FAR_VALUE;
551         result = osEnqueuePrivateEvt(sensorGetMyEventType(SENS_TYPE_PROX), sample.vptr, NULL, tid);
552     }
553     return result;
554 }
555 
556 static const struct SensorInfo sensorInfoAls =
557 {
558     .sensorName = "ALS",
559     .supportedRates = supportedRates,
560     .sensorType = SENS_TYPE_ALS,
561     .numAxis = NUM_AXIS_EMBEDDED,
562     .interrupt = NANOHUB_INT_NONWAKEUP,
563     .minSamples = 20
564 };
565 
566 static const struct SensorOps sensorOpsAls =
567 {
568     .sensorPower = sensorPowerAls,
569     .sensorFirmwareUpload = sensorFirmwareAls,
570     .sensorSetRate = sensorRateAls,
571     .sensorFlush = sensorFlushAls,
572     .sensorTriggerOndemand = NULL,
573     .sensorCalibrate = sensorCalibrateAls,
574     .sensorCfgData = sensorCfgDataAls,
575     .sensorSendOneDirectEvt = sendLastSampleAls
576 };
577 
578 static const struct SensorInfo sensorInfoProx =
579 {
580     .sensorName = "Proximity",
581     .supportedRates = supportedRates,
582     .sensorType = SENS_TYPE_PROX,
583     .numAxis = NUM_AXIS_EMBEDDED,
584     .interrupt = NANOHUB_INT_WAKEUP,
585     .minSamples = 300
586 };
587 
588 static const struct SensorOps sensorOpsProx =
589 {
590     .sensorPower = sensorPowerProx,
591     .sensorFirmwareUpload = sensorFirmwareProx,
592     .sensorSetRate = sensorRateProx,
593     .sensorFlush = sensorFlushProx,
594     .sensorTriggerOndemand = NULL,
595     .sensorCalibrate = sensorCalibrateProx,
596     .sensorCfgData = sensorCfgDataProx,
597     .sensorSendOneDirectEvt = sendLastSampleProx
598 };
599 
600 /*
601  * Sensor i2c state machine
602  */
603 
handle_i2c_event(int state)604 static void handle_i2c_event(int state)
605 {
606     union EmbeddedDataPoint sample;
607     uint16_t c, r, g, b, ps;
608     uint8_t lastProxState;
609     int i;
610 
611     switch (state) {
612     case SENSOR_STATE_VERIFY_ID:
613         DEBUG_PRINT("REVID = 0x%02x, ID = 0x%02x\n", mTask.txrxBuf[0], mTask.txrxBuf[1]);
614 
615         // Check the sensor ID
616         if (mTask.txrxBuf[1] != AMS_TMD4903_ID) {
617             INFO_PRINT("not detected\n");
618             sensorUnregister(mTask.alsHandle);
619             sensorUnregister(mTask.proxHandle);
620             break;
621         }
622 
623         // There is no SW reset on the AMS TMD4903, so we have to reset all registers manually
624         mTask.txrxBuf[0]  = AMS_TMD4903_REG_ENABLE;
625         mTask.txrxBuf[1]  = 0x00;                                          // REG_ENABLE - reset value from datasheet
626         mTask.txrxBuf[2]  = AMS_TMD4903_ATIME_SETTING;                     // REG_ATIME - 100 ms
627         mTask.txrxBuf[3]  = AMS_TMD4903_PTIME_SETTING;                     // REG_PTIME - 50 ms
628         mTask.txrxBuf[4]  = 0xff;                                          // REG_WTIME - reset value from datasheet
629         mTask.txrxBuf[5]  = 0x00;                                          // REG_AILTL - reset value from datasheet
630         mTask.txrxBuf[6]  = 0x00;                                          // REG_AILTH - reset value from datasheet
631         mTask.txrxBuf[7]  = 0x00;                                          // REG_AIHTL - reset value from datasheet
632         mTask.txrxBuf[8]  = 0x00;                                          // REG_AIHTH - reset value from datasheet
633         mTask.txrxBuf[9]  = (AMS_TMD4903_PROX_THRESHOLD_LOW & 0xFF);       // REG_PILTL
634         mTask.txrxBuf[10] = (AMS_TMD4903_PROX_THRESHOLD_LOW >> 8) & 0xFF;  // REG_PILTH
635         mTask.txrxBuf[11] = (AMS_TMD4903_PROX_THRESHOLD_HIGH & 0xFF);      // REG_PIHTL
636         mTask.txrxBuf[12] = (AMS_TMD4903_PROX_THRESHOLD_HIGH >> 8) & 0xFF; // REG_PIHTH
637         mTask.txrxBuf[13] = 0x00;                                          // REG_PERS - reset value from datasheet
638         mTask.txrxBuf[14] = 0xa0;                                          // REG_CFG0 - reset value from datasheet
639         mTask.txrxBuf[15] = AMS_TMD4903_PGCFG0_SETTING;                    // REG_PGCFG0
640         mTask.txrxBuf[16] = AMS_TMD4903_PGCFG1_SETTING;                    // REG_PGCFG1
641         mTask.txrxBuf[17] = 0x00;                                          // REG_CFG1 - reset value from datasheet
642         i2cMasterTx(I2C_BUS_ID, I2C_ADDR, mTask.txrxBuf, 18, &i2cCallback, (void *)SENSOR_STATE_INIT_0);
643         break;
644 
645     case SENSOR_STATE_INIT_0:
646         mTask.txrxBuf[0] = AMS_TMD4903_REG_CFG4;
647         mTask.txrxBuf[1] = 0x07; // REG_CFG4 - reset value from datasheet
648         i2cMasterTx(I2C_BUS_ID, I2C_ADDR, mTask.txrxBuf, 2, &i2cCallback, (void *)SENSOR_STATE_INIT_1);
649         break;
650 
651     case SENSOR_STATE_INIT_1:
652         mTask.txrxBuf[0] = AMS_TMD4903_REG_OFFSETNL;
653         for (i = 0; i < 8; i++)
654             mTask.txrxBuf[1+i] = 0x00;
655         i2cMasterTx(I2C_BUS_ID, I2C_ADDR, mTask.txrxBuf, 9, &i2cCallback, (void *)SENSOR_STATE_INIT_2);
656         break;
657 
658     case SENSOR_STATE_INIT_2:
659         mTask.txrxBuf[0] = AMS_TMD4903_REG_INTCLEAR;
660         mTask.txrxBuf[1] = 0xFA; // REG_INTCLEAR - clear all interrupts
661         i2cMasterTx(I2C_BUS_ID, I2C_ADDR, mTask.txrxBuf, 2, &i2cCallback, (void *)SENSOR_STATE_FINISH_INIT);
662         break;
663 
664     case SENSOR_STATE_FINISH_INIT:
665         sensorRegisterInitComplete(mTask.alsHandle);
666         sensorRegisterInitComplete(mTask.proxHandle);
667         break;
668 
669     case SENSOR_STATE_START_PROX_CALIBRATION_0:
670         mTask.txrxBuf[0] = AMS_TMD4903_REG_INTENAB;
671         mTask.txrxBuf[1] = CAL_INT_ENABLE_BIT; // REG_INTENAB - enable calibration interrupt
672         i2cMasterTx(I2C_BUS_ID, I2C_ADDR, mTask.txrxBuf, 2, &i2cCallback, (void*)SENSOR_STATE_START_PROX_CALIBRATION_1);
673         break;
674 
675     case SENSOR_STATE_START_PROX_CALIBRATION_1:
676         mTask.txrxBuf[0] = AMS_TMD4903_REG_CALIB;
677         mTask.txrxBuf[1] = 0x01; // REG_CALIB - start calibration
678         i2cMasterTx(I2C_BUS_ID, I2C_ADDR, mTask.txrxBuf, 2, &i2cCallback, (void *)SENSOR_STATE_IDLE);
679         break;
680 
681     case SENSOR_STATE_FINISH_PROX_CALIBRATION_0:
682         disableInterrupt(mTask.pin, &mTask.isr);
683         extiClearPendingGpio(mTask.pin);
684 
685         mTask.proxOn = false;
686         mTask.proxCalibrating = false;
687 
688         INFO_PRINT("Calibration offsets = {%d, %d, %d, %d}\n", *((int16_t*)&mTask.txrxBuf[0]),
689                     *((int16_t*)&mTask.txrxBuf[2]), *((int16_t*)&mTask.txrxBuf[4]),
690                     *((int16_t*)&mTask.txrxBuf[6]));
691 
692         // Send calibration result
693         sendCalibrationResultProx(SENSOR_APP_EVT_STATUS_SUCCESS, (int16_t*)mTask.txrxBuf);
694 
695         mTask.txrxBuf[0] = AMS_TMD4903_REG_INTENAB;
696         mTask.txrxBuf[1] = 0x00; //  REG_INTENAB - disable all interrupts
697         i2cMasterTx(I2C_BUS_ID, I2C_ADDR, mTask.txrxBuf, 2, &i2cCallback, (void*)SENSOR_STATE_FINISH_PROX_CALIBRATION_1);
698         break;
699 
700     case SENSOR_STATE_FINISH_PROX_CALIBRATION_1:
701         mTask.txrxBuf[0] = AMS_TMD4903_REG_ENABLE;
702         mTask.txrxBuf[1] = 0x00; //  REG_ENABLE
703         i2cMasterTx(I2C_BUS_ID, I2C_ADDR, mTask.txrxBuf, 2, &i2cCallback, (void*)SENSOR_STATE_IDLE);
704         break;
705 
706     case SENSOR_STATE_ENABLING_ALS:
707         sensorSignalInternalEvt(mTask.alsHandle, SENSOR_INTERNAL_EVT_POWER_STATE_CHG, true, 0);
708         break;
709 
710     case SENSOR_STATE_ENABLING_PROX:
711         sensorSignalInternalEvt(mTask.proxHandle, SENSOR_INTERNAL_EVT_POWER_STATE_CHG, true, 0);
712         break;
713 
714     case SENSOR_STATE_DISABLING_ALS:
715         sensorSignalInternalEvt(mTask.alsHandle, SENSOR_INTERNAL_EVT_POWER_STATE_CHG, false, 0);
716         break;
717 
718     case SENSOR_STATE_DISABLING_PROX:
719         // Clear direct proximity to interrupt setting
720         mTask.txrxBuf[0] = AMS_TMD4903_REG_CFG4;
721         mTask.txrxBuf[1] = 0x07; // REG_CFG4 - reset value from datasheet
722         i2cMasterTx(I2C_BUS_ID, I2C_ADDR, mTask.txrxBuf, 2, &i2cCallback, (void *)SENSOR_STATE_DISABLING_PROX_2);
723         break;
724 
725     case SENSOR_STATE_DISABLING_PROX_2:
726         // Reset interrupt
727         mTask.txrxBuf[0] = AMS_TMD4903_REG_INTCLEAR;
728         mTask.txrxBuf[1] = 0x60; // REG_INTCLEAR - clear proximity interrupts
729         i2cMasterTx(I2C_BUS_ID, I2C_ADDR, mTask.txrxBuf, 2, &i2cCallback, (void *)SENSOR_STATE_DISABLING_PROX_3);
730         break;
731 
732     case SENSOR_STATE_DISABLING_PROX_3:
733         sensorSignalInternalEvt(mTask.proxHandle, SENSOR_INTERNAL_EVT_POWER_STATE_CHG, false, 0);
734         break;
735 
736     case SENSOR_STATE_ALS_SAMPLING:
737         c = *(uint16_t*)(mTask.txrxBuf);
738         r = *(uint16_t*)(mTask.txrxBuf+2);
739         g = *(uint16_t*)(mTask.txrxBuf+4);
740         b = *(uint16_t*)(mTask.txrxBuf+6);
741 
742         DEBUG_PRINT("als sample ready: c=%u r=%u g=%u b=%u\n", c, r, g, b);
743 
744         if (mTask.alsOn) {
745             sample.fdata = getLuxFromAlsData(c, r, g, b);
746 
747             if (mTask.alsCalibrating) {
748                 sendCalibrationResultAls(SENSOR_APP_EVT_STATUS_SUCCESS, sample.fdata);
749 
750                 mTask.alsOn = false;
751                 mTask.alsCalibrating = false;
752 
753                 mTask.txrxBuf[0] = AMS_TMD4903_REG_ENABLE;
754                 mTask.txrxBuf[1] = 0; // REG_ENABLE
755                 i2cMasterTx(I2C_BUS_ID, I2C_ADDR, mTask.txrxBuf, 2, &i2cCallback, (void*)SENSOR_STATE_IDLE);
756             } else if (mTask.lastAlsSample.idata != sample.idata) {
757                 osEnqueueEvt(sensorGetMyEventType(SENS_TYPE_ALS), sample.vptr, NULL);
758                 mTask.lastAlsSample.fdata = sample.fdata;
759             }
760         }
761 
762         break;
763 
764     case SENSOR_STATE_PROX_SAMPLING:
765         ps = *(uint16_t*)(mTask.txrxBuf);
766         lastProxState = mTask.lastProxState;
767 
768         DEBUG_PRINT("prox sample ready: prox=%u\n", ps);
769 
770         if (mTask.proxOn) {
771 #if PROX_STREAMING
772             (void)lastProxState;
773             sample.fdata = ps;
774             osEnqueueEvt(sensorGetMyEventType(SENS_TYPE_PROX), sample.vptr, NULL);
775 #else
776             if (ps > AMS_TMD4903_PROX_THRESHOLD_HIGH) {
777                 sample.fdata = AMS_TMD4903_REPORT_NEAR_VALUE;
778                 mTask.lastProxState = PROX_STATE_NEAR;
779             } else {
780                 sample.fdata = AMS_TMD4903_REPORT_FAR_VALUE;
781                 mTask.lastProxState = PROX_STATE_FAR;
782             }
783 
784             if (mTask.lastProxState != lastProxState)
785                 osEnqueueEvt(sensorGetMyEventType(SENS_TYPE_PROX), sample.vptr, NULL);
786 #endif
787 
788 #if PROX_STREAMING
789             // clear the interrupt
790             mTask.txrxBuf[0] = AMS_TMD4903_REG_INTCLEAR;
791             mTask.txrxBuf[1] = 0x60; // REG_INTCLEAR - reset proximity interrupts
792             i2cMasterTx(I2C_BUS_ID, I2C_ADDR, mTask.txrxBuf, 2, &i2cCallback, (void *)SENSOR_STATE_IDLE);
793 #else
794             // The TMD4903 direct interrupt mode does not work properly if enabled while something is covering the sensor,
795             // so we need to wait until it is far.
796             if (mTask.lastProxState == PROX_STATE_FAR) {
797                 disableInterrupt(mTask.pin, &mTask.isr);
798                 extiClearPendingGpio(mTask.pin);
799 
800                 // Switch to proximity interrupt direct mode
801                 mTask.txrxBuf[0] = AMS_TMD4903_REG_CFG4;
802                 mTask.txrxBuf[1] = 0x27; // REG_CFG4 - proximity state direct to interrupt pin
803                 i2cMasterTx(I2C_BUS_ID, I2C_ADDR, mTask.txrxBuf, 2, &i2cCallback, (void *)SENSOR_STATE_PROX_TRANSITION_0);
804             } else {
805                 // If we are in the "near" state, we cannot change to direct interrupt mode, so just clear the interrupt
806                 mTask.txrxBuf[0] = AMS_TMD4903_REG_INTCLEAR;
807                 mTask.txrxBuf[1] = 0x60; // REG_INTCLEAR - reset proximity interrupts
808                 i2cMasterTx(I2C_BUS_ID, I2C_ADDR, mTask.txrxBuf, 2, &i2cCallback, (void *)SENSOR_STATE_IDLE);
809             }
810 #endif
811         }
812         break;
813 
814     case SENSOR_STATE_PROX_TRANSITION_0:
815         if (mTask.proxOn) {
816             mTask.proxDirectMode = true;
817             extiClearPendingGpio(mTask.pin);
818             enableInterrupt(mTask.pin, &mTask.isr, EXTI_TRIGGER_BOTH);
819         }
820         break;
821 
822     default:
823         break;
824     }
825 }
826 
827 /*
828  * Main driver entry points
829  */
830 
init_app(uint32_t myTid)831 static bool init_app(uint32_t myTid)
832 {
833     INFO_PRINT("task starting\n");
834 
835     /* Set up driver private data */
836     mTask.tid = myTid;
837     mTask.alsOn = false;
838     mTask.proxOn = false;
839     mTask.lastAlsSample.idata = AMS_TMD4903_ALS_INVALID;
840     mTask.lastProxState = PROX_STATE_INIT;
841     mTask.proxCalibrating = false;
842     mTask.alsOffset = 1.0f;
843 
844     mTask.pin = gpioRequest(PROX_INT_PIN);
845     gpioConfigInput(mTask.pin, GPIO_SPEED_LOW, GPIO_PULL_NONE);
846     syscfgSetExtiPort(mTask.pin);
847     mTask.isr.func = proxIsr;
848 
849     mTask.alsHandle = sensorRegister(&sensorInfoAls, &sensorOpsAls, NULL, false);
850     mTask.proxHandle = sensorRegister(&sensorInfoProx, &sensorOpsProx, NULL, false);
851 
852     osEventSubscribe(myTid, EVT_APP_START);
853 
854     return true;
855 }
856 
end_app(void)857 static void end_app(void)
858 {
859     disableInterrupt(mTask.pin, &mTask.isr);
860     extiUnchainIsr(PROX_IRQ, &mTask.isr);
861     extiClearPendingGpio(mTask.pin);
862     gpioRelease(mTask.pin);
863 
864     sensorUnregister(mTask.alsHandle);
865     sensorUnregister(mTask.proxHandle);
866 
867     i2cMasterRelease(I2C_BUS_ID);
868 }
869 
handle_event(uint32_t evtType,const void * evtData)870 static void handle_event(uint32_t evtType, const void* evtData)
871 {
872     switch (evtType) {
873     case EVT_APP_START:
874         i2cMasterRequest(I2C_BUS_ID, I2C_SPEED);
875 
876         // Read the ID
877         mTask.txrxBuf[0] = AMS_TMD4903_REG_REVID;
878         i2cMasterTxRx(I2C_BUS_ID, I2C_ADDR, mTask.txrxBuf, 1, mTask.txrxBuf, 2, &i2cCallback, (void *)SENSOR_STATE_VERIFY_ID);
879         break;
880 
881     case EVT_SENSOR_I2C:
882         handle_i2c_event((int)evtData);
883         break;
884 
885     case EVT_SENSOR_ALS_INTERRUPT:
886         disableInterrupt(mTask.pin, &mTask.isr);
887         extiClearPendingGpio(mTask.pin);
888         // NOTE: fall-through to initiate read of ALS data registers
889 
890     case EVT_SENSOR_ALS_TIMER:
891         mTask.txrxBuf[0] = AMS_TMD4903_REG_CDATAL;
892         i2cMasterTxRx(I2C_BUS_ID, I2C_ADDR, mTask.txrxBuf, 1, mTask.txrxBuf, 8, &i2cCallback, (void *)SENSOR_STATE_ALS_SAMPLING);
893         break;
894 
895     case EVT_SENSOR_PROX_INTERRUPT:
896         if (mTask.proxCalibrating) {
897             mTask.txrxBuf[0] = AMS_TMD4903_REG_OFFSETNL;
898             i2cMasterTxRx(I2C_BUS_ID, I2C_ADDR, mTask.txrxBuf, 1, mTask.txrxBuf, 8, &i2cCallback, (void *)SENSOR_STATE_FINISH_PROX_CALIBRATION_0);
899         } else {
900             mTask.txrxBuf[0] = AMS_TMD4903_REG_PDATAL;
901             i2cMasterTxRx(I2C_BUS_ID, I2C_ADDR, mTask.txrxBuf, 1, mTask.txrxBuf, 2, &i2cCallback, (void *)SENSOR_STATE_PROX_SAMPLING);
902         }
903         break;
904 
905     }
906 }
907 
908 INTERNAL_APP_INIT(AMS_TMD4903_APP_ID, AMS_TMD4903_APP_VERSION, init_app, end_app, handle_event);
909 
910