/*
 * 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 <plat/inc/taggedPtr.h>
#include <cpu/inc/barrier.h>
#include <atomicBitset.h>
#include <inttypes.h>
#include <sensors.h>
#include <atomic.h>
#include <stdio.h>
#include <slab.h>
#include <seos.h>
#include <util.h>

#define MAX_INTERNAL_EVENTS       32 //also used for external app sensors' setRate() calls
#define MAX_CLI_SENS_MATRIX_SZ    64 /* MAX(numClients * numSensors) */

#define SENSOR_RATE_OFF           0x00000000UL /* used in sensor state machine */
#define SENSOR_RATE_POWERING_ON   0xFFFFFFF0UL /* used in sensor state machine */
#define SENSOR_RATE_POWERING_OFF  0xFFFFFFF1UL /* used in sensor state machine */
#define SENSOR_RATE_FW_UPLOADING  0xFFFFFFF2UL /* used in sensor state machine */
#define SENSOR_RATE_IMPOSSIBLE    0xFFFFFFF3UL /* used in rate calc to indicate impossible combinations */
#define SENSOR_LATENCY_INVALID    0xFFFFFFFFFFFFFFFFULL

#define HANDLE_TO_TID(handle) (((handle) >> (32 - TASK_TID_BITS)) & TASK_TID_MASK)
#define EXT_APP_TID(s) HANDLE_TO_TID(s->handle)
#define LOCAL_APP_OPS(s) ((const struct SensorOps*)taggedPtrToPtr(s->callInfo))
#define IS_LOCAL_APP(s) (taggedPtrIsPtr(s->callInfo))

struct Sensor {
    const struct SensorInfo *si;
    uint32_t handle;         /* here 0 means invalid */
    uint64_t currentLatency; /* here 0 means no batching */
    uint32_t currentRate;    /* here 0 means off */
    TaggedPtr callInfo;      /* pointer to ops struct or app tid */
    void *callData;
    uint32_t initComplete:1; /* sensor finished initializing */
    uint32_t hasOnchange :1; /* sensor supports onchange and wants to be notified to send new clients current state */
    uint32_t hasOndemand :1; /* sensor supports ondemand and wants to get triggers */
};

struct SensorsInternalEvent {
    union {
        struct {
            uint32_t handle;
            uint32_t value1;
            uint64_t value2;
        };
        struct SensorPowerEvent externalPowerEvt;
        struct SensorSetRateEvent externalSetRateEvt;
        struct SensorCfgDataEvent externalCfgDataEvt;
        struct SensorSendDirectEventEvent externalSendDirectEvt;
        struct SensorMarshallUserEventEvent externalMarshallEvt;
    };
};

struct SensorsClientRequest {
    uint32_t handle;
    uint32_t clientTid;
    uint64_t latency;
    uint32_t rate;
};

static struct Sensor mSensors[MAX_REGISTERED_SENSORS];
ATOMIC_BITSET_DECL(mSensorsUsed, MAX_REGISTERED_SENSORS, static);
static struct SlabAllocator *mInternalEvents;
static struct SlabAllocator *mCliSensMatrix;
static uint32_t mNextSensorHandle;
struct SingleAxisDataEvent singleAxisFlush = { .referenceTime = 0 };
struct TripleAxisDataEvent tripleAxisFlush = { .referenceTime = 0 };

static inline uint32_t newSensorHandle()
{
    // FIXME: only let lower 8 bits of counter to the id; should use all 16 bits, but this
    // somehow confuses upper layers; pending investigation
    return (osGetCurrentTid() << 16) | (atomicAdd32bits(&mNextSensorHandle, 1) & 0xFF);
}

bool sensorsInit(void)
{
    atomicBitsetInit(mSensorsUsed, MAX_REGISTERED_SENSORS);

    mInternalEvents = slabAllocatorNew(sizeof(struct SensorsInternalEvent), alignof(struct SensorsInternalEvent), MAX_INTERNAL_EVENTS);
    if (!mInternalEvents)
        return false;

    mCliSensMatrix = slabAllocatorNew(sizeof(struct SensorsClientRequest), alignof(struct SensorsClientRequest), MAX_CLI_SENS_MATRIX_SZ);
    if (mCliSensMatrix)
        return true;

    slabAllocatorDestroy(mInternalEvents);

    return false;
}

static struct Sensor* sensorFindByHandle(uint32_t handle)
{
    uint32_t i;

    for (i = 0; i < MAX_REGISTERED_SENSORS; i++)
        if (mSensors[i].handle == handle)
            return mSensors + i;

    return NULL;
}

static uint32_t sensorRegisterEx(const struct SensorInfo *si, TaggedPtr callInfo, void *callData, bool initComplete)
{
    int32_t idx = atomicBitsetFindClearAndSet(mSensorsUsed);
    uint32_t handle, i;
    struct Sensor *s;

    /* grab a slot */
    if (idx < 0)
        return 0;

    /* grab a handle:
     * this is safe since nobody else could have "JUST" taken this handle,
     * we'll need to circle around 16 bits before that happens, and have the same TID
     */
    do {
        handle = newSensorHandle();
    } while (!handle || sensorFindByHandle(handle));

    /* fill the struct in and mark it valid (by setting handle) */
    s = mSensors + idx;
    s->si = si;
    s->currentRate = SENSOR_RATE_OFF;
    s->currentLatency = SENSOR_LATENCY_INVALID;
    s->callInfo = callInfo;
    // TODO: is internal app, callinfo is OPS struct; shall we validate it here?
    s->callData = callData;
    s->initComplete = initComplete ? 1 : 0;
    mem_reorder_barrier();
    s->handle = handle;
    s->hasOnchange = 0;
    s->hasOndemand = 0;

    if (si->supportedRates) {
        for (i = 0; si->supportedRates[i]; i++) {
            if (si->supportedRates[i] == SENSOR_RATE_ONCHANGE)
                s->hasOnchange = 1;
            if (si->supportedRates[i] == SENSOR_RATE_ONDEMAND)
                s->hasOndemand = 1;
        }
    }

    return handle;
}

uint32_t sensorRegister(const struct SensorInfo *si, const struct SensorOps *ops, void *callData, bool initComplete)
{
    return sensorRegisterEx(si, taggedPtrMakeFromPtr(ops), callData, initComplete);
}

uint32_t sensorRegisterAsApp(const struct SensorInfo *si, uint32_t unusedTid, void *callData, bool initComplete)
{
    (void)unusedTid;
    return sensorRegisterEx(si, taggedPtrMakeFromUint(0), callData, initComplete);
}

bool sensorRegisterInitComplete(uint32_t handle)
{
    struct Sensor *s = sensorFindByHandle(handle);

    if (!s)
        return false;

    s->initComplete = true;
    mem_reorder_barrier();

    return true;
}

bool sensorUnregister(uint32_t handle)
{
    struct Sensor *s = sensorFindByHandle(handle);

    if (!s)
        return false;

    /* mark as invalid */
    s->handle = 0;
    mem_reorder_barrier();

    /* free struct */
    atomicBitsetClearBit(mSensorsUsed, s - mSensors);

    return true;
}

static void sensorCallFuncPowerEvtFreeF(void* event)
{
    slabAllocatorFree(mInternalEvents, event);
}

#define INVOKE_AS_OWNER_AND_RETURN(func, ...)                       \
{                                                                   \
    if (!func)                                                      \
        return false;                                               \
    uint16_t oldTid = osSetCurrentTid(HANDLE_TO_TID(s->handle));    \
    bool done = func(__VA_ARGS__);                                  \
    osSetCurrentTid(oldTid);                                        \
    return done;                                                    \
}

static bool sensorCallFuncPower(struct Sensor* s, bool on)
{
    if (IS_LOCAL_APP(s)) {
        INVOKE_AS_OWNER_AND_RETURN(LOCAL_APP_OPS(s)->sensorPower, on, s->callData);
    } else {
        struct SensorsInternalEvent *evt = (struct SensorsInternalEvent*)slabAllocatorAlloc(mInternalEvents);

        if (!evt)
            return false;

        evt->externalPowerEvt.on = on;
        evt->externalPowerEvt.callData = s->callData;

        if (osEnqueuePrivateEvt(EVT_APP_SENSOR_POWER, &evt->externalPowerEvt,
            sensorCallFuncPowerEvtFreeF, EXT_APP_TID(s)))
            return true;

        slabAllocatorFree(mInternalEvents, evt);
        return false;
    }
}

// the most common callback goes as a helper function
static bool sensorCallAsOwner(struct Sensor* s, bool (*callback)(void*))
{
    INVOKE_AS_OWNER_AND_RETURN(callback, s->callData);
}

static bool sensorCallFuncFwUpld(struct Sensor* s)
{
    if (IS_LOCAL_APP(s))
        return sensorCallAsOwner(s, LOCAL_APP_OPS(s)->sensorFirmwareUpload);
    else
        return osEnqueuePrivateEvt(EVT_APP_SENSOR_FW_UPLD, s->callData, NULL, EXT_APP_TID(s));
}

static void sensorCallFuncExternalEvtFreeF(void* event)
{
    slabAllocatorFree(mInternalEvents, event);
}

static bool sensorCallFuncSetRate(struct Sensor* s, uint32_t rate, uint64_t latency)
{
    if (IS_LOCAL_APP(s)) {
        INVOKE_AS_OWNER_AND_RETURN(LOCAL_APP_OPS(s)->sensorSetRate, rate, latency, s->callData);
    } else {
        struct SensorsInternalEvent *evt = (struct SensorsInternalEvent*)slabAllocatorAlloc(mInternalEvents);

        if (!evt)
            return false;

        evt->externalSetRateEvt.latency = latency;
        evt->externalSetRateEvt.rate = rate;
        evt->externalSetRateEvt.callData = s->callData;
        if (osEnqueuePrivateEvt(EVT_APP_SENSOR_SET_RATE, &evt->externalSetRateEvt,
            sensorCallFuncExternalEvtFreeF, EXT_APP_TID(s)))
            return true;

        slabAllocatorFree(mInternalEvents, evt);
        return false;
    }
}

static bool sensorCallFuncCalibrate(struct Sensor* s)
{
    if (IS_LOCAL_APP(s))
        return sensorCallAsOwner(s, LOCAL_APP_OPS(s)->sensorCalibrate);
    else
        return osEnqueuePrivateEvt(EVT_APP_SENSOR_CALIBRATE, s->callData, NULL, EXT_APP_TID(s));
}

static bool sensorCallFuncFlush(struct Sensor* s)
{
    if (IS_LOCAL_APP(s))
        return sensorCallAsOwner(s, LOCAL_APP_OPS(s)->sensorFlush);
    else
        return osEnqueuePrivateEvt(EVT_APP_SENSOR_FLUSH, s->callData, NULL, EXT_APP_TID(s));
}

static bool sensorCallFuncCfgData(struct Sensor* s, void* cfgData)
{
    if (IS_LOCAL_APP(s)) {
        INVOKE_AS_OWNER_AND_RETURN(LOCAL_APP_OPS(s)->sensorCfgData, cfgData, s->callData);
    } else {
        struct SensorsInternalEvent *evt = (struct SensorsInternalEvent*)slabAllocatorAlloc(mInternalEvents);

        if (!evt)
            return false;

        evt->externalCfgDataEvt.data = cfgData;
        evt->externalCfgDataEvt.callData = s->callData;
        if (osEnqueuePrivateEvt(EVT_APP_SENSOR_CFG_DATA, &evt->externalCfgDataEvt,
            sensorCallFuncExternalEvtFreeF, EXT_APP_TID(s)))
            return true;

        slabAllocatorFree(mInternalEvents, evt);
        return false;
    }
}

static bool sensorCallFuncMarshall(struct Sensor* s, uint32_t evtType, void *evtData, TaggedPtr *evtFreeingInfoP)
{
    if (IS_LOCAL_APP(s)) {
        INVOKE_AS_OWNER_AND_RETURN(LOCAL_APP_OPS(s)->sensorMarshallData, evtType, evtData, evtFreeingInfoP, s->callData);
    } else {
        struct SensorsInternalEvent *evt = (struct SensorsInternalEvent*)slabAllocatorAlloc(mInternalEvents);

        if (!evt)
            return false;

        evt->externalMarshallEvt.origEvtType = evtType;
        evt->externalMarshallEvt.origEvtData = evtData;
        evt->externalMarshallEvt.evtFreeingInfo = *evtFreeingInfoP;
        evt->externalMarshallEvt.callData = s->callData;
        if (osEnqueuePrivateEvt(EVT_APP_SENSOR_MARSHALL, &evt->externalMarshallEvt,
            sensorCallFuncExternalEvtFreeF, EXT_APP_TID(s)))
            return true;

        slabAllocatorFree(mInternalEvents, evt);
        return false;
    }
}

static bool sensorCallFuncTrigger(struct Sensor* s)
{
    if (IS_LOCAL_APP(s))
        return sensorCallAsOwner(s, LOCAL_APP_OPS(s)->sensorTriggerOndemand);
    else
        return osEnqueuePrivateEvt(EVT_APP_SENSOR_TRIGGER, s->callData, NULL, EXT_APP_TID(s));
}

static bool sensorCallFuncSendOneDirectEvt(struct Sensor* s, uint32_t tid)
{
    if (IS_LOCAL_APP(s)) {
        INVOKE_AS_OWNER_AND_RETURN(LOCAL_APP_OPS(s)->sensorSendOneDirectEvt, s->callData, tid);
    } else {
        struct SensorsInternalEvent *evt = (struct SensorsInternalEvent*)slabAllocatorAlloc(mInternalEvents);

        if (!evt)
            return false;

        evt->externalSendDirectEvt.tid = tid;
        evt->externalSendDirectEvt.callData = s->callData;
        if (osEnqueuePrivateEvt(EVT_APP_SENSOR_SEND_ONE_DIR_EVT, &evt->externalSendDirectEvt,
            sensorCallFuncExternalEvtFreeF, EXT_APP_TID(s)))
            return true;

        slabAllocatorFree(mInternalEvents, evt);
    }

    return false;
}

static void sensorReconfig(struct Sensor* s, uint32_t newHwRate, uint64_t newHwLatency)
{
    if (s->currentRate == newHwRate && s->currentLatency == newHwLatency) {
        /* do nothing */
    }
    else if (s->currentRate == SENSOR_RATE_OFF) {
        /* if it was off or is off, tell it to come on */
        if (sensorCallFuncPower(s, true)) {
            s->currentRate = SENSOR_RATE_POWERING_ON;
            s->currentLatency = SENSOR_LATENCY_INVALID;
        }
    }
    else if (s->currentRate == SENSOR_RATE_POWERING_OFF) {
        /* if it was going to be off or is off, tell it to come back on */
        s->currentRate = SENSOR_RATE_POWERING_ON;
        s->currentLatency = SENSOR_LATENCY_INVALID;
    }
    else if (s->currentRate == SENSOR_RATE_POWERING_ON || s->currentRate == SENSOR_RATE_FW_UPLOADING) {
        /* if it is powering on - do nothing - all will be done for us */
    }
    else if (newHwRate > SENSOR_RATE_OFF || newHwLatency < SENSOR_LATENCY_INVALID) {
        /* simple rate change - > do it, there is nothing we can do if this fails, so we ignore the immediate errors :( */
        (void)sensorCallFuncSetRate(s, newHwRate, newHwLatency);
    }
    else {
        /* powering off */
        if (sensorCallFuncPower(s, false)) {
            s->currentRate = SENSOR_RATE_POWERING_OFF;
            s->currentLatency = SENSOR_LATENCY_INVALID;
        }
    }
}

static uint64_t sensorCalcHwLatency(struct Sensor* s)
{
    uint64_t smallestLatency = SENSOR_LATENCY_INVALID;
    uint32_t i;

    for (i = 0; i < MAX_CLI_SENS_MATRIX_SZ; i++) {
        struct SensorsClientRequest *req = slabAllocatorGetNth(mCliSensMatrix, i);

        /* we only care about this sensor's stuff */
        if (!req || req->handle != s->handle)
            continue;

        if (smallestLatency > req->latency)
            smallestLatency = req->latency;
    }

    return smallestLatency;
}

static uint32_t sensorCalcHwRate(struct Sensor* s, uint32_t extraReqedRate, uint32_t removedRate)
{
    bool haveUsers = false, haveOnChange = extraReqedRate == SENSOR_RATE_ONCHANGE;
    uint32_t highestReq = 0;
    uint32_t i;

    if (s->si->supportedRates &&
        ((extraReqedRate == SENSOR_RATE_ONCHANGE && !s->hasOnchange) ||
         (extraReqedRate == SENSOR_RATE_ONDEMAND && !s->hasOndemand))) {
        osLog(LOG_WARN, "Bad rate 0x%08" PRIX32 " for sensor %u", extraReqedRate, s->si->sensorType);
        return SENSOR_RATE_IMPOSSIBLE;
    }

    if (extraReqedRate) {
        haveUsers = true;
        highestReq = (extraReqedRate == SENSOR_RATE_ONDEMAND || extraReqedRate == SENSOR_RATE_ONCHANGE) ? 0 : extraReqedRate;
    }

    for (i = 0; i < MAX_CLI_SENS_MATRIX_SZ; i++) {
        struct SensorsClientRequest *req = slabAllocatorGetNth(mCliSensMatrix, i);

        /* we only care about this sensor's stuff */
        if (!req || req->handle != s->handle)
            continue;

        /* skip an instance of a removed rate if one was given */
        if (req->rate == removedRate) {
            removedRate = SENSOR_RATE_OFF;
            continue;
        }

        haveUsers = true;

        /* we can always do ondemand and if we see an on-change then we already checked and do allow it */
        if (req->rate == SENSOR_RATE_ONDEMAND)
            continue;
        if (req->rate == SENSOR_RATE_ONCHANGE) {
            haveOnChange = true;
            continue;
        }

        if (highestReq < req->rate)
            highestReq = req->rate;
    }

    if (!highestReq) {   /* no requests -> we can definitely do that */
        if (!haveUsers)
            return SENSOR_RATE_OFF;
        else if (haveOnChange)
            return SENSOR_RATE_ONCHANGE;
        else
            return SENSOR_RATE_ONDEMAND;
    }

    for (i = 0; s->si->supportedRates && s->si->supportedRates[i]; i++)
        if (s->si->supportedRates[i] >= highestReq)
            return s->si->supportedRates[i];

    return SENSOR_RATE_IMPOSSIBLE;
}

static void sensorInternalFwStateChanged(void *evtP)
{
    struct SensorsInternalEvent *evt = (struct SensorsInternalEvent*)evtP;
    struct Sensor* s = sensorFindByHandle(evt->handle);

    if (s) {

        if (!evt->value1) {                                       //we failed -> give up
            s->currentRate = SENSOR_RATE_POWERING_OFF;
            s->currentLatency = SENSOR_LATENCY_INVALID;
            sensorCallFuncPower(s, false);
        }
        else if (s->currentRate == SENSOR_RATE_FW_UPLOADING) {    //we're up
            s->currentRate = evt->value1;
            s->currentLatency = evt->value2;
            sensorReconfig(s, sensorCalcHwRate(s, 0, 0), sensorCalcHwLatency(s));
        }
        else if (s->currentRate == SENSOR_RATE_POWERING_OFF) {    //we need to power off
            sensorCallFuncPower(s, false);
        }
    }
    slabAllocatorFree(mInternalEvents, evt);
}

static void sensorInternalPowerStateChanged(void *evtP)
{
    struct SensorsInternalEvent *evt = (struct SensorsInternalEvent*)evtP;
    struct Sensor* s = sensorFindByHandle(evt->handle);

    if (s) {

        if (s->currentRate == SENSOR_RATE_POWERING_ON && evt->value1) {          //we're now on - upload firmware
            s->currentRate = SENSOR_RATE_FW_UPLOADING;
            s->currentLatency = SENSOR_LATENCY_INVALID;
            sensorCallFuncFwUpld(s);
        }
        else if (s->currentRate == SENSOR_RATE_POWERING_OFF && !evt->value1) {   //we're now off
            s->currentRate = SENSOR_RATE_OFF;
            s->currentLatency = SENSOR_LATENCY_INVALID;
        }
        else if (s->currentRate == SENSOR_RATE_POWERING_ON && !evt->value1) {    //we need to power back on
            sensorCallFuncPower(s, true);
        }
        else if (s->currentRate == SENSOR_RATE_POWERING_OFF && evt->value1) {    //we need to power back off
            sensorCallFuncPower(s, false);
        }
    }
    slabAllocatorFree(mInternalEvents, evt);
}

static void sensorInternalRateChanged(void *evtP)
{
    struct SensorsInternalEvent *evt = (struct SensorsInternalEvent*)evtP;
    struct Sensor* s = sensorFindByHandle(evt->handle);

    /* If the current rate is a state, do not change the rate */
    if (s && s->currentRate != SENSOR_RATE_OFF && s->currentRate < SENSOR_RATE_POWERING_ON) {
        s->currentRate = evt->value1;
        s->currentLatency = evt->value2;
    }
    slabAllocatorFree(mInternalEvents, evt);
}

bool sensorSignalInternalEvt(uint32_t handle, uint32_t intEvtNum, uint32_t value1, uint64_t value2)
{
    static const OsDeferCbkF internalEventCallbacks[] = {
        [SENSOR_INTERNAL_EVT_POWER_STATE_CHG] = sensorInternalPowerStateChanged,
        [SENSOR_INTERNAL_EVT_FW_STATE_CHG] = sensorInternalFwStateChanged,
        [SENSOR_INTERNAL_EVT_RATE_CHG] = sensorInternalRateChanged,
    };
    struct SensorsInternalEvent *evt = (struct SensorsInternalEvent*)slabAllocatorAlloc(mInternalEvents);

    if (!evt)
        return false;

    evt->handle = handle;
    evt->value1 = value1;
    evt->value2 = value2;

    if (osDefer(internalEventCallbacks[intEvtNum], evt, false))
        return true;

    slabAllocatorFree(mInternalEvents, evt);
    return false;
}

const struct SensorInfo* sensorFind(uint32_t sensorType, uint32_t idx, uint32_t *handleP)
{
    uint32_t i;

    for (i = 0; i < MAX_REGISTERED_SENSORS; i++) {
        if (mSensors[i].handle && mSensors[i].si->sensorType == sensorType && !idx--) {
            if (handleP)
                *handleP = mSensors[i].handle;
            return mSensors[i].si;
        }
    }

    return NULL;
}

static bool sensorAddRequestor(uint32_t sensorHandle, uint32_t clientTid, uint32_t rate, uint64_t latency)
{
    struct SensorsClientRequest *req = slabAllocatorAlloc(mCliSensMatrix);

    if (!req)
        return false;

    req->handle = sensorHandle;
    req->clientTid = clientTid;
    mem_reorder_barrier();
    req->rate = rate;
    req->latency = latency;

    return true;
}

static bool sensorGetCurRequestorRate(uint32_t sensorHandle, uint32_t clientTid, uint32_t *rateP, uint64_t *latencyP)
{
    uint32_t i;

    for (i = 0; i < MAX_CLI_SENS_MATRIX_SZ; i++) {
        struct SensorsClientRequest *req = slabAllocatorGetNth(mCliSensMatrix, i);

        if (req && req->handle == sensorHandle && req->clientTid == clientTid) {
            if (rateP) {
                *rateP = req->rate;
                *latencyP = req->latency;
            }
            return true;
        }
    }

    return false;
}

static bool sensorAmendRequestor(uint32_t sensorHandle, uint32_t clientTid, uint32_t newRate, uint64_t newLatency)
{
    uint32_t i;

    for (i = 0; i < MAX_CLI_SENS_MATRIX_SZ; i++) {
        struct SensorsClientRequest *req = slabAllocatorGetNth(mCliSensMatrix, i);

        if (req && req->handle == sensorHandle && req->clientTid == clientTid) {
            req->rate = newRate;
            req->latency = newLatency;
            return true;
        }
    }

    return false;
}

static bool sensorDeleteRequestor(uint32_t sensorHandle, uint32_t clientTid)
{
    uint32_t i;

    for (i = 0; i < MAX_CLI_SENS_MATRIX_SZ; i++) {
        struct SensorsClientRequest *req = slabAllocatorGetNth(mCliSensMatrix, i);

        if (req && req->handle == sensorHandle && req->clientTid == clientTid) {
            req->rate = SENSOR_RATE_OFF;
            req->latency = SENSOR_LATENCY_INVALID;
            req->clientTid = 0;
            req->handle = 0;
            mem_reorder_barrier();
            slabAllocatorFree(mCliSensMatrix, req);
            return true;
        }
    }

    return false;
}

bool sensorRequest(uint32_t unusedTid, uint32_t sensorHandle, uint32_t rate, uint64_t latency)
{
    struct Sensor* s = sensorFindByHandle(sensorHandle);
    uint32_t newSensorRate;
    uint64_t samplingPeriod;
    uint32_t clientTid;

    (void)unusedTid;

    if (!s)
        return false;

    clientTid = osGetCurrentTid();

    /* verify the rate is possible */
    newSensorRate = sensorCalcHwRate(s, rate, 0);
    if (newSensorRate == SENSOR_RATE_IMPOSSIBLE)
        return false;

    /* the latency should be lower bounded by sampling period */
    samplingPeriod = ((uint64_t)(1000000000 / rate)) << 10;
    latency = latency > samplingPeriod ? latency : samplingPeriod;

    /* record the request */
    if (!sensorAddRequestor(sensorHandle, clientTid, rate, latency))
        return false;

    /* update actual sensor if needed */
    sensorReconfig(s, newSensorRate, sensorCalcHwLatency(s));

    /* if onchange request, ask sensor to send last state */
    if (s->hasOnchange && !sensorCallFuncSendOneDirectEvt(s, clientTid))
        osLog(LOG_WARN, "Cannot send last state for onchange sensor: enqueue fail");

    return true;
}

bool sensorRequestRateChange(uint32_t unusedTid, uint32_t sensorHandle, uint32_t newRate, uint64_t newLatency)
{
    struct Sensor* s = sensorFindByHandle(sensorHandle);
    uint32_t oldRate, newSensorRate;
    uint64_t oldLatency, samplingPeriod;
    uint32_t clientTid;

    (void)unusedTid;

    if (!s)
        return false;

    clientTid = osGetCurrentTid();
    /* get current rate */
    if (!sensorGetCurRequestorRate(sensorHandle, clientTid, &oldRate, &oldLatency))
        return false;

    /* verify the new rate is possible given all other ongoing requests */
    newSensorRate = sensorCalcHwRate(s, newRate, oldRate);
    if (newSensorRate == SENSOR_RATE_IMPOSSIBLE)
        return false;

    /* the latency should be lower bounded by sampling period */
    samplingPeriod = ((uint64_t)(1000000000 / newRate)) << 10;
    newLatency = newLatency > samplingPeriod ? newLatency : samplingPeriod;

    /* record the request */
    if (!sensorAmendRequestor(sensorHandle, clientTid, newRate, newLatency))
        return false;

    /* update actual sensor if needed */
    sensorReconfig(s, newSensorRate, sensorCalcHwLatency(s));
    return true;
}

bool sensorRelease(uint32_t unusedTid, uint32_t sensorHandle)
{
    struct Sensor* s = sensorFindByHandle(sensorHandle);

    (void) unusedTid;

    if (!s)
        return false;

    /* record the request */
    if (!sensorDeleteRequestor(sensorHandle, osGetCurrentTid()))
        return false;

    /* update actual sensor if needed */
    sensorReconfig(s, sensorCalcHwRate(s, 0, 0), sensorCalcHwLatency(s));
    return true;
}

bool sensorTriggerOndemand(uint32_t unusedTid, uint32_t sensorHandle)
{
    struct Sensor* s = sensorFindByHandle(sensorHandle);
    uint32_t i;
    uint32_t clientTid;

    (void)unusedTid;

    if (!s || !s->hasOndemand)
        return false;

    clientTid = osGetCurrentTid();

    for (i = 0; i < MAX_CLI_SENS_MATRIX_SZ; i++) {
        struct SensorsClientRequest *req = slabAllocatorGetNth(mCliSensMatrix, i);

        if (req && req->handle == sensorHandle && req->clientTid == clientTid)
            return sensorCallFuncTrigger(s);
    }

    // not found -> do not report
    return false;
}

bool sensorFlush(uint32_t sensorHandle)
{
    struct Sensor* s = sensorFindByHandle(sensorHandle);

    if (!s)
        return false;

    return sensorCallFuncFlush(s);
}

bool sensorCalibrate(uint32_t sensorHandle)
{
    struct Sensor* s = sensorFindByHandle(sensorHandle);

    if (!s)
        return false;

    return sensorCallFuncCalibrate(s);
}

bool sensorCfgData(uint32_t sensorHandle, void* cfgData)
{
    struct Sensor* s = sensorFindByHandle(sensorHandle);

    if (!s)
        return false;

    return sensorCallFuncCfgData(s, cfgData);
}

uint32_t sensorGetCurRate(uint32_t sensorHandle)
{
    struct Sensor* s = sensorFindByHandle(sensorHandle);

    return s ? s->currentRate : SENSOR_RATE_OFF;
}

uint64_t sensorGetCurLatency(uint32_t sensorHandle)
{
    struct Sensor* s = sensorFindByHandle(sensorHandle);

    return s ? s->currentLatency : SENSOR_LATENCY_INVALID;
}

bool sensorGetInitComplete(uint32_t sensorHandle)
{
    struct Sensor* s = sensorFindByHandle(sensorHandle);

    return s ? s->initComplete : false;
}

bool sensorMarshallEvent(uint32_t sensorHandle, uint32_t evtType, void *evtData, TaggedPtr *evtFreeingInfoP)
{
    struct Sensor* s = sensorFindByHandle(sensorHandle);

    if (!s)
        return false;

    return sensorCallFuncMarshall(s, evtType, evtData, evtFreeingInfoP);
}

int sensorUnregisterAll(uint32_t tid)
{
    int i, count = 0;

    for (i = 0; i < MAX_REGISTERED_SENSORS; i++)
        if (HANDLE_TO_TID(mSensors[i].handle) == tid) {
            sensorUnregister(mSensors[i].handle);
            count++;
        }

    return count;
}