/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <stdlib.h> #include <string.h> #include <eventnums.h> #include <heap.h> #include <hostIntf.h> #include <i2c.h> #include <leds_gpio.h> #include <nanohubPacket.h> #include <sensors.h> #include <seos.h> #include <timer.h> #include <util.h> #include <variant/variant.h> #define LP3943_LEDS_APP_ID APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 21) #define LP3943_LEDS_APP_VERSION 1 #ifdef LP3943_I2C_BUS_ID #define I2C_BUS_ID LP3943_I2C_BUS_ID #else #define I2C_BUS_ID 0 #endif #ifdef LP3943_I2C_SPEED #define I2C_SPEED LP3943_I2C_SPEED #else #define I2C_SPEED 400000 #endif #ifdef LP3943_I2C_ADDR #define I2C_ADDR LP3943_I2C_ADDR #else #define I2C_ADDR 0x60 #endif #define LP3943_REG_PSC0 0x02 #define LP3943_REG_PWM0 0x03 #define LP3943_REG_PSC1 0x04 #define LP3943_REG_PWM1 0x05 #define LP3943_REG_LS0 0x06 #define LP3943_REG_LS1 0x07 #define LP3943_REG_LS2 0x08 #define LP3943_REG_LS3 0x09 #define LP3943_MAX_PENDING_I2C_REQUESTS 4 #define LP3943_MAX_I2C_TRANSFER_SIZE 2 #define LP3943_MAX_LED_NUM 16 #define LP3943_MAX_LED_SECTION 4 #ifndef LP3943_DBG_ENABLE #define LP3943_DBG_ENABLE 0 #endif #define LP3943_DBG_VALUE 0x55 enum LP3943SensorEvents { EVT_SENSOR_I2C = EVT_APP_START + 1, EVT_SENSOR_LEDS_TIMER, EVT_TEST, }; enum LP3943TaskState { STATE_RESET, STATE_CLEAN_LS1, STATE_CLEAN_LS2, STATE_FINISH_INIT, STATE_LED, }; struct I2cTransfer { size_t tx; size_t rx; int err; uint8_t txrxBuf[LP3943_MAX_I2C_TRANSFER_SIZE]; uint8_t state; bool inUse; }; static struct LP3943Task { uint32_t id; uint32_t sHandle; uint32_t num; bool ledsOn; bool blink; uint32_t ledsTimerHandle; uint8_t led[LP3943_MAX_LED_SECTION]; struct I2cTransfer transfers[LP3943_MAX_PENDING_I2C_REQUESTS]; } mTask; /* sensor callbacks from nanohub */ static void i2cCallback(void *cookie, size_t tx, size_t rx, int err) { struct I2cTransfer *xfer = cookie; xfer->tx = tx; xfer->rx = rx; xfer->err = err; osEnqueuePrivateEvt(EVT_SENSOR_I2C, cookie, NULL, mTask.id); if (err != 0) osLog(LOG_INFO, "[LP3943] i2c error (tx: %d, rx: %d, err: %d)\n", tx, rx, err); } static void sensorLP3943TimerCallback(uint32_t timerId, void *data) { osEnqueuePrivateEvt(EVT_SENSOR_LEDS_TIMER, data, NULL, mTask.id); } static uint32_t ledsRates[] = { SENSOR_HZ(0.1), SENSOR_HZ(0.5), SENSOR_HZ(1.0f), SENSOR_HZ(2.0f), 0 }; // should match "supported rates in length" static const uint64_t ledsRatesRateVals[] = { 10 * 1000000000ULL, 2 * 1000000000ULL, 1 * 1000000000ULL, 1000000000ULL / 2, }; // Allocate a buffer and mark it as in use with the given state, or return NULL // if no buffers available. Must *not* be called from interrupt context. static struct I2cTransfer *allocXfer(uint8_t state) { size_t i; for (i = 0; i < ARRAY_SIZE(mTask.transfers); i++) { if (!mTask.transfers[i].inUse) { mTask.transfers[i].inUse = true; mTask.transfers[i].state = state; return &mTask.transfers[i]; } } osLog(LOG_ERROR, "[LP3943]: Ran out of i2c buffers!"); return NULL; } // Helper function to release I2cTranfer structure. static inline void releaseXfer(struct I2cTransfer *xfer) { xfer->inUse = false; } // Helper function to write a one byte register. Returns true if we got a // successful return value from i2cMasterTx(). static bool writeRegister(uint8_t reg, uint8_t value, uint8_t state) { struct I2cTransfer *xfer = allocXfer(state); int ret = -1; if (xfer != NULL) { xfer->txrxBuf[0] = reg; xfer->txrxBuf[1] = value; ret = i2cMasterTx(I2C_BUS_ID, I2C_ADDR, xfer->txrxBuf, 2, i2cCallback, xfer); if (ret) releaseXfer(xfer); } return (ret == 0); } /* Sensor Operations */ static bool sensorLP3943Power(bool on, void *cookie) { if (mTask.ledsTimerHandle) { timTimerCancel(mTask.ledsTimerHandle); mTask.ledsTimerHandle = 0; } mTask.ledsOn = on; return sensorSignalInternalEvt(mTask.sHandle, SENSOR_INTERNAL_EVT_POWER_STATE_CHG, on, 0); } static bool sensorLP3943FwUpload(void *cookie) { return sensorSignalInternalEvt(mTask.sHandle, SENSOR_INTERNAL_EVT_FW_STATE_CHG, 1, 0); } static bool sensorLP3943SetRate(uint32_t rate, uint64_t latency, void *cookie) { if (mTask.ledsTimerHandle) timTimerCancel(mTask.ledsTimerHandle); mTask.ledsTimerHandle = timTimerSet(sensorTimerLookupCommon(ledsRates, ledsRatesRateVals, rate), 0, 50, sensorLP3943TimerCallback, NULL, false); return sensorSignalInternalEvt(mTask.sHandle, SENSOR_INTERNAL_EVT_RATE_CHG, rate, latency); } static bool sensorCfgDataLedsLP3943(void *cfg, void *cookie) { struct LedsCfg *lcfg = (struct LedsCfg *)cfg; uint8_t laddr = LP3943_REG_LS0; uint8_t lval; uint8_t index; uint8_t lnum; if (lcfg->led_num >= mTask.num) { osLog(LOG_INFO, "Wrong led number %"PRIu32"\n", lcfg->led_num); return false; } index = lcfg->led_num >> 2; lnum = (lcfg->led_num & 0x3) << 1; lval = mTask.led[index]; laddr += index; if (lcfg->value) { lval |= (1 << lnum); } else { lval &= ~(1 << lnum); } writeRegister(laddr, lval, STATE_LED); mTask.led[index] = lval; osLog(LOG_INFO, "Set led[%"PRIu32"]=%"PRIu32"\n", lcfg->led_num, lcfg->value); return true; } static void sensorLedsOnOff(bool flag) { uint8_t laddr = LP3943_REG_LS0; uint8_t lval; uint8_t index; for (index=0; index < LP3943_MAX_LED_SECTION; index++) { lval = flag ? mTask.led[index] : 0; writeRegister(laddr + index, lval, STATE_LED); } } static const struct SensorInfo sensorInfoLedsLP3943 = { .sensorName = "Leds-LP3943", .sensorType = SENS_TYPE_LEDS_I2C, .supportedRates = ledsRates, }; static const struct SensorOps sensorOpsLedsLP3943 = { .sensorPower = sensorLP3943Power, .sensorFirmwareUpload = sensorLP3943FwUpload, .sensorSetRate = sensorLP3943SetRate, .sensorCfgData = sensorCfgDataLedsLP3943, }; static void handleI2cEvent(struct I2cTransfer *xfer) { switch (xfer->state) { case STATE_RESET: writeRegister(LP3943_REG_LS1, 0, STATE_CLEAN_LS1); break; case STATE_CLEAN_LS1: writeRegister(LP3943_REG_LS2, 0, STATE_FINISH_INIT); break; case STATE_CLEAN_LS2: writeRegister(LP3943_REG_LS3, 0, STATE_FINISH_INIT); break; case STATE_FINISH_INIT: if (xfer->err != 0) { osLog(LOG_INFO, "[LP3943] not detected\n"); } else { osLog(LOG_INFO, "[LP3943] detected\n"); sensorRegisterInitComplete(mTask.sHandle); if (LP3943_DBG_ENABLE) { mTask.ledsOn = true; mTask.led[0] = LP3943_DBG_VALUE; osEnqueuePrivateEvt(EVT_TEST, NULL, NULL, mTask.id); } } break; case STATE_LED: break; default: break; } releaseXfer(xfer); } static void handleEvent(uint32_t evtType, const void* evtData) { switch (evtType) { case EVT_APP_START: osEventUnsubscribe(mTask.id, EVT_APP_START); i2cMasterRequest(I2C_BUS_ID, I2C_SPEED); /* Reset Leds */ writeRegister(LP3943_REG_LS0, 0, STATE_RESET); break; case EVT_SENSOR_I2C: handleI2cEvent((struct I2cTransfer *)evtData); break; case EVT_SENSOR_LEDS_TIMER: if (!mTask.ledsOn) break; mTask.blink = !mTask.blink; sensorLedsOnOff(mTask.blink); break; case EVT_TEST: sensorLP3943SetRate(SENSOR_HZ(1), 0, NULL); break; default: break; } } static bool startTask(uint32_t taskId) { mTask.id = taskId; mTask.num = LP3943_MAX_LED_NUM; memset(mTask.led, 0x00, LP3943_MAX_LED_SECTION); mTask.ledsOn = mTask.blink = false; /* Register sensors */ mTask.sHandle = sensorRegister(&sensorInfoLedsLP3943, &sensorOpsLedsLP3943, NULL, false); osEventSubscribe(taskId, EVT_APP_START); return true; } static void endTask(void) { sensorUnregister(mTask.sHandle); } INTERNAL_APP_INIT(LP3943_LEDS_APP_ID, LP3943_LEDS_APP_VERSION, startTask, endTask, handleEvent);