| /* |
| * Copyright (C) 2017 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 <atomic.h> |
| #include <gpio.h> |
| #include <isr.h> |
| #include <nanohubPacket.h> |
| #include <plat/exti.h> |
| #include <plat/gpio.h> |
| #include <platform.h> |
| #include <plat/syscfg.h> |
| #include <plat/rtc.h> |
| #include <sensors.h> |
| #include <seos.h> |
| #include <slab.h> |
| #include <heap.h> |
| #include <i2c.h> |
| #include <timer.h> |
| #include <variant/sensType.h> |
| #include <cpu/cpuMath.h> |
| #include <floatRt.h> |
| |
| #include <stdlib.h> |
| #include <string.h> |
| #include <variant/variant.h> |
| |
| #define ST_ACC44_APP_ID APP_ID_MAKE(NANOHUB_VENDOR_STMICRO, 7) |
| |
| /* Sensor registers */ |
| #define ST_ACC44_WAI_REG_ADDR 0x0F |
| #define ST_ACC44_WAI_REG_VAL 0x44 |
| |
| /* |
| * CTRL1 Register |
| * |
| * CTRL1[7:4] := ODR |
| * CTRL1[3:2] := MODE |
| * CTRL1[1:0] := LP_MODE |
| */ |
| #define ST_ACC44_CTRL1_REG 0x20 |
| #define ST_ACC44_ODR_POWER_DOWN 0x00 |
| #define ST_ACC44_ODR_12_5_HZ 0x20 |
| #define ST_ACC44_ODR_25_HZ 0x30 |
| #define ST_ACC44_ODR_50_HZ 0x40 |
| #define ST_ACC44_ODR_100_HZ 0x50 |
| #define ST_ACC44_ODR_200_HZ 0x60 |
| #define ST_ACC44_ODR_400_HZ 0x70 |
| #define ST_ACC44_ODR_800_HZ 0x80 |
| #define ST_ACC44_ODR_1600_HZ 0x90 |
| #define ST_ACC44_HIPERF_MODE 0x04 |
| #define ST_ACC44_CTRL1_DEFVAL (ST_ACC44_HIPERF_MODE) |
| |
| /* |
| * CTRL2 Register |
| * |
| * CTRL2[7] := BOOT |
| * CTRL2[6] := SOFT_RESET |
| * CTRL2[3] := BDU |
| */ |
| #define ST_ACC44_CTRL2_REG 0x21 |
| #define ST_ACC44_CTRL2_BOOT 0x80 |
| #define ST_ACC44_CTRL2_SW_RST 0x40 |
| #define ST_ACC44_CTRL2_BDU 0x08 |
| #define ST_ACC44_CTRL2_IF_ADD_INC 0x04 |
| #define ST_ACC44_CTRL2_DEFVAL (ST_ACC44_CTRL2_BDU | ST_ACC44_CTRL2_IF_ADD_INC) |
| |
| /* |
| * CTRL3 Register |
| */ |
| #define ST_ACC44_CTRL3_REG 0x22 |
| #define ST_ACC44_CTRL3_LIR 0x10 |
| |
| /* |
| * CTRL4 Register |
| * |
| * CTRL4[7] := INT1_6D |
| * CTRL4[6] := INT1_SINGLE_TAP |
| * CTRL4[5] := INT1_WU |
| * CTRL4[4] := INT1_FF |
| * CTRL4[3] := INT1_TAP |
| * CTRL4[2] := INT1_DIFF5 |
| * CTRL4[1] := INT1_FTH |
| * CTRL4[0] := INT1_DRDY |
| */ |
| #define ST_ACC44_CTRL4_REG 0x23 |
| #define ST_ACC44_CTRL4_INT1_6D 0x80 |
| #define ST_ACC44_CTRL4_INT1_STAP 0x40 |
| #define ST_ACC44_CTRL4_INT1_WU 0x20 |
| #define ST_ACC44_CTRL4_INT1_FF 0x10 |
| #define ST_ACC44_CTRL4_INT1_DTAP 0x08 |
| #define ST_ACC44_CTRL4_INT1_DIFF5 0x04 |
| #define ST_ACC44_CTRL4_INT1_FTH 0x02 |
| #define ST_ACC44_CTRL4_INT1_DRDY 0x01 |
| |
| /* |
| * CTRL5 Register |
| */ |
| #define ST_ACC44_CTRL5_REG 0x24 |
| |
| /* |
| * CTRL6 Register |
| * |
| * CTRL6[5:4] := FS |
| */ |
| #define ST_ACC44_CTRL6_REG 0x25 |
| #define ST_ACC44_CTRL6_FS_2G 0x00 |
| #define ST_ACC44_CTRL6_FS_4G 0x10 |
| #define ST_ACC44_CTRL6_FS_8G 0x20 |
| #define ST_ACC44_CTRL6_FS_16G 0x30 |
| |
| /* |
| * STATUS Register |
| */ |
| #define ST_ACC44_STATUS_REG_ADDR 0x27 |
| #define ST_ACC44_STATUS_REG_FTH 0x80 |
| #define ST_ACC44_STATUS_REG_DRDY 0x01 |
| |
| /* |
| * OUTXL Register |
| */ |
| #define ST_ACC44_OUTXL_REG_ADDR 0x28 |
| |
| /* |
| * value in m/s2 per LSB (in high-resolution mode @8g) |
| * Since samples are 14-bit left aligned, the value |
| * must also be right-shifted by 2. |
| * |
| * (9.80665 * 0.976) / (4 * 1000) |
| */ |
| #define ST_ACC44_KSCALE 0.0023928226 |
| |
| |
| /* Enable auto-increment of the I2C subaddress (to allow I2C multiple ops) */ |
| #define ST_ACC44_I2C_AUTO_INCR 0x80 |
| |
| #define INFO_PRINT(fmt, ...) \ |
| do { \ |
| osLog(LOG_INFO, "%s " fmt, "[ST_ACC44]", ##__VA_ARGS__); \ |
| } while (0); |
| |
| #define DEBUG_PRINT(fmt, ...) \ |
| do { \ |
| if (ST_ACC44_DBG_ENABLED) { \ |
| osLog(LOG_DEBUG, "%s " fmt, "[ST_ACC44]", ##__VA_ARGS__); \ |
| } \ |
| } while (0); |
| |
| #define ERROR_PRINT(fmt, ...) \ |
| do { \ |
| osLog(LOG_ERROR, "%s " fmt, "[ST_ACC44]", ##__VA_ARGS__); \ |
| } while (0); |
| |
| /* DO NOT MODIFY, just to avoid compiler error if not defined using FLAGS */ |
| #ifndef ST_ACC44_DBG_ENABLED |
| #define ST_ACC44_DBG_ENABLED 0 |
| #endif /* ST_ACC44_DBG_ENABLED */ |
| |
| enum st_acc44_SensorEvents |
| { |
| EVT_COMM_DONE = EVT_APP_START + 1, |
| EVT_SENSOR_INTERRUPT, |
| }; |
| |
| enum st_acc44_SensorState { |
| SENSOR_BOOT, |
| SENSOR_VERIFY_ID, |
| SENSOR_INIT, |
| SENSOR_IDLE, |
| SENSOR_ACCEL_POWER_UP, |
| SENSOR_ACCEL_POWER_DOWN, |
| SENSOR_CHANGE_RATE, |
| SENSOR_READ_SAMPLES, |
| }; |
| |
| #ifndef ST_ACC44_I2C_BUS_ID |
| #error "ST_ACC44_I2C_BUS_ID is not defined; please define in variant.h" |
| #endif |
| |
| #ifndef ST_ACC44_I2C_SPEED |
| #error "ST_ACC44_I2C_SPEED is not defined; please define in variant.h" |
| #endif |
| |
| #ifndef ST_ACC44_I2C_ADDR |
| #error "ST_ACC44_I2C_ADDR is not defined; please define in variant.h" |
| #endif |
| |
| #ifndef ST_ACC44_INT_PIN |
| #error "ST_ACC44_INT_PIN is not defined; please define in variant.h" |
| #endif |
| |
| #ifndef ST_ACC44_INT_IRQ |
| #error "ST_ACC44_INT_IRQ is not defined; please define in variant.h" |
| #endif |
| |
| #ifndef ST_ACC44_TO_ANDROID_COORDINATE |
| #error "ST_ACC44_TO_ANDROID_COORDINATE is not defined; please define in variant.h" |
| #endif |
| |
| #define RAW_TO_MS2(raw_axis) ((float)raw_axis * ST_ACC44_KSCALE) |
| |
| #define ST_ACC44_MAX_PENDING_I2C_REQUESTS 10 |
| #define ST_ACC44_MAX_I2C_TRANSFER_SIZE 6 |
| #define ST_ACC44_MAX_ACC_EVENTS 50 |
| |
| struct I2cTransfer |
| { |
| size_t tx; |
| size_t rx; |
| int err; |
| uint8_t txrxBuf[ST_ACC44_MAX_I2C_TRANSFER_SIZE]; |
| bool last; |
| bool inUse; |
| uint32_t delay; |
| }; |
| |
| /* Task structure */ |
| struct st_acc44_Task { |
| uint32_t tid; |
| |
| struct SlabAllocator *accDataSlab; |
| |
| volatile uint8_t state; //task state, type enum st_mag40_SensorState, do NOT change this directly |
| bool accOn; |
| uint32_t sample_rate_ns; |
| uint32_t irq_rate_ns; |
| uint32_t rate; |
| uint32_t latency; |
| uint8_t currentODR; |
| uint8_t samplesToDiscard; |
| uint64_t Timestamp; |
| uint64_t lastTime; |
| |
| bool pendingInt; |
| bool pendingSetPower; |
| bool pendingSetRate; |
| uint32_t pendingRate; |
| uint32_t pendingLatency; |
| bool pendingPower; |
| |
| struct I2cTransfer transfers[ST_ACC44_MAX_PENDING_I2C_REQUESTS]; |
| |
| /* Communication functions */ |
| bool (*comm_tx)(uint8_t addr, uint8_t data, uint32_t delay, bool last); |
| bool (*comm_rx)(uint8_t addr, uint16_t len, uint32_t delay, bool last); |
| |
| /* irq */ |
| struct Gpio *Int1; |
| struct ChainedIsr Isr1; |
| uint32_t int_num; |
| |
| /* sensors */ |
| uint32_t accHandle; |
| }; |
| |
| static struct st_acc44_Task mTask; |
| |
| #if DBG_STATE |
| #define PRI_STATE PRIi32 |
| static int32_t getStateName(int32_t s) { |
| return s; |
| } |
| #endif |
| |
| // Atomic get state |
| #define GET_STATE() (atomicReadByte(&mTask.state)) |
| |
| // Atomic set state, this set the state to arbitrary value, use with caution |
| #define SET_STATE(s) do{\ |
| atomicWriteByte(&mTask.state, (s));\ |
| }while(0) |
| |
| // Atomic switch state from IDLE to desired state. |
| static bool trySwitchState(enum st_acc44_SensorState newState) { |
| #if DBG_STATE |
| bool ret = atomicCmpXchgByte(&mTask.state, SENSOR_IDLE, newState); |
| uint8_t prevState = ret ? SENSOR_IDLE : GET_STATE(); |
| DEBUG_PRINT("switch state %" PRI_STATE "->%" PRI_STATE ", %s\n", |
| getStateName(prevState), getStateName(newState), ret ? "ok" : "failed"); |
| return ret; |
| #else |
| return atomicCmpXchgByte(&mTask.state, SENSOR_IDLE, newState); |
| #endif |
| } |
| |
| #define DEC_INFO(name, type, axis, inter, samples, rates, raw, scale) \ |
| .sensorName = name, \ |
| .sensorType = type, \ |
| .numAxis = axis, \ |
| .interrupt = inter, \ |
| .minSamples = samples, \ |
| .supportedRates = rates, \ |
| .rawType = raw, \ |
| .rawScale = scale, |
| |
| static uint32_t st_acc44_Rates[] = { |
| SENSOR_HZ(25.0f/2.0f), |
| SENSOR_HZ(25.0f), |
| SENSOR_HZ(50.0f), |
| SENSOR_HZ(100.0f), |
| SENSOR_HZ(200.0f), |
| SENSOR_HZ(400.0f), |
| SENSOR_HZ(800.0f), |
| 0 |
| }; |
| |
| static uint32_t st_acc44_Rates_in_ns[] = { |
| 80000000, /* 12.5 Hz */ |
| 40000000, /* 25 Hz */ |
| 20000000, /* 50 Hz */ |
| 10000000, /* 100 Hz */ |
| 5000000, /* 200 Hz */ |
| 2500000, /* 400 Hz */ |
| 1250000, /* 800 Hz */ |
| 0 |
| }; |
| |
| static uint32_t st_acc44_regVal[] = { |
| ST_ACC44_ODR_12_5_HZ, |
| ST_ACC44_ODR_25_HZ, |
| ST_ACC44_ODR_50_HZ, |
| ST_ACC44_ODR_100_HZ, |
| ST_ACC44_ODR_200_HZ, |
| ST_ACC44_ODR_400_HZ, |
| ST_ACC44_ODR_800_HZ, |
| ST_ACC44_ODR_1600_HZ, |
| }; |
| |
| static uint8_t st_acc44_computeOdr(uint32_t rate) |
| { |
| int i; |
| |
| for (i = 0; i < (ARRAY_SIZE(st_acc44_Rates) - 1); i++) { |
| if (st_acc44_Rates[i] == rate) |
| break; |
| } |
| if (i == (ARRAY_SIZE(st_acc44_Rates) -1 )) { |
| ERROR_PRINT("ODR not valid! Choosed smallest ODR available\n"); |
| i = 0; |
| } |
| |
| return i; |
| } |
| |
| static uint32_t st_acc44_Rate_hz_to_ns(uint32_t rate) |
| { |
| int i; |
| |
| if ((i = st_acc44_computeOdr(rate)) >= 0) |
| return st_acc44_Rates_in_ns[i]; |
| |
| return 0; |
| } |
| |
| static const struct SensorInfo st_acc44_SensorInfo = |
| { |
| DEC_INFO("Accelerometer", SENS_TYPE_ACCEL, NUM_AXIS_THREE, NANOHUB_INT_NONWAKEUP, |
| 600, st_acc44_Rates, SENS_TYPE_ACCEL_RAW, 1.0f / ST_ACC44_KSCALE) |
| }; |
| |
| static bool st_acc44_Power(bool on, void *cookie) |
| { |
| bool oldMode = mTask.accOn; |
| bool newMode = on; |
| uint32_t state = on ? SENSOR_ACCEL_POWER_UP : SENSOR_ACCEL_POWER_DOWN; |
| bool ret = true; |
| |
| INFO_PRINT("Power %s\n", on ? "on" : "off"); |
| |
| if (trySwitchState(state)) { |
| if (oldMode != newMode) { |
| if (on) { |
| ret = mTask.comm_tx(ST_ACC44_CTRL1_REG, ST_ACC44_ODR_12_5_HZ | |
| ST_ACC44_CTRL1_DEFVAL, 0, true); |
| } else { |
| ret = mTask.comm_tx(ST_ACC44_CTRL1_REG, ST_ACC44_ODR_POWER_DOWN | |
| ST_ACC44_CTRL1_DEFVAL, 0, true); |
| } |
| } else |
| sensorSignalInternalEvt(mTask.accHandle, |
| SENSOR_INTERNAL_EVT_POWER_STATE_CHG, on, 0); |
| } else { |
| mTask.pendingSetPower = true; |
| mTask.pendingPower = on; |
| } |
| |
| return ret; |
| } |
| |
| static bool st_acc44_FwUpload(void *cookie) |
| { |
| INFO_PRINT("FwUpload\n"); |
| return sensorSignalInternalEvt(mTask.accHandle, SENSOR_INTERNAL_EVT_FW_STATE_CHG, 1, 0); |
| } |
| |
| static bool st_acc44_SetRate(uint32_t rate, uint64_t latency, void *cookie) |
| { |
| uint8_t num = 0; |
| |
| INFO_PRINT("SetRate %lu Hz - %llu ns\n", rate, latency); |
| |
| if (trySwitchState(SENSOR_CHANGE_RATE)) { |
| num = st_acc44_computeOdr(rate); |
| mTask.currentODR = st_acc44_regVal[num]; |
| mTask.latency = latency; |
| mTask.rate = rate; |
| mTask.sample_rate_ns = st_acc44_Rate_hz_to_ns(rate); |
| mTask.samplesToDiscard = 2; |
| mTask.lastTime = 0; |
| |
| /* one interrupt every sample */ |
| mTask.irq_rate_ns = mTask.sample_rate_ns; |
| |
| mTask.comm_rx(ST_ACC44_OUTXL_REG_ADDR, 6, 0, false); |
| mTask.comm_tx(ST_ACC44_CTRL4_REG, ST_ACC44_CTRL4_INT1_DRDY, 0, false); |
| mTask.comm_tx(ST_ACC44_CTRL1_REG, mTask.currentODR | ST_ACC44_CTRL1_DEFVAL, 0, true); |
| } else { |
| mTask.pendingSetRate = true; |
| mTask.pendingRate = rate; |
| mTask.pendingLatency = latency; |
| } |
| |
| return true; |
| } |
| |
| static bool st_acc44_Flush(void *cookie) |
| { |
| INFO_PRINT("Flush\n"); |
| return osEnqueueEvt(sensorGetMyEventType(SENS_TYPE_ACCEL), SENSOR_DATA_EVENT_FLUSH, NULL); |
| } |
| |
| static bool st_acc44_SelfTest(void *cookie) |
| { |
| INFO_PRINT("SelfTest\n"); |
| return true; |
| } |
| |
| #define DEC_OPS(power, firmware, rate, flush, test, cal, cfg) \ |
| .sensorPower = power, \ |
| .sensorFirmwareUpload = firmware, \ |
| .sensorSetRate = rate, \ |
| .sensorFlush = flush, \ |
| .sensorCalibrate = cal, \ |
| .sensorSelfTest = test, \ |
| .sensorCfgData = cfg |
| |
| static const struct SensorOps st_acc44_SensorOps = |
| { |
| DEC_OPS(st_acc44_Power, st_acc44_FwUpload, st_acc44_SetRate, st_acc44_Flush, st_acc44_SelfTest, NULL, NULL), |
| }; |
| |
| static void inline enableInterrupt(struct Gpio *pin, struct ChainedIsr *isr) |
| { |
| gpioConfigInput(pin, GPIO_SPEED_LOW, GPIO_PULL_NONE); |
| syscfgSetExtiPort(pin); |
| extiEnableIntGpio(pin, EXTI_TRIGGER_RISING); |
| extiChainIsr(ST_ACC44_INT_IRQ, isr); |
| } |
| |
| static void inline disableInterrupt(struct Gpio *pin, struct ChainedIsr *isr) |
| { |
| extiUnchainIsr(ST_ACC44_INT_IRQ, isr); |
| extiDisableIntGpio(pin); |
| } |
| |
| static void st_acc44_calc_timestamp(void) |
| { |
| if (mTask.lastTime == 0) { |
| mTask.Timestamp = sensorGetTime(); |
| } else { |
| uint64_t currTime = sensorGetTime(); |
| uint64_t deltaTime = currTime - mTask.lastTime; |
| |
| deltaTime = (deltaTime + 7*mTask.irq_rate_ns)/8; |
| mTask.Timestamp = mTask.lastTime + deltaTime; |
| } |
| mTask.lastTime = mTask.Timestamp; |
| } |
| |
| static bool st_acc44_int1_isr(struct ChainedIsr *isr) |
| { |
| if (!extiIsPendingGpio(mTask.Int1)) |
| return false; |
| |
| /* Start sampling for a value */ |
| if (!osEnqueuePrivateEvt(EVT_SENSOR_INTERRUPT, NULL, NULL, mTask.tid)) |
| ERROR_PRINT("st_acc44_int1_isr: osEnqueuePrivateEvt() failed\n"); |
| |
| mTask.int_num++; |
| extiClearPendingGpio(mTask.Int1); |
| return true; |
| } |
| |
| static void int2Evt(void) |
| { |
| if (trySwitchState(SENSOR_READ_SAMPLES)) { |
| mTask.comm_rx(ST_ACC44_OUTXL_REG_ADDR, 6, 0, true); |
| } else { |
| mTask.pendingInt = true; |
| } |
| } |
| |
| static void processPendingEvt(void) |
| { |
| if (mTask.pendingInt) { |
| mTask.pendingInt = false; |
| int2Evt(); |
| return; |
| } |
| |
| if (mTask.pendingSetPower) { |
| mTask.pendingSetPower = false; |
| st_acc44_Power(mTask.pendingPower, NULL); |
| } |
| |
| if (mTask.pendingSetRate) { |
| mTask.pendingSetRate = false; |
| st_acc44_SetRate(mTask.pendingRate, mTask.pendingLatency, NULL); |
| } |
| } |
| |
| static bool accAllocateEvt(struct TripleAxisDataEvent **evPtr) |
| { |
| struct TripleAxisDataEvent *ev; |
| |
| ev = *evPtr = slabAllocatorAlloc(mTask.accDataSlab); |
| if (!ev) { |
| ERROR_PRINT("Failed to allocate acc event memory"); |
| return false; |
| } |
| |
| memset(&ev->samples[0].firstSample, 0x00, sizeof(struct SensorFirstSample)); |
| return true; |
| } |
| |
| static void accFreeEvt(void *ptr) |
| { |
| slabAllocatorFree(mTask.accDataSlab, ptr); |
| } |
| |
| // 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(void) |
| { |
| size_t i; |
| |
| for (i = 0; i < ARRAY_SIZE(mTask.transfers); i++) { |
| if (!mTask.transfers[i].inUse) { |
| mTask.transfers[i].inUse = true; |
| return &mTask.transfers[i]; |
| } |
| } |
| |
| ERROR_PRINT("Ran out of i2c buffers!"); |
| return NULL; |
| } |
| |
| static inline void releaseXfer(struct I2cTransfer *xfer) |
| { |
| xfer->inUse = false; |
| } |
| |
| static void st_acc44_i2cCallback(void *cookie, size_t tx, size_t rx, int err) |
| { |
| struct I2cTransfer *xfer = cookie; |
| |
| /* Do not run callback if not the last one in a set of i2c transfers */ |
| if (xfer && !xfer->last) { |
| releaseXfer(xfer); |
| return; |
| } |
| |
| xfer->tx = tx; |
| xfer->rx = rx; |
| xfer->err = err; |
| |
| osEnqueuePrivateEvt(EVT_COMM_DONE, cookie, NULL, mTask.tid); |
| if (err != 0) |
| ERROR_PRINT("i2c error (tx: %d, rx: %d, err: %d)\n", tx, rx, err); |
| } |
| |
| static bool st_acc44_i2c_read(uint8_t addr, uint16_t len, uint32_t delay, bool last) |
| { |
| struct I2cTransfer *xfer = allocXfer(); |
| int ret = -1; |
| |
| if (xfer != NULL) { |
| xfer->delay = delay; |
| xfer->last = last; |
| xfer->txrxBuf[0] = ST_ACC44_I2C_AUTO_INCR | addr; |
| if ((ret = i2cMasterTxRx(ST_ACC44_I2C_BUS_ID, ST_ACC44_I2C_ADDR, xfer->txrxBuf, 1, xfer->txrxBuf, len, st_acc44_i2cCallback, xfer)) < 0) { |
| releaseXfer(xfer); |
| DEBUG_PRINT("st_acc44_i2c_read: i2cMasterTxRx operation failed (ret: %d)\n", ret); |
| return false; |
| } |
| } |
| |
| return (ret == -1) ? false : true; |
| } |
| |
| static bool st_acc44_i2c_write(uint8_t addr, uint8_t data, uint32_t delay, bool last) |
| { |
| struct I2cTransfer *xfer = allocXfer(); |
| int ret = -1; |
| |
| if (xfer != NULL) { |
| xfer->delay = delay; |
| xfer->last = last; |
| xfer->txrxBuf[0] = addr; |
| xfer->txrxBuf[1] = data; |
| if ((ret = i2cMasterTx(ST_ACC44_I2C_BUS_ID, ST_ACC44_I2C_ADDR, xfer->txrxBuf, 2, st_acc44_i2cCallback, xfer)) < 0) { |
| releaseXfer(xfer); |
| DEBUG_PRINT("st_acc44_i2c_write: i2cMasterTx operation failed (ret: %d)\n", ret); |
| return false; |
| } |
| } |
| |
| return (ret == -1) ? false : true; |
| } |
| |
| static void parseRawData(uint8_t *raw, uint8_t num_of_smpl, uint64_t sensor_time) |
| { |
| uint8_t i; |
| struct TripleAxisDataEvent *accSample; |
| float x, y, z; |
| int32_t raw_x; |
| int32_t raw_y; |
| int32_t raw_z; |
| |
| /* Discard samples generated during sensor turn-on time */ |
| if (mTask.samplesToDiscard > 0) { |
| if (num_of_smpl > mTask.samplesToDiscard) { |
| num_of_smpl -= mTask.samplesToDiscard; |
| mTask.samplesToDiscard = 0; |
| } else{ |
| mTask.samplesToDiscard -= num_of_smpl; |
| return; |
| } |
| } |
| |
| if (accAllocateEvt(&accSample) == false) |
| return; |
| |
| accSample->referenceTime = sensor_time; |
| |
| accSample->samples[0].deltaTime = 0; |
| accSample->samples[0].firstSample.numSamples = num_of_smpl; |
| |
| for (i = 0; i < num_of_smpl; i++) { |
| raw_x = (*(int16_t *)&raw[6*i + 0]); |
| raw_y = (*(int16_t *)&raw[6*i + 2]); |
| raw_z = (*(int16_t *)&raw[6*i + 4]); |
| |
| /* convert raw data in m/s2 */ |
| x = RAW_TO_MS2(raw_x); |
| y = RAW_TO_MS2(raw_y); |
| z = RAW_TO_MS2(raw_z); |
| |
| /* rotate axis */ |
| ST_ACC44_TO_ANDROID_COORDINATE(x, y, z); |
| |
| accSample->samples[i].x = x; |
| accSample->samples[i].y = y; |
| accSample->samples[i].z = z; |
| |
| if (i > 0) |
| accSample->samples[i].deltaTime = mTask.sample_rate_ns; |
| } |
| |
| osEnqueueEvtOrFree(sensorGetMyEventType(SENS_TYPE_ACCEL), accSample, accFreeEvt); |
| } |
| |
| static int st_acc44_handleCommDoneEvt(const void* evtData) |
| { |
| bool returnIdle = false; |
| struct I2cTransfer *xfer = (struct I2cTransfer *)evtData; |
| |
| switch (GET_STATE()) { |
| case SENSOR_BOOT: |
| SET_STATE(SENSOR_VERIFY_ID); |
| if (!mTask.comm_rx(ST_ACC44_WAI_REG_ADDR, 1, 0, true)) { |
| DEBUG_PRINT("Not able to read WAI\n"); |
| return -1; |
| } |
| break; |
| |
| case SENSOR_VERIFY_ID: |
| /* Check the sensor ID */ |
| if (xfer->err != 0 || xfer->txrxBuf[0] != ST_ACC44_WAI_REG_VAL) { |
| DEBUG_PRINT("WAI returned is: %02x\n", xfer->txrxBuf[0]); |
| break; |
| } |
| |
| INFO_PRINT("Device ID is correct! (%02x)\n", xfer->txrxBuf[0]); |
| |
| SET_STATE(SENSOR_INIT); |
| mTask.comm_tx(ST_ACC44_CTRL1_REG, ST_ACC44_ODR_POWER_DOWN | ST_ACC44_CTRL1_DEFVAL, 0, false); |
| mTask.comm_tx(ST_ACC44_CTRL2_REG, ST_ACC44_CTRL2_DEFVAL, 0, false); |
| mTask.comm_tx(ST_ACC44_CTRL3_REG, ST_ACC44_CTRL3_LIR, 0, false); |
| mTask.comm_tx(ST_ACC44_CTRL6_REG, ST_ACC44_CTRL6_FS_8G, 0, false); |
| mTask.comm_tx(ST_ACC44_CTRL4_REG, 0, 0, true); |
| break; |
| |
| case SENSOR_INIT: |
| DEBUG_PRINT("SENSOR INIT\n"); |
| returnIdle = true; |
| sensorRegisterInitComplete(mTask.accHandle); |
| break; |
| |
| case SENSOR_ACCEL_POWER_UP: |
| DEBUG_PRINT("POWER UP\n"); |
| returnIdle = true; |
| mTask.accOn = true; |
| sensorSignalInternalEvt(mTask.accHandle, |
| SENSOR_INTERNAL_EVT_POWER_STATE_CHG, true, 0); |
| break; |
| |
| case SENSOR_ACCEL_POWER_DOWN: |
| DEBUG_PRINT("POWER DWN\n"); |
| returnIdle = true; |
| mTask.accOn = false; |
| sensorSignalInternalEvt(mTask.accHandle, |
| SENSOR_INTERNAL_EVT_POWER_STATE_CHG, false, 0); |
| break; |
| |
| case SENSOR_CHANGE_RATE: |
| DEBUG_PRINT("CHANGE RATE\n"); |
| returnIdle = true; |
| DEBUG_PRINT("int_num %ld\n", mTask.int_num); |
| mTask.int_num = 0; |
| sensorSignalInternalEvt(mTask.accHandle, |
| SENSOR_INTERNAL_EVT_RATE_CHG, mTask.rate, mTask.latency); |
| break; |
| |
| case SENSOR_READ_SAMPLES: |
| returnIdle = true; |
| |
| parseRawData(&xfer->txrxBuf[0], 1, mTask.Timestamp); |
| break; |
| |
| case SENSOR_IDLE: |
| default: |
| break; |
| } |
| |
| releaseXfer(xfer); |
| |
| if (returnIdle) { |
| SET_STATE(SENSOR_IDLE); |
| processPendingEvt(); |
| } |
| |
| return (0); |
| } |
| |
| static void st_acc44_handleEvent(uint32_t evtType, const void* evtData) |
| { |
| switch (evtType) { |
| case EVT_APP_START: |
| INFO_PRINT("EVT_APP_START\n"); |
| osEventUnsubscribe(mTask.tid, EVT_APP_START); |
| |
| SET_STATE(SENSOR_BOOT); |
| mTask.comm_tx(ST_ACC44_CTRL2_REG, ST_ACC44_CTRL2_SW_RST, 0, true); |
| break; |
| |
| case EVT_COMM_DONE: |
| st_acc44_handleCommDoneEvt(evtData); |
| break; |
| |
| case EVT_SENSOR_INTERRUPT: |
| st_acc44_calc_timestamp(); |
| int2Evt(); |
| break; |
| |
| default: |
| break; |
| } |
| } |
| |
| static bool st_acc44_startTask(uint32_t task_id) |
| { |
| size_t slabSize; |
| |
| mTask.tid = task_id; |
| |
| INFO_PRINT("start driver\n"); |
| |
| mTask.accOn = false; |
| mTask.pendingInt = false; |
| mTask.pendingSetPower = false; |
| mTask.pendingSetRate = false; |
| |
| mTask.currentODR = ST_ACC44_ODR_POWER_DOWN; |
| |
| slabSize = sizeof(struct TripleAxisDataEvent) + sizeof(struct TripleAxisDataPoint); |
| |
| mTask.accDataSlab = slabAllocatorNew(slabSize, 4, ST_ACC44_MAX_ACC_EVENTS); |
| if (!mTask.accDataSlab) { |
| ERROR_PRINT("Failed to allocate accDataSlab memory\n"); |
| return false; |
| } |
| |
| /* Init the communication part */ |
| i2cMasterRequest(ST_ACC44_I2C_BUS_ID, ST_ACC44_I2C_SPEED); |
| |
| mTask.comm_tx = st_acc44_i2c_write; |
| mTask.comm_rx = st_acc44_i2c_read; |
| |
| /* irq */ |
| mTask.int_num = 0; |
| mTask.Int1 = gpioRequest(ST_ACC44_INT_PIN); |
| gpioConfigInput(mTask.Int1, GPIO_SPEED_LOW, GPIO_PULL_NONE); |
| mTask.Isr1.func = st_acc44_int1_isr; |
| enableInterrupt(mTask.Int1, &mTask.Isr1); |
| |
| mTask.accHandle = sensorRegister(&st_acc44_SensorInfo, &st_acc44_SensorOps, NULL, false); |
| |
| osEventSubscribe(mTask.tid, EVT_APP_START); |
| |
| return true; |
| } |
| |
| static void st_acc44_endTask(void) |
| { |
| INFO_PRINT("ended\n"); |
| slabAllocatorDestroy(mTask.accDataSlab); |
| disableInterrupt(mTask.Int1, &mTask.Isr1); |
| } |
| |
| INTERNAL_APP_INIT(ST_ACC44_APP_ID, 0, st_acc44_startTask, st_acc44_endTask, st_acc44_handleEvent); |