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