Home | History | Annotate | Download | only in ams_tmd4903
      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.
    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().
    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 
    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 
    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 
    362 static bool disableInterrupt(struct Gpio *pin, struct ChainedIsr *isr)
    363 {
    364     extiUnchainIsr(PROX_IRQ, isr);
    365     extiDisableIntGpio(pin);
    366     return true;
    367 }
    368 
    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 
    382 static void alsTimerCallback(uint32_t timerId, void *cookie)
    383 {
    384     osEnqueuePrivateEvt(EVT_SENSOR_ALS_TIMER, cookie, NULL, mTask.tid);
    385 }
    386 
    387 static inline uint32_t getAlsGainFromSetting(uint8_t gainSetting)
    388 {
    389     return 0x1 << (2 * gainSetting);
    390 }
    391 
    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 
    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 
    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 
    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 
    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 
    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 
    500 static bool sensorFirmwareAls(void *cookie)
    501 {
    502     return sensorSignalInternalEvt(mTask.alsHandle, SENSOR_INTERNAL_EVT_FW_STATE_CHG, 1, 0);
    503 }
    504 
    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 
    515 static bool sensorFlushAls(void *cookie)
    516 {
    517     return osEnqueueEvt(sensorGetMyEventType(SENS_TYPE_ALS), SENSOR_DATA_EVENT_FLUSH, NULL);
    518 }
    519 
    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 
    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 
    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 
    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 
    587 static bool sensorFirmwareProx(void *cookie)
    588 {
    589     return sensorSignalInternalEvt(mTask.proxHandle, SENSOR_INTERNAL_EVT_FW_STATE_CHG, 1, 0);
    590 }
    591 
    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 
    602 static bool sensorFlushProx(void *cookie)
    603 {
    604     return osEnqueueEvt(sensorGetMyEventType(SENS_TYPE_PROX), SENSOR_DATA_EVENT_FLUSH, NULL);
    605 }
    606 
    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 
    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 
    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 
    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 
    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 
    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  */
    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 
    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 
    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 
   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