/* * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define HOSTINTF_MAX_ERR_MSG 8 #define MAX_NUM_BLOCKS 280 /* times 256 = 71680 bytes */ #define MIN_NUM_BLOCKS 10 /* times 256 = 2560 bytes */ #define SENSOR_INIT_DELAY 500000000 /* ns */ #define SENSOR_INIT_ERROR_MAX 4 #define CHECK_LATENCY_TIME 500000000 /* ns */ #define EVT_LATENCY_TIMER EVT_NO_FIRST_USER_EVENT static const uint32_t delta_time_multiplier_order = 9; static const uint32_t delta_time_coarse_mask = ~1; static const uint32_t delta_time_fine_mask = 1; static const uint32_t delta_time_rounding = 0x200; /* 1ul << delta_time_multiplier_order */ static const uint64_t delta_time_max = 0x1FFFFFFFE00; /* UINT32_MAX << delta_time_multiplier_order */ enum ConfigCmds { CONFIG_CMD_DISABLE = 0, CONFIG_CMD_ENABLE = 1, CONFIG_CMD_FLUSH = 2, CONFIG_CMD_CFG_DATA = 3, CONFIG_CMD_CALIBRATE = 4, CONFIG_CMD_SELF_TEST = 5, }; struct ConfigCmd { uint64_t latency; uint32_t rate; uint8_t sensType; uint8_t cmd; uint16_t flags; } __attribute__((packed)); struct ActiveSensor { uint64_t latency; uint64_t firstTime; uint64_t lastTime; struct HostIntfDataBuffer buffer; uint32_t rate; uint32_t sensorHandle; float rawScale; uint16_t minSamples; uint16_t curSamples; uint8_t numAxis; uint8_t interrupt; uint8_t numSamples; uint8_t packetSamples; // The sensorType used to report bias samples; normally the same as // buffer.sensorType, but in the case of raw, this gets set to the base // sensorType matching struct SensorInfo (because the sensor can have a // different rawType). Note that this is different than biasType in struct // SensorInfo. uint8_t biasReportType; uint8_t oneshot : 1; uint8_t discard : 1; uint8_t raw : 1; uint8_t reserved : 5; } __attribute__((packed)); static uint8_t mSensorList[SENS_TYPE_LAST_USER]; static struct SimpleQueue *mOutputQ; static struct ActiveSensor *mActiveSensorTable; static uint8_t mNumSensors; static uint8_t mLastSensor; static const struct HostIntfComm *mComm; static bool mBusy; static uint64_t mRxTimestamp; static uint8_t mRxBuf[NANOHUB_PACKET_SIZE_MAX]; static size_t mRxSize; static struct { const struct NanohubCommand *cmd; uint32_t seq; bool seqMatch; } mTxRetrans; static struct { uint8_t pad; // packet header is 10 bytes. + 2 to word align uint8_t prePreamble; uint8_t buf[NANOHUB_PACKET_SIZE_MAX]; uint8_t postPreamble; } mTxBuf; static struct { uint8_t pad; // packet header is 10 bytes. + 2 to word align uint8_t prePreamble; uint8_t buf[NANOHUB_PACKET_SIZE_MIN]; uint8_t postPreamble; } mTxNakBuf; static size_t mTxSize; static uint8_t *mTxBufPtr; static const struct NanohubCommand *mRxCmd; ATOMIC_BITSET_DECL(mInterrupt, HOSTINTF_MAX_INTERRUPTS, static); ATOMIC_BITSET_DECL(mInterruptMask, HOSTINTF_MAX_INTERRUPTS, static); static uint32_t mInterruptCntWkup, mInterruptCntNonWkup; static uint32_t mWakeupBlocks, mNonWakeupBlocks, mTotalBlocks; static uint32_t mHostIntfTid; static uint32_t mLatencyTimer; static uint8_t mLatencyCnt; static uint8_t mRxIdle; static uint8_t mWakeActive; static uint8_t mActiveWrite; static uint8_t mRestartRx; static uint8_t mIntErrMsgIdx; static volatile uint32_t mIntErrMsgCnt; enum hostIntfIntErrReason { HOSTINTF_ERR_PKG_INCOMPELETE = 0, HOSTINTF_ERR_PGK_SIZE, HOSTINTF_ERR_PKG_PAYLOAD_SIZE, HOSTINTF_ERR_PKG_CRC, HOSTINTF_ERR_RECEIVE, HOSTINTF_ERR_SEND, HOSTINTF_ERR_ACK, HOSTINTF_ERR_NAK, HOSTINTF_ERR_UNKNOWN }; struct hostIntfIntErrMsg { enum LogLevel level; enum hostIntfIntErrReason reason; const char *func; }; static struct hostIntfIntErrMsg mIntErrMsg[HOSTINTF_MAX_ERR_MSG]; static void hostIntfTxPacket(uint32_t reason, uint8_t len, uint32_t seq, HostIntfCommCallbackF callback); static void hostIntfRxDone(size_t rx, int err); static void hostIntfGenerateAck(void *cookie); static void hostIntfTxAckDone(size_t tx, int err); static void hostIntfGenerateResponse(void *cookie); static void hostIntfTxPayloadDone(size_t tx, int err); static inline void *hostIntfGetPayload(uint8_t *buf) { struct NanohubPacket *packet = (struct NanohubPacket *)buf; return packet->data; } static inline uint8_t hostIntfGetPayloadLen(uint8_t *buf) { struct NanohubPacket *packet = (struct NanohubPacket *)buf; return packet->len; } static inline struct NanohubPacketFooter *hostIntfGetFooter(uint8_t *buf) { struct NanohubPacket *packet = (struct NanohubPacket *)buf; return (struct NanohubPacketFooter *)(buf + sizeof(*packet) + packet->len); } static inline __le32 hostIntfComputeCrc(uint8_t *buf) { struct NanohubPacket *packet = (struct NanohubPacket *)buf; uint32_t crc = crc32(packet, packet->len + sizeof(*packet), CRC_INIT); return htole32(crc); } static void hostIntfPrintErrMsg(void *cookie) { struct hostIntfIntErrMsg *msg = (struct hostIntfIntErrMsg *)cookie; osLog(msg->level, "%s failed with: %d\n", msg->func, msg->reason); atomicAdd32bits(&mIntErrMsgCnt, -1UL); } static void hostIntfDeferErrLog(enum LogLevel level, enum hostIntfIntErrReason reason, const char *func) { // If the message buffer is full, we drop the newer messages. if (atomicRead32bits(&mIntErrMsgCnt) == HOSTINTF_MAX_ERR_MSG) return; mIntErrMsg[mIntErrMsgIdx].level = level; mIntErrMsg[mIntErrMsgIdx].reason = reason; mIntErrMsg[mIntErrMsgIdx].func = func; if (osDefer(hostIntfPrintErrMsg, &mIntErrMsg[mIntErrMsgIdx], false)) { atomicAdd32bits(&mIntErrMsgCnt, 1UL); mIntErrMsgIdx = (mIntErrMsgIdx + 1) % HOSTINTF_MAX_ERR_MSG; } } static inline const struct NanohubCommand *hostIntfFindHandler(uint8_t *buf, size_t size, uint32_t *seq) { struct NanohubPacket *packet = (struct NanohubPacket *)buf; struct NanohubPacketFooter *footer; __le32 packetCrc; uint32_t packetReason; const struct NanohubCommand *cmd; if (size < NANOHUB_PACKET_SIZE(0)) { hostIntfDeferErrLog(LOG_WARN, HOSTINTF_ERR_PKG_INCOMPELETE, __func__); return NULL; } if (size != NANOHUB_PACKET_SIZE(packet->len)) { hostIntfDeferErrLog(LOG_WARN, HOSTINTF_ERR_PGK_SIZE, __func__); return NULL; } footer = hostIntfGetFooter(buf); packetCrc = hostIntfComputeCrc(buf); if (footer->crc != packetCrc) { hostIntfDeferErrLog(LOG_WARN, HOSTINTF_ERR_PKG_CRC, __func__); return NULL; } if (mTxRetrans.seq == packet->seq) { mTxRetrans.seqMatch = true; return mTxRetrans.cmd; } else { mTxRetrans.seqMatch = false; } *seq = packet->seq; if (mBusy) return NULL; packetReason = le32toh(packet->reason); if ((cmd = nanohubFindCommand(packetReason)) != NULL) { if (packet->len < cmd->minDataLen || packet->len > cmd->maxDataLen) { hostIntfDeferErrLog(LOG_WARN, HOSTINTF_ERR_PKG_PAYLOAD_SIZE, __func__); return NULL; } return cmd; } hostIntfDeferErrLog(LOG_WARN, HOSTINTF_ERR_UNKNOWN, __func__); return NULL; } static void hostIntfTxBuf(int size, uint8_t *buf, HostIntfCommCallbackF callback) { mTxSize = size; mTxBufPtr = buf; mComm->txPacket(mTxBufPtr, mTxSize, callback); } static void hostIntfTxPacket(__le32 reason, uint8_t len, uint32_t seq, HostIntfCommCallbackF callback) { struct NanohubPacket *txPacket = (struct NanohubPacket *)(mTxBuf.buf); txPacket->reason = reason; txPacket->seq = seq; txPacket->sync = NANOHUB_SYNC_BYTE; txPacket->len = len; struct NanohubPacketFooter *txFooter = hostIntfGetFooter(mTxBuf.buf); txFooter->crc = hostIntfComputeCrc(mTxBuf.buf); // send starting with the prePremable byte hostIntfTxBuf(1+NANOHUB_PACKET_SIZE(len), &mTxBuf.prePreamble, callback); } static void hostIntfTxNakPacket(__le32 reason, uint32_t seq, HostIntfCommCallbackF callback) { struct NanohubPacket *txPacket = (struct NanohubPacket *)(mTxNakBuf.buf); txPacket->reason = reason; txPacket->seq = seq; txPacket->sync = NANOHUB_SYNC_BYTE; txPacket->len = 0; struct NanohubPacketFooter *txFooter = hostIntfGetFooter(mTxNakBuf.buf); txFooter->crc = hostIntfComputeCrc(mTxNakBuf.buf); // send starting with the prePremable byte hostIntfTxBuf(1+NANOHUB_PACKET_SIZE_MIN, &mTxNakBuf.prePreamble, callback); } static inline bool hostIntfTxPacketDone(int err, size_t tx, HostIntfCommCallbackF callback) { if (!err && tx < mTxSize) { mTxSize -= tx; mTxBufPtr += tx; mComm->txPacket(mTxBufPtr, mTxSize, callback); return false; } return true; } static bool hostIntfRequest(uint32_t tid) { mHostIntfTid = tid; atomicBitsetInit(mInterrupt, HOSTINTF_MAX_INTERRUPTS); atomicBitsetInit(mInterruptMask, HOSTINTF_MAX_INTERRUPTS); #ifdef AP_INT_NONWAKEUP hostIntfSetInterruptMask(NANOHUB_INT_NONWAKEUP); #endif mTxBuf.prePreamble = NANOHUB_PREAMBLE_BYTE; mTxBuf.postPreamble = NANOHUB_PREAMBLE_BYTE; mTxNakBuf.prePreamble = NANOHUB_PREAMBLE_BYTE; mTxNakBuf.postPreamble = NANOHUB_PREAMBLE_BYTE; mComm = platHostIntfInit(); if (mComm) { int err = mComm->request(); if (!err) { nanohubInitCommand(); mComm->rxPacket(mRxBuf, sizeof(mRxBuf), hostIntfRxDone); osEventSubscribe(mHostIntfTid, EVT_APP_START); return true; } } return false; } void hostIntfRxPacket(bool wakeupActive) { if (mWakeActive) { if (atomicXchgByte(&mRxIdle, false)) { if (!wakeupActive) hostIntfClearInterrupt(NANOHUB_INT_WAKE_COMPLETE); mComm->rxPacket(mRxBuf, sizeof(mRxBuf), hostIntfRxDone); if (wakeupActive) hostIntfSetInterrupt(NANOHUB_INT_WAKE_COMPLETE); } else if (atomicReadByte(&mActiveWrite)) { atomicWriteByte(&mRestartRx, true); } else { if (!wakeupActive) hostIntfClearInterrupt(NANOHUB_INT_WAKE_COMPLETE); else hostIntfSetInterrupt(NANOHUB_INT_WAKE_COMPLETE); } } else if (wakeupActive && !atomicReadByte(&mActiveWrite)) hostIntfSetInterrupt(NANOHUB_INT_WAKE_COMPLETE); mWakeActive = wakeupActive; } static void hostIntfRxDone(size_t rx, int err) { mRxTimestamp = sensorGetTime(); mRxSize = rx; if (err != 0) { hostIntfDeferErrLog(LOG_ERROR, HOSTINTF_ERR_RECEIVE, __func__); return; } hostIntfGenerateAck(NULL); } static void hostIntfTxSendAck(uint32_t resp) { void *txPayload = hostIntfGetPayload(mTxBuf.buf); if (resp == NANOHUB_FAST_UNHANDLED_ACK) { hostIntfCopyInterrupts(txPayload, HOSTINTF_MAX_INTERRUPTS); hostIntfTxPacket(NANOHUB_REASON_ACK, 32, mTxRetrans.seq, hostIntfTxAckDone); } else if (resp == NANOHUB_FAST_DONT_ACK) { // do nothing. something else will do the ack } else { hostIntfTxPacket(mRxCmd->reason, resp, mTxRetrans.seq, hostIntfTxPayloadDone); } } void hostIntfTxAck(void *buffer, uint8_t len) { void *txPayload = hostIntfGetPayload(mTxBuf.buf); memcpy(txPayload, buffer, len); hostIntfTxSendAck(len); } static void hostIntfGenerateAck(void *cookie) { uint32_t seq = 0; void *txPayload = hostIntfGetPayload(mTxBuf.buf); void *rxPayload = hostIntfGetPayload(mRxBuf); uint8_t rx_len = hostIntfGetPayloadLen(mRxBuf); uint32_t resp = NANOHUB_FAST_UNHANDLED_ACK; atomicWriteByte(&mActiveWrite, true); hostIntfSetInterrupt(NANOHUB_INT_WAKE_COMPLETE); mRxCmd = hostIntfFindHandler(mRxBuf, mRxSize, &seq); if (mRxCmd) { if (mTxRetrans.seqMatch) { hostIntfTxBuf(mTxSize, &mTxBuf.prePreamble, hostIntfTxPayloadDone); } else { mTxRetrans.seq = seq; mTxRetrans.cmd = mRxCmd; if (mRxCmd->fastHandler) resp = mRxCmd->fastHandler(rxPayload, rx_len, txPayload, mRxTimestamp); hostIntfTxSendAck(resp); } } else { if (mBusy) hostIntfTxNakPacket(NANOHUB_REASON_NAK_BUSY, seq, hostIntfTxAckDone); else hostIntfTxNakPacket(NANOHUB_REASON_NAK, seq, hostIntfTxAckDone); } } static void hostIntfTxComplete(bool clearInt, bool restartRx) { if (restartRx || clearInt || !mWakeActive) hostIntfClearInterrupt(NANOHUB_INT_WAKE_COMPLETE); atomicWriteByte(&mActiveWrite, false); atomicWriteByte(&mRestartRx, false); if (restartRx) { mComm->rxPacket(mRxBuf, sizeof(mRxBuf), hostIntfRxDone); hostIntfSetInterrupt(NANOHUB_INT_WAKE_COMPLETE); } else { atomicWriteByte(&mRxIdle, true); } } static void hostIntfTxAckDone(size_t tx, int err) { hostIntfTxPacketDone(err, tx, hostIntfTxAckDone); if (err) { hostIntfDeferErrLog(LOG_ERROR, HOSTINTF_ERR_ACK, __func__); hostIntfTxComplete(false, false); return; } if (!mRxCmd) { if (!mBusy) hostIntfDeferErrLog(LOG_DEBUG, HOSTINTF_ERR_NAK, __func__); if (atomicReadByte(&mRestartRx)) hostIntfTxComplete(false, true); else hostIntfTxComplete(false, false); return; } else if (atomicReadByte(&mRestartRx)) { mTxRetrans.seq = 0; mTxRetrans.cmd = NULL; hostIntfTxComplete(false, true); } else { if (!osDefer(hostIntfGenerateResponse, NULL, true)) { mTxRetrans.seq = 0; mTxRetrans.cmd = NULL; hostIntfTxComplete(false, false); } } } static void hostIntfGenerateResponse(void *cookie) { void *rxPayload = hostIntfGetPayload(mRxBuf); uint8_t rx_len = hostIntfGetPayloadLen(mRxBuf); void *txPayload = hostIntfGetPayload(mTxBuf.buf); uint8_t respLen = mRxCmd->handler(rxPayload, rx_len, txPayload, mRxTimestamp); hostIntfTxPacket(mRxCmd->reason, respLen, mTxRetrans.seq, hostIntfTxPayloadDone); } static void hostIntfTxPayloadDone(size_t tx, int err) { bool done = hostIntfTxPacketDone(err, tx, hostIntfTxPayloadDone); if (err) hostIntfDeferErrLog(LOG_ERROR, HOSTINTF_ERR_SEND, __func__); if (done) { if (atomicReadByte(&mRestartRx)) hostIntfTxComplete(true, true); else hostIntfTxComplete(true, false); } } static void hostIntfRelease() { mComm->release(); } static void resetBuffer(struct ActiveSensor *sensor) { sensor->discard = true; sensor->buffer.length = 0; memset(&sensor->buffer.firstSample, 0x00, sizeof(struct SensorFirstSample)); } void hostIntfSetBusy(bool busy) { mBusy = busy; } static inline struct ActiveSensor *getActiveSensorByType(uint32_t sensorType) { struct ActiveSensor *sensor = NULL; if (sensorType > SENS_TYPE_INVALID && sensorType <= SENS_TYPE_LAST_USER && mSensorList[sensorType - 1] < MAX_REGISTERED_SENSORS) sensor = mActiveSensorTable + mSensorList[sensorType - 1]; return sensor; } bool hostIntfPacketDequeue(void *data, uint32_t *wakeup, uint32_t *nonwakeup) { struct HostIntfDataBuffer *buffer = data; bool ret; struct ActiveSensor *sensor; uint32_t i; ret = simpleQueueDequeue(mOutputQ, buffer); while (ret) { sensor = getActiveSensorByType(buffer->sensType); if (sensor) { // do not sent sensor data if sensor is not requested; only maintain stats if (sensor->sensorHandle == 0 && !buffer->firstSample.biasPresent && !buffer->firstSample.numFlushes) { if (sensor->interrupt == NANOHUB_INT_WAKEUP) mWakeupBlocks--; else if (sensor->interrupt == NANOHUB_INT_NONWAKEUP) mNonWakeupBlocks--; sensor->curSamples -= buffer->firstSample.numSamples; ret = simpleQueueDequeue(mOutputQ, buffer); } else { break; } } else { break; } } if (!ret) { // nothing in queue. look for partial buffers to flush for (i = 0; i < mNumSensors; i++, mLastSensor = (mLastSensor + 1) % mNumSensors) { sensor = mActiveSensorTable + mLastSensor; if (sensor->curSamples != sensor->buffer.firstSample.numSamples) { osLog(LOG_ERROR, "hostIntfPacketDequeue: sensor(%d)->curSamples=%d != buffer->numSamples=%d\n", sensor->buffer.sensType, sensor->curSamples, sensor->buffer.firstSample.numSamples); sensor->curSamples = sensor->buffer.firstSample.numSamples; } if (sensor->buffer.length > 0) { memcpy(buffer, &sensor->buffer, sizeof(struct HostIntfDataBuffer)); resetBuffer(sensor); ret = true; mLastSensor = (mLastSensor + 1) % mNumSensors; break; } } } if (ret) { sensor = getActiveSensorByType(buffer->sensType); if (sensor) { if (sensor->interrupt == NANOHUB_INT_WAKEUP) mWakeupBlocks--; else if (sensor->interrupt == NANOHUB_INT_NONWAKEUP) mNonWakeupBlocks--; sensor->curSamples -= buffer->firstSample.numSamples; sensor->firstTime = 0ull; } else { if (buffer->interrupt == NANOHUB_INT_WAKEUP) mWakeupBlocks--; else if (buffer->interrupt == NANOHUB_INT_NONWAKEUP) mNonWakeupBlocks--; } } *wakeup = mWakeupBlocks; *nonwakeup = mNonWakeupBlocks; return ret; } static void initCompleteCallback(uint32_t timerId, void *data) { osEnqueuePrivateEvt(EVT_APP_START, NULL, NULL, mHostIntfTid); } static bool queueDiscard(void *data, bool onDelete) { struct HostIntfDataBuffer *buffer = data; struct ActiveSensor *sensor = getActiveSensorByType(buffer->sensType); if (sensor) { if (sensor->curSamples - buffer->firstSample.numSamples >= sensor->minSamples || onDelete) { if (sensor->interrupt == NANOHUB_INT_WAKEUP) mWakeupBlocks--; else if (sensor->interrupt == NANOHUB_INT_NONWAKEUP) mNonWakeupBlocks--; sensor->curSamples -= buffer->firstSample.numSamples; return true; } else { return false; } } else { if (buffer->interrupt == NANOHUB_INT_WAKEUP) mWakeupBlocks--; else if (buffer->interrupt == NANOHUB_INT_NONWAKEUP) mNonWakeupBlocks--; return true; } } static void latencyTimerCallback(uint32_t timerId, void* data) { osEnqueuePrivateEvt(EVT_LATENCY_TIMER, data, NULL, mHostIntfTid); } static bool initSensors() { uint32_t i, j, blocks, maxBlocks, numAxis, packetSamples; bool present, error; const struct SensorInfo *si; uint32_t handle; static uint8_t errorCnt = 0; uint32_t totalBlocks = 0; uint8_t numSensors = 0; ATOMIC_BITSET_DECL(sensorPresent, SENS_TYPE_LAST_USER - SENS_TYPE_INVALID,); atomicBitsetInit(sensorPresent, SENS_TYPE_LAST_USER - SENS_TYPE_INVALID); for (i = SENS_TYPE_INVALID + 1; i <= SENS_TYPE_LAST_USER; i++) { for (j = 0, present = 0, error = 0; (si = sensorFind(i, j, &handle)) != NULL; j++) { if (!sensorGetInitComplete(handle)) { if (errorCnt >= SENSOR_INIT_ERROR_MAX) { osLog(LOG_ERROR, "initSensors: %s not ready - skipping!\n", si->sensorName); continue; } else { osLog(LOG_INFO, "initSensors: %s not ready!\n", si->sensorName); timTimerSet(SENSOR_INIT_DELAY, 0, 50, initCompleteCallback, NULL, true); errorCnt ++; return false; } } else if (!(si->flags1 & SENSOR_INFO_FLAGS1_LOCAL_ONLY)) { if (!present) { present = 1; numAxis = si->numAxis; switch (si->numAxis) { case NUM_AXIS_EMBEDDED: case NUM_AXIS_ONE: packetSamples = HOSTINTF_SENSOR_DATA_MAX / sizeof(struct SingleAxisDataPoint); break; case NUM_AXIS_THREE: if (si->flags1 & SENSOR_INFO_FLAGS1_RAW) packetSamples = HOSTINTF_SENSOR_DATA_MAX / sizeof(struct RawTripleAxisDataPoint); else packetSamples = HOSTINTF_SENSOR_DATA_MAX / sizeof(struct TripleAxisDataPoint); break; default: packetSamples = 1; error = true; } if (si->minSamples > MAX_MIN_SAMPLES) maxBlocks = (MAX_MIN_SAMPLES + packetSamples - 1) / packetSamples; else maxBlocks = (si->minSamples + packetSamples - 1) / packetSamples; } else { if (si->numAxis != numAxis) { error = true; } else { if (si->minSamples > MAX_MIN_SAMPLES) blocks = (MAX_MIN_SAMPLES + packetSamples - 1) / packetSamples; else blocks = (si->minSamples + packetSamples - 1) / packetSamples; maxBlocks = maxBlocks > blocks ? maxBlocks : blocks; } } } } if (present && !error) { atomicBitsetSetBit(sensorPresent, i - 1); numSensors++; totalBlocks += maxBlocks; } } if (totalBlocks > MAX_NUM_BLOCKS) { osLog(LOG_INFO, "initSensors: totalBlocks of %ld exceeds maximum of %d\n", totalBlocks, MAX_NUM_BLOCKS); totalBlocks = MAX_NUM_BLOCKS; } else if (totalBlocks < MIN_NUM_BLOCKS) { totalBlocks = MIN_NUM_BLOCKS; } mOutputQ = simpleQueueAlloc(totalBlocks, sizeof(struct HostIntfDataBuffer), queueDiscard); if (!mOutputQ) { osLog(LOG_ERROR, "initSensors: failed to allocate data buffer queue!\n"); return false; } mActiveSensorTable = heapAlloc(numSensors * sizeof(struct ActiveSensor)); if (!mActiveSensorTable) { osLog(LOG_ERROR, "initSensors: failed to allocate active sensor table!\n"); simpleQueueDestroy(mOutputQ); return false; } memset(mActiveSensorTable, 0x00, numSensors * sizeof(struct ActiveSensor)); for (i = SENS_TYPE_INVALID; i < SENS_TYPE_LAST_USER; i++) { mSensorList[i] = MAX_REGISTERED_SENSORS; } for (i = SENS_TYPE_INVALID + 1, j = 0; i <= SENS_TYPE_LAST_USER && j < numSensors; i++) { if (atomicBitsetGetBit(sensorPresent, i - 1) && (si = sensorFind(i, 0, &handle)) != NULL && !(si->flags1 & SENSOR_INFO_FLAGS1_LOCAL_ONLY)) { mSensorList[i - 1] = j; resetBuffer(mActiveSensorTable + j); mActiveSensorTable[j].buffer.sensType = i; mActiveSensorTable[j].biasReportType = 0; mActiveSensorTable[j].rate = 0; mActiveSensorTable[j].latency = 0; mActiveSensorTable[j].numAxis = si->numAxis; mActiveSensorTable[j].interrupt = si->interrupt; if (si->flags1 & SENSOR_INFO_FLAGS1_RAW) { mSensorList[si->rawType - 1] = j; mActiveSensorTable[j].buffer.sensType = si->rawType; mActiveSensorTable[j].raw = true; mActiveSensorTable[j].rawScale = si->rawScale; } if (si->flags1 & SENSOR_INFO_FLAGS1_BIAS) { mSensorList[si->biasType - 1] = j; mActiveSensorTable[j].biasReportType = i; osEventSubscribe(mHostIntfTid, sensorGetMyEventType(si->biasType)); } if (si->minSamples > MAX_MIN_SAMPLES) { mActiveSensorTable[j].minSamples = MAX_MIN_SAMPLES; osLog(LOG_INFO, "initSensors: %s: minSamples of %d exceeded max of %d\n", si->sensorName, si->minSamples, MAX_MIN_SAMPLES); } else { mActiveSensorTable[j].minSamples = si->minSamples; } mActiveSensorTable[j].curSamples = 0; mActiveSensorTable[j].oneshot = false; mActiveSensorTable[j].firstTime = 0ull; switch (si->numAxis) { case NUM_AXIS_EMBEDDED: case NUM_AXIS_ONE: mActiveSensorTable[j].packetSamples = HOSTINTF_SENSOR_DATA_MAX / sizeof(struct SingleAxisDataPoint); break; case NUM_AXIS_THREE: if (mActiveSensorTable[j].raw) mActiveSensorTable[j].packetSamples = HOSTINTF_SENSOR_DATA_MAX / sizeof(struct RawTripleAxisDataPoint); else mActiveSensorTable[j].packetSamples = HOSTINTF_SENSOR_DATA_MAX / sizeof(struct TripleAxisDataPoint); break; } j++; } } mTotalBlocks = totalBlocks; mNumSensors = numSensors; return true; } static inline int16_t floatToInt16(float val) { if (val < (INT16_MIN + 0.5f)) return INT16_MIN; else if (val > (INT16_MAX - 0.5f)) return INT16_MAX; else if (val >= 0.0f) return val + 0.5f; else return val - 0.5f; } static uint32_t encodeDeltaTime(uint64_t time) { uint32_t deltaTime; if (time <= UINT32_MAX) { deltaTime = time | delta_time_fine_mask; } else { deltaTime = ((time + delta_time_rounding) >> delta_time_multiplier_order) & delta_time_coarse_mask; } return deltaTime; } static bool enqueueSensorBuffer(struct ActiveSensor *sensor) { bool queued = simpleQueueEnqueue(mOutputQ, &sensor->buffer, sizeof(uint32_t) + sensor->buffer.length, sensor->discard); if (!queued) { // undo counters if failed to add buffer if (sensor->interrupt == NANOHUB_INT_WAKEUP) mWakeupBlocks--; else if (sensor->interrupt == NANOHUB_INT_NONWAKEUP) mNonWakeupBlocks--; sensor->curSamples -= sensor->buffer.firstSample.numSamples; } resetBuffer(sensor); return queued; } static void copySingleSamples(struct ActiveSensor *sensor, const struct SingleAxisDataEvent *single) { int i; uint32_t deltaTime; uint8_t numSamples; uint8_t evtNumSamples = single->samples[0].firstSample.numSamples; for (i = 0; i < evtNumSamples; i++) { if (sensor->buffer.firstSample.numSamples == sensor->packetSamples) enqueueSensorBuffer(sensor); if (sensor->buffer.firstSample.numSamples == 0) { if (i == 0) { sensor->lastTime = sensor->buffer.referenceTime = single->referenceTime; } else { sensor->lastTime += single->samples[i].deltaTime; sensor->buffer.referenceTime = sensor->lastTime; } sensor->buffer.length = sizeof(struct SingleAxisDataEvent) + sizeof(struct SingleAxisDataPoint); sensor->buffer.single[0].idata = single->samples[i].idata; if (sensor->interrupt == NANOHUB_INT_WAKEUP) mWakeupBlocks++; else if (sensor->interrupt == NANOHUB_INT_NONWAKEUP) mNonWakeupBlocks++; sensor->buffer.firstSample.numSamples = 1; sensor->buffer.firstSample.interrupt = sensor->interrupt; if (sensor->curSamples++ == 0) sensor->firstTime = sensor->buffer.referenceTime; } else { if (i == 0) { if (sensor->lastTime > single->referenceTime) { // shouldn't happen. flush current packet enqueueSensorBuffer(sensor); i--; } else if (single->referenceTime - sensor->lastTime >= delta_time_max) { enqueueSensorBuffer(sensor); i--; } else { deltaTime = encodeDeltaTime(single->referenceTime - sensor->lastTime); numSamples = sensor->buffer.firstSample.numSamples; sensor->buffer.length += sizeof(struct SingleAxisDataPoint); sensor->buffer.single[numSamples].deltaTime = deltaTime; sensor->buffer.single[numSamples].idata = single->samples[0].idata; sensor->lastTime = single->referenceTime; sensor->buffer.firstSample.numSamples++; sensor->curSamples++; } } else { deltaTime = single->samples[i].deltaTime; numSamples = sensor->buffer.firstSample.numSamples; sensor->buffer.length += sizeof(struct SingleAxisDataPoint); sensor->buffer.single[numSamples].deltaTime = deltaTime | delta_time_fine_mask; sensor->buffer.single[numSamples].idata = single->samples[i].idata; sensor->lastTime += deltaTime; sensor->buffer.firstSample.numSamples++; sensor->curSamples++; } } } } static void copyTripleSamples(struct ActiveSensor *sensor, const struct TripleAxisDataEvent *triple) { int i; uint32_t deltaTime; uint8_t numSamples; for (i = 0; i < triple->samples[0].firstSample.numSamples; i++) { if (sensor->buffer.firstSample.numSamples == sensor->packetSamples) enqueueSensorBuffer(sensor); if (sensor->buffer.firstSample.numSamples == 0) { if (i == 0) { sensor->lastTime = sensor->buffer.referenceTime = triple->referenceTime; } else { sensor->lastTime += triple->samples[i].deltaTime; sensor->buffer.referenceTime = sensor->lastTime; } sensor->buffer.length = sizeof(struct TripleAxisDataEvent) + sizeof(struct TripleAxisDataPoint); sensor->buffer.triple[0].ix = triple->samples[i].ix; sensor->buffer.triple[0].iy = triple->samples[i].iy; sensor->buffer.triple[0].iz = triple->samples[i].iz; if (triple->samples[0].firstSample.biasPresent && triple->samples[0].firstSample.biasSample == i) { sensor->buffer.firstSample.biasCurrent = triple->samples[0].firstSample.biasCurrent; sensor->buffer.firstSample.biasPresent = 1; sensor->buffer.firstSample.biasSample = 0; sensor->discard = false; } if (sensor->interrupt == NANOHUB_INT_WAKEUP) mWakeupBlocks++; else if (sensor->interrupt == NANOHUB_INT_NONWAKEUP) mNonWakeupBlocks++; sensor->buffer.firstSample.numSamples = 1; sensor->buffer.firstSample.interrupt = sensor->interrupt; if (sensor->curSamples++ == 0) sensor->firstTime = sensor->buffer.referenceTime; } else { if (i == 0) { if (sensor->lastTime > triple->referenceTime) { // shouldn't happen. flush current packet enqueueSensorBuffer(sensor); i--; } else if (triple->referenceTime - sensor->lastTime >= delta_time_max) { enqueueSensorBuffer(sensor); i--; } else { deltaTime = encodeDeltaTime(triple->referenceTime - sensor->lastTime); numSamples = sensor->buffer.firstSample.numSamples; sensor->buffer.length += sizeof(struct TripleAxisDataPoint); sensor->buffer.triple[numSamples].deltaTime = deltaTime; sensor->buffer.triple[numSamples].ix = triple->samples[0].ix; sensor->buffer.triple[numSamples].iy = triple->samples[0].iy; sensor->buffer.triple[numSamples].iz = triple->samples[0].iz; sensor->lastTime = triple->referenceTime; if (triple->samples[0].firstSample.biasPresent && triple->samples[0].firstSample.biasSample == 0) { sensor->buffer.firstSample.biasCurrent = triple->samples[0].firstSample.biasCurrent; sensor->buffer.firstSample.biasPresent = 1; sensor->buffer.firstSample.biasSample = numSamples; sensor->discard = false; } sensor->buffer.firstSample.numSamples++; sensor->curSamples++; } } else { deltaTime = triple->samples[i].deltaTime; numSamples = sensor->buffer.firstSample.numSamples; sensor->buffer.length += sizeof(struct TripleAxisDataPoint); sensor->buffer.triple[numSamples].deltaTime = deltaTime | delta_time_fine_mask; sensor->buffer.triple[numSamples].ix = triple->samples[i].ix; sensor->buffer.triple[numSamples].iy = triple->samples[i].iy; sensor->buffer.triple[numSamples].iz = triple->samples[i].iz; sensor->lastTime += deltaTime; if (triple->samples[0].firstSample.biasPresent && triple->samples[0].firstSample.biasSample == i) { sensor->buffer.firstSample.biasCurrent = triple->samples[0].firstSample.biasCurrent; sensor->buffer.firstSample.biasPresent = 1; sensor->buffer.firstSample.biasSample = numSamples; sensor->discard = false; } sensor->buffer.firstSample.numSamples++; sensor->curSamples++; } } } } static void copyTripleSamplesBias(struct ActiveSensor *sensor, const struct TripleAxisDataEvent *triple) { uint8_t sensType = sensor->buffer.sensType; if (sensType == sensor->biasReportType) { copyTripleSamples(sensor, triple); } else { // Bias needs to be sent with a different sensType, so enqueue any pending buffer, enqueue // bias with a different sensor type, then restore the sensType if (sensor->buffer.firstSample.numSamples > 0) enqueueSensorBuffer(sensor); sensor->buffer.sensType = sensor->biasReportType; copyTripleSamples(sensor, triple); if (sensor->buffer.firstSample.numSamples > 0) enqueueSensorBuffer(sensor); sensor->buffer.sensType = sensType; } } static void copyTripleSamplesRaw(struct ActiveSensor *sensor, const struct TripleAxisDataEvent *triple) { int i; uint32_t deltaTime; uint8_t numSamples; // Bias not supported in raw format; treat as regular format triple samples (potentially // handling alternate bias report type) if (triple->samples[0].firstSample.biasPresent) { copyTripleSamplesBias(sensor, triple); return; } for (i = 0; i < triple->samples[0].firstSample.numSamples; i++) { if (sensor->buffer.firstSample.numSamples == sensor->packetSamples) enqueueSensorBuffer(sensor); if (sensor->buffer.firstSample.numSamples == 0) { if (i == 0) { sensor->lastTime = sensor->buffer.referenceTime = triple->referenceTime; } else { sensor->lastTime += triple->samples[i].deltaTime; sensor->buffer.referenceTime = sensor->lastTime; } sensor->buffer.length = sizeof(struct RawTripleAxisDataEvent) + sizeof(struct RawTripleAxisDataPoint); sensor->buffer.rawTriple[0].ix = floatToInt16(triple->samples[i].x * sensor->rawScale); sensor->buffer.rawTriple[0].iy = floatToInt16(triple->samples[i].y * sensor->rawScale); sensor->buffer.rawTriple[0].iz = floatToInt16(triple->samples[i].z * sensor->rawScale); if (sensor->interrupt == NANOHUB_INT_WAKEUP) mWakeupBlocks++; else if (sensor->interrupt == NANOHUB_INT_NONWAKEUP) mNonWakeupBlocks++; sensor->buffer.firstSample.numSamples = 1; sensor->buffer.firstSample.interrupt = sensor->interrupt; if (sensor->curSamples++ == 0) sensor->firstTime = sensor->buffer.referenceTime; } else { if (i == 0) { if (sensor->lastTime > triple->referenceTime) { // shouldn't happen. flush current packet enqueueSensorBuffer(sensor); i--; } else if (triple->referenceTime - sensor->lastTime >= delta_time_max) { enqueueSensorBuffer(sensor); i--; } else { deltaTime = encodeDeltaTime(triple->referenceTime - sensor->lastTime); numSamples = sensor->buffer.firstSample.numSamples; sensor->buffer.length += sizeof(struct RawTripleAxisDataPoint); sensor->buffer.rawTriple[numSamples].deltaTime = deltaTime; sensor->buffer.rawTriple[numSamples].ix = floatToInt16(triple->samples[0].x * sensor->rawScale); sensor->buffer.rawTriple[numSamples].iy = floatToInt16(triple->samples[0].y * sensor->rawScale); sensor->buffer.rawTriple[numSamples].iz = floatToInt16(triple->samples[0].z * sensor->rawScale); sensor->lastTime = triple->referenceTime; sensor->buffer.firstSample.numSamples++; sensor->curSamples++; } } else { deltaTime = triple->samples[i].deltaTime; numSamples = sensor->buffer.firstSample.numSamples; sensor->buffer.length += sizeof(struct RawTripleAxisDataPoint); sensor->buffer.rawTriple[numSamples].deltaTime = deltaTime | delta_time_fine_mask; sensor->buffer.rawTriple[numSamples].ix = floatToInt16(triple->samples[i].x * sensor->rawScale); sensor->buffer.rawTriple[numSamples].iy = floatToInt16(triple->samples[i].y * sensor->rawScale); sensor->buffer.rawTriple[numSamples].iz = floatToInt16(triple->samples[i].z * sensor->rawScale); sensor->lastTime += deltaTime; sensor->buffer.firstSample.numSamples++; sensor->curSamples++; } } } } static void hostIntfAddBlock(struct HostIntfDataBuffer *data, bool discardable, bool interrupt) { if (!simpleQueueEnqueue(mOutputQ, data, sizeof(uint32_t) + data->length, discardable)) return; if (data->interrupt == NANOHUB_INT_WAKEUP) mWakeupBlocks++; else if (data->interrupt == NANOHUB_INT_NONWAKEUP) mNonWakeupBlocks++; nanohubPrefetchTx(interrupt ? data->interrupt : HOSTINTF_MAX_INTERRUPTS, mWakeupBlocks, mNonWakeupBlocks); } static void hostIntfNotifyReboot(uint32_t reason) { __le32 raw_reason = htole32(reason); struct NanohubHalSysMgmtTx *resp; resp = heapAlloc(sizeof(*resp)); if (resp) { resp->hdr = (struct NanohubHalHdr) { .appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0), .len = sizeof(*resp) - sizeof(resp->hdr), }; resp->ret = (struct NanohubHalRet) { .msg = NANOHUB_HAL_SYS_MGMT, .status = raw_reason, }; resp->cmd = NANOHUB_HAL_SYS_MGMT_REBOOT; osEnqueueEvtOrFree(EVT_APP_TO_HOST_CHRE, resp, heapFree); } #ifdef LEGACY_HAL_ENABLED struct NanohubHalLegacyRebootTx *respLegacy; respLegacy = heapAlloc(sizeof(*respLegacy)); if (respLegacy) { respLegacy->hdr = (struct NanohubHalLegacyHdr) { .appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0), .len = sizeof(*respLegacy) - sizeof(respLegacy->hdr) + sizeof(respLegacy->hdr.msg), .msg = NANOHUB_HAL_LEGACY_REBOOT, }; memcpy(&respLegacy->reason, &raw_reason, sizeof(respLegacy->reason)); osEnqueueEvtOrFree(EVT_APP_TO_HOST, respLegacy, heapFree); } #endif } static void queueFlush(struct ActiveSensor *sensor) { if (sensor->buffer.length == 0) { sensor->buffer.length = sizeof(sensor->buffer.referenceTime) + sizeof(struct SensorFirstSample); sensor->buffer.referenceTime = 0ull; if (sensor->interrupt == NANOHUB_INT_WAKEUP) mWakeupBlocks++; else if (sensor->interrupt == NANOHUB_INT_NONWAKEUP) mNonWakeupBlocks++; sensor->buffer.firstSample.numFlushes = 1; } else { sensor->buffer.firstSample.numFlushes++; } sensor->discard = false; hostIntfSetInterrupt(sensor->interrupt); } static void fakeFlush(struct ConfigCmd *cmd) { struct HostIntfDataBuffer *buffer; uint8_t size = sizeof(buffer->evtType) + sizeof(buffer->referenceTime) + sizeof(struct SensorFirstSample); buffer = alloca(size); memset(buffer, 0x00, size); buffer->sensType = cmd->sensType; buffer->length = sizeof(buffer->referenceTime) + sizeof(struct SensorFirstSample); buffer->interrupt = NANOHUB_INT_WAKEUP; mWakeupBlocks++; buffer->firstSample.numFlushes = 1; if (!simpleQueueEnqueue(mOutputQ, buffer, size, false)) mWakeupBlocks--; } static void onEvtAppStart(const void *evtData) { if (initSensors()) { uint32_t reason; struct HostIntfDataBuffer *data; osEventUnsubscribe(mHostIntfTid, EVT_APP_START); osEventsSubscribe(4, EVT_NO_SENSOR_CONFIG_EVENT, EVT_APP_TO_SENSOR_HAL_DATA, EVT_APP_TO_HOST, EVT_APP_TO_HOST_CHRE); #ifdef DEBUG_LOG_EVT osEventSubscribe(mHostIntfTid, EVT_DEBUG_LOG); platEarlyLogFlush(); #endif reason = pwrResetReason(); data = alloca(sizeof(uint32_t) + sizeof(reason)); data->sensType = SENS_TYPE_INVALID; data->length = sizeof(reason); data->dataType = HOSTINTF_DATA_TYPE_RESET_REASON; data->interrupt = NANOHUB_INT_WAKEUP; memcpy(data->buffer, &reason, sizeof(reason)); hostIntfAddBlock(data, false, true); hostIntfNotifyReboot(reason); } } static void onEvtAppToHost(const void *evtData) { const struct HostHubRawPacket *hostMsg = evtData; if (hostMsg->dataLen <= HOST_HUB_RAW_PACKET_MAX_LEN) { struct HostIntfDataBuffer *data = alloca(sizeof(uint32_t) + sizeof(*hostMsg) + hostMsg->dataLen); data->sensType = SENS_TYPE_INVALID; data->length = sizeof(*hostMsg) + hostMsg->dataLen; data->dataType = HOSTINTF_DATA_TYPE_APP_TO_HOST; data->interrupt = NANOHUB_INT_WAKEUP; memcpy(data->buffer, evtData, data->length); hostIntfAddBlock(data, false, true); } } static void onEvtAppToHostChre(const void *evtData) { const struct HostHubChrePacket *hostMsg = evtData; if (hostMsg->messageSize <= HOST_HUB_CHRE_PACKET_MAX_LEN) { struct HostIntfDataBuffer *data = alloca(sizeof(uint32_t) + sizeof(*hostMsg) + hostMsg->messageSize); data->sensType = SENS_TYPE_INVALID; data->length = sizeof(*hostMsg) + hostMsg->messageSize; data->dataType = HOSTINTF_DATA_TYPE_APP_TO_HOST; data->interrupt = NANOHUB_INT_WAKEUP; memcpy(data->buffer, evtData, data->length); hostIntfAddBlock(data, false, true); } } #ifdef LEGACY_HAL_ENABLED static void handleLegacyHalCmd(const uint8_t *halData, uint8_t size) { const struct NanohubHalLegacyCommand *halCmd = nanohubHalLegacyFindCommand(halData[0]); if (halCmd) halCmd->handler((void *)&halData[1], size - 1); } static void onEvtAppFromHost(const void *evtData) { const uint8_t *halMsg = evtData; handleLegacyHalCmd(&halMsg[1], halMsg[0]); } #endif static void onEvtAppFromHostChre(const void *evtData) { const struct NanohubMsgChreHdr *halMsg = (const struct NanohubMsgChreHdr *)evtData; const struct NanohubHalCommand *halCmd; const uint8_t *halData = (const uint8_t *)(halMsg+1); uint8_t len; uint32_t transactionId; memcpy(&transactionId, &halMsg->appEvent, sizeof(halMsg->appEvent)); if (halMsg->size >= 1) { len = halMsg->size - 1; halCmd = nanohubHalFindCommand(halData[0]); if (halCmd) { if (len >= halCmd->minDataLen && len <= halCmd->maxDataLen) halCmd->handler((void *)&halData[1], len, transactionId); return; } } #ifdef LEGACY_HAL_ENABLED handleLegacyHalCmd(halData, halMsg->size); #endif } #ifdef DEBUG_LOG_EVT static void onEvtDebugLog(const void *evtData) { struct HostIntfDataBuffer *data = (struct HostIntfDataBuffer *)evtData; if (data->sensType == SENS_TYPE_INVALID && data->dataType == HOSTINTF_DATA_TYPE_LOG) hostIntfAddBlock(data, true, true); } #endif static void onEvtLatencyTimer(const void *evtData) { uint64_t sensorTime = sensorGetTime(); uint32_t i, cnt; for (i = 0, cnt = 0; i < mNumSensors && cnt < mLatencyCnt; i++) { if (mActiveSensorTable[i].latency > 0) { cnt++; if (mActiveSensorTable[i].firstTime && sensorTime >= mActiveSensorTable[i].firstTime + mActiveSensorTable[i].latency) { hostIntfSetInterrupt(mActiveSensorTable[i].interrupt); } } } } static void onConfigCmdFlushOne(struct ActiveSensor *sensor, struct ConfigCmd *cmd) { sensorFlush(sensor->sensorHandle); } static void onConfigCmdEnableOne(struct ActiveSensor *sensor, struct ConfigCmd *cmd) { if (sensorRequestRateChange(mHostIntfTid, sensor->sensorHandle, cmd->rate, cmd->latency)) { sensor->rate = cmd->rate; if (sensor->latency != cmd->latency) { if (!sensor->latency) { if (mLatencyCnt++ == 0) mLatencyTimer = timTimerSet(CHECK_LATENCY_TIME, 100, 100, latencyTimerCallback, NULL, false); } else if (!cmd->latency) { if (--mLatencyCnt == 0) { timTimerCancel(mLatencyTimer); mLatencyTimer = 0; } } sensor->latency = cmd->latency; } } } static void onConfigCmdEnableAll(struct ActiveSensor *sensor, struct ConfigCmd *cmd) { for (uint32_t i = 0; sensorFind(cmd->sensType, i, &sensor->sensorHandle) != NULL; i++) { if (cmd->rate == SENSOR_RATE_ONESHOT) { cmd->rate = SENSOR_RATE_ONCHANGE; sensor->oneshot = true; } else { sensor->oneshot = false; } if (sensorRequest(mHostIntfTid, sensor->sensorHandle, cmd->rate, cmd->latency)) { if (cmd->latency) { if (mLatencyCnt++ == 0) mLatencyTimer = timTimerSet(CHECK_LATENCY_TIME, 100, 100, latencyTimerCallback, NULL, false); } sensor->rate = cmd->rate; sensor->latency = cmd->latency; osEventSubscribe(mHostIntfTid, sensorGetMyEventType(cmd->sensType)); break; } else { sensor->sensorHandle = 0; } } } static void onConfigCmdDisableOne(struct ActiveSensor *sensor, struct ConfigCmd *cmd) { sensorRelease(mHostIntfTid, sensor->sensorHandle); osEventUnsubscribe(mHostIntfTid, sensorGetMyEventType(cmd->sensType)); if (sensor->latency) { if (--mLatencyCnt == 0) { timTimerCancel(mLatencyTimer); mLatencyTimer = 0; } } sensor->rate = 0; sensor->latency = 0; sensor->oneshot = false; sensor->sensorHandle = 0; if (sensor->buffer.length) { enqueueSensorBuffer(sensor); hostIntfSetInterrupt(sensor->interrupt); } } static void onConfigCmdCalibrateAll(struct ActiveSensor *sensor, struct ConfigCmd *cmd) { uint32_t tempSensorHandle; for (uint32_t i = 0; sensorFind(cmd->sensType, i, &tempSensorHandle) != NULL; i++) sensorCalibrate(tempSensorHandle); } static void onConfigCmdSelfTestAll(struct ActiveSensor *sensor, struct ConfigCmd *cmd) { uint32_t tempSensorHandle; for (uint32_t i = 0; sensorFind(cmd->sensType, i, &tempSensorHandle) != NULL; i++) sensorSelfTest(tempSensorHandle); } static void onConfigCmdCfgDataAll(struct ActiveSensor *sensor, struct ConfigCmd *cmd) { uint32_t tempSensorHandle; for (uint32_t i = 0; sensorFind(cmd->sensType, i, &tempSensorHandle) != NULL; i++) sensorCfgData(tempSensorHandle, (void *)(cmd+1)); } static void onEvtNoSensorConfigEvent(const void *evtData) { struct ConfigCmd *cmd = (struct ConfigCmd *)evtData; struct ActiveSensor *sensor = getActiveSensorByType(cmd->sensType); if (sensor) { if (sensor->sensorHandle) { switch (cmd->cmd) { case CONFIG_CMD_FLUSH: onConfigCmdFlushOne(sensor, cmd); break; case CONFIG_CMD_ENABLE: onConfigCmdEnableOne(sensor, cmd); break; case CONFIG_CMD_DISABLE: onConfigCmdDisableOne(sensor, cmd); break; case CONFIG_CMD_CFG_DATA: onConfigCmdCfgDataAll(sensor, cmd); break; } } else { switch (cmd->cmd) { case CONFIG_CMD_ENABLE: onConfigCmdEnableAll(sensor, cmd); break; case CONFIG_CMD_CALIBRATE: onConfigCmdCalibrateAll(sensor, cmd); break; case CONFIG_CMD_SELF_TEST: onConfigCmdSelfTestAll(sensor, cmd); break; case CONFIG_CMD_CFG_DATA: onConfigCmdCfgDataAll(sensor, cmd); break; case CONFIG_CMD_FLUSH: queueFlush(sensor); break; } } } else if (cmd->cmd == CONFIG_CMD_FLUSH && cmd->sensType > SENS_TYPE_INVALID) { // if a flush event is for an unknown sensor, we just return a fake flush event. osLog(LOG_INFO, "Flush request from unrecognized sensor, returning a fake flush\n"); fakeFlush(cmd); } } static void onEvtAppToSensorHalData(const void *evtData) { struct HostIntfDataBuffer *data = (struct HostIntfDataBuffer *)evtData; if (data->sensType == SENS_TYPE_INVALID && data->dataType == HOSTINTF_DATA_TYPE_APP_TO_SENSOR_HAL) { struct AppToSensorHalDataBuffer *buffer = (struct AppToSensorHalDataBuffer *)data; hostIntfAddBlock(data, (buffer->payload.type & EVENT_TYPE_BIT_DISCARDABLE) != 0, false); } } static void copyEmbeddedSamples(struct ActiveSensor *sensor, const void* evtData) { uint64_t sensorTime = sensorGetTime(); if (sensor->buffer.length > 0 && sensorTime - sensor->lastTime >= delta_time_max) enqueueSensorBuffer(sensor); if (sensor->buffer.length == 0) { sensor->buffer.length = sizeof(struct SingleAxisDataEvent) + sizeof(struct SingleAxisDataPoint); sensor->lastTime = sensor->buffer.referenceTime = sensorTime; if (sensor->interrupt == NANOHUB_INT_WAKEUP) mWakeupBlocks++; else if (sensor->interrupt == NANOHUB_INT_NONWAKEUP) mNonWakeupBlocks++; sensor->buffer.firstSample.numSamples = 1; sensor->buffer.firstSample.interrupt = sensor->interrupt; sensor->buffer.single[0].idata = (uint32_t)evtData; } else { sensor->buffer.length += sizeof(struct SingleAxisDataPoint); sensor->buffer.single[sensor->buffer.firstSample.numSamples].deltaTime = encodeDeltaTime(sensorTime - sensor->lastTime); sensor->lastTime = sensorTime; sensor->buffer.single[sensor->buffer.firstSample.numSamples].idata = (uint32_t)evtData; sensor->buffer.firstSample.numSamples++; } if (sensor->curSamples++ == 0) sensor->firstTime = sensor->buffer.referenceTime; } static uint32_t getSensorInterrupt(struct ActiveSensor *sensor) { uint32_t interrupt = HOSTINTF_MAX_INTERRUPTS; uint64_t sensorTime = sensorGetTime(); if (sensor->firstTime && ((sensorTime >= sensor->firstTime + sensor->latency) || ((sensor->latency > sensorGetCurLatency(sensor->sensorHandle)) && (sensorTime + sensorGetCurLatency(sensor->sensorHandle) > sensor->firstTime + sensor->latency)))) { interrupt = sensor->interrupt; } else if (mWakeupBlocks + mNonWakeupBlocks >= mTotalBlocks) { interrupt = sensor->interrupt; } return interrupt; } static void onEvtSensorDataActive(struct ActiveSensor *sensor, uint32_t evtType, const void* evtData) { if (evtData == SENSOR_DATA_EVENT_FLUSH) { queueFlush(sensor); } else { bool haveFlush = sensor->buffer.firstSample.numFlushes > 0; if (sensor->buffer.length > 0 && (haveFlush || sensor->buffer.firstSample.numSamples == sensor->packetSamples)) { // processing will be aborted if we have pending flush and are not able to send // in this case, send eventually will be retried, otherwise data will be lost if (!enqueueSensorBuffer(sensor) && haveFlush) return; } switch (sensor->numAxis) { case NUM_AXIS_EMBEDDED: copyEmbeddedSamples(sensor, evtData); break; case NUM_AXIS_ONE: copySingleSamples(sensor, evtData); break; case NUM_AXIS_THREE: if (sensor->raw) copyTripleSamplesRaw(sensor, evtData); else copyTripleSamples(sensor, evtData); break; default: return; } } nanohubPrefetchTx(getSensorInterrupt(sensor), mWakeupBlocks, mNonWakeupBlocks); if (sensor->oneshot) { sensorRelease(mHostIntfTid, sensor->sensorHandle); osEventUnsubscribe(mHostIntfTid, evtType); sensor->sensorHandle = 0; sensor->oneshot = false; } } static void onEvtSensorDataInactive(struct ActiveSensor *sensor, uint32_t evtType, const void* evtData) { if (evtData != SENSOR_DATA_EVENT_FLUSH) { // handle bias data which can be generated for sensors that are // not currently requested by the AP switch (sensor->numAxis) { case NUM_AXIS_THREE: if (((const struct TripleAxisDataEvent *)evtData)->samples[0].firstSample.biasPresent) { copyTripleSamplesBias(sensor, evtData); nanohubPrefetchTx(HOSTINTF_MAX_INTERRUPTS, mWakeupBlocks, mNonWakeupBlocks); } break; } } } static void onEvtSensorData(uint32_t evtType, const void* evtData) { if (evtType > EVT_NO_FIRST_SENSOR_EVENT && evtType < EVT_NO_SENSOR_CONFIG_EVENT) { struct ActiveSensor *sensor = getActiveSensorByType(evtType & 0xFF); if (sensor) { if (sensor->sensorHandle) onEvtSensorDataActive(sensor, evtType, evtData); else onEvtSensorDataInactive(sensor, evtType, evtData); } } } static void hostIntfHandleEvent(uint32_t evtType, const void* evtData) { switch (EVENT_GET_EVENT(evtType)) { case EVT_APP_START: onEvtAppStart(evtData); break; case EVT_APP_TO_HOST: onEvtAppToHost(evtData); break; case EVT_APP_TO_HOST_CHRE: onEvtAppToHostChre(evtData); break; #ifdef LEGACY_HAL_ENABLED case EVT_APP_FROM_HOST: onEvtAppFromHost(evtData); break; #endif case EVT_APP_FROM_HOST_CHRE: onEvtAppFromHostChre(evtData); break; #ifdef DEBUG_LOG_EVT case EVT_DEBUG_LOG: onEvtDebugLog(evtData); break; #endif case EVT_LATENCY_TIMER: onEvtLatencyTimer(evtData); break; case EVT_NO_SENSOR_CONFIG_EVENT: onEvtNoSensorConfigEvent(evtData); break; case EVT_APP_TO_SENSOR_HAL_DATA: onEvtAppToSensorHalData(evtData); break; default: onEvtSensorData(EVENT_GET_EVENT(evtType), evtData); break; } } void hostIntfCopyInterrupts(void *dst, uint32_t numBits) { if (mInterrupt->numBits != numBits) return; atomicBitsetBulkRead(mInterrupt, dst, numBits); } void hostIntfClearInterrupts() { uint32_t i; for (i = 0; i < HOSTINTF_MAX_INTERRUPTS; i++) { if (atomicBitsetGetBit(mInterrupt, i)) hostIntfClearInterrupt(i); } } void hostIntfSetInterrupt(uint32_t bit) { uint64_t state = cpuIntsOff(); if (mHostIntfTid) { if (!atomicBitsetGetBit(mInterrupt, bit)) { atomicBitsetSetBit(mInterrupt, bit); if (!atomicBitsetGetBit(mInterruptMask, bit)) { if (mInterruptCntWkup++ == 0) apIntSet(true); } else { if (mInterruptCntNonWkup++ == 0) apIntSet(false); } } } cpuIntsRestore(state); } bool hostIntfGetInterrupt(uint32_t bit) { return atomicBitsetGetBit(mInterrupt, bit); } void hostIntfClearInterrupt(uint32_t bit) { uint64_t state = cpuIntsOff(); if (mHostIntfTid) { if (atomicBitsetGetBit(mInterrupt, bit)) { atomicBitsetClearBit(mInterrupt, bit); if (!atomicBitsetGetBit(mInterruptMask, bit)) { if (--mInterruptCntWkup == 0) apIntClear(true); } else { if (--mInterruptCntNonWkup == 0) apIntClear(false); } } } cpuIntsRestore(state); } void hostIntfSetInterruptMask(uint32_t bit) { uint64_t state = cpuIntsOff(); if (mHostIntfTid) { if (!atomicBitsetGetBit(mInterruptMask, bit)) { atomicBitsetSetBit(mInterruptMask, bit); if (atomicBitsetGetBit(mInterrupt, bit)) { if (--mInterruptCntWkup == 0) apIntClear(true); if (mInterruptCntNonWkup++ == 0) apIntSet(false); } } } cpuIntsRestore(state); } bool hostIntfGetInterruptMask(uint32_t bit) { return atomicBitsetGetBit(mInterruptMask, bit); } void hostIntfClearInterruptMask(uint32_t bit) { uint64_t state = cpuIntsOff(); if (mHostIntfTid) { if (atomicBitsetGetBit(mInterruptMask, bit)) { atomicBitsetClearBit(mInterruptMask, bit); if (atomicBitsetGetBit(mInterrupt, bit)) { if (mInterruptCntWkup++ == 0) apIntSet(true); if (--mInterruptCntNonWkup == 0) apIntClear(false); } } } cpuIntsRestore(state); } INTERNAL_CHRE_APP_INIT(APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0), 0, hostIntfRequest, hostIntfRelease, hostIntfHandleEvent);